diff --git a/packages/backend.ai-ui/src/components/fragments/BAIModelDeploymentNodes.tsx b/packages/backend.ai-ui/src/components/fragments/BAIModelDeploymentNodes.tsx new file mode 100644 index 0000000000..71c001c772 --- /dev/null +++ b/packages/backend.ai-ui/src/components/fragments/BAIModelDeploymentNodes.tsx @@ -0,0 +1,349 @@ +import { + BAIModelDeploymentNodesFragment$data, + BAIModelDeploymentNodesFragment$key, +} from '../../__generated__/BAIModelDeploymentNodesFragment.graphql'; +import { + SemanticColor, + filterOutEmpty, + filterOutNullAndUndefined, + toLocalId, + useSemanticColorMap, +} from '../../helper'; +import BAITag from '../BAITag'; +import BAIText from '../BAIText'; +import BooleanTag from '../BooleanTag'; +import { + BAIColumnType, + BAIColumnsType, + BAINameActionCell, + BAINameActionCellProps, + BAITable, + BAITableProps, +} from '../Table'; +import dayjs from 'dayjs'; +import * as _ from 'lodash-es'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { graphql, useFragment } from 'react-relay'; + +export type ModelDeploymentNodeInList = NonNullable< + BAIModelDeploymentNodesFragment$data[number] +>; + +export type BAIModelDeploymentNodesNameColumnActionProps = + | BAINameActionCellProps + | (( + value: any, + record: ModelDeploymentNodeInList, + index: number, + ) => BAINameActionCellProps); + +const availableDeploymentSorterKeys = [ + 'name', + 'createdAt', + 'updatedAt', +] as const; + +export const availableDeploymentSorterValues = [ + ...availableDeploymentSorterKeys, + ...availableDeploymentSorterKeys.map((key) => `-${key}` as const), +] as const; + +const isEnableSorter = (key: string) => { + return _.includes(availableDeploymentSorterKeys, key); +}; + +const deploymentStatusSemanticMap: Record = { + PENDING: 'info', + SCALING: 'info', + DEPLOYING: 'info', + READY: 'success', + STOPPING: 'warning', + STOPPED: 'default', + DESTROYING: 'warning', + DESTROYED: 'default', +}; + +export interface BAIModelDeploymentNodesProps extends Omit< + BAITableProps, + 'dataSource' | 'columns' | 'onChangeOrder' +> { + deploymentsFrgmt: BAIModelDeploymentNodesFragment$key; + customizeColumns?: ( + baseColumns: BAIColumnsType, + ) => BAIColumnsType; + disableSorter?: boolean; + onChangeOrder?: ( + order: (typeof availableDeploymentSorterValues)[number] | null, + ) => void; + /** + * Props forwarded to the `BAINameActionCell` used in the `name` column. + * Accepts either a static object or a function receiving the column + * render arguments `(value, record, index)` and returning props. + */ + nameColumnActionProps?: BAIModelDeploymentNodesNameColumnActionProps; +} + +const BAIModelDeploymentNodes: React.FC = ({ + deploymentsFrgmt, + customizeColumns, + disableSorter, + onChangeOrder, + nameColumnActionProps, + ...tableProps +}) => { + 'use memo'; + const { t } = useTranslation(); + const semanticColorMap = useSemanticColorMap(); + + const deployments = useFragment( + graphql` + fragment BAIModelDeploymentNodesFragment on ModelDeployment + @relay(plural: true) { + id + currentRevisionId + metadata { + projectId + domainName + name + status + tags + createdAt + updatedAt + } + networkAccess { + endpointUrl + preferredDomainName + openToPublic + } + defaultDeploymentStrategy { + type + } + replicaState { + desiredReplicaCount + } + # creator { + # id + # basicInfo { + # email + # } + # } + } + `, + deploymentsFrgmt, + ); + + const baseColumns = _.map( + filterOutEmpty>([ + { + key: 'name', + title: t('comp:BAIModelDeploymentNodes.Name'), + fixed: 'left', + required: true, + sorter: isEnableSorter('name'), + render: (value, record, index) => { + const resolvedProps = + typeof nameColumnActionProps === 'function' + ? nameColumnActionProps(value, record, index) + : nameColumnActionProps; + return ( + + ); + }, + }, + { + key: 'status', + title: t('comp:BAIModelDeploymentNodes.Status'), + dataIndex: ['metadata', 'status'], + render: (__, record) => { + const status = record.metadata?.status; + if (!status || status === '%future added value') { + return '-'; + } + return ( + + {status} + + ); + }, + }, + { + key: 'replicas', + title: t('comp:BAIModelDeploymentNodes.Replicas'), + render: (__, record) => { + const desired = record.replicaState?.desiredReplicaCount; + if (!_.isNumber(desired)) { + return '-'; + } + return {desired}; + }, + }, + // { + // key: 'basicInfo.email', + // title: t('comp:BAIModelDeploymentNodes.CreatedUser'), + // render: (__, record) => record.creator?.basicInfo?.email ?? '-', + // }, + { + key: 'id', + title: t('comp:BAIModelDeploymentNodes.DeploymentID'), + defaultHidden: true, + render: (__, record) => ( + + {toLocalId(record.id)} + + ), + }, + { + key: 'projectId', + title: t('comp:BAIModelDeploymentNodes.ProjectID'), + defaultHidden: true, + render: (__, record) => + record.metadata?.projectId ? ( + + {record.metadata.projectId} + + ) : ( + '-' + ), + }, + { + key: 'domainName', + title: t('comp:BAIModelDeploymentNodes.DomainName'), + defaultHidden: true, + render: (__, record) => record.metadata?.domainName ?? '-', + }, + { + key: 'tags', + title: t('comp:BAIModelDeploymentNodes.Tags'), + defaultHidden: true, + render: (__, record) => { + const tags = record.metadata?.tags ?? []; + if (_.isEmpty(tags)) { + return '-'; + } + return ( + + {tags.map((tag) => ( + + {tag} + + ))} + + ); + }, + }, + { + key: 'currentRevisionId', + title: t('comp:BAIModelDeploymentNodes.CurrentRevisionID'), + defaultHidden: true, + render: (__, record) => + record.currentRevisionId ? ( + + {record.currentRevisionId} + + ) : ( + '-' + ), + }, + { + key: 'openToPublic', + title: t('comp:BAIModelDeploymentNodes.OpenToPublic'), + defaultHidden: true, + render: (__, record) => ( + + ), + }, + { + key: 'endpointUrl', + title: t('comp:BAIModelDeploymentNodes.EndpointURL'), + defaultHidden: true, + render: (__, record) => + record.networkAccess?.endpointUrl ? ( + + {record.networkAccess.endpointUrl} + + ) : ( + '-' + ), + }, + { + key: 'preferredDomainName', + title: t('comp:BAIModelDeploymentNodes.PreferredDomainName'), + defaultHidden: true, + render: (__, record) => + record.networkAccess?.preferredDomainName ?? '-', + }, + { + key: 'strategyType', + title: t('comp:BAIModelDeploymentNodes.StrategyType'), + defaultHidden: true, + render: (__, record) => { + const type = record.defaultDeploymentStrategy?.type; + if (!type || type === '%future added value') { + return '-'; + } + return type; + }, + }, + { + key: 'updatedAt', + title: t('comp:BAIModelDeploymentNodes.UpdatedAt'), + defaultHidden: true, + sorter: isEnableSorter('updatedAt'), + render: (_, record) => + record.metadata?.updatedAt + ? dayjs(record.metadata.updatedAt).format('lll') + : '-', + }, + { + key: 'createdAt', + title: t('comp:BAIModelDeploymentNodes.CreatedAt'), + sorter: isEnableSorter('createdAt'), + defaultSortOrder: 'descend', + render: (_, record) => + record.metadata?.createdAt + ? dayjs(record.metadata.createdAt).format('lll') + : '-', + }, + ]), + (column) => { + return disableSorter ? _.omit(column, 'sorter') : column; + }, + ); + + const allColumns = customizeColumns + ? customizeColumns(baseColumns) + : baseColumns; + + return ( + + resizable + rowKey="id" + size="small" + dataSource={filterOutNullAndUndefined(deployments)} + columns={allColumns} + scroll={{ x: 'max-content' }} + onChangeOrder={(order) => { + onChangeOrder?.( + order + ? (order as (typeof availableDeploymentSorterValues)[number]) + : null, + ); + }} + {...tableProps} + /> + ); +}; + +export default BAIModelDeploymentNodes; diff --git a/packages/backend.ai-ui/src/components/fragments/index.ts b/packages/backend.ai-ui/src/components/fragments/index.ts index 42f3269bac..1d0d1e8f0e 100644 --- a/packages/backend.ai-ui/src/components/fragments/index.ts +++ b/packages/backend.ai-ui/src/components/fragments/index.ts @@ -125,6 +125,14 @@ export type { } from './BAIHuggingFaceRegistrySettingModal'; export { default as BAIRouteNodes } from './BAIRouteNodes'; export type { BAIRouteNodesProps, RouteNodeInList } from './BAIRouteNodes'; +export { + default as BAIModelDeploymentNodes, + availableDeploymentSorterValues, +} from './BAIModelDeploymentNodes'; +export type { + BAIModelDeploymentNodesProps, + ModelDeploymentNodeInList, +} from './BAIModelDeploymentNodes'; export { default as BAISchedulingHistoryNodes } from './BAISchedulingHistoryNodes'; export type { BAISchedulingHistoryNodesProps, diff --git a/packages/backend.ai-ui/src/locale/de.json b/packages/backend.ai-ui/src/locale/de.json index 287b9a5c19..d3b2347cbf 100644 --- a/packages/backend.ai-ui/src/locale/de.json +++ b/packages/backend.ai-ui/src/locale/de.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Möchten Sie das Deployment \"{{deploymentName}}\" wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.", + "CreatedAt": "Erstellt am", + "CreatedUser": "Autor", + "CurrentRevisionID": "Aktuelle Revisions-ID", + "Delete": "Löschen", + "DeleteDeployment": "Deployment löschen", + "DeploymentDeleted": "Deployment gelöscht.", + "DeploymentID": "Deployment-ID", + "DomainName": "Domain", + "EndpointURL": "Endpunkt URL", + "FailedToDeleteDeployment": "Fehler beim Löschen des Deployments.", + "Name": "Name", + "OpenToPublic": "Öffentlich", + "PreferredDomainName": "Bevorzugte Domain", + "ProjectID": "Projekt-ID", + "Replicas": "Replikate", + "Status": "Status", + "StrategyType": "Strategie", + "Tags": "Stichworte", + "UpdatedAt": "Aktualisiert am" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Die folgenden Ordner werden aktualisiert.", "ProjectResourcePolicy": "Projektressourcenrichtlinie", diff --git a/packages/backend.ai-ui/src/locale/el.json b/packages/backend.ai-ui/src/locale/el.json index d1b7f21dd0..fdfed77847 100644 --- a/packages/backend.ai-ui/src/locale/el.json +++ b/packages/backend.ai-ui/src/locale/el.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Είστε σίγουροι ότι θέλετε να διαγράψετε την ανάπτυξη \"{{deploymentName}}\"; Αυτή η ενέργεια δεν μπορεί να αναιρεθεί.", + "CreatedAt": "Δημιουργήθηκε", + "CreatedUser": "Συντάκτης", + "CurrentRevisionID": "ID Τρέχουσας Αναθεώρησης", + "Delete": "Διαγραφή", + "DeleteDeployment": "Διαγραφή Ανάπτυξης", + "DeploymentDeleted": "Η ανάπτυξη διαγράφηκε.", + "DeploymentID": "ID Ανάπτυξης", + "DomainName": "Τομέας", + "EndpointURL": "URL Τελικού Σημείου", + "FailedToDeleteDeployment": "Αποτυχία διαγραφής ανάπτυξης.", + "Name": "Όνομα", + "OpenToPublic": "Ανοιχτό στο Κοινό", + "PreferredDomainName": "Προτιμώμενος Τομέας", + "ProjectID": "ID Έργου", + "Replicas": "Αντίγραφα", + "Status": "Κατάσταση", + "StrategyType": "Στρατηγική", + "Tags": "Ετικέτες", + "UpdatedAt": "Ενημερώθηκε" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Οι ακόλουθοι φάκελοι θα ενημερωθούν.", "ProjectResourcePolicy": "Πολιτική πόρων έργου", diff --git a/packages/backend.ai-ui/src/locale/en.json b/packages/backend.ai-ui/src/locale/en.json index 561ec2a0bc..442ab79859 100644 --- a/packages/backend.ai-ui/src/locale/en.json +++ b/packages/backend.ai-ui/src/locale/en.json @@ -155,6 +155,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Are you sure you want to delete deployment \"{{deploymentName}}\"? This action cannot be undone.", + "CreatedAt": "Created At", + "CreatedUser": "Author", + "CurrentRevisionID": "Current Revision ID", + "Delete": "Delete", + "DeleteDeployment": "Delete Deployment", + "DeploymentDeleted": "Deployment deleted.", + "DeploymentID": "Deployment ID", + "DomainName": "Domain", + "EndpointURL": "Endpoint URL", + "FailedToDeleteDeployment": "Failed to delete deployment.", + "Name": "Name", + "OpenToPublic": "Open to Public", + "PreferredDomainName": "Preferred Domain", + "ProjectID": "Project ID", + "Replicas": "Replicas", + "Status": "Status", + "StrategyType": "Strategy", + "Tags": "Tags", + "UpdatedAt": "Updated At" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "The following folder(s) will be updated.", "ProjectResourcePolicy": "Project Resource Policy", diff --git a/packages/backend.ai-ui/src/locale/es.json b/packages/backend.ai-ui/src/locale/es.json index 6a9e7c1528..2f938444da 100644 --- a/packages/backend.ai-ui/src/locale/es.json +++ b/packages/backend.ai-ui/src/locale/es.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "¿Está seguro de que desea eliminar el despliegue \"{{deploymentName}}\"? Esta acción no se puede deshacer.", + "CreatedAt": "Creado en", + "CreatedUser": "Autor", + "CurrentRevisionID": "ID de revisión actual", + "Delete": "Borrar", + "DeleteDeployment": "Eliminar despliegue", + "DeploymentDeleted": "Despliegue eliminado.", + "DeploymentID": "ID de despliegue", + "DomainName": "Dominio", + "EndpointURL": "URL del punto final", + "FailedToDeleteDeployment": "Error al eliminar el despliegue.", + "Name": "Nombre", + "OpenToPublic": "Abierto al público", + "PreferredDomainName": "Dominio preferido", + "ProjectID": "ID del proyecto", + "Replicas": "Réplicas", + "Status": "Estado", + "StrategyType": "Estrategia", + "Tags": "Etiquetas", + "UpdatedAt": "Actualizado en" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Se actualizará(n) la(s) siguiente(s) carpeta(s).", "ProjectResourcePolicy": "Política de recursos del proyecto", diff --git a/packages/backend.ai-ui/src/locale/fi.json b/packages/backend.ai-ui/src/locale/fi.json index 8c4900ef4c..5a19280af1 100644 --- a/packages/backend.ai-ui/src/locale/fi.json +++ b/packages/backend.ai-ui/src/locale/fi.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Haluatko varmasti poistaa käyttöönoton \"{{deploymentName}}\"? Tätä toimintoa ei voi kumota.", + "CreatedAt": "Luotu", + "CreatedUser": "Tekijä", + "CurrentRevisionID": "Nykyinen revisiotunnus", + "Delete": "Poista", + "DeleteDeployment": "Poista käyttöönotto", + "DeploymentDeleted": "Käyttöönotto poistettu.", + "DeploymentID": "Käyttöönoton tunnus", + "DomainName": "Toimialue", + "EndpointURL": "Päätepisteen URL", + "FailedToDeleteDeployment": "Käyttöönoton poistaminen epäonnistui.", + "Name": "Nimi", + "OpenToPublic": "Avoin julkisesti", + "PreferredDomainName": "Ensisijainen toimialue", + "ProjectID": "Projektin tunnus", + "Replicas": "Kopioita", + "Status": "Tila", + "StrategyType": "Strategia", + "Tags": "Tunnisteet", + "UpdatedAt": "Päivitetty" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Seuraavat kansiot päivitetään.", "ProjectResourcePolicy": "Projektin resurssipolitiikka", diff --git a/packages/backend.ai-ui/src/locale/fr.json b/packages/backend.ai-ui/src/locale/fr.json index ee12f3e196..03f8f53987 100644 --- a/packages/backend.ai-ui/src/locale/fr.json +++ b/packages/backend.ai-ui/src/locale/fr.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Êtes-vous sûr de vouloir supprimer le déploiement \"{{deploymentName}}\" ? Cette action est irréversible.", + "CreatedAt": "Créé le", + "CreatedUser": "Auteur", + "CurrentRevisionID": "ID de révision actuel", + "Delete": "Supprimer", + "DeleteDeployment": "Supprimer le déploiement", + "DeploymentDeleted": "Déploiement supprimé.", + "DeploymentID": "ID de déploiement", + "DomainName": "Domaine", + "EndpointURL": "URL du point final", + "FailedToDeleteDeployment": "Échec de la suppression du déploiement.", + "Name": "Nom", + "OpenToPublic": "Ouvert au public", + "PreferredDomainName": "Domaine préféré", + "ProjectID": "ID du projet", + "Replicas": "Réplicas", + "Status": "Statut", + "StrategyType": "Stratégie", + "Tags": "Tags", + "UpdatedAt": "Mis à jour le" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Le(s) dossier(s) suivant(s) sera(ont) mis à jour.", "ProjectResourcePolicy": "Politique de ressources du projet", diff --git a/packages/backend.ai-ui/src/locale/id.json b/packages/backend.ai-ui/src/locale/id.json index 25bed58762..96ef2ce24b 100644 --- a/packages/backend.ai-ui/src/locale/id.json +++ b/packages/backend.ai-ui/src/locale/id.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Apakah Anda yakin ingin menghapus penerapan \"{{deploymentName}}\"? Tindakan ini tidak dapat dibatalkan.", + "CreatedAt": "Dibuat Pada", + "CreatedUser": "Penulis", + "CurrentRevisionID": "ID Revisi Saat Ini", + "Delete": "Menghapus", + "DeleteDeployment": "Hapus Penerapan", + "DeploymentDeleted": "Penerapan berhasil dihapus.", + "DeploymentID": "ID Penerapan", + "DomainName": "Domain", + "EndpointURL": "URL Titik Akhir", + "FailedToDeleteDeployment": "Gagal menghapus penerapan.", + "Name": "Nama", + "OpenToPublic": "Terbuka untuk Umum", + "PreferredDomainName": "Domain Pilihan", + "ProjectID": "ID Proyek", + "Replicas": "Replika", + "Status": "Status", + "StrategyType": "Strategi", + "Tags": "Tag", + "UpdatedAt": "Diperbarui Pada" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Folder berikut akan diperbarui.", "ProjectResourcePolicy": "Kebijakan Sumber Daya Proyek", diff --git a/packages/backend.ai-ui/src/locale/it.json b/packages/backend.ai-ui/src/locale/it.json index f0782dce57..f736a71e9e 100644 --- a/packages/backend.ai-ui/src/locale/it.json +++ b/packages/backend.ai-ui/src/locale/it.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Sei sicuro di voler eliminare il deployment \"{{deploymentName}}\"? Questa azione non può essere annullata.", + "CreatedAt": "Creato il", + "CreatedUser": "Autore", + "CurrentRevisionID": "ID revisione corrente", + "Delete": "Elimina", + "DeleteDeployment": "Elimina deployment", + "DeploymentDeleted": "Deployment eliminato.", + "DeploymentID": "ID deployment", + "DomainName": "Dominio", + "EndpointURL": "URL del punto finale", + "FailedToDeleteDeployment": "Eliminazione del deployment non riuscita.", + "Name": "Nome", + "OpenToPublic": "Aperto al pubblico", + "PreferredDomainName": "Dominio preferito", + "ProjectID": "ID progetto", + "Replicas": "Repliche", + "Status": "Stato", + "StrategyType": "Strategia", + "Tags": "Tag", + "UpdatedAt": "Aggiornato il" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "La cartella o le cartelle seguenti verranno aggiornate.", "ProjectResourcePolicy": "Politica delle risorse del progetto", diff --git a/packages/backend.ai-ui/src/locale/ja.json b/packages/backend.ai-ui/src/locale/ja.json index c456153f8c..031af9eedd 100644 --- a/packages/backend.ai-ui/src/locale/ja.json +++ b/packages/backend.ai-ui/src/locale/ja.json @@ -152,6 +152,28 @@ "Minimize": "最小化", "Restore": "復元" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "デプロイメント \"{{deploymentName}}\" を削除しますか?この操作は取り消せません。", + "CreatedAt": "作成日時", + "CreatedUser": "作成者", + "CurrentRevisionID": "現在のリビジョンID", + "Delete": "削除", + "DeleteDeployment": "デプロイメントを削除", + "DeploymentDeleted": "デプロイメントが削除されました。", + "DeploymentID": "デプロイメントID", + "DomainName": "ドメイン", + "EndpointURL": "エンドポイントURL", + "FailedToDeleteDeployment": "デプロイメントの削除に失敗しました。", + "Name": "名前", + "OpenToPublic": "公開", + "PreferredDomainName": "優先ドメイン", + "ProjectID": "プロジェクトID", + "Replicas": "レプリカ", + "Status": "状態", + "StrategyType": "戦略", + "Tags": "タグ", + "UpdatedAt": "更新日時" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "以下のフォルダーが更新されます.", "ProjectResourcePolicy": "プロジェクトのリソースポリシー", diff --git a/packages/backend.ai-ui/src/locale/ko.json b/packages/backend.ai-ui/src/locale/ko.json index 31c9427e19..f5ee4b14e3 100644 --- a/packages/backend.ai-ui/src/locale/ko.json +++ b/packages/backend.ai-ui/src/locale/ko.json @@ -155,6 +155,28 @@ "Minimize": "최소화", "Restore": "복원" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "배포 \"{{deploymentName}}\"을(를) 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", + "CreatedAt": "생성 시각", + "CreatedUser": "생성자", + "CurrentRevisionID": "현재 리비전 ID", + "Delete": "삭제", + "DeleteDeployment": "배포 삭제", + "DeploymentDeleted": "배포가 삭제되었습니다.", + "DeploymentID": "배포 ID", + "DomainName": "도메인", + "EndpointURL": "엔드포인트 URL", + "FailedToDeleteDeployment": "배포 삭제에 실패했습니다.", + "Name": "이름", + "OpenToPublic": "공개", + "PreferredDomainName": "선호 도메인", + "ProjectID": "프로젝트 ID", + "Replicas": "복제본 수", + "Status": "상태", + "StrategyType": "전략", + "Tags": "태그", + "UpdatedAt": "수정 시각" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "다음 폴더(들)이 업데이트됩니다.", "ProjectResourcePolicy": "프로젝트 리소스 정책", diff --git a/packages/backend.ai-ui/src/locale/mn.json b/packages/backend.ai-ui/src/locale/mn.json index 1ff6c3fd24..c3d6c6b921 100644 --- a/packages/backend.ai-ui/src/locale/mn.json +++ b/packages/backend.ai-ui/src/locale/mn.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "\"{{deploymentName}}\" байршуулалтыг устгахдаа итгэлтэй байна уу? Энэ үйлдлийг буцаах боломжгүй.", + "CreatedAt": "Үүсгэсэн огноо", + "CreatedUser": "Зохиогч", + "CurrentRevisionID": "Одоогийн засвариин ID", + "Delete": "Устгах", + "DeleteDeployment": "Байршуулалт устгах", + "DeploymentDeleted": "Байршуулалт устгагдлаа.", + "DeploymentID": "Байршуулалтын ID", + "DomainName": "Домайн", + "EndpointURL": "Төгсгөлийн цэгийн URL", + "FailedToDeleteDeployment": "Байршуулалт устгаж чадсангүй.", + "Name": "Нэр", + "OpenToPublic": "Нийтэд нээлттэй", + "PreferredDomainName": "Давуу домайн", + "ProjectID": "Төслийн ID", + "Replicas": "Хуулбар", + "Status": "Төлөв", + "StrategyType": "Стратеги", + "Tags": "Шошго", + "UpdatedAt": "Шинэчлэгдсэн огноо" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Дараах хавтас(ууд) шинэчлэгдэх болно.", "ProjectResourcePolicy": "Төслийн нөөцийн бодлого", diff --git a/packages/backend.ai-ui/src/locale/ms.json b/packages/backend.ai-ui/src/locale/ms.json index 7e06fb19be..9ad32d81c0 100644 --- a/packages/backend.ai-ui/src/locale/ms.json +++ b/packages/backend.ai-ui/src/locale/ms.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Adakah anda pasti mahu memadamkan penggunaan \"{{deploymentName}}\"? Tindakan ini tidak boleh dibatalkan.", + "CreatedAt": "Dicipta Pada", + "CreatedUser": "Pengarang", + "CurrentRevisionID": "ID Semakan Semasa", + "Delete": "Padam", + "DeleteDeployment": "Padam Penggunaan", + "DeploymentDeleted": "Penggunaan dipadamkan.", + "DeploymentID": "ID Penggunaan", + "DomainName": "Domain", + "EndpointURL": "URL Titik Akhir", + "FailedToDeleteDeployment": "Gagal memadamkan penggunaan.", + "Name": "Nama", + "OpenToPublic": "Terbuka untuk Awam", + "PreferredDomainName": "Domain Pilihan", + "ProjectID": "ID Projek", + "Replicas": "Replika", + "Status": "Status", + "StrategyType": "Strategi", + "Tags": "Tag", + "UpdatedAt": "Dikemas kini Pada" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Folder berikut akan dikemas kini.", "ProjectResourcePolicy": "Polisi Sumber Projek", diff --git a/packages/backend.ai-ui/src/locale/pl.json b/packages/backend.ai-ui/src/locale/pl.json index d4d6f68aa1..b440853486 100644 --- a/packages/backend.ai-ui/src/locale/pl.json +++ b/packages/backend.ai-ui/src/locale/pl.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Czy na pewno chcesz usunąć wdrożenie \"{{deploymentName}}\"? Tej operacji nie można cofnąć.", + "CreatedAt": "Utworzono", + "CreatedUser": "Autor", + "CurrentRevisionID": "Bieżące ID rewizji", + "Delete": "Usuń", + "DeleteDeployment": "Usuń wdrożenie", + "DeploymentDeleted": "Wdrożenie usunięte.", + "DeploymentID": "ID wdrożenia", + "DomainName": "Domena", + "EndpointURL": "URL punktu końcowego", + "FailedToDeleteDeployment": "Nie udało się usunąć wdrożenia.", + "Name": "Nazwa", + "OpenToPublic": "Otwarty dla wszystkich", + "PreferredDomainName": "Preferowana domena", + "ProjectID": "ID projektu", + "Replicas": "Repliki", + "Status": "Status", + "StrategyType": "Strategia", + "Tags": "Tagi", + "UpdatedAt": "Zaktualizowano" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Poniższe foldery zostaną zaktualizowane.", "ProjectResourcePolicy": "Polityka zasobów projektu", diff --git a/packages/backend.ai-ui/src/locale/pt-BR.json b/packages/backend.ai-ui/src/locale/pt-BR.json index ffc66c5c7b..ebbdbdc016 100644 --- a/packages/backend.ai-ui/src/locale/pt-BR.json +++ b/packages/backend.ai-ui/src/locale/pt-BR.json @@ -151,6 +151,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Tem certeza que deseja excluir o deployment \"{{deploymentName}}\"? Esta ação não pode ser desfeita.", + "CreatedAt": "Criado em", + "CreatedUser": "Autor", + "CurrentRevisionID": "ID de revisão atual", + "Delete": "Excluir", + "DeleteDeployment": "Excluir deployment", + "DeploymentDeleted": "Deployment excluído.", + "DeploymentID": "ID do deployment", + "DomainName": "Domínio", + "EndpointURL": "URL do ponto final", + "FailedToDeleteDeployment": "Falha ao excluir o deployment.", + "Name": "Nome", + "OpenToPublic": "Aberto ao público", + "PreferredDomainName": "Domínio preferido", + "ProjectID": "ID do projeto", + "Replicas": "Réplicas", + "Status": "Status", + "StrategyType": "Estratégia", + "Tags": "Tag", + "UpdatedAt": "Atualizado em" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "A(s) pasta(s) a seguir será(ão) atualizada(s).", "ProjectResourcePolicy": "Política de Recursos do Projeto", diff --git a/packages/backend.ai-ui/src/locale/pt.json b/packages/backend.ai-ui/src/locale/pt.json index f3a3d26cff..ca4938b64f 100644 --- a/packages/backend.ai-ui/src/locale/pt.json +++ b/packages/backend.ai-ui/src/locale/pt.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Tem certeza que deseja excluir o deployment \"{{deploymentName}}\"? Esta ação não pode ser desfeita.", + "CreatedAt": "Criado em", + "CreatedUser": "Autor", + "CurrentRevisionID": "ID de revisão atual", + "Delete": "Excluir", + "DeleteDeployment": "Excluir deployment", + "DeploymentDeleted": "Deployment excluído.", + "DeploymentID": "ID do deployment", + "DomainName": "Domínio", + "EndpointURL": "URL do ponto final", + "FailedToDeleteDeployment": "Falha ao excluir o deployment.", + "Name": "Nome", + "OpenToPublic": "Aberto ao público", + "PreferredDomainName": "Domínio preferido", + "ProjectID": "ID do projeto", + "Replicas": "Réplicas", + "Status": "Estado", + "StrategyType": "Estratégia", + "Tags": "Tag", + "UpdatedAt": "Atualizado em" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "A(s) pasta(s) a seguir será(ão) atualizada(s).", "ProjectResourcePolicy": "Política de Recursos do Projeto", diff --git a/packages/backend.ai-ui/src/locale/ru.json b/packages/backend.ai-ui/src/locale/ru.json index 9fff479d40..c2a41d8ef0 100644 --- a/packages/backend.ai-ui/src/locale/ru.json +++ b/packages/backend.ai-ui/src/locale/ru.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Вы уверены, что хотите удалить развёртывание \"{{deploymentName}}\"? Это действие нельзя отменить.", + "CreatedAt": "Создано", + "CreatedUser": "Автор", + "CurrentRevisionID": "ID текущей ревизии", + "Delete": "Удалить", + "DeleteDeployment": "Удалить развёртывание", + "DeploymentDeleted": "Развёртывание удалено.", + "DeploymentID": "ID развёртывания", + "DomainName": "Домен", + "EndpointURL": "URL конечной точки", + "FailedToDeleteDeployment": "Не удалось удалить развёртывание.", + "Name": "Имя", + "OpenToPublic": "Открыто для всех", + "PreferredDomainName": "Предпочтительный домен", + "ProjectID": "ID проекта", + "Replicas": "Реплики", + "Status": "Статус", + "StrategyType": "Стратегия", + "Tags": "Теги", + "UpdatedAt": "Обновлено" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Будут обновлены следующие папки.", "ProjectResourcePolicy": "Политика ресурсов проекта", diff --git a/packages/backend.ai-ui/src/locale/th.json b/packages/backend.ai-ui/src/locale/th.json index 7374571a4e..936321c6ea 100644 --- a/packages/backend.ai-ui/src/locale/th.json +++ b/packages/backend.ai-ui/src/locale/th.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "คุณแน่ใจหรือไม่ว่าต้องการลบการปรับใช้ \"{{deploymentName}}\"? การดำเนินการนี้ไม่สามารถยกเลิกได้", + "CreatedAt": "วันที่สร้าง", + "CreatedUser": "ผู้เขียน", + "CurrentRevisionID": "รหัสการแก้ไขปัจจุบัน", + "Delete": "ลบ", + "DeleteDeployment": "ลบการปรับใช้", + "DeploymentDeleted": "ลบการปรับใช้แล้ว", + "DeploymentID": "รหัสการปรับใช้", + "DomainName": "โดเมน", + "EndpointURL": "URL ปลายทาง", + "FailedToDeleteDeployment": "ไม่สามารถลบการปรับใช้ได้", + "Name": "ชื่อ", + "OpenToPublic": "เปิดสาธารณะ", + "PreferredDomainName": "โดเมนที่ต้องการ", + "ProjectID": "รหัสโปรเจกต์", + "Replicas": "จำนวนสำเนา", + "Status": "สถานะ", + "StrategyType": "กลยุทธ์", + "Tags": "แท็ก", + "UpdatedAt": "วันที่อัปเดต" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "โฟลเดอร์ต่อไปนี้จะถูกอัปเดต.", "ProjectResourcePolicy": "นโยบายทรัพยากรโครงการ", diff --git a/packages/backend.ai-ui/src/locale/tr.json b/packages/backend.ai-ui/src/locale/tr.json index 75536d5ddd..0917f5fe94 100644 --- a/packages/backend.ai-ui/src/locale/tr.json +++ b/packages/backend.ai-ui/src/locale/tr.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "\"{{deploymentName}}\" dağıtımını silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.", + "CreatedAt": "Oluşturulma Tarihi", + "CreatedUser": "Yazar", + "CurrentRevisionID": "Mevcut Revizyon Kimliği", + "Delete": "Sil", + "DeleteDeployment": "Dağıtımı Sil", + "DeploymentDeleted": "Dağıtım silindi.", + "DeploymentID": "Dağıtım Kimliği", + "DomainName": "Alan Adı", + "EndpointURL": "Uç Nokta URL'si", + "FailedToDeleteDeployment": "Dağıtım silinemedi.", + "Name": "Ad", + "OpenToPublic": "Herkese Açık", + "PreferredDomainName": "Tercih Edilen Alan Adı", + "ProjectID": "Proje Kimliği", + "Replicas": "Kopyalar", + "Status": "Durum", + "StrategyType": "Strateji", + "Tags": "Etiketler", + "UpdatedAt": "Güncellenme Tarihi" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Aşağıdaki klasör(ler) güncellenecek.", "ProjectResourcePolicy": "Proje Kaynak Politikası", diff --git a/packages/backend.ai-ui/src/locale/vi.json b/packages/backend.ai-ui/src/locale/vi.json index a45b8d3866..426a320794 100644 --- a/packages/backend.ai-ui/src/locale/vi.json +++ b/packages/backend.ai-ui/src/locale/vi.json @@ -152,6 +152,28 @@ "Minimize": "Minimize", "Restore": "Restore" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "Bạn có chắc chắn muốn xóa triển khai \"{{deploymentName}}\"? Hành động này không thể hoàn tác.", + "CreatedAt": "Ngày tạo", + "CreatedUser": "Tác giả", + "CurrentRevisionID": "ID phiên bản hiện tại", + "Delete": "Xóa", + "DeleteDeployment": "Xóa triển khai", + "DeploymentDeleted": "Đã xóa triển khai.", + "DeploymentID": "ID triển khai", + "DomainName": "Tên miền", + "EndpointURL": "URL điểm cuối", + "FailedToDeleteDeployment": "Không thể xóa triển khai.", + "Name": "Tên", + "OpenToPublic": "Mở cho công khai", + "PreferredDomainName": "Tên miền ưa thích", + "ProjectID": "ID dự án", + "Replicas": "Số bản sao", + "Status": "Trạng thái", + "StrategyType": "Chiến lược", + "Tags": "Thẻ", + "UpdatedAt": "Ngày cập nhật" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "Thư mục sau sẽ được cập nhật.", "ProjectResourcePolicy": "Chính sách tài nguyên dự án", diff --git a/packages/backend.ai-ui/src/locale/zh-CN.json b/packages/backend.ai-ui/src/locale/zh-CN.json index a08ce7127f..f1ada3c6ee 100644 --- a/packages/backend.ai-ui/src/locale/zh-CN.json +++ b/packages/backend.ai-ui/src/locale/zh-CN.json @@ -152,6 +152,28 @@ "Minimize": "最小化", "Restore": "还原" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "确定要删除部署 \"{{deploymentName}}\" 吗?此操作无法撤销。", + "CreatedAt": "创建时间", + "CreatedUser": "作者", + "CurrentRevisionID": "当前修订版本ID", + "Delete": "删除", + "DeleteDeployment": "删除部署", + "DeploymentDeleted": "部署已删除。", + "DeploymentID": "部署ID", + "DomainName": "域", + "EndpointURL": "端点URL", + "FailedToDeleteDeployment": "删除部署失败。", + "Name": "名称", + "OpenToPublic": "公开", + "PreferredDomainName": "首选域", + "ProjectID": "项目ID", + "Replicas": "副本数", + "Status": "状态", + "StrategyType": "策略", + "Tags": "标签", + "UpdatedAt": "更新时间" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "以下文件夹将被更新。", "ProjectResourcePolicy": "项目资源策略", diff --git a/packages/backend.ai-ui/src/locale/zh-TW.json b/packages/backend.ai-ui/src/locale/zh-TW.json index 4b9174374c..5a7003a2e5 100644 --- a/packages/backend.ai-ui/src/locale/zh-TW.json +++ b/packages/backend.ai-ui/src/locale/zh-TW.json @@ -152,6 +152,28 @@ "Minimize": "最小化", "Restore": "還原" }, + "comp:BAIModelDeploymentNodes": { + "AreYouSureToDeleteDeployment": "確定要刪除部署 \"{{deploymentName}}\" 嗎?此操作無法復原。", + "CreatedAt": "建立時間", + "CreatedUser": "作者", + "CurrentRevisionID": "目前修訂版本ID", + "Delete": "刪除", + "DeleteDeployment": "刪除部署", + "DeploymentDeleted": "部署已刪除。", + "DeploymentID": "部署ID", + "DomainName": "網域", + "EndpointURL": "端點URL", + "FailedToDeleteDeployment": "刪除部署失敗。", + "Name": "名稱", + "OpenToPublic": "公開", + "PreferredDomainName": "偏好網域", + "ProjectID": "專案ID", + "Replicas": "副本數", + "Status": "狀態", + "StrategyType": "策略", + "Tags": "標籤", + "UpdatedAt": "更新時間" + }, "comp:BAIProjectBulkEditModal": { "FollowingFoldersWillBeUpdated": "下列資料夾將會更新。", "ProjectResourcePolicy": "專案資源政策", diff --git a/react/src/hooks/useWebUIMenuItems.tsx b/react/src/hooks/useWebUIMenuItems.tsx index 96fc3428dc..36489938c7 100644 --- a/react/src/hooks/useWebUIMenuItems.tsx +++ b/react/src/hooks/useWebUIMenuItems.tsx @@ -106,6 +106,7 @@ export const VALID_MENU_KEYS = [ 'admin-data', 'project-admin-users', 'project-data', + 'project-admin-deployments', 'agent', 'project', 'settings', @@ -132,6 +133,7 @@ const ALL_ADMIN_PAGE_KEYS: ReadonlySet = new Set([ 'admin-data', 'project-admin-users', 'project-data', + 'project-admin-deployments', 'agent', 'project', 'settings', @@ -153,6 +155,7 @@ export const PROJECT_ADMIN_PAGE_KEYS = [ // 'admin-data', 'project-admin-users', 'project-data', + 'project-admin-deployments', ] as const; const PROJECT_ADMIN_PAGE_KEY_SET: ReadonlySet = new Set( @@ -366,6 +369,16 @@ export const useWebUIMenuItems = (props?: UseWebUIMenuItemsProps) => { key: 'project-data' as MenuKeys, group: 'admin-operations' as AdminMenuGroupName, }, + { + label: ( + + {t('webui.menu.ProjectDeployments')} + + ), + icon: , + key: 'project-admin-deployments' as MenuKeys, + group: 'admin-operations' as AdminMenuGroupName, + }, isSuperAdmin && { label: {t('webui.menu.Projects')}, icon: , diff --git a/react/src/pages/ProjectAdminDeploymentsPage.tsx b/react/src/pages/ProjectAdminDeploymentsPage.tsx new file mode 100644 index 0000000000..ac5848f50c --- /dev/null +++ b/react/src/pages/ProjectAdminDeploymentsPage.tsx @@ -0,0 +1,347 @@ +/** + @license + Copyright (c) 2015-2026 Lablup Inc. All rights reserved. + */ +import type { ProjectAdminDeploymentsPageDeleteMutation } from '../__generated__/ProjectAdminDeploymentsPageDeleteMutation.graphql'; +import type { + DeploymentOrderBy, + ProjectAdminDeploymentsPageQuery, +} from '../__generated__/ProjectAdminDeploymentsPageQuery.graphql'; +import BAIErrorBoundary from '../components/BAIErrorBoundary'; +import BAIRadioGroup from '../components/BAIRadioGroup'; +import { convertToOrderBy } from '../helper'; +import { useBAIPaginationOptionStateOnSearchParam } from '../hooks/reactPaginationQueryOptions'; +import { useCurrentProjectValue } from '../hooks/useCurrentProject'; +import { DeleteOutlined } from '@ant-design/icons'; +import { App, Skeleton } from 'antd'; +import { + availableDeploymentSorterValues, + BAICard, + BAIDeleteConfirmModal, + BAIFetchKeyButton, + BAIFlex, + BAIGraphQLPropertyFilter, + BAIModelDeploymentNodes, + GraphQLFilter, + INITIAL_FETCH_KEY, + ModelDeploymentNodeInList, + toLocalId, + useErrorMessageResolver, + useFetchKey, +} from 'backend.ai-ui'; +import { parseAsJson, parseAsStringLiteral, useQueryStates } from 'nuqs'; +import React, { Suspense, useDeferredValue, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { graphql, useLazyLoadQuery, useMutation } from 'react-relay'; + +const ALLOWED_FILTER_KEYS = ['name', 'tags', 'endpointUrl'] as const; +type AllowedFilter = Partial< + Pick +>; + +const parseFilter = parseAsJson((raw) => { + if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) { + return {}; + } + const filtered: AllowedFilter = {}; + for (const key of ALLOWED_FILTER_KEYS) { + if (key in raw) { + filtered[key] = (raw as Record)[key]; + } + } + return filtered; +}); + +const statusFilterValues = ['ACTIVE', 'INACTIVE'] as const; + +const INACTIVE_DEPLOYMENT_STATUSES = ['STOPPED'] as const; + +interface ProjectAdminDeploymentsContentProps { + projectId: string; +} + +const ProjectAdminDeploymentsContent: React.FC< + ProjectAdminDeploymentsContentProps +> = ({ projectId }) => { + 'use memo'; + const { t } = useTranslation(); + const { message } = App.useApp(); + const { getErrorMessage } = useErrorMessageResolver(); + const [deploymentToDelete, setDeploymentToDelete] = + useState(null); + + const { + baiPaginationOption, + tablePaginationOption, + setTablePaginationOption, + } = useBAIPaginationOptionStateOnSearchParam({ + current: 1, + pageSize: 10, + }); + + const [commitDeleteDeployment] = + useMutation(graphql` + mutation ProjectAdminDeploymentsPageDeleteMutation( + $input: DeleteDeploymentInput! + ) { + deleteModelDeployment(input: $input) { + id + } + } + `); + + const [queryParams, setQueryParams] = useQueryStates( + { + status: parseAsStringLiteral(statusFilterValues).withDefault('ACTIVE'), + order: parseAsStringLiteral(availableDeploymentSorterValues), + filter: parseFilter, + }, + { + history: 'replace', + }, + ); + + const [fetchKey, updateFetchKey] = useFetchKey(); + + const statusFilter = + queryParams.status === 'ACTIVE' + ? { notIn: [...INACTIVE_DEPLOYMENT_STATUSES] } + : { in: [...INACTIVE_DEPLOYMENT_STATUSES] }; + + const queryVariables = { + projectId, + filter: { + ...(queryParams.filter ?? {}), + status: statusFilter, + }, + orderBy: convertToOrderBy>(queryParams.order), + limit: baiPaginationOption.limit, + offset: baiPaginationOption.offset, + }; + + const deferredQueryVariables = useDeferredValue(queryVariables); + const deferredFetchKey = useDeferredValue(fetchKey); + + const data = useLazyLoadQuery( + graphql` + query ProjectAdminDeploymentsPageQuery( + $projectId: UUID! + $filter: DeploymentFilter + $orderBy: [DeploymentOrderBy!] + $limit: Int + $offset: Int + ) { + projectDeployments( + scope: { projectId: $projectId } + filter: $filter + orderBy: $orderBy + limit: $limit + offset: $offset + ) { + count + edges { + node { + id + ...BAIModelDeploymentNodesFragment + } + } + } + } + `, + deferredQueryVariables, + { + fetchKey: deferredFetchKey, + fetchPolicy: + deferredFetchKey === INITIAL_FETCH_KEY + ? 'store-and-network' + : 'network-only', + }, + ); + + const deploymentNodes = + data.projectDeployments?.edges?.map((edge) => edge?.node) ?? []; + const total = data.projectDeployments?.count ?? 0; + + const isLoading = + deferredQueryVariables !== queryVariables || deferredFetchKey !== fetchKey; + + return ( + + + + { + setQueryParams({ status: e.target.value }); + setTablePaginationOption({ current: 1 }); + }} + options={[ + { label: t('modelService.Active'), value: 'ACTIVE' }, + { label: t('modelService.Destroyed'), value: 'INACTIVE' }, + ]} + /> + { + setQueryParams({ + filter: (value as AllowedFilter | undefined) ?? null, + }); + setTablePaginationOption({ current: 1 }); + }} + /> + + updateFetchKey(next)} + autoUpdateDelay={15_000} + /> + + { + setQueryParams({ order }); + }} + nameColumnActionProps={(_value, record) => { + const status = record.metadata?.status; + const isDeleteDisabled = + !!status && + status !== '%future added value' && + (INACTIVE_DEPLOYMENT_STATUSES as readonly string[]).includes( + status, + ); + return { + title: record.metadata?.name ?? '-', + actions: [ + { + key: 'delete', + title: t('button.Delete'), + icon: , + type: 'danger', + disabled: isDeleteDisabled, + onClick: () => { + setDeploymentToDelete(record); + }, + }, + ], + }; + }} + pagination={{ + current: tablePaginationOption.current, + pageSize: tablePaginationOption.pageSize, + total, + onChange: (current, pageSize) => { + setTablePaginationOption({ current, pageSize }); + }, + }} + /> + { + if (!deploymentToDelete) return; + const target = deploymentToDelete; + const deploymentName = target.metadata?.name ?? toLocalId(target.id); + return new Promise((resolve) => { + commitDeleteDeployment({ + variables: { input: { id: toLocalId(target.id) } }, + onCompleted: (_response, errors) => { + if (errors && errors.length > 0) { + errors.forEach((error) => { + message.error( + getErrorMessage( + error, + t('modelService.FailedToTerminateService'), + ), + ); + }); + } else { + message.success( + t('modelService.ServiceTerminated', { + name: deploymentName, + }), + ); + updateFetchKey(); + } + setDeploymentToDelete(null); + resolve(); + }, + onError: (error) => { + message.error( + getErrorMessage( + error, + t('modelService.FailedToTerminateService'), + ), + ); + setDeploymentToDelete(null); + resolve(); + }, + }); + }); + }} + onCancel={() => setDeploymentToDelete(null)} + /> + + ); +}; + +const ProjectAdminDeploymentsPage: React.FC = () => { + 'use memo'; + const { t } = useTranslation(); + const currentProject = useCurrentProjectValue(); + + return ( + + + }> + {currentProject.id ? ( + + ) : ( + + )} + + + + ); +}; + +export default ProjectAdminDeploymentsPage; diff --git a/react/src/routes.tsx b/react/src/routes.tsx index d6837a6872..b39d3d528a 100644 --- a/react/src/routes.tsx +++ b/react/src/routes.tsx @@ -121,6 +121,9 @@ const ProjectAdminUsersPage = React.lazy( const ProjectAdminDataPage = React.lazy( () => import('./pages/ProjectAdminDataPage'), ); +const ProjectAdminDeploymentsPage = React.lazy( + () => import('./pages/ProjectAdminDeploymentsPage'), +); const EmailVerificationPage = React.lazy( () => import('./pages/EmailVerificationPage'), ); @@ -477,6 +480,18 @@ export const mainLayoutChildRoutes: RouteObject[] = [ ); }, }, + { + path: '/project-admin-deployments', + handle: { labelKey: 'webui.menu.ProjectDeployments' }, + Component: () => { + useSuspendedBackendaiClient(); + return ( + }> + + + ); + }, + }, { path: '/environment', handle: { labelKey: 'webui.menu.Environments' }, diff --git a/resources/i18n/de.json b/resources/i18n/de.json index 15103c4830..fd8c582a43 100644 --- a/resources/i18n/de.json +++ b/resources/i18n/de.json @@ -1485,6 +1485,7 @@ "EditNotAvailableWhileDeploying": "Die Bearbeitung ist während der Bereitstellung des Dienstes nicht verfügbar. Bitte versuchen Sie es später erneut.", "EndpointId": "Endpunkt-ID", "EndpointName": "Endpunkt Name", + "EndpointURL": "Endpunkt URL", "EnterCommand": "Befehl eingeben", "Error": "Fehler", "ExpiredDate": "Ablaufdatum", @@ -1518,6 +1519,7 @@ "ModelMountTooltip": "Der Pfad, an dem der Modellordner innerhalb des Containers gemountet wird.", "ModelServiceCreationHasBeenCanceled": "Die Erstellung des Modelldienstes wurde storniert.", "ModelServiceFailedToStart": "Den Modelldienst nicht starten.", + "Name": "Name", "NextRevisionApplying": "Die nächste Revision wird angewendet.", "NimApiKey": "Ihr NGC-API-Schlüssel", "NoExtraMounts": "Keine zusätzlichen Halterungen", @@ -1640,6 +1642,7 @@ "SyncRoutes": "Routen synchronisieren", "SyncRoutesFailed": "Die Anfrage zur Routensynchronisierung ist fehlgeschlagen.", "SyncRoutesRequested": "Routensynchronisierung wurde angefordert.", + "Tags": "Tags", "TimeStamp": "Zeitstempel", "Token": "Token", "TokenExpiredDateError": "Die Ablaufzeit des Tokens muss nach der aktuellen Zeit liegen", @@ -3060,6 +3063,7 @@ "PrivacyPolicy": "Datenschutz-Bestimmungen", "ProfileUpdated": "Das Profil wurde erfolgreich aktualisiert.", "Project": "Projekt", + "ProjectDeployments": "Bereitstellungen", "ProjectMembers": "Benutzer", "Projects": "Projekte", "RBACManagement": "RBAC-Verwaltung", diff --git a/resources/i18n/el.json b/resources/i18n/el.json index 097d1528eb..7ec5597c41 100644 --- a/resources/i18n/el.json +++ b/resources/i18n/el.json @@ -1483,6 +1483,7 @@ "EditNotAvailableWhileDeploying": "Η επεξεργασία δεν είναι διαθέσιμη ενώ η υπηρεσία αναπτύσσεται. Παρακαλώ δοκιμάστε ξανά αργότερα.", "EndpointId": "Αναγνωριστικό τελικού σημείου", "EndpointName": "Όνομα τελικού σημείου", + "EndpointURL": "URL τελικού σημείου", "EnterCommand": "Εισαγωγή εντολής", "Error": "Λάθος", "ExpiredDate": "Ημερομηνία Λήξης", @@ -1516,6 +1517,7 @@ "ModelMountTooltip": "Η διαδρομή όπου ο φάκελος μοντέλου είναι προσαρτημένος εντός του container.", "ModelServiceCreationHasBeenCanceled": "Η δημιουργία υπηρεσιών μοντέλου έχει ακυρωθεί.", "ModelServiceFailedToStart": "Αποτυχία εκκίνησης της υπηρεσίας μοντέλου.", + "Name": "Ονομα", "NextRevisionApplying": "Η επόμενη αναθεώρηση εφαρμόζεται.", "NimApiKey": "Το κλειδί API του NGC σας", "NoExtraMounts": "Χωρίς επιπλέον βάσεις", @@ -1638,6 +1640,7 @@ "SyncRoutes": "Διαδρομές συγχρονισμού", "SyncRoutesFailed": "Το αίτημα συγχρονισμού διαδρομής απέτυχε.", "SyncRoutesRequested": "Ζητήθηκε συγχρονισμός διαδρομής.", + "Tags": "Tags", "TimeStamp": "Χρονική σήμανση", "Token": "Token", "TokenExpiredDateError": "Ο χρόνος λήξης του κουπονιού πρέπει να είναι μετά την τρέχουσα ώρα.", @@ -3058,6 +3061,7 @@ "PrivacyPolicy": "Πολιτική απορρήτου", "ProfileUpdated": "Το προφίλ ενημερώθηκε με επιτυχία.", "Project": "Έργο", + "ProjectDeployments": "Αναπτύξεις", "ProjectMembers": "Χρήστες", "Projects": "Έργα", "RBACManagement": "Διαχείριση RBAC", diff --git a/resources/i18n/en.json b/resources/i18n/en.json index 347c7f9f0e..a600a24157 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -1484,6 +1484,7 @@ "EditNotAvailableWhileDeploying": "Editing is not available while the service is being deployed. Please try again later.", "EndpointId": "Endpoint ID", "EndpointName": "Endpoint Name", + "EndpointURL": "Endpoint URL", "EnterCommand": "Enter Command", "Error": "Error", "ExpiredDate": "Expiration Date", @@ -1517,6 +1518,7 @@ "ModelMountTooltip": "The path where the model folder is mounted inside the container.", "ModelServiceCreationHasBeenCanceled": "Model service creation has been canceled.", "ModelServiceFailedToStart": "Failed to start model service.", + "Name": "Name", "NextRevisionApplying": "The next revision is being applied.", "NimApiKey": "Your NGC API key", "NoExtraMounts": "No extra mounts", @@ -1639,6 +1641,7 @@ "SyncRoutes": "Sync routes", "SyncRoutesFailed": "The route synchronization request failed.", "SyncRoutesRequested": "The route synchronization requested.", + "Tags": "Tags", "TimeStamp": "Timestamp", "Token": "Token", "TokenExpiredDateError": "The token expiration time must be after the current time", @@ -3068,6 +3071,7 @@ "PrivacyPolicy": "Privacy Policy", "ProfileUpdated": "Profile has been successfully updated.", "Project": "Project", + "ProjectDeployments": "Deployments", "ProjectMembers": "Users", "Projects": "Projects", "RBACManagement": "RBAC Management", diff --git a/resources/i18n/es.json b/resources/i18n/es.json index 37383f9ab5..5e6ca0a52b 100644 --- a/resources/i18n/es.json +++ b/resources/i18n/es.json @@ -1483,6 +1483,7 @@ "EditNotAvailableWhileDeploying": "La edición no está disponible mientras el servicio se está desplegando. Por favor, inténtelo de nuevo más tarde.", "EndpointId": "ID de punto final", "EndpointName": "Nombre del punto final", + "EndpointURL": "URL del punto final", "EnterCommand": "Ingresar comando", "Error": "Error", "ExpiredDate": "Fecha de expiración", @@ -1516,6 +1517,7 @@ "ModelMountTooltip": "La ruta donde la carpeta del modelo está montada dentro del contenedor.", "ModelServiceCreationHasBeenCanceled": "La creación del servicio modelo ha sido cancelado.", "ModelServiceFailedToStart": "No se pudo iniciar el servicio de modelos.", + "Name": "Nombre", "NextRevisionApplying": "Se está aplicando la siguiente revisión.", "NimApiKey": "Su clave de API de NGC", "NoExtraMounts": "Sin soportes adicionales", @@ -1638,6 +1640,7 @@ "SyncRoutes": "Rutas de sincronización", "SyncRoutesFailed": "La solicitud de sincronización de ruta ha fallado.", "SyncRoutesRequested": "Se ha solicitado sincronización de ruta.", + "Tags": "Tags", "TimeStamp": "Marca de tiempo", "Token": "Ficha", "TokenExpiredDateError": "La hora de caducidad del token debe ser posterior a la hora actual", @@ -3058,6 +3061,7 @@ "PrivacyPolicy": "Política de privacidad", "ProfileUpdated": "El perfil se ha actualizado correctamente.", "Project": "Proyecto", + "ProjectDeployments": "Implementaciones", "ProjectMembers": "Usuarios", "Projects": "Proyectos", "RBACManagement": "Gestión RBAC", diff --git a/resources/i18n/fi.json b/resources/i18n/fi.json index 244957adf9..09d1ddd28c 100644 --- a/resources/i18n/fi.json +++ b/resources/i18n/fi.json @@ -1483,6 +1483,7 @@ "EditNotAvailableWhileDeploying": "Muokkaaminen ei ole käytettävissä palvelun käyttöönoton aikana. Yritä myöhemmin uudelleen.", "EndpointId": "Päätepisteen tunnus", "EndpointName": "Päätepisteen nimi", + "EndpointURL": "Päätepisteen URL", "EnterCommand": "Syötä komento", "Error": "Virhe", "ExpiredDate": "Vanhenemispäivä", @@ -1516,6 +1517,7 @@ "ModelMountTooltip": "Polku, johon mallikansio on liitetty kontin sisällä.", "ModelServiceCreationHasBeenCanceled": "Mallipalvelun luominen on peruutettu.", "ModelServiceFailedToStart": "Mallipalvelun aloittaminen epäonnistui.", + "Name": "Nimi", "NextRevisionApplying": "Seuraavaa revisiota otetaan käyttöön.", "NimApiKey": "NGC:n API-avaimesi", "NoExtraMounts": "Ei ylimääräisiä kiinnikkeitä", @@ -1638,6 +1640,7 @@ "SyncRoutes": "Synkronoi reitit", "SyncRoutesFailed": "Reitin synkronointipyyntö epäonnistui.", "SyncRoutesRequested": "Reitin synkronointia on pyydetty.", + "Tags": "Tags", "TimeStamp": "Aikaleima", "Token": "Merkki", "TokenExpiredDateError": "Merkin voimassaoloajan on oltava nykyisen ajan jälkeen.", @@ -3059,6 +3062,7 @@ "PrivacyPolicy": "Tietosuojakäytäntö", "ProfileUpdated": "Profiili on päivitetty onnistuneesti.", "Project": "Hanke", + "ProjectDeployments": "Käyttöönotot", "ProjectMembers": "Käyttäjät", "Projects": "Hankkeet", "RBACManagement": "RBAC-hallinta", diff --git a/resources/i18n/fr.json b/resources/i18n/fr.json index 54a9b4052b..7022b9346b 100644 --- a/resources/i18n/fr.json +++ b/resources/i18n/fr.json @@ -1484,6 +1484,7 @@ "EditNotAvailableWhileDeploying": "La modification n'est pas disponible pendant le déploiement du service. Veuillez réessayer ultérieurement.", "EndpointId": "ID du point final", "EndpointName": "Nom du point final", + "EndpointURL": "URL du point final", "EnterCommand": "Saisir une commande", "Error": "Erreur", "ExpiredDate": "Date d'expiration", @@ -1517,6 +1518,7 @@ "ModelMountTooltip": "Le chemin où le dossier du modèle est monté à l'intérieur du conteneur.", "ModelServiceCreationHasBeenCanceled": "La création de services modèles a été annulée.", "ModelServiceFailedToStart": "Échec du démarrage du service du modèle.", + "Name": "Nom", "NextRevisionApplying": "La révision suivante est en cours d'application.", "NimApiKey": "Votre clé API NGC", "NoExtraMounts": "Pas de montures supplémentaires", @@ -1640,6 +1642,7 @@ "SyncRoutes": "Synchroniser les itinéraires", "SyncRoutesFailed": "La demande de synchronisation des routes a échoué.", "SyncRoutesRequested": "La synchronisation de l'itinéraire a été demandée.", + "Tags": "Tags", "TimeStamp": "Horodatage", "Token": "Jeton", "TokenExpiredDateError": "L'heure d'expiration du jeton doit être postérieure à l'heure actuelle.", @@ -3061,6 +3064,7 @@ "PrivacyPolicy": "Politique de confidentialité", "ProfileUpdated": "Le profil a été mis à jour avec succès.", "Project": "Projet", + "ProjectDeployments": "Déploiements", "ProjectMembers": "Utilisateurs", "Projects": "Projets", "RBACManagement": "Gestion RBAC", diff --git a/resources/i18n/id.json b/resources/i18n/id.json index 61dd88e808..7c9b6a0266 100644 --- a/resources/i18n/id.json +++ b/resources/i18n/id.json @@ -1486,6 +1486,7 @@ "EditNotAvailableWhileDeploying": "Pengeditan tidak tersedia saat layanan sedang diterapkan. Silakan coba lagi nanti.", "EndpointId": "ID titik akhir", "EndpointName": "Nama Titik Akhir", + "EndpointURL": "URL Titik Akhir", "EnterCommand": "Masukkan Perintah", "Error": "Kesalahan", "ExpiredDate": "Tanggal Kedaluwarsa", @@ -1519,6 +1520,7 @@ "ModelMountTooltip": "Jalur tempat folder model di-mount di dalam container.", "ModelServiceCreationHasBeenCanceled": "Pembuatan Layanan Model telah dibatalkan.", "ModelServiceFailedToStart": "Gagal memulai layanan model.", + "Name": "Nama", "NextRevisionApplying": "Revisi berikutnya sedang diterapkan.", "NimApiKey": "Kunci API NGC Anda", "NoExtraMounts": "Tidak ada tunggangan tambahan", @@ -1641,6 +1643,7 @@ "SyncRoutes": "Menyinkronkan rute", "SyncRoutesFailed": "Permintaan sinkronisasi rute gagal.", "SyncRoutesRequested": "Sinkronisasi rute telah diminta.", + "Tags": "Tags", "TimeStamp": "Stempel waktu", "Token": "Token", "TokenExpiredDateError": "Waktu kedaluwarsa token harus setelah waktu saat ini", @@ -3062,6 +3065,7 @@ "PrivacyPolicy": "Kebijakan Privasi", "ProfileUpdated": "Profil berhasil diperbarui.", "Project": "Proyek", + "ProjectDeployments": "Penerapan", "ProjectMembers": "Pengguna", "Projects": "Proyek", "RBACManagement": "Manajemen RBAC", diff --git a/resources/i18n/it.json b/resources/i18n/it.json index fc57590b3a..c2da837257 100644 --- a/resources/i18n/it.json +++ b/resources/i18n/it.json @@ -1483,6 +1483,7 @@ "EditNotAvailableWhileDeploying": "La modifica non è disponibile mentre il servizio è in fase di distribuzione. Riprovare più tardi.", "EndpointId": "ID punto finale", "EndpointName": "Nome del punto finale", + "EndpointURL": "URL del punto finale", "EnterCommand": "Inserisci comando", "Error": "Errore", "ExpiredDate": "Data di Scadenza", @@ -1516,6 +1517,7 @@ "ModelMountTooltip": "Il percorso in cui la cartella del modello è montata all'interno del container.", "ModelServiceCreationHasBeenCanceled": "La creazione del servizio modello è stata annullata.", "ModelServiceFailedToStart": "Impossibile avviare il servizio modello.", + "Name": "Nome", "NextRevisionApplying": "La revisione successiva è in fase di applicazione.", "NimApiKey": "La tua chiave API NGC", "NoExtraMounts": "Nessun supporto aggiuntivo", @@ -1638,6 +1640,7 @@ "SyncRoutes": "Sincronizzazione dei percorsi", "SyncRoutesFailed": "La richiesta di sincronizzazione del percorso non è riuscita.", "SyncRoutesRequested": "È stata richiesta la sincronizzazione del percorso.", + "Tags": "Tags", "TimeStamp": "Timestamp", "Token": "Gettone", "TokenExpiredDateError": "L'ora di scadenza del token deve essere successiva all'ora corrente.", @@ -3058,6 +3061,7 @@ "PrivacyPolicy": "politica sulla riservatezza", "ProfileUpdated": "Il profilo è stato aggiornato con successo.", "Project": "Progetto", + "ProjectDeployments": "Distribuzioni", "ProjectMembers": "Utenti", "Projects": "Progetti", "RBACManagement": "Gestione RBAC", diff --git a/resources/i18n/ja.json b/resources/i18n/ja.json index ffff4a7d3e..8d076ad0f8 100644 --- a/resources/i18n/ja.json +++ b/resources/i18n/ja.json @@ -1485,6 +1485,7 @@ "EditNotAvailableWhileDeploying": "サービスのデプロイ中は編集できません。しばらくしてから再度お試しください。", "EndpointId": "エンドポイントID", "EndpointName": "エンドポイント名", + "EndpointURL": "エンドポイントURL", "EnterCommand": "コマンドを入力", "Error": "エラー", "ExpiredDate": "有効期限", @@ -1518,6 +1519,7 @@ "ModelMountTooltip": "コンテナ内にモデルフォルダがマウントされるパスです。", "ModelServiceCreationHasBeenCanceled": "モデルサービスの作成がキャンセルされました。", "ModelServiceFailedToStart": "モデルサービスを開始できませんでした。", + "Name": "名前", "NextRevisionApplying": "次のリビジョンを適用中です。", "NimApiKey": "あなたのNGC APIキー", "NoExtraMounts": "余分なマウントはありません", @@ -1640,6 +1642,7 @@ "SyncRoutes": "同期ルート", "SyncRoutesFailed": "ルート同期要求に失敗しました。", "SyncRoutesRequested": "ルート同期をリクエストしました。", + "Tags": "Tags", "TimeStamp": "タイムスタンプ", "Token": "トークン", "TokenExpiredDateError": "トークンの有効期限は現在の時間以降でなければなりません。", @@ -3060,6 +3063,7 @@ "PrivacyPolicy": "個人情報保護方針", "ProfileUpdated": "プロフィールが正常に更新されました。", "Project": "プロジェクト", + "ProjectDeployments": "デプロイメント", "ProjectMembers": "ユーザー", "Projects": "プロジェクト", "RBACManagement": "RBAC管理", diff --git a/resources/i18n/ko.json b/resources/i18n/ko.json index c5214e3ed2..7ea480fb14 100644 --- a/resources/i18n/ko.json +++ b/resources/i18n/ko.json @@ -1486,6 +1486,7 @@ "EditNotAvailableWhileDeploying": "서비스가 배포 중에는 수정할 수 없습니다. 잠시 후 다시 시도해 주세요.", "EndpointId": "엔드포인트 ID", "EndpointName": "엔드포인트 이름", + "EndpointURL": "엔드포인트 URL", "EnterCommand": "명령어 입력", "Error": "오류", "ExpiredDate": "토큰 만료 시각", @@ -1519,6 +1520,7 @@ "ModelMountTooltip": "컨테이너 내부에 모델 폴더가 마운트되는 경로입니다.", "ModelServiceCreationHasBeenCanceled": "모델 서비스 생성이 취소되었습니다.", "ModelServiceFailedToStart": "모델 서비스 생성에 실패했습니다.", + "Name": "이름", "NextRevisionApplying": "다음 리비전을 적용 중입니다.", "NimApiKey": "NGC API 키", "NoExtraMounts": "추가 마운트 없음", @@ -1641,6 +1643,7 @@ "SyncRoutes": "라우트 동기화", "SyncRoutesFailed": "라우트 동기화 요청이 실패했습니다.", "SyncRoutesRequested": "라우트 동기화를 요청했습니다.", + "Tags": "태그", "TimeStamp": "타임스탬프", "Token": "토큰", "TokenExpiredDateError": "토큰 만료 시간은 현재 시간 이후여야 합니다.", @@ -3073,6 +3076,7 @@ "PrivacyPolicy": "개인정보 보호", "ProfileUpdated": "프로필이 성공적으로 업데이트되었습니다.", "Project": "프로젝트", + "ProjectDeployments": "배포", "ProjectMembers": "사용자", "Projects": "프로젝트", "RBACManagement": "RBAC 관리", diff --git a/resources/i18n/mn.json b/resources/i18n/mn.json index 53d631036f..5de4219bb3 100644 --- a/resources/i18n/mn.json +++ b/resources/i18n/mn.json @@ -1484,6 +1484,7 @@ "EditNotAvailableWhileDeploying": "Үйлчилгээ байршуулж байх үед засах боломжгүй. Дараа дахин оролдоно уу.", "EndpointId": "Төгсгөлийн цэгийн ID", "EndpointName": "Төгсгөлийн цэгийн нэр", + "EndpointURL": "Төгсгөлийн цэгийн URL", "EnterCommand": "Тушаал оруулах", "Error": "Алдаа", "ExpiredDate": "Дуусах огноо", @@ -1517,6 +1518,7 @@ "ModelMountTooltip": "Загварын хавтас контейнерийн дотор холбогдох зам.", "ModelServiceCreationHasBeenCanceled": "Загвар үйлчилгээний бүтээлийг цуцаллаа.", "ModelServiceFailedToStart": "Загвар үйлчилгээг эхлүүлж чадсангүй.", + "Name": "Нэр", "NextRevisionApplying": "Дараагийн хувилбарыг хэрэгжүүлж байна.", "NimApiKey": "Таны NGC API түлхүүр", "NoExtraMounts": "Нэмэлт бэхэлгээ байхгүй", @@ -1639,6 +1641,7 @@ "SyncRoutes": "Замуудыг синк хийх", "SyncRoutesFailed": "Маршрутын синхрончлолын хүсэлт амжилтгүй боллоо.", "SyncRoutesRequested": "Маршрутыг синхрончлох хүсэлт тавьсан.", + "Tags": "Tags", "TimeStamp": "Цагийн тэмдэг", "Token": "Томог", "TokenExpiredDateError": "Токен дуусах хугацаа нь одоогийн цагаас хойш байх ёстой", @@ -3060,6 +3063,7 @@ "PrivacyPolicy": "Нууцлалын бодлого", "ProfileUpdated": "Профайл амжилттай шинэчлэгдлээ.", "Project": "Төсөл", + "ProjectDeployments": "Байршуулалтууд", "ProjectMembers": "Хэрэглэгчид", "Projects": "Төслүүд", "RBACManagement": "RBAC удирдлага", diff --git a/resources/i18n/ms.json b/resources/i18n/ms.json index 09b75d8490..c3a6af75ac 100644 --- a/resources/i18n/ms.json +++ b/resources/i18n/ms.json @@ -1483,6 +1483,7 @@ "EditNotAvailableWhileDeploying": "Pengeditan tidak tersedia semasa perkhidmatan sedang digunakan. Sila cuba lagi kemudian.", "EndpointId": "ID titik akhir", "EndpointName": "Nama Titik Akhir", + "EndpointURL": "URL Titik Akhir", "EnterCommand": "Masukkan Perintah", "Error": "ralat", "ExpiredDate": "Tarikh Tamat Tempoh", @@ -1516,6 +1517,7 @@ "ModelMountTooltip": "Laluan tempat folder model dipasang di dalam bekas.", "ModelServiceCreationHasBeenCanceled": "Penciptaan perkhidmatan model telah dibatalkan.", "ModelServiceFailedToStart": "Gagal memulakan perkhidmatan model.", + "Name": "Nama", "NextRevisionApplying": "Semakan seterusnya sedang diterapkan.", "NimApiKey": "Kunci API NGC anda", "NoExtraMounts": "Tiada pelekap tambahan", @@ -1638,6 +1640,7 @@ "SyncRoutes": "Segerakkan laluan", "SyncRoutesFailed": "Permintaan penyegerakan laluan gagal.", "SyncRoutesRequested": "Penyegerakan laluan telah diminta.", + "Tags": "Tags", "TimeStamp": "Cap masa", "Token": "Token", "TokenExpiredDateError": "Masa tamat tempoh token mestilah selepas masa semasa", @@ -3058,6 +3061,7 @@ "PrivacyPolicy": "Dasar Privasi", "ProfileUpdated": "Profil telah berjaya dikemas kini.", "Project": "Projek", + "ProjectDeployments": "Penggunaan", "ProjectMembers": "Pengguna", "Projects": "Projek", "RBACManagement": "Pengurusan RBAC", diff --git a/resources/i18n/pl.json b/resources/i18n/pl.json index 12f3acf6b9..ffcea66f68 100644 --- a/resources/i18n/pl.json +++ b/resources/i18n/pl.json @@ -1484,6 +1484,7 @@ "EditNotAvailableWhileDeploying": "Edytowanie jest niedostępne podczas wdrażania usługi. Spróbuj ponownie później.", "EndpointId": "Identyfikator punktu końcowego", "EndpointName": "Nazwa punktu końcowego", + "EndpointURL": "URL punktu końcowego", "EnterCommand": "Wprowadź polecenie", "Error": "Błąd", "ExpiredDate": "Data Wygaśnięcia", @@ -1517,6 +1518,7 @@ "ModelMountTooltip": "Ścieżka, pod którą folder modelu jest montowany wewnątrz kontenera.", "ModelServiceCreationHasBeenCanceled": "Modelowe tworzenie usług zostało anulowane.", "ModelServiceFailedToStart": "Nie udało się uruchomić Model Service.", + "Name": "Nazwa", "NextRevisionApplying": "Następna rewizja jest w trakcie stosowania.", "NimApiKey": "Twój klucz API NGC", "NoExtraMounts": "Żadnych dodatkowych mocowań", @@ -1640,6 +1642,7 @@ "SyncRoutes": "Synchronizacja tras", "SyncRoutesFailed": "Żądanie synchronizacji trasy nie powiodło się.", "SyncRoutesRequested": "Zażądano synchronizacji tras.", + "Tags": "Tags", "TimeStamp": "Znak czasu", "Token": "Token", "TokenExpiredDateError": "Czas wygaśnięcia tokena musi być późniejszy niż bieżący czas", @@ -3061,6 +3064,7 @@ "PrivacyPolicy": "Polityka prywatności", "ProfileUpdated": "Profil został pomyślnie zaktualizowany.", "Project": "Projekt", + "ProjectDeployments": "Wdrożenia", "ProjectMembers": "Użytkownicy", "Projects": "Projekty", "RBACManagement": "Zarządzanie RBAC", diff --git a/resources/i18n/pt-BR.json b/resources/i18n/pt-BR.json index 28ad0d2718..809de0965c 100644 --- a/resources/i18n/pt-BR.json +++ b/resources/i18n/pt-BR.json @@ -1483,6 +1483,7 @@ "EditNotAvailableWhileDeploying": "A edição não está disponível enquanto o serviço está sendo implantado. Por favor, tente novamente mais tarde.", "EndpointId": "ID do ponto final", "EndpointName": "Nome do ponto final", + "EndpointURL": "URL do ponto final", "EnterCommand": "Inserir comando", "Error": "Erro", "ExpiredDate": "Data de Expiração", @@ -1516,6 +1517,7 @@ "ModelMountTooltip": "O caminho onde a pasta do modelo é montada dentro do container.", "ModelServiceCreationHasBeenCanceled": "A criação do serviço de modelo foi cancelada.", "ModelServiceFailedToStart": "Falha ao iniciar o serviço de modelo.", + "Name": "Nome", "NextRevisionApplying": "A próxima revisão está sendo aplicada.", "NimApiKey": "Sua chave de API do NGC", "NoExtraMounts": "Sem montagens extras", @@ -1638,6 +1640,7 @@ "SyncRoutes": "Sincronizar rotas", "SyncRoutesFailed": "O pedido de sincronização de rotas falhou.", "SyncRoutesRequested": "A sincronização de rota foi solicitada.", + "Tags": "Tags", "TimeStamp": "Carimbo de data e hora", "Token": "Ficha", "TokenExpiredDateError": "A hora de expiração do token deve ser posterior à hora atual", @@ -3058,6 +3061,7 @@ "PrivacyPolicy": "Política de Privacidade", "ProfileUpdated": "O perfil foi atualizado com sucesso.", "Project": "Projeto", + "ProjectDeployments": "Implantações", "ProjectMembers": "Usuários", "Projects": "Projetos", "RBACManagement": "Gerenciamento RBAC", diff --git a/resources/i18n/pt.json b/resources/i18n/pt.json index 6df2e3b379..7a34fcdb9a 100644 --- a/resources/i18n/pt.json +++ b/resources/i18n/pt.json @@ -1485,6 +1485,7 @@ "EditNotAvailableWhileDeploying": "A edição não está disponível enquanto o serviço está a ser implementado. Por favor, tente novamente mais tarde.", "EndpointId": "ID do ponto final", "EndpointName": "Nome do ponto final", + "EndpointURL": "URL do ponto final", "EnterCommand": "Inserir comando", "Error": "Erro", "ExpiredDate": "Data de Expiração", @@ -1518,6 +1519,7 @@ "ModelMountTooltip": "O caminho onde a pasta do modelo é montada dentro do container.", "ModelServiceCreationHasBeenCanceled": "A criação do serviço de modelo foi cancelada.", "ModelServiceFailedToStart": "Falha ao iniciar o serviço de modelo.", + "Name": "Nome", "NextRevisionApplying": "A próxima revisão está a ser aplicada.", "NimApiKey": "Sua chave de API do NGC", "NoExtraMounts": "Sem montagens extras", @@ -1640,6 +1642,7 @@ "SyncRoutes": "Sincronizar rotas", "SyncRoutesFailed": "O pedido de sincronização de rotas falhou.", "SyncRoutesRequested": "A sincronização de rota foi solicitada.", + "Tags": "Tags", "TimeStamp": "Carimbo de data e hora", "Token": "Ficha", "TokenExpiredDateError": "A hora de expiração do token deve ser posterior à hora atual", @@ -3060,6 +3063,7 @@ "PrivacyPolicy": "Política de Privacidade", "ProfileUpdated": "O perfil foi atualizado com sucesso.", "Project": "Projeto", + "ProjectDeployments": "Implantações", "ProjectMembers": "Usuários", "Projects": "Projetos", "RBACManagement": "Gestão RBAC", diff --git a/resources/i18n/ru.json b/resources/i18n/ru.json index f7dcef8851..102298a2c0 100644 --- a/resources/i18n/ru.json +++ b/resources/i18n/ru.json @@ -1483,6 +1483,7 @@ "EditNotAvailableWhileDeploying": "Редактирование недоступно во время развёртывания сервиса. Пожалуйста, повторите попытку позже.", "EndpointId": "Идентификатор конечной точки", "EndpointName": "Имя конечной точки", + "EndpointURL": "URL конечной точки", "EnterCommand": "Введите команду", "Error": "Ошибка", "ExpiredDate": "Дата Истечения", @@ -1516,6 +1517,7 @@ "ModelMountTooltip": "Путь, по которому папка с моделью монтируется внутри контейнера.", "ModelServiceCreationHasBeenCanceled": "Создание услуг моделей было отменено.", "ModelServiceFailedToStart": "Не удалось запустить модельную службу.", + "Name": "Имя", "NextRevisionApplying": "Применяется следующая ревизия.", "NimApiKey": "Ваш API-ключ NGC", "NoExtraMounts": "Никаких дополнительных креплений", @@ -1638,6 +1640,7 @@ "SyncRoutes": "Синхронизация маршрутов", "SyncRoutesFailed": "Запрос на синхронизацию маршрута завершился неудачей.", "SyncRoutesRequested": "Запрошена синхронизация маршрутов.", + "Tags": "Tags", "TimeStamp": "Временная метка", "Token": "Токен", "TokenExpiredDateError": "Время истечения срока действия токена должно быть после текущего времени", @@ -3058,6 +3061,7 @@ "PrivacyPolicy": "Политика конфиденциальности", "ProfileUpdated": "Профиль успешно обновлён.", "Project": "Проект", + "ProjectDeployments": "Развёртывания", "ProjectMembers": "Пользователи", "Projects": "Проекты", "RBACManagement": "Управление RBAC", diff --git a/resources/i18n/th.json b/resources/i18n/th.json index 97e30cba4a..fa60c9ac3e 100644 --- a/resources/i18n/th.json +++ b/resources/i18n/th.json @@ -1485,6 +1485,7 @@ "EditNotAvailableWhileDeploying": "ไม่สามารถแก้ไขได้ขณะที่บริการกำลังถูกปรับใช้ กรุณาลองใหม่อีกครั้งในภายหลัง", "EndpointId": "รหัสจุดสิ้นสุด", "EndpointName": "ชื่อจุดสิ้นสุด", + "EndpointURL": "URL จุดสิ้นสุด", "EnterCommand": "ป้อนคำสั่ง", "Error": "ข้อผิดพลาด", "ExpiredDate": "วันที่หมดอายุ", @@ -1518,6 +1519,7 @@ "ModelMountTooltip": "เส้นทางที่โฟลเดอร์โมเดลถูกเมานต์ภายในคอนเทนเนอร์", "ModelServiceCreationHasBeenCanceled": "การสร้างบริการแบบจำลองได้ถูกยกเลิก", "ModelServiceFailedToStart": "ไม่สามารถเริ่มบริการรุ่น", + "Name": "ชื่อ", "NextRevisionApplying": "กำลังใช้งานรีวิชันถัดไป", "NimApiKey": "คีย์ API NGC ของคุณ", "NoExtraMounts": "ไม่มีการเมาท์เพิ่มเติม", @@ -1640,6 +1642,7 @@ "SyncRoutes": "ซิงค์เส้นทาง", "SyncRoutesFailed": "คำขอซิงโครไนซ์เส้นทางล้มเหลว", "SyncRoutesRequested": "ขอซิงโครไนซ์เส้นทางแล้ว", + "Tags": "Tags", "TimeStamp": "ประทับเวลา", "Token": "โทเค็น", "TokenExpiredDateError": "เวลาหมดอายุของโทเคนต้องอยู่หลังเวลาปัจจุบัน", @@ -3060,6 +3063,7 @@ "PrivacyPolicy": "นโยบายความเป็นส่วนตัว", "ProfileUpdated": "อัปเดตโปรไฟล์สำเร็จแล้ว", "Project": "โครงการ", + "ProjectDeployments": "การปรับใช้", "ProjectMembers": "ผู้ใช้", "Projects": "โครงการ", "RBACManagement": "การจัดการ RBAC", diff --git a/resources/i18n/tr.json b/resources/i18n/tr.json index 3596c84110..05ed06a90a 100644 --- a/resources/i18n/tr.json +++ b/resources/i18n/tr.json @@ -1483,6 +1483,7 @@ "EditNotAvailableWhileDeploying": "Hizmet dağıtılırken düzenleme yapılamaz. Lütfen daha sonra tekrar deneyin.", "EndpointId": "Uç Nokta Kimliği", "EndpointName": "Uç Nokta Adı", + "EndpointURL": "Uç Nokta URL", "EnterCommand": "Komut girin", "Error": "Hata", "ExpiredDate": "Son Kullanma Tarihi", @@ -1516,6 +1517,7 @@ "ModelMountTooltip": "Model klasörünün container içinde bağlandığı yol.", "ModelServiceCreationHasBeenCanceled": "Model hizmet oluşturma iptal edildi.", "ModelServiceFailedToStart": "Model hizmeti başlatılamadı.", + "Name": "isim", "NextRevisionApplying": "Sonraki revizyon uygulanıyor.", "NimApiKey": "NGC API anahtarınız", "NoExtraMounts": "Ekstra montaj yok", @@ -1638,6 +1640,7 @@ "SyncRoutes": "Rotaları senkronize et", "SyncRoutesFailed": "Rota senkronizasyon isteği başarısız oldu.", "SyncRoutesRequested": "Rota senkronizasyonu talep edildi.", + "Tags": "Tags", "TimeStamp": "Zaman damgası", "Token": "Jeton", "TokenExpiredDateError": "Belirteç sona erme süresi geçerli saatten sonra olmalıdır", @@ -3058,6 +3061,7 @@ "PrivacyPolicy": "Gizlilik Politikası", "ProfileUpdated": "Profil başarıyla güncellendi.", "Project": "Proje", + "ProjectDeployments": "Dağıtımlar", "ProjectMembers": "Kullanıcılar", "Projects": "Projeler", "RBACManagement": "RBAC Yönetimi", diff --git a/resources/i18n/vi.json b/resources/i18n/vi.json index 6d05ba208e..335bc9c607 100644 --- a/resources/i18n/vi.json +++ b/resources/i18n/vi.json @@ -1485,6 +1485,7 @@ "EditNotAvailableWhileDeploying": "Không thể chỉnh sửa trong khi dịch vụ đang được triển khai. Vui lòng thử lại sau.", "EndpointId": "ID điểm cuối", "EndpointName": "Tên điểm cuối", + "EndpointURL": "URL điểm cuối", "EnterCommand": "Nhập lệnh", "Error": "Lỗi", "ExpiredDate": "Ngày Hết Hạn", @@ -1518,6 +1519,7 @@ "ModelMountTooltip": "Đường dẫn nơi thư mục mô hình được gắn kết bên trong container.", "ModelServiceCreationHasBeenCanceled": "Tạo dịch vụ mô hình đã bị hủy bỏ.", "ModelServiceFailedToStart": "Không thể bắt đầu dịch vụ mô hình.", + "Name": "Tên", "NextRevisionApplying": "Phiên bản tiếp theo đang được áp dụng.", "NimApiKey": "Khóa API NGC của bạn", "NoExtraMounts": "Không có gắn kết bổ sung", @@ -1640,6 +1642,7 @@ "SyncRoutes": "Đồng bộ hóa tuyến đường", "SyncRoutesFailed": "Yêu cầu đồng bộ hóa tuyến đường không thành công.", "SyncRoutesRequested": "Đồng bộ hóa tuyến đường đã được yêu cầu.", + "Tags": "Tags", "TimeStamp": "Dấu thời gian", "Token": "Mã thông báo", "TokenExpiredDateError": "Thời gian hết hạn của mã thông báo phải sau thời điểm hiện tại", @@ -3060,6 +3063,7 @@ "PrivacyPolicy": "Chính sách bảo mật", "ProfileUpdated": "Hồ sơ đã được cập nhật thành công.", "Project": "Dự án", + "ProjectDeployments": "Triển khai", "ProjectMembers": "Người dùng", "Projects": "Dự án", "RBACManagement": "Quản lý RBAC", diff --git a/resources/i18n/zh-CN.json b/resources/i18n/zh-CN.json index 371991989f..4f3618d438 100644 --- a/resources/i18n/zh-CN.json +++ b/resources/i18n/zh-CN.json @@ -1485,6 +1485,7 @@ "EditNotAvailableWhileDeploying": "服务部署期间无法进行编辑,请稍后再试。", "EndpointId": "端点 ID", "EndpointName": "端点名称", + "EndpointURL": "端点URL", "EnterCommand": "输入命令", "Error": "错误", "ExpiredDate": "到期日期", @@ -1518,6 +1519,7 @@ "ModelMountTooltip": "模型文件夹在容器内部挂载的路径。", "ModelServiceCreationHasBeenCanceled": "模型服务创建已被取消。", "ModelServiceFailedToStart": "无法启动模型服务。", + "Name": "名称", "NextRevisionApplying": "正在应用下一个版本。", "NimApiKey": "您的 NGC API 密钥", "NoExtraMounts": "没有额外的安装座", @@ -1640,6 +1642,7 @@ "SyncRoutes": "同步路线", "SyncRoutesFailed": "路由同步请求失败。", "SyncRoutesRequested": "已请求路由同步。", + "Tags": "Tags", "TimeStamp": "时间戳", "Token": "代币", "TokenExpiredDateError": "令牌过期时间必须在当前时间之后", @@ -3060,6 +3063,7 @@ "PrivacyPolicy": "隐私政策", "ProfileUpdated": "个人资料已成功更新。", "Project": "项目", + "ProjectDeployments": "部署", "ProjectMembers": "用户", "Projects": "项目", "RBACManagement": "RBAC管理", diff --git a/resources/i18n/zh-TW.json b/resources/i18n/zh-TW.json index 6966270c26..a92b29aacb 100644 --- a/resources/i18n/zh-TW.json +++ b/resources/i18n/zh-TW.json @@ -1487,6 +1487,7 @@ "EditNotAvailableWhileDeploying": "服務部署期間無法進行編輯,請稍後再試。", "EndpointId": "端点 ID", "EndpointName": "端点名称", + "EndpointURL": "端點URL", "EnterCommand": "輸入命令", "Error": "錯誤", "ExpiredDate": "到期日期", @@ -1520,6 +1521,7 @@ "ModelMountTooltip": "模型資料夾在容器內部掛載的路徑。", "ModelServiceCreationHasBeenCanceled": "模型服務創建已被取消。", "ModelServiceFailedToStart": "模型服務啟動失敗。", + "Name": "名稱", "NextRevisionApplying": "正在套用下一個版本。", "NimApiKey": "您的 NGC API 金鑰", "NoExtraMounts": "沒有額外的安裝座", @@ -1642,6 +1644,7 @@ "SyncRoutes": "同步路线", "SyncRoutesFailed": "路由同步请求失败。", "SyncRoutesRequested": "已請求路由同步。", + "Tags": "Tags", "TimeStamp": "時間戳", "Token": "代币", "TokenExpiredDateError": "令牌过期时间必须在当前时间之后", @@ -3062,6 +3065,7 @@ "PrivacyPolicy": "隱私政策", "ProfileUpdated": "個人資料已成功更新。", "Project": "項目", + "ProjectDeployments": "部署", "ProjectMembers": "使用者", "Projects": "項目", "RBACManagement": "RBAC管理",