App.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import { lazy, Suspense, useEffect } from "react";
  2. import { Navigate, Route, Routes } from "react-router-dom";
  3. import { useTranslation } from "react-i18next";
  4. import { ProtectedRoute } from "@/components/auth/ProtectedRoute";
  5. import { AppLayout } from "@/components/layout/AppLayout";
  6. import { ErrorBoundary } from "@/components/shared/ErrorBoundary";
  7. import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
  8. import { Toaster } from "@/components/ui/toaster";
  9. import { useUiStore } from "@/stores/ui";
  10. import i18n from "@/i18n";
  11. const LoginPage = lazy(() => import("@/pages/login/LoginPage").then((module) => ({ default: module.LoginPage })));
  12. const DashboardPage = lazy(() => import("@/pages/dashboard/DashboardPage").then((module) => ({ default: module.DashboardPage })));
  13. const AgentListPage = lazy(() => import("@/pages/agents/AgentListPage").then((module) => ({ default: module.AgentListPage })));
  14. const SessionChatPage = lazy(() => import("@/pages/sessions/SessionChatPage").then((module) => ({ default: module.SessionChatPage })));
  15. const ToolsPage = lazy(() => import("@/pages/tools/ToolsPage").then((module) => ({ default: module.ToolsPage })));
  16. const KnowledgePage = lazy(() => import("@/pages/knowledge/KnowledgePage").then((module) => ({ default: module.KnowledgePage })));
  17. const TeamsPage = lazy(() => import("@/pages/teams/TeamsPage").then((module) => ({ default: module.TeamsPage })));
  18. const SkillsPage = lazy(() => import("@/pages/skills/SkillsPage").then((module) => ({ default: module.SkillsPage })));
  19. const ModelProvidersPage = lazy(() => import("@/pages/models/ModelProvidersPage").then((module) => ({ default: module.ModelProvidersPage })));
  20. const SettingsPage = lazy(() => import("@/pages/settings/SettingsPage").then((module) => ({ default: module.SettingsPage })));
  21. export default function App() {
  22. const { t } = useTranslation();
  23. return (
  24. <>
  25. <ThemeSync />
  26. <LanguageSync />
  27. <RoutePreloader />
  28. <ErrorBoundary>
  29. <Suspense fallback={<LoadingSpinner label={t("app.loadingStudio")} />}>
  30. <Routes>
  31. <Route path="/login" element={<LoginPage />} />
  32. <Route path="/" element={<Navigate to="/dashboard" replace />} />
  33. <Route
  34. element={
  35. <ProtectedRoute>
  36. <AppLayout />
  37. </ProtectedRoute>
  38. }
  39. >
  40. <Route path="/dashboard" element={<DashboardPage />} />
  41. <Route path="/agents" element={<AgentListPage />} />
  42. <Route path="/sessions" element={<SessionChatPage />} />
  43. <Route path="/tools" element={<ToolsPage />} />
  44. <Route path="/knowledge" element={<KnowledgePage />} />
  45. <Route path="/knowledge/:section" element={<KnowledgePage />} />
  46. <Route path="/teams" element={<TeamsPage />} />
  47. <Route path="/skills" element={<SkillsPage />} />
  48. <Route path="/models" element={<ModelProvidersPage />} />
  49. <Route path="/settings" element={<SettingsPage />} />
  50. </Route>
  51. <Route path="*" element={<Navigate to="/dashboard" replace />} />
  52. </Routes>
  53. </Suspense>
  54. </ErrorBoundary>
  55. <Toaster />
  56. </>
  57. );
  58. }
  59. function ThemeSync() {
  60. const theme = useUiStore((state) => state.theme);
  61. useEffect(() => {
  62. document.documentElement.classList.toggle("dark", theme === "dark");
  63. }, [theme]);
  64. return null;
  65. }
  66. function RoutePreloader() {
  67. useEffect(() => {
  68. const preload = () => {
  69. void Promise.all([
  70. import("@/pages/dashboard/DashboardPage"),
  71. import("@/pages/agents/AgentListPage"),
  72. import("@/pages/sessions/SessionChatPage"),
  73. import("@/pages/tools/ToolsPage"),
  74. import("@/pages/knowledge/KnowledgePage"),
  75. import("@/pages/teams/TeamsPage"),
  76. import("@/pages/skills/SkillsPage"),
  77. import("@/pages/models/ModelProvidersPage"),
  78. import("@/pages/settings/SettingsPage"),
  79. ]);
  80. };
  81. const requestIdle = window.requestIdleCallback ?? ((callback: IdleRequestCallback) => window.setTimeout(callback, 400));
  82. const cancelIdle = window.cancelIdleCallback ?? window.clearTimeout;
  83. const handle = requestIdle(preload);
  84. return () => cancelIdle(handle);
  85. }, []);
  86. return null;
  87. }
  88. function LanguageSync() {
  89. const language = useUiStore((state) => state.language);
  90. useEffect(() => {
  91. if (language && i18n.language !== language) {
  92. i18n.changeLanguage(language);
  93. }
  94. }, [language]);
  95. return null;
  96. }