Skip to content

Commit 9a7bebf

Browse files
committed
feat(FR-2664): add /deployments + /admin-deployments routes with legacy fallbacks
1 parent b135d5d commit 9a7bebf

5 files changed

Lines changed: 213 additions & 27 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
@license
3+
Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
4+
*/
5+
import React from 'react';
6+
7+
// TODO(needs-backend): FR-2672 — Admin deployment list page.
8+
// This is a placeholder stub introduced by FR-2664 so that the new
9+
// /admin-deployments route can be wired before the real page lands in
10+
// Phase 5.
11+
const AdminDeploymentListPage: React.FC = () => {
12+
'use memo';
13+
return <div>TODO: AdminDeploymentListPage — FR-2672</div>;
14+
};
15+
16+
export default AdminDeploymentListPage;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
@license
3+
Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
4+
*/
5+
import React from 'react';
6+
7+
// TODO(needs-backend): FR-2681 — Deployment detail page.
8+
// This is a placeholder stub introduced by FR-2664 so that the new
9+
// /deployments/:deploymentId route can be wired before the real page
10+
// lands in Phase 4.
11+
const DeploymentDetailPage: React.FC = () => {
12+
'use memo';
13+
return <div>TODO: DeploymentDetailPage — FR-2681</div>;
14+
};
15+
16+
export default DeploymentDetailPage;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
@license
3+
Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
4+
*/
5+
import React from 'react';
6+
7+
// TODO(needs-backend): FR-2675 — Deployment launcher page (create + edit).
8+
// This is a placeholder stub introduced by FR-2664 so that the new
9+
// /deployments/new and /deployments/:deploymentId/edit routes can be
10+
// wired before the real page lands in Phase 3.
11+
const DeploymentLauncherPage: React.FC = () => {
12+
'use memo';
13+
return <div>TODO: DeploymentLauncherPage — FR-2675</div>;
14+
};
15+
16+
export default DeploymentLauncherPage;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
@license
3+
Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
4+
*/
5+
import React from 'react';
6+
7+
// TODO(needs-backend): FR-2671 — Deployment list page (user view).
8+
// This is a placeholder stub introduced by FR-2664 so that the new
9+
// /deployments route can be wired before the real page lands in Phase 3.
10+
const DeploymentListPage: React.FC = () => {
11+
'use memo';
12+
return <div>TODO: DeploymentListPage — FR-2671</div>;
13+
};
14+
15+
export default DeploymentListPage;

react/src/routes.tsx

Lines changed: 150 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,18 @@ import { pluginApiEndpointState } from './hooks/useWebUIPluginState';
2626
import ComputeSessionListPage from './pages/ComputeSessionListPage';
2727
import LegacyModelStoreListPage from './pages/LegacyModelStoreListPage';
2828
import Page404 from './pages/Page404';
29-
import ServingPage from './pages/ServingPage';
3029
import VFolderNodeListPage from './pages/VFolderNodeListPage';
3130
import { Skeleton, theme } from 'antd';
3231
import { BAIFlex, BAICard } from 'backend.ai-ui';
3332
import { useSetAtom } from 'jotai';
3433
import { parseAsString, useQueryStates } from 'nuqs';
3534
import React, { Suspense } from 'react';
3635
import { useTranslation } from 'react-i18next';
37-
import { RouteObject, useLocation } from 'react-router-dom';
36+
import { RouteObject, useLocation, useParams } from 'react-router-dom';
3837

3938
const LoginViewLazy = React.lazy(() => import('./components/LoginView'));
4039

4140
const Information = React.lazy(() => import('./components/Information'));
42-
const EndpointDetailPage = React.lazy(
43-
() => import('./pages/EndpointDetailPage'),
44-
);
4541
const StartPage = React.lazy(() => import('./pages/StartPage'));
4642
const DashboardPage = React.lazy(() => import('./pages/DashboardPage'));
4743
const AdminDashboardPage = React.lazy(
@@ -75,6 +71,21 @@ const ServiceLauncherCreatePage = React.lazy(
7571
const 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+
);
7889
const InteractiveLoginPage = React.lazy(
7990
() => import('./pages/InteractiveLoginPage'),
8091
);
@@ -111,7 +122,6 @@ const RBACManagementPage = React.lazy(
111122
() => import('./pages/RBACManagementPage'),
112123
);
113124
const AdminSessionPage = React.lazy(() => import('./pages/AdminSessionPage'));
114-
const AdminServingPage = React.lazy(() => import('./pages/AdminServingPage'));
115125
const 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

Comments
 (0)