Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify terminal is child window of details panel. #1903

Merged
merged 5 commits into from
Oct 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions client/app/scripts/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import Nodes from './nodes';
import GridModeSelector from './grid-mode-selector';
import MetricSelector from './metric-selector';
import NetworkSelector from './networks-selector';
import EmbeddedTerminal from './embedded-terminal';
import { getRouter } from '../utils/router-utils';
import DebugToolbar, { showingDebugToolbar,
toggleDebugToolbar } from './debug-toolbar.js';
Expand Down Expand Up @@ -103,7 +102,7 @@ class App extends React.Component {

render() {
const { gridMode, showingDetails, showingHelp, showingMetricsSelector,
showingNetworkSelector, showingTerminal } = this.props;
showingNetworkSelector } = this.props;
const isIframe = window !== window.top;

return (
Expand All @@ -114,8 +113,6 @@ class App extends React.Component {

{showingDetails && <Details />}

{showingTerminal && <EmbeddedTerminal />}

<div className="header">
<div className="logo">
{!isIframe && <svg width="100%" height="100%" viewBox="0 0 1089 217">
Expand Down
22 changes: 19 additions & 3 deletions client/app/scripts/components/details-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { connect } from 'react-redux';

import NodeDetails from './node-details';
import EmbeddedTerminal from './embedded-terminal';
import { DETAILS_PANEL_WIDTH as WIDTH, DETAILS_PANEL_OFFSET as OFFSET,
DETAILS_PANEL_MARGINS as MARGINS } from '../constants/styles';

Expand All @@ -22,7 +23,7 @@ class DetailsCard extends React.Component {

render() {
let transform;
const origin = this.props.origin;
const { origin, showingTerminal } = this.props;
const panelHeight = window.innerHeight - MARGINS.bottom - MARGINS.top;
if (origin && !this.state.mounted) {
// render small panel near origin, will transition into normal panel after being mounted
Expand All @@ -45,12 +46,27 @@ class DetailsCard extends React.Component {
transform = `translateX(${shiftX}px)`;
}
}
const style = {
transform,
left: showingTerminal ? MARGINS.right : null,
width: showingTerminal ? null : WIDTH
};
return (
<div className="details-wrapper" style={{transform}}>
<div className="details-wrapper" style={style}>
{showingTerminal && <EmbeddedTerminal />}
<NodeDetails nodeId={this.props.id} key={this.props.id} {...this.props} />
</div>
);
}
}

export default connect()(DetailsCard);

function mapStateToProps(state, props) {
const pipe = state.get('controlPipes').last();
return {
showingTerminal: pipe && pipe.get('nodeId') === props.id,
};
}


export default connect(mapStateToProps)(DetailsCard);
58 changes: 44 additions & 14 deletions client/app/scripts/components/embedded-terminal.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,63 @@
import React from 'react';
import { connect } from 'react-redux';

import { getNodeColor, getNodeColorDark } from '../utils/color-utils';
import { brightenColor, getNodeColorDark } from '../utils/color-utils';
import { DETAILS_PANEL_WIDTH, DETAILS_PANEL_MARGINS } from '../constants/styles';
import Terminal from './terminal';
import { DETAILS_PANEL_WIDTH, DETAILS_PANEL_MARGINS,
DETAILS_PANEL_OFFSET } from '../constants/styles';

class EmeddedTerminal extends React.Component {

constructor(props, context) {
super(props, context);
this.state = {
mounted: null,
animated: null,
};

this.handleTransitionEnd = this.handleTransitionEnd.bind(this);
}

componentDidMount() {
setTimeout(() => {
this.setState({mounted: true});
});
}

getTransform() {
const dx = this.state.mounted ? 0 :
window.innerWidth - DETAILS_PANEL_WIDTH - DETAILS_PANEL_MARGINS.right;
return `translateX(${dx}px)`;
}

handleTransitionEnd() {
this.setState({ animated: true });
}

render() {
const { pipe, details } = this.props;
const nodeId = pipe.get('nodeId');
const node = details.get(nodeId);
const d = node && node.details;
const titleBarColor = d && getNodeColorDark(d.rank, d.label);
const statusBarColor = d && getNodeColor(d.rank, d.label);
const titleBarColor = d && getNodeColorDark(d.rank, d.label, d.pseudo);
const statusBarColor = d && brightenColor(titleBarColor);
const title = d && d.label;

const style = {
right: DETAILS_PANEL_MARGINS.right + DETAILS_PANEL_WIDTH + 10 +
(details.size * DETAILS_PANEL_OFFSET)
};

// React unmount/remounts when key changes, this is important for cleaning up
// the term.js and creating a new one for the new pipe.
return (
<div className="terminal-embedded" style={style}>
<Terminal key={pipe.get('id')} pipe={pipe} titleBarColor={titleBarColor}
statusBarColor={statusBarColor} containerMargin={style.right}
title={title} />
<div className="terminal-embedded">
<div
onTransitionEnd={this.handleTransitionEnd}
className="terminal-animation-wrapper"
style={{transform: this.getTransform()}} >
<Terminal
key={pipe.get('id')}
pipe={pipe}
connect={this.state.animated}
titleBarColor={titleBarColor}
statusBarColor={statusBarColor}
title={title} />
</div>
</div>
);
}
Expand Down
55 changes: 41 additions & 14 deletions client/app/scripts/components/terminal.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,11 @@ class Terminal extends React.Component {
pixelPerCol: 0,
pixelPerRow: 0
};

this.handleCloseClick = this.handleCloseClick.bind(this);
this.handlePopoutTerminal = this.handlePopoutTerminal.bind(this);
this.handleResize = this.handleResize.bind(this);
this.focusTerminal = this.focusTerminal.bind(this);
}

createWebsocket(term) {
Expand All @@ -106,7 +108,13 @@ class Terminal extends React.Component {
};

socket.onclose = () => {
log('socket closed');
//
// componentWillUnmount has called close and tidied up! don't try and do it again here
// (setState etc), its too late.
//
if (!this.socket) {
return;
}
this.socket = null;
const wereConnected = this.state.connected;
this.setState({connected: false});
Expand All @@ -133,16 +141,26 @@ class Terminal extends React.Component {
this.socket = socket;
}

componentWillReceiveProps(nextProps) {
if (this.props.connect !== nextProps.connect && nextProps.connect) {
this.mountTerminal();
}
}

componentDidMount() {
const component = this;
if (this.props.connect) {
this.mountTerminal();
}
}

mountTerminal() {
this.term = new Term({
cols: this.state.cols,
rows: this.state.rows,
convertEol: !this.props.raw
});

const innerNode = ReactDOM.findDOMNode(component.inner);
const innerNode = ReactDOM.findDOMNode(this.inner);
this.term.open(innerNode);
this.term.on('data', (data) => {
if (this.socket) {
Expand Down Expand Up @@ -180,21 +198,14 @@ class Terminal extends React.Component {
this.term.destroy();
this.term = null;
}

if (this.socket) {
log('close socket');
this.socket.close();
this.socket = null;
}
}

componentWillReceiveProps(nextProps) {
const containerMarginChanged = nextProps.containerMargin !== this.props.containerMargin;
log(nextProps.containerMargin);
if (containerMarginChanged) {
this.handleResize();
}
}

componentDidUpdate(prevProps, prevState) {
const sizeChanged = (
prevState.cols !== this.state.cols ||
Expand All @@ -213,6 +224,12 @@ class Terminal extends React.Component {
this.props.dispatch(clickCloseTerminal(this.getPipeId(), true));
}

focusTerminal() {
if (this.term) {
this.term.focus();
}
}

handlePopoutTerminal(ev) {
ev.preventDefault();
const paramString = JSON.stringify(this.props);
Expand Down Expand Up @@ -247,8 +264,9 @@ class Terminal extends React.Component {
}

getTerminalHeader() {
const light = this.props.statusBarColor || getNeutralColor();
const style = {
backgroundColor: this.props.titleBarColor || getNeutralColor()
backgroundColor: light,
};
return (
<div className="terminal-header" style={style}>
Expand Down Expand Up @@ -318,8 +336,11 @@ class Terminal extends React.Component {
return (
<div className="terminal-wrapper">
{this.isEmbedded() && this.getTerminalHeader()}
<div ref={(ref) => this.innerFlex = ref}
className={innerClassName} style={innerFlexStyle} >
<div
onClick={this.focusTerminal}
ref={(ref) => this.innerFlex = ref}
className={innerClassName}
style={innerFlexStyle} >
<div style={innerStyle} ref={(ref) => this.inner = ref} />
</div>
{this.getTerminalStatusBar()}
Expand All @@ -328,4 +349,10 @@ class Terminal extends React.Component {
}
}


Terminal.defaultProps = {
connect: true

This comment was marked as abuse.

This comment was marked as abuse.

};


export default connect()(Terminal);
45 changes: 26 additions & 19 deletions client/app/styles/main.less
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
@details-window-padding-left: 36px;
@border-radius: 4px;

@terminal-header-height: 34px;
@terminal-header-height: 44px;

@node-opacity-blurred: 0.25;
@node-highlight-fill-opacity: 0.1;
Expand Down Expand Up @@ -578,17 +578,18 @@ h2 {
.details {
&-wrapper {
position: fixed;
display: flex;
z-index: 1024;
right: @details-window-padding-left;
top: 24px;
bottom: 48px;
width: @details-window-width;
transition: transform 0.33333s cubic-bezier(0,0,0.21,1);
}
}

.node-details {
height: 100%;
width: @details-window-width;
background-color: rgba(255, 255, 255, 0.86);
display: flex;
flex-flow: column;
Expand All @@ -597,6 +598,8 @@ h2 {
border-radius: 2px;
background-color: #fff;
.shadow-2;
// keep node-details above the terminal.
z-index: 2;

&:last-child {
margin-bottom: 0;
Expand Down Expand Up @@ -979,35 +982,38 @@ h2 {
}

&-embedded {
z-index: 512;
position: fixed;
top: 24px;
bottom: 48px;
left: 36px;
right: (@details-window-width + @details-window-padding-left + 10px);
position: relative;
// shadow of animation-wrapper is 10px, let it fit in here without being
// overflow hiddened.
padding: 10px 0 10px 10px;
flex: 1;
overflow-x: hidden;
}

&-animation-wrapper {
width: 100%;
height: 100%;
transition: transform 0.5s cubic-bezier(0.230, 1.000, 0.320, 1.000);

This comment was marked as abuse.

.shadow-2;
}

&-wrapper {
position: absolute;
bottom: 0;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
border: 0px solid #000000;
border-radius: 4px;
color: #f0f0f0;
font-family: @mono-font;
.shadow-2;
}

&-header {
.truncate;
text-align: center;
color: @white;
height: @terminal-header-height;
padding: 8px 24px;
background-color: @text-color;
position: relative;
font-size: 14px;
line-height: 28px;
border-radius: 4px 0 0 0;

&-title {
cursor: default;
Expand All @@ -1030,7 +1036,6 @@ h2 {
font-size: 0.8em;
font-weight: bold;
text-transform: uppercase;
word-spacing: -4px;

&:hover {
opacity: 1;
Expand All @@ -1047,13 +1052,15 @@ h2 {
&-embedded &-inner { top: @terminal-header-height; }
&-app &-inner { top: 0; }
&-inner {
cursor: text;
font-family: @mono-font;
position: absolute;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.93);
padding: 8px;
border-radius: 0 0 2px 2px;
border-radius: 0 0 0 4px;

.terminal {
background-color: transparent !important;
Expand Down