diff --git a/scripts/langindex.json b/scripts/langindex.json index 64a23a98d..f3d2bc96c 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -346,6 +346,7 @@ "addon.mod_assign.cannotsubmitduetostatementsubmission": "local_moodlemobileapp", "addon.mod_assign.confirmstart": "assign", "addon.mod_assign.confirmsubmission": "assign", + "addon.mod_assign.currentassigngrade": "assign", "addon.mod_assign.currentattempt": "assign", "addon.mod_assign.currentattemptof": "assign", "addon.mod_assign.currentgrade": "assign", @@ -702,8 +703,8 @@ "addon.mod_glossary.entrydeleted": "glossary", "addon.mod_glossary.entrypendingapproval": "local_moodlemobileapp", "addon.mod_glossary.entryusedynalink": "glossary", - "addon.mod_glossary.errordeleting": "local_moodlemobileapp", "addon.mod_glossary.errconceptalreadyexists": "glossary", + "addon.mod_glossary.errordeleting": "local_moodlemobileapp", "addon.mod_glossary.errorloadingentries": "local_moodlemobileapp", "addon.mod_glossary.errorloadingentry": "local_moodlemobileapp", "addon.mod_glossary.errorloadingglossary": "local_moodlemobileapp", diff --git a/src/addons/mod/assign/components/submission/addon-mod-assign-submission.html b/src/addons/mod/assign/components/submission/addon-mod-assign-submission.html index 6a1777f15..1aa153367 100644 --- a/src/addons/mod/assign/components/submission/addon-mod-assign-submission.html +++ b/src/addons/mod/assign/components/submission/addon-mod-assign-submission.html @@ -308,6 +308,15 @@

{{ outcome.selected }}

+ + + +

{{ 'addon.mod_assign.currentassigngrade' | translate }}

+

{{ grade.unreleasedGrade}} / {{ gradeInfo.grade }}

+

{{ grade.unreleasedGrade }}

+
+
+ diff --git a/src/addons/mod/assign/components/submission/submission.ts b/src/addons/mod/assign/components/submission/submission.ts index 3715161ef..c045ff47a 100644 --- a/src/addons/mod/assign/components/submission/submission.ts +++ b/src/addons/mod/assign/components/submission/submission.ts @@ -59,6 +59,7 @@ import { AddonModAssignSubmissionPluginComponent } from '../submission-plugin/su import { AddonModAssignModuleHandlerService } from '../../services/handlers/module'; import { CanLeave } from '@guards/can-leave'; import { CoreTime } from '@singletons/time'; +import { isSafeNumber, SafeNumber } from '@/core/utils/types'; /** * Component that displays an assignment submission. @@ -476,6 +477,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can )); promises.push(AddonModAssign.invalidateAssignmentUserMappingsData(this.assign.id)); promises.push(AddonModAssign.invalidateListParticipantsData(this.assign.id)); + promises.push(AddonModAssign.invalidateAssignmentGradesData(this.assign.id)); } promises.push(CoreGradesHelper.invalidateGradeModuleItems(this.courseId, this.submitId)); promises.push(CoreCourse.invalidateModule(this.moduleId)); @@ -691,7 +693,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can } // Treat the grade info. - await this.treatGradeInfo(); + await this.treatGradeInfo(assign); const isManual = assign.attemptreopenmethod == AddonModAssignAttemptReopenMethodValues.MANUAL; const isUnlimited = assign.maxattempts == AddonModAssignProvider.UNLIMITED_ATTEMPTS; @@ -708,7 +710,10 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can AddonModAssign.getSubmissionGradingStatusTranslationId(this.grade.gradingStatus); } - if (this.lastAttempt?.gradingstatus == 'graded' && !assign.markingworkflow && this.userSubmission && feedback) { + if ( + this.lastAttempt?.gradingstatus === AddonModAssignGradingStates.GRADED && !assign.markingworkflow && + this.userSubmission && feedback + ) { if (feedback.gradeddate < this.userSubmission.timemodified) { this.lastAttempt.gradingstatus = AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT; @@ -975,9 +980,10 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can /** * Treat the grade info. * + * @param assign Assign info. * @returns Promise resolved when done. */ - protected async treatGradeInfo(): Promise { + protected async treatGradeInfo(assign: AddonModAssignAssign): Promise { if (!this.gradeInfo) { return; } @@ -997,12 +1003,33 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can this.canSaveGrades = this.grade.method == 'simple'; // Grades can be saved if simple grading. + const gradeNotReleased = assign.markingworkflow && + this.grade.gradingStatus !== AddonModAssignGradingStates.MARKING_WORKFLOW_STATE_RELEASED; + + const [gradebookGrades, assignGrades] = await Promise.all([ + CoreGradesHelper.getGradeModuleItems(this.courseId, this.moduleId, this.submitId), + gradeNotReleased ? + CoreUtils.ignoreErrors(AddonModAssign.getAssignmentGrades(assign.id, { cmId: assign.cmid })) : + undefined, + ]); + + const unreleasedGrade = Number(assignGrades?.find(grade => grade.userid === this.submitId)?.grade); + this.grade.unreleasedGrade = undefined; + if (gradeInfo.scale) { - this.grade.scale = - CoreUtils.makeMenuFromList(gradeInfo.scale, Translate.instant('core.nograde')); + this.grade.scale = CoreUtils.makeMenuFromList(gradeInfo.scale, Translate.instant('core.nograde')); + + if (isSafeNumber(unreleasedGrade)) { + const scaleItem = this.grade.scale.find(scaleItem => scaleItem.value === unreleasedGrade); + this.grade.unreleasedGrade = scaleItem?.label; + this.grade.grade = (scaleItem ?? this.grade.scale[0])?.value; + this.originalGrades.grade = this.grade.grade; + } } else { + this.grade.unreleasedGrade = isSafeNumber(unreleasedGrade) ? unreleasedGrade : undefined; + // Format the grade. - this.grade.grade = CoreUtils.formatFloat(this.grade.grade); + this.grade.grade = CoreUtils.formatFloat(this.grade.unreleasedGrade ?? this.grade.grade); this.originalGrades.grade = this.grade.grade; // Get current language to format grade input field. @@ -1024,12 +1051,9 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can }); } - // Get grade items. - const grades = await CoreGradesHelper.getGradeModuleItems(this.courseId, this.moduleId, this.submitId); - const outcomes: AddonModAssignGradeOutcome[] = []; - grades.forEach((grade: CoreGradesFormattedItem) => { + gradebookGrades.forEach((grade: CoreGradesFormattedItem) => { if (!grade.outcomeid && !grade.scaleid) { // Clean HTML tags, grade can contain an icon. @@ -1245,6 +1269,7 @@ type AddonModAssignSubmissionGrade = { scale?: CoreMenuItem[]; lang: string; disabled: boolean; + unreleasedGrade?: SafeNumber | string; }; type AddonModAssignSubmissionOriginalGrades = { diff --git a/src/addons/mod/assign/lang.json b/src/addons/mod/assign/lang.json index 050cb5d21..de0b0cc9d 100644 --- a/src/addons/mod/assign/lang.json +++ b/src/addons/mod/assign/lang.json @@ -22,6 +22,7 @@ "cannotsubmitduetostatementsubmission": "You can't make a submission in the app because the submission statement could not be retrieved from the site.", "confirmstart": "You have {{$a}} to complete this assignment. When you begin, the timer will start to count down and can't be paused.", "confirmsubmission": "Are you sure you want to submit your work for grading? You will not be able to make any more changes.", + "currentassigngrade": "Current grade in assignment", "currentattempt": "This is attempt {{$a}}.", "currentattemptof": "This is attempt {{$a.attemptnumber}} ( {{$a.maxattempts}} attempts allowed ).", "currentgrade": "Current grade in gradebook", diff --git a/src/addons/mod/assign/services/handlers/prefetch.ts b/src/addons/mod/assign/services/handlers/prefetch.ts index 29d6afbfd..0cb4fc2f4 100644 --- a/src/addons/mod/assign/services/handlers/prefetch.ts +++ b/src/addons/mod/assign/services/handlers/prefetch.ts @@ -374,10 +374,7 @@ export class AddonModAssignPrefetchHandlerService extends CoreCourseActivityPref return this.prefetchSubmission(assign, courseId, moduleId, submissionOptions, true); }); - if (!assign.markingworkflow) { - // Get assignment grades only if workflow is not enabled to check grading date. - subPromises.push(AddonModAssign.getAssignmentGrades(assign.id, modOptions)); - } + subPromises.push(AddonModAssign.getAssignmentGrades(assign.id, modOptions)); // Prefetch the submission of the current user even if it does not exist, this will be create it. if (!submissions || !submissions.find((subm: AddonModAssignSubmissionFormatted) => subm.submitid == userId)) { diff --git a/src/addons/mod/assign/tests/behat/marking_workflow.feature b/src/addons/mod/assign/tests/behat/marking_workflow.feature index e834ee1ee..f3359b460 100755 --- a/src/addons/mod/assign/tests/behat/marking_workflow.feature +++ b/src/addons/mod/assign/tests/behat/marking_workflow.feature @@ -9,6 +9,7 @@ Feature: Test marking workflow in assignment activity in app | student2 | Student2 | student2 | student2@example.com | | student3 | Student3 | student3 | student3@example.com | | student4 | Student4 | student4 | student4@example.com | + | student5 | Student5 | student5 | student5@example.com | And the following "courses" exist: | fullname | shortname | category | | Course 1 | C1 | 0 | @@ -19,15 +20,18 @@ Feature: Test marking workflow in assignment activity in app | student2 | C1 | student | | student3 | C1 | student | | student4 | C1 | student | + | student5 | C1 | student | And the following "groups" exist: | name | course | idnumber | | Group 1 | C1 | G1 | | Group 2 | C1 | G2 | + | Group 3 | C1 | G3 | And the following "group members" exist: | user | group | | student1 | G1 | | student2 | G1 | | student3 | G2 | + | student4 | G3 | And the following "activities" exist: | activity | course | idnumber | name | assignsubmission_onlinetext_enabled | assignfeedback_comments_enabled | markingworkflow | teamsubmission | groupmode | submissiondrafts | | assign | C1 | assign1 | Group Assign | 1 | 1 | 1 | 1 | 1 | 0 | @@ -35,7 +39,8 @@ Feature: Test marking workflow in assignment activity in app | assign | user | onlinetext | | assign1 | student1 | Lorem | | assign1 | student3 | Ipsum | - # Mark a submission. + | assign1 | student4 | Dolor | + # Mark submissions. And I am on the "Group Assign" "assign activity" page logged in as teacher1 And I follow "View all submissions" And I click on "Grade" "link" in the "Student1" "table_row" @@ -44,16 +49,72 @@ Feature: Test marking workflow in assignment activity in app And I set the field "Feedback comments" to "Great job! Lol, not really." And I set the field "Notify student" to "0" And I press "Save changes" + And I am on the "Group Assign" "assign activity" page + And I follow "View all submissions" + And I click on "Grade" "link" in the "Student3" "table_row" + And I set the field "Grade out of 100" to "30" + And I set the field "Marking workflow state" to "Released" + And I set the field "Feedback comments" to "Needs to be improved." + And I set the field "Notify student" to "0" + And I press "Save changes" And I log out - Scenario: View submissions with marking workflow as teacher + Scenario: View submissions with marking workflow and using points as teacher Given I entered the assign activity "Group Assign" on course "Course 1" as "teacher1" in the app - And I press "Groups" in the app + When I press "Groups" in the app Then I should find "Submitted for grading" within "Student1" "ion-item" in the app And I should find "In review" within "Student1" "ion-item" in the app And I should find "Submitted for grading" within "Student2" "ion-item" in the app And I should find "In review" within "Student2" "ion-item" in the app And I should find "Submitted for grading" within "Student3" "ion-item" in the app - And I should find "Not marked" within "Student3" "ion-item" in the app - And I should find "No submission" within "Student4" "ion-item" in the app - And I should not find "Not marked" within "Student4" "ion-item" in the app + And I should find "Released" within "Student3" "ion-item" in the app + And I should find "Submitted for grading" within "Student4" "ion-item" in the app + And I should find "Not marked" within "Student4" "ion-item" in the app + And I should find "No submission" within "Student5" "ion-item" in the app + And I should not find "Not marked" within "Student5" "ion-item" in the app + + When I press "Student1" in the app + And I press "Grade" in the app + Then I should find "Submitted for grading" in the app + And I should find "50 / 100" within "Current grade in assignment" "ion-item" in the app + And I should find "-" within "Current grade in gradebook" "ion-item" in the app + And I should find "In review" within "Marking workflow state" "ion-item" in the app + And the field "Grade out of 100" matches value "50" in the app + And I should not find "Graded by" in the app + + When I press the back button in the app + And I press "Student3" in the app + And I press "Grade" in the app + Then I should find "Submitted for grading" in the app + And I should find "30" within "Current grade in gradebook" "ion-item" in the app + And I should find "Released" within "Marking workflow state" "ion-item" in the app + And I should find "Teacher teacher" within "Graded by" "ion-item" in the app + And the field "Grade out of 100" matches value "30" in the app + And I should not find "Current grade in assignment" in the app + + Scenario: Grade submissions with marking workflow and using points + Given I entered the assign activity "Group Assign" on course "Course 1" as "teacher1" in the app + And I press "Groups" in the app + And I press "Student1" in the app + And I press "Grade" in the app + When I set the field "Grade out of 100" to "60" in the app + And I press "Done" in the app + And I press "Student1" in the app + And I press "Grade" in the app + Then I should find "60 / 100" within "Current grade in assignment" "ion-item" in the app + And I should find "-" within "Current grade in gradebook" "ion-item" in the app + And I should find "In review" within "Marking workflow state" "ion-item" in the app + And the field "Grade out of 100" matches value "60" in the app + + When I press the back button in the app + And I press "Student3" in the app + And I press "Grade" in the app + When I set the field "Grade out of 100" to "80" in the app + And I press "Done" in the app + And I press "Student3" in the app + And I press "Grade" in the app + Then I should find "80" within "Current grade in gradebook" "ion-item" in the app + And I should find "Released" within "Marking workflow state" "ion-item" in the app + And I should find "Teacher teacher" within "Graded by" "ion-item" in the app + And the field "Grade out of 100" matches value "80" in the app + And I should not find "Current grade in assignment" in the app