From 1f1d698deb922add26e065e799cea2437fa2ae22 Mon Sep 17 00:00:00 2001 From: Sophie <47993817+sdankel@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:15:40 -0800 Subject: [PATCH 1/3] feat: Add ABI view --- app/src/AbiApp.tsx | 74 +++++++++++++++++++ .../editor/components/AbiEditorView.tsx | 50 +++++++++++++ .../features/editor/components/JsonEditor.tsx | 37 ++++++++++ .../toolbar/components/AbiActionToolbar.tsx | 59 +++++++++++++++ .../toolbar/hooks/useConnectIfNotAlready.ts | 2 +- app/src/index.tsx | 5 ++ 6 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 app/src/AbiApp.tsx create mode 100644 app/src/features/editor/components/AbiEditorView.tsx create mode 100644 app/src/features/editor/components/JsonEditor.tsx create mode 100644 app/src/features/toolbar/components/AbiActionToolbar.tsx diff --git a/app/src/AbiApp.tsx b/app/src/AbiApp.tsx new file mode 100644 index 0000000..f65bea1 --- /dev/null +++ b/app/src/AbiApp.tsx @@ -0,0 +1,74 @@ +import { useCallback, useState } from "react"; +import LogView from "./features/editor/components/LogView"; +import { loadAbi, saveSwayCode } from "./utils/localStorage"; +import InteractionDrawer from "./features/interact/components/InteractionDrawer"; +import { useLog } from "./features/editor/hooks/useLog"; +import { Analytics } from "@vercel/analytics/react"; +import useTheme from "./context/theme"; +import AbiActionToolbar from "./features/toolbar/components/AbiActionToolbar"; +import AbiEditorView from "./features/editor/components/AbiEditorView"; + +const DRAWER_WIDTH = "40vw"; + +function AbiApp() { + // The current sway code in the editor. + const [abiCode, setAbiCode] = useState(loadAbi()); + + // Functions for reading and writing to the log output. + const [log, updateLog] = useLog(); + + // The contract ID of the deployed contract. + const [contractId, setContractId] = useState(""); + + // An error message to display to the user. + const [drawerOpen, setDrawerOpen] = useState(false); + + // The theme color for the app. + const { themeColor } = useTheme(); + + const onSwayCodeChange = useCallback( + (code: string) => { + saveSwayCode(code); + setAbiCode(code); + }, + [setAbiCode], + ); + + return ( +
+ +
+ + +
+ + +
+ ); +} + +export default AbiApp; diff --git a/app/src/features/editor/components/AbiEditorView.tsx b/app/src/features/editor/components/AbiEditorView.tsx new file mode 100644 index 0000000..aea7d2a --- /dev/null +++ b/app/src/features/editor/components/AbiEditorView.tsx @@ -0,0 +1,50 @@ +import React from "react"; +import { useIsMobile } from "../../../hooks/useIsMobile"; +import JsonEditor from "./JsonEditor"; +import { TextField } from "@mui/material"; + +export interface AbiEditorViewProps { + abiCode: string; + onAbiCodeChange: (value: string) => void; + contractId: string; + setContractId: (contractId: string) => void; +} + +function AbiEditorView({ + abiCode, + onAbiCodeChange, + contractId, + setContractId, +}: AbiEditorViewProps) { + const isMobile = useIsMobile(); + + return ( +
+ setContractId(e.target.value)} + style={{ width: "100%", marginBottom: "10px" }} + /> +
+ +
+
+ ); +} + +export default AbiEditorView; diff --git a/app/src/features/editor/components/JsonEditor.tsx b/app/src/features/editor/components/JsonEditor.tsx new file mode 100644 index 0000000..4795154 --- /dev/null +++ b/app/src/features/editor/components/JsonEditor.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import AceEditor from "react-ace"; +import "ace-builds/webpack-resolver"; +import "ace-builds/src-noconflict/mode-json"; +import "ace-builds/src-noconflict/theme-chrome"; +import "ace-builds/src-noconflict/theme-tomorrow_night_bright"; +import { StyledBorder } from "../../../components/shared"; +import useTheme from "../../../context/theme"; + +export interface JsonEditorProps { + code: string; + onChange: (value: string) => void; +} + +function JsonEditor({ code, onChange }: JsonEditorProps) { + const { editorTheme, themeColor } = useTheme(); + + return ( + + + + ); +} + +export default JsonEditor; diff --git a/app/src/features/toolbar/components/AbiActionToolbar.tsx b/app/src/features/toolbar/components/AbiActionToolbar.tsx new file mode 100644 index 0000000..a12fbec --- /dev/null +++ b/app/src/features/toolbar/components/AbiActionToolbar.tsx @@ -0,0 +1,59 @@ +import React, { useCallback } from "react"; +import OpenInNew from "@mui/icons-material/OpenInNew"; +import SecondaryButton from "../../../components/SecondaryButton"; +import { useIsMobile } from "../../../hooks/useIsMobile"; +import SwitchThemeButton from "./SwitchThemeButton"; +import { useConnectIfNotAlready } from "../hooks/useConnectIfNotAlready"; +import { useDisconnect } from "@fuels/react"; + +export interface AbiActionToolbarProps { + drawerOpen: boolean; + setDrawerOpen: (open: boolean) => void; +} + +function AbiActionToolbar({ + drawerOpen, + setDrawerOpen, +}: AbiActionToolbarProps) { + const isMobile = useIsMobile(); + const { isConnected, connect } = useConnectIfNotAlready(); + const { disconnect } = useDisconnect(); + + const onDocsClick = useCallback(() => { + window.open("https://docs.fuel.network/docs/sway", "_blank", "noreferrer"); + }, []); + + return ( +
+ setDrawerOpen(!drawerOpen)} + text="INTERACT" + tooltip="Interact with the contract ABI" + /> + } + /> + + {!isMobile && } +
+ ); +} + +export default AbiActionToolbar; diff --git a/app/src/features/toolbar/hooks/useConnectIfNotAlready.ts b/app/src/features/toolbar/hooks/useConnectIfNotAlready.ts index 0cec27f..329bc1d 100644 --- a/app/src/features/toolbar/hooks/useConnectIfNotAlready.ts +++ b/app/src/features/toolbar/hooks/useConnectIfNotAlready.ts @@ -39,5 +39,5 @@ export function useConnectIfNotAlready() { } }, [isError, failedCallbackRef]); - return { connectIfNotAlready, isConnected }; + return { connectIfNotAlready, isConnected, connect }; } diff --git a/app/src/index.tsx b/app/src/index.tsx index 1d1a120..f46dd23 100644 --- a/app/src/index.tsx +++ b/app/src/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; +import AbiApp from "./AbiApp"; import reportWebVitals from "./reportWebVitals"; import "./index.css"; import { Providers } from "./components/Providers"; @@ -11,6 +12,10 @@ const router = createBrowserRouter([ path: "/", element: , }, + { + path: "/abi", + element: , + }, ]); const root = ReactDOM.createRoot( From e99c810a1a5447e58d5b039ab9d531b40ceb65f0 Mon Sep 17 00:00:00 2001 From: Sophie <47993817+sdankel@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:29:18 -0800 Subject: [PATCH 2/3] Add link from main page --- app/src/features/toolbar/components/ActionToolbar.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/features/toolbar/components/ActionToolbar.tsx b/app/src/features/toolbar/components/ActionToolbar.tsx index 2568904..729b6c0 100644 --- a/app/src/features/toolbar/components/ActionToolbar.tsx +++ b/app/src/features/toolbar/components/ActionToolbar.tsx @@ -14,6 +14,7 @@ import { useIsMobile } from "../../../hooks/useIsMobile"; import SwitchThemeButton from "./SwitchThemeButton"; import { useConnectIfNotAlready } from "../hooks/useConnectIfNotAlready"; import { useDisconnect } from "@fuels/react"; +import { useNavigate } from "react-router-dom"; export interface ActionToolbarProps { deployState: DeployState; @@ -45,6 +46,7 @@ function ActionToolbar({ const isMobile = useIsMobile(); const { isConnected } = useConnectIfNotAlready(); const { disconnect } = useDisconnect(); + const navigate = useNavigate(); const onDocsClick = useCallback(() => { window.open("https://docs.fuel.network/docs/sway", "_blank", "noreferrer"); @@ -99,6 +101,12 @@ function ActionToolbar({ : "Show the Solidity editor to transpile Solidity to Sway" } /> + navigate("/abi")} + text="ABI" + tooltip="Query an already-deployed contract using the ABI" + /> Date: Fri, 13 Dec 2024 17:50:57 -0800 Subject: [PATCH 3/3] update localstorage --- app/src/AbiApp.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/AbiApp.tsx b/app/src/AbiApp.tsx index f65bea1..877138a 100644 --- a/app/src/AbiApp.tsx +++ b/app/src/AbiApp.tsx @@ -1,6 +1,6 @@ -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import LogView from "./features/editor/components/LogView"; -import { loadAbi, saveSwayCode } from "./utils/localStorage"; +import { loadAbi, saveAbi, saveSwayCode } from "./utils/localStorage"; import InteractionDrawer from "./features/interact/components/InteractionDrawer"; import { useLog } from "./features/editor/hooks/useLog"; import { Analytics } from "@vercel/analytics/react"; @@ -26,6 +26,11 @@ function AbiApp() { // The theme color for the app. const { themeColor } = useTheme(); + // Update the ABI in localstorage when the editor changes. + useEffect(() => { + saveAbi(abiCode); + }, [abiCode]); + const onSwayCodeChange = useCallback( (code: string) => { saveSwayCode(code);