From 52ded04a4c8c1e8ce554ec93d497d52e500462bb Mon Sep 17 00:00:00 2001 From: Harshith Mohan <26010946+harshithmohan@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:59:53 +0530 Subject: [PATCH] Fix: don't logout on refresh after WebUI update (#1023) * Fix server version in sentry * Fix: don't logout on refresh after WebUI update --- src/core/localStorage.ts | 53 ++++++++++++++++-------- src/core/react-query/init/queries.ts | 1 + src/core/store.ts | 7 ++-- src/core/types/api.ts | 1 + src/pages/SentryErrorBoundaryWrapper.tsx | 7 +--- 5 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/core/localStorage.ts b/src/core/localStorage.ts index dbc85a05e..e296fba39 100644 --- a/src/core/localStorage.ts +++ b/src/core/localStorage.ts @@ -1,32 +1,42 @@ /* global globalThis */ - -import { get } from 'lodash'; - import type { RootState } from './store'; import type { ApiSessionState } from '@/core/types/api'; const { VITE_APPVERSION } = import.meta.env; -const checkVersion = (version: string) => version === VITE_APPVERSION; - -const isSerializedState = (data: unknown): data is RootState => checkVersion(get(data, 'apiSession.version', '')); -const isApiSession = (data: unknown): data is ApiSessionState => checkVersion(get(data, 'version', '')); - export const loadState = (): RootState => { try { const serializedState = JSON.parse(globalThis.sessionStorage.getItem('state') ?? '{}') as RootState; - const apiSessionString = globalThis.localStorage.getItem('apiSession'); - if (apiSessionString === null) { - return isSerializedState(serializedState) ? serializedState : {} as RootState; + + // If the version is the same, we can return the state as is from session storage. + if (serializedState.apiSession?.version === VITE_APPVERSION) { + return serializedState; } - const apiSession: unknown = JSON.parse(apiSessionString); - if (!isApiSession(apiSession)) { - globalThis.localStorage.removeItem('apiSession'); - return {} as RootState; + + // If the version is different, we update the apiSession state to the current version and reset other slices. + if (serializedState.apiSession?.version) { + return { + apiSession: { + ...serializedState.apiSession, + version: VITE_APPVERSION, + }, + } as RootState; } - return { ...serializedState, apiSession }; + + // If the version is missing above, it's a new session. Check local storage for apiSession. + const apiSession = JSON.parse(globalThis.localStorage.getItem('apiSession') ?? '{}') as ApiSessionState; + + // If the apiSession is missing from localStorage, we reset the state. + if (!apiSession.version) return ({} as RootState); + + // Update the apiSession state to the current version and return the state. + return { + apiSession: { + ...apiSession, + version: VITE_APPVERSION, + }, + } as RootState; } catch (err) { - console.error('Error in loading state. Resetting!'); return ({} as RootState); } }; @@ -38,6 +48,13 @@ export const saveState = (state: RootState) => { } globalThis.sessionStorage.setItem('state', JSON.stringify(state)); } catch (err) { // Ignore write errors. - console.error('Error in saving state'); } }; + +export const clearSessionStorage = () => { + globalThis.sessionStorage.clear(); +}; + +export const clearApiSession = () => { + globalThis.localStorage.removeItem('apiSession'); +}; diff --git a/src/core/react-query/init/queries.ts b/src/core/react-query/init/queries.ts index a1f95da18..60a99c64b 100644 --- a/src/core/react-query/init/queries.ts +++ b/src/core/react-query/init/queries.ts @@ -8,6 +8,7 @@ export const useVersionQuery = () => useQuery({ queryKey: ['init', 'version'], queryFn: () => axios.get('Init/Version'), + staleTime: Infinity, }); export const useDefaultUserQuery = () => diff --git a/src/core/store.ts b/src/core/store.ts index 2d851001b..cd02773b6 100644 --- a/src/core/store.ts +++ b/src/core/store.ts @@ -1,10 +1,9 @@ -/* global globalThis */ import { configureStore } from '@reduxjs/toolkit'; import { setupListeners } from '@reduxjs/toolkit/query/react'; import { throttle } from 'lodash'; import Events from './events'; -import { loadState, saveState } from './localStorage'; +import { clearApiSession, clearSessionStorage, loadState, saveState } from './localStorage'; import combinedReducer from './reducers'; import signalrMiddleware from './signalr/signalr'; @@ -12,8 +11,8 @@ import type { UnknownAction } from 'redux'; const rootReducer = (state: ReturnType, action: UnknownAction) => { if (action.type === Events.AUTH_LOGOUT) { // check for action type - globalThis.localStorage.removeItem('apiSession'); - globalThis.sessionStorage.clear(); + clearApiSession(); + clearSessionStorage(); return combinedReducer(undefined, action); } return combinedReducer(state, action); diff --git a/src/core/types/api.ts b/src/core/types/api.ts index 0023b5d16..d9d45b429 100644 --- a/src/core/types/api.ts +++ b/src/core/types/api.ts @@ -2,6 +2,7 @@ export type ApiSessionState = { apikey: string; username: string; rememberUser: boolean; + version: string; }; export type GlobalAlertType = { diff --git a/src/pages/SentryErrorBoundaryWrapper.tsx b/src/pages/SentryErrorBoundaryWrapper.tsx index e88ac8d00..b23332290 100644 --- a/src/pages/SentryErrorBoundaryWrapper.tsx +++ b/src/pages/SentryErrorBoundaryWrapper.tsx @@ -1,7 +1,6 @@ import React, { useEffect } from 'react'; import { Outlet } from 'react-router'; import * as Sentry from '@sentry/react'; -import { get } from 'lodash'; import ErrorBoundary from '@/components/ErrorBoundary'; import { useVersionQuery } from '@/core/react-query/init/queries'; @@ -10,11 +9,7 @@ const SentryErrorBoundaryWrapper = () => { const versionQuery = useVersionQuery(); useEffect(() => { - if (!get(versionQuery.data, 'Server', false)) return; - const versionHash = versionQuery?.data?.Server.ReleaseChannel !== 'Stable' - ? versionQuery?.data?.Server.Commit - : versionQuery.data.Server.Version; - Sentry.setTag('server_version', versionHash); + Sentry.setTag('server_release', versionQuery.data?.Server?.Version ?? 'Unknown'); }, [versionQuery.data]); return (