From 38eda1c7cf5dc784e539bd3ab39a2e0646af2bb1 Mon Sep 17 00:00:00 2001 From: LukeGus Date: Wed, 29 Apr 2026 17:00:07 -0500 Subject: [PATCH] feat: improve lazy loading with loading spinners --- src/ui/desktop/DesktopApp.tsx | 37 +- src/ui/desktop/apps/admin/AdminSettings.tsx | 64 +- .../host-manager/hosts/HostManagerViewer.tsx | 10 +- src/ui/desktop/navigation/AppView.tsx | 15 +- src/ui/desktop/user/UserProfile.tsx | 927 +++++++++--------- 5 files changed, 540 insertions(+), 513 deletions(-) diff --git a/src/ui/desktop/DesktopApp.tsx b/src/ui/desktop/DesktopApp.tsx index 812109ef..1fbd4040 100644 --- a/src/ui/desktop/DesktopApp.tsx +++ b/src/ui/desktop/DesktopApp.tsx @@ -28,6 +28,7 @@ import { import { useTheme } from "@/components/theme-provider"; import { dbHealthMonitor } from "@/lib/db-health-monitor.ts"; import { useTranslation } from "react-i18next"; +import { SimpleLoader } from "@/ui/desktop/navigation/animations/SimpleLoader.tsx"; const Dashboard = lazy(() => import("@/ui/desktop/apps/dashboard/Dashboard.tsx").then((module) => ({ @@ -445,12 +446,17 @@ function AppContent({ + > + + } > + > + + } > + > + + } > + > + + } > { - if (res) setOidcConfig(res); - }) - .catch((err) => { - if (!err.message?.includes("No server configured")) { - toast.error(t("admin.failedToFetchOidcConfig")); - } - }); - getUserInfo() - .then((info) => { - if (info) { - setCurrentUser({ - id: info.userId, - username: info.username, - is_admin: info.is_admin, - is_oidc: info.is_oidc, - }); - } - }) - .catch((err) => { - if (!err?.message?.includes("No server configured")) { - console.warn("Failed to fetch current user info", err); - } - }); - fetchSessions(); + Promise.allSettled([ + getAdminOIDCConfig() + .then((res) => { + if (res) setOidcConfig(res); + }) + .catch((err) => { + if (!err.message?.includes("No server configured")) { + toast.error(t("admin.failedToFetchOidcConfig")); + } + }), + getUserInfo() + .then((info) => { + if (info) { + setCurrentUser({ + id: info.userId, + username: info.username, + is_admin: info.is_admin, + is_oidc: info.is_oidc, + }); + } + }) + .catch((err) => { + if (!err?.message?.includes("No server configured")) { + console.warn("Failed to fetch current user info", err); + } + }), + getSessions() + .then((data) => setSessions(data.sessions || [])) + .catch((err) => { + if (!err?.message?.includes("No server configured")) { + toast.error(t("admin.failedToFetchSessions")); + } + }), + ]).finally(() => setLoading(false)); }, []); React.useEffect(() => { @@ -333,6 +344,7 @@ export function AdminSettings({ style={wrapperStyle} className="bg-canvas text-foreground rounded-lg border-2 border-edge overflow-hidden" > +

{t("admin.title")}

diff --git a/src/ui/desktop/apps/host-manager/hosts/HostManagerViewer.tsx b/src/ui/desktop/apps/host-manager/hosts/HostManagerViewer.tsx index 8d38ef53..9f39c84f 100644 --- a/src/ui/desktop/apps/host-manager/hosts/HostManagerViewer.tsx +++ b/src/ui/desktop/apps/host-manager/hosts/HostManagerViewer.tsx @@ -102,6 +102,7 @@ import { DEFAULT_STATS_CONFIG } from "@/types/stats-widgets.ts"; import { Checkbox } from "@/components/ui/checkbox.tsx"; import { FolderEditDialog } from "@/ui/desktop/apps/host-manager/dialogs/FolderEditDialog.tsx"; import { useTabs } from "@/ui/desktop/navigation/tabs/TabContext.tsx"; +import { SimpleLoader } from "@/ui/desktop/navigation/animations/SimpleLoader.tsx"; const INITIAL_HOSTS_PER_FOLDER = 12; @@ -1047,14 +1048,7 @@ export function HostManagerViewer({ ); if (loading) { - return ( -
-
-
-

{t("hosts.loadingHosts")}

-
-
- ); + return ; } if (error) { diff --git a/src/ui/desktop/navigation/AppView.tsx b/src/ui/desktop/navigation/AppView.tsx index ba632244..f8349dd9 100644 --- a/src/ui/desktop/navigation/AppView.tsx +++ b/src/ui/desktop/navigation/AppView.tsx @@ -22,6 +22,8 @@ import { DEFAULT_TERMINAL_CONFIG, } from "@/constants/terminal-themes"; import { useTheme } from "@/components/theme-provider"; +import { SimpleLoader } from "@/ui/desktop/navigation/animations/SimpleLoader.tsx"; +import { useTranslation } from "react-i18next"; const Terminal = lazy(() => import("@/ui/desktop/apps/features/terminal/Terminal.tsx").then((module) => ({ @@ -150,6 +152,7 @@ export function AppView({ }; const { state: sidebarState } = useSidebar(); const { theme: appTheme } = useTheme(); + const { t: translate } = useTranslation(); const isDarkMode = useMemo(() => { if (appTheme === "dark") return true; @@ -446,7 +449,17 @@ export function AppView({ : "var(--bg-base)", }} > - + + } + > {t.type === "terminal" ? ( -
-
-

{t("nav.userProfile")}

-
- -
-
- {t("common.loading")} -
-
-
-
- ); - } - - if (error || !userInfo) { + if (!loading && (error || !userInfo)) { return (
+

{t("nav.userProfile")}

@@ -378,471 +359,477 @@ export function UserProfile({
- - - - - {t("profile.account")} - - - - {t("profile.appearance")} - - {supportsClientTunnels && ( + {userInfo && ( + + - - {t("tunnels.clientTunnels")} - - )} - {(!userInfo.is_oidc || userInfo.is_dual_auth) && ( - - - {t("profile.security")} + + {t("profile.account")} - )} - - - -
-

- {t("profile.accountInfo")} -

-
-
- -

- {userInfo.username} -

-
-
- -
- {userRoles.length > 0 ? ( -
- {userRoles.map((role) => ( - - {t(role.roleDisplayName)} - - ))} -
- ) : ( -

- {userInfo.is_admin - ? t("interface.administrator") - : t("interface.user")} -

- )} -
-
-
- -

- {userInfo.is_dual_auth - ? t("profile.externalAndLocal") - : userInfo.is_oidc - ? t("profile.external") - : t("profile.local")} -

-
-
- -

- {userInfo.is_oidc && !userInfo.is_dual_auth ? ( - - {t("auth.lockedOidcAuth")} - - ) : userInfo.totp_enabled ? ( - - - {t("common.enabled")} - - ) : ( - - {t("common.disabled")} - - )} -

-
-
- -

- {versionInfo?.version || t("common.loading")} -

-
-
- -
-
-
- -

- {t("leftSidebar.deleteAccountWarningShort")} -

-
- -
-
-
-
- - -
-

- {t("profile.languageLocalization")} -

-
-
-
- -

- {t("profile.selectPreferredLanguage")} -

-
- -
-
-
- -
-

+ + {t("profile.appearance")} -

-
-
+ + {supportsClientTunnels && ( + + + {t("tunnels.clientTunnels")} + + )} + {(!userInfo.is_oidc || userInfo.is_dual_auth) && ( + + + {t("profile.security")} + + )} + + + +
+

+ {t("profile.accountInfo")} +

+
-

- {t("profile.appearanceDesc")} +

+ {userInfo.username}

- + {t("leftSidebar.deleteAccount")} + +
-
- -
-

- {t("profile.fileManagerSettings")} -

-
-
-
- -

- {t("profile.fileColorCodingDesc")} -

-
- -
-
-
- -
-

- {t("profile.terminalSettings")} -

-
-
-
- -

- {t("profile.commandAutocompleteDesc")} -

-
- -
-
-
- -

- {t("profile.commandHistoryTrackingDesc")} -

-
- -
-
-
- -

- {t("profile.terminalSyntaxHighlightingDesc")} -

-
- -
-
-
- -

- {t("profile.enableCommandPaletteShortcutDesc")} -

-
- -
-
-
- -

- {t("profile.enableTerminalSessionPersistenceDesc")} -

-
- -
-
-
- -
-

- {t("profile.hostSidebarSettings")} -

-
-
-
- -

- {t("profile.showHostTagsDesc")} -

-
- -
-
-
- -
-

- {t("profile.snippetsSettings")} -

-
-
-
- -

- {t("profile.defaultSnippetFoldersCollapsedDesc")} -

-
- -
-
-
- -

- {t("profile.confirmSnippetExecutionDesc")} -

-
- -
-
-
- -
-

- {t("profile.updateSettings")} -

-
-
-
- -

- {t("profile.disableUpdateCheckDesc")} -

-
- -
-
-
- - - {supportsClientTunnels && ( - - - )} - - + +
+

+ {t("profile.languageLocalization")} +

+
+
+
+ +

+ {t("profile.selectPreferredLanguage")} +

+
+ +
+
+
- {(!userInfo.is_oidc || userInfo.is_dual_auth) && ( - +
+

+ {t("profile.appearance")} +

+
+
+
+ +

+ {t("profile.appearanceDesc")} +

+
+ +
+
+
+ +
+

+ {t("profile.fileManagerSettings")} +

+
+
+
+ +

+ {t("profile.fileColorCodingDesc")} +

+
+ +
+
+
+ +
+

+ {t("profile.terminalSettings")} +

+
+
+
+ +

+ {t("profile.commandAutocompleteDesc")} +

+
+ +
+
+
+ +

+ {t("profile.commandHistoryTrackingDesc")} +

+
+ +
+
+
+ +

+ {t("profile.terminalSyntaxHighlightingDesc")} +

+
+ +
+
+
+ +

+ {t("profile.enableCommandPaletteShortcutDesc")} +

+
+ +
+
+
+ +

+ {t("profile.enableTerminalSessionPersistenceDesc")} +

+
+ +
+
+
+ +
+

+ {t("profile.hostSidebarSettings")} +

+
+
+
+ +

+ {t("profile.showHostTagsDesc")} +

+
+ +
+
+
+ +
+

+ {t("profile.snippetsSettings")} +

+
+
+
+ +

+ {t("profile.defaultSnippetFoldersCollapsedDesc")} +

+
+ +
+
+
+ +

+ {t("profile.confirmSnippetExecutionDesc")} +

+
+ +
+
+
+ +
+

+ {t("profile.updateSettings")} +

+
+
+
+ +

+ {t("profile.disableUpdateCheckDesc")} +

+
+ +
+
+
+
+ + {supportsClientTunnels && ( + + + )} -
- + + + + + {(!userInfo.is_oidc || userInfo.is_dual_auth) && ( + + )} + + + )}