Add remark42 to Mixnode page

This commit is contained in:
Yana
2024-11-04 20:25:41 +07:00
parent 147ec12a28
commit fd62ee8204
5 changed files with 191 additions and 65 deletions
@@ -1,6 +1,6 @@
'use client'
"use client";
import * as React from 'react'
import * as React from "react";
import {
Alert,
AlertTitle,
@@ -8,75 +8,102 @@ import {
CircularProgress,
Grid,
Typography,
} from '@mui/material'
import { ColumnsType, DetailTable } from '@/app/components/DetailTable'
import { BondBreakdownTable } from '@/app/components/MixNodes/BondBreakdown'
} from "@mui/material";
import { useTheme } from "@mui/material/styles";
import { ColumnsType, DetailTable } from "@/app/components/DetailTable";
import { BondBreakdownTable } from "@/app/components/MixNodes/BondBreakdown";
import {
DelegatorsInfoTable,
EconomicsInfoColumns,
EconomicsInfoRows,
} from '@/app/components/MixNodes/Economics'
import { ComponentError } from '@/app/components/ComponentError'
import { ContentCard } from '@/app/components/ContentCard'
import { TwoColSmallTable } from '@/app/components/TwoColSmallTable'
import { UptimeChart } from '@/app/components/UptimeChart'
import { WorldMap } from '@/app/components/WorldMap'
import { MixNodeDetailSection } from '@/app/components/MixNodes/DetailSection'
} from "@/app/components/MixNodes/Economics";
import { ComponentError } from "@/app/components/ComponentError";
import { ContentCard } from "@/app/components/ContentCard";
import { TwoColSmallTable } from "@/app/components/TwoColSmallTable";
import { UptimeChart } from "@/app/components/UptimeChart";
import { WorldMap } from "@/app/components/WorldMap";
import { MixNodeDetailSection } from "@/app/components/MixNodes/DetailSection";
import {
MixnodeContextProvider,
useMixnodeContext,
} from '@/app/context/mixnode'
import { Title } from '@/app/components/Title'
import { useIsMobile } from '@/app/hooks/useIsMobile'
import { useParams } from 'next/navigation'
} from "@/app/context/mixnode";
import { Title } from "@/app/components/Title";
import { useIsMobile } from "@/app/hooks/useIsMobile";
import { useParams } from "next/navigation";
import Script from "next/script";
import Head from "next/head";
import { useEffect } from "react";
import { useMainContext } from "@/app/context/main";
const columns: ColumnsType[] = [
{
field: 'owner',
title: 'Owner',
width: '15%',
field: "owner",
title: "Owner",
width: "15%",
},
{
field: 'identity_key',
title: 'Identity Key',
width: '15%',
field: "identity_key",
title: "Identity Key",
width: "15%",
},
{
field: 'bond',
title: 'Stake',
width: '12.5%',
field: "bond",
title: "Stake",
width: "12.5%",
},
{
field: 'stake_saturation',
title: 'Stake Saturation',
width: '12.5%',
field: "stake_saturation",
title: "Stake Saturation",
width: "12.5%",
tooltipInfo:
'Level of stake saturation for this node. Nodes receive more rewards the higher their saturation level, up to 100%. Beyond 100% no additional rewards are granted. The current stake saturation level is 940k NYMs, computed as S/K where S is target amount of tokens staked in the network and K is the number of nodes in the reward set.',
"Level of stake saturation for this node. Nodes receive more rewards the higher their saturation level, up to 100%. Beyond 100% no additional rewards are granted. The current stake saturation level is 940k NYMs, computed as S/K where S is target amount of tokens staked in the network and K is the number of nodes in the reward set.",
},
{
field: 'self_percentage',
width: '10%',
title: 'Bond %',
field: "self_percentage",
width: "10%",
title: "Bond %",
tooltipInfo:
"Percentage of the operator's bond to the total stake on the node",
},
{
field: 'host',
width: '10%',
title: 'Host',
field: "host",
width: "10%",
title: "Host",
},
{
field: 'location',
title: 'Location',
field: "location",
title: "Location",
},
{
field: 'layer',
title: 'Layer',
field: "layer",
title: "Layer",
},
]
];
declare global {
interface Window {
remark_config: {
host: string;
site_id: string;
components: string[];
max_shown_comments: number;
theme: string;
page_title: string;
locale: string;
show_email_subscription: boolean;
simple_view: boolean;
no_footer: boolean;
};
REMARK42: {
createInstance: (config: typeof window.remark_config) => void;
changeTheme: (theme: "light" | "dark") => void;
};
}
}
/**
* Shows mix node details
@@ -90,10 +117,54 @@ const PageMixnodeDetailWithState = () => {
status,
uptimeStory,
uniqDelegations,
} = useMixnodeContext()
const isMobile = useIsMobile()
} = useMixnodeContext();
const isMobile = useIsMobile();
const { mode } = useMainContext();
console.log("toggleMode :>> ", mode);
useEffect(() => {
if (typeof window !== "undefined") {
// Set Remark42 configuration on the window object
window.remark_config = {
host: "http://localhost:8081",
site_id: "remark42",
components: ["embed", "last-comments"],
max_shown_comments: 100,
theme: mode === "light" ? "light" : "dark",
page_title: "My custom title for a page",
locale: "en",
show_email_subscription: false,
simple_view: true,
no_footer: false,
};
// Dynamically load the Remark42 script if it doesn't exist
if (!document.getElementById("remark42-script")) {
const script = document.createElement("script");
script.src = `${window.remark_config.host}/web/embed.js`;
script.async = true;
script.defer = true;
script.id = "remark42-script";
document.body.appendChild(script);
} else if (window.REMARK42) {
// Re-initialize if the script is already loaded
window.REMARK42.createInstance(window.remark_config);
}
}
}, []);
// React to mode changes and update Remark42 theme
useEffect(() => {
if (window.REMARK42 && window.REMARK42.changeTheme) {
window.REMARK42.changeTheme(mode === "dark" ? "dark" : "light");
}
}, [mode]);
return (
<Box component="main">
<Head>
<title>Mixnode Detail</title>
</Head>
<Title text="Mixnode Detail" />
<Grid container spacing={2} mt={1} mb={6}>
<Grid item xs={12}>
@@ -105,9 +176,9 @@ const PageMixnodeDetailWithState = () => {
)}
{mixNodeRow?.blacklisted && (
<Typography
textAlign={isMobile ? 'left' : 'right'}
textAlign={isMobile ? "left" : "right"}
fontSize="smaller"
sx={{ color: 'error.main' }}
sx={{ color: "error.main" }}
>
This node is having a poor performance
</Typography>
@@ -153,7 +224,7 @@ const PageMixnodeDetailWithState = () => {
loading={stats.isLoading}
error={stats?.error?.message}
title="Since startup"
keys={['Received', 'Sent', 'Explicitly dropped']}
keys={["Received", "Sent", "Explicitly dropped"]}
values={[
stats?.data?.packets_received_since_startup || 0,
stats?.data?.packets_sent_since_startup || 0,
@@ -164,7 +235,7 @@ const PageMixnodeDetailWithState = () => {
loading={stats.isLoading}
error={stats?.error?.message}
title="Since last update"
keys={['Received', 'Sent', 'Explicitly dropped']}
keys={["Received", "Sent", "Explicitly dropped"]}
values={[
stats?.data?.packets_received_since_last_update || 0,
stats?.data?.packets_sent_since_last_update || 0,
@@ -204,7 +275,7 @@ const PageMixnodeDetailWithState = () => {
<TwoColSmallTable
loading={status.isLoading}
error={status?.error?.message}
keys={['Mix port', 'Verloc port', 'HTTP port']}
keys={["Mix port", "Verloc port", "HTTP port"]}
values={[1789, 1790, 8000].map((each) => each)}
icons={
(status?.data?.ports && Object.values(status.data.ports)) || [
@@ -237,29 +308,41 @@ const PageMixnodeDetailWithState = () => {
)}
</Grid>
</Grid>
<div id="remark42"></div>
<Script
id="remark-init"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
if (window.REMARK42) {
window.REMARK42.createInstance(window.remark_config);
}
`,
}}
/>
</Box>
)
}
);
};
/**
* Guard component to handle loading and not found states
*/
const PageMixnodeDetailGuard = () => {
const { mixNode } = useMixnodeContext()
const { id } = useParams()
const { mixNode } = useMixnodeContext();
const { id } = useParams();
if (mixNode?.isLoading) {
return <CircularProgress />
return <CircularProgress />;
}
if (mixNode?.error) {
// eslint-disable-next-line no-console
console.error(mixNode?.error)
console.error(mixNode?.error);
return (
<Alert severity="error">
Oh no! Could not load mixnode <code>{id || ''}</code>
Oh no! Could not load mixnode <code>{id || ""}</code>
</Alert>
)
);
}
// loaded, but not found
@@ -267,31 +350,31 @@ const PageMixnodeDetailGuard = () => {
return (
<Alert severity="warning">
<AlertTitle>Mixnode not found</AlertTitle>
Sorry, we could not find a mixnode with id <code>{id || ''}</code>
Sorry, we could not find a mixnode with id <code>{id || ""}</code>
</Alert>
)
);
}
return <PageMixnodeDetailWithState />
}
return <PageMixnodeDetailWithState />;
};
/**
* Wrapper component that adds the mixnode content based on the `id` in the address URL
*/
const PageMixnodeDetail = () => {
const { id } = useParams()
const { id } = useParams();
if (!id || typeof id !== 'string') {
if (!id || typeof id !== "string") {
return (
<Alert severity="error">Oh no! No mixnode identity key specified</Alert>
)
);
}
return (
<MixnodeContextProvider mixId={id}>
<PageMixnodeDetailGuard />
</MixnodeContextProvider>
)
}
);
};
export default PageMixnodeDetail
export default PageMixnodeDetail;
+43
View File
@@ -0,0 +1,43 @@
version: "2"
services:
remark:
# remove the next line in case you want to use this Docker Compose file separately
# as otherwise it would complain for absence of Dockerfile
build: .
image: umputun/remark42:latest
container_name: "explorer_remark42"
hostname: "remark42"
restart: always
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
# uncomment to expose directly (no proxy)
ports:
- "8081:8080"
- "443:8443"
environment:
- REMARK_URL=http://localhost:8081
- SECRET=secret-key
- AUTH_ANON=true
- SITE=remark42
# - DEBUG=true
# - AUTH_GOOGLE_CID
# - AUTH_GOOGLE_CSEC
# - AUTH_GITHUB_CID
# - AUTH_GITHUB_CSEC
# - AUTH_FACEBOOK_CID
# - AUTH_FACEBOOK_CSEC
# - AUTH_DISQUS_CID
# - AUTH_DISQUS_CSEC
# Enable it only for the initial comment import or for manual backups.
# Do not leave the server running with the ADMIN_PASSWD set if you don't have an intention
# to keep creating backups manually!
- ADMIN_PASSWD=password
volumes:
- ./var:/srv/var
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

Binary file not shown.