Skip to content

Commit 7b40b51

Browse files
committed
feat(FR-2521): add Suspense skeleton fallback to lazy-loaded pages (#6596)
Resolves #6595(FR-2521) ## Summary - Wrap all 20 lazy-loaded pages in `routes.tsx` with `<Suspense fallback={<Skeleton active />}>` that were missing loading indicators - Users now see an in-place skeleton instead of a blank screen during code-split chunk loading - Consistent with the pattern already used by DashboardPage, ComputeSessionListPage, etc. **Main layout pages (15)**: StartPage, MyEnvironmentPage, AgentSummaryPage, AdminSessionPage, EnvironmentPage, ResourcesPage, ResourcePolicyPage, ConfigurationsPage, MaintenancePage, DiagnosticsPage, BrandingPage, StorageHostSettingPage, Information, UserSettingsPage, UserCredentialsPage **Root-level pages (5)**: InteractiveLoginPage, EmailVerificationPage, ChangePasswordPage, EduAppLauncherPage (×2 routes) ## Verification ``` === ALL PASS === ``` ## Test plan - [ ] Navigate to each affected page and verify skeleton appears during lazy load - [ ] Verify no regressions on pages that already had Suspense boundaries - [ ] `verify.sh` passes (Relay, Lint, Format, TypeScript) 🤖 Generated with [Claude Code](https://claude.ai/code)
1 parent 2e3a854 commit 7b40b51

1 file changed

Lines changed: 91 additions & 27 deletions

File tree

react/src/routes.tsx

Lines changed: 91 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,11 @@ export const mainLayoutChildRoutes: RouteObject[] = [
149149
},
150150
{
151151
path: '/start',
152-
element: <StartPage />,
152+
element: (
153+
<Suspense fallback={<Skeleton active />}>
154+
<StartPage />
155+
</Suspense>
156+
),
153157
handle: { labelKey: 'webui.menu.Start' },
154158
},
155159
{
@@ -317,13 +321,7 @@ export const mainLayoutChildRoutes: RouteObject[] = [
317321
Component: () => {
318322
const baiClient = useSuspendedBackendaiClient();
319323
return (
320-
<Suspense
321-
fallback={
322-
<BAIFlex direction="column" style={{ maxWidth: 700 }}>
323-
<Skeleton active />
324-
</BAIFlex>
325-
}
326-
>
324+
<Suspense fallback={<Skeleton active />}>
327325
{baiClient?.supports('model-card-v2') ? (
328326
<ModelStoreListPageV2 />
329327
) : (
@@ -358,12 +356,20 @@ export const mainLayoutChildRoutes: RouteObject[] = [
358356
},
359357
{
360358
path: '/my-environment',
361-
element: <MyEnvironmentPage />,
359+
element: (
360+
<Suspense fallback={<Skeleton active />}>
361+
<MyEnvironmentPage />
362+
</Suspense>
363+
),
362364
handle: { labelKey: 'webui.menu.MyEnvironments' },
363365
},
364366
{
365367
path: '/agent-summary',
366-
element: <AgentSummaryPage />,
368+
element: (
369+
<Suspense fallback={<Skeleton active />}>
370+
<AgentSummaryPage />
371+
</Suspense>
372+
),
367373
handle: { labelKey: 'webui.menu.AgentSummary' },
368374
},
369375
{
@@ -387,7 +393,11 @@ export const mainLayoutChildRoutes: RouteObject[] = [
387393
{
388394
path: '/admin-session',
389395
handle: { labelKey: 'webui.menu.Sessions' },
390-
Component: AdminSessionPage,
396+
element: (
397+
<Suspense fallback={<Skeleton active />}>
398+
<AdminSessionPage />
399+
</Suspense>
400+
),
391401
},
392402
{
393403
path: '/admin-serving',
@@ -434,7 +444,11 @@ export const mainLayoutChildRoutes: RouteObject[] = [
434444
{
435445
path: '/environment',
436446
handle: { labelKey: 'webui.menu.Environments' },
437-
Component: EnvironmentPage,
447+
element: (
448+
<Suspense fallback={<Skeleton active />}>
449+
<EnvironmentPage />
450+
</Suspense>
451+
),
438452
},
439453
{
440454
path: '/scheduler',
@@ -454,12 +468,20 @@ export const mainLayoutChildRoutes: RouteObject[] = [
454468
{
455469
path: '/agent',
456470
handle: { labelKey: 'webui.menu.Resources' },
457-
Component: ResourcesPage,
471+
element: (
472+
<Suspense fallback={<Skeleton active />}>
473+
<ResourcesPage />
474+
</Suspense>
475+
),
458476
},
459477
{
460478
path: '/resource-policy',
461479
handle: { labelKey: 'webui.menu.ResourcePolicies' },
462-
Component: ResourcePolicyPage,
480+
element: (
481+
<Suspense fallback={<Skeleton active />}>
482+
<ResourcePolicyPage />
483+
</Suspense>
484+
),
463485
},
464486
{
465487
path: '/reservoir',
@@ -502,17 +524,29 @@ export const mainLayoutChildRoutes: RouteObject[] = [
502524
},
503525
{
504526
path: '/settings',
505-
element: <ConfigurationsPage />,
527+
element: (
528+
<Suspense fallback={<Skeleton active />}>
529+
<ConfigurationsPage />
530+
</Suspense>
531+
),
506532
handle: { labelKey: 'webui.menu.Configurations' },
507533
},
508534
{
509535
path: '/maintenance',
510-
element: <MaintenancePage />,
536+
element: (
537+
<Suspense fallback={<Skeleton active />}>
538+
<MaintenancePage />
539+
</Suspense>
540+
),
511541
handle: { labelKey: 'webui.menu.Maintenance' },
512542
},
513543
{
514544
path: '/diagnostics',
515-
element: <DiagnosticsPage />,
545+
element: (
546+
<Suspense fallback={<Skeleton active />}>
547+
<DiagnosticsPage />
548+
</Suspense>
549+
),
516550
handle: { labelKey: 'webui.menu.Diagnostics' },
517551
},
518552
{
@@ -531,7 +565,11 @@ export const mainLayoutChildRoutes: RouteObject[] = [
531565
},
532566
{
533567
path: '/branding',
534-
element: <BrandingPage />,
568+
element: (
569+
<Suspense fallback={<Skeleton active />}>
570+
<BrandingPage />
571+
</Suspense>
572+
),
535573
handle: { labelKey: 'webui.menu.Branding' },
536574
},
537575
{
@@ -548,17 +586,29 @@ export const mainLayoutChildRoutes: RouteObject[] = [
548586
{
549587
path: '/storage-settings/:hostname',
550588
handle: { labelKey: 'storageHost.StorageSetting' },
551-
Component: StorageHostSettingPage,
589+
element: (
590+
<Suspense fallback={<Skeleton active />}>
591+
<StorageHostSettingPage />
592+
</Suspense>
593+
),
552594
},
553595
{
554596
path: '/information',
555597
handle: { labelKey: 'webui.menu.Information' },
556-
Component: Information,
598+
element: (
599+
<Suspense fallback={<Skeleton active />}>
600+
<Information />
601+
</Suspense>
602+
),
557603
},
558604
{
559605
path: '/usersettings',
560606
handle: { labelKey: 'webui.menu.Settings&Logs' },
561-
Component: UserSettingsPage,
607+
element: (
608+
<Suspense fallback={<Skeleton active />}>
609+
<UserSettingsPage />
610+
</Suspense>
611+
),
562612
},
563613
{
564614
path: '/admin-dashboard',
@@ -576,7 +626,11 @@ export const mainLayoutChildRoutes: RouteObject[] = [
576626
{
577627
path: '/credential',
578628
handle: { labelKey: 'webui.menu.UserCredentials&Policies' },
579-
Component: UserCredentialsPage,
629+
element: (
630+
<Suspense fallback={<Skeleton active />}>
631+
<UserCredentialsPage />
632+
</Suspense>
633+
),
580634
},
581635
{
582636
path: '/logs',
@@ -637,7 +691,9 @@ export const routes: RouteObject[] = [
637691
<LoginView waitForMainLayout={false} />
638692
</Suspense>
639693
<LogoutEventHandler />
640-
<InteractiveLoginPage />
694+
<Suspense fallback={<Skeleton active />}>
695+
<InteractiveLoginPage />
696+
</Suspense>
641697
</DefaultProvidersForReactRoot>
642698
</BAIErrorBoundary>
643699
),
@@ -648,7 +704,9 @@ export const routes: RouteObject[] = [
648704
element: (
649705
<BAIErrorBoundary>
650706
<DefaultProvidersForReactRoot>
651-
<EmailVerificationPage />
707+
<Suspense fallback={<Skeleton active />}>
708+
<EmailVerificationPage />
709+
</Suspense>
652710
</DefaultProvidersForReactRoot>
653711
</BAIErrorBoundary>
654712
),
@@ -659,7 +717,9 @@ export const routes: RouteObject[] = [
659717
element: (
660718
<BAIErrorBoundary>
661719
<DefaultProvidersForReactRoot>
662-
<ChangePasswordPage />
720+
<Suspense fallback={<Skeleton active />}>
721+
<ChangePasswordPage />
722+
</Suspense>
663723
</DefaultProvidersForReactRoot>
664724
</BAIErrorBoundary>
665725
),
@@ -670,7 +730,9 @@ export const routes: RouteObject[] = [
670730
element: (
671731
<BAIErrorBoundary>
672732
<DefaultProvidersForReactRoot>
673-
<EduAppLauncherPage />
733+
<Suspense fallback={<Skeleton active />}>
734+
<EduAppLauncherPage />
735+
</Suspense>
674736
</DefaultProvidersForReactRoot>
675737
</BAIErrorBoundary>
676738
),
@@ -681,7 +743,9 @@ export const routes: RouteObject[] = [
681743
element: (
682744
<BAIErrorBoundary>
683745
<DefaultProvidersForReactRoot>
684-
<EduAppLauncherPage />
746+
<Suspense fallback={<Skeleton active />}>
747+
<EduAppLauncherPage />
748+
</Suspense>
685749
</DefaultProvidersForReactRoot>
686750
</BAIErrorBoundary>
687751
),

0 commit comments

Comments
 (0)