Sort gradebook filters alphabetically
This ignore GradingPeriodFilter since these would need to be sorted by start_date. Natcompare was used so this can sort as expected in all locales. Closes: APG-101 Test Plan: - Given New Gradebook is enabled - Given assignment groups, modules, sections, and student groups that were created in non alphabetical order (e.g. 'Section 2' was created before 'Section 1') - Given the Gradebook page - When using any of the filters except for grading periods - Then the contents are in alphabetical order Change-Id: I6b85da1f503eea1074fcff2d1885dc794d96e639 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/213374 Tested-by: Jenkins Reviewed-by: Spencer Olson <solson@instructure.com> Reviewed-by: Gary Mei <gmei@instructure.com> QA-Review: Derek Bender <djbender@instructure.com> Product-Review: Jonathan Fenton <jfenton@instructure.com>
This commit is contained in:
parent
af22a1e9de
commit
6349c6e2cc
|
@ -35,6 +35,7 @@ export default function AssignmentGroupFilter(props) {
|
|||
items={assignmentGroups}
|
||||
label={I18n.t('Assignment Group Filter')}
|
||||
selectedItemId={selectedAssignmentGroupId || ALL_ITEMS_ID}
|
||||
sortAlphabetically
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import {arrayOf, bool, func, shape, string} from 'prop-types'
|
|||
import {ScreenReaderContent} from '@instructure/ui-a11y'
|
||||
import {Select} from '@instructure/ui-select'
|
||||
|
||||
import natcompare from 'compiled/util/natcompare'
|
||||
import I18n from 'i18n!gradezilla_default_gradebook_components_content_filters_content_filter'
|
||||
|
||||
function renderItem(option, {disabled, highlightedItemId, selectedItemId}) {
|
||||
|
@ -85,7 +86,12 @@ export default function ContentFilter(props) {
|
|||
}
|
||||
}
|
||||
|
||||
const options = [{id: allItemsId, name: allItemsLabel}].concat(items)
|
||||
let options = [{id: allItemsId, name: allItemsLabel}]
|
||||
if (props.sortAlphabetically) {
|
||||
options = options.concat(items.sort(natcompare.byKey('name')))
|
||||
} else {
|
||||
options = options.concat(items)
|
||||
}
|
||||
|
||||
return (
|
||||
<Select
|
||||
|
@ -129,9 +135,11 @@ ContentFilter.propTypes = {
|
|||
).isRequired,
|
||||
|
||||
onSelect: func.isRequired,
|
||||
selectedItemId: string
|
||||
selectedItemId: string,
|
||||
sortAlphabetically: bool
|
||||
}
|
||||
|
||||
ContentFilter.defaultProps = {
|
||||
selectedItemId: null
|
||||
selectedItemId: null,
|
||||
sortAlphabetically: false
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ export default function ModuleFilter(props) {
|
|||
items={modules}
|
||||
label={I18n.t('Module Filter')}
|
||||
selectedItemId={selectedModuleId}
|
||||
sortAlphabetically
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ export default function SectionFilter(props) {
|
|||
items={sections}
|
||||
label={I18n.t('Section Filter')}
|
||||
selectedItemId={selectedSectionId}
|
||||
sortAlphabetically
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
import React from 'react'
|
||||
import {arrayOf, shape, string} from 'prop-types'
|
||||
|
||||
import natcompare from 'compiled/util/natcompare'
|
||||
import I18n from 'i18n!gradezilla_default_gradebook_components_content_filters_student_group_filter'
|
||||
|
||||
import ContentFilter from './ContentFilter'
|
||||
|
||||
function normalizeStudentGroupSets(studentGroupSets) {
|
||||
return studentGroupSets.map(category => ({
|
||||
children: [...category.groups].sort((a, b) => a.id - b.id),
|
||||
children: [...category.groups].sort(natcompare.byKey('name')),
|
||||
id: category.id,
|
||||
name: category.name
|
||||
}))
|
||||
|
@ -41,6 +43,7 @@ export default function StudentGroupFilter(props) {
|
|||
items={normalizeStudentGroupSets(studentGroupSets)}
|
||||
label={I18n.t('Student Group Filter')}
|
||||
selectedItemId={selectedStudentGroupId}
|
||||
sortAlphabetically
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5580,8 +5580,8 @@ QUnit.module('Gradebook#updateCurrentAssignmentGroup', {
|
|||
}
|
||||
})
|
||||
this.gradebook.setAssignmentGroups({
|
||||
'1': {id: '1'},
|
||||
'2': {id: '2'}
|
||||
'1': {id: '1', name: 'First'},
|
||||
'2': {id: '2', name: 'Second'}
|
||||
})
|
||||
sinon.spy(this.gradebook, 'setFilterColumnsBySetting')
|
||||
sandbox.spy($, 'ajaxJSON')
|
||||
|
|
|
@ -76,11 +76,11 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
equal($allItemsOption.textContent.trim(), 'All Assignment Groups')
|
||||
})
|
||||
|
||||
test('labels each option using the related assignment group name', () => {
|
||||
test('labels each option using the related assignment group name in alphabetical order', () => {
|
||||
renderComponent()
|
||||
filter.clickToExpand()
|
||||
const labels = filter.$options.slice(1).map($option => $option.textContent.trim())
|
||||
deepEqual(labels, ['In-Class', 'Homework'])
|
||||
deepEqual(labels, ['Homework', 'In-Class'])
|
||||
})
|
||||
|
||||
test('disables non-selected options when the filter is disabled', () => {
|
||||
|
|
|
@ -102,6 +102,19 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
deepEqual(filter.optionLabels.slice(1), ['Item 1', 'Item 2'])
|
||||
})
|
||||
|
||||
QUnit.module('when sortAlphabetically is enabled', hooks => {
|
||||
hooks.beforeEach(() => {
|
||||
props.sortAlphabetically = true
|
||||
props.items = [{id: '2', name: 'Item 2'}, {id: '1', name: 'Item 1'}]
|
||||
})
|
||||
|
||||
test('labels each item option using the related item .name in alphabetical order', () => {
|
||||
renderComponent()
|
||||
filter.clickToExpand()
|
||||
deepEqual(filter.optionLabels.slice(1), ['Item 1', 'Item 2'])
|
||||
})
|
||||
})
|
||||
|
||||
QUnit.module('when using option groups', hooks => {
|
||||
hooks.beforeEach(() => {
|
||||
props.items = [
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
import React from 'react'
|
||||
import {render} from '@testing-library/react'
|
||||
|
||||
import SectionFilter from 'jsx/gradezilla/default_gradebook/components/content-filters/SectionFilter'
|
||||
import ModuleFilter from 'jsx/gradezilla/default_gradebook/components/content-filters/ModuleFilter'
|
||||
import ContentFilterDriver from './ContentFilterDriver'
|
||||
|
||||
QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', () => {
|
||||
QUnit.module('SectionFilter', suiteHooks => {
|
||||
QUnit.module('ModuleFilter', suiteHooks => {
|
||||
let $container
|
||||
let component
|
||||
let filter
|
||||
|
@ -34,9 +34,9 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
|
||||
props = {
|
||||
disabled: false,
|
||||
sections: [{id: '2001', name: 'Section 1'}, {id: '2002', name: 'Section 2'}],
|
||||
modules: [{id: '2002', name: 'Module 2'}, {id: '2001', name: 'Module 1'}],
|
||||
onSelect: sinon.stub(),
|
||||
selectedSectionId: '0'
|
||||
selectedModuleId: '0'
|
||||
}
|
||||
|
||||
component = null
|
||||
|
@ -48,46 +48,46 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
})
|
||||
|
||||
function renderComponent() {
|
||||
component = render(<SectionFilter {...props} />, {container: $container})
|
||||
filter = ContentFilterDriver.findWithLabelText('Section Filter', $container)
|
||||
component = render(<ModuleFilter {...props} />, {container: $container})
|
||||
filter = ContentFilterDriver.findWithLabelText('Module Filter', $container)
|
||||
}
|
||||
|
||||
test('labels the filter with "Section Filter"', () => {
|
||||
test('labels the filter with "Module Filter"', () => {
|
||||
renderComponent()
|
||||
equal(filter.labelText, 'Section Filter')
|
||||
equal(filter.labelText, 'Module Filter')
|
||||
})
|
||||
|
||||
test('displays the name of the selected section as the value', () => {
|
||||
props.selectedSectionId = '2002'
|
||||
test('displays the name of the selected module as the value', () => {
|
||||
props.selectedModuleId = '2002'
|
||||
renderComponent()
|
||||
equal(filter.selectedItemLabel, 'Section 2')
|
||||
equal(filter.selectedItemLabel, 'Module 2')
|
||||
})
|
||||
|
||||
test('displays "All Sections" as the value when selected', () => {
|
||||
test('displays "All Modules" as the value when selected', () => {
|
||||
renderComponent()
|
||||
equal(filter.selectedItemLabel, 'All Sections')
|
||||
equal(filter.selectedItemLabel, 'All Modules')
|
||||
})
|
||||
|
||||
QUnit.module('sections list', () => {
|
||||
test('labels the "all items" option with "All Sections"', () => {
|
||||
QUnit.module('modules list', () => {
|
||||
test('labels the "all items" option with "All Modules"', () => {
|
||||
renderComponent()
|
||||
filter.clickToExpand()
|
||||
const $allItemsOption = filter.$options[0]
|
||||
equal($allItemsOption.textContent.trim(), 'All Sections')
|
||||
equal($allItemsOption.textContent.trim(), 'All Modules')
|
||||
})
|
||||
|
||||
test('labels each option using the related section name', () => {
|
||||
test('labels each option using the related module name in alphabetical order', () => {
|
||||
renderComponent()
|
||||
filter.clickToExpand()
|
||||
const labels = filter.$options.slice(1).map($option => $option.textContent.trim())
|
||||
deepEqual(labels, ['Section 1', 'Section 2'])
|
||||
deepEqual(labels, ['Module 1', 'Module 2'])
|
||||
})
|
||||
|
||||
test('disables non-selected options when the filter is disabled', () => {
|
||||
props.disabled = true
|
||||
renderComponent()
|
||||
filter.clickToExpand()
|
||||
const $option = filter.getOptionWithLabel('Section 2')
|
||||
const $option = filter.getOptionWithLabel('Module 2')
|
||||
strictEqual($option.getAttribute('aria-disabled'), 'true')
|
||||
})
|
||||
})
|
||||
|
@ -96,25 +96,25 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
test('calls the .onSelect callback', () => {
|
||||
renderComponent()
|
||||
filter.clickToExpand()
|
||||
filter.clickToSelectOption('Section 1')
|
||||
filter.clickToSelectOption('Module 1')
|
||||
strictEqual(props.onSelect.callCount, 1)
|
||||
})
|
||||
|
||||
test('includes the section id when calling the .onSelect callback', () => {
|
||||
test('includes the module id when calling the .onSelect callback', () => {
|
||||
renderComponent()
|
||||
filter.clickToExpand()
|
||||
filter.clickToSelectOption('Section 1')
|
||||
const [selectedSectionId] = props.onSelect.lastCall.args
|
||||
strictEqual(selectedSectionId, '2001')
|
||||
filter.clickToSelectOption('Module 1')
|
||||
const [selectedModuleId] = props.onSelect.lastCall.args
|
||||
strictEqual(selectedModuleId, '2001')
|
||||
})
|
||||
|
||||
test('includes "0" when the "All Sections" is clicked', () => {
|
||||
props.selectedSectionId = '2001'
|
||||
test('includes "0" when the "All Modules" is clicked', () => {
|
||||
props.selectedModuleId = '2001'
|
||||
renderComponent()
|
||||
filter.clickToExpand()
|
||||
filter.clickToSelectOption('All Sections')
|
||||
const [selectedSectionId] = props.onSelect.lastCall.args
|
||||
strictEqual(selectedSectionId, '0')
|
||||
filter.clickToSelectOption('All Modules')
|
||||
const [selectedModuleId] = props.onSelect.lastCall.args
|
||||
strictEqual(selectedModuleId, '0')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -34,7 +34,7 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
|
||||
props = {
|
||||
disabled: false,
|
||||
sections: [{id: '2001', name: 'Section 1'}, {id: '2002', name: 'Section 2'}],
|
||||
sections: [{id: '2002', name: 'Section 2'}, {id: '2001', name: 'Section 1'}],
|
||||
onSelect: sinon.stub(),
|
||||
selectedSectionId: '0'
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
equal($allItemsOption.textContent.trim(), 'All Sections')
|
||||
})
|
||||
|
||||
test('labels each option using the related section name', () => {
|
||||
test('labels each option using the related section name in alphabetical order', () => {
|
||||
renderComponent()
|
||||
filter.clickToExpand()
|
||||
const labels = filter.$options.slice(1).map($option => $option.textContent.trim())
|
||||
|
|
|
@ -36,16 +36,15 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
disabled: false,
|
||||
|
||||
studentGroupSets: [
|
||||
{
|
||||
groups: [{id: '2101', name: 'Group A1'}, {id: '2102', name: 'Group A2'}],
|
||||
id: '2151',
|
||||
name: 'Group Set A'
|
||||
},
|
||||
|
||||
{
|
||||
groups: [{id: '2103', name: 'Group B1'}, {id: '2104', name: 'Group B2'}],
|
||||
id: '2152',
|
||||
name: 'Group Set B'
|
||||
},
|
||||
{
|
||||
groups: [{id: '2101', name: 'Group A2'}, {id: '2102', name: 'Group A1'}],
|
||||
id: '2151',
|
||||
name: 'Group Set A'
|
||||
}
|
||||
],
|
||||
|
||||
|
@ -72,7 +71,7 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
})
|
||||
|
||||
test('displays the name of the selected student group as the value', () => {
|
||||
props.selectedStudentGroupId = '2102'
|
||||
props.selectedStudentGroupId = '2101'
|
||||
renderComponent()
|
||||
equal(filter.selectedItemLabel, 'Group A2')
|
||||
})
|
||||
|
@ -83,7 +82,7 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
})
|
||||
|
||||
QUnit.module('student group sets', () => {
|
||||
test('labels each group set option group using the related name', () => {
|
||||
test('labels each group set option group using the related name in alphabetical order', () => {
|
||||
renderComponent()
|
||||
filter.clickToExpand()
|
||||
const labels = filter.optionGroupLabels
|
||||
|
@ -99,7 +98,7 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
equal($allItemsOption.textContent.trim(), 'All Student Groups')
|
||||
})
|
||||
|
||||
test('labels each option using the related student group name', () => {
|
||||
test('labels each option using the related student group name in alphabetical order', () => {
|
||||
renderComponent()
|
||||
filter.clickToExpand()
|
||||
const labels = filter.$options.slice(1).map($option => $option.textContent.trim())
|
||||
|
@ -128,7 +127,7 @@ QUnit.module('Gradebook > Default Gradebook > Components > Content Filters', ()
|
|||
filter.clickToExpand()
|
||||
filter.clickToSelectOption('Group A1')
|
||||
const [selectedStudentGroupId] = props.onSelect.lastCall.args
|
||||
strictEqual(selectedStudentGroupId, '2101')
|
||||
strictEqual(selectedStudentGroupId, '2102')
|
||||
})
|
||||
|
||||
test('includes "0" when the "All Student Groups" is clicked', () => {
|
||||
|
|
Loading…
Reference in New Issue