Skip to content

Commit

Permalink
feat(ConsoleSelector): introduce ConsoleSelector component (#606)
Browse files Browse the repository at this point in the history
* feat(ConsoleSelector): introduce ConsoleSelector component

affects: @patternfly/react-console

The component unifies composition of various console components
for server/virtual machine remote access (recently via serial
console or VNC).

* update paddings

* fix(VncConsole): sync .scss and .less and minor fixes

Fixes (as top-level Toolbar is gone):
- unit tests
- padding of VncConsole actions

* feat(AccessConsoles): Rename ConsoleSelector to AccessConsoles

Based on design-review.
Former `ConsoleSelector` component has not been released yet.
  • Loading branch information
mareklibra authored and priley86 committed Oct 26, 2018
1 parent f1d591c commit d876589
Show file tree
Hide file tree
Showing 17 changed files with 1,900 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.console-selector-pf {
margin-bottom: 0px;
}

.console-selector-pf-disconnect-switch {
margin-left: 15px;
}
1 change: 1 addition & 0 deletions packages/patternfly-3/react-console/less/console.less
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
*/
@import 'serial-console';
@import 'vnc-console';
@import 'console-selector';
24 changes: 13 additions & 11 deletions packages/patternfly-3/react-console/less/vnc-console.less
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
.vnc-console {
padding-right: 0px;
padding-left: 0px;

.toolbar-pf-results {
padding: 15px 0;
border-top: none;
margin-top: 0px;
}
.vnc-console-connecting {
background-color: @color-pf-green;
}

.vnc-console-disconnected {
background-color: @color-pf-red;
}
.toolbar-pf {
border-bottom: none;
}
.toolbar-pf-results {
padding-top: 10px;
}
.toolbar-pf-action-right .dropdown-menu {
min-width: 102px; /* avoid overflow if DropdownButton is used under Toolbar.RightContent */

.toolbar-pf-action-right {
padding-bottom: 5px;

.dropdown-menu {
min-width: 102px;
}
}
}
12 changes: 9 additions & 3 deletions packages/patternfly-3/react-console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,19 @@
"dependencies": {
"@novnc/novnc": "^1.0.0",
"classnames": "^2.2.5",
"patternfly": "^3.52.1",
"patternfly-react": "^2.21.5",
"xterm": "^3.3.0"
},
"devDependencies": {
"patternfly": "^3.52.1",
"patternfly-react": "^2.21.5"
},
"peerDependencies": {
"prop-types": "^15.6.1",
"react": "^16.3.2",
"react-dom": "^16.3.2"
"react-dom": "^16.3.2",
"patternfly": "^3.52.1",
"patternfly-react": "^2.21.5",
"react-bootstrap": "^0.32.1"
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.console-selector-pf {
margin-bottom: 0;
}

.console-selector-pf-disconnect-switch {
margin-left: 15px;
}
13 changes: 11 additions & 2 deletions packages/patternfly-3/react-console/sass/_vnc-console.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
.vnc-console {
.toolbar-pf-results {
padding: 15px 0;
border-top: none;
margin-top: 0px;
}
.vnc-console-connecting {
background-color: $color-pf-green;
}
Expand All @@ -7,7 +12,11 @@
background-color: $color-pf-red;
}

.toolbar-pf-action-right .dropdown-menu {
min-width: 102px;
.toolbar-pf-action-right {
padding-bottom: 5px;

.dropdown-menu {
min-width: 102px;
}
}
}
1 change: 1 addition & 0 deletions packages/patternfly-3/react-console/sass/console.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// Console StyleSheets
@import "serial-console";
@import "vnc-console";
@import "console-selector";

/**
Styling shared by both VncConsole and SerialConsole.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import React from 'react';
import PropTypes from 'prop-types';

import { Grid, Row, Col, Form, FormGroup, Dropdown, MenuItem, Checkbox } from 'patternfly-react';

import { NONE_TYPE, SERIAL_CONSOLE_TYPE, VNC_CONSOLE_TYPE } from '../common/constants';

class AccessConsoles extends React.Component {
state = {
type: NONE_TYPE,
disconnectByChange: this.props.disconnectByChange,
keptConnection: {} // no connection exists when mounted
};

onTypeChange(type) {
this.setState(prevState => {
const keptConnection = prevState.disconnectByChange
? { [type]: true }
: { ...prevState.keptConnection, [type]: true };

return {
type,
keptConnection
};
});
}

onChangeDisconnectBySwitchClick(target) {
this.setState(prevState => ({
disconnectByChange: target.checked,
keptConnection: target.checked ? { [prevState.type]: true } : prevState.keptConnection
}));
}

getSelectedConsole() {
return this.getConsoleForType(this.state.type);
}

getConsoleForType(type) {
if (!this.props.children) {
return null;
}

const getChildTypeName = child => (child.props.type ? child.props.type : (child.type && child.type.name) || null);
const isChildOfType = child => getChildTypeName(child) === type;

// To keep connection, render all consoles but hide those unused
return React.Children.map(
this.props.children,
child =>
this.state.keptConnection[getChildTypeName(child)] ? (
<div key={getChildTypeName(child)} hidden={!isChildOfType(child)}>
{child}
</div>
) : null
);
}

render() {
const items = {
[NONE_TYPE]: this.props.textSelectConsoleType,
[SERIAL_CONSOLE_TYPE]: this.props.textSerialConsole,
[VNC_CONSOLE_TYPE]: this.props.textVncConsole
};

return (
<Grid fluid>
<Form horizontal>
<FormGroup controlId="console-type" className="console-selector-pf">
<Col>
<Dropdown id="console-type-selector" disabled={!this.props.children}>
<Dropdown.Toggle>
{this.props.children ? items[this.state.type] : this.props.textEmptyConsoleList}
</Dropdown.Toggle>
<Dropdown.Menu>
{this.getConsoleForType(SERIAL_CONSOLE_TYPE) && (
<MenuItem eventKey="1" onClick={() => this.onTypeChange(SERIAL_CONSOLE_TYPE)}>
{items[SERIAL_CONSOLE_TYPE]}
</MenuItem>
)}
{this.getConsoleForType(VNC_CONSOLE_TYPE) && (
<MenuItem eventKey="2" onClick={() => this.onTypeChange(VNC_CONSOLE_TYPE)}>
{items[VNC_CONSOLE_TYPE]}
</MenuItem>
)}
</Dropdown.Menu>
</Dropdown>
{this.state.type !== NONE_TYPE && (
<Checkbox
className="console-selector-pf-disconnect-switch"
inline
defaultChecked={this.props.disconnectByChange}
onChange={e => this.onChangeDisconnectBySwitchClick(e.target)}
>
{this.props.textDisconnectByChange}
</Checkbox>
)}
</Col>
</FormGroup>
</Form>
<Row>
<Col>{this.getSelectedConsole()}</Col>
</Row>
</Grid>
);
}
}

const validChildrenTypes = [SERIAL_CONSOLE_TYPE, VNC_CONSOLE_TYPE];
const childElementValidator = propValue => {
if (propValue) {
const children = Array.isArray(propValue) ? propValue : [propValue];
if (
!children.every(
child =>
(child.type && validChildrenTypes.indexOf(child.type.name) >= 0) ||
(child.props && validChildrenTypes.indexOf(child.props.type) >= 0)
)
) {
return new Error('AccessConsoles child validation failed');
}
}
return true;
};

AccessConsoles.propTypes = {
/**
* Child element can be either
* - <SerialConsole> or <VncConsole>
* - or has a property "type" of value either SERIAL_CONSOLE_TYPE or VNC_CONSOLE_TYPE (useful when wrapping (composing) basic console components
*/
children: PropTypes.oneOfType([PropTypes.objectOf(childElementValidator), PropTypes.arrayOf(childElementValidator)]),

textSelectConsoleType: PropTypes.string /** Internationalization */,
textSerialConsole: PropTypes.string /** Internationalization */,
textVncConsole: PropTypes.string /** Internationalization */,
textDisconnectByChange: PropTypes.string /** Internationalization */,
textEmptyConsoleList: PropTypes.string /** Internationalization */,

disconnectByChange:
PropTypes.bool /** Initial value of "Disconnect before switching" checkbox, "false" to disconnect when console type changed */
};

AccessConsoles.defaultProps = {
children: null,

textSelectConsoleType: 'Select Console Type',
textSerialConsole: 'Serial Console',
textVncConsole: 'VNC Console',
textDisconnectByChange: 'Disconnect before switching',
textEmptyConsoleList: 'No console available',

disconnectByChange: true /** By default, console is unmounted (disconnected) when switching to other type */
};

export default AccessConsoles;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { withInfo } from '@storybook/addon-info';
import { inlineTemplate } from 'storybook/decorators/storyTemplates';
import { name } from '../../package.json';
import { storybookPackageName } from 'storybook/constants/siteConstants';

import { noop } from 'patternfly-react';
import { AccessConsoles, VncConsole } from '../index';
import { SerialConsoleConnector } from '../SerialConsole/SerialConsole.stories'; // contains mock backend
import { DISCONNECTED } from '../SerialConsole/constants';
import { SERIAL_CONSOLE_TYPE } from '../common/constants';

const stories = storiesOf(`${storybookPackageName(name)}/AccessConsoles`, module);

stories.add(
'AccessConsoles',
withInfo()(() => {
const story = (
<AccessConsoles>
<SerialConsoleConnector onConnect={noop} onDisconnect={noop} status={DISCONNECTED} type={SERIAL_CONSOLE_TYPE} />
<VncConsole
host="foo.bar.host"
textDisconnected="Disconnected as expected - VncConsole component is not connected to a real backend"
/>
</AccessConsoles>
);
return inlineTemplate({
story,
title: 'AccessConsoles'
});
})
);

stories.add(
'AccessConsoles - empty',
withInfo()(() => {
const story = <AccessConsoles />;
return inlineTemplate({
story,
title: 'AccessConsoles - empty'
});
})
);
Loading

0 comments on commit d876589

Please sign in to comment.