From 8e02f174c29e16d1f8ff41d7eadfee691194125e Mon Sep 17 00:00:00 2001 From: Guy Sandler Date: Mon, 19 Oct 2026 18:40:00 -0700 Subject: [PATCH] Peer Review in the Better Todo hopefully --- js/content.js | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/js/content.js b/js/content.js index 643a4b5..4971066 100644 --- a/js/content.js +++ b/js/content.js @@ -2204,11 +2204,25 @@ function progressFilterDim(courseId) { return betterTodoProgressFilter != null && String(courseId) !== String(betterTodoProgressFilter); } // Assignments, quizzes and graded discussions (plus custom planner notes) are tasks. +// Peer Review items arrive as assessment_request (legacy peer reviews) and +// peer_review_sub_assignment (new allocation/grading flows), plus checkpoint +// sub_assignments which should also surface in the todo list. +const TODO_PEER_REVIEW_TYPES = ["assessment_request", "peer_review_sub_assignment"]; +const TODO_SUB_ASSIGNMENT_TYPES = ["sub_assignment"]; function isTodoTaskType(item) { - return item.plannable_type == "assignment" - || item.plannable_type == "planner_note" - || item.plannable_type == "quiz" - || item.plannable_type == "discussion_topic"; + const t = String(item.plannable_type || "").toLowerCase(); + return t === "assignment" + || t === "planner_note" + || t === "quiz" + || t === "discussion_topic" + || TODO_PEER_REVIEW_TYPES.includes(t) + || TODO_SUB_ASSIGNMENT_TYPES.includes(t); +} +function isPeerReviewType(item) { + return TODO_PEER_REVIEW_TYPES.includes(String(item.plannable_type || "").toLowerCase()); +} +function isSubAssignmentType(item) { + return TODO_SUB_ASSIGNMENT_TYPES.includes(String(item.plannable_type || "").toLowerCase()); } // Click filters the todo list to one class; no-op on course pages, toggles off. @@ -3731,13 +3745,21 @@ async function getTodoPreviewText(item) { } let url = null; let field = "description"; - if (type === "assignment") { + const lowType = String(type || "").toLowerCase(); + if (lowType === "assignment") { url = `${domain}/api/v1/courses/${item.course_id}/assignments/${id}`; - } else if (type === "quiz") { + } else if (lowType === "quiz") { url = `${domain}/api/v1/courses/${item.course_id}/quizzes/${id}`; - } else if (type === "discussion_topic" || type === "announcement") { + } else if (lowType === "discussion_topic" || lowType === "announcement") { url = `${domain}/api/v1/courses/${item.course_id}/discussion_topics/${id}`; field = "message"; + } else if (TODO_PEER_REVIEW_TYPES.includes(lowType) || TODO_SUB_ASSIGNMENT_TYPES.includes(lowType)) { + // Peer review / sub-assignment planner payloads already carry the + // assignment description inline; avoid an extra API call. + const raw = item.plannable?.description || item.plannable?.message || item.plannable?.details || ""; + const text = stripHtmlPreview(raw) || chrome.i18n.getMessage("no_details") || "No details given"; + todoPreviewCache.set(key, text); + return text; } if (!url) { const text = getMsg("preview_unavailable", "No preview available"); @@ -3794,6 +3816,8 @@ function attachTodoHoverPreview(anchor, item) { // Quiz / discussion row icons, sharing the assignment icon's fill variable. const TODO_QUIZ_ICON_SVG = ''; +const TODO_PEER_REVIEW_ICON_SVG = ''; +const TODO_SUB_ASSIGNMENT_ICON_SVG = ''; const TODO_DISCUSSION_ICON_SVG = ''; // Scores: planner items omit the earned score, so it is fetched per course and cached; @@ -3808,7 +3832,8 @@ function formatTodoScoreNumber(n) { function todoGradedBadgeHtml() { return ``; } function todoScoreBadgeHtml(item) { - if (item.plannable_type == "planner_note" || item.planner_override?.custom === true) return ""; + const _low = String(item.plannable_type || "").toLowerCase(); + if (_low === "planner_note" || TODO_PEER_REVIEW_TYPES.includes(_low) || TODO_SUB_ASSIGNMENT_TYPES.includes(_low) || item.planner_override?.custom === true) return ""; const points = item.plannable?.points_possible; if (points == null) return ""; const pts = formatTodoScoreNumber(points); @@ -3831,7 +3856,8 @@ async function loadTodoScores(items) { if (options.todo_show_scores !== true) return; const byCourse = new Map(); for (const item of items) { - if (item.plannable_type == "planner_note" || item.planner_override?.custom === true) continue; + const _lt = String(item.plannable_type || "").toLowerCase(); + if (_lt === "planner_note" || TODO_PEER_REVIEW_TYPES.includes(_lt) || TODO_SUB_ASSIGNMENT_TYPES.includes(_lt) || item.planner_override?.custom === true) continue; if (item.plannable?.points_possible == null) continue; const cid = item.course_id ?? item.context_id; if (cid == null) continue; @@ -3980,7 +4006,7 @@ function populateAssignments(iscompleted = false) { ? ` ` - : (item.plannable_type == "quiz" ? TODO_QUIZ_ICON_SVG : item.plannable_type == "discussion_topic" ? TODO_DISCUSSION_ICON_SVG : ` + : (isPeerReviewType(item) ? TODO_PEER_REVIEW_ICON_SVG : isSubAssignmentType(item) ? TODO_SUB_ASSIGNMENT_ICON_SVG : item.plannable_type == "quiz" ? TODO_QUIZ_ICON_SVG : item.plannable_type == "discussion_topic" ? TODO_DISCUSSION_ICON_SVG : `