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.

You can specify network, or layer, or both.
  • Loading branch information
csillag committed Feb 21, 2024
1 parent c152dcf commit 5d690cd
Show file tree
Hide file tree
Showing 16 changed files with 222 additions and 88 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 @@ -23,3 +23,5 @@ REACT_APP_SOCIAL_REDDIT=https://www.reddit.com/r/oasisnetwork/
REACT_APP_PRODUCTION_URLS=https://explorer.oasis.io, https://explorer.prd.oasis.io
REACT_APP_STAGING_URLS=https://explorer.stg.oasis.io
REACT_APP_SHOW_BUILD_BANNERS=true
# REACT_APP_FIXED_NETWORK=testnet
# REACT_APP_FIXED_LAYER=sapphire
2 changes: 2 additions & 0 deletions .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ REACT_APP_SOCIAL_REDDIT=https://www.reddit.com/r/oasisnetwork/
REACT_APP_PRODUCTION_URLS=https://explorer.oasis.io, https://explorer.prd.oasis.io
REACT_APP_STAGING_URLS=https://explorer.stg.oasis.io
REACT_APP_SHOW_BUILD_BANNERS=true
# REACT_APP_FIXED_NETWORK=testnet
# REACT_APP_FIXED_LAYER=sapphire
5 changes: 4 additions & 1 deletion src/app/components/LayerPicker/LayerMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { RouteUtils } from '../../utils/route-utils'
import { Network } from '../../../types/network'
import { isLayerHidden, orderByLayer } from '../../../types/layers'
import { useScreenSize } from '../../hooks/useScreensize'
import { useScopeParam } from '../../hooks/useScopeParam'

type BaseLayerMenuItemProps = {
divider: boolean
Expand Down Expand Up @@ -107,9 +108,11 @@ export const LayerMenu: FC<LayerMenuProps> = ({
selectedNetwork,
setSelectedLayer,
}) => {
const currentScope = useScopeParam()
const [hoveredLayer, setHoveredLayer] = useState<undefined | Layer>()
const options = Object.values(Layer)
.filter(layer => !isLayerHidden(layer))
// Don't show hidden layers, unless we are already viewing them.
.filter(layer => !isLayerHidden(layer) || layer === currentScope?.layer)
.map(layer => ({
layer,
enabled: RouteUtils.getAllLayersForNetwork(selectedNetwork || network).enabled.includes(layer),
Expand Down
109 changes: 60 additions & 49 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 { scopeFreedom, 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 @@ -104,61 +104,72 @@ const LayerPickerContent: FC<LayerPickerContentProps> = ({ isOutOfDate, onClose,
{isTablet && (
<TabletActionBar>
<div>
{tabletStep === LayerPickerTabletStep.Layer && (
<TabletBackButton
variant="text"
startIcon={<KeyboardArrowLeft />}
onClick={() => {
setTabletStep(LayerPickerTabletStep.Network)
}}
>
{t('layerPicker.viewNetworks')}
</TabletBackButton>
)}
{tabletStep === LayerPickerTabletStep.LayerDetails && (
<TabletBackButton
variant="text"
startIcon={<KeyboardArrowLeft />}
onClick={() => {
setTabletStep(LayerPickerTabletStep.Layer)
}}
>
{t('layerPicker.viewLayers')}
</TabletBackButton>
)}
{
// Do we need a "back to networks" button ?
((scopeFreedom === 'network-layer' && tabletStep === LayerPickerTabletStep.Layer) || // Stepping back from layers
(scopeFreedom === 'network' && tabletStep === LayerPickerTabletStep.LayerDetails)) && ( // Stepping back from details, skipping layers
<TabletBackButton
variant="text"
startIcon={<KeyboardArrowLeft />}
onClick={() => {
setTabletStep(LayerPickerTabletStep.Network)
}}
>
{t('layerPicker.viewNetworks')}
</TabletBackButton>
)
}
{scopeFreedom !== 'network' &&
tabletStep === LayerPickerTabletStep.LayerDetails && ( // Stepping back from details, going to layers
<TabletBackButton
variant="text"
startIcon={<KeyboardArrowLeft />}
onClick={() => {
setTabletStep(LayerPickerTabletStep.Layer)
}}
>
{t('layerPicker.viewLayers')}
</TabletBackButton>
)}
</div>
<MobileNetworkButton isOutOfDate={isOutOfDate} network={network} layer={layer} onClick={onClose} />
</TabletActionBar>
)}
<Divider />
<StyledContent>
<Grid container>
{(!isTablet || (isTablet && tabletStep === LayerPickerTabletStep.Network)) && (
<Grid xs={12} md={3}>
<NetworkMenu
activeNetwork={network}
selectedNetwork={selectedNetwork}
setSelectedNetwork={network => {
selectNetwork(network)
setTabletStep(LayerPickerTabletStep.Layer)
}}
/>
</Grid>
)}
{(!isTablet || (isTablet && tabletStep === LayerPickerTabletStep.Layer)) && (
<Grid xs={12} md={3}>
<LayerMenu
activeLayer={layer}
network={network}
selectedLayer={selectedLayer}
selectedNetwork={selectedNetwork}
setSelectedLayer={layer => {
setSelectedLayer(layer)
setTabletStep(LayerPickerTabletStep.LayerDetails)
}}
/>
</Grid>
)}
{scopeFreedom !== 'layer' &&
(!isTablet || (isTablet && tabletStep === LayerPickerTabletStep.Network)) && (
<Grid xs={12} md={3}>
<NetworkMenu
activeNetwork={network}
selectedNetwork={selectedNetwork}
setSelectedNetwork={network => {
selectNetwork(network)
setTabletStep(
scopeFreedom === 'network' // Are we fixed to a specific layer, selecting only network?
? LayerPickerTabletStep.LayerDetails // If so, skip layer selection, go straight to layer details.
: LayerPickerTabletStep.Layer, // Otherwise, go to layer selection.
)
}}
/>
</Grid>
)}
{scopeFreedom !== 'network' &&
(!isTablet || (isTablet && tabletStep === LayerPickerTabletStep.Layer)) && (
<Grid xs={12} md={3}>
<LayerMenu
activeLayer={layer}
network={network}
selectedLayer={selectedLayer}
selectedNetwork={selectedNetwork}
setSelectedLayer={layer => {
setSelectedLayer(layer)
setTabletStep(LayerPickerTabletStep.LayerDetails)
}}
/>
</Grid>
)}
{(!isTablet || (isTablet && tabletStep === LayerPickerTabletStep.LayerDetails)) && (
<Grid xs={12} md={6}>
<LayerDetails
Expand Down
4 changes: 3 additions & 1 deletion src/app/components/PageLayout/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import { NetworkSelector } from './NetworkSelector'
import Box from '@mui/material/Box'
import { useScopeParam } from '../../hooks/useScopeParam'
import { useScreenSize } from '../../hooks/useScreensize'
import { isScopeSelectorNeeded } from '../../utils/route-utils'

export const Header: FC = () => {
const theme = useTheme()
const { isMobile } = useScreenSize()
const scope = useScopeParam()
const withScopeSelector = !!scope && isScopeSelectorNeeded(scope)
const scrollTrigger = useScrollTrigger({
disableHysteresis: true,
threshold: 0,
Expand Down Expand Up @@ -49,7 +51,7 @@ export const Header: FC = () => {
showText={!scrollTrigger && !isMobile}
/>
</Grid>
{scope && (
{withScopeSelector && (
<>
<Grid lg={6} xs={8}>
<NetworkSelector layer={scope.layer} network={scope.network} />
Expand Down
15 changes: 10 additions & 5 deletions src/app/components/PageLayout/NetworkButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import Button, { buttonClasses } from '@mui/material/Button'
import EditIcon from '@mui/icons-material/Edit'
import { styled } from '@mui/material/styles'
import { COLORS } from '../../../styles/theme/colors'
import { Network } from '../../../types/network'
import { getNetworkNames, Network } from '../../../types/network'
import { Layer } from '../../../oasis-nexus/api'
import { getLayerLabels, getNetworkIcons } from '../../utils/content'
import { LayerStatus } from '../LayerStatus'
import { fixedLayer } from '../../utils/route-utils'
import { TFunction } from 'i18next'

export const StyledNetworkButton = styled(Button)(({ theme }) => ({
alignItems: 'center',
Expand Down Expand Up @@ -75,9 +77,13 @@ type NetworkButtonProps = {
onClick: () => void
}

const getNetworkButtonLabel = (t: TFunction, network: Network, layer: Layer) =>
fixedLayer // If we are fixed to a layer,
? getNetworkNames(t)[network] // let's show the name of the network,
: getLayerLabels(t)[layer] // otherwise, the name of the layer.

export const NetworkButton: FC<NetworkButtonProps> = ({ isOutOfDate, layer, network, onClick }) => {
const { t } = useTranslation()
const labels = getLayerLabels(t)
const icons = getNetworkIcons()

return (
Expand All @@ -90,7 +96,7 @@ export const NetworkButton: FC<NetworkButtonProps> = ({ isOutOfDate, layer, netw
onClick={onClick}
>
<StyledBox>
{labels[layer]}
{getNetworkButtonLabel(t, network, layer)}
<LayerStatus isOutOfDate={isOutOfDate} />
</StyledBox>
</StyledNetworkButton>
Expand All @@ -115,11 +121,10 @@ export const StyledMobileNetworkButton = styled(Button)(({ theme }) => ({

export const MobileNetworkButton: FC<NetworkButtonProps> = ({ isOutOfDate, layer, network, onClick }) => {
const { t } = useTranslation()
const labels = getLayerLabels(t)

return (
<StyledMobileNetworkButton onClick={onClick}>
{labels[layer]}
{getNetworkButtonLabel(t, network, layer)}
<LayerStatus isOutOfDate={isOutOfDate} />
</StyledMobileNetworkButton>
)
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/PageLayout/NetworkSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { COLORS } from '../../../styles/theme/colors'
import { Network, getNetworkNames } from '../../../types/network'
import { Layer } from '../../../oasis-nexus/api'
import { LayerPicker } from './../LayerPicker'
import { RouteUtils } from '../../utils/route-utils'
import { fixedLayer, RouteUtils } from '../../utils/route-utils'
import { useConsensusFreshness, useRuntimeFreshness } from '../OfflineBanner/hook'

export const StyledBox = styled(Box)(({ theme }) => ({
Expand Down Expand Up @@ -84,7 +84,7 @@ const NetworkSelectorView: FC<NetworkSelectorViewProps> = ({ isOutOfDate, layer,
{!isMobile && (
<NetworkButton isOutOfDate={isOutOfDate} layer={layer} network={network} onClick={handleDrawerOpen} />
)}
{!isTablet && network !== Network.mainnet && (
{!fixedLayer && !isTablet && network !== Network.mainnet && (
<StyledBox>
<Typography
component="span"
Expand Down
7 changes: 5 additions & 2 deletions 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 { fixedNetwork } from '../../utils/route-utils'

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

export const withDefaultTheme = (node: ReactNode) => (
<ThemeByNetwork network={Network.mainnet}>{node}</ThemeByNetwork>
export const withDefaultTheme = (node: ReactNode, alwaysMainnet = false) => (
<ThemeByNetwork network={alwaysMainnet ? Network.mainnet : fixedNetwork ?? Network.mainnet}>
{node}
</ThemeByNetwork>
)
4 changes: 2 additions & 2 deletions 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 { fixedNetwork, RouteUtils } from '../utils/route-utils'
import { AppErrors } from '../../types/errors'

/**
Expand All @@ -12,7 +12,7 @@ export const useSearchQueryNetworkParam = (): {
setNetwork: (network: Network) => void
} => {
const [searchParams, setSearchParams] = useSearchParams()
const networkQueryParam = searchParams.get('network') ?? Network.mainnet
const networkQueryParam = fixedNetwork ?? 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 { fixedNetwork } 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 && (
{!fixedNetwork && step === ParaTimeSelectorStep.Explore && (
<NetworkSelector network={network} setNetwork={network => setNetwork(network ?? Network.mainnet)} />
)}
</ParaTimeSelectorGlow>
Expand Down
19 changes: 18 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 { fixedNetwork, 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,23 @@ export const GlobalSearchResultsView: FC<{

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

if (fixedNetwork) {
return (
<>
{!searchResults.length && <NoResultsWhatsoever />}
<SearchResultsList
key={fixedNetwork}
title={networkNames[fixedNetwork]}
searchTerm={searchTerm}
searchResults={searchResults}
networkForTheme={fixedNetwork}
tokenPrices={tokenPrices}
/>
</>
)
}

const otherNetworks = RouteUtils.getEnabledNetworks().filter(isNotMainnet)
const notificationTheme = themes[Network.testnet]
const mainnetResults = searchResults.filter(isOnMainnet).sort(orderByLayer)
Expand Down
10 changes: 4 additions & 6 deletions src/app/pages/SearchResultsPage/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,10 @@ export function useRuntimeTokenConditionally(
export function useNetworkProposalsConditionally(
nameFragment: string | undefined,
): ConditionalResults<Proposal> {
const queries = RouteUtils.getEnabledNetworks()
.filter(network => RouteUtils.getAllLayersForNetwork(network).enabled.includes(Layer.consensus))
.map(network =>
// eslint-disable-next-line react-hooks/rules-of-hooks
useGetConsensusProposalsByName(network, nameFragment),
)
const queries = RouteUtils.getEnabledNetworksForLayer(Layer.consensus).map(network =>
// eslint-disable-next-line react-hooks/rules-of-hooks
useGetConsensusProposalsByName(network, nameFragment),
)
return {
isLoading: queries.some(query => query.isInitialLoading),
results: queries
Expand Down
Loading

0 comments on commit 5d690cd

Please sign in to comment.