From 1c0439cdf6fd4058e95ce6b04a683a4cd248a08f Mon Sep 17 00:00:00 2001 From: Kristof Csillag Date: Wed, 29 May 2024 14:39:47 +0200 Subject: [PATCH 01/10] Add support for overriding names of special scopes Normally, the name of a scope is derived by concatenating the name of the layer (i.e. "Sapphire") and the name of the network (i.e. "Testnet") ==> "Sapphire Testnet" However, in some specific cases, we might want to have something different. This can be achieved by this override function. --- src/config.ts | 6 ++++++ src/types/searchScope.ts | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/config.ts b/src/config.ts index c14207c66..79c0039b0 100644 --- a/src/config.ts +++ b/src/config.ts @@ -3,6 +3,7 @@ import { Layer } from './oasis-nexus/generated/api' import { NativeToken, NativeTokenInfo } from './types/ticker' import { SearchScope } from './types/searchScope' +import { Network } from './types/network' export const consensusDecimals = 9 /** @@ -202,3 +203,8 @@ export const getFiatCurrencyForScope = (scope: SearchScope | undefined) => (scope ? paraTimesConfig[scope.layer]?.[scope.network]?.fiatCurrency : undefined) ?? 'usd' export const showFiatValues = process.env.REACT_APP_SHOW_FIAT_VALUES === 'true' + +export const specialScopeNames: Partial>>> = { + [Network.mainnet]: {}, + [Network.testnet]: {}, +} diff --git a/src/types/searchScope.ts b/src/types/searchScope.ts index 74a8a5888..035d2bfcd 100644 --- a/src/types/searchScope.ts +++ b/src/types/searchScope.ts @@ -2,6 +2,7 @@ import { getNetworkNames, Network } from './network' import { getLayerLabels } from '../app/utils/content' import { HasScope, Layer } from '../oasis-nexus/api' import { TFunction } from 'i18next' +import { specialScopeNames } from '../config' export interface SearchScope { network: Network @@ -14,6 +15,7 @@ export const MainnetEmerald: SearchScope = { } export const getNameForScope = (t: TFunction, scope: SearchScope) => + specialScopeNames[scope.network]?.[scope.layer] ?? `${getLayerLabels(t)[scope.layer]} ${getNetworkNames(t)[scope.network]}` export const getKeyForScope: (scope: SearchScope) => string = ({ network, layer }) => `${network}.${layer}` From 16f838c54108c825c87568c8526a615250ceb8e1 Mon Sep 17 00:00:00 2001 From: Kristof Csillag Date: Thu, 30 May 2024 19:01:59 +0200 Subject: [PATCH 02/10] Centralize how scope routes are built --- src/app/utils/route-utils.ts | 54 ++++++++++++++---------------------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/src/app/utils/route-utils.ts b/src/app/utils/route-utils.ts index b518783aa..70eaecfb6 100644 --- a/src/app/utils/route-utils.ts +++ b/src/app/utils/route-utils.ts @@ -65,38 +65,34 @@ export abstract class RouteUtils { }, } satisfies Record> - static getDashboardRoute = ({ network, layer }: SearchScope) => { + static getScopeRoute = ({ network, layer }: SearchScope) => { return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}` } - static getLatestTransactionsRoute = ({ network, layer }: SearchScope) => { - return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/tx` + static getDashboardRoute = (scope: SearchScope) => this.getScopeRoute(scope) + + static getLatestTransactionsRoute = (scope: SearchScope) => { + return `${this.getScopeRoute(scope)}/tx` } - static getTopTokensRoute = ({ network, layer }: SearchScope) => { - return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/token` + static getTopTokensRoute = (scope: SearchScope) => { + return `${this.getScopeRoute(scope)}/token` } - static getLatestBlocksRoute = ({ network, layer }: SearchScope) => { - return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/block` + static getLatestBlocksRoute = (scope: SearchScope) => { + return `${this.getScopeRoute(scope)}/block` } - static getBlockRoute = ({ network, layer }: SearchScope, blockHeight: number) => { - return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/block/${encodeURIComponent( - blockHeight, - )}` + static getBlockRoute = (scope: SearchScope, blockHeight: number) => { + return `${this.getScopeRoute(scope)}/block/${encodeURIComponent(blockHeight)}` } static getTransactionRoute = (scope: SearchScope, txHash: string) => { - return `/${encodeURIComponent(scope.network)}/${encodeURIComponent(scope.layer)}/tx/${encodeURIComponent( - txHash, - )}` + return `${this.getScopeRoute(scope)}/tx/${encodeURIComponent(txHash)}` } - static getAccountRoute = ({ network, layer }: SearchScope, account: string) => { - return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/address/${encodeURIComponent( - account, - )}` + static getAccountRoute = (scope: SearchScope, accountAddress: string) => { + return `${this.getScopeRoute(scope)}/address/${encodeURIComponent(accountAddress)}` } static getAccountsRoute = (network: Network) => { @@ -128,28 +124,20 @@ export abstract class RouteUtils { static getSearchRoute = (scope: SearchScope | undefined, searchTerm: string) => { return scope - ? `/${encodeURIComponent(scope.network)}/${encodeURIComponent(scope.layer)}/search?q=${encodeURIComponent(searchTerm)}` + ? `${this.getScopeRoute(scope)}/search?q=${encodeURIComponent(searchTerm)}` : `/search?q=${encodeURIComponent(searchTerm)}` } - static getTokenRoute = ({ network, layer }: SearchScope, tokenAddress: string) => { - return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/token/${encodeURIComponent( - tokenAddress, - )}` + static getTokenRoute = (scope: SearchScope, tokenAddress: string) => { + return `${this.getScopeRoute(scope)}/token/${encodeURIComponent(tokenAddress)}` } - static getTokenHoldersRoute = ({ network, layer }: SearchScope, tokenAddress: string) => { - return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/token/${encodeURIComponent( - tokenAddress, - )}/holders` + static getTokenHoldersRoute = (scope: SearchScope, tokenAddress: string) => { + return `${this.getScopeRoute(scope)}/token/${encodeURIComponent(tokenAddress)}/holders` } - static getNFTInstanceRoute = ( - { network, layer }: SearchScope, - contractAddress: string, - instanceId: string, - ): string => - `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}/token/${encodeURIComponent( + static getNFTInstanceRoute = (scope: SearchScope, contractAddress: string, instanceId: string): string => + `${this.getScopeRoute(scope)}/token/${encodeURIComponent( contractAddress, )}/instance/${encodeURIComponent(instanceId)}` From 1ace609b94960c61fd32818f1fb24ab2a8bcaddf Mon Sep 17 00:00:00 2001 From: Kristof Csillag Date: Mon, 3 Jun 2024 16:20:14 +0200 Subject: [PATCH 03/10] Add code for customizing scope paths Normally the "sapphire" paratime on the "testnet" network will be available via "testnet/sapphire". This commit adds a config option to override the paths for specific paratimes with any two-word constant. (So that we can use "magic/kingdom" instead of "testnet/sapphire", if we want to.) --- src/app/utils/route-utils.ts | 53 ++++++++++++++++++++++++++++++------ src/config.ts | 5 ++++ 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/app/utils/route-utils.ts b/src/app/utils/route-utils.ts index 70eaecfb6..b5057ba70 100644 --- a/src/app/utils/route-utils.ts +++ b/src/app/utils/route-utils.ts @@ -5,7 +5,7 @@ import { AppError, AppErrors } from '../../types/errors' import { EvmTokenType, Layer } from '../../oasis-nexus/api' import { Network } from '../../types/network' import { SearchScope } from '../../types/searchScope' -import { isStableDeploy } from '../../config' +import { isStableDeploy, specialScopePaths } from '../../config' import { getSearchTermFromRequest } from '../components/Search/search-utils' import type { HasLayer } from '../../types/layers' @@ -37,6 +37,33 @@ export type SpecifiedPerEnabledLayer = { export type SpecifiedPerEnabledRuntime = SpecifiedPerEnabledLayer +export const specialScopeRecognition: Partial>>> = {} + +function invertSpecialScopePaths() { + const networks = Object.keys(specialScopePaths) as Network[] + + networks.forEach(network => { + const networkPaths = specialScopePaths[network]! + const layers = Object.keys(networkPaths) as Layer[] + layers.forEach(layer => { + const [word1, word2] = networkPaths[layer]! + if (!specialScopeRecognition[word1]) { + specialScopeRecognition[word1] = {} + } + if (specialScopeRecognition[word1]![word2]) { + const other = specialScopeRecognition[word1]![word2]! + console.warn( + `Wrong config: conflicting special scope paths ${word1}/${word2} definitions used both for ${other.network}/${other.layer} and ${network}/${layer} `, + ) + } else { + specialScopeRecognition[word1]![word2] = { network, layer } + } + }) + }) +} + +invertSpecialScopePaths() + export const hiddenLayers: Layer[] = [Layer.pontusxdev] export const isLayerHidden = (layer: Layer): boolean => hiddenLayers.includes(layer) @@ -66,7 +93,11 @@ export abstract class RouteUtils { } satisfies Record> static getScopeRoute = ({ network, layer }: SearchScope) => { - return `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}` + const specialPath = specialScopePaths[network]?.[layer] + const result = specialPath + ? `/${specialPath[0]}/${specialPath[1]}` + : `/${encodeURIComponent(network)}/${encodeURIComponent(layer)}` + return result } static getDashboardRoute = (scope: SearchScope) => this.getScopeRoute(scope) @@ -303,19 +334,25 @@ export const runtimeTransactionParamLoader = async ({ params }: LoaderFunctionAr return validateRuntimeTxHashParam(params.hash!) } -export const assertEnabledScope = ({ - network, - layer, -}: { +export const assertEnabledScope = (params: { network: string | undefined layer: string | undefined }): SearchScope => { - if (!network || !RouteUtils.getEnabledNetworks().includes(network as Network)) { + const { network: networkLike, layer: layerLike } = params + if (!networkLike || !layerLike) { + throw new AppError(AppErrors.InvalidUrl) + } + + const { network, layer } = specialScopeRecognition[networkLike]?.[layerLike] ?? { + network: networkLike as Network, + layer: layerLike as Layer, + } + + if (!RouteUtils.getEnabledNetworks().includes(network as Network)) { throw new AppError(AppErrors.InvalidUrl) } if ( - !layer || // missing param !RouteUtils.getAllLayersForNetwork(network as Network).enabled.includes(layer as Layer) // unsupported on network ) { throw new AppError(AppErrors.UnsupportedLayer) diff --git a/src/config.ts b/src/config.ts index 79c0039b0..527106b3a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -208,3 +208,8 @@ export const specialScopeNames: Partial>>> = { + [Network.mainnet]: {}, + [Network.testnet]: {}, +} From 287db7b589dd484e15e26c98f6b7384e20fd6945 Mon Sep 17 00:00:00 2001 From: Kristof Csillag Date: Wed, 29 May 2024 16:13:06 +0200 Subject: [PATCH 04/10] Add config variable for skipping the graph This is mostly useful if we want to restrict a deployment to display only a few layers. --- .changelog/1441.internal.md | 1 + .env | 1 + .env.production | 1 + src/app/utils/route-utils.ts | 1 + src/routes.tsx | 12 ++++++++---- src/types/global.d.ts | 1 + 6 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 .changelog/1441.internal.md diff --git a/.changelog/1441.internal.md b/.changelog/1441.internal.md new file mode 100644 index 000000000..9de0c9493 --- /dev/null +++ b/.changelog/1441.internal.md @@ -0,0 +1 @@ +Add more configuration options for paratimes diff --git a/.env b/.env index 41f5ce993..ffcfc490d 100644 --- a/.env +++ b/.env @@ -27,4 +27,5 @@ 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 +# REACT_APP_SKIP_GRAPH=true REACT_APP_SHOW_FIAT_VALUES=true diff --git a/.env.production b/.env.production index 165b287f8..6551bf3ff 100644 --- a/.env.production +++ b/.env.production @@ -22,4 +22,5 @@ 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 +# REACT_APP_SKIP_GRAPH=true REACT_APP_SHOW_FIAT_VALUES=true diff --git a/src/app/utils/route-utils.ts b/src/app/utils/route-utils.ts index b5057ba70..0cbbfec79 100644 --- a/src/app/utils/route-utils.ts +++ b/src/app/utils/route-utils.ts @@ -11,6 +11,7 @@ import type { HasLayer } from '../../types/layers' export const fixedNetwork = process.env.REACT_APP_FIXED_NETWORK as Network | undefined export const fixedLayer = process.env.REACT_APP_FIXED_LAYER as Layer | undefined +export const skipGraph = !!fixedLayer || !!(process.env.REACT_APP_SKIP_GRAPH as boolean | undefined) export type ScopeFreedom = | 'network' // We can select only the network diff --git a/src/routes.tsx b/src/routes.tsx index f183bd10a..1964e2ae3 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -25,6 +25,7 @@ import { fixedNetwork, fixedLayer, RouteUtils, + skipGraph, } from './app/utils/route-utils' import { RoutingErrorPage } from './app/pages/RoutingErrorPage' import { ThemeByNetwork, withDefaultTheme } from './app/components/ThemeByNetwork' @@ -72,7 +73,7 @@ const NetworkSpecificPart = () => ( ) /** - * In case of being restricted to a specific layer, jump to a dashboard + * In case of being restricted to a specific layer or layers, jump to a dashboard * * This should be rendered on the landing page, since we don't want the opening graph. */ @@ -82,8 +83,11 @@ const RedirectToDashboard: FC = () => { useEffect(() => navigate( RouteUtils.getDashboardRoute({ - network: fixedNetwork ?? RouteUtils.getEnabledNetworksForLayer(fixedLayer!)[0]!, - layer: fixedLayer!, + network: + fixedNetwork ?? fixedLayer + ? RouteUtils.getEnabledNetworksForLayer(fixedLayer)[0]! + : RouteUtils.getEnabledScopes()[0].network, + layer: fixedLayer ?? RouteUtils.getEnabledScopes()[0].layer, }), ), ) @@ -106,7 +110,7 @@ export const routes: RouteObject[] = [ children: [ { path: '/', - element: fixedLayer ? : withDefaultTheme(, true), + element: skipGraph ? : withDefaultTheme(, true), }, ...(!!fixedNetwork && !!fixedLayer ? [] diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 42bdd6740..ce3fbc22b 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -28,6 +28,7 @@ declare global { REACT_APP_STAGING_URLS?: string REACT_APP_FIXED_NETWORK?: string REACT_APP_FIXED_LAYER?: string + REACT_APP_SKIP_GRAPH?: string REACT_APP_SHOW_FIAT_VALUES: 'true' | 'false' } } From fdb3e58a9d54459617a8a88a65d8c28079b0eb0f Mon Sep 17 00:00:00 2001 From: Kristof Csillag Date: Wed, 5 Jun 2024 01:42:51 +0200 Subject: [PATCH 05/10] Rename ThemeByNetwork to ThemeByScope, preparing for extension --- .storybook/preview.tsx | 2 +- src/app/components/AnalyticsConsent/index.tsx | 6 +++--- .../components/{ThemeByNetwork => ThemeByScope}/index.tsx | 6 +++--- src/app/pages/HomePage/index.tsx | 6 +++--- src/app/pages/RoutingErrorPage/index.tsx | 6 +++--- src/app/utils/renderWithProviders.tsx | 2 +- src/routes.tsx | 6 +++--- 7 files changed, 17 insertions(+), 17 deletions(-) rename src/app/components/{ThemeByNetwork => ThemeByScope}/index.tsx (82%) diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index a17c4bcaf..7677f19cb 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -2,7 +2,7 @@ import React from 'react' import { Preview } from '@storybook/react' import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport' import '../src/locales/i18n' -import { withDefaultTheme } from '../src/app/components/ThemeByNetwork' +import { withDefaultTheme } from '../src/app/components/ThemeByScope' import { initialize, mswLoader } from 'msw-storybook-addon' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { handlers } from '../internals/mocks/msw-handlers' diff --git a/src/app/components/AnalyticsConsent/index.tsx b/src/app/components/AnalyticsConsent/index.tsx index 721cdebe0..4c8ff5d7c 100644 --- a/src/app/components/AnalyticsConsent/index.tsx +++ b/src/app/components/AnalyticsConsent/index.tsx @@ -6,7 +6,7 @@ import Button from '@mui/material/Button' import Link from '@mui/material/Link' import { Trans, useTranslation } from 'react-i18next' import * as matomo from './initializeMatomo' -import { ThemeByNetwork } from '../ThemeByNetwork' +import { ThemeByScope } from '../ThemeByScope' import { Network } from '../../../types/network' import { AnalyticsIsBlocked } from './AnalyticsIsBlocked' import { AnalyticsDialogLayout } from './AnalyticsDialogLayout' @@ -63,7 +63,7 @@ export const AnalyticsConsentProvider = (props: { children: React.ReactNode }) = > {props.children} {/* Theme is needed because AnalyticsConsentProvider is outside network-themed routes */} - + { @@ -80,7 +80,7 @@ export const AnalyticsConsentProvider = (props: { children: React.ReactNode }) = onReload={() => window.location.reload()} onClose={() => setHasAccepted('timed_out_matomo_not_loaded')} /> - + ) } diff --git a/src/app/components/ThemeByNetwork/index.tsx b/src/app/components/ThemeByScope/index.tsx similarity index 82% rename from src/app/components/ThemeByNetwork/index.tsx rename to src/app/components/ThemeByScope/index.tsx index da52c9481..c96cc09c2 100644 --- a/src/app/components/ThemeByNetwork/index.tsx +++ b/src/app/components/ThemeByScope/index.tsx @@ -5,7 +5,7 @@ import { getThemesForNetworks } from '../../../styles/theme' import CssBaseline from '@mui/material/CssBaseline' import { fixedNetwork } from '../../utils/route-utils' -export const ThemeByNetwork: FC<{ network: Network; isRootTheme: boolean; children: React.ReactNode }> = ({ +export const ThemeByScope: FC<{ network: Network; isRootTheme: boolean; children: React.ReactNode }> = ({ network, isRootTheme, children, @@ -17,10 +17,10 @@ export const ThemeByNetwork: FC<{ network: Network; isRootTheme: boolean; childr ) export const withDefaultTheme = (node: ReactNode, alwaysMainnet = false) => ( - {node} - + ) diff --git a/src/app/pages/HomePage/index.tsx b/src/app/pages/HomePage/index.tsx index eab589ecf..0d53f27f6 100644 --- a/src/app/pages/HomePage/index.tsx +++ b/src/app/pages/HomePage/index.tsx @@ -14,7 +14,7 @@ import { useTranslation } from 'react-i18next' import { ParaTimeSelectorStep } from './Graph/types' import { BuildBanner } from '../../components/BuildBanner' import { useSearchQueryNetworkParam } from '../../hooks/useSearchQueryNetworkParam' -import { ThemeByNetwork } from '../../components/ThemeByNetwork' +import { ThemeByScope } from '../../components/ThemeByScope' import { NetworkOfflineBanner } from '../../components/OfflineBanner' import { useIsApiReachable } from '../../components/OfflineBanner/hook' @@ -168,7 +168,7 @@ export const HomePage: FC = () => { )} - + { onGraphZoomedIn={setIsGraphZoomedIn} /> - + diff --git a/src/app/pages/RoutingErrorPage/index.tsx b/src/app/pages/RoutingErrorPage/index.tsx index d581f00b3..159b4f68d 100644 --- a/src/app/pages/RoutingErrorPage/index.tsx +++ b/src/app/pages/RoutingErrorPage/index.tsx @@ -3,18 +3,18 @@ import Divider from '@mui/material/Divider' import { PageLayout } from '../../components/PageLayout' import { ErrorDisplay } from '../../components/ErrorDisplay' import { useRouteError } from 'react-router-dom' -import { ThemeByNetwork } from '../../components/ThemeByNetwork' +import { ThemeByScope } from '../../components/ThemeByScope' import { useScopeParam } from '../../hooks/useScopeParam' import { Network } from '../../../types/network' export const RoutingErrorPage: FC = () => { const scope = useScopeParam() return ( - + - + ) } diff --git a/src/app/utils/renderWithProviders.tsx b/src/app/utils/renderWithProviders.tsx index 8120e51c7..2556b7361 100644 --- a/src/app/utils/renderWithProviders.tsx +++ b/src/app/utils/renderWithProviders.tsx @@ -1,6 +1,6 @@ import { MemoryRouter } from 'react-router-dom' import { render } from '@testing-library/react' -import { withDefaultTheme } from '../components/ThemeByNetwork' +import { withDefaultTheme } from '../components/ThemeByScope' import React from 'react' import { useIsApiReachable, useRuntimeFreshness } from '../components/OfflineBanner/hook' diff --git a/src/routes.tsx b/src/routes.tsx index 1964e2ae3..909116b82 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -28,7 +28,7 @@ import { skipGraph, } from './app/utils/route-utils' import { RoutingErrorPage } from './app/pages/RoutingErrorPage' -import { ThemeByNetwork, withDefaultTheme } from './app/components/ThemeByNetwork' +import { ThemeByScope, withDefaultTheme } from './app/components/ThemeByScope' import { useRequiredScopeParam } from './app/hooks/useScopeParam' import { TokensPage } from './app/pages/TokensOverviewPage' import { AccountEventsCard } from 'app/pages/RuntimeAccountDetailsPage/AccountEventsCard' @@ -67,9 +67,9 @@ import { FC, useEffect } from 'react' import { AnalyticsConsentProvider } from './app/components/AnalyticsConsent' const NetworkSpecificPart = () => ( - + - + ) /** From 2e97ccb17b1cb726cfb24f30f1d08882bda22825 Mon Sep 17 00:00:00 2001 From: Kristof Csillag Date: Wed, 5 Jun 2024 01:44:38 +0200 Subject: [PATCH 06/10] Rename NetworkSpecificPart to ScopeSpecificPart, preparing for extension --- src/routes.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes.tsx b/src/routes.tsx index 909116b82..9ad5f9ffb 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -66,7 +66,7 @@ import { ConsensusAccountTransactionsCard } from './app/pages/ConsensusAccountDe import { FC, useEffect } from 'react' import { AnalyticsConsentProvider } from './app/components/AnalyticsConsent' -const NetworkSpecificPart = () => ( +const ScopeSpecificPart = () => ( @@ -122,7 +122,7 @@ export const routes: RouteObject[] = [ ]), { path: '/:_network/consensus', - element: , + element: , errorElement: , loader: async ({ params }): Promise => { return assertEnabledScope({ network: params._network, layer: Layer.consensus }) @@ -220,7 +220,7 @@ export const routes: RouteObject[] = [ }, { path: '/:_network/:_layer', - element: , + element: , errorElement: , loader: async ({ params }): Promise => { return assertEnabledScope({ network: params._network, layer: params._layer }) From 12ef6758021b1f87e904750ccb091a401f0d5cbe Mon Sep 17 00:00:00 2001 From: Kristof Csillag Date: Wed, 5 Jun 2024 01:58:31 +0200 Subject: [PATCH 07/10] Change semantics of getThemesForNetworks function Up to now, this function has returned all the themes, for all networks. Now it will only return one theme, for the requested network. --- src/app/components/ThemeByScope/index.tsx | 4 ++-- .../SearchResultsPage/GlobalSearchResultsView.tsx | 5 ++--- .../SearchResultsPage/ScopedSearchResultsView.tsx | 7 ++++--- .../pages/SearchResultsPage/SearchResultsList.tsx | 4 ++-- src/styles/theme/index.ts | 12 ++++++++---- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/app/components/ThemeByScope/index.tsx b/src/app/components/ThemeByScope/index.tsx index c96cc09c2..a8e3b2905 100644 --- a/src/app/components/ThemeByScope/index.tsx +++ b/src/app/components/ThemeByScope/index.tsx @@ -1,7 +1,7 @@ import { FC, ReactNode } from 'react' import { Network } from '../../../types/network' import { ThemeProvider } from '@mui/material/styles' -import { getThemesForNetworks } from '../../../styles/theme' +import { getThemeForNetwork } from '../../../styles/theme' import CssBaseline from '@mui/material/CssBaseline' import { fixedNetwork } from '../../utils/route-utils' @@ -10,7 +10,7 @@ export const ThemeByScope: FC<{ network: Network; isRootTheme: boolean; children isRootTheme, children, }) => ( - + {isRootTheme && } {children} diff --git a/src/app/pages/SearchResultsPage/GlobalSearchResultsView.tsx b/src/app/pages/SearchResultsPage/GlobalSearchResultsView.tsx index a847b50de..166500163 100644 --- a/src/app/pages/SearchResultsPage/GlobalSearchResultsView.tsx +++ b/src/app/pages/SearchResultsPage/GlobalSearchResultsView.tsx @@ -15,7 +15,7 @@ import { Network, } from '../../../types/network' import { HideMoreResults, ShowMoreResults } from './notifications' -import { getThemesForNetworks } from '../../../styles/theme' +import { getThemeForNetwork } from '../../../styles/theme' import { orderByLayer } from '../../../types/layers' import { useRedirectIfSingleResult } from './useRedirectIfSingleResult' import { SearchParams } from '../../components/Search/search-utils' @@ -30,7 +30,6 @@ export const GlobalSearchResultsView: FC<{ const [othersOpen, setOthersOpen] = useState(false) useRedirectIfSingleResult(undefined, searchParams, searchResults) - const themes = getThemesForNetworks() const networkNames = getNetworkNames(t) const { searchTerm } = searchParams @@ -51,7 +50,7 @@ export const GlobalSearchResultsView: FC<{ } const otherNetworks = RouteUtils.getEnabledNetworks().filter(isNotMainnet) - const notificationTheme = themes[Network.testnet] + const notificationTheme = getThemeForNetwork(Network.testnet) const mainnetResults = searchResults.filter(isOnMainnet).sort(orderByLayer) const otherResults = searchResults.filter(isNotOnMainnet).sort(orderByLayer) diff --git a/src/app/pages/SearchResultsPage/ScopedSearchResultsView.tsx b/src/app/pages/SearchResultsPage/ScopedSearchResultsView.tsx index 27cb31e5f..0030c0f0a 100644 --- a/src/app/pages/SearchResultsPage/ScopedSearchResultsView.tsx +++ b/src/app/pages/SearchResultsPage/ScopedSearchResultsView.tsx @@ -7,7 +7,7 @@ import { getInverseFilterForScope, SearchScope, } from '../../../types/searchScope' -import { getThemesForNetworks } from '../../../styles/theme' +import { getThemeForNetwork } from '../../../styles/theme' import { RouteUtils } from '../../utils/route-utils' import { SearchResults } from './hooks' import { SearchResultsList } from './SearchResultsList' @@ -27,12 +27,13 @@ export const ScopedSearchResultsView: FC<{ const { t } = useTranslation() const [othersOpen, setOthersOpen] = useState(false) const networkNames = getNetworkNames(t) - const themes = getThemesForNetworks() const isInWantedScope = getFilterForScope(wantedScope) const isNotInWantedScope = getInverseFilterForScope(wantedScope) const wantedResults = searchResults.filter(isInWantedScope) const otherResults = searchResults.filter(isNotInWantedScope) - const notificationTheme = themes[otherResults.some(isOnMainnet) ? Network.mainnet : Network.testnet] + const notificationTheme = getThemeForNetwork( + otherResults.some(isOnMainnet) ? Network.mainnet : Network.testnet, + ) useRedirectIfSingleResult(wantedScope, searchParams, searchResults) diff --git a/src/app/pages/SearchResultsPage/SearchResultsList.tsx b/src/app/pages/SearchResultsPage/SearchResultsList.tsx index 9d40a7a91..f20da2258 100644 --- a/src/app/pages/SearchResultsPage/SearchResultsList.tsx +++ b/src/app/pages/SearchResultsPage/SearchResultsList.tsx @@ -15,7 +15,7 @@ import { TokenResult, TransactionResult, } from './hooks' -import { getThemesForNetworks } from '../../../styles/theme' +import { getThemeForNetwork } from '../../../styles/theme' import { Network } from '../../../types/network' import { SubPageCard } from '../../components/SubPageCard' import { AllTokenPrices } from '../../../coin-gecko/api' @@ -44,7 +44,7 @@ export const SearchResultsList: FC<{ if (!numberOfResults) { return null } - const theme = getThemesForNetworks()[networkForTheme] + const theme = getThemeForNetwork(networkForTheme) return ( diff --git a/src/styles/theme/index.ts b/src/styles/theme/index.ts index ff2cec728..a9752c730 100644 --- a/src/styles/theme/index.ts +++ b/src/styles/theme/index.ts @@ -9,7 +9,11 @@ export { testnetTheme } from './testnet/theme' export const tooltipDelay = 500 export const typingDelay = 1000 -export const getThemesForNetworks: () => Record = () => ({ - [Network.mainnet]: defaultTheme, - [Network.testnet]: testnetTheme, -}) +export const getThemeForNetwork = (network: Network): Theme => { + switch (network) { + case Network.mainnet: + return defaultTheme + case Network.testnet: + return testnetTheme + } +} From 19e662add5d5b8cf85cc600e66301afeac7bf39a Mon Sep 17 00:00:00 2001 From: Kristof Csillag Date: Wed, 5 Jun 2024 02:03:29 +0200 Subject: [PATCH 08/10] Rename getThemeForNetwork to getThemeForScope, preparing for extension --- src/app/components/ThemeByScope/index.tsx | 4 ++-- src/app/pages/SearchResultsPage/GlobalSearchResultsView.tsx | 4 ++-- src/app/pages/SearchResultsPage/ScopedSearchResultsView.tsx | 4 ++-- src/app/pages/SearchResultsPage/SearchResultsList.tsx | 4 ++-- src/styles/theme/index.ts | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/components/ThemeByScope/index.tsx b/src/app/components/ThemeByScope/index.tsx index a8e3b2905..3a2579bf7 100644 --- a/src/app/components/ThemeByScope/index.tsx +++ b/src/app/components/ThemeByScope/index.tsx @@ -1,7 +1,7 @@ import { FC, ReactNode } from 'react' import { Network } from '../../../types/network' import { ThemeProvider } from '@mui/material/styles' -import { getThemeForNetwork } from '../../../styles/theme' +import { getThemeForScope } from '../../../styles/theme' import CssBaseline from '@mui/material/CssBaseline' import { fixedNetwork } from '../../utils/route-utils' @@ -10,7 +10,7 @@ export const ThemeByScope: FC<{ network: Network; isRootTheme: boolean; children isRootTheme, children, }) => ( - + {isRootTheme && } {children} diff --git a/src/app/pages/SearchResultsPage/GlobalSearchResultsView.tsx b/src/app/pages/SearchResultsPage/GlobalSearchResultsView.tsx index 166500163..5d9e78c4c 100644 --- a/src/app/pages/SearchResultsPage/GlobalSearchResultsView.tsx +++ b/src/app/pages/SearchResultsPage/GlobalSearchResultsView.tsx @@ -15,7 +15,7 @@ import { Network, } from '../../../types/network' import { HideMoreResults, ShowMoreResults } from './notifications' -import { getThemeForNetwork } from '../../../styles/theme' +import { getThemeForScope } from '../../../styles/theme' import { orderByLayer } from '../../../types/layers' import { useRedirectIfSingleResult } from './useRedirectIfSingleResult' import { SearchParams } from '../../components/Search/search-utils' @@ -50,7 +50,7 @@ export const GlobalSearchResultsView: FC<{ } const otherNetworks = RouteUtils.getEnabledNetworks().filter(isNotMainnet) - const notificationTheme = getThemeForNetwork(Network.testnet) + const notificationTheme = getThemeForScope(Network.testnet) const mainnetResults = searchResults.filter(isOnMainnet).sort(orderByLayer) const otherResults = searchResults.filter(isNotOnMainnet).sort(orderByLayer) diff --git a/src/app/pages/SearchResultsPage/ScopedSearchResultsView.tsx b/src/app/pages/SearchResultsPage/ScopedSearchResultsView.tsx index 0030c0f0a..b5e4676b5 100644 --- a/src/app/pages/SearchResultsPage/ScopedSearchResultsView.tsx +++ b/src/app/pages/SearchResultsPage/ScopedSearchResultsView.tsx @@ -7,7 +7,7 @@ import { getInverseFilterForScope, SearchScope, } from '../../../types/searchScope' -import { getThemeForNetwork } from '../../../styles/theme' +import { getThemeForScope } from '../../../styles/theme' import { RouteUtils } from '../../utils/route-utils' import { SearchResults } from './hooks' import { SearchResultsList } from './SearchResultsList' @@ -31,7 +31,7 @@ export const ScopedSearchResultsView: FC<{ const isNotInWantedScope = getInverseFilterForScope(wantedScope) const wantedResults = searchResults.filter(isInWantedScope) const otherResults = searchResults.filter(isNotInWantedScope) - const notificationTheme = getThemeForNetwork( + const notificationTheme = getThemeForScope( otherResults.some(isOnMainnet) ? Network.mainnet : Network.testnet, ) diff --git a/src/app/pages/SearchResultsPage/SearchResultsList.tsx b/src/app/pages/SearchResultsPage/SearchResultsList.tsx index f20da2258..d98f07b38 100644 --- a/src/app/pages/SearchResultsPage/SearchResultsList.tsx +++ b/src/app/pages/SearchResultsPage/SearchResultsList.tsx @@ -15,7 +15,7 @@ import { TokenResult, TransactionResult, } from './hooks' -import { getThemeForNetwork } from '../../../styles/theme' +import { getThemeForScope } from '../../../styles/theme' import { Network } from '../../../types/network' import { SubPageCard } from '../../components/SubPageCard' import { AllTokenPrices } from '../../../coin-gecko/api' @@ -44,7 +44,7 @@ export const SearchResultsList: FC<{ if (!numberOfResults) { return null } - const theme = getThemeForNetwork(networkForTheme) + const theme = getThemeForScope(networkForTheme) return ( diff --git a/src/styles/theme/index.ts b/src/styles/theme/index.ts index a9752c730..a367f6682 100644 --- a/src/styles/theme/index.ts +++ b/src/styles/theme/index.ts @@ -9,7 +9,7 @@ export { testnetTheme } from './testnet/theme' export const tooltipDelay = 500 export const typingDelay = 1000 -export const getThemeForNetwork = (network: Network): Theme => { +export const getThemeForScope = (network: Network): Theme => { switch (network) { case Network.mainnet: return defaultTheme From e32b1adb1bb63bd76b8cb66a156a4e98d28d27d4 Mon Sep 17 00:00:00 2001 From: Kristof Csillag Date: Wed, 5 Jun 2024 02:06:55 +0200 Subject: [PATCH 09/10] Extend getThemeForScope function to accept layer --- src/app/components/ThemeByScope/index.tsx | 14 ++++++++------ src/app/pages/RoutingErrorPage/index.tsx | 2 +- src/routes.tsx | 13 ++++++++----- src/styles/theme/index.ts | 3 ++- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/app/components/ThemeByScope/index.tsx b/src/app/components/ThemeByScope/index.tsx index 3a2579bf7..23dba0716 100644 --- a/src/app/components/ThemeByScope/index.tsx +++ b/src/app/components/ThemeByScope/index.tsx @@ -4,13 +4,15 @@ import { ThemeProvider } from '@mui/material/styles' import { getThemeForScope } from '../../../styles/theme' import CssBaseline from '@mui/material/CssBaseline' import { fixedNetwork } from '../../utils/route-utils' +import { Layer } from '../../../oasis-nexus/api' -export const ThemeByScope: FC<{ network: Network; isRootTheme: boolean; children: React.ReactNode }> = ({ - network, - isRootTheme, - children, -}) => ( - +export const ThemeByScope: FC<{ + network: Network + layer?: Layer + isRootTheme: boolean + children: React.ReactNode +}> = ({ network, layer, isRootTheme, children }) => ( + {isRootTheme && } {children} diff --git a/src/app/pages/RoutingErrorPage/index.tsx b/src/app/pages/RoutingErrorPage/index.tsx index 159b4f68d..c19db1ac9 100644 --- a/src/app/pages/RoutingErrorPage/index.tsx +++ b/src/app/pages/RoutingErrorPage/index.tsx @@ -10,7 +10,7 @@ import { Network } from '../../../types/network' export const RoutingErrorPage: FC = () => { const scope = useScopeParam() return ( - + diff --git a/src/routes.tsx b/src/routes.tsx index 9ad5f9ffb..6125f6628 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -66,11 +66,14 @@ import { ConsensusAccountTransactionsCard } from './app/pages/ConsensusAccountDe import { FC, useEffect } from 'react' import { AnalyticsConsentProvider } from './app/components/AnalyticsConsent' -const ScopeSpecificPart = () => ( - - - -) +const ScopeSpecificPart = () => { + const { network, layer } = useRequiredScopeParam() + return ( + + + + ) +} /** * In case of being restricted to a specific layer or layers, jump to a dashboard diff --git a/src/styles/theme/index.ts b/src/styles/theme/index.ts index a367f6682..da7188d3a 100644 --- a/src/styles/theme/index.ts +++ b/src/styles/theme/index.ts @@ -2,6 +2,7 @@ import { Network } from '../../types/network' import { defaultTheme } from './defaultTheme' import { testnetTheme } from './testnet/theme' import type { Theme } from '@mui/material/styles/createTheme' +import { Layer } from '../../oasis-nexus/api' export { defaultTheme } from './defaultTheme' export { testnetTheme } from './testnet/theme' @@ -9,7 +10,7 @@ export { testnetTheme } from './testnet/theme' export const tooltipDelay = 500 export const typingDelay = 1000 -export const getThemeForScope = (network: Network): Theme => { +export const getThemeForScope = (network: Network, layer?: Layer): Theme => { switch (network) { case Network.mainnet: return defaultTheme From 04a687123886676426eed3728f181620e30e21ad Mon Sep 17 00:00:00 2001 From: Kristof Csillag Date: Wed, 5 Jun 2024 02:13:25 +0200 Subject: [PATCH 10/10] Add support for adding custom themes for specific paratimes --- src/config.ts | 6 ++++++ src/styles/theme/index.ts | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/config.ts b/src/config.ts index 527106b3a..92ad4e2bb 100644 --- a/src/config.ts +++ b/src/config.ts @@ -4,6 +4,7 @@ import { Layer } from './oasis-nexus/generated/api' import { NativeToken, NativeTokenInfo } from './types/ticker' import { SearchScope } from './types/searchScope' import { Network } from './types/network' +import type { Theme } from '@mui/material/styles/createTheme' export const consensusDecimals = 9 /** @@ -213,3 +214,8 @@ export const specialScopePaths: Partial>>> = { + [Network.mainnet]: {}, + [Network.testnet]: {}, +} diff --git a/src/styles/theme/index.ts b/src/styles/theme/index.ts index da7188d3a..aabd697fd 100644 --- a/src/styles/theme/index.ts +++ b/src/styles/theme/index.ts @@ -3,6 +3,7 @@ import { defaultTheme } from './defaultTheme' import { testnetTheme } from './testnet/theme' import type { Theme } from '@mui/material/styles/createTheme' import { Layer } from '../../oasis-nexus/api' +import { specialScopeThemes } from '../../config' export { defaultTheme } from './defaultTheme' export { testnetTheme } from './testnet/theme' @@ -11,6 +12,9 @@ export const tooltipDelay = 500 export const typingDelay = 1000 export const getThemeForScope = (network: Network, layer?: Layer): Theme => { + const specialTheme = layer ? specialScopeThemes[network]?.[layer] : undefined + if (specialTheme) return specialTheme + switch (network) { case Network.mainnet: return defaultTheme