From 990ba28831c331da97c57a3c804d9c2ad08bbbc2 Mon Sep 17 00:00:00 2001 From: Konstantinos Spartalis Date: Mon, 10 Nov 2025 19:43:38 +0200 Subject: [PATCH 01/11] Update SiteFooter.tsx --- frontend/src/components/SiteFooter.tsx | 175 +++++++++++++++++-------- 1 file changed, 117 insertions(+), 58 deletions(-) diff --git a/frontend/src/components/SiteFooter.tsx b/frontend/src/components/SiteFooter.tsx index a1778395..3f5a3dde 100644 --- a/frontend/src/components/SiteFooter.tsx +++ b/frontend/src/components/SiteFooter.tsx @@ -1,64 +1,123 @@ +import { useEffect, useState } from "react"; import { useHealth } from "src/hooks"; import { T } from "src/locale"; export function SiteFooter() { - const health = useHealth(); + const health = useHealth(); + const [latestVersion, setLatestVersion] = useState(null); + const [isNewVersionAvailable, setIsNewVersionAvailable] = useState(false); - const getVersion = () => { - if (!health.data) { - return ""; - } - const v = health.data.version; - return `v${v.major}.${v.minor}.${v.revision}`; - }; + const getVersion = () => { + if (!health.data) { + return ""; + } + const v = health.data.version; + return `v${v.major}.${v.minor}.${v.revision}`; + }; - return ( - - ); -} + const compareVersions = (current: string, latest: string): boolean => { + const cleanCurrent = current.replace(/^v/, ""); + const cleanLatest = latest.replace(/^v/, ""); + + const currentParts = cleanCurrent.split(".").map(Number); + const latestParts = cleanLatest.split(".").map(Number); + + for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { + const curr = currentParts[i] || 0; + const lat = latestParts[i] || 0; + + if (lat > curr) return true; + if (lat < curr) return false; + } + return false; + }; + + useEffect(() => { + const checkForUpdates = async () => { + try { + const response = await fetch( + "https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest" + ); + if (response.ok) { + const data = await response.json(); + const latest = data.tag_name; + setLatestVersion(latest); + + const currentVersion = "2.12.1"; + if (currentVersion && compareVersions(currentVersion, latest)) { + setIsNewVersionAvailable(true); + } + } + } catch (error) { + console.debug("Could not check for updates:", error); + } + }; + + if (health.data) { + checkForUpdates(); + } + }, [health.data]); + + return ( + + ); +} \ No newline at end of file From f1d7203212eee0f255296cc5362a6d7bb2892838 Mon Sep 17 00:00:00 2001 From: Konstantinos Spartalis Date: Mon, 10 Nov 2025 19:57:55 +0200 Subject: [PATCH 02/11] v2 --- frontend/src/components/SiteFooter.tsx | 34 +++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/frontend/src/components/SiteFooter.tsx b/frontend/src/components/SiteFooter.tsx index 3f5a3dde..a472efd2 100644 --- a/frontend/src/components/SiteFooter.tsx +++ b/frontend/src/components/SiteFooter.tsx @@ -2,6 +2,23 @@ import { useEffect, useState } from "react"; import { useHealth } from "src/hooks"; import { T } from "src/locale"; +const compareVersions = (current: string, latest: string): boolean => { + const cleanCurrent = current.replace(/^v/, ""); + const cleanLatest = latest.replace(/^v/, ""); + + const currentParts = cleanCurrent.split(".").map(Number); + const latestParts = cleanLatest.split(".").map(Number); + + for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { + const curr = currentParts[i] || 0; + const lat = latestParts[i] || 0; + + if (lat > curr) return true; + if (lat < curr) return false; + } + return false; +}; + export function SiteFooter() { const health = useHealth(); const [latestVersion, setLatestVersion] = useState(null); @@ -15,23 +32,6 @@ export function SiteFooter() { return `v${v.major}.${v.minor}.${v.revision}`; }; - const compareVersions = (current: string, latest: string): boolean => { - const cleanCurrent = current.replace(/^v/, ""); - const cleanLatest = latest.replace(/^v/, ""); - - const currentParts = cleanCurrent.split(".").map(Number); - const latestParts = cleanLatest.split(".").map(Number); - - for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { - const curr = currentParts[i] || 0; - const lat = latestParts[i] || 0; - - if (lat > curr) return true; - if (lat < curr) return false; - } - return false; - }; - useEffect(() => { const checkForUpdates = async () => { try { From b434bba12f3e764fb14815e8085e276baac83579 Mon Sep 17 00:00:00 2001 From: Konstantinos Spartalis Date: Mon, 10 Nov 2025 20:37:25 +0200 Subject: [PATCH 03/11] remove hardcoded version number --- frontend/src/components/SiteFooter.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/SiteFooter.tsx b/frontend/src/components/SiteFooter.tsx index a472efd2..889d4b9b 100644 --- a/frontend/src/components/SiteFooter.tsx +++ b/frontend/src/components/SiteFooter.tsx @@ -43,7 +43,7 @@ export function SiteFooter() { const latest = data.tag_name; setLatestVersion(latest); - const currentVersion = "2.12.1"; + const currentVersion = getVersion(); if (currentVersion && compareVersions(currentVersion, latest)) { setIsNewVersionAvailable(true); } From b6dbb68ef35300251f6f7b8fddee3518d4178dd3 Mon Sep 17 00:00:00 2001 From: Konstantinos Spartalis Date: Mon, 10 Nov 2025 20:42:52 +0200 Subject: [PATCH 04/11] Update SiteFooter.tsx --- frontend/src/components/SiteFooter.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/SiteFooter.tsx b/frontend/src/components/SiteFooter.tsx index 889d4b9b..9c94afae 100644 --- a/frontend/src/components/SiteFooter.tsx +++ b/frontend/src/components/SiteFooter.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { useHealth } from "src/hooks"; import { T } from "src/locale"; @@ -24,13 +24,13 @@ export function SiteFooter() { const [latestVersion, setLatestVersion] = useState(null); const [isNewVersionAvailable, setIsNewVersionAvailable] = useState(false); - const getVersion = () => { + const getVersion = useCallback(() => { if (!health.data) { return ""; } const v = health.data.version; return `v${v.major}.${v.minor}.${v.revision}`; - }; + }, [health.data]); useEffect(() => { const checkForUpdates = async () => { @@ -56,7 +56,7 @@ export function SiteFooter() { if (health.data) { checkForUpdates(); } - }, [health.data]); + }, [health.data, getVersion]); return (
From ae5faa75fac70a96f8e57374655081bec1a9825b Mon Sep 17 00:00:00 2001 From: Konstantinos Spartalis Date: Tue, 11 Nov 2025 10:35:00 +0200 Subject: [PATCH 05/11] backend test --- backend/routes/main.js | 36 ++++++------ backend/routes/version.js | 77 ++++++++++++++++++++++++++ frontend/src/components/SiteFooter.tsx | 32 ++--------- 3 files changed, 100 insertions(+), 45 deletions(-) create mode 100644 backend/routes/version.js diff --git a/backend/routes/main.js b/backend/routes/main.js index 7bc4323d..9b367df3 100644 --- a/backend/routes/main.js +++ b/backend/routes/main.js @@ -14,11 +14,12 @@ import schemaRoutes from "./schema.js"; import settingsRoutes from "./settings.js"; import tokensRoutes from "./tokens.js"; import usersRoutes from "./users.js"; +import versionRoutes from "./version.js"; const router = express.Router({ - caseSensitive: true, - strict: true, - mergeParams: true, + caseSensitive: true, + strict: true, + mergeParams: true, }); /** @@ -26,18 +27,18 @@ const router = express.Router({ * GET /api */ router.get("/", async (_, res /*, next*/) => { - const version = pjson.version.split("-").shift().split("."); - const setup = await isSetup(); + const version = pjson.version.split("-").shift().split("."); + const setup = await isSetup(); - res.status(200).send({ - status: "OK", - setup, - version: { - major: Number.parseInt(version.shift(), 10), - minor: Number.parseInt(version.shift(), 10), - revision: Number.parseInt(version.shift(), 10), - }, - }); + res.status(200).send({ + status: "OK", + setup, + version: { + major: Number.parseInt(version.shift(), 10), + minor: Number.parseInt(version.shift(), 10), + revision: Number.parseInt(version.shift(), 10), + }, + }); }); router.use("/schema", schemaRoutes); @@ -46,6 +47,7 @@ router.use("/users", usersRoutes); router.use("/audit-log", auditLogRoutes); router.use("/reports", reportsRoutes); router.use("/settings", settingsRoutes); +router.use("/version", versionRoutes); router.use("/nginx/proxy-hosts", proxyHostsRoutes); router.use("/nginx/redirection-hosts", redirectionHostsRoutes); router.use("/nginx/dead-hosts", deadHostsRoutes); @@ -59,8 +61,8 @@ router.use("/nginx/certificates", certificatesHostsRoutes); * ALL /api/* */ router.all(/(.+)/, (req, _, next) => { - req.params.page = req.params["0"]; - next(new errs.ItemNotFoundError(req.params.page)); + req.params.page = req.params["0"]; + next(new errs.ItemNotFoundError(req.params.page)); }); -export default router; +export default router; \ No newline at end of file diff --git a/backend/routes/version.js b/backend/routes/version.js new file mode 100644 index 00000000..cd46f12a --- /dev/null +++ b/backend/routes/version.js @@ -0,0 +1,77 @@ +import express from "express"; +import { debug, express as logger } from "../logger.js"; +import pjson from "../package.json" with { type: "json" }; + +const router = express.Router({ + caseSensitive: true, + strict: true, + mergeParams: true, +}); + +/** + * /api/version/check + */ +router + .route("/check") + .options((_, res) => { + res.sendStatus(204); + }) + + /** + * GET /api/version/check + * + * Check for available updates + */ + .get(async (req, res, next) => { + try { + const response = await fetch( + "https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest" + ); + + if (!response.ok) { + throw new Error(`GitHub API returned ${response.status}`); + } + + const data = await response.json(); + const latestVersion = data.tag_name; + + const version = pjson.version.split("-").shift().split("."); + const currentVersion = `v${version[0]}.${version[1]}.${version[2]}`; + + res.status(200).send({ + current: currentVersion, + latest: latestVersion, + updateAvailable: compareVersions(currentVersion, latestVersion), + }); + } catch (error) { + debug(logger, `${req.method.toUpperCase()} ${req.path}: ${error}`); + res.status(200).send({ + current: null, + latest: null, + updateAvailable: false, + }); + } + }); + +/** + * Compare two version strings + * + */ +function compareVersions(current, latest) { + const cleanCurrent = current.replace(/^v/, ""); + const cleanLatest = latest.replace(/^v/, ""); + + const currentParts = cleanCurrent.split(".").map(Number); + const latestParts = cleanLatest.split(".").map(Number); + + for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { + const curr = currentParts[i] || 0; + const lat = latestParts[i] || 0; + + if (lat > curr) return true; + if (lat < curr) return false; + } + return false; +} + +export default router; \ No newline at end of file diff --git a/frontend/src/components/SiteFooter.tsx b/frontend/src/components/SiteFooter.tsx index 9c94afae..255bb700 100644 --- a/frontend/src/components/SiteFooter.tsx +++ b/frontend/src/components/SiteFooter.tsx @@ -2,23 +2,6 @@ import { useCallback, useEffect, useState } from "react"; import { useHealth } from "src/hooks"; import { T } from "src/locale"; -const compareVersions = (current: string, latest: string): boolean => { - const cleanCurrent = current.replace(/^v/, ""); - const cleanLatest = latest.replace(/^v/, ""); - - const currentParts = cleanCurrent.split(".").map(Number); - const latestParts = cleanLatest.split(".").map(Number); - - for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { - const curr = currentParts[i] || 0; - const lat = latestParts[i] || 0; - - if (lat > curr) return true; - if (lat < curr) return false; - } - return false; -}; - export function SiteFooter() { const health = useHealth(); const [latestVersion, setLatestVersion] = useState(null); @@ -35,18 +18,11 @@ export function SiteFooter() { useEffect(() => { const checkForUpdates = async () => { try { - const response = await fetch( - "https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest" - ); + const response = await fetch("/api/version/check"); if (response.ok) { const data = await response.json(); - const latest = data.tag_name; - setLatestVersion(latest); - - const currentVersion = getVersion(); - if (currentVersion && compareVersions(currentVersion, latest)) { - setIsNewVersionAvailable(true); - } + setLatestVersion(data.latest); + setIsNewVersionAvailable(data.updateAvailable); } } catch (error) { console.debug("Could not check for updates:", error); @@ -56,7 +32,7 @@ export function SiteFooter() { if (health.data) { checkForUpdates(); } - }, [health.data, getVersion]); + }, [health.data]); return (
From dc03ad8239ea8c4c5463457086e06d65951016a5 Mon Sep 17 00:00:00 2001 From: Konstantinos Spartalis Date: Tue, 11 Nov 2025 17:42:46 +0200 Subject: [PATCH 06/11] minimal changes --- backend/routes/main.js | 2 +- backend/routes/version.js | 2 +- frontend/src/components/SiteFooter.tsx | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/routes/main.js b/backend/routes/main.js index 9b367df3..2108144a 100644 --- a/backend/routes/main.js +++ b/backend/routes/main.js @@ -65,4 +65,4 @@ router.all(/(.+)/, (req, _, next) => { next(new errs.ItemNotFoundError(req.params.page)); }); -export default router; \ No newline at end of file +export default router; diff --git a/backend/routes/version.js b/backend/routes/version.js index cd46f12a..d05581c2 100644 --- a/backend/routes/version.js +++ b/backend/routes/version.js @@ -74,4 +74,4 @@ function compareVersions(current, latest) { return false; } -export default router; \ No newline at end of file +export default router; diff --git a/frontend/src/components/SiteFooter.tsx b/frontend/src/components/SiteFooter.tsx index 255bb700..e1c4f3ab 100644 --- a/frontend/src/components/SiteFooter.tsx +++ b/frontend/src/components/SiteFooter.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { useHealth } from "src/hooks"; import { T } from "src/locale"; @@ -7,7 +7,7 @@ export function SiteFooter() { const [latestVersion, setLatestVersion] = useState(null); const [isNewVersionAvailable, setIsNewVersionAvailable] = useState(false); - const getVersion = useCallback(() => { + const getVersion = () => { if (!health.data) { return ""; } @@ -96,4 +96,4 @@ export function SiteFooter() {
); -} \ No newline at end of file +} From 87eef10ff8cda4cf34b0097716d3d6516ec4e5bd Mon Sep 17 00:00:00 2001 From: Konstantinos Spartalis Date: Tue, 11 Nov 2025 18:05:17 +0200 Subject: [PATCH 07/11] remove useCallback logic --- frontend/src/components/SiteFooter.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/SiteFooter.tsx b/frontend/src/components/SiteFooter.tsx index e1c4f3ab..e529a19d 100644 --- a/frontend/src/components/SiteFooter.tsx +++ b/frontend/src/components/SiteFooter.tsx @@ -13,7 +13,7 @@ export function SiteFooter() { } const v = health.data.version; return `v${v.major}.${v.minor}.${v.revision}`; - }, [health.data]); + }; useEffect(() => { const checkForUpdates = async () => { @@ -96,4 +96,4 @@ export function SiteFooter() {
); -} +} \ No newline at end of file From 2d6252d75ded818a06123a4f182fc2c23b910bbf Mon Sep 17 00:00:00 2001 From: Konstantinos Spartalis Date: Wed, 12 Nov 2025 15:45:59 +0200 Subject: [PATCH 08/11] https.get --- backend/routes/version.js | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/backend/routes/version.js b/backend/routes/version.js index d05581c2..115d74f4 100644 --- a/backend/routes/version.js +++ b/backend/routes/version.js @@ -1,6 +1,8 @@ import express from "express"; import { debug, express as logger } from "../logger.js"; import pjson from "../package.json" with { type: "json" }; +import https from "node:https"; +import { ProxyAgent } from "proxy-agent"; const router = express.Router({ caseSensitive: true, @@ -24,15 +26,37 @@ router */ .get(async (req, res, next) => { try { - const response = await fetch( - "https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest" - ); + const agent = new ProxyAgent(); + const url = "https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest"; - if (!response.ok) { - throw new Error(`GitHub API returned ${response.status}`); - } + const data = await new Promise((resolve, reject) => { + https + .get(url, { agent }, (response) => { + if (response.statusCode !== 200) { + reject(new Error(`GitHub API returned ${response.statusCode}`)); + return; + } + + response.setEncoding("utf8"); + let raw_data = ""; + + response.on("data", (chunk) => { + raw_data += chunk; + }); + + response.on("end", () => { + try { + resolve(JSON.parse(raw_data)); + } catch (err) { + reject(err); + } + }); + }) + .on("error", (err) => { + reject(err); + }); + }); - const data = await response.json(); const latestVersion = data.tag_name; const version = pjson.version.split("-").shift().split("."); From 15394c653277e6122e3d048765a5ec2a2018fd11 Mon Sep 17 00:00:00 2001 From: Konstantinos Spartalis Date: Wed, 12 Nov 2025 15:50:11 +0200 Subject: [PATCH 09/11] trigger Jenkins that failed due to internet connection problems --- backend/routes/version.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/routes/version.js b/backend/routes/version.js index 115d74f4..de614f0c 100644 --- a/backend/routes/version.js +++ b/backend/routes/version.js @@ -12,7 +12,7 @@ const router = express.Router({ /** * /api/version/check - */ + */ router .route("/check") .options((_, res) => { From 963125f963c2ccc5d297405a6106eac6ba5283e7 Mon Sep 17 00:00:00 2001 From: 7heMech <83923848+7heMech@users.noreply.github.com> Date: Thu, 13 Nov 2025 00:45:07 +0200 Subject: [PATCH 10/11] Space scandal retified (hopefully) --- backend/routes/main.js | 32 ++--- backend/routes/version.js | 136 +++++++++---------- frontend/src/components/SiteFooter.tsx | 180 ++++++++++++------------- 3 files changed, 174 insertions(+), 174 deletions(-) diff --git a/backend/routes/main.js b/backend/routes/main.js index 2108144a..94682cfb 100644 --- a/backend/routes/main.js +++ b/backend/routes/main.js @@ -17,9 +17,9 @@ import usersRoutes from "./users.js"; import versionRoutes from "./version.js"; const router = express.Router({ - caseSensitive: true, - strict: true, - mergeParams: true, + caseSensitive: true, + strict: true, + mergeParams: true, }); /** @@ -27,18 +27,18 @@ const router = express.Router({ * GET /api */ router.get("/", async (_, res /*, next*/) => { - const version = pjson.version.split("-").shift().split("."); - const setup = await isSetup(); + const version = pjson.version.split("-").shift().split("."); + const setup = await isSetup(); - res.status(200).send({ - status: "OK", - setup, - version: { - major: Number.parseInt(version.shift(), 10), - minor: Number.parseInt(version.shift(), 10), - revision: Number.parseInt(version.shift(), 10), - }, - }); + res.status(200).send({ + status: "OK", + setup, + version: { + major: Number.parseInt(version.shift(), 10), + minor: Number.parseInt(version.shift(), 10), + revision: Number.parseInt(version.shift(), 10), + }, + }); }); router.use("/schema", schemaRoutes); @@ -61,8 +61,8 @@ router.use("/nginx/certificates", certificatesHostsRoutes); * ALL /api/* */ router.all(/(.+)/, (req, _, next) => { - req.params.page = req.params["0"]; - next(new errs.ItemNotFoundError(req.params.page)); + req.params.page = req.params["0"]; + next(new errs.ItemNotFoundError(req.params.page)); }); export default router; diff --git a/backend/routes/version.js b/backend/routes/version.js index de614f0c..328888af 100644 --- a/backend/routes/version.js +++ b/backend/routes/version.js @@ -5,97 +5,97 @@ import https from "node:https"; import { ProxyAgent } from "proxy-agent"; const router = express.Router({ - caseSensitive: true, - strict: true, - mergeParams: true, + caseSensitive: true, + strict: true, + mergeParams: true, }); /** * /api/version/check */ router - .route("/check") - .options((_, res) => { - res.sendStatus(204); - }) + .route("/check") + .options((_, res) => { + res.sendStatus(204); + }) - /** - * GET /api/version/check - * - * Check for available updates - */ - .get(async (req, res, next) => { - try { - const agent = new ProxyAgent(); - const url = "https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest"; + /** + * GET /api/version/check + * + * Check for available updates + */ + .get(async (req, res, next) => { + try { + const agent = new ProxyAgent(); + const url = "https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest"; - const data = await new Promise((resolve, reject) => { - https - .get(url, { agent }, (response) => { - if (response.statusCode !== 200) { - reject(new Error(`GitHub API returned ${response.statusCode}`)); - return; - } + const data = await new Promise((resolve, reject) => { + https + .get(url, { agent }, (response) => { + if (response.statusCode !== 200) { + reject(new Error(`GitHub API returned ${response.statusCode}`)); + return; + } - response.setEncoding("utf8"); - let raw_data = ""; + response.setEncoding("utf8"); + let raw_data = ""; - response.on("data", (chunk) => { - raw_data += chunk; - }); + response.on("data", (chunk) => { + raw_data += chunk; + }); - response.on("end", () => { - try { - resolve(JSON.parse(raw_data)); - } catch (err) { - reject(err); - } - }); - }) - .on("error", (err) => { - reject(err); - }); - }); + response.on("end", () => { + try { + resolve(JSON.parse(raw_data)); + } catch (err) { + reject(err); + } + }); + }) + .on("error", (err) => { + reject(err); + }); + }); - const latestVersion = data.tag_name; + const latestVersion = data.tag_name; - const version = pjson.version.split("-").shift().split("."); - const currentVersion = `v${version[0]}.${version[1]}.${version[2]}`; + const version = pjson.version.split("-").shift().split("."); + const currentVersion = `v${version[0]}.${version[1]}.${version[2]}`; - res.status(200).send({ - current: currentVersion, - latest: latestVersion, - updateAvailable: compareVersions(currentVersion, latestVersion), - }); - } catch (error) { - debug(logger, `${req.method.toUpperCase()} ${req.path}: ${error}`); - res.status(200).send({ - current: null, - latest: null, - updateAvailable: false, - }); - } - }); + res.status(200).send({ + current: currentVersion, + latest: latestVersion, + updateAvailable: compareVersions(currentVersion, latestVersion), + }); + } catch (error) { + debug(logger, `${req.method.toUpperCase()} ${req.path}: ${error}`); + res.status(200).send({ + current: null, + latest: null, + updateAvailable: false, + }); + } + }); /** * Compare two version strings * */ function compareVersions(current, latest) { - const cleanCurrent = current.replace(/^v/, ""); - const cleanLatest = latest.replace(/^v/, ""); + const cleanCurrent = current.replace(/^v/, ""); + const cleanLatest = latest.replace(/^v/, ""); - const currentParts = cleanCurrent.split(".").map(Number); - const latestParts = cleanLatest.split(".").map(Number); + const currentParts = cleanCurrent.split(".").map(Number); + const latestParts = cleanLatest.split(".").map(Number); - for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { - const curr = currentParts[i] || 0; - const lat = latestParts[i] || 0; + for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { + const curr = currentParts[i] || 0; + const lat = latestParts[i] || 0; - if (lat > curr) return true; - if (lat < curr) return false; - } - return false; + if (lat > curr) return true; + if (lat < curr) return false; + } + return false; } export default router; diff --git a/frontend/src/components/SiteFooter.tsx b/frontend/src/components/SiteFooter.tsx index e529a19d..2135d2c6 100644 --- a/frontend/src/components/SiteFooter.tsx +++ b/frontend/src/components/SiteFooter.tsx @@ -3,97 +3,97 @@ import { useHealth } from "src/hooks"; import { T } from "src/locale"; export function SiteFooter() { - const health = useHealth(); - const [latestVersion, setLatestVersion] = useState(null); - const [isNewVersionAvailable, setIsNewVersionAvailable] = useState(false); + const health = useHealth(); + const [latestVersion, setLatestVersion] = useState(null); + const [isNewVersionAvailable, setIsNewVersionAvailable] = useState(false); - const getVersion = () => { - if (!health.data) { - return ""; - } - const v = health.data.version; - return `v${v.major}.${v.minor}.${v.revision}`; - }; + const getVersion = () => { + if (!health.data) { + return ""; + } + const v = health.data.version; + return `v${v.major}.${v.minor}.${v.revision}`; + }; - useEffect(() => { - const checkForUpdates = async () => { - try { - const response = await fetch("/api/version/check"); - if (response.ok) { - const data = await response.json(); - setLatestVersion(data.latest); - setIsNewVersionAvailable(data.updateAvailable); - } - } catch (error) { - console.debug("Could not check for updates:", error); - } - }; + useEffect(() => { + const checkForUpdates = async () => { + try { + const response = await fetch("/api/version/check"); + if (response.ok) { + const data = await response.json(); + setLatestVersion(data.latest); + setIsNewVersionAvailable(data.updateAvailable); + } + } catch (error) { + console.debug("Could not check for updates:", error); + } + }; - if (health.data) { - checkForUpdates(); - } - }, [health.data]); + if (health.data) { + checkForUpdates(); + } + }, [health.data]); - return ( - - ); -} \ No newline at end of file + return ( + + ); +} From b4fd242eb76816c5d4ac0745499be02ae09b8858 Mon Sep 17 00:00:00 2001 From: Konstantinos Spartalis Date: Thu, 13 Nov 2025 00:48:49 +0200 Subject: [PATCH 11/11] remove 1 --- backend/routes/version.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/routes/version.js b/backend/routes/version.js index 328888af..ac1ac4d7 100644 --- a/backend/routes/version.js +++ b/backend/routes/version.js @@ -12,7 +12,7 @@ const router = express.Router({ /** * /api/version/check - */ + */ router .route("/check") .options((_, res) => {