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', () => {
|
||||
const options = {
|
||||
conversions: [{ targetField: 'time', destinationType: FieldType.string, dateFormat: 'YYYY-MM' }],
|
||||
|
@ -27,6 +27,10 @@ export interface ConvertFieldTypeOptions {
|
||||
* Date format to parse a string datetime
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@ -103,7 +107,7 @@ export function convertFieldType(field: Field, opts: ConvertFieldTypeOptions): F
|
||||
case FieldType.number:
|
||||
return fieldToNumberField(field);
|
||||
case FieldType.string:
|
||||
return fieldToStringField(field, opts.dateFormat, { timeZone: opts.timezone });
|
||||
return fieldToStringField(field, opts.dateFormat, { timeZone: opts.timezone }, opts.joinWith);
|
||||
case FieldType.boolean:
|
||||
return fieldToBooleanField(field);
|
||||
case FieldType.enum:
|
||||
@ -192,7 +196,8 @@ function fieldToBooleanField(field: Field): Field {
|
||||
export function fieldToStringField(
|
||||
field: Field,
|
||||
dateFormat?: string,
|
||||
parseOptions?: DateTimeOptionsWhenParsing
|
||||
parseOptions?: DateTimeOptionsWhenParsing,
|
||||
joinWith?: string
|
||||
): Field {
|
||||
let values = field.values;
|
||||
|
||||
@ -202,7 +207,12 @@ export function fieldToStringField(
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { guessFieldTypeForField } from '../../dataframe/processDataFrame';
|
||||
import { guessFieldTypeForField, guessFieldTypeFromValue } from '../../dataframe/processDataFrame';
|
||||
import { getFieldDisplayName } from '../../field';
|
||||
import { KeyValue } from '../../types/data';
|
||||
import { DataFrame, Field, FieldType } from '../../types/dataFrame';
|
||||
@ -224,6 +224,7 @@ export function reduceFields(data: DataFrame[], matcher: FieldMatcher, reducerId
|
||||
const value = results[reducer];
|
||||
const copy = {
|
||||
...field,
|
||||
type: guessFieldTypeFromValue(value),
|
||||
values: [value],
|
||||
};
|
||||
copy.state = undefined;
|
||||
|
@ -82,6 +82,18 @@ export const ConvertFieldTypeTransformerEditor = ({
|
||||
[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(() => {
|
||||
onChange({
|
||||
...options,
|
||||
@ -119,6 +131,7 @@ export const ConvertFieldTypeTransformerEditor = ({
|
||||
return (
|
||||
<>
|
||||
{options.conversions.map((c: ConvertFieldTypeOptions, idx: number) => {
|
||||
const targetField = findField(input?.[0], c.targetField);
|
||||
return (
|
||||
<div key={`${c.targetField}-${idx}`}>
|
||||
<InlineFieldRow>
|
||||
@ -152,8 +165,15 @@ export const ConvertFieldTypeTransformerEditor = ({
|
||||
/>
|
||||
</InlineField>
|
||||
)}
|
||||
{c.destinationType === FieldType.string &&
|
||||
(c.dateFormat || findField(input?.[0], c.targetField)?.type === FieldType.time) && (
|
||||
{c.destinationType === FieldType.string && (
|
||||
<>
|
||||
{(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.">
|
||||
<Input
|
||||
@ -167,6 +187,8 @@ export const ConvertFieldTypeTransformerEditor = ({
|
||||
<Select options={timeZoneOptions} value={c.timezone} onChange={onTzChange(idx)} isClearable />
|
||||
</InlineField>
|
||||
</>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
size="md"
|
||||
|
Loading…
Reference in New Issue
Block a user