@things-factory/learning 0.0.0-stage → 10.1.261
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/dist-client/bootstrap.d.ts +2 -0
- package/dist-client/bootstrap.js +4 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/components/learning-assign-form.d.ts +24 -0
- package/dist-client/components/learning-assign-form.js +77 -0
- package/dist-client/components/learning-assign-form.js.map +1 -0
- package/dist-client/components/learning-course-form.d.ts +29 -0
- package/dist-client/components/learning-course-form.js +104 -0
- package/dist-client/components/learning-course-form.js.map +1 -0
- package/dist-client/components/learning-material-form.d.ts +41 -0
- package/dist-client/components/learning-material-form.js +202 -0
- package/dist-client/components/learning-material-form.js.map +1 -0
- package/dist-client/components/learning-question-form.d.ts +33 -0
- package/dist-client/components/learning-question-form.js +142 -0
- package/dist-client/components/learning-question-form.js.map +1 -0
- package/dist-client/components/learning-todo.d.ts +12 -0
- package/dist-client/components/learning-todo.js +43 -0
- package/dist-client/components/learning-todo.js.map +1 -0
- package/dist-client/components/learning-unit-form.d.ts +44 -0
- package/dist-client/components/learning-unit-form.js +151 -0
- package/dist-client/components/learning-unit-form.js.map +1 -0
- package/dist-client/index.d.ts +2 -0
- package/dist-client/index.js +3 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/pages/learning-course-editor.d.ts +63 -0
- package/dist-client/pages/learning-course-editor.js +476 -0
- package/dist-client/pages/learning-course-editor.js.map +1 -0
- package/dist-client/pages/learning-course-list.d.ts +37 -0
- package/dist-client/pages/learning-course-list.js +92 -0
- package/dist-client/pages/learning-course-list.js.map +1 -0
- package/dist-client/pages/learning-enrollment-status.d.ts +65 -0
- package/dist-client/pages/learning-enrollment-status.js +211 -0
- package/dist-client/pages/learning-enrollment-status.js.map +1 -0
- package/dist-client/pages/learning-view.d.ts +63 -0
- package/dist-client/pages/learning-view.js +446 -0
- package/dist-client/pages/learning-view.js.map +1 -0
- package/dist-client/pages/my-learning.d.ts +22 -0
- package/dist-client/pages/my-learning.js +110 -0
- package/dist-client/pages/my-learning.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +21 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-client/utils/learning-api.d.ts +61 -0
- package/dist-client/utils/learning-api.js +85 -0
- package/dist-client/utils/learning-api.js.map +1 -0
- package/dist-client/utils/learning-words.d.ts +20 -0
- package/dist-client/utils/learning-words.js +22 -0
- package/dist-client/utils/learning-words.js.map +1 -0
- package/dist-client/utils/material-source.d.ts +12 -0
- package/dist-client/utils/material-source.js +77 -0
- package/dist-client/utils/material-source.js.map +1 -0
- package/dist-server/activities.d.ts +38 -0
- package/dist-server/activities.js +42 -0
- package/dist-server/activities.js.map +1 -0
- package/dist-server/ai-reads.d.ts +9 -0
- package/dist-server/ai-reads.js +70 -0
- package/dist-server/ai-reads.js.map +1 -0
- package/dist-server/attachment-reader.d.ts +1 -0
- package/dist-server/attachment-reader.js +23 -0
- package/dist-server/attachment-reader.js.map +1 -0
- package/dist-server/index.d.ts +4 -0
- package/dist-server/index.js +33 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/learning-subjects.d.ts +10 -0
- package/dist-server/learning-subjects.js +31 -0
- package/dist-server/learning-subjects.js.map +1 -0
- package/dist-server/role-tasks.d.ts +2 -0
- package/dist-server/role-tasks.js +17 -0
- package/dist-server/role-tasks.js.map +1 -0
- package/dist-server/service/course/course-mutation.d.ts +19 -0
- package/dist-server/service/course/course-mutation.js +177 -0
- package/dist-server/service/course/course-mutation.js.map +1 -0
- package/dist-server/service/course/course-query.d.ts +27 -0
- package/dist-server/service/course/course-query.js +183 -0
- package/dist-server/service/course/course-query.js.map +1 -0
- package/dist-server/service/course/course-question.d.ts +41 -0
- package/dist-server/service/course/course-question.js +116 -0
- package/dist-server/service/course/course-question.js.map +1 -0
- package/dist-server/service/course/course-rules.d.ts +51 -0
- package/dist-server/service/course/course-rules.js +93 -0
- package/dist-server/service/course/course-rules.js.map +1 -0
- package/dist-server/service/course/course-service.d.ts +72 -0
- package/dist-server/service/course/course-service.js +398 -0
- package/dist-server/service/course/course-service.js.map +1 -0
- package/dist-server/service/course/course-type.d.ts +56 -0
- package/dist-server/service/course/course-type.js +202 -0
- package/dist-server/service/course/course-type.js.map +1 -0
- package/dist-server/service/course/course-unit.d.ts +37 -0
- package/dist-server/service/course/course-unit.js +128 -0
- package/dist-server/service/course/course-unit.js.map +1 -0
- package/dist-server/service/course/course-version.d.ts +45 -0
- package/dist-server/service/course/course-version.js +151 -0
- package/dist-server/service/course/course-version.js.map +1 -0
- package/dist-server/service/course/course.d.ts +23 -0
- package/dist-server/service/course/course.js +92 -0
- package/dist-server/service/course/course.js.map +1 -0
- package/dist-server/service/course/index.d.ts +15 -0
- package/dist-server/service/course/index.js +25 -0
- package/dist-server/service/course/index.js.map +1 -0
- package/dist-server/service/course/material-audio.d.ts +1 -0
- package/dist-server/service/course/material-audio.js +43 -0
- package/dist-server/service/course/material-audio.js.map +1 -0
- package/dist-server/service/course/material-draft-mutation.d.ts +13 -0
- package/dist-server/service/course/material-draft-mutation.js +55 -0
- package/dist-server/service/course/material-draft-mutation.js.map +1 -0
- package/dist-server/service/course/material-draft-rules.d.ts +38 -0
- package/dist-server/service/course/material-draft-rules.js +83 -0
- package/dist-server/service/course/material-draft-rules.js.map +1 -0
- package/dist-server/service/course/material-draft-service.d.ts +15 -0
- package/dist-server/service/course/material-draft-service.js +162 -0
- package/dist-server/service/course/material-draft-service.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-mutation.d.ts +11 -0
- package/dist-server/service/enrollment/enrollment-mutation.js +124 -0
- package/dist-server/service/enrollment/enrollment-mutation.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-query.d.ts +24 -0
- package/dist-server/service/enrollment/enrollment-query.js +236 -0
- package/dist-server/service/enrollment/enrollment-query.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-remind.d.ts +1 -0
- package/dist-server/service/enrollment/enrollment-remind.js +45 -0
- package/dist-server/service/enrollment/enrollment-remind.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-service.d.ts +110 -0
- package/dist-server/service/enrollment/enrollment-service.js +427 -0
- package/dist-server/service/enrollment/enrollment-service.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-status.d.ts +53 -0
- package/dist-server/service/enrollment/enrollment-status.js +194 -0
- package/dist-server/service/enrollment/enrollment-status.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-type.d.ts +82 -0
- package/dist-server/service/enrollment/enrollment-type.js +293 -0
- package/dist-server/service/enrollment/enrollment-type.js.map +1 -0
- package/dist-server/service/enrollment/enrollment.d.ts +53 -0
- package/dist-server/service/enrollment/enrollment.js +191 -0
- package/dist-server/service/enrollment/enrollment.js.map +1 -0
- package/dist-server/service/enrollment/index.d.ts +15 -0
- package/dist-server/service/enrollment/index.js +26 -0
- package/dist-server/service/enrollment/index.js.map +1 -0
- package/dist-server/service/enrollment/learning-ai.d.ts +45 -0
- package/dist-server/service/enrollment/learning-ai.js +93 -0
- package/dist-server/service/enrollment/learning-ai.js.map +1 -0
- package/dist-server/service/enrollment/learning-documents.d.ts +7 -0
- package/dist-server/service/enrollment/learning-documents.js +159 -0
- package/dist-server/service/enrollment/learning-documents.js.map +1 -0
- package/dist-server/service/enrollment/learning-outcome.d.ts +10 -0
- package/dist-server/service/enrollment/learning-outcome.js +16 -0
- package/dist-server/service/enrollment/learning-outcome.js.map +1 -0
- package/dist-server/service/enrollment/progress-rules.d.ts +119 -0
- package/dist-server/service/enrollment/progress-rules.js +132 -0
- package/dist-server/service/enrollment/progress-rules.js.map +1 -0
- package/dist-server/service/enrollment/quiz-attempt.d.ts +34 -0
- package/dist-server/service/enrollment/quiz-attempt.js +105 -0
- package/dist-server/service/enrollment/quiz-attempt.js.map +1 -0
- package/dist-server/service/enrollment/unit-progress.d.ts +34 -0
- package/dist-server/service/enrollment/unit-progress.js +134 -0
- package/dist-server/service/enrollment/unit-progress.js.map +1 -0
- package/dist-server/service/index.d.ts +14 -0
- package/dist-server/service/index.js +43 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/package.json +57 -4
- package/things-factory.config.js +14 -0
- package/translations/en.json +278 -0
- package/translations/es.json +278 -0
- package/translations/ja.json +278 -0
- package/translations/ko.json +278 -0
- package/translations/ms.json +278 -0
- package/translations/zh.json +278 -0
- package/README.md +0 -3
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ENROLLMENT_STATES = void 0;
|
|
4
|
+
exports.rowsOf = rowsOf;
|
|
5
|
+
exports.headedDepartmentsOf = headedDepartmentsOf;
|
|
6
|
+
exports.statusOnly = statusOnly;
|
|
7
|
+
exports.completionRegister = completionRegister;
|
|
8
|
+
exports.teamReachOf = teamReachOf;
|
|
9
|
+
exports.reachOf = reachOf;
|
|
10
|
+
exports.enrollmentPage = enrollmentPage;
|
|
11
|
+
exports.enrollmentStateCounts = enrollmentStateCounts;
|
|
12
|
+
/*
|
|
13
|
+
* Where enrolments stand, for managers and department heads (ADR-0194 decisions 10, 11): every enrolment of a course or
|
|
14
|
+
* a source with its progress and evidence for a manager (`course` query); for a department head, whether each person
|
|
15
|
+
* of their departments is done - status and days only, never a score or an attempt.
|
|
16
|
+
*/
|
|
17
|
+
const typeorm_1 = require("typeorm");
|
|
18
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
19
|
+
const organization_1 = require("@things-factory/organization");
|
|
20
|
+
const shell_1 = require("@things-factory/shell");
|
|
21
|
+
const course_1 = require("../course/course");
|
|
22
|
+
const course_unit_1 = require("../course/course-unit");
|
|
23
|
+
const course_version_1 = require("../course/course-version");
|
|
24
|
+
const course_service_1 = require("../course/course-service");
|
|
25
|
+
const enrollment_1 = require("./enrollment");
|
|
26
|
+
const enrollment_service_1 = require("./enrollment-service");
|
|
27
|
+
const progress_rules_1 = require("./progress-rules");
|
|
28
|
+
const unit_progress_1 = require("./unit-progress");
|
|
29
|
+
/** The working employee record of each user given - for the department a row names. */
|
|
30
|
+
async function employeesOf(tx, domain, userIds) {
|
|
31
|
+
if (!userIds.length)
|
|
32
|
+
return new Map();
|
|
33
|
+
const rows = await tx.getRepository(organization_1.Employee).find({ where: { domain: { id: domain.id }, user: { id: (0, typeorm_1.In)(userIds) } }, relations: ['department'] });
|
|
34
|
+
const out = new Map();
|
|
35
|
+
for (const row of rows)
|
|
36
|
+
if (row.active !== false && (!out.has(row.userId) || out.get(row.userId).active === false))
|
|
37
|
+
out.set(row.userId, row);
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
/** The rows of the enrolments given - each with its person, course, department, state today and units done. */
|
|
41
|
+
async function rowsOf(tx, domain, enrollments) {
|
|
42
|
+
if (!enrollments.length)
|
|
43
|
+
return [];
|
|
44
|
+
const today = (0, enrollment_service_1.todayIn)(domain);
|
|
45
|
+
const users = await tx.getRepository(auth_base_1.User).find({ where: { id: (0, typeorm_1.In)([...new Set(enrollments.map(one => one.userId))]) } });
|
|
46
|
+
const courses = await tx.getRepository(course_1.Course).find({ where: { id: (0, typeorm_1.In)([...new Set(enrollments.map(one => one.courseId))]) } });
|
|
47
|
+
const employees = await employeesOf(tx, domain, users.map(one => one.id));
|
|
48
|
+
const versionIds = new Set();
|
|
49
|
+
const shown = new Map();
|
|
50
|
+
for (const enrollment of enrollments) {
|
|
51
|
+
const id = enrollment.versionId ?? (await (0, course_service_1.publishedVersionOf)(tx, domain, enrollment.courseId))?.id ?? null;
|
|
52
|
+
shown.set(enrollment.id, id);
|
|
53
|
+
if (id)
|
|
54
|
+
versionIds.add(id);
|
|
55
|
+
}
|
|
56
|
+
const versions = versionIds.size ? await tx.getRepository(course_version_1.CourseVersion).find({ where: { id: (0, typeorm_1.In)([...versionIds]) }, withDeleted: true }) : [];
|
|
57
|
+
const units = versionIds.size ? (await tx.getRepository(course_unit_1.CourseUnit).find({ where: { version: { id: (0, typeorm_1.In)([...versionIds]) } } })).filter(progress_rules_1.counts) : [];
|
|
58
|
+
const progress = await tx.getRepository(unit_progress_1.UnitProgress).find({ where: { enrollment: { id: (0, typeorm_1.In)(enrollments.map(one => one.id)) } } });
|
|
59
|
+
return enrollments.map(enrollment => {
|
|
60
|
+
const versionId = shown.get(enrollment.id);
|
|
61
|
+
const mine = units.filter(unit => unit.versionId === versionId);
|
|
62
|
+
return {
|
|
63
|
+
enrollment,
|
|
64
|
+
user: users.find(one => one.id === enrollment.userId) ?? null,
|
|
65
|
+
course: courses.find(one => one.id === enrollment.courseId) ?? null,
|
|
66
|
+
departmentName: employees.get(enrollment.userId)?.department?.name ?? null,
|
|
67
|
+
state: (0, progress_rules_1.overdue)(enrollment, today) ? 'OVERDUE' : enrollment.status,
|
|
68
|
+
units: mine.length,
|
|
69
|
+
unitsDone: mine.filter(unit => progress.some(one => one.enrollmentId === enrollment.id && one.unitId === unit.id && one.doneAt)).length,
|
|
70
|
+
versionNumber: enrollment.versionId ? (versions.find(one => one.id === enrollment.versionId)?.number ?? null) : null
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/** The departments the request's person heads, with those under them - none for anyone else. */
|
|
75
|
+
async function headedDepartmentsOf(context) {
|
|
76
|
+
const { domain, user } = context.state;
|
|
77
|
+
const tx = (0, course_service_1.learningManagerOf)(context);
|
|
78
|
+
const me = (await employeesOf(tx, domain, [user.id])).get(user.id);
|
|
79
|
+
if (!me)
|
|
80
|
+
return [];
|
|
81
|
+
const managed = await tx.getRepository(organization_1.Department).find({ where: { domain: { id: domain.id }, manager: { id: me.id } } });
|
|
82
|
+
if (!managed.length)
|
|
83
|
+
return [];
|
|
84
|
+
return (0, organization_1.withDescendants)(managed.map(one => one.id), await (0, organization_1.departmentTreeOf)(domain, tx));
|
|
85
|
+
}
|
|
86
|
+
/** An enrolment as a department head reads it - where it stands and its days, nothing of how it went. */
|
|
87
|
+
function statusOnly(enrollment) {
|
|
88
|
+
const { score, attempts, learnedSeconds, acknowledgedAt, certificateNo, cancelReason, ...kept } = enrollment;
|
|
89
|
+
return { ...kept, score: null, attempts: null, learnedSeconds: null, acknowledgedAt: null, certificateNo: null, cancelReason: null };
|
|
90
|
+
}
|
|
91
|
+
/** The completion register of a course - every completed enrolment, by completion day (decision 10). */
|
|
92
|
+
async function completionRegister(courseId, context) {
|
|
93
|
+
const { domain } = context.state;
|
|
94
|
+
const tx = (0, course_service_1.learningManagerOf)(context);
|
|
95
|
+
const enrollments = await tx.getRepository(enrollment_1.Enrollment).find({ where: { domain: { id: domain.id }, course: { id: courseId }, status: enrollment_1.EnrollmentStatus.COMPLETED }, order: { completedAt: 'ASC' } });
|
|
96
|
+
return await rowsOf(tx, domain, enrollments);
|
|
97
|
+
}
|
|
98
|
+
/* ================================================================ the list rule */
|
|
99
|
+
/** Where an enrolment stands as a list shows it - OVERDUE is an open one past its due day, read on the day. */
|
|
100
|
+
exports.ENROLLMENT_STATES = ['ASSIGNED', 'IN_PROGRESS', 'COMPLETED', 'OVERDUE', 'CANCELLED'];
|
|
101
|
+
/** The people of the request's departments, refused to anyone who heads none. */
|
|
102
|
+
async function teamReachOf(context) {
|
|
103
|
+
const { domain } = context.state;
|
|
104
|
+
const headed = await headedDepartmentsOf(context);
|
|
105
|
+
if (!headed.length)
|
|
106
|
+
throw new shell_1.Refusal('learning-not-a-department-head', {}, 'only a department head reads where their people stand');
|
|
107
|
+
const people = await (0, course_service_1.learningManagerOf)(context).getRepository(organization_1.Employee).find({ where: { domain: { id: domain.id }, department: { id: (0, typeorm_1.In)(headed) } } });
|
|
108
|
+
return { kind: 'team', userIds: [...new Set(people.filter(one => one.active !== false && one.userId).map(one => one.userId))] };
|
|
109
|
+
}
|
|
110
|
+
/** The widest reach the request has - a manager's, a department head's, or their own. */
|
|
111
|
+
async function reachOf(context) {
|
|
112
|
+
if (await (0, auth_base_1.requestHolds)(context, 'course', 'query'))
|
|
113
|
+
return { kind: 'all' };
|
|
114
|
+
if ((await headedDepartmentsOf(context)).length)
|
|
115
|
+
return await teamReachOf(context);
|
|
116
|
+
return { kind: 'own', userId: context.state.user.id };
|
|
117
|
+
}
|
|
118
|
+
/*
|
|
119
|
+
* The list's names (getQueryBuilderFromListParams): `course` a course id, `learner` and `courseName` the words a search
|
|
120
|
+
* reads, `sourceKind` and `sourceId` who asked. `state` is not a column - narrowed below.
|
|
121
|
+
*/
|
|
122
|
+
const LIST = {
|
|
123
|
+
alias: 'E',
|
|
124
|
+
searchables: ['learner', 'courseName'],
|
|
125
|
+
columnExpressions: { course: 'C.id', learner: 'U.name', courseName: 'C.name' },
|
|
126
|
+
sortables: ['dueOn', 'createdAt', 'startedAt', 'completedAt', 'learner', 'courseName'],
|
|
127
|
+
defaultSortings: [{ name: 'dueOn' }, { name: 'createdAt' }]
|
|
128
|
+
};
|
|
129
|
+
const valuesOf = (filter) => (Array.isArray(filter.value) ? filter.value : [filter.value]).map(String).filter(Boolean);
|
|
130
|
+
/** The SQL of the states named - the parameters keyed apart so two conditions in one query never meet. */
|
|
131
|
+
function stateClause(states, today, key) {
|
|
132
|
+
const parameters = { [`${key}Open`]: enrollment_1.OPEN_ENROLLMENT_STATUSES, [`${key}Today`]: today };
|
|
133
|
+
const parts = states
|
|
134
|
+
.filter(state => exports.ENROLLMENT_STATES.includes(state))
|
|
135
|
+
.map((state, i) => {
|
|
136
|
+
if (state === 'OVERDUE')
|
|
137
|
+
return `(E.status IN (:...${key}Open) AND E.dueOn IS NOT NULL AND E.dueOn < :${key}Today)`;
|
|
138
|
+
parameters[`${key}S${i}`] = state;
|
|
139
|
+
if (enrollment_1.OPEN_ENROLLMENT_STATUSES.includes(state))
|
|
140
|
+
return `(E.status = :${key}S${i} AND (E.dueOn IS NULL OR E.dueOn >= :${key}Today))`;
|
|
141
|
+
return `E.status = :${key}S${i}`;
|
|
142
|
+
});
|
|
143
|
+
return parts.length ? { sql: `(${parts.join(' OR ')})`, parameters } : null;
|
|
144
|
+
}
|
|
145
|
+
let narrowSeq = 0;
|
|
146
|
+
/** The joins the list's names read, the reach, and the `state` filter as SQL. */
|
|
147
|
+
function narrow(builder, reach, state, today, extra) {
|
|
148
|
+
const key = `learningList${narrowSeq++}`;
|
|
149
|
+
builder.leftJoin('E.user', 'U').leftJoin('E.course', 'C');
|
|
150
|
+
if (reach.kind === 'own')
|
|
151
|
+
builder.andWhere(`U.id = :${key}Me`, { [`${key}Me`]: reach.userId });
|
|
152
|
+
if (reach.kind === 'team') {
|
|
153
|
+
if (!reach.userIds.length)
|
|
154
|
+
builder.andWhere('1 = 0');
|
|
155
|
+
else
|
|
156
|
+
builder.andWhere(`U.id IN (:...${key}Team)`, { [`${key}Team`]: reach.userIds }).andWhere(`E.status IN (:...${key}Shown)`, { [`${key}Shown`]: [...enrollment_1.OPEN_ENROLLMENT_STATUSES, enrollment_1.EnrollmentStatus.COMPLETED] });
|
|
157
|
+
}
|
|
158
|
+
const clause = state ? stateClause(valuesOf(state), today, `${key}State`) : null;
|
|
159
|
+
if (clause)
|
|
160
|
+
builder.andWhere(['noteq', 'notin'].includes(state.operator) ? `NOT ${clause.sql}` : clause.sql, clause.parameters);
|
|
161
|
+
extra?.(builder);
|
|
162
|
+
}
|
|
163
|
+
/** The filters but `state`, and the `state` one. */
|
|
164
|
+
function splitState(params) {
|
|
165
|
+
const filters = params?.filters ?? [];
|
|
166
|
+
return { rest: filters.filter(one => one.name !== 'state'), state: filters.find(one => one.name === 'state') };
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* One page of the enrolments a list asks for, within a reach - its conditions, search, sort and page by the framework's
|
|
170
|
+
* list rule, the rows then read with their people, courses and units. A department head's rows are status only.
|
|
171
|
+
*/
|
|
172
|
+
async function enrollmentPage(params, reach, context, extra) {
|
|
173
|
+
const { domain } = context.state;
|
|
174
|
+
const tx = (0, course_service_1.learningManagerOf)(context);
|
|
175
|
+
const { rest, state } = splitState(params);
|
|
176
|
+
const builder = (0, shell_1.getQueryBuilderFromListParams)({ ...LIST, repository: tx.getRepository(enrollment_1.Enrollment), params: { ...params, filters: rest }, domain });
|
|
177
|
+
narrow(builder, reach, state, (0, enrollment_service_1.todayIn)(domain), extra);
|
|
178
|
+
const [enrollments, total] = await builder.getManyAndCount();
|
|
179
|
+
const rows = await rowsOf(tx, domain, enrollments);
|
|
180
|
+
return { rows: reach.kind === 'team' ? rows.map(row => ({ ...row, enrollment: statusOnly(row.enrollment) })) : rows, total };
|
|
181
|
+
}
|
|
182
|
+
/** How many enrolments stand in each state under the list's other conditions - every state, in order. */
|
|
183
|
+
async function enrollmentStateCounts(params, reach, context) {
|
|
184
|
+
const { domain } = context.state;
|
|
185
|
+
const tx = (0, course_service_1.learningManagerOf)(context);
|
|
186
|
+
const today = (0, enrollment_service_1.todayIn)(domain);
|
|
187
|
+
const { rest } = splitState(params);
|
|
188
|
+
const common = { ...LIST, repository: tx.getRepository(enrollment_1.Enrollment), domain, params: { filters: rest, search: params?.search, inherited: params?.inherited }, field: 'status' };
|
|
189
|
+
const all = await (0, shell_1.countListByField)({ ...common, narrow: builder => narrow(builder, reach, undefined, today) });
|
|
190
|
+
const late = await (0, shell_1.countListByField)({ ...common, narrow: builder => narrow(builder, reach, { name: 'state', operator: 'eq', value: 'OVERDUE' }, today) });
|
|
191
|
+
const overdueCount = [...late.values()].reduce((sum, one) => sum + one, 0);
|
|
192
|
+
return exports.ENROLLMENT_STATES.map(value => ({ value, count: value === 'OVERDUE' ? overdueCount : (all.get(value) ?? 0) - (late.get(value) ?? 0) }));
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=enrollment-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enrollment-status.js","sourceRoot":"","sources":["../../../server/service/enrollment/enrollment-status.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Where enrolments stand, for managers and department heads (ADR-0194 decisions 10, 11): every enrolment of a course or\n * a source with its progress and evidence for a manager (`course` query); for a department head, whether each person\n * of their departments is done - status and days only, never a score or an attempt.\n */\nimport { EntityManager, In, SelectQueryBuilder } from 'typeorm'\n\nimport { requestHolds, User } from '@things-factory/auth-base'\nimport { Department, departmentTreeOf, Employee, withDescendants } from '@things-factory/organization'\nimport { countListByField, Filter, getQueryBuilderFromListParams, ListParam, ListValueCount, Refusal } from '@things-factory/shell'\n\nimport { Course } from '../course/course'\nimport { CourseUnit } from '../course/course-unit'\nimport { CourseVersion } from '../course/course-version'\nimport { learningManagerOf, publishedVersionOf } from '../course/course-service'\nimport { Enrollment, EnrollmentStatus, OPEN_ENROLLMENT_STATUSES } from './enrollment'\nimport { todayIn } from './enrollment-service'\nimport { counts, overdue } from './progress-rules'\nimport { UnitProgress } from './unit-progress'\n\nexport interface StatusRow {\n enrollment: Enrollment\n user: User | null\n course: Course | null\n departmentName: string | null\n /** The status as it reads today - OVERDUE for an open one past its due day. */\n state: string\n units: number\n unitsDone: number\n versionNumber: number | null\n}\n\n/** The working employee record of each user given - for the department a row names. */\nasync function employeesOf(tx: EntityManager, domain: { id: string }, userIds: string[]): Promise<Map<string, Employee>> {\n if (!userIds.length) return new Map()\n const rows = await tx.getRepository(Employee).find({ where: { domain: { id: domain.id }, user: { id: In(userIds) } } as any, relations: ['department'] })\n const out = new Map<string, Employee>()\n for (const row of rows) if (row.active !== false && (!out.has(row.userId!) || out.get(row.userId!)!.active === false)) out.set(row.userId!, row)\n return out\n}\n\n/** The rows of the enrolments given - each with its person, course, department, state today and units done. */\nexport async function rowsOf(tx: EntityManager, domain: any, enrollments: Enrollment[]): Promise<StatusRow[]> {\n if (!enrollments.length) return []\n const today = todayIn(domain)\n const users = await tx.getRepository(User).find({ where: { id: In([...new Set(enrollments.map(one => one.userId!))]) } })\n const courses = await tx.getRepository(Course).find({ where: { id: In([...new Set(enrollments.map(one => one.courseId!))]) } as any })\n const employees = await employeesOf(tx, domain, users.map(one => one.id))\n const versionIds = new Set<string>()\n const shown = new Map<string, string | null>()\n for (const enrollment of enrollments) {\n const id = enrollment.versionId ?? (await publishedVersionOf(tx, domain, enrollment.courseId!))?.id ?? null\n shown.set(enrollment.id, id)\n if (id) versionIds.add(id)\n }\n const versions = versionIds.size ? await tx.getRepository(CourseVersion).find({ where: { id: In([...versionIds]) } as any, withDeleted: true }) : []\n const units = versionIds.size ? (await tx.getRepository(CourseUnit).find({ where: { version: { id: In([...versionIds]) } } as any })).filter(counts) : []\n const progress = await tx.getRepository(UnitProgress).find({ where: { enrollment: { id: In(enrollments.map(one => one.id)) } } as any })\n return enrollments.map(enrollment => {\n const versionId = shown.get(enrollment.id)\n const mine = units.filter(unit => unit.versionId === versionId)\n return {\n enrollment,\n user: users.find(one => one.id === enrollment.userId) ?? null,\n course: courses.find(one => one.id === enrollment.courseId) ?? null,\n departmentName: employees.get(enrollment.userId!)?.department?.name ?? null,\n state: overdue(enrollment, today) ? 'OVERDUE' : enrollment.status,\n units: mine.length,\n unitsDone: mine.filter(unit => progress.some(one => one.enrollmentId === enrollment.id && one.unitId === unit.id && one.doneAt)).length,\n versionNumber: enrollment.versionId ? (versions.find(one => one.id === enrollment.versionId)?.number ?? null) : null\n }\n })\n}\n\n/** The departments the request's person heads, with those under them - none for anyone else. */\nexport async function headedDepartmentsOf(context: any): Promise<string[]> {\n const { domain, user } = context.state\n const tx = learningManagerOf(context)\n const me = (await employeesOf(tx, domain, [user.id])).get(user.id)\n if (!me) return []\n const managed = await tx.getRepository(Department).find({ where: { domain: { id: domain.id }, manager: { id: me.id } } as any })\n if (!managed.length) return []\n return withDescendants(managed.map(one => one.id), await departmentTreeOf(domain, tx))\n}\n\n/** An enrolment as a department head reads it - where it stands and its days, nothing of how it went. */\nexport function statusOnly(enrollment: Enrollment): Enrollment {\n const { score, attempts, learnedSeconds, acknowledgedAt, certificateNo, cancelReason, ...kept } = enrollment as any\n return { ...kept, score: null, attempts: null, learnedSeconds: null, acknowledgedAt: null, certificateNo: null, cancelReason: null } as Enrollment\n}\n\n/** The completion register of a course - every completed enrolment, by completion day (decision 10). */\nexport async function completionRegister(courseId: string, context: any): Promise<StatusRow[]> {\n const { domain } = context.state\n const tx = learningManagerOf(context)\n const enrollments = await tx.getRepository(Enrollment).find({ where: { domain: { id: domain.id }, course: { id: courseId }, status: EnrollmentStatus.COMPLETED } as any, order: { completedAt: 'ASC' } as any })\n return await rowsOf(tx, domain, enrollments)\n}\n\n\n/* ================================================================ the list rule */\n\n/** Where an enrolment stands as a list shows it - OVERDUE is an open one past its due day, read on the day. */\nexport const ENROLLMENT_STATES = ['ASSIGNED', 'IN_PROGRESS', 'COMPLETED', 'OVERDUE', 'CANCELLED'] as const\n\n/**\n * Whose enrolments a request reads (decision 11): a manager everyone's; a department head the people of their\n * departments - open and completed ones, status only; anyone else their own.\n */\nexport type EnrollmentReach = { kind: 'all' } | { kind: 'team'; userIds: string[] } | { kind: 'own'; userId: string }\n\n/** The people of the request's departments, refused to anyone who heads none. */\nexport async function teamReachOf(context: any): Promise<EnrollmentReach> {\n const { domain } = context.state\n const headed = await headedDepartmentsOf(context)\n if (!headed.length) throw new Refusal('learning-not-a-department-head', {}, 'only a department head reads where their people stand')\n const people = await learningManagerOf(context).getRepository(Employee).find({ where: { domain: { id: domain.id }, department: { id: In(headed) } } as any })\n return { kind: 'team', userIds: [...new Set(people.filter(one => one.active !== false && one.userId).map(one => one.userId!))] }\n}\n\n/** The widest reach the request has - a manager's, a department head's, or their own. */\nexport async function reachOf(context: any): Promise<EnrollmentReach> {\n if (await requestHolds(context, 'course', 'query')) return { kind: 'all' }\n if ((await headedDepartmentsOf(context)).length) return await teamReachOf(context)\n return { kind: 'own', userId: context.state.user.id }\n}\n\n/*\n * The list's names (getQueryBuilderFromListParams): `course` a course id, `learner` and `courseName` the words a search\n * reads, `sourceKind` and `sourceId` who asked. `state` is not a column - narrowed below.\n */\nconst LIST = {\n alias: 'E',\n searchables: ['learner', 'courseName'],\n columnExpressions: { course: 'C.id', learner: 'U.name', courseName: 'C.name' },\n sortables: ['dueOn', 'createdAt', 'startedAt', 'completedAt', 'learner', 'courseName'],\n defaultSortings: [{ name: 'dueOn' }, { name: 'createdAt' }]\n}\n\nconst valuesOf = (filter: Filter) => (Array.isArray(filter.value) ? filter.value : [filter.value]).map(String).filter(Boolean)\n\n/** The SQL of the states named - the parameters keyed apart so two conditions in one query never meet. */\nfunction stateClause(states: string[], today: string, key: string): { sql: string; parameters: Record<string, any> } | null {\n const parameters: Record<string, any> = { [`${key}Open`]: OPEN_ENROLLMENT_STATUSES, [`${key}Today`]: today }\n const parts = states\n .filter(state => (ENROLLMENT_STATES as readonly string[]).includes(state))\n .map((state, i) => {\n if (state === 'OVERDUE') return `(E.status IN (:...${key}Open) AND E.dueOn IS NOT NULL AND E.dueOn < :${key}Today)`\n parameters[`${key}S${i}`] = state\n if ((OPEN_ENROLLMENT_STATUSES as string[]).includes(state)) return `(E.status = :${key}S${i} AND (E.dueOn IS NULL OR E.dueOn >= :${key}Today))`\n return `E.status = :${key}S${i}`\n })\n return parts.length ? { sql: `(${parts.join(' OR ')})`, parameters } : null\n}\n\nlet narrowSeq = 0\n\n/** The joins the list's names read, the reach, and the `state` filter as SQL. */\nfunction narrow(builder: SelectQueryBuilder<Enrollment>, reach: EnrollmentReach, state: Filter | undefined, today: string, extra?: (builder: SelectQueryBuilder<Enrollment>) => void): void {\n const key = `learningList${narrowSeq++}`\n builder.leftJoin('E.user', 'U').leftJoin('E.course', 'C')\n if (reach.kind === 'own') builder.andWhere(`U.id = :${key}Me`, { [`${key}Me`]: reach.userId })\n if (reach.kind === 'team') {\n if (!reach.userIds.length) builder.andWhere('1 = 0')\n else builder.andWhere(`U.id IN (:...${key}Team)`, { [`${key}Team`]: reach.userIds }).andWhere(`E.status IN (:...${key}Shown)`, { [`${key}Shown`]: [...OPEN_ENROLLMENT_STATUSES, EnrollmentStatus.COMPLETED] })\n }\n const clause = state ? stateClause(valuesOf(state), today, `${key}State`) : null\n if (clause) builder.andWhere(['noteq', 'notin'].includes(state!.operator) ? `NOT ${clause.sql}` : clause.sql, clause.parameters)\n extra?.(builder)\n}\n\n/** The filters but `state`, and the `state` one. */\nfunction splitState(params: ListParam | undefined): { rest: Filter[]; state?: Filter } {\n const filters = params?.filters ?? []\n return { rest: filters.filter(one => one.name !== 'state'), state: filters.find(one => one.name === 'state') }\n}\n\n/**\n * One page of the enrolments a list asks for, within a reach - its conditions, search, sort and page by the framework's\n * list rule, the rows then read with their people, courses and units. A department head's rows are status only.\n */\nexport async function enrollmentPage(params: ListParam, reach: EnrollmentReach, context: any, extra?: (builder: SelectQueryBuilder<Enrollment>) => void): Promise<{ rows: StatusRow[]; total: number }> {\n const { domain } = context.state\n const tx = learningManagerOf(context)\n const { rest, state } = splitState(params)\n const builder = getQueryBuilderFromListParams({ ...LIST, repository: tx.getRepository(Enrollment), params: { ...params, filters: rest }, domain })\n narrow(builder, reach, state, todayIn(domain), extra)\n const [enrollments, total] = await builder.getManyAndCount()\n const rows = await rowsOf(tx, domain, enrollments)\n return { rows: reach.kind === 'team' ? rows.map(row => ({ ...row, enrollment: statusOnly(row.enrollment) })) : rows, total }\n}\n\n/** How many enrolments stand in each state under the list's other conditions - every state, in order. */\nexport async function enrollmentStateCounts(params: ListParam, reach: EnrollmentReach, context: any): Promise<ListValueCount[]> {\n const { domain } = context.state\n const tx = learningManagerOf(context)\n const today = todayIn(domain)\n const { rest } = splitState(params)\n const common = { ...LIST, repository: tx.getRepository(Enrollment), domain, params: { filters: rest, search: params?.search, inherited: params?.inherited }, field: 'status' }\n const all = await countListByField({ ...common, narrow: builder => narrow(builder, reach, undefined, today) })\n const late = await countListByField({ ...common, narrow: builder => narrow(builder, reach, { name: 'state', operator: 'eq', value: 'OVERDUE' } as Filter, today) })\n const overdueCount = [...late.values()].reduce((sum, one) => sum + one, 0)\n return ENROLLMENT_STATES.map(value => ({ value, count: value === 'OVERDUE' ? overdueCount : (all.get(value) ?? 0) - (late.get(value) ?? 0) }))\n}\n"]}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { User } from '@things-factory/auth-base';
|
|
2
|
+
import { Course } from '../course/course';
|
|
3
|
+
import { CourseUnit } from '../course/course-unit';
|
|
4
|
+
import { Enrollment } from './enrollment';
|
|
5
|
+
import { UnitProgress } from './unit-progress';
|
|
6
|
+
export declare class LearningUnit {
|
|
7
|
+
unit: CourseUnit;
|
|
8
|
+
progress?: UnitProgress | null;
|
|
9
|
+
counts: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare class QuizChoiceView {
|
|
12
|
+
id: string;
|
|
13
|
+
text: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class QuizQuestionView {
|
|
16
|
+
id: string;
|
|
17
|
+
kind: string;
|
|
18
|
+
text: string;
|
|
19
|
+
choices: QuizChoiceView[];
|
|
20
|
+
}
|
|
21
|
+
export declare class QuizAttemptView {
|
|
22
|
+
attemptId: string;
|
|
23
|
+
questions: QuizQuestionView[];
|
|
24
|
+
}
|
|
25
|
+
export declare class QuizResultView {
|
|
26
|
+
score: number;
|
|
27
|
+
passed: boolean;
|
|
28
|
+
attemptsLeft?: number | null;
|
|
29
|
+
enrollment: Enrollment;
|
|
30
|
+
}
|
|
31
|
+
export declare class LearningTickResult {
|
|
32
|
+
enrollment: Enrollment;
|
|
33
|
+
progress: UnitProgress;
|
|
34
|
+
}
|
|
35
|
+
export declare class EnrollmentStatusRow {
|
|
36
|
+
id: string;
|
|
37
|
+
enrollment: Enrollment;
|
|
38
|
+
user?: User | null;
|
|
39
|
+
course?: Course | null;
|
|
40
|
+
departmentName?: string | null;
|
|
41
|
+
state: string;
|
|
42
|
+
units: number;
|
|
43
|
+
unitsDone: number;
|
|
44
|
+
versionNumber?: number | null;
|
|
45
|
+
}
|
|
46
|
+
export declare class EnrollmentStatusList {
|
|
47
|
+
items: EnrollmentStatusRow[];
|
|
48
|
+
total: number;
|
|
49
|
+
}
|
|
50
|
+
export declare class LearningAudienceInput {
|
|
51
|
+
scope: string;
|
|
52
|
+
targetId: string;
|
|
53
|
+
targetName?: string;
|
|
54
|
+
}
|
|
55
|
+
export declare class LearningEnrollmentRow {
|
|
56
|
+
id: string;
|
|
57
|
+
learner: string;
|
|
58
|
+
departmentName?: string | null;
|
|
59
|
+
course: string;
|
|
60
|
+
state: string;
|
|
61
|
+
dueOn?: string | null;
|
|
62
|
+
daysLeft?: number | null;
|
|
63
|
+
startedAt?: Date | null;
|
|
64
|
+
completedAt?: Date | null;
|
|
65
|
+
unitsDone: number;
|
|
66
|
+
units: number;
|
|
67
|
+
}
|
|
68
|
+
export declare class LearningEnrollmentList {
|
|
69
|
+
items: LearningEnrollmentRow[];
|
|
70
|
+
total: number;
|
|
71
|
+
}
|
|
72
|
+
export declare class LearningContentUnit {
|
|
73
|
+
seq: number;
|
|
74
|
+
kind: string;
|
|
75
|
+
name: string;
|
|
76
|
+
text?: string | null;
|
|
77
|
+
}
|
|
78
|
+
export declare class LearningContent {
|
|
79
|
+
course: string;
|
|
80
|
+
version: number;
|
|
81
|
+
units: LearningContentUnit[];
|
|
82
|
+
}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LearningContent = exports.LearningContentUnit = exports.LearningEnrollmentList = exports.LearningEnrollmentRow = exports.LearningAudienceInput = exports.EnrollmentStatusList = exports.EnrollmentStatusRow = exports.LearningTickResult = exports.QuizResultView = exports.QuizAttemptView = exports.QuizQuestionView = exports.QuizChoiceView = exports.LearningUnit = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
7
|
+
const course_1 = require("../course/course");
|
|
8
|
+
const course_unit_1 = require("../course/course-unit");
|
|
9
|
+
const enrollment_1 = require("./enrollment");
|
|
10
|
+
const unit_progress_1 = require("./unit-progress");
|
|
11
|
+
let LearningUnit = class LearningUnit {
|
|
12
|
+
};
|
|
13
|
+
exports.LearningUnit = LearningUnit;
|
|
14
|
+
tslib_1.__decorate([
|
|
15
|
+
(0, type_graphql_1.Field)(type => course_unit_1.CourseUnit, { description: 'The unit.' }),
|
|
16
|
+
tslib_1.__metadata("design:type", course_unit_1.CourseUnit)
|
|
17
|
+
], LearningUnit.prototype, "unit", void 0);
|
|
18
|
+
tslib_1.__decorate([
|
|
19
|
+
(0, type_graphql_1.Field)(type => unit_progress_1.UnitProgress, { nullable: true, description: 'How far the learner went - none before they started it.' }),
|
|
20
|
+
tslib_1.__metadata("design:type", unit_progress_1.UnitProgress)
|
|
21
|
+
], LearningUnit.prototype, "progress", void 0);
|
|
22
|
+
tslib_1.__decorate([
|
|
23
|
+
(0, type_graphql_1.Field)({ description: 'Whether it counts toward completion - a link does not.' }),
|
|
24
|
+
tslib_1.__metadata("design:type", Boolean)
|
|
25
|
+
], LearningUnit.prototype, "counts", void 0);
|
|
26
|
+
exports.LearningUnit = LearningUnit = tslib_1.__decorate([
|
|
27
|
+
(0, type_graphql_1.ObjectType)({ description: 'A unit as its learner sees it - with how far they went through it' })
|
|
28
|
+
], LearningUnit);
|
|
29
|
+
let QuizChoiceView = class QuizChoiceView {
|
|
30
|
+
};
|
|
31
|
+
exports.QuizChoiceView = QuizChoiceView;
|
|
32
|
+
tslib_1.__decorate([
|
|
33
|
+
(0, type_graphql_1.Field)({ description: 'The choice id.' }),
|
|
34
|
+
tslib_1.__metadata("design:type", String)
|
|
35
|
+
], QuizChoiceView.prototype, "id", void 0);
|
|
36
|
+
tslib_1.__decorate([
|
|
37
|
+
(0, type_graphql_1.Field)({ description: 'What it says.' }),
|
|
38
|
+
tslib_1.__metadata("design:type", String)
|
|
39
|
+
], QuizChoiceView.prototype, "text", void 0);
|
|
40
|
+
exports.QuizChoiceView = QuizChoiceView = tslib_1.__decorate([
|
|
41
|
+
(0, type_graphql_1.ObjectType)({ description: 'A choice as a learner is drawn it - never whether it is right' })
|
|
42
|
+
], QuizChoiceView);
|
|
43
|
+
let QuizQuestionView = class QuizQuestionView {
|
|
44
|
+
};
|
|
45
|
+
exports.QuizQuestionView = QuizQuestionView;
|
|
46
|
+
tslib_1.__decorate([
|
|
47
|
+
(0, type_graphql_1.Field)({ description: 'The question id.' }),
|
|
48
|
+
tslib_1.__metadata("design:type", String)
|
|
49
|
+
], QuizQuestionView.prototype, "id", void 0);
|
|
50
|
+
tslib_1.__decorate([
|
|
51
|
+
(0, type_graphql_1.Field)({ description: 'SINGLE, MULTIPLE or TRUE_FALSE.' }),
|
|
52
|
+
tslib_1.__metadata("design:type", String)
|
|
53
|
+
], QuizQuestionView.prototype, "kind", void 0);
|
|
54
|
+
tslib_1.__decorate([
|
|
55
|
+
(0, type_graphql_1.Field)({ description: 'What it asks.' }),
|
|
56
|
+
tslib_1.__metadata("design:type", String)
|
|
57
|
+
], QuizQuestionView.prototype, "text", void 0);
|
|
58
|
+
tslib_1.__decorate([
|
|
59
|
+
(0, type_graphql_1.Field)(type => [QuizChoiceView], { description: 'Its choices, shuffled.' }),
|
|
60
|
+
tslib_1.__metadata("design:type", Array)
|
|
61
|
+
], QuizQuestionView.prototype, "choices", void 0);
|
|
62
|
+
exports.QuizQuestionView = QuizQuestionView = tslib_1.__decorate([
|
|
63
|
+
(0, type_graphql_1.ObjectType)({ description: 'A question as a learner is drawn it - its choices in the order shown, no answer' })
|
|
64
|
+
], QuizQuestionView);
|
|
65
|
+
let QuizAttemptView = class QuizAttemptView {
|
|
66
|
+
};
|
|
67
|
+
exports.QuizAttemptView = QuizAttemptView;
|
|
68
|
+
tslib_1.__decorate([
|
|
69
|
+
(0, type_graphql_1.Field)({ description: 'The attempt id - its answers are sent with it.' }),
|
|
70
|
+
tslib_1.__metadata("design:type", String)
|
|
71
|
+
], QuizAttemptView.prototype, "attemptId", void 0);
|
|
72
|
+
tslib_1.__decorate([
|
|
73
|
+
(0, type_graphql_1.Field)(type => [QuizQuestionView], { description: 'The questions drawn, shuffled.' }),
|
|
74
|
+
tslib_1.__metadata("design:type", Array)
|
|
75
|
+
], QuizAttemptView.prototype, "questions", void 0);
|
|
76
|
+
exports.QuizAttemptView = QuizAttemptView = tslib_1.__decorate([
|
|
77
|
+
(0, type_graphql_1.ObjectType)({ description: 'An attempt as a learner is drawn it' })
|
|
78
|
+
], QuizAttemptView);
|
|
79
|
+
let QuizResultView = class QuizResultView {
|
|
80
|
+
};
|
|
81
|
+
exports.QuizResultView = QuizResultView;
|
|
82
|
+
tslib_1.__decorate([
|
|
83
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'The score, out of 100.' }),
|
|
84
|
+
tslib_1.__metadata("design:type", Number)
|
|
85
|
+
], QuizResultView.prototype, "score", void 0);
|
|
86
|
+
tslib_1.__decorate([
|
|
87
|
+
(0, type_graphql_1.Field)({ description: 'Whether it passed.' }),
|
|
88
|
+
tslib_1.__metadata("design:type", Boolean)
|
|
89
|
+
], QuizResultView.prototype, "passed", void 0);
|
|
90
|
+
tslib_1.__decorate([
|
|
91
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: 'Attempts left - no limit when empty.' }),
|
|
92
|
+
tslib_1.__metadata("design:type", Number)
|
|
93
|
+
], QuizResultView.prototype, "attemptsLeft", void 0);
|
|
94
|
+
tslib_1.__decorate([
|
|
95
|
+
(0, type_graphql_1.Field)(type => enrollment_1.Enrollment, { description: 'The enrolment after it - completed when nothing else is missing.' }),
|
|
96
|
+
tslib_1.__metadata("design:type", enrollment_1.Enrollment)
|
|
97
|
+
], QuizResultView.prototype, "enrollment", void 0);
|
|
98
|
+
exports.QuizResultView = QuizResultView = tslib_1.__decorate([
|
|
99
|
+
(0, type_graphql_1.ObjectType)({ description: "An attempt's result - the score and whether it passed; never the right answers" })
|
|
100
|
+
], QuizResultView);
|
|
101
|
+
let LearningTickResult = class LearningTickResult {
|
|
102
|
+
};
|
|
103
|
+
exports.LearningTickResult = LearningTickResult;
|
|
104
|
+
tslib_1.__decorate([
|
|
105
|
+
(0, type_graphql_1.Field)(type => enrollment_1.Enrollment, { description: 'The enrolment.' }),
|
|
106
|
+
tslib_1.__metadata("design:type", enrollment_1.Enrollment)
|
|
107
|
+
], LearningTickResult.prototype, "enrollment", void 0);
|
|
108
|
+
tslib_1.__decorate([
|
|
109
|
+
(0, type_graphql_1.Field)(type => unit_progress_1.UnitProgress, { description: "The unit's progress." }),
|
|
110
|
+
tslib_1.__metadata("design:type", unit_progress_1.UnitProgress)
|
|
111
|
+
], LearningTickResult.prototype, "progress", void 0);
|
|
112
|
+
exports.LearningTickResult = LearningTickResult = tslib_1.__decorate([
|
|
113
|
+
(0, type_graphql_1.ObjectType)({ description: "A tick's result - the unit's progress and the enrolment after it" })
|
|
114
|
+
], LearningTickResult);
|
|
115
|
+
let EnrollmentStatusRow = class EnrollmentStatusRow {
|
|
116
|
+
};
|
|
117
|
+
exports.EnrollmentStatusRow = EnrollmentStatusRow;
|
|
118
|
+
tslib_1.__decorate([
|
|
119
|
+
(0, type_graphql_1.Field)({ description: 'The enrolment id.' }),
|
|
120
|
+
tslib_1.__metadata("design:type", String)
|
|
121
|
+
], EnrollmentStatusRow.prototype, "id", void 0);
|
|
122
|
+
tslib_1.__decorate([
|
|
123
|
+
(0, type_graphql_1.Field)(type => enrollment_1.Enrollment, { description: 'The enrolment - for a department head its status and days only.' }),
|
|
124
|
+
tslib_1.__metadata("design:type", enrollment_1.Enrollment)
|
|
125
|
+
], EnrollmentStatusRow.prototype, "enrollment", void 0);
|
|
126
|
+
tslib_1.__decorate([
|
|
127
|
+
(0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true, description: 'Who takes it.' }),
|
|
128
|
+
tslib_1.__metadata("design:type", auth_base_1.User)
|
|
129
|
+
], EnrollmentStatusRow.prototype, "user", void 0);
|
|
130
|
+
tslib_1.__decorate([
|
|
131
|
+
(0, type_graphql_1.Field)(type => course_1.Course, { nullable: true, description: 'The course.' }),
|
|
132
|
+
tslib_1.__metadata("design:type", course_1.Course)
|
|
133
|
+
], EnrollmentStatusRow.prototype, "course", void 0);
|
|
134
|
+
tslib_1.__decorate([
|
|
135
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Their department.' }),
|
|
136
|
+
tslib_1.__metadata("design:type", String)
|
|
137
|
+
], EnrollmentStatusRow.prototype, "departmentName", void 0);
|
|
138
|
+
tslib_1.__decorate([
|
|
139
|
+
(0, type_graphql_1.Field)({ description: 'ASSIGNED, IN_PROGRESS, COMPLETED, CANCELLED, or OVERDUE for an open one past its due day.' }),
|
|
140
|
+
tslib_1.__metadata("design:type", String)
|
|
141
|
+
], EnrollmentStatusRow.prototype, "state", void 0);
|
|
142
|
+
tslib_1.__decorate([
|
|
143
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'The units that count.' }),
|
|
144
|
+
tslib_1.__metadata("design:type", Number)
|
|
145
|
+
], EnrollmentStatusRow.prototype, "units", void 0);
|
|
146
|
+
tslib_1.__decorate([
|
|
147
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'The units done.' }),
|
|
148
|
+
tslib_1.__metadata("design:type", Number)
|
|
149
|
+
], EnrollmentStatusRow.prototype, "unitsDone", void 0);
|
|
150
|
+
tslib_1.__decorate([
|
|
151
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: 'The version taken.' }),
|
|
152
|
+
tslib_1.__metadata("design:type", Number)
|
|
153
|
+
], EnrollmentStatusRow.prototype, "versionNumber", void 0);
|
|
154
|
+
exports.EnrollmentStatusRow = EnrollmentStatusRow = tslib_1.__decorate([
|
|
155
|
+
(0, type_graphql_1.ObjectType)({ description: 'One enrolment as the status reads it' })
|
|
156
|
+
], EnrollmentStatusRow);
|
|
157
|
+
let EnrollmentStatusList = class EnrollmentStatusList {
|
|
158
|
+
};
|
|
159
|
+
exports.EnrollmentStatusList = EnrollmentStatusList;
|
|
160
|
+
tslib_1.__decorate([
|
|
161
|
+
(0, type_graphql_1.Field)(type => [EnrollmentStatusRow], { description: 'The enrolments of the page.' }),
|
|
162
|
+
tslib_1.__metadata("design:type", Array)
|
|
163
|
+
], EnrollmentStatusList.prototype, "items", void 0);
|
|
164
|
+
tslib_1.__decorate([
|
|
165
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'How many there are under the conditions.' }),
|
|
166
|
+
tslib_1.__metadata("design:type", Number)
|
|
167
|
+
], EnrollmentStatusList.prototype, "total", void 0);
|
|
168
|
+
exports.EnrollmentStatusList = EnrollmentStatusList = tslib_1.__decorate([
|
|
169
|
+
(0, type_graphql_1.ObjectType)({ description: 'A page of enrolments as the status reads them' })
|
|
170
|
+
], EnrollmentStatusList);
|
|
171
|
+
let LearningAudienceInput = class LearningAudienceInput {
|
|
172
|
+
};
|
|
173
|
+
exports.LearningAudienceInput = LearningAudienceInput;
|
|
174
|
+
tslib_1.__decorate([
|
|
175
|
+
(0, type_graphql_1.Field)({ description: 'DOMAIN | DEPARTMENT | ROLE | USER.' }),
|
|
176
|
+
tslib_1.__metadata("design:type", String)
|
|
177
|
+
], LearningAudienceInput.prototype, "scope", void 0);
|
|
178
|
+
tslib_1.__decorate([
|
|
179
|
+
(0, type_graphql_1.Field)({ description: 'The id of the domain, department, role or user.' }),
|
|
180
|
+
tslib_1.__metadata("design:type", String)
|
|
181
|
+
], LearningAudienceInput.prototype, "targetId", void 0);
|
|
182
|
+
tslib_1.__decorate([
|
|
183
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Its name, as shown.' }),
|
|
184
|
+
tslib_1.__metadata("design:type", String)
|
|
185
|
+
], LearningAudienceInput.prototype, "targetName", void 0);
|
|
186
|
+
exports.LearningAudienceInput = LearningAudienceInput = tslib_1.__decorate([
|
|
187
|
+
(0, type_graphql_1.InputType)({ description: 'One target of an audience - the domain, a department (with those under it), a role or a person' })
|
|
188
|
+
], LearningAudienceInput);
|
|
189
|
+
let LearningEnrollmentRow = class LearningEnrollmentRow {
|
|
190
|
+
};
|
|
191
|
+
exports.LearningEnrollmentRow = LearningEnrollmentRow;
|
|
192
|
+
tslib_1.__decorate([
|
|
193
|
+
(0, type_graphql_1.Field)({ description: 'The enrolment id.' }),
|
|
194
|
+
tslib_1.__metadata("design:type", String)
|
|
195
|
+
], LearningEnrollmentRow.prototype, "id", void 0);
|
|
196
|
+
tslib_1.__decorate([
|
|
197
|
+
(0, type_graphql_1.Field)({ description: 'Who takes it.' }),
|
|
198
|
+
tslib_1.__metadata("design:type", String)
|
|
199
|
+
], LearningEnrollmentRow.prototype, "learner", void 0);
|
|
200
|
+
tslib_1.__decorate([
|
|
201
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Their department.' }),
|
|
202
|
+
tslib_1.__metadata("design:type", String)
|
|
203
|
+
], LearningEnrollmentRow.prototype, "departmentName", void 0);
|
|
204
|
+
tslib_1.__decorate([
|
|
205
|
+
(0, type_graphql_1.Field)({ description: 'The course.' }),
|
|
206
|
+
tslib_1.__metadata("design:type", String)
|
|
207
|
+
], LearningEnrollmentRow.prototype, "course", void 0);
|
|
208
|
+
tslib_1.__decorate([
|
|
209
|
+
(0, type_graphql_1.Field)({ description: 'ASSIGNED, IN_PROGRESS, COMPLETED or OVERDUE.' }),
|
|
210
|
+
tslib_1.__metadata("design:type", String)
|
|
211
|
+
], LearningEnrollmentRow.prototype, "state", void 0);
|
|
212
|
+
tslib_1.__decorate([
|
|
213
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'YYYY-MM-DD it is due.' }),
|
|
214
|
+
tslib_1.__metadata("design:type", String)
|
|
215
|
+
], LearningEnrollmentRow.prototype, "dueOn", void 0);
|
|
216
|
+
tslib_1.__decorate([
|
|
217
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: 'Days to the due day - negative past it.' }),
|
|
218
|
+
tslib_1.__metadata("design:type", Number)
|
|
219
|
+
], LearningEnrollmentRow.prototype, "daysLeft", void 0);
|
|
220
|
+
tslib_1.__decorate([
|
|
221
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'When it was started.' }),
|
|
222
|
+
tslib_1.__metadata("design:type", Date)
|
|
223
|
+
], LearningEnrollmentRow.prototype, "startedAt", void 0);
|
|
224
|
+
tslib_1.__decorate([
|
|
225
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'When it was completed.' }),
|
|
226
|
+
tslib_1.__metadata("design:type", Date)
|
|
227
|
+
], LearningEnrollmentRow.prototype, "completedAt", void 0);
|
|
228
|
+
tslib_1.__decorate([
|
|
229
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Units done.' }),
|
|
230
|
+
tslib_1.__metadata("design:type", Number)
|
|
231
|
+
], LearningEnrollmentRow.prototype, "unitsDone", void 0);
|
|
232
|
+
tslib_1.__decorate([
|
|
233
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Units that count.' }),
|
|
234
|
+
tslib_1.__metadata("design:type", Number)
|
|
235
|
+
], LearningEnrollmentRow.prototype, "units", void 0);
|
|
236
|
+
exports.LearningEnrollmentRow = LearningEnrollmentRow = tslib_1.__decorate([
|
|
237
|
+
(0, type_graphql_1.ObjectType)({ description: 'An enrolment as the assistant lists it' })
|
|
238
|
+
], LearningEnrollmentRow);
|
|
239
|
+
let LearningEnrollmentList = class LearningEnrollmentList {
|
|
240
|
+
};
|
|
241
|
+
exports.LearningEnrollmentList = LearningEnrollmentList;
|
|
242
|
+
tslib_1.__decorate([
|
|
243
|
+
(0, type_graphql_1.Field)(type => [LearningEnrollmentRow], { description: 'The enrolments.' }),
|
|
244
|
+
tslib_1.__metadata("design:type", Array)
|
|
245
|
+
], LearningEnrollmentList.prototype, "items", void 0);
|
|
246
|
+
tslib_1.__decorate([
|
|
247
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'How many there are.' }),
|
|
248
|
+
tslib_1.__metadata("design:type", Number)
|
|
249
|
+
], LearningEnrollmentList.prototype, "total", void 0);
|
|
250
|
+
exports.LearningEnrollmentList = LearningEnrollmentList = tslib_1.__decorate([
|
|
251
|
+
(0, type_graphql_1.ObjectType)({ description: 'A page of enrolments as the assistant lists them' })
|
|
252
|
+
], LearningEnrollmentList);
|
|
253
|
+
let LearningContentUnit = class LearningContentUnit {
|
|
254
|
+
};
|
|
255
|
+
exports.LearningContentUnit = LearningContentUnit;
|
|
256
|
+
tslib_1.__decorate([
|
|
257
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Its place.' }),
|
|
258
|
+
tslib_1.__metadata("design:type", Number)
|
|
259
|
+
], LearningContentUnit.prototype, "seq", void 0);
|
|
260
|
+
tslib_1.__decorate([
|
|
261
|
+
(0, type_graphql_1.Field)({ description: 'VIDEO, PDF, MARKDOWN or LINK.' }),
|
|
262
|
+
tslib_1.__metadata("design:type", String)
|
|
263
|
+
], LearningContentUnit.prototype, "kind", void 0);
|
|
264
|
+
tslib_1.__decorate([
|
|
265
|
+
(0, type_graphql_1.Field)({ description: 'Its name.' }),
|
|
266
|
+
tslib_1.__metadata("design:type", String)
|
|
267
|
+
], LearningContentUnit.prototype, "name", void 0);
|
|
268
|
+
tslib_1.__decorate([
|
|
269
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'The text of a MARKDOWN unit, the address of a LINK.' }),
|
|
270
|
+
tslib_1.__metadata("design:type", String)
|
|
271
|
+
], LearningContentUnit.prototype, "text", void 0);
|
|
272
|
+
exports.LearningContentUnit = LearningContentUnit = tslib_1.__decorate([
|
|
273
|
+
(0, type_graphql_1.ObjectType)({ description: 'A unit as the assistant reads it' })
|
|
274
|
+
], LearningContentUnit);
|
|
275
|
+
let LearningContent = class LearningContent {
|
|
276
|
+
};
|
|
277
|
+
exports.LearningContent = LearningContent;
|
|
278
|
+
tslib_1.__decorate([
|
|
279
|
+
(0, type_graphql_1.Field)({ description: 'The course.' }),
|
|
280
|
+
tslib_1.__metadata("design:type", String)
|
|
281
|
+
], LearningContent.prototype, "course", void 0);
|
|
282
|
+
tslib_1.__decorate([
|
|
283
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'The version number.' }),
|
|
284
|
+
tslib_1.__metadata("design:type", Number)
|
|
285
|
+
], LearningContent.prototype, "version", void 0);
|
|
286
|
+
tslib_1.__decorate([
|
|
287
|
+
(0, type_graphql_1.Field)(type => [LearningContentUnit], { description: 'Its units.' }),
|
|
288
|
+
tslib_1.__metadata("design:type", Array)
|
|
289
|
+
], LearningContent.prototype, "units", void 0);
|
|
290
|
+
exports.LearningContent = LearningContent = tslib_1.__decorate([
|
|
291
|
+
(0, type_graphql_1.ObjectType)({ description: 'The units of one course version, as the assistant reads them' })
|
|
292
|
+
], LearningContent);
|
|
293
|
+
//# sourceMappingURL=enrollment-type.js.map
|