From 1b020104e128af7d3519dfd07b8910ff04d54097 Mon Sep 17 00:00:00 2001 From: Evgeny Kochetkov Date: Mon, 25 Dec 2017 15:08:23 +0300 Subject: [PATCH] feat(xod-client, xod-client-electron): deployment pane Closes #959 --- package.json | 2 +- packages/xod-arduino-deploy/src/uploader.js | 19 +- .../xod-client-browser/src/containers/App.jsx | 3 +- .../src/app/arduinoActions.js | 2 +- .../xod-client-electron/src/popups/reducer.js | 6 +- .../upload/components/PopupUploadProject.jsx | 144 ------------- .../src/upload/messages.js | 3 + .../src/view/containers/App.jsx | 24 +-- .../src/core/assets/icons/clear-log.svg | 31 +++ .../src/core/assets/icons/debug.svg | 25 +++ .../src/core/assets/icons/filter.svg | 10 + .../src/core/assets/icons/quick-upload.svg | 11 + .../src/core/styles/abstracts/icons.scss | 13 ++ .../core/styles/components/Breadcrumbs.scss | 1 - .../components/CppImplementationEditor.scss | 1 - .../src/core/styles/components/Debugger.scss | 164 +++++++++------ .../src/core/styles/components/Sidebar.scss | 1 + .../src/core/styles/components/Workarea.scss | 6 + .../xod-client/src/debugger/actionTypes.js | 4 +- packages/xod-client/src/debugger/actions.js | 12 +- packages/xod-client/src/debugger/constants.js | 15 ++ .../src/debugger/containers/Debugger.jsx | 199 ++++++++++++++---- .../src/debugger/containers/Log.jsx | 16 +- packages/xod-client/src/debugger/messages.js | 2 + packages/xod-client/src/debugger/reducer.js | 92 +++++++- packages/xod-client/src/debugger/selectors.js | 12 ++ packages/xod-client/src/debugger/state.js | 2 + .../src/editor/containers/Editor.jsx | 22 +- packages/xod-client/src/utils/menu.js | 2 +- packages/xod-client/stories/Debugger.jsx | 124 ++++++++++- 30 files changed, 654 insertions(+), 314 deletions(-) delete mode 100644 packages/xod-client-electron/src/upload/components/PopupUploadProject.jsx create mode 100644 packages/xod-client-electron/src/upload/messages.js create mode 100644 packages/xod-client/src/core/assets/icons/clear-log.svg create mode 100644 packages/xod-client/src/core/assets/icons/debug.svg create mode 100644 packages/xod-client/src/core/assets/icons/filter.svg create mode 100644 packages/xod-client/src/core/assets/icons/quick-upload.svg create mode 100644 packages/xod-client/src/debugger/constants.js create mode 100644 packages/xod-client/src/debugger/messages.js diff --git a/package.json b/package.json index 3ab29335..8002155d 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "doc:fz": "cd docs && make", "lerna": "lerna", "lint": "eslint packages/*/src packages/*/test packages/*/test-func --ext js,jsx --max-warnings 0", - "start:electron": "lerna run start --scope xod-client-electron", + "start:electron": "lerna run start --scope xod-client-electron --stream", "start:spectron-repl": "./tools/spectron-repl", "storybook": "lerna run storybook --stream --scope xod-client", "test": "XOD_HM_DEF=true lerna run test", diff --git a/packages/xod-arduino-deploy/src/uploader.js b/packages/xod-arduino-deploy/src/uploader.js index 15b972d4..5482987e 100644 --- a/packages/xod-arduino-deploy/src/uploader.js +++ b/packages/xod-arduino-deploy/src/uploader.js @@ -140,11 +140,22 @@ export const upload = R.curry( export const buildAndUpload = R.curry( (sketchFilePath, fqbn, packagesDir, librariesDir, buildDir, portName, builderToolDir) => build(sketchFilePath, fqbn, packagesDir, librariesDir, buildDir, builderToolDir) - .then((res) => { - if (res.exitCode !== 0) { - return Promise.reject(Object.assign(new Error(res.stderr), res)); + .then((buildResult) => { + if (buildResult.exitCode !== 0) { + return Promise.reject(Object.assign(new Error(buildResult.stderr), buildResult)); } - return upload(sketchFilePath, fqbn, packagesDir, buildDir, portName); + return upload(sketchFilePath, fqbn, packagesDir, buildDir, portName) + .then((uploadResult) => { + if (uploadResult.exitCode !== 0) { + return Promise.reject(Object.assign(new Error(uploadResult.stderr), uploadResult)); + } + + return { + exitCode: uploadResult.exitCode, + stdout: [buildResult.stdout, uploadResult.stdout].join('\n'), + stderr: [buildResult.stderr, uploadResult.stderr].join('\n'), + }; + }); }) ); diff --git a/packages/xod-client-browser/src/containers/App.jsx b/packages/xod-client-browser/src/containers/App.jsx index 1ac7bb7b..cbf3d4a3 100644 --- a/packages/xod-client-browser/src/containers/App.jsx +++ b/packages/xod-client-browser/src/containers/App.jsx @@ -267,8 +267,9 @@ class App extends client.App { /> - { switch (action.type) { case UPLOAD: case UPLOAD_TO_ARDUINO: { - if (action.meta.status === 'deleted') { - return hideOnePopup(POPUP_ID.UPLOADING, state); - } else if (action.meta.status !== 'failed') { - return showOnlyPopup(POPUP_ID.UPLOADING, {}, state); + if (action.meta.status === 'started') { + return hideOnePopup(POPUP_ID.UPLOADING_CONFIG, state); } return state; } diff --git a/packages/xod-client-electron/src/upload/components/PopupUploadProject.jsx b/packages/xod-client-electron/src/upload/components/PopupUploadProject.jsx deleted file mode 100644 index 49528063..00000000 --- a/packages/xod-client-electron/src/upload/components/PopupUploadProject.jsx +++ /dev/null @@ -1,144 +0,0 @@ -import R from 'ramda'; -import React from 'react'; -import PropTypes from 'prop-types'; -import { STATUS, PopupForm } from 'xod-client'; -import { Line as ProgressBar } from 'rc-progress'; - -class PopupUploadProject extends React.Component { - constructor(props) { - super(props); - - this.state = { - isVisible: props.isVisible, - }; - - this.onClose = this.onClose.bind(this); - } - - onClose() { - if (this.canClose()) { - this.props.onClose(this.props.upload.id); - } - } - - getTitle() { - switch (this.props.upload.status) { - default: - return 'Uploading project'; - } - } - - getMessage() { - const preStyle = { - overflow: 'auto', - maxWidth: 'auto', - maxHeight: '300px', - // allow user to select the log for bug reporting etc - userSelect: 'initial', - cursor: 'auto', - }; - - const message = (this.props.upload.message) ? - (
{this.props.upload.message.replace(/\r[^\n]/g, '\n')}
) : - null; - - - const titleMessage = R.cond([ - [R.equals(STATUS.SUCCEEDED), R.always( -

- The program uploaded successfully. -

- )], - [R.equals(STATUS.FAILED), R.always( -

- Oops! Error occured. -

- )], - [R.T, R.always( -

- Your program is uploading onto device.
- Do not unplug the device. -

- )], - ])(this.props.upload.status); - - return ( -
- {titleMessage} - {message} -
- ); - } - - getProgress() { - if (this.isSucceeded()) { - return '100'; - } - - if (this.props.upload.percentage) { - return this.props.upload.percentage.toString(); - } - - return '0'; - } - - isSucceeded() { - return (this.props.upload.status === STATUS.SUCCEEDED); - } - - isFailed() { - return (this.props.upload.status === STATUS.FAILED); - } - - canClose() { - return (this.isSucceeded() || this.isFailed()); - } - - render() { - const title = this.getTitle(); - const message = this.getMessage(); - const progress = this.getProgress(); - const color = this.isFailed() ? '#ed5b5b' : '#81c522'; - - return ( - -
- -
-
- {message} -
-
- ); - } -} - -PopupUploadProject.propTypes = { - upload: PropTypes.object, - isVisible: PropTypes.bool, - onClose: PropTypes.func, -}; - -PopupUploadProject.defaultProps = { - upload: { - status: STATUS.STARTED, - message: '', - percentage: 0, - }, - isVisible: false, -}; - -export default PopupUploadProject; diff --git a/packages/xod-client-electron/src/upload/messages.js b/packages/xod-client-electron/src/upload/messages.js new file mode 100644 index 00000000..cc7f08c3 --- /dev/null +++ b/packages/xod-client-electron/src/upload/messages.js @@ -0,0 +1,3 @@ +export default { + SUCCESS: 'Uploaded successfully', +}; diff --git a/packages/xod-client-electron/src/view/containers/App.jsx b/packages/xod-client-electron/src/view/containers/App.jsx index bb6fdb6c..a2985ef1 100644 --- a/packages/xod-client-electron/src/view/containers/App.jsx +++ b/packages/xod-client-electron/src/view/containers/App.jsx @@ -27,7 +27,6 @@ import { UPLOAD, UPLOAD_TO_ARDUINO } from '../../upload/actionTypes'; import PopupSetWorkspace from '../../settings/components/PopupSetWorkspace'; import PopupCreateWorkspace from '../../settings/components/PopupCreateWorkspace'; import PopupProjectSelection from '../../projects/components/PopupProjectSelection'; -import PopupUploadProject from '../../upload/components/PopupUploadProject'; import PopupUploadConfig from '../../upload/components/PopupUploadConfig'; import { REDUCER_STATUS } from '../../projects/constants'; import { SaveProgressBar } from '../components/SaveProgressBar'; @@ -35,6 +34,7 @@ import { SaveProgressBar } from '../components/SaveProgressBar'; import formatError from '../../shared/errorFormatter'; import * as EVENTS from '../../shared/events'; import * as MESSAGES from '../../shared/messages'; +import UPLOAD_MESSAGES from '../../upload/messages'; import { createSystemMessage } from '../../shared/debuggerMessages'; import { subscribeAutoUpdaterEvents } from '../autoupdate'; @@ -83,6 +83,7 @@ class App extends client.App { this.getSelectedBoard = this.getSelectedBoard.bind(this); this.onUploadToArduinoClicked = this.onUploadToArduinoClicked.bind(this); + this.onUploadToArduinoAndDebugClicked = this.onUploadToArduinoAndDebugClicked.bind(this); this.onUploadToArduino = this.onUploadToArduino.bind(this); this.onArduinoTargetBoardChange = this.onArduinoTargetBoardChange.bind(this); this.onSerialPortChange = this.onSerialPortChange.bind(this); @@ -188,6 +189,10 @@ class App extends client.App { this.props.actions.uploadToArduinoConfig(); } + onUploadToArduinoAndDebugClicked() { + this.props.actions.uploadToArduinoConfig(true); + } + onUploadToArduino(board, port, cloud, debug, processActions = null) { const proc = (processActions !== null) ? processActions : this.props.actions.uploadToArduino(); const eitherTProject = this.transformProjectForTranspiler(debug); @@ -219,6 +224,9 @@ class App extends client.App { } if (payload.success) { proc.success(payload.message); + + this.props.actions.addConfirmation({ title: UPLOAD_MESSAGES.SUCCESS }); + if (debug) { foldEither( error => this.props.actions.addError( @@ -633,15 +641,6 @@ class App extends client.App { /> ) : null; } - renderPopupUploadProcess() { - return (this.props.popups.uploadProject) ? ( - - ) : null; - } render() { return ( @@ -654,10 +653,11 @@ class App extends client.App { debuggerIPC.sendStopDebuggerSession(ipcRenderer)} + onUploadClick={this.onUploadToArduinoClicked} + onUploadAndDebugClick={this.onUploadToArduinoAndDebugClicked} /> {this.renderPopupShowCode()} {this.renderPopupUploadConfig()} - {this.renderPopupUploadProcess()} {this.renderPopupProjectPreferences()} {this.renderPopupPublishProject()} {this.renderPopupCreateNewProject()} @@ -762,7 +762,6 @@ const mapStateToProps = R.applySpec({ switchWorkspace: client.getPopupVisibility(client.POPUP_ID.SWITCHING_WORKSPACE), createWorkspace: client.getPopupVisibility(client.POPUP_ID.CREATING_WORKSPACE), uploadToArduinoConfig: client.getPopupVisibility(client.POPUP_ID.UPLOADING_CONFIG), - uploadProject: client.getPopupVisibility(client.POPUP_ID.UPLOADING), showCode: client.getPopupVisibility(client.POPUP_ID.SHOWING_CODE), projectPreferences: client.getPopupVisibility( client.POPUP_ID.EDITING_PROJECT_PREFERENCES @@ -789,6 +788,7 @@ const mapDispatchToProps = dispatch => ({ switchWorkspace: settingsActions.switchWorkspace, openProject: client.openProject, saveAll: actions.saveAll, + addConfirmation: client.addConfirmation, uploadToArduino: uploadActions.uploadToArduino, uploadToArduinoConfig: uploadActions.uploadToArduinoConfig, hideUploadConfigPopup: uploadActions.hideUploadConfigPopup, diff --git a/packages/xod-client/src/core/assets/icons/clear-log.svg b/packages/xod-client/src/core/assets/icons/clear-log.svg new file mode 100644 index 00000000..d53eb6f4 --- /dev/null +++ b/packages/xod-client/src/core/assets/icons/clear-log.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/xod-client/src/core/assets/icons/debug.svg b/packages/xod-client/src/core/assets/icons/debug.svg new file mode 100644 index 00000000..32aba180 --- /dev/null +++ b/packages/xod-client/src/core/assets/icons/debug.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + diff --git a/packages/xod-client/src/core/assets/icons/filter.svg b/packages/xod-client/src/core/assets/icons/filter.svg new file mode 100644 index 00000000..a25031b5 --- /dev/null +++ b/packages/xod-client/src/core/assets/icons/filter.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/packages/xod-client/src/core/assets/icons/quick-upload.svg b/packages/xod-client/src/core/assets/icons/quick-upload.svg new file mode 100644 index 00000000..7b100473 --- /dev/null +++ b/packages/xod-client/src/core/assets/icons/quick-upload.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/packages/xod-client/src/core/styles/abstracts/icons.scss b/packages/xod-client/src/core/styles/abstracts/icons.scss index 0dac74a0..b5c573fd 100644 --- a/packages/xod-client/src/core/styles/abstracts/icons.scss +++ b/packages/xod-client/src/core/styles/abstracts/icons.scss @@ -32,3 +32,16 @@ .icon-account { @include icon('../assets/icons/account.svg'); } + +.icon-quick-upload { + @include icon('../assets/icons/quick-upload.svg'); +} +.icon-debug { + @include icon('../assets/icons/debug.svg'); +} +.icon-filter { + @include icon('../assets/icons/filter.svg'); +} +.icon-clear-log { + @include icon('../assets/icons/clear-log.svg'); +} diff --git a/packages/xod-client/src/core/styles/components/Breadcrumbs.scss b/packages/xod-client/src/core/styles/components/Breadcrumbs.scss index 4b42ae67..450cad4f 100644 --- a/packages/xod-client/src/core/styles/components/Breadcrumbs.scss +++ b/packages/xod-client/src/core/styles/components/Breadcrumbs.scss @@ -1,7 +1,6 @@ .Breadcrumbs { z-index: 9; position: absolute; - top: 30px; left: 0; right: 0; diff --git a/packages/xod-client/src/core/styles/components/CppImplementationEditor.scss b/packages/xod-client/src/core/styles/components/CppImplementationEditor.scss index 3e7703e0..00ac0152 100644 --- a/packages/xod-client/src/core/styles/components/CppImplementationEditor.scss +++ b/packages/xod-client/src/core/styles/components/CppImplementationEditor.scss @@ -1,6 +1,5 @@ .CppImplementationEditors { display: flex; - height: 100%; width: 100%; flex-grow: 1; diff --git a/packages/xod-client/src/core/styles/components/Debugger.scss b/packages/xod-client/src/core/styles/components/Debugger.scss index 627d879b..ed5c6725 100644 --- a/packages/xod-client/src/core/styles/components/Debugger.scss +++ b/packages/xod-client/src/core/styles/components/Debugger.scss @@ -1,7 +1,7 @@ .debug-session-stop-button { z-index: 10; position: absolute; - top: 33px; + top: 3px; right: 3px; padding: 8px 15px 10px 15px; @@ -13,88 +13,126 @@ } .Debugger { - position: absolute; - z-index: 10; bottom: 0; - height: 196px; + height: 220px; width: 100%; + border-top: 2px solid $chrome-outlines; color: $sidebar-color-text; - .caption { - position: relative; - display: block; - box-sizing: border-box; - height: 20px; - width: 120px; - margin-left: 2em; - margin-top: -20px; - - padding: 4px 8px; - cursor: default; - - background: $sidebar-color-bg; - border-top-right-radius: 2px; - border-top-left-radius: 2px; - - .close-button { - display: inline-block; - width: 16px; - height: 16px; - padding: 0; - - position: absolute; - top: 2px; - right: 2px; - - background: none; - border: none; - font-size: 1.4em; - line-height: 0; - color: $sidebar-color-text; - - &:hover { - color: $sidebar-color-text-hover; - } - } - .title { - vertical-align: middle; - } - .status { - font-size: $font-size-s; - margin-right: 0.5em; - } + &.isCollapsed { + height: 24px; } - .clear-log-button { - position: absolute; - top: 2px; - right: 22px; - z-index: 3; + .titlebar { + background-color: $coal-bright; - border: 0; - background: $sidebar-color-bg; - color: $sidebar-color-text; + display: flex; + flex-direction: row; + align-items: stretch; - padding: 2px 4px; + .expander { + flex-grow: 1; + display: flex; + flex-direction: row; + align-items: center; - &:hover { - color: $sidebar-color-text-hover; - background: $sidebar-color-bg-hover; + .title { + margin-left: 7px; + color: $light-grey-bright; + } + + .progress { + + padding-left: 14px; + + .progress-trail { + width: 150px; + height: 7px; + border-radius: 7px; + + background-color: $dark; + overflow: hidden; + + .progress-line { + height: 7px; + background-color: $green; + } + } + } + } + + + @mixin deploymentPanelButton() { + box-sizing: border-box; + width: 24px; + height: 24px; + padding: 0; + text-align: center; + vertical-align: middle; + line-height: 1; + background: none; + border-radius: 0; + border: none; + outline: none; + cursor: pointer; + color: #ccc; + + &:hover { + color: #ccc; + background: #444; + } + } + + .quick-upload-button { + @include deploymentPanelButton(); + @extend .icon-quick-upload; + } + .debug-button { + @include deploymentPanelButton(); + @extend .icon-debug; + } + .filter-button { + @include deploymentPanelButton(); + @extend .icon-filter; + } + .clear-log-button { + @include deploymentPanelButton(); + @extend .icon-clear-log; + } + .close-button { + @include deploymentPanelButton(); + + &::before { + line-height: 24px; + opacity: 0.4; + } } } .container { display: block; - height: 180px; - padding: 8px; + height: 196px; background: $sidebar-color-bg; border-left: 1px solid $color-canvas-background; } .log { - max-height: 180px; + max-height: 196px; + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-track { + opacity: 0; + } + + &::-webkit-scrollbar-thumb { + background-color: rgba(white, 0.35); + border-radius: 3px; + } pre { margin: 0; @@ -142,8 +180,6 @@ display: inline-block; color: $color-comment-text; font-family: $font-family-mono; - - white-space: nowrap; } } diff --git a/packages/xod-client/src/core/styles/components/Sidebar.scss b/packages/xod-client/src/core/styles/components/Sidebar.scss index f9d98805..5fe5ad41 100644 --- a/packages/xod-client/src/core/styles/components/Sidebar.scss +++ b/packages/xod-client/src/core/styles/components/Sidebar.scss @@ -5,6 +5,7 @@ display: flex; flex-direction: column; flex-wrap: nowrap; + flex-shrink: 0; background: $sidebar-color-bg; diff --git a/packages/xod-client/src/core/styles/components/Workarea.scss b/packages/xod-client/src/core/styles/components/Workarea.scss index cf227563..8d442ad5 100644 --- a/packages/xod-client/src/core/styles/components/Workarea.scss +++ b/packages/xod-client/src/core/styles/components/Workarea.scss @@ -4,3 +4,9 @@ flex-direction: column; flex-grow: 1; } + +.Workarea-inner { + position: relative; + display: flex; + flex-grow: 1; +} diff --git a/packages/xod-client/src/debugger/actionTypes.js b/packages/xod-client/src/debugger/actionTypes.js index 4a7c4c73..f2358ad6 100644 --- a/packages/xod-client/src/debugger/actionTypes.js +++ b/packages/xod-client/src/debugger/actionTypes.js @@ -1,5 +1,5 @@ -export const SHOW_DEBUGGER_PANEL = 'SHOW_DEBUGGER_PANEL'; -export const HIDE_DEBUGGER_PANEL = 'HIDE_DEBUGGER_PANEL'; +export const UPLOAD = 'UPLOAD'; + export const TOGGLE_DEBUGGER_PANEL = 'TOGGLE_DEBUGGER_PANEL'; export const DEBUGGER_LOG_ADD_MESSAGES = 'DEBUGGER_LOG_ADD_MESSAGES'; diff --git a/packages/xod-client/src/debugger/actions.js b/packages/xod-client/src/debugger/actions.js index 71de6fdf..f8894c07 100644 --- a/packages/xod-client/src/debugger/actions.js +++ b/packages/xod-client/src/debugger/actions.js @@ -1,20 +1,12 @@ import * as AT from './actionTypes'; -export const showDebugger = () => ({ - type: AT.SHOW_DEBUGGER_PANEL, -}); - -export const hideDebugger = () => ({ - type: AT.HIDE_DEBUGGER_PANEL, -}); - export const toggleDebugger = () => ({ type: AT.TOGGLE_DEBUGGER_PANEL, }); -export const addMessagesToDebuggerLog = message => ({ +export const addMessagesToDebuggerLog = messages => ({ type: AT.DEBUGGER_LOG_ADD_MESSAGES, - payload: message, + payload: messages, }); export const clearDebuggerLog = () => ({ diff --git a/packages/xod-client/src/debugger/constants.js b/packages/xod-client/src/debugger/constants.js new file mode 100644 index 00000000..fed62d79 --- /dev/null +++ b/packages/xod-client/src/debugger/constants.js @@ -0,0 +1,15 @@ + +export const UPLOAD_STATUS = { + STARTED: 'started', + PROGRESSED: 'progressed', + SUCCEEDED: 'succeeded', + FAILED: 'failed', +}; + +export const UPLOAD_MSG_TYPE = { + XOD: 'xod', + LOG: 'log', + ERROR: 'error', + SYSTEM: 'system', + FLASHER: 'flasher', +}; diff --git a/packages/xod-client/src/debugger/containers/Debugger.jsx b/packages/xod-client/src/debugger/containers/Debugger.jsx index 9faecdec..821f7a28 100644 --- a/packages/xod-client/src/debugger/containers/Debugger.jsx +++ b/packages/xod-client/src/debugger/containers/Debugger.jsx @@ -1,65 +1,180 @@ import R from 'ramda'; import React from 'react'; import PropTypes from 'prop-types'; +import cn from 'classnames'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; +import { ContextMenuTrigger, ContextMenu, MenuItem } from 'react-contextmenu'; import { Icon } from 'react-fa'; -import classNames from 'classnames'; +import { foldMaybe } from 'xod-func-tools'; -import { isDebugSession } from '../selectors'; +import { getUploadProgress, isDebuggerVisible } from '../selectors'; +import { UPLOAD_MSG_TYPE } from '../constants'; import * as DA from '../actions'; import Log from './Log'; -const Debugger = ({ active, actions }) => { - const cls = classNames('Debugger', { - 'is-active': active, - }); - - const statusIcon = (active) ? 'play' : 'stop'; - - return ( -
-
- - - Debugger - - -
- -
- -
-
- ); +const contextMenuAttrs = { + className: 'contextmenu filter-button', }; +const DEPLOYMENT_PANEL_FILTER_CONTEXT_MENU_ID = 'DEPLOYMENT_PANEL_FILTER_CONTEXT_MENU_ID'; + +const checkmark = active => (active ? : null); + +class Debugger extends React.Component { + constructor(props) { + super(props); + + this.state = { + messageTypeFilter: { + [UPLOAD_MSG_TYPE.FLASHER]: true, + [UPLOAD_MSG_TYPE.XOD]: false, + }, + }; + + this.toggleDebugMessages = this.toggleMessageType.bind(this, UPLOAD_MSG_TYPE.XOD); + this.toggleUploadMessages = this.toggleMessageType.bind(this, UPLOAD_MSG_TYPE.FLASHER); + } + + toggleMessageType(type) { + this.setState(R.over( + R.lensPath(['messageTypeFilter', type]), + R.not + )); + } + + renderControlsForExpandedState() { + const { isExpanded, actions } = this.props; + + if (!isExpanded) return null; + + const { messageTypeFilter } = this.state; + + return ( + +