@openedx/frontend-app-instructor-dashboard 1.0.0-alpha.4 → 1.0.0-alpha.40

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 (301) hide show
  1. package/dist/Main.d.ts +1 -1
  2. package/dist/Main.js +11 -18
  3. package/dist/Main.js.map +1 -1
  4. package/dist/app.js +0 -6
  5. package/dist/app.js.map +1 -1
  6. package/dist/certificates/CertificatesPage.d.ts +1 -0
  7. package/dist/certificates/CertificatesPage.js +312 -2
  8. package/dist/certificates/CertificatesPage.js.map +1 -1
  9. package/dist/certificates/CertificatesPage.scss +90 -0
  10. package/dist/certificates/components/CertificateTable.d.ts +14 -0
  11. package/dist/certificates/components/CertificateTable.js +88 -0
  12. package/dist/certificates/components/CertificateTable.js.map +1 -0
  13. package/dist/certificates/components/CertificatesPageHeader.d.ts +7 -0
  14. package/dist/certificates/components/CertificatesPageHeader.js +11 -0
  15. package/dist/certificates/components/CertificatesPageHeader.js.map +1 -0
  16. package/dist/certificates/components/CertificatesToolbar.d.ts +11 -0
  17. package/dist/certificates/components/CertificatesToolbar.js +33 -0
  18. package/dist/certificates/components/CertificatesToolbar.js.map +1 -0
  19. package/dist/certificates/components/DisableCertificatesModal.d.ts +9 -0
  20. package/dist/certificates/components/DisableCertificatesModal.js +24 -0
  21. package/dist/certificates/components/DisableCertificatesModal.js.map +1 -0
  22. package/dist/certificates/components/FilterDropdown.d.ts +8 -0
  23. package/dist/certificates/components/FilterDropdown.js +50 -0
  24. package/dist/certificates/components/FilterDropdown.js.map +1 -0
  25. package/dist/certificates/components/GenerateCertificatesModal.d.ts +9 -0
  26. package/dist/certificates/components/GenerateCertificatesModal.js +19 -0
  27. package/dist/certificates/components/GenerateCertificatesModal.js.map +1 -0
  28. package/dist/certificates/components/GenerationHistoryTable.d.ts +11 -0
  29. package/dist/certificates/components/GenerationHistoryTable.js +25 -0
  30. package/dist/certificates/components/GenerationHistoryTable.js.map +1 -0
  31. package/dist/certificates/components/GrantExceptionsModal.d.ts +9 -0
  32. package/dist/certificates/components/GrantExceptionsModal.js +55 -0
  33. package/dist/certificates/components/GrantExceptionsModal.js.map +1 -0
  34. package/dist/certificates/components/InvalidateCertificateModal.d.ts +8 -0
  35. package/dist/certificates/components/InvalidateCertificateModal.js +26 -0
  36. package/dist/certificates/components/InvalidateCertificateModal.js.map +1 -0
  37. package/dist/certificates/components/IssuedCertificatesTab.d.ts +18 -0
  38. package/dist/certificates/components/IssuedCertificatesTab.js +6 -0
  39. package/dist/certificates/components/IssuedCertificatesTab.js.map +1 -0
  40. package/dist/certificates/components/LearnerActionModal.d.ts +16 -0
  41. package/dist/certificates/components/LearnerActionModal.js +27 -0
  42. package/dist/certificates/components/LearnerActionModal.js.map +1 -0
  43. package/dist/certificates/components/RegenerateCertificatesModal.d.ts +11 -0
  44. package/dist/certificates/components/RegenerateCertificatesModal.js +46 -0
  45. package/dist/certificates/components/RegenerateCertificatesModal.js.map +1 -0
  46. package/dist/certificates/components/RemoveExceptionModal.d.ts +9 -0
  47. package/dist/certificates/components/RemoveExceptionModal.js +10 -0
  48. package/dist/certificates/components/RemoveExceptionModal.js.map +1 -0
  49. package/dist/certificates/components/RemoveInvalidationModal.d.ts +9 -0
  50. package/dist/certificates/components/RemoveInvalidationModal.js +10 -0
  51. package/dist/certificates/components/RemoveInvalidationModal.js.map +1 -0
  52. package/dist/certificates/constants.d.ts +15 -0
  53. package/dist/certificates/constants.js +16 -0
  54. package/dist/certificates/constants.js.map +1 -0
  55. package/dist/certificates/data/api.d.ts +30 -0
  56. package/dist/certificates/data/api.js +126 -0
  57. package/dist/certificates/data/api.js.map +1 -0
  58. package/dist/certificates/data/apiHook.d.ts +63 -0
  59. package/dist/certificates/data/apiHook.js +133 -0
  60. package/dist/certificates/data/apiHook.js.map +1 -0
  61. package/dist/certificates/data/queryKeys.d.ts +9 -0
  62. package/dist/certificates/data/queryKeys.js +9 -0
  63. package/dist/certificates/data/queryKeys.js.map +1 -0
  64. package/dist/certificates/messages.d.ts +548 -0
  65. package/dist/certificates/messages.js +550 -0
  66. package/dist/certificates/messages.js.map +1 -0
  67. package/dist/certificates/types.d.ts +66 -0
  68. package/dist/certificates/types.js +26 -0
  69. package/dist/certificates/types.js.map +1 -0
  70. package/dist/certificates/utils/errorHandling.d.ts +12 -0
  71. package/dist/certificates/utils/errorHandling.js +24 -0
  72. package/dist/certificates/utils/errorHandling.js.map +1 -0
  73. package/dist/certificates/utils/filterUtils.d.ts +4 -0
  74. package/dist/certificates/utils/filterUtils.js +31 -0
  75. package/dist/certificates/utils/filterUtils.js.map +1 -0
  76. package/dist/certificates/utils/index.d.ts +2 -0
  77. package/dist/certificates/utils/index.js +2 -0
  78. package/dist/certificates/utils/index.js.map +1 -0
  79. package/dist/components/ActionCard.d.ts +2 -2
  80. package/dist/components/ActionCard.js +1 -1
  81. package/dist/components/ActionCard.js.map +1 -1
  82. package/dist/components/CodeEditor.d.ts +5 -0
  83. package/dist/components/CodeEditor.js +34 -0
  84. package/dist/components/CodeEditor.js.map +1 -0
  85. package/dist/components/PendingTasks.d.ts +3 -1
  86. package/dist/components/PendingTasks.js +3 -2
  87. package/dist/components/PendingTasks.js.map +1 -1
  88. package/dist/components/SpecifyLearnerField.d.ts +4 -1
  89. package/dist/components/SpecifyLearnerField.js +55 -15
  90. package/dist/components/SpecifyLearnerField.js.map +1 -1
  91. package/dist/components/SpecifyProblemField.d.ts +13 -0
  92. package/dist/components/SpecifyProblemField.js +52 -0
  93. package/dist/components/SpecifyProblemField.js.map +1 -0
  94. package/dist/components/UsernameFilter.d.ts +7 -0
  95. package/dist/components/UsernameFilter.js +19 -0
  96. package/dist/components/UsernameFilter.js.map +1 -0
  97. package/dist/components/messages.d.ts +45 -0
  98. package/dist/components/messages.js +45 -0
  99. package/dist/components/messages.js.map +1 -1
  100. package/dist/courseInfo/types.d.ts +5 -0
  101. package/dist/courseInfo/types.js.map +1 -1
  102. package/dist/courseTeam/CourseTeamPage.js +25 -2
  103. package/dist/courseTeam/CourseTeamPage.js.map +1 -1
  104. package/dist/courseTeam/components/AddTeamMemberModal.d.ts +6 -0
  105. package/dist/courseTeam/components/AddTeamMemberModal.js +61 -0
  106. package/dist/courseTeam/components/AddTeamMemberModal.js.map +1 -0
  107. package/dist/courseTeam/components/EditTeamMemberModal.d.ts +8 -0
  108. package/dist/courseTeam/components/EditTeamMemberModal.js +102 -0
  109. package/dist/courseTeam/components/EditTeamMemberModal.js.map +1 -0
  110. package/dist/courseTeam/components/MembersContent.d.ts +6 -0
  111. package/dist/courseTeam/components/MembersContent.js +48 -0
  112. package/dist/courseTeam/components/MembersContent.js.map +1 -0
  113. package/dist/courseTeam/components/RoleFilter.d.ts +7 -0
  114. package/dist/courseTeam/components/RoleFilter.js +22 -0
  115. package/dist/courseTeam/components/RoleFilter.js.map +1 -0
  116. package/dist/courseTeam/components/RolesContent.d.ts +3 -0
  117. package/dist/courseTeam/components/RolesContent.js +25 -0
  118. package/dist/courseTeam/components/RolesContent.js.map +1 -0
  119. package/dist/courseTeam/constants.d.ts +3 -0
  120. package/dist/courseTeam/constants.js +4 -0
  121. package/dist/courseTeam/constants.js.map +1 -0
  122. package/dist/courseTeam/data/api.d.ts +6 -0
  123. package/dist/courseTeam/data/api.js +38 -0
  124. package/dist/courseTeam/data/api.js.map +1 -0
  125. package/dist/courseTeam/data/apiHook.d.ts +8 -0
  126. package/dist/courseTeam/data/apiHook.js +32 -0
  127. package/dist/courseTeam/data/apiHook.js.map +1 -0
  128. package/dist/courseTeam/data/queryKeys.d.ts +7 -0
  129. package/dist/courseTeam/data/queryKeys.js +14 -0
  130. package/dist/courseTeam/data/queryKeys.js.map +1 -0
  131. package/dist/courseTeam/messages.d.ts +258 -0
  132. package/dist/courseTeam/messages.js +260 -0
  133. package/dist/courseTeam/messages.js.map +1 -0
  134. package/dist/courseTeam/types.d.ts +29 -0
  135. package/dist/courseTeam/types.js +3 -0
  136. package/dist/courseTeam/types.js.map +1 -0
  137. package/dist/data/api.d.ts +2 -1
  138. package/dist/data/api.js +9 -3
  139. package/dist/data/api.js.map +1 -1
  140. package/dist/data/apiHook.d.ts +1 -0
  141. package/dist/data/apiHook.js +11 -2
  142. package/dist/data/apiHook.js.map +1 -1
  143. package/dist/data/queryKeys.d.ts +4 -0
  144. package/dist/data/queryKeys.js +4 -0
  145. package/dist/data/queryKeys.js.map +1 -1
  146. package/dist/data/utils.d.ts +2 -0
  147. package/dist/data/utils.js +9 -0
  148. package/dist/data/utils.js.map +1 -0
  149. package/dist/dateExtensions/components/AddExtensionModal.d.ts +1 -1
  150. package/dist/dateExtensions/components/AddExtensionModal.js +6 -7
  151. package/dist/dateExtensions/components/AddExtensionModal.js.map +1 -1
  152. package/dist/dateExtensions/components/DateExtensionsList.js +3 -14
  153. package/dist/dateExtensions/components/DateExtensionsList.js.map +1 -1
  154. package/dist/dateExtensions/data/apiHook.d.ts +2 -2
  155. package/dist/dateExtensions/data/apiHook.js +4 -4
  156. package/dist/dateExtensions/data/apiHook.js.map +1 -1
  157. package/dist/dateExtensions/messages.d.ts +0 -5
  158. package/dist/dateExtensions/messages.js +1 -6
  159. package/dist/dateExtensions/messages.js.map +1 -1
  160. package/dist/enrollments/EnrollmentsPage.js +34 -7
  161. package/dist/enrollments/EnrollmentsPage.js.map +1 -1
  162. package/dist/enrollments/components/AddBetaTestersModal.d.ts +6 -0
  163. package/dist/enrollments/components/AddBetaTestersModal.js +69 -0
  164. package/dist/enrollments/components/AddBetaTestersModal.js.map +1 -0
  165. package/dist/enrollments/components/EnrollLearnersModal.d.ts +6 -0
  166. package/dist/enrollments/components/EnrollLearnersModal.js +53 -0
  167. package/dist/enrollments/components/EnrollLearnersModal.js.map +1 -0
  168. package/dist/enrollments/components/EnrollmentStatusModal.js +3 -3
  169. package/dist/enrollments/components/EnrollmentStatusModal.js.map +1 -1
  170. package/dist/enrollments/components/EnrollmentsList.d.ts +3 -2
  171. package/dist/enrollments/components/EnrollmentsList.js +13 -14
  172. package/dist/enrollments/components/EnrollmentsList.js.map +1 -1
  173. package/dist/enrollments/components/UnenrollModal.d.ts +1 -1
  174. package/dist/enrollments/components/UnenrollModal.js +29 -3
  175. package/dist/enrollments/components/UnenrollModal.js.map +1 -1
  176. package/dist/enrollments/components/UpdateBetaTesterModal.d.ts +8 -0
  177. package/dist/enrollments/components/UpdateBetaTesterModal.js +72 -0
  178. package/dist/enrollments/components/UpdateBetaTesterModal.js.map +1 -0
  179. package/dist/enrollments/data/api.d.ts +3 -1
  180. package/dist/enrollments/data/api.js +11 -1
  181. package/dist/enrollments/data/api.js.map +1 -1
  182. package/dist/enrollments/data/apiHook.d.ts +5 -3
  183. package/dist/enrollments/data/apiHook.js +21 -3
  184. package/dist/enrollments/data/apiHook.js.map +1 -1
  185. package/dist/enrollments/data/queryKeys.d.ts +1 -1
  186. package/dist/enrollments/data/queryKeys.js.map +1 -1
  187. package/dist/enrollments/messages.d.ts +131 -1
  188. package/dist/enrollments/messages.js +136 -6
  189. package/dist/enrollments/messages.js.map +1 -1
  190. package/dist/enrollments/types.d.ts +25 -0
  191. package/dist/enrollments/types.js.map +1 -1
  192. package/dist/grading/GradingPage.js +15 -2
  193. package/dist/grading/GradingPage.js.map +1 -1
  194. package/dist/grading/components/GradingActionRow.d.ts +2 -0
  195. package/dist/grading/components/GradingActionRow.js +20 -0
  196. package/dist/grading/components/GradingActionRow.js.map +1 -0
  197. package/dist/grading/components/GradingConfigurationModal.d.ts +6 -0
  198. package/dist/grading/components/GradingConfigurationModal.js +15 -0
  199. package/dist/grading/components/GradingConfigurationModal.js.map +1 -0
  200. package/dist/grading/components/GradingLearnerContent.d.ts +7 -0
  201. package/dist/grading/components/GradingLearnerContent.js +199 -0
  202. package/dist/grading/components/GradingLearnerContent.js.map +1 -0
  203. package/dist/grading/data/api.d.ts +6 -0
  204. package/dist/grading/data/api.js +59 -0
  205. package/dist/grading/data/api.js.map +1 -0
  206. package/dist/grading/data/apiHook.d.ts +6 -0
  207. package/dist/grading/data/apiHook.js +29 -0
  208. package/dist/grading/data/apiHook.js.map +1 -0
  209. package/dist/grading/data/queryKeys.d.ts +9 -0
  210. package/dist/grading/data/queryKeys.js +8 -0
  211. package/dist/grading/data/queryKeys.js.map +1 -0
  212. package/dist/grading/messages.d.ts +248 -0
  213. package/dist/grading/messages.js +250 -0
  214. package/dist/grading/messages.js.map +1 -0
  215. package/dist/grading/types.d.ts +11 -0
  216. package/dist/grading/types.js +2 -0
  217. package/dist/grading/types.js.map +1 -0
  218. package/dist/hooks/useDebouncedFilter.d.ts +1 -0
  219. package/dist/hooks/useDebouncedFilter.js +5 -0
  220. package/dist/hooks/useDebouncedFilter.js.map +1 -1
  221. package/dist/instructorNav/InstructorNav.js +16 -4
  222. package/dist/instructorNav/InstructorNav.js.map +1 -1
  223. package/dist/messages.d.ts +8 -0
  224. package/dist/messages.js +10 -0
  225. package/dist/messages.js.map +1 -0
  226. package/dist/pageWrapper/PageWrapper.js +3 -1
  227. package/dist/pageWrapper/PageWrapper.js.map +1 -1
  228. package/dist/providers/AccessErrorObserver.d.ts +9 -0
  229. package/dist/providers/AccessErrorObserver.js +35 -0
  230. package/dist/providers/AccessErrorObserver.js.map +1 -0
  231. package/dist/providers/AccessErrorProvider.d.ts +19 -0
  232. package/dist/providers/AccessErrorProvider.js +51 -0
  233. package/dist/providers/AccessErrorProvider.js.map +1 -0
  234. package/dist/providers/messages.d.ts +33 -0
  235. package/dist/providers/messages.js +35 -0
  236. package/dist/providers/messages.js.map +1 -0
  237. package/dist/provides.d.ts +2 -1
  238. package/dist/provides.js +3 -2
  239. package/dist/provides.js.map +1 -1
  240. package/dist/routes.d.ts +1 -1
  241. package/dist/routes.js +2 -2
  242. package/dist/routes.js.map +1 -1
  243. package/dist/slots/CourseInfoSlot/CourseInfoSlot.d.ts +2 -0
  244. package/dist/slots/CourseInfoSlot/CourseInfoSlot.js +14 -0
  245. package/dist/slots/CourseInfoSlot/CourseInfoSlot.js.map +1 -0
  246. package/dist/slots.js +13 -1
  247. package/dist/slots.js.map +1 -1
  248. package/dist/specialExams/SpecialExamsPage.js +14 -2
  249. package/dist/specialExams/SpecialExamsPage.js.map +1 -1
  250. package/dist/specialExams/components/AddAllowanceModal.d.ts +6 -0
  251. package/dist/specialExams/components/AddAllowanceModal.js +84 -0
  252. package/dist/specialExams/components/AddAllowanceModal.js.map +1 -0
  253. package/dist/specialExams/components/Allowances.d.ts +2 -0
  254. package/dist/specialExams/components/Allowances.js +89 -0
  255. package/dist/specialExams/components/Allowances.js.map +1 -0
  256. package/dist/specialExams/components/AllowancesList.d.ts +8 -0
  257. package/dist/specialExams/components/AllowancesList.js +63 -0
  258. package/dist/specialExams/components/AllowancesList.js.map +1 -0
  259. package/dist/specialExams/components/AttemptsList.d.ts +3 -0
  260. package/dist/specialExams/components/AttemptsList.js +50 -0
  261. package/dist/specialExams/components/AttemptsList.js.map +1 -0
  262. package/dist/specialExams/components/DeleteAllowanceModal.d.ts +8 -0
  263. package/dist/specialExams/components/DeleteAllowanceModal.js +29 -0
  264. package/dist/specialExams/components/DeleteAllowanceModal.js.map +1 -0
  265. package/dist/specialExams/components/EditAllowanceModal.d.ts +8 -0
  266. package/dist/specialExams/components/EditAllowanceModal.js +62 -0
  267. package/dist/specialExams/components/EditAllowanceModal.js.map +1 -0
  268. package/dist/specialExams/constants.d.ts +43 -0
  269. package/dist/specialExams/constants.js +19 -0
  270. package/dist/specialExams/constants.js.map +1 -0
  271. package/dist/specialExams/data/api.d.ts +7 -0
  272. package/dist/specialExams/data/api.js +55 -0
  273. package/dist/specialExams/data/api.js.map +1 -0
  274. package/dist/specialExams/data/apiHook.d.ts +6 -0
  275. package/dist/specialExams/data/apiHook.js +37 -0
  276. package/dist/specialExams/data/apiHook.js.map +1 -0
  277. package/dist/specialExams/data/queryKeys.d.ts +8 -0
  278. package/dist/specialExams/data/queryKeys.js +9 -0
  279. package/dist/specialExams/data/queryKeys.js.map +1 -0
  280. package/dist/specialExams/messages.d.ts +228 -0
  281. package/dist/specialExams/messages.js +230 -0
  282. package/dist/specialExams/messages.js.map +1 -0
  283. package/dist/specialExams/types.d.ts +65 -0
  284. package/dist/specialExams/types.js +2 -0
  285. package/dist/specialExams/types.js.map +1 -0
  286. package/dist/style.scss +16 -0
  287. package/dist/testUtils.js +2 -2
  288. package/dist/testUtils.js.map +1 -1
  289. package/dist/types/index.d.ts +15 -0
  290. package/dist/types/index.js.map +1 -1
  291. package/dist/utils/formatters.d.ts +5 -0
  292. package/dist/utils/formatters.js +10 -0
  293. package/dist/utils/formatters.js.map +1 -1
  294. package/package.json +6 -6
  295. package/dist/app.scss +0 -10
  296. package/dist/providers/QueryProvider.d.ts +0 -6
  297. package/dist/providers/QueryProvider.js +0 -16
  298. package/dist/providers/QueryProvider.js.map +0 -1
  299. package/dist/providers.d.ts +0 -3
  300. package/dist/providers.js +0 -8
  301. package/dist/providers.js.map +0 -1
@@ -0,0 +1,66 @@
1
+ import type { PaginationParams } from '../types';
2
+ export declare enum CertificateFilter {
3
+ ALL_LEARNERS = "all",
4
+ RECEIVED = "received",
5
+ NOT_RECEIVED = "not_received",
6
+ AUDIT_PASSING = "audit_passing",
7
+ AUDIT_NOT_PASSING = "audit_not_passing",
8
+ ERROR_STATE = "error",
9
+ GRANTED_EXCEPTIONS = "granted_exceptions",
10
+ INVALIDATED = "invalidated"
11
+ }
12
+ export declare enum CertificateStatus {
13
+ RECEIVED = "downloadable",
14
+ NOT_RECEIVED = "notpassing",
15
+ AUDIT_PASSING = "audit_passing",
16
+ AUDIT_NOT_PASSING = "audit_notpassing",
17
+ ERROR_STATE = "error"
18
+ }
19
+ export declare enum SpecialCase {
20
+ NONE = "",
21
+ INVALIDATION = "invalidated",
22
+ EXCEPTION = "exception"
23
+ }
24
+ export interface CertificateData {
25
+ username: string;
26
+ email: string;
27
+ enrollmentTrack: string;
28
+ certificateStatus: CertificateStatus;
29
+ specialCase: SpecialCase;
30
+ exceptionGranted?: string;
31
+ exceptionNotes?: string;
32
+ invalidatedBy?: string;
33
+ invalidationDate?: string;
34
+ invalidationNote?: string;
35
+ }
36
+ export interface InstructorTask {
37
+ taskId: string;
38
+ taskName: string;
39
+ taskState: string;
40
+ taskOutput?: string;
41
+ created: string;
42
+ updated: string;
43
+ }
44
+ export interface CertificateGenerationHistory {
45
+ taskName: string;
46
+ date: string;
47
+ details: string;
48
+ }
49
+ export interface CertificateQueryParams extends PaginationParams {
50
+ filter: CertificateFilter;
51
+ search: string;
52
+ }
53
+ export interface GrantExceptionRequest {
54
+ learners: string[];
55
+ notes?: string;
56
+ }
57
+ export interface InvalidateCertificateRequest {
58
+ learners: string[];
59
+ notes?: string;
60
+ }
61
+ export interface RemoveExceptionRequest {
62
+ username: string;
63
+ }
64
+ export interface RemoveInvalidationRequest {
65
+ username: string;
66
+ }
@@ -0,0 +1,26 @@
1
+ export var CertificateFilter;
2
+ (function (CertificateFilter) {
3
+ CertificateFilter["ALL_LEARNERS"] = "all";
4
+ CertificateFilter["RECEIVED"] = "received";
5
+ CertificateFilter["NOT_RECEIVED"] = "not_received";
6
+ CertificateFilter["AUDIT_PASSING"] = "audit_passing";
7
+ CertificateFilter["AUDIT_NOT_PASSING"] = "audit_not_passing";
8
+ CertificateFilter["ERROR_STATE"] = "error";
9
+ CertificateFilter["GRANTED_EXCEPTIONS"] = "granted_exceptions";
10
+ CertificateFilter["INVALIDATED"] = "invalidated";
11
+ })(CertificateFilter || (CertificateFilter = {}));
12
+ export var CertificateStatus;
13
+ (function (CertificateStatus) {
14
+ CertificateStatus["RECEIVED"] = "downloadable";
15
+ CertificateStatus["NOT_RECEIVED"] = "notpassing";
16
+ CertificateStatus["AUDIT_PASSING"] = "audit_passing";
17
+ CertificateStatus["AUDIT_NOT_PASSING"] = "audit_notpassing";
18
+ CertificateStatus["ERROR_STATE"] = "error";
19
+ })(CertificateStatus || (CertificateStatus = {}));
20
+ export var SpecialCase;
21
+ (function (SpecialCase) {
22
+ SpecialCase["NONE"] = "";
23
+ SpecialCase["INVALIDATION"] = "invalidated";
24
+ SpecialCase["EXCEPTION"] = "exception";
25
+ })(SpecialCase || (SpecialCase = {}));
26
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/certificates/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAN,IAAY,iBASX;AATD,WAAY,iBAAiB;IAC3B,yCAAoB,CAAA;IACpB,0CAAqB,CAAA;IACrB,kDAA6B,CAAA;IAC7B,oDAA+B,CAAA;IAC/B,4DAAuC,CAAA;IACvC,0CAAqB,CAAA;IACrB,8DAAyC,CAAA;IACzC,gDAA2B,CAAA;AAC7B,CAAC,EATW,iBAAiB,KAAjB,iBAAiB,QAS5B;AAED,MAAM,CAAN,IAAY,iBAMX;AAND,WAAY,iBAAiB;IAC3B,8CAAyB,CAAA;IACzB,gDAA2B,CAAA;IAC3B,oDAA+B,CAAA;IAC/B,2DAAsC,CAAA;IACtC,0CAAqB,CAAA;AACvB,CAAC,EANW,iBAAiB,KAAjB,iBAAiB,QAM5B;AAED,MAAM,CAAN,IAAY,WAIX;AAJD,WAAY,WAAW;IACrB,wBAAS,CAAA;IACT,2CAA4B,CAAA;IAC5B,sCAAuB,CAAA;AACzB,CAAC,EAJW,WAAW,KAAX,WAAW,QAItB","sourcesContent":["import type { PaginationParams } from '@src/types';\n\nexport enum CertificateFilter {\n ALL_LEARNERS = 'all',\n RECEIVED = 'received',\n NOT_RECEIVED = 'not_received',\n AUDIT_PASSING = 'audit_passing',\n AUDIT_NOT_PASSING = 'audit_not_passing',\n ERROR_STATE = 'error',\n GRANTED_EXCEPTIONS = 'granted_exceptions',\n INVALIDATED = 'invalidated',\n}\n\nexport enum CertificateStatus {\n RECEIVED = 'downloadable',\n NOT_RECEIVED = 'notpassing',\n AUDIT_PASSING = 'audit_passing',\n AUDIT_NOT_PASSING = 'audit_notpassing',\n ERROR_STATE = 'error',\n}\n\nexport enum SpecialCase {\n NONE = '',\n INVALIDATION = 'invalidated',\n EXCEPTION = 'exception',\n}\n\nexport interface CertificateData {\n username: string,\n email: string,\n enrollmentTrack: string,\n certificateStatus: CertificateStatus,\n specialCase: SpecialCase,\n exceptionGranted?: string,\n exceptionNotes?: string,\n invalidatedBy?: string,\n invalidationDate?: string,\n invalidationNote?: string,\n}\n\nexport interface InstructorTask {\n taskId: string,\n taskName: string,\n taskState: string,\n taskOutput?: string,\n created: string,\n updated: string,\n}\n\nexport interface CertificateGenerationHistory {\n taskName: string,\n date: string,\n details: string,\n}\n\nexport interface CertificateQueryParams extends PaginationParams {\n filter: CertificateFilter,\n search: string,\n}\n\nexport interface GrantExceptionRequest {\n learners: string[],\n notes?: string,\n}\n\nexport interface InvalidateCertificateRequest {\n learners: string[],\n notes?: string,\n}\n\nexport interface RemoveExceptionRequest {\n username: string,\n}\n\nexport interface RemoveInvalidationRequest {\n username: string,\n}\n"]}
@@ -0,0 +1,12 @@
1
+ export interface ApiError {
2
+ response?: {
3
+ data?: {
4
+ error?: string;
5
+ message?: string;
6
+ detail?: string;
7
+ } | string;
8
+ };
9
+ message?: string;
10
+ }
11
+ export declare const getErrorMessage: (error: ApiError, fallbackMessage: string) => string;
12
+ export declare const parseLearnersCount: (learners: string) => number;
@@ -0,0 +1,24 @@
1
+ export const getErrorMessage = (error, fallbackMessage) => {
2
+ var _a, _b;
3
+ // Handle case where response.data is an object
4
+ if (((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) && typeof error.response.data === 'object') {
5
+ const data = error.response.data;
6
+ // Try different common error message fields
7
+ if (data.error && typeof data.error === 'string')
8
+ return data.error;
9
+ if (data.message && typeof data.message === 'string')
10
+ return data.message;
11
+ if (data.detail && typeof data.detail === 'string')
12
+ return data.detail;
13
+ // If data is an object we can't display, use fallback
14
+ return fallbackMessage;
15
+ }
16
+ // Handle case where response.data is a string
17
+ if (((_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.data) && typeof error.response.data === 'string') {
18
+ return error.response.data;
19
+ }
20
+ // Fall back to error.message or the fallback
21
+ return (error === null || error === void 0 ? void 0 : error.message) || fallbackMessage;
22
+ };
23
+ export const parseLearnersCount = (learners) => learners.split(/[\n,]/).filter((l) => l.trim()).length;
24
+ //# sourceMappingURL=errorHandling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorHandling.js","sourceRoot":"","sources":["../../../src/certificates/utils/errorHandling.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAe,EAAE,eAAuB,EAAU,EAAE;;IAClF,+CAA+C;IAC/C,IAAI,CAAA,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,QAAQ,0CAAE,IAAI,KAAI,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACrE,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;QACjC,4CAA4C;QAC5C,IAAI,IAAI,CAAC,KAAK,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;QACpE,IAAI,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC;QAC1E,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,MAAM,CAAC;QACvE,sDAAsD;QACtD,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,8CAA8C;IAC9C,IAAI,CAAA,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,QAAQ,0CAAE,IAAI,KAAI,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACrE,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC7B,CAAC;IAED,6CAA6C;IAC7C,OAAO,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,OAAO,KAAI,eAAe,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAAgB,EAAU,EAAE,CAC7D,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC","sourcesContent":["export interface ApiError {\n response?: {\n data?: {\n error?: string,\n message?: string,\n detail?: string,\n } | string,\n },\n message?: string,\n}\n\nexport const getErrorMessage = (error: ApiError, fallbackMessage: string): string => {\n // Handle case where response.data is an object\n if (error?.response?.data && typeof error.response.data === 'object') {\n const data = error.response.data;\n // Try different common error message fields\n if (data.error && typeof data.error === 'string') return data.error;\n if (data.message && typeof data.message === 'string') return data.message;\n if (data.detail && typeof data.detail === 'string') return data.detail;\n // If data is an object we can't display, use fallback\n return fallbackMessage;\n }\n\n // Handle case where response.data is a string\n if (error?.response?.data && typeof error.response.data === 'string') {\n return error.response.data;\n }\n\n // Fall back to error.message or the fallback\n return error?.message || fallbackMessage;\n};\n\nexport const parseLearnersCount = (learners: string): number =>\n learners.split(/[\\n,]/).filter((l) => l.trim()).length;\n"]}
@@ -0,0 +1,4 @@
1
+ import { CertificateData, CertificateFilter } from '../../certificates/types';
2
+ export declare const matchesFilter: (item: CertificateData, filter: CertificateFilter) => boolean;
3
+ export declare const matchesSearch: (item: CertificateData, search: string) => boolean;
4
+ export declare const filterCertificates: (data: CertificateData[], filter: CertificateFilter, search: string) => CertificateData[];
@@ -0,0 +1,31 @@
1
+ import { CertificateFilter, CertificateStatus, SpecialCase } from '../../certificates/types';
2
+ export const matchesFilter = (item, filter) => {
3
+ switch (filter) {
4
+ case CertificateFilter.RECEIVED:
5
+ return item.certificateStatus === CertificateStatus.RECEIVED;
6
+ case CertificateFilter.NOT_RECEIVED:
7
+ return item.certificateStatus === CertificateStatus.NOT_RECEIVED;
8
+ case CertificateFilter.AUDIT_PASSING:
9
+ return item.certificateStatus === CertificateStatus.AUDIT_PASSING;
10
+ case CertificateFilter.AUDIT_NOT_PASSING:
11
+ return item.certificateStatus === CertificateStatus.AUDIT_NOT_PASSING;
12
+ case CertificateFilter.ERROR_STATE:
13
+ return item.certificateStatus === CertificateStatus.ERROR_STATE;
14
+ case CertificateFilter.GRANTED_EXCEPTIONS:
15
+ return item.specialCase === SpecialCase.EXCEPTION;
16
+ case CertificateFilter.INVALIDATED:
17
+ return item.specialCase === SpecialCase.INVALIDATION;
18
+ case CertificateFilter.ALL_LEARNERS:
19
+ default:
20
+ return true;
21
+ }
22
+ };
23
+ export const matchesSearch = (item, search) => {
24
+ if (!search)
25
+ return true;
26
+ const searchLower = search.toLowerCase();
27
+ return (item.username.toLowerCase().includes(searchLower)
28
+ || item.email.toLowerCase().includes(searchLower));
29
+ };
30
+ export const filterCertificates = (data, filter, search) => data.filter((item) => matchesFilter(item, filter) && matchesSearch(item, search));
31
+ //# sourceMappingURL=filterUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filterUtils.js","sourceRoot":"","sources":["../../../src/certificates/utils/filterUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,iBAAiB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE7G,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAqB,EAAE,MAAyB,EAAW,EAAE;IACzF,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,iBAAiB,CAAC,QAAQ;YAC7B,OAAO,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,CAAC,QAAQ,CAAC;QAC/D,KAAK,iBAAiB,CAAC,YAAY;YACjC,OAAO,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,CAAC,YAAY,CAAC;QACnE,KAAK,iBAAiB,CAAC,aAAa;YAClC,OAAO,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,CAAC,aAAa,CAAC;QACpE,KAAK,iBAAiB,CAAC,iBAAiB;YACtC,OAAO,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,CAAC,iBAAiB,CAAC;QACxE,KAAK,iBAAiB,CAAC,WAAW;YAChC,OAAO,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,CAAC,WAAW,CAAC;QAClE,KAAK,iBAAiB,CAAC,kBAAkB;YACvC,OAAO,IAAI,CAAC,WAAW,KAAK,WAAW,CAAC,SAAS,CAAC;QACpD,KAAK,iBAAiB,CAAC,WAAW;YAChC,OAAO,IAAI,CAAC,WAAW,KAAK,WAAW,CAAC,YAAY,CAAC;QACvD,KAAK,iBAAiB,CAAC,YAAY,CAAC;QACpC;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAqB,EAAE,MAAc,EAAW,EAAE;IAC9E,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACzC,OAAO,CACL,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;WAC9C,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAClD,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,IAAuB,EACvB,MAAyB,EACzB,MAAc,EACK,EAAE,CACrB,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC","sourcesContent":["import { CertificateData, CertificateFilter, CertificateStatus, SpecialCase } from '@src/certificates/types';\n\nexport const matchesFilter = (item: CertificateData, filter: CertificateFilter): boolean => {\n switch (filter) {\n case CertificateFilter.RECEIVED:\n return item.certificateStatus === CertificateStatus.RECEIVED;\n case CertificateFilter.NOT_RECEIVED:\n return item.certificateStatus === CertificateStatus.NOT_RECEIVED;\n case CertificateFilter.AUDIT_PASSING:\n return item.certificateStatus === CertificateStatus.AUDIT_PASSING;\n case CertificateFilter.AUDIT_NOT_PASSING:\n return item.certificateStatus === CertificateStatus.AUDIT_NOT_PASSING;\n case CertificateFilter.ERROR_STATE:\n return item.certificateStatus === CertificateStatus.ERROR_STATE;\n case CertificateFilter.GRANTED_EXCEPTIONS:\n return item.specialCase === SpecialCase.EXCEPTION;\n case CertificateFilter.INVALIDATED:\n return item.specialCase === SpecialCase.INVALIDATION;\n case CertificateFilter.ALL_LEARNERS:\n default:\n return true;\n }\n};\n\nexport const matchesSearch = (item: CertificateData, search: string): boolean => {\n if (!search) return true;\n const searchLower = search.toLowerCase();\n return (\n item.username.toLowerCase().includes(searchLower)\n || item.email.toLowerCase().includes(searchLower)\n );\n};\n\nexport const filterCertificates = (\n data: CertificateData[],\n filter: CertificateFilter,\n search: string,\n): CertificateData[] =>\n data.filter((item) => matchesFilter(item, filter) && matchesSearch(item, search));\n"]}
@@ -0,0 +1,2 @@
1
+ export { getErrorMessage } from '../../certificates/utils/errorHandling';
2
+ export type { ApiError } from '../../certificates/utils/errorHandling';
@@ -0,0 +1,2 @@
1
+ export { getErrorMessage } from '../../certificates/utils/errorHandling';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/certificates/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC","sourcesContent":["export { getErrorMessage } from '@src/certificates/utils/errorHandling';\nexport type { ApiError } from '@src/certificates/utils/errorHandling';\n"]}
@@ -1,5 +1,5 @@
1
- interface ActionCardProps {
2
- buttonLabel: string;
1
+ export interface ActionCardProps {
2
+ buttonLabel?: string;
3
3
  customAction?: React.ReactNode;
4
4
  description: string;
5
5
  hasBorderBottom?: boolean;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Button, Card } from '@openedx/paragon';
3
3
  const ActionCard = ({ buttonLabel, customAction, description, hasBorderBottom = true, isLoading = false, title, onButtonClick, }) => {
4
- return (_jsxs(Card, { className: `bg-light-200 py-2 border-gray-500 rounded-0 shadow-none ${hasBorderBottom ? 'border-bottom' : ''}`, orientation: "horizontal", children: [_jsx(Card.Body, { className: "flex-grow-1", children: _jsxs(Card.Section, { children: [_jsx("h4", { className: "mb-2", children: title }), _jsx("p", { className: "text-muted mb-0", children: description })] }) }), _jsx(Card.Footer, { className: "d-flex align-items-center justify-content-end", children: customAction !== null && customAction !== void 0 ? customAction : (_jsx(Button, { onClick: onButtonClick, disabled: isLoading, variant: "primary", children: buttonLabel })) })] }));
4
+ return (_jsxs(Card, { className: `bg-light-200 pb-2 mt-2 border-gray-500 rounded-0 shadow-none ${hasBorderBottom ? 'border-bottom' : ''}`, orientation: "horizontal", children: [_jsx(Card.Body, { className: "flex-grow-1", children: _jsxs(Card.Section, { className: "pl-0", children: [_jsx("h4", { className: "text-primary-700 mb-2", children: title }), _jsx("p", { className: "text-primary-500 mb-0", children: description })] }) }), _jsx(Card.Footer, { className: "d-flex align-items-center justify-content-end", children: customAction !== null && customAction !== void 0 ? customAction : (buttonLabel && onButtonClick && (_jsx(Button, { onClick: onButtonClick, disabled: isLoading, variant: "primary", children: buttonLabel }))) })] }));
5
5
  };
6
6
  export default ActionCard;
7
7
  //# sourceMappingURL=ActionCard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ActionCard.js","sourceRoot":"","sources":["../../src/components/ActionCard.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAYhD,MAAM,UAAU,GAAG,CAAC,EAClB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,eAAe,GAAG,IAAI,EACtB,SAAS,GAAG,KAAK,EACjB,KAAK,EACL,aAAa,GACG,EAAE,EAAE;IACpB,OAAO,CACL,MAAC,IAAI,IAAC,SAAS,EAAE,2DAA2D,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,WAAW,EAAC,YAAY,aAC5I,KAAC,IAAI,CAAC,IAAI,IAAC,SAAS,EAAC,aAAa,YAChC,MAAC,IAAI,CAAC,OAAO,eACX,aAAI,SAAS,EAAC,MAAM,YAAE,KAAK,GAAM,EACjC,YAAG,SAAS,EAAC,iBAAiB,YAAE,WAAW,GAAK,IACnC,GACL,EACZ,KAAC,IAAI,CAAC,MAAM,IAAC,SAAS,EAAC,+CAA+C,YACnE,YAAY,aAAZ,YAAY,cAAZ,YAAY,GAAI,CACf,KAAC,MAAM,IACL,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,SAAS,EACnB,OAAO,EAAC,SAAS,YAEhB,WAAW,GACL,CACV,GACW,IACT,CACR,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["import { Button, Card } from '@openedx/paragon';\n\ninterface ActionCardProps {\n buttonLabel: string,\n customAction?: React.ReactNode,\n description: string,\n hasBorderBottom?: boolean,\n isLoading?: boolean,\n title: string,\n onButtonClick?: () => void,\n}\n\nconst ActionCard = ({\n buttonLabel,\n customAction,\n description,\n hasBorderBottom = true,\n isLoading = false,\n title,\n onButtonClick,\n}: ActionCardProps) => {\n return (\n <Card className={`bg-light-200 py-2 border-gray-500 rounded-0 shadow-none ${hasBorderBottom ? 'border-bottom' : ''}`} orientation=\"horizontal\">\n <Card.Body className=\"flex-grow-1\">\n <Card.Section>\n <h4 className=\"mb-2\">{title}</h4>\n <p className=\"text-muted mb-0\">{description}</p>\n </Card.Section>\n </Card.Body>\n <Card.Footer className=\"d-flex align-items-center justify-content-end\">\n {customAction ?? (\n <Button\n onClick={onButtonClick}\n disabled={isLoading}\n variant=\"primary\"\n >\n {buttonLabel}\n </Button>\n )}\n </Card.Footer>\n </Card>\n );\n};\n\nexport default ActionCard;\n"]}
1
+ {"version":3,"file":"ActionCard.js","sourceRoot":"","sources":["../../src/components/ActionCard.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAYhD,MAAM,UAAU,GAAG,CAAC,EAClB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,eAAe,GAAG,IAAI,EACtB,SAAS,GAAG,KAAK,EACjB,KAAK,EACL,aAAa,GACG,EAAE,EAAE;IACpB,OAAO,CACL,MAAC,IAAI,IAAC,SAAS,EAAE,gEAAgE,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,WAAW,EAAC,YAAY,aACjJ,KAAC,IAAI,CAAC,IAAI,IAAC,SAAS,EAAC,aAAa,YAChC,MAAC,IAAI,CAAC,OAAO,IAAC,SAAS,EAAC,MAAM,aAC5B,aAAI,SAAS,EAAC,uBAAuB,YAAE,KAAK,GAAM,EAClD,YAAG,SAAS,EAAC,uBAAuB,YAAE,WAAW,GAAK,IACzC,GACL,EACZ,KAAC,IAAI,CAAC,MAAM,IAAC,SAAS,EAAC,+CAA+C,YACnE,YAAY,aAAZ,YAAY,cAAZ,YAAY,GAAI,CAAC,WAAW,IAAI,aAAa,IAAI,CAChD,KAAC,MAAM,IACL,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,SAAS,EACnB,OAAO,EAAC,SAAS,YAEhB,WAAW,GACL,CACV,CAAC,GACU,IACT,CACR,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["import { Button, Card } from '@openedx/paragon';\n\nexport interface ActionCardProps {\n buttonLabel?: string,\n customAction?: React.ReactNode,\n description: string,\n hasBorderBottom?: boolean,\n isLoading?: boolean,\n title: string,\n onButtonClick?: () => void,\n}\n\nconst ActionCard = ({\n buttonLabel,\n customAction,\n description,\n hasBorderBottom = true,\n isLoading = false,\n title,\n onButtonClick,\n}: ActionCardProps) => {\n return (\n <Card className={`bg-light-200 pb-2 mt-2 border-gray-500 rounded-0 shadow-none ${hasBorderBottom ? 'border-bottom' : ''}`} orientation=\"horizontal\">\n <Card.Body className=\"flex-grow-1\">\n <Card.Section className=\"pl-0\">\n <h4 className=\"text-primary-700 mb-2\">{title}</h4>\n <p className=\"text-primary-500 mb-0\">{description}</p>\n </Card.Section>\n </Card.Body>\n <Card.Footer className=\"d-flex align-items-center justify-content-end\">\n {customAction ?? (buttonLabel && onButtonClick && (\n <Button\n onClick={onButtonClick}\n disabled={isLoading}\n variant=\"primary\"\n >\n {buttonLabel}\n </Button>\n ))}\n </Card.Footer>\n </Card>\n );\n};\n\nexport default ActionCard;\n"]}
@@ -0,0 +1,5 @@
1
+ interface CodeEditorProps {
2
+ data: string;
3
+ }
4
+ declare const CodeEditor: ({ data }: CodeEditorProps) => import("react/jsx-runtime").JSX.Element;
5
+ export default CodeEditor;
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCallback, useRef } from 'react';
3
+ import { EditorView, basicSetup } from 'codemirror';
4
+ import { EditorState } from '@codemirror/state';
5
+ const decodeHtml = (raw) => {
6
+ const parser = new DOMParser();
7
+ const doc = parser.parseFromString(raw, 'text/html');
8
+ return doc.documentElement.textContent || '';
9
+ };
10
+ const CodeEditor = ({ data }) => {
11
+ const editorRef = useRef(null);
12
+ const containerRef = useCallback((node) => {
13
+ if (editorRef.current) {
14
+ editorRef.current.destroy();
15
+ editorRef.current = null;
16
+ }
17
+ if (node && data) {
18
+ editorRef.current = new EditorView({
19
+ state: EditorState.create({
20
+ doc: decodeHtml(data),
21
+ extensions: [
22
+ basicSetup,
23
+ EditorState.readOnly.of(true),
24
+ EditorView.editable.of(false),
25
+ ],
26
+ }),
27
+ parent: node,
28
+ });
29
+ }
30
+ }, [data]);
31
+ return _jsx("div", { ref: containerRef });
32
+ };
33
+ export default CodeEditor;
34
+ //# sourceMappingURL=CodeEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeEditor.js","sourceRoot":"","sources":["../../src/components/CodeEditor.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMhD,MAAM,UAAU,GAAG,CAAC,GAAW,EAAU,EAAE;IACzC,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACrD,OAAO,GAAG,CAAC,eAAe,CAAC,WAAW,IAAI,EAAE,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,EAAE,IAAI,EAAmB,EAAE,EAAE;IAC/C,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAElD,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,IAA2B,EAAE,EAAE;QAC/D,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;YACtB,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YAC5B,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;QAC3B,CAAC;QACD,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;YACjB,SAAS,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC;gBACjC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;oBACxB,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC;oBACrB,UAAU,EAAE;wBACV,UAAU;wBACV,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC;wBAC7B,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC;qBAC9B;iBACF,CAAC;gBACF,MAAM,EAAE,IAAI;aACb,CAAC,CAAC;QACL,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,OAAO,cAAK,GAAG,EAAE,YAAY,GAAI,CAAC;AACpC,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["import { useCallback, useRef } from 'react';\nimport { EditorView, basicSetup } from 'codemirror';\nimport { EditorState } from '@codemirror/state';\n\ninterface CodeEditorProps {\n data: string,\n}\n\nconst decodeHtml = (raw: string): string => {\n const parser = new DOMParser();\n const doc = parser.parseFromString(raw, 'text/html');\n return doc.documentElement.textContent || '';\n};\n\nconst CodeEditor = ({ data }: CodeEditorProps) => {\n const editorRef = useRef<EditorView | null>(null);\n\n const containerRef = useCallback((node: HTMLDivElement | null) => {\n if (editorRef.current) {\n editorRef.current.destroy();\n editorRef.current = null;\n }\n if (node && data) {\n editorRef.current = new EditorView({\n state: EditorState.create({\n doc: decodeHtml(data),\n extensions: [\n basicSetup,\n EditorState.readOnly.of(true),\n EditorView.editable.of(false),\n ],\n }),\n parent: node,\n });\n }\n }, [data]);\n\n return <div ref={containerRef} />;\n};\n\nexport default CodeEditor;\n"]}
@@ -1,5 +1,7 @@
1
1
  interface PendingTasksProps {
2
2
  isPolling?: boolean;
3
+ isOpen?: boolean;
4
+ onToggle?: () => void;
3
5
  }
4
- declare const PendingTasks: ({ isPolling }: PendingTasksProps) => import("react/jsx-runtime").JSX.Element;
6
+ declare const PendingTasks: ({ isPolling, isOpen, onToggle }: PendingTasksProps) => import("react/jsx-runtime").JSX.Element;
5
7
  export { PendingTasks };
@@ -7,7 +7,7 @@ import { ExpandLess, ExpandMore } from '@openedx/paragon/icons';
7
7
  import { usePendingTasks } from '../data/apiHook';
8
8
  import { useParams } from 'react-router';
9
9
  import { ObjectCell } from './ObjectCell';
10
- const PendingTasks = ({ isPolling = false }) => {
10
+ const PendingTasks = ({ isPolling = false, isOpen = false, onToggle }) => {
11
11
  const intl = useIntl();
12
12
  const { courseId = '' } = useParams();
13
13
  const { data: tasks, isLoading } = usePendingTasks(courseId, { enablePolling: isPolling });
@@ -32,7 +32,8 @@ const PendingTasks = ({ isPolling = false }) => {
32
32
  }
33
33
  return (_jsx(DataTable, { columns: tableColumns, data: tasks, RowStatusComponent: () => null }));
34
34
  };
35
- return (_jsxs(Collapsible.Advanced, { className: "mt-4 pt-4 border-top", styling: "basic", children: [_jsxs(Collapsible.Trigger, { className: "collapsible-trigger d-flex border-0 align-items-center text-decoration-none", children: [_jsx("div", { className: "d-flex", children: _jsx("h3", { className: "text-primary-700", children: intl.formatMessage(messages.pendingTasksTitle) }) }), _jsx(Collapsible.Visible, { whenClosed: true, children: _jsx("div", { className: "pl-2 d-flex", children: _jsx(Icon, { className: "text-primary-500", src: ExpandMore }) }) }), _jsx(Collapsible.Visible, { whenOpen: true, children: _jsx("div", { className: "pl-2 d-flex", children: _jsx(Icon, { className: "text-primary-500", src: ExpandLess }) }) })] }), _jsx(Collapsible.Body, { children: renderContent() })] }));
35
+ const collapsibleProps = onToggle ? { open: isOpen, onToggle } : {};
36
+ return (_jsxs(Collapsible.Advanced, Object.assign({ className: "mt-4 pt-4 border-top", styling: "basic" }, collapsibleProps, { children: [_jsxs(Collapsible.Trigger, { className: "collapsible-trigger d-flex border-0 align-items-center text-decoration-none", children: [_jsx("div", { className: "d-flex", children: _jsx("h3", { className: "text-primary-700", children: intl.formatMessage(messages.pendingTasksTitle) }) }), _jsx(Collapsible.Visible, { whenClosed: true, children: _jsx("div", { className: "pl-2 d-flex", children: _jsx(Icon, { className: "text-primary-500", src: ExpandMore }) }) }), _jsx(Collapsible.Visible, { whenOpen: true, children: _jsx("div", { className: "pl-2 d-flex", children: _jsx(Icon, { className: "text-primary-500", src: ExpandLess }) }) })] }), _jsx(Collapsible.Body, { children: renderContent() })] })));
36
37
  };
37
38
  export { PendingTasks };
38
39
  //# sourceMappingURL=PendingTasks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PendingTasks.js","sourceRoot":"","sources":["../../src/components/PendingTasks.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useIntl } from '@openedx/frontend-base';\nimport { Collapsible, DataTable, Icon, Skeleton } from '@openedx/paragon';\nimport { useMemo } from 'react';\nimport messages from './messages';\nimport { ExpandLess, ExpandMore } from '@openedx/paragon/icons';\nimport { usePendingTasks } from '@src/data/apiHook';\nimport { useParams } from 'react-router';\nimport { ObjectCell } from './ObjectCell';\nimport { PendingTask, TableCellValue } from '@src/types';\n\ninterface PendingTasksProps {\n isPolling?: boolean,\n}\n\nconst PendingTasks = ({ isPolling = false }: PendingTasksProps) => {\n const intl = useIntl();\n const { courseId = '' } = useParams();\n const { data: tasks, isLoading } = usePendingTasks(courseId, { enablePolling: isPolling });\n\n const tableColumns = useMemo(() => [\n { accessor: 'taskType', Header: intl.formatMessage(messages.taskTypeColumnName) },\n { accessor: 'taskInput', Header: intl.formatMessage(messages.taskInputColumnName), Cell: ({ row }: TableCellValue<PendingTask>) => <ObjectCell value={row.original.taskInput} /> },\n { accessor: 'taskId', Header: intl.formatMessage(messages.taskIdColumnName) },\n { accessor: 'requester', Header: intl.formatMessage(messages.requesterColumnName) },\n { accessor: 'taskState', Header: intl.formatMessage(messages.taskStateColumnName) },\n { accessor: 'created', Header: intl.formatMessage(messages.createdColumnName) },\n { accessor: 'taskOutput', Header: intl.formatMessage(messages.taskOutputColumnName), Cell: ({ row }: TableCellValue<PendingTask>) => <ObjectCell value={row.original.taskOutput} /> },\n { accessor: 'durationSec', Header: intl.formatMessage(messages.durationColumnName) },\n { accessor: 'status', Header: intl.formatMessage(messages.statusColumnName) },\n { accessor: 'taskMessage', Header: intl.formatMessage(messages.taskMessageColumnName) },\n ], [intl]);\n\n const renderContent = () => {\n if (isLoading) {\n return <Skeleton count={3} />;\n }\n\n if (!tasks || tasks?.length === 0) {\n return <div className=\"my-3\">{intl.formatMessage(messages.noTasksMessage)}</div>;\n }\n\n return (\n <DataTable\n columns={tableColumns}\n data={tasks}\n RowStatusComponent={() => null}\n />\n );\n };\n\n return (\n <Collapsible.Advanced\n className=\"mt-4 pt-4 border-top\"\n styling=\"basic\"\n >\n <Collapsible.Trigger\n className=\"collapsible-trigger d-flex border-0 align-items-center text-decoration-none\"\n >\n <div className=\"d-flex\">\n <h3 className=\"text-primary-700\">{intl.formatMessage(messages.pendingTasksTitle)}</h3>\n </div>\n\n <Collapsible.Visible whenClosed>\n <div className=\"pl-2 d-flex\">\n <Icon className=\"text-primary-500\" src={ExpandMore} />\n </div>\n </Collapsible.Visible>\n <Collapsible.Visible whenOpen>\n <div className=\"pl-2 d-flex\">\n <Icon className=\"text-primary-500\" src={ExpandLess} />\n </div>\n </Collapsible.Visible>\n </Collapsible.Trigger>\n <Collapsible.Body>\n {renderContent() }\n </Collapsible.Body>\n </Collapsible.Advanced>\n );\n};\n\nexport { PendingTasks };\n"]}
1
+ {"version":3,"file":"PendingTasks.js","sourceRoot":"","sources":["../../src/components/PendingTasks.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useIntl } from '@openedx/frontend-base';\nimport { Collapsible, DataTable, Icon, Skeleton } from '@openedx/paragon';\nimport { useMemo } from 'react';\nimport messages from './messages';\nimport { ExpandLess, ExpandMore } from '@openedx/paragon/icons';\nimport { usePendingTasks } from '@src/data/apiHook';\nimport { useParams } from 'react-router';\nimport { ObjectCell } from './ObjectCell';\nimport { PendingTask, TableCellValue } from '@src/types';\n\ninterface PendingTasksProps {\n isPolling?: boolean,\n isOpen?: boolean,\n onToggle?: () => void,\n}\n\nconst PendingTasks = ({ isPolling = false, isOpen = false, onToggle }: PendingTasksProps) => {\n const intl = useIntl();\n const { courseId = '' } = useParams();\n const { data: tasks, isLoading } = usePendingTasks(courseId, { enablePolling: isPolling });\n\n const tableColumns = useMemo(() => [\n { accessor: 'taskType', Header: intl.formatMessage(messages.taskTypeColumnName) },\n { accessor: 'taskInput', Header: intl.formatMessage(messages.taskInputColumnName), Cell: ({ row }: TableCellValue<PendingTask>) => <ObjectCell value={row.original.taskInput} /> },\n { accessor: 'taskId', Header: intl.formatMessage(messages.taskIdColumnName) },\n { accessor: 'requester', Header: intl.formatMessage(messages.requesterColumnName) },\n { accessor: 'taskState', Header: intl.formatMessage(messages.taskStateColumnName) },\n { accessor: 'created', Header: intl.formatMessage(messages.createdColumnName) },\n { accessor: 'taskOutput', Header: intl.formatMessage(messages.taskOutputColumnName), Cell: ({ row }: TableCellValue<PendingTask>) => <ObjectCell value={row.original.taskOutput} /> },\n { accessor: 'durationSec', Header: intl.formatMessage(messages.durationColumnName) },\n { accessor: 'status', Header: intl.formatMessage(messages.statusColumnName) },\n { accessor: 'taskMessage', Header: intl.formatMessage(messages.taskMessageColumnName) },\n ], [intl]);\n\n const renderContent = () => {\n if (isLoading) {\n return <Skeleton count={3} />;\n }\n\n if (!tasks || tasks?.length === 0) {\n return <div className=\"my-3\">{intl.formatMessage(messages.noTasksMessage)}</div>;\n }\n\n return (\n <DataTable\n columns={tableColumns}\n data={tasks}\n RowStatusComponent={() => null}\n />\n );\n };\n\n const collapsibleProps = onToggle ? { open: isOpen, onToggle } : {};\n\n return (\n <Collapsible.Advanced\n className=\"mt-4 pt-4 border-top\"\n styling=\"basic\"\n {...collapsibleProps}\n >\n <Collapsible.Trigger\n className=\"collapsible-trigger d-flex border-0 align-items-center text-decoration-none\"\n >\n <div className=\"d-flex\">\n <h3 className=\"text-primary-700\">{intl.formatMessage(messages.pendingTasksTitle)}</h3>\n </div>\n\n <Collapsible.Visible whenClosed>\n <div className=\"pl-2 d-flex\">\n <Icon className=\"text-primary-500\" src={ExpandMore} />\n </div>\n </Collapsible.Visible>\n <Collapsible.Visible whenOpen>\n <div className=\"pl-2 d-flex\">\n <Icon className=\"text-primary-500\" src={ExpandLess} />\n </div>\n </Collapsible.Visible>\n </Collapsible.Trigger>\n <Collapsible.Body>\n {renderContent() }\n </Collapsible.Body>\n </Collapsible.Advanced>\n );\n};\n\nexport { PendingTasks };\n"]}
@@ -3,5 +3,8 @@ interface SpecifyLearnerFieldProps {
3
3
  learner?: SelectedLearner;
4
4
  onClickSelect: (emailOrUsername: string) => void;
5
5
  }
6
- declare const SpecifyLearnerField: ({ learner, onClickSelect }: SpecifyLearnerFieldProps) => import("react/jsx-runtime").JSX.Element;
6
+ interface SpecifyLearnerFieldRef {
7
+ reset: () => void;
8
+ }
9
+ declare const SpecifyLearnerField: import("react").ForwardRefExoticComponent<SpecifyLearnerFieldProps & import("react").RefAttributes<SpecifyLearnerFieldRef>>;
7
10
  export default SpecifyLearnerField;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useState } from 'react';
2
+ import { useState, useImperativeHandle, forwardRef } from 'react';
3
3
  import { isAxiosError } from 'axios';
4
4
  import { useParams } from 'react-router-dom';
5
5
  import { Avatar, Button, FormControl, FormGroup, FormLabel, useToggle } from '@openedx/paragon';
@@ -8,37 +8,77 @@ import { SpinnerIcon } from '@openedx/paragon/icons';
8
8
  import { useDebouncedFilter } from '../hooks/useDebouncedFilter';
9
9
  import { useCourseInfo, useLearner } from '../data/apiHook';
10
10
  import messages from './messages';
11
- const SpecifyLearnerField = ({ learner, onClickSelect }) => {
12
- var _a;
11
+ const errorMessages = {
12
+ not_found: messages.learnerNotFound,
13
+ generic_error: messages.learnerGenericError,
14
+ not_enrolled: messages.learnerNotEnrolled,
15
+ };
16
+ const getErrorState = (error, data) => {
17
+ var _a, _b;
18
+ const isNotFoundError = isAxiosError(error)
19
+ && (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404 || ((_b = error.response) === null || _b === void 0 ? void 0 : _b.status) === 400);
20
+ if (isNotFoundError)
21
+ return 'not_found';
22
+ if (data && !data.isEnrolled)
23
+ return 'not_enrolled';
24
+ if (error && !isNotFoundError)
25
+ return 'generic_error';
26
+ return null;
27
+ };
28
+ const initialLearnerState = {
29
+ username: '',
30
+ fullName: '',
31
+ email: '',
32
+ isEnrolled: false,
33
+ };
34
+ const SpecifyLearnerField = forwardRef(({ learner, onClickSelect }, ref) => {
13
35
  const intl = useIntl();
14
36
  const { courseId = '' } = useParams();
15
37
  const [identifier, setIdentifier] = useState('');
16
- const [showLearner, enableShowLearner, disableShowLearner] = useToggle(false);
38
+ const [showLearner, enableShowLearner, disableShowLearner] = useToggle(!!learner);
39
+ const [errorState, setErrorState] = useState(null);
17
40
  const { data: courseInfo } = useCourseInfo(courseId);
18
41
  const permissions = (courseInfo === null || courseInfo === void 0 ? void 0 : courseInfo.permissions) || { admin: false, dataResearcher: false };
19
- const { inputValue, handleChange } = useDebouncedFilter({
42
+ const { inputValue, handleChange, resetFilter } = useDebouncedFilter({
20
43
  filterValue: identifier,
21
44
  setFilter: setIdentifier,
22
45
  });
23
- const { data = { email: '', fullName: '', username: '' }, refetch, error } = useLearner(courseId, inputValue);
24
- const selectedLearner = learner || data;
46
+ const { data, refetch } = useLearner(courseId, inputValue);
47
+ const resetState = () => {
48
+ resetFilter();
49
+ onClickSelect('');
50
+ disableShowLearner();
51
+ setErrorState(null);
52
+ };
53
+ useImperativeHandle(ref, () => ({
54
+ reset: resetState,
55
+ }));
56
+ const selectedLearner = learner || data || initialLearnerState;
25
57
  const handleInputChange = (event) => {
26
58
  handleChange(event.target.value);
59
+ if (errorState) {
60
+ setErrorState(null);
61
+ }
27
62
  if (showLearner) {
28
63
  disableShowLearner();
29
64
  }
30
65
  };
31
66
  const handleClickSelect = () => {
32
67
  if (inputValue) {
33
- onClickSelect(inputValue);
34
- refetch();
35
- enableShowLearner();
68
+ refetch().then((result) => {
69
+ var _a;
70
+ // Need to pass empty value if learner is not valid to clear out any previously selected learner
71
+ // We could have other conditions/fields depending on valid learner
72
+ const formValue = !result.error && ((_a = result.data) === null || _a === void 0 ? void 0 : _a.isEnrolled) ? inputValue : '';
73
+ setErrorState(getErrorState(result.error, result === null || result === void 0 ? void 0 : result.data));
74
+ onClickSelect(formValue);
75
+ enableShowLearner();
76
+ });
36
77
  }
37
78
  };
38
- return (_jsxs(FormGroup, { className: "mb-0", size: "sm", children: [_jsx(FormLabel, { className: "text-primary-500 d-flex", children: intl.formatMessage(messages.specifyLearner) }), _jsxs("div", { className: "d-flex align-items-center", children: [_jsx(FormControl, { className: `mr-2 ${selectedLearner.username && showLearner ? 'd-none' : ''}`, name: "emailOrUsername", placeholder: intl.formatMessage(messages.specifyLearnerPlaceholder), size: "md", autoResize: true, value: inputValue, onChange: handleInputChange }), selectedLearner.username && showLearner ? (_jsxs(_Fragment, { children: [_jsx(Avatar, { className: "mr-2.5", size: "sm" }), _jsxs("div", { className: "d-flex flex-column mr-3 text-primary-500", children: [_jsx("p", { className: "mb-0", children: selectedLearner.username }), (permissions.admin || permissions.dataResearcher)
39
- && (_jsxs("div", { className: "d-flex x-small", children: [_jsx("p", { className: "mr-3 mb-0", children: selectedLearner.fullName }), _jsx("p", { className: "mb-0", children: selectedLearner.email })] }))] }), !learner && _jsx(Button, { iconBefore: SpinnerIcon, onClick: disableShowLearner, children: intl.formatMessage(messages.change) })] })) : (_jsx(Button, { onClick: handleClickSelect, disabled: !inputValue, children: intl.formatMessage(messages.select) }))] }), showLearner && error
40
- && isAxiosError(error)
41
- && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404 && (_jsx("p", { className: "text-danger-500 mb-0 x-small mt-2", children: intl.formatMessage(messages.learnerNotFound, { identifier }) }))] }));
42
- };
79
+ return (_jsxs(FormGroup, { className: "mb-0", size: "sm", children: [_jsx(FormLabel, { className: "text-primary-500 d-flex", children: selectedLearner.username ? intl.formatMessage(messages.selectedLearner) : intl.formatMessage(messages.specifyLearner) }), _jsxs("div", { className: "d-flex align-items-center", children: [_jsx(FormControl, { className: `mr-2 ${selectedLearner.username && showLearner ? 'd-none' : ''}`, name: "emailOrUsername", placeholder: intl.formatMessage(messages.specifyLearnerPlaceholder), size: "md", autoResize: true, value: inputValue, onChange: handleInputChange }), selectedLearner.username && showLearner ? (_jsxs(_Fragment, { children: [_jsx(Avatar, { className: "mr-2.5", size: "sm" }), _jsxs("div", { className: "d-flex flex-column mr-3 text-primary-500", children: [_jsx("p", { className: "mb-0", children: selectedLearner.username }), (permissions.admin || permissions.dataResearcher)
80
+ && (_jsxs("div", { className: "d-flex x-small", children: [_jsx("p", { className: "mr-3 mb-0", children: selectedLearner.fullName }), _jsx("p", { className: "mb-0", children: selectedLearner.email })] }))] }), !learner && _jsx(Button, { iconBefore: SpinnerIcon, onClick: resetState, children: intl.formatMessage(messages.change) })] })) : (_jsx(Button, { onClick: handleClickSelect, disabled: !inputValue, children: intl.formatMessage(messages.select) }))] }), showLearner && errorState && (_jsx("p", { className: "text-danger-500 mb-0 x-small mt-2", children: intl.formatMessage(errorMessages[errorState], { identifier: inputValue }) }))] }));
81
+ });
82
+ SpecifyLearnerField.displayName = 'SpecifyLearnerField';
43
83
  export default SpecifyLearnerField;
44
84
  //# sourceMappingURL=SpecifyLearnerField.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SpecifyLearnerField.js","sourceRoot":"","sources":["../../src/components/SpecifyLearnerField.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState, ChangeEvent } from 'react';\nimport { isAxiosError } from 'axios';\nimport { useParams } from 'react-router-dom';\nimport { Avatar, Button, FormControl, FormGroup, FormLabel, useToggle } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport { SpinnerIcon } from '@openedx/paragon/icons';\nimport { useDebouncedFilter } from '@src/hooks/useDebouncedFilter';\nimport { useCourseInfo, useLearner } from '@src/data/apiHook';\nimport { SelectedLearner } from '@src/types';\nimport messages from './messages';\n\ninterface SpecifyLearnerFieldProps {\n learner?: SelectedLearner,\n onClickSelect: (emailOrUsername: string) => void,\n}\n\nconst SpecifyLearnerField = ({ learner, onClickSelect }: SpecifyLearnerFieldProps) => {\n const intl = useIntl();\n const { courseId = '' } = useParams<{ courseId: string }>();\n const [identifier, setIdentifier] = useState('');\n const [showLearner, enableShowLearner, disableShowLearner] = useToggle(false);\n const { data: courseInfo } = useCourseInfo(courseId);\n const permissions = courseInfo?.permissions || { admin: false, dataResearcher: false };\n const { inputValue, handleChange } = useDebouncedFilter({\n filterValue: identifier,\n setFilter: setIdentifier,\n });\n const { data = { email: '', fullName: '', username: '' }, refetch, error } = useLearner(courseId, inputValue);\n\n const selectedLearner = learner || data;\n\n const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {\n handleChange(event.target.value);\n\n if (showLearner) {\n disableShowLearner();\n }\n };\n\n const handleClickSelect = () => {\n if (inputValue) {\n onClickSelect(inputValue);\n refetch();\n enableShowLearner();\n }\n };\n\n return (\n <FormGroup className=\"mb-0\" size=\"sm\">\n <FormLabel className=\"text-primary-500 d-flex\">{intl.formatMessage(messages.specifyLearner)}</FormLabel>\n <div className=\"d-flex align-items-center\">\n <FormControl\n className={`mr-2 ${selectedLearner.username && showLearner ? 'd-none' : ''}`}\n name=\"emailOrUsername\"\n placeholder={intl.formatMessage(messages.specifyLearnerPlaceholder)}\n size=\"md\"\n autoResize\n value={inputValue}\n onChange={handleInputChange}\n />\n {selectedLearner.username && showLearner ? (\n <>\n <Avatar className=\"mr-2.5\" size=\"sm\" />\n <div className=\"d-flex flex-column mr-3 text-primary-500\">\n <p className=\"mb-0\">{selectedLearner.username}</p>\n {(permissions.admin || permissions.dataResearcher)\n && (\n <div className=\"d-flex x-small\">\n <p className=\"mr-3 mb-0\">{selectedLearner.fullName}</p>\n <p className=\"mb-0\">{selectedLearner.email}</p>\n </div>\n )}\n </div>\n {!learner && <Button iconBefore={SpinnerIcon} onClick={disableShowLearner}>{intl.formatMessage(messages.change)}</Button>}\n </>\n ) : (\n <Button onClick={handleClickSelect} disabled={!inputValue}>{intl.formatMessage(messages.select)}</Button>\n )}\n </div>\n {showLearner && error\n && isAxiosError(error)\n && error.response?.status === 404 && (\n <p className=\"text-danger-500 mb-0 x-small mt-2\">\n {intl.formatMessage(messages.learnerNotFound, { identifier })}\n </p>\n )}\n </FormGroup>\n );\n};\n\nexport default SpecifyLearnerField;\n"]}
1
+ {"version":3,"file":"SpecifyLearnerField.js","sourceRoot":"","sources":["../../src/components/SpecifyLearnerField.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState, ChangeEvent, useImperativeHandle, forwardRef } from 'react';\nimport { isAxiosError } from 'axios';\nimport { useParams } from 'react-router-dom';\nimport { Avatar, Button, FormControl, FormGroup, FormLabel, useToggle } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport { SpinnerIcon } from '@openedx/paragon/icons';\nimport { useDebouncedFilter } from '@src/hooks/useDebouncedFilter';\nimport { useCourseInfo, useLearner } from '@src/data/apiHook';\nimport { SelectedLearner } from '@src/types';\nimport messages from './messages';\n\ninterface SpecifyLearnerFieldProps {\n learner?: SelectedLearner,\n onClickSelect: (emailOrUsername: string) => void,\n}\n\ninterface SpecifyLearnerFieldRef {\n reset: () => void,\n}\n\ntype ErrorState = 'not_enrolled' | 'not_found' | 'generic_error' | null;\n\nconst errorMessages = {\n not_found: messages.learnerNotFound,\n generic_error: messages.learnerGenericError,\n not_enrolled: messages.learnerNotEnrolled,\n};\n\nconst getErrorState = (error: Error | null, data?: SelectedLearner): ErrorState => {\n const isNotFoundError = isAxiosError(error)\n && (error.response?.status === 404 || error.response?.status === 400);\n\n if (isNotFoundError) return 'not_found';\n if (data && !data.isEnrolled) return 'not_enrolled';\n if (error && !isNotFoundError) return 'generic_error';\n return null;\n};\n\nconst initialLearnerState = {\n username: '',\n fullName: '',\n email: '',\n isEnrolled: false,\n};\n\nconst SpecifyLearnerField = forwardRef<SpecifyLearnerFieldRef, SpecifyLearnerFieldProps>(({ learner, onClickSelect }, ref) => {\n const intl = useIntl();\n const { courseId = '' } = useParams<{ courseId: string }>();\n const [identifier, setIdentifier] = useState('');\n const [showLearner, enableShowLearner, disableShowLearner] = useToggle(!!learner);\n const [errorState, setErrorState] = useState<ErrorState>(null);\n const { data: courseInfo } = useCourseInfo(courseId);\n const permissions = courseInfo?.permissions || { admin: false, dataResearcher: false };\n const { inputValue, handleChange, resetFilter } = useDebouncedFilter({\n filterValue: identifier,\n setFilter: setIdentifier,\n });\n const { data, refetch } = useLearner(courseId, inputValue);\n\n const resetState = () => {\n resetFilter();\n onClickSelect('');\n disableShowLearner();\n setErrorState(null);\n };\n\n useImperativeHandle(ref, () => ({\n reset: resetState,\n }));\n\n const selectedLearner = learner || data || initialLearnerState;\n\n const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {\n handleChange(event.target.value);\n\n if (errorState) {\n setErrorState(null);\n }\n\n if (showLearner) {\n disableShowLearner();\n }\n };\n\n const handleClickSelect = () => {\n if (inputValue) {\n refetch().then((result) => {\n // Need to pass empty value if learner is not valid to clear out any previously selected learner\n // We could have other conditions/fields depending on valid learner\n const formValue = !result.error && result.data?.isEnrolled ? inputValue : '';\n\n setErrorState(getErrorState(result.error, result?.data));\n onClickSelect(formValue);\n enableShowLearner();\n });\n }\n };\n\n return (\n <FormGroup className=\"mb-0\" size=\"sm\">\n <FormLabel className=\"text-primary-500 d-flex\">{selectedLearner.username ? intl.formatMessage(messages.selectedLearner) : intl.formatMessage(messages.specifyLearner)}</FormLabel>\n <div className=\"d-flex align-items-center\">\n <FormControl\n className={`mr-2 ${selectedLearner.username && showLearner ? 'd-none' : ''}`}\n name=\"emailOrUsername\"\n placeholder={intl.formatMessage(messages.specifyLearnerPlaceholder)}\n size=\"md\"\n autoResize\n value={inputValue}\n onChange={handleInputChange}\n />\n {selectedLearner.username && showLearner ? (\n <>\n <Avatar className=\"mr-2.5\" size=\"sm\" />\n <div className=\"d-flex flex-column mr-3 text-primary-500\">\n <p className=\"mb-0\">{selectedLearner.username}</p>\n {(permissions.admin || permissions.dataResearcher)\n && (\n <div className=\"d-flex x-small\">\n <p className=\"mr-3 mb-0\">{selectedLearner.fullName}</p>\n <p className=\"mb-0\">{selectedLearner.email}</p>\n </div>\n )}\n </div>\n {!learner && <Button iconBefore={SpinnerIcon} onClick={resetState}>{intl.formatMessage(messages.change)}</Button>}\n </>\n ) : (\n <Button onClick={handleClickSelect} disabled={!inputValue}>{intl.formatMessage(messages.select)}</Button>\n )}\n </div>\n {showLearner && errorState && (\n <p className=\"text-danger-500 mb-0 x-small mt-2\">\n {intl.formatMessage(errorMessages[errorState], { identifier: inputValue })}\n </p>\n )}\n </FormGroup>\n );\n});\n\nSpecifyLearnerField.displayName = 'SpecifyLearnerField';\n\nexport default SpecifyLearnerField;\n"]}
@@ -0,0 +1,13 @@
1
+ interface SpecifyProblemFieldProps {
2
+ buttonLabel: string;
3
+ disabled?: boolean;
4
+ fieldLabel: string;
5
+ problemResponsesError?: string;
6
+ usernameOrEmail?: string;
7
+ onClickSelect: (problemLocation: string, event: React.MouseEvent<HTMLButtonElement>) => void;
8
+ }
9
+ interface SpecifyProblemFieldRef {
10
+ reset: () => void;
11
+ }
12
+ declare const SpecifyProblemField: import("react").ForwardRefExoticComponent<SpecifyProblemFieldProps & import("react").RefAttributes<SpecifyProblemFieldRef>>;
13
+ export default SpecifyProblemField;
@@ -0,0 +1,52 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useImperativeHandle, forwardRef } from 'react';
3
+ import { isAxiosError } from 'axios';
4
+ import { useParams } from 'react-router-dom';
5
+ import { Button, Form, Icon, OverlayTrigger, Tooltip, useToggle } from '@openedx/paragon';
6
+ import { InfoOutline, SpinnerIcon } from '@openedx/paragon/icons';
7
+ import { useIntl } from '@openedx/frontend-base';
8
+ import messages from './messages';
9
+ import { useDebouncedFilter } from '../hooks/useDebouncedFilter';
10
+ import { useProblemDetails } from '../data/apiHook';
11
+ const SpecifyProblemField = forwardRef(({ buttonLabel, disabled, fieldLabel, problemResponsesError, usernameOrEmail = '', onClickSelect, }, ref) => {
12
+ var _a, _b;
13
+ const intl = useIntl();
14
+ const { courseId = '' } = useParams();
15
+ const [problemLocation, setProblemLocation] = useState('');
16
+ const [showSelectedLocation, enableShowSelectedLocation, disableShowSelectedLocation] = useToggle(false);
17
+ const { inputValue, handleChange, resetFilter } = useDebouncedFilter({
18
+ filterValue: problemLocation,
19
+ setFilter: setProblemLocation,
20
+ });
21
+ const { data = { breadcrumbs: [], name: '', id: '' }, refetch, error } = useProblemDetails(courseId, inputValue, usernameOrEmail);
22
+ useImperativeHandle(ref, () => ({
23
+ reset: () => {
24
+ resetFilter();
25
+ disableShowSelectedLocation();
26
+ }
27
+ }));
28
+ const handleInputChange = (e) => {
29
+ handleChange(e.target.value);
30
+ if (showSelectedLocation) {
31
+ disableShowSelectedLocation();
32
+ }
33
+ };
34
+ const handleClick = (event) => {
35
+ if (inputValue) {
36
+ refetch().then(() => {
37
+ onClickSelect(inputValue, event);
38
+ enableShowSelectedLocation();
39
+ });
40
+ }
41
+ };
42
+ return (_jsxs(Form.Group, { className: "mb-0", isInvalid: !!problemResponsesError, size: "sm", children: [_jsx(Form.Label, { className: "d-flex align-content-end align-items-center gap-2 text-primary-500", children: showSelectedLocation ? intl.formatMessage(messages.selectedProblem)
43
+ : (_jsxs(_Fragment, { children: [fieldLabel, _jsx(OverlayTrigger, { placement: "top", overlay: (_jsx(Tooltip, { id: "problem-location-tooltip", className: "info-tooltip", children: intl.formatMessage(messages.problemLocationTooltip) })), children: _jsx(Icon, { src: InfoOutline, size: "sm", "aria-label": intl.formatMessage(messages.problemLocationInfoIconLabel) }) })] })) }), _jsx("div", { className: "d-flex align-items-center", children: showSelectedLocation && data && !error ? (_jsxs("div", { className: "d-flex gap-3 align-items-center col-8 p-0", children: [_jsxs("div", { className: "d-block w-100", children: [_jsx("p", { className: "x-small mb-0 text-primary-500 text-truncate", children: data.breadcrumbs
44
+ .slice(1, -1)
45
+ .map(breadcrumb => breadcrumb.displayName)
46
+ .join(' > ') }), _jsx("p", { className: "text-primary-500 mb-0", children: data.name }), _jsx("p", { className: "x-small text-gray-700 text-truncate mb-0", children: data.id })] }), _jsx(Button, { iconBefore: SpinnerIcon, onClick: disableShowSelectedLocation, children: intl.formatMessage(messages.change) })] })) : (_jsxs(_Fragment, { children: [_jsx(Form.Control, { type: "text", placeholder: intl.formatMessage(messages.problemLocationPlaceholder), value: inputValue, onChange: handleInputChange, className: "flex-grow-1", size: "md" }), problemResponsesError && (_jsx(Form.Control.Feedback, { type: "invalid", children: problemResponsesError })), _jsx(Button, { variant: "primary", onClick: handleClick, disabled: disabled || !inputValue, className: "text-nowrap", children: buttonLabel })] })) }), showSelectedLocation && error
47
+ && isAxiosError(error)
48
+ && ((((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 400) || (((_b = error.response) === null || _b === void 0 ? void 0 : _b.status) === 404)) && (_jsx("p", { className: "text-danger-500 mb-0 x-small mt-2", children: intl.formatMessage(messages.problemNotFound, { identifier: inputValue }) }))] }));
49
+ });
50
+ SpecifyProblemField.displayName = 'SpecifyProblemField';
51
+ export default SpecifyProblemField;
52
+ //# sourceMappingURL=SpecifyProblemField.js.map