parent
dc34f3478d
commit
7a2a88b7ad
@ -5,6 +5,7 @@
|
|||||||
- [VM migration] Display same-pool hosts first in the selector [#3262](https://github.com/vatesfr/xen-orchestra/issues/3262) (PR [#3890](https://github.com/vatesfr/xen-orchestra/pull/3890))
|
- [VM migration] Display same-pool hosts first in the selector [#3262](https://github.com/vatesfr/xen-orchestra/issues/3262) (PR [#3890](https://github.com/vatesfr/xen-orchestra/pull/3890))
|
||||||
- [Home/VM] Sort VM by start time [#3955](https://github.com/vatesfr/xen-orchestra/issues/3955) (PR [#3970](https://github.com/vatesfr/xen-orchestra/pull/3970))
|
- [Home/VM] Sort VM by start time [#3955](https://github.com/vatesfr/xen-orchestra/issues/3955) (PR [#3970](https://github.com/vatesfr/xen-orchestra/pull/3970))
|
||||||
- [Editable fields] Unfocusing (clicking outside) submits the change instead of canceling (PR [#3980](https://github.com/vatesfr/xen-orchestra/pull/3980))
|
- [Editable fields] Unfocusing (clicking outside) submits the change instead of canceling (PR [#3980](https://github.com/vatesfr/xen-orchestra/pull/3980))
|
||||||
|
- [Network] Dedicated page for network creation [#3895](https://github.com/vatesfr/xen-orchestra/issues/3895) (PR [#3906](https://github.com/vatesfr/xen-orchestra/pull/3906))
|
||||||
|
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
|
||||||
|
@ -101,6 +101,7 @@ const messages = {
|
|||||||
newMenu: 'New',
|
newMenu: 'New',
|
||||||
taskMenu: 'Tasks',
|
taskMenu: 'Tasks',
|
||||||
taskPage: 'Tasks',
|
taskPage: 'Tasks',
|
||||||
|
newNetworkPage: 'Network',
|
||||||
newVmPage: 'VM',
|
newVmPage: 'VM',
|
||||||
newSrPage: 'Storage',
|
newSrPage: 'Storage',
|
||||||
newServerPage: 'Server',
|
newServerPage: 'Server',
|
||||||
@ -563,6 +564,10 @@ const messages = {
|
|||||||
newSrNfsOptions: 'Comma delimited NFS options',
|
newSrNfsOptions: 'Comma delimited NFS options',
|
||||||
reattachNewSrTooltip: 'Reattach SR',
|
reattachNewSrTooltip: 'Reattach SR',
|
||||||
|
|
||||||
|
// ------ New Newtork -----
|
||||||
|
createNewNetworkNoPermission: 'You have no permission to create a network',
|
||||||
|
createNewNetworkOn: 'Create a new network on {select}',
|
||||||
|
|
||||||
// ----- Acls, Users, Groups ------
|
// ----- Acls, Users, Groups ------
|
||||||
subjectName: 'Users/Groups',
|
subjectName: 'Users/Groups',
|
||||||
objectName: 'Object',
|
objectName: 'Object',
|
||||||
@ -1690,7 +1695,6 @@ const messages = {
|
|||||||
|
|
||||||
// ----- Network -----
|
// ----- Network -----
|
||||||
newNetworkCreate: 'Create network',
|
newNetworkCreate: 'Create network',
|
||||||
newBondedNetworkCreate: 'Create bonded network',
|
|
||||||
newNetworkInterface: 'Interface',
|
newNetworkInterface: 'Interface',
|
||||||
newNetworkName: 'Name',
|
newNetworkName: 'Name',
|
||||||
newNetworkDescription: 'Description',
|
newNetworkDescription: 'Description',
|
||||||
@ -1698,13 +1702,14 @@ const messages = {
|
|||||||
newNetworkDefaultVlan: 'No VLAN if empty',
|
newNetworkDefaultVlan: 'No VLAN if empty',
|
||||||
newNetworkMtu: 'MTU',
|
newNetworkMtu: 'MTU',
|
||||||
newNetworkDefaultMtu: 'Default: 1500',
|
newNetworkDefaultMtu: 'Default: 1500',
|
||||||
newNetworkNoNameErrorTitle: 'Name required',
|
|
||||||
newNetworkNoNameErrorMessage: 'A name is required to create a network',
|
|
||||||
newNetworkBondMode: 'Bond mode',
|
newNetworkBondMode: 'Bond mode',
|
||||||
|
newNetworkInfo: 'Info',
|
||||||
|
newNetworkType: 'Type',
|
||||||
deleteNetwork: 'Delete network',
|
deleteNetwork: 'Delete network',
|
||||||
deleteNetworkConfirm: 'Are you sure you want to delete this network?',
|
deleteNetworkConfirm: 'Are you sure you want to delete this network?',
|
||||||
networkInUse: 'This network is currently in use',
|
networkInUse: 'This network is currently in use',
|
||||||
pillBonded: 'Bonded',
|
pillBonded: 'Bonded',
|
||||||
|
bondedNetwork: 'Bonded network',
|
||||||
|
|
||||||
// ----- Add host -----
|
// ----- Add host -----
|
||||||
addHostSelectHost: 'Host',
|
addHostSelectHost: 'Host',
|
||||||
|
@ -1,113 +0,0 @@
|
|||||||
import Component from 'base-component'
|
|
||||||
import map from 'lodash/map'
|
|
||||||
import React from 'react'
|
|
||||||
import { createGetObject, createSelector } from 'selectors'
|
|
||||||
import { getBondModes } from 'xo'
|
|
||||||
import { injectIntl } from 'react-intl'
|
|
||||||
|
|
||||||
import _, { messages } from '../../intl'
|
|
||||||
import { Col } from '../../grid'
|
|
||||||
import { connectStore } from '../../utils'
|
|
||||||
import { SelectPif } from '../../select-objects'
|
|
||||||
import SingleLineRow from '../../single-line-row'
|
|
||||||
|
|
||||||
@connectStore(
|
|
||||||
() => ({
|
|
||||||
poolMaster: createSelector(
|
|
||||||
createGetObject((_, props) => props.pool),
|
|
||||||
pool => pool.master
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
{ withRef: true }
|
|
||||||
)
|
|
||||||
class CreateBondedNetworkModalBody extends Component {
|
|
||||||
componentWillMount() {
|
|
||||||
getBondModes().then(bondModes =>
|
|
||||||
this.setState({ bondModes, bondMode: bondModes[0] })
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
_getPifPredicate = createSelector(
|
|
||||||
() => this.props.poolMaster,
|
|
||||||
hostId => pif => pif.$host === hostId && pif.vlan === -1
|
|
||||||
)
|
|
||||||
|
|
||||||
get value() {
|
|
||||||
const { name, description, pifs, mtu, bondMode } = this.state
|
|
||||||
return {
|
|
||||||
pool: this.props.pool,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
pifs: map(pifs, pif => pif.id),
|
|
||||||
mtu,
|
|
||||||
bondMode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { formatMessage } = this.props.intl
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SingleLineRow>
|
|
||||||
<Col size={6}>{_('newNetworkInterface')}</Col>
|
|
||||||
<Col size={6}>
|
|
||||||
<SelectPif
|
|
||||||
multi
|
|
||||||
onChange={this.linkState('pifs')}
|
|
||||||
predicate={this._getPifPredicate()}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</SingleLineRow>
|
|
||||||
|
|
||||||
<SingleLineRow>
|
|
||||||
<Col size={6}>{_('newNetworkName')}</Col>
|
|
||||||
<Col size={6}>
|
|
||||||
<input
|
|
||||||
className='form-control'
|
|
||||||
onChange={this.linkState('name')}
|
|
||||||
type='text'
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</SingleLineRow>
|
|
||||||
|
|
||||||
<SingleLineRow>
|
|
||||||
<Col size={6}>{_('newNetworkDescription')}</Col>
|
|
||||||
<Col size={6}>
|
|
||||||
<input
|
|
||||||
className='form-control'
|
|
||||||
onChange={this.linkState('description')}
|
|
||||||
type='text'
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</SingleLineRow>
|
|
||||||
|
|
||||||
<SingleLineRow>
|
|
||||||
<Col size={6}>{_('newNetworkMtu')}</Col>
|
|
||||||
<Col size={6}>
|
|
||||||
<input
|
|
||||||
className='form-control'
|
|
||||||
onChange={this.linkState('mtu')}
|
|
||||||
placeholder={formatMessage(messages.newNetworkDefaultMtu)}
|
|
||||||
type='text'
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</SingleLineRow>
|
|
||||||
|
|
||||||
<SingleLineRow>
|
|
||||||
<Col size={6}>{_('newNetworkBondMode')}</Col>
|
|
||||||
<Col size={6}>
|
|
||||||
<select
|
|
||||||
className='form-control'
|
|
||||||
onChange={this.linkState('bondMode')}
|
|
||||||
>
|
|
||||||
{map(this.state.bondModes, mode => (
|
|
||||||
<option value={mode}>{mode}</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</Col>
|
|
||||||
</SingleLineRow>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default injectIntl(CreateBondedNetworkModalBody, { withRef: true })
|
|
@ -1,84 +0,0 @@
|
|||||||
import React, { Component } from 'react'
|
|
||||||
import { injectIntl } from 'react-intl'
|
|
||||||
import { createSelector } from 'selectors'
|
|
||||||
|
|
||||||
import SingleLineRow from '../../single-line-row'
|
|
||||||
import _, { messages } from '../../intl'
|
|
||||||
import { SelectPif } from '../../select-objects'
|
|
||||||
import { Col } from '../../grid'
|
|
||||||
|
|
||||||
class CreateNetworkModalBody extends Component {
|
|
||||||
_getPifPredicate = createSelector(
|
|
||||||
() => {
|
|
||||||
const { container } = this.props
|
|
||||||
return container.type === 'pool' ? container.master : container.id
|
|
||||||
},
|
|
||||||
hostId => pif => pif.$host === hostId && pif.vlan === -1
|
|
||||||
)
|
|
||||||
|
|
||||||
get value() {
|
|
||||||
const { refs } = this
|
|
||||||
const { container } = this.props
|
|
||||||
return {
|
|
||||||
pool: container.$pool,
|
|
||||||
name: refs.name.value,
|
|
||||||
description: refs.description.value,
|
|
||||||
pif: refs.pif.value && refs.pif.value.id,
|
|
||||||
mtu: refs.mtu.value,
|
|
||||||
vlan: refs.vlan.value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { formatMessage } = this.props.intl
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SingleLineRow>
|
|
||||||
<Col size={6}>{_('newNetworkInterface')}</Col>
|
|
||||||
<Col size={6}>
|
|
||||||
<SelectPif predicate={this._getPifPredicate()} ref='pif' />
|
|
||||||
</Col>
|
|
||||||
</SingleLineRow>
|
|
||||||
|
|
||||||
<SingleLineRow>
|
|
||||||
<Col size={6}>{_('newNetworkName')}</Col>
|
|
||||||
<Col size={6}>
|
|
||||||
<input className='form-control' ref='name' type='text' />
|
|
||||||
</Col>
|
|
||||||
</SingleLineRow>
|
|
||||||
|
|
||||||
<SingleLineRow>
|
|
||||||
<Col size={6}>{_('newNetworkDescription')}</Col>
|
|
||||||
<Col size={6}>
|
|
||||||
<input className='form-control' ref='description' type='text' />
|
|
||||||
</Col>
|
|
||||||
</SingleLineRow>
|
|
||||||
|
|
||||||
<SingleLineRow>
|
|
||||||
<Col size={6}>{_('newNetworkVlan')}</Col>
|
|
||||||
<Col size={6}>
|
|
||||||
<input
|
|
||||||
className='form-control'
|
|
||||||
placeholder={formatMessage(messages.newNetworkDefaultVlan)}
|
|
||||||
ref='vlan'
|
|
||||||
type='text'
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</SingleLineRow>
|
|
||||||
|
|
||||||
<SingleLineRow>
|
|
||||||
<Col size={6}>{_('newNetworkMtu')}</Col>
|
|
||||||
<Col size={6}>
|
|
||||||
<input
|
|
||||||
className='form-control'
|
|
||||||
placeholder={formatMessage(messages.newNetworkDefaultMtu)}
|
|
||||||
ref='mtu'
|
|
||||||
type='text'
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</SingleLineRow>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default injectIntl(CreateNetworkModalBody, { withRef: true })
|
|
@ -1627,39 +1627,10 @@ export const setVif = (
|
|||||||
export const editNetwork = (network, props) =>
|
export const editNetwork = (network, props) =>
|
||||||
_call('network.set', { ...props, id: resolveId(network) })
|
_call('network.set', { ...props, id: resolveId(network) })
|
||||||
|
|
||||||
import CreateNetworkModalBody from './create-network-modal' // eslint-disable-line import/first
|
|
||||||
export const createNetwork = container =>
|
|
||||||
confirm({
|
|
||||||
icon: 'network',
|
|
||||||
title: _('newNetworkCreate'),
|
|
||||||
body: <CreateNetworkModalBody container={container} />,
|
|
||||||
}).then(params => {
|
|
||||||
if (!params.name) {
|
|
||||||
return error(
|
|
||||||
_('newNetworkNoNameErrorTitle'),
|
|
||||||
_('newNetworkNoNameErrorMessage')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return _call('network.create', params)
|
|
||||||
}, noop)
|
|
||||||
|
|
||||||
export const getBondModes = () => _call('network.getBondModes')
|
export const getBondModes = () => _call('network.getBondModes')
|
||||||
|
export const createNetwork = params => _call('network.create', params)
|
||||||
import CreateBondedNetworkModalBody from './create-bonded-network-modal' // eslint-disable-line import/first
|
export const createBondedNetwork = params =>
|
||||||
export const createBondedNetwork = container =>
|
_call('network.createBonded', params)
|
||||||
confirm({
|
|
||||||
icon: 'network',
|
|
||||||
title: _('newBondedNetworkCreate'),
|
|
||||||
body: <CreateBondedNetworkModalBody pool={container.$pool} />,
|
|
||||||
}).then(params => {
|
|
||||||
if (!params.name) {
|
|
||||||
return error(
|
|
||||||
_('newNetworkNoNameErrorTitle'),
|
|
||||||
_('newNetworkNoNameErrorMessage')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return _call('network.createBonded', params)
|
|
||||||
}, noop)
|
|
||||||
|
|
||||||
export const deleteNetwork = network =>
|
export const deleteNetwork = network =>
|
||||||
confirm({
|
confirm({
|
||||||
|
@ -854,6 +854,10 @@
|
|||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-database;
|
@extend .fa-database;
|
||||||
}
|
}
|
||||||
|
&-network {
|
||||||
|
@extend .fa;
|
||||||
|
@extend .fa-sitemap;
|
||||||
|
}
|
||||||
&-import {
|
&-import {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-file-archive-o;
|
@extend .fa-file-archive-o;
|
||||||
@ -906,6 +910,13 @@
|
|||||||
@extend .fa-times;
|
@extend .fa-times;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// New network
|
||||||
|
&-new-network {
|
||||||
|
&-create {
|
||||||
|
@extend .fa;
|
||||||
|
@extend .fa-play;
|
||||||
|
}
|
||||||
|
}
|
||||||
// OS Icons
|
// OS Icons
|
||||||
&-centos {
|
&-centos {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
|
@ -369,6 +369,11 @@ export default class Menu extends Component {
|
|||||||
label: 'newVmPage',
|
label: 'newVmPage',
|
||||||
},
|
},
|
||||||
isAdmin && { to: '/new/sr', icon: 'menu-new-sr', label: 'newSrPage' },
|
isAdmin && { to: '/new/sr', icon: 'menu-new-sr', label: 'newSrPage' },
|
||||||
|
isPoolAdmin && {
|
||||||
|
to: '/new/network',
|
||||||
|
icon: 'menu-new-network',
|
||||||
|
label: 'newNetworkPage',
|
||||||
|
},
|
||||||
isAdmin && {
|
isAdmin && {
|
||||||
to: '/settings/servers',
|
to: '/settings/servers',
|
||||||
icon: 'menu-settings-servers',
|
icon: 'menu-settings-servers',
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { routes } from 'utils'
|
import { routes } from 'utils'
|
||||||
|
|
||||||
|
import Network from './network'
|
||||||
import Sr from './sr'
|
import Sr from './sr'
|
||||||
|
|
||||||
const New = routes('vm', {
|
const New = routes('vm', {
|
||||||
|
network: Network,
|
||||||
sr: Sr,
|
sr: Sr,
|
||||||
})(({ children }) => children)
|
})(({ children }) => children)
|
||||||
|
|
||||||
|
5
packages/xo-web/src/xo-app/new/network/index.css
Normal file
5
packages/xo-web/src/xo-app/new/network/index.css
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.inlineSelect {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 1rem;
|
||||||
|
width: 20em;
|
||||||
|
}
|
242
packages/xo-web/src/xo-app/new/network/index.js
Normal file
242
packages/xo-web/src/xo-app/new/network/index.js
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
import _, { messages } from 'intl'
|
||||||
|
import ActionButton from 'action-button'
|
||||||
|
import decorate from 'apply-decorators'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import Wizard, { Section } from 'wizard'
|
||||||
|
import { connectStore } from 'utils'
|
||||||
|
import { createBondedNetwork, createNetwork, getBondModes } from 'xo'
|
||||||
|
import { createGetObject, getIsPoolAdmin } from 'selectors'
|
||||||
|
import { injectIntl } from 'react-intl'
|
||||||
|
import { injectState, provideState } from 'reaclette'
|
||||||
|
import { linkState } from 'reaclette-utils'
|
||||||
|
import { map } from 'lodash'
|
||||||
|
import { Select, Toggle } from 'form'
|
||||||
|
import { SelectPif, SelectPool } from 'select-objects'
|
||||||
|
|
||||||
|
import Page from '../../page'
|
||||||
|
import styles from './index.css'
|
||||||
|
|
||||||
|
const EMPTY = {
|
||||||
|
bonded: false,
|
||||||
|
bondMode: undefined,
|
||||||
|
description: '',
|
||||||
|
mtu: '',
|
||||||
|
name: '',
|
||||||
|
pif: undefined,
|
||||||
|
pifs: [],
|
||||||
|
vlan: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
const NewNetwork = decorate([
|
||||||
|
connectStore(() => ({
|
||||||
|
isPoolAdmin: getIsPoolAdmin,
|
||||||
|
pool: createGetObject((_, props) => props.location.query.pool),
|
||||||
|
})),
|
||||||
|
injectIntl,
|
||||||
|
provideState({
|
||||||
|
initialState: () => ({ ...EMPTY, bondModes: undefined }),
|
||||||
|
effects: {
|
||||||
|
initialize: async () => ({ bondModes: await getBondModes() }),
|
||||||
|
linkState,
|
||||||
|
onChangeMode: (_, bondMode) => ({ bondMode }),
|
||||||
|
onChangePif: (_, value) => ({ bonded }) =>
|
||||||
|
bonded ? { pifs: value } : { pif: value },
|
||||||
|
reset: () => EMPTY,
|
||||||
|
toggleBonded: () => ({ bonded }) => ({
|
||||||
|
...EMPTY,
|
||||||
|
bonded: !bonded,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
modeOptions: ({ bondModes }) =>
|
||||||
|
bondModes !== undefined
|
||||||
|
? bondModes.map(mode => ({
|
||||||
|
label: mode,
|
||||||
|
value: mode,
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
|
pifPredicate: (_, { pool }) => pif =>
|
||||||
|
pif.vlan === -1 && pif.$host === (pool && pool.master),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
injectState,
|
||||||
|
class extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
router: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
|
_create = () => {
|
||||||
|
const { pool, state } = this.props
|
||||||
|
const {
|
||||||
|
bonded,
|
||||||
|
bondMode,
|
||||||
|
description,
|
||||||
|
mtu,
|
||||||
|
name,
|
||||||
|
pif,
|
||||||
|
pifs,
|
||||||
|
vlan,
|
||||||
|
} = state
|
||||||
|
return bonded
|
||||||
|
? createBondedNetwork({
|
||||||
|
bondMode: bondMode.value,
|
||||||
|
description,
|
||||||
|
mtu,
|
||||||
|
name,
|
||||||
|
pifs: map(pifs, 'id'),
|
||||||
|
pool: pool.id,
|
||||||
|
vlan,
|
||||||
|
})
|
||||||
|
: createNetwork({
|
||||||
|
description,
|
||||||
|
mtu,
|
||||||
|
name,
|
||||||
|
pif: pif.id,
|
||||||
|
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,
|
||||||
|
description,
|
||||||
|
modeOptions,
|
||||||
|
mtu,
|
||||||
|
name,
|
||||||
|
pif,
|
||||||
|
pifPredicate,
|
||||||
|
pifs,
|
||||||
|
vlan,
|
||||||
|
} = state
|
||||||
|
const { formatMessage } = intl
|
||||||
|
return (
|
||||||
|
<Page header={this._renderHeader()}>
|
||||||
|
{pool !== undefined && (
|
||||||
|
<form id='networkCreation'>
|
||||||
|
<Wizard>
|
||||||
|
<Section icon='network' title='newNetworkType'>
|
||||||
|
<div>
|
||||||
|
<Toggle onChange={effects.toggleBonded} value={bonded} />{' '}
|
||||||
|
<label>{_('bondedNetwork')}</label>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
<Section icon='info' title='newNetworkInfo'>
|
||||||
|
<div className='form-group'>
|
||||||
|
<label>{_('newNetworkInterface')}</label>
|
||||||
|
<SelectPif
|
||||||
|
multi={bonded}
|
||||||
|
onChange={effects.onChangePif}
|
||||||
|
predicate={pifPredicate}
|
||||||
|
required
|
||||||
|
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}
|
||||||
|
/>
|
||||||
|
<label>{_('newNetworkMtu')}</label>
|
||||||
|
<input
|
||||||
|
className='form-control'
|
||||||
|
name='mtu'
|
||||||
|
onChange={effects.linkState}
|
||||||
|
placeholder={formatMessage(messages.newNetworkDefaultMtu)}
|
||||||
|
type='text'
|
||||||
|
value={mtu}
|
||||||
|
/>
|
||||||
|
{bonded ? (
|
||||||
|
<div>
|
||||||
|
<label>{_('newNetworkBondMode')}</label>
|
||||||
|
<Select
|
||||||
|
onChange={effects.onChangeMode}
|
||||||
|
options={modeOptions}
|
||||||
|
required
|
||||||
|
value={bondMode}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<label>{_('newNetworkVlan')}</label>
|
||||||
|
<input
|
||||||
|
className='form-control'
|
||||||
|
name='vlan'
|
||||||
|
onChange={effects.linkState}
|
||||||
|
placeholder={formatMessage(
|
||||||
|
messages.newNetworkDefaultVlan
|
||||||
|
)}
|
||||||
|
type='text'
|
||||||
|
value={vlan}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</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 }
|
@ -10,10 +10,10 @@ import map from 'lodash/map'
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import some from 'lodash/some'
|
import some from 'lodash/some'
|
||||||
import SortedTable from 'sorted-table'
|
import SortedTable from 'sorted-table'
|
||||||
import TabButton from 'tab-button'
|
|
||||||
import Tooltip from 'tooltip'
|
import Tooltip from 'tooltip'
|
||||||
import { connectStore } from 'utils'
|
import { connectStore } from 'utils'
|
||||||
import { Container, Row, Col } from 'grid'
|
import { Container, Row, Col } from 'grid'
|
||||||
|
import { TabButtonLink } from 'tab-button'
|
||||||
import { Text, Number } from 'editable'
|
import { Text, Number } from 'editable'
|
||||||
import { Toggle } from 'form'
|
import { Toggle } from 'form'
|
||||||
import {
|
import {
|
||||||
@ -24,8 +24,6 @@ import {
|
|||||||
} from 'selectors'
|
} from 'selectors'
|
||||||
import {
|
import {
|
||||||
connectPif,
|
connectPif,
|
||||||
createBondedNetwork,
|
|
||||||
createNetwork,
|
|
||||||
deleteNetwork,
|
deleteNetwork,
|
||||||
disconnectPif,
|
disconnectPif,
|
||||||
editNetwork,
|
editNetwork,
|
||||||
@ -362,19 +360,10 @@ export default class TabNetworks extends Component {
|
|||||||
<Container>
|
<Container>
|
||||||
<Row>
|
<Row>
|
||||||
<Col className='text-xs-right'>
|
<Col className='text-xs-right'>
|
||||||
<TabButton
|
<TabButtonLink
|
||||||
btnStyle='primary'
|
|
||||||
handler={createBondedNetwork}
|
|
||||||
handlerParam={this.props.pool}
|
|
||||||
icon='add'
|
|
||||||
labelId='networkCreateBondedButton'
|
|
||||||
/>
|
|
||||||
<TabButton
|
|
||||||
btnStyle='primary'
|
|
||||||
handler={createNetwork}
|
|
||||||
handlerParam={this.props.pool}
|
|
||||||
icon='add'
|
icon='add'
|
||||||
labelId='networkCreateButton'
|
labelId='networkCreateButton'
|
||||||
|
to={`new/network?pool=${this.props.pool.id}`}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
Loading…
Reference in New Issue
Block a user