diff --git a/package-lock.json b/package-lock.json
index a3195012..8193800a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 74f44274..0c4ff32c 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json
index bb804eac..ce060c7f 100644
--- a/public/locales/en/translation.json
+++ b/public/locales/en/translation.json
@@ -199,6 +199,7 @@
"register": "Register",
"username": "Username",
"password": "Password",
+ "version" : "Version",
"confirmPassword": "Confirm Password",
"back": "Back",
"email": "Email",
diff --git a/src/backend/database/database.ts b/src/backend/database/database.ts
index a56faf1d..40466490 100644
--- a/src/backend/database/database.ts
+++ b/src/backend/database/database.ts
@@ -147,22 +147,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');
@@ -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,
diff --git a/src/ui/Desktop/User/UserProfile.tsx b/src/ui/Desktop/User/UserProfile.tsx
index 8fdc0d31..2cc462b0 100644
--- a/src/ui/Desktop/User/UserProfile.tsx
+++ b/src/ui/Desktop/User/UserProfile.tsx
@@ -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
+ {versionInfo?.version || t('common.loading')} +
+{t('profile.selectPreferredLanguage')}