feat(profile): display version number from .env in profile menu (#182)

* feat(profile): display version number from .env in profile menu

* Update version checking process

---------

Co-authored-by: LukeGus <bugattiguy527@gmail.com>
This commit was merged in pull request #182.
This commit is contained in:
Shivam Kumar
2025-09-08 10:44:17 +05:30
committed by GitHub
parent aa04597e16
commit dfb50ed8b1
6 changed files with 47 additions and 36 deletions

11
package-lock.json generated
View File

@@ -69,6 +69,7 @@
"react-hook-form": "^7.60.0",
"react-i18next": "^15.7.3",
"react-resizable-panels": "^3.0.3",
"react-simple-keyboard": "^3.8.120",
"react-xtermjs": "^1.0.10",
"sonner": "^2.0.7",
"speakeasy": "^2.0.0",
@@ -7818,6 +7819,16 @@
"react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
}
},
"node_modules/react-simple-keyboard": {
"version": "3.8.120",
"resolved": "https://registry.npmjs.org/react-simple-keyboard/-/react-simple-keyboard-3.8.120.tgz",
"integrity": "sha512-VREEGZWXUeqRKvRVg0n8hmoAqz/TSWZEs5UwbfLuan4yKvOQZUFHtS11QGnvIVYjkThh+JYslO2CHT4Lxf5d0w==",
"license": "MIT",
"peerDependencies": {
"react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/react-style-singleton": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",

View File

@@ -1,29 +1,15 @@
{
"name": "termix",
"private": true,
"version": "1.6.0",
"description": "Open-source server management platform with SSH terminal access, tunnel management, and file editing",
"author": {
"name": "LukeGus",
"email": "support@termix.site"
},
"version": "0.0.0",
"type": "module",
"main": "electron/main-simple.cjs",
"scripts": {
"dev": "vite",
"build": "vite build && npm run build:backend",
"build:frontend": "vite build",
"build": "vite build",
"build:backend": "tsc -p tsconfig.node.json",
"dev:backend": "tsc -p tsconfig.node.json && node ./dist/backend/starter.js",
"lint": "eslint .",
"preview": "vite preview",
"electron": "electron .",
"electron:dev": "npm run build:backend && NODE_ENV=development electron .",
"electron:package": "npm run build && electron-packager . Termix --platform=win32 --arch=x64 --out=release --overwrite --ignore=\"^/src|^/public|^/node_modules|^/repo-images\" --prune=true --icon=public/favicon.ico",
"electron:package:win": "npm run build && electron-packager . Termix --platform=win32 --arch=x64 --out=release --overwrite --ignore=\"^/src|^/public|^/node_modules|^/repo-images\" --prune=true --icon=public/favicon.ico",
"electron:package:mac": "npm run build && electron-packager . Termix --platform=darwin --arch=universal --out=release --overwrite --ignore=\"^/src|^/public|^/node_modules|^/repo-images\" --prune=true --icon=public/icon.png",
"electron:package:linux": "npm run build && electron-packager . Termix --platform=linux --arch=x64 --out=release --overwrite --ignore=\"^/src|^/public|^/node_modules|^/repo-images\" --prune=true --icon=public/icon.png",
"electron:package:all": "npm run build && npm run electron:package:win && npm run electron:package:mac && npm run electron:package:linux"
"preview": "vite preview"
},
"dependencies": {
"@hookform/resolvers": "^5.1.1",
@@ -44,6 +30,11 @@
"@radix-ui/react-switch": "^1.2.5",
"@radix-ui/react-tabs": "^1.1.12",
"@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/vite": "^4.1.11",
"@types/bcryptjs": "^2.4.6",
"@types/multer": "^2.0.0",
"@types/qrcode": "^1.5.5",
"@types/speakeasy": "^2.0.10",
"@uiw/codemirror-extensions-hyper-link": "^4.24.1",
"@uiw/codemirror-extensions-langs": "^4.24.1",
"@uiw/codemirror-themes": "^4.24.1",
@@ -82,43 +73,34 @@
"react-hook-form": "^7.60.0",
"react-i18next": "^15.7.3",
"react-resizable-panels": "^3.0.3",
"react-responsive": "^10.0.1",
"react-simple-keyboard": "^3.8.120",
"react-xtermjs": "^1.0.10",
"sonner": "^2.0.7",
"speakeasy": "^2.0.0",
"ssh2": "^1.16.0",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.11",
"validator": "^13.15.15",
"ws": "^8.18.3",
"xterm": "^5.3.0",
"zod": "^4.0.5"
},
"devDependencies": {
"@eslint/js": "^9.34.0",
"@tailwindcss/vite": "^4.1.12",
"@types/bcryptjs": "^2.4.6",
"@types/better-sqlite3": "^7.6.13",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/jsonwebtoken": "^9.0.10",
"@types/multer": "^2.0.0",
"@types/node": "^24.3.0",
"@types/qrcode": "^1.5.5",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@types/speakeasy": "^2.0.10",
"@types/ssh2": "^1.15.5",
"@types/ws": "^8.18.1",
"@vitejs/plugin-react-swc": "^3.10.2",
"autoprefixer": "^10.4.21",
"electron": "^31.7.0",
"electron-packager": "^17.1.2",
"eslint": "^9.34.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.3.0",
"tailwindcss": "^4.1.12",
"ts-node": "^10.9.2",
"tw-animate-css": "^1.3.5",
"typescript": "~5.9.2",

View File

@@ -199,6 +199,7 @@
"register": "Register",
"username": "Username",
"password": "Password",
"version" : "Version",
"confirmPassword": "Confirm Password",
"back": "Back",
"email": "Email",

View File

@@ -148,22 +148,16 @@ app.get('/health', (req, res) => {
app.get('/version', async (req, res) => {
let localVersion = process.env.VERSION;
// Fallback to package.json version if env variable not set
if (!localVersion) {
try {
const packagePath = path.resolve(process.cwd(), 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
localVersion = packageJson.version;
logger.info(`Using version from package.json: ${localVersion}`);
} catch (error) {
logger.error('Failed to read version from package.json:', error);
}
}
// Debug logging
logger.debug(`Final version: ${localVersion}`);
logger.debug(`Working directory: ${process.cwd()}`);
if (!localVersion) {
logger.error('No version information available');
return res.status(404).send('Local Version Not Set');
@@ -186,6 +180,7 @@ app.get('/version', async (req, res) => {
const response = {
status: localVersion === remoteVersion ? 'up_to_date' : 'requires_update',
localVersion: localVersion,
version: remoteVersion,
latest_release: {
tag_name: releaseData.data.tag_name,

View File

@@ -8,11 +8,13 @@ import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs.tsx
import {User, Shield, Key, AlertCircle} from "lucide-react";
import {TOTPSetup} from "@/ui/Desktop/User/TOTPSetup.tsx";
import {getUserInfo} from "@/ui/main-axios.ts";
import {getVersionInfo} from "@/ui/main-axios.ts";
import {toast} from "sonner";
import {PasswordReset} from "@/ui/Desktop/User/PasswordReset.tsx";
import {useTranslation} from "react-i18next";
import {LanguageSwitcher} from "@/components/LanguageSwitcher.tsx";
interface UserProfileProps {
isTopbarOpen?: boolean;
}
@@ -27,11 +29,23 @@ export function UserProfile({isTopbarOpen = true}: UserProfileProps) {
} | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [versionInfo, setVersionInfo] = useState<{ version: string } | null>(null);
useEffect(() => {
fetchUserInfo();
fetchVersion();
}, []);
const fetchVersion = async () => {
try {
const info = await getVersionInfo();
setVersionInfo({version: info.localVersion});
} catch (err) {
console.error("Failed to load version info", err);
}
};
const fetchUserInfo = async () => {
setLoading(true);
setError(null);
@@ -146,6 +160,13 @@ export function UserProfile({isTopbarOpen = true}: UserProfileProps) {
)}
</p>
</div>
<div>
<Label>{t('common.version')}</Label>
<p className="text-lg font-medium mt-1">
{versionInfo?.version || t('common.loading')}
</p>
</div>
</div>
<div className="mt-6 pt-6 border-t">

View File

@@ -142,6 +142,7 @@ interface AuthResponse {
}
interface UserInfo {
totp_enabled: boolean;
id: string;
username: string;
is_admin: boolean;