11import { BrowserRouter , Routes , Route , Navigate , useNavigate , useLocation , useSearchParams } from 'react-router-dom' ;
22import { useState , useEffect , useCallback , lazy , Suspense , useMemo , type ReactNode } from 'react' ;
33import { ModalForm } from '@object-ui/plugin-form' ;
4- import { Empty , EmptyTitle , EmptyDescription } from '@object-ui/components' ;
4+ import { Empty , EmptyTitle , EmptyDescription , Button } from '@object-ui/components' ;
55import { toast } from 'sonner' ;
66import { SchemaRendererProvider , useActionRunner , useGlobalUndo } from '@object-ui/react' ;
77import type { ConnectionState } from './dataSource' ;
@@ -261,28 +261,49 @@ export function AppContent() {
261261 // Allow create-app route even when no active app exists
262262 const isCreateAppRoute = location . pathname . endsWith ( '/create-app' ) ;
263263
264- if ( ! activeApp && ! isCreateAppRoute ) return (
264+ // Check if we're on a system route (accessible without an active app)
265+ const isSystemRoute = location . pathname . includes ( '/system' ) ;
266+
267+ if ( ! activeApp && ! isCreateAppRoute && ! isSystemRoute ) return (
265268 < div className = "h-screen flex items-center justify-center" >
266269 < Empty >
267270 < EmptyTitle > No Apps Configured</ EmptyTitle >
268- < EmptyDescription > No applications have been registered.</ EmptyDescription >
269- < button
270- className = "mt-4 inline-flex items-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90"
271- onClick = { ( ) => navigate ( 'create-app' ) }
272- data-testid = "create-first-app-btn"
273- >
274- Create Your First App
275- </ button >
271+ < EmptyDescription >
272+ No applications have been registered. Create your first app or visit System Settings to configure your environment.
273+ </ EmptyDescription >
274+ < div className = "mt-4 flex flex-col sm:flex-row items-center gap-3" >
275+ < Button
276+ onClick = { ( ) => navigate ( '/create-app' ) }
277+ data-testid = "create-first-app-btn"
278+ >
279+ Create Your First App
280+ </ Button >
281+ < Button
282+ variant = "outline"
283+ onClick = { ( ) => navigate ( '/system' ) }
284+ data-testid = "go-to-settings-btn"
285+ >
286+ System Settings
287+ </ Button >
288+ </ div >
276289 </ Empty >
277290 </ div >
278291 ) ;
279292
280293 // When on create-app without an active app, render a minimal layout with just the wizard
281- if ( ! activeApp && isCreateAppRoute ) {
294+ if ( ! activeApp && ( isCreateAppRoute || isSystemRoute ) ) {
282295 return (
283296 < Suspense fallback = { < LoadingScreen /> } >
284297 < Routes >
285298 < Route path = "create-app" element = { < CreateAppPage /> } />
299+ < Route path = "system" element = { < SystemHubPage /> } />
300+ < Route path = "system/apps" element = { < AppManagementPage /> } />
301+ < Route path = "system/users" element = { < UserManagementPage /> } />
302+ < Route path = "system/organizations" element = { < OrgManagementPage /> } />
303+ < Route path = "system/roles" element = { < RoleManagementPage /> } />
304+ < Route path = "system/permissions" element = { < PermissionManagementPage /> } />
305+ < Route path = "system/audit-log" element = { < AuditLogPage /> } />
306+ < Route path = "system/profile" element = { < ProfilePage /> } />
286307 </ Routes >
287308 </ Suspense >
288309 ) ;
@@ -455,22 +476,51 @@ function RootRedirect() {
455476 < Empty >
456477 < EmptyTitle > { error ? 'Failed to Load Configuration' : 'No Apps Configured' } </ EmptyTitle >
457478 < EmptyDescription >
458- { error ? error . message : 'No applications have been registered. Check your ObjectStack configuration.' }
479+ { error
480+ ? 'There was an error loading the configuration. You can still create an app or access System Settings.'
481+ : 'No applications have been registered. Create your first app or configure your system.' }
459482 </ EmptyDescription >
460- { ! error && (
461- < button
462- className = "mt-4 inline-flex items-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90"
463- onClick = { ( ) => navigate ( '/apps/_new/create-app' ) }
483+ < div className = "mt-4 flex flex-col sm:flex-row items-center gap-3" >
484+ < Button
485+ onClick = { ( ) => navigate ( '/create-app' ) }
464486 data-testid = "create-first-app-btn"
465487 >
466488 Create Your First App
467- </ button >
468- ) }
489+ </ Button >
490+ < Button
491+ variant = "outline"
492+ onClick = { ( ) => navigate ( '/system' ) }
493+ data-testid = "go-to-settings-btn"
494+ >
495+ System Settings
496+ </ Button >
497+ </ div >
469498 </ Empty >
470499 </ div >
471500 ) ;
472501}
473502
503+ /**
504+ * SystemRoutes — Top-level system admin routes accessible without any app context.
505+ * Provides a minimal layout with system navigation sidebar.
506+ */
507+ function SystemRoutes ( ) {
508+ return (
509+ < Suspense fallback = { < LoadingScreen /> } >
510+ < Routes >
511+ < Route path = "/" element = { < SystemHubPage /> } />
512+ < Route path = "apps" element = { < AppManagementPage /> } />
513+ < Route path = "users" element = { < UserManagementPage /> } />
514+ < Route path = "organizations" element = { < OrgManagementPage /> } />
515+ < Route path = "roles" element = { < RoleManagementPage /> } />
516+ < Route path = "permissions" element = { < PermissionManagementPage /> } />
517+ < Route path = "audit-log" element = { < AuditLogPage /> } />
518+ < Route path = "profile" element = { < ProfilePage /> } />
519+ </ Routes >
520+ </ Suspense >
521+ ) ;
522+ }
523+
474524export function App ( ) {
475525 return (
476526 < ThemeProvider defaultTheme = "system" storageKey = "object-ui-theme" >
@@ -483,6 +533,24 @@ export function App() {
483533 < Route path = "/login" element = { < LoginPage /> } />
484534 < Route path = "/register" element = { < RegisterPage /> } />
485535 < Route path = "/forgot-password" element = { < ForgotPasswordPage /> } />
536+ { /* Top-level system routes — accessible without any app */ }
537+ < Route path = "/system/*" element = {
538+ < AuthGuard fallback = { < Navigate to = "/login" /> } loadingFallback = { < LoadingScreen /> } >
539+ < ConnectedShell >
540+ < SystemRoutes />
541+ </ ConnectedShell >
542+ </ AuthGuard >
543+ } />
544+ { /* Top-level create-app — accessible without any app */ }
545+ < Route path = "/create-app" element = {
546+ < AuthGuard fallback = { < Navigate to = "/login" /> } loadingFallback = { < LoadingScreen /> } >
547+ < ConnectedShell >
548+ < Suspense fallback = { < LoadingScreen /> } >
549+ < CreateAppPage />
550+ </ Suspense >
551+ </ ConnectedShell >
552+ </ AuthGuard >
553+ } />
486554 < Route path = "/apps/:appName/*" element = {
487555 < AuthGuard fallback = { < Navigate to = "/login" /> } loadingFallback = { < LoadingScreen /> } >
488556 < ConnectedShell >
0 commit comments