diff --git a/packages/patternfly-3/react-console/src/VncConsole/VncActions.js b/packages/patternfly-3/react-console/src/VncConsole/VncActions.js index f036c2eff5b..787aaf28227 100644 --- a/packages/patternfly-3/react-console/src/VncConsole/VncActions.js +++ b/packages/patternfly-3/react-console/src/VncConsole/VncActions.js @@ -1,30 +1,59 @@ import React from 'react'; +import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import { MenuItem, Button, helpers } from 'patternfly-react'; const { Dropdown } = Button; const { noop } = helpers; -const VncActions = ({ textSendShortcut, textCtrlAltDel, onCtrlAltDel }) => ( - - - {textCtrlAltDel} - - -); +const VncActions = ({ + textSendShortcut, + textCtrlAltDel, + textDisconnect, + onCtrlAltDel, + onDisconnect, + insertToolbarTo +}) => { + const toolbar = ( +
+ + + {textCtrlAltDel} + + + +
+ ); + + if (!insertToolbarTo) { + return toolbar; + } + return ( + document.getElementById(insertToolbarTo) && ReactDOM.createPortal(toolbar, document.getElementById(insertToolbarTo)) + ); +}; VncActions.propTypes = { + onDisconnect: PropTypes.func.isRequired, onCtrlAltDel: PropTypes.func, textCtrlAltDel: PropTypes.string, - textSendShortcut: PropTypes.string + textSendShortcut: PropTypes.string, + textDisconnect: PropTypes.string, + + insertToolbarTo: PropTypes.string // id of element where VncAction should be inserted }; VncActions.defaultProps = { onCtrlAltDel: noop, textCtrlAltDel: 'Ctrl+Alt+Del', - textSendShortcut: 'Send Key' + textSendShortcut: 'Send Key', + textDisconnect: 'Disconnect', + + insertToolbarTo: '' }; export default VncActions; diff --git a/packages/patternfly-3/react-console/src/VncConsole/VncActions.test.js b/packages/patternfly-3/react-console/src/VncConsole/VncActions.test.js index 651514fb592..85f2fb2f2a3 100644 --- a/packages/patternfly-3/react-console/src/VncConsole/VncActions.test.js +++ b/packages/patternfly-3/react-console/src/VncConsole/VncActions.test.js @@ -4,20 +4,30 @@ import { shallow, mount } from 'enzyme'; import VncActions from './VncActions'; test('placeholder render test', () => { - const view = shallow(); + const view = shallow(); expect(view).toMatchSnapshot(); }); test('VncActions renders correctly component hierarchy', () => { const view = shallow( - + ); expect(view).toMatchSnapshot(); }); test('VncActions renders correctly html', () => { const view = shallow( - + ); expect(view.html()).toMatchSnapshot(); }); @@ -30,6 +40,7 @@ test('VncActions calls ctrl+alt+del action', () => { textSendShortcut="My Send Shortcut description" textCtrlAltDel="CtrlAltDel" onCtrlAltDel={onCtrlAltDel} + onDisconnect={jest.fn()} /> ); diff --git a/packages/patternfly-3/react-console/src/VncConsole/VncConsole.js b/packages/patternfly-3/react-console/src/VncConsole/VncConsole.js index c36edd438f4..f4c0d9ff083 100644 --- a/packages/patternfly-3/react-console/src/VncConsole/VncConsole.js +++ b/packages/patternfly-3/react-console/src/VncConsole/VncConsole.js @@ -31,6 +31,7 @@ class VncConsole extends React.Component { path, encrypt, resizeSession, + scaleViewport, viewOnly, shared, credentials, @@ -53,7 +54,7 @@ class VncConsole extends React.Component { this.rfb = new RFB(this.novncElem, url, options); this.addEventListeners(); this.rfb.viewOnly = viewOnly; - this.rfb.scaleViewport = false; // if the remote session is smaller than HTML container, the view will be centered + this.rfb.scaleViewport = scaleViewport; this.rfb.resizeSession = resizeSession; } catch (e) { onInitFailed && onInitFailed(e); @@ -62,17 +63,17 @@ class VncConsole extends React.Component { } componentWillUnmount() { - this.removeEventListeners(); this.disconnect(); + this.removeEventListeners(); + this.rfb = undefined; } - disconnect() { + disconnect = () => { if (!this.rfb) { return; } this.rfb.disconnect(); - this.rfb = undefined; - } + }; onConnected = () => { this.setState({ status: CONNECTED }); @@ -95,11 +96,11 @@ class VncConsole extends React.Component { this.props.onSecurityFailure(e); }; - removeEventListeners() { + removeEventListeners = () => { this.rfb.removeEventListener('connect', this.onConnected); this.rfb.removeEventListener('disconnect', this.onDisconnected); this.rfb.removeEventListener('securityfailure', this.onSecurityFailure); - } + }; setNovncElem = e => { this.novncElem = e; @@ -113,7 +114,14 @@ class VncConsole extends React.Component { }; render() { - const { textDisconnected, textConnecting, textSendShortcut, textCtrlAltDel } = this.props; + const { + textDisconnected, + textConnecting, + textSendShortcut, + textCtrlAltDel, + textDisconnect, + portalToolbarTo + } = this.props; let status = null; let rightContent = null; @@ -121,9 +129,12 @@ class VncConsole extends React.Component { case CONNECTED: rightContent = ( ); break; @@ -143,11 +154,21 @@ class VncConsole extends React.Component { return (
{this.props.children} - {rightContent} - - {status} - {this.novncStaticComponent} - + {portalToolbarTo ? ( + + {rightContent} + {status} + {this.novncStaticComponent} + + ) : ( + + {rightContent} + + {status} + {this.novncStaticComponent} + + + )}
); } @@ -163,11 +184,13 @@ VncConsole.propTypes = { path: PropTypes.string /** host:port/path */, encrypt: PropTypes.bool /** For all following, see: https://github.com/novnc/noVNC/blob/master/docs/API.md */, resizeSession: PropTypes.bool /** Change remote session size according to local HTML container */, + scaleViewport: PropTypes.bool /** Scale session size according to parent HTML container */, viewOnly: PropTypes.bool, shared: PropTypes.bool, credentials: PropTypes.object /** { username: '', password: '', target: ''} */, repeaterID: PropTypes.string, vncLogging: PropTypes.string /** log-level for noVNC */, + portalToolbarTo: PropTypes.string, topClassName: PropTypes.string /** Enable customization */, @@ -175,8 +198,12 @@ VncConsole.propTypes = { onInitFailed: PropTypes.func /** Initialization of RFB failed */, onSecurityFailure: PropTypes.func /** Handshake failed */, - textConnecting: PropTypes.string /** For localization */, + textConnecting: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.node + ]) /** For localization and better integration */, textDisconnected: PropTypes.string, + textDisconnect: PropTypes.string, textSendShortcut: PropTypes.string, textCtrlAltDel: PropTypes.string }; @@ -188,11 +215,13 @@ VncConsole.defaultProps = { path: '', encrypt: false, resizeSession: true, + scaleViewport: false, viewOnly: false, shared: false, credentials: undefined, repeaterID: '', vncLogging: 'warn', + portalToolbarTo: '', topClassName: '', @@ -202,6 +231,7 @@ VncConsole.defaultProps = { textConnecting: 'Connecting', textDisconnected: 'Disconnected', + textDisconnect: 'Disconnect', textSendShortcut: undefined /** Default value defined in VncActions */, textCtrlAltDel: undefined /** Default value defined in VncActions */ }; diff --git a/packages/patternfly-3/react-console/src/VncConsole/__snapshots__/VncActions.test.js.snap b/packages/patternfly-3/react-console/src/VncConsole/__snapshots__/VncActions.test.js.snap index d81d4711dba..9bd8ca54944 100644 --- a/packages/patternfly-3/react-console/src/VncConsole/__snapshots__/VncActions.test.js.snap +++ b/packages/patternfly-3/react-console/src/VncConsole/__snapshots__/VncActions.test.js.snap @@ -1,43 +1,67 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`VncActions renders correctly component hierarchy 1`] = ` - - + + + foobar + + + + `; -exports[`VncActions renders correctly html 1`] = `"
"`; +exports[`VncActions renders correctly html 1`] = `"
"`; exports[`placeholder render test 1`] = ` - - + + + Ctrl+Alt+Del + + + + `;