ConvertFieldType: Update "join with" to work on array of strings (#105074)

* fix: update join with to work on array of strings

* chore: simplify

* chore: cleanup

* chore: add tests!

* fix: more robust check
pull/105487/head
Alex Spencer 1 month ago committed by GitHub
parent f7cad3a2fe
commit b77bf98890
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 34
      packages/grafana-data/src/transformations/transformers/convertFieldType.test.ts
  2. 5
      packages/grafana-data/src/transformations/transformers/convertFieldType.ts
  3. 12
      public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx

@ -359,7 +359,7 @@ describe('field convert types transformer', () => {
]); ]);
}); });
it('will support custom join separators', () => { it('will support custom join separators for field type other', () => {
const options = { const options = {
conversions: [{ targetField: 'vals', destinationType: FieldType.string, joinWith: '|' }], conversions: [{ targetField: 'vals', destinationType: FieldType.string, joinWith: '|' }],
}; };
@ -391,6 +391,38 @@ describe('field convert types transformer', () => {
]); ]);
}); });
it('will support custom join separators for field type string', () => {
const options = {
conversions: [{ targetField: 'string_arrays', destinationType: FieldType.string, joinWith: '&' }],
};
const stringArrayValues = toDataFrame({
fields: [
{
name: 'string_arrays',
type: FieldType.string,
values: [
['a', 'b', 'c'],
['d', 'e', 'f'],
],
},
],
});
const stringified = convertFieldTypes(options, [stringArrayValues]);
expect(
stringified[0].fields.map(({ type, values }) => ({
type,
values,
}))
).toEqual([
{
type: FieldType.string,
values: ['a&b&c', 'd&e&f'],
},
]);
});
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' }],

@ -210,12 +210,15 @@ export function fieldToStringField(
values = values.map((v) => dateTimeParse(v, parseOptions).format(dateFormat)); values = values.map((v) => dateTimeParse(v, parseOptions).format(dateFormat));
break; break;
// Handle both "string" and "other" types to ensure compatibility across Grafana versions (10 & 11)
// In some cases fields are classified as 'other' in Grafana 10 but as 'string' in Grafana 11
case FieldType.string:
case FieldType.other: case FieldType.other:
values = values.map((v) => { values = values.map((v) => {
if (joinWith?.length && Array.isArray(v)) { if (joinWith?.length && Array.isArray(v)) {
return v.join(joinWith); return v.join(joinWith);
} }
return JSON.stringify(v); // will quote strings and avoid "object" return field.type === FieldType.other ? JSON.stringify(v) : `${v}`;
}); });
break; break;

@ -130,6 +130,14 @@ export const ConvertFieldTypeTransformerEditor = ({
<> <>
{options.conversions.map((c: ConvertFieldTypeOptions, idx: number) => { {options.conversions.map((c: ConvertFieldTypeOptions, idx: number) => {
const targetField = findField(input?.[0], c.targetField); const targetField = findField(input?.[0], c.targetField);
// Show "Join with" input when:
// - A join value exists (maintains backward compatibility)
// - Target field type is 'other' (Grafana 10) or 'string' (Grafana 11)
// This ensures consistent UI across versions where arrays may be classified differently.
const shouldRenderJoinWith =
c.joinWith?.length || (targetField?.type && [FieldType.other, FieldType.string].includes(targetField.type));
return ( return (
<div key={`${c.targetField}-${idx}`}> <div key={`${c.targetField}-${idx}`}>
<InlineFieldRow> <InlineFieldRow>
@ -169,7 +177,7 @@ export const ConvertFieldTypeTransformerEditor = ({
)} )}
{c.destinationType === FieldType.string && ( {c.destinationType === FieldType.string && (
<> <>
{(c.joinWith?.length || targetField?.type === FieldType.other) && ( {shouldRenderJoinWith && (
<InlineField <InlineField
label={t('transformers.convert-field-type-transformer-editor.label-join-with', 'Join with')} label={t('transformers.convert-field-type-transformer-editor.label-join-with', 'Join with')}
tooltip={t( tooltip={t(
@ -182,7 +190,7 @@ export const ConvertFieldTypeTransformerEditor = ({
// eslint-disable-next-line @grafana/no-untranslated-strings // eslint-disable-next-line @grafana/no-untranslated-strings
placeholder={'JSON'} placeholder={'JSON'}
onChange={onJoinWithChange(idx)} onChange={onJoinWithChange(idx)}
width={9} width={16}
/> />
</InlineField> </InlineField>
)} )}

Loading…
Cancel
Save