feat(xo-web/vm/console): direct connection to SSH button (#4415)
This commit is contained in:
parent
ae6cc8eea3
commit
2b0f1b6aab
@ -8,6 +8,7 @@
|
||||
> Users must be able to say: “Nice enhancement, I'm eager to test it”
|
||||
|
||||
- [VM/disks] Don't hide disks that are attached to the same VM twice [#4400](https://github.com/vatesfr/xen-orchestra/issues/4400) (PR [#4414](https://github.com/vatesfr/xen-orchestra/pull/4414))
|
||||
- [VM/console] Add a button to connect to the VM via the local SSH client (PR [#4415](https://github.com/vatesfr/xen-orchestra/pull/4415))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
@ -984,11 +984,18 @@ const messages = {
|
||||
// ----- VM console tab -----
|
||||
copyToClipboardLabel: 'Copy',
|
||||
ctrlAltDelButtonLabel: 'Ctrl+Alt+Del',
|
||||
ctrlAltDelConfirmation: 'Send Ctrl+Alt+Del to VM?',
|
||||
multilineCopyToClipboard: 'Multiline copy',
|
||||
tipLabel: 'Tip:',
|
||||
hideHeaderTooltip: 'Hide info',
|
||||
showHeaderTooltip: 'Show info',
|
||||
sendToClipboard: 'Send to clipboard',
|
||||
sshRootTooltip: 'Connect using external SSH tool as root',
|
||||
sshRootLabel: 'SSH',
|
||||
sshUserTooltip: 'Connect using external SSH tool as user…',
|
||||
sshUserLabel: 'SSH as…',
|
||||
sshUsernameLabel: 'SSH user name',
|
||||
sshNeedClientTools: 'No IP address reported by client tools',
|
||||
|
||||
// ----- VM container tab -----
|
||||
containerName: 'Name',
|
||||
|
@ -3,6 +3,7 @@ import ActionButton from 'action-button'
|
||||
import Button from 'button'
|
||||
import Component from 'base-component'
|
||||
import CopyToClipboard from 'react-copy-to-clipboard'
|
||||
import cookies from 'cookies-js'
|
||||
import debounce from 'lodash/debounce'
|
||||
import getEventValue from 'get-event-value'
|
||||
import Icon from 'icon'
|
||||
@ -13,7 +14,7 @@ import React from 'react'
|
||||
import Tooltip from 'tooltip'
|
||||
import { isVmRunning, resolveUrl } from 'xo'
|
||||
import { Col, Container, Row } from 'grid'
|
||||
import { confirm } from 'modal'
|
||||
import { confirm, form } from 'modal'
|
||||
import {
|
||||
CpuSparkLines,
|
||||
MemorySparkLines,
|
||||
@ -61,7 +62,13 @@ export default class TabConsole extends Component {
|
||||
this._toggleMinimalLayout()
|
||||
}
|
||||
}
|
||||
_sendCtrlAltDel = () => {
|
||||
|
||||
_sendCtrlAltDel = async () => {
|
||||
await confirm({
|
||||
icon: 'vm-keyboard',
|
||||
title: _('ctrlAltDelButtonLabel'),
|
||||
body: _('ctrlAltDelConfirmation'),
|
||||
})
|
||||
this.refs.noVnc.sendCtrlAltDel()
|
||||
}
|
||||
|
||||
@ -91,9 +98,40 @@ export default class TabConsole extends Component {
|
||||
this.setState({ minimalLayout: !this.state.minimalLayout })
|
||||
}
|
||||
|
||||
_openSsh = (username = 'root') => {
|
||||
window.location = `ssh://${encodeURIComponent(username)}@${
|
||||
this.props.vm.addresses['0/ip']
|
||||
}`
|
||||
}
|
||||
|
||||
_openSshMore = async () => {
|
||||
const cookieKey = `${this.props.vm.uuid}/ssh-user-name`
|
||||
const username = await form({
|
||||
defaultValue: cookies.get(cookieKey) || 'root',
|
||||
header: _('sshUsernameLabel'),
|
||||
render: ({ value, onChange }) => (
|
||||
<div>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
})
|
||||
if (username !== (cookies.get(cookieKey) || 'root')) {
|
||||
// seems to be seconds
|
||||
const expires = 31 * 3600 * 24
|
||||
cookies.set(cookieKey, username, { expires })
|
||||
}
|
||||
this._openSsh(username)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { statsOverview, vm } = this.props
|
||||
const { minimalLayout, scale } = this.state
|
||||
const canSsh = vm.addresses && vm.addresses['0/ip']
|
||||
|
||||
if (!isVmRunning(vm)) {
|
||||
return (
|
||||
@ -161,12 +199,42 @@ export default class TabConsole extends Component {
|
||||
</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col mediumSize={2}>
|
||||
<Button onClick={this._sendCtrlAltDel}>
|
||||
<Icon icon='vm-keyboard' /> {_('ctrlAltDelButtonLabel')}
|
||||
</Button>
|
||||
<Col mediumSize={5} largeSize={3}>
|
||||
<div className='btn-group'>
|
||||
<span className='input-group-btn'>
|
||||
<ActionButton
|
||||
handler={this._openSsh}
|
||||
tooltip={
|
||||
canSsh ? _('sshRootTooltip') : _('sshNeedClientTools')
|
||||
}
|
||||
disabled={!canSsh}
|
||||
icon='remote'
|
||||
>
|
||||
{_('sshRootLabel')}
|
||||
</ActionButton>
|
||||
</span>
|
||||
<span className='input-group-btn'>
|
||||
<ActionButton
|
||||
handler={this._openSshMore}
|
||||
tooltip={
|
||||
canSsh ? _('sshUserTooltip') : _('sshNeedClientTools')
|
||||
}
|
||||
disabled={!canSsh}
|
||||
icon='remote'
|
||||
>
|
||||
{_('sshUserLabel')}
|
||||
</ActionButton>
|
||||
</span>
|
||||
<span className='input-group-btn'>
|
||||
<ActionButton
|
||||
handler={this._sendCtrlAltDel}
|
||||
tooltip={_('ctrlAltDelButtonLabel')}
|
||||
icon='vm-keyboard'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col mediumSize={3}>
|
||||
<Col mediumSize={2} className='hidden-lg-down'>
|
||||
<input
|
||||
className='form-control'
|
||||
max={3}
|
||||
|
Loading…
Reference in New Issue
Block a user