From 72cb554cafdc0663680e9525c5f45f4f088d1e9e Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Wed, 7 Feb 2024 11:50:23 +0100 Subject: [PATCH 1/4] Prepare component to render signed blocks --- .changelog/1236.trivial.md | 1 + src/app/components/BlockStats/index.tsx | 64 +++++++++++++++++++ .../ValidatorDetailsPage/SignedBlocks.tsx | 47 ++++++++++++++ src/app/pages/ValidatorDetailsPage/index.tsx | 10 +++ src/locales/en/translation.json | 5 ++ 5 files changed, 127 insertions(+) create mode 100644 .changelog/1236.trivial.md create mode 100644 src/app/components/BlockStats/index.tsx create mode 100644 src/app/pages/ValidatorDetailsPage/SignedBlocks.tsx diff --git a/.changelog/1236.trivial.md b/.changelog/1236.trivial.md new file mode 100644 index 000000000..ccf449823 --- /dev/null +++ b/.changelog/1236.trivial.md @@ -0,0 +1 @@ +Validator details cards placeholders diff --git a/src/app/components/BlockStats/index.tsx b/src/app/components/BlockStats/index.tsx new file mode 100644 index 000000000..a2065b415 --- /dev/null +++ b/src/app/components/BlockStats/index.tsx @@ -0,0 +1,64 @@ +import { ReactNode } from 'react' +import Box from '@mui/material/Box' +import Tooltip from '@mui/material/Tooltip' +import { styled } from '@mui/material/styles' +import { COLORS } from '../../../styles/theme/colors' + +const StyledSquare = styled(Box, { + shouldForwardProp: prop => prop !== 'success', +})(({ success }: { success?: boolean }) => { + return { + display: 'flex', + width: '24px', + height: '24px', + borderRadius: '3px', + backgroundColor: success ? COLORS.eucalyptus : COLORS.errorIndicatorBackground, + } +}) + +type BlockStatsProps = { + data: T[] + dataKey: Extract + legendLabels?: { + success: string + fail: string + } + tooltipFormatter?: (data: string) => ReactNode +} + +export const BlockStats = ({ + data, + dataKey, + legendLabels, + tooltipFormatter, +}: BlockStatsProps) => { + const statusKey = Object.keys(data[0]).find(key => key !== dataKey) + if (!statusKey) { + throw new Error('Not able to determine status key') + } + + return ( + <> + + {data.map(item => { + const title = tooltipFormatter ? tooltipFormatter(item[dataKey].toString()) : item[dataKey] + return ( + + + + ) + })} + + {legendLabels && ( + + + {legendLabels.success} + + + {legendLabels.fail} + + + )} + + ) +} diff --git a/src/app/pages/ValidatorDetailsPage/SignedBlocks.tsx b/src/app/pages/ValidatorDetailsPage/SignedBlocks.tsx new file mode 100644 index 000000000..056f44f19 --- /dev/null +++ b/src/app/pages/ValidatorDetailsPage/SignedBlocks.tsx @@ -0,0 +1,47 @@ +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import Card from '@mui/material/Card' +import CardHeader from '@mui/material/CardHeader' +import CardContent from '@mui/material/CardContent' +import Typography from '@mui/material/Typography' +import { COLORS } from 'styles/theme/colors' +import { BlockStats } from '../../components/BlockStats' + +export const SignedBlocks: FC = () => { + const { t } = useTranslation() + // TODO: provide data from the API and sync dataKey value + const data: any[] = [] + const dataKey = '' + + return ( + + + + {data && data.length > 0 && ( + <> + + {t('validator.signedBlocksDescription')} + + t('validator.blockWithHeight', { height: value })} + /> + + )} + + + ) +} diff --git a/src/app/pages/ValidatorDetailsPage/index.tsx b/src/app/pages/ValidatorDetailsPage/index.tsx index b3de8fa84..680d8a44c 100644 --- a/src/app/pages/ValidatorDetailsPage/index.tsx +++ b/src/app/pages/ValidatorDetailsPage/index.tsx @@ -4,6 +4,7 @@ import { useHref, useLoaderData } from 'react-router-dom' import Card from '@mui/material/Card' import CardContent from '@mui/material/CardContent' import Divider from '@mui/material/Divider' +import Grid from '@mui/material/Grid' import { useScreenSize } from '../../hooks/useScreensize' import { Validator, useGetConsensusValidatorsEntityId } from '../../../oasis-nexus/api' import { RouterTabs } from '../../components/RouterTabs' @@ -18,6 +19,7 @@ import { ValidatorTitleCard } from './ValidatorTitleCard' import { useRequiredScopeParam } from 'app/hooks/useScopeParam' import { AddressLoaderData } from 'app/utils/route-utils' import { ValidatorSnapshot } from './ValidatorSnapshot' +import { SignedBlocks } from './SignedBlocks' import { ValidatorDetailsContext } from './hooks' export const ValidatorDetailsPage: FC = () => { @@ -38,6 +40,14 @@ export const ValidatorDetailsPage: FC = () => { + + + <> + + + + + ) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 855c2f9c9..52bd022b1 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -587,6 +587,7 @@ "validator": { "active": "Active", "balanceDistribution": "Balance Distribution", + "blockWithHeight": "Block {{height}}", "boundsNotSet": "No bounds set (0% - 100%)", "change": "Change (24h)", "commission": "Commission", @@ -600,8 +601,12 @@ "groupStatus": "{{status}} validators", "inactive": "Inactive", "listTitle": "Validators", + "missed": "Missed", "nodeId": "Node ID", "participationRate": "Participation Rate", + "signed": "Signed", + "signedBlocks": "Signed Blocks", + "signedBlocksDescription": "Last 100 blocks", "snapshot": "Validator Snapshot", "staked": "Staked", "startDate": "Start Date", From 094669f671cb90cf7a494ee1d37423aecb2ae997 Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Fri, 23 Feb 2024 13:40:57 +0100 Subject: [PATCH 2/4] Prepare staking trend card layout --- .../ValidatorDetailsPage/StakingTrend.tsx | 42 +++++++++++++++++++ src/app/pages/ValidatorDetailsPage/index.tsx | 3 +- src/locales/en/translation.json | 1 + 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/app/pages/ValidatorDetailsPage/StakingTrend.tsx diff --git a/src/app/pages/ValidatorDetailsPage/StakingTrend.tsx b/src/app/pages/ValidatorDetailsPage/StakingTrend.tsx new file mode 100644 index 000000000..3e223a956 --- /dev/null +++ b/src/app/pages/ValidatorDetailsPage/StakingTrend.tsx @@ -0,0 +1,42 @@ +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import Card from '@mui/material/Card' +import CardHeader from '@mui/material/CardHeader' +import CardContent from '@mui/material/CardContent' +import { LineChart } from '../../components/charts/LineChart' +import { SearchScope } from 'types/searchScope' +import { useScreenSize } from '../../hooks/useScreensize' + +export const StakingTrend: FC<{ scope: SearchScope }> = ({ scope }) => { + const { t } = useTranslation() + const { isMobile } = useScreenSize() + // TODO: provide data from the API is ready and sync dataKey value + const windows = undefined + + return ( + + + + {windows && ( + value.toLocaleString(), + label: (value: string) => + t('common.formattedDateTime', { + timestamp: new Date(value), + }), + }} + /> + )} + + + ) +} diff --git a/src/app/pages/ValidatorDetailsPage/index.tsx b/src/app/pages/ValidatorDetailsPage/index.tsx index 680d8a44c..a05c5594d 100644 --- a/src/app/pages/ValidatorDetailsPage/index.tsx +++ b/src/app/pages/ValidatorDetailsPage/index.tsx @@ -20,6 +20,7 @@ import { useRequiredScopeParam } from 'app/hooks/useScopeParam' import { AddressLoaderData } from 'app/utils/route-utils' import { ValidatorSnapshot } from './ValidatorSnapshot' import { SignedBlocks } from './SignedBlocks' +import { StakingTrend } from './StakingTrend' import { ValidatorDetailsContext } from './hooks' export const ValidatorDetailsPage: FC = () => { @@ -42,7 +43,7 @@ export const ValidatorDetailsPage: FC = () => { - <> + diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 52bd022b1..e25cce6c7 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -609,6 +609,7 @@ "signedBlocksDescription": "Last 100 blocks", "snapshot": "Validator Snapshot", "staked": "Staked", + "stakingTrend": "Staking Trend", "startDate": "Start Date", "title": "Validator", "totalShare": "Total Share", From 4a87543c0a879dc3e6f04493263c1c03b64791c9 Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Fri, 23 Feb 2024 13:48:17 +0100 Subject: [PATCH 3/4] Add proposed blocks card placeholder --- .../ValidatorDetailsPage/ProposedBlocks.tsx | 17 +++++++++++++++++ src/app/pages/ValidatorDetailsPage/index.tsx | 2 ++ src/locales/en/translation.json | 1 + 3 files changed, 20 insertions(+) create mode 100644 src/app/pages/ValidatorDetailsPage/ProposedBlocks.tsx diff --git a/src/app/pages/ValidatorDetailsPage/ProposedBlocks.tsx b/src/app/pages/ValidatorDetailsPage/ProposedBlocks.tsx new file mode 100644 index 000000000..c8ddf1e76 --- /dev/null +++ b/src/app/pages/ValidatorDetailsPage/ProposedBlocks.tsx @@ -0,0 +1,17 @@ +import { FC } from 'react' +import { useTranslation } from 'react-i18next' +import Card from '@mui/material/Card' +import CardHeader from '@mui/material/CardHeader' +import CardContent from '@mui/material/CardContent' +import { SearchScope } from 'types/searchScope' + +export const ProposedBlocks: FC<{ scope: SearchScope }> = ({ scope }) => { + const { t } = useTranslation() + + return ( + + + {/* TODO: add proposed block paginated list when API is ready */} + + ) +} diff --git a/src/app/pages/ValidatorDetailsPage/index.tsx b/src/app/pages/ValidatorDetailsPage/index.tsx index a05c5594d..6ff62477c 100644 --- a/src/app/pages/ValidatorDetailsPage/index.tsx +++ b/src/app/pages/ValidatorDetailsPage/index.tsx @@ -21,6 +21,7 @@ import { AddressLoaderData } from 'app/utils/route-utils' import { ValidatorSnapshot } from './ValidatorSnapshot' import { SignedBlocks } from './SignedBlocks' import { StakingTrend } from './StakingTrend' +import { ProposedBlocks } from './ProposedBlocks' import { ValidatorDetailsContext } from './hooks' export const ValidatorDetailsPage: FC = () => { @@ -49,6 +50,7 @@ export const ValidatorDetailsPage: FC = () => { + ) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index e25cce6c7..5b9106258 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -607,6 +607,7 @@ "signed": "Signed", "signedBlocks": "Signed Blocks", "signedBlocksDescription": "Last 100 blocks", + "proposedBlocks": "Proposed Blocks", "snapshot": "Validator Snapshot", "staked": "Staked", "stakingTrend": "Staking Trend", From 6eb3a8c03100b78b8273736961407cb2544065d0 Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Mon, 26 Feb 2024 11:48:32 +0100 Subject: [PATCH 4/4] Keep validator cards height the same --- .../pages/ValidatorDetailsPage/SignedBlocks.tsx | 2 +- .../pages/ValidatorDetailsPage/StakingTrend.tsx | 2 +- src/app/pages/ValidatorDetailsPage/index.tsx | 15 +++++++++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/app/pages/ValidatorDetailsPage/SignedBlocks.tsx b/src/app/pages/ValidatorDetailsPage/SignedBlocks.tsx index 056f44f19..8d456b00f 100644 --- a/src/app/pages/ValidatorDetailsPage/SignedBlocks.tsx +++ b/src/app/pages/ValidatorDetailsPage/SignedBlocks.tsx @@ -14,7 +14,7 @@ export const SignedBlocks: FC = () => { const dataKey = '' return ( - + = ({ scope }) => { const windows = undefined return ( - + {windows && ( diff --git a/src/app/pages/ValidatorDetailsPage/index.tsx b/src/app/pages/ValidatorDetailsPage/index.tsx index 6ff62477c..4fb637c30 100644 --- a/src/app/pages/ValidatorDetailsPage/index.tsx +++ b/src/app/pages/ValidatorDetailsPage/index.tsx @@ -1,4 +1,5 @@ import { FC } from 'react' +import { styled } from '@mui/material/styles' import { useTranslation } from 'react-i18next' import { useHref, useLoaderData } from 'react-router-dom' import Card from '@mui/material/Card' @@ -24,6 +25,12 @@ import { StakingTrend } from './StakingTrend' import { ProposedBlocks } from './ProposedBlocks' import { ValidatorDetailsContext } from './hooks' +export const StyledGrid = styled(Grid)(({ theme }) => ({ + [theme.breakpoints.up('sm')]: { + display: 'flex', + }, +})) + export const ValidatorDetailsPage: FC = () => { const { t } = useTranslation() const { isMobile } = useScreenSize() @@ -43,12 +50,12 @@ export const ValidatorDetailsPage: FC = () => { - + - - + + - +