From d64d214191063d7a6a9bcdb008b4a916c96f0f88 Mon Sep 17 00:00:00 2001 From: Victor Oliva Date: Thu, 24 Oct 2024 14:48:29 +0200 Subject: [PATCH] add key editing --- .../EditCodec/Tree/codec-components.tsx | 2 +- src/codec-components/common/SubtreeFocus.ts | 9 +- src/pages/Storage/StorageQuery.tsx | 148 ++++++++++++++++-- 3 files changed, 142 insertions(+), 17 deletions(-) diff --git a/src/codec-components/EditCodec/Tree/codec-components.tsx b/src/codec-components/EditCodec/Tree/codec-components.tsx index b5298b1..687fab9 100644 --- a/src/codec-components/EditCodec/Tree/codec-components.tsx +++ b/src/codec-components/EditCodec/Tree/codec-components.tsx @@ -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 diff --git a/src/codec-components/common/SubtreeFocus.ts b/src/codec-components/common/SubtreeFocus.ts index 57848d9..86748d9 100644 --- a/src/codec-components/common/SubtreeFocus.ts +++ b/src/codec-components/common/SubtreeFocus.ts @@ -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[]) => { diff --git a/src/pages/Storage/StorageQuery.tsx b/src/pages/Storage/StorageQuery.tsx index 01791eb..99ddb50 100644 --- a/src/pages/Storage/StorageQuery.tsx +++ b/src/pages/Storage/StorageQuery.tsx @@ -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 ( - <> +
Query - +
) } @@ -91,20 +99,130 @@ const StorageKeysInput: FC = () => { isToggled={keysEnabled > idx} toggle={() => toggleKey(idx)} /> - + ))} ) } -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 ( -
- Key type={type} enabled={String(!disabled)} +
+
+
{getTypeName()}
+ setBinaryOpen(true)} + /> +
+ + setKeyValue({ idx, value: value.empty ? NOTIN : value.decoded }) + } + /> + { + setKeyValue({ idx, value }) + return true + }, + decode: codec.dec, + type: "complete", + }} + open={binaryOpen} + path="" + onClose={() => setBinaryOpen(false)} + />
) }