mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Transformations: Use an explicit join seperator when converting from an array to string field (#80169)
This commit is contained in:
parent
3c045d1dfb
commit
114845a99a
@ -359,6 +359,38 @@ describe('field convert types transformer', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('will support custom join separators', () => {
|
||||||
|
const options = {
|
||||||
|
conversions: [{ targetField: 'vals', destinationType: FieldType.string, joinWith: '|' }],
|
||||||
|
};
|
||||||
|
|
||||||
|
const arrayValues = toDataFrame({
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'vals',
|
||||||
|
type: FieldType.other,
|
||||||
|
values: [
|
||||||
|
['a', 'b', 2],
|
||||||
|
[3, 'x', 'y'],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const stringified = convertFieldTypes(options, [arrayValues]);
|
||||||
|
expect(
|
||||||
|
stringified[0].fields.map((f) => ({
|
||||||
|
type: f.type,
|
||||||
|
values: f.values,
|
||||||
|
}))
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
type: FieldType.string,
|
||||||
|
values: ['a|b|2', '3|x|y'],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('will convert time fields to strings', () => {
|
it('will convert time fields to strings', () => {
|
||||||
const options = {
|
const options = {
|
||||||
conversions: [{ targetField: 'time', destinationType: FieldType.string, dateFormat: 'YYYY-MM' }],
|
conversions: [{ targetField: 'time', destinationType: FieldType.string, dateFormat: 'YYYY-MM' }],
|
||||||
|
@ -27,6 +27,10 @@ export interface ConvertFieldTypeOptions {
|
|||||||
* Date format to parse a string datetime
|
* Date format to parse a string datetime
|
||||||
*/
|
*/
|
||||||
dateFormat?: string;
|
dateFormat?: string;
|
||||||
|
/**
|
||||||
|
* When converting an array to a string, the values can be joined with a custom separator
|
||||||
|
*/
|
||||||
|
joinWith?: string;
|
||||||
/**
|
/**
|
||||||
* When converting a date to a string an option timezone.
|
* When converting a date to a string an option timezone.
|
||||||
*/
|
*/
|
||||||
@ -103,7 +107,7 @@ export function convertFieldType(field: Field, opts: ConvertFieldTypeOptions): F
|
|||||||
case FieldType.number:
|
case FieldType.number:
|
||||||
return fieldToNumberField(field);
|
return fieldToNumberField(field);
|
||||||
case FieldType.string:
|
case FieldType.string:
|
||||||
return fieldToStringField(field, opts.dateFormat, { timeZone: opts.timezone });
|
return fieldToStringField(field, opts.dateFormat, { timeZone: opts.timezone }, opts.joinWith);
|
||||||
case FieldType.boolean:
|
case FieldType.boolean:
|
||||||
return fieldToBooleanField(field);
|
return fieldToBooleanField(field);
|
||||||
case FieldType.enum:
|
case FieldType.enum:
|
||||||
@ -192,7 +196,8 @@ function fieldToBooleanField(field: Field): Field {
|
|||||||
export function fieldToStringField(
|
export function fieldToStringField(
|
||||||
field: Field,
|
field: Field,
|
||||||
dateFormat?: string,
|
dateFormat?: string,
|
||||||
parseOptions?: DateTimeOptionsWhenParsing
|
parseOptions?: DateTimeOptionsWhenParsing,
|
||||||
|
joinWith?: string
|
||||||
): Field {
|
): Field {
|
||||||
let values = field.values;
|
let values = field.values;
|
||||||
|
|
||||||
@ -202,7 +207,12 @@ export function fieldToStringField(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FieldType.other:
|
case FieldType.other:
|
||||||
values = values.map((v) => JSON.stringify(v));
|
values = values.map((v) => {
|
||||||
|
if (joinWith?.length && Array.isArray(v)) {
|
||||||
|
return v.join(joinWith);
|
||||||
|
}
|
||||||
|
return JSON.stringify(v); // will quote strings and avoid "object"
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { guessFieldTypeForField } from '../../dataframe/processDataFrame';
|
import { guessFieldTypeForField, guessFieldTypeFromValue } from '../../dataframe/processDataFrame';
|
||||||
import { getFieldDisplayName } from '../../field';
|
import { getFieldDisplayName } from '../../field';
|
||||||
import { KeyValue } from '../../types/data';
|
import { KeyValue } from '../../types/data';
|
||||||
import { DataFrame, Field, FieldType } from '../../types/dataFrame';
|
import { DataFrame, Field, FieldType } from '../../types/dataFrame';
|
||||||
@ -224,6 +224,7 @@ export function reduceFields(data: DataFrame[], matcher: FieldMatcher, reducerId
|
|||||||
const value = results[reducer];
|
const value = results[reducer];
|
||||||
const copy = {
|
const copy = {
|
||||||
...field,
|
...field,
|
||||||
|
type: guessFieldTypeFromValue(value),
|
||||||
values: [value],
|
values: [value],
|
||||||
};
|
};
|
||||||
copy.state = undefined;
|
copy.state = undefined;
|
||||||
|
@ -82,6 +82,18 @@ export const ConvertFieldTypeTransformerEditor = ({
|
|||||||
[onChange, options]
|
[onChange, options]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onJoinWithChange = useCallback(
|
||||||
|
(idx: number) => (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const conversions = options.conversions;
|
||||||
|
conversions[idx] = { ...conversions[idx], joinWith: e.currentTarget.value };
|
||||||
|
onChange({
|
||||||
|
...options,
|
||||||
|
conversions: conversions,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[onChange, options]
|
||||||
|
);
|
||||||
|
|
||||||
const onAddConvertFieldType = useCallback(() => {
|
const onAddConvertFieldType = useCallback(() => {
|
||||||
onChange({
|
onChange({
|
||||||
...options,
|
...options,
|
||||||
@ -119,6 +131,7 @@ export const ConvertFieldTypeTransformerEditor = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{options.conversions.map((c: ConvertFieldTypeOptions, idx: number) => {
|
{options.conversions.map((c: ConvertFieldTypeOptions, idx: number) => {
|
||||||
|
const targetField = findField(input?.[0], c.targetField);
|
||||||
return (
|
return (
|
||||||
<div key={`${c.targetField}-${idx}`}>
|
<div key={`${c.targetField}-${idx}`}>
|
||||||
<InlineFieldRow>
|
<InlineFieldRow>
|
||||||
@ -152,8 +165,15 @@ export const ConvertFieldTypeTransformerEditor = ({
|
|||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
)}
|
)}
|
||||||
{c.destinationType === FieldType.string &&
|
{c.destinationType === FieldType.string && (
|
||||||
(c.dateFormat || findField(input?.[0], c.targetField)?.type === FieldType.time) && (
|
<>
|
||||||
|
{(c.joinWith?.length || targetField?.type === FieldType.other) && (
|
||||||
|
<InlineField label="Join with" tooltip="Use an explicit separator when joining array values">
|
||||||
|
<Input value={c.joinWith} placeholder={'JSON'} onChange={onJoinWithChange(idx)} width={9} />
|
||||||
|
</InlineField>
|
||||||
|
)}
|
||||||
|
{c.dateFormat ||
|
||||||
|
(targetField?.type === FieldType.time && (
|
||||||
<>
|
<>
|
||||||
<InlineField label="Date format" tooltip="Specify the output format.">
|
<InlineField label="Date format" tooltip="Specify the output format.">
|
||||||
<Input
|
<Input
|
||||||
@ -167,6 +187,8 @@ export const ConvertFieldTypeTransformerEditor = ({
|
|||||||
<Select options={timeZoneOptions} value={c.timezone} onChange={onTzChange(idx)} isClearable />
|
<Select options={timeZoneOptions} value={c.timezone} onChange={onTzChange(idx)} isClearable />
|
||||||
</InlineField>
|
</InlineField>
|
||||||
</>
|
</>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
size="md"
|
size="md"
|
||||||
|
Loading…
Reference in New Issue
Block a user