From 19703726193ecb7562821bd9ac6620181db17f29 Mon Sep 17 00:00:00 2001 From: Radoslaw Szwajkowski Date: Jun 14 2022 09:08:01 +0000 Subject: Port VncConsole from TypeScript to plain JS Source: @patternfly/react-console/src/components/VncConsole/VncConsole.tsx Commit: e0240737eb6abb091c3ac83c3de8fb68420d7578 --- diff --git a/src/components/VmConsole/VncConsole.js b/src/components/VmConsole/VncConsole.js new file mode 100644 index 0000000..5829876 --- /dev/null +++ b/src/components/VmConsole/VncConsole.js @@ -0,0 +1,233 @@ +import React, { useRef, useState, useEffect } from 'react' + +import PropTypes from 'prop-types' +import { css } from '@patternfly/react-styles' +import { Button, EmptyState, EmptyStateBody, EmptyStateIcon, Spinner } from '@patternfly/react-core' + +import { initLogging } from '@novnc/novnc/core/util/logging' +import RFB from '@novnc/novnc/core/rfb' + +import { + VncActions, + constants, +} from '@patternfly/react-console' + +import styles from '@patternfly/react-styles/css/components/Consoles/VncConsole' +import '@patternfly/react-styles/css/components/Consoles/VncConsole.css' + +const { CONNECTED, CONNECTING, DISCONNECTED } = constants + +const VncConsole = ({ + children, + host, + port = '80', + path = '', + encrypt = false, + resizeSession = true, + scaleViewport = false, + viewOnly = false, + shared = false, + credentials, + repeaterID = '', + vncLogging = 'warn', + consoleContainerId, + additionalButtons = [], + onDisconnected = () => {}, + onInitFailed, + onSecurityFailure, + textConnect = 'Connect', + textConnecting = 'Connecting', + textDisconnected = 'Click Connect to open the VNC console.', + textDisconnect = 'Disconnect', + textSendShortcut, + textCtrlAltDel, +}) => { + const rfb = useRef() + let novncStaticComponent + let novncElem + + const [status, setStatus] = useState(CONNECTING) + + const addEventListeners = () => { + if (rfb.current) { + rfb.current?.addEventListener('connect', onConnected) + rfb.current?.addEventListener('disconnect', _onDisconnected) + rfb.current?.addEventListener('securityfailure', _onSecurityFailure) + } + } + + const removeEventListeners = () => { + if (rfb.current) { + rfb.current.removeEventListener('connect', onConnected) + rfb.current.removeEventListener('disconnect', _onDisconnected) + rfb.current.removeEventListener('securityfailure', _onSecurityFailure) + } + } + + const connect = () => { + const protocol = encrypt ? 'wss' : 'ws' + const url = `${protocol}://${host}:${port}/${path}` + + const options = { + repeaterID, + shared, + credentials, + } + rfb.current = new RFB(novncElem, url, options) + addEventListeners() + rfb.current.viewOnly = viewOnly + rfb.current.scaleViewport = scaleViewport + rfb.current.resizeSession = resizeSession + } + + useEffect(() => { + initLogging(vncLogging) + try { + connect() + } catch (e) { + onInitFailed && onInitFailed(e) + rfb.current = undefined + } + + return () => { + disconnect() + removeEventListeners() + rfb.current = undefined + } + }, [connect, onInitFailed, removeEventListeners, vncLogging]) + + const disconnect = () => { + if (!rfb.current) { + return + } + rfb.current.disconnect() + } + + const onConnected = () => { + setStatus(CONNECTED) + } + + const _onDisconnected = (e) => { + setStatus(DISCONNECTED) + onDisconnected(e) + } + + const _onSecurityFailure = (e) => { + setStatus(DISCONNECTED) + onSecurityFailure(e) + } + + const onCtrlAltDel = () => { + if (rfb.current) { + rfb?.current?.sendCtrlAltDel() + } + } + + let rightContent + let emptyState + switch (status) { + case CONNECTED: + rightContent = ( + + ) + break + case DISCONNECTED: + emptyState = ( + + {textDisconnected} + + + ) + break + case CONNECTING: + default: + emptyState = ( + + + {textConnecting} + + ) + } + + if (!novncStaticComponent) { + novncStaticComponent =
(novncElem = e)} /> + } + + return ( + <> + {rightContent} +
+ {children} + <> +
+ {emptyState} + {novncStaticComponent} +
+ +
+ + ) +} +VncConsole.displayName = 'VncConsole' + +VncConsole.propTypes = { + /** Children nodes */ + children: PropTypes.any, + + /** FQDN or IP to connect to */ + host: PropTypes.string.isRequired, + /** TCP Port */ + port: PropTypes.string, + /** host:port/path */ + path: PropTypes.string, + encrypt: PropTypes.bool, + /** Is a boolean indicating if a request to resize the remote session should be sent whenever the container changes dimensions */ + resizeSession: PropTypes.bool, + /** Is a boolean indicating if the remote session should be scaled locally so it fits its container */ + scaleViewport: PropTypes.bool, + /** Is a boolean indicating if any events (e.g. key presses or mouse movement) should be prevented from being sent to the server */ + viewOnly: PropTypes.bool, + /** Is a boolean indicating if the remote server should be shared or if any other connected clients should be disconnected */ + shared: PropTypes.bool, + /** An Object specifying the credentials to provide to the server when authenticating + * { username: '' password: '' target: ''} + */ + credentials: PropTypes.object, + /** A DOMString specifying the ID to provide to any VNC repeater encountered */ + repeaterID: PropTypes.string, + /** log-level for noVNC */ + vncLogging: PropTypes.oneOf(['error', 'warn', 'none', 'debug', 'info']), + consoleContainerId: PropTypes.string, + additionalButtons: PropTypes.array, + + /** Callback. VNC server disconnected. */ + onDisconnected: PropTypes.func, + /** Initialization of RFB failed */ + onInitFailed: PropTypes.func, + /** Handshake failed */ + onSecurityFailure: PropTypes.func, + + /* Text content rendered inside the EmptyState in the "Connect' button for when console is disconnnected */ + textConnect: PropTypes.string, + /* Text content rendered inside the EmptyState for when console is connecting */ + textConnecting: PropTypes.string, + /* Text content rendered inside the EmptyState for when console is disconnnected */ + textDisconnected: PropTypes.string, + /** Text content rendered inside the Disconnect button */ + textDisconnect: PropTypes.string, + /** Text content rendered inside the button Send shortcut dropdown toggle */ + textSendShortcut: PropTypes.string, + /** Text content rendered inside the Ctrl-Alt-Delete dropdown entry */ + textCtrlAltDel: PropTypes.string, +} + +export default VncConsole