import { ArrowLeftOutlined, ArrowRightOutlined, CloseOutlined, SearchOutlined, } from '@ant-design/icons'; import { Button, Col, Layout, Radio, Row, Space, Tag, Tooltip } from 'antd'; import { DataInspector, DetailSidebar, Spinner } from 'flipper-plugin'; import React, { useEffect, useState } from 'react'; import { DeserializedRealmObject, PlainRealmObject, RealmObjectReference } from '../CommonTypes'; import { BoldSpan } from './SchemaSelect'; export type InspectionDataType = { data: PlainRealmObject | RealmObjectReference; // Whether the data specified is a reference to another object that needs to be lazy loaded. isReference: boolean; view: 'object' | 'schema' | 'property'; }; type RealmDataInspectorProps = { schemas: Realm.CanonicalObjectSchema[]; inspectionData: InspectionDataType | undefined; setInspectionData: React.Dispatch< React.SetStateAction >; showSidebar: boolean; setShowSidebar: (value: boolean) => void; goBackStack: Array; setGoBackStack: React.Dispatch>; goForwardStack: Array; setGoForwardStack: React.Dispatch>; setNewInspectionData: (newInspectionData: InspectionDataType) => void; getObject: (object: RealmObjectReference) => Promise; }; // Helper function to traverse through a Realm object given a path // Can return any type that a Realm Object could contain. function traverseThroughObject(object: any, path: string[]) { let traversedObject: unknown = object; path.forEach( //@ts-expect-error We expect traversal path to be correct. (key) => (traversedObject = traversedObject[key]) ); return traversedObject as Type } export const RealmDataInspector = ({ schemas, inspectionData, setInspectionData, showSidebar, setShowSidebar, goBackStack, setGoBackStack, goForwardStack, setGoForwardStack, setNewInspectionData, getObject, }: RealmDataInspectorProps) => { if (!showSidebar || inspectionData === undefined) return null; /** Utilities to trigger a brief flickering when the InspectionData is updated. * In some cases this makes it easier to see when the data changed. */ const [flickering, setFlickering] = useState(false); const doFlicker = () => { if(inspectionData.isReference && inspectionData.data != null) { getObject(inspectionData.data as RealmObjectReference).then((loadedObject) => { if(loadedObject === null) { // TODO: Better handling. return; } setInspectionData({ data: { [inspectionData.data.objectType as string]: loadedObject.realmObject, }, view: inspectionData.view, isReference: false, }) }) return; } else if(!inspectionData.isReference) { // Do not flicker when referenced data is being fetched. setFlickering(true); setTimeout(() => setFlickering(false), 5); } }; useEffect(doFlicker, [inspectionData]); const flickerStyle = { backgroundColor: flickering ? '#6932c9' : 'transparent', }; return ( {'Inspector - Realm ' + inspectionData.view}{' '} setShowSidebar(false)}> {' '} {/* */} {inspectionData.isReference ? : /* @ts-expect-error See https://github.com/facebook/flipper/issues/3996 */ { const nameAsIndex = Number(name); // Check whether we are rendering a list item, i.e. object.listName[0] const isCollectionItem = Number.isInteger(nameAsIndex) && path.length > 1 // TODO: Unsure if this is good enough to handle collection items. const fieldName:string = isCollectionItem ? path.at(-2) as string : name; // Finding out if the currently rendered value has a schema belonging to it and assigning it to linkedSchema let ownSchema: Realm.CanonicalObjectSchema | undefined; let linkedSchema: Realm.CanonicalObjectSchema | undefined = schemas.find( (schema) => schema.properties[fieldName] ); if(linkedSchema) { ownSchema = schemas.find( ( innerSchema // And there exists some schema that fits the objectType of that property ) => linkedSchema && linkedSchema.properties[fieldName].objectType === innerSchema.name ) } // If there is a linked existing, non-collection, non-embedded schema on the property then this is a linked object const isCollection = !isCollectionItem && linkedSchema?.properties[fieldName].type == "list" || linkedSchema?.properties[fieldName].type == "set" const isLinkedObject = linkedSchema && !isCollection && ownSchema && !ownSchema.embedded // If this is a linked object field and there is a value assigned to it, add a clickable reference. if (isLinkedObject && traverseThroughObject(inspectionData.data, path)) { return ( <> {name + ' '} Ref