From a07d323cdabe8a0a01e70cb272790c3bcc43f332 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 27 Feb 2026 11:24:06 +0000
Subject: [PATCH 1/5] Initial plan
From 58a4892e32eebc433c46535742f99b6578ed57dd Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 27 Feb 2026 11:32:06 +0000
Subject: [PATCH 2/5] feat: improve empty state UX and add top-level system
routes
- Always show Create App button in empty state (even on error)
- Add System Settings link to empty state pages
- Add top-level /system/* and /create-app routes for access without app context
- Modify AppSidebar to show system navigation when no apps configured
- Update SystemHubPage and AppManagementPage to handle missing appName
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
---
apps/console/src/App.tsx | 104 +++++--
apps/console/src/components/AppSidebar.tsx | 280 +++++++++++-------
.../src/pages/system/AppManagementPage.tsx | 2 +-
.../src/pages/system/SystemHubPage.tsx | 2 +-
4 files changed, 256 insertions(+), 132 deletions(-)
diff --git a/apps/console/src/App.tsx b/apps/console/src/App.tsx
index 3d6a0e06..610ab8f1 100644
--- a/apps/console/src/App.tsx
+++ b/apps/console/src/App.tsx
@@ -1,7 +1,7 @@
import { BrowserRouter, Routes, Route, Navigate, useNavigate, useLocation, useSearchParams } from 'react-router-dom';
import { useState, useEffect, useCallback, lazy, Suspense, useMemo, type ReactNode } from 'react';
import { ModalForm } from '@object-ui/plugin-form';
-import { Empty, EmptyTitle, EmptyDescription } from '@object-ui/components';
+import { Empty, EmptyTitle, EmptyDescription, Button } from '@object-ui/components';
import { toast } from 'sonner';
import { SchemaRendererProvider, useActionRunner, useGlobalUndo } from '@object-ui/react';
import type { ConnectionState } from './dataSource';
@@ -261,28 +261,49 @@ export function AppContent() {
// Allow create-app route even when no active app exists
const isCreateAppRoute = location.pathname.endsWith('/create-app');
- if (!activeApp && !isCreateAppRoute) return (
+ // Check if we're on a system route (accessible without an active app)
+ const isSystemRoute = location.pathname.includes('/system');
+
+ if (!activeApp && !isCreateAppRoute && !isSystemRoute) return (
No Apps Configured
- No applications have been registered.
-
+
+ No applications have been registered. Create your first app or visit System Settings to configure your environment.
+
+
+
+
+
);
// When on create-app without an active app, render a minimal layout with just the wizard
- if (!activeApp && isCreateAppRoute) {
+ if (!activeApp && (isCreateAppRoute || isSystemRoute)) {
return (
}>
} />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
);
@@ -455,22 +476,51 @@ function RootRedirect() {
{error ? 'Failed to Load Configuration' : 'No Apps Configured'}
- {error ? error.message : 'No applications have been registered. Check your ObjectStack configuration.'}
+ {error
+ ? 'There was an error loading the configuration. You can still create an app or access System Settings.'
+ : 'No applications have been registered. Create your first app or configure your system.'}
- {!error && (
-
);
}
+/**
+ * SystemRoutes — Top-level system admin routes accessible without any app context.
+ * Provides a minimal layout with system navigation sidebar.
+ */
+function SystemRoutes() {
+ return (
+ }>
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+ );
+}
+
export function App() {
return (
@@ -483,6 +533,24 @@ export function App() {
} />
} />
} />
+ {/* Top-level system routes — accessible without any app */}
+ } loadingFallback={}>
+
+
+
+
+ } />
+ {/* Top-level create-app — accessible without any app */}
+ } loadingFallback={}>
+
+ }>
+
+
+
+
+ } />
} loadingFallback={}>
diff --git a/apps/console/src/components/AppSidebar.tsx b/apps/console/src/components/AppSidebar.tsx
index 6a1dc9d8..4281873c 100644
--- a/apps/console/src/components/AppSidebar.tsx
+++ b/apps/console/src/components/AppSidebar.tsx
@@ -250,7 +250,17 @@ export function AppSidebar({ activeAppName, onAppChange }: { activeAppName: stri
[can],
);
- const basePath = `/apps/${activeAppName}`;
+ const basePath = activeApp ? `/apps/${activeAppName}` : '';
+
+ // Fallback system navigation when no active app exists
+ const systemFallbackNavigation: NavigationItem[] = React.useMemo(() => [
+ { id: 'sys-settings', label: 'System Settings', type: 'url' as const, url: '/system', icon: 'settings' },
+ { id: 'sys-apps', label: 'Applications', type: 'url' as const, url: '/system/apps', icon: 'layout-grid' },
+ { id: 'sys-users', label: 'Users', type: 'url' as const, url: '/system/users', icon: 'users' },
+ { id: 'sys-orgs', label: 'Organizations', type: 'url' as const, url: '/system/organizations', icon: 'building-2' },
+ { id: 'sys-roles', label: 'Roles', type: 'url' as const, url: '/system/roles', icon: 'shield' },
+ { id: 'sys-create-app', label: 'Create App', type: 'url' as const, url: '/create-app', icon: 'plus' },
+ ], []);
return (
<>
@@ -258,6 +268,7 @@ export function AppSidebar({ activeAppName, onAppChange }: { activeAppName: stri
+ {activeApp ? (
+ ) : (
+ /* No-app fallback header */
+ navigate('/system')}
+ data-testid="system-sidebar-header"
+ >
+