From 9b93a0450cbcd0f1133deffcf33add22c8b852d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Fri, 7 Jan 2022 13:34:19 +0100 Subject: [PATCH 1/6] MOBILE-3787 assign: Fix non-null checks --- .../mod/assign/components/index/index.ts | 54 +++++++++++-------- .../components/submission/submission.ts | 8 +-- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/addons/mod/assign/components/index/index.ts b/src/addons/mod/assign/components/index/index.ts index 0aa2a9a8e..84e64cb19 100644 --- a/src/addons/mod/assign/components/index/index.ts +++ b/src/addons/mod/assign/components/index/index.ts @@ -79,8 +79,8 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo submissionStatusDraft = AddonModAssignProvider.SUBMISSION_STATUS_DRAFT; needGrading = AddonModAssignProvider.NEED_GRADING; - protected currentUserId?: number; // Current user ID. - protected currentSite?: CoreSite; // Current user ID. + protected currentUserId!: number; // Current user ID. + protected currentSite!: CoreSite; // Current site. protected syncEventName = AddonModAssignSyncProvider.AUTO_SYNCED; // Observers. @@ -93,6 +93,9 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo @Optional() courseContentsPage?: CoreCourseContentsPage, ) { super('AddonModLessonIndexComponent', content, courseContentsPage); + + this.currentSite = CoreSites.getRequiredCurrentSite(); + this.currentUserId = this.currentSite.getUserId(); } /** @@ -101,9 +104,6 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo async ngOnInit(): Promise { super.ngOnInit(); - this.currentUserId = CoreSites.getCurrentSiteUserId(); - this.currentSite = CoreSites.getCurrentSite(); - // Listen to events. this.savedObserver = CoreEvents.on( AddonModAssignProvider.SUBMISSION_SAVED_EVENT, @@ -139,8 +139,12 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo await this.loadContent(false, true); + if (!this.assign) { + return; + } + try { - await AddonModAssign.logView(this.assign!.id, this.assign!.name); + await AddonModAssign.logView(this.assign.id, this.assign.name); CoreCourse.checkModuleCompletion(this.courseId, this.module.completiondata); } catch { // Ignore errors. Just don't check Module completion. @@ -148,10 +152,10 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo if (this.canViewAllSubmissions) { // User can see all submissions, log grading view. - CoreUtils.ignoreErrors(AddonModAssign.logGradingView(this.assign!.id, this.assign!.name)); + CoreUtils.ignoreErrors(AddonModAssign.logGradingView(this.assign.id, this.assign.name)); } else if (this.canViewOwnSubmission) { // User can only see their own submission, log view the user submission. - CoreUtils.ignoreErrors(AddonModAssign.logSubmissionView(this.assign!.id, this.assign!.name)); + CoreUtils.ignoreErrors(AddonModAssign.logSubmissionView(this.assign.id, this.assign.name)); } } @@ -266,7 +270,11 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo async setGroup(groupId = 0): Promise { this.group = groupId; - const submissionStatus = await AddonModAssign.getSubmissionStatus(this.assign!.id, { + if (!this.assign) { + return; + } + + const submissionStatus = await AddonModAssign.getSubmissionStatus(this.assign.id, { groupId: this.group, cmId: this.module.id, }); @@ -278,10 +286,10 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo return; } - if (this.summary?.warnofungroupedusers === true) { + if (this.summary.warnofungroupedusers === true) { this.summary.warnofungroupedusers = 'ungroupedusers'; } else { - switch (this.summary?.warnofungroupedusers) { + switch (this.summary.warnofungroupedusers) { case AddonModAssignProvider.WARN_GROUPS_REQUIRED: this.summary.warnofungroupedusers = 'ungroupedusers'; break; @@ -386,16 +394,16 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo * @return True if refresh is needed, false otherwise. */ protected isRefreshSyncNeeded(syncEventData: AddonModAssignAutoSyncData): boolean { - if (this.assign && syncEventData.assignId == this.assign.id) { - if (syncEventData.warnings && syncEventData.warnings.length) { - // Show warnings. - CoreDomUtils.showErrorModal(syncEventData.warnings[0]); - } - - return true; + if (!this.assign || syncEventData.assignId != this.assign.id) { + return false; } - return false; + if (syncEventData.warnings && syncEventData.warnings.length) { + // Show warnings. + CoreDomUtils.showErrorModal(syncEventData.warnings[0]); + } + + return true; } /** @@ -403,8 +411,12 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo * * @return Promise resolved when done. */ - protected sync(): Promise { - return AddonModAssignSync.syncAssign(this.assign!.id); + protected async sync(): Promise { + if (!this.assign) { + return; + } + + await AddonModAssignSync.syncAssign(this.assign.id); } /** diff --git a/src/addons/mod/assign/components/submission/submission.ts b/src/addons/mod/assign/components/submission/submission.ts index 5b7b69785..290feb84e 100644 --- a/src/addons/mod/assign/components/submission/submission.ts +++ b/src/addons/mod/assign/components/submission/submission.ts @@ -612,11 +612,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can // If we have data about the grader, get its profile. if (feedback.grade && feedback.grade.grader > 0) { - try { - this.grader = await CoreUser.getProfile(feedback.grade.grader, this.courseId); - } catch { - // Ignore errors. - } + this.grader = await CoreUtils.ignoreErrors(CoreUser.getProfile(feedback.grade.grader, this.courseId)); } else { delete this.grader; } @@ -633,7 +629,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can if (feedback.grade && feedback.grade.grade && !this.grade.grade) { const parsedGrade = parseFloat(feedback.grade.grade); - this.grade!.grade = parsedGrade >= 0 ? parsedGrade : undefined; + this.grade.grade = parsedGrade >= 0 ? parsedGrade : undefined; this.grade.gradebookGrade = CoreUtils.formatFloat(this.grade.grade); this.originalGrades.grade = this.grade.grade; } From 59e1a4fcf549adfa425ab17b09594c947a1e454d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Fri, 7 Jan 2022 16:49:04 +0100 Subject: [PATCH 2/6] MOBILE-3787 assign: Always show submission status --- .../mod/assign/classes/submissions-source.ts | 11 +++-------- .../mod/assign/components/index/index.ts | 2 +- .../pages/submission-list/submission-list.html | 18 ++++++++++-------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/addons/mod/assign/classes/submissions-source.ts b/src/addons/mod/assign/classes/submissions-source.ts index a1c36e70c..4faec578d 100644 --- a/src/addons/mod/assign/classes/submissions-source.ts +++ b/src/addons/mod/assign/classes/submissions-source.ts @@ -211,14 +211,9 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc submission.gradingstatus, ); - // Show submission status if not submitted for grading. - if (submission.statusColor != 'success' || !submission.gradingstatus) { - submission.statusTranslated = Translate.instant( - 'addon.mod_assign.submissionstatus_' + submission.status, - ); - } else { - submission.statusTranslated = ''; - } + submission.statusTranslated = Translate.instant( + 'addon.mod_assign.submissionstatus_' + submission.status, + ); if (notSynced) { submission.gradingStatusTranslationId = 'addon.mod_assign.gradenotsynced'; diff --git a/src/addons/mod/assign/components/index/index.ts b/src/addons/mod/assign/components/index/index.ts index 84e64cb19..72b161007 100644 --- a/src/addons/mod/assign/components/index/index.ts +++ b/src/addons/mod/assign/components/index/index.ts @@ -302,7 +302,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo } } - this.needsGradingAvailable = (submissionStatus.gradingsummary?.submissionsneedgradingcount || 0) > 0; + this.needsGradingAvailable = this.summary.submissionsneedgradingcount > 0; } /** diff --git a/src/addons/mod/assign/pages/submission-list/submission-list.html b/src/addons/mod/assign/pages/submission-list/submission-list.html index 0a6635371..40ad93441 100644 --- a/src/addons/mod/assign/pages/submission-list/submission-list.html +++ b/src/addons/mod/assign/pages/submission-list/submission-list.html @@ -63,14 +63,16 @@ {{ 'addon.mod_assign.defaultteam' | translate }}

- - {{ submission.statusTranslated }} - - - {{ submission.gradingStatusTranslationId | translate }} - +

+ + {{ submission.statusTranslated }} + +

+

+ + {{ submission.gradingStatusTranslationId | translate }} + +

From 03ccd026361315293d0ce2adbee2a760c4967f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 13 Jan 2022 08:54:33 +0100 Subject: [PATCH 3/6] MOBILE-3787 assign: Fix submission and grading status on groups --- .../mod/assign/classes/submissions-source.ts | 108 +++++++++--------- .../mod/assign/services/assign-helper.ts | 77 ++++++------- 2 files changed, 83 insertions(+), 102 deletions(-) diff --git a/src/addons/mod/assign/classes/submissions-source.ts b/src/addons/mod/assign/classes/submissions-source.ts index 4faec578d..fba320993 100644 --- a/src/addons/mod/assign/classes/submissions-source.ts +++ b/src/addons/mod/assign/classes/submissions-source.ts @@ -157,7 +157,7 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc } // Fetch submissions and grades. - const submissions = + let submissions = await AddonModAssignHelper.getSubmissionsUserData( assign, this.submissionsData.submissions, @@ -172,67 +172,61 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc const getNeedGrading = this.SELECTED_STATUS == AddonModAssignProvider.NEED_GRADING; const searchStatus = getNeedGrading ? AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED : this.SELECTED_STATUS; - const promises: Promise[] = []; const showSubmissions: AddonModAssignSubmissionForList[] = []; - submissions.forEach((submission: AddonModAssignSubmissionForList) => { - if (!searchStatus || searchStatus == submission.status) { - promises.push( - CoreUtils.ignoreErrors( - AddonModAssignOffline.getSubmissionGrade(assign.id, submission.userid), - ).then(async (data) => { - if (getNeedGrading) { - // Only show the submissions that need to be graded. - const add = await AddonModAssign.needsSubmissionToBeGraded(submission, assign.id); + if (searchStatus) { + submissions = submissions.filter((submission: AddonModAssignSubmissionForList) => searchStatus == submission.status); + } - if (!add) { - return; - } - } + const promises: Promise[] = submissions.map(async (submission: AddonModAssignSubmissionForList) => { + const gradeData = await CoreUtils.ignoreErrors(AddonModAssignOffline.getSubmissionGrade(assign.id, submission.userid)); + if (getNeedGrading) { + // Only show the submissions that need to be graded. + const add = await AddonModAssign.needsSubmissionToBeGraded(submission, assign.id); - // Load offline grades. - const notSynced = !!data && submission.timemodified < data.timemodified; - - if (submission.gradingstatus == 'graded' && !assign.markingworkflow) { - // Get the last grade of the submission. - const grade = grades - .filter((grade) => grade.userid == submission.userid) - .reduce( - (a, b) => (a && a.timemodified > b.timemodified ? a : b), - undefined, - ); - - if (grade && grade.timemodified < submission.timemodified) { - submission.gradingstatus = AddonModAssignProvider.GRADED_FOLLOWUP_SUBMIT; - } - } - submission.statusColor = AddonModAssign.getSubmissionStatusColor(submission.status); - submission.gradingColor = AddonModAssign.getSubmissionGradingStatusColor( - submission.gradingstatus, - ); - - submission.statusTranslated = Translate.instant( - 'addon.mod_assign.submissionstatus_' + submission.status, - ); - - if (notSynced) { - submission.gradingStatusTranslationId = 'addon.mod_assign.gradenotsynced'; - submission.gradingColor = ''; - } else if (submission.statusColor != 'danger' || submission.gradingColor != 'danger') { - // Show grading status if one of the statuses is not done. - submission.gradingStatusTranslationId = AddonModAssign.getSubmissionGradingStatusTranslationId( - submission.gradingstatus, - ); - } else { - submission.gradingStatusTranslationId = ''; - } - - showSubmissions.push(submission); - - return; - }), - ); + if (!add) { + return; + } } + + // Load offline grades. + const notSynced = !!gradeData && submission.timemodified < gradeData.timemodified; + + if (submission.gradingstatus == 'graded' && !assign.markingworkflow) { + // Get the last grade of the submission. + const grade = grades + .filter((grade) => grade.userid == submission.userid) + .reduce( + (a, b) => (a && a.timemodified > b.timemodified ? a : b), + undefined, + ); + + if (grade && grade.timemodified < submission.timemodified) { + submission.gradingstatus = AddonModAssignProvider.GRADED_FOLLOWUP_SUBMIT; + } + } + submission.statusColor = AddonModAssign.getSubmissionStatusColor(submission.status); + submission.gradingColor = AddonModAssign.getSubmissionGradingStatusColor( + submission.gradingstatus, + ); + + submission.statusTranslated = Translate.instant( + 'addon.mod_assign.submissionstatus_' + submission.status, + ); + + if (notSynced) { + submission.gradingStatusTranslationId = 'addon.mod_assign.gradenotsynced'; + submission.gradingColor = ''; + } else if (submission.statusColor != 'danger' || submission.gradingColor != 'danger') { + // Show grading status if one of the statuses is not done. + submission.gradingStatusTranslationId = AddonModAssign.getSubmissionGradingStatusTranslationId( + submission.gradingstatus, + ); + } else { + submission.gradingStatusTranslationId = ''; + } + + showSubmissions.push(submission); }); await Promise.all(promises); diff --git a/src/addons/mod/assign/services/assign-helper.ts b/src/addons/mod/assign/services/assign-helper.ts index 680bfbdaa..017e9a389 100644 --- a/src/addons/mod/assign/services/assign-helper.ts +++ b/src/addons/mod/assign/services/assign-helper.ts @@ -398,48 +398,34 @@ export class AddonModAssignHelperProvider { groupId?: number, options: CoreSitesCommonWSOptions = {}, ): Promise { - const parts = await this.getParticipants(assign, groupId, options); + const participants = await this.getParticipants(assign, groupId, options); - const blind = assign.blindmarking && !assign.revealidentities; - const result: AddonModAssignSubmissionFormatted[] = []; - const participants: {[id: number]: AddonModAssignParticipant} = CoreUtils.arrayToObject(parts, 'id'); + const blind = !!assign.blindmarking && !assign.revealidentities; + const teamsubmission = !!assign.teamsubmission; - submissions.forEach((submission) => { - submission.submitid = submission.userid && submission.userid > 0 ? submission.userid : submission.blindid; - if (submission.submitid === undefined || submission.submitid <= 0) { - return; + return participants.map((participant) => { + const groupId = participant.groupid ?? + (participant.groups && participant.groups[0] ? participant.groups[0].id : 0); + + const foundSubmission = submissions.find((submission) => { + if (teamsubmission) { + return submission.userid == 0 && submission.groupid == groupId; + } + + const submitId = submission.userid && submission.userid > 0 ? submission.userid : submission.blindid; + + return participant.id == submitId; + }); + + let submission: AddonModAssignSubmissionFormatted | undefined; + if (!foundSubmission) { + // Create submission if none. + submission = this.createEmptySubmission(); + submission.groupid = groupId; + } else { + submission = Object.assign({}, foundSubmission); } - const participant = participants[submission.submitid]; - if (!participant) { - // Avoid permission denied error. Participant not found on list. - return; - } - - delete participants[submission.submitid]; - - if (!blind) { - submission.userfullname = participant.fullname; - submission.userprofileimageurl = participant.profileimageurl; - } - - submission.manyGroups = !!participant.groups && participant.groups.length > 1; - submission.noGroups = !!participant.groups && participant.groups.length == 0; - if (participant.groupname) { - submission.groupid = participant.groupid!; - submission.groupname = participant.groupname; - } - - // Add to the list. - if (submission.userfullname || submission.blindid) { - result.push(submission); - } - }); - - // Create a submission for each participant left in the list (the participants already treated were removed). - CoreUtils.objectToArray(participants).forEach((participant: AddonModAssignParticipant) => { - const submission = this.createEmptySubmission(); - submission.submitid = participant.id; if (!blind) { @@ -453,16 +439,16 @@ export class AddonModAssignHelperProvider { submission.manyGroups = !!participant.groups && participant.groups.length > 1; submission.noGroups = !!participant.groups && participant.groups.length == 0; if (participant.groupname) { - submission.groupid = participant.groupid!; + submission.groupid = participant.groupid; submission.groupname = participant.groupname; } - submission.status = participant.submitted ? AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED : - AddonModAssignProvider.SUBMISSION_STATUS_NEW; - result.push(submission); + submission.status = submission.status ?? (participant.submitted ? AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED : + AddonModAssignProvider.SUBMISSION_STATUS_NEW); + + return submission; + }); - - return result; } /** @@ -714,8 +700,9 @@ export const AddonModAssignHelper = makeSingleton(AddonModAssignHelperProvider); * Assign submission with some calculated data. */ export type AddonModAssignSubmissionFormatted = - Omit & { + Omit & { userid?: number; // Student id. + groupid?: number; // Group id. blindid?: number; // Calculated in the app. Blindid of the user that did the submission. submitid?: number; // Calculated in the app. Userid or blindid of the user that did the submission. userfullname?: string; // Calculated in the app. Full name of the user that did the submission. From 7cdafca794eb8bf1741bf1d9989ad9a13adba647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 13 Jan 2022 10:44:47 +0100 Subject: [PATCH 4/6] MOBILE-3787 assign: Add enums to different states --- .../mod/assign/classes/submissions-source.ts | 36 ++++-- .../mod/assign/components/index/index.ts | 9 +- .../components/submission/submission.ts | 47 +++---- .../submission-list/submission-list.page.ts | 10 +- .../submission-review/submission-review.ts | 6 +- .../mod/assign/services/assign-helper.ts | 9 +- src/addons/mod/assign/services/assign.ts | 119 +++++++++++------- src/core/singletons/colors.ts | 12 ++ 8 files changed, 152 insertions(+), 96 deletions(-) diff --git a/src/addons/mod/assign/classes/submissions-source.ts b/src/addons/mod/assign/classes/submissions-source.ts index fba320993..4e3ee9953 100644 --- a/src/addons/mod/assign/classes/submissions-source.ts +++ b/src/addons/mod/assign/classes/submissions-source.ts @@ -18,13 +18,14 @@ import { CoreGroupInfo, CoreGroups } from '@services/groups'; import { CoreSites } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; +import { CoreIonicColorNames } from '@singletons/colors'; import { CoreEvents } from '@singletons/events'; import { AddonModAssign, AddonModAssignAssign, - AddonModAssignGrade, - AddonModAssignProvider, + AddonModAssignGradingStates, AddonModAssignSubmission, + AddonModAssignSubmissionStatusValues, } from '../services/assign'; import { AddonModAssignHelper, AddonModAssignSubmissionFormatted } from '../services/assign-helper'; import { AddonModAssignOffline } from '../services/assign-offline'; @@ -38,15 +39,15 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc /** * @inheritdoc */ - static getSourceId(courseId: number, moduleId: number, selectedStatus?: string): string { - selectedStatus = selectedStatus ?? '__empty__'; + static getSourceId(courseId: number, moduleId: number, selectedStatus?: AddonModAssignListFilterName): string { + const statusId = selectedStatus ?? '__empty__'; - return `submissions-${courseId}-${moduleId}-${selectedStatus}`; + return `submissions-${courseId}-${moduleId}-${statusId}`; } readonly COURSE_ID: number; readonly MODULE_ID: number; - readonly SELECTED_STATUS: string | undefined; + readonly SELECTED_STATUS: AddonModAssignListFilterName | undefined; assign?: AddonModAssignAssign; groupId = 0; @@ -62,7 +63,7 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc canviewsubmissions: false, }; - constructor(courseId: number, moduleId: number, selectedStatus?: string) { + constructor(courseId: number, moduleId: number, selectedStatus?: AddonModAssignListFilterName) { super(); this.COURSE_ID = courseId; @@ -169,8 +170,8 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc : []; // Filter the submissions to get only the ones with the right status and add some extra data. - const getNeedGrading = this.SELECTED_STATUS == AddonModAssignProvider.NEED_GRADING; - const searchStatus = getNeedGrading ? AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED : this.SELECTED_STATUS; + const getNeedGrading = this.SELECTED_STATUS == AddonModAssignListFilterName.NEED_GRADING; + const searchStatus = getNeedGrading ? AddonModAssignSubmissionStatusValues.SUBMITTED : this.SELECTED_STATUS; const showSubmissions: AddonModAssignSubmissionForList[] = []; @@ -192,7 +193,7 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc // Load offline grades. const notSynced = !!gradeData && submission.timemodified < gradeData.timemodified; - if (submission.gradingstatus == 'graded' && !assign.markingworkflow) { + if (submission.gradingstatus == AddonModAssignGradingStates.GRADED && !assign.markingworkflow) { // Get the last grade of the submission. const grade = grades .filter((grade) => grade.userid == submission.userid) @@ -202,7 +203,7 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc ); if (grade && grade.timemodified < submission.timemodified) { - submission.gradingstatus = AddonModAssignProvider.GRADED_FOLLOWUP_SUBMIT; + submission.gradingstatus = AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT; } } submission.statusColor = AddonModAssign.getSubmissionStatusColor(submission.status); @@ -217,7 +218,8 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc if (notSynced) { submission.gradingStatusTranslationId = 'addon.mod_assign.gradenotsynced'; submission.gradingColor = ''; - } else if (submission.statusColor != 'danger' || submission.gradingColor != 'danger') { + } else if (submission.statusColor != CoreIonicColorNames.DANGER || + submission.gradingColor != CoreIonicColorNames.DANGER) { // Show grading status if one of the statuses is not done. submission.gradingStatusTranslationId = AddonModAssign.getSubmissionGradingStatusTranslationId( submission.gradingstatus, @@ -245,3 +247,13 @@ export type AddonModAssignSubmissionForList = AddonModAssignSubmissionFormatted statusTranslated?: string; // Calculated in the app. Translated text of the submission status. gradingStatusTranslationId?: string; // Calculated in the app. Key of the text of the submission grading status. }; + +/** + * List filter by status name. + */ +export enum AddonModAssignListFilterName { + ALL = '', + NEED_GRADING = 'needgrading', + DRAFT = 'draft', + SUBMITTED = 'submitted', +}; diff --git a/src/addons/mod/assign/components/index/index.ts b/src/addons/mod/assign/components/index/index.ts index 72b161007..28827e331 100644 --- a/src/addons/mod/assign/components/index/index.ts +++ b/src/addons/mod/assign/components/index/index.ts @@ -28,6 +28,7 @@ import { CoreTimeUtils } from '@services/utils/time'; import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; +import { AddonModAssignListFilterName } from '../../classes/submissions-source'; import { AddonModAssign, AddonModAssignAssign, @@ -75,9 +76,9 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo }; // Status. - submissionStatusSubmitted = AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED; - submissionStatusDraft = AddonModAssignProvider.SUBMISSION_STATUS_DRAFT; - needGrading = AddonModAssignProvider.NEED_GRADING; + submissionStatusSubmitted = AddonModAssignListFilterName.SUBMITTED; + submissionStatusDraft = AddonModAssignListFilterName.DRAFT; + needGrading = AddonModAssignListFilterName.NEED_GRADING; protected currentUserId!: number; // Current user ID. protected currentSite!: CoreSite; // Current site. @@ -311,7 +312,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo * @param status Status to see. * @param hasSubmissions If the status has any submission. */ - goToSubmissionList(status?: string, hasSubmissions = false): void { + goToSubmissionList(status?: AddonModAssignListFilterName, hasSubmissions = false): void { if (status !== undefined && !hasSubmissions) { return; } diff --git a/src/addons/mod/assign/components/submission/submission.ts b/src/addons/mod/assign/components/submission/submission.ts index 290feb84e..da2154f88 100644 --- a/src/addons/mod/assign/components/submission/submission.ts +++ b/src/addons/mod/assign/components/submission/submission.ts @@ -25,6 +25,9 @@ import { AddonModAssign, AddonModAssignGetSubmissionStatusWSResponse, AddonModAssignSavePluginData, + AddonModAssignGradingStates, + AddonModAssignSubmissionStatusValues, + AddonModAssignAttemptReopenMethodValues, } from '../../services/assign'; import { AddonModAssignAutoSyncData, @@ -125,9 +128,9 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can showDates = false; // Whether to show some dates. // Some constants. - statusNew = AddonModAssignProvider.SUBMISSION_STATUS_NEW; - statusReopened = AddonModAssignProvider.SUBMISSION_STATUS_REOPENED; - attemptReopenMethodNone = AddonModAssignProvider.ATTEMPT_REOPEN_METHOD_NONE; + statusNew = AddonModAssignSubmissionStatusValues.NEW; + statusReopened = AddonModAssignSubmissionStatusValues.REOPENED; + attemptReopenMethodNone = AddonModAssignAttemptReopenMethodValues.NONE; unlimitedAttempts = AddonModAssignProvider.UNLIMITED_ATTEMPTS; protected siteId: string; // Current site ID. @@ -214,7 +217,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can } // Not submitted. - if (!this.userSubmission || this.userSubmission.status != AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED) { + if (!this.userSubmission || this.userSubmission.status != AddonModAssignSubmissionStatusValues.SUBMITTED) { if (response.lastattempt?.submissionsenabled || response.gradingsummary?.submissionsenabled) { this.timeRemaining = Translate.instant( @@ -651,7 +654,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can // Treat the grade info. await this.treatGradeInfo(); - const isManual = this.assign!.attemptreopenmethod == AddonModAssignProvider.ATTEMPT_REOPEN_METHOD_MANUAL; + const isManual = this.assign!.attemptreopenmethod == AddonModAssignAttemptReopenMethodValues.MANUAL; const isUnlimited = this.assign!.maxattempts == AddonModAssignProvider.UNLIMITED_ATTEMPTS; const isLessThanMaxAttempts = !!this.userSubmission && (this.userSubmission.attemptnumber < (this.assign!.maxattempts - 1)); @@ -668,7 +671,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can if (this.lastAttempt?.gradingstatus == 'graded' && !this.assign!.markingworkflow && this.userSubmission && feedback) { if (feedback.gradeddate < this.userSubmission.timemodified) { - this.lastAttempt.gradingstatus = AddonModAssignProvider.GRADED_FOLLOWUP_SUBMIT; + this.lastAttempt.gradingstatus = AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT; // Get grading text and color. this.gradingStatusTranslationId = AddonModAssign.getSubmissionGradingStatusTranslationId( @@ -749,43 +752,43 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can * @param status Submission status. */ protected setStatusNameAndClass(status: AddonModAssignGetSubmissionStatusWSResponse): void { - const translateService = Translate.instance; - if (this.hasOffline || this.submittedOffline) { // Offline data. - this.statusTranslated = translateService.instant('core.notsent'); + this.statusTranslated = Translate.instant('core.notsent'); this.statusColor = 'warning'; } else if (!this.assign!.teamsubmission) { // Single submission. if (this.userSubmission && this.userSubmission.status != this.statusNew) { - this.statusTranslated = translateService.instant('addon.mod_assign.submissionstatus_' + this.userSubmission.status); + this.statusTranslated = Translate.instant('addon.mod_assign.submissionstatus_' + this.userSubmission.status); this.statusColor = AddonModAssign.getSubmissionStatusColor(this.userSubmission.status); } else { if (!status.lastattempt?.submissionsenabled) { - this.statusTranslated = translateService.instant('addon.mod_assign.noonlinesubmissions'); - this.statusColor = AddonModAssign.getSubmissionStatusColor('noonlinesubmissions'); + this.statusTranslated = Translate.instant('addon.mod_assign.noonlinesubmissions'); + this.statusColor = + AddonModAssign.getSubmissionStatusColor(AddonModAssignSubmissionStatusValues.NO_ONLINE_SUBMISSIONS); } else { - this.statusTranslated = translateService.instant('addon.mod_assign.noattempt'); - this.statusColor = AddonModAssign.getSubmissionStatusColor('noattempt'); + this.statusTranslated = Translate.instant('addon.mod_assign.noattempt'); + this.statusColor = AddonModAssign.getSubmissionStatusColor(AddonModAssignSubmissionStatusValues.NO_ATTEMPT); } } } else { // Team submission. if (!status.lastattempt?.submissiongroup && this.assign!.preventsubmissionnotingroup) { - this.statusTranslated = translateService.instant('addon.mod_assign.nosubmission'); - this.statusColor = AddonModAssign.getSubmissionStatusColor('nosubmission'); + this.statusTranslated = Translate.instant('addon.mod_assign.nosubmission'); + this.statusColor = AddonModAssign.getSubmissionStatusColor(AddonModAssignSubmissionStatusValues.NO_SUBMISSION); } else if (this.userSubmission && this.userSubmission.status != this.statusNew) { - this.statusTranslated = translateService.instant('addon.mod_assign.submissionstatus_' + this.userSubmission.status); + this.statusTranslated = Translate.instant('addon.mod_assign.submissionstatus_' + this.userSubmission.status); this.statusColor = AddonModAssign.getSubmissionStatusColor(this.userSubmission.status); } else { if (!status.lastattempt?.submissionsenabled) { - this.statusTranslated = translateService.instant('addon.mod_assign.noonlinesubmissions'); - this.statusColor = AddonModAssign.getSubmissionStatusColor('noonlinesubmissions'); + this.statusTranslated = Translate.instant('addon.mod_assign.noonlinesubmissions'); + this.statusColor = + AddonModAssign.getSubmissionStatusColor(AddonModAssignSubmissionStatusValues.NO_ONLINE_SUBMISSIONS); } else { - this.statusTranslated = translateService.instant('addon.mod_assign.nosubmission'); - this.statusColor = AddonModAssign.getSubmissionStatusColor('nosubmission'); + this.statusTranslated = Translate.instant('addon.mod_assign.nosubmission'); + this.statusColor = AddonModAssign.getSubmissionStatusColor(AddonModAssignSubmissionStatusValues.NO_SUBMISSION); } } } @@ -1180,7 +1183,7 @@ type AddonModAssignSubmissionGrade = { grade?: number | string; gradebookGrade?: string; modified?: number; - gradingStatus?: string; + gradingStatus?: AddonModAssignGradingStates; addAttempt: boolean; applyToAll: boolean; scale?: CoreMenuItem[]; diff --git a/src/addons/mod/assign/pages/submission-list/submission-list.page.ts b/src/addons/mod/assign/pages/submission-list/submission-list.page.ts index e0b09e3b2..9ac31e50e 100644 --- a/src/addons/mod/assign/pages/submission-list/submission-list.page.ts +++ b/src/addons/mod/assign/pages/submission-list/submission-list.page.ts @@ -23,7 +23,11 @@ import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; import { Translate } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; -import { AddonModAssignSubmissionForList, AddonModAssignSubmissionsSource } from '../../classes/submissions-source'; +import { + AddonModAssignListFilterName, + AddonModAssignSubmissionForList, + AddonModAssignSubmissionsSource, +} from '../../classes/submissions-source'; import { AddonModAssignAssign, AddonModAssignProvider } from '../../services/assign'; import { AddonModAssignSyncProvider, @@ -85,7 +89,7 @@ export class AddonModAssignSubmissionListPage implements AfterViewInit, OnDestro const moduleId = CoreNavigator.getRequiredRouteNumberParam('cmId'); const courseId = CoreNavigator.getRequiredRouteNumberParam('courseId'); const groupId = CoreNavigator.getRouteNumberParam('groupId') || 0; - const selectedStatus = CoreNavigator.getRouteParam('status'); + const selectedStatus = CoreNavigator.getRouteParam('status'); const submissionsSource = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource( AddonModAssignSubmissionsSource, [courseId, moduleId, selectedStatus], @@ -143,7 +147,7 @@ export class AddonModAssignSubmissionListPage implements AfterViewInit, OnDestro this.title = Translate.instant( selectedStatus ? ( - selectedStatus === AddonModAssignProvider.NEED_GRADING + selectedStatus === AddonModAssignListFilterName.NEED_GRADING ? 'addon.mod_assign.numberofsubmissionsneedgrading' : `addon.mod_assign.submissionstatus_${selectedStatus}` ) diff --git a/src/addons/mod/assign/pages/submission-review/submission-review.ts b/src/addons/mod/assign/pages/submission-review/submission-review.ts index a51cf4bc4..f722bdef6 100644 --- a/src/addons/mod/assign/pages/submission-review/submission-review.ts +++ b/src/addons/mod/assign/pages/submission-review/submission-review.ts @@ -22,7 +22,7 @@ import { IonRefresher } from '@ionic/angular'; import { CoreNavigator } from '@services/navigator'; import { CoreScreen } from '@services/screen'; import { CoreDomUtils } from '@services/utils/dom'; -import { AddonModAssignSubmissionsSource } from '../../classes/submissions-source'; +import { AddonModAssignListFilterName, AddonModAssignSubmissionsSource } from '../../classes/submissions-source'; import { AddonModAssignSubmissionComponent } from '../../components/submission/submission'; import { AddonModAssign, AddonModAssignAssign } from '../../services/assign'; @@ -53,7 +53,7 @@ export class AddonModAssignSubmissionReviewPage implements OnInit, OnDestroy, Ca constructor(protected route: ActivatedRoute) { } /** - * Component being initialized. + * @inheritdoc */ ngOnInit(): void { this.route.queryParams.subscribe((params) => { @@ -63,7 +63,7 @@ export class AddonModAssignSubmissionReviewPage implements OnInit, OnDestroy, Ca this.submitId = CoreNavigator.getRouteNumberParam('submitId') || 0; this.blindId = CoreNavigator.getRouteNumberParam('blindId', { params }); const groupId = CoreNavigator.getRequiredRouteNumberParam('groupId'); - const selectedStatus = CoreNavigator.getRouteParam('selectedStatus'); + const selectedStatus = CoreNavigator.getRouteParam('selectedStatus'); const submissionsSource = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource( AddonModAssignSubmissionsSource, [this.courseId, this.moduleId, selectedStatus], diff --git a/src/addons/mod/assign/services/assign-helper.ts b/src/addons/mod/assign/services/assign-helper.ts index 017e9a389..25653194c 100644 --- a/src/addons/mod/assign/services/assign-helper.ts +++ b/src/addons/mod/assign/services/assign-helper.ts @@ -25,6 +25,7 @@ import { AddonModAssign, AddonModAssignPlugin, AddonModAssignSavePluginData, + AddonModAssignSubmissionStatusValues, } from './assign'; import { AddonModAssignOffline } from './assign-offline'; import { CoreUtils } from '@services/utils/utils'; @@ -55,8 +56,8 @@ export class AddonModAssignHelperProvider { return false; } - if (submission.status == AddonModAssignProvider.SUBMISSION_STATUS_NEW || - submission.status == AddonModAssignProvider.SUBMISSION_STATUS_REOPENED) { + if (submission.status == AddonModAssignSubmissionStatusValues.NEW || + submission.status == AddonModAssignSubmissionStatusValues.REOPENED) { // It's a new submission, allow creating it in offline. return true; } @@ -443,8 +444,8 @@ export class AddonModAssignHelperProvider { submission.groupname = participant.groupname; } - submission.status = submission.status ?? (participant.submitted ? AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED : - AddonModAssignProvider.SUBMISSION_STATUS_NEW); + submission.status = submission.status ?? (participant.submitted ? AddonModAssignSubmissionStatusValues.SUBMITTED : + AddonModAssignSubmissionStatusValues.NEW); return submission; diff --git a/src/addons/mod/assign/services/assign.ts b/src/addons/mod/assign/services/assign.ts index b0b198c8b..4a9623ddd 100644 --- a/src/addons/mod/assign/services/assign.ts +++ b/src/addons/mod/assign/services/assign.ts @@ -34,6 +34,7 @@ import { CoreWSError } from '@classes/errors/wserror'; import { AddonModAssignAutoSyncData, AddonModAssignManualSyncData, AddonModAssignSyncProvider } from './assign-sync'; import { CoreFormFields } from '@singletons/form'; import { CoreFileHelper } from '@services/file-helper'; +import { CoreIonicColorNames } from '@singletons/colors'; const ROOT_CACHE_KEY = 'mmaModAssign:'; @@ -64,23 +65,6 @@ export class AddonModAssignProvider { static readonly SUBMISSION_COMPONENT = 'mmaModAssignSubmission'; static readonly UNLIMITED_ATTEMPTS = -1; - // Submission status. - static readonly SUBMISSION_STATUS_NEW = 'new'; - static readonly SUBMISSION_STATUS_REOPENED = 'reopened'; - static readonly SUBMISSION_STATUS_DRAFT = 'draft'; - static readonly SUBMISSION_STATUS_SUBMITTED = 'submitted'; - - // "Re-open" methods (to retry the assign). - static readonly ATTEMPT_REOPEN_METHOD_NONE = 'none'; - static readonly ATTEMPT_REOPEN_METHOD_MANUAL = 'manual'; - - // Grading status. - static readonly GRADING_STATUS_GRADED = 'graded'; - static readonly GRADING_STATUS_NOT_GRADED = 'notgraded'; - static readonly MARKING_WORKFLOW_STATE_RELEASED = 'released'; - static readonly NEED_GRADING = 'needgrading'; - static readonly GRADED_FOLLOWUP_SUBMIT = 'gradedfollowupsubmit'; - // Group submissions warnings. static readonly WARN_GROUPS_REQUIRED = 'warnrequired'; static readonly WARN_GROUPS_OPTIONAL = 'warnoptional'; @@ -108,17 +92,17 @@ export class AddonModAssignProvider { const teamSubmission = submissionStatus.lastattempt?.teamsubmission; if (teamSubmission) { - if (teamSubmission.status === AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED) { + if (teamSubmission.status === AddonModAssignSubmissionStatusValues.SUBMITTED) { // The assignment submission has been completed. return false; - } else if (userSubmission && userSubmission.status === AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED) { + } else if (userSubmission && userSubmission.status === AddonModAssignSubmissionStatusValues.SUBMITTED) { // The user has already clicked the submit button on the team submission. return false; } else if (assign.preventsubmissionnotingroup && !submissionStatus.lastattempt?.submissiongroup) { return false; } } else if (userSubmission) { - if (userSubmission.status === AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED) { + if (userSubmission.status === AddonModAssignSubmissionStatusValues.SUBMITTED) { // The assignment submission has been completed. return false; } @@ -347,17 +331,17 @@ export class AddonModAssignProvider { * @param status Grading status name * @return The color name. */ - getSubmissionGradingStatusColor(status?: string): string { + getSubmissionGradingStatusColor(status?: AddonModAssignGradingStates): CoreIonicColorNames { if (!status) { - return ''; + return CoreIonicColorNames.NONE; } - if (status == AddonModAssignProvider.GRADING_STATUS_GRADED || - status == AddonModAssignProvider.MARKING_WORKFLOW_STATE_RELEASED) { - return 'success'; + if (status == AddonModAssignGradingStates.GRADED + || status == AddonModAssignGradingStates.MARKING_WORKFLOW_STATE_RELEASED) { + return CoreIonicColorNames.SUCCESS; } - return 'danger'; + return CoreIonicColorNames.DANGER; } /** @@ -366,13 +350,14 @@ export class AddonModAssignProvider { * @param status Grading Status name * @return The status translation identifier. */ - getSubmissionGradingStatusTranslationId(status?: string): string | undefined { + getSubmissionGradingStatusTranslationId(status?: AddonModAssignGradingStates): string | undefined { if (!status) { return; } - if (status == AddonModAssignProvider.GRADING_STATUS_GRADED || status == AddonModAssignProvider.GRADING_STATUS_NOT_GRADED - || status == AddonModAssignProvider.GRADED_FOLLOWUP_SUBMIT) { + if (status == AddonModAssignGradingStates.GRADED + || status == AddonModAssignGradingStates.NOT_GRADED + || status == AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT) { return 'addon.mod_assign.' + status; } @@ -604,20 +589,20 @@ export class AddonModAssignProvider { * @param status Status name * @return The color name. */ - getSubmissionStatusColor(status: string): string { + getSubmissionStatusColor(status: AddonModAssignSubmissionStatusValues): CoreIonicColorNames { switch (status) { - case 'submitted': - return 'success'; - case 'draft': - return 'info'; - case 'new': - case 'noattempt': - case 'noonlinesubmissions': - case 'nosubmission': - case 'gradedfollowupsubmit': - return 'danger'; + case AddonModAssignSubmissionStatusValues.SUBMITTED: + return CoreIonicColorNames.SUCCESS; + case AddonModAssignSubmissionStatusValues.DRAFT: + return CoreIonicColorNames.INFO; + case AddonModAssignSubmissionStatusValues.NEW: + case AddonModAssignSubmissionStatusValues.NO_ATTEMPT: + case AddonModAssignSubmissionStatusValues.NO_ONLINE_SUBMISSIONS: + case AddonModAssignSubmissionStatusValues.NO_SUBMISSION: + case AddonModAssignSubmissionStatusValues.GRADED_FOLLOWUP_SUBMIT: + return CoreIonicColorNames.DANGER; default: - return 'light'; + return CoreIonicColorNames.LIGHT; } } @@ -878,7 +863,7 @@ export class AddonModAssignProvider { } if (submission) { - if (assign.submissiondrafts && submission.status == AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED) { + if (assign.submissiondrafts && submission.status == AddonModAssignSubmissionStatusValues.SUBMITTED) { // Drafts are tracked and the student has submitted the assignment. return false; } @@ -975,8 +960,8 @@ export class AddonModAssignProvider { return true; } - if (submission.gradingstatus != AddonModAssignProvider.GRADING_STATUS_GRADED && - submission.gradingstatus != AddonModAssignProvider.MARKING_WORKFLOW_STATE_RELEASED) { + if (submission.gradingstatus != AddonModAssignGradingStates.GRADED && + submission.gradingstatus != AddonModAssignGradingStates.MARKING_WORKFLOW_STATE_RELEASED) { // Not graded. return true; } @@ -1349,7 +1334,7 @@ export type AddonModAssignAssign = { blindmarking: number; // If enabled, hide identities until reveal identities actioned. hidegrader?: number; // @since 3.7. If enabled, hide grader to student. revealidentities: number; // Show identities for a blind marking assignment. - attemptreopenmethod: string; // Method used to control opening new attempts. + attemptreopenmethod: AddonModAssignAttemptReopenMethodValues; // Method used to control opening new attempts. maxattempts: number; // Maximum number of attempts allowed. markingworkflow: number; // Enable marking workflow. markingallocation: number; // Enable marking allocation. @@ -1400,12 +1385,12 @@ export type AddonModAssignSubmission = { attemptnumber: number; // Attempt number. timecreated: number; // Submission creation time. timemodified: number; // Submission last modified time. - status: string; // Submission status. + status: AddonModAssignSubmissionStatusValues; // Submission status. groupid: number; // Group id. assignment?: number; // Assignment id. latest?: number; // Latest attempt. plugins?: AddonModAssignPlugin[]; // Plugins. - gradingstatus?: string; // Grading status. + gradingstatus?: AddonModAssignGradingStates; // Grading status. }; /** @@ -1454,7 +1439,7 @@ export type AddonModAssignSubmissionAttempt = { cansubmit: boolean; // Whether the user can submit. extensionduedate: number; // Extension due date. blindmarking: boolean; // Whether blind marking is enabled. - gradingstatus: string; // Grading status. + gradingstatus: AddonModAssignGradingStates; // Grading status. usergroups: number[]; // User groups in the course. }; @@ -1749,3 +1734,41 @@ export type AddonModAssignSubmissionSavedEventData = AddonModAssignSubmittedForG * Data sent by GRADED_EVENT event. */ export type AddonModAssignGradedEventData = AddonModAssignSubmittedForGradingEventData; + +/** + * Submission status. + * Constants on LMS starting with ASSIGN_SUBMISSION_STATUS_ + */ +export enum AddonModAssignSubmissionStatusValues { + SUBMITTED = 'submitted', + DRAFT = 'draft', + NEW = 'new', + REOPENED = 'reopened', + // Added by App Statuses. + NO_ATTEMPT = 'noattempt', + NO_ONLINE_SUBMISSIONS = 'noonlinesubmissions', + NO_SUBMISSION = 'nosubmission', + GRADED_FOLLOWUP_SUBMIT = 'gradedfollowupsubmit', +}; + +/** + * Grading status. + * Constants on LMS starting with ASSIGN_GRADING_STATUS_ + */ +export enum AddonModAssignGradingStates { + GRADED = 'graded', + NOT_GRADED = 'notgraded', + // Added by App Statuses. + MARKING_WORKFLOW_STATE_RELEASED = 'released', // with ASSIGN_MARKING_WORKFLOW_STATE_RELEASED + GRADED_FOLLOWUP_SUBMIT = 'gradedfollowupsubmit', +}; + +/** + * Reopen attempt methods. + * Constants on LMS starting with ASSIGN_ATTEMPT_REOPEN_METHOD_ + */ +export enum AddonModAssignAttemptReopenMethodValues { + NONE = 'none', + MANUAL = 'manual', + UNTILPASS = 'untilpass', +}; diff --git a/src/core/singletons/colors.ts b/src/core/singletons/colors.ts index 97a2eac81..5a5eeb0c9 100644 --- a/src/core/singletons/colors.ts +++ b/src/core/singletons/colors.ts @@ -21,6 +21,18 @@ interface ColorComponents { blue: number; // Blue component of an RGB color [0-255]. } +/** + * Ionic color names. + */ +export enum CoreIonicColorNames { + SUCCESS = 'success', + INFO = 'info', + DANGER = 'danger', + DARK = 'dark', + LIGHT = 'light', + NONE = '', +}; + /** * Singleton with helper functions for colors. */ From c5ef18183b7cfd894b1921339ac279bbaf1b5660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 13 Jan 2022 10:57:36 +0100 Subject: [PATCH 5/6] MOBILE-3787 assign: Improve submission list filtering --- .../mod/assign/classes/submissions-source.ts | 100 +++++++++--------- src/addons/mod/assign/services/assign.ts | 4 + 2 files changed, 55 insertions(+), 49 deletions(-) diff --git a/src/addons/mod/assign/classes/submissions-source.ts b/src/addons/mod/assign/classes/submissions-source.ts index 4e3ee9953..9fd25f21d 100644 --- a/src/addons/mod/assign/classes/submissions-source.ts +++ b/src/addons/mod/assign/classes/submissions-source.ts @@ -170,68 +170,69 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc : []; // Filter the submissions to get only the ones with the right status and add some extra data. - const getNeedGrading = this.SELECTED_STATUS == AddonModAssignListFilterName.NEED_GRADING; - const searchStatus = getNeedGrading ? AddonModAssignSubmissionStatusValues.SUBMITTED : this.SELECTED_STATUS; + if (this.SELECTED_STATUS == AddonModAssignListFilterName.NEED_GRADING) { + const promises: Promise[] = submissions.map(async (submission: AddonModAssignSubmissionForList) => { + // Only show the submissions that need to be graded. + submission.needsGrading = await AddonModAssign.needsSubmissionToBeGraded(submission, assign.id); + }); - const showSubmissions: AddonModAssignSubmissionForList[] = []; + await Promise.all(promises); - if (searchStatus) { - submissions = submissions.filter((submission: AddonModAssignSubmissionForList) => searchStatus == submission.status); + submissions = submissions.filter((submission: AddonModAssignSubmissionForList) => submission.needsGrading); + } else if (this.SELECTED_STATUS) { + const searchStatus = this.SELECTED_STATUS == AddonModAssignListFilterName.DRAFT + ? AddonModAssignSubmissionStatusValues.DRAFT + : AddonModAssignSubmissionStatusValues.SUBMITTED; + + submissions = submissions.filter((submission: AddonModAssignSubmissionForList) => submission.status == searchStatus); } - const promises: Promise[] = submissions.map(async (submission: AddonModAssignSubmissionForList) => { - const gradeData = await CoreUtils.ignoreErrors(AddonModAssignOffline.getSubmissionGrade(assign.id, submission.userid)); - if (getNeedGrading) { - // Only show the submissions that need to be graded. - const add = await AddonModAssign.needsSubmissionToBeGraded(submission, assign.id); + const showSubmissions: AddonModAssignSubmissionForList[] = await Promise.all( + submissions.map(async (submission: AddonModAssignSubmissionForList) => { + const gradeData = + await CoreUtils.ignoreErrors(AddonModAssignOffline.getSubmissionGrade(assign.id, submission.userid)); - if (!add) { - return; - } - } + // Load offline grades. + const notSynced = !!gradeData && submission.timemodified < gradeData.timemodified; - // Load offline grades. - const notSynced = !!gradeData && submission.timemodified < gradeData.timemodified; - - if (submission.gradingstatus == AddonModAssignGradingStates.GRADED && !assign.markingworkflow) { - // Get the last grade of the submission. - const grade = grades - .filter((grade) => grade.userid == submission.userid) - .reduce( - (a, b) => (a && a.timemodified > b.timemodified ? a : b), + if (submission.gradingstatus == AddonModAssignGradingStates.GRADED && !assign.markingworkflow) { + // Get the last grade of the submission. + const grade = grades + .filter((grade) => grade.userid == submission.userid) + .reduce( + (a, b) => (a && a.timemodified > b.timemodified ? a : b), undefined, - ); + ); - if (grade && grade.timemodified < submission.timemodified) { - submission.gradingstatus = AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT; + if (grade && grade.timemodified < submission.timemodified) { + submission.gradingstatus = AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT; + } } - } - submission.statusColor = AddonModAssign.getSubmissionStatusColor(submission.status); - submission.gradingColor = AddonModAssign.getSubmissionGradingStatusColor( - submission.gradingstatus, - ); - - submission.statusTranslated = Translate.instant( - 'addon.mod_assign.submissionstatus_' + submission.status, - ); - - if (notSynced) { - submission.gradingStatusTranslationId = 'addon.mod_assign.gradenotsynced'; - submission.gradingColor = ''; - } else if (submission.statusColor != CoreIonicColorNames.DANGER || - submission.gradingColor != CoreIonicColorNames.DANGER) { - // Show grading status if one of the statuses is not done. - submission.gradingStatusTranslationId = AddonModAssign.getSubmissionGradingStatusTranslationId( + submission.statusColor = AddonModAssign.getSubmissionStatusColor(submission.status); + submission.gradingColor = AddonModAssign.getSubmissionGradingStatusColor( submission.gradingstatus, ); - } else { - submission.gradingStatusTranslationId = ''; - } - showSubmissions.push(submission); - }); + submission.statusTranslated = Translate.instant( + 'addon.mod_assign.submissionstatus_' + submission.status, + ); - await Promise.all(promises); + if (notSynced) { + submission.gradingStatusTranslationId = 'addon.mod_assign.gradenotsynced'; + submission.gradingColor = ''; + } else if (submission.statusColor != CoreIonicColorNames.DANGER || + submission.gradingColor != CoreIonicColorNames.DANGER) { + // Show grading status if one of the statuses is not done. + submission.gradingStatusTranslationId = AddonModAssign.getSubmissionGradingStatusTranslationId( + submission.gradingstatus, + ); + } else { + submission.gradingStatusTranslationId = ''; + } + + return submission; + }), + ); return { items: showSubmissions }; } @@ -246,6 +247,7 @@ export type AddonModAssignSubmissionForList = AddonModAssignSubmissionFormatted gradingColor?: string; // Calculated in the app. Color of the submission grading status. statusTranslated?: string; // Calculated in the app. Translated text of the submission status. gradingStatusTranslationId?: string; // Calculated in the app. Key of the text of the submission grading status. + needsGrading?: boolean; // Calculated in the app. If submission and grading status means that it needs grading. }; /** diff --git a/src/addons/mod/assign/services/assign.ts b/src/addons/mod/assign/services/assign.ts index 4a9623ddd..643e4647c 100644 --- a/src/addons/mod/assign/services/assign.ts +++ b/src/addons/mod/assign/services/assign.ts @@ -955,6 +955,10 @@ export class AddonModAssignProvider { * @return Promise resolved with boolean: whether it needs to be graded or not. */ async needsSubmissionToBeGraded(submission: AddonModAssignSubmissionFormatted, assignId: number): Promise { + if (submission.status != AddonModAssignSubmissionStatusValues.SUBMITTED) { + return false; + } + if (!submission.gradingstatus) { // This should not happen, but it's better to show rather than not showing any of the submissions. return true; From 4fc3c8b0d0e6471e09da0bcf97172ae8a2acc96a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 13 Jan 2022 12:23:03 +0100 Subject: [PATCH 6/6] MOBILE-3787 assign: Apply grading status when grades are found --- .../mod/assign/classes/submissions-source.ts | 23 ++++++++++--------- .../mod/assign/services/assign-helper.ts | 15 ++++++++---- src/core/components/loading/loading.scss | 1 - 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/addons/mod/assign/classes/submissions-source.ts b/src/addons/mod/assign/classes/submissions-source.ts index 9fd25f21d..8a5ef3441 100644 --- a/src/addons/mod/assign/classes/submissions-source.ts +++ b/src/addons/mod/assign/classes/submissions-source.ts @@ -164,11 +164,14 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc this.submissionsData.submissions, this.groupId, ); + // Get assignment grades only if workflow is not enabled to check grading date. - const grades = !assign.markingworkflow + let grades = !assign.markingworkflow ? await AddonModAssign.getAssignmentGrades(assign.id, { cmId: assign.cmid }) : []; + // Remove grades (not graded) and sort by timemodified DESC to allow finding quicker. + grades = grades.filter((grade) => parseInt(grade.grade, 10) >= 0).sort((a, b) => b.timemodified - a.timemodified); // Filter the submissions to get only the ones with the right status and add some extra data. if (this.SELECTED_STATUS == AddonModAssignListFilterName.NEED_GRADING) { const promises: Promise[] = submissions.map(async (submission: AddonModAssignSubmissionForList) => { @@ -195,17 +198,15 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc // Load offline grades. const notSynced = !!gradeData && submission.timemodified < gradeData.timemodified; - if (submission.gradingstatus == AddonModAssignGradingStates.GRADED && !assign.markingworkflow) { + if (!assign.markingworkflow) { // Get the last grade of the submission. - const grade = grades - .filter((grade) => grade.userid == submission.userid) - .reduce( - (a, b) => (a && a.timemodified > b.timemodified ? a : b), - undefined, - ); + const grade = grades.find((grade) => grade.userid == submission.userid); - if (grade && grade.timemodified < submission.timemodified) { - submission.gradingstatus = AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT; + if (grade) { + // Override status if grade is found. + submission.gradingstatus = grade.timemodified < submission.timemodified + ? AddonModAssignGradingStates.GRADED_FOLLOWUP_SUBMIT + : AddonModAssignGradingStates.GRADED; } } submission.statusColor = AddonModAssign.getSubmissionStatusColor(submission.status); @@ -222,7 +223,7 @@ export class AddonModAssignSubmissionsSource extends CoreRoutedItemsManagerSourc submission.gradingColor = ''; } else if (submission.statusColor != CoreIonicColorNames.DANGER || submission.gradingColor != CoreIonicColorNames.DANGER) { - // Show grading status if one of the statuses is not done. + // Show grading status if one of the statuses is not done. submission.gradingStatusTranslationId = AddonModAssign.getSubmissionGradingStatusTranslationId( submission.gradingstatus, ); diff --git a/src/addons/mod/assign/services/assign-helper.ts b/src/addons/mod/assign/services/assign-helper.ts index 25653194c..cb062c240 100644 --- a/src/addons/mod/assign/services/assign-helper.ts +++ b/src/addons/mod/assign/services/assign-helper.ts @@ -150,7 +150,7 @@ export class AddonModAssignHelperProvider { attemptnumber: 0, timecreated: 0, timemodified: 0, - status: '', + status: AddonModAssignSubmissionStatusValues.NEW, groupid: 0, }; } @@ -404,13 +404,18 @@ export class AddonModAssignHelperProvider { const blind = !!assign.blindmarking && !assign.revealidentities; const teamsubmission = !!assign.teamsubmission; + if (teamsubmission) { + // On team submission discard user submissions. + submissions = submissions.filter((submission) => submission.userid == 0); + } + return participants.map((participant) => { const groupId = participant.groupid ?? (participant.groups && participant.groups[0] ? participant.groups[0].id : 0); const foundSubmission = submissions.find((submission) => { if (teamsubmission) { - return submission.userid == 0 && submission.groupid == groupId; + return submission.groupid == groupId; } const submitId = submission.userid && submission.userid > 0 ? submission.userid : submission.blindid; @@ -423,6 +428,9 @@ export class AddonModAssignHelperProvider { // Create submission if none. submission = this.createEmptySubmission(); submission.groupid = groupId; + submission.status = participant.submitted + ? AddonModAssignSubmissionStatusValues.SUBMITTED + : AddonModAssignSubmissionStatusValues.NEW; } else { submission = Object.assign({}, foundSubmission); } @@ -444,9 +452,6 @@ export class AddonModAssignHelperProvider { submission.groupname = participant.groupname; } - submission.status = submission.status ?? (participant.submitted ? AddonModAssignSubmissionStatusValues.SUBMITTED : - AddonModAssignSubmissionStatusValues.NEW); - return submission; }); diff --git a/src/core/components/loading/loading.scss b/src/core/components/loading/loading.scss index 3861b04e2..ef26afe30 100644 --- a/src/core/components/loading/loading.scss +++ b/src/core/components/loading/loading.scss @@ -44,7 +44,6 @@ } .core-loading-content { - display: contents; @include core-transition(opacity, 200ms); }