Skip to content

Commit 58a4892

Browse files
Copilothotlong
andcommitted
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>
1 parent a07d323 commit 58a4892

4 files changed

Lines changed: 256 additions & 132 deletions

File tree

apps/console/src/App.tsx

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BrowserRouter, Routes, Route, Navigate, useNavigate, useLocation, useSearchParams } from 'react-router-dom';
22
import { useState, useEffect, useCallback, lazy, Suspense, useMemo, type ReactNode } from 'react';
33
import { 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';
55
import { toast } from 'sonner';
66
import { SchemaRendererProvider, useActionRunner, useGlobalUndo } from '@object-ui/react';
77
import 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+
474524
export 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

Comments
 (0)