inline non-complex parts in the ViewCodec
This commit is contained in:
@@ -1,33 +1,65 @@
|
||||
import { ExpandBtn } from "@/components/Expand"
|
||||
import { getFinalType } from "@/utils/shape"
|
||||
import { ViewStruct } from "@codec-components"
|
||||
import { Var } from "@polkadot-api/metadata-builders"
|
||||
import { useStateObservable } from "@react-rxjs/core"
|
||||
import React, { useContext, useState } from "react"
|
||||
import { twMerge as clsx, twMerge } from "tailwind-merge"
|
||||
import { Marker } from "../common/Markers"
|
||||
import { useSubtreeFocus } from "../common/SubtreeFocus"
|
||||
import {
|
||||
isActive$,
|
||||
isCollapsed$,
|
||||
setHovered,
|
||||
toggleCollapsed,
|
||||
} from "../common/paths.state"
|
||||
import { useSubtreeFocus } from "../common/SubtreeFocus"
|
||||
import { ItemMarker } from "../EditCodec/Tree/codec-components"
|
||||
import { ChildProvider, TitleContext } from "./TitleContext"
|
||||
import { CopyChildBinary, useReportBinary } from "./CopyBinary"
|
||||
import { ChildProvider, TitleContext } from "./TitleContext"
|
||||
import { isComplexNested } from "./utils"
|
||||
|
||||
const StructItem: React.FC<{
|
||||
name: string
|
||||
children: React.ReactNode
|
||||
path: string[]
|
||||
type?: string
|
||||
}> = ({ name, children, path }) => {
|
||||
field: Var
|
||||
value: unknown
|
||||
}> = ({ name, children, path, field, value }) => {
|
||||
const pathStr = path.join(".")
|
||||
const isActive = useStateObservable(isActive$(pathStr))
|
||||
const isExpanded = !useStateObservable(isCollapsed$(pathStr))
|
||||
const hasParentTitle = !!useContext(TitleContext)
|
||||
const [titleElement, setTitleElement] = useState<HTMLElement | null>(null)
|
||||
|
||||
const isComplexShape = isComplexNested(field, value)
|
||||
|
||||
const title = isComplexShape ? (
|
||||
<span
|
||||
onClick={() => toggleCollapsed(pathStr)}
|
||||
className="cursor-pointer flex select-none items-center py-1 gap-1"
|
||||
>
|
||||
{hasParentTitle && <ItemMarker />}
|
||||
<ExpandBtn expanded={isExpanded} />
|
||||
<span className="flex items-center gap-1" ref={setTitleElement}>
|
||||
<span className="opacity-75">{name}</span>
|
||||
</span>
|
||||
<div className="flex-1 text-right">
|
||||
<CopyChildBinary visible={isActive} />
|
||||
</div>
|
||||
</span>
|
||||
) : (
|
||||
<span className="flex items-center py-1 gap-1">
|
||||
{hasParentTitle && <ItemMarker />}
|
||||
<span className="select-none flex items-center gap-1">
|
||||
<span className="opacity-75">{name}</span>
|
||||
<span ref={setTitleElement} />
|
||||
</span>
|
||||
<div>{children}</div>
|
||||
<div className="flex-1 text-right">
|
||||
<CopyChildBinary visible={isActive} />
|
||||
</div>
|
||||
</span>
|
||||
)
|
||||
|
||||
return (
|
||||
<li
|
||||
className={twMerge(
|
||||
@@ -39,27 +71,17 @@ const StructItem: React.FC<{
|
||||
>
|
||||
<ChildProvider titleElement={titleElement}>
|
||||
<Marker id={path} />
|
||||
<span
|
||||
onClick={() => toggleCollapsed(pathStr)}
|
||||
className="cursor-pointer flex select-none items-center py-1 gap-1"
|
||||
>
|
||||
{hasParentTitle && <ItemMarker />}
|
||||
<ExpandBtn expanded={isExpanded} />
|
||||
<span className="flex items-center gap-1" ref={setTitleElement}>
|
||||
<span className="opacity-75">{name}</span>
|
||||
</span>
|
||||
<div className="flex-1 text-right">
|
||||
<CopyChildBinary visible={isActive} />
|
||||
{title}
|
||||
{isComplexShape && (
|
||||
<div
|
||||
className={clsx(
|
||||
"flex flex-row pl-2 pb-2",
|
||||
isExpanded ? "" : "hidden",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</span>
|
||||
<div
|
||||
className={clsx(
|
||||
"flex flex-row pl-4 pb-2",
|
||||
isExpanded ? "" : "hidden",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</ChildProvider>
|
||||
</li>
|
||||
)
|
||||
@@ -70,6 +92,7 @@ export const CStruct: ViewStruct = ({
|
||||
path,
|
||||
shape,
|
||||
encodedValue,
|
||||
value,
|
||||
}) => {
|
||||
useReportBinary(encodedValue)
|
||||
const focus = useSubtreeFocus()
|
||||
@@ -92,7 +115,8 @@ export const CStruct: ViewStruct = ({
|
||||
name={name}
|
||||
key={name}
|
||||
path={[...path, name]}
|
||||
type={getFinalType(shape, name)}
|
||||
field={shape.value[name]}
|
||||
value={value[name]}
|
||||
>
|
||||
{jsx}
|
||||
</StructItem>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { getEnumInnerVar, isComplex } from "@/utils/shape"
|
||||
import { Var } from "@polkadot-api/metadata-builders"
|
||||
|
||||
export const isComplexNested = (field: Var, value: any): boolean => {
|
||||
if (!isComplex(field.type)) return false
|
||||
|
||||
if (field.type === "enum")
|
||||
return isComplexNested(getEnumInnerVar(field, value.type), value.value)
|
||||
|
||||
if (field.type === "option")
|
||||
return value == null ? false : isComplexNested(field.value, value)
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -30,8 +30,8 @@ const metadataStorage$ = state(
|
||||
|
||||
export const Storage = withSubscribe(() => {
|
||||
const { lookup, entries } = useStateObservable(metadataStorage$)
|
||||
const [pallet, setPallet] = useState<string | null>("Staking")
|
||||
const [entry, setEntry] = useState<string | null>("ErasStakersPaged")
|
||||
const [pallet, setPallet] = useState<string | null>("System")
|
||||
const [entry, setEntry] = useState<string | null>("Account")
|
||||
|
||||
const selectedPallet =
|
||||
(pallet && lookup.metadata.pallets.find((p) => p.name === pallet)) || null
|
||||
|
||||
@@ -38,7 +38,7 @@ export const StorageSubscriptions: FC = () => {
|
||||
const StorageSubscriptionBox: FC<{ subscription: string }> = ({
|
||||
subscription,
|
||||
}) => {
|
||||
const [mode, setMode] = useState<"json" | "decoded">("json")
|
||||
const [mode, setMode] = useState<"json" | "decoded">("decoded")
|
||||
const storageSubscription = useStateObservable(
|
||||
storageSubscription$(subscription),
|
||||
)
|
||||
@@ -181,14 +181,16 @@ const ValueDisplay: FC<{
|
||||
<h3 className="overflow-hidden text-ellipsis">{title}</h3>
|
||||
</div>
|
||||
{mode === "decoded" ? (
|
||||
<ViewCodec
|
||||
codecType={storageSubscription.type}
|
||||
value={{
|
||||
type: CodecComponentType.Initial,
|
||||
value: codec.enc(value),
|
||||
}}
|
||||
metadata={metadata}
|
||||
/>
|
||||
<div className="leading-tight">
|
||||
<ViewCodec
|
||||
codecType={storageSubscription.type}
|
||||
value={{
|
||||
type: CodecComponentType.Initial,
|
||||
value: codec.enc(value),
|
||||
}}
|
||||
metadata={metadata}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<JsonDisplay src={value} />
|
||||
)}
|
||||
|
||||
+18
-9
@@ -1,7 +1,14 @@
|
||||
import { EnumVar, StructVar } from "@polkadot-api/metadata-builders"
|
||||
import { EnumVar, StructVar, Var } from "@polkadot-api/metadata-builders"
|
||||
|
||||
const complexTypes = new Set(["array", "sequence", "struct", "enum", "result"])
|
||||
export const isComplex = (type: string) => complexTypes.has(type)
|
||||
const complexTypes = new Set<Var["type"]>([
|
||||
"array",
|
||||
"sequence",
|
||||
"struct",
|
||||
"enum",
|
||||
"result",
|
||||
"option",
|
||||
])
|
||||
export const isComplex = (type: Var["type"]) => complexTypes.has(type)
|
||||
|
||||
export const isEnumComplex = <T extends EnumVar>(
|
||||
shape: T,
|
||||
@@ -13,15 +20,17 @@ export const isEnumComplex = <T extends EnumVar>(
|
||||
)
|
||||
}
|
||||
|
||||
export const getEnumInnerVar = <T extends EnumVar>(
|
||||
shape: T,
|
||||
type: keyof T["value"],
|
||||
): Var => {
|
||||
const innerShape = shape.value[type]
|
||||
return innerShape.type === "lookupEntry" ? innerShape.value : innerShape
|
||||
}
|
||||
export const getEnumInnerType = <T extends EnumVar>(
|
||||
shape: T,
|
||||
type: keyof T["value"],
|
||||
) => {
|
||||
const innerShape = shape.value[type]
|
||||
return innerShape.type === "lookupEntry"
|
||||
? innerShape.value.type
|
||||
: innerShape.type
|
||||
}
|
||||
) => getEnumInnerVar(shape, type).type
|
||||
|
||||
export const getStructInnerType = <T extends StructVar>(
|
||||
shape: T,
|
||||
|
||||
Reference in New Issue
Block a user