diff --git a/.secrets.baseline b/.secrets.baseline index 790eaa95..49373ff5 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": null, "lines": null }, - "generated_at": "2025-10-09T10:00:02Z", + "generated_at": "2025-10-09T10:36:06Z", "plugins_used": [ { "name": "AWSKeyDetector" diff --git a/apps/api/src/api/assignment/v2/services/version-management.service.ts b/apps/api/src/api/assignment/v2/services/version-management.service.ts index 08864185..d5ed2967 100644 --- a/apps/api/src/api/assignment/v2/services/version-management.service.ts +++ b/apps/api/src/api/assignment/v2/services/version-management.service.ts @@ -645,7 +645,8 @@ export class VersionManagementService { graded: versionToRestore.graded, numAttempts: versionToRestore.numAttempts, attemptsBeforeCoolDown: versionToRestore.attemptsBeforeCoolDown, - retakeAttemptCoolDownMinutes: versionToRestore.retakeAttemptCoolDownMinutes, + retakeAttemptCoolDownMinutes: + versionToRestore.retakeAttemptCoolDownMinutes, allotedTimeMinutes: versionToRestore.allotedTimeMinutes, attemptsPerTimeRange: versionToRestore.attemptsPerTimeRange, attemptsTimeRangeHours: versionToRestore.attemptsTimeRangeHours, @@ -1643,7 +1644,8 @@ export class VersionManagementService { graded: sourceVersion.graded, numAttempts: sourceVersion.numAttempts, attemptsBeforeCoolDown: sourceVersion.attemptsBeforeCoolDown, - retakeAttemptCoolDownMinutes: sourceVersion.retakeAttemptCoolDownMinutes, + retakeAttemptCoolDownMinutes: + sourceVersion.retakeAttemptCoolDownMinutes, allotedTimeMinutes: sourceVersion.allotedTimeMinutes, attemptsPerTimeRange: sourceVersion.attemptsPerTimeRange, attemptsTimeRangeHours: sourceVersion.attemptsTimeRangeHours, @@ -2105,9 +2107,11 @@ export class VersionManagementService { numAttempts: draftData.assignmentData.numAttempts ?? assignment.numAttempts, attemptsBeforeCoolDown: - draftData.assignmentData.attemptsBeforeCoolDown ?? assignment.attemptsBeforeCoolDown, + draftData.assignmentData.attemptsBeforeCoolDown ?? + assignment.attemptsBeforeCoolDown, retakeAttemptCoolDownMinutes: - draftData.assignmentData.retakeAttemptCoolDownMinutes ?? assignment.retakeAttemptCoolDownMinutes, + draftData.assignmentData.retakeAttemptCoolDownMinutes ?? + assignment.retakeAttemptCoolDownMinutes, allotedTimeMinutes: draftData.assignmentData.allotedTimeMinutes ?? assignment.allotedTimeMinutes, diff --git a/apps/web/app/author/[assignmentId]/review/page.tsx b/apps/web/app/author/[assignmentId]/review/page.tsx index f34c9e2d..97d3a810 100644 --- a/apps/web/app/author/[assignmentId]/review/page.tsx +++ b/apps/web/app/author/[assignmentId]/review/page.tsx @@ -33,6 +33,23 @@ import { } from "@heroicons/react/24/solid"; import { QuestionAuthorStore } from "@/config/types"; import ExportModal, { ExportOptions } from "../../(components)/ExportModal"; +import { omit } from "../../../../lib/utils"; + +const CONFIG_KEYS_TO_OMIT = [ + "errors", + "updatedAt", + "id", + "name", + "introduction", + "instructions", + "gradingCriteriaOverview", + "type", + "questionOrder", + "published", + "languageCode", + "currentVersionId", + "questions", +]; // Helper function to determine if a validation error is question-related const isQuestionRelatedValidationError = (message: string): boolean => { @@ -744,31 +761,7 @@ function Component() { const [isExportModalOpen, setIsExportModalOpen] = useState(false); const [isIssuesModalOpen, setIsIssuesModalOpen] = useState(false); - const [ - graded, - allotedTimeMinutes, - timeEstimateMinutes, - numAttempts, - attemptsBeforeCoolDown, - retakeAttemptCoolDownMinutes, - passingGrade, - displayOrder, - questionDisplay, - numberOfQuestionsPerAttempt, - strictTimeLimit, - ] = useAssignmentConfig((state) => [ - state.graded, - state.allotedTimeMinutes, - state.timeEstimateMinutes, - state.numAttempts, - state.attemptsBeforeCoolDown, - state.retakeAttemptCoolDownMinutes, - state.passingGrade, - state.displayOrder, - state.questionDisplay, - state.numberOfQuestionsPerAttempt, - state.strictTimeLimit, - ]); + const assignmentConfig = useAssignmentConfig((state) => state); const [ introduction, @@ -1124,19 +1117,7 @@ function Component() { } if (exportOptions.includeConfig) { - exportData.config = { - graded, - allotedTimeMinutes, - timeEstimateMinutes, - numAttempts, - attemptsBeforeCoolDown, - retakeAttemptCoolDownMinutes, - passingGrade, - displayOrder, - questionDisplay, - numberOfQuestionsPerAttempt, - strictTimeLimit, - }; + exportData.config = omit(assignmentConfig, CONFIG_KEYS_TO_OMIT); } if (exportOptions.includeFeedbackConfig) { @@ -1698,7 +1679,7 @@ function Component() { router.push(`/author/${activeAssignmentId}/config`) } @@ -1714,8 +1695,8 @@ function Component() { : "No time limit" } after={ - allotedTimeMinutes - ? `${allotedTimeMinutes} minutes` + assignmentConfig.allotedTimeMinutes + ? `${assignmentConfig.allotedTimeMinutes} minutes` : "No time limit" } /> @@ -1730,8 +1711,8 @@ function Component() { : "Not set" } after={ - timeEstimateMinutes - ? `${timeEstimateMinutes} minutes` + assignmentConfig.timeEstimateMinutes + ? `${assignmentConfig.timeEstimateMinutes} minutes` : "Not set" } /> @@ -1745,7 +1726,11 @@ function Component() { ? "Unlimited" : originalAssignment.numAttempts } - after={numAttempts === -1 ? "Unlimited" : numAttempts} + after={ + assignmentConfig.numAttempts === -1 + ? "Unlimited" + : assignmentConfig.numAttempts + } /> )} @@ -1753,7 +1738,7 @@ function Component() { )} @@ -1761,7 +1746,23 @@ function Component() { + )} + + {changes.attemptsBeforeCoolDown && ( + + )} + + {changes.retakeAttemptCoolDownMinutes && ( + )} @@ -1769,7 +1770,7 @@ function Component() { )} @@ -1777,7 +1778,7 @@ function Component() { )} @@ -1788,7 +1789,10 @@ function Component() { /_/g, " ", )} - after={questionDisplay?.replace(/_/g, " ")} + after={assignmentConfig.questionDisplay?.replace( + /_/g, + " ", + )} /> )} @@ -1796,7 +1800,7 @@ function Component() { )} diff --git a/apps/web/lib/utils.ts b/apps/web/lib/utils.ts index 98c10d33..3d5bd5bd 100644 --- a/apps/web/lib/utils.ts +++ b/apps/web/lib/utils.ts @@ -187,6 +187,13 @@ export const getSubmitButtonStatus = ( return { disabled: false, reason: null }; }; + export const generateTempQuestionId = (): number => { return Math.floor(Math.random() * 2e9); }; + +export const omit = (obj: object, keys: string[]): object => { + return Object.fromEntries( + Object.entries(obj).filter(([k]) => !keys.includes(k)), + ); +}; diff --git a/apps/web/stores/author.ts b/apps/web/stores/author.ts index 86603b6f..5c552db8 100644 --- a/apps/web/stores/author.ts +++ b/apps/web/stores/author.ts @@ -16,6 +16,7 @@ import { shallow } from "zustand/shallow"; import { createWithEqualityFn } from "zustand/traditional"; import { withUpdatedAt } from "./middlewares"; import { DraftSummary, VersionSummary } from "@/lib/author"; +import { config } from "process"; const NON_PERSIST_KEYS = new Set([ // version control state "versions",