Merge pull request #1916 from LLK/revert-1888-revert-1887-revert-preview-update
Revert "Bring back "Updates to preview modal for release""
This commit is contained in:
10 files changed
+561
-45
No files matched your search
@@ -19,6 +19,7 @@ import Box from '../box/box.jsx';
|
||||
import MenuBar from '../menu-bar/menu-bar.jsx';
|
||||
|
||||
import PreviewModal from '../../containers/preview-modal.jsx';
|
||||
import ImportModal from '../../containers/import-modal.jsx';
|
||||
import WebGlModal from '../../containers/webgl-modal.jsx';
|
||||
import TipsLibrary from '../../containers/tips-library.jsx';
|
||||
import Cards from '../../containers/cards.jsx';
|
||||
@@ -50,6 +51,7 @@ const GUIComponent = props => {
|
||||
cardsVisible,
|
||||
children,
|
||||
costumesTabVisible,
|
||||
importInfoVisible,
|
||||
intl,
|
||||
loading,
|
||||
onExtensionButtonClick,
|
||||
@@ -93,6 +95,9 @@ const GUIComponent = props => {
|
||||
{loading ? (
|
||||
<Loader />
|
||||
) : null}
|
||||
{importInfoVisible ? (
|
||||
<ImportModal />
|
||||
) : null}
|
||||
{isRendererSupported ? null : (
|
||||
<WebGlModal />
|
||||
)}
|
||||
@@ -225,6 +230,7 @@ GUIComponent.propTypes = {
|
||||
cardsVisible: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
costumesTabVisible: PropTypes.bool,
|
||||
importInfoVisible: PropTypes.bool,
|
||||
intl: intlShape.isRequired,
|
||||
loading: PropTypes.bool,
|
||||
onActivateCostumesTab: PropTypes.func,
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
@import "../../css/colors.css";
|
||||
@import "../../css/units.css";
|
||||
@import "../../css/typography.css";
|
||||
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
background-color: $ui-modal-overlay;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
margin: 100px auto;
|
||||
outline: none;
|
||||
border: .25rem solid $ui-white-transparent;
|
||||
padding: 0;
|
||||
border-radius: $space;
|
||||
user-select: none;
|
||||
width: 500px;
|
||||
color: $text-primary;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO figure out how to remove filter altogether
|
||||
since it is null...
|
||||
Modal header has 3 items:
|
||||
|x title filter|
|
||||
|
||||
Use the same width for both side item containers,
|
||||
so that title remains centered
|
||||
*/
|
||||
$sides: 20rem;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
height: $library-header-height;
|
||||
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
background-color: $pen-primary;
|
||||
}
|
||||
|
||||
.header-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.header-item-filter {
|
||||
display: flex;
|
||||
flex-basis: $sides;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.header-item-title {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
user-select: none;
|
||||
letter-spacing: 0.4px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.header-item-title h2 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.header-item-close {
|
||||
display: flex;
|
||||
flex-basis: $sides;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.body {
|
||||
background: $ui-white;
|
||||
padding: 1.5rem 2.25rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
margin: 1.5rem 0;
|
||||
font-weight: bolder;
|
||||
text-align: right;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border: 1px solid;
|
||||
border-radius: 0.25rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ok-input-container {
|
||||
border-color: $motion-primary;
|
||||
box-shadow: 0 0 0 0.2rem $motion-transparent;
|
||||
}
|
||||
|
||||
.bad-input-container {
|
||||
border-color: $data-primary;
|
||||
box-shadow: 0 0 0 0.2rem hsla(30, 100%, 55%, 0.15);
|
||||
}
|
||||
|
||||
.input-row input {
|
||||
width: 100%;
|
||||
padding: 0 1rem;
|
||||
height: 3rem;
|
||||
color: $text-primary;
|
||||
font-size: .875rem;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.input-row input::placeholder {
|
||||
font-style: italic;
|
||||
color: $text-primary-transparent;
|
||||
}
|
||||
|
||||
.input-row button {
|
||||
padding: 0.5rem 2rem;
|
||||
font-weight: bold;
|
||||
font-size: .875rem;
|
||||
cursor: pointer;
|
||||
border: 0px solid $pen-primary;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.input-row button.ok-button {
|
||||
background: $pen-primary;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.error-row {
|
||||
margin: 1.5rem 0;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background: hsla(30, 100%, 55%, 0.25);
|
||||
color: $data-primary;
|
||||
border: 1px solid $data-primary;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.error-row p {
|
||||
font-size: 0.875rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Confirmation buttons at the bottom of the modal */
|
||||
.button-row {
|
||||
margin: 1.5rem 0;
|
||||
font-weight: bolder;
|
||||
text-align: right;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.button-row button {
|
||||
border: 1px solid $motion-primary;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.5rem 1.5rem;
|
||||
background: white;
|
||||
font-weight: bold;
|
||||
font-size: .875rem;
|
||||
cursor: pointer;
|
||||
color: $motion-primary;
|
||||
}
|
||||
|
||||
.faq-link-text {
|
||||
margin: 2rem 0 .5rem 0;
|
||||
font-size: .875rem;
|
||||
color: $text-primary;
|
||||
}
|
||||
|
||||
.faq-link {
|
||||
color: $motion-primary;
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ReactModal from 'react-modal';
|
||||
import Box from '../box/box.jsx';
|
||||
import {defineMessages, injectIntl, intlShape, FormattedMessage} from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import CloseButton from '../close-button/close-button.jsx';
|
||||
|
||||
import styles from './import-modal.css';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'gui.importInfo.title',
|
||||
defaultMessage: 'View a Scratch 2.0 Project',
|
||||
description: 'Scratch 2.0 import modal label - for accessibility'
|
||||
},
|
||||
formDescription: {
|
||||
defaultMessage:
|
||||
'Enter a link to one of your shared Scratch projects. Changes made in this 3.0 Preview will not be saved.',
|
||||
description: 'Import project message',
|
||||
id: 'gui.importInfo.message'
|
||||
},
|
||||
invalidFormatError: {
|
||||
id: 'gui.importInfo.invalidFormatError',
|
||||
defaultMessage: 'Uh oh, that project link or id doesn\'t look quite right.',
|
||||
description: 'Invalid project link or id message'
|
||||
}
|
||||
});
|
||||
|
||||
const ImportModal = ({intl, ...props}) => (
|
||||
<ReactModal
|
||||
isOpen
|
||||
className={styles.modalContent}
|
||||
contentLabel={intl.formatMessage({...messages.title})}
|
||||
overlayClassName={styles.modalOverlay}
|
||||
onRequestClose={props.onCancel}
|
||||
>
|
||||
<Box>
|
||||
<div className={styles.header}>
|
||||
<div
|
||||
className={classNames(
|
||||
styles.headerItem,
|
||||
styles.headerItemClose
|
||||
)}
|
||||
>
|
||||
<CloseButton
|
||||
buttonType="back"
|
||||
size={CloseButton.SIZE_LARGE}
|
||||
onClick={props.onGoBack}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
styles.headerItem,
|
||||
styles.headerItemTitle
|
||||
)}
|
||||
>
|
||||
<h2>
|
||||
{intl.formatMessage({...messages.title})}
|
||||
</h2>
|
||||
</div>
|
||||
<div className={classNames(styles.headerItem, styles.headerItemFilter)}>
|
||||
{null}
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
|
||||
<Box className={styles.body}>
|
||||
<p>
|
||||
{intl.formatMessage({...messages.formDescription})}
|
||||
</p>
|
||||
<Box
|
||||
className={classNames(styles.inputRow,
|
||||
(props.hasValidationError ? styles.badInputContainer : styles.okInputContainer))
|
||||
}
|
||||
>
|
||||
<input
|
||||
autoFocus
|
||||
placeholder={props.placeholder}
|
||||
value={props.inputValue}
|
||||
onChange={props.onChange}
|
||||
onKeyPress={props.onKeyPress}
|
||||
/>
|
||||
<button
|
||||
className={styles.okButton}
|
||||
title="viewproject"
|
||||
onClick={props.onViewProject}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View"
|
||||
description="Label for button to load a scratch 2.0 project"
|
||||
id="gui.importModal.viewproject"
|
||||
/>
|
||||
</button>
|
||||
</Box>
|
||||
{props.hasValidationError ?
|
||||
<Box className={styles.errorRow}>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
{...messages[`${props.errorMessage}`]}
|
||||
/>
|
||||
</p>
|
||||
</Box> : null
|
||||
}
|
||||
<Box className={styles.buttonRow}>
|
||||
<button
|
||||
onClick={props.onGoBack}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Go Back"
|
||||
description="Label for button to back out of importing a project"
|
||||
id="gui.importInfo.goback"
|
||||
/>
|
||||
</button>
|
||||
</Box>
|
||||
<Box className={styles.faqLinkText}>
|
||||
<FormattedMessage
|
||||
defaultMessage="To learn more, go to the {previewFaqLink}."
|
||||
description="Invitation to try 3.0 preview"
|
||||
id="gui.importInfo.previewfaq"
|
||||
values={{
|
||||
previewFaqLink: (
|
||||
<a
|
||||
className={styles.faqLink}
|
||||
href="//scratch.mit.edu/preview-faq"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Preview FAQ"
|
||||
description="link to Scratch 3.0 preview FAQ page"
|
||||
id="gui.importInfo.previewfaqlink"
|
||||
/>
|
||||
</a>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</ReactModal>
|
||||
);
|
||||
|
||||
ImportModal.propTypes = {
|
||||
errorMessage: PropTypes.string.isRequired,
|
||||
hasValidationError: PropTypes.bool.isRequired,
|
||||
inputValue: PropTypes.string.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
onCancel: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onGoBack: PropTypes.func.isRequired,
|
||||
onKeyPress: PropTypes.func.isRequired,
|
||||
onViewProject: PropTypes.func.isRequired,
|
||||
placeholder: PropTypes.string
|
||||
};
|
||||
|
||||
export default injectIntl(ImportModal);
|
||||
@@ -39,12 +39,6 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.disclaimer {
|
||||
margin-top: 2.0rem;
|
||||
border-top: 1px solid $text-primary;
|
||||
padding-top: 1.0rem;
|
||||
}
|
||||
|
||||
/* Confirmation buttons at the bottom of the modal */
|
||||
.button-row {
|
||||
margin: 1.5rem 0;
|
||||
@@ -73,6 +67,12 @@
|
||||
color: $motion-primary;
|
||||
}
|
||||
|
||||
.button-row button.view-project-button {
|
||||
background: $pen-primary;
|
||||
border-color: $pen-primary;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.button-row button + button {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -35,45 +35,12 @@ const PreviewModal = ({intl, ...props}) => (
|
||||
</h2>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="We're excited for you to try the next generation of Scratch!
|
||||
To learn more, go to the {previewFaqLink}."
|
||||
defaultMessage="We're working on the next generation of Scratch. We're excited for you to try it!"
|
||||
description="Invitation to try 3.0 preview"
|
||||
id="gui.previewInfo.previewfaq"
|
||||
values={{
|
||||
previewFaqLink: (
|
||||
<a
|
||||
className={styles.faqLink}
|
||||
href="//scratch.mit.edu/preview-faq"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Preview FAQ"
|
||||
description="link to Scratch 3.0 preview FAQ page"
|
||||
id="gui.previewInfo.previewfaqlink"
|
||||
/>
|
||||
</a>
|
||||
)
|
||||
}}
|
||||
id="gui.previewInfo.invitation"
|
||||
/>
|
||||
</p>
|
||||
|
||||
<Box className={styles.disclaimer}>
|
||||
<p>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
defaultMessage="Changes to projects will not be saved."
|
||||
description="Disclaimer for 3.0 preview"
|
||||
id="gui.previewInfo.disclaimer"
|
||||
/>
|
||||
<br />
|
||||
<FormattedMessage
|
||||
defaultMessage="This feature is coming soon!"
|
||||
description="Notice that a feature is in progress"
|
||||
id="gui.previewInfo.comingsoon"
|
||||
/>
|
||||
</strong>
|
||||
</p>
|
||||
</Box>
|
||||
|
||||
<Box className={styles.buttonRow}>
|
||||
<button
|
||||
className={styles.noButton}
|
||||
@@ -104,6 +71,38 @@ const PreviewModal = ({intl, ...props}) => (
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
className={styles.viewProjectButton}
|
||||
title="viewproject"
|
||||
onClick={props.onViewProject}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View 2.0 Project"
|
||||
description="Label for button to import a 2.0 project"
|
||||
id="gui.previewModal.viewproject"
|
||||
/>
|
||||
</button>
|
||||
</Box>
|
||||
<Box className={styles.faqLinkText}>
|
||||
<FormattedMessage
|
||||
defaultMessage="To learn more, go to the {previewFaqLink}."
|
||||
description="Invitation to try 3.0 preview"
|
||||
id="gui.previewInfo.previewfaq"
|
||||
values={{
|
||||
previewFaqLink: (
|
||||
<a
|
||||
className={styles.faqLink}
|
||||
href="//scratch.mit.edu/preview-faq"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Preview FAQ"
|
||||
description="link to Scratch 3.0 preview FAQ page"
|
||||
id="gui.previewInfo.previewfaqlink"
|
||||
/>
|
||||
</a>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</ReactModal>
|
||||
@@ -112,7 +111,8 @@ const PreviewModal = ({intl, ...props}) => (
|
||||
PreviewModal.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
onCancel: PropTypes.func.isRequired,
|
||||
onTryIt: PropTypes.func.isRequired
|
||||
onTryIt: PropTypes.func.isRequired,
|
||||
onViewProject: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(PreviewModal);
|
||||
@@ -86,6 +86,7 @@ class GUI extends React.Component {
|
||||
GUI.propTypes = {
|
||||
...GUIComponent.propTypes,
|
||||
fetchingProject: PropTypes.bool,
|
||||
importInfoVisible: PropTypes.bool,
|
||||
loadingStateVisible: PropTypes.bool,
|
||||
previewInfoVisible: PropTypes.bool,
|
||||
projectData: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
|
||||
@@ -99,6 +100,7 @@ const mapStateToProps = state => ({
|
||||
blocksTabVisible: state.editorTab.activeTabIndex === BLOCKS_TAB_INDEX,
|
||||
cardsVisible: state.cards.visible,
|
||||
costumesTabVisible: state.editorTab.activeTabIndex === COSTUMES_TAB_INDEX,
|
||||
importInfoVisible: state.modals.importInfo,
|
||||
loadingStateVisible: state.modals.loadingProject,
|
||||
previewInfoVisible: state.modals.previewInfo,
|
||||
soundsTabVisible: state.editorTab.activeTabIndex === SOUNDS_TAB_INDEX,
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import bindAll from 'lodash.bindall';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import ImportModalComponent from '../components/import-modal/import-modal.jsx';
|
||||
|
||||
import {
|
||||
closeImportInfo,
|
||||
openPreviewInfo
|
||||
} from '../reducers/modals';
|
||||
|
||||
class ImportModal extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
bindAll(this, [
|
||||
'handleViewProject',
|
||||
'handleCancel',
|
||||
'handleChange',
|
||||
'handleGoBack',
|
||||
'handleKeyPress'
|
||||
]);
|
||||
|
||||
this.state = {
|
||||
inputValue: '',
|
||||
hasValidationError: false,
|
||||
errorMessage: ''
|
||||
};
|
||||
}
|
||||
handleKeyPress (event) {
|
||||
if (event.key === 'Enter') this.handleViewProject();
|
||||
}
|
||||
handleViewProject () {
|
||||
const inputValue = this.state.inputValue;
|
||||
const projectId = this.validate(inputValue);
|
||||
|
||||
if (projectId) {
|
||||
const projectLink = document.createElement('a');
|
||||
document.body.appendChild(projectLink);
|
||||
projectLink.href = `#${projectId}`;
|
||||
projectLink.click();
|
||||
document.body.removeChild(projectLink);
|
||||
this.props.onViewProject();
|
||||
} else {
|
||||
this.setState({
|
||||
hasValidationError: true,
|
||||
errorMessage: `invalidFormatError`});
|
||||
}
|
||||
}
|
||||
handleChange (e) {
|
||||
this.setState({inputValue: e.target.value, hasValidationError: false});
|
||||
}
|
||||
validate (input) {
|
||||
const urlMatches = input.match(/^(?:https?:\/\/)?scratch\.mit\.edu\/projects\/(\d+)/);
|
||||
if (urlMatches && urlMatches.length > 0) {
|
||||
return urlMatches[1];
|
||||
}
|
||||
const projectIdMatches = input.match(/^#?(\d+)$/);
|
||||
if (projectIdMatches && projectIdMatches.length > 0) {
|
||||
return projectIdMatches[1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
handleCancel () {
|
||||
this.props.onCancel();
|
||||
}
|
||||
handleGoBack () {
|
||||
this.props.onBack();
|
||||
}
|
||||
render () {
|
||||
return (
|
||||
<ImportModalComponent
|
||||
errorMessage={this.state.errorMessage}
|
||||
hasValidationError={this.state.hasValidationError}
|
||||
inputValue={this.state.inputValue}
|
||||
placeholder="scratch.mit.edu/projects/123456789"
|
||||
onCancel={this.handleCancel}
|
||||
onChange={this.handleChange}
|
||||
onGoBack={this.handleGoBack}
|
||||
onKeyPress={this.handleKeyPress}
|
||||
onViewProject={this.handleViewProject}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ImportModal.propTypes = {
|
||||
onBack: PropTypes.func.isRequired,
|
||||
onCancel: PropTypes.func.isRequired,
|
||||
onViewProject: PropTypes.func
|
||||
};
|
||||
|
||||
const mapStateToProps = () => ({});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onBack: () => {
|
||||
dispatch(closeImportInfo());
|
||||
dispatch(openPreviewInfo());
|
||||
},
|
||||
onCancel: () => {
|
||||
dispatch(closeImportInfo());
|
||||
},
|
||||
onViewProject: () => {
|
||||
dispatch(closeImportInfo());
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ImportModal);
|
||||
@@ -8,7 +8,8 @@ import PreviewModalComponent from '../components/preview-modal/preview-modal.jsx
|
||||
import BrowserModalComponent from '../components/browser-modal/browser-modal.jsx';
|
||||
|
||||
import {
|
||||
closePreviewInfo
|
||||
closePreviewInfo,
|
||||
openImportInfo
|
||||
} from '../reducers/modals';
|
||||
|
||||
class PreviewModal extends React.Component {
|
||||
@@ -16,7 +17,8 @@ class PreviewModal extends React.Component {
|
||||
super(props);
|
||||
bindAll(this, [
|
||||
'handleTryIt',
|
||||
'handleCancel'
|
||||
'handleCancel',
|
||||
'handleViewProject'
|
||||
]);
|
||||
|
||||
this.state = {
|
||||
@@ -30,6 +32,9 @@ class PreviewModal extends React.Component {
|
||||
handleCancel () {
|
||||
window.location.replace('https://scratch.mit.edu');
|
||||
}
|
||||
handleViewProject () {
|
||||
this.props.onViewProject();
|
||||
}
|
||||
supportedBrowser () {
|
||||
return !['IE', 'Opera', 'Opera Mini', 'Silk', 'Vivaldi'].includes(platform.name);
|
||||
}
|
||||
@@ -39,6 +44,7 @@ class PreviewModal extends React.Component {
|
||||
previewing={this.state.previewing}
|
||||
onCancel={this.handleCancel}
|
||||
onTryIt={this.handleTryIt}
|
||||
onViewProject={this.handleViewProject}
|
||||
/> :
|
||||
<BrowserModalComponent
|
||||
onBack={this.handleCancel}
|
||||
@@ -48,7 +54,8 @@ class PreviewModal extends React.Component {
|
||||
}
|
||||
|
||||
PreviewModal.propTypes = {
|
||||
onTryIt: PropTypes.func
|
||||
onTryIt: PropTypes.func,
|
||||
onViewProject: PropTypes.func
|
||||
};
|
||||
|
||||
const mapStateToProps = () => ({});
|
||||
@@ -56,6 +63,10 @@ const mapStateToProps = () => ({});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onTryIt: () => {
|
||||
dispatch(closePreviewInfo());
|
||||
},
|
||||
onViewProject: () => {
|
||||
dispatch(closePreviewInfo());
|
||||
dispatch(openImportInfo());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ const CLOSE_MODAL = 'scratch-gui/modals/CLOSE_MODAL';
|
||||
const MODAL_BACKDROP_LIBRARY = 'backdropLibrary';
|
||||
const MODAL_COSTUME_LIBRARY = 'costumeLibrary';
|
||||
const MODAL_EXTENSION_LIBRARY = 'extensionLibrary';
|
||||
const MODAL_IMPORT_INFO = 'importInfo';
|
||||
const MODAL_LOADING_PROJECT = 'loadingProject';
|
||||
const MODAL_PREVIEW_INFO = 'previewInfo';
|
||||
const MODAL_SOUND_LIBRARY = 'soundLibrary';
|
||||
@@ -19,6 +20,7 @@ const initialState = {
|
||||
[MODAL_BACKDROP_LIBRARY]: false,
|
||||
[MODAL_COSTUME_LIBRARY]: false,
|
||||
[MODAL_EXTENSION_LIBRARY]: false,
|
||||
[MODAL_IMPORT_INFO]: false,
|
||||
[MODAL_LOADING_PROJECT]: false,
|
||||
[MODAL_PREVIEW_INFO]: true,
|
||||
[MODAL_SOUND_LIBRARY]: false,
|
||||
@@ -66,6 +68,10 @@ const openExtensionLibrary = function () {
|
||||
analytics.pageview('/libraries/extensions');
|
||||
return openModal(MODAL_EXTENSION_LIBRARY);
|
||||
};
|
||||
const openImportInfo = function () {
|
||||
analytics.pageview('modals/import');
|
||||
return openModal(MODAL_IMPORT_INFO);
|
||||
};
|
||||
const openLoadingProject = function () {
|
||||
analytics.pageview('modals/loading');
|
||||
return openModal(MODAL_LOADING_PROJECT);
|
||||
@@ -99,6 +105,9 @@ const closeCostumeLibrary = function () {
|
||||
const closeExtensionLibrary = function () {
|
||||
return closeModal(MODAL_EXTENSION_LIBRARY);
|
||||
};
|
||||
const closeImportInfo = function () {
|
||||
return closeModal(MODAL_IMPORT_INFO);
|
||||
};
|
||||
const closeLoadingProject = function () {
|
||||
return closeModal(MODAL_LOADING_PROJECT);
|
||||
};
|
||||
@@ -122,6 +131,7 @@ export {
|
||||
openBackdropLibrary,
|
||||
openCostumeLibrary,
|
||||
openExtensionLibrary,
|
||||
openImportInfo,
|
||||
openLoadingProject,
|
||||
openPreviewInfo,
|
||||
openSoundLibrary,
|
||||
@@ -131,6 +141,7 @@ export {
|
||||
closeBackdropLibrary,
|
||||
closeCostumeLibrary,
|
||||
closeExtensionLibrary,
|
||||
closeImportInfo,
|
||||
closeLoadingProject,
|
||||
closePreviewInfo,
|
||||
closeSpriteLibrary,
|
||||
|
||||
@@ -4,6 +4,7 @@ import SeleniumHelper from '../helpers/selenium-helper';
|
||||
const {
|
||||
clickText,
|
||||
clickXpath,
|
||||
findByXpath,
|
||||
getDriver,
|
||||
getLogs,
|
||||
loadUri
|
||||
@@ -30,6 +31,40 @@ describe('Loading scratch gui', () => {
|
||||
});
|
||||
|
||||
describe('Loading projects by ID', () => {
|
||||
|
||||
test('Load 2.0 project using import modal', async () => {
|
||||
await loadUri(uri);
|
||||
await clickText('View 2.0 Project');
|
||||
const el = await findByXpath("//input[@placeholder='scratch.mit.edu/projects/123456789']");
|
||||
const projectId = '96708228';
|
||||
await el.sendKeys(`scratch.mit.edu/projects/${projectId}`);
|
||||
await clickXpath('//button[@title="viewproject"]');
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
await clickXpath('//img[@title="Go"]');
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
await clickXpath('//img[@title="Stop"]');
|
||||
const logs = await getLogs();
|
||||
await expect(logs).toEqual([]);
|
||||
});
|
||||
|
||||
test('Invalid url when loading project through modal lets you try again', async () => {
|
||||
await loadUri(uri);
|
||||
await clickText('View 2.0 Project');
|
||||
let el = await findByXpath("//input[@placeholder='scratch.mit.edu/projects/123456789']");
|
||||
await el.sendKeys('thisisnotaurl');
|
||||
await clickXpath('//button[@title="viewproject"]');
|
||||
el = await findByXpath("//input[@placeholder='scratch.mit.edu/projects/123456789']");
|
||||
await el.clear();
|
||||
await el.sendKeys('scratch.mit.edu/projects/96708228');
|
||||
await clickXpath('//button[@title="viewproject"]');
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
await clickXpath('//img[@title="Go"]');
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
await clickXpath('//img[@title="Stop"]');
|
||||
const logs = await getLogs();
|
||||
await expect(logs).toEqual([]);
|
||||
});
|
||||
|
||||
test('Load a project by ID directly through url', async () => {
|
||||
await driver.quit(); // Reset driver to test hitting # url directly
|
||||
driver = getDriver();
|
||||
|
||||
Reference in new issue
Block a user