From d1664390e2bd73597b0cda87dca18cf63cc2c832 Mon Sep 17 00:00:00 2001 From: Ed Schiebel Date: Tue, 14 Feb 2017 16:54:51 -0500 Subject: [PATCH] Upgrade instructure-ui to 1.0 fixes CNVS-34969 test plan: - go /profile/settings and turn on high contrast - go to the course people page (/courses/#/users) - click on the +People button > expected result: the modal honors high contrast - enter some text in he text area > expected result: nothing bad happens, as the event handler for TextArea has changed. - there's a TextArea in MessageStudents also, but I don't know where to find it in the UI. You should probalby test it doesn't blow up either. Change-Id: Ia8102dacfa2b01ee043002ee0f5c27943abe5743 Reviewed-on: https://gerrit.instructure.com/102133 Tested-by: Jenkins Reviewed-by: Ryan Shaw QA-Review: Dan Sasaki Product-Review: Ryan Shaw Product-Review: Ed Schiebel --- app/coffeescripts/bundles/common.coffee | 10 +- app/jsx/add_people/components/add_people.jsx | 23 ++-- app/jsx/add_people/components/api_error.jsx | 6 +- .../components/duplicate_section.jsx | 15 ++- .../components/missing_people_section.jsx | 24 ++-- .../components/people_ready_list.jsx | 6 +- .../add_people/components/people_search.jsx | 30 +++-- .../components/people_validation_issues.jsx | 4 +- app/jsx/add_people/components/shapes.jsx | 2 +- app/jsx/appBootstrap.jsx | 17 ++- app/jsx/context_cards/Avatar.jsx | 2 +- app/jsx/context_cards/Rating.jsx | 2 +- app/jsx/context_cards/StudentContextTray.jsx | 22 ++-- .../context_cards/SubmissionProgressBars.jsx | 2 +- .../components/CoursePickerTable.jsx | 6 +- .../components/AssignmentColumnHeader.jsx | 6 +- .../AssignmentGroupColumnHeader.jsx | 4 +- .../components/StudentColumnHeader.jsx | 4 +- .../components/TotalGradeColumnHeader.jsx | 4 +- app/jsx/new_user_tutorial/trays/HomeTray.jsx | 6 +- .../new_user_tutorial/trays/ModulesTray.jsx | 2 +- app/jsx/shared/MessageStudents.jsx | 13 +- app/stylesheets/bundles/roster.scss | 13 +- frontend_build/baseWebpackConfig.js | 1 + lib/canvas/require_js.rb | 1 + package.json | 39 ++++-- .../components/missingPeopleSectionSpec.jsx | 13 +- .../components/ActionMenuSpec.jsx | 8 +- .../components/AssignmentColumnHeaderSpec.jsx | 41 ++++--- .../components/GradebookMenuSpec.jsx | 10 +- spec/javascripts/load_tests.js.erb | 9 ++ spec/javascripts/webpack_spec_index.js | 13 +- .../grades/gradezilla/gradebook_spec.rb | 6 +- yarn.lock | 115 ++++++++++-------- 34 files changed, 274 insertions(+), 205 deletions(-) diff --git a/app/coffeescripts/bundles/common.coffee b/app/coffeescripts/bundles/common.coffee index 735ba1ac920..2205ead289f 100644 --- a/app/coffeescripts/bundles/common.coffee +++ b/app/coffeescripts/bundles/common.coffee @@ -7,6 +7,7 @@ require [ 'compiled/helpDialog' 'jsx/subnav_menu/updateSubnavMenuToggle' 'jsx/new_user_tutorial/initializeNewUserTutorials' + 'instructure-ui/ApplyTheme' # modules that do their own thing on every page that simply need to # be required @@ -30,6 +31,7 @@ require [ 'compiled/behaviors/ping' 'LtiThumbnailLauncher' 'compiled/badge_counts' + 'instructure-ui-themes/canvas' # Other stuff several bundles use. # If any of these really arn't used on most pages, @@ -41,7 +43,7 @@ require [ 'jqueryui/tabs' 'compiled/registration/incompleteRegistrationWarning' 'moment' -], ($, _, I18n, Backbone, helpDialog, updateSubnavMenuToggle, initializeNewUserTutorials) -> +], ($, _, I18n, Backbone, helpDialog, updateSubnavMenuToggle, initializeNewUserTutorials, ApplyTheme) -> helpDialog.initTriggers() @@ -80,3 +82,9 @@ require [ $('body').on 'click', '[data-pushstate]', (event) -> event.preventDefault() Backbone.history.navigate $(this).attr('href'), yes + + # setup the inst-ui default theme + if ENV.use_high_contrast + ApplyTheme.default.setDefaultTheme('canvas-a11y') + else + ApplyTheme.default.setDefaultTheme('canvas') diff --git a/app/jsx/add_people/components/add_people.jsx b/app/jsx/add_people/components/add_people.jsx index ec15240da7b..3d8681972f6 100644 --- a/app/jsx/add_people/components/add_people.jsx +++ b/app/jsx/add_people/components/add_people.jsx @@ -2,16 +2,21 @@ define([ 'i18n!roster', 'react', 'react-dom', - 'instructure-ui', + 'instructure-ui/Modal', + 'instructure-ui/Heading', + 'instructure-ui/Button', + 'instructure-ui/Spinner', + 'instructure-ui/Alert', + 'instructure-ui/ScreenReaderContent', './shapes', './people_search', './people_ready_list', './people_validation_issues', './api_error' ], (I18n, React, ReactDOM, - {Modal, ModalHeader, ModalBody, ModalFooter, - Heading, Button, Spinner, Alert, - ScreenReaderContent, ApplyTheme}, + {default: Modal, ModalHeader, ModalBody, ModalFooter}, + {default: Heading}, {default: Button}, {default: Spinner}, {default: Alert}, + {default: ScreenReaderContent}, {courseParamsShape, apiStateShape, inputParamsShape, validateResultShape, personReadyToEnrollShape}, PeopleSearch, PeopleReadyList, PeopleValidationIssues, APIError) => { const PEOPLESEARCH = 'peoplesearch'; @@ -307,13 +312,5 @@ define([ ); } } - - const DeleteMe = props => ( - - - - ) - - /* TODO: after instui gets updated, just return AddPeople */ - return ENV.use_high_contrast ? DeleteMe : AddPeople; + return AddPeople; }); diff --git a/app/jsx/add_people/components/api_error.jsx b/app/jsx/add_people/components/api_error.jsx index ee382afce2c..5882914782c 100644 --- a/app/jsx/add_people/components/api_error.jsx +++ b/app/jsx/add_people/components/api_error.jsx @@ -1,8 +1,8 @@ define([ 'i18n!roster', 'react', - 'instructure-ui' -], (I18n, React, {Alert}) => { + 'instructure-ui/Alert' +], (I18n, React, {default: Alert}) => { class ApiError extends React.Component { static propTypes = { error: React.PropTypes.oneOfType([ @@ -17,7 +17,7 @@ define([ {I18n.t('The following users could not be created.')}
    { - this.props.error.map((e, i) =>
  • {e}
  • ) + this.props.error.map(e =>
  • {e}
  • ) }
diff --git a/app/jsx/add_people/components/duplicate_section.jsx b/app/jsx/add_people/components/duplicate_section.jsx index e6f16d38cb3..60da0b32a20 100644 --- a/app/jsx/add_people/components/duplicate_section.jsx +++ b/app/jsx/add_people/components/duplicate_section.jsx @@ -2,9 +2,14 @@ define([ 'i18n!roster', 'react', './shapes', - 'instructure-ui' -], (I18n, React, shapes, {Table, ScreenReaderContent, - TextInput, RadioInput, Typography, Link}) => { + 'instructure-ui/Table', + 'instructure-ui/ScreenReaderContent', + 'instructure-ui/TextInput', + 'instructure-ui/RadioInput', + 'instructure-ui/Typography', + 'instructure-ui/Link' +], (I18n, React, shapes, {default: Table}, {default: ScreenReaderContent}, + {default: TextInput}, {default: RadioInput}, {default: Typography}, {default: Link}) => { const CREATE_NEW = '__CREATE_NEW__'; const SKIP = '__SKIP'; const nameLabel = I18n.t("New user's name"); @@ -39,7 +44,9 @@ define([ onSelectNewForDuplicate = (event) => { // if the event was not from the radio button, find and focus it if (!(event.target.tagName === 'input' && event.target.getAttribute('type') === 'radio')) { - const radioButton = event.target.parentElement.parentElement.querySelector('input[type="radio"]'); + let elem = event.target; + for (; elem.tagName !== 'TR'; elem = elem.parentElement); + const radioButton = elem.querySelector('input[type="radio"]'); radioButton.focus(); } this.props.onNewForDuplicate(this.props.duplicates.address, this.props.duplicates.newUserInfo); diff --git a/app/jsx/add_people/components/missing_people_section.jsx b/app/jsx/add_people/components/missing_people_section.jsx index e0d335c9ec6..1f55ea2f22a 100644 --- a/app/jsx/add_people/components/missing_people_section.jsx +++ b/app/jsx/add_people/components/missing_people_section.jsx @@ -2,9 +2,13 @@ define([ 'i18n!roster', 'react', './shapes', - 'instructure-ui' -], (I18n, React, shapes, {Table, ScreenReaderContent, - TextInput, Checkbox, Link}) => { + 'instructure-ui/Table', + 'instructure-ui/ScreenReaderContent', + 'instructure-ui/TextInput', + 'instructure-ui/Checkbox', + 'instructure-ui/Link' +], (I18n, React, shapes, {default: Table}, {default: ScreenReaderContent}, + {default: TextInput}, {default: Checkbox}, {default: Link}) => { const namePrompt = I18n.t('Click to add a name'); const nameLabel = I18n.t("New user's name"); const emailLabel = I18n.t('Required Email Address'); @@ -31,6 +35,7 @@ define([ this.state = { selectAll: false }; + this.tbodyNode = null; } componentWillReceiveProps (nextProps) { @@ -44,11 +49,14 @@ define([ eatEvent(event); // user may have clicked on the link. if so, put focus on the adjacent checkbox - if (!(event.target.tagName === 'input' && event.target.getAttribute('type') === 'checkbox')) { - const checkbox = event.target.parentElement.parentElement.querySelector('input[type="checkbox"]'); - checkbox.focus(); + if (!(event.target.tagName === 'INPUT' && event.target.getAttribute('type') === 'checkbox')) { + // The link was rendered with the attribute data-address=address for this row. + // Use it to find the checkbox with the matching value. + const checkbox = this.tbodyNode.querySelector(`input[type="checkbox"][value="${event.target.getAttribute('data-address')}"]`); + if (checkbox) { + checkbox.focus(); + } } - const address = event.target.value || event.target.getAttribute('data-address'); this.onSelectNewForMissingByAddress(address); } @@ -288,7 +296,7 @@ define([
{I18n.t('Unmatched login list')}}> {this.renderTableHead()} - + { this.tbodyNode = n; }} > {this.props.searchType === 'cc_path' ? this.renderMissingEmail() : this.renderMissingIds()}
diff --git a/app/jsx/add_people/components/people_ready_list.jsx b/app/jsx/add_people/components/people_ready_list.jsx index 07d052c6837..3e8bf4ab7c7 100644 --- a/app/jsx/add_people/components/people_ready_list.jsx +++ b/app/jsx/add_people/components/people_ready_list.jsx @@ -2,9 +2,11 @@ define([ 'i18n!roster', 'react', './shapes', - 'instructure-ui' + 'instructure-ui/Alert', + 'instructure-ui/Table', + 'instructure-ui/ScreenReaderContent' ], (I18n, React, {personReadyToEnrollShape}, - {Alert, Table, ScreenReaderContent}) => { + {default: Alert}, {default: Table}, {default: ScreenReaderContent}) => { class PeopleReadyList extends React.Component { static propTypes = { nameList: React.PropTypes.arrayOf(React.PropTypes.shape(personReadyToEnrollShape)), diff --git a/app/jsx/add_people/components/people_search.jsx b/app/jsx/add_people/components/people_search.jsx index f2c9bbefbf1..153aee6fbd8 100644 --- a/app/jsx/add_people/components/people_search.jsx +++ b/app/jsx/add_people/components/people_search.jsx @@ -1,12 +1,22 @@ define([ 'i18n!roster', 'react', - 'instructure-ui', + 'instructure-ui/Button', + 'instructure-ui/Typography', + 'instructure-ui/RadioInputGroup', + 'instructure-ui/RadioInput', + 'instructure-ui/Select', + 'instructure-ui/TextArea', + 'instructure-ui/ScreenReaderContent', + 'instructure-ui/Checkbox', + 'instructure-ui/Alert', + 'instructure-icons/react/Solid/IconUserSolid', './shapes', '../helpers' -], (I18n, React, {Button, Typography, RadioInputGroup, - RadioInput, Select, TextArea, ScreenReaderContent, - Checkbox, Alert}, {courseParamsShape, inputParamsShape}, +], (I18n, React, {default: Button}, {default: Typography}, {default: RadioInputGroup}, + {default: RadioInput}, {default: Select}, {default: TextArea}, {default: ScreenReaderContent}, + {default: Checkbox}, {default: Alert}, {default: IconUserSolid}, + {courseParamsShape, inputParamsShape}, {parseNameList, findEmailInEntry, emailValidator}) => { class PeopleSearch extends React.Component { static propTypes = Object.assign({}, inputParamsShape, courseParamsShape); @@ -38,8 +48,8 @@ define([ onChangeSearchType = (newValue) => { this.props.onChange({searchType: newValue}); } - onChangeNameList = (newValue) => { - this.props.onChange({nameList: newValue}); + onChangeNameList = (event) => { + this.props.onChange({nameList: event.target.value}); } onChangeSection = (event) => { @@ -98,17 +108,16 @@ define([ defaultValue={this.props.searchType} description={I18n.t('Add user(s) by')} onChange={this.onChangeSearchType} + layout="columns" >
- +
+ +
{I18n.t('When adding multiple users, use a comma or line break to separate users.')} diff --git a/app/jsx/add_people/components/people_validation_issues.jsx b/app/jsx/add_people/components/people_validation_issues.jsx index 4ed2c05cf27..1c3e946736a 100644 --- a/app/jsx/add_people/components/people_validation_issues.jsx +++ b/app/jsx/add_people/components/people_validation_issues.jsx @@ -4,8 +4,8 @@ define([ './shapes', './duplicate_section', './missing_people_section', - 'instructure-ui' -], (I18n, React, shapes, DuplicateSection, MissingPeopleSection, {Alert}) => { + 'instructure-ui/Alert' +], (I18n, React, shapes, DuplicateSection, MissingPeopleSection, {default: Alert}) => { class PeopleValidationIssues extends React.Component { static propTypes = { searchType: React.PropTypes.string.isRequired, diff --git a/app/jsx/add_people/components/shapes.jsx b/app/jsx/add_people/components/shapes.jsx index 97beb7b2725..62cfa5c7fac 100644 --- a/app/jsx/add_people/components/shapes.jsx +++ b/app/jsx/add_people/components/shapes.jsx @@ -10,7 +10,7 @@ define([ const apiStateShape = { pendingCount: PropTypes.number, // number of api calls in-flight - error: PropTypes.string // error message or undefined + error: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]) // error message or undefined }; const inputParamsShape = { diff --git a/app/jsx/appBootstrap.jsx b/app/jsx/appBootstrap.jsx index e76667e941b..38337a53c94 100644 --- a/app/jsx/appBootstrap.jsx +++ b/app/jsx/appBootstrap.jsx @@ -1,19 +1,24 @@ +import ApplyTheme from 'instructure-ui/ApplyTheme' +import 'instructure-ui-themes/canvas' +import moment from 'moment' +import tz from 'timezone_core' +import './fakeRequireJSFallback' -// Sets up moment to use the right locale -const moment = require('moment') // we already put a