diff --git a/desktop/flipper-plugin/src/ui/DataFormatter.tsx b/desktop/flipper-plugin/src/ui/DataFormatter.tsx index aabc1f61c..a1dc5fdc4 100644 --- a/desktop/flipper-plugin/src/ui/DataFormatter.tsx +++ b/desktop/flipper-plugin/src/ui/DataFormatter.tsx @@ -20,6 +20,7 @@ import {safeStringify} from '../utils/safeStringify'; import {urlRegex} from '../utils/urlRegex'; import {useTableRedraw} from '../data-source/index'; import {theme} from './theme'; +import {HighlightManager} from './Highlight'; /** * A Formatter is used to render an arbitrarily value to React. If a formatter returns 'undefined' @@ -27,48 +28,65 @@ import {theme} from './theme'; * * In case further processing by the default formatter is to be avoided, make sure a string is returned from any custom formatter. */ -export type Formatter = (value: any) => string | React.ReactElement | any; +export type Formatter = ( + value: any, + highlighter?: HighlightManager, +) => string | React.ReactElement | any; export const DataFormatter = { - defaultFormatter(value: any) { + defaultFormatter(value: any, highlighter?: HighlightManager) { if (isValidElement(value)) { return value; } + let res = ''; switch (typeof value) { case 'boolean': - return value ? 'true' : 'false'; + res = value ? 'true' : 'false'; + break; case 'number': - return '' + value; + res = '' + value; + break; case 'undefined': - return ''; + break; case 'string': - return value; + res = value; + break; case 'object': { - if (value === null) return ''; + if (value === null) break; if (value instanceof Date) { - return ( + res = value.toTimeString().split(' ')[0] + '.' + - pad('' + value.getMilliseconds(), 3, '0') - ); + pad('' + value.getMilliseconds(), 3, '0'); + break; } if (value instanceof Map) { - return safeStringify(Array.from(value.entries())); + res = safeStringify(Array.from(value.entries())); + break; } if (value instanceof Set) { - return safeStringify(Array.from(value.values())); + res = safeStringify(Array.from(value.values())); + break; } - return safeStringify(value); + res = safeStringify(value); + break; } default: - return ''; + res = ''; } + return highlighter?.render(res) ?? res; }, truncate(maxLength: number) { - return (value: any) => { + return (value: any, highlighter?: HighlightManager) => { if (typeof value === 'string' && value.length > maxLength) { - return ; + return ( + + ); } return value; }; @@ -131,16 +149,20 @@ export const DataFormatter = { return value; }, - format(value: any, formatters?: Formatter[] | Formatter): any { + format( + value: any, + formatters?: Formatter[] | Formatter, + highlighter?: HighlightManager, + ): any { let res = value; if (Array.isArray(formatters)) { for (const formatter of formatters) { - res = formatter(res); + res = formatter(res, highlighter); } } else if (formatters) { - res = formatters(res); + res = formatters(res, highlighter); } - return DataFormatter.defaultFormatter(res); + return DataFormatter.defaultFormatter(res, highlighter); }, }; @@ -148,16 +170,18 @@ export const DataFormatter = { export function TruncateHelper({ value, maxLength, + textWrapper, }: { value: string; maxLength: number; + textWrapper?: HighlightManager; //Could be a generic type }) { const [collapsed, setCollapsed] = useState(true); const redrawRow = useTableRedraw(); - + const message = collapsed ? value.substr(0, maxLength) : value; return ( <> - {collapsed ? value.substr(0, maxLength) : value} + {textWrapper ? textWrapper.render(message) : message}