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
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Input, Typography} from 'antd';
|
import {Divider, Input, Typography} from 'antd';
|
||||||
import {Panel, theme, Layout} from 'flipper-plugin';
|
import {Panel, theme, Layout} from 'flipper-plugin';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
@@ -19,7 +19,8 @@ import {
|
|||||||
import {MetadataMap} from '../../DesktopTypes';
|
import {MetadataMap} from '../../DesktopTypes';
|
||||||
import {NoData} from '../sidebar/inspector/NoData';
|
import {NoData} from '../sidebar/inspector/NoData';
|
||||||
import {css, cx} from '@emotion/css';
|
import {css, cx} from '@emotion/css';
|
||||||
import {upperFirst} from 'lodash';
|
import {upperFirst, sortBy} from 'lodash';
|
||||||
|
import {any} from 'lodash/fp';
|
||||||
|
|
||||||
export function AttributesInspector({
|
export function AttributesInspector({
|
||||||
node,
|
node,
|
||||||
@@ -64,40 +65,63 @@ function AttributeSection(
|
|||||||
name: string,
|
name: string,
|
||||||
inspectable: InspectableObject,
|
inspectable: InspectableObject,
|
||||||
) {
|
) {
|
||||||
const children = Object.keys(inspectable.fields)
|
const attributesOrSubSubsections = Object.entries(inspectable.fields).map(
|
||||||
.map((key) => {
|
([fieldKey, attributeValue]) => {
|
||||||
const metadataId: number = Number(key);
|
const metadataId: number = Number(fieldKey);
|
||||||
const attributeMetadata = metadataMap.get(metadataId);
|
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) {
|
if (attributeMetadata == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const attributeValue = inspectable.fields[metadataId];
|
|
||||||
|
|
||||||
const attributeName =
|
if (isSubSection) {
|
||||||
upperFirst(attributeMetadata?.name) ?? String(metadataId);
|
if (attributeValue.type === 'object') {
|
||||||
return (
|
return (
|
||||||
<Layout.Horizontal key={key} gap="small">
|
<SubSection
|
||||||
<Typography.Text
|
attributeName={attributeName}
|
||||||
style={{
|
inspectableObject={attributeValue}
|
||||||
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}
|
|
||||||
metadataMap={metadataMap}
|
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);
|
.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
|
* disables hover and focsued states
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user