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 : `