diff --git a/docusaurus.config.js b/docusaurus.config.js index 1d8fe01a04..6ce07aa717 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -2,6 +2,8 @@ // Note: type annotations allow type checking and IDEs autocompletion require("dotenv").config(); +const { fetchAndGenerateSidebarItems } = require("./src/helpers/index.ts"); +const capitalize = require("lodash.capitalize"); const { themes } = require("prism-react-renderer"); const codeTheme = themes.dracula; const remarkCodesandbox = require("remark-codesandbox"); @@ -32,6 +34,7 @@ const config = { customFields: { LD_CLIENT_ID: process.env.LD_CLIENT_ID, + sidebarData: {}, }, trailingSlash: true, @@ -122,6 +125,19 @@ const config = { editUrl: "https://github.com/MetaMask/metamask-docs/edit/main/", sidebarPath: require.resolve("./services-sidebar.js"), breadcrumbs: false, + sidebarItemsGenerator: async function ({ defaultSidebarItemsGenerator, ...args }) { + config.customFields.sidebarData = args; + let sidebarItems = await defaultSidebarItemsGenerator(args); + const networkName = "linea"; + const dynamicSidebarItems = await fetchAndGenerateSidebarItems(networkName); + const updatedItems = sidebarItems.map(item => { + if (item?.label === capitalize(networkName) && item?.items) { + item.items = [...item.items, ...dynamicSidebarItems] + } + return item; + }) + return [...updatedItems]; + }, }, ], [ diff --git a/package.json b/package.json index 20e3e53e62..22e2c8c15d 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "dotenv": "^16.4.5", "js-cookie": "^3.0.5", "launchdarkly-js-client-sdk": "^3.3.0", + "lodash.capitalize": "^4.2.1", "lodash.debounce": "^4.0.8", "lodash.isobject": "^3.0.2", "node-polyfill-webpack-plugin": "^2.0.1", diff --git a/src/components/ParserOpenRPC/index.tsx b/src/components/ParserOpenRPC/index.tsx index 63b1192426..874263fea5 100644 --- a/src/components/ParserOpenRPC/index.tsx +++ b/src/components/ParserOpenRPC/index.tsx @@ -13,6 +13,7 @@ import clsx from "clsx"; import { useColorMode } from "@docusaurus/theme-common"; import { trackClickForSegment, trackInputChangeForSegment } from "@site/src/lib/segmentAnalytics"; import { MetamaskProviderContext } from "@site/src/theme/Root"; +import { useLocation } from "@docusaurus/router"; interface ParserProps { network: NETWORK_NAMES; @@ -40,6 +41,16 @@ export default function ParserOpenRPC({ network, method, extraContent }: ParserP const [drawerLabel, setDrawerLabel] = useState(null); const [isComplexTypeView, setIsComplexTypeView] = useState(false); const { colorMode } = useColorMode(); + const location = useLocation(); + const isWalletReferencePage = location.pathname.includes("/wallet/reference"); + const trackAnalyticsForRequest = (response) => { + trackClickForSegment({ + eventName: "Request Sent", + clickType: "Request Sent", + userExperience: "B", + ...(response?.code && { responseStatus: response.code }), + }); + } const openModal = () => { setModalOpen(true); trackClickForSegment({ @@ -132,21 +143,40 @@ export default function ParserOpenRPC({ network, method, extraContent }: ParserP }; const onSubmitRequestHandle = async () => { - if (!metaMaskProvider) return - try { - const response = await metaMaskProvider?.request({ - method: method, - params: paramsData - }) - setReqResult(response); - trackClickForSegment({ - eventName: "Request Sent", - clickType: "Request Sent", - userExperience: "B", - ...(response?.code && { responseStatus: response.code }), - }); - } catch (e) { - setReqResult(e); + if (isMetamaskNetwork) { + if (!metaMaskProvider) return + try { + const response = await metaMaskProvider?.request({ + method: method, + params: paramsData + }) + setReqResult(response); + trackAnalyticsForRequest(response); + } catch (e) { + setReqResult(e); + } + } else { + const NETWORK_URL = "https://linea-mainnet.infura.io"; + const API_KEY = "366ba274ec6f4cf1810de6003cbb9a5e"; + const URL = `${NETWORK_URL}/v3/${API_KEY}`; + let params = { + method: "POST", + "Content-Type": "application/json", + body: JSON.stringify({ + jsonrpc: "2.0", + method, + params: paramsData, + id: 1, + }), + }; + const res = await fetch(URL, params); + if (res.ok) { + const response = await res.json(); + setReqResult(response.result); + trackAnalyticsForRequest(response.result); + } else { + console.error("error"); + } } }; @@ -228,7 +258,7 @@ export default function ParserOpenRPC({ network, method, extraContent }: ParserP
- {!metaMaskAccount && } + {isWalletReferencePage && !metaMaskAccount && } { + try { + const response = await fetch(`https://sot-network-methods.vercel.app/specs/${networkName}`); + const data = await response.json(); + const dynamicItems = data.methods.map((method) => ({ + type: "link", + label: method.name, + href: `/services/reference/linea/json-rpc-methods-new/${method.name}`, + })).sort((a, b) => a.label.localeCompare(b.label)); + return [ + { + type: "category", + label: "JSON-RPC Methods NEW", + collapsed: true, + collapsible: true, + items: dynamicItems, + }, + ]; + } catch (error) { + console.error("Error fetching methods:", error); + return []; + } +} diff --git a/src/pages/CustomPage/index.tsx b/src/pages/CustomPage/index.tsx new file mode 100644 index 0000000000..d2413a9e86 --- /dev/null +++ b/src/pages/CustomPage/index.tsx @@ -0,0 +1,125 @@ +import Layout from "@theme/Layout"; +import { NETWORK_NAMES } from "@site/src/plugins/plugin-json-rpc"; +import ParserOpenRPC from "@site/src/components/ParserOpenRPC"; +import React, { useEffect, useState } from "react"; +import DocSidebar from '@theme/DocSidebar'; +import styles from "@site/src/theme/Layout/styles.module.css" +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import { fetchAndGenerateSidebarItems } from "@site/src/helpers"; +import * as capitalize from "lodash.capitalize" + +function generateSidebarItems(docs) { + const categories = {}; + + docs.forEach((doc) => { + if (doc.id === 'index') { + categories['Introduction'] = { + type: 'link', + href: '/services', + label: capitalize(doc.frontMatter?.sidebar_label || doc.title), + }; + return; + } + + const pathParts = doc.sourceDirName.split('/'); + let currentCategory = categories; + let isIndexPage = doc.id.endsWith('/index'); + + pathParts.forEach((part, index) => { + if (!currentCategory[part]) { + if (isIndexPage && index === pathParts.length - 2) { + currentCategory[part] = { + type: 'category', + label: capitalize(doc.frontMatter?.sidebar_label || doc.frontMatter?.title || part), + collapsed: true, + collapsible: true, + link: { + type: 'generated-index', + slug: pathParts.slice(0, index + 1).join('/') + }, + items: [] + }; + } else { + currentCategory[part] = { + type: 'category', + label: capitalize(part), + collapsed: true, + collapsible: true, + items: [] + }; + } + } + + if (index === pathParts.length - 1 && !isIndexPage) { + currentCategory[part].items.push({ + type: 'link', + label: capitalize(doc.frontMatter?.title || doc.title), + href: `/services/${doc.id.replace(/\/index$/, '')}`, + sidebar_position: doc.frontMatter?.sidebar_position || Number.MAX_SAFE_INTEGER + }); + } + currentCategory = currentCategory[part].items; + }); + }); + + const convertToArray = (categoryObj) => { + return Object.values(categoryObj).map((category) => { + if (category.items && typeof category.items === 'object') { + category.items = convertToArray(category.items); + if (category.items.every(item => item.sidebar_position !== undefined)) { + category.items.sort((a, b) => (a.sidebar_position || Number.MAX_SAFE_INTEGER) - (b.sidebar_position || Number.MAX_SAFE_INTEGER)); + } + } + return category; + }); + }; + return convertToArray(categories); +} + +const sidebar_wrapper_classes = "theme-doc-sidebar-container docSidebarContainer_node_modules-@docusaurus-theme-classic-lib-theme-DocRoot-Layout-Sidebar-styles-module" + +const CustomPage = (props) => { + const customData = props.route.customData; + const { siteConfig } = useDocusaurusContext(); + const [formattedData, setFormattedData] = useState([]); + const networkName = "linea"; + + useEffect(() => { + fetchAndGenerateSidebarItems(networkName).then(generatedItems => { + setFormattedData(generateSidebarItems(siteConfig.customFields.sidebarData.docs).map(item => { + if (item?.label === "Reference" && item?.items) { + return { + ...item, + items: item.items.map(referenceItem => { + if (referenceItem?.label === capitalize(networkName) && referenceItem?.items) { + return { ...referenceItem, items: [...referenceItem.items, ...generatedItems] }; + } + return referenceItem; + }) + } + } + return item; + })); + }); + }, []); + + return formattedData ? ( + +
+ +
+
+ +
+
+
+
+ ) : null; +}; + +export default CustomPage; diff --git a/src/plugins/plugin-json-rpc.ts b/src/plugins/plugin-json-rpc.ts index 505d3c23d0..78ccb5f18c 100644 --- a/src/plugins/plugin-json-rpc.ts +++ b/src/plugins/plugin-json-rpc.ts @@ -40,14 +40,42 @@ const requests = [ }, ]; +function generateMethodMDX(page) { + return `--- +title: '${page.name}' +--- +# ${page.name} + `; +} + export default function useNetworksMethodPlugin() { return { name: "plugin-json-rpc", async contentLoaded({ actions }) { - const { setGlobalData } = actions; + const { setGlobalData, createData, addRoute } = actions; await fetchMultipleData(requests) .then((responseArray) => { + const networkName = "linea"; setGlobalData({ netData: responseArray }); + return Promise.all(responseArray[responseArray.findIndex(item => item.name === networkName) || 0].data.methods.map(async (page) => { + + const methodMDXContent = generateMethodMDX(page); + + const filePath = await createData( + `services/reference/linea/json-rpc-methods-new/${page.name}.mdx`, + methodMDXContent + ); + + return addRoute({ + path: `/services/reference/linea/json-rpc-methods-new/${page.name}`, + component: require.resolve("../pages/CustomPage/index.tsx"), + exact: true, + modules: { + methodFile: filePath, + }, + customData: { ...page } + }); + })); }) .catch(() => { setGlobalData({ netData: [] }); diff --git a/yarn.lock b/yarn.lock index a42fab8b4e..cdd67c8e90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12493,6 +12493,13 @@ __metadata: languageName: node linkType: hard +"lodash.capitalize@npm:^4.2.1": + version: 4.2.1 + resolution: "lodash.capitalize@npm:4.2.1" + checksum: d9195f31d48c105206f1099946d8bbc8ab71435bc1c8708296992a31a992bb901baf120fdcadd773098ac96e62a79e6b023ee7d26a2deb0d6c6aada930e6ad0a + languageName: node + linkType: hard + "lodash.debounce@npm:^4.0.8": version: 4.0.8 resolution: "lodash.debounce@npm:4.0.8" @@ -13380,6 +13387,7 @@ __metadata: eslint-plugin-react: ^7.34.2 js-cookie: ^3.0.5 launchdarkly-js-client-sdk: ^3.3.0 + lodash.capitalize: ^4.2.1 lodash.debounce: ^4.0.8 lodash.isobject: ^3.0.2 node-polyfill-webpack-plugin: ^2.0.1