mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
FieldType: Add enum type and include it in testdata scenarios (#64059)
This commit is contained in:
@@ -6,7 +6,7 @@ import { getFieldTypeFromValue } from '../dataframe/processDataFrame';
|
||||
import { toUtc, dateTimeParse } from '../datetime';
|
||||
import { GrafanaTheme2 } from '../themes/types';
|
||||
import { KeyValue, TimeZone } from '../types';
|
||||
import { Field, FieldType } from '../types/dataFrame';
|
||||
import { EnumFieldConfig, Field, FieldType } from '../types/dataFrame';
|
||||
import { DecimalCount, DisplayProcessor, DisplayValue } from '../types/displayValue';
|
||||
import { anyToNumber } from '../utils/anyToNumber';
|
||||
import { getValueMappingResult } from '../utils/valueMappings';
|
||||
@@ -70,6 +70,8 @@ export function getDisplayProcessor(options?: DisplayProcessorOptions): DisplayP
|
||||
}
|
||||
} else if (!unit && field.type === FieldType.string) {
|
||||
unit = 'string';
|
||||
} else if (field.type === FieldType.enum) {
|
||||
return getEnumDisplayProcessor(options.theme, config.type?.enum);
|
||||
}
|
||||
|
||||
const hasCurrencyUnit = unit?.startsWith('currency');
|
||||
@@ -190,6 +192,41 @@ function toStringProcessor(value: unknown): DisplayValue {
|
||||
return { text: toString(value), numeric: anyToNumber(value) };
|
||||
}
|
||||
|
||||
export function getEnumDisplayProcessor(theme: GrafanaTheme2, cfg?: EnumFieldConfig): DisplayProcessor {
|
||||
const config = {
|
||||
text: cfg?.text ?? [],
|
||||
color: cfg?.color ?? [],
|
||||
};
|
||||
// use the theme specific color values
|
||||
config.color = config.color.map((v) => theme.visualization.getColorByName(v));
|
||||
|
||||
return (value: unknown) => {
|
||||
if (value == null) {
|
||||
return {
|
||||
text: '',
|
||||
numeric: NaN,
|
||||
};
|
||||
}
|
||||
const idx = +value;
|
||||
let text = config.text[idx];
|
||||
if (text == null) {
|
||||
text = `${value}`; // the original value
|
||||
}
|
||||
let color = config.color[idx];
|
||||
if (color == null) {
|
||||
// constant color for index
|
||||
const { palette } = theme.visualization;
|
||||
color = palette[idx % palette.length];
|
||||
config.color[idx] = color;
|
||||
}
|
||||
return {
|
||||
text,
|
||||
numeric: idx,
|
||||
color,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function getRawDisplayProcessor(): DisplayProcessor {
|
||||
return (value: unknown) => ({
|
||||
text: getFieldTypeFromValue(value) === 'other' ? `${JSON.stringify(value, getCircularReplacer())}` : `${value}`,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { map } from 'rxjs/operators';
|
||||
|
||||
import { dateTimeParse } from '../../datetime';
|
||||
import { SynchronousDataTransformerInfo } from '../../types';
|
||||
import { DataFrame, Field, FieldType } from '../../types/dataFrame';
|
||||
import { DataFrame, EnumFieldConfig, Field, FieldType } from '../../types/dataFrame';
|
||||
import { ArrayVector } from '../../vector';
|
||||
import { fieldMatchers } from '../matchers';
|
||||
import { FieldMatcherID } from '../matchers/ids';
|
||||
@@ -26,6 +26,9 @@ export interface ConvertFieldTypeOptions {
|
||||
* Date format to parse a string datetime
|
||||
*/
|
||||
dateFormat?: string;
|
||||
|
||||
/** When converting to an enumeration, this is the target config */
|
||||
enumConfig?: EnumFieldConfig;
|
||||
}
|
||||
|
||||
export const convertFieldTypeTransformer: SynchronousDataTransformerInfo<ConvertFieldTypeTransformerOptions> = {
|
||||
@@ -44,11 +47,7 @@ export const convertFieldTypeTransformer: SynchronousDataTransformerInfo<Convert
|
||||
if (!Array.isArray(data) || data.length === 0) {
|
||||
return data;
|
||||
}
|
||||
const timeParsed = convertFieldTypes(options, data);
|
||||
if (!timeParsed) {
|
||||
return [];
|
||||
}
|
||||
return timeParsed;
|
||||
return convertFieldTypes(options, data) ?? [];
|
||||
},
|
||||
};
|
||||
|
||||
@@ -101,6 +100,8 @@ export function convertFieldType(field: Field, opts: ConvertFieldTypeOptions): F
|
||||
return fieldToStringField(field, opts.dateFormat);
|
||||
case FieldType.boolean:
|
||||
return fieldToBooleanField(field);
|
||||
case FieldType.enum:
|
||||
return fieldToEnumField(field, opts.enumConfig);
|
||||
case FieldType.other:
|
||||
return fieldToComplexField(field);
|
||||
default:
|
||||
@@ -241,3 +242,37 @@ export function ensureTimeField(field: Field, dateFormat?: string): Field {
|
||||
}
|
||||
return fieldToTimeField(field, dateFormat);
|
||||
}
|
||||
|
||||
function fieldToEnumField(field: Field, cfg?: EnumFieldConfig): Field {
|
||||
const enumConfig = { ...cfg };
|
||||
const enumValues = field.values.toArray().slice();
|
||||
const lookup = new Map<unknown, number>();
|
||||
if (enumConfig.text) {
|
||||
for (let i = 0; i < enumConfig.text.length; i++) {
|
||||
lookup.set(enumConfig.text[i], i);
|
||||
}
|
||||
} else {
|
||||
enumConfig.text = [];
|
||||
}
|
||||
|
||||
for (let i = 0; i < enumValues.length; i++) {
|
||||
const v = enumValues[i];
|
||||
if (!lookup.has(v)) {
|
||||
enumConfig.text[lookup.size] = v;
|
||||
lookup.set(v, lookup.size);
|
||||
}
|
||||
enumValues[i] = lookup.get(v);
|
||||
}
|
||||
|
||||
return {
|
||||
...field,
|
||||
config: {
|
||||
...field.config,
|
||||
type: {
|
||||
enum: enumConfig,
|
||||
},
|
||||
},
|
||||
type: FieldType.enum,
|
||||
values: new ArrayVector(enumValues),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ export enum FieldType {
|
||||
// Used to detect that the value is some kind of trace data to help with the visualisation and processing.
|
||||
trace = 'trace',
|
||||
geo = 'geo',
|
||||
enum = 'enum',
|
||||
other = 'other', // Object, Array, etc
|
||||
}
|
||||
|
||||
@@ -91,10 +92,24 @@ export interface FieldConfig<TOptions = any> {
|
||||
// Alternative to empty string
|
||||
noValue?: string;
|
||||
|
||||
// The field type may map to specific config
|
||||
type?: FieldTypeConfig;
|
||||
|
||||
// Panel Specific Values
|
||||
custom?: TOptions;
|
||||
}
|
||||
|
||||
export interface FieldTypeConfig {
|
||||
enum?: EnumFieldConfig;
|
||||
}
|
||||
|
||||
export interface EnumFieldConfig {
|
||||
text?: string[];
|
||||
color?: string[];
|
||||
icon?: string[];
|
||||
description?: string[];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface ValueLinkConfig {
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,7 @@ export const availableIconsIndex = {
|
||||
link: true,
|
||||
'list-ui-alt': true,
|
||||
'list-ul': true,
|
||||
'list-ol': true,
|
||||
lock: true,
|
||||
'map-marker': true,
|
||||
message: true,
|
||||
|
||||
Reference in New Issue
Block a user