diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index 3621f64e9..4220d859d 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -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'; @@ -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 ( @@ -114,8 +113,6 @@ class App extends React.Component { {showingDetails &&
} - {showingTerminal && } -
{!isIframe && diff --git a/client/app/scripts/components/details-card.js b/client/app/scripts/components/details-card.js index a8469625d..ffd7a1f04 100644 --- a/client/app/scripts/components/details-card.js +++ b/client/app/scripts/components/details-card.js @@ -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'; @@ -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 @@ -45,12 +46,23 @@ class DetailsCard extends React.Component { transform = `translateX(${shiftX}px)`; } } + const style = {transform, left: showingTerminal ? 36 : null}; return ( -
+
+ {showingTerminal && }
); } } -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); diff --git a/client/app/scripts/components/embedded-terminal.js b/client/app/scripts/components/embedded-terminal.js index 3c50fcc6e..e85ef251d 100644 --- a/client/app/scripts/components/embedded-terminal.js +++ b/client/app/scripts/components/embedded-terminal.js @@ -3,8 +3,6 @@ import { connect } from 'react-redux'; import { brightenColor, getNodeColorDark } from '../utils/color-utils'; import Terminal from './terminal'; -import { DETAILS_PANEL_WIDTH, DETAILS_PANEL_MARGINS, - DETAILS_PANEL_OFFSET } from '../constants/styles'; class EmeddedTerminal extends React.Component { render() { @@ -16,17 +14,12 @@ class EmeddedTerminal extends React.Component { const statusBarColor = d && brightenColor(titleBarColor); const title = d && d.label; - const style = { - right: DETAILS_PANEL_MARGINS.right + DETAILS_PANEL_WIDTH + - ((details.size - 1) * 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 ( -
+
); diff --git a/client/app/scripts/components/terminal.js b/client/app/scripts/components/terminal.js index 8ea4d44e1..03f4c1590 100644 --- a/client/app/scripts/components/terminal.js +++ b/client/app/scripts/components/terminal.js @@ -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) { @@ -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}); @@ -134,15 +142,13 @@ class Terminal extends React.Component { } componentDidMount() { - const component = this; - 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) { @@ -180,6 +186,7 @@ class Terminal extends React.Component { this.term.destroy(); this.term = null; } + if (this.socket) { log('close socket'); this.socket.close(); @@ -187,14 +194,6 @@ class Terminal extends React.Component { } } - 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 || @@ -213,6 +212,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); @@ -252,7 +257,6 @@ class Terminal extends React.Component { const border = `4px solid ${dark}`; const style = { borderTop: border, - borderBottom: border, borderLeft: border, backgroundColor: light, }; @@ -324,8 +328,11 @@ class Terminal extends React.Component { return (
{this.isEmbedded() && this.getTerminalHeader()} -
this.innerFlex = ref} - className={innerClassName} style={innerFlexStyle} > +
this.innerFlex = ref} + className={innerClassName} + style={innerFlexStyle} >
this.inner = ref} />
{this.getTerminalStatusBar()} diff --git a/client/app/styles/main.less b/client/app/styles/main.less index 56119dce8..e4819553e 100644 --- a/client/app/styles/main.less +++ b/client/app/styles/main.less @@ -41,7 +41,7 @@ @details-window-padding-left: 36px; @border-radius: 4px; -@terminal-header-height: 44px + 8px; +@terminal-header-height: 40px + 8px; @node-opacity-blurred: 0.25; @node-highlight-fill-opacity: 0.1; @@ -578,17 +578,19 @@ 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); + .shadow-2; } } .node-details { height: 100%; + width: @details-window-width; background-color: rgba(255, 255, 255, 0.86); display: flex; flex-flow: column; @@ -596,7 +598,6 @@ h2 { padding-bottom: 2px; border-radius: 2px; background-color: #fff; - .shadow-2; &:last-child { margin-bottom: 0; @@ -979,20 +980,13 @@ h2 { } &-embedded { - z-index: 1024; - position: fixed; - top: 24px; - bottom: 48px; - left: 36px; - right: (@details-window-width + @details-window-padding-left + 10px); + position: relative; + flex: 1; } &-wrapper { - position: absolute; - bottom: 0; - top: 0; - left: 0; - right: 0; + width: 100%; + height: 100%; border: 0px solid #000000; border-radius: 4px; color: #f0f0f0; @@ -1045,6 +1039,7 @@ h2 { &-embedded &-inner { top: @terminal-header-height; } &-app &-inner { top: 0; } &-inner { + cursor: text; font-family: @mono-font; position: absolute; bottom: 0;