add temporary conditional release popup to assignments
refs: CYOE-74 Test plan: View conditional content on assignment, quiz, and discussion topic edit pages. - Button should be disabled before assignment has saved (though some assignments save before first edit) - Button should be enabled after save - Clicking button should bring up a modal (with an error page loaded in it) - For discussion topics, saving here means "saved as a graded topic" Change-Id: I3faed62567488c71067f94ff911b57ca71de9648 Reviewed-on: https://gerrit.instructure.com/77677 Tested-by: Jenkins Reviewed-by: Matt Berns <mberns@instructure.com> Reviewed-by: Christian Prescott <cprescott@instructure.com> QA-Review: Jahnavi Yetukuri <jyetukuri@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com>
This commit is contained in:
parent
1cd05d560b
commit
ca63fdc0e4
|
@ -17,11 +17,13 @@ define [
|
|||
'compiled/fn/preventDefault'
|
||||
'compiled/views/calendar/MissingDateDialogView'
|
||||
'compiled/views/editor/KeyboardShortcuts'
|
||||
'jsx/shared/conditional_release/ConditionalRelease'
|
||||
'jquery.instructure_misc_helpers' # $.scrollSidebar
|
||||
'compiled/jquery.rails_flash_notifications' #flashMessage
|
||||
], (I18n, ValidatedFormView, AssignmentGroupSelector, GradingTypeSelector,
|
||||
GroupCategorySelector, PeerReviewsSelector, PostToSisSelector, _, template, RichContentEditor,
|
||||
htmlEscape, DiscussionTopic, Announcement, Assignment, $, preventDefault, MissingDateDialog, KeyboardShortcuts) ->
|
||||
htmlEscape, DiscussionTopic, Announcement, Assignment, $, preventDefault, MissingDateDialog, KeyboardShortcuts,
|
||||
ConditionalRelease) ->
|
||||
|
||||
RichContentEditor.preloadRemoteModule()
|
||||
|
||||
|
@ -42,14 +44,16 @@ htmlEscape, DiscussionTopic, Announcement, Assignment, $, preventDefault, Missin
|
|||
'#discussion_point_change_warning' : '$discussionPointPossibleWarning'
|
||||
'#discussion-edit-view' : '$discussionEditView'
|
||||
'#discussion-details-tab' : '$discussionDetailsTab'
|
||||
'#conditional-release-target' : '$conditionalReleaseTarget'
|
||||
|
||||
events: _.extend(@::events,
|
||||
'click .removeAttachment' : 'removeAttachment'
|
||||
'click .save_and_publish': 'saveAndPublish'
|
||||
'click .cancel_button' : 'handleCancel'
|
||||
'change #use_for_grading' : 'toggleAvailabilityOptions'
|
||||
'change #use_for_grading' : 'updateTabView'
|
||||
'change #use_for_grading' : 'toggleConditionalReleaseTab'
|
||||
'change #discussion_topic_assignment_points_possible' : 'handlePointsChange'
|
||||
'change' : 'onChange'
|
||||
)
|
||||
|
||||
messages:
|
||||
|
@ -88,7 +92,6 @@ htmlEscape, DiscussionTopic, Announcement, Assignment, $, preventDefault, Missin
|
|||
canModerate: @permissions.CAN_MODERATE
|
||||
isLargeRoster: ENV?.IS_LARGE_ROSTER || false
|
||||
threaded: data.discussion_type is "threaded"
|
||||
CONDITIONAL_RELEASE_SERVICE_ENABLED: ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED
|
||||
json.assignment = json.assignment.toView()
|
||||
json
|
||||
|
||||
|
@ -130,6 +133,7 @@ htmlEscape, DiscussionTopic, Announcement, Assignment, $, preventDefault, Missin
|
|||
_.defer(@watchUnload)
|
||||
_.defer(@attachKeyboardShortcuts)
|
||||
_.defer(@renderTabs) if ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED
|
||||
_.defer(@loadConditionalRelease) if ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED
|
||||
|
||||
@$(".datetime_field").datetime_field()
|
||||
|
||||
|
@ -188,7 +192,15 @@ htmlEscape, DiscussionTopic, Announcement, Assignment, $, preventDefault, Missin
|
|||
renderTabs: =>
|
||||
@$discussionEditView.tabs()
|
||||
@$discussionDetailsTab.show()
|
||||
@updateTabView()
|
||||
@toggleConditionalReleaseTab()
|
||||
|
||||
loadConditionalRelease: =>
|
||||
if !ENV.CONDITIONAL_RELEASE_ENV
|
||||
return # can happen during unit tests due to _.defer
|
||||
@conditionalReleaseEditor = ConditionalRelease.attach(
|
||||
@$conditionalReleaseTarget.get(0),
|
||||
I18n.t('discussion topic'),
|
||||
ENV.CONDITIONAL_RELEASE_ENV)
|
||||
|
||||
getFormData: ->
|
||||
data = super
|
||||
|
@ -322,10 +334,15 @@ htmlEscape, DiscussionTopic, Announcement, Assignment, $, preventDefault, Missin
|
|||
else
|
||||
@$availabilityOptions.show()
|
||||
|
||||
updateTabView: ->
|
||||
toggleConditionalReleaseTab: ->
|
||||
if ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED
|
||||
if @$useForGrading.is(':checked')
|
||||
@$discussionEditView.tabs("option", "disabled", false)
|
||||
else
|
||||
@$discussionEditView.tabs("option", "disabled", [1])
|
||||
@$discussionDetailsTab.show()
|
||||
|
||||
onChange: ->
|
||||
if ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED && !@assignmentDirty
|
||||
@assignmentDirty = true
|
||||
@conditionalReleaseEditor.setProps({ assignmentDirty: true })
|
||||
|
|
|
@ -2,9 +2,10 @@ define [
|
|||
'i18n!assignments'
|
||||
'Backbone'
|
||||
'jquery'
|
||||
'jsx/shared/conditional_release/ConditionalRelease'
|
||||
'jst/assignments/EditHeaderView'
|
||||
'jquery.disableWhileLoading'
|
||||
], (I18n, Backbone, $, template) ->
|
||||
], (I18n, Backbone, $, ConditionalRelease, template) ->
|
||||
|
||||
class EditHeaderView extends Backbone.View
|
||||
|
||||
|
@ -12,6 +13,8 @@ define [
|
|||
|
||||
events:
|
||||
'click .delete_assignment_link': 'onDelete'
|
||||
'change #grading_type_selector': 'onGradingTypeUpdate'
|
||||
'change' : 'onChange'
|
||||
|
||||
messages:
|
||||
confirm: I18n.t('confirms.delete_assignment', 'Are you sure you want to delete this assignment?')
|
||||
|
@ -19,12 +22,20 @@ define [
|
|||
els:
|
||||
'#edit-assignment-header-tabs': '$headerTabs'
|
||||
'#edit-assignment-header-cr-tabs': '$headerTabsCr'
|
||||
'#conditional-release-target': '$conditionalReleaseTarget'
|
||||
|
||||
afterRender: ->
|
||||
# doubled for conditional release
|
||||
@$headerTabs.tabs()
|
||||
@$headerTabsCr.tabs()
|
||||
|
||||
if ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED
|
||||
@toggleConditionalReleaseTab(@model.gradingType())
|
||||
@conditionalReleaseEditor = ConditionalRelease.attach(
|
||||
@$conditionalReleaseTarget.get(0),
|
||||
I18n.t('assignment'),
|
||||
ENV.CONDITIONAL_RELEASE_ENV)
|
||||
|
||||
onDelete: (e) =>
|
||||
e.preventDefault()
|
||||
@delete() if confirm(@messages.confirm)
|
||||
|
@ -42,7 +53,23 @@ define [
|
|||
onDeleteSuccess: ->
|
||||
location.href = ENV.ASSIGNMENT_INDEX_URL
|
||||
|
||||
onGradingTypeUpdate: (e) =>
|
||||
if ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED
|
||||
@toggleConditionalReleaseTab(e.target.value)
|
||||
|
||||
toggleConditionalReleaseTab: (gradingType) ->
|
||||
if ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED
|
||||
if gradingType == 'not_graded'
|
||||
@$headerTabsCr.tabs("option", "disabled", [1])
|
||||
else
|
||||
@$headerTabsCr.tabs("option", "disabled", false)
|
||||
|
||||
toJSON: ->
|
||||
json = @model.toView()
|
||||
json['CONDITIONAL_RELEASE_SERVICE_ENABLED'] = ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED
|
||||
json
|
||||
|
||||
onChange: ->
|
||||
if ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED && !@assignmentDirty
|
||||
@assignmentDirty = true
|
||||
@conditionalReleaseEditor.setProps({ assignmentDirty: true })
|
||||
|
|
|
@ -27,7 +27,7 @@ module ConditionalRelease
|
|||
conditional_release_js_env
|
||||
|
||||
render locals: {
|
||||
cr_app_url: ConditionalRelease::Service.configure_defaults_url,
|
||||
cr_app_url: ConditionalRelease::Service.edit_rule_path,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
define([
|
||||
'jquery',
|
||||
'react',
|
||||
'react-modal',
|
||||
'i18n!conditional_release',
|
||||
], function($, React, Modal, I18n) {
|
||||
|
||||
// Conditional Release adds its form at the tail of the page
|
||||
// because it is sometimes nested within a larger form (eg., discussion topics)
|
||||
const HiddenForm = React.createClass({
|
||||
propTypes: {
|
||||
env: React.PropTypes.object.isRequired,
|
||||
target: React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<form id="conditional-release-editor-form"
|
||||
target={this.props.target}
|
||||
method="POST"
|
||||
|
||||
action={this.props.env.edit_rule_url}>
|
||||
<input type="hidden" name="env" value={JSON.stringify(this.props.env)} />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Need to specify componentDidMount so that we can be sure the iframe exists before
|
||||
// submitting a form targetting it
|
||||
const ConditionalReleaseFrame = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<div className="conditional-release-editor-body ReactModal__Body">
|
||||
<iframe className="conditional-release-editor-frame" id={this.props.name} name={this.props.name} src={this.props.source}></iframe>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
this.props.onComponentDidMount();
|
||||
}
|
||||
});
|
||||
|
||||
const Editor = React.createClass({
|
||||
displayName: 'ConditionalReleaseEditor',
|
||||
|
||||
propTypes: {
|
||||
env: React.PropTypes.object.isRequired,
|
||||
type: React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
modalIsOpen: false,
|
||||
hiddenContainer: null
|
||||
};
|
||||
},
|
||||
|
||||
enabled() {
|
||||
return this.props.env &&
|
||||
this.props.env.assignment &&
|
||||
this.props.env.assignment.id &&
|
||||
!this.props.assignmentDirty;
|
||||
},
|
||||
|
||||
saveDataMessage() {
|
||||
if (!this.enabled()) {
|
||||
return (
|
||||
<div ref="saveDataMessage" className="conditional-release-save-data">
|
||||
{I18n.t('Save your %{type} to begin specifying conditional content.', { type: this.props.type })}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
popupId() {
|
||||
if (this.props.env.assignment) {
|
||||
return "conditional_release_" + this.props.env.assignment.id;
|
||||
} else {
|
||||
return "conditional_release_no_assignment";
|
||||
}
|
||||
},
|
||||
|
||||
hiddenContainer() {
|
||||
return this.state.hiddenContainer;
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
const $hiddenContainer = $('<div id="conditional-release-hidden-form-container"></div>');
|
||||
this.setState({ hiddenContainer: $hiddenContainer });
|
||||
$('body').append($hiddenContainer);
|
||||
React.render(
|
||||
<HiddenForm target={this.popupId()} env={this.props.env}></HiddenForm>,
|
||||
$hiddenContainer.get(0));
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
React.unmountComponentAtNode(this.hiddenContainer().get(0));
|
||||
this.hiddenContainer().remove();
|
||||
},
|
||||
|
||||
onClick(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.setState({ modalIsOpen: true });
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.setState({ modalIsOpen: false });
|
||||
this.refs.iframe.source = null;
|
||||
},
|
||||
|
||||
submitForm() {
|
||||
$("#conditional-release-editor-form").submit();
|
||||
},
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className="conditional-release-editor">
|
||||
<button ref="button" className="Button" disabled={!this.enabled()} onClick={this.onClick}>
|
||||
{I18n.t('View conditional content settings')}
|
||||
</button>
|
||||
{ this.saveDataMessage() }
|
||||
<Modal isOpen={this.state.modalIsOpen}
|
||||
onAfterOpen={this.onModalOpen}
|
||||
onRequestClose={this.closeModal}
|
||||
className='conditional-release-editor-modal ReactModal__Content--canvas'
|
||||
overlayClassName='ReactModal__Overlay--canvas'>
|
||||
<div className="conditional-release-editor-layout ReactModal__Layout">
|
||||
<div className="ReactModal__Header">
|
||||
<div className="ReactModal__Header-Title">
|
||||
<h4>{I18n.t('Conditional Content')}</h4>
|
||||
</div>
|
||||
<div className="ReactModal__Header-Actions">
|
||||
<button className="Button Button--icon-action" type="button" onClick={this.closeModal}>
|
||||
<i className="icon-x"></i>
|
||||
<span className="screenreader-only">Close</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ConditionalReleaseFrame ref="iframe" name={this.popupId()} onComponentDidMount={this.submitForm} />
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
const attach = function(element, type, env) {
|
||||
const editor = (
|
||||
<Editor env={env} type={type} />
|
||||
);
|
||||
return React.render(editor, element);
|
||||
};
|
||||
|
||||
const ConditionalRelease = {
|
||||
Editor: Editor,
|
||||
attach: attach
|
||||
};
|
||||
|
||||
return ConditionalRelease;
|
||||
});
|
|
@ -24,8 +24,8 @@ module ConditionalRelease
|
|||
enabled: false, # required
|
||||
host: nil, # required
|
||||
protocol: nil, # defaults to Canvas
|
||||
configure_defaults_app_path: 'javascripts/edit_defaults.js',
|
||||
edit_object_score_ranges_path: 'javascripts/edit_object_score_ranges.js',
|
||||
edit_rule_path: "api/editor",
|
||||
create_account_path: 'api/account',
|
||||
}.freeze
|
||||
|
||||
def self.env_for(context, user = nil, session: nil, assignment: nil, domain: nil, real_user: nil)
|
||||
|
@ -35,9 +35,10 @@ module ConditionalRelease
|
|||
}
|
||||
if enabled && user
|
||||
env.merge!({
|
||||
CONDITIONAL_RELEASE_JWT: jwt_for(context, user, domain, session: session, real_user: real_user),
|
||||
CONDITIONAL_RELEASE_ENV: {
|
||||
assignment: assignment_attributes(assignment)
|
||||
jwt: jwt_for(context, user, domain, session: session, real_user: real_user),
|
||||
assignment: assignment_attributes(assignment),
|
||||
edit_rule_url: edit_rule_url
|
||||
}
|
||||
})
|
||||
end
|
||||
|
@ -45,7 +46,7 @@ module ConditionalRelease
|
|||
end
|
||||
|
||||
def self.jwt_for(context, user, domain, claims: {}, session: nil, real_user: nil)
|
||||
return Canvas::Security::ServicesJwt.generate(
|
||||
Canvas::Security::ServicesJwt.generate(
|
||||
claims.merge({
|
||||
sub: user.id.to_s,
|
||||
account_id: Context.get_account(context).root_account.lti_guid.to_s,
|
||||
|
@ -74,12 +75,12 @@ module ConditionalRelease
|
|||
!!(configured? && context.feature_enabled?(:conditional_release))
|
||||
end
|
||||
|
||||
def self.configure_defaults_url
|
||||
build_url configure_defaults_app_path
|
||||
def self.edit_rule_url
|
||||
build_url edit_rule_path
|
||||
end
|
||||
|
||||
def self.edit_object_score_ranges_url
|
||||
build_url edit_object_score_ranges_path
|
||||
def self.create_account_url
|
||||
build_url create_account_path
|
||||
end
|
||||
|
||||
def self.protocol
|
||||
|
@ -90,12 +91,16 @@ module ConditionalRelease
|
|||
config[:host]
|
||||
end
|
||||
|
||||
def self.configure_defaults_app_path
|
||||
config[:configure_defaults_app_path]
|
||||
def self.unique_id
|
||||
config[:unique_id] || "conditional-release-service@instructure.auth"
|
||||
end
|
||||
|
||||
def self.edit_object_score_ranges_path
|
||||
config[:edit_object_score_ranges_path]
|
||||
def self.edit_rule_path
|
||||
config[:edit_rule_path]
|
||||
end
|
||||
|
||||
def self.create_account_path
|
||||
config[:create_account_path]
|
||||
end
|
||||
|
||||
class << self
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
@import "pages/shared/grading_standards.scss";
|
||||
@import "pages/shared/mark_as_done.scss";
|
||||
@import "vendor/embed_content.scss";
|
||||
|
||||
@import "components/conditional_release";
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@import "base/_environment.scss";
|
||||
@import "components/conditional_release";
|
||||
|
||||
.removeAttachment {
|
||||
@include fontSize(20px);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@import "pages/quizzes/quizzes";
|
||||
@import "pages/quizzes/quizzes-mobile";
|
||||
@import "pages/shared/message_students";
|
||||
@import "components/ui.selectmenu";
|
||||
@import "components/ui.selectmenu";
|
||||
@import "components/conditional_release";
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
.conditional-release-editor {
|
||||
padding-top: 12px;
|
||||
}
|
||||
|
||||
.conditional-release-editor-layout {
|
||||
width: 90% !important;
|
||||
height: 90% !important;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.conditional-release-editor-body {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.conditional-release-editor-frame {
|
||||
border: none;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.conditional-release-save-data {
|
||||
padding: 12px 0px;
|
||||
}
|
|
@ -9,31 +9,19 @@
|
|||
<div id="discussion-edit-view" class="ui-tabs-minimal">
|
||||
{{#unless isAnnouncement}}
|
||||
<div id="discussion-edit-header" class="discussion-edit-header row-fluid">
|
||||
{{#if CONDITIONAL_RELEASE_SERVICE_ENABLED }}
|
||||
{{#if ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED }}
|
||||
<ul id="discussion-edit-header-tabs">
|
||||
<li><a href="#discussion-details-tab" id="details_link">{{#t}}Details{{/t}}</a></li>
|
||||
<li><a href="#discussion-conditional-release-tab" id="conditional_release_link">{{#t}}Conditional Content{{/t}}</a></li>
|
||||
<span id="discussion-edit-header-spacer"></span>
|
||||
{{else}}
|
||||
<div class="span4 offset8 text-right">
|
||||
{{/if}}
|
||||
{{#if published}}
|
||||
<span id="topic-draft-state" class="published-status published">
|
||||
<i class="icon-publish"></i>
|
||||
{{#t "buttons.published"}}Published{{/t}}
|
||||
</span>
|
||||
{{else}}
|
||||
<span id="topic-draft-state" class="published-status unpublished">
|
||||
<i class="icon-unpublished"></i>
|
||||
{{#t "buttons.not_published"}}Not Published{{/t}}
|
||||
</span>
|
||||
{{/if}}
|
||||
{{#if CONDITIONAL_RELEASE_SERVICE_ENABLED }}
|
||||
{{> DiscussionTopics/publishedButton }}
|
||||
</ul>
|
||||
{{else}}
|
||||
<div class="span4 offset8 text-right">
|
||||
{{> DiscussionTopics/publishedButton }}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
|
||||
<div id="discussion-details-tab">
|
||||
|
@ -300,10 +288,10 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if CONDITIONAL_RELEASE_SERVICE_ENABLED }}
|
||||
{{#if ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED }}
|
||||
{{#unless isAnnouncement }}
|
||||
<div id="discussion-conditional-release-tab">
|
||||
Conditional release content goes here
|
||||
<div id="conditional-release-target" />
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
{{#if published}}
|
||||
<span id="topic-draft-state" class="published-status published">
|
||||
<i class="icon-publish"></i>
|
||||
{{#t "buttons.published"}}Published{{/t}}
|
||||
</span>
|
||||
{{else}}
|
||||
<span id="topic-draft-state" class="published-status unpublished">
|
||||
<i class="icon-unpublished"></i>
|
||||
{{#t "buttons.not_published"}}Not Published{{/t}}
|
||||
</span>
|
||||
{{/if}}
|
|
@ -46,7 +46,9 @@
|
|||
<form id="edit_assignment_form" class="form-horizontal bootstrap-form">
|
||||
</form>
|
||||
</div>
|
||||
<div id="conditional_release_wrapper"></div>
|
||||
<div id="conditional_release_wrapper">
|
||||
<div id="conditional-release-target" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
<div id="conditional_release_tab">
|
||||
Conditional release content goes here
|
||||
<div id="conditional-release-target"></div>
|
||||
</div>
|
||||
|
|
|
@ -41,6 +41,7 @@ define([
|
|||
'INST', // safari sniffing for VO workarounds
|
||||
'quiz_formula_solution',
|
||||
'jsx/shared/rce/RichContentEditor',
|
||||
'jsx/shared/conditional_release/ConditionalRelease',
|
||||
'jquery.ajaxJSON' /* ajaxJSON */,
|
||||
'jquery.instructure_date_and_time' /* time_field, datetime_field */,
|
||||
'jquery.instructure_forms' /* formSubmit, fillFormData, getFormData, formErrors, errorBox */,
|
||||
|
@ -60,7 +61,8 @@ define([
|
|||
Handlebars, DueDateOverrideView, Quiz,
|
||||
DueDateList, QuizRegradeView, SectionList,
|
||||
MissingDateDialog,MultipleChoiceToggle,EditorToggle,TextHelper,
|
||||
RCEKeyboardShortcuts, INST, QuizFormulaSolution, RichContentEditor){
|
||||
RCEKeyboardShortcuts, INST, QuizFormulaSolution, RichContentEditor,
|
||||
ConditionalRelease){
|
||||
|
||||
var dueDateList, overrideView, quizModel, sectionList, correctAnswerVisibility,
|
||||
scoreValidation;
|
||||
|
@ -1476,6 +1478,16 @@ define([
|
|||
return result;
|
||||
}
|
||||
|
||||
function toggleConditionalReleaseTab(quizType) {
|
||||
if (ENV['CONDITIONAL_RELEASE_SERVICE_ENABLED']) {
|
||||
if (quizType == "assignment") {
|
||||
$('#quiz_tabs').tabs("option", "disabled", false);
|
||||
} else {
|
||||
$('#quiz_tabs').tabs("option", "disabled", [2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
quiz.init().updateDisplayComments();
|
||||
correctAnswerVisibility.init();
|
||||
|
@ -1879,6 +1891,10 @@ define([
|
|||
var url = $("#quiz_urls .update_quiz_url").attr('href');
|
||||
$("#quiz_title_input").val(quiz_title);
|
||||
$("#quiz_title_text").text(quiz_title);
|
||||
|
||||
if (ENV['CONDITIONAL_RELEASE_SERVICE_ENABLED']) {
|
||||
toggleConditionalReleaseTab(event.target.value);
|
||||
}
|
||||
}).change();
|
||||
|
||||
$(".question_form :input").keycodes("esc", function(event) {
|
||||
|
@ -3703,6 +3719,20 @@ define([
|
|||
success: function() { window.location.replace(ENV.QUIZZES_URL); }
|
||||
});
|
||||
});
|
||||
|
||||
if (ENV['CONDITIONAL_RELEASE_SERVICE_ENABLED']) {
|
||||
this.conditionalReleaseEditor = ConditionalRelease.attach(
|
||||
$('#conditional-release-target').get(0),
|
||||
I18n.t('quiz'),
|
||||
ENV['CONDITIONAL_RELEASE_ENV']);
|
||||
|
||||
$('div.form').on('change', function(event) {
|
||||
if (!this.assignmentDirty) {
|
||||
this.assignmentDirty = true
|
||||
this.conditionalReleaseEditor.setProps({ assignmentDirty: true });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.fn.multipleAnswerSetsQuestion = function() {
|
||||
|
@ -4101,7 +4131,6 @@ define([
|
|||
if(!showCorrectAnswersLastAttempt) {
|
||||
$('#quiz_show_correct_answers_last_attempt').prop('checked', false);
|
||||
}
|
||||
|
||||
}).triggerHandler('change');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -85,6 +85,7 @@ GroupCategorySelector, fakeENV) ->
|
|||
equal view.$el.find('#podcast_enabled').length, 1
|
||||
equal view.$el.find('#podcast_has_student_posts_container').length, 0
|
||||
|
||||
conditionalReleaseEnv = { assignment: { id: 1 }, jwt: 'foo' }
|
||||
test 'does not show conditional release tab when feature not enabled', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = false
|
||||
view = @editView()
|
||||
|
@ -93,23 +94,29 @@ GroupCategorySelector, fakeENV) ->
|
|||
|
||||
test 'shows disabled conditional release tab when feature enabled, but not assignment', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = conditionalReleaseEnv
|
||||
view = @editView()
|
||||
view.renderTabs()
|
||||
view.loadConditionalRelease()
|
||||
equal view.$el.find('#discussion-conditional-release-tab').length, 1
|
||||
equal view.$discussionEditView.hasClass('ui-tabs'), true
|
||||
equal view.$discussionEditView.tabs("option", "disabled"), true
|
||||
|
||||
test 'shows enabled conditional release tab when feature enabled, and assignment', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = conditionalReleaseEnv
|
||||
view = @editView({ withAssignment: true })
|
||||
view.renderTabs()
|
||||
view.loadConditionalRelease()
|
||||
equal view.$el.find('#discussion-conditional-release-tab').length, 1
|
||||
equal view.$discussionEditView.hasClass('ui-tabs'), true
|
||||
equal view.$discussionEditView.tabs("option", "disabled"), false
|
||||
|
||||
test 'enables conditional release tab when changed to assignment', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = conditionalReleaseEnv
|
||||
view = @editView()
|
||||
view.loadConditionalRelease()
|
||||
view.renderTabs()
|
||||
equal view.$discussionEditView.tabs("option", "disabled"), true
|
||||
|
||||
|
@ -119,10 +126,38 @@ GroupCategorySelector, fakeENV) ->
|
|||
|
||||
test 'disables conditional release tab when changed from assignment', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = conditionalReleaseEnv
|
||||
view = @editView({ withAssignment: true })
|
||||
view.loadConditionalRelease()
|
||||
view.renderTabs()
|
||||
equal view.$discussionEditView.tabs("option", "disabled"), false
|
||||
|
||||
view.$useForGrading.prop('checked', false)
|
||||
view.$useForGrading.trigger('change')
|
||||
equal view.$discussionEditView.tabs("option", "disabled"), true
|
||||
|
||||
test 'renders conditional release tab content', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = conditionalReleaseEnv
|
||||
view = @editView({ withAssignment: true })
|
||||
view.loadConditionalRelease()
|
||||
equal 1, view.$conditionalReleaseTarget.children().size()
|
||||
|
||||
test 'conditional release editor is disabled on change', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = conditionalReleaseEnv
|
||||
view = @editView({ withAssignment: true })
|
||||
view.loadConditionalRelease()
|
||||
view.onChange()
|
||||
equal false, view.conditionalReleaseEditor.enabled()
|
||||
|
||||
test 'conditional release editor is disabled only once', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = conditionalReleaseEnv
|
||||
view = @editView({ withAssignment: true })
|
||||
view.loadConditionalRelease()
|
||||
debugger
|
||||
stub = @stub(view.conditionalReleaseEditor, 'setProps')
|
||||
view.onChange()
|
||||
view.onChange()
|
||||
ok stub.calledOnce
|
||||
|
|
|
@ -10,8 +10,9 @@ define [
|
|||
name: 'Test Assignment'
|
||||
assignment_overrides: []
|
||||
|
||||
editHeaderView = () ->
|
||||
assignment = new Assignment defaultAssignmentOpts
|
||||
editHeaderView = (assignment_opts = {}) ->
|
||||
$.extend(assignment_opts, defaultAssignmentOpts)
|
||||
assignment = new Assignment assignment_opts
|
||||
|
||||
app = new EditHeaderView
|
||||
model: assignment
|
||||
|
@ -34,3 +35,45 @@ define [
|
|||
|
||||
view.delete()
|
||||
equal cb.called, true, 'onDeleteSuccess was called'
|
||||
|
||||
test 'attaches conditional release editor', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = { assignment: { id: 1 }, jwt: 'foo' }
|
||||
view = editHeaderView()
|
||||
equal 1, view.$conditionalReleaseTarget.children().size()
|
||||
|
||||
test 'disables conditional release tab on load when grading type is not_graded', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = { assignment: { id: 1 }, jwt: 'foo' }
|
||||
view = editHeaderView({ grading_type: 'not_graded' })
|
||||
equal true, view.$headerTabsCr.tabs('option', 'disabled')
|
||||
|
||||
test 'enables conditional release tab when grading type switched from not_graded', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = { assignment: { id: 1 }, jwt: 'foo' }
|
||||
view = editHeaderView({ grading_type: 'not_graded' })
|
||||
view.onGradingTypeUpdate({target: { value: 'points' }})
|
||||
equal false, view.$headerTabsCr.tabs('option', 'disabled')
|
||||
|
||||
test 'disables conditional release tab when grading type switched to not_graded', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = { assignment: { id: 1 }, jwt: 'foo' }
|
||||
view = editHeaderView({ grading_type: 'points' })
|
||||
view.onGradingTypeUpdate({target: { value: 'not_graded' }})
|
||||
equal true, view.$headerTabsCr.tabs('option', 'disabled')
|
||||
|
||||
test 'disables conditional release component on data change', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = { assignment: { id: 1 }, jwt: 'foo' }
|
||||
view = editHeaderView({ grading_type: 'points' })
|
||||
view.onChange()
|
||||
equal false, view.$headerTabsCr.tabs('option', 'disabled')
|
||||
equal false, view.conditionalReleaseEditor.enabled()
|
||||
|
||||
test 'disables conditional release component once', ->
|
||||
ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
|
||||
ENV.CONDITIONAL_RELEASE_ENV = { assignment: { id: 1 }, jwt: 'foo' }
|
||||
view = editHeaderView({ grading_type: 'points' })
|
||||
stub = @stub(view.conditionalReleaseEditor, 'setProps')
|
||||
view.onChange()
|
||||
ok stub.calledOnce
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
define([
|
||||
'react',
|
||||
'jquery',
|
||||
'jsx/shared/conditional_release/ConditionalRelease'
|
||||
], (React, $, ConditionalRelease) => {
|
||||
|
||||
const TestUtils = React.addons.TestUtils;
|
||||
let component = null;
|
||||
|
||||
module('Conditional Release component', {
|
||||
teardown: () => {
|
||||
if (component) {
|
||||
const componentNode = React.findDOMNode(component);
|
||||
if (componentNode) {
|
||||
React.unmountComponentAtNode(componentNode.parentNode);
|
||||
}
|
||||
}
|
||||
component = null;
|
||||
}
|
||||
});
|
||||
|
||||
const assignmentEnv = { assignment: { id: 1 }, edit_rule_url: 'about:blank', jwt: 'foo' }
|
||||
const noAssignmentEnv = { edit_rule_url: 'about:blank', jwt: 'foo' }
|
||||
const assignmentNoIdEnv = { assignment: { foo: 'bar' }, edit_rule_url: 'about:blank', jwt: 'foo' }
|
||||
|
||||
test('it disables its button when no assignment', () => {
|
||||
component = TestUtils.renderIntoDocument(
|
||||
<ConditionalRelease.Editor env={noAssignmentEnv} type='foo' />
|
||||
);
|
||||
const button = React.findDOMNode(component.refs.button);
|
||||
equal(button.disabled, true)
|
||||
});
|
||||
|
||||
test('it shows the help text when no assignment', () => {
|
||||
component = TestUtils.renderIntoDocument(
|
||||
<ConditionalRelease.Editor env={noAssignmentEnv} type='foo' />
|
||||
);
|
||||
ok(component.refs.saveDataMessage);
|
||||
});
|
||||
|
||||
test('it shows the help text when an assignment but no id', () => {
|
||||
component = TestUtils.renderIntoDocument(
|
||||
<ConditionalRelease.Editor env={assignmentNoIdEnv} type='foo' />
|
||||
);
|
||||
ok(component.refs.saveDataMessage);
|
||||
});
|
||||
|
||||
test('it enabled its button when there is an assignment', () => {
|
||||
component = TestUtils.renderIntoDocument(
|
||||
<ConditionalRelease.Editor env={assignmentEnv} type='foo' />
|
||||
);
|
||||
const button = React.findDOMNode(component.refs.button);
|
||||
equal(button.disabled, false)
|
||||
});
|
||||
|
||||
test('it does not show the help text when there is an assignment', () => {
|
||||
component = TestUtils.renderIntoDocument(
|
||||
<ConditionalRelease.Editor env={assignmentEnv} type='foo' />
|
||||
);
|
||||
notOk(component.refs.saveDataMessage);
|
||||
});
|
||||
|
||||
test('it adds the hidden form when mounted', () => {
|
||||
component = TestUtils.renderIntoDocument(
|
||||
<ConditionalRelease.Editor env={assignmentEnv} type='foo' />
|
||||
);
|
||||
ok(document.contains(component.hiddenContainer().get(0)))
|
||||
});
|
||||
|
||||
test('it removes the hidden form when unmounted', () => {
|
||||
component = TestUtils.renderIntoDocument(
|
||||
<ConditionalRelease.Editor env={assignmentEnv} type='foo' />
|
||||
);
|
||||
const removed = React.unmountComponentAtNode(React.findDOMNode(component).parentNode);
|
||||
ok(removed)
|
||||
notOk(document.contains(component.hiddenContainer().get(0)))
|
||||
|
||||
component = null; // we've already removed, skip teardown
|
||||
});
|
||||
|
||||
test('it pops up the modal when the button is clicked', () => {
|
||||
component = TestUtils.renderIntoDocument(
|
||||
<ConditionalRelease.Editor env={assignmentEnv} type='foo' />
|
||||
);
|
||||
sinon.spy(component, 'submitForm');
|
||||
TestUtils.Simulate.click(component.refs.button);
|
||||
ok(component.submitForm.called);
|
||||
});
|
||||
|
||||
test('it disables when data is dirty', () => {
|
||||
component = TestUtils.renderIntoDocument(
|
||||
<ConditionalRelease.Editor env={assignmentEnv} type='foo' assignmentDirty={true} />
|
||||
);
|
||||
notOk(component.enabled());
|
||||
});
|
||||
});
|
|
@ -71,9 +71,9 @@ describe ConditionalRelease::Service do
|
|||
it 'creates urls' do
|
||||
stub_config({
|
||||
protocol: 'foo', host: 'bar',
|
||||
configure_defaults_app_path: 'some/path'
|
||||
edit_rule_path: 'some/path'
|
||||
})
|
||||
expect(Service.configure_defaults_url).to eq 'foo://bar/some/path'
|
||||
expect(Service.edit_rule_url).to eq 'foo://bar/some/path'
|
||||
end
|
||||
|
||||
it 'requires feature flag to be enabled' do
|
||||
|
@ -113,19 +113,19 @@ describe ConditionalRelease::Service do
|
|||
Service.stubs(:enabled_in_context?).returns(false)
|
||||
course_with_student_logged_in(active_all: true)
|
||||
env = Service.env_for(@course, @student, domain: 'foo.bar')
|
||||
expect(env).not_to have_key :CONDITIONAL_RELEASE_JWT
|
||||
expect(env).not_to have_key :CONDITIONAL_RELEASE_ENV
|
||||
end
|
||||
|
||||
it 'returns no jwt or env if user not specified' do
|
||||
course_model
|
||||
env = Service.env_for(@course)
|
||||
expect(env).not_to have_key :CONDITIONAL_RELEASE_JWT
|
||||
expect(env).not_to have_key :CONDITIONAL_RELEASE_ENV
|
||||
end
|
||||
|
||||
it 'returns a jwt if everything enabled' do
|
||||
it 'returns an env with jwt if everything enabled' do
|
||||
course_with_student_logged_in(active_all: true)
|
||||
env = Service.env_for(@course, @student, domain: 'foo.bar')
|
||||
expect(env[:CONDITIONAL_RELEASE_JWT]).to eq :jwt
|
||||
expect(env[:CONDITIONAL_RELEASE_ENV][:jwt]).to eq :jwt
|
||||
end
|
||||
|
||||
it 'includes assignment data when an assignment is specified' do
|
||||
|
|
Loading…
Reference in New Issue