Fields: __field.name as field name and __field.displayName as displayName (#26531)

* name vs displayName

* name vs displayName

* add __values

* add docs for displayName expressions

* Update docs/sources/panels/field-configuration-options.md

Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Update docs/sources/panels/field-configuration-options.md

Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Update docs/sources/panels/field-configuration-options.md

Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Update docs/sources/panels/field-configuration-options.md

Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Update docs/sources/panels/field-configuration-options.md

Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Update docs/sources/panels/field-configuration-options.md

Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

Co-authored-by: kyle <kyle@grafana.com>
Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
This commit is contained in:
Ryan McKinley 2020-08-04 21:22:14 -07:00 committed by GitHub
parent 9e5fe8dbdb
commit ec783fbff4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 95 additions and 19 deletions

View File

@ -139,7 +139,19 @@ For more information and instructions, refer to [Data links]({{< relref "../link
Lets you set the display title of all fields. You can use [variables]({{< relref "../variables/templates-and-variables.md" >}}) in the field title.
When multiple stats are shown, this field controls the title in each stat. By default this is the series name and field name. You can use expressions like ${__series.name} or ${**field.name} to use only series name or field name in title or \${**cell_2} to refer to other fields (2 being field/column with index 2).
When multiple stats, fields, or series are shown, this field controls the title in each stat. You can use expressions like `${__field.name}` to use only the series name or the field name in title.
Given a field with a name of Temp, and labels of {"Loc"="PBI", "Sensor"="3"}
| Expression syntax | Example | Renders to | Explanation |
| ---------------------------- | ---------------------- | --------------------------------- | ----------- |
| `${__field.displayName}` | Same as syntax | `Temp {Loc="PBI", Sensor="3"}` | Displays the field name, and labels in `{}` if they are present. If there is only one label key in the response, then for the label portion, Grafana displays the value of the label without the enclosing braces. |
| `${__field.name}` | Same as syntax | `Temp` | Displays the name of the field (without labels). |
| `${__field.labels}` | Same as syntax | `Loc="PBI", Sensor="3"` | Displays the labels without the name. |
| `${__field.labels.X}` | `${__field.labels.Loc}` | `PBI` | Displays the value of the specified label key. |
| `${__field.labels.__values}` | Same as Syntax | `PBI, 3` | Displays the values of the labels separated by a comma (without label keys). |
If the value is an empty string after rendering the expression for a particular field, then the default display method is used.
### Max

View File

@ -40,7 +40,7 @@ export interface ReduceDataOptions {
// TODO: use built in variables, same as for data links?
export const VAR_SERIES_NAME = '__series.name';
export const VAR_FIELD_NAME = '__field.name';
export const VAR_FIELD_NAME = '__field.displayName'; // Includes the rendered tags and naming strategy
export const VAR_FIELD_LABELS = '__field.labels';
export const VAR_CALC = '__calc';
export const VAR_CELL_PREFIX = '__cell_'; // consistent with existing table templates

View File

@ -127,11 +127,7 @@ describe('applyFieldOverrides', () => {
Object {
"__field": Object {
"text": "Field",
"value": Object {
"formattedLabels": "",
"labels": undefined,
"name": "A message",
},
"value": Object {},
},
"__series": Object {
"text": "Series",
@ -146,11 +142,7 @@ describe('applyFieldOverrides', () => {
Object {
"__field": Object {
"text": "Field",
"value": Object {
"formattedLabels": "",
"labels": undefined,
"name": "B info",
},
"value": Object {},
},
"__series": Object {
"text": "Series",

View File

@ -32,10 +32,10 @@ import { FieldConfigOptionsRegistry } from './FieldConfigOptionsRegistry';
import { DataLinkBuiltInVars, locationUtil } from '../utils';
import { formattedValueToString } from '../valueFormats';
import { getFieldDisplayValuesProxy } from './getFieldDisplayValuesProxy';
import { formatLabels } from '../utils/labels';
import { getFrameDisplayName, getFieldDisplayName } from './fieldState';
import { getTimeField } from '../dataframe/processDataFrame';
import { mapInternalLinkToExplore } from '../utils/dataLinks';
import { getTemplateProxyForField } from './templateProxies';
interface OverrideProps {
match: FieldMatcher;
@ -113,11 +113,7 @@ export function applyFieldOverrides(options: ApplyFieldOverrideOptions): DataFra
fieldScopedVars['__field'] = {
text: 'Field',
value: {
name: displayName, // Generally appropriate (may include the series name if useful)
formattedLabels: formatLabels(field.labels!),
labels: field.labels,
},
value: getTemplateProxyForField(field, frame, options.data),
};
field.state = {

View File

@ -0,0 +1,32 @@
import { getTemplateProxyForField } from './templateProxies';
import { toDataFrame } from '../dataframe';
describe('Template proxies', () => {
it('supports name and displayName', () => {
const frames = [
toDataFrame({
fields: [
{
name: '🔥',
config: { displayName: '✨' },
labels: {
b: 'BBB',
a: 'AAA',
},
},
],
}),
];
const f = getTemplateProxyForField(frames[0].fields[0], frames[0], frames);
expect(f.name).toEqual('🔥');
expect(f.displayName).toEqual('✨');
expect(`${f.labels}`).toEqual('a="AAA", b="BBB"');
expect(f.labels.__values).toEqual('AAA, BBB');
expect(f.labels.a).toEqual('AAA');
// Deprecated syntax
expect(`${f.formattedLabels}`).toEqual('a="AAA", b="BBB"');
});
});

View File

@ -0,0 +1,41 @@
import { DataFrame, Field } from '../types';
import { getFieldDisplayName } from './fieldState';
import { formatLabels } from '../utils/labels';
/**
* This object is created often, and only used when tmplates exist. Using a proxy lets us delay
* calculations of the more complex structures (label names) until they are actually used
*/
export function getTemplateProxyForField(field: Field, frame?: DataFrame, frames?: DataFrame[]): any {
return new Proxy(
{} as any, // This object shows up in test snapshots
{
get: (obj: Field, key: string, reciever: any) => {
if (key === 'name') {
return field.name;
}
if (key === 'displayName') {
return getFieldDisplayName(field, frame, frames);
}
if (key === 'labels' || key === 'formattedLabels') {
// formattedLabels deprecated
if (!field.labels) {
return '';
}
return {
...field.labels,
__values: Object.values(field.labels)
.sort()
.join(', '),
toString: () => {
return formatLabels(field.labels!, '', true);
},
};
}
return undefined; // (field as any)[key]; // any property?
},
}
);
}

View File

@ -62,11 +62,14 @@ export function findUniqueLabels(labels: Labels | undefined, commonLabels: Label
/**
* Serializes the given labels to a string.
*/
export function formatLabels(labels: Labels, defaultValue = ''): string {
export function formatLabels(labels: Labels, defaultValue = '', withoutBraces?: boolean): string {
if (!labels || Object.keys(labels).length === 0) {
return defaultValue;
}
const labelKeys = Object.keys(labels).sort();
const cleanSelector = labelKeys.map(key => `${key}="${labels[key]}"`).join(', ');
if (withoutBraces) {
return cleanSelector;
}
return ['{', cleanSelector, '}'].join('');
}