From 29e67683b3d54921e9ab3c1aceedcc9aba7eddb4 Mon Sep 17 00:00:00 2001 From: Simon Howe Date: Wed, 27 Jul 2016 20:37:35 +0200 Subject: [PATCH] New selection model. - highlight whole row - don't do anything when selecting text --- client/app/scripts/charts/nodes-grid.js | 13 ++--- .../node-details/node-details-table-row.js | 40 +++++++++++++-- .../node-details/node-details-table.js | 12 +++-- client/app/styles/main.less | 51 +++++++------------ 4 files changed, 68 insertions(+), 48 deletions(-) diff --git a/client/app/scripts/charts/nodes-grid.js b/client/app/scripts/charts/nodes-grid.js index 1bfcf72e4..e78a2a9bd 100644 --- a/client/app/scripts/charts/nodes-grid.js +++ b/client/app/scripts/charts/nodes-grid.js @@ -53,7 +53,7 @@ function getColumns(nodes) { } -function renderIdCell(props, onClick) { +function renderIdCell(props) { const style = { width: 16, flex: 'none', @@ -61,7 +61,7 @@ function renderIdCell(props, onClick) { }; return ( -
+
@@ -87,15 +87,15 @@ class NodesGrid extends React.Component { this.onMouseLeaveRow = this.onMouseLeaveRow.bind(this); } - clickRow(ev, nodeId, nodeLabel) { - if (ev.target.className === 'node-details-relatives-link') { + clickRow(ev, node, el) { + if (ev.target.className === 'node-details-table-node-link') { return; } - this.props.clickNode(nodeId, nodeLabel); + this.props.clickNode(node.id, node.label, el.getBoundingClientRect()); } renderIdCell(props) { - return renderIdCell(props, (ev) => this.clickRow(ev, props.id, props.label)); + return renderIdCell(props); } onMouseEnterRow() { @@ -144,6 +144,7 @@ class NodesGrid extends React.Component { tbodyStyle={tbodyStyle} topologyId={this.props.topologyId} onSortChange={this.onSortChange} + onClickRow={this.clickRow} {...detailsData} sortBy={gridSortBy} sortedDesc={gridSortedDesc} diff --git a/client/app/scripts/components/node-details/node-details-table-row.js b/client/app/scripts/components/node-details/node-details-table-row.js index 3e1eb47c2..25f40d6b0 100644 --- a/client/app/scripts/components/node-details/node-details-table-row.js +++ b/client/app/scripts/components/node-details/node-details-table-row.js @@ -1,4 +1,5 @@ import React from 'react'; +import ReactDOM from 'react-dom'; import classNames from 'classnames'; import NodeDetailsTableNodeLink from './node-details-table-node-link'; @@ -66,10 +67,20 @@ function renderValues(node, columns = [], columnWidths = []) { export default class NodeDetailsTableRow extends React.Component { constructor(props, context) { super(props, context); + + this.mouseDragOrigin = [0, 0]; + + this.storeLabelRef = this.storeLabelRef.bind(this); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); this.onMouseEnter = this.onMouseEnter.bind(this); this.onMouseLeave = this.onMouseLeave.bind(this); } + storeLabelRef(ref) { + this.labelEl = ref; + } + onMouseEnter() { const { node, onMouseEnterRow } = this.props; onMouseEnterRow(node); @@ -80,9 +91,30 @@ export default class NodeDetailsTableRow extends React.Component { onMouseLeaveRow(node); } + onMouseDown(ev) { + const { pageX, pageY } = ev; + this.mouseDragOrigin = [pageX, pageY]; + } + + onMouseUp(ev) { + const [originX, originY] = this.mouseDragOrigin; + const { pageX, pageY } = ev; + const thresholdPx = 2; + const movedTheMouseTooMuch = ( + Math.abs(originX - pageX) > thresholdPx || + Math.abs(originY - pageY) > thresholdPx + ); + if (movedTheMouseTooMuch) { + return; + } + + const { node, onClick } = this.props; + onClick(ev, node, ReactDOM.findDOMNode(this.labelEl)); + } + render() { - const { node, nodeIdKey, topologyId, columns, onMouseEnterRow, onMouseLeaveRow, selected, - widths } = this.props; + const { node, nodeIdKey, topologyId, columns, onClick, onMouseEnterRow, onMouseLeaveRow, + selected, widths } = this.props; const [firstColumnWidth, ...columnWidths] = widths; const values = renderValues(node, columns, columnWidths); const nodeId = node[nodeIdKey]; @@ -90,10 +122,12 @@ export default class NodeDetailsTableRow extends React.Component { return ( - {this.props.renderIdCell(Object.assign(node, {topologyId, nodeId}))} diff --git a/client/app/scripts/components/node-details/node-details-table.js b/client/app/scripts/components/node-details/node-details-table.js index 75ec09ff7..cd9f17fbf 100644 --- a/client/app/scripts/components/node-details/node-details-table.js +++ b/client/app/scripts/components/node-details/node-details-table.js @@ -23,8 +23,9 @@ const COLUMN_WIDTHS = { docker_container_uptime: '85px', docker_container_restart_count: '80px', docker_container_ips: '80px', - docker_container_created: '110px', - docker_container_state_human: '120px', + // 27 Jul 16 11:33 UTC + docker_container_created: '140px', + docker_container_state_human: '170px', open_files_count: '80px', ppid: '80px', pid: '80px', @@ -63,7 +64,7 @@ function getValueForSortBy(sortBy) { } } - return ''; + return null; }; } @@ -205,8 +206,8 @@ export default class NodeDetailsTable extends React.Component { render() { const headers = this.renderHeaders(); - const { nodeIdKey, columns, topologyId, onMouseEnter, onMouseLeave, onMouseEnterRow, - onMouseLeaveRow } = this.props; + const { nodeIdKey, columns, topologyId, onClickRow, onMouseEnter, onMouseLeave, + onMouseEnterRow, onMouseLeaveRow } = this.props; let nodes = getSortedNodes(this.props.nodes, this.props.columns, this.state.sortBy, this.state.sortedDesc); const limited = nodes && this.state.limit > 0 && nodes.length > this.state.limit; @@ -243,6 +244,7 @@ export default class NodeDetailsTable extends React.Component { nodeIdKey={nodeIdKey} widths={getColumnsWidths(this.getColumnHeaders())} columns={columns} + onClick={onClickRow} onMouseLeaveRow={onMouseLeaveRow} onMouseEnterRow={onMouseEnterRow} topologyId={topologyId} /> diff --git a/client/app/styles/main.less b/client/app/styles/main.less index 7e0fdc920..ee97b40fb 100644 --- a/client/app/styles/main.less +++ b/client/app/styles/main.less @@ -1541,43 +1541,13 @@ h2 { padding: 2px 2px; .content { - padding: 1px 4px; - cursor: pointer; - border: 1px solid transparent; - border-radius: 4px; display: flex; - div { flex: 1; } } - - .selected &, &:hover { - .content { - background-color: #d7ecf5; - } - } - .selected & .content { - border: 1px solid @weave-blue; - } } - /* - .node-details-relatives { - color: inherit; - font-size: 90%; - white-space: normal; - opacity: 0.8; - line-height: 110%; - text-align: right; - - margin-left: 0; - // margin-top: 0; - // display: inline-block; - float: right; - } - */ - .node-details-table-wrapper-wrapper { flex: 1; @@ -1603,10 +1573,23 @@ h2 { height: 24px; } - .node-details-table-node { - &.selected, &:hover { - background-color: @background-lighter-color; - } + tr:nth-child(even) { + background: @background-color; + } + + tbody tr { + border: 1px solid transparent; + border-radius: 4px; + cursor: pointer; + } + + tbody tr.selected, tbody tr:hover { + background-color: #d7ecf5; + border: 1px solid @weave-blue; + } + + tbody tr.selected { + // box-shadow: 0 4px 2px -2px rgba(0, 0, 0, 0.16); } }