MOBILE-4281 assign: Display submission grade when using marking workflow
parent
c631db2082
commit
d4aab021f0
|
@ -346,6 +346,7 @@
|
||||||
"addon.mod_assign.cannotsubmitduetostatementsubmission": "local_moodlemobileapp",
|
"addon.mod_assign.cannotsubmitduetostatementsubmission": "local_moodlemobileapp",
|
||||||
"addon.mod_assign.confirmstart": "assign",
|
"addon.mod_assign.confirmstart": "assign",
|
||||||
"addon.mod_assign.confirmsubmission": "assign",
|
"addon.mod_assign.confirmsubmission": "assign",
|
||||||
|
"addon.mod_assign.currentassigngrade": "assign",
|
||||||
"addon.mod_assign.currentattempt": "assign",
|
"addon.mod_assign.currentattempt": "assign",
|
||||||
"addon.mod_assign.currentattemptof": "assign",
|
"addon.mod_assign.currentattemptof": "assign",
|
||||||
"addon.mod_assign.currentgrade": "assign",
|
"addon.mod_assign.currentgrade": "assign",
|
||||||
|
@ -702,8 +703,8 @@
|
||||||
"addon.mod_glossary.entrydeleted": "glossary",
|
"addon.mod_glossary.entrydeleted": "glossary",
|
||||||
"addon.mod_glossary.entrypendingapproval": "local_moodlemobileapp",
|
"addon.mod_glossary.entrypendingapproval": "local_moodlemobileapp",
|
||||||
"addon.mod_glossary.entryusedynalink": "glossary",
|
"addon.mod_glossary.entryusedynalink": "glossary",
|
||||||
"addon.mod_glossary.errordeleting": "local_moodlemobileapp",
|
|
||||||
"addon.mod_glossary.errconceptalreadyexists": "glossary",
|
"addon.mod_glossary.errconceptalreadyexists": "glossary",
|
||||||
|
"addon.mod_glossary.errordeleting": "local_moodlemobileapp",
|
||||||
"addon.mod_glossary.errorloadingentries": "local_moodlemobileapp",
|
"addon.mod_glossary.errorloadingentries": "local_moodlemobileapp",
|
||||||
"addon.mod_glossary.errorloadingentry": "local_moodlemobileapp",
|
"addon.mod_glossary.errorloadingentry": "local_moodlemobileapp",
|
||||||
"addon.mod_glossary.errorloadingglossary": "local_moodlemobileapp",
|
"addon.mod_glossary.errorloadingglossary": "local_moodlemobileapp",
|
||||||
|
|
|
@ -308,6 +308,15 @@
|
||||||
<p *ngIf="!canSaveGrades || !outcome.itemNumber">{{ outcome.selected }}</p>
|
<p *ngIf="!canSaveGrades || !outcome.itemNumber">{{ outcome.selected }}</p>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
|
<!-- Assign grade if it wasn't released to gradebook. -->
|
||||||
|
<ion-item class="ion-text-wrap" *ngIf="gradeInfo && grade.unreleasedGrade !== undefined">
|
||||||
|
<ion-label>
|
||||||
|
<p class="item-heading">{{ 'addon.mod_assign.currentassigngrade' | translate }}</p>
|
||||||
|
<p *ngIf="grade.method != 'simple' || !grade.scale">{{ grade.unreleasedGrade}} / {{ gradeInfo.grade }}</p>
|
||||||
|
<p *ngIf="grade.method == 'simple' && grade.scale">{{ grade.unreleasedGrade }}</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
<!-- Gradebook grade for simple grading. -->
|
<!-- Gradebook grade for simple grading. -->
|
||||||
<ion-item class="ion-text-wrap" *ngIf="grade.method == 'simple'">
|
<ion-item class="ion-text-wrap" *ngIf="grade.method == 'simple'">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
|
|
|
@ -59,6 +59,7 @@ import { AddonModAssignSubmissionPluginComponent } from '../submission-plugin/su
|
||||||
import { AddonModAssignModuleHandlerService } from '../../services/handlers/module';
|
import { AddonModAssignModuleHandlerService } from '../../services/handlers/module';
|
||||||
import { CanLeave } from '@guards/can-leave';
|
import { CanLeave } from '@guards/can-leave';
|
||||||
import { CoreTime } from '@singletons/time';
|
import { CoreTime } from '@singletons/time';
|
||||||
|
import { isSafeNumber, SafeNumber } from '@/core/utils/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that displays an assignment submission.
|
* 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.invalidateAssignmentUserMappingsData(this.assign.id));
|
||||||
promises.push(AddonModAssign.invalidateListParticipantsData(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(CoreGradesHelper.invalidateGradeModuleItems(this.courseId, this.submitId));
|
||||||
promises.push(CoreCourse.invalidateModule(this.moduleId));
|
promises.push(CoreCourse.invalidateModule(this.moduleId));
|
||||||
|
@ -691,7 +693,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
||||||
}
|
}
|
||||||
|
|
||||||
// Treat the grade info.
|
// Treat the grade info.
|
||||||
await this.treatGradeInfo();
|
await this.treatGradeInfo(assign);
|
||||||
|
|
||||||
const isManual = assign.attemptreopenmethod == AddonModAssignAttemptReopenMethodValues.MANUAL;
|
const isManual = assign.attemptreopenmethod == AddonModAssignAttemptReopenMethodValues.MANUAL;
|
||||||
const isUnlimited = assign.maxattempts == AddonModAssignProvider.UNLIMITED_ATTEMPTS;
|
const isUnlimited = assign.maxattempts == AddonModAssignProvider.UNLIMITED_ATTEMPTS;
|
||||||
|
@ -708,7 +710,10 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
||||||
AddonModAssign.getSubmissionGradingStatusTranslationId(this.grade.gradingStatus);
|
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) {
|
if (feedback.gradeddate < this.userSubmission.timemodified) {
|
||||||
this.lastAttempt.gradingstatus = AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT;
|
this.lastAttempt.gradingstatus = AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT;
|
||||||
|
|
||||||
|
@ -975,9 +980,10 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
||||||
/**
|
/**
|
||||||
* Treat the grade info.
|
* Treat the grade info.
|
||||||
*
|
*
|
||||||
|
* @param assign Assign info.
|
||||||
* @returns Promise resolved when done.
|
* @returns Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected async treatGradeInfo(): Promise<void> {
|
protected async treatGradeInfo(assign: AddonModAssignAssign): Promise<void> {
|
||||||
if (!this.gradeInfo) {
|
if (!this.gradeInfo) {
|
||||||
return;
|
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.
|
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) {
|
if (gradeInfo.scale) {
|
||||||
this.grade.scale =
|
this.grade.scale = CoreUtils.makeMenuFromList(gradeInfo.scale, Translate.instant('core.nograde'));
|
||||||
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 {
|
} else {
|
||||||
|
this.grade.unreleasedGrade = isSafeNumber(unreleasedGrade) ? unreleasedGrade : undefined;
|
||||||
|
|
||||||
// Format the grade.
|
// 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;
|
this.originalGrades.grade = this.grade.grade;
|
||||||
|
|
||||||
// Get current language to format grade input field.
|
// 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[] = [];
|
const outcomes: AddonModAssignGradeOutcome[] = [];
|
||||||
|
|
||||||
grades.forEach((grade: CoreGradesFormattedItem) => {
|
gradebookGrades.forEach((grade: CoreGradesFormattedItem) => {
|
||||||
if (!grade.outcomeid && !grade.scaleid) {
|
if (!grade.outcomeid && !grade.scaleid) {
|
||||||
|
|
||||||
// Clean HTML tags, grade can contain an icon.
|
// Clean HTML tags, grade can contain an icon.
|
||||||
|
@ -1245,6 +1269,7 @@ type AddonModAssignSubmissionGrade = {
|
||||||
scale?: CoreMenuItem<number>[];
|
scale?: CoreMenuItem<number>[];
|
||||||
lang: string;
|
lang: string;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
|
unreleasedGrade?: SafeNumber | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type AddonModAssignSubmissionOriginalGrades = {
|
type AddonModAssignSubmissionOriginalGrades = {
|
||||||
|
|
|
@ -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.",
|
"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.",
|
"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.",
|
"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}}.",
|
"currentattempt": "This is attempt {{$a}}.",
|
||||||
"currentattemptof": "This is attempt {{$a.attemptnumber}} ( {{$a.maxattempts}} attempts allowed ).",
|
"currentattemptof": "This is attempt {{$a.attemptnumber}} ( {{$a.maxattempts}} attempts allowed ).",
|
||||||
"currentgrade": "Current grade in gradebook",
|
"currentgrade": "Current grade in gradebook",
|
||||||
|
|
|
@ -374,10 +374,7 @@ export class AddonModAssignPrefetchHandlerService extends CoreCourseActivityPref
|
||||||
return this.prefetchSubmission(assign, courseId, moduleId, submissionOptions, true);
|
return this.prefetchSubmission(assign, courseId, moduleId, submissionOptions, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!assign.markingworkflow) {
|
subPromises.push(AddonModAssign.getAssignmentGrades(assign.id, modOptions));
|
||||||
// Get assignment grades only if workflow is not enabled to check grading date.
|
|
||||||
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.
|
// 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)) {
|
if (!submissions || !submissions.find((subm: AddonModAssignSubmissionFormatted) => subm.submitid == userId)) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ Feature: Test marking workflow in assignment activity in app
|
||||||
| student2 | Student2 | student2 | student2@example.com |
|
| student2 | Student2 | student2 | student2@example.com |
|
||||||
| student3 | Student3 | student3 | student3@example.com |
|
| student3 | Student3 | student3 | student3@example.com |
|
||||||
| student4 | Student4 | student4 | student4@example.com |
|
| student4 | Student4 | student4 | student4@example.com |
|
||||||
|
| student5 | Student5 | student5 | student5@example.com |
|
||||||
And the following "courses" exist:
|
And the following "courses" exist:
|
||||||
| fullname | shortname | category |
|
| fullname | shortname | category |
|
||||||
| Course 1 | C1 | 0 |
|
| Course 1 | C1 | 0 |
|
||||||
|
@ -19,15 +20,18 @@ Feature: Test marking workflow in assignment activity in app
|
||||||
| student2 | C1 | student |
|
| student2 | C1 | student |
|
||||||
| student3 | C1 | student |
|
| student3 | C1 | student |
|
||||||
| student4 | C1 | student |
|
| student4 | C1 | student |
|
||||||
|
| student5 | C1 | student |
|
||||||
And the following "groups" exist:
|
And the following "groups" exist:
|
||||||
| name | course | idnumber |
|
| name | course | idnumber |
|
||||||
| Group 1 | C1 | G1 |
|
| Group 1 | C1 | G1 |
|
||||||
| Group 2 | C1 | G2 |
|
| Group 2 | C1 | G2 |
|
||||||
|
| Group 3 | C1 | G3 |
|
||||||
And the following "group members" exist:
|
And the following "group members" exist:
|
||||||
| user | group |
|
| user | group |
|
||||||
| student1 | G1 |
|
| student1 | G1 |
|
||||||
| student2 | G1 |
|
| student2 | G1 |
|
||||||
| student3 | G2 |
|
| student3 | G2 |
|
||||||
|
| student4 | G3 |
|
||||||
And the following "activities" exist:
|
And the following "activities" exist:
|
||||||
| activity | course | idnumber | name | assignsubmission_onlinetext_enabled | assignfeedback_comments_enabled | markingworkflow | teamsubmission | groupmode | submissiondrafts |
|
| 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 |
|
| 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 |
|
| assign | user | onlinetext |
|
||||||
| assign1 | student1 | Lorem |
|
| assign1 | student1 | Lorem |
|
||||||
| assign1 | student3 | Ipsum |
|
| 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 am on the "Group Assign" "assign activity" page logged in as teacher1
|
||||||
And I follow "View all submissions"
|
And I follow "View all submissions"
|
||||||
And I click on "Grade" "link" in the "Student1" "table_row"
|
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 "Feedback comments" to "Great job! Lol, not really."
|
||||||
And I set the field "Notify student" to "0"
|
And I set the field "Notify student" to "0"
|
||||||
And I press "Save changes"
|
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
|
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
|
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
|
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 "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 "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 "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 "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 "Released" within "Student3" "ion-item" in the app
|
||||||
And I should find "No submission" within "Student4" "ion-item" in the app
|
And I should find "Submitted for grading" 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 "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
|
||||||
|
|
Loading…
Reference in New Issue