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

Support limiting scope to one network or layer - full version #1242

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems hard to maintain. Did any other approaches have issues?

Copy link
Contributor Author

@csillag csillag Feb 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems hard to maintain.

Well, I guess we can simplify it a great deal if we give up on having the shortest possible URLs.... lemme prepare and alternate PR with that version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about #1269?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's nice that you split that subset into a separate PR. I wouldn't necessarily throw away the rest tho.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a different approach tho

Some other approaches:

  • Do we only need to support one of pinning network | pinning layer | pinning network+layer for PontusX? Does it matter? Are there issues supporting just one?
  • Issues if we tried to unify "fixed" vs unfixed by moving enabled layers to .env.production?
  • Can react router intercept and rewrite paths
  • ..

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.getEnabledLayersForNetwork(selectedNetwork || network).includes(layer),
Expand Down
117 changes: 64 additions & 53 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 @@ -77,8 +77,8 @@ type LayerPickerContentProps = Omit<LayerPickerProps, 'open'>

enum LayerPickerTabletStep {
Network,
ParaTime,
lubej marked this conversation as resolved.
Show resolved Hide resolved
ParaTimeDetails,
Layer,
LayerDetails,
}

const LayerPickerContent: FC<LayerPickerContentProps> = ({ isOutOfDate, onClose, onConfirm }) => {
Expand All @@ -87,7 +87,7 @@ const LayerPickerContent: FC<LayerPickerContentProps> = ({ isOutOfDate, onClose,
const { network, layer } = useRequiredScopeParam()
const [selectedLayer, setSelectedLayer] = useState<Layer>(layer)
const [selectedNetwork, setSelectedNetwork] = useState<Network>(network)
const [tabletStep, setTabletStep] = useState<LayerPickerTabletStep>(LayerPickerTabletStep.ParaTimeDetails)
const [tabletStep, setTabletStep] = useState<LayerPickerTabletStep>(LayerPickerTabletStep.LayerDetails)
const selectNetwork = (newNetwork: Network) => {
const enabledLayers = RouteUtils.getEnabledLayersForNetwork(newNetwork)
const targetLayer = enabledLayers.includes(selectedLayer) ? selectedLayer : enabledLayers[0]
Expand All @@ -104,62 +104,73 @@ const LayerPickerContent: FC<LayerPickerContentProps> = ({ isOutOfDate, onClose,
{isTablet && (
<TabletActionBar>
<div>
{tabletStep === LayerPickerTabletStep.ParaTime && (
<TabletBackButton
variant="text"
startIcon={<KeyboardArrowLeft />}
onClick={() => {
setTabletStep(LayerPickerTabletStep.Network)
}}
>
{t('layerPicker.viewNetworks')}
</TabletBackButton>
)}
{tabletStep === LayerPickerTabletStep.ParaTimeDetails && (
<TabletBackButton
variant="text"
startIcon={<KeyboardArrowLeft />}
onClick={() => {
setTabletStep(LayerPickerTabletStep.ParaTime)
}}
>
{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.ParaTime)
}}
/>
</Grid>
)}
{(!isTablet || (isTablet && tabletStep === LayerPickerTabletStep.ParaTime)) && (
<Grid xs={12} md={3}>
<LayerMenu
activeLayer={layer}
network={network}
selectedLayer={selectedLayer}
selectedNetwork={selectedNetwork}
setSelectedLayer={layer => {
setSelectedLayer(layer)
setTabletStep(LayerPickerTabletStep.ParaTimeDetails)
}}
/>
</Grid>
)}
{(!isTablet || (isTablet && tabletStep === LayerPickerTabletStep.ParaTimeDetails)) && (
{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
handleConfirm={handleConfirm}
Expand Down
6 changes: 4 additions & 2 deletions 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 = isScopeSelectorNeeded(scope)
const scrollTrigger = useScrollTrigger({
disableHysteresis: true,
threshold: 0,
Expand Down Expand Up @@ -49,10 +51,10 @@ export const Header: FC = () => {
showText={!scrollTrigger && !isMobile}
/>
</Grid>
{scope && (
{withScopeSelector && (
<>
<Grid lg={6} xs={8}>
<NetworkSelector layer={scope.layer} network={scope.network} />
<NetworkSelector layer={scope!.layer} network={scope!.network} />
</Grid>
<Grid lg={3} xs={0} />
</>
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>
)
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 { fixedNetwork, 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 (fixedNetwork) {
return {
network: fixedNetwork,
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 { 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.getEnabledLayersForNetwork(network).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
1 change: 1 addition & 0 deletions src/app/utils/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const isTesting = process.env.NODE_ENV === 'test'
Loading
Loading