mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
9e5fe8dbdb
commit
ec783fbff4
@ -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 = {
|
||||
|
32
packages/grafana-data/src/field/templateProxies.test.ts
Normal file
32
packages/grafana-data/src/field/templateProxies.test.ts
Normal 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"');
|
||||
});
|
||||
});
|
41
packages/grafana-data/src/field/templateProxies.ts
Normal file
41
packages/grafana-data/src/field/templateProxies.ts
Normal 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?
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
@ -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('');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user