diff --git a/src/public/app/services/utils.js b/src/public/app/services/utils.js index e8c92351e..0544c8622 100644 --- a/src/public/app/services/utils.js +++ b/src/public/app/services/utils.js @@ -527,6 +527,58 @@ function downloadSvg(nameWithoutExtension, svgContent) { document.body.removeChild(element); } +/** + * Compares two semantic version strings. + * Returns: + * 1 if v1 is greater than v2 + * 0 if v1 is equal to v2 + * -1 if v1 is less than v2 + * + * @param {string} v1 First version string + * @param {string} v2 Second version string + * @returns {number} + */ +function compareVersions(v1, v2) { + + // Remove 'v' prefix and everything after dash if present + v1 = v1.replace(/^v/, '').split('-')[0]; + v2 = v2.replace(/^v/, '').split('-')[0]; + + const v1parts = v1.split('.').map(Number); + const v2parts = v2.split('.').map(Number); + + // Pad shorter version with zeros + while (v1parts.length < 3) v1parts.push(0); + while (v2parts.length < 3) v2parts.push(0); + + // Compare major version + if (v1parts[0] !== v2parts[0]) { + return v1parts[0] > v2parts[0] ? 1 : -1; + } + + // Compare minor version + if (v1parts[1] !== v2parts[1]) { + return v1parts[1] > v2parts[1] ? 1 : -1; + } + + // Compare patch version + if (v1parts[2] !== v2parts[2]) { + return v1parts[2] > v2parts[2] ? 1 : -1; + } + + return 0; +} + +/** + * Compares two semantic version strings and returns `true` if the latest version is greater than the current version. + * @param {string} latestVersion + * @param {string} currentVersion + * @returns {boolean} + */ +function isUpdateAvailable(latestVersion, currentVersion) { + return compareVersions(latestVersion, currentVersion) > 0; +} + export default { reloadFrontendApp, parseDate, @@ -567,5 +619,7 @@ export default { areObjectsEqual, copyHtmlToClipboard, createImageSrcUrl, - downloadSvg + downloadSvg, + compareVersions, + isUpdateAvailable }; diff --git a/src/public/app/widgets/buttons/global_menu.js b/src/public/app/widgets/buttons/global_menu.js index d4e65b989..d760ecd5c 100644 --- a/src/public/app/widgets/buttons/global_menu.js +++ b/src/public/app/widgets/buttons/global_menu.js @@ -333,7 +333,8 @@ export default class GlobalMenuWidget extends BasicWidget { const latestVersion = await this.fetchLatestVersion(); this.updateAvailableWidget.updateVersionStatus(latestVersion); - this.$updateToLatestVersionButton.toggle(latestVersion > glob.triliumVersion); + // Show "click to download" button in options menu if there's a new version available + this.$updateToLatestVersionButton.toggle(utils.isUpdateAvailable(latestVersion, glob.triliumVersion)); this.$updateToLatestVersionButton.find(".version-text").text(`Version ${latestVersion} is available, click to download.`); } diff --git a/src/public/app/widgets/buttons/update_available.js b/src/public/app/widgets/buttons/update_available.js index 50351cf0e..39db4cfd2 100644 --- a/src/public/app/widgets/buttons/update_available.js +++ b/src/public/app/widgets/buttons/update_available.js @@ -1,5 +1,6 @@ import { t } from "../../services/i18n.js"; import BasicWidget from "../basic_widget.js"; +import utils from "../../services/utils.js"; const TPL = `