)
}
- isMessageExpanded(msg) {
- return this.state.expandedMessages.indexOf(msg.time) !== -1;
+ renderLogListItemMessage(msg, key) {
+ const msgIsExpanded = this.state.allPacketsExpanded || this.isMessageExpanded(msg);
+ const msgHasSignals = Object.keys(msg.signals).length > 0;
+ const hasSignalsClass = msgHasSignals ? 'has-signals' : null;
+ const expandedClass = msgIsExpanded ? 'is-expanded' : null;
+ const row = (
+
+ );
+
+ return row;
}
- messageRow(msg, key) {
- const msgIsExpanded = this.state.expandAllChecked || this.isMessageExpanded(msg);
- const hasSignals = Object.keys(msg.signals).length > 0;
- const rowStyle = (hasSignals ? Styles.pointer : null);
- const row = [
];
+ renderLogListItem(index, key) {
+ let offset = this.props.messageIndex;
+ if(offset === 0 && this.props.segmentIndices.length === 2) {
+ offset = this.props.segmentIndices[0];
+ }
- if(msgIsExpanded) {
- row.push(this.expandedMessage(msg));
- }
-
- return row;
+ return this.renderLogListItemMessage(this.props.message.entries[offset + index], key);
}
- renderMessage(index, key) {
- let offset = this.props.messageIndex;
- if(offset === 0 && this.props.segmentIndices.length === 2) {
- offset = this.props.segmentIndices[0];
- }
-
- return this.messageRow(this.props.message.entries[offset + index], key);
- }
-
- renderTable(items, ref) {
- return (
-
-
-
Time (s)
-
- Message
-
-
- Bytes
-
+ renderLogList(items, ref) {
+ return (
+
+
-
- {items}
+ {items}
-
)
+
+ )
}
listLength() {
@@ -218,25 +224,36 @@ export default class CanLog extends Component {
}
onExpandAllChanged(e) {
- this.setState({expandAllChecked: e.target.checked});
+ this.setState({allPacketsExpanded: e.target.checked});
+ }
+
+ toggleExpandAllPackets() {
+ this.setState({allPacketsExpanded: !this.state.allPacketsExpanded});
}
render() {
-
- return
-
Expand all messages:
-
-
-
-
;
+ let expandAllText = this.state.allPacketsExpanded ? 'Collapse All' : 'Expand All';
+ let expandAllClass = this.state.allPacketsExpanded ? null : 'button--alpha';
+ return (
+
+
+ Message Packets
+
+
+
+
+
+
+ );
}
}
diff --git a/src/components/Explorer/explorer.scss b/src/components/Explorer/explorer.scss
index 068144b..24d98a4 100644
--- a/src/components/Explorer/explorer.scss
+++ b/src/components/Explorer/explorer.scss
@@ -5,23 +5,91 @@
*/
-@import '../../styles/_global/colors';
+@import '../../styles/_global/all';
-.cabana {
+#cabana {
display: flex;
+ height: 100%;
+ flex-direction: column;
+ flex-grow: 1;
+}
+
+.cabana-header {
+ background: $color-grey-90;
+ color: #fff;
+ height: 68px;
+ padding: 22px;
+ &-logo {
+ color: #fff;
+ font-size: 20px;
+ font-weight: 600;
+ text-decoration: none;
+ pointer-events: none; // disable actual click
+ }
+ &-account {
+ float: right;
+ a {
+ color: #fff;
+ font-size: 14px;
+ font-weight: 600;
+ text-decoration: none;
+ }
+ }
+}
+
+.cabana-window {
+ display: flex;
+ flex-grow: 1;
+ overflow: hidden;
}
.cabana-explorer {
display: flex;
flex: 1;
+ &-header {
+ }
&-signals {
flex: 1;
- height: 100vh;
- overflow-x: hidden;
- overflow-y: scroll;
- padding: 3%;
- &-header {}
- &-controller {}
+ max-height: 100vh;
+ &-wrapper {
+ display: flex;
+ height: 100%;
+ flex-direction: column;
+ }
+ &-header {
+ border-bottom: 1px solid rgba(0,0,0,.2);
+ display: flex;
+ flex-direction: row;
+ min-height: 89px;
+ padding: 5%;
+ h6,
+ h3 {
+ margin: 0;
+ }
+ h6 {
+ font-size: 13px;
+ font-weight: normal;
+ padding-bottom: 5px;
+ text-transform: uppercase;
+ }
+ &-context {
+ flex: 4;
+ }
+ &-action {
+ flex: 1;
+ button {
+ width: 100%;
+ }
+ }
+ }
+ &-window {
+ overflow-x: hidden;
+ overflow-y: scroll;
+ height: 100%;
+ }
+ &-controller {
+ padding: 5%;
+ }
&-matrix {
table {
border: 1px solid rgba(0,0,0,.2);
@@ -32,19 +100,41 @@
}
}
&-log {
- background: $color-grey-10;
- border: 1px solid rgba(0,0,0,.2);
- border-radius: 5px;
- padding: 3%;
+ border-top: 1px solid $color-grey-30;
+ padding: 0 5%;
+ &-header {
+ padding: 5% 0;
+ strong {
+ color: $color-grey-70;
+ font-size: 14px;
+ }
+ button {
+ float: right;
+ text-transform: uppercase;
+ }
+ }
+ &-body {
+ background: $color-grey-10;
+ border: 1px solid rgba(0,0,0,.2);
+ border-radius: 5px;
+ }
+ &-list {
+ padding: 3%;
+ }
}
}
&-visuals {
+ background: $color-grey-10;
flex: 1;
- height: 100vh;
+ max-height: 100vh;
overflow-x: hidden;
overflow-y: scroll;
- padding: 1.5%;
- padding-left: 0;
+ padding: 1.5% 3%;
+ &-header {
+ border-bottom: 1px solid rgba(0,0,0,.1);
+ margin-bottom: 2%;
+ padding: 2% 0;
+ }
&-camera {
border: 5px solid #000;
border-radius: 5px;
@@ -66,11 +156,13 @@
}
}
&-plots {
- border: 1px solid $color-grey-30;
+ border: 1px solid $color-grey-40;
border-radius: 5px;
margin: 3% 0;
}
&-plot {
+ background: #fff;
+ border-radius: 5px;
padding: 1.5% 3%;
&:first-child,
&:last-child {
diff --git a/src/components/Meta/meta.scss b/src/components/Meta/meta.scss
index 2ff662d..7caeafc 100644
--- a/src/components/Meta/meta.scss
+++ b/src/components/Meta/meta.scss
@@ -5,15 +5,99 @@
*/
-@import '../../styles/_global/colors';
+@import '../../styles/_global/all';
.cabana-meta {
background: $color-grey-20;
+ display: flex;
flex: .5;
flex-direction: column;
- height: 100vh;
+ max-height: 100vh;
overflow-y: scroll;
+ &-header {
+ border-bottom: 1px solid rgba(0,0,0,.1);
+ flex-direction: row;
+ padding: 22px;
+ @extend %clearfix;
+ &-label {
+ display: block;
+ font-size: 13px;
+ padding-bottom: 1%;
+ text-transform: uppercase;
+ }
+ &-filename {
+ display: block;
+ }
+ &-last-saved {
+ color: $color-grey-60;
+ font-size: 13px;
+ margin-bottom: -5px;
+ padding-top: 3px;
+ }
+ &-actions {
+ padding: 18px 0;
+ }
+ &-action {
+ float: left;
+ padding: 0 1%;
+ width: (100%/3);
+ &:first-child {
+ padding-left: 0;
+ }
+ &:last-child {
+ padding-right: 0;
+ }
+ button {
+ width: 100%;
+ }
+ }
+ }
+ &-messages {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ padding-left: 11px;
+ &-header {
+ height: 34px;
+ padding: 22px 11px;
+ }
+ &-window {
+ background: $color-grey-30;
+ border-radius: 5px;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ }
+ &-filter {
+ border-bottom: 1px solid rgba(0,0,0,.05);
+ height: 64px;
+ padding: 11px;
+ }
+ &-list {
+ height: 100%;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ &-item {
+ cursor: pointer;
+ position: relative;
+ transition-duration: .1s;
+ &:not(.is-selected):hover {
+ background: rgba(0,0,0,.05);
+ }
+ &.is-selected {
+ background: $color-grey-40;
+ font-weight: 600;
+ }
+ }
+ }
+ }
table {
+ border-spacing: 0;
+ font-size: 12px;
width: 100%;
+ thead tr td:first-child,
+ tbody tr td:first-child {
+ padding-left: 11px;
+ }
}
}
diff --git a/src/components/PartSelector.js b/src/components/PartSelector.js
index 6cdddea..2673b07 100644
--- a/src/components/PartSelector.js
+++ b/src/components/PartSelector.js
@@ -131,7 +131,7 @@ const Styles = StyleSheet.create({
position: 'relative'
},
selectedPart: {
- backgroundColor: 'black',
+ backgroundColor: '#6f6f6f',
height: '100%',
position: 'absolute',
},
diff --git a/src/components/SignalLegend/signalLegend.scss b/src/components/SignalLegend/signalLegend.scss
index c149137..8b86a8f 100644
--- a/src/components/SignalLegend/signalLegend.scss
+++ b/src/components/SignalLegend/signalLegend.scss
@@ -5,38 +5,112 @@
*/
-@import '../../styles/_global/index';
+@import '../../styles/_global/all';
.cabana-explorer-signals-legend {
background: $color-grey-10;
border: 1px solid rgba(0,0,0,.2);
border-radius: 5px;
- margin: 5% 0;
- padding: 2%;
+ margin-top: 5%;
}
.signals-legend-entry {
+ $entry-header-height: 42px;
+ $entry-header-icon-size: 28px;
overflow: auto;
+ transition-duration: .1s;
+ padding: 0 2%;
&:not(:last-child) {
border-bottom: 1px solid rgba(0,0,0,.05);
}
- &-header {
- cursor: pointer;
- line-height: 42px;
- &-name {
- float: left;
- width: 70%;
+ &:hover {
+ background: rgba(0,0,0,.02);
+ }
+ &.is-expanded {
+ .signals-legend-entry-header {
+ border-bottom-color: rgba(0,0,0,.05);
+ height: $entry-header-height + 3px;
+ &:before {
+ left: 0;
+ padding-top: 5px;
+ top: -3px;
+ transform: rotate(90deg);
+ }
}
- &-plotted {
+ .signals-legend-entry-body {
+ display: block;
+ }
+ }
+ &-header {
+ border-bottom: 1px solid transparent;
+ cursor: pointer;
+ height: $entry-header-height;
+ line-height: $entry-header-height;
+ position: relative;
+ transition-duration: .2s;
+ &:before {
+ color: $color-grey-80;
+ content: $fa-var-chevron-right;
+ display: block;
+ font-size: 10px;
+ font-family: 'FontAwesome';
+ height: $entry-header-height;
+ left: -2px;
+ top: 0;
+ pointer-events: none;
+ position: absolute;
+ transition-duration: .1s;
+ text-align: center;
+ width: $entry-header-icon-size;
+ }
+ &-name {
+ color: $color-grey-80;
+ font-size: 14px;
+ float: left;
+ padding-left: $entry-header-icon-size;
+ width: 75%;
+ }
+ &-action {
float: left;
text-align: right;
- width: 30%;
+ padding-right: 2%;
+ width: 25%;
+ button {
+ display: inline-block;
+ width: 100%;
+ }
}
}
&-body {
+ display: none;
padding: 2%;
}
- &.is-expanded {
-
+ &-form {
+ &-field {
+ min-height: $input-height;
+ padding: 1px 0;
+ @extend %clearfix;
+ &:not(:last-child) {
+ border-bottom: 1px solid rgba(0,0,0,.05);
+ margin-bottom: 3px;
+ }
+ label {
+ color: $color-grey-80;
+ cursor: pointer;
+ float: left;
+ font-size: 12px;
+ font-weight: 600;
+ line-height: $input-height--small;
+ width: 40%;
+ }
+ input,
+ select {
+ float: left;
+ width: 60%;
+ }
+ }
+ &-remove {
+ padding: 2% 0;
+ }
}
}
diff --git a/src/components/SignalLegendEntry.js b/src/components/SignalLegendEntry.js
index 76a6a4a..c304d14 100644
--- a/src/components/SignalLegendEntry.js
+++ b/src/components/SignalLegendEntry.js
@@ -3,6 +3,7 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { StyleSheet, css } from 'aphrodite/no-important';
+import cx from 'classnames';
import Signal from '../models/can/signal';
import DbcUtils from '../utils/dbc';
@@ -150,6 +151,7 @@ export default class SignalLegendEntry extends Component {
this.toggleEditing = this.toggleEditing.bind(this);
this.updateField = this.updateField.bind(this);
this.onNameChange = this.onNameChange.bind(this);
+ this.toggleSignalPlot = this.toggleSignalPlot.bind(this);
}
componentWillReceiveProps(nextProps) {
@@ -159,12 +161,16 @@ export default class SignalLegendEntry extends Component {
}
}
- field(field, title, valueCol) {
+ field(field, title, valueCol, signal) {
const value = this.props.signal[field];
-
let titleCol =
{title} | ;
- return
{titleCol}{valueCol} |
;
+ return (
+
+
+ {valueCol}
+
+ )
}
updateField(fieldSpec, value) {
@@ -187,7 +193,7 @@ export default class SignalLegendEntry extends Component {
this.props.onSignalChange(signalCopy, signal);
}
- numberField(fieldSpec) {
+ renderNumberField(fieldSpec, signal) {
const {field, title, options} = fieldSpec;
let valueCol;
@@ -197,39 +203,40 @@ export default class SignalLegendEntry extends Component {
let num = Number(value);
value = (isNaN(num) ? '' : num);
}
-
- valueCol =
{
- let {value} = e.target;
-
- this.updateField(fieldSpec, value);
- }}/>;
+ valueCol = (
+
{this.updateField(fieldSpec, e.target)}
+ }/>
+ );
} else {
let value = this.props.signal[field];
valueCol =
{value};
}
- return this.field(field, title, valueCol);
+ return this.field(field, title, valueCol, signal);
}
- stringField(fieldSpec) {
+ renderStringField(fieldSpec, signal) {
const {field, title} = fieldSpec;
let valueCol;
if(this.state.isEditing) {
- valueCol =
{
- this.updateField(fieldSpec, e.target.value)
- }}
- />;
+ valueCol = (
+
{
+ this.updateField(fieldSpec, e.target.value)
+ }}
+ />);
} else {
valueCol =
{this.props.signal[field]};
}
- return this.field(field, title, valueCol);
+ return this.field(field, title, valueCol, signal);
}
- optionField(fieldSpec) {
+ renderOptionField(fieldSpec, signal) {
let valueCol;
const {field, title} = fieldSpec;
const {options, optionValues} = fieldSpec.options;
@@ -243,24 +250,20 @@ export default class SignalLegendEntry extends Component {
value={optionValues[opt]}>{opt}
}
);
- valueCol =
;
+ onChange={
+ (e) => { this.updateField(fieldSpec, e.target.value === "true") }
+ }>
+ {optionEles}
+
+ );
} else {
valueCol =
{valueOptions[this.props.signal[field]]};
}
- return this.field(field, title, valueCol);
- }
-
- removeSignal(signal) {
- return (
- {this.props.onSignalRemove(signal)}}>Remove Signal |
-
);
+ return this.field(field, title, valueCol, signal);
}
titleForField(field, signal) {
@@ -271,14 +274,14 @@ export default class SignalLegendEntry extends Component {
}
}
- fieldNode(field, signal) {
+ renderFieldNode(field, signal) {
field.title = this.titleForField(field, signal);
if(field.type === 'number') {
- return this.numberField(field);
+ return this.renderNumberField(field, signal);
} else if(field.type === 'option') {
- return this.optionField(field);
+ return this.renderOptionField(field, signal);
} else if(field.type === 'string') {
- return this.stringField(field);
+ return this.renderStringField(field, signal);
}
}
@@ -304,8 +307,6 @@ export default class SignalLegendEntry extends Component {
this.props.onSignalChange(signalCopy, signal);
} else {
signalEdited = signalCopy;
- // Show plot when expanding
- this.props.onSignalPlotChange(true, signal.name)
}
// Expand and enable signal editing
@@ -320,57 +321,62 @@ export default class SignalLegendEntry extends Component {
}
onNameChange(e) {
- // this.updateField('name', e.target.value);
this.setState({nameEdited: e.target.value})
}
- expandedSignal(signal) {
+ renderSignalForm(signal) {
const startBitTitle = signal.isLittleEndian ? 'Least significant bit' : 'Most significant bit';
return (
-
-
-
-
-
- {SignalLegendEntry.fields.map((field) => this.fieldNode(field, signal))}
- {this.removeSignal(signal)}
-
-
- |
-
-
+
+ {SignalLegendEntry.fields.map((field) => {
+ return (
+
+ {this.renderFieldNode(field, signal.name)}
+
+ )
+ })}
+
+
+
+
);
}
+ toggleSignalPlot(e) {
+ const {signal, isPlotted} = this.props;
+ e.preventDefault();
+ this.props.onSignalPlotChange(!isPlotted, signal.name);
+ }
+
render() {
const {isExpanded, isEditing, signalEdited, nameEdited} = this.state;
const {signal, highlightedStyle, plottedSignals, isPlotted} = this.props;
+ const expandedEntryClass = this.props.isExpanded ? 'is-expanded' : null;
+ const plottedButtonClass = this.props.isPlotted ? 'button' : 'button--alpha';
+ const plottedButtonText = this.props.isPlotted ? 'Hide Plot' : 'Show Plot';
return (
this.props.onSignalHover(signal)}
- onMouseLeave={() => this.props.onSignalHoverEnd(signal)}>
-
-
-
{this.props.isExpanded ? '\u2193' : '\u2192'}
-
{signal.name}
+ className={cx('signals-legend-entry', expandedEntryClass)}
+ onMouseEnter={() => this.props.onSignalHover(signal)}
+ onMouseLeave={() => this.props.onSignalHoverEnd(signal)}>
+
+
+ {signal.name}
+
+
+
+
-
-
Plot:
-
e.stopPropagation()}
- onChange={(e) => {
- this.props.onSignalPlotChange(e.target.checked, signal.name)
- }}
- />
+
+ {this.props.isExpanded ? this.renderSignalForm(signal) : null}
-
-
- {this.props.isExpanded ? this.expandedSignal(signal) : null}
-
);
}
diff --git a/src/components/SignalLog/signalLog.scss b/src/components/SignalLog/signalLog.scss
index 76d8498..98fe15d 100644
--- a/src/components/SignalLog/signalLog.scss
+++ b/src/components/SignalLog/signalLog.scss
@@ -6,4 +6,91 @@
*/
-@import '../../styles/_global/index';
+@import '../../styles/_global/all';
+
+.signals-log-list {
+ color: $color-grey-80;
+ font-size: 14px;
+ &-time {
+ flex: 1;
+ }
+ &-message {
+ flex: 3;
+ }
+ &-bytes {
+ flex: 2;
+ }
+ &-header {
+ border-bottom: 1px solid rgba(0,0,0,.1);
+ display: flex;
+ font-size: 11px;
+ padding: 2% 3% 2% 7%;
+ text-transform: uppercase;
+ }
+ &-item {
+ border-color: transparent;
+ border-style: solid;
+ border-width: 1px 0;
+ padding-right: 3%;
+ position: relative;
+ transition-duration: .1s;
+ &:not(.is-expanded):hover {
+ background: rgba(0,0,0,.02);
+ }
+ &:not(.is-expanded):active {
+ padding-top: 0.5%;
+ padding-bottom: 0.5%;
+ }
+ &.has-signals {
+ &:before {
+ color: $color-grey-80;
+ content: $fa-var-chevron-right;
+ display: block;
+ font-family: 'FontAwesome';
+ font-size: 8px;
+ line-height: 26px;
+ text-align: center;
+ pointer-events: none;
+ position: absolute;
+ transition-duration: .1s;
+ width: 8%;
+ }
+ }
+ &.is-expanded {
+ background: rgba(0,0,0,.03);
+ border-color: rgba(0,0,0,.05);
+ padding-top: 1%;
+ &:before {
+ margin-top: -3px;
+ transform: rotate(90deg);
+ }
+ }
+ &-header {
+ cursor: pointer;
+ display: flex;
+ padding: 1% 0 1% 7%;
+ }
+ }
+ &-signals {}
+ &-signal {
+ align-items: center;
+ border-top: 1px solid rgba(0,0,0,.05);
+ display: flex;
+ font-size: 12px;
+ padding: 1% 0 1% 7%;
+ &-message {
+ flex: 3;
+ }
+ &-value {
+ flex: 1;
+
+ }
+ &-action {
+ flex: 1;
+ button {
+ font-size: 10px;
+ width: 100%
+ }
+ }
+ }
+}
diff --git a/src/components/explorer.js b/src/components/explorer.js
index 64f2b29..cdbe6b3 100644
--- a/src/components/explorer.js
+++ b/src/components/explorer.js
@@ -2,6 +2,7 @@ import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { StyleSheet, css } from 'aphrodite/no-important';
+import Moment from 'moment';
import AddSignals from './AddSignals';
import CanHistogram from './CanHistogram';
@@ -13,6 +14,7 @@ import Entries from '../models/can/entries';
import debounce from '../utils/debounce';
import CommonStyles from '../styles/styles';
import Images from '../styles/images';
+import PartSelector from './PartSelector';
export default class Explorer extends Component {
static propTypes = {
@@ -24,6 +26,8 @@ export default class Explorer extends Component {
firstCanTime: PropTypes.number,
onSeek: PropTypes.func,
autoplay: PropTypes.bool,
+ onPartChanged: PropTypes.func,
+ partsCount: PropTypes.number,
};
constructor(props) {
@@ -191,6 +195,19 @@ export default class Explorer extends Component {
}
}
+ timeWindow() {
+ const {route, currentParts} = this.props;
+ if(route) {
+ const partStartOffset = currentParts[0] * 60,
+ partEndOffset = (currentParts[1] + 1) * 60;
+
+ const windowStartTime = Moment(route.start_time).add(partStartOffset, 's').format('HH:mm:ss');
+ const windowEndTime = Moment(route.start_time).add(partEndOffset, 's').format('HH:mm:ss');
+
+ return `${windowStartTime} - ${windowEndTime}`;
+ } else return '';
+ }
+
calcGraphData(msg, signalName) {
if(!msg) return null;
@@ -426,33 +443,46 @@ export default class Explorer extends Component {
}
renderExplorerSignals() {
+ const selectedMessageKey = this.props.selectedMessage;
+ const selectedMessage = this.props.messages[selectedMessageKey];
+ const selectedMessageName = selectedMessage.frame !== undefined ? selectedMessage.frame.name : 'undefined';
return (
-
+
-
Edit Signals
+ className='cabana-explorer-signals-header'
+ onClick={this.toggleEditSignals}>
+
+
Selected Message:
+ {selectedMessageName}
+
+
+
+
+
+
+ {this.state.shouldShowAddSignal ?
+
{this.setState({shouldShowAddSignal: false})}}
+ messageIndex={this.props.seekIndex}
+ onSignalPlotChange={this.onSignalPlotChanged}
+ plottedSignals={this.state.plottedSignals.filter(
+ ({messageId, signalName}) => messageId === this.props.selectedMessage
+ ).map(({messageId, signalName}) => signalName)
+ }
+ /> : null}
+
- {this.state.shouldShowAddSignal ?
-
{this.setState({shouldShowAddSignal: false})}}
- messageIndex={this.props.seekIndex}
- onSignalPlotChange={this.onSignalPlotChanged}
- plottedSignals={this.state.plottedSignals.filter(
- ({messageId, signalName}) => messageId === this.props.selectedMessage
- ).map(({messageId, signalName}) => signalName)
- }
- /> : null}
-
)
}
@@ -464,7 +494,7 @@ export default class Explorer extends Component {
{this.onSignalUnplotPressed(messageId, signalName)}}
messageId={messageId}
- messageName={msg.frame ? msg.frame.name : null}
+ message={msg.frame ? msg.frame.name : null}
signalSpec={Object.assign(Object.create(msg.signals[signalName]), msg.signals[signalName])}
onSegmentChanged={this.onSegmentChanged}
segment={this.state.segment}
@@ -483,6 +513,13 @@ export default class Explorer extends Component {
: this.selectMessagePrompt()}
+
+ {this.timeWindow()}
+
+
nextMsgKeys.indexOf(m) !== -1);
- this.setState({selectedMessages, hoveredMessages: []});
+ this.setState({hoveredMessages: []});
}
}
@@ -123,10 +120,6 @@ export default class Meta extends Component {
this.setState({hoveredMessages});
}
- onMsgEditClick(key) {
- this.props.showEditMessageModal(key);
- }
-
onMsgRemoveClick(key) {
let {selectedMessages} = this.state;
selectedMessages = selectedMessages.filter((m) => m != key);
@@ -134,50 +127,12 @@ export default class Meta extends Component {
this.setState({selectedMessages});
}
- hoverButtons(key) {
- return ([ this.onMsgEditClick(key)}>
-
Edit
-
,
- this.onMsgRemoveClick(key)}>
-
Remove
-
]);
- }
-
- selectedMessagesList() {
- const {selectedMessages, hoveredMessages} = this.state;
- if(selectedMessages.length === 0) return null;
-
- const messages = selectedMessages
- .sort()
- .map((key) => {
- const msg = this.props.messages[key];
- return this.onMessageHover(key)}
- onMouseLeave={() => this.onMessageHoverEnd(key)}>
- {msg.frame ? msg.frame.name : ''} {key}
- {hoveredMessages.indexOf(key) !== -1 ? this.hoverButtons(key): null}
-
- });
- return ();
- }
-
onMessageSelected(key) {
// uncomment when we support multiple messages
// const selectedMessages = this.state.selectedMessages.filter((m) => m != key);
const selectedMessages = [];
selectedMessages.push(key);
- this.setState({selectedMessages});
+ this.props.updateSelectedMessages(selectedMessages);
this.props.onMessageSelected(key);
}
@@ -223,75 +178,45 @@ export default class Meta extends Component {
}
selectedMessageClass(messageId) {
- return (this.state.selectedMessages.includes(messageId) ? Styles.messageIsSelected : null);
+ return (this.props.selectedMessages.includes(messageId) ? 'is-selected' : null);
}
- availableMessagesList() {
+ renderAvailableMessagesList() {
if(Object.keys(this.props.messages).length === 0) {
- return null;
+ return Loading messages...
;
}
-
- const defaultTextVisible = this.state.filterText.trim() === 'Filter';
-
- return (
-
-
Available Messages
-
-
- {this.state.filterText.trim().length > 0 && this.state.filterText !== 'Filter' ?
- this.setState({filterText: 'Filter'})} />
- : null}
-
-
-
-
- |
- |
- Signals |
- Count |
- Bytes |
-
-
-
- {this.orderedMessages()
- .map((msg) => {
- return {this.onMessageSelected(msg.id)}}
- key={msg.id}
- className={css(Styles.message, this.selectedMessageClass(msg.id))}>
- {msg.frame ? msg.frame.name : ''} |
- {msg.id} |
- {Object.keys(msg.signals).length} |
- {msg.entries.length} |
-
-
- |
-
- })}
-
-
-
);
- }
-
- timeWindow() {
- const {route, currentParts} = this.props;
- if(route) {
- const partStartOffset = currentParts[0] * 60,
- partEndOffset = (currentParts[1] + 1) * 60;
-
- const windowStartTime = Moment(route.start_time).add(partStartOffset, 's').format('HH:mm:ss');
- const windowEndTime = Moment(route.start_time).add(partEndOffset, 's').format('HH:mm:ss');
-
- return `${windowStartTime} - ${windowEndTime}`;
- } else return '';
+ return (
+
+
+
+ Name |
+ ID |
+ Count |
+ Bytes |
+
+
+
+ {this.orderedMessages()
+ .map((msg) => {
+ return (
+ {this.onMessageSelected(msg.id)}}
+ key={msg.id}
+ className={cx('cabana-meta-messages-list-item', this.selectedMessageClass(msg.id))}>
+ {msg.frame ? msg.frame.name : 'undefined'} |
+ {msg.id} |
+ {msg.entries.length} |
+
+
+ |
+
+ )
+ })}
+
+
+ );
}
shareUrl() {
@@ -303,182 +228,53 @@ export default class Meta extends Component {
}
render() {
return (
-
- {this.props.isDemo ?
-
: null}
-
-
-
- comma cabana
-
-
-
- {this.props.githubAuthToken ?
-
GitHub Authenticated
- :
- this.props.loginWithGithub
- }
-
-
-
Load DBC
- /
-
Save DBC
- {this.props.dbcLastSaved !== null ?
+
+
+
Currently editing:
+
{this.props.dbcFilename}
+ {this.props.dbcLastSaved !== null ?
+
Last saved: {this.lastSavedPretty()}
- : null
- }
- {this.props.dbcFilename ?
Editing: {this.props.dbcFilename}
: null}
-
ref ? new Clipboard(ref) : null}>
- e.preventDefault()}>Copy share link
+
+ : null
+ }
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+ {this.renderAvailableMessagesList()}
+
-
- {this.selectedMessagesList()}
- {this.availableMessagesList()}
);
}
}
-
-const Styles = StyleSheet.create({
- chffrPanda: {
- minWidth: 450,
- width: '100%',
- flexDirection: 'row',
- display: 'flex',
- alignItems: 'center',
- borderBottom: '1px solid rgba(0,0,0,0.8)',
- borderRight: '1px solid rgba(0,0,0,0.8)',
- backgroundColor: 'white',
- padding: 10
- },
- chffrPandaDesc: {
- textAlign: 'center',
- justifyContent: 'center',
- alignItems: 'center',
- paddingLeft: 10
- },
- chffrPandaGet: {
- display: 'block',
- fontWeight: 'bold',
- textDecoration: 'none',
- ':hover': {
- textDecoration: 'underline'
- },
- color: 'rgba(0,0,0,0.8)'
- },
- panda: {
- width: 150,
- height: 138
- },
- scrollContainer: {
- display: 'block',
- height: '100%',
- overflowY: 'scroll',
- overflowX: 'hidden',
- padding: 10,
- },
- githubAuth: {
- marginTop: 10,
- marginBottom: 10
- },
- titleText: {
- fontFamily: 'monospace',
- paddingRight: 10,
- fontSize: 24
- },
- routeMeta: {
- borderBottomWidth: '1px',
- borderColor: 'grey',
- '*': {
- display: 'inline-block'
- }
- },
- message: {
- cursor: 'pointer',
- ':hover' : {
- backgroundColor: 'rgba(0,0,0,0.1)'
- },
- marginTop: 5,
- fontSize: 12,
- },
- selectedMessage: {
- display: 'flex',
- flexDirection: 'row'
- },
- messageIsSelected: {
- backgroundColor: 'blue',
- color: 'rgb(233, 233, 233)',
- fontWeight: 'bold'
- },
- messageList: {
- margin: 0,
- padding: 0
- },
- loadDbc: {
- cursor: 'pointer',
- ':hover': {
- textDecoration: 'underline'
- },
- display: 'inline',
- fontWeight: 'bold'
- },
- timeWindow: {
- marginTop: 10,
- marginBottom: 10,
- },
- hoverButton: {
- height: 15,
- padding: 8,
- borderRadius: 4,
- justifyContent: 'center',
- alignItems: 'center',
- display: 'flex',
- marginLeft: 15
- },
- editButton: {
- backgroundColor: 'RGBA(105, 69, 33, 1.00)',
- color: 'RGBA(251, 253, 242, 1.00)'
- },
- removeButton: {
- backgroundColor: 'RGBA(255, 34, 59, 0.83)',
- color: 'RGBA(251, 253, 242, 1.00)'
- },
- defaultFilterText: {
- color: 'rgb(205,205,205)'
- },
- filter: {
- display: 'flex',
- flexDirection: 'row',
- height: 24
- },
- messagesList: {
- marginTop: 10
- },
- messageHeader: {
- fontSize: 12
- },
- copyShareLink: {
- color: 'black'
- }
-});
diff --git a/src/fonts/FontAwesome.otf b/src/fonts/FontAwesome.otf
new file mode 100644
index 0000000..401ec0f
Binary files /dev/null and b/src/fonts/FontAwesome.otf differ
diff --git a/src/fonts/fontawesome-webfont.eot b/src/fonts/fontawesome-webfont.eot
new file mode 100644
index 0000000..e9f60ca
Binary files /dev/null and b/src/fonts/fontawesome-webfont.eot differ
diff --git a/src/fonts/fontawesome-webfont.svg b/src/fonts/fontawesome-webfont.svg
new file mode 100644
index 0000000..855c845
--- /dev/null
+++ b/src/fonts/fontawesome-webfont.svg
@@ -0,0 +1,2671 @@
+
+
+
diff --git a/src/fonts/fontawesome-webfont.ttf b/src/fonts/fontawesome-webfont.ttf
new file mode 100644
index 0000000..35acda2
Binary files /dev/null and b/src/fonts/fontawesome-webfont.ttf differ
diff --git a/src/fonts/fontawesome-webfont.woff b/src/fonts/fontawesome-webfont.woff
new file mode 100644
index 0000000..400014a
Binary files /dev/null and b/src/fonts/fontawesome-webfont.woff differ
diff --git a/src/fonts/fontawesome-webfont.woff2 b/src/fonts/fontawesome-webfont.woff2
new file mode 100644
index 0000000..4d13fc6
Binary files /dev/null and b/src/fonts/fontawesome-webfont.woff2 differ
diff --git a/src/index.css b/src/index.css
deleted file mode 100644
index 58add0d..0000000
--- a/src/index.css
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
-
- Comma Cabana Styles
- ~~~~~~~~~~~~~~~~~~~
-
-*/
-html, body {
- min-width: 1340px;
- margin: 0;
- padding: 0;
- height: 100%;
- width: 100%;
- font-family: sans-serif; }
-
-p {
- margin: 0;
- padding: 0; }
-
-#root {
- width: 100%;
- height: 100%; }
-
-* {
- box-sizing: border-box; }
-
-.g-container {
- width: 90%;
- margin-left: auto;
- margin-right: auto; }
- @media only screen and (min-width: 540px) {
- .g-container {
- width: 80%; } }
- @media only screen and (min-width: 960px) {
- .g-container {
- width: 75%; } }
-
-.g-row {
- position: relative;
- width: 100%; }
-
-.g-row::after {
- content: "";
- display: table;
- clear: both; }
-
-[class*="g-col"] {
- float: left;
- min-height: 0.125rem; }
-
-.g-col-1,
-.g-col-2,
-.g-col-3,
-.g-col-4,
-.g-col-5,
-.g-col-6,
-.g-col-7,
-.g-col-8,
-.g-col-9,
-.g-col-10,
-.g-col-11,
-.g-col-12 {
- width: 100%; }
-
-@media only screen and (min-width: 720px) {
- .g-col-1 {
- width: 8.3333333333%; }
-
- .g-col-2 {
- width: 16.6666666667%; }
-
- .g-col-3 {
- width: 25%; }
-
- .g-col-4 {
- width: 33.3333333333%; }
-
- .g-col-5 {
- width: 41.6666666667%; }
-
- .g-col-6 {
- width: 50%; }
-
- .g-col-7 {
- width: 58.3333333333%; }
-
- .g-col-8 {
- width: 66.6666666667%; }
-
- .g-col-9 {
- width: 75%; }
-
- .g-col-10 {
- width: 83.3333333333%; }
-
- .g-col-11 {
- width: 91.6666666667%; }
-
- .g-col-12 {
- width: 100%; }
-
- .hidden-sm {
- display: block; } }
-/*
-
- VG Tooltip Library
- ~~~~~~~~~~~~~~~~~~
-
-*/
-.vg-tooltip {
- visibility: hidden;
- padding: 6px;
- border-radius: 3px;
- position: fixed;
- z-index: 2000;
- font-family: sans-serif;
- font-size: 1em;
- /* The default look of the tooltip is the same as .light-theme
- but it can be overwritten by .dark-theme */
- background-color: rgba(255, 255, 255, 0.9);
- border: 1px solid #d9d9d9;
- color: black; }
-
-.vg-tooltip td.key, .vg-tooltip td.value {
- overflow: hidden;
- text-overflow: ellipsis; }
-
-.vg-tooltip td.key {
- max-width: 150px;
- text-align: right;
- padding-right: 1px;
- font-weight: bold; }
-
-.vg-tooltip td.value {
- max-width: 200px;
- text-align: left; }
-
-/* Dark and light color themes */
-.vg-tooltip.dark-theme {
- background-color: rgba(64, 64, 64, 0.9);
- color: rgba(255, 255, 255, 0.95); }
-
-/*
-
- Meta Component Styles
- ~~~~~~~~~~~~~~~~~~~~~
-
-*/
-.cabana-meta {
- background: #e5e5e5;
- flex: .5;
- flex-direction: column;
- height: 100vh;
- overflow-y: scroll; }
- .cabana-meta table {
- width: 100%; }
-
-/*
-
- Explorer Component Styles
- ~~~~~~~~~~~~~~~~~~~~~~~~~
-
-*/
-.cabana {
- display: flex; }
-
-.cabana-explorer {
- display: flex;
- flex: 1; }
- .cabana-explorer-signals {
- flex: 1;
- height: 100vh;
- overflow-x: hidden;
- overflow-y: scroll;
- padding: 3%; }
- .cabana-explorer-signals-matrix table {
- border: 1px solid rgba(0, 0, 0, 0.2);
- border-radius: 5px;
- font-family: monospace;
- margin: 2% 0;
- width: 100%; }
- .cabana-explorer-signals-log {
- background: #fafafa;
- border: 1px solid rgba(0, 0, 0, 0.2);
- border-radius: 5px;
- padding: 3%; }
- .cabana-explorer-visuals {
- flex: 1;
- height: 100vh;
- overflow-x: hidden;
- overflow-y: scroll;
- padding: 1.5%;
- padding-left: 0; }
- .cabana-explorer-visuals-camera {
- border: 5px solid #000;
- border-radius: 5px;
- max-height: 480px;
- max-width: 640px;
- overflow: hidden;
- position: relative; }
- .cabana-explorer-visuals-camera-seeker {
- background: rgba(233, 233, 233, 0.2);
- bottom: 0;
- position: absolute;
- width: 100%;
- z-index: 4; }
- .cabana-explorer-visuals-camera video {
- cursor: pointer;
- width: 100%; }
- .cabana-explorer-visuals-plots {
- border: 1px solid #d3d3d3;
- border-radius: 5px;
- margin: 3% 0; }
- .cabana-explorer-visuals-plot {
- padding: 1.5% 3%; }
- .cabana-explorer-visuals-plot:first-child, .cabana-explorer-visuals-plot:last-child {
- padding-top: 3%;
- padding-bottom: 3%; }
- .cabana-explorer-visuals-plot-message {
- color: #a2a2a2;
- font-size: 12px; }
- .cabana-explorer-visuals-plot-signal strong {
- padding-right: 5px; }
- .cabana-explorer-visuals-plot-signal a {
- color: #a2a2a2;
- cursor: pointer; }
- .cabana-explorer-visuals-plot-canvas svg {
- height: auto;
- width: 100%; }
-
-/*
-
- Signal Legend Component
- ~~~~~~~~~~~~~~~~~~~~~~~
-
-*/
-.cabana-explorer-signals-legend {
- background: #fafafa;
- border: 1px solid rgba(0, 0, 0, 0.2);
- border-radius: 5px;
- margin: 5% 0;
- padding: 2%; }
-
-.signals-legend-entry {
- overflow: auto; }
- .signals-legend-entry:not(:last-child) {
- border-bottom: 1px solid rgba(0, 0, 0, 0.05); }
- .signals-legend-entry-header {
- cursor: pointer;
- line-height: 42px; }
- .signals-legend-entry-header-name {
- float: left;
- width: 70%; }
- .signals-legend-entry-header-plotted {
- float: left;
- text-align: right;
- width: 30%; }
- .signals-legend-entry-body {
- padding: 2%; }
-
-/*
-
- ExplorerSignalLog Component Styles
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Also known as CanLog
-
-*/
-
-/*# sourceMappingURL=index.css.map */
diff --git a/src/index.scss b/src/index.scss
index 36cf8bd..da58102 100644
--- a/src/index.scss
+++ b/src/index.scss
@@ -8,9 +8,11 @@
// Globals
@import './styles/base/base';
@import './styles/base/grid';
+@import './styles/base/forms';
// Libraries
@import './styles/lib/index';
+@import './styles/lib/font-awesome';
// Components
@import './components/Meta/meta';
diff --git a/src/styles/_global/all.scss b/src/styles/_global/all.scss
new file mode 100644
index 0000000..fa0a26d
--- /dev/null
+++ b/src/styles/_global/all.scss
@@ -0,0 +1,4 @@
+// All Global Variables and Mixins
+@import 'colors';
+@import 'mixins';
+@import '../../../node_modules/font-awesome/scss/variables';
diff --git a/src/styles/_global/colors.scss b/src/styles/_global/colors.scss
index 1aa0290..52aea9c 100644
--- a/src/styles/_global/colors.scss
+++ b/src/styles/_global/colors.scss
@@ -1,5 +1,10 @@
// Cabana Color Variables
$color-grey-10: #fafafa;
-$color-grey-20: #e5e5e5;
-$color-grey-30: #d3d3d3;
+$color-grey-20: #ededed;
+$color-grey-30: #e1e1e1;
+$color-grey-40: #d4d4d4;
$color-grey-50: #a2a2a2;
+$color-grey-60: #979797;
+$color-grey-70: #6f6f6f;
+$color-grey-80: #484848;
+$color-grey-90: #2d2d2d;
diff --git a/src/styles/_global/index.scss b/src/styles/_global/index.scss
deleted file mode 100644
index 038968a..0000000
--- a/src/styles/_global/index.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-// Global Cabana Variables
-
-@import './colors';
diff --git a/src/styles/_global/mixins.scss b/src/styles/_global/mixins.scss
new file mode 100644
index 0000000..5b5531a
--- /dev/null
+++ b/src/styles/_global/mixins.scss
@@ -0,0 +1,9 @@
+// Mixins
+
+%clearfix {
+ &:after {
+ content: "";
+ display: table;
+ clear: both;
+ }
+}
diff --git a/src/styles/base/base.scss b/src/styles/base/base.scss
index bd13a88..8b5e666 100644
--- a/src/styles/base/base.scss
+++ b/src/styles/base/base.scss
@@ -2,6 +2,7 @@
html, body {
min-width: 1340px;
margin: 0;
+ overflow-x: hidden;
padding: 0;
height: 100%;
width: 100%;
diff --git a/src/styles/base/forms.scss b/src/styles/base/forms.scss
new file mode 100644
index 0000000..3a289fd
--- /dev/null
+++ b/src/styles/base/forms.scss
@@ -0,0 +1,88 @@
+/*
+
+ Base Form Elements
+ ~~~~~~~~~~~~~~~~~~
+
+*/
+
+@import '../../styles/_global/all';
+
+$input-height: 42px;
+$input-height--small: 34px;
+$input-height--tiny: 22px;
+$input-radius: 3px;
+$input-background: #fff;
+$button-background: $color-grey-50;
+$button-background--alpha: rgba(0,0,0,.02);
+
+.form-field {
+ &.form-field--small {
+ input,
+ select {
+ font-size: 12px;
+ height: $input-height--small;
+ }
+ }
+}
+
+input[type='text'],
+input[type='number'],
+select {
+ background: $input-background;
+ border: 1px solid $color-grey-50;
+ border-radius: $input-radius;
+ font-size: 14px;
+ height: $input-height;
+ outline: none;
+ padding: 0 14px;
+ width: 100%;
+ &:focus {
+ border-color: $color-grey-60;
+ }
+}
+
+input[type='button'],
+button,
+a.button {
+ background: $color-grey-50;
+ border: 1px solid $color-grey-60;
+ border-bottom-width: 3px;
+ border-radius: $input-radius;
+ color: #fff;
+ cursor: pointer;
+ display: block;
+ font-size: 14px;
+ font-weight: 600;
+ height: $input-height;
+ line-height: $input-height - 2px;
+ outline: 0;
+ padding: 0 5%;
+ text-align: center;
+ text-decoration: none;
+ text-shadow: 0 1px rgba(0,0,0,.2);
+ &:active {
+ background: $color-grey-60;
+ border-bottom-width: 1px;
+ }
+ &.button--small {
+ height: $input-height--small;
+ line-height: $input-height--small - 2px;
+ }
+ &.button--tiny {
+ height: $input-height--tiny;
+ font-size: 12px;
+ line-height: $input-height--tiny - 2px;
+ }
+ &.button--alpha {
+ background: $button-background--alpha;
+ border-color: $color-grey-30;
+ border-width: 1px;
+ color: $color-grey-70;
+ text-shadow: none;
+ }
+ &.button--inverted {
+ background: transparent;
+ border-width: 1px;
+ color: $button-background;
+ }
+}
diff --git a/src/styles/lib/font-awesome.scss b/src/styles/lib/font-awesome.scss
new file mode 100644
index 0000000..165649f
--- /dev/null
+++ b/src/styles/lib/font-awesome.scss
@@ -0,0 +1,9 @@
+/*
+
+ Font Awesome Icons
+ ~~~~~~~~~~~~~~~~~~
+
+*/
+
+$fa-font-path: './fonts';
+@import '../../../node_modules/font-awesome/scss/font-awesome';