Show first and last names columns in gradebook
Last name column has all the same fields as the original student column. The first name column only shows the first name. closes EVAL-1990 flag=gradebook_show_first_last_names Test plan: With the FF on and the account admin setting to show separate columns enabled, as a teacher go to gradebook: 1. Select the "Split Student Names" view option - See that the gradebook grid shows separate columns for student last and first names - Make sure all the column options in the last name column work "Sort by", "Secondary Info" and "Show - Inactive/Concluded enrollments" and the option to "Display as" is not there - See that there are no column options for first name - See that the assignment and student search work as before 2. Unselect the "Split Student Names" view option - See that the grid shows the Student column as before Change-Id: Ic3ffefcd2069eca84823d60bb993d98521c8861d Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/276013 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> Reviewed-by: Adrian Packel <apackel@instructure.com> QA-Review: Dustin Cowles <dustin.cowles@instructure.com> Product-Review: Syed Hussain <shussain@instructure.com>
This commit is contained in:
parent
ae7a2ad851
commit
873f88e270
|
@ -21,7 +21,62 @@ import {
|
|||
createGradebook,
|
||||
setFixtureHtml
|
||||
} from 'ui/features/gradebook/react/default_gradebook/__tests__/GradebookSpecHelper.js'
|
||||
import StudentColumnHeader from 'ui/features/gradebook/react/default_gradebook/GradebookGrid/headers/StudentColumnHeader'
|
||||
import StudentColumnHeaderRenderer from 'ui/features/gradebook/react/default_gradebook/GradebookGrid/headers/StudentColumnHeaderRenderer.js'
|
||||
import StudentLastNameColumnHeader from 'ui/features/gradebook/react/default_gradebook/GradebookGrid/headers/StudentLastNameColumnHeader'
|
||||
|
||||
QUnit.module('GradebookGrid StudentLastNameColumnHeaderRenderer', suiteHooks => {
|
||||
let $container
|
||||
let gradebook
|
||||
let renderer
|
||||
let component
|
||||
|
||||
function render() {
|
||||
renderer.render(
|
||||
{} /* column */,
|
||||
$container,
|
||||
{} /* gridSupport */,
|
||||
{
|
||||
ref(ref) {
|
||||
component = ref
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
suiteHooks.beforeEach(() => {
|
||||
$container = document.createElement('div')
|
||||
document.body.appendChild($container)
|
||||
setFixtureHtml($container)
|
||||
|
||||
gradebook = createGradebook({
|
||||
login_handle_name: 'a_jones',
|
||||
sis_name: 'Example SIS'
|
||||
})
|
||||
sinon.stub(gradebook, 'saveSettings')
|
||||
renderer = new StudentColumnHeaderRenderer(gradebook, StudentLastNameColumnHeader, 'student_lastname')
|
||||
})
|
||||
|
||||
suiteHooks.afterEach(() => {
|
||||
$container.remove()
|
||||
})
|
||||
|
||||
QUnit.module('#render()', () => {
|
||||
test('renders the StudentLastNameColumnHeader to the given container node', () => {
|
||||
render()
|
||||
ok($container.innerText.includes('Student Last Name'), 'the "Student Last Name" header is rendered')
|
||||
})
|
||||
})
|
||||
|
||||
QUnit.module('#destroy()', () => {
|
||||
test('unmounts the component', () => {
|
||||
render()
|
||||
renderer.destroy({}, $container)
|
||||
const removed = ReactDOM.unmountComponentAtNode($container)
|
||||
strictEqual(removed, false, 'the component was already unmounted')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/* eslint-disable qunit/no-identical-names */
|
||||
QUnit.module('GradebookGrid StudentColumnHeaderRenderer', suiteHooks => {
|
||||
|
@ -53,7 +108,7 @@ QUnit.module('GradebookGrid StudentColumnHeaderRenderer', suiteHooks => {
|
|||
sis_name: 'Example SIS'
|
||||
})
|
||||
sinon.stub(gradebook, 'saveSettings')
|
||||
renderer = new StudentColumnHeaderRenderer(gradebook)
|
||||
renderer = new StudentColumnHeaderRenderer(gradebook, StudentColumnHeader, 'student')
|
||||
})
|
||||
|
||||
suiteHooks.afterEach(() => {
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import ReactDOM from 'react-dom'
|
||||
import {
|
||||
createGradebook,
|
||||
setFixtureHtml
|
||||
} from 'ui/features/gradebook/react/default_gradebook/__tests__/GradebookSpecHelper'
|
||||
import StudentFirstNameColumnHeader from 'ui/features/gradebook/react/default_gradebook/GradebookGrid/headers/StudentFirstNameColumnHeader'
|
||||
import StudentFirstNameColumnHeaderRenderer from 'ui/features/gradebook/react/default_gradebook/GradebookGrid/headers/StudentFirstNameColumnHeaderRenderer'
|
||||
|
||||
/* eslint-disable qunit/no-identical-names */
|
||||
QUnit.module('GradebookGrid StudentFirstNameColumnHeaderRenderer', suiteHooks => {
|
||||
let $container
|
||||
let gradebook
|
||||
let renderer
|
||||
let component
|
||||
|
||||
function render() {
|
||||
renderer.render(
|
||||
{} /* column */,
|
||||
$container,
|
||||
{} /* gridSupport */,
|
||||
{
|
||||
ref(ref) {
|
||||
component = ref
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
suiteHooks.beforeEach(() => {
|
||||
$container = document.createElement('div')
|
||||
document.body.appendChild($container)
|
||||
setFixtureHtml($container)
|
||||
|
||||
gradebook = createGradebook({
|
||||
login_handle_name: 'a_jones',
|
||||
sis_name: 'Example SIS'
|
||||
})
|
||||
sinon.stub(gradebook, 'saveSettings')
|
||||
renderer = new StudentFirstNameColumnHeaderRenderer(gradebook)
|
||||
})
|
||||
|
||||
suiteHooks.afterEach(() => {
|
||||
$container.remove()
|
||||
})
|
||||
|
||||
QUnit.module('#render()', () => {
|
||||
test('renders the StudentFirstNameColumnHeader to the given container node', () => {
|
||||
render()
|
||||
ok($container.innerText.includes('Student First Name'), 'the "Student First Name" header is rendered')
|
||||
})
|
||||
|
||||
test('calls the "ref" callback option with the component reference', () => {
|
||||
render()
|
||||
equal(component.constructor.name, 'StudentFirstNameColumnHeader')
|
||||
})
|
||||
|
||||
test('includes a callback for adding elements to the Gradebook KeyboardNav', () => {
|
||||
sinon.stub(gradebook.keyboardNav, 'addGradebookElement')
|
||||
render()
|
||||
component.props.addGradebookElement()
|
||||
strictEqual(gradebook.keyboardNav.addGradebookElement.callCount, 1)
|
||||
})
|
||||
|
||||
test('sets the component as disabled when students are not loaded', () => {
|
||||
gradebook.setStudentsLoaded(false)
|
||||
render()
|
||||
strictEqual(component.props.disabled, true)
|
||||
})
|
||||
|
||||
test('sets the component as not disabled when students are loaded', () => {
|
||||
gradebook.setStudentsLoaded(true)
|
||||
render()
|
||||
strictEqual(component.props.disabled, false)
|
||||
})
|
||||
|
||||
test('includes a callback for keyDown events', () => {
|
||||
sinon.stub(gradebook, 'handleHeaderKeyDown')
|
||||
render()
|
||||
component.props.onHeaderKeyDown({})
|
||||
strictEqual(gradebook.handleHeaderKeyDown.callCount, 1)
|
||||
})
|
||||
|
||||
test('calls Gradebook#handleHeaderKeyDown with a given event', () => {
|
||||
const exampleEvent = new Event('example')
|
||||
sinon.stub(gradebook, 'handleHeaderKeyDown')
|
||||
render()
|
||||
component.props.onHeaderKeyDown(exampleEvent)
|
||||
const event = gradebook.handleHeaderKeyDown.lastCall.args[0]
|
||||
equal(event, exampleEvent)
|
||||
})
|
||||
|
||||
test('calls Gradebook#handleHeaderKeyDown with a given event', () => {
|
||||
sinon.stub(gradebook, 'handleHeaderKeyDown')
|
||||
render()
|
||||
component.props.onHeaderKeyDown({})
|
||||
const columnId = gradebook.handleHeaderKeyDown.lastCall.args[1]
|
||||
equal(columnId, 'student_firstname')
|
||||
})
|
||||
|
||||
test('includes a callback for removing elements to the Gradebook KeyboardNav', () => {
|
||||
sinon.stub(gradebook.keyboardNav, 'removeGradebookElement')
|
||||
render()
|
||||
component.props.removeGradebookElement()
|
||||
strictEqual(gradebook.keyboardNav.removeGradebookElement.callCount, 1)
|
||||
})
|
||||
})
|
||||
|
||||
QUnit.module('#destroy()', () => {
|
||||
test('unmounts the component', () => {
|
||||
render()
|
||||
renderer.destroy({}, $container)
|
||||
const removed = ReactDOM.unmountComponentAtNode($container)
|
||||
strictEqual(removed, false, 'the component was already unmounted')
|
||||
})
|
||||
})
|
||||
})
|
||||
/* eslint-enable qunit/no-identical-names */
|
|
@ -321,6 +321,7 @@ class Gradebook extends React.Component {
|
|||
this.removeHeaderComponentRef = this.removeHeaderComponentRef.bind(this)
|
||||
// # React Grid Component Rendering Methods
|
||||
this.updateColumnHeaders = this.updateColumnHeaders.bind(this)
|
||||
this.updateStudentColumnHeaders = this.updateStudentColumnHeaders.bind(this)
|
||||
// Column Header Helpers
|
||||
this.handleHeaderKeyDown = this.handleHeaderKeyDown.bind(this)
|
||||
// Total Grade Column Header
|
||||
|
@ -2233,9 +2234,14 @@ class Gradebook extends React.Component {
|
|||
|
||||
setVisibleGridColumns() {
|
||||
let assignmentGroupId, ref1
|
||||
const parentColumnIds = this.gridData.columns.frozen.filter(function (columnId) {
|
||||
return !/^custom_col_/.test(columnId)
|
||||
let parentColumnIds = this.gridData.columns.frozen.filter(function (columnId) {
|
||||
return !/^custom_col_/.test(columnId) && !/^student/.test(columnId)
|
||||
})
|
||||
if (this.gridDisplaySettings.showSeparateFirstLastNames) {
|
||||
parentColumnIds = ['student_lastname', 'student_firstname'].concat(parentColumnIds)
|
||||
} else {
|
||||
parentColumnIds = ['student'].concat(parentColumnIds)
|
||||
}
|
||||
const customColumnIds = this.listVisibleCustomColumns().map(column => {
|
||||
return getCustomColumnId(column.id)
|
||||
})
|
||||
|
@ -2276,18 +2282,14 @@ class Gradebook extends React.Component {
|
|||
|
||||
// # Grid Column Definitions
|
||||
|
||||
// Student Column
|
||||
buildStudentColumn() {
|
||||
let studentColumnWidth
|
||||
studentColumnWidth = 150
|
||||
if (this.gradebookColumnSizeSettings) {
|
||||
if (this.gradebookColumnSizeSettings.student) {
|
||||
studentColumnWidth = parseInt(this.gradebookColumnSizeSettings.student, 10)
|
||||
}
|
||||
}
|
||||
// Student Columns
|
||||
buildStudentColumn(columnId, gradebookColumnSizeSetting, defaultWidth) {
|
||||
const studentColumnWidth = gradebookColumnSizeSetting
|
||||
? parseInt(gradebookColumnSizeSetting, 10)
|
||||
: defaultWidth
|
||||
return {
|
||||
id: 'student',
|
||||
type: 'student',
|
||||
id: columnId,
|
||||
type: columnId,
|
||||
width: studentColumnWidth,
|
||||
cssClass: 'meta-cell primary-column student',
|
||||
headerCssClass: 'primary-column student',
|
||||
|
@ -2429,9 +2431,28 @@ class Gradebook extends React.Component {
|
|||
initGrid() {
|
||||
let assignmentGroup, assignmentGroupColumn, id
|
||||
this.updateFilteredContentInfo()
|
||||
const studentColumn = this.buildStudentColumn()
|
||||
const studentColumn = this.buildStudentColumn(
|
||||
'student',
|
||||
this.gradebookColumnSizeSettings?.student,
|
||||
150
|
||||
)
|
||||
this.gridData.columns.definitions[studentColumn.id] = studentColumn
|
||||
this.gridData.columns.frozen.push(studentColumn.id)
|
||||
const studentColumnLastName = this.buildStudentColumn(
|
||||
'student_lastname',
|
||||
this.gradebookColumnSizeSettings?.student_lastname,
|
||||
155
|
||||
)
|
||||
this.gridData.columns.definitions[studentColumnLastName.id] = studentColumnLastName
|
||||
this.gridData.columns.frozen.push(studentColumnLastName.id)
|
||||
const studentColumnFirstName = this.buildStudentColumn(
|
||||
'student_firstname',
|
||||
this.gradebookColumnSizeSettings?.student_firstname,
|
||||
155
|
||||
)
|
||||
this.gridData.columns.definitions[studentColumnFirstName.id] = studentColumnFirstName
|
||||
this.gridData.columns.frozen.push(studentColumnFirstName.id)
|
||||
|
||||
const ref2 = this.assignmentGroups
|
||||
for (id in ref2) {
|
||||
assignmentGroup = ref2[id]
|
||||
|
@ -2471,7 +2492,10 @@ class Gradebook extends React.Component {
|
|||
})
|
||||
this.gradebookGrid.gridSupport.initialize()
|
||||
this.gradebookGrid.gridSupport.events.onActiveLocationChanged.subscribe((event, location) => {
|
||||
if (location.columnId === 'student' && location.region === 'body') {
|
||||
if (
|
||||
['student', 'student_lastname'].includes(location.columnId) &&
|
||||
location.region === 'body'
|
||||
) {
|
||||
// In IE11, if we're navigating into the student column from a grade
|
||||
// input cell with no text, this focus() call will select the <body>
|
||||
// instead of the grades link. Delaying the call (even with no actual
|
||||
|
@ -3054,6 +3078,13 @@ class Gradebook extends React.Component {
|
|||
: undefined
|
||||
}
|
||||
|
||||
updateStudentColumnHeaders() {
|
||||
const columnIds = this.gridDisplaySettings.showSeparateFirstLastNames
|
||||
? ['student_lastname', 'student_firstname']
|
||||
: ['student']
|
||||
return this.updateColumnHeaders(columnIds)
|
||||
}
|
||||
|
||||
handleHeaderKeyDown(e, columnId) {
|
||||
return this.gradebookGrid.gridSupport.navigation.handleHeaderKeyDown(e, {
|
||||
region: 'header',
|
||||
|
@ -3730,7 +3761,7 @@ class Gradebook extends React.Component {
|
|||
this.saveSettings()
|
||||
if (!skipRedraw) {
|
||||
this.buildRows()
|
||||
return this.gradebookGrid.gridSupport.columns.updateColumnHeaders(['student'])
|
||||
return this.updateStudentColumnHeaders()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3759,7 +3790,7 @@ class Gradebook extends React.Component {
|
|||
this.saveSettings()
|
||||
if (!skipRedraw) {
|
||||
this.buildRows()
|
||||
return this.gradebookGrid.gridSupport.columns.updateColumnHeaders(['student'])
|
||||
return this.updateStudentColumnHeaders()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3824,7 +3855,7 @@ class Gradebook extends React.Component {
|
|||
}
|
||||
|
||||
updateStudentHeadersAndReloadData() {
|
||||
this.gradebookGrid.gridSupport.columns.updateColumnHeaders(['student'])
|
||||
this.updateStudentColumnHeaders()
|
||||
return this.dataLoader.reloadStudentDataForEnrollmentFilterChange()
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ import AssignmentCellFormatter from './AssignmentCellFormatter'
|
|||
import AssignmentGroupCellFormatter from './AssignmentGroupCellFormatter'
|
||||
import CustomColumnCellFormatter from './CustomColumnCellFormatter'
|
||||
import StudentCellFormatter from './StudentCellFormatter'
|
||||
import StudentLastNameCellFormatter from './StudentLastNameCellFormatter'
|
||||
import StudentFirstNameCellFormatter from './StudentFirstNameCellFormatter'
|
||||
import TotalGradeCellFormatter from './TotalGradeCellFormatter'
|
||||
import TotalGradeOverrideCellFormatter from './TotalGradeOverrideCellFormatter'
|
||||
|
||||
|
@ -30,6 +32,8 @@ class CellFormatterFactory {
|
|||
assignment_group: new AssignmentGroupCellFormatter(),
|
||||
custom_column: new CustomColumnCellFormatter(),
|
||||
student: new StudentCellFormatter(gradebook),
|
||||
student_lastname: new StudentLastNameCellFormatter(gradebook),
|
||||
student_firstname: new StudentFirstNameCellFormatter(gradebook),
|
||||
total_grade: new TotalGradeCellFormatter(gradebook),
|
||||
total_grade_override: new TotalGradeOverrideCellFormatter(gradebook)
|
||||
}
|
||||
|
|
|
@ -19,95 +19,15 @@
|
|||
import $ from 'jquery'
|
||||
import I18n from 'i18n!gradebook'
|
||||
import '@canvas/jquery/jquery.instructure_misc_helpers' // $.toSentence
|
||||
import htmlEscape from 'html-escape'
|
||||
|
||||
function getSecondaryDisplayInfo(student, secondaryInfo, options) {
|
||||
if (options.shouldShowSections() && secondaryInfo === 'section') {
|
||||
const sectionNames = student.sections
|
||||
.filter(options.isVisibleSection)
|
||||
.map(sectionId => options.getSection(sectionId).name)
|
||||
return $.toSentence(sectionNames.sort())
|
||||
}
|
||||
|
||||
if (options.shouldShowGroups() && secondaryInfo === 'group') {
|
||||
const groupNames = student.group_ids.map(groupId => options.getGroup(groupId).name)
|
||||
return $.toSentence(groupNames.sort())
|
||||
}
|
||||
|
||||
return {
|
||||
login_id: student.login_id,
|
||||
sis_id: student.sis_user_id,
|
||||
integration_id: student.integration_id
|
||||
}[secondaryInfo]
|
||||
}
|
||||
|
||||
function getEnrollmentLabel(student) {
|
||||
if (student.isConcluded) {
|
||||
return I18n.t('concluded')
|
||||
}
|
||||
if (student.isInactive) {
|
||||
return I18n.t('inactive')
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
// xsslint safeString.property enrollmentLabel secondaryInfo studentId courseId url displayName
|
||||
function render(options) {
|
||||
let enrollmentStatus = ''
|
||||
let secondaryInfo = ''
|
||||
|
||||
if (options.enrollmentLabel) {
|
||||
const title = I18n.t('This user is currently not able to access the course')
|
||||
// xsslint safeString.identifier title
|
||||
enrollmentStatus = ` <span title="${title}" class="label">${options.enrollmentLabel}</span>`
|
||||
}
|
||||
|
||||
if (options.secondaryInfo) {
|
||||
secondaryInfo = `<div class="secondary-info">${options.secondaryInfo}</div>`
|
||||
}
|
||||
|
||||
// xsslint safeString.identifier enrollmentStatus secondaryInfo
|
||||
return `
|
||||
<div class="student-name">
|
||||
<a
|
||||
class="student-grades-link student_context_card_trigger"
|
||||
data-student_id="${options.studentId}"
|
||||
data-course_id="${options.courseId}"
|
||||
href="${options.url}"
|
||||
>${htmlEscape(options.displayName)}</a>
|
||||
${enrollmentStatus}
|
||||
</div>
|
||||
${secondaryInfo}
|
||||
`
|
||||
}
|
||||
import {
|
||||
getSecondaryDisplayInfo,
|
||||
getEnrollmentLabel,
|
||||
getOptions,
|
||||
renderCell} from './StudentCellFormatter.utils'
|
||||
|
||||
export default class StudentCellFormatter {
|
||||
constructor(gradebook) {
|
||||
this.options = {
|
||||
courseId: gradebook.options.context_id,
|
||||
getSection(sectionId) {
|
||||
return gradebook.sections[sectionId]
|
||||
},
|
||||
getGroup(groupId) {
|
||||
return gradebook.studentGroups[groupId]
|
||||
},
|
||||
getSelectedPrimaryInfo() {
|
||||
return gradebook.getSelectedPrimaryInfo()
|
||||
},
|
||||
getSelectedSecondaryInfo() {
|
||||
return gradebook.getSelectedSecondaryInfo()
|
||||
},
|
||||
isVisibleSection(sectionId) {
|
||||
return gradebook.sections[sectionId] != null
|
||||
},
|
||||
shouldShowSections() {
|
||||
return gradebook.showSections()
|
||||
},
|
||||
shouldShowGroups() {
|
||||
return gradebook.showStudentGroups()
|
||||
}
|
||||
}
|
||||
this.options = getOptions(gradebook)
|
||||
}
|
||||
|
||||
render = (_row, _cell, _value, _columnDef, student /* dataContext */) => {
|
||||
|
@ -127,6 +47,6 @@ export default class StudentCellFormatter {
|
|||
url: `${student.enrollments[0].grades.html_url}#tab-assignments`
|
||||
}
|
||||
|
||||
return render(options)
|
||||
return renderCell(options)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import $ from 'jquery'
|
||||
import htmlEscape from 'html-escape'
|
||||
import I18n from 'i18n!gradebook'
|
||||
|
||||
export function getSecondaryDisplayInfo(student, secondaryInfo, options) {
|
||||
if (options.shouldShowSections() && secondaryInfo === 'section') {
|
||||
const sectionNames = student.sections
|
||||
.filter(options.isVisibleSection)
|
||||
.map(sectionId => options.getSection(sectionId).name)
|
||||
return $.toSentence(sectionNames.sort())
|
||||
}
|
||||
|
||||
if (options.shouldShowGroups() && secondaryInfo === 'group') {
|
||||
const groupNames = student.group_ids.map(groupId => options.getGroup(groupId).name)
|
||||
return $.toSentence(groupNames.sort())
|
||||
}
|
||||
|
||||
return {
|
||||
login_id: student.login_id,
|
||||
sis_id: student.sis_user_id,
|
||||
integration_id: student.integration_id
|
||||
}[secondaryInfo]
|
||||
}
|
||||
|
||||
export function getEnrollmentLabel(student) {
|
||||
if (student.isConcluded) {
|
||||
return I18n.t('concluded')
|
||||
}
|
||||
if (student.isInactive) {
|
||||
return I18n.t('inactive')
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export function getOptions(gradebook) {
|
||||
return {
|
||||
courseId: gradebook.options.context_id,
|
||||
getSection(sectionId) {
|
||||
return gradebook.sections[sectionId]
|
||||
},
|
||||
getGroup(groupId) {
|
||||
return gradebook.studentGroups[groupId]
|
||||
},
|
||||
getSelectedPrimaryInfo() {
|
||||
return gradebook.getSelectedPrimaryInfo()
|
||||
},
|
||||
getSelectedSecondaryInfo() {
|
||||
return gradebook.getSelectedSecondaryInfo()
|
||||
},
|
||||
isVisibleSection(sectionId) {
|
||||
return gradebook.sections[sectionId] != null
|
||||
},
|
||||
shouldShowSections() {
|
||||
return gradebook.showSections()
|
||||
},
|
||||
shouldShowGroups() {
|
||||
return gradebook.showStudentGroups()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// xsslint safeString.property enrollmentLabel secondaryInfo studentId courseId url displayName
|
||||
export function renderCell(options) {
|
||||
let enrollmentStatus = ''
|
||||
let secondaryInfo = ''
|
||||
|
||||
if (options.enrollmentLabel) {
|
||||
const title = I18n.t('This user is currently not able to access the course')
|
||||
// xsslint safeString.identifier title
|
||||
enrollmentStatus = ` <span title="${title}" class="label">${options.enrollmentLabel}</span>`
|
||||
}
|
||||
|
||||
if (options.secondaryInfo) {
|
||||
secondaryInfo = `<div class="secondary-info">${options.secondaryInfo}</div>`
|
||||
}
|
||||
|
||||
// xsslint safeString.identifier enrollmentStatus secondaryInfo
|
||||
return `
|
||||
<div class="student-name">
|
||||
<a
|
||||
class="student-grades-link student_context_card_trigger"
|
||||
data-student_id="${options.studentId}"
|
||||
data-course_id="${options.courseId}"
|
||||
href="${options.url}"
|
||||
>${htmlEscape(options.displayName)}</a>
|
||||
${enrollmentStatus}
|
||||
</div>
|
||||
${secondaryInfo}
|
||||
`
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import I18n from 'i18n!gradebook'
|
||||
import '@canvas/jquery/jquery.instructure_misc_helpers' // $.toSentence
|
||||
import htmlEscape from 'html-escape'
|
||||
import {getEnrollmentLabel, renderCell} from './StudentCellFormatter.utils'
|
||||
|
||||
export default class StudentFirstNameCellFormatter {
|
||||
constructor(gradebook) {
|
||||
this.options = {
|
||||
courseId: gradebook.options.context_id
|
||||
}
|
||||
}
|
||||
|
||||
render = (_row, _cell, _value, _columnDef, student /* dataContext */) => {
|
||||
if (student.isPlaceholder) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const options = {
|
||||
courseId: this.options.courseId,
|
||||
displayName: student.first_name,
|
||||
enrollmentLabel: getEnrollmentLabel(student),
|
||||
studentId: student.id,
|
||||
url: `${student.enrollments[0].grades.html_url}#tab-assignments`
|
||||
}
|
||||
|
||||
return renderCell(options)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import $ from 'jquery'
|
||||
import I18n from 'i18n!gradebook'
|
||||
import '@canvas/jquery/jquery.instructure_misc_helpers' // $.toSentence
|
||||
import {
|
||||
getSecondaryDisplayInfo,
|
||||
getEnrollmentLabel,
|
||||
getOptions,
|
||||
renderCell} from './StudentCellFormatter.utils'
|
||||
|
||||
export default class StudentLastNameCellFormatter {
|
||||
constructor(gradebook) {
|
||||
this.options = getOptions(gradebook)
|
||||
}
|
||||
|
||||
render = (_row, _cell, _value, _columnDef, student /* dataContext */) => {
|
||||
if (student.isPlaceholder) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const secondaryInfo = this.options.getSelectedSecondaryInfo()
|
||||
|
||||
const options = {
|
||||
courseId: this.options.courseId,
|
||||
displayName: student.last_name,
|
||||
enrollmentLabel: getEnrollmentLabel(student),
|
||||
secondaryInfo: getSecondaryDisplayInfo(student, secondaryInfo, this.options),
|
||||
studentId: student.id,
|
||||
url: `${student.enrollments[0].grades.html_url}#tab-assignments`
|
||||
}
|
||||
|
||||
return renderCell(options)
|
||||
}
|
||||
}
|
|
@ -19,7 +19,10 @@
|
|||
import AssignmentColumnHeaderRenderer from './AssignmentColumnHeaderRenderer'
|
||||
import AssignmentGroupColumnHeaderRenderer from './AssignmentGroupColumnHeaderRenderer'
|
||||
import CustomColumnHeaderRenderer from './CustomColumnHeaderRenderer'
|
||||
import StudentColumnHeader from './StudentColumnHeader'
|
||||
import StudentColumnHeaderRenderer from './StudentColumnHeaderRenderer'
|
||||
import StudentLastNameColumnHeader from './StudentLastNameColumnHeader'
|
||||
import StudentFirstNameColumnHeaderRenderer from './StudentFirstNameColumnHeaderRenderer'
|
||||
import TotalGradeColumnHeaderRenderer from './TotalGradeColumnHeaderRenderer'
|
||||
import TotalGradeOverrideColumnHeaderRenderer from './TotalGradeOverrideColumnHeaderRenderer'
|
||||
|
||||
|
@ -30,7 +33,13 @@ export default class ColumnHeaderRenderer {
|
|||
assignment: new AssignmentColumnHeaderRenderer(gradebook),
|
||||
assignment_group: new AssignmentGroupColumnHeaderRenderer(gradebook),
|
||||
custom_column: new CustomColumnHeaderRenderer(gradebook),
|
||||
student: new StudentColumnHeaderRenderer(gradebook),
|
||||
student: new StudentColumnHeaderRenderer(gradebook, StudentColumnHeader, 'student'),
|
||||
student_lastname: new StudentColumnHeaderRenderer(
|
||||
gradebook,
|
||||
StudentLastNameColumnHeader,
|
||||
'student_lastname'
|
||||
),
|
||||
student_firstname: new StudentFirstNameColumnHeaderRenderer(gradebook),
|
||||
total_grade: new TotalGradeColumnHeaderRenderer(gradebook),
|
||||
total_grade_override: new TotalGradeOverrideColumnHeaderRenderer(gradebook)
|
||||
}
|
||||
|
|
|
@ -70,6 +70,18 @@ export default class StudentColumnHeader extends ColumnHeader {
|
|||
...ColumnHeader.defaultProps
|
||||
}
|
||||
|
||||
getColumnHeaderName() {
|
||||
return I18n.t('Student Name')
|
||||
}
|
||||
|
||||
getColumnHeaderOptions() {
|
||||
return I18n.t('Student Name Options')
|
||||
}
|
||||
|
||||
showDisplayAsViewOption() {
|
||||
return true
|
||||
}
|
||||
|
||||
onShowSectionNames = () => {
|
||||
this.onSelectSecondaryInfo('section')
|
||||
}
|
||||
|
@ -228,7 +240,7 @@ export default class StudentColumnHeader extends ColumnHeader {
|
|||
padding="0 0 0 small"
|
||||
>
|
||||
<Text fontStyle="normal" size="x-small" weight="bold">
|
||||
{I18n.t('Student Name')}
|
||||
{this.getColumnHeaderName()}
|
||||
</Text>
|
||||
</View>
|
||||
</Grid.Col>
|
||||
|
@ -246,7 +258,7 @@ export default class StudentColumnHeader extends ColumnHeader {
|
|||
variant="icon"
|
||||
icon={IconMoreSolid}
|
||||
>
|
||||
<ScreenReaderContent>{I18n.t('Student Name Options')}</ScreenReaderContent>
|
||||
<ScreenReaderContent>{this.getColumnHeaderOptions()}</ScreenReaderContent>
|
||||
</Button>
|
||||
}
|
||||
onToggle={this.onToggle}
|
||||
|
@ -254,6 +266,7 @@ export default class StudentColumnHeader extends ColumnHeader {
|
|||
>
|
||||
{sortMenu}
|
||||
|
||||
{this.showDisplayAsViewOption() && (
|
||||
<Menu
|
||||
label={I18n.t('Display as')}
|
||||
contentRef={this.bindDisplayAsMenuContent}
|
||||
|
@ -278,6 +291,7 @@ export default class StudentColumnHeader extends ColumnHeader {
|
|||
</Menu.Item>
|
||||
</Menu.Group>
|
||||
</Menu>
|
||||
)}
|
||||
|
||||
<Menu
|
||||
contentRef={this.bindSecondaryInfoMenuContent}
|
||||
|
|
|
@ -18,79 +18,19 @@
|
|||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import StudentColumnHeader from './StudentColumnHeader'
|
||||
|
||||
function getProps(gradebook, options) {
|
||||
const columnId = 'student'
|
||||
const sortRowsBySetting = gradebook.getSortRowsBySetting()
|
||||
const {columnId: currentColumnId, direction, settingKey} = sortRowsBySetting
|
||||
|
||||
const studentSettingKey = currentColumnId === 'student' ? settingKey : 'sortable_name'
|
||||
|
||||
return {
|
||||
ref: options.ref,
|
||||
addGradebookElement: gradebook.keyboardNav.addGradebookElement,
|
||||
disabled: !gradebook.contentLoadStates.studentsLoaded,
|
||||
loginHandleName: gradebook.options.login_handle_name,
|
||||
onHeaderKeyDown: event => {
|
||||
gradebook.handleHeaderKeyDown(event, columnId)
|
||||
},
|
||||
onMenuDismiss() {
|
||||
setTimeout(gradebook.handleColumnHeaderMenuClose)
|
||||
},
|
||||
onSelectPrimaryInfo: gradebook.setSelectedPrimaryInfo,
|
||||
onSelectSecondaryInfo: gradebook.setSelectedSecondaryInfo,
|
||||
onToggleEnrollmentFilter: gradebook.toggleEnrollmentFilter,
|
||||
removeGradebookElement: gradebook.keyboardNav.removeGradebookElement,
|
||||
sectionsEnabled: gradebook.sections_enabled,
|
||||
selectedEnrollmentFilters: gradebook.getSelectedEnrollmentFilters(),
|
||||
selectedPrimaryInfo: gradebook.getSelectedPrimaryInfo(),
|
||||
selectedSecondaryInfo: gradebook.getSelectedSecondaryInfo(),
|
||||
sisName: gradebook.options.sis_name,
|
||||
sortBySetting: {
|
||||
direction,
|
||||
disabled: !gradebook.contentLoadStates.studentsLoaded,
|
||||
isSortColumn: sortRowsBySetting.columnId === columnId,
|
||||
// sort functions with additional sort options enabled
|
||||
onSortBySortableName: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'sortable_name', direction)
|
||||
},
|
||||
onSortBySisId: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'sis_user_id', direction)
|
||||
},
|
||||
onSortByIntegrationId: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'integration_id', direction)
|
||||
},
|
||||
onSortByLoginId: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'login_id', direction)
|
||||
},
|
||||
onSortInAscendingOrder: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, studentSettingKey, 'ascending')
|
||||
},
|
||||
onSortInDescendingOrder: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, studentSettingKey, 'descending')
|
||||
},
|
||||
// sort functions with additional sort options disabled
|
||||
onSortBySortableNameAscending: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'sortable_name', 'ascending')
|
||||
},
|
||||
onSortBySortableNameDescending: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'sortable_name', 'descending')
|
||||
},
|
||||
settingKey
|
||||
},
|
||||
studentGroupsEnabled: gradebook.showStudentGroups()
|
||||
}
|
||||
}
|
||||
import {getProps} from './StudentColumnHeaderRenderer.utils'
|
||||
|
||||
export default class StudentColumnHeaderRenderer {
|
||||
constructor(gradebook) {
|
||||
constructor(gradebook, element, columnName) {
|
||||
this.gradebook = gradebook
|
||||
this.element = element
|
||||
this.columnName = columnName
|
||||
}
|
||||
|
||||
render(_column, $container, _gridSupport, options) {
|
||||
const props = getProps(this.gradebook, options)
|
||||
ReactDOM.render(<StudentColumnHeader {...props} />, $container)
|
||||
const Element = this.element
|
||||
const props = getProps(this.gradebook, options, this.columnName)
|
||||
ReactDOM.render(<Element {...props} />, $container)
|
||||
}
|
||||
|
||||
destroy(_column, $container, _gridSupport) {
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export function getProps(gradebook, options, columnHeaderName) {
|
||||
const columnId = columnHeaderName
|
||||
const sortRowsBySetting = gradebook.getSortRowsBySetting()
|
||||
const {columnId: currentColumnId, direction, settingKey} = sortRowsBySetting
|
||||
|
||||
const studentSettingKey = currentColumnId === columnHeaderName ? settingKey : 'sortable_name'
|
||||
|
||||
return {
|
||||
ref: options.ref,
|
||||
addGradebookElement: gradebook.keyboardNav.addGradebookElement,
|
||||
disabled: !gradebook.contentLoadStates.studentsLoaded,
|
||||
loginHandleName: gradebook.options.login_handle_name,
|
||||
onHeaderKeyDown: event => {
|
||||
gradebook.handleHeaderKeyDown(event, columnId)
|
||||
},
|
||||
onMenuDismiss() {
|
||||
setTimeout(gradebook.handleColumnHeaderMenuClose)
|
||||
},
|
||||
onSelectPrimaryInfo: gradebook.setSelectedPrimaryInfo,
|
||||
onSelectSecondaryInfo: gradebook.setSelectedSecondaryInfo,
|
||||
onToggleEnrollmentFilter: gradebook.toggleEnrollmentFilter,
|
||||
removeGradebookElement: gradebook.keyboardNav.removeGradebookElement,
|
||||
sectionsEnabled: gradebook.sections_enabled,
|
||||
selectedEnrollmentFilters: gradebook.getSelectedEnrollmentFilters(),
|
||||
selectedPrimaryInfo: gradebook.getSelectedPrimaryInfo(),
|
||||
selectedSecondaryInfo: gradebook.getSelectedSecondaryInfo(),
|
||||
sisName: gradebook.options.sis_name,
|
||||
sortBySetting: {
|
||||
direction,
|
||||
disabled: !gradebook.contentLoadStates.studentsLoaded,
|
||||
isSortColumn: sortRowsBySetting.columnId === columnId,
|
||||
// sort functions with additional sort options enabled
|
||||
onSortBySortableName: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'sortable_name', direction)
|
||||
},
|
||||
onSortBySisId: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'sis_user_id', direction)
|
||||
},
|
||||
onSortByIntegrationId: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'integration_id', direction)
|
||||
},
|
||||
onSortByLoginId: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'login_id', direction)
|
||||
},
|
||||
onSortInAscendingOrder: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, studentSettingKey, 'ascending')
|
||||
},
|
||||
onSortInDescendingOrder: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, studentSettingKey, 'descending')
|
||||
},
|
||||
// sort functions with additional sort options disabled
|
||||
onSortBySortableNameAscending: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'sortable_name', 'ascending')
|
||||
},
|
||||
onSortBySortableNameDescending: () => {
|
||||
gradebook.setSortRowsBySetting(columnId, 'sortable_name', 'descending')
|
||||
},
|
||||
settingKey
|
||||
},
|
||||
studentGroupsEnabled: gradebook.showStudentGroups()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {Grid} from '@instructure/ui-grid'
|
||||
import {View} from '@instructure/ui-view'
|
||||
|
||||
import {Text} from '@instructure/ui-text'
|
||||
import I18n from 'i18n!gradebook'
|
||||
import ColumnHeader from './ColumnHeader'
|
||||
|
||||
export default class StudentFirstNameColumnHeader extends ColumnHeader {
|
||||
static propTypes = {
|
||||
...ColumnHeader.propTypes
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
...ColumnHeader.defaultProps
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
className={`Gradebook__ColumnHeaderContent ${this.state.hasFocus ? 'focused' : ''}`}
|
||||
onBlur={this.handleBlur}
|
||||
onFocus={this.handleFocus}
|
||||
>
|
||||
<div style={{flex: 1, minWidth: '1px'}}>
|
||||
<Grid colSpacing="none" hAlign="space-between" vAlign="middle">
|
||||
<Grid.Row>
|
||||
<Grid.Col textAlign="start">
|
||||
<View
|
||||
className="Gradebook__ColumnHeaderDetail Gradebook__ColumnHeaderDetail--OneLine"
|
||||
padding="0 0 0 small"
|
||||
>
|
||||
<Text fontStyle="normal" size="x-small" weight="bold">
|
||||
{I18n.t('Student First Name')}
|
||||
</Text>
|
||||
</View>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import StudentFirstNameColumnHeader from './StudentFirstNameColumnHeader'
|
||||
|
||||
function getProps(gradebook, options) {
|
||||
const columnId = 'student_firstname'
|
||||
|
||||
return {
|
||||
ref: options.ref,
|
||||
addGradebookElement: gradebook.keyboardNav.addGradebookElement,
|
||||
disabled: !gradebook.contentLoadStates.studentsLoaded,
|
||||
removeGradebookElement: gradebook.keyboardNav.removeGradebookElement,
|
||||
onHeaderKeyDown: event => {
|
||||
gradebook.handleHeaderKeyDown(event, columnId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default class StudentFirstNameColumnHeaderRenderer {
|
||||
constructor(gradebook) {
|
||||
this.gradebook = gradebook
|
||||
}
|
||||
|
||||
render(_column, $container, _gridSupport, options) {
|
||||
const props = getProps(this.gradebook, options)
|
||||
ReactDOM.render(<StudentFirstNameColumnHeader {...props} />, $container)
|
||||
}
|
||||
|
||||
destroy(_column, $container, _gridSupport) {
|
||||
ReactDOM.unmountComponentAtNode($container)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import I18n from 'i18n!gradebook'
|
||||
import StudentColumnHeader from './StudentColumnHeader'
|
||||
|
||||
export default class StudentLastNameColumnHeader extends StudentColumnHeader {
|
||||
getColumnHeaderName() {
|
||||
return I18n.t('Student Last Name')
|
||||
}
|
||||
|
||||
getColumnHeaderOptions() {
|
||||
return I18n.t('Student Last Name Options')
|
||||
}
|
||||
|
||||
showDisplayAsViewOption() {
|
||||
return false
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue