diff --git a/package.json b/package.json index 1b564e9..cfe9b33 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dependencies": { "@acala-network/chopsticks-core": "^1.2.4", "@ledgerhq/hw-transport-webusb": "^6.29.13", + "@monaco-editor/react": "^4.7.0", "@polkadot-api/descriptors": "file:.papi/descriptors", "@polkadot-api/json-rpc-provider-proxy": "^0.2.6", "@polkadot-api/metadata-builders": "^0.13.7", @@ -40,7 +41,6 @@ "@radix-ui/react-tooltip": "^1.2.8", "@react-rxjs/core": "^0.10.8", "@react-rxjs/utils": "^0.9.7", - "buffer": "^6.0.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "idb-keyval": "^6.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9615a24..5aa9f58 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,6 +19,9 @@ importers: '@ledgerhq/hw-transport-webusb': specifier: ^6.29.13 version: 6.29.13 + '@monaco-editor/react': + specifier: ^4.7.0 + version: 4.7.0(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@polkadot-api/descriptors': specifier: file:.papi/descriptors version: file:.papi/descriptors(polkadot-api@1.20.4(jiti@2.6.1)(postcss@8.5.6)(rxjs@7.8.2)(yaml@2.6.1)) @@ -91,9 +94,6 @@ importers: '@react-rxjs/utils': specifier: ^0.9.7 version: 0.9.7(@react-rxjs/core@0.10.8(react@19.2.0)(rxjs@7.8.2))(react@19.2.0)(rxjs@7.8.2) - buffer: - specifier: ^6.0.3 - version: 6.0.3 class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -589,6 +589,16 @@ packages: '@polkadot-api/substrate-bindings': '*' '@polkadot-api/utils': '*' + '@monaco-editor/loader@1.6.1': + resolution: {integrity: sha512-w3tEnj9HYEC73wtjdpR089AqkUPskFRcdkxsiSFt3SoUc3OHpmu+leP94CXBm4mHfefmhsdfI0ZQu6qJ0wgtPg==} + + '@monaco-editor/react@4.7.0': + resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} + peerDependencies: + monaco-editor: '>= 0.25.0 < 1' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@msgpack/msgpack@3.1.2': resolution: {integrity: sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ==} engines: {node: '>= 18'} @@ -2240,6 +2250,9 @@ packages: dijkstrajs@1.0.3: resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + dompurify@3.1.7: + resolution: {integrity: sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -2750,6 +2763,11 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + marked@14.0.0: + resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} + engines: {node: '>= 18'} + hasBin: true + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -2783,6 +2801,9 @@ packages: resolution: {integrity: sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==} engines: {node: '>= 8'} + monaco-editor@0.54.0: + resolution: {integrity: sha512-hx45SEUoLatgWxHKCmlLJH81xBo0uXP4sRkESUpmDQevfi+e7K1VuiSprK6UpQ8u4zOcKNiH0pMvHvlMWA/4cw==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -3281,6 +3302,9 @@ packages: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + stdin-discarder@0.2.2: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} engines: {node: '>=18'} @@ -4122,6 +4146,17 @@ snapshots: '@polkadot-api/substrate-bindings': 0.16.5 '@polkadot-api/utils': 0.2.0 + '@monaco-editor/loader@1.6.1': + dependencies: + state-local: 1.0.7 + + '@monaco-editor/react@4.7.0(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@monaco-editor/loader': 1.6.1 + monaco-editor: 0.54.0 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@msgpack/msgpack@3.1.2': {} '@noble/ciphers@1.3.0': {} @@ -6656,6 +6691,8 @@ snapshots: dijkstrajs@1.0.3: {} + dompurify@3.1.7: {} + eastasianwidth@0.2.0: {} electron-to-chromium@1.5.250: {} @@ -7154,6 +7191,8 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + marked@14.0.0: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -7184,6 +7223,11 @@ snapshots: mock-socket@9.3.1: {} + monaco-editor@0.54.0: + dependencies: + dompurify: 3.1.7 + marked: 14.0.0 + ms@2.1.3: {} multiformats@9.9.0: {} @@ -7792,6 +7836,8 @@ snapshots: split2@4.2.0: {} + state-local@1.0.7: {} + stdin-discarder@0.2.2: {} string-width@4.2.3: diff --git a/public/rpc_schemas/chain_getBlock.json b/public/rpc_schemas/chain_getBlock.json new file mode 100644 index 0000000..ded36ce --- /dev/null +++ b/public/rpc_schemas/chain_getBlock.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "chain_getBlock params", + "oneOf": [ + { + "type": "object", + "description": "{} or { hash }.", + "maxProperties": 1, + "additionalProperties": false, + "properties": { "hash": { "$ref": "./common.json#/$defs/hex" } } + }, + { + "type": "array", + "description": "[] or [hash].", + "maxItems": 1, + "items": { "$ref": "./common.json#/$defs/hex" } + } + ] +} diff --git a/public/rpc_schemas/chain_getBlockHash.json b/public/rpc_schemas/chain_getBlockHash.json new file mode 100644 index 0000000..3172ec3 --- /dev/null +++ b/public/rpc_schemas/chain_getBlockHash.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "chain_getBlockHash params", + "oneOf": [ + { + "type": "array", + "description": "[] or [blockNumber].", + "maxItems": 1, + "items": { + "type": "number" + } + } + ] +} diff --git a/public/rpc_schemas/chain_getHeader.json b/public/rpc_schemas/chain_getHeader.json new file mode 100644 index 0000000..6687f80 --- /dev/null +++ b/public/rpc_schemas/chain_getHeader.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "chain_getHeader params", + "oneOf": [ + { + "type": "object", + "description": "{} or { hash }.", + "maxProperties": 1, + "additionalProperties": false, + "properties": { "hash": { "$ref": "./common.json#/$defs/hex" } } + }, + { + "type": "array", + "description": "[] or [hash].", + "maxItems": 1, + "items": { "$ref": "./common.json#/$defs/hex" } + } + ] +} diff --git a/public/rpc_schemas/common.json b/public/rpc_schemas/common.json new file mode 100644 index 0000000..b67be81 --- /dev/null +++ b/public/rpc_schemas/common.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "common.json", + "$defs": { + "hex": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]*$", + "description": "0x-prefixed hex." + } + } +} diff --git a/public/rpc_schemas/state_getReadProof.json b/public/rpc_schemas/state_getReadProof.json new file mode 100644 index 0000000..790194d --- /dev/null +++ b/public/rpc_schemas/state_getReadProof.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "state_getReadProof params", + "oneOf": [ + { + "type": "array", + "description": "[keys] or [keys, at].", + "minItems": 1, + "maxItems": 2, + "prefixItems": [ + { + "type": "array", + "description": "Storage keys to prove.", + "items": { "$ref": "./common.json#/$defs/hex" } + }, + { "$ref": "./common.json#/$defs/hex" } + ] + }, + { + "type": "object", + "description": "{ keys } or { keys, at } or { keys, hash }.", + "required": ["keys"], + "additionalProperties": false, + "properties": { + "keys": { + "type": "array", + "description": "Storage keys to prove.", + "items": { "$ref": "./common.json#/$defs/hex" } + }, + "at": { "$ref": "./common.json#/$defs/hex" }, + "hash": { "$ref": "./common.json#/$defs/hex" } + } + } + ] +} diff --git a/src/main.tsx b/src/main.tsx index 6a95d9d..f1e913a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,5 +1,3 @@ -import { Buffer } from "buffer" -globalThis.Buffer = Buffer import { dynamicBuilder$ } from "@/state/chains/chain.state" import { RemoveSubscribe, Subscribe } from "@react-rxjs/core" import { PolkaHubProvider } from "polkahub" diff --git a/src/pages/RpcCalls/RpcCalls.tsx b/src/pages/RpcCalls/RpcCalls.tsx index 67d8ef4..fc79ec3 100644 --- a/src/pages/RpcCalls/RpcCalls.tsx +++ b/src/pages/RpcCalls/RpcCalls.tsx @@ -1,14 +1,16 @@ import { ActionButton } from "@/components/ActionButton" import { LoadingMetadata } from "@/components/Loading" import { SearchableSelect } from "@/components/Select" -import { Textarea } from "@/components/ui/textarea" import { withSubscribe } from "@/components/withSuspense" import { chainClient$ } from "@/state/chains/chain.state" import { state, useStateObservable } from "@react-rxjs/core" -import { useState } from "react" +import { lazy, Suspense, useRef, useState } from "react" import { firstValueFrom, map, switchMap } from "rxjs" import { RpcCallResults } from "./RpcCallResults" import { addRpcCallQuery } from "./rpcCalls.state" +import { useTheme } from "@/ThemeProvider" + +const Editor = lazy(() => import("@monaco-editor/react")) const chainRpcMethods$ = state( chainClient$.pipe( @@ -19,11 +21,19 @@ const chainRpcMethods$ = state( ), ) +const SCHEMA_URL = window.location.origin export const RpcCalls = withSubscribe( () => { const methods = useStateObservable(chainRpcMethods$) - const [method, setMethod] = useState(null) - const [params, setParams] = useState("[\n\n]") + const setSchema = useRef<((method: string | null) => void) | null>(null) + const [method, _setMethod] = useState(null) + const [params, setParams] = useState("[\n \n]") + const theme = useTheme() + + const setMethod = (method: string | null) => { + _setMethod(method) + setSchema.current?.(method) + } const submit = async () => { const { client } = await firstValueFrom(chainClient$) @@ -54,14 +64,56 @@ export const RpcCalls = withSubscribe( allowCustomValue /> -