diff --git a/new-ui/src/pages/compact/CompactLocationsPage/CompactLocationsPage.tsx b/new-ui/src/pages/compact/CompactLocationsPage/CompactLocationsPage.tsx index f9c467419..1a9e864b8 100644 --- a/new-ui/src/pages/compact/CompactLocationsPage/CompactLocationsPage.tsx +++ b/new-ui/src/pages/compact/CompactLocationsPage/CompactLocationsPage.tsx @@ -16,17 +16,15 @@ import { getLocationsQueryOptions, getTunnelsQueryOptions, } from '../../../shared/rust-api/query'; -import { useAppStore, useTrayConnectionError } from '../../../shared/store/useAppStore'; +import { useAppStore } from '../../../shared/store/useAppStore'; import { ThemeSpacing } from '../../../shared/types'; import { isPresent } from '../../../shared/utils/isPresent'; import { CompactPage } from '../CompactPage/CompactPage'; import { InstanceSwitcher } from './components/InstanceSwitcher'; -import { TrayConnectionError } from './components/TrayConnectionError'; export const CompactLocationsPage = () => { const { viewSelection: selection, setViewSelection } = useAppData(); const openLocation = useAppStore((s) => s.expandedLocation); - const connectionError = useTrayConnectionError((s) => s.visible); const routeData = useLoaderData({ from: '/compact/' }); @@ -78,37 +76,33 @@ export const CompactLocationsPage = () => { }} > - {connectionError ? ( - - ) : ( - -
- -
- {displayedLocations.map((location) => { - const isOpen = - location.id === openLocation || displayedLocations.length === 1; - return ( - { - if (isOpen) { - useAppStore.setState({ expandedLocation: null }); - } else { - useAppStore.setState({ expandedLocation: location.id }); - } - }} - /> - ); - })} -
+ +
+ +
+ {displayedLocations.map((location) => { + const isOpen = + location.id === openLocation || displayedLocations.length === 1; + return ( + { + if (isOpen) { + useAppStore.setState({ expandedLocation: null }); + } else { + useAppStore.setState({ expandedLocation: location.id }); + } + }} + /> + ); + })}
- - )} +
+
diff --git a/new-ui/src/pages/compact/CompactLocationsPage/components/TrayConnectionError.scss b/new-ui/src/pages/compact/CompactLocationsPage/components/TrayConnectionError.scss deleted file mode 100644 index 9389f841e..000000000 --- a/new-ui/src/pages/compact/CompactLocationsPage/components/TrayConnectionError.scss +++ /dev/null @@ -1,20 +0,0 @@ -.tray-connection-error { - flex: 1 1 auto; - box-sizing: border-box; - border-radius: var(--radius-lg); - padding: var(--spacing-lg); - background-color: var(--bg-dark-blue-40); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: var(--spacing-2xl); - - .description { - width: 296px; - font: var(--t-body-xs-400); - color: var(--fg-white-100); - text-align: center; - opacity: 0.7; - } -} diff --git a/new-ui/src/pages/compact/CompactLocationsPage/components/TrayConnectionError.tsx b/new-ui/src/pages/compact/CompactLocationsPage/components/TrayConnectionError.tsx deleted file mode 100644 index d624a4e11..000000000 --- a/new-ui/src/pages/compact/CompactLocationsPage/components/TrayConnectionError.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import './TrayConnectionError.scss'; -import { Button } from '../../../../shared/components/Button/Button'; -import { ButtonVariant } from '../../../../shared/components/Button/types'; -import { Icon, IconKind } from '../../../../shared/components/Icon'; -import { useTrayConnectionError } from '../../../../shared/store/useAppStore'; - -export const TrayConnectionError = () => { - const close = () => useTrayConnectionError.setState({ visible: false }); - - return ( -
- -

- One or more external services are unavailable or unreachable. This may be caused - by a network issue or a temporary service outage. Please try again later. -

-
- ); -}; diff --git a/new-ui/src/shared/components/LocationCard/LocationCard.tsx b/new-ui/src/shared/components/LocationCard/LocationCard.tsx index 5c204e120..35a08166e 100644 --- a/new-ui/src/shared/components/LocationCard/LocationCard.tsx +++ b/new-ui/src/shared/components/LocationCard/LocationCard.tsx @@ -12,6 +12,7 @@ import { LocationCardProvider, useLocationCardContext } from './context/context' import { LocationCardViews, type LocationCardViewsValue } from './context/types'; import { ConnectedView } from './views/ConnectedView/ConnectedView'; import { DefaultView } from './views/DefaultView/DefaultView'; +import { LocationCardConnectionErrorView } from './views/LocationCardConnectionErrorView/LocationCardConnectionErrorView'; import { LocationCardMfaEmailView } from './views/LocationCardMfaEmailView/LocationCardMfaEmailView'; import { LocationCardMfaMobileView } from './views/LocationCardMfaMobileView/LocationCardMfaMobileView'; import { LocationCardMfaOidcView } from './views/LocationCardMfaOidcView/LocationCardMfaOidcView'; @@ -37,6 +38,7 @@ const views: Record = { [LocationCardViews.Connecting]: null, [LocationCardViews.Connected]: , [LocationCardViews.PostureCheckFail]: , + [LocationCardViews.ConnectionError]: , }; interface InnerProps { diff --git a/new-ui/src/shared/components/LocationCard/context/types.ts b/new-ui/src/shared/components/LocationCard/context/types.ts index a17e666e3..007abfe48 100644 --- a/new-ui/src/shared/components/LocationCard/context/types.ts +++ b/new-ui/src/shared/components/LocationCard/context/types.ts @@ -8,6 +8,7 @@ export const LocationCardViews = { Connecting: 'connecting', Connected: 'connected', PostureCheckFail: 'posture-check-fail', + ConnectionError: 'connection-error', } as const; export type LocationCardViewsValue = diff --git a/new-ui/src/shared/components/LocationCard/hooks/useMfaOidcConnect.ts b/new-ui/src/shared/components/LocationCard/hooks/useMfaOidcConnect.ts index 2cc7611cc..0abb7e1d2 100644 --- a/new-ui/src/shared/components/LocationCard/hooks/useMfaOidcConnect.ts +++ b/new-ui/src/shared/components/LocationCard/hooks/useMfaOidcConnect.ts @@ -4,7 +4,6 @@ import { error } from '@tauri-apps/plugin-log'; import { useCallback, useEffect, useRef, useState } from 'react'; import { api } from '../../../rust-api/api'; import { getInstancesQueryOptions } from '../../../rust-api/query'; -import { useTrayConnectionError } from '../../../store/useAppStore'; import { CLIENT_MFA_ENDPOINT, isEdgeUnavailable, @@ -147,7 +146,7 @@ export const useMfaOidcConnect = () => { return; } if (isEdgeUnavailable(e)) { - useTrayConnectionError.setState({ visible: true }); + setView(LocationCardViews.ConnectionError); return; } setStartError( diff --git a/new-ui/src/shared/components/LocationCard/views/LocationCardConnectionErrorView/LocationCardConnectionErrorView.tsx b/new-ui/src/shared/components/LocationCard/views/LocationCardConnectionErrorView/LocationCardConnectionErrorView.tsx new file mode 100644 index 000000000..a19ddd1c6 --- /dev/null +++ b/new-ui/src/shared/components/LocationCard/views/LocationCardConnectionErrorView/LocationCardConnectionErrorView.tsx @@ -0,0 +1,33 @@ +import './style.scss'; +import { ThemeSpacing } from '../../../../types'; +import { Button } from '../../../Button/Button'; +import { ButtonVariant } from '../../../Button/types'; +import { Divider } from '../../../Divider/Divider'; +import { Icon, IconKind } from '../../../Icon'; +import { SizedBox } from '../../../SizedBox/SizedBox'; +import { useLocationCardContext } from '../../context/context'; +import { LocationCardViews } from '../../context/types'; + +export const LocationCardConnectionErrorView = () => { + const { setView } = useLocationCardContext(); + + return ( +
+ + + + +

+ One or more external services are unavailable or unreachable. This may be caused + by a network issue or a temporary service outage. Please try again later. +

+ +
+ ); +}; diff --git a/new-ui/src/shared/components/LocationCard/views/LocationCardConnectionErrorView/style.scss b/new-ui/src/shared/components/LocationCard/views/LocationCardConnectionErrorView/style.scss new file mode 100644 index 000000000..076a82814 --- /dev/null +++ b/new-ui/src/shared/components/LocationCard/views/LocationCardConnectionErrorView/style.scss @@ -0,0 +1,11 @@ +.location-card-connection-error-view { + display: flex; + flex-direction: column; + align-items: center; + + .description { + font: var(--t-body-xs-400); + color: var(--fg-white-70); + text-align: center; + } +} diff --git a/new-ui/src/shared/components/LocationCard/views/LocationCardMfaEmailView/LocationCardMfaEmailView.tsx b/new-ui/src/shared/components/LocationCard/views/LocationCardMfaEmailView/LocationCardMfaEmailView.tsx index 6be641c3c..4b1387ba7 100644 --- a/new-ui/src/shared/components/LocationCard/views/LocationCardMfaEmailView/LocationCardMfaEmailView.tsx +++ b/new-ui/src/shared/components/LocationCard/views/LocationCardMfaEmailView/LocationCardMfaEmailView.tsx @@ -1,5 +1,4 @@ import { useCallback, useEffect, useState } from 'react'; -import { useTrayConnectionError } from '../../../../store/useAppStore'; import { ThemeSpacing } from '../../../../types'; import { isPresent } from '../../../../utils/isPresent'; import { Button } from '../../../Button/Button'; @@ -33,7 +32,7 @@ export const LocationCardMfaEmailView = () => { setPostureError(msg); setView(LocationCardViews.PostureCheckFail); }, - onServiceUnavailable: () => useTrayConnectionError.setState({ visible: true }), + onServiceUnavailable: () => setView(LocationCardViews.ConnectionError), }, ); diff --git a/new-ui/src/shared/components/LocationCard/views/LocationCardMfaMobileView/LocationCardMfaMobileView.tsx b/new-ui/src/shared/components/LocationCard/views/LocationCardMfaMobileView/LocationCardMfaMobileView.tsx index 91fb81923..a3bb41f12 100644 --- a/new-ui/src/shared/components/LocationCard/views/LocationCardMfaMobileView/LocationCardMfaMobileView.tsx +++ b/new-ui/src/shared/components/LocationCard/views/LocationCardMfaMobileView/LocationCardMfaMobileView.tsx @@ -1,6 +1,5 @@ import './style.scss'; import { useEffect, useRef, useState } from 'react'; -import { useTrayConnectionError } from '../../../../store/useAppStore'; import { ThemeSpacing } from '../../../../types'; import { Button } from '../../../Button/Button'; import { ButtonVariant } from '../../../Button/types'; @@ -22,7 +21,7 @@ export const LocationCardMfaMobileView = () => { const { start, startError, qrValue, connectionError } = useMfaMobileConnect(location, { onConnected: () => setView(LocationCardViews.Connected), onPostureError: (message) => setPostureError(message ?? null), - onServiceUnavailable: () => useTrayConnectionError.setState({ visible: true }), + onServiceUnavailable: () => setView(LocationCardViews.ConnectionError), }); const [screen, setScreen] = useState('loading'); const startedRef = useRef(false); diff --git a/new-ui/src/shared/components/LocationCard/views/LocationCardMfaTotpView/LocationCardMfaTotpView.tsx b/new-ui/src/shared/components/LocationCard/views/LocationCardMfaTotpView/LocationCardMfaTotpView.tsx index 98e16f1bd..f6b0f3bcd 100644 --- a/new-ui/src/shared/components/LocationCard/views/LocationCardMfaTotpView/LocationCardMfaTotpView.tsx +++ b/new-ui/src/shared/components/LocationCard/views/LocationCardMfaTotpView/LocationCardMfaTotpView.tsx @@ -1,5 +1,4 @@ import { useCallback, useEffect, useState } from 'react'; -import { useTrayConnectionError } from '../../../../store/useAppStore'; import { ThemeSpacing } from '../../../../types'; import { isPresent } from '../../../../utils/isPresent'; import { Button } from '../../../Button/Button'; @@ -33,7 +32,7 @@ export const LocationCardMfaTotpView = () => { setPostureError(msg); setView(LocationCardViews.PostureCheckFail); }, - onServiceUnavailable: () => useTrayConnectionError.setState({ visible: true }), + onServiceUnavailable: () => setView(LocationCardViews.ConnectionError), }, ); diff --git a/new-ui/src/shared/store/useAppStore.tsx b/new-ui/src/shared/store/useAppStore.tsx index 47329fb92..d013881c3 100644 --- a/new-ui/src/shared/store/useAppStore.tsx +++ b/new-ui/src/shared/store/useAppStore.tsx @@ -20,11 +20,3 @@ export const useAppStore = create()( }, ), ); - -interface TrayConnectionErrorStore { - visible: boolean; -} - -export const useTrayConnectionError = create(() => ({ - visible: false, -}));