mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 01:31:17 +00:00
Merge pull request #1903 from weaveworks/1152-clarify-term-is-child-window
Clarify terminal is child window of details panel.
This commit is contained in:
@@ -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 && <Details />}
|
||||
|
||||
{showingTerminal && <EmbeddedTerminal />}
|
||||
|
||||
<div className="header">
|
||||
<div className="logo">
|
||||
{!isIframe && <svg width="100%" height="100%" viewBox="0 0 1089 217">
|
||||
|
||||
@@ -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,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);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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});
|
||||
@@ -133,16 +141,26 @@ class Terminal extends React.Component {
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const component = this;
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.props.connect !== nextProps.connect && nextProps.connect) {
|
||||
this.mountTerminal();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
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) {
|
||||
@@ -180,6 +198,7 @@ class Terminal extends React.Component {
|
||||
this.term.destroy();
|
||||
this.term = null;
|
||||
}
|
||||
|
||||
if (this.socket) {
|
||||
log('close socket');
|
||||
this.socket.close();
|
||||
@@ -187,14 +206,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 +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);
|
||||
@@ -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}>
|
||||
@@ -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()}
|
||||
@@ -328,4 +349,10 @@ class Terminal extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Terminal.defaultProps = {
|
||||
connect: true
|
||||
};
|
||||
|
||||
|
||||
export default connect()(Terminal);
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
.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;
|
||||
@@ -1030,7 +1036,6 @@ h2 {
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
word-spacing: -4px;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user