diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/authentication/providers/auth.tsx b/app/ide-desktop/lib/dashboard/src/authentication/src/authentication/providers/auth.tsx index cd8452c0ede..8c8ae720003 100644 --- a/app/ide-desktop/lib/dashboard/src/authentication/src/authentication/providers/auth.tsx +++ b/app/ide-desktop/lib/dashboard/src/authentication/src/authentication/providers/auth.tsx @@ -163,6 +163,7 @@ const AuthContext = react.createContext({} as AuthContextType) /** Props for an {@link AuthProvider}. */ export interface AuthProviderProps { shouldStartInOfflineMode: boolean + supportsLocalBackend: boolean authService: authServiceModule.AuthService /** Callback to execute once the user has authenticated successfully. */ onAuthenticated: () => void @@ -171,7 +172,13 @@ export interface AuthProviderProps { /** A React provider for the Cognito API. */ export function AuthProvider(props: AuthProviderProps) { - const { shouldStartInOfflineMode, authService, onAuthenticated, children } = props + const { + shouldStartInOfflineMode, + supportsLocalBackend, + authService, + onAuthenticated, + children, + } = props const { cognito } = authService const { session, deinitializeSession } = sessionProvider.useSession() const { setBackendWithoutSavingType } = backendProvider.useSetBackend() @@ -208,8 +215,7 @@ export function AuthProvider(props: AuthProviderProps) { setUserSession(null) } else { const { accessToken, email } = session.val - const headers = new Headers() - headers.append('Authorization', `Bearer ${accessToken}`) + const headers = new Headers([['Authorization', `Bearer ${accessToken}`]]) const client = new http.Client(headers) const backend = new remoteBackend.RemoteBackend(client, logger) // The backend MUST be the remote backend before login is finished. @@ -294,7 +300,14 @@ export function AuthProvider(props: AuthProviderProps) { const goOfflineInternal = () => { setInitialized(true) setUserSession(OFFLINE_USER_SESSION) - setBackendWithoutSavingType(new localBackend.LocalBackend()) + if (supportsLocalBackend) { + setBackendWithoutSavingType(new localBackend.LocalBackend()) + } else { + // Provide dummy headers to avoid errors. This `Backend` will never be called as + // the entire UI will be disabled. + const client = new http.Client(new Headers([['Authorization', '']])) + setBackendWithoutSavingType(new remoteBackend.RemoteBackend(client, logger)) + } } const goOffline = () => { diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/components/app.tsx b/app/ide-desktop/lib/dashboard/src/authentication/src/components/app.tsx index 7bf4394f235..b507ffa087a 100644 --- a/app/ide-desktop/lib/dashboard/src/authentication/src/components/app.tsx +++ b/app/ide-desktop/lib/dashboard/src/authentication/src/components/app.tsx @@ -134,7 +134,13 @@ function App(props: AppProps) { * because the {@link AppRouter} relies on React hooks, which can't be used in the same React * component as the component that defines the provider. */ function AppRouter(props: AppProps) { - const { logger, isAuthenticationDisabled, shouldShowDashboard, onAuthenticated } = props + const { + logger, + supportsLocalBackend, + isAuthenticationDisabled, + shouldShowDashboard, + onAuthenticated, + } = props const navigate = hooks.useNavigate() // FIXME[sb]: After platform detection for Electron is merged in, `IS_DEV_MODE` should be // set to true on `ide watch`. @@ -190,6 +196,7 @@ function AppRouter(props: AppProps) { diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/projectActionButton.tsx b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/projectActionButton.tsx index 8a0aef9ea09..5a4d0d40934 100644 --- a/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/projectActionButton.tsx +++ b/app/ide-desktop/lib/dashboard/src/authentication/src/dashboard/components/projectActionButton.tsx @@ -319,7 +319,9 @@ function ProjectActionButton(props: ProjectActionButtonProps) { setProjectData(oldProjectData => ({ ...oldProjectData, isRunning: true })) setState(oldState => { if (oldState === backendModule.ProjectState.openInProgress) { - doRefresh() + setTimeout(() => { + doRefresh() + }, 0) return backendModule.ProjectState.opened } else { return oldState diff --git a/app/ide-desktop/lib/dashboard/src/authentication/src/providers/backend.tsx b/app/ide-desktop/lib/dashboard/src/authentication/src/providers/backend.tsx index a2ac1de22ca..05044678ca5 100644 --- a/app/ide-desktop/lib/dashboard/src/authentication/src/providers/backend.tsx +++ b/app/ide-desktop/lib/dashboard/src/authentication/src/providers/backend.tsx @@ -50,7 +50,11 @@ export function BackendProvider(props: BackendProviderProps) { const { children } = props const [backend, setBackendWithoutSavingType] = react.useState< localBackend.LocalBackend | remoteBackend.RemoteBackend - >(() => new localBackend.LocalBackend()) + // This default value is UNSAFE, but must neither be `LocalBackend`, which may not be + // available, not `RemoteBackend`, which does not work when not yet logged in. + // Care must be taken to initialize the backend before its first usage. + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + >(null!) const setBackend = react.useCallback((newBackend: AnyBackendAPI) => { setBackendWithoutSavingType(newBackend) localStorage.setItem(BACKEND_TYPE_KEY, newBackend.type)