split metadata page into separate tabs

This commit is contained in:
Victor Oliva
2024-11-08 06:37:09 +03:00
parent 9b291e0899
commit 041e5bb6d5
6 changed files with 97 additions and 74 deletions

View File

@@ -25,6 +25,7 @@ export const CopyText: React.FC<{
return (
<button
aria-label={binary ? "copy binary" : "copy"}
disabled={disabled || copied}
className={twMerge(className, disabled ? "opacity-50" : "")}
onClick={copy}

View File

@@ -9,6 +9,7 @@ import {
useState,
} from "react"
import { Link } from "react-router-dom"
import { twMerge } from "tailwind-merge"
export const Lookup: FC = () => {
const [id, setId] = useState(0)
@@ -25,7 +26,7 @@ export const Lookup: FC = () => {
type="number"
/>
</label>
<div className="border-t max-h-[75vh] overflow-auto">
<div className="border-t">
<LookupNode id={id} />
</div>
</div>
@@ -71,7 +72,12 @@ export const LookupLink: FC<{ id: number }> = ({ id }) => {
const [expanded, setExpanded] = useState(false)
return (
<div className="border rounded p-2">
<div
className={twMerge(
"border rounded p-2",
expanded && "bg-slate-500 bg-opacity-10",
)}
>
<button
onClick={() => setExpanded((e) => !e)}
className="flex items-center gap-1"

View File

@@ -5,15 +5,14 @@ import { JsonDisplay } from "@/components/JsonDisplay"
import { LoadingMetadata } from "@/components/Loading"
import { withSubscribe } from "@/components/withSuspense"
import { getTypeComplexity } from "@/utils/shape"
import { V14, V15 } from "@polkadot-api/substrate-bindings"
import { useStateObservable } from "@react-rxjs/core"
import { FC, useState } from "react"
import { useState } from "react"
import { Route, Routes, useParams } from "react-router-dom"
import { Extrinsic } from "./Extrinsic"
import { Lookup, LookupContext } from "./Lookup"
import { Pallets } from "./Pallets"
import { RuntimeApis } from "./RuntimeApis"
import { V15Fields } from "./V15Fields"
import { Custom, OuterEnums } from "./V15Fields"
export const Metadata = withSubscribe(
() => (
@@ -28,43 +27,66 @@ export const Metadata = withSubscribe(
)
const MetadataExplorer = () => {
const [mode, setMode] = useState<"json" | "explorer">("explorer")
const [mode, setMode] = useState<string>("pallets")
const metadata = useStateObservable(metadata$)
const tabs = [
{
id: "pallets",
label: "Pallets",
element: <Pallets pallets={metadata.pallets} />,
},
{
id: "apis",
label: "Runtime APIs",
element: <RuntimeApis apis={metadata.apis} />,
},
{
id: "extrinsic",
label: "Extrinsic",
element: <Extrinsic extrinsic={metadata.extrinsic} />,
},
{
id: "lookup",
label: "Lookup",
element: <Lookup />,
},
...("outerEnums" in metadata
? [
{
id: "outerEnums",
label: "Outer Enums",
element: <OuterEnums metadata={metadata} />,
},
{
id: "custom",
label: "Custom",
element: <Custom metadata={metadata} />,
disabled: metadata.custom.length === 0,
},
]
: []),
{
id: "json",
label: "JSON",
element: <JsonDisplay src={metadata} />,
},
].filter((v) => !v.disabled)
return (
<div className="p-4 pb-0 flex flex-col overflow-auto items-start gap-2">
<ButtonGroup
value={mode}
onValueChange={setMode as any}
items={[
{
value: "explorer",
content: "Explorer",
},
{
value: "json",
content: "JSON",
},
]}
items={tabs.map((tab) => ({
value: tab.id,
content: tab.label,
}))}
/>
{mode === "json" ? (
<JsonDisplay src={metadata} />
) : (
<DecodedExplorer value={metadata} />
)}
</div>
)
}
const DecodedExplorer: FC<{ value: V14 | V15 }> = ({ value }) => {
return (
<div className="w-full flex flex-col gap-6">
<LookupContext.Provider value={value.lookup}>
<Lookup />
<Pallets pallets={value.pallets} />
<RuntimeApis apis={value.apis} />
<Extrinsic extrinsic={value.extrinsic} />
{"outerEnums" in value && <V15Fields metadata={value} />}
<LookupContext.Provider value={metadata.lookup}>
<div className="w-full flex flex-col">
{tabs.find((t) => t.id === mode)?.element}
</div>
</LookupContext.Provider>
</div>
)

View File

@@ -10,7 +10,6 @@ export const Pallets: FC<{ pallets: Array<Pallet> }> = ({ pallets }) => {
return (
<div className="border rounded p-2 flex flex-col gap-2">
<h3 className="font-bold text-xl">Pallets</h3>
<label className="self-start">
Pallet:{" "}
<SearchableSelect

View File

@@ -1,43 +1,38 @@
import { CopyText } from "@/components/Copy"
import { V15 } from "@polkadot-api/substrate-bindings"
import { FC } from "react"
import { LookupLink } from "./Lookup"
import { CopyText } from "@/components/Copy"
export const V15Fields: FC<{ metadata: V15 }> = ({ metadata }) => {
return (
<>
<div className="border rounded p-2 flex flex-col gap-2">
<h3 className="font-bold text-xl">Outer Enums</h3>
<div>
<h4>Call</h4>
<LookupLink id={metadata.outerEnums.call} />
export const OuterEnums: FC<{ metadata: V15 }> = ({ metadata }) => (
<div className="border rounded p-2 flex flex-col gap-2">
<div>
<h4>Call</h4>
<LookupLink id={metadata.outerEnums.call} />
</div>
<div>
<h4>Event</h4>
<LookupLink id={metadata.outerEnums.event} />
</div>
<div>
<h4>Error</h4>
<LookupLink id={metadata.outerEnums.error} />
</div>
</div>
)
export const Custom: FC<{ metadata: V15 }> = ({ metadata }) => (
<div className="border rounded p-2 flex flex-col gap-2">
{Object.entries(
metadata.custom.map(([key, { type, value }]) => (
<div key={key}>
<h4>{key}</h4>
<LookupLink id={type} />
<div className="whitespace-nowrap overflow-hidden text-ellipsis">
<CopyText text={value} binary className="mr-2" />
{value}
</div>
</div>
<div>
<h4>Event</h4>
<LookupLink id={metadata.outerEnums.event} />
</div>
<div>
<h4>Error</h4>
<LookupLink id={metadata.outerEnums.error} />
</div>
</div>
{metadata.custom.length > 0 && (
<div className="border rounded p-2 flex flex-col gap-2">
<h3 className="font-bold text-xl">Custom</h3>
{Object.entries(
metadata.custom.map(([key, { type, value }]) => (
<div key={key}>
<h4>{key}</h4>
<LookupLink id={type} />
<div className="whitespace-nowrap overflow-hidden text-ellipsis">
<CopyText text={value} binary className="mr-2" />
{value}
</div>
</div>
)),
)}
</div>
)}
</>
)
}
)),
)}
</div>
)

View File

@@ -311,7 +311,7 @@ const KeyDisplay: FC = () => {
>
{key ?? "Fill in all the storage keys to calculate the encoded key"}
</div>
<CopyText text={key ?? ""} disabled={key === null} />
<CopyText text={key ?? ""} disabled={key === null} binary />
{keys.length === keysEnabled && (
<BinaryEditButton
initialValue={key ? Binary.fromHex(key).asBytes() : undefined}