Render react student grades page

refs VICE-3474
refs VICE-3471
refs VICE-3472
refs VICE-3473

flag=restrict_quantitative_data

Test Plan:
- with “Update grade summary table to use a modern framework”
    turned on
- go to the student grade summary page
- table should calculate grades correctly according to
   - assignment group weights
   - grading period weights
- turn RQD ff on
- students grade table should show correct letter grades

Change-Id: I5685a2db505734c8b4cea3592de66802456e9426
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/318040
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Jason Gillett <jason.gillett@instructure.com>
QA-Review: Caleb Guanzon <cguanzon@instructure.com>
Product-Review: Drake Harper <drake.harper@instructure.com>
This commit is contained in:
Drake Harper 2023-05-12 01:06:11 -06:00
parent 4377d3c7e3
commit ba9bb1c467
4 changed files with 215 additions and 1 deletions

View File

@ -28,6 +28,7 @@ import '@canvas/jquery/jquery.disableWhileLoading'
// Ensure the gradebook summary code has had a chance to setup all its handlers
GradeSummary.setup()
let router
class GradebookSummaryRouter extends Backbone.Router {
initialize() {
if (!ENV.student_outcome_gradebook_enabled) return
@ -77,10 +78,11 @@ GradebookSummaryRouter.prototype.routes = {
'tab-:route(/*path)': 'tab',
}
let router
$(() => {
GradeSummary.renderSelectMenuGroup()
GradeSummary.renderSubmissionCommentsTray()
if (ENV.student_grade_summary_upgrade || ENV.restrict_quantitative_data)
GradeSummary.renderGradeSummaryTable()
router = new GradebookSummaryRouter()
Backbone.history.start()

View File

@ -38,6 +38,7 @@ import {scopeToUser} from '@canvas/grading/EffectiveDueDates'
import {scoreToGrade} from '@canvas/grading/GradingSchemeHelper'
import GradeFormatHelper from '@canvas/grading/GradeFormatHelper'
import StatusPill from '@canvas/grading-status-pill'
import GradeSummaryManager from '../react/GradeSummary/GradeSummaryManager'
import SelectMenuGroup from '../react/SelectMenuGroup'
import SubmissionCommentsTray from '../react/SubmissionCommentsTray'
import {scoreToPercentage} from '@canvas/grading/GradeCalculationHelper'
@ -610,6 +611,10 @@ function renderSelectMenuGroup() {
)
}
function renderGradeSummaryTable() {
ReactDOM.render(<GradeSummaryManager />, document.getElementById('grade-summary-react'))
}
function handleSubmissionsCommentTray(assignmentId) {
const {submissionTrayAssignmentId, submissionTrayOpen} = useStore.getState()
@ -875,6 +880,7 @@ export default _.extend(GradeSummary, {
formatPercentGrade,
getSelectMenuGroupProps,
renderSelectMenuGroup,
renderGradeSummaryTable,
getSubmissionCommentsTrayProps,
handleSubmissionsCommentTray,
renderSubmissionCommentsTray,

View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2023 - 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 {useQuery} from 'react-apollo'
import {useScope as useI18nScope} from '@canvas/i18n'
import GenericErrorPage from '@canvas/generic-error-page'
import errorShipUrl from '@canvas/images/ErrorShip.svg'
import {CloseButton} from '@instructure/ui-buttons'
import {Flex} from '@instructure/ui-flex'
import {Heading} from '@instructure/ui-heading'
import {Responsive} from '@instructure/ui-responsive'
import {Spinner} from '@instructure/ui-spinner'
import {Tray} from '@instructure/ui-tray'
import {View} from '@instructure/ui-view'
import {ASSIGNMENTS} from '../../graphql/queries'
import AssignmentTable from './AssignmentTable'
import SubmissionComment from './SubmissionComment'
import {getGradingPeriodID} from './utils'
const I18n = useI18nScope('grade_summary')
const GradeSummaryContainer = () => {
const [showTray, setShowTray] = React.useState(false)
const [selectedSubmission, setSelectedSubmission] = React.useState([])
const gradingPeriod = getGradingPeriodID()
const assignmentQuery = useQuery(ASSIGNMENTS, {
variables: {
courseID: ENV.course_id,
studentID: ENV.current_user.id,
gradingPeriodID: gradingPeriod && gradingPeriod !== '0' ? gradingPeriod : null,
},
})
if (assignmentQuery.loading) {
return (
<Flex alignItems="center" justifyItems="center" width="100%">
<Flex.Item>
<Spinner renderTitle="Loading" size="large" margin="0 0 0 medium" />
</Flex.Item>
</Flex>
)
}
if (assignmentQuery.error || !assignmentQuery?.data?.legacyNode) {
return (
<GenericErrorPage
imageUrl={errorShipUrl}
errorSubject={I18n.t('Grade Summary initial query error')}
errorCategory={I18n.t('Grade Summary Error Page')}
/>
)
}
const renderCloseButton = () => {
return (
<Flex>
<Flex.Item shouldGrow={true} shouldShrink={true}>
<Heading>Submission Comments</Heading>
</Flex.Item>
<Flex.Item>
<CloseButton
placement="end"
offset="small"
screenReaderLabel="Close"
onClick={() => setShowTray(false)}
/>
</Flex.Item>
</Flex>
)
}
return (
<Responsive
query={{
small: {maxWidth: '40rem'},
large: {minWidth: '41rem'},
}}
props={{
small: {layout: 'stacked'},
large: {layout: 'fixed'},
}}
>
{({layout}) => (
<View as="div">
<AssignmentTable
queryData={assignmentQuery?.data?.legacyNode}
layout={layout}
setShowTray={setShowTray}
setSelectedSubmission={setSelectedSubmission}
/>
<Tray
label={I18n.t('Submission Comments Tray')}
open={showTray}
onDismiss={() => {
setShowTray(false)
}}
size="medium"
placement="end"
>
<View as="div" padding="medium">
{renderCloseButton()}
{selectedSubmission?.commentsConnection?.nodes?.map(comment => {
return <SubmissionComment comment={comment} key={comment?._id} />
})}
</View>
</Tray>
</View>
)}
</Responsive>
)
}
export default GradeSummaryContainer

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2023 - 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 PropTypes from 'prop-types'
import React, {useEffect, useState} from 'react'
import {ApolloProvider, createClient, createPersistentCache} from '@canvas/apollo'
import {useScope as useI18nScope} from '@canvas/i18n'
import ErrorBoundary from '@canvas/error-boundary'
import GenericErrorPage from '@canvas/generic-error-page'
import errorShipUrl from '@canvas/images/ErrorShip.svg'
import GradeSummaryContainer from './GradeSummaryContainer'
import LoadingIndicator from '@canvas/loading-indicator'
const I18n = useI18nScope('grade_summary')
const GradeSummaryManager = () => {
const [client, setClient] = useState(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
document.querySelector('body').classList.add('full-width')
document.querySelector('div.ic-Layout-contentMain').classList.remove('ic-Layout-contentMain')
const setupApolloClient = async () => {
if (ENV.apollo_caching) {
const cache = await createPersistentCache(ENV.conversation_cache_key)
setClient(createClient({cache}))
} else {
setClient(createClient())
}
setLoading(false)
}
setupApolloClient()
}, [])
if (loading) {
return <LoadingIndicator />
}
return (
<ApolloProvider client={client}>
<ErrorBoundary
errorComponent={
<GenericErrorPage
imageUrl={errorShipUrl}
errorCategory={I18n.t('Grade Summary Error Page')}
/>
}
>
<GradeSummaryContainer />
</ErrorBoundary>
</ApolloProvider>
)
}
export default GradeSummaryManager