Skip to content

Commit 4d45eba

Browse files
committed
feat(FR-2679): add TODO(needs-backend) comment for BA-5853 blocking token creation
1 parent a76920c commit 4d45eba

6 files changed

Lines changed: 44 additions & 162 deletions

react/src/components/DeploymentAccessTokensTab.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ const DeploymentAccessTokensTab: React.FC<DeploymentAccessTokensTabProps> = ({
9494
listData?.accessTokens?.edges?.map((edge) => edge?.node),
9595
);
9696

97+
// TODO(needs-backend): BA-5853 — createAccessToken mutation fails with a
98+
// Pydantic validation error ("deployment_id Field required"). The frontend
99+
// sends `modelDeploymentId` per the supergraph schema but the backend
100+
// resolver expects `deployment_id`. Token creation is disabled until fixed.
97101
const commitCreateMutation =
98102
useMutationWithPromise<DeploymentAccessTokensTabCreateMutation>(graphql`
99103
mutation DeploymentAccessTokensTabCreateMutation(

react/src/components/DeploymentConfigurationSection.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import { DeploymentConfigurationSectionQuery } from '../__generated__/DeploymentConfigurationSectionQuery.graphql';
66
import { DeploymentConfigurationSection_deployment$key } from '../__generated__/DeploymentConfigurationSection_deployment.graphql';
77
import { useWebUINavigate } from '../hooks';
8+
import ImageNodeSimpleTag from './ImageNodeSimpleTag';
89
import { CheckOutlined, CloseOutlined, EditOutlined } from '@ant-design/icons';
910
import { Descriptions, Tag, Typography, theme } from 'antd';
1011
import { DescriptionsItemType } from 'antd/es/descriptions';
@@ -81,7 +82,9 @@ const DeploymentConfigurationSection: React.FC<
8182
resourceGroupName
8283
}
8384
modelRuntimeConfig {
84-
runtimeVariant
85+
runtimeVariant {
86+
name
87+
}
8588
environ {
8689
entries {
8790
name
@@ -104,6 +107,9 @@ const DeploymentConfigurationSection: React.FC<
104107
canonicalName
105108
}
106109
}
110+
image {
111+
...ImageNodeSimpleTagFragment
112+
}
107113
}
108114
}
109115
}
@@ -183,13 +189,16 @@ const DeploymentConfigurationSection: React.FC<
183189
{
184190
key: 'runtime-variant',
185191
label: t('deployment.RuntimeVariant'),
186-
children: runtimeConfig?.runtimeVariant || renderFallback(),
192+
children: runtimeConfig?.runtimeVariant?.name || renderFallback(),
187193
},
188194
{
189195
key: 'image',
190196
label: t('deployment.Image'),
191-
children:
192-
currentRevision?.imageV2?.identity?.canonicalName || renderFallback(),
197+
children: currentRevision?.image ? (
198+
<ImageNodeSimpleTag imageFrgmt={currentRevision.image} />
199+
) : (
200+
renderFallback()
201+
),
193202
},
194203
{
195204
key: 'cluster-mode',

react/src/components/DeploymentLauncherPageContent.tsx

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@
44
*/
55
import { DeploymentLauncherPageContentPresetSummaryQuery } from '../__generated__/DeploymentLauncherPageContentPresetSummaryQuery.graphql';
66
import { DeploymentLauncherPageContent_deployment$key } from '../__generated__/DeploymentLauncherPageContent_deployment.graphql';
7-
import { useBaiSignedRequestWithPromise } from '../helper';
87
import { parseCliCommand } from '../helper/parseCliCommand';
9-
import { useSuspendedBackendaiClient } from '../hooks';
108
import { ResourceSlotName, useResourceSlots } from '../hooks/backendai';
11-
import { useSuspenseTanQuery } from '../hooks/reactQueryAlias';
129
import { useBAISettingUserState } from '../hooks/useBAISetting';
1310
import { useCurrentProjectValue } from '../hooks/useCurrentProject';
1411
import {
@@ -140,6 +137,8 @@ export interface DeploymentLauncherPageContentProps {
140137
* Provides the deployment snapshot used to pre-fill the form.
141138
*/
142139
deploymentFrgmt?: DeploymentLauncherPageContent_deployment$key | null;
140+
/** Available runtime variants fetched by the parent page layout. */
141+
runtimeVariants?: ReadonlyArray<{ name: string; rowId: string }>;
143142
/**
144143
* Optional change observer forwarded to the underlying antd `<Form>`.
145144
* Useful for parent pages that want to persist the draft state
@@ -212,6 +211,7 @@ const DeploymentLauncherPageContent: React.FC<
212211
mode,
213212
form,
214213
deploymentFrgmt,
214+
runtimeVariants = [],
215215
onValuesChange,
216216
onCancel,
217217
onSubmit,
@@ -222,20 +222,6 @@ const DeploymentLauncherPageContent: React.FC<
222222
const { t } = useTranslation();
223223
const { token } = theme.useToken();
224224
const screens = Grid.useBreakpoint();
225-
const baiClient = useSuspendedBackendaiClient();
226-
const baiRequestWithPromise = useBaiSignedRequestWithPromise();
227-
228-
// Fetch available runtime variants from the model-service runtimes endpoint.
229-
// Falls back to an empty list so the Select renders without crashing.
230-
const { data: availableRuntimes } = useSuspenseTanQuery<{
231-
runtimes: { name: string; human_readable_name: string }[];
232-
}>({
233-
queryKey: ['DeploymentLauncher.runtime.list'],
234-
queryFn: () =>
235-
baiRequestWithPromise({ method: 'GET', url: `/services/_/runtimes` }),
236-
staleTime: 60_000,
237-
});
238-
239225
// Debounced CLI command parser — auto-fills port/health/mount from the
240226
// pasted command, mirroring ServiceLauncherPageContent behaviour.
241227
const { run: parseCommandWithDebounce } = useDebounceFn(
@@ -250,8 +236,6 @@ const DeploymentLauncherPageContent: React.FC<
250236
{ wait: 400 },
251237
);
252238

253-
void baiClient; // used only for feature-flag checks in future wiring
254-
255239
const currentProject = useCurrentProjectValue();
256240

257241
// Refs for runtime parameter UI values. Kept outside form state so that
@@ -491,10 +475,10 @@ const DeploymentLauncherPageContent: React.FC<
491475
{ title: t('deployment.step.ReviewAndCreate') },
492476
];
493477

494-
const runtimeVariantOptions = _.map(
495-
availableRuntimes?.runtimes ?? [],
496-
(rt) => ({ value: rt.name, label: rt.human_readable_name }),
497-
);
478+
const runtimeVariantOptions = _.map(runtimeVariants, (rt) => ({
479+
value: rt.name,
480+
label: rt.name,
481+
}));
498482

499483
return (
500484
<BAIFlex direction="row" gap="md" align="start" style={{ width: '100%' }}>

react/src/components/DeploymentReplicasTab.tsx

Lines changed: 9 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import { convertToOrderBy } from '../helper';
1111
import { useBAISettingUserState } from '../hooks/useBAISetting';
1212
import ReplicaStatusTag, { ReplicaStatus } from './ReplicaStatusTag';
1313
import SessionDetailDrawer from './SessionDetailDrawer';
14-
import { Descriptions, Drawer, Tag, Typography } from 'antd';
15-
import { DescriptionsItemType } from 'antd/es/descriptions';
14+
import { Tag, Typography } from 'antd';
1615
import {
1716
BAIColumnType,
1817
BAIFetchKeyButton,
@@ -24,7 +23,6 @@ import {
2423
BAIUnmountAfterClose,
2524
type GraphQLFilter,
2625
filterOutEmpty,
27-
toLocalId,
2826
} from 'backend.ai-ui';
2927
import dayjs from 'dayjs';
3028
import * as _ from 'lodash-es';
@@ -88,7 +86,6 @@ const DeploymentReplicasTab: React.FC<DeploymentReplicasTabProps> = ({
8886
current: parseAsInteger.withDefault(1),
8987
pageSize: parseAsInteger.withDefault(10),
9088
order: parseAsStringLiteral(availableReplicaSorterValues),
91-
selected: parseAsString,
9289
rFilter: parseAsString,
9390
},
9491
{
@@ -97,18 +94,15 @@ const DeploymentReplicasTab: React.FC<DeploymentReplicasTabProps> = ({
9794
current: 'rCurrent',
9895
pageSize: 'rPageSize',
9996
order: 'rOrder',
100-
selected: 'rSelected',
10197
rFilter: 'rFilter',
10298
},
10399
},
104100
);
105101

106-
const deployment = useFragment(
102+
useFragment(
107103
graphql`
108104
fragment DeploymentReplicasTab_deployment on ModelDeployment {
109-
networkAccess {
110-
endpointUrl
111-
}
105+
id
112106
}
113107
`,
114108
deploymentFrgmt,
@@ -198,10 +192,6 @@ const DeploymentReplicasTab: React.FC<DeploymentReplicasTabProps> = ({
198192

199193
type ReplicaNode = (typeof replicas)[number];
200194

201-
const selectedReplica = replicas.find(
202-
(replica) => replica.id === queryParams.selected,
203-
);
204-
205195
const doRefetch = (overrides?: {
206196
filter?: ReturnType<typeof parseReplicaFilter>;
207197
orderBy?: ReturnType<typeof convertToOrderBy<ReplicaOrderBy>>;
@@ -240,13 +230,7 @@ const DeploymentReplicasTab: React.FC<DeploymentReplicasTabProps> = ({
240230
title: t('deployment.ReplicaId'),
241231
dataIndex: 'id',
242232
fixed: 'left',
243-
render: (value: string, record: ReplicaNode) => (
244-
<BAINameActionCell
245-
title={toLocalId(value)}
246-
showActions="always"
247-
onTitleClick={() => setQueryParams({ selected: record.id })}
248-
/>
249-
),
233+
render: (value: string) => <BAIId globalId={value} copyable />,
250234
},
251235
{
252236
key: 'livenessStatus',
@@ -278,13 +262,17 @@ const DeploymentReplicasTab: React.FC<DeploymentReplicasTabProps> = ({
278262
render: (value) => value ?? '-',
279263
},
280264
{
265+
// TODO(needs-backend): BA-5838 — ModelReplica.sessionId returns the
266+
// replica's own route_id instead of the compute session ID. Hidden by
267+
// default until the backend fix lands so users don't see wrong data.
281268
key: 'sessionId',
282269
title: t('deployment.SessionId'),
283270
dataIndex: 'sessionId',
271+
defaultHidden: true,
284272
render: (value: string | null | undefined) =>
285273
value ? (
286274
<BAINameActionCell
287-
title={value}
275+
title={<BAIId uuid={value} />}
288276
showActions="always"
289277
onTitleClick={() => setSelectedSessionId(value)}
290278
/>
@@ -310,84 +298,6 @@ const DeploymentReplicasTab: React.FC<DeploymentReplicasTabProps> = ({
310298
},
311299
]);
312300

313-
const drawerItems: DescriptionsItemType[] = selectedReplica
314-
? filterOutEmpty([
315-
{
316-
key: 'replicaId',
317-
label: t('deployment.ReplicaId'),
318-
children: <BAIId globalId={selectedReplica.id} ellipsis={false} />,
319-
},
320-
{
321-
key: 'readinessStatus',
322-
label: t('deployment.ReadinessStatus'),
323-
children: (
324-
<Tag>
325-
{t(
326-
`replicaStatus.${readinessStatusI18nKey(
327-
selectedReplica.readinessStatus,
328-
)}`,
329-
{
330-
defaultValue: selectedReplica.readinessStatus ?? '-',
331-
},
332-
)}
333-
</Tag>
334-
),
335-
},
336-
{
337-
key: 'livenessStatus',
338-
label: t('deployment.LivenessStatus'),
339-
children: (
340-
<ReplicaStatusTag
341-
status={toReplicaTagStatus(selectedReplica.livenessStatus)}
342-
/>
343-
),
344-
},
345-
{
346-
key: 'activenessStatus',
347-
label: t('deployment.ActivenessStatus'),
348-
children: (
349-
<Tag
350-
color={
351-
selectedReplica.activenessStatus === 'ACTIVE'
352-
? 'green'
353-
: 'default'
354-
}
355-
>
356-
{selectedReplica.activenessStatus ?? '-'}
357-
</Tag>
358-
),
359-
},
360-
selectedReplica.sessionId && {
361-
key: 'sessionId',
362-
label: t('deployment.SessionId'),
363-
children: (
364-
<BAIId uuid={selectedReplica.sessionId} ellipsis={false} copyable />
365-
),
366-
},
367-
selectedReplica.revision && {
368-
key: 'revision',
369-
label: t('deployment.Revision'),
370-
children: selectedReplica.revision.name,
371-
},
372-
deployment?.networkAccess?.endpointUrl && {
373-
key: 'endpointUrl',
374-
label: t('deployment.EndpointUrl'),
375-
children: (
376-
<Typography.Text copyable>
377-
{deployment.networkAccess.endpointUrl}
378-
</Typography.Text>
379-
),
380-
},
381-
{
382-
key: 'createdAt',
383-
label: t('deployment.CreatedAt'),
384-
children: selectedReplica.createdAt
385-
? dayjs(selectedReplica.createdAt).format('lll')
386-
: '-',
387-
},
388-
])
389-
: [];
390-
391301
return (
392302
<>
393303
<BAIFlex
@@ -445,17 +355,6 @@ const DeploymentReplicasTab: React.FC<DeploymentReplicasTabProps> = ({
445355
},
446356
}}
447357
/>
448-
<Drawer
449-
title={t('deployment.ReplicaDetail')}
450-
size="large"
451-
open={!!selectedReplica}
452-
onClose={() => setQueryParams({ selected: null })}
453-
destroyOnHidden
454-
>
455-
{selectedReplica && (
456-
<Descriptions column={1} size="small" bordered items={drawerItems} />
457-
)}
458-
</Drawer>
459358
<BAIUnmountAfterClose>
460359
<SessionDetailDrawer
461360
open={!!selectedSessionId}
@@ -467,23 +366,4 @@ const DeploymentReplicasTab: React.FC<DeploymentReplicasTabProps> = ({
467366
);
468367
};
469368

470-
/**
471-
* Maps the GraphQL `ReadinessStatus` enum to the i18n key suffix registered
472-
* under `replicaStatus.*`. Defaults to `NotChecked` for unknown values so the
473-
* tag always renders something readable.
474-
*/
475-
const readinessStatusI18nKey = (
476-
readinessStatus: string | null | undefined,
477-
): string => {
478-
switch (readinessStatus) {
479-
case 'HEALTHY':
480-
return 'Healthy';
481-
case 'UNHEALTHY':
482-
return 'Unhealthy';
483-
case 'NOT_CHECKED':
484-
default:
485-
return 'NotChecked';
486-
}
487-
};
488-
489369
export default DeploymentReplicasTab;

react/src/components/DeploymentRevisionHistoryTab.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,9 @@ const DeploymentRevisionHistoryTab: React.FC<
173173
size
174174
}
175175
modelRuntimeConfig {
176-
runtimeVariant
176+
runtimeVariant {
177+
name
178+
}
177179
}
178180
modelDefinition {
179181
models {
@@ -368,7 +370,7 @@ const DeploymentRevisionHistoryTab: React.FC<
368370
key: 'runtimeVariant',
369371
dataIndex: 'runtimeVariant',
370372
render: (_value, record) =>
371-
record.modelRuntimeConfig?.runtimeVariant ?? '-',
373+
record.modelRuntimeConfig?.runtimeVariant?.name ?? '-',
372374
},
373375
{
374376
title: t('deployment.Image'),

react/src/pages/DeploymentLauncherPage.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,13 @@ const DeploymentLauncherPageLayout: React.FC<
187187
{ fetchPolicy: 'store-or-network' },
188188
);
189189

190+
const runtimeVariantList =
191+
runtimeVariants?.edges
192+
?.map((e) => e?.node)
193+
?.filter((n): n is NonNullable<typeof n> => Boolean(n)) ?? [];
194+
190195
const runtimeVariantByName = Object.fromEntries(
191-
(runtimeVariants?.edges ?? [])
192-
.map((e) => e?.node)
193-
.filter((n): n is NonNullable<typeof n> => n != null)
194-
.map((n) => [n.name, n]),
196+
runtimeVariantList.map((n) => [n.name, n]),
195197
);
196198

197199
// Track form dirtiness to guard cancel with a confirm dialog. We use
@@ -499,6 +501,7 @@ const DeploymentLauncherPageLayout: React.FC<
499501
mode={mode}
500502
form={form}
501503
deploymentFrgmt={deploymentFrgmt}
504+
runtimeVariants={runtimeVariantList}
502505
onValuesChange={() => setIsDirty(true)}
503506
onCancel={handleCancel}
504507
onSubmit={handleSubmit}

0 commit comments

Comments
 (0)