@@ -26,22 +26,18 @@ import { pluginApiEndpointState } from './hooks/useWebUIPluginState';
2626import ComputeSessionListPage from './pages/ComputeSessionListPage' ;
2727import LegacyModelStoreListPage from './pages/LegacyModelStoreListPage' ;
2828import Page404 from './pages/Page404' ;
29- import ServingPage from './pages/ServingPage' ;
3029import VFolderNodeListPage from './pages/VFolderNodeListPage' ;
3130import { Skeleton , theme } from 'antd' ;
3231import { BAIFlex , BAICard } from 'backend.ai-ui' ;
3332import { useSetAtom } from 'jotai' ;
3433import { parseAsString , useQueryStates } from 'nuqs' ;
3534import React , { Suspense } from 'react' ;
3635import { useTranslation } from 'react-i18next' ;
37- import { RouteObject , useLocation } from 'react-router-dom' ;
36+ import { RouteObject , useLocation , useParams } from 'react-router-dom' ;
3837
3938const LoginViewLazy = React . lazy ( ( ) => import ( './components/LoginView' ) ) ;
4039
4140const Information = React . lazy ( ( ) => import ( './components/Information' ) ) ;
42- const EndpointDetailPage = React . lazy (
43- ( ) => import ( './pages/EndpointDetailPage' ) ,
44- ) ;
4541const StartPage = React . lazy ( ( ) => import ( './pages/StartPage' ) ) ;
4642const DashboardPage = React . lazy ( ( ) => import ( './pages/DashboardPage' ) ) ;
4743const AdminDashboardPage = React . lazy (
@@ -75,6 +71,21 @@ const ServiceLauncherCreatePage = React.lazy(
7571const ServiceLauncherUpdatePage = React . lazy (
7672 ( ) => import ( './pages/ServiceLauncherPage' ) ,
7773) ;
74+ // FR-2664 — Deployment UI migration (Phase 1: Foundation).
75+ // These pages are currently stub placeholders and will be implemented in
76+ // Phase 3/4/5 (FR-2671 / FR-2675 / FR-2681 / FR-2672).
77+ const DeploymentListPage = React . lazy (
78+ ( ) => import ( './pages/DeploymentListPage' ) ,
79+ ) ;
80+ const DeploymentLauncherPage = React . lazy (
81+ ( ) => import ( './pages/DeploymentLauncherPage' ) ,
82+ ) ;
83+ const DeploymentDetailPage = React . lazy (
84+ ( ) => import ( './pages/DeploymentDetailPage' ) ,
85+ ) ;
86+ const AdminDeploymentListPage = React . lazy (
87+ ( ) => import ( './pages/AdminDeploymentListPage' ) ,
88+ ) ;
7889const InteractiveLoginPage = React . lazy (
7990 ( ) => import ( './pages/InteractiveLoginPage' ) ,
8091) ;
@@ -111,7 +122,6 @@ const RBACManagementPage = React.lazy(
111122 ( ) => import ( './pages/RBACManagementPage' ) ,
112123) ;
113124const AdminSessionPage = React . lazy ( ( ) => import ( './pages/AdminSessionPage' ) ) ;
114- const AdminServingPage = React . lazy ( ( ) => import ( './pages/AdminServingPage' ) ) ;
115125const AdminVFolderNodeListPage = React . lazy (
116126 ( ) => import ( './pages/AdminVFolderNodeListPage' ) ,
117127) ;
@@ -255,8 +265,9 @@ export const mainLayoutChildRoutes: RouteObject[] = [
255265 ] ,
256266 } ,
257267 {
258- path : '/serving' ,
259-
268+ // FR-2664 — New Deployment UI routes. Replaces the legacy /serving
269+ // routes (see fallback redirects below).
270+ path : '/deployments' ,
260271 handle : { labelKey : 'webui.menu.Serving' } ,
261272 children : [
262273 {
@@ -268,19 +279,79 @@ export const mainLayoutChildRoutes: RouteObject[] = [
268279 < Suspense
269280 fallback = { < BAICard title = { t ( 'webui.menu.Serving' ) } loading /> }
270281 >
271- < ServingPage />
282+ < DeploymentListPage />
272283 </ Suspense >
273284 ) ;
274285 } ,
275286 } ,
276287 {
277- path : '/serving/:serviceId' ,
288+ path : 'new' ,
289+ handle : { labelKey : 'modelService.StartNewService' } ,
278290 element : (
279- < Suspense fallback = { < Skeleton active /> } >
280- < EndpointDetailPage />
291+ < Suspense
292+ fallback = {
293+ < BAIFlex direction = "column" style = { { maxWidth : 700 } } >
294+ < Skeleton active />
295+ </ BAIFlex >
296+ }
297+ >
298+ < DeploymentLauncherPage />
281299 </ Suspense >
282300 ) ,
301+ } ,
302+ {
303+ path : ':deploymentId' ,
283304 handle : { labelKey : 'modelService.RoutingInfo' } ,
305+ element : (
306+ < Suspense fallback = { < Skeleton active /> } >
307+ < DeploymentDetailPage />
308+ </ Suspense >
309+ ) ,
310+ } ,
311+ {
312+ path : ':deploymentId/edit' ,
313+ handle : { labelKey : 'modelService.UpdateService' } ,
314+ element : (
315+ < Suspense
316+ fallback = {
317+ < BAIFlex direction = "column" style = { { maxWidth : 700 } } >
318+ < Skeleton active />
319+ </ BAIFlex >
320+ }
321+ >
322+ < DeploymentLauncherPage />
323+ </ Suspense >
324+ ) ,
325+ } ,
326+ ] ,
327+ } ,
328+ {
329+ // FR-2664 — Legacy /serving fallback. Transient redirect; remove once
330+ // all internal links + external references have been migrated.
331+ path : '/serving' ,
332+ handle : { labelKey : 'webui.menu.Serving' } ,
333+ children : [
334+ {
335+ path : '' ,
336+ Component : ( ) => {
337+ const location = useLocation ( ) ;
338+ return (
339+ < WebUINavigate to = { '/deployments' + location . search } replace />
340+ ) ;
341+ } ,
342+ } ,
343+ {
344+ path : ':serviceId' ,
345+ Component : ( ) => {
346+ const { serviceId } = useParams < { serviceId : string } > ( ) ;
347+ const location = useLocation ( ) ;
348+ return (
349+ < WebUINavigate
350+ to = { `/deployments/${ serviceId } ${ location . search } ` }
351+ replace
352+ />
353+ ) ;
354+ } ,
284355 } ,
285356 ] ,
286357 } ,
@@ -290,7 +361,7 @@ export const mainLayoutChildRoutes: RouteObject[] = [
290361 children : [
291362 {
292363 path : '' ,
293- element : < WebUINavigate to = "/serving " replace /> ,
364+ element : < WebUINavigate to = "/deployments " replace /> ,
294365 } ,
295366 {
296367 path : 'start' ,
@@ -322,6 +393,34 @@ export const mainLayoutChildRoutes: RouteObject[] = [
322393 </ Suspense >
323394 ) ,
324395 } ,
396+ {
397+ // FR-2664 — Legacy fallback: /service/:endpointId → /deployments/:deploymentId
398+ path : ':endpointId' ,
399+ Component : ( ) => {
400+ const { endpointId } = useParams < { endpointId : string } > ( ) ;
401+ const location = useLocation ( ) ;
402+ return (
403+ < WebUINavigate
404+ to = { `/deployments/${ endpointId } ${ location . search } ` }
405+ replace
406+ />
407+ ) ;
408+ } ,
409+ } ,
410+ {
411+ // FR-2664 — Legacy fallback: /service/:endpointId/edit → /deployments/:deploymentId/edit
412+ path : ':endpointId/edit' ,
413+ Component : ( ) => {
414+ const { endpointId } = useParams < { endpointId : string } > ( ) ;
415+ const location = useLocation ( ) ;
416+ return (
417+ < WebUINavigate
418+ to = { `/deployments/${ endpointId } /edit${ location . search } ` }
419+ replace
420+ />
421+ ) ;
422+ } ,
423+ } ,
325424 ] ,
326425 } ,
327426 {
@@ -409,32 +508,56 @@ export const mainLayoutChildRoutes: RouteObject[] = [
409508 ) ,
410509 } ,
411510 {
511+ // FR-2664 — New admin deployment list route. Replaces the legacy
512+ // /admin-serving route (see fallback redirect below).
513+ path : '/admin-deployments' ,
514+ handle : { labelKey : 'webui.menu.Serving' } ,
515+ Component : ( ) => {
516+ const { t } = useTranslation ( ) ;
517+ return (
518+ < BAIErrorBoundary >
519+ < Suspense
520+ fallback = { < BAICard title = { t ( 'webui.menu.Serving' ) } loading /> }
521+ >
522+ < AdminDeploymentListPage />
523+ </ Suspense >
524+ </ BAIErrorBoundary >
525+ ) ;
526+ } ,
527+ } ,
528+ {
529+ // FR-2664 — Legacy /admin-serving fallback. Transient redirect; remove
530+ // once all internal links + external references have been migrated.
412531 path : '/admin-serving' ,
413532 handle : { labelKey : 'webui.menu.Serving' } ,
414533 children : [
415534 {
416535 index : true ,
417536 Component : ( ) => {
418- const { t } = useTranslation ( ) ;
537+ const location = useLocation ( ) ;
419538 return (
420- < BAIErrorBoundary >
421- < Suspense
422- fallback = { < BAICard title = { t ( 'webui.menu.Serving' ) } loading /> }
423- >
424- < AdminServingPage />
425- </ Suspense >
426- </ BAIErrorBoundary >
539+ < WebUINavigate
540+ to = { '/admin-deployments' + location . search }
541+ replace
542+ />
427543 ) ;
428544 } ,
429545 } ,
430546 {
547+ // /admin-deployments has no nested detail route — the deployment
548+ // detail page is shared at /deployments/:deploymentId regardless
549+ // of the viewer's role.
431550 path : ':serviceId' ,
432- element : (
433- < Suspense fallback = { < Skeleton active /> } >
434- < EndpointDetailPage />
435- </ Suspense >
436- ) ,
437- handle : { labelKey : 'modelService.RoutingInfo' } ,
551+ Component : ( ) => {
552+ const { serviceId } = useParams < { serviceId : string } > ( ) ;
553+ const location = useLocation ( ) ;
554+ return (
555+ < WebUINavigate
556+ to = { `/deployments/${ serviceId } ${ location . search } ` }
557+ replace
558+ />
559+ ) ;
560+ } ,
438561 } ,
439562 ] ,
440563 } ,
0 commit comments