mirror of https://github.com/grafana/grafana.git
				
				
				
			Typescript: Removes implicit anys (#17625)
* Chore: Remove implicit anys from ResultProcessor and tests * Chore: Removes implicit anys for /loki/**/*.ts * Chore: Removes implicit anys for prometheus/**/*
This commit is contained in:
		
							parent
							
								
									d6ee96ee64
								
							
						
					
					
						commit
						3424b64299
					
				| 
						 | 
				
			
			@ -11,7 +11,7 @@ jest.mock('@grafana/ui/src/utils/moment_wrapper', () => ({
 | 
			
		|||
import { ResultProcessor } from './ResultProcessor';
 | 
			
		||||
import { ExploreItemState, ExploreMode } from 'app/types/explore';
 | 
			
		||||
import TableModel from 'app/core/table_model';
 | 
			
		||||
import { toFixed } from '@grafana/ui';
 | 
			
		||||
import { toFixed, TimeSeries, LogRowModel, LogsMetaItem } from '@grafana/ui';
 | 
			
		||||
 | 
			
		||||
const testContext = (options: any = {}) => {
 | 
			
		||||
  const response = [
 | 
			
		||||
| 
						 | 
				
			
			@ -47,9 +47,9 @@ const testContext = (options: any = {}) => {
 | 
			
		|||
    mode: ExploreMode.Metrics,
 | 
			
		||||
    replacePreviousResults: true,
 | 
			
		||||
    result: { data: response },
 | 
			
		||||
    graphResult: [],
 | 
			
		||||
    graphResult: [] as TimeSeries[],
 | 
			
		||||
    tableResult: new TableModel(),
 | 
			
		||||
    logsResult: { hasUniqueLabels: false, rows: [] },
 | 
			
		||||
    logsResult: { hasUniqueLabels: false, rows: [] as LogRowModel[] },
 | 
			
		||||
  };
 | 
			
		||||
  const combinedOptions = { ...defaultOptions, ...options };
 | 
			
		||||
  const state = ({
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +174,7 @@ describe('ResultProcessor', () => {
 | 
			
		|||
              labels: undefined,
 | 
			
		||||
              logLevel: 'unknown',
 | 
			
		||||
              raw: 'This is a message',
 | 
			
		||||
              searchWords: [],
 | 
			
		||||
              searchWords: [] as string[],
 | 
			
		||||
              timeEpochMs: 1559038519831,
 | 
			
		||||
              timeFromNow: 'fromNow() jest mocked',
 | 
			
		||||
              timeLocal: 'format() jest mocked',
 | 
			
		||||
| 
						 | 
				
			
			@ -187,7 +187,7 @@ describe('ResultProcessor', () => {
 | 
			
		|||
              labels: undefined,
 | 
			
		||||
              logLevel: 'unknown',
 | 
			
		||||
              raw: 'This is a message',
 | 
			
		||||
              searchWords: [],
 | 
			
		||||
              searchWords: [] as string[],
 | 
			
		||||
              timeEpochMs: 1559038518831,
 | 
			
		||||
              timeFromNow: 'fromNow() jest mocked',
 | 
			
		||||
              timeLocal: 'format() jest mocked',
 | 
			
		||||
| 
						 | 
				
			
			@ -317,7 +317,7 @@ describe('ResultProcessor', () => {
 | 
			
		|||
                labels: { cluster: 'some-cluster' },
 | 
			
		||||
                logLevel: 'unknown',
 | 
			
		||||
                raw: 'This is a previous message 1',
 | 
			
		||||
                searchWords: [],
 | 
			
		||||
                searchWords: [] as string[],
 | 
			
		||||
                timeEpochMs: 1558038519831,
 | 
			
		||||
                timeFromNow: 'fromNow() jest mocked',
 | 
			
		||||
                timeLocal: 'format() jest mocked',
 | 
			
		||||
| 
						 | 
				
			
			@ -331,7 +331,7 @@ describe('ResultProcessor', () => {
 | 
			
		|||
                labels: { cluster: 'some-cluster' },
 | 
			
		||||
                logLevel: 'unknown',
 | 
			
		||||
                raw: 'This is a previous message 2',
 | 
			
		||||
                searchWords: [],
 | 
			
		||||
                searchWords: [] as string[],
 | 
			
		||||
                timeEpochMs: 1558038518831,
 | 
			
		||||
                timeFromNow: 'fromNow() jest mocked',
 | 
			
		||||
                timeLocal: 'format() jest mocked',
 | 
			
		||||
| 
						 | 
				
			
			@ -362,7 +362,7 @@ describe('ResultProcessor', () => {
 | 
			
		|||
        const theResult = resultProcessor.getLogsResult();
 | 
			
		||||
        const expected = {
 | 
			
		||||
          hasUniqueLabels: false,
 | 
			
		||||
          meta: [],
 | 
			
		||||
          meta: [] as LogsMetaItem[],
 | 
			
		||||
          rows: [
 | 
			
		||||
            {
 | 
			
		||||
              entry: 'This is a previous message 1',
 | 
			
		||||
| 
						 | 
				
			
			@ -371,7 +371,7 @@ describe('ResultProcessor', () => {
 | 
			
		|||
              labels: { cluster: 'some-cluster' },
 | 
			
		||||
              logLevel: 'unknown',
 | 
			
		||||
              raw: 'This is a previous message 1',
 | 
			
		||||
              searchWords: [],
 | 
			
		||||
              searchWords: [] as string[],
 | 
			
		||||
              timeEpochMs: 1558038519831,
 | 
			
		||||
              timeFromNow: 'fromNow() jest mocked',
 | 
			
		||||
              timeLocal: 'format() jest mocked',
 | 
			
		||||
| 
						 | 
				
			
			@ -385,7 +385,7 @@ describe('ResultProcessor', () => {
 | 
			
		|||
              labels: { cluster: 'some-cluster' },
 | 
			
		||||
              logLevel: 'unknown',
 | 
			
		||||
              raw: 'This is a previous message 2',
 | 
			
		||||
              searchWords: [],
 | 
			
		||||
              searchWords: [] as string[],
 | 
			
		||||
              timeEpochMs: 1558038518831,
 | 
			
		||||
              timeFromNow: 'fromNow() jest mocked',
 | 
			
		||||
              timeLocal: 'format() jest mocked',
 | 
			
		||||
| 
						 | 
				
			
			@ -399,7 +399,7 @@ describe('ResultProcessor', () => {
 | 
			
		|||
              labels: undefined,
 | 
			
		||||
              logLevel: 'unknown',
 | 
			
		||||
              raw: 'This is a message',
 | 
			
		||||
              searchWords: [],
 | 
			
		||||
              searchWords: [] as string[],
 | 
			
		||||
              timeEpochMs: 1559038519831,
 | 
			
		||||
              timeFromNow: 'fromNow() jest mocked',
 | 
			
		||||
              timeLocal: 'format() jest mocked',
 | 
			
		||||
| 
						 | 
				
			
			@ -413,7 +413,7 @@ describe('ResultProcessor', () => {
 | 
			
		|||
              labels: undefined,
 | 
			
		||||
              logLevel: 'unknown',
 | 
			
		||||
              raw: 'This is a message',
 | 
			
		||||
              searchWords: [],
 | 
			
		||||
              searchWords: [] as string[],
 | 
			
		||||
              timeEpochMs: 1559038518831,
 | 
			
		||||
              timeFromNow: 'fromNow() jest mocked',
 | 
			
		||||
              timeLocal: 'format() jest mocked',
 | 
			
		||||
| 
						 | 
				
			
			@ -440,7 +440,7 @@ describe('ResultProcessor', () => {
 | 
			
		|||
                [39.91264531864214, 1559038518831],
 | 
			
		||||
                [40.35179822906545, 1559038519831],
 | 
			
		||||
              ],
 | 
			
		||||
              unit: undefined,
 | 
			
		||||
              unit: undefined as string,
 | 
			
		||||
              valueFormater: toFixed,
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,7 +66,7 @@ export class ResultProcessor {
 | 
			
		|||
      return new TableModel();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const prevTableResults = this.state.tableResult || [];
 | 
			
		||||
    const prevTableResults: any[] | TableModel = this.state.tableResult || [];
 | 
			
		||||
    const tablesToMerge = this.replacePreviousResults ? this.tables : [].concat(prevTableResults, this.tables);
 | 
			
		||||
 | 
			
		||||
    return mergeTablesIntoModel(new TableModel(), ...tablesToMerge);
 | 
			
		||||
| 
						 | 
				
			
			@ -116,13 +116,17 @@ export class ResultProcessor {
 | 
			
		|||
 | 
			
		||||
  private isSameTimeSeries = (a: TimeSeries | TimeSeries2, b: TimeSeries | TimeSeries2) => {
 | 
			
		||||
    if (a.hasOwnProperty('id') && b.hasOwnProperty('id')) {
 | 
			
		||||
      if (a['id'] !== undefined && b['id'] !== undefined && a['id'] === b['id']) {
 | 
			
		||||
      const aValue = (a as TimeSeries2).id;
 | 
			
		||||
      const bValue = (b as TimeSeries2).id;
 | 
			
		||||
      if (aValue !== undefined && bValue !== undefined && aValue === bValue) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (a.hasOwnProperty('alias') && b.hasOwnProperty('alias')) {
 | 
			
		||||
      if (a['alias'] !== undefined && b['alias'] !== undefined && a['alias'] === b['alias']) {
 | 
			
		||||
      const aValue = (a as TimeSeries2).alias;
 | 
			
		||||
      const bValue = (b as TimeSeries2).alias;
 | 
			
		||||
      if (aValue !== undefined && bValue !== undefined && aValue === bValue) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import LokiDatasource from './datasource';
 | 
			
		||||
import { LokiQuery } from './types';
 | 
			
		||||
import { getQueryOptions } from 'test/helpers/getQueryOptions';
 | 
			
		||||
import { SeriesData } from '@grafana/ui';
 | 
			
		||||
import { SeriesData, DataSourceApi } from '@grafana/ui';
 | 
			
		||||
import { BackendSrv } from 'app/core/services/backend_srv';
 | 
			
		||||
import { TemplateSrv } from 'app/features/templating/template_srv';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -26,8 +26,8 @@ describe('LokiDatasource', () => {
 | 
			
		|||
    const backendSrv = (backendSrvMock as unknown) as BackendSrv;
 | 
			
		||||
 | 
			
		||||
    const templateSrvMock = ({
 | 
			
		||||
      getAdhocFilters: () => [],
 | 
			
		||||
      replace: a => a,
 | 
			
		||||
      getAdhocFilters: (): any[] => [],
 | 
			
		||||
      replace: (a: string) => a,
 | 
			
		||||
    } as unknown) as TemplateSrv;
 | 
			
		||||
 | 
			
		||||
    test('should use default max lines when no limit given', () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -75,8 +75,8 @@ describe('LokiDatasource', () => {
 | 
			
		|||
  });
 | 
			
		||||
 | 
			
		||||
  describe('when performing testDataSource', () => {
 | 
			
		||||
    let ds;
 | 
			
		||||
    let result;
 | 
			
		||||
    let ds: DataSourceApi<any, any>;
 | 
			
		||||
    let result: any;
 | 
			
		||||
 | 
			
		||||
    describe('and call succeeds', () => {
 | 
			
		||||
      beforeEach(async () => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,8 @@ import {
 | 
			
		|||
  DataStreamObserver,
 | 
			
		||||
  LoadingState,
 | 
			
		||||
  DataStreamState,
 | 
			
		||||
  DataQueryResponse,
 | 
			
		||||
  DateTime,
 | 
			
		||||
} from '@grafana/ui';
 | 
			
		||||
import { LokiQuery, LokiOptions } from './types';
 | 
			
		||||
import { BackendSrv } from 'app/core/services/backend_srv';
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +72,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
 | 
			
		|||
    this.subscriptions = {};
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _request(apiUrl: string, data?, options?: any) {
 | 
			
		||||
  _request(apiUrl: string, data?: any, options?: any) {
 | 
			
		||||
    const baseUrl = this.instanceSettings.url;
 | 
			
		||||
    const params = data ? serializeParams(data) : '';
 | 
			
		||||
    const url = `${baseUrl}${apiUrl}?${params}`;
 | 
			
		||||
| 
						 | 
				
			
			@ -254,11 +256,11 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
 | 
			
		|||
    return this.languageProvider.importQueries(queries, originMeta.id);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  metadataRequest(url) {
 | 
			
		||||
  metadataRequest(url: string) {
 | 
			
		||||
    // 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 => {
 | 
			
		||||
      const data = { data: { data: res.data.values || [] } };
 | 
			
		||||
    return this._request(apiUrl, { silent: true }).then((res: DataQueryResponse) => {
 | 
			
		||||
      const data: any = { data: { data: res.data.values || [] } };
 | 
			
		||||
      return data;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -282,7 +284,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
 | 
			
		|||
    return getHighlighterExpressionsFromQuery(query.expr);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getTime(date, roundUp) {
 | 
			
		||||
  getTime(date: string | DateTime, roundUp: boolean) {
 | 
			
		||||
    if (_.isString(date)) {
 | 
			
		||||
      date = dateMath.parse(date, roundUp);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -357,7 +359,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
 | 
			
		|||
 | 
			
		||||
  testDatasource() {
 | 
			
		||||
    return this._request('/api/prom/label')
 | 
			
		||||
      .then(res => {
 | 
			
		||||
      .then((res: DataQueryResponse) => {
 | 
			
		||||
        if (res && res.data && res.data.values && res.data.values.length > 0) {
 | 
			
		||||
          return { status: 'success', message: 'Data source connected and labels found.' };
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -367,7 +369,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
 | 
			
		|||
            'Data source connected, but no labels received. Verify that Loki and Promtail is configured properly.',
 | 
			
		||||
        };
 | 
			
		||||
      })
 | 
			
		||||
      .catch(err => {
 | 
			
		||||
      .catch((err: any) => {
 | 
			
		||||
        let message = 'Loki: ';
 | 
			
		||||
        if (err.statusText) {
 | 
			
		||||
          message += err.statusText;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,14 @@
 | 
			
		|||
// @ts-ignore
 | 
			
		||||
import Plain from 'slate-plain-serializer';
 | 
			
		||||
 | 
			
		||||
import LanguageProvider, { LABEL_REFRESH_INTERVAL } from './language_provider';
 | 
			
		||||
import { advanceTo, clear, advanceBy } from 'jest-date-mock';
 | 
			
		||||
import { beforeEach } from 'test/lib/common';
 | 
			
		||||
import { DataQueryResponseData } from '@grafana/ui';
 | 
			
		||||
 | 
			
		||||
describe('Language completion provider', () => {
 | 
			
		||||
  const datasource = {
 | 
			
		||||
    metadataRequest: () => ({ data: { data: [] } }),
 | 
			
		||||
    metadataRequest: () => ({ data: { data: [] as DataQueryResponseData[] } }),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  describe('empty query suggestions', () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -91,7 +93,7 @@ describe('Language completion provider', () => {
 | 
			
		|||
 | 
			
		||||
describe('Query imports', () => {
 | 
			
		||||
  const datasource = {
 | 
			
		||||
    metadataRequest: () => ({ data: { data: [] } }),
 | 
			
		||||
    metadataRequest: () => ({ data: { data: [] as DataQueryResponseData[] } }),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  it('returns empty queries for unknown origin datasource', async () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +111,8 @@ describe('Query imports', () => {
 | 
			
		|||
 | 
			
		||||
    it('returns empty query from selector query if label is not available', async () => {
 | 
			
		||||
      const datasourceWithLabels = {
 | 
			
		||||
        metadataRequest: url => (url === '/api/prom/label' ? { data: { data: ['other'] } } : { data: { data: [] } }),
 | 
			
		||||
        metadataRequest: (url: string) =>
 | 
			
		||||
          url === '/api/prom/label' ? { data: { data: ['other'] } } : { data: { data: [] as DataQueryResponseData[] } },
 | 
			
		||||
      };
 | 
			
		||||
      const instance = new LanguageProvider(datasourceWithLabels);
 | 
			
		||||
      const result = await instance.importPrometheusQuery('{foo="bar"}');
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +121,8 @@ describe('Query imports', () => {
 | 
			
		|||
 | 
			
		||||
    it('returns selector query from selector query with common labels', async () => {
 | 
			
		||||
      const datasourceWithLabels = {
 | 
			
		||||
        metadataRequest: url => (url === '/api/prom/label' ? { data: { data: ['foo'] } } : { data: { data: [] } }),
 | 
			
		||||
        metadataRequest: (url: string) =>
 | 
			
		||||
          url === '/api/prom/label' ? { data: { data: ['foo'] } } : { data: { data: [] as DataQueryResponseData[] } },
 | 
			
		||||
      };
 | 
			
		||||
      const instance = new LanguageProvider(datasourceWithLabels);
 | 
			
		||||
      const result = await instance.importPrometheusQuery('metric{foo="bar",baz="42"}');
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +131,10 @@ describe('Query imports', () => {
 | 
			
		|||
 | 
			
		||||
    it('returns selector query from selector query with all labels if logging label list is empty', async () => {
 | 
			
		||||
      const datasourceWithLabels = {
 | 
			
		||||
        metadataRequest: url => (url === '/api/prom/label' ? { data: { data: [] } } : { data: { data: [] } }),
 | 
			
		||||
        metadataRequest: (url: string) =>
 | 
			
		||||
          url === '/api/prom/label'
 | 
			
		||||
            ? { data: { data: [] as DataQueryResponseData[] } }
 | 
			
		||||
            : { data: { data: [] as DataQueryResponseData[] } },
 | 
			
		||||
      };
 | 
			
		||||
      const instance = new LanguageProvider(datasourceWithLabels);
 | 
			
		||||
      const result = await instance.importPrometheusQuery('metric{foo="bar",baz="42"}');
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +145,7 @@ describe('Query imports', () => {
 | 
			
		|||
 | 
			
		||||
describe('Labels refresh', () => {
 | 
			
		||||
  const datasource = {
 | 
			
		||||
    metadataRequest: () => ({ data: { data: [] } }),
 | 
			
		||||
    metadataRequest: () => ({ data: { data: [] as DataQueryResponseData[] } }),
 | 
			
		||||
  };
 | 
			
		||||
  const instance = new LanguageProvider(datasource);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ export function addLabelToQuery(query: string, key: string, value: string, opera
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  // Add empty selectors to bare metric names
 | 
			
		||||
  let previousWord;
 | 
			
		||||
  let previousWord: string;
 | 
			
		||||
  query = query.replace(metricNameRegexp, (match, word, offset) => {
 | 
			
		||||
    const insideSelector = isPositionInsideChars(query, offset, '{', '}');
 | 
			
		||||
    // Handle "sum by (key) (metric)"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,24 @@
 | 
			
		|||
import { PrometheusDatasource } from './datasource';
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
import { TemplateSrv } from 'app/features/templating/template_srv';
 | 
			
		||||
 | 
			
		||||
export interface CompleterPosition {
 | 
			
		||||
  row: number;
 | 
			
		||||
  column: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CompleterToken {
 | 
			
		||||
  type: string;
 | 
			
		||||
  value: string;
 | 
			
		||||
  row: number;
 | 
			
		||||
  column: number;
 | 
			
		||||
  index: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CompleterSession {
 | 
			
		||||
  getTokenAt: (row: number, column: number) => CompleterToken;
 | 
			
		||||
  getTokens: (row: number) => CompleterToken[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class PromCompleter {
 | 
			
		||||
  labelQueryCache: any;
 | 
			
		||||
| 
						 | 
				
			
			@ -9,11 +28,11 @@ export class PromCompleter {
 | 
			
		|||
 | 
			
		||||
  identifierRegexps = [/\[/, /[a-zA-Z0-9_:]/];
 | 
			
		||||
 | 
			
		||||
  constructor(private datasource: PrometheusDatasource, private templateSrv) {
 | 
			
		||||
  constructor(private datasource: PrometheusDatasource, private templateSrv: TemplateSrv) {
 | 
			
		||||
    this.labelQueryCache = {};
 | 
			
		||||
    this.labelNameCache = {};
 | 
			
		||||
    this.labelValueCache = {};
 | 
			
		||||
    this.templateVariableCompletions = this.templateSrv.variables.map(variable => {
 | 
			
		||||
    this.templateVariableCompletions = this.templateSrv.variables.map((variable: any) => {
 | 
			
		||||
      return {
 | 
			
		||||
        caption: '$' + variable.name,
 | 
			
		||||
        value: '$' + variable.name,
 | 
			
		||||
| 
						 | 
				
			
			@ -23,8 +42,8 @@ export class PromCompleter {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getCompletions(editor, session, pos, prefix, callback) {
 | 
			
		||||
    const wrappedCallback = (err, completions) => {
 | 
			
		||||
  getCompletions(editor: any, session: CompleterSession, pos: CompleterPosition, prefix: string, callback: Function) {
 | 
			
		||||
    const wrappedCallback = (err: any, completions: any[]) => {
 | 
			
		||||
      completions = completions.concat(this.templateVariableCompletions);
 | 
			
		||||
      return callback(err, completions);
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +98,7 @@ export class PromCompleter {
 | 
			
		|||
 | 
			
		||||
    const query = prefix;
 | 
			
		||||
 | 
			
		||||
    return this.datasource.performSuggestQuery(query, true).then(metricNames => {
 | 
			
		||||
    return this.datasource.performSuggestQuery(query, true).then((metricNames: string[]) => {
 | 
			
		||||
      wrappedCallback(
 | 
			
		||||
        null,
 | 
			
		||||
        metricNames.map(name => {
 | 
			
		||||
| 
						 | 
				
			
			@ -98,7 +117,7 @@ export class PromCompleter {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getCompletionsForLabelMatcherName(session, pos) {
 | 
			
		||||
  getCompletionsForLabelMatcherName(session: CompleterSession, pos: CompleterPosition) {
 | 
			
		||||
    const metricName = this.findMetricName(session, pos.row, pos.column);
 | 
			
		||||
    if (!metricName) {
 | 
			
		||||
      return Promise.resolve(this.transformToCompletions(['__name__', 'instance', 'job'], 'label name'));
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +131,7 @@ export class PromCompleter {
 | 
			
		|||
      const labelNames = this.transformToCompletions(
 | 
			
		||||
        _.uniq(
 | 
			
		||||
          _.flatten(
 | 
			
		||||
            result.map(r => {
 | 
			
		||||
            result.map((r: any) => {
 | 
			
		||||
              return Object.keys(r);
 | 
			
		||||
            })
 | 
			
		||||
          )
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +143,7 @@ export class PromCompleter {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getCompletionsForLabelMatcherValue(session, pos) {
 | 
			
		||||
  getCompletionsForLabelMatcherValue(session: CompleterSession, pos: CompleterPosition) {
 | 
			
		||||
    const metricName = this.findMetricName(session, pos.row, pos.column);
 | 
			
		||||
    if (!metricName) {
 | 
			
		||||
      return Promise.resolve([]);
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +169,7 @@ export class PromCompleter {
 | 
			
		|||
    return this.getLabelNameAndValueForExpression(metricName, 'metricName').then(result => {
 | 
			
		||||
      const labelValues = this.transformToCompletions(
 | 
			
		||||
        _.uniq(
 | 
			
		||||
          result.map(r => {
 | 
			
		||||
          result.map((r: any) => {
 | 
			
		||||
            return r[labelName];
 | 
			
		||||
          })
 | 
			
		||||
        ),
 | 
			
		||||
| 
						 | 
				
			
			@ -162,12 +181,12 @@ export class PromCompleter {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getCompletionsForBinaryOperator(session, pos) {
 | 
			
		||||
  getCompletionsForBinaryOperator(session: CompleterSession, pos: CompleterPosition) {
 | 
			
		||||
    const keywordOperatorToken = this.findToken(session, pos.row, pos.column, 'keyword.control', null, 'identifier');
 | 
			
		||||
    if (!keywordOperatorToken) {
 | 
			
		||||
      return Promise.resolve([]);
 | 
			
		||||
    }
 | 
			
		||||
    let rparenToken, expr;
 | 
			
		||||
    let rparenToken: CompleterToken, expr: string;
 | 
			
		||||
    switch (keywordOperatorToken.value) {
 | 
			
		||||
      case 'by':
 | 
			
		||||
      case 'without':
 | 
			
		||||
| 
						 | 
				
			
			@ -190,7 +209,7 @@ export class PromCompleter {
 | 
			
		|||
          const labelNames = this.transformToCompletions(
 | 
			
		||||
            _.uniq(
 | 
			
		||||
              _.flatten(
 | 
			
		||||
                result.map(r => {
 | 
			
		||||
                result.map((r: any) => {
 | 
			
		||||
                  return Object.keys(r);
 | 
			
		||||
                })
 | 
			
		||||
              )
 | 
			
		||||
| 
						 | 
				
			
			@ -232,7 +251,7 @@ export class PromCompleter {
 | 
			
		|||
            const labelNames = this.transformToCompletions(
 | 
			
		||||
              _.uniq(
 | 
			
		||||
                _.flatten(
 | 
			
		||||
                  result.map(r => {
 | 
			
		||||
                  result.map((r: any) => {
 | 
			
		||||
                    return Object.keys(r);
 | 
			
		||||
                  })
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			@ -248,7 +267,7 @@ export class PromCompleter {
 | 
			
		|||
            const labelNames = this.transformToCompletions(
 | 
			
		||||
              _.uniq(
 | 
			
		||||
                _.flatten(
 | 
			
		||||
                  result.map(r => {
 | 
			
		||||
                  result.map((r: any) => {
 | 
			
		||||
                    return Object.keys(r);
 | 
			
		||||
                  })
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			@ -278,27 +297,27 @@ export class PromCompleter {
 | 
			
		|||
    }
 | 
			
		||||
    const { start, end } = this.datasource.getTimeRange();
 | 
			
		||||
    const url = '/api/v1/series?match[]=' + encodeURIComponent(query) + '&start=' + start + '&end=' + end;
 | 
			
		||||
    return this.datasource.metadataRequest(url).then(response => {
 | 
			
		||||
    return this.datasource.metadataRequest(url).then((response: any) => {
 | 
			
		||||
      this.labelQueryCache[expr] = response.data.data;
 | 
			
		||||
      return response.data.data;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  transformToCompletions(words, meta) {
 | 
			
		||||
  transformToCompletions(words: string[], meta: any) {
 | 
			
		||||
    return words.map(name => {
 | 
			
		||||
      return {
 | 
			
		||||
        caption: name,
 | 
			
		||||
        value: name,
 | 
			
		||||
        meta: meta,
 | 
			
		||||
        meta,
 | 
			
		||||
        score: Number.MAX_VALUE,
 | 
			
		||||
      };
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  findMetricName(session, row, column) {
 | 
			
		||||
  findMetricName(session: CompleterSession, row: number, column: number) {
 | 
			
		||||
    let metricName = '';
 | 
			
		||||
 | 
			
		||||
    let tokens;
 | 
			
		||||
    let tokens: CompleterToken[];
 | 
			
		||||
    const nameLabelNameToken = this.findToken(
 | 
			
		||||
      session,
 | 
			
		||||
      row,
 | 
			
		||||
| 
						 | 
				
			
			@ -324,11 +343,11 @@ export class PromCompleter {
 | 
			
		|||
    return metricName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  findToken(session, row, column, target, value, guard) {
 | 
			
		||||
    let tokens, idx;
 | 
			
		||||
  findToken(session: CompleterSession, row: number, column: number, target: string, value: string, guard: string) {
 | 
			
		||||
    let tokens: CompleterToken[], idx: number;
 | 
			
		||||
    // find index and get column of previous token
 | 
			
		||||
    for (let r = row; r >= 0; r--) {
 | 
			
		||||
      let c;
 | 
			
		||||
      let c: number;
 | 
			
		||||
      tokens = session.getTokens(r);
 | 
			
		||||
      if (r === row) {
 | 
			
		||||
        // current row
 | 
			
		||||
| 
						 | 
				
			
			@ -368,8 +387,8 @@ export class PromCompleter {
 | 
			
		|||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  findExpressionMatchedParen(session, row, column) {
 | 
			
		||||
    let tokens, idx;
 | 
			
		||||
  findExpressionMatchedParen(session: CompleterSession, row: number, column: number) {
 | 
			
		||||
    let tokens: CompleterToken[], idx: number;
 | 
			
		||||
    let deep = 1;
 | 
			
		||||
    let expression = ')';
 | 
			
		||||
    for (let r = row; r >= 0; r--) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@ export class PrometheusConfigCtrl {
 | 
			
		|||
  current: any;
 | 
			
		||||
 | 
			
		||||
  /** @ngInject */
 | 
			
		||||
  constructor($scope) {
 | 
			
		||||
  constructor($scope: any) {
 | 
			
		||||
    this.current.jsonData.httpMethod = this.current.jsonData.httpMethod || 'GET';
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,12 +25,24 @@ import {
 | 
			
		|||
  DataQueryError,
 | 
			
		||||
  DataStreamObserver,
 | 
			
		||||
  LoadingState,
 | 
			
		||||
  DataQueryResponseData,
 | 
			
		||||
} from '@grafana/ui/src/types';
 | 
			
		||||
import { ExploreUrlState } from 'app/types/explore';
 | 
			
		||||
import { safeStringifyValue } from 'app/core/utils/explore';
 | 
			
		||||
import { TemplateSrv } from 'app/features/templating/template_srv';
 | 
			
		||||
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
 | 
			
		||||
import { TimeRange } from '@grafana/ui/src';
 | 
			
		||||
import { TimeRange, DateTime } from '@grafana/ui/src';
 | 
			
		||||
 | 
			
		||||
export interface PromDataQueryResponse {
 | 
			
		||||
  data: {
 | 
			
		||||
    status: string;
 | 
			
		||||
    data: {
 | 
			
		||||
      resultType: string;
 | 
			
		||||
      results?: DataQueryResponseData[];
 | 
			
		||||
      result?: DataQueryResponseData[];
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions> {
 | 
			
		||||
  type: string;
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +118,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
 | 
			
		||||
      options.transformRequest = data => {
 | 
			
		||||
      options.transformRequest = (data: any) => {
 | 
			
		||||
        return $.param(data);
 | 
			
		||||
      };
 | 
			
		||||
      options.data = data;
 | 
			
		||||
| 
						 | 
				
			
			@ -279,9 +291,9 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
    });
 | 
			
		||||
 | 
			
		||||
    const allPromise = this.$q.all(allQueryPromise).then((responseList: any) => {
 | 
			
		||||
      let result = [];
 | 
			
		||||
      let result: any[] = [];
 | 
			
		||||
 | 
			
		||||
      _.each(responseList, (response, index) => {
 | 
			
		||||
      _.each(responseList, (response, index: number) => {
 | 
			
		||||
        if (response.cancelled) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -361,7 +373,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
    return query;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  adjustInterval(interval, minInterval, range, intervalFactor) {
 | 
			
		||||
  adjustInterval(interval: number, minInterval: number, range: number, intervalFactor: number) {
 | 
			
		||||
    // Prometheus will drop queries that might return more than 11000 data points.
 | 
			
		||||
    // Calibrate interval if it is too small.
 | 
			
		||||
    if (interval !== 0 && range / intervalFactor / interval > 11000) {
 | 
			
		||||
| 
						 | 
				
			
			@ -370,35 +382,39 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
    return Math.max(interval * intervalFactor, minInterval, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  performTimeSeriesQuery(query, start, end) {
 | 
			
		||||
  performTimeSeriesQuery(query: PromQueryRequest, start: number, end: number) {
 | 
			
		||||
    if (start > end) {
 | 
			
		||||
      throw { message: 'Invalid time range' };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const url = '/api/v1/query_range';
 | 
			
		||||
    const data = {
 | 
			
		||||
    const data: any = {
 | 
			
		||||
      query: query.expr,
 | 
			
		||||
      start: start,
 | 
			
		||||
      end: end,
 | 
			
		||||
      start,
 | 
			
		||||
      end,
 | 
			
		||||
      step: query.step,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (this.queryTimeout) {
 | 
			
		||||
      data['timeout'] = this.queryTimeout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return this._request(url, data, { requestId: query.requestId, headers: query.headers }).catch((err: any) =>
 | 
			
		||||
      this.handleErrors(err, query)
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  performInstantQuery(query, time) {
 | 
			
		||||
  performInstantQuery(query: PromQueryRequest, time: number) {
 | 
			
		||||
    const url = '/api/v1/query';
 | 
			
		||||
    const data = {
 | 
			
		||||
    const data: any = {
 | 
			
		||||
      query: query.expr,
 | 
			
		||||
      time: time,
 | 
			
		||||
      time,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (this.queryTimeout) {
 | 
			
		||||
      data['timeout'] = this.queryTimeout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return this._request(url, data, { requestId: query.requestId, headers: query.headers }).catch((err: any) =>
 | 
			
		||||
      this.handleErrors(err, query)
 | 
			
		||||
    );
 | 
			
		||||
| 
						 | 
				
			
			@ -432,7 +448,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
    throw error;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  performSuggestQuery(query, cache = false) {
 | 
			
		||||
  performSuggestQuery(query: string, cache = false) {
 | 
			
		||||
    const url = '/api/v1/label/__name__/values';
 | 
			
		||||
 | 
			
		||||
    if (cache && this.metricsNameCache && this.metricsNameCache.expire > Date.now()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -443,7 +459,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return this.metadataRequest(url).then(result => {
 | 
			
		||||
    return this.metadataRequest(url).then((result: PromDataQueryResponse) => {
 | 
			
		||||
      this.metricsNameCache = {
 | 
			
		||||
        data: result.data.data,
 | 
			
		||||
        expire: Date.now() + 60 * 1000,
 | 
			
		||||
| 
						 | 
				
			
			@ -454,7 +470,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  metricFindQuery(query) {
 | 
			
		||||
  metricFindQuery(query: string) {
 | 
			
		||||
    if (!query) {
 | 
			
		||||
      return this.$q.when([]);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -481,7 +497,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  annotationQuery(options) {
 | 
			
		||||
  annotationQuery(options: any) {
 | 
			
		||||
    const annotation = options.annotation;
 | 
			
		||||
    const expr = annotation.expr || '';
 | 
			
		||||
    let tagKeys = annotation.tagKeys || '';
 | 
			
		||||
| 
						 | 
				
			
			@ -504,8 +520,8 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
    const query = this.createQuery({ expr, interval: minStep, refId: 'X' }, queryOptions, start, end);
 | 
			
		||||
 | 
			
		||||
    const self = this;
 | 
			
		||||
    return this.performTimeSeriesQuery(query, query.start, query.end).then(results => {
 | 
			
		||||
      const eventList = [];
 | 
			
		||||
    return this.performTimeSeriesQuery(query, query.start, query.end).then((results: PromDataQueryResponse) => {
 | 
			
		||||
      const eventList: AnnotationEvent[] = [];
 | 
			
		||||
      tagKeys = tagKeys.split(',');
 | 
			
		||||
 | 
			
		||||
      _.each(results.data.data.result, series => {
 | 
			
		||||
| 
						 | 
				
			
			@ -515,7 +531,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
          })
 | 
			
		||||
          .value();
 | 
			
		||||
 | 
			
		||||
        const dupCheck = {};
 | 
			
		||||
        const dupCheck: { [key: number]: boolean } = {};
 | 
			
		||||
        for (const value of series.values) {
 | 
			
		||||
          const valueIsTrue = value[1] === '1'; // e.g. ALERTS
 | 
			
		||||
          if (valueIsTrue || annotation.useValueForTime) {
 | 
			
		||||
| 
						 | 
				
			
			@ -546,18 +562,18 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getTagKeys(options) {
 | 
			
		||||
  getTagKeys(options: any = {}) {
 | 
			
		||||
    const url = '/api/v1/labels';
 | 
			
		||||
    return this.metadataRequest(url).then(result => {
 | 
			
		||||
    return this.metadataRequest(url).then((result: any) => {
 | 
			
		||||
      return _.map(result.data.data, value => {
 | 
			
		||||
        return { text: value };
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getTagValues(options) {
 | 
			
		||||
  getTagValues(options: any = {}) {
 | 
			
		||||
    const url = '/api/v1/label/' + options.key + '/values';
 | 
			
		||||
    return this.metadataRequest(url).then(result => {
 | 
			
		||||
    return this.metadataRequest(url).then((result: any) => {
 | 
			
		||||
      return _.map(result.data.data, value => {
 | 
			
		||||
        return { text: value };
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			@ -566,7 +582,8 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
 | 
			
		||||
  testDatasource() {
 | 
			
		||||
    const now = new Date().getTime();
 | 
			
		||||
    return this.performInstantQuery({ expr: '1+1' }, now / 1000).then(response => {
 | 
			
		||||
    const query = { expr: '1+1' } as PromQueryRequest;
 | 
			
		||||
    return this.performInstantQuery(query, now / 1000).then((response: any) => {
 | 
			
		||||
      if (response.data.status === 'success') {
 | 
			
		||||
        return { status: 'success', message: 'Data source is working' };
 | 
			
		||||
      } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -601,14 +618,14 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
 | 
			
		||||
  loadRules() {
 | 
			
		||||
    this.metadataRequest('/api/v1/rules')
 | 
			
		||||
      .then(res => res.data || res.json())
 | 
			
		||||
      .then(body => {
 | 
			
		||||
      .then((res: any) => res.data || res.json())
 | 
			
		||||
      .then((body: any) => {
 | 
			
		||||
        const groups = _.get(body, ['data', 'groups']);
 | 
			
		||||
        if (groups) {
 | 
			
		||||
          this.ruleMappings = extractRuleMappingFromGroups(groups);
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      .catch(e => {
 | 
			
		||||
      .catch((e: any) => {
 | 
			
		||||
        console.log('Rules API is experimental. Ignore next error.');
 | 
			
		||||
        console.error(e);
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			@ -645,7 +662,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
    return { ...query, expr: expression };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getPrometheusTime(date, roundUp) {
 | 
			
		||||
  getPrometheusTime(date: string | DateTime, roundUp: boolean) {
 | 
			
		||||
    if (_.isString(date)) {
 | 
			
		||||
      date = dateMath.parse(date, roundUp);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -660,7 +677,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
 | 
			
		|||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getOriginalMetricName(labelData) {
 | 
			
		||||
  getOriginalMetricName(labelData: { [key: string]: string }) {
 | 
			
		||||
    return this.resultTransformer.getOriginalMetricName(labelData);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -685,9 +702,9 @@ export function extractRuleMappingFromGroups(groups: any[]) {
 | 
			
		|||
  return groups.reduce(
 | 
			
		||||
    (mapping, group) =>
 | 
			
		||||
      group.rules
 | 
			
		||||
        .filter(rule => rule.type === 'recording')
 | 
			
		||||
        .filter((rule: any) => rule.type === 'recording')
 | 
			
		||||
        .reduce(
 | 
			
		||||
          (acc, rule) => ({
 | 
			
		||||
          (acc: { [key: string]: string }, rule: any) => ({
 | 
			
		||||
            ...acc,
 | 
			
		||||
            [rule.name]: rule.query,
 | 
			
		||||
          }),
 | 
			
		||||
| 
						 | 
				
			
			@ -697,14 +714,14 @@ export function extractRuleMappingFromGroups(groups: any[]) {
 | 
			
		|||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function prometheusRegularEscape(value) {
 | 
			
		||||
export function prometheusRegularEscape(value: any) {
 | 
			
		||||
  if (typeof value === 'string') {
 | 
			
		||||
    return value.replace(/'/g, "\\\\'");
 | 
			
		||||
  }
 | 
			
		||||
  return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function prometheusSpecialRegexEscape(value) {
 | 
			
		||||
export function prometheusSpecialRegexEscape(value: any) {
 | 
			
		||||
  if (typeof value === 'string') {
 | 
			
		||||
    return prometheusRegularEscape(value.replace(/\\/g, '\\\\\\\\').replace(/[$^*{}\[\]+?.()|]/g, '\\\\$&'));
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,13 @@
 | 
			
		|||
import _ from 'lodash';
 | 
			
		||||
import { TimeRange } from '@grafana/ui';
 | 
			
		||||
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
 | 
			
		||||
import { PrometheusDatasource, PromDataQueryResponse } from './datasource';
 | 
			
		||||
import { PromQueryRequest } from './types';
 | 
			
		||||
 | 
			
		||||
export default class PrometheusMetricFindQuery {
 | 
			
		||||
  datasource: any;
 | 
			
		||||
  query: any;
 | 
			
		||||
  range: any;
 | 
			
		||||
  range: TimeRange;
 | 
			
		||||
 | 
			
		||||
  constructor(datasource, query, timeSrv) {
 | 
			
		||||
  constructor(private datasource: PrometheusDatasource, private query: string, timeSrv: TimeSrv) {
 | 
			
		||||
    this.datasource = datasource;
 | 
			
		||||
    this.query = query;
 | 
			
		||||
    this.range = timeSrv.timeRange();
 | 
			
		||||
| 
						 | 
				
			
			@ -47,21 +49,21 @@ export default class PrometheusMetricFindQuery {
 | 
			
		|||
 | 
			
		||||
  labelNamesQuery() {
 | 
			
		||||
    const url = '/api/v1/labels';
 | 
			
		||||
    return this.datasource.metadataRequest(url).then(result => {
 | 
			
		||||
    return this.datasource.metadataRequest(url).then((result: any) => {
 | 
			
		||||
      return _.map(result.data.data, value => {
 | 
			
		||||
        return { text: value };
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  labelValuesQuery(label, metric) {
 | 
			
		||||
    let url;
 | 
			
		||||
  labelValuesQuery(label: string, metric?: string) {
 | 
			
		||||
    let url: string;
 | 
			
		||||
 | 
			
		||||
    if (!metric) {
 | 
			
		||||
      // return label values globally
 | 
			
		||||
      url = '/api/v1/label/' + label + '/values';
 | 
			
		||||
 | 
			
		||||
      return this.datasource.metadataRequest(url).then(result => {
 | 
			
		||||
      return this.datasource.metadataRequest(url).then((result: any) => {
 | 
			
		||||
        return _.map(result.data.data, value => {
 | 
			
		||||
          return { text: value };
 | 
			
		||||
        });
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +73,7 @@ export default class PrometheusMetricFindQuery {
 | 
			
		|||
      const end = this.datasource.getPrometheusTime(this.range.to, true);
 | 
			
		||||
      url = '/api/v1/series?match[]=' + encodeURIComponent(metric) + '&start=' + start + '&end=' + end;
 | 
			
		||||
 | 
			
		||||
      return this.datasource.metadataRequest(url).then(result => {
 | 
			
		||||
      return this.datasource.metadataRequest(url).then((result: any) => {
 | 
			
		||||
        const _labels = _.map(result.data.data, metric => {
 | 
			
		||||
          return metric[label] || '';
 | 
			
		||||
        }).filter(label => {
 | 
			
		||||
| 
						 | 
				
			
			@ -88,10 +90,10 @@ export default class PrometheusMetricFindQuery {
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  metricNameQuery(metricFilterPattern) {
 | 
			
		||||
  metricNameQuery(metricFilterPattern: string) {
 | 
			
		||||
    const url = '/api/v1/label/__name__/values';
 | 
			
		||||
 | 
			
		||||
    return this.datasource.metadataRequest(url).then(result => {
 | 
			
		||||
    return this.datasource.metadataRequest(url).then((result: any) => {
 | 
			
		||||
      return _.chain(result.data.data)
 | 
			
		||||
        .filter(metricName => {
 | 
			
		||||
          const r = new RegExp(metricFilterPattern);
 | 
			
		||||
| 
						 | 
				
			
			@ -107,9 +109,10 @@ export default class PrometheusMetricFindQuery {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  queryResultQuery(query) {
 | 
			
		||||
  queryResultQuery(query: string) {
 | 
			
		||||
    const end = this.datasource.getPrometheusTime(this.range.to, true);
 | 
			
		||||
    return this.datasource.performInstantQuery({ expr: query }, end).then(result => {
 | 
			
		||||
    const instantQuery: PromQueryRequest = { expr: query } as PromQueryRequest;
 | 
			
		||||
    return this.datasource.performInstantQuery(instantQuery, end).then((result: PromDataQueryResponse) => {
 | 
			
		||||
      return _.map(result.data.data.result, metricData => {
 | 
			
		||||
        let text = metricData.metric.__name__ || '';
 | 
			
		||||
        delete metricData.metric.__name__;
 | 
			
		||||
| 
						 | 
				
			
			@ -129,14 +132,14 @@ export default class PrometheusMetricFindQuery {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  metricNameAndLabelsQuery(query) {
 | 
			
		||||
  metricNameAndLabelsQuery(query: string) {
 | 
			
		||||
    const start = this.datasource.getPrometheusTime(this.range.from, false);
 | 
			
		||||
    const end = this.datasource.getPrometheusTime(this.range.to, true);
 | 
			
		||||
    const url = '/api/v1/series?match[]=' + encodeURIComponent(query) + '&start=' + start + '&end=' + end;
 | 
			
		||||
 | 
			
		||||
    const self = this;
 | 
			
		||||
    return this.datasource.metadataRequest(url).then(result => {
 | 
			
		||||
      return _.map(result.data.data, metric => {
 | 
			
		||||
    return this.datasource.metadataRequest(url).then((result: PromDataQueryResponse) => {
 | 
			
		||||
      return _.map(result.data.data, (metric: { [key: string]: string }) => {
 | 
			
		||||
        return {
 | 
			
		||||
          text: self.datasource.getOriginalMetricName(metric),
 | 
			
		||||
          expandable: true,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ import { QueryCtrl } from 'app/plugins/sdk';
 | 
			
		|||
import { PromCompleter } from './completer';
 | 
			
		||||
import './mode-prometheus';
 | 
			
		||||
import './snippets/prometheus';
 | 
			
		||||
import { TemplateSrv } from 'app/features/templating/template_srv';
 | 
			
		||||
 | 
			
		||||
class PrometheusQueryCtrl extends QueryCtrl {
 | 
			
		||||
  static templateUrl = 'partials/query.editor.html';
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +19,7 @@ class PrometheusQueryCtrl extends QueryCtrl {
 | 
			
		|||
  linkToPrometheus: any;
 | 
			
		||||
 | 
			
		||||
  /** @ngInject */
 | 
			
		||||
  constructor($scope, $injector, private templateSrv) {
 | 
			
		||||
  constructor($scope: any, $injector: angular.auto.IInjectorService, private templateSrv: TemplateSrv) {
 | 
			
		||||
    super($scope, $injector);
 | 
			
		||||
 | 
			
		||||
    const target = this.target;
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +43,7 @@ class PrometheusQueryCtrl extends QueryCtrl {
 | 
			
		|||
    this.updateLink();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getCompleter(query) {
 | 
			
		||||
  getCompleter(query: string) {
 | 
			
		||||
    return new PromCompleter(this.datasource, this.templateSrv);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,12 @@
 | 
			
		|||
import _ from 'lodash';
 | 
			
		||||
import { QueryHint } from '@grafana/ui/src/types';
 | 
			
		||||
import { QueryHint, QueryFix } from '@grafana/ui/src/types';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Number of time series results needed before starting to suggest sum aggregation hints
 | 
			
		||||
 */
 | 
			
		||||
export const SUM_HINT_THRESHOLD_COUNT = 20;
 | 
			
		||||
 | 
			
		||||
export function getQueryHints(query: string, series?: any[], datasource?: any): QueryHint[] {
 | 
			
		||||
export function getQueryHints(query: string, series?: any[], datasource?: any): QueryHint[] | null {
 | 
			
		||||
  const hints = [];
 | 
			
		||||
 | 
			
		||||
  // ..._bucket metric needs a histogram_quantile()
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ export function getQueryHints(query: string, series?: any[], datasource?: any):
 | 
			
		|||
          type: 'ADD_HISTOGRAM_QUANTILE',
 | 
			
		||||
          query,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      } as QueryFix,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +44,7 @@ export function getQueryHints(query: string, series?: any[], datasource?: any):
 | 
			
		|||
        if (increasing && monotonic) {
 | 
			
		||||
          const simpleMetric = query.trim().match(/^\w+$/);
 | 
			
		||||
          let label = 'Time series is monotonically increasing.';
 | 
			
		||||
          let fix;
 | 
			
		||||
          let fix: QueryFix;
 | 
			
		||||
          if (simpleMetric) {
 | 
			
		||||
            fix = {
 | 
			
		||||
              label: 'Fix by adding rate().',
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ export function getQueryHints(query: string, series?: any[], datasource?: any):
 | 
			
		|||
                type: 'ADD_RATE',
 | 
			
		||||
                query,
 | 
			
		||||
              },
 | 
			
		||||
            };
 | 
			
		||||
            } as QueryFix;
 | 
			
		||||
          } else {
 | 
			
		||||
            label = `${label} Try applying a rate() function.`;
 | 
			
		||||
          }
 | 
			
		||||
| 
						 | 
				
			
			@ -83,14 +83,14 @@ export function getQueryHints(query: string, series?: any[], datasource?: any):
 | 
			
		|||
      hints.push({
 | 
			
		||||
        type: 'EXPAND_RULES',
 | 
			
		||||
        label,
 | 
			
		||||
        fix: {
 | 
			
		||||
        fix: ({
 | 
			
		||||
          label: 'Expand rules',
 | 
			
		||||
          action: {
 | 
			
		||||
            type: 'EXPAND_RULES',
 | 
			
		||||
            query,
 | 
			
		||||
            mapping: mappingForQuery,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        } as any) as QueryFix,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +108,7 @@ export function getQueryHints(query: string, series?: any[], datasource?: any):
 | 
			
		|||
            query: query,
 | 
			
		||||
            preventSubmit: true,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        } as QueryFix,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,10 @@
 | 
			
		|||
import _ from 'lodash';
 | 
			
		||||
import TableModel from 'app/core/table_model';
 | 
			
		||||
import { TimeSeries, FieldType } from '@grafana/ui';
 | 
			
		||||
import { TemplateSrv } from 'app/features/templating/template_srv';
 | 
			
		||||
 | 
			
		||||
export class ResultTransformer {
 | 
			
		||||
  constructor(private templateSrv) {}
 | 
			
		||||
  constructor(private templateSrv: TemplateSrv) {}
 | 
			
		||||
 | 
			
		||||
  transform(response: any, options: any): any[] {
 | 
			
		||||
    const prometheusResult = response.data.data.result;
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +40,7 @@ export class ResultTransformer {
 | 
			
		|||
    return [];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  transformMetricData(metricData, options, start, end) {
 | 
			
		||||
  transformMetricData(metricData: any, options: any, start: number, end: number) {
 | 
			
		||||
    const dps = [];
 | 
			
		||||
    let metricLabel = null;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -78,10 +79,10 @@ export class ResultTransformer {
 | 
			
		|||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  transformMetricDataToTable(md, resultCount: number, refId: string, valueWithRefId?: boolean) {
 | 
			
		||||
  transformMetricDataToTable(md: any, resultCount: number, refId: string, valueWithRefId?: boolean) {
 | 
			
		||||
    const table = new TableModel();
 | 
			
		||||
    let i, j;
 | 
			
		||||
    const metricLabels = {};
 | 
			
		||||
    let i: number, j: number;
 | 
			
		||||
    const metricLabels: { [key: string]: number } = {};
 | 
			
		||||
 | 
			
		||||
    if (!md || md.length === 0) {
 | 
			
		||||
      return table;
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +135,7 @@ export class ResultTransformer {
 | 
			
		|||
    return table;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  transformInstantMetricData(md, options) {
 | 
			
		||||
  transformInstantMetricData(md: any, options: any) {
 | 
			
		||||
    const dps = [];
 | 
			
		||||
    let metricLabel = null;
 | 
			
		||||
    metricLabel = this.createMetricLabel(md.metric, options);
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +143,7 @@ export class ResultTransformer {
 | 
			
		|||
    return { target: metricLabel, datapoints: dps, labels: md.metric };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  createMetricLabel(labelData, options) {
 | 
			
		||||
  createMetricLabel(labelData: { [key: string]: string }, options: any) {
 | 
			
		||||
    let label = '';
 | 
			
		||||
    if (_.isUndefined(options) || _.isEmpty(options.legendFormat)) {
 | 
			
		||||
      label = this.getOriginalMetricName(labelData);
 | 
			
		||||
| 
						 | 
				
			
			@ -155,7 +156,7 @@ export class ResultTransformer {
 | 
			
		|||
    return label;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  renderTemplate(aliasPattern, aliasData) {
 | 
			
		||||
  renderTemplate(aliasPattern: string, aliasData: { [key: string]: string }) {
 | 
			
		||||
    const aliasRegex = /\{\{\s*(.+?)\s*\}\}/g;
 | 
			
		||||
    return aliasPattern.replace(aliasRegex, (match, g1) => {
 | 
			
		||||
      if (aliasData[g1]) {
 | 
			
		||||
| 
						 | 
				
			
			@ -165,7 +166,7 @@ export class ResultTransformer {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getOriginalMetricName(labelData) {
 | 
			
		||||
  getOriginalMetricName(labelData: { [key: string]: string }) {
 | 
			
		||||
    const metricName = labelData.__name__ || '';
 | 
			
		||||
    delete labelData.__name__;
 | 
			
		||||
    const labelPart = _.map(_.toPairs(labelData), label => {
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +175,7 @@ export class ResultTransformer {
 | 
			
		|||
    return metricName + '{' + labelPart + '}';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  transformToHistogramOverTime(seriesList) {
 | 
			
		||||
  transformToHistogramOverTime(seriesList: TimeSeries[]) {
 | 
			
		||||
    /*      t1 = timestamp1, t2 = timestamp2 etc.
 | 
			
		||||
            t1  t2  t3          t1  t2  t3
 | 
			
		||||
    le10    10  10  0     =>    10  10  0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ jest.mock('../datasource');
 | 
			
		|||
jest.mock('@grafana/ui');
 | 
			
		||||
 | 
			
		||||
describe('Prometheus editor completer', () => {
 | 
			
		||||
  function getSessionStub(data) {
 | 
			
		||||
  function getSessionStub(data: any) {
 | 
			
		||||
    return {
 | 
			
		||||
      getTokenAt: jest.fn(() => data.currentToken),
 | 
			
		||||
      getTokens: jest.fn(() => data.tokens),
 | 
			
		||||
| 
						 | 
				
			
			@ -37,14 +37,14 @@ describe('Prometheus editor completer', () => {
 | 
			
		|||
  });
 | 
			
		||||
  datasourceStub.performSuggestQuery = jest.fn(() => Promise.resolve(['node_cpu']));
 | 
			
		||||
 | 
			
		||||
  const templateSrv = {
 | 
			
		||||
  const templateSrv: TemplateSrv = ({
 | 
			
		||||
    variables: [
 | 
			
		||||
      {
 | 
			
		||||
        name: 'var_name',
 | 
			
		||||
        options: [{ text: 'foo', value: 'foo', selected: false }, { text: 'bar', value: 'bar', selected: true }],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  };
 | 
			
		||||
  } as any) as TemplateSrv;
 | 
			
		||||
  const completer = new PromCompleter(datasourceStub, templateSrv);
 | 
			
		||||
 | 
			
		||||
  describe('When inside brackets', () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +55,7 @@ describe('Prometheus editor completer', () => {
 | 
			
		|||
        line: 'node_cpu[',
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return completer.getCompletions(editor, session, { row: 0, column: 10 }, '[', (s, res) => {
 | 
			
		||||
      return completer.getCompletions(editor, session, { row: 0, column: 10 }, '[', (s: any, res: any) => {
 | 
			
		||||
        expect(res[0].caption).toEqual('$__interval');
 | 
			
		||||
        expect(res[0].value).toEqual('[$__interval');
 | 
			
		||||
        expect(res[0].meta).toEqual('range vector');
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +86,7 @@ describe('Prometheus editor completer', () => {
 | 
			
		|||
        line: 'node_cpu{j}',
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return completer.getCompletions(editor, session, { row: 0, column: 10 }, 'j', (s, res) => {
 | 
			
		||||
      return completer.getCompletions(editor, session, { row: 0, column: 10 }, 'j', (s: any, res: any) => {
 | 
			
		||||
        expect(res[0].meta).toEqual('label name');
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +118,7 @@ describe('Prometheus editor completer', () => {
 | 
			
		|||
        line: '{__name__=~"node_cpu",j}',
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return completer.getCompletions(editor, session, { row: 0, column: 23 }, 'j', (s, res) => {
 | 
			
		||||
      return completer.getCompletions(editor, session, { row: 0, column: 23 }, 'j', (s: any, res: any) => {
 | 
			
		||||
        expect(res[0].meta).toEqual('label name');
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -149,7 +149,7 @@ describe('Prometheus editor completer', () => {
 | 
			
		|||
        line: 'node_cpu{job="n"}',
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return completer.getCompletions(editor, session, { row: 0, column: 15 }, 'n', (s, res) => {
 | 
			
		||||
      return completer.getCompletions(editor, session, { row: 0, column: 15 }, 'n', (s: any, res: any) => {
 | 
			
		||||
        expect(res[0].meta).toEqual('label value');
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -185,7 +185,7 @@ describe('Prometheus editor completer', () => {
 | 
			
		|||
        line: '(count(node_cpu)) by (m)',
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return completer.getCompletions(editor, session, { row: 0, column: 23 }, 'm', (s, res) => {
 | 
			
		||||
      return completer.getCompletions(editor, session, { row: 0, column: 23 }, 'm', (s: any, res: any) => {
 | 
			
		||||
        expect(res[0].meta).toEqual('label name');
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
import _ from 'lodash';
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
import q from 'q';
 | 
			
		||||
import {
 | 
			
		||||
  alignRange,
 | 
			
		||||
| 
						 | 
				
			
			@ -8,7 +9,7 @@ import {
 | 
			
		|||
  prometheusSpecialRegexEscape,
 | 
			
		||||
} from '../datasource';
 | 
			
		||||
import { dateTime } from '@grafana/ui/src/utils/moment_wrapper';
 | 
			
		||||
import { DataSourceInstanceSettings } from '@grafana/ui';
 | 
			
		||||
import { DataSourceInstanceSettings, DataQueryResponseData } from '@grafana/ui';
 | 
			
		||||
import { PromOptions } from '../types';
 | 
			
		||||
import { TemplateSrv } from 'app/features/templating/template_srv';
 | 
			
		||||
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
 | 
			
		||||
| 
						 | 
				
			
			@ -17,8 +18,8 @@ import { CustomVariable } from 'app/features/templating/custom_variable';
 | 
			
		|||
jest.mock('../metric_find_query');
 | 
			
		||||
 | 
			
		||||
const DEFAULT_TEMPLATE_SRV_MOCK = {
 | 
			
		||||
  getAdhocFilters: () => [],
 | 
			
		||||
  replace: a => a,
 | 
			
		||||
  getAdhocFilters: () => [] as any[],
 | 
			
		||||
  replace: (a: string) => a,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
describe('PrometheusDatasource', () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +180,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
      ];
 | 
			
		||||
 | 
			
		||||
      ctx.ds.performTimeSeriesQuery = jest.fn().mockReturnValue(responseMock);
 | 
			
		||||
      return ctx.ds.query(ctx.query).then(result => {
 | 
			
		||||
      return ctx.ds.query(ctx.query).then((result: any) => {
 | 
			
		||||
        const results = result.data;
 | 
			
		||||
        return expect(results).toMatchObject(expected);
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +210,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
      const expected = ['1', '2', '4', '+Inf'];
 | 
			
		||||
 | 
			
		||||
      ctx.ds.performTimeSeriesQuery = jest.fn().mockReturnValue(responseMock);
 | 
			
		||||
      return ctx.ds.query(ctx.query).then(result => {
 | 
			
		||||
      return ctx.ds.query(ctx.query).then((result: any) => {
 | 
			
		||||
        const seriesLabels = _.map(result.data, 'target');
 | 
			
		||||
        return expect(seriesLabels).toEqual(expected);
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			@ -412,7 +413,7 @@ const backendSrv = {
 | 
			
		|||
} as any;
 | 
			
		||||
 | 
			
		||||
const templateSrv = ({
 | 
			
		||||
  getAdhocFilters: () => [],
 | 
			
		||||
  getAdhocFilters: (): any[] => [],
 | 
			
		||||
  replace: jest.fn(str => str),
 | 
			
		||||
} as unknown) as TemplateSrv;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -424,7 +425,7 @@ const timeSrv = ({
 | 
			
		|||
 | 
			
		||||
describe('PrometheusDatasource', () => {
 | 
			
		||||
  describe('When querying prometheus with one target using query editor target spec', () => {
 | 
			
		||||
    let results;
 | 
			
		||||
    let results: any;
 | 
			
		||||
    const query = {
 | 
			
		||||
      range: { from: time({ seconds: 63 }), to: time({ seconds: 183 }) },
 | 
			
		||||
      targets: [{ expr: 'test{job="testjob"}', format: 'time_series' }],
 | 
			
		||||
| 
						 | 
				
			
			@ -452,7 +453,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
      backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response));
 | 
			
		||||
      ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv as any, templateSrv as any, timeSrv as any);
 | 
			
		||||
 | 
			
		||||
      await ctx.ds.query(query).then(data => {
 | 
			
		||||
      await ctx.ds.query(query).then((data: any) => {
 | 
			
		||||
        results = data;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -468,7 +469,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
    });
 | 
			
		||||
  });
 | 
			
		||||
  describe('When querying prometheus with one target which returns multiple series', () => {
 | 
			
		||||
    let results;
 | 
			
		||||
    let results: any;
 | 
			
		||||
    const start = 60;
 | 
			
		||||
    const end = 360;
 | 
			
		||||
    const step = 60;
 | 
			
		||||
| 
						 | 
				
			
			@ -502,7 +503,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
      backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response));
 | 
			
		||||
      ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv as any, templateSrv as any, timeSrv as any);
 | 
			
		||||
 | 
			
		||||
      await ctx.ds.query(query).then(data => {
 | 
			
		||||
      await ctx.ds.query(query).then((data: any) => {
 | 
			
		||||
        results = data;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -536,7 +537,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
    });
 | 
			
		||||
  });
 | 
			
		||||
  describe('When querying prometheus with one target and instant = true', () => {
 | 
			
		||||
    let results;
 | 
			
		||||
    let results: any;
 | 
			
		||||
    const urlExpected = 'proxied/api/v1/query?query=' + encodeURIComponent('test{job="testjob"}') + '&time=123';
 | 
			
		||||
    const query = {
 | 
			
		||||
      range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) },
 | 
			
		||||
| 
						 | 
				
			
			@ -563,7 +564,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
      backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response));
 | 
			
		||||
      ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv as any, templateSrv as any, timeSrv as any);
 | 
			
		||||
 | 
			
		||||
      await ctx.ds.query(query).then(data => {
 | 
			
		||||
      await ctx.ds.query(query).then((data: any) => {
 | 
			
		||||
        results = data;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -578,7 +579,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
    });
 | 
			
		||||
  });
 | 
			
		||||
  describe('When performing annotationQuery', () => {
 | 
			
		||||
    let results;
 | 
			
		||||
    let results: any;
 | 
			
		||||
 | 
			
		||||
    const options: any = {
 | 
			
		||||
      annotation: {
 | 
			
		||||
| 
						 | 
				
			
			@ -620,7 +621,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
        backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response));
 | 
			
		||||
        ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv as any, templateSrv as any, timeSrv as any);
 | 
			
		||||
 | 
			
		||||
        await ctx.ds.annotationQuery(options).then(data => {
 | 
			
		||||
        await ctx.ds.annotationQuery(options).then((data: any) => {
 | 
			
		||||
          results = data;
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			@ -640,7 +641,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
        backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response));
 | 
			
		||||
        ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv as any, templateSrv as any, timeSrv as any);
 | 
			
		||||
 | 
			
		||||
        await ctx.ds.annotationQuery(options).then(data => {
 | 
			
		||||
        await ctx.ds.annotationQuery(options).then((data: any) => {
 | 
			
		||||
          results = data;
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			@ -725,7 +726,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
  });
 | 
			
		||||
 | 
			
		||||
  describe('When resultFormat is table and instant = true', () => {
 | 
			
		||||
    let results;
 | 
			
		||||
    let results: any;
 | 
			
		||||
    const query = {
 | 
			
		||||
      range: { from: time({ seconds: 63 }), to: time({ seconds: 123 }) },
 | 
			
		||||
      targets: [{ expr: 'test{job="testjob"}', format: 'time_series', instant: true }],
 | 
			
		||||
| 
						 | 
				
			
			@ -750,7 +751,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
 | 
			
		||||
      backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response));
 | 
			
		||||
      ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv as any, templateSrv as any, timeSrv as any);
 | 
			
		||||
      await ctx.ds.query(query).then(data => {
 | 
			
		||||
      await ctx.ds.query(query).then((data: any) => {
 | 
			
		||||
        results = data;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -766,7 +767,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
      data: {
 | 
			
		||||
        data: {
 | 
			
		||||
          resultType: 'matrix',
 | 
			
		||||
          result: [],
 | 
			
		||||
          result: [] as DataQueryResponseData[],
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -963,7 +964,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
      data: {
 | 
			
		||||
        data: {
 | 
			
		||||
          resultType: 'matrix',
 | 
			
		||||
          result: [],
 | 
			
		||||
          result: [] as DataQueryResponseData[],
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -1232,7 +1233,7 @@ describe('PrometheusDatasource', () => {
 | 
			
		|||
      data: {
 | 
			
		||||
        data: {
 | 
			
		||||
          resultType: 'matrix',
 | 
			
		||||
          result: [],
 | 
			
		||||
          result: [] as DataQueryResponseData[],
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -1293,7 +1294,7 @@ describe('PrometheusDatasource for POST', () => {
 | 
			
		|||
  } as unknown) as DataSourceInstanceSettings<PromOptions>;
 | 
			
		||||
 | 
			
		||||
  describe('When querying prometheus with one target using query editor target spec', () => {
 | 
			
		||||
    let results;
 | 
			
		||||
    let results: any;
 | 
			
		||||
    const urlExpected = 'proxied/api/v1/query_range';
 | 
			
		||||
    const dataExpected = {
 | 
			
		||||
      query: 'test{job="testjob"}',
 | 
			
		||||
| 
						 | 
				
			
			@ -1324,7 +1325,7 @@ describe('PrometheusDatasource for POST', () => {
 | 
			
		|||
      };
 | 
			
		||||
      backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response));
 | 
			
		||||
      ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv as any, templateSrv as any, timeSrv as any);
 | 
			
		||||
      await ctx.ds.query(query).then(data => {
 | 
			
		||||
      await ctx.ds.query(query).then((data: any) => {
 | 
			
		||||
        results = data;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -1344,7 +1345,7 @@ describe('PrometheusDatasource for POST', () => {
 | 
			
		|||
    const options = { dashboardId: 1, panelId: 2 };
 | 
			
		||||
 | 
			
		||||
    const httpOptions = {
 | 
			
		||||
      headers: {},
 | 
			
		||||
      headers: {} as { [key: string]: number | undefined },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    it('with proxy access tracing headers should be added', () => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,11 @@
 | 
			
		|||
// @ts-ignore
 | 
			
		||||
import Plain from 'slate-plain-serializer';
 | 
			
		||||
 | 
			
		||||
import LanguageProvider from '../language_provider';
 | 
			
		||||
 | 
			
		||||
describe('Language completion provider', () => {
 | 
			
		||||
  const datasource = {
 | 
			
		||||
    metadataRequest: () => ({ data: { data: [] } }),
 | 
			
		||||
    metadataRequest: () => ({ data: { data: [] as any[] } }),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  describe('empty query suggestions', () => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import { PrometheusDatasource } from '../datasource';
 | 
			
		||||
import PrometheusMetricFindQuery from '../metric_find_query';
 | 
			
		||||
//@ts-ignore
 | 
			
		||||
import q from 'q';
 | 
			
		||||
import { toUtc } from '@grafana/ui/src/utils/moment_wrapper';
 | 
			
		||||
import { DataSourceInstanceSettings } from '@grafana/ui';
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +23,7 @@ describe('PrometheusMetricFindQuery', () => {
 | 
			
		|||
      datasourceRequest: jest.fn(() => Promise.resolve({})),
 | 
			
		||||
    },
 | 
			
		||||
    templateSrvMock: {
 | 
			
		||||
      replace: a => a,
 | 
			
		||||
      replace: (a: string) => a,
 | 
			
		||||
    },
 | 
			
		||||
    timeSrvMock: {
 | 
			
		||||
      timeRange: () => ({
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,12 @@
 | 
			
		|||
import { ResultTransformer } from '../result_transformer';
 | 
			
		||||
import { DataQueryResponseData } from '@grafana/ui';
 | 
			
		||||
 | 
			
		||||
describe('Prometheus Result Transformer', () => {
 | 
			
		||||
  const ctx: any = {};
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    ctx.templateSrv = {
 | 
			
		||||
      replace: str => str,
 | 
			
		||||
      replace: (str: string) => str,
 | 
			
		||||
    };
 | 
			
		||||
    ctx.resultTransformer = new ResultTransformer(ctx.templateSrv);
 | 
			
		||||
  });
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +17,7 @@ describe('Prometheus Result Transformer', () => {
 | 
			
		|||
        status: 'success',
 | 
			
		||||
        data: {
 | 
			
		||||
          resultType: '',
 | 
			
		||||
          result: null,
 | 
			
		||||
          result: null as DataQueryResponseData[],
 | 
			
		||||
        },
 | 
			
		||||
      };
 | 
			
		||||
      const series = ctx.resultTransformer.transform({ data: response }, {});
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +28,7 @@ describe('Prometheus Result Transformer', () => {
 | 
			
		|||
        status: 'success',
 | 
			
		||||
        data: {
 | 
			
		||||
          resultType: '',
 | 
			
		||||
          result: null,
 | 
			
		||||
          result: null as DataQueryResponseData[],
 | 
			
		||||
        },
 | 
			
		||||
      };
 | 
			
		||||
      const table = ctx.resultTransformer.transform({ data: response }, { format: 'table' });
 | 
			
		||||
| 
						 | 
				
			
			@ -168,7 +169,7 @@ describe('Prometheus Result Transformer', () => {
 | 
			
		|||
    });
 | 
			
		||||
 | 
			
		||||
    it('should throw error when data in wrong format', () => {
 | 
			
		||||
      const seriesList = [{ rows: [] }, { datapoints: [] }];
 | 
			
		||||
      const seriesList = [{ rows: [] as any[] }, { datapoints: [] as any[] }];
 | 
			
		||||
      expect(() => {
 | 
			
		||||
        ctx.resultTransformer.transformToHistogramOverTime(seriesList);
 | 
			
		||||
      }).toThrow();
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +177,7 @@ describe('Prometheus Result Transformer', () => {
 | 
			
		|||
 | 
			
		||||
    it('should throw error when prometheus returned non-timeseries', () => {
 | 
			
		||||
      // should be { metric: {}, values: [] } for timeseries
 | 
			
		||||
      const metricData = { metric: {}, value: [] };
 | 
			
		||||
      const metricData = { metric: {}, value: [] as any[] };
 | 
			
		||||
      expect(() => {
 | 
			
		||||
        ctx.resultTransformer.transformMetricData(metricData, { step: 1 }, 1000, 2000);
 | 
			
		||||
      }).toThrow();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,4 +29,5 @@ export interface PromQueryRequest extends PromQuery {
 | 
			
		|||
  requestId?: string;
 | 
			
		||||
  start: number;
 | 
			
		||||
  end: number;
 | 
			
		||||
  headers?: any;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue