[release-12.2.2] Table: Pill and JSON Cells should allow formatting (#113130)
Table: Pill and JSON Cells should allow formatting (#111951)
* Table: PillCell should use formatted text inside pills
* Table: JSONCell should use formatted text
* remove unused imports
(cherry picked from commit 237ab6c1b4)
Co-authored-by: Paul Marbach <paul.marbach@grafana.com>
This commit is contained in:
co-authored by
Paul Marbach
parent
75d12036b8
commit
dc12aeb4ab
@@ -14,6 +14,7 @@ describe('PillCell', () => {
|
||||
type: FieldType.string,
|
||||
values: values,
|
||||
config: {},
|
||||
display: (value: unknown) => ({ text: String(value), color: '#FF780A', numeric: NaN }),
|
||||
});
|
||||
|
||||
const ser = new XMLSerializer();
|
||||
@@ -119,6 +120,29 @@ describe('PillCell', () => {
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('custom display text', () => {
|
||||
const mockField = fieldWithValues(['value1,value2,value3']);
|
||||
const field = {
|
||||
...mockField,
|
||||
display: (value: unknown) => ({
|
||||
text: `${value} lbs`,
|
||||
color: '#FF780A',
|
||||
numeric: 0,
|
||||
}),
|
||||
} satisfies Field;
|
||||
|
||||
expectHTML(
|
||||
render(
|
||||
<PillCell getTextColorForBackground={getTextColorForBackground} field={field} rowIdx={0} theme={theme} />
|
||||
),
|
||||
`
|
||||
<span style=\"background-color: rgb(207, 250, 255); color: rgb(32, 34, 38);\">value1 lbs</span>
|
||||
<span style=\"background-color: rgb(229, 172, 14); color: rgb(247, 248, 250);\">value2 lbs</span>
|
||||
<span style=\"background-color: rgb(63, 104, 51); color: rgb(247, 248, 250);\">value3 lbs</span>
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Color by value mappings', () => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
getColorByStringHash,
|
||||
FALLBACK_COLOR,
|
||||
fieldColorModeRegistry,
|
||||
formattedValueToString,
|
||||
} from '@grafana/data';
|
||||
import { FieldColorModeId } from '@grafana/schema';
|
||||
|
||||
@@ -20,10 +21,11 @@ export function PillCell({ rowIdx, field, theme, getTextColorForBackground }: Pi
|
||||
const pillValues = inferPills(value);
|
||||
return pillValues.length > 0
|
||||
? pillValues.map((pill, index) => {
|
||||
const bgColor = getPillColor(pill, field, theme);
|
||||
const renderedValue = formattedValueToString(field.display!(pill));
|
||||
const bgColor = getPillColor(renderedValue, field, theme);
|
||||
const textColor = getTextColorForBackground(bgColor);
|
||||
return {
|
||||
value: String(pill),
|
||||
value: renderedValue,
|
||||
key: `${pill}-${index}`,
|
||||
bgColor,
|
||||
color: textColor,
|
||||
|
||||
@@ -438,7 +438,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
|
||||
|
||||
@@ -47,6 +47,7 @@ import {
|
||||
getDisplayName,
|
||||
predicateByName,
|
||||
calculateFooterHeight,
|
||||
displayJsonValue,
|
||||
} from './utils';
|
||||
|
||||
describe('TableNG utils', () => {
|
||||
@@ -1354,10 +1355,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', () => {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user