mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-05-04 00:21:19 +00:00
Add beta version update status
This commit is contained in:
+28
-2
@@ -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: {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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} />
|
||||
</>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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?: {
|
||||
|
||||
Reference in New Issue
Block a user