Skip to content

Commit 0680ea4

Browse files
author
Josh Lory
committed
Merge branch 'staging' into rubocop-fixes
# Conflicts: # dashboard/test/models/script_test.rb
2 parents e79c5e9 + 6899d3f commit 0680ea4

237 files changed

Lines changed: 2838 additions & 698 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.rubocop.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ Style/AlignParameters:
1919
Style/DotPosition:
2020
EnforcedStyle: trailing
2121

22+
Style/EmptyElse:
23+
EnforcedStyle: empty
24+
2225
Style/EmptyLineBetweenDefs:
2326
AllowAdjacentOneLineDefs: true
2427

.rubocop_todo.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,6 @@ Style/DefWithParentheses:
151151
Style/DeprecatedHashMethods:
152152
Enabled: false
153153

154-
# Offense count: 8
155-
# Cop supports --auto-correct.
156-
# Configuration parameters: EnforcedStyle, SupportedStyles.
157-
# SupportedStyles: empty, nil, both
158-
Style/EmptyElse:
159-
Enabled: false
160-
161154
# Offense count: 27
162155
# Cop supports --auto-correct.
163156
Style/EmptyLinesAroundAccessModifier:

apps/Gruntfile.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ module.exports = function (grunt) {
4040
var PLAYGROUND_PORT = grunt.option('playground-port') || 8000;
4141

4242
/** @const {string} */
43-
var APP_TO_BUILD = grunt.option('app') || process.env.MOOC_APP;
43+
var APP_TO_BUILD = grunt.option('app') || process.env.APP || process.env.MOOC_APP;
44+
if (process.env.MOOC_APP) {
45+
console.warn('The MOOC_APP environment variable is deprecated. Use APP instead');
46+
}
4447

4548
/** @const {string[]} */
4649
var APPS = [
@@ -67,9 +70,12 @@ module.exports = function (grunt) {
6770

6871
// Parse options from environment.
6972
var envOptions = {
70-
dev: (process.env.MOOC_DEV === '1'),
73+
dev: (process.env.MOOC_DEV === '1' || process.env.DEV === '1'),
7174
autoReload: ['true', '1'].indexOf(process.env.AUTO_RELOAD) !== -1
7275
};
76+
if (process.env.MOOC_DEV) {
77+
console.warn('The MOOC_DEV environment variable is deprecated. Use DEV instead');
78+
}
7379

7480
config.clean = {
7581
all: ['build']
@@ -308,10 +314,13 @@ module.exports = function (grunt) {
308314
convertScssVars: './script/convert-scss-variables.js',
309315
};
310316

317+
if (process.env.MOOC_WATCH) {
318+
console.warn('The MOOC_WATCH environment variable is deprecated. Use WATCH instead');
319+
}
311320
config.karma = {
312321
options: {
313322
configFile: 'karma.conf.js',
314-
singleRun: process.env.MOOC_WATCH !== '1',
323+
singleRun: process.env.WATCH !== '1',
315324
files: [
316325
{pattern: 'test/audio/**/*', watched: false, included: false, nocache: true},
317326
{pattern: 'test/integration/**/*', watched: false, included: false, nocache: true},
@@ -360,6 +369,7 @@ module.exports = function (grunt) {
360369
if (entries.applab) {
361370
entries['applab-api'] = './src/applab/api-entry.js';
362371
}
372+
entries['styleguide'] = './src/styleguide-entry.js';
363373
config.webpack = {
364374
build: _.extend({}, webpackConfig, {
365375
output: {
@@ -371,7 +381,7 @@ module.exports = function (grunt) {
371381
plugins: [
372382
new webpack.DefinePlugin({
373383
IN_UNIT_TEST: JSON.stringify(false),
374-
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
384+
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
375385
PISKEL_DEVELOPMENT_MODE: PISKEL_DEVELOPMENT_MODE
376386
}),
377387
new webpack.optimize.CommonsChunkPlugin({

apps/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Since the longer the polling is, the longer the delay before builds can be, we'l
9595
To have grunt rebuild on changes but not run an express server, you can use the constituent commands:
9696

9797
```
98-
MOOC_DEV=1 grunt build watch
98+
DEV=1 grunt build watch
9999
```
100100

101101
#### Running tests
@@ -116,10 +116,10 @@ npm run test:entry -- --entry ./test/unit/gridUtilsTest.js
116116
##### Rerun Tests Automatically #####
117117

118118
To rerun tests automatically on every file change, set the environment variable
119-
`MOOC_WATCH=1`:
119+
`WATCH=1`:
120120

121121
```
122-
MOOC_WATCH=1 npm run test:unit
122+
WATCH=1 npm run test:unit
123123
```
124124

125125
This will work on any of the test commands.
@@ -129,10 +129,10 @@ This will work on any of the test commands.
129129
To debug tests, your best bet is to run them in Chrome. Keep in mind that there
130130
can be subtle differences between Chrome and PhantomJS, so after fixing your
131131
test in Chrome, make sure it still works in PhantomJS. To run the tests in
132-
Chrome, use the `MOOC_BROWSER` environment variable in conjunction with `MOOC_WATCH`:
132+
Chrome, use the `BROWSER` environment variable in conjunction with `WATCH`:
133133

134134
```
135-
MOOC_BROWSER=Chrome MOOC_WATCH=1 npm run test:unit
135+
BROWSER=Chrome WATCH=1 npm run test:unit
136136
```
137137

138138
A new chrome browser window will open where the tests will be running. You can

apps/firebase/rules.bolt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,19 @@ type RateLimitCounter {
8585

8686
type Storage {
8787
tables: TableStorage[]
88-
keys: String[]
88+
keys: KeyValue[]
89+
}
90+
91+
type KeyValue extends String {
92+
validate() { this.length <= root.v3.config.channels.maxPropertySize}
8993
}
9094

9195
type TableStorage {
92-
records: String[]
96+
records: Record[]
97+
}
98+
99+
type Record extends String {
100+
validate() { this.length <= root.v3.config.channels.maxRecordSize}
93101
}
94102

95103
///////////////////////////////////////////////////////////////////////////

apps/karma.conf.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ module.exports = function (config) {
112112
// start these browsers
113113
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
114114
browsers: [
115-
process.env.MOOC_BROWSER || 'PhantomJS'
115+
process.env.BROWSER || 'PhantomJS'
116116
],
117117

118118

apps/package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
"test:integration": "grunt integrationTest",
1616
"test:entry": "grunt karma:entry",
1717
"clean": "grunt clean",
18-
"build": "MOOC_DEV=1 grunt build && grunt logBuildTimes",
19-
"build:dist": "NODE_ENV=production MOOC_DEV=0 grunt clean build && grunt logBuildTimes",
20-
"start": "MOOC_DEV=1 grunt dev; grunt logBuildTimes",
21-
"start:applab": "MOOC_DEV=1 grunt dev --app=applab; grunt logBuildTimes",
22-
"start:gamelab": "MOOC_DEV=1 grunt dev --app=gamelab; grunt logBuildTimes",
18+
"build": "DEV=1 grunt build && grunt logBuildTimes",
19+
"build:dist": "NODE_ENV=production DEV=0 grunt clean build && grunt logBuildTimes",
20+
"start": "DEV=1 grunt dev; grunt logBuildTimes",
21+
"start:applab": "DEV=1 grunt dev --app=applab; grunt logBuildTimes",
22+
"start:gamelab": "DEV=1 grunt dev --app=gamelab; grunt logBuildTimes",
2323
"test-audio": "echo \"Open your browser to http://127.0.0.1:8080/test/audio/audio_test.html\" && http-server .",
2424
"build:log": "grunt logBuildTimes",
2525
"build:stats": "node ./script/build-stats.js"
@@ -145,6 +145,7 @@
145145
"require-globify": "1.2.1",
146146
"rgbcolor": "0.0.4",
147147
"sanitize-html": "^1.11.3",
148+
"script-loader": "^0.7.0",
148149
"seedrandom": "2.4.2",
149150
"sinon": "^2.0.0-pre",
150151
"sprintf-js": "^1.0.3",

apps/src/JSInterpreter.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,9 @@ JSInterpreter.prototype.patchInterpreterMethods_ = function () {
171171
* can be added with calls to createGlobalProperty()
172172
*/
173173
JSInterpreter.prototype.parse = function (options) {
174-
if (!this.studioApp.hideSource) {
175-
this.calculateCodeInfo(options.code);
174+
this.calculateCodeInfo(options.code);
176175

176+
if (!this.studioApp.hideSource) {
177177
var session = this.studioApp.editor.aceEditor.getSession();
178178
this.isBreakpointRow = codegen.isAceBreakpointRow.bind(null, session);
179179
} else {

apps/src/StudioApp.js

Lines changed: 34 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ var AuthoredHints = require('./authoredHints');
2727
var Instructions = require('./templates/instructions/Instructions');
2828
var DialogButtons = require('./templates/DialogButtons');
2929
var WireframeSendToPhone = require('./templates/WireframeSendToPhone');
30+
import InstructionsDialogWrapper from './templates/instructions/InstructionsDialogWrapper';
31+
import DialogInstructions from './templates/instructions/DialogInstructions';
3032
var assetsApi = require('./clientApi').assets;
3133
var assetPrefix = require('./assetManagement/assetPrefix');
3234
var annotationList = require('./acemode/annotationList');
@@ -35,11 +37,16 @@ var shareWarnings = require('./shareWarnings');
3537
import { setPageConstants } from './redux/pageConstants';
3638

3739
var redux = require('./redux');
40+
import { Provider } from 'react-redux';
3841
import {
3942
substituteInstructionImages,
4043
determineInstructionsConstants,
4144
setInstructionsConstants
4245
} from './redux/instructions';
46+
import {
47+
openDialog as openInstructionsDialog,
48+
closeDialog as closeInstructionsDialog
49+
} from './redux/instructionsDialog';
4350
import { setIsRunning } from './redux/runState';
4451
var commonReducers = require('./redux/commonReducers');
4552
var combineReducers = require('redux').combineReducers;
@@ -325,6 +332,17 @@ StudioApp.prototype.init = function (config) {
325332

326333
this.configureDom(config);
327334

335+
ReactDOM.render(
336+
<Provider store={this.reduxStore}>
337+
<InstructionsDialogWrapper
338+
showInstructionsDialog={(autoClose, showHints) => {
339+
this.showInstructionsDialog_(config.level, autoClose, showHints);
340+
}}
341+
/>
342+
</Provider>,
343+
document.body.appendChild(document.createElement('div'))
344+
);
345+
328346
if (config.usesAssets) {
329347
assetPrefix.init(config);
330348

@@ -424,7 +442,7 @@ StudioApp.prototype.init = function (config) {
424442
return;
425443
}
426444
var shouldAutoClose = !!config.level.aniGifURL;
427-
this.showInstructionsDialog_(config.level, shouldAutoClose, false);
445+
this.reduxStore.dispatch(openInstructionsDialog(shouldAutoClose, false));
428446
}.bind(this));
429447
}
430448

@@ -609,21 +627,6 @@ StudioApp.prototype.configureHints_ = function (config) {
609627
return;
610628
}
611629

612-
var bubble = document.getElementById('bubble');
613-
if (bubble) {
614-
dom.addClickTouchEvent(bubble, function () {
615-
const reduxState = this.reduxStore.getState();
616-
const instructionsInTopPane = reduxState.pageConstants.instructionsInTopPane;
617-
const hasAuthoredHints = reduxState.instructions.hasAuthoredHints;
618-
619-
// Don't show dialog on click in top pane unless we have hints
620-
if (instructionsInTopPane && !hasAuthoredHints) {
621-
return;
622-
}
623-
this.showInstructionsDialog_(config.level, false, true);
624-
}.bind(this));
625-
}
626-
627630
var promptIcon = document.getElementById('prompt-icon');
628631
this.authoredHintsController_.display(promptIcon);
629632
};
@@ -1077,44 +1080,8 @@ StudioApp.prototype.onReportComplete = function (response) {
10771080
};
10781081

10791082
/**
1080-
* @param {string} [puzzleTitle] - Optional param that only gets used if we dont
1081-
* have markdown instructions
1082-
* @param {object} level
1083-
* @param {boolean} showHints
1084-
* @returns {React.element}
1085-
*/
1086-
StudioApp.prototype.getInstructionsContent_ = function (puzzleTitle, level, showHints) {
1087-
var renderedMarkdown;
1088-
1089-
var longInstructions = this.reduxStore.getState().instructions.longInstructions;
1090-
1091-
// longInstructions will be undefined if non-english
1092-
if (longInstructions) {
1093-
var markdownWithImages = substituteInstructionImages(longInstructions,
1094-
this.skin.instructions2ImageSubstitutions);
1095-
renderedMarkdown = processMarkdown(markdownWithImages);
1096-
}
1097-
1098-
var authoredHints;
1099-
if (showHints) {
1100-
authoredHints = this.authoredHintsController_.getHintsDisplay();
1101-
}
1102-
1103-
return (
1104-
<Instructions
1105-
puzzleTitle={puzzleTitle}
1106-
instructions={substituteInstructionImages(level.instructions,
1107-
this.skin.instructions2ImageSubstitutions)}
1108-
instructions2={substituteInstructionImages(level.instructions2,
1109-
this.skin.instructions2ImageSubstitutions)}
1110-
renderedMarkdown={renderedMarkdown}
1111-
markdownClassicMargins={level.markdownInstructionsWithClassicMargins}
1112-
aniGifURL={level.aniGifURL}
1113-
authoredHints={authoredHints}/>
1114-
);
1115-
};
1116-
1117-
/**
1083+
* Show our instructions dialog. This should never be called directly, and will
1084+
* instead be called when the state of our redux store changes.
11181085
* @param {object} level
11191086
* @param {boolean} autoClose - closes instructions after 32s if true
11201087
* @param {boolean} showHints
@@ -1145,9 +1112,6 @@ StudioApp.prototype.showInstructionsDialog_ = function (level, autoClose, showHi
11451112
}
11461113
}
11471114

1148-
var instructionsContent = this.getInstructionsContent_(puzzleTitle, level,
1149-
showHints);
1150-
11511115
// Create a div to eventually hold this content, and add it to the
11521116
// overall container. We don't want to render directly into the
11531117
// container just yet, because our React component could contain some
@@ -1188,6 +1152,9 @@ StudioApp.prototype.showInstructionsDialog_ = function (level, autoClose, showHi
11881152
var event = document.createEvent('Event');
11891153
event.initEvent('instructionsHidden', true, true);
11901154
document.dispatchEvent(event);
1155+
1156+
// update redux
1157+
this.reduxStore.dispatch(closeInstructionsDialog());
11911158
}, this);
11921159

11931160
this.instructionsDialog = this.createModalDialog({
@@ -1201,10 +1168,17 @@ StudioApp.prototype.showInstructionsDialog_ = function (level, autoClose, showHi
12011168
header: headerElement
12021169
});
12031170

1171+
const authoredHints = showHints ?
1172+
this.authoredHintsController_.getHintsDisplay() : undefined;
1173+
12041174
// Now that our elements are guaranteed to be in the DOM, we can
12051175
// render in our react components
1206-
$(this.instructionsDialog.div).on('show.bs.modal', function () {
1207-
ReactDOM.render(instructionsContent, instructionsReactContainer);
1176+
$(this.instructionsDialog.div).on('show.bs.modal', () => {
1177+
ReactDOM.render(
1178+
<Provider store={this.reduxStore}>
1179+
<DialogInstructions authoredHints={authoredHints}/>
1180+
</Provider>,
1181+
instructionsReactContainer);
12081182
});
12091183

12101184
if (autoClose) {
@@ -2762,6 +2736,7 @@ StudioApp.prototype.setPageConstants = function (config, appSpecificConstants) {
27622736
isShareView: !!config.share,
27632737
pinWorkspaceToBottom: !!config.pinWorkspaceToBottom,
27642738
instructionsInTopPane: !!config.showInstructionsInTopPane,
2739+
hasContainedLevels: config.hasContainedLevels,
27652740
puzzleNumber: level.puzzle_number,
27662741
stageTotal: level.stage_total,
27672742
noVisualization: false,

apps/src/applab/applab.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,10 @@ Applab.init = function (config) {
557557

558558
config.runButtonClickWrapper = runButtonClickWrapper;
559559

560+
if (!config.channel) {
561+
throw new Error('Cannot initialize App Lab without a channel id. ' +
562+
'You may need to sign in to your code studio account first.');
563+
}
560564
Applab.channelId = config.channel;
561565
Applab.firebaseName = config.firebaseName;
562566
Applab.firebaseAuthToken = config.firebaseAuthToken;

0 commit comments

Comments
 (0)