trufflesuite/truffle

View on GitHub
packages/dashboard/src/components/composed/Debugger/Variables.tsx

Summary

Maintainability
D
2 days
Test Coverage
import { useEffect, useState } from "react";
import * as CodecComponents from "@truffle/codec-components/react";
import "@truffle/codec-components/react-styles";
import { createStyles, Flex } from "@mantine/core";
import { useDash } from "src/hooks";

const useStyles = createStyles(theme => ({
  sectionHeader: {
    height: 42,
    fontSize: 16,
    paddingTop: 10,
    paddingLeft: 16,
    backgroundColor:
      theme.colorScheme === "dark"
        ? `${theme.colors["truffle-beige"][8]}33`
        : theme.colors["truffle-beige"][2],
    borderBottom: "1px solid",
    borderColor:
      theme.colorScheme === "dark"
        ? theme.colors["truffle-brown"][5]
        : `${theme.colors["truffle-beige"][5]}73`
  },
  variablesContainer: {
    overflow: "hidden",
    height: "40%",
    borderWidth: 1,
    borderStyle: "solid",
    borderRadius: 4,
    marginBottom: 20,
    borderColor:
      theme.colorScheme === "dark"
        ? theme.colors["truffle-brown"][5]
        : `${theme.colors["truffle-beige"][5]}73`
  },
  variables: {
    overflow: "scroll",
    height: "100%",
    backgroundColor:
      theme.colorScheme === "dark" ? theme.colors["truffle-brown"][8] : "white"
  },
  variablesContent: {
    paddingLeft: 10
  },
  variablesSection: {
    listStyleType: "none",
    marginBlockStart: "0em",
    marginBlockEnd: "0em",
    marginInlineStart: "0em",
    marginInlineEnd: "0em",
    paddingInlineStart: "0em",
    marginBottom: "1em"
  },
  variablesTypes: {
    fontSize: 12,
    fontWeight: 800,
    textDecoration: "underline",
    marginBottom: "0.5em"
  }
}));

function Variables(): JSX.Element | null {
  const { classes } = useStyles();
  const {
    state: {
      debugger: { session }
    }
  } = useDash()!;
  const [variables, setVariables] = useState<any>(null);

  // when the debugger step changes, update variables
  useEffect(() => {
    async function getVariables() {
      // we don't render this component until session is defined
      const sections = session!.view(
        session!.selectors.data.current.identifiers.sections
      );
      const vars = await session!.variables();
      if (!vars || Object.keys(vars).length === 0) return;

      const variableValues: { [key: string]: any } = {};

      // section here is a variable category/type such as a Solidity built-in
      // or contract variable
      Object.keys(sections).forEach((section: string) => {
        const sectionVars = sections[section];
        if (!sectionVars || sectionVars.length === 0) return;
        sectionVars.forEach((varName: string) => {
          variableValues[section] = {
            ...variableValues[section],
            [varName]: vars[varName]
          };
        });
      });
      setVariables(variableValues);
    }

    getVariables();
  }, [session!.view(session!.selectors.trace.index)]);

  const output = variables
    ? Object.keys(variables).map(sectionName => {
        // if there are no variables for a section/type, display just the name
        if (
          !variables[sectionName] ||
          Object.keys(variables[sectionName]).length === 0
        ) {
          return (
            <div key={sectionName}>
              <div className={classes.variablesTypes}>{sectionName}</div>
              <ul className={classes.variablesSection}></ul>
            </div>
          );
        }

        // calculate variable values and put them in the appropriate section
        const variableVals = Object.keys(variables[sectionName]).map(
          (variableName: string) => {
            return (
              <li key={variableName}>
                <CodecComponents.NameValuePair
                  data={{
                    name: `${variableName}`,
                    value: variables[sectionName][variableName]
                  }}
                />
              </li>
            );
          }
        );
        return (
          <div key={sectionName}>
            <div className={classes.variablesTypes}>{sectionName}</div>
            <ul className={classes.variablesSection}>{variableVals}</ul>
          </div>
        );
      })
    : null;

  return (
    <Flex direction="column" className={classes.variablesContainer}>
      <div className={classes.sectionHeader}>Variables</div>
      <div className={classes.variables}>
        <pre className={classes.variablesContent}>{output}</pre>
      </div>
    </Flex>
  );
}

export default Variables;