From 3a9eee06f95e8942b86944a918bfc3a2ba7ed658 Mon Sep 17 00:00:00 2001 From: Sol Dubock <94075844+sjd210@users.noreply.github.com> Date: Mon, 27 Oct 2025 14:15:23 +0000 Subject: [PATCH 1/9] Change markbook "Parts" heading to "Marks" --- src/IsaacAppTypes.tsx | 8 ++-- .../elements/quiz/QuizProgressCommon.tsx | 42 ++++++++----------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/IsaacAppTypes.tsx b/src/IsaacAppTypes.tsx index 85310b3fd3..62bfd91be1 100644 --- a/src/IsaacAppTypes.tsx +++ b/src/IsaacAppTypes.tsx @@ -338,7 +338,7 @@ export interface ActiveModalWithoutState { bodyContainerClassName?: string; } -export type ProgressSortOrder = number | "name" | "totalPartPercentage" | "totalAttemptedPartPercentage" | "totalQuestionPercentage" | "totalAttemptedQuestionPercentage"; +export type ProgressSortOrder = number | "name" | "totalMarkPercentage" | "totalAttemptedMarkPercentage" | "totalQuestionPercentage" | "totalAttemptedQuestionPercentage"; export enum QuizzesBoardOrder { "title" = "title", @@ -497,14 +497,14 @@ export const AssignmentScheduleContext = React.createContext<{ collapsed: boolean; setCollapsed: (b: boolean) => void; viewBy: "startDate" | "dueDate"; - }>({boardsById: {}, groupsById: {}, groupFilter: {}, boardIdsByGroupId: {}, groups: [], gameboards: [], openAssignmentModal: () => {}, collapsed: false, setCollapsed: () => {}, viewBy: "startDate"}); +}>({boardsById: {}, groupsById: {}, groupFilter: {}, boardIdsByGroupId: {}, groups: [], gameboards: [], openAssignmentModal: () => {}, collapsed: false, setCollapsed: () => {}, viewBy: "startDate"}); export const ContentSidebarContext = React.createContext<{ toggle: () => void; close: () => void; } | undefined>(undefined); export interface AuthorisedAssignmentProgress extends ApiTypes.AssignmentProgressDTO { completed?: boolean; correctQuestionPagesCount: number; - correctQuestionPartsCount: number; - incorrectQuestionPartsCount: number; + correctQuestionMarksCount: number; + incorrectQuestionMarksCount: number; notAttemptedPartResults: number[]; } diff --git a/src/app/components/elements/quiz/QuizProgressCommon.tsx b/src/app/components/elements/quiz/QuizProgressCommon.tsx index 00e6f34a96..8887372aff 100644 --- a/src/app/components/elements/quiz/QuizProgressCommon.tsx +++ b/src/app/components/elements/quiz/QuizProgressCommon.tsx @@ -195,10 +195,10 @@ export function ResultsTable({ switch (sortOrder) { case "name": return sortByName(item); - case "totalPartPercentage": - return -item.correctQuestionPartsCount; - case "totalAttemptedPartPercentage": - return -(item.correctQuestionPartsCount + item.incorrectQuestionPartsCount); + case "totalMarkPercentage": + return -item.correctQuestionMarksCount; + case "totalAttemptedMarkPercentage": + return -(item.correctQuestionMarksCount + item.incorrectQuestionMarksCount); case "totalQuestionPercentage": return -item.correctQuestionPagesCount; case "totalAttemptedQuestionPercentage": @@ -273,35 +273,29 @@ export function ResultsTable({ pageSettings?.attemptedOrCorrect === "CORRECT" ? className={classNames("pointer-cursor correct-attempted-header", {"sticky-ca-col": isPhy})} - defaultOrder={"totalPartPercentage"} - reverseOrder={"totalPartPercentage"} + defaultOrder={"totalMarkPercentage"} + reverseOrder={"totalMarkPercentage"} currentOrder={sortOrder} setOrder={toggleSort} reversed={reverseOrder} onClick={() => setSelectedQuestionIndex(undefined)} - label={"Total correct parts"} + label={"Total marks awarded"} > - {siteSpecific( -
- Parts - (total) -
, - "Correct" - )} +
+ Marks + (total) +
: className={classNames("pointer-cursor correct-attempted-header", {"sticky-ca-col": isPhy})} - defaultOrder={"totalAttemptedPartPercentage"} - reverseOrder={"totalAttemptedPartPercentage"} + defaultOrder={"totalAttemptedMarkPercentage"} + reverseOrder={"totalAttemptedMarkPercentage"} currentOrder={sortOrder} setOrder={toggleSort} reversed={reverseOrder} onClick={() => setSelectedQuestionIndex(undefined)} - label={"Total attempted parts"} + label={"Total marks awarded"} > - {siteSpecific( -
- Parts - (total) -
, - "Attempted" - )} +
+ Marks + (total) +
)} {questions.map((_, index) => From 075e97d35e80b26ed50101001ab22705915cdaa3 Mon Sep 17 00:00:00 2001 From: Sol Dubock <94075844+sjd210@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:27:22 +0000 Subject: [PATCH 2/9] Read correct marks and mark totals from DTO --- src/IsaacApiTypes.tsx | 2 + .../elements/quiz/QuizProgressCommon.tsx | 54 +++++++++++-------- .../pages/AssignmentProgressIndividual.tsx | 12 ++--- .../pages/quizzes/QuizTeacherFeedback.tsx | 10 ++-- 4 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/IsaacApiTypes.tsx b/src/IsaacApiTypes.tsx index 17a5c28bc5..16a55a2c0c 100644 --- a/src/IsaacApiTypes.tsx +++ b/src/IsaacApiTypes.tsx @@ -48,6 +48,8 @@ export interface AssignmentProgressDTO { user?: UserSummaryDTO; correctPartResults?: number[]; incorrectPartResults?: number[]; + correctMarkResults?: number[][]; + markTotals?: number[][]; questionResults?: CompletionState[]; questionPartResults?: QuestionPartState[][]; } diff --git a/src/app/components/elements/quiz/QuizProgressCommon.tsx b/src/app/components/elements/quiz/QuizProgressCommon.tsx index 8887372aff..67cfbc8199 100644 --- a/src/app/components/elements/quiz/QuizProgressCommon.tsx +++ b/src/app/components/elements/quiz/QuizProgressCommon.tsx @@ -279,10 +279,13 @@ export function ResultsTable({ onClick={() => setSelectedQuestionIndex(undefined)} label={"Total marks awarded"} > -
- Marks - (total) -
+ {siteSpecific( +
+ Marks + (total) +
, + "Correct" + )} : className={classNames("pointer-cursor correct-attempted-header", {"sticky-ca-col": isPhy})} @@ -292,10 +295,13 @@ export function ResultsTable({ onClick={() => setSelectedQuestionIndex(undefined)} label={"Total marks awarded"} > -
- Marks - (total) -
+ {siteSpecific( +
+ Marks + (total) +
, + "Attempted" + )} )} {questions.map((_, index) => @@ -417,8 +423,8 @@ export function ResultsTable({ ? studentProgress.correctQuestionPagesCount : studentProgress.questionResults?.filter(r => r !== CompletionState.NOT_ATTEMPTED).length ?? 0 : pageSettings?.attemptedOrCorrect === "CORRECT" - ? studentProgress.correctQuestionPartsCount - : studentProgress.correctQuestionPartsCount + studentProgress.incorrectQuestionPartsCount, + ? studentProgress.correctQuestionMarksCount + : studentProgress.correctQuestionMarksCount + studentProgress.incorrectQuestionMarksCount, questions.length, !!pageSettings?.formatAsPercentage ) @@ -430,8 +436,8 @@ export function ResultsTable({ {fullAccess ? formatMark( pageSettings?.attemptedOrCorrect === "CORRECT" - ? studentProgress.correctQuestionPartsCount - : studentProgress.correctQuestionPartsCount + studentProgress.incorrectQuestionPartsCount, + ? studentProgress.correctQuestionMarksCount + : studentProgress.correctQuestionMarksCount + studentProgress.incorrectQuestionMarksCount, assignmentTotalQuestionParts, !!pageSettings?.formatAsPercentage ) @@ -445,15 +451,15 @@ export function ResultsTable({ )}> {isAssignment ? (fullAccess - ? isPhy - ? formatMark( + ? siteSpecific( + formatMark( pageSettings?.attemptedOrCorrect === "CORRECT" ? (studentProgress.correctPartResults || [])[index] : (studentProgress.correctPartResults || [])[index] + (studentProgress.incorrectPartResults || [])[index], questions[index].questionPartsTotal as number, !!pageSettings?.formatAsPercentage - ) - : getAssignmentQuestionCorrectnessIcon((studentProgress.questionResults || [])[index], pageSettings?.attemptedOrCorrect || "CORRECT") + ), + getAssignmentQuestionCorrectnessIcon((studentProgress.questionResults || [])[index], pageSettings?.attemptedOrCorrect || "CORRECT")) : "" ) : getQuizQuestionCorrectnessIcon(pageSettings?.attemptedOrCorrect || "CORRECT", studentProgress, index) @@ -519,8 +525,8 @@ export function ResultsTablePartBreakdown({ switch (sortOrder) { case "name": return (item.user?.familyName + ", " + item.user?.givenName).toLowerCase(); - case "totalPartPercentage": - case "totalAttemptedPartPercentage": + case "totalMarkPercentage": + case "totalAttemptedMarkPercentage": case "totalQuestionPercentage": case "totalAttemptedQuestionPercentage": return 0; // These sorts are not applicable for part breakdown @@ -567,7 +573,7 @@ export function ResultsTablePartBreakdown({ > {siteSpecific(
- Parts + Marks (total)
, "Correct" @@ -582,7 +588,7 @@ export function ResultsTablePartBreakdown({ > {siteSpecific(
- Parts + Marks (total)
, "Attempted" @@ -637,9 +643,11 @@ export function ResultsTablePartBreakdown({ {/* main data */} {studentProgress.questionPartResults && - studentProgress.questionPartResults[questionIndex].map((questionPartResult, questionPartIndex) => ( - {getQuizQuestionPartCorrectnessIcon(questionPartResult)} - )) + studentProgress.questionPartResults[questionIndex].map((_q, questionPartIndex) => { + const correctMarkResult = studentProgress.correctMarkResults ? studentProgress.correctMarkResults[questionIndex][questionPartIndex] ?? 0 : 0; + const markTotal = studentProgress.markTotals ? studentProgress.markTotals[questionIndex][questionPartIndex] ?? 0 : 0; + return {formatMark(correctMarkResult, markTotal, !!pageSettings?.formatAsPercentage)}; + }) } ))} diff --git a/src/app/components/pages/AssignmentProgressIndividual.tsx b/src/app/components/pages/AssignmentProgressIndividual.tsx index 8841f2cb05..9720c3cc3e 100644 --- a/src/app/components/pages/AssignmentProgressIndividual.tsx +++ b/src/app/components/pages/AssignmentProgressIndividual.tsx @@ -102,8 +102,8 @@ const GroupAssignmentTab = ({assignment, progress}: GroupAssignmentTabProps) => return "revoked"; } - const correctParts = studentProgress.correctQuestionPartsCount; - const incorrectParts = studentProgress.incorrectQuestionPartsCount; + const correctParts = studentProgress.correctQuestionMarksCount; + const incorrectParts = studentProgress.incorrectQuestionMarksCount; const status = null; return markClassesInternal(assignmentProgressContext?.attemptedOrCorrect ?? "CORRECT", studentProgress, status, correctParts, incorrectParts, totalParts); @@ -333,8 +333,8 @@ export const ProgressDetails = ({assignment}: { assignment: EnhancedAssignmentWi const initialState = { ...p, correctQuestionPagesCount: 0, - correctQuestionPartsCount: 0, - incorrectQuestionPartsCount: 0, + correctQuestionMarksCount: 0, + incorrectQuestionMarksCount: 0, notAttemptedPartResults: [] }; @@ -344,8 +344,8 @@ export const ProgressDetails = ({assignment}: { assignment: EnhancedAssignmentWi return { ...oldP, correctQuestionPagesCount: correctQuestionsCount, - correctQuestionPartsCount: oldP.correctQuestionPartsCount + (p.correctPartResults || [])[i], - incorrectQuestionPartsCount: oldP.incorrectQuestionPartsCount + (p.incorrectPartResults || [])[i], + correctQuestionMarksCount: oldP.correctQuestionMarksCount + (p.correctPartResults || [])[i], + incorrectQuestionMarksCount: oldP.incorrectQuestionMarksCount + (p.incorrectPartResults || [])[i], notAttemptedPartResults: [ ...oldP.notAttemptedPartResults, (questions[i].questionPartsTotal - (p.correctPartResults || [])[i] - (p.incorrectPartResults || [])[i]) diff --git a/src/app/components/pages/quizzes/QuizTeacherFeedback.tsx b/src/app/components/pages/quizzes/QuizTeacherFeedback.tsx index 7d6d40e7be..e30cfc00b1 100644 --- a/src/app/components/pages/quizzes/QuizTeacherFeedback.tsx +++ b/src/app/components/pages/quizzes/QuizTeacherFeedback.tsx @@ -197,8 +197,8 @@ export const QuizProgressDetails = ({assignment}: {assignment: QuizAssignmentDTO return "revoked"; } - const correctParts = studentProgress.correctQuestionPartsCount; - const incorrectParts = studentProgress.incorrectQuestionPartsCount; + const correctParts = studentProgress.correctQuestionMarksCount; + const incorrectParts = studentProgress.incorrectQuestionMarksCount; const total = questions.reduce((acc, q) => acc + (q.questionPartsTotal ?? 0), 0); return markClassesInternal(assignmentProgressContext?.attemptedOrCorrect ?? "CORRECT", studentProgress, null, correctParts, incorrectParts, total); @@ -218,7 +218,7 @@ export const QuizProgressDetails = ({assignment}: {assignment: QuizAssignmentDTO const totalParts = questions.length; - const progress : AuthorisedAssignmentProgress[] = !assignment.userFeedback ? [] : assignment.userFeedback.map(user => { + const progress: AuthorisedAssignmentProgress[] = !assignment.userFeedback ? [] : assignment.userFeedback.map(user => { const partsCorrect = questions.reduce((acc, q) => acc + (user.feedback?.questionMarks?.[q?.id ?? -1]?.correct ?? 0), 0); return { user: user.user as UserSummaryDTO, @@ -232,8 +232,8 @@ export const QuizProgressDetails = ({assignment}: {assignment: QuizAssignmentDTO : questions.map(q => q.questionPartsTotal ?? 0), questionResults: [], correctQuestionPagesCount: partsCorrect, // quizzes don't have pages, but QuizProgressCommon expects this key to be the "Correct" column value for sorting - correctQuestionPartsCount: partsCorrect, - incorrectQuestionPartsCount: questions.reduce((acc, q) => acc + (user.feedback?.questionMarks?.[q?.id ?? -1]?.incorrect ?? 0), 0), + correctQuestionMarksCount: partsCorrect, + incorrectQuestionMarksCount: questions.reduce((acc, q) => acc + (user.feedback?.questionMarks?.[q?.id ?? -1]?.incorrect ?? 0), 0), }; }); From b2d8ed2f3e0987a61dccda13060fcb747e655c95 Mon Sep 17 00:00:00 2001 From: Sol Dubock <94075844+sjd210@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:29:01 +0000 Subject: [PATCH 3/9] Remove unused function --- .../components/elements/quiz/QuizProgressCommon.tsx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/app/components/elements/quiz/QuizProgressCommon.tsx b/src/app/components/elements/quiz/QuizProgressCommon.tsx index 67cfbc8199..5e4696ec17 100644 --- a/src/app/components/elements/quiz/QuizProgressCommon.tsx +++ b/src/app/components/elements/quiz/QuizProgressCommon.tsx @@ -30,18 +30,6 @@ export function formatMark(numerator: number, denominator: number, formatAsPerce return result; } -export const generateCorrectnessIcon = (correct: number, incorrect: number, notAttempted: number, totalParts: number) => { - if (correct === totalParts) { - return ICON.correct; - } else if (notAttempted === totalParts) { - return ICON.notAttempted; - } else if (correct === 0) { - return ICON.incorrect; - } else { - return ICON.partial; - } -}; - const getAssignmentQuestionCorrectnessIcon = (state: CompletionState, attemptedOrCorrect: "ATTEMPTED" | "CORRECT") => { if (attemptedOrCorrect === "CORRECT") { switch (state) { From cf7328e084618ab8057d87a8bec93e46ac517685 Mon Sep 17 00:00:00 2001 From: Sol Dubock <94075844+sjd210@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:44:58 +0000 Subject: [PATCH 4/9] Display marks rather than parts in table body --- src/IsaacApiTypes.tsx | 1 + src/app/components/elements/quiz/QuizProgressCommon.tsx | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/IsaacApiTypes.tsx b/src/IsaacApiTypes.tsx index 16a55a2c0c..7e8e81fcd5 100644 --- a/src/IsaacApiTypes.tsx +++ b/src/IsaacApiTypes.tsx @@ -49,6 +49,7 @@ export interface AssignmentProgressDTO { correctPartResults?: number[]; incorrectPartResults?: number[]; correctMarkResults?: number[][]; + incorrectMarkResults?: number[][]; markTotals?: number[][]; questionResults?: CompletionState[]; questionPartResults?: QuestionPartState[][]; diff --git a/src/app/components/elements/quiz/QuizProgressCommon.tsx b/src/app/components/elements/quiz/QuizProgressCommon.tsx index 5e4696ec17..e2d78f0f13 100644 --- a/src/app/components/elements/quiz/QuizProgressCommon.tsx +++ b/src/app/components/elements/quiz/QuizProgressCommon.tsx @@ -442,9 +442,9 @@ export function ResultsTable({ ? siteSpecific( formatMark( pageSettings?.attemptedOrCorrect === "CORRECT" - ? (studentProgress.correctPartResults || [])[index] - : (studentProgress.correctPartResults || [])[index] + (studentProgress.incorrectPartResults || [])[index], - questions[index].questionPartsTotal as number, + ? (studentProgress.correctMarkResults || [])[index].reduce((a, b) => a + b, 0) + : (studentProgress.correctMarkResults || [])[index].concat((studentProgress.incorrectMarkResults || [])[index]).reduce((a, b) => a + b, 0), + studentProgress.markTotals![index].reduce((a, b) => a + b, 0) ?? 0, !!pageSettings?.formatAsPercentage ), getAssignmentQuestionCorrectnessIcon((studentProgress.questionResults || [])[index], pageSettings?.attemptedOrCorrect || "CORRECT")) From 7c32cb84d6c72b6074832dc1abfdbe4851b1021b Mon Sep 17 00:00:00 2001 From: Sol Dubock <94075844+sjd210@users.noreply.github.com> Date: Mon, 27 Oct 2025 17:28:51 +0000 Subject: [PATCH 5/9] Accurately display mark totals --- .../elements/quiz/QuizProgressCommon.tsx | 14 ++++---------- .../pages/AssignmentProgressIndividual.tsx | 13 ++++++++----- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/app/components/elements/quiz/QuizProgressCommon.tsx b/src/app/components/elements/quiz/QuizProgressCommon.tsx index e2d78f0f13..8cdc567bee 100644 --- a/src/app/components/elements/quiz/QuizProgressCommon.tsx +++ b/src/app/components/elements/quiz/QuizProgressCommon.tsx @@ -419,14 +419,14 @@ export function ResultsTable({ : "" } - {/* total parts */} + {/* total marks */} {isPhy && isAssignment && {fullAccess ? formatMark( pageSettings?.attemptedOrCorrect === "CORRECT" ? studentProgress.correctQuestionMarksCount : studentProgress.correctQuestionMarksCount + studentProgress.incorrectQuestionMarksCount, - assignmentTotalQuestionParts, + studentProgress.markTotals?.reduce((acc, arr) => acc + arr.reduce((a, b) => a + b, 0), 0) ?? 0, !!pageSettings?.formatAsPercentage ) : "" @@ -616,14 +616,8 @@ export function ResultsTablePartBreakdown({ {isPhy && studentProgress.questionPartResults && {formatMark( - studentProgress.questionPartResults[questionIndex].reduce((acc, questionPartResult) => { - if (pageSettings?.attemptedOrCorrect === "CORRECT") { - return acc + (questionPartResult === "CORRECT" ? 1 : 0); - } else { - return acc + (questionPartResult !== "NOT_ATTEMPTED" ? 1 : 0); - } - }, 0), - studentProgress.questionPartResults[questionIndex].length, + studentProgress.correctMarkResults![questionIndex].reduce((a, b) => a + b, 0), + studentProgress.markTotals![questionIndex].reduce((a, b) => a + b, 0), !!pageSettings?.formatAsPercentage )} diff --git a/src/app/components/pages/AssignmentProgressIndividual.tsx b/src/app/components/pages/AssignmentProgressIndividual.tsx index 9720c3cc3e..9e05d11b8e 100644 --- a/src/app/components/pages/AssignmentProgressIndividual.tsx +++ b/src/app/components/pages/AssignmentProgressIndividual.tsx @@ -340,20 +340,23 @@ export const ProgressDetails = ({assignment}: { assignment: EnhancedAssignmentWi const ret = (p.questionResults || []).reduce((oldP, results, i) => { const correctQuestionsCount = [CompletionState.ALL_CORRECT].includes(results) ? oldP.correctQuestionPagesCount + 1 : oldP.correctQuestionPagesCount; - const questions = assignment.gameboard.contents; + // const questions = assignment.gameboard.contents; + const correctMarkTotal = (p.correctMarkResults || [])[i].reduce((a, b) => a + b, 0); + const incorrectMarkTotal = (p.incorrectMarkResults || [])[i].reduce((a, b) => a + b, 0); + const markTotal = (p.markTotals || [])[i].reduce((a, b) => a + b, 0); return { ...oldP, correctQuestionPagesCount: correctQuestionsCount, - correctQuestionMarksCount: oldP.correctQuestionMarksCount + (p.correctPartResults || [])[i], - incorrectQuestionMarksCount: oldP.incorrectQuestionMarksCount + (p.incorrectPartResults || [])[i], + correctQuestionMarksCount: oldP.correctQuestionMarksCount + correctMarkTotal, + incorrectQuestionMarksCount: oldP.incorrectQuestionMarksCount + incorrectMarkTotal, notAttemptedPartResults: [ ...oldP.notAttemptedPartResults, - (questions[i].questionPartsTotal - (p.correctPartResults || [])[i] - (p.incorrectPartResults || [])[i]) + (markTotal - correctMarkTotal - incorrectMarkTotal) ] }; }, initialState); return [ret, questions.length === ret.correctQuestionPagesCount]; - }), [assignment.gameboard.contents, assignment.progress, questions.length]); + }), [assignment.progress, questions.length]); const progress = progressData.map(pd => pd[0]); From 0e19fa1ab89f7d341d50c778696096cf3532b4b5 Mon Sep 17 00:00:00 2001 From: Sol Dubock <94075844+sjd210@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:49:25 +0000 Subject: [PATCH 6/9] Add setting to toggle between marks/parts display --- src/IsaacAppTypes.tsx | 4 ++++ .../components/pages/AssignmentProgressIndividual.tsx | 9 +++++++++ src/app/services/progress.ts | 2 ++ 3 files changed, 15 insertions(+) diff --git a/src/IsaacAppTypes.tsx b/src/IsaacAppTypes.tsx index 62bfd91be1..223968c74c 100644 --- a/src/IsaacAppTypes.tsx +++ b/src/IsaacAppTypes.tsx @@ -438,6 +438,8 @@ export interface AssignmentProgressPageSettings { setFormatAsPercentage: (formatAsPercentage: boolean) => void; attemptedOrCorrect: "ATTEMPTED" | "CORRECT"; setAttemptedOrCorrect: (attemptedOrCorrect: "ATTEMPTED" | "CORRECT") => void; + displayIndividualMarks: boolean; + setDisplayIndividualMarks: (displayIndividualMarks: boolean) => void; assignmentOrder: AssignmentOrderSpec; setAssignmentOrder: (assignmentOrder: AssignmentOrderSpec) => void; groupSortOrder: GroupSortOrder; @@ -741,6 +743,8 @@ export interface PageSettings { assignmentOrder?: AssignmentOrderSpec; attemptedOrCorrect?: "ATTEMPTED" | "CORRECT"; setAttemptedOrCorrect?: (newValue: "ATTEMPTED" | "CORRECT") => void; + displayIndividualMarks: boolean; + setDisplayIndividualMarks: (displayIndividualMarks: boolean) => void; } export interface GameboardBuilderQuestions { diff --git a/src/app/components/pages/AssignmentProgressIndividual.tsx b/src/app/components/pages/AssignmentProgressIndividual.tsx index 9e05d11b8e..17220137fd 100644 --- a/src/app/components/pages/AssignmentProgressIndividual.tsx +++ b/src/app/components/pages/AssignmentProgressIndividual.tsx @@ -47,6 +47,15 @@ export const AssignmentProgressSettings = () => { onChange={(e) => assignmentProgressContext?.setAttemptedOrCorrect?.(e.currentTarget.checked ? "CORRECT" : "ATTEMPTED")} /> } + + {isPhy &&
+ Marks display mode + + assignmentProgressContext?.setDisplayIndividualMarks?.(e.currentTarget.checked)} + /> +
} ; }; diff --git a/src/app/services/progress.ts b/src/app/services/progress.ts index 238db64535..62dee759de 100644 --- a/src/app/services/progress.ts +++ b/src/app/services/progress.ts @@ -28,6 +28,7 @@ export function useAssignmentProgressAccessibilitySettings({user}: {user: Regist const [colourBlind, setColourBlind] = useState(false); const [formatAsPercentage, setFormatAsPercentage] = useState(false); const [attemptedOrCorrect, setAttemptedOrCorrect] = useState<"ATTEMPTED" | "CORRECT">("CORRECT"); + const [displayIndividualMarks, setDisplayIndividualMarks] = useState(false); const [assignmentOrder, setAssignmentOrder] = useState(AssignmentOrder.startDateDescending); const [groupSortOrder, setGroupSortOrder] = useState(GroupSortOrder.Alphabetical); @@ -35,6 +36,7 @@ export function useAssignmentProgressAccessibilitySettings({user}: {user: Regist colourBlind, setColourBlind, formatAsPercentage, setFormatAsPercentage, attemptedOrCorrect, setAttemptedOrCorrect, + displayIndividualMarks, setDisplayIndividualMarks, assignmentOrder, setAssignmentOrder, groupSortOrder, setGroupSortOrder, isTeacher: isTeacherOrAbove(user), From 7f6a20af1e42dff069d0d99b6f71a95275d0e490 Mon Sep 17 00:00:00 2001 From: Sol Dubock <94075844+sjd210@users.noreply.github.com> Date: Tue, 28 Oct 2025 17:00:09 +0000 Subject: [PATCH 7/9] Toggle between marks/parts on detailed mark tab --- .../elements/quiz/QuizProgressCommon.tsx | 57 +++++++++++-------- .../pages/AssignmentProgressIndividual.tsx | 1 - 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/app/components/elements/quiz/QuizProgressCommon.tsx b/src/app/components/elements/quiz/QuizProgressCommon.tsx index 8cdc567bee..383c3e64fa 100644 --- a/src/app/components/elements/quiz/QuizProgressCommon.tsx +++ b/src/app/components/elements/quiz/QuizProgressCommon.tsx @@ -265,15 +265,12 @@ export function ResultsTable({ reverseOrder={"totalMarkPercentage"} currentOrder={sortOrder} setOrder={toggleSort} reversed={reverseOrder} onClick={() => setSelectedQuestionIndex(undefined)} - label={"Total marks awarded"} + label={pageSettings?.displayIndividualMarks ? "Total marks awarded" : "Total correct parts"} > - {siteSpecific( -
- Marks - (total) -
, - "Correct" - )} +
+ {pageSettings?.displayIndividualMarks ? "Marks" : "Parts"} + (total) +
: className={classNames("pointer-cursor correct-attempted-header", {"sticky-ca-col": isPhy})} @@ -281,15 +278,12 @@ export function ResultsTable({ reverseOrder={"totalAttemptedMarkPercentage"} currentOrder={sortOrder} setOrder={toggleSort} reversed={reverseOrder} onClick={() => setSelectedQuestionIndex(undefined)} - label={"Total marks awarded"} + label={pageSettings?.displayIndividualMarks ? "Total marks awarded" : "Total correct parts"} > - {siteSpecific( -
- Marks - (total) -
, - "Attempted" - )} +
+ {pageSettings?.displayIndividualMarks ? "Marks" : "Parts"} + (total) +
)} {questions.map((_, index) => @@ -599,8 +593,23 @@ export function ResultsTablePartBreakdown({ )} - {sortedProgress.map((studentProgress, studentIndex) => ( - + {sortedProgress.map((studentProgress, studentIndex) => { + const markPartNumerator: number[] = pageSettings?.displayIndividualMarks + ? pageSettings?.attemptedOrCorrect === "CORRECT" + ? studentProgress.correctMarkResults![questionIndex] + : studentProgress.correctMarkResults![questionIndex].map((mark, partIndex) => + mark + studentProgress.incorrectMarkResults![questionIndex][partIndex] + ) + : studentProgress.questionPartResults![questionIndex].map(part => + (pageSettings?.attemptedOrCorrect === "CORRECT" + ? part === "CORRECT" + : part !== "NOT_ATTEMPTED" + ) ? 1 : 0 + ); + const markPartDenominator: number[] = studentProgress.markTotals && pageSettings?.displayIndividualMarks + ? studentProgress.markTotals[questionIndex] + : Array(studentProgress.markTotals![questionIndex]?.length).fill(1); + return {/* student name */}
@@ -616,8 +625,8 @@ export function ResultsTablePartBreakdown({ {isPhy && studentProgress.questionPartResults && {formatMark( - studentProgress.correctMarkResults![questionIndex].reduce((a, b) => a + b, 0), - studentProgress.markTotals![questionIndex].reduce((a, b) => a + b, 0), + markPartNumerator.reduce((a, b) => a + b, 0), + markPartDenominator.reduce((a, b) => a + b, 0), !!pageSettings?.formatAsPercentage )} @@ -626,13 +635,13 @@ export function ResultsTablePartBreakdown({ {/* main data */} {studentProgress.questionPartResults && studentProgress.questionPartResults[questionIndex].map((_q, questionPartIndex) => { - const correctMarkResult = studentProgress.correctMarkResults ? studentProgress.correctMarkResults[questionIndex][questionPartIndex] ?? 0 : 0; - const markTotal = studentProgress.markTotals ? studentProgress.markTotals[questionIndex][questionPartIndex] ?? 0 : 0; + const correctMarkResult = markPartNumerator[questionPartIndex] ?? 0; + const markTotal = markPartDenominator[questionPartIndex] ?? 0; return {formatMark(correctMarkResult, markTotal, !!pageSettings?.formatAsPercentage)}; }) } - - ))} + ; + })} diff --git a/src/app/components/pages/AssignmentProgressIndividual.tsx b/src/app/components/pages/AssignmentProgressIndividual.tsx index 17220137fd..4e5b9d2cf5 100644 --- a/src/app/components/pages/AssignmentProgressIndividual.tsx +++ b/src/app/components/pages/AssignmentProgressIndividual.tsx @@ -349,7 +349,6 @@ export const ProgressDetails = ({assignment}: { assignment: EnhancedAssignmentWi const ret = (p.questionResults || []).reduce((oldP, results, i) => { const correctQuestionsCount = [CompletionState.ALL_CORRECT].includes(results) ? oldP.correctQuestionPagesCount + 1 : oldP.correctQuestionPagesCount; - // const questions = assignment.gameboard.contents; const correctMarkTotal = (p.correctMarkResults || [])[i].reduce((a, b) => a + b, 0); const incorrectMarkTotal = (p.incorrectMarkResults || [])[i].reduce((a, b) => a + b, 0); const markTotal = (p.markTotals || [])[i].reduce((a, b) => a + b, 0); From 6f45fa9135841695d390b34a65dc85b4c6516284 Mon Sep 17 00:00:00 2001 From: Sol Dubock <94075844+sjd210@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:13:35 +0000 Subject: [PATCH 8/9] Remove now redundant partResults DTO variables --- src/IsaacApiTypes.tsx | 2 -- .../elements/quiz/QuizProgressCommon.tsx | 20 +++++++++---- .../pages/AssignmentProgressIndividual.tsx | 7 ++--- .../pages/quizzes/QuizTeacherFeedback.tsx | 10 +++---- src/mocks/data.ts | 28 +++++++++---------- 5 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/IsaacApiTypes.tsx b/src/IsaacApiTypes.tsx index 7e8e81fcd5..e0a6c9cacd 100644 --- a/src/IsaacApiTypes.tsx +++ b/src/IsaacApiTypes.tsx @@ -46,8 +46,6 @@ export interface AssignmentStatusDTO { export interface AssignmentProgressDTO { user?: UserSummaryDTO; - correctPartResults?: number[]; - incorrectPartResults?: number[]; correctMarkResults?: number[][]; incorrectMarkResults?: number[][]; markTotals?: number[][]; diff --git a/src/app/components/elements/quiz/QuizProgressCommon.tsx b/src/app/components/elements/quiz/QuizProgressCommon.tsx index 383c3e64fa..530ce946f1 100644 --- a/src/app/components/elements/quiz/QuizProgressCommon.tsx +++ b/src/app/components/elements/quiz/QuizProgressCommon.tsx @@ -58,17 +58,27 @@ const getAssignmentQuestionCorrectnessIcon = (state: CompletionState, attemptedO }; +export function markResultsToPartResults(markResults: number[][] = [], markTotals: number[][] = []): number[] { + return markResults.map((marks, i) => { + const markTotal = markTotals[i].reduce((acc, curr) => acc + curr, 0); + const markObtained = marks.reduce((acc, curr) => acc + curr, 0); + return Math.floor(markTotal / markObtained); + }); +}; + const getQuizQuestionCorrectnessIcon = (attemptedOrCorrect: "ATTEMPTED" | "CORRECT", studentProgress: AssignmentProgressDTO, questionIndex: number) => { + const questionCorrect = (markResultsToPartResults(studentProgress.correctMarkResults, studentProgress.markTotals))[questionIndex] === 1; + const questionIncorrect = (markResultsToPartResults(studentProgress.incorrectMarkResults, studentProgress.markTotals))[questionIndex] === 1; if (attemptedOrCorrect === "CORRECT") { - if ((studentProgress.correctPartResults || [])[questionIndex] === 1) { + if (questionCorrect) { return ICON.correct; } - else if ((studentProgress.incorrectPartResults || [])[questionIndex] === 1) { + else if (questionIncorrect) { return ICON.incorrect; } return ICON.notAttempted; } else { - if ((studentProgress.correctPartResults || [])[questionIndex] === 1 || (studentProgress.incorrectPartResults || [])[questionIndex] === 1) { + if (questionCorrect || questionIncorrect) { return ICON.correct; } return ICON.notAttempted; @@ -194,7 +204,7 @@ export function ResultsTable({ return item.notAttemptedPartResults?.reduce((acc, curr) => acc + curr, 0) || 0; default: if (pageSettings?.attemptedOrCorrect === "CORRECT") { - return -(item.correctPartResults || [])[sortOrder]; + return -(item.correctMarkResults || [])[sortOrder]; } else { return (item.notAttemptedPartResults || [])[sortOrder]; } @@ -323,7 +333,7 @@ export function ResultsTable({ const studentsWithAllAttempted = progress.reduce((acc, p) => acc + (isAuthorisedFullAccess(p) && !p.notAttemptedPartResults?.[index] ? 1 : 0), 0); return [studentsWithAllAttempted, progress.length]; } else { - const studentsWithAllCorrect = progress.reduce((acc, p) => acc + (p.correctPartResults?.[index] ? 1 : 0), 0); + const studentsWithAllCorrect = progress.reduce((acc, p) => acc + (markResultsToPartResults(p.correctMarkResults, p.markTotals)?.[index] ? 1 : 0), 0); return [studentsWithAllCorrect, progress.length]; } } diff --git a/src/app/components/pages/AssignmentProgressIndividual.tsx b/src/app/components/pages/AssignmentProgressIndividual.tsx index 4e5b9d2cf5..70f5704208 100644 --- a/src/app/components/pages/AssignmentProgressIndividual.tsx +++ b/src/app/components/pages/AssignmentProgressIndividual.tsx @@ -3,7 +3,7 @@ import { Link } from "react-router-dom"; import { AssignmentProgressDTO, GameboardItem, CompletionState } from "../../../IsaacApiTypes"; import { EnhancedAssignmentWithProgress, AssignmentProgressPageSettingsContext, AuthorisedAssignmentProgress } from "../../../IsaacAppTypes"; import { getAssignmentProgressCSVDownloadLink, isAda, isAuthorisedFullAccess, isPhy, PATHS, siteSpecific } from "../../services"; -import { ICON, passMark, ResultsTable, ResultsTablePartBreakdown } from "../elements/quiz/QuizProgressCommon"; +import { ICON, markResultsToPartResults, passMark, ResultsTable, ResultsTablePartBreakdown } from "../elements/quiz/QuizProgressCommon"; import { Badge, Button, Card, CardBody } from "reactstrap"; import { formatDate } from "../elements/DateString"; import { StyledCheckbox } from "../elements/inputs/StyledCheckbox"; @@ -123,12 +123,11 @@ const GroupAssignmentTab = ({assignment, progress}: GroupAssignmentTabProps) => return "revoked"; } - const question = questions[index]; const totalParts = question.questionPartsTotal; - const correctParts = (studentProgress.correctPartResults || [])[index]; - const incorrectParts = (studentProgress.incorrectPartResults || [])[index]; + const correctParts = markResultsToPartResults(studentProgress.correctMarkResults, studentProgress.markTotals)[index]; + const incorrectParts = markResultsToPartResults(studentProgress.incorrectMarkResults, studentProgress.markTotals)[index]; const status = (studentProgress.questionResults || [])[index]; return markClassesInternal(assignmentProgressContext?.attemptedOrCorrect ?? "CORRECT", studentProgress, status, correctParts, incorrectParts, totalParts); diff --git a/src/app/components/pages/quizzes/QuizTeacherFeedback.tsx b/src/app/components/pages/quizzes/QuizTeacherFeedback.tsx index e30cfc00b1..9f6341ea0a 100644 --- a/src/app/components/pages/quizzes/QuizTeacherFeedback.tsx +++ b/src/app/components/pages/quizzes/QuizTeacherFeedback.tsx @@ -34,7 +34,7 @@ import { } from "../../../../IsaacAppTypes"; import {teacherQuizzesCrumbs} from "../../elements/quiz/QuizContentsComponent"; import {formatDate} from "../../elements/DateString"; -import {ResultsTable} from "../../elements/quiz/QuizProgressCommon"; +import {markResultsToPartResults, ResultsTable} from "../../elements/quiz/QuizProgressCommon"; import { Alert, Button, @@ -209,8 +209,8 @@ export const QuizProgressDetails = ({assignment}: {assignment: QuizAssignmentDTO return "revoked"; } - const correctParts = (studentProgress.correctPartResults || [])[index]; - const incorrectParts = (studentProgress.incorrectPartResults || [])[index]; + const correctParts = markResultsToPartResults(studentProgress.correctMarkResults, studentProgress.markTotals)[index]; + const incorrectParts = markResultsToPartResults(studentProgress.incorrectMarkResults, studentProgress.markTotals)[index]; const totalParts = questions[index].questionPartsTotal ?? 0; return markClassesInternal(assignmentProgressContext?.attemptedOrCorrect ?? "CORRECT", studentProgress, null, correctParts, incorrectParts, totalParts); @@ -224,8 +224,8 @@ export const QuizProgressDetails = ({assignment}: {assignment: QuizAssignmentDTO user: user.user as UserSummaryDTO, completed: user.feedback?.complete ?? false, // a list of the correct parts of an answer, one list for each question - correctPartResults: questions.map(q => user.feedback?.questionMarks?.[q?.id ?? -1]?.correct ?? 0), - incorrectPartResults: questions.map(q => user.feedback?.questionMarks?.[q?.id ?? -1]?.incorrect ?? 0), + correctMarkResults: [questions.map(q => user.feedback?.questionMarks?.[q?.id ?? -1]?.correct ?? 0)], + incorrectMarkResults: [questions.map(q => user.feedback?.questionMarks?.[q?.id ?? -1]?.incorrect ?? 0)], notAttemptedPartResults: user.feedback?.complete || user.feedback?.questionMarks !== undefined ? questions.map(q => user.feedback?.questionMarks?.[q?.id ?? -1]?.notAttempted ?? 0) // if the quiz has not been completed (i.e. submitted), then all parts are not attempted diff --git a/src/mocks/data.ts b/src/mocks/data.ts index ff75256957..28f9a5f992 100644 --- a/src/mocks/data.ts +++ b/src/mocks/data.ts @@ -6207,8 +6207,8 @@ export const mockProgress = { "registeredContexts": [], "id": 19 }, - "correctPartResults": null, - "incorrectPartResults": null, + "correctMarkResults": null, + "incorrectMarkResults": null, "questionResults": null, "questionPartResults": null, }, @@ -6226,13 +6226,13 @@ export const mockProgress = { ], "id": 9 }, - "correctPartResults": [ - 6, - 1 + "correctMarkResults": [ + [1,1,1,1,1,1], + [1,0,0] ], - "incorrectPartResults": [ - 0, - 2 + "incorrectMarkResults": [ + [0,0,0,0,0,0], + [0,1,1] ], "questionResults": [ "ALL_CORRECT", @@ -6268,13 +6268,13 @@ export const mockProgress = { ], "id": 8 }, - "correctPartResults": [ - 0, - 0 + "correctMarkResults": [ + [0,0,0,0,0,0], + [0,0,0] ], - "incorrectPartResults": [ - 6, - 0 + "incorrectMarkResults": [ + [1,1,1,1,1,1], + [0,0,0] ], "questionResults": [ "ALL_INCORRECT", From b6d36b61d4467ebbfc3befd5d984cc639cb90fd8 Mon Sep 17 00:00:00 2001 From: Sol Dubock <94075844+sjd210@users.noreply.github.com> Date: Thu, 30 Oct 2025 14:52:22 +0000 Subject: [PATCH 9/9] Switch between parts/marks display on both tables --- .../elements/quiz/QuizProgressCommon.tsx | 54 ++++++++++++------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/app/components/elements/quiz/QuizProgressCommon.tsx b/src/app/components/elements/quiz/QuizProgressCommon.tsx index 530ce946f1..14cbb44c19 100644 --- a/src/app/components/elements/quiz/QuizProgressCommon.tsx +++ b/src/app/components/elements/quiz/QuizProgressCommon.tsx @@ -62,7 +62,7 @@ export function markResultsToPartResults(markResults: number[][] = [], markTotal return markResults.map((marks, i) => { const markTotal = markTotals[i].reduce((acc, curr) => acc + curr, 0); const markObtained = marks.reduce((acc, curr) => acc + curr, 0); - return Math.floor(markTotal / markObtained); + return Math.floor(markObtained / markTotal); }); }; @@ -367,6 +367,12 @@ export function ResultsTable({ {sortedProgress.map((studentProgress, index) => { const fullAccess = isAuthorisedFullAccess(studentProgress); const internalCellSpacing = isPhy && isAssignment ? "py-1" : "py-3"; + + const correctPartResults = studentProgress.questionPartResults?.map(statuses => statuses.reduce((acc, status) => acc + (status === "CORRECT" ? 1 : 0), 0)) || []; + const incorrectPartResults = studentProgress.questionPartResults?.map(statuses => statuses.reduce((acc, status) => acc + (status === "INCORRECT" ? 1 : 0), 0)) || []; + const correctPartOrMarkCount = (fullAccess && pageSettings?.displayIndividualMarks) ? studentProgress.correctQuestionMarksCount : correctPartResults.reduce((acc, curr) => acc + curr, 0); + const incorrectPartOrMarkCount = (fullAccess && pageSettings?.displayIndividualMarks) ? studentProgress.incorrectQuestionMarksCount : incorrectPartResults.reduce((acc, curr) => acc + curr, 0); + return {fullAccess && pageSettings?.isTeacher ? @@ -415,22 +421,24 @@ export function ResultsTable({ ? studentProgress.correctQuestionPagesCount : studentProgress.questionResults?.filter(r => r !== CompletionState.NOT_ATTEMPTED).length ?? 0 : pageSettings?.attemptedOrCorrect === "CORRECT" - ? studentProgress.correctQuestionMarksCount - : studentProgress.correctQuestionMarksCount + studentProgress.incorrectQuestionMarksCount, + ? correctPartOrMarkCount + : correctPartOrMarkCount + incorrectPartOrMarkCount, questions.length, !!pageSettings?.formatAsPercentage ) : "" } - {/* total marks */} + {/* total parts/marks */} {isPhy && isAssignment && {fullAccess ? formatMark( pageSettings?.attemptedOrCorrect === "CORRECT" - ? studentProgress.correctQuestionMarksCount - : studentProgress.correctQuestionMarksCount + studentProgress.incorrectQuestionMarksCount, - studentProgress.markTotals?.reduce((acc, arr) => acc + arr.reduce((a, b) => a + b, 0), 0) ?? 0, + ? correctPartOrMarkCount + : correctPartOrMarkCount + incorrectPartOrMarkCount, + pageSettings?.displayIndividualMarks + ? studentProgress.markTotals?.reduce((acc, arr) => acc + arr.reduce((a, b) => a + b, 0), 0) ?? 0 + : assignmentTotalQuestionParts, !!pageSettings?.formatAsPercentage ) : "" @@ -446,9 +454,15 @@ export function ResultsTable({ ? siteSpecific( formatMark( pageSettings?.attemptedOrCorrect === "CORRECT" - ? (studentProgress.correctMarkResults || [])[index].reduce((a, b) => a + b, 0) - : (studentProgress.correctMarkResults || [])[index].concat((studentProgress.incorrectMarkResults || [])[index]).reduce((a, b) => a + b, 0), - studentProgress.markTotals![index].reduce((a, b) => a + b, 0) ?? 0, + ? pageSettings?.displayIndividualMarks + ? studentProgress.correctMarkResults![index].reduce((a, b) => a + b, 0) ?? 0 + : correctPartResults[index] + : pageSettings?.displayIndividualMarks + ? studentProgress.correctMarkResults![index].concat(studentProgress.incorrectMarkResults![index]).reduce((a, b) => a + b, 0) ?? 0 + : correctPartResults[index] + incorrectPartResults[index], + pageSettings?.displayIndividualMarks + ? studentProgress.markTotals![index].reduce((a, b) => a + b, 0) ?? 0 + : studentProgress.markTotals![index].length, !!pageSettings?.formatAsPercentage ), getAssignmentQuestionCorrectnessIcon((studentProgress.questionResults || [])[index], pageSettings?.attemptedOrCorrect || "CORRECT")) @@ -561,11 +575,11 @@ export function ResultsTablePartBreakdown({ defaultOrder={"totalQuestionPercentage"} reverseOrder={"totalQuestionPercentage"} currentOrder={sortOrder} setOrder={toggleSort} reversed={reverseOrder} - label={"Total correct"} + label={pageSettings?.displayIndividualMarks ? "Total marks awarded" : "Total correct"} > {siteSpecific(
- Marks + {pageSettings?.displayIndividualMarks ? "Marks" : "Parts"} (total)
, "Correct" @@ -576,11 +590,11 @@ export function ResultsTablePartBreakdown({ defaultOrder={"totalAttemptedQuestionPercentage"} reverseOrder={"totalAttemptedQuestionPercentage"} currentOrder={sortOrder} setOrder={toggleSort} reversed={reverseOrder} - label={"Total attempted"} + label={pageSettings?.displayIndividualMarks ? "Total marks attempted" : "Total correct"} > {siteSpecific(
- Marks + {pageSettings?.displayIndividualMarks ? "Marks" : "Parts"} (total)
, "Attempted" @@ -644,10 +658,14 @@ export function ResultsTablePartBreakdown({ {/* main data */} {studentProgress.questionPartResults && - studentProgress.questionPartResults[questionIndex].map((_q, questionPartIndex) => { - const correctMarkResult = markPartNumerator[questionPartIndex] ?? 0; - const markTotal = markPartDenominator[questionPartIndex] ?? 0; - return {formatMark(correctMarkResult, markTotal, !!pageSettings?.formatAsPercentage)}; + studentProgress.questionPartResults[questionIndex].map((questionPartResult, questionPartIndex) => { + if (pageSettings?.displayIndividualMarks) { + const correctMarkResult = markPartNumerator[questionPartIndex] ?? 0; + const markTotal = markPartDenominator[questionPartIndex] ?? 0; + return {formatMark(correctMarkResult, markTotal, !!pageSettings?.formatAsPercentage)}; + } else { + return {getQuizQuestionPartCorrectnessIcon(questionPartResult)}; + } }) } ;