From 8f48ae08c4d99fd7f00ff3b08789b01f586df491 Mon Sep 17 00:00:00 2001 From: Yana Matrosova <42305364+yanok87@users.noreply.github.com> Date: Tue, 28 Jan 2025 19:30:45 +0200 Subject: [PATCH] Redirect from mixnode page to nodes page (#5397) Co-authored-by: Yana --- .../network-components/nodes/[id]/page.tsx | 356 ++++++++++-------- explorer-nextjs/next.config.mjs | 12 +- explorer-nextjs/tsconfig.json | 3 +- 3 files changed, 220 insertions(+), 151 deletions(-) diff --git a/explorer-nextjs/app/network-components/nodes/[id]/page.tsx b/explorer-nextjs/app/network-components/nodes/[id]/page.tsx index 2f92542b3b..95a172d21e 100644 --- a/explorer-nextjs/app/network-components/nodes/[id]/page.tsx +++ b/explorer-nextjs/app/network-components/nodes/[id]/page.tsx @@ -1,62 +1,62 @@ -'use client' +"use client"; -import * as React from 'react' -import { Alert, AlertTitle, Box, CircularProgress, Grid } from '@mui/material' -import { useParams } from 'next/navigation' -import { ColumnsType, DetailTable } from '@/app/components/DetailTable' -import { ComponentError } from '@/app/components/ComponentError' -import { ContentCard } from '@/app/components/ContentCard' -import { UptimeChart } from '@/app/components/UptimeChart' -import { - NymNodeContextProvider, - useNymNodeContext, -} from '@/app/context/node' -import { useMainContext } from '@/app/context/main' -import { Title } from '@/app/components/Title' +import * as React from "react"; +import { Alert, AlertTitle, Box, CircularProgress, Grid } from "@mui/material"; +import { useParams } from "next/navigation"; +import { ColumnsType, DetailTable } from "@/app/components/DetailTable"; +import { ComponentError } from "@/app/components/ComponentError"; +import { ContentCard } from "@/app/components/ContentCard"; +import { UptimeChart } from "@/app/components/UptimeChart"; +import { NymNodeContextProvider, useNymNodeContext } from "@/app/context/node"; +import { useMainContext } from "@/app/context/main"; +import { Title } from "@/app/components/Title"; import Paper from "@mui/material/Paper"; -import Table from '@mui/material/Table'; -import TableBody from '@mui/material/TableBody'; -import TableCell from '@mui/material/TableCell'; -import TableContainer from '@mui/material/TableContainer'; -import TableRow from '@mui/material/TableRow'; -import {humanReadableCurrencyToString} from "@/app/utils/currency"; -import {DeclaredRole} from "@/app/network-components/nodes/DeclaredRole"; -import {NodeDelegationsTable, VestingDelegationWarning} from "@/app/network-components/nodes/[id]/NodeDelegationsTable"; +import Table from "@mui/material/Table"; +import TableBody from "@mui/material/TableBody"; +import TableCell from "@mui/material/TableCell"; +import TableContainer from "@mui/material/TableContainer"; +import TableRow from "@mui/material/TableRow"; +import { humanReadableCurrencyToString } from "@/app/utils/currency"; +import { DeclaredRole } from "@/app/network-components/nodes/DeclaredRole"; +import { + NodeDelegationsTable, + VestingDelegationWarning, +} from "@/app/network-components/nodes/[id]/NodeDelegationsTable"; const columns: ColumnsType[] = [ { - field: 'identity_key', - title: 'Identity Key', - headerAlign: 'left', + field: "identity_key", + title: "Identity Key", + headerAlign: "left", width: 230, }, { - field: 'bond', - title: 'Bond', - headerAlign: 'left', + field: "bond", + title: "Bond", + headerAlign: "left", }, { - field: 'host', - title: 'IP', - headerAlign: 'left', + field: "host", + title: "IP", + headerAlign: "left", width: 99, }, { - field: 'location', - title: 'Location', - headerAlign: 'left', + field: "location", + title: "Location", + headerAlign: "left", }, { - field: 'owner', - title: 'Owner', - headerAlign: 'left', + field: "owner", + title: "Owner", + headerAlign: "left", }, { - field: 'version', - title: 'Version', - headerAlign: 'left', + field: "version", + title: "Version", + headerAlign: "left", }, -] +]; interface NodeEnrichedRowType { node_id: number; @@ -71,28 +71,33 @@ interface NodeEnrichedRowType { function nodeEnrichedToGridRow(node: any): NodeEnrichedRowType { return { node_id: node.node_id, - owner: node.bond_information?.owner || '', - identity_key: node.bond_information?.node?.identity_key || '', - location: node.location?.country_name || '', + owner: node.bond_information?.owner || "", + identity_key: node.bond_information?.node?.identity_key || "", + location: node.location?.country_name || "", bond: node.bond_information?.original_pledge.amount || 0, // TODO: format - host: node.bond_information?.node?.host || '', - version: node.description?.build_information?.build_version || '', + host: node.bond_information?.node?.host || "", + version: node.description?.build_information?.build_version || "", }; } - /** * Shows nym node details */ const PageNymNodeDetailsWithState = ({ selectedNymNode, }: { - selectedNymNode?: any + selectedNymNode?: any; }) => { - const { uptimeHistory } = useNymNodeContext() - const enrichedData = React.useMemo(() => selectedNymNode ? [nodeEnrichedToGridRow(selectedNymNode)] : [], []); + const { uptimeHistory } = useNymNodeContext(); + const enrichedData = React.useMemo( + () => (selectedNymNode ? [nodeEnrichedToGridRow(selectedNymNode)] : []), + [] + ); - const hasVestingContractDelegations = React.useMemo(() => selectedNymNode?.delegations?.filter((d: any) => d.proxy)?.length, [selectedNymNode]); + const hasVestingContractDelegations = React.useMemo( + () => selectedNymNode?.delegations?.filter((d: any) => d.proxy)?.length, + [selectedNymNode] + ); return ( @@ -109,81 +114,128 @@ const PageNymNodeDetailsWithState = ({ - {selectedNymNode.rewarding_details && - - - - - - - Delegations and Rewards - - - - - Operator - - - {humanReadableCurrencyToString({ amount : selectedNymNode.rewarding_details.operator.split('.')[0], denom: "unym" })} - - - - - - {hasVestingContractDelegations ? - - Delegates ({selectedNymNode.rewarding_details.unique_delegations} delegates) - : - <>Delegates ({selectedNymNode.rewarding_details.unique_delegations} delegates) - } - - - - {humanReadableCurrencyToString({ amount : selectedNymNode.rewarding_details.delegates.split('.')[0], denom: "unym" })} - - - - - Profit margin - - - {selectedNymNode.rewarding_details.cost_params.profit_margin_percent * 100}% - - - - - Operator costs - - - {humanReadableCurrencyToString(selectedNymNode.rewarding_details.cost_params.interval_operating_cost)} - - - -
-
-
} + {selectedNymNode.rewarding_details && ( + + + + + + Delegations and Rewards + + + + Operator + + + {humanReadableCurrencyToString({ + amount: + selectedNymNode.rewarding_details.operator.split( + "." + )[0], + denom: "unym", + })} + + + + + + {hasVestingContractDelegations ? ( + + Delegates ( + { + selectedNymNode.rewarding_details + .unique_delegations + }{" "} + delegates) + + ) : ( + <> + Delegates ( + { + selectedNymNode.rewarding_details + .unique_delegations + }{" "} + delegates) + + )} + + + + {humanReadableCurrencyToString({ + amount: + selectedNymNode.rewarding_details.delegates.split( + "." + )[0], + denom: "unym", + })} + + + + + Profit margin + + + {selectedNymNode.rewarding_details.cost_params + .profit_margin_percent * 100} + % + + + + + Operator costs + + + {humanReadableCurrencyToString( + selectedNymNode.rewarding_details.cost_params + .interval_operating_cost + )} + + + +
+
+
+ )} - {selectedNymNode.description?.declared_role && - - - - - - Node roles - - - - - Self declared roles - - - - - - -
-
-
} + {selectedNymNode.description?.declared_role && ( + + + + + + Node roles + + + Self declared roles + + + + + +
+
+
+ )}
@@ -205,42 +257,41 @@ const PageNymNodeDetailsWithState = ({ - +
- ) -} + ); +}; /** * Guard component to handle loading and not found states */ const PageNymNodeDetailGuard = () => { - const [selectedNode, setSelectedNode] = React.useState() + const [selectedNode, setSelectedNode] = React.useState(); const [isLoading, setLoading] = React.useState(true); const [error, setError] = React.useState(); - const { fetchNodeById } = useMainContext() - const { id } = useParams() + const { fetchNodeById } = useMainContext(); + const { id } = useParams(); React.useEffect(() => { setSelectedNode(undefined); setLoading(true); (async () => { - if(typeof(id) === "string") { + if (typeof id === "string") { try { const res = await fetchNodeById(Number.parseInt(id)); setSelectedNode(res); - } catch(e: any) { + } catch (e: any) { setError(e.message); - } - finally { + } finally { setLoading(false); } } })(); - }, [id]) + }, [id, fetchNodeById]); if (isLoading) { - return + return ; } // loaded, but not found @@ -248,31 +299,38 @@ const PageNymNodeDetailGuard = () => { return ( Nym node not found - Sorry, we could not find a node with id {id || ''} + Sorry, we could not find a node with id {id || ""} - ) + ); } - return -} + if (!selectedNode) { + return ( + + Legacy Node + Unable to load details for the selected Nym node. + + ); + } + + return ; +}; /** * Wrapper component that adds the node content based on the `id` in the address URL */ const PageNymNodeDetail = () => { - const { id } = useParams() + const { id } = useParams(); - if (!id || typeof id !== 'string') { - return ( - Oh no! Could not find that node - ) + if (!id || typeof id !== "string") { + return Oh no! Could not find that node; } return ( - ) -} + ); +}; -export default PageNymNodeDetail +export default PageNymNodeDetail; diff --git a/explorer-nextjs/next.config.mjs b/explorer-nextjs/next.config.mjs index 4678774e6d..d642290145 100644 --- a/explorer-nextjs/next.config.mjs +++ b/explorer-nextjs/next.config.mjs @@ -1,4 +1,14 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + async redirects() { + return [ + { + source: '/network-components/mixnode/:id', // Match the old URL + destination: '/network-components/nodes/:id', // Redirect to the new URL + permanent: true, + }, + ]; + }, +}; export default nextConfig; diff --git a/explorer-nextjs/tsconfig.json b/explorer-nextjs/tsconfig.json index 68ef0fdf3b..701d0e6984 100644 --- a/explorer-nextjs/tsconfig.json +++ b/explorer-nextjs/tsconfig.json @@ -28,7 +28,8 @@ "../assets/*" ] }, - "moduleResolution": "node" + "moduleResolution": "node", + "target": "ES2017" }, "include": [ "next-env.d.ts",