From b5ed64de513e9d0b6a0ca75366a0defe4ff1afcc Mon Sep 17 00:00:00 2001 From: jialin Date: Wed, 20 May 2026 11:33:39 +0800 Subject: [PATCH] chore: ssh key selection --- src/atoms/gpuservice.ts | 4 + src/locales/en-US/gpuservice.ts | 3 + src/locales/en-US/no-result.ts | 6 +- src/locales/ja-JP/gpuservice.ts | 3 + src/locales/ja-JP/no-result.ts | 5 +- src/locales/ru-RU/gpuservice.ts | 3 + src/locales/ru-RU/no-result.ts | 6 +- src/locales/tr-TR/gpuservice.ts | 3 + src/locales/tr-TR/no-result.ts | 5 +- src/locales/zh-CN/gpuservice.ts | 3 + src/locales/zh-CN/no-result.ts | 5 +- .../gpu-service/instances/forms/index.tsx | 87 ++++++++++++++----- .../instances/forms/instance-type.tsx | 2 +- 13 files changed, 107 insertions(+), 28 deletions(-) diff --git a/src/atoms/gpuservice.ts b/src/atoms/gpuservice.ts index f7f9df55..2b33c050 100644 --- a/src/atoms/gpuservice.ts +++ b/src/atoms/gpuservice.ts @@ -4,3 +4,7 @@ import { atom } from 'jotai'; export const currentClusterAtom = atom< (Partial & { label?: string; value?: number }) | null >(null); + +export const addSSHKeyPageAtom = atom<{ create: boolean }>({ + create: false +}); diff --git a/src/locales/en-US/gpuservice.ts b/src/locales/en-US/gpuservice.ts index b922b3a1..c2ee160b 100644 --- a/src/locales/en-US/gpuservice.ts +++ b/src/locales/en-US/gpuservice.ts @@ -40,6 +40,9 @@ export default { 'gpuservice.template.card.resources': 'Resources', 'gpuservice.template.card.ports': 'Ports', 'gpuservice.publicKey.label': 'SSH Public Key', + 'gpuservice.instance.ssh.enable': 'Enable SSH Access', + 'gpuservice.instance.ssh.assignKey': 'Assign SSH Public Key', + 'gpuservice.instance.ssh.addKey': 'Add SSH Public Key', 'gpuservice.publicKey.placeholder': 'Begin with ssh-rsa or ssh-ed25519. One Public Key per line.\n\nView Public Key:\n- RSA\ncat ~/.ssh/id_rsa.pub\n- Ed25519\ncat ~/.ssh/id_ed25519.pub', 'gpuservice.instance': 'GPU Instance', diff --git a/src/locales/en-US/no-result.ts b/src/locales/en-US/no-result.ts index d42fce82..a7d91b8f 100644 --- a/src/locales/en-US/no-result.ts +++ b/src/locales/en-US/no-result.ts @@ -64,5 +64,9 @@ export default { 'noresult.gpuservice.instance.nofound': 'No matching GPU instances found.', 'noresult.gpuservice.storage.title': 'No Storage', 'noresult.gpuservice.storage.subTitle': 'No storage has been added yet.', - 'noresult.gpuservice.storage.nofound': 'No matching storage found.' + 'noresult.gpuservice.storage.nofound': 'No matching storage found.', + 'noresult.gpuservice.sshkey.title': 'No SSH Public Keys', + 'noresult.gpuservice.sshkey.subTitle': + 'No SSH public keys have been added yet.', + 'noresult.gpuservice.sshkey.nofound': 'No matching SSH public keys found.' }; diff --git a/src/locales/ja-JP/gpuservice.ts b/src/locales/ja-JP/gpuservice.ts index c022e1a4..60a9e9b5 100644 --- a/src/locales/ja-JP/gpuservice.ts +++ b/src/locales/ja-JP/gpuservice.ts @@ -38,6 +38,9 @@ export default { 'gpuservice.template.card.resources': 'リソース', 'gpuservice.template.card.ports': 'ポート', 'gpuservice.publicKey.label': 'SSH 公開鍵', + 'gpuservice.instance.ssh.enable': 'SSH アクセスを有効化', + 'gpuservice.instance.ssh.assignKey': 'SSH 公開鍵を割り当て', + 'gpuservice.instance.ssh.addKey': 'SSH 公開鍵を追加', 'gpuservice.publicKey.placeholder': 'ssh-rsa または ssh-ed25519 で始まり、各公開鍵は1行ずつ記述します\n\n公開鍵を確認:\n- RSA\ncat ~/.ssh/id_rsa.pub\n- Ed25519\ncat ~/.ssh/id_ed25519.pub', 'gpuservice.instance': 'GPU インスタンス', diff --git a/src/locales/ja-JP/no-result.ts b/src/locales/ja-JP/no-result.ts index 2fd7ec4c..9e0e86ec 100644 --- a/src/locales/ja-JP/no-result.ts +++ b/src/locales/ja-JP/no-result.ts @@ -66,5 +66,8 @@ export default { 'noresult.gpuservice.storage.title': 'ストレージなし', 'noresult.gpuservice.storage.subTitle': 'ストレージはまだ追加されていません。', - 'noresult.gpuservice.storage.nofound': '一致するストレージが見つかりません。' + 'noresult.gpuservice.storage.nofound': '一致するストレージが見つかりません。', + 'noresult.gpuservice.sshkey.title': 'SSH 公開鍵なし', + 'noresult.gpuservice.sshkey.subTitle': 'SSH 公開鍵はまだ追加されていません。', + 'noresult.gpuservice.sshkey.nofound': '一致する SSH 公開鍵が見つかりません。' }; diff --git a/src/locales/ru-RU/gpuservice.ts b/src/locales/ru-RU/gpuservice.ts index d2358c18..3b755956 100644 --- a/src/locales/ru-RU/gpuservice.ts +++ b/src/locales/ru-RU/gpuservice.ts @@ -41,6 +41,9 @@ export default { 'gpuservice.template.card.resources': 'Ресурсы', 'gpuservice.template.card.ports': 'Порты', 'gpuservice.publicKey.label': 'Открытый ключ SSH', + 'gpuservice.instance.ssh.enable': 'Включить SSH-доступ', + 'gpuservice.instance.ssh.assignKey': 'Назначить открытый ключ SSH', + 'gpuservice.instance.ssh.addKey': 'Добавить открытый ключ SSH', 'gpuservice.publicKey.placeholder': 'Начинается с ssh-rsa или ssh-ed25519, по одному открытому ключу на строку\n\nПросмотр открытого ключа:\n- RSA\ncat ~/.ssh/id_rsa.pub\n- Ed25519\ncat ~/.ssh/id_ed25519.pub', 'gpuservice.instance': 'Экземпляр GPU', diff --git a/src/locales/ru-RU/no-result.ts b/src/locales/ru-RU/no-result.ts index c8de8586..53b6b0db 100644 --- a/src/locales/ru-RU/no-result.ts +++ b/src/locales/ru-RU/no-result.ts @@ -65,7 +65,11 @@ export default { 'Подходящие экземпляры GPU не найдены.', 'noresult.gpuservice.storage.title': 'Нет хранилищ', 'noresult.gpuservice.storage.subTitle': 'Хранилища ещё не добавлены.', - 'noresult.gpuservice.storage.nofound': 'Подходящие хранилища не найдены.' + 'noresult.gpuservice.storage.nofound': 'Подходящие хранилища не найдены.', + 'noresult.gpuservice.sshkey.title': 'Нет открытых ключей SSH', + 'noresult.gpuservice.sshkey.subTitle': 'Открытые ключи SSH ещё не добавлены.', + 'noresult.gpuservice.sshkey.nofound': + 'Подходящие открытые ключи SSH не найдены.' }; // ========== To-Do: Translate Keys (Remove After Translation) ========== diff --git a/src/locales/tr-TR/gpuservice.ts b/src/locales/tr-TR/gpuservice.ts index 945067e4..c93cc2c3 100644 --- a/src/locales/tr-TR/gpuservice.ts +++ b/src/locales/tr-TR/gpuservice.ts @@ -40,6 +40,9 @@ export default { 'gpuservice.template.card.resources': 'Kaynaklar', 'gpuservice.template.card.ports': 'Bağlantı Noktaları', 'gpuservice.publicKey.label': 'SSH Açık Anahtarı', + 'gpuservice.instance.ssh.enable': 'SSH Erişimini Etkinleştir', + 'gpuservice.instance.ssh.assignKey': 'SSH Açık Anahtarı Ata', + 'gpuservice.instance.ssh.addKey': 'SSH Açık Anahtarı Ekle', 'gpuservice.publicKey.placeholder': 'ssh-rsa veya ssh-ed25519 ile başlar, her açık anahtar ayrı bir satırda\n\nAçık anahtarı görüntüle:\n- RSA\ncat ~/.ssh/id_rsa.pub\n- Ed25519\ncat ~/.ssh/id_ed25519.pub', 'gpuservice.instance': 'GPU Örneği', diff --git a/src/locales/tr-TR/no-result.ts b/src/locales/tr-TR/no-result.ts index 46237449..dd7c03d6 100644 --- a/src/locales/tr-TR/no-result.ts +++ b/src/locales/tr-TR/no-result.ts @@ -63,7 +63,10 @@ export default { 'noresult.gpuservice.instance.nofound': 'Eşleşen GPU örneği bulunamadı.', 'noresult.gpuservice.storage.title': 'Depolama Yok', 'noresult.gpuservice.storage.subTitle': 'Henüz depolama eklenmedi.', - 'noresult.gpuservice.storage.nofound': 'Eşleşen depolama bulunamadı.' + 'noresult.gpuservice.storage.nofound': 'Eşleşen depolama bulunamadı.', + 'noresult.gpuservice.sshkey.title': 'SSH Açık Anahtarı Yok', + 'noresult.gpuservice.sshkey.subTitle': 'Henüz SSH açık anahtarı eklenmedi.', + 'noresult.gpuservice.sshkey.nofound': 'Eşleşen SSH açık anahtarı bulunamadı.' }; // ========== To-Do: Translate Keys (Remove After Translation) ========== diff --git a/src/locales/zh-CN/gpuservice.ts b/src/locales/zh-CN/gpuservice.ts index 42eb0746..cd98679f 100644 --- a/src/locales/zh-CN/gpuservice.ts +++ b/src/locales/zh-CN/gpuservice.ts @@ -35,6 +35,9 @@ export default { 'gpuservice.template.card.resources': '资源', 'gpuservice.template.card.ports': '端口', 'gpuservice.publicKey.label': 'SSH 公钥', + 'gpuservice.instance.ssh.enable': '启用 SSH 访问', + 'gpuservice.instance.ssh.assignKey': '分配 SSH 公钥', + 'gpuservice.instance.ssh.addKey': '添加 SSH 公钥', 'gpuservice.publicKey.placeholder': '以 ssh-rsa 或 ssh-ed25519 开头,每个公钥单独一行\n\n查看公钥:\n- RSA\ncat ~/.ssh/id_rsa.pub\n- Ed25519\ncat ~/.ssh/id_ed25519.pub', 'gpuservice.instance': 'GPU 实例', diff --git a/src/locales/zh-CN/no-result.ts b/src/locales/zh-CN/no-result.ts index b1f357b8..d369efd2 100644 --- a/src/locales/zh-CN/no-result.ts +++ b/src/locales/zh-CN/no-result.ts @@ -59,5 +59,8 @@ export default { 'noresult.gpuservice.instance.nofound': '未找到匹配的 GPU 实例', 'noresult.gpuservice.storage.title': '暂无存储', 'noresult.gpuservice.storage.subTitle': '尚未添加任何存储。', - 'noresult.gpuservice.storage.nofound': '未找到匹配的存储' + 'noresult.gpuservice.storage.nofound': '未找到匹配的存储', + 'noresult.gpuservice.sshkey.title': '暂无 SSH 公钥', + 'noresult.gpuservice.sshkey.subTitle': '尚未添加任何 SSH 公钥。', + 'noresult.gpuservice.sshkey.nofound': '未找到匹配的 SSH 公钥' }; diff --git a/src/pages/gpu-service/instances/forms/index.tsx b/src/pages/gpu-service/instances/forms/index.tsx index 6a9e3d05..db45a653 100644 --- a/src/pages/gpu-service/instances/forms/index.tsx +++ b/src/pages/gpu-service/instances/forms/index.tsx @@ -1,17 +1,21 @@ +import { addSSHKeyPageAtom } from '@/atoms/gpuservice'; import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; +import { PlusOutlined } from '@ant-design/icons'; import { CheckboxField, CollapsePanel, IconFont, MultipleSelect, ScrollSpyTabs, + useAppUtils, useFinishFailed, useScrollActiveChange, useWrapperContext } from '@gpustack/core-ui'; -import { useIntl } from '@umijs/max'; -import { Form } from 'antd'; +import { useIntl, useNavigate } from '@umijs/max'; +import { Button, Empty, Form } from 'antd'; +import { useSetAtom } from 'jotai'; import { forwardRef, useEffect, @@ -96,6 +100,9 @@ const GPUServiceInstanceForm: React.FC = forwardRef( onFinish } = props; const intl = useIntl(); + const navigate = useNavigate(); + const setAddSSHKeyPage = useSetAtom(addSSHKeyPageAtom); + const { getRuleMessage } = useAppUtils(); const [form] = Form.useForm(); const scrollTabsRef = useRef(null); const formAction = @@ -278,6 +285,12 @@ const GPUServiceInstanceForm: React.FC = forwardRef( getFieldsValue: () => form.getFieldsValue() })); + const handleAddSSHKey = () => { + setAddSSHKeyPage({ create: true }); + // to go ssh key page + navigate('/gpu-service/public-keys'); + }; + return ( = forwardRef( resources: { accelerator: '1' }, - sshPublicKey: { - name: 'gpustack-ssh-public-key' - }, volume: { ephemeral: { capacity: '20Gi' @@ -379,37 +389,70 @@ const GPUServiceInstanceForm: React.FC = forwardRef( > {sshEnabled && (
- name={['spec', 'sshPublicKey', 'name']}> + + name={['spec', 'sshPublicKey', 'name']} + style={{ + marginBottom: 12 + }} + rules={[ + { + required: true, + message: getRuleMessage( + 'select', + 'gpuservice.instance.ssh.assignKey' + ) + } + ]} + > + + + } >
diff --git a/src/pages/gpu-service/instances/forms/instance-type.tsx b/src/pages/gpu-service/instances/forms/instance-type.tsx index 531e9c63..27325a6b 100644 --- a/src/pages/gpu-service/instances/forms/instance-type.tsx +++ b/src/pages/gpu-service/instances/forms/instance-type.tsx @@ -118,7 +118,7 @@ const InstanceTypeFormItem: React.FC = ({ - {!selectedInstanceType?.spec?.acceleratable && ( + {selectedInstanceType?.spec?.acceleratable && (