Files
weave-scope/client/app/scripts/components/node-details/node-details-table-row.js
Roland Schilter 8188b7aed2 Append links directly to metrics
The initial idea was to keep it separate since the unattached
links were also to be displayed distinctively from the metrics.
With the new design, unattached links are rendered in the same
list as metrics with attached links.

Therefore, we treat unattached metric links as an empty metric.
2017-08-11 16:45:13 +01:00

175 lines
5.0 KiB
JavaScript

import React from 'react';
import classNames from 'classnames';
import { groupBy, mapValues } from 'lodash';
import { intersperse } from '../../utils/array-utils';
import NodeDetailsTableNodeLink from './node-details-table-node-link';
import NodeDetailsTableNodeMetricLink from './node-details-table-node-metric-link';
import { formatDataType } from '../../utils/string-utils';
function getValuesForNode(node) {
let values = {};
['metrics', 'metadata'].forEach((collection) => {
if (node[collection]) {
node[collection].forEach((field) => {
const result = Object.assign({}, field);
result.valueType = collection;
values[field.id] = result;
});
}
});
if (node.parents) {
const byTopologyId = groupBy(node.parents, parent => parent.topologyId);
const relativesByTopologyId = mapValues(byTopologyId, (relatives, topologyId) => ({
id: topologyId,
label: topologyId,
value: relatives.map(relative => relative.label).join(', '),
valueType: 'relatives',
relatives,
}));
values = {
...values,
...relativesByTopologyId,
};
}
return values;
}
function renderValues(node, columns = [], columnStyles = [], timestamp = null, topologyId = null) {
const fields = getValuesForNode(node);
return columns.map(({ id }, i) => {
const field = fields[id];
const style = columnStyles[i];
if (field) {
if (field.valueType === 'metadata') {
const { value, title } = formatDataType(field, timestamp);
return (
<td
className="node-details-table-node-value truncate"
title={title}
style={style}
key={field.id}>
{value}
</td>
);
}
if (field.valueType === 'relatives') {
return (
<td
className="node-details-table-node-value truncate"
title={field.value}
style={style}
key={field.id}>
{intersperse(field.relatives.map(relative =>
<NodeDetailsTableNodeLink
key={relative.id}
linkable
nodeId={relative.id}
{...relative}
/>
), ' ')}
</td>
);
}
// valueType === 'metrics'
return (
<NodeDetailsTableNodeMetricLink
style={style} key={field.id} topologyId={topologyId} {...field} />
);
}
// empty cell to complete the row for proper hover
return (
<td className="node-details-table-node-value" style={style} key={id} />
);
});
}
export default class NodeDetailsTableRow extends React.Component {
constructor(props, context) {
super(props, context);
//
// We watch how far the mouse moves when click on a row, move to much and we assume that the
// user is selecting some data in the row. In this case don't trigger the onClick event which
// is most likely a details panel popping open.
//
this.state = { focused: false };
this.mouseDragOrigin = [0, 0];
this.onMouseDown = this.onMouseDown.bind(this);
this.onMouseUp = this.onMouseUp.bind(this);
this.onMouseEnter = this.onMouseEnter.bind(this);
this.onMouseLeave = this.onMouseLeave.bind(this);
}
onMouseEnter() {
this.setState({ focused: true });
if (this.props.onMouseEnter) {
this.props.onMouseEnter(this.props.index, this.props.node);
}
}
onMouseLeave() {
this.setState({ focused: false });
if (this.props.onMouseLeave) {
this.props.onMouseLeave();
}
}
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;
}
this.props.onClick(ev, this.props.node);
}
render() {
const { node, nodeIdKey, topologyId, columns, onClick, colStyles, timestamp } = this.props;
const [firstColumnStyle, ...columnStyles] = colStyles;
const values = renderValues(node, columns, columnStyles, timestamp, topologyId);
const nodeId = node[nodeIdKey];
const className = classNames('node-details-table-node', {
selected: this.props.selected,
focused: this.state.focused,
});
return (
<tr
onMouseDown={onClick && this.onMouseDown}
onMouseUp={onClick && this.onMouseUp}
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}
className={className}>
<td className="node-details-table-node-label truncate" style={firstColumnStyle}>
{this.props.renderIdCell(Object.assign(node, {topologyId, nodeId}))}
</td>
{values}
</tr>
);
}
}
NodeDetailsTableRow.defaultProps = {
renderIdCell: props => <NodeDetailsTableNodeLink {...props} />
};