From bded1d32ba2fa3ceaefdf39e63849024a9d7e889 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Tue, 9 May 2023 12:58:09 -0700 Subject: [PATCH] feat(explorer,governance): always allow selecting a node, add node guard (#3678) --- apps/explorer/src/app/app.tsx | 26 +++- .../src/app/components/footer/footer.tsx | 80 ++++++------- apps/governance/src/app.tsx | 51 +++++--- .../governance/src/i18n/translations/dev.json | 3 +- .../src/integration/closed-markets.cy.ts | 2 + apps/trading-e2e/src/support/trading.ts | 2 + .../components/app-loader/app-loader.tsx | 2 +- apps/trading/components/app-loader/index.tsx | 1 - apps/trading/components/footer/footer.tsx | 11 +- apps/trading/pages/_app.page.tsx | 12 +- apps/trading/stores/global.ts | 2 - libs/cypress/mock.ts | 1 + .../components/app-failure}/app-failure.tsx | 10 +- .../src/components/app-failure/index.ts | 1 + libs/environment/src/components/index.ts | 1 + .../components/node-guard/NodeGuard.graphql | 11 ++ .../node-guard/__generated__/NodeGuard.ts | 51 ++++++++ .../components/node-guard/node-guard.mock.ts | 53 +++++++++ .../src/components/node-guard/node-guard.tsx | 13 +- .../src/components/node-switcher/row-data.tsx | 30 +---- libs/environment/src/hooks/index.ts | 1 + .../src/hooks/use-node-switcher-store.ts | 11 ++ libs/network-info/src/network-info.tsx | 111 +++++++++--------- 23 files changed, 318 insertions(+), 168 deletions(-) rename {apps/trading/components/app-loader => libs/environment/src/components/app-failure}/app-failure.tsx (65%) create mode 100644 libs/environment/src/components/app-failure/index.ts create mode 100644 libs/environment/src/components/node-guard/NodeGuard.graphql create mode 100644 libs/environment/src/components/node-guard/__generated__/NodeGuard.ts create mode 100644 libs/environment/src/components/node-guard/node-guard.mock.ts create mode 100644 libs/environment/src/hooks/use-node-switcher-store.ts diff --git a/apps/explorer/src/app/app.tsx b/apps/explorer/src/app/app.tsx index 7afe05ce2..e17ececb0 100644 --- a/apps/explorer/src/app/app.tsx +++ b/apps/explorer/src/app/app.tsx @@ -1,9 +1,18 @@ -import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment'; +import { + AppFailure, + NetworkLoader, + NodeGuard, + NodeSwitcherDialog, + useEnvironment, + useInitializeEnv, + useNodeSwitcherStore, +} from '@vegaprotocol/environment'; import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider'; import { Loader, Splash } from '@vegaprotocol/ui-toolkit'; import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client'; import { RouterProvider } from 'react-router-dom'; import { router } from './routes/router-config'; +import { t } from '@vegaprotocol/i18n'; const splashLoading = ( @@ -12,10 +21,23 @@ const splashLoading = ( ); function App() { + const { VEGA_URL } = useEnvironment(); + const [nodeSwitcherOpen, setNodeSwitcherOpen] = useNodeSwitcherStore( + (store) => [store.dialogOpen, store.setDialogOpen] + ); return ( - + {t('Loading')}} + failure={} + > + + + ); diff --git a/apps/explorer/src/app/components/footer/footer.tsx b/apps/explorer/src/app/components/footer/footer.tsx index fd9f00c6d..e41fe3253 100644 --- a/apps/explorer/src/app/components/footer/footer.tsx +++ b/apps/explorer/src/app/components/footer/footer.tsx @@ -1,13 +1,19 @@ -import { NodeSwitcherDialog, useEnvironment } from '@vegaprotocol/environment'; +import { + useEnvironment, + useNodeSwitcherStore, +} from '@vegaprotocol/environment'; import { t } from '@vegaprotocol/i18n'; import { useScreenDimensions } from '@vegaprotocol/react-helpers'; import { ExternalLink, Link } from '@vegaprotocol/ui-toolkit'; -import { useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { ENV } from '../../config/env'; export const Footer = () => { const { VEGA_URL, GIT_COMMIT_HASH, GIT_ORIGIN_URL } = useEnvironment(); - const [nodeSwitcherOpen, setNodeSwitcherOpen] = useState(false); + const setNodeSwitcherOpen = useNodeSwitcherStore( + (store) => store.setDialogOpen + ); + const { screenSize } = useScreenDimensions(); const showFullFeedbackLabel = useMemo( () => ['md', 'lg', 'xl', 'xxl', 'xxxl'].includes(screenSize), @@ -15,46 +21,40 @@ export const Footer = () => { ); return ( - <> -
-
- {GIT_COMMIT_HASH && ( -
-

- {t('Version')}:{' '} - - {GIT_COMMIT_HASH} - -

-
- )} - -
- {VEGA_URL && } - setNodeSwitcherOpen(true)}> - {t('Change')} - +
+
+ {GIT_COMMIT_HASH && ( +
+

+ {t('Version')}:{' '} + + {GIT_COMMIT_HASH} + +

+ )} -
- - {showFullFeedbackLabel ? t('Share your feedback') : t('Feedback')} - -
+
+ {VEGA_URL && } + setNodeSwitcherOpen(true)}> + {t('Change')} +
-
- - + +
+ + {showFullFeedbackLabel ? t('Share your feedback') : t('Feedback')} + +
+
+
); }; diff --git a/apps/governance/src/app.tsx b/apps/governance/src/app.tsx index 13e55d089..0e44162cc 100644 --- a/apps/governance/src/app.tsx +++ b/apps/governance/src/app.tsx @@ -37,6 +37,10 @@ import { useEnvironment, NetworkLoader, useInitializeEnv, + NodeGuard, + AppFailure, + NodeSwitcherDialog, + useNodeSwitcherStore, } from '@vegaprotocol/environment'; import { ENV } from './config'; import type { InMemoryCacheConfig } from '@apollo/client'; @@ -48,6 +52,7 @@ import { TELEMETRY_ON, } from './components/telemetry-dialog/telemetry-dialog'; import { useLocalStorage } from '@vegaprotocol/react-helpers'; +import { useTranslation } from 'react-i18next'; const cache: InMemoryCacheConfig = { typePolicies: { @@ -181,9 +186,19 @@ const ScrollToTop = () => { const AppContainer = () => { const { config, loading, error } = useEthereumConfig(); - const { VEGA_ENV, GIT_COMMIT_HASH, GIT_BRANCH, ETHEREUM_PROVIDER_URL } = - useEnvironment(); + const { + VEGA_ENV, + VEGA_URL, + GIT_COMMIT_HASH, + GIT_BRANCH, + ETHEREUM_PROVIDER_URL, + } = useEnvironment(); const [telemetryOn] = useLocalStorage(TELEMETRY_ON); + const { t } = useTranslation(); + const [nodeSwitcherOpen, setNodeSwitcher] = useNodeSwitcherStore((store) => [ + store.dialogOpen, + store.setDialogOpen, + ]); useEffect(() => { if (ENV.dsn && telemetryOn) { @@ -219,21 +234,29 @@ const AppContainer = () => {
- - loading={loading} - data={config} - error={error} - render={(cnf) => - cnf && ( - - ) + {t('Loading')}
} + failure={ + } - /> + > + + loading={loading} + data={config} + error={error} + render={(cnf) => + cnf && ( + + ) + } + /> +
+ ); }; diff --git a/apps/governance/src/i18n/translations/dev.json b/apps/governance/src/i18n/translations/dev.json index 8d9df1aca..d714cc82b 100644 --- a/apps/governance/src/i18n/translations/dev.json +++ b/apps/governance/src/i18n/translations/dev.json @@ -811,5 +811,6 @@ "OptOutOfTelemetry": "You can opt out any time via settings", "NoThanks": "No thanks", "ShareData": "Share data", - "ContinueSharingData": "Continue sharing data" + "ContinueSharingData": "Continue sharing data", + "NodeUnsuitable": "Node: {{url}} is unsuitable" } diff --git a/apps/trading-e2e/src/integration/closed-markets.cy.ts b/apps/trading-e2e/src/integration/closed-markets.cy.ts index a80f0ce47..0c63d9964 100644 --- a/apps/trading-e2e/src/integration/closed-markets.cy.ts +++ b/apps/trading-e2e/src/integration/closed-markets.cy.ts @@ -12,6 +12,7 @@ import { createMarketsDataFragment, assetQuery, networkParamsQuery, + nodeGuardQuery, } from '@vegaprotocol/mock'; import { addDecimalsFormatNumber, @@ -158,6 +159,7 @@ describe('Closed markets', { tags: '@smoke' }, () => { cy.mockGQL((req) => { aliasGQLQuery(req, 'ChainId', chainIdQuery()); aliasGQLQuery(req, 'Statistics', statisticsQuery()); + aliasGQLQuery(req, 'NodeGuard', nodeGuardQuery()); aliasGQLQuery(req, 'NetworkParams', networkParamsQuery()); aliasGQLQuery( req, diff --git a/apps/trading-e2e/src/support/trading.ts b/apps/trading-e2e/src/support/trading.ts index 99691e270..17b9f35f0 100644 --- a/apps/trading-e2e/src/support/trading.ts +++ b/apps/trading-e2e/src/support/trading.ts @@ -20,6 +20,7 @@ import { marketsDataQuery, marketsQuery, networkParamsQuery, + nodeGuardQuery, ordersQuery, positionsQuery, proposalListQuery, @@ -82,6 +83,7 @@ const mockTradingPage = ( ) => { aliasGQLQuery(req, 'ChainId', chainIdQuery()); aliasGQLQuery(req, 'Statistics', statisticsQuery()); + aliasGQLQuery(req, 'NodeGuard', nodeGuardQuery()); aliasGQLQuery( req, 'Markets', diff --git a/apps/trading/components/app-loader/app-loader.tsx b/apps/trading/components/app-loader/app-loader.tsx index 8a63dd8cb..64e9ac040 100644 --- a/apps/trading/components/app-loader/app-loader.tsx +++ b/apps/trading/components/app-loader/app-loader.tsx @@ -1,5 +1,6 @@ import type { InMemoryCacheConfig } from '@apollo/client'; import { + AppFailure, NetworkLoader, NodeGuard, useEnvironment, @@ -9,7 +10,6 @@ import { MaintenancePage } from '@vegaprotocol/ui-toolkit'; import { VegaWalletProvider } from '@vegaprotocol/wallet'; import dynamic from 'next/dynamic'; import type { ReactNode } from 'react'; -import { AppFailure } from './app-failure'; import { Web3Provider } from './web3-provider'; export const DynamicLoader = dynamic(() => import('../preloader/preloader'), { diff --git a/apps/trading/components/app-loader/index.tsx b/apps/trading/components/app-loader/index.tsx index 624edba38..2a7420559 100644 --- a/apps/trading/components/app-loader/index.tsx +++ b/apps/trading/components/app-loader/index.tsx @@ -1,3 +1,2 @@ -export * from './app-failure'; export * from './app-loader'; export * from './web3-provider'; diff --git a/apps/trading/components/footer/footer.tsx b/apps/trading/components/footer/footer.tsx index 8fdaa7f08..dd45db002 100644 --- a/apps/trading/components/footer/footer.tsx +++ b/apps/trading/components/footer/footer.tsx @@ -1,11 +1,14 @@ import { useCallback } from 'react'; -import { useEnvironment, useNodeHealth } from '@vegaprotocol/environment'; +import { + useEnvironment, + useNodeHealth, + useNodeSwitcherStore, +} from '@vegaprotocol/environment'; import { t } from '@vegaprotocol/i18n'; import type { Intent } from '@vegaprotocol/ui-toolkit'; import { Indicator, ExternalLink } from '@vegaprotocol/ui-toolkit'; import classNames from 'classnames'; import type { ButtonHTMLAttributes, ReactNode } from 'react'; -import { useGlobalStore } from '../../stores'; export const Footer = () => { return ( @@ -20,9 +23,7 @@ export const Footer = () => { export const NodeHealth = () => { const { VEGA_URL, VEGA_INCIDENT_URL } = useEnvironment(); - const setNodeSwitcher = useGlobalStore( - (store) => (open: boolean) => store.update({ nodeSwitcherDialog: open }) - ); + const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen); const { datanodeBlockHeight, text, intent } = useNodeHealth(); const onClick = useCallback(() => { setNodeSwitcher(true); diff --git a/apps/trading/pages/_app.page.tsx b/apps/trading/pages/_app.page.tsx index 05c86867e..1d1074b86 100644 --- a/apps/trading/pages/_app.page.tsx +++ b/apps/trading/pages/_app.page.tsx @@ -21,9 +21,10 @@ import { NodeSwitcherDialog, useEnvironment, useInitializeEnv, + useNodeSwitcherStore, } from '@vegaprotocol/environment'; import './styles.css'; -import { useGlobalStore, usePageTitleStore } from '../stores'; +import { usePageTitleStore } from '../stores'; import { Footer } from '../components/footer'; import DialogsContainer from './dialogs-container'; import ToastsManager from './toasts-manager'; @@ -115,11 +116,10 @@ function AppBody({ Component }: AppProps) { function VegaTradingApp(props: AppProps) { const status = useEnvironment((store) => store.status); - const { nodeSwitcherOpen, setNodeSwitcher } = useGlobalStore((store) => ({ - nodeSwitcherOpen: store.nodeSwitcherDialog, - setNodeSwitcher: (open: boolean) => - store.update({ nodeSwitcherDialog: open }), - })); + const [nodeSwitcherOpen, setNodeSwitcher] = useNodeSwitcherStore((store) => [ + store.dialogOpen, + store.setDialogOpen, + ]); useInitializeEnv(); diff --git a/apps/trading/stores/global.ts b/apps/trading/stores/global.ts index aac6a71b9..f631d6827 100644 --- a/apps/trading/stores/global.ts +++ b/apps/trading/stores/global.ts @@ -3,7 +3,6 @@ import { create } from 'zustand'; import produce from 'immer'; interface GlobalStore { - nodeSwitcherDialog: boolean; marketId: string | null; update: (store: Partial>) => void; shouldDisplayWelcomeDialog: boolean; @@ -15,7 +14,6 @@ interface PageTitleStore { } export const useGlobalStore = create()((set) => ({ - nodeSwitcherDialog: false, marketId: LocalStorage.getItem('marketId') || null, shouldDisplayWelcomeDialog: false, update: (newState) => { diff --git a/libs/cypress/mock.ts b/libs/cypress/mock.ts index 3c90c5cda..d2aff6cfc 100644 --- a/libs/cypress/mock.ts +++ b/libs/cypress/mock.ts @@ -7,6 +7,7 @@ export * from '../candles-chart/src/lib/chart.mock'; export * from '../deal-ticket/src/hooks/estimate-order.mock'; export * from '../deposits/src/lib/deposit.mock'; export * from '../environment/src/utils/node.mock'; +export * from '../environment/src/components/node-guard/node-guard.mock'; export * from '../fills/src/lib/fills.mock'; export * from '../proposals/src/lib/proposals-data-provider/proposals.mock'; export * from '../ledger/src/lib/ledger-entries.mock'; diff --git a/apps/trading/components/app-loader/app-failure.tsx b/libs/environment/src/components/app-failure/app-failure.tsx similarity index 65% rename from apps/trading/components/app-loader/app-failure.tsx rename to libs/environment/src/components/app-failure/app-failure.tsx index 842db1e2c..7afb9e4c3 100644 --- a/apps/trading/components/app-loader/app-failure.tsx +++ b/libs/environment/src/components/app-failure/app-failure.tsx @@ -1,6 +1,6 @@ import { t } from '@vegaprotocol/i18n'; import { Button } from '@vegaprotocol/ui-toolkit'; -import { useGlobalStore } from '../../stores'; +import { useNodeSwitcherStore } from '../../hooks/use-node-switcher-store'; export const AppFailure = ({ title, @@ -9,17 +9,13 @@ export const AppFailure = ({ title: string; error?: string | null; }) => { - const { setNodeSwitcher } = useGlobalStore((store) => ({ - nodeSwitcherOpen: store.nodeSwitcherDialog, - setNodeSwitcher: (open: boolean) => - store.update({ nodeSwitcherDialog: open }), - })); + const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen); const nonIdealWrapperClasses = 'h-full min-h-screen flex items-center justify-center'; return (
-

{title}

+

{title}

{error &&

{error}

}