ViewOptionsMenu.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*
  2. * Copyright (C) 2017 - present Instructure, Inc.
  3. *
  4. * This file is part of Canvas.
  5. *
  6. * Canvas is free software: you can redistribute it and/or modify it under
  7. * the terms of the GNU Affero General Public License as published by the Free
  8. * Software Foundation, version 3 of the License.
  9. *
  10. * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
  11. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. * details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. import React from 'react';
  19. import { arrayOf, bool, func, shape, string } from 'prop-types'
  20. import IconMiniArrowDownSolid from 'instructure-icons/lib/Solid/IconMiniArrowDownSolid'
  21. import Button from 'instructure-ui/lib/components/Button';
  22. import {
  23. MenuItem,
  24. MenuItemGroup,
  25. MenuItemFlyout,
  26. MenuItemSeparator
  27. } from 'instructure-ui/lib/components/Menu';
  28. import PopoverMenu from 'instructure-ui/lib/components/PopoverMenu';
  29. import Typography from 'instructure-ui/lib/components/Typography';
  30. import I18n from 'i18n!gradebook';
  31. import { filterLabels } from 'jsx/gradezilla/default_gradebook/constants/ViewOptions';
  32. import ScreenReaderContent from 'instructure-ui/lib/components/ScreenReaderContent';
  33. function renderTriggerButton (bindButton) {
  34. return (
  35. <Button ref={bindButton} variant="link">
  36. <Typography color="primary">
  37. {I18n.t('View')} <IconMiniArrowDownSolid />
  38. </Typography>
  39. </Button>
  40. );
  41. }
  42. class ViewOptionsMenu extends React.Component {
  43. static propTypes = {
  44. columnSortSettings: shape({
  45. criterion: string.isRequired,
  46. direction: string.isRequired,
  47. disabled: bool.isRequired,
  48. modulesEnabled: bool.isRequired,
  49. onSortByDefault: func.isRequired,
  50. onSortByNameAscending: func.isRequired,
  51. onSortByNameDescending: func.isRequired,
  52. onSortByDueDateAscending: func.isRequired,
  53. onSortByDueDateDescending: func.isRequired,
  54. onSortByPointsAscending: func.isRequired,
  55. onSortByPointsDescending: func.isRequired,
  56. onSortByModuleAscending: func.isRequired,
  57. onSortByModuleDescending: func.isRequired
  58. }).isRequired,
  59. filterSettings: shape({
  60. available: arrayOf(string).isRequired,
  61. onSelect: func.isRequired,
  62. selected: arrayOf(string).isRequired
  63. }),
  64. teacherNotes: shape({
  65. disabled: bool.isRequired,
  66. onSelect: func.isRequired,
  67. selected: bool.isRequired
  68. }).isRequired,
  69. onSelectShowStatusesModal: func.isRequired,
  70. showUnpublishedAssignments: bool.isRequired,
  71. onSelectShowUnpublishedAssignments: func.isRequired
  72. };
  73. onFilterSelect = (_event, filters) => { this.props.filterSettings.onSelect(filters) };
  74. bindMenuContent = (menuContent) => { this.menuContent = menuContent };
  75. bindButton = (button) => { this.button = button };
  76. bindStatusesMenuItem = (menuItem) => { this.statusesMenuItem = menuItem };
  77. bindArrangeByMenuContent = (menuContent) => { this.arrangeByMenuContent = menuContent };
  78. bindFiltersMenuContent = (menuContent) => { this.filtersMenuContent = menuContent };
  79. areColumnsOrderedBy (criterion, direction) {
  80. const sortSettings = this.props.columnSortSettings;
  81. const result = sortSettings.criterion === criterion;
  82. if (direction === undefined) {
  83. return result;
  84. } else {
  85. return result && sortSettings.direction === direction;
  86. }
  87. }
  88. focus () {
  89. this.button.focus();
  90. }
  91. render () {
  92. return (
  93. <PopoverMenu
  94. trigger={renderTriggerButton(this.bindButton)}
  95. contentRef={this.bindMenuContent}
  96. >
  97. <MenuItemFlyout
  98. contentRef={this.bindArrangeByMenuContent}
  99. label={I18n.t('Arrange By')}
  100. >
  101. <MenuItemGroup label={<ScreenReaderContent>{I18n.t('Arrange By')}</ScreenReaderContent>}>
  102. <MenuItem
  103. disabled={this.props.columnSortSettings.disabled}
  104. selected={this.areColumnsOrderedBy('default')}
  105. onSelect={this.props.columnSortSettings.onSortByDefault}
  106. >
  107. { I18n.t('Default Order') }
  108. </MenuItem>
  109. <MenuItem
  110. disabled={this.props.columnSortSettings.disabled}
  111. selected={this.areColumnsOrderedBy('name', 'ascending')}
  112. onSelect={this.props.columnSortSettings.onSortByNameAscending}
  113. >
  114. { I18n.t('Assignment Name - A-Z') }
  115. </MenuItem>
  116. <MenuItem
  117. disabled={this.props.columnSortSettings.disabled}
  118. selected={this.areColumnsOrderedBy('name', 'descending')}
  119. onSelect={this.props.columnSortSettings.onSortByNameDescending}
  120. >
  121. { I18n.t('Assignment Name - Z-A') }
  122. </MenuItem>
  123. <MenuItem
  124. disabled={this.props.columnSortSettings.disabled}
  125. selected={this.areColumnsOrderedBy('due_date', 'ascending')}
  126. onSelect={this.props.columnSortSettings.onSortByDueDateAscending}
  127. >
  128. { I18n.t('Due Date - Oldest to Newest') }
  129. </MenuItem>
  130. <MenuItem
  131. disabled={this.props.columnSortSettings.disabled}
  132. selected={this.areColumnsOrderedBy('due_date', 'descending')}
  133. onSelect={this.props.columnSortSettings.onSortByDueDateDescending}
  134. >
  135. { I18n.t('Due Date - Newest to Oldest') }
  136. </MenuItem>
  137. <MenuItem
  138. disabled={this.props.columnSortSettings.disabled}
  139. selected={this.areColumnsOrderedBy('points', 'ascending')}
  140. onSelect={this.props.columnSortSettings.onSortByPointsAscending}
  141. >
  142. { I18n.t('Points - Lowest to Highest') }
  143. </MenuItem>
  144. <MenuItem
  145. disabled={this.props.columnSortSettings.disabled}
  146. selected={this.areColumnsOrderedBy('points', 'descending')}
  147. onSelect={this.props.columnSortSettings.onSortByPointsDescending}
  148. >
  149. { I18n.t('Points - Highest to Lowest') }
  150. </MenuItem>
  151. {
  152. this.props.columnSortSettings.modulesEnabled &&
  153. <MenuItem
  154. disabled={this.props.columnSortSettings.disabled}
  155. selected={this.areColumnsOrderedBy('module_position', 'ascending')}
  156. onSelect={this.props.columnSortSettings.onSortByModuleAscending}
  157. >
  158. { I18n.t('Module - First to Last') }
  159. </MenuItem>
  160. }
  161. {
  162. this.props.columnSortSettings.modulesEnabled &&
  163. <MenuItem
  164. disabled={this.props.columnSortSettings.disabled}
  165. selected={this.areColumnsOrderedBy('module_position', 'descending')}
  166. onSelect={this.props.columnSortSettings.onSortByModuleDescending}
  167. >
  168. { I18n.t('Module - Last to First') }
  169. </MenuItem>
  170. }
  171. </MenuItemGroup>
  172. </MenuItemFlyout>
  173. <MenuItemSeparator />
  174. {
  175. this.props.filterSettings.available.length > 0 &&
  176. <MenuItemFlyout
  177. contentRef={this.bindFiltersMenuContent}
  178. label={I18n.t('Filters')}
  179. >
  180. <MenuItemGroup
  181. allowMultiple
  182. label={<ScreenReaderContent>{I18n.t('Filters')}</ScreenReaderContent>}
  183. onSelect={this.onFilterSelect}
  184. selected={this.props.filterSettings.selected}
  185. >
  186. {
  187. this.props.filterSettings.available.map(filterKey => (
  188. <MenuItem key={filterKey} value={filterKey}>
  189. { filterLabels[filterKey] }
  190. </MenuItem>
  191. ))
  192. }
  193. </MenuItemGroup>
  194. </MenuItemFlyout>
  195. }
  196. { this.props.filterSettings.available.length > 0 && <MenuItemSeparator /> }
  197. <MenuItem ref={this.bindStausMenuItem} onSelect={this.props.onSelectShowStatusesModal}>
  198. {I18n.t('Statuses…')}
  199. </MenuItem>
  200. <MenuItemSeparator />
  201. <MenuItemGroup allowMultiple label={I18n.t('Columns')}>
  202. <MenuItem
  203. disabled={this.props.teacherNotes.disabled}
  204. onSelect={this.props.teacherNotes.onSelect}
  205. selected={this.props.teacherNotes.selected}
  206. >
  207. <span data-menu-item-id="show-notes-column">{I18n.t('Notes')}</span>
  208. </MenuItem>
  209. <MenuItem
  210. selected={this.props.showUnpublishedAssignments}
  211. onSelect={this.props.onSelectShowUnpublishedAssignments}
  212. >
  213. {I18n.t('Unpublished Assignments')}
  214. </MenuItem>
  215. </MenuItemGroup>
  216. </PopoverMenu>
  217. );
  218. }
  219. }
  220. export default ViewOptionsMenu;