Skip to content

Commit

Permalink
Support limiting scope to one network or layer
Browse files Browse the repository at this point in the history
It's now possible to specify a given network or layer
in the .env file, and when given, the scope of the whole
explorer will be limited to that specific network,
or even a specific layer within that network.
No data external to the required scope will be shown.
The network (and the layer) will not be part of the URLs.

LIMITATION:

please note that specifying a layer without network
is currently not supported.
  • Loading branch information
csillag committed Feb 9, 2024
1 parent 5afbfe2 commit a7b58d1
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 56 deletions.
1 change: 1 addition & 0 deletions .changelog/1242.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support limiting scope to one network or layer
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ REACT_APP_BUILD_VERSION=
# REACT_APP_TESTNET_API=https://testnet.nexus.stg.oasis.io/v1/
REACT_APP_API=https://nexus.oasis.io/v1/
REACT_APP_TESTNET_API=https://testnet.nexus.oasis.io/v1/
# REACT_APP_FIXED_NETWORK=testnet
# REACT_APP_FIXED_LAYER=sapphire
22 changes: 13 additions & 9 deletions src/app/components/LayerPicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useRequiredScopeParam } from '../../hooks/useScopeParam'
import { NetworkMenu } from './NetworkMenu'
import { LayerMenu } from './LayerMenu'
import { LayerDetails } from './LayerDetails'
import { RouteUtils } from '../../utils/route-utils'
import { hasFixedNetwork, RouteUtils } from '../../utils/route-utils'
import { styled } from '@mui/material/styles'
import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft'
import { useScreenSize } from '../../hooks/useScreensize'
Expand Down Expand Up @@ -96,6 +96,8 @@ const LayerPickerContent: FC<LayerPickerContentProps> = ({ isOutOfDate, onClose,
}
const handleConfirm = () => onConfirm(selectedNetwork, selectedLayer)

const fixedNetwork = hasFixedNetwork()

return (
<StyledLayerPickerContent>
<Box sx={{ mb: isTablet ? 0 : 5, color: 'red', position: 'relative' }}>
Expand All @@ -104,7 +106,7 @@ const LayerPickerContent: FC<LayerPickerContentProps> = ({ isOutOfDate, onClose,
{isTablet && (
<TabletActionBar>
<div>
{tabletStep === LayerPickerTabletStep.ParaTime && (
{!fixedNetwork && tabletStep === LayerPickerTabletStep.ParaTime && (
<TabletBackButton
variant="text"
startIcon={<KeyboardArrowLeft />}
Expand All @@ -127,18 +129,20 @@ const LayerPickerContent: FC<LayerPickerContentProps> = ({ isOutOfDate, onClose,
</TabletBackButton>
)}
</div>
<MobileNetworkButton
isOutOfDate={isOutOfDate}
network={network}
layer={layer}
onClick={handleConfirm}
/>
{!fixedNetwork && (
<MobileNetworkButton
isOutOfDate={isOutOfDate}
network={network}
layer={layer}
onClick={handleConfirm}
/>
)}
</TabletActionBar>
)}
<Divider />
<StyledContent>
<Grid container>
{(!isTablet || (isTablet && tabletStep === LayerPickerTabletStep.Network)) && (
{!fixedNetwork && (!isTablet || (isTablet && tabletStep === LayerPickerTabletStep.Network)) && (
<Grid xs={12} md={3}>
<NetworkMenu
activeNetwork={network}
Expand Down
3 changes: 2 additions & 1 deletion src/app/components/PageLayout/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { NetworkSelector } from './NetworkSelector'
import Box from '@mui/material/Box'
import { useScopeParam } from '../../hooks/useScopeParam'
import { useScreenSize } from '../../hooks/useScreensize'
import { hasFixedNetworkAndLayer } from '../../utils/route-utils'

export const Header: FC = () => {
const theme = useTheme()
Expand Down Expand Up @@ -49,7 +50,7 @@ export const Header: FC = () => {
showText={!scrollTrigger && !isMobile}
/>
</Grid>
{scope && (
{scope && !hasFixedNetworkAndLayer() && (
<>
<Grid lg={6} xs={8}>
<NetworkSelector layer={scope.layer} network={scope.network} />
Expand Down
7 changes: 6 additions & 1 deletion src/app/components/ThemeByNetwork/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Network } from '../../../types/network'
import { ThemeProvider } from '@mui/material/styles'
import { getThemesForNetworks } from '../../../styles/theme'
import CssBaseline from '@mui/material/CssBaseline'
import { getFixedNetwork } from '../../utils/route-utils'

export const ThemeByNetwork: FC<{ network: Network; children: React.ReactNode }> = ({
network,
Expand All @@ -14,6 +15,10 @@ export const ThemeByNetwork: FC<{ network: Network; children: React.ReactNode }>
</ThemeProvider>
)

export const withDefaultTheme = (node: ReactNode) => (
export const withMainnetTheme = (node: ReactNode) => (
<ThemeByNetwork network={Network.mainnet}>{node}</ThemeByNetwork>
)

export const withDefaultTheme = (node: ReactNode) => (
<ThemeByNetwork network={getFixedNetwork() ?? Network.mainnet}>{node}</ThemeByNetwork>
)
8 changes: 7 additions & 1 deletion src/app/hooks/useSearchQueryNetworkParam.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useSearchParams } from 'react-router-dom'
import { Network } from '../../types/network'
import { RouteUtils } from '../utils/route-utils'
import { getFixedNetwork, hasFixedNetwork, RouteUtils } from '../utils/route-utils'
import { AppErrors } from '../../types/errors'

/**
Expand All @@ -12,6 +12,12 @@ export const useSearchQueryNetworkParam = (): {
setNetwork: (network: Network) => void
} => {
const [searchParams, setSearchParams] = useSearchParams()
if (hasFixedNetwork()) {
return {
network: getFixedNetwork()!,
setNetwork: () => {},
}
}
const networkQueryParam = searchParams.get('network') ?? Network.mainnet
if (!RouteUtils.getEnabledNetworks().includes(networkQueryParam as any)) {
throw AppErrors.InvalidUrl
Expand Down
3 changes: 2 additions & 1 deletion src/app/pages/HomePage/Graph/ParaTimeSelector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { useSearchQueryNetworkParam } from '../../../../hooks/useSearchQueryNetw
import { storage } from '../../../../utils/storage'
import { StorageKeys } from '../../../../../types/storage'
import { GraphTooltipMobile } from '../GraphTooltipMobile'
import { hasFixedNetwork } from '../../../../utils/route-utils'

interface ParaTimeSelectorBaseProps {
disabled: boolean
Expand Down Expand Up @@ -284,7 +285,7 @@ const ParaTimeSelectorCmp: FC<ParaTimeSelectorProps> = ({
<HelpScreen setParaTimeStep={setStep} />
)}
</ParaTimeSelectorGlobe>
{step === ParaTimeSelectorStep.Explore && (
{!hasFixedNetwork() && step === ParaTimeSelectorStep.Explore && (
<NetworkSelector network={network} setNetwork={network => setNetwork(network ?? Network.mainnet)} />
)}
</ParaTimeSelectorGlow>
Expand Down
21 changes: 20 additions & 1 deletion src/app/pages/SearchResultsPage/GlobalSearchResultsView.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next'

import { RouteUtils } from '../../utils/route-utils'
import { getFixedNetwork, hasFixedNetwork, RouteUtils } from '../../utils/route-utils'
import { SearchResults } from './hooks'
import { NoResultsOnMainnet, NoResultsWhatsoever } from './NoResults'
import { SearchResultsList } from './SearchResultsList'
Expand Down Expand Up @@ -30,6 +30,25 @@ export const GlobalSearchResultsView: FC<{

const themes = getThemesForNetworks()
const networkNames = getNetworkNames(t)

if (hasFixedNetwork()) {
const network = getFixedNetwork()!
const wantedResults = searchResults.filter(result => result.network === network)
return (
<>
{!wantedResults.length && <NoResultsWhatsoever />}
<SearchResultsList
key={network}
title={networkNames[network]}
searchTerm={searchTerm}
searchResults={wantedResults}
networkForTheme={network}
tokenPrices={tokenPrices}
/>
</>
)
}

const otherNetworks = RouteUtils.getEnabledNetworks().filter(isNotMainnet)
const notificationTheme = themes[Network.testnet]
const mainnetResults = searchResults.filter(isOnMainnet).sort(orderByLayer)
Expand Down
78 changes: 50 additions & 28 deletions src/app/utils/route-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ import { SearchScope } from '../../types/searchScope'
import { isStableDeploy } from '../../config'
import { getSearchTermFromRequest } from '../components/Search/search-utils'

export const isTesting = () => process.env.NODE_ENV === 'test'

export const getFixedNetwork = () =>
isTesting() ? undefined : (process.env.REACT_APP_FIXED_NETWORK as Network | undefined)
export const getFixedLayer = () =>
isTesting() ? undefined : (process.env.REACT_APP_FIXED_LAYER as Layer | undefined)
export const hasFixedNetwork = () => !!getFixedNetwork()

export const hasFixedLayer = () => !!getFixedLayer()

export const hasFixedNetworkAndLayer = () => !!getFixedNetwork() && !!getFixedLayer()

export const isFixedOnConsensus = () => getFixedLayer() === Layer.consensus

export const isFixedOnParatime = () => hasFixedLayer() && getFixedLayer() !== Layer.consensus

export type SpecifiedPerEnabledLayer<T = any, ExcludeLayers = never> = {
[N in keyof (typeof RouteUtils)['ENABLED_LAYERS_FOR_NETWORK']]: {
[L in keyof (typeof RouteUtils)['ENABLED_LAYERS_FOR_NETWORK'][N] as Exclude<
Expand All @@ -17,8 +33,22 @@ export type SpecifiedPerEnabledLayer<T = any, ExcludeLayers = never> = {
}
}

export const getNetworkRoutePath = (routePath: string) =>
hasFixedNetwork() ? routePath : `/:_network${routePath}`

export const getLayerRoutePath = () => (hasFixedLayer() ? '' : `/:_layer`)

export const getConsensusRoutePath = () => (isFixedOnConsensus() ? '' : '/consensus')

export type SpecifiedPerEnabledRuntime<T = any> = SpecifiedPerEnabledLayer<T, typeof Layer.consensus>

const getNetworkPath = (network: Network) => (hasFixedNetwork() ? '' : `/${encodeURIComponent(network)}`)

const getLayerPath = (layer: Layer) => (hasFixedLayer() ? '' : `/${encodeURIComponent(layer)}`)

const getNetworkAndLayerPath = (network: Network, layer: Layer) =>
`${getNetworkPath(network)}${getLayerPath(layer)}`

export abstract class RouteUtils {
private static ENABLED_LAYERS_FOR_NETWORK = {
[Network.mainnet]: {
Expand All @@ -37,45 +67,39 @@ export abstract class RouteUtils {
} satisfies Record<Network, Record<Layer, boolean>>

static getDashboardRoute = ({ network, layer }: SearchScope) => {
return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}`
return `${getNetworkAndLayerPath(network, layer)}`
}

static getLatestTransactionsRoute = ({ network, layer }: SearchScope) => {
return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/tx`
return `${getNetworkAndLayerPath(network, layer)}/tx`
}

static getTopTokensRoute = ({ network, layer }: SearchScope) => {
return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/token`
return `${getNetworkAndLayerPath(network, layer)}/token`
}

static getLatestBlocksRoute = ({ network, layer }: SearchScope) => {
return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/block`
return `${getNetworkAndLayerPath(network, layer)}/block`
}

static getBlockRoute = ({ network, layer }: SearchScope, blockHeight: number) => {
return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/block/${encodeURIComponent(
blockHeight,
)}`
return `${getNetworkAndLayerPath(network, layer)}/block/${encodeURIComponent(blockHeight)}`
}

static getTransactionRoute = (scope: SearchScope, txHash: string) => {
return `/${encodeURIComponent(scope.network)}/${encodeURIComponent(scope.layer)}/tx/${encodeURIComponent(
txHash,
)}`
return `${getNetworkAndLayerPath(scope.network, scope.layer)}/tx/${encodeURIComponent(txHash)}`
}

static getAccountRoute = ({ network, layer }: SearchScope, account: string) => {
return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/address/${encodeURIComponent(
account,
)}`
return `${getNetworkAndLayerPath(network, layer)}/address/${encodeURIComponent(account)}`
}

static getAccountsRoute = (network: Network) => {
return `/${encodeURIComponent(network)}/consensus/address`
return `${getNetworkPath(network)}${getConsensusRoutePath()}/address`
}

static getValidatorsRoute = (network: Network) => {
return `/${encodeURIComponent(network)}/consensus/validators`
return `${getNetworkPath(network)}${getConsensusRoutePath()}/validators`
}

static getAccountTokensRoute = (
Expand All @@ -95,28 +119,24 @@ export abstract class RouteUtils {

static getSearchRoute = (scope: SearchScope | undefined, searchTerm: string) => {
return scope
? `/${scope.network}/${scope.layer}/search?q=${encodeURIComponent(searchTerm)}`
? `${getNetworkAndLayerPath(scope.network, scope.layer)}/search?q=${encodeURIComponent(searchTerm)}`
: `/search?q=${encodeURIComponent(searchTerm)}`
}

static getTokenRoute = ({ network, layer }: SearchScope, tokenAddress: string) => {
return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/token/${encodeURIComponent(
tokenAddress,
)}`
return `${getNetworkAndLayerPath(network, layer)}/token/${encodeURIComponent(tokenAddress)}`
}

static getTokenHoldersRoute = ({ network, layer }: SearchScope, tokenAddress: string) => {
return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/token/${encodeURIComponent(
tokenAddress,
)}/holders`
return `${getNetworkAndLayerPath(network, layer)}/token/${encodeURIComponent(tokenAddress)}/holders`
}

static getNFTInstanceRoute = (
{ network, layer }: SearchScope,
contractAddress: string,
instanceId: string,
): string =>
`/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/token/${encodeURIComponent(
`${getNetworkAndLayerPath(network, layer)}/token/${encodeURIComponent(
contractAddress,
)}/instance/${encodeURIComponent(instanceId)}`

Expand All @@ -125,11 +145,11 @@ export abstract class RouteUtils {
}

static getProposalsRoute = (network: Network) => {
return `/${encodeURIComponent(network)}/consensus/proposal`
return `${getNetworkPath(network)}/consensus/proposal`
}

static getProposalRoute = (network: Network, proposalId: string | number) => {
return `/${encodeURIComponent(network)}/consensus/proposal/${encodeURIComponent(proposalId)}`
return `${getNetworkPath(network)}/consensus/proposal/${encodeURIComponent(proposalId)}`
}

static getEnabledScopes(): SearchScope[] {
Expand All @@ -139,9 +159,11 @@ export abstract class RouteUtils {
}

static getEnabledNetworks(): Network[] {
return Object.values(Network).filter(network => {
return RouteUtils.getEnabledLayersForNetwork(network).length > 0
})
return hasFixedNetwork()
? [getFixedNetwork()!]
: Object.values(Network).filter(network => {
return RouteUtils.getEnabledLayersForNetwork(network).length > 0
})
}

static getEnabledSearchScopes(): SearchScope[] {
Expand Down
Loading

0 comments on commit a7b58d1

Please sign in to comment.