diff --git a/src/components/Form/index.jsx b/src/components/Form/index.jsx index 603515f8..1af0f841 100644 --- a/src/components/Form/index.jsx +++ b/src/components/Form/index.jsx @@ -242,6 +242,10 @@ export default class BaseForm extends React.Component { return false; } + getSubmitData(data) { + return { ...data }; + } + updateContext = (allFields) => { const { updateContext } = this.props; updateContext && updateContext(allFields); @@ -271,7 +275,8 @@ export default class BaseForm extends React.Component { if (!this.onSubmit) { return callback(true, false); } - return this.onSubmit(values, containerProps).then( + const submitData = this.getSubmitData(values); + return this.onSubmit(submitData, containerProps).then( (response) => { this.updateSumbitting(false); !this.isModal && this.routing.push(this.listUrl); diff --git a/src/components/FormItem/NetworkSelectTable/index.jsx b/src/components/FormItem/NetworkSelectTable/index.jsx index d6926e91..aeb32766 100644 --- a/src/components/FormItem/NetworkSelectTable/index.jsx +++ b/src/components/FormItem/NetworkSelectTable/index.jsx @@ -20,9 +20,7 @@ import { yesNoOptions } from 'utils/constants'; import { networkColumns, networkSortProps } from 'resources/network'; import { isAdminPage } from 'utils/index'; -@inject('rootStore') -@observer -export default class NetworkSelectTable extends Component { +export class NetworkSelectTable extends Component { constructor(props) { super(props); this.stores = { @@ -188,3 +186,5 @@ export default class NetworkSelectTable extends Component { ); } } + +export default inject('rootStore')(observer(NetworkSelectTable)); diff --git a/src/components/StepForm/index.jsx b/src/components/StepForm/index.jsx index 77dcf3de..51c71eea 100644 --- a/src/components/StepForm/index.jsx +++ b/src/components/StepForm/index.jsx @@ -233,7 +233,8 @@ export default class BaseStepForm extends React.Component { // eslint-disable-next-line no-console console.log('onOk', data); this.values = data; - this.onSubmit(data).then( + const submitData = this.getSubmitData(data); + this.onSubmit(submitData).then( () => { this.routing.push(this.listUrl); Notify.success(this.successText); @@ -276,6 +277,10 @@ export default class BaseStepForm extends React.Component { ); } + getSubmitData(data) { + return { ...data }; + } + updateDataOnPrev = (values) => { this.updateData(values, () => { // const current = this.state.current - 1; diff --git a/src/locales/en.json b/src/locales/en.json index da5aee9e..282b1df2 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -67,7 +67,6 @@ "Affinity (mandatory):": "Affinity (mandatory):", "Affinity (not mandatory):": "Affinity (not mandatory):", "After attaching interface, you may need to login the instance to update the network interface configuration and restart the network service.": "After attaching interface, you may need to login the instance to update the network interface configuration and restart the network service.", - "After deletion, the instance will be stored in the recycle bin, which will be reserved for 7 * 24h by default and can be restored within the period. After successful recovery, the status of the instance is running and related resources remain unchanged.": "After deletion, the instance will be stored in the recycle bin, which will be reserved for 7 * 24h by default and can be restored within the period. After successful recovery, the status of the instance is running and related resources remain unchanged.", "After disable the compute service, the new instance will not schedule to the compute node.": "After disable the compute service, the new instance will not schedule to the compute node.", "After shelving, the instance will be shut down, resources will be released, and the snapshot will be saved to Glance. This will take about a few minutes, please be patient. You also can choose to unshelve to restore the instance.": "After shelving, the instance will be shut down, resources will be released, and the snapshot will be saved to Glance. This will take about a few minutes, please be patient. You also can choose to unshelve to restore the instance.", "After the instance is deleted, the instance root disk data will be lost. ": "After the instance is deleted, the instance root disk data will be lost. ", @@ -774,8 +773,7 @@ "If the volume associated with the snapshot has changed the volume type, please modify this option manually; if the volume associated with the snapshot keeps the volume type unchanged, please ignore this option. (no need to change).": "If the volume associated with the snapshot has changed the volume type, please modify this option manually; if the volume associated with the snapshot keeps the volume type unchanged, please ignore this option. (no need to change).", "If you are not authorized to access any project, or if the project you are involved in has been deleted or disabled, contact the platform administrator to reassign the project": "If you are not authorized to access any project, or if the project you are involved in has been deleted or disabled, contact the platform administrator to reassign the project", "If you do not fill in parameters such as cpus, memory_mb, local_gb, cpu_arch, etc., you can automatically inject the configuration and Mac address of the physical machine by performing the \"Auto Inspect\" operation.": "If you do not fill in parameters such as cpus, memory_mb, local_gb, cpu_arch, etc., you can automatically inject the configuration and Mac address of the physical machine by performing the \"Auto Inspect\" operation.", - "If you still want to keep the disk data, it is recommended that you create a snapshot for the disk before deleting, or create a snapshot for instance.": "If you still want to keep the disk data, it is recommended that you create a snapshot for the disk before deleting, or create a snapshot for instance.", - "If you still want to keep the root disk data, it is recommended that you create a backup for the root disk before deleting, or upload the instance snapshot as an image.": "If you still want to keep the root disk data, it is recommended that you create a backup for the root disk before deleting, or upload the instance snapshot as an image.", + "If you still want to keep the disk data, it is recommended that you create a snapshot for the disk before deleting.": "If you still want to keep the disk data, it is recommended that you create a snapshot for the disk before deleting.", "Illegal JSON scheme": "Illegal JSON scheme", "Image": "Image", "Image & OS": "Image & OS", @@ -1371,7 +1369,6 @@ "Rollback Failed": "Rollback Failed", "Rollback In Progress": "Rollback In Progress", "Root Disk": "Root Disk", - "Root disk snapshot": "Root disk snapshot", "Router": "Router", "Router Detail": "Router Detail", "Router External": "Router External", @@ -1556,7 +1553,6 @@ "The description can be up to 255 characters long.": "The description can be up to 255 characters long.", "The entire inspection process takes 5 to 10 minutes, so you need to be patient. After the registration is completed, the node configuration status will return to the manageable status.": "The entire inspection process takes 5 to 10 minutes, so you need to be patient. After the registration is completed, the node configuration status will return to the manageable status.", "The feasible configuration of cloud-init or cloudbase-init service in the image is not synced to image's properties, so the Login Name is unknown.": "The feasible configuration of cloud-init or cloudbase-init service in the image is not synced to image's properties, so the Login Name is unknown.", - "The instance": "The instance", "The instance architecture diagram mainly shows the overall architecture composition of the instance. If you need to view the network topology of the instance, please go to: ": "The instance architecture diagram mainly shows the overall architecture composition of the instance. If you need to view the network topology of the instance, please go to: ", "The instance deleted immediately cannot be restored": "The instance deleted immediately cannot be restored", "The instance is not shut down, unable to restore.": "The instance is not shut down, unable to restore.", @@ -1585,7 +1581,6 @@ "The port created here will be automatically deleted when detach. If you need a reusable port, please go to the Virtual Adapter page to create and attach the port to instance.": "The port created here will be automatically deleted when detach. If you need a reusable port, please go to the Virtual Adapter page to create and attach the port to instance.", "The port of this fip is in use, Please change another port.": "The port of this fip is in use, Please change another port.", "The resource class of the scheduled node needs to correspond to the resource class name of the flavor used by the ironic instance (for example, the resource class name of the scheduling node is baremetal.with-GPU, and the custom resource class name of the flavor is CUSTOM_BAREMETAL_WITH_GPU=1).": "The resource class of the scheduled node needs to correspond to the resource class name of the flavor used by the ironic instance (for example, the resource class name of the scheduling node is baremetal.with-GPU, and the custom resource class name of the flavor is CUSTOM_BAREMETAL_WITH_GPU=1).", - "The root disk of the instance": "The root disk of the instance", "The security group is similar to the firewall function and is used to set up network access control. ": "The security group is similar to the firewall function and is used to set up network access control. ", "The security group is similar to the firewall function for setting up network access control, or you can go to the console and create a new security group. (Note: The security group you selected will work on all virtual LANS on the instances.)": "The security group is similar to the firewall function for setting up network access control, or you can go to the console and create a new security group. (Note: The security group you selected will work on all virtual LANS on the instances.)", "The selected VPC/ subnet does not have IPv6 enabled.": "The selected VPC/ subnet does not have IPv6 enabled.", @@ -1758,8 +1753,8 @@ "Weights": "Weights", "Welcome": "Welcome", "Welcome, {name}": "Welcome, {name}", + "When the computing service starts the recycling instance interval, the instance will be stored in the recycling bin after deletion, and will be retained according to the corresponding time interval. You can choose to restore it within this period. After successful recovery, the status of the instance is running and related resources remain unchanged.": "When the computing service starts the recycling instance interval, the instance will be stored in the recycling bin after deletion, and will be retained according to the corresponding time interval. You can choose to restore it within this period. After successful recovery, the status of the instance is running and related resources remain unchanged.", "When the volume is \"bootable\" and the status is \"available\", it can be used as a startup source to create an instance.": "When the volume is \"bootable\" and the status is \"available\", it can be used as a startup source to create an instance.", - "When you delete an instance, the following resources will be released(Non-root disks will be unmounted and retained):": "When you delete an instance, the following resources will be released(Non-root disks will be unmounted and retained):", "When you do online backup of the volume that has been bound, you need to pay attention to the following points:": "When you do online backup of the volume that has been bound, you need to pay attention to the following points:", "When you restore a backup, you need to meet one of the following conditions:": "When you restore a backup, you need to meet one of the following conditions:", "When you restore a snapshot, one of the following conditions must be met:": "When you restore a snapshot, one of the following conditions must be met:", diff --git a/src/locales/zh.json b/src/locales/zh.json index 4cb4c1ef..26d2be76 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -67,7 +67,6 @@ "Affinity (mandatory):": "亲和(强制):", "Affinity (not mandatory):": "亲和 (非强制):", "After attaching interface, you may need to login the instance to update the network interface configuration and restart the network service.": "挂载网卡后,您可能需要登录到云主机更新网卡配置并且重启网络服务。", - "After deletion, the instance will be stored in the recycle bin, which will be reserved for 7 * 24h by default and can be restored within the period. After successful recovery, the status of the instance is running and related resources remain unchanged.": "删除后云主机会存放在回收站,默认保留 7 * 24 小时,在期限内可以选择恢复。恢复成功后的云主机状态为运行中,且相关资源保持不变。", "After disable the compute service, the new instance will not schedule to the compute node.": "禁用计算服务之后,新的云主机不会调度到该计算节点。", "After shelving, the instance will be shut down, resources will be released, and the snapshot will be saved to Glance. This will take about a few minutes, please be patient. You also can choose to unshelve to restore the instance.": "归档后会关闭云主机,释放资源,并将快照保存到 Glance ,这大约需要数分钟时间,请耐心等待。在归档之后您也可以选择取消归档来恢复这台云主机。", "After the instance is deleted, the instance root disk data will be lost. ": "删除云主机后,云主机根硬盘数据将丢失。", @@ -774,8 +773,7 @@ "If the volume associated with the snapshot has changed the volume type, please modify this option manually; if the volume associated with the snapshot keeps the volume type unchanged, please ignore this option. (no need to change).": "若快照关联的云硬盘修改过云硬盘类型,请手动修改此选项;若快照关联的云硬盘保持云硬盘类型不变,请忽略此选项(不需要做变更)。", "If you are not authorized to access any project, or if the project you are involved in has been deleted or disabled, contact the platform administrator to reassign the project": "您未被授权访问任何项目,或您参与中的项目已被删除或禁用,可联系平台管理员重新分配项目", "If you do not fill in parameters such as cpus, memory_mb, local_gb, cpu_arch, etc., you can automatically inject the configuration and Mac address of the physical machine by performing the \"Auto Inspect\" operation.": "如不填写cpus、memory_mb、local_gb、cpu_arch等参数,您可以通过执行“自动检测”操作来自动注入物理机的配置和 Mac 地址。", - "If you still want to keep the disk data, it is recommended that you create a snapshot for the disk before deleting, or create a snapshot for instance.": "如果您仍想保留云硬盘数据,建议您在删除之前为云硬盘创建快照,或者为云主机创建快照。", - "If you still want to keep the root disk data, it is recommended that you create a backup for the root disk before deleting, or upload the instance snapshot as an image.": "如果您仍想保留根硬盘数据,建议您在删除之前为根硬盘创建备份,或者将云主机快照上传为镜像。", + "If you still want to keep the disk data, it is recommended that you create a snapshot for the disk before deleting.": "如果您仍想保留云硬盘数据,建议您在删除之前为云硬盘创建快照。", "Illegal JSON scheme": "不合法的JSON格式", "Image": "镜像", "Image & OS": "镜像和操作系统", @@ -1371,7 +1369,6 @@ "Rollback Failed": "回滚失败", "Rollback In Progress": "回滚中", "Root Disk": "系统盘", - "Root disk snapshot": "根硬盘快照", "Router": "路由器", "Router Detail": "路由器详情", "Router External": "外部网关", @@ -1556,7 +1553,6 @@ "The description can be up to 255 characters long.": "描述最长为255字符", "The entire inspection process takes 5 to 10 minutes, so you need to be patient. After the registration is completed, the node configuration status will return to the manageable status.": "检查的整个过程需要耗费 5 到 10 分钟时间,您需要耐心等待。在完成注册后,节点配置状态会重新回到可管理状态。", "The feasible configuration of cloud-init or cloudbase-init service in the image is not synced to image's properties, so the Login Name is unknown.": "镜像中的cloud-init或cloudbase-init服务的预制配置未同步至镜像属性, 登录名未知", - "The instance": "云主机", "The instance architecture diagram mainly shows the overall architecture composition of the instance. If you need to view the network topology of the instance, please go to: ": "云主机架构图主要展示云主机的总体架构组成。如果需要查看云主机的网络拓扑,请转到:", "The instance deleted immediately cannot be restored": "立即删除的云主机无法恢复", "The instance is not shut down, unable to restore.": "云主机不处于关机状态,不支持恢复备份操作。", @@ -1585,7 +1581,6 @@ "The port created here will be automatically deleted when detach. If you need a reusable port, please go to the Virtual Adapter page to create and attach the port to instance.": "此处创建的网卡会在卸载的时候被自动删除,如果需要可复用的网卡,请前往虚拟网卡页面创建再从虚拟网卡页面绑定云主机。", "The port of this fip is in use, Please change another port.": "FIP的此端口已经在使用中,请更换另一个端口。", "The resource class of the scheduled node needs to correspond to the resource class name of the flavor used by the ironic instance (for example, the resource class name of the scheduling node is baremetal.with-GPU, and the custom resource class name of the flavor is CUSTOM_BAREMETAL_WITH_GPU=1).": "被调度节点的资源类需要与裸机实例使用的云主机类型的资源类名称对应(比如:调度节点的资源类名称为 baremetal.with-GPU,云主机类型的资源类名称为CUSTOM_BAREMETAL_WITH_GPU=1 )。", - "The root disk of the instance": "云主机根硬盘", "The security group is similar to the firewall function and is used to set up network access control. ": "安全组类似防火墙功能,用于设置网络访问控制。", "The security group is similar to the firewall function for setting up network access control, or you can go to the console and create a new security group. (Note: The security group you selected will work on all virtual LANS on the instances.)": "安全组类似防火墙功能,用于设置网络访问控制,您也可以前往控制台新建安全组。(注:您所选的安全组将作用于云主机的全部虚拟网卡。)", "The selected VPC/ subnet does not have IPv6 enabled.": "所选的VPC/子网未开通IPv6", @@ -1758,8 +1753,8 @@ "Weights": "权重", "Welcome": "欢迎", "Welcome, {name}": "欢迎,登录{name}", + "When the computing service starts the recycling instance interval, the instance will be stored in the recycling bin after deletion, and will be retained according to the corresponding time interval. You can choose to restore it within this period. After successful recovery, the status of the instance is running and related resources remain unchanged.": "当计算服务开启回收实例间隔时,删除后云主机会存放在回收站,按对应的时间间隔保留,在此期限内可以选择恢复。恢复成功后的云主机状态为运行中,且相关资源保持不变。", "When the volume is \"bootable\" and the status is \"available\", it can be used as a startup source to create an instance.": "云硬盘为“可启用”并且状态为“可用”时,可以作为启动源来创建云主机。", - "When you delete an instance, the following resources will be released(Non-root disks will be unmounted and retained):": "删除云主机时,将释放以下资源(非根硬盘将会卸载并保留):", "When you do online backup of the volume that has been bound, you need to pay attention to the following points:": "当您对已经绑定的硬盘做在线备份时,需要注意以下几点:", "When you restore a backup, you need to meet one of the following conditions:": "当您恢复备份时,需要满足以下条件之一:", "When you restore a snapshot, one of the following conditions must be met:": "当您恢复快照时,需要满足以下条件之一:", diff --git a/src/pages/compute/containers/Instance/Detail/SecurityGroup/action/ManageSecurityGroup.jsx b/src/pages/compute/containers/Instance/Detail/SecurityGroup/action/ManageSecurityGroup.jsx index 74f972a6..bd0faba5 100644 --- a/src/pages/compute/containers/Instance/Detail/SecurityGroup/action/ManageSecurityGroup.jsx +++ b/src/pages/compute/containers/Instance/Detail/SecurityGroup/action/ManageSecurityGroup.jsx @@ -21,9 +21,7 @@ import { securityGroupColumns, } from 'resources/security-group'; -@inject('rootStore') -@observer -export default class ManageSecurityGroup extends ModalAction { +export class ManageSecurityGroup extends ModalAction { static id = 'manage-security-group'; static title = t('Manage Security Group'); @@ -91,3 +89,5 @@ export default class ManageSecurityGroup extends ModalAction { return this.securityGroupStore.updatePortSecurityGroup({ id, reqBody }); }; } + +export default inject('rootStore')(observer(ManageSecurityGroup)); diff --git a/src/pages/compute/containers/Instance/actions/CreateIronic/index.jsx b/src/pages/compute/containers/Instance/actions/CreateIronic/index.jsx index 5a1e6e70..cc00f21f 100644 --- a/src/pages/compute/containers/Instance/actions/CreateIronic/index.jsx +++ b/src/pages/compute/containers/Instance/actions/CreateIronic/index.jsx @@ -200,6 +200,10 @@ export class CreateIronic extends StepAction { ); } + renderExtra() { + return null; + } + renderFooterLeft() { const { data } = this.state; const { count = 1 } = data; @@ -221,16 +225,17 @@ export class CreateIronic extends StepAction { className={classnames(styles.input, 'instance-count')} /> + {this.renderExtra()} {this.renderBadge()} ); } - onSubmit = (values) => { + getSubmitData(values) { const { status } = this.state; if (status === 'error') { - return Promise.reject(); + return null; } /* eslint-disable no-unused-vars */ const { @@ -311,16 +316,23 @@ export class CreateIronic extends StepAction { if (server.adminPass || userData) { server.user_data = btoa(getUserData(server.adminPass, userData)); } - const body = { + return { server, }; + } + + onSubmit = (body) => { + if (!body) { + return Promise.reject(); + } return this.store.create(body); }; onOk = () => { const { data } = this.state; this.values = data; - this.onSubmit(data).then( + const submitData = this.getSubmitData(data); + this.onSubmit(submitData).then( () => { this.routing.push(this.listUrl); Notify.success(this.successText); diff --git a/src/pages/compute/containers/Instance/actions/Delete.jsx b/src/pages/compute/containers/Instance/actions/Delete.jsx deleted file mode 100644 index fa19308b..00000000 --- a/src/pages/compute/containers/Instance/actions/Delete.jsx +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2021 99cloud -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import React from 'react'; -import { ConfirmAction } from 'containers/Action'; -import { isArray } from 'lodash'; -import { isNotLocked } from 'resources/instance'; -import globalServerStore from 'stores/nova/instance'; - -export default class DeleteAction extends ConfirmAction { - get id() { - return 'delete'; - } - - get title() { - return t('Delete Instance'); - } - - get buttonType() { - return 'danger'; - } - - get buttonText() { - return t('Delete'); - } - - get actionName() { - return t('delete instance'); - } - - policy = 'os_compute_api:servers:create'; - - confirmContext = (data) => { - const name = isArray(data) - ? data.map((it) => it.name).join(',') - : data.name; - return ( -
- {t('Are you sure to delete instance { name }? ', { name })} - {t( - 'When you delete an instance, the following resources will be released(Non-root disks will be unmounted and retained):' - )} - -
- {t( - 'After the instance is deleted, the instance root disk data will be lost. ' - )} - {t( - 'If you still want to keep the root disk data, it is recommended that you create a backup for the root disk before deleting, or upload the instance snapshot as an image.' - )} -
-
- ); - }; - - allowedCheckFunc = (item) => { - if (!item) { - return true; - } - return isNotLocked(item); - }; - - performErrorMsg = (failedItems) => { - const instances = isArray(failedItems) ? failedItems : [failedItems]; - const names = this.getName(instances); - let errorMsg = t('Instance "{ name }" is locked, can not delete it.', { - names, - }); - if (names.length > 1) { - errorMsg = t('Instances "{ name }" are locked, can not delete them.', { - names, - }); - } - return errorMsg; - }; - - onSubmit = (item) => { - const { id } = item || this.item; - return globalServerStore.delete({ id }); - }; -} diff --git a/src/pages/compute/containers/Instance/actions/SoftDelete.jsx b/src/pages/compute/containers/Instance/actions/SoftDelete.jsx index 892ffd4f..4b743d88 100644 --- a/src/pages/compute/containers/Instance/actions/SoftDelete.jsx +++ b/src/pages/compute/containers/Instance/actions/SoftDelete.jsx @@ -83,7 +83,7 @@ export default class SoftDelete extends ConfirmAction {

{/* {t('After the instance is deleted, the instance root disk data will be lost. ')} */} {t( - 'If you still want to keep the disk data, it is recommended that you create a snapshot for the disk before deleting, or create a snapshot for instance.' + 'If you still want to keep the disk data, it is recommended that you create a snapshot for the disk before deleting.' )}

@@ -97,7 +97,7 @@ export default class SoftDelete extends ConfirmAction {

{t( - 'After deletion, the instance will be stored in the recycle bin, which will be reserved for 7 * 24h by default and can be restored within the period. After successful recovery, the status of the instance is running and related resources remain unchanged.' + 'When the computing service starts the recycling instance interval, the instance will be stored in the recycling bin after deletion, and will be retained according to the corresponding time interval. You can choose to restore it within this period. After successful recovery, the status of the instance is running and related resources remain unchanged.' )}

@@ -140,10 +140,10 @@ export default class SoftDelete extends ConfirmAction { }; onSubmit = (item) => { - const { id, isHardDeleted = false, expiredTime } = item || this.item; + const { id, isHardDeleted = false } = item || this.item; if (isHardDeleted) { - return globalServerStore.forceDelete({ id }, expiredTime); + return globalServerStore.forceDelete({ id }); } - return globalServerStore.delete({ id }, expiredTime); + return globalServerStore.delete({ id }); }; } diff --git a/src/pages/compute/containers/Instance/actions/StepCreate/BaseStep/index.jsx b/src/pages/compute/containers/Instance/actions/StepCreate/BaseStep/index.jsx index 74f7c0ab..31ae9929 100644 --- a/src/pages/compute/containers/Instance/actions/StepCreate/BaseStep/index.jsx +++ b/src/pages/compute/containers/Instance/actions/StepCreate/BaseStep/index.jsx @@ -58,9 +58,9 @@ export class BaseStep extends Base { get defaultValue() { const { volume } = this.locationParams; - let source = this.sourceTypes[0]; + let source = this.imageSourceType; if (volume) { - source = this.sourceTypes[1]; + source = this.volumeSourceType; } const values = { systemDisk: this.defaultVolumeType, @@ -144,6 +144,14 @@ export class BaseStep extends Base { ]; } + get imageSourceType() { + return this.sourceTypes[0]; + } + + get volumeSourceType() { + return this.sourceTypes[1]; + } + allowed = () => Promise.resolve(); async getAvailZones() { @@ -185,7 +193,7 @@ export class BaseStep extends Base { id: volume, }); this.updateContext({ - source: this.sourceTypes[1], + source: this.volumeSourceType, }); } else { await this.volumeStore.fetchList({ @@ -256,12 +264,12 @@ export class BaseStep extends Base { get sourceTypeIsImage() { const { source } = this.state; - return source === this.sourceTypes[0].value; + return source === this.imageSourceType.value; } get sourceTypeIsVolume() { const { source } = this.state; - return source === this.sourceTypes[1].value; + return source === this.volumeSourceType.value; } getImageExtraWords() { @@ -292,11 +300,11 @@ export class BaseStep extends Base { }); }; - onSourceChange = (value) => { + onSourceChange(value) { this.updateContext({ source: value, }); - }; + } onDataDiskChange = (value) => { this.updateContext({ diff --git a/src/pages/compute/containers/Instance/actions/StepCreate/ConfirmStep/index.jsx b/src/pages/compute/containers/Instance/actions/StepCreate/ConfirmStep/index.jsx index b56be6af..6651cdc4 100644 --- a/src/pages/compute/containers/Instance/actions/StepCreate/ConfirmStep/index.jsx +++ b/src/pages/compute/containers/Instance/actions/StepCreate/ConfirmStep/index.jsx @@ -147,9 +147,7 @@ export class ConfirmStep extends Base { } get defaultValue() { - return { - autoRelease: false, - }; + return {}; } get formItems() { diff --git a/src/pages/compute/containers/Instance/actions/StepCreate/index.jsx b/src/pages/compute/containers/Instance/actions/StepCreate/index.jsx index 7a4d4de1..3be436cc 100644 --- a/src/pages/compute/containers/Instance/actions/StepCreate/index.jsx +++ b/src/pages/compute/containers/Instance/actions/StepCreate/index.jsx @@ -29,7 +29,7 @@ import SystemStep from './SystemStep'; import NetworkStep from './NetworkStep'; import BaseStep from './BaseStep'; -class StepCreate extends StepAction { +export class StepCreate extends StepAction { static id = 'instance-create'; static title = t('Create Instance'); @@ -189,6 +189,10 @@ class StepCreate extends StepAction { ); } + renderExtra() { + return null; + } + renderFooterLeft() { const { data } = this.state; const { count = 1, source: { value: sourceValue } = {} } = data; @@ -210,16 +214,17 @@ class StepCreate extends StepAction { className={classnames(styles.input, 'instance-count')} />
+ {this.renderExtra()} {this.renderBadge()} ); } - onSubmit = (values) => { + getSubmitData(values) { const { status } = this.state; if (status === 'error') { - return Promise.reject(); + return null; } /* eslint-disable no-unused-vars */ const { @@ -357,13 +362,21 @@ class StepCreate extends StepAction { group: serverGroup.selectedRowKeys[0], }; } + return body; + } + + onSubmit = (body) => { + if (!body) { + return Promise.reject(); + } return this.store.create(body); }; onOk = () => { const { data } = this.state; this.values = data; - this.onSubmit(data).then( + const submitData = this.getSubmitData(data); + this.onSubmit(submitData).then( () => { this.routing.push(this.listUrl); Notify.success(this.successText); diff --git a/src/pages/compute/containers/Instance/actions/index.jsx b/src/pages/compute/containers/Instance/actions/index.jsx index 9e447641..1b07b476 100644 --- a/src/pages/compute/containers/Instance/actions/index.jsx +++ b/src/pages/compute/containers/Instance/actions/index.jsx @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Delete from './Delete'; +import SoftDelete from './SoftDelete'; // import CreateImage from './CreateImage'; import CreateSnapshot from './CreateSnapshot'; import AttachInterface from './AttachInterface'; @@ -46,7 +46,6 @@ import Unshelve from './Unshelve'; import DisassociateFip from './DisassociateFip'; import LiveMigrate from './LiveMigrate'; import AssociateFip from './AssociateFip'; -// import SoftDelete from './SoftDelete'; import ManageSecurityGroup from './ManageSecurityGroup'; import DeleteIronic from './DeleteIronic'; @@ -84,8 +83,7 @@ const batchActions = [ StopAction, RebootAction, SoftRebootAction, - // SoftDelete, - Delete, + SoftDelete, ]; const batchActionsForIronic = batchActions.slice(0, -2).concat(DeleteIronic); @@ -122,8 +120,7 @@ const actionConfigs = { action: Edit, }, { - // action: SoftDelete, - action: Delete, + action: SoftDelete, }, { action: DeleteIronic, @@ -149,8 +146,7 @@ const adminActions = { action: LiveMigrate, }, { - // action: SoftDelete, - action: Delete, + action: SoftDelete, }, { action: DeleteIronic, diff --git a/src/pages/compute/containers/Instance/index.jsx b/src/pages/compute/containers/Instance/index.jsx index 22ce3a92..eccb26cd 100644 --- a/src/pages/compute/containers/Instance/index.jsx +++ b/src/pages/compute/containers/Instance/index.jsx @@ -27,9 +27,7 @@ import globalServerStore, { ServerStore } from 'stores/nova/instance'; import { ServerGroupInstanceStore } from 'stores/skyline/server-group-instance'; import actionConfigs from './actions'; -@inject('rootStore') -@observer -export default class Instance extends Base { +export class Instance extends Base { init() { if (!this.inDetailPage) { this.store = globalServerStore; @@ -304,3 +302,5 @@ export default class Instance extends Base { return newParams; }; } + +export default inject('rootStore')(observer(Instance)); diff --git a/src/pages/network/containers/FloatingIp/actions/Associate.jsx b/src/pages/network/containers/FloatingIp/actions/Associate.jsx index 78dd8923..0badea7e 100644 --- a/src/pages/network/containers/FloatingIp/actions/Associate.jsx +++ b/src/pages/network/containers/FloatingIp/actions/Associate.jsx @@ -30,9 +30,7 @@ import { instanceSelectTablePropsBackend } from 'resources/instance'; import { getPortFormItem, getPortsAndReasons } from 'resources/port'; import { getInterfaceWithReason } from 'resources/floatingip'; -@inject('rootStore') -@observer -export default class Associate extends ModalAction { +export class Associate extends ModalAction { static id = 'associate'; static title = t('Associate'); @@ -398,3 +396,5 @@ export default class Associate extends ModalAction { return ret; } } + +export default inject('rootStore')(observer(Associate)); diff --git a/src/pages/network/containers/VirtualAdapter/actions/Attach.jsx b/src/pages/network/containers/VirtualAdapter/actions/Attach.jsx index ec077773..62c7ff7a 100644 --- a/src/pages/network/containers/VirtualAdapter/actions/Attach.jsx +++ b/src/pages/network/containers/VirtualAdapter/actions/Attach.jsx @@ -20,9 +20,7 @@ import { allowAttachInterfaceStatus, } from 'resources/instance'; -@inject('rootStore') -@observer -export default class Attach extends ModalAction { +export class Attach extends ModalAction { static id = 'attach_instance'; static title = t('Attach Instance'); @@ -97,3 +95,5 @@ export default class Attach extends ModalAction { ]; } } + +export default inject('rootStore')(observer(Attach)); diff --git a/src/pages/network/containers/VirtualAdapter/actions/Create.jsx b/src/pages/network/containers/VirtualAdapter/actions/Create.jsx index 9c028f7f..67280793 100644 --- a/src/pages/network/containers/VirtualAdapter/actions/Create.jsx +++ b/src/pages/network/containers/VirtualAdapter/actions/Create.jsx @@ -28,9 +28,7 @@ import { getQoSPolicyTabs } from 'resources/qos-policy'; const portTypes = 'normal,macvtap,direct,baremetal,direct-physical,virtio-forwarder,smart-nic'; -@inject('rootStore') -@observer -export default class CreateAction extends ModalAction { +export class CreateAction extends ModalAction { static id = 'create-virtual-adapter'; static title = t('Create Virtual Adapter'); @@ -366,3 +364,5 @@ export default class CreateAction extends ModalAction { ]; } } + +export default inject('rootStore')(observer(CreateAction)); diff --git a/src/pages/storage/containers/Volume/actions/Attach.jsx b/src/pages/storage/containers/Volume/actions/Attach.jsx index fd3481f8..5611e8af 100644 --- a/src/pages/storage/containers/Volume/actions/Attach.jsx +++ b/src/pages/storage/containers/Volume/actions/Attach.jsx @@ -25,9 +25,7 @@ import { } from 'resources/instance'; import { isAvailable, isMultiAttach } from 'resources/volume'; -@inject('rootStore') -@observer -export default class Attach extends ModalAction { +export class Attach extends ModalAction { static id = 'attach'; static title = t('Attach'); @@ -119,3 +117,5 @@ export default class Attach extends ModalAction { ); }; } + +export default inject('rootStore')(observer(Attach)); diff --git a/src/resources/image.jsx b/src/resources/image.jsx index a4a14e75..b4c57565 100644 --- a/src/resources/image.jsx +++ b/src/resources/image.jsx @@ -131,10 +131,12 @@ export const isSnapshot = (item) => { }; export const canImageCreateInstance = (item) => - item.status === 'active' && (item.usage_type === 'common' || item.usage_type === undefined); + item.status === 'active' && + (item.usage_type === 'common' || item.usage_type === undefined); export const canImageCreateIronicInstance = (item) => - item.status === 'active' && (item.usage_type === 'ironic' || item.usage_type === undefined); + item.status === 'active' && + (item.usage_type === 'ironic' || item.usage_type === undefined); export const canSnapshotCreateInstance = (item) => item.status === 'active'; diff --git a/src/stores/nova/instance.js b/src/stores/nova/instance.js index 8865311a..7013365b 100644 --- a/src/stores/nova/instance.js +++ b/src/stores/nova/instance.js @@ -302,10 +302,7 @@ export class ServerStore extends Base { } @action - async forceDelete({ id }, expiredTime) { - if (!expiredTime) { - return this.operation({ key: 'forceDelete', id }); - } + async forceDelete({ id }) { const body = { forceDelete: null, };