add key editing

This commit is contained in:
Victor Oliva
2024-10-24 14:48:29 +02:00
parent 2753755e44
commit d64d214191
3 changed files with 142 additions and 17 deletions

View File

@@ -1,4 +1,5 @@
import { BinaryEdit, Focus, TypeIcon, TypeIcons } from "@/components/Icons"
import { BinaryEditModal } from "@/pages/Extrinsics/BinaryEditModal"
import {
EditAccountId,
EditBigNumber,
@@ -28,7 +29,6 @@ import {
useState,
} from "react"
import { twMerge } from "tailwind-merge"
import { BinaryEditModal } from "../../BinaryEditModal"
import { isActive$, setHovered } from "../../common/paths.state"
export const CVoid: EditVoid = () => null

View File

@@ -1,4 +1,5 @@
import { createContext, useContext } from "react"
import { noop } from "rxjs"
const SubtreeFocusContext = createContext<{
callback: (path: string[]) => void
@@ -9,7 +10,13 @@ export const SubtreeFocus = SubtreeFocusContext.Provider
export const useSubtreeFocus = () => {
const ctx = useContext(SubtreeFocusContext)
if (!ctx) throw new Error("SubtreeFocus provider not found")
if (!ctx) {
return {
setFocus: noop,
getNextPath: () => null,
}
}
return {
setFocus: ctx.callback,
getNextPath: (path: string[]) => {

View File

@@ -1,25 +1,33 @@
import SliderToggle from "@/components/Toggle"
import { state, useStateObservable, withDefault } from "@react-rxjs/core"
import { combineKeys, createSignal } from "@react-rxjs/utils"
import { FC } from "react"
import { combineLatest, filter, map, scan, startWith, switchMap } from "rxjs"
import { selectedEntry$ } from "./storage.state"
import { NOTIN } from "@codec-components"
import { ActionButton } from "@/components/ActionButton"
import { lookup$ } from "@/chain.state"
import { getDynamicBuilder } from "@polkadot-api/metadata-builders"
import { EditCodec } from "@/codec-components/EditCodec"
import { ActionButton } from "@/components/ActionButton"
import { CopyText } from "@/components/Copy"
import { BinaryEdit } from "@/components/Icons"
import SliderToggle from "@/components/Toggle"
import {
CodecComponentType,
CodecComponentValue,
NOTIN,
} from "@codec-components"
import { getDynamicBuilder } from "@polkadot-api/metadata-builders"
import { state, useStateObservable, withDefault } from "@react-rxjs/core"
import { createSignal } from "@react-rxjs/utils"
import { Binary } from "polkadot-api"
import { FC, useState } from "react"
import { combineLatest, filter, map, scan, startWith, switchMap } from "rxjs"
import { twMerge } from "tailwind-merge"
import { BinaryEditModal } from "../Extrinsics/BinaryEditModal"
import { selectedEntry$ } from "./storage.state"
export const StorageQuery: FC = () => {
const isReady = useStateObservable(isReady$)
return (
<>
<div className="p-2 flex flex-col gap-4 items-start w-full">
<StorageKeysInput />
<KeyDisplay />
<ActionButton disabled={!isReady}>Query</ActionButton>
</>
</div>
)
}
@@ -91,20 +99,130 @@ const StorageKeysInput: FC = () => {
isToggled={keysEnabled > idx}
toggle={() => toggleKey(idx)}
/>
<StorageKeyInput type={type} disabled={keysEnabled <= idx} />
<StorageKeyInput
idx={idx}
type={type}
disabled={keysEnabled <= idx}
/>
</li>
))}
</ol>
)
}
const StorageKeyInput: FC<{ type: number; disabled: boolean }> = ({
const lookupState$ = state(lookup$, null)
const keyInputValue$ = state(
(idx: number) =>
keyValues$.pipe(
map(
(v, i): CodecComponentValue =>
i === 0
? {
type: CodecComponentType.Initial,
}
: {
type: CodecComponentType.Updated,
value:
v[idx] === NOTIN
? {
empty: true,
}
: {
empty: false,
decoded: v[idx],
},
},
),
),
{
type: CodecComponentType.Initial,
} satisfies CodecComponentValue,
)
const StorageKeyInput: FC<{ idx: number; type: number; disabled: boolean }> = ({
idx,
type,
disabled,
}) => {
const [binaryOpen, setBinaryOpen] = useState(false)
const lookup = useStateObservable(lookupState$)
const value = useStateObservable(keyInputValue$(idx))
if (!lookup) return null
const codec = getDynamicBuilder(lookup).buildDefinition(type)
const binaryValue =
(value.type === CodecComponentType.Initial
? value.value
: value.value.empty
? null
: (value.value.encoded ?? codec.enc(value.value.decoded))) ?? null
const getTypeName = () => {
const lookupEntry = lookup(type)
switch (lookupEntry.type) {
case "primitive":
return lookupEntry.value
case "compact":
return (lookupEntry as any).size ?? "u128"
case "enum":
return "Enum"
case "array":
if (
lookupEntry.value.type === "primitive" &&
lookupEntry.value.value === "u8"
) {
return "Binary"
}
return null
case "bitSequence":
case "AccountId20":
case "AccountId32":
return lookupEntry.type
default:
return null
}
}
return (
<div className="border-l p-2">
Key type={type} enabled={String(!disabled)}
<div
className={twMerge(
"border-l px-2",
disabled && "pointer-events-none opacity-50",
)}
>
<div className="flex justify-between">
<div>{getTypeName()}</div>
<BinaryEdit
size={18}
className={twMerge("cursor-pointer hover:text-polkadot-300")}
onClick={() => setBinaryOpen(true)}
/>
</div>
<EditCodec
metadata={lookup.metadata}
codecType={type}
value={value}
onUpdate={(value) =>
setKeyValue({ idx, value: value.empty ? NOTIN : value.decoded })
}
/>
<BinaryEditModal
status={{
encodedValue:
typeof binaryValue === "string"
? Binary.fromHex(binaryValue).asBytes()
: (binaryValue ?? undefined),
onValueChanged: (value) => {
setKeyValue({ idx, value })
return true
},
decode: codec.dec,
type: "complete",
}}
open={binaryOpen}
path=""
onClose={() => setBinaryOpen(false)}
/>
</div>
)
}