feat(xo-web/VM): change the "share" button position (#2667)

Fixes #2663
This commit is contained in:
badrAZ 2018-02-28 14:10:27 +01:00 committed by Pierre Donias
parent 30483ab2d9
commit c62cab39f1
3 changed files with 345 additions and 349 deletions

View File

@ -99,11 +99,14 @@ set.params = {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
export function get ({ id }) { export function get ({ id }) {
const { user } = this
if (!user) {
throw unauthorized()
}
return this.getResourceSet(id) return this.getResourceSet(id)
} }
get.permission = 'admin'
get.params = { get.params = {
id: { id: {
type: 'string', type: 'string',

View File

@ -1201,11 +1201,14 @@ export const createVgpu = (vm, { gpuGroup, vgpuType }) =>
export const deleteVgpu = vgpu => _call('vm.deleteVgpu', resolveIds({ vgpu })) export const deleteVgpu = vgpu => _call('vm.deleteVgpu', resolveIds({ vgpu }))
export const shareVm = (vm, resourceSet) => export const shareVm = async (vm, resourceSet) =>
confirm({ confirm({
title: _('shareVmInResourceSetModalTitle'), title: _('shareVmInResourceSetModalTitle'),
body: _('shareVmInResourceSetModalMessage', { body: _('shareVmInResourceSetModalMessage', {
self: renderXoItem(resourceSet), self: renderXoItem({
...(await getResourceSet(resourceSet)),
type: 'resourceSet',
}),
}), }),
}).then(() => editVm(vm, { share: true }), noop) }).then(() => editVm(vm, { share: true }), noop)
@ -1682,6 +1685,9 @@ export const deleteResourceSet = async id => {
export const recomputeResourceSetsLimits = () => export const recomputeResourceSetsLimits = () =>
_call('resourceSet.recomputeAllLimits') _call('resourceSet.recomputeAllLimits')
export const getResourceSet = id =>
_call('resourceSet.get', { id: resolveId(id) })
// Remote ------------------------------------------------------------ // Remote ------------------------------------------------------------
export const getRemote = remote => export const getRemote = remote =>

View File

@ -42,16 +42,16 @@ import {
XEN_DEFAULT_CPU_WEIGHT, XEN_DEFAULT_CPU_WEIGHT,
XEN_VIDEORAM_VALUES, XEN_VIDEORAM_VALUES,
} from 'xo' } from 'xo'
import { import { createGetObjectsOfType, createSelector, isAdmin } from 'selectors'
createGetObjectsOfType,
createSelector, // Button's height = react-select's height(36 px) + react-select's border-width(1 px) * 2
getCheckPermissions, // https://github.com/JedWatson/react-select/blob/916ab0e62fc7394be8e24f22251c399a68de8b1c/less/select.less#L21, L22
isAdmin, const SHARE_BUTTON_STYLE = { height: '38px' }
} from 'selectors'
const forceReboot = vm => restartVm(vm, true) const forceReboot = vm => restartVm(vm, true)
const forceShutdown = vm => stopVm(vm, true) const forceShutdown = vm => stopVm(vm, true)
const fullCopy = vm => cloneVm(vm, true) const fullCopy = vm => cloneVm(vm, true)
const shareVmProxy = vm => shareVm(vm, vm.resourceSet)
@connectStore(() => { @connectStore(() => {
const getAffinityHost = createGetObjectsOfType('host').find((_, { vm }) => ({ const getAffinityHost = createGetObjectsOfType('host').find((_, { vm }) => ({
@ -128,31 +128,6 @@ class ResourceSetItem extends Component {
} }
} }
@addSubscriptions({
resourceSets: subscribeResourceSets,
})
class ShareVmButton extends Component {
_shareVm = () => {
const { resourceSets, vm } = this.props
return shareVm(vm, {
...find(resourceSets, { id: vm.resourceSet }),
type: 'resourceSet',
})
}
render () {
return (
<TabButton
btnStyle='primary'
handler={this._shareVm}
icon='vm-share'
labelId='vmShareButton'
/>
)
}
}
class NewVgpu extends Component { class NewVgpu extends Component {
get value () { get value () {
return this.state return this.state
@ -315,332 +290,322 @@ export default connectStore(() => {
createSelector(getVgpus, vgpus => map(vgpus, 'gpuGroup')) createSelector(getVgpus, vgpus => map(vgpus, 'gpuGroup'))
) )
const getCanAdministrate = createSelector(
getCheckPermissions,
(_, props) => props.vm.id,
(check, id) => check(id, 'administrate')
)
return { return {
canAdministrate: getCanAdministrate,
gpuGroup: getGpuGroup, gpuGroup: getGpuGroup,
isAdmin, isAdmin,
vgpus: getVgpus, vgpus: getVgpus,
vgpuTypes: getVgpuTypes, vgpuTypes: getVgpuTypes,
} }
})( })(({ container, gpuGroup, isAdmin, vgpus, vgpuTypes, vm }) => (
({ canAdministrate, container, gpuGroup, isAdmin, vgpus, vgpuTypes, vm }) => ( <Container>
<Container> <Row>
<Row> <Col className='text-xs-right'>
<Col className='text-xs-right'> {vm.power_state === 'Running' && (
{(isAdmin || canAdministrate) && <span>
vm.resourceSet != null && <ShareVmButton vm={vm} />} <TabButton
{vm.power_state === 'Running' && ( btnStyle='primary'
<span> handler={suspendVm}
<TabButton handlerParam={vm}
btnStyle='primary' icon='vm-suspend'
handler={suspendVm} labelId='suspendVmLabel'
handlerParam={vm} />
icon='vm-suspend' <TabButton
labelId='suspendVmLabel' btnStyle='warning'
/> handler={forceReboot}
<TabButton handlerParam={vm}
btnStyle='warning' icon='vm-force-reboot'
handler={forceReboot} labelId='forceRebootVmLabel'
handlerParam={vm} />
icon='vm-force-reboot' <TabButton
labelId='forceRebootVmLabel' btnStyle='warning'
/> handler={forceShutdown}
<TabButton handlerParam={vm}
btnStyle='warning' icon='vm-force-shutdown'
handler={forceShutdown} labelId='forceShutdownVmLabel'
handlerParam={vm} />
icon='vm-force-shutdown' </span>
labelId='forceShutdownVmLabel' )}
/> {vm.power_state === 'Halted' && (
</span> <span>
)} <TabButton
{vm.power_state === 'Halted' && ( btnStyle='primary'
<span> handler={recoveryStartVm}
<TabButton handlerParam={vm}
btnStyle='primary' icon='vm-recovery-mode'
handler={recoveryStartVm} labelId='recoveryModeLabel'
handlerParam={vm} />
icon='vm-recovery-mode' <TabButton
labelId='recoveryModeLabel' btnStyle='primary'
/> handler={fullCopy}
<TabButton handlerParam={vm}
btnStyle='primary' icon='vm-clone'
handler={fullCopy} labelId='cloneVmLabel'
handlerParam={vm} />
icon='vm-clone' <TabButton
labelId='cloneVmLabel' btnStyle='danger'
/> handler={convertVmToTemplate}
<TabButton handlerParam={vm}
btnStyle='danger' icon='vm-create-template'
handler={convertVmToTemplate} labelId='vmConvertButton'
handlerParam={vm} redirectOnSuccess='/'
icon='vm-create-template' />
labelId='vmConvertButton' </span>
redirectOnSuccess='/' )}
/> {vm.power_state === 'Suspended' && (
</span> <span>
)} <TabButton
{vm.power_state === 'Suspended' && ( btnStyle='primary'
<span> handler={resumeVm}
<TabButton handlerParam={vm}
btnStyle='primary' icon='vm-start'
handler={resumeVm} labelId='resumeVmLabel'
handlerParam={vm} />
icon='vm-start' <TabButton
labelId='resumeVmLabel' btnStyle='warning'
/> handler={forceShutdown}
<TabButton handlerParam={vm}
btnStyle='warning' icon='vm-force-shutdown'
handler={forceShutdown} labelId='forceShutdownVmLabel'
handlerParam={vm} />
icon='vm-force-shutdown' </span>
labelId='forceShutdownVmLabel' )}
/> <TabButton
</span> btnStyle='danger'
)} handler={deleteVm}
<TabButton handlerParam={vm}
btnStyle='danger' icon='vm-delete'
handler={deleteVm} labelId='vmRemoveButton'
handlerParam={vm} />
icon='vm-delete' </Col>
labelId='vmRemoveButton' </Row>
/> <Row>
</Col> <Col>
</Row> <h3>{_('xenSettingsLabel')}</h3>
<Row> <table className='table'>
<Col> <tbody>
<h3>{_('xenSettingsLabel')}</h3> <tr>
<table className='table'> <th>{_('uuid')}</th>
<tbody> <Copiable tagName='td'>{vm.uuid}</Copiable>
</tr>
<tr>
<th>{_('virtualizationMode')}</th>
<td>
{vm.virtualizationMode === 'pv'
? _('paraVirtualizedMode')
: _('hardwareVirtualizedMode')}
</td>
</tr>
{vm.virtualizationMode === 'pv' && (
<tr> <tr>
<th>{_('uuid')}</th> <th>{_('pvArgsLabel')}</th>
<Copiable tagName='td'>{vm.uuid}</Copiable>
</tr>
<tr>
<th>{_('virtualizationMode')}</th>
<td> <td>
{vm.virtualizationMode === 'pv' <Text
? _('paraVirtualizedMode') value={vm.PV_args}
: _('hardwareVirtualizedMode')} onChange={value => editVm(vm, { PV_args: value })}
/>
</td> </td>
</tr> </tr>
{vm.virtualizationMode === 'pv' && ( )}
<tr> <tr>
<th>{_('pvArgsLabel')}</th> <th>{_('cpuWeightLabel')}</th>
<td> <td>
<Text <Number
value={vm.PV_args} value={vm.cpuWeight == null ? null : vm.cpuWeight}
onChange={value => editVm(vm, { PV_args: value })} onChange={value => editVm(vm, { cpuWeight: value })}
/> nullable
</td> >
</tr> {vm.cpuWeight == null
)} ? _('defaultCpuWeight', { value: XEN_DEFAULT_CPU_WEIGHT })
: vm.cpuWeight}
</Number>
</td>
</tr>
<tr>
<th>{_('cpuCapLabel')}</th>
<td>
<Number
value={vm.cpuCap == null ? null : vm.cpuCap}
onChange={value => editVm(vm, { cpuCap: value })}
nullable
>
{vm.cpuCap == null
? _('defaultCpuCap', { value: XEN_DEFAULT_CPU_CAP })
: vm.cpuCap}
</Number>
</td>
</tr>
<tr>
<th>{_('autoPowerOn')}</th>
<td>
<Toggle
value={Boolean(vm.auto_poweron)}
onChange={value => editVm(vm, { auto_poweron: value })}
/>
</td>
</tr>
<tr>
<th>{_('ha')}</th>
<td>
<Toggle
value={vm.high_availability}
onChange={value => editVm(vm, { high_availability: value })}
/>
</td>
</tr>
<tr>
<th>{_('vmAffinityHost')}</th>
<td>
<AffinityHost vm={vm} />
</td>
</tr>
{vm.virtualizationMode === 'hvm' && (
<tr> <tr>
<th>{_('cpuWeightLabel')}</th> <th>{_('vmVgpus')}</th>
<td> <td>
<Number <Vgpus vgpus={vgpus} vm={vm} />
value={vm.cpuWeight == null ? null : vm.cpuWeight}
onChange={value => editVm(vm, { cpuWeight: value })}
nullable
>
{vm.cpuWeight == null
? _('defaultCpuWeight', { value: XEN_DEFAULT_CPU_WEIGHT })
: vm.cpuWeight}
</Number>
</td> </td>
</tr> </tr>
)}
{vm.virtualizationMode === 'hvm' && (
<tr> <tr>
<th>{_('cpuCapLabel')}</th> <th>{_('vmVga')}</th>
<td>
<Number
value={vm.cpuCap == null ? null : vm.cpuCap}
onChange={value => editVm(vm, { cpuCap: value })}
nullable
>
{vm.cpuCap == null
? _('defaultCpuCap', { value: XEN_DEFAULT_CPU_CAP })
: vm.cpuCap}
</Number>
</td>
</tr>
<tr>
<th>{_('autoPowerOn')}</th>
<td> <td>
<Toggle <Toggle
value={Boolean(vm.auto_poweron)} value={vm.vga === 'std'}
onChange={value => editVm(vm, { auto_poweron: value })} onChange={value =>
editVm(vm, { vga: value ? 'std' : 'cirrus' })
}
/> />
</td> </td>
</tr> </tr>
)}
{vm.vga === 'std' && (
<tr> <tr>
<th>{_('ha')}</th> <th>{_('vmVideoram')}</th>
<td> <td>
<Toggle <select
value={vm.high_availability} className='form-control'
onChange={value => editVm(vm, { high_availability: value })} onChange={event =>
/> editVm(vm, { videoram: +getEventValue(event) })
}
value={vm.videoram}
>
{map(XEN_VIDEORAM_VALUES, val => (
<option key={val} value={val}>
{formatSize(val * 1048576)}
</option>
))}
</select>
</td> </td>
</tr> </tr>
<tr> )}
<th>{_('vmAffinityHost')}</th> </tbody>
<td> </table>
<AffinityHost vm={vm} /> <br />
</td> <h3>{_('vmLimitsLabel')}</h3>
</tr> <table className='table table-hover'>
{vm.virtualizationMode === 'hvm' && ( <tbody>
<tr> <tr>
<th>{_('vmVgpus')}</th> <th>{_('vmCpuLimitsLabel')}</th>
<td> <td>
<Vgpus vgpus={vgpus} vm={vm} /> <Number
</td> value={vm.CPUs.number}
</tr> onChange={cpus => editVm(vm, { cpus })}
)} />
{vm.virtualizationMode === 'hvm' && ( /
<tr> {vm.power_state === 'Running' ? (
<th>{_('vmVga')}</th> vm.CPUs.max
<td> ) : (
<Toggle
value={vm.vga === 'std'}
onChange={value =>
editVm(vm, { vga: value ? 'std' : 'cirrus' })
}
/>
</td>
</tr>
)}
{vm.vga === 'std' && (
<tr>
<th>{_('vmVideoram')}</th>
<td>
<select
className='form-control'
onChange={event =>
editVm(vm, { videoram: +getEventValue(event) })
}
value={vm.videoram}
>
{map(XEN_VIDEORAM_VALUES, val => (
<option key={val} value={val}>
{formatSize(val * 1048576)}
</option>
))}
</select>
</td>
</tr>
)}
</tbody>
</table>
<br />
<h3>{_('vmLimitsLabel')}</h3>
<table className='table table-hover'>
<tbody>
<tr>
<th>{_('vmCpuLimitsLabel')}</th>
<td>
<Number <Number
value={vm.CPUs.number} value={vm.CPUs.max}
onChange={cpus => editVm(vm, { cpus })} onChange={cpusStaticMax => editVm(vm, { cpusStaticMax })}
/> />
/ )}
{vm.power_state === 'Running' ? ( </td>
vm.CPUs.max </tr>
) : ( <tr>
<Number <th>{_('vmCpuTopology')}</th>
value={vm.CPUs.max} <td>
onChange={cpusStaticMax => editVm(vm, { cpusStaticMax })} <CoresPerSocket container={container} vm={vm} />
/> </td>
)} </tr>
</td> <tr>
</tr> <th>{_('vmMemoryLimitsLabel')}</th>
<tr> <td>
<th>{_('vmCpuTopology')}</th> <p>
<td> Static: {formatSize(vm.memory.static[0])}/<Size
<CoresPerSocket container={container} vm={vm} /> value={defined(vm.memory.static[1], null)}
</td> onChange={memoryStaticMax =>
</tr> editVm(vm, { memoryStaticMax })
<tr> }
<th>{_('vmMemoryLimitsLabel')}</th> />
<td> </p>
<p> <p>
Static: {formatSize(vm.memory.static[0])}/<Size Dynamic:{' '}
value={defined(vm.memory.static[1], null)} <Size
onChange={memoryStaticMax => value={defined(vm.memory.dynamic[0], null)}
editVm(vm, { memoryStaticMax }) onChange={memoryMin => editVm(vm, { memoryMin })}
} />/<Size
/> value={defined(vm.memory.dynamic[1], null)}
</p> onChange={memoryMax => editVm(vm, { memoryMax })}
<p> />
Dynamic:{' '} </p>
<Size </td>
value={defined(vm.memory.dynamic[0], null)} </tr>
onChange={memoryMin => editVm(vm, { memoryMin })} </tbody>
/>/<Size </table>
value={defined(vm.memory.dynamic[1], null)} <br />
onChange={memoryMax => editVm(vm, { memoryMax })} <h3>{_('guestOsLabel')}</h3>
/> <table className='table table-hover'>
</p> <tbody>
</td> <tr>
</tr> <th>{_('xenToolsStatus')}</th>
</tbody> <td>
</table> {_('xenToolsStatusValue', {
<br /> status: normalizeXenToolsStatus(vm.xenTools),
<h3>{_('guestOsLabel')}</h3> })}
<table className='table table-hover'> </td>
<tbody> </tr>
<tr> <tr>
<th>{_('xenToolsStatus')}</th> <th>{_('osName')}</th>
<td> <td>
{_('xenToolsStatusValue', { {isEmpty(vm.os_version) ? (
status: normalizeXenToolsStatus(vm.xenTools), _('unknownOsName')
})} ) : (
</td> <span>
</tr> <Icon
<tr> className='text-info'
<th>{_('osName')}</th> icon={osFamily(vm.os_version.distro)}
<td> />&nbsp;{vm.os_version.name}
{isEmpty(vm.os_version) ? ( </span>
_('unknownOsName') )}
) : ( </td>
<span> </tr>
<Icon <tr>
className='text-info' <th>{_('osKernel')}</th>
icon={osFamily(vm.os_version.distro)} <td>
/>&nbsp;{vm.os_version.name} {(vm.os_version && vm.os_version.uname) || _('unknownOsKernel')}
</span> </td>
)} </tr>
</td> </tbody>
</tr> </table>
<tr> <br />
<th>{_('osKernel')}</th> <h3>{_('miscLabel')}</h3>
<td> <table className='table table-hover'>
{(vm.os_version && vm.os_version.uname) || <tbody>
_('unknownOsKernel')} <tr>
</td> <th>{_('originalTemplate')}</th>
</tr> <td>
</tbody> {vm.other.base_template_name
</table> ? vm.other.base_template_name
<br /> : _('unknownOriginalTemplate')}
<h3>{_('miscLabel')}</h3> </td>
<table className='table table-hover'> </tr>
<tbody> <tr>
<tr> <th>{_('resourceSet')}</th>
<th>{_('originalTemplate')}</th> <td>
<td> {isAdmin ? (
{vm.other.base_template_name <div className='input-group'>
? vm.other.base_template_name
: _('unknownOriginalTemplate')}
</td>
</tr>
<tr>
<th>{_('resourceSet')}</th>
<td>
{isAdmin ? (
<SelectResourceSet <SelectResourceSet
onChange={resourceSet => onChange={resourceSet =>
editVm(vm, { editVm(vm, {
@ -650,17 +615,39 @@ export default connectStore(() => {
} }
value={vm.resourceSet} value={vm.resourceSet}
/> />
) : vm.resourceSet !== undefined ? ( {vm.resourceSet !== undefined && (
<ResourceSetItem id={vm.resourceSet} /> <span className='input-group-btn'>
) : ( <ActionButton
_('resourceSetNone') btnStyle='primary'
)} handler={shareVmProxy}
</td> handlerParam={vm}
</tr> icon='vm-share'
</tbody> style={SHARE_BUTTON_STYLE}
</table> tooltip={_('vmShareButton')}
</Col> />
</Row> </span>
</Container> )}
) </div>
) ) : vm.resourceSet !== undefined ? (
<span>
<ResourceSetItem id={vm.resourceSet} />{' '}
<ActionButton
btnStyle='primary'
handler={shareVmProxy}
handlerParam={vm}
icon='vm-share'
size='small'
tooltip={_('vmShareButton')}
/>
</span>
) : (
_('resourceSetNone')
)}
</td>
</tr>
</tbody>
</table>
</Col>
</Row>
</Container>
))