From a5397242abd89b28b4388476dfb3cbf533490c13 Mon Sep 17 00:00:00 2001 From: Joe Bottigliero <694253+jbottigliero@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:31:56 -0500 Subject: [PATCH] feat: adds 'table' field type and scaffold for JSONTree component --- src/components/Field.tsx | 9 ++- src/components/Fields/FallbackField.tsx | 18 ++--- src/components/Fields/TableField.tsx | 50 +++++++++++++ src/components/JSONTree.tsx | 10 +++ src/components/Result.tsx | 5 +- src/components/ResultListing.tsx | 97 +++++++++++++------------ 6 files changed, 128 insertions(+), 61 deletions(-) create mode 100644 src/components/Fields/TableField.tsx create mode 100644 src/components/JSONTree.tsx diff --git a/src/components/Field.tsx b/src/components/Field.tsx index 23feb5e..006a8ad 100644 --- a/src/components/Field.tsx +++ b/src/components/Field.tsx @@ -5,6 +5,7 @@ import jsonata from "jsonata"; import RgbaField from "./Fields/RgbaField"; import ImageField from "./Fields/ImageField"; +import TableField from "./Fields/TableField"; import FallbackField from "./Fields/FallbackField"; import type { GMetaResult } from "../globus/search"; @@ -69,7 +70,13 @@ export const FieldValue = ({ if (type === "image") { return ; } - return ; // fallback + if (type === "table") { + return ; + } + /** + * If no `type` is provided, or the `type` is not recognized, use the fallback field. + */ + return ; }; export const Field = ({ diff --git a/src/components/Fields/FallbackField.tsx b/src/components/Fields/FallbackField.tsx index 508eb38..58dc403 100644 --- a/src/components/Fields/FallbackField.tsx +++ b/src/components/Fields/FallbackField.tsx @@ -1,22 +1,22 @@ import React from "react"; -import { Box, Code, Text } from "@chakra-ui/react"; +import { Box, Text } from "@chakra-ui/react"; +import { JSONTree } from "../JSONTree"; type Value = unknown; -// function isValidValue(value: unknown): value is Value { -// return true; -// } - /** * A fallback field that will introspect the value and render it as best as it can. */ export default function FallbackField({ value }: { value: Value }) { + if (value === null || value === undefined) { + return ; + } if ( typeof value === "string" || typeof value === "number" || typeof value === "boolean" ) { - return {value}; + return {value}; } if (Array.isArray(value)) { return value.map((v, i) => ( @@ -25,9 +25,5 @@ export default function FallbackField({ value }: { value: Value }) { )); } - return ( - - {JSON.stringify(value, null, 2)} - - ); + return ; } diff --git a/src/components/Fields/TableField.tsx b/src/components/Fields/TableField.tsx new file mode 100644 index 0000000..7364030 --- /dev/null +++ b/src/components/Fields/TableField.tsx @@ -0,0 +1,50 @@ +import React from "react"; +import { + Table, + Tbody, + Tr, + Thead, + Th, + Td, + TableContainer, +} from "@chakra-ui/react"; +import { FieldValue } from "../Field"; + +type Value = Record; + +function isValidValue(value: unknown): value is Value { + return typeof value === "object" && value !== null; +} + +/** + * Render a field as an RGBA color. + */ +export default function TableField({ value }: { value: unknown }) { + if (!isValidValue(value)) { + return; + } + return ( + + + + + + + + + + {Object.entries(value).map(([key, value]) => { + return ( + + + + + ); + })} + +
PropertyValue
{key} + +
+
+ ); +} diff --git a/src/components/JSONTree.tsx b/src/components/JSONTree.tsx new file mode 100644 index 0000000..763806e --- /dev/null +++ b/src/components/JSONTree.tsx @@ -0,0 +1,10 @@ +import React from "react"; + +import { Code } from "@chakra-ui/react"; + +/** + * @todo + */ +export const JSONTree = ({ data }: { data: unknown }) => { + return {JSON.stringify(data, null, 2)}; +}; diff --git a/src/components/Result.tsx b/src/components/Result.tsx index 4069deb..f452bc5 100644 --- a/src/components/Result.tsx +++ b/src/components/Result.tsx @@ -5,7 +5,6 @@ import { Heading, Text, Box, - Code, Flex, Button, Drawer, @@ -22,8 +21,8 @@ import { import { getAttribute, getAttributeFrom } from "../../static"; import { Error } from "./Error"; import { isGError, type GError, type GMetaResult } from "@/globus/search"; - import { Field, type FieldDefinition } from "./Field"; +import { JSONTree } from "./JSONTree"; export type ResultComponentOptions = { /** @@ -104,7 +103,7 @@ export default function Result({ result }: { result?: GMetaResult | GError }) { - {JSON.stringify(result, null, 2)} + diff --git a/src/components/ResultListing.tsx b/src/components/ResultListing.tsx index 00d5755..cf2223b 100644 --- a/src/components/ResultListing.tsx +++ b/src/components/ResultListing.tsx @@ -13,6 +13,7 @@ import { Tr, Td, HStack, + Link, } from "@chakra-ui/react"; import { getAttributeFrom, getAttribute } from "../../static"; @@ -125,60 +126,64 @@ export default function ResultListing({ gmeta }: { gmeta: GMetaResult }) { src: string; alt?: string; }>(); - getAttributeFrom(gmeta, "components.ResultListing.heading").then( - (result) => { - setHeading(result); - }, - ); - getAttributeFrom(gmeta, "components.ResultListing.summary").then( - (result) => { - setSummary(result); - }, - ); + useEffect(() => { + async function resolveAttributes() { + const heading = await getAttributeFrom( + gmeta, + "components.ResultListing.heading", + ); + const summary = await getAttributeFrom( + gmeta, + "components.ResultListing.summary", + ); + let image = await getAttributeFrom< + | string + | { + src: string; + alt?: string; + } + >(gmeta, "components.ResultListing.image"); - getAttributeFrom< - | string - | { - src: string; - alt?: string; + setHeading(heading); + setSummary(summary); + + if (typeof image === "string") { + image = { src: image }; } - >(gmeta, "components.ResultListing.image").then((result) => { - let image = result; - if (typeof image === "string") { - image = { src: image }; + setImage(image); } - setImage(image); - }); + resolveAttributes(); + }, [gmeta]); const fields = getAttribute("components.ResultListing.fields"); return ( - - - - + + + + {heading} - - - - - {image && ( - - )} - {summary && {summary}} - - - - - + + + + + + {image && ( + + )} + {summary && {summary}} + + + + ); }