mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Fix typescript strict null errors from 674 -> 565 (#26057)
* Chore: Fix typescript strict null errors * Added new limit * Fixed ts issue * fixed tests * trying to fix type inference * Fixing more ts errors * Revert tsconfig option * Fix * Fixed code * More fixes * fix tests * Updated snapshot
This commit is contained in:
parent
4fc984f771
commit
7e8bd0c1b7
@ -15,20 +15,10 @@ export interface DataSourcePluginOptionsEditorProps<JSONData = DataSourceJsonDat
|
||||
}
|
||||
|
||||
// Utility type to extract the query type TQuery from a class extending DataSourceApi<TQuery, TOptions>
|
||||
export type DataSourceQueryType<DSType extends DataSourceApi<any, any>> = DSType extends DataSourceApi<
|
||||
infer TQuery,
|
||||
infer _TOptions
|
||||
>
|
||||
? TQuery
|
||||
: never;
|
||||
export type DataSourceQueryType<DSType> = DSType extends DataSourceApi<infer TQuery, any> ? TQuery : never;
|
||||
|
||||
// Utility type to extract the options type TOptions from a class extending DataSourceApi<TQuery, TOptions>
|
||||
export type DataSourceOptionsType<DSType extends DataSourceApi<any, any>> = DSType extends DataSourceApi<
|
||||
infer _TQuery,
|
||||
infer TOptions
|
||||
>
|
||||
? TOptions
|
||||
: never;
|
||||
export type DataSourceOptionsType<DSType> = DSType extends DataSourceApi<any, infer TOptions> ? TOptions : never;
|
||||
|
||||
export class DataSourcePlugin<
|
||||
DSType extends DataSourceApi<TQuery, TOptions>,
|
||||
@ -453,7 +443,6 @@ export interface DataQueryTimings {
|
||||
}
|
||||
|
||||
export interface QueryFix {
|
||||
type: string;
|
||||
label: string;
|
||||
action?: QueryFixAction;
|
||||
}
|
||||
@ -472,6 +461,7 @@ export interface QueryHint {
|
||||
|
||||
export interface MetricFindValue {
|
||||
text: string;
|
||||
expandable?: boolean;
|
||||
}
|
||||
|
||||
export interface DataSourceJsonData {
|
||||
|
@ -230,7 +230,7 @@ kbn.interval_to_ms = (str: string) => {
|
||||
return info.sec * 1000 * info.count;
|
||||
};
|
||||
|
||||
kbn.interval_to_seconds = (str: string) => {
|
||||
kbn.interval_to_seconds = (str: string): number => {
|
||||
const info = kbn.describe_interval(str);
|
||||
return info.sec * info.count;
|
||||
};
|
||||
|
@ -58,7 +58,7 @@ export interface GetDataOptions {
|
||||
}
|
||||
|
||||
export class PanelQueryRunner {
|
||||
private subject?: ReplaySubject<PanelData>;
|
||||
private subject: ReplaySubject<PanelData>;
|
||||
private subscription?: Unsubscribable;
|
||||
private lastResult?: PanelData;
|
||||
private dataConfigSource: DataConfigSource;
|
||||
@ -244,7 +244,7 @@ export class PanelQueryRunner {
|
||||
}
|
||||
}
|
||||
|
||||
getLastResult(): PanelData {
|
||||
getLastResult(): PanelData | undefined {
|
||||
return this.lastResult;
|
||||
}
|
||||
}
|
||||
|
@ -265,9 +265,9 @@ export class TemplateSrv implements BaseTemplateSrv {
|
||||
return variableName;
|
||||
}
|
||||
|
||||
variableExists(expression: string) {
|
||||
variableExists(expression: string): boolean {
|
||||
const name = this.getVariableName(expression);
|
||||
return name && this.getVariableAtIndex(name) !== void 0;
|
||||
return (name && this.getVariableAtIndex(name)) !== undefined;
|
||||
}
|
||||
|
||||
highlightVariablesAsHtml(str: string) {
|
||||
|
@ -77,6 +77,7 @@ exports[`LokiExploreQueryEditor should render component 1`] = `
|
||||
},
|
||||
Symbol(length): 0,
|
||||
},
|
||||
"logLabelFetchTs": 0,
|
||||
"request": [Function],
|
||||
"seriesCache": LRUCache {
|
||||
Symbol(max): 10,
|
||||
|
@ -8,7 +8,7 @@ import { ArrayVector, Field, FieldType, LinkModel } from '@grafana/data';
|
||||
import { getFieldLinksForExplore } from '../../../../features/explore/utils/links';
|
||||
|
||||
type Props = {
|
||||
derivedFields: DerivedFieldConfig[];
|
||||
derivedFields?: DerivedFieldConfig[];
|
||||
className?: string;
|
||||
};
|
||||
export const DebugSection = (props: Props) => {
|
||||
@ -92,7 +92,7 @@ function makeDebugFields(derivedFields: DerivedFieldConfig[], debugText: string)
|
||||
try {
|
||||
const testMatch = debugText.match(field.matcherRegex);
|
||||
const value = testMatch && testMatch[1];
|
||||
let link: LinkModel<Field> = null;
|
||||
let link: LinkModel<Field> | null = null;
|
||||
|
||||
if (field.url && value) {
|
||||
link = getFieldLinksForExplore(
|
||||
@ -116,7 +116,6 @@ function makeDebugFields(derivedFields: DerivedFieldConfig[], debugText: string)
|
||||
href: link && link.href,
|
||||
} as DebugField;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return {
|
||||
name: field.name,
|
||||
error,
|
||||
|
@ -20,6 +20,7 @@ type Props = {
|
||||
value?: DerivedFieldConfig[];
|
||||
onChange: (value: DerivedFieldConfig[]) => void;
|
||||
};
|
||||
|
||||
export const DerivedFields = (props: Props) => {
|
||||
const { value, onChange } = props;
|
||||
const theme = useTheme();
|
||||
|
@ -370,7 +370,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
||||
|
||||
getTime(date: string | DateTime, roundUp: boolean) {
|
||||
if (typeof date === 'string') {
|
||||
date = dateMath.parse(date, roundUp);
|
||||
date = dateMath.parse(date, roundUp)!;
|
||||
}
|
||||
|
||||
return Math.ceil(date.valueOf() * 1e6);
|
||||
@ -517,9 +517,9 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
showContextToggle = (row?: LogRowModel) => {
|
||||
return row && row.searchWords && row.searchWords.length > 0;
|
||||
};
|
||||
showContextToggle(row?: LogRowModel): boolean {
|
||||
return (row && row.searchWords && row.searchWords.length > 0) === true;
|
||||
}
|
||||
|
||||
throwUnless = (err: any, condition: boolean, target: LokiQuery) => {
|
||||
if (condition) {
|
||||
|
@ -58,7 +58,7 @@ export function addHistoryMetadata(item: CompletionItem, history: LokiHistoryIte
|
||||
export default class LokiLanguageProvider extends LanguageProvider {
|
||||
labelKeys: string[];
|
||||
logLabelOptions: any[];
|
||||
logLabelFetchTs?: number;
|
||||
logLabelFetchTs: number;
|
||||
started: boolean;
|
||||
initialRange: AbsoluteTimeRange;
|
||||
datasource: LokiDatasource;
|
||||
@ -77,6 +77,7 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
|
||||
this.datasource = datasource;
|
||||
this.labelKeys = [];
|
||||
this.logLabelFetchTs = 0;
|
||||
|
||||
Object.assign(this, initialValues);
|
||||
}
|
||||
@ -127,6 +128,11 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
*/
|
||||
async provideCompletionItems(input: TypeaheadInput, context?: TypeaheadContext): Promise<TypeaheadOutput> {
|
||||
const { wrapperClasses, value, prefix, text } = input;
|
||||
const emptyResult: TypeaheadOutput = { suggestions: [] };
|
||||
|
||||
if (!value) {
|
||||
return emptyResult;
|
||||
}
|
||||
|
||||
// Local text properties
|
||||
const empty = value?.document.text.length === 0;
|
||||
@ -169,18 +175,16 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
return this.getTermCompletionItems();
|
||||
}
|
||||
|
||||
return {
|
||||
suggestions: [],
|
||||
};
|
||||
return emptyResult;
|
||||
}
|
||||
|
||||
getBeginningCompletionItems = (context: TypeaheadContext): TypeaheadOutput => {
|
||||
getBeginningCompletionItems = (context?: TypeaheadContext): TypeaheadOutput => {
|
||||
return {
|
||||
suggestions: [...this.getEmptyCompletionItems(context).suggestions, ...this.getTermCompletionItems().suggestions],
|
||||
};
|
||||
};
|
||||
|
||||
getEmptyCompletionItems(context: TypeaheadContext): TypeaheadOutput {
|
||||
getEmptyCompletionItems(context?: TypeaheadContext): TypeaheadOutput {
|
||||
const history = context?.history;
|
||||
const suggestions = [];
|
||||
|
||||
@ -386,7 +390,7 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
async fetchLogLabels(absoluteRange: AbsoluteTimeRange): Promise<any> {
|
||||
const url = '/loki/api/v1/label';
|
||||
try {
|
||||
this.logLabelFetchTs = Date.now();
|
||||
this.logLabelFetchTs = Date.now().valueOf();
|
||||
const rangeParams = absoluteRange ? rangeToParams(absoluteRange) : {};
|
||||
const res = await this.request(url, rangeParams);
|
||||
this.labelKeys = res.slice().sort();
|
||||
@ -398,7 +402,7 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
}
|
||||
|
||||
async refreshLogLabels(absoluteRange: AbsoluteTimeRange, forceRefresh?: boolean) {
|
||||
if ((this.labelKeys && Date.now() - this.logLabelFetchTs > LABEL_REFRESH_INTERVAL) || forceRefresh) {
|
||||
if ((this.labelKeys && Date.now().valueOf() - this.logLabelFetchTs > LABEL_REFRESH_INTERVAL) || forceRefresh) {
|
||||
await this.fetchLogLabels(absoluteRange);
|
||||
}
|
||||
}
|
||||
@ -409,7 +413,7 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
* @param name
|
||||
*/
|
||||
fetchSeriesLabels = async (match: string, absoluteRange: AbsoluteTimeRange): Promise<Record<string, string[]>> => {
|
||||
const rangeParams: { start?: number; end?: number } = absoluteRange ? rangeToParams(absoluteRange) : {};
|
||||
const rangeParams = absoluteRange ? rangeToParams(absoluteRange) : { start: 0, end: 0 };
|
||||
const url = '/loki/api/v1/series';
|
||||
const { start, end } = rangeParams;
|
||||
|
||||
@ -447,7 +451,7 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
async fetchLabelValues(key: string, absoluteRange: AbsoluteTimeRange): Promise<string[]> {
|
||||
const url = `/loki/api/v1/label/${key}/values`;
|
||||
let values: string[] = [];
|
||||
const rangeParams: { start?: number; end?: number } = absoluteRange ? rangeToParams(absoluteRange) : {};
|
||||
const rangeParams = absoluteRange ? rangeToParams(absoluteRange) : { start: 0, end: 0 };
|
||||
const { start, end } = rangeParams;
|
||||
|
||||
const cacheKey = this.generateCacheKey(url, start, end, key);
|
||||
|
@ -18,7 +18,7 @@ describe('getHighlighterExpressionsFromQuery', () => {
|
||||
});
|
||||
|
||||
it('returns null if filter term is not wrapped in double quotes', () => {
|
||||
expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= x')).toEqual(null);
|
||||
expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= x')).toEqual([]);
|
||||
});
|
||||
|
||||
it('escapes filter term if regex filter operator is not used', () => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import escapeRegExp from 'lodash/escapeRegExp';
|
||||
|
||||
export function formatQuery(selector: string): string {
|
||||
export function formatQuery(selector: string | undefined): string {
|
||||
return `${selector || ''}`.trim();
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ export function formatQuery(selector: string): string {
|
||||
export function getHighlighterExpressionsFromQuery(input: string): string[] {
|
||||
let expression = input;
|
||||
const results = [];
|
||||
|
||||
// Consume filter expression from left to right
|
||||
while (expression) {
|
||||
const filterStart = expression.search(/\|=|\|~|!=|!~/);
|
||||
@ -43,8 +44,9 @@ export function getHighlighterExpressionsFromQuery(input: string): string[] {
|
||||
const regexOperator = filterOperator === '|~';
|
||||
results.push(regexOperator ? unwrappedFilterTerm : escapeRegExp(unwrappedFilterTerm));
|
||||
} else {
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
Field,
|
||||
QueryResultMetaStat,
|
||||
QueryResultMeta,
|
||||
TimeSeriesValue,
|
||||
} from '@grafana/data';
|
||||
|
||||
import templateSrv from 'app/features/templating/template_srv';
|
||||
@ -154,16 +155,14 @@ function lokiMatrixToTimeSeries(matrixResult: LokiMatrixResult, options: Transfo
|
||||
};
|
||||
}
|
||||
|
||||
function lokiPointsToTimeseriesPoints(
|
||||
data: Array<[number, string]>,
|
||||
options: TransformerOptions
|
||||
): Array<[number, number]> {
|
||||
function lokiPointsToTimeseriesPoints(data: Array<[number, string]>, options: TransformerOptions): TimeSeriesValue[][] {
|
||||
const stepMs = options.step * 1000;
|
||||
const datapoints: Array<[number, number]> = [];
|
||||
const datapoints: TimeSeriesValue[][] = [];
|
||||
|
||||
let baseTimestampMs = options.start / 1e6;
|
||||
for (const [time, value] of data) {
|
||||
let datapointValue = parseFloat(value);
|
||||
let datapointValue: TimeSeriesValue = parseFloat(value);
|
||||
|
||||
if (isNaN(datapointValue)) {
|
||||
datapointValue = null;
|
||||
}
|
||||
@ -198,7 +197,7 @@ export function lokiResultsToTableModel(
|
||||
|
||||
// Collect all labels across all metrics
|
||||
const metricLabels: Set<string> = new Set<string>(
|
||||
lokiResults.reduce((acc, cur) => acc.concat(Object.keys(cur.metric)), [])
|
||||
lokiResults.reduce((acc, cur) => acc.concat(Object.keys(cur.metric)), [] as string[])
|
||||
);
|
||||
|
||||
// Sort metric labels, create columns for them and record their index
|
||||
@ -245,9 +244,9 @@ function createMetricLabel(labelData: { [key: string]: string }, options?: Trans
|
||||
let label =
|
||||
options === undefined || _.isEmpty(options.legendFormat)
|
||||
? getOriginalMetricName(labelData)
|
||||
: renderTemplate(templateSrv.replace(options.legendFormat), labelData);
|
||||
: renderTemplate(templateSrv.replace(options.legendFormat ?? ''), labelData);
|
||||
|
||||
if (!label) {
|
||||
if (!label && options) {
|
||||
label = options.query;
|
||||
}
|
||||
return label;
|
||||
@ -272,11 +271,13 @@ export function decamelize(s: string): string {
|
||||
}
|
||||
|
||||
// Turn loki stats { metric: value } into meta stat { title: metric, value: value }
|
||||
function lokiStatsToMetaStat(stats: LokiStats): QueryResultMetaStat[] {
|
||||
function lokiStatsToMetaStat(stats: LokiStats | undefined): QueryResultMetaStat[] {
|
||||
const result: QueryResultMetaStat[] = [];
|
||||
|
||||
if (!stats) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const section in stats) {
|
||||
const values = stats[section];
|
||||
for (const label in values) {
|
||||
@ -293,6 +294,7 @@ function lokiStatsToMetaStat(stats: LokiStats): QueryResultMetaStat[] {
|
||||
result.push({ displayName: title, value, unit });
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -309,6 +311,7 @@ export function lokiStreamsToDataframes(
|
||||
const custom = {
|
||||
lokiQueryStatKey: 'Summary: total bytes processed',
|
||||
};
|
||||
|
||||
const series: DataFrame[] = data.map(stream => {
|
||||
const dataFrame = lokiStreamResultToDataFrame(stream, reverse);
|
||||
enhanceDataFrame(dataFrame, config);
|
||||
@ -406,10 +409,10 @@ export function rangeQueryResponseToTimeSeries(
|
||||
|
||||
const transformerOptions: TransformerOptions = {
|
||||
format: target.format,
|
||||
legendFormat: target.legendFormat,
|
||||
start: query.start,
|
||||
end: query.end,
|
||||
step: query.step,
|
||||
legendFormat: target.legendFormat ?? '',
|
||||
start: query.start!,
|
||||
end: query.end!,
|
||||
step: query.step!,
|
||||
query: query.query,
|
||||
responseListLength,
|
||||
refId: target.refId,
|
||||
|
@ -59,7 +59,7 @@ export interface LokiVectorResponse {
|
||||
}
|
||||
|
||||
export interface LokiMatrixResult {
|
||||
metric: { [label: string]: string };
|
||||
metric: Record<string, string>;
|
||||
values: Array<[number, string]>;
|
||||
}
|
||||
|
||||
@ -115,8 +115,8 @@ export type DerivedFieldConfig = {
|
||||
};
|
||||
|
||||
export interface TransformerOptions {
|
||||
format: string;
|
||||
legendFormat: string;
|
||||
format?: string;
|
||||
legendFormat?: string;
|
||||
step: number;
|
||||
start: number;
|
||||
end: number;
|
||||
|
@ -38,14 +38,17 @@ export class MixedDatasource extends DataSourceApi<DataQuery> {
|
||||
// Build groups of queries to run in parallel
|
||||
const sets: { [key: string]: DataQuery[] } = groupBy(queries, 'datasource');
|
||||
const mixed: BatchedQueries[] = [];
|
||||
|
||||
for (const key in sets) {
|
||||
const targets = sets[key];
|
||||
const dsName: string | undefined = targets[0].datasource;
|
||||
const dsName = targets[0].datasource;
|
||||
|
||||
mixed.push({
|
||||
datasource: getDataSourceSrv().get(dsName, request.scopedVars),
|
||||
targets,
|
||||
});
|
||||
}
|
||||
|
||||
return this.batchQueries(mixed, request);
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,8 @@ export default class OpenTsDatasource extends DataSourceApi<OpenTsdbQuery, OpenT
|
||||
|
||||
// Called once per panel (graph)
|
||||
query(options: DataQueryRequest<OpenTsdbQuery>) {
|
||||
const start = this.convertToTSDBTime(options.rangeRaw.from, false, options.timezone);
|
||||
const end = this.convertToTSDBTime(options.rangeRaw.to, true, options.timezone);
|
||||
const start = this.convertToTSDBTime(options.range.raw.from, false, options.timezone);
|
||||
const end = this.convertToTSDBTime(options.range.raw.to, true, options.timezone);
|
||||
const qs: any[] = [];
|
||||
|
||||
_.each(options.targets, target => {
|
||||
|
@ -19,7 +19,7 @@ export function PromExploreExtraField(props: PromExploreExtraFieldProps) {
|
||||
return (
|
||||
<div className="gf-form-inline" aria-label="Prometheus extra field">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel width={5} tooltip={hasTooltip ? tooltipContent : null}>
|
||||
<InlineFormLabel width={5} tooltip={hasTooltip ? tooltipContent : undefined}>
|
||||
{label}
|
||||
</InlineFormLabel>
|
||||
<input
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { memo } from 'react';
|
||||
import React, { memo, FC } from 'react';
|
||||
|
||||
// Types
|
||||
import { ExploreQueryFieldProps } from '@grafana/data';
|
||||
@ -11,7 +11,7 @@ import { PromExploreExtraField } from './PromExploreExtraField';
|
||||
|
||||
export type Props = ExploreQueryFieldProps<PrometheusDatasource, PromQuery, PromOptions>;
|
||||
|
||||
export function PromExploreQueryEditor(props: Props) {
|
||||
export const PromExploreQueryEditor: FC<Props> = (props: Props) => {
|
||||
const { query, data, datasource, history, onChange, onRunQuery } = props;
|
||||
|
||||
function onChangeQueryStep(value: string) {
|
||||
@ -55,6 +55,6 @@ export function PromExploreQueryEditor(props: Props) {
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default memo(PromExploreQueryEditor);
|
||||
|
@ -17,7 +17,8 @@ interface State {
|
||||
}
|
||||
|
||||
export default class PromLink extends Component<Props, State> {
|
||||
state: State = { href: null };
|
||||
state: State = { href: '' };
|
||||
|
||||
async componentDidUpdate(prevProps: Props) {
|
||||
const { panelData } = this.props;
|
||||
|
||||
|
@ -26,9 +26,9 @@ const INTERVAL_FACTOR_OPTIONS: Array<SelectableValue<number>> = _.map([1, 2, 3,
|
||||
}));
|
||||
|
||||
interface State {
|
||||
legendFormat: string;
|
||||
legendFormat?: string;
|
||||
formatOption: SelectableValue<string>;
|
||||
interval: string;
|
||||
interval?: string;
|
||||
intervalFactorOption: SelectableValue<number>;
|
||||
instant: boolean;
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
||||
|
||||
const result = isDataFrame(data.series[0]) ? data.series.map(toLegacyResponseData) : data.series;
|
||||
const hints = datasource.getQueryHints(query, result);
|
||||
const hint = hints && hints.length > 0 ? hints[0] : null;
|
||||
const hint = hints.length > 0 ? hints[0] : null;
|
||||
this.setState({ hint });
|
||||
};
|
||||
|
||||
@ -250,7 +250,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
||||
const { datasource, query, onChange, onRunQuery } = this.props;
|
||||
const { hint } = this.state;
|
||||
|
||||
onChange(datasource.modifyQuery(query, hint.fix.action));
|
||||
onChange(datasource.modifyQuery(query, hint!.fix!.action));
|
||||
onRunQuery();
|
||||
};
|
||||
|
||||
@ -277,7 +277,8 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
||||
: metricsByPrefix;
|
||||
|
||||
// Hint for big disabled lookups
|
||||
let hint: QueryHint;
|
||||
let hint: QueryHint | null = null;
|
||||
|
||||
if (!datasource.lookupsDisabled && languageProvider.lookupsDisabled) {
|
||||
hint = {
|
||||
label: `Dynamic label lookup is disabled for datasources with more than ${lookupMetricsThreshold} metrics.`,
|
||||
|
@ -9,7 +9,6 @@ exports[`PrometheusExploreExtraField should render component 1`] = `
|
||||
className="gf-form"
|
||||
>
|
||||
<Component
|
||||
tooltip={null}
|
||||
width={5}
|
||||
>
|
||||
Prometheus Explore Extra Field
|
||||
|
@ -78,7 +78,7 @@ export const PromSettings = (props: Props) => {
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<Switch
|
||||
checked={options.jsonData.disableMetricsLookup}
|
||||
checked={options.jsonData.disableMetricsLookup ?? false}
|
||||
label="Disable metrics lookup"
|
||||
labelClass="width-14"
|
||||
onChange={onUpdateDatasourceJsonDataOptionChecked(props, 'disableMetricsLookup')}
|
||||
|
@ -26,7 +26,7 @@ import { filter, map, tap } from 'rxjs/operators';
|
||||
import PrometheusMetricFindQuery from './metric_find_query';
|
||||
import { ResultTransformer } from './result_transformer';
|
||||
import PrometheusLanguageProvider from './language_provider';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { getBackendSrv, BackendSrvRequest } from '@grafana/runtime';
|
||||
import addLabelToQuery from './add_label_to_query';
|
||||
import { getQueryHints } from './query_hints';
|
||||
import { expandRecordingRules } from './language_utils';
|
||||
@ -39,17 +39,6 @@ import TableModel from 'app/core/table_model';
|
||||
|
||||
export const ANNOTATION_QUERY_STEP_DEFAULT = '60s';
|
||||
|
||||
interface RequestOptions {
|
||||
method?: string;
|
||||
url?: string;
|
||||
headers?: Record<string, string>;
|
||||
transformRequest?: (data: any) => string;
|
||||
data?: any;
|
||||
withCredentials?: boolean;
|
||||
silent?: boolean;
|
||||
requestId?: string;
|
||||
}
|
||||
|
||||
export interface PromDataQueryResponse {
|
||||
data: {
|
||||
status: string;
|
||||
@ -92,7 +81,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
|
||||
|
||||
this.type = 'prometheus';
|
||||
this.editorSrc = 'app/features/prometheus/partials/query.editor.html';
|
||||
this.url = instanceSettings.url;
|
||||
this.url = instanceSettings.url!;
|
||||
this.basicAuth = instanceSettings.basicAuth;
|
||||
this.withCredentials = instanceSettings.withCredentials;
|
||||
this.interval = instanceSettings.jsonData.timeInterval || '15s';
|
||||
@ -102,7 +91,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
|
||||
this.resultTransformer = new ResultTransformer(templateSrv);
|
||||
this.ruleMappings = {};
|
||||
this.languageProvider = new PrometheusLanguageProvider(this);
|
||||
this.lookupsDisabled = instanceSettings.jsonData.disableMetricsLookup;
|
||||
this.lookupsDisabled = instanceSettings.jsonData.disableMetricsLookup ?? false;
|
||||
this.customQueryParameters = new URLSearchParams(instanceSettings.jsonData.customQueryParameters);
|
||||
}
|
||||
|
||||
@ -123,8 +112,8 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
|
||||
}
|
||||
}
|
||||
|
||||
_request(url: string, data: Record<string, string> = {}, options?: RequestOptions) {
|
||||
options = defaults(options || {}, {
|
||||
_request(url: string, data: Record<string, string> | null, overrides?: Partial<BackendSrvRequest>) {
|
||||
const options: BackendSrvRequest = defaults(overrides || {}, {
|
||||
url: this.url + url,
|
||||
method: this.httpMethod,
|
||||
headers: {},
|
||||
@ -153,7 +142,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
|
||||
options.headers.Authorization = this.basicAuth;
|
||||
}
|
||||
|
||||
return getBackendSrv().datasourceRequest(options as Required<RequestOptions>);
|
||||
return getBackendSrv().datasourceRequest(options);
|
||||
}
|
||||
|
||||
// Use this for tab completion features, wont publish response to other components
|
||||
@ -271,13 +260,10 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
|
||||
let runningQueriesCount = queries.length;
|
||||
const subQueries = queries.map((query, index) => {
|
||||
const target = activeTargets[index];
|
||||
let observable: Observable<any> = null;
|
||||
|
||||
if (query.instant) {
|
||||
observable = from(this.performInstantQuery(query, end));
|
||||
} else {
|
||||
observable = from(this.performTimeSeriesQuery(query, query.start, query.end));
|
||||
}
|
||||
let observable = query.instant
|
||||
? from(this.performInstantQuery(query, end))
|
||||
: from(this.performTimeSeriesQuery(query, query.start, query.end));
|
||||
|
||||
return observable.pipe(
|
||||
// Decrease the counter here. We assume that each request returns only single value and then completes
|
||||
@ -301,13 +287,10 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
|
||||
private panelsQuery(queries: PromQueryRequest[], activeTargets: PromQuery[], end: number, requestId: string) {
|
||||
const observables: Array<Observable<Array<TableModel | TimeSeries>>> = queries.map((query, index) => {
|
||||
const target = activeTargets[index];
|
||||
let observable: Observable<any> = null;
|
||||
|
||||
if (query.instant) {
|
||||
observable = from(this.performInstantQuery(query, end));
|
||||
} else {
|
||||
observable = from(this.performTimeSeriesQuery(query, query.start, query.end));
|
||||
}
|
||||
let observable = query.instant
|
||||
? from(this.performInstantQuery(query, end))
|
||||
: from(this.performTimeSeriesQuery(query, query.start, query.end));
|
||||
|
||||
return observable.pipe(
|
||||
filter((response: any) => (response.cancelled ? false : true)),
|
||||
@ -346,10 +329,10 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
|
||||
const range = Math.ceil(end - start);
|
||||
|
||||
// options.interval is the dynamically calculated interval
|
||||
let interval = kbn.interval_to_seconds(options.interval);
|
||||
let interval: number = kbn.interval_to_seconds(options.interval);
|
||||
// Minimum interval ("Min step"), if specified for the query or datasource. or same as interval otherwise
|
||||
const minInterval = kbn.interval_to_seconds(
|
||||
templateSrv.replace(target.interval, options.scopedVars) || options.interval
|
||||
templateSrv.replace(target.interval || options.interval, options.scopedVars)
|
||||
);
|
||||
const intervalFactor = target.intervalFactor || 1;
|
||||
// Adjust the interval to take into account any specified minimum and interval factor plus Prometheus limits
|
||||
@ -576,7 +559,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
|
||||
return [];
|
||||
}
|
||||
|
||||
const step = Math.floor(query.step) * 1000;
|
||||
const step = Math.floor(query.step ?? 15) * 1000;
|
||||
|
||||
response?.data?.data?.result?.forEach(series => {
|
||||
const tags = Object.entries(series.metric)
|
||||
@ -596,16 +579,17 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
|
||||
});
|
||||
|
||||
const activeValues = series.values.filter((value: Record<number, string>) => parseFloat(value[1]) >= 1);
|
||||
const activeValuesTimestamps = activeValues.map((value: number[]) => value[0]);
|
||||
const activeValuesTimestamps: number[] = activeValues.map((value: number[]) => value[0]);
|
||||
|
||||
// Instead of creating singular annotation for each active event we group events into region if they are less
|
||||
// then `step` apart.
|
||||
let latestEvent: AnnotationEvent = null;
|
||||
activeValuesTimestamps.forEach((timestamp: number) => {
|
||||
let latestEvent: AnnotationEvent | null = null;
|
||||
|
||||
for (const timestamp of activeValuesTimestamps) {
|
||||
// We already have event `open` and we have new event that is inside the `step` so we just update the end.
|
||||
if (latestEvent && latestEvent.timeEnd + step >= timestamp) {
|
||||
if (latestEvent && (latestEvent.timeEnd ?? 0) + step >= timestamp) {
|
||||
latestEvent.timeEnd = timestamp;
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Event exists but new one is outside of the `step` so we "finish" the current region.
|
||||
@ -622,7 +606,8 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
|
||||
tags,
|
||||
text: self.resultTransformer.renderTemplate(textFormat, series.metric),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (latestEvent) {
|
||||
// finish up last point if we have one
|
||||
latestEvent.timeEnd = activeValuesTimestamps[activeValuesTimestamps.length - 1];
|
||||
@ -723,7 +708,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
|
||||
|
||||
getPrometheusTime(date: string | DateTime, roundUp: boolean) {
|
||||
if (typeof date === 'string') {
|
||||
date = dateMath.parse(date, roundUp);
|
||||
date = dateMath.parse(date, roundUp)!;
|
||||
}
|
||||
|
||||
return Math.ceil(date.valueOf() / 1000);
|
||||
|
@ -54,9 +54,9 @@ function addMetricsMetadata(metric: string, metadata?: PromMetricsMetadata): Com
|
||||
const PREFIX_DELIMITER_REGEX = /(="|!="|=~"|!~"|\{|\[|\(|\+|-|\/|\*|%|\^|\band\b|\bor\b|\bunless\b|==|>=|!=|<=|>|<|=|~|,)/;
|
||||
|
||||
export default class PromQlLanguageProvider extends LanguageProvider {
|
||||
histogramMetrics?: string[];
|
||||
histogramMetrics: string[];
|
||||
timeRange?: { start: number; end: number };
|
||||
metrics?: string[];
|
||||
metrics: string[];
|
||||
metricsMetadata?: PromMetricsMetadata;
|
||||
startTask: Promise<any>;
|
||||
datasource: PrometheusDatasource;
|
||||
@ -87,7 +87,7 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
||||
// Strip syntax chars so that typeahead suggestions can work on clean inputs
|
||||
cleanText(s: string) {
|
||||
const parts = s.split(PREFIX_DELIMITER_REGEX);
|
||||
const last = parts.pop();
|
||||
const last = parts.pop()!;
|
||||
return last
|
||||
.trimLeft()
|
||||
.replace(/"$/, '')
|
||||
@ -136,6 +136,12 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
||||
{ prefix, text, value, labelKey, wrapperClasses }: TypeaheadInput,
|
||||
context: { history: Array<HistoryItem<PromQuery>> } = { history: [] }
|
||||
): Promise<TypeaheadOutput> => {
|
||||
const emptyResult: TypeaheadOutput = { suggestions: [] };
|
||||
|
||||
if (!value) {
|
||||
return emptyResult;
|
||||
}
|
||||
|
||||
// Local text properties
|
||||
const empty = value.document.text.length === 0;
|
||||
const selectedLines = value.document.getTextsAtRange(value.selection);
|
||||
@ -179,9 +185,7 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
||||
return this.getTermCompletionItems();
|
||||
}
|
||||
|
||||
return {
|
||||
suggestions: [],
|
||||
};
|
||||
return emptyResult;
|
||||
};
|
||||
|
||||
getBeginningCompletionItems = (context: { history: Array<HistoryItem<PromQuery>> }): TypeaheadOutput => {
|
||||
@ -253,7 +257,12 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
||||
// Stitch all query lines together to support multi-line queries
|
||||
let queryOffset;
|
||||
const queryText = value.document.getBlocks().reduce((text: string, block) => {
|
||||
const blockText = block.getText();
|
||||
if (!block) {
|
||||
return text;
|
||||
}
|
||||
|
||||
const blockText = block?.getText();
|
||||
|
||||
if (value.anchorBlock.key === block.key) {
|
||||
// Newline characters are not accounted for but this is irrelevant
|
||||
// for the purpose of extracting the selector string
|
||||
@ -305,6 +314,10 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
||||
labelKey,
|
||||
value,
|
||||
}: TypeaheadInput): Promise<TypeaheadOutput> => {
|
||||
if (!value) {
|
||||
return { suggestions: [] };
|
||||
}
|
||||
|
||||
const suggestions: CompletionItemGroup[] = [];
|
||||
const line = value.anchorBlock.getText();
|
||||
const cursorOffset = value.selection.anchor.offset;
|
||||
@ -346,7 +359,8 @@ export default class PromQlLanguageProvider extends LanguageProvider {
|
||||
return { suggestions };
|
||||
}
|
||||
|
||||
let context: string;
|
||||
let context: string | undefined;
|
||||
|
||||
if ((text && isValueStart) || wrapperClasses.includes('attr-value')) {
|
||||
// Label values
|
||||
if (labelKey && labelValues[labelKey]) {
|
||||
|
@ -119,19 +119,20 @@ export function expandRecordingRules(query: string, mapping: { [name: string]: s
|
||||
// Regex that matches occurences of ){ or }{ or ]{ which is a sign of incorrecly added labels.
|
||||
const invalidLabelsRegex = /(\)\{|\}\{|\]\{)/;
|
||||
const correctlyExpandedQueryArray = queryArray.map(query => {
|
||||
let expression = query;
|
||||
if (expression.match(invalidLabelsRegex)) {
|
||||
expression = addLabelsToExpression(expression, invalidLabelsRegex);
|
||||
}
|
||||
return expression;
|
||||
return addLabelsToExpression(query, invalidLabelsRegex);
|
||||
});
|
||||
|
||||
return correctlyExpandedQueryArray.join('');
|
||||
}
|
||||
|
||||
function addLabelsToExpression(expr: string, invalidLabelsRegexp: RegExp) {
|
||||
const match = expr.match(invalidLabelsRegexp);
|
||||
if (!match) {
|
||||
return expr;
|
||||
}
|
||||
|
||||
// Split query into 2 parts - before the invalidLabelsRegex match and after.
|
||||
const indexOfRegexMatch = expr.match(invalidLabelsRegexp).index;
|
||||
const indexOfRegexMatch = match.index ?? 0;
|
||||
const exprBeforeRegexMatch = expr.substr(0, indexOfRegexMatch + 1);
|
||||
const exprAfterRegexMatch = expr.substr(indexOfRegexMatch + 1);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import _ from 'lodash';
|
||||
import { TimeRange } from '@grafana/data';
|
||||
import { TimeRange, MetricFindValue } from '@grafana/data';
|
||||
import { PrometheusDatasource, PromDataQueryResponse } from './datasource';
|
||||
import { PromQueryRequest } from './types';
|
||||
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
@ -13,7 +13,7 @@ export default class PrometheusMetricFindQuery {
|
||||
this.range = getTimeSrv().timeRange();
|
||||
}
|
||||
|
||||
process() {
|
||||
process(): Promise<MetricFindValue[]> {
|
||||
const labelNamesRegex = /^label_names\(\)\s*$/;
|
||||
const labelValuesRegex = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]*)\)\s*$/;
|
||||
const metricNamesRegex = /^metrics\((.+)\)\s*$/;
|
||||
@ -28,7 +28,7 @@ export default class PrometheusMetricFindQuery {
|
||||
if (labelValuesQuery[1]) {
|
||||
return this.labelValuesQuery(labelValuesQuery[2], labelValuesQuery[1]);
|
||||
} else {
|
||||
return this.labelValuesQuery(labelValuesQuery[2], null);
|
||||
return this.labelValuesQuery(labelValuesQuery[2]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@ export default class PrometheusMetricFindQuery {
|
||||
});
|
||||
}
|
||||
|
||||
metricNameAndLabelsQuery(query: string) {
|
||||
metricNameAndLabelsQuery(query: string): Promise<MetricFindValue[]> {
|
||||
const start = this.datasource.getPrometheusTime(this.range.from, false);
|
||||
const end = this.datasource.getPrometheusTime(this.range.to, true);
|
||||
const params = new URLSearchParams({
|
||||
@ -144,10 +144,11 @@ export default class PrometheusMetricFindQuery {
|
||||
start: start.toString(),
|
||||
end: end.toString(),
|
||||
});
|
||||
const url = `/api/v1/series?${params.toString()}`;
|
||||
|
||||
const url = `/api/v1/series?${params.toString()}`;
|
||||
const self = this;
|
||||
return this.datasource.metadataRequest(url).then((result: PromDataQueryResponse) => {
|
||||
|
||||
return this.datasource.metadataRequest(url).then((result: any) => {
|
||||
return _.map(result.data.data, (metric: { [key: string]: string }) => {
|
||||
return {
|
||||
text: self.datasource.getOriginalMetricName(metric),
|
||||
|
@ -3,11 +3,11 @@ import { PrometheusDatasource } from './datasource';
|
||||
|
||||
describe('getQueryHints()', () => {
|
||||
it('returns no hints for no series', () => {
|
||||
expect(getQueryHints('', [])).toEqual(null);
|
||||
expect(getQueryHints('', [])).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns no hints for empty series', () => {
|
||||
expect(getQueryHints('', [{ datapoints: [] }])).toEqual(null);
|
||||
expect(getQueryHints('', [{ datapoints: [] }])).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns a rate hint for a counter metric', () => {
|
||||
@ -59,7 +59,7 @@ describe('getQueryHints()', () => {
|
||||
|
||||
// Test substring match not triggering hint
|
||||
hints = getQueryHints('foo_foo', series, datasource);
|
||||
expect(hints).toBe(null);
|
||||
expect(hints).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns no rate hint for a counter metric that already has a rate', () => {
|
||||
@ -72,7 +72,7 @@ describe('getQueryHints()', () => {
|
||||
},
|
||||
];
|
||||
const hints = getQueryHints('rate(metric_total[1m])', series);
|
||||
expect(hints).toEqual(null);
|
||||
expect(hints).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns no rate hint for a counter metric that already has an increase', () => {
|
||||
@ -85,7 +85,7 @@ describe('getQueryHints()', () => {
|
||||
},
|
||||
];
|
||||
const hints = getQueryHints('increase(metric_total[1m])', series);
|
||||
expect(hints).toEqual(null);
|
||||
expect(hints).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns a rate hint w/o action for a complex counter metric', () => {
|
||||
|
@ -7,7 +7,7 @@ import { PrometheusDatasource } from './datasource';
|
||||
*/
|
||||
export const SUM_HINT_THRESHOLD_COUNT = 20;
|
||||
|
||||
export function getQueryHints(query: string, series?: any[], datasource?: PrometheusDatasource): QueryHint[] | null {
|
||||
export function getQueryHints(query: string, series?: any[], datasource?: PrometheusDatasource): QueryHint[] {
|
||||
const hints = [];
|
||||
|
||||
// ..._bucket metric needs a histogram_quantile()
|
||||
@ -32,27 +32,32 @@ export function getQueryHints(query: string, series?: any[], datasource?: Promet
|
||||
// Use metric metadata for exact types
|
||||
const nameMatch = query.match(/\b(\w+_(total|sum|count))\b/);
|
||||
let counterNameMetric = nameMatch ? nameMatch[1] : '';
|
||||
const metricsMetadata = datasource?.languageProvider?.metricsMetadata;
|
||||
const metricsMetadata = datasource?.languageProvider?.metricsMetadata ?? {};
|
||||
const metricMetadataKeys = Object.keys(metricsMetadata);
|
||||
let certain = false;
|
||||
if (_.size(metricsMetadata) > 0) {
|
||||
counterNameMetric = Object.keys(metricsMetadata).find(metricName => {
|
||||
// Only considering first type information, could be non-deterministic
|
||||
const metadata = metricsMetadata[metricName][0];
|
||||
if (metadata.type.toLowerCase() === 'counter') {
|
||||
const metricRegex = new RegExp(`\\b${metricName}\\b`);
|
||||
if (query.match(metricRegex)) {
|
||||
certain = true;
|
||||
return true;
|
||||
|
||||
if (metricMetadataKeys.length > 0) {
|
||||
counterNameMetric =
|
||||
metricMetadataKeys.find(metricName => {
|
||||
// Only considering first type information, could be non-deterministic
|
||||
const metadata = metricsMetadata[metricName][0];
|
||||
if (metadata.type.toLowerCase() === 'counter') {
|
||||
const metricRegex = new RegExp(`\\b${metricName}\\b`);
|
||||
if (query.match(metricRegex)) {
|
||||
certain = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
}) ?? '';
|
||||
}
|
||||
|
||||
if (counterNameMetric) {
|
||||
const simpleMetric = query.trim().match(/^\w+$/);
|
||||
const verb = certain ? 'is' : 'looks like';
|
||||
let label = `Metric ${counterNameMetric} ${verb} a counter.`;
|
||||
let fix: QueryFix;
|
||||
let fix: QueryFix | undefined;
|
||||
|
||||
if (simpleMetric) {
|
||||
fix = {
|
||||
label: 'Fix by adding rate().',
|
||||
@ -60,10 +65,11 @@ export function getQueryHints(query: string, series?: any[], datasource?: Promet
|
||||
type: 'ADD_RATE',
|
||||
query,
|
||||
},
|
||||
} as QueryFix;
|
||||
};
|
||||
} else {
|
||||
label = `${label} Try applying a rate() function.`;
|
||||
}
|
||||
|
||||
hints.push({
|
||||
type: 'APPLY_RATE',
|
||||
label,
|
||||
@ -119,5 +125,5 @@ export function getQueryHints(query: string, series?: any[], datasource?: Promet
|
||||
}
|
||||
}
|
||||
|
||||
return hints.length > 0 ? hints : null;
|
||||
return hints;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ export class ResultTransformer {
|
||||
),
|
||||
];
|
||||
} else if (prometheusResult && options.format === 'heatmap') {
|
||||
let seriesList = [];
|
||||
let seriesList: TimeSeries[] = [];
|
||||
for (const metricData of prometheusResult) {
|
||||
seriesList.push(this.transformMetricData(metricData, options, options.start, options.end));
|
||||
}
|
||||
@ -28,7 +28,7 @@ export class ResultTransformer {
|
||||
seriesList = this.transformToHistogramOverTime(seriesList);
|
||||
return seriesList;
|
||||
} else if (prometheusResult) {
|
||||
const seriesList = [];
|
||||
const seriesList: TimeSeries[] = [];
|
||||
for (const metricData of prometheusResult) {
|
||||
if (response.data.data.resultType === 'matrix') {
|
||||
seriesList.push(this.transformMetricData(metricData, options, options.start, options.end));
|
||||
@ -41,7 +41,7 @@ export class ResultTransformer {
|
||||
return [];
|
||||
}
|
||||
|
||||
transformMetricData(metricData: any, options: any, start: number, end: number) {
|
||||
transformMetricData(metricData: any, options: any, start: number, end: number): TimeSeries {
|
||||
const dps = [];
|
||||
const { name, labels, title } = this.createLabelInfo(metricData.metric, options);
|
||||
|
||||
@ -53,7 +53,8 @@ export class ResultTransformer {
|
||||
}
|
||||
|
||||
for (const value of metricData.values) {
|
||||
let dpValue = parseFloat(value[1]);
|
||||
let dpValue: number | null = parseFloat(value[1]);
|
||||
|
||||
if (_.isNaN(dpValue)) {
|
||||
dpValue = null;
|
||||
}
|
||||
@ -73,9 +74,8 @@ export class ResultTransformer {
|
||||
|
||||
return {
|
||||
datapoints: dps,
|
||||
query: options.query,
|
||||
refId: options.refId,
|
||||
target: name,
|
||||
target: name ?? '',
|
||||
tags: labels,
|
||||
title,
|
||||
meta: options.meta,
|
||||
@ -147,11 +147,11 @@ export class ResultTransformer {
|
||||
return table;
|
||||
}
|
||||
|
||||
transformInstantMetricData(md: any, options: any) {
|
||||
transformInstantMetricData(md: any, options: any): TimeSeries {
|
||||
const dps = [];
|
||||
const { name, labels } = this.createLabelInfo(md.metric, options);
|
||||
dps.push([parseFloat(md.value[1]), md.value[0] * 1000]);
|
||||
return { target: name, title: name, datapoints: dps, tags: labels, refId: options.refId, meta: options.meta };
|
||||
return { target: name ?? '', title: name, datapoints: dps, tags: labels, refId: options.refId, meta: options.meta };
|
||||
}
|
||||
|
||||
createLabelInfo(labels: { [key: string]: string }, options: any): { name?: string; labels: Labels; title?: string } {
|
||||
@ -210,7 +210,7 @@ export class ResultTransformer {
|
||||
|
||||
for (let j = 0; j < topSeries.length; j++) {
|
||||
const bottomPoint = bottomSeries[j] || [0];
|
||||
topSeries[j][0] -= bottomPoint[0];
|
||||
topSeries[j][0]! -= bottomPoint[0]!;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ export function useLoadOptions(datasource: ZipkinDatasource) {
|
||||
const newTraces = traces.length
|
||||
? fromPairs(
|
||||
traces.map(trace => {
|
||||
const rootSpan = trace.find(span => !span.parentId);
|
||||
const rootSpan = trace.find(span => !span.parentId)!;
|
||||
|
||||
return [`${rootSpan.name} [${Math.floor(rootSpan.duration / 1000)} ms]`, rootSpan.traceId];
|
||||
})
|
||||
@ -186,7 +186,8 @@ export function useLoadOptions(datasource: ZipkinDatasource) {
|
||||
|
||||
function useMapToCascaderOptions(services: AsyncState<CascaderOption[]>, allOptions: OptionsState) {
|
||||
return useMemo(() => {
|
||||
let cascaderOptions: CascaderOption[];
|
||||
let cascaderOptions: CascaderOption[] = [];
|
||||
|
||||
if (services.value && services.value.length) {
|
||||
cascaderOptions = services.value.map(services => {
|
||||
return {
|
||||
|
@ -16,10 +16,9 @@ import { apiPrefix } from './constants';
|
||||
import { ZipkinSpan } from './types';
|
||||
import { transformResponse } from './utils/transforms';
|
||||
|
||||
export type ZipkinQuery = {
|
||||
// At the moment this should be simply the trace ID to get
|
||||
export interface ZipkinQuery extends DataQuery {
|
||||
query: string;
|
||||
} & DataQuery;
|
||||
}
|
||||
|
||||
export class ZipkinDatasource extends DataSourceApi<ZipkinQuery> {
|
||||
constructor(private instanceSettings: DataSourceInstanceSettings) {
|
||||
|
@ -117,8 +117,8 @@ class AlertListPanel extends PanelCtrl {
|
||||
params.dashboardId = this.dashboard.id;
|
||||
}
|
||||
|
||||
params.from = dateMath.parse(this.dashboard.time.from).unix() * 1000;
|
||||
params.to = dateMath.parse(this.dashboard.time.to).unix() * 1000;
|
||||
params.from = dateMath.parse(this.dashboard.time.from)!.unix() * 1000;
|
||||
params.to = dateMath.parse(this.dashboard.time.to)!.unix() * 1000;
|
||||
|
||||
return promiseToDigest(this.$scope)(
|
||||
getBackendSrv()
|
||||
|
@ -123,7 +123,7 @@ describe('Graph Panel Migrations', () => {
|
||||
expect(result.dataLinks).toBeUndefined();
|
||||
expect(fieldSource.defaults.links).toHaveLength(1);
|
||||
|
||||
const link = fieldSource.defaults.links[0];
|
||||
const link = fieldSource.defaults.links![0];
|
||||
expect(link.url).toEqual('THE DRILLDOWN URL');
|
||||
});
|
||||
});
|
||||
|
@ -429,7 +429,8 @@ class GraphElement {
|
||||
|
||||
// Function for rendering panel
|
||||
renderPanel() {
|
||||
this.panelWidth = this.elem.width();
|
||||
this.panelWidth = this.elem.width() ?? 0;
|
||||
|
||||
if (this.shouldAbortRender()) {
|
||||
return;
|
||||
}
|
||||
|
@ -207,14 +207,18 @@ export default function GraphTooltip(this: any, elem: any, dashboard: any, scope
|
||||
self.clear(plot);
|
||||
return;
|
||||
}
|
||||
|
||||
pos.pageX = elem.offset().left + pointOffset.left;
|
||||
pos.pageY = elem.offset().top + elem.height() * pos.panelRelY;
|
||||
const isVisible =
|
||||
pos.pageY >= $(window).scrollTop() && pos.pageY <= $(window).innerHeight() + $(window).scrollTop();
|
||||
|
||||
const scrollTop = $(window).scrollTop() ?? 0;
|
||||
const isVisible = pos.pageY >= scrollTop && pos.pageY <= $(window).innerHeight()! + scrollTop;
|
||||
|
||||
if (!isVisible) {
|
||||
self.clear(plot);
|
||||
return;
|
||||
}
|
||||
|
||||
plot.setCrosshair(pos);
|
||||
allSeriesMode = true;
|
||||
|
||||
|
@ -470,8 +470,8 @@ export class EventMarkers {
|
||||
},
|
||||
left,
|
||||
top,
|
||||
line.width(),
|
||||
line.height()
|
||||
line.width() ?? 1,
|
||||
line.height() ?? 1
|
||||
);
|
||||
|
||||
return drawableEvent;
|
||||
@ -604,8 +604,8 @@ export class EventMarkers {
|
||||
},
|
||||
left,
|
||||
top,
|
||||
region.width(),
|
||||
region.height()
|
||||
region.width() ?? 1,
|
||||
region.height() ?? 1
|
||||
);
|
||||
|
||||
return drawableEvent;
|
||||
|
@ -33,7 +33,7 @@ coreModule.directive('colorLegend', () => {
|
||||
|
||||
function render() {
|
||||
const legendElem = $(elem).find('svg');
|
||||
const legendWidth = Math.floor(legendElem.outerWidth());
|
||||
const legendWidth = Math.floor(legendElem.outerWidth() ?? 10);
|
||||
|
||||
if (panel.color.mode === 'spectrum') {
|
||||
const colorScheme: any = _.find(ctrl.colorSchemes, {
|
||||
@ -102,7 +102,7 @@ function drawColorLegend(
|
||||
const legend = d3.select(legendElem.get(0));
|
||||
clearLegend(elem);
|
||||
|
||||
const legendWidth = Math.floor(legendElem.outerWidth()) - 30;
|
||||
const legendWidth = Math.floor(legendElem.outerWidth() ?? 10) - 30;
|
||||
const legendHeight = legendElem.attr('height');
|
||||
|
||||
const rangeStep = ((rangeTo - rangeFrom) / legendWidth) * LEGEND_SEGMENT_WIDTH;
|
||||
@ -140,7 +140,7 @@ function drawOpacityLegend(
|
||||
const legend = d3.select(legendElem.get(0));
|
||||
clearLegend(elem);
|
||||
|
||||
const legendWidth = Math.floor(legendElem.outerWidth()) - 30;
|
||||
const legendWidth = Math.floor(legendElem.outerWidth() ?? 30) - 30;
|
||||
const legendHeight = legendElem.attr('height');
|
||||
|
||||
const rangeStep = ((rangeTo - rangeFrom) / legendWidth) * LEGEND_SEGMENT_WIDTH;
|
||||
@ -214,7 +214,7 @@ function drawSimpleColorLegend(elem: JQuery, colorScale: any) {
|
||||
const legendElem = $(elem).find('svg');
|
||||
clearLegend(elem);
|
||||
|
||||
const legendWidth = Math.floor(legendElem.outerWidth());
|
||||
const legendWidth = Math.floor(legendElem.outerWidth() ?? 30);
|
||||
const legendHeight = legendElem.attr('height');
|
||||
|
||||
if (legendWidth) {
|
||||
@ -242,7 +242,7 @@ function drawSimpleOpacityLegend(elem: JQuery, options: { colorScale: string; ex
|
||||
clearLegend(elem);
|
||||
|
||||
const legend = d3.select(legendElem.get(0));
|
||||
const legendWidth = Math.floor(legendElem.outerWidth());
|
||||
const legendWidth = Math.floor(legendElem.outerWidth() ?? 30);
|
||||
const legendHeight = legendElem.attr('height');
|
||||
|
||||
if (legendWidth) {
|
||||
|
@ -19,7 +19,7 @@ import { ColumnRender, TableRenderModel, ColumnStyle } from './types';
|
||||
import { ColumnOptionsCtrl } from './column_options';
|
||||
|
||||
export class TableRenderer {
|
||||
formatters: any[];
|
||||
formatters: any[] = [];
|
||||
colorState: any;
|
||||
|
||||
constructor(
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
echo -e "Collecting code stats (typescript errors & more)"
|
||||
|
||||
ERROR_COUNT_LIMIT=700
|
||||
ERROR_COUNT_LIMIT=600
|
||||
DIRECTIVES_LIMIT=172
|
||||
CONTROLLERS_LIMIT=139
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user