@anantagnanam/lms 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -2
- package/astro/assignment-player.ts +231 -0
- package/astro/client.ts +24 -1
- package/astro/components/AssignmentFeedback.astro +32 -0
- package/astro/components/AssignmentRubric.astro +27 -0
- package/astro/components/LearnerDashboard.astro +3 -0
- package/astro/components/LearningShell.astro +6 -0
- package/astro/components/LessonContent.astro +16 -2
- package/astro/components/LessonPlayer.astro +126 -38
- package/astro/draft-queue.ts +95 -0
- package/astro/media-player.ts +26 -1
- package/astro/pages/author-preview.astro +2 -0
- package/astro/pages/study.astro +180 -0
- package/astro/quiz-drafts.ts +12 -76
- package/astro/study-tools.ts +386 -0
- package/astro/styles.css +18 -0
- package/astro/transcript-search.ts +56 -0
- package/dist/admin.js +172 -12
- package/dist/admin.js.map +1 -1
- package/dist/assignments-CsuAjxGO.js +75 -0
- package/dist/assignments-CsuAjxGO.js.map +1 -0
- package/dist/astro.js +1 -0
- package/dist/astro.js.map +1 -1
- package/dist/{constants-Cnx7k82Z.js → constants-DyQbwNbP.js} +2 -2
- package/dist/{constants-Cnx7k82Z.js.map → constants-DyQbwNbP.js.map} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/runtime.d.ts +26 -5
- package/dist/runtime.js +307 -16
- package/dist/runtime.js.map +1 -1
- package/dist/schemas.d.ts +69 -3
- package/dist/schemas.js +47 -6
- package/dist/schemas.js.map +1 -1
- package/dist/server.d.ts +9 -2
- package/dist/server.js +6 -3
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +67 -2
- package/package.json +1 -1
- package/dist/errors-ChzJS9al.js +0 -16
- package/dist/errors-ChzJS9al.js.map +0 -1
package/dist/admin.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as PLUGIN_ID, t as API_BASE } from "./constants-
|
|
1
|
+
import { r as PLUGIN_ID, t as API_BASE } from "./constants-DyQbwNbP.js";
|
|
2
2
|
import { assignmentSchema, courseDataSchema, lessonSchema, moduleSchema, questionSchema, quizSchema, settingsSchema } from "./schemas.js";
|
|
3
3
|
import { n as enrollmentCsvLines, t as enrollmentCsvHeader } from "./csv-DKq_4OWU.js";
|
|
4
4
|
import { useEffect, useState } from "react";
|
|
@@ -1117,6 +1117,83 @@ function ContentPicker({ value, onChange }) {
|
|
|
1117
1117
|
})
|
|
1118
1118
|
] });
|
|
1119
1119
|
}
|
|
1120
|
+
function RubricEditor({ assignment, update }) {
|
|
1121
|
+
const rubric = assignment.rubric ?? [];
|
|
1122
|
+
const change = (criteria, removed = false) => {
|
|
1123
|
+
const maxPoints = criteria.length ? criteria.reduce((sum, item) => sum + item.maxPoints, 0) : assignment.maxPoints;
|
|
1124
|
+
update({
|
|
1125
|
+
...assignment,
|
|
1126
|
+
rubric: criteria,
|
|
1127
|
+
maxPoints,
|
|
1128
|
+
passingPoints: removed ? Math.min(assignment.passingPoints, maxPoints) : assignment.passingPoints
|
|
1129
|
+
});
|
|
1130
|
+
};
|
|
1131
|
+
return /* @__PURE__ */ jsxs("section", { children: [
|
|
1132
|
+
/* @__PURE__ */ jsx("h3", { children: "Grading rubric" }),
|
|
1133
|
+
/* @__PURE__ */ jsx("p", { children: "Describe what learners should demonstrate. Criterion points add up to the assignment maximum. Submitted work keeps its original rubric." }),
|
|
1134
|
+
rubric.map((criterion, index) => /* @__PURE__ */ jsxs("fieldset", {
|
|
1135
|
+
className: "lms-resource",
|
|
1136
|
+
children: [
|
|
1137
|
+
/* @__PURE__ */ jsxs("legend", { children: ["Criterion ", index + 1] }),
|
|
1138
|
+
/* @__PURE__ */ jsx(Field, {
|
|
1139
|
+
label: "Criterion title",
|
|
1140
|
+
children: /* @__PURE__ */ jsx("input", {
|
|
1141
|
+
required: true,
|
|
1142
|
+
maxLength: 200,
|
|
1143
|
+
value: criterion.title,
|
|
1144
|
+
onChange: (event) => change(rubric.map((item) => item.id === criterion.id ? {
|
|
1145
|
+
...item,
|
|
1146
|
+
title: event.target.value
|
|
1147
|
+
} : item))
|
|
1148
|
+
})
|
|
1149
|
+
}),
|
|
1150
|
+
/* @__PURE__ */ jsx(Field, {
|
|
1151
|
+
label: "What earns these points",
|
|
1152
|
+
children: /* @__PURE__ */ jsx("textarea", {
|
|
1153
|
+
rows: 3,
|
|
1154
|
+
maxLength: 2e3,
|
|
1155
|
+
value: criterion.description,
|
|
1156
|
+
onChange: (event) => change(rubric.map((item) => item.id === criterion.id ? {
|
|
1157
|
+
...item,
|
|
1158
|
+
description: event.target.value
|
|
1159
|
+
} : item))
|
|
1160
|
+
})
|
|
1161
|
+
}),
|
|
1162
|
+
/* @__PURE__ */ jsx(Field, {
|
|
1163
|
+
label: "Maximum criterion points",
|
|
1164
|
+
children: /* @__PURE__ */ jsx("input", {
|
|
1165
|
+
type: "number",
|
|
1166
|
+
required: true,
|
|
1167
|
+
min: 1,
|
|
1168
|
+
max: 1e3 - (assignment.maxPoints - criterion.maxPoints),
|
|
1169
|
+
step: 1,
|
|
1170
|
+
value: criterion.maxPoints,
|
|
1171
|
+
onChange: (event) => change(rubric.map((item) => item.id === criterion.id ? {
|
|
1172
|
+
...item,
|
|
1173
|
+
maxPoints: Number(event.target.value)
|
|
1174
|
+
} : item))
|
|
1175
|
+
})
|
|
1176
|
+
}),
|
|
1177
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
1178
|
+
danger: true,
|
|
1179
|
+
onClick: () => change(rubric.filter((item) => item.id !== criterion.id), true),
|
|
1180
|
+
children: ["Remove criterion ", index + 1]
|
|
1181
|
+
})
|
|
1182
|
+
]
|
|
1183
|
+
}, criterion.id)),
|
|
1184
|
+
/* @__PURE__ */ jsx(Button, {
|
|
1185
|
+
disabled: rubric.length >= 20 || rubric.length > 0 && assignment.maxPoints >= 1e3,
|
|
1186
|
+
onClick: () => change([...rubric, {
|
|
1187
|
+
id: crypto.randomUUID(),
|
|
1188
|
+
title: "New criterion",
|
|
1189
|
+
description: "",
|
|
1190
|
+
maxPoints: rubric.length ? Math.min(10, 1e3 - assignment.maxPoints) : assignment.maxPoints
|
|
1191
|
+
}]),
|
|
1192
|
+
children: rubric.length ? "Add criterion" : "Add grading rubric"
|
|
1193
|
+
}),
|
|
1194
|
+
/* @__PURE__ */ jsx("p", { children: rubric.length ? `${rubric.length} ${rubric.length === 1 ? "criterion" : "criteria"} · ${assignment.maxPoints} points total (maximum 1000). Review the passing points when changing scores.` : "Without a rubric, graders enter a single overall score." })
|
|
1195
|
+
] });
|
|
1196
|
+
}
|
|
1120
1197
|
function LessonEditor({ lesson, previewUrl, update, remove }) {
|
|
1121
1198
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1122
1199
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -1377,6 +1454,8 @@ function LessonEditor({ lesson, previewUrl, update, remove }) {
|
|
|
1377
1454
|
children: /* @__PURE__ */ jsx("input", {
|
|
1378
1455
|
type: "number",
|
|
1379
1456
|
min: 1,
|
|
1457
|
+
max: 1e3,
|
|
1458
|
+
readOnly: Boolean(lesson.assignment.rubric?.length),
|
|
1380
1459
|
value: lesson.assignment.maxPoints,
|
|
1381
1460
|
onChange: (event) => update({ assignment: {
|
|
1382
1461
|
...lesson.assignment,
|
|
@@ -1389,6 +1468,7 @@ function LessonEditor({ lesson, previewUrl, update, remove }) {
|
|
|
1389
1468
|
children: /* @__PURE__ */ jsx("input", {
|
|
1390
1469
|
type: "number",
|
|
1391
1470
|
min: 1,
|
|
1471
|
+
max: lesson.assignment.maxPoints,
|
|
1392
1472
|
value: lesson.assignment.passingPoints,
|
|
1393
1473
|
onChange: (event) => update({ assignment: {
|
|
1394
1474
|
...lesson.assignment,
|
|
@@ -1419,6 +1499,10 @@ function LessonEditor({ lesson, previewUrl, update, remove }) {
|
|
|
1419
1499
|
allowResubmission: event.target.checked
|
|
1420
1500
|
} })
|
|
1421
1501
|
}), "Allow another submission after a failing grade"]
|
|
1502
|
+
}),
|
|
1503
|
+
/* @__PURE__ */ jsx(RubricEditor, {
|
|
1504
|
+
assignment: lesson.assignment,
|
|
1505
|
+
update: (assignment) => update({ assignment })
|
|
1422
1506
|
})
|
|
1423
1507
|
]
|
|
1424
1508
|
}),
|
|
@@ -2056,7 +2140,9 @@ function AssignmentsPage() {
|
|
|
2056
2140
|
}, !!courseId);
|
|
2057
2141
|
const [selected, setSelected] = useState();
|
|
2058
2142
|
const [points, setPoints] = useState(0);
|
|
2143
|
+
const [rubricScores, setRubricScores] = useState([]);
|
|
2059
2144
|
const [feedback, setFeedback] = useState("");
|
|
2145
|
+
const rubricTotal = rubricScores.reduce((sum, item) => sum + item.points, 0);
|
|
2060
2146
|
const action = useAction();
|
|
2061
2147
|
const grade = (event) => {
|
|
2062
2148
|
event.preventDefault();
|
|
@@ -2067,7 +2153,7 @@ function AssignmentsPage() {
|
|
|
2067
2153
|
lessonId: selected.lessonId,
|
|
2068
2154
|
userId: selected.userId,
|
|
2069
2155
|
submissionId: selected.id,
|
|
2070
|
-
points,
|
|
2156
|
+
...selected.rubric?.length ? { rubricScores } : { points },
|
|
2071
2157
|
feedback
|
|
2072
2158
|
}, "POST");
|
|
2073
2159
|
setSelected(void 0);
|
|
@@ -2107,7 +2193,59 @@ function AssignmentsPage() {
|
|
|
2107
2193
|
/* @__PURE__ */ jsxs("form", {
|
|
2108
2194
|
onSubmit: grade,
|
|
2109
2195
|
children: [
|
|
2110
|
-
/* @__PURE__ */
|
|
2196
|
+
selected.rubric?.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2197
|
+
/* @__PURE__ */ jsx("p", { children: "Score each criterion using the rubric saved with this submission." }),
|
|
2198
|
+
selected.rubric.map((criterion) => {
|
|
2199
|
+
const score = rubricScores.find((item) => item.criterionId === criterion.id);
|
|
2200
|
+
const updateScore = (values) => setRubricScores((items) => items.map((item) => item.criterionId === criterion.id ? {
|
|
2201
|
+
...item,
|
|
2202
|
+
...values
|
|
2203
|
+
} : item));
|
|
2204
|
+
return /* @__PURE__ */ jsxs("fieldset", {
|
|
2205
|
+
className: "lms-resource",
|
|
2206
|
+
children: [
|
|
2207
|
+
/* @__PURE__ */ jsx("legend", { children: criterion.title }),
|
|
2208
|
+
/* @__PURE__ */ jsx("p", {
|
|
2209
|
+
className: "lms-body",
|
|
2210
|
+
children: criterion.description
|
|
2211
|
+
}),
|
|
2212
|
+
/* @__PURE__ */ jsx(Field, {
|
|
2213
|
+
label: `Points for ${criterion.title} (out of ${criterion.maxPoints})`,
|
|
2214
|
+
children: /* @__PURE__ */ jsx("input", {
|
|
2215
|
+
type: "number",
|
|
2216
|
+
required: true,
|
|
2217
|
+
min: 0,
|
|
2218
|
+
max: criterion.maxPoints,
|
|
2219
|
+
step: 1,
|
|
2220
|
+
value: score.points,
|
|
2221
|
+
onChange: (event) => updateScore({ points: Number(event.target.value) })
|
|
2222
|
+
})
|
|
2223
|
+
}),
|
|
2224
|
+
/* @__PURE__ */ jsx(Field, {
|
|
2225
|
+
label: `Feedback for ${criterion.title}`,
|
|
2226
|
+
children: /* @__PURE__ */ jsx("textarea", {
|
|
2227
|
+
rows: 3,
|
|
2228
|
+
maxLength: 2e3,
|
|
2229
|
+
value: score.feedback,
|
|
2230
|
+
onChange: (event) => updateScore({ feedback: event.target.value })
|
|
2231
|
+
})
|
|
2232
|
+
})
|
|
2233
|
+
]
|
|
2234
|
+
}, criterion.id);
|
|
2235
|
+
}),
|
|
2236
|
+
/* @__PURE__ */ jsxs("p", {
|
|
2237
|
+
role: "status",
|
|
2238
|
+
children: [
|
|
2239
|
+
"Total: ",
|
|
2240
|
+
rubricTotal,
|
|
2241
|
+
"/",
|
|
2242
|
+
selected.maxPoints,
|
|
2243
|
+
" · Passing grade:",
|
|
2244
|
+
" ",
|
|
2245
|
+
selected.passingPoints
|
|
2246
|
+
]
|
|
2247
|
+
})
|
|
2248
|
+
] }) : /* @__PURE__ */ jsx(Field, {
|
|
2111
2249
|
label: `Points out of ${selected.maxPoints}`,
|
|
2112
2250
|
help: `Passing grade: ${selected.passingPoints}`,
|
|
2113
2251
|
children: /* @__PURE__ */ jsx("input", {
|
|
@@ -2123,6 +2261,7 @@ function AssignmentsPage() {
|
|
|
2123
2261
|
label: "Feedback",
|
|
2124
2262
|
children: /* @__PURE__ */ jsx("textarea", {
|
|
2125
2263
|
rows: 6,
|
|
2264
|
+
maxLength: 1e4,
|
|
2126
2265
|
value: feedback,
|
|
2127
2266
|
onChange: (event) => setFeedback(event.target.value)
|
|
2128
2267
|
})
|
|
@@ -2164,18 +2303,39 @@ function AssignmentsPage() {
|
|
|
2164
2303
|
rel: "noopener noreferrer",
|
|
2165
2304
|
children: "Open attachment ↗"
|
|
2166
2305
|
}) }),
|
|
2167
|
-
item.status === "graded" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2306
|
+
item.status === "graded" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2307
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
2308
|
+
item.points,
|
|
2309
|
+
"/",
|
|
2310
|
+
item.maxPoints,
|
|
2311
|
+
" points"
|
|
2312
|
+
] }),
|
|
2313
|
+
/* @__PURE__ */ jsx("p", {
|
|
2314
|
+
className: "lms-body",
|
|
2315
|
+
children: item.feedback
|
|
2316
|
+
}),
|
|
2317
|
+
(item.rubric ?? []).map((criterion) => {
|
|
2318
|
+
const score = item.rubricScores?.find((entry) => entry.criterionId === criterion.id);
|
|
2319
|
+
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("strong", { children: [
|
|
2320
|
+
criterion.title,
|
|
2321
|
+
": ",
|
|
2322
|
+
score?.points ?? "—",
|
|
2323
|
+
"/",
|
|
2324
|
+
criterion.maxPoints
|
|
2325
|
+
] }), score?.feedback && /* @__PURE__ */ jsx("p", {
|
|
2326
|
+
className: "lms-body",
|
|
2327
|
+
children: score.feedback
|
|
2328
|
+
})] }, criterion.id);
|
|
2329
|
+
})
|
|
2330
|
+
] }) : /* @__PURE__ */ jsx(Button, {
|
|
2176
2331
|
onClick: () => {
|
|
2177
2332
|
setSelected(item);
|
|
2178
2333
|
setPoints(0);
|
|
2334
|
+
setRubricScores((item.rubric ?? []).map((criterion) => ({
|
|
2335
|
+
criterionId: criterion.id,
|
|
2336
|
+
points: 0,
|
|
2337
|
+
feedback: ""
|
|
2338
|
+
})));
|
|
2179
2339
|
setFeedback("");
|
|
2180
2340
|
},
|
|
2181
2341
|
children: "Review & grade"
|