import { BrowserRouter, Routes, Route, Navigate } from 'react-router'; import * as Authentication from './Screens/Authentication'; import * as Dashboard from './Screens/Dashboard'; import { useAuth } from 'hooks/useAuth'; import { useServerSettings } from 'state/useServerSettings'; import { useServerEnvironment } from 'state/useServerEnvironment'; import { useInitialData } from '@/state/useInitialData'; // `installedPlugins`, not `plugins`: App.tsx already destructures a `plugins` from useServerSettings(), // which is the DEAD plugin system — /server-settings/plugins scans src/workspaces/plugins/, a directory // that does not exist, so it is always []. Different thing entirely; see plugins/offscale/PLUGIN.md. import { plugins as installedPlugins } from './Plugins.gen'; export function App() { const { isLoading, isAuthenticated } = useAuth(); const { plugins, isLoading: isServerSettingsLoading } = useServerSettings(); useServerEnvironment(); useInitialData(); if (isLoading || isServerSettingsLoading) return null; return ( {!isAuthenticated && ( } /> } /> } /> } /> )} {isAuthenticated && ( } /> {/* Route pairs, like /headscale and /photos below: the bare page route exists so the existing links into it keep working, and its `SettingsRoute` guard redirects to the first section. The section is the URL rather than a `*_SELECTED` global, so a settings sub-page is linkable, bookmarkable and cmd-clickable. */} } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> {/* A project group is a working directory, so it is spelled as a path, not ?cwd= — see apps/ChatHistory/chat-routes.ts. The splat has to be last in a pattern, which is why "new" comes before the group rather than after it. A session carries no group: the transcript records its own cwd and the server resolves it by id. */} } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> {/* Installed plugins. Core routes above stay hand-written; everything below is generated from what is installed, because a bundler cannot follow a runtime import specifier. The wildcard hands the whole subtree to the plugin's own router, which react-router nests natively. */} {installedPlugins.flatMap((plugin) => [ } />, // The section pair, exactly as the core screens do it (`/headscale/:section`): the plugin's // panels read `useParams` themselves, so which section is open is the URL rather than state // passed between them. } />, ])} } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> {/* TEMPORARY / EXPERIMENTAL — offline file transfer over animated QR codes */} } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> )} ); }