From 28cded2a290efa3d3833056a5ab22b25fafbb6ea Mon Sep 17 00:00:00 2001 From: "Jingwei.Zhang" Date: Wed, 6 Jul 2022 15:40:51 +0800 Subject: [PATCH] feat: support create key pair when create instance 1. Support create key pair in the third step of instance creating 2. Auto select the new key pair after creating Change-Id: Ib9f0745a7b04b764e1ab7582716d1c82a5bcc1f9 --- src/locales/en.json | 2 +- src/locales/zh.json | 2 +- .../actions/StepCreate/SystemStep/index.jsx | 64 +++++++++++++++++-- .../Instance/actions/StepCreate/index.less | 13 ++++ src/stores/nova/keypair.js | 12 ++++ 5 files changed, 87 insertions(+), 6 deletions(-) diff --git a/src/locales/en.json b/src/locales/en.json index eb85b985..92fafd89 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -2023,7 +2023,6 @@ "Share Type ID": "Share Type ID", "Share Type Name": "Share Type Name", "Share Types": "Share Types", - "Share group": "Share group", "Shared": "Shared", "Shared Image": "Shared Image", "Shared Network": "Shared Network", @@ -2232,6 +2231,7 @@ "The instances in the anti-affinity group are strictly allocated to different physical machines. When there are no more physical machines to allocate, the allocation fails.": "The instances in the anti-affinity group are strictly allocated to different physical machines. When there are no more physical machines to allocate, the allocation fails.", "The ip is not within the allocated pool!": "The ip is not within the allocated pool!", "The ip of external members can be any, including the public network ip.": "The ip of external members can be any, including the public network ip.", + "The key pair allows you to SSH into your newly created instance. You can select an existing key pair, import a key pair, or generate a new key pair.": "The key pair allows you to SSH into your newly created instance. You can select an existing key pair, import a key pair, or generate a new key pair.", "The kill signal to send": "The kill signal to send", "The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.": "The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.", "The min size is {size} GiB": "The min size is {size} GiB", diff --git a/src/locales/zh.json b/src/locales/zh.json index 26745b6b..dc8ce959 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -2023,7 +2023,6 @@ "Share Type ID": "共享类型ID", "Share Type Name": "共享类型名称", "Share Types": "共享类型", - "Share group": "", "Shared": "共享", "Shared Image": "共享镜像", "Shared Network": "共享网络", @@ -2232,6 +2231,7 @@ "The instances in the anti-affinity group are strictly allocated to different physical machines. When there are no more physical machines to allocate, the allocation fails.": "将反亲和组内的云主机严格分配到不同物理机上,当没有更多物理机可分配时,则分配失败。", "The ip is not within the allocated pool!": "该ip不在分配的资源池范围内!", "The ip of external members can be any, including the public network ip.": "外部成员的IP可以是任何IP,包括公网IP。", + "The key pair allows you to SSH into your newly created instance. You can select an existing key pair, import a key pair, or generate a new key pair.": "密钥对允许您SSH到您新创建的实例。 您可以选择一个已存在的密钥对、导入一个密钥对或生成一个新的密钥对。", "The kill signal to send": "要发送的终止信号", "The maximum transmission unit (MTU) value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.": "地址片段的最大传输单位。IPv4最小68,IPv6最小1280。", "The min size is {size} GiB": "最小内存为 {size} GiB", diff --git a/src/pages/compute/containers/Instance/actions/StepCreate/SystemStep/index.jsx b/src/pages/compute/containers/Instance/actions/StepCreate/SystemStep/index.jsx index 92430fab..d16bf11d 100644 --- a/src/pages/compute/containers/Instance/actions/StepCreate/SystemStep/index.jsx +++ b/src/pages/compute/containers/Instance/actions/StepCreate/SystemStep/index.jsx @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import React from 'react'; import { inject, observer } from 'mobx-react'; import globalKeyPairStore from 'stores/nova/keypair'; import globalServerStore from 'stores/nova/instance'; @@ -26,6 +27,9 @@ import { } from 'resources/nova/hypervisor'; import { physicalNodeTypes } from 'resources/nova/instance'; import { getOptions } from 'utils'; +import CreateKeyPair from 'pages/compute/containers/Keypair/actions/Create'; +import ItemActionButtons from 'components/Tables/Base/ItemActionButtons'; +import styles from '../index.less'; export class SystemStep extends Base { init() { @@ -151,6 +155,13 @@ export class SystemStep extends Base { selectedRows: this.serverGroups.filter((it) => it.id === servergroup), }; } + const { initKeyPair, name } = this.state; + if (initKeyPair) { + data.keypair = initKeyPair; + } + if (name) { + data.name = name; + } return data; } @@ -170,8 +181,8 @@ export class SystemStep extends Base { allowed = () => Promise.resolve(); - getKeypairs() { - this.keyPairStore.fetchList(); + async getKeypairs() { + return this.keyPairStore.fetchList(); } getHypervisors() { @@ -185,6 +196,7 @@ export class SystemStep extends Base { get nameForStateUpdate() { return [ + 'name', 'loginType', 'password', 'confirmPassword', @@ -197,17 +209,60 @@ export class SystemStep extends Base { return this.sourceInfo && this.sourceInfo.os_admin_user; } + onFinishCreateKeyPair = async () => { + const { createdItem } = this.keyPairStore; + const result = await this.getKeypairs(); + const newItem = result.find((it) => it.name === (createdItem || {}).name); + if (newItem) { + const initKeyPair = { + selectedRowKeys: [newItem.id], + selectedRows: [newItem], + }; + this.setState( + { + initKeyPair, + }, + () => { + this.updateDefaultValue(); + } + ); + } + }; + + getKeyPairHeader() { + const { isLoading } = this.keyPairStore.list || {}; + if (isLoading) { + return null; + } + return ( +
+ + {t( + 'The key pair allows you to SSH into your newly created instance. You can select an existing key pair, import a key pair, or generate a new key pair.' + )} + + + + +
+ ); + } + get formItems() { const { loginType, more = false, physicalNodeType } = this.state; const isPassword = loginType === this.loginTypes[1].value; const isManually = physicalNodeType === physicalNodeTypes[1].value; + const { initKeyPair } = this.state; + return [ { name: 'name', label: t('Name'), type: 'input-name', - placeholder: t('Please input name'), required: true, isInstance: true, }, @@ -237,9 +292,10 @@ export class SystemStep extends Base { type: 'select-table', data: this.keypairs, isLoading: this.keyPairStore.list.isLoading, - isMulti: false, required: !isPassword, hidden: isPassword, + header: this.getKeyPairHeader(), + initValue: initKeyPair, tip: t( 'The SSH key is a way to remotely log in to the instance. The cloud platform only helps to keep the public key. Please keep your private key properly.' ), diff --git a/src/pages/compute/containers/Instance/actions/StepCreate/index.less b/src/pages/compute/containers/Instance/actions/StepCreate/index.less index 3eb55de1..d25136f1 100644 --- a/src/pages/compute/containers/Instance/actions/StepCreate/index.less +++ b/src/pages/compute/containers/Instance/actions/StepCreate/index.less @@ -1,3 +1,5 @@ +@import '~styles/variables'; + .input { margin-right: 32px; margin-left: 16px; @@ -6,3 +8,14 @@ .number-input { min-width: 165px; } + +.action-wrapper { + margin-left: 8px; + + :global { + .ant-btn-link { + padding: 5.6px 15px !important; + border-color: @primary-color; + } + } +} diff --git a/src/stores/nova/keypair.js b/src/stores/nova/keypair.js index 116a9415..4c6b5688 100644 --- a/src/stores/nova/keypair.js +++ b/src/stores/nova/keypair.js @@ -12,10 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { action, observable } from 'mobx'; import client from 'client'; import Base from 'stores/base'; export class KeypairStore extends Base { + @observable + createdItem = null; + get client() { return client.nova.keypairs; } @@ -36,6 +40,14 @@ export class KeypairStore extends Base { return item; }; } + + @action + async create(data) { + const body = {}; + body[this.responseKey] = data; + this.createdItem = data; + return this.submitting(this.client.create(body)); + } } const globalKeypairStore = new KeypairStore();