diff --git a/src/locales/en-US/menu.ts b/src/locales/en-US/menu.ts index 622f1373..2b1d8e7c 100644 --- a/src/locales/en-US/menu.ts +++ b/src/locales/en-US/menu.ts @@ -8,7 +8,7 @@ export default { 'menu.playground.text2images': 'Image', 'menu.playground.video': 'Video', 'menu.compare': 'Compare', - 'menu.models': 'Models', + 'menu.models': 'Model Service', 'menu.models.modelList': 'Deploy & Manage', 'menu.models.modelCatalog': 'Catalog', 'menu.models.catalog': 'Model Catalog', diff --git a/src/locales/ja-JP/menu.ts b/src/locales/ja-JP/menu.ts index 1298dc0c..981c50da 100644 --- a/src/locales/ja-JP/menu.ts +++ b/src/locales/ja-JP/menu.ts @@ -8,7 +8,7 @@ export default { 'menu.playground.text2images': '画像生成', 'menu.playground.video': '動画', 'menu.compare': '比較', - 'menu.models': 'モデル', + 'menu.models': 'モデルサービス', 'menu.models.modelList': 'デプロイと管理', 'menu.models.modelCatalog': 'カタログ', 'menu.models.catalog': 'モデルカタログ', diff --git a/src/locales/ru-RU/menu.ts b/src/locales/ru-RU/menu.ts index b6fbb72e..92da486e 100644 --- a/src/locales/ru-RU/menu.ts +++ b/src/locales/ru-RU/menu.ts @@ -8,7 +8,7 @@ export default { 'menu.playground.text2images': 'Генерация изображений', 'menu.playground.video': 'Видео', 'menu.compare': 'Сравнение', - 'menu.models': 'Модели', + 'menu.models': 'Сервисы моделей', 'menu.models.modelList': 'Развертывание и управление', 'menu.models.modelCatalog': 'Каталог', 'menu.models.catalog': 'Каталог моделей', diff --git a/src/locales/tr-TR/menu.ts b/src/locales/tr-TR/menu.ts index fb182e1c..9a1e99dd 100644 --- a/src/locales/tr-TR/menu.ts +++ b/src/locales/tr-TR/menu.ts @@ -8,7 +8,7 @@ export default { 'menu.playground.text2images': 'Görsel', 'menu.playground.video': 'Video', 'menu.compare': 'Karşılaştır', - 'menu.models': 'Modeller', + 'menu.models': 'Model Hizmetleri', 'menu.models.modelList': 'Dağıt ve Yönet', 'menu.models.modelCatalog': 'Katalog', 'menu.models.catalog': 'Model Kataloğu', diff --git a/src/locales/zh-CN/menu.ts b/src/locales/zh-CN/menu.ts index 800992b2..91c73333 100644 --- a/src/locales/zh-CN/menu.ts +++ b/src/locales/zh-CN/menu.ts @@ -8,7 +8,7 @@ export default { 'menu.playground.text2images': '图像', 'menu.playground.video': '视频', 'menu.compare': '多模型对比', - 'menu.models': '模型', + 'menu.models': '模型服务', 'menu.models.modelList': '部署与管理', 'menu.models.modelCatalog': '模型库', 'menu.models.deployment': '部署', diff --git a/src/pages/cluster-management/hooks/use-cluster-columns.tsx b/src/pages/cluster-management/hooks/use-cluster-columns.tsx index c2bbd4ea..91ea494c 100644 --- a/src/pages/cluster-management/hooks/use-cluster-columns.tsx +++ b/src/pages/cluster-management/hooks/use-cluster-columns.tsx @@ -86,8 +86,8 @@ const useClusterColumns = ( // `clusterDetail.linkableName`. Without a plugin we render the // name as plain text (matches the pre-restore behaviour); with one // we use Typography.Link wired to the parent's `onCellClick`. - const nameLinkable: boolean = !!getGPUStackPlugin()?.clusterDetail - ?.linkableName; + const nameLinkable: boolean = + !!getGPUStackPlugin()?.clusterDetail?.linkableName; const setActionsItems = (row: ClusterListItem) => { return clusterActionList.filter((item) => { @@ -112,9 +112,7 @@ const useClusterColumns = ( <> {nameLinkable ? ( - onCellClick?.(record, 'name')} - > + onCellClick?.(record, 'name')}> {record.name} ) : ( diff --git a/src/pages/gpu-service/instances/components/instance-type-item.tsx b/src/pages/gpu-service/instances/components/instance-type-item.tsx index 61996ddd..f5c6061e 100644 --- a/src/pages/gpu-service/instances/components/instance-type-item.tsx +++ b/src/pages/gpu-service/instances/components/instance-type-item.tsx @@ -83,13 +83,11 @@ const InstanceTypeItem: React.FC = ({ item }) => { const specData = item.spec || {}; const acceleratable = specData.acceleratable; - const manufacturerKey = specData.manufacturer || (acceleratable ? '' : 'cpu'); - const manufacturer = manufacturerKey?.toUpperCase(); - const manufacturerColor = - (manufacturerKey && manufactureColorMap[manufacturerKey]) ?? 'purple'; + const manufacturer = acceleratable ? specData.manufacturer || '' : 'cpu'; + const manufacturerColor = manufactureColorMap[manufacturer] ?? 'purple'; - // resource remaining status - const remainingData = item.status?.remaining || {}; + // resource once-max-request status + const onceMaxRequestData = item.status?.onceMaxRequest || {}; const renderName = () => { const displayName = specData.acceleratable @@ -113,7 +111,7 @@ const InstanceTypeItem: React.FC = ({ item }) => { }} > - {manufacturer} + {manufacturer?.toUpperCase()} )} @@ -157,14 +155,14 @@ const InstanceTypeItem: React.FC = ({ item }) => { showDot={false} icon="icon-ram-02" label={intl.formatMessage({ id: 'gpuservice.instance.ram' })} - value={toDisplayUnit(convertKiToGi(remainingData.ram)) ?? '-'} + value={toDisplayUnit(convertKiToGi(onceMaxRequestData.ram)) ?? '-'} > diff --git a/src/pages/gpu-service/instances/config/index.ts b/src/pages/gpu-service/instances/config/index.ts index 399ed900..25696984 100644 --- a/src/pages/gpu-service/instances/config/index.ts +++ b/src/pages/gpu-service/instances/config/index.ts @@ -183,20 +183,20 @@ const parseQuantity = (value?: string | null): number => { }; // Returns the slider max for the accelerator count: the largest -// tier.onceMaxRequest across all acceleratorTiers (not from candidates). +// tier.onceMaxRequest.accelerator across all acceleratorTiers (not from candidates). export const getAcceleratorMax = ( - tiers?: { onceMaxRequest: string }[] | null + tiers?: { onceMaxRequest: { accelerator?: string } }[] | null ) => { if (!tiers?.length) return 0; return tiers.reduce((acc, tier) => { - const n = parseQuantity(tier.onceMaxRequest); + const n = parseQuantity(tier.onceMaxRequest?.accelerator); return n > acc ? n : acc; }, 0); }; // Picks the candidate (cluster + type name) that should fulfill a requested // accelerator count: the first candidate of the smallest tier whose -// onceMaxRequest is >= the requested count and whose cpu/ram/localStorage +// onceMaxRequest.accelerator is >= the requested count and whose cpu/ram/localStorage // remaining are all > 0. export const pickCandidateForAccelerator = < C extends { @@ -208,7 +208,10 @@ export const pickCandidateForAccelerator = < } >( tiers: - | { onceMaxRequest: string; candidates?: C[] | null }[] + | { + onceMaxRequest: { accelerator?: string }; + candidates?: C[] | null; + }[] | undefined | null, count: number @@ -221,12 +224,14 @@ export const pickCandidateForAccelerator = < parseQuantity(c.localStorage?.remaining) > 0; const sorted = [...tiers].sort( - (a, b) => parseQuantity(a.onceMaxRequest) - parseQuantity(b.onceMaxRequest) + (a, b) => + parseQuantity(a.onceMaxRequest?.accelerator) - + parseQuantity(b.onceMaxRequest?.accelerator) ); - // count === 0 ? parseQuantity(tier.onceMaxRequest) > count; this is CPU-only case. + // count === 0 ? parseQuantity(tier.onceMaxRequest.accelerator) > count; this is CPU-only case. for (const tier of sorted) { - const fits = parseQuantity(tier.onceMaxRequest) >= count; + const fits = parseQuantity(tier.onceMaxRequest?.accelerator) >= count; if (!fits) continue; const candidate = tier.candidates?.find(hasResources); if (candidate) return candidate; diff --git a/src/pages/gpu-service/instances/config/types.ts b/src/pages/gpu-service/instances/config/types.ts index e88988a9..ab2c4308 100644 --- a/src/pages/gpu-service/instances/config/types.ts +++ b/src/pages/gpu-service/instances/config/types.ts @@ -28,9 +28,6 @@ export interface FormData { cpu?: string; ram?: string; localStorage?: string; - // Stored in the form as a number so NumberSelection's strict - // equality picks up the active item. Serialized to a string at the - // API boundary in handleFinish. accelerator?: number | string; }; volume: { @@ -101,12 +98,19 @@ export interface InstanceTypeCandidate { localStorage: InstanceTypeResource; } +export interface InstanceTypeTierOnceMaxRequestResource { + accelerator?: string; + cpu: string; + ram: string; + localStorage: string; +} + export interface InstanceTypeTier { - onceMaxRequest: string; + onceMaxRequest: InstanceTypeTierOnceMaxRequestResource; candidates?: InstanceTypeCandidate[] | null; } -export interface InstanceTypeRemainingResource { +export interface InstanceTypeOnceMaxRequestResource { accelerator?: string | null; cpu: string; ram: string; @@ -125,7 +129,7 @@ export interface InstanceTypeSpec { } export interface InstanceTypeStatus { - remaining: InstanceTypeRemainingResource; + onceMaxRequest: InstanceTypeOnceMaxRequestResource; acceleratorTiers?: InstanceTypeTier[] | null; } @@ -137,11 +141,6 @@ export interface InstanceTypeItem { status: InstanceTypeStatus; } -// =========== Events / logs (placeholder) =========== -// The /v2/gpu-instances API does not yet expose log/event endpoints. These -// shapes are retained as minimal placeholders so disabled UI continues to -// compile until backend support lands. - export interface InstanceEventItem { type?: string; reason?: string; diff --git a/src/pages/gpu-service/instances/forms/index.tsx b/src/pages/gpu-service/instances/forms/index.tsx index b972954a..bb83dcb7 100644 --- a/src/pages/gpu-service/instances/forms/index.tsx +++ b/src/pages/gpu-service/instances/forms/index.tsx @@ -25,7 +25,6 @@ import { useState } from 'react'; import { FormData as PublicKeyFormData } from '../../public-keys/config/types'; -import useCreateSshkey from '../../public-keys/services/use-create-sshkey'; import useQuerySshkeys from '../../public-keys/services/use-query-sshkeys'; import { DefaultImagePullPolicy } from '../../templates/config'; import TemplateBasicForm, { @@ -109,7 +108,11 @@ const requiredFields = { }, [TABKeysMap.STORAGE]: { sort: 4, - fields: ['spec.volume.persistent.name', 'spec.volume.ephemeral.capacity'] + fields: [ + 'spec.volume.persistent.name', + 'spec.volume.ephemeral.capacity', + 'spec.sshPublicKeys' + ] } }; @@ -132,7 +135,6 @@ const GPUServiceInstanceForm: React.FC = forwardRef( realAction === PageAction.CREATE ? PageAction.CREATE : action; const sshEnabled = Form.useWatch('enable_ssh', form); const { sshkeyOptions, fetchData: fetchSSHData } = useQuerySshkeys(); - const { fetchData: createSshkey } = useCreateSshkey(); const [sshOverlayOpen, setSshOverlayOpen] = useState(false); const { getScrollElementScrollableHeight } = useWrapperContext(); const {