feat(xo-web/host/network): display and edit the IPv6 PIF field
This commit is contained in:
parent
b95b1622b1
commit
1becccffbc
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
> Users must be able to say: “Nice enhancement, I'm eager to test it”
|
> Users must be able to say: “Nice enhancement, I'm eager to test it”
|
||||||
|
|
||||||
|
- [Host/Network/PIF] Display and ability to edit IPv6 field [#5400](https://github.com/vatesfr/xen-orchestra/issues/5400) (PR [#7218](https://github.com/vatesfr/xen-orchestra/pull/7218))
|
||||||
|
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
|
||||||
> Users must be able to say: “I had this issue, happy to know it's fixed”
|
> Users must be able to say: “I had this issue, happy to know it's fixed”
|
||||||
@ -28,5 +30,6 @@
|
|||||||
<!--packages-start-->
|
<!--packages-start-->
|
||||||
|
|
||||||
- xo-server minor
|
- xo-server minor
|
||||||
|
- xo-web minor
|
||||||
|
|
||||||
<!--packages-end-->
|
<!--packages-end-->
|
||||||
|
@ -1541,9 +1541,6 @@ export default {
|
|||||||
// Original text: 'Invalid parameters'
|
// Original text: 'Invalid parameters'
|
||||||
configIpErrorTitle: undefined,
|
configIpErrorTitle: undefined,
|
||||||
|
|
||||||
// Original text: 'IP address and netmask required'
|
|
||||||
configIpErrorMessage: undefined,
|
|
||||||
|
|
||||||
// Original text: 'Static IP address'
|
// Original text: 'Static IP address'
|
||||||
staticIp: undefined,
|
staticIp: undefined,
|
||||||
|
|
||||||
|
@ -1596,9 +1596,6 @@ export default {
|
|||||||
// Original text: "Invalid parameters"
|
// Original text: "Invalid parameters"
|
||||||
configIpErrorTitle: 'Paramètres invalides',
|
configIpErrorTitle: 'Paramètres invalides',
|
||||||
|
|
||||||
// Original text: "IP address and netmask required"
|
|
||||||
configIpErrorMessage: 'Adresse IP et masque de réseau requis',
|
|
||||||
|
|
||||||
// Original text: "Static IP address"
|
// Original text: "Static IP address"
|
||||||
staticIp: 'Adresse IP statique',
|
staticIp: 'Adresse IP statique',
|
||||||
|
|
||||||
|
@ -1295,9 +1295,6 @@ export default {
|
|||||||
// Original text: 'Invalid parameters'
|
// Original text: 'Invalid parameters'
|
||||||
configIpErrorTitle: undefined,
|
configIpErrorTitle: undefined,
|
||||||
|
|
||||||
// Original text: 'IP address and netmask required'
|
|
||||||
configIpErrorMessage: undefined,
|
|
||||||
|
|
||||||
// Original text: 'Static IP address'
|
// Original text: 'Static IP address'
|
||||||
staticIp: undefined,
|
staticIp: undefined,
|
||||||
|
|
||||||
|
@ -1491,9 +1491,6 @@ export default {
|
|||||||
// Original text: "Invalid parameters"
|
// Original text: "Invalid parameters"
|
||||||
configIpErrorTitle: 'Invalid parameters',
|
configIpErrorTitle: 'Invalid parameters',
|
||||||
|
|
||||||
// Original text: "IP address and netmask required"
|
|
||||||
configIpErrorMessage: 'IP cím and netmask required',
|
|
||||||
|
|
||||||
// Original text: "Static IP address"
|
// Original text: "Static IP address"
|
||||||
staticIp: 'Static IP cím',
|
staticIp: 'Static IP cím',
|
||||||
|
|
||||||
|
@ -2387,9 +2387,6 @@ export default {
|
|||||||
// Original text: 'Invalid parameters'
|
// Original text: 'Invalid parameters'
|
||||||
configIpErrorTitle: 'Parametri non validi',
|
configIpErrorTitle: 'Parametri non validi',
|
||||||
|
|
||||||
// Original text: 'IP address and netmask required'
|
|
||||||
configIpErrorMessage: 'Indirizzo IP e maschera di rete richiesti',
|
|
||||||
|
|
||||||
// Original text: 'Static IP address'
|
// Original text: 'Static IP address'
|
||||||
staticIp: 'Indirizzo IP statico',
|
staticIp: 'Indirizzo IP statico',
|
||||||
|
|
||||||
|
@ -1298,9 +1298,6 @@ export default {
|
|||||||
// Original text: 'Invalid parameters'
|
// Original text: 'Invalid parameters'
|
||||||
configIpErrorTitle: undefined,
|
configIpErrorTitle: undefined,
|
||||||
|
|
||||||
// Original text: 'IP address and netmask required'
|
|
||||||
configIpErrorMessage: undefined,
|
|
||||||
|
|
||||||
// Original text: 'Static IP address'
|
// Original text: 'Static IP address'
|
||||||
staticIp: undefined,
|
staticIp: undefined,
|
||||||
|
|
||||||
|
@ -1296,9 +1296,6 @@ export default {
|
|||||||
// Original text: 'Invalid parameters'
|
// Original text: 'Invalid parameters'
|
||||||
configIpErrorTitle: undefined,
|
configIpErrorTitle: undefined,
|
||||||
|
|
||||||
// Original text: 'IP address and netmask required'
|
|
||||||
configIpErrorMessage: undefined,
|
|
||||||
|
|
||||||
// Original text: 'Static IP address'
|
// Original text: 'Static IP address'
|
||||||
staticIp: undefined,
|
staticIp: undefined,
|
||||||
|
|
||||||
|
@ -1542,9 +1542,6 @@ export default {
|
|||||||
// Original text: 'Invalid parameters'
|
// Original text: 'Invalid parameters'
|
||||||
configIpErrorTitle: undefined,
|
configIpErrorTitle: undefined,
|
||||||
|
|
||||||
// Original text: 'IP address and netmask required'
|
|
||||||
configIpErrorMessage: undefined,
|
|
||||||
|
|
||||||
// Original text: 'Static IP address'
|
// Original text: 'Static IP address'
|
||||||
staticIp: undefined,
|
staticIp: undefined,
|
||||||
|
|
||||||
|
@ -1990,9 +1990,6 @@ export default {
|
|||||||
// Original text: "Invalid parameters"
|
// Original text: "Invalid parameters"
|
||||||
configIpErrorTitle: 'Geçersiz parametre',
|
configIpErrorTitle: 'Geçersiz parametre',
|
||||||
|
|
||||||
// Original text: "IP address and netmask required"
|
|
||||||
configIpErrorMessage: 'IP adresi ve ağ maskesi gerekli',
|
|
||||||
|
|
||||||
// Original text: "Static IP address"
|
// Original text: "Static IP address"
|
||||||
staticIp: 'Statik IP adresi',
|
staticIp: 'Statik IP adresi',
|
||||||
|
|
||||||
|
@ -1072,11 +1072,13 @@ const messages = {
|
|||||||
defaultLockingMode: 'Default locking mode',
|
defaultLockingMode: 'Default locking mode',
|
||||||
pifConfigureIp: 'Configure IP address',
|
pifConfigureIp: 'Configure IP address',
|
||||||
configIpErrorTitle: 'Invalid parameters',
|
configIpErrorTitle: 'Invalid parameters',
|
||||||
configIpErrorMessage: 'IP address and netmask required',
|
|
||||||
staticIp: 'Static IP address',
|
staticIp: 'Static IP address',
|
||||||
|
staticIpv6: 'Static IPv6 address',
|
||||||
netmask: 'Netmask',
|
netmask: 'Netmask',
|
||||||
dns: 'DNS',
|
dns: 'DNS',
|
||||||
gateway: 'Gateway',
|
gateway: 'Gateway',
|
||||||
|
ipRequired: 'An IP address is required',
|
||||||
|
netmaskRequired: 'Netmask required',
|
||||||
// ----- Host storage tabs -----
|
// ----- Host storage tabs -----
|
||||||
addSrDeviceButton: 'Add a storage',
|
addSrDeviceButton: 'Add a storage',
|
||||||
srType: 'Type',
|
srType: 'Type',
|
||||||
|
@ -2244,11 +2244,13 @@ export const deletePifs = pifs =>
|
|||||||
body: _('deletePifsConfirm', { nPifs: pifs.length }),
|
body: _('deletePifsConfirm', { nPifs: pifs.length }),
|
||||||
}).then(() => Promise.all(map(pifs, pif => _call('pif.delete', { pif: resolveId(pif) }))), noop)
|
}).then(() => Promise.all(map(pifs, pif => _call('pif.delete', { pif: resolveId(pif) }))), noop)
|
||||||
|
|
||||||
export const reconfigurePifIp = (pif, { mode, ip, netmask, gateway, dns }) =>
|
export const reconfigurePifIp = (pif, { mode, ip, ipv6, ipv6Mode, netmask, gateway, dns }) =>
|
||||||
_call('pif.reconfigureIp', {
|
_call('pif.reconfigureIp', {
|
||||||
pif: resolveId(pif),
|
pif: resolveId(pif),
|
||||||
mode,
|
mode,
|
||||||
ip,
|
ip,
|
||||||
|
ipv6,
|
||||||
|
ipv6Mode,
|
||||||
netmask,
|
netmask,
|
||||||
gateway,
|
gateway,
|
||||||
dns,
|
dns,
|
||||||
@ -2256,6 +2258,8 @@ export const reconfigurePifIp = (pif, { mode, ip, netmask, gateway, dns }) =>
|
|||||||
|
|
||||||
export const getIpv4ConfigModes = () => _call('pif.getIpv4ConfigurationModes')
|
export const getIpv4ConfigModes = () => _call('pif.getIpv4ConfigurationModes')
|
||||||
|
|
||||||
|
export const getIpv6ConfigModes = () => _call('pif.getIpv6ConfigurationModes')
|
||||||
|
|
||||||
export const editPif = (pif, { vlan }) => _call('pif.editPif', { pif: resolveId(pif), vlan })
|
export const editPif = (pif, { vlan }) => _call('pif.editPif', { pif: resolveId(pif), vlan })
|
||||||
|
|
||||||
export const scanHostPifs = hostId => _call('host.scanPifs', { host: hostId })
|
export const scanHostPifs = hostId => _call('host.scanPifs', { host: hostId })
|
||||||
|
@ -26,6 +26,7 @@ import {
|
|||||||
editNetwork,
|
editNetwork,
|
||||||
editPif,
|
editPif,
|
||||||
getIpv4ConfigModes,
|
getIpv4ConfigModes,
|
||||||
|
getIpv6ConfigModes,
|
||||||
reconfigurePifIp,
|
reconfigurePifIp,
|
||||||
scanHostPifs,
|
scanHostPifs,
|
||||||
} from 'xo'
|
} from 'xo'
|
||||||
@ -41,7 +42,10 @@ class ConfigureIpModal extends Component {
|
|||||||
|
|
||||||
const { pif } = props
|
const { pif } = props
|
||||||
if (pif) {
|
if (pif) {
|
||||||
this.state = pick(pif, ['ip', 'netmask', 'dns', 'gateway'])
|
this.state = {
|
||||||
|
...pick(pif, ['ip', 'netmask', 'dns', 'gateway']),
|
||||||
|
ipv6: pif.ipv6?.[0],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +54,7 @@ class ConfigureIpModal extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { ip, netmask, dns, gateway } = this.state
|
const { ip, ipv6, netmask, dns, gateway } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -61,6 +65,13 @@ class ConfigureIpModal extends Component {
|
|||||||
</Col>
|
</Col>
|
||||||
</SingleLineRow>
|
</SingleLineRow>
|
||||||
|
|
||||||
|
<SingleLineRow>
|
||||||
|
<Col size={6}>{_('staticIpv6')}</Col>
|
||||||
|
<Col size={6}>
|
||||||
|
<input className='form-control' onChange={this.linkState('ipv6')} value={ipv6} />
|
||||||
|
</Col>
|
||||||
|
</SingleLineRow>
|
||||||
|
|
||||||
<SingleLineRow>
|
<SingleLineRow>
|
||||||
<Col size={6}>{_('netmask')}</Col>
|
<Col size={6}>{_('netmask')}</Col>
|
||||||
<Col size={6}>
|
<Col size={6}>
|
||||||
@ -111,14 +122,19 @@ const reconfigureIp = (pif, mode) => {
|
|||||||
title: _('pifConfigureIp'),
|
title: _('pifConfigureIp'),
|
||||||
body: <ConfigureIpModal pif={pif} />,
|
body: <ConfigureIpModal pif={pif} />,
|
||||||
}).then(params => {
|
}).then(params => {
|
||||||
if (!params.ip || !params.netmask) {
|
if (params.ip === undefined && params.ipv6 === undefined) {
|
||||||
error(_('configIpErrorTitle'), _('configIpErrorMessage'))
|
return error(_('configIpErrorTitle'), _('ipRequired'))
|
||||||
return
|
}
|
||||||
|
if (params.ip !== undefined && params.netmask === undefined) {
|
||||||
|
return error(_('configIpErrorTitle'), _('netmaskRequired'))
|
||||||
|
}
|
||||||
|
if (params.ipv6 !== undefined) {
|
||||||
|
params.ipv6Mode = mode
|
||||||
}
|
}
|
||||||
return reconfigurePifIp(pif, { mode, ...params })
|
return reconfigurePifIp(pif, { mode, ...params })
|
||||||
}, noop)
|
}, noop)
|
||||||
}
|
}
|
||||||
return reconfigurePifIp(pif, { mode })
|
return reconfigurePifIp(pif, { [pif.primaryAddressType === 'IPv6' ? 'ipv6Mode' : 'mode']: mode })
|
||||||
}
|
}
|
||||||
|
|
||||||
class PifItemIp extends Component {
|
class PifItemIp extends Component {
|
||||||
@ -126,7 +142,7 @@ class PifItemIp extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { pif } = this.props
|
const { pif } = this.props
|
||||||
const pifIp = pif.ip
|
const pifIp = pif.primaryAddressType === 'IPv6' ? pif.ipv6?.[0] : pif.ip
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{pifIp}{' '}
|
{pifIp}{' '}
|
||||||
@ -143,26 +159,41 @@ class PifItemIp extends Component {
|
|||||||
class PifItemMode extends Component {
|
class PifItemMode extends Component {
|
||||||
state = { configModes: [] }
|
state = { configModes: [] }
|
||||||
|
|
||||||
componentDidMount() {
|
async componentDidMount() {
|
||||||
getIpv4ConfigModes().then(configModes => this.setState({ configModes }))
|
const [ipv4ConfigModes, ipv6ConfigModes] = await Promise.all([getIpv4ConfigModes(), getIpv6ConfigModes()])
|
||||||
|
this.setState({ ipv4ConfigModes, ipv6ConfigModes })
|
||||||
}
|
}
|
||||||
|
|
||||||
_configIp = mode => mode != null && reconfigureIp(this.props.pif, mode.value)
|
_configIp = mode => mode != null && reconfigureIp(this.props.pif, mode.value)
|
||||||
|
|
||||||
|
_isIpv6 = createSelector(
|
||||||
|
() => this.props.pif.primaryAddressType,
|
||||||
|
primaryAddressType => primaryAddressType === 'IPv6'
|
||||||
|
)
|
||||||
|
|
||||||
_getOptions = createSelector(
|
_getOptions = createSelector(
|
||||||
() => this.state.configModes,
|
this._isIpv6,
|
||||||
configModes => configModes.map(mode => ({ label: mode, value: mode }))
|
() => this.state.ipv4ConfigModes,
|
||||||
|
() => this.state.ipv6ConfigModes,
|
||||||
|
(isIpv6, ipv4ConfigModes, ipv6ConfigModes) =>
|
||||||
|
(isIpv6 ? ipv6ConfigModes : ipv4ConfigModes).map(mode => ({ label: mode, value: mode }))
|
||||||
)
|
)
|
||||||
|
|
||||||
_getValue = createSelector(
|
_getValue = createSelector(
|
||||||
|
this._isIpv6,
|
||||||
() => this.props.pif.mode,
|
() => this.props.pif.mode,
|
||||||
mode => ({ label: mode, value: mode })
|
() => this.props.pif.ipv6Mode,
|
||||||
|
(isIpv6, mode, ipv6Mode) => {
|
||||||
|
mode = isIpv6 ? ipv6Mode : mode
|
||||||
|
return { label: mode, value: mode }
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const isIpv6 = this._isIpv6()
|
||||||
return (
|
return (
|
||||||
<Select onChange={this._configIp} options={this._getOptions()} value={this._getValue()}>
|
<Select onChange={this._configIp} options={this._getOptions()} value={this._getValue()}>
|
||||||
{this.props.pif.mode}
|
{this.props.pif[isIpv6 ? 'ipv6Mode' : 'mode']}
|
||||||
</Select>
|
</Select>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user