diff --git a/src/locales/en.json b/src/locales/en.json index 5e5a3e96..0139220a 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -698,6 +698,7 @@ "Details *": "Details *", "Device ID": "Device ID", "Device Owner": "Device Owner", + "Devicemapper": "Devicemapper", "Direct": "Direct", "Direction": "Direction", "Disable": "Disable", @@ -2023,6 +2024,7 @@ "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", @@ -2234,6 +2236,7 @@ "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 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", "The name cannot be modified after creation": "The name cannot be modified after creation", "The name of the physical network to which a port is connected": "The name of the physical network to which a port is connected", "The name should contain letter or number, the length is 1 to 16, characters can only contain \"0-9, a-z, A-Z, -, _.\"": "The name should contain letter or number, the length is 1 to 16, characters can only contain \"0-9, a-z, A-Z, -, _.\"", diff --git a/src/locales/zh.json b/src/locales/zh.json index 969b620b..1a85dade 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -698,6 +698,7 @@ "Details *": "详情 *", "Device ID": "设备ID", "Device Owner": "设备所属者", + "Devicemapper": "设备映射", "Direct": "方向", "Direction": "方向", "Disable": "禁用", @@ -729,8 +730,8 @@ "Do not set with a backend": "不设置后端", "Docker": "Docker", "Docker Storage Driver": "Docker存储驱动程序", - "Docker Swarm": "Docker集群", - "Docker Swarm Mode": "Docker集群模式", + "Docker Swarm": "Docker Swarm", + "Docker Swarm Mode": "Docker Swarm Mode", "Docker Volume Size": "Docker硬盘大小", "Docker Volume Size (GiB)": "Docker硬盘大小(GiB)", "Domain": "域", @@ -924,7 +925,7 @@ "Flavors": "云主机类型", "Floating IP": "浮动IP", "Floating IP Address": "浮动IP地址", - "Floating IP Enabled": "启用浮动IP", + "Floating IP Enabled": "允许浮动IP", "Floating IPs": "浮动IP", "Floating Ip": "浮动IP", "Floating Ip Address": "浮动IP地址", @@ -1375,8 +1376,8 @@ "Master Count": "主数量", "Master Flavor": "主类型", "Master Flavor ID": "主类型ID", - "Master LB": "主LB", - "Master LB Enabled": "主LB启用", + "Master LB": "主负载均衡", + "Master LB Enabled": "允许主负载均衡", "Mauritania": "毛里塔尼亚", "Mauritius": "毛里求斯", "Max Avail": "最大可用量", @@ -1502,7 +1503,7 @@ "No Console": "", "No Monitor": "无监控", "No Outputs": "无输出", - "No Proxy": "无代理", + "No Proxy": "非代理", "No Raid": "", "No State": "无状态", "No Task": "空闲", @@ -2023,6 +2024,7 @@ "Share Type ID": "共享类型ID", "Share Type Name": "共享类型名称", "Share Types": "共享类型", + "Share group": "", "Shared": "共享", "Shared Image": "共享镜像", "Shared Network": "共享网络", @@ -2234,6 +2236,7 @@ "The ip of external members can be any, including the public network ip.": "外部成员的IP可以是任何IP,包括公网IP。", "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", "The name cannot be modified after creation": "名称创建后不可修改", "The name of the physical network to which a port is connected": "端口连接到的物理网络的名称", "The name should contain letter or number, the length is 1 to 16, characters can only contain \"0-9, a-z, A-Z, -, _.\"": "名称应包含字母或数字,长度为 1 到 16,且字符只能包含“0-9、a-z、A-Z、-、_”。", diff --git a/src/pages/container-infra/containers/ClusterTemplates/Detail/BaseDetail.jsx b/src/pages/container-infra/containers/ClusterTemplates/Detail/BaseDetail.jsx index ed264261..b6fbbb7b 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/Detail/BaseDetail.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/Detail/BaseDetail.jsx @@ -20,6 +20,12 @@ export class BaseDetail extends Base { return [this.baseInfoCard, this.networkCard]; } + get leftCardsStyle() { + return { + flex: 1, + }; + } + get rightCards() { return [this.specCard, this.labelCard]; } diff --git a/src/pages/container-infra/containers/ClusterTemplates/actions/Edit.jsx b/src/pages/container-infra/containers/ClusterTemplates/actions/Edit.jsx index f839477b..eb94487e 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/actions/Edit.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/actions/Edit.jsx @@ -19,7 +19,7 @@ import { StepCreate as Base } from './StepCreate'; export class Edit extends Base { static id = 'update-cluster-template'; - static title = t('Update Cluster Template'); + static title = t('Edit'); get name() { return t('Update Cluster Template'); diff --git a/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepInfo/index.jsx b/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepInfo/index.jsx index 92acb133..53cc804d 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepInfo/index.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepInfo/index.jsx @@ -65,7 +65,6 @@ export class StepInfo extends Base { label: t('Cluster Template Name'), type: 'input', placeholder: t('Cluster Template Name'), - required: true, }, { name: 'coe', diff --git a/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepNetwork/index.jsx b/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepNetwork/index.jsx index cfa2de6b..b4248ff1 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepNetwork/index.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepNetwork/index.jsx @@ -19,10 +19,8 @@ import globalSubnetStore from 'src/stores/neutron/subnet'; export class StepNetwork extends Base { async init() { - const { extra: { fixed_network } = {} } = this.props; - this.state.selectedSubnetId = fixed_network || ''; - this.getFloatingIps(); - this.getSubnets(); + this.getNetworkList(); + this.getSubnetList(); } get title() { @@ -41,11 +39,11 @@ export class StepNetwork extends Base { return !!this.props.extra; } - async getFloatingIps() { - globalNetworkStore.fetchList(); + async getNetworkList() { + await globalNetworkStore.fetchList(); } - get getFloatingIpList() { + get externalNetworks() { return (globalNetworkStore.list.data || []) .filter( (it) => @@ -58,7 +56,7 @@ export class StepNetwork extends Base { })); } - get getPrivateFloatingIpList() { + get privateNetworks() { return (globalNetworkStore.list.data || []) .filter( (it) => @@ -68,60 +66,44 @@ export class StepNetwork extends Base { .map((it) => ({ value: it.id, label: it.name, - subnetId: it.subnets, })); } - async getSubnets() { - globalSubnetStore.fetchList(); + async getSubnetList() { + await globalSubnetStore.fetchList(); } - get getSubnetList() { + get subnetList() { + const { fixed_network } = this.state; return (globalSubnetStore.list.data || []) - .filter((it) => this.state.selectedSubnetId === it.network_id) + .filter((it) => fixed_network === it.network_id) .map((it) => ({ value: it.id, label: it.name, })); } - onSelectChangeFixedNetwork(value) { - this.setState({ - selectedSubnetId: value, - }); - this.resetFormValue(['fixed_subnet']); + get networkDrivers() { + const { context: { coe = '' } = {} } = this.props; + let acceptedDrivers = []; + if (coe === 'kubernetes') { + acceptedDrivers = [ + { value: 'calico', label: 'Calico' }, + { value: 'flannel', label: 'Flannel' }, + ]; + } else if (['swarm', 'swarm-mode'].includes(coe)) { + acceptedDrivers = [ + { value: 'docker', label: 'Docker' }, + { value: 'flannel', label: 'Flannel' }, + ]; + } else if (['mesos', 'dcos'].includes(coe)) { + acceptedDrivers = [{ value: 'docker', label: 'Docker' }]; + } + return acceptedDrivers; } - get getNetworkDriver() { - const { context = {} } = this.props; - const { coeSelectRows = '', coe = '' } = context; - const networkDriver = []; - if (!coeSelectRows || !coe) { - networkDriver.push( - { val: 'docker', name: 'Docker' }, - { val: 'flannel', name: 'Flannel' }, - { val: 'calico', name: 'Calico' } - ); - } - if (coeSelectRows === 'swarm' || coeSelectRows === 'swarm-mode') { - networkDriver.push( - { val: 'docker', name: 'Docker' }, - { val: 'flannel', name: 'Flannel' } - ); - } - if (coeSelectRows === 'kubernetes') { - networkDriver.push( - { val: 'calico', name: 'Calico' }, - { val: 'flannel', name: 'Flannel' } - ); - } - if (coeSelectRows === 'mesos' || coeSelectRows === 'dcos') { - networkDriver.push({ val: 'docker', name: 'Docker' }); - } - return (networkDriver || []).map((it) => ({ - value: it.val, - label: it.name, - })); + get nameForStateUpdate() { + return ['fixed_network']; } get defaultValue() { @@ -159,14 +141,14 @@ export class StepNetwork extends Base { } get formItems() { - const { extra: { network_driver, external_network_id } = {} } = this.props; + const { extra: { network_driver } = {} } = this.props; return [ { name: 'network_driver', label: t('Network Driver'), placeholder: t('Choose a Network Driver'), type: 'select', - options: this.getNetworkDriver, + options: this.networkDrivers, disabled: network_driver && this.isEdit, }, { @@ -192,23 +174,26 @@ export class StepNetwork extends Base { label: t('External Network'), placeholder: t('Choose a External Network'), type: 'select', - options: this.getFloatingIpList, - disabled: external_network_id && this.isEdit, + options: this.externalNetworks, + disabled: this.isEdit, + required: true, }, { name: 'fixed_network', label: t('Fixed Network'), placeholder: t('Choose a Private Network'), type: 'select', - options: this.getPrivateFloatingIpList, - onChange: (val) => this.onSelectChangeFixedNetwork(val), + options: this.privateNetworks, + onChange: () => { + this.updateFormValue('fixed_subnet', null); + }, }, { name: 'fixed_subnet', label: t('Fixed Subnet'), placeholder: t('Choose a Private Network at first'), type: 'select', - options: this.getSubnetList, + options: this.subnetList, }, { name: 'dns_nameserver', diff --git a/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepNodeSpec/index.jsx b/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepNodeSpec/index.jsx index 212ed49b..7ec4be62 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepNodeSpec/index.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepNodeSpec/index.jsx @@ -21,8 +21,8 @@ import FlavorSelectTable from 'src/pages/compute/containers/Instance/components/ export class StepNodeSpec extends Base { init() { - this.getImageOsDistro(); - this.getKeypairs(); + this.getImageList(); + this.getKeypairsList(); } get title() { @@ -33,10 +33,6 @@ export class StepNodeSpec extends Base { return t('Node Spec'); } - async getImageOsDistro() { - globalImageStore.fetchList(); - } - get isStep() { return true; } @@ -45,46 +41,53 @@ export class StepNodeSpec extends Base { return !!this.props.extra; } - get getImageOsDistroList() { + async getImageList() { + await globalImageStore.fetchList(); + } + + get imageList() { + const { context: { coe = '' } = {} } = this.props; + let acceptedOs = []; + if (coe === 'kubernetes') { + acceptedOs = ['fedora', 'coreos']; + } else if (['swarm', 'swarm-mode'].includes(coe)) { + acceptedOs = ['fedora']; + } else if (['mesos', 'dcos'].includes(coe)) { + acceptedOs = ['ubuntu']; + } + return (globalImageStore.list.data || []) - .filter((it) => it.name.indexOf('coreos') >= 0) - .filter((it) => it.owner === this.currentProjectId) + .filter( + (it) => + it.owner === this.currentProjectId && + acceptedOs.includes(it.os_distro) + ) .map((it) => ({ value: it.id, label: it.name, })); } - async getKeypairs() { - globalKeypairStore.fetchList(); + async getKeypairsList() { + await globalKeypairStore.fetchList(); } - get getKeypairList() { + get keypairsList() { return (globalKeypairStore.list.data || []).map((it) => ({ value: it.name, label: it.name, })); } - get getVolumeDriver() { - const { context = {} } = this.props; - const { coeSelectRows = '', coe = '' } = context; - const volumeDriver = []; - if (!coeSelectRows || !coe) { - volumeDriver.push( - { val: 'cinder', name: 'Cinder' }, - { val: 'rexray', name: 'Rexray' } - ); + get volumeDrivers() { + const { context: { coe = '' } = {} } = this.props; + let acceptedVolumeDriver = []; + if (coe === 'kubernetes') { + acceptedVolumeDriver = [{ value: 'cinder', label: 'Cinder' }]; + } else if (['swarm', 'mesos'].includes(coe)) { + acceptedVolumeDriver = [{ value: 'rexray', label: 'Rexray' }]; } - if (coeSelectRows === 'kubernetes') { - volumeDriver.push({ val: 'cinder', name: 'Cinder' }); - } else if (coeSelectRows) { - volumeDriver.push({ val: 'rexray', name: 'Rexray' }); - } - return (volumeDriver || []).map((it) => ({ - value: it.val, - label: it.name, - })); + return acceptedVolumeDriver; } onFlavorChange = (value) => { @@ -125,20 +128,29 @@ export class StepNodeSpec extends Base { return values; } + get minVolumeSize() { + const { docker_storage_driver } = this.state; + return docker_storage_driver === 'devicemapper' ? 3 : 1; + } + + get nameForStateUpdate() { + return ['docker_storage_driver']; + } + get formItems() { return [ { name: 'image_id', label: t('Image'), type: 'select', - options: this.getImageOsDistroList, + options: this.imageList, required: true, }, { name: 'keypair_id', label: t('Keypair'), type: 'select', - options: this.getKeypairList, + options: this.keypairsList, }, { name: 'flavor', @@ -156,13 +168,17 @@ export class StepNodeSpec extends Base { name: 'volume_driver', label: t('Volume Driver'), type: 'select', - options: this.getVolumeDriver, + options: this.volumeDrivers, }, { name: 'docker_storage_driver', label: t('Docker Storage Driver'), type: 'select', options: [ + { + label: t('Devicemapper'), + value: 'devicemapper', + }, { label: t('Overlay'), value: 'overlay', @@ -172,13 +188,29 @@ export class StepNodeSpec extends Base { value: 'overlay2', }, ], + onChange: () => { + this.resetFormValue(['docker_volume_size']); + }, }, { name: 'docker_volume_size', label: t('Docker Volume Size (GiB)'), type: 'input-int', - min: 1, + min: this.minVolumeSize, placeholder: t('Spec'), + validator: (rule, value) => { + if ( + this.minVolumeSize === 3 && + (!value || value < this.minVolumeSize) + ) { + return Promise.reject( + new Error( + t('The min size is {size} GiB', { size: this.minVolumeSize }) + ) + ); + } + return Promise.resolve(); + }, }, ]; }