Skip to content

Commit

Permalink
Merge pull request #30526 from code-dot-org/starter-assets-4
Browse files Browse the repository at this point in the history
Populate starter assets with real data
  • Loading branch information
Madelyn Kasula committed Sep 3, 2019
2 parents ddfbaa1 + 18376eb commit 03d0905
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 5 deletions.
8 changes: 8 additions & 0 deletions apps/src/applab/applab.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,14 @@ Applab.init = function(config) {
);
config.getGeneratedProperties = getGeneratedProperties;

// Set information about the current Applab level being displayed.
getStore().dispatch(
actions.setLevelData({
name: config.level.name,
isStartMode: config.isStartMode
})
);

// replace studioApp methods with our own
studioApp().reset = this.reset.bind(this);
studioApp().runButtonClick = this.runButtonClick.bind(this);
Expand Down
32 changes: 30 additions & 2 deletions apps/src/applab/redux/applab.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const REDIRECT_RESPONSE = {
const CHANGE_INTERFACE_MODE = 'applab/CHANGE_INTERFACE_MODE';
const ADD_REDIRECT_NOTICE = 'applab/ADD_REDIRECT_NOTICE';
const DISMISS_REDIRECT_NOTICE = 'applab/DISMISS_REDIRECT_NOTICE';
const SET_LEVEL_DATA = 'applab/SET_LEVEL_DATA';

/**
* Change the interface mode between Design Mode and Code Mode
Expand Down Expand Up @@ -59,10 +60,22 @@ function dismissRedirectNotice() {
};
}

/**
* Store data about the current Applab level (e.g., level name).
* @returns {{type: string, levelData: object}}
*/
function setLevelData(data) {
return {
type: SET_LEVEL_DATA,
data
};
}

export const actions = {
changeInterfaceMode,
addRedirectNotice,
dismissRedirectNotice
dismissRedirectNotice,
setLevelData
};

// Reducers
Expand Down Expand Up @@ -102,11 +115,26 @@ function redirectDisplay(state, action) {
}
}

function level(state, action) {
state = state || {};

switch (action.type) {
case SET_LEVEL_DATA:
return {
...state,
...action.data
};
default:
return state;
}
}

export const reducers = {
...jsDebuggerReducers,
maker,
data,
interfaceMode,
redirectDisplay,
screens
screens,
level
};
23 changes: 23 additions & 0 deletions apps/src/assetManagement/assetPrefix.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {unicode} from '@cdo/apps/code-studio/components/icons';
import {getStore} from '@cdo/apps/redux';

// For proxying non-https assets
const MEDIA_PROXY = '//' + location.host + '/media?u=';
Expand All @@ -18,6 +19,11 @@ export const ICON_PREFIX_REGEX = new RegExp('^icon://');
export const SOUND_PREFIX = 'sound://';
export const SOUND_PREFIX_REGEX = new RegExp('^sound://');

// Starter assets are currently only used for image assets, but may be extended
// in the future, where we will want to change this prefix.
export const STARTER_ASSET_PREFIX = 'image://';
export const STARTER_ASSET_PREFIX_REGEX = new RegExp('^image://');

const DEFAULT_ASSET_PATH_PREFIX = '/v3/assets/';
export const DEFAULT_SOUND_PATH_PREFIX = '/api/v1/sound-library/';
const DEFAULT_CHANNEL_ID = undefined;
Expand Down Expand Up @@ -71,6 +77,14 @@ export function fixPath(filename) {
return filename.replace(SOUND_PREFIX, soundPathPrefix);
}

if (STARTER_ASSET_PREFIX_REGEX.test(filename)) {
const state = getStore().getState();
return filename.replace(
STARTER_ASSET_PREFIX,
starterAssetPathPrefix(state.level.name)
);
}

if (filename.indexOf('/') !== -1 || !channelId) {
return filename;
}
Expand All @@ -81,6 +95,15 @@ export function fixPath(filename) {
return assetPathPrefix + channelId + '/' + encodeURIComponent(filename);
}

/**
* Get path prefix for starter assets, given a level name.
* @param levelName {string}
* @return {string}
*/
function starterAssetPathPrefix(levelName) {
return `/level_starter_assets/${levelName}/`;
}

/**
* Create a data-URI with the image data of the given icon glyph.
* @param value {string} An icon identifier of the format "icon://fa-icon-name".
Expand Down
8 changes: 7 additions & 1 deletion apps/src/code-studio/components/AssetManager.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import AudioRecorder from './AudioRecorder';
import firehoseClient from '@cdo/apps/lib/util/firehose';
import AddAssetButtonRow from './AddAssetButtonRow';
import i18n from '@cdo/locale';
import {STARTER_ASSET_PREFIX} from '@cdo/apps/assetManagement/assetPrefix';

export const AudioErrorType = {
NONE: 'none',
Expand Down Expand Up @@ -257,7 +258,12 @@ export default class AssetManager extends React.Component {
<AssetRow
{...this.defaultAssetProps(asset)}
api={boundApi}
onChoose={() => console.log('choose!')}
onChoose={() =>
this.props.assetChosen(
STARTER_ASSET_PREFIX + asset.filename,
asset.timestamp
)
}
onDelete={() => this.deleteStarterAssetRow(asset.filename)}
levelName={this.props.levelName}
hideDelete={!this.props.isStartMode}
Expand Down
11 changes: 11 additions & 0 deletions apps/src/code-studio/components/ImagePicker.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React from 'react';
import {getStore} from '@cdo/apps/redux';
import AssetManager from './AssetManager';
import color from '../../util/color';
import IconLibrary from './IconLibrary';
Expand Down Expand Up @@ -96,6 +97,14 @@ export default class ImagePicker extends React.Component {

const disableAudio =
this.props.disableAudioRecording || this.props.assetChosen;

const reduxState = getStore().getState();
let levelName, isStartMode;
if (reduxState && reduxState.level) {
levelName = reduxState.level.name;
isStartMode = reduxState.level.isStartMode;
}

const body =
!this.props.assetChosen || this.state.mode === 'files' ? (
<AssetManager
Expand All @@ -109,6 +118,8 @@ export default class ImagePicker extends React.Component {
disableAudioRecording={disableAudio}
imagePicker={true}
elementId={this.props.elementId}
levelName={levelName}
isStartMode={isStartMode}
/>
) : (
<IconLibrary assetChosen={this.getAssetNameWithPrefix} />
Expand Down
16 changes: 15 additions & 1 deletion apps/test/unit/applab/redux/applabTest.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @file Tests for App Lab redux module */
import {expect} from '../../../util/configuredChai';
import {expect, assert} from '../../../util/configuredChai';
import {
getStore,
registerReducers,
Expand Down Expand Up @@ -131,6 +131,20 @@ describe('App Lab redux module', () => {
});
});

describe('level', () => {
describe('setLevelData', () => {
it('sets given data on the level', () => {
let data = {name: 'Favorite Level!', isStartMode: true};
store.dispatch(actions.setLevelData(data));
assert.deepEqual(data, store.getState().level);
// Only update level name, make sure other data is unaffected.
data.name = 'New Name!';
store.dispatch(actions.setLevelData({name: data.name}));
assert.deepEqual(data, store.getState().level);
});
});
});

describe('maker', () => {
it('exposes state on the maker key', () => {
expect(store.getState().maker).to.be.defined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class LevelStarterAssetsController < ApplicationController

# GET /level_starter_assets/:level_name
def show
starter_assets = @level.starter_assets.map do |friendly_name, uuid_name|
starter_assets = (@level.starter_assets || []).map do |friendly_name, uuid_name|
file_obj = get_object(uuid_name)
summarize(file_obj, friendly_name, uuid_name)
end.compact
Expand Down
2 changes: 2 additions & 0 deletions dashboard/app/controllers/levels_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ def edit_blocks
)
end

@is_start_mode = type == 'start_blocks'

show
render :show
end
Expand Down
1 change: 1 addition & 0 deletions dashboard/app/helpers/levels_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ def blockly_options
dev_with_credentials = rack_env?(:development) && (!!CDO.aws_access_key || !!CDO.aws_role) && !!CDO.cloudfront_key_pair_id
use_restricted_songs = CDO.cdn_enabled || dev_with_credentials || (rack_env?(:test) && ENV['CI'])
app_options[:useRestrictedSongs] = use_restricted_songs if @game == Game.dance
app_options[:isStartMode] = @is_start_mode || false

if params[:blocks]
level_options[:sharedBlocks] = Block.for(*params[:blocks].split(','))
Expand Down
1 change: 1 addition & 0 deletions dashboard/app/models/levels/blockly.rb
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ def blockly_level_options

if is_a? Applab
level_prop['startHtml'] = try(:project_template_level).try(:start_html) || start_html
level_prop['name'] = name
end

if is_a? Gamelab
Expand Down

0 comments on commit 03d0905

Please sign in to comment.