@things-factory/learning 0.0.0-stage → 10.1.260

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.
Files changed (149) hide show
  1. package/dist-client/bootstrap.d.ts +2 -0
  2. package/dist-client/bootstrap.js +4 -0
  3. package/dist-client/bootstrap.js.map +1 -0
  4. package/dist-client/components/learning-assign-form.d.ts +24 -0
  5. package/dist-client/components/learning-assign-form.js +77 -0
  6. package/dist-client/components/learning-assign-form.js.map +1 -0
  7. package/dist-client/components/learning-course-form.d.ts +29 -0
  8. package/dist-client/components/learning-course-form.js +104 -0
  9. package/dist-client/components/learning-course-form.js.map +1 -0
  10. package/dist-client/components/learning-question-form.d.ts +33 -0
  11. package/dist-client/components/learning-question-form.js +142 -0
  12. package/dist-client/components/learning-question-form.js.map +1 -0
  13. package/dist-client/components/learning-todo.d.ts +12 -0
  14. package/dist-client/components/learning-todo.js +43 -0
  15. package/dist-client/components/learning-todo.js.map +1 -0
  16. package/dist-client/components/learning-unit-form.d.ts +41 -0
  17. package/dist-client/components/learning-unit-form.js +143 -0
  18. package/dist-client/components/learning-unit-form.js.map +1 -0
  19. package/dist-client/index.d.ts +2 -0
  20. package/dist-client/index.js +3 -0
  21. package/dist-client/index.js.map +1 -0
  22. package/dist-client/pages/learning-course-editor.d.ts +62 -0
  23. package/dist-client/pages/learning-course-editor.js +463 -0
  24. package/dist-client/pages/learning-course-editor.js.map +1 -0
  25. package/dist-client/pages/learning-course-list.d.ts +37 -0
  26. package/dist-client/pages/learning-course-list.js +88 -0
  27. package/dist-client/pages/learning-course-list.js.map +1 -0
  28. package/dist-client/pages/learning-enrollment-status.d.ts +53 -0
  29. package/dist-client/pages/learning-enrollment-status.js +228 -0
  30. package/dist-client/pages/learning-enrollment-status.js.map +1 -0
  31. package/dist-client/pages/learning-view.d.ts +52 -0
  32. package/dist-client/pages/learning-view.js +371 -0
  33. package/dist-client/pages/learning-view.js.map +1 -0
  34. package/dist-client/pages/my-learning.d.ts +22 -0
  35. package/dist-client/pages/my-learning.js +110 -0
  36. package/dist-client/pages/my-learning.js.map +1 -0
  37. package/dist-client/route.d.ts +1 -0
  38. package/dist-client/route.js +21 -0
  39. package/dist-client/route.js.map +1 -0
  40. package/dist-client/tsconfig.tsbuildinfo +1 -0
  41. package/dist-client/utils/learning-api.d.ts +16 -0
  42. package/dist-client/utils/learning-api.js +36 -0
  43. package/dist-client/utils/learning-api.js.map +1 -0
  44. package/dist-client/utils/learning-words.d.ts +20 -0
  45. package/dist-client/utils/learning-words.js +22 -0
  46. package/dist-client/utils/learning-words.js.map +1 -0
  47. package/dist-server/activities.d.ts +38 -0
  48. package/dist-server/activities.js +42 -0
  49. package/dist-server/activities.js.map +1 -0
  50. package/dist-server/ai-reads.d.ts +9 -0
  51. package/dist-server/ai-reads.js +70 -0
  52. package/dist-server/ai-reads.js.map +1 -0
  53. package/dist-server/attachment-reader.d.ts +1 -0
  54. package/dist-server/attachment-reader.js +23 -0
  55. package/dist-server/attachment-reader.js.map +1 -0
  56. package/dist-server/index.d.ts +4 -0
  57. package/dist-server/index.js +33 -0
  58. package/dist-server/index.js.map +1 -0
  59. package/dist-server/learning-subjects.d.ts +10 -0
  60. package/dist-server/learning-subjects.js +31 -0
  61. package/dist-server/learning-subjects.js.map +1 -0
  62. package/dist-server/role-tasks.d.ts +2 -0
  63. package/dist-server/role-tasks.js +17 -0
  64. package/dist-server/role-tasks.js.map +1 -0
  65. package/dist-server/service/course/course-mutation.d.ts +19 -0
  66. package/dist-server/service/course/course-mutation.js +176 -0
  67. package/dist-server/service/course/course-mutation.js.map +1 -0
  68. package/dist-server/service/course/course-query.d.ts +26 -0
  69. package/dist-server/service/course/course-query.js +172 -0
  70. package/dist-server/service/course/course-query.js.map +1 -0
  71. package/dist-server/service/course/course-question.d.ts +41 -0
  72. package/dist-server/service/course/course-question.js +116 -0
  73. package/dist-server/service/course/course-question.js.map +1 -0
  74. package/dist-server/service/course/course-rules.d.ts +49 -0
  75. package/dist-server/service/course/course-rules.js +89 -0
  76. package/dist-server/service/course/course-rules.js.map +1 -0
  77. package/dist-server/service/course/course-service.d.ts +71 -0
  78. package/dist-server/service/course/course-service.js +402 -0
  79. package/dist-server/service/course/course-service.js.map +1 -0
  80. package/dist-server/service/course/course-type.d.ts +55 -0
  81. package/dist-server/service/course/course-type.js +198 -0
  82. package/dist-server/service/course/course-type.js.map +1 -0
  83. package/dist-server/service/course/course-unit.d.ts +36 -0
  84. package/dist-server/service/course/course-unit.js +123 -0
  85. package/dist-server/service/course/course-unit.js.map +1 -0
  86. package/dist-server/service/course/course-version.d.ts +45 -0
  87. package/dist-server/service/course/course-version.js +151 -0
  88. package/dist-server/service/course/course-version.js.map +1 -0
  89. package/dist-server/service/course/course.d.ts +23 -0
  90. package/dist-server/service/course/course.js +92 -0
  91. package/dist-server/service/course/course.js.map +1 -0
  92. package/dist-server/service/course/index.d.ts +14 -0
  93. package/dist-server/service/course/index.js +24 -0
  94. package/dist-server/service/course/index.js.map +1 -0
  95. package/dist-server/service/enrollment/enrollment-mutation.d.ts +11 -0
  96. package/dist-server/service/enrollment/enrollment-mutation.js +124 -0
  97. package/dist-server/service/enrollment/enrollment-mutation.js.map +1 -0
  98. package/dist-server/service/enrollment/enrollment-query.d.ts +23 -0
  99. package/dist-server/service/enrollment/enrollment-query.js +245 -0
  100. package/dist-server/service/enrollment/enrollment-query.js.map +1 -0
  101. package/dist-server/service/enrollment/enrollment-remind.d.ts +1 -0
  102. package/dist-server/service/enrollment/enrollment-remind.js +45 -0
  103. package/dist-server/service/enrollment/enrollment-remind.js.map +1 -0
  104. package/dist-server/service/enrollment/enrollment-service.d.ts +110 -0
  105. package/dist-server/service/enrollment/enrollment-service.js +417 -0
  106. package/dist-server/service/enrollment/enrollment-service.js.map +1 -0
  107. package/dist-server/service/enrollment/enrollment-status.d.ts +40 -0
  108. package/dist-server/service/enrollment/enrollment-status.js +135 -0
  109. package/dist-server/service/enrollment/enrollment-status.js.map +1 -0
  110. package/dist-server/service/enrollment/enrollment-type.d.ts +95 -0
  111. package/dist-server/service/enrollment/enrollment-type.js +341 -0
  112. package/dist-server/service/enrollment/enrollment-type.js.map +1 -0
  113. package/dist-server/service/enrollment/enrollment.d.ts +52 -0
  114. package/dist-server/service/enrollment/enrollment.js +186 -0
  115. package/dist-server/service/enrollment/enrollment.js.map +1 -0
  116. package/dist-server/service/enrollment/index.d.ts +15 -0
  117. package/dist-server/service/enrollment/index.js +26 -0
  118. package/dist-server/service/enrollment/index.js.map +1 -0
  119. package/dist-server/service/enrollment/learning-ai.d.ts +38 -0
  120. package/dist-server/service/enrollment/learning-ai.js +96 -0
  121. package/dist-server/service/enrollment/learning-ai.js.map +1 -0
  122. package/dist-server/service/enrollment/learning-documents.d.ts +7 -0
  123. package/dist-server/service/enrollment/learning-documents.js +160 -0
  124. package/dist-server/service/enrollment/learning-documents.js.map +1 -0
  125. package/dist-server/service/enrollment/learning-outcome.d.ts +10 -0
  126. package/dist-server/service/enrollment/learning-outcome.js +16 -0
  127. package/dist-server/service/enrollment/learning-outcome.js.map +1 -0
  128. package/dist-server/service/enrollment/progress-rules.d.ts +94 -0
  129. package/dist-server/service/enrollment/progress-rules.js +97 -0
  130. package/dist-server/service/enrollment/progress-rules.js.map +1 -0
  131. package/dist-server/service/enrollment/quiz-attempt.d.ts +34 -0
  132. package/dist-server/service/enrollment/quiz-attempt.js +105 -0
  133. package/dist-server/service/enrollment/quiz-attempt.js.map +1 -0
  134. package/dist-server/service/enrollment/unit-progress.d.ts +30 -0
  135. package/dist-server/service/enrollment/unit-progress.js +114 -0
  136. package/dist-server/service/enrollment/unit-progress.js.map +1 -0
  137. package/dist-server/service/index.d.ts +14 -0
  138. package/dist-server/service/index.js +43 -0
  139. package/dist-server/service/index.js.map +1 -0
  140. package/dist-server/tsconfig.tsbuildinfo +1 -0
  141. package/package.json +56 -4
  142. package/things-factory.config.js +14 -0
  143. package/translations/en.json +255 -0
  144. package/translations/es.json +255 -0
  145. package/translations/ja.json +255 -0
  146. package/translations/ko.json +255 -0
  147. package/translations/ms.json +255 -0
  148. package/translations/zh.json +255 -0
  149. package/README.md +0 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-words.js","sourceRoot":"","sources":["../../client/utils/learning-words.ts"],"names":[],"mappings":"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","sourcesContent":["import { i18next } from '@operato/i18n'\n\n/** A word of this module - its translations, the key printed only when none is found. */\nexport const t = (key: string, options: Record<string, unknown> = {}) => i18next.t(key, options) as string\n\nexport const STATES = ['ASSIGNED', 'IN_PROGRESS', 'COMPLETED', 'OVERDUE', 'CANCELLED'] as const\nexport const stateWord = (state?: string | null) => (state ? t(`text.learning-state-${state.toLowerCase().replace(/_/g, '-')}`) : '')\n\nexport const CATEGORIES = ['MANDATORY', 'ONBOARDING', 'JOB', 'PRODUCT', 'RULES', 'OTHER'] as const\nexport const categoryWord = (category?: string | null) => (category ? t(`text.learning-category-${category.toLowerCase()}`) : '')\n\nexport const UNIT_KINDS = ['VIDEO', 'PDF', 'MARKDOWN', 'LINK'] as const\nexport const unitKindWord = (kind?: string | null) => (kind ? t(`text.learning-unit-${kind.toLowerCase()}`) : '')\n\nexport const QUESTION_KINDS = ['SINGLE', 'MULTIPLE', 'TRUE_FALSE'] as const\nexport const questionKindWord = (kind?: string | null) => (kind ? t(`text.learning-question-${kind.toLowerCase().replace(/_/g, '-')}`) : '')\n\nexport const VERSION_STATUSES = ['DRAFT', 'PUBLISHED', 'CLOSED'] as const\nexport const versionStatusWord = (status?: string | null) => (status ? t(`text.learning-version-${status.toLowerCase()}`) : '')\n\nexport const SOURCE_KINDS = ['PUBLIC', 'OWN', 'PURCHASED'] as const\nexport const sourceKindWord = (kind?: string | null) => (kind ? t(`text.learning-source-${kind.toLowerCase()}`) : '')\n\n/** What still stands before completion, said as the learner reads it. */\nexport const missingWord = (missing: string) => t(`text.learning-missing-${missing}`)\n\n/** Seconds as whole minutes - a learner reads time in minutes. */\nexport const minutesOf = (seconds?: number | null) => Math.floor((seconds ?? 0) / 60)\n\n/** A moment as the day it fell on, in the browser's time. */\nexport const dayOf = (at?: string | Date | null) => (at ? new Intl.DateTimeFormat('en-CA', { year: 'numeric', month: '2-digit', day: '2-digit' }).format(new Date(at)) : '')\n"]}
@@ -0,0 +1,38 @@
1
+ export declare const LEARNING_COURSE_ACTIVITY = "Learning Course";
2
+ export declare const LEARNING_ACTIVITIES: {
3
+ name: string;
4
+ label: string;
5
+ description: string;
6
+ guide: string[];
7
+ release: string;
8
+ provider: string;
9
+ category: string;
10
+ activityType: string;
11
+ priority: number;
12
+ startingType: string;
13
+ multiple: string;
14
+ uiType: string;
15
+ uiSource: string;
16
+ searchKeys: {
17
+ name: string;
18
+ description: string;
19
+ inputKey: string;
20
+ tKey: string;
21
+ }[];
22
+ viewType: string;
23
+ viewSource: string;
24
+ model: {
25
+ name: string;
26
+ description: string;
27
+ tag: string;
28
+ hidden: boolean;
29
+ mandatory: boolean;
30
+ inout: string;
31
+ type: string;
32
+ options: {};
33
+ unit: any;
34
+ quantifier: number[];
35
+ spec: {};
36
+ }[];
37
+ standardTime: number;
38
+ }[];
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LEARNING_ACTIVITIES = exports.LEARNING_COURSE_ACTIVITY = void 0;
4
+ /*
5
+ * 수강 (ADR-0194 decision 5) - not an approval: one person is asked to take one course by a day. It shows the course and
6
+ * the day, with the way to the course (`learning-todo`). Completing the course ends it as done; a withdrawn or cancelled
7
+ * enrolment aborts it. Reminding one past its day is worklist's (ADR-0186).
8
+ *
9
+ * Data only. An application installs it into its domains (Office `REQUIRED_ACTIVITIES`).
10
+ */
11
+ exports.LEARNING_COURSE_ACTIVITY = 'Learning Course';
12
+ exports.LEARNING_ACTIVITIES = [
13
+ {
14
+ name: exports.LEARNING_COURSE_ACTIVITY,
15
+ label: 'course learning',
16
+ description: 'A course to take by a day',
17
+ guide: [
18
+ 'an enrolment hands it out - a mandatory training session, onboarding, or a manager assigning a course.',
19
+ 'it opens the course; completing the course ends it.',
20
+ 'a to-do past its day is reminded as every overdue to-do is.'
21
+ ],
22
+ release: '1.0.0',
23
+ provider: 'hatiolab.com',
24
+ category: 'learning',
25
+ activityType: 'user',
26
+ priority: 2,
27
+ startingType: 'issue',
28
+ multiple: 'single',
29
+ uiType: 'custom-element',
30
+ uiSource: 'learning-todo',
31
+ searchKeys: [{ name: 'headline', description: 'The course and its due day', inputKey: 'headline', tKey: 'field.subject' }],
32
+ viewType: '',
33
+ viewSource: '',
34
+ model: [
35
+ { name: 'enrollmentId', description: 'The enrolment', tag: 'enrollmentId', hidden: true, mandatory: true, inout: 'in', type: 'string', options: {}, unit: null, quantifier: [1], spec: {} },
36
+ { name: 'headline', description: 'The course and its due day', tag: 'headline', hidden: true, mandatory: true, inout: 'in', type: 'string', options: {}, unit: null, quantifier: [1], spec: {} },
37
+ { name: 'address', description: 'The course screen', tag: 'address', hidden: true, mandatory: true, inout: 'in', type: 'string', options: {}, unit: null, quantifier: [1], spec: {} }
38
+ ],
39
+ standardTime: 14 * 24 * 60 * 60
40
+ }
41
+ ];
42
+ //# sourceMappingURL=activities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activities.js","sourceRoot":"","sources":["../server/activities.ts"],"names":[],"mappings":";;;AAAA;;;;;;GAMG;AACU,QAAA,wBAAwB,GAAG,iBAAiB,CAAA;AAE5C,QAAA,mBAAmB,GAAG;IACjC;QACE,IAAI,EAAE,gCAAwB;QAC9B,KAAK,EAAE,iBAAiB;QACxB,WAAW,EAAE,2BAA2B;QACxC,KAAK,EAAE;YACL,wGAAwG;YACxG,qDAAqD;YACrD,6DAA6D;SAC9D;QACD,OAAO,EAAE,OAAO;QAChB,QAAQ,EAAE,cAAc;QACxB,QAAQ,EAAE,UAAU;QACpB,YAAY,EAAE,MAAM;QACpB,QAAQ,EAAE,CAAC;QACX,YAAY,EAAE,OAAO;QACrB,QAAQ,EAAE,QAAQ;QAClB,MAAM,EAAE,gBAAgB;QACxB,QAAQ,EAAE,eAAe;QACzB,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,4BAA4B,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;QAC1H,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,EAAE;QACd,KAAK,EAAE;YACL,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;YAC3L,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,4BAA4B,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;YAChM,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,mBAAmB,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;SACtL;QACD,YAAY,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;KAChC;CACF,CAAA","sourcesContent":["/*\n * 수강 (ADR-0194 decision 5) - not an approval: one person is asked to take one course by a day. It shows the course and\n * the day, with the way to the course (`learning-todo`). Completing the course ends it as done; a withdrawn or cancelled\n * enrolment aborts it. Reminding one past its day is worklist's (ADR-0186).\n *\n * Data only. An application installs it into its domains (Office `REQUIRED_ACTIVITIES`).\n */\nexport const LEARNING_COURSE_ACTIVITY = 'Learning Course'\n\nexport const LEARNING_ACTIVITIES = [\n {\n name: LEARNING_COURSE_ACTIVITY,\n label: 'course learning',\n description: 'A course to take by a day',\n guide: [\n 'an enrolment hands it out - a mandatory training session, onboarding, or a manager assigning a course.',\n 'it opens the course; completing the course ends it.',\n 'a to-do past its day is reminded as every overdue to-do is.'\n ],\n release: '1.0.0',\n provider: 'hatiolab.com',\n category: 'learning',\n activityType: 'user',\n priority: 2,\n startingType: 'issue',\n multiple: 'single',\n uiType: 'custom-element',\n uiSource: 'learning-todo',\n searchKeys: [{ name: 'headline', description: 'The course and its due day', inputKey: 'headline', tKey: 'field.subject' }],\n viewType: '',\n viewSource: '',\n model: [\n { name: 'enrollmentId', description: 'The enrolment', tag: 'enrollmentId', hidden: true, mandatory: true, inout: 'in', type: 'string', options: {}, unit: null, quantifier: [1], spec: {} },\n { name: 'headline', description: 'The course and its due day', tag: 'headline', hidden: true, mandatory: true, inout: 'in', type: 'string', options: {}, unit: null, quantifier: [1], spec: {} },\n { name: 'address', description: 'The course screen', tag: 'address', hidden: true, mandatory: true, inout: 'in', type: 'string', options: {}, unit: null, quantifier: [1], spec: {} }\n ],\n standardTime: 14 * 24 * 60 * 60\n }\n]\n"]}
@@ -0,0 +1,9 @@
1
+ import { type DetailRead, type EntryTarget, type ListRead } from '@things-factory/ai-assistant';
2
+ export declare const LEARNING_ENROLLMENTS_READ: ListRead;
3
+ export declare const LEARNING_CONTENT_READ: DetailRead;
4
+ export declare const QUESTION_DRAFT_TARGET: EntryTarget;
5
+ export declare function registerLearningReads(): void;
6
+ /** The keys an application's assistant mode names to read learning. */
7
+ export declare const LEARNING_READ_TARGETS: string[];
8
+ /** The keys an application's assistant mode names to let the assistant enter learning records. */
9
+ export declare const LEARNING_ENTRY_TARGETS: string[];
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LEARNING_ENTRY_TARGETS = exports.LEARNING_READ_TARGETS = exports.QUESTION_DRAFT_TARGET = exports.LEARNING_CONTENT_READ = exports.LEARNING_ENROLLMENTS_READ = void 0;
4
+ exports.registerLearningReads = registerLearningReads;
5
+ /*
6
+ * The assistant's reads and entry of learning (ADR-0194 decision 12) - registered at load; an application names the keys
7
+ * in its assistant mode's `readTargets`.
8
+ */
9
+ const ai_assistant_1 = require("@things-factory/ai-assistant");
10
+ const learning_ai_1 = require("./service/enrollment/learning-ai");
11
+ exports.LEARNING_ENROLLMENTS_READ = {
12
+ key: 'learning.enrollments',
13
+ title: 'title.learning-enrollment-status',
14
+ name: 'Course enrolments (수강) - who is to take which course by when and where each stands: ASSIGNED (not started), IN_PROGRESS, COMPLETED or OVERDUE (open past its due day), with the days left to the due day. A manager reads everyone, a department head their people, anyone else their own.',
15
+ listQuery: 'learningEnrollments',
16
+ selection: 'id learner departmentName course state dueOn daysLeft startedAt completedAt unitsDone units',
17
+ columns: [
18
+ { name: 'learner', type: 'string', labelKey: 'field.learning-learner' },
19
+ { name: 'departmentName', type: 'string', labelKey: 'field.learning-department' },
20
+ { name: 'course', type: 'string', labelKey: 'field.learning-course-name' },
21
+ { name: 'state', type: 'string', labelKey: 'field.learning-state' },
22
+ { name: 'dueOn', type: 'date', labelKey: 'field.learning-due-on' },
23
+ { name: 'daysLeft', type: 'number', labelKey: 'field.learning-days-left' },
24
+ { name: 'completedAt', type: 'date', labelKey: 'field.learning-completed-on' },
25
+ { name: 'unitsDone', type: 'number', labelKey: 'field.learning-units-done' }
26
+ ],
27
+ status: { field: 'state', values: ['ASSIGNED', 'IN_PROGRESS', 'COMPLETED', 'OVERDUE'] },
28
+ search: "learner's name, department or course",
29
+ route: 'learning-enrollment-status'
30
+ };
31
+ exports.LEARNING_CONTENT_READ = {
32
+ key: 'learning.course-content',
33
+ labelKey: 'title.learning-units',
34
+ description: "The units of one course version - names and texts - to answer a question on the course the person is taking (give their enrollmentId; only that course's version, refused while their quiz attempt is open - do not help with the quiz) or, for a manager, to draft questions of a version (give versionId). Answer only from these units.",
35
+ query: 'query ($enrollmentId: String, $versionId: String) { learningContent(enrollmentId: $enrollmentId, versionId: $versionId) { course version units { seq kind name text } } }',
36
+ args: [
37
+ { name: 'enrollmentId', type: 'string', axis: 'enrollment', description: 'The enrolment open on the course screen (learning-view?id=...)' },
38
+ { name: 'versionId', type: 'string', axis: 'course-version', description: 'A version open in the course editor - managers only' }
39
+ ]
40
+ };
41
+ exports.QUESTION_DRAFT_TARGET = {
42
+ key: 'learning.question-draft',
43
+ labelKey: 'title.learning-questions',
44
+ description: 'A quiz question drafted from the units of a DRAFT course version (read learning.course-content with its versionId first). It is entered marked as an AI draft; a manager reviews and saves it before the version can be published. Only a draft version takes it.',
45
+ fields: [
46
+ { name: 'versionId', type: 'string', required: true, axis: 'course-version', description: 'The draft version the question belongs to', labelKey: 'title.learning-versions' },
47
+ { name: 'kind', type: 'enum', required: true, values: ['SINGLE', 'MULTIPLE', 'TRUE_FALSE'], valueKeyPrefix: 'text.learning-question-', labelKey: 'field.learning-question-kind' },
48
+ { name: 'text', type: 'text', required: true, description: 'What it asks - from the units only', labelKey: 'field.learning-question-text' },
49
+ { name: 'choices', type: 'text', required: true, description: 'One choice a line; start each right choice with *. TRUE_FALSE has two lines.', labelKey: 'field.learning-question-choices' },
50
+ { name: 'explanation', type: 'text', description: 'Why the answer is right, citing the unit', labelKey: 'field.learning-question-explanation' }
51
+ ],
52
+ mutation: 'mutation ($versionId: String!, $question: CourseQuestionInput!) { addDraftedCourseQuestion(versionId: $versionId, question: $question) { id } }',
53
+ variables: row => ({
54
+ versionId: row.values.versionId,
55
+ question: { kind: row.values.kind, text: row.values.text, choices: (0, learning_ai_1.choicesOfText)(String(row.values.choices ?? '')), explanation: row.values.explanation ?? null }
56
+ }),
57
+ appliedOf: (data, row) => ({ id: data?.addDraftedCourseQuestion?.id, label: String(row.values.text ?? '').slice(0, 60) }),
58
+ screen: 'learning-course-editor',
59
+ maxRows: 30
60
+ };
61
+ function registerLearningReads() {
62
+ (0, ai_assistant_1.registerReadTarget)((0, ai_assistant_1.listReadTarget)(exports.LEARNING_ENROLLMENTS_READ));
63
+ (0, ai_assistant_1.registerDetailRead)(exports.LEARNING_CONTENT_READ);
64
+ (0, ai_assistant_1.registerEntryTarget)(exports.QUESTION_DRAFT_TARGET);
65
+ }
66
+ /** The keys an application's assistant mode names to read learning. */
67
+ exports.LEARNING_READ_TARGETS = [exports.LEARNING_ENROLLMENTS_READ.key, exports.LEARNING_CONTENT_READ.key];
68
+ /** The keys an application's assistant mode names to let the assistant enter learning records. */
69
+ exports.LEARNING_ENTRY_TARGETS = [exports.QUESTION_DRAFT_TARGET.key];
70
+ //# sourceMappingURL=ai-reads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-reads.js","sourceRoot":"","sources":["../server/ai-reads.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The assistant's reads and entry of learning (ADR-0194 decision 12) - registered at load; an application names the keys\n * in its assistant mode's `readTargets`.\n */\nimport { listReadTarget, registerDetailRead, registerEntryTarget, registerReadTarget, type DetailRead, type EntryTarget, type ListRead } from '@things-factory/ai-assistant'\n\nimport { choicesOfText } from './service/enrollment/learning-ai'\n\nexport const LEARNING_ENROLLMENTS_READ: ListRead = {\n key: 'learning.enrollments',\n title: 'title.learning-enrollment-status',\n name: 'Course enrolments (수강) - who is to take which course by when and where each stands: ASSIGNED (not started), IN_PROGRESS, COMPLETED or OVERDUE (open past its due day), with the days left to the due day. A manager reads everyone, a department head their people, anyone else their own.',\n listQuery: 'learningEnrollments',\n selection: 'id learner departmentName course state dueOn daysLeft startedAt completedAt unitsDone units',\n columns: [\n { name: 'learner', type: 'string', labelKey: 'field.learning-learner' },\n { name: 'departmentName', type: 'string', labelKey: 'field.learning-department' },\n { name: 'course', type: 'string', labelKey: 'field.learning-course-name' },\n { name: 'state', type: 'string', labelKey: 'field.learning-state' },\n { name: 'dueOn', type: 'date', labelKey: 'field.learning-due-on' },\n { name: 'daysLeft', type: 'number', labelKey: 'field.learning-days-left' },\n { name: 'completedAt', type: 'date', labelKey: 'field.learning-completed-on' },\n { name: 'unitsDone', type: 'number', labelKey: 'field.learning-units-done' }\n ],\n status: { field: 'state', values: ['ASSIGNED', 'IN_PROGRESS', 'COMPLETED', 'OVERDUE'] },\n search: \"learner's name, department or course\",\n route: 'learning-enrollment-status'\n}\n\nexport const LEARNING_CONTENT_READ: DetailRead = {\n key: 'learning.course-content',\n labelKey: 'title.learning-units',\n description:\n \"The units of one course version - names and texts - to answer a question on the course the person is taking (give their enrollmentId; only that course's version, refused while their quiz attempt is open - do not help with the quiz) or, for a manager, to draft questions of a version (give versionId). Answer only from these units.\",\n query: 'query ($enrollmentId: String, $versionId: String) { learningContent(enrollmentId: $enrollmentId, versionId: $versionId) { course version units { seq kind name text } } }',\n args: [\n { name: 'enrollmentId', type: 'string', axis: 'enrollment', description: 'The enrolment open on the course screen (learning-view?id=...)' },\n { name: 'versionId', type: 'string', axis: 'course-version', description: 'A version open in the course editor - managers only' }\n ]\n}\n\nexport const QUESTION_DRAFT_TARGET: EntryTarget = {\n key: 'learning.question-draft',\n labelKey: 'title.learning-questions',\n description:\n 'A quiz question drafted from the units of a DRAFT course version (read learning.course-content with its versionId first). It is entered marked as an AI draft; a manager reviews and saves it before the version can be published. Only a draft version takes it.',\n fields: [\n { name: 'versionId', type: 'string', required: true, axis: 'course-version', description: 'The draft version the question belongs to', labelKey: 'title.learning-versions' },\n { name: 'kind', type: 'enum', required: true, values: ['SINGLE', 'MULTIPLE', 'TRUE_FALSE'], valueKeyPrefix: 'text.learning-question-', labelKey: 'field.learning-question-kind' },\n { name: 'text', type: 'text', required: true, description: 'What it asks - from the units only', labelKey: 'field.learning-question-text' },\n { name: 'choices', type: 'text', required: true, description: 'One choice a line; start each right choice with *. TRUE_FALSE has two lines.', labelKey: 'field.learning-question-choices' },\n { name: 'explanation', type: 'text', description: 'Why the answer is right, citing the unit', labelKey: 'field.learning-question-explanation' }\n ],\n mutation: 'mutation ($versionId: String!, $question: CourseQuestionInput!) { addDraftedCourseQuestion(versionId: $versionId, question: $question) { id } }',\n variables: row => ({\n versionId: row.values.versionId,\n question: { kind: row.values.kind, text: row.values.text, choices: choicesOfText(String(row.values.choices ?? '')), explanation: row.values.explanation ?? null }\n }),\n appliedOf: (data, row) => ({ id: data?.addDraftedCourseQuestion?.id, label: String(row.values.text ?? '').slice(0, 60) }),\n screen: 'learning-course-editor',\n maxRows: 30\n}\n\nexport function registerLearningReads(): void {\n registerReadTarget(listReadTarget(LEARNING_ENROLLMENTS_READ))\n registerDetailRead(LEARNING_CONTENT_READ)\n registerEntryTarget(QUESTION_DRAFT_TARGET)\n}\n\n/** The keys an application's assistant mode names to read learning. */\nexport const LEARNING_READ_TARGETS = [LEARNING_ENROLLMENTS_READ.key, LEARNING_CONTENT_READ.key]\n\n/** The keys an application's assistant mode names to let the assistant enter learning records. */\nexport const LEARNING_ENTRY_TARGETS = [QUESTION_DRAFT_TARGET.key]\n"]}
@@ -0,0 +1 @@
1
+ export declare function registerLearningFiles(): void;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerLearningFiles = registerLearningFiles;
4
+ /*
5
+ * Who may open a unit's file by its path (ADR-0194 decisions 3, 11) - whoever may read the unit's version
6
+ * (`mayReadVersion`: a manager, or a learner whose enrolment shows that version), the same rule the GraphQL fields ask.
7
+ * attachment-base has already checked the file is of the request's domain.
8
+ */
9
+ const attachment_base_1 = require("@things-factory/attachment-base");
10
+ const shell_1 = require("@things-factory/shell");
11
+ const course_1 = require("./service/course");
12
+ const course_unit_1 = require("./service/course/course-unit");
13
+ const course_version_1 = require("./service/course/course-version");
14
+ const course_service_1 = require("./service/course/course-service");
15
+ function registerLearningFiles() {
16
+ (0, attachment_base_1.registerAttachmentReader)(course_1.COURSE_UNIT_REF_TYPE, async (attachment, context) => {
17
+ const unit = attachment.refBy ? await (0, shell_1.getRepository)(course_unit_1.CourseUnit).findOne({ where: { id: attachment.refBy, domain: { id: context.state.domain.id } } }) : null;
18
+ if (!unit)
19
+ return false;
20
+ return await (0, course_service_1.mayReadVersion)(context, await (0, shell_1.getRepository)(course_version_1.CourseVersion).findOne({ where: { id: unit.versionId }, withDeleted: true }));
21
+ });
22
+ }
23
+ //# sourceMappingURL=attachment-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-reader.js","sourceRoot":"","sources":["../server/attachment-reader.ts"],"names":[],"mappings":";;AAaA,sDAMC;AAnBD;;;;GAIG;AACH,qEAA0E;AAC1E,iDAAqD;AAErD,6CAAuD;AACvD,8DAAyD;AACzD,oEAA+D;AAC/D,oEAAgE;AAEhE,SAAgB,qBAAqB;IACnC,IAAA,0CAAwB,EAAC,6BAAoB,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE;QAC3E,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,wBAAU,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAS,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QACnK,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAA;QACvB,OAAO,MAAM,IAAA,+BAAc,EAAC,OAAO,EAAE,MAAM,IAAA,qBAAa,EAAC,8BAAa,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,SAAS,EAAS,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAC/I,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["/*\n * Who may open a unit's file by its path (ADR-0194 decisions 3, 11) - whoever may read the unit's version\n * (`mayReadVersion`: a manager, or a learner whose enrolment shows that version), the same rule the GraphQL fields ask.\n * attachment-base has already checked the file is of the request's domain.\n */\nimport { registerAttachmentReader } from '@things-factory/attachment-base'\nimport { getRepository } from '@things-factory/shell'\n\nimport { COURSE_UNIT_REF_TYPE } from './service/course'\nimport { CourseUnit } from './service/course/course-unit'\nimport { CourseVersion } from './service/course/course-version'\nimport { mayReadVersion } from './service/course/course-service'\n\nexport function registerLearningFiles(): void {\n registerAttachmentReader(COURSE_UNIT_REF_TYPE, async (attachment, context) => {\n const unit = attachment.refBy ? await getRepository(CourseUnit).findOne({ where: { id: attachment.refBy, domain: { id: context.state.domain.id } } as any }) : null\n if (!unit) return false\n return await mayReadVersion(context, await getRepository(CourseVersion).findOne({ where: { id: unit.versionId } as any, withDeleted: true }))\n })\n}\n"]}
@@ -0,0 +1,4 @@
1
+ export * from './service';
2
+ export { LEARNING_ACTIVITIES, LEARNING_COURSE_ACTIVITY } from './activities';
3
+ export { LEARNING_ENTRY_TARGETS, LEARNING_READ_TARGETS } from './ai-reads';
4
+ export { ROLE_TASKS as LEARNING_ROLE_TASKS } from './role-tasks';
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LEARNING_ROLE_TASKS = exports.LEARNING_READ_TARGETS = exports.LEARNING_ENTRY_TARGETS = exports.LEARNING_COURSE_ACTIVITY = exports.LEARNING_ACTIVITIES = void 0;
4
+ const tslib_1 = require("tslib");
5
+ tslib_1.__exportStar(require("./service"), exports);
6
+ var activities_1 = require("./activities");
7
+ Object.defineProperty(exports, "LEARNING_ACTIVITIES", { enumerable: true, get: function () { return activities_1.LEARNING_ACTIVITIES; } });
8
+ Object.defineProperty(exports, "LEARNING_COURSE_ACTIVITY", { enumerable: true, get: function () { return activities_1.LEARNING_COURSE_ACTIVITY; } });
9
+ var ai_reads_1 = require("./ai-reads");
10
+ Object.defineProperty(exports, "LEARNING_ENTRY_TARGETS", { enumerable: true, get: function () { return ai_reads_1.LEARNING_ENTRY_TARGETS; } });
11
+ Object.defineProperty(exports, "LEARNING_READ_TARGETS", { enumerable: true, get: function () { return ai_reads_1.LEARNING_READ_TARGETS; } });
12
+ var role_tasks_1 = require("./role-tasks");
13
+ Object.defineProperty(exports, "LEARNING_ROLE_TASKS", { enumerable: true, get: function () { return role_tasks_1.ROLE_TASKS; } });
14
+ const auth_base_1 = require("@things-factory/auth-base");
15
+ const worklist_1 = require("@things-factory/worklist");
16
+ const activities_2 = require("./activities");
17
+ const ai_reads_2 = require("./ai-reads");
18
+ const attachment_reader_1 = require("./attachment-reader");
19
+ const learning_subjects_1 = require("./learning-subjects");
20
+ const role_tasks_2 = require("./role-tasks");
21
+ const learning_documents_1 = require("./service/enrollment/learning-documents");
22
+ for (const task of role_tasks_2.ROLE_TASKS)
23
+ (0, auth_base_1.registerRoleTask)(task);
24
+ (0, attachment_reader_1.registerLearningFiles)();
25
+ (0, learning_documents_1.registerLearningDocuments)();
26
+ (0, ai_reads_2.registerLearningReads)();
27
+ (0, learning_subjects_1.registerLearningSubjects)();
28
+ /*
29
+ * Importing this file registers the learner's to-do (ADR-0194 decision 5) - a bootstrap hook would be too late for
30
+ * worklist to find it. Which domains have it is the application's call: it installs `LEARNING_ACTIVITIES`.
31
+ */
32
+ activities_2.LEARNING_ACTIVITIES.forEach(template => worklist_1.ActivityInstallations.installActivityTemplate(template));
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;;AAAA,oDAAyB;AACzB,2CAA4E;AAAnE,iHAAA,mBAAmB,OAAA;AAAE,sHAAA,wBAAwB,OAAA;AACtD,uCAA0E;AAAjE,kHAAA,sBAAsB,OAAA;AAAE,iHAAA,qBAAqB,OAAA;AACtD,2CAAgE;AAAvD,iHAAA,UAAU,OAAuB;AAE1C,yDAA4D;AAC5D,uDAAgE;AAEhE,6CAAkD;AAClD,yCAAkD;AAClD,2DAA2D;AAC3D,2DAA8D;AAC9D,6CAAyC;AACzC,gFAAmF;AAEnF,KAAK,MAAM,IAAI,IAAI,uBAAU;IAAE,IAAA,4BAAgB,EAAC,IAAI,CAAC,CAAA;AACrD,IAAA,yCAAqB,GAAE,CAAA;AACvB,IAAA,8CAAyB,GAAE,CAAA;AAC3B,IAAA,gCAAqB,GAAE,CAAA;AACvB,IAAA,4CAAwB,GAAE,CAAA;AAE1B;;;GAGG;AACH,gCAAmB,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,gCAAqB,CAAC,uBAAuB,CAAC,QAAe,CAAC,CAAC,CAAA","sourcesContent":["export * from './service'\nexport { LEARNING_ACTIVITIES, LEARNING_COURSE_ACTIVITY } from './activities'\nexport { LEARNING_ENTRY_TARGETS, LEARNING_READ_TARGETS } from './ai-reads'\nexport { ROLE_TASKS as LEARNING_ROLE_TASKS } from './role-tasks'\n\nimport { registerRoleTask } from '@things-factory/auth-base'\nimport { ActivityInstallations } from '@things-factory/worklist'\n\nimport { LEARNING_ACTIVITIES } from './activities'\nimport { registerLearningReads } from './ai-reads'\nimport { registerLearningFiles } from './attachment-reader'\nimport { registerLearningSubjects } from './learning-subjects'\nimport { ROLE_TASKS } from './role-tasks'\nimport { registerLearningDocuments } from './service/enrollment/learning-documents'\n\nfor (const task of ROLE_TASKS) registerRoleTask(task)\nregisterLearningFiles()\nregisterLearningDocuments()\nregisterLearningReads()\nregisterLearningSubjects()\n\n/*\n * Importing this file registers the learner's to-do (ADR-0194 decision 5) - a bootstrap hook would be too late for\n * worklist to find it. Which domains have it is the application's call: it installs `LEARNING_ACTIVITIES`.\n */\nLEARNING_ACTIVITIES.forEach(template => ActivityInstallations.installActivityTemplate(template as any))\n"]}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The enrolment and the course version open on screen, named for the assistant each turn (operato-application
3
+ * design/ai/screen-pattern.md §2-1, ADR-0194 decision 12). The course screen anchors its conversation to
4
+ * `enrollment:<uuid>` - its learner's own, read by `Query.myEnrollment` - and the course editor to `course-version:<uuid>`,
5
+ * read by `Query.courseVersion`; each is named only for someone that door lets through.
6
+ */
7
+ import { type RecordSubject } from '@things-factory/ai-assistant';
8
+ export declare const ENROLLMENT_SUBJECT: RecordSubject;
9
+ export declare const COURSE_VERSION_SUBJECT: RecordSubject;
10
+ export declare function registerLearningSubjects(): void;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.COURSE_VERSION_SUBJECT = exports.ENROLLMENT_SUBJECT = void 0;
4
+ exports.registerLearningSubjects = registerLearningSubjects;
5
+ /**
6
+ * The enrolment and the course version open on screen, named for the assistant each turn (operato-application
7
+ * design/ai/screen-pattern.md §2-1, ADR-0194 decision 12). The course screen anchors its conversation to
8
+ * `enrollment:<uuid>` - its learner's own, read by `Query.myEnrollment` - and the course editor to `course-version:<uuid>`,
9
+ * read by `Query.courseVersion`; each is named only for someone that door lets through.
10
+ */
11
+ const ai_assistant_1 = require("@things-factory/ai-assistant");
12
+ const shell_1 = require("@things-factory/shell");
13
+ exports.ENROLLMENT_SUBJECT = {
14
+ axis: 'enrollment',
15
+ noun: 'course enrolment',
16
+ door: 'Query.myEnrollment',
17
+ read: (rowId, domainId) => (0, shell_1.getRepository)('Enrollment').findOne({ where: { id: rowId, domain: { id: domainId } }, relations: ['course'] }),
18
+ nameOf: row => row.course?.name ?? ''
19
+ };
20
+ exports.COURSE_VERSION_SUBJECT = {
21
+ axis: 'course-version',
22
+ noun: 'course version',
23
+ door: 'Query.courseVersion',
24
+ read: (rowId, domainId) => (0, shell_1.getRepository)('CourseVersion').findOne({ where: { id: rowId, domain: { id: domainId } }, relations: ['course'] }),
25
+ nameOf: row => (row.course?.name ? `${row.course.name} v${row.number} (${row.status})` : '')
26
+ };
27
+ function registerLearningSubjects() {
28
+ (0, ai_assistant_1.registerRecordSubject)(exports.ENROLLMENT_SUBJECT);
29
+ (0, ai_assistant_1.registerRecordSubject)(exports.COURSE_VERSION_SUBJECT);
30
+ }
31
+ //# sourceMappingURL=learning-subjects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-subjects.js","sourceRoot":"","sources":["../server/learning-subjects.ts"],"names":[],"mappings":";;;AAyBA,4DAGC;AA5BD;;;;;GAKG;AACH,+DAAwF;AACxF,iDAAqD;AAExC,QAAA,kBAAkB,GAAkB;IAC/C,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,kBAAkB;IACxB,IAAI,EAAE,oBAAoB;IAC1B,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,IAAA,qBAAa,EAAC,YAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAS,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;IAChJ,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE;CACtC,CAAA;AAEY,QAAA,sBAAsB,GAAkB;IACnD,IAAI,EAAE,gBAAgB;IACtB,IAAI,EAAE,gBAAgB;IACtB,IAAI,EAAE,qBAAqB;IAC3B,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,IAAA,qBAAa,EAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAS,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;IACnJ,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;CAC7F,CAAA;AAED,SAAgB,wBAAwB;IACtC,IAAA,oCAAqB,EAAC,0BAAkB,CAAC,CAAA;IACzC,IAAA,oCAAqB,EAAC,8BAAsB,CAAC,CAAA;AAC/C,CAAC","sourcesContent":["/**\n * The enrolment and the course version open on screen, named for the assistant each turn (operato-application\n * design/ai/screen-pattern.md §2-1, ADR-0194 decision 12). The course screen anchors its conversation to\n * `enrollment:<uuid>` - its learner's own, read by `Query.myEnrollment` - and the course editor to `course-version:<uuid>`,\n * read by `Query.courseVersion`; each is named only for someone that door lets through.\n */\nimport { registerRecordSubject, type RecordSubject } from '@things-factory/ai-assistant'\nimport { getRepository } from '@things-factory/shell'\n\nexport const ENROLLMENT_SUBJECT: RecordSubject = {\n axis: 'enrollment',\n noun: 'course enrolment',\n door: 'Query.myEnrollment',\n read: (rowId, domainId) => getRepository('Enrollment').findOne({ where: { id: rowId, domain: { id: domainId } } as any, relations: ['course'] }),\n nameOf: row => row.course?.name ?? ''\n}\n\nexport const COURSE_VERSION_SUBJECT: RecordSubject = {\n axis: 'course-version',\n noun: 'course version',\n door: 'Query.courseVersion',\n read: (rowId, domainId) => getRepository('CourseVersion').findOne({ where: { id: rowId, domain: { id: domainId } } as any, relations: ['course'] }),\n nameOf: row => (row.course?.name ? `${row.course.name} v${row.number} (${row.status})` : '')\n}\n\nexport function registerLearningSubjects(): void {\n registerRecordSubject(ENROLLMENT_SUBJECT)\n registerRecordSubject(COURSE_VERSION_SUBJECT)\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { RoleTask } from '@things-factory/auth-base';
2
+ export declare const ROLE_TASKS: RoleTask[];
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ /*
3
+ * The work this module names, for the seats applications build (ADR-0139 decision 11, ADR-0194 decision 11).
4
+ *
5
+ * `learning.taking` - one's own enrolments, progress, quiz attempts and certificates; every employee. A department head
6
+ * reads where the people of their departments stand through it too - status only, no score.
7
+ * `learning.managing` - writing courses, assigning them, the status of everyone and the completion register.
8
+ *
9
+ * Data only - `server/index.ts` registers it - so an application's tests read it without starting the framework.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ROLE_TASKS = void 0;
13
+ exports.ROLE_TASKS = [
14
+ { id: 'learning.taking', grants: [{ category: 'learning', axes: ['query', 'mutation'] }] },
15
+ { id: 'learning.managing', grants: [{ category: 'course', axes: ['query', 'mutation'] }] }
16
+ ];
17
+ //# sourceMappingURL=role-tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role-tasks.js","sourceRoot":"","sources":["../server/role-tasks.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAIU,QAAA,UAAU,GAAe;IACpC,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE;IAC1F,EAAE,EAAE,EAAE,mBAAmB,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE;CAC3F,CAAA","sourcesContent":["/*\n * The work this module names, for the seats applications build (ADR-0139 decision 11, ADR-0194 decision 11).\n *\n * `learning.taking` - one's own enrolments, progress, quiz attempts and certificates; every employee. A department head\n * reads where the people of their departments stand through it too - status only, no score.\n * `learning.managing` - writing courses, assigning them, the status of everyone and the completion register.\n *\n * Data only - `server/index.ts` registers it - so an application's tests read it without starting the framework.\n */\n\nimport type { RoleTask } from '@things-factory/auth-base'\n\nexport const ROLE_TASKS: RoleTask[] = [\n { id: 'learning.taking', grants: [{ category: 'learning', axes: ['query', 'mutation'] }] },\n { id: 'learning.managing', grants: [{ category: 'course', axes: ['query', 'mutation'] }] }\n]\n"]}
@@ -0,0 +1,19 @@
1
+ import type { FileUpload } from 'graphql-upload/GraphQLUpload.js';
2
+ import { Course } from './course';
3
+ import { CourseQuestion } from './course-question';
4
+ import { CourseUnit } from './course-unit';
5
+ import { CourseVersion } from './course-version';
6
+ import { CoursePatch, CourseQuestionInput, CourseUnitInput, CourseVersionPatch, NewCourse } from './course-type';
7
+ export declare class CourseMutation {
8
+ createCourse(course: NewCourse, context: ResolverContext): Promise<Course>;
9
+ updateCourse(id: string, patch: CoursePatch, context: ResolverContext): Promise<Course>;
10
+ createCourseVersion(courseId: string, fromId: string, context: ResolverContext): Promise<CourseVersion>;
11
+ updateCourseVersion(id: string, patch: CourseVersionPatch, context: ResolverContext): Promise<CourseVersion>;
12
+ saveCourseUnits(versionId: string, units: CourseUnitInput[], context: ResolverContext): Promise<CourseUnit[]>;
13
+ attachCourseUnitFile(unitId: string, file: FileUpload, durationSeconds: number, context: ResolverContext): Promise<CourseUnit>;
14
+ saveCourseQuestions(versionId: string, questions: CourseQuestionInput[], context: ResolverContext): Promise<CourseQuestion[]>;
15
+ addDraftedCourseQuestion(versionId: string, question: CourseQuestionInput, context: ResolverContext): Promise<CourseQuestion>;
16
+ publishCourseVersion(id: string, context: ResolverContext): Promise<CourseVersion>;
17
+ closeCourseVersion(id: string, context: ResolverContext): Promise<CourseVersion>;
18
+ deleteCourseVersion(id: string, context: ResolverContext): Promise<boolean>;
19
+ }
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CourseMutation = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const GraphQLUpload_js_1 = tslib_1.__importDefault(require("graphql-upload/GraphQLUpload.js"));
6
+ const type_graphql_1 = require("type-graphql");
7
+ const shell_1 = require("@things-factory/shell");
8
+ const course_1 = require("./course");
9
+ const course_question_1 = require("./course-question");
10
+ const course_unit_1 = require("./course-unit");
11
+ const course_version_1 = require("./course-version");
12
+ const course_type_1 = require("./course-type");
13
+ const course_service_1 = require("./course-service");
14
+ /* The managers' writes of courses (ADR-0194 decisions 2-4) - `course` mutation, the task `learning.managing`. */
15
+ let CourseMutation = class CourseMutation {
16
+ async createCourse(course, context) {
17
+ return await (0, course_service_1.createCourse)(course, context);
18
+ }
19
+ async updateCourse(id, patch, context) {
20
+ return await (0, course_service_1.updateCourse)(id, patch, context);
21
+ }
22
+ async createCourseVersion(courseId, fromId, context) {
23
+ return await (0, course_service_1.createCourseVersion)(courseId, fromId, context);
24
+ }
25
+ async updateCourseVersion(id, patch, context) {
26
+ return await (0, course_service_1.updateCourseVersion)(id, patch, context);
27
+ }
28
+ async saveCourseUnits(versionId, units, context) {
29
+ return await (0, course_service_1.saveCourseUnits)(versionId, units, context);
30
+ }
31
+ async attachCourseUnitFile(unitId, file, durationSeconds, context) {
32
+ return await (0, course_service_1.attachCourseUnitFile)(unitId, file, durationSeconds, context);
33
+ }
34
+ async saveCourseQuestions(versionId, questions, context) {
35
+ return await (0, course_service_1.saveCourseQuestions)(versionId, questions, context);
36
+ }
37
+ async addDraftedCourseQuestion(versionId, question, context) {
38
+ const [saved] = await (0, course_service_1.addDraftedQuestions)(versionId, [question], context);
39
+ if (!saved)
40
+ throw new shell_1.Refusal('learning-question-draft-invalid', {}, 'the drafted question is not complete - its text, two choices and the right ones');
41
+ return saved;
42
+ }
43
+ async publishCourseVersion(id, context) {
44
+ return await (0, course_service_1.publishCourseVersion)(id, context);
45
+ }
46
+ async closeCourseVersion(id, context) {
47
+ return await (0, course_service_1.closeCourseVersion)(id, context);
48
+ }
49
+ async deleteCourseVersion(id, context) {
50
+ return await (0, course_service_1.deleteCourseVersion)(id, context);
51
+ }
52
+ };
53
+ exports.CourseMutation = CourseMutation;
54
+ tslib_1.__decorate([
55
+ (0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
56
+ (0, type_graphql_1.Directive)('@transaction'),
57
+ (0, type_graphql_1.Mutation)(returns => course_1.Course, { description: 'To make a course.' }),
58
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('course', type => course_type_1.NewCourse)),
59
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
60
+ tslib_1.__metadata("design:type", Function),
61
+ tslib_1.__metadata("design:paramtypes", [course_type_1.NewCourse, Object]),
62
+ tslib_1.__metadata("design:returntype", Promise)
63
+ ], CourseMutation.prototype, "createCourse", null);
64
+ tslib_1.__decorate([
65
+ (0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
66
+ (0, type_graphql_1.Directive)('@transaction'),
67
+ (0, type_graphql_1.Mutation)(returns => course_1.Course, { description: "To change a course's name, description, category or manager." }),
68
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
69
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('patch', type => course_type_1.CoursePatch)),
70
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
71
+ tslib_1.__metadata("design:type", Function),
72
+ tslib_1.__metadata("design:paramtypes", [String, course_type_1.CoursePatch, Object]),
73
+ tslib_1.__metadata("design:returntype", Promise)
74
+ ], CourseMutation.prototype, "updateCourse", null);
75
+ tslib_1.__decorate([
76
+ (0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
77
+ (0, type_graphql_1.Directive)('@transaction'),
78
+ (0, type_graphql_1.Mutation)(returns => course_version_1.CourseVersion, { description: 'To make the next draft version of a course - a copy of `fromId`, or of the latest version.' }),
79
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('courseId')),
80
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('fromId', { nullable: true })),
81
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
82
+ tslib_1.__metadata("design:type", Function),
83
+ tslib_1.__metadata("design:paramtypes", [String, String, Object]),
84
+ tslib_1.__metadata("design:returntype", Promise)
85
+ ], CourseMutation.prototype, "createCourseVersion", null);
86
+ tslib_1.__decorate([
87
+ (0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
88
+ (0, type_graphql_1.Directive)('@transaction'),
89
+ (0, type_graphql_1.Mutation)(returns => course_version_1.CourseVersion, { description: 'To change what a draft version says - a published one never changes.' }),
90
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
91
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('patch', type => course_type_1.CourseVersionPatch)),
92
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
93
+ tslib_1.__metadata("design:type", Function),
94
+ tslib_1.__metadata("design:paramtypes", [String, course_type_1.CourseVersionPatch, Object]),
95
+ tslib_1.__metadata("design:returntype", Promise)
96
+ ], CourseMutation.prototype, "updateCourseVersion", null);
97
+ tslib_1.__decorate([
98
+ (0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
99
+ (0, type_graphql_1.Directive)('@transaction'),
100
+ (0, type_graphql_1.Mutation)(returns => [course_unit_1.CourseUnit], { description: 'To save the units of a draft version, in order - the ones left out are deleted.' }),
101
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('versionId')),
102
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('units', type => [course_type_1.CourseUnitInput])),
103
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
104
+ tslib_1.__metadata("design:type", Function),
105
+ tslib_1.__metadata("design:paramtypes", [String, Array, Object]),
106
+ tslib_1.__metadata("design:returntype", Promise)
107
+ ], CourseMutation.prototype, "saveCourseUnits", null);
108
+ tslib_1.__decorate([
109
+ (0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
110
+ (0, type_graphql_1.Directive)('@transaction'),
111
+ (0, type_graphql_1.Mutation)(returns => course_unit_1.CourseUnit, { description: "To attach a video's or a PDF's file to a unit of a draft version - a video with its length." }),
112
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('unitId')),
113
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('file', type => GraphQLUpload_js_1.default)),
114
+ tslib_1.__param(2, (0, type_graphql_1.Arg)('durationSeconds', type => type_graphql_1.Int, { nullable: true })),
115
+ tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
116
+ tslib_1.__metadata("design:type", Function),
117
+ tslib_1.__metadata("design:paramtypes", [String, Object, Number, Object]),
118
+ tslib_1.__metadata("design:returntype", Promise)
119
+ ], CourseMutation.prototype, "attachCourseUnitFile", null);
120
+ tslib_1.__decorate([
121
+ (0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
122
+ (0, type_graphql_1.Directive)('@transaction'),
123
+ (0, type_graphql_1.Mutation)(returns => [course_question_1.CourseQuestion], { description: 'To save the questions of a draft version, in order - the ones left out are deleted.' }),
124
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('versionId')),
125
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('questions', type => [course_type_1.CourseQuestionInput])),
126
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
127
+ tslib_1.__metadata("design:type", Function),
128
+ tslib_1.__metadata("design:paramtypes", [String, Array, Object]),
129
+ tslib_1.__metadata("design:returntype", Promise)
130
+ ], CourseMutation.prototype, "saveCourseQuestions", null);
131
+ tslib_1.__decorate([
132
+ (0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
133
+ (0, type_graphql_1.Directive)('@transaction'),
134
+ (0, type_graphql_1.Mutation)(returns => course_question_1.CourseQuestion, { description: 'To add a question drafted by the assistant to a draft version - marked drafted until a manager saves it (ADR-0194 decision 12).' }),
135
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('versionId')),
136
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('question', type => course_type_1.CourseQuestionInput)),
137
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
138
+ tslib_1.__metadata("design:type", Function),
139
+ tslib_1.__metadata("design:paramtypes", [String, course_type_1.CourseQuestionInput, Object]),
140
+ tslib_1.__metadata("design:returntype", Promise)
141
+ ], CourseMutation.prototype, "addDraftedCourseQuestion", null);
142
+ tslib_1.__decorate([
143
+ (0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
144
+ (0, type_graphql_1.Directive)('@transaction'),
145
+ (0, type_graphql_1.Mutation)(returns => course_version_1.CourseVersion, { description: 'To publish a draft version - the version published before is closed.' }),
146
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
147
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
148
+ tslib_1.__metadata("design:type", Function),
149
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
150
+ tslib_1.__metadata("design:returntype", Promise)
151
+ ], CourseMutation.prototype, "publishCourseVersion", null);
152
+ tslib_1.__decorate([
153
+ (0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
154
+ (0, type_graphql_1.Directive)('@transaction'),
155
+ (0, type_graphql_1.Mutation)(returns => course_version_1.CourseVersion, { description: 'To close the published version - nobody starts it any more.' }),
156
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
157
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
158
+ tslib_1.__metadata("design:type", Function),
159
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
160
+ tslib_1.__metadata("design:returntype", Promise)
161
+ ], CourseMutation.prototype, "closeCourseVersion", null);
162
+ tslib_1.__decorate([
163
+ (0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
164
+ (0, type_graphql_1.Directive)('@transaction'),
165
+ (0, type_graphql_1.Mutation)(returns => Boolean, { description: 'To delete a draft version.' }),
166
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
167
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
168
+ tslib_1.__metadata("design:type", Function),
169
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
170
+ tslib_1.__metadata("design:returntype", Promise)
171
+ ], CourseMutation.prototype, "deleteCourseVersion", null);
172
+ exports.CourseMutation = CourseMutation = tslib_1.__decorate([
173
+ (0, type_graphql_1.Resolver)(course_1.Course),
174
+ (0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals)
175
+ ], CourseMutation);
176
+ //# sourceMappingURL=course-mutation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"course-mutation.js","sourceRoot":"","sources":["../../../server/service/course/course-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport GraphQLUpload from 'graphql-upload/GraphQLUpload.js'\nimport { Arg, Ctx, Directive, Int, Mutation, Resolver, UseMiddleware } from 'type-graphql'\n\nimport { Refusal, SpeakRefusals } from '@things-factory/shell'\n\nimport { Course } from './course'\nimport { CourseQuestion } from './course-question'\nimport { CourseUnit } from './course-unit'\nimport { CourseVersion } from './course-version'\nimport { CoursePatch, CourseQuestionInput, CourseUnitInput, CourseVersionPatch, NewCourse } from './course-type'\nimport {\n addDraftedQuestions,\n attachCourseUnitFile,\n closeCourseVersion,\n createCourse,\n createCourseVersion,\n deleteCourseVersion,\n publishCourseVersion,\n saveCourseQuestions,\n saveCourseUnits,\n updateCourse,\n updateCourseVersion\n} from './course-service'\n\n\n/* The managers' writes of courses (ADR-0194 decisions 2-4) - `course` mutation, the task `learning.managing`. */\n@Resolver(Course)\n@UseMiddleware(SpeakRefusals)\nexport class CourseMutation {\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Course, { description: 'To make a course.' })\n async createCourse(@Arg('course', type => NewCourse) course: NewCourse, @Ctx() context: ResolverContext): Promise<Course> {\n return await createCourse(course, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Course, { description: \"To change a course's name, description, category or manager.\" })\n async updateCourse(@Arg('id') id: string, @Arg('patch', type => CoursePatch) patch: CoursePatch, @Ctx() context: ResolverContext): Promise<Course> {\n return await updateCourse(id, patch, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseVersion, { description: 'To make the next draft version of a course - a copy of `fromId`, or of the latest version.' })\n async createCourseVersion(@Arg('courseId') courseId: string, @Arg('fromId', { nullable: true }) fromId: string, @Ctx() context: ResolverContext): Promise<CourseVersion> {\n return await createCourseVersion(courseId, fromId, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseVersion, { description: 'To change what a draft version says - a published one never changes.' })\n async updateCourseVersion(@Arg('id') id: string, @Arg('patch', type => CourseVersionPatch) patch: CourseVersionPatch, @Ctx() context: ResolverContext): Promise<CourseVersion> {\n return await updateCourseVersion(id, patch, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [CourseUnit], { description: 'To save the units of a draft version, in order - the ones left out are deleted.' })\n async saveCourseUnits(@Arg('versionId') versionId: string, @Arg('units', type => [CourseUnitInput]) units: CourseUnitInput[], @Ctx() context: ResolverContext): Promise<CourseUnit[]> {\n return await saveCourseUnits(versionId, units, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseUnit, { description: \"To attach a video's or a PDF's file to a unit of a draft version - a video with its length.\" })\n async attachCourseUnitFile(\n @Arg('unitId') unitId: string,\n @Arg('file', type => GraphQLUpload) file: FileUpload,\n @Arg('durationSeconds', type => Int, { nullable: true }) durationSeconds: number,\n @Ctx() context: ResolverContext\n ): Promise<CourseUnit> {\n return await attachCourseUnitFile(unitId, file, durationSeconds, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [CourseQuestion], { description: 'To save the questions of a draft version, in order - the ones left out are deleted.' })\n async saveCourseQuestions(@Arg('versionId') versionId: string, @Arg('questions', type => [CourseQuestionInput]) questions: CourseQuestionInput[], @Ctx() context: ResolverContext): Promise<CourseQuestion[]> {\n return await saveCourseQuestions(versionId, questions, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseQuestion, { description: 'To add a question drafted by the assistant to a draft version - marked drafted until a manager saves it (ADR-0194 decision 12).' })\n async addDraftedCourseQuestion(@Arg('versionId') versionId: string, @Arg('question', type => CourseQuestionInput) question: CourseQuestionInput, @Ctx() context: ResolverContext): Promise<CourseQuestion> {\n const [saved] = await addDraftedQuestions(versionId, [question], context)\n if (!saved) throw new Refusal('learning-question-draft-invalid', {}, 'the drafted question is not complete - its text, two choices and the right ones')\n return saved\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseVersion, { description: 'To publish a draft version - the version published before is closed.' })\n async publishCourseVersion(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<CourseVersion> {\n return await publishCourseVersion(id, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseVersion, { description: 'To close the published version - nobody starts it any more.' })\n async closeCourseVersion(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<CourseVersion> {\n return await closeCourseVersion(id, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, { description: 'To delete a draft version.' })\n async deleteCourseVersion(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {\n return await deleteCourseVersion(id, context)\n }\n}\n"]}