From 0b8d11a15ae2673e2dcd4263febf9a1296634e76 Mon Sep 17 00:00:00 2001 From: John Kane Date: Tue, 26 Sep 2023 21:25:15 +0100 Subject: [PATCH] feat/update-visualize (#486) * feat(visualization-report): change title to HH branding Apply Harhdat branding: * The title of the report has been changed to `Hardhat Ignition - `. * The page title has been changed to `Hardhat Ignition`. * Add the HH favicon * feat(visualize-report): update summary to show ids Replace the bespoke approach to deploys/calls with a display of ids. Turn the lists of ids into links that lead to the detail page. * feat(visualization-report): rename overview subtitle to futures Rename `Actions` to `Futures`. We no longer use the name `Actions`. * feat(visualizition-report): display ids in futures list * feat: reflow mermaid top to bottom * feat(visualization-report): include breadcrumb on details page * feat: fix mermaid tests * remove duplicate futures from html * move future details into dropdown --------- Co-authored-by: zoeyTM --- packages/ui/index.html | 3 +- packages/ui/public/favicon.ico | Bin 0 -> 15406 bytes packages/ui/src/components/shared.tsx | 4 + packages/ui/src/main.tsx | 5 - .../components/future-summary.tsx | 193 --------------- .../pages/future-details/future-details.tsx | 34 --- .../components/action.tsx | 106 -------- .../components/future-block.tsx | 232 ++++++++++++++++++ .../components/visualization-details.tsx | 31 ++- .../components/visualization-summary.tsx | 17 +- .../visualization-overview.tsx | 2 +- packages/ui/src/queries/futures.ts | 10 +- packages/ui/src/utils/to-mermaid.ts | 8 +- packages/ui/test/to-mermaid.ts | 32 +-- 14 files changed, 299 insertions(+), 378 deletions(-) create mode 100644 packages/ui/public/favicon.ico delete mode 100644 packages/ui/src/pages/future-details/components/future-summary.tsx delete mode 100644 packages/ui/src/pages/future-details/future-details.tsx delete mode 100644 packages/ui/src/pages/visualization-overview/components/action.tsx create mode 100644 packages/ui/src/pages/visualization-overview/components/future-block.tsx diff --git a/packages/ui/index.html b/packages/ui/index.html index 69895eb22..39a9286d4 100644 --- a/packages/ui/index.html +++ b/packages/ui/index.html @@ -3,7 +3,8 @@ - Ignition + + Hardhat Ignition
diff --git a/packages/ui/public/favicon.ico b/packages/ui/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d5e6b335eb8776f9c0f1909ba912bcac6112f509 GIT binary patch literal 15406 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 literal 0 HcmV?d00001 diff --git a/packages/ui/src/components/shared.tsx b/packages/ui/src/components/shared.tsx index 1210b0ccf..48005feea 100644 --- a/packages/ui/src/components/shared.tsx +++ b/packages/ui/src/components/shared.tsx @@ -14,3 +14,7 @@ export const Panel = styled.div` border: 1px solid black; padding: 1rem; `; + +export const Breadcrumb = styled.div` + padding-bottom: 1rem; +`; diff --git a/packages/ui/src/main.tsx b/packages/ui/src/main.tsx index 1bcf46e48..246006793 100644 --- a/packages/ui/src/main.tsx +++ b/packages/ui/src/main.tsx @@ -7,7 +7,6 @@ import { } from "@nomicfoundation/ignition-core/ui-helpers"; import ReactDOM from "react-dom/client"; import { RouterProvider, createHashRouter } from "react-router-dom"; -import { FutureDetails } from "./pages/future-details/future-details"; import { VisualizationOverview } from "./pages/visualization-overview/visualization-overview"; const loadDeploymentFromEmbeddedDiv = (): IgnitionModule< @@ -49,10 +48,6 @@ const main = async () => { path: "/", element: , }, - { - path: "/future/:futureId", - element: , - }, ]); ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( diff --git a/packages/ui/src/pages/future-details/components/future-summary.tsx b/packages/ui/src/pages/future-details/components/future-summary.tsx deleted file mode 100644 index 3ffbd30e8..000000000 --- a/packages/ui/src/pages/future-details/components/future-summary.tsx +++ /dev/null @@ -1,193 +0,0 @@ -import { - Future, - FutureType, - isFuture, -} from "@nomicfoundation/ignition-core/ui-helpers"; -import { PageTitle, Panel } from "../../../components/shared"; -import { SummaryHeader } from "../../../components/summary-header"; -import { argumentTypeToString } from "../../../utils/argumentTypeToString"; - -export const FutureSummary: React.FC<{ - future: Future; -}> = ({ future }) => { - const title = resolveTitleFor(future); - - return ( -
-
- {title} -
- - - - -
- -
-
-
- ); -}; - -function resolveTitleFor(future: Future): string { - switch (future.type) { - case FutureType.NAMED_ARTIFACT_CONTRACT_DEPLOYMENT: - return `Contract deploy - ${future.contractName}`; - case FutureType.CONTRACT_DEPLOYMENT: - return `Contract deploy from Artifact - ${future.contractName}`; - case FutureType.NAMED_ARTIFACT_LIBRARY_DEPLOYMENT: - return `Library deploy - ${future.contractName}`; - case FutureType.LIBRARY_DEPLOYMENT: - return `Library deploy from Artifact - ${future.contractName}`; - case FutureType.CONTRACT_CALL: - return `Call - ${future.contract.contractName}/${future.functionName}`; - case FutureType.STATIC_CALL: - return `Static call - ${future.contract.contractName}/${future.functionName}`; - case FutureType.NAMED_ARTIFACT_CONTRACT_AT: - return `Existing contract - ${future.contractName} (${ - typeof future.address === "string" - ? future.address - : isFuture(future.address) - ? future.address.id - : argumentTypeToString(future.address) - })`; - case FutureType.CONTRACT_AT: - return `Existing contract from Artifact - ${future.contractName} (${ - typeof future.address === "string" - ? future.address - : isFuture(future.address) - ? future.address.id - : argumentTypeToString(future.address) - })`; - case FutureType.READ_EVENT_ARGUMENT: - return `Read event argument from future - ${future.id}`; - case FutureType.SEND_DATA: - return `Send data - ${future.id}`; - } -} - -const FutureDetailsSection: React.FC<{ future: Future }> = ({ future }) => { - switch (future.type) { - case FutureType.NAMED_ARTIFACT_CONTRACT_DEPLOYMENT: - return ( -
-

Contract - {future.contractName}

-

Constructor Args

-
    - {Object.entries(future.constructorArgs).map(([key, value]) => ( -
  • - {key} - {argumentTypeToString(value)} -
  • - ))} -
-
- ); - case FutureType.CONTRACT_DEPLOYMENT: - return ( -
-

Contract - {future.contractName}

-

Constructor Args

-
    - {Object.entries(future.constructorArgs).map(([key, value]) => ( -
  • - {key} - {argumentTypeToString(value)} -
  • - ))} -
-
- ); - case FutureType.NAMED_ARTIFACT_LIBRARY_DEPLOYMENT: - return ( -
-

Library - {future.contractName}

-
- ); - case FutureType.LIBRARY_DEPLOYMENT: - return ( -
-

Library - {future.contractName}

-
- ); - case FutureType.CONTRACT_CALL: - return ( -
-

Contract - {future.contract.contractName}

-

function - {future.functionName}

-

Args

-
    - {Object.entries(future.args).map(([, value]) => ( -
  • {argumentTypeToString(value)}
  • - ))} -
-
- ); - case FutureType.STATIC_CALL: - return ( -
-

Contract - {future.contract.contractName}

-

function - {future.functionName}

-

Args

-
    - {Object.entries(future.args).map(([, value]) => ( -
  • {argumentTypeToString(value)}
  • - ))} -
-
- ); - case FutureType.NAMED_ARTIFACT_CONTRACT_AT: - return ( -
-

Contract - {future.contractName}

-

- Address -{" "} - {typeof future.address === "string" - ? future.address - : isFuture(future.address) - ? future.address.id - : argumentTypeToString(future.address)} -

-
- ); - - case FutureType.CONTRACT_AT: - return ( -
-

Contract - {future.contractName}

-

- Address -{" "} - {typeof future.address === "string" - ? future.address - : isFuture(future.address) - ? future.address.id - : argumentTypeToString(future.address)} -

-
- ); - case FutureType.READ_EVENT_ARGUMENT: - return ( -
-

Future - {future.futureToReadFrom.id}

- {future.futureToReadFrom !== future.emitter ? ( -

Emitter - {future.emitter.id}

- ) : null} -

Event - {future.eventName}

-

Event index - {future.eventIndex}

-

Argument - {future.nameOrIndex}

-
- ); - case FutureType.SEND_DATA: - return ( -
-

- To -{" "} - {typeof future.to === "string" - ? future.to - : isFuture(future.to) - ? future.to.id - : argumentTypeToString(future.to)} -

-

Data - {future.data}

-
- ); - } -}; diff --git a/packages/ui/src/pages/future-details/future-details.tsx b/packages/ui/src/pages/future-details/future-details.tsx deleted file mode 100644 index 5b0a22027..000000000 --- a/packages/ui/src/pages/future-details/future-details.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { - IgnitionModule, - IgnitionModuleResult, -} from "@nomicfoundation/ignition-core/ui-helpers"; -import React, { useMemo } from "react"; -import { useParams } from "react-router-dom"; -import { Page } from "../../components/shared"; -import { getFutureById } from "../../queries/futures"; -import { FutureSummary } from "./components/future-summary"; - -export const FutureDetails: React.FC<{ - ignitionModule: IgnitionModule>; -}> = ({ ignitionModule }) => { - const { futureId } = useParams(); - - const future = useMemo( - () => getFutureById(ignitionModule, futureId), - [ignitionModule, futureId] - ); - - if (future === undefined) { - return ( - -

Future not found

-
- ); - } - - return ( - - - - ); -}; diff --git a/packages/ui/src/pages/visualization-overview/components/action.tsx b/packages/ui/src/pages/visualization-overview/components/action.tsx deleted file mode 100644 index 848173066..000000000 --- a/packages/ui/src/pages/visualization-overview/components/action.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { - Future, - FutureType, - isFuture, -} from "@nomicfoundation/ignition-core/ui-helpers"; -import React, { useCallback } from "react"; -import { useNavigate } from "react-router-dom"; -import styled, { css } from "styled-components"; -import { argumentTypeToString } from "../../../utils/argumentTypeToString"; - -export const Action: React.FC<{ - future: Future; -}> = ({ future }) => { - const navigate = useNavigate(); - - const displayText = toDisplayText(future); - - const navigateToFuture = useCallback(() => { - return navigate(`/future/${encodeURIComponent(future.id)}`); - }, [future.id, navigate]); - - return ( - - {displayText} - - ); -}; - -function toDisplayText(future: Future): string { - switch (future.type) { - case FutureType.NAMED_ARTIFACT_CONTRACT_DEPLOYMENT: - return `Contract deploy ${future.contractName}`; - case FutureType.CONTRACT_DEPLOYMENT: - return `Deploy contract ${future.contractName} from artifact`; - case FutureType.NAMED_ARTIFACT_LIBRARY_DEPLOYMENT: - return `Library deploy ${future.contractName}`; - case FutureType.LIBRARY_DEPLOYMENT: - return `Library deploy ${future.contractName} from artifact`; - case FutureType.CONTRACT_CALL: - return `Call ${future.contract.contractName}/${future.functionName}`; - case FutureType.STATIC_CALL: - return `Static call ${future.contract.contractName}/${future.functionName}`; - case FutureType.NAMED_ARTIFACT_CONTRACT_AT: - return `Existing contract ${future.contractName} (${ - typeof future.address === "string" - ? future.address - : isFuture(future.address) - ? future.address.id - : argumentTypeToString(future.address) - })`; - case FutureType.CONTRACT_AT: - return `Existing contract ${future.contractName} from artifact (${ - typeof future.address === "string" - ? future.address - : isFuture(future.address) - ? future.address.id - : argumentTypeToString(future.address) - })`; - case FutureType.READ_EVENT_ARGUMENT: - return `Read event from future ${future.futureToReadFrom.id} (event ${future.eventName} argument ${future.nameOrIndex})`; - case FutureType.SEND_DATA: - return `Send data to ${ - typeof future.to === "string" - ? future.to - : isFuture(future.to) - ? future.to.id - : argumentTypeToString(future.to) - }`; - } -} - -const Text = styled.p` - margin: 0; -`; - -const ActionBtn = styled.div<{ futureType: FutureType }>` - border: 1px solid black; - padding: 1rem; - font-weight: bold; - - &:hover { - background: blue; - cursor: pointer; - } - - ${(props) => - [ - FutureType.NAMED_ARTIFACT_CONTRACT_DEPLOYMENT, - FutureType.CONTRACT_DEPLOYMENT, - FutureType.NAMED_ARTIFACT_LIBRARY_DEPLOYMENT, - FutureType.LIBRARY_DEPLOYMENT, - ].includes(props.futureType) && - css` - background: green; - color: white; - `} - - ${(props) => - [FutureType.CONTRACT_CALL, FutureType.STATIC_CALL].includes( - props.futureType - ) && - css` - background: yellow; - color: black; - `} -`; diff --git a/packages/ui/src/pages/visualization-overview/components/future-block.tsx b/packages/ui/src/pages/visualization-overview/components/future-block.tsx new file mode 100644 index 000000000..72f158852 --- /dev/null +++ b/packages/ui/src/pages/visualization-overview/components/future-block.tsx @@ -0,0 +1,232 @@ +import { + ArgumentType, + Future, + FutureType, + isFuture, +} from "@nomicfoundation/ignition-core/ui-helpers"; +import React from "react"; +import styled, { css } from "styled-components"; +import { argumentTypeToString } from "../../../utils/argumentTypeToString"; + +export const FutureBlock: React.FC<{ + future: Future; + toggleState: Record; + setToggled: (id: string) => void; +}> = ({ future, toggleState, setToggled }) => { + const futureId = future.id; + const toggled = toggleState[futureId]; + + const displayText = toDisplayText(future); + + const fontWeight = toggled ? "normal" : "bold"; + + const isLibrary = + future.type === FutureType.LIBRARY_DEPLOYMENT || + future.type === FutureType.NAMED_ARTIFACT_LIBRARY_DEPLOYMENT; + + return ( + + {!isLibrary && ( + setToggled(futureId)} toggled={toggled} /> + )} + {displayText} + [{future.module.id}] + {toggled && ( + + )} + + ); +}; + +function toDisplayText(future: Future): string { + switch (future.type) { + case FutureType.NAMED_ARTIFACT_CONTRACT_DEPLOYMENT: + return `Contract deploy ${future.id}`; + case FutureType.CONTRACT_DEPLOYMENT: + return `Deploy contract ${future.id} from artifact`; + case FutureType.NAMED_ARTIFACT_LIBRARY_DEPLOYMENT: + return `Library deploy ${future.id}`; + case FutureType.LIBRARY_DEPLOYMENT: + return `Library deploy ${future.id} from artifact`; + case FutureType.CONTRACT_CALL: + return `Call ${future.id}`; + case FutureType.STATIC_CALL: + return `Static call ${future.id}`; + case FutureType.NAMED_ARTIFACT_CONTRACT_AT: + return `Existing contract ${future.id} (${ + typeof future.address === "string" + ? future.address + : isFuture(future.address) + ? future.address.id + : argumentTypeToString(future.address) + })`; + case FutureType.CONTRACT_AT: + return `Existing contract ${future.id} from artifact (${ + typeof future.address === "string" + ? future.address + : isFuture(future.address) + ? future.address.id + : argumentTypeToString(future.address) + })`; + case FutureType.READ_EVENT_ARGUMENT: + return `Read event from future ${future.futureToReadFrom.id} (event ${future.eventName} argument ${future.nameOrIndex})`; + case FutureType.SEND_DATA: + return `Send data ${future.id} to ${ + typeof future.to === "string" + ? future.to + : isFuture(future.to) + ? future.to.id + : argumentTypeToString(future.to) + }`; + } +} + +const Text = styled.div` + margin: 0; + display: inline; +`; + +const FutureBtn = styled.div<{ futureType: FutureType }>` + border: 1px solid black; + padding: 1rem; + font-weight: normal; + + ${(props) => + [ + FutureType.NAMED_ARTIFACT_CONTRACT_DEPLOYMENT, + FutureType.CONTRACT_DEPLOYMENT, + FutureType.NAMED_ARTIFACT_LIBRARY_DEPLOYMENT, + FutureType.LIBRARY_DEPLOYMENT, + ].includes(props.futureType) && + css` + background: green; + color: white; + `} + + ${(props) => + [FutureType.CONTRACT_CALL, FutureType.STATIC_CALL].includes( + props.futureType + ) && + css` + background: yellow; + color: black; + `} +`; + +const ToggleBtn: React.FC<{ + toggled: boolean; + setToggled: () => void; +}> = ({ toggled, setToggled }) => { + return ( + + {toggled ? "- " : "+ "} + + ); +}; + +const FutureDetailsSection: React.FC<{ + future: Future; + setToggled: (id: string) => void; +}> = ({ future, setToggled }) => { + switch (future.type) { + case FutureType.NAMED_ARTIFACT_CONTRACT_DEPLOYMENT: + case FutureType.CONTRACT_DEPLOYMENT: + return ( +
+

Constructor Arguments

+
    + {Object.entries(future.constructorArgs).map(([, arg]) => ( + + ))} +
+
+ ); + case FutureType.NAMED_ARTIFACT_LIBRARY_DEPLOYMENT: + case FutureType.LIBRARY_DEPLOYMENT: + return null; + case FutureType.CONTRACT_CALL: + return ( +
+

Arguments

+
    + {Object.entries(future.args).map(([, arg]) => ( + + ))} +
+
+ ); + case FutureType.STATIC_CALL: + return ( +
+

Arguments

+
    + {Object.entries(future.args).map(([, arg]) => ( + + ))} +
+
+ ); + case FutureType.NAMED_ARTIFACT_CONTRACT_AT: + case FutureType.CONTRACT_AT: + return ( +
+

Contract - {future.contractName}

+

+ Address -{" "} + {typeof future.address === "string" ? ( + future.address + ) : ( + + )} +

+
+ ); + case FutureType.READ_EVENT_ARGUMENT: + return ( +
+

Emitter - {future.emitter.id}

+

Event - {future.eventName}

+

Event index - {future.eventIndex}

+

Argument - {future.nameOrIndex}

+
+ ); + case FutureType.SEND_DATA: + return ( +
+

+ To -{" "} + {typeof future.to === "string" ? ( + future.to + ) : ( + + )} +

+

Data - {future.data}

+
+ ); + } +}; + +const Argument: React.FC<{ + setToggled: (id: string) => void; + arg: ArgumentType; +}> = ({ setToggled, arg }) => { + if (isFuture(arg)) { + return ( +
  • setToggled(arg.id)} + > + {argumentTypeToString(arg)} +
  • + ); + } + return
  • {argumentTypeToString(arg)}
  • ; +}; diff --git a/packages/ui/src/pages/visualization-overview/components/visualization-details.tsx b/packages/ui/src/pages/visualization-overview/components/visualization-details.tsx index f3e6213dd..299f24f0c 100644 --- a/packages/ui/src/pages/visualization-overview/components/visualization-details.tsx +++ b/packages/ui/src/pages/visualization-overview/components/visualization-details.tsx @@ -1,12 +1,13 @@ import { + FutureType, IgnitionModule, IgnitionModuleResult, } from "@nomicfoundation/ignition-core/ui-helpers"; -import { useMemo } from "react"; +import { useMemo, useState } from "react"; import styled from "styled-components"; import { Mermaid } from "../../../components/mermaid"; import { getAllFuturesForModule } from "../../../queries/futures"; -import { Action } from "./action"; +import { FutureBlock } from "./future-block"; export const VisualizationDetails: React.FC<{ ignitionModule: IgnitionModule>; @@ -16,6 +17,23 @@ export const VisualizationDetails: React.FC<{ [ignitionModule] ); + const toggleMap = Object.fromEntries( + futures + .filter( + ({ type }) => + type !== FutureType.LIBRARY_DEPLOYMENT && + type !== FutureType.NAMED_ARTIFACT_LIBRARY_DEPLOYMENT + ) + .map(({ id }) => [id, false]) + ); + + const [toggleState, setToggledInternal] = useState(toggleMap); + + const setToggled = (id: string) => { + const newState = { ...toggleState, [id]: !toggleState[id] }; + setToggledInternal(newState); + }; + return (

    Visualization

    @@ -24,10 +42,15 @@ export const VisualizationDetails: React.FC<{
    -

    Actions

    +

    Futures

    {futures.map((future) => ( - + ))}
    diff --git a/packages/ui/src/pages/visualization-overview/components/visualization-summary.tsx b/packages/ui/src/pages/visualization-overview/components/visualization-summary.tsx index 6f16006f9..7b9847d5d 100644 --- a/packages/ui/src/pages/visualization-overview/components/visualization-summary.tsx +++ b/packages/ui/src/pages/visualization-overview/components/visualization-summary.tsx @@ -27,9 +27,8 @@ export const VisualizationSummary: React.FC<{

    - The successful completion of the deployment will send{" "} - {deployFutures.length + callFutures.length} - transactions: + The successful completion of the deployment will apply{" "} + {deployFutures.length + callFutures.length} updates on-chain:

    @@ -39,7 +38,7 @@ export const VisualizationSummary: React.FC<{
      {deployFutures.map((deploy) => (
    • - {deploy.contractName} ({deploy.module.id}) + {deploy.id}
    • ))}
    @@ -51,7 +50,9 @@ export const VisualizationSummary: React.FC<{

    {callFutures.length} calls

      {callFutures.map((call) => ( -
    • {call.id}
    • +
    • + {call.id} +
    • ))}
    @@ -63,15 +64,11 @@ export const VisualizationSummary: React.FC<{ const SummaryColumns = styled.div` display: grid; - grid-template-columns: 1fr 1fr 1fr; + grid-template-columns: 1fr 1fr; `; const SummaryColumn = styled.div` h4 { text-decoration: underline; } - - ul { - list-style-type: none; - } `; diff --git a/packages/ui/src/pages/visualization-overview/visualization-overview.tsx b/packages/ui/src/pages/visualization-overview/visualization-overview.tsx index 0f2116ced..ab940156c 100644 --- a/packages/ui/src/pages/visualization-overview/visualization-overview.tsx +++ b/packages/ui/src/pages/visualization-overview/visualization-overview.tsx @@ -13,7 +13,7 @@ export const VisualizationOverview: React.FC<{ return (
    - Ignition - {ignitionModule.id} + Hardhat Ignition - {ignitionModule.id}
    diff --git a/packages/ui/src/queries/futures.ts b/packages/ui/src/queries/futures.ts index 897ed0dfe..c1b831662 100644 --- a/packages/ui/src/queries/futures.ts +++ b/packages/ui/src/queries/futures.ts @@ -32,11 +32,13 @@ export function getAllFuturesForModule({ futures, submodules, }: IgnitionModule>): Future[] { - return Array.from(futures).concat( - Array.from(submodules.values()).flatMap((submodule) => - getAllFuturesForModule(submodule) + return Array.from(futures) + .concat( + Array.from(submodules.values()).flatMap((submodule) => + getAllFuturesForModule(submodule) + ) ) - ); + .filter((v, i, a) => a.indexOf(v) === i); // remove duplicates } /** diff --git a/packages/ui/src/utils/to-mermaid.ts b/packages/ui/src/utils/to-mermaid.ts index a9695da87..b0cc7436f 100644 --- a/packages/ui/src/utils/to-mermaid.ts +++ b/packages/ui/src/utils/to-mermaid.ts @@ -43,7 +43,7 @@ export function toMermaid( ), ].join("\n"); - return `flowchart BT\n\n${toEscapedId( + return `flowchart TB\n\n${toEscapedId( ignitionModule.id )}:::startModule\n\n${subgraphSections}${ futureDependencies === "" ? "" : "\n\n" + futureDependencies @@ -70,7 +70,7 @@ function prettyPrintModule( .map((f) => `${lineIndent}${toEscapedId(f.id)}["${toLabel(f)}"]`) .join(`\n${lineIndent}`); - return `${lineIndent}subgraph ${module.id}\n${lineIndent} direction BT\n\n${lineIndent}${futureList}\n${lineIndent}end`; + return `${lineIndent}subgraph ${module.id}\n${lineIndent} direction TB\n\n${lineIndent}${futureList}\n${lineIndent}end`; } function toLabel(f: Future): string { @@ -84,9 +84,9 @@ function toLabel(f: Future): string { case FutureType.LIBRARY_DEPLOYMENT: return `Deploy library from artifact ${f.contractName}`; case FutureType.CONTRACT_CALL: - return `Call ${f.contract.contractName}/${f.functionName}`; + return `Call ${f.contract.contractName}.${f.functionName}`; case FutureType.STATIC_CALL: - return `Static call ${f.contract.contractName}/${f.functionName}`; + return `Static call ${f.contract.contractName}.${f.functionName}`; case FutureType.NAMED_ARTIFACT_CONTRACT_AT: return `Existing contract ${f.contractName} (${ typeof f.address === "string" diff --git a/packages/ui/test/to-mermaid.ts b/packages/ui/test/to-mermaid.ts index 6695dd4fa..3a51ffa81 100644 --- a/packages/ui/test/to-mermaid.ts +++ b/packages/ui/test/to-mermaid.ts @@ -16,12 +16,12 @@ describe("to-mermaid", () => { }); const expectedResult = testFormat` - flowchart BT + flowchart TB Module:::startModule subgraph Module - direction BT + direction TB Module#Contract1["Deploy Contract1"] end @@ -40,12 +40,12 @@ describe("to-mermaid", () => { }); const expectedResult = testFormat` - flowchart BT + flowchart TB Test_registrar:::startModule subgraph Test_registrar - direction BT + direction TB Test_registrar#Contract1["Deploy Contract1"] end @@ -80,22 +80,22 @@ describe("to-mermaid", () => { }); const expectedResult = testFormat` - flowchart BT + flowchart TB Module:::startModule subgraph Module - direction BT + direction TB Module#Contract3["Deploy Contract3"] end subgraph Submodule1 - direction BT + direction TB Submodule1#Contract1["Deploy Contract1"] end subgraph Submodule2 - direction BT + direction TB Submodule2#Contract2["Deploy Contract2"] end @@ -159,20 +159,20 @@ describe("to-mermaid", () => { }); const expectedResult = testFormat` - flowchart BT + flowchart TB Module:::startModule subgraph Module - direction BT + direction TB Module#BasicContract["Deploy BasicContract"] Module#BasicLibrary["Deploy library BasicLibrary"] Module#BasicLibrary2["Deploy library from artifact BasicLibrary"] Module#ContractWithLibrary["Deploy from artifact ContractWithLibrary"] - Module#BasicContract.basicFunction["Call BasicContract/basicFunction"] + Module#BasicContract.basicFunction["Call BasicContract.basicFunction"] Module#BasicContract.BasicEvent.eventArg.0["Read event from future Module#BasicContract.basicFunction (event BasicEvent argument eventArg)"] - Module#ContractWithLibrary.readonlyFunction["Static call ContractWithLibrary/readonlyFunction"] + Module#ContractWithLibrary.readonlyFunction["Static call ContractWithLibrary.readonlyFunction"] Module#BasicContract2["Existing contract BasicContract (Module#BasicContract)"] Module#ContractWithLibrary2["Existing contract from artifact ContractWithLibrary (Module#ContractWithLibrary)"] Module#test_send["Send data to Module#BasicContract2"] @@ -203,16 +203,16 @@ describe("to-mermaid", () => { }); const expectedResult = testFormat` - flowchart BT + flowchart TB Module:::startModule subgraph Module - direction BT + direction TB Module#ens["Deploy ens"] - Module#ens.setAddr_bytes32_address_["Call ens/setAddr(bytes32,address)"] - Module#ens.getAddr_bytes32_address_["Static call ens/getAddr(bytes32,address)"] + Module#ens.setAddr_bytes32_address_["Call ens.setAddr(bytes32,address)"] + Module#ens.getAddr_bytes32_address_["Static call ens.getAddr(bytes32,address)"] end Module#ens.setAddr_bytes32_address_ --> Module#ens