@openedx/frontend-app-instructor-dashboard 1.0.0-alpha.3 → 1.0.0-alpha.31

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 (270) hide show
  1. package/dist/Main.d.ts +1 -1
  2. package/dist/Main.js +4 -13
  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 +214 -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 +32 -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 +16 -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/GenerationHistoryTable.d.ts +11 -0
  26. package/dist/certificates/components/GenerationHistoryTable.js +25 -0
  27. package/dist/certificates/components/GenerationHistoryTable.js.map +1 -0
  28. package/dist/certificates/components/GrantExceptionsModal.d.ts +8 -0
  29. package/dist/certificates/components/GrantExceptionsModal.js +10 -0
  30. package/dist/certificates/components/GrantExceptionsModal.js.map +1 -0
  31. package/dist/certificates/components/InvalidateCertificateModal.d.ts +8 -0
  32. package/dist/certificates/components/InvalidateCertificateModal.js +10 -0
  33. package/dist/certificates/components/InvalidateCertificateModal.js.map +1 -0
  34. package/dist/certificates/components/IssuedCertificatesTab.d.ts +18 -0
  35. package/dist/certificates/components/IssuedCertificatesTab.js +6 -0
  36. package/dist/certificates/components/IssuedCertificatesTab.js.map +1 -0
  37. package/dist/certificates/components/LearnerActionModal.d.ts +16 -0
  38. package/dist/certificates/components/LearnerActionModal.js +27 -0
  39. package/dist/certificates/components/LearnerActionModal.js.map +1 -0
  40. package/dist/certificates/components/RemoveExceptionModal.d.ts +9 -0
  41. package/dist/certificates/components/RemoveExceptionModal.js +10 -0
  42. package/dist/certificates/components/RemoveExceptionModal.js.map +1 -0
  43. package/dist/certificates/components/RemoveInvalidationModal.d.ts +9 -0
  44. package/dist/certificates/components/RemoveInvalidationModal.js +10 -0
  45. package/dist/certificates/components/RemoveInvalidationModal.js.map +1 -0
  46. package/dist/certificates/constants.d.ts +15 -0
  47. package/dist/certificates/constants.js +16 -0
  48. package/dist/certificates/constants.js.map +1 -0
  49. package/dist/certificates/data/api.d.ts +23 -0
  50. package/dist/certificates/data/api.js +115 -0
  51. package/dist/certificates/data/api.js.map +1 -0
  52. package/dist/certificates/data/apiHook.d.ts +50 -0
  53. package/dist/certificates/data/apiHook.js +118 -0
  54. package/dist/certificates/data/apiHook.js.map +1 -0
  55. package/dist/certificates/data/queryKeys.d.ts +9 -0
  56. package/dist/certificates/data/queryKeys.js +9 -0
  57. package/dist/certificates/data/queryKeys.js.map +1 -0
  58. package/dist/certificates/messages.d.ts +343 -0
  59. package/dist/certificates/messages.js +345 -0
  60. package/dist/certificates/messages.js.map +1 -0
  61. package/dist/certificates/types.d.ts +66 -0
  62. package/dist/certificates/types.js +26 -0
  63. package/dist/certificates/types.js.map +1 -0
  64. package/dist/certificates/utils/errorHandling.d.ts +10 -0
  65. package/dist/certificates/utils/errorHandling.js +3 -0
  66. package/dist/certificates/utils/errorHandling.js.map +1 -0
  67. package/dist/certificates/utils/filterUtils.d.ts +4 -0
  68. package/dist/certificates/utils/filterUtils.js +31 -0
  69. package/dist/certificates/utils/filterUtils.js.map +1 -0
  70. package/dist/certificates/utils/index.d.ts +2 -0
  71. package/dist/certificates/utils/index.js +2 -0
  72. package/dist/certificates/utils/index.js.map +1 -0
  73. package/dist/components/ActionCard.d.ts +2 -2
  74. package/dist/components/ActionCard.js +1 -1
  75. package/dist/components/ActionCard.js.map +1 -1
  76. package/dist/components/CodeEditor.d.ts +5 -0
  77. package/dist/components/CodeEditor.js +34 -0
  78. package/dist/components/CodeEditor.js.map +1 -0
  79. package/dist/components/PendingTasks.d.ts +3 -1
  80. package/dist/components/PendingTasks.js +3 -2
  81. package/dist/components/PendingTasks.js.map +1 -1
  82. package/dist/components/SpecifyLearnerField.d.ts +4 -1
  83. package/dist/components/SpecifyLearnerField.js +33 -13
  84. package/dist/components/SpecifyLearnerField.js.map +1 -1
  85. package/dist/components/SpecifyProblemField.d.ts +13 -0
  86. package/dist/components/SpecifyProblemField.js +52 -0
  87. package/dist/components/SpecifyProblemField.js.map +1 -0
  88. package/dist/components/UsernameFilter.d.ts +7 -0
  89. package/dist/components/UsernameFilter.js +19 -0
  90. package/dist/components/UsernameFilter.js.map +1 -0
  91. package/dist/components/messages.d.ts +40 -0
  92. package/dist/components/messages.js +40 -0
  93. package/dist/components/messages.js.map +1 -1
  94. package/dist/courseInfo/types.d.ts +5 -0
  95. package/dist/courseInfo/types.js.map +1 -1
  96. package/dist/courseTeam/CourseTeamPage.js +25 -2
  97. package/dist/courseTeam/CourseTeamPage.js.map +1 -1
  98. package/dist/courseTeam/components/AddTeamMemberModal.d.ts +6 -0
  99. package/dist/courseTeam/components/AddTeamMemberModal.js +61 -0
  100. package/dist/courseTeam/components/AddTeamMemberModal.js.map +1 -0
  101. package/dist/courseTeam/components/EditTeamMemberModal.d.ts +8 -0
  102. package/dist/courseTeam/components/EditTeamMemberModal.js +102 -0
  103. package/dist/courseTeam/components/EditTeamMemberModal.js.map +1 -0
  104. package/dist/courseTeam/components/MembersContent.d.ts +6 -0
  105. package/dist/courseTeam/components/MembersContent.js +48 -0
  106. package/dist/courseTeam/components/MembersContent.js.map +1 -0
  107. package/dist/courseTeam/components/RoleFilter.d.ts +7 -0
  108. package/dist/courseTeam/components/RoleFilter.js +22 -0
  109. package/dist/courseTeam/components/RoleFilter.js.map +1 -0
  110. package/dist/courseTeam/components/RolesContent.d.ts +3 -0
  111. package/dist/courseTeam/components/RolesContent.js +25 -0
  112. package/dist/courseTeam/components/RolesContent.js.map +1 -0
  113. package/dist/courseTeam/constants.d.ts +3 -0
  114. package/dist/courseTeam/constants.js +4 -0
  115. package/dist/courseTeam/constants.js.map +1 -0
  116. package/dist/courseTeam/data/api.d.ts +6 -0
  117. package/dist/courseTeam/data/api.js +38 -0
  118. package/dist/courseTeam/data/api.js.map +1 -0
  119. package/dist/courseTeam/data/apiHook.d.ts +8 -0
  120. package/dist/courseTeam/data/apiHook.js +32 -0
  121. package/dist/courseTeam/data/apiHook.js.map +1 -0
  122. package/dist/courseTeam/data/queryKeys.d.ts +7 -0
  123. package/dist/courseTeam/data/queryKeys.js +14 -0
  124. package/dist/courseTeam/data/queryKeys.js.map +1 -0
  125. package/dist/courseTeam/messages.d.ts +258 -0
  126. package/dist/courseTeam/messages.js +260 -0
  127. package/dist/courseTeam/messages.js.map +1 -0
  128. package/dist/courseTeam/types.d.ts +29 -0
  129. package/dist/courseTeam/types.js +3 -0
  130. package/dist/courseTeam/types.js.map +1 -0
  131. package/dist/data/api.d.ts +2 -1
  132. package/dist/data/api.js +9 -3
  133. package/dist/data/api.js.map +1 -1
  134. package/dist/data/apiHook.d.ts +1 -0
  135. package/dist/data/apiHook.js +10 -2
  136. package/dist/data/apiHook.js.map +1 -1
  137. package/dist/data/queryKeys.d.ts +4 -0
  138. package/dist/data/queryKeys.js +4 -0
  139. package/dist/data/queryKeys.js.map +1 -1
  140. package/dist/dateExtensions/components/AddExtensionModal.d.ts +1 -1
  141. package/dist/dateExtensions/components/AddExtensionModal.js +6 -7
  142. package/dist/dateExtensions/components/AddExtensionModal.js.map +1 -1
  143. package/dist/dateExtensions/components/DateExtensionsList.js +3 -14
  144. package/dist/dateExtensions/components/DateExtensionsList.js.map +1 -1
  145. package/dist/dateExtensions/data/apiHook.d.ts +2 -2
  146. package/dist/dateExtensions/data/apiHook.js +4 -4
  147. package/dist/dateExtensions/data/apiHook.js.map +1 -1
  148. package/dist/dateExtensions/messages.d.ts +0 -5
  149. package/dist/dateExtensions/messages.js +1 -6
  150. package/dist/dateExtensions/messages.js.map +1 -1
  151. package/dist/enrollments/EnrollmentsPage.js +41 -7
  152. package/dist/enrollments/EnrollmentsPage.js.map +1 -1
  153. package/dist/enrollments/components/AddBetaTestersModal.d.ts +6 -0
  154. package/dist/enrollments/components/AddBetaTestersModal.js +69 -0
  155. package/dist/enrollments/components/AddBetaTestersModal.js.map +1 -0
  156. package/dist/enrollments/components/EnrollLearnersModal.d.ts +6 -0
  157. package/dist/enrollments/components/EnrollLearnersModal.js +53 -0
  158. package/dist/enrollments/components/EnrollLearnersModal.js.map +1 -0
  159. package/dist/enrollments/components/EnrollmentStatusModal.js +3 -3
  160. package/dist/enrollments/components/EnrollmentStatusModal.js.map +1 -1
  161. package/dist/enrollments/components/EnrollmentsList.d.ts +3 -2
  162. package/dist/enrollments/components/EnrollmentsList.js +13 -14
  163. package/dist/enrollments/components/EnrollmentsList.js.map +1 -1
  164. package/dist/enrollments/components/UnenrollModal.d.ts +1 -1
  165. package/dist/enrollments/components/UnenrollModal.js +29 -3
  166. package/dist/enrollments/components/UnenrollModal.js.map +1 -1
  167. package/dist/enrollments/components/UpdateBetaTesterModal.d.ts +8 -0
  168. package/dist/enrollments/components/UpdateBetaTesterModal.js +52 -0
  169. package/dist/enrollments/components/UpdateBetaTesterModal.js.map +1 -0
  170. package/dist/enrollments/data/api.d.ts +3 -1
  171. package/dist/enrollments/data/api.js +11 -1
  172. package/dist/enrollments/data/api.js.map +1 -1
  173. package/dist/enrollments/data/apiHook.d.ts +5 -3
  174. package/dist/enrollments/data/apiHook.js +21 -3
  175. package/dist/enrollments/data/apiHook.js.map +1 -1
  176. package/dist/enrollments/data/queryKeys.d.ts +1 -1
  177. package/dist/enrollments/data/queryKeys.js.map +1 -1
  178. package/dist/enrollments/messages.d.ts +131 -1
  179. package/dist/enrollments/messages.js +136 -6
  180. package/dist/enrollments/messages.js.map +1 -1
  181. package/dist/enrollments/types.d.ts +25 -0
  182. package/dist/enrollments/types.js.map +1 -1
  183. package/dist/grading/GradingPage.js +15 -2
  184. package/dist/grading/GradingPage.js.map +1 -1
  185. package/dist/grading/components/GradingActionRow.d.ts +2 -0
  186. package/dist/grading/components/GradingActionRow.js +28 -0
  187. package/dist/grading/components/GradingActionRow.js.map +1 -0
  188. package/dist/grading/components/GradingConfigurationModal.d.ts +6 -0
  189. package/dist/grading/components/GradingConfigurationModal.js +15 -0
  190. package/dist/grading/components/GradingConfigurationModal.js.map +1 -0
  191. package/dist/grading/components/GradingLearnerContent.d.ts +7 -0
  192. package/dist/grading/components/GradingLearnerContent.js +114 -0
  193. package/dist/grading/components/GradingLearnerContent.js.map +1 -0
  194. package/dist/grading/data/api.d.ts +6 -0
  195. package/dist/grading/data/api.js +59 -0
  196. package/dist/grading/data/api.js.map +1 -0
  197. package/dist/grading/data/apiHook.d.ts +6 -0
  198. package/dist/grading/data/apiHook.js +29 -0
  199. package/dist/grading/data/apiHook.js.map +1 -0
  200. package/dist/grading/data/queryKeys.d.ts +9 -0
  201. package/dist/grading/data/queryKeys.js +8 -0
  202. package/dist/grading/data/queryKeys.js.map +1 -0
  203. package/dist/grading/messages.d.ts +173 -0
  204. package/dist/grading/messages.js +175 -0
  205. package/dist/grading/messages.js.map +1 -0
  206. package/dist/grading/types.d.ts +11 -0
  207. package/dist/grading/types.js +2 -0
  208. package/dist/grading/types.js.map +1 -0
  209. package/dist/hooks/useDebouncedFilter.d.ts +1 -0
  210. package/dist/hooks/useDebouncedFilter.js +5 -0
  211. package/dist/hooks/useDebouncedFilter.js.map +1 -1
  212. package/dist/instructorNav/InstructorNav.js +6 -1
  213. package/dist/instructorNav/InstructorNav.js.map +1 -1
  214. package/dist/routes.d.ts +1 -1
  215. package/dist/routes.js +2 -2
  216. package/dist/routes.js.map +1 -1
  217. package/dist/specialExams/SpecialExamsPage.js +14 -2
  218. package/dist/specialExams/SpecialExamsPage.js.map +1 -1
  219. package/dist/specialExams/components/AddAllowanceModal.d.ts +6 -0
  220. package/dist/specialExams/components/AddAllowanceModal.js +84 -0
  221. package/dist/specialExams/components/AddAllowanceModal.js.map +1 -0
  222. package/dist/specialExams/components/Allowances.d.ts +2 -0
  223. package/dist/specialExams/components/Allowances.js +32 -0
  224. package/dist/specialExams/components/Allowances.js.map +1 -0
  225. package/dist/specialExams/components/AllowancesList.d.ts +8 -0
  226. package/dist/specialExams/components/AllowancesList.js +58 -0
  227. package/dist/specialExams/components/AllowancesList.js.map +1 -0
  228. package/dist/specialExams/components/AttemptsList.d.ts +3 -0
  229. package/dist/specialExams/components/AttemptsList.js +45 -0
  230. package/dist/specialExams/components/AttemptsList.js.map +1 -0
  231. package/dist/specialExams/components/DeleteAllowanceModal.d.ts +8 -0
  232. package/dist/specialExams/components/DeleteAllowanceModal.js +29 -0
  233. package/dist/specialExams/components/DeleteAllowanceModal.js.map +1 -0
  234. package/dist/specialExams/components/EditAllowanceModal.d.ts +8 -0
  235. package/dist/specialExams/components/EditAllowanceModal.js +62 -0
  236. package/dist/specialExams/components/EditAllowanceModal.js.map +1 -0
  237. package/dist/specialExams/constants.d.ts +43 -0
  238. package/dist/specialExams/constants.js +19 -0
  239. package/dist/specialExams/constants.js.map +1 -0
  240. package/dist/specialExams/data/api.d.ts +7 -0
  241. package/dist/specialExams/data/api.js +49 -0
  242. package/dist/specialExams/data/api.js.map +1 -0
  243. package/dist/specialExams/data/apiHook.d.ts +6 -0
  244. package/dist/specialExams/data/apiHook.js +37 -0
  245. package/dist/specialExams/data/apiHook.js.map +1 -0
  246. package/dist/specialExams/data/queryKeys.d.ts +8 -0
  247. package/dist/specialExams/data/queryKeys.js +9 -0
  248. package/dist/specialExams/data/queryKeys.js.map +1 -0
  249. package/dist/specialExams/messages.d.ts +223 -0
  250. package/dist/specialExams/messages.js +225 -0
  251. package/dist/specialExams/messages.js.map +1 -0
  252. package/dist/specialExams/types.d.ts +64 -0
  253. package/dist/specialExams/types.js +2 -0
  254. package/dist/specialExams/types.js.map +1 -0
  255. package/dist/style.scss +16 -0
  256. package/dist/testUtils.js +2 -2
  257. package/dist/testUtils.js.map +1 -1
  258. package/dist/types/index.d.ts +1 -0
  259. package/dist/types/index.js.map +1 -1
  260. package/dist/utils/formatters.d.ts +5 -0
  261. package/dist/utils/formatters.js +10 -0
  262. package/dist/utils/formatters.js.map +1 -1
  263. package/package.json +4 -5
  264. package/dist/app.scss +0 -10
  265. package/dist/providers/QueryProvider.d.ts +0 -6
  266. package/dist/providers/QueryProvider.js +0 -16
  267. package/dist/providers/QueryProvider.js.map +0 -1
  268. package/dist/providers.d.ts +0 -3
  269. package/dist/providers.js +0 -8
  270. package/dist/providers.js.map +0 -1
package/dist/Main.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import './app.scss';
1
+ import './style.scss';
2
2
  declare const Main: () => import("react/jsx-runtime").JSX.Element;
3
3
  export default Main;
package/dist/Main.js CHANGED
@@ -1,19 +1,10 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { lazy, Suspense } from 'react';
3
- import { CurrentAppProvider, getAppConfig } from '@openedx/frontend-base';
4
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { CurrentAppProvider } from '@openedx/frontend-base';
5
3
  import { Outlet } from 'react-router-dom';
6
4
  import { AlertProvider } from './providers/AlertProvider';
7
5
  import { appId } from './constants';
8
6
  import PageWrapper from './pageWrapper/PageWrapper';
9
- import './app.scss';
10
- // Use a dynamic import guarded by process.env.NODE_ENV so the consumer's
11
- // webpack dead-code-eliminates this in production builds, meaning
12
- // @tanstack/react-query-devtools does not need to be installed by consumers.
13
- const ReactQueryDevtools = process.env.NODE_ENV === 'development'
14
- ? lazy(() => import('@tanstack/react-query-devtools').then((m) => ({ default: m.ReactQueryDevtools })))
15
- : null;
16
- const queryClient = new QueryClient();
17
- const Main = () => (_jsx(CurrentAppProvider, { appId: appId, children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(AlertProvider, { children: _jsxs("main", { className: "d-flex flex-column flex-grow-1", children: [_jsx(PageWrapper, { children: _jsx(Outlet, {}) }), ReactQueryDevtools && getAppConfig(appId).NODE_ENV === 'development' && (_jsx(Suspense, { fallback: null, children: _jsx(ReactQueryDevtools, { initialIsOpen: false }) }))] }) }) }) }));
7
+ import './style.scss';
8
+ const Main = () => (_jsx(CurrentAppProvider, { appId: appId, children: _jsx(AlertProvider, { children: _jsx("main", { className: "d-flex flex-column flex-grow-1", children: _jsx(PageWrapper, { children: _jsx(Outlet, {}) }) }) }) }));
18
9
  export default Main;
19
10
  //# sourceMappingURL=Main.js.map
package/dist/Main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Main.js","sourceRoot":"","sources":["../src/Main.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,WAAW,MAAM,2BAA2B,CAAC;AAEpD,OAAO,YAAY,CAAC;AAEpB,yEAAyE;AACzE,kEAAkE;AAClE,6EAA6E;AAC7E,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa;IAC/D,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,gCAAgC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC;IACvG,CAAC,CAAC,IAAI,CAAC;AAET,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AAEtC,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,CACjB,KAAC,kBAAkB,IAAC,KAAK,EAAE,KAAK,YAC9B,KAAC,mBAAmB,IAAC,MAAM,EAAE,WAAW,YACtC,KAAC,aAAa,cACZ,gBAAM,SAAS,EAAC,gCAAgC,aAC9C,KAAC,WAAW,cACV,KAAC,MAAM,KAAG,GACE,EACb,kBAAkB,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,QAAQ,KAAK,aAAa,IAAI,CACvE,KAAC,QAAQ,IAAC,QAAQ,EAAE,IAAI,YACtB,KAAC,kBAAkB,IAAC,aAAa,EAAE,KAAK,GAAI,GACnC,CACZ,IACI,GACO,GACI,GACH,CACtB,CAAC;AAEF,eAAe,IAAI,CAAC","sourcesContent":["import { lazy, Suspense } from 'react';\nimport { CurrentAppProvider, getAppConfig } from '@openedx/frontend-base';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { Outlet } from 'react-router-dom';\nimport { AlertProvider } from './providers/AlertProvider';\nimport { appId } from './constants';\nimport PageWrapper from './pageWrapper/PageWrapper';\n\nimport './app.scss';\n\n// Use a dynamic import guarded by process.env.NODE_ENV so the consumer's\n// webpack dead-code-eliminates this in production builds, meaning\n// @tanstack/react-query-devtools does not need to be installed by consumers.\nconst ReactQueryDevtools = process.env.NODE_ENV === 'development'\n ? lazy(() => import('@tanstack/react-query-devtools').then((m) => ({ default: m.ReactQueryDevtools })))\n : null;\n\nconst queryClient = new QueryClient();\n\nconst Main = () => (\n <CurrentAppProvider appId={appId}>\n <QueryClientProvider client={queryClient}>\n <AlertProvider>\n <main className=\"d-flex flex-column flex-grow-1\">\n <PageWrapper>\n <Outlet />\n </PageWrapper>\n {ReactQueryDevtools && getAppConfig(appId).NODE_ENV === 'development' && (\n <Suspense fallback={null}>\n <ReactQueryDevtools initialIsOpen={false} />\n </Suspense>\n )}\n </main>\n </AlertProvider>\n </QueryClientProvider>\n </CurrentAppProvider>\n);\n\nexport default Main;\n"]}
1
+ {"version":3,"file":"Main.js","sourceRoot":"","sources":["../src/Main.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,WAAW,MAAM,2BAA2B,CAAC;AAEpD,OAAO,cAAc,CAAC;AAEtB,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,CACjB,KAAC,kBAAkB,IAAC,KAAK,EAAE,KAAK,YAC9B,KAAC,aAAa,cACZ,eAAM,SAAS,EAAC,gCAAgC,YAC9C,KAAC,WAAW,cACV,KAAC,MAAM,KAAG,GACE,GACT,GACO,GACG,CACtB,CAAC;AAEF,eAAe,IAAI,CAAC","sourcesContent":["import { CurrentAppProvider } from '@openedx/frontend-base';\nimport { Outlet } from 'react-router-dom';\nimport { AlertProvider } from './providers/AlertProvider';\nimport { appId } from './constants';\nimport PageWrapper from './pageWrapper/PageWrapper';\n\nimport './style.scss';\n\nconst Main = () => (\n <CurrentAppProvider appId={appId}>\n <AlertProvider>\n <main className=\"d-flex flex-column flex-grow-1\">\n <PageWrapper>\n <Outlet />\n </PageWrapper>\n </main>\n </AlertProvider>\n </CurrentAppProvider>\n);\n\nexport default Main;\n"]}
package/dist/app.js CHANGED
@@ -1,18 +1,12 @@
1
1
  import { appId } from './constants';
2
2
  import routes from './routes';
3
3
  import slots from './slots';
4
- import providers from './providers';
5
4
  import provides from './provides';
6
5
  const app = {
7
6
  appId,
8
7
  routes,
9
- providers,
10
8
  provides,
11
9
  slots,
12
- config: {
13
- NODE_ENV: 'development',
14
- LMS_BASE_URL: 'http://local.openedx.io:8000'
15
- },
16
10
  };
17
11
  export default app;
18
12
  //# sourceMappingURL=app.js.map
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,QAAQ,MAAM,eAAe,CAAC;AAErC,MAAM,GAAG,GAAQ;IACf,KAAK;IACL,MAAM;IACN,SAAS;IACT,QAAQ;IACR,KAAK;IACL,MAAM,EAAE;QACN,QAAQ,EAAE,aAAa;QACvB,YAAY,EAAE,8BAA8B;KAC7C;CACF,CAAC;AAEF,eAAe,GAAG,CAAC","sourcesContent":["import { App } from '@openedx/frontend-base';\nimport { appId } from '@src/constants';\nimport routes from '@src/routes';\nimport slots from '@src/slots';\nimport providers from '@src/providers';\nimport provides from '@src/provides';\n\nconst app: App = {\n appId,\n routes,\n providers,\n provides,\n slots,\n config: {\n NODE_ENV: 'development',\n LMS_BASE_URL: 'http://local.openedx.io:8000'\n },\n};\n\nexport default app;\n"]}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,QAAQ,MAAM,eAAe,CAAC;AAErC,MAAM,GAAG,GAAQ;IACf,KAAK;IACL,MAAM;IACN,QAAQ;IACR,KAAK;CACN,CAAC;AAEF,eAAe,GAAG,CAAC","sourcesContent":["import { App } from '@openedx/frontend-base';\nimport { appId } from '@src/constants';\nimport routes from '@src/routes';\nimport slots from '@src/slots';\nimport provides from '@src/provides';\n\nconst app: App = {\n appId,\n routes,\n provides,\n slots,\n};\n\nexport default app;\n"]}
@@ -1,2 +1,3 @@
1
+ import './CertificatesPage.scss';
1
2
  declare const CertificatesPage: () => import("react/jsx-runtime").JSX.Element;
2
3
  export default CertificatesPage;
@@ -1,6 +1,218 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useCallback } from 'react';
3
+ import { useParams } from 'react-router-dom';
4
+ import { Card, Container, Tab, Tabs, Alert } from '@openedx/paragon';
5
+ import { useIntl } from '@openedx/frontend-base';
6
+ import { useAlert } from '../providers/AlertProvider';
7
+ import { useCourseInfo } from '../data/apiHook';
8
+ import CertificatesPageHeader from '../certificates/components/CertificatesPageHeader';
9
+ import IssuedCertificatesTab from '../certificates/components/IssuedCertificatesTab';
10
+ import GenerationHistoryTable from '../certificates/components/GenerationHistoryTable';
11
+ import GrantExceptionsModal from '../certificates/components/GrantExceptionsModal';
12
+ import InvalidateCertificateModal from '../certificates/components/InvalidateCertificateModal';
13
+ import RemoveExceptionModal from '../certificates/components/RemoveExceptionModal';
14
+ import RemoveInvalidationModal from '../certificates/components/RemoveInvalidationModal';
15
+ import DisableCertificatesModal from '../certificates/components/DisableCertificatesModal';
16
+ import { useCertificateGenerationHistory, useGrantBulkExceptions, useInvalidateCertificate, useIssuedCertificates, useRegenerateCertificates, useRemoveException, useRemoveInvalidation, useToggleCertificateGeneration, } from '../certificates/data/apiHook';
17
+ import { CertificateFilter } from '../certificates/types';
18
+ import { CERTIFICATES_PAGE_SIZE, TAB_KEYS, MODAL_TITLES, ALERT_VARIANTS } from '../certificates/constants';
19
+ import { getErrorMessage } from '../certificates/utils/errorHandling';
20
+ import messages from '../certificates/messages';
21
+ import './CertificatesPage.scss';
2
22
  const CertificatesPage = () => {
3
- return (_jsx("div", { children: _jsx("h3", { children: "Certificates" }) }));
23
+ const intl = useIntl();
24
+ const { courseId = '' } = useParams();
25
+ const { showToast, showModal } = useAlert();
26
+ const { data: courseInfo } = useCourseInfo(courseId);
27
+ const [filter, setFilter] = useState(CertificateFilter.ALL_LEARNERS);
28
+ const [search, setSearch] = useState('');
29
+ const [certificatesPage, setCertificatesPage] = useState(0);
30
+ const [tasksPage, setTasksPage] = useState(0);
31
+ const [activeTab, setActiveTab] = useState(TAB_KEYS.ISSUED);
32
+ const [selectedUsername, setSelectedUsername] = useState('');
33
+ const [selectedEmail, setSelectedEmail] = useState('');
34
+ const [isCertificateGenerationEnabled, setIsCertificateGenerationEnabled] = useState(true);
35
+ const [isGrantExceptionsOpen, setIsGrantExceptionsOpen] = useState(false);
36
+ const [isInvalidateCertificateOpen, setIsInvalidateCertificateOpen] = useState(false);
37
+ const [isRemoveExceptionOpen, setIsRemoveExceptionOpen] = useState(false);
38
+ const [isRemoveInvalidationOpen, setIsRemoveInvalidationOpen] = useState(false);
39
+ const [isDisableCertificatesOpen, setIsDisableCertificatesOpen] = useState(false);
40
+ const { data: certificatesData, isLoading: isLoadingCertificates, } = useIssuedCertificates(courseId, {
41
+ page: certificatesPage,
42
+ pageSize: CERTIFICATES_PAGE_SIZE,
43
+ filter,
44
+ search,
45
+ });
46
+ const { data: historyData, isLoading: isLoadingHistory, } = useCertificateGenerationHistory(courseId, {
47
+ page: tasksPage,
48
+ pageSize: CERTIFICATES_PAGE_SIZE,
49
+ });
50
+ const { mutate: grantExceptions, isPending: isGrantingExceptions } = useGrantBulkExceptions(courseId);
51
+ const { mutate: invalidateCert, isPending: isInvalidating } = useInvalidateCertificate(courseId);
52
+ const { mutate: removeExcept, isPending: isRemovingException } = useRemoveException(courseId);
53
+ const { mutate: removeInval, isPending: isRemovingInvalidation } = useRemoveInvalidation(courseId);
54
+ const { mutate: toggleGeneration, isPending: isTogglingGeneration } = useToggleCertificateGeneration(courseId);
55
+ const { mutate: regenerateCerts } = useRegenerateCertificates(courseId);
56
+ const handleGrantExceptions = useCallback((learners, notes) => {
57
+ grantExceptions({ learners, notes }, {
58
+ onSuccess: (data) => {
59
+ setIsGrantExceptionsOpen(false);
60
+ if (data.errors && data.errors.length > 0) {
61
+ const errorMessages = data.errors.map(err => `${err.learner}: ${err.message}`).join('\n');
62
+ showModal({
63
+ title: MODAL_TITLES.ERROR,
64
+ message: `Some exceptions failed:\n${errorMessages}`,
65
+ variant: ALERT_VARIANTS.WARNING,
66
+ });
67
+ }
68
+ if (data.success && data.success.length > 0) {
69
+ showToast(intl.formatMessage(messages.exceptionsGrantedToast, { count: data.success.length }));
70
+ }
71
+ },
72
+ onError: (error) => {
73
+ showModal({
74
+ title: MODAL_TITLES.ERROR,
75
+ message: getErrorMessage(error, intl.formatMessage(messages.errorGrantException)),
76
+ variant: ALERT_VARIANTS.DANGER,
77
+ });
78
+ },
79
+ });
80
+ }, [grantExceptions, showToast, showModal, intl]);
81
+ const handleInvalidateCertificate = useCallback((learners, notes) => {
82
+ invalidateCert({ learners, notes }, {
83
+ onSuccess: (data) => {
84
+ setIsInvalidateCertificateOpen(false);
85
+ if (data.errors && data.errors.length > 0) {
86
+ const errorMessages = data.errors.map(err => `${err.learner}: ${err.message}`).join('\n');
87
+ showModal({
88
+ title: MODAL_TITLES.ERROR,
89
+ message: `Some invalidations failed:\n${errorMessages}`,
90
+ variant: ALERT_VARIANTS.WARNING,
91
+ });
92
+ }
93
+ if (data.success && data.success.length > 0) {
94
+ showToast(intl.formatMessage(messages.certificatesInvalidatedToast, { count: data.success.length }));
95
+ }
96
+ },
97
+ onError: (error) => {
98
+ showModal({
99
+ title: MODAL_TITLES.ERROR,
100
+ message: getErrorMessage(error, intl.formatMessage(messages.errorInvalidateCertificate)),
101
+ variant: ALERT_VARIANTS.DANGER,
102
+ });
103
+ },
104
+ });
105
+ }, [invalidateCert, showToast, showModal, intl]);
106
+ const handleRemoveExceptionClick = useCallback((username, email) => {
107
+ setSelectedUsername(username);
108
+ setSelectedEmail(email);
109
+ setIsRemoveExceptionOpen(true);
110
+ }, []);
111
+ const handleRemoveExceptionConfirm = useCallback(() => {
112
+ // Backend accepts either username or email - use whichever is available
113
+ const identifier = selectedUsername || selectedEmail;
114
+ if (!identifier) {
115
+ showModal({
116
+ title: MODAL_TITLES.ERROR,
117
+ message: intl.formatMessage(messages.errorRemoveException) + ': Username or email is required',
118
+ variant: ALERT_VARIANTS.DANGER,
119
+ });
120
+ return;
121
+ }
122
+ removeExcept({ username: identifier }, {
123
+ onSuccess: () => {
124
+ setIsRemoveExceptionOpen(false);
125
+ setSelectedUsername('');
126
+ setSelectedEmail('');
127
+ showToast(intl.formatMessage(messages.exceptionRemovedToast, { email: selectedEmail }));
128
+ },
129
+ onError: (error) => {
130
+ showModal({
131
+ title: MODAL_TITLES.ERROR,
132
+ message: getErrorMessage(error, intl.formatMessage(messages.errorRemoveException)),
133
+ variant: ALERT_VARIANTS.DANGER,
134
+ });
135
+ },
136
+ });
137
+ }, [removeExcept, selectedUsername, selectedEmail, showToast, showModal, intl]);
138
+ const handleRemoveInvalidationClick = useCallback((username, email) => {
139
+ setSelectedUsername(username);
140
+ setSelectedEmail(email);
141
+ setIsRemoveInvalidationOpen(true);
142
+ }, []);
143
+ const handleRemoveInvalidationConfirm = useCallback(() => {
144
+ // Backend accepts either username or email - use whichever is available
145
+ const identifier = selectedUsername || selectedEmail;
146
+ if (!identifier) {
147
+ showModal({
148
+ title: MODAL_TITLES.ERROR,
149
+ message: intl.formatMessage(messages.errorRemoveInvalidation) + ': Username or email is required',
150
+ variant: ALERT_VARIANTS.DANGER,
151
+ });
152
+ return;
153
+ }
154
+ removeInval({ username: identifier }, {
155
+ onSuccess: () => {
156
+ setIsRemoveInvalidationOpen(false);
157
+ setSelectedUsername('');
158
+ setSelectedEmail('');
159
+ showToast(intl.formatMessage(messages.invalidationRemovedToast, { email: selectedEmail }));
160
+ },
161
+ onError: (error) => {
162
+ showModal({
163
+ title: MODAL_TITLES.ERROR,
164
+ message: getErrorMessage(error, intl.formatMessage(messages.errorRemoveInvalidation)),
165
+ variant: ALERT_VARIANTS.DANGER,
166
+ });
167
+ },
168
+ });
169
+ }, [removeInval, selectedUsername, selectedEmail, showToast, showModal, intl]);
170
+ const handleToggleCertificateGeneration = useCallback(() => {
171
+ const newState = !isCertificateGenerationEnabled;
172
+ toggleGeneration(newState, {
173
+ onSuccess: () => {
174
+ setIsCertificateGenerationEnabled(newState);
175
+ setIsDisableCertificatesOpen(false);
176
+ showToast(newState
177
+ ? intl.formatMessage(messages.successEnableCertificates)
178
+ : intl.formatMessage(messages.successDisableCertificates));
179
+ },
180
+ onError: (error) => {
181
+ showModal({
182
+ title: MODAL_TITLES.ERROR,
183
+ message: getErrorMessage(error, intl.formatMessage(messages.errorToggleCertificateGeneration)),
184
+ variant: ALERT_VARIANTS.DANGER,
185
+ });
186
+ },
187
+ });
188
+ }, [isCertificateGenerationEnabled, toggleGeneration, showToast, showModal, intl]);
189
+ const handleRegenerateCertificates = useCallback(() => {
190
+ regenerateCerts(filter, {
191
+ onSuccess: () => {
192
+ showToast(intl.formatMessage(messages.certificatesRegeneratedToast));
193
+ },
194
+ onError: (error) => {
195
+ showModal({
196
+ title: MODAL_TITLES.ERROR,
197
+ message: getErrorMessage(error, intl.formatMessage(messages.errorRegenerateCertificates)),
198
+ variant: ALERT_VARIANTS.DANGER,
199
+ });
200
+ },
201
+ });
202
+ }, [regenerateCerts, filter, showToast, showModal, intl]);
203
+ // Check if certificate management is disabled
204
+ if (courseInfo && !courseInfo.certificatesEnabled) {
205
+ return (_jsx(Container, { className: "mt-4.5 mb-4", fluid: true, children: _jsx(Alert, { variant: "warning", children: intl.formatMessage(messages.certificatesDisabledMessage) }) }));
206
+ }
207
+ return (_jsxs(Container, { className: "mt-4.5 mb-4", fluid: true, children: [_jsx(CertificatesPageHeader, { onGrantExceptions: () => setIsGrantExceptionsOpen(true), onInvalidateCertificate: () => setIsInvalidateCertificateOpen(true), onDisableCertificates: () => setIsDisableCertificatesOpen(true) }), _jsx(Card, { variant: "muted", className: "pt-3 pt-md-4 pb-4 pb-md-6 certificates-card", children: _jsxs(Tabs, { activeKey: activeTab, onSelect: (key) => setActiveTab(key || TAB_KEYS.ISSUED), className: "mx-4", variant: "button-group", children: [_jsx(Tab, { eventKey: TAB_KEYS.ISSUED, title: intl.formatMessage(messages.issuedCertificatesTab), children: _jsx(IssuedCertificatesTab, { data: (certificatesData === null || certificatesData === void 0 ? void 0 : certificatesData.results) || [], isLoading: isLoadingCertificates, itemCount: (certificatesData === null || certificatesData === void 0 ? void 0 : certificatesData.count) || 0, pageCount: (certificatesData === null || certificatesData === void 0 ? void 0 : certificatesData.numPages) || 0, search: search, onSearchChange: setSearch, filter: filter, onFilterChange: setFilter, currentPage: certificatesPage, onPageChange: setCertificatesPage, onRemoveException: handleRemoveExceptionClick, onRemoveInvalidation: handleRemoveInvalidationClick, onRegenerateCertificates: handleRegenerateCertificates }) }), _jsx(Tab, { eventKey: TAB_KEYS.HISTORY, title: intl.formatMessage(messages.generationHistoryTab), children: _jsx("div", { className: "d-flex flex-column mt-3 mt-md-4", children: _jsx(GenerationHistoryTable, { data: (historyData === null || historyData === void 0 ? void 0 : historyData.results) || [], isLoading: isLoadingHistory, itemCount: (historyData === null || historyData === void 0 ? void 0 : historyData.count) || 0, pageCount: (historyData === null || historyData === void 0 ? void 0 : historyData.numPages) || 0, currentPage: tasksPage, onPageChange: setTasksPage }) }) })] }) }), _jsx(GrantExceptionsModal, { isOpen: isGrantExceptionsOpen, onClose: () => setIsGrantExceptionsOpen(false), onSubmit: handleGrantExceptions, isSubmitting: isGrantingExceptions }), _jsx(InvalidateCertificateModal, { isOpen: isInvalidateCertificateOpen, onClose: () => setIsInvalidateCertificateOpen(false), onSubmit: handleInvalidateCertificate, isSubmitting: isInvalidating }), _jsx(RemoveExceptionModal, { isOpen: isRemoveExceptionOpen, email: selectedEmail, onClose: () => {
208
+ setIsRemoveExceptionOpen(false);
209
+ setSelectedUsername('');
210
+ setSelectedEmail('');
211
+ }, onConfirm: handleRemoveExceptionConfirm, isSubmitting: isRemovingException }), _jsx(RemoveInvalidationModal, { isOpen: isRemoveInvalidationOpen, email: selectedEmail, onClose: () => {
212
+ setIsRemoveInvalidationOpen(false);
213
+ setSelectedUsername('');
214
+ setSelectedEmail('');
215
+ }, onConfirm: handleRemoveInvalidationConfirm, isSubmitting: isRemovingInvalidation }), _jsx(DisableCertificatesModal, { isOpen: isDisableCertificatesOpen, isEnabled: isCertificateGenerationEnabled, onClose: () => setIsDisableCertificatesOpen(false), onConfirm: handleToggleCertificateGeneration, isSubmitting: isTogglingGeneration })] }));
4
216
  };
5
217
  export default CertificatesPage;
6
218
  //# sourceMappingURL=CertificatesPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CertificatesPage.js","sourceRoot":"","sources":["../../src/certificates/CertificatesPage.tsx"],"names":[],"mappings":";AAAA,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,OAAO,CACL,wBACE,wCAAqB,GACjB,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["const CertificatesPage = () => {\n return (\n <div>\n <h3>Certificates</h3>\n </div>\n );\n};\n\nexport default CertificatesPage;\n"]}
1
+ {"version":3,"file":"CertificatesPage.js","sourceRoot":"","sources":["../../src/certificates/CertificatesPage.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { Card, Container, Tab, Tabs, Alert } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport { useAlert } from '@src/providers/AlertProvider';\nimport { useCourseInfo } from '@src/data/apiHook';\nimport CertificatesPageHeader from '@src/certificates/components/CertificatesPageHeader';\nimport IssuedCertificatesTab from '@src/certificates/components/IssuedCertificatesTab';\nimport GenerationHistoryTable from '@src/certificates/components/GenerationHistoryTable';\nimport GrantExceptionsModal from '@src/certificates/components/GrantExceptionsModal';\nimport InvalidateCertificateModal from '@src/certificates/components/InvalidateCertificateModal';\nimport RemoveExceptionModal from '@src/certificates/components/RemoveExceptionModal';\nimport RemoveInvalidationModal from '@src/certificates/components/RemoveInvalidationModal';\nimport DisableCertificatesModal from '@src/certificates/components/DisableCertificatesModal';\nimport {\n useCertificateGenerationHistory,\n useGrantBulkExceptions,\n useInvalidateCertificate,\n useIssuedCertificates,\n useRegenerateCertificates,\n useRemoveException,\n useRemoveInvalidation,\n useToggleCertificateGeneration,\n} from '@src/certificates/data/apiHook';\nimport { CertificateFilter } from '@src/certificates/types';\nimport { CERTIFICATES_PAGE_SIZE, TAB_KEYS, MODAL_TITLES, ALERT_VARIANTS } from '@src/certificates/constants';\nimport { getErrorMessage } from '@src/certificates/utils/errorHandling';\nimport messages from '@src/certificates/messages';\nimport './CertificatesPage.scss';\n\nconst CertificatesPage = () => {\n const intl = useIntl();\n const { courseId = '' } = useParams<{ courseId: string }>();\n const { showToast, showModal } = useAlert();\n const { data: courseInfo } = useCourseInfo(courseId);\n\n const [filter, setFilter] = useState<CertificateFilter>(CertificateFilter.ALL_LEARNERS);\n const [search, setSearch] = useState('');\n const [certificatesPage, setCertificatesPage] = useState(0);\n const [tasksPage, setTasksPage] = useState(0);\n const [activeTab, setActiveTab] = useState(TAB_KEYS.ISSUED);\n const [selectedUsername, setSelectedUsername] = useState('');\n const [selectedEmail, setSelectedEmail] = useState('');\n const [isCertificateGenerationEnabled, setIsCertificateGenerationEnabled] = useState(true);\n\n const [isGrantExceptionsOpen, setIsGrantExceptionsOpen] = useState(false);\n const [isInvalidateCertificateOpen, setIsInvalidateCertificateOpen] = useState(false);\n const [isRemoveExceptionOpen, setIsRemoveExceptionOpen] = useState(false);\n const [isRemoveInvalidationOpen, setIsRemoveInvalidationOpen] = useState(false);\n const [isDisableCertificatesOpen, setIsDisableCertificatesOpen] = useState(false);\n\n const {\n data: certificatesData,\n isLoading: isLoadingCertificates,\n } = useIssuedCertificates(courseId, {\n page: certificatesPage,\n pageSize: CERTIFICATES_PAGE_SIZE,\n filter,\n search,\n });\n\n const {\n data: historyData,\n isLoading: isLoadingHistory,\n } = useCertificateGenerationHistory(courseId, {\n page: tasksPage,\n pageSize: CERTIFICATES_PAGE_SIZE,\n });\n\n const { mutate: grantExceptions, isPending: isGrantingExceptions } = useGrantBulkExceptions(courseId);\n const { mutate: invalidateCert, isPending: isInvalidating } = useInvalidateCertificate(courseId);\n const { mutate: removeExcept, isPending: isRemovingException } = useRemoveException(courseId);\n const { mutate: removeInval, isPending: isRemovingInvalidation } = useRemoveInvalidation(courseId);\n const { mutate: toggleGeneration, isPending: isTogglingGeneration } = useToggleCertificateGeneration(courseId);\n const { mutate: regenerateCerts } = useRegenerateCertificates(courseId);\n\n const handleGrantExceptions = useCallback((learners: string[], notes: string) => {\n grantExceptions(\n { learners, notes },\n {\n onSuccess: (data) => {\n setIsGrantExceptionsOpen(false);\n if (data.errors && data.errors.length > 0) {\n const errorMessages = data.errors.map(err => `${err.learner}: ${err.message}`).join('\\n');\n showModal({\n title: MODAL_TITLES.ERROR,\n message: `Some exceptions failed:\\n${errorMessages}`,\n variant: ALERT_VARIANTS.WARNING,\n });\n }\n if (data.success && data.success.length > 0) {\n showToast(intl.formatMessage(messages.exceptionsGrantedToast, { count: data.success.length }));\n }\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorGrantException)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [grantExceptions, showToast, showModal, intl]);\n\n const handleInvalidateCertificate = useCallback((learners: string[], notes: string) => {\n invalidateCert(\n { learners, notes },\n {\n onSuccess: (data) => {\n setIsInvalidateCertificateOpen(false);\n if (data.errors && data.errors.length > 0) {\n const errorMessages = data.errors.map(err => `${err.learner}: ${err.message}`).join('\\n');\n showModal({\n title: MODAL_TITLES.ERROR,\n message: `Some invalidations failed:\\n${errorMessages}`,\n variant: ALERT_VARIANTS.WARNING,\n });\n }\n if (data.success && data.success.length > 0) {\n showToast(intl.formatMessage(messages.certificatesInvalidatedToast, { count: data.success.length }));\n }\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorInvalidateCertificate)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [invalidateCert, showToast, showModal, intl]);\n\n const handleRemoveExceptionClick = useCallback((username: string, email: string) => {\n setSelectedUsername(username);\n setSelectedEmail(email);\n setIsRemoveExceptionOpen(true);\n }, []);\n\n const handleRemoveExceptionConfirm = useCallback(() => {\n // Backend accepts either username or email - use whichever is available\n const identifier = selectedUsername || selectedEmail;\n\n if (!identifier) {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: intl.formatMessage(messages.errorRemoveException) + ': Username or email is required',\n variant: ALERT_VARIANTS.DANGER,\n });\n return;\n }\n\n removeExcept(\n { username: identifier },\n {\n onSuccess: () => {\n setIsRemoveExceptionOpen(false);\n setSelectedUsername('');\n setSelectedEmail('');\n showToast(intl.formatMessage(messages.exceptionRemovedToast, { email: selectedEmail }));\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorRemoveException)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [removeExcept, selectedUsername, selectedEmail, showToast, showModal, intl]);\n\n const handleRemoveInvalidationClick = useCallback((username: string, email: string) => {\n setSelectedUsername(username);\n setSelectedEmail(email);\n setIsRemoveInvalidationOpen(true);\n }, []);\n\n const handleRemoveInvalidationConfirm = useCallback(() => {\n // Backend accepts either username or email - use whichever is available\n const identifier = selectedUsername || selectedEmail;\n\n if (!identifier) {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: intl.formatMessage(messages.errorRemoveInvalidation) + ': Username or email is required',\n variant: ALERT_VARIANTS.DANGER,\n });\n return;\n }\n\n removeInval(\n { username: identifier },\n {\n onSuccess: () => {\n setIsRemoveInvalidationOpen(false);\n setSelectedUsername('');\n setSelectedEmail('');\n showToast(intl.formatMessage(messages.invalidationRemovedToast, { email: selectedEmail }));\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorRemoveInvalidation)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n },\n );\n }, [removeInval, selectedUsername, selectedEmail, showToast, showModal, intl]);\n\n const handleToggleCertificateGeneration = useCallback(() => {\n const newState = !isCertificateGenerationEnabled;\n toggleGeneration(newState, {\n onSuccess: () => {\n setIsCertificateGenerationEnabled(newState);\n setIsDisableCertificatesOpen(false);\n showToast(\n newState\n ? intl.formatMessage(messages.successEnableCertificates)\n : intl.formatMessage(messages.successDisableCertificates),\n );\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorToggleCertificateGeneration)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n });\n }, [isCertificateGenerationEnabled, toggleGeneration, showToast, showModal, intl]);\n\n const handleRegenerateCertificates = useCallback(() => {\n regenerateCerts(filter, {\n onSuccess: () => {\n showToast(intl.formatMessage(messages.certificatesRegeneratedToast));\n },\n onError: (error) => {\n showModal({\n title: MODAL_TITLES.ERROR,\n message: getErrorMessage(error, intl.formatMessage(messages.errorRegenerateCertificates)),\n variant: ALERT_VARIANTS.DANGER,\n });\n },\n });\n }, [regenerateCerts, filter, showToast, showModal, intl]);\n\n // Check if certificate management is disabled\n if (courseInfo && !courseInfo.certificatesEnabled) {\n return (\n <Container className=\"mt-4.5 mb-4\" fluid>\n <Alert variant=\"warning\">\n {intl.formatMessage(messages.certificatesDisabledMessage)}\n </Alert>\n </Container>\n );\n }\n\n return (\n <Container className=\"mt-4.5 mb-4\" fluid>\n <CertificatesPageHeader\n onGrantExceptions={() => setIsGrantExceptionsOpen(true)}\n onInvalidateCertificate={() => setIsInvalidateCertificateOpen(true)}\n onDisableCertificates={() => setIsDisableCertificatesOpen(true)}\n />\n\n <Card variant=\"muted\" className=\"pt-3 pt-md-4 pb-4 pb-md-6 certificates-card\">\n <Tabs\n activeKey={activeTab}\n onSelect={(key) => setActiveTab(key || TAB_KEYS.ISSUED)}\n className=\"mx-4\"\n variant=\"button-group\"\n >\n <Tab eventKey={TAB_KEYS.ISSUED} title={intl.formatMessage(messages.issuedCertificatesTab)}>\n <IssuedCertificatesTab\n data={certificatesData?.results || []}\n isLoading={isLoadingCertificates}\n itemCount={certificatesData?.count || 0}\n pageCount={certificatesData?.numPages || 0}\n search={search}\n onSearchChange={setSearch}\n filter={filter}\n onFilterChange={setFilter}\n currentPage={certificatesPage}\n onPageChange={setCertificatesPage}\n onRemoveException={handleRemoveExceptionClick}\n onRemoveInvalidation={handleRemoveInvalidationClick}\n onRegenerateCertificates={handleRegenerateCertificates}\n />\n </Tab>\n <Tab eventKey={TAB_KEYS.HISTORY} title={intl.formatMessage(messages.generationHistoryTab)}>\n <div className=\"d-flex flex-column mt-3 mt-md-4\">\n <GenerationHistoryTable\n data={historyData?.results || []}\n isLoading={isLoadingHistory}\n itemCount={historyData?.count || 0}\n pageCount={historyData?.numPages || 0}\n currentPage={tasksPage}\n onPageChange={setTasksPage}\n />\n </div>\n </Tab>\n </Tabs>\n </Card>\n\n <GrantExceptionsModal\n isOpen={isGrantExceptionsOpen}\n onClose={() => setIsGrantExceptionsOpen(false)}\n onSubmit={handleGrantExceptions}\n isSubmitting={isGrantingExceptions}\n />\n <InvalidateCertificateModal\n isOpen={isInvalidateCertificateOpen}\n onClose={() => setIsInvalidateCertificateOpen(false)}\n onSubmit={handleInvalidateCertificate}\n isSubmitting={isInvalidating}\n />\n <RemoveExceptionModal\n isOpen={isRemoveExceptionOpen}\n email={selectedEmail}\n onClose={() => {\n setIsRemoveExceptionOpen(false);\n setSelectedUsername('');\n setSelectedEmail('');\n }}\n onConfirm={handleRemoveExceptionConfirm}\n isSubmitting={isRemovingException}\n />\n <RemoveInvalidationModal\n isOpen={isRemoveInvalidationOpen}\n email={selectedEmail}\n onClose={() => {\n setIsRemoveInvalidationOpen(false);\n setSelectedUsername('');\n setSelectedEmail('');\n }}\n onConfirm={handleRemoveInvalidationConfirm}\n isSubmitting={isRemovingInvalidation}\n />\n <DisableCertificatesModal\n isOpen={isDisableCertificatesOpen}\n isEnabled={isCertificateGenerationEnabled}\n onClose={() => setIsDisableCertificatesOpen(false)}\n onConfirm={handleToggleCertificateGeneration}\n isSubmitting={isTogglingGeneration}\n />\n </Container>\n );\n};\n\nexport default CertificatesPage;\n"]}
@@ -0,0 +1,90 @@
1
+ .filter-dropdown-item {
2
+ &:hover,
3
+ &.active {
4
+ text-decoration: none;
5
+ color: var(--pgn-color-menu-item-hover-color);
6
+ border-color: var(--pgn-color-menu-item-hover-border);
7
+ background: var(--pgn-color-menu-item-hover-bg);
8
+ }
9
+
10
+ &.active {
11
+ font-weight: 600;
12
+ }
13
+ }
14
+
15
+ .certificates-filter-dropdown,
16
+ .certificate-actions-dropdown {
17
+ position: relative;
18
+ z-index: 1050;
19
+
20
+ .dropdown-menu {
21
+ position: absolute;
22
+ z-index: 9999;
23
+ max-height: 400px;
24
+ overflow-y: auto;
25
+ }
26
+ }
27
+
28
+ .certificate-actions-dropdown {
29
+ position: static;
30
+
31
+ .dropdown-toggle {
32
+ position: relative;
33
+ z-index: 1;
34
+ }
35
+
36
+ .dropdown-menu {
37
+ will-change: transform;
38
+ }
39
+ }
40
+
41
+ .certificates-card {
42
+ position: relative;
43
+ overflow: visible;
44
+ overflow-x: hidden;
45
+
46
+ .card-body,
47
+ .pgn__tabs,
48
+ .tab-content,
49
+ .tab-pane {
50
+ overflow: visible;
51
+ }
52
+ }
53
+
54
+ .certificates-tab-container {
55
+ overflow: visible;
56
+ }
57
+
58
+ .certificates-table-wrapper {
59
+ overflow-x: auto;
60
+ overflow-y: visible;
61
+ position: relative;
62
+ }
63
+
64
+ .certificates-card .pgn__data-table-layout {
65
+ overflow: visible;
66
+
67
+ table,
68
+ tbody,
69
+ tr,
70
+ td {
71
+ position: relative;
72
+ }
73
+ }
74
+
75
+ .certificates-card {
76
+ .pgn__data-table-footer,
77
+ .pgn__data-table-pagination {
78
+ position: relative;
79
+ z-index: 1;
80
+ }
81
+ }
82
+
83
+ .certificates-toolbar-wrapper {
84
+ min-width: 0;
85
+ }
86
+
87
+ .certificates-search-field {
88
+ min-width: 320px;
89
+ max-width: 400px;
90
+ }
@@ -0,0 +1,14 @@
1
+ import type { CertificateData, CertificateFilter } from '../../certificates/types';
2
+ interface CertificateTableProps {
3
+ data: CertificateData[];
4
+ isLoading: boolean;
5
+ itemCount: number;
6
+ pageCount: number;
7
+ currentPage: number;
8
+ filter: CertificateFilter;
9
+ onPageChange: (pageIndex: number) => void;
10
+ onRemoveException: (username: string, email: string) => void;
11
+ onRemoveInvalidation: (username: string, email: string) => void;
12
+ }
13
+ declare const CertificateTable: ({ data, isLoading, itemCount, filter, onRemoveException, onRemoveInvalidation, }: CertificateTableProps) => import("react/jsx-runtime").JSX.Element;
14
+ export default CertificateTable;
@@ -0,0 +1,88 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo } from 'react';
3
+ import { DataTable, IconButton, OverlayTrigger, Popover, TableFooter } from '@openedx/paragon';
4
+ import { MoreVert } from '@openedx/paragon/icons';
5
+ import { useIntl } from '@openedx/frontend-base';
6
+ import { CertificateFilter as FilterEnum } from '../../certificates/types';
7
+ import { CERTIFICATES_TABLE_PAGE_SIZE } from '../../certificates/constants';
8
+ import messages from '../../certificates/messages';
9
+ const CertificateTable = ({ data, isLoading, itemCount, filter, onRemoveException, onRemoveInvalidation, }) => {
10
+ const intl = useIntl();
11
+ const baseColumns = useMemo(() => [
12
+ {
13
+ Header: intl.formatMessage(messages.columnUsername),
14
+ accessor: 'username',
15
+ },
16
+ {
17
+ Header: intl.formatMessage(messages.columnEmail),
18
+ accessor: 'email',
19
+ },
20
+ {
21
+ Header: intl.formatMessage(messages.columnEnrollmentTrack),
22
+ accessor: 'enrollmentTrack',
23
+ },
24
+ {
25
+ Header: intl.formatMessage(messages.columnCertificateStatus),
26
+ accessor: 'certificateStatus',
27
+ },
28
+ {
29
+ Header: intl.formatMessage(messages.columnSpecialCase),
30
+ accessor: 'specialCase',
31
+ },
32
+ ], [intl]);
33
+ const conditionalColumns = useMemo(() => {
34
+ const columns = [];
35
+ if (filter === FilterEnum.ALL_LEARNERS || filter === FilterEnum.GRANTED_EXCEPTIONS) {
36
+ columns.push({
37
+ Header: intl.formatMessage(messages.columnExceptionGranted),
38
+ accessor: 'exceptionGranted',
39
+ }, {
40
+ Header: intl.formatMessage(messages.columnExceptionNotes),
41
+ accessor: 'exceptionNotes',
42
+ });
43
+ }
44
+ if (filter === FilterEnum.ALL_LEARNERS || filter === FilterEnum.INVALIDATED) {
45
+ columns.push({
46
+ Header: intl.formatMessage(messages.columnInvalidatedBy),
47
+ accessor: 'invalidatedBy',
48
+ }, {
49
+ Header: intl.formatMessage(messages.columnInvalidationDate),
50
+ accessor: 'invalidationDate',
51
+ Cell: ({ value }) => {
52
+ if (!value)
53
+ return null;
54
+ return (_jsx(_Fragment, { children: intl.formatDate(new Date(value), {
55
+ year: 'numeric',
56
+ month: '2-digit',
57
+ day: '2-digit',
58
+ hour: '2-digit',
59
+ minute: '2-digit',
60
+ }) }));
61
+ },
62
+ }, {
63
+ Header: intl.formatMessage(messages.columnInvalidationNote),
64
+ accessor: 'invalidationNote',
65
+ });
66
+ }
67
+ return columns;
68
+ }, [filter, intl]);
69
+ const additionalColumns = useMemo(() => {
70
+ if (filter !== FilterEnum.GRANTED_EXCEPTIONS && filter !== FilterEnum.INVALIDATED) {
71
+ return [];
72
+ }
73
+ return [
74
+ {
75
+ id: 'action',
76
+ Header: intl.formatMessage(messages.columnActions),
77
+ Cell: ({ row }) => {
78
+ const popoverContent = (_jsx(Popover, { id: `popover-${row.original.username}`, className: "border-0 shadow-sm", children: _jsx(Popover.Content, { className: "p-0 border-0", children: _jsxs("div", { className: "dropdown-menu show position-static border shadow-sm", children: [filter === FilterEnum.GRANTED_EXCEPTIONS && (_jsx("button", { type: "button", className: "dropdown-item", onClick: () => onRemoveException(row.original.username, row.original.email), children: intl.formatMessage(messages.removeExceptionAction) })), filter === FilterEnum.INVALIDATED && (_jsx("button", { type: "button", className: "dropdown-item", onClick: () => onRemoveInvalidation(row.original.username, row.original.email), children: intl.formatMessage(messages.removeInvalidationAction) }))] }) }) }));
79
+ return (_jsx(OverlayTrigger, { trigger: "click", placement: "bottom-end", overlay: popoverContent, rootClose: true, children: _jsx(IconButton, { alt: intl.formatMessage(messages.columnActions), iconAs: MoreVert }) }));
80
+ },
81
+ },
82
+ ];
83
+ }, [filter, intl, onRemoveException, onRemoveInvalidation]);
84
+ const allColumns = useMemo(() => [...baseColumns, ...conditionalColumns, ...additionalColumns], [baseColumns, conditionalColumns, additionalColumns]);
85
+ return (_jsxs(DataTable, { columns: allColumns, data: data, isLoading: isLoading, isPaginated: true, itemCount: itemCount, initialState: { pageIndex: 0, pageSize: CERTIFICATES_TABLE_PAGE_SIZE }, children: [_jsx(DataTable.Table, {}), _jsx(DataTable.EmptyTable, { content: intl.formatMessage(messages.noDataMessage) }), _jsx(TableFooter, {})] }));
86
+ };
87
+ export default CertificateTable;
88
+ //# sourceMappingURL=CertificateTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CertificateTable.js","sourceRoot":"","sources":["../../../src/certificates/components/CertificateTable.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo } from 'react';\nimport { DataTable, IconButton, OverlayTrigger, Popover, TableFooter } from '@openedx/paragon';\nimport { MoreVert } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport type { CertificateData, CertificateFilter } from '@src/certificates/types';\nimport { CertificateFilter as FilterEnum } from '@src/certificates/types';\nimport { CERTIFICATES_TABLE_PAGE_SIZE } from '@src/certificates/constants';\nimport messages from '@src/certificates/messages';\n\ninterface CertificateTableProps {\n data: CertificateData[],\n isLoading: boolean,\n itemCount: number,\n pageCount: number,\n currentPage: number,\n filter: CertificateFilter,\n onPageChange: (pageIndex: number) => void,\n onRemoveException: (username: string, email: string) => void,\n onRemoveInvalidation: (username: string, email: string) => void,\n}\n\ninterface ColumnType {\n Header: string,\n accessor?: string,\n id?: string,\n Cell?: ({ row, value }: { row?: { original: CertificateData }, value?: string }) => JSX.Element | null,\n}\n\nconst CertificateTable = ({\n data,\n isLoading,\n itemCount,\n filter,\n onRemoveException,\n onRemoveInvalidation,\n}: CertificateTableProps) => {\n const intl = useIntl();\n\n const baseColumns = useMemo(\n () => [\n {\n Header: intl.formatMessage(messages.columnUsername),\n accessor: 'username',\n },\n {\n Header: intl.formatMessage(messages.columnEmail),\n accessor: 'email',\n },\n {\n Header: intl.formatMessage(messages.columnEnrollmentTrack),\n accessor: 'enrollmentTrack',\n },\n {\n Header: intl.formatMessage(messages.columnCertificateStatus),\n accessor: 'certificateStatus',\n },\n {\n Header: intl.formatMessage(messages.columnSpecialCase),\n accessor: 'specialCase',\n },\n ],\n [intl],\n );\n\n const conditionalColumns = useMemo(() => {\n const columns: ColumnType[] = [];\n\n if (filter === FilterEnum.ALL_LEARNERS || filter === FilterEnum.GRANTED_EXCEPTIONS) {\n columns.push(\n {\n Header: intl.formatMessage(messages.columnExceptionGranted),\n accessor: 'exceptionGranted',\n },\n {\n Header: intl.formatMessage(messages.columnExceptionNotes),\n accessor: 'exceptionNotes',\n },\n );\n }\n\n if (filter === FilterEnum.ALL_LEARNERS || filter === FilterEnum.INVALIDATED) {\n columns.push(\n {\n Header: intl.formatMessage(messages.columnInvalidatedBy),\n accessor: 'invalidatedBy',\n },\n {\n Header: intl.formatMessage(messages.columnInvalidationDate),\n accessor: 'invalidationDate',\n Cell: ({ value }: { value?: string }) => {\n if (!value) return null;\n return (\n <>\n {intl.formatDate(new Date(value), {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n })}\n </>\n );\n },\n },\n {\n Header: intl.formatMessage(messages.columnInvalidationNote),\n accessor: 'invalidationNote',\n },\n );\n }\n\n return columns;\n }, [filter, intl]);\n\n const additionalColumns = useMemo(() => {\n if (filter !== FilterEnum.GRANTED_EXCEPTIONS && filter !== FilterEnum.INVALIDATED) {\n return [];\n }\n\n return [\n {\n id: 'action',\n Header: intl.formatMessage(messages.columnActions),\n Cell: ({ row }: { row: { original: CertificateData } }) => {\n const popoverContent = (\n <Popover\n id={`popover-${row.original.username}`}\n className=\"border-0 shadow-sm\"\n >\n <Popover.Content className=\"p-0 border-0\">\n <div className=\"dropdown-menu show position-static border shadow-sm\">\n {filter === FilterEnum.GRANTED_EXCEPTIONS && (\n <button\n type=\"button\"\n className=\"dropdown-item\"\n onClick={() => onRemoveException(row.original.username, row.original.email)}\n >\n {intl.formatMessage(messages.removeExceptionAction)}\n </button>\n )}\n {filter === FilterEnum.INVALIDATED && (\n <button\n type=\"button\"\n className=\"dropdown-item\"\n onClick={() => onRemoveInvalidation(row.original.username, row.original.email)}\n >\n {intl.formatMessage(messages.removeInvalidationAction)}\n </button>\n )}\n </div>\n </Popover.Content>\n </Popover>\n );\n\n return (\n <OverlayTrigger\n trigger=\"click\"\n placement=\"bottom-end\"\n overlay={popoverContent}\n rootClose\n >\n <IconButton\n alt={intl.formatMessage(messages.columnActions)}\n iconAs={MoreVert}\n />\n </OverlayTrigger>\n );\n },\n },\n ];\n }, [filter, intl, onRemoveException, onRemoveInvalidation]);\n\n const allColumns = useMemo(\n () => [...baseColumns, ...conditionalColumns, ...additionalColumns],\n [baseColumns, conditionalColumns, additionalColumns],\n );\n\n return (\n <DataTable\n columns={allColumns}\n data={data}\n isLoading={isLoading}\n isPaginated\n itemCount={itemCount}\n initialState={{ pageIndex: 0, pageSize: CERTIFICATES_TABLE_PAGE_SIZE }}\n >\n <DataTable.Table />\n <DataTable.EmptyTable content={intl.formatMessage(messages.noDataMessage)} />\n <TableFooter />\n </DataTable>\n );\n};\n\nexport default CertificateTable;\n"]}
@@ -0,0 +1,7 @@
1
+ interface CertificatesPageHeaderProps {
2
+ onGrantExceptions: () => void;
3
+ onInvalidateCertificate: () => void;
4
+ onDisableCertificates: () => void;
5
+ }
6
+ declare const CertificatesPageHeader: ({ onGrantExceptions, onInvalidateCertificate, onDisableCertificates, }: CertificatesPageHeaderProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default CertificatesPageHeader;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Dropdown, IconButton, Stack } from '@openedx/paragon';
3
+ import { Add, Close, MoreVert } from '@openedx/paragon/icons';
4
+ import { useIntl } from '@openedx/frontend-base';
5
+ import messages from '../../certificates/messages';
6
+ const CertificatesPageHeader = ({ onGrantExceptions, onInvalidateCertificate, onDisableCertificates, }) => {
7
+ const intl = useIntl();
8
+ return (_jsxs("div", { className: "d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center mb-4 gap-3", children: [_jsx("h3", { className: "text-primary-700 mb-0", children: intl.formatMessage(messages.pageTitle) }), _jsxs(Stack, { direction: "horizontal", gap: 2, className: "flex-wrap", children: [_jsxs(Dropdown, { children: [_jsx(Dropdown.Toggle, { as: IconButton, src: MoreVert, alt: intl.formatMessage(messages.disableCertificatesButton), id: "certificates-more-menu" }), _jsx(Dropdown.Menu, { children: _jsx(Dropdown.Item, { onClick: onDisableCertificates, children: intl.formatMessage(messages.disableCertificatesButton) }) })] }), _jsx(Button, { variant: "outline-primary", iconBefore: Close, onClick: onInvalidateCertificate, className: "text-nowrap", children: intl.formatMessage(messages.invalidateCertificateButton) }), _jsx(Button, { variant: "primary", iconBefore: Add, onClick: onGrantExceptions, className: "text-nowrap", children: intl.formatMessage(messages.grantExceptionsButton) })] })] }));
9
+ };
10
+ export default CertificatesPageHeader;
11
+ //# sourceMappingURL=CertificatesPageHeader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CertificatesPageHeader.js","sourceRoot":"","sources":["../../../src/certificates/components/CertificatesPageHeader.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,QAAQ,MAAM,4BAA4B,CAAC;AAQlD,MAAM,sBAAsB,GAAG,CAAC,EAC9B,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,GACO,EAAE,EAAE;IAChC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,OAAO,CACL,eAAK,SAAS,EAAC,2GAA2G,aACxH,aAAI,SAAS,EAAC,uBAAuB,YAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAM,EACnF,MAAC,KAAK,IAAC,SAAS,EAAC,YAAY,EAAC,GAAG,EAAE,CAAC,EAAE,SAAS,EAAC,WAAW,aACzD,MAAC,QAAQ,eACP,KAAC,QAAQ,CAAC,MAAM,IACd,EAAE,EAAE,UAAU,EACd,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAC3D,EAAE,EAAC,wBAAwB,GAC3B,EACF,KAAC,QAAQ,CAAC,IAAI,cACZ,KAAC,QAAQ,CAAC,IAAI,IAAC,OAAO,EAAE,qBAAqB,YAC1C,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,yBAAyB,CAAC,GACzC,GACF,IACP,EACX,KAAC,MAAM,IACL,OAAO,EAAC,iBAAiB,EACzB,UAAU,EAAE,KAAK,EACjB,OAAO,EAAE,uBAAuB,EAChC,SAAS,EAAC,aAAa,YAEtB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,GAClD,EACT,KAAC,MAAM,IACL,OAAO,EAAC,SAAS,EACjB,UAAU,EAAE,GAAG,EACf,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAC,aAAa,YAEtB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAC5C,IACH,IACJ,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,sBAAsB,CAAC","sourcesContent":["import { Button, Dropdown, IconButton, Stack } from '@openedx/paragon';\nimport { Add, Close, MoreVert } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport messages from '@src/certificates/messages';\n\ninterface CertificatesPageHeaderProps {\n onGrantExceptions: () => void,\n onInvalidateCertificate: () => void,\n onDisableCertificates: () => void,\n}\n\nconst CertificatesPageHeader = ({\n onGrantExceptions,\n onInvalidateCertificate,\n onDisableCertificates,\n}: CertificatesPageHeaderProps) => {\n const intl = useIntl();\n\n return (\n <div className=\"d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center mb-4 gap-3\">\n <h3 className=\"text-primary-700 mb-0\">{intl.formatMessage(messages.pageTitle)}</h3>\n <Stack direction=\"horizontal\" gap={2} className=\"flex-wrap\">\n <Dropdown>\n <Dropdown.Toggle\n as={IconButton}\n src={MoreVert}\n alt={intl.formatMessage(messages.disableCertificatesButton)}\n id=\"certificates-more-menu\"\n />\n <Dropdown.Menu>\n <Dropdown.Item onClick={onDisableCertificates}>\n {intl.formatMessage(messages.disableCertificatesButton)}\n </Dropdown.Item>\n </Dropdown.Menu>\n </Dropdown>\n <Button\n variant=\"outline-primary\"\n iconBefore={Close}\n onClick={onInvalidateCertificate}\n className=\"text-nowrap\"\n >\n {intl.formatMessage(messages.invalidateCertificateButton)}\n </Button>\n <Button\n variant=\"primary\"\n iconBefore={Add}\n onClick={onGrantExceptions}\n className=\"text-nowrap\"\n >\n {intl.formatMessage(messages.grantExceptionsButton)}\n </Button>\n </Stack>\n </div>\n );\n};\n\nexport default CertificatesPageHeader;\n"]}
@@ -0,0 +1,11 @@
1
+ import { CertificateFilter } from '../../certificates/types';
2
+ import '../CertificatesPage.scss';
3
+ interface CertificatesToolbarProps {
4
+ search: string;
5
+ onSearchChange: (value: string) => void;
6
+ filter: CertificateFilter;
7
+ onFilterChange: (value: CertificateFilter) => void;
8
+ onRegenerateCertificates: () => void;
9
+ }
10
+ declare const CertificatesToolbar: ({ search, onSearchChange, filter, onFilterChange, onRegenerateCertificates, }: CertificatesToolbarProps) => import("react/jsx-runtime").JSX.Element;
11
+ export default CertificatesToolbar;