Commit 3424b642 by Hugo Häggmark Committed by GitHub

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/**/*
parent d6ee96ee
......@@ -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;
}
}
......
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;
......
// @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)"
......
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, '\\\\$&'));
}
......
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);
}
......
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,
});
}
}
......
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');
});
});
......
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', () => {
......
// @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', () => {
......
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: () => ({
......
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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment