Add eslint with explorer configuration (#26)

* Add eslint and run --fix

* Remove precommit prettier
main
Chris Vickery 2019-10-07 16:11:53 -07:00 committed by GitHub
parent 8bcda7c579
commit 1be5544df3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 2277 additions and 2214 deletions

5
.eslintignore 100644
View File

@ -0,0 +1,5 @@
node_modules/
public/
build/
.storybook
src/registerServiceWorker.js

18
.eslintrc 100644
View File

@ -0,0 +1,18 @@
{
"parser": "babel-eslint",
"extends": [
"airbnb"
],
"rules": {
"import/prefer-default-export": 0,
"import/no-named-as-default": 0,
"comma-dangle": 0,
"react/jsx-filename-extension": 0, // .jsx should be better? But git diff will be crazy
"react/forbid-prop-types": 0, // Too time consuming to map out types for now
"react/require-default-props": 0,
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }]
},
"env": {
"browser": true
}
}

View File

@ -1,12 +0,0 @@
{
"extends": "react-app",
"rules": {
"no-undef": 1
},
"env": {
"browser": true
},
"globals": {
"window": false
}
}

View File

@ -1,25 +1,25 @@
const WorkerLoaderPlugin = require("craco-worker-loader"); const WorkerLoaderPlugin = require('craco-worker-loader');
const SentryPlugin = require("craco-sentry-plugin"); const SentryPlugin = require('craco-sentry-plugin');
module.exports = function({ env }) { module.exports = function ({ env }) {
var plugins = [ const plugins = [
{ {
plugin: WorkerLoaderPlugin plugin: WorkerLoaderPlugin
} }
]; ];
if (env === "production") { if (env === 'production') {
// plugins.push({ // plugins.push({
// plugin: SentryPlugin // plugin: SentryPlugin
// }); // });
} }
return { return {
plugins: plugins, plugins,
webpack: { webpack: {
configure: (webpackConfig, { env, paths }) => { configure: (webpackConfig, { env, paths }) => {
webpackConfig.output.globalObject = "this"; webpackConfig.output.globalObject = 'this';
webpackConfig.optimization.minimizer = webpackConfig.optimization.minimizer.map( webpackConfig.optimization.minimizer = webpackConfig.optimization.minimizer.map(
function(plugin) { (plugin) => {
if (plugin.constructor.name !== "TerserPlugin") { if (plugin.constructor.name !== 'TerserPlugin') {
return plugin; return plugin;
} }
plugin.options.terserOptions.keep_fnames = true; plugin.options.terserOptions.keep_fnames = true;

View File

@ -11,6 +11,7 @@
"@craco/craco": "^5.5.0", "@craco/craco": "^5.5.0",
"ap": "^0.2.0", "ap": "^0.2.0",
"aphrodite": "^1.2.1", "aphrodite": "^1.2.1",
"babel-eslint": "^10.0.3",
"base64-inline-loader": "^1.1.0", "base64-inline-loader": "^1.1.0",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"clipboard": "^1.7.1", "clipboard": "^1.7.1",
@ -22,6 +23,12 @@
"emotion": "^8.0.12", "emotion": "^8.0.12",
"enzyme": "^3.2.0", "enzyme": "^3.2.0",
"enzyme-adapter-react-16": "^1.1.0", "enzyme-adapter-react-16": "^1.1.0",
"eslint": "^6.5.1",
"eslint-config-airbnb": "^18.0.1",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.16.0",
"eslint-plugin-react-hooks": "^2.1.2",
"file-saver": "^1.3.3", "file-saver": "^1.3.3",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
"github-api": "^3.0.0", "github-api": "^3.0.0",
@ -86,11 +93,10 @@
"test-ci": "CI=true craco test --env=jsdom", "test-ci": "CI=true craco test --env=jsdom",
"netlify-sass": "node-sass src/index.scss > src/index.css", "netlify-sass": "node-sass src/index.scss > src/index.css",
"sass": "node-sass src/index.scss -o src && node-sass -w src/index.scss -o src", "sass": "node-sass src/index.scss -o src && node-sass -w src/index.scss -o src",
"precommit": "lint-staged",
"deploy": "npm run build && gh-pages -d build" "deploy": "npm run build && gh-pages -d build"
}, },
"lint-staged": { "lint-staged": {
"*.{js,jsx}": ["prettier --parser flow --write", "git add"], "*.{js,jsx}": ["eslint --fix", "git add"],
"*.json": ["prettier --parser json --write", "git add"], "*.json": ["prettier --parser json --write", "git add"],
"*.{graphql,gql}": ["prettier --parser graphql --write", "git add"], "*.{graphql,gql}": ["prettier --parser graphql --write", "git add"],
"*.{md,markdown}": ["prettier --parser markdown --write", "git add"], "*.{md,markdown}": ["prettier --parser markdown --write", "git add"],

View File

@ -1,43 +1,43 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import Moment from "moment"; import Moment from 'moment';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import cx from "classnames"; import cx from 'classnames';
import { createWriteStream } from "streamsaver"; import { createWriteStream } from 'streamsaver';
import Panda from "@commaai/pandajs"; import Panda from '@commaai/pandajs';
import CommaAuth from "@commaai/my-comma-auth"; import CommaAuth from '@commaai/my-comma-auth';
import { raw as RawDataApi, drives as DrivesApi } from "@commaai/comma-api"; import { raw as RawDataApi, drives as DrivesApi } from '@commaai/comma-api';
import { import {
USE_UNLOGGER, USE_UNLOGGER,
PART_SEGMENT_LENGTH, PART_SEGMENT_LENGTH,
STREAMING_WINDOW, STREAMING_WINDOW,
GITHUB_AUTH_TOKEN_KEY GITHUB_AUTH_TOKEN_KEY
} from "./config"; } from './config';
import * as GithubAuth from "./api/github-auth"; import * as GithubAuth from './api/github-auth';
import DBC from "./models/can/dbc"; import DBC from './models/can/dbc';
import Meta from "./components/Meta"; import Meta from './components/Meta';
import Explorer from "./components/Explorer"; import Explorer from './components/Explorer';
import OnboardingModal from "./components/Modals/OnboardingModal"; import OnboardingModal from './components/Modals/OnboardingModal';
import SaveDbcModal from "./components/SaveDbcModal"; import SaveDbcModal from './components/SaveDbcModal';
import LoadDbcModal from "./components/LoadDbcModal"; import LoadDbcModal from './components/LoadDbcModal';
import debounce from "./utils/debounce"; import debounce from './utils/debounce';
import EditMessageModal from "./components/EditMessageModal"; import EditMessageModal from './components/EditMessageModal';
import LoadingBar from "./components/LoadingBar"; import LoadingBar from './components/LoadingBar';
import { import {
persistDbc, persistDbc,
fetchPersistedDbc, fetchPersistedDbc,
unpersistGithubAuthToken unpersistGithubAuthToken
} from "./api/localstorage"; } from './api/localstorage';
import OpenDbc from "./api/OpenDbc"; import OpenDbc from './api/OpenDbc';
import UnloggerClient from "./api/unlogger"; import UnloggerClient from './api/unlogger';
import * as ObjectUtils from "./utils/object"; import * as ObjectUtils from './utils/object';
import { hash } from "./utils/string"; import { hash } from './utils/string';
import { modifyQueryParameters } from "./utils/url"; import { modifyQueryParameters } from './utils/url';
const RLogDownloader = require("./workers/rlog-downloader.worker.js"); const RLogDownloader = require('./workers/rlog-downloader.worker.js');
const LogCSVDownloader = require("./workers/dbc-csv-downloader.worker.js"); const LogCSVDownloader = require('./workers/dbc-csv-downloader.worker.js');
const MessageParser = require("./workers/message-parser.worker.js"); const MessageParser = require('./workers/message-parser.worker.js');
const CanStreamerWorker = require("./workers/CanStreamerWorker.worker.js"); const CanStreamerWorker = require('./workers/CanStreamerWorker.worker.js');
export default class CanExplorer extends Component { export default class CanExplorer extends Component {
static propTypes = { static propTypes = {
@ -73,7 +73,7 @@ export default class CanExplorer extends Component {
editMessageModalMessage: null, editMessageModalMessage: null,
dbc: props.dbc ? props.dbc : new DBC(), dbc: props.dbc ? props.dbc : new DBC(),
dbcText: props.dbc ? props.dbc.text() : new DBC().text(), dbcText: props.dbc ? props.dbc.text() : new DBC().text(),
dbcFilename: props.dbcFilename ? props.dbcFilename : "New_DBC", dbcFilename: props.dbcFilename ? props.dbcFilename : 'New_DBC',
dbcLastSaved: null, dbcLastSaved: null,
seekTime: 0, seekTime: 0,
seekIndex: 0, seekIndex: 0,
@ -135,19 +135,19 @@ export default class CanExplorer extends Component {
if (CommaAuth.isAuthenticated() && !name) { if (CommaAuth.isAuthenticated() && !name) {
this.showOnboarding(); this.showOnboarding();
} else if ( } else if (
this.props.max && this.props.max
this.props.url && && this.props.url
!this.props.exp && && !this.props.exp
!this.props.sig && !this.props.sig
) { ) {
// probably the demo! // probably the demo!
const { max, url } = this.props; const { max, url } = this.props;
const startTime = Moment(name, "YYYY-MM-DD--H-m-s"); const startTime = Moment(name, 'YYYY-MM-DD--H-m-s');
const route = { const route = {
fullname: dongleId + "|" + name, fullname: `${dongleId}|${name}`,
proclog: max, proclog: max,
url: url, url,
start_time: startTime start_time: startTime
}; };
this.setState( this.setState(
@ -158,15 +158,14 @@ export default class CanExplorer extends Component {
this.initCanData this.initCanData
); );
} else if (dongleId && name) { } else if (dongleId && name) {
const routeName = dongleId + "|" + name; const routeName = `${dongleId}|${name}`;
let urlPromise, logUrlsPromise; let urlPromise;
let logUrlsPromise;
if (this.props.url) { if (this.props.url) {
urlPromise = Promise.resolve(this.props.url); urlPromise = Promise.resolve(this.props.url);
} else { } else {
urlPromise = DrivesApi.getRouteInfo(routeName).then(function(route) { urlPromise = DrivesApi.getRouteInfo(routeName).then((route) => route.url);
return route.url;
});
} }
if (this.props.sig && this.props.exp) { if (this.props.sig && this.props.exp) {
@ -178,13 +177,13 @@ export default class CanExplorer extends Component {
logUrlsPromise = RawDataApi.getLogUrls(routeName); logUrlsPromise = RawDataApi.getLogUrls(routeName);
} }
Promise.all([urlPromise, logUrlsPromise]) Promise.all([urlPromise, logUrlsPromise])
.then(initData => { .then((initData) => {
let [url, logUrls] = initData; const [url, logUrls] = initData;
const newState = { const newState = {
route: { route: {
fullname: routeName, fullname: routeName,
proclog: logUrls.length - 1, proclog: logUrls.length - 1,
start_time: Moment(name, "YYYY-MM-DD--H-m-s"), start_time: Moment(name, 'YYYY-MM-DD--H-m-s'),
url url
}, },
currentParts: [ currentParts: [
@ -195,21 +194,19 @@ export default class CanExplorer extends Component {
}; };
this.setState(newState, this.initCanData); this.setState(newState, this.initCanData);
DrivesApi.getShareSignature(routeName).then(shareSignature => DrivesApi.getShareSignature(routeName).then((shareSignature) => this.setState({
this.setState({ shareUrl: modifyQueryParameters({
shareUrl: modifyQueryParameters({ add: {
add: { exp: shareSignature.exp,
exp: shareSignature.exp, sig: shareSignature.sig,
sig: shareSignature.sig, max: logUrls.length - 1,
max: logUrls.length - 1, url
url },
}, remove: [GITHUB_AUTH_TOKEN_KEY]
remove: [GITHUB_AUTH_TOKEN_KEY]
})
}) })
); }));
}) })
.catch(err => { .catch((err) => {
console.error(err); console.error(err);
this.showOnboarding(); this.showOnboarding();
}); });
@ -245,7 +242,12 @@ export default class CanExplorer extends Component {
} }
); );
} else { } else {
this.setState({ dbc, dbcFilename, dbcText: dbc.text(), messages: {} }); this.setState({
dbc,
dbcFilename,
dbcText: dbc.text(),
messages: {}
});
} }
} }
@ -262,10 +264,10 @@ export default class CanExplorer extends Component {
// } // }
downloadLogAsCSV() { downloadLogAsCSV() {
console.log("downloadLogAsCSV:start"); console.log('downloadLogAsCSV:start');
const { dbcFilename } = this.state; const { dbcFilename } = this.state;
const fileStream = createWriteStream( const fileStream = createWriteStream(
`${dbcFilename.replace(/\.dbc/g, "-")}${+new Date()}.csv` `${dbcFilename.replace(/\.dbc/g, '-')}${+new Date()}.csv`
); );
const writer = fileStream.getWriter(); const writer = fileStream.getWriter();
const encoder = new TextEncoder(); const encoder = new TextEncoder();
@ -278,15 +280,16 @@ export default class CanExplorer extends Component {
function dataHandler(e) { function dataHandler(e) {
const { logData, shouldClose, progress } = e.data; const { logData, shouldClose, progress } = e.data;
if (shouldClose) { if (shouldClose) {
console.log("downloadLogAsCSV:close"); console.log('downloadLogAsCSV:close');
writer.close(); writer.close();
return; return;
} }
console.log("CSV export progress:", progress); console.log('CSV export progress:', progress);
const uint8array = encoder.encode(logData + "\n"); const uint8array = encoder.encode(`${logData}\n`);
writer.write(uint8array); writer.write(uint8array);
} }
} }
downloadRawLogAsCSV(handler) { downloadRawLogAsCSV(handler) {
return this.downloadLiveLogAsCSV(handler); return this.downloadLiveLogAsCSV(handler);
} }
@ -301,8 +304,8 @@ export default class CanExplorer extends Component {
worker.onmessage = handler; worker.onmessage = handler;
worker.postMessage({ worker.postMessage({
data: Object.keys(this.state.messages).map(sourceId => { data: Object.keys(this.state.messages).map((sourceId) => {
var source = this.state.messages[sourceId]; const source = this.state.messages[sourceId];
return { return {
id: source.id, id: source.id,
bus: source.bus, bus: source.bus,
@ -321,16 +324,16 @@ export default class CanExplorer extends Component {
options = options || {}; options = options || {};
const messages = { ...this.state.messages }; const messages = { ...this.state.messages };
for (var key in newMessages) { for (const key in newMessages) {
// add message // add message
if (options.replace !== true && key in messages) { if (options.replace !== true && key in messages) {
// should merge here instead of concat // should merge here instead of concat
// assumes messages are always sequential // assumes messages are always sequential
let msgEntries = messages[key].entries; const msgEntries = messages[key].entries;
let newMsgEntries = newMessages[key].entries; const newMsgEntries = newMessages[key].entries;
let msgLength = msgEntries.length; const msgLength = msgEntries.length;
let newMsgLength = newMsgEntries.length; const newMsgLength = newMsgEntries.length;
let entryLength = msgLength + newMsgLength; const entryLength = msgLength + newMsgLength;
messages[key].entries = Array(entryLength); messages[key].entries = Array(entryLength);
let msgIndex = 0; let msgIndex = 0;
@ -351,8 +354,7 @@ export default class CanExplorer extends Component {
messages[key].entries[i] = newMsgEntries[newMsgIndex++]; messages[key].entries[i] = newMsgEntries[newMsgIndex++];
} }
} }
messages[key].byteStateChangeCounts = messages[key].byteStateChangeCounts = newMessages[key].byteStateChangeCounts;
newMessages[key].byteStateChangeCounts;
} else { } else {
messages[key] = newMessages[key]; messages[key] = newMessages[key];
messages[key].frame = this.state.dbc.getMessageFrame( messages[key].frame = this.state.dbc.getMessageFrame(
@ -365,15 +367,15 @@ export default class CanExplorer extends Component {
} }
cancelWorker(workerHash) { cancelWorker(workerHash) {
let currentWorkers = { ...this.state.currentWorkers }; const currentWorkers = { ...this.state.currentWorkers };
let { worker, part } = currentWorkers[workerHash]; const { worker, part } = currentWorkers[workerHash];
let loadingParts = this.state.loadingParts.filter(p => p !== part); const loadingParts = this.state.loadingParts.filter((p) => p !== part);
let loadedParts = this.state.loadedParts.filter(p => p !== part); const loadedParts = this.state.loadedParts.filter((p) => p !== part);
delete currentWorkers[workerHash]; delete currentWorkers[workerHash];
console.log("Stoping worker", workerHash, "for part", part); console.log('Stoping worker', workerHash, 'for part', part);
worker.postMessage({ worker.postMessage({
action: "terminate" action: 'terminate'
}); });
this.setState({ this.setState({
@ -385,16 +387,16 @@ export default class CanExplorer extends Component {
spawnWorker(options) { spawnWorker(options) {
let { currentParts, currentWorkers } = this.state; let { currentParts, currentWorkers } = this.state;
console.log("Checking worker for", currentParts); console.log('Checking worker for', currentParts);
if (!this.state.isLoading) { if (!this.state.isLoading) {
this.setState({ isLoading: true }); this.setState({ isLoading: true });
} }
const [minPart, maxPart] = currentParts; const [minPart, maxPart] = currentParts;
// cancel old workers that are still loading data no longer inside the window // cancel old workers that are still loading data no longer inside the window
Object.keys(currentWorkers).forEach(workerHash => { Object.keys(currentWorkers).forEach((workerHash) => {
if ( if (
currentWorkers[workerHash].part < minPart || currentWorkers[workerHash].part < minPart
currentWorkers[workerHash].part > maxPart || currentWorkers[workerHash].part > maxPart
) { ) {
this.cancelWorker(workerHash); this.cancelWorker(workerHash);
} }
@ -406,12 +408,12 @@ export default class CanExplorer extends Component {
// clean this up just in case, the cancel process above *should* have already done this // clean this up just in case, the cancel process above *should* have already done this
// they have at most 4 entries so it's trivial // they have at most 4 entries so it's trivial
loadingParts = loadingParts.filter(p => p >= minPart && p <= maxPart); loadingParts = loadingParts.filter((p) => p >= minPart && p <= maxPart);
loadedParts = loadedParts.filter(p => p >= minPart && p <= maxPart); loadedParts = loadedParts.filter((p) => p >= minPart && p <= maxPart);
let part = -1; let part = -1;
let allWorkerParts = Object.keys(currentWorkers).map( const allWorkerParts = Object.keys(currentWorkers).map(
i => currentWorkers[i].part (i) => currentWorkers[i].part
); );
for (let partOffset = 0; partOffset <= maxPart - minPart; ++partOffset) { for (let partOffset = 0; partOffset <= maxPart - minPart; ++partOffset) {
@ -425,15 +427,15 @@ export default class CanExplorer extends Component {
} }
} }
if (part === -1) { if (part === -1) {
console.log("Loading complete"); console.log('Loading complete');
this.setState({ isLoading: false }); this.setState({ isLoading: false });
return; return;
} }
console.log("Starting worker for part", part); console.log('Starting worker for part', part);
// options is object of {part, prevMsgEntries, spawnWorkerHash, prepend} // options is object of {part, prevMsgEntries, spawnWorkerHash, prepend}
options = options || {}; options = options || {};
let prevMsgEntries = options.prevMsgEntries; let { prevMsgEntries } = options;
let prepend = false; const prepend = false;
const { const {
dbc, dbc,
@ -446,19 +448,19 @@ export default class CanExplorer extends Component {
if (!prevMsgEntries) { if (!prevMsgEntries) {
// we have previous messages loaded // we have previous messages loaded
let { messages } = this.state; const { messages } = this.state;
let canStartTime = firstCanTime - canFrameOffset; const canStartTime = firstCanTime - canFrameOffset;
prevMsgEntries = {}; prevMsgEntries = {};
Object.keys(messages).forEach(function(key) { Object.keys(messages).forEach((key) => {
let entries = messages[key].entries; const { entries } = messages[key];
prevMsgEntries[key] = entries[entries.length - 1]; prevMsgEntries[key] = entries[entries.length - 1];
}); });
} }
// var worker = new CanFetcher(); // var worker = new CanFetcher();
var worker = new RLogDownloader(); const worker = new RLogDownloader();
let spawnWorkerHash = hash(Math.random().toString(16)); const spawnWorkerHash = hash(Math.random().toString(16));
currentWorkers[spawnWorkerHash] = { currentWorkers[spawnWorkerHash] = {
part, part,
worker worker
@ -471,9 +473,9 @@ export default class CanExplorer extends Component {
loadingParts loadingParts
}); });
worker.onmessage = e => { worker.onmessage = (e) => {
if (this.state.currentWorkers[spawnWorkerHash] === undefined) { if (this.state.currentWorkers[spawnWorkerHash] === undefined) {
console.log("Worker was canceled"); console.log('Worker was canceled');
return; return;
} }
@ -495,16 +497,15 @@ export default class CanExplorer extends Component {
maxByteStateChangeCount maxByteStateChangeCount
); );
const prevMsgEntries = {}; const prevMsgEntries = {};
for (let key in newMessages) { for (const key in newMessages) {
prevMsgEntries[key] = prevMsgEntries[key] = newMessages[key].entries[newMessages[key].entries.length - 1];
newMessages[key].entries[newMessages[key].entries.length - 1];
} }
if (!isFinished) { if (!isFinished) {
this.setState({ messages }); this.setState({ messages });
} else { } else {
let loadingParts = this.state.loadingParts.filter(p => p !== part); const loadingParts = this.state.loadingParts.filter((p) => p !== part);
let loadedParts = [part, ...this.state.loadedParts]; const loadedParts = [part, ...this.state.loadedParts];
this.setState( this.setState(
{ {
@ -537,7 +538,7 @@ export default class CanExplorer extends Component {
// data that is used // data that is used
dbcText: dbc.text(), dbcText: dbc.text(),
route: route.fullname, route: route.fullname,
part: part, part,
canStartTime: firstCanTime != null ? firstCanTime - canFrameOffset : null, canStartTime: firstCanTime != null ? firstCanTime - canFrameOffset : null,
prevMsgEntries, prevMsgEntries,
maxByteStateChangeCount maxByteStateChangeCount
@ -553,11 +554,11 @@ export default class CanExplorer extends Component {
showEditMessageModal showEditMessageModal
} = this.state; } = this.state;
return ( return (
showOnboarding || showOnboarding
showLoadDbc || || showLoadDbc
showSaveDbc || || showSaveDbc
showAddSignal || || showAddSignal
showEditMessageModal || showEditMessageModal
); );
} }
@ -589,8 +590,8 @@ export default class CanExplorer extends Component {
this.setState({ isLoading: true }); this.setState({ isLoading: true });
const { dbc } = this.state; const { dbc } = this.state;
var worker = new MessageParser(); const worker = new MessageParser();
worker.onmessage = e => { worker.onmessage = (e) => {
let messages = e.data; let messages = e.data;
messages = this.addAndRehydrateMessages(messages, { replace: true }); messages = this.addAndRehydrateMessages(messages, { replace: true });
@ -616,7 +617,7 @@ export default class CanExplorer extends Component {
if (route) { if (route) {
persistDbc(route.fullname, { dbcFilename, dbc }); persistDbc(route.fullname, { dbcFilename, dbc });
} else { } else {
persistDbc("live", { dbcFilename, dbc }); persistDbc('live', { dbcFilename, dbc });
} }
} }
@ -635,19 +636,17 @@ export default class CanExplorer extends Component {
messages[message.id] = newMessage; messages[message.id] = newMessage;
this.setState({ dbc, dbcText: dbc.text() }, () => this.setState({ dbc, dbcText: dbc.text() }, () => this.reparseMessages(messages));
this.reparseMessages(messages)
);
} }
partChangeDebounced = debounce(() => { partChangeDebounced = debounce(() => {
let [minPart, maxPart] = this.state.currentParts; const [minPart, maxPart] = this.state.currentParts;
let messages = { ...this.state.messages }; const messages = { ...this.state.messages };
// update messages to only preserve entries in new part range // update messages to only preserve entries in new part range
let minTime = minPart * 60; const minTime = minPart * 60;
let maxTime = maxPart * 60 + 60; const maxTime = maxPart * 60 + 60;
Object.keys(messages).forEach(key => { Object.keys(messages).forEach((key) => {
let entries = messages[key].entries; const { entries } = messages[key];
let minIndex = 0; let minIndex = 0;
let maxIndex = entries.length - 1; let maxIndex = entries.length - 1;
while (minIndex < entries.length && entries[minIndex].relTime < minTime) { while (minIndex < entries.length && entries[minIndex].relTime < minTime) {
@ -669,14 +668,16 @@ export default class CanExplorer extends Component {
}, 500); }, 500);
onPartChange(part) { onPartChange(part) {
let { currentParts, currentPart, canFrameOffset, route } = this.state; let {
currentParts, currentPart, canFrameOffset, route
} = this.state;
if (canFrameOffset === -1 || part === currentPart) { if (canFrameOffset === -1 || part === currentPart) {
return; return;
} }
// determine new parts to load, whether to prepend or append // determine new parts to load, whether to prepend or append
let maxPart = Math.min(route.proclog, part + 1); let maxPart = Math.min(route.proclog, part + 1);
let minPart = Math.max(0, maxPart - PART_SEGMENT_LENGTH + 1); const minPart = Math.max(0, maxPart - PART_SEGMENT_LENGTH + 1);
if (minPart === 0) { if (minPart === 0) {
maxPart = Math.min(route.proclog, 2); maxPart = Math.min(route.proclog, 2);
} }
@ -687,9 +688,9 @@ export default class CanExplorer extends Component {
currentPart = part; currentPart = part;
if ( if (
currentPart !== this.state.currentPart || currentPart !== this.state.currentPart
currentParts[0] !== this.state.currentParts[0] || || currentParts[0] !== this.state.currentParts[0]
currentParts[1] !== this.state.currentParts[1] || currentParts[1] !== this.state.currentParts[1]
) { ) {
// update state then load new parts // update state then load new parts
this.setState({ currentParts, currentPart }, this.partChangeDebounced); this.setState({ currentParts, currentPart }, this.partChangeDebounced);
@ -715,9 +716,11 @@ export default class CanExplorer extends Component {
} }
onMessageFrameEdited(messageFrame) { onMessageFrameEdited(messageFrame) {
const { messages, dbcFilename, dbc, editMessageModalMessage } = this.state; const {
messages, dbcFilename, dbc, editMessageModalMessage
} = this.state;
const message = Object.assign({}, messages[editMessageModalMessage]); const message = { ...messages[editMessageModalMessage] };
message.frame = messageFrame; message.frame = messageFrame;
dbc.messages.set(messageFrame.id, messageFrame); dbc.messages.set(messageFrame.id, messageFrame);
this.persistDbc({ dbcFilename, dbc }); this.persistDbc({ dbcFilename, dbc });
@ -730,8 +733,8 @@ export default class CanExplorer extends Component {
onSeek(seekIndex, seekTime) { onSeek(seekIndex, seekTime) {
this.setState({ seekIndex, seekTime }); this.setState({ seekIndex, seekTime });
let { currentPart } = this.state; const { currentPart } = this.state;
let part = ~~(seekTime / 60); const part = ~~(seekTime / 60);
if (part !== currentPart) { if (part !== currentPart) {
this.onPartChange(part); this.onPartChange(part);
} }
@ -745,7 +748,7 @@ export default class CanExplorer extends Component {
const msg = this.state.messages[this.state.selectedMessage]; const msg = this.state.messages[this.state.selectedMessage];
let seekIndex; let seekIndex;
if (msg) { if (msg) {
seekIndex = msg.entries.findIndex(e => e.relTime >= seekTime); seekIndex = msg.entries.findIndex((e) => e.relTime >= seekTime);
if (seekIndex === -1) { if (seekIndex === -1) {
seekIndex = 0; seekIndex = 0;
} }
@ -761,7 +764,7 @@ export default class CanExplorer extends Component {
const msg = messages[msgKey]; const msg = messages[msgKey];
if (seekTime > 0 && msg.entries.length > 0) { if (seekTime > 0 && msg.entries.length > 0) {
seekIndex = msg.entries.findIndex(e => e.relTime >= seekTime); seekIndex = msg.entries.findIndex((e) => e.relTime >= seekTime);
if (seekIndex === -1) { if (seekIndex === -1) {
seekIndex = 0; seekIndex = 0;
} }
@ -785,7 +788,7 @@ export default class CanExplorer extends Component {
return ( return (
<a <a
href={GithubAuth.authorizeUrl( href={GithubAuth.authorizeUrl(
route && route.fullname ? route.fullname : "" route && route.fullname ? route.fullname : ''
)} )}
className="button button--dark button--inline" className="button button--dark button--inline"
> >
@ -847,7 +850,7 @@ export default class CanExplorer extends Component {
} }
enforceStreamingMessageWindow(messages) { enforceStreamingMessageWindow(messages) {
let messageIds = Object.keys(messages); const messageIds = Object.keys(messages);
for (let i = 0; i < messageIds.length; i++) { for (let i = 0; i < messageIds.length; i++) {
const messageId = messageIds[i]; const messageId = messageIds[i];
const message = messages[messageId]; const message = messages[messageId];
@ -886,8 +889,8 @@ export default class CanExplorer extends Component {
messages = this.enforceStreamingMessageWindow(messages); messages = this.enforceStreamingMessageWindow(messages);
let { seekIndex, selectedMessages } = this.state; let { seekIndex, selectedMessages } = this.state;
if ( if (
selectedMessages.length > 0 && selectedMessages.length > 0
messages[selectedMessages[0]] !== undefined && messages[selectedMessages[0]] !== undefined
) { ) {
seekIndex = Math.max(0, messages[selectedMessages[0]].entries.length - 1); seekIndex = Math.max(0, messages[selectedMessages[0]].entries.length - 1);
} }
@ -908,16 +911,16 @@ export default class CanExplorer extends Component {
async handlePandaConnect(e) { async handlePandaConnect(e) {
this.setState({ attemptingPandaConnection: true, live: true }); this.setState({ attemptingPandaConnection: true, live: true });
const persistedDbc = fetchPersistedDbc("live"); const persistedDbc = fetchPersistedDbc('live');
if (persistedDbc) { if (persistedDbc) {
let { dbc, dbcText } = persistedDbc; const { dbc, dbcText } = persistedDbc;
this.setState({ dbc, dbcText }); this.setState({ dbc, dbcText });
} }
this.canStreamerWorker = new CanStreamerWorker(); this.canStreamerWorker = new CanStreamerWorker();
this.canStreamerWorker.onmessage = this.onStreamedCanMessagesProcessed; this.canStreamerWorker.onmessage = this.onStreamedCanMessagesProcessed;
// if any errors go off during connection, mark as not trying to connect anymore... // if any errors go off during connection, mark as not trying to connect anymore...
let unlisten = this.pandaReader.onError(err => { const unlisten = this.pandaReader.onError((err) => {
console.error(err.stack || err); console.error(err.stack || err);
this.setState({ attemptingPandaConnection: false }); this.setState({ attemptingPandaConnection: false });
}); });
@ -943,7 +946,7 @@ export default class CanExplorer extends Component {
return ( return (
<div <div
id="cabana" id="cabana"
className={cx({ "is-showing-modal": this.showingModal() })} className={cx({ 'is-showing-modal': this.showingModal() })}
> >
{this.state.isLoading ? ( {this.state.isLoading ? (
<LoadingBar isLoading={this.state.isLoading} /> <LoadingBar isLoading={this.state.isLoading} />

View File

@ -1,27 +1,28 @@
global.__JEST__ = 1; import DBC from '../../models/can/dbc';
import DBC from "../../models/can/dbc"; import Signal from '../../models/can/signal';
import Signal from "../../models/can/signal";
test("setting signals should create a message", () => { global.__JEST__ = 1;
test('setting signals should create a message', () => {
const dbc = new DBC(); const dbc = new DBC();
dbc.setSignals(100, { "My Signal": new Signal({ name: "My Signal" }) }); dbc.setSignals(100, { 'My Signal': new Signal({ name: 'My Signal' }) });
expect(dbc.messages.has(100)).toBe(true); expect(dbc.messages.has(100)).toBe(true);
}); });
test("setting signals should update DBC.boardUnits", () => { test('setting signals should update DBC.boardUnits', () => {
const dbc = new DBC(); const dbc = new DBC();
dbc.setSignals(100, { dbc.setSignals(100, {
"My Signal": new Signal({ name: "My Signal", receiver: ["NEO"] }) 'My Signal': new Signal({ name: 'My Signal', receiver: ['NEO'] })
}); });
expect(dbc.boardUnits.map(bu => bu.name).indexOf("NEO")).toBe(0); expect(dbc.boardUnits.map((bu) => bu.name).indexOf('NEO')).toBe(0);
}); });
test("adding a signal should update DBC.boardUnits", () => { test('adding a signal should update DBC.boardUnits', () => {
const dbc = new DBC(); const dbc = new DBC();
dbc.createFrame(100); dbc.createFrame(100);
dbc.addSignal(100, new Signal({ name: "My Signal", receiver: ["NEO"] })); dbc.addSignal(100, new Signal({ name: 'My Signal', receiver: ['NEO'] }));
expect(dbc.boardUnits.map(bu => bu.name).indexOf("NEO")).toBe(0); expect(dbc.boardUnits.map((bu) => bu.name).indexOf('NEO')).toBe(0);
}); });

View File

@ -1,6 +1,7 @@
import DBC, { swapOrder } from '../../models/can/dbc';
import Signal from '../../models/can/signal';
global.__JEST__ = 1; global.__JEST__ = 1;
import DBC, { swapOrder } from "../../models/can/dbc";
import Signal from "../../models/can/signal";
const DBC_MESSAGE_DEF = `BO_ 228 STEERING_CONTROL: 5 ADAS const DBC_MESSAGE_DEF = `BO_ 228 STEERING_CONTROL: 5 ADAS
SG_ STEER_TORQUE : 7|16@0- (1,0) [-3840|3840] "" EPS SG_ STEER_TORQUE : 7|16@0- (1,0) [-3840|3840] "" EPS
@ -145,7 +146,7 @@ BO_ 464 WHEEL_SPEEDS: 8 VSA
`; `;
const steerTorqueSignal = new Signal({ const steerTorqueSignal = new Signal({
name: "STEER_TORQUE", name: 'STEER_TORQUE',
startBit: 7, startBit: 7,
size: 16, size: 16,
isLittleEndian: false, isLittleEndian: false,
@ -154,165 +155,165 @@ const steerTorqueSignal = new Signal({
offset: 0, offset: 0,
min: -3840, min: -3840,
max: 3840, max: 3840,
receiver: ["EPS"], receiver: ['EPS'],
unit: "" unit: ''
}); });
function dbcInt32SignalValue(dbc, signalSpec, hex) { function dbcInt32SignalValue(dbc, signalSpec, hex) {
// expects hex string to represent 8 bytes, left-justified with zeroes if frame size is smaller // expects hex string to represent 8 bytes, left-justified with zeroes if frame size is smaller
const buffer = Buffer.from(hex, "hex"); const buffer = Buffer.from(hex, 'hex');
return dbc.valueForInt32Signal(signalSpec, buffer); return dbc.valueForInt32Signal(signalSpec, buffer);
} }
test("DBC parses steering control message", () => { test('DBC parses steering control message', () => {
const dbcParsed = new DBC(DBC_MESSAGE_DEF); const dbcParsed = new DBC(DBC_MESSAGE_DEF);
const { signals } = dbcParsed.getMessageFrame(228); const { signals } = dbcParsed.getMessageFrame(228);
expect(Object.keys(signals).length).toBe(6); expect(Object.keys(signals).length).toBe(6);
expect(signals["STEER_TORQUE"].equals(steerTorqueSignal)).toBe(true); expect(signals.STEER_TORQUE.equals(steerTorqueSignal)).toBe(true);
}); });
test("DBC parses signal comment", () => { test('DBC parses signal comment', () => {
const dbcParsed = new DBC(DBC_SIGNAL_WITH_COMMENT); const dbcParsed = new DBC(DBC_SIGNAL_WITH_COMMENT);
const { signals } = dbcParsed.getMessageFrame(228); const { signals } = dbcParsed.getMessageFrame(228);
expect(signals.STEER_TORQUE.comment).toEqual( expect(signals.STEER_TORQUE.comment).toEqual(
"steer torque is the amount of torque in Nm applied" 'steer torque is the amount of torque in Nm applied'
); );
}); });
test("DBC parses multi-line signal comment", () => { test('DBC parses multi-line signal comment', () => {
const dbcParsed = new DBC(DBC_SIGNAL_WITH_MULTI_LINE_COMMENT); const dbcParsed = new DBC(DBC_SIGNAL_WITH_MULTI_LINE_COMMENT);
const { signals } = dbcParsed.getMessageFrame(228); const { signals } = dbcParsed.getMessageFrame(228);
expect(signals.STEER_TORQUE.comment).toEqual( expect(signals.STEER_TORQUE.comment).toEqual(
"steer torque is the\namount of torque in Nm applied" 'steer torque is the\namount of torque in Nm applied'
); );
}); });
test("DBC parses message comment", () => { test('DBC parses message comment', () => {
const dbcParsed = new DBC(DBC_MESSAGE_WITH_COMMENT); const dbcParsed = new DBC(DBC_MESSAGE_WITH_COMMENT);
const msg = dbcParsed.getMessageFrame(228); const msg = dbcParsed.getMessageFrame(228);
expect(msg.comment).toEqual("this message contains steer torque information"); expect(msg.comment).toEqual('this message contains steer torque information');
}); });
test("DBC parses multi-line message comment", () => { test('DBC parses multi-line message comment', () => {
const dbcParsed = new DBC(DBC_MESSAGE_WITH_MULTI_LINE_COMMENT); const dbcParsed = new DBC(DBC_MESSAGE_WITH_MULTI_LINE_COMMENT);
const msg = dbcParsed.getMessageFrame(228); const msg = dbcParsed.getMessageFrame(228);
expect(msg.comment).toEqual( expect(msg.comment).toEqual(
"this message contains\nsteer torque information" 'this message contains\nsteer torque information'
); );
}); });
test("DBC parses board unit names", () => { test('DBC parses board unit names', () => {
const dbcParsed = new DBC(DBC_BOARD_UNITS); const dbcParsed = new DBC(DBC_BOARD_UNITS);
expect(dbcParsed.boardUnits[0].name).toEqual("first_board_unit"); expect(dbcParsed.boardUnits[0].name).toEqual('first_board_unit');
expect(dbcParsed.boardUnits[1].name).toEqual("second_board_unit"); expect(dbcParsed.boardUnits[1].name).toEqual('second_board_unit');
}); });
test("DBC parses board unit comments", () => { test('DBC parses board unit comments', () => {
const dbcParsed = new DBC(DBC_BOARD_UNITS_WITH_COMMENT); const dbcParsed = new DBC(DBC_BOARD_UNITS_WITH_COMMENT);
expect(dbcParsed.boardUnits[0].comment).toEqual("first board unit comment"); expect(dbcParsed.boardUnits[0].comment).toEqual('first board unit comment');
}); });
test("DBC parses multi-line board unit comments", () => { test('DBC parses multi-line board unit comments', () => {
const dbcParsed = new DBC(DBC_BOARD_UNITS_WITH_COMMENT_LINES); const dbcParsed = new DBC(DBC_BOARD_UNITS_WITH_COMMENT_LINES);
expect(dbcParsed.boardUnits[0].comment).toEqual("first board unit\ncomment"); expect(dbcParsed.boardUnits[0].comment).toEqual('first board unit\ncomment');
}); });
test("DBC parses signal value descriptions", () => { test('DBC parses signal value descriptions', () => {
const dbcParsed = new DBC(DBC_SIGNALS_WITH_VAL); const dbcParsed = new DBC(DBC_SIGNALS_WITH_VAL);
const { signals } = dbcParsed.getMessageFrame(228); const { signals } = dbcParsed.getMessageFrame(228);
const expectedTorqueRequestVals = new Map([ const expectedTorqueRequestVals = new Map([
["1", "requesting torque"], ['1', 'requesting torque'],
["0", "not requesting torque"] ['0', 'not requesting torque']
]); ]);
expect(signals.STEER_TORQUE_REQUEST.valueDescriptions).toEqual( expect(signals.STEER_TORQUE_REQUEST.valueDescriptions).toEqual(
expectedTorqueRequestVals expectedTorqueRequestVals
); );
}); });
test("DBC parses value tables", () => { test('DBC parses value tables', () => {
const dbcParsed = new DBC(DBC_VALUE_TABLE); const dbcParsed = new DBC(DBC_VALUE_TABLE);
const stateTableEntries = [ const stateTableEntries = [
["4", "DI_STATE_ENABLE"], ['4', 'DI_STATE_ENABLE'],
["3", "DI_STATE_FAULT"], ['3', 'DI_STATE_FAULT'],
["2", "DI_STATE_CLEAR_FAULT"], ['2', 'DI_STATE_CLEAR_FAULT'],
["1", "DI_STATE_STANDBY"], ['1', 'DI_STATE_STANDBY'],
["0", "DI_STATE_PREAUTH"] ['0', 'DI_STATE_PREAUTH']
]; ];
const stateTable = new Map(stateTableEntries); const stateTable = new Map(stateTableEntries);
const speedUnitsEntries = [["1", "DI_SPEED_KPH"], ["0", "DI_SPEED_MPH"]]; const speedUnitsEntries = [['1', 'DI_SPEED_KPH'], ['0', 'DI_SPEED_MPH']];
const speedUnitsTable = new Map(speedUnitsEntries); const speedUnitsTable = new Map(speedUnitsEntries);
const valueTableEntries = Array.from(dbcParsed.valueTables.entries()); const valueTableEntries = Array.from(dbcParsed.valueTables.entries());
expect(valueTableEntries[0]).toEqual(["DI_state", stateTable]); expect(valueTableEntries[0]).toEqual(['DI_state', stateTable]);
expect(valueTableEntries[1]).toEqual(["DI_speedUnits", speedUnitsTable]); expect(valueTableEntries[1]).toEqual(['DI_speedUnits', speedUnitsTable]);
}); });
test("swapOrder properly converts little endian to big endian", () => { test('swapOrder properly converts little endian to big endian', () => {
const littleEndianHex = "e2d62a0bd0d3b5e5"; const littleEndianHex = 'e2d62a0bd0d3b5e5';
const bigEndianHex = "e5b5d3d00b2ad6e2"; const bigEndianHex = 'e5b5d3d00b2ad6e2';
const littleEndianHexSwapped = swapOrder(littleEndianHex, 16, 2); const littleEndianHexSwapped = swapOrder(littleEndianHex, 16, 2);
expect(littleEndianHexSwapped == bigEndianHex).toBe(true); expect(littleEndianHexSwapped == bigEndianHex).toBe(true);
}); });
test("int32 parser produces correct value for steer torque signal", () => { test('int32 parser produces correct value for steer torque signal', () => {
const dbc = new DBC(DBC_MESSAGE_DEF); const dbc = new DBC(DBC_MESSAGE_DEF);
const hex = "e2d62a0bd0d3b5e5"; const hex = 'e2d62a0bd0d3b5e5';
const value = dbcInt32SignalValue( const value = dbcInt32SignalValue(
dbc, dbc,
dbc.getMessageFrame(228).signals["STEER_TORQUE"], dbc.getMessageFrame(228).signals.STEER_TORQUE,
hex hex
); );
expect(value).toBe(-7466); expect(value).toBe(-7466);
}); });
test("int64 parser produces correct value for steer torque signal", () => { test('int64 parser produces correct value for steer torque signal', () => {
const dbc = new DBC(DBC_MESSAGE_DEF); const dbc = new DBC(DBC_MESSAGE_DEF);
const hex = "e2d62a0bd0d3b5e5"; const hex = 'e2d62a0bd0d3b5e5';
const value = dbc.valueForInt64Signal(steerTorqueSignal, hex); const value = dbc.valueForInt64Signal(steerTorqueSignal, hex);
expect(value).toBe(-7466); expect(value).toBe(-7466);
}); });
test("int32 parser produces correct value for wheel speeds", () => { test('int32 parser produces correct value for wheel speeds', () => {
const dbc = new DBC(DBC_WHEEL_SPEEDS); const dbc = new DBC(DBC_WHEEL_SPEEDS);
const hex = "36806cd8d8f1b0b7"; const hex = '36806cd8d8f1b0b7';
const rearRight = dbcInt32SignalValue( const rearRight = dbcInt32SignalValue(
dbc, dbc,
dbc.getMessageFrame(464).signals["WHEEL_SPEED_RR"], dbc.getMessageFrame(464).signals.WHEEL_SPEED_RR,
hex hex
); );
expect(rearRight).toBe(69.23); expect(rearRight).toBe(69.23);
const rearLeft = dbcInt32SignalValue( const rearLeft = dbcInt32SignalValue(
dbc, dbc,
dbc.getMessageFrame(464).signals["WHEEL_SPEED_RL"], dbc.getMessageFrame(464).signals.WHEEL_SPEED_RL,
hex hex
); );
expect(rearLeft).toBe(69.42); expect(rearLeft).toBe(69.42);
const frontLeft = dbcInt32SignalValue( const frontLeft = dbcInt32SignalValue(
dbc, dbc,
dbc.getMessageFrame(464).signals["WHEEL_SPEED_FL"], dbc.getMessageFrame(464).signals.WHEEL_SPEED_FL,
hex hex
); );
expect(frontLeft).toBe(69.76); expect(frontLeft).toBe(69.76);
const frontRight = dbcInt32SignalValue( const frontRight = dbcInt32SignalValue(
dbc, dbc,
dbc.getMessageFrame(464).signals["WHEEL_SPEED_FR"], dbc.getMessageFrame(464).signals.WHEEL_SPEED_FR,
hex hex
); );
expect(frontRight).toBe(69.66); expect(frontRight).toBe(69.66);
@ -323,12 +324,12 @@ BO_ 768 NEW_MSG_1: 8 XXX
SG_ NEW_SIGNAL_1 : 37|1@1+ (1,0) [0|1] "" XXX SG_ NEW_SIGNAL_1 : 37|1@1+ (1,0) [0|1] "" XXX
`; `;
test("int32 parsers produces correct value for binary little endian signal", () => { test('int32 parsers produces correct value for binary little endian signal', () => {
const dbc = new DBC(DBC_BINARY_LE_SIGNAL); const dbc = new DBC(DBC_BINARY_LE_SIGNAL);
const signalSpec = dbc.getMessageFrame(768).signals["NEW_SIGNAL_1"]; const signalSpec = dbc.getMessageFrame(768).signals.NEW_SIGNAL_1;
const hexDataSet = "0000000020000000"; const hexDataSet = '0000000020000000';
const hexDataNotSet = "0000000000000000"; const hexDataNotSet = '0000000000000000';
const setValue = dbcInt32SignalValue(dbc, signalSpec, hexDataSet, 8); const setValue = dbcInt32SignalValue(dbc, signalSpec, hexDataSet, 8);
const notSetValue = dbcInt32SignalValue(dbc, signalSpec, hexDataNotSet, 8); const notSetValue = dbcInt32SignalValue(dbc, signalSpec, hexDataNotSet, 8);
@ -341,11 +342,11 @@ const DBC_TWO_BIT_LE_SIGNAL = `
BO_ 768 NEW_MSG_1: 8 XXX BO_ 768 NEW_MSG_1: 8 XXX
SG_ NEW_SIGNAL_1 : 35|2@1+ (1,0) [0|3] "" XXX SG_ NEW_SIGNAL_1 : 35|2@1+ (1,0) [0|3] "" XXX
`; `;
test("int32 parser produces correct value for 2-bit little endian signal spanning words", () => { test('int32 parser produces correct value for 2-bit little endian signal spanning words', () => {
const dbc = new DBC(DBC_TWO_BIT_LE_SIGNAL); const dbc = new DBC(DBC_TWO_BIT_LE_SIGNAL);
const signalSpec = dbc.getMessageFrame(768).signals["NEW_SIGNAL_1"]; const signalSpec = dbc.getMessageFrame(768).signals.NEW_SIGNAL_1;
const hexData = "00000001f8000000"; const hexData = '00000001f8000000';
const value = dbcInt32SignalValue(dbc, signalSpec, hexData, 8); const value = dbcInt32SignalValue(dbc, signalSpec, hexData, 8);
expect(value).toEqual(3); expect(value).toEqual(3);
@ -355,17 +356,17 @@ const DBC_FOUR_BIT_LE_SIGNAL = `
BO_ 768 NEW_MSG_1: 8 XXX BO_ 768 NEW_MSG_1: 8 XXX
SG_ NEW_SIGNAL_1 : 6|4@1+ (1,0) [0|15] "" XXX SG_ NEW_SIGNAL_1 : 6|4@1+ (1,0) [0|15] "" XXX
`; `;
test("int32 parser produces correct value for 4-bit little endian signal", () => { test('int32 parser produces correct value for 4-bit little endian signal', () => {
const dbc = new DBC(DBC_FOUR_BIT_LE_SIGNAL); const dbc = new DBC(DBC_FOUR_BIT_LE_SIGNAL);
const signalSpec = dbc.getMessageFrame(768).signals["NEW_SIGNAL_1"]; const signalSpec = dbc.getMessageFrame(768).signals.NEW_SIGNAL_1;
// this data is symmetric, the data bits are 1111 // this data is symmetric, the data bits are 1111
const hexDataSymmetric = "f00f000000000000"; const hexDataSymmetric = 'f00f000000000000';
const symValue = dbcInt32SignalValue(dbc, signalSpec, hexDataSymmetric, 8); const symValue = dbcInt32SignalValue(dbc, signalSpec, hexDataSymmetric, 8);
expect(symValue).toEqual(15); expect(symValue).toEqual(15);
// this data is asymmetric, the data bits are 1101 // this data is asymmetric, the data bits are 1101
const hexDataAsymmetric = "f002000000000000"; const hexDataAsymmetric = 'f002000000000000';
const aSymValue = dbcInt32SignalValue(dbc, signalSpec, hexDataAsymmetric, 8); const aSymValue = dbcInt32SignalValue(dbc, signalSpec, hexDataAsymmetric, 8);
expect(aSymValue).toEqual(11); expect(aSymValue).toEqual(11);
}); });
@ -385,12 +386,12 @@ BO_ 1265 CLU11: 4 CLU
SG_ CF_Clu_AmpInfo : 25|1@1+ (1.0,0.0) [0.0|1.0] "" BCM SG_ CF_Clu_AmpInfo : 25|1@1+ (1.0,0.0) [0.0|1.0] "" BCM
SG_ CF_Clu_AliveCnt1 : 28|4@1+ (1.0,0.0) [0.0|15.0] "" AHLS,EMS,EPB,LDWS_LKAS,MDPS,SCC SG_ CF_Clu_AliveCnt1 : 28|4@1+ (1.0,0.0) [0.0|15.0] "" AHLS,EMS,EPB,LDWS_LKAS,MDPS,SCC
`; `;
test("int32 parser produces correct value for 4-bit little endian signal within a 4-byte message", () => { test('int32 parser produces correct value for 4-bit little endian signal within a 4-byte message', () => {
const dbc = new DBC(DBC_FOUR_BIT_LE_SIGNAL_FOUR_BYTE_MESSAGE); const dbc = new DBC(DBC_FOUR_BIT_LE_SIGNAL_FOUR_BYTE_MESSAGE);
const frame = dbc.getMessageFrame(1265); const frame = dbc.getMessageFrame(1265);
const signalSpec = frame.signals["CF_Clu_AliveCnt1"]; const signalSpec = frame.signals.CF_Clu_AliveCnt1;
const hexData = "2000662000000000"; const hexData = '2000662000000000';
const value = dbcInt32SignalValue(dbc, signalSpec, hexData, frame.size); const value = dbcInt32SignalValue(dbc, signalSpec, hexData, frame.size);
expect(value).toEqual(2); expect(value).toEqual(2);
}); });
@ -403,16 +404,16 @@ BO_ 688 SAS11: 5 MDPS
SG_ MsgCount : 32|4@1+ (1.0,0.0) [0.0|15.0] "" ECS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS,ECS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS SG_ MsgCount : 32|4@1+ (1.0,0.0) [0.0|15.0] "" ECS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS,ECS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS
SG_ CheckSum : 36|4@1+ (1.0,0.0) [0.0|15.0] "" ECS,EMS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS,ECS,EMS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS SG_ CheckSum : 36|4@1+ (1.0,0.0) [0.0|15.0] "" ECS,EMS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS,ECS,EMS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS
`; `;
test("int32 parser produces correct value for 2-byte signed little endian signal within a 5-byte message", () => { test('int32 parser produces correct value for 2-byte signed little endian signal within a 5-byte message', () => {
const dbc = new DBC(DBC_MESSAGE_WITH_LE_SIGNED_SIGNAL); const dbc = new DBC(DBC_MESSAGE_WITH_LE_SIGNED_SIGNAL);
const frame = dbc.getMessageFrame(688); const frame = dbc.getMessageFrame(688);
const signalSpec = frame.signals["SAS_Angle"]; const signalSpec = frame.signals.SAS_Angle;
const hexData = "000000fafe000700"; const hexData = '000000fafe000700';
const value = dbcInt32SignalValue(dbc, signalSpec, hexData, frame.size); const value = dbcInt32SignalValue(dbc, signalSpec, hexData, frame.size);
expect(value).toEqual(0.0); expect(value).toEqual(0.0);
const hexData2 = "0b000907d8b30000"; const hexData2 = '0b000907d8b30000';
const value2 = dbcInt32SignalValue(dbc, signalSpec, hexData2, frame.size); const value2 = dbcInt32SignalValue(dbc, signalSpec, hexData2, frame.size);
expect(value2).toEqual(1.1); expect(value2).toEqual(1.1);
}); });
@ -424,12 +425,12 @@ BO_ 37 STEERING_CONTROL: 8 XXX
CM_ "CHFFR_METRIC 37 STEER_ANGLE STEER_ANGLE 0.36 180"; CM_ "CHFFR_METRIC 37 STEER_ANGLE STEER_ANGLE 0.36 180";
`; `;
test("dbc parser parses top-level comment with chffr metric", () => { test('dbc parser parses top-level comment with chffr metric', () => {
const dbc = new DBC(DBC_CHFFR_METRIC_COMMENT); const dbc = new DBC(DBC_CHFFR_METRIC_COMMENT);
const { comments } = dbc; const { comments } = dbc;
expect(comments.length).toEqual(1); expect(comments.length).toEqual(1);
expect(comments[0]).toEqual( expect(comments[0]).toEqual(
"CHFFR_METRIC 37 STEER_ANGLE STEER_ANGLE 0.36 180" 'CHFFR_METRIC 37 STEER_ANGLE STEER_ANGLE 0.36 180'
); );
}); });

View File

@ -1,11 +1,11 @@
import DBC, { swapOrder } from "../../models/can/dbc"; import fs from 'fs';
import fs from "fs"; import path from 'path';
import path from "path"; import DBC, { swapOrder } from '../../models/can/dbc';
const ACURA_DBC = fs.readFileSync("src/__tests__/res/acura.dbc", "utf-8"); const ACURA_DBC = fs.readFileSync('src/__tests__/res/acura.dbc', 'utf-8');
//import { TESLA_DBC } from "../res/tesla.dbc"; // import { TESLA_DBC } from "../res/tesla.dbc";
test("DBC.text() for acura DBC should be equivalent to its original text", () => { test('DBC.text() for acura DBC should be equivalent to its original text', () => {
const dbc = new DBC(ACURA_DBC); const dbc = new DBC(ACURA_DBC);
expect(dbc.text()).toBe(ACURA_DBC); expect(dbc.text()).toBe(ACURA_DBC);

View File

@ -1,6 +1,6 @@
import Entries from "../../models/can/entries"; import Entries from '../../models/can/entries';
test("segment index low is inclusive and index high is exclusive", () => { test('segment index low is inclusive and index high is exclusive', () => {
const entries = [ const entries = [
{ time: 1.0 }, { time: 1.0 },
{ time: 3.45 }, { time: 3.45 },
@ -16,8 +16,8 @@ test("segment index low is inclusive and index high is exclusive", () => {
expect(segmentIdxHi).toBe(entries.length - 1); expect(segmentIdxHi).toBe(entries.length - 1);
}); });
test("segment index cant return negative indexes", () => { test('segment index cant return negative indexes', () => {
var indices = Entries.findSegmentIndices([], [123, 321], true); const indices = Entries.findSegmentIndices([], [123, 321], true);
expect(indices[0]).toBe(0); expect(indices[0]).toBe(0);
expect(indices[1]).toBe(0); expect(indices[1]).toBe(0);
}); });

View File

@ -1,13 +1,13 @@
import Frame from "../../models/can/frame"; import Frame from '../../models/can/frame';
const FRAME_HEADER = "BO_ 255 SOME_FRAME: 5 ADAS"; const FRAME_HEADER = 'BO_ 255 SOME_FRAME: 5 ADAS';
test("Frame.header() returns spec compliant representation", () => { test('Frame.header() returns spec compliant representation', () => {
const frame = new Frame({ const frame = new Frame({
name: "SOME_FRAME", name: 'SOME_FRAME',
id: 255, id: 255,
size: 5, size: 5,
transmitters: ["ADAS"] transmitters: ['ADAS']
}); });
expect(frame.header()).toEqual(FRAME_HEADER); expect(frame.header()).toEqual(FRAME_HEADER);
}); });

View File

@ -1,7 +1,7 @@
import Signal from "../../models/can/signal"; import Signal from '../../models/can/signal';
const someSignalParams = { const someSignalParams = {
name: "STEER_TORQUE", name: 'STEER_TORQUE',
startBit: 7, startBit: 7,
size: 16, size: 16,
isLittleEndian: false, isLittleEndian: false,
@ -10,11 +10,11 @@ const someSignalParams = {
offset: 0, offset: 0,
min: -3840, min: -3840,
max: 3840, max: 3840,
unit: "" unit: ''
}; };
const someOtherSignalParams = { const someOtherSignalParams = {
name: "DIFFERENT_NAME", name: 'DIFFERENT_NAME',
startBit: 0, startBit: 0,
size: 16, size: 16,
isLittleEndian: false, isLittleEndian: false,
@ -23,24 +23,24 @@ const someOtherSignalParams = {
offset: 0, offset: 0,
min: -3840, min: -3840,
max: 3840, max: 3840,
unit: "" unit: ''
}; };
test("Signal.equals returns true for signals with identical properties", () => { test('Signal.equals returns true for signals with identical properties', () => {
const someSignal = new Signal(someSignalParams); const someSignal = new Signal(someSignalParams);
const someEquivalentSignal = new Signal(someSignalParams); const someEquivalentSignal = new Signal(someSignalParams);
expect(someSignal.equals(someEquivalentSignal)).toBe(true); expect(someSignal.equals(someEquivalentSignal)).toBe(true);
}); });
test("Signal.equals returns false for signals with different properties", () => { test('Signal.equals returns false for signals with different properties', () => {
const someSignal = new Signal(someSignalParams); const someSignal = new Signal(someSignalParams);
const differentSignal = new Signal(someOtherSignalParams); const differentSignal = new Signal(someOtherSignalParams);
expect(someSignal.equals(differentSignal)).toBe(false); expect(someSignal.equals(differentSignal)).toBe(false);
}); });
test("Signal.bitDescription returns proper description for a little endian signal", () => { test('Signal.bitDescription returns proper description for a little endian signal', () => {
const littleEndianSignal = new Signal({ const littleEndianSignal = new Signal({
name: "little endian signal", name: 'little endian signal',
startBit: 20, startBit: 20,
size: 4, size: 4,
isLittleEndian: true isLittleEndian: true
@ -52,9 +52,9 @@ test("Signal.bitDescription returns proper description for a little endian signa
expect(littleEndianSignal.bitDescription(23).bitNumber).toBe(3); expect(littleEndianSignal.bitDescription(23).bitNumber).toBe(3);
}); });
test("Signal.bitDescription returns proper description for a big endian signal", () => { test('Signal.bitDescription returns proper description for a big endian signal', () => {
const bigEndianSignal = new Signal({ const bigEndianSignal = new Signal({
name: "big endian signal", name: 'big endian signal',
startBit: 7, startBit: 7,
size: 16, size: 16,
isLittleEndian: false isLittleEndian: false
@ -91,9 +91,9 @@ test("Signal.bitDescription returns proper description for a big endian signal",
expect(bigEndianSignal.bitDescription(7)).toEqual(bitSevenDescription); expect(bigEndianSignal.bitDescription(7)).toEqual(bitSevenDescription);
}); });
test("Signal.bitDescription returns null for bit index that is not in its range", () => { test('Signal.bitDescription returns null for bit index that is not in its range', () => {
const someSignal = new Signal({ const someSignal = new Signal({
name: "some signal", name: 'some signal',
startBit: 20, startBit: 20,
size: 4, size: 4,
isLittleEndian: false isLittleEndian: false

View File

@ -5,10 +5,10 @@ note: 'right' and 'left' in test descriptions
refer to the sides of the bit matrix refer to the sides of the bit matrix
as displayed to the user. as displayed to the user.
*/ */
import AddSignals from "../../components/AddSignals"; import React from 'react';
import React from "react"; import { shallow, mount, render } from 'enzyme';
import { shallow, mount, render } from "enzyme"; import { StyleSheetTestUtils } from 'aphrodite';
import { StyleSheetTestUtils } from "aphrodite"; import AddSignals from '../../components/AddSignals';
// Prevents style injection from firing after test finishes // Prevents style injection from firing after test finishes
// and jsdom is torn down. // and jsdom is torn down.
@ -31,7 +31,7 @@ function createAddSignals(signals) {
entries: [ entries: [
{ {
relTime: 0, relTime: 0,
hexData: "0000000000000000" hexData: '0000000000000000'
} }
] ]
}; };
@ -46,99 +46,99 @@ function createAddSignals(signals) {
return component; return component;
} }
test("double clicking adds a signal", () => { test('double clicking adds a signal', () => {
const component = createAddSignals(); const component = createAddSignals();
const firstBit = component.find(".bit").first(); const firstBit = component.find('.bit').first();
firstBit.simulate("dblclick"); firstBit.simulate('dblclick');
const newSignal = Object.values(component.state("signals"))[0]; const newSignal = Object.values(component.state('signals'))[0];
expect(newSignal).toBeDefined(); expect(newSignal).toBeDefined();
expect(newSignal.size).toBe(1); expect(newSignal.size).toBe(1);
}); });
test("dragging right to left across a byte creates a little endian signal", () => { test('dragging right to left across a byte creates a little endian signal', () => {
const component = createAddSignals(); const component = createAddSignals();
const leftBitInByte = component.find(".bit").first(); const leftBitInByte = component.find('.bit').first();
const rightBitInByte = component.find(".bit").at(7); const rightBitInByte = component.find('.bit').at(7);
rightBitInByte.simulate("mousedown"); rightBitInByte.simulate('mousedown');
leftBitInByte.simulate("mouseup"); leftBitInByte.simulate('mouseup');
const newSignal = Object.values(component.state("signals"))[0]; const newSignal = Object.values(component.state('signals'))[0];
expect(newSignal).toBeDefined(); expect(newSignal).toBeDefined();
expect(newSignal.size).toBe(8); expect(newSignal.size).toBe(8);
expect(newSignal.isLittleEndian).toBe(true); expect(newSignal.isLittleEndian).toBe(true);
expect(newSignal.startBit).toBe(0); expect(newSignal.startBit).toBe(0);
}); });
test("dragging left to right across a byte creates a big endian signal", () => { test('dragging left to right across a byte creates a big endian signal', () => {
const component = createAddSignals(); const component = createAddSignals();
const leftBitInByte = component.find(".bit").first(); const leftBitInByte = component.find('.bit').first();
const rightBitInByte = component.find(".bit").at(7); const rightBitInByte = component.find('.bit').at(7);
leftBitInByte.simulate("mousedown"); leftBitInByte.simulate('mousedown');
rightBitInByte.simulate("mouseup"); rightBitInByte.simulate('mouseup');
const newSignal = Object.values(component.state("signals"))[0]; const newSignal = Object.values(component.state('signals'))[0];
expect(newSignal).toBeDefined(); expect(newSignal).toBeDefined();
expect(newSignal.size).toBe(8); expect(newSignal.size).toBe(8);
expect(newSignal.isLittleEndian).toBe(false); expect(newSignal.isLittleEndian).toBe(false);
expect(newSignal.startBit).toBe(7); expect(newSignal.startBit).toBe(7);
}); });
test("dragging from the left of byte 0 to right of byte 1 creates a big endian signal spanning both bytes", () => { test('dragging from the left of byte 0 to right of byte 1 creates a big endian signal spanning both bytes', () => {
const component = createAddSignals(); const component = createAddSignals();
const leftBitInByte = component.find(".bit").first(); const leftBitInByte = component.find('.bit').first();
const rightBitInByte = component.find(".bit").at(15); const rightBitInByte = component.find('.bit').at(15);
leftBitInByte.simulate("mousedown"); leftBitInByte.simulate('mousedown');
rightBitInByte.simulate("mouseup"); rightBitInByte.simulate('mouseup');
const newSignal = Object.values(component.state("signals"))[0]; const newSignal = Object.values(component.state('signals'))[0];
expect(newSignal).toBeDefined(); expect(newSignal).toBeDefined();
expect(newSignal.size).toBe(16); expect(newSignal.size).toBe(16);
expect(newSignal.isLittleEndian).toBe(false); expect(newSignal.isLittleEndian).toBe(false);
expect(newSignal.startBit).toBe(7); expect(newSignal.startBit).toBe(7);
}); });
test("dragging from the right of byte 0 to the left of byte 1 creates a little endian signal spanning both bytes", () => { test('dragging from the right of byte 0 to the left of byte 1 creates a little endian signal spanning both bytes', () => {
const component = createAddSignals(); const component = createAddSignals();
const leftBitInByteOne = component.find(".bit").at(8); // left of byte 1 const leftBitInByteOne = component.find('.bit').at(8); // left of byte 1
const rightBitInByteZero = component.find(".bit").at(7); // right of byte 0 const rightBitInByteZero = component.find('.bit').at(7); // right of byte 0
rightBitInByteZero.simulate("mousedown"); rightBitInByteZero.simulate('mousedown');
leftBitInByteOne.simulate("mouseup"); leftBitInByteOne.simulate('mouseup');
const newSignal = Object.values(component.state("signals"))[0]; const newSignal = Object.values(component.state('signals'))[0];
expect(newSignal).toBeDefined(); expect(newSignal).toBeDefined();
expect(newSignal.size).toBe(16); expect(newSignal.size).toBe(16);
expect(newSignal.isLittleEndian).toBe(true); expect(newSignal.isLittleEndian).toBe(true);
expect(newSignal.startBit).toBe(0); expect(newSignal.startBit).toBe(0);
}); });
test("dragging from the left of byte 1 to the right of byte 0 creates a little endian signal spanning both bytes", () => { test('dragging from the left of byte 1 to the right of byte 0 creates a little endian signal spanning both bytes', () => {
const component = createAddSignals(); const component = createAddSignals();
const leftBitInByteOne = component.find(".bit").at(8); const leftBitInByteOne = component.find('.bit').at(8);
const rightBitInByteZero = component.find(".bit").at(7); const rightBitInByteZero = component.find('.bit').at(7);
leftBitInByteOne.simulate("mousedown"); leftBitInByteOne.simulate('mousedown');
rightBitInByteZero.simulate("mouseup"); rightBitInByteZero.simulate('mouseup');
const signal = Object.values(component.state("signals"))[0]; const signal = Object.values(component.state('signals'))[0];
expect(signal).toBeDefined(); expect(signal).toBeDefined();
expect(signal.size).toBe(16); expect(signal.size).toBe(16);
expect(signal.isLittleEndian).toBe(true); expect(signal.isLittleEndian).toBe(true);
expect(signal.startBit).toBe(0); expect(signal.startBit).toBe(0);
}); });
test("dragging from the right of byte 1 to the left of byte 0 creates a big endian signal spanning both bytes", () => { test('dragging from the right of byte 1 to the left of byte 0 creates a big endian signal spanning both bytes', () => {
const component = createAddSignals(); const component = createAddSignals();
const leftBitInByteZero = component.find(".bit").at(0); const leftBitInByteZero = component.find('.bit').at(0);
const rightBitInByteOne = component.find(".bit").at(15); const rightBitInByteOne = component.find('.bit').at(15);
rightBitInByteOne.simulate("mousedown"); rightBitInByteOne.simulate('mousedown');
leftBitInByteZero.simulate("mouseup"); leftBitInByteZero.simulate('mouseup');
const signal = Object.values(component.state("signals"))[0]; const signal = Object.values(component.state('signals'))[0];
expect(signal).toBeDefined(); expect(signal).toBeDefined();
expect(signal.size).toBe(16); expect(signal.size).toBe(16);
expect(signal.isLittleEndian).toBe(false); expect(signal.isLittleEndian).toBe(false);
@ -147,205 +147,205 @@ test("dragging from the right of byte 1 to the left of byte 0 creates a big endi
// signal mutation // signal mutation
test.skip("dragging a one-bit big-endian signal to the right should extend it to the right of the byte", () => { test.skip('dragging a one-bit big-endian signal to the right should extend it to the right of the byte', () => {
const component = createAddSignals(); const component = createAddSignals();
component component
.instance() .instance()
.createSignal({ startBit: 7, size: 1, isLittleEndian: false }); .createSignal({ startBit: 7, size: 1, isLittleEndian: false });
const signalBit = component.find(".bit").at(0); const signalBit = component.find('.bit').at(0);
signalBit.simulate("mousedown"); signalBit.simulate('mousedown');
for (let i = 1; i < 8; i++) { for (let i = 1; i < 8; i++) {
component component
.find(".bit") .find('.bit')
.at(i) .at(i)
.simulate("mouseenter"); .simulate('mouseenter');
} }
const bitAtRightOfFirstByte = component.find(".bit").at(7); const bitAtRightOfFirstByte = component.find('.bit').at(7);
bitAtRightOfFirstByte.simulate("mouseup"); bitAtRightOfFirstByte.simulate('mouseup');
const signal = Object.values(component.state("signals"))[0]; const signal = Object.values(component.state('signals'))[0];
expect(signal).toBeDefined(); expect(signal).toBeDefined();
expect(signal.size).toBe(8); expect(signal.size).toBe(8);
expect(signal.isLittleEndian).toBe(false); expect(signal.isLittleEndian).toBe(false);
expect(signal.startBit).toBe(7); expect(signal.startBit).toBe(7);
}); });
test.skip("dragging a one-bit little-endian signal to the right should extend it to the right of the byte", () => { test.skip('dragging a one-bit little-endian signal to the right should extend it to the right of the byte', () => {
const component = createAddSignals(); const component = createAddSignals();
component component
.instance() .instance()
.createSignal({ startBit: 7, size: 1, isLittleEndian: true }); .createSignal({ startBit: 7, size: 1, isLittleEndian: true });
const signalBit = component.find(".bit").at(0); const signalBit = component.find('.bit').at(0);
signalBit.simulate("mousedown"); signalBit.simulate('mousedown');
for (let i = 1; i < 8; i++) { for (let i = 1; i < 8; i++) {
component component
.find(".bit") .find('.bit')
.at(i) .at(i)
.simulate("mouseenter"); .simulate('mouseenter');
} }
const bitAtRightOfFirstByte = component.find(".bit").at(7); const bitAtRightOfFirstByte = component.find('.bit').at(7);
bitAtRightOfFirstByte.simulate("mouseup"); bitAtRightOfFirstByte.simulate('mouseup');
const signal = Object.values(component.state("signals"))[0]; const signal = Object.values(component.state('signals'))[0];
expect(signal).toBeDefined(); expect(signal).toBeDefined();
expect(signal.size).toBe(8); expect(signal.size).toBe(8);
expect(signal.isLittleEndian).toBe(true); expect(signal.isLittleEndian).toBe(true);
expect(signal.startBit).toBe(0); expect(signal.startBit).toBe(0);
}); });
test.skip("dragging a one-bit big-endian signal to the left should extend it to the left of the byte", () => { test.skip('dragging a one-bit big-endian signal to the left should extend it to the left of the byte', () => {
const component = createAddSignals(); const component = createAddSignals();
component component
.instance() .instance()
.createSignal({ startBit: 0, size: 1, isLittleEndian: false }); .createSignal({ startBit: 0, size: 1, isLittleEndian: false });
const signalBit = component.find(".bit").at(7); const signalBit = component.find('.bit').at(7);
signalBit.simulate("mousedown"); signalBit.simulate('mousedown');
for (let i = 6; i > -1; i--) { for (let i = 6; i > -1; i--) {
component component
.find(".bit") .find('.bit')
.at(i) .at(i)
.simulate("mouseenter"); .simulate('mouseenter');
} }
const bitAtRightOfFirstByte = component.find(".bit").at(0); const bitAtRightOfFirstByte = component.find('.bit').at(0);
bitAtRightOfFirstByte.simulate("mouseup"); bitAtRightOfFirstByte.simulate('mouseup');
const signal = Object.values(component.state("signals"))[0]; const signal = Object.values(component.state('signals'))[0];
expect(signal).toBeDefined(); expect(signal).toBeDefined();
expect(signal.size).toBe(8); expect(signal.size).toBe(8);
expect(signal.isLittleEndian).toBe(false); expect(signal.isLittleEndian).toBe(false);
expect(signal.startBit).toBe(7); expect(signal.startBit).toBe(7);
}); });
test.skip("extending a two-bit big-endian signal by its LSB should extend it to the right of the byte", () => { test.skip('extending a two-bit big-endian signal by its LSB should extend it to the right of the byte', () => {
const component = createAddSignals(); const component = createAddSignals();
component component
.instance() .instance()
.createSignal({ startBit: 7, size: 2, isLittleEndian: false }); .createSignal({ startBit: 7, size: 2, isLittleEndian: false });
const lsb = component.find(".bit").at(1); const lsb = component.find('.bit').at(1);
lsb.simulate("mousedown"); lsb.simulate('mousedown');
for (let i = 0; i < 8; i++) { for (let i = 0; i < 8; i++) {
component component
.find(".bit") .find('.bit')
.at(i) .at(i)
.simulate("mouseenter"); .simulate('mouseenter');
} }
const bitAtRightOfFirstByte = component.find(".bit").at(7); const bitAtRightOfFirstByte = component.find('.bit').at(7);
bitAtRightOfFirstByte.simulate("mouseup"); bitAtRightOfFirstByte.simulate('mouseup');
const signal = Object.values(component.state("signals"))[0]; const signal = Object.values(component.state('signals'))[0];
expect(signal).toBeDefined(); expect(signal).toBeDefined();
expect(signal.size).toBe(8); expect(signal.size).toBe(8);
expect(signal.isLittleEndian).toBe(false); expect(signal.isLittleEndian).toBe(false);
expect(signal.startBit).toBe(7); expect(signal.startBit).toBe(7);
}); });
test.skip("a two-bit little-endian signal should extend by its LSB to the end of the byte", () => { test.skip('a two-bit little-endian signal should extend by its LSB to the end of the byte', () => {
const component = createAddSignals(); const component = createAddSignals();
component component
.instance() .instance()
.createSignal({ startBit: 6, size: 2, isLittleEndian: true }); .createSignal({ startBit: 6, size: 2, isLittleEndian: true });
const lsb = component.find(".bit").at(1); const lsb = component.find('.bit').at(1);
lsb.simulate("mousedown"); lsb.simulate('mousedown');
for (let i = 0; i < 8; i++) { for (let i = 0; i < 8; i++) {
component component
.find(".bit") .find('.bit')
.at(i) .at(i)
.simulate("mouseenter"); .simulate('mouseenter');
} }
const bitAtRightOfFirstByte = component.find(".bit").at(7); const bitAtRightOfFirstByte = component.find('.bit').at(7);
bitAtRightOfFirstByte.simulate("mouseup"); bitAtRightOfFirstByte.simulate('mouseup');
const signal = Object.values(component.state("signals"))[0]; const signal = Object.values(component.state('signals'))[0];
expect(signal).toBeDefined(); expect(signal).toBeDefined();
expect(signal.size).toBe(8); expect(signal.size).toBe(8);
expect(signal.isLittleEndian).toBe(true); expect(signal.isLittleEndian).toBe(true);
expect(signal.startBit).toBe(0); expect(signal.startBit).toBe(0);
}); });
test("dragging the lsb of a little-endian signal spanning an entire byte should not be allowed to pass the MSB", () => { test('dragging the lsb of a little-endian signal spanning an entire byte should not be allowed to pass the MSB', () => {
const component = createAddSignals(); const component = createAddSignals();
component component
.instance() .instance()
.createSignal({ startBit: 0, size: 8, isLittleEndian: true }); .createSignal({ startBit: 0, size: 8, isLittleEndian: true });
const lsb = component.find(".bit").at(7); const lsb = component.find('.bit').at(7);
lsb.simulate("mousedown"); lsb.simulate('mousedown');
const bitPastMsb = component.find(".bit").at(15); const bitPastMsb = component.find('.bit').at(15);
bitPastMsb.simulate("mouseenter"); bitPastMsb.simulate('mouseenter');
bitPastMsb.simulate("mouseup"); bitPastMsb.simulate('mouseup');
const signal = Object.values(component.state("signals"))[0]; const signal = Object.values(component.state('signals'))[0];
expect(signal).toBeDefined(); expect(signal).toBeDefined();
expect(signal.size).toBe(8); expect(signal.size).toBe(8);
expect(signal.isLittleEndian).toBe(true); expect(signal.isLittleEndian).toBe(true);
expect(signal.startBit).toBe(0); expect(signal.startBit).toBe(0);
}); });
test.skip("dragging the lsb of a big-endian signal towards the msb in the same byte should contract the signal", () => { test.skip('dragging the lsb of a big-endian signal towards the msb in the same byte should contract the signal', () => {
const component = createAddSignals(); const component = createAddSignals();
component component
.instance() .instance()
.createSignal({ startBit: 7, size: 8, isLittleEndian: false }); .createSignal({ startBit: 7, size: 8, isLittleEndian: false });
const lsb = component.find(".bit").at(7); const lsb = component.find('.bit').at(7);
lsb.simulate("mousedown"); lsb.simulate('mousedown');
for (let i = 6; i > 0; i--) { for (let i = 6; i > 0; i--) {
component component
.find(".bit") .find('.bit')
.at(i) .at(i)
.simulate("mouseenter"); .simulate('mouseenter');
} }
component component
.find(".bit") .find('.bit')
.at(1) .at(1)
.simulate("mouseup"); .simulate('mouseup');
const signal = Object.values(component.state("signals"))[0]; const signal = Object.values(component.state('signals'))[0];
expect(signal).toBeDefined(); expect(signal).toBeDefined();
expect(signal.size).toBe(2); expect(signal.size).toBe(2);
expect(signal.isLittleEndian).toBe(false); expect(signal.isLittleEndian).toBe(false);
expect(signal.startBit).toBe(7); expect(signal.startBit).toBe(7);
}); });
test("a big endian signal spanning one byte should switch to little endian preserving its bit coverage", () => { test('a big endian signal spanning one byte should switch to little endian preserving its bit coverage', () => {
const component = createAddSignals(); const component = createAddSignals();
component component
.instance() .instance()
.createSignal({ startBit: 0, size: 8, isLittleEndian: true }); .createSignal({ startBit: 0, size: 8, isLittleEndian: true });
const lsb = component.find(".bit").at(7); const lsb = component.find('.bit').at(7);
lsb.simulate("mousedown"); lsb.simulate('mousedown');
const bitPastMsb = component.find(".bit").at(15); const bitPastMsb = component.find('.bit').at(15);
bitPastMsb.simulate("mouseenter"); bitPastMsb.simulate('mouseenter');
bitPastMsb.simulate("mouseup"); bitPastMsb.simulate('mouseup');
const signal = Object.values(component.state("signals"))[0]; const signal = Object.values(component.state('signals'))[0];
expect(signal).toBeDefined(); expect(signal).toBeDefined();
expect(signal.size).toBe(8); expect(signal.size).toBe(8);
expect(signal.isLittleEndian).toBe(true); expect(signal.isLittleEndian).toBe(true);
expect(signal.startBit).toBe(0); expect(signal.startBit).toBe(0);
}); });
test("dragging the msb of a 2-bit little endian signal to a lower byte should not change the signal", () => { test('dragging the msb of a 2-bit little endian signal to a lower byte should not change the signal', () => {
const component = createAddSignals(); const component = createAddSignals();
component component
.instance() .instance()
.createSignal({ startBit: 14, size: 2, isLittleEndian: true }); .createSignal({ startBit: 14, size: 2, isLittleEndian: true });
const msb = component.find(".bit").at(8); const msb = component.find('.bit').at(8);
msb.simulate("mousedown"); msb.simulate('mousedown');
const bitOutOfBounds = component.find(".bit").at(0); const bitOutOfBounds = component.find('.bit').at(0);
bitOutOfBounds.simulate("mouseenter"); bitOutOfBounds.simulate('mouseenter');
bitOutOfBounds.simulate("mouseup"); bitOutOfBounds.simulate('mouseup');
const signal = Object.values(component.state("signals"))[0]; const signal = Object.values(component.state('signals'))[0];
expect(signal).toBeDefined(); expect(signal).toBeDefined();
expect(signal.size).toBe(2); expect(signal.size).toBe(2);
expect(signal.isLittleEndian).toBe(true); expect(signal.isLittleEndian).toBe(true);

View File

@ -1,9 +1,10 @@
global.__JEST__ = 1; import React from 'react';
import CanExplorer from "../../CanExplorer"; import { shallow, mount, render } from 'enzyme';
import React from "react"; import { StyleSheetTestUtils } from 'aphrodite';
import { shallow, mount, render } from "enzyme"; import CanExplorer from '../../CanExplorer';
import { StyleSheetTestUtils } from "aphrodite";
test("CanExplorer renders", () => { global.__JEST__ = 1;
test('CanExplorer renders', () => {
const canExplorer = shallow(<CanExplorer />); const canExplorer = shallow(<CanExplorer />);
}); });

View File

@ -1,10 +1,10 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import CanGraph from '../../components/CanGraph';
global.__JEST__ = 1; global.__JEST__ = 1;
import CanGraph from "../../components/CanGraph"; test('CanGraph successfully mounts with minimal default props', () => {
import React from "react";
import { shallow, mount, render } from "enzyme";
test("CanGraph successfully mounts with minimal default props", () => {
const component = shallow( const component = shallow(
<CanGraph <CanGraph
onGraphRefAvailable={() => {}} onGraphRefAvailable={() => {}}
@ -24,7 +24,7 @@ test("CanGraph successfully mounts with minimal default props", () => {
dragPos={null} dragPos={null}
canReceiveGraphDrop={false} canReceiveGraphDrop={false}
plottedSignals={[]} plottedSignals={[]}
live={true} live
/> />
); );
expect(component.exists()).toBe(true); expect(component.exists()).toBe(true);

View File

@ -1,10 +1,10 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import CanGraphList from '../../components/CanGraphList';
global.__JEST__ = 1; global.__JEST__ = 1;
import CanGraphList from "../../components/CanGraphList"; test('CanGraphList successfully mounts with minimal default props', () => {
import React from "react";
import { shallow, mount, render } from "enzyme";
test("CanGraphList successfully mounts with minimal default props", () => {
const component = shallow( const component = shallow(
<CanGraphList <CanGraphList
plottedSignals={[]} plottedSignals={[]}
@ -16,7 +16,7 @@ test("CanGraphList successfully mounts with minimal default props", () => {
onSignalUnplotPressed={() => {}} onSignalUnplotPressed={() => {}}
segment={[]} segment={[]}
mergePlots={() => {}} mergePlots={() => {}}
live={true} live
/> />
); );
expect(component.exists()).toBe(true); expect(component.exists()).toBe(true);

View File

@ -1,10 +1,10 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import CanLog from '../../components/CanLog';
global.__JEST__ = 1; global.__JEST__ = 1;
import CanLog from "../../components/CanLog"; test('CanLog successfully mounts with minimal default props', () => {
import React from "react";
import { shallow, mount, render } from "enzyme";
test("CanLog successfully mounts with minimal default props", () => {
const component = shallow( const component = shallow(
<CanLog <CanLog
message={null} message={null}

View File

@ -1,10 +1,10 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import DbcUpload from '../../components/DbcUpload';
global.__JEST__ = 1; global.__JEST__ = 1;
import DbcUpload from "../../components/DbcUpload"; test('DbcUpload successfully mounts with minimal default props', () => {
import React from "react";
import { shallow, mount, render } from "enzyme";
test("DbcUpload successfully mounts with minimal default props", () => {
const component = shallow(<DbcUpload />); const component = shallow(<DbcUpload />);
expect(component.exists()).toBe(true); expect(component.exists()).toBe(true);
}); });

View File

@ -1,15 +1,15 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import EditMessageModal from '../../components/EditMessageModal';
import DbcUtils from '../../utils/dbc';
import DBC from '../../models/can/dbc';
global.__JEST__ = 1; global.__JEST__ = 1;
import EditMessageModal from "../../components/EditMessageModal"; test('EditMessageModal successfully mounts with minimal default props', () => {
import React from "react";
import { shallow, mount, render } from "enzyme";
import DbcUtils from "../../utils/dbc";
import DBC from "../../models/can/dbc";
test("EditMessageModal successfully mounts with minimal default props", () => {
const dbc = new DBC(); const dbc = new DBC();
const frame = dbc.createFrame(0); const frame = dbc.createFrame(0);
const message = DbcUtils.createMessageSpec(dbc, 0, "0", 1); const message = DbcUtils.createMessageSpec(dbc, 0, '0', 1);
const component = shallow( const component = shallow(
<EditMessageModal <EditMessageModal

View File

@ -1,15 +1,15 @@
import React from 'react';
import Moment from 'moment';
import { shallow, mount, render } from 'enzyme';
import Explorer from '../../components/Explorer';
global.__JEST__ = 1; global.__JEST__ = 1;
import Explorer from "../../components/Explorer"; test('Explorer successfully mounts with minimal default props', () => {
import React from "react";
import Moment from "moment";
import { shallow, mount, render } from "enzyme";
test("Explorer successfully mounts with minimal default props", () => {
const component = shallow( const component = shallow(
<Explorer <Explorer
url={null} url={null}
live={true} live
messages={{}} messages={{}}
selectedMessage={null} selectedMessage={null}
onConfirmedSignalChange={() => {}} onConfirmedSignalChange={() => {}}
@ -21,7 +21,7 @@ test("Explorer successfully mounts with minimal default props", () => {
seekIndex={0} seekIndex={0}
currentParts={[0, 0]} currentParts={[0, 0]}
partsLoaded={0} partsLoaded={0}
autoplay={true} autoplay
showEditMessageModal={() => {}} showEditMessageModal={() => {}}
onPartChange={() => {}} onPartChange={() => {}}
routeStartTime={Moment()} routeStartTime={Moment()}

View File

@ -1,12 +1,12 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import GithubDbcList from '../../components/GithubDbcList';
import OpenDbc from '../../api/OpenDbc';
global.__JEST__ = 1; global.__JEST__ = 1;
import GithubDbcList from "../../components/GithubDbcList"; test('GithubDbcList successfully mounts with minimal default props', () => {
import React from "react";
import { shallow, mount, render } from "enzyme";
import OpenDbc from "../../api/OpenDbc";
test("GithubDbcList successfully mounts with minimal default props", () => {
const openDbcClient = new OpenDbc(null); const openDbcClient = new OpenDbc(null);
const component = shallow( const component = shallow(

View File

@ -1,11 +1,11 @@
import HLS from "../../components/HLS"; import React from 'react';
import React from "react"; import { shallow, mount, render } from 'enzyme';
import { shallow, mount, render } from "enzyme"; import HLS from '../../components/HLS';
test("HLS successfully mounts with minimal default props", () => { test('HLS successfully mounts with minimal default props', () => {
const component = shallow( const component = shallow(
<HLS <HLS
source={"http://comma.ai"} source="http://comma.ai"
startTime={0} startTime={0}
playbackSpeed={1} playbackSpeed={1}
onVideoElementAvailable={() => {}} onVideoElementAvailable={() => {}}

View File

@ -1,12 +1,12 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import LoadDbcModal from '../../components/LoadDbcModal';
import OpenDbc from '../../api/OpenDbc';
global.__JEST__ = 1; global.__JEST__ = 1;
import React from "react"; test('LoadDbcModal successfully mounts with minimal default props', () => {
import { shallow, mount, render } from "enzyme";
import LoadDbcModal from "../../components/LoadDbcModal";
import OpenDbc from "../../api/OpenDbc";
test("LoadDbcModal successfully mounts with minimal default props", () => {
const openDbcClient = new OpenDbc(null); const openDbcClient = new OpenDbc(null);
const component = shallow( const component = shallow(
<LoadDbcModal <LoadDbcModal

View File

@ -1,8 +1,8 @@
import LoadingBar from "../../components/LoadingBar"; import React from 'react';
import React from "react"; import { shallow, mount, render } from 'enzyme';
import { shallow, mount, render } from "enzyme"; import LoadingBar from '../../components/LoadingBar';
test("LoadingBar successfully mounts with minimal default props", () => { test('LoadingBar successfully mounts with minimal default props', () => {
const component = shallow(<LoadingBar />); const component = shallow(<LoadingBar />);
expect(component.exists()).toBe(true); expect(component.exists()).toBe(true);
}); });

View File

@ -1,16 +1,16 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import MessageBytes from '../../components/MessageBytes';
import DbcUtils from '../../utils/dbc';
import DBC from '../../models/can/dbc';
global.__JEST__ = 1; global.__JEST__ = 1;
import React from "react"; test('MessageBytes successfully mounts with minimal default props', () => {
import { shallow, mount, render } from "enzyme"; const message = DbcUtils.createMessageSpec(new DBC(), 0, '0', 1);
import MessageBytes from "../../components/MessageBytes";
import DbcUtils from "../../utils/dbc";
import DBC from "../../models/can/dbc";
test("MessageBytes successfully mounts with minimal default props", () => {
const message = DbcUtils.createMessageSpec(new DBC(), 0, "0", 1);
const component = shallow( const component = shallow(
<MessageBytes seekTime={0} message={message} live={true} /> <MessageBytes seekTime={0} message={message} live />
); );
expect(component.exists()).toBe(true); expect(component.exists()).toBe(true);
}); });

View File

@ -1,10 +1,10 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import Meta from '../../components/Meta';
global.__JEST__ = 1; global.__JEST__ = 1;
import Meta from "../../components/Meta"; test('Meta successfully mounts with minimal default props', () => {
import React from "react";
import { shallow, mount, render } from "enzyme";
test("Meta successfully mounts with minimal default props", () => {
const component = shallow( const component = shallow(
<Meta <Meta
url={null} url={null}
@ -26,7 +26,7 @@ test("Meta successfully mounts with minimal default props", () => {
seekIndex={0} seekIndex={0}
maxByteStateChangeCount={0} maxByteStateChangeCount={0}
isDemo={false} isDemo={false}
live={true} live
/> />
); );
expect(component.exists()).toBe(true); expect(component.exists()).toBe(true);

View File

@ -1,10 +1,10 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import PartSelector from '../../components/PartSelector';
global.__JEST__ = 1; global.__JEST__ = 1;
import PartSelector from "../../components/PartSelector"; test('PartSelector successfully mounts with minimal default props', () => {
import React from "react";
import { shallow, mount, render } from "enzyme";
test("PartSelector successfully mounts with minimal default props", () => {
const component = shallow( const component = shallow(
<PartSelector onPartChange={() => {}} partsCount={0} selectedPart={0} /> <PartSelector onPartChange={() => {}} partsCount={0} selectedPart={0} />
); );

View File

@ -1,10 +1,10 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import PlayButton from '../../components/PlayButton';
global.__JEST__ = 1; global.__JEST__ = 1;
import PlayButton from "../../components/PlayButton"; test('PlayButton successfully mounts with minimal default props', () => {
import React from "react";
import { shallow, mount, render } from "enzyme";
test("PlayButton successfully mounts with minimal default props", () => {
const component = shallow(<PlayButton />); const component = shallow(<PlayButton />);
expect(component.exists()).toBe(true); expect(component.exists()).toBe(true);
}); });

View File

@ -1,10 +1,10 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import RouteSeeker from '../../components/RouteSeeker';
global.__JEST__ = 1; global.__JEST__ = 1;
import RouteSeeker from "../../components/RouteSeeker"; test('RouteSeeker successfully mounts with minimal default props', () => {
import React from "react";
import { shallow, mount, render } from "enzyme";
test("RouteSeeker successfully mounts with minimal default props", () => {
const component = shallow( const component = shallow(
<RouteSeeker <RouteSeeker
nearestFrameTime={0} nearestFrameTime={0}

View File

@ -1,10 +1,10 @@
global.__JEST__ = 1; import API from '@commaai/comma-api';
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import { StyleSheetTestUtils } from 'aphrodite';
import RouteVideoSync from '../../components/RouteVideoSync';
import API from "@commaai/comma-api"; global.__JEST__ = 1;
import RouteVideoSync from "../../components/RouteVideoSync";
import React from "react";
import { shallow, mount, render } from "enzyme";
import { StyleSheetTestUtils } from "aphrodite";
// Prevents style injection from firing after test finishes // Prevents style injection from firing after test finishes
// and jsdom is torn down. // and jsdom is torn down.
@ -15,7 +15,7 @@ afterEach(() => {
StyleSheetTestUtils.clearBufferAndResumeStyleInjection(); StyleSheetTestUtils.clearBufferAndResumeStyleInjection();
}); });
test("RouteVideoSync successfully mounts with minimal default props", () => { test('RouteVideoSync successfully mounts with minimal default props', () => {
const component = shallow( const component = shallow(
<RouteVideoSync <RouteVideoSync
message={null} message={null}
@ -26,7 +26,7 @@ test("RouteVideoSync successfully mounts with minimal default props", () => {
userSeekIndex={0} userSeekIndex={0}
playing={false} playing={false}
playSpeed={1} playSpeed={1}
url={"http://comma.ai"} url="http://comma.ai"
canFrameOffset={0} canFrameOffset={0}
firstCanTime={0} firstCanTime={0}
onVideoClick={() => {}} onVideoClick={() => {}}

View File

@ -1,19 +1,19 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import SaveDbcModal from '../../components/SaveDbcModal';
import OpenDbc from '../../api/OpenDbc';
import DBC from '../../models/can/dbc';
global.__JEST__ = 1; global.__JEST__ = 1;
import React from "react"; test('SaveDbcModal successfully mounts with minimal default props', () => {
import { shallow, mount, render } from "enzyme";
import SaveDbcModal from "../../components/SaveDbcModal";
import OpenDbc from "../../api/OpenDbc";
import DBC from "../../models/can/dbc";
test("SaveDbcModal successfully mounts with minimal default props", () => {
const openDbcClient = new OpenDbc(null); const openDbcClient = new OpenDbc(null);
const dbc = new DBC(); const dbc = new DBC();
const component = shallow( const component = shallow(
<SaveDbcModal <SaveDbcModal
dbc={dbc} dbc={dbc}
sourceDbcFilename={""} sourceDbcFilename=""
onDbcSaved={() => {}} onDbcSaved={() => {}}
handleClose={() => {}} handleClose={() => {}}
openDbcClient={openDbcClient} openDbcClient={openDbcClient}

View File

@ -1,10 +1,10 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import SignalLegend from '../../components/SignalLegend';
global.__JEST__ = 1; global.__JEST__ = 1;
import SignalLegend from "../../components/SignalLegend"; test('SignalLegend successfully mounts with minimal default props', () => {
import React from "react";
import { shallow, mount, render } from "enzyme";
test("SignalLegend successfully mounts with minimal default props", () => {
const component = shallow( const component = shallow(
<SignalLegend <SignalLegend
signals={{}} signals={{}}

View File

@ -1,6 +1,6 @@
import { shade } from "../../utils/color"; import { shade } from '../../utils/color';
test("Shade darkens rgb white (255,255,255)", () => { test('Shade darkens rgb white (255,255,255)', () => {
const rgb = [255, 255, 255]; const rgb = [255, 255, 255];
const darkenRgb = shade(rgb, -0.5); const darkenRgb = shade(rgb, -0.5);

View File

@ -1,21 +1,23 @@
global.__JEST__ = 1; import extend from 'xtend';
import DbcUtils from '../../utils/dbc';
import DBC from '../../models/can/dbc';
import Signal from '../../models/can/signal';
import DbcUtils from "../../utils/dbc"; global.__JEST__ = 1;
import DBC from "../../models/can/dbc";
import Signal from "../../models/can/signal";
import extend from "xtend";
// want to mock pandareader and test processStreamedCanMessages // want to mock pandareader and test processStreamedCanMessages
const SAMPLE_MESSAGE = { const SAMPLE_MESSAGE = {
address: 0x10, address: 0x10,
busTime: 0, busTime: 0,
data: Buffer.from("abababababababab", "hex"), data: Buffer.from('abababababababab', 'hex'),
bus: 1 bus: 1
}; };
const SAMPLE_MESSAGE_ID = "1:10"; const SAMPLE_MESSAGE_ID = '1:10';
function expectSampleMessageFieldsPreserved(messages, frame) { function expectSampleMessageFieldsPreserved(messages, frame) {
const { address, busTime, data, bus } = SAMPLE_MESSAGE; const {
address, busTime, data, bus
} = SAMPLE_MESSAGE;
expect(messages[SAMPLE_MESSAGE_ID].address).toEqual(address); expect(messages[SAMPLE_MESSAGE_ID].address).toEqual(address);
expect(messages[SAMPLE_MESSAGE_ID].id).toEqual(SAMPLE_MESSAGE_ID); expect(messages[SAMPLE_MESSAGE_ID].id).toEqual(SAMPLE_MESSAGE_ID);
expect(messages[SAMPLE_MESSAGE_ID].bus).toEqual(bus); expect(messages[SAMPLE_MESSAGE_ID].bus).toEqual(bus);
@ -28,7 +30,7 @@ function expectSampleMessageFieldsPreserved(messages, frame) {
// function addCanMessage([address, busTime, data, bus], dbc, canStartTime, messages, prevMsgEntries, byteStateChangeCountsByMessage) { // function addCanMessage([address, busTime, data, bus], dbc, canStartTime, messages, prevMsgEntries, byteStateChangeCountsByMessage) {
function addMessages(messages, message, dbc, n) { function addMessages(messages, message, dbc, n) {
const firstCanTime = 0; const firstCanTime = 0;
let nextMessage = () => { const nextMessage = () => {
message = extend(message); message = extend(message);
message.busTime += 1; message.busTime += 1;
return message; return message;
@ -38,7 +40,7 @@ function addMessages(messages, message, dbc, n) {
DbcUtils.addCanMessage(nextMessage(), dbc, firstCanTime, messages, {}, {}); DbcUtils.addCanMessage(nextMessage(), dbc, firstCanTime, messages, {}, {});
} }
} }
test("addCanMessage should add raw can message with empty dbc", () => { test('addCanMessage should add raw can message with empty dbc', () => {
const messages = {}; const messages = {};
addMessages(messages, SAMPLE_MESSAGE, new DBC(), 1); addMessages(messages, SAMPLE_MESSAGE, new DBC(), 1);
@ -46,7 +48,7 @@ test("addCanMessage should add raw can message with empty dbc", () => {
expectSampleMessageFieldsPreserved(messages); expectSampleMessageFieldsPreserved(messages);
}); });
test("addCanMessage should add multiple raw can messages with empty dbc", () => { test('addCanMessage should add multiple raw can messages with empty dbc', () => {
const messages = {}; const messages = {};
addMessages(messages, SAMPLE_MESSAGE, new DBC(), 3); addMessages(messages, SAMPLE_MESSAGE, new DBC(), 3);
@ -54,12 +56,12 @@ test("addCanMessage should add multiple raw can messages with empty dbc", () =>
expectSampleMessageFieldsPreserved(messages); expectSampleMessageFieldsPreserved(messages);
}); });
test("addCanMessage should add parsed can message with dbc containing message spec", () => { test('addCanMessage should add parsed can message with dbc containing message spec', () => {
const messages = {}; const messages = {};
// create dbc with message spec and signal for sample_message // create dbc with message spec and signal for sample_message
const dbc = new DBC(); const dbc = new DBC();
dbc.createFrame(SAMPLE_MESSAGE.address); dbc.createFrame(SAMPLE_MESSAGE.address);
const signal = new Signal({ name: "NEW_SIGNAL", startBit: 0, size: 8 }); const signal = new Signal({ name: 'NEW_SIGNAL', startBit: 0, size: 8 });
dbc.addSignal(SAMPLE_MESSAGE.address, signal); dbc.addSignal(SAMPLE_MESSAGE.address, signal);
// add 1 sample_message // add 1 sample_message

View File

@ -1,4 +1,4 @@
import DBC from "./models/can/dbc"; import DBC from './models/can/dbc';
const AcuraDbc = new DBC(` const AcuraDbc = new DBC(`
VERSION "" VERSION ""

View File

@ -1,12 +1,12 @@
import GitHub from "github-api"; import GitHub from 'github-api';
import { OPENDBC_SOURCE_REPO } from "../config"; import { OPENDBC_SOURCE_REPO } from '../config';
export default class OpenDBC { export default class OpenDBC {
constructor(token) { constructor(token) {
this.token = token; this.token = token;
this.github = new GitHub({ token }); this.github = new GitHub({ token });
this.sourceRepo = this.github.getRepo("commaai", "opendbc"); this.sourceRepo = this.github.getRepo('commaai', 'opendbc');
this.githubUsername = null; this.githubUsername = null;
} }
@ -17,11 +17,10 @@ export default class OpenDBC {
async getGithubUsername() { async getGithubUsername() {
if (this.githubUsername) { if (this.githubUsername) {
return this.githubUsername; return this.githubUsername;
} else { }
const githubUsername = await this.fetchGithubUsername(); const githubUsername = await this.fetchGithubUsername();
if (githubUsername) { if (githubUsername) {
return githubUsername; return githubUsername;
}
} }
} }
@ -50,13 +49,13 @@ export default class OpenDBC {
if (repoFullName === undefined) { if (repoFullName === undefined) {
repo = this.sourceRepo; repo = this.sourceRepo;
} else { } else {
const [username, repoName] = repoFullName.split("/"); const [username, repoName] = repoFullName.split('/');
repo = this.github.getRepo(username, repoName); repo = this.github.getRepo(username, repoName);
} }
try { try {
const response = await repo.getContents("master", ""); const response = await repo.getContents('master', '');
return response.data.map(content => content.path); return response.data.map((content) => content.path);
} catch (e) { } catch (e) {
return []; return [];
} }
@ -67,15 +66,15 @@ export default class OpenDBC {
if (repoFullName === undefined) { if (repoFullName === undefined) {
repo = this.sourceRepo; repo = this.sourceRepo;
} else { } else {
const [username, repoName] = repoFullName.split("/"); const [username, repoName] = repoFullName.split('/');
repo = this.github.getRepo(username, repoName); repo = this.github.getRepo(username, repoName);
} }
const fileContents = await repo.getContents("master", dbcPath); const fileContents = await repo.getContents('master', dbcPath);
const rawContentsUrl = fileContents.data.download_url; const rawContentsUrl = fileContents.data.download_url;
const resp = await fetch(rawContentsUrl, { cache: "no-cache" }); const resp = await fetch(rawContentsUrl, { cache: 'no-cache' });
return resp.text(); return resp.text();
} }
@ -90,24 +89,22 @@ export default class OpenDBC {
const githubUsername = await this.getGithubUsername(); const githubUsername = await this.getGithubUsername();
if (!githubUsername) return null; if (!githubUsername) return null;
const openDbcFork = this.github.getRepo(githubUsername, "opendbc"); const openDbcFork = this.github.getRepo(githubUsername, 'opendbc');
const repoDetailResp = await openDbcFork.getDetails(); const repoDetailResp = await openDbcFork.getDetails();
const repoDetails = repoDetailResp.data; const repoDetails = repoDetailResp.data;
if (this.repoSourceIsOpenDbc(repoDetails)) { if (this.repoSourceIsOpenDbc(repoDetails)) {
return repoDetails.full_name; return repoDetails.full_name;
} else {
return null;
} }
return null;
} }
async fork() { async fork() {
const forkResponse = await this.sourceRepo.fork(); const forkResponse = await this.sourceRepo.fork();
if (forkResponse.status === 202) { if (forkResponse.status === 202) {
return true; return true;
} else {
return false;
} }
return false;
} }
async commitFile(repoFullName, path, contents, commitMessage) { async commitFile(repoFullName, path, contents, commitMessage) {
@ -115,11 +112,11 @@ export default class OpenDBC {
repo is of format username/reponame repo is of format username/reponame
authenciated user must have write access to repo authenciated user must have write access to repo
*/ */
const [user, repoName] = repoFullName.split("/"); const [user, repoName] = repoFullName.split('/');
const repo = this.github.getRepo(user, repoName); const repo = this.github.getRepo(user, repoName);
// get HEAD reference // get HEAD reference
const refResp = await repo.getRef("heads/master"); const refResp = await repo.getRef('heads/master');
const ref = refResp.data; const ref = refResp.data;
// get HEAD commit sha // get HEAD commit sha
@ -133,9 +130,9 @@ export default class OpenDBC {
// create new tree // create new tree
const tree = [ const tree = [
{ {
mode: "100644", mode: '100644',
path: path, path,
type: "blob", type: 'blob',
content: contents content: contents
} }
]; ];
@ -147,13 +144,13 @@ export default class OpenDBC {
const commitResp = await repo.commit( const commitResp = await repo.commit(
headCommit.sha, headCommit.sha,
createdTree.sha, createdTree.sha,
commitMessage || "OpenDBC updates" commitMessage || 'OpenDBC updates'
); );
const commit = commitResp.data; const commit = commitResp.data;
// update HEAD // update HEAD
const updateHeadResp = await repo.updateHead( const updateHeadResp = await repo.updateHead(
"heads/master", 'heads/master',
commit.sha, commit.sha,
false false
); );

View File

@ -1,11 +1,11 @@
import { GITHUB_CLIENT_ID, GITHUB_REDIRECT_URL } from "../config"; import { GITHUB_CLIENT_ID, GITHUB_REDIRECT_URL } from '../config';
import { objToQuery } from "../utils/url"; import { objToQuery } from '../utils/url';
export function authorizeUrl(route) { export function authorizeUrl(route) {
const params = { const params = {
client_id: GITHUB_CLIENT_ID, client_id: GITHUB_CLIENT_ID,
redirect_uri: GITHUB_REDIRECT_URL, redirect_uri: GITHUB_REDIRECT_URL,
scope: "user:email public_repo", scope: 'user:email public_repo',
state: JSON.stringify({ route }) state: JSON.stringify({ route })
}; };

View File

@ -1,4 +1,4 @@
import DBC from "../models/can/dbc"; import DBC from '../models/can/dbc';
export function fetchPersistedDbc(routeName) { export function fetchPersistedDbc(routeName) {
const maybeDbc = window.localStorage.getItem(routeName); const maybeDbc = window.localStorage.getItem(routeName);
@ -7,7 +7,8 @@ export function fetchPersistedDbc(routeName) {
const dbc = new DBC(dbcText); const dbc = new DBC(dbcText);
return { dbc, dbcText, dbcFilename }; return { dbc, dbcText, dbcFilename };
} else return null; }
return null;
} }
export function persistDbc(routeName, { dbcFilename, dbc }) { export function persistDbc(routeName, { dbcFilename, dbc }) {
@ -18,7 +19,7 @@ export function persistDbc(routeName, { dbcFilename, dbc }) {
window.localStorage.setItem(routeName, dbcJson); window.localStorage.setItem(routeName, dbcJson);
} }
const GITHUB_AUTH_TOKEN_LOCALSTORAGE_KEY = "gh_auth_token"; const GITHUB_AUTH_TOKEN_LOCALSTORAGE_KEY = 'gh_auth_token';
export function fetchPersistedGithubAuthToken() { export function fetchPersistedGithubAuthToken() {
return window.localStorage.getItem(GITHUB_AUTH_TOKEN_LOCALSTORAGE_KEY); return window.localStorage.getItem(GITHUB_AUTH_TOKEN_LOCALSTORAGE_KEY);
} }

View File

@ -1,13 +1,13 @@
import { raw as RawDataApi, request as Request } from "@commaai/comma-api"; import { raw as RawDataApi, request as Request } from '@commaai/comma-api';
import CommaAuth from "@commaai/my-comma-auth"; import CommaAuth from '@commaai/my-comma-auth';
import request from "simple-get"; import request from 'simple-get';
const urlStore = {}; const urlStore = {};
var initPromise; let initPromise;
function ensureInit() { function ensureInit() {
if (!initPromise) { if (!initPromise) {
initPromise = CommaAuth.init().then(function(token) { initPromise = CommaAuth.init().then((token) => {
Request.configure(token); Request.configure(token);
return Promise.resolve(); return Promise.resolve();
}); });
@ -16,8 +16,8 @@ function ensureInit() {
} }
export async function getLogPart(logUrl) { export async function getLogPart(logUrl) {
return new Promise(async function(resolve, reject) { return new Promise(async (resolve, reject) => {
request(logUrl, function(err, res) { request(logUrl, (err, res) => {
if (err) { if (err) {
return reject(err); return reject(err);
} }

View File

@ -1,5 +1,5 @@
import SocketIO from "socket.io-client"; import SocketIO from 'socket.io-client';
import { UNLOGGER_HOST } from "../config"; import { UNLOGGER_HOST } from '../config';
export default class UnloggerClient { export default class UnloggerClient {
constructor() { constructor() {
@ -7,6 +7,6 @@ export default class UnloggerClient {
} }
seek(dongleId, baseTime, seekSeconds) { seek(dongleId, baseTime, seekSeconds) {
this.socket.emit("seek", dongleId, baseTime, seekSeconds); this.socket.emit('seek', dongleId, baseTime, seekSeconds);
} }
} }

View File

@ -1,4 +1,4 @@
import DBC from "./models/can/dbc"; import DBC from './models/can/dbc';
const CivicDbc = new DBC(` const CivicDbc = new DBC(`
VERSION "" VERSION ""

View File

@ -1,12 +1,12 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import { StyleSheet } from "aphrodite/no-important"; import { StyleSheet } from 'aphrodite/no-important';
import css from "../utils/css"; import css from '../utils/css';
import SignalLegend from "./SignalLegend"; import SignalLegend from './SignalLegend';
import Signal from "../models/can/signal"; import Signal from '../models/can/signal';
import { shade } from "../utils/color"; import { shade } from '../utils/color';
import DbcUtils from "../utils/dbc"; import DbcUtils from '../utils/dbc';
/* /*
AddSignals component draws an 8x8 matrix AddSignals component draws an 8x8 matrix
@ -20,25 +20,25 @@ const Styles = StyleSheet.create({
bit: { bit: {
margin: 0, margin: 0,
padding: 12, padding: 12,
userSelect: "none", userSelect: 'none',
cursor: "pointer", cursor: 'pointer',
textAlign: "center", textAlign: 'center',
position: "relative" position: 'relative'
}, },
bitSelectedStyle: { bitSelectedStyle: {
backgroundColor: "rgba(0,119,158,0.5)" backgroundColor: 'rgba(0,119,158,0.5)'
}, },
bitSignificance: { bitSignificance: {
fontSize: 12, fontSize: 12,
display: "block", display: 'block',
position: "absolute", position: 'absolute',
bottom: 0, bottom: 0,
left: 0, left: 0,
right: 0, right: 0,
margin: "0 auto" margin: '0 auto'
}, },
highlightedSignalTitle: { highlightedSignalTitle: {
backgroundColor: "rgba(0,0,0,0.2)" backgroundColor: 'rgba(0,0,0,0.2)'
} }
}); });
@ -61,7 +61,7 @@ export default class AddSignals extends Component {
this.state = { this.state = {
bits: [], bits: [],
signals: signals, signals,
signalStyles: this.calcSignalStyles(signals), signalStyles: this.calcSignalStyles(signals),
highlightedSignal: null, highlightedSignal: null,
dragStartBit: null, dragStartBit: null,
@ -82,28 +82,29 @@ export default class AddSignals extends Component {
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
return ( return (
nextProps.message.hexData !== this.props.message.hexData || nextProps.message.hexData !== this.props.message.hexData
nextProps.messageIndex !== this.props.messageIndex || || nextProps.messageIndex !== this.props.messageIndex
JSON.stringify(nextProps.plottedSignalUids) !== || JSON.stringify(nextProps.plottedSignalUids)
JSON.stringify(this.props.plottedSignalUids) || !== JSON.stringify(this.props.plottedSignalUids)
JSON.stringify(this.state) !== JSON.stringify(nextState) || JSON.stringify(this.state) !== JSON.stringify(nextState)
); );
} }
signalColorStyle(signal) { signalColorStyle(signal) {
const { colors } = signal; const { colors } = signal;
let colorRgbStr, backgroundColor; let colorRgbStr;
let backgroundColor;
if (this.state && this.state.highlightedSignal === signal.name) { if (this.state && this.state.highlightedSignal === signal.name) {
// when signal highlighted, // when signal highlighted,
// darkened background and lightened text. // darkened background and lightened text.
const darkenedColors = shade(colors, -0.5); const darkenedColors = shade(colors, -0.5);
const lightenedColors = shade(colors, 0.9); const lightenedColors = shade(colors, 0.9);
colorRgbStr = `rgb(${lightenedColors.join(",")})`; colorRgbStr = `rgb(${lightenedColors.join(',')})`;
backgroundColor = `rgba(${darkenedColors.join(",")},0.5)`; backgroundColor = `rgba(${darkenedColors.join(',')},0.5)`;
} else { } else {
const colorsCommaSep = colors.join(","); const colorsCommaSep = colors.join(',');
colorRgbStr = `rgb(${colorsCommaSep})`; colorRgbStr = `rgb(${colorsCommaSep})`;
backgroundColor = `rgba(${colorsCommaSep},0.2)`; backgroundColor = `rgba(${colorsCommaSep},0.2)`;
} }
@ -122,7 +123,7 @@ export default class AddSignals extends Component {
calcSignalStyles(signals) { calcSignalStyles(signals) {
const signalStyles = {}; const signalStyles = {};
Object.values(signals).forEach(signal => { Object.values(signals).forEach((signal) => {
signalStyles[signal.name] = this.signalColorStyle(signal); signalStyles[signal.name] = this.signalColorStyle(signal);
}); });
@ -145,12 +146,12 @@ export default class AddSignals extends Component {
// bitIdx in [0,64) // bitIdx in [0,64)
// returns instance of Signal // returns instance of Signal
return Object.values(this.state.signals).filter(signal => { return Object.values(this.state.signals).filter(
return signal.bitDescription(bitIdx) !== null; (signal) => signal.bitDescription(bitIdx) !== null
})[0]; )[0];
} }
onSignalHover = signal => { onSignalHover = (signal) => {
if (!signal) return; if (!signal) return;
this.setState({ highlightedSignal: signal.name }, this.updateSignalStyles); this.setState({ highlightedSignal: signal.name }, this.updateSignalStyles);
@ -214,22 +215,20 @@ export default class AddSignals extends Component {
dragSignal.size = bitIdx - dragStartBit + 1; dragSignal.size = bitIdx - dragStartBit + 1;
dragStartBit = bitIdx; dragStartBit = bitIdx;
} }
} else if (dragSignal.isLittleEndian) {
dragSignal.startBit = bitIdx;
dragSignal.size = dragStartBit - bitIdx + 1;
dragStartBit = bitIdx;
} else { } else {
if (dragSignal.isLittleEndian) { dragSignal.size = dragStartBit - bitIdx + 1;
dragSignal.startBit = bitIdx; dragStartBit = bitIdx;
dragSignal.size = dragStartBit - bitIdx + 1;
dragStartBit = bitIdx;
} else {
dragSignal.size = dragStartBit - bitIdx + 1;
dragStartBit = bitIdx;
}
} }
} }
signals[dragSignal.name] = dragSignal; signals[dragSignal.name] = dragSignal;
} else if ( } else if (
dragSignal.isLittleEndian && dragSignal.isLittleEndian
dragStartBit === dragSignal.msbBitIndex() && dragStartBit === dragSignal.msbBitIndex()
) { ) {
if (bitIdx < dragSignal.startBit) { if (bitIdx < dragSignal.startBit) {
// should not be able to drag the MSB past the LSB // should not be able to drag the MSB past the LSB
@ -244,8 +243,8 @@ export default class AddSignals extends Component {
signals[dragSignal.name] = dragSignal; signals[dragSignal.name] = dragSignal;
dragStartBit = dragSignal.msbBitIndex(); dragStartBit = dragSignal.msbBitIndex();
} else if ( } else if (
!dragSignal.isLittleEndian && !dragSignal.isLittleEndian
dragStartBit === dragSignal.lsbBitIndex() && dragStartBit === dragSignal.lsbBitIndex()
) { ) {
const diff = bitIdx - dragStartBit; const diff = bitIdx - dragStartBit;
if (dragSignal.bitDescription(bitIdx) === null) { if (dragSignal.bitDescription(bitIdx) === null) {
@ -271,7 +270,7 @@ export default class AddSignals extends Component {
} }
}; };
onSignalHoverEnd = signal => { onSignalHoverEnd = (signal) => {
if (!signal) return; if (!signal) return;
this.setState({ highlightedSignal: null }, this.updateSignalStyles); this.setState({ highlightedSignal: null }, this.updateSignalStyles);
@ -279,10 +278,10 @@ export default class AddSignals extends Component {
nextNewSignalName() { nextNewSignalName() {
const existingNames = Object.keys(this.state.signals); const existingNames = Object.keys(this.state.signals);
let signalNum = 1, let signalNum = 1;
signalName; let signalName;
do { do {
signalName = "NEW_SIGNAL_" + signalNum; signalName = `NEW_SIGNAL_${signalNum}`;
signalNum++; signalNum++;
} while (existingNames.indexOf(signalName) !== -1); } while (existingNames.indexOf(signalName) !== -1);
@ -300,7 +299,7 @@ export default class AddSignals extends Component {
const signal = new Signal({ const signal = new Signal({
name: this.nextNewSignalName(), name: this.nextNewSignalName(),
startBit, startBit,
size: size, size,
isLittleEndian isLittleEndian
}); });
let { signals } = this.state; let { signals } = this.state;
@ -319,10 +318,8 @@ export default class AddSignals extends Component {
return; return;
} }
} }
const isDragAcrossSingleByte = const isDragAcrossSingleByte = Math.floor(dragEndBit / 8) === Math.floor(dragStartBit / 8);
Math.floor(dragEndBit / 8) === Math.floor(dragStartBit / 8); const isDragDirectionUp = !isDragAcrossSingleByte && dragEndBit < dragStartBit;
const isDragDirectionUp =
!isDragAcrossSingleByte && dragEndBit < dragStartBit;
let isLittleEndian; let isLittleEndian;
if (isDragAcrossSingleByte || !isDragDirectionUp) { if (isDragAcrossSingleByte || !isDragDirectionUp) {
@ -330,30 +327,27 @@ export default class AddSignals extends Component {
} else { } else {
isLittleEndian = dragStartBit % 8 >= 4; isLittleEndian = dragStartBit % 8 >= 4;
} }
let size, let size;
startBit = dragStartBit; let startBit = dragStartBit;
if (isDragAcrossSingleByte) { if (isDragAcrossSingleByte) {
size = Math.abs(dragEndBit - dragStartBit) + 1; size = Math.abs(dragEndBit - dragStartBit) + 1;
} else { } else if (isLittleEndian) {
if (isLittleEndian) { if (dragEndBit > dragStartBit) {
if (dragEndBit > dragStartBit) { startBit = dragStartBit;
startBit = dragStartBit; size = dragEndBit - dragStartBit + 1;
size = dragEndBit - dragStartBit + 1;
} else {
startBit = dragEndBit;
size = dragStartBit - dragEndBit + 1;
}
} else { } else {
if (dragEndBit < dragStartBit) { startBit = dragEndBit;
startBit = dragEndBit; size = dragStartBit - dragEndBit + 1;
}
size =
Math.abs(
DbcUtils.bigEndianBitIndex(dragEndBit) -
DbcUtils.bigEndianBitIndex(dragStartBit)
) + 1;
} }
} else {
if (dragEndBit < dragStartBit) {
startBit = dragEndBit;
}
size = Math.abs(
DbcUtils.bigEndianBitIndex(dragEndBit)
- DbcUtils.bigEndianBitIndex(dragStartBit)
) + 1;
} }
this.createSignal({ startBit, size, isLittleEndian }); this.createSignal({ startBit, size, isLittleEndian });
@ -362,7 +356,7 @@ export default class AddSignals extends Component {
onBitMouseUp(dragEndBit, signal) { onBitMouseUp(dragEndBit, signal) {
if (this.state.dragStartBit !== null) { if (this.state.dragStartBit !== null) {
let { dragStartBit } = this.state; const { dragStartBit } = this.state;
if (dragEndBit !== dragStartBit) { if (dragEndBit !== dragStartBit) {
// one-bit signal requires double click // one-bit signal requires double click
@ -380,24 +374,22 @@ export default class AddSignals extends Component {
const entry = entries[this.props.messageIndex]; const entry = entries[this.props.messageIndex];
return entry.hexData.substr(byteIdx * 2, 2); return entry.hexData.substr(byteIdx * 2, 2);
} else {
return "--";
} }
return '--';
} }
bitValue(byteIdx, byteBitIdx) { bitValue(byteIdx, byteBitIdx) {
const { entries } = this.props.message; const { entries } = this.props.message;
if (this.props.messageIndex < entries.length) { if (this.props.messageIndex < entries.length) {
const entry = entries[this.props.messageIndex]; const entry = entries[this.props.messageIndex];
const data = Buffer.from(entry.hexData, "hex"); const data = Buffer.from(entry.hexData, 'hex');
if (byteIdx >= data.length) { if (byteIdx >= data.length) {
return "-"; return '-';
} }
const byte = data.readInt8(byteIdx); const byte = data.readInt8(byteIdx);
return (byte >> byteBitIdx) & 1; return (byte >> byteBitIdx) & 1;
} else {
return "-";
} }
return '-';
} }
bitIsContainedInSelection(bitIdx, isLittleEndian = false) { bitIsContainedInSelection(bitIdx, isLittleEndian = false) {
@ -405,22 +397,21 @@ export default class AddSignals extends Component {
if (isLittleEndian || dragStartBit % 8 < 4) { if (isLittleEndian || dragStartBit % 8 < 4) {
return ( return (
dragStartBit !== null && dragStartBit !== null
dragCurrentBit !== null && && dragCurrentBit !== null
bitIdx >= dragStartBit && && bitIdx >= dragStartBit
bitIdx <= dragCurrentBit && bitIdx <= dragCurrentBit
);
} else {
const bigEndianStartBit = DbcUtils.bigEndianBitIndex(dragStartBit);
const bigEndianCurrentBit = DbcUtils.bigEndianBitIndex(dragCurrentBit);
const bigEndianBitIdx = DbcUtils.bigEndianBitIndex(bitIdx);
return (
dragStartBit !== null &&
dragCurrentBit !== null &&
bigEndianBitIdx >= bigEndianStartBit &&
bigEndianBitIdx <= bigEndianCurrentBit
); );
} }
const bigEndianStartBit = DbcUtils.bigEndianBitIndex(dragStartBit);
const bigEndianCurrentBit = DbcUtils.bigEndianBitIndex(dragCurrentBit);
const bigEndianBitIdx = DbcUtils.bigEndianBitIndex(bitIdx);
return (
dragStartBit !== null
&& dragCurrentBit !== null
&& bigEndianBitIdx >= bigEndianStartBit
&& bigEndianBitIdx <= bigEndianCurrentBit
);
} }
onBitDoubleClick(startBit, signal) { onBitDoubleClick(startBit, signal) {
@ -434,26 +425,26 @@ export default class AddSignals extends Component {
const rows = []; const rows = [];
let rowCount; let rowCount;
if (message.frame && message.frame.size) { if (message.frame && message.frame.size) {
rowCount = Math.floor(message.frame.size * 8 / 8); rowCount = Math.floor((message.frame.size * 8) / 8);
} else { } else {
rowCount = 8; rowCount = 8;
} }
for (var i = 0; i < rowCount; i++) { for (let i = 0; i < rowCount; i++) {
const rowBits = []; const rowBits = [];
for (var j = 7; j >= 0; j--) { for (let j = 7; j >= 0; j--) {
const bitIdx = i * 8 + j; const bitIdx = i * 8 + j;
const signal = this.signalForBit(bitIdx); const signal = this.signalForBit(bitIdx);
let bitStyle = null, let bitStyle = null;
bitSignificance = ""; let bitSignificance = '';
if (signal) { if (signal) {
bitStyle = this.state.signalStyles[signal.name] || null; bitStyle = this.state.signalStyles[signal.name] || null;
const bitDesc = signal.bitDescription(bitIdx); const bitDesc = signal.bitDescription(bitIdx);
bitSignificance = bitDesc.isMsb ? "msb" : bitDesc.isLsb ? "lsb" : ""; bitSignificance = bitDesc.isMsb ? 'msb' : bitDesc.isLsb ? 'lsb' : '';
} else if (this.bitIsContainedInSelection(bitIdx)) { } else if (this.bitIsContainedInSelection(bitIdx)) {
bitStyle = Styles.bitSelectedStyle; bitStyle = Styles.bitSelectedStyle;
} }
const className = css("bit", Styles.bit, bitStyle); const className = css('bit', Styles.bit, bitStyle);
const bitValue = this.bitValue(i, j); const bitValue = this.bitValue(i, j);
rowBits.push( rowBits.push(
@ -474,7 +465,7 @@ export default class AddSignals extends Component {
); );
} }
rowBits.push(<td key={"hex-repr"}>{this.byteValueHex(i)}</td>); rowBits.push(<td key="hex-repr">{this.byteValueHex(i)}</td>);
rows.push(<tr key={i.toString()}>{rowBits}</tr>); rows.push(<tr key={i.toString()}>{rowBits}</tr>);
} }
@ -495,7 +486,7 @@ export default class AddSignals extends Component {
}); });
}; };
onTentativeSignalChange = signal => { onTentativeSignalChange = (signal) => {
// Tentative signal changes are not propagated up // Tentative signal changes are not propagated up
// but their effects are displayed in the bitmatrix // but their effects are displayed in the bitmatrix
const { signals } = this.state; const { signals } = this.state;
@ -506,7 +497,7 @@ export default class AddSignals extends Component {
onSignalChange = (signal, oldSignal) => { onSignalChange = (signal, oldSignal) => {
const { signals } = this.state; const { signals } = this.state;
for (let signalName in signals) { for (const signalName in signals) {
if (signals[signalName].uid === signal.uid) { if (signals[signalName].uid === signal.uid) {
delete signals[signalName]; delete signals[signalName];
} }
@ -516,7 +507,7 @@ export default class AddSignals extends Component {
this.setState({ signals }, this.propagateUpSignalChange); this.setState({ signals }, this.propagateUpSignalChange);
}; };
onSignalRemove = signal => { onSignalRemove = (signal) => {
const { signals } = this.state; const { signals } = this.state;
delete signals[signal.name]; delete signals[signal.name];
this.setState({ signals }, this.propagateUpSignalChange); this.setState({ signals }, this.propagateUpSignalChange);
@ -546,7 +537,8 @@ export default class AddSignals extends Component {
{this.props.message.entries[this.props.messageIndex] ? ( {this.props.message.entries[this.props.messageIndex] ? (
<div className="cabana-explorer-signals-time"> <div className="cabana-explorer-signals-time">
<p> <p>
time:{" "} time:
{' '}
{this.props.message.entries[ {this.props.message.entries[
this.props.messageIndex this.props.messageIndex
].relTime.toFixed(3)} ].relTime.toFixed(3)}

View File

@ -1,16 +1,16 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import Measure from "react-measure"; import Measure from 'react-measure';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import cx from "classnames"; import cx from 'classnames';
import { Vega } from "react-vega"; import { Vega } from 'react-vega';
import Signal from "../models/can/signal"; import Signal from '../models/can/signal';
import GraphData from "../models/graph-data"; import GraphData from '../models/graph-data';
import CanPlotSpec from "../vega/CanPlot"; import CanPlotSpec from '../vega/CanPlot';
import debounce from "../utils/debounce"; import debounce from '../utils/debounce';
const DefaultPlotInnerStyle = { const DefaultPlotInnerStyle = {
position: "absolute", position: 'absolute',
top: 0, top: 0,
left: 0 left: 0
}; };
@ -63,10 +63,10 @@ export default class CanGraph extends Component {
getGraphData(props) { getGraphData(props) {
let firstRelTime = -1; let firstRelTime = -1;
let lastRelTime = -1; let lastRelTime = -1;
let series = props.plottedSignals const series = props.plottedSignals
.map(signals => { .map((signals) => {
const { messageId, signalUid } = signals; const { messageId, signalUid } = signals;
let entries = props.messages[messageId].entries; const { entries } = props.messages[messageId];
if (entries.length) { if (entries.length) {
let messageRelTime = entries[0].relTime; let messageRelTime = entries[0].relTime;
if (firstRelTime === -1) { if (firstRelTime === -1) {
@ -109,15 +109,15 @@ export default class CanGraph extends Component {
segmentIsNew(newSegment) { segmentIsNew(newSegment) {
return ( return (
newSegment.length !== this.props.segment.length || newSegment.length !== this.props.segment.length
!newSegment.every((val, idx) => this.props.segment[idx] === val) || !newSegment.every((val, idx) => this.props.segment[idx] === val)
); );
} }
visualChanged(prevProps, nextProps) { visualChanged(prevProps, nextProps) {
return ( return (
prevProps.canReceiveGraphDrop !== nextProps.canReceiveGraphDrop || prevProps.canReceiveGraphDrop !== nextProps.canReceiveGraphDrop
JSON.stringify(prevProps.dragPos) !== JSON.stringify(nextProps.dragPos) || JSON.stringify(prevProps.dragPos) !== JSON.stringify(nextProps.dragPos)
); );
} }
@ -138,46 +138,46 @@ export default class CanGraph extends Component {
} }
updateBounds = debounce(() => { updateBounds = debounce(() => {
this.view.signal("width", this.state.bounds.width - 70); this.view.signal('width', this.state.bounds.width - 70);
this.view.signal("height", 0.4 * (this.state.bounds.width - 70)); // 5:2 aspect ratio this.view.signal('height', 0.4 * (this.state.bounds.width - 70)); // 5:2 aspect ratio
this.view.run(); this.view.run();
}, 100); }, 100);
insertData = debounce(() => { insertData = debounce(() => {
if (!this.view) { if (!this.view) {
console.log("Cannot insertData"); console.log('Cannot insertData');
return; return;
} }
// adding plot points by diff isn't faster since it basically has to be n^2 // adding plot points by diff isn't faster since it basically has to be n^2
// out-of-order events make it so that you can't just check the bounds // out-of-order events make it so that you can't just check the bounds
let { series } = this.state.data; const { series } = this.state.data;
let changeset = this.view const changeset = this.view
.changeset() .changeset()
.remove(v => true) .remove((v) => true)
.insert(series); .insert(series);
this.view.change("table", changeset); this.view.change('table', changeset);
this.view.run(); this.view.run();
}, 250); }, 250);
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if ( if (
nextProps.dragPos && nextProps.dragPos
JSON.stringify(nextProps.dragPos) !== JSON.stringify(this.props.dragPos) && JSON.stringify(nextProps.dragPos) !== JSON.stringify(this.props.dragPos)
) { ) {
this.updateStyleFromDragPos(nextProps.dragPos); this.updateStyleFromDragPos(nextProps.dragPos);
} else if (!nextProps.dragPos && this.state.plotInnerStyle !== null) { } else if (!nextProps.dragPos && this.state.plotInnerStyle !== null) {
this.setState({ plotInnerStyle: null }); this.setState({ plotInnerStyle: null });
} }
if ( if (
this.props.messages !== nextProps.messages || this.props.messages !== nextProps.messages
this.props.plottedSignal !== nextProps.plottedSignal || this.props.plottedSignal !== nextProps.plottedSignal
) { ) {
let data = this.getGraphData(nextProps); const data = this.getGraphData(nextProps);
if ( if (
data.series.length === this.state.data.series.length && data.series.length === this.state.data.series.length
data.firstRelTime === this.state.data.firstRelTime && && data.firstRelTime === this.state.data.firstRelTime
data.lastRelTime === this.state.data.lastRelTime && data.lastRelTime === this.state.data.lastRelTime
) { ) {
// do nothing, the data didn't *actually* change // do nothing, the data didn't *actually* change
} else { } else {
@ -188,6 +188,7 @@ export default class CanGraph extends Component {
this.setState({ spec: this.getGraphSpec(nextProps) }); this.setState({ spec: this.getGraphSpec(nextProps) });
} }
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
if (!this.view) { if (!this.view) {
return true; return true;
@ -199,30 +200,31 @@ export default class CanGraph extends Component {
this.insertData(); this.insertData();
} }
if (this.props.currentTime !== nextProps.currentTime) { if (this.props.currentTime !== nextProps.currentTime) {
this.view.signal("videoTime", nextProps.currentTime); this.view.signal('videoTime', nextProps.currentTime);
} }
if (this.segmentIsNew(nextProps.segment)) { if (this.segmentIsNew(nextProps.segment)) {
if (nextProps.segment.length > 0) { if (nextProps.segment.length > 0) {
// Set segmented domain // Set segmented domain
this.view.signal("segment", nextProps.segment); this.view.signal('segment', nextProps.segment);
} else { } else {
// Reset segment to full domain // Reset segment to full domain
this.view.signal("segment", 0); this.view.signal('segment', 0);
} }
} }
this.view.runAsync(); this.view.runAsync();
return false; return false;
} }
componentDidUpdate(oldProps, oldState) { componentDidUpdate(oldProps, oldState) {
if (this.view) { if (this.view) {
if (this.props.segment.length > 0) { if (this.props.segment.length > 0) {
// Set segmented domain // Set segmented domain
this.view.signal("segment", this.props.segment); this.view.signal('segment', this.props.segment);
} else { } else {
// Reset segment to full domain // Reset segment to full domain
this.view.signal("segment", 0); this.view.signal('segment', 0);
} }
this.view.signal("videoTime", this.props.currentTime); this.view.signal('videoTime', this.props.currentTime);
this.view.runAsync(); this.view.runAsync();
} }
} }
@ -241,9 +243,9 @@ export default class CanGraph extends Component {
this.onPlotResize(); this.onPlotResize();
} }
if (this.props.segment.length > 0) { if (this.props.segment.length > 0) {
view.signal("segment", this.props.segment); view.signal('segment', this.props.segment);
} }
view.signal("videoTime", this.props.currentTime); view.signal('videoTime', this.props.currentTime);
this.insertData(); this.insertData();
} }
@ -319,7 +321,7 @@ export default class CanGraph extends Component {
render() { render() {
const { plotInnerStyle } = this.state; const { plotInnerStyle } = this.state;
const canReceiveDropClass = this.props.canReceiveGraphDrop const canReceiveDropClass = this.props.canReceiveGraphDrop
? "is-droppable" ? 'is-droppable'
: null; : null;
return ( return (
@ -329,7 +331,7 @@ export default class CanGraph extends Component {
> >
<div <div
className={cx( className={cx(
"cabana-explorer-visuals-plot-inner", 'cabana-explorer-visuals-plot-inner',
canReceiveDropClass canReceiveDropClass
)} )}
style={plotInnerStyle || null} style={plotInnerStyle || null}
@ -344,13 +346,13 @@ export default class CanGraph extends Component {
({ messageId, signalUid, messageName }) => { ({ messageId, signalUid, messageName }) => {
const signal = Object.values( const signal = Object.values(
this.props.messages[messageId].frame.signals this.props.messages[messageId].frame.signals
).find(s => s.uid === signalUid); ).find((s) => s.uid === signalUid);
const { colors } = signal; const { colors } = signal;
return ( return (
<div <div
className="cabana-explorer-visuals-plot-header" className="cabana-explorer-visuals-plot-header"
key={messageId + "_" + signal.uid} key={`${messageId}_${signal.uid}`}
> >
<div className="cabana-explorer-visuals-plot-header-toggle"> <div className="cabana-explorer-visuals-plot-header-toggle">
<button <button
@ -377,29 +379,27 @@ export default class CanGraph extends Component {
} }
)} )}
<Measure bounds onResize={this.onPlotResize}> <Measure bounds onResize={this.onPlotResize}>
{({ measureRef }) => { {({ measureRef }) => (
return ( <div
<div ref={measureRef}
ref={measureRef} className="cabana-explorer-visuals-plot-container"
className="cabana-explorer-visuals-plot-container" >
> <Vega
<Vega onNewView={this.onNewView}
onNewView={this.onNewView} logLevel={1}
logLevel={1} signalListeners={{
signalListeners={{ clickTime: this.onSignalClickTime,
clickTime: this.onSignalClickTime, segment: this.onSignalSegment
segment: this.onSignalSegment }}
}} renderer="canvas"
renderer={"canvas"} spec={this.state.spec}
spec={this.state.spec} actions={false}
actions={false} data={{
data={{ table: this.state.data.series
table: this.state.data.series }}
}} />
/> </div>
</div> )}
);
}}
</Measure> </Measure>
</div> </div>
</div> </div>

View File

@ -1,9 +1,9 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import CanGraph from "./CanGraph"; import CanGraph from './CanGraph';
require("element-closest"); require('element-closest');
export default class CanGraphList extends Component { export default class CanGraphList extends Component {
static propTypes = { static propTypes = {
@ -46,9 +46,8 @@ export default class CanGraphList extends Component {
determineDraggingGraph() { determineDraggingGraph() {
const { draggingSignal } = this.state; const { draggingSignal } = this.state;
return this.plotRefs.find( return this.plotRefs.find(
({ messageId, signalUid }) => ({ messageId, signalUid }) => draggingSignal.messageId === messageId
draggingSignal.messageId === messageId && && draggingSignal.signalUid === signalUid
draggingSignal.signalUid === signalUid
); );
} }
@ -66,13 +65,12 @@ export default class CanGraphList extends Component {
draggingGraph.ref.hidden = true; draggingGraph.ref.hidden = true;
const ele = document.elementFromPoint(e.clientX, e.clientY); const ele = document.elementFromPoint(e.clientX, e.clientY);
draggingGraph.ref.hidden = false; draggingGraph.ref.hidden = false;
const closestPlot = ele.closest(".cabana-explorer-visuals-plot"); const closestPlot = ele.closest('.cabana-explorer-visuals-plot');
const closestPlotRef = this.plotRefs.find( const closestPlotRef = this.plotRefs.find(
({ ref, messageId, signalUid }) => ({ ref, messageId, signalUid }) => !(
!( messageId === draggingGraph.messageId
messageId === draggingGraph.messageId && && signalUid === draggingGraph.signalUid
signalUid === draggingGraph.signalUid ) && ref.isEqualNode(closestPlot)
) && ref.isEqualNode(closestPlot)
); );
if (closestPlotRef) { if (closestPlotRef) {
this.setState({ graphToReceiveDrop: closestPlotRef }); this.setState({ graphToReceiveDrop: closestPlotRef });
@ -107,7 +105,7 @@ export default class CanGraphList extends Component {
let { plotRefs } = this; let { plotRefs } = this;
plotRefs = plotRefs plotRefs = plotRefs
.filter( .filter(
ref => !(ref.messageId === messageId && ref.signalUid === signalUid) (ref) => !(ref.messageId === messageId && ref.signalUid === signalUid)
) )
.concat([{ messageId, signalUid, ref }]); .concat([{ messageId, signalUid, ref }]);
this.plotRefs = plotRefs; this.plotRefs = plotRefs;
@ -119,33 +117,29 @@ export default class CanGraphList extends Component {
const { messageId, signalUid } = plottedSignals[0]; const { messageId, signalUid } = plottedSignals[0];
const msg = this.props.messages[messageId]; const msg = this.props.messages[messageId];
const signal = Object.values(msg.frame.signals).find( const signal = Object.values(msg.frame.signals).find(
s => s.uid === signalUid (s) => s.uid === signalUid
); );
if (!this.plotListRef) { if (!this.plotListRef) {
return []; return [];
} }
const isDragging = const isDragging = draggingSignal.signalUid === signalUid
draggingSignal.signalUid === signalUid && && draggingSignal.messageId === messageId;
draggingSignal.messageId === messageId; const canReceiveGraphDrop = graphToReceiveDrop
const canReceiveGraphDrop = && graphToReceiveDrop.signalUid === signalUid
graphToReceiveDrop && && graphToReceiveDrop.messageId === messageId;
graphToReceiveDrop.signalUid === signalUid && plottedSignals = plottedSignals.map((plottedSignal) => ({
graphToReceiveDrop.messageId === messageId; messageName: this.props.messages[plottedSignal.messageId].frame.name,
plottedSignals = plottedSignals.map(plottedSignal => { ...plottedSignal
return { }));
messageName: this.props.messages[plottedSignal.messageId].frame.name,
...plottedSignal
};
});
const key = plottedSignals.reduce( const key = plottedSignals.reduce(
(key, { messageId, signalUid }) => key + messageId + "_" + signalUid, (key, { messageId, signalUid }) => `${key + messageId}_${signalUid}`,
"" ''
); );
return ( return (
<CanGraph <CanGraph
onGraphRefAvailable={ref => { onGraphRefAvailable={(ref) => {
this.addCanGraphRef(ref, messageId, signalUid); this.addCanGraphRef(ref, messageId, signalUid);
}} }}
key={key} key={key}

View File

@ -1,8 +1,8 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import ReactList from "react-list"; import ReactList from 'react-list';
import cx from "classnames"; import cx from 'classnames';
export default class CanLog extends Component { export default class CanLog extends Component {
static ITEMS_PER_PAGE = 50; static ITEMS_PER_PAGE = 50;
@ -52,21 +52,20 @@ export default class CanLog extends Component {
? nextProps.message.entries.length ? nextProps.message.entries.length
: 0; : 0;
const shouldUpdate = const shouldUpdate = this.props.message !== nextProps.message
this.props.message !== nextProps.message || || nextMessageLength !== curMessageLength
nextMessageLength !== curMessageLength || || nextProps.messageIndex !== this.props.messageIndex
nextProps.messageIndex !== this.props.messageIndex || || nextProps.plottedSignals.length !== this.props.plottedSignals.length
nextProps.plottedSignals.length !== this.props.plottedSignals.length || || JSON.stringify(nextProps.segmentIndices)
JSON.stringify(nextProps.segmentIndices) !== !== JSON.stringify(this.props.segmentIndices)
JSON.stringify(this.props.segmentIndices) || || JSON.stringify(nextState) !== JSON.stringify(this.state)
JSON.stringify(nextState) !== JSON.stringify(this.state) || || this.props.message !== nextProps.message
this.props.message !== nextProps.message || || (this.props.message !== undefined
(this.props.message !== undefined && && nextProps.message !== undefined
nextProps.message !== undefined && && this.props.message.frame !== undefined
this.props.message.frame !== undefined && && nextProps.message.frame !== undefined
nextProps.message.frame !== undefined && && JSON.stringify(this.props.message.frame)
JSON.stringify(this.props.message.frame) !== !== JSON.stringify(nextProps.message.frame));
JSON.stringify(nextProps.message.frame));
return shouldUpdate; return shouldUpdate;
} }
@ -88,24 +87,23 @@ export default class CanLog extends Component {
collapseMessage(msg, msgIdx) { collapseMessage(msg, msgIdx) {
this.setState({ this.setState({
expandedMessages: this.state.expandedMessages.filter( expandedMessages: this.state.expandedMessages.filter(
expMsgTime => expMsgTime !== msg.time (expMsgTime) => expMsgTime !== msg.time
) )
}); });
} }
isSignalPlotted(msgId, signalUid) { isSignalPlotted(msgId, signalUid) {
const plottedSignal = this.props.plottedSignals.find(plot => const plottedSignal = this.props.plottedSignals.find((plot) => plot.some(
plot.some( (signal) => signal.messageId === msgId && signal.signalUid === signalUid
signal => signal.messageId === msgId && signal.signalUid === signalUid ));
)
);
return plottedSignal !== undefined; return plottedSignal !== undefined;
} }
signalValuePretty(signal, value) { signalValuePretty(signal, value) {
if (signal.isFloat) { if (signal.isFloat) {
return value.toFixed(3); return value.toFixed(3);
} else return value; }
return value;
} }
isMessageExpanded(msg) { isMessageExpanded(msg) {
@ -124,15 +122,13 @@ export default class CanLog extends Component {
if (!this.props.message.frame) { if (!this.props.message.frame) {
return; return;
} }
const msgIsExpanded = const msgIsExpanded = this.state.allPacketsExpanded || this.isMessageExpanded(msgEntry);
this.state.allPacketsExpanded || this.isMessageExpanded(msgEntry);
const msgHasSignals = const msgHasSignals = Object.keys(this.props.message.frame.signals).length > 0;
Object.keys(this.props.message.frame.signals).length > 0;
if (msgIsExpanded && msgHasSignals) { if (msgIsExpanded && msgHasSignals) {
this.setState({ this.setState({
expandedMessages: this.state.expandedMessages.filter( expandedMessages: this.state.expandedMessages.filter(
expMsgTime => expMsgTime !== msgEntry.time (expMsgTime) => expMsgTime !== msgEntry.time
) )
}); });
} else if (msgHasSignals) { } else if (msgHasSignals) {
@ -141,7 +137,6 @@ export default class CanLog extends Component {
}); });
this.props.onMessageExpanded(); this.props.onMessageExpanded();
} else { } else {
return;
} }
} }
@ -155,10 +150,10 @@ export default class CanLog extends Component {
// Signal removed? // Signal removed?
return null; return null;
} }
const unit = signal.unit.length > 0 ? signal.unit : "units"; const unit = signal.unit.length > 0 ? signal.unit : 'units';
const isPlotted = this.isSignalPlotted(message.id, signal.uid); const isPlotted = this.isSignalPlotted(message.id, signal.uid);
const plottedButtonClass = isPlotted ? null : "button--alpha"; const plottedButtonClass = isPlotted ? null : 'button--alpha';
const plottedButtonText = isPlotted ? "Hide Plot" : "Show Plot"; const plottedButtonText = isPlotted ? 'Hide Plot' : 'Show Plot';
return ( return (
<div key={name} className="signals-log-list-signal"> <div key={name} className="signals-log-list-signal">
<div className="signals-log-list-signal-message"> <div className="signals-log-list-signal-message">
@ -166,8 +161,11 @@ export default class CanLog extends Component {
</div> </div>
<div className="signals-log-list-signal-value"> <div className="signals-log-list-signal-value">
<span> <span>
(<strong>{this.signalValuePretty(signal, value)}</strong>{" "} (
{unit}) <strong>{this.signalValuePretty(signal, value)}</strong>
{' '}
{unit}
)
</span> </span>
</div> </div>
<div <div
@ -176,7 +174,7 @@ export default class CanLog extends Component {
this.toggleSignalPlot(message.id, signal.uid, isPlotted); this.toggleSignalPlot(message.id, signal.uid, isPlotted);
}} }}
> >
<button className={cx("button--tiny", plottedButtonClass)}> <button className={cx('button--tiny', plottedButtonClass)}>
<span>{plottedButtonText}</span> <span>{plottedButtonText}</span>
</button> </button>
</div> </div>
@ -189,15 +187,14 @@ export default class CanLog extends Component {
renderLogListItemMessage(msgEntry, key) { renderLogListItemMessage(msgEntry, key) {
const { message } = this.props; const { message } = this.props;
const msgIsExpanded = const msgIsExpanded = this.state.allPacketsExpanded || this.isMessageExpanded(msgEntry);
this.state.allPacketsExpanded || this.isMessageExpanded(msgEntry);
const msgHasSignals = Object.keys(msgEntry.signals).length > 0; const msgHasSignals = Object.keys(msgEntry.signals).length > 0;
const hasSignalsClass = msgHasSignals ? "has-signals" : null; const hasSignalsClass = msgHasSignals ? 'has-signals' : null;
const expandedClass = msgIsExpanded ? "is-expanded" : null; const expandedClass = msgIsExpanded ? 'is-expanded' : null;
const row = ( const row = (
<div <div
key={key} key={key}
className={cx("signals-log-list-item", hasSignalsClass, expandedClass)} className={cx('signals-log-list-item', hasSignalsClass, expandedClass)}
> >
<div <div
className="signals-log-list-item-header" className="signals-log-list-item-header"
@ -211,7 +208,11 @@ export default class CanLog extends Component {
</strong> </strong>
</div> </div>
<div className="signals-log-list-time"> <div className="signals-log-list-time">
<span>[{msgEntry.relTime.toFixed(3)}]</span> <span>
[
{msgEntry.relTime.toFixed(3)}
]
</span>
</div> </div>
<div className="signals-log-list-bytes"> <div className="signals-log-list-bytes">
<span className="t-mono">{msgEntry.hexData}</span> <span className="t-mono">{msgEntry.hexData}</span>
@ -239,9 +240,8 @@ export default class CanLog extends Component {
this.props.message.entries[offset + index], this.props.message.entries[offset + index],
key key
); );
} else {
return null;
} }
return null;
} }
renderLogList(items, ref) { renderLogList(items, ref) {
@ -263,14 +263,15 @@ export default class CanLog extends Component {
const { segmentIndices, messageIndex } = this.props; const { segmentIndices, messageIndex } = this.props;
if (messageIndex > 0) { if (messageIndex > 0) {
return this.props.message.entries.length - messageIndex; 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;
} }
if (segmentIndices.length === 2) {
return segmentIndices[1] - segmentIndices[0];
}
if (this.props.message) {
return this.props.message.entries.length;
}
// no message yet
return 0;
} }
onExpandAllChanged(e) { onExpandAllChanged(e) {
@ -282,16 +283,18 @@ export default class CanLog extends Component {
} }
render() { render() {
let expandAllText = this.state.allPacketsExpanded const expandAllText = this.state.allPacketsExpanded
? "Collapse All" ? 'Collapse All'
: "Expand All"; : 'Expand All';
let expandAllClass = this.state.allPacketsExpanded ? null : "button--alpha"; const expandAllClass = this.state.allPacketsExpanded
? null
: 'button--alpha';
return ( return (
<div className="cabana-explorer-signals-log"> <div className="cabana-explorer-signals-log">
<div className="cabana-explorer-signals-log-header"> <div className="cabana-explorer-signals-log-header">
<strong>Message Packets</strong> <strong>Message Packets</strong>
<button <button
className={cx("button--tiny", expandAllClass)} className={cx('button--tiny', expandAllClass)}
onClick={this.toggleExpandAllPackets} onClick={this.toggleExpandAllPackets}
> >
{expandAllText} {expandAllText}

View File

@ -1,14 +1,15 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
export default class DbcUpload extends Component { export default class DbcUpload extends Component {
static propTypes = { static propTypes = {
onDbcLoaded: PropTypes.func onDbcLoaded: PropTypes.func
}; };
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
dbcText: "" dbcText: ''
}; };
this.onTextChanged = this.onTextChanged.bind(this); this.onTextChanged = this.onTextChanged.bind(this);
@ -17,7 +18,7 @@ export default class DbcUpload extends Component {
onTextChanged(e) { onTextChanged(e) {
const dbcText = e.target.value; const dbcText = e.target.value;
this.setState({ dbcText }); this.setState({ dbcText });
this.props.onDbcLoaded("from paste", dbcText); this.props.onDbcLoaded('from paste', dbcText);
} }
render() { render() {

View File

@ -1,7 +1,7 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import Modal from "./Modals/baseModal"; import Modal from './Modals/baseModal';
export default class EditMessageModal extends Component { export default class EditMessageModal extends Component {
static propTypes = { static propTypes = {
@ -32,9 +32,7 @@ export default class EditMessageModal extends Component {
this.setState({ messageFrame }); this.setState({ messageFrame });
} }
editTransmitter(transmitter) { editTransmitter(transmitter) {}
return;
}
renderActions() { renderActions() {
return ( return (
@ -67,7 +65,7 @@ export default class EditMessageModal extends Component {
type="text" type="text"
id="message_name" id="message_name"
value={this.state.messageFrame.name} value={this.state.messageFrame.name}
onChange={e => { onChange={(e) => {
const { messageFrame } = this.state; const { messageFrame } = this.state;
messageFrame.name = e.target.value; messageFrame.name = e.target.value;
this.setState({ messageFrame }); this.setState({ messageFrame });
@ -83,7 +81,7 @@ export default class EditMessageModal extends Component {
type="number" type="number"
id="message_size" id="message_size"
value={this.state.messageFrame.size} value={this.state.messageFrame.size}
onChange={e => { onChange={(e) => {
const { messageFrame } = this.state; const { messageFrame } = this.state;
if (e.target.value > 8) { if (e.target.value > 8) {
return; return;
@ -102,23 +100,21 @@ export default class EditMessageModal extends Component {
</label> </label>
<div className="form-field-inset"> <div className="form-field-inset">
<ul className="form-field-inset-list"> <ul className="form-field-inset-list">
{this.state.messageFrame.transmitters.map(transmitter => { {this.state.messageFrame.transmitters.map((transmitter) => (
return ( <li className="form-field-inset-list-item" key={transmitter}>
<li className="form-field-inset-list-item" key={transmitter}> <div className="form-field-inset-list-item-title">
<div className="form-field-inset-list-item-title"> <span>{transmitter}</span>
<span>{transmitter}</span> </div>
</div> <div className="form-field-inset-list-item-action">
<div className="form-field-inset-list-item-action"> <button className="button--tiny button--alpha">Edit</button>
<button className="button--tiny button--alpha"> </div>
Edit </li>
</button> ))}
</div>
</li>
);
})}
<button className="button--tiny button--alpha"> <button className="button--tiny button--alpha">
<span> <span>
<i className="fa fa-plus" /> Add Transmitter <i className="fa fa-plus" />
{' '}
Add Transmitter
</span> </span>
</button> </button>
</ul> </ul>

View File

@ -1,16 +1,16 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import cx from "classnames"; import cx from 'classnames';
import AddSignals from "./AddSignals"; import AddSignals from './AddSignals';
import CanGraphList from "./CanGraphList"; import CanGraphList from './CanGraphList';
import RouteVideoSync from "./RouteVideoSync"; import RouteVideoSync from './RouteVideoSync';
import CanLog from "./CanLog"; import CanLog from './CanLog';
import Entries from "../models/can/entries"; import Entries from '../models/can/entries';
import debounce from "../utils/debounce"; import debounce from '../utils/debounce';
import PartSelector from "./PartSelector"; import PartSelector from './PartSelector';
import PlaySpeedSelector from "./PlaySpeedSelector"; import PlaySpeedSelector from './PlaySpeedSelector';
export default class Explorer extends Component { export default class Explorer extends Component {
static propTypes = { static propTypes = {
@ -66,20 +66,20 @@ export default class Explorer extends Component {
} }
componentWillMount() { componentWillMount() {
document.addEventListener("keydown", this._onKeyDown); document.addEventListener('keydown', this._onKeyDown);
} }
componentWillUnmount() { componentWillUnmount() {
document.removeEventListener("keydown", this._onKeyDown); document.removeEventListener('keydown', this._onKeyDown);
} }
clipSegment(segment, segmentIndices, nextMessage) { clipSegment(segment, segmentIndices, nextMessage) {
if (segment.length === 2) { if (segment.length === 2) {
const segmentStartIdx = nextMessage.entries.findIndex( const segmentStartIdx = nextMessage.entries.findIndex(
e => e.relTime >= segment[0] (e) => e.relTime >= segment[0]
); );
let segmentEndIdx = nextMessage.entries.findIndex( let segmentEndIdx = nextMessage.entries.findIndex(
e => e.relTime >= segment[1] (e) => e.relTime >= segment[1]
); );
if (segmentStartIdx !== -1) { if (segmentStartIdx !== -1) {
if (segmentEndIdx === -1) { if (segmentEndIdx === -1) {
@ -119,32 +119,30 @@ export default class Explorer extends Component {
// remove plottedSignals that no longer exist // remove plottedSignals that no longer exist
plottedSignals = plottedSignals plottedSignals = plottedSignals
.map(plot => .map((plot) => plot.filter(({ messageId, signalUid }, index) => {
plot.filter(({ messageId, signalUid }, index) => { const messageExists = !!nextProps.messages[messageId];
const messageExists = !!nextProps.messages[messageId]; let signalExists = true;
let signalExists = true; if (messageExists) {
if (messageExists) { signalExists = Object.values(
signalExists = Object.values( nextProps.messages[messageId].frame.signals
nextProps.messages[messageId].frame.signals ).some((signal) => signal.uid === signalUid);
).some(signal => signal.uid === signalUid); }
}
return messageExists && signalExists; return messageExists && signalExists;
}) }))
) .filter((plot) => plot.length > 0);
.filter(plot => plot.length > 0);
this.setState({ plottedSignals }); this.setState({ plottedSignals });
if ( if (
nextProps.selectedMessage && nextProps.selectedMessage
nextProps.selectedMessage !== this.props.selectedMessage && nextProps.selectedMessage !== this.props.selectedMessage
) { ) {
// Update segment and seek state // Update segment and seek state
// by finding a entry indices // by finding a entry indices
// corresponding to old message segment/seek times. // corresponding to old message segment/seek times.
let { segment, segmentIndices } = this.clipSegment( const { segment, segmentIndices } = this.clipSegment(
this.state.segment, this.state.segment,
this.state.segmentIndices, this.state.segmentIndices,
nextMessage nextMessage
@ -169,11 +167,11 @@ export default class Explorer extends Component {
} }
if ( if (
nextMessage && nextMessage
curMessage && && curMessage
nextMessage.entries.length !== curMessage.entries.length && nextMessage.entries.length !== curMessage.entries.length
) { ) {
let { segment, segmentIndices } = this.clipSegment( const { segment, segmentIndices } = this.clipSegment(
this.state.segment, this.state.segment,
this.state.segmentIndices, this.state.segmentIndices,
nextMessage nextMessage
@ -193,20 +191,21 @@ export default class Explorer extends Component {
const { routeStartTime, currentParts } = this.props; const { routeStartTime, currentParts } = this.props;
if (routeStartTime) { if (routeStartTime) {
const partStartOffset = currentParts[0] * 60, const partStartOffset = currentParts[0] * 60;
partEndOffset = (currentParts[1] + 1) * 60; const partEndOffset = (currentParts[1] + 1) * 60;
const windowStartTime = routeStartTime const windowStartTime = routeStartTime
.clone() .clone()
.add(partStartOffset, "s") .add(partStartOffset, 's')
.format("HH:mm:ss"); .format('HH:mm:ss');
const windowEndTime = routeStartTime const windowEndTime = routeStartTime
.clone() .clone()
.add(partEndOffset, "s") .add(partEndOffset, 's')
.format("HH:mm:ss"); .format('HH:mm:ss');
return `${windowStartTime} - ${windowEndTime}`; return `${windowStartTime} - ${windowEndTime}`;
} else return ""; }
return '';
} }
onSignalPlotPressed(messageId, signalUid) { onSignalPlotPressed(messageId, signalUid) {
@ -220,13 +219,10 @@ export default class Explorer extends Component {
onSignalUnplotPressed(messageId, signalUid) { onSignalUnplotPressed(messageId, signalUid) {
const { plottedSignals } = this.state; const { plottedSignals } = this.state;
const newPlottedSignals = plottedSignals const newPlottedSignals = plottedSignals
.map(plot => .map((plot) => plot.filter(
plot.filter( (signal) => !(signal.messageId === messageId && signal.signalUid === signalUid)
signal => ))
!(signal.messageId === messageId && signal.signalUid === signalUid) .filter((plot) => plot.length > 0);
)
)
.filter(plot => plot.length > 0);
this.setState({ plottedSignals: newPlottedSignals }); this.setState({ plottedSignals: newPlottedSignals });
} }
@ -237,8 +233,8 @@ export default class Explorer extends Component {
// console.log(this.state.segment, '->', segment, segmentIndices); // console.log(this.state.segment, '->', segment, segmentIndices);
if ( if (
segment[0] === this.props.currentParts[0] * 60 && segment[0] === this.props.currentParts[0] * 60
segment[1] === (this.props.currentParts[1] + 1) * 60 && segment[1] === (this.props.currentParts[1] + 1) * 60
) { ) {
segment = []; segment = [];
segmentIndices = []; segmentIndices = [];
@ -297,14 +293,13 @@ export default class Explorer extends Component {
} }
} }
return segmentIndices[1]; return segmentIndices[1];
} else {
for (let i = 0; i < entries.length; i++) {
if (entries[i].relTime >= time) {
return i;
}
}
return entries.length - 1;
} }
for (let i = 0; i < entries.length; i++) {
if (entries[i].relTime >= time) {
return i;
}
}
return entries.length - 1;
} }
onUserSeek(time) { onUserSeek(time) {
@ -377,24 +372,20 @@ export default class Explorer extends Component {
selectedMessagePlottedSignalUids() { selectedMessagePlottedSignalUids() {
const { plottedSignals } = this.state; const { plottedSignals } = this.state;
return plottedSignals return plottedSignals
.map(plot => .map((plot) => plot
plot .filter(
.filter( ({ messageId, signalUid }) => messageId === this.props.selectedMessage
({ messageId, signalUid }) => )
messageId === this.props.selectedMessage .map(({ signalUid }) => signalUid))
)
.map(({ signalUid }) => signalUid)
)
.reduce((arr, signalUid) => arr.concat(signalUid), []); .reduce((arr, signalUid) => arr.concat(signalUid), []);
} }
renderExplorerSignals() { renderExplorerSignals() {
const selectedMessageKey = this.props.selectedMessage; const selectedMessageKey = this.props.selectedMessage;
const selectedMessage = this.props.messages[selectedMessageKey]; const selectedMessage = this.props.messages[selectedMessageKey];
const selectedMessageName = const selectedMessageName = selectedMessage.frame !== undefined
selectedMessage.frame !== undefined ? selectedMessage.frame.name
? selectedMessage.frame.name : 'undefined';
: "undefined";
return ( return (
<div className="cabana-explorer-signals-wrapper"> <div className="cabana-explorer-signals-wrapper">
<div className="cabana-explorer-signals-header"> <div className="cabana-explorer-signals-header">
@ -405,9 +396,7 @@ export default class Explorer extends Component {
<div className="cabana-explorer-signals-header-action"> <div className="cabana-explorer-signals-header-action">
<button <button
className="button--small" className="button--small"
onClick={() => onClick={() => this.props.showEditMessageModal(selectedMessageKey)}
this.props.showEditMessageModal(selectedMessageKey)
}
> >
Edit Edit
</button> </button>
@ -448,25 +437,19 @@ export default class Explorer extends Component {
} }
mergePlots({ fromPlot, toPlot }) { mergePlots({ fromPlot, toPlot }) {
let { plottedSignals } = this.state; const { plottedSignals } = this.state;
// remove fromPlot from plottedSignals // remove fromPlot from plottedSignals
const fromPlotIdx = plottedSignals.findIndex(plot => const fromPlotIdx = plottedSignals.findIndex((plot) => plot.some(
plot.some( (signal) => signal.signalUid === fromPlot.signalUid
signal => && signal.messageId === fromPlot.messageId
signal.signalUid === fromPlot.signalUid && ));
signal.messageId === fromPlot.messageId
)
);
plottedSignals.splice(fromPlotIdx, 1); plottedSignals.splice(fromPlotIdx, 1);
const toPlotIdx = plottedSignals.findIndex(plot => const toPlotIdx = plottedSignals.findIndex((plot) => plot.some(
plot.some( (signal) => signal.signalUid === toPlot.signalUid
signal => && signal.messageId === toPlot.messageId
signal.signalUid === toPlot.signalUid && ));
signal.messageId === toPlot.messageId
)
);
plottedSignals[toPlotIdx] = [fromPlot, toPlot]; plottedSignals[toPlotIdx] = [fromPlot, toPlot];
this.setState({ plottedSignals }); this.setState({ plottedSignals });
@ -474,7 +457,7 @@ export default class Explorer extends Component {
render() { render() {
const signalsExpandedClass = this.state.shouldShowAddSignal const signalsExpandedClass = this.state.shouldShowAddSignal
? "is-expanded" ? 'is-expanded'
: null; : null;
let graphSegment = this.state.segment; let graphSegment = this.state.segment;
@ -487,7 +470,7 @@ export default class Explorer extends Component {
return ( return (
<div className="cabana-explorer"> <div className="cabana-explorer">
<div className={cx("cabana-explorer-signals", signalsExpandedClass)}> <div className={cx('cabana-explorer-signals', signalsExpandedClass)}>
{this.props.messages[this.props.selectedMessage] {this.props.messages[this.props.selectedMessage]
? this.renderExplorerSignals() ? this.renderExplorerSignals()
: this.renderSelectMessagePrompt()} : this.renderSelectMessagePrompt()}
@ -522,7 +505,7 @@ export default class Explorer extends Component {
) : null} ) : null}
{this.state.segment.length > 0 ? ( {this.state.segment.length > 0 ? (
<div <div
className={"cabana-explorer-visuals-segmentreset"} className="cabana-explorer-visuals-segmentreset"
onClick={() => { onClick={() => {
this.resetSegment(); this.resetSegment();
}} }}

View File

@ -1,8 +1,8 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import cx from "classnames"; import cx from 'classnames';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import OpenDbc from "../api/OpenDbc"; import OpenDbc from '../api/OpenDbc';
export default class GithubDbcList extends Component { export default class GithubDbcList extends Component {
static propTypes = { static propTypes = {
@ -17,7 +17,7 @@ export default class GithubDbcList extends Component {
this.state = { this.state = {
paths: [], paths: [],
selectedPath: null, selectedPath: null,
pathQuery: "" pathQuery: ''
}; };
this.updatePathQuery = this.updatePathQuery.bind(this); this.updatePathQuery = this.updatePathQuery.bind(this);
@ -25,15 +25,15 @@ export default class GithubDbcList extends Component {
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (nextProps.repo !== this.props.repo) { if (nextProps.repo !== this.props.repo) {
this.props.openDbcClient.list(nextProps.repo).then(paths => { this.props.openDbcClient.list(nextProps.repo).then((paths) => {
this.setState({ paths, selectedPath: null }); this.setState({ paths, selectedPath: null });
}); });
} }
} }
componentWillMount() { componentWillMount() {
this.props.openDbcClient.list(this.props.repo).then(paths => { this.props.openDbcClient.list(this.props.repo).then((paths) => {
paths = paths.filter(path => path.indexOf(".dbc") !== -1); paths = paths.filter((path) => path.indexOf('.dbc') !== -1);
this.setState({ paths }); this.setState({ paths });
}); });
} }
@ -48,7 +48,7 @@ export default class GithubDbcList extends Component {
this.setState({ selectedPath: path }); this.setState({ selectedPath: path });
this.props.openDbcClient this.props.openDbcClient
.getDbcContents(path, this.props.repo) .getDbcContents(path, this.props.repo)
.then(dbcContents => { .then((dbcContents) => {
this.props.onDbcLoaded(path, dbcContents); this.props.onDbcLoaded(path, dbcContents);
}); });
} }
@ -72,24 +72,21 @@ export default class GithubDbcList extends Component {
<div className="cabana-dbc-list-files"> <div className="cabana-dbc-list-files">
{this.state.paths {this.state.paths
.filter( .filter(
p => (p) => (this.state.pathQuery === '') | p.includes(this.state.pathQuery)
(this.state.pathQuery === "") | p.includes(this.state.pathQuery)
) )
.map(path => { .map((path) => (
return ( <div
<div className={cx('cabana-dbc-list-file', {
className={cx("cabana-dbc-list-file", { 'is-selected': this.state.selectedPath === path
"is-selected": this.state.selectedPath === path })}
})} onClick={() => {
onClick={() => { this.selectPath(path);
this.selectPath(path); }}
}} key={path}
key={path} >
> <span>{path}</span>
<span>{path}</span> </div>
</div> ))}
);
})}
</div> </div>
</div> </div>
); );

View File

@ -1,6 +1,6 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import Hls from "hls.js"; import Hls from 'hls.js';
export default class HLS extends Component { export default class HLS extends Component {
static propTypes = { static propTypes = {
@ -26,8 +26,8 @@ export default class HLS extends Component {
} }
if (nextProps.playing) { if (nextProps.playing) {
if ( if (
this.videoElement && this.videoElement
(this.videoElement.paused || this.videoElement.currentTime < 0.01) && (this.videoElement.paused || this.videoElement.currentTime < 0.01)
) { ) {
this.videoElement.play(); this.videoElement.play();
} }
@ -46,6 +46,7 @@ export default class HLS extends Component {
// legacy outer scope variable. Revisit this to see if putting in state // legacy outer scope variable. Revisit this to see if putting in state
// makes more sense // makes more sense
shouldInitVideoTime = true; shouldInitVideoTime = true;
onSeeked = () => { onSeeked = () => {
if (!this.props.playing) { if (!this.props.playing) {
if (this.shouldInitVideoTime) { if (this.shouldInitVideoTime) {
@ -84,7 +85,7 @@ export default class HLS extends Component {
onClick={this.props.onClick} onClick={this.props.onClick}
> >
<video <video
ref={video => { ref={(video) => {
this.videoElement = video; this.videoElement = video;
}} }}
autoPlay={this.props.playing} autoPlay={this.props.playing}

View File

@ -1,12 +1,12 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import cx from "classnames"; import cx from 'classnames';
import DBC from "../models/can/dbc"; import DBC from '../models/can/dbc';
import OpenDbc from "../api/OpenDbc"; import OpenDbc from '../api/OpenDbc';
import Modal from "./Modals/baseModal"; import Modal from './Modals/baseModal';
import GithubDbcList from "./GithubDbcList"; import GithubDbcList from './GithubDbcList';
import DbcUpload from "./DbcUpload"; import DbcUpload from './DbcUpload';
export default class LoadDbcModal extends Component { export default class LoadDbcModal extends Component {
static propTypes = { static propTypes = {
@ -19,8 +19,8 @@ export default class LoadDbcModal extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
tab: "OpenDBC", tab: 'OpenDBC',
tabs: ["OpenDBC", "GitHub", "Upload"], tabs: ['OpenDBC', 'GitHub', 'Upload'],
dbc: null, dbc: null,
dbcSource: null, dbcSource: null,
userOpenDbcRepo: null userOpenDbcRepo: null
@ -34,7 +34,7 @@ export default class LoadDbcModal extends Component {
} }
componentWillMount() { componentWillMount() {
this.props.openDbcClient.getUserOpenDbcFork().then(userOpenDbcRepo => { this.props.openDbcClient.getUserOpenDbcFork().then((userOpenDbcRepo) => {
this.setState({ userOpenDbcRepo }); this.setState({ userOpenDbcRepo });
}); });
} }
@ -54,26 +54,24 @@ export default class LoadDbcModal extends Component {
renderTabNavigation() { renderTabNavigation() {
return ( return (
<div className="cabana-tabs-navigation"> <div className="cabana-tabs-navigation">
{this.state.tabs.map(tab => { {this.state.tabs.map((tab) => (
return ( <a
<a className={cx({ 'is-active': this.state.tab === tab })}
className={cx({ "is-active": this.state.tab === tab })} onClick={() => {
onClick={() => { this.setState({ tab });
this.setState({ tab }); }}
}} key={tab}
key={tab} >
> <span>{tab}</span>
<span>{tab}</span> </a>
</a> ))}
);
})}
</div> </div>
); );
} }
renderTabContent() { renderTabContent() {
const { tab } = this.state; const { tab } = this.state;
if (tab === "OpenDBC") { if (tab === 'OpenDBC') {
return ( return (
<GithubDbcList <GithubDbcList
onDbcLoaded={this.onDbcLoaded} onDbcLoaded={this.onDbcLoaded}
@ -81,21 +79,23 @@ export default class LoadDbcModal extends Component {
openDbcClient={this.props.openDbcClient} openDbcClient={this.props.openDbcClient}
/> />
); );
} else if (tab === "GitHub") { }
if (tab === 'GitHub') {
if (!this.props.openDbcClient.hasAuth()) { if (!this.props.openDbcClient.hasAuth()) {
return this.props.loginWithGithub; return this.props.loginWithGithub;
} else if (this.state.userOpenDbcRepo === null) {
return <div>Fork it</div>;
} else {
return (
<GithubDbcList
onDbcLoaded={this.onDbcLoaded}
repo={this.state.userOpenDbcRepo}
openDbcClient={this.props.openDbcClient}
/>
);
} }
} else if (tab === "Upload") { if (this.state.userOpenDbcRepo === null) {
return <div>Fork it</div>;
}
return (
<GithubDbcList
onDbcLoaded={this.onDbcLoaded}
repo={this.state.userOpenDbcRepo}
openDbcClient={this.props.openDbcClient}
/>
);
}
if (tab === 'Upload') {
return <DbcUpload onDbcLoaded={this.onDbcLoaded} />; return <DbcUpload onDbcLoaded={this.onDbcLoaded} />;
} }
} }

View File

@ -1,4 +1,4 @@
import styled, { keyframes } from "react-emotion"; import styled, { keyframes } from 'react-emotion';
const frames = keyframes` const frames = keyframes`
0% { 0% {
@ -8,10 +8,10 @@ const frames = keyframes`
transform: translateX(-400px) transform: translateX(-400px)
} }
`; `;
const animationColor1 = "rgba(74, 242, 161, 1.00)"; const animationColor1 = 'rgba(74, 242, 161, 1.00)';
const animationColor2 = "rgba(140, 169, 197, 1.00)"; const animationColor2 = 'rgba(140, 169, 197, 1.00)';
export default styled("div")` export default styled('div')`
display: block; display: block;
animation-name: ${frames}; animation-name: ${frames};
animation-duration: 2s; animation-duration: 2s;

View File

@ -1,5 +1,5 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
export default class MessageBytes extends Component { export default class MessageBytes extends Component {
static propTypes = { static propTypes = {
@ -23,22 +23,20 @@ export default class MessageBytes extends Component {
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
if (nextProps.live) { if (nextProps.live) {
const nextLastEntry = const nextLastEntry = nextProps.message.entries[nextProps.message.entries.length - 1];
nextProps.message.entries[nextProps.message.entries.length - 1];
const curLastEntry = this.props.message.entries[ const curLastEntry = this.props.message.entries[
this.props.message.entries.length - 1 this.props.message.entries.length - 1
]; ];
return nextLastEntry.hexData !== curLastEntry.hexData; return nextLastEntry.hexData !== curLastEntry.hexData;
} else {
return nextProps.seekTime !== this.props.seekTime;
} }
return nextProps.seekTime !== this.props.seekTime;
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if ( if (
this.props.seekIndex !== nextProps.seekIndex || this.props.seekIndex !== nextProps.seekIndex
frameForTime(this.props.seekTime) !== frameForTime(nextProps.seekTime) || frameForTime(this.props.seekTime) !== frameForTime(nextProps.seekTime)
) { ) {
this.updateCanvas(nextProps); this.updateCanvas(nextProps);
} }
@ -66,7 +64,7 @@ export default class MessageBytes extends Component {
// TODO this can be faster with binary search, not currently a bottleneck though. // TODO this can be faster with binary search, not currently a bottleneck though.
mostRecentMessageIndex = message.entries.findIndex( mostRecentMessageIndex = message.entries.findIndex(
e => e.relTime >= seekTime (e) => e.relTime >= seekTime
); );
} }
@ -92,7 +90,7 @@ export default class MessageBytes extends Component {
} }
} }
const ctx = this.canvas.getContext("2d"); const ctx = this.canvas.getContext('2d');
// ctx.clearRect(0, 0, 180, 15); // ctx.clearRect(0, 0, 180, 15);
for (let i = 0; i < message.byteStateChangeCounts.length; ++i) { for (let i = 0; i < message.byteStateChangeCounts.length; ++i) {
@ -101,12 +99,12 @@ export default class MessageBytes extends Component {
ctx.fillRect(i * 20, 0, 20, 15); ctx.fillRect(i * 20, 0, 20, 15);
ctx.font = "12px Courier"; ctx.font = '12px Courier';
ctx.fillStyle = "white"; ctx.fillStyle = 'white';
if (hexData) { if (hexData) {
ctx.fillText(hexData, i * 20 + 2, 12); ctx.fillText(hexData, i * 20 + 2, 12);
} else { } else {
ctx.fillText("-", i * 20 + 7, 12); ctx.fillText('-', i * 20 + 7, 12);
} }
} }
} }
@ -123,7 +121,7 @@ export default class MessageBytes extends Component {
this.canvas = ref; this.canvas = ref;
this.canvas.width = 160 * window.devicePixelRatio; this.canvas.width = 160 * window.devicePixelRatio;
this.canvas.height = 15 * window.devicePixelRatio; this.canvas.height = 15 * window.devicePixelRatio;
const ctx = this.canvas.getContext("2d"); const ctx = this.canvas.getContext('2d');
ctx.scale(window.devicePixelRatio, window.devicePixelRatio); ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
} }

View File

@ -1,10 +1,11 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import cx from "classnames"; import cx from 'classnames';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import Clipboard from "clipboard"; import Clipboard from 'clipboard';
import MessageBytes from "./MessageBytes"; import MessageBytes from './MessageBytes';
const { ckmeans } = require("simple-statistics");
const { ckmeans } = require('simple-statistics');
export default class Meta extends Component { export default class Meta extends Component {
static propTypes = { static propTypes = {
@ -44,7 +45,7 @@ export default class Meta extends Component {
const { dbcLastSaved } = props; const { dbcLastSaved } = props;
this.state = { this.state = {
filterText: "Filter", filterText: 'Filter',
lastSaved: lastSaved:
dbcLastSaved !== null ? this.props.dbcLastSaved.fromNow() : null, dbcLastSaved !== null ? this.props.dbcLastSaved.fromNow() : null,
hoveredMessages: [], hoveredMessages: [],
@ -67,25 +68,25 @@ export default class Meta extends Component {
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if ( if (
nextProps.lastSaved !== this.props.lastSaved && nextProps.lastSaved !== this.props.lastSaved
typeof nextProps === "object" && typeof nextProps === 'object'
) { ) {
this.setState({ lastSaved: nextProps.dbcLastSaved.fromNow() }); this.setState({ lastSaved: nextProps.dbcLastSaved.fromNow() });
} }
const nextMsgKeys = Object.keys(nextProps.messages); const nextMsgKeys = Object.keys(nextProps.messages);
if ( if (
JSON.stringify(nextMsgKeys) !== JSON.stringify(nextMsgKeys)
JSON.stringify(Object.keys(this.props.messages)) !== JSON.stringify(Object.keys(this.props.messages))
) { ) {
const orderedMessageKeys = this.sortMessages(nextProps.messages); const orderedMessageKeys = this.sortMessages(nextProps.messages);
this.setState({ hoveredMessages: [], orderedMessageKeys }); this.setState({ hoveredMessages: [], orderedMessageKeys });
} else if ( } else if (
this.state.orderedMessageKeys.length === 0 || this.state.orderedMessageKeys.length === 0
(!this.props.live && || (!this.props.live
this.props.messages && && this.props.messages
nextProps.messages && && nextProps.messages
this.byteCountsDidUpdate(this.props.messages, nextProps.messages)) && this.byteCountsDidUpdate(this.props.messages, nextProps.messages))
) { ) {
const orderedMessageKeys = this.sortMessages(nextProps.messages); const orderedMessageKeys = this.sortMessages(nextProps.messages);
this.setState({ orderedMessageKeys }); this.setState({ orderedMessageKeys });
@ -94,9 +95,8 @@ export default class Meta extends Component {
byteCountsDidUpdate(prevMessages, nextMessages) { byteCountsDidUpdate(prevMessages, nextMessages) {
return Object.entries(nextMessages).some( return Object.entries(nextMessages).some(
([msgId, msg]) => ([msgId, msg]) => JSON.stringify(msg.byteStateChangeCounts)
JSON.stringify(msg.byteStateChangeCounts) !== !== JSON.stringify(prevMessages[msgId].byteStateChangeCounts)
JSON.stringify(prevMessages[msgId].byteStateChangeCounts)
); );
} }
@ -121,27 +121,22 @@ export default class Meta extends Component {
{} {}
); );
const entryCounts = Object.keys(messagesByEntryCount).map(count => const entryCounts = Object.keys(messagesByEntryCount).map((count) => parseInt(count, 10));
parseInt(count, 10)
);
const binnedEntryCounts = ckmeans( const binnedEntryCounts = ckmeans(
entryCounts, entryCounts,
Math.min(entryCounts.length, 10) Math.min(entryCounts.length, 10)
); );
const sortedKeys = binnedEntryCounts const sortedKeys = binnedEntryCounts
.map(bin => .map((bin) => bin
bin .map((entryCount) => messagesByEntryCount[entryCount.toString()])
.map(entryCount => messagesByEntryCount[entryCount.toString()]) .reduce((messages, partial) => messages.concat(partial), [])
.reduce((messages, partial) => messages.concat(partial), []) .sort((msg1, msg2) => {
.sort((msg1, msg2) => { if (msg1.address < msg2.address) {
if (msg1.address < msg2.address) { return 1;
return 1; }
} else { return -1;
return -1; })
} .map((msg) => msg.id))
})
.map(msg => msg.id)
)
.reduce((keys, bin) => keys.concat(bin), []) .reduce((keys, bin) => keys.concat(bin), [])
.reverse(); .reverse();
@ -156,20 +151,20 @@ export default class Meta extends Component {
onFilterChanged(e) { onFilterChanged(e) {
let val = e.target.value; let val = e.target.value;
if (val.trim() === "Filter") val = ""; if (val.trim() === 'Filter') val = '';
this.setState({ filterText: val }); this.setState({ filterText: val });
} }
onFilterFocus(e) { onFilterFocus(e) {
if (this.state.filterText.trim() === "Filter") { if (this.state.filterText.trim() === 'Filter') {
this.setState({ filterText: "" }); this.setState({ filterText: '' });
} }
} }
onFilterUnfocus(e) { onFilterUnfocus(e) {
if (this.state.filterText.trim() === "") { if (this.state.filterText.trim() === '') {
this.setState({ filterText: "Filter" }); this.setState({ filterText: 'Filter' });
} }
} }
@ -178,13 +173,13 @@ export default class Meta extends Component {
return; return;
} }
const { filterText } = this.state; const { filterText } = this.state;
const msgName = msg.frame ? msg.frame.name : ""; const msgName = msg.frame ? msg.frame.name : '';
return ( return (
filterText === "Filter" || filterText === 'Filter'
filterText === "" || || filterText === ''
msg.id.toLowerCase().indexOf(filterText.toLowerCase()) !== -1 || || msg.id.toLowerCase().indexOf(filterText.toLowerCase()) !== -1
msgName.toLowerCase().indexOf(filterText.toLowerCase()) !== -1 || msgName.toLowerCase().indexOf(filterText.toLowerCase()) !== -1
); );
} }
@ -193,13 +188,13 @@ export default class Meta extends Component {
return; return;
} }
const { filterText } = this.state; const { filterText } = this.state;
const msgName = msg.frame ? msg.frame.name : ""; const msgName = msg.frame ? msg.frame.name : '';
return ( return (
filterText === "Filter" || filterText === 'Filter'
filterText === "" || || filterText === ''
msg.id.toLowerCase().indexOf(filterText.toLowerCase()) !== -1 || || msg.id.toLowerCase().indexOf(filterText.toLowerCase()) !== -1
msgName.toLowerCase().indexOf(filterText.toLowerCase()) !== -1 || msgName.toLowerCase().indexOf(filterText.toLowerCase()) !== -1
); );
} }
@ -209,7 +204,7 @@ export default class Meta extends Component {
} }
onMessageHover(key) { onMessageHover(key) {
let { hoveredMessages } = this.state; const { hoveredMessages } = this.state;
if (hoveredMessages.indexOf(key) !== -1) return; if (hoveredMessages.indexOf(key) !== -1) return;
hoveredMessages.push(key); hoveredMessages.push(key);
@ -218,13 +213,13 @@ export default class Meta extends Component {
onMessageHoverEnd(key) { onMessageHoverEnd(key) {
let { hoveredMessages } = this.state; let { hoveredMessages } = this.state;
hoveredMessages = hoveredMessages.filter(m => m !== key); hoveredMessages = hoveredMessages.filter((m) => m !== key);
this.setState({ hoveredMessages }); this.setState({ hoveredMessages });
} }
onMsgRemoveClick(key) { onMsgRemoveClick(key) {
let { selectedMessages } = this.state; let { selectedMessages } = this.state;
selectedMessages = selectedMessages.filter(m => m !== key); selectedMessages = selectedMessages.filter((m) => m !== key);
this.props.onMessageUnselected(key); this.props.onMessageUnselected(key);
this.setState({ selectedMessages }); this.setState({ selectedMessages });
} }
@ -241,12 +236,12 @@ export default class Meta extends Component {
orderedMessages() { orderedMessages() {
const { orderedMessageKeys } = this.state; const { orderedMessageKeys } = this.state;
const { messages } = this.props; const { messages } = this.props;
return orderedMessageKeys.map(key => messages[key]); return orderedMessageKeys.map((key) => messages[key]);
} }
selectedMessageClass(messageId) { selectedMessageClass(messageId) {
return this.props.selectedMessages.includes(messageId) return this.props.selectedMessages.includes(messageId)
? "is-selected" ? 'is-selected'
: null; : null;
} }
@ -258,17 +253,17 @@ export default class Meta extends Component {
}} }}
key={msg.id} key={msg.id}
className={cx( className={cx(
"cabana-meta-messages-list-item", 'cabana-meta-messages-list-item',
this.selectedMessageClass(msg.id) this.selectedMessageClass(msg.id)
)} )}
> >
{msg.isLogEvent ? ( {msg.isLogEvent ? (
<td colSpan="2">{msg.id}</td> <td colSpan="2">{msg.id}</td>
) : ( ) : (
<React.Fragment> <>
<td>{msg.frame ? msg.frame.name : "untitled"}</td> <td>{msg.frame ? msg.frame.name : 'untitled'}</td>
<td>{msg.id}</td> <td>{msg.id}</td>
</React.Fragment> </>
)} )}
<td>{msg.entries.length}</td> <td>{msg.entries.length}</td>
<td> <td>
@ -303,10 +298,10 @@ export default class Meta extends Component {
return <p>Loading messages...</p>; return <p>Loading messages...</p>;
} }
return ( return (
<React.Fragment> <>
<table cellPadding="5"> <table cellPadding="5">
{this.state.showLogEvents && ( {this.state.showLogEvents && (
<React.Fragment> <>
<thead> <thead>
<tr> <tr>
<td colSpan="2">Name</td> <td colSpan="2">Name</td>
@ -322,7 +317,7 @@ export default class Meta extends Component {
</td> </td>
</tr> </tr>
</tbody> </tbody>
</React.Fragment> </>
)} )}
<thead> <thead>
<tr> <tr>
@ -334,7 +329,7 @@ export default class Meta extends Component {
</thead> </thead>
<tbody>{this.renderCanMessages()}</tbody> <tbody>{this.renderCanMessages()}</tbody>
</table> </table>
</React.Fragment> </>
); );
} }
@ -342,13 +337,14 @@ export default class Meta extends Component {
try { try {
// eslint-disable-next-line // eslint-disable-next-line
"serviceWorker" in navigator && "serviceWorker" in navigator &&
!!new ReadableStream() && !!new ReadableStream()
!!new WritableStream(); // eslint-disable-line no-undef && !!new WritableStream(); // eslint-disable-line no-undef
return "saveable"; return 'saveable';
} catch (e) { } catch (e) {
return false; return false;
} }
} }
render() { render() {
return ( return (
<div className="cabana-meta"> <div className="cabana-meta">
@ -361,7 +357,10 @@ export default class Meta extends Component {
</strong> </strong>
{this.props.dbcLastSaved !== null ? ( {this.props.dbcLastSaved !== null ? (
<div className="cabana-meta-header-last-saved"> <div className="cabana-meta-header-last-saved">
<p>Last saved: {this.lastSavedPretty()}</p> <p>
Last saved:
{this.lastSavedPretty()}
</p>
</div> </div>
) : null} ) : null}
<div className={`cabana-meta-header-actions ${this.saveable()}`}> <div className={`cabana-meta-header-actions ${this.saveable()}`}>
@ -378,12 +377,12 @@ export default class Meta extends Component {
className="cabana-meta-header-action special-wide" className="cabana-meta-header-action special-wide"
data-clipboard-text={this.props.shareUrl} data-clipboard-text={this.props.shareUrl}
data-clipboard-action="copy" data-clipboard-action="copy"
ref={ref => (ref ? new Clipboard(ref) : null)} ref={(ref) => (ref ? new Clipboard(ref) : null)}
> >
<a <a
className="button" className="button"
href={this.props.shareUrl} href={this.props.shareUrl}
onClick={e => e.preventDefault()} onClick={(e) => e.preventDefault()}
> >
Copy Share Link Copy Share Link
</a> </a>
@ -398,8 +397,8 @@ export default class Meta extends Component {
<div className="cabana-meta-messages-header"> <div className="cabana-meta-messages-header">
<div <div
style={{ style={{
display: "inline-block", display: 'inline-block',
float: "right" float: 'right'
}} }}
> >
<h5 className="t-capline"> <h5 className="t-capline">

View File

@ -1,12 +1,12 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import Moment from "moment"; import Moment from 'moment';
import _ from "lodash"; import _ from 'lodash';
import cx from "classnames"; import cx from 'classnames';
import CommaAuth from "@commaai/my-comma-auth"; import CommaAuth from '@commaai/my-comma-auth';
import { EXPLORER_URL } from "../../config"; import { EXPLORER_URL } from '../../config';
import Modal from "../Modals/baseModal"; import Modal from './baseModal';
export default class OnboardingModal extends Component { export default class OnboardingModal extends Component {
static propTypes = { static propTypes = {
@ -15,8 +15,8 @@ export default class OnboardingModal extends Component {
}; };
static instructionalImages = { static instructionalImages = {
step2: require("../../images/webusb-enable-experimental-features.png"), step2: require('../../images/webusb-enable-experimental-features.png'),
step3: require("../../images/webusb-enable-webusb.png") step3: require('../../images/webusb-enable-webusb.png')
}; };
constructor(props) { constructor(props) {
@ -66,7 +66,8 @@ export default class OnboardingModal extends Component {
</a> </a>
</p> </p>
); );
} else if (!pandaConnected && attemptingPandaConnection) { }
if (!pandaConnected && attemptingPandaConnection) {
return ( return (
<p> <p>
<i className="fa fa-spinner animate-spin" /> <i className="fa fa-spinner animate-spin" />
@ -87,8 +88,8 @@ export default class OnboardingModal extends Component {
<i className="fa fa-video-camera" /> <i className="fa fa-video-camera" />
<strong> <strong>
{CommaAuth.isAuthenticated() {CommaAuth.isAuthenticated()
? "Find a drive in Explorer" ? 'Find a drive in Explorer'
: "Log in with Explorer"} : 'Log in with Explorer'}
</strong> </strong>
<sup>Click "View CAN Data" while replaying a drive</sup> <sup>Click "View CAN Data" while replaying a drive</sup>
</button> </button>
@ -101,17 +102,19 @@ export default class OnboardingModal extends Component {
<div className="cabana-onboarding-mode">{this.renderLogin()}</div> <div className="cabana-onboarding-mode">{this.renderLogin()}</div>
<div className="cabana-onboarding-mode"> <div className="cabana-onboarding-mode">
<button <button
className={cx("button--secondary button--kiosk", { className={cx('button--secondary button--kiosk', {
"is-disabled": 'is-disabled':
!this.state.webUsbEnabled || !this.state.webUsbEnabled
this.props.attemptingPandaConnection || this.props.attemptingPandaConnection
})} })}
onClick={this.attemptPandaConnection} onClick={this.attemptPandaConnection}
> >
<i className="fa fa-bolt" /> <i className="fa fa-bolt" />
<strong>Launch Realtime Streaming</strong> <strong>Launch Realtime Streaming</strong>
<sup> <sup>
Interactively stream car data over USB with <em>panda</em> Interactively stream car data over USB with
{' '}
<em>panda</em>
</sup> </sup>
{this.renderPandaEligibility()} {this.renderPandaEligibility()}
</button> </button>
@ -147,7 +150,7 @@ export default class OnboardingModal extends Component {
<strong>Enable Experimental Platform features:</strong> <strong>Enable Experimental Platform features:</strong>
</p> </p>
<img <img
alt={"Screenshot of Google Chrome Experimental Platform features"} alt="Screenshot of Google Chrome Experimental Platform features"
src={OnboardingModal.instructionalImages.step2} src={OnboardingModal.instructionalImages.step2}
/> />
</li> </li>
@ -156,7 +159,7 @@ export default class OnboardingModal extends Component {
<strong>Enable WebUSB:</strong> <strong>Enable WebUSB:</strong>
</p> </p>
<img <img
alt={"Screenshot of Google Chrome enable WebUSB"} alt="Screenshot of Google Chrome enable WebUSB"
src={OnboardingModal.instructionalImages.step3} src={OnboardingModal.instructionalImages.step3}
/> />
</li> </li>
@ -175,23 +178,25 @@ export default class OnboardingModal extends Component {
renderModalContent() { renderModalContent() {
if (this.state.viewingUsbInstructions) { if (this.state.viewingUsbInstructions) {
return this.renderUsbInstructions(); return this.renderUsbInstructions();
} else {
return this.renderOnboardingOptions();
} }
return this.renderOnboardingOptions();
} }
renderModalFooter() { renderModalFooter() {
return ( return (
<p> <p>
<span> <span>
Don't have a{" "} Don't have a
{' '}
<a <a
href="https://panda.comma.ai" href="https://panda.comma.ai"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
panda panda
</a>?{" "} </a>
?
{' '}
</span> </span>
<span> <span>
<a <a
@ -200,10 +205,14 @@ export default class OnboardingModal extends Component {
rel="noopener noreferrer" rel="noopener noreferrer"
> >
Get one here Get one here
</a>{" "} </a>
{' '}
</span> </span>
<span> <span>
or <a href={`${window.location.href}?demo=1`}>try the demo</a>. or
{' '}
<a href={`${window.location.href}?demo=1`}>try the demo</a>
.
</span> </span>
</p> </p>
); );
@ -215,8 +224,8 @@ export default class OnboardingModal extends Component {
title="Welcome to Cabana" title="Welcome to Cabana"
subtitle="Get started by selecting a drive from Explorer or enabling live mode" subtitle="Get started by selecting a drive from Explorer or enabling live mode"
footer={this.renderModalFooter()} footer={this.renderModalFooter()}
disableClose={true} disableClose
variations={["wide", "dark"]} variations={['wide', 'dark']}
> >
{this.renderModalContent()} {this.renderModalContent()}
</Modal> </Modal>

View File

@ -1,7 +1,7 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import cx from "classnames"; import cx from 'classnames';
import Measure from "react-measure"; import Measure from 'react-measure';
export default class Modal extends Component { export default class Modal extends Component {
static propTypes = { static propTypes = {
@ -36,8 +36,8 @@ export default class Modal extends Component {
if (this.props.variations) { if (this.props.variations) {
const { variations } = this.props; const { variations } = this.props;
const classes = variations.reduce( const classes = variations.reduce(
(classes, variation) => classes + `cabana-modal--${variation} `, (classes, variation) => `${classes}cabana-modal--${variation} `,
"" ''
); );
return classes; return classes;
} }
@ -54,14 +54,14 @@ export default class Modal extends Component {
render() { render() {
return ( return (
<div <div
className={cx("cabana-modal", this.readVariationClasses(), { className={cx('cabana-modal', this.readVariationClasses(), {
"cabana-modal--not-closable": this.checkClosability(), 'cabana-modal--not-closable': this.checkClosability(),
"cabana-modal--scrollable-y": this.checkYScrollability() 'cabana-modal--scrollable-y': this.checkYScrollability()
})} })}
> >
<Measure <Measure
bounds bounds
onResize={contentRect => { onResize={(contentRect) => {
this.updateHeights(contentRect); this.updateHeights(contentRect);
}} }}
> >

View File

@ -1,10 +1,11 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import { PART_SEGMENT_LENGTH } from "../config"; import { PART_SEGMENT_LENGTH } from '../config';
export default class PartSelector extends Component { export default class PartSelector extends Component {
static selectorWidth = 150; static selectorWidth = 150;
static propTypes = { static propTypes = {
onPartChange: PropTypes.func.isRequired, onPartChange: PropTypes.func.isRequired,
partsCount: PropTypes.number.isRequired, partsCount: PropTypes.number.isRequired,
@ -29,14 +30,14 @@ export default class PartSelector extends Component {
makePartStyle(partsCount, selectedPart) { makePartStyle(partsCount, selectedPart) {
return { return {
left: selectedPart / partsCount * PartSelector.selectorWidth, left: (selectedPart / partsCount) * PartSelector.selectorWidth,
width: PART_SEGMENT_LENGTH / partsCount * PartSelector.selectorWidth width: (PART_SEGMENT_LENGTH / partsCount) * PartSelector.selectorWidth
}; };
} }
componentWillUpdate(nextProps, nextState) { componentWillUpdate(nextProps, nextState) {
if (nextProps.selectedPart !== this.props.selectedPart) { if (nextProps.selectedPart !== this.props.selectedPart) {
console.log("updating styles for part picker"); console.log('updating styles for part picker');
const selectedPartStyle = this.makePartStyle( const selectedPartStyle = this.makePartStyle(
nextProps.partsCount, nextProps.partsCount,
nextProps.selectedPart nextProps.selectedPart
@ -80,12 +81,12 @@ export default class PartSelector extends Component {
partAtClientX(clientX) { partAtClientX(clientX) {
const rect = this.selectorRect.getBoundingClientRect(); const rect = this.selectorRect.getBoundingClientRect();
const x = clientX - rect.left; const x = clientX - rect.left;
return Math.floor(x * this.props.partsCount / PartSelector.selectorWidth); return Math.floor((x * this.props.partsCount) / PartSelector.selectorWidth);
} }
onSelectedPartDragStart(e) { onSelectedPartDragStart(e) {
this.setState({ isDragging: true }); this.setState({ isDragging: true });
document.addEventListener("mouseup", this.onSelectedPartDragEnd); document.addEventListener('mouseup', this.onSelectedPartDragEnd);
} }
onSelectedPartMouseMove(e) { onSelectedPartMouseMove(e) {
@ -97,7 +98,7 @@ export default class PartSelector extends Component {
onSelectedPartDragEnd(e) { onSelectedPartDragEnd(e) {
this.setState({ isDragging: false }); this.setState({ isDragging: false });
document.removeEventListener("mouseup", this.onSelectedPartDragEnd); document.removeEventListener('mouseup', this.onSelectedPartDragEnd);
} }
onClick(e) { onClick(e) {
@ -116,7 +117,7 @@ export default class PartSelector extends Component {
<div className="cabana-explorer-part-selector"> <div className="cabana-explorer-part-selector">
<div <div
className="cabana-explorer-part-selector-track" className="cabana-explorer-part-selector-track"
ref={selector => (this.selectorRect = selector)} ref={(selector) => (this.selectorRect = selector)}
style={{ width: PartSelector.selectorWidth }} style={{ width: PartSelector.selectorWidth }}
onMouseMove={this.onSelectedPartMouseMove} onMouseMove={this.onSelectedPartMouseMove}
onClick={this.onClick} onClick={this.onClick}

View File

@ -1,5 +1,5 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
export default class PlayButton extends Component { export default class PlayButton extends Component {
static propTypes = { static propTypes = {
@ -21,29 +21,18 @@ export default class PlayButton extends Component {
const { isPlaying } = this.props; const { isPlaying } = this.props;
if (isPlaying) { if (isPlaying) {
if (hover) { if (hover) {
return ( return `${process.env.PUBLIC_URL}/img/ic_pause_circle_filled_white_24px.svg`;
process.env.PUBLIC_URL + "/img/ic_pause_circle_filled_white_24px.svg"
);
} else {
return (
process.env.PUBLIC_URL + "/img/ic_pause_circle_outline_white_24px.svg"
);
}
} else {
if (hover) {
return (
process.env.PUBLIC_URL + "/img/ic_play_circle_filled_white_24px.svg"
);
} else {
return (
process.env.PUBLIC_URL + "/img/ic_play_circle_outline_white_24px.svg"
);
} }
return `${process.env.PUBLIC_URL}/img/ic_pause_circle_outline_white_24px.svg`;
} }
if (hover) {
return `${process.env.PUBLIC_URL}/img/ic_play_circle_filled_white_24px.svg`;
}
return `${process.env.PUBLIC_URL}/img/ic_play_circle_outline_white_24px.svg`;
} }
onClick(e) { onClick(e) {
let { isPlaying } = this.props; const { isPlaying } = this.props;
if (!isPlaying) { if (!isPlaying) {
this.props.onPlay(); this.props.onPlay();
@ -56,7 +45,7 @@ export default class PlayButton extends Component {
return ( return (
<img <img
src={this.imageSource()} src={this.imageSource()}
alt={this.props.isPlaying ? "Pause" : "Play"} alt={this.props.isPlaying ? 'Pause' : 'Play'}
className={this.props.className} className={this.props.className}
onClick={this.onClick} onClick={this.onClick}
onMouseOver={() => this.setState({ hover: true })} onMouseOver={() => this.setState({ hover: true })}

View File

@ -1,4 +1,4 @@
import React, { Component } from "react"; import React, { Component } from 'react';
export default class PlaySpeedSelector extends Component { export default class PlaySpeedSelector extends Component {
constructor(props) { constructor(props) {
@ -16,8 +16,8 @@ export default class PlaySpeedSelector extends Component {
return ( return (
<div <div
style={{ style={{
display: "inline-block", display: 'inline-block',
float: "right", float: 'right',
margin: 10 margin: 10
}} }}
> >

View File

@ -1,7 +1,7 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import PlayButton from "../PlayButton"; import PlayButton from '../PlayButton';
import debounce from "../../utils/debounce"; import debounce from '../../utils/debounce';
export default class RouteSeeker extends Component { export default class RouteSeeker extends Component {
static propTypes = { static propTypes = {
@ -18,10 +18,14 @@ export default class RouteSeeker extends Component {
nearestFrameTime: PropTypes.number nearestFrameTime: PropTypes.number
}; };
static hiddenMarkerStyle = { display: "none", left: 0 }; static hiddenMarkerStyle = { display: 'none', left: 0 };
static zeroSeekedBarStyle = { width: 0 }; static zeroSeekedBarStyle = { width: 0 };
static hiddenTooltipStyle = { display: "none", left: 0 };
static hiddenTooltipStyle = { display: 'none', left: 0 };
static markerWidth = 20; static markerWidth = 20;
static tooltipWidth = 50; static tooltipWidth = 50;
constructor(props) { constructor(props) {
@ -31,7 +35,7 @@ export default class RouteSeeker extends Component {
markerStyle: RouteSeeker.hiddenMarkerStyle, markerStyle: RouteSeeker.hiddenMarkerStyle,
tooltipStyle: RouteSeeker.hiddenTooltipStyle, tooltipStyle: RouteSeeker.hiddenTooltipStyle,
ratio: 0, ratio: 0,
tooltipTime: "0:00", tooltipTime: '0:00',
isPlaying: false, isPlaying: false,
isDragging: false isDragging: false
}; };
@ -50,8 +54,8 @@ export default class RouteSeeker extends Component {
const { ratio } = this.state; const { ratio } = this.state;
if ( if (
JSON.stringify(this.props.segmentIndices) !== JSON.stringify(this.props.segmentIndices)
JSON.stringify(nextProps.segmentIndices) !== JSON.stringify(nextProps.segmentIndices)
) { ) {
this.setState({ this.setState({
seekedBarStyle: RouteSeeker.zeroSeekedBarStyle, seekedBarStyle: RouteSeeker.zeroSeekedBarStyle,
@ -88,7 +92,7 @@ export default class RouteSeeker extends Component {
return 100 * (x / this.progressBar.offsetWidth); return 100 * (x / this.progressBar.offsetWidth);
} }
updateDraggingSeek = debounce(ratio => this.props.onUserSeek(ratio), 250); updateDraggingSeek = debounce((ratio) => this.props.onUserSeek(ratio), 250);
onMouseMove(e) { onMouseMove(e) {
const markerOffsetPct = this.mouseEventXOffsetPercent(e); const markerOffsetPct = this.mouseEventXOffsetPercent(e);
@ -96,18 +100,18 @@ export default class RouteSeeker extends Component {
this.onMouseLeave(); this.onMouseLeave();
return; return;
} }
const markerWidth = RouteSeeker.markerWidth; const { markerWidth } = RouteSeeker;
const markerLeft = `calc(${markerOffsetPct + "%"} - ${markerWidth / 2}px)`; const markerLeft = `calc(${`${markerOffsetPct}%`} - ${markerWidth / 2}px)`;
const markerStyle = { const markerStyle = {
display: "", display: '',
left: markerLeft left: markerLeft
}; };
const tooltipWidth = RouteSeeker.tooltipWidth; const { tooltipWidth } = RouteSeeker;
const tooltipLeft = `calc(${markerOffsetPct + "%"} - ${tooltipWidth / const tooltipLeft = `calc(${`${markerOffsetPct}%`} - ${tooltipWidth
2}px)`; / 2}px)`;
const tooltipStyle = { display: "flex", left: tooltipLeft }; const tooltipStyle = { display: 'flex', left: tooltipLeft };
const ratio = Math.max(0, markerOffsetPct / 100); const ratio = Math.max(0, markerOffsetPct / 100);
if (this.state.isDragging) { if (this.state.isDragging) {
this.updateSeekedBar(ratio); this.updateSeekedBar(ratio);
@ -130,7 +134,7 @@ export default class RouteSeeker extends Component {
} }
updateSeekedBar(ratio) { updateSeekedBar(ratio) {
const seekedBarStyle = { width: 100 * ratio + "%" }; const seekedBarStyle = { width: `${100 * ratio}%` };
this.setState({ seekedBarStyle, ratio }); this.setState({ seekedBarStyle, ratio });
} }
@ -210,32 +214,32 @@ export default class RouteSeeker extends Component {
return ( return (
<div className="cabana-explorer-visuals-camera-seeker"> <div className="cabana-explorer-visuals-camera-seeker">
<PlayButton <PlayButton
className={"cabana-explorer-visuals-camera-seeker-playbutton"} className="cabana-explorer-visuals-camera-seeker-playbutton"
onPlay={this.onPlay} onPlay={this.onPlay}
onPause={this.onPause} onPause={this.onPause}
isPlaying={this.state.isPlaying} isPlaying={this.state.isPlaying}
/> />
<div <div
className={"cabana-explorer-visuals-camera-seeker-progress"} className="cabana-explorer-visuals-camera-seeker-progress"
onMouseMove={this.onMouseMove} onMouseMove={this.onMouseMove}
onMouseLeave={this.onMouseLeave} onMouseLeave={this.onMouseLeave}
onMouseDown={this.onMouseDown} onMouseDown={this.onMouseDown}
onMouseUp={this.onMouseUp} onMouseUp={this.onMouseUp}
onClick={this.onClick} onClick={this.onClick}
ref={ref => (this.progressBar = ref)} ref={(ref) => (this.progressBar = ref)}
> >
<div <div
className={"cabana-explorer-visuals-camera-seeker-progress-tooltip"} className="cabana-explorer-visuals-camera-seeker-progress-tooltip"
style={tooltipStyle} style={tooltipStyle}
> >
{this.state.tooltipTime} {this.state.tooltipTime}
</div> </div>
<div <div
className={"cabana-explorer-visuals-camera-seeker-progress-marker"} className="cabana-explorer-visuals-camera-seeker-progress-marker"
style={markerStyle} style={markerStyle}
/> />
<div <div
className={"cabana-explorer-visuals-camera-seeker-progress-inner"} className="cabana-explorer-visuals-camera-seeker-progress-inner"
style={seekedBarStyle} style={seekedBarStyle}
/> />
</div> </div>

View File

@ -1,2 +1,3 @@
import RouteSeeker from "./RouteSeeker"; import RouteSeeker from './RouteSeeker';
export default RouteSeeker; export default RouteSeeker;

View File

@ -1,44 +1,44 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import { StyleSheet, css } from "aphrodite/no-important"; import { StyleSheet, css } from 'aphrodite/no-important';
import { derived as RouteApi, video as VideoApi } from "@commaai/comma-api"; import { derived as RouteApi, video as VideoApi } from '@commaai/comma-api';
import HLS from "./HLS"; import HLS from './HLS';
import RouteSeeker from "./RouteSeeker/RouteSeeker"; import RouteSeeker from './RouteSeeker/RouteSeeker';
const Styles = StyleSheet.create({ const Styles = StyleSheet.create({
loadingOverlay: { loadingOverlay: {
position: "absolute", position: 'absolute',
top: 0, top: 0,
left: 0, left: 0,
width: "100%", width: '100%',
height: "100%", height: '100%',
display: "flex", display: 'flex',
justifyContent: "center", justifyContent: 'center',
alignItems: "center", alignItems: 'center',
zIndex: 3 zIndex: 3
}, },
loadingSpinner: { loadingSpinner: {
width: "25%", width: '25%',
height: "25%", height: '25%',
display: "block" display: 'block'
}, },
img: { img: {
height: 480, height: 480,
display: "block", display: 'block',
position: "absolute", position: 'absolute',
zIndex: 2 zIndex: 2
}, },
hls: { hls: {
zIndex: 1, zIndex: 1,
height: 480, height: 480,
backgroundColor: "rgba(0,0,0,0.9)" backgroundColor: 'rgba(0,0,0,0.9)'
}, },
seekBar: { seekBar: {
position: "absolute", position: 'absolute',
bottom: 0, bottom: 0,
left: 0, left: 0,
width: "100%", width: '100%',
zIndex: 4 zIndex: 4
} }
}); });
@ -79,17 +79,17 @@ export default class RouteVideoSync extends Component {
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if ( if (
this.props.userSeekIndex !== nextProps.userSeekIndex || this.props.userSeekIndex !== nextProps.userSeekIndex
this.props.canFrameOffset !== nextProps.canFrameOffset || || this.props.canFrameOffset !== nextProps.canFrameOffset
(this.props.message && || (this.props.message
nextProps.message && && nextProps.message
this.props.message.entries.length !== nextProps.message.entries.length) && this.props.message.entries.length !== nextProps.message.entries.length)
) { ) {
this.setState({ shouldRestartHls: true }); this.setState({ shouldRestartHls: true });
} }
if ( if (
nextProps.userSeekTime && nextProps.userSeekTime
this.props.userSeekTime !== nextProps.userSeekTime && this.props.userSeekTime !== nextProps.userSeekTime
) { ) {
if (this.state.videoElement) { if (this.state.videoElement) {
this.state.videoElement.currentTime = nextProps.userSeekTime; this.state.videoElement.currentTime = nextProps.userSeekTime;
@ -111,8 +111,8 @@ export default class RouteVideoSync extends Component {
<div className={css(Styles.loadingOverlay)}> <div className={css(Styles.loadingOverlay)}>
<img <img
className={css(Styles.loadingSpinner)} className={css(Styles.loadingSpinner)}
src={process.env.PUBLIC_URL + "/img/loading.svg"} src={`${process.env.PUBLIC_URL}/img/loading.svg`}
alt={"Loading video"} alt="Loading video"
/> />
</div> </div>
); );
@ -154,7 +154,7 @@ export default class RouteVideoSync extends Component {
segmentProgress(currentTime) { segmentProgress(currentTime) {
// returns progress as number in [0,1] // returns progress as number in [0,1]
let startTime = this.startTime(); const startTime = this.startTime();
if (currentTime < startTime) { if (currentTime < startTime) {
currentTime = startTime; currentTime = startTime;
@ -175,12 +175,12 @@ export default class RouteVideoSync extends Component {
onUserSeek(ratio) { onUserSeek(ratio) {
/* ratio in [0,1] */ /* ratio in [0,1] */
let { videoElement } = this.state; const { videoElement } = this.state;
if (isNaN(videoElement.duration)) { if (isNaN(videoElement.duration)) {
this.setState({ shouldRestartHls: true }, funcSeekToRatio); this.setState({ shouldRestartHls: true }, funcSeekToRatio);
return; return;
} }
let seekTime = this.ratioTime(ratio); const seekTime = this.ratioTime(ratio);
videoElement.currentTime = seekTime; videoElement.currentTime = seekTime;
const funcSeekToRatio = () => this.props.onUserSeek(seekTime); const funcSeekToRatio = () => this.props.onUserSeek(seekTime);
@ -203,7 +203,7 @@ export default class RouteVideoSync extends Component {
<img <img
src={this.nearestFrameUrl()} src={this.nearestFrameUrl()}
className={css(Styles.img)} className={css(Styles.img)}
alt={"Camera preview at t = " + Math.round(this.props.userSeekTime)} alt={`Camera preview at t = ${Math.round(this.props.userSeekTime)}`}
/> />
) : null} ) : null}
<HLS <HLS

View File

@ -1,11 +1,11 @@
import React, { Component } from "react"; import React, { Component } from 'react';
import cx from "classnames"; import cx from 'classnames';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import FileSaver from "file-saver"; import FileSaver from 'file-saver';
import OpenDbc from "../api/OpenDbc"; import OpenDbc from '../api/OpenDbc';
import DBC from "../models/can/dbc"; import DBC from '../models/can/dbc';
import Modal from "./Modals/baseModal"; import Modal from './Modals/baseModal';
// import TabStyles from '../styles/modal-tabs'; // import TabStyles from '../styles/modal-tabs';
export default class SaveDbcModal extends Component { export default class SaveDbcModal extends Component {
@ -22,11 +22,11 @@ export default class SaveDbcModal extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
tab: "GitHub", tab: 'GitHub',
openDbcFork: null, openDbcFork: null,
dbcFilename: this.props.sourceDbcFilename, dbcFilename: this.props.sourceDbcFilename,
tabs: ["GitHub", "Download"], tabs: ['GitHub', 'Download'],
commitMessage: "OpenDBC updates" commitMessage: 'OpenDBC updates'
}; };
this.commitToGitHub = this.commitToGitHub.bind(this); this.commitToGitHub = this.commitToGitHub.bind(this);
@ -44,7 +44,7 @@ export default class SaveDbcModal extends Component {
async commitToGitHub() { async commitToGitHub() {
const { openDbcFork, dbcFilename } = this.state; const { openDbcFork, dbcFilename } = this.state;
const filename = dbcFilename.replace(/\.dbc/g, "") + ".dbc"; const filename = `${dbcFilename.replace(/\.dbc/g, '')}.dbc`;
const success = await this.props.openDbcClient.commitFile( const success = await this.props.openDbcClient.commitFile(
openDbcFork, openDbcFork,
filename, filename,
@ -58,9 +58,9 @@ export default class SaveDbcModal extends Component {
async downloadDbcFile() { async downloadDbcFile() {
const blob = new Blob([this.props.dbc.text()], { const blob = new Blob([this.props.dbc.text()], {
type: "text/plain;charset=utf-8" type: 'text/plain;charset=utf-8'
}); });
const filename = this.state.dbcFilename.replace(/\.dbc/g, "") + ".dbc"; const filename = `${this.state.dbcFilename.replace(/\.dbc/g, '')}.dbc`;
FileSaver.saveAs(blob, filename, true); FileSaver.saveAs(blob, filename, true);
} }
@ -74,7 +74,7 @@ export default class SaveDbcModal extends Component {
const interval = window.setInterval(() => { const interval = window.setInterval(() => {
if (!isTimedOut) { if (!isTimedOut) {
this.props.openDbcClient.getUserOpenDbcFork().then(openDbcFork => { this.props.openDbcClient.getUserOpenDbcFork().then((openDbcFork) => {
if (openDbcFork !== null) { if (openDbcFork !== null) {
this.setState({ openDbcFork }); this.setState({ openDbcFork });
window.clearInterval(interval); window.clearInterval(interval);
@ -92,11 +92,12 @@ export default class SaveDbcModal extends Component {
primaryActionDisabled() { primaryActionDisabled() {
const { tab } = this.state; const { tab } = this.state;
if (tab === "GitHub") { if (tab === 'GitHub') {
return ( return (
this.state.openDbcFork != null && this.state.dbcFilename.length > 0 this.state.openDbcFork != null && this.state.dbcFilename.length > 0
); );
} else if (tab === "Download") { }
if (tab === 'Download') {
return true; return true;
} }
} }
@ -117,7 +118,11 @@ export default class SaveDbcModal extends Component {
content = ( content = (
<button disabled> <button disabled>
<i className="fa fa-code-fork" /> <i className="fa fa-code-fork" />
<span> Forked: {openDbcFork}</span> <span>
{' '}
Forked:
{openDbcFork}
</span>
</button> </button>
); );
} else if (this.props.hasGithubAuth) { } else if (this.props.hasGithubAuth) {
@ -144,9 +149,9 @@ export default class SaveDbcModal extends Component {
<input <input
type="text" type="text"
id="filename" id="filename"
value={this.state.dbcFilename.replace(/\.dbc/g, "")} value={this.state.dbcFilename.replace(/\.dbc/g, '')}
size={this.state.dbcFilename.length + 2} size={this.state.dbcFilename.length + 2}
onChange={e => this.setState({ dbcFilename: e.target.value })} onChange={(e) => this.setState({ dbcFilename: e.target.value })}
/> />
</div> </div>
); );
@ -155,19 +160,17 @@ export default class SaveDbcModal extends Component {
renderTabNavigation() { renderTabNavigation() {
return ( return (
<div className="cabana-tabs-navigation"> <div className="cabana-tabs-navigation">
{this.state.tabs.map(tab => { {this.state.tabs.map((tab) => (
return ( <a
<a className={cx({ 'is-active': this.state.tab === tab })}
className={cx({ "is-active": this.state.tab === tab })} onClick={() => {
onClick={() => { this.setState({ tab });
this.setState({ tab }); }}
}} key={tab}
key={tab} >
> <span>{tab}</span>
<span>{tab}</span> </a>
</a> ))}
);
})}
</div> </div>
); );
} }
@ -183,7 +186,7 @@ export default class SaveDbcModal extends Component {
type="text" type="text"
id="commit-message" id="commit-message"
value={this.state.commitMessage} value={this.state.commitMessage}
onChange={e => this.setState({ commitMessage: e.target.value })} onChange={(e) => this.setState({ commitMessage: e.target.value })}
/> />
</div> </div>
); );
@ -191,7 +194,7 @@ export default class SaveDbcModal extends Component {
renderTabContent() { renderTabContent() {
const { tab } = this.state; const { tab } = this.state;
if (tab === "GitHub") { if (tab === 'GitHub') {
return ( return (
<div> <div>
{this.renderForkStep()} {this.renderForkStep()}
@ -199,14 +202,15 @@ export default class SaveDbcModal extends Component {
{this.renderCommitMessage()} {this.renderCommitMessage()}
</div> </div>
); );
} else if (tab === "Download") { }
if (tab === 'Download') {
return <div>{this.renderFilenameField()}</div>; return <div>{this.renderFilenameField()}</div>;
} }
} }
renderActions() { renderActions() {
const { tab } = this.state; const { tab } = this.state;
if (tab === "GitHub") { if (tab === 'GitHub') {
return ( return (
<div> <div>
<button className="button--inverted" onClick={this.props.handleClose}> <button className="button--inverted" onClick={this.props.handleClose}>
@ -217,7 +221,8 @@ export default class SaveDbcModal extends Component {
</button> </button>
</div> </div>
); );
} else if (tab === "Download") { }
if (tab === 'Download') {
return ( return (
<div> <div>
<button className="button--inverted" onClick={this.props.handleClose}> <button className="button--inverted" onClick={this.props.handleClose}>

View File

@ -1,8 +1,8 @@
// SignalLegend.js // SignalLegend.js
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import SignalLegendEntry from "./SignalLegendEntry"; import SignalLegendEntry from './SignalLegendEntry';
export default class SignalLegend extends Component { export default class SignalLegend extends Component {
static propTypes = { static propTypes = {
@ -23,13 +23,13 @@ export default class SignalLegend extends Component {
expandedSignals: [] expandedSignals: []
}; };
toggleExpandSignal = s => { toggleExpandSignal = (s) => {
const { expandedSignals } = this.state; const { expandedSignals } = this.state;
if (!expandedSignals.includes(s.uid)) { if (!expandedSignals.includes(s.uid)) {
const updatedExpandedSignals = [...expandedSignals, s.uid]; const updatedExpandedSignals = [...expandedSignals, s.uid];
this.setState({ expandedSignals: updatedExpandedSignals }); this.setState({ expandedSignals: updatedExpandedSignals });
} else { } else {
const updatedExpandedSignals = expandedSignals.filter(i => i !== s.uid); const updatedExpandedSignals = expandedSignals.filter((i) => i !== s.uid);
this.setState({ expandedSignals: updatedExpandedSignals }); this.setState({ expandedSignals: updatedExpandedSignals });
} }
}; };
@ -44,9 +44,8 @@ export default class SignalLegend extends Component {
.sort(([_, signal1], [__, signal2]) => { .sort(([_, signal1], [__, signal2]) => {
if (signal1.startBit < signal2.startBit) { if (signal1.startBit < signal2.startBit) {
return -1; return -1;
} else {
return 1;
} }
return 1;
}) })
.map(([signalName, signal]) => { .map(([signalName, signal]) => {
const { colors } = signals[signalName]; const { colors } = signals[signalName];
@ -73,10 +72,8 @@ export default class SignalLegend extends Component {
}); });
const signalRows = signalRowsNested const signalRows = signalRowsNested
.filter(row => row != null) .filter((row) => row != null)
.reduce((a, b) => { .reduce((a, b) => a.concat(b), []);
return a.concat(b);
}, []);
return <div className="cabana-explorer-signals-legend">{signalRows}</div>; return <div className="cabana-explorer-signals-legend">{signalRows}</div>;
} }

View File

@ -1,12 +1,12 @@
import styled from "react-emotion"; import styled from 'react-emotion';
// color bar on the left side of the signals legend // color bar on the left side of the signals legend
export default styled("div")` export default styled('div')`
display: block; display: block;
height: 100%; height: 100%;
left: 0; left: 0;
position: absolute; position: absolute;
width: 1.5%; width: 1.5%;
opacity: ${({ isHighlighted }) => (isHighlighted ? 0.5 : 0.3)}; opacity: ${({ isHighlighted }) => (isHighlighted ? 0.5 : 0.3)};
background-color: rgb(${({ rgb }) => rgb.join(",")}); background-color: rgb(${({ rgb }) => rgb.join(',')});
`; `;

View File

@ -1,44 +1,41 @@
import DbcUtils from "../../utils/dbc"; import DbcUtils from '../../utils/dbc';
const unsignedTransformation = field => { const unsignedTransformation = (field) => (value, signal) => {
return (value, signal) => { if (value !== '') {
if (value !== "") { value = Number(value) || 0;
value = Number(value) || 0;
if (value < 0) { if (value < 0) {
value = 0; value = 0;
}
} }
signal[field] = value; }
return signal; signal[field] = value;
}; return signal;
}; };
export default [ export default [
{ {
field: "name", field: 'name',
title: "Name", title: 'Name',
type: "string" type: 'string'
}, },
{ {
field: "size", field: 'size',
title: "Size", title: 'Size',
type: "number", type: 'number',
transform: unsignedTransformation("size") transform: unsignedTransformation('size')
}, },
{ {
field: "startBit", field: 'startBit',
title: signal => title: (signal) => (signal.isLittleEndian ? 'Least significant bit' : 'Most significant bit'),
signal.isLittleEndian ? "Least significant bit" : "Most significant bit", type: 'number',
type: "number", transform: unsignedTransformation('startBit')
transform: unsignedTransformation("startBit")
}, },
{ {
field: "isLittleEndian", field: 'isLittleEndian',
title: "Endianness", title: 'Endianness',
type: "option", type: 'option',
options: { options: {
options: ["Little", "Big"], options: ['Little', 'Big'],
optionValues: { Little: true, Big: false } optionValues: { Little: true, Big: false }
}, },
transform: (isLittleEndian, signal) => { transform: (isLittleEndian, signal) => {
@ -47,8 +44,8 @@ export default [
if (isLittleEndian) { if (isLittleEndian) {
// big endian -> little endian // big endian -> little endian
const startByte = Math.floor(signal.startBit / 8), const startByte = Math.floor(signal.startBit / 8);
endByte = Math.floor((signal.startBit - signal.size + 1) / 8); const endByte = Math.floor((signal.startBit - signal.size + 1) / 8);
if (startByte === endByte) { if (startByte === endByte) {
signal.startBit = signal.startBit - signal.size + 1; signal.startBit = signal.startBit - signal.size + 1;
@ -57,8 +54,8 @@ export default [
} }
} else { } else {
// little endian -> big endian // little endian -> big endian
const startByte = Math.floor(signal.startBit / 8), const startByte = Math.floor(signal.startBit / 8);
endByte = Math.floor((signal.startBit + signal.size - 1) / 8); const endByte = Math.floor((signal.startBit + signal.size - 1) / 8);
if (startByte === endByte) { if (startByte === endByte) {
signal.startBit = signal.startBit + signal.size - 1; signal.startBit = signal.startBit + signal.size - 1;
@ -72,42 +69,42 @@ export default [
} }
}, },
{ {
field: "isSigned", field: 'isSigned',
title: "Sign", title: 'Sign',
type: "option", type: 'option',
options: { options: {
options: ["Signed", "Unsigned"], options: ['Signed', 'Unsigned'],
optionValues: { Signed: true, Unsigned: false } optionValues: { Signed: true, Unsigned: false }
} }
}, },
{ {
field: "factor", field: 'factor',
title: "Factor", title: 'Factor',
type: "number" type: 'number'
}, },
{ {
field: "offset", field: 'offset',
title: "Offset", title: 'Offset',
type: "number" type: 'number'
}, },
{ {
field: "unit", field: 'unit',
title: "Unit", title: 'Unit',
type: "string" type: 'string'
}, },
{ {
field: "comment", field: 'comment',
title: "Comment", title: 'Comment',
type: "string" type: 'string'
}, },
{ {
field: "min", field: 'min',
title: "Minimum value", title: 'Minimum value',
type: "number" type: 'number'
}, },
{ {
field: "max", field: 'max',
title: "Maximum value", title: 'Maximum value',
type: "number" type: 'number'
} }
]; ];

View File

@ -1,4 +1,4 @@
import React, { Component } from "react"; import React, { Component } from 'react';
export default class Field extends Component { export default class Field extends Component {
render() { render() {

View File

@ -1,5 +1,5 @@
import React from "react"; import React from 'react';
import Field from "./Field"; import Field from './Field';
export default ({ export default ({
fieldSpec, fieldSpec,
@ -14,27 +14,27 @@ export default ({
if (isExpanded) { if (isExpanded) {
let value = signalEdited; let value = signalEdited;
if (value !== "") { if (value !== '') {
let num = Number(value); const num = Number(value);
value = isNaN(num) ? "" : num; value = isNaN(num) ? '' : num;
} }
valueCol = ( valueCol = (
<input <input
id={htmlFor} id={htmlFor}
type="number" type="number"
value={value} value={value}
onChange={e => { onChange={(e) => {
updateField(fieldSpec, e.target.value); updateField(fieldSpec, e.target.value);
}} }}
/> />
); );
} else { } else {
let value = signal[field]; const value = signal[field];
valueCol = <span>{value}</span>; valueCol = <span>{value}</span>;
} }
return ( return (
<Field <Field
title={typeof title === "function" ? title(signal) : title} title={typeof title === 'function' ? title(signal) : title}
htmlFor={htmlFor} htmlFor={htmlFor}
> >
{valueCol} {valueCol}

View File

@ -1,7 +1,7 @@
import React from "react"; import React from 'react';
import Field from "./Field"; import Field from './Field';
import { swapKeysAndValues } from "../../utils/object"; import { swapKeysAndValues } from '../../utils/object';
export default ({ export default ({
fieldSpec, fieldSpec,
@ -14,10 +14,10 @@ export default ({
const { field, title } = fieldSpec; const { field, title } = fieldSpec;
const htmlFor = `${signal.name}_${field}`; const htmlFor = `${signal.name}_${field}`;
const { options, optionValues } = fieldSpec.options; const { options, optionValues } = fieldSpec.options;
let valueOptions = swapKeysAndValues(optionValues); const valueOptions = swapKeysAndValues(optionValues);
if (isExpanded) { if (isExpanded) {
const optionEles = options.map(opt => ( const optionEles = options.map((opt) => (
<option key={opt} value={optionValues[opt]}> <option key={opt} value={optionValues[opt]}>
{opt} {opt}
</option> </option>
@ -26,8 +26,8 @@ export default ({
<select <select
id={htmlFor} id={htmlFor}
defaultValue={signalEdited} defaultValue={signalEdited}
onChange={e => { onChange={(e) => {
updateField(fieldSpec, e.target.value === "true"); updateField(fieldSpec, e.target.value === 'true');
}} }}
> >
{optionEles} {optionEles}
@ -39,7 +39,7 @@ export default ({
return ( return (
<Field <Field
title={typeof title === "function" ? title(signal) : title} title={typeof title === 'function' ? title(signal) : title}
htmlFor={htmlFor} htmlFor={htmlFor}
> >
{valueCol} {valueCol}

View File

@ -1,9 +1,9 @@
import React from "react"; import React from 'react';
import FIELDS from "./FIELDS"; import FIELDS from './FIELDS';
import NumberField from "./NumberField"; import NumberField from './NumberField';
import StringField from "./StringField"; import StringField from './StringField';
import OptionField from "./OptionField"; import OptionField from './OptionField';
const FieldMap = { const FieldMap = {
number: NumberField, number: NumberField,
@ -17,31 +17,29 @@ export default ({
isExpanded, isExpanded,
getSignalEdited, getSignalEdited,
update update
}) => { }) => (
return ( <div className="signals-legend-entry-form">
<div className="signals-legend-entry-form"> {FIELDS.map((field) => {
{FIELDS.map(field => { const Node = FieldMap[field.type];
const Node = FieldMap[field.type]; return (
return ( <div className="signals-legend-entry-form-field" key={field.field}>
<div className="signals-legend-entry-form-field" key={field.field}> <Node
<Node fieldSpec={field}
fieldSpec={field} signal={signal}
signal={signal} isExpanded={isExpanded}
isExpanded={isExpanded} signalEdited={getSignalEdited(field.field)}
signalEdited={getSignalEdited(field.field)} updateField={update}
updateField={update} />
/> </div>
</div> );
); })}
})} <div className="signals-legend-entry-form-remove">
<div className="signals-legend-entry-form-remove"> <button
<button className="button--tiny button--alpha"
className="button--tiny button--alpha" onClick={() => onSignalRemove(signal)}
onClick={() => onSignalRemove(signal)} >
> Remove Signal
Remove Signal </button>
</button>
</div>
</div> </div>
); </div>
}; );

View File

@ -1,5 +1,5 @@
import React from "react"; import React from 'react';
import Field from "./Field"; import Field from './Field';
export default ({ export default ({
fieldSpec, fieldSpec,
@ -16,8 +16,8 @@ export default ({
<input <input
id={htmlFor} id={htmlFor}
type="text" type="text"
value={signalEdited || ""} value={signalEdited || ''}
onChange={e => { onChange={(e) => {
updateField(fieldSpec, e.target.value); updateField(fieldSpec, e.target.value);
}} }}
/> />
@ -28,7 +28,7 @@ export default ({
return ( return (
<Field <Field
title={typeof title === "function" ? title(signal) : title} title={typeof title === 'function' ? title(signal) : title}
htmlFor={htmlFor} htmlFor={htmlFor}
> >
{valueCol} {valueCol}

View File

@ -1,13 +1,13 @@
// SignalLegendEntry.js // SignalLegendEntry.js
import React, { Component } from "react"; import React, { Component } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import cx from "classnames"; import cx from 'classnames';
import Signal from "../../models/can/signal"; import Signal from '../../models/can/signal';
import SignalForm from "./SignalForm"; import SignalForm from './SignalForm';
import ColorBar from "./ColorBar"; import ColorBar from './ColorBar';
import FIELDS from "./FIELDS"; import FIELDS from './FIELDS';
export default class SignalLegendEntry extends Component { export default class SignalLegendEntry extends Component {
static propTypes = { static propTypes = {
@ -25,9 +25,7 @@ export default class SignalLegendEntry extends Component {
isExpanded: PropTypes.bool isExpanded: PropTypes.bool
}; };
static fieldSpecForName = name => { static fieldSpecForName = (name) => FIELDS.find((field) => field.field === name);
return FIELDS.find(field => field.field === name);
};
constructor(props) { constructor(props) {
super(props); super(props);
@ -66,7 +64,7 @@ export default class SignalLegendEntry extends Component {
this.props.onSignalChange(signalCopy, signal); this.props.onSignalChange(signalCopy, signal);
}; };
toggleEditing = e => { toggleEditing = (e) => {
if (this.props.isLogEvent) { if (this.props.isLogEvent) {
return; return;
} }
@ -81,9 +79,9 @@ export default class SignalLegendEntry extends Component {
const fieldSpec = SignalLegendEntry.fieldSpecForName(field); const fieldSpec = SignalLegendEntry.fieldSpecForName(field);
if ( if (
fieldSpec && fieldSpec
fieldSpec.type === "number" && && fieldSpec.type === 'number'
isNaN(parseInt(value, 10)) && isNaN(parseInt(value, 10))
) { ) {
value = 0; value = 0;
} }
@ -103,22 +101,23 @@ export default class SignalLegendEntry extends Component {
e.stopPropagation(); e.stopPropagation();
}; };
toggleSignalPlot = e => { toggleSignalPlot = (e) => {
const { signal, isPlotted } = this.props; const { signal, isPlotted } = this.props;
e.preventDefault(); e.preventDefault();
this.props.onSignalPlotChange(!isPlotted, signal.uid); this.props.onSignalPlotChange(!isPlotted, signal.uid);
}; };
getSignalEdited = field => { getSignalEdited = (field) => this.state.signalEdited[field];
return this.state.signalEdited[field];
};
render() { render() {
const { signal, isHighlighted, color, isPlotted, isExpanded } = this.props; const {
const expandedEntryClass = isExpanded ? "is-expanded" : null; signal, isHighlighted, color, isPlotted, isExpanded
const plottedButtonClass = isPlotted ? "button" : "button--alpha"; } = this.props;
const expandedEntryClass = isExpanded ? 'is-expanded' : null;
const plottedButtonClass = isPlotted ? 'button' : 'button--alpha';
return ( return (
<div <div
className={cx("signals-legend-entry", expandedEntryClass)} className={cx('signals-legend-entry', expandedEntryClass)}
onMouseEnter={() => this.props.onSignalHover(signal)} onMouseEnter={() => this.props.onSignalHover(signal)}
onMouseLeave={() => this.props.onSignalHoverEnd(signal)} onMouseLeave={() => this.props.onSignalHoverEnd(signal)}
> >
@ -134,8 +133,8 @@ export default class SignalLegendEntry extends Component {
className="signals-legend-entry-header-action" className="signals-legend-entry-header-action"
onClick={this.toggleSignalPlot} onClick={this.toggleSignalPlot}
> >
<button className={cx("button--tiny", plottedButtonClass)}> <button className={cx('button--tiny', plottedButtonClass)}>
{isPlotted ? "Hide Plot" : "Show Plot"} {isPlotted ? 'Hide Plot' : 'Show Plot'}
</button> </button>
</div> </div>
</div> </div>

View File

@ -1,8 +1,8 @@
import SignalLegendEntry from "."; import React from 'react';
import Signal from "../../models/can/signal"; import { shallow, mount, render } from 'enzyme';
import React from "react"; import { StyleSheetTestUtils } from 'aphrodite';
import { shallow, mount, render } from "enzyme"; import Signal from '../../models/can/signal';
import { StyleSheetTestUtils } from "aphrodite"; import SignalLegendEntry from '.';
// Prevents style injection from firing after test finishes // Prevents style injection from firing after test finishes
// and jsdom is torn down. // and jsdom is torn down.
@ -14,11 +14,11 @@ afterEach(() => {
}); });
function createSignalLegendEntry(props) { function createSignalLegendEntry(props) {
let signal = props.signal, let { signal } = props;
onSignalChange = props.onSignalChange, let { onSignalChange } = props;
onTentativeSignalChange = props.onTentativeSignalChange; let { onTentativeSignalChange } = props;
if (signal === undefined) { if (signal === undefined) {
signal = new Signal({ name: "NEW_SIGNAL" }); signal = new Signal({ name: 'NEW_SIGNAL' });
} }
if (onSignalChange === undefined) { if (onSignalChange === undefined) {
onSignalChange = () => {}; onSignalChange = () => {};
@ -37,9 +37,9 @@ function createSignalLegendEntry(props) {
); );
} }
test("a little endian signal spanning one byte should adjust its startBit switching to big endian, preserving its bit coverage", () => { test('a little endian signal spanning one byte should adjust its startBit switching to big endian, preserving its bit coverage', () => {
const signal = new Signal({ const signal = new Signal({
name: "signal", name: 'signal',
startBit: 0, startBit: 0,
size: 8, size: 8,
isLittleEndian: true isLittleEndian: true
@ -47,30 +47,30 @@ test("a little endian signal spanning one byte should adjust its startBit switch
const component = createSignalLegendEntry({ signal }); const component = createSignalLegendEntry({ signal });
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName( const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
"isLittleEndian" 'isLittleEndian'
); );
component.instance().updateField(endiannessFieldSpec, false); component.instance().updateField(endiannessFieldSpec, false);
const signalEdited = component.state("signalEdited"); const signalEdited = component.state('signalEdited');
expect(signalEdited.isLittleEndian).toBe(false); expect(signalEdited.isLittleEndian).toBe(false);
expect(signalEdited.startBit).toBe(7); expect(signalEdited.startBit).toBe(7);
expect(signalEdited.size).toBe(8); expect(signalEdited.size).toBe(8);
}); });
test("a big endian signal spanning two bytes should should adjust its startBit switching to little endian, preserving its bit coverage", () => { test('a big endian signal spanning two bytes should should adjust its startBit switching to little endian, preserving its bit coverage', () => {
const signal = new Signal({ const signal = new Signal({
name: "signal", name: 'signal',
startBit: 7, startBit: 7,
size: 8, size: 8,
isLittleEndian: false isLittleEndian: false
}); });
const component = createSignalLegendEntry({ signal }); const component = createSignalLegendEntry({ signal });
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName( const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
"isLittleEndian" 'isLittleEndian'
); );
component.instance().updateField(endiannessFieldSpec, true); component.instance().updateField(endiannessFieldSpec, true);
const signalEdited = component.state("signalEdited"); const signalEdited = component.state('signalEdited');
expect(signalEdited.isLittleEndian).toBe(true); expect(signalEdited.isLittleEndian).toBe(true);
expect(signalEdited.startBit).toBe(0); expect(signalEdited.startBit).toBe(0);
expect(signalEdited.size).toBe(8); expect(signalEdited.size).toBe(8);
@ -78,7 +78,7 @@ test("a big endian signal spanning two bytes should should adjust its startBit s
test("a big endian signal spanning one and a half bytes should adjust its startBit switching to little endian, preserving the first byte's coverage", () => { test("a big endian signal spanning one and a half bytes should adjust its startBit switching to little endian, preserving the first byte's coverage", () => {
const signal = new Signal({ const signal = new Signal({
name: "signal", name: 'signal',
startBit: 7, startBit: 7,
size: 12, size: 12,
isLittleEndian: false isLittleEndian: false
@ -86,49 +86,49 @@ test("a big endian signal spanning one and a half bytes should adjust its startB
const component = createSignalLegendEntry({ signal }); const component = createSignalLegendEntry({ signal });
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName( const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
"isLittleEndian" 'isLittleEndian'
); );
component.instance().updateField(endiannessFieldSpec, true); component.instance().updateField(endiannessFieldSpec, true);
const signalEdited = component.state("signalEdited"); const signalEdited = component.state('signalEdited');
expect(signalEdited.isLittleEndian).toBe(true); expect(signalEdited.isLittleEndian).toBe(true);
expect(signalEdited.startBit).toBe(0); expect(signalEdited.startBit).toBe(0);
expect(signalEdited.size).toBe(12); expect(signalEdited.size).toBe(12);
}); });
test("a little endian signal spanning 3 bits on one byte should adjust its startBit switching to big endian, preserving its bit coverage", () => { test('a little endian signal spanning 3 bits on one byte should adjust its startBit switching to big endian, preserving its bit coverage', () => {
const signal = new Signal({ const signal = new Signal({
name: "signal", name: 'signal',
startBit: 13, startBit: 13,
size: 3, size: 3,
isLittleEndian: true isLittleEndian: true
}); });
const component = createSignalLegendEntry({ signal }); const component = createSignalLegendEntry({ signal });
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName( const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
"isLittleEndian" 'isLittleEndian'
); );
component.instance().updateField(endiannessFieldSpec, false); component.instance().updateField(endiannessFieldSpec, false);
const signalEdited = component.state("signalEdited"); const signalEdited = component.state('signalEdited');
expect(signalEdited.isLittleEndian).toBe(false); expect(signalEdited.isLittleEndian).toBe(false);
expect(signalEdited.startBit).toBe(15); expect(signalEdited.startBit).toBe(15);
expect(signalEdited.size).toBe(3); expect(signalEdited.size).toBe(3);
}); });
test("a big endian signal spanning 3 bytes on one byte should adjust its startBit switching to little endian, preserving its bit coverage", () => { test('a big endian signal spanning 3 bytes on one byte should adjust its startBit switching to little endian, preserving its bit coverage', () => {
const signal = new Signal({ const signal = new Signal({
name: "signal", name: 'signal',
startBit: 15, startBit: 15,
size: 3, size: 3,
isLittleEndian: false isLittleEndian: false
}); });
const component = createSignalLegendEntry({ signal }); const component = createSignalLegendEntry({ signal });
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName( const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
"isLittleEndian" 'isLittleEndian'
); );
component.instance().updateField(endiannessFieldSpec, true); component.instance().updateField(endiannessFieldSpec, true);
const signalEdited = component.state("signalEdited"); const signalEdited = component.state('signalEdited');
expect(signalEdited.isLittleEndian).toBe(true); expect(signalEdited.isLittleEndian).toBe(true);
expect(signalEdited.startBit).toBe(13); expect(signalEdited.startBit).toBe(13);
expect(signalEdited.size).toBe(3); expect(signalEdited.size).toBe(3);

View File

@ -1,26 +1,25 @@
import { getUrlParameter } from "./utils/url"; import { getUrlParameter } from './utils/url';
const ENV = process.env.NODE_ENV === "production" ? "prod" : "debug"; const ENV = process.env.NODE_ENV === 'production' ? 'prod' : 'debug';
const ENV_GITHUB_CLIENT_ID = { const ENV_GITHUB_CLIENT_ID = {
debug: "f1e42d14f45491f9ca34", debug: 'f1e42d14f45491f9ca34',
prod: "4b43250e7499a97d62a5" prod: '4b43250e7499a97d62a5'
}; };
export const GITHUB_CLIENT_ID = ENV_GITHUB_CLIENT_ID[ENV]; export const GITHUB_CLIENT_ID = ENV_GITHUB_CLIENT_ID[ENV];
const ENV_GITHUB_REDIRECT_URL = { const ENV_GITHUB_REDIRECT_URL = {
debug: "http://127.0.0.1:1235/callback", debug: 'http://127.0.0.1:1235/callback',
prod: "https://api.comma.ai/cabana/ghcallback" prod: 'https://api.comma.ai/cabana/ghcallback'
}; };
export const GITHUB_REDIRECT_URL = ENV_GITHUB_REDIRECT_URL[ENV]; export const GITHUB_REDIRECT_URL = ENV_GITHUB_REDIRECT_URL[ENV];
export const GITHUB_AUTH_TOKEN_KEY = "gh_access_token"; export const GITHUB_AUTH_TOKEN_KEY = 'gh_access_token';
export const OPENDBC_SOURCE_REPO = "commaai/opendbc"; export const OPENDBC_SOURCE_REPO = 'commaai/opendbc';
export const USE_UNLOGGER = export const USE_UNLOGGER = typeof window !== 'undefined' && getUrlParameter('unlogger') !== null;
typeof window !== "undefined" && getUrlParameter("unlogger") !== null; export const UNLOGGER_HOST = 'http://localhost:8080/unlogger';
export const UNLOGGER_HOST = "http://localhost:8080/unlogger";
export const LOGENTRIES_TOKEN = "4bc98019-8277-4fe0-867c-ed21ea843cc5"; export const LOGENTRIES_TOKEN = '4bc98019-8277-4fe0-867c-ed21ea843cc5';
export const PART_SEGMENT_LENGTH = 3; export const PART_SEGMENT_LENGTH = 3;
@ -29,7 +28,7 @@ export const CAN_GRAPH_MAX_POINTS = 5000;
export const STREAMING_WINDOW = 60; export const STREAMING_WINDOW = 60;
const ENV_EXPLORER_URL = { const ENV_EXPLORER_URL = {
debug: "http://127.0.0.1:3000/", debug: 'http://127.0.0.1:3000/',
prod: "https://my.comma.ai/" prod: 'https://my.comma.ai/'
}; };
export const EXPLORER_URL = ENV_EXPLORER_URL[ENV]; export const EXPLORER_URL = ENV_EXPLORER_URL[ENV];

View File

@ -1,37 +1,37 @@
import Sentry from "./logging/Sentry"; import React from 'react';
import React from "react"; import ReactDOM from 'react-dom';
import ReactDOM from "react-dom"; import CommaAuth from '@commaai/my-comma-auth';
import CommaAuth from "@commaai/my-comma-auth"; import { request as Request } from '@commaai/comma-api';
import { request as Request } from "@commaai/comma-api"; import Sentry from './logging/Sentry';
import CanExplorer from "./CanExplorer"; import CanExplorer from './CanExplorer';
import AcuraDbc from "./acura-dbc"; import AcuraDbc from './acura-dbc';
import { getUrlParameter, modifyQueryParameters } from "./utils/url"; import { getUrlParameter, modifyQueryParameters } from './utils/url';
import { GITHUB_AUTH_TOKEN_KEY } from "./config"; import { GITHUB_AUTH_TOKEN_KEY } from './config';
import { import {
fetchPersistedDbc, fetchPersistedDbc,
fetchPersistedGithubAuthToken, fetchPersistedGithubAuthToken,
persistGithubAuthToken persistGithubAuthToken
} from "./api/localstorage"; } from './api/localstorage';
import "./index.css"; import './index.css';
Sentry.init(); Sentry.init();
const routeFullName = getUrlParameter("route"); const routeFullName = getUrlParameter('route');
let isDemo = !routeFullName; const isDemo = !routeFullName;
let props = { autoplay: true, isDemo }; const props = { autoplay: true, isDemo };
let persistedDbc = null; let persistedDbc = null;
if (routeFullName) { if (routeFullName) {
const [dongleId, route] = routeFullName.split("|"); const [dongleId, route] = routeFullName.split('|');
props.dongleId = dongleId; props.dongleId = dongleId;
props.name = route; props.name = route;
persistedDbc = fetchPersistedDbc(routeFullName); persistedDbc = fetchPersistedDbc(routeFullName);
let max = getUrlParameter("max"), const max = getUrlParameter('max');
url = getUrlParameter("url"), const url = getUrlParameter('url');
exp = getUrlParameter("exp"), const exp = getUrlParameter('exp');
sig = getUrlParameter("sig"); const sig = getUrlParameter('sig');
if (max) { if (max) {
props.max = max; props.max = max;
@ -47,15 +47,14 @@ if (routeFullName) {
} }
props.isLegacyShare = max && url && !exp && !sig; props.isLegacyShare = max && url && !exp && !sig;
props.isShare = max && url && exp && sig; props.isShare = max && url && exp && sig;
} else if (getUrlParameter("demo")) { } else if (getUrlParameter('demo')) {
props.max = 12; props.max = 12;
props.url = props.url = 'https://chffrprivate.blob.core.windows.net/chffrprivate3-permanent/v2/cb38263377b873ee/78392b99580c5920227cc5b43dff8a70_2017-06-12--18-51-47';
"https://chffrprivate.blob.core.windows.net/chffrprivate3-permanent/v2/cb38263377b873ee/78392b99580c5920227cc5b43dff8a70_2017-06-12--18-51-47"; props.name = '2017-06-12--18-51-47';
props.name = "2017-06-12--18-51-47"; props.dongleId = 'cb38263377b873ee';
props.dongleId = "cb38263377b873ee";
props.dbc = AcuraDbc; props.dbc = AcuraDbc;
props.isDemo = true; props.isDemo = true;
props.dbcFilename = "acura_ilx_2016_can.dbc"; props.dbcFilename = 'acura_ilx_2016_can.dbc';
// lots of 404s on this one // lots of 404s on this one
// props.max = 752; // props.max = 752;
@ -97,17 +96,17 @@ async function init() {
if (token) { if (token) {
Request.configure(token); Request.configure(token);
} }
ReactDOM.render(<CanExplorer {...props} />, document.getElementById("root")); ReactDOM.render(<CanExplorer {...props} />, document.getElementById('root'));
} }
if (routeFullName || isDemo) { if (routeFullName || isDemo) {
init(); init();
} else { } else {
const img = document.createElement("img"); const img = document.createElement('img');
img.src = process.env.PUBLIC_URL + "/img/cabana.jpg"; img.src = `${process.env.PUBLIC_URL}/img/cabana.jpg`;
img.style.width = "100%"; img.style.width = '100%';
const comment = document.createComment("7/6/17"); const comment = document.createComment('7/6/17');
document.getElementById("root").appendChild(img); document.getElementById('root').appendChild(img);
document.getElementById("root").appendChild(comment); document.getElementById('root').appendChild(comment);
} }

View File

@ -1,5 +1,5 @@
import LogEntries from "./LogEntries"; import LogEntries from './LogEntries';
import { LOGENTRIES_TOKEN } from "../config"; import { LOGENTRIES_TOKEN } from '../config';
class CloudLog { class CloudLog {
constructor() { constructor() {
@ -15,8 +15,8 @@ class CloudLog {
this.context.update(obj); this.context.update(obj);
} }
emit(message, level = "log") { emit(message, level = 'log') {
if (typeof global.__JEST__ !== "undefined") { if (typeof global.__JEST__ !== 'undefined') {
// Don't log in testing environment // Don't log in testing environment
return; return;
} }
@ -25,14 +25,14 @@ class CloudLog {
ctx: this.context, ctx: this.context,
created: new Date().getTime() / 1000, created: new Date().getTime() / 1000,
msg: message, msg: message,
src: "JSCloudLog" src: 'JSCloudLog'
}; };
if (level === "log") { if (level === 'log') {
LogEntries.log(entry); LogEntries.log(entry);
} else if (level === "warn") { } else if (level === 'warn') {
LogEntries.warn(entry); LogEntries.warn(entry);
} else if (level === "error") { } else if (level === 'error') {
LogEntries.error(entry); LogEntries.error(entry);
} }
} }
@ -42,11 +42,11 @@ class CloudLog {
} }
warn(message) { warn(message) {
this.emit(message, "warn"); this.emit(message, 'warn');
} }
error(message) { error(message) {
this.emit(message, "error"); this.emit(message, 'error');
} }
} }

View File

@ -1,15 +1,15 @@
import Raven from "raven-js"; import Raven from 'raven-js';
function init() { function init() {
if (process.env.NODE_ENV === "production") { if (process.env.NODE_ENV === 'production') {
const opts = {}; const opts = {};
if (typeof __webpack_hash__ !== "undefined") { if (typeof __webpack_hash__ !== 'undefined') {
opts["release"] = __webpack_hash__; // eslint-disable-line no-undef opts.release = __webpack_hash__; // eslint-disable-line no-undef
} }
Raven.config( Raven.config(
"https://50006e5d91894f508dd288bbbf4585a6@sentry.io/185303", 'https://50006e5d91894f508dd288bbbf4585a6@sentry.io/185303',
opts opts
).install(); ).install();
} }

View File

@ -1,4 +1,4 @@
const Uint64BE = require("int64-buffer").Uint64BE; const { Uint64BE } = require('int64-buffer');
export function formatForMsg(msg) { export function formatForMsg(msg) {
return { bstart: 0, bend: 15 }; return { bstart: 0, bend: 15 };
@ -7,7 +7,7 @@ export function formatForMsg(msg) {
export function formatMsgDec(msg) { export function formatMsgDec(msg) {
const { bstart, bend } = formatForMsg(msg); const { bstart, bend } = formatForMsg(msg);
const uint = Uint64BE(msg[1]); const uint = Uint64BE(msg[1]);
var tt = "0" + uint.toString(2); let tt = `0${uint.toString(2)}`;
tt = tt.substring(0, tt.length - (63 - bend)); tt = tt.substring(0, tt.length - (63 - bend));
tt = tt.substring(tt.length - (bend - bstart) - 1); tt = tt.substring(tt.length - (bend - bstart) - 1);
return [msg[0], parseInt(tt, 2)]; return [msg[0], parseInt(tt, 2)];
@ -20,17 +20,17 @@ export function uint64BEToHex(int64) {
export function int64BufferToPrettyHexStr(buffer) { export function int64BufferToPrettyHexStr(buffer) {
const uint = Uint64BE(buffer); const uint = Uint64BE(buffer);
let hex = uint.toString(16); let hex = uint.toString(16);
if (hex.length === 1) hex = "0" + hex; if (hex.length === 1) hex = `0${hex}`;
let hexParts = hex.match(/.{1,2}/g); const hexParts = hex.match(/.{1,2}/g);
return hexParts.join(" "); return hexParts.join(' ');
} }
export function formatMsgHex(msg) { export function formatMsgHex(msg) {
const uint = Uint64BE(msg[1]); const uint = Uint64BE(msg[1]);
let hex = uint.toString(16); let hex = uint.toString(16);
if (hex.length === 1) hex = "0" + hex; if (hex.length === 1) hex = `0${hex}`;
let hexParts = hex.match(/.{1,2}/g); const hexParts = hex.match(/.{1,2}/g);
return [msg[0], hexParts.join(" ")]; return [msg[0], hexParts.join(' ')];
} }

View File

@ -1,12 +1,12 @@
import rightPad from "right-pad"; import rightPad from 'right-pad';
import CloudLog from "../../logging/CloudLog"; import CloudLog from '../../logging/CloudLog';
import Signal from "./signal"; import Signal from './signal';
import Frame from "./frame"; import Frame from './frame';
import BoardUnit from "./BoardUnit"; import BoardUnit from './BoardUnit';
import DbcUtils from "../../utils/dbc"; import DbcUtils from '../../utils/dbc';
import * as LogSignals from "./logSignals"; import * as LogSignals from './logSignals';
const UINT64 = require("cuint").UINT64; const { UINT64 } = require('cuint');
const DBC_COMMENT_RE = /^CM_ *"(.*)";/; const DBC_COMMENT_RE = /^CM_ *"(.*)";/;
const DBC_COMMENT_MULTI_LINE_RE = /^CM_ *"(.*)/; const DBC_COMMENT_MULTI_LINE_RE = /^CM_ *"(.*)/;
@ -34,17 +34,16 @@ const BOARD_UNIT_COMMENT_RE = /^CM_ BU_ *(\w+) *"(.*)";/;
const BOARD_UNIT_COMMENT_MULTI_LINE_RE = /^CM_ BU_ *(\w+) *"(.*)/; const BOARD_UNIT_COMMENT_MULTI_LINE_RE = /^CM_ BU_ *(\w+) *"(.*)/;
// Follow ups are used to parse multi-line comment definitions // Follow ups are used to parse multi-line comment definitions
const FOLLOW_UP_DBC_COMMENT = "FollowUpDbcComment"; const FOLLOW_UP_DBC_COMMENT = 'FollowUpDbcComment';
const FOLLOW_UP_SIGNAL_COMMENT = "FollowUpSignalComment"; const FOLLOW_UP_SIGNAL_COMMENT = 'FollowUpSignalComment';
const FOLLOW_UP_MSG_COMMENT = "FollowUpMsgComment"; const FOLLOW_UP_MSG_COMMENT = 'FollowUpMsgComment';
const FOLLOW_UP_BOARD_UNIT_COMMENT = "FollowUpBoardUnitComment"; const FOLLOW_UP_BOARD_UNIT_COMMENT = 'FollowUpBoardUnitComment';
function floatOrInt(numericStr) { function floatOrInt(numericStr) {
if (Number.isInteger(numericStr)) { if (Number.isInteger(numericStr)) {
return parseInt(numericStr, 10); return parseInt(numericStr, 10);
} else {
return parseFloat(numericStr);
} }
return parseFloat(numericStr);
} }
export function swapOrder(arr, wordSize, gSize) { export function swapOrder(arr, wordSize, gSize) {
@ -57,7 +56,7 @@ export function swapOrder(arr, wordSize, gSize) {
} }
} }
return swappedWords.join(""); return swappedWords.join('');
} }
export default class DBC { export default class DBC {
@ -82,14 +81,14 @@ export default class DBC {
nextNewFrameName() { nextNewFrameName() {
const messageNames = []; const messageNames = [];
for (let msg of this.messages.values()) { for (const msg of this.messages.values()) {
messageNames.push(msg.name); messageNames.push(msg.name);
} }
let msgNum = 1, let msgNum = 1;
msgName; let msgName;
do { do {
msgName = "NEW_MSG_" + msgNum; msgName = `NEW_MSG_${msgNum}`;
msgNum++; msgNum++;
} while (messageNames.indexOf(msgName) !== -1); } while (messageNames.indexOf(msgName) !== -1);
@ -97,15 +96,15 @@ export default class DBC {
} }
updateBoardUnits() { updateBoardUnits() {
const boardUnitNames = this.boardUnits.map(bu => bu.name); const boardUnitNames = this.boardUnits.map((bu) => bu.name);
const missingBoardUnits = Array.from(this.messages.entries()) const missingBoardUnits = Array.from(this.messages.entries())
.map(([msgId, frame]) => Object.values(frame.signals)) .map(([msgId, frame]) => Object.values(frame.signals))
.reduce((arr, signals) => arr.concat(signals), []) .reduce((arr, signals) => arr.concat(signals), [])
.map(signal => signal.receiver) .map((signal) => signal.receiver)
.reduce((arr, receivers) => arr.concat(receivers), []) .reduce((arr, receivers) => arr.concat(receivers), [])
.filter((recv, idx, array) => array.indexOf(recv) === idx) .filter((recv, idx, array) => array.indexOf(recv) === idx)
.filter(recv => boardUnitNames.indexOf(recv) === -1) .filter((recv) => boardUnitNames.indexOf(recv) === -1)
.map(recv => new BoardUnit(recv)); .map((recv) => new BoardUnit(recv));
this.boardUnits = this.boardUnits.concat(missingBoardUnits); this.boardUnits = this.boardUnits.concat(missingBoardUnits);
} }
@ -114,57 +113,54 @@ export default class DBC {
this.updateBoardUnits(); this.updateBoardUnits();
let txt = 'VERSION ""\n\n\n'; let txt = 'VERSION ""\n\n\n';
txt += "NS_ :" + this._newSymbols(); txt += `NS_ :${this._newSymbols()}`;
txt += "\n\nBS_:\n"; txt += '\n\nBS_:\n';
const boardUnitsText = this.boardUnits.map(bu => bu.text()).join(" "); const boardUnitsText = this.boardUnits.map((bu) => bu.text()).join(' ');
txt += "\nBU_: " + boardUnitsText + "\n\n\n"; txt += `\nBU_: ${boardUnitsText}\n\n\n`;
const frames = []; const frames = [];
for (let frame of this.messages.values()) { for (const frame of this.messages.values()) {
frames.push(frame); frames.push(frame);
} }
txt += frames.map(f => f.text()).join("\n\n") + "\n\n"; txt += `${frames.map((f) => f.text()).join('\n\n')}\n\n`;
const messageTxs = frames const messageTxs = frames
.map(f => [f.id, f.transmitters.slice(1)]) .map((f) => [f.id, f.transmitters.slice(1)])
.filter(([addr, txs]) => txs.length > 0); .filter(([addr, txs]) => txs.length > 0);
txt += txt += `${messageTxs
messageTxs .map(([addr, txs]) => `BO_TX_BU_ ${addr} : ${txs.join(',')};`)
.map(([addr, txs]) => `BO_TX_BU_ ${addr} : ${txs.join(",")};`) .join('\n')}\n\n\n`;
.join("\n") + "\n\n\n";
txt += this.boardUnits txt += this.boardUnits
.filter(bu => bu.comment !== null) .filter((bu) => bu.comment !== null)
.map(bu => `CM_ BU_ ${bu.name} "${bu.comment}";`) .map((bu) => `CM_ BU_ ${bu.name} "${bu.comment}";`)
.join("\n"); .join('\n');
txt += frames txt += frames
.filter(f => f.comment !== null) .filter((f) => f.comment !== null)
.map(msg => `CM_ BO_ ${msg.address} "${msg.comment}";`) .map((msg) => `CM_ BO_ ${msg.address} "${msg.comment}";`)
.join("\n"); .join('\n');
const signalsByMsgId = frames const signalsByMsgId = frames
.map(f => Object.values(f.signals).map(sig => [f.id, sig])) .map((f) => Object.values(f.signals).map((sig) => [f.id, sig]))
.reduce((s1, s2) => s1.concat(s2), []); .reduce((s1, s2) => s1.concat(s2), []);
txt += txt += `${signalsByMsgId
signalsByMsgId .filter(([msgAddr, sig]) => sig.comment !== null)
.filter(([msgAddr, sig]) => sig.comment !== null) .map(
.map( ([msgAddr, sig]) => `CM_ SG_ ${msgAddr} ${sig.name} "${sig.comment}";`
([msgAddr, sig]) => `CM_ SG_ ${msgAddr} ${sig.name} "${sig.comment}";` )
) .join('\n')}\n`;
.join("\n") + "\n";
txt += txt += `${signalsByMsgId
signalsByMsgId .filter(([msgAddr, sig]) => sig.valueDescriptions.size > 0)
.filter(([msgAddr, sig]) => sig.valueDescriptions.size > 0) .map(([msgAddr, sig]) => sig.valueDescriptionText(msgAddr))
.map(([msgAddr, sig]) => sig.valueDescriptionText(msgAddr)) .join('\n')}\n`;
.join("\n") + "\n";
txt += this.comments.map(comment => `CM_ "${comment}";`).join("\n"); txt += this.comments.map((comment) => `CM_ "${comment}";`).join('\n');
return txt.trim() + "\n"; return `${txt.trim()}\n`;
} }
getMessageName(msgId) { getMessageName(msgId) {
@ -218,11 +214,11 @@ export default class DBC {
const warnings = []; const warnings = [];
const messages = new Map(); const messages = new Map();
let boardUnits = []; let boardUnits = [];
let valueTables = new Map(); const valueTables = new Map();
let id = 0; let id = 0;
let followUp = null; let followUp = null;
const lines = dbcString.split("\n"); const lines = dbcString.split('\n');
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
let line = lines[i].trim(); let line = lines[i].trim();
@ -230,7 +226,7 @@ export default class DBC {
if (followUp != null) { if (followUp != null) {
const { type, data } = followUp; const { type, data } = followUp;
line = line.replace(/" *;/, ""); line = line.replace(/" *;/, '');
let followUpLine = `\n${line.substr(0, line.length)}`; let followUpLine = `\n${line.substr(0, line.length)}`;
if (line.indexOf('"') !== -1) { if (line.indexOf('"') !== -1) {
followUp = null; followUp = null;
@ -248,13 +244,12 @@ export default class DBC {
} else if (type === FOLLOW_UP_DBC_COMMENT) { } else if (type === FOLLOW_UP_DBC_COMMENT) {
// const comment = data; // const comment = data;
const partialComment = this.comments[this.comments.length - 1]; const partialComment = this.comments[this.comments.length - 1];
this.comments[this.comments.length - 1] = this.comments[this.comments.length - 1] = partialComment + followUpLine;
partialComment + followUpLine;
} }
} }
if (line.indexOf("BO_ ") === 0) { if (line.indexOf('BO_ ') === 0) {
let matches = line.match(MSG_RE); const matches = line.match(MSG_RE);
if (matches === null) { if (matches === null) {
warnings.push( warnings.push(
`failed to parse message definition on line ${i + 1} -- ${line}` `failed to parse message definition on line ${i + 1} -- ${line}`
@ -271,7 +266,7 @@ export default class DBC {
transmitters: [transmitter] transmitters: [transmitter]
}); });
messages.set(id, frame); messages.set(id, frame);
} else if (line.indexOf("SG_") === 0) { } else if (line.indexOf('SG_') === 0) {
let matches = line.match(SIGNAL_RE); let matches = line.match(SIGNAL_RE);
if (matches === null) { if (matches === null) {
@ -304,12 +299,12 @@ export default class DBC {
startBit = parseInt(startBit, 10); startBit = parseInt(startBit, 10);
size = parseInt(size, 10); size = parseInt(size, 10);
isLittleEndian = parseInt(isLittleEndian, 10) === 1; isLittleEndian = parseInt(isLittleEndian, 10) === 1;
isSigned = isSigned === "-"; isSigned = isSigned === '-';
factor = floatOrInt(factor); factor = floatOrInt(factor);
offset = floatOrInt(offset); offset = floatOrInt(offset);
min = floatOrInt(min); min = floatOrInt(min);
max = floatOrInt(max); max = floatOrInt(max);
const receiver = receiverStr.split(",").map(s => s.trim()); const receiver = receiverStr.split(',').map((s) => s.trim());
const signalProperties = { const signalProperties = {
name, name,
@ -330,35 +325,32 @@ export default class DBC {
messages.get(id).signals[name] = signal; messages.get(id).signals[name] = signal;
} else { } else {
CloudLog.warn( CloudLog.warn(
"importDbcString: could not add signal: " + `importDbcString: could not add signal: ${name} due to missing message: ${id}`
name +
" due to missing message: " +
id
); );
} }
} else if (line.indexOf("VAL_ ") === 0) { } else if (line.indexOf('VAL_ ') === 0) {
let matches = line.match(VAL_RE); const matches = line.match(VAL_RE);
if (matches !== null) { if (matches !== null) {
let [messageId, signalName, vals] = matches.slice(1); let [messageId, signalName, vals] = matches.slice(1);
vals = vals vals = vals
.split('"') .split('"')
.map(s => s.trim()) .map((s) => s.trim())
.filter(s => s.length > 0); .filter((s) => s.length > 0);
messageId = parseInt(messageId, 10); messageId = parseInt(messageId, 10);
const msg = messages.get(messageId); const msg = messages.get(messageId);
const signal = msg.signals[signalName]; const signal = msg.signals[signalName];
if (signal === undefined) { if (signal === undefined) {
warnings.push( warnings.push(
`could not find signal for value description on line ${i + `could not find signal for value description on line ${i
1} -- ${line}` + 1} -- ${line}`
); );
continue; continue;
} }
for (let i = 0; i < vals.length; i += 2) { for (let i = 0; i < vals.length; i += 2) {
const value = vals[i].trim(), const value = vals[i].trim();
description = vals[i + 1].trim(); const description = vals[i + 1].trim();
signal.valueDescriptions.set(value, description); signal.valueDescriptions.set(value, description);
} }
} else { } else {
@ -366,20 +358,20 @@ export default class DBC {
`failed to parse value description on line ${i + 1} -- ${line}` `failed to parse value description on line ${i + 1} -- ${line}`
); );
} }
} else if (line.indexOf("VAL_TABLE_ ") === 0) { } else if (line.indexOf('VAL_TABLE_ ') === 0) {
let matches = line.match(VAL_TABLE_RE); const matches = line.match(VAL_TABLE_RE);
if (matches !== null) { if (matches !== null) {
const table = new Map(); const table = new Map();
let [tableName, items] = matches.slice(1); let [tableName, items] = matches.slice(1);
items = items items = items
.split('"') .split('"')
.map(s => s.trim()) .map((s) => s.trim())
.filter(s => s.length > 0); .filter((s) => s.length > 0);
for (let i = 0; i < items.length; i += 2) { for (let i = 0; i < items.length; i += 2) {
const key = items[i], const key = items[i];
value = items[i + 1]; const value = items[i + 1];
table.set(key, value); table.set(key, value);
} }
valueTables.set(tableName, table); valueTables.set(tableName, table);
@ -388,8 +380,8 @@ export default class DBC {
`failed to parse value table on line ${i + 1} -- ${line}` `failed to parse value table on line ${i + 1} -- ${line}`
); );
} }
} else if (line.indexOf("BO_TX_BU_ ") === 0) { } else if (line.indexOf('BO_TX_BU_ ') === 0) {
let matches = line.match(MSG_TRANSMITTER_RE); const matches = line.match(MSG_TRANSMITTER_RE);
if (matches !== null) { if (matches !== null) {
let [messageId, transmitter] = matches.slice(1); let [messageId, transmitter] = matches.slice(1);
@ -400,11 +392,11 @@ export default class DBC {
messages.set(messageId, msg); messages.set(messageId, msg);
} else { } else {
warnings.push( warnings.push(
`failed to parse message transmitter definition on line ${i + `failed to parse message transmitter definition on line ${i
1} -- ${line}` + 1} -- ${line}`
); );
} }
} else if (line.indexOf("CM_ SG_ ") === 0) { } else if (line.indexOf('CM_ SG_ ') === 0) {
let matches = line.match(SIGNAL_COMMENT_RE); let matches = line.match(SIGNAL_COMMENT_RE);
let hasFollowUp = false; let hasFollowUp = false;
if (matches === null) { if (matches === null) {
@ -423,8 +415,8 @@ export default class DBC {
messageId = parseInt(messageId, 10); messageId = parseInt(messageId, 10);
const msg = messages.get(messageId); const msg = messages.get(messageId);
if (msg === undefined) { if (msg === undefined) {
warnings.push(`failed to parse signal comment on line ${i + warnings.push(`failed to parse signal comment on line ${i
1} -- ${line}: + 1} -- ${line}:
message id ${messageId} does not exist prior to this line`); message id ${messageId} does not exist prior to this line`);
continue; continue;
} }
@ -442,7 +434,7 @@ export default class DBC {
if (hasFollowUp) { if (hasFollowUp) {
followUp = { type: FOLLOW_UP_SIGNAL_COMMENT, data: signal }; followUp = { type: FOLLOW_UP_SIGNAL_COMMENT, data: signal };
} }
} else if (line.indexOf("CM_ BO_ ") === 0) { } else if (line.indexOf('CM_ BO_ ') === 0) {
let matches = line.match(MESSAGE_COMMENT_RE); let matches = line.match(MESSAGE_COMMENT_RE);
let hasFollowUp = false; let hasFollowUp = false;
if (matches === null) { if (matches === null) {
@ -464,16 +456,16 @@ export default class DBC {
if (hasFollowUp) { if (hasFollowUp) {
followUp = { type: FOLLOW_UP_MSG_COMMENT, data: msg }; followUp = { type: FOLLOW_UP_MSG_COMMENT, data: msg };
} }
} else if (line.indexOf("BU_: ") === 0) { } else if (line.indexOf('BU_: ') === 0) {
let matches = line.match(BOARD_UNIT_RE); const matches = line.match(BOARD_UNIT_RE);
if (matches !== null) { if (matches !== null) {
const [boardUnitNameStr] = matches.slice(1); const [boardUnitNameStr] = matches.slice(1);
const newBoardUnits = boardUnitNameStr const newBoardUnits = boardUnitNameStr
.split(" ") .split(' ')
.map(s => s.trim()) .map((s) => s.trim())
.filter(s => s.length > 0) .filter((s) => s.length > 0)
.map(name => new BoardUnit(name)); .map((name) => new BoardUnit(name));
boardUnits = boardUnits.concat(newBoardUnits); boardUnits = boardUnits.concat(newBoardUnits);
} else { } else {
@ -482,7 +474,7 @@ export default class DBC {
); );
continue; continue;
} }
} else if (line.indexOf("CM_ BU_ ") === 0) { } else if (line.indexOf('CM_ BU_ ') === 0) {
let matches = line.match(BOARD_UNIT_COMMENT_RE); let matches = line.match(BOARD_UNIT_COMMENT_RE);
let hasFollowUp = false; let hasFollowUp = false;
if (matches === null) { if (matches === null) {
@ -496,8 +488,8 @@ export default class DBC {
} }
} }
let [boardUnitName, comment] = matches.slice(1); const [boardUnitName, comment] = matches.slice(1);
let boardUnit = boardUnits.find(bu => bu.name === boardUnitName); const boardUnit = boardUnits.find((bu) => bu.name === boardUnitName);
if (boardUnit) { if (boardUnit) {
boardUnit.comment = comment; boardUnit.comment = comment;
} }
@ -505,7 +497,7 @@ export default class DBC {
if (hasFollowUp) { if (hasFollowUp) {
followUp = { type: FOLLOW_UP_BOARD_UNIT_COMMENT, data: boardUnit }; followUp = { type: FOLLOW_UP_BOARD_UNIT_COMMENT, data: boardUnit };
} }
} else if (line.indexOf("CM_ ") === 0) { } else if (line.indexOf('CM_ ') === 0) {
let matches = line.match(DBC_COMMENT_RE); let matches = line.match(DBC_COMMENT_RE);
let hasFollowUp = false; let hasFollowUp = false;
if (matches === null) { if (matches === null) {
@ -520,7 +512,7 @@ export default class DBC {
} }
} }
let [comment] = matches.slice(1); const [comment] = matches.slice(1);
this.comments.push(comment); this.comments.push(comment);
if (hasFollowUp) { if (hasFollowUp) {
followUp = { type: FOLLOW_UP_DBC_COMMENT, data: comment }; followUp = { type: FOLLOW_UP_DBC_COMMENT, data: comment };
@ -542,7 +534,9 @@ export default class DBC {
valueForInt64Signal(signalSpec, hexData) { valueForInt64Signal(signalSpec, hexData) {
const blen = hexData.length * 4; const blen = hexData.length * 4;
let value, startBit, dataBitPos; let value;
let startBit;
let dataBitPos;
if (signalSpec.isLittleEndian) { if (signalSpec.isLittleEndian) {
value = UINT64(swapOrder(hexData, 16, 2), 16); value = UINT64(swapOrder(hexData, 16, 2), 16);
@ -559,7 +553,7 @@ export default class DBC {
return null; return null;
} }
let rightHandAnd = UINT64(Math.pow(2, signalSpec.size) - 1); const rightHandAnd = UINT64(Math.pow(2, signalSpec.size) - 1);
let ival = value let ival = value
.shiftr(dataBitPos) .shiftr(dataBitPos)
.and(rightHandAnd) .and(rightHandAnd)
@ -573,11 +567,11 @@ export default class DBC {
} }
valueForInt32Signal(signalSpec, buf) { valueForInt32Signal(signalSpec, buf) {
var startBit; let startBit;
if (signalSpec.isLittleEndian) { if (signalSpec.isLittleEndian) {
startBit = 64 - signalSpec.startBit - signalSpec.size; startBit = 64 - signalSpec.startBit - signalSpec.size;
} else { } else {
var bitPos = (-signalSpec.startBit - 1) % 8; let bitPos = (-signalSpec.startBit - 1) % 8;
if (bitPos < 0) { if (bitPos < 0) {
bitPos += 8; // mimic python modulo behavior bitPos += 8; // mimic python modulo behavior
} }
@ -585,8 +579,9 @@ export default class DBC {
startBit = Math.floor(signalSpec.startBit / 8) * 8 + bitPos; startBit = Math.floor(signalSpec.startBit / 8) * 8 + bitPos;
} }
var shiftAmount, signalValue; let shiftAmount;
let byteOffset = Math.min(4, Math.floor(signalSpec.startBit / 8)); let signalValue;
const byteOffset = Math.min(4, Math.floor(signalSpec.startBit / 8));
if (signalSpec.isLittleEndian) { if (signalSpec.isLittleEndian) {
signalValue = buf.readUInt32LE(byteOffset); signalValue = buf.readUInt32LE(byteOffset);
shiftAmount = signalSpec.startBit - 8 * byteOffset; shiftAmount = signalSpec.startBit - 8 * byteOffset;
@ -609,17 +604,17 @@ export default class DBC {
} }
const frame = this.getMessageFrame(messageId); const frame = this.getMessageFrame(messageId);
let buffer = Buffer.from(data); const buffer = Buffer.from(data);
let paddedBuffer = buffer; let paddedBuffer = buffer;
if (buffer.length !== 8) { if (buffer.length !== 8) {
// pad data it's 64 bits long // pad data it's 64 bits long
const paddedDataHex = rightPad(buffer.toString("hex"), 16, "0"); const paddedDataHex = rightPad(buffer.toString('hex'), 16, '0');
paddedBuffer = Buffer.from(paddedDataHex, "hex"); paddedBuffer = Buffer.from(paddedDataHex, 'hex');
} }
const hexData = paddedBuffer.toString("hex"); const hexData = paddedBuffer.toString('hex');
const signalValuesByName = {}; const signalValuesByName = {};
Object.values(frame.signals).forEach(signalSpec => { Object.values(frame.signals).forEach((signalSpec) => {
let value; let value;
if (signalSpec.size > 32) { if (signalSpec.size > 32) {
value = this.valueForInt64Signal(signalSpec, hexData); value = this.valueForInt64Signal(signalSpec, hexData);
@ -634,15 +629,15 @@ export default class DBC {
getChffrMetricMappings() { getChffrMetricMappings() {
const metricComment = this.comments.find( const metricComment = this.comments.find(
comment => comment.indexOf("CHFFR_METRIC") === 0 (comment) => comment.indexOf('CHFFR_METRIC') === 0
); );
if (!metricComment) { if (!metricComment) {
return null; return null;
} }
return metricComment return metricComment
.split(";") .split(';')
.map(metric => metric.trim().split(" ")) .map((metric) => metric.trim().split(' '))
.reduce( .reduce(
(metrics, [_, messageId, signalName, metricName, factor, offset]) => { (metrics, [_, messageId, signalName, metricName, factor, offset]) => {
metrics[metricName] = { metrics[metricName] = {

View File

@ -1,9 +1,9 @@
function findTimeIndex(entries, time) { function findTimeIndex(entries, time) {
return entries.findIndex(e => e.time >= time); return entries.findIndex((e) => e.time >= time);
} }
function findRelativeTimeIndex(entries, relTime) { function findRelativeTimeIndex(entries, relTime) {
return entries.findIndex(e => e.relTime >= relTime); return entries.findIndex((e) => e.relTime >= relTime);
} }
function findSegmentIndices( function findSegmentIndices(
@ -20,17 +20,15 @@ function findSegmentIndices(
Returns `[segmentIdxLow, segmentIdxHigh]` Returns `[segmentIdxLow, segmentIdxHigh]`
(inclusive, exclusive) (inclusive, exclusive)
*/ */
let timeIndexFunc = const timeIndexFunc = isRelative === true ? findRelativeTimeIndex : findTimeIndex;
isRelative === true ? findRelativeTimeIndex : findTimeIndex;
const segmentIdxLow = Math.max(0, timeIndexFunc(entries, segmentTimeLow)); const segmentIdxLow = Math.max(0, timeIndexFunc(entries, segmentTimeLow));
const upperSegments = entries.slice(segmentIdxLow); const upperSegments = entries.slice(segmentIdxLow);
let upperSegmentIdxHi = timeIndexFunc(upperSegments, segmentTimeHi); const upperSegmentIdxHi = timeIndexFunc(upperSegments, segmentTimeHi);
const segmentIdxHi = const segmentIdxHi = upperSegmentIdxHi >= 0
upperSegmentIdxHi >= 0 ? upperSegmentIdxHi + segmentIdxLow + 1
? upperSegmentIdxHi + segmentIdxLow + 1 : entries.length - 1;
: entries.length - 1;
return [ return [
segmentIdxLow, segmentIdxLow,

View File

@ -20,10 +20,10 @@ export default class Frame {
} }
nextNewTransmitterName() { nextNewTransmitterName() {
let txNum = 1, let txNum = 1;
txName; let txName;
do { do {
txName = "NEW_TRANSMITTER_" + txNum; txName = `NEW_TRANSMITTER_${txNum}`;
txNum++; txNum++;
} while (this.transmitters.indexOf(txName) !== -1); } while (this.transmitters.indexOf(txName) !== -1);
@ -38,21 +38,20 @@ export default class Frame {
header() { header() {
return ( return (
`BO_ ${this.id} ${this.name}: ${this.size} ` + `BO_ ${this.id} ${this.name}: ${this.size} `
`${this.transmitters[0] || "XXX"}` + `${this.transmitters[0] || 'XXX'}`
); );
} }
text() { text() {
const signals = Object.values(this.signals) const signals = Object.values(this.signals)
.map(signal => " " + signal.text()) // indent .map((signal) => ` ${signal.text()}`) // indent
.join("\n"); .join('\n');
if (signals.length > 0) { if (signals.length > 0) {
return this.header() + "\n" + signals; return `${this.header()}\n${signals}`;
} else {
return this.header();
} }
return this.header();
} }
copy() { copy() {

View File

@ -1,5 +1,5 @@
import Frame from "./frame"; import Frame from './frame';
import Signal from "./signal"; import Signal from './signal';
export const wheelSpeeds = { export const wheelSpeeds = {
FrontLeftWheel: shortSignal({ FrontLeftWheel: shortSignal({
@ -82,13 +82,13 @@ export const flags = {
Standstill: boolSignal({ Standstill: boolSignal({
index: 8 index: 8
}), }),
"CruiseState.Enabled": boolSignal({ 'CruiseState.Enabled': boolSignal({
index: 9 index: 9
}), }),
"CruiseState.Available": boolSignal({ 'CruiseState.Available': boolSignal({
index: 10 index: 10
}), }),
"CruiseState.Standstill": boolSignal({ 'CruiseState.Standstill': boolSignal({
index: 11 index: 11
}), }),
GearShifter: { GearShifter: {
@ -96,7 +96,7 @@ export const flags = {
size: 4, size: 4,
unsigned: true unsigned: true
}, },
"CruiseState.Speed": charSignal({ 'CruiseState.Speed': charSignal({
index: 2 index: 2
}) })
}; };
@ -192,21 +192,21 @@ export const thermalFreeSpace = {
}; };
export const signalMap = { export const signalMap = {
"CarState:WheelSpeeds": wheelSpeeds, 'CarState:WheelSpeeds': wheelSpeeds,
"CarState:Ego": ego, 'CarState:Ego': ego,
"CarState:Controls": controls, 'CarState:Controls': controls,
"CarState:Flags": flags, 'CarState:Flags': flags,
"UbloxGnss:MeasurementReport": ubloxGnss, 'UbloxGnss:MeasurementReport': ubloxGnss,
"Health:Data": health, 'Health:Data': health,
"Thermal:CPU": thermalCPU, 'Thermal:CPU': thermalCPU,
"Thermal:Data": thermalData, 'Thermal:Data': thermalData,
"Thermal:FreeSpace": thermalFreeSpace 'Thermal:FreeSpace': thermalFreeSpace
}; };
const ADDRESS_LIST = []; const ADDRESS_LIST = [];
Object.keys(signalMap).forEach(function(name) { Object.keys(signalMap).forEach((name) => {
Object.keys(signalMap[name]).forEach(function(signal) { Object.keys(signalMap[name]).forEach((signal) => {
signalMap[name][signal] = createSignalEntry({ signalMap[name][signal] = createSignalEntry({
name: signal, name: signal,
...signalMap[name][signal] ...signalMap[name][signal]
@ -224,7 +224,7 @@ function createSignalEntry(options) {
isSigned: !options.unsigned, isSigned: !options.unsigned,
factor: options.factor || 1, factor: options.factor || 1,
offset: options.offset || 0, offset: options.offset || 0,
unit: options.unit || "" unit: options.unit || ''
}); });
} }
@ -262,7 +262,7 @@ function boolSignal(options) {
} }
export function addressForName(name) { export function addressForName(name) {
var i = ADDRESS_LIST.indexOf(name); const i = ADDRESS_LIST.indexOf(name);
if (i === -1) { if (i === -1) {
ADDRESS_LIST.push(name); ADDRESS_LIST.push(name);
return ADDRESS_LIST.indexOf(name) + 0x1000; return ADDRESS_LIST.indexOf(name) + 0x1000;
@ -282,10 +282,10 @@ export function isLogAddress(address) {
} }
export function frameForAddress(address) { export function frameForAddress(address) {
let name = nameForAddress(address); const name = nameForAddress(address);
return new Frame({ return new Frame({
id: name, id: name,
name: name, name,
size: 8, size: 8,
signals: signalMap[name] signals: signalMap[name]
}); });

View File

@ -1,4 +1,4 @@
import DbcUtils from "../../utils/dbc"; import DbcUtils from '../../utils/dbc';
export default class Signal { export default class Signal {
constructor({ constructor({
@ -10,8 +10,8 @@ export default class Signal {
isFloat = false, isFloat = false,
factor = 1, factor = 1,
offset = 0, offset = 0,
unit = "", unit = '',
receiver = ["XXX"], receiver = ['XXX'],
comment = null, comment = null,
multiplex = null, multiplex = null,
min = null, min = null,
@ -45,28 +45,33 @@ export default class Signal {
const colors = this.generateColors(); const colors = this.generateColors();
Object.assign(this, { min, max, uid, colors }); Object.assign(this, {
min,
max,
uid,
colors
});
} }
text() { text() {
const multiplex = this.multiplex ? " " + this.multiplex : ""; const multiplex = this.multiplex ? ` ${this.multiplex}` : '';
const byteOrder = this.isLittleEndian ? 1 : 0; const byteOrder = this.isLittleEndian ? 1 : 0;
const signedChar = this.isSigned ? "-" : "+"; const signedChar = this.isSigned ? '-' : '+';
return ( return (
`SG_ ${this.name}${multiplex} : ` + `SG_ ${this.name}${multiplex} : `
`${this.startBit}|${this.size}@${byteOrder}${signedChar}` + + `${this.startBit}|${this.size}@${byteOrder}${signedChar}`
` (${this.factor},${this.offset})` + + ` (${this.factor},${this.offset})`
` [${this.min}|${this.max}]` + + ` [${this.min}|${this.max}]`
` "${this.unit}" ${this.receiver}` + ` "${this.unit}" ${this.receiver}`
); );
} }
valueDescriptionText(msgId) { valueDescriptionText(msgId) {
const entryPairs = Array.from(this.valueDescriptions.entries()); const entryPairs = Array.from(this.valueDescriptions.entries());
const values = entryPairs.reduce( const values = entryPairs.reduce(
(str, [value, desc]) => str + value + ` "${desc}" `, (str, [value, desc]) => `${str + value} "${desc}" `,
"" ''
); );
return `VAL_ ${msgId} ${this.name} ${values};`; return `VAL_ ${msgId} ${this.name} ${values};`;
} }
@ -76,11 +81,10 @@ export default class Signal {
if (this.isLittleEndian) { if (this.isLittleEndian) {
return this.startBit; return this.startBit;
} else {
const lsbBitNumber = this.lsbBitNumber();
return DbcUtils.matrixBitNumber(lsbBitNumber);
} }
const lsbBitNumber = this.lsbBitNumber();
return DbcUtils.matrixBitNumber(lsbBitNumber);
} }
lsbBitNumber() { lsbBitNumber() {
@ -92,21 +96,19 @@ export default class Signal {
msbBitIndex() { msbBitIndex() {
if (this.isLittleEndian) { if (this.isLittleEndian) {
return this.startBit + this.size - 1; return this.startBit + this.size - 1;
} else {
return this.startBit;
} }
return this.startBit;
} }
littleEndianBitDescription(bitIndex) { littleEndianBitDescription(bitIndex) {
const bitRange = [this.startBit, this.startBit + this.size - 1]; const bitRange = [this.startBit, this.startBit + this.size - 1];
if (bitIndex < bitRange[0] || bitIndex > bitRange[1]) { if (bitIndex < bitRange[0] || bitIndex > bitRange[1]) {
return null; return null;
} else {
const bitNumber = bitIndex - bitRange[0];
const isLsb = bitIndex === bitRange[0];
const isMsb = bitIndex === bitRange[1];
return { bitNumber, isLsb, isMsb };
} }
const bitNumber = bitIndex - bitRange[0];
const isLsb = bitIndex === bitRange[0];
const isMsb = bitIndex === bitRange[1];
return { bitNumber, isLsb, isMsb };
} }
bigEndianBitDescription(bitIndex) { bigEndianBitDescription(bitIndex) {
@ -120,15 +122,19 @@ export default class Signal {
const isLsb = bitNumber === range[1]; const isLsb = bitNumber === range[1];
const isMsb = bitIndex === this.startBit; const isMsb = bitIndex === this.startBit;
return { bitNumber, isLsb, isMsb, range }; return {
bitNumber,
isLsb,
isMsb,
range
};
} }
bitDescription(bitIndex) { bitDescription(bitIndex) {
if (this.isLittleEndian) { if (this.isLittleEndian) {
return this.littleEndianBitDescription(bitIndex); return this.littleEndianBitDescription(bitIndex);
} else {
return this.bigEndianBitDescription(bitIndex);
} }
return this.bigEndianBitDescription(bitIndex);
} }
calculateRawRange() { calculateRawRange() {
@ -150,7 +156,7 @@ export default class Signal {
} }
generateColors() { generateColors() {
let colors = Array(3); const colors = Array(3);
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {
colors[i] = Math.floor(Math.random() * 211); colors[i] = Math.floor(Math.random() * 211);
} }
@ -160,19 +166,19 @@ export default class Signal {
equals(otherSignal) { equals(otherSignal) {
return ( return (
otherSignal.name === this.name && otherSignal.name === this.name
otherSignal.startBit === this.startBit && && otherSignal.startBit === this.startBit
otherSignal.size === this.size && && otherSignal.size === this.size
otherSignal.isLittleEndian === this.isLittleEndian && && otherSignal.isLittleEndian === this.isLittleEndian
otherSignal.isSigned === this.isSigned && && otherSignal.isSigned === this.isSigned
otherSignal.isFloat === this.isFloat && && otherSignal.isFloat === this.isFloat
otherSignal.factor === this.factor && && otherSignal.factor === this.factor
otherSignal.offset === this.offset && && otherSignal.offset === this.offset
otherSignal.unit === this.unit && && otherSignal.unit === this.unit
otherSignal.receiver.length === this.receiver.length && && otherSignal.receiver.length === this.receiver.length
otherSignal.receiver.every((v, i) => v === this.receiver[i]) && && otherSignal.receiver.every((v, i) => v === this.receiver[i])
otherSignal.comment === this.comment && && otherSignal.comment === this.comment
otherSignal.multiplex === this.multiplex && otherSignal.multiplex === this.multiplex
); );
} }
} }

View File

@ -1,18 +1,18 @@
import ArrayUtils from "../utils/array"; import ArrayUtils from '../utils/array';
import { CAN_GRAPH_MAX_POINTS } from "../config"; import { CAN_GRAPH_MAX_POINTS } from '../config';
function _calcGraphData(msg, signalUid, firstCanTime) { function _calcGraphData(msg, signalUid, firstCanTime) {
if (!msg) return null; if (!msg) return null;
const signal = Object.values(msg.frame.signals).find( const signal = Object.values(msg.frame.signals).find(
s => s.uid === signalUid (s) => s.uid === signalUid
); );
if (!signal) { if (!signal) {
console.warn("_calcGraphData: no signal", signalUid, msg); console.warn('_calcGraphData: no signal', signalUid, msg);
return null; return null;
} }
let samples = []; let samples = [];
let skip = Math.floor(msg.entries.length / CAN_GRAPH_MAX_POINTS); const skip = Math.floor(msg.entries.length / CAN_GRAPH_MAX_POINTS);
if (skip === 0) { if (skip === 0) {
samples = msg.entries; samples = msg.entries;
@ -29,8 +29,8 @@ function _calcGraphData(msg, signalUid, firstCanTime) {
// sorting these doesn't fix the phantom lines // sorting these doesn't fix the phantom lines
let lastEntry = samples[0].relTime; let lastEntry = samples[0].relTime;
return samples return samples
.filter(e => e.signals[signal.name] !== undefined) .filter((e) => e.signals[signal.name] !== undefined)
.map(entry => { .map((entry) => {
if (entry.relTime - lastEntry > 2) { if (entry.relTime - lastEntry > 2) {
signalUid = Math.random().toString(36); signalUid = Math.random().toString(36);
} }
@ -41,7 +41,7 @@ function _calcGraphData(msg, signalUid, firstCanTime) {
relTime: entry.relTime, relTime: entry.relTime,
y: entry.signals[signal.name], y: entry.signals[signal.name],
unit: signal.unit, unit: signal.unit,
color: `rgba(${signal.colors.join(",")}, 0.5)`, color: `rgba(${signal.colors.join(',')}, 0.5)`,
signalName: signal.name, signalName: signal.name,
signalUid signalUid
}; };
@ -49,17 +49,13 @@ function _calcGraphData(msg, signalUid, firstCanTime) {
} }
function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) { function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
const messagesPerPlot = plottedSignals.map(plottedMessages => const messagesPerPlot = plottedSignals.map((plottedMessages) => plottedMessages.reduce((messages, { messageId, signalUid }) => {
plottedMessages.reduce((messages, { messageId, signalUid }) => { messages.push(messageId);
messages.push(messageId); return messages;
return messages; }, []));
}, [])
);
const extendedPlots = messagesPerPlot const extendedPlots = messagesPerPlot
.map((plottedMessageIds, index) => { .map((plottedMessageIds, index) => ({ plottedMessageIds, index })) // preserve index so we can look up graphData
return { plottedMessageIds, index };
}) // preserve index so we can look up graphData
.filter(({ plottedMessageIds, index }) => { .filter(({ plottedMessageIds, index }) => {
if (index < graphData.length) { if (index < graphData.length) {
let maxGraphTime = 0; let maxGraphTime = 0;
@ -69,13 +65,11 @@ function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
} }
return plottedMessageIds.some( return plottedMessageIds.some(
messageId => (messageId) => (messages[messageId].entries.length > 0 && series.length === 0)
(messages[messageId].entries.length > 0 && series.length === 0) || || messages[messageId].entries.some((e) => e.relTime > maxGraphTime)
messages[messageId].entries.some(e => e.relTime > maxGraphTime)
); );
} else {
return false;
} }
return false;
}) })
.map(({ plottedMessageIds, index }) => { .map(({ plottedMessageIds, index }) => {
plottedMessageIds = plottedMessageIds.reduce((arr, messageId) => { plottedMessageIds = plottedMessageIds.reduce((arr, messageId) => {
@ -102,9 +96,10 @@ function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
const graphDataMaxMessageTimes = plottedMessageIds.reduce( const graphDataMaxMessageTimes = plottedMessageIds.reduce(
(obj, messageId) => { (obj, messageId) => {
const signalUids = signalUidsByMessageId[messageId]; const signalUids = signalUidsByMessageId[messageId];
const maxIndex = ArrayUtils.findIndexRight(series, entry => { const maxIndex = ArrayUtils.findIndexRight(
return signalUids.indexOf(entry.signalUid) !== -1; series,
}); (entry) => signalUids.indexOf(entry.signalUid) !== -1
);
if (maxIndex) { if (maxIndex) {
obj[messageId] = series[maxIndex].relTime; obj[messageId] = series[maxIndex].relTime;
} else if (series.length > 0) { } else if (series.length > 0) {
@ -121,24 +116,21 @@ function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
let newGraphData = []; let newGraphData = [];
plottedMessageIds plottedMessageIds
.map(messageId => { .map((messageId) => ({ messageId, entries: messages[messageId].entries }))
return { messageId, entries: messages[messageId].entries };
})
.filter( .filter(
( (
{ messageId, entries } // Filter to only messages with stale graphData { messageId, entries } // Filter to only messages with stale graphData
) => ) => entries[entries.length - 1].relTime
entries[entries.length - 1].relTime > > graphDataMaxMessageTimes[messageId]
graphDataMaxMessageTimes[messageId]
) )
.forEach(({ messageId, entries }) => { .forEach(({ messageId, entries }) => {
// Compute and append new graphData // Compute and append new graphData
let firstNewEntryIdx = entries.findIndex( const firstNewEntryIdx = entries.findIndex(
entry => entry.relTime > graphDataMaxMessageTimes[messageId] (entry) => entry.relTime > graphDataMaxMessageTimes[messageId]
); );
const newEntries = entries.slice(firstNewEntryIdx); const newEntries = entries.slice(firstNewEntryIdx);
signalUidsByMessageId[messageId].forEach(signalUid => { signalUidsByMessageId[messageId].forEach((signalUid) => {
const signalGraphData = _calcGraphData( const signalGraphData = _calcGraphData(
{ {
...messages[messageId], ...messages[messageId],
@ -152,12 +144,10 @@ function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
}); });
}); });
const messageIdOutOfBounds = const messageIdOutOfBounds = series.length > 0
series.length > 0 && && plottedMessageIds.find(
plottedMessageIds.find( (messageId) => messages[messageId].entries.length > 0
messageId => && series[0].relTime < messages[messageId].entries[0].relTime
messages[messageId].entries.length > 0 &&
series[0].relTime < messages[messageId].entries[0].relTime
); );
graphData[index] = { graphData[index] = {
series: graphData[index].series.concat(newGraphData), series: graphData[index].series.concat(newGraphData),
@ -166,7 +156,7 @@ function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
if (messageIdOutOfBounds) { if (messageIdOutOfBounds) {
const graphDataLowerBound = graphData[index].series.findIndex( const graphDataLowerBound = graphData[index].series.findIndex(
e => e.relTime > messages[messageIdOutOfBounds].entries[0].relTime (e) => e.relTime > messages[messageIdOutOfBounds].entries[0].relTime
); );
if (graphDataLowerBound) { if (graphDataLowerBound) {

View File

@ -1,4 +1,4 @@
import { configure } from "enzyme"; import { configure } from 'enzyme';
import Adapter from "enzyme-adapter-react-16"; import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() }); configure({ adapter: new Adapter() });

View File

@ -1,7 +1,7 @@
import React from "react"; import React from 'react';
import { StyleSheet, css } from "aphrodite/no-important"; import { StyleSheet, css } from 'aphrodite/no-important';
import * as ObjectUtils from "../utils/object"; import * as ObjectUtils from '../utils/object';
function createImageComponent(source, alt, styles) { function createImageComponent(source, alt, styles) {
if (styles === undefined) { if (styles === undefined) {
@ -10,13 +10,13 @@ function createImageComponent(source, alt, styles) {
styles = [styles]; styles = [styles];
} }
return props => { return (props) => {
let localStyles = styles.slice(); let localStyles = styles.slice();
if (Array.isArray(props.styles)) { if (Array.isArray(props.styles)) {
localStyles = localStyles.concat(props.styles); localStyles = localStyles.concat(props.styles);
// filter 'styles' from props, which is passed via spread to <img> tag. // filter 'styles' from props, which is passed via spread to <img> tag.
props = ObjectUtils.fromArray( props = ObjectUtils.fromArray(
Object.entries(props).filter(([k, v]) => k !== "styles") Object.entries(props).filter(([k, v]) => k !== 'styles')
); );
} }
@ -32,36 +32,42 @@ const Styles = StyleSheet.create({
height: 24 height: 24
}, },
pointer: { pointer: {
cursor: "pointer" cursor: 'pointer'
} }
}); });
const leftArrow = createImageComponent( const leftArrow = createImageComponent(
process.env.PUBLIC_URL + "/img/ic_arrow_left_black_24dp.png", `${process.env.PUBLIC_URL}/img/ic_arrow_left_black_24dp.png`,
"Left arrow", 'Left arrow',
Styles.materialIcon Styles.materialIcon
); );
const rightArrow = createImageComponent( const rightArrow = createImageComponent(
process.env.PUBLIC_URL + "/img/ic_arrow_right_black_24dp.png", `${process.env.PUBLIC_URL}/img/ic_arrow_right_black_24dp.png`,
"Right arrow", 'Right arrow',
Styles.materialIcon Styles.materialIcon
); );
const downArrow = createImageComponent( const downArrow = createImageComponent(
process.env.PUBLIC_URL + "/img/ic_arrow_drop_down_black_24dp.png", `${process.env.PUBLIC_URL}/img/ic_arrow_drop_down_black_24dp.png`,
"Down arrow", 'Down arrow',
Styles.materialIcon Styles.materialIcon
); );
const clear = createImageComponent( const clear = createImageComponent(
process.env.PUBLIC_URL + "/img/ic_clear_black_24dp.png", `${process.env.PUBLIC_URL}/img/ic_clear_black_24dp.png`,
"Clear", 'Clear',
[Styles.materialIcon, Styles.pointer] [Styles.materialIcon, Styles.pointer]
); );
const panda = createImageComponent( const panda = createImageComponent(
process.env.PUBLIC_URL + "/img/panda.png", `${process.env.PUBLIC_URL}/img/panda.png`,
"Panda", 'Panda',
[] []
); );
export default { rightArrow, leftArrow, downArrow, clear, panda }; export default {
rightArrow,
leftArrow,
downArrow,
clear,
panda
};

View File

@ -1,14 +1,14 @@
import { StyleSheet } from "aphrodite/no-important"; import { StyleSheet } from 'aphrodite/no-important';
export default StyleSheet.create({ export default StyleSheet.create({
tab: { tab: {
display: "inline", display: 'inline',
marginRight: 20, marginRight: 20,
cursor: "pointer" cursor: 'pointer'
}, },
selectedTab: { selectedTab: {
borderBottom: "2px solid #000", borderBottom: '2px solid #000',
fontWeight: "bold" fontWeight: 'bold'
}, },
tabContent: { tabContent: {
paddingTop: 20 paddingTop: 20

View File

@ -1,22 +1,22 @@
import { StyleSheet } from "aphrodite/no-important"; import { StyleSheet } from 'aphrodite/no-important';
export default StyleSheet.create({ export default StyleSheet.create({
root: { root: {
flexDirection: "row" flexDirection: 'row'
}, },
button: { button: {
cursor: "pointer", cursor: 'pointer',
backgroundColor: "RGB(63, 135, 255)", backgroundColor: 'RGB(63, 135, 255)',
borderRadius: 5, borderRadius: 5,
minWidth: 80, minWidth: 80,
paddingLeft: 20, paddingLeft: 20,
paddingRight: 20, paddingRight: 20,
display: "flex", display: 'flex',
alignItems: "center", alignItems: 'center',
justifyContent: "center", justifyContent: 'center',
color: "white", color: 'white',
":hover": { ':hover': {
backgroundColor: "RGBA(63, 135, 255, 0.5)" backgroundColor: 'RGBA(63, 135, 255, 0.5)'
} }
} }
}); });

View File

@ -4,14 +4,14 @@
// Useful for component testing // Useful for component testing
import { css } from "aphrodite"; import { css } from 'aphrodite';
import classNames from "classnames"; import classNames from 'classnames';
export default function() { export default function () {
const styles = []; const styles = [];
const classes = []; const classes = [];
[].forEach.call(arguments, it => { [].forEach.call(arguments, (it) => {
if (it && it._definition && it._name) styles.push(it); if (it && it._definition && it._name) styles.push(it);
else classes.push(it); else classes.push(it);
}); });

View File

@ -1,6 +1,6 @@
function findMaxByteStateChangeCount(messages) { function findMaxByteStateChangeCount(messages) {
return Object.values(messages) return Object.values(messages)
.map(m => m.byteStateChangeCounts) .map((m) => m.byteStateChangeCounts)
.reduce((counts, countArr) => counts.concat(countArr), []) // flatten arrays .reduce((counts, countArr) => counts.concat(countArr), []) // flatten arrays
.reduce((count1, count2) => (count1 > count2 ? count1 : count2), 0); // find max .reduce((count1, count2) => (count1 > count2 ? count1 : count2), 0); // find max
} }
@ -13,20 +13,20 @@ function addCanMessage(
prevMsgEntries, prevMsgEntries,
byteStateChangeCountsByMessage byteStateChangeCountsByMessage
) { ) {
var { address, busTime, data, bus } = canMessage; const {
var id = bus + ":" + address.toString(16); address, busTime, data, bus
} = canMessage;
const id = `${bus}:${address.toString(16)}`;
if (messages[id] === undefined) if (messages[id] === undefined) messages[id] = createMessageSpec(dbc, address, id, bus);
messages[id] = createMessageSpec(dbc, address, id, bus);
const prevMsgEntry = const prevMsgEntry = messages[id].entries.length > 0
messages[id].entries.length > 0 ? messages[id].entries[messages[id].entries.length - 1]
? messages[id].entries[messages[id].entries.length - 1] : prevMsgEntries[id] || null;
: prevMsgEntries[id] || null;
if ( if (
byteStateChangeCountsByMessage[id] && byteStateChangeCountsByMessage[id]
messages[id].byteStateChangeCounts.every(c => c === 0) && messages[id].byteStateChangeCounts.every((c) => c === 0)
) { ) {
messages[id].byteStateChangeCounts = byteStateChangeCountsByMessage[id]; messages[id].byteStateChangeCounts = byteStateChangeCountsByMessage[id];
} }
@ -54,11 +54,11 @@ function createMessageSpec(dbc, address, id, bus) {
const size = frame ? frame.size : 8; const size = frame ? frame.size : 8;
return { return {
address: address, address,
id: id, id,
bus: bus, bus,
entries: [], entries: [],
frame: frame, frame,
byteColors: Array(size).fill(0), byteColors: Array(size).fill(0),
byteStateChangeCounts: Array(size).fill(0) byteStateChangeCounts: Array(size).fill(0)
}; };
@ -79,8 +79,8 @@ function determineByteStateChangeTimes(
byteStateChangeTimes = Array.from(lastParsedMessage.byteStateChangeTimes); byteStateChangeTimes = Array.from(lastParsedMessage.byteStateChangeTimes);
for (let i = 0; i < byteStateChangeTimes.length; i++) { for (let i = 0; i < byteStateChangeTimes.length; i++) {
const currentData = hexData.substr(i * 2, 2), const currentData = hexData.substr(i * 2, 2);
prevData = lastParsedMessage.hexData.substr(i * 2, 2); const prevData = lastParsedMessage.hexData.substr(i * 2, 2);
if (currentData !== prevData) { if (currentData !== prevData) {
byteStateChangeTimes[i] = time; byteStateChangeTimes[i] = time;
@ -104,7 +104,7 @@ function createMessageEntry(
signals: dbc.getSignalValues(address, data), signals: dbc.getSignalValues(address, data),
time, time,
relTime, relTime,
hexData: Buffer.from(data).toString("hex"), hexData: Buffer.from(data).toString('hex'),
byteStateChangeTimes, byteStateChangeTimes,
updated: Date.now() updated: Date.now()
}; };
@ -112,11 +112,11 @@ function createMessageEntry(
function parseMessage(dbc, time, address, data, timeStart, lastParsedMessage) { function parseMessage(dbc, time, address, data, timeStart, lastParsedMessage) {
let hexData; let hexData;
if (typeof data === "string") { if (typeof data === 'string') {
hexData = data; hexData = data;
data = Buffer.from(data, "hex"); data = Buffer.from(data, 'hex');
} else { } else {
hexData = Buffer.from(data).toString("hex"); hexData = Buffer.from(data).toString('hex');
} }
const msgSpec = dbc.getMessageFrame(address); const msgSpec = dbc.getMessageFrame(address);
const msgSize = msgSpec ? msgSpec.size : 8; const msgSize = msgSpec ? msgSpec.size : 8;
@ -160,13 +160,10 @@ function matrixBitNumber(bigEndianIndex) {
function setMessageByteColors(message, maxByteStateChangeCount) { function setMessageByteColors(message, maxByteStateChangeCount) {
message.byteColors = message.byteStateChangeCounts message.byteColors = message.byteStateChangeCounts
.map( .map((count) => (isNaN(count)
count => ? 0
isNaN(count) : Math.min(255, 75 + 180 * (count / maxByteStateChangeCount))))
? 0 .map((red) => `rgb(${Math.round(red)},0,0)`);
: Math.min(255, 75 + 180 * (count / maxByteStateChangeCount))
)
.map(red => "rgb(" + Math.round(red) + ",0,0)");
return message; return message;
} }

View File

@ -1,13 +1,13 @@
export default function debounce(func, wait, immediate) { export default function debounce(func, wait, immediate) {
var timeout; let timeout;
return function() { return function () {
var context = this, const context = this;
args = arguments; const args = arguments;
var later = function() { const later = function () {
timeout = null; timeout = null;
if (!immediate) func.apply(context, args); if (!immediate) func.apply(context, args);
}; };
var callNow = immediate && !timeout; const callNow = immediate && !timeout;
clearTimeout(timeout); clearTimeout(timeout);
timeout = setTimeout(later, wait); timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args); if (callNow) func.apply(context, args);

View File

@ -1,19 +1,19 @@
const binTimeIntervals = [ const binTimeIntervals = [
{ {
seconds: 1, seconds: 1,
title: "second" title: 'second'
}, },
{ {
seconds: 60, seconds: 60,
title: "minute" title: 'minute'
}, },
{ {
seconds: 300, seconds: 300,
title: "5 minutes" title: '5 minutes'
}, },
{ {
seconds: 3600, seconds: 3600,
title: "hour" title: 'hour'
} }
]; ];
@ -33,13 +33,13 @@ function prettyBinDuration(samplesDurationSeconds, maxBinCount = 100) {
} }
export function binMessages(messageEntries, segmentIndices) { export function binMessages(messageEntries, segmentIndices) {
let startIdx = 0, let startIdx = 0;
endIdx = messageEntries.length - 1; let endIdx = messageEntries.length - 1;
if (segmentIndices && segmentIndices.length === 2) { if (segmentIndices && segmentIndices.length === 2) {
[startIdx, endIdx] = segmentIndices; [startIdx, endIdx] = segmentIndices;
} }
const first = messageEntries[startIdx], const first = messageEntries[startIdx];
last = messageEntries[endIdx]; const last = messageEntries[endIdx];
const binDuration = prettyBinDuration(last.time - first.time); const binDuration = prettyBinDuration(last.time - first.time);
const bins = []; const bins = [];
@ -63,5 +63,5 @@ export function binMessages(messageEntries, segmentIndices) {
}); });
} }
return { bins: bins, binDuration }; return { bins, binDuration };
} }

View File

@ -7,103 +7,103 @@ const NumpyLoader = (function NumpyLoader() {
} }
function readUint16LE(buffer) { function readUint16LE(buffer) {
var view = new DataView(buffer); const view = new DataView(buffer);
var val = view.getUint8(0); let val = view.getUint8(0);
val |= view.getUint8(1) << 8; val |= view.getUint8(1) << 8;
return val; return val;
} }
function fromArrayBuffer(buf) { function fromArrayBuffer(buf) {
// Check the magic number // Check the magic number
var magic = asciiDecode(buf.slice(0, 6)); const magic = asciiDecode(buf.slice(0, 6));
if (magic !== "\x93NUMPY") { if (magic !== '\x93NUMPY') {
throw new Error("Bad magic number"); throw new Error('Bad magic number');
} }
var version = new Uint8Array(buf.slice(6, 8)), const version = new Uint8Array(buf.slice(6, 8));
headerLength = readUint16LE(buf.slice(8, 10)), const headerLength = readUint16LE(buf.slice(8, 10));
headerStr = asciiDecode(buf.slice(10, 10 + headerLength)); const headerStr = asciiDecode(buf.slice(10, 10 + headerLength));
const offsetBytes = 10 + headerLength; const offsetBytes = 10 + headerLength;
//rest = buf.slice(10+headerLength); XXX -- This makes a copy!!! https://www.khronos.org/registry/typedarray/specs/latest/#5 // rest = buf.slice(10+headerLength); XXX -- This makes a copy!!! https://www.khronos.org/registry/typedarray/specs/latest/#5
// Hacky conversion of dict literal string to JS Object // Hacky conversion of dict literal string to JS Object
const info = JSON.parse( const info = JSON.parse(
headerStr headerStr
.toLowerCase() .toLowerCase()
.replace("(", "[") .replace('(', '[')
.replace("),", "]") .replace('),', ']')
.replace(/'/g, '"') .replace(/'/g, '"')
.replace(",]", "]") .replace(',]', ']')
); );
// Intepret the bytes according to the specified dtype // Intepret the bytes according to the specified dtype
var data; let data;
if (info.descr === "|u1") { if (info.descr === '|u1') {
data = new Uint8Array(buf, offsetBytes); data = new Uint8Array(buf, offsetBytes);
} else if (info.descr === "|i1") { } else if (info.descr === '|i1') {
data = new Int8Array(buf, offsetBytes); data = new Int8Array(buf, offsetBytes);
} else if (info.descr === "<u2") { } else if (info.descr === '<u2') {
data = new Uint16Array(buf, offsetBytes); data = new Uint16Array(buf, offsetBytes);
} else if (info.descr === "<i2") { } else if (info.descr === '<i2') {
data = new Int16Array(buf, offsetBytes); data = new Int16Array(buf, offsetBytes);
} else if (info.descr === "<u4") { } else if (info.descr === '<u4') {
data = new Uint32Array(buf, offsetBytes); data = new Uint32Array(buf, offsetBytes);
} else if (info.descr === "<i4") { } else if (info.descr === '<i4') {
data = new Int32Array(buf, offsetBytes); data = new Int32Array(buf, offsetBytes);
} else if (info.descr === "<f4") { } else if (info.descr === '<f4') {
data = new Float32Array(buf, offsetBytes); data = new Float32Array(buf, offsetBytes);
} else if (info.descr === "<f8") { } else if (info.descr === '<f8') {
data = new Float64Array(buf, offsetBytes); data = new Float64Array(buf, offsetBytes);
} else if (info.descr === "<u8") { } else if (info.descr === '<u8') {
// 8 byte uint64s // 8 byte uint64s
data = new Uint8Array(buf, offsetBytes); data = new Uint8Array(buf, offsetBytes);
} else if (info.descr === "<i8") { } else if (info.descr === '<i8') {
// 8 byte int64s // 8 byte int64s
data = new Uint8Array(buf, offsetBytes); data = new Uint8Array(buf, offsetBytes);
} else if (info.descr === "|s5") { } else if (info.descr === '|s5') {
// 5 byte string // 5 byte string
data = new Uint8Array(buf, offsetBytes); data = new Uint8Array(buf, offsetBytes);
} else if (info.descr === "|s8") { } else if (info.descr === '|s8') {
// 8 byte strings // 8 byte strings
data = new Uint8Array(buf, offsetBytes); data = new Uint8Array(buf, offsetBytes);
} else if (info.descr === "|s15") { } else if (info.descr === '|s15') {
// 15 byte strings? // 15 byte strings?
data = new Uint8Array(buf, offsetBytes); data = new Uint8Array(buf, offsetBytes);
} else { } else {
throw new Error("unknown numeric dtype " + info.descr); throw new Error(`unknown numeric dtype ${info.descr}`);
} }
return { return {
shape: info.shape, shape: info.shape,
fortran_order: info.fortran_order, fortran_order: info.fortran_order,
data: data data
}; };
} }
function open(file, callback) { function open(file, callback) {
var reader = new FileReader(); const reader = new FileReader();
reader.onload = function() { reader.onload = function () {
// the file contents have been read as an array buffer // the file contents have been read as an array buffer
var buf = reader.result; const buf = reader.result;
var ndarray = fromArrayBuffer(buf); const ndarray = fromArrayBuffer(buf);
callback(ndarray); callback(ndarray);
}; };
reader.readAsArrayBuffer(file); reader.readAsArrayBuffer(file);
} }
function promise(url) { function promise(url) {
return new Promise(function(resolve, reject) { return new Promise((resolve, reject) => {
// Do the usual XHR stuff // Do the usual XHR stuff
var req = new XMLHttpRequest(); const req = new XMLHttpRequest();
req.onload = function() { req.onload = function () {
// This is called even on 404 etc // This is called even on 404 etc
// so check the status // so check the status
if (req.status == 200) { if (req.status == 200) {
var buf = req.response; // not responseText const buf = req.response; // not responseText
var ndarray = fromArrayBuffer(buf); const ndarray = fromArrayBuffer(buf);
resolve(ndarray); resolve(ndarray);
} else if (req.status == 404) { } else if (req.status == 404) {
console.log("yup"); console.log('yup');
reject({ is404: true }); reject({ is404: true });
} else { } else {
// Otherwise reject with the status text // Otherwise reject with the status text
@ -113,22 +113,22 @@ const NumpyLoader = (function NumpyLoader() {
}; };
// Handle network errors // Handle network errors
req.onerror = function() { req.onerror = function () {
reject(Error("Network Error")); reject(Error('Network Error'));
}; };
// Make the request // Make the request
req.open("GET", url, true); req.open('GET', url, true);
req.responseType = "arraybuffer"; req.responseType = 'arraybuffer';
req.send(null); req.send(null);
}); });
} }
return { return {
open: open, open,
promise: promise, promise,
fromArrayBuffer: fromArrayBuffer fromArrayBuffer
}; };
})(); }());
module.exports = NumpyLoader; module.exports = NumpyLoader;

View File

@ -1,5 +1,5 @@
export function swapKeysAndValues(obj, f) { export function swapKeysAndValues(obj, f) {
return Object.keys(obj).reduce(function(acc, k) { return Object.keys(obj).reduce((acc, k) => {
acc[obj[k]] = k; acc[obj[k]] = k;
return acc; return acc;
}, {}); }, {});
@ -12,7 +12,6 @@ export function fromArray(arr) {
const pairs = arr.map(([k, v]) => ({ [k]: v })); const pairs = arr.map(([k, v]) => ({ [k]: v }));
if (pairs.length > 0) { if (pairs.length > 0) {
return Object.assign(...pairs); return Object.assign(...pairs);
} else {
return {};
} }
return {};
} }

View File

@ -1,6 +1,6 @@
export function hash(str) { export function hash(str) {
var hash = 5381, let hash = 5381;
i = str.length; let i = str.length;
while (i) { while (i) {
hash = (hash * 33) ^ str.charCodeAt(--i); hash = (hash * 33) ^ str.charCodeAt(--i);

View File

@ -1,33 +1,33 @@
/* eslint-disable no-restricted-globals*/ /* eslint-disable no-restricted-globals */
export function objToQuery(obj) { export function objToQuery(obj) {
return Object.keys(obj) return Object.keys(obj)
.map(k => k + "=" + encodeURIComponent(decodeURIComponent(obj[k]))) .map((k) => `${k}=${encodeURIComponent(decodeURIComponent(obj[k]))}`)
.join("&"); .join('&');
} }
export function getUrlParameter(name) { export function getUrlParameter(name) {
var location = window.location; const { location } = window;
name = name.replace(/[[]/, "\\[").replace(/[\]]/, "\\]"); name = name.replace(/[[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"); const regex = new RegExp(`[\\?&]${name}=([^&#]*)`);
var results = regex.exec(location.search); const results = regex.exec(location.search);
return results === null return results === null
? null ? null
: decodeURIComponent(results[1].replace(/\+/g, " ")); : decodeURIComponent(results[1].replace(/\+/g, ' '));
} }
export function modifyQueryParameters({ add, remove = [] }) { export function modifyQueryParameters({ add, remove = [] }) {
var regex = new RegExp("[\\?&]([^&#]+)=([^&#]*)"); const regex = new RegExp('[\\?&]([^&#]+)=([^&#]*)');
var results = regex.exec(location.search); const results = regex.exec(location.search);
let params = {}; let params = {};
if (results != null) { if (results != null) {
for (let i = 1; i < results.length - 1; i += 2) { for (let i = 1; i < results.length - 1; i += 2) {
let key = results[i], const key = results[i];
value = results[i + 1]; const value = results[i + 1];
params[key] = value; params[key] = value;
} }
for (let key in params) { for (const key in params) {
if (remove.indexOf(key) !== -1) { if (remove.indexOf(key) !== -1) {
delete params[key]; delete params[key];
} }
@ -37,5 +37,5 @@ export function modifyQueryParameters({ add, remove = [] }) {
params = add; params = add;
} }
return location.origin + location.pathname + "?" + objToQuery(params); return `${location.origin + location.pathname}?${objToQuery(params)}`;
} }

View File

@ -1,111 +1,121 @@
import { createClassFromSpec } from "react-vega"; import { createClassFromSpec } from 'react-vega';
const canHistogramSpec = { const canHistogramSpec = {
$schema: "https://vega.github.io/schema/vega/v3.0.json", $schema: 'https://vega.github.io/schema/vega/v3.0.json',
width: 1000, width: 1000,
height: 100, height: 100,
padding: 5, padding: 5,
signals: [ signals: [
{ {
name: "segment" name: 'segment'
} }
], ],
data: [ data: [
{ {
name: "binned" name: 'binned'
} }
], ],
scales: [ scales: [
{ {
name: "xscale", name: 'xscale',
type: "linear", type: 'linear',
zero: false, zero: false,
range: "width", range: 'width',
domain: { data: "binned", field: "startTime" } domain: { data: 'binned', field: 'startTime' }
}, },
{ {
name: "xrelscale", name: 'xrelscale',
type: "linear", type: 'linear',
zero: false, zero: false,
range: "width", range: 'width',
domain: { data: "binned", field: "relStartTime" } domain: { data: 'binned', field: 'relStartTime' }
}, },
{ {
name: "yscale", name: 'yscale',
type: "linear", type: 'linear',
range: "height", range: 'height',
round: true, round: true,
domain: { data: "binned", field: "count" }, domain: { data: 'binned', field: 'count' },
zero: true, zero: true,
nice: true nice: true
} }
], ],
axes: [ axes: [
{ orient: "bottom", scale: "xrelscale", zindex: 1, tickCount: 10 }, {
{ orient: "left", scale: "yscale", tickCount: 5, zindex: 1 } orient: 'bottom',
scale: 'xrelscale',
zindex: 1,
tickCount: 10
},
{
orient: 'left',
scale: 'yscale',
tickCount: 5,
zindex: 1
}
], ],
marks: [ marks: [
{ {
type: "group", type: 'group',
name: "histogram", name: 'histogram',
interactive: true, interactive: true,
encode: { encode: {
enter: { enter: {
height: { value: 75 }, height: { value: 75 },
width: { value: 1000 }, width: { value: 1000 },
fill: { value: "transparent" } fill: { value: 'transparent' }
} }
}, },
signals: [ signals: [
{ {
name: "brush", name: 'brush',
value: 0, value: 0,
on: [ on: [
{ {
events: "@bins:mousedown", events: '@bins:mousedown',
update: "[x(), x()]" update: '[x(), x()]'
}, },
{ {
events: "[@bins:mousedown, window:mouseup] > window:mousemove!", events: '[@bins:mousedown, window:mouseup] > window:mousemove!',
update: "[brush[0], clamp(x(), 0, width)]" update: '[brush[0], clamp(x(), 0, width)]'
}, },
{ {
events: { signal: "delta" }, events: { signal: 'delta' },
update: update:
"clampRange([anchor[0] + delta, anchor[1] + delta], 0, width)" 'clampRange([anchor[0] + delta, anchor[1] + delta], 0, width)'
} }
] ]
}, },
{ {
name: "anchor", name: 'anchor',
value: null, value: null,
on: [{ events: "@brush:mousedown", update: "slice(brush)" }] on: [{ events: '@brush:mousedown', update: 'slice(brush)' }]
}, },
{ {
name: "xdown", name: 'xdown',
value: 0, value: 0,
on: [{ events: "@brush:mousedown", update: "x()" }] on: [{ events: '@brush:mousedown', update: 'x()' }]
}, },
{ {
name: "delta", name: 'delta',
value: 0, value: 0,
on: [ on: [
{ {
events: "[@brush:mousedown, window:mouseup] > window:mousemove!", events: '[@brush:mousedown, window:mouseup] > window:mousemove!',
update: "x() - xdown" update: 'x() - xdown'
} }
] ]
}, },
{ {
name: "segment", name: 'segment',
push: "outer", push: 'outer',
on: [ on: [
{ {
events: { signal: "brush" }, events: { signal: 'brush' },
update: "span(brush) ? invert('xscale', brush) : null" update: "span(brush) ? invert('xscale', brush) : null"
} }
] ]
@ -113,72 +123,72 @@ const canHistogramSpec = {
], ],
marks: [ marks: [
{ {
type: "rect", type: 'rect',
interactive: true, interactive: true,
from: { data: "binned" }, from: { data: 'binned' },
name: "bins", name: 'bins',
encode: { encode: {
update: { update: {
x: { scale: "xscale", field: "startTime" }, x: { scale: 'xscale', field: 'startTime' },
x2: { x2: {
scale: "xscale", scale: 'xscale',
field: "endTime", field: 'endTime',
offset: 0 offset: 0
}, },
y: { scale: "yscale", field: "count" }, y: { scale: 'yscale', field: 'count' },
y2: { scale: "yscale", value: 0 }, y2: { scale: 'yscale', value: 0 },
fill: { value: "steelblue" } fill: { value: 'steelblue' }
}, },
hover: { hover: {
fill: { value: "goldenrod" }, fill: { value: 'goldenrod' },
cursor: { value: "ew-resize" } cursor: { value: 'ew-resize' }
} }
} }
}, },
{ {
type: "rect", type: 'rect',
interactive: true, interactive: true,
name: "brush", name: 'brush',
encode: { encode: {
enter: { enter: {
y: { value: 0 }, y: { value: 0 },
height: { value: 100 }, height: { value: 100 },
fill: { value: "#333" }, fill: { value: '#333' },
fillOpacity: { value: 0.2 } fillOpacity: { value: 0.2 }
}, },
update: { update: {
x: { signal: "brush[0]" }, x: { signal: 'brush[0]' },
x2: { signal: "brush[1]" } x2: { signal: 'brush[1]' }
} }
} }
}, },
{ {
type: "rect", type: 'rect',
interactive: false, interactive: false,
encode: { encode: {
enter: { enter: {
y: { value: 0 }, y: { value: 0 },
height: { value: 100 }, height: { value: 100 },
width: { value: 2 }, width: { value: 2 },
fill: { value: "firebrick" } fill: { value: 'firebrick' }
}, },
update: { update: {
x: { signal: "brush[0]" } x: { signal: 'brush[0]' }
} }
} }
}, },
{ {
type: "rect", type: 'rect',
interactive: false, interactive: false,
encode: { encode: {
enter: { enter: {
y: { value: 0 }, y: { value: 0 },
height: { value: 100 }, height: { value: 100 },
width: { value: 2 }, width: { value: 2 },
fill: { value: "firebrick" } fill: { value: 'firebrick' }
}, },
update: { update: {
x: { signal: "brush[1]" } x: { signal: 'brush[1]' }
} }
} }
} }

View File

@ -1,5 +1,5 @@
export default { export default {
$schema: "https://vega.github.io/schema/vega/v5.6.json", $schema: 'https://vega.github.io/schema/vega/v5.6.json',
width: 400, width: 400,
height: 200, height: 200,
padding: { padding: {
@ -10,166 +10,166 @@ export default {
}, },
signals: [ signals: [
{ {
name: "tipTime", name: 'tipTime',
on: [ on: [
{ {
events: "mousemove", events: 'mousemove',
update: "invert('xrelscale', x())" update: "invert('xrelscale', x())"
} }
] ]
}, },
{ {
name: "clickTime", name: 'clickTime',
on: [ on: [
{ {
events: "click", events: 'click',
update: "invert('xrelscale', x())" update: "invert('xrelscale', x())"
} }
] ]
}, },
{ name: "videoTime" }, { name: 'videoTime' },
{ {
name: "segment", name: 'segment',
value: { data: "table", field: "relTime" } value: { data: 'table', field: 'relTime' }
} }
], ],
data: [ data: [
{ {
name: "table" name: 'table'
}, },
{ {
name: "segment" name: 'segment'
}, },
{ {
name: "tooltip", name: 'tooltip',
source: "table", source: 'table',
transform: [ transform: [
{ {
type: "filter", type: 'filter',
expr: "abs(datum.relTime - tipTime) <= 0.01" expr: 'abs(datum.relTime - tipTime) <= 0.01'
}, },
{ {
type: "aggregate", type: 'aggregate',
fields: ["relTime", "y", "unit"], fields: ['relTime', 'y', 'unit'],
ops: ["min", "argmin", "argmin"], ops: ['min', 'argmin', 'argmin'],
as: ["min", "argmin", "argmin"] as: ['min', 'argmin', 'argmin']
} }
] ]
}, },
{ {
name: "ySegmentScale", name: 'ySegmentScale',
source: "table", source: 'table',
transform: [ transform: [
{ {
type: "filter", type: 'filter',
expr: expr:
"length(segment) != 2 || (datum.relTime >= segment[0] && datum.relTime <= segment[1])" 'length(segment) != 2 || (datum.relTime >= segment[0] && datum.relTime <= segment[1])'
}, },
{ type: "extent", field: "y", signal: "ySegment" } { type: 'extent', field: 'y', signal: 'ySegment' }
] ]
} }
], ],
scales: [ scales: [
{ {
name: "xscale", name: 'xscale',
type: "linear", type: 'linear',
range: "width", range: 'width',
domain: { data: "table", field: "x" }, domain: { data: 'table', field: 'x' },
zero: false zero: false
}, },
{ {
name: "xrelscale", name: 'xrelscale',
type: "linear", type: 'linear',
range: "width", range: 'width',
domain: { data: "table", field: "relTime" }, domain: { data: 'table', field: 'relTime' },
zero: false, zero: false,
clamp: true, clamp: true,
domainRaw: { signal: "segment" } domainRaw: { signal: 'segment' }
}, },
{ {
name: "yscale", name: 'yscale',
type: "linear", type: 'linear',
range: "height", range: 'height',
clamp: true, clamp: true,
zero: false, zero: false,
domain: { signal: "ySegment" } domain: { signal: 'ySegment' }
}, },
{ {
name: "color", name: 'color',
type: "ordinal", type: 'ordinal',
domain: { data: "table", field: "color" }, domain: { data: 'table', field: 'color' },
range: { data: "table", field: "color" } range: { data: 'table', field: 'color' }
} }
], ],
axes: [ axes: [
{ orient: "bottom", scale: "xrelscale", labelOverlap: true }, { orient: 'bottom', scale: 'xrelscale', labelOverlap: true },
{ orient: "left", scale: "yscale" } { orient: 'left', scale: 'yscale' }
], ],
marks: [ marks: [
{ {
type: "group", type: 'group',
name: "plot", name: 'plot',
interactive: true, interactive: true,
encode: { encode: {
enter: { enter: {
width: { signal: "width" }, width: { signal: 'width' },
height: { signal: "height" }, height: { signal: 'height' },
fill: { value: "transparent" } fill: { value: 'transparent' }
} }
}, },
signals: [ signals: [
{ {
name: "brush", name: 'brush',
value: 0, value: 0,
on: [ on: [
{ {
events: "@boundingRect:mousedown", events: '@boundingRect:mousedown',
update: "[x(), x()]" update: '[x(), x()]'
}, },
{ {
events: events:
"[@boundingRect:mousedown, window:mouseup] > window:mousemove!", '[@boundingRect:mousedown, window:mouseup] > window:mousemove!',
update: "[brush[0], clamp(x(), 0, width)]" update: '[brush[0], clamp(x(), 0, width)]'
}, },
{ {
events: { signal: "delta" }, events: { signal: 'delta' },
update: update:
"clampRange([anchor[0] + delta, anchor[1] + delta], 0, width)" 'clampRange([anchor[0] + delta, anchor[1] + delta], 0, width)'
} }
] ]
}, },
{ {
name: "anchor", name: 'anchor',
value: null, value: null,
on: [{ events: "@brush:mousedown", update: "slice(brush)" }] on: [{ events: '@brush:mousedown', update: 'slice(brush)' }]
}, },
{ {
name: "xdown", name: 'xdown',
value: 0, value: 0,
on: [{ events: "@brush:mousedown", update: "x()" }] on: [{ events: '@brush:mousedown', update: 'x()' }]
}, },
{ {
name: "xup", name: 'xup',
value: 0, value: 0,
on: [{ events: "@brush:mouseup", update: "x()" }] on: [{ events: '@brush:mouseup', update: 'x()' }]
}, },
{ {
name: "delta", name: 'delta',
value: 0, value: 0,
on: [ on: [
{ {
events: "[@brush:mousedown, window:mouseup] > window:mousemove!", events: '[@brush:mousedown, window:mouseup] > window:mousemove!',
update: "x() - xdown" update: 'x() - xdown'
} }
] ]
}, },
{ {
name: "segment", name: 'segment',
push: "outer", push: 'outer',
on: [ on: [
{ {
events: "window:mouseup", events: 'window:mouseup',
update: update:
"span(brush) && span(brush) > 15 ? invert('xrelscale', brush) : segment" "span(brush) && span(brush) > 15 ? invert('xrelscale', brush) : segment"
} }
@ -178,50 +178,50 @@ export default {
], ],
marks: [ marks: [
{ {
type: "group", type: 'group',
from: { from: {
facet: { facet: {
name: "series", name: 'series',
data: "table", data: 'table',
groupby: "signalUid" groupby: 'signalUid'
} }
}, },
marks: { marks: {
type: "line", type: 'line',
name: "lineMark", name: 'lineMark',
from: { data: "series" }, from: { data: 'series' },
interactive: true, interactive: true,
encode: { encode: {
update: { update: {
interpolate: { value: "step" }, interpolate: { value: 'step' },
x: { scale: "xrelscale", field: "relTime" }, x: { scale: 'xrelscale', field: 'relTime' },
y: { scale: "yscale", field: "y" } y: { scale: 'yscale', field: 'y' }
}, },
hover: { hover: {
fillOpacity: { value: 0.5 } fillOpacity: { value: 0.5 }
}, },
enter: { enter: {
clip: { value: true }, clip: { value: true },
stroke: { scale: "color", field: "color" }, stroke: { scale: 'color', field: 'color' },
strokeWidth: { value: 2 } strokeWidth: { value: 2 }
} }
} }
} }
}, },
{ {
type: "rect", type: 'rect',
interactive: true, interactive: true,
name: "brush", name: 'brush',
encode: { encode: {
enter: { enter: {
y: { value: 0 }, y: { value: 0 },
height: { signal: "height" }, height: { signal: 'height' },
fill: { value: "#333" }, fill: { value: '#333' },
fillOpacity: { value: 0.2 } fillOpacity: { value: 0.2 }
}, },
update: { update: {
x: { signal: "brush[0]" }, x: { signal: 'brush[0]' },
x2: { signal: "brush[1]" } x2: { signal: 'brush[1]' }
} }
} }
}, },
@ -256,61 +256,61 @@ export default {
// } // }
// }, // },
{ {
type: "rule", type: 'rule',
encode: { encode: {
update: { update: {
y: { value: 0 }, y: { value: 0 },
y2: { field: { group: "height" } }, y2: { field: { group: 'height' } },
stroke: { value: "#000" }, stroke: { value: '#000' },
strokeWidth: { value: 2 }, strokeWidth: { value: 2 },
x: { x: {
scale: "xrelscale", scale: 'xrelscale',
signal: "videoTime", signal: 'videoTime',
offset: 0.5 offset: 0.5
} }
} }
} }
}, },
{ {
type: "symbol", type: 'symbol',
from: { data: "tooltip" }, from: { data: 'tooltip' },
encode: { encode: {
update: { update: {
x: { scale: "xrelscale", field: "argmin.relTime" }, x: { scale: 'xrelscale', field: 'argmin.relTime' },
y: { scale: "yscale", field: "argmin.y" }, y: { scale: 'yscale', field: 'argmin.y' },
size: { value: 50 }, size: { value: 50 },
fill: { value: "black" } fill: { value: 'black' }
} }
} }
}, },
{ {
type: "group", type: 'group',
from: { data: "tooltip" }, from: { data: 'tooltip' },
interactive: false, interactive: false,
name: "tooltipGroup", name: 'tooltipGroup',
encode: { encode: {
update: { update: {
x: [ x: [
{ {
test: test:
"inrange(datum.argmin.relTime + 80, domain('xrelscale'))", "inrange(datum.argmin.relTime + 80, domain('xrelscale'))",
scale: "xrelscale", scale: 'xrelscale',
field: "argmin.relTime" field: 'argmin.relTime'
}, },
{ scale: "xrelscale", field: "argmin.relTime", offset: -80 } { scale: 'xrelscale', field: 'argmin.relTime', offset: -80 }
], ],
y: { scale: "yscale", field: "argmin.y" }, y: { scale: 'yscale', field: 'argmin.y' },
height: { value: 20 }, height: { value: 20 },
width: { value: 80 }, width: { value: 80 },
fill: { value: "#fff" }, fill: { value: '#fff' },
fillOpacity: { value: 0.85 }, fillOpacity: { value: 0.85 },
stroke: { value: "#aaa" }, stroke: { value: '#aaa' },
strokeWidth: { value: 0.5 } strokeWidth: { value: 0.5 }
} }
}, },
marks: [ marks: [
{ {
type: "text", type: 'text',
interactive: false, interactive: false,
encode: { encode: {
update: { update: {
@ -318,8 +318,8 @@ export default {
signal: signal:
"format(parent.argmin.relTime, ',.2f') + ': ' + format(parent.argmin.y, ',.2f') + ' ' + parent.argmin.unit" "format(parent.argmin.relTime, ',.2f') + ': ' + format(parent.argmin.y, ',.2f') + ' ' + parent.argmin.unit"
}, },
fill: { value: "black" }, fill: { value: 'black' },
fontWeight: { value: "bold" }, fontWeight: { value: 'bold' },
y: { value: 20 } y: { value: 20 }
} }
} }
@ -327,14 +327,14 @@ export default {
] ]
}, },
{ {
type: "rect", type: 'rect',
name: "boundingRect", name: 'boundingRect',
interactive: true, interactive: true,
encode: { encode: {
enter: { enter: {
width: { signal: "width" }, width: { signal: 'width' },
height: { signal: "height" }, height: { signal: 'height' },
fill: { value: "transparent" } fill: { value: 'transparent' }
} }
} }
} }

View File

@ -1,8 +1,8 @@
/* eslint-env worker */ /* eslint-env worker */
/* eslint-disable no-restricted-globals */ /* eslint-disable no-restricted-globals */
import DBC from "../models/can/dbc"; import extend from 'xtend';
import DbcUtils from "../utils/dbc"; import DBC from '../models/can/dbc';
import extend from "xtend"; import DbcUtils from '../utils/dbc';
function processStreamedCanMessages( function processStreamedCanMessages(
newCanMessages, newCanMessages,
@ -21,17 +21,19 @@ function processStreamedCanMessages(
canMessages = canMessages.sort((msg1, msg2) => { canMessages = canMessages.sort((msg1, msg2) => {
if (msg1[1] < msg2[1]) { if (msg1[1] < msg2[1]) {
return -1; return -1;
} else if (msg1[1] > msg2[1]) {
return 1;
} else {
return 0;
} }
if (msg1[1] > msg2[1]) {
return 1;
}
return 0;
}); });
let busTimeSum = 0; let busTimeSum = 0;
for (let i = 0; i < canMessages.length; i++) { for (let i = 0; i < canMessages.length; i++) {
let { address, busTime, data, bus } = canMessages[i]; const {
address, busTime, data, bus
} = canMessages[i];
let prevBusTime; let prevBusTime;
if (i === 0) { if (i === 0) {
@ -78,7 +80,7 @@ function processStreamedCanMessages(
maxByteStateChangeCount = newMaxByteStateChangeCount; maxByteStateChangeCount = newMaxByteStateChangeCount;
} }
Object.keys(messages).forEach(key => { Object.keys(messages).forEach((key) => {
messages[key] = DbcUtils.setMessageByteColors( messages[key] = DbcUtils.setMessageByteColors(
messages[key], messages[key],
maxByteStateChangeCount maxByteStateChangeCount
@ -95,7 +97,7 @@ function processStreamedCanMessages(
}); });
} }
self.onmessage = function(e) { self.onmessage = function (e) {
const { const {
newCanMessages, newCanMessages,
prevMsgEntries, prevMsgEntries,

View File

@ -2,19 +2,19 @@
/* eslint-disable no-restricted-globals */ /* eslint-disable no-restricted-globals */
// import Sentry from '../logging/Sentry'; // import Sentry from '../logging/Sentry';
import NumpyLoader from "../utils/loadnpy"; import NumpyLoader from '../utils/loadnpy';
const MAX_CONNECTIONS = 8; const MAX_CONNECTIONS = 8;
var window = self; const window = self;
const Int64LE = require("int64-buffer").Int64LE; const { Int64LE } = require('int64-buffer');
function transformAndSend(rawData) { function transformAndSend(rawData) {
var totalSize = 0; let totalSize = 0;
var maxTime = rawData.reduce(function(memo, sourceData) { const maxTime = rawData.reduce((memo, sourceData) => {
totalSize += sourceData.entries.length; totalSize += sourceData.entries.length;
sourceData.entries = sourceData.entries.sort(function(a, b) { sourceData.entries = sourceData.entries.sort((a, b) => {
if (a.relTime > b.relTime) { if (a.relTime > b.relTime) {
return 1; return 1;
} }
@ -26,14 +26,14 @@ function transformAndSend(rawData) {
return Math.max(memo, getLastTimeFromEntries(sourceData.entries)); return Math.max(memo, getLastTimeFromEntries(sourceData.entries));
}, 0); }, 0);
var minTime = Math.max(0, maxTime - 30); const minTime = Math.max(0, maxTime - 30);
console.log("Time span from", minTime, maxTime); console.log('Time span from', minTime, maxTime);
var curIndexes = {}; const curIndexes = {};
rawData.forEach(function(sourceData) { rawData.forEach((sourceData) => {
if (!sourceData.entries.length) { if (!sourceData.entries.length) {
return; return;
} }
var sourceId = sourceData.id; const sourceId = sourceData.id;
if (minTime === 0 || sourceData.entries[0].relTime > minTime) { if (minTime === 0 || sourceData.entries[0].relTime > minTime) {
curIndexes[sourceId] = 0; curIndexes[sourceId] = 0;
return; return;
@ -41,12 +41,12 @@ function transformAndSend(rawData) {
curIndexes[sourceId] = findFirstEntryIndex(sourceData.entries, minTime); curIndexes[sourceId] = findFirstEntryIndex(sourceData.entries, minTime);
}); });
var entryBuffer = []; let entryBuffer = [];
var totalEntries = 0; let totalEntries = 0;
while (!isAtEnd()) { while (!isAtEnd()) {
let nextSource = rawData.reduce(function(memo, sourceData) { const nextSource = rawData.reduce((memo, sourceData) => {
let curEntry = sourceData.entries[curIndexes[sourceData.id]]; const curEntry = sourceData.entries[curIndexes[sourceData.id]];
if (!curEntry) { if (!curEntry) {
return memo; return memo;
} }
@ -79,7 +79,7 @@ function transformAndSend(rawData) {
if (entryBuffer.length > 5000) { if (entryBuffer.length > 5000) {
self.postMessage({ self.postMessage({
progress: 100 * (totalEntries / totalSize), progress: 100 * (totalEntries / totalSize),
logData: entryBuffer.join("\n"), logData: entryBuffer.join('\n'),
shouldClose: false shouldClose: false
}); });
entryBuffer = []; entryBuffer = [];
@ -88,13 +88,13 @@ function transformAndSend(rawData) {
if (entryBuffer.length > 0) { if (entryBuffer.length > 0) {
self.postMessage({ self.postMessage({
progress: 99, progress: 99,
logData: entryBuffer.join("\n"), logData: entryBuffer.join('\n'),
shouldClose: false shouldClose: false
}); });
entryBuffer = []; entryBuffer = [];
} }
console.log("Wrote", totalEntries, "lines of CSV"); console.log('Wrote', totalEntries, 'lines of CSV');
self.postMessage({ self.postMessage({
progress: 100, progress: 100,
shouldClose: true shouldClose: true
@ -102,8 +102,7 @@ function transformAndSend(rawData) {
function isAtEnd() { function isAtEnd() {
return rawData.reduce( return rawData.reduce(
(memo, sourceData) => (memo, sourceData) => memo && curIndexes[sourceData.id] >= sourceData.entries.length
memo && curIndexes[sourceData.id] >= sourceData.entries.length
); );
} }
} }
@ -114,7 +113,7 @@ function makeEntry(nextSource) {
nextSource.address, nextSource.address,
nextSource.bus, nextSource.bus,
nextSource.entry.hexData nextSource.entry.hexData
].join(","); ].join(',');
} }
function findFirstEntryIndex(entries, minTime, start, length) { function findFirstEntryIndex(entries, minTime, start, length) {
@ -160,11 +159,11 @@ function getLastTimeFromEntries(entries) {
return entries[entries.length - 1].relTime; return entries[entries.length - 1].relTime;
} }
self.onmessage = function(e) { self.onmessage = function (e) {
console.log("onmessage worker"); console.log('onmessage worker');
self.postMessage({ self.postMessage({
progress: 0, progress: 0,
logData: "time,addr,bus,data", logData: 'time,addr,bus,data',
shouldClose: false shouldClose: false
}); });
const { const {
@ -180,7 +179,7 @@ self.onmessage = function(e) {
// saveDBC(dbc, base, num, canStartTime); // saveDBC(dbc, base, num, canStartTime);
if (data) { if (data) {
// has raw data from live mode, process this instead // has raw data from live mode, process this instead
console.log("Using raw data from memory", canStartTime); console.log('Using raw data from memory', canStartTime);
transformAndSend(data, canStartTime); transformAndSend(data, canStartTime);
} else { } else {
self.postMessage({ self.postMessage({

Some files were not shown because too many files have changed in this diff Show More