From ec4bcb3c93e32e4c152bf47bec4b65991ad322cc Mon Sep 17 00:00:00 2001 From: xusongfu Date: Thu, 23 Jun 2022 17:15:40 +0800 Subject: [PATCH] fix: fix cluster template 1. Fix the params when create or update cluster template 2. Show search for all select items 3. Fix the route path for update cluster template Change-Id: Ic3435abb340f6e129815fde368b5b12bcabcdcb5 --- src/components/Form/index.jsx | 5 + src/components/FormItem/Select/index.jsx | 4 + src/components/StepForm/index.jsx | 5 + src/layouts/menu.jsx | 2 +- src/locales/en.json | 7 +- src/locales/zh.json | 7 +- .../ClusterTemplates/Detail/BaseDetail.jsx | 116 +++++++---- .../ClusterTemplates/Detail/index.jsx | 13 +- .../ClusterTemplates/actions/Delete.jsx | 2 +- .../actions/{EditStep.jsx => Edit.jsx} | 10 +- .../actions/StepCreate/StepInfo/index.jsx | 110 ++++++----- .../actions/StepCreate/StepLabel/index.jsx | 32 ++- .../actions/StepCreate/StepNetwork/index.jsx | 187 ++++++++++-------- .../actions/StepCreate/StepNodeSpec/index.jsx | 72 ++++--- .../actions/StepCreate/index.jsx | 100 ++++------ .../ClusterTemplates/actions/index.jsx | 16 +- .../containers/ClusterTemplates/index.jsx | 10 +- src/pages/container-infra/routes/index.js | 2 +- src/resources/magnum/template.js | 16 ++ src/stores/magnum/clusterTemplates.js | 22 ++- 20 files changed, 423 insertions(+), 315 deletions(-) rename src/pages/container-infra/containers/ClusterTemplates/actions/{EditStep.jsx => Edit.jsx} (89%) create mode 100644 src/resources/magnum/template.js diff --git a/src/components/Form/index.jsx b/src/components/Form/index.jsx index 2f12036f..b1b666b2 100644 --- a/src/components/Form/index.jsx +++ b/src/components/Form/index.jsx @@ -74,6 +74,11 @@ export default class BaseForm extends React.Component { this.unMountActions && this.unMountActions(); } + get path() { + const { location: { pathname = '' } = {} } = this.props; + return pathname || ''; + } + get disableSubmit() { return false; } diff --git a/src/components/FormItem/Select/index.jsx b/src/components/FormItem/Select/index.jsx index df619f3c..952685a4 100644 --- a/src/components/FormItem/Select/index.jsx +++ b/src/components/FormItem/Select/index.jsx @@ -62,6 +62,7 @@ export default class index extends Component { checkOptions, checkBoxInfo, allowClear = true, + showSearch = true, ...rest } = this.props; if (isUndefined(value) || isNull(value)) { @@ -69,6 +70,7 @@ export default class index extends Component { { level: 2, }, { - path: /^\/container-infra\/cluster-template\/update\/.[^/]+\/.[^/]+$/, + path: /^\/container-infra\/cluster-template\/update\/.[^/]+$/, name: t('Update Cluster Template'), key: 'containerInfraUpdateClusterTemplate', level: 2, diff --git a/src/locales/en.json b/src/locales/en.json index f26e3e24..f80cdaa8 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -322,9 +322,9 @@ "Checksum": "Checksum", "Chile": "Chile", "China": "China", - "Choose a External Network ID": "Choose a External Network ID", + "Choose a External Network": "Choose a External Network", "Choose a Network Driver": "Choose a Network Driver", - "Choose a Private Network ID": "Choose a Private Network ID", + "Choose a Private Network": "Choose a Private Network", "Choose a Private Network at first": "Choose a Private Network at first", "Choose a host to live migrate instance to. If not selected, the scheduler will auto select target host.": "Choose a host to live migrate instance to. If not selected, the scheduler will auto select target host.", "Choose a host to migrate instance to. If not selected, the scheduler will auto select target host.": "Choose a host to migrate instance to. If not selected, the scheduler will auto select target host.", @@ -542,7 +542,6 @@ "Current Flavor": "Current Flavor", "Current Host": "Current Host", "Current Interface": "Current Interface", - "Current Master Flavor": "Current Master Flavor", "Current Password": "Current Password", "Current Path: ": "Current Path: ", "Current Project": "Current Project", @@ -911,7 +910,9 @@ "Fixed IP Address": "Fixed IP Address", "Fixed IPs": "Fixed IPs", "Fixed Network": "Fixed Network", + "Fixed Network ID": "Fixed Network ID", "Fixed Subnet": "Fixed Subnet", + "Fixed Subnet ID": "Fixed Subnet ID", "Flavor": "Flavor", "Flavor Detail": "Flavor Detail", "Flavor ID": "Flavor ID", diff --git a/src/locales/zh.json b/src/locales/zh.json index 2b831ab1..fb0df15c 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -322,9 +322,9 @@ "Checksum": "校验和", "Chile": "智利", "China": "中国大陆", - "Choose a External Network ID": "选择外部网络 ID", + "Choose a External Network": "选择外部网络", "Choose a Network Driver": "选择网络驱动程序", - "Choose a Private Network ID": "选择专用网络 ID", + "Choose a Private Network": "选择专用网络", "Choose a Private Network at first": "首先选择一个专用网络", "Choose a host to live migrate instance to. If not selected, the scheduler will auto select target host.": "选择计算节点来热迁移云主机,如果没有选择,调度器会自动选择目标计算节点。", "Choose a host to migrate instance to. If not selected, the scheduler will auto select target host.": "选择计算节点来迁移云主机,如果没有选择,调度器会自动选择目标计算节点。", @@ -542,7 +542,6 @@ "Current Flavor": "当前配置", "Current Host": "当前主机", "Current Interface": "当前接口", - "Current Master Flavor": "当前主类型", "Current Password": "原密码", "Current Path: ": "当前路径:", "Current Project": "当前项目", @@ -911,7 +910,9 @@ "Fixed IP Address": "内网IP地址", "Fixed IPs": "内网IP", "Fixed Network": "内网", + "Fixed Network ID": "内网ID", "Fixed Subnet": "内网子网", + "Fixed Subnet ID": "内网子网ID", "Flavor": "云主机类型", "Flavor Detail": "云主机类型详情", "Flavor ID": "云主机类型ID", diff --git a/src/pages/container-infra/containers/ClusterTemplates/Detail/BaseDetail.jsx b/src/pages/container-infra/containers/ClusterTemplates/Detail/BaseDetail.jsx index ce9dc6bb..85ea61b0 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/Detail/BaseDetail.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/Detail/BaseDetail.jsx @@ -10,9 +10,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Base from 'containers/BaseDetail'; import React from 'react'; -import { Link } from 'react-router-dom'; +import Base from 'containers/BaseDetail'; import { inject, observer } from 'mobx-react'; export class BaseDetail extends Base { @@ -28,82 +27,94 @@ export class BaseDetail extends Base { const options = [ { label: t('COE'), - dataIndex: 'coe' + dataIndex: 'coe', }, { label: t('Cluster Distro'), - dataIndex: 'cluster_distro' + dataIndex: 'cluster_distro', }, { label: t('Server Type'), - dataIndex: 'server_type' + dataIndex: 'server_type', }, { label: t('Public'), dataIndex: 'public', - valueRender: 'yesNo' + valueRender: 'yesNo', }, { label: t('Registry Enabled'), dataIndex: 'registry_enabled', - valueRender: 'yesNo' + valueRender: 'yesNo', }, { label: t('TLS Disabled'), dataIndex: 'tls_disabled', - valueRender: 'yesNo' + valueRender: 'yesNo', }, ]; return { title: t('Cluster Type'), - options + options, }; } get networkCard() { + const { external_network_id, fixed_network } = this.detailData || {}; + const externalNetworkUrl = external_network_id + ? this.getLinkRender('networkDetail', external_network_id, { + id: external_network_id, + }) + : '-'; + const fixedNetworkUrl = fixed_network + ? this.getLinkRender('networkDetail', fixed_network, { + id: fixed_network, + }) + : '-'; + const options = [ { label: t('Network Driver'), - dataIndex: 'network_driver' + dataIndex: 'network_driver', }, { label: t('HTTP Proxy'), - dataIndex: 'http_proxy' + dataIndex: 'http_proxy', }, { label: t('HTTPS Proxy'), - dataIndex: 'https_proxy' + dataIndex: 'https_proxy', }, { label: t('No Proxy'), - dataIndex: 'no_proxy' + dataIndex: 'no_proxy', }, { label: t('External Network ID'), - dataIndex: 'external_network_id' + content: externalNetworkUrl, }, { - label: t('Fixed Network'), - dataIndex: 'fixed_network' + label: t('Fixed Network ID'), + content: fixedNetworkUrl, }, { - label: t('Fixed Subnet'), - dataIndex: 'fixed_subnet' + label: t('Fixed Subnet ID'), + dataIndex: 'fixed_subnet', }, { label: t('DNS'), - dataIndex: 'dns_nameserver' + dataIndex: 'dns_nameserver', }, { label: t('Master LB Enabled'), dataIndex: 'master_lb_enabled', - valueRender: 'yesNo' + valueRender: 'yesNo', }, { label: t('Floating IP Enabled'), dataIndex: 'floating_ip_enabled', - valueRender: 'yesNo' + valueRender: 'yesNo', }, ]; @@ -114,44 +125,64 @@ export class BaseDetail extends Base { } get specCard() { - const image = this.detailData.image_id; - const imageUrl = this.getRoutePath('imageDetail', { id: image }); + const { image_id, keypair_id, flavor_id, master_flavor_id } = + this.detailData; + const imageUrl = image_id + ? this.getLinkRender('imageDetail', image_id, { + id: image_id, + }) + : '-'; - const keypair = this.detailData.keypair_id; - const keypairUrl = this.getRoutePath('keypairDetail', { id: keypair }); + const keypairUrl = keypair_id + ? this.getLinkRender('keypairDetail', keypair_id, { + id: keypair_id, + }) + : '-'; + + const flavorUrl = flavor_id + ? this.getLinkRender('flavorDetail', flavor_id, { + id: flavor_id, + }) + : '-'; + + const masterFlavorUrl = master_flavor_id + ? this.getLinkRender('flavorDetail', master_flavor_id, { + id: master_flavor_id, + }) + : '-'; const options = [ { label: t('Image ID'), - content: {image} + content: imageUrl, }, { label: t('Keypair'), - content: {keypair} + content: keypairUrl, }, { label: t('Flavor ID'), - dataIndex: 'flavor_id' + content: flavorUrl, }, { label: t('Master Flavor ID'), - dataIndex: 'master_flavor_id' + content: masterFlavorUrl, }, { label: t('Volume Driver'), - dataIndex: 'volume_driver' + dataIndex: 'volume_driver', }, { label: t('Docker Storage Driver'), - dataIndex: 'docker_storage_driver' + dataIndex: 'docker_storage_driver', }, { label: t('Docker Volume Size'), - dataIndex: 'docker_volume_size' + dataIndex: 'docker_volume_size', }, { label: t('Insecure Registry'), - dataIndex: 'insecure_registry' + dataIndex: 'insecure_registry', }, ]; @@ -166,9 +197,20 @@ export class BaseDetail extends Base { { label: t('labels'), dataIndex: 'labels', - render: (value) => value ? Object.entries(value).map(([key, val]) => { - return
- }) : '-' + render: (value) => + value + ? Object.entries(value).map(([key, val]) => { + return ( +
+ +
+ ); + }) + : '-', }, ]; @@ -180,4 +222,4 @@ export class BaseDetail extends Base { } } -export default inject("rootStore")(observer(BaseDetail)) \ No newline at end of file +export default inject('rootStore')(observer(BaseDetail)); diff --git a/src/pages/container-infra/containers/ClusterTemplates/Detail/index.jsx b/src/pages/container-infra/containers/ClusterTemplates/Detail/index.jsx index 8c415a44..1710c72d 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/Detail/index.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/Detail/index.jsx @@ -12,8 +12,9 @@ import { inject, observer } from 'mobx-react'; import Base from 'containers/TabDetail'; -import BaseDetail from './BaseDetail'; import globalClusterTemplateStore from 'src/stores/magnum/clusterTemplates'; +import BaseDetail from './BaseDetail'; +import actionConfigs from '../actions'; export class ClusterTemplateDetail extends Base { init() { @@ -32,6 +33,10 @@ export class ClusterTemplateDetail extends Base { return 'container-infra:clustertemplate:detail'; } + get actionConfigs() { + return actionConfigs; + } + get detailInfos() { return [ { @@ -41,12 +46,12 @@ export class ClusterTemplateDetail extends Base { { title: t('Created'), dataIndex: 'created_at', - valueRender: 'toLocalTime' + valueRender: 'toLocalTime', }, { title: t('Updated'), dataIndex: 'updated_at', - valueRender: 'toLocalTime' + valueRender: 'toLocalTime', }, ]; } @@ -62,4 +67,4 @@ export class ClusterTemplateDetail extends Base { } } -export default inject("rootStore")(observer(ClusterTemplateDetail)) \ No newline at end of file +export default inject('rootStore')(observer(ClusterTemplateDetail)); diff --git a/src/pages/container-infra/containers/ClusterTemplates/actions/Delete.jsx b/src/pages/container-infra/containers/ClusterTemplates/actions/Delete.jsx index cdd2cf55..d7c1cf26 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/actions/Delete.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/actions/Delete.jsx @@ -13,7 +13,7 @@ import { ConfirmAction } from 'containers/Action'; import globalClusterTemplateStore from 'stores/magnum/clusterTemplates'; -export default class DeleteClusterTemplates extends ConfirmAction { +export default class Delete extends ConfirmAction { get id() { return 'delete'; } diff --git a/src/pages/container-infra/containers/ClusterTemplates/actions/EditStep.jsx b/src/pages/container-infra/containers/ClusterTemplates/actions/Edit.jsx similarity index 89% rename from src/pages/container-infra/containers/ClusterTemplates/actions/EditStep.jsx rename to src/pages/container-infra/containers/ClusterTemplates/actions/Edit.jsx index 46af33fa..2145e56b 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/actions/EditStep.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/actions/Edit.jsx @@ -14,11 +14,9 @@ import { inject, observer } from 'mobx-react'; import { getPath } from 'src/utils/route-map'; -import StepCreate from './StepCreate'; +import { StepCreate as Base } from './StepCreate'; -@inject('rootStore') -@observer -export default class Edit extends StepCreate { +export class Edit extends Base { static id = 'update-cluster-template'; static title = t('Update Cluster Template'); @@ -42,4 +40,6 @@ export default class Edit extends StepCreate { static allowed() { return Promise.resolve(true); } -} \ No newline at end of file +} + +export default inject('rootStore')(observer(Edit)); 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 b45565e4..92acb133 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 @@ -12,16 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Base from "components/Form"; -import { inject, observer } from "mobx-react"; +import Base from 'components/Form'; +import { inject, observer } from 'mobx-react'; export class StepInfo extends Base { get title() { - return t("Info") + return t('Info'); } get name() { - return t("Info") + return t('Info'); } get isEdit() { @@ -32,22 +32,28 @@ export class StepInfo extends Base { return true; } - onCOEChange = (value) => { - this.updateContext({ - coeSelectRows: value, - }); - } - get defaultValue() { - const values = {}; + let values = {}; if (this.isEdit) { - values.clusterTemplateName = this.props.extra.name; - values.coe = this.props.extra.coe; - values.cluster_template_public = this.props.extra.public; - values.cluster_template_hidden = this.props.extra.hidden; - values.docker_registry_enabled = this.props.extra.registry_enabled; - values.tls_disabled = this.props.extra.tls_disabled; + const { + extra: { + name, + coe, + public: publics, + hidden, + registry_enabled, + tls_disabled, + } = {}, + } = this.props; + values = { + name, + coe, + public: publics, + hidden, + registry_enabled, + tls_disabled, + }; } return values; } @@ -55,64 +61,62 @@ export class StepInfo extends Base { get formItems() { return [ { - name: "clusterTemplateName", - label: t("Cluster Template Name"), - type: "input", - placeholder: t("Cluster Template Name"), - required: true + name: 'name', + label: t('Cluster Template Name'), + type: 'input', + placeholder: t('Cluster Template Name'), + required: true, }, { - name: "coe", - label: t("Container Orchestration Engine"), - type: "select", + name: 'coe', + label: t('Container Orchestration Engine'), + type: 'select', options: [ { - label: t("Kubernetes"), - value: "kubernetes" + label: t('Kubernetes'), + value: 'kubernetes', }, { - label: t("Docker Swarm"), - value: "swarm" + label: t('Docker Swarm'), + value: 'swarm', }, { - label: t("Docker Swarm Mode"), - value: "swarm-mode" + label: t('Docker Swarm Mode'), + value: 'swarm-mode', }, { - label: t("Mesos"), - value: "mesos" + label: t('Mesos'), + value: 'mesos', }, { - label: t("DC/OS"), - value: "dcos" + label: t('DC/OS'), + value: 'dcos', }, ], - onChange: this.onCOEChange, - allowClear: true, - showSearch: true + required: true, }, { - name: "cluster_template_public", - label: t("Public"), - type: "check" + name: 'public', + label: t('Public'), + type: 'check', }, { - name: "cluster_template_hidden", - label: t("Hidden"), - type: "check" + name: 'hidden', + label: t('Hidden'), + type: 'check', }, { - name: "docker_registry_enabled", - label: t("Enable Registry"), - type: "check" + name: 'registry_enabled', + label: t('Enable Registry'), + type: 'check', }, { - name: "tls_disabled", - label: t("Disable TLS"), - type: "check" - } - ] + name: 'tls_disabled', + label: t('Disable TLS'), + type: 'check', + }, + ]; } } -export default inject("rootStore")(observer(StepInfo)) \ No newline at end of file +export default inject('rootStore')(observer(StepInfo)); diff --git a/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepLabel/index.jsx b/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepLabel/index.jsx index e0e12edf..a6d5e480 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepLabel/index.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/StepLabel/index.jsx @@ -10,8 +10,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Base from "components/Form"; -import { inject, observer } from "mobx-react"; +import Base from 'components/Form'; +import { inject, observer } from 'mobx-react'; import KeyValueInput from 'components/FormItem/KeyValueInput'; export class StepLabel extends Base { @@ -23,6 +23,30 @@ export class StepLabel extends Base { return t('Labels'); } + get isStep() { + return true; + } + + get isEdit() { + return !!this.props.extra; + } + + get defaultValue() { + const values = {}; + if (this.isEdit) { + const { + extra: { labels }, + } = this.props; + values.additionalLabels = Object.keys(labels || {}).map((key) => ({ + value: { + key, + value: labels[key], + }, + })); + } + return values; + } + get formItems() { return [ { @@ -32,8 +56,8 @@ export class StepLabel extends Base { itemComponent: KeyValueInput, addText: t('Add Label'), }, - ] + ]; } } -export default inject("rootStore")(observer(StepLabel)) +export default inject('rootStore')(observer(StepLabel)); 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 303cc4fb..9e22ae68 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 @@ -18,10 +18,11 @@ import globalNetworkStore from 'src/stores/neutron/network'; import globalSubnetStore from 'src/stores/neutron/subnet'; export class StepNetwork extends Base { - init() { + async init() { + const { extra: { fixed_network } = {} } = this.props; + this.state.selectedSubnetId = fixed_network || ''; this.getFloatingIps(); this.getSubnets(); - this.state = { selectedSubnetId: '' }; } get title() { @@ -46,7 +47,11 @@ export class StepNetwork extends Base { get getFloatingIpList() { return (globalNetworkStore.list.data || []) - .filter((it) => it['router:external'] === true && it.project_id === this.currentProjectId) + .filter( + (it) => + it['router:external'] === true && + it.project_id === this.currentProjectId + ) .map((it) => ({ value: it.id, label: it.name, @@ -55,7 +60,11 @@ export class StepNetwork extends Base { get getPrivateFloatingIpList() { return (globalNetworkStore.list.data || []) - .filter((it) => it['router:external'] === false && it.project_id === this.currentProjectId) + .filter( + (it) => + it['router:external'] === false && + it.project_id === this.currentProjectId + ) .map((it) => ({ value: it.id, label: it.name, @@ -80,49 +89,71 @@ export class StepNetwork extends Base { this.setState({ selectedSubnetId: value, }); - this.resetFormValue(['fixedSubnet']); + this.resetFormValue(['fixed_subnet']); } get getNetworkDriver() { const { context = {} } = this.props; - const { - coeSelectRows = "", - coe = "" - } = context; - let networkDriver = []; + const { coeSelectRows = '', coe = '' } = context; + const networkDriver = []; if (!coeSelectRows || !coe) { - networkDriver.push({ val: "docker", name: "Docker" }, { val: "flannel", name: "Flannel" }, { val: "calico", name: "Calico" }) + 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 === '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 === 'kubernetes') { + networkDriver.push( + { val: 'calico', name: 'Calico' }, + { val: 'flannel', name: 'Flannel' } + ); } - if (coeSelectRows === "mesos" || coeSelectRows === "dcos") { - networkDriver.push({ val: "docker", name: "Docker" }) + if (coeSelectRows === 'mesos' || coeSelectRows === 'dcos') { + networkDriver.push({ val: 'docker', name: 'Docker' }); } - return (networkDriver || []) - .map((it) => ({ - value: it.val, - label: it.name, - })); + return (networkDriver || []).map((it) => ({ + value: it.val, + label: it.name, + })); } get defaultValue() { - const values = {}; + let values = {}; if (this.isEdit) { - values.networkDriver = this.props.extra.network_driver; - values.HTTPProxy = this.props.extra.http_proxy; - values.HTTPSProxy = this.props.extra.https_proxy; - values.noProxy = this.props.extra.no_proxy; - values.externalNetworkID = this.props.extra.external_network_id; - values.fixedNetwork = this.props.extra.fixed_network; - values.fixedSubnet = this.props.extra.fixed_subnet; - values.DNS = this.props.extra.dns_nameserver; - values.masterLB = this.props.extra.master_lb_enabled; - values.floatingIP = this.props.extra.floating_ip_enabled; + const { + extra: { + network_driver, + http_proxy, + https_proxy, + no_proxy, + external_network_id, + fixed_network, + fixed_subnet, + dns_nameserver, + master_lb_enabled, + floating_ip_enabled, + } = {}, + } = this.props; + values = { + network_driver, + http_proxy, + https_proxy, + no_proxy, + external_network_id, + fixed_network, + fixed_subnet, + dns_nameserver, + master_lb_enabled, + floating_ip_enabled, + }; } return values; } @@ -130,78 +161,70 @@ export class StepNetwork extends Base { get formItems() { return [ { - name: "networkDriver", - label: t("Network Driver"), - placeholder: t("Choose a Network Driver"), - type: "select", + name: 'network_driver', + label: t('Network Driver'), + placeholder: t('Choose a Network Driver'), + type: 'select', options: this.getNetworkDriver, - allowClear: true, - showSearch: true }, { - name: "HTTPProxy", - label: t("HTTP Proxy"), - placeholder: t("The http_proxy address to use for nodes in cluster"), - type: "input" + name: 'http_proxy', + label: t('HTTP Proxy'), + placeholder: t('The http_proxy address to use for nodes in cluster'), + type: 'input', }, { - name: "HTTPSProxy", - label: t("HTTPS Proxy"), - placeholder: t("The https_proxy address to use for nodes in cluster"), - type: "input" + name: 'https_proxy', + label: t('HTTPS Proxy'), + placeholder: t('The https_proxy address to use for nodes in cluster'), + type: 'input', }, { - name: "noProxy", - label: t("No Proxy"), - placeholder: t("The no_proxy address to use for nodes in cluster"), - type: "input" + name: 'no_proxy', + label: t('No Proxy'), + placeholder: t('The no_proxy address to use for nodes in cluster'), + type: 'input', }, { - name: "externalNetworkID", - label: t("External Network ID"), - placeholder: t("Choose a External Network ID"), - type: "select", + name: 'external_network_id', + label: t('External Network'), + placeholder: t('Choose a External Network'), + type: 'select', options: this.getFloatingIpList, - allowClear: true, - showSearch: true }, { - name: "fixedNetwork", - label: t("Fixed Network"), - placeholder: t("Choose a Private Network ID"), - type: "select", + name: 'fixed_network', + label: t('Fixed Network'), + placeholder: t('Choose a Private Network'), + type: 'select', options: this.getPrivateFloatingIpList, onChange: (val) => this.onSelectChangeFixedNetwork(val), - allowClear: true, - showSearch: true }, { - name: "fixedSubnet", - label: t("Fixed Subnet"), - placeholder: t("Choose a Private Network at first"), - type: "select", + name: 'fixed_subnet', + label: t('Fixed Subnet'), + placeholder: t('Choose a Private Network at first'), + type: 'select', options: this.getSubnetList, - allowClear: true, - showSearch: true }, { - name: "DNS", - label: t("DNS"), - placeholder: t("The DNS nameserver to use for this cluster template"), - type: "input" + name: 'dns_nameserver', + label: t('DNS'), + placeholder: t('The DNS nameserver to use for this cluster template'), + type: 'input', }, { - name: "masterLB", - label: t("Master LB"), - type: "check" + name: 'master_lb_enabled', + label: t('Master LB'), + type: 'check', }, { - name: "floatingIP", - label: t("Floating IP"), - type: "check" - } - ] + name: 'floating_ip_enabled', + label: t('Floating IP'), + type: 'check', + }, + ]; } } -export default inject("rootStore")(observer(StepNetwork)) \ No newline at end of file +export default inject('rootStore')(observer(StepNetwork)); 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 52e7db3c..212ed49b 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 @@ -94,18 +94,33 @@ export class StepNodeSpec extends Base { }; get defaultValue() { - const values = {}; + let values = {}; if (this.isEdit) { - values.image = this.props.extra.image_id; - values.keypair = this.props.extra.keypair_id; - values.flavorCurrent = this.props.extra.flavor_id; - values.flavor = this.props.extra.flavor_id; - values.masterFlavor = this.props.extra.master_flavor_id; - values.masterFlavorCurrent = this.props.extra.master_flavor_id; - values.volumeDriver = this.props.extra.volume_driver; - values.dockerStorageDriver = this.props.extra.docker_storage_driver; - values.dockerVolumeSize = this.props.extra.docker_volume_size; + const { + extra: { + image_id, + keypair_id, + flavor_id, + master_flavor_id, + volume_driver, + docker_storage_driver, + docker_volume_size, + } = {}, + } = this.props; + values = { + image_id, + keypair_id, + volume_driver, + docker_storage_driver, + docker_volume_size, + }; + if (flavor_id) { + values.flavor = { selectedRowKeys: [flavor_id] }; + } + if (master_flavor_id) { + values.masterFlavor = { selectedRowKeys: [master_flavor_id] }; + } } return values; } @@ -113,26 +128,17 @@ export class StepNodeSpec extends Base { get formItems() { return [ { - name: 'image', + name: 'image_id', label: t('Image'), type: 'select', options: this.getImageOsDistroList, - allowClear: true, - showSearch: true, + required: true, }, { - name: 'keypair', + name: 'keypair_id', label: t('Keypair'), type: 'select', options: this.getKeypairList, - allowClear: true, - showSearch: true, - }, - { - name: 'flavorCurrent', - label: t('Current Flavor'), - type: 'label', - iconType: 'flavor', }, { name: 'flavor', @@ -140,12 +146,6 @@ export class StepNodeSpec extends Base { type: 'select-table', component: , }, - { - name: 'masterFlavorCurrent', - label: t('Current Master Flavor'), - type: 'label', - iconType: 'flavor', - }, { name: 'masterFlavor', label: t('Master Flavor'), @@ -153,15 +153,13 @@ export class StepNodeSpec extends Base { component: , }, { - name: 'volumeDriver', + name: 'volume_driver', label: t('Volume Driver'), type: 'select', options: this.getVolumeDriver, - allowClear: true, - showSearch: true, }, { - name: 'dockerStorageDriver', + name: 'docker_storage_driver', label: t('Docker Storage Driver'), type: 'select', options: [ @@ -174,15 +172,13 @@ export class StepNodeSpec extends Base { value: 'overlay2', }, ], - allowClear: true, - showSearch: true, }, { - name: 'dockerVolumeSize', + name: 'docker_volume_size', label: t('Docker Volume Size (GiB)'), - type: 'input-number', - min: '1', - placeholder: 'Spec', + type: 'input-int', + min: 1, + placeholder: t('Spec'), }, ]; } diff --git a/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/index.jsx b/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/index.jsx index fcd29bc4..ba3f82ed 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/index.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/actions/StepCreate/index.jsx @@ -10,14 +10,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -import StepInfo from "./StepInfo"; -import StepNodeSpec from "./StepNodeSpec"; -import StepNetwork from "./StepNetwork"; -import StepLabel from "./StepLabel"; -import { inject, observer } from "mobx-react"; -import { StepAction } from "src/containers/Action"; -import globalClusterTemplateStore from "src/stores/magnum/clusterTemplates"; -import { toJS } from "mobx"; +import { inject, observer } from 'mobx-react'; +import { StepAction } from 'src/containers/Action'; +import globalClusterTemplateStore from 'src/stores/magnum/clusterTemplates'; +import { toJS } from 'mobx'; +import { admission_control_list } from 'resources/magnum/template'; +import StepInfo from './StepInfo'; +import StepNodeSpec from './StepNodeSpec'; +import StepNetwork from './StepNetwork'; +import StepLabel from './StepLabel'; export class StepCreate extends StepAction { init() { @@ -25,29 +26,28 @@ export class StepCreate extends StepAction { this.getDetail(); } - static id = "create-cluster-template"; + static id = 'create-cluster-template'; - static title = t("Create Cluster Template"); + static title = t('Create Cluster Template'); - static path = "/container-infra/cluster-template/create"; + static path = '/container-infra/cluster-template/create'; - static policy = "container-infra:clustertemplate:create"; + static policy = 'container-infra:clustertemplate:create'; static allowed() { return Promise.resolve(true); } get name() { - return t("Create Cluster Template"); + return t('Create Cluster Template'); } get listUrl() { - return this.getRoutePath("clusterTemplate"); + return this.getRoutePath('clusterTemplate'); } get isEdit() { - const { pathname } = this.props.location; - return pathname.indexOf('update') >= 0; + return this.path.includes('update'); } get hasExtraProps() { @@ -75,73 +75,53 @@ export class StepCreate extends StepAction { get steps() { return [ { - title: t("Info *"), - component: StepInfo + title: t('Info *'), + component: StepInfo, }, { - title: t("Node Spec *"), - component: StepNodeSpec + title: t('Node Spec *'), + component: StepNodeSpec, }, { - title: t("Network"), - component: StepNetwork + title: t('Network'), + component: StepNetwork, }, { - title: t("Labels"), - component: StepLabel - } - ] + title: t('Labels'), + component: StepLabel, + }, + ]; } onSubmit = (values) => { + const { flavor, masterFlavor, additionalLabels, ...rest } = values; const requestLabels = {}; - const { additionalLabels } = values; if (additionalLabels) { - additionalLabels.forEach(item => { + additionalLabels.forEach((item) => { const labelKey = item.value.key.toLowerCase().trim(); const labelValue = item.value.value.toLowerCase().trim(); requestLabels[labelKey] = labelValue; - }) + }); } const body = { labels: { ...requestLabels, - admission_control_list: 'NodeRestriction,NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,TaintNodesByCondition,Priority,DefaultTolerationSeconds,DefaultStorageClass,StorageObjectInUseProtection,PersistentVolumeClaimResize,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,RuntimeClass' + admission_control_list, }, - fixed_subnet: values.fixedSubnet, - master_flavor_id: values.masterFlavor, - http_proxy: values.HTTPProxy != null ? values.HTTPProxy : null, - https_proxy: values.HTTPSProxy != null ? values.HTTPSProxy : null, - no_proxy: values.noProxy != null ? values.noProxy : null, - keypair_id: values.keypair, - docker_volume_size: values.dockerVolumeSize, - external_network_id: values.externalNetworkID, - image_id: values.image, - volume_driver: values.volumeDriver, - - public: values.cluster_template_public, - hidden: values.cluster_template_hidden, - tls_disabled: values.tls_disabled, - registry_enabled: values.docker_registry_enabled, - master_lb_enabled: values.masterLB, - floating_ip_enabled: values.floatingIP, - - docker_storage_driver: values.dockerStorageDriver, - name: values.clusterTemplateName, - network_driver: values.networkDriver, - fixed_network: values.fixedNetwork, - coe: values.coe, - flavor_id: values.flavor, - dns_nameserver: values.DNS, + ...rest, + }; + if (flavor) { + body.flavor_id = flavor.selectedRowKeys[0]; + } + if (masterFlavor) { + body.master_flavor_id = masterFlavor.selectedRowKeys[0]; } - if (this.isEdit) { return this.store.update({ id: this.params.id }, body); - } else { - return this.store.create(body); } - } + return this.store.create(body); + }; } -export default inject("rootStore")(observer(StepCreate)) \ No newline at end of file +export default inject('rootStore')(observer(StepCreate)); diff --git a/src/pages/container-infra/containers/ClusterTemplates/actions/index.jsx b/src/pages/container-infra/containers/ClusterTemplates/actions/index.jsx index ee7981c5..cb762a23 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/actions/index.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/actions/index.jsx @@ -9,19 +9,17 @@ // 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 StepCreate from './StepCreate'; -import DeleteClusterTemplates from './Delete'; -import EditClusterTemplateStep from './EditStep'; +import Create from './StepCreate'; +import Delete from './Delete'; +import Edit from './Edit'; const actionConfigs = { rowActions: { - firstAction: DeleteClusterTemplates, - moreActions: [ - { action: EditClusterTemplateStep }, - ], + firstAction: Delete, + moreActions: [{ action: Edit }], }, - batchActions: [DeleteClusterTemplates], - primaryActions: [StepCreate], + batchActions: [Delete], + primaryActions: [Create], }; export default actionConfigs; diff --git a/src/pages/container-infra/containers/ClusterTemplates/index.jsx b/src/pages/container-infra/containers/ClusterTemplates/index.jsx index 6992ce43..ec937278 100644 --- a/src/pages/container-infra/containers/ClusterTemplates/index.jsx +++ b/src/pages/container-infra/containers/ClusterTemplates/index.jsx @@ -38,7 +38,9 @@ export class ClusterTemplates extends Base { title: t('ID'), dataIndex: 'uuid', render: (data) => { - return this.getLinkRender("containerInfraClusterTemplateDetail", data, { id: data }) + return this.getLinkRender('containerInfraClusterTemplateDetail', data, { + id: data, + }); }, }, { @@ -56,10 +58,10 @@ export class ClusterTemplates extends Base { isHideable: true, dataIndex: 'keypair_id', render: (value) => { - return this.getLinkRender("keypairDetail", value, { id: value }) - } + return this.getLinkRender('keypairDetail', value, { id: value }); + }, }, ]; } -export default inject("rootStore")(observer(ClusterTemplates)) \ No newline at end of file +export default inject('rootStore')(observer(ClusterTemplates)); diff --git a/src/pages/container-infra/routes/index.js b/src/pages/container-infra/routes/index.js index 8adace4b..a5cf7dfd 100644 --- a/src/pages/container-infra/routes/index.js +++ b/src/pages/container-infra/routes/index.js @@ -20,7 +20,7 @@ import ClusterTemplates from '../containers/ClusterTemplates'; import ClusterTemplateDetail from '../containers/ClusterTemplates/Detail'; import ClustersCreate from '../containers/Clusters/actions/StepCreate'; import ClustersTemplateCreate from '../containers/ClusterTemplates/actions/StepCreate'; -import StepUpdateClusterTemplate from '../containers/ClusterTemplates/actions/EditStep'; +import StepUpdateClusterTemplate from '../containers/ClusterTemplates/actions/Edit'; const PATH = '/container-infra'; export default [ diff --git a/src/resources/magnum/template.js b/src/resources/magnum/template.js new file mode 100644 index 00000000..d2e3e8a6 --- /dev/null +++ b/src/resources/magnum/template.js @@ -0,0 +1,16 @@ +// Copyright 2022 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. + +export const admission_control_list = + 'NodeRestriction,NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,TaintNodesByCondition,Priority,DefaultTolerationSeconds,DefaultStorageClass,StorageObjectInUseProtection,PersistentVolumeClaimResize,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,RuntimeClass'; diff --git a/src/stores/magnum/clusterTemplates.js b/src/stores/magnum/clusterTemplates.js index 0a4adc57..cb02a666 100644 --- a/src/stores/magnum/clusterTemplates.js +++ b/src/stores/magnum/clusterTemplates.js @@ -32,18 +32,20 @@ export class ClusterTemplatesStore extends Base { } @action - async get(data) { - return this.client.get(data); + async update({ id }, body) { + const newBody = Object.keys(body).map((key) => ({ + path: `/${key}`, + value: key === 'labels' ? JSON.stringify(body[key] || {}) : body[key], + op: [null, undefined, ''].includes(body[key]) ? 'remove' : 'replace', + })); + return this.submitting(this.client.patch(id, newBody)); } - @action - async update({ id }, newbody) { - return this.client.update(id, newbody); - } - - async listDidFetch(items) { - if (!items.length) return items - return items.map(it => ({ ...it, id: it.uuid })); + get mapper() { + return (data) => ({ + ...data, + id: data.uuid, + }); } }