Improve data inspector by showing previews of simple values

Summary:
It was requested a few times to inline simple values in the preview, to be able to quickly inspect vectors etc while inspecting elements

Implements https://github.com/facebook/flipper/issues/2551

Reviewed By: passy

Differential Revision: D29555541

fbshipit-source-id: c2c171cd7d2bf213f0cd05b5b5723918c9536025
This commit is contained in:
Michel Weststrate
2021-07-07 05:04:18 -07:00
committed by Facebook GitHub Bot
parent 6c534f5749
commit 17e064294c
3 changed files with 49 additions and 9 deletions

View File

@@ -41,7 +41,7 @@ export const presetColors = Object.values({
grape: '#8c72cb', // Grape grape: '#8c72cb', // Grape
}); });
const NullValue = styled.span({ export const NullValue = styled.span({
color: theme.semanticColors.nullValue, color: theme.semanticColors.nullValue,
}); });
NullValue.displayName = 'DataDescription:NullValue'; NullValue.displayName = 'DataDescription:NullValue';
@@ -51,7 +51,7 @@ const UndefinedValue = styled.span({
}); });
UndefinedValue.displayName = 'DataDescription:UndefinedValue'; UndefinedValue.displayName = 'DataDescription:UndefinedValue';
const StringValue = styled.span({ export const StringValue = styled.span({
color: theme.semanticColors.stringValue, color: theme.semanticColors.stringValue,
wordWrap: 'break-word', wordWrap: 'break-word',
}); });
@@ -67,12 +67,12 @@ const SymbolValue = styled.span({
}); });
SymbolValue.displayName = 'DataDescription:SymbolValue'; SymbolValue.displayName = 'DataDescription:SymbolValue';
const NumberValue = styled.span({ export const NumberValue = styled.span({
color: theme.semanticColors.numberValue, color: theme.semanticColors.numberValue,
}); });
NumberValue.displayName = 'DataDescription:NumberValue'; NumberValue.displayName = 'DataDescription:NumberValue';
const BooleanValue = styled.span({ export const BooleanValue = styled.span({
color: theme.semanticColors.booleanValue, color: theme.semanticColors.booleanValue,
}); });
BooleanValue.displayName = 'DataDescription:BooleanValue'; BooleanValue.displayName = 'DataDescription:BooleanValue';

View File

@@ -7,7 +7,14 @@
* @format * @format
*/ */
import {DataDescriptionType, DataDescription} from './DataDescription'; import {
DataDescriptionType,
DataDescription,
NullValue,
BooleanValue,
NumberValue,
StringValue,
} from './DataDescription';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import {getSortedKeys} from './utils'; import {getSortedKeys} from './utils';
import {PureComponent} from 'react'; import {PureComponent} from 'react';
@@ -67,6 +74,27 @@ export default class DataPreview extends PureComponent<{
maxProperties: 5, maxProperties: 5,
}; };
previewSimpleValue(propValue: any) {
let propValueElement: React.ReactElement | null = null;
switch (typeof propValue) {
case 'object':
if (propValue === null) propValueElement = <NullValue>null</NullValue>;
break;
case 'boolean':
propValueElement = <BooleanValue>{'' + propValue}</BooleanValue>;
break;
case 'number':
propValueElement = <NumberValue>{'' + propValue}</NumberValue>;
break;
case 'string':
if (propValue.length <= 20) {
propValueElement = <StringValue>{propValue}</StringValue>;
}
break;
}
return propValueElement;
}
render() { render() {
const {depth, extractValue, path, type, value} = this.props; const {depth, extractValue, path, type, value} = this.props;
@@ -109,10 +137,17 @@ export default class DataPreview extends PureComponent<{
if (i >= this.props.maxProperties) { if (i >= this.props.maxProperties) {
ellipsis = <span key={'ellipsis'}></span>; ellipsis = <span key={'ellipsis'}></span>;
} }
const propValueElement = this.previewSimpleValue(
value[key]?.value ?? value[key], // might be a wrapped reflection object or not..
);
propertyNodes.push( propertyNodes.push(
<span key={key}> <span key={key}>
<InspectorName>{key}</InspectorName> <InspectorName>
{key}
{propValueElement ? `: ` : null}
{propValueElement}
</InspectorName>
{ellipsis} {ellipsis}
</span>, </span>,
); );

View File

@@ -16,10 +16,12 @@ import {sleep} from '../../../utils/sleep';
const json = { const json = {
data: { data: {
is: { is: {
awesomely: 'cool', awesomely: 'cool cool cool cool cool cool cool', // long enough to prevent quick preview
}, },
and: { and: {
also: 'json', also: {
deeper: 'json',
},
}, },
}, },
}; };
@@ -46,10 +48,13 @@ test('can manually collapse properties', async () => {
fireEvent.click(await res.findByText(/data/)); fireEvent.click(await res.findByText(/data/));
await res.findByText(/awesomely/); await res.findByText(/awesomely/);
expect(res.queryAllByText(/cool/).length).toBe(0); expect(res.queryAllByText(/cool/).length).toBe(0);
expect(res.queryAllByText(/also/).length).toBe(1); // key shown as preview
expect(res.queryAllByText(/deeper/).length).toBe(0);
fireEvent.click(await res.findByText(/is/)); fireEvent.click(await res.findByText(/is/));
await res.findByText(/cool/); await res.findByText(/cool/);
expect(res.queryAllByText(/json/).length).toBe(0); // this node is not shown
expect(res.queryAllByText(/json/).length).toBe(0); // this is shown thanks to quick preview
// collapsing everything again // collapsing everything again
fireEvent.click(await res.findByText(/data/)); fireEvent.click(await res.findByText(/data/));