Skip to content

Commit 1fd9a1f

Browse files
author
Christopher Willis-Ford
committed
Merge branch 'develop' into load-library-images-through-storage
2 parents f773ee2 + 33f3d1d commit 1fd9a1f

File tree

9 files changed

+110
-20
lines changed

9 files changed

+110
-20
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,13 @@
106106
"redux-throttle": "0.1.1",
107107
"rimraf": "^2.6.1",
108108
"scratch-audio": "0.1.0-prerelease.20190114210212",
109-
"scratch-blocks": "0.1.0-prerelease.1551865183",
109+
"scratch-blocks": "0.1.0-prerelease.1552509492",
110110
"scratch-l10n": "3.1.20190220143732",
111111
"scratch-paint": "0.2.0-prerelease.20190311150519",
112112
"scratch-render": "0.1.0-prerelease.20190312125229",
113113
"scratch-storage": "1.2.2",
114114
"scratch-svg-renderer": "0.2.0-prerelease.20190304180800",
115-
"scratch-vm": "0.2.0-prerelease.20190312212117",
115+
"scratch-vm": "0.2.0-prerelease.20190314020908",
116116
"selenium-webdriver": "3.6.0",
117117
"startaudiocontext": "1.2.1",
118118
"style-loader": "^0.23.0",

src/components/gui/gui.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ const GUIComponent = props => {
9797
onActivateTab,
9898
onClickLogo,
9999
onExtensionButtonClick,
100+
onProjectTelemetryEvent,
100101
onRequestCloseBackdropLibrary,
101102
onRequestCloseCostumeLibrary,
102103
onRequestCloseTelemetryModal,
@@ -217,6 +218,7 @@ const GUIComponent = props => {
217218
onCloseAccountNav={onCloseAccountNav}
218219
onLogOut={onLogOut}
219220
onOpenRegistration={onOpenRegistration}
221+
onProjectTelemetryEvent={onProjectTelemetryEvent}
220222
onSeeCommunity={onSeeCommunity}
221223
onShare={onShare}
222224
onToggleLoginOpen={onToggleLoginOpen}

src/components/library-item/library-item.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@
178178
font-weight: bold;
179179
}
180180

181+
.featured-extension-metadata-detail img{
182+
margin-right: 0.25rem;
183+
}
184+
181185
.coming-soon-text {
182186
position: absolute;
183187
background-color: $data-primary;

src/components/library-item/library-item.jsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,12 @@ class LibraryItemComponent extends React.PureComponent {
7575
<div
7676
className={styles.featuredExtensionMetadataDetail}
7777
>
78-
<img
79-
src={this.props.bluetoothRequired ?
80-
bluetoothIconURL :
81-
internetConnectionIconURL
82-
}
83-
/>
78+
{this.props.bluetoothRequired ? (
79+
<img src={bluetoothIconURL} />
80+
) : null}
81+
{this.props.internetConnectionRequired ? (
82+
<img src={internetConnectionIconURL} />
83+
) : null}
8484
</div>
8585
</div>
8686
) : null}

src/components/menu-bar/menu-bar.jsx

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import bindAll from 'lodash.bindall';
66
import bowser from 'bowser';
77
import React from 'react';
88

9+
import VM from 'scratch-vm';
10+
911
import Box from '../box/box.jsx';
1012
import Button from '../button/button.jsx';
1113
import CommunityButton from './community-button.jsx';
@@ -55,6 +57,8 @@ import {
5557
loginMenuOpen
5658
} from '../../reducers/menus';
5759

60+
import collectMetadata from '../../lib/collect-metadata';
61+
5862
import styles from './menu-bar.css';
5963

6064
import helpIcon from '../../lib/assets/icon--tutorials.svg';
@@ -146,10 +150,10 @@ class MenuBar extends React.Component {
146150
'handleClickSaveAsCopy',
147151
'handleClickSeeCommunity',
148152
'handleClickShare',
149-
'handleCloseFileMenuAndThen',
150153
'handleKeyPress',
151154
'handleLanguageMouseUp',
152155
'handleRestoreOption',
156+
'handleSaveToComputer',
153157
'restoreOptionMessage'
154158
]);
155159
}
@@ -216,19 +220,23 @@ class MenuBar extends React.Component {
216220
this.props.onRequestCloseEdit();
217221
};
218222
}
219-
handleCloseFileMenuAndThen (fn) {
220-
return () => {
221-
this.props.onRequestCloseFile();
222-
fn();
223-
};
224-
}
225223
handleKeyPress (event) {
226224
const modifier = bowser.mac ? event.metaKey : event.ctrlKey;
227225
if (modifier && event.key === 's') {
228226
this.props.onClickSave();
229227
event.preventDefault();
230228
}
231229
}
230+
handleSaveToComputer (downloadProjectCallback) {
231+
return () => {
232+
this.props.onRequestCloseFile();
233+
downloadProjectCallback();
234+
if (this.props.onProjectTelemetryEvent) {
235+
const metadata = collectMetadata(this.props.vm, this.props.projectTitle, this.props.locale);
236+
this.props.onProjectTelemetryEvent('projectDidSave', metadata);
237+
}
238+
};
239+
}
232240
handleLanguageMouseUp (e) {
233241
if (!this.props.languageMenuOpen) {
234242
this.props.onClickLanguage(e);
@@ -402,10 +410,10 @@ class MenuBar extends React.Component {
402410
</MenuItem>
403411
)}
404412
</SBFileUploader>
405-
<SB3Downloader>{(className, downloadProject) => (
413+
<SB3Downloader>{(className, downloadProjectCallback) => (
406414
<MenuItem
407415
className={className}
408-
onClick={this.handleCloseFileMenuAndThen(downloadProject)}
416+
onClick={this.handleSaveToComputer(downloadProjectCallback)}
409417
>
410418
<FormattedMessage
411419
defaultMessage="Save to your computer"
@@ -743,6 +751,7 @@ MenuBar.propTypes = {
743751
onLogOut: PropTypes.func,
744752
onOpenRegistration: PropTypes.func,
745753
onOpenTipLibrary: PropTypes.func,
754+
onProjectTelemetryEvent: PropTypes.func,
746755
onRequestCloseAccount: PropTypes.func,
747756
onRequestCloseEdit: PropTypes.func,
748757
onRequestCloseFile: PropTypes.func,
@@ -757,7 +766,8 @@ MenuBar.propTypes = {
757766
renderLogin: PropTypes.func,
758767
sessionExists: PropTypes.bool,
759768
showComingSoon: PropTypes.bool,
760-
username: PropTypes.string
769+
username: PropTypes.string,
770+
vm: PropTypes.instanceOf(VM).isRequired
761771
};
762772

763773
MenuBar.defaultProps = {
@@ -775,11 +785,13 @@ const mapStateToProps = state => {
775785
isUpdating: getIsUpdating(loadingState),
776786
isShowingProject: getIsShowingProject(loadingState),
777787
languageMenuOpen: languageMenuOpen(state),
788+
locale: state.locales.locale,
778789
loginMenuOpen: loginMenuOpen(state),
779790
projectChanged: state.scratchGui.projectChanged,
780791
projectTitle: state.scratchGui.projectTitle,
781792
sessionExists: state.session && typeof state.session.session !== 'undefined',
782-
username: user ? user.username : null
793+
username: user ? user.username : null,
794+
vm: state.scratchGui.vm
783795
};
784796
};
785797

src/lib/collect-metadata.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Report a telemetry event.
3+
* @param {string} event - one of `projectWasCreated`, `projectDidLoad`, `projectDidSave`, `projectWasUploaded`
4+
*/
5+
// TODO make a telemetry HOC and move this stuff there
6+
const collectMetadata = function (vm, projectName = '', locale = '') {
7+
// TODO move most or all of this into a collectMetadata() method on the VM/Runtime
8+
const metadata = {
9+
projectName: projectName,
10+
language: locale,
11+
spriteCount: 0,
12+
blocksCount: 0,
13+
costumesCount: 0,
14+
listsCount: 0,
15+
scriptCount: 0,
16+
soundsCount: 0,
17+
variablesCount: 0
18+
};
19+
20+
for (const target of vm.runtime.targets) {
21+
++metadata.spriteCount;
22+
metadata.blocksCount += Object.keys(target.sprite.blocks._blocks).length;
23+
metadata.costumesCount += target.sprite.costumes_.length;
24+
metadata.scriptCount += target.sprite.blocks._scripts.length;
25+
metadata.soundsCount += target.sprite.sounds.length;
26+
for (const variableName in target.variables) {
27+
const variable = target.variables[variableName];
28+
if (variable.type === 'list') {
29+
++metadata.listsCount;
30+
} else {
31+
++metadata.variablesCount;
32+
}
33+
}
34+
}
35+
36+
return metadata;
37+
};
38+
39+
export default collectMetadata;

src/lib/libraries/extensions/index.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ export default [
163163
featured: true,
164164
disabled: false,
165165
bluetoothRequired: true,
166+
internetConnectionRequired: true,
166167
launchPeripheralConnectionFlow: true,
167168
useAutoScan: false,
168169
peripheralImage: microbitPeripheralImage,
@@ -192,6 +193,7 @@ export default [
192193
featured: true,
193194
disabled: false,
194195
bluetoothRequired: true,
196+
internetConnectionRequired: true,
195197
launchPeripheralConnectionFlow: true,
196198
useAutoScan: false,
197199
peripheralImage: ev3PeripheralImage,
@@ -221,6 +223,7 @@ export default [
221223
featured: true,
222224
disabled: false,
223225
bluetoothRequired: true,
226+
internetConnectionRequired: true,
224227
launchPeripheralConnectionFlow: true,
225228
useAutoScan: true,
226229
peripheralImage: wedoPeripheralImage,
@@ -250,6 +253,7 @@ export default [
250253
),
251254
featured: true,
252255
disabled: true,
253-
bluetoothRequired: true
256+
bluetoothRequired: true,
257+
internetConnectionRequired: true
254258
}
255259
];

src/lib/project-saver-hoc.jsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {connect} from 'react-redux';
66
import VM from 'scratch-vm';
77
import xhr from 'xhr';
88

9+
import collectMetadata from '../lib/collect-metadata';
910
import log from '../lib/log';
1011
import storage from '../lib/storage';
1112
import dataURItoBlob from '../lib/data-uri-to-blob';
@@ -25,6 +26,7 @@ import {
2526
getIsAnyCreatingNewState,
2627
getIsCreatingCopy,
2728
getIsCreatingNew,
29+
getIsLoading,
2830
getIsManualUpdating,
2931
getIsRemixing,
3032
getIsShowingWithId,
@@ -61,6 +63,13 @@ const ProjectSaverHOC = function (WrappedComponent) {
6163
this.props.onSetProjectThumbnailer(this.getProjectThumbnail);
6264
}
6365
componentDidUpdate (prevProps) {
66+
if (!this.props.isAnyCreatingNewState && prevProps.isAnyCreatingNewState) {
67+
this.reportTelemetryEvent('projectWasCreated');
68+
}
69+
if (!this.props.isLoading && prevProps.isLoading) {
70+
this.reportTelemetryEvent('projectDidLoad');
71+
}
72+
6473
if (this.props.projectChanged && !prevProps.projectChanged) {
6574
this.scheduleAutoSave();
6675
}
@@ -305,6 +314,18 @@ const ProjectSaverHOC = function (WrappedComponent) {
305314
this.props.vm.renderer.draw();
306315
}
307316

317+
/**
318+
* Report a telemetry event.
319+
* @param {string} event - one of `projectWasCreated`, `projectDidLoad`, `projectDidSave`, `projectWasUploaded`
320+
*/
321+
// TODO make a telemetry HOC and move this stuff there
322+
reportTelemetryEvent (event) {
323+
if (this.props.onProjectTelemetryEvent) {
324+
const metadata = collectMetadata(this.props.vm, this.props.reduxProjectTitle, this.props.locale);
325+
this.props.onProjectTelemetryEvent(event, metadata);
326+
}
327+
}
328+
308329
render () {
309330
const {
310331
/* eslint-disable no-unused-vars */
@@ -314,6 +335,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
314335
isCreatingNew,
315336
projectChanged,
316337
isAnyCreatingNewState,
338+
isLoading,
317339
isManualUpdating,
318340
isRemixing,
319341
isShowingSaveable,
@@ -359,6 +381,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
359381
isAnyCreatingNewState: PropTypes.bool,
360382
isCreatingCopy: PropTypes.bool,
361383
isCreatingNew: PropTypes.bool,
384+
isLoading: PropTypes.bool,
362385
isManualUpdating: PropTypes.bool,
363386
isRemixing: PropTypes.bool,
364387
isShared: PropTypes.bool,
@@ -371,6 +394,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
371394
onCreateProject: PropTypes.func,
372395
onCreatedProject: PropTypes.func,
373396
onProjectError: PropTypes.func,
397+
onProjectTelemetryEvent: PropTypes.func,
374398
onRemixing: PropTypes.func,
375399
onShowAlert: PropTypes.func,
376400
onShowCopySuccessAlert: PropTypes.func,
@@ -397,6 +421,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
397421
return {
398422
autoSaveTimeoutId: state.scratchGui.timeout.autoSaveTimeoutId,
399423
isAnyCreatingNewState: getIsAnyCreatingNewState(loadingState),
424+
isLoading: getIsLoading(loadingState),
400425
isCreatingCopy: getIsCreatingCopy(loadingState),
401426
isCreatingNew: getIsCreatingNew(loadingState),
402427
isRemixing: getIsRemixing(loadingState),
@@ -406,6 +431,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
406431
isUpdating: getIsUpdating(loadingState),
407432
isManualUpdating: getIsManualUpdating(loadingState),
408433
loadingState: loadingState,
434+
locale: state.locales.locale,
409435
projectChanged: state.scratchGui.projectChanged,
410436
reduxProjectId: state.scratchGui.projectState.projectId,
411437
reduxProjectTitle: state.scratchGui.projectTitle,

test/unit/util/project-saver-hoc.test.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ describe('projectSaverHOC', () => {
2222
timeout: {
2323
autoSaveTimeoutId: null
2424
}
25+
},
26+
locales: {
27+
locale: 'en'
2528
}
2629
});
2730
vm = new VM();

0 commit comments

Comments
 (0)