Add beta version update status

This commit is contained in:
Xenthys
2026-04-24 19:44:36 +02:00
parent fd8554fe8f
commit de277fde86
9 changed files with 111 additions and 16 deletions
+28 -2
View File
@@ -30,6 +30,26 @@ function logToFile(...args) {
console.log(...args);
}
function parseSemver(version) {
const match = String(version || "").match(/(\d+)\.(\d+)(?:\.(\d+))?/);
if (!match) return null;
return [Number(match[1]), Number(match[2]), Number(match[3] || 0)];
}
function compareSemver(a, b) {
const parsedA = parseSemver(a);
const parsedB = parseSemver(b);
if (!parsedA || !parsedB) return null;
for (let i = 0; i < 3; i += 1) {
if (parsedA[i] > parsedB[i]) return 1;
if (parsedA[i] < parsedB[i]) return -1;
}
return 0;
}
function httpFetch(url, options = {}) {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
@@ -548,11 +568,17 @@ ipcMain.handle("check-electron-update", async () => {
};
}
const isUpToDate = localVersion === remoteVersion;
const versionComparison = compareSemver(localVersion, remoteVersion);
const status =
versionComparison === null || versionComparison === 0
? "up_to_date"
: versionComparison > 0
? "beta"
: "requires_update";
const result = {
success: true,
status: isUpToDate ? "up_to_date" : "requires_update",
status,
localVersion: localVersion,
remoteVersion: remoteVersion,
latest_release: {
+34 -2
View File
@@ -119,6 +119,31 @@ class GitHubCache {
const githubCache = new GitHubCache();
function parseSemver(
version: string | undefined,
): [number, number, number] | null {
const match = String(version || "").match(/(\d+)\.(\d+)(?:\.(\d+))?/);
if (!match) return null;
return [Number(match[1]), Number(match[2]), Number(match[3] || 0)];
}
function compareSemver(
a: string | undefined,
b: string | undefined,
): number | null {
const parsedA = parseSemver(a);
const parsedB = parseSemver(b);
if (!parsedA || !parsedB) return null;
for (let i = 0; i < 3; i += 1) {
if (parsedA[i] > parsedB[i]) return 1;
if (parsedA[i] < parsedB[i]) return -1;
}
return 0;
}
const GITHUB_API_BASE = "https://api.github.com";
const REPO_OWNER = "Termix-SSH";
const REPO_NAME = "Termix";
@@ -300,12 +325,19 @@ app.get("/version", authenticateJWT, async (req, res) => {
return res.status(401).send("Remote Version Not Found");
}
const isUpToDate = localVersion === remoteVersion;
const versionComparison = compareSemver(localVersion, remoteVersion);
const status =
versionComparison === null || versionComparison === 0
? "up_to_date"
: versionComparison > 0
? "beta"
: "requires_update";
const response = {
status: isUpToDate ? "up_to_date" : "requires_update",
status,
localVersion: localVersion,
version: remoteVersion,
remoteVersion: remoteVersion,
latest_release: {
tag_name: releaseData.data.tag_name,
name: releaseData.data.name,
+17 -2
View File
@@ -1,13 +1,13 @@
import React from "react";
import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert.tsx";
import { Button } from "@/components/ui/button.tsx";
import { ExternalLink, Download, AlertTriangle } from "lucide-react";
import { ExternalLink, Download, AlertTriangle, Info } from "lucide-react";
import { useTranslation } from "react-i18next";
interface VersionAlertProps {
updateInfo: {
success: boolean;
status?: "up_to_date" | "requires_update";
status?: "up_to_date" | "requires_update" | "beta";
localVersion?: string;
remoteVersion?: string;
latest_release?: {
@@ -53,6 +53,21 @@ export function VersionAlert({ updateInfo, onDownload }: VersionAlertProps) {
);
}
if (updateInfo.status === "beta") {
return (
<Alert>
<Info className="h-4 w-4" />
<AlertTitle>{t("versionCheck.betaVersion")}</AlertTitle>
<AlertDescription>
{t("versionCheck.betaVersionDesc", {
current: updateInfo.localVersion,
latest: updateInfo.remoteVersion,
})}
</AlertDescription>
</Alert>
);
}
if (updateInfo.status === "requires_update") {
return (
<Alert variant="destructive">
+3
View File
@@ -402,6 +402,8 @@
"currentVersion": "You are running version {{version}}",
"updateAvailable": "Update Available",
"newVersionAvailable": "A new version is available! You are running {{current}}, but {{latest}} is available.",
"betaVersion": "Beta Version",
"betaVersionDesc": "You are running {{current}}, which is newer than the latest stable release {{latest}}.",
"releasedOn": "Released on {{date}}",
"downloadUpdate": "Download Update",
"dismiss": "Dismiss",
@@ -2602,6 +2604,7 @@
"version": "Version",
"upToDate": "Up to Date",
"updateAvailable": "Update Available",
"beta": "Beta",
"uptime": "Uptime",
"database": "Database",
"healthy": "Healthy",
+3 -2
View File
@@ -68,7 +68,7 @@ export function Dashboard({
const [uptime, setUptime] = useState<string>("0d 0h 0m");
const [versionStatus, setVersionStatus] = useState<
"up_to_date" | "requires_update"
"up_to_date" | "requires_update" | "beta"
>("up_to_date");
const [versionText, setVersionText] = useState<string>("");
const [dbHealth, setDbHealth] = useState<"healthy" | "error">("healthy");
@@ -173,7 +173,8 @@ export function Dashboard({
setVersionText(`v${versionInfo.localVersion}`);
if (
versionInfo.status === "up_to_date" ||
versionInfo.status === "requires_update"
versionInfo.status === "requires_update" ||
versionInfo.status === "beta"
) {
setVersionStatus(versionInfo.status);
}
@@ -48,8 +48,9 @@ interface RSSResponse {
}
interface VersionResponse {
status: "up_to_date" | "requires_update";
status: "up_to_date" | "requires_update" | "beta";
version: string;
localVersion?: string;
latest_release: {
name: string;
published_at: string;
@@ -136,6 +137,19 @@ export function UpdateLog({ loggedIn }: UpdateLogProps) {
</AlertDescription>
</Alert>
)}
{versionInfo && versionInfo.status === "beta" && (
<Alert className="bg-elevated border-edge text-foreground mb-3">
<AlertTitle className="text-foreground">
{t("versionCheck.betaVersion")}
</AlertTitle>
<AlertDescription className="text-foreground-secondary">
{t("versionCheck.betaVersionDesc", {
current: versionInfo.localVersion,
latest: versionInfo.version,
})}
</AlertDescription>
</Alert>
)}
{loading && (
<div className="flex items-center justify-center h-32">
@@ -14,7 +14,7 @@ import { UpdateLog } from "@/ui/desktop/apps/dashboard/apps/UpdateLog";
interface ServerOverviewCardProps {
loggedIn: boolean;
versionText: string;
versionStatus: "up_to_date" | "requires_update";
versionStatus: "up_to_date" | "requires_update" | "beta";
uptime: string;
dbHealth: "healthy" | "error";
totalServers: number;
@@ -61,11 +61,13 @@ export function ServerOverviewCard({
<Button
variant="outline"
size="sm"
className={`ml-2 text-sm border-1 border-edge ${versionStatus === "up_to_date" ? "text-green-400" : "text-yellow-400"}`}
className={`ml-2 text-sm border-1 border-edge ${versionStatus === "up_to_date" ? "text-green-400" : versionStatus === "beta" ? "text-blue-400" : "text-yellow-400"}`}
>
{versionStatus === "up_to_date"
? t("dashboard.upToDate")
: t("dashboard.updateAvailable")}
: versionStatus === "beta"
? t("dashboard.beta")
: t("dashboard.updateAvailable")}
</Button>
<UpdateLog loggedIn={loggedIn} />
</>
+5 -3
View File
@@ -32,6 +32,10 @@ export function ElectronVersionCheck({
(theme === "system" &&
window.matchMedia("(prefers-color-scheme: dark)").matches);
const lineColor = isDarkMode ? "#151517" : "#f9f9f9";
const versionModalTitle =
versionInfo?.status === "beta"
? t("versionCheck.betaVersion")
: t("versionCheck.updateRequired");
useEffect(() => {
const updateCheckDisabled =
@@ -183,9 +187,7 @@ export function ElectronVersionCheck({
>
<div className="w-[420px] max-w-full p-8 flex flex-col backdrop-blur-sm bg-card/50 rounded-2xl shadow-xl border-2 border-edge overflow-y-auto thin-scrollbar my-2 animate-in fade-in zoom-in-95 duration-300">
<div className="mb-4">
<h2 className="text-lg font-semibold">
{t("versionCheck.updateRequired")}
</h2>
<h2 className="text-lg font-semibold">{versionModalTitle}</h2>
</div>
<div className="mb-4">
+1 -1
View File
@@ -679,7 +679,7 @@ export async function testServerConnection(
export async function checkElectronUpdate(): Promise<{
success: boolean;
status?: "up_to_date" | "requires_update";
status?: "up_to_date" | "requires_update" | "beta";
localVersion?: string;
remoteVersion?: string;
latest_release?: {