mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 00:47:38 -06:00
Transformations: Use fieldMatchers for convertFieldType and add doc (#38769)
This commit is contained in:
parent
caef39b6a4
commit
2a2f10da7e
@ -10,6 +10,7 @@ Grafana comes with the following transformations:
|
|||||||
- [Add field from calculation]({{< relref "./types-options.md#add-field-from-calculation" >}})
|
- [Add field from calculation]({{< relref "./types-options.md#add-field-from-calculation" >}})
|
||||||
- [Concatenate fields]({{< relref "./types-options.md#concatenate-fields" >}})
|
- [Concatenate fields]({{< relref "./types-options.md#concatenate-fields" >}})
|
||||||
- [Config from query results]({{< relref "./config-from-query.md" >}})
|
- [Config from query results]({{< relref "./config-from-query.md" >}})
|
||||||
|
- [Convert field type]({{< relref "./types-options.md#convert-field-type" >}})
|
||||||
- [Filter data by name]({{< relref "./types-options.md#filter-data-by-name" >}})
|
- [Filter data by name]({{< relref "./types-options.md#filter-data-by-name" >}})
|
||||||
- [Filter data by query]({{< relref "./types-options.md#filter-data-by-query" >}})
|
- [Filter data by query]({{< relref "./types-options.md#filter-data-by-query" >}})
|
||||||
- [Filter data by value]({{< relref "./types-options.md#filter-data-by-value" >}})
|
- [Filter data by value]({{< relref "./types-options.md#filter-data-by-value" >}})
|
||||||
@ -324,6 +325,36 @@ After you concatenate the fields, the data frame would be:
|
|||||||
| ---- | ------- | --- | ------ |
|
| ---- | ------- | --- | ------ |
|
||||||
| 15.4 | 1230233 | 3.2 | 5 |
|
| 15.4 | 1230233 | 3.2 | 5 |
|
||||||
|
|
||||||
|
## Convert field type
|
||||||
|
|
||||||
|
This transformation changes the field type of the specified field.
|
||||||
|
|
||||||
|
- **Field -** Select from available fields
|
||||||
|
- **as -** Select the FieldType to convert to
|
||||||
|
- **Numeric -** attempts to make the values numbers
|
||||||
|
- **String -** will make the values strings
|
||||||
|
- **Time -** attempts to parse the values as time
|
||||||
|
- Will show an option to specify a DateFormat as input by a string like yyyy-mm-dd or DD MM YYYY hh:mm:ss
|
||||||
|
- **Boolean -** will make the values booleans
|
||||||
|
|
||||||
|
For example the following query could be modified by selecting the time field, as Time, and Date Format as YYYY.
|
||||||
|
|
||||||
|
| Time | Mark | Value |
|
||||||
|
| ---------- | ----- | ----- |
|
||||||
|
| 2017-07-01 | above | 25 |
|
||||||
|
| 2018-08-02 | below | 22 |
|
||||||
|
| 2019-09-02 | below | 29 |
|
||||||
|
| 2020-10-04 | above | 22 |
|
||||||
|
|
||||||
|
The result:
|
||||||
|
|
||||||
|
| Time | Mark | Value |
|
||||||
|
| ------------------- | ----- | ----- |
|
||||||
|
| 2017-01-01 00:00:00 | above | 25 |
|
||||||
|
| 2018-01-01 00:00:00 | below | 22 |
|
||||||
|
| 2019-01-01 00:00:00 | below | 29 |
|
||||||
|
| 2020-01-01 00:00:00 | above | 22 |
|
||||||
|
|
||||||
## Series to rows
|
## Series to rows
|
||||||
|
|
||||||
> **Note:** This transformation is available in Grafana 7.1+.
|
> **Note:** This transformation is available in Grafana 7.1+.
|
||||||
|
@ -5,20 +5,28 @@ import { DataTransformerID } from './ids';
|
|||||||
import { DataFrame, Field, FieldType } from '../../types/dataFrame';
|
import { DataFrame, Field, FieldType } from '../../types/dataFrame';
|
||||||
import { dateTimeParse } from '../../datetime';
|
import { dateTimeParse } from '../../datetime';
|
||||||
import { ArrayVector } from '../../vector';
|
import { ArrayVector } from '../../vector';
|
||||||
|
import { fieldMatchers } from '../matchers';
|
||||||
|
import { FieldMatcherID } from '../matchers/ids';
|
||||||
|
|
||||||
export interface ConvertFieldTypeTransformerOptions {
|
export interface ConvertFieldTypeTransformerOptions {
|
||||||
conversions: ConvertFieldTypeOptions[];
|
conversions: ConvertFieldTypeOptions[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConvertFieldTypeOptions {
|
export interface ConvertFieldTypeOptions {
|
||||||
|
/**
|
||||||
|
* The field to convert field type
|
||||||
|
*/
|
||||||
targetField?: string;
|
targetField?: string;
|
||||||
|
/**
|
||||||
|
* The field type to convert to
|
||||||
|
*/
|
||||||
destinationType?: FieldType;
|
destinationType?: FieldType;
|
||||||
|
/**
|
||||||
|
* Date format to parse a string datetime
|
||||||
|
*/
|
||||||
dateFormat?: string;
|
dateFormat?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @alpha
|
|
||||||
*/
|
|
||||||
export const convertFieldTypeTransformer: SynchronousDataTransformerInfo<ConvertFieldTypeTransformerOptions> = {
|
export const convertFieldTypeTransformer: SynchronousDataTransformerInfo<ConvertFieldTypeTransformerOptions> = {
|
||||||
id: DataTransformerID.convertFieldType,
|
id: DataTransformerID.convertFieldType,
|
||||||
name: 'Convert field type',
|
name: 'Convert field type',
|
||||||
@ -43,32 +51,44 @@ export const convertFieldTypeTransformer: SynchronousDataTransformerInfo<Convert
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @alpha
|
* Convert field types for dataframe(s)
|
||||||
|
* @param options - field type conversion options
|
||||||
|
* @param frames - dataframe(s) with field types to convert
|
||||||
|
* @returns dataframe(s) with converted field types
|
||||||
*/
|
*/
|
||||||
export function convertFieldTypes(options: ConvertFieldTypeTransformerOptions, frames: DataFrame[]): DataFrame[] {
|
export function convertFieldTypes(options: ConvertFieldTypeTransformerOptions, frames: DataFrame[]): DataFrame[] {
|
||||||
if (!options.conversions.length) {
|
if (!options.conversions.length) {
|
||||||
return frames;
|
return frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
const frameCopy: DataFrame[] = [];
|
const framesCopy = frames.map((frame) => ({ ...frame }));
|
||||||
|
|
||||||
frames.forEach((frame) => {
|
for (const conversion of options.conversions) {
|
||||||
for (let fieldIdx = 0; fieldIdx < frame.fields.length; fieldIdx++) {
|
if (!conversion.targetField) {
|
||||||
let field = frame.fields[fieldIdx];
|
continue;
|
||||||
for (let cIdx = 0; cIdx < options.conversions.length; cIdx++) {
|
|
||||||
if (field.name === options.conversions[cIdx].targetField) {
|
|
||||||
//check in about matchers with Ryan
|
|
||||||
const conversion = options.conversions[cIdx];
|
|
||||||
frame.fields[fieldIdx] = convertFieldType(field, conversion);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
frameCopy.push(frame);
|
const matches = fieldMatchers.get(FieldMatcherID.byName).get(conversion.targetField);
|
||||||
});
|
for (const frame of framesCopy) {
|
||||||
return frameCopy;
|
frame.fields = frame.fields.map((field) => {
|
||||||
|
if (matches(field, frame, framesCopy)) {
|
||||||
|
return convertFieldType(field, conversion);
|
||||||
|
}
|
||||||
|
return field;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return framesCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a single field type to specifed field type.
|
||||||
|
* @param field - field to convert
|
||||||
|
* @param opts - field conversion options
|
||||||
|
* @returns converted field
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
export function convertFieldType(field: Field, opts: ConvertFieldTypeOptions): Field {
|
export function convertFieldType(field: Field, opts: ConvertFieldTypeOptions): Field {
|
||||||
switch (opts.destinationType) {
|
switch (opts.destinationType) {
|
||||||
case FieldType.time:
|
case FieldType.time:
|
||||||
@ -84,6 +104,9 @@ export function convertFieldType(field: Field, opts: ConvertFieldTypeOptions): F
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
export function fieldToTimeField(field: Field, dateFormat?: string): Field {
|
export function fieldToTimeField(field: Field, dateFormat?: string): Field {
|
||||||
let opts = dateFormat ? { format: dateFormat } : undefined;
|
let opts = dateFormat ? { format: dateFormat } : undefined;
|
||||||
|
|
||||||
@ -109,12 +132,8 @@ function fieldToNumberField(field: Field): Field {
|
|||||||
const numValues = field.values.toArray().slice();
|
const numValues = field.values.toArray().slice();
|
||||||
|
|
||||||
for (let n = 0; n < numValues.length; n++) {
|
for (let n = 0; n < numValues.length; n++) {
|
||||||
if (numValues[n]) {
|
const number = +numValues[n];
|
||||||
let number = +numValues[n];
|
numValues[n] = Number.isFinite(number) ? number : null;
|
||||||
numValues[n] = Number.isFinite(number) ? number : null;
|
|
||||||
} else {
|
|
||||||
numValues[n] = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -128,7 +147,7 @@ function fieldToBooleanField(field: Field): Field {
|
|||||||
const booleanValues = field.values.toArray().slice();
|
const booleanValues = field.values.toArray().slice();
|
||||||
|
|
||||||
for (let b = 0; b < booleanValues.length; b++) {
|
for (let b = 0; b < booleanValues.length; b++) {
|
||||||
booleanValues[b] = Boolean(booleanValues[b]);
|
booleanValues[b] = Boolean(!!booleanValues[b]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -153,7 +172,12 @@ function fieldToStringField(field: Field): Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @alpha
|
* Checks the first value. Assumes any number should be time fieldtype. Otherwise attempts to make the fieldtype time.
|
||||||
|
* @param field - field to ensure is a time fieldtype
|
||||||
|
* @param dateFormat - date format used to parse a string datetime
|
||||||
|
* @returns field as time
|
||||||
|
*
|
||||||
|
* @public
|
||||||
*/
|
*/
|
||||||
export function ensureTimeField(field: Field, dateFormat?: string): Field {
|
export function ensureTimeField(field: Field, dateFormat?: string): Field {
|
||||||
const firstValueTypeIsNumber = typeof field.values.get(0) === 'number';
|
const firstValueTypeIsNumber = typeof field.values.get(0) === 'number';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { ChangeEvent, useCallback } from 'react';
|
||||||
import {
|
import {
|
||||||
DataTransformerID,
|
DataTransformerID,
|
||||||
FieldNamePickerConfigSettings,
|
FieldNamePickerConfigSettings,
|
||||||
@ -56,9 +56,9 @@ export const ConvertFieldTypeTransformerEditor: React.FC<TransformerUIProps<Conv
|
|||||||
);
|
);
|
||||||
|
|
||||||
const onInputFormat = useCallback(
|
const onInputFormat = useCallback(
|
||||||
(idx) => (value: SelectableValue<string>) => {
|
(idx) => (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
const conversions = options.conversions;
|
const conversions = options.conversions;
|
||||||
conversions[idx] = { ...conversions[idx], dateFormat: value.value };
|
conversions[idx] = { ...conversions[idx], dateFormat: e.currentTarget.value };
|
||||||
onChange({
|
onChange({
|
||||||
...options,
|
...options,
|
||||||
conversions: conversions,
|
conversions: conversions,
|
||||||
|
Loading…
Reference in New Issue
Block a user