packages/dashboard/src/components/composed/RPCs/RPC/Overview.tsx
import {
Group,
Stack,
Button,
Badge,
Text,
Tooltip,
createStyles
} from "@mantine/core";
import type { ReceivedMessageLifecycle } from "@truffle/dashboard-message-bus-client";
import type { DashboardProviderMessage } from "@truffle/dashboard-message-bus-common";
import { useDash } from "src/hooks";
import { inspectDecoding } from "src/utils/dash";
import type { Decoding } from "src/utils/dash";
import ChainIcon from "src/components/common/ChainIcon";
import { useNavigate } from "react-router-dom";
const useStyles = createStyles((theme, _params, getRef) => {
const {
colors,
colorScheme,
white,
radius,
spacing,
fontFamilyMonospace,
fn
} = theme;
const buttonsWidth = 234;
return {
container: {
flexWrap: "nowrap",
backgroundColor:
colorScheme === "dark"
? fn.rgba(colors["truffle-beige"][8], 0.12)
: colors["truffle-beige"][1],
transition: "background-color 0.2s",
borderRadius: `${radius.sm}px ${radius.sm}px 0 0`,
cursor: "pointer"
},
activeContainer: {
backgroundColor:
colorScheme === "dark"
? fn.rgba(colors["truffle-beige"][8], 0.2)
: white,
[`& .${getRef("button")}`]: {
opacity: 1
},
[`& .${getRef("rejectButton")}`]: {
"backgroundColor": fn.rgba(colors.red[8], 0.5),
"&:hover": {
backgroundColor: colors.red[8]
}
},
[`& .${getRef("confirmButton")}`]: {
"backgroundColor": fn.rgba(colors["truffle-teal"][9], 0.5),
"&:hover": {
backgroundColor: colors["truffle-teal"][9]
}
},
[`& .${getRef("debugButton")}`]: {
"backgroundColor": fn.rgba(colors["truffle-teal"][7], 0.6),
"&:hover": {
backgroundColor: colors["truffle-teal"][7]
}
}
},
info: {
width: `calc(100% - ${buttonsWidth + spacing.xl}px)`
},
methodBadge: {
textTransform: "initial",
cursor: "pointer",
transition: "background-color 0.2s"
},
activeMethodBadge: {
backgroundColor:
colorScheme === "dark"
? fn.darken(colors["truffle-beige"][9], 0.56)
: colors["yellow"][1]
},
decoding: {
display: "inline-block",
maxWidth: "90%",
fontFamily: fontFamilyMonospace,
fontWeight: 700,
color:
colorScheme === "dark"
? colors["truffle-beige"][3]
: colors["truffle-beige"][8]
},
buttonsContainer: {
minWidth: buttonsWidth
},
button: {
ref: getRef("button"),
backgroundColor: colors.gray[7],
transition: "all 0.2s",
opacity: 0.15
},
rejectButton: { ref: getRef("rejectButton") },
confirmButton: { ref: getRef("confirmButton") },
debugButton: { ref: getRef("debugButton") },
confirmButtonRightIcon: {
marginLeft: 4,
marginRight: 6
}
};
});
type OverviewProps = {
lifecycle: ReceivedMessageLifecycle<DashboardProviderMessage>;
showDecoding: boolean;
decoding: Decoding;
decodingFallback?: string;
decodingSucceeded: boolean;
active: boolean;
onBackClick: React.MouseEventHandler<HTMLDivElement>;
onBackEnter: React.MouseEventHandler<HTMLDivElement>;
onBackLeave: React.MouseEventHandler<HTMLDivElement>;
onRejectButtonEnter: React.MouseEventHandler<HTMLButtonElement>;
onRejectButtonLeave: React.MouseEventHandler<HTMLButtonElement>;
onConfirmButtonEnter: React.MouseEventHandler<HTMLButtonElement>;
onConfirmButtonLeave: React.MouseEventHandler<HTMLButtonElement>;
onDebugButtonEnter: React.MouseEventHandler<HTMLButtonElement>;
onDebugButtonLeave: React.MouseEventHandler<HTMLButtonElement>;
};
function Overview({
lifecycle,
showDecoding,
decoding,
decodingFallback = "?",
decodingSucceeded,
active,
onBackClick,
onBackEnter,
onBackLeave,
onRejectButtonEnter,
onRejectButtonLeave,
onConfirmButtonEnter,
onConfirmButtonLeave,
onDebugButtonEnter,
onDebugButtonLeave
}: OverviewProps): JSX.Element {
const { method } = lifecycle.message.payload;
const decodingInspected = inspectDecoding(decoding);
const {
state: { chainInfo },
operations: { userConfirmMessage, userRejectMessage, setTxToRun }
} = useDash()!;
const { classes } = useStyles();
const navigate = useNavigate();
const onConfirmButtonClick = () => void userConfirmMessage(lifecycle);
const onRejectButtonClick = () => void userRejectMessage(lifecycle);
const onDebugButtonClick = () => {
setTxToRun(lifecycle);
navigate("/debugger");
};
const debugButtonTooltipMessage =
`Simulate transaction in Ganache and ` + `debug the result.`;
return (
<Stack
onClick={onBackClick}
onMouseEnter={onBackEnter}
onMouseLeave={onBackLeave}
pl={42}
pr={35}
py="lg"
className={`${classes.container} ${
active ? classes.activeContainer : ""
}`}
tabIndex={0}
>
<Stack className={classes.info} align="flex-start" spacing="xs">
<Badge
size="lg"
variant="outline"
color="truffle-beige"
radius="sm"
className={`${classes.methodBadge} ${
active ? classes.activeMethodBadge : ""
}`}
>
{method}
</Badge>
{showDecoding && (
<Text size="xl" className={classes.decoding} lineClamp={1}>
{decodingSucceeded ? decodingInspected : decodingFallback}
</Text>
)}
</Stack>
<Group className={classes.buttonsContainer} position="apart">
<Group>
<Button
size="md"
onClick={onRejectButtonClick}
onMouseEnter={onRejectButtonEnter}
onMouseLeave={onRejectButtonLeave}
className={`${classes.button} ${classes.rejectButton}`}
>
Reject
</Button>
<Button
size="md"
onClick={onConfirmButtonClick}
onMouseEnter={onConfirmButtonEnter}
onMouseLeave={onConfirmButtonLeave}
rightIcon={<ChainIcon chainID={chainInfo.id!} height={16} />}
className={`${classes.button} ${classes.confirmButton}`}
classNames={{ rightIcon: classes.confirmButtonRightIcon }}
>
Confirm
</Button>
</Group>
<Tooltip label={debugButtonTooltipMessage}>
<Button
size="md"
onClick={onDebugButtonClick}
onMouseEnter={onDebugButtonEnter}
onMouseLeave={onDebugButtonLeave}
className={`${classes.button} ${classes.debugButton}`}
>
Debug
</Button>
</Tooltip>
</Group>
</Stack>
);
}
export default Overview;