import debug from 'debug';
import React from 'react';
import classNames from 'classnames';
import { connect } from 'react-redux';
import { Map as makeMap } from 'immutable';
import { clickCloseDetails, clickShowTopologyForNode } from '../actions/app-actions';
import { brightenColor, getNeutralColor, getNodeColorDark } from '../utils/color-utils';
import { isGenericTable, isPropertyList } from '../utils/node-details-utils';
import { resetDocumentTitle, setDocumentTitle } from '../utils/title-utils';
import MatchedText from './matched-text';
import NodeDetailsControls from './node-details/node-details-controls';
import NodeDetailsGenericTable from './node-details/node-details-generic-table';
import NodeDetailsPropertyList from './node-details/node-details-property-list';
import NodeDetailsHealth from './node-details/node-details-health';
import NodeDetailsInfo from './node-details/node-details-info';
import NodeDetailsRelatives from './node-details/node-details-relatives';
import NodeDetailsTable from './node-details/node-details-table';
import Warning from './warning';
const log = debug('scope:node-details');
function getTruncationText(count) {
return 'This section was too long to be handled efficiently and has been truncated'
+ ` (${count} extra entries not included). We are working to remove this limitation.`;
}
class NodeDetails extends React.Component {
constructor(props, context) {
super(props, context);
this.handleClickClose = this.handleClickClose.bind(this);
this.handleShowTopologyForNode = this.handleShowTopologyForNode.bind(this);
}
handleClickClose(ev) {
ev.preventDefault();
this.props.clickCloseDetails(this.props.nodeId);
}
handleShowTopologyForNode(ev) {
ev.preventDefault();
this.props.clickShowTopologyForNode(this.props.topologyId, this.props.nodeId);
}
componentDidMount() {
this.updateTitle();
}
componentWillUnmount() {
resetDocumentTitle();
}
renderTools() {
const showSwitchTopology = this.props.nodeId !== this.props.selectedNodeId;
const topologyTitle = `View ${this.props.label} in ${this.props.topologyId}`;
return (
{showSwitchTopology &&
Show in {this.props.topologyId.replace(/-/g, ' ')}
}
);
}
renderLoading() {
const node = this.props.nodes.get(this.props.nodeId);
const label = node ? node.get('label') : this.props.label;
// NOTE: If we start the fa-spin animation before the node details panel has been
// mounted, the spinner is displayed blurred the whole time in Chrome (possibly
// caused by a bug having to do with animating the details panel).
const spinnerClassName = classNames('fa fa-circle-o-notch', { 'fa-spin': this.props.mounted });
const nodeColor = (node ?
getNodeColorDark(node.get('rank'), label, node.get('pseudo')) :
getNeutralColor());
const tools = this.renderTools();
const styles = {
header: {
backgroundColor: nodeColor
}
};
return (
);
}
renderNotAvailable() {
const tools = this.renderTools();
return (
{tools}
{this.props.label} is not visible to Scope when it
is not communicating.
Details will become available here when it communicates again.
);
}
render() {
if (this.props.notFound) {
return this.renderNotAvailable();
}
if (this.props.details) {
return this.renderDetails();
}
return this.renderLoading();
}
renderDetails() {
const { details, nodeControlStatus, nodeMatches = makeMap() } = this.props;
const showControls = details.controls && details.controls.length > 0;
const nodeColor = getNodeColorDark(details.rank, details.label, details.pseudo);
const {error, pending} = nodeControlStatus ? nodeControlStatus.toJS() : {};
const tools = this.renderTools();
const styles = {
controls: {
backgroundColor: brightenColor(nodeColor)
},
header: {
backgroundColor: nodeColor
}
};
return (
{tools}
{showControls &&
}
{details.metrics &&
}
{details.metadata &&
}
{details.connections && details.connections.map(connections => (
))}
{details.children && details.children.map(children => (
))}
{details.tables && details.tables.length > 0 && details.tables.map((table) => {
if (table.rows.length > 0) {
return (
{table.label && table.label.length > 0 && table.label}
{table.truncationCount > 0 &&
}
{this.renderTable(table)}
);
}
return null;
})}
);
}
renderTable(table) {
const { nodeMatches = makeMap() } = this.props;
if (isGenericTable(table)) {
return (
);
} else if (isPropertyList(table)) {
return (
);
}
log(`Undefined type '${table.type}' for table ${table.id}`);
return null;
}
componentDidUpdate() {
this.updateTitle();
}
updateTitle() {
setDocumentTitle(this.props.details && this.props.details.label);
}
}
function mapStateToProps(state, ownProps) {
const currentTopologyId = state.get('currentTopologyId');
return {
nodeMatches: state.getIn(['searchNodeMatches', currentTopologyId, ownProps.id]),
nodes: state.get('nodes'),
selectedNodeId: state.get('selectedNodeId'),
};
}
export default connect(
mapStateToProps,
{ clickCloseDetails, clickShowTopologyForNode }
)(NodeDetails);