141 lines
3.9 KiB
TypeScript
141 lines
3.9 KiB
TypeScript
import { ButtonGroup } from "@/components/ButtonGroup"
|
|
import { DocsRenderer } from "@/components/DocsRenderer"
|
|
import { Chopsticks } from "@/components/Icons"
|
|
import { LoadingMetadata } from "@/components/Loading"
|
|
import { SearchableSelect } from "@/components/Select"
|
|
import { withSubscribe } from "@/components/withSuspense"
|
|
import { canSetStorage$ } from "@/state/chains/chain.state"
|
|
import { state, useStateObservable } from "@react-rxjs/core"
|
|
import { FC, useState } from "react"
|
|
import { map } from "rxjs"
|
|
import { BlockPicker, selectedBlock$ } from "./BlockPicker"
|
|
import { partialEntry$, selectedEntry$, selectEntry } from "./storage.state"
|
|
import { StorageDecode } from "./StorageDecode"
|
|
import { StorageQuery } from "./StorageQuery"
|
|
import { StorageSet } from "./StorageSet"
|
|
import { StorageSubscriptions } from "./StorageSubscriptions"
|
|
|
|
const metadataStorage$ = state(
|
|
selectedBlock$.pipe(
|
|
map(({ ctx }) => ({
|
|
lookup: ctx.lookup,
|
|
entries: Object.fromEntries(
|
|
ctx.lookup.metadata.pallets
|
|
.filter((p) => p.storage)
|
|
.map((p) => [
|
|
p.name,
|
|
Object.fromEntries(
|
|
p.storage!.items.map((item) => [item.name, item.type]),
|
|
),
|
|
]),
|
|
),
|
|
})),
|
|
),
|
|
)
|
|
|
|
export const Storage = withSubscribe(
|
|
() => {
|
|
const { entries } = useStateObservable(metadataStorage$)
|
|
const partialEntry = useStateObservable(partialEntry$)
|
|
const selectedEntry = useStateObservable(selectedEntry$)
|
|
|
|
return (
|
|
<div className="p-4 pb-0 flex flex-col gap-2 items-start">
|
|
<div className="flex items-center gap-2">
|
|
<label>
|
|
Block
|
|
<BlockPicker />
|
|
</label>
|
|
<label>
|
|
Pallet
|
|
<SearchableSelect
|
|
value={partialEntry.pallet}
|
|
setValue={(v) => selectEntry({ pallet: v })}
|
|
options={Object.keys(entries).map((e) => ({
|
|
text: e,
|
|
value: e,
|
|
}))}
|
|
/>
|
|
</label>
|
|
{partialEntry.pallet && (
|
|
<label>
|
|
Entry
|
|
<SearchableSelect
|
|
value={partialEntry.entry}
|
|
setValue={(v) => selectEntry({ entry: v })}
|
|
options={
|
|
Object.keys(entries[partialEntry.pallet]).map((s) => ({
|
|
text: s,
|
|
value: s,
|
|
})) ?? []
|
|
}
|
|
/>
|
|
</label>
|
|
)}
|
|
</div>
|
|
{selectedEntry?.docs.length ? (
|
|
<div className="w-full">
|
|
Docs
|
|
<DocsRenderer docs={selectedEntry.docs} />
|
|
</div>
|
|
) : null}
|
|
<StorageEntry />
|
|
<StorageSubscriptions />
|
|
</div>
|
|
)
|
|
},
|
|
{
|
|
fallback: <LoadingMetadata />,
|
|
},
|
|
)
|
|
|
|
const StorageEntry: FC = () => {
|
|
const selectedEntry = useStateObservable(selectedEntry$)
|
|
const canSetStorage = useStateObservable(canSetStorage$)
|
|
const [mode, setMode] = useState<"query" | "decode" | "set">("query")
|
|
|
|
if (!selectedEntry) return null
|
|
|
|
return (
|
|
<>
|
|
<ButtonGroup
|
|
value={mode}
|
|
onValueChange={setMode as any}
|
|
items={[
|
|
{
|
|
value: "query",
|
|
content: "Query",
|
|
},
|
|
{
|
|
value: "decode",
|
|
content: "Decode Value",
|
|
},
|
|
...(canSetStorage
|
|
? [
|
|
{
|
|
value: "set",
|
|
content: (
|
|
<>
|
|
Set
|
|
<Chopsticks
|
|
className="inline-block align-middle ml-2"
|
|
size={20}
|
|
/>
|
|
</>
|
|
),
|
|
},
|
|
]
|
|
: []),
|
|
]}
|
|
/>
|
|
{mode === "query" ? (
|
|
<StorageQuery />
|
|
) : mode === "decode" ? (
|
|
<StorageDecode />
|
|
) : (
|
|
<StorageSet />
|
|
)}
|
|
</>
|
|
)
|
|
}
|