From 970491b83e8fb986cd44083b969a2f3b87c9a2ef Mon Sep 17 00:00:00 2001 From: rafael Date: Wed, 19 Jun 2024 12:02:18 +0200 Subject: [PATCH 01/32] allow bigger legends for GeoDonut --- src/library/Graphs/GeoDonut.tsx | 3 ++- src/library/Graphs/types.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/library/Graphs/GeoDonut.tsx b/src/library/Graphs/GeoDonut.tsx index 74bb3bc544..9dd92f55ef 100644 --- a/src/library/Graphs/GeoDonut.tsx +++ b/src/library/Graphs/GeoDonut.tsx @@ -18,6 +18,7 @@ export const GeoDonut = ({ series = { labels: [], data: [] }, height = 'auto', width = 'auto', + legendHeight = 25 }: GeoDonutProps) => { const { mode } = useTheme(); const { colors } = useNetwork().networkData; @@ -46,7 +47,7 @@ export const GeoDonut = ({ legend: { display: true, position: 'bottom' as const, - maxHeight: 25, + maxHeight: legendHeight, labels: { boxWidth: 10, generateLabels: (chart: AnyJson) => { diff --git a/src/library/Graphs/types.ts b/src/library/Graphs/types.ts index 3dc394f8c8..f8cdd9d114 100644 --- a/src/library/Graphs/types.ts +++ b/src/library/Graphs/types.ts @@ -51,4 +51,5 @@ export interface GeoDonutProps { series: AnyPolkawatch; width?: string | number; height?: string | number; + legendHeight?: number; } From c1833fa7323c4558aa448b80dacbed8beb6b5c3a Mon Sep 17 00:00:00 2001 From: rafael Date: Wed, 19 Jun 2024 12:09:55 +0200 Subject: [PATCH 02/32] Created Nomination Decentralization section --- src/config/pages.ts | 9 + src/locale/en/base.json | 1 + src/locale/en/pages.json | 7 + .../NominationGeoList/context.tsx | 39 ++++ .../NominationGeo/NominationGeoList/index.tsx | 119 +++++++++++ .../NominationGeo/Stats/AnalyzedDays.tsx | 18 ++ .../NominationGeo/Stats/AnalyzedEras.tsx | 21 ++ .../NominationGeo/Stats/AnalyzedPayouts.tsx | 28 +++ src/pages/NominationGeo/Wrappers.ts | 95 +++++++++ src/pages/NominationGeo/index.tsx | 188 ++++++++++++++++++ src/pages/NominationGeo/types.ts | 29 +++ 11 files changed, 554 insertions(+) create mode 100644 src/pages/NominationGeo/NominationGeoList/context.tsx create mode 100644 src/pages/NominationGeo/NominationGeoList/index.tsx create mode 100644 src/pages/NominationGeo/Stats/AnalyzedDays.tsx create mode 100644 src/pages/NominationGeo/Stats/AnalyzedEras.tsx create mode 100644 src/pages/NominationGeo/Stats/AnalyzedPayouts.tsx create mode 100644 src/pages/NominationGeo/Wrappers.ts create mode 100644 src/pages/NominationGeo/index.tsx create mode 100644 src/pages/NominationGeo/types.ts diff --git a/src/config/pages.ts b/src/config/pages.ts index 92b76cd0f5..98f84344a4 100644 --- a/src/config/pages.ts +++ b/src/config/pages.ts @@ -5,6 +5,7 @@ import { Community } from 'pages/Community'; import { Nominate } from 'pages/Nominate'; import { Overview } from 'pages/Overview'; import { Payouts } from 'pages/Payouts'; +import { NominationGeo } from 'pages/NominationGeo'; import { Pools } from 'pages/Pools'; import { Validators } from 'pages/Validators'; import type { PageCategoryItems, PagesConfigItems } from 'types'; @@ -58,6 +59,14 @@ export const PagesConfig: PagesConfigItems = [ Entry: Payouts, lottie: 'analytics', }, + { + category: 2, + key: 'decentralization', + uri: `${BASE_URL}decentralization`, + hash: '/decentralization', + Entry: NominationGeo, + lottie: 'globe', + }, { category: 3, key: 'validators', diff --git a/src/locale/en/base.json b/src/locale/en/base.json index a0e4adb22a..4e3ab1243d 100644 --- a/src/locale/en/base.json +++ b/src/locale/en/base.json @@ -2,6 +2,7 @@ "base": { "active": "Active", "community": "Community", + "decentralization": "Decentralization", "goTo": "Go To", "help": "Help", "inactive": "Inactive", diff --git a/src/locale/en/pages.json b/src/locale/en/pages.json index 211f72d6ca..0b557657a6 100644 --- a/src/locale/en/pages.json +++ b/src/locale/en/pages.json @@ -121,6 +121,13 @@ "slashed": "Slashed", "subscanDisabled": "Subscan Disabled" }, + "decentralization": { + "howDecentralizedIsYourNomination": "How decentralized is your Nomination?", + "totalPayoutsAnalysed": "Total Payouts Analysed", + "maxErasAnalyzed": "Max Eras Analysed", + "PayoutDistribution": "Payout Distribution", + "byRegionCountryNetwork": "by Region, Country and Network" + }, "pools": { "activePools": "Active Pools", "address": "Address", diff --git a/src/pages/NominationGeo/NominationGeoList/context.tsx b/src/pages/NominationGeo/NominationGeoList/context.tsx new file mode 100644 index 0000000000..b4d81550fc --- /dev/null +++ b/src/pages/NominationGeo/NominationGeoList/context.tsx @@ -0,0 +1,39 @@ +// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import type { ReactNode } from 'react'; +import { createContext, useContext, useState } from 'react'; +import type { NominationGeoListContextInterface } from '../types'; +import type { ListFormat } from 'library/PoolList/types'; + +export const NominationGeoListContext = + createContext({ + // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars + setListFormat: (v: ListFormat) => {}, + listFormat: 'col', + }); + +export const useNominationGeoList = () => useContext(NominationGeoListContext); + +export const NominationGeoListProvider = ({ + children, +}: { + children: ReactNode; +}) => { + const [listFormat, _setListFormat] = useState('col'); + + const setListFormat = (v: ListFormat) => { + _setListFormat(v); + }; + + return ( + + {children} + + ); +}; diff --git a/src/pages/NominationGeo/NominationGeoList/index.tsx b/src/pages/NominationGeo/NominationGeoList/index.tsx new file mode 100644 index 0000000000..5f86837efb --- /dev/null +++ b/src/pages/NominationGeo/NominationGeoList/index.tsx @@ -0,0 +1,119 @@ +// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import { faBars, faGripVertical } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { motion } from 'framer-motion'; +//import { useTranslation } from 'react-i18next'; +import { useTheme } from 'contexts/Themes'; +import { Header, List, Wrapper as ListWrapper } from 'library/List'; +import { MotionContainer } from 'library/List/MotionContainer'; +import { Identity } from 'library/ListItem/Labels/Identity'; +import { ItemWrapper } from '../Wrappers'; +import type { NomninationGeoListProps } from '../types'; +import { NominationGeoListProvider, useNominationGeoList } from './context'; +import { useNetwork } from 'contexts/Network'; +//import { useValidators } from 'contexts/Validators/ValidatorEntries'; + +export const NominationGeoList = (props: NomninationGeoListProps) => ( + + + +); + +export const NominationGeoListInner = ({ + allowMoreCols, + title, + data, +}: NomninationGeoListProps) => { + //const { i18n, t } = useTranslation('pages'); + const { mode } = useTheme(); + const { + networkData: { colors }, + } = useNetwork(); + const { listFormat, setListFormat } = useNominationGeoList(); + //const { validators } = useValidators(); + + if (!data?.nodeDistributionDetail) { + return null; + } + + let totalRewards = data.nodeDistributionDetail.reduce((acc,n,i)=>acc+n.TokenRewards, 0); + + return ( + +
+
+

{title}

+
+
+ + +
+
+ + + {data.nodeDistributionDetail + .sort((a, b) => b.TokenRewards - a.TokenRewards) + .map((n, index: number) => { + const labelClass = 'reward'; + + return ( + + +
+
+
+
+

+ <> +

{n.LastNetwork}, {n.LastCountry}, {n.LastRegion} {n.Countries+n.Regions > 2 ? '++.':'.'}

+ +

+
+
+
+
+
+
+
+ +
+
+
{Math.round((n.TokenRewards / totalRewards) * 1000)/10} %
+
+
+
+
+ + + ); + })} + + + + ); +}; diff --git a/src/pages/NominationGeo/Stats/AnalyzedDays.tsx b/src/pages/NominationGeo/Stats/AnalyzedDays.tsx new file mode 100644 index 0000000000..0f474d2a3a --- /dev/null +++ b/src/pages/NominationGeo/Stats/AnalyzedDays.tsx @@ -0,0 +1,18 @@ +// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import { Number } from 'library/StatBoxList/Number'; +import { useTranslation } from 'react-i18next'; + +// We simply report the number of days used to analyse the nomination, currently is fixed to 30 + +export const AnalyzedDays = () => { + const { t } = useTranslation('pages'); + const params = { + label: t('decentralization.maxErasAnalyzed'), + value: 30, + unit: 'Days', + helpKey: 'Max Days Analysed', + }; + return ; +}; diff --git a/src/pages/NominationGeo/Stats/AnalyzedEras.tsx b/src/pages/NominationGeo/Stats/AnalyzedEras.tsx new file mode 100644 index 0000000000..74362ff2e4 --- /dev/null +++ b/src/pages/NominationGeo/Stats/AnalyzedEras.tsx @@ -0,0 +1,21 @@ +// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import { Number } from 'library/StatBoxList/Number'; +import { useTranslation } from 'react-i18next'; + +import type { AnalyzedErasProps } from '../types'; + +// We currently analyse the number of eras in the last 30 days/month. + +export const AnalyzedEras = ({ meta }: AnalyzedErasProps) => { + const { t } = useTranslation('pages'); + + const params = { + label: t('decentralization.maxErasAnalyzed'), + value: meta?.ErasPerMonth || 0, + unit: 'Eras', + helpKey: 'Max Eras Analysed', + }; + return ; +}; diff --git a/src/pages/NominationGeo/Stats/AnalyzedPayouts.tsx b/src/pages/NominationGeo/Stats/AnalyzedPayouts.tsx new file mode 100644 index 0000000000..020320b099 --- /dev/null +++ b/src/pages/NominationGeo/Stats/AnalyzedPayouts.tsx @@ -0,0 +1,28 @@ +// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import { Number } from 'library/StatBoxList/Number'; +import { useNetwork } from 'contexts/Network'; +import { useTranslation } from 'react-i18next'; + +import type { AnalyzedPayoutsProps } from '../types'; + +// We simply report the size of payouts that have been analyzed for decentralization purpose + +export const AnalyzedPayouts = ({ data }: AnalyzedPayoutsProps) => { + const { t } = useTranslation('pages'); + const { unit } = useNetwork().networkData; + + const params = { + label: t('decentralization.totalPayoutsAnalysed'), + value: + data?.nodeDistributionDetail?.reduce( + (acc, node) => acc + node.TokenRewards, + 0 + ) || 0, + decimals: 1, + unit, + helpKey: 'Total Payouts Analysed', + }; + return ; +}; diff --git a/src/pages/NominationGeo/Wrappers.ts b/src/pages/NominationGeo/Wrappers.ts new file mode 100644 index 0000000000..fa141972a3 --- /dev/null +++ b/src/pages/NominationGeo/Wrappers.ts @@ -0,0 +1,95 @@ +// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import { motion } from 'framer-motion'; +import styled from 'styled-components'; + +export const ItemWrapper = styled(motion.div)` + padding: 0.5rem; + width: 100%; + + > .inner { + background: var(--background-list-item); + padding: 0 0.75rem; + flex: 1; + border-radius: 1rem; + display: flex; + flex-flow: column wrap; + align-items: center; + flex: 1; + max-width: 100%; + + > .row { + width: 100%; + display: flex; + flex-flow: row wrap; + align-items: center; + + &:first-child { + padding: 1rem 0 0.75rem 0; + } + + &:last-child { + border-top: 1px solid var(--border-primary-color); + padding-top: 0rem; + + > div { + min-height: 3.2rem; + } + } + + > div { + display: flex; + flex-flow: row wrap; + align-items: center; + flex: 1; + max-width: 100%; + + h4 { + color: var(--text-color-secondary); + font-family: InterSemiBold, sans-serif; + &.claim { + color: var(--accent-color-secondary); + } + &.reward { + color: var(--accent-color-primary); + } + } + + h5 { + color: var(--text-color-secondary); + &.claim { + color: var(--accent-color-secondary); + border: 1px solid var(--accent-color-secondary); + border-radius: 0.75rem; + padding: 0.2rem 0.5rem; + } + &.reward { + color: var(--accent-color-primary); + border: 1px solid var(--accent-color-primary); + border-radius: 0.75rem; + padding: 0.2rem 0.5rem; + } + } + + > div:first-child { + flex-grow: 1; + display: flex; + flex-flow: row wrap; + align-items: center; + } + + > div:last-child { + display: flex; + flex-flow: row wrap; + justify-content: flex-end; + + > h4 { + color: var(--text-color-secondary); + opacity: 0.8; + } + } + } + } + } +`; diff --git a/src/pages/NominationGeo/index.tsx b/src/pages/NominationGeo/index.tsx new file mode 100644 index 0000000000..8025712be4 --- /dev/null +++ b/src/pages/NominationGeo/index.tsx @@ -0,0 +1,188 @@ +// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import { useTranslation } from 'react-i18next'; +import type { PageProps } from 'types'; +import { PageTitle } from 'kits/Structure/PageTitle'; +import { StatBoxList } from 'library/StatBoxList'; +import { useNetwork } from 'contexts/Network'; +import { useEffect, useState } from 'react'; + +import { usePlugins } from 'contexts/Plugins'; +import { useActiveAccounts } from 'contexts/ActiveAccounts'; + +import type { NominatorDetail, ChainMetadata } from './types'; +import { PolkawatchApi } from '@polkawatch/ddp-client'; +import { PolkaWatchController } from 'controllers/PolkaWatchController'; + +import { AnalyzedPayouts } from './Stats/AnalyzedPayouts'; +import { AnalyzedDays } from './Stats/AnalyzedDays'; +import { AnalyzedEras } from './Stats/AnalyzedEras'; + + +import { PageRow } from 'kits/Structure/PageRow'; +import { PageHeadingWrapper } from 'kits/Structure/PageHeading/Wrapper'; +import { CardHeaderWrapper, CardWrapper } from 'library/Card/Wrappers'; +import { PluginLabel } from 'library/PluginLabel'; +//import { RowSection } from 'kits/Structure/RowSection'; +import { GraphWrapper } from 'library/Graphs/Wrapper'; +import { GeoDonut } from 'library/Graphs/GeoDonut'; +import { ButtonHelp } from 'kits/Buttons/ButtonHelp'; +import { useHelp } from 'contexts/Help'; +import { Separator } from 'kits/Structure/Separator'; +import { NominationGeoList } from './NominationGeoList'; + +export const NominationGeo = ({ page: { key } }: PageProps) => { + const { activeAccount } = useActiveAccounts(); + const { t } = useTranslation(); + const { openHelp } = useHelp(); + const { network } = useNetwork(); + const { pluginEnabled } = usePlugins(); + const enabled = pluginEnabled('polkawatch'); + + // Polkawatch Analytics chain metadata, contains information about how the decentralization is 1 + // computed for this particular blockchain + + const [networkMeta, setNetworkMeta] = useState( + {} as ChainMetadata + ); + + useEffect(() => { + if (networkSupported && enabled) { + const polkaWatchApi = new PolkawatchApi( + PolkaWatchController.apiConfig(network) + ); + polkaWatchApi + .ddpIpfsAboutChain() + .then((response) => { + setAnalyticsAvailable(true); + setNetworkMeta(response.data); + }) + .catch(() => { + setNetworkMeta({} as ChainMetadata); + setAnalyticsAvailable(false); + }); + } else { + setNetworkMeta({} as ChainMetadata); + setAnalyticsAvailable(false); + } + }, [network]); + + const [nominationDetail, setNominationDetail] = useState( + {} as NominatorDetail + ); + + const [, setAnalyticsAvailable] = useState(true); + + const networkSupported = + PolkaWatchController.SUPPORTED_NETWORKS.includes(network); + + // Please note that the list of dependencies assume that changing network + // triggers a change of account also (i.e. different network prefix). + useEffect(() => { + if (networkSupported && enabled) { + const polkaWatchApi = new PolkawatchApi( + PolkaWatchController.apiConfig(network) + ); + polkaWatchApi + .ddpIpfsNominatorDetail({ + lastDays: 30, + nominator: activeAccount, + }) + .then((response) => { + setAnalyticsAvailable(true); + setNominationDetail(response.data); + }) + .catch(() => { + setNominationDetail({} as NominatorDetail); + setAnalyticsAvailable(false); + }); + } else { + setNominationDetail({} as NominatorDetail); + setAnalyticsAvailable(false); + } + }, [activeAccount]); + + return ( + <> + + + +

+ {t('decentralization.howDecentralizedIsYourNomination', { + ns: 'pages', + })} +

+
+
+ + + + + + + + + +

+ {t('decentralization.PayoutDistribution', { ns: 'pages' })} + openHelp('Payout Distribution')} + /> +

+

+ {t('decentralization.byRegionCountryNetwork', { ns: 'pages' })} +

+
+ +
+ + + + + + + + + +
+
+
+ + + + + + + ); +}; diff --git a/src/pages/NominationGeo/types.ts b/src/pages/NominationGeo/types.ts new file mode 100644 index 0000000000..ba8d2e02b5 --- /dev/null +++ b/src/pages/NominationGeo/types.ts @@ -0,0 +1,29 @@ +// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import type { NominatorDetail } from '@polkawatch/ddp-client'; +export type { NominatorDetail } from '@polkawatch/ddp-client'; + +import type { ChainMetadata } from '@polkawatch/ddp-client'; + +export type { ChainMetadata } from '@polkawatch/ddp-client'; + +export interface AnalyzedPayoutsProps { + data?: NominatorDetail; +} + +export interface AnalyzedErasProps { + meta?: ChainMetadata; +} + +export interface NomninationGeoListProps { + allowMoreCols: boolean; + title: string; + data?: NominatorDetail; +} + +import type { ListFormat } from 'library/PoolList/types'; +export interface NominationGeoListContextInterface { + setListFormat: (v: ListFormat) => void; + listFormat: ListFormat; +} \ No newline at end of file From b4b1597eb251badfa4f9c64ae1c8995b68e4f422 Mon Sep 17 00:00:00 2001 From: rafael Date: Thu, 20 Jun 2024 13:22:38 +0200 Subject: [PATCH 03/32] added optional control on GeoDonut labels --- src/library/Graphs/GeoDonut.tsx | 8 ++++++-- src/library/Graphs/types.ts | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/library/Graphs/GeoDonut.tsx b/src/library/Graphs/GeoDonut.tsx index 9dd92f55ef..8d8938bbe7 100644 --- a/src/library/Graphs/GeoDonut.tsx +++ b/src/library/Graphs/GeoDonut.tsx @@ -18,7 +18,8 @@ export const GeoDonut = ({ series = { labels: [], data: [] }, height = 'auto', width = 'auto', - legendHeight = 25 + legendHeight = 25, + maxLabelLen = 3, }: GeoDonutProps) => { const { mode } = useTheme(); const { colors } = useNetwork().networkData; @@ -56,7 +57,10 @@ export const GeoDonut = ({ chart ); return ls.map((l) => { - l.text = ellipsisFn(l.text, undefined, 'end'); + l.text = + maxLabelLen && l.text.length > maxLabelLen + ? ellipsisFn(l.text, maxLabelLen, 'end') + : l.text; return l; }); }, diff --git a/src/library/Graphs/types.ts b/src/library/Graphs/types.ts index f8cdd9d114..48542adae6 100644 --- a/src/library/Graphs/types.ts +++ b/src/library/Graphs/types.ts @@ -52,4 +52,5 @@ export interface GeoDonutProps { width?: string | number; height?: string | number; legendHeight?: number; + maxLabelLen?: number; } From 7e86ddf647bb4f5ef77c6186b34cb06aa31e1c42 Mon Sep 17 00:00:00 2001 From: rafael Date: Thu, 20 Jun 2024 13:23:36 +0200 Subject: [PATCH 04/32] initial version of Nomination Decentralization / GeoNomination page --- src/config/help.ts | 16 ++ src/locale/cn/base.json | 1 + src/locale/cn/help.json | 39 ++++ src/locale/cn/pages.json | 8 + src/locale/en/help.json | 37 +++- src/locale/en/pages.json | 15 +- .../NominationGeo/NominationGeoList/index.tsx | 198 +++++++++++------- .../NominationGeo/Stats/AnalyzedDays.tsx | 14 +- .../NominationGeo/Stats/AnalyzedEras.tsx | 2 +- src/pages/NominationGeo/index.tsx | 11 +- src/pages/NominationGeo/types.ts | 6 +- 11 files changed, 246 insertions(+), 101 deletions(-) diff --git a/src/config/help.ts b/src/config/help.ts index 47fcb30138..c04abbae96 100644 --- a/src/config/help.ts +++ b/src/config/help.ts @@ -114,6 +114,22 @@ export const HelpConfig: HelpItems = [ ], ], }, + { + key: 'decentralization', + definitions: [ + 'Decentralization Analytics Period', + 'Geolocation of Each Nomination', + 'Nomination Payout Distribution', + 'Total Payouts Analysed', + ], + external: [ + [ + 'polkawatchAnalytics', + 'https://blog.polkawatch.app/introducing-polkawatch/', + 'polkawatch.app', + ], + ], + }, { key: 'validators', definitions: [ diff --git a/src/locale/cn/base.json b/src/locale/cn/base.json index 78709a95c0..a170580bf2 100644 --- a/src/locale/cn/base.json +++ b/src/locale/cn/base.json @@ -2,6 +2,7 @@ "base": { "active": "激活", "community": "社区", + "decentralization": "去中心化", "goTo": "查看", "help": "帮助", "inactive": "未激活", diff --git a/src/locale/cn/help.json b/src/locale/cn/help.json index 4c2fbc2133..547d23542e 100644 --- a/src/locale/cn/help.json +++ b/src/locale/cn/help.json @@ -82,6 +82,15 @@ "用至少{EXISTENTIAL_DEPOSIT} {NETWORK_UNIT}将使其符合资格并可选择作为Controller." ] ], + "decentralizationAnalyticsPeriod": [ + "去中心化分析周期", + [ + "通过分析过去30天支付的奖励来计算您的提名的去中心化程度.", + "根据网络的不同,这将转化为若干个Era.", + "30天提供了足够的信息,使聚合有意义.", + "30天的周期也足够短,可以在几天后开始影响此分析中提名的变化." + ] + ], "epoch": [ "Epoch", [ @@ -103,6 +112,15 @@ "作为抵押者,您不需要在意Era点数. 一般来说,性能更好的验证人会产生更多的Era 点数,这反过来会得到更高的奖励." ] ], + "geolocationOfEachNomination": [ + "每个提名的地理位置", + [ + "每个被提名的验证人在特定的数据中心运行,该数据中心可以通过其IP地址进行地理定位.", + "表格显示了每个被提名验证人在上次分析期间被地理定位的地区、国家和网络.", + "如果在分析期间验证人被定位在多个位置,则会显示++符号.", + "显示的百分比是该验证人在分析期间向您支付的奖励比例." + ] + ], "idealStaked": ["最优比例", ["理想网络条件下的抵押占发行量的百分比."]], "inactiveNominations": [ "非活跃提名", @@ -182,6 +200,13 @@ "一旦提名了选定的验证人,他们就会成为您的提名." ] ], + "nominationPayoutDistribution": [ + "提名收益分布", + [ + "您的提名去中心化程度.", + "以下图表显示了按验证人支付奖励的地区、国家和IP网络聚合的奖励分布." + ] + ], "nominationPools": [ "提名池", [ @@ -368,6 +393,20 @@ "抵押{NETWORK_UNIT}的前提是成为提名人或加入提名池,提名池本身就是一个提名人." ] ], + "totalPayoutsAnalysed": [ + "总收益分析", + [ + "过去30天内由提名的验证人支付的累计{NETWORK_UNIT}奖励.", + "这些收益用于计算您的提名的去中心化程度." + ] + ], + "totalPayoutsAnalysed": [ + "总收益分析", + [ + "过去30天内由提名的验证人支付的累计{NETWORK_UNIT}奖励.", + "这些收益用于计算您的提名的去中心化程度." + ] + ], "validator": [ "验证人", [ diff --git a/src/locale/cn/pages.json b/src/locale/cn/pages.json index 09dae46e41..5935ef3e41 100644 --- a/src/locale/cn/pages.json +++ b/src/locale/cn/pages.json @@ -10,6 +10,14 @@ "validator": "{{count}} 个验证人", "website": "个人网站" }, + "decentralization": { + "PayoutDistribution": "收益分布", + "byRegionCountryNetwork": "按地区、国家和网络", + "howDecentralizedIsYourNomination": "您的提名去中心化程度如何?", + "maxErasAnalyzed": "最大分析Era数", + "totalPayoutsAnalysed": "总收益分析", + "DecentralizationPerNomination": "每个提名的地理位置" + }, "nominate": { "activeNominations": "活跃提名人", "addressCopied": "地址已复制到剪贴板", diff --git a/src/locale/en/help.json b/src/locale/en/help.json index 452f8df6bc..9efe68097f 100644 --- a/src/locale/en/help.json +++ b/src/locale/en/help.json @@ -3,9 +3,7 @@ "definitions": { "activeNominators": [ "Active Nominators", - [ - "Nominators who are active in the current session." - ] + ["Nominators who are active in the current session."] ], "activePools": [ "Active Pools", @@ -75,6 +73,15 @@ "A validator can update their commission rates as and when they please, and such changes will have an impact on your profitability. Be sure to monitor your nominations on this dashboard to keep updated on their commission rates." ] ], + "decentralizationAnalyticsPeriod": [ + "Decentralization Analytics Period", + [ + "The decentralization of your nomination is calculated analysing the rewards payed out in the last 30 days.", + "Depending on the Network this will translate into a number of Eras.", + "30 days provides enough information for the aggregation to be meaningful.", + "30 days is also short enough for changes in nominations to start impacting this analysis after a few days." + ] + ], "epoch": [ "Epoch", [ @@ -96,6 +103,15 @@ "As a staker, you do not need to worry about Era Points. In general, better performing validators produce more Era Points, which in-turn lead to higher staking rewards." ] ], + "geolocationOfEachNomination": [ + "Geolocation of Each Nomination", + [ + "Each nominated validator runs at a given datacenter that can be geolocated by its IP address. ", + "The table displays the last Region, Country and Network where each nominated validator was geolocated.", + "When the validator has been located at more than one location during the analytic period a ++ sign will be displayed.", + "The percentage shown is the proportion of rewards payed out to you by this validator in the analytic period." + ] + ], "idealStaked": [ "Ideal Staked", ["The percentage of staked total supply in ideal network conditions."] @@ -183,6 +199,13 @@ "Once you have nominated your selected validators, they become your nominations." ] ], + "nominationPayoutDistribution": [ + "Nomination Payout Distribution", + [ + "The decentralization of your nomination.", + "The following charts display the distribution of rewards aggregated by the Region, Country and IP Network of the validator the payed out the reward." + ] + ], "nominationPools": [ "Nomination Pools", [ @@ -359,6 +382,13 @@ "In order to stake {NETWORK_UNIT}, you can either become a nominator or join a pool - that act as nominators themselves." ] ], + "totalPayoutsAnalysed": [ + "Total Payouts Analysed", + [ + "The aggregated {NETWORK_UNIT} rewards payed out by nominated validators in the last 30 days.", + "These payouts were used to calculate the decentralization of your nomination." + ] + ], "validator": [ "Validator", [ @@ -391,6 +421,7 @@ "connectAccounts": "How to Connect Your Accounts", "createPools": "Creating Nomination Pools", "howToUse": "How to Use the Staking Dashboard: Overview", + "polkawatchAnalytics": "Decentralization Analytics by Polkawatch: Introduction", "rebonding": "Rebonding", "stakeDot": "Staking your DOT", "unbondingTokens": "Unbonding Your Tokens" diff --git a/src/locale/en/pages.json b/src/locale/en/pages.json index 0b557657a6..c6fbb6792a 100644 --- a/src/locale/en/pages.json +++ b/src/locale/en/pages.json @@ -11,6 +11,14 @@ "validator_other": "{{count}} Validators", "website": "Website" }, + "decentralization": { + "PayoutDistribution": "Payout Distribution", + "byRegionCountryNetwork": "by Region, Country and Network", + "howDecentralizedIsYourNomination": "How decentralized is your Nomination?", + "maxErasAnalyzed": "Max Eras Analysed", + "totalPayoutsAnalysed": "Total Payouts Analysed", + "DecentralizationPerNomination": "Geolocation per nomination" + }, "nominate": { "activeNominations": "Active Nominations", "addressCopied": "Address Copied to Clipboard", @@ -121,13 +129,6 @@ "slashed": "Slashed", "subscanDisabled": "Subscan Disabled" }, - "decentralization": { - "howDecentralizedIsYourNomination": "How decentralized is your Nomination?", - "totalPayoutsAnalysed": "Total Payouts Analysed", - "maxErasAnalyzed": "Max Eras Analysed", - "PayoutDistribution": "Payout Distribution", - "byRegionCountryNetwork": "by Region, Country and Network" - }, "pools": { "activePools": "Active Pools", "address": "Address", diff --git a/src/pages/NominationGeo/NominationGeoList/index.tsx b/src/pages/NominationGeo/NominationGeoList/index.tsx index 5f86837efb..e5d6899115 100644 --- a/src/pages/NominationGeo/NominationGeoList/index.tsx +++ b/src/pages/NominationGeo/NominationGeoList/index.tsx @@ -1,10 +1,13 @@ // Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors // SPDX-License-Identifier: GPL-3.0-only -import { faBars, faGripVertical } from '@fortawesome/free-solid-svg-icons'; +import { + faBars, + faExternalLinkAlt, + faGripVertical, +} from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { motion } from 'framer-motion'; -//import { useTranslation } from 'react-i18next'; import { useTheme } from 'contexts/Themes'; import { Header, List, Wrapper as ListWrapper } from 'library/List'; import { MotionContainer } from 'library/List/MotionContainer'; @@ -13,7 +16,12 @@ import { ItemWrapper } from '../Wrappers'; import type { NomninationGeoListProps } from '../types'; import { NominationGeoListProvider, useNominationGeoList } from './context'; import { useNetwork } from 'contexts/Network'; -//import { useValidators } from 'contexts/Validators/ValidatorEntries'; +import { Separator } from 'kits/Structure/Separator'; +import { ButtonPrimaryInvert } from 'kits/Buttons/ButtonPrimaryInvert'; +import { useStaking } from 'contexts/Staking'; +import { useActiveAccounts } from 'contexts/ActiveAccounts'; +import { ButtonHelp } from 'kits/Buttons/ButtonHelp'; +import { useHelp } from 'contexts/Help'; export const NominationGeoList = (props: NomninationGeoListProps) => ( @@ -26,94 +34,134 @@ export const NominationGeoListInner = ({ title, data, }: NomninationGeoListProps) => { - //const { i18n, t } = useTranslation('pages'); const { mode } = useTheme(); const { + network, networkData: { colors }, } = useNetwork(); const { listFormat, setListFormat } = useNominationGeoList(); - //const { validators } = useValidators(); + const { isNominating } = useStaking(); + const { activeAccount } = useActiveAccounts(); + const { openHelp } = useHelp(); if (!data?.nodeDistributionDetail) { return null; } - let totalRewards = data.nodeDistributionDetail.reduce((acc,n,i)=>acc+n.TokenRewards, 0); + const totalRewards = data.nodeDistributionDetail.reduce( + (acc, n) => acc + n.TokenRewards, + 0 + ); return ( - -
-
-

{title}

-
-
- - -
-
- - - {data.nodeDistributionDetail - .sort((a, b) => b.TokenRewards - a.TokenRewards) - .map((n, index: number) => { - const labelClass = 'reward'; +
+
+ + +
+ + + + {data.nodeDistributionDetail + .sort((a, b) => b.TokenRewards - a.TokenRewards) + .map((n, index: number) => { + const labelClass = 'reward'; - return ( - - -
-
-
-
-

- <> -

{n.LastNetwork}, {n.LastCountry}, {n.LastRegion} {n.Countries+n.Regions > 2 ? '++.':'.'}

- -

-
-
-
-
-
-
-
- + return ( + + +
+
+
+
+

+

+ {n.LastNetwork}, {n.LastCountry},{' '} + {n.LastRegion}{' '} + {n.Countries + n.Regions > 2 ? '++.' : '.'} +

+

+
+
+
-
-
{Math.round((n.TokenRewards / totalRewards) * 1000)/10} %
+
+
+
+ +
+
+
+ {Math.round( + (n.TokenRewards / totalRewards) * 1000 + ) / 10}{' '} + % +
+
+
-
-
-
-
- ); - })} - - - + + + ); + })} + + + + +
+ + window.open( + `https://${network}.polkawatch.app/nomination/${activeAccount}`, + '_blank' + ) + } + iconRight={faExternalLinkAlt} + iconTransform="shrink-2" + text="Polkawatch" + disabled={ + !( + activeAccount && + ['polkadot', 'kusama'].includes(network) && + isNominating() + ) + } + /> +
+ ); }; diff --git a/src/pages/NominationGeo/Stats/AnalyzedDays.tsx b/src/pages/NominationGeo/Stats/AnalyzedDays.tsx index 0f474d2a3a..1f1a1cacfb 100644 --- a/src/pages/NominationGeo/Stats/AnalyzedDays.tsx +++ b/src/pages/NominationGeo/Stats/AnalyzedDays.tsx @@ -8,11 +8,11 @@ import { useTranslation } from 'react-i18next'; export const AnalyzedDays = () => { const { t } = useTranslation('pages'); - const params = { - label: t('decentralization.maxErasAnalyzed'), - value: 30, - unit: 'Days', - helpKey: 'Max Days Analysed', - }; - return ; + const params = { + label: t('decentralization.maxErasAnalyzed'), + value: 30, + unit: 'Days', + helpKey: 'Decentralization Analytics Period', + }; + return ; }; diff --git a/src/pages/NominationGeo/Stats/AnalyzedEras.tsx b/src/pages/NominationGeo/Stats/AnalyzedEras.tsx index 74362ff2e4..57e150075e 100644 --- a/src/pages/NominationGeo/Stats/AnalyzedEras.tsx +++ b/src/pages/NominationGeo/Stats/AnalyzedEras.tsx @@ -15,7 +15,7 @@ export const AnalyzedEras = ({ meta }: AnalyzedErasProps) => { label: t('decentralization.maxErasAnalyzed'), value: meta?.ErasPerMonth || 0, unit: 'Eras', - helpKey: 'Max Eras Analysed', + helpKey: 'Decentralization Analytics Period', }; return ; }; diff --git a/src/pages/NominationGeo/index.tsx b/src/pages/NominationGeo/index.tsx index 8025712be4..7f99a7513c 100644 --- a/src/pages/NominationGeo/index.tsx +++ b/src/pages/NominationGeo/index.tsx @@ -19,12 +19,10 @@ import { AnalyzedPayouts } from './Stats/AnalyzedPayouts'; import { AnalyzedDays } from './Stats/AnalyzedDays'; import { AnalyzedEras } from './Stats/AnalyzedEras'; - import { PageRow } from 'kits/Structure/PageRow'; import { PageHeadingWrapper } from 'kits/Structure/PageHeading/Wrapper'; import { CardHeaderWrapper, CardWrapper } from 'library/Card/Wrappers'; import { PluginLabel } from 'library/PluginLabel'; -//import { RowSection } from 'kits/Structure/RowSection'; import { GraphWrapper } from 'library/Graphs/Wrapper'; import { GeoDonut } from 'library/Graphs/GeoDonut'; import { ButtonHelp } from 'kits/Buttons/ButtonHelp'; @@ -128,7 +126,7 @@ export const NominationGeo = ({ page: { key } }: PageProps) => { {t('decentralization.PayoutDistribution', { ns: 'pages' })} openHelp('Payout Distribution')} + onClick={() => openHelp('Nomination Payout Distribution')} />

@@ -151,6 +149,7 @@ export const NominationGeo = ({ page: { key } }: PageProps) => { height={`${300}px`} width={300} legendHeight={50} + maxLabelLen={0} /> @@ -160,6 +159,7 @@ export const NominationGeo = ({ page: { key } }: PageProps) => { height={`${300}px`} width={300} legendHeight={50} + maxLabelLen={10} /> @@ -169,6 +169,7 @@ export const NominationGeo = ({ page: { key } }: PageProps) => { height={`${300}px`} width={300} legendHeight={50} + maxLabelLen={10} />

@@ -178,7 +179,9 @@ export const NominationGeo = ({ page: { key } }: PageProps) => { diff --git a/src/pages/NominationGeo/types.ts b/src/pages/NominationGeo/types.ts index ba8d2e02b5..d645389931 100644 --- a/src/pages/NominationGeo/types.ts +++ b/src/pages/NominationGeo/types.ts @@ -1,11 +1,9 @@ // Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors // SPDX-License-Identifier: GPL-3.0-only -import type { NominatorDetail } from '@polkawatch/ddp-client'; +import type { NominatorDetail, ChainMetadata } from '@polkawatch/ddp-client'; export type { NominatorDetail } from '@polkawatch/ddp-client'; -import type { ChainMetadata } from '@polkawatch/ddp-client'; - export type { ChainMetadata } from '@polkawatch/ddp-client'; export interface AnalyzedPayoutsProps { @@ -26,4 +24,4 @@ import type { ListFormat } from 'library/PoolList/types'; export interface NominationGeoListContextInterface { setListFormat: (v: ListFormat) => void; listFormat: ListFormat; -} \ No newline at end of file +} From a6c85ca9fdc9f8d3b36ea5bf37f09f64c2f764b8 Mon Sep 17 00:00:00 2001 From: rafael Date: Thu, 20 Jun 2024 13:24:03 +0200 Subject: [PATCH 05/32] better modal labels --- src/modals/ValidatorGeo/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modals/ValidatorGeo/index.tsx b/src/modals/ValidatorGeo/index.tsx index 6ca9825d36..4f84df0657 100644 --- a/src/modals/ValidatorGeo/index.tsx +++ b/src/modals/ValidatorGeo/index.tsx @@ -130,6 +130,7 @@ export const ValidatorGeo = () => { series={pwData.topCountryDistributionChart} height={`${height}px`} width={chartWidth} + maxLabelLen={10} /> @@ -144,6 +145,7 @@ export const ValidatorGeo = () => { series={pwData.topNetworkDistributionChart} height={`${height}px`} width={chartWidth} + maxLabelLen={10} />
From aee713e33553de0757c6ba1c2bf73050cd69e3c0 Mon Sep 17 00:00:00 2001 From: rafael Date: Thu, 20 Jun 2024 14:31:39 +0200 Subject: [PATCH 06/32] handling exception cases, and presented localized messages --- src/locale/cn/help.json | 7 ----- src/locale/cn/pages.json | 9 ++++-- src/locale/en/pages.json | 10 ++++-- src/pages/NominationGeo/index.tsx | 51 +++++++++++++++++++++++-------- 4 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/locale/cn/help.json b/src/locale/cn/help.json index 547d23542e..84e5b4a550 100644 --- a/src/locale/cn/help.json +++ b/src/locale/cn/help.json @@ -400,13 +400,6 @@ "这些收益用于计算您的提名的去中心化程度." ] ], - "totalPayoutsAnalysed": [ - "总收益分析", - [ - "过去30天内由提名的验证人支付的累计{NETWORK_UNIT}奖励.", - "这些收益用于计算您的提名的去中心化程度." - ] - ], "validator": [ "验证人", [ diff --git a/src/locale/cn/pages.json b/src/locale/cn/pages.json index 5935ef3e41..8841969187 100644 --- a/src/locale/cn/pages.json +++ b/src/locale/cn/pages.json @@ -11,12 +11,15 @@ "website": "个人网站" }, "decentralization": { - "PayoutDistribution": "收益分布", + "analyticsNotAvailable": "无法使用该分布式分析器", + "analyticsNotSupported": "此网络不支持该分布式分析器", "byRegionCountryNetwork": "按地区、国家和网络", + "decentralizationPerNomination": "每个提名的地理位置", "howDecentralizedIsYourNomination": "您的提名去中心化程度如何?", "maxErasAnalyzed": "最大分析Era数", - "totalPayoutsAnalysed": "总收益分析", - "DecentralizationPerNomination": "每个提名的地理位置" + "payoutDistribution": "收益分布", + "polkawatchDisabled": "Polkawatch己断开", + "totalPayoutsAnalysed": "总收益分析" }, "nominate": { "activeNominations": "活跃提名人", diff --git a/src/locale/en/pages.json b/src/locale/en/pages.json index c6fbb6792a..8d797d9f3e 100644 --- a/src/locale/en/pages.json +++ b/src/locale/en/pages.json @@ -12,12 +12,16 @@ "website": "Website" }, "decentralization": { - "PayoutDistribution": "Payout Distribution", + "analyticsNotAvailable": "Analytics Not Available", + "analyticsNotSupported": "Analytics Not Supported", "byRegionCountryNetwork": "by Region, Country and Network", + "decentralizationPerNomination": "Geolocation per nomination", "howDecentralizedIsYourNomination": "How decentralized is your Nomination?", "maxErasAnalyzed": "Max Eras Analysed", - "totalPayoutsAnalysed": "Total Payouts Analysed", - "DecentralizationPerNomination": "Geolocation per nomination" + "networkNotSupported": "Network Not Supported", + "payoutDistribution": "Payout Distribution", + "polkawatchDisabled": "Polkawatch Disabled", + "totalPayoutsAnalysed": "Total Payouts Analysed" }, "nominate": { "activeNominations": "Active Nominations", diff --git a/src/pages/NominationGeo/index.tsx b/src/pages/NominationGeo/index.tsx index 7f99a7513c..1106aa3da9 100644 --- a/src/pages/NominationGeo/index.tsx +++ b/src/pages/NominationGeo/index.tsx @@ -29,6 +29,7 @@ import { ButtonHelp } from 'kits/Buttons/ButtonHelp'; import { useHelp } from 'contexts/Help'; import { Separator } from 'kits/Structure/Separator'; import { NominationGeoList } from './NominationGeoList'; +import { StatusLabel } from 'library/StatusLabel'; export const NominationGeo = ({ page: { key } }: PageProps) => { const { activeAccount } = useActiveAccounts(); @@ -70,7 +71,7 @@ export const NominationGeo = ({ page: { key } }: PageProps) => { {} as NominatorDetail ); - const [, setAnalyticsAvailable] = useState(true); + const [analyticsAvailable, setAnalyticsAvailable] = useState(true); const networkSupported = PolkaWatchController.SUPPORTED_NETWORKS.includes(network); @@ -123,7 +124,7 @@ export const NominationGeo = ({ page: { key } }: PageProps) => {

- {t('decentralization.PayoutDistribution', { ns: 'pages' })} + {t('decentralization.payoutDistribution', { ns: 'pages' })} openHelp('Nomination Payout Distribution')} @@ -142,6 +143,28 @@ export const NominationGeo = ({ page: { key } }: PageProps) => { flexWrap: 'wrap', }} > + {!enabled || analyticsAvailable ? ( + + ) : ( + + )} {

- - - - - + {nominationDetail?.nodeDistributionDetail && ( + + + + + + )} ); }; From 9830e665c6966569806c4af4a7991da4614d3399 Mon Sep 17 00:00:00 2001 From: rafael Date: Thu, 20 Jun 2024 16:58:04 +0200 Subject: [PATCH 07/32] added missing help key --- src/locale/cn/help.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/locale/cn/help.json b/src/locale/cn/help.json index 84e5b4a550..ec3948d09b 100644 --- a/src/locale/cn/help.json +++ b/src/locale/cn/help.json @@ -432,6 +432,7 @@ "connectAccounts": "如何连接您的帐户", "createPools": "创建提名池", "howToUse": "如何使用Staking Dashboard:概述", + "polkawatchAnalytics": "Polkawatch的去中心化分析: 介绍", "rebonding": "解除质押中", "stakeDot": "抵押您的DOT", "unbondingTokens": "解除您的质押" From 13a0c79b4848c351a3b9b49d1462b3b575e76c02 Mon Sep 17 00:00:00 2001 From: rafael Date: Thu, 20 Jun 2024 17:02:08 +0200 Subject: [PATCH 08/32] using new cloud license --- src/pages/NominationGeo/NominationGeoList/context.tsx | 2 +- src/pages/NominationGeo/NominationGeoList/index.tsx | 2 +- src/pages/NominationGeo/Stats/AnalyzedDays.tsx | 2 +- src/pages/NominationGeo/Stats/AnalyzedEras.tsx | 2 +- src/pages/NominationGeo/Stats/AnalyzedPayouts.tsx | 2 +- src/pages/NominationGeo/Wrappers.ts | 2 +- src/pages/NominationGeo/index.tsx | 2 +- src/pages/NominationGeo/types.ts | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pages/NominationGeo/NominationGeoList/context.tsx b/src/pages/NominationGeo/NominationGeoList/context.tsx index b4d81550fc..774a7a8d8f 100644 --- a/src/pages/NominationGeo/NominationGeoList/context.tsx +++ b/src/pages/NominationGeo/NominationGeoList/context.tsx @@ -1,4 +1,4 @@ -// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors // SPDX-License-Identifier: GPL-3.0-only import type { ReactNode } from 'react'; diff --git a/src/pages/NominationGeo/NominationGeoList/index.tsx b/src/pages/NominationGeo/NominationGeoList/index.tsx index e5d6899115..21df1e7d2f 100644 --- a/src/pages/NominationGeo/NominationGeoList/index.tsx +++ b/src/pages/NominationGeo/NominationGeoList/index.tsx @@ -1,4 +1,4 @@ -// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors // SPDX-License-Identifier: GPL-3.0-only import { diff --git a/src/pages/NominationGeo/Stats/AnalyzedDays.tsx b/src/pages/NominationGeo/Stats/AnalyzedDays.tsx index 1f1a1cacfb..8330ab141f 100644 --- a/src/pages/NominationGeo/Stats/AnalyzedDays.tsx +++ b/src/pages/NominationGeo/Stats/AnalyzedDays.tsx @@ -1,4 +1,4 @@ -// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors // SPDX-License-Identifier: GPL-3.0-only import { Number } from 'library/StatBoxList/Number'; diff --git a/src/pages/NominationGeo/Stats/AnalyzedEras.tsx b/src/pages/NominationGeo/Stats/AnalyzedEras.tsx index 57e150075e..e017099848 100644 --- a/src/pages/NominationGeo/Stats/AnalyzedEras.tsx +++ b/src/pages/NominationGeo/Stats/AnalyzedEras.tsx @@ -1,4 +1,4 @@ -// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors // SPDX-License-Identifier: GPL-3.0-only import { Number } from 'library/StatBoxList/Number'; diff --git a/src/pages/NominationGeo/Stats/AnalyzedPayouts.tsx b/src/pages/NominationGeo/Stats/AnalyzedPayouts.tsx index 020320b099..b2fd50d188 100644 --- a/src/pages/NominationGeo/Stats/AnalyzedPayouts.tsx +++ b/src/pages/NominationGeo/Stats/AnalyzedPayouts.tsx @@ -1,4 +1,4 @@ -// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors // SPDX-License-Identifier: GPL-3.0-only import { Number } from 'library/StatBoxList/Number'; diff --git a/src/pages/NominationGeo/Wrappers.ts b/src/pages/NominationGeo/Wrappers.ts index fa141972a3..f76956a8b7 100644 --- a/src/pages/NominationGeo/Wrappers.ts +++ b/src/pages/NominationGeo/Wrappers.ts @@ -1,4 +1,4 @@ -// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors // SPDX-License-Identifier: GPL-3.0-only import { motion } from 'framer-motion'; diff --git a/src/pages/NominationGeo/index.tsx b/src/pages/NominationGeo/index.tsx index 1106aa3da9..042714d76d 100644 --- a/src/pages/NominationGeo/index.tsx +++ b/src/pages/NominationGeo/index.tsx @@ -1,4 +1,4 @@ -// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors // SPDX-License-Identifier: GPL-3.0-only import { useTranslation } from 'react-i18next'; diff --git a/src/pages/NominationGeo/types.ts b/src/pages/NominationGeo/types.ts index d645389931..3303db421a 100644 --- a/src/pages/NominationGeo/types.ts +++ b/src/pages/NominationGeo/types.ts @@ -1,4 +1,4 @@ -// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors +// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors // SPDX-License-Identifier: GPL-3.0-only import type { NominatorDetail, ChainMetadata } from '@polkawatch/ddp-client'; From 060325f22ef8abe1c47a0d6f73edaed656f9afa2 Mon Sep 17 00:00:00 2001 From: rafael Date: Thu, 20 Jun 2024 17:11:13 +0200 Subject: [PATCH 09/32] removed deprecated key --- src/locale/en/pages.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/locale/en/pages.json b/src/locale/en/pages.json index 8d797d9f3e..b4c61dcf99 100644 --- a/src/locale/en/pages.json +++ b/src/locale/en/pages.json @@ -18,7 +18,6 @@ "decentralizationPerNomination": "Geolocation per nomination", "howDecentralizedIsYourNomination": "How decentralized is your Nomination?", "maxErasAnalyzed": "Max Eras Analysed", - "networkNotSupported": "Network Not Supported", "payoutDistribution": "Payout Distribution", "polkawatchDisabled": "Polkawatch Disabled", "totalPayoutsAnalysed": "Total Payouts Analysed" From a7c739857371f73ccda6e3aaf8fb32fed8142a71 Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 24 Jun 2024 17:05:59 +0200 Subject: [PATCH 10/32] added icon and tooltipe for share of rewards of a geolocated nomination --- src/locale/cn/pages.json | 1 + src/locale/en/pages.json | 1 + .../NominationGeo/NominationGeoList/index.tsx | 108 ++++++++++-------- 3 files changed, 63 insertions(+), 47 deletions(-) diff --git a/src/locale/cn/pages.json b/src/locale/cn/pages.json index 8841969187..fd28618c23 100644 --- a/src/locale/cn/pages.json +++ b/src/locale/cn/pages.json @@ -17,6 +17,7 @@ "decentralizationPerNomination": "每个提名的地理位置", "howDecentralizedIsYourNomination": "您的提名去中心化程度如何?", "maxErasAnalyzed": "最大分析Era数", + "nominationShareInRewards": "奖励份额", "payoutDistribution": "收益分布", "polkawatchDisabled": "Polkawatch己断开", "totalPayoutsAnalysed": "总收益分析" diff --git a/src/locale/en/pages.json b/src/locale/en/pages.json index b4c61dcf99..ff9652cb4c 100644 --- a/src/locale/en/pages.json +++ b/src/locale/en/pages.json @@ -18,6 +18,7 @@ "decentralizationPerNomination": "Geolocation per nomination", "howDecentralizedIsYourNomination": "How decentralized is your Nomination?", "maxErasAnalyzed": "Max Eras Analysed", + "nominationShareInRewards": "Share of rewards", "payoutDistribution": "Payout Distribution", "polkawatchDisabled": "Polkawatch Disabled", "totalPayoutsAnalysed": "Total Payouts Analysed" diff --git a/src/pages/NominationGeo/NominationGeoList/index.tsx b/src/pages/NominationGeo/NominationGeoList/index.tsx index 21df1e7d2f..bc18b095b8 100644 --- a/src/pages/NominationGeo/NominationGeoList/index.tsx +++ b/src/pages/NominationGeo/NominationGeoList/index.tsx @@ -3,6 +3,7 @@ import { faBars, + faChartPie, faExternalLinkAlt, faGripVertical, } from '@fortawesome/free-solid-svg-icons'; @@ -22,6 +23,9 @@ import { useStaking } from 'contexts/Staking'; import { useActiveAccounts } from 'contexts/ActiveAccounts'; import { ButtonHelp } from 'kits/Buttons/ButtonHelp'; import { useHelp } from 'contexts/Help'; +import { TooltipTrigger } from 'library/ListItem/Wrappers'; +import { useTooltip } from 'contexts/Tooltip'; +import { useTranslation } from 'react-i18next'; export const NominationGeoList = (props: NomninationGeoListProps) => ( @@ -35,6 +39,7 @@ export const NominationGeoListInner = ({ data, }: NomninationGeoListProps) => { const { mode } = useTheme(); + const { t } = useTranslation('pages'); const { network, networkData: { colors }, @@ -43,6 +48,7 @@ export const NominationGeoListInner = ({ const { isNominating } = useStaking(); const { activeAccount } = useActiveAccounts(); const { openHelp } = useHelp(); + const { setTooltipTextAndOpen } = useTooltip(); if (!data?.nodeDistributionDetail) { return null; @@ -53,6 +59,8 @@ export const NominationGeoListInner = ({ 0 ); + const tooltipText = t('decentralization.nominationShareInRewards'); + return ( <> @@ -83,60 +91,66 @@ export const NominationGeoListInner = ({ {data.nodeDistributionDetail .sort((a, b) => b.TokenRewards - a.TokenRewards) - .map((n, index: number) => { - const labelClass = 'reward'; - - return ( - - -
-
+ .map((n, index: number) => ( + + +
+
+
-
-

-

- {n.LastNetwork}, {n.LastCountry},{' '} - {n.LastRegion}{' '} - {n.Countries + n.Regions > 2 ? '++.' : '.'} -

-

-
-
+

+

+ {n.LastNetwork}, {n.LastCountry}, {n.LastRegion}{' '} + {n.Countries + n.Regions > 2 ? '++.' : '.'} +

+

+
-
+
+
+
+
+ +
-
- -
-
-
- {Math.round( - (n.TokenRewards / totalRewards) * 1000 - ) / 10}{' '} - % -
-
+
+ + setTooltipTextAndOpen(tooltipText) + } + /> + {Math.round( + (n.TokenRewards / totalRewards) * 1000 + ) / 10}{' '} + %{' '} + +
- - - ); - })} +
+ + + ))} From 46cb29319b4763056468207e69687bce8baa58b4 Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 24 Jun 2024 17:17:35 +0200 Subject: [PATCH 11/32] Alternate UI design with decentralization in Nomination --- src/config/pages.ts | 9 ------- .../NominationGeoList/context.tsx | 0 .../NominationGeo/NominationGeoList/index.tsx | 0 .../NominationGeo/Stats/AnalyzedDays.tsx | 0 .../NominationGeo/Stats/AnalyzedEras.tsx | 0 .../NominationGeo/Stats/AnalyzedPayouts.tsx | 0 .../{ => Nominate}/NominationGeo/Wrappers.ts | 0 .../{ => Nominate}/NominationGeo/index.tsx | 25 +++++-------------- .../{ => Nominate}/NominationGeo/types.ts | 0 src/pages/Nominate/index.tsx | 2 ++ 10 files changed, 8 insertions(+), 28 deletions(-) rename src/pages/{ => Nominate}/NominationGeo/NominationGeoList/context.tsx (100%) rename src/pages/{ => Nominate}/NominationGeo/NominationGeoList/index.tsx (100%) rename src/pages/{ => Nominate}/NominationGeo/Stats/AnalyzedDays.tsx (100%) rename src/pages/{ => Nominate}/NominationGeo/Stats/AnalyzedEras.tsx (100%) rename src/pages/{ => Nominate}/NominationGeo/Stats/AnalyzedPayouts.tsx (100%) rename src/pages/{ => Nominate}/NominationGeo/Wrappers.ts (100%) rename src/pages/{ => Nominate}/NominationGeo/index.tsx (92%) rename src/pages/{ => Nominate}/NominationGeo/types.ts (100%) diff --git a/src/config/pages.ts b/src/config/pages.ts index 98f84344a4..92b76cd0f5 100644 --- a/src/config/pages.ts +++ b/src/config/pages.ts @@ -5,7 +5,6 @@ import { Community } from 'pages/Community'; import { Nominate } from 'pages/Nominate'; import { Overview } from 'pages/Overview'; import { Payouts } from 'pages/Payouts'; -import { NominationGeo } from 'pages/NominationGeo'; import { Pools } from 'pages/Pools'; import { Validators } from 'pages/Validators'; import type { PageCategoryItems, PagesConfigItems } from 'types'; @@ -59,14 +58,6 @@ export const PagesConfig: PagesConfigItems = [ Entry: Payouts, lottie: 'analytics', }, - { - category: 2, - key: 'decentralization', - uri: `${BASE_URL}decentralization`, - hash: '/decentralization', - Entry: NominationGeo, - lottie: 'globe', - }, { category: 3, key: 'validators', diff --git a/src/pages/NominationGeo/NominationGeoList/context.tsx b/src/pages/Nominate/NominationGeo/NominationGeoList/context.tsx similarity index 100% rename from src/pages/NominationGeo/NominationGeoList/context.tsx rename to src/pages/Nominate/NominationGeo/NominationGeoList/context.tsx diff --git a/src/pages/NominationGeo/NominationGeoList/index.tsx b/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx similarity index 100% rename from src/pages/NominationGeo/NominationGeoList/index.tsx rename to src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx diff --git a/src/pages/NominationGeo/Stats/AnalyzedDays.tsx b/src/pages/Nominate/NominationGeo/Stats/AnalyzedDays.tsx similarity index 100% rename from src/pages/NominationGeo/Stats/AnalyzedDays.tsx rename to src/pages/Nominate/NominationGeo/Stats/AnalyzedDays.tsx diff --git a/src/pages/NominationGeo/Stats/AnalyzedEras.tsx b/src/pages/Nominate/NominationGeo/Stats/AnalyzedEras.tsx similarity index 100% rename from src/pages/NominationGeo/Stats/AnalyzedEras.tsx rename to src/pages/Nominate/NominationGeo/Stats/AnalyzedEras.tsx diff --git a/src/pages/NominationGeo/Stats/AnalyzedPayouts.tsx b/src/pages/Nominate/NominationGeo/Stats/AnalyzedPayouts.tsx similarity index 100% rename from src/pages/NominationGeo/Stats/AnalyzedPayouts.tsx rename to src/pages/Nominate/NominationGeo/Stats/AnalyzedPayouts.tsx diff --git a/src/pages/NominationGeo/Wrappers.ts b/src/pages/Nominate/NominationGeo/Wrappers.ts similarity index 100% rename from src/pages/NominationGeo/Wrappers.ts rename to src/pages/Nominate/NominationGeo/Wrappers.ts diff --git a/src/pages/NominationGeo/index.tsx b/src/pages/Nominate/NominationGeo/index.tsx similarity index 92% rename from src/pages/NominationGeo/index.tsx rename to src/pages/Nominate/NominationGeo/index.tsx index 042714d76d..80f4e2cbca 100644 --- a/src/pages/NominationGeo/index.tsx +++ b/src/pages/Nominate/NominationGeo/index.tsx @@ -2,8 +2,6 @@ // SPDX-License-Identifier: GPL-3.0-only import { useTranslation } from 'react-i18next'; -import type { PageProps } from 'types'; -import { PageTitle } from 'kits/Structure/PageTitle'; import { StatBoxList } from 'library/StatBoxList'; import { useNetwork } from 'contexts/Network'; import { useEffect, useState } from 'react'; @@ -20,7 +18,6 @@ import { AnalyzedDays } from './Stats/AnalyzedDays'; import { AnalyzedEras } from './Stats/AnalyzedEras'; import { PageRow } from 'kits/Structure/PageRow'; -import { PageHeadingWrapper } from 'kits/Structure/PageHeading/Wrapper'; import { CardHeaderWrapper, CardWrapper } from 'library/Card/Wrappers'; import { PluginLabel } from 'library/PluginLabel'; import { GraphWrapper } from 'library/Graphs/Wrapper'; @@ -31,7 +28,7 @@ import { Separator } from 'kits/Structure/Separator'; import { NominationGeoList } from './NominationGeoList'; import { StatusLabel } from 'library/StatusLabel'; -export const NominationGeo = ({ page: { key } }: PageProps) => { +export const NominationGeo = () => { const { activeAccount } = useActiveAccounts(); const { t } = useTranslation(); const { openHelp } = useHelp(); @@ -104,21 +101,6 @@ export const NominationGeo = ({ page: { key } }: PageProps) => { return ( <> - - - -

- {t('decentralization.howDecentralizedIsYourNomination', { - ns: 'pages', - })} -

-
-
- - - - - @@ -198,6 +180,11 @@ export const NominationGeo = ({ page: { key } }: PageProps) => {
+ + + + + {nominationDetail?.nodeDistributionDetail && ( diff --git a/src/pages/NominationGeo/types.ts b/src/pages/Nominate/NominationGeo/types.ts similarity index 100% rename from src/pages/NominationGeo/types.ts rename to src/pages/Nominate/NominationGeo/types.ts diff --git a/src/pages/Nominate/index.tsx b/src/pages/Nominate/index.tsx index 4a1716559f..93da3bc58e 100644 --- a/src/pages/Nominate/index.tsx +++ b/src/pages/Nominate/index.tsx @@ -2,10 +2,12 @@ // SPDX-License-Identifier: GPL-3.0-only import { Active } from './Active'; +import { NominationGeo } from './NominationGeo'; import { Wrapper } from './Wrappers'; export const Nominate = () => ( + ); From 3fa9a910331e8be34ed5c9d0b858aa08544430d6 Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 24 Jun 2024 18:06:29 +0200 Subject: [PATCH 12/32] using a tabbed nomination section --- src/locale/en/pages.json | 2 ++ src/pages/Nominate/Active/index.tsx | 2 -- src/pages/Nominate/NominationGeo/index.tsx | 10 +++---- src/pages/Nominate/index.tsx | 35 ++++++++++++++++++---- 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/locale/en/pages.json b/src/locale/en/pages.json index ff9652cb4c..113b2955cf 100644 --- a/src/locale/en/pages.json +++ b/src/locale/en/pages.json @@ -35,6 +35,7 @@ "change": "Change", "controllerAccount": "Controller Account", "controllerNotImported": "You have not imported your controller account. If you have lost access to your controller account, set a new one now. Otherwise, import the controller into one of your active extensions.", + "decentralization": "Decentralization", "earningRewards": "Earning Rewards", "inactiveNominations": "Inactive Nominations", "manage": "Manage", @@ -49,6 +50,7 @@ "notAssigned": "Not Assigned", "notEarningRewards": "Not Earning Rewards", "notNominating": "Not Nominating", + "overview": "Overview", "payoutDestination": "Payout Destination", "payoutDestinationSubtitle": "Choose how payouts will be received. Payouts can either be compounded or sent to an account as free balance.", "pendingPayouts": "Pending Payouts", diff --git a/src/pages/Nominate/Active/index.tsx b/src/pages/Nominate/Active/index.tsx index 2ec2df34c1..596d89aa95 100644 --- a/src/pages/Nominate/Active/index.tsx +++ b/src/pages/Nominate/Active/index.tsx @@ -23,7 +23,6 @@ import { useSyncing } from 'hooks/useSyncing'; import { useBalances } from 'contexts/Balances'; import { ButtonHelp } from 'kits/Buttons/ButtonHelp'; import { ButtonPrimary } from 'kits/Buttons/ButtonPrimary'; -import { PageTitle } from 'kits/Structure/PageTitle'; import { PageRow } from 'kits/Structure/PageRow'; import { RowSection } from 'kits/Structure/RowSection'; import { WithdrawPrompt } from 'library/WithdrawPrompt'; @@ -44,7 +43,6 @@ export const Active = () => { return ( <> - diff --git a/src/pages/Nominate/NominationGeo/index.tsx b/src/pages/Nominate/NominationGeo/index.tsx index 80f4e2cbca..e4c1d4992c 100644 --- a/src/pages/Nominate/NominationGeo/index.tsx +++ b/src/pages/Nominate/NominationGeo/index.tsx @@ -101,6 +101,11 @@ export const NominationGeo = () => { return ( <> + + + + + @@ -180,11 +185,6 @@ export const NominationGeo = () => {
- - - - - {nominationDetail?.nodeDistributionDetail && ( diff --git a/src/pages/Nominate/index.tsx b/src/pages/Nominate/index.tsx index 93da3bc58e..9d6fd08fd5 100644 --- a/src/pages/Nominate/index.tsx +++ b/src/pages/Nominate/index.tsx @@ -4,10 +4,33 @@ import { Active } from './Active'; import { NominationGeo } from './NominationGeo'; import { Wrapper } from './Wrappers'; +import { PageTitle } from '../../kits/Structure/PageTitle'; +import { useTranslation } from 'react-i18next'; +import type { PageTitleTabProps } from 'kits/Structure/PageTitleTabs/types'; +import { useState } from 'react'; -export const Nominate = () => ( - - - - -); +export const Nominate = () => { + const { t } = useTranslation('pages'); + const [activeTab, setActiveTab] = useState(0); + + const tabs: PageTitleTabProps[] = [ + { + title: t('nominate.overview'), + active: activeTab === 0, + onClick: () => setActiveTab(0), + }, + { + title: t('nominate.decentralization'), + active: activeTab === 1, + onClick: () => setActiveTab(1), + }, + ]; + + return ( + + + {activeTab == 0 && } + {activeTab == 1 && } + + ); +}; From 26b48e3a1cfc168a3080264d0bc1c93c230fa0f2 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 12:02:20 +0100 Subject: [PATCH 13/32] sep Node, + RewardShare label, use `ListItem` wrapper --- src/library/List/index.ts | 5 + src/library/ListItem/Labels/RewardShare.tsx | 27 ++++ .../NominationGeo/NominationGeoList/Node.tsx | 58 ++++++++ .../NominationGeo/NominationGeoList/index.tsx | 132 ++++-------------- src/pages/Nominate/NominationGeo/Wrappers.ts | 95 ------------- 5 files changed, 114 insertions(+), 203 deletions(-) create mode 100644 src/library/ListItem/Labels/RewardShare.tsx create mode 100644 src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx delete mode 100644 src/pages/Nominate/NominationGeo/Wrappers.ts diff --git a/src/library/List/index.ts b/src/library/List/index.ts index 49d42bbcc5..6ba6bfeb0e 100644 --- a/src/library/List/index.ts +++ b/src/library/List/index.ts @@ -24,6 +24,11 @@ export const Header = styled.div<{ $displayFor?: DisplayFor }>` padding: 0 0.25rem 0.75rem 0.25rem; flex: 1; + &.noBorder { + border: none; + padding-bottom: 0; + } + h4 { color: var(--text-color-secondary); font-family: InterSemiBold, sans-serif; diff --git a/src/library/ListItem/Labels/RewardShare.tsx b/src/library/ListItem/Labels/RewardShare.tsx new file mode 100644 index 0000000000..0fbb9c371f --- /dev/null +++ b/src/library/ListItem/Labels/RewardShare.tsx @@ -0,0 +1,27 @@ +// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import { useTranslation } from 'react-i18next'; +import { useTooltip } from 'contexts/Tooltip'; +import { TooltipTrigger } from 'library/ListItem/Wrappers'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faChartPie } from '@fortawesome/free-solid-svg-icons'; + +export const RewardShare = ({ share }: { share: number }) => { + const { t } = useTranslation('pages'); + const { setTooltipTextAndOpen } = useTooltip(); + + const tooltipText = t('decentralization.nominationShareInRewards'); + + return ( +
+ setTooltipTextAndOpen(tooltipText)} + /> + + {share}%{' '} +
+ ); +}; diff --git a/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx b/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx new file mode 100644 index 0000000000..3e2326e40b --- /dev/null +++ b/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx @@ -0,0 +1,58 @@ +// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import type { RewardsByValidationNode } from '@polkawatch/ddp-client'; +import { useNominationGeoList } from './context'; +import { motion } from 'framer-motion'; +import { Labels, Wrapper, Separator } from 'library/ListItem/Wrappers'; +import { Identity } from 'library/ListItem/Labels/Identity'; +import { RewardShare } from 'library/ListItem/Labels/RewardShare'; + +export const Node = ({ + node, + rewardTotal, +}: { + node: RewardsByValidationNode; + rewardTotal: number; +}) => { + const { listFormat } = useNominationGeoList(); + + const rewardShare = Math.round((node.TokenRewards / rewardTotal) * 1000) / 10; + + return ( + + +
+
+ +
+ +
+
+

+ {node.LastNetwork}, {node.LastCountry}, {node.LastRegion}{' '} + {node.Countries + node.Regions > 2 ? '++.' : '.'} +

+
+ + + + +
+
+
+
+ ); +}; diff --git a/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx b/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx index bc18b095b8..45b01e0e38 100644 --- a/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx +++ b/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx @@ -1,21 +1,11 @@ // Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors // SPDX-License-Identifier: GPL-3.0-only -import { - faBars, - faChartPie, - faExternalLinkAlt, - faGripVertical, -} from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { motion } from 'framer-motion'; -import { useTheme } from 'contexts/Themes'; +import { faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons'; import { Header, List, Wrapper as ListWrapper } from 'library/List'; import { MotionContainer } from 'library/List/MotionContainer'; -import { Identity } from 'library/ListItem/Labels/Identity'; -import { ItemWrapper } from '../Wrappers'; import type { NomninationGeoListProps } from '../types'; -import { NominationGeoListProvider, useNominationGeoList } from './context'; +import { NominationGeoListProvider } from './context'; import { useNetwork } from 'contexts/Network'; import { Separator } from 'kits/Structure/Separator'; import { ButtonPrimaryInvert } from 'kits/Buttons/ButtonPrimaryInvert'; @@ -23,9 +13,8 @@ import { useStaking } from 'contexts/Staking'; import { useActiveAccounts } from 'contexts/ActiveAccounts'; import { ButtonHelp } from 'kits/Buttons/ButtonHelp'; import { useHelp } from 'contexts/Help'; -import { TooltipTrigger } from 'library/ListItem/Wrappers'; -import { useTooltip } from 'contexts/Tooltip'; -import { useTranslation } from 'react-i18next'; +import { Node } from './Node'; +import { CardHeaderWrapper } from 'library/Card/Wrappers'; export const NominationGeoList = (props: NomninationGeoListProps) => ( @@ -38,123 +27,50 @@ export const NominationGeoListInner = ({ title, data, }: NomninationGeoListProps) => { - const { mode } = useTheme(); - const { t } = useTranslation('pages'); - const { - network, - networkData: { colors }, - } = useNetwork(); - const { listFormat, setListFormat } = useNominationGeoList(); + const { network } = useNetwork(); + const { openHelp } = useHelp(); const { isNominating } = useStaking(); const { activeAccount } = useActiveAccounts(); - const { openHelp } = useHelp(); - const { setTooltipTextAndOpen } = useTooltip(); if (!data?.nodeDistributionDetail) { return null; } - const totalRewards = data.nodeDistributionDetail.reduce( + const rewardTotal = data.nodeDistributionDetail.reduce( (acc, n) => acc + n.TokenRewards, 0 ); - - const tooltipText = t('decentralization.nominationShareInRewards'); - return ( <> -
-
-

{title}

- openHelp('Geolocation of Each Nomination')} - /> -
+
- - + +

+ {title} + openHelp('Nominations')} + /> +

+
{data.nodeDistributionDetail .sort((a, b) => b.TokenRewards - a.TokenRewards) - .map((n, index: number) => ( - - -
-
-
-
-

-

- {n.LastNetwork}, {n.LastCountry}, {n.LastRegion}{' '} - {n.Countries + n.Regions > 2 ? '++.' : '.'} -

-

-
-
-
-
-
-
-
- -
-
-
- - setTooltipTextAndOpen(tooltipText) - } - /> - {Math.round( - (n.TokenRewards / totalRewards) * 1000 - ) / 10}{' '} - %{' '} - -
-
-
-
-
- - + .map((node, i: number) => ( + ))} - +
.inner { - background: var(--background-list-item); - padding: 0 0.75rem; - flex: 1; - border-radius: 1rem; - display: flex; - flex-flow: column wrap; - align-items: center; - flex: 1; - max-width: 100%; - - > .row { - width: 100%; - display: flex; - flex-flow: row wrap; - align-items: center; - - &:first-child { - padding: 1rem 0 0.75rem 0; - } - - &:last-child { - border-top: 1px solid var(--border-primary-color); - padding-top: 0rem; - - > div { - min-height: 3.2rem; - } - } - - > div { - display: flex; - flex-flow: row wrap; - align-items: center; - flex: 1; - max-width: 100%; - - h4 { - color: var(--text-color-secondary); - font-family: InterSemiBold, sans-serif; - &.claim { - color: var(--accent-color-secondary); - } - &.reward { - color: var(--accent-color-primary); - } - } - - h5 { - color: var(--text-color-secondary); - &.claim { - color: var(--accent-color-secondary); - border: 1px solid var(--accent-color-secondary); - border-radius: 0.75rem; - padding: 0.2rem 0.5rem; - } - &.reward { - color: var(--accent-color-primary); - border: 1px solid var(--accent-color-primary); - border-radius: 0.75rem; - padding: 0.2rem 0.5rem; - } - } - - > div:first-child { - flex-grow: 1; - display: flex; - flex-flow: row wrap; - align-items: center; - } - - > div:last-child { - display: flex; - flex-flow: row wrap; - justify-content: flex-end; - - > h4 { - color: var(--text-color-secondary); - opacity: 0.8; - } - } - } - } - } -`; From 0944cbe73b16fa080b0154cbcf0abdeb2cbd0890 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 12:07:32 +0100 Subject: [PATCH 14/32] rm list format context --- .../NominationGeo/NominationGeoList/Node.tsx | 5 +-- .../NominationGeoList/context.tsx | 39 ------------------- .../NominationGeo/NominationGeoList/index.tsx | 9 +---- 3 files changed, 2 insertions(+), 51 deletions(-) delete mode 100644 src/pages/Nominate/NominationGeo/NominationGeoList/context.tsx diff --git a/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx b/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx index 3e2326e40b..1a2e87c55e 100644 --- a/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx +++ b/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: GPL-3.0-only import type { RewardsByValidationNode } from '@polkawatch/ddp-client'; -import { useNominationGeoList } from './context'; import { motion } from 'framer-motion'; import { Labels, Wrapper, Separator } from 'library/ListItem/Wrappers'; import { Identity } from 'library/ListItem/Labels/Identity'; @@ -15,13 +14,11 @@ export const Node = ({ node: RewardsByValidationNode; rewardTotal: number; }) => { - const { listFormat } = useNominationGeoList(); - const rewardShare = Math.round((node.TokenRewards / rewardTotal) * 1000) / 10; return ( ({ - // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars - setListFormat: (v: ListFormat) => {}, - listFormat: 'col', - }); - -export const useNominationGeoList = () => useContext(NominationGeoListContext); - -export const NominationGeoListProvider = ({ - children, -}: { - children: ReactNode; -}) => { - const [listFormat, _setListFormat] = useState('col'); - - const setListFormat = (v: ListFormat) => { - _setListFormat(v); - }; - - return ( - - {children} - - ); -}; diff --git a/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx b/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx index 45b01e0e38..f8671afac7 100644 --- a/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx +++ b/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx @@ -5,7 +5,6 @@ import { faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons'; import { Header, List, Wrapper as ListWrapper } from 'library/List'; import { MotionContainer } from 'library/List/MotionContainer'; import type { NomninationGeoListProps } from '../types'; -import { NominationGeoListProvider } from './context'; import { useNetwork } from 'contexts/Network'; import { Separator } from 'kits/Structure/Separator'; import { ButtonPrimaryInvert } from 'kits/Buttons/ButtonPrimaryInvert'; @@ -16,13 +15,7 @@ import { useHelp } from 'contexts/Help'; import { Node } from './Node'; import { CardHeaderWrapper } from 'library/Card/Wrappers'; -export const NominationGeoList = (props: NomninationGeoListProps) => ( - - - -); - -export const NominationGeoListInner = ({ +export const NominationGeoList = ({ allowMoreCols, title, data, From cf5133c69b0cd891080fc64d337ddb5ccc50abb9 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 12:13:21 +0100 Subject: [PATCH 15/32] fix cols --- .../Nominate/NominationGeo/NominationGeoList/Node.tsx | 2 +- .../Nominate/NominationGeo/NominationGeoList/index.tsx | 8 ++------ src/pages/Nominate/NominationGeo/index.tsx | 1 - src/pages/Nominate/NominationGeo/types.ts | 1 - 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx b/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx index 1a2e87c55e..6499e239dc 100644 --- a/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx +++ b/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx @@ -18,7 +18,7 @@ export const Node = ({ return ( { +export const NominationGeoList = ({ title, data }: NomninationGeoListProps) => { const { network } = useNetwork(); const { openHelp } = useHelp(); const { isNominating } = useStaking(); @@ -49,7 +45,7 @@ export const NominationGeoList = ({
- + {data.nodeDistributionDetail .sort((a, b) => b.TokenRewards - a.TokenRewards) diff --git a/src/pages/Nominate/NominationGeo/index.tsx b/src/pages/Nominate/NominationGeo/index.tsx index e4c1d4992c..1efa54653b 100644 --- a/src/pages/Nominate/NominationGeo/index.tsx +++ b/src/pages/Nominate/NominationGeo/index.tsx @@ -189,7 +189,6 @@ export const NominationGeo = () => { Date: Sun, 7 Jul 2024 12:13:37 +0100 Subject: [PATCH 16/32] fix locales --- src/locale/en/pages.json | 2 -- src/pages/Nominate/index.tsx | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/locale/en/pages.json b/src/locale/en/pages.json index 113b2955cf..ff9652cb4c 100644 --- a/src/locale/en/pages.json +++ b/src/locale/en/pages.json @@ -35,7 +35,6 @@ "change": "Change", "controllerAccount": "Controller Account", "controllerNotImported": "You have not imported your controller account. If you have lost access to your controller account, set a new one now. Otherwise, import the controller into one of your active extensions.", - "decentralization": "Decentralization", "earningRewards": "Earning Rewards", "inactiveNominations": "Inactive Nominations", "manage": "Manage", @@ -50,7 +49,6 @@ "notAssigned": "Not Assigned", "notEarningRewards": "Not Earning Rewards", "notNominating": "Not Nominating", - "overview": "Overview", "payoutDestination": "Payout Destination", "payoutDestinationSubtitle": "Choose how payouts will be received. Payouts can either be compounded or sent to an account as free balance.", "pendingPayouts": "Pending Payouts", diff --git a/src/pages/Nominate/index.tsx b/src/pages/Nominate/index.tsx index 9d6fd08fd5..783646aa67 100644 --- a/src/pages/Nominate/index.tsx +++ b/src/pages/Nominate/index.tsx @@ -10,17 +10,17 @@ import type { PageTitleTabProps } from 'kits/Structure/PageTitleTabs/types'; import { useState } from 'react'; export const Nominate = () => { - const { t } = useTranslation('pages'); + const { t } = useTranslation(); const [activeTab, setActiveTab] = useState(0); const tabs: PageTitleTabProps[] = [ { - title: t('nominate.overview'), + title: t('overview', { ns: 'base' }), active: activeTab === 0, onClick: () => setActiveTab(0), }, { - title: t('nominate.decentralization'), + title: t('decentralization', { ns: 'base' }), active: activeTab === 1, onClick: () => setActiveTab(1), }, From 8ebff17f7eb6758d7988f19868cf9e9135c768f6 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 12:15:24 +0100 Subject: [PATCH 17/32] capitalise title --- src/locale/en/pages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locale/en/pages.json b/src/locale/en/pages.json index ff9652cb4c..feb1f433a5 100644 --- a/src/locale/en/pages.json +++ b/src/locale/en/pages.json @@ -15,7 +15,7 @@ "analyticsNotAvailable": "Analytics Not Available", "analyticsNotSupported": "Analytics Not Supported", "byRegionCountryNetwork": "by Region, Country and Network", - "decentralizationPerNomination": "Geolocation per nomination", + "decentralizationPerNomination": "Geolocation per Nomination", "howDecentralizedIsYourNomination": "How decentralized is your Nomination?", "maxErasAnalyzed": "Max Eras Analysed", "nominationShareInRewards": "Share of rewards", From 93332759cfa910924a4288aac1af9aef9ab20b44 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 12:16:47 +0100 Subject: [PATCH 18/32] misc: fix changelog --- CHANGELOG.md | 10 ---------- docs/CHANGELOG.md | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 2328f3c90f..0000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,10 +0,0 @@ -# Changelog - -## [1.5.0](https://github.com/paritytech/polkadot-staking-dashboard/compare/v1.4.4...v1.5.0) (2024-06-12) - - -### Features - -* **refactor:** Remove pre-paged rewards code (part 1) ([#2101](https://github.com/paritytech/polkadot-staking-dashboard/issues/2101)) ([6fa02f9](https://github.com/paritytech/polkadot-staking-dashboard/commit/6fa02f9d394930d6f339d46dfc227fc0c70795ad)) -* **refactor:** Tidy up `TxMeta` context ([#2130](https://github.com/paritytech/polkadot-staking-dashboard/issues/2130)) ([95468bf](https://github.com/paritytech/polkadot-staking-dashboard/commit/95468bfcee68759560d5ea46b399d7c1756c3eaf)) -* **refactor:** Use `@w3ux/types` types ([#2156](https://github.com/paritytech/polkadot-staking-dashboard/issues/2156)) ([6db115a](https://github.com/paritytech/polkadot-staking-dashboard/commit/6db115a317b1ab3a8eb67e2c0cd08302af8da512)) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index fef413bd4e..e735f94c6d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [1.5.0](https://github.com/polkadot-cloud/polkadot-staking-dashboard/compare/v1.4.4...v1.5.0) (2024-06-12) + + +### Features + +* **refactor:** Remove pre-paged rewards code (part 1) ([#2101](https://github.com/polkadot-cloud/polkadot-staking-dashboard/issues/2101)) ([6fa02f9](https://github.com/polkadot-cloud/polkadot-staking-dashboard/commit/6fa02f9d394930d6f339d46dfc227fc0c70795ad)) +* **refactor:** Tidy up `TxMeta` context ([#2130](https://github.com/polkadot-cloud/polkadot-staking-dashboard/issues/2130)) ([95468bf](https://github.com/polkadot-cloud/polkadot-staking-dashboard/commit/95468bfcee68759560d5ea46b399d7c1756c3eaf)) +* **refactor:** Use `@w3ux/types` types ([#2156](https://github.com/polkadot-cloud/polkadot-staking-dashboard/issues/2156)) ([6db115a](https://github.com/polkadot-cloud/polkadot-staking-dashboard/commit/6db115a317b1ab3a8eb67e2c0cd08302af8da512)) + + ## [1.4.4](https://github.com/polkadot-cloud/polkadot-staking-dashboard/compare/v1.4.3...v1.4.4) (2024-04-23) From 6b687d2e7b07c1be9a231ee9bb58d11a42f70ff3 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 12:20:42 +0100 Subject: [PATCH 19/32] re-org stats, add label --- src/locale/cn/pages.json | 1 + src/locale/en/pages.json | 1 + src/pages/Nominate/NominationGeo/Stats/AnalyzedDays.tsx | 2 +- src/pages/Nominate/NominationGeo/index.tsx | 4 ++-- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/locale/cn/pages.json b/src/locale/cn/pages.json index fd28618c23..72d0e5a7ba 100644 --- a/src/locale/cn/pages.json +++ b/src/locale/cn/pages.json @@ -17,6 +17,7 @@ "decentralizationPerNomination": "每个提名的地理位置", "howDecentralizedIsYourNomination": "您的提名去中心化程度如何?", "maxErasAnalyzed": "最大分析Era数", + "maxDaysAnalyzed": "Max Days Analysed", "nominationShareInRewards": "奖励份额", "payoutDistribution": "收益分布", "polkawatchDisabled": "Polkawatch己断开", diff --git a/src/locale/en/pages.json b/src/locale/en/pages.json index feb1f433a5..05838a4c90 100644 --- a/src/locale/en/pages.json +++ b/src/locale/en/pages.json @@ -18,6 +18,7 @@ "decentralizationPerNomination": "Geolocation per Nomination", "howDecentralizedIsYourNomination": "How decentralized is your Nomination?", "maxErasAnalyzed": "Max Eras Analysed", + "maxDaysAnalyzed": "Max Days Analysed", "nominationShareInRewards": "Share of rewards", "payoutDistribution": "Payout Distribution", "polkawatchDisabled": "Polkawatch Disabled", diff --git a/src/pages/Nominate/NominationGeo/Stats/AnalyzedDays.tsx b/src/pages/Nominate/NominationGeo/Stats/AnalyzedDays.tsx index 8330ab141f..1dd4345055 100644 --- a/src/pages/Nominate/NominationGeo/Stats/AnalyzedDays.tsx +++ b/src/pages/Nominate/NominationGeo/Stats/AnalyzedDays.tsx @@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next'; export const AnalyzedDays = () => { const { t } = useTranslation('pages'); const params = { - label: t('decentralization.maxErasAnalyzed'), + label: t('decentralization.maxDaysAnalyzed'), value: 30, unit: 'Days', helpKey: 'Decentralization Analytics Period', diff --git a/src/pages/Nominate/NominationGeo/index.tsx b/src/pages/Nominate/NominationGeo/index.tsx index 1efa54653b..491ec1e957 100644 --- a/src/pages/Nominate/NominationGeo/index.tsx +++ b/src/pages/Nominate/NominationGeo/index.tsx @@ -102,9 +102,9 @@ export const NominationGeo = () => { return ( <> - - + + From d7dc3bbdabb21a5d3ce03b24ae8d7745187a2a42 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 12:21:57 +0100 Subject: [PATCH 20/32] fix locales --- src/locale/cn/pages.json | 2 +- src/locale/en/pages.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locale/cn/pages.json b/src/locale/cn/pages.json index 72d0e5a7ba..aa1cd428bc 100644 --- a/src/locale/cn/pages.json +++ b/src/locale/cn/pages.json @@ -16,8 +16,8 @@ "byRegionCountryNetwork": "按地区、国家和网络", "decentralizationPerNomination": "每个提名的地理位置", "howDecentralizedIsYourNomination": "您的提名去中心化程度如何?", - "maxErasAnalyzed": "最大分析Era数", "maxDaysAnalyzed": "Max Days Analysed", + "maxErasAnalyzed": "最大分析Era数", "nominationShareInRewards": "奖励份额", "payoutDistribution": "收益分布", "polkawatchDisabled": "Polkawatch己断开", diff --git a/src/locale/en/pages.json b/src/locale/en/pages.json index 05838a4c90..ffcbe1e86c 100644 --- a/src/locale/en/pages.json +++ b/src/locale/en/pages.json @@ -17,8 +17,8 @@ "byRegionCountryNetwork": "by Region, Country and Network", "decentralizationPerNomination": "Geolocation per Nomination", "howDecentralizedIsYourNomination": "How decentralized is your Nomination?", - "maxErasAnalyzed": "Max Eras Analysed", "maxDaysAnalyzed": "Max Days Analysed", + "maxErasAnalyzed": "Max Eras Analysed", "nominationShareInRewards": "Share of rewards", "payoutDistribution": "Payout Distribution", "polkawatchDisabled": "Polkawatch Disabled", From 75a70439afadfabc4bf11ff88dc8768a9100ead4 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 13:37:56 +0100 Subject: [PATCH 21/32] progress graph behaviour --- src/library/Graphs/GeoDonut.tsx | 2 +- src/pages/Nominate/NominationGeo/Wrappers.ts | 11 ++ src/pages/Nominate/NominationGeo/index.tsx | 119 +++++++++++-------- 3 files changed, 84 insertions(+), 48 deletions(-) create mode 100644 src/pages/Nominate/NominationGeo/Wrappers.ts diff --git a/src/library/Graphs/GeoDonut.tsx b/src/library/Graphs/GeoDonut.tsx index 8d8938bbe7..d708d701a0 100644 --- a/src/library/Graphs/GeoDonut.tsx +++ b/src/library/Graphs/GeoDonut.tsx @@ -43,7 +43,7 @@ export const GeoDonut = ({ responsive: true, maintainAspectRatio: false, spacing: 0, - cutout: '70%', + cutout: '75%', plugins: { legend: { display: true, diff --git a/src/pages/Nominate/NominationGeo/Wrappers.ts b/src/pages/Nominate/NominationGeo/Wrappers.ts new file mode 100644 index 0000000000..ffcf3e849d --- /dev/null +++ b/src/pages/Nominate/NominationGeo/Wrappers.ts @@ -0,0 +1,11 @@ +// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import styled from 'styled-components'; + +export const GraphsWrapper = styled.div` + margin-top: 0.5rem; + display: flex; + justify-content: space-evenly; + flex-wrap: wrap; +`; diff --git a/src/pages/Nominate/NominationGeo/index.tsx b/src/pages/Nominate/NominationGeo/index.tsx index 491ec1e957..157f5c0741 100644 --- a/src/pages/Nominate/NominationGeo/index.tsx +++ b/src/pages/Nominate/NominationGeo/index.tsx @@ -24,27 +24,29 @@ import { GraphWrapper } from 'library/Graphs/Wrapper'; import { GeoDonut } from 'library/Graphs/GeoDonut'; import { ButtonHelp } from 'kits/Buttons/ButtonHelp'; import { useHelp } from 'contexts/Help'; -import { Separator } from 'kits/Structure/Separator'; import { NominationGeoList } from './NominationGeoList'; import { StatusLabel } from 'library/StatusLabel'; +import { GraphsWrapper } from './Wrappers'; +import { useStaking } from 'contexts/Staking'; export const NominationGeo = () => { - const { activeAccount } = useActiveAccounts(); const { t } = useTranslation(); const { openHelp } = useHelp(); const { network } = useNetwork(); + const { isNominating } = useStaking(); const { pluginEnabled } = usePlugins(); + const { activeAccount } = useActiveAccounts(); + const enabled = pluginEnabled('polkawatch'); // Polkawatch Analytics chain metadata, contains information about how the decentralization is 1 // computed for this particular blockchain - const [networkMeta, setNetworkMeta] = useState( {} as ChainMetadata ); useEffect(() => { - if (networkSupported && enabled) { + if (networkSupported && enabled && isNominating()) { const polkaWatchApi = new PolkawatchApi( PolkaWatchController.apiConfig(network) ); @@ -62,7 +64,7 @@ export const NominationGeo = () => { setNetworkMeta({} as ChainMetadata); setAnalyticsAvailable(false); } - }, [network]); + }, [network, isNominating()]); const [nominationDetail, setNominationDetail] = useState( {} as NominatorDetail @@ -73,6 +75,20 @@ export const NominationGeo = () => { const networkSupported = PolkaWatchController.SUPPORTED_NETWORKS.includes(network); + // Min height of the graph container. + const graphContainerMinHeight = analyticsAvailable ? 320 : 25; + + // Donut size and legend height. + const donutSize = '300px'; + const legendHeight = 50; + const maxLabelLen = 10; + + // Status label config. + const showDisabledLabel = !enabled; + const showNotNominatingLabel = enabled && !isNominating(); + const showNotAvailableLabel = + enabled && !analyticsAvailable && isNominating(); + // Please note that the list of dependencies assume that changing network // triggers a change of account also (i.e. different network prefix). useEffect(() => { @@ -121,16 +137,9 @@ export const NominationGeo = () => { {t('decentralization.byRegionCountryNetwork', { ns: 'pages' })} - -
- {!enabled || analyticsAvailable ? ( + + + {showDisabledLabel && ( { ns: 'pages', })} /> - ) : ( + )} + + {showNotNominatingLabel && ( + + )} + + {showNotAvailableLabel && ( { } /> )} - - - - - - - - - -
+ + {enabled && analyticsAvailable && ( + <> + + + + + + + + + + + )} +
{nominationDetail?.nodeDistributionDetail && ( From 50f9872f80824b80819e2614f7c507c638195499 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 13:39:11 +0100 Subject: [PATCH 22/32] fix useEffect on plugin toggle --- src/pages/Nominate/NominationGeo/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Nominate/NominationGeo/index.tsx b/src/pages/Nominate/NominationGeo/index.tsx index 157f5c0741..d0422d3d07 100644 --- a/src/pages/Nominate/NominationGeo/index.tsx +++ b/src/pages/Nominate/NominationGeo/index.tsx @@ -64,7 +64,7 @@ export const NominationGeo = () => { setNetworkMeta({} as ChainMetadata); setAnalyticsAvailable(false); } - }, [network, isNominating()]); + }, [network, enabled, isNominating()]); const [nominationDetail, setNominationDetail] = useState( {} as NominatorDetail @@ -113,7 +113,7 @@ export const NominationGeo = () => { setNominationDetail({} as NominatorDetail); setAnalyticsAvailable(false); } - }, [activeAccount]); + }, [activeAccount, enabled]); return ( <> From 17868fcfeb99d7b28d160640352bc5d489d02a27 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 13:42:16 +0100 Subject: [PATCH 23/32] misc fixes --- src/locale/en/pages.json | 2 +- src/pages/Nominate/NominationGeo/index.tsx | 51 ++++++++++++---------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/locale/en/pages.json b/src/locale/en/pages.json index ffcbe1e86c..d1f9a464f9 100644 --- a/src/locale/en/pages.json +++ b/src/locale/en/pages.json @@ -15,7 +15,7 @@ "analyticsNotAvailable": "Analytics Not Available", "analyticsNotSupported": "Analytics Not Supported", "byRegionCountryNetwork": "by Region, Country and Network", - "decentralizationPerNomination": "Geolocation per Nomination", + "decentralizationPerNomination": "Geolocation Per Nomination", "howDecentralizedIsYourNomination": "How decentralized is your Nomination?", "maxDaysAnalyzed": "Max Days Analysed", "maxErasAnalyzed": "Max Eras Analysed", diff --git a/src/pages/Nominate/NominationGeo/index.tsx b/src/pages/Nominate/NominationGeo/index.tsx index d0422d3d07..c062bc999b 100644 --- a/src/pages/Nominate/NominationGeo/index.tsx +++ b/src/pages/Nominate/NominationGeo/index.tsx @@ -45,27 +45,6 @@ export const NominationGeo = () => { {} as ChainMetadata ); - useEffect(() => { - if (networkSupported && enabled && isNominating()) { - const polkaWatchApi = new PolkawatchApi( - PolkaWatchController.apiConfig(network) - ); - polkaWatchApi - .ddpIpfsAboutChain() - .then((response) => { - setAnalyticsAvailable(true); - setNetworkMeta(response.data); - }) - .catch(() => { - setNetworkMeta({} as ChainMetadata); - setAnalyticsAvailable(false); - }); - } else { - setNetworkMeta({} as ChainMetadata); - setAnalyticsAvailable(false); - } - }, [network, enabled, isNominating()]); - const [nominationDetail, setNominationDetail] = useState( {} as NominatorDetail ); @@ -89,10 +68,34 @@ export const NominationGeo = () => { const showNotAvailableLabel = enabled && !analyticsAvailable && isNominating(); - // Please note that the list of dependencies assume that changing network + // Whether to interact with Polkawatch API. + const callPolkawatchApi = networkSupported && enabled && isNominating(); + + useEffect(() => { + if (callPolkawatchApi) { + const polkaWatchApi = new PolkawatchApi( + PolkaWatchController.apiConfig(network) + ); + polkaWatchApi + .ddpIpfsAboutChain() + .then((response) => { + setAnalyticsAvailable(true); + setNetworkMeta(response.data); + }) + .catch(() => { + setNetworkMeta({} as ChainMetadata); + setAnalyticsAvailable(false); + }); + } else { + setNetworkMeta({} as ChainMetadata); + setAnalyticsAvailable(false); + } + }, [activeAccount, network, enabled, isNominating()]); + + // NOTE: The list of dependencies assume that changing network // triggers a change of account also (i.e. different network prefix). useEffect(() => { - if (networkSupported && enabled) { + if (callPolkawatchApi) { const polkaWatchApi = new PolkawatchApi( PolkaWatchController.apiConfig(network) ); @@ -113,7 +116,7 @@ export const NominationGeo = () => { setNominationDetail({} as NominatorDetail); setAnalyticsAvailable(false); } - }, [activeAccount, enabled]); + }, [activeAccount, network, enabled, isNominating()]); return ( <> From bc0f73a1a23d81d54e75575cb1aada14043b95e0 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 13:43:50 +0100 Subject: [PATCH 24/32] fixes --- src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx | 2 +- src/pages/Nominate/NominationGeo/index.tsx | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx b/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx index 49bac738b3..0cf17e348f 100644 --- a/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx +++ b/src/pages/Nominate/NominationGeo/NominationGeoList/index.tsx @@ -39,7 +39,7 @@ export const NominationGeoList = ({ title, data }: NomninationGeoListProps) => { {title} openHelp('Nominations')} + onClick={() => openHelp('Geolocation of Each Nomination')} /> diff --git a/src/pages/Nominate/NominationGeo/index.tsx b/src/pages/Nominate/NominationGeo/index.tsx index c062bc999b..83f7754ddc 100644 --- a/src/pages/Nominate/NominationGeo/index.tsx +++ b/src/pages/Nominate/NominationGeo/index.tsx @@ -151,7 +151,6 @@ export const NominationGeo = () => { })} /> )} - {showNotNominatingLabel && ( { })} /> )} - {showNotAvailableLabel && ( { } /> )} - {enabled && analyticsAvailable && ( <> From 74fe4d813703a34ff741198766892e239167d47a Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 19:44:34 +0700 Subject: [PATCH 25/32] Update src/locale/cn/pages.json Co-authored-by: Ting A Lin --- src/locale/cn/pages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locale/cn/pages.json b/src/locale/cn/pages.json index aa1cd428bc..4bfb5a3fd8 100644 --- a/src/locale/cn/pages.json +++ b/src/locale/cn/pages.json @@ -16,7 +16,7 @@ "byRegionCountryNetwork": "按地区、国家和网络", "decentralizationPerNomination": "每个提名的地理位置", "howDecentralizedIsYourNomination": "您的提名去中心化程度如何?", - "maxDaysAnalyzed": "Max Days Analysed", + "maxDaysAnalyzed": "分析的最大天数", "maxErasAnalyzed": "最大分析Era数", "nominationShareInRewards": "奖励份额", "payoutDistribution": "收益分布", From 5e14aa24ee7b192692d5d2d09b9b609f2b013037 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 19:48:55 +0700 Subject: [PATCH 26/32] Update src/locale/en/help.json --- src/locale/en/help.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locale/en/help.json b/src/locale/en/help.json index a4acc5e7c6..63a8c50918 100644 --- a/src/locale/en/help.json +++ b/src/locale/en/help.json @@ -106,7 +106,7 @@ "geolocationOfEachNomination": [ "Geolocation of Each Nomination", [ - "Each nominated validator runs at a given datacenter that can be geolocated by its IP address. ", + "Each nominated validator runs at a given data center that can be geolocated by its IP address.", "The table displays the last Region, Country and Network where each nominated validator was geolocated.", "When the validator has been located at more than one location during the analytic period a ++ sign will be displayed.", "The percentage shown is the proportion of rewards payed out to you by this validator in the analytic period." From 63b950cf8becac79f556b1dd87a9065e7e07a180 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 19:49:00 +0700 Subject: [PATCH 27/32] Update src/locale/en/help.json --- src/locale/en/help.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/locale/en/help.json b/src/locale/en/help.json index 63a8c50918..dbacf7ecd5 100644 --- a/src/locale/en/help.json +++ b/src/locale/en/help.json @@ -76,10 +76,8 @@ "decentralizationAnalyticsPeriod": [ "Decentralization Analytics Period", [ - "The decentralization of your nomination is calculated analysing the rewards payed out in the last 30 days.", - "Depending on the Network this will translate into a number of Eras.", - "30 days provides enough information for the aggregation to be meaningful.", - "30 days is also short enough for changes in nominations to start impacting this analysis after a few days." + "The decentralization of your nomination is calculated by analysing the rewards payed out in the last 30 days. Depending on the network, this will translate into a number of Eras.", + "30 days provides enough information for the aggregation to be meaningful, and is also short enough for changes in nominations to start impacting this analysis after a few days." ] ], "epoch": [ From 0d5bc468b0b7894ab3d8e9a464d9f36272fe4a6e Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 19:49:05 +0700 Subject: [PATCH 28/32] Update src/locale/en/help.json --- src/locale/en/help.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locale/en/help.json b/src/locale/en/help.json index dbacf7ecd5..5baaba9bec 100644 --- a/src/locale/en/help.json +++ b/src/locale/en/help.json @@ -105,7 +105,7 @@ "Geolocation of Each Nomination", [ "Each nominated validator runs at a given data center that can be geolocated by its IP address.", - "The table displays the last Region, Country and Network where each nominated validator was geolocated.", + "The table displays the last region, country and network where each nominated validator was geolocated.", "When the validator has been located at more than one location during the analytic period a ++ sign will be displayed.", "The percentage shown is the proportion of rewards payed out to you by this validator in the analytic period." ] From 71dd4b168f483c57477cc283908ac1f7470c9b63 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 19:49:09 +0700 Subject: [PATCH 29/32] Update src/locale/en/help.json --- src/locale/en/help.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locale/en/help.json b/src/locale/en/help.json index 5baaba9bec..c6ad0951aa 100644 --- a/src/locale/en/help.json +++ b/src/locale/en/help.json @@ -201,7 +201,7 @@ "Nomination Payout Distribution", [ "The decentralization of your nomination.", - "The following charts display the distribution of rewards aggregated by the Region, Country and IP Network of the validator the payed out the reward." + "The following charts display the distribution of rewards aggregated by the region, country and IP network of the validator the payed out the reward." ] ], "nominationPools": [ From fb89ceafdbe297a4e079722b88ed01c04f098191 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 13:50:51 +0100 Subject: [PATCH 30/32] amend text --- src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx b/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx index 6499e239dc..c269c0e492 100644 --- a/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx +++ b/src/pages/Nominate/NominationGeo/NominationGeoList/Node.tsx @@ -40,7 +40,7 @@ export const Node = ({

{node.LastNetwork}, {node.LastCountry}, {node.LastRegion}{' '} - {node.Countries + node.Regions > 2 ? '++.' : '.'} + {node.Countries + node.Regions > 2 ? ', ++' : ''}

From 2799de2159ae9f9897a01e2c8c628cfed5ba0845 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Sun, 7 Jul 2024 13:56:03 +0100 Subject: [PATCH 31/32] lint --- .github/workflows/gh-pages.yml | 19 +++++++++--------- README.md | 1 + index.html | 10 ++++++++-- public/favicons/site.webmanifest | 34 ++++++++++++++++---------------- 4 files changed, 35 insertions(+), 29 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index b6ab1b9e3f..5518f1a01a 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -25,7 +25,6 @@ jobs: target_branch: gh-deploy github_token: ${{ secrets.GITHUB_TOKEN }} - build: runs-on: ubuntu-latest needs: merge @@ -51,7 +50,7 @@ jobs: with: name: github-pages path: build - + deploy: runs-on: ubuntu-latest needs: build @@ -63,12 +62,12 @@ jobs: environment: name: github-pages url: ${{steps.deployment.outputs.page_url}} - + steps: - - uses: actions/download-artifact@master - with: - name: github-pages - path: build - - uses: actions/configure-pages@v5 - - id: deployment - uses: actions/deploy-pages@main \ No newline at end of file + - uses: actions/download-artifact@master + with: + name: github-pages + path: build + - uses: actions/configure-pages@v5 + - id: deployment + uses: actions/deploy-pages@main diff --git a/README.md b/README.md index 01f5f58437..a2da459e16 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ [![Polkadot - App](https://img.shields.io/badge/Polkadot-App-E6007A?logo=polkadot&logoColor=E6007A)](https://staking.polkadot.cloud) ![ci](https://github.com/polkadot-cloud/polkadot-staking-dashboard/actions/workflows/ci.yml/badge.svg) [![License](https://img.shields.io/badge/License-GPL3.0-blue.svg)](https://opensource.org/licenses/GPL-3.0) > #### 📢 17/06/2024: Repository Migration +> > This repository was previously at `paritytech/polkadot-staking-dashboard`. As of 17/06/2024, Polkadot Staking Dashboard lives at `polkadot-cloud/polkadot-staking-dashboard`. # Polkadot Staking Dashboard diff --git a/index.html b/index.html index 06d26e3199..55d24f6139 100644 --- a/index.html +++ b/index.html @@ -48,7 +48,10 @@ property="og:description" content="Polkadot Staking Dashboard is the easiest way to stake DOT, check validator stats, manage your nominations and join nomination pools. Stake on Polkadot (DOT)." /> - + @@ -61,7 +64,10 @@ property="twitter:description" content="Polkadot Staking Dashboard is the easiest way to stake DOT, check validator stats, manage your nominations and join nomination pools. Stake on Polkadot (DOT)." /> - + Date: Mon, 8 Jul 2024 09:07:20 +0100 Subject: [PATCH 32/32] hide tabs if polkawatch disabled --- src/pages/Nominate/index.tsx | 40 ++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/pages/Nominate/index.tsx b/src/pages/Nominate/index.tsx index 783646aa67..8bcc847a34 100644 --- a/src/pages/Nominate/index.tsx +++ b/src/pages/Nominate/index.tsx @@ -7,24 +7,38 @@ import { Wrapper } from './Wrappers'; import { PageTitle } from '../../kits/Structure/PageTitle'; import { useTranslation } from 'react-i18next'; import type { PageTitleTabProps } from 'kits/Structure/PageTitleTabs/types'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; +import { usePlugins } from 'contexts/Plugins'; export const Nominate = () => { const { t } = useTranslation(); + const { pluginEnabled } = usePlugins(); + const [activeTab, setActiveTab] = useState(0); - const tabs: PageTitleTabProps[] = [ - { - title: t('overview', { ns: 'base' }), - active: activeTab === 0, - onClick: () => setActiveTab(0), - }, - { - title: t('decentralization', { ns: 'base' }), - active: activeTab === 1, - onClick: () => setActiveTab(1), - }, - ]; + // Only include tabs if the Polkawatch plugin is enabled. + let tabs: PageTitleTabProps[] | undefined = undefined; + if (pluginEnabled('polkawatch')) { + tabs = [ + { + title: t('overview', { ns: 'base' }), + active: activeTab === 0, + onClick: () => setActiveTab(0), + }, + { + title: t('decentralization', { ns: 'base' }), + active: activeTab === 1, + onClick: () => setActiveTab(1), + }, + ]; + } + + // Go back to the first tab if the Polkawatch plugin is disabled. + useEffect(() => { + if (!pluginEnabled('polkawatch')) { + setActiveTab(0); + } + }, [pluginEnabled('polkawatch')]); return (