diff --git a/packages/grafana-data/src/transformations/transformers/convertFieldType.test.ts b/packages/grafana-data/src/transformations/transformers/convertFieldType.test.ts index d8e70c81138..96f55445c8f 100644 --- a/packages/grafana-data/src/transformations/transformers/convertFieldType.test.ts +++ b/packages/grafana-data/src/transformations/transformers/convertFieldType.test.ts @@ -338,6 +338,31 @@ describe('field convert types transformer', () => { }, ]); }); + + it('will convert time fields to strings', () => { + const options = { + conversions: [{ targetField: 'time', destinationType: FieldType.string, dateFormat: 'YYYY-MM' }], + }; + + const stringified = convertFieldTypes(options, [ + toDataFrame({ + fields: [ + { + name: 'time', + type: FieldType.time, + values: [1626674400000, 1627020000000, 1627192800000, 1627797600000, 1627884000000], + }, + ], + }), + ])[0].fields[0]; + expect(stringified.values.toArray()).toEqual([ + '2021-07', + '2021-07', + '2021-07', // can group by month + '2021-08', + '2021-08', + ]); + }); }); describe('ensureTimeField', () => { diff --git a/packages/grafana-data/src/transformations/transformers/convertFieldType.ts b/packages/grafana-data/src/transformations/transformers/convertFieldType.ts index 58136aa4f03..975d8ad55c9 100644 --- a/packages/grafana-data/src/transformations/transformers/convertFieldType.ts +++ b/packages/grafana-data/src/transformations/transformers/convertFieldType.ts @@ -98,7 +98,7 @@ export function convertFieldType(field: Field, opts: ConvertFieldTypeOptions): F case FieldType.number: return fieldToNumberField(field); case FieldType.string: - return fieldToStringField(field); + return fieldToStringField(field, opts.dateFormat); case FieldType.boolean: return fieldToBooleanField(field); case FieldType.other: @@ -179,17 +179,26 @@ function fieldToBooleanField(field: Field): Field { }; } -function fieldToStringField(field: Field): Field { - const stringValues = field.values.toArray().slice(); +function fieldToStringField(field: Field, dateFormat?: string): Field { + let values = field.values.toArray(); - for (let s = 0; s < stringValues.length; s++) { - stringValues[s] = `${stringValues[s]}`; + switch (field.type) { + case FieldType.time: + values = values.map((v) => dateTimeParse(v).format(dateFormat)); + break; + + case FieldType.other: + values = values.map((v) => JSON.stringify(v)); + break; + + default: + values = values.map((v) => `${v}`); } return { ...field, type: FieldType.string, - values: new ArrayVector(stringValues), + values: new ArrayVector(values), }; } diff --git a/packages/grafana-ui/src/types/icon.ts b/packages/grafana-ui/src/types/icon.ts index ab6313993b8..bf34ad0f357 100644 --- a/packages/grafana-ui/src/types/icon.ts +++ b/packages/grafana-ui/src/types/icon.ts @@ -12,7 +12,10 @@ export type IconSize = ComponentSize | 'xl' | 'xxl' | 'xxxl'; // function remains for backwards compatibility export const getAvailableIcons = () => Object.keys(availableIconsIndex); -/** Get the icon for a given field type */ +/** + * Get the icon for a given field type + * @deprecated use getFieldTypeIconName + */ export function getFieldTypeIcon(field?: Field): IconName { if (field) { switch (field.type) { @@ -34,3 +37,24 @@ export function getFieldTypeIcon(field?: Field): IconName { } return 'question-circle'; } + +/** Get the icon for a given field type */ +export function getFieldTypeIconName(fieldType?: FieldType): IconName { + switch (fieldType) { + case FieldType.time: + return 'clock-nine'; + case FieldType.string: + return 'font'; + case FieldType.number: + return 'calculator-alt'; + case FieldType.boolean: + return 'toggle-on'; + case FieldType.trace: + return 'info-circle'; + case FieldType.geo: + return 'map-marker'; + case FieldType.other: + return 'brackets-curly'; + } + return 'question-circle'; +} diff --git a/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx b/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx index 5589e33e898..0e6a10b1d57 100644 --- a/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx +++ b/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx @@ -14,8 +14,9 @@ import { ConvertFieldTypeOptions, ConvertFieldTypeTransformerOptions, } from '@grafana/data/src/transformations/transformers/convertFieldType'; -import { Button, InlineField, InlineFieldRow, Input, Select } from '@grafana/ui'; +import { Button, InlineField, InlineFieldRow, Input, Select, getFieldTypeIconName } from '@grafana/ui'; import { FieldNamePicker } from '@grafana/ui/src/components/MatchersUI/FieldNamePicker'; +import { findField } from 'app/features/dimensions'; const fieldNamePickerSettings: StandardEditorsRegistryItem = { settings: { width: 24, isClearable: false }, @@ -27,11 +28,11 @@ export const ConvertFieldTypeTransformerEditor = ({ onChange, }: TransformerUIProps) => { const allTypes: Array> = [ - { value: FieldType.number, label: 'Numeric' }, - { value: FieldType.string, label: 'String' }, - { value: FieldType.time, label: 'Time' }, - { value: FieldType.boolean, label: 'Boolean' }, - { value: FieldType.other, label: 'JSON' }, + { value: FieldType.number, label: 'Number', icon: getFieldTypeIconName(FieldType.number) }, + { value: FieldType.string, label: 'String', icon: getFieldTypeIconName(FieldType.string) }, + { value: FieldType.time, label: 'Time', icon: getFieldTypeIconName(FieldType.time) }, + { value: FieldType.boolean, label: 'Boolean', icon: getFieldTypeIconName(FieldType.boolean) }, + { value: FieldType.other, label: 'JSON', icon: getFieldTypeIconName(FieldType.other) }, ]; const onSelectField = useCallback( @@ -122,6 +123,11 @@ export const ConvertFieldTypeTransformerEditor = ({ )} + {c.destinationType === FieldType.string && (c.dateFormat || findField(input?.[0], c.targetField)) && ( + + + + )}