Add support for Subsections
Summary:
in the figma design we have the concept of subsections which are single level deep objects shown inline
{F1126292520}
More complex nested objects are shown a a preview that you have to click on and will come later
Reviewed By: lblasa
Differential Revision: D50595984
fbshipit-source-id: ea831731b87ce9968516129cf177953e200cf4d5
This commit is contained in:
committed by
Facebook GitHub Bot
parent
b184500d94
commit
65de40be7c
@@ -7,7 +7,7 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {Input, Typography} from 'antd';
|
||||
import {Divider, Input, Typography} from 'antd';
|
||||
import {Panel, theme, Layout} from 'flipper-plugin';
|
||||
import React from 'react';
|
||||
import {
|
||||
@@ -19,7 +19,8 @@ import {
|
||||
import {MetadataMap} from '../../DesktopTypes';
|
||||
import {NoData} from '../sidebar/inspector/NoData';
|
||||
import {css, cx} from '@emotion/css';
|
||||
import {upperFirst} from 'lodash';
|
||||
import {upperFirst, sortBy} from 'lodash';
|
||||
import {any} from 'lodash/fp';
|
||||
|
||||
export function AttributesInspector({
|
||||
node,
|
||||
@@ -64,40 +65,63 @@ function AttributeSection(
|
||||
name: string,
|
||||
inspectable: InspectableObject,
|
||||
) {
|
||||
const children = Object.keys(inspectable.fields)
|
||||
.map((key) => {
|
||||
const metadataId: number = Number(key);
|
||||
const attributesOrSubSubsections = Object.entries(inspectable.fields).map(
|
||||
([fieldKey, attributeValue]) => {
|
||||
const metadataId: number = Number(fieldKey);
|
||||
const attributeMetadata = metadataMap.get(metadataId);
|
||||
const attributeName =
|
||||
upperFirst(attributeMetadata?.name) ?? String(metadataId);
|
||||
//subsections are complex types that are only 1 level deep
|
||||
const isSubSection =
|
||||
attributeValue.type === 'object' &&
|
||||
!any(
|
||||
(inspectable) =>
|
||||
inspectable.type === 'array' || inspectable.type === 'object',
|
||||
Object.values(attributeValue.fields),
|
||||
);
|
||||
return {
|
||||
attributeName,
|
||||
attributeMetadata,
|
||||
isSubSection,
|
||||
attributeValue,
|
||||
metadataId,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
//push sub sections to the end
|
||||
const sortedAttributesOrSubsections = sortBy(
|
||||
attributesOrSubSubsections,
|
||||
[(item) => item.isSubSection],
|
||||
(item) => item.attributeName,
|
||||
);
|
||||
|
||||
const children = sortedAttributesOrSubsections
|
||||
.map(({isSubSection, attributeValue, attributeMetadata, attributeName}) => {
|
||||
if (attributeMetadata == null) {
|
||||
return null;
|
||||
}
|
||||
const attributeValue = inspectable.fields[metadataId];
|
||||
|
||||
const attributeName =
|
||||
upperFirst(attributeMetadata?.name) ?? String(metadataId);
|
||||
if (isSubSection) {
|
||||
if (attributeValue.type === 'object') {
|
||||
return (
|
||||
<Layout.Horizontal key={key} gap="small">
|
||||
<Typography.Text
|
||||
style={{
|
||||
marginTop: 3, //to center with top input when multiline
|
||||
flex: '0 0 30%', //take 30% of the width
|
||||
color: theme.textColorSecondary,
|
||||
fontWeight: 50,
|
||||
}}>
|
||||
{attributeName}
|
||||
</Typography.Text>
|
||||
|
||||
<Layout.Container style={{flex: '1 1 auto'}}>
|
||||
<AttributeValue
|
||||
name={attributeName}
|
||||
attributeMetadata={attributeMetadata}
|
||||
<SubSection
|
||||
attributeName={attributeName}
|
||||
inspectableObject={attributeValue}
|
||||
metadataMap={metadataMap}
|
||||
inspectable={attributeValue}
|
||||
level={1}
|
||||
/>
|
||||
</Layout.Container>
|
||||
</Layout.Horizontal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<NamedAttribute
|
||||
attributeMetadata={attributeMetadata}
|
||||
key={attributeName}
|
||||
metadataMap={metadataMap}
|
||||
name={attributeName}
|
||||
value={attributeValue}
|
||||
/>
|
||||
);
|
||||
})
|
||||
.filter((attr) => attr != null);
|
||||
@@ -115,6 +139,81 @@ function AttributeSection(
|
||||
}
|
||||
}
|
||||
|
||||
function SubSection({
|
||||
attributeName,
|
||||
inspectableObject,
|
||||
metadataMap,
|
||||
}: {
|
||||
attributeName: string;
|
||||
inspectableObject: InspectableObject;
|
||||
metadataMap: MetadataMap;
|
||||
}) {
|
||||
return (
|
||||
<Layout.Container gap="small" padv="small">
|
||||
<Divider style={{margin: 0}} />
|
||||
<Typography.Text>{attributeName}</Typography.Text>
|
||||
{Object.entries(inspectableObject.fields).map(([key, value]) => {
|
||||
const metadataId: number = Number(key);
|
||||
const attributeMetadata = metadataMap.get(metadataId);
|
||||
if (attributeMetadata == null) {
|
||||
return null;
|
||||
}
|
||||
const attributeName =
|
||||
upperFirst(attributeMetadata?.name) ?? String(metadataId);
|
||||
|
||||
return (
|
||||
<NamedAttribute
|
||||
key={key}
|
||||
name={attributeName}
|
||||
value={value}
|
||||
attributeMetadata={attributeMetadata}
|
||||
metadataMap={metadataMap}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Layout.Container>
|
||||
);
|
||||
}
|
||||
|
||||
function NamedAttribute({
|
||||
key,
|
||||
name,
|
||||
value,
|
||||
metadataMap,
|
||||
attributeMetadata,
|
||||
}: {
|
||||
name: string;
|
||||
value: Inspectable;
|
||||
attributeMetadata: Metadata;
|
||||
metadataMap: MetadataMap;
|
||||
key: string;
|
||||
}) {
|
||||
return (
|
||||
<Layout.Horizontal key={key} gap="small">
|
||||
<Typography.Text
|
||||
style={{
|
||||
marginTop: 3, //to center with top input when multiline
|
||||
flex: '0 0 30%', //take 30% of the width
|
||||
color: theme.textColorSecondary,
|
||||
opacity: 0.7,
|
||||
fontWeight: 50,
|
||||
}}>
|
||||
{name}
|
||||
</Typography.Text>
|
||||
|
||||
<Layout.Container style={{flex: '1 1 auto'}}>
|
||||
<AttributeValue
|
||||
name={name}
|
||||
attributeMetadata={attributeMetadata}
|
||||
metadataMap={metadataMap}
|
||||
inspectable={value}
|
||||
level={1}
|
||||
/>
|
||||
</Layout.Container>
|
||||
</Layout.Horizontal>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* disables hover and focsued states
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user