feat(wallet-bonding): node settings wip

This commit is contained in:
pierre
2022-06-24 12:19:25 +02:00
committed by fmtabbara
parent 79bc2ab493
commit 76a22035be
10 changed files with 234 additions and 29 deletions
@@ -36,7 +36,7 @@ export const CopyToClipboard = ({ text = '', iconButton }: { text?: string; icon
color: 'text.primary',
}}
>
{!copied ? <ContentCopy fontSize="small" /> : <Check color="success" />}
{!copied ? <ContentCopy sx={{ fontSize: 14 }} /> : <Check color="success" sx={{ fontSize: 14 }} />}
</IconButton>
</Tooltip>
);
+23 -12
View File
@@ -1,4 +1,4 @@
import { MajorCurrencyAmount, TransactionExecuteResult } from '@nymproject/types';
import { MajorCurrencyAmount, MixnodeStatus, TransactionExecuteResult } from '@nymproject/types';
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import type { Network } from 'src/types';
import { TBondGatewayArgs, TBondMixNodeArgs } from 'src/types';
@@ -11,6 +11,26 @@ import {
unbondMixNode as unbondMixNodeRequest,
} from '../requests';
/* const bounded: BondedMixnode = {
bond: { denom: 'NYM', amount: '1234' },
key: 'B2Xx4haarLWMajX8w259oHjtRZsC7nHwagbWrJNiA3QC',
delegators: 123,
ip: '1.2.34.5',
nodeRewards: { denom: 'NYM', amount: '123' },
operatorRewards: { denom: 'NYM', amount: '12' },
profitMargin: 10,
stake: { denom: 'NYM', amount: '99' },
stakeSaturation: 99,
status: 'active',
}; */
const bounded: BondedMixnode | BondedGateway = {
bond: { denom: 'NYM', amount: '1234' },
key: 'B2Xx4haarLWMajX8w259oHjtRZsC7nHwagbWrJNiA3QC',
ip: '1.2.34.5',
location: 'France',
};
// TODO temporary type for bonded mixnode data
export interface BondedMixnode {
key: string;
@@ -22,6 +42,7 @@ export interface BondedMixnode {
nodeRewards: MajorCurrencyAmount;
operatorRewards: MajorCurrencyAmount;
delegators: number;
status: MixnodeStatus;
}
// TODO temporary type for bonded gateway data
@@ -89,17 +110,6 @@ export const BondingContextProvider = ({
};
const refresh = useCallback(async () => {
const bounded: BondedMixnode = {
bond: { denom: 'NYM', amount: '1234' },
key: 'B2Xx4haarLWMajX8w259oHjtRZsC7nHwagbWrJNiA3QC',
delegators: 123,
ip: '1.2.34.5',
nodeRewards: { denom: 'NYM', amount: '123' },
operatorRewards: { denom: 'NYM', amount: '12' },
profitMargin: 10,
stake: { denom: 'NYM', amount: '99' },
stakeSaturation: 99,
};
// TODO fetch bondedMixnode and bondedGatway via tauri dedicated requests
/* try {
bounded = await fetchBondingData();
@@ -192,6 +202,7 @@ export const BondingContextProvider = ({
error,
bondMixnode,
bondedMixnode,
bondedGateway,
bondGateway,
unbondMixnode,
unbondGateway,
+1
View File
@@ -16,6 +16,7 @@ const bondedMixnodeMock: BondedMixnode = {
nodeRewards: { denom: 'NYM', amount: '1234' },
operatorRewards: { denom: 'NYM', amount: '1234' },
delegators: 5423,
status: 'active',
};
const bondedGatewayMock: BondedGateway = {
@@ -0,0 +1,86 @@
import * as React from 'react';
import { Card, CardContent, CardHeader, Stack, Typography } from '@mui/material';
import { MixnodeStatus } from '@nymproject/types';
import { CheckCircleOutline, CircleOutlined, PauseCircleOutlined } from '@mui/icons-material';
import { CopyToClipboard } from '../../components';
import { splice } from '../../utils';
interface Props {
children?: React.ReactNode;
title: string;
identityKey: string;
status?: MixnodeStatus;
action?: React.ReactNode;
}
const IdentityKey = ({ identityKey }: { identityKey: string }) => (
<Typography variant="body2" component="span" fontWeight={400} sx={{ mr: 1, color: 'text.primary' }}>
{splice(6, identityKey)}
<CopyToClipboard text={identityKey} iconButton />
</Typography>
);
export const getNodeStatus = ({ status }: { status: MixnodeStatus }) => {
switch (status) {
case 'active':
return (
<Typography display="flex" alignItems="center" sx={{ color: 'success.main' }}>
<CheckCircleOutline color="success" sx={{ mr: 0.5, fontSize: 13 }} /> Active
</Typography>
);
case 'standby':
return (
<Typography display="flex" alignItems="center" sx={{ color: 'info.main' }}>
<PauseCircleOutlined color="info" sx={{ mr: 0.5, fontSize: 13 }} /> Standby
</Typography>
);
case 'inactive':
return (
<Typography display="flex" alignItems="center" sx={{ color: 'nym.text.dark' }}>
<CircleOutlined sx={{ mr: 0.5, color: 'nym.text.dark', fontSize: 13 }} /> Inactive
</Typography>
);
case 'not_found':
return (
<Typography display="flex" alignItems="center" sx={{ color: 'nym.text.dark' }}>
<CircleOutlined sx={{ mr: 0.5, color: 'nym.text.dark', fontSize: 13 }} /> Not found
</Typography>
);
default:
return null;
}
};
const BondedNodeCard = (props: Props) => {
const { title: rawTitle, identityKey, status: rawStatus, action, children } = props;
let title: string | React.ReactNode = (
<Typography fontSize={20} fontWeight={600}>
{rawTitle}
</Typography>
);
if (rawStatus) {
title = (
<Stack direction="row" spacing={1.2} alignItems="center">
<Typography fontSize={20} fontWeight={600}>
{rawTitle}
</Typography>
{getNodeStatus({ status: rawStatus })}
</Stack>
);
}
return (
<Card variant="outlined" sx={{ overflow: 'auto', border: 'none', dropShadow: 'none' }}>
<CardHeader
title={title}
subheader={<IdentityKey identityKey={identityKey} />}
action={action}
disableTypography
sx={{ pb: 0 }}
/>
<CardContent sx={{ p: 3 }}>{children}</CardContent>
</Card>
);
};
export default BondedNodeCard;
+59 -9
View File
@@ -1,11 +1,61 @@
import React from 'react';
import { Grid } from '@mui/material';
import React, { useMemo } from 'react';
import { IconButton } from '@mui/material';
import { MoreVert } from '@mui/icons-material';
import { useTheme } from '@mui/material/styles';
import { NymCard } from '../../components';
import { BondedGateway } from '../../context';
import { Cell, Header, NodeTable } from './NodeTable';
import BondedNodeCard from './BondedNodeCard';
import { bondGateway } from '../../requests';
export const GatewayCard = () => (
<NymCard title="Balance">
<Grid container direction="column" spacing={2}>
<Grid item>bonded gateway data table</Grid>
</Grid>
</NymCard>
);
const headers: Header[] = [
{
header: 'IP',
id: 'ip-header',
sx: { pl: 0 },
},
{
header: 'Bond',
id: 'bond-header',
},
{
id: 'menu-button',
size: 'small',
sx: { pr: 0 },
},
];
export const GatewayCard = ({ gateway }: { gateway: BondedGateway }) => {
const { ip, bond } = gateway;
const theme = useTheme();
const cells: Cell[] = useMemo(
() => [
{
cell: ip,
id: 'ip-cell',
sx: { pl: 0 },
},
{
cell: `${bond.amount} ${bond.denom}`,
id: 'bond-cell',
},
{
cell: (
<IconButton sx={{ fontSize: '1rem', padding: 0 }}>
<MoreVert fontSize="inherit" sx={{ color: 'text.primary' }} />
</IconButton>
),
id: 'menu-button-cell',
align: 'center',
size: 'small',
sx: { pr: 0 },
},
],
[gateway, theme],
);
return (
<BondedNodeCard title="Valhalla gateway" identityKey={gateway.key}>
<NodeTable headers={headers} cells={cells} />
</BondedNodeCard>
);
};
+28 -5
View File
@@ -1,10 +1,12 @@
import React, { useMemo } from 'react';
import { IconButton, Typography } from '@mui/material';
import { Button, IconButton, Typography } from '@mui/material';
import { MoreVert } from '@mui/icons-material';
import { useTheme } from '@mui/material/styles';
import { Link } from '@nymproject/react/link/Link';
import { NymCard } from '../../components';
import { BondedMixnode } from '../../context';
import { Node as NodeIcon } from '../../svg-icons/node';
import { Cell, Header, NodeTable } from './NodeTable';
import BondedNodeCard from './BondedNodeCard';
const headers: Header[] = [
{
@@ -51,6 +53,7 @@ const headers: Header[] = [
export const MixnodeCard = ({ mixnode }: { mixnode: BondedMixnode }) => {
const { stake, bond, stakeSaturation, profitMargin, nodeRewards, operatorRewards, delegators } = mixnode;
const theme = useTheme();
const cells: Cell[] = useMemo(
() => [
{
@@ -65,6 +68,7 @@ export const MixnodeCard = ({ mixnode }: { mixnode: BondedMixnode }) => {
{
cell: `${stakeSaturation}%`,
id: 'stake-saturation-cell',
color: stakeSaturation > 100 ? theme.palette.nym.nymWallet.selectionChance.underModerate : undefined,
},
{
cell: `${profitMargin}%`,
@@ -94,10 +98,29 @@ export const MixnodeCard = ({ mixnode }: { mixnode: BondedMixnode }) => {
sx: { pr: 0 },
},
],
[mixnode],
[mixnode, theme],
);
return (
<NymCard title="Monster node">
<BondedNodeCard
title="Monster node"
identityKey={mixnode.key}
status={mixnode.status}
action={
<Button
variant="text"
color="secondary"
sx={{
fontWeight: 500,
'& .MuiSvgIcon-root': {
fontSize: 14,
},
}}
startIcon={<NodeIcon />}
>
Node settings
</Button>
}
>
<NodeTable headers={headers} cells={cells} />
<Typography sx={{ mt: 2 }}>
Check more stats of your node on the{' '}
@@ -105,6 +128,6 @@ export const MixnodeCard = ({ mixnode }: { mixnode: BondedMixnode }) => {
explorer
</Link>
</Typography>
</NymCard>
</BondedNodeCard>
);
};
+2 -2
View File
@@ -25,7 +25,7 @@ export interface TableCell {
export type TableHeader = TableCell & { tooltip?: React.ReactNode };
const CellHeader = ({ children, tooltip, sx, size, align, color }: TableHeader) => (
<MUITableCell sx={{ py: 1.2, ...sx }} size={size} align={align} color={color}>
<MUITableCell sx={{ py: 1.2, color, ...sx }} size={size} align={align}>
{tooltip ? (
<Tooltip title={tooltip} arrow placement="top-start">
<Stack direction="row" alignItems="center" fontSize="0.8rem">
@@ -40,7 +40,7 @@ const CellHeader = ({ children, tooltip, sx, size, align, color }: TableHeader)
);
const CellValue = ({ children, align, size, color, sx }: TableCell) => (
<MUITableCell component="th" scope="row" sx={{ py: 1, ...sx }} align={align} size={size} color={color}>
<MUITableCell component="th" scope="row" sx={{ py: 1, color, ...sx }} align={align} size={size}>
{children}
</MUITableCell>
);
+1
View File
@@ -27,6 +27,7 @@ const Bonding = () => {
<PageLayout>
<Box display="flex" flexDirection="column" gap={2}>
{bondedMixnode && <MixnodeCard mixnode={bondedMixnode} />}
{bondedGateway && <GatewayCard gateway={bondedGateway} />}
</Box>
</PageLayout>
);
+11
View File
@@ -64,6 +64,17 @@ declare module '@mui/material/styles' {
nav: {
background: string;
};
mixnodes: {
status: {
active: string;
standby: string;
};
};
selectionChance: {
overModerate: string;
moderate: string;
underModerate: string;
};
}
/**
+22
View File
@@ -56,6 +56,17 @@ const darkMode: NymPaletteVariant = {
nav: {
background: '#292E34',
},
mixnodes: {
status: {
active: '#20D073',
standby: '#5FD7EF',
},
},
selectionChance: {
overModerate: '#20D073',
moderate: '#EBA53D',
underModerate: '#DA465B',
},
};
const lightMode: NymPaletteVariant = {
@@ -80,6 +91,17 @@ const lightMode: NymPaletteVariant = {
nav: {
background: '#FFFFFF',
},
mixnodes: {
status: {
active: '#1CBB67',
standby: '#55C1D7',
},
},
selectionChance: {
overModerate: '#20D073',
moderate: '#EBA53D',
underModerate: '#DA465B',
},
};
/**