Skip to content

Commit

Permalink
Merge pull request #149 from topmonks/Chain-dashboard-asset-value-chart
Browse files Browse the repository at this point in the history
Chain dashboard asset value chart
  • Loading branch information
uiii committed May 18, 2023
2 parents cbb7d33 + a0c9892 commit a6d0c28
Show file tree
Hide file tree
Showing 22 changed files with 563 additions and 65 deletions.
3 changes: 1 addition & 2 deletions scripts/update-networks/config/squids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ export const squidUrlTemplates: Record<string, (network: string) => string> = {

export const forceSquidUrl: Record<string, Partial<Record<typeof squidTypes[number], string>>> = {
"kusama": {
"stats": "https://squid.subsquid.io/chain-analytics-squid/v/kusama-multi-parallel-2-0/graphql",
"main-identites": "https://squid.subsquid.io/gs-main-kusama-beta/v/v3/graphql"
},
"polkadot": {
"stats": "https://squid.subsquid.io/chain-analytics-squid/v/polkadot-multi-parallel-2-0/graphql"
"stats": "https://squid.subsquid.io/gs-stats-polkadot/v/v1122/graphql"
}
};
1 change: 1 addition & 0 deletions src/assets/block.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/inflation.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/nominator.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/signed.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/staking-reward.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/validator.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { useCallback, useEffect } from "react";
import { Divider, ListItemIcon, ListItemText, ListSubheader, MenuItem, Select, SelectProps } from "@mui/material";
import { css } from "@emotion/react";

import { useNetworks } from "../../hooks/useNetworks";
import { useNetworkGroups } from "../../hooks/useNetworkGroups";
import { useNetworks } from "../hooks/useNetworks";
import { useNetworkGroups } from "../hooks/useNetworkGroups";

const selectStyle = css`
&.MuiInputBase-root {
Expand Down Expand Up @@ -69,7 +69,7 @@ const NetworkSelect = (props: NetworkSelectProps) => {
>
{networkGroups.map((group, index) => [
index > 0 && <Divider />,
<ListSubheader>
<ListSubheader key={index}>
{group.relayChainNetwork?.displayName || "Other"}
{group.relayChainNetwork && <span> and parachains</span>}
</ListSubheader>,
Expand Down
2 changes: 1 addition & 1 deletion src/components/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Button, FormGroup, TextField } from "@mui/material";
import SearchIcon from "@mui/icons-material/Search";
import { css, Theme } from "@emotion/react";

import NetworkSelect from "./network-select/NetworkSelect";
import NetworkSelect from "./NetworkSelect";

const formGroupStyle = css`
flex-direction: row;
Expand Down
58 changes: 29 additions & 29 deletions src/components/account/AccountPortfolio.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @jsxImportSource @emotion/react */
import { HTMLAttributes, useMemo, useState } from "react";
import { ToggleButton, ToggleButtonGroup } from "@mui/material";
import { css, Theme } from "@emotion/react";
import { Theme, css } from "@emotion/react";

import { AccountBalance } from "../../model/accountBalance";
import { Resource } from "../../model/resource";
Expand All @@ -15,29 +15,9 @@ import NotFound from "../NotFound";

import { AccountPortfolioChartMode, AccountPortfolioChart } from "./AccountPortfolioChart";

const switchStyle = (theme: Theme) => css`
position: absolute;
top: 48px;
right: 48px;
margin: 4px 0;
.MuiToggleButton-root {
padding: 0 10px;
font-size: 14px;
}
${theme.breakpoints.down("md")} {
top: 24px;
right: 24px;
}
${theme.breakpoints.down("sm")} {
position: relative;
top: -28px;
right: auto;
display: flex;
justify-content: center;
}
const chartStyle = css`
margin: 0 auto;
margin-top: 32px;
`;

const valuesStyle = (theme: Theme) => css`
Expand Down Expand Up @@ -78,16 +58,37 @@ const separatorStyle = css`
background-color: rgba(0, 0, 0, .125);
`;

const chartStyle = css`
margin: 0 auto;
margin-top: 32px;
`;

const notFoundStyle = css`
margin: 0 auto;
max-width: 300px;
`;

const switchStyle = (theme: Theme) => css`
position: absolute;
top: 48px;
right: 48px;
margin: 4px 0;
.MuiToggleButton-root {
padding: 0 10px;
font-size: 14px;
}
${theme.breakpoints.down("md")} {
top: 24px;
right: 24px;
}
${theme.breakpoints.down("sm")} {
position: relative;
top: -28px;
right: auto;
display: flex;
justify-content: center;
}
`;

export type AccountPortfolioProps = HTMLAttributes<HTMLDivElement> & {
balances: Resource<AccountBalance[]>;
usdRates: Resource<UsdRates>;
Expand Down Expand Up @@ -149,7 +150,6 @@ export const AccountPortfolio = (props: AccountPortfolioProps) => {
<div css={valueTypeStyle}>Reserved</div>
<div>{formatCurrency(stats.reserved, "USD", {decimalPlaces: "optimal"})}</div>
</div>
<div css={separatorStyle} />
</div>
<AccountPortfolioChart
css={chartStyle}
Expand Down
128 changes: 128 additions & 0 deletions src/components/network/NetworkStats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";

import Block from "../../assets/block.svg";
import Signed from "../../assets/signed.svg";
import Nominator from "../../assets/nominator.svg";
import Validator from "../../assets/validator.svg";
import Inflation from "../../assets/inflation.svg";
import StakingReward from "../../assets/staking-reward.svg";

import { Resource } from "../../model/resource";
import { Stats } from "../../model/stats";
import { getNetwork } from "../../services/networksService";

import { ErrorMessage } from "../ErrorMessage";
import Loading from "../Loading";
import NotFound from "../NotFound";

const statStyle = css`
min-width: 100px;
width: 100%;
display: flex;
align-items: center;
`;

const statIconStyle = css`
width: 44px;
height: 44px;
margin-right: 10px;
padding: 10px;
`;

const statTitleStyle = css`
font-weight: 900;
margin-top: auto;
`;

const statValueStyle = css`
font-weight: 500;
height: 32px;
`;

const statsLayoutStyle = css`
display: grid;
width: 100%;
height: auto;
gap: 10px;
grid-template-columns: repeat(2, auto);
@media (max-width: 530px) {
grid-template-columns: repeat(1, auto);
}
`;

type StatItemProps = {
title: string;
icon?: string;
value?: string | number;
};

const StatItem = (props: StatItemProps) => {
const {
title,
value,
icon,
} = props;

return (
<div css={statStyle}>
<img css={statIconStyle} src={icon} />
<div style={{display: "flex", flexDirection: "column", justifyContent: "center" }}>
<div css={statTitleStyle}>{title}</div>
<div css={statValueStyle}>{value}</div>
</div>
</div>
);
};

export type NetworkInfoTableProps = {
stats: Resource<Stats>;
networkName: string;
}

export const NetworkStats = (props: NetworkInfoTableProps) => {
const { stats, networkName } = props;

const network = getNetwork(networkName);

if (stats.loading) {
return <Loading />;
}

if (stats.notFound) {
return <NotFound>Stats not found.</NotFound>;
}

if (stats.error) {
return (
<ErrorMessage
message="Unexpected error occured while fetching data"
details={stats.error.message}
showReported
/>
);
}

if (!stats.data || !network) {
return null;
}

return (
<div css={statsLayoutStyle}>
<StatItem title="Finalized blocks" value={stats.data.chainFinalizedBlocks} icon={Block} />
<StatItem title="Signed extrinsics" value={stats.data.chainSignedExtrinsics} icon={Signed} />
<StatItem title="Staking inflation" value={`${stats.data.stakingInflationRatio.toFixed(1)}%`} icon={Inflation} />
<StatItem title="Staking rewards" value={`${stats.data.stakingRewardsRatio.toFixed(1)}%`} icon={StakingReward} />
<StatItem
title="Validators"
value={`${stats.data.stakingActiveValidatorsAmount}/${stats.data.stakingValidatorsIdealAmount}`}
icon={Validator}
/>
<StatItem title="Nomination pools" value={`${stats.data.nominationPoolsPoolsActiveAmount}`} icon={Nominator} />
</div>
);
};
91 changes: 91 additions & 0 deletions src/components/network/NetworkTokenDistribution.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/** @jsxImportSource @emotion/react */
import { HTMLAttributes } from "react";
import { css } from "@emotion/react";

import { Resource } from "../../model/resource";
import { Stats } from "../../model/stats";
import { Network } from "../../model/network";
import { formatNumber } from "../../utils/number";

import { ErrorMessage } from "../ErrorMessage";
import Loading from "../Loading";
import NotFound from "../NotFound";

import { NetworkTokenDistributionChart } from "./NetworkTokenDistributionChart";

export const valueStyle = css`
min-width: 70px;
display: flex;
max-width: 230px;
margin: 0 auto;
`;

export const valueTypeStyle = css`
margin-bottom: 8px;
font-weight: 700;
flex: 1 1 auto;
`;

export const separatorStyle = css`
display: block;
width: 1px;
flex: 0 0 auto;
background-color: rgba(0, 0, 0, .125);
`;

export const notFoundStyle = css`
margin: 0 auto;
margin-top: 32px;
`;

export const chartStyle = css`
margin: 0 auto;
margin-top: 32px;
`;

export type NetworkTokenDistributionProps = HTMLAttributes<HTMLDivElement> & {
stats: Resource<Stats>;
network: Network;
};

export const NetworkTokenDistribution = (props: NetworkTokenDistributionProps) => {
const {stats, network} = props;

if (stats.loading) {
return <Loading />;
}

if (stats.notFound) {
return <NotFound css={notFoundStyle}>No stats data found</NotFound>;
}

if (stats.error) {
return (
<ErrorMessage
message="Unexpected error occured while fetching data"
details={stats.error.message}
showReported
/>
);
}

if (!stats.data) {
return null;
}

return (
<div>
<div>
<div css={valueStyle}>
<div css={valueTypeStyle}>Total issuance</div>
<div>{formatNumber(stats.data.balancesTotalIssuance, {compact: true})}</div>
</div>
</div>
<NetworkTokenDistributionChart
css={chartStyle}
stats={stats.data}
network={network}
/>
</div>
);
};
Loading

0 comments on commit a6d0c28

Please sign in to comment.