add pallets inspector

This commit is contained in:
Victor Oliva
2024-11-03 13:57:53 +01:00
parent 98dba2d33f
commit 03b9cd2eff
4 changed files with 176 additions and 10 deletions
+4 -6
View File
@@ -10,7 +10,7 @@ import {
} from "react"
import { Link } from "react-router-dom"
export const Lookup: FC<{ lookup: V14Lookup }> = ({ lookup }) => {
export const Lookup: FC = () => {
const [id, setId] = useState(0)
return (
@@ -26,9 +26,7 @@ export const Lookup: FC<{ lookup: V14Lookup }> = ({ lookup }) => {
/>
</label>
<div className="border-t max-h-[75vh] overflow-auto">
<LookupContext.Provider value={lookup}>
<LookupNode id={id} />
</LookupContext.Provider>
<LookupNode id={id} />
</div>
</div>
)
@@ -42,7 +40,7 @@ type NodeProps<T extends V14Def["tag"]> = {
value: V14SpecificDef<T>
}
const LookupContext = createContext<V14Lookup>(null as any)
export const LookupContext = createContext<V14Lookup>(null as any)
const LookupNode: FC<{ id: number }> = ({ id }) => {
const lookup = useContext(LookupContext)
@@ -69,7 +67,7 @@ const LookupNode: FC<{ id: number }> = ({ id }) => {
}
}
const LookupLink: FC<{ id: number }> = ({ id }) => {
export const LookupLink: FC<{ id: number }> = ({ id }) => {
const [expanded, setExpanded] = useState(false)
return (
+7 -3
View File
@@ -9,7 +9,8 @@ import { V14, V15 } from "@polkadot-api/substrate-bindings"
import { useStateObservable } from "@react-rxjs/core"
import { FC, useState } from "react"
import { Route, Routes, useParams } from "react-router-dom"
import { Lookup } from "./Lookup"
import { Lookup, LookupContext } from "./Lookup"
import { Pallets } from "./Pallets"
export const Metadata = withSubscribe(
() => (
@@ -54,8 +55,11 @@ const MetadataExplorer = () => {
const DecodedExplorer: FC<{ value: V14 | V15 }> = ({ value }) => {
return (
<div className="w-full">
<Lookup lookup={value.lookup} />
<div className="w-full flex flex-col gap-2">
<LookupContext.Provider value={value.lookup}>
<Lookup />
<Pallets pallets={value.pallets} />
</LookupContext.Provider>
</div>
)
}
+164
View File
@@ -0,0 +1,164 @@
import { SearchableSelect } from "@/components/Select"
import { V14, V15 } from "@polkadot-api/substrate-bindings"
import { FC, useEffect, useState } from "react"
import { LookupLink } from "./Lookup"
import { CopyText } from "@/components/Copy"
type Pallet = (V14 | V15)["pallets"][number]
export const Pallets: FC<{ pallets: Array<Pallet> }> = ({ pallets }) => {
const [pallet, setPallet] = useState<Pallet | null>(null)
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
value={pallet}
setValue={setPallet}
options={pallets.map((p) => ({
text: p.name,
value: p,
}))}
/>
</label>
{pallet && (
<>
<p>Index: {pallet.index}</p>
{pallet.storage && (
<div>
<h4>Storage</h4>
<PalletStorage pallet={pallet} />
</div>
)}
{pallet.constants.length && (
<div>
<h4>Constants</h4>
<PalletConstants pallet={pallet} />
</div>
)}
{pallet.calls != null && (
<div>
<h4>Calls</h4>
<LookupLink id={pallet.calls} />
</div>
)}
{pallet.events != null && (
<div>
<h4>Events</h4>
<LookupLink id={pallet.events} />
</div>
)}
{pallet.errors != null && (
<div>
<h4>Errors</h4>
<LookupLink id={pallet.errors} />
</div>
)}
</>
)}
</div>
)
}
type StorageEntry = Pallet["storage"] extends
| undefined
| { items: Array<infer R> }
? R
: never
const PalletStorage: FC<{ pallet: Pallet }> = ({ pallet }) => {
const [entry, setEntry] = useState<StorageEntry | null>(null)
useEffect(() => {
setEntry(null)
}, [pallet])
if (!pallet.storage) return null
const value =
entry &&
(entry.type.tag === "map" ? entry.type.value.value : entry.type.value)
const key = entry && (entry.type.tag === "map" ? entry.type.value.key : null)
const acceptsPartialKey =
entry?.type.tag === "map" && entry.type.value.hashers.length > 1
return (
<div className="flex flex-col p-2 gap-2">
<label className="self-start">
Entry:{" "}
<SearchableSelect
value={entry}
setValue={setEntry}
options={pallet.storage.items.map((s) => ({
text: s.name,
value: s,
}))}
/>
</label>
{entry && (
<>
{key != null && (
<div>
<h4>Key</h4>
{acceptsPartialKey && <p>Accepts partial keys</p>}
<LookupLink id={key} />
</div>
)}
<div>
<h4>Value</h4>
<LookupLink id={value!} />
</div>
<div>
<h4>Fallback</h4>
<div className="whitespace-nowrap overflow-hidden text-ellipsis">
<CopyText text={entry.fallback} binary className="mr-2" />
{entry.fallback}
</div>
</div>
</>
)}
</div>
)
}
type ConstantEntry = Pallet["constants"] extends Array<infer R> ? R : never
const PalletConstants: FC<{ pallet: Pallet }> = ({ pallet }) => {
const [entry, setEntry] = useState<ConstantEntry | null>(null)
useEffect(() => {
setEntry(null)
}, [pallet])
if (!pallet.constants.length) return null
return (
<div className="flex flex-col p-2 gap-2">
<label className="self-start">
Entry:{" "}
<SearchableSelect
value={entry}
setValue={setEntry}
options={pallet.constants.map((c) => ({
text: c.name,
value: c,
}))}
/>
</label>
{entry && (
<>
<div>
<h4>Type</h4>
<LookupLink id={entry.type} />
</div>
<div>
<h4>Value</h4>
<div className="whitespace-nowrap overflow-hidden text-ellipsis">
<CopyText text={entry.value} binary className="mr-2" />
{entry.value}
</div>
</div>
</>
)}
</div>
)
}