diff --git a/src/components/Dashboard/context/AppUpdateContext.jsx b/src/components/Dashboard/context/AppUpdateContext.jsx index 9b4b786..91bf26f 100644 --- a/src/components/Dashboard/context/AppUpdateContext.jsx +++ b/src/components/Dashboard/context/AppUpdateContext.jsx @@ -21,6 +21,42 @@ const { Text } = Typography const UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1000 const DEFAULT_UPDATE_BRANCH = 'main' const CURRENT_BUILD_NUMBER = import.meta.env.VITE_BUILD_NUMBER +const APP_UPDATE_DISMISSED_KEY = 'appUpdateDismissed' + +const getDismissedUpdate = () => { + try { + const stored = sessionStorage.getItem(APP_UPDATE_DISMISSED_KEY) + return stored ? JSON.parse(stored) : null + } catch { + return null + } +} + +const isUpdateDismissed = (update) => { + if (!update) return false + + const dismissed = getDismissedUpdate() + if (!dismissed) return false + + return ( + dismissed.version === update.version && + dismissed.buildNumber === update.buildNumber && + dismissed.branch === update.branch + ) +} + +const saveDismissedUpdate = (update) => { + if (!update) return + + sessionStorage.setItem( + APP_UPDATE_DISMISSED_KEY, + JSON.stringify({ + version: update.version, + buildNumber: update.buildNumber, + branch: update.branch + }) + ) +} const AppUpdateContext = createContext() @@ -77,6 +113,7 @@ export const AppUpdateProvider = ({ children }) => { const [checking, setChecking] = useState(false) const [noUpdateOpen, setNoUpdateOpen] = useState(false) const [availableUpdate, setAvailableUpdate] = useState(null) + const [updatePromptOpen, setUpdatePromptOpen] = useState(false) const [installingUpdate, setInstallingUpdate] = useState(null) const [updateProgress, setUpdateProgress] = useState(null) const runningCheckRef = useRef(null) @@ -136,14 +173,20 @@ export const AppUpdateProvider = ({ children }) => { } }, []) - const showUpdateIfAvailable = useCallback(async () => { - const update = await checkForAvailableUpdate() - if (update) { - setNoUpdateOpen(false) - setAvailableUpdate(update) - } - return update - }, [checkForAvailableUpdate]) + const showUpdateIfAvailable = useCallback( + async ({ forcePrompt = false } = {}) => { + const update = await checkForAvailableUpdate() + if (update) { + setNoUpdateOpen(false) + setAvailableUpdate(update) + if (forcePrompt || !isUpdateDismissed(update)) { + setUpdatePromptOpen(true) + } + } + return update + }, + [checkForAvailableUpdate] + ) const checkForUpdates = useCallback(async () => { if (!isElectron) return null @@ -151,7 +194,7 @@ export const AppUpdateProvider = ({ children }) => { setChecking(true) try { - const update = await showUpdateIfAvailable() + const update = await showUpdateIfAvailable({ forcePrompt: true }) if (!update) { setNoUpdateOpen(true) } @@ -183,15 +226,22 @@ export const AppUpdateProvider = ({ children }) => { }) }, [isElectron, onAppUpdateProgress]) + const dismissUpdatePrompt = () => { + if (availableUpdate) { + saveDismissedUpdate(availableUpdate) + } + setUpdatePromptOpen(false) + } + const closeUpdateModal = () => { - setAvailableUpdate(null) + setUpdatePromptOpen(false) setInstallingUpdate(null) setUpdateProgress(null) } const handleUpdate = async (update) => { setNoUpdateOpen(false) - setAvailableUpdate(null) + setUpdatePromptOpen(false) setInstallingUpdate(update) setModelWidth(550) setUpdateProgress({ @@ -215,7 +265,7 @@ export const AppUpdateProvider = ({ children }) => { } } - const updateModalOpen = Boolean(availableUpdate || installingUpdate) + const updateModalOpen = Boolean(updatePromptOpen || installingUpdate) const updateModalBusy = Boolean(installingUpdate) && updateProgress?.phase !== 'error' @@ -268,7 +318,13 @@ export const AppUpdateProvider = ({ children }) => { centered closable={!updateModalBusy} maskClosable={!updateModalBusy} - onCancel={updateModalBusy ? undefined : closeUpdateModal} + onCancel={ + updateModalBusy + ? undefined + : installingUpdate + ? closeUpdateModal + : dismissUpdatePrompt + } > {installingUpdate ? ( { ) : ( )}