show correct info when adding multiple grading schemes
when adding multiple grading schemes without refreshing the page, the information should show up correctly. also, when editing a scheme, you should not be able to edit, trash, or add any new schemes (until you've saved or cancelled editing). i also did some refactoring and split up the TabContainer file into two new components: GradingStandardContainer and GradingPeriodContainer. closes CNVS-18481 test plan: 1. Go to the grading standards page for a course or an account (/courses/:course_id/grading_standards or /accounts/:account_id/grading_standards) 2. Click the 'Add grading scheme' button. Verify that the button is grayed out and disabled after you click it. Also verify that the 'pencil' and 'trash' icons are not present on the scheme while you are editing it. Enter a new name for the grading scheme and change some of the row values, delete a few rows, etc. Then click 'Save'. Verify after clicking 'Save' that the 'Add grading scheme' button is un-grayed out and re-enabled. 3. Click the 'Add grading scheme' button again. Verify that the title and data of the _first_ grading scheme you created (listed below the one you're creating now) is still accurate. Enter in some custom data for the new scheme and then hit 'Save'. After hitting save, make sure both schemes show accurate information. 4. Refresh the page and make sure accurate data is still showing up. 5. Whenever a grading scheme is being edited, verify that clicking edit or trash icons on other schemes does not do anything. The icons of other schemes should be disabled when you are editing a scheme. 6. Whenever a grading scheme is being edited, verify that the 'Add grading scheme' button is grayed out/disabled. 7. Click the 'Add Grading Scheme' button and then, without clicking 'Save' or 'Cancel', refresh the page. The scheme that was just added should not be present, since it was never saved. Change-Id: I07f662729022a5d2ea4569fcbd8774147b4e2eee Reviewed-on: https://gerrit.instructure.com/48697 Tested-by: Jenkins Reviewed-by: Cameron Sutter <csutter@instructure.com> Product-Review: Spencer Olson <solson@instructure.com> QA-Review: Amber Taniuchi <amber@instructure.com>
This commit is contained in:
parent
a1315792db
commit
d5afa47968
|
@ -1 +1 @@
|
|||
require ['jsx/grading/tab_container']
|
||||
require ['jsx/grading/tabContainer']
|
||||
|
|
|
@ -30,7 +30,8 @@ class GradingStandardsController < ApplicationController
|
|||
js_env({
|
||||
:GRADING_STANDARDS_URL => context_url(@context, :context_grading_standards_url),
|
||||
:GRADING_PERIODS_URL => context_url(@context, :api_v1_context_grading_periods_url),
|
||||
:MULTIPLE_GRADING_PERIODS => multiple_grading_periods?
|
||||
:MULTIPLE_GRADING_PERIODS => multiple_grading_periods?,
|
||||
:DEFAULT_DATA => default_data
|
||||
})
|
||||
@standards = GradingStandard.standards_for(@context).sorted.limit(100)
|
||||
respond_to do |format|
|
||||
|
@ -52,7 +53,7 @@ class GradingStandardsController < ApplicationController
|
|||
@standard.user = @current_user
|
||||
respond_to do |format|
|
||||
if @standard.save
|
||||
format.json{ render :json => @standard.as_json(permissions: {user: @current_user}) }
|
||||
format.json{ render :json => @standard.as_json(methods: [:display_name, :context_code, :assessed_assignment?, :context_name], permissions: {user: @current_user}) }
|
||||
else
|
||||
format.json{ render :json => @standard.errors, :status => :bad_request }
|
||||
end
|
||||
|
@ -61,12 +62,12 @@ class GradingStandardsController < ApplicationController
|
|||
end
|
||||
|
||||
def update
|
||||
@standard = @context.grading_standards.find(params[:id])
|
||||
if authorized_action(@context, @current_user, :manage_grades)
|
||||
@standard = GradingStandard.standards_for(@context).find(params[:id])
|
||||
if authorized_action(@standard, @current_user, :manage)
|
||||
@standard.user = @current_user
|
||||
respond_to do |format|
|
||||
if @standard.update_attributes(params[:grading_standard])
|
||||
format.json{ render :json => @standard.as_json(permissions: {user: @current_user}) }
|
||||
format.json{ render :json => @standard.as_json(methods: [:display_name, :context_code, :assessed_assignment?, :context_name], permissions: {user: @current_user}) }
|
||||
else
|
||||
format.json{ render :json => @standard.errors, :status => :bad_request }
|
||||
end
|
||||
|
@ -75,11 +76,11 @@ class GradingStandardsController < ApplicationController
|
|||
end
|
||||
|
||||
def destroy
|
||||
@standard = @context.grading_standards.find(params[:id])
|
||||
if authorized_action(@context, @current_user, :manage_grades)
|
||||
@standard = GradingStandard.standards_for(@context).find(params[:id])
|
||||
if authorized_action(@standard, @current_user, :manage)
|
||||
respond_to do |format|
|
||||
if @standard.destroy
|
||||
format.json{ render :json => @standard.as_json(permissions: {user: @current_user}) }
|
||||
format.json{ render :json => @standard.as_json(methods: [:display_name, :context_code, :assessed_assignment?, :context_name], permissions: {user: @current_user}) }
|
||||
else
|
||||
format.json{ render :json => @standard.errors, :status => :bad_request }
|
||||
end
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/** @jsx React.DOM */
|
||||
|
||||
define([
|
||||
'old_unsupported_dont_use_react',
|
||||
'jsx/grading/gradingPeriod',
|
||||
'jquery',
|
||||
'i18n!external_tools',
|
||||
'underscore',
|
||||
'jquery.instructure_misc_plugins'
|
||||
],
|
||||
function(React, GradingPeriod, $, I18n, _) {
|
||||
|
||||
var GradingPeriodCollection = React.createClass({
|
||||
|
||||
getInitialState: function() {
|
||||
return {periods: null};
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
$.getJSON(ENV.GRADING_PERIODS_URL)
|
||||
.done(this.gotPeriods)
|
||||
},
|
||||
|
||||
gotPeriods: function(periods) {
|
||||
this.setState({periods: periods.grading_periods});
|
||||
},
|
||||
|
||||
deleteGradingPeriod: function(event, key) {
|
||||
var self = this,
|
||||
$period = $(event.target).parents(".grading-period");
|
||||
|
||||
$period.confirmDelete({
|
||||
url: ENV.GRADING_PERIODS_URL + "/" + key,
|
||||
message: I18n.t("Are you sure you want to delete this grading period?"),
|
||||
success: function() {
|
||||
$(this).slideUp(function() {
|
||||
$(this).remove();
|
||||
});
|
||||
var newPeriods = _.reject(self.state.periods, function(period){ return period.id === key });
|
||||
self.setState({periods: newPeriods});
|
||||
},
|
||||
error: function() {
|
||||
$.flashError(I18n.t("There was a problem deleting the grading period"));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
renderGradingPeriods: function() {
|
||||
if(!this.state.periods){
|
||||
return null;
|
||||
} else if(this.state.periods.length === 0){
|
||||
return <h3>{I18n.t("No grading periods to display")}</h3>;
|
||||
}
|
||||
var self = this;
|
||||
return this.state.periods.map(function(period){
|
||||
return (<GradingPeriod key={period.id} title={period.title} startDate={new Date(period.start_date)}
|
||||
endDate={new Date(period.end_date)} weight={period.weight}
|
||||
onDeleteGradingPeriod={self.deleteGradingPeriod}/>);
|
||||
});
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return(
|
||||
<div id="grading_periods" className="content-box">
|
||||
{this.renderGradingPeriods()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return GradingPeriodCollection;
|
||||
});
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
define([
|
||||
'old_unsupported_dont_use_react',
|
||||
'jsx/grading/data_row',
|
||||
'jsx/grading/dataRow',
|
||||
'jquery',
|
||||
'i18n!external_tools'
|
||||
],
|
||||
|
@ -15,9 +15,7 @@ function(React, DataRow, $, I18n) {
|
|||
standard: this.props.standard,
|
||||
permissions: this.props.permissions,
|
||||
editingStandard: $.extend(true, {}, this.props.standard),
|
||||
editing: this.props.editing,
|
||||
saving: false,
|
||||
justAdded: this.props.justAdded
|
||||
saving: false
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -26,64 +24,37 @@ function(React, DataRow, $, I18n) {
|
|||
standard: nextProps.standard,
|
||||
permissions: nextProps.permissions,
|
||||
editingStandard: $.extend(true, {}, this.props.standard),
|
||||
editing: nextProps.editing,
|
||||
saving: nextProps.saving,
|
||||
justAdded: nextProps.justAdded
|
||||
saving: nextProps.saving
|
||||
});
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
if(this.props.justAdded) this.refs.gradingStandardTitle.getDOMNode().focus();
|
||||
},
|
||||
|
||||
componentDidUpdate: function(prevProps, prevState) {
|
||||
if(this.state.editing !== prevState.editing) this.refs.gradingStandardTitle.getDOMNode().focus();
|
||||
},
|
||||
|
||||
startEditing: function(event) {
|
||||
event.preventDefault();
|
||||
this.setState({editing: true});
|
||||
},
|
||||
|
||||
stopEditing: function() {
|
||||
if(this.state.justAdded){
|
||||
return this.props.onDeleteGradingStandardNoWarning(this.props.key);
|
||||
}else{
|
||||
this.setState({standard: this.state.standard, editing: false,
|
||||
editingStandard: $.extend(true, {}, this.state.standard)});
|
||||
if(this.props.editing !== prevProps.editing){
|
||||
this.refs.gradingStandardTitle.getDOMNode().focus();
|
||||
this.setState({editingStandard: $.extend(true, {}, this.state.standard)})
|
||||
}
|
||||
},
|
||||
|
||||
triggerEditGradingStandard: function(event) {
|
||||
event.preventDefault();
|
||||
this.props.onSetEditingStatus(this.props.key, true);
|
||||
},
|
||||
|
||||
triggerStopEditingGradingStandard: function() {
|
||||
this.props.onSetEditingStatus(this.props.key, false);
|
||||
},
|
||||
|
||||
triggerDeleteGradingStandard: function(event) {
|
||||
return this.props.onDeleteGradingStandard(event, this.props.key);
|
||||
},
|
||||
|
||||
dataFormattedForPost: function() {
|
||||
var formattedData = { grading_standard: { title: this.state.editingStandard.title, standard_data: {} } };
|
||||
for(i = 0; i < this.state.editingStandard.data.length; i++){
|
||||
formattedData["grading_standard"]["standard_data"]["scheme_" + i] = {
|
||||
name: this.state.editingStandard.data[i][0],
|
||||
value: Math.round(this.state.editingStandard.data[i][1] * 10000)/100
|
||||
};
|
||||
};
|
||||
return formattedData;
|
||||
},
|
||||
|
||||
saveGradingStandard: function() {
|
||||
var self = this;
|
||||
var formattedData = this.dataFormattedForPost();
|
||||
triggerSaveGradingStandard: function() {
|
||||
this.setState({saving: true});
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
url: ENV.GRADING_STANDARDS_URL + "/" + this.state.editingStandard.id,
|
||||
data: formattedData,
|
||||
dataType: "json"
|
||||
})
|
||||
.success(function(response){
|
||||
self.setState({standard: response.grading_standard, editing: false,
|
||||
editingStandard: $.extend(true, {}, response.grading_standard),
|
||||
saving: false, justAdded: false});
|
||||
})
|
||||
.error(function(){
|
||||
self.setState({saving: false});
|
||||
$.flashError(I18n.t("There was a problem saving the grading scheme"));
|
||||
});
|
||||
return this.props.onSaveGradingStandard(this.state.editingStandard);
|
||||
},
|
||||
|
||||
assessedAssignment: function() {
|
||||
|
@ -96,9 +67,8 @@ function(React, DataRow, $, I18n) {
|
|||
},
|
||||
|
||||
insertGradingStandardRow: function(index) {
|
||||
var newEditingStandard = $.extend(true, {}, this.state.editingStandard);
|
||||
newEditingStandard.data.splice(index + 1, 0, [""," "]);
|
||||
this.setState({editingStandard: newEditingStandard});
|
||||
this.state.editingStandard.data.splice(index + 1, 0, [""," "]);
|
||||
this.setState({editingStandard: this.state.editingStandard});
|
||||
},
|
||||
|
||||
titleChange: function(event) {
|
||||
|
@ -117,6 +87,7 @@ function(React, DataRow, $, I18n) {
|
|||
},
|
||||
|
||||
renderCannotManageMessage: function() {
|
||||
if(this.props.permissions.manage && this.props.othersEditing) return null;
|
||||
if(this.state.standard.context_name){
|
||||
return (
|
||||
<div>
|
||||
|
@ -137,7 +108,7 @@ function(React, DataRow, $, I18n) {
|
|||
},
|
||||
|
||||
renderTitle: function() {
|
||||
if(this.state.editing){
|
||||
if(this.props.editing){
|
||||
return (
|
||||
<div className="pull-left" tabIndex="0">
|
||||
<input type="text" onChange={this.titleChange} className="grading_standard_title"
|
||||
|
@ -157,10 +128,10 @@ function(React, DataRow, $, I18n) {
|
|||
},
|
||||
|
||||
renderDataRows: function() {
|
||||
var data = this.state.editing ? this.state.editingStandard.data : this.state.standard.data;
|
||||
var data = this.props.editing ? this.state.editingStandard.data : this.state.standard.data;
|
||||
return data.map(function(item, idx, array){
|
||||
return (
|
||||
<DataRow key={idx} row={item} siblingRow={array[idx - 1]} editing={this.state.editing}
|
||||
<DataRow key={idx} row={item} siblingRow={array[idx - 1]} editing={this.props.editing}
|
||||
onDeleteRow={this.deleteDataRow} onInsertRow={this.insertGradingStandardRow}
|
||||
onRowMinScoreChange={this.changeRowMinScore} onRowNameChange={this.changeRowName}/>
|
||||
);
|
||||
|
@ -176,17 +147,17 @@ function(React, DataRow, $, I18n) {
|
|||
);
|
||||
}
|
||||
return (
|
||||
<button type="button" onClick={this.saveGradingStandard} className="btn btn-primary save_button">
|
||||
<button type="button" onClick={this.triggerSaveGradingStandard} className="btn btn-primary save_button">
|
||||
{I18n.t("Save")}
|
||||
</button>
|
||||
);
|
||||
},
|
||||
|
||||
renderSaveAndCancelButtons: function() {
|
||||
if(this.state.editing){
|
||||
if(this.props.editing){
|
||||
return (
|
||||
<div className="form-actions">
|
||||
<button type="button" onClick={this.stopEditing} className="btn cancel_button">
|
||||
<button type="button" onClick={this.triggerStopEditingGradingStandard} className="btn cancel_button">
|
||||
{I18n.t("Cancel")}
|
||||
</button>
|
||||
{this.renderSaveButton()}
|
||||
|
@ -196,32 +167,34 @@ function(React, DataRow, $, I18n) {
|
|||
return null;
|
||||
},
|
||||
|
||||
renderEditIcon: function() {
|
||||
if(!this.state.editing){
|
||||
renderEditAndDeleteIcons: function() {
|
||||
if(!this.props.editing){
|
||||
return(
|
||||
<a href="#" onClick={this.startEditing} title={I18n.t("Edit Grading Scheme")}
|
||||
className={"edit_grading_standard_link no-hover " + (this.assessedAssignment() ? "read_only" : "")}
|
||||
tabIndex="1">
|
||||
<span className="screenreader-only">{I18n.t("Edit Grading Scheme")}</span>
|
||||
<i className="icon-edit standalone-icon"/>
|
||||
</a>
|
||||
<div>
|
||||
<a href="#" onClick={this.triggerEditGradingStandard} title={I18n.t("Edit Grading Scheme")}
|
||||
className={"edit_grading_standard_link no-hover " + (this.assessedAssignment() ? "read_only" : "")}
|
||||
tabIndex="1">
|
||||
<span className="screenreader-only">{I18n.t("Edit Grading Scheme")}</span>
|
||||
<i className="icon-edit standalone-icon"/>
|
||||
</a>
|
||||
<a href="#" title={I18n.t("Delete Grading Scheme")} onClick={this.triggerDeleteGradingStandard}
|
||||
className="delete_grading_standard_link no-hover" tabIndex="1">
|
||||
<span className="screenreader-only">{I18n.t("Delete Grading Scheme")}</span>
|
||||
<i className="icon-trash standalone-icon"/>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
renderIconsAndTitle: function() {
|
||||
if(this.state.permissions.manage){
|
||||
if(this.state.permissions.manage && !this.props.othersEditing){
|
||||
return (
|
||||
<div>
|
||||
{this.renderTitle()}
|
||||
<div className="links">
|
||||
{this.renderEditIcon()}
|
||||
<a href="#" title={I18n.t("Delete Grading Scheme")} onClick={this.triggerDeleteGradingStandard}
|
||||
className="delete_grading_standard_link no-hover" tabIndex="1">
|
||||
<span className="screenreader-only">{I18n.t("Delete Grading Scheme")}</span>
|
||||
<i className="icon-trash standalone-icon"/>
|
||||
</a>
|
||||
{this.renderEditAndDeleteIcons()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
|
@ -0,0 +1,172 @@
|
|||
/** @jsx React.DOM */
|
||||
|
||||
define([
|
||||
'old_unsupported_dont_use_react',
|
||||
'jsx/grading/gradingStandard',
|
||||
'jquery',
|
||||
'i18n!external_tools',
|
||||
'underscore',
|
||||
'jquery.instructure_misc_plugins'
|
||||
],
|
||||
function(React, GradingStandard, $, I18n, _) {
|
||||
|
||||
var GradingStandardCollection = React.createClass({
|
||||
|
||||
getInitialState: function() {
|
||||
return {standards: null};
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
$.getJSON(ENV.GRADING_STANDARDS_URL)
|
||||
.done(this.gotStandards)
|
||||
},
|
||||
|
||||
gotStandards: function(standards) {
|
||||
this.setState({standards: standards});
|
||||
},
|
||||
|
||||
addGradingStandard: function() {
|
||||
var newStandards = _.map(this.state.standards, function(standard){
|
||||
standard.editing = false;
|
||||
standard.justAdded = false;
|
||||
return standard;
|
||||
});
|
||||
|
||||
var newStandard = {
|
||||
editing: true,
|
||||
justAdded: true,
|
||||
grading_standard: {
|
||||
permissions: { manage: true },
|
||||
title: "",
|
||||
data: ENV.DEFAULT_DATA,
|
||||
id: -1
|
||||
}
|
||||
};
|
||||
|
||||
newStandards.unshift(newStandard);
|
||||
this.setState({standards: newStandards});
|
||||
},
|
||||
|
||||
getStandardById: function(id) {
|
||||
return _.find(this.state.standards, function(standard){ return standard.grading_standard.id === id });
|
||||
},
|
||||
|
||||
standardNotCreated: function(gradingStandard){
|
||||
return gradingStandard.id === -1;
|
||||
},
|
||||
|
||||
setEditingStatus: function(id, setEditingStatusTo){
|
||||
var existingStandard = this.getStandardById(id)
|
||||
var indexToEdit = this.state.standards.indexOf(existingStandard);
|
||||
if(setEditingStatusTo === false && this.standardNotCreated(existingStandard.grading_standard)){
|
||||
var newStandards = this.state.standards;
|
||||
newStandards.splice(indexToEdit, 1);
|
||||
this.setState({standards: newStandards});
|
||||
}else{
|
||||
this.state.standards[indexToEdit].editing = setEditingStatusTo;
|
||||
this.setState({standards: this.state.standards})
|
||||
}
|
||||
},
|
||||
|
||||
standardBeingEdited: function() {
|
||||
return !!_.find(this.state.standards, function(standard){return standard.editing});
|
||||
},
|
||||
|
||||
saveGradingStandard: function(standard) {
|
||||
var indexToUpdate = this.state.standards.indexOf(this.getStandardById(standard.id));
|
||||
if(standard.title === "" && this.standardNotCreated(standard)) standard.title = "New Grading Scheme";
|
||||
var self = this;
|
||||
$.ajax({
|
||||
type: this.standardNotCreated(standard) ? "POST" : "PUT",
|
||||
url: this.standardNotCreated(standard) ? ENV.GRADING_STANDARDS_URL : ENV.GRADING_STANDARDS_URL + "/" + standard.id,
|
||||
data: this.dataFormattedForUpdate(standard),
|
||||
dataType: "json"
|
||||
})
|
||||
.success(function(updatedStandard){
|
||||
self.state.standards[indexToUpdate] = updatedStandard;
|
||||
self.setState({standards: self.state.standards});
|
||||
})
|
||||
.error(function(){
|
||||
self.state.standards[indexToUpdate].grading_standard.saving = false;
|
||||
self.setState({standards: self.state.standards});
|
||||
$.flashError(I18n.t("There was a problem saving the grading scheme"));
|
||||
});
|
||||
},
|
||||
|
||||
dataFormattedForUpdate: function(standard) {
|
||||
var formattedData = { grading_standard: { title: standard.title, standard_data: {} } };
|
||||
for(i = 0; i < standard.data.length; i++){
|
||||
formattedData["grading_standard"]["standard_data"]["scheme_" + i] = {
|
||||
name: standard.data[i][0],
|
||||
value: Math.round(standard.data[i][1] * 10000)/100
|
||||
};
|
||||
};
|
||||
return formattedData;
|
||||
},
|
||||
|
||||
deleteGradingStandard: function(event, key) {
|
||||
var self = this,
|
||||
$standard = $(event.target).parents(".grading_standard");
|
||||
$standard.confirmDelete({
|
||||
url: ENV.GRADING_STANDARDS_URL + "/" + key,
|
||||
message: I18n.t("Are you sure you want to delete this grading scheme?"),
|
||||
success: function() {
|
||||
$(this).slideUp(function() {
|
||||
$(this).remove();
|
||||
});
|
||||
var newStandards = _.reject(self.state.standards, function(standard){ return standard.grading_standard.id === key });
|
||||
self.setState({standards: newStandards});
|
||||
},
|
||||
error: function() {
|
||||
$.flashError(I18n.t("There was a problem deleting the grading scheme"));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
hasAdminOrTeacherRole: function() {
|
||||
return _.intersection(ENV.current_user_roles, ["teacher", "admin"]).length > 0;
|
||||
},
|
||||
|
||||
getAddButtonCssClasses: function() {
|
||||
var classes = "btn pull-right add_standard_link"
|
||||
if(!this.hasAdminOrTeacherRole() || this.standardBeingEdited()) classes += " disabled"
|
||||
return classes;
|
||||
},
|
||||
|
||||
renderGradingStandards: function() {
|
||||
if(!this.state.standards){
|
||||
return null;
|
||||
} else if(this.state.standards.length === 0){
|
||||
return <h3>{I18n.t("No grading schemes to display")}</h3>;
|
||||
}
|
||||
var self = this;
|
||||
return this.state.standards.map(function(s){
|
||||
return (<GradingStandard key={s.grading_standard.id} standard={s.grading_standard}
|
||||
editing={!!s.editing} permissions={s.grading_standard.permissions}
|
||||
justAdded={s.justAdded} onSetEditingStatus={self.setEditingStatus}
|
||||
othersEditing={!s.editing && self.standardBeingEdited()}
|
||||
onDeleteGradingStandard={self.deleteGradingStandard}
|
||||
onSaveGradingStandard={self.saveGradingStandard}/>);
|
||||
});
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return(
|
||||
<div>
|
||||
<div className="rs-margin-all pull-right">
|
||||
<a href="#" onClick={this.addGradingStandard} className={this.getAddButtonCssClasses()}>
|
||||
<i className="icon-add"/>
|
||||
{I18n.t(" Add grading scheme")}
|
||||
</a>
|
||||
</div>
|
||||
<div id="standards" className="content-box react_grading_standards">
|
||||
{this.renderGradingStandards()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return GradingStandardCollection;
|
||||
|
||||
});
|
|
@ -0,0 +1,51 @@
|
|||
/** @jsx React.DOM */
|
||||
|
||||
define([
|
||||
'old_unsupported_dont_use_react',
|
||||
'jsx/grading/gradingStandardCollection',
|
||||
'jsx/grading/gradingPeriodCollection',
|
||||
'jquery',
|
||||
'i18n!external_tools',
|
||||
'underscore',
|
||||
'jquery.instructure_misc_plugins'
|
||||
],
|
||||
function(React, GradingStandardCollection, GradingPeriodCollection, $, I18n, _) {
|
||||
|
||||
var TabContainer = React.createClass({
|
||||
|
||||
componentDidMount: function() {
|
||||
$(this.getDOMNode()).children(".ui-tabs-minimal").tabs();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
if(ENV.MULTIPLE_GRADING_PERIODS){
|
||||
return (
|
||||
<div>
|
||||
<div className="ui-tabs-minimal">
|
||||
<ul>
|
||||
<li><a href="#grading-periods-tab" className="grading_periods_tab"> {I18n.t('Grading Periods')}</a></li>
|
||||
<li><a href="#grading-standards-tab" className="grading_standards_tab"> {I18n.t('Grading Schemes')}</a></li>
|
||||
</ul>
|
||||
<div id="grading-periods-tab">
|
||||
<GradingPeriodCollection/>
|
||||
</div>
|
||||
<div id="grading-standards-tab">
|
||||
<GradingStandardCollection/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else{
|
||||
return (
|
||||
<div>
|
||||
<h1 tabIndex="0">{I18n.t("Grading Schemes")}</h1>
|
||||
<GradingStandardCollection/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
React.renderComponent(<TabContainer/>, document.getElementById("react_grading_tabs"));
|
||||
|
||||
});
|
|
@ -1,209 +0,0 @@
|
|||
/** @jsx React.DOM */
|
||||
|
||||
define([
|
||||
'old_unsupported_dont_use_react',
|
||||
'jsx/grading/grading_standard',
|
||||
'jsx/grading/grading_period',
|
||||
'jquery',
|
||||
'i18n!external_tools',
|
||||
'underscore',
|
||||
'jquery.instructure_misc_plugins'
|
||||
],
|
||||
function(React, GradingStandard, GradingPeriod, $, I18n, _) {
|
||||
|
||||
var TabContainer = React.createClass({
|
||||
|
||||
getInitialState: function() {
|
||||
return {standards: null, periods: null};
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
$.getJSON(ENV.GRADING_STANDARDS_URL)
|
||||
.done(this.gotStandards)
|
||||
|
||||
if(ENV.MULTIPLE_GRADING_PERIODS){
|
||||
$.getJSON(ENV.GRADING_PERIODS_URL)
|
||||
.done(this.gotPeriods)
|
||||
}
|
||||
},
|
||||
|
||||
gotStandards: function(standards) {
|
||||
this.setState({standards: standards});
|
||||
},
|
||||
|
||||
gotPeriods: function(periods) {
|
||||
this.setState({periods: periods.grading_periods});
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
$(this.getDOMNode()).children(".ui-tabs-minimal").tabs();
|
||||
},
|
||||
|
||||
addGradingStandard: function() {
|
||||
var newStandards = _.map(this.state.standards, function(standard){
|
||||
standard.editing = false;
|
||||
standard.justAdded = false;
|
||||
return standard;
|
||||
});
|
||||
var self = this;
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: ENV.GRADING_STANDARDS_URL,
|
||||
data: { grading_standard: { title: I18n.t("New Title") } },
|
||||
dataType: "json"
|
||||
})
|
||||
.success(function(newStandard) {
|
||||
newStandard.editing = true;
|
||||
newStandard.justAdded = true;
|
||||
newStandards.unshift(newStandard);
|
||||
$(this).slideDown();
|
||||
self.setState({standards: newStandards});
|
||||
})
|
||||
.error(function() {
|
||||
$.flashError(I18n.t("There was a problem adding the grading scheme"));
|
||||
});
|
||||
},
|
||||
|
||||
deleteGradingStandard: function(event, key) {
|
||||
var self = this,
|
||||
$standard = $(event.target).parents(".grading_standard");
|
||||
|
||||
$standard.confirmDelete({
|
||||
url: ENV.GRADING_STANDARDS_URL + "/" + key,
|
||||
message: I18n.t("Are you sure you want to delete this grading scheme?"),
|
||||
success: function() {
|
||||
$(this).slideUp(function() {
|
||||
$(this).remove();
|
||||
});
|
||||
var newStandards = _.reject(self.state.standards, function(standard){ return standard.grading_standard.id === key });
|
||||
self.setState({standards: newStandards});
|
||||
},
|
||||
error: function() {
|
||||
$.flashError(I18n.t("There was a problem deleting the grading scheme"));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
deleteGradingPeriod: function(event, key) {
|
||||
var self = this,
|
||||
$period = $(event.target).parents(".grading-period");
|
||||
|
||||
$period.confirmDelete({
|
||||
url: ENV.GRADING_PERIODS_URL + "/" + key,
|
||||
message: I18n.t("Are you sure you want to delete this grading period?"),
|
||||
success: function() {
|
||||
$(this).slideUp(function() {
|
||||
$(this).remove();
|
||||
});
|
||||
var newPeriods = _.reject(self.state.periods, function(period){ return period.id === key });
|
||||
self.setState({periods: newPeriods});
|
||||
},
|
||||
error: function() {
|
||||
$.flashError(I18n.t("There was a problem deleting the grading period"));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
deleteGradingStandardNoWarning: function(key) {
|
||||
var self = this;
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
url: ENV.GRADING_STANDARDS_URL + "/" + key,
|
||||
dataType: "json"
|
||||
})
|
||||
.success(function(){
|
||||
var newStandards = _.reject(self.state.standards, function(standard){ return standard.grading_standard.id === key });
|
||||
self.setState({standards: newStandards});
|
||||
})
|
||||
.error(function(){
|
||||
$.flashError(I18n.t("There was a problem deleting the grading scheme"));
|
||||
});
|
||||
},
|
||||
|
||||
hasAdminOrTeacherRole: function() {
|
||||
return _.intersection(ENV.current_user_roles, ["teacher", "admin"]).length > 0;
|
||||
},
|
||||
|
||||
renderAddGradingStandardButton: function() {
|
||||
if(this.hasAdminOrTeacherRole()){
|
||||
return(
|
||||
<div className="rs-margin-all pull-right">
|
||||
<a href="#" onClick={this.addGradingStandard} className="btn pull-right add_standard_link">
|
||||
<i className="icon-add"/>
|
||||
{I18n.t(" Add grading scheme")}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
renderGradingStandards: function() {
|
||||
if(!this.state.standards){
|
||||
return null;
|
||||
} else if(this.state.standards.length === 0){
|
||||
return <h3>{I18n.t("No grading schemes to display")}</h3>;
|
||||
}
|
||||
var self = this;
|
||||
return this.state.standards.map(function(s){
|
||||
return (<GradingStandard key={s.grading_standard.id} standard={s.grading_standard}
|
||||
editing={!!s.editing} permissions={s.grading_standard.permissions}
|
||||
justAdded={!!s.justAdded} onDeleteGradingStandard={self.deleteGradingStandard}
|
||||
onDeleteGradingStandardNoWarning={self.deleteGradingStandardNoWarning}/>);
|
||||
});
|
||||
},
|
||||
|
||||
renderGradingPeriods: function() {
|
||||
if(!this.state.periods){
|
||||
return null;
|
||||
} else if(this.state.periods.length === 0){
|
||||
return <h3>{I18n.t("No grading periods to display")}</h3>;
|
||||
}
|
||||
var self = this;
|
||||
return this.state.periods.map(function(p){
|
||||
return (<GradingPeriod key={p.id} title={p.title} startDate={new Date(p.start_date)}
|
||||
endDate={new Date(p.end_date)} weight={p.weight}
|
||||
onDeleteGradingPeriod={self.deleteGradingPeriod}/>);
|
||||
});
|
||||
},
|
||||
|
||||
render: function () {
|
||||
if(ENV.MULTIPLE_GRADING_PERIODS){
|
||||
return (
|
||||
<div>
|
||||
<div className="ui-tabs-minimal">
|
||||
<ul>
|
||||
<li><a href="#grading-periods-tab" className="grading_periods_tab"> {I18n.t('Grading Periods')}</a></li>
|
||||
<li><a href="#grading-standards-tab" className="grading_standards_tab"> {I18n.t('Grading Schemes')}</a></li>
|
||||
</ul>
|
||||
<div id="grading-periods-tab">
|
||||
<div id="grading_periods" className="content-box">
|
||||
{this.renderGradingPeriods()}
|
||||
</div>
|
||||
</div>
|
||||
<div id="grading-standards-tab">
|
||||
{this.renderAddGradingStandardButton()}
|
||||
<div id="standards" className="content-box react_grading_standards">
|
||||
{this.renderGradingStandards()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else{
|
||||
return (
|
||||
<div>
|
||||
<h1 tabIndex="0">{I18n.t("Grading Schemes")}</h1>
|
||||
{this.renderAddGradingStandardButton()}
|
||||
<div id="standards" className="content-box react_grading_standards">
|
||||
{this.renderGradingStandards()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
React.renderComponent(<TabContainer/>, document.getElementById("react_grading_tabs"));
|
||||
|
||||
});
|
|
@ -17,6 +17,17 @@ describe "grading standards" do
|
|||
should_delete_a_grading_scheme(@course, "/courses/#{@course.id}/grading_standards")
|
||||
end
|
||||
|
||||
it "should display correct info when multiple standards are added without refreshing page" do
|
||||
course_with_teacher_logged_in
|
||||
get "/courses/#{@course.id}/grading_standards"
|
||||
should_add_a_grading_scheme(name: "First Grading Standard")
|
||||
first_grading_standard = @new_grading_standard
|
||||
should_add_a_grading_scheme(name: "Second Grading Standard")
|
||||
second_grading_standard = @new_grading_standard
|
||||
expect(fj("#grading_standard_#{first_grading_standard.id} span:eq(1)").text).to eq("First Grading Standard")
|
||||
expect(fj("#grading_standard_#{second_grading_standard.id} span:eq(1)").text).to eq("Second Grading Standard")
|
||||
end
|
||||
|
||||
it "should allow setting a grading standard for an assignment" do
|
||||
course_with_teacher_logged_in
|
||||
|
||||
|
|
|
@ -14,15 +14,15 @@ def simple_grading_standard(context)
|
|||
})
|
||||
end
|
||||
|
||||
def should_add_a_grading_scheme
|
||||
new_standard_name = 'new grading standard'
|
||||
def should_add_a_grading_scheme(options = {name: "new grading standard"})
|
||||
new_standard_name = options[:name]
|
||||
f('.add_standard_link').click
|
||||
replace_content(f('.scheme_name'), new_standard_name)
|
||||
f('.save_button').click
|
||||
wait_for_ajax_requests
|
||||
new_grading_standard = GradingStandard.last
|
||||
expect(new_grading_standard.title).to eq new_standard_name
|
||||
expect(f("#grading_standard_#{new_grading_standard.id}")).to be_displayed
|
||||
@new_grading_standard = GradingStandard.last
|
||||
expect(@new_grading_standard.title).to eq new_standard_name
|
||||
expect(f("#grading_standard_#{@new_grading_standard.id}")).to be_displayed
|
||||
end
|
||||
|
||||
def should_edit_a_grading_scheme(context, url)
|
||||
|
|
Loading…
Reference in New Issue