Commit ec783fbf by Ryan McKinley Committed by GitHub

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>
parent 9e5fe8db
......@@ -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
......
......@@ -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
......
......@@ -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",
......
......@@ -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 = {
......
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"');
});
});
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?
},
}
);
}
......@@ -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('');
}
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