add custom statuses to gradebook imports - FE 1/2
allows the front end importer to recognize that there are custom statuses for overrides that have changed from the current import, showing which rows/columns changed. this is part 1/2, as the next commit will add the last part which is saving those changes closes EVAL-3441 flag=custom_gradebook_statuses test plan: - CANNOT BE QA'd UNTIL g/326378 IS MERGED - go to a course with grading periods and for the gradebook filter, select "All Grading Periods" - add a custom status to a final grade override using the tray - export the entire gradebook - open a CSV editor and change the custom status you added to something else and add another status for another student - MAKE SURE THAT BOTH STUDENTS WHO WERE CHANGED ARE USERS WITH LOGINS (otherwise they are not gradable students and the importer does not recognize them) - use the importer to import the CSV you just edited - it should recognize the changes and show the columns and rows that changed - now do the same but for a single grading period, using the option to export the current gradebook view instead of entire gradebook - it should recognize the changes and show the columns and rows that changed - note: "applying" the changes or saving them will not work until the next commit is merged Change-Id: I081b05d63ac0a75d08ae23acb79388fcbf58ca4b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/326452 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Christopher Soto <christopher.soto@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> QA-Review: Christopher Soto <christopher.soto@instructure.com> Product-Review: Ravi Koll <ravi.koll@instructure.com>
This commit is contained in:
parent
685406a1df
commit
b2dbfa076b
|
@ -191,6 +191,14 @@ QUnit.module('override score changes', hooks => {
|
|||
],
|
||||
includes_course_scores: false,
|
||||
},
|
||||
override_statuses: {
|
||||
grading_periods: [
|
||||
{id: 1, title: 'first GP'},
|
||||
{id: 2, title: 'second GP'},
|
||||
{id: 3, title: 'third GP'},
|
||||
],
|
||||
includes_course_score_status: false,
|
||||
},
|
||||
students: [
|
||||
{
|
||||
custom_column_data: [],
|
||||
|
@ -213,6 +221,26 @@ QUnit.module('override score changes', hooks => {
|
|||
new_score: null,
|
||||
},
|
||||
],
|
||||
override_statuses: [
|
||||
{
|
||||
grading_period_id: '1',
|
||||
student_id: '1',
|
||||
current_grade_status: 'CARROT',
|
||||
new_grade_status: 'POTATO',
|
||||
},
|
||||
{
|
||||
grading_period_id: '2',
|
||||
student_id: '1',
|
||||
current_grade_status: null,
|
||||
new_grade_status: 'CARROT',
|
||||
},
|
||||
{
|
||||
grading_period_id: '3',
|
||||
student_id: '1',
|
||||
current_grade_status: 'POTATO',
|
||||
new_grade_status: null,
|
||||
},
|
||||
],
|
||||
previous_id: '1',
|
||||
submissions: [{assignment_id: '-1', grade: '0.0', gradeable: true, original_grade: null}],
|
||||
},
|
||||
|
@ -317,6 +345,70 @@ QUnit.module('override score changes', hooks => {
|
|||
)
|
||||
notOk(gradingPeriodColumn)
|
||||
})
|
||||
|
||||
test('creates a pair of columns for each grading period in the grading_periods hash of override status', () => {
|
||||
initGradebook()
|
||||
|
||||
const columnIds = mainGridArgs.columns
|
||||
.map(column => column.id)
|
||||
.filter(id => id.includes('override_status'))
|
||||
|
||||
deepEqual(columnIds, [
|
||||
'override_status_1_conflicting',
|
||||
'override_status_1',
|
||||
'override_status_2_conflicting',
|
||||
'override_status_2',
|
||||
'override_status_3_conflicting',
|
||||
'override_status_3',
|
||||
])
|
||||
})
|
||||
|
||||
test('adds a header for each grading period including the title of the grading period of override status', () => {
|
||||
initGradebook()
|
||||
|
||||
const headers = headerGridArgs.columns
|
||||
.map(column => column.name)
|
||||
.filter(name => name.includes('Override Status'))
|
||||
|
||||
deepEqual(headers, [
|
||||
'Override Status (first GP)',
|
||||
'Override Status (second GP)',
|
||||
'Override Status (third GP)',
|
||||
])
|
||||
})
|
||||
|
||||
test('creates a column for course status if includes_course_score_status is true', () => {
|
||||
defaultUploadedGradebook.override_statuses.includes_course_score_status = true
|
||||
defaultUploadedGradebook.override_statuses.grading_periods = []
|
||||
|
||||
initGradebook()
|
||||
|
||||
const gradingPeriodColumn = mainGridArgs.columns.find(
|
||||
column => column.id === 'override_status_course'
|
||||
)
|
||||
ok(gradingPeriodColumn)
|
||||
})
|
||||
|
||||
test('adds a header for course status with the label of plain old "Override Status"', () => {
|
||||
defaultUploadedGradebook.override_statuses.includes_course_score_status = true
|
||||
defaultUploadedGradebook.override_statuses.grading_periods = []
|
||||
|
||||
initGradebook()
|
||||
|
||||
const gradingPeriodColumn = headerGridArgs.columns.find(
|
||||
column => column.name === 'Override Status'
|
||||
)
|
||||
ok(gradingPeriodColumn)
|
||||
})
|
||||
|
||||
test('does not create a column for course status if includes_course_score_status is false', () => {
|
||||
initGradebook()
|
||||
|
||||
const gradingPeriodColumn = mainGridArgs.columns.find(
|
||||
column => column.id === 'override_status_course'
|
||||
)
|
||||
notOk(gradingPeriodColumn)
|
||||
})
|
||||
})
|
||||
|
||||
QUnit.module('value population', () => {
|
||||
|
@ -389,6 +481,7 @@ QUnit.module('override score changes', hooks => {
|
|||
new_score: '70',
|
||||
},
|
||||
]
|
||||
defaultUploadedGradebook.students[0].override_statuses = []
|
||||
initGradebook()
|
||||
|
||||
// setCellCssStyles should be called with an empty hash since nothing to
|
||||
|
@ -404,11 +497,126 @@ QUnit.module('override score changes', hooks => {
|
|||
new_score: '70',
|
||||
},
|
||||
]
|
||||
defaultUploadedGradebook.students[0].override_statuses = []
|
||||
initGradebook()
|
||||
|
||||
// setCellCssStyles should be called with an empty hash since nothing to
|
||||
// highlight
|
||||
deepEqual(gradeReviewRow, {}, 'no highlightable changes')
|
||||
})
|
||||
|
||||
test('populates the grid data with course override statuses for each student', () => {
|
||||
defaultUploadedGradebook.override_statuses.includes_course_score_status = true
|
||||
defaultUploadedGradebook.override_statuses.grading_periods = []
|
||||
defaultUploadedGradebook.students[0].override_statuses = [
|
||||
{
|
||||
grading_period_id: null,
|
||||
student_id: '1',
|
||||
current_grade_status: 'BROCCOLI',
|
||||
new_grade_status: 'POTATO',
|
||||
},
|
||||
]
|
||||
initGradebook()
|
||||
|
||||
const dataForStudent = mainGridArgs.data.find(datum => datum.id === '1')
|
||||
deepEqual(dataForStudent.override_status_course, {
|
||||
current_grade_status: 'BROCCOLI',
|
||||
new_grade_status: 'POTATO',
|
||||
grading_period_id: null,
|
||||
student_id: '1',
|
||||
})
|
||||
})
|
||||
|
||||
test('populates the grid data with grading period override statuses for each student', () => {
|
||||
initGradebook()
|
||||
|
||||
const dataForStudent = mainGridArgs.data.find(datum => datum.id === '1')
|
||||
deepEqual(dataForStudent.override_status_1, {
|
||||
grading_period_id: '1',
|
||||
student_id: '1',
|
||||
current_grade_status: 'CARROT',
|
||||
new_grade_status: 'POTATO',
|
||||
})
|
||||
})
|
||||
|
||||
test('highlights cells if the override status is changed', () => {
|
||||
initGradebook()
|
||||
const firstStudentRow = gradeReviewRow[0]
|
||||
strictEqual(
|
||||
firstStudentRow.override_status_1_conflicting,
|
||||
'left-highlight',
|
||||
'current status is highlighted'
|
||||
)
|
||||
strictEqual(
|
||||
firstStudentRow.override_status_1,
|
||||
'right-highlight',
|
||||
'updated status is highlighted'
|
||||
)
|
||||
})
|
||||
|
||||
test('highlights cells if the override status has been removed', () => {
|
||||
initGradebook()
|
||||
|
||||
const firstStudentRow = gradeReviewRow[0]
|
||||
strictEqual(
|
||||
firstStudentRow.override_status_3_conflicting,
|
||||
'left-highlight',
|
||||
'current status is highlighted'
|
||||
)
|
||||
strictEqual(
|
||||
firstStudentRow.override_status_3,
|
||||
'right-highlight',
|
||||
'updated (removed) status is highlighted'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test('does not highlight the cells if the override status has been newly added', () => {
|
||||
defaultUploadedGradebook.students[0].override_scores = []
|
||||
defaultUploadedGradebook.students[0].override_statuses = [
|
||||
{
|
||||
grading_period_id: '1',
|
||||
student_id: '1',
|
||||
current_grade_status: null,
|
||||
new_grade_status: 'POTATO',
|
||||
},
|
||||
]
|
||||
initGradebook()
|
||||
|
||||
deepEqual(gradeReviewRow, {}, 'no highlightable changes')
|
||||
})
|
||||
|
||||
test('does not highlight cells if the override status has not changed', () => {
|
||||
defaultUploadedGradebook.students[0].override_scores = []
|
||||
defaultUploadedGradebook.students[0].override_statuses = [
|
||||
{
|
||||
grading_period_id: '1',
|
||||
student_id: '1',
|
||||
current_grade_status: 'POTATO',
|
||||
new_grade_status: 'POTATO',
|
||||
},
|
||||
]
|
||||
initGradebook()
|
||||
|
||||
// setCellCssStyles should be called with an empty hash since nothing to
|
||||
// highlight
|
||||
deepEqual(gradeReviewRow, {}, 'no highlightable changes')
|
||||
})
|
||||
|
||||
test('does not highlight cells if the override status case changed', () => {
|
||||
defaultUploadedGradebook.students[0].override_scores = []
|
||||
defaultUploadedGradebook.students[0].override_statuses = [
|
||||
{
|
||||
grading_period_id: '1',
|
||||
student_id: '1',
|
||||
current_grade_status: 'POTATO',
|
||||
new_grade_status: 'potato',
|
||||
},
|
||||
]
|
||||
initGradebook()
|
||||
|
||||
// setCellCssStyles should be called with an empty hash since nothing to
|
||||
// highlight
|
||||
deepEqual(gradeReviewRow, {}, 'no highlightable changes')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -197,6 +197,16 @@ const GradebookUploader = {
|
|||
this.addOverrideScoreChangeColumn(labelData, gridData, gradingPeriod)
|
||||
})
|
||||
}
|
||||
if (uploadedGradebook.override_statuses != null) {
|
||||
const overrideStatuses = uploadedGradebook.override_statuses
|
||||
if (overrideStatuses.includes_course_score_status) {
|
||||
this.addOverrideStatusChangeColumn(labelData, gridData)
|
||||
}
|
||||
|
||||
overrideStatuses.grading_periods.forEach(gradingPeriod => {
|
||||
this.addOverrideStatusChangeColumn(labelData, gridData, gradingPeriod)
|
||||
})
|
||||
}
|
||||
|
||||
$.each(uploadedGradebook.students, function (index) {
|
||||
const row = {
|
||||
|
@ -235,6 +245,21 @@ const GradebookUploader = {
|
|||
row[`${columnId}_conflicting`] = overrideScore
|
||||
})
|
||||
|
||||
currentStudent.override_statuses?.forEach(overrideStatus => {
|
||||
const id = overrideStatus.grading_period_id || 'course'
|
||||
const columnId = `override_status_${id}`
|
||||
|
||||
if (
|
||||
overrideStatus.current_grade_status !== null &&
|
||||
overrideStatus.current_grade_status?.toLowerCase() !==
|
||||
overrideStatus.new_grade_status?.toLowerCase()
|
||||
) {
|
||||
rowsToHighlight.push({rowIndex: index, id: columnId})
|
||||
}
|
||||
row[columnId] = overrideStatus
|
||||
row[`${columnId}_conflicting`] = overrideStatus
|
||||
})
|
||||
|
||||
gridData.data.push(row)
|
||||
row.active = true
|
||||
})
|
||||
|
@ -530,6 +555,46 @@ const GradebookUploader = {
|
|||
}
|
||||
labelData.columns.push(overrideScoreHeaderColumn)
|
||||
},
|
||||
|
||||
addOverrideStatusChangeColumn(labelData, gridData, gradingPeriod = null) {
|
||||
// A null grading period means these changes are for override grades for the course
|
||||
const id = gradingPeriod?.id || 'course'
|
||||
const title = gradingPeriod?.title
|
||||
? I18n.t('Override Status (%{gradingPeriod})', {gradingPeriod: gradingPeriod.title})
|
||||
: I18n.t('Override Status')
|
||||
|
||||
const newOverrideStatusColumn = {
|
||||
id: `override_status_${id}`,
|
||||
type: 'assignment',
|
||||
name: htmlEscape(I18n.t('To')),
|
||||
field: `override_status_${id}`,
|
||||
width: 125,
|
||||
editor: Slick.Editors.UploadGradeCellEditor,
|
||||
editorFormatter: 'override_status',
|
||||
editorParser: 'override_status',
|
||||
formatter: GradebookUploader.createGeneralFormatter('new_grade_status'),
|
||||
active: true,
|
||||
cssClass: 'new-grade',
|
||||
}
|
||||
|
||||
const conflictingOverrideScoreColumn = {
|
||||
id: `override_status_${id}_conflicting`,
|
||||
width: 125,
|
||||
formatter: GradebookUploader.createGeneralFormatter('current_grade_status'),
|
||||
field: `override_status_${id}_conflicting`,
|
||||
name: htmlEscape(I18n.t('From')),
|
||||
cssClass: 'conflicting-grade',
|
||||
}
|
||||
gridData.columns.push(conflictingOverrideScoreColumn, newOverrideStatusColumn)
|
||||
|
||||
const overrideScoreHeaderColumn = {
|
||||
id: `override_status_${id}`,
|
||||
width: 250,
|
||||
name: htmlEscape(title),
|
||||
headerCssClass: 'assignment',
|
||||
}
|
||||
labelData.columns.push(overrideScoreHeaderColumn)
|
||||
},
|
||||
}
|
||||
|
||||
export default GradebookUploader
|
||||
|
|
Loading…
Reference in New Issue