2019-02-21 11:43:40 +01:00
|
|
|
import _, { messages } from 'intl'
|
|
|
|
|
import ActionButton from 'action-button'
|
2019-08-28 16:31:33 +02:00
|
|
|
import Button from 'button'
|
|
|
|
|
import classNames from 'classnames'
|
2019-02-21 11:43:40 +01:00
|
|
|
import decorate from 'apply-decorators'
|
2019-08-28 16:31:33 +02:00
|
|
|
import Icon from 'icon'
|
2019-02-21 11:43:40 +01:00
|
|
|
import PropTypes from 'prop-types'
|
|
|
|
|
import React, { Component } from 'react'
|
|
|
|
|
import Wizard, { Section } from 'wizard'
|
2019-06-27 09:49:58 +02:00
|
|
|
import { addSubscriptions, connectStore } from 'utils'
|
2020-11-24 10:50:40 +01:00
|
|
|
import { createBondedNetwork, createNetwork, createPrivateNetwork, getBondModes, subscribePlugins } from 'xo'
|
|
|
|
|
import { isAdmin, createGetObject, createGetObjectsOfType, getIsPoolAdmin } from 'selectors'
|
2019-02-21 11:43:40 +01:00
|
|
|
import { injectIntl } from 'react-intl'
|
|
|
|
|
import { injectState, provideState } from 'reaclette'
|
|
|
|
|
import { linkState } from 'reaclette-utils'
|
2023-02-23 13:42:03 +01:00
|
|
|
import map from 'lodash/map.js'
|
2019-02-21 11:43:40 +01:00
|
|
|
import { Select, Toggle } from 'form'
|
2020-05-26 16:56:46 +02:00
|
|
|
import { SelectHost, SelectPif, SelectPool } from 'select-objects'
|
2019-02-21 11:43:40 +01:00
|
|
|
|
|
|
|
|
import Page from '../../page'
|
|
|
|
|
import styles from './index.css'
|
|
|
|
|
|
|
|
|
|
const EMPTY = {
|
|
|
|
|
bonded: false,
|
|
|
|
|
bondMode: undefined,
|
2020-05-26 16:56:46 +02:00
|
|
|
networkCenter: undefined,
|
2019-02-21 11:43:40 +01:00
|
|
|
description: '',
|
2019-06-27 09:49:58 +02:00
|
|
|
encapsulation: 'gre',
|
2019-09-17 15:26:19 +02:00
|
|
|
encrypted: false,
|
2019-06-27 09:49:58 +02:00
|
|
|
isPrivate: false,
|
2019-02-21 11:43:40 +01:00
|
|
|
mtu: '',
|
|
|
|
|
name: '',
|
2023-01-30 17:34:21 +01:00
|
|
|
nbd: undefined,
|
2019-08-28 16:31:33 +02:00
|
|
|
networks: [],
|
2019-02-21 11:43:40 +01:00
|
|
|
pif: undefined,
|
|
|
|
|
pifs: [],
|
|
|
|
|
vlan: '',
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-24 10:50:40 +01:00
|
|
|
const LineItem = ({ children }) => <div className={styles.lineItem}>{children}</div>
|
2019-08-28 16:31:33 +02:00
|
|
|
|
|
|
|
|
const Item = ({ label, children, className }) => (
|
|
|
|
|
<span className={styles.item}>
|
|
|
|
|
{label && (
|
|
|
|
|
<span>
|
|
|
|
|
{label}
|
|
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
<span className={classNames(styles.input, className)}>{children}</span>
|
|
|
|
|
</span>
|
|
|
|
|
)
|
|
|
|
|
|
2019-12-03 16:54:19 +01:00
|
|
|
/*
|
|
|
|
|
From XAPI doc, a tunnel can only be created on:
|
|
|
|
|
- Physical PIF
|
|
|
|
|
- Bond master PIF
|
|
|
|
|
- VLAN PIF
|
|
|
|
|
If and only if the PIF:
|
|
|
|
|
- Has an IP configuration
|
|
|
|
|
- is NOT a bond slave
|
|
|
|
|
|
|
|
|
|
For more info see: https://xapi-project.github.io/xapi/design/tunnelling.html
|
|
|
|
|
*/
|
|
|
|
|
const canSupportPrivateNetwork = (pool, pif) =>
|
|
|
|
|
(pif.isBondMaster || pif.physical || pif.vlan !== -1) &&
|
|
|
|
|
pif.mode !== 'None' &&
|
|
|
|
|
!pif.isBondSlave &&
|
|
|
|
|
pif.$host === pool.master
|
|
|
|
|
|
2019-02-21 11:43:40 +01:00
|
|
|
const NewNetwork = decorate([
|
|
|
|
|
connectStore(() => ({
|
2020-10-13 15:30:06 +02:00
|
|
|
isAdmin,
|
2019-02-21 11:43:40 +01:00
|
|
|
isPoolAdmin: getIsPoolAdmin,
|
2019-08-28 16:31:33 +02:00
|
|
|
nPools: createGetObjectsOfType('pool').count(),
|
2019-02-21 11:43:40 +01:00
|
|
|
pool: createGetObject((_, props) => props.location.query.pool),
|
|
|
|
|
})),
|
2020-10-13 15:30:06 +02:00
|
|
|
addSubscriptions(
|
|
|
|
|
({ isAdmin }) =>
|
|
|
|
|
isAdmin && {
|
|
|
|
|
plugins: subscribePlugins,
|
|
|
|
|
}
|
|
|
|
|
),
|
2019-02-21 11:43:40 +01:00
|
|
|
injectIntl,
|
|
|
|
|
provideState({
|
|
|
|
|
initialState: () => ({ ...EMPTY, bondModes: undefined }),
|
|
|
|
|
effects: {
|
2019-08-28 16:31:33 +02:00
|
|
|
addPool() {
|
|
|
|
|
const { state } = this
|
2020-11-24 10:50:40 +01:00
|
|
|
state.networks = [...state.networks, { pool: undefined, pif: undefined }]
|
2019-08-28 16:31:33 +02:00
|
|
|
},
|
|
|
|
|
onChangeNetwork(_, key, pool, pif) {
|
|
|
|
|
const networks = [...this.state.networks]
|
|
|
|
|
const entry = networks[key]
|
|
|
|
|
if (pool !== undefined) {
|
|
|
|
|
entry.pool = pool
|
|
|
|
|
}
|
|
|
|
|
if (pif !== undefined) {
|
|
|
|
|
entry.pif = pif
|
|
|
|
|
}
|
|
|
|
|
this.state.networks = networks
|
|
|
|
|
},
|
2023-01-30 17:34:21 +01:00
|
|
|
onChangeNbd: (_, nbd) => ({ nbd: nbd?.value }),
|
2019-02-21 11:43:40 +01:00
|
|
|
initialize: async () => ({ bondModes: await getBondModes() }),
|
|
|
|
|
linkState,
|
|
|
|
|
onChangeMode: (_, bondMode) => ({ bondMode }),
|
2021-06-03 12:12:59 +02:00
|
|
|
onChangePif:
|
|
|
|
|
(_, value) =>
|
|
|
|
|
({ bonded }) =>
|
|
|
|
|
bonded ? { pifs: value } : { pif: value },
|
2019-06-27 09:49:58 +02:00
|
|
|
onChangeEncapsulation(_, encapsulation) {
|
|
|
|
|
return { encapsulation: encapsulation.value }
|
|
|
|
|
},
|
2020-05-26 16:56:46 +02:00
|
|
|
onChangeCenter(_, networkCenter) {
|
|
|
|
|
this.state.networkCenter = networkCenter
|
|
|
|
|
},
|
2019-11-15 11:05:30 +01:00
|
|
|
onDeletePool(_, { currentTarget: { dataset } }) {
|
2019-08-28 16:31:33 +02:00
|
|
|
const networks = [...this.state.networks]
|
|
|
|
|
networks.splice(dataset.position, 1)
|
|
|
|
|
this.state.networks = networks
|
|
|
|
|
},
|
2019-02-21 11:43:40 +01:00
|
|
|
reset: () => EMPTY,
|
2019-06-27 09:49:58 +02:00
|
|
|
toggleBonded() {
|
|
|
|
|
const { bonded, isPrivate } = this.state
|
|
|
|
|
return {
|
|
|
|
|
...EMPTY,
|
|
|
|
|
bonded: !bonded,
|
|
|
|
|
isPrivate: bonded ? isPrivate : false,
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
togglePrivate() {
|
|
|
|
|
const { bonded, isPrivate } = this.state
|
|
|
|
|
return {
|
|
|
|
|
...EMPTY,
|
|
|
|
|
isPrivate: !isPrivate,
|
|
|
|
|
bonded: isPrivate ? bonded : false,
|
|
|
|
|
}
|
|
|
|
|
},
|
2019-09-17 15:26:19 +02:00
|
|
|
toggleEncrypted() {
|
|
|
|
|
return { encrypted: !this.state.encrypted }
|
|
|
|
|
},
|
2019-02-21 11:43:40 +01:00
|
|
|
},
|
|
|
|
|
computed: {
|
2020-11-24 10:50:40 +01:00
|
|
|
disableAddPool: ({ networks }, { nPools }) => networks.length >= nPools - 1,
|
2019-02-21 11:43:40 +01:00
|
|
|
modeOptions: ({ bondModes }) =>
|
|
|
|
|
bondModes !== undefined
|
|
|
|
|
? bondModes.map(mode => ({
|
|
|
|
|
label: mode,
|
|
|
|
|
value: mode,
|
|
|
|
|
}))
|
|
|
|
|
: [],
|
2021-06-03 12:12:59 +02:00
|
|
|
hostPredicate:
|
|
|
|
|
({ networks }, { pool }) =>
|
|
|
|
|
host =>
|
|
|
|
|
host.$pool === pool.id || networks.some(({ pool }) => pool !== undefined && pool.id === host.$pool),
|
|
|
|
|
pifPredicate:
|
|
|
|
|
(_, { pool }) =>
|
|
|
|
|
pif =>
|
|
|
|
|
!pif.isBondSlave && pif.vlan === -1 && pif.$host === (pool && pool.master),
|
|
|
|
|
pifPredicateSdnController:
|
|
|
|
|
(_, { pool }) =>
|
|
|
|
|
pif =>
|
|
|
|
|
canSupportPrivateNetwork(pool, pif),
|
|
|
|
|
networkPifPredicate:
|
|
|
|
|
({ networks }) =>
|
|
|
|
|
(pif, key) =>
|
|
|
|
|
canSupportPrivateNetwork(networks[key].pool, pif),
|
|
|
|
|
networkPoolPredicate:
|
|
|
|
|
({ networks }, { pool: rootPool }) =>
|
|
|
|
|
(pool, index) =>
|
|
|
|
|
pool.id !== rootPool.id &&
|
|
|
|
|
!networks.some(
|
|
|
|
|
({ pool: networksPool = {} }, networksIndex) => pool.id === networksPool.id && index !== networksIndex
|
|
|
|
|
),
|
2019-06-27 09:49:58 +02:00
|
|
|
isSdnControllerLoaded: (state, { plugins = [] }) =>
|
2020-11-24 10:50:40 +01:00
|
|
|
plugins.some(plugin => plugin.name === 'sdn-controller' && plugin.loaded),
|
2019-02-21 11:43:40 +01:00
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
injectState,
|
|
|
|
|
class extends Component {
|
|
|
|
|
static contextTypes = {
|
|
|
|
|
router: PropTypes.object,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_create = () => {
|
|
|
|
|
const { pool, state } = this.props
|
|
|
|
|
const {
|
|
|
|
|
bonded,
|
|
|
|
|
bondMode,
|
2020-05-26 16:56:46 +02:00
|
|
|
networkCenter,
|
2019-06-27 09:49:58 +02:00
|
|
|
isPrivate,
|
2019-02-21 11:43:40 +01:00
|
|
|
description,
|
2019-06-27 09:49:58 +02:00
|
|
|
encapsulation,
|
2019-09-17 15:26:19 +02:00
|
|
|
encrypted,
|
2019-02-21 11:43:40 +01:00
|
|
|
name,
|
2023-01-30 17:34:21 +01:00
|
|
|
nbd,
|
2019-08-28 16:31:33 +02:00
|
|
|
networks,
|
2019-02-21 11:43:40 +01:00
|
|
|
pif,
|
|
|
|
|
pifs,
|
|
|
|
|
vlan,
|
|
|
|
|
} = state
|
2023-03-14 12:14:16 +01:00
|
|
|
|
|
|
|
|
let { mtu } = state
|
|
|
|
|
mtu = mtu === '' ? undefined : +mtu
|
|
|
|
|
|
2019-02-21 11:43:40 +01:00
|
|
|
return bonded
|
|
|
|
|
? createBondedNetwork({
|
|
|
|
|
bondMode: bondMode.value,
|
|
|
|
|
description,
|
|
|
|
|
mtu,
|
|
|
|
|
name,
|
|
|
|
|
pifs: map(pifs, 'id'),
|
|
|
|
|
pool: pool.id,
|
|
|
|
|
})
|
2019-06-27 09:49:58 +02:00
|
|
|
: isPrivate
|
2019-10-18 17:04:26 +02:00
|
|
|
? (() => {
|
|
|
|
|
const poolIds = [pool.id]
|
|
|
|
|
const pifIds = [pif.id]
|
|
|
|
|
for (const network of networks) {
|
|
|
|
|
poolIds.push(network.pool.id)
|
|
|
|
|
pifIds.push(network.pif.id)
|
|
|
|
|
}
|
|
|
|
|
return createPrivateNetwork({
|
|
|
|
|
poolIds,
|
|
|
|
|
pifIds,
|
|
|
|
|
name,
|
|
|
|
|
description,
|
|
|
|
|
encapsulation,
|
2019-09-17 15:26:19 +02:00
|
|
|
encrypted,
|
2023-03-14 12:14:16 +01:00
|
|
|
mtu,
|
2020-05-26 16:56:46 +02:00
|
|
|
preferredCenter: networkCenter,
|
2019-08-28 16:31:33 +02:00
|
|
|
})
|
2019-10-18 17:04:26 +02:00
|
|
|
})()
|
2019-02-21 11:43:40 +01:00
|
|
|
: createNetwork({
|
|
|
|
|
description,
|
|
|
|
|
mtu,
|
|
|
|
|
name,
|
2023-01-30 17:34:21 +01:00
|
|
|
nbd,
|
2019-03-04 17:45:48 +01:00
|
|
|
pif: pif == null ? undefined : pif.id,
|
2019-02-21 11:43:40 +01:00
|
|
|
pool: pool.id,
|
|
|
|
|
vlan,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_selectPool = pool => {
|
|
|
|
|
const {
|
|
|
|
|
effects,
|
|
|
|
|
location: { pathname },
|
|
|
|
|
} = this.props
|
|
|
|
|
effects.reset()
|
|
|
|
|
this.context.router.push({
|
|
|
|
|
pathname,
|
|
|
|
|
query: pool !== null && { pool: pool.id },
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_renderHeader = () => {
|
|
|
|
|
const { isPoolAdmin, pool } = this.props
|
|
|
|
|
return (
|
|
|
|
|
<h2>
|
|
|
|
|
{isPoolAdmin
|
|
|
|
|
? _('createNewNetworkOn', {
|
|
|
|
|
select: (
|
|
|
|
|
<span className={styles.inlineSelect}>
|
|
|
|
|
<SelectPool onChange={this._selectPool} value={pool} />
|
|
|
|
|
</span>
|
|
|
|
|
),
|
|
|
|
|
})
|
|
|
|
|
: _('createNewNetworkNoPermission')}
|
|
|
|
|
</h2>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
const { state, effects, intl, pool } = this.props
|
|
|
|
|
const {
|
|
|
|
|
bonded,
|
|
|
|
|
bondMode,
|
2020-05-26 16:56:46 +02:00
|
|
|
networkCenter,
|
|
|
|
|
hostPredicate,
|
2019-06-27 09:49:58 +02:00
|
|
|
isPrivate,
|
2019-02-21 11:43:40 +01:00
|
|
|
description,
|
2019-06-27 09:49:58 +02:00
|
|
|
encapsulation,
|
2019-09-17 15:26:19 +02:00
|
|
|
encrypted,
|
2019-02-21 11:43:40 +01:00
|
|
|
modeOptions,
|
|
|
|
|
mtu,
|
|
|
|
|
name,
|
2023-01-30 17:34:21 +01:00
|
|
|
nbd,
|
2019-02-21 11:43:40 +01:00
|
|
|
pif,
|
|
|
|
|
pifPredicate,
|
2019-07-30 15:05:17 +02:00
|
|
|
pifPredicateSdnController,
|
2019-02-21 11:43:40 +01:00
|
|
|
pifs,
|
|
|
|
|
vlan,
|
2019-06-27 09:49:58 +02:00
|
|
|
isSdnControllerLoaded,
|
2019-02-21 11:43:40 +01:00
|
|
|
} = state
|
|
|
|
|
const { formatMessage } = intl
|
|
|
|
|
return (
|
|
|
|
|
<Page header={this._renderHeader()}>
|
|
|
|
|
{pool !== undefined && (
|
|
|
|
|
<form id='networkCreation'>
|
|
|
|
|
<Wizard>
|
|
|
|
|
<Section icon='network' title='newNetworkType'>
|
|
|
|
|
<div>
|
2020-11-24 10:50:40 +01:00
|
|
|
<Toggle onChange={effects.toggleBonded} value={bonded} /> <label>{_('bondedNetwork')}</label>
|
2019-02-21 11:43:40 +01:00
|
|
|
</div>
|
2019-06-27 09:49:58 +02:00
|
|
|
<div>
|
2020-11-24 10:50:40 +01:00
|
|
|
<Toggle disabled={!isSdnControllerLoaded} onChange={effects.togglePrivate} value={isPrivate} />{' '}
|
2019-06-27 09:49:58 +02:00
|
|
|
<label>{_('privateNetwork')}</label>
|
2019-09-04 08:48:27 +02:00
|
|
|
<div>
|
|
|
|
|
<em>
|
|
|
|
|
<Icon icon='info' />{' '}
|
|
|
|
|
<a href='https://xen-orchestra.com/docs/sdn_controller.html#requirements'>
|
|
|
|
|
{_('newNetworkSdnControllerTip')}
|
|
|
|
|
</a>
|
|
|
|
|
</em>
|
|
|
|
|
</div>
|
2019-06-27 09:49:58 +02:00
|
|
|
</div>
|
2019-02-21 11:43:40 +01:00
|
|
|
</Section>
|
|
|
|
|
<Section icon='info' title='newNetworkInfo'>
|
2019-07-30 15:05:17 +02:00
|
|
|
<div className='form-group'>
|
|
|
|
|
<label>{_('newNetworkInterface')}</label>
|
|
|
|
|
<SelectPif
|
|
|
|
|
multi={bonded}
|
|
|
|
|
onChange={effects.onChangePif}
|
2020-11-24 10:50:40 +01:00
|
|
|
predicate={isPrivate ? pifPredicateSdnController : pifPredicate}
|
2019-07-30 15:05:17 +02:00
|
|
|
required={bonded || isPrivate}
|
|
|
|
|
value={bonded ? pifs : pif}
|
|
|
|
|
/>
|
|
|
|
|
<label>{_('newNetworkName')}</label>
|
|
|
|
|
<input
|
|
|
|
|
className='form-control'
|
|
|
|
|
name='name'
|
|
|
|
|
onChange={effects.linkState}
|
|
|
|
|
required
|
|
|
|
|
type='text'
|
|
|
|
|
value={name}
|
|
|
|
|
/>
|
|
|
|
|
<label>{_('newNetworkDescription')}</label>
|
|
|
|
|
<input
|
|
|
|
|
className='form-control'
|
|
|
|
|
name='description'
|
|
|
|
|
onChange={effects.linkState}
|
|
|
|
|
type='text'
|
|
|
|
|
value={description}
|
|
|
|
|
/>
|
2019-09-20 11:19:18 +02:00
|
|
|
<label>{_('newNetworkMtu')}</label>
|
|
|
|
|
<input
|
|
|
|
|
className='form-control'
|
|
|
|
|
name='mtu'
|
|
|
|
|
onChange={effects.linkState}
|
|
|
|
|
placeholder={formatMessage(messages.newNetworkDefaultMtu)}
|
|
|
|
|
type='text'
|
|
|
|
|
value={mtu}
|
|
|
|
|
/>
|
2019-07-30 15:05:17 +02:00
|
|
|
{isPrivate ? (
|
|
|
|
|
<div>
|
|
|
|
|
<label>{_('newNetworkEncapsulation')}</label>
|
|
|
|
|
<Select
|
|
|
|
|
name='encapsulation'
|
|
|
|
|
onChange={effects.onChangeEncapsulation}
|
|
|
|
|
options={[
|
|
|
|
|
{ label: 'GRE', value: 'gre' },
|
|
|
|
|
{ label: 'VxLAN', value: 'vxlan' },
|
|
|
|
|
]}
|
|
|
|
|
value={encapsulation}
|
|
|
|
|
/>
|
2020-11-24 10:50:40 +01:00
|
|
|
<Toggle onChange={effects.toggleEncrypted} value={encrypted} />{' '}
|
2019-09-17 15:26:19 +02:00
|
|
|
<label>{_('newNetworkEncrypted')}</label>
|
|
|
|
|
<div>
|
|
|
|
|
<em>
|
|
|
|
|
<Icon icon='info' /> {_('encryptionWarning')}
|
|
|
|
|
</em>
|
|
|
|
|
</div>
|
2020-05-26 16:56:46 +02:00
|
|
|
<label>{_('newNetworkPreferredCenter')}</label>
|
2020-11-24 10:50:40 +01:00
|
|
|
<SelectHost onChange={effects.onChangeCenter} predicate={hostPredicate} value={networkCenter} />
|
2020-05-26 16:56:46 +02:00
|
|
|
<div>
|
|
|
|
|
<em>
|
|
|
|
|
<Icon icon='info' /> {_('preferredCenterTip')}
|
|
|
|
|
</em>
|
|
|
|
|
</div>
|
2019-08-28 16:31:33 +02:00
|
|
|
<div className='mt-1'>
|
|
|
|
|
{state.networks.map(({ pool, pif }, key) => (
|
|
|
|
|
<div key={key}>
|
|
|
|
|
<LineItem>
|
|
|
|
|
<Item label={_('homeTypePool')}>
|
|
|
|
|
<span className={styles.inlineSelect}>
|
|
|
|
|
<SelectPool
|
2020-11-24 10:50:40 +01:00
|
|
|
onChange={value => effects.onChangeNetwork(key, value)}
|
2019-08-28 16:31:33 +02:00
|
|
|
value={pool}
|
2020-11-24 10:50:40 +01:00
|
|
|
predicate={pool => state.networkPoolPredicate(pool, key)}
|
2019-08-28 16:31:33 +02:00
|
|
|
required
|
|
|
|
|
/>
|
|
|
|
|
</span>
|
|
|
|
|
</Item>
|
|
|
|
|
<Item label={_('pif')}>
|
|
|
|
|
<span className={styles.inlineSelect}>
|
|
|
|
|
<SelectPif
|
2020-11-24 10:50:40 +01:00
|
|
|
onChange={value => effects.onChangeNetwork(key, undefined, value)}
|
2019-08-28 16:31:33 +02:00
|
|
|
value={pif}
|
2020-11-24 10:50:40 +01:00
|
|
|
predicate={pif => state.networkPifPredicate(pif, key)}
|
2019-08-28 16:31:33 +02:00
|
|
|
required
|
|
|
|
|
/>
|
|
|
|
|
</span>
|
|
|
|
|
</Item>
|
|
|
|
|
<Item>
|
2020-11-24 10:50:40 +01:00
|
|
|
<Button onClick={effects.onDeletePool} data-position={key}>
|
2019-08-28 16:31:33 +02:00
|
|
|
<Icon icon='new-vm-remove' />
|
|
|
|
|
</Button>
|
|
|
|
|
</Item>
|
|
|
|
|
</LineItem>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
2020-11-24 10:50:40 +01:00
|
|
|
<ActionButton handler={effects.addPool} disabled={state.disableAddPool} icon='add'>
|
2019-08-28 16:31:33 +02:00
|
|
|
{_('addPool')}
|
|
|
|
|
</ActionButton>
|
|
|
|
|
</div>
|
2019-07-30 15:05:17 +02:00
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div>
|
|
|
|
|
{bonded ? (
|
|
|
|
|
<div>
|
|
|
|
|
<label>{_('newNetworkBondMode')}</label>
|
2020-11-24 10:50:40 +01:00
|
|
|
<Select onChange={effects.onChangeMode} options={modeOptions} required value={bondMode} />
|
2019-07-30 15:05:17 +02:00
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div>
|
|
|
|
|
<label>{_('newNetworkVlan')}</label>
|
|
|
|
|
<input
|
|
|
|
|
className='form-control'
|
|
|
|
|
name='vlan'
|
|
|
|
|
onChange={effects.linkState}
|
2020-11-24 10:50:40 +01:00
|
|
|
placeholder={formatMessage(messages.newNetworkDefaultVlan)}
|
2019-07-30 15:05:17 +02:00
|
|
|
type='text'
|
|
|
|
|
value={vlan}
|
|
|
|
|
/>
|
2023-01-30 17:34:21 +01:00
|
|
|
<label>{_('nbd')}</label>
|
|
|
|
|
<Select
|
|
|
|
|
name='nbd'
|
|
|
|
|
onChange={effects.onChangeNbd}
|
|
|
|
|
options={[
|
|
|
|
|
{ label: _('noNbdConnection'), value: false },
|
|
|
|
|
{ label: _('nbdConnection'), value: true },
|
|
|
|
|
]}
|
|
|
|
|
value={nbd}
|
|
|
|
|
/>
|
2019-07-30 15:05:17 +02:00
|
|
|
</div>
|
2019-06-27 09:49:58 +02:00
|
|
|
)}
|
2019-07-30 15:05:17 +02:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2019-02-21 11:43:40 +01:00
|
|
|
</Section>
|
|
|
|
|
</Wizard>
|
|
|
|
|
<div className='form-group pull-right'>
|
|
|
|
|
<ActionButton
|
|
|
|
|
btnStyle='primary'
|
|
|
|
|
className='mr-1'
|
|
|
|
|
form='networkCreation'
|
|
|
|
|
handler={this._create}
|
|
|
|
|
icon='new-network-create'
|
|
|
|
|
redirectOnSuccess={`pools/${pool.id}/network`}
|
|
|
|
|
>
|
|
|
|
|
{_('newNetworkCreate')}
|
|
|
|
|
</ActionButton>
|
|
|
|
|
<ActionButton handler={effects.reset} icon='reset'>
|
|
|
|
|
{_('formReset')}
|
|
|
|
|
</ActionButton>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
)}
|
|
|
|
|
</Page>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
])
|
|
|
|
|
export { NewNetwork as default }
|