From 994d00e91fcffe6a18399cfd0778da3611ddc330 Mon Sep 17 00:00:00 2001 From: LukeGus Date: Sat, 1 Nov 2025 20:46:40 -0500 Subject: [PATCH] fix: Desktop app login issues and rename version check and host manager folder --- src/backend/database/database.ts | 4 +- src/backend/utils/user-agent-parser.ts | 4 +- src/main.tsx | 52 ++++++++++-- src/ui/desktop/DesktopApp.tsx | 51 ++++-------- .../HostManager.tsx | 4 +- .../HostManagerEditor.tsx | 0 .../HostManagerViewer.tsx | 0 src/ui/desktop/authentication/Auth.tsx | 12 --- .../desktop/user/ElectronVersionCheck.tsx} | 79 ++++++------------- src/ui/main-axios.ts | 12 +-- 10 files changed, 99 insertions(+), 119 deletions(-) rename src/ui/desktop/apps/{host manager => host-manager}/HostManager.tsx (97%) rename src/ui/desktop/apps/{host manager => host-manager}/HostManagerEditor.tsx (100%) rename src/ui/desktop/apps/{host manager => host-manager}/HostManagerViewer.tsx (100%) rename src/{components/ui/version-check-modal.tsx => ui/desktop/user/ElectronVersionCheck.tsx} (70%) diff --git a/src/backend/database/database.ts b/src/backend/database/database.ts index 256c2122..38bee98d 100644 --- a/src/backend/database/database.ts +++ b/src/backend/database/database.ts @@ -68,7 +68,7 @@ app.use( return callback(null, true); } - callback(null, true); + callback(new Error("Not allowed by CORS")); }, credentials: true, methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"], @@ -77,6 +77,8 @@ app.use( "Authorization", "User-Agent", "X-Electron-App", + "Accept", + "Origin", ], }), ); diff --git a/src/backend/utils/user-agent-parser.ts b/src/backend/utils/user-agent-parser.ts index 74e0dca7..0d67c487 100644 --- a/src/backend/utils/user-agent-parser.ts +++ b/src/backend/utils/user-agent-parser.ts @@ -44,10 +44,10 @@ function parseElectronUserAgent(userAgent: string): DeviceInfo { let os = "Unknown OS"; let version = "Unknown"; - const termixMatch = userAgent.match(/Termix-Desktop\/([\d.]+) \(([^;]+);/); + const termixMatch = userAgent.match(/Termix-Desktop\/([\d.]+)\s*\(([^;)]+)/); if (termixMatch) { version = termixMatch[1]; - os = termixMatch[2]; + os = termixMatch[2].trim(); } else { if (userAgent.includes("Windows")) { os = parseWindowsVersion(userAgent); diff --git a/src/main.tsx b/src/main.tsx index aceeca24..31612fdf 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -5,6 +5,7 @@ import "./index.css"; import DesktopApp from "@/ui/desktop/DesktopApp.tsx"; import { MobileApp } from "@/ui/mobile/MobileApp.tsx"; import { ThemeProvider } from "@/components/theme-provider"; +import { ElectronVersionCheck } from "@/ui/desktop/user/ElectronVersionCheck.tsx"; import "./i18n/i18n"; import { isElectron } from "./ui/main-axios.ts"; @@ -55,20 +56,57 @@ function useWindowWidth() { function RootApp() { const width = useWindowWidth(); const isMobile = width < 768; + const [showVersionCheck, setShowVersionCheck] = useState(true); const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera || ""; const isTermixMobile = /Termix-Mobile/.test(userAgent); - if (isElectron()) { - return ; - } + const renderApp = () => { + if (isElectron()) { + return ; + } - if (isTermixMobile) { - return ; - } + if (isTermixMobile) { + return ; + } - return isMobile ? : ; + return isMobile ? : ; + }; + + return ( + <> + {isElectron() && ( +
+ )} +
+ {isElectron() && showVersionCheck ? ( + setShowVersionCheck(false)} + isAuthenticated={false} + /> + ) : ( + renderApp() + )} +
+ + ); } createRoot(document.getElementById("root")!).render( diff --git a/src/ui/desktop/DesktopApp.tsx b/src/ui/desktop/DesktopApp.tsx index f8a3de80..4d8c2b16 100644 --- a/src/ui/desktop/DesktopApp.tsx +++ b/src/ui/desktop/DesktopApp.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react"; import { LeftSidebar } from "@/ui/desktop/navigation/LeftSidebar.tsx"; import { Dashboard } from "@/ui/desktop/apps/dashboard/Dashboard.tsx"; import { AppView } from "@/ui/desktop/navigation/AppView.tsx"; -import { HostManager } from "@/ui/desktop/apps/host manager/HostManager.tsx"; +import { HostManager } from "@/ui/desktop/apps/host-manager/HostManager.tsx"; import { TabProvider, useTabs, @@ -11,7 +11,6 @@ import { TopNavbar } from "@/ui/desktop/navigation/TopNavbar.tsx"; import { AdminSettings } from "@/ui/desktop/admin/AdminSettings.tsx"; import { UserProfile } from "@/ui/desktop/user/UserProfile.tsx"; import { Toaster } from "@/components/ui/sonner.tsx"; -import { VersionCheckModal } from "@/components/ui/version-check-modal.tsx"; import { getUserInfo } from "@/ui/main-axios.ts"; function AppContent() { @@ -19,7 +18,6 @@ function AppContent() { const [username, setUsername] = useState(null); const [isAdmin, setIsAdmin] = useState(false); const [authLoading, setAuthLoading] = useState(true); - const [showVersionCheck, setShowVersionCheck] = useState(true); const [isTopbarOpen, setIsTopbarOpen] = useState(() => { const saved = localStorage.getItem("topNavbarOpen"); return saved !== null ? JSON.parse(saved) : true; @@ -31,9 +29,16 @@ function AppContent() { setAuthLoading(true); getUserInfo() .then((meRes) => { - setIsAuthenticated(true); - setIsAdmin(!!meRes.is_admin); - setUsername(meRes.username || null); + // Check if response is actually HTML (Vite dev server page) + if (typeof meRes === "string" || !meRes.username) { + setIsAuthenticated(false); + setIsAdmin(false); + setUsername(null); + } else { + setIsAuthenticated(true); + setIsAdmin(!!meRes.is_admin); + setUsername(meRes.username || null); + } }) .catch((err) => { setIsAuthenticated(false); @@ -45,7 +50,9 @@ function AppContent() { console.warn("Session expired - please log in again"); } }) - .finally(() => setAuthLoading(false)); + .finally(() => { + setAuthLoading(false); + }); }; checkAuth(); @@ -84,35 +91,7 @@ function AppContent() { return (
- {showVersionCheck && ( - setShowVersionCheck(false)} - onContinue={() => setShowVersionCheck(false)} - isAuthenticated={isAuthenticated} - /> - )} - - {!isAuthenticated && !authLoading && !showVersionCheck && ( -
-
-
- )} - - {!isAuthenticated && !authLoading && !showVersionCheck && ( + {!isAuthenticated && !authLoading && (
{ - if (isInElectronWebView()) { - return; - } - getRegistrationAllowed().then((res) => { setRegistrationAllowed(res.allowed); }); }, []); useEffect(() => { - if (isInElectronWebView()) { - return; - } - getPasswordLoginAllowed() .then((res) => { setPasswordLoginAllowed(res.allowed); @@ -130,10 +122,6 @@ export function Auth({ }, []); useEffect(() => { - if (isInElectronWebView()) { - return; - } - getOIDCConfig() .then((response) => { if (response) { diff --git a/src/components/ui/version-check-modal.tsx b/src/ui/desktop/user/ElectronVersionCheck.tsx similarity index 70% rename from src/components/ui/version-check-modal.tsx rename to src/ui/desktop/user/ElectronVersionCheck.tsx index 52b10ddd..9496afc2 100644 --- a/src/components/ui/version-check-modal.tsx +++ b/src/ui/desktop/user/ElectronVersionCheck.tsx @@ -9,7 +9,7 @@ interface VersionCheckModalProps { isAuthenticated?: boolean; } -export function VersionCheckModal({ +export function ElectronVersionCheck({ onContinue, isAuthenticated = false, }: VersionCheckModalProps) { @@ -35,7 +35,26 @@ export function VersionCheckModal({ const updateInfo = await checkElectronUpdate(); setVersionInfo(updateInfo); + // Get current app version + const currentVersion = await (window as any).electronAPI?.getAppVersion(); + const dismissedVersion = localStorage.getItem( + "electron-version-check-dismissed", + ); + + // If this version was already dismissed, skip the modal + if (dismissedVersion === currentVersion) { + onContinue(); + return; + } + if (updateInfo?.status === "up_to_date") { + // Store this version as checked (but don't show modal since up to date) + if (currentVersion) { + localStorage.setItem( + "electron-version-check-dismissed", + currentVersion, + ); + } onContinue(); return; } @@ -53,7 +72,12 @@ export function VersionCheckModal({ } }; - const handleContinue = () => { + const handleContinue = async () => { + // Store the current version as dismissed + const currentVersion = await (window as any).electronAPI?.getAppVersion(); + if (currentVersion) { + localStorage.setItem("electron-version-check-dismissed", currentVersion); + } onContinue(); }; @@ -64,23 +88,6 @@ export function VersionCheckModal({ if (versionChecking && !versionInfo) { return (
- {!isAuthenticated && ( -
- )}
@@ -96,23 +103,6 @@ export function VersionCheckModal({ if (!versionInfo || versionDismissed) { return (
- {!isAuthenticated && ( -
- )}

@@ -141,23 +131,6 @@ export function VersionCheckModal({ return (
- {!isAuthenticated && ( -
- )}

diff --git a/src/ui/main-axios.ts b/src/ui/main-axios.ts index 4e2b05bb..d367b886 100644 --- a/src/ui/main-axios.ts +++ b/src/ui/main-axios.ts @@ -484,12 +484,7 @@ function getApiUrl(path: string, defaultPort: number): string { const devMode = isDev(); const electronMode = isElectron(); - if (devMode) { - const protocol = window.location.protocol === "https:" ? "https" : "http"; - const sslPort = protocol === "https" ? 8443 : defaultPort; - const url = `${protocol}://${apiHost}:${sslPort}${path}`; - return url; - } else if (electronMode) { + if (electronMode) { if (configuredServerUrl) { const baseUrl = configuredServerUrl.replace(/\/$/, ""); const url = `${baseUrl}${path}`; @@ -497,6 +492,11 @@ function getApiUrl(path: string, defaultPort: number): string { } console.warn("Electron mode but no server configured!"); return "http://no-server-configured"; + } else if (devMode) { + const protocol = window.location.protocol === "https:" ? "https" : "http"; + const sslPort = protocol === "https" ? 8443 : defaultPort; + const url = `${protocol}://${apiHost}:${sslPort}${path}`; + return url; } else { return path; }