2017-12-12 19:27:20 -07:00
|
|
|
import React, { Component } from "react";
|
2018-08-15 13:53:21 -06:00
|
|
|
import { connect } from "react-redux";
|
|
|
|
import Obstruction from "obstruction";
|
2017-12-12 19:27:20 -07:00
|
|
|
import PropTypes from "prop-types";
|
|
|
|
import ReactList from "react-list";
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
import cx from "classnames";
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2018-08-15 13:53:21 -06:00
|
|
|
class CanLog extends Component {
|
2017-12-12 19:27:20 -07:00
|
|
|
static ITEMS_PER_PAGE = 50;
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
static propTypes = {
|
|
|
|
plottedSignals: PropTypes.array,
|
|
|
|
segmentIndices: PropTypes.array,
|
|
|
|
onSignalUnplotPressed: PropTypes.func,
|
|
|
|
onSignalPlotPressed: PropTypes.func,
|
|
|
|
message: PropTypes.object,
|
|
|
|
messageIndex: PropTypes.number,
|
|
|
|
onMessageExpanded: PropTypes.func
|
|
|
|
};
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
// only want to display up to length elements at a time
|
|
|
|
// offset, length
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
this.state = {
|
|
|
|
length: 0,
|
|
|
|
expandedMessages: [],
|
|
|
|
messageHeights: [],
|
|
|
|
allPacketsExpanded: false
|
|
|
|
};
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
this.renderLogListItemMessage = this.renderLogListItemMessage.bind(this);
|
|
|
|
this.addDisplayedMessages = this.addDisplayedMessages.bind(this);
|
|
|
|
this.renderLogListItem = this.renderLogListItem.bind(this);
|
|
|
|
this.renderLogList = this.renderLogList.bind(this);
|
|
|
|
this.onExpandAllChanged = this.onExpandAllChanged.bind(this);
|
|
|
|
this.toggleExpandAllPackets = this.toggleExpandAllPackets.bind(this);
|
|
|
|
this.toggleSignalPlot = this.toggleSignalPlot.bind(this);
|
|
|
|
}
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
|
if (nextProps.message && !this.props.message) {
|
|
|
|
this.addDisplayedMessages();
|
2017-05-29 17:52:17 -06:00
|
|
|
}
|
2017-12-12 19:27:20 -07:00
|
|
|
}
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
shouldComponentUpdate(nextProps, nextState) {
|
|
|
|
const curMessageLength = this.props.message
|
|
|
|
? this.props.message.entries.length
|
|
|
|
: 0;
|
|
|
|
const nextMessageLength = nextProps.message
|
|
|
|
? nextProps.message.entries.length
|
|
|
|
: 0;
|
2017-06-13 18:40:05 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
const shouldUpdate =
|
|
|
|
this.props.message !== nextProps.message ||
|
|
|
|
nextMessageLength !== curMessageLength ||
|
|
|
|
nextProps.messageIndex !== this.props.messageIndex ||
|
|
|
|
nextProps.plottedSignals.length !== this.props.plottedSignals.length ||
|
|
|
|
JSON.stringify(nextProps.segmentIndices) !==
|
|
|
|
JSON.stringify(this.props.segmentIndices) ||
|
|
|
|
JSON.stringify(nextState) !== JSON.stringify(this.state) ||
|
|
|
|
this.props.message !== nextProps.message ||
|
|
|
|
(this.props.message !== undefined &&
|
|
|
|
nextProps.message !== undefined &&
|
|
|
|
this.props.message.frame !== undefined &&
|
|
|
|
nextProps.message.frame !== undefined &&
|
|
|
|
JSON.stringify(this.props.message.frame) !==
|
|
|
|
JSON.stringify(nextProps.message.frame));
|
2017-06-20 17:46:07 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
return shouldUpdate;
|
|
|
|
}
|
2017-06-13 18:40:05 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
addDisplayedMessages() {
|
|
|
|
const { length } = this.state;
|
|
|
|
const newLength = length + CanLog.ITEMS_PER_PAGE;
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
this.setState({ length: newLength });
|
|
|
|
}
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
expandMessage(msg, msgIdx) {
|
|
|
|
this.setState({
|
|
|
|
expandedMessages: this.state.expandedMessages.concat([msg.time])
|
|
|
|
});
|
|
|
|
this.props.onMessageExpanded();
|
|
|
|
}
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
collapseMessage(msg, msgIdx) {
|
|
|
|
this.setState({
|
|
|
|
expandedMessages: this.state.expandedMessages.filter(
|
|
|
|
expMsgTime => expMsgTime !== msg.time
|
|
|
|
)
|
|
|
|
});
|
|
|
|
}
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
isSignalPlotted(msgId, signalUid) {
|
|
|
|
const plottedSignal = this.props.plottedSignals.find(plot =>
|
|
|
|
plot.some(
|
|
|
|
signal => signal.messageId === msgId && signal.signalUid === signalUid
|
|
|
|
)
|
|
|
|
);
|
|
|
|
return plottedSignal !== undefined;
|
|
|
|
}
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
signalValuePretty(signal, value) {
|
|
|
|
if (signal.isFloat) {
|
|
|
|
return value.toFixed(3);
|
|
|
|
} else return value;
|
|
|
|
}
|
2017-06-20 23:52:57 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
isMessageExpanded(msg) {
|
|
|
|
return this.state.expandedMessages.indexOf(msg.time) !== -1;
|
|
|
|
}
|
2017-07-19 23:40:20 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
toggleSignalPlot(msg, signalUid, plotted) {
|
|
|
|
if (!plotted) {
|
|
|
|
this.props.onSignalPlotPressed(msg, signalUid);
|
|
|
|
} else {
|
|
|
|
this.props.onSignalUnplotPressed(msg, signalUid);
|
2017-07-19 23:40:20 -06:00
|
|
|
}
|
2017-12-12 19:27:20 -07:00
|
|
|
}
|
2017-07-19 23:40:20 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
toggleExpandPacketSignals(msgEntry) {
|
|
|
|
if (!this.props.message.frame) {
|
|
|
|
return;
|
2017-07-19 23:40:20 -06:00
|
|
|
}
|
2017-12-12 19:27:20 -07:00
|
|
|
const msgIsExpanded =
|
|
|
|
this.state.allPacketsExpanded || this.isMessageExpanded(msgEntry);
|
2017-07-19 23:40:20 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
const msgHasSignals =
|
|
|
|
Object.keys(this.props.message.frame.signals).length > 0;
|
|
|
|
if (msgIsExpanded && msgHasSignals) {
|
|
|
|
this.setState({
|
|
|
|
expandedMessages: this.state.expandedMessages.filter(
|
|
|
|
expMsgTime => expMsgTime !== msgEntry.time
|
|
|
|
)
|
|
|
|
});
|
|
|
|
} else if (msgHasSignals) {
|
|
|
|
this.setState({
|
|
|
|
expandedMessages: this.state.expandedMessages.concat([msgEntry.time])
|
|
|
|
});
|
|
|
|
this.props.onMessageExpanded();
|
|
|
|
} else {
|
|
|
|
return;
|
2017-05-29 17:52:17 -06:00
|
|
|
}
|
2017-12-12 19:27:20 -07:00
|
|
|
}
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
renderLogListItemSignals(msgEntry) {
|
|
|
|
const { message } = this.props;
|
|
|
|
return (
|
|
|
|
<div className="signals-log-list-signals">
|
|
|
|
{Object.entries(msgEntry.signals).map(([name, value]) => {
|
|
|
|
const signal = message.frame.signals[name];
|
|
|
|
if (signal === undefined) {
|
|
|
|
// Signal removed?
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const unit = signal.unit.length > 0 ? signal.unit : "units";
|
|
|
|
const isPlotted = this.isSignalPlotted(message.id, signal.uid);
|
|
|
|
const plottedButtonClass = isPlotted ? null : "button--alpha";
|
|
|
|
const plottedButtonText = isPlotted ? "Hide Plot" : "Show Plot";
|
|
|
|
return (
|
|
|
|
<div key={name} className="signals-log-list-signal">
|
|
|
|
<div className="signals-log-list-signal-message">
|
|
|
|
<span>{name}</span>
|
|
|
|
</div>
|
|
|
|
<div className="signals-log-list-signal-value">
|
|
|
|
<span>
|
|
|
|
(<strong>{this.signalValuePretty(signal, value)}</strong>{" "}
|
|
|
|
{unit})
|
|
|
|
</span>
|
2017-07-19 23:40:20 -06:00
|
|
|
</div>
|
2017-12-12 19:27:20 -07:00
|
|
|
<div
|
|
|
|
className="signals-log-list-signal-action"
|
|
|
|
onClick={() => {
|
|
|
|
this.toggleSignalPlot(message.id, signal.uid, isPlotted);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<button className={cx("button--tiny", plottedButtonClass)}>
|
|
|
|
<span>{plottedButtonText}</span>
|
|
|
|
</button>
|
2017-07-19 23:40:20 -06:00
|
|
|
</div>
|
|
|
|
</div>
|
2017-12-12 19:27:20 -07:00
|
|
|
);
|
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
renderLogListItemMessage(msgEntry, key) {
|
|
|
|
const { message } = this.props;
|
|
|
|
const msgIsExpanded =
|
|
|
|
this.state.allPacketsExpanded || this.isMessageExpanded(msgEntry);
|
|
|
|
const msgHasSignals = Object.keys(msgEntry.signals).length > 0;
|
|
|
|
const hasSignalsClass = msgHasSignals ? "has-signals" : null;
|
|
|
|
const expandedClass = msgIsExpanded ? "is-expanded" : null;
|
|
|
|
const row = (
|
|
|
|
<div
|
|
|
|
key={key}
|
|
|
|
className={cx("signals-log-list-item", hasSignalsClass, expandedClass)}
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
className="signals-log-list-item-header"
|
|
|
|
onClick={() => {
|
|
|
|
this.toggleExpandPacketSignals(msgEntry);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<div className="signals-log-list-message">
|
|
|
|
<strong>
|
|
|
|
{(message.frame ? message.frame.name : null) || message.id}
|
|
|
|
</strong>
|
|
|
|
</div>
|
|
|
|
<div className="signals-log-list-time">
|
|
|
|
<span>[{msgEntry.relTime.toFixed(3)}]</span>
|
|
|
|
</div>
|
|
|
|
<div className="signals-log-list-bytes">
|
|
|
|
<span className="t-mono">{msgEntry.hexData}</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className="signals-log-list-item-body">
|
|
|
|
{msgIsExpanded ? this.renderLogListItemSignals(msgEntry) : null}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
return row;
|
|
|
|
}
|
2017-05-29 17:52:17 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
renderLogListItem(index, key) {
|
|
|
|
let offset = this.props.messageIndex;
|
|
|
|
if (offset === 0 && this.props.segmentIndices.length === 2) {
|
|
|
|
offset = this.props.segmentIndices[0];
|
2017-05-29 17:52:17 -06:00
|
|
|
}
|
2017-12-12 19:27:20 -07:00
|
|
|
if (offset + index < this.props.message.entries.length) {
|
|
|
|
return this.renderLogListItemMessage(
|
|
|
|
this.props.message.entries[offset + index],
|
|
|
|
key
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
return null;
|
2017-06-13 18:40:05 -06:00
|
|
|
}
|
2017-12-12 19:27:20 -07:00
|
|
|
}
|
2017-06-13 18:40:05 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
renderLogList(items, ref) {
|
|
|
|
return (
|
|
|
|
<div className="signals-log-list">
|
|
|
|
<div className="signals-log-list-header">
|
|
|
|
<div className="signals-log-list-message">Message</div>
|
|
|
|
<div className="signals-log-list-time">Time</div>
|
|
|
|
<div className="signals-log-list-bytes">Bytes</div>
|
|
|
|
</div>
|
|
|
|
<div className="signals-log-list-items" ref={ref}>
|
|
|
|
{items}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
2017-06-20 22:21:35 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
listLength() {
|
|
|
|
const { segmentIndices, messageIndex } = this.props;
|
|
|
|
if (messageIndex > 0) {
|
|
|
|
return this.props.message.entries.length - messageIndex;
|
|
|
|
} else if (segmentIndices.length === 2) {
|
|
|
|
return segmentIndices[1] - segmentIndices[0];
|
|
|
|
} else if (this.props.message) {
|
|
|
|
return this.props.message.entries.length;
|
|
|
|
} else {
|
|
|
|
// no message yet
|
|
|
|
return 0;
|
2017-07-19 23:40:20 -06:00
|
|
|
}
|
2017-12-12 19:27:20 -07:00
|
|
|
}
|
2017-06-20 22:21:35 -06:00
|
|
|
|
2017-12-12 19:27:20 -07:00
|
|
|
onExpandAllChanged(e) {
|
|
|
|
this.setState({ allPacketsExpanded: e.target.checked });
|
|
|
|
}
|
|
|
|
|
|
|
|
toggleExpandAllPackets() {
|
|
|
|
this.setState({ allPacketsExpanded: !this.state.allPacketsExpanded });
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
let expandAllText = this.state.allPacketsExpanded
|
|
|
|
? "Collapse All"
|
|
|
|
: "Expand All";
|
|
|
|
let expandAllClass = this.state.allPacketsExpanded ? null : "button--alpha";
|
|
|
|
return (
|
|
|
|
<div className="cabana-explorer-signals-log">
|
|
|
|
<div className="cabana-explorer-signals-log-header">
|
|
|
|
<strong>Message Packets</strong>
|
|
|
|
<button
|
|
|
|
className={cx("button--tiny", expandAllClass)}
|
|
|
|
onClick={this.toggleExpandAllPackets}
|
|
|
|
>
|
|
|
|
{expandAllText}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<div className="cabana-explorer-signals-log-body">
|
|
|
|
<ReactList
|
|
|
|
itemRenderer={this.renderLogListItem}
|
|
|
|
itemsRenderer={this.renderLogList}
|
|
|
|
length={this.listLength()}
|
|
|
|
pageSize={50}
|
|
|
|
updateWhenThisValueChanges={this.props.messageIndex}
|
|
|
|
type="variable"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
2017-05-29 17:52:17 -06:00
|
|
|
}
|
2018-08-15 13:53:21 -06:00
|
|
|
|
|
|
|
const stateToProps = Obstruction({
|
|
|
|
segmentIndices: "segment.segmentIndices"
|
|
|
|
});
|
|
|
|
|
|
|
|
export default connect(stateToProps)(CanLog);
|