feat: live class sessions, CE workflow, and docs (#683)
Adds live-class session scheduling on lessons (join link, date/time, timezone) with automatic 24h and 1h reminder emails plus a calendar invite (.ics), a time-change notification with an updated invite, a teacher-authored welcome email and session invite on enrollment, and a "Notify students" quiz nudge. LMS gets an upcoming live-sessions card and Join buttons, plus a reusable live-session card component (3 states) in @cio/ui with a Storybook story. The sidebar content tree now reflects sequential progression locking like the content list, and the course-completion confetti regression is fixed. Org-based emails no longer reference ClassroomIO by name. Docs add live-class, welcome-email, and course-progression guides, expand the certificates guide (design, signatures, corrected labels), move plan-required callouts to the top, flatten how-to-guides to the docs root with redirects, and add screenshots. Includes an add-docs-image skill.
This commit is contained in:
@@ -350,13 +350,14 @@
|
||||
return typeIds.length > 0 && typeIds.every((id) => isAutoGradableQuestionType(getQuestionTypeKeyFromId(id)));
|
||||
}
|
||||
|
||||
/** When true, every question must have points > 0 before save */
|
||||
const requiresPositivePointsForAutoGrade = $derived(
|
||||
isSelfPacedCourse && isExerciseFullyAutoGradable(activeQuestionTypeIds)
|
||||
);
|
||||
const isFullyAutoGradable = $derived(isExerciseFullyAutoGradable(activeQuestionTypeIds));
|
||||
|
||||
/** When true, every question must have points > 0 before save (for meaningful auto-grading) */
|
||||
const requiresPositivePointsForAutoGrade = $derived(isFullyAutoGradable);
|
||||
|
||||
const teacherAutoGradeBadge = $derived.by(() => {
|
||||
if ($isOrgStudent || !isSelfPacedCourse || activeQuestionTypeIds.length === 0) return null;
|
||||
return isExerciseFullyAutoGradable(activeQuestionTypeIds) ? ('auto' as const) : ('manual' as const);
|
||||
if ($isOrgStudent || isPublicCourse || activeQuestionTypeIds.length === 0) return null;
|
||||
return isFullyAutoGradable ? ('auto' as const) : ('manual' as const);
|
||||
});
|
||||
|
||||
async function scrollToExerciseElement(elementId: string) {
|
||||
@@ -498,6 +499,16 @@
|
||||
{$t('course.navItem.lessons.exercises.all_exercises.reorder')}
|
||||
</DropdownMenu.Item>
|
||||
{/if}
|
||||
<DropdownMenu.Item
|
||||
disabled={!courseApi.course?.id || !exerciseId}
|
||||
onclick={() => {
|
||||
if (courseApi.course?.id && exerciseId) {
|
||||
exerciseApi.notifyStudents(courseApi.course.id, exerciseId);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{$t('course.navItem.lessons.exercises.all_exercises.notify.action')}
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item
|
||||
class="text-red-600 focus:text-red-600 dark:text-red-400"
|
||||
|
||||
Reference in New Issue
Block a user