Table: JSONCell should use formatted text

This commit is contained in:
Paul Marbach 2025-10-02 10:57:07 -04:00
parent ce6239b5da
commit c4a5d86a69
3 changed files with 47 additions and 22 deletions

View File

@ -19,9 +19,11 @@ import {
import {
DataHoverClearEvent,
DataHoverEvent,
DecimalCount,
FALLBACK_COLOR,
Field,
FieldType,
formattedValueToString,
getDisplayProcessor,
} from '@grafana/data';
import { Trans } from '@grafana/i18n';
@ -439,7 +441,7 @@ export function TableNG(props: TableNGProps) {
// attach JSONCell custom display function to JSONView cell type
if (cellType === TableCellDisplayMode.JSONView || field.type === FieldType.other) {
field.display = displayJsonValue;
field.display = displayJsonValue(field);
}
// For some cells, "aligning" the cell will mean aligning the inline contents of the cell with

View File

@ -48,6 +48,7 @@ import {
predicateByName,
parseStyleJson,
calculateFooterHeight,
displayJsonValue,
} from './utils';
describe('TableNG utils', () => {
@ -1355,10 +1356,35 @@ describe('TableNG utils', () => {
});
describe('displayJsonValue', () => {
it.todo('should parse and then stringify string values');
it.todo('should not throw for non-serializable string values');
it.todo('should stringify non-string values');
it.todo('should not throw for non-serializable non-string values');
let field: Field;
beforeEach(() => {
field = {
name: 'test',
type: FieldType.string,
config: {},
state: { displayName: 'Test Display Name' },
values: [],
display: (val: unknown) => ({ text: String(val), numeric: NaN }),
};
});
it('should parse and then stringify string values', () => {
expect(displayJsonValue(field)('{"valid": "json"}').text).toBe('{\n "valid": "json"\n}');
});
it('should not throw for non-serializable string values', () => {
expect(displayJsonValue(field)('{"invalid": "json').text).toBe('{"invalid": "json');
});
it('should stringify non-string values', () => {
expect(displayJsonValue(field)(42).text).toBe('42');
});
it('should use the underlying field.display method to format values and return numeric values', () => {
field.display = (val: unknown) => ({ text: `**${val}**`, numeric: Number(val), suffix: 'ms' });
expect(displayJsonValue(field)(42).text).toBe('**42**ms');
expect(displayJsonValue(field)(42).numeric).toBe(42);
});
});
describe('applySort', () => {

View File

@ -15,6 +15,7 @@ import {
DisplayValueAlignmentFactors,
DataFrame,
DisplayProcessor,
DecimalCount,
} from '@grafana/data';
import {
BarGaugeDisplayMode,
@ -970,28 +971,24 @@ export function canFieldBeColorized(
);
}
export const displayJsonValue: DisplayProcessor = (value: unknown): DisplayValue => {
let displayValue: string;
export const displayJsonValue: (field: Field) => DisplayProcessor = (field: Field, decimals?: DecimalCount) => {
const origDisplay = field.display!;
return (value: unknown): DisplayValue => {
let jsonText: string;
// Handle string values that might be JSON
if (typeof value === 'string') {
const displayValue = origDisplay(value, decimals);
const formattedValue = formattedValueToString(displayValue);
// Handle string values that might be JSON
try {
const parsed = JSON.parse(value);
displayValue = JSON.stringify(parsed, null, ' ');
const parsed = JSON.parse(formattedValue);
jsonText = JSON.stringify(parsed, null, ' ');
} catch {
displayValue = value; // Keep original if not valid JSON
jsonText = formattedValue; // Keep original if not valid JSON
}
} else {
// For non-string values, stringify them
try {
displayValue = JSON.stringify(value, null, ' ');
} catch (error) {
// Handle circular references or other stringify errors
displayValue = String(value);
}
}
return { text: displayValue, numeric: Number.NaN };
return { ...displayValue, text: jsonText };
};
};
export function getSummaryCellTextAlign(textAlign: TextAlign, cellType: TableCellDisplayMode): TextAlign {