From 3caae592f191b6aeea3b056d2e139f476c510588 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Sun, 9 Aug 2026 14:06:04 +0100 Subject: [PATCH] Enhance update messaging and version formatting in AppUpdateContext and appupdate.js - Introduced a new function `formatFullAppVersion` to standardize the application version and build number representation. - Updated the `getUpdateInstalledMessage` function to provide detailed feedback on updates, including changes in version, branch, and engine. - Refactored the update handling logic to improve clarity and maintainability, ensuring users receive accurate and informative update notifications. --- .../Dashboard/context/AppUpdateContext.jsx | 27 ++++-- src/desktop/appupdate.js | 86 +++++++++++++++++-- 2 files changed, 99 insertions(+), 14 deletions(-) diff --git a/src/components/Dashboard/context/AppUpdateContext.jsx b/src/components/Dashboard/context/AppUpdateContext.jsx index 8cb3be4..bab0631 100644 --- a/src/components/Dashboard/context/AppUpdateContext.jsx +++ b/src/components/Dashboard/context/AppUpdateContext.jsx @@ -62,6 +62,20 @@ const isUpdateDismissed = (update) => { ) } +const formatFullAppVersion = (version, buildNumber) => { + const normalizedVersion = String(version || '') + .trim() + .replace(/^v/i, '') + + if (!normalizedVersion) return null + + const build = String(buildNumber || '').trim() + const buildSuffix = + !build || build === 'dev' ? 'dev' : build.startsWith('b') ? build : `b${build}` + + return `v${normalizedVersion}-${buildSuffix}` +} + const saveDismissedUpdate = (update) => { if (!update) return @@ -543,13 +557,12 @@ export const AppUpdateProvider = ({ children }) => { ]} > - Farm Control was successfully updated to version{' '} - {completedUpdate?.current?.version || appVersion} - {completedUpdate?.previous?.version && - completedUpdate.previous.version !== completedUpdate?.current?.version - ? ` (previously ${completedUpdate.previous.version})` - : ''} - . + {completedUpdate?.message || + `Farm Control was successfully updated to version ${ + completedUpdate?.current?.version || + formatFullAppVersion(appVersion, CURRENT_BUILD_NUMBER) || + `v${appVersion}` + }.`} { const stateValueChanged = (previous, next) => Boolean(previous) && Boolean(next) && previous !== next +const formatEngineLabel = (engine) => { + const normalized = normalizeEngine(engine) + if (normalized === 'chromium') return 'Chromium' + if (normalized === 'native') return 'Native' + return String(engine || 'Unknown') +} + +export const getUpdateInstalledMessage = ({ changes, current } = {}) => { + if (!current) return 'Farm Control was successfully updated.' + + const versionChanged = Boolean(changes?.version && current.version) + const branchChanged = Boolean(changes?.branch && current.branch) + const engineChanged = Boolean(changes?.engine && current.engine) + + if (!versionChanged && !branchChanged && !engineChanged) { + const version = current.version || getRunningAppVersion() + return version + ? `Farm Control was successfully updated to version ${version}.` + : 'Farm Control was successfully updated.' + } + + const segments = [] + + if (versionChanged) { + segments.push({ type: 'version', text: `version ${current.version}` }) + } + if (branchChanged) { + segments.push({ type: 'branch', text: `the ${current.branch} branch` }) + } + if (engineChanged) { + segments.push({ + type: 'engine', + text: `the ${formatEngineLabel(current.engine)} engine` + }) + } + + if (segments.length === 1) { + const [segment] = segments + if (segment.type === 'engine') { + return `Farm Control was successfully updated to use ${segment.text}.` + } + return `Farm Control was successfully updated to ${segment.text}.` + } + + let message = `Farm Control was successfully updated to ${segments[0].text}` + + for (const segment of segments.slice(1)) { + if (segment.type === 'branch') { + message += ` on ${segment.text}` + } else if (segment.type === 'engine') { + message += ` using ${segment.text}` + } else { + message += ` and ${segment.text}` + } + } + + return `${message}.` +} + let completedUpdateResult = null export const checkForCompletedUpdate = async (mainWindow) => { @@ -280,18 +339,31 @@ export const checkForCompletedUpdate = async (mainWindow) => { await setAppSettings({ ...settings, current }) + const changes = { + version: stateValueChanged(previous.version, current.version), + branch: stateValueChanged(previous.branch, current.branch), + engine: stateValueChanged( + normalizeEngine(previous.engine), + normalizeEngine(current.engine) + ) + } + const updated = Boolean(previous) && - (stateValueChanged(previous.version, current.version) || - stateValueChanged(previous.branch, current.branch) || - stateValueChanged( - normalizeEngine(previous.engine), - normalizeEngine(current.engine) - )) + (changes.version || changes.branch || changes.engine) const duplicates = checkForDuplicateInstallations() - completedUpdateResult = { updated, previous, current, duplicates } + completedUpdateResult = { + updated, + previous, + current, + changes, + message: updated + ? getUpdateInstalledMessage({ changes, current }) + : null, + duplicates + } } catch (error) { console.warn('[app-update] Failed to check for a completed update.', error) completedUpdateResult = {