/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import {Divider, Input, Typography} from 'antd';
import {Panel, theme, Layout} from 'flipper-plugin';
import React from 'react';
import {
ClientNode,
Inspectable,
InspectableObject,
Metadata,
} from '../../ClientTypes';
import {MetadataMap} from '../../DesktopTypes';
import {NoData} from '../sidebar/inspector/NoData';
import {css, cx} from '@emotion/css';
import {upperFirst, sortBy} from 'lodash';
import {any} from 'lodash/fp';
export function AttributesInspector({
node,
metadata,
}: {
node: ClientNode;
metadata: MetadataMap;
}) {
const keys = Object.keys(node.attributes);
const sections = keys
.map((key, _) => {
/**
* The node top-level attributes refer to the displayable panels.
* The panel name is obtained by querying the metadata.
* The inspectable contains the actual attributes belonging to each panel.
*/
const metadataId: number = Number(key);
const sectionMetadata = metadata.get(metadataId);
if (sectionMetadata == null) {
return null;
}
const sectionAttributes = node.attributes[
metadataId
] as InspectableObject;
return AttributeSection(
metadata,
sectionMetadata.name,
sectionAttributes,
);
})
.filter((section) => section != null);
if (sections.length === 0) {
return ;
}
return <>{sections}>;
}
function AttributeSection(
metadataMap: MetadataMap,
name: string,
inspectable: InspectableObject,
) {
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;
}
if (isSubSection) {
if (attributeValue.type === 'object') {
return (
);
}
}
return (
);
})
.filter((attr) => attr != null);
if (children.length > 0) {
return (
{...children}
);
} else {
return null;
}
}
function SubSection({
attributeName,
inspectableObject,
metadataMap,
}: {
attributeName: string;
inspectableObject: InspectableObject;
metadataMap: MetadataMap;
}) {
return (
{attributeName}
{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 (
);
})}
);
}
function NamedAttribute({
key,
name,
value,
metadataMap,
attributeMetadata,
}: {
name: string;
value: Inspectable;
attributeMetadata: Metadata;
metadataMap: MetadataMap;
key: string;
}) {
return (
{name}
);
}
/**
* disables hover and focsued states
*/
const readOnlyInput = css`
:hover {
border-color: ${theme.disabledColor} !important;
}
:focus {
border-color: ${theme.disabledColor} !important;
box-shadow: none !important;
}
box-shadow: none !important;
border-color: ${theme.disabledColor} !important;
padding: 2px 4px 2px 4px;
min-height: 20px !important; //this is for text area
`;
function StyledInput({
value,
color,
mutable,
rightAddon,
}: {
value: any;
color: string;
mutable: boolean;
rightAddon?: string;
}) {
return (
);
}
function StyledTextArea({
value,
color,
mutable,
}: {
value: any;
color: string;
mutable: boolean;
rightAddon?: string;
}) {
return (
);
}
const boolColor = '#C41D7F';
const stringColor = '#AF5800';
const enumColor = '#006D75';
const numberColor = '#003EB3';
type NumberGroupValue = {value: number; addonText: string};
function NumberGroup({values}: {values: NumberGroupValue[]}) {
return (
{values.map(({value, addonText}, idx) => (
))}
);
}
function AttributeValue({
inspectable,
}: {
attributeMetadata: Metadata;
metadataMap: MetadataMap;
name: string;
inspectable: Inspectable;
level: number;
}) {
switch (inspectable.type) {
case 'boolean':
return (
);
case 'text':
return (
);
case 'number':
return (
);
case 'enum':
return (
);
case 'size':
return (
);
case 'coordinate':
return (
);
case 'coordinate3d':
return (
);
case 'space':
return (
);
case 'bounds':
return (
);
}
return null;
}