From 554e59134377b670d896659977d9d3c9c4f5aa44 Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum <eric.rosenbaum@gmail.com> Date: Thu, 14 Jun 2018 15:20:20 -0400 Subject: [PATCH] wip --- .../connection-modal/connected-step.jsx | 29 ++++++++++ .../connection-modal/connecting-step.jsx | 29 ++++++++++ .../connection-modal/connection-modal.css | 45 ++------------ .../connection-modal/connection-modal.jsx | 29 +++++----- .../connection-modal/error-step.jsx | 29 ++++++++++ .../connection-modal/scanning-step.jsx | 58 +++++++++++++++++++ src/components/modal/modal.jsx | 3 +- src/containers/blocks.jsx | 41 +++++++++---- src/containers/connection-modal.jsx | 16 ++++- src/containers/scanning-step.jsx | 42 ++++++++++++++ src/lib/libraries/extensions/index.jsx | 6 +- 11 files changed, 255 insertions(+), 72 deletions(-) create mode 100644 src/components/connection-modal/connected-step.jsx create mode 100644 src/components/connection-modal/connecting-step.jsx create mode 100644 src/components/connection-modal/error-step.jsx create mode 100644 src/components/connection-modal/scanning-step.jsx create mode 100644 src/containers/scanning-step.jsx diff --git a/src/components/connection-modal/connected-step.jsx b/src/components/connection-modal/connected-step.jsx new file mode 100644 index 000000000..03a70235e --- /dev/null +++ b/src/components/connection-modal/connected-step.jsx @@ -0,0 +1,29 @@ +import {FormattedMessage} from 'react-intl'; +import PropTypes from 'prop-types'; +import React from 'react'; + +import Box from '../box/box.jsx'; + +import styles from './connection-modal.css'; + +const ConnectedStep = props => ( + <Box className={styles.body}> + <Box className={styles.buttonRow}> + <button + className={styles.searchButton} + onClick={props.onSearch} + > + <FormattedMessage + defaultMessage="connected" + description="Button in prompt for starting a search" + id="gui.connection.search" + /> + </button> + </Box> + </Box> +); + +ConnectedStep.propTypes = { +}; + +export default ConnectedStep; diff --git a/src/components/connection-modal/connecting-step.jsx b/src/components/connection-modal/connecting-step.jsx new file mode 100644 index 000000000..b2b30cffb --- /dev/null +++ b/src/components/connection-modal/connecting-step.jsx @@ -0,0 +1,29 @@ +import {FormattedMessage} from 'react-intl'; +import PropTypes from 'prop-types'; +import React from 'react'; + +import Box from '../box/box.jsx'; + +import styles from './connection-modal.css'; + +const ConnectingStep = props => ( + <Box className={styles.body}> + <Box className={styles.buttonRow}> + <button + className={styles.searchButton} + onClick={props.onSearch} + > + <FormattedMessage + defaultMessage="connecting" + description="Button in prompt for starting a search" + id="gui.connection.search" + /> + </button> + </Box> + </Box> +); + +ConnectingStep.propTypes = { +}; + +export default ConnectingStep; diff --git a/src/components/connection-modal/connection-modal.css b/src/components/connection-modal/connection-modal.css index 34a8f5a21..d403af910 100644 --- a/src/components/connection-modal/connection-modal.css +++ b/src/components/connection-modal/connection-modal.css @@ -5,6 +5,10 @@ width: 360px; } +.header { + background-color: $pen-primary; +} + .body { background: $ui-white; padding: 1.5rem 2.25rem; @@ -15,17 +19,6 @@ margin: 0 0 0.75rem; } -.input { - margin-bottom: 1.5rem; - width: 100%; - border: 1px solid $ui-black-transparent; - border-radius: 5px; - padding: 0 1rem; - height: 3rem; - color: $text-primary-transparent; - font-size: .875rem; -} - .button-row { font-weight: bolder; text-align: right; @@ -49,33 +42,3 @@ .button-row button + button { margin-left: 0.5rem; } - -.more-options { - border-top: 1px dashed hsla(0, 0%, 0%, .25); - overflow: visible; - padding: 1rem; - text-align: center; - margin: 0 0 1rem; -} - -.hide-more-options { - display: none; -} - -.more-options-accordion { - width: 60%; - margin: 0 auto; -} - -.more-options-text { - opacity: .5; -} - -.more-options-icon { - width: .75rem; - height: .75rem; - margin-left: .5rem; - vertical-align: middle; - padding-bottom: .2rem; - opacity: .5; -} diff --git a/src/components/connection-modal/connection-modal.jsx b/src/components/connection-modal/connection-modal.jsx index e9ce818e8..73699b937 100644 --- a/src/components/connection-modal/connection-modal.jsx +++ b/src/components/connection-modal/connection-modal.jsx @@ -1,37 +1,40 @@ -import {FormattedMessage} from 'react-intl'; import PropTypes from 'prop-types'; import React from 'react'; import Box from '../box/box.jsx'; import Modal from '../modal/modal.jsx'; +import ScanningStep from '../../containers/scanning-step.jsx'; +import ConnectingStep from './connecting-step.jsx'; +import ConnectedStep from './connected-step.jsx'; +import ErrorStep from './error-step.jsx'; + import styles from './connection-modal.css'; +const phases = { + scanning: ScanningStep, + connecting: ConnectingStep, + connected: ConnectedStep, + error: ErrorStep +}; + const ConnectionModalComponent = props => ( <Modal className={styles.modalContent} contentLabel={props.title} + headerClassName={styles.header} onRequestClose={props.onCancel} > <Box className={styles.body}> - <Box className={styles.buttonRow}> - <button - className={styles.cancelButton} - onClick={props.onCancel} - > - <FormattedMessage - defaultMessage="cancel" - description="Button in prompt for cancelling the dialog" - id="gui.prompt.cancel" - /> - </button> - </Box> + {React.createElement(phases[props.phase], props)} </Box> </Modal> ); ConnectionModalComponent.propTypes = { onCancel: PropTypes.func.isRequired, + onSearch: PropTypes.func.isRequired, + phase: PropTypes.string.isRequired, title: PropTypes.string.isRequired }; diff --git a/src/components/connection-modal/error-step.jsx b/src/components/connection-modal/error-step.jsx new file mode 100644 index 000000000..451c7ab37 --- /dev/null +++ b/src/components/connection-modal/error-step.jsx @@ -0,0 +1,29 @@ +import {FormattedMessage} from 'react-intl'; +import PropTypes from 'prop-types'; +import React from 'react'; + +import Box from '../box/box.jsx'; + +import styles from './connection-modal.css'; + +const ErrorStep = props => ( + <Box className={styles.body}> + <Box className={styles.buttonRow}> + <button + className={styles.searchButton} + onClick={props.onSearch} + > + <FormattedMessage + defaultMessage="error" + description="Button in prompt for starting a search" + id="gui.connection.search" + /> + </button> + </Box> + </Box> +); + +ErrorStep.propTypes = { +}; + +export default ErrorStep; diff --git a/src/components/connection-modal/scanning-step.jsx b/src/components/connection-modal/scanning-step.jsx new file mode 100644 index 000000000..c5fc4bbe6 --- /dev/null +++ b/src/components/connection-modal/scanning-step.jsx @@ -0,0 +1,58 @@ +import {FormattedMessage} from 'react-intl'; +import PropTypes from 'prop-types'; +import React from 'react'; + +import Box from '../box/box.jsx'; + +import styles from './connection-modal.css'; + +const ScanningStep = props => ( + <Box className={styles.body}> + <Box className={styles.activityArea}> + {props.searching ? ( + props.devices.length === 0 ? ( + <div>search icon here</div> + ) : ( + props.devices.map(device => ( + <div>{device.name}</div> + )) + ) + ) : ( + <div>No devices found, click on this hyperlink right now</div> + )} + </Box> + <Box className={styles.instructions}> + <FormattedMessage + defaultMessage="Select your device in the list above." + description="" + id="gui.connection.scanning.instructions" + /> + </Box> + <Box className={styles.buttonRow}> + <button + className={styles.searchButton} + onClick={props.onSearch} + > + <FormattedMessage + defaultMessage="scanning" + description="Button in prompt for starting a search" + id="gui.connection.search" + /> + </button> + </Box> + </Box> +); + +ScanningStep.propTypes = { + devices: PropTypes.arrayOf(PropTypes.shape({ + name: PropTypes.string + })), + searching: PropTypes.bool.isRequired +}; + +ScanningStep.defaultProps = { + devices: [], + searching: true +}; + +export default ScanningStep; diff --git a/src/components/modal/modal.jsx b/src/components/modal/modal.jsx index dff3ce853..631e77261 100644 --- a/src/components/modal/modal.jsx +++ b/src/components/modal/modal.jsx @@ -26,7 +26,7 @@ const ModalComponent = props => ( direction="column" grow={1} > - <div className={styles.header}> + <div className={classNames(styles.header, props.headerClassName)}> <div className={classNames( styles.headerItem, @@ -74,6 +74,7 @@ ModalComponent.propTypes = { PropTypes.object ]).isRequired, fullScreen: PropTypes.bool, + headerClassName: PropTypes.string, onRequestClose: PropTypes.func }; diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx index 13d87d9d4..30c7dd9e4 100644 --- a/src/containers/blocks.jsx +++ b/src/containers/blocks.jsx @@ -39,6 +39,8 @@ class Blocks extends React.Component { 'attachVM', 'detachVM', 'handleCategorySelected', + 'handleConnectionModalStart', + 'handleConnectionModalClose', 'handlePromptStart', 'handlePromptCallback', 'handlePromptClose', @@ -57,12 +59,16 @@ class Blocks extends React.Component { 'setLocale' ]); this.ScratchBlocks.prompt = this.handlePromptStart; + this.ScratchBlocks.statusButtonCallback = this.handleConnectionModalStart; this.state = { workspaceMetrics: {}, - prompt: null + prompt: null, + connectionModal: null }; this.onTargetsUpdate = debounce(this.onTargetsUpdate, 100); this.toolboxUpdateQueue = []; + + this.state.connectionModal = true; } componentDidMount () { this.ScratchBlocks.FieldColourSlider.activateEyedropper_ = this.props.onActivateColorPicker; @@ -95,6 +101,7 @@ class Blocks extends React.Component { shouldComponentUpdate (nextProps, nextState) { return ( this.state.prompt !== nextState.prompt || + this.state.connectionModal !== nextState.connectionModal || this.props.isVisible !== nextProps.isVisible || this.props.toolboxXML !== nextProps.toolboxXML || this.props.extensionLibraryVisible !== nextProps.extensionLibraryVisible || @@ -327,6 +334,15 @@ class Blocks extends React.Component { optVarType !== this.ScratchBlocks.BROADCAST_MESSAGE_VARIABLE_TYPE; this.setState(p); } + handleConnectionModalStart (extensionId) { + const c = {connectionModal: { + id: extensionId + }}; + this.setState(c); + } + handleConnectionModalClose () { + this.setState({connectionModal: null}); + } handlePromptCallback (data) { this.state.prompt.callback(data); this.handlePromptClose(); @@ -366,17 +382,20 @@ class Blocks extends React.Component { {...props} /> {this.state.prompt ? ( - // <Prompt - // label={this.state.prompt.message} - // placeholder={this.state.prompt.defaultValue} - // showMoreOptions={this.state.prompt.showMoreOptions} - // title={this.state.prompt.title} - // onCancel={this.handlePromptClose} - // onOk={this.handlePromptCallback} - // /> - <ConnectionModal - title={'OMG a modal 😲 🔥 💯'} + <Prompt + label={this.state.prompt.message} + placeholder={this.state.prompt.defaultValue} + showMoreOptions={this.state.prompt.showMoreOptions} + title={this.state.prompt.title} onCancel={this.handlePromptClose} + onOk={this.handlePromptCallback} + /> + ) : null} + {this.state.connectionModal ? ( + <ConnectionModal + id={this.state.connectionModal.id} + vm={vm} + onCancel={this.handleConnectionModalClose} /> ) : null} {extensionLibraryVisible ? ( diff --git a/src/containers/connection-modal.jsx b/src/containers/connection-modal.jsx index 460db8f96..0860b50b6 100644 --- a/src/containers/connection-modal.jsx +++ b/src/containers/connection-modal.jsx @@ -7,25 +7,35 @@ class ConnectionModal extends React.Component { constructor (props) { super(props); bindAll(this, [ - 'handleCancel' + 'handleCancel', + 'handleSearch' ]); + this.state = { + phase: 'scanning' + }; } handleCancel () { this.props.onCancel(); } + handleSearch () { + this.props.onSearch(); + } render () { return ( <ConnectionModalComponent - title={this.props.title} + title={this.props.id} onCancel={this.handleCancel} + onSearch={this.handleSearch} + phase={this.state.phase} /> ); } } ConnectionModal.propTypes = { + id: PropTypes.string.isRequired, onCancel: PropTypes.func.isRequired, - title: PropTypes.string.isRequired + onSearch: PropTypes.func.isRequired }; export default ConnectionModal; diff --git a/src/containers/scanning-step.jsx b/src/containers/scanning-step.jsx new file mode 100644 index 000000000..44d0c5781 --- /dev/null +++ b/src/containers/scanning-step.jsx @@ -0,0 +1,42 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import bindAll from 'lodash.bindall'; +import ScanningStepComponent from '../components/connection-modal/scanning-step.jsx'; + +class ScanningStep extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleCancel', + 'handleSearch' + ]); + this.state = { + searching: true, + devices: [] + }; + } + handleCancel () { + this.props.onCancel(); + } + handleSearch () { + this.props.onSearch(); + } + render () { + return ( + <ScanningStepComponent + title={this.props.id} + onCancel={this.handleCancel} + onSearch={this.handleSearch} + phase={this.state.phase} + /> + ); + } +} + +ScanningStep.propTypes = { + id: PropTypes.string.isRequired, + onCancel: PropTypes.func.isRequired, + onSearch: PropTypes.func.isRequired +}; + +export default ScanningStep; diff --git a/src/lib/libraries/extensions/index.jsx b/src/lib/libraries/extensions/index.jsx index 71404f8fb..82b5e67d9 100644 --- a/src/lib/libraries/extensions/index.jsx +++ b/src/lib/libraries/extensions/index.jsx @@ -120,7 +120,7 @@ export default [ /> ), featured: true, - disabled: true + disabled: false }, { name: 'LEGO WeDo 2.0', @@ -134,7 +134,7 @@ export default [ /> ), featured: true, - disabled: true + disabled: false }, { name: 'LEGO MINDSTORMS EV3', @@ -148,7 +148,7 @@ export default [ /> ), featured: true, - disabled: true + disabled: false }, { name: 'LEGO Boost', -- GitLab