Skip to content

Commit

Permalink
Merge pull request #39166 from code-dot-org/dtl_candidate_405a95f8
Browse files Browse the repository at this point in the history
  • Loading branch information
deploy-code-org committed Feb 19, 2021
2 parents c63ee49 + 405a95f commit 9c4694a
Show file tree
Hide file tree
Showing 43 changed files with 431 additions and 203 deletions.
12 changes: 7 additions & 5 deletions apps/src/applab/ai.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ function generateCodeDesignElements(modelId, modelData) {
y = y + SPACER_PIXELS;
var label = designMode.createElement('LABEL', x, y);
var alphaNumFeature = stripSpaceAndSpecial(feature);
let fieldId;
label.textContent = feature + ':';
label.id = 'design_' + alphaNumFeature + '_label';
label.style.width = '300px';
y = y + SPACER_PIXELS;
if (Object.keys(modelData.featureNumberKey).includes(feature)) {
var selectId = alphaNumFeature + '_dropdown';
fieldId = alphaNumFeature + '_dropdown';
var select = designMode.createElement('DROPDOWN', x, y);
select.id = 'design_' + selectId;
select.id = 'design_' + fieldId;
// App Lab automatically addss "option 1" and "option 2", remove them.
select.options.remove(0);
select.options.remove(0);
Expand All @@ -30,11 +31,12 @@ function generateCodeDesignElements(modelId, modelData) {
});
y = y + SPACER_PIXELS;
} else {
var input = designMode.createElement('TEXT_INPUT');
input.id = 'design_' + alphaNumFeature + '_input';
var input = designMode.createElement('TEXT_INPUT', x, y);
fieldId = alphaNumFeature + '_input';
input.id = 'design_' + fieldId;
y = y + SPACER_PIXELS;
}
var addFeature = `testValues.${alphaNumFeature} = getText("${selectId}");`;
var addFeature = `testValues.${alphaNumFeature} = getText("${fieldId}");`;
inputFields.push(addFeature);
});
y = y + 2 * SPACER_PIXELS;
Expand Down
2 changes: 1 addition & 1 deletion apps/src/code-studio/components/header/SignInCallout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export default class SignInCallout extends React.Component {
return (
<div style={styles.container}>
<div
className="modal-backdrop"
className="login-callout"
style={styles.modalBackdrop}
onClick={this.props.handleClose}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,17 @@ export default class SignInCalloutWrapper extends React.Component {
};
}

// Upon close, set both cookies and session storage, and prevent the click
// event from being bubbled up to any other components. The path '/' allows
// the data to be seen one directory higher.
closeCallout(event) {
this.setState({hideCallout: true});
cookies.set(HideSignInCallout, 'true', {expires: 1, path: '/'});
sessionStorage.setItem(HideSignInCallout, 'true');
event.preventDefault();
}

// For readibility: returning an empty div here explicitly if the callout is
// not supposed to be displayed. This avoids using a render statement that
// often returns *nothing.
// After the first dismissal, this returns null
render() {
if (this.state.hideCallout) {
return null;
Expand Down
9 changes: 9 additions & 0 deletions apps/src/code-studio/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {getStore} from '../redux';

import {PUZZLE_PAGE_NONE} from '@cdo/apps/templates/progress/progressTypes';
import HeaderMiddle from '@cdo/apps/code-studio/components/header/HeaderMiddle';
import SignInCalloutWrapper from './components/header/SignInCalloutWrapper';

/**
* Dynamic header generation and event bindings for header actions.
Expand Down Expand Up @@ -119,6 +120,14 @@ header.build = function(
</Provider>,
document.querySelector('.header_level')
);
// Only render sign in callout if the course is CSF and the user is
// not signed in
if (scriptData.is_csf && !signedIn) {
ReactDOM.render(
<SignInCalloutWrapper />,
document.querySelector('.signin_callout_wrapper')
);
}
});
};

Expand Down
83 changes: 80 additions & 3 deletions apps/test/unit/code-studio/components/header/SignInCalloutTest.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,99 @@
import React from 'react';
import SignInCalloutWrapper from '@cdo/apps/code-studio/components/header/SignInCalloutWrapper';
import {shallow} from 'enzyme';
import {shallow, mount} from 'enzyme';
import {expect} from '../../../../util/reconfiguredChai';
import i18n from '@cdo/locale';

const wrapper = shallow(<SignInCalloutWrapper />);
import sinon from 'sinon';
import cookies from 'js-cookie';

describe('ViewPopup', () => {
it('displays the correct background darkness', () => {
const wrapper = shallow(<SignInCalloutWrapper />);
wrapper.setState({hideCallout: false});
expect(wrapper.html().includes('opacity:0.5')).to.be.true;
});

it('shows the correct header', () => {
const wrapper = shallow(<SignInCalloutWrapper />);
expect(wrapper.html().includes(i18n.notSignedInHeader())).to.be.true;
});

it('shows the correct image', () => {
const wrapper = shallow(<SignInCalloutWrapper />);
expect(wrapper.html().includes('user-not-signed-in.png')).to.be.true;
});
});

describe('Check popup does not appear when flag is set', () => {
it('does not obscure the current view', () => {
const wrapper = shallow(<SignInCalloutWrapper />);
wrapper.setState({hideCallout: true});
expect(wrapper.html()).to.be.null;
});
});

describe('Check cookies and session storage appear on click', () => {
afterEach(() => {
if (cookies.get.restore) {
cookies.get.restore();
}
if (cookies.set.restore) {
cookies.set.restore();
}
if (sessionStorage.getItem.restore) {
sessionStorage.getItem.restore();
}
if (sessionStorage.setItem.restore) {
sessionStorage.setItem.restore();
}
});

it('cookies appear when clicked', () => {
const wrapper = mount(<SignInCalloutWrapper />);
wrapper.setState({hideCallout: false});
var cookieSetStub = sinon.stub(cookies, 'set');
wrapper.find('.login-callout').simulate('click');
expect(cookieSetStub).to.have.been.calledWith(
'hide_signin_callout',
'true',
{expires: 1, path: '/'}
);
});

it('session storage appears when clicked', () => {
const wrapper = mount(<SignInCalloutWrapper />);
wrapper.setState({hideCallout: false});
var sessionSetStub = sinon.stub(sessionStorage, 'setItem');
wrapper.find('.login-callout').simulate('click');
expect(sessionSetStub).to.have.been.calledWith(
'hide_signin_callout',
'true'
);
});

it('if cookie is set, callout does not appear', () => {
const wrapper = mount(<SignInCalloutWrapper />);
sinon
.stub(cookies, 'get')
.withArgs('hide_signin_callout')
.returns('true');
expect(wrapper.html()).to.be.null;
});

it('if session storage flag is set, callout does not appear', () => {
const wrapper = mount(<SignInCalloutWrapper />);
sinon
.stub(sessionStorage, 'getItem')
.withArgs('hide_signin_callout')
.returns('true');
expect(wrapper.html()).to.be.null;
});

it('shows prior to click, and dismisses after', () => {
const wrapper = mount(<SignInCalloutWrapper />);
wrapper.setState({hideCallout: false});
expect(wrapper.html().includes('uitest-signincallout')).to.be.true;
wrapper.find('.login-callout').simulate('click');
expect(wrapper.html()).to.be.null;
});
});
3 changes: 2 additions & 1 deletion dashboard/app/controllers/api/v1/ml_models_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ def user_ml_model_names
# GET api/v1/ml_models/metadata/:model_id
# Retrieve a trained ML model's metadata
def user_ml_model_metadata
metadata = UserMlModel.where(user_id: current_user&.id, model_id: params[:model_id]).first.metadata
metadata = UserMlModel.where(user_id: current_user&.id, model_id: params[:model_id])&.first&.metadata
return render_404 unless metadata
render json: JSON.parse(metadata)
end

Expand Down
4 changes: 3 additions & 1 deletion dashboard/app/controllers/lessons_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@ def update
msg = "The last level in a lockable lesson must be a LevelGroup and an assessment."
raise msg unless @lesson.script_levels.last.assessment && @lesson.script_levels.last.level.type == 'LevelGroup'
end

@lesson.script.prevent_duplicate_levels
@lesson.script.fix_lesson_positions
end

if Rails.application.config.levelbuilder_mode
@lesson.script.fix_lesson_positions
@lesson.script.reload

# This endpoint will only be hit from the lesson edit page, which is only
Expand Down
13 changes: 12 additions & 1 deletion dashboard/app/models/script.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@ def hide_pilot_scripts

validate :set_is_migrated_only_for_migrated_scripts

def prevent_duplicate_levels
reload

unless levels.count == levels.uniq.count
levels_by_key = levels.map(&:key).group_by {|key| key}
duplicate_keys = levels_by_key.select {|_key, values| values.count > 1}.keys
raise "duplicate levels detected: #{duplicate_keys.to_json}"
end
end

include SerializedProperties

after_save :generate_plc_objects
Expand Down Expand Up @@ -1420,7 +1430,8 @@ def summarize_header
disablePostMilestone: disable_post_milestone?,
isHocScript: hoc?,
student_detail_progress_view: student_detail_progress_view?,
age_13_required: logged_out_age_13_required?
age_13_required: logged_out_age_13_required?,
is_csf: csf?
}
end

Expand Down
36 changes: 18 additions & 18 deletions dashboard/app/models/sections/clever_section.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@
#
# Table name: sections
#
# id :integer not null, primary key
# user_id :integer not null
# name :string(255)
# created_at :datetime
# updated_at :datetime
# code :string(255)
# script_id :integer
# course_id :integer
# grade :string(255)
# login_type :string(255) default("email"), not null
# deleted_at :datetime
# stage_extras :boolean default(FALSE), not null
# section_type :string(255)
# first_activity_at :datetime
# pairing_allowed :boolean default(TRUE), not null
# sharing_disabled :boolean default(FALSE), not null
# hidden :boolean default(FALSE), not null
# autoplay_enabled :boolean default(FALSE), not null
# id :integer not null, primary key
# user_id :integer not null
# name :string(255)
# created_at :datetime
# updated_at :datetime
# code :string(255)
# script_id :integer
# course_id :integer
# grade :string(255)
# login_type :string(255) default("email"), not null
# deleted_at :datetime
# stage_extras :boolean default(FALSE), not null
# section_type :string(255)
# first_activity_at :datetime
# pairing_allowed :boolean default(TRUE), not null
# sharing_disabled :boolean default(FALSE), not null
# hidden :boolean default(FALSE), not null
# tts_autoplay_enabled :boolean default(FALSE), not null
#
# Indexes
#
Expand Down
36 changes: 18 additions & 18 deletions dashboard/app/models/sections/email_section.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@
#
# Table name: sections
#
# id :integer not null, primary key
# user_id :integer not null
# name :string(255)
# created_at :datetime
# updated_at :datetime
# code :string(255)
# script_id :integer
# course_id :integer
# grade :string(255)
# login_type :string(255) default("email"), not null
# deleted_at :datetime
# stage_extras :boolean default(FALSE), not null
# section_type :string(255)
# first_activity_at :datetime
# pairing_allowed :boolean default(TRUE), not null
# sharing_disabled :boolean default(FALSE), not null
# hidden :boolean default(FALSE), not null
# autoplay_enabled :boolean default(FALSE), not null
# id :integer not null, primary key
# user_id :integer not null
# name :string(255)
# created_at :datetime
# updated_at :datetime
# code :string(255)
# script_id :integer
# course_id :integer
# grade :string(255)
# login_type :string(255) default("email"), not null
# deleted_at :datetime
# stage_extras :boolean default(FALSE), not null
# section_type :string(255)
# first_activity_at :datetime
# pairing_allowed :boolean default(TRUE), not null
# sharing_disabled :boolean default(FALSE), not null
# hidden :boolean default(FALSE), not null
# tts_autoplay_enabled :boolean default(FALSE), not null
#
# Indexes
#
Expand Down
36 changes: 18 additions & 18 deletions dashboard/app/models/sections/google_classroom_section.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@
#
# Table name: sections
#
# id :integer not null, primary key
# user_id :integer not null
# name :string(255)
# created_at :datetime
# updated_at :datetime
# code :string(255)
# script_id :integer
# course_id :integer
# grade :string(255)
# login_type :string(255) default("email"), not null
# deleted_at :datetime
# stage_extras :boolean default(FALSE), not null
# section_type :string(255)
# first_activity_at :datetime
# pairing_allowed :boolean default(TRUE), not null
# sharing_disabled :boolean default(FALSE), not null
# hidden :boolean default(FALSE), not null
# autoplay_enabled :boolean default(FALSE), not null
# id :integer not null, primary key
# user_id :integer not null
# name :string(255)
# created_at :datetime
# updated_at :datetime
# code :string(255)
# script_id :integer
# course_id :integer
# grade :string(255)
# login_type :string(255) default("email"), not null
# deleted_at :datetime
# stage_extras :boolean default(FALSE), not null
# section_type :string(255)
# first_activity_at :datetime
# pairing_allowed :boolean default(TRUE), not null
# sharing_disabled :boolean default(FALSE), not null
# hidden :boolean default(FALSE), not null
# tts_autoplay_enabled :boolean default(FALSE), not null
#
# Indexes
#
Expand Down

0 comments on commit 9c4694a

Please sign in to comment.