From 3e97402403ea5648670f6d27b5accd73c154ff0a Mon Sep 17 00:00:00 2001 From: Evgeny Kochetkov Date: Tue, 26 Feb 2019 22:47:49 +0300 Subject: [PATCH] feat(xod-client, xod-client-browser, xod-client-electron): add UI for sending pulses during debug sessions through tweak-pulse nodes --- .../src/debugger/sendToSerialMiddleware.js | 8 ++-- .../src/core/styles/components/Inspector.scss | 7 +++ .../sendToSimulationSerialMiddleware.js | 5 ++- packages/xod-client/src/editor/actionTypes.js | 2 + packages/xod-client/src/editor/actions.js | 12 ++++++ .../src/editor/components/Inspector.jsx | 21 ++++++++- .../src/editor/components/NodeInspector.jsx | 29 ++++++++++++- .../src/editor/components/PinWidgetsGroup.jsx | 2 +- .../inspectorWidgets/PulseTweakWidget.jsx | 43 +++++++++++++++++++ .../components/inspectorWidgets/index.js | 1 + .../inspectorWidgets/pinWidgets/PinWidget.jsx | 1 + .../src/editor/containers/Sidebar.jsx | 7 +++ packages/xod-client/src/index.js | 13 +++++- .../components/nodeParts/ConstantNodeBody.jsx | 11 ++++- 14 files changed, 149 insertions(+), 13 deletions(-) create mode 100644 packages/xod-client/src/editor/components/inspectorWidgets/PulseTweakWidget.jsx diff --git a/packages/xod-client-electron/src/debugger/sendToSerialMiddleware.js b/packages/xod-client-electron/src/debugger/sendToSerialMiddleware.js index af5a6be6f..3aac53f2d 100644 --- a/packages/xod-client-electron/src/debugger/sendToSerialMiddleware.js +++ b/packages/xod-client-electron/src/debugger/sendToSerialMiddleware.js @@ -17,10 +17,10 @@ export default ({ getState }) => next => action => { ipcRenderer.send(DEBUG_SERIAL_SEND, action.payload); } - if ( - action.type === client.NODE_UPDATE_PROPERTY && - client.isSerialDebugRunning(state) - ) { + const isTweakActionType = + action.type === client.NODE_UPDATE_PROPERTY || + action.type === client.TWEAK_PULSE_SENT; + if (isTweakActionType && client.isSerialDebugRunning(state)) { const { id: nodeId, value, patchPath } = action.payload; const nodeType = R.compose( XP.getNodeType, diff --git a/packages/xod-client/src/core/styles/components/Inspector.scss b/packages/xod-client/src/core/styles/components/Inspector.scss index eb99212c9..c17d56c33 100644 --- a/packages/xod-client/src/core/styles/components/Inspector.scss +++ b/packages/xod-client/src/core/styles/components/Inspector.scss @@ -132,6 +132,12 @@ } } +.inspectorButton { + box-sizing: border-box; + line-height: 16px; + padding: 5px 4px; +} + .Widget { margin: 6px 0; overflow: hidden; @@ -215,6 +221,7 @@ .inspector-input-wrapper, .inspectorTextInput, + .inspectorButton, .inspectorSelectInput { float: right; width: 120px; diff --git a/packages/xod-client/src/debugger/sendToSimulationSerialMiddleware.js b/packages/xod-client/src/debugger/sendToSimulationSerialMiddleware.js index 4de8ad22f..7ccd33db0 100644 --- a/packages/xod-client/src/debugger/sendToSimulationSerialMiddleware.js +++ b/packages/xod-client/src/debugger/sendToSimulationSerialMiddleware.js @@ -10,12 +10,15 @@ import { import * as editorSelectors from '../editor/selectors'; import { NODE_UPDATE_PROPERTY } from '../project/actionTypes'; +import { TWEAK_PULSE_SENT } from '../editor/actionTypes'; export default ({ getState }) => next => action => { const state = getState(); const result = next(action); - if (action.type === NODE_UPDATE_PROPERTY && isSimulationRunning(state)) { + const isTweakActionType = + action.type === NODE_UPDATE_PROPERTY || action.type === TWEAK_PULSE_SENT; + if (isTweakActionType && isSimulationRunning(state)) { const { id: nodeId, value, patchPath } = action.payload; const nodeType = R.compose( XP.getNodeType, diff --git a/packages/xod-client/src/editor/actionTypes.js b/packages/xod-client/src/editor/actionTypes.js index 6ab748816..86304bba4 100644 --- a/packages/xod-client/src/editor/actionTypes.js +++ b/packages/xod-client/src/editor/actionTypes.js @@ -62,3 +62,5 @@ export const SIMULATION_COMPILED = 'SIMULATION_COMPILED'; export const SIMULATION_LAUNCHED = 'SIMULATION_LAUNCHED'; export const SIMULATION_ABORT = 'SIMULATION_ABORT'; export const SIMULATION_ERROR = 'SIMULATION_ERROR'; + +export const TWEAK_PULSE_SENT = 'TWEAK_PULSE_SENT'; diff --git a/packages/xod-client/src/editor/actions.js b/packages/xod-client/src/editor/actions.js index 144fbda79..6d5ee7a77 100644 --- a/packages/xod-client/src/editor/actions.js +++ b/packages/xod-client/src/editor/actions.js @@ -879,3 +879,15 @@ export const runSimulation = (simulationPatchPath, nodeIdsMap, code) => ( }); }); }; + +export const sendTweakPulse = tweakNodeId => (dispatch, getState) => { + Selectors.getCurrentPatchPath(getState()).map(patchPath => + dispatch({ + type: ActionType.TWEAK_PULSE_SENT, + payload: { + patchPath, + id: tweakNodeId, + }, + }) + ); +}; diff --git a/packages/xod-client/src/editor/components/Inspector.jsx b/packages/xod-client/src/editor/components/Inspector.jsx index 27dd06564..027021c09 100644 --- a/packages/xod-client/src/editor/components/Inspector.jsx +++ b/packages/xod-client/src/editor/components/Inspector.jsx @@ -49,11 +49,19 @@ const renderSelectedComment = () => ( ); const renderSelectedNode = R.curry( - (onPropUpdate, onNodeSpecializationChanged, selection) => ( + ( + onPropUpdate, + onNodeSpecializationChanged, + onSendTweakPulse, + isDebugSession, + selection + ) => ( ) ); @@ -97,9 +105,11 @@ const Inspector = ({ autohide, selection, currentPatch, + isDebugSession, onPropUpdate, onNodeSpecializationChanged, onPatchDescriptionUpdate, + onSendTweakPulse, }) => { const inspectorContent = R.cond([ [isMany, renderSelectedManyElements], @@ -107,7 +117,12 @@ const Inspector = ({ [isSingleComment, renderSelectedComment], [ isSingleNode, - renderSelectedNode(onPropUpdate, onNodeSpecializationChanged), + renderSelectedNode( + onPropUpdate, + onNodeSpecializationChanged, + onSendTweakPulse, + isDebugSession + ), ], [ isPatchSelected(currentPatch), @@ -134,9 +149,11 @@ Inspector.propTypes = { autohide: PropTypes.bool.isRequired, selection: sanctuaryPropType($.Array(RenderableSelection)), currentPatch: sanctuaryPropType($Maybe(Patch)), + isDebugSession: PropTypes.bool.isRequired, onPropUpdate: PropTypes.func.isRequired, onNodeSpecializationChanged: PropTypes.func.isRequired, onPatchDescriptionUpdate: PropTypes.func.isRequired, + onSendTweakPulse: PropTypes.func.isRequired, }; Inspector.defaultProps = { diff --git a/packages/xod-client/src/editor/components/NodeInspector.jsx b/packages/xod-client/src/editor/components/NodeInspector.jsx index 6becf8e26..40881e2be 100644 --- a/packages/xod-client/src/editor/components/NodeInspector.jsx +++ b/packages/xod-client/src/editor/components/NodeInspector.jsx @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import R from 'ramda'; import * as XP from 'xod-project'; import { WIDGET_TYPE } from '../constants'; @@ -10,6 +11,7 @@ import { Widget, HintWidget, NodeSpecializationWidget, + PulseTweakWidget, getNodeWidgetConfig, } from './inspectorWidgets'; @@ -19,7 +21,19 @@ import { getUtmSiteUrl } from '../../utils/urls'; import * as MESSAGES from '../messages'; -const NodeInspector = ({ node, onPropUpdate, onNodeSpecializationChanged }) => { +const isTweakPulseNode = R.compose( + nodeType => + XP.isTweakPath(nodeType) && XP.getTweakType(nodeType) === XP.PIN_TYPE.PULSE, + XP.getNodeType +); + +const NodeInspector = ({ + node, + isDebugSession, + onPropUpdate, + onNodeSpecializationChanged, + onSendTweakPulse, +}) => { const type = XP.getNodeType(node); const baseName = XP.getBaseName(type); const nodeId = XP.getNodeId(node); @@ -58,7 +72,16 @@ const NodeInspector = ({ node, onPropUpdate, onNodeSpecializationChanged }) => { {DeadNodeMessage} - +
    + {isDebugSession && isTweakPulseNode(node) ? ( + + ) : ( + + )} +
R.compose( - widgets =>
    {widgets}
, + widgets => {widgets}, R.map(renderablePin => { const widgetProps = R.applySpec({ entityId: R.prop('nodeId'), diff --git a/packages/xod-client/src/editor/components/inspectorWidgets/PulseTweakWidget.jsx b/packages/xod-client/src/editor/components/inspectorWidgets/PulseTweakWidget.jsx new file mode 100644 index 000000000..a66ea4594 --- /dev/null +++ b/packages/xod-client/src/editor/components/inspectorWidgets/PulseTweakWidget.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import PT from 'prop-types'; +import * as XP from 'xod-project'; + +import PinWidget from './pinWidgets/PinWidget'; + +class PulseTweakWidget extends React.Component { + constructor(props) { + super(props); + + this.handleClick = this.handleClick.bind(this); + } + + handleClick() { + this.props.onSendTweakPulse(this.props.nodeId); + } + + render() { + return ( +
  • + + + +
  • + ); + } +} + +PulseTweakWidget.propTypes = { + nodeId: PT.string.isRequired, + onSendTweakPulse: PT.func.isRequired, +}; + +export default PulseTweakWidget; diff --git a/packages/xod-client/src/editor/components/inspectorWidgets/index.js b/packages/xod-client/src/editor/components/inspectorWidgets/index.js index 24922c20c..2b950ee02 100644 --- a/packages/xod-client/src/editor/components/inspectorWidgets/index.js +++ b/packages/xod-client/src/editor/components/inspectorWidgets/index.js @@ -148,6 +148,7 @@ export { } from './pinWidgets/DisabledInputWidget'; export { default as DescriptionWidget } from './DescriptionWidget'; export { default as LabelWidget } from './LabelWidget'; +export { default as PulseTweakWidget } from './PulseTweakWidget'; export { default as NodeSpecializationWidget, } from './NodeSpecializationWidget'; diff --git a/packages/xod-client/src/editor/components/inspectorWidgets/pinWidgets/PinWidget.jsx b/packages/xod-client/src/editor/components/inspectorWidgets/pinWidgets/PinWidget.jsx index c8903b2a9..7274bb140 100644 --- a/packages/xod-client/src/editor/components/inspectorWidgets/pinWidgets/PinWidget.jsx +++ b/packages/xod-client/src/editor/components/inspectorWidgets/pinWidgets/PinWidget.jsx @@ -80,6 +80,7 @@ PinWidget.propTypes = { PinWidget.defaultProps = { children: null, + isLastVariadicGroup: false, }; export default PinWidget; diff --git a/packages/xod-client/src/editor/containers/Sidebar.jsx b/packages/xod-client/src/editor/containers/Sidebar.jsx index a783d28c7..e52f45687 100644 --- a/packages/xod-client/src/editor/containers/Sidebar.jsx +++ b/packages/xod-client/src/editor/containers/Sidebar.jsx @@ -22,6 +22,7 @@ import * as EditorSelectors from '../selectors'; import * as ProjectActions from '../../project/actions'; import * as ProjectSelectors from '../../project/selectors'; import * as UserSelectors from '../../user/selectors'; +import * as DebuggerSelectors from '../../debugger/selectors'; import { RenderableSelection } from '../../types'; import sanctuaryPropType from '../../utils/sanctuaryPropType'; import { SIDEBAR_IDS, PANEL_IDS, FOCUS_AREAS } from '../constants'; @@ -147,6 +148,8 @@ class Sidebar extends React.Component { this.props.actions.changeNodeSpecialization } onPatchDescriptionUpdate={this.props.actions.updatePatchDescription} + onSendTweakPulse={this.props.actions.sendTweakPulse} + isDebugSession={this.props.isDebugSession} /> ); @@ -237,6 +240,7 @@ Sidebar.propTypes = { windowSize: PropTypes.object.isRequired, selection: sanctuaryPropType($.Array(RenderableSelection)), currentPatch: sanctuaryPropType($Maybe(XP.Patch)), + isDebugSession: PropTypes.bool.isRequired, panels: PropTypes.objectOf( PropTypes.shape({ /* eslint-disable react/no-unused-prop-types */ @@ -253,6 +257,7 @@ Sidebar.propTypes = { resizePanels: PropTypes.func.isRequired, togglePanel: PropTypes.func.isRequired, setFocusedArea: PropTypes.func.isRequired, + sendTweakPulse: PropTypes.func.isRequired, }), userAuthorised: PropTypes.bool.isRequired, }; @@ -262,6 +267,7 @@ const mapStateToProps = R.applySpec({ currentPatch: ProjectSelectors.getCurrentPatch, panels: EditorSelectors.getAllPanelsSettings, userAuthorised: UserSelectors.isAuthorized, + isDebugSession: DebuggerSelectors.isDebugSession, }); const mapDispatchToProps = dispatch => ({ actions: bindActionCreators( @@ -272,6 +278,7 @@ const mapDispatchToProps = dispatch => ({ resizePanels: EditorActions.resizePanels, togglePanel: EditorActions.togglePanel, setFocusedArea: EditorActions.setFocusedArea, + sendTweakPulse: EditorActions.sendTweakPulse, }, dispatch ), diff --git a/packages/xod-client/src/index.js b/packages/xod-client/src/index.js index b0eec5dd0..3a98a2a69 100644 --- a/packages/xod-client/src/index.js +++ b/packages/xod-client/src/index.js @@ -26,7 +26,11 @@ import { import { LOG_TAB_TYPE } from './debugger/constants'; import { MESSAGE_BUTTON_CLICKED } from './messages/actionTypes'; -import { TAB_CLOSE, INSTALL_LIBRARIES_COMPLETE } from './editor/actionTypes'; +import { + TAB_CLOSE, + INSTALL_LIBRARIES_COMPLETE, + TWEAK_PULSE_SENT, +} from './editor/actionTypes'; import { SAVE_ALL, NODE_UPDATE_PROPERTY } from './project/actionTypes'; import * as EditorConstants from './editor/constants'; @@ -84,7 +88,11 @@ export { LOG_TAB_TYPE } from './debugger/constants'; export { MESSAGE_BUTTON_CLICKED } from './messages/actionTypes'; export { TAB_CLOSE, INSTALL_LIBRARIES_COMPLETE } from './editor/actionTypes'; -export { SAVE_ALL, NODE_UPDATE_PROPERTY } from './project/actionTypes'; +export { + SAVE_ALL, + NODE_UPDATE_PROPERTY, + TWEAK_PULSE_SENT, +} from './project/actionTypes'; export { SERIAL_SESSION_STARTED, LINE_SENT_TO_SERIAL, @@ -172,6 +180,7 @@ export default Object.assign( TAB_CLOSE, SAVE_ALL, NODE_UPDATE_PROPERTY, + TWEAK_PULSE_SENT, INSTALL_LIBRARIES_COMPLETE, MESSAGE_BUTTON_CLICKED, Messages: coreMessages, diff --git a/packages/xod-client/src/project/components/nodeParts/ConstantNodeBody.jsx b/packages/xod-client/src/project/components/nodeParts/ConstantNodeBody.jsx index af9b8e756..9448fbd06 100644 --- a/packages/xod-client/src/project/components/nodeParts/ConstantNodeBody.jsx +++ b/packages/xod-client/src/project/components/nodeParts/ConstantNodeBody.jsx @@ -7,7 +7,16 @@ import { noop } from 'xod-func-tools'; import RegularNodeBody from './RegularNodeBody'; export const getConstantValue = ({ pins }) => - R.compose(R.prop('value'), R.head, R.values)(pins); + R.compose( + R.ifElse( + // because for pulse nodes value will always be 'Never' + R.pipe(XP.getPinType, R.equals(XP.PIN_TYPE.PULSE)), + R.always(null), + R.prop('value') + ), + R.head, + R.values + )(pins); const ConstantNodeBody = props => (