diff --git a/scripts/start.js b/scripts/start.js index 94b5d85957..0ee0419297 100644 --- a/scripts/start.js +++ b/scripts/start.js @@ -8,8 +8,6 @@ var webpack = require('webpack'); var WebpackDevServer = require('webpack-dev-server'); var historyApiFallback = require('connect-history-api-fallback'); var httpProxyMiddleware = require('http-proxy-middleware'); -var http = require('http'); -var httpProxy = require('http-proxy'); var execSync = require('child_process').execSync; var opn = require('opn'); var detect = require('detect-port'); diff --git a/src/components/Pages/index.js b/src/components/Pages/index.js index d02f771eb6..6c186cf5f4 100644 --- a/src/components/Pages/index.js +++ b/src/components/Pages/index.js @@ -155,7 +155,7 @@ class VmConsolePage extends React.Component { render () { const { vms, match } = this.props if (match.params.id && vms.getIn(['vms', match.params.id])) { - return + return } return null } diff --git a/src/components/Toolbar/index.js b/src/components/Toolbar/index.js index c0e2befef5..607ba49682 100644 --- a/src/components/Toolbar/index.js +++ b/src/components/Toolbar/index.js @@ -53,12 +53,12 @@ const VmConsoleToolbar = ({ match, vms, consoles }) => {
diff --git a/src/components/VmActions/Action.js b/src/components/VmActions/Action.js index 2055064107..c248037c69 100644 --- a/src/components/VmActions/Action.js +++ b/src/components/VmActions/Action.js @@ -114,7 +114,7 @@ const ActionButtonWraper = (props) => { disabled={actionDisabled} > { items.filter(i => i !== null).map(item => { - return + return }) } } diff --git a/src/components/VmActions/index.js b/src/components/VmActions/index.js index b3ffe37a4b..6c8bc96417 100644 --- a/src/components/VmActions/index.js +++ b/src/components/VmActions/index.js @@ -49,14 +49,6 @@ EmptyAction.propTypes = { isOnCard: PropTypes.bool.isRequired, } -function reshapeArray (resArray, current) { - if (current.constructor === Array) { - return resArray.concat(current) - } - resArray.push(current) - return resArray -} - class VmDropdownActions extends React.Component { render () { const { actions, id } = this.props @@ -76,12 +68,11 @@ class VmDropdownActions extends React.Component { onClick={actionsCopy[0].onClick} id={id} > - { actionsCopy.slice(1).map(action => { + { [].concat(...actionsCopy.slice(1).map(action => { return action.items && action.items.length > 0 ? action.items.filter(a => a !== null).map(a => ) : - }).reduce(reshapeArray, []) - } + }))} ) diff --git a/src/components/VmConsole/VmConsoleSelector.js b/src/components/VmConsole/VmConsoleSelector.js index de43a994d9..ab2a489dd0 100644 --- a/src/components/VmConsole/VmConsoleSelector.js +++ b/src/components/VmConsole/VmConsoleSelector.js @@ -13,63 +13,66 @@ import { getRDP } from '_/actions' import { isWindows } from '_/helpers' import style from './style.css' -class VmConsoleSelector extends React.Component { - render () { - const { vmId, vms, consoles, config, consoleId, isConsolePage, onRDP } = this.props - let actions = vms.getIn(['vms', vmId, 'consoles']) - if (actions.size === 0) { - return
- } - const activeConsole = consoleId === 'rdp' - ? msg.rdpConsole() - : consoles.getIn(['vms', vmId, 'consoleStatus']) === DOWNLOAD_CONSOLE - ? msg[actions.find((a) => a.get('id') === consoleId).get('protocol') + 'Console']() - : msg.vncConsoleBrowser() - const vnc = actions.find((a) => a.get('protocol') === 'vnc') - const consoleItems = actions.map(action => - {}} />} - shortTitle={msg[action.get('protocol') + 'Console']()} - icon={} - /> - ).toJS() +const RDP_ID = 'rdp' + +const VmConsoleSelector = ({ vmId, vms, consoles, config, consoleId, isConsolePage, onRDP }) => { + let actions = vms.getIn(['vms', vmId, 'consoles']) + if (actions.size === 0) { + return
+ } + + const vnc = actions.find((a) => a.get('protocol') === 'vnc') - const hasRdp = isWindows(vms.getIn(['vms', vmId, 'os', 'type'])) + const consoleItems = actions.map(action => + {}} />} + shortTitle={msg[action.get('protocol') + 'Console']()} + icon={} + /> + ).toJS() - if (hasRdp) { - const domain = config.get('domain') - const username = config.getIn([ 'user', 'name' ]) - consoleItems.push( { e.preventDefault(); onRDP({ domain, username }) }} - > - {msg.rdpConsole()} - ) - } + const hasRdp = isWindows(vms.getIn(['vms', vmId, 'os', 'type'])) - if (vnc.size) { - consoleItems.push( - {}} />} - shortTitle={msg.vncConsoleBrowser()} - /> - ) - } - return
- {`${msg.console()}:`} - - { consoleItems } - -
+ if (hasRdp) { + const domain = config.get('domain') + const username = config.getIn([ 'user', 'name' ]) + consoleItems.push( { e.preventDefault(); onRDP({ domain, username }) }} + > + {msg.rdpConsole()} + ) } + + if (vnc.size) { + consoleItems.push( + {}} />} + shortTitle={msg.vncConsoleBrowser()} + /> + ) + } + + const activeConsole = consoleId === RDP_ID + ? msg.rdpConsole() + : consoles.getIn(['vms', vmId, 'consoleStatus']) === DOWNLOAD_CONSOLE + ? msg[actions.find((a) => a.get('id') === consoleId).get('protocol') + 'Console']() + : msg.vncConsoleBrowser() + + return
+ {`${msg.console()}:`} + + { consoleItems } + +
} VmConsoleSelector.propTypes = { diff --git a/src/components/VmConsole/index.js b/src/components/VmConsole/index.js index 53cfe0b16a..e9de3a3114 100644 --- a/src/components/VmConsole/index.js +++ b/src/components/VmConsole/index.js @@ -3,7 +3,7 @@ import { connect } from 'react-redux' import PropTypes from 'prop-types' import style from './style.css' -import VncConsole from './VncConsole' +import VncConsole from '_/react-console' import { setConsoleStatus, getRDP } from '_/actions' import ConsoleConfirmationModal from '../VmActions/ConsoleConfirmationModal' import { INIT_CONSOLE, DOWNLOAD_CONSOLE, DISCONNECTED_CONSOLE } from '_/constants' @@ -61,19 +61,31 @@ class VmConsole extends React.Component { render () { const { vmId, config, consoleId, vms, onDisconnected } = this.props const websocket = config.get('websocket') + const vmConsole = this.props.consoles.getIn(['vms', vmId]) if (consoleId === RDP_ID) { - return + return } const currentConsole = vms.getIn(['vms', vmId, 'consoles']).find(c => c.get('id') === consoleId) if (this.state.isFirstRun) { return
- this.setState({ isFirstRun: false })} show /> + this.setState({ isFirstRun: false })} + isConsolePage + isNoVNC + show + />
} - const proxyTicket = this.props.consoles.getIn(['vms', vmId, 'proxyTicket']) - const ticket = this.props.consoles.getIn(['vms', vmId, 'ticket']) - switch (this.props.consoles.getIn(['vms', vmId, 'consoleStatus'])) { + const proxyTicket = vmConsole && vmConsole.get('proxyTicket') + const ticket = vmConsole && vmConsole.get('ticket') + switch (vmConsole && vmConsole.get('consoleStatus')) { case INIT_CONSOLE: if (ticket !== undefined && websocket !== null) { return } + textDisconnect={msg.disconnect()} + textSendShortcut={msg.sendShortcutKey()} + textCtrlAltDel={msg.sendCtrlAltDel()} credentials={{ password: ticket.value }} path={proxyTicket} host={websocket.get('host')} port={websocket.get('port')} - portalToolbarTo='vm-console-toolbar-sendkeys' + toolbarContainer='vm-console-toolbar-sendkeys' onDisconnected={onDisconnected} /> } - return null + break case DOWNLOAD_CONSOLE: return case DISCONNECTED_CONSOLE: @@ -100,7 +115,9 @@ class VmConsole extends React.Component { secondaryComponent={} /> } - return null + return
+ +
} } diff --git a/src/components/VmConsole/style.css b/src/components/VmConsole/style.css index a240729c88..16a660be9e 100644 --- a/src/components/VmConsole/style.css +++ b/src/components/VmConsole/style.css @@ -72,26 +72,3 @@ font-size: 15px; margin-top: 20px; } - -.loaderBox { - width: 100%; - text-align: center; - align-content: center; - margin-top: 60px; -} - -.loader { - border: 6px solid #e3e3e3; /* Light grey */ - border-top: 6px solid #292e34; /* Blue */ - border-radius: 50%; - width: 30px; - height: 30px; - animation: spin 2s linear infinite; - margin-left: auto; - margin-right: auto; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} diff --git a/src/components/VmDetails/cards/DetailsCard/style.css b/src/components/VmDetails/cards/DetailsCard/style.css index 4fcab143a8..65a359df43 100644 --- a/src/components/VmDetails/cards/DetailsCard/style.css +++ b/src/components/VmDetails/cards/DetailsCard/style.css @@ -24,26 +24,6 @@ padding-right: 15px; } -/* - * For the console field - */ -.console-list-active { - color: black; -} - -.console-list-inactive { - color: #888888; -} - -.console-link { - padding-right: 5px; -} - -.console-link + .console-link { - padding-left: 5px; - border-left: 1px solid rgba(0, 0, 0, 0.2); -} - /* * For cloud-init and boot-menu on/off icons */ diff --git a/src/components/VmsList/Vms.js b/src/components/VmsList/Vms.js index d7d7faadb4..2eb8571b23 100644 --- a/src/components/VmsList/Vms.js +++ b/src/components/VmsList/Vms.js @@ -9,6 +9,7 @@ import Pool from './Pool' import ScrollPositionHistory from '../ScrollPositionHistory' import { getByPage } from '_/actions' import InfiniteScroll from 'react-infinite-scroller' +import Loader, { SIZES } from '../Loader' /** * Use Patternfly 'Single Select Card View' pattern to show every VM and Pool @@ -47,7 +48,7 @@ class Vms extends React.Component {
} + loader={} useWindow={false} > diff --git a/src/components/VmsList/style.css b/src/components/VmsList/style.css index 60e934644a..7fc9f83db3 100644 --- a/src/components/VmsList/style.css +++ b/src/components/VmsList/style.css @@ -46,28 +46,6 @@ color: black; } -.loaderBox { - width: 100%; - text-align: center; - align-content: center; -} - -.loader { - border: 12px solid #f3f3f3; /* Light grey */ - border-top: 12px solid #292e34; /* Blue */ - border-radius: 50%; - width: 100px; - height: 100px; - animation: spin 2s linear infinite; - margin-left: auto; - margin-right: auto; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - .card-icon { text-align: center; height: 134px; diff --git a/src/intl/messages.js b/src/intl/messages.js index 2f773265a0..9f3428db7a 100644 --- a/src/intl/messages.js +++ b/src/intl/messages.js @@ -91,6 +91,7 @@ export const messages: { [messageId: string]: MessageType } = { delete: 'Delete', description: 'Description', details: 'Details', + disconnect: { message: 'Disconnect', description: 'Text for disconnect button in noVNC console' }, disconectedConsole: 'Disconnected from Console', disconectedConsoleInfo: 'The console has been diconnected. Press the \'Connect\' button to reconnect the console.', diskActionCreateNew: 'Create Disk', @@ -404,6 +405,8 @@ export const messages: { [messageId: string]: MessageType } = { secondDevice: 'Second Device', secondDeviceTooltip: 'Second device in order.', secondsShort: 's', + sendShortcutKey: 'Send Key', + sendCtrlAltDel: 'Ctrl+Alt+Del', shutdown: 'Shutdown', shutdownVm: 'Shutdown the VM', shutdownVmQuestion: 'Are you sure you want to Shutdown the VM?', diff --git a/src/components/VmConsole/VncConsole/VncActions.js b/src/react-console/VncActions.js similarity index 84% rename from src/components/VmConsole/VncConsole/VncActions.js rename to src/react-console/VncActions.js index 88d97c7fce..be340e4f5d 100644 --- a/src/components/VmConsole/VncConsole/VncActions.js +++ b/src/react-console/VncActions.js @@ -6,7 +6,7 @@ import { MenuItem, Button, DropdownButton, noop } from 'patternfly-react' const VncActions = ({ textSendShortcut, textCtrlAltDel, - portalToolbarTo, + toolbarContainer, textDisconnect, onCtrlAltDel, onDisconnect, @@ -24,13 +24,13 @@ const VncActions = ({ {textDisconnect}
- if (!portalToolbarTo) { + if (!toolbarContainer) { return toolbar } - return document.getElementById(portalToolbarTo) && + return document.getElementById(toolbarContainer) && ReactDOM.createPortal( toolbar, - document.getElementById(portalToolbarTo) + document.getElementById(toolbarContainer) ) } @@ -41,7 +41,7 @@ VncActions.propTypes = { textCtrlAltDel: PropTypes.string, textSendShortcut: PropTypes.string, textDisconnect: PropTypes.string, - portalToolbarTo: PropTypes.string, + toolbarContainer: PropTypes.string, } VncActions.defaultProps = { @@ -51,7 +51,7 @@ VncActions.defaultProps = { textCtrlAltDel: 'Ctrl+Alt+Del', textSendShortcut: 'Send Key', textDisconnect: 'Disconnect', - portalToolbarTo: '', + toolbarContainer: '', } export default VncActions diff --git a/src/components/VmConsole/VncConsole/constants.js b/src/react-console/constants.js similarity index 100% rename from src/components/VmConsole/VncConsole/constants.js rename to src/react-console/constants.js diff --git a/src/components/VmConsole/VncConsole/index.js b/src/react-console/index.js similarity index 94% rename from src/components/VmConsole/VncConsole/index.js rename to src/react-console/index.js index e728580545..667f446b7d 100644 --- a/src/components/VmConsole/VncConsole/index.js +++ b/src/react-console/index.js @@ -118,7 +118,8 @@ class VncConsole extends React.Component { textConnecting, textSendShortcut, textCtrlAltDel, - portalToolbarTo, + textDisconnect, + toolbarContainer, } = this.props let status = null @@ -127,10 +128,11 @@ class VncConsole extends React.Component { case CONNECTED: rightContent = ( ) @@ -152,7 +154,7 @@ class VncConsole extends React.Component {
{this.props.children} { - !portalToolbarTo && + !toolbarContainer && {rightContent} @@ -162,7 +164,7 @@ class VncConsole extends React.Component { } { - portalToolbarTo && + toolbarContainer && {rightContent} {status} @@ -190,7 +192,7 @@ VncConsole.propTypes = { credentials: PropTypes.object /** { username: '', password: '', target: ''} */, repeaterID: PropTypes.string, vncLogging: PropTypes.string /** log-level for noVNC */, - portalToolbarTo: PropTypes.string, + toolbarContainer: PropTypes.string, topClassName: PropTypes.string /** Enable customization */, @@ -200,6 +202,7 @@ VncConsole.propTypes = { textConnecting: PropTypes.oneOfType([PropTypes.string, PropTypes.node]) /** For localization */, textDisconnected: PropTypes.string, + textDisconnect: PropTypes.string, textSendShortcut: PropTypes.string, textCtrlAltDel: PropTypes.string, } @@ -216,7 +219,7 @@ VncConsole.defaultProps = { credentials: undefined, repeaterID: '', vncLogging: 'warn', - portalToolbarTo: '', + toolbarContainer: '', topClassName: '', @@ -226,6 +229,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/src/reducers/consoles.js b/src/reducers/consoles.js index feba69a44c..1cf0f83950 100644 --- a/src/reducers/consoles.js +++ b/src/reducers/consoles.js @@ -19,9 +19,9 @@ const initialState = Immutable.fromJS({ vms: {}, modals: {} }) const consoles = actionReducer(initialState, { [SET_CONSOLE_TICKETS] (state, { payload: { vmId, proxyTicket, ticket } }) { - const tmpState = state.setIn(['vms', vmId, 'proxyTicket'], proxyTicket) - return tmpState + return state .setIn(['vms', vmId, 'ticket'], ticket) + .setIn(['vms', vmId, 'proxyTicket'], proxyTicket) }, [SET_ACTIVE_CONSOLE] (state, { payload: { vmId, consoleId } }) { return state.setIn(['vms', vmId, 'id'], consoleId) diff --git a/src/routes.js b/src/routes.js index ad85d961eb..ea5f55e169 100644 --- a/src/routes.js +++ b/src/routes.js @@ -50,11 +50,11 @@ export default function getRoutes (vms) { type: DETAIL_PAGE_TYPE, routes: [ { - path: '/vm/:id/console/:console_id', - title: (match) => match.params.console_id, + path: '/vm/:id/console/:console', + title: (match) => msg.console(), component: VmConsolePage, closeable: true, - toolbars: [(match) => ()], + toolbars: [(match) => ()], isToolbarFullWidth: true, type: CONSOLE_PAGE_TYPE, },