123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- 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,
- relatives,
- value: relatives.map(relative => relative.label).join(', '),
- valueType: '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}>
- {field.dataType === 'link'
- ? (
- <a
- rel="noopener noreferrer"
- target="_blank"
- className="node-details-table-node-link"
- href={value}>
- {value}
- </a>
- )
- : 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.mouseDrag = {};
- }
- 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) => {
- this.mouseDrag = {
- originX: ev.pageX,
- originY: ev.pageY,
- };
- }
- onClick = (ev) => {
- const thresholdPx = 2;
- const { pageX, pageY } = ev;
- const { originX, originY } = this.mouseDrag;
- const movedTheMouseTooMuch = (
- Math.abs(originX - pageX) > thresholdPx
- || Math.abs(originY - pageY) > thresholdPx
- );
- if (movedTheMouseTooMuch && originX && originY) {
- return;
- }
- this.props.onClick(ev, this.props.node);
- this.mouseDrag = {};
- }
- 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('tour-step-anchor node-details-table-node', {
- focused: this.state.focused,
- selected: this.props.selected,
- });
- return (
- <tr
- onClick={onClick && this.onClick}
- onMouseDown={onClick && this.onMouseDown}
- onMouseEnter={this.onMouseEnter}
- onMouseLeave={this.onMouseLeave}
- className={className}>
- <td className="node-details-table-node-label truncate" style={firstColumnStyle}>
- {this.props.renderIdCell(Object.assign(node, { nodeId, topologyId }))}
- </td>
- {values}
- </tr>
- );
- }
- }
- NodeDetailsTableRow.defaultProps = {
- renderIdCell: props => <NodeDetailsTableNodeLink {...props} />
- };
|