Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/network status #514

Merged
merged 10 commits into from
Mar 17, 2024
13 changes: 12 additions & 1 deletion app.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,16 @@ module.exports = {
},

// Display alert banner for the developer preview deployment
showPreviewAlert: process.env.NEXT_PUBLIC_SHOW_PREVIEW_ALERT || 'false'
showPreviewAlert: process.env.NEXT_PUBLIC_SHOW_PREVIEW_ALERT || 'false',

networkAlertConfig: {
// Refresh interval for network status - 30 sec
refreshInterval: 30000,
// Margin of error for block count (how much difference between min / max block numbers before showing an alert)
errorMargin: 10,
// Map chainIds to their respective status endpoints
statusEndpoints: {
100: 'https://status.genx.delta-dao.com/api/check-blocks'
}
}
}
10 changes: 10 additions & 0 deletions src/@context/MarketMetadata/_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ export interface AppConfig {
roughTxGasEstimate: number
}
showPreviewAlert: string
networkAlertConfig: {
// Refresh interval for network status - 30 sec
refreshInterval: number
// Margin of error for block count (how much difference between min / max block numbers before showing an alert)
errorMargin: number
// Map chainIds to their respective status endpoints
statusEndpoints: {
[chainId: number]: string
}
}
}
export interface SiteContent {
siteTitle: string
Expand Down
84 changes: 84 additions & 0 deletions src/components/@shared/NetworkStatus/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { ReactElement, useCallback, useEffect, useState } from 'react'
import { useNetwork } from 'wagmi'
import { useMarketMetadata } from '../../../@context/MarketMetadata'
import Alert from '../atoms/Alert'
import axios from 'axios'
import { LoggerInstance } from '@oceanprotocol/lib'

export default function NetworkStatus({
className
}: {
className?: string
}): ReactElement {
const [showNetworkAlert, setShowNetworkAlert] = useState(true)
const [network, setNetwork] = useState<string>()
const { appConfig } = useMarketMetadata()
const { chain } = useNetwork()

const { networkAlertConfig } = appConfig

const fetchNetworkStatus = useCallback(
async (chainId: number) => {
if (!chainId) return
setNetwork(chain?.name)
const apiEndpoint = networkAlertConfig.statusEndpoints[chainId]
if (!apiEndpoint) return
LoggerInstance.log(`[NetworkStatus] retrieving network status`, {
apiEndpoint
})
try {
const result = await axios.get(apiEndpoint)
const { Nodes } = result.data
const { nodes }: { nodes: { [node: string]: number } } = Nodes
let minBlock: number
let maxBlock: number
Object.values(nodes).forEach((block) => {
if (!minBlock || block < minBlock) minBlock = block
if (!maxBlock || block > maxBlock) maxBlock = block
})
const hasError = maxBlock - minBlock > networkAlertConfig.errorMargin
setShowNetworkAlert(hasError)
LoggerInstance.log(`[NetworkStatus] network status updated:`, {
minBlock,
maxBlock,
hasError
})
} catch (error) {
LoggerInstance.error(
`[NetworkStatus] could not retrieve network status:`,
error.message
)
}
},
[networkAlertConfig, chain]
)

useEffect(() => {
if (!chain?.id) return

fetchNetworkStatus(chain?.id)

// init periodic refresh for network status
const networkStatusInterval = setInterval(
() => fetchNetworkStatus(chain?.id),
networkAlertConfig.refreshInterval
)

return () => {
clearInterval(networkStatusInterval)
}
}, [chain, fetchNetworkStatus])

return (
showNetworkAlert && (
<Alert
state="warning"
text="The network is currently undergoing maintenance, which may cause instabilities or transaction delays. Please try again later if you run into issues."
title="Network Status"
badge={network || chain?.id.toString()}
onDismiss={() => setShowNetworkAlert(false)}
className={className}
/>
)
)
}
5 changes: 4 additions & 1 deletion src/components/@shared/Page/PageHeader.module.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
.header {
margin-bottom: var(--spacer);
max-width: 50rem;
}

.title {
Expand Down Expand Up @@ -81,3 +80,7 @@
margin-top: calc(var(--spacer) / 2);
max-width: 30rem;
}

.networkAlert {
margin: var(--spacer) auto;
}
14 changes: 9 additions & 5 deletions src/components/@shared/Page/PageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ReactElement } from 'react'
import classNames from 'classnames/bind'
import styles from './PageHeader.module.css'
import Markdown from '@shared/Markdown'
import SearchBar from '@components/Header/SearchBar'
import BrandLogo from '@images/brand-logo.svg'
import GaiaXLogo from '@images/gaia-x-logo.svg'
import Markdown from '@shared/Markdown'
import classNames from 'classnames/bind'
import { ReactElement } from 'react'
import NetworkStatus from '../NetworkStatus'
import styles from './PageHeader.module.css'

const cx = classNames.bind(styles)

Expand Down Expand Up @@ -46,7 +47,10 @@ export default function PageHeader({
</div>
</div>
) : (
<h1 className={styles.title}>{title}</h1>
<div>
<h1 className={styles.title}>{title}</h1>
<NetworkStatus className={styles.networkAlert} />
</div>
)}
{description && !isHome && (
<Markdown text={description} className={styles.description} />
Expand Down
Loading