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 NodeDetailsTableNodeMetric from './node-details-table-node-metric'; 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) { 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 ( {value} ); } if (field.valueType === 'relatives') { return ( {intersperse(field.relatives.map(relative => ), ' ')} ); } return ( ); } // empty cell to complete the row for proper hover return ( ); }); } 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); const nodeId = node[nodeIdKey]; const className = classNames('node-details-table-node', { selected: this.props.selected, focused: this.state.focused, }); return ( {this.props.renderIdCell(Object.assign(node, {topologyId, nodeId}))} {values} ); } } NodeDetailsTableRow.defaultProps = { renderIdCell: props => };