From 775173661fade65b7f8ef0d65a79d6514ecc1de5 Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Tue, 17 Sep 2019 21:49:48 -0400 Subject: [PATCH 01/15] embed view with minimal functionality, route --- src/routes.json | 10 +- src/views/preview/embed-view.jsx | 154 +++++++++++++++++++++++++++++ src/views/preview/embed.jsx | 29 ++++++ src/views/preview/project-view.jsx | 5 +- 4 files changed, 193 insertions(+), 5 deletions(-) create mode 100644 src/views/preview/embed-view.jsx create mode 100644 src/views/preview/embed.jsx diff --git a/src/routes.json b/src/routes.json index c1494768f..4cfeb3963 100644 --- a/src/routes.json +++ b/src/routes.json @@ -177,12 +177,20 @@ }, { "name": "projects", - "pattern": "^/projects(/editor|(/\\d+(/editor|/fullscreen|/embed)?)?)?/?(\\?.*)?$", + "pattern": "^/projects(/editor|(/\\d+(/editor|/fullscreen)?)?)?/?(\\?.*)?$", "routeAlias": "/projects/?$", "view": "preview/preview", "title": "Scratch Project", "dynamicMetaTags": true }, + { + "name": "projects", + "pattern": "^/projects/\\d+/embed/?(\\?.*)?$", + "routeAlias": "/projects/?$", + "view": "preview/embed", + "title": "Scratch Project", + "dynamicMetaTags": true + }, { "name": "parents", "pattern": "^/parents/?(\\?.*)?$", diff --git a/src/views/preview/embed-view.jsx b/src/views/preview/embed-view.jsx new file mode 100644 index 000000000..94d6afe5c --- /dev/null +++ b/src/views/preview/embed-view.jsx @@ -0,0 +1,154 @@ +// embed view + +const bindAll = require('lodash.bindall'); +const React = require('react'); +const PropTypes = require('prop-types'); +const connect = require('react-redux').connect; +const injectIntl = require('react-intl').injectIntl; + +const Page = require('../../components/page/www/page.jsx'); +const storage = require('../../lib/storage.js').default; +const jar = require('../../lib/jar.js'); +const projectShape = require('./projectshape.jsx').projectShape; +const NotAvailable = require('../../components/not-available/not-available.jsx'); +const Meta = require('./meta.jsx'); + +const sessionActions = require('../../redux/session.js'); +const previewActions = require('../../redux/preview.js'); + +const GUI = require('scratch-gui'); +const IntlGUI = injectIntl(GUI.default); + +const Sentry = require('@sentry/browser'); +if (`${process.env.SENTRY_DSN}` !== '') { + Sentry.init({ + dsn: `${process.env.SENTRY_DSN}`, + // Do not collect global onerror, only collect specifically from React error boundaries. + // TryCatch plugin also includes errors from setTimeouts (i.e. the VM) + integrations: integrations => integrations.filter(i => + !(i.name === 'GlobalHandlers' || i.name === 'TryCatch')) + }); + window.Sentry = Sentry; // Allow GUI access to Sentry via window +} + +class EmbedView extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + ]); + const pathname = window.location.pathname.toLowerCase(); + const parts = pathname.split('/').filter(Boolean); + this.state = { + extensions: [], + invalidProject: parts.length === 1, + projectId: parts[1] + }; + } + componentDidUpdate (prevProps) { + if (this.state.projectId > 0 && + ((this.props.sessionStatus !== prevProps.sessionStatus && + this.props.sessionStatus === sessionActions.Status.FETCHED))) { + this.props.getProjectInfo(this.state.projectId); + this.getProjectData(this.state.projectId, true /* Show cloud/username alerts */); + } + } + getProjectData (projectId) { + if (projectId <= 0) return 0; + storage + .load(storage.AssetType.Project, projectId, storage.DataFormat.JSON) + .then(projectAsset => { // NOTE: this is turning up null, breaking the line below. + let input = projectAsset.data; + if (typeof input === 'object' && !(input instanceof ArrayBuffer) && + !ArrayBuffer.isView(input)) { // taken from scratch-vm + // If the input is an object and not any ArrayBuffer + // or an ArrayBuffer view (this includes all typed arrays and DataViews) + // turn the object into a JSON string, because we suspect + // this is a project.json as an object + // validate expects a string or buffer as input + // TODO not sure if we need to check that it also isn't a data view + input = JSON.stringify(input); + } + }); + } + handleSetLanguage (locale) { + jar.set('scratchlanguage', locale); + } + render () { + if (this.props.projectNotAvailable || this.state.invalidProject) { + return ( + +
+ +
+
+ ); + } + + return ( + + + + + + + ); + } +} + +EmbedView.propTypes = { + assetHost: PropTypes.string.isRequired, + getProjectInfo: PropTypes.func.isRequired, + projectHost: PropTypes.string.isRequired, + projectInfo: projectShape, + projectNotAvailable: PropTypes.bool, + sessionStatus: PropTypes.string +}; + +EmbedView.defaultProps = { + assetHost: process.env.ASSET_HOST, + projectHost: process.env.PROJECT_HOST +}; + +const mapStateToProps = state => ({ + projectInfo: state.preview.projectInfo, + projectNotAvailable: state.preview.projectNotAvailable +}); + +const mapDispatchToProps = dispatch => ({ + getProjectInfo: (id, token) => { + dispatch(previewActions.getProjectInfo(id, token)); + } +}); + +module.exports.View = connect( + mapStateToProps, + mapDispatchToProps +)(EmbedView); + +// initialize GUI by calling its reducer functions depending on URL +GUI.setAppElement(document.getElementById('app')); +module.exports.initGuiState = guiInitialState => { + const pathname = window.location.pathname.toLowerCase(); + const parts = pathname.split('/').filter(Boolean); + // parts[0]: 'projects' + // parts[1]: either :id or 'editor' + // parts[2]: undefined if no :id, otherwise either 'editor', 'fullscreen' or 'embed' + if (parts.indexOf('embed') !== -1) { + guiInitialState = GUI.initEmbedded(guiInitialState); + } + return guiInitialState; +}; + +module.exports.guiReducers = GUI.guiReducers; +module.exports.guiInitialState = GUI.guiInitialState; +module.exports.guiMiddleware = GUI.guiMiddleware; +module.exports.initLocale = GUI.initLocale; +module.exports.localesInitialState = GUI.localesInitialState; diff --git a/src/views/preview/embed.jsx b/src/views/preview/embed.jsx new file mode 100644 index 000000000..278fe3591 --- /dev/null +++ b/src/views/preview/embed.jsx @@ -0,0 +1,29 @@ +// preview view can show either project page or editor page; +// idea is that we shouldn't require a page reload to switch back and forth +const React = require('react'); +const Page = require('../../components/page/www/page.jsx'); +const render = require('../../lib/render.jsx'); + +const previewActions = require('../../redux/preview.js'); + +const isSupportedBrowser = require('../../lib/supported-browser').default; +const UnsupportedBrowser = require('./unsupported-browser.jsx'); + +if (isSupportedBrowser()) { + const EmbedView = require('./embed-view.jsx'); + render( + , + document.getElementById('app'), + { + preview: previewActions.previewReducer, + ...EmbedView.guiReducers + }, + { + locales: EmbedView.initLocale(EmbedView.localesInitialState, window._locale), + scratchGui: EmbedView.initGuiState(EmbedView.guiInitialState) + }, + EmbedView.guiMiddleware + ); +} else { + render(, document.getElementById('app')); +} diff --git a/src/views/preview/project-view.jsx b/src/views/preview/project-view.jsx index f31353bc1..97ffd7fd3 100644 --- a/src/views/preview/project-view.jsx +++ b/src/views/preview/project-view.jsx @@ -1092,16 +1092,13 @@ module.exports.initGuiState = guiInitialState => { const parts = pathname.split('/').filter(Boolean); // parts[0]: 'projects' // parts[1]: either :id or 'editor' - // parts[2]: undefined if no :id, otherwise either 'editor', 'fullscreen' or 'embed' + // parts[2]: undefined if no :id, otherwise either 'editor' or 'fullscreen' if (parts.indexOf('editor') === -1) { guiInitialState = GUI.initPlayer(guiInitialState); } if (parts.indexOf('fullscreen') !== -1) { guiInitialState = GUI.initFullScreen(guiInitialState); } - if (parts.indexOf('embed') !== -1) { - guiInitialState = GUI.initEmbedded(guiInitialState); - } return guiInitialState; }; From ae661a48c7ce16297f3ba0e34bdba1d8dfc4a6bc Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Sat, 28 Sep 2019 10:17:59 -0400 Subject: [PATCH 02/15] corrected embed route name --- src/routes.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes.json b/src/routes.json index 4cfeb3963..d90277313 100644 --- a/src/routes.json +++ b/src/routes.json @@ -184,7 +184,7 @@ "dynamicMetaTags": true }, { - "name": "projects", + "name": "embed", "pattern": "^/projects/\\d+/embed/?(\\?.*)?$", "routeAlias": "/projects/?$", "view": "preview/embed", From ca4a4bcbb32106f0efe2a00299518842b911dfc4 Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Sat, 28 Sep 2019 10:18:19 -0400 Subject: [PATCH 03/15] added project view hoc, not hooked up yes --- src/views/preview/project-view-hoc.jsx | 88 ++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/views/preview/project-view-hoc.jsx diff --git a/src/views/preview/project-view-hoc.jsx b/src/views/preview/project-view-hoc.jsx new file mode 100644 index 000000000..aa0b388c8 --- /dev/null +++ b/src/views/preview/project-view-hoc.jsx @@ -0,0 +1,88 @@ +const bindAll = require('lodash.bindall'); +const React = require('react'); +const PropTypes = require('prop-types'); +const connect = require('react-redux').connect; + +const storage = require('../../lib/storage.js').default; +const previewActions = require('../../redux/preview.js'); + +const Sentry = require('@sentry/browser'); +if (`${process.env.SENTRY_DSN}` !== '') { + Sentry.init({ + dsn: `${process.env.SENTRY_DSN}`, + // Do not collect global onerror, only collect specifically from React error boundaries. + // TryCatch plugin also includes errors from setTimeouts (i.e. the VM) + integrations: integrations => integrations.filter(i => + !(i.name === 'GlobalHandlers' || i.name === 'TryCatch')) + }); + window.Sentry = Sentry; // Allow GUI access to Sentry via window +} + +/** + * Higher-order component for presenting a project view. + * @param {React.Component} Component a project view component + * @return {React.Component} a wrapped project view component + */ + +const ProjectViewHOC = Component => { + class WrappedComponent extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'fetchProjectData' + ]); + } + fetchProjectData (projectId) { + if (projectId <= 0) return Promise.reject(null); + return storage + .load(storage.AssetType.Project, projectId, storage.DataFormat.JSON) + .then(projectAsset => { // NOTE: this is turning up null, breaking the line below. + let input = projectAsset.data; + if (typeof input === 'object' && !(input instanceof ArrayBuffer) && + !ArrayBuffer.isView(input)) { // taken from scratch-vm + // If the input is an object and not any ArrayBuffer + // or an ArrayBuffer view (this includes all typed arrays and DataViews) + // turn the object into a JSON string, because we suspect + // this is a project.json as an object + // validate expects a string or buffer as input + // TODO not sure if we need to check that it also isn't a data view + input = JSON.stringify(input); // NOTE: what is the point of doing this?? + } + }); + } + render () { + return (); + } + } + + WrappedComponent.propTypes = { + assetHost: PropTypes.string.isRequired, + projectHost: PropTypes.string.isRequired + }; + + WrappedComponent.defaultProps = { + assetHost: process.env.ASSET_HOST, + projectHost: process.env.PROJECT_HOST + }; + + const mapStateToProps = state => ({ + projectInfo: state.preview.projectInfo, + projectNotAvailable: state.preview.projectNotAvailable + }); + + const mapDispatchToProps = dispatch => ({ + getProjectInfo: (id, token) => { + dispatch(previewActions.getProjectInfo(id, token)); + } + }); + + return connect( + mapStateToProps, + mapDispatchToProps + )(WrappedComponent); +}; + +module.exports = ProjectViewHOC; From 01a273b1f86c46348680729974e32dddb3b5441f Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Sat, 28 Sep 2019 10:19:06 -0400 Subject: [PATCH 04/15] refactored project view and embed view to use hoc --- src/views/preview/embed-view.jsx | 84 +++-------------- src/views/preview/embed.jsx | 6 +- src/views/preview/project-view.jsx | 139 ++++++++++++----------------- 3 files changed, 72 insertions(+), 157 deletions(-) diff --git a/src/views/preview/embed-view.jsx b/src/views/preview/embed-view.jsx index 94d6afe5c..19594da80 100644 --- a/src/views/preview/embed-view.jsx +++ b/src/views/preview/embed-view.jsx @@ -3,19 +3,14 @@ const bindAll = require('lodash.bindall'); const React = require('react'); const PropTypes = require('prop-types'); -const connect = require('react-redux').connect; const injectIntl = require('react-intl').injectIntl; -const Page = require('../../components/page/www/page.jsx'); -const storage = require('../../lib/storage.js').default; -const jar = require('../../lib/jar.js'); +const ProjectViewHOC = require('./project-view-hoc.jsx'); +const ErrorBoundary = require('../../components/errorboundary/errorboundary.jsx'); const projectShape = require('./projectshape.jsx').projectShape; const NotAvailable = require('../../components/not-available/not-available.jsx'); const Meta = require('./meta.jsx'); -const sessionActions = require('../../redux/session.js'); -const previewActions = require('../../redux/preview.js'); - const GUI = require('scratch-gui'); const IntlGUI = injectIntl(GUI.default); @@ -44,43 +39,18 @@ class EmbedView extends React.Component { projectId: parts[1] }; } - componentDidUpdate (prevProps) { - if (this.state.projectId > 0 && - ((this.props.sessionStatus !== prevProps.sessionStatus && - this.props.sessionStatus === sessionActions.Status.FETCHED))) { - this.props.getProjectInfo(this.state.projectId); - this.getProjectData(this.state.projectId, true /* Show cloud/username alerts */); - } - } - getProjectData (projectId) { - if (projectId <= 0) return 0; - storage - .load(storage.AssetType.Project, projectId, storage.DataFormat.JSON) - .then(projectAsset => { // NOTE: this is turning up null, breaking the line below. - let input = projectAsset.data; - if (typeof input === 'object' && !(input instanceof ArrayBuffer) && - !ArrayBuffer.isView(input)) { // taken from scratch-vm - // If the input is an object and not any ArrayBuffer - // or an ArrayBuffer view (this includes all typed arrays and DataViews) - // turn the object into a JSON string, because we suspect - // this is a project.json as an object - // validate expects a string or buffer as input - // TODO not sure if we need to check that it also isn't a data view - input = JSON.stringify(input); - } - }); - } - handleSetLanguage (locale) { - jar.set('scratchlanguage', locale); + componentDidMount () { + this.props.getProjectInfo(this.state.projectId); + this.props.fetchProjectData(this.state.projectId); } render () { if (this.props.projectNotAvailable || this.state.invalidProject) { return ( - +
-
+ ); } @@ -95,7 +65,6 @@ class EmbedView extends React.Component { projectHost={this.props.projectHost} projectId={this.state.projectId} projectTitle={this.props.projectInfo.title} - onSetLanguage={this.handleSetLanguage} /> @@ -105,48 +74,17 @@ class EmbedView extends React.Component { EmbedView.propTypes = { assetHost: PropTypes.string.isRequired, + fetchProjectData: PropTypes.func.isRequired, getProjectInfo: PropTypes.func.isRequired, projectHost: PropTypes.string.isRequired, projectInfo: projectShape, - projectNotAvailable: PropTypes.bool, - sessionStatus: PropTypes.string + projectNotAvailable: PropTypes.bool }; -EmbedView.defaultProps = { - assetHost: process.env.ASSET_HOST, - projectHost: process.env.PROJECT_HOST -}; +module.exports.View = ProjectViewHOC(EmbedView); -const mapStateToProps = state => ({ - projectInfo: state.preview.projectInfo, - projectNotAvailable: state.preview.projectNotAvailable -}); - -const mapDispatchToProps = dispatch => ({ - getProjectInfo: (id, token) => { - dispatch(previewActions.getProjectInfo(id, token)); - } -}); - -module.exports.View = connect( - mapStateToProps, - mapDispatchToProps -)(EmbedView); - -// initialize GUI by calling its reducer functions depending on URL GUI.setAppElement(document.getElementById('app')); -module.exports.initGuiState = guiInitialState => { - const pathname = window.location.pathname.toLowerCase(); - const parts = pathname.split('/').filter(Boolean); - // parts[0]: 'projects' - // parts[1]: either :id or 'editor' - // parts[2]: undefined if no :id, otherwise either 'editor', 'fullscreen' or 'embed' - if (parts.indexOf('embed') !== -1) { - guiInitialState = GUI.initEmbedded(guiInitialState); - } - return guiInitialState; -}; - +module.exports.initGuiState = GUI.initEmbedded; module.exports.guiReducers = GUI.guiReducers; module.exports.guiInitialState = GUI.guiInitialState; module.exports.guiMiddleware = GUI.guiMiddleware; diff --git a/src/views/preview/embed.jsx b/src/views/preview/embed.jsx index 278fe3591..cb2d9ba9b 100644 --- a/src/views/preview/embed.jsx +++ b/src/views/preview/embed.jsx @@ -1,7 +1,5 @@ -// preview view can show either project page or editor page; -// idea is that we shouldn't require a page reload to switch back and forth const React = require('react'); -const Page = require('../../components/page/www/page.jsx'); +const ErrorBoundary = require('../../components/errorboundary/errorboundary.jsx'); const render = require('../../lib/render.jsx'); const previewActions = require('../../redux/preview.js'); @@ -25,5 +23,5 @@ if (isSupportedBrowser()) { EmbedView.guiMiddleware ); } else { - render(, document.getElementById('app')); + render(, document.getElementById('app')); } diff --git a/src/views/preview/project-view.jsx b/src/views/preview/project-view.jsx index 97ffd7fd3..3d6e671fb 100644 --- a/src/views/preview/project-view.jsx +++ b/src/views/preview/project-view.jsx @@ -10,10 +10,10 @@ const injectIntl = require('react-intl').injectIntl; const parser = require('scratch-parser'); const Page = require('../../components/page/www/page.jsx'); -const storage = require('../../lib/storage.js').default; const log = require('../../lib/log'); const jar = require('../../lib/jar.js'); const thumbnailUrl = require('../../lib/user-thumbnail'); +const ProjectViewHOC = require('./project-view-hoc.jsx'); const ProjectInfo = require('../../lib/project-info'); const PreviewPresentation = require('./presentation.jsx'); const projectShape = require('./projectshape.jsx').projectShape; @@ -35,18 +35,6 @@ const IntlGUI = injectIntl(GUI.default); const localStorageAvailable = 'localStorage' in window && window.localStorage !== null; -const Sentry = require('@sentry/browser'); -if (`${process.env.SENTRY_DSN}` !== '') { - Sentry.init({ - dsn: `${process.env.SENTRY_DSN}`, - // Do not collect global onerror, only collect specifically from React error boundaries. - // TryCatch plugin also includes errors from setTimeouts (i.e. the VM) - integrations: integrations => integrations.filter(i => - !(i.name === 'GlobalHandlers' || i.name === 'TryCatch')) - }); - window.Sentry = Sentry; // Allow GUI access to Sentry via window -} - class Preview extends React.Component { constructor (props) { super(props); @@ -134,12 +122,17 @@ class Preview extends React.Component { } componentDidMount () { this.addEventListeners(); + console.log(`componentDidMount: session status: ${this.props.sessionStatus}`); + } componentDidUpdate (prevProps, prevState) { + console.log(`componentDidUpdate: session status: ${this.props.sessionStatus}`); if (this.state.projectId > 0 && ((this.props.sessionStatus !== prevProps.sessionStatus && this.props.sessionStatus === sessionActions.Status.FETCHED) || (this.state.projectId !== prevState.projectId))) { + console.log("got here A"); + console.log(`this: ${this.state.projectId} prev: ${prevState.projectId}`); this.fetchCommunityData(); this.getProjectData(this.state.projectId, true /* Show cloud/username alerts */); if (this.state.justShared) { @@ -245,67 +238,53 @@ class Preview extends React.Component { } } getProjectData (projectId, showAlerts) { - if (projectId <= 0) return 0; - storage - .load(storage.AssetType.Project, projectId, storage.DataFormat.JSON) - .then(projectAsset => { // NOTE: this is turning up null, breaking the line below. - let input = projectAsset.data; - if (typeof input === 'object' && !(input instanceof ArrayBuffer) && - !ArrayBuffer.isView(input)) { // taken from scratch-vm - // If the input is an object and not any ArrayBuffer - // or an ArrayBuffer view (this includes all typed arrays and DataViews) - // turn the object into a JSON string, because we suspect - // this is a project.json as an object - // validate expects a string or buffer as input - // TODO not sure if we need to check that it also isn't a data view - input = JSON.stringify(input); + this.props.fetchProjectData(projectId).then(projectAsset => { + parser(projectAsset.data, false, (err, projectData) => { + if (err) { + log.error(`Unhandled project parsing error: ${err}`); + return; } - parser(projectAsset.data, false, (err, projectData) => { - if (err) { - log.error(`Unhandled project parsing error: ${err}`); - return; - } - const newState = { - modInfo: {} // Filled in below - }; + const newState = { + modInfo: {} // Filled in below + }; - const helpers = ProjectInfo[projectData[0].projectVersion]; - if (!helpers) return; // sb1 not handled - newState.extensions = Array.from(helpers.extensions(projectData[0])); - newState.modInfo.scriptCount = helpers.scriptCount(projectData[0]); - newState.modInfo.spriteCount = helpers.spriteCount(projectData[0]); - const hasCloudData = helpers.cloudData(projectData[0]); - if (hasCloudData) { - if (this.props.isLoggedIn) { - // show cloud variables log link if logged in - newState.extensions.push({ - action: { - l10nId: 'project.cloudDataLink', - uri: `/cloudmonitor/${projectId}/` - }, - icon: 'clouddata.svg', - l10nId: 'project.cloudVariables', - linked: true - }); - } else { - newState.extensions.push({ - icon: 'clouddata.svg', - l10nId: 'project.cloudVariables' - }); - } + const helpers = ProjectInfo[projectData[0].projectVersion]; + if (!helpers) return; // sb1 not handled + newState.extensions = Array.from(helpers.extensions(projectData[0])); + newState.modInfo.scriptCount = helpers.scriptCount(projectData[0]); + newState.modInfo.spriteCount = helpers.spriteCount(projectData[0]); + const hasCloudData = helpers.cloudData(projectData[0]); + if (hasCloudData) { + if (this.props.isLoggedIn) { + // show cloud variables log link if logged in + newState.extensions.push({ + action: { + l10nId: 'project.cloudDataLink', + uri: `/cloudmonitor/${projectId}/` + }, + icon: 'clouddata.svg', + l10nId: 'project.cloudVariables', + linked: true + }); + } else { + newState.extensions.push({ + icon: 'clouddata.svg', + l10nId: 'project.cloudVariables' + }); } + } - if (showAlerts) { - // Check for username block only if user is logged in - if (this.props.isLoggedIn) { - newState.showUsernameBlockAlert = helpers.usernameBlock(projectData[0]); - } else { // Check for cloud vars only if user is logged out - newState.showCloudDataAlert = hasCloudData; - } + if (showAlerts) { + // Check for username block only if user is logged in + if (this.props.isLoggedIn) { + newState.showUsernameBlockAlert = helpers.usernameBlock(projectData[0]); + } else { // Check for cloud vars only if user is logged out + newState.showCloudDataAlert = hasCloudData; } - this.setState(newState); - }); + } + this.setState(newState); }); + }); } handleToggleComments () { this.props.updateProject( @@ -792,6 +771,7 @@ Preview.propTypes = { enableCommunity: PropTypes.bool, faved: PropTypes.bool, favedLoaded: PropTypes.bool, + fetchProjectData: PropTypes.func.isRequired, fullScreen: PropTypes.bool, getCommentById: PropTypes.func.isRequired, getCuratedStudios: PropTypes.func.isRequired, @@ -879,17 +859,17 @@ Preview.defaultProps = { userPresent: false }; -const mapStateToProps = state => { - const projectInfoPresent = state.preview.projectInfo && - Object.keys(state.preview.projectInfo).length > 0 && state.preview.projectInfo.id > 0; +const mapStateToProps = (state, ownProps) => { + const projectInfoPresent = ownProps.projectInfo && + Object.keys(ownProps.projectInfo).length > 0 && ownProps.projectInfo.id > 0; const userPresent = state.session.session.user !== null && typeof state.session.session.user !== 'undefined' && Object.keys(state.session.session.user).length > 0; const isLoggedIn = state.session.status === sessionActions.Status.FETCHED && userPresent; const isAdmin = isLoggedIn && state.session.session.permissions.admin; - const author = projectInfoPresent && state.preview.projectInfo.author; - const authorPresent = author && Object.keys(state.preview.projectInfo.author).length > 0; + const author = projectInfoPresent && ownProps.projectInfo.author; + const authorPresent = author && Object.keys(ownProps.projectInfo.author).length > 0; const authorId = authorPresent && author.id && author.id.toString(); const authorUsername = authorPresent && author.username; const userOwnsProject = isLoggedIn && authorPresent && @@ -899,7 +879,7 @@ const mapStateToProps = state => { state.permissions.admin === true); // if we don't have projectInfo, assume it's shared until we know otherwise - const isShared = !projectInfoPresent || state.preview.projectInfo.is_published; + const isShared = !projectInfoPresent || ownProps.projectInfo.is_published; return { authorId: authorId, @@ -935,8 +915,8 @@ const mapStateToProps = state => { original: state.preview.original, parent: state.preview.parent, playerMode: state.scratchGui.mode.isPlayerOnly, - projectInfo: state.preview.projectInfo, - projectNotAvailable: state.preview.projectNotAvailable, + projectInfo: ownProps.projectInfo, + projectNotAvailable: ownProps.projectNotAvailable, projectStudios: state.preview.projectStudios, registrationOpen: state.navigation.registrationOpen, remixes: state.preview.remixes, @@ -991,9 +971,6 @@ const mapDispatchToProps = dispatch => ({ getParentInfo: id => { dispatch(previewActions.getParentInfo(id)); }, - getProjectInfo: (id, token) => { - dispatch(previewActions.getProjectInfo(id, token)); - }, getRemixes: id => { dispatch(previewActions.getRemixes(id)); }, @@ -1064,11 +1041,13 @@ const mapDispatchToProps = dispatch => ({ } }); -module.exports.View = connect( +const ConnectedPreview = connect( mapStateToProps, mapDispatchToProps )(Preview); +module.exports.View = ProjectViewHOC(ConnectedPreview); + // replace old Scratch 2.0-style hashtag URLs with updated format if (window.location.hash) { let pathname = window.location.pathname; From a2e045f8ef857fb592068efd65ce81fd67343700 Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Sat, 28 Sep 2019 13:59:43 -0400 Subject: [PATCH 05/15] removed extra sentry init --- src/views/preview/embed-view.jsx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/views/preview/embed-view.jsx b/src/views/preview/embed-view.jsx index 19594da80..2a17b2a66 100644 --- a/src/views/preview/embed-view.jsx +++ b/src/views/preview/embed-view.jsx @@ -14,18 +14,6 @@ const Meta = require('./meta.jsx'); const GUI = require('scratch-gui'); const IntlGUI = injectIntl(GUI.default); -const Sentry = require('@sentry/browser'); -if (`${process.env.SENTRY_DSN}` !== '') { - Sentry.init({ - dsn: `${process.env.SENTRY_DSN}`, - // Do not collect global onerror, only collect specifically from React error boundaries. - // TryCatch plugin also includes errors from setTimeouts (i.e. the VM) - integrations: integrations => integrations.filter(i => - !(i.name === 'GlobalHandlers' || i.name === 'TryCatch')) - }); - window.Sentry = Sentry; // Allow GUI access to Sentry via window -} - class EmbedView extends React.Component { constructor (props) { super(props); From ae591857a4d306d1149f2cf60779b718fd33fd2b Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Mon, 30 Sep 2019 10:04:44 -0400 Subject: [PATCH 06/15] removed unnecessary React.Fragment --- src/views/preview/embed-view.jsx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/views/preview/embed-view.jsx b/src/views/preview/embed-view.jsx index 2a17b2a66..5adc54b41 100644 --- a/src/views/preview/embed-view.jsx +++ b/src/views/preview/embed-view.jsx @@ -45,16 +45,14 @@ class EmbedView extends React.Component { return ( - - - + ); } From df95f4f1165c7a495f4102b0893c5c622a8a87bc Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Mon, 30 Sep 2019 10:06:06 -0400 Subject: [PATCH 07/15] refactored getProjectData back into only project-view --- src/views/preview/embed-view.jsx | 2 - src/views/preview/project-view-hoc.jsx | 21 ------ src/views/preview/project-view.jsx | 100 ++++++++++++++----------- 3 files changed, 57 insertions(+), 66 deletions(-) diff --git a/src/views/preview/embed-view.jsx b/src/views/preview/embed-view.jsx index 5adc54b41..251ab0267 100644 --- a/src/views/preview/embed-view.jsx +++ b/src/views/preview/embed-view.jsx @@ -29,7 +29,6 @@ class EmbedView extends React.Component { } componentDidMount () { this.props.getProjectInfo(this.state.projectId); - this.props.fetchProjectData(this.state.projectId); } render () { if (this.props.projectNotAvailable || this.state.invalidProject) { @@ -60,7 +59,6 @@ class EmbedView extends React.Component { EmbedView.propTypes = { assetHost: PropTypes.string.isRequired, - fetchProjectData: PropTypes.func.isRequired, getProjectInfo: PropTypes.func.isRequired, projectHost: PropTypes.string.isRequired, projectInfo: projectShape, diff --git a/src/views/preview/project-view-hoc.jsx b/src/views/preview/project-view-hoc.jsx index aa0b388c8..08da7d221 100644 --- a/src/views/preview/project-view-hoc.jsx +++ b/src/views/preview/project-view-hoc.jsx @@ -3,7 +3,6 @@ const React = require('react'); const PropTypes = require('prop-types'); const connect = require('react-redux').connect; -const storage = require('../../lib/storage.js').default; const previewActions = require('../../redux/preview.js'); const Sentry = require('@sentry/browser'); @@ -29,30 +28,10 @@ const ProjectViewHOC = Component => { constructor (props) { super(props); bindAll(this, [ - 'fetchProjectData' ]); } - fetchProjectData (projectId) { - if (projectId <= 0) return Promise.reject(null); - return storage - .load(storage.AssetType.Project, projectId, storage.DataFormat.JSON) - .then(projectAsset => { // NOTE: this is turning up null, breaking the line below. - let input = projectAsset.data; - if (typeof input === 'object' && !(input instanceof ArrayBuffer) && - !ArrayBuffer.isView(input)) { // taken from scratch-vm - // If the input is an object and not any ArrayBuffer - // or an ArrayBuffer view (this includes all typed arrays and DataViews) - // turn the object into a JSON string, because we suspect - // this is a project.json as an object - // validate expects a string or buffer as input - // TODO not sure if we need to check that it also isn't a data view - input = JSON.stringify(input); // NOTE: what is the point of doing this?? - } - }); - } render () { return (); } diff --git a/src/views/preview/project-view.jsx b/src/views/preview/project-view.jsx index 3d6e671fb..f98fe1083 100644 --- a/src/views/preview/project-view.jsx +++ b/src/views/preview/project-view.jsx @@ -10,6 +10,7 @@ const injectIntl = require('react-intl').injectIntl; const parser = require('scratch-parser'); const Page = require('../../components/page/www/page.jsx'); +const storage = require('../../lib/storage.js').default; const log = require('../../lib/log'); const jar = require('../../lib/jar.js'); const thumbnailUrl = require('../../lib/user-thumbnail'); @@ -238,53 +239,67 @@ class Preview extends React.Component { } } getProjectData (projectId, showAlerts) { - this.props.fetchProjectData(projectId).then(projectAsset => { - parser(projectAsset.data, false, (err, projectData) => { - if (err) { - log.error(`Unhandled project parsing error: ${err}`); - return; + if (projectId <= 0) return 0; + return storage + .load(storage.AssetType.Project, projectId, storage.DataFormat.JSON) + .then(projectAsset => { // NOTE: this is turning up null, breaking the line below. + let input = projectAsset.data; + if (typeof input === 'object' && !(input instanceof ArrayBuffer) && + !ArrayBuffer.isView(input)) { // taken from scratch-vm + // If the input is an object and not any ArrayBuffer + // or an ArrayBuffer view (this includes all typed arrays and DataViews) + // turn the object into a JSON string, because we suspect + // this is a project.json as an object + // validate expects a string or buffer as input + // TODO not sure if we need to check that it also isn't a data view + input = JSON.stringify(input); // NOTE: what is the point of doing this?? } - const newState = { - modInfo: {} // Filled in below - }; - - const helpers = ProjectInfo[projectData[0].projectVersion]; - if (!helpers) return; // sb1 not handled - newState.extensions = Array.from(helpers.extensions(projectData[0])); - newState.modInfo.scriptCount = helpers.scriptCount(projectData[0]); - newState.modInfo.spriteCount = helpers.spriteCount(projectData[0]); - const hasCloudData = helpers.cloudData(projectData[0]); - if (hasCloudData) { - if (this.props.isLoggedIn) { - // show cloud variables log link if logged in - newState.extensions.push({ - action: { - l10nId: 'project.cloudDataLink', - uri: `/cloudmonitor/${projectId}/` - }, - icon: 'clouddata.svg', - l10nId: 'project.cloudVariables', - linked: true - }); - } else { - newState.extensions.push({ - icon: 'clouddata.svg', - l10nId: 'project.cloudVariables' - }); + parser(projectAsset.data, false, (err, projectData) => { + if (err) { + log.error(`Unhandled project parsing error: ${err}`); + return; } - } + const newState = { + modInfo: {} // Filled in below + }; - if (showAlerts) { - // Check for username block only if user is logged in - if (this.props.isLoggedIn) { - newState.showUsernameBlockAlert = helpers.usernameBlock(projectData[0]); - } else { // Check for cloud vars only if user is logged out - newState.showCloudDataAlert = hasCloudData; + const helpers = ProjectInfo[projectData[0].projectVersion]; + if (!helpers) return; // sb1 not handled + newState.extensions = Array.from(helpers.extensions(projectData[0])); + newState.modInfo.scriptCount = helpers.scriptCount(projectData[0]); + newState.modInfo.spriteCount = helpers.spriteCount(projectData[0]); + const hasCloudData = helpers.cloudData(projectData[0]); + if (hasCloudData) { + if (this.props.isLoggedIn) { + // show cloud variables log link if logged in + newState.extensions.push({ + action: { + l10nId: 'project.cloudDataLink', + uri: `/cloudmonitor/${projectId}/` + }, + icon: 'clouddata.svg', + l10nId: 'project.cloudVariables', + linked: true + }); + } else { + newState.extensions.push({ + icon: 'clouddata.svg', + l10nId: 'project.cloudVariables' + }); + } } - } - this.setState(newState); + + if (showAlerts) { + // Check for username block only if user is logged in + if (this.props.isLoggedIn) { + newState.showUsernameBlockAlert = helpers.usernameBlock(projectData[0]); + } else { // Check for cloud vars only if user is logged out + newState.showCloudDataAlert = hasCloudData; + } + } + this.setState(newState); + }); }); - }); } handleToggleComments () { this.props.updateProject( @@ -771,7 +786,6 @@ Preview.propTypes = { enableCommunity: PropTypes.bool, faved: PropTypes.bool, favedLoaded: PropTypes.bool, - fetchProjectData: PropTypes.func.isRequired, fullScreen: PropTypes.bool, getCommentById: PropTypes.func.isRequired, getCuratedStudios: PropTypes.func.isRequired, From afb7957d04d82d248bdb9f875d5c9d344abc7244 Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Mon, 30 Sep 2019 10:06:33 -0400 Subject: [PATCH 08/15] =?UTF-8?q?moved=20Sentry=20init=20into=20ProjectVie?= =?UTF-8?q?wHOC=20wrapper=E2=80=99s=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/preview/project-view-hoc.jsx | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/views/preview/project-view-hoc.jsx b/src/views/preview/project-view-hoc.jsx index 08da7d221..7bae86eff 100644 --- a/src/views/preview/project-view-hoc.jsx +++ b/src/views/preview/project-view-hoc.jsx @@ -5,18 +5,6 @@ const connect = require('react-redux').connect; const previewActions = require('../../redux/preview.js'); -const Sentry = require('@sentry/browser'); -if (`${process.env.SENTRY_DSN}` !== '') { - Sentry.init({ - dsn: `${process.env.SENTRY_DSN}`, - // Do not collect global onerror, only collect specifically from React error boundaries. - // TryCatch plugin also includes errors from setTimeouts (i.e. the VM) - integrations: integrations => integrations.filter(i => - !(i.name === 'GlobalHandlers' || i.name === 'TryCatch')) - }); - window.Sentry = Sentry; // Allow GUI access to Sentry via window -} - /** * Higher-order component for presenting a project view. * @param {React.Component} Component a project view component @@ -24,6 +12,19 @@ if (`${process.env.SENTRY_DSN}` !== '') { */ const ProjectViewHOC = Component => { + // initialize Sentry instance, making sure it hasn't been initialized already + if (!window.Sentry && `${process.env.SENTRY_DSN}` !== '') { + const Sentry = require('@sentry/browser'); + Sentry.init({ + dsn: `${process.env.SENTRY_DSN}`, + // Do not collect global onerror, only collect specifically from React error boundaries. + // TryCatch plugin also includes errors from setTimeouts (i.e. the VM) + integrations: integrations => integrations.filter(i => + !(i.name === 'GlobalHandlers' || i.name === 'TryCatch')) + }); + window.Sentry = Sentry; // Allow GUI access to Sentry via window + } + class WrappedComponent extends React.Component { constructor (props) { super(props); From 10e6685a159032aa65486699f9aabb72cb01652f Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Mon, 30 Sep 2019 10:07:18 -0400 Subject: [PATCH 09/15] remove console.log statements --- src/views/preview/project-view.jsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/views/preview/project-view.jsx b/src/views/preview/project-view.jsx index f98fe1083..7ffb8621a 100644 --- a/src/views/preview/project-view.jsx +++ b/src/views/preview/project-view.jsx @@ -123,17 +123,12 @@ class Preview extends React.Component { } componentDidMount () { this.addEventListeners(); - console.log(`componentDidMount: session status: ${this.props.sessionStatus}`); - } componentDidUpdate (prevProps, prevState) { - console.log(`componentDidUpdate: session status: ${this.props.sessionStatus}`); if (this.state.projectId > 0 && ((this.props.sessionStatus !== prevProps.sessionStatus && this.props.sessionStatus === sessionActions.Status.FETCHED) || (this.state.projectId !== prevState.projectId))) { - console.log("got here A"); - console.log(`this: ${this.state.projectId} prev: ${prevState.projectId}`); this.fetchCommunityData(); this.getProjectData(this.state.projectId, true /* Show cloud/username alerts */); if (this.state.justShared) { From 4a2553e8194ce92db215ef40a96b410cb7250b96 Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Mon, 30 Sep 2019 10:48:10 -0400 Subject: [PATCH 10/15] create sentry library for initing Sentry --- src/lib/sentry.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/lib/sentry.js diff --git a/src/lib/sentry.js b/src/lib/sentry.js new file mode 100644 index 000000000..b16cd03a9 --- /dev/null +++ b/src/lib/sentry.js @@ -0,0 +1,18 @@ +const initSentry = () => { + // initialize Sentry instance, making sure it hasn't been initialized already + if (!window.Sentry && `${process.env.SENTRY_DSN}` !== '') { + const Sentry = require('@sentry/browser'); + + Sentry.init({ + dsn: `${process.env.SENTRY_DSN}`, + // Do not collect global onerror, only collect specifically from React error boundaries. + // TryCatch plugin also includes errors from setTimeouts (i.e. the VM) + integrations: integrations => integrations.filter(i => + !(i.name === 'GlobalHandlers' || i.name === 'TryCatch')) + }); + + window.Sentry = Sentry; // Allow GUI access to Sentry via window + } +}; + +module.exports = initSentry; From 6772dc3b6d2a5ea836c2c6c5e9c912dd26c947b8 Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Mon, 30 Sep 2019 10:49:19 -0400 Subject: [PATCH 11/15] refactor project view and embed view to not use shared hoc --- src/views/preview/embed-view.jsx | 31 ++++++++++-- src/views/preview/project-view-hoc.jsx | 68 -------------------------- src/views/preview/project-view.jsx | 27 +++++----- 3 files changed, 41 insertions(+), 85 deletions(-) delete mode 100644 src/views/preview/project-view-hoc.jsx diff --git a/src/views/preview/embed-view.jsx b/src/views/preview/embed-view.jsx index 251ab0267..be3184d5b 100644 --- a/src/views/preview/embed-view.jsx +++ b/src/views/preview/embed-view.jsx @@ -1,24 +1,26 @@ // embed view -const bindAll = require('lodash.bindall'); const React = require('react'); const PropTypes = require('prop-types'); +const connect = require('react-redux').connect; const injectIntl = require('react-intl').injectIntl; -const ProjectViewHOC = require('./project-view-hoc.jsx'); const ErrorBoundary = require('../../components/errorboundary/errorboundary.jsx'); const projectShape = require('./projectshape.jsx').projectShape; const NotAvailable = require('../../components/not-available/not-available.jsx'); const Meta = require('./meta.jsx'); +const previewActions = require('../../redux/preview.js'); + const GUI = require('scratch-gui'); const IntlGUI = injectIntl(GUI.default); +const initSentry = require('../../lib/sentry.js'); +initSentry(); + class EmbedView extends React.Component { constructor (props) { super(props); - bindAll(this, [ - ]); const pathname = window.location.pathname.toLowerCase(); const parts = pathname.split('/').filter(Boolean); this.state = { @@ -65,7 +67,26 @@ EmbedView.propTypes = { projectNotAvailable: PropTypes.bool }; -module.exports.View = ProjectViewHOC(EmbedView); +EmbedView.defaultProps = { + assetHost: process.env.ASSET_HOST, + projectHost: process.env.PROJECT_HOST +}; + +const mapStateToProps = state => ({ + projectInfo: state.preview.projectInfo, + projectNotAvailable: state.preview.projectNotAvailable +}); + +const mapDispatchToProps = dispatch => ({ + getProjectInfo: (id, token) => { + dispatch(previewActions.getProjectInfo(id, token)); + } +}); + +module.exports.View = connect( + mapStateToProps, + mapDispatchToProps +)(EmbedView); GUI.setAppElement(document.getElementById('app')); module.exports.initGuiState = GUI.initEmbedded; diff --git a/src/views/preview/project-view-hoc.jsx b/src/views/preview/project-view-hoc.jsx deleted file mode 100644 index 7bae86eff..000000000 --- a/src/views/preview/project-view-hoc.jsx +++ /dev/null @@ -1,68 +0,0 @@ -const bindAll = require('lodash.bindall'); -const React = require('react'); -const PropTypes = require('prop-types'); -const connect = require('react-redux').connect; - -const previewActions = require('../../redux/preview.js'); - -/** - * Higher-order component for presenting a project view. - * @param {React.Component} Component a project view component - * @return {React.Component} a wrapped project view component - */ - -const ProjectViewHOC = Component => { - // initialize Sentry instance, making sure it hasn't been initialized already - if (!window.Sentry && `${process.env.SENTRY_DSN}` !== '') { - const Sentry = require('@sentry/browser'); - Sentry.init({ - dsn: `${process.env.SENTRY_DSN}`, - // Do not collect global onerror, only collect specifically from React error boundaries. - // TryCatch plugin also includes errors from setTimeouts (i.e. the VM) - integrations: integrations => integrations.filter(i => - !(i.name === 'GlobalHandlers' || i.name === 'TryCatch')) - }); - window.Sentry = Sentry; // Allow GUI access to Sentry via window - } - - class WrappedComponent extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - ]); - } - render () { - return (); - } - } - - WrappedComponent.propTypes = { - assetHost: PropTypes.string.isRequired, - projectHost: PropTypes.string.isRequired - }; - - WrappedComponent.defaultProps = { - assetHost: process.env.ASSET_HOST, - projectHost: process.env.PROJECT_HOST - }; - - const mapStateToProps = state => ({ - projectInfo: state.preview.projectInfo, - projectNotAvailable: state.preview.projectNotAvailable - }); - - const mapDispatchToProps = dispatch => ({ - getProjectInfo: (id, token) => { - dispatch(previewActions.getProjectInfo(id, token)); - } - }); - - return connect( - mapStateToProps, - mapDispatchToProps - )(WrappedComponent); -}; - -module.exports = ProjectViewHOC; diff --git a/src/views/preview/project-view.jsx b/src/views/preview/project-view.jsx index 7ffb8621a..cc192af46 100644 --- a/src/views/preview/project-view.jsx +++ b/src/views/preview/project-view.jsx @@ -14,7 +14,6 @@ const storage = require('../../lib/storage.js').default; const log = require('../../lib/log'); const jar = require('../../lib/jar.js'); const thumbnailUrl = require('../../lib/user-thumbnail'); -const ProjectViewHOC = require('./project-view-hoc.jsx'); const ProjectInfo = require('../../lib/project-info'); const PreviewPresentation = require('./presentation.jsx'); const projectShape = require('./projectshape.jsx').projectShape; @@ -36,6 +35,9 @@ const IntlGUI = injectIntl(GUI.default); const localStorageAvailable = 'localStorage' in window && window.localStorage !== null; +const initSentry = require('../../lib/sentry.js'); +initSentry(); + class Preview extends React.Component { constructor (props) { super(props); @@ -868,17 +870,17 @@ Preview.defaultProps = { userPresent: false }; -const mapStateToProps = (state, ownProps) => { - const projectInfoPresent = ownProps.projectInfo && - Object.keys(ownProps.projectInfo).length > 0 && ownProps.projectInfo.id > 0; +const mapStateToProps = state => { + const projectInfoPresent = state.preview.projectInfo && + Object.keys(state.preview.projectInfo).length > 0 && state.preview.projectInfo.id > 0; const userPresent = state.session.session.user !== null && typeof state.session.session.user !== 'undefined' && Object.keys(state.session.session.user).length > 0; const isLoggedIn = state.session.status === sessionActions.Status.FETCHED && userPresent; const isAdmin = isLoggedIn && state.session.session.permissions.admin; - const author = projectInfoPresent && ownProps.projectInfo.author; - const authorPresent = author && Object.keys(ownProps.projectInfo.author).length > 0; + const author = projectInfoPresent && state.preview.projectInfo.author; + const authorPresent = author && Object.keys(state.preview.projectInfo.author).length > 0; const authorId = authorPresent && author.id && author.id.toString(); const authorUsername = authorPresent && author.username; const userOwnsProject = isLoggedIn && authorPresent && @@ -888,7 +890,7 @@ const mapStateToProps = (state, ownProps) => { state.permissions.admin === true); // if we don't have projectInfo, assume it's shared until we know otherwise - const isShared = !projectInfoPresent || ownProps.projectInfo.is_published; + const isShared = !projectInfoPresent || state.preview.projectInfo.is_published; return { authorId: authorId, @@ -924,8 +926,8 @@ const mapStateToProps = (state, ownProps) => { original: state.preview.original, parent: state.preview.parent, playerMode: state.scratchGui.mode.isPlayerOnly, - projectInfo: ownProps.projectInfo, - projectNotAvailable: ownProps.projectNotAvailable, + projectInfo: state.preview.projectInfo, + projectNotAvailable: state.preview.projectNotAvailable, projectStudios: state.preview.projectStudios, registrationOpen: state.navigation.registrationOpen, remixes: state.preview.remixes, @@ -980,6 +982,9 @@ const mapDispatchToProps = dispatch => ({ getParentInfo: id => { dispatch(previewActions.getParentInfo(id)); }, + getProjectInfo: (id, token) => { + dispatch(previewActions.getProjectInfo(id, token)); + }, getRemixes: id => { dispatch(previewActions.getRemixes(id)); }, @@ -1050,13 +1055,11 @@ const mapDispatchToProps = dispatch => ({ } }); -const ConnectedPreview = connect( +module.exports.View = connect( mapStateToProps, mapDispatchToProps )(Preview); -module.exports.View = ProjectViewHOC(ConnectedPreview); - // replace old Scratch 2.0-style hashtag URLs with updated format if (window.location.hash) { let pathname = window.location.pathname; From 60ad7e5125f1b7e2c431fd3c7f162c7c6ac0cbb8 Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Mon, 30 Sep 2019 10:56:42 -0400 Subject: [PATCH 12/15] removed unnecessary return statement --- src/views/preview/project-view.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/preview/project-view.jsx b/src/views/preview/project-view.jsx index cc192af46..c41ec84ee 100644 --- a/src/views/preview/project-view.jsx +++ b/src/views/preview/project-view.jsx @@ -237,7 +237,7 @@ class Preview extends React.Component { } getProjectData (projectId, showAlerts) { if (projectId <= 0) return 0; - return storage + storage .load(storage.AssetType.Project, projectId, storage.DataFormat.JSON) .then(projectAsset => { // NOTE: this is turning up null, breaking the line below. let input = projectAsset.data; From 309e5a77e1833d746c2e200d9a53e0e9a73c694e Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Mon, 30 Sep 2019 23:57:11 -0400 Subject: [PATCH 13/15] try adding Page to make build succeed --- src/views/preview/embed.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/views/preview/embed.jsx b/src/views/preview/embed.jsx index cb2d9ba9b..f458948be 100644 --- a/src/views/preview/embed.jsx +++ b/src/views/preview/embed.jsx @@ -2,6 +2,9 @@ const React = require('react'); const ErrorBoundary = require('../../components/errorboundary/errorboundary.jsx'); const render = require('../../lib/render.jsx'); +// Require this even though we don't use it because, without it, webpack runs out of memory... +const Page = require('../../components/page/www/page.jsx'); // eslint-disable-line no-unused-vars + const previewActions = require('../../redux/preview.js'); const isSupportedBrowser = require('../../lib/supported-browser').default; From 06124331ccae76ba1a8e625f38fdb7a43960ce5d Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Tue, 1 Oct 2019 00:46:32 -0400 Subject: [PATCH 14/15] removing Page --- src/views/preview/embed.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/views/preview/embed.jsx b/src/views/preview/embed.jsx index f458948be..cb2d9ba9b 100644 --- a/src/views/preview/embed.jsx +++ b/src/views/preview/embed.jsx @@ -2,9 +2,6 @@ const React = require('react'); const ErrorBoundary = require('../../components/errorboundary/errorboundary.jsx'); const render = require('../../lib/render.jsx'); -// Require this even though we don't use it because, without it, webpack runs out of memory... -const Page = require('../../components/page/www/page.jsx'); // eslint-disable-line no-unused-vars - const previewActions = require('../../redux/preview.js'); const isSupportedBrowser = require('../../lib/supported-browser').default; From f9b436182bb3d78f032f1cfd9cfe1c4d8c9a8755 Mon Sep 17 00:00:00 2001 From: Ben Wheeler Date: Tue, 1 Oct 2019 18:21:14 -0400 Subject: [PATCH 15/15] Revert "removing Page" This reverts commit 06124331ccae76ba1a8e625f38fdb7a43960ce5d. --- src/views/preview/embed.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/views/preview/embed.jsx b/src/views/preview/embed.jsx index cb2d9ba9b..f458948be 100644 --- a/src/views/preview/embed.jsx +++ b/src/views/preview/embed.jsx @@ -2,6 +2,9 @@ const React = require('react'); const ErrorBoundary = require('../../components/errorboundary/errorboundary.jsx'); const render = require('../../lib/render.jsx'); +// Require this even though we don't use it because, without it, webpack runs out of memory... +const Page = require('../../components/page/www/page.jsx'); // eslint-disable-line no-unused-vars + const previewActions = require('../../redux/preview.js'); const isSupportedBrowser = require('../../lib/supported-browser').default;