Attach links supplier to when applying field overrides

This commit is contained in:
Dominik Prokop
2020-04-15 14:39:57 +02:00
parent 18e4f17c6c
commit 4b8bcfca3e
4 changed files with 137 additions and 16 deletions
@@ -11,6 +11,11 @@ import {
ScopedVars,
ApplyFieldOverrideOptions,
FieldConfigPropertyItem,
LinkModel,
InterpolateFunction,
ValueLinkConfig,
LinkModelSupplier,
GrafanaTheme,
} from '../types';
import { fieldMatchers, ReducerID, reduceField } from '../transformations';
import { FieldMatcher } from '../types/transformations';
@@ -19,10 +24,11 @@ import set from 'lodash/set';
import unset from 'lodash/unset';
import get from 'lodash/get';
import { getDisplayProcessor } from './displayProcessor';
import { guessFieldTypeForField } from '../dataframe';
import { getTimeField, guessFieldTypeForField } from '../dataframe';
import { standardFieldConfigEditorRegistry } from './standardFieldConfigEditorRegistry';
import { FieldConfigOptionsRegistry } from './FieldConfigOptionsRegistry';
import { DataLinkBuiltInVars, locationUtil } from '../utils';
import { formattedValueToString } from '../valueFormats';
import { getFieldDisplayValuesProxy } from './getFieldDisplayValuesProxy';
interface OverrideProps {
@@ -104,10 +110,10 @@ export function applyFieldOverrides(options: ApplyFieldOverrideOptions): DataFra
if (!fieldName) {
fieldName = `Field[${fieldIndex}]`;
}
const fieldScopedVars = { ...scopedVars };
fieldScopedVars['__field'] = { text: 'Field', value: { name: fieldName } };
scopedVars['__field'] = { text: 'Field', value: { name: fieldName } };
const config: FieldConfig = { ...field.config, scopedVars } || {};
const config: FieldConfig = { ...field.config, scopedVars: fieldScopedVars } || {};
const context = {
field,
data: options.data!,
@@ -184,6 +190,14 @@ export function applyFieldOverrides(options: ApplyFieldOverrideOptions): DataFra
theme: options.theme,
timeZone: options.timeZone,
});
// Attach data links supplier
if (f.config.links && f.config.links.length > 0) {
f.getDataLinksSupplier = getLinksSupplier(frame, f, fieldScopedVars, context.replaceVariables, {
theme: options.theme,
});
}
return f;
});
@@ -316,3 +330,90 @@ export function validateFieldConfig(config: FieldConfig) {
config.min = tmp;
}
}
const getLinksSupplier = (
frame: DataFrame,
field: Field,
fieldScopedVars: ScopedVars,
replaceVariables: InterpolateFunction,
options: {
theme: GrafanaTheme;
}
) => (config: ValueLinkConfig): LinkModelSupplier<Field> => {
return {
getLinks: (scopedVars?: any): Array<LinkModel<Field>> => {
if (!field.config.links || field.config.links.length === 0) {
return [];
}
const timeRangeUrl = locationUtil.getTimeRangeUrlParams();
const { timeField } = getTimeField(frame);
return field.config.links.map(link => {
let href = link.url;
let dataFrameVars = {};
let valueVars = {};
const info: LinkModel<Field> = {
href: locationUtil.assureBaseUrl(href.replace(/\n/g, '')),
title: replaceVariables(link.title || '', scopedVars),
target: link.targetBlank ? '_blank' : '_self',
origin: field,
};
const variablesQuery = locationUtil.getVariablesUrlParams(scopedVars);
// We are not displaying reduction result
if (config.valueRowIndex !== undefined && !isNaN(config.valueRowIndex)) {
const fieldsProxy = getFieldDisplayValuesProxy(frame, config.valueRowIndex, options);
valueVars = {
raw: field.values.get(config.valueRowIndex),
numeric: fieldsProxy[field.name].numeric,
text: fieldsProxy[field.name].text,
time: timeField ? timeField.values.get(config.valueRowIndex) : undefined,
};
dataFrameVars = {
__data: {
value: {
name: frame.name,
refId: frame.refId,
fields: fieldsProxy,
},
text: 'Data',
},
};
} else {
if (config.calculatedValue) {
valueVars = {
raw: config.calculatedValue.display.numeric,
numeric: config.calculatedValue.display.numeric,
text: formattedValueToString(config.calculatedValue.display),
calc: config.calculatedValue.name,
};
}
}
info.href = replaceVariables(info.href, {
...scopedVars,
...fieldScopedVars,
__value: {
text: 'Value',
value: valueVars,
},
...dataFrameVars,
[DataLinkBuiltInVars.keepTime]: {
text: timeRangeUrl,
value: timeRangeUrl,
},
[DataLinkBuiltInVars.includeVars]: {
text: variablesQuery,
value: variablesQuery,
},
});
info.href = locationUtil.processUrl(info.href);
return info;
});
},
};
};
+18 -1
View File
@@ -2,11 +2,12 @@ import { ThresholdsConfig } from './thresholds';
import { ValueMapping } from './valueMapping';
import { QueryResultBase, Labels, NullValueMode } from './data';
import { DisplayProcessor } from './displayValue';
import { DataLink } from './dataLink';
import { DataLink, LinkModelSupplier } from './dataLink';
import { Vector } from './vector';
import { FieldCalcs } from '../transformations/fieldReducer';
import { FieldColor } from './fieldColor';
import { ScopedVars } from './ScopedVars';
import { FieldDisplay } from '../field';
export enum FieldType {
time = 'time', // or date
@@ -57,6 +58,17 @@ export interface FieldConfig<TOptions extends object = any> {
scopedVars?: ScopedVars;
}
export interface ValueLinkConfig {
/**
* Result of field reduction
*/
calculatedValue?: FieldDisplay;
/**
* Index of the value row within Field. Should be provided only when value is not a result of a reduction
*/
valueRowIndex?: number;
}
export interface Field<T = any, V = Vector<T>> {
/**
* Name of the field (column)
@@ -87,6 +99,11 @@ export interface Field<T = any, V = Vector<T>> {
* Convert a value for display
*/
display?: DisplayProcessor;
/**
* Get value data links with variables interpolated
*/
getDataLinksSupplier?: (config: ValueLinkConfig) => LinkModelSupplier<Field>;
}
export interface DataFrame extends QueryResultBase {
@@ -264,7 +264,7 @@ export class TimeSrv {
this.$timeout(this.refreshDashboard.bind(this), 0);
}
timeRangeForUrl() {
timeRangeForUrl = () => {
const range = this.timeRange().raw;
if (isDateTime(range.from)) {
@@ -275,7 +275,7 @@ export class TimeSrv {
}
return range;
}
};
timeRange(): TimeRange {
// make copies if they are moment (do not want to return out internal moment, because they are mutable!)
@@ -1,19 +1,20 @@
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import {
DataLink,
DisplayValue,
Field,
FieldDisplay,
LinkModelSupplier,
formattedValueToString,
getFieldDisplayValuesProxy,
getTimeField,
Labels,
ScopedVars,
ScopedVar,
Field,
LinkModel,
formattedValueToString,
DisplayValue,
DataLink,
LinkModelSupplier,
ScopedVar,
ScopedVars,
} from '@grafana/data';
import { getLinkSrv } from './link_srv';
import { getFieldDisplayValuesProxy } from './fieldDisplayValuesProxy';
import { config } from 'app/core/config';
interface SeriesVars {
name?: string;
@@ -100,7 +101,9 @@ export const getFieldLinksSupplier = (value: FieldDisplay): LinkModelSupplier<Fi
value: {
name: dataFrame.name,
refId: dataFrame.refId,
fields: getFieldDisplayValuesProxy(dataFrame, value.rowIndex!),
fields: getFieldDisplayValuesProxy(dataFrame, value.rowIndex!, {
theme: config.theme,
}),
},
text: 'Data',
};