@openedx/frontend-app-instructor-dashboard 1.0.0-alpha.2 → 1.0.0-alpha.20

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 (261) 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 +2 -11
  5. package/dist/app.js.map +1 -1
  6. package/dist/certificates/CertificatesPage.d.ts +1 -0
  7. package/dist/certificates/CertificatesPage.js +162 -2
  8. package/dist/certificates/CertificatesPage.js.map +1 -1
  9. package/dist/certificates/CertificatesPage.scss +81 -0
  10. package/dist/certificates/components/CertificateTable.d.ts +14 -0
  11. package/dist/certificates/components/CertificateTable.js +85 -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 +10 -0
  17. package/dist/certificates/components/CertificatesToolbar.js +12 -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 +40 -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 +22 -0
  39. package/dist/certificates/components/LearnerActionModal.js.map +1 -0
  40. package/dist/certificates/components/RemoveInvalidationModal.d.ts +9 -0
  41. package/dist/certificates/components/RemoveInvalidationModal.js +10 -0
  42. package/dist/certificates/components/RemoveInvalidationModal.js.map +1 -0
  43. package/dist/certificates/constants.d.ts +15 -0
  44. package/dist/certificates/constants.js +16 -0
  45. package/dist/certificates/constants.js.map +1 -0
  46. package/dist/certificates/data/api.d.ts +9 -0
  47. package/dist/certificates/data/api.js +63 -0
  48. package/dist/certificates/data/api.js.map +1 -0
  49. package/dist/certificates/data/apiHook.d.ts +30 -0
  50. package/dist/certificates/data/apiHook.js +90 -0
  51. package/dist/certificates/data/apiHook.js.map +1 -0
  52. package/dist/certificates/data/dummyData.d.ts +2 -0
  53. package/dist/certificates/data/dummyData.js +234 -0
  54. package/dist/certificates/data/dummyData.js.map +1 -0
  55. package/dist/certificates/data/queryKeys.d.ts +8 -0
  56. package/dist/certificates/data/queryKeys.js +8 -0
  57. package/dist/certificates/data/queryKeys.js.map +1 -0
  58. package/dist/certificates/messages.d.ts +313 -0
  59. package/dist/certificates/messages.js +315 -0
  60. package/dist/certificates/messages.js.map +1 -0
  61. package/dist/certificates/types.d.ts +61 -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/cohorts/data/queryKeys.d.ts +4 -4
  74. package/dist/components/ActionCard.d.ts +2 -2
  75. package/dist/components/ActionCard.js +1 -1
  76. package/dist/components/ActionCard.js.map +1 -1
  77. package/dist/components/PendingTasks.d.ts +3 -1
  78. package/dist/components/PendingTasks.js +3 -2
  79. package/dist/components/PendingTasks.js.map +1 -1
  80. package/dist/components/SpecifyLearnerField.d.ts +4 -1
  81. package/dist/components/SpecifyLearnerField.js +24 -10
  82. package/dist/components/SpecifyLearnerField.js.map +1 -1
  83. package/dist/components/SpecifyProblemField.d.ts +13 -0
  84. package/dist/components/SpecifyProblemField.js +46 -0
  85. package/dist/components/SpecifyProblemField.js.map +1 -0
  86. package/dist/components/UsernameFilter.d.ts +7 -0
  87. package/dist/components/UsernameFilter.js +19 -0
  88. package/dist/components/UsernameFilter.js.map +1 -0
  89. package/dist/components/messages.d.ts +30 -0
  90. package/dist/components/messages.js +30 -0
  91. package/dist/components/messages.js.map +1 -1
  92. package/dist/constants.d.ts +2 -1
  93. package/dist/constants.js +2 -1
  94. package/dist/constants.js.map +1 -1
  95. package/dist/courseInfo/types.d.ts +2 -0
  96. package/dist/courseInfo/types.js.map +1 -1
  97. package/dist/courseTeam/CourseTeamPage.js +20 -2
  98. package/dist/courseTeam/CourseTeamPage.js.map +1 -1
  99. package/dist/courseTeam/components/AddTeamMemberModal.d.ts +6 -0
  100. package/dist/courseTeam/components/AddTeamMemberModal.js +60 -0
  101. package/dist/courseTeam/components/AddTeamMemberModal.js.map +1 -0
  102. package/dist/courseTeam/components/EditTeamMemberModal.d.ts +8 -0
  103. package/dist/courseTeam/components/EditTeamMemberModal.js +90 -0
  104. package/dist/courseTeam/components/EditTeamMemberModal.js.map +1 -0
  105. package/dist/courseTeam/components/MembersContent.d.ts +6 -0
  106. package/dist/courseTeam/components/MembersContent.js +48 -0
  107. package/dist/courseTeam/components/MembersContent.js.map +1 -0
  108. package/dist/courseTeam/components/RoleFilter.d.ts +7 -0
  109. package/dist/courseTeam/components/RoleFilter.js +22 -0
  110. package/dist/courseTeam/components/RoleFilter.js.map +1 -0
  111. package/dist/courseTeam/components/RolesContent.d.ts +3 -0
  112. package/dist/courseTeam/components/RolesContent.js +25 -0
  113. package/dist/courseTeam/components/RolesContent.js.map +1 -0
  114. package/dist/courseTeam/data/api.d.ts +6 -0
  115. package/dist/courseTeam/data/api.js +38 -0
  116. package/dist/courseTeam/data/api.js.map +1 -0
  117. package/dist/courseTeam/data/apiHook.d.ts +11 -0
  118. package/dist/courseTeam/data/apiHook.js +32 -0
  119. package/dist/courseTeam/data/apiHook.js.map +1 -0
  120. package/dist/courseTeam/data/queryKeys.d.ts +7 -0
  121. package/dist/courseTeam/data/queryKeys.js +14 -0
  122. package/dist/courseTeam/data/queryKeys.js.map +1 -0
  123. package/dist/courseTeam/messages.d.ts +243 -0
  124. package/dist/courseTeam/messages.js +245 -0
  125. package/dist/courseTeam/messages.js.map +1 -0
  126. package/dist/courseTeam/types.d.ts +22 -0
  127. package/dist/courseTeam/types.js +3 -0
  128. package/dist/courseTeam/types.js.map +1 -0
  129. package/dist/data/api.d.ts +2 -1
  130. package/dist/data/api.js +9 -3
  131. package/dist/data/api.js.map +1 -1
  132. package/dist/data/apiHook.d.ts +1 -0
  133. package/dist/data/apiHook.js +10 -2
  134. package/dist/data/apiHook.js.map +1 -1
  135. package/dist/data/queryKeys.d.ts +10 -6
  136. package/dist/data/queryKeys.js +4 -0
  137. package/dist/data/queryKeys.js.map +1 -1
  138. package/dist/dataDownloads/data/queryKeys.d.ts +3 -3
  139. package/dist/dateExtensions/components/AddExtensionModal.d.ts +1 -1
  140. package/dist/dateExtensions/components/AddExtensionModal.js +5 -6
  141. package/dist/dateExtensions/components/AddExtensionModal.js.map +1 -1
  142. package/dist/dateExtensions/components/DateExtensionsList.js +2 -13
  143. package/dist/dateExtensions/components/DateExtensionsList.js.map +1 -1
  144. package/dist/dateExtensions/data/apiHook.d.ts +2 -2
  145. package/dist/dateExtensions/data/apiHook.js +4 -4
  146. package/dist/dateExtensions/data/apiHook.js.map +1 -1
  147. package/dist/dateExtensions/data/queryKeys.d.ts +5 -5
  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 +32 -5
  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 +61 -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 +5 -5
  177. package/dist/enrollments/data/queryKeys.js.map +1 -1
  178. package/dist/enrollments/messages.d.ts +121 -1
  179. package/dist/enrollments/messages.js +126 -6
  180. package/dist/enrollments/messages.js.map +1 -1
  181. package/dist/enrollments/types.d.ts +24 -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 +14 -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/index.d.ts +2 -3
  213. package/dist/index.js +2 -3
  214. package/dist/index.js.map +1 -1
  215. package/dist/instructorNav/InstructorNav.js +1 -1
  216. package/dist/instructorNav/InstructorNav.js.map +1 -1
  217. package/dist/provides.d.ts +4 -0
  218. package/dist/provides.js +7 -0
  219. package/dist/provides.js.map +1 -0
  220. package/dist/routes.d.ts +1 -1
  221. package/dist/routes.js +5 -4
  222. package/dist/routes.js.map +1 -1
  223. package/dist/specialExams/SpecialExamsPage.js +10 -2
  224. package/dist/specialExams/SpecialExamsPage.js.map +1 -1
  225. package/dist/specialExams/components/Allowances.d.ts +2 -0
  226. package/dist/specialExams/components/Allowances.js +6 -0
  227. package/dist/specialExams/components/Allowances.js.map +1 -0
  228. package/dist/specialExams/components/AttemptsList.d.ts +3 -0
  229. package/dist/specialExams/components/AttemptsList.js +44 -0
  230. package/dist/specialExams/components/AttemptsList.js.map +1 -0
  231. package/dist/specialExams/data/api.d.ts +3 -0
  232. package/dist/specialExams/data/api.js +23 -0
  233. package/dist/specialExams/data/api.js.map +1 -0
  234. package/dist/specialExams/data/apiHook.d.ts +2 -0
  235. package/dist/specialExams/data/apiHook.js +9 -0
  236. package/dist/specialExams/data/apiHook.js.map +1 -0
  237. package/dist/specialExams/data/queryKeys.d.ts +5 -0
  238. package/dist/specialExams/data/queryKeys.js +6 -0
  239. package/dist/specialExams/data/queryKeys.js.map +1 -0
  240. package/dist/specialExams/messages.d.ts +58 -0
  241. package/dist/specialExams/messages.js +60 -0
  242. package/dist/specialExams/messages.js.map +1 -0
  243. package/dist/specialExams/types.d.ts +13 -0
  244. package/dist/specialExams/types.js +2 -0
  245. package/dist/specialExams/types.js.map +1 -0
  246. package/dist/style.scss +16 -0
  247. package/dist/testUtils.js +1 -1
  248. package/dist/testUtils.js.map +1 -1
  249. package/dist/types/index.d.ts +1 -0
  250. package/dist/types/index.js.map +1 -1
  251. package/dist/utils/formatters.d.ts +5 -0
  252. package/dist/utils/formatters.js +10 -0
  253. package/dist/utils/formatters.js.map +1 -1
  254. package/package.json +2 -5
  255. package/dist/app.scss +0 -10
  256. package/dist/providers/QueryProvider.d.ts +0 -6
  257. package/dist/providers/QueryProvider.js +0 -16
  258. package/dist/providers/QueryProvider.js.map +0 -1
  259. package/dist/providers.d.ts +0 -3
  260. package/dist/providers.js +0 -8
  261. package/dist/providers.js.map +0 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,QAAQ,CAAC","sourcesContent":["export { default as instructApp } from './app';\nexport { default as instructRoutes } from './routes';\nexport { default as instructMessages } from './i18n';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,UAAU,CAAC","sourcesContent":["export { default as instructorDashboardApp } from './app';\nexport { default as instructorDashboardRoutes } from './routes';\n"]}
@@ -8,7 +8,7 @@ import { useWidgetProps } from '../slots/SlotUtils';
8
8
  const InstructorNav = () => {
9
9
  const { courseId = '', tabId = '' } = useParams();
10
10
  const { data: courseInfo, isLoading } = useCourseInfo(courseId);
11
- const widgetPropsArray = useWidgetProps('org.openedx.frontend.slot.instructor.tabs.v1');
11
+ const widgetPropsArray = useWidgetProps('org.openedx.frontend.slot.instructorDashboard.tabs.v1');
12
12
  const { clearAlerts } = useAlert();
13
13
  const sortedTabs = useMemo(() => {
14
14
  var _a;
@@ -1 +1 @@
1
- {"version":3,"file":"InstructorNav.js","sourceRoot":"","sources":["../../src/instructorNav/InstructorNav.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo } from 'react';\nimport { useParams, Link } from 'react-router-dom';\nimport { Nav, Navbar, Skeleton } from '@openedx/paragon';\nimport { useCourseInfo } from '@src/data/apiHook';\nimport { useAlert } from '@src/providers/AlertProvider';\nimport { useWidgetProps } from '../slots/SlotUtils';\n\nexport interface TabProps {\n tabId: string,\n url: string,\n title: string,\n sortOrder: number,\n}\n\nconst InstructorNav = () => {\n const { courseId = '', tabId = '' } = useParams<{ courseId: string, tabId?: string }>();\n const { data: courseInfo, isLoading } = useCourseInfo(courseId);\n const widgetPropsArray = useWidgetProps('org.openedx.frontend.slot.instructor.tabs.v1') as TabProps[];\n const { clearAlerts } = useAlert();\n\n const sortedTabs = useMemo(() => {\n if (isLoading) return [];\n const apiTabs: TabProps[] = courseInfo?.tabs ?? [];\n const tabMap = new Map<string, TabProps>();\n\n // Adding tabs from API and from slot into a map to avoid duplicates\n apiTabs.forEach(tab => {\n tabMap.set(tab.tabId, tab);\n });\n\n widgetPropsArray.forEach(slotTab => {\n // If the slotTab doesn't have a tabId or title, we can't render it properly, so we skip it.\n if (!slotTab.tabId || !slotTab.title) {\n return;\n }\n\n tabMap.set(slotTab.tabId, slotTab);\n });\n\n const allTabs = Array.from(tabMap.values());\n\n // Tabs are sorted by sortOrder, with a fallback to 1000 to be placed at the end for tabs that don't have sortOrder defined (to avoid NaN issues)\n return allTabs.sort((a, b) => (a.sortOrder ?? 1000) - (b.sortOrder ?? 1000));\n }, [courseInfo?.tabs, isLoading, widgetPropsArray]);\n\n if (isLoading) {\n return <Skeleton className=\"lead\" />;\n }\n\n if (sortedTabs.length === 0) return null;\n\n return (\n <Navbar expand=\"md\" className=\"py-0\">\n <Nav\n variant=\"tabs\"\n activeKey={tabId}\n >\n <Navbar.Toggle aria-controls=\"instructor-nav\" />\n <Navbar.Collapse id=\"instructor-nav\">\n {\n sortedTabs.map((tab) => (\n <Nav.Item key={tab.tabId}>\n <Nav.Link\n as={Link}\n to={tab.url}\n active={tab.tabId === tabId}\n onClick={() => clearAlerts()}\n >\n {tab.title}\n </Nav.Link>\n </Nav.Item>\n ))\n }\n </Navbar.Collapse>\n </Nav>\n </Navbar>\n );\n};\n\nexport default InstructorNav;\n"]}
1
+ {"version":3,"file":"InstructorNav.js","sourceRoot":"","sources":["../../src/instructorNav/InstructorNav.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo } from 'react';\nimport { useParams, Link } from 'react-router-dom';\nimport { Nav, Navbar, Skeleton } from '@openedx/paragon';\nimport { useCourseInfo } from '@src/data/apiHook';\nimport { useAlert } from '@src/providers/AlertProvider';\nimport { useWidgetProps } from '../slots/SlotUtils';\n\nexport interface TabProps {\n tabId: string,\n url: string,\n title: string,\n sortOrder: number,\n}\n\nconst InstructorNav = () => {\n const { courseId = '', tabId = '' } = useParams<{ courseId: string, tabId?: string }>();\n const { data: courseInfo, isLoading } = useCourseInfo(courseId);\n const widgetPropsArray = useWidgetProps('org.openedx.frontend.slot.instructorDashboard.tabs.v1') as TabProps[];\n const { clearAlerts } = useAlert();\n\n const sortedTabs = useMemo(() => {\n if (isLoading) return [];\n const apiTabs: TabProps[] = courseInfo?.tabs ?? [];\n const tabMap = new Map<string, TabProps>();\n\n // Adding tabs from API and from slot into a map to avoid duplicates\n apiTabs.forEach(tab => {\n tabMap.set(tab.tabId, tab);\n });\n\n widgetPropsArray.forEach(slotTab => {\n // If the slotTab doesn't have a tabId or title, we can't render it properly, so we skip it.\n if (!slotTab.tabId || !slotTab.title) {\n return;\n }\n\n tabMap.set(slotTab.tabId, slotTab);\n });\n\n const allTabs = Array.from(tabMap.values());\n\n // Tabs are sorted by sortOrder, with a fallback to 1000 to be placed at the end for tabs that don't have sortOrder defined (to avoid NaN issues)\n return allTabs.sort((a, b) => (a.sortOrder ?? 1000) - (b.sortOrder ?? 1000));\n }, [courseInfo?.tabs, isLoading, widgetPropsArray]);\n\n if (isLoading) {\n return <Skeleton className=\"lead\" />;\n }\n\n if (sortedTabs.length === 0) return null;\n\n return (\n <Navbar expand=\"md\" className=\"py-0\">\n <Nav\n variant=\"tabs\"\n activeKey={tabId}\n >\n <Navbar.Toggle aria-controls=\"instructor-nav\" />\n <Navbar.Collapse id=\"instructor-nav\">\n {\n sortedTabs.map((tab) => (\n <Nav.Item key={tab.tabId}>\n <Nav.Link\n as={Link}\n to={tab.url}\n active={tab.tabId === tabId}\n onClick={() => clearAlerts()}\n >\n {tab.title}\n </Nav.Link>\n </Nav.Item>\n ))\n }\n </Navbar.Collapse>\n </Nav>\n </Navbar>\n );\n};\n\nexport default InstructorNav;\n"]}
@@ -0,0 +1,4 @@
1
+ declare const provides: {
2
+ "org.openedx.frontend.provides.courseNavigationRoles.v1": string;
3
+ };
4
+ export default provides;
@@ -0,0 +1,7 @@
1
+ import { providesCourseNavigationRolesId } from '@openedx/frontend-base';
2
+ import { instructorDashboardRole } from './constants';
3
+ const provides = {
4
+ [providesCourseNavigationRolesId]: instructorDashboardRole
5
+ };
6
+ export default provides;
7
+ //# sourceMappingURL=provides.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provides.js","sourceRoot":"","sources":["../src/provides.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,QAAQ,GAAG;IACf,CAAC,+BAA+B,CAAC,EAAE,uBAAuB;CAC3D,CAAC;AAEF,eAAe,QAAQ,CAAC","sourcesContent":["import { providesCourseNavigationRolesId } from '@openedx/frontend-base';\nimport { instructorDashboardRole } from './constants';\n\nconst provides = {\n [providesCourseNavigationRolesId]: instructorDashboardRole\n};\n\nexport default provides;\n"]}
package/dist/routes.d.ts CHANGED
@@ -2,7 +2,7 @@ declare const routes: {
2
2
  id: string;
3
3
  path: string;
4
4
  handle: {
5
- role: string;
5
+ roles: string[];
6
6
  };
7
7
  lazy(): Promise<{
8
8
  Component: () => import("react/jsx-runtime").JSX.Element;
package/dist/routes.js CHANGED
@@ -21,6 +21,7 @@ import OpenResponsesPage from './openResponses/OpenResponsesPage';
21
21
  import SpecialExamsPage from './specialExams/SpecialExamsPage';
22
22
  import PageNotFound from './components/PageNotFound';
23
23
  import { useWidgetProps } from './slots/SlotUtils';
24
+ import { instructorDashboardRole } from './constants';
24
25
  const defaultTabs = [
25
26
  { tabId: 'course_info', content: _jsx(CourseInfoPage, {}) },
26
27
  { tabId: 'enrollments', content: _jsx(EnrollmentsPage, {}) },
@@ -35,7 +36,7 @@ const defaultTabs = [
35
36
  ];
36
37
  const TabContent = () => {
37
38
  const { tabId } = useParams();
38
- const routeWidgets = useWidgetProps('org.openedx.frontend.slot.instructor.routes.v1');
39
+ const routeWidgets = useWidgetProps('org.openedx.frontend.slot.instructorDashboard.routes.v1');
39
40
  const tabRoutes = [
40
41
  ...defaultTabs.filter(defaultTab => !routeWidgets.some(slotTab => slotTab.tabId === defaultTab.tabId)),
41
42
  ...routeWidgets
@@ -45,14 +46,14 @@ const TabContent = () => {
45
46
  };
46
47
  const routes = [
47
48
  {
48
- id: 'org.openedx.frontend.route.instructor.main',
49
+ id: 'org.openedx.frontend.route.instructorDashboard.main',
49
50
  path: 'instructor-dashboard/:courseId',
50
51
  handle: {
51
- role: 'org.openedx.frontend.role.instructor'
52
+ roles: [instructorDashboardRole]
52
53
  },
53
54
  lazy() {
54
55
  return __awaiter(this, void 0, void 0, function* () {
55
- const module = yield import('./Main');
56
+ const module = yield import(/* webpackChunkName: "instructor-dashboard-main" */ './Main');
56
57
  return { Component: module.default };
57
58
  });
58
59
  },
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useParams, Navigate } from 'react-router-dom';\nimport CohortsPage from '@src/cohorts/CohortsPage';\nimport CourseInfoPage from '@src/courseInfo/CourseInfoPage';\nimport CertificatesPage from '@src/certificates/CertificatesPage';\nimport CourseTeamPage from '@src/courseTeam/CourseTeamPage';\nimport DataDownloadsPage from '@src/dataDownloads/DataDownloadsPage';\nimport DateExtensionsPage from '@src/dateExtensions/DateExtensionsPage';\nimport EnrollmentsPage from '@src/enrollments/EnrollmentsPage';\nimport GradingPage from '@src/grading/GradingPage';\nimport OpenResponsesPage from '@src/openResponses/OpenResponsesPage';\nimport SpecialExamsPage from '@src/specialExams/SpecialExamsPage';\nimport PageNotFound from '@src/components/PageNotFound';\nimport { useWidgetProps } from './slots/SlotUtils';\n\ninterface InstructorRouteProps {\n tabId: string,\n content: React.ReactNode,\n}\n\nconst defaultTabs: InstructorRouteProps[] = [\n { tabId: 'course_info', content: <CourseInfoPage /> },\n { tabId: 'enrollments', content: <EnrollmentsPage /> },\n { tabId: 'course_team', content: <CourseTeamPage /> },\n { tabId: 'cohorts', content: <CohortsPage /> },\n { tabId: 'date_extensions', content: <DateExtensionsPage /> },\n { tabId: 'grading', content: <GradingPage /> },\n { tabId: 'data_downloads', content: <DataDownloadsPage /> },\n { tabId: 'special_exams', content: <SpecialExamsPage /> },\n { tabId: 'certificates', content: <CertificatesPage /> },\n { tabId: 'open_responses', content: <OpenResponsesPage /> },\n];\n\nconst TabContent = () => {\n const { tabId } = useParams<{ tabId: string }>();\n const routeWidgets = useWidgetProps('org.openedx.frontend.slot.instructor.routes.v1') as InstructorRouteProps[];\n\n const tabRoutes = [\n ...defaultTabs.filter(\n defaultTab => !routeWidgets.some(slotTab => slotTab.tabId === defaultTab.tabId)\n ),\n ...routeWidgets\n ];\n\n const foundTab = tabRoutes.find(tab => tab.tabId === tabId);\n\n return foundTab ? foundTab.content : <PageNotFound />;\n};\n\nconst routes = [\n {\n id: 'org.openedx.frontend.route.instructor.main',\n path: 'instructor-dashboard/:courseId',\n handle: {\n role: 'org.openedx.frontend.role.instructor'\n },\n async lazy() {\n const module = await import('./Main');\n return { Component: module.default };\n },\n children: [\n {\n index: true,\n element: <Navigate to=\"course_info\" replace />\n },\n {\n path: ':tabId',\n element: <TabContent />\n },\n ]\n }\n];\n\nexport default routes;\n"]}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useParams, Navigate } from 'react-router-dom';\nimport CohortsPage from '@src/cohorts/CohortsPage';\nimport CourseInfoPage from '@src/courseInfo/CourseInfoPage';\nimport CertificatesPage from '@src/certificates/CertificatesPage';\nimport CourseTeamPage from '@src/courseTeam/CourseTeamPage';\nimport DataDownloadsPage from '@src/dataDownloads/DataDownloadsPage';\nimport DateExtensionsPage from '@src/dateExtensions/DateExtensionsPage';\nimport EnrollmentsPage from '@src/enrollments/EnrollmentsPage';\nimport GradingPage from '@src/grading/GradingPage';\nimport OpenResponsesPage from '@src/openResponses/OpenResponsesPage';\nimport SpecialExamsPage from '@src/specialExams/SpecialExamsPage';\nimport PageNotFound from '@src/components/PageNotFound';\nimport { useWidgetProps } from './slots/SlotUtils';\nimport { instructorDashboardRole } from './constants';\n\ninterface InstructorRouteProps {\n tabId: string,\n content: React.ReactNode,\n}\n\nconst defaultTabs: InstructorRouteProps[] = [\n { tabId: 'course_info', content: <CourseInfoPage /> },\n { tabId: 'enrollments', content: <EnrollmentsPage /> },\n { tabId: 'course_team', content: <CourseTeamPage /> },\n { tabId: 'cohorts', content: <CohortsPage /> },\n { tabId: 'date_extensions', content: <DateExtensionsPage /> },\n { tabId: 'grading', content: <GradingPage /> },\n { tabId: 'data_downloads', content: <DataDownloadsPage /> },\n { tabId: 'special_exams', content: <SpecialExamsPage /> },\n { tabId: 'certificates', content: <CertificatesPage /> },\n { tabId: 'open_responses', content: <OpenResponsesPage /> },\n];\n\nconst TabContent = () => {\n const { tabId } = useParams<{ tabId: string }>();\n const routeWidgets = useWidgetProps('org.openedx.frontend.slot.instructorDashboard.routes.v1') as InstructorRouteProps[];\n\n const tabRoutes = [\n ...defaultTabs.filter(\n defaultTab => !routeWidgets.some(slotTab => slotTab.tabId === defaultTab.tabId)\n ),\n ...routeWidgets\n ];\n\n const foundTab = tabRoutes.find(tab => tab.tabId === tabId);\n\n return foundTab ? foundTab.content : <PageNotFound />;\n};\n\nconst routes = [\n {\n id: 'org.openedx.frontend.route.instructorDashboard.main',\n path: 'instructor-dashboard/:courseId',\n handle: {\n roles: [instructorDashboardRole]\n },\n async lazy() {\n const module = await import(/* webpackChunkName: \"instructor-dashboard-main\" */ './Main');\n return { Component: module.default };\n },\n children: [\n {\n index: true,\n element: <Navigate to=\"course_info\" replace />\n },\n {\n path: ':tabId',\n element: <TabContent />\n },\n ]\n }\n];\n\nexport default routes;\n"]}
@@ -1,6 +1,14 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { useIntl } from '@openedx/frontend-base';
4
+ import { Button, ButtonGroup, Card } from '@openedx/paragon';
5
+ import messages from './messages';
6
+ import Allowances from './components/Allowances';
7
+ import AttemptsList from './components/AttemptsList';
2
8
  const SpecialExamsPage = () => {
3
- return (_jsx("div", { children: _jsx("h3", { children: "Special Exams" }) }));
9
+ const intl = useIntl();
10
+ const [selectedTab, setSelectedTab] = useState('attempts');
11
+ return (_jsxs(_Fragment, { children: [_jsx("h3", { className: "text-primary-700", children: intl.formatMessage(messages.specialExamsTitle) }), _jsxs(Card, { className: "bg-light-200 mt-4.5", children: [_jsxs(ButtonGroup, { className: "d-block mx-4 mt-4", children: [_jsx(Button, { variant: selectedTab === 'attempts' ? 'primary' : 'outline-primary', onClick: () => setSelectedTab('attempts'), children: intl.formatMessage(messages.examAttempts) }), _jsx(Button, { variant: selectedTab === 'allowances' ? 'primary' : 'outline-primary', onClick: () => setSelectedTab('allowances'), children: intl.formatMessage(messages.allowances) })] }), selectedTab === 'attempts' ? _jsx(AttemptsList, {}) : _jsx(Allowances, {})] })] }));
4
12
  };
5
13
  export default SpecialExamsPage;
6
14
  //# sourceMappingURL=SpecialExamsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SpecialExamsPage.js","sourceRoot":"","sources":["../../src/specialExams/SpecialExamsPage.tsx"],"names":[],"mappings":";AAAA,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,OAAO,CACL,wBACE,yCAAsB,GAClB,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["const SpecialExamsPage = () => {\n return (\n <div>\n <h3>Special Exams</h3>\n </div>\n );\n};\n\nexport default SpecialExamsPage;\n"]}
1
+ {"version":3,"file":"SpecialExamsPage.js","sourceRoot":"","sources":["../../src/specialExams/SpecialExamsPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,UAAU,MAAM,yBAAyB,CAAC;AACjD,OAAO,YAAY,MAAM,2BAA2B,CAAC;AAErD,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAA4B,UAAU,CAAC,CAAC;IAEtF,OAAO,CACL,8BACE,aAAI,SAAS,EAAC,kBAAkB,YAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,GAAM,EACtF,MAAC,IAAI,IAAC,SAAS,EAAC,qBAAqB,aACnC,MAAC,WAAW,IAAC,SAAS,EAAC,mBAAmB,aACxC,KAAC,MAAM,IAAC,OAAO,EAAE,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC,YAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAU,EAC5K,KAAC,MAAM,IAAC,OAAO,EAAE,WAAW,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,YAAY,CAAC,YAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAU,IAClK,EAEZ,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,KAAC,YAAY,KAAG,CAAC,CAAC,CAAC,KAAC,UAAU,KAAG,IAE3D,IACN,CACJ,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["import { useState } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Button, ButtonGroup, Card } from '@openedx/paragon';\nimport messages from './messages';\nimport Allowances from './components/Allowances';\nimport AttemptsList from './components/AttemptsList';\n\nconst SpecialExamsPage = () => {\n const intl = useIntl();\n const [selectedTab, setSelectedTab] = useState<'attempts' | 'allowances'>('attempts');\n\n return (\n <>\n <h3 className=\"text-primary-700\">{intl.formatMessage(messages.specialExamsTitle)}</h3>\n <Card className=\"bg-light-200 mt-4.5\">\n <ButtonGroup className=\"d-block mx-4 mt-4\">\n <Button variant={selectedTab === 'attempts' ? 'primary' : 'outline-primary'} onClick={() => setSelectedTab('attempts')}>{intl.formatMessage(messages.examAttempts)}</Button>\n <Button variant={selectedTab === 'allowances' ? 'primary' : 'outline-primary'} onClick={() => setSelectedTab('allowances')}>{intl.formatMessage(messages.allowances)}</Button>\n </ButtonGroup>\n {\n selectedTab === 'attempts' ? <AttemptsList /> : <Allowances />\n }\n </Card>\n </>\n );\n};\n\nexport default SpecialExamsPage;\n"]}
@@ -0,0 +1,2 @@
1
+ declare const Allowances: () => import("react/jsx-runtime").JSX.Element;
2
+ export default Allowances;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ const Allowances = () => {
3
+ return _jsx("div", { children: "Allowances" });
4
+ };
5
+ export default Allowances;
6
+ //# sourceMappingURL=Allowances.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Allowances.js","sourceRoot":"","sources":["../../../src/specialExams/components/Allowances.tsx"],"names":[],"mappings":";AAAA,MAAM,UAAU,GAAG,GAAG,EAAE;IACtB,OAAO,uCAAqB,CAAC;AAC/B,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["const Allowances = () => {\n return <div>Allowances</div>;\n};\n\nexport default Allowances;\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const ATTEMPTS_PAGE_SIZE = 25;
2
+ declare const AttemptsList: () => import("react/jsx-runtime").JSX.Element;
3
+ export default AttemptsList;
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useState } from 'react';
3
+ import { useParams } from 'react-router-dom';
4
+ import { useIntl } from '@openedx/frontend-base';
5
+ import { DataTable } from '@openedx/paragon';
6
+ import UsernameFilter from '../../components/UsernameFilter';
7
+ import messages from '../../specialExams/messages';
8
+ import { useAttempts } from '../../specialExams/data/apiHook';
9
+ export const ATTEMPTS_PAGE_SIZE = 25;
10
+ const AttemptsList = () => {
11
+ const intl = useIntl();
12
+ const { courseId = '' } = useParams();
13
+ const [filters, setFilters] = useState({ page: 0, emailOrUsername: '' });
14
+ const { data = { results: [], count: 0, numPages: 0 }, isLoading = false } = useAttempts(courseId, Object.assign(Object.assign({}, filters), { pageSize: ATTEMPTS_PAGE_SIZE }));
15
+ const columns = useMemo(() => [
16
+ { accessor: 'username', Header: intl.formatMessage(messages.username), Filter: UsernameFilter, },
17
+ { accessor: 'examName', Header: intl.formatMessage(messages.examName), disableFilters: true, },
18
+ { accessor: 'timeLimit', Header: intl.formatMessage(messages.timeLimit), disableFilters: true, },
19
+ { accessor: 'type', Header: intl.formatMessage(messages.type), disableFilters: true, },
20
+ { accessor: 'startedAt', Header: intl.formatMessage(messages.startedAt), disableFilters: true, },
21
+ { accessor: 'completedAt', Header: intl.formatMessage(messages.completedAt), disableFilters: true, },
22
+ { accessor: 'status', Header: intl.formatMessage(messages.status), disableFilters: true, },
23
+ ], [intl]);
24
+ const handleFetchData = (data) => {
25
+ var _a;
26
+ const emailOrUsernameFilter = (_a = data.filters) === null || _a === void 0 ? void 0 : _a.find((f) => f.id === 'username');
27
+ if (emailOrUsernameFilter && emailOrUsernameFilter.value !== filters.emailOrUsername) {
28
+ setFilters((prevFilters) => (Object.assign(Object.assign({}, prevFilters), { emailOrUsername: emailOrUsernameFilter.value, page: 0 })));
29
+ return;
30
+ }
31
+ if (data.pageIndex !== filters.page) {
32
+ setFilters((prevFilters) => (Object.assign(Object.assign({}, prevFilters), { page: data.pageIndex })));
33
+ }
34
+ };
35
+ return (_jsxs(DataTable, { className: "mt-3", columns: columns, data: data.results, state: {
36
+ pageIndex: filters.page,
37
+ pageSize: ATTEMPTS_PAGE_SIZE,
38
+ filters: [
39
+ { id: 'emailOrUsername', value: filters.emailOrUsername }
40
+ ]
41
+ }, fetchData: handleFetchData, isFilterable: true, isLoading: isLoading, isPaginated: true, isSortable: true, itemCount: data.count, manualFilters: true, manualPagination: true, manualSortBy: true, pageSize: ATTEMPTS_PAGE_SIZE, pageCount: data.numPages, FilterStatusComponent: () => null, children: [_jsx(DataTable.TableControlBar, { className: "bg-light-200 py-3 px-4" }), _jsx(DataTable.Table, {}), _jsx(DataTable.EmptyTable, { content: intl.formatMessage(messages.noAttempts) }), _jsx(DataTable.TableFooter, {})] }));
42
+ };
43
+ export default AttemptsList;
44
+ //# sourceMappingURL=AttemptsList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttemptsList.js","sourceRoot":"","sources":["../../../src/specialExams/components/AttemptsList.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useIntl } from '@openedx/frontend-base';\nimport { DataTable } from '@openedx/paragon';\nimport UsernameFilter from '@src/components/UsernameFilter';\nimport messages from '@src/specialExams/messages';\nimport { useAttempts } from '@src/specialExams/data/apiHook';\nimport { DataTableFetchDataProps } from '@src/types';\n\nexport const ATTEMPTS_PAGE_SIZE = 25;\n\nconst AttemptsList = () => {\n const intl = useIntl();\n const { courseId = '' } = useParams();\n const [filters, setFilters] = useState({ page: 0, emailOrUsername: '' });\n const { data = { results: [], count: 0, numPages: 0 }, isLoading = false } = useAttempts(courseId, {\n ...filters,\n pageSize: ATTEMPTS_PAGE_SIZE\n });\n\n const columns = useMemo(() => [\n { accessor: 'username', Header: intl.formatMessage(messages.username), Filter: UsernameFilter, },\n { accessor: 'examName', Header: intl.formatMessage(messages.examName), disableFilters: true, },\n { accessor: 'timeLimit', Header: intl.formatMessage(messages.timeLimit), disableFilters: true, },\n { accessor: 'type', Header: intl.formatMessage(messages.type), disableFilters: true, },\n { accessor: 'startedAt', Header: intl.formatMessage(messages.startedAt), disableFilters: true, },\n { accessor: 'completedAt', Header: intl.formatMessage(messages.completedAt), disableFilters: true, },\n { accessor: 'status', Header: intl.formatMessage(messages.status), disableFilters: true, },\n ], [intl]);\n\n const handleFetchData = (data: DataTableFetchDataProps) => {\n const emailOrUsernameFilter = data.filters?.find((f) => f.id === 'username');\n if (emailOrUsernameFilter && emailOrUsernameFilter.value !== filters.emailOrUsername) {\n setFilters((prevFilters) => ({ ...prevFilters, emailOrUsername: emailOrUsernameFilter.value, page: 0 }));\n return;\n }\n if (data.pageIndex !== filters.page) {\n setFilters((prevFilters) => ({ ...prevFilters, page: data.pageIndex }));\n }\n };\n\n return (\n <DataTable\n className=\"mt-3\"\n columns={columns}\n data={data.results}\n state={{\n pageIndex: filters.page,\n pageSize: ATTEMPTS_PAGE_SIZE,\n filters: [\n { id: 'emailOrUsername', value: filters.emailOrUsername }\n ]\n }}\n fetchData={handleFetchData}\n isFilterable\n isLoading={isLoading}\n isPaginated\n isSortable\n itemCount={data.count}\n manualFilters\n manualPagination\n manualSortBy\n pageSize={ATTEMPTS_PAGE_SIZE}\n pageCount={data.numPages}\n FilterStatusComponent={() => null}\n >\n <DataTable.TableControlBar className=\"bg-light-200 py-3 px-4\" />\n <DataTable.Table />\n <DataTable.EmptyTable content={intl.formatMessage(messages.noAttempts)} />\n <DataTable.TableFooter />\n </DataTable>\n );\n};\n\nexport default AttemptsList;\n"]}
@@ -0,0 +1,3 @@
1
+ import { DataList } from '../../types';
2
+ import { Attempt, AttemptsParams } from '../types';
3
+ export declare const getAttempts: (courseId: string, params: AttemptsParams) => Promise<DataList<Attempt>>;
@@ -0,0 +1,23 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { getAuthenticatedHttpClient, camelCaseObject } from '@openedx/frontend-base';
11
+ import { getApiBaseUrl } from '../../data/api';
12
+ export const getAttempts = (courseId, params) => __awaiter(void 0, void 0, void 0, function* () {
13
+ const queryParams = new URLSearchParams({
14
+ page: (params.page + 1).toString(),
15
+ page_size: params.pageSize.toString(),
16
+ });
17
+ if (params.emailOrUsername) {
18
+ queryParams.append('search', params.emailOrUsername);
19
+ }
20
+ const { data } = yield getAuthenticatedHttpClient().get(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/special_exams/attempts?${queryParams.toString()}`);
21
+ return camelCaseObject(data);
22
+ });
23
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/specialExams/data/api.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI9C,MAAM,CAAC,MAAM,WAAW,GAAG,CAAO,QAAgB,EAAE,MAAsB,EAA8B,EAAE;IACxG,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC;QACtC,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE;QAClC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE;KACtC,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;QAC3B,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE,CAAC,GAAG,CACrD,GAAG,aAAa,EAAE,8BAA8B,QAAQ,2BAA2B,WAAW,CAAC,QAAQ,EAAE,EAAE,CAC5G,CAAC;IACF,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC","sourcesContent":["import { getAuthenticatedHttpClient, camelCaseObject } from '@openedx/frontend-base';\nimport { getApiBaseUrl } from '@src/data/api';\nimport { DataList } from '@src/types';\nimport { Attempt, AttemptsParams } from '../types';\n\nexport const getAttempts = async (courseId: string, params: AttemptsParams): Promise<DataList<Attempt>> => {\n const queryParams = new URLSearchParams({\n page: (params.page + 1).toString(),\n page_size: params.pageSize.toString(),\n });\n\n if (params.emailOrUsername) {\n queryParams.append('search', params.emailOrUsername);\n }\n\n const { data } = await getAuthenticatedHttpClient().get(\n `${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}/special_exams/attempts?${queryParams.toString()}`\n );\n return camelCaseObject(data);\n};\n"]}
@@ -0,0 +1,2 @@
1
+ import { AttemptsParams } from '../types';
2
+ export declare const useAttempts: (courseId: string, params: AttemptsParams) => import("@tanstack/react-query").UseQueryResult<import("../../types").DataList<import("../types").Attempt>, Error>;
@@ -0,0 +1,9 @@
1
+ import { useQuery } from '@tanstack/react-query';
2
+ import { getAttempts } from './api';
3
+ import { specialExamsQueryKeys } from './queryKeys';
4
+ export const useAttempts = (courseId, params) => (useQuery({
5
+ queryKey: specialExamsQueryKeys.attempts(courseId, params),
6
+ queryFn: () => getAttempts(courseId, params),
7
+ enabled: !!courseId,
8
+ }));
9
+ //# sourceMappingURL=apiHook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiHook.js","sourceRoot":"","sources":["../../../src/specialExams/data/apiHook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGpD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAAgB,EAAE,MAAsB,EAAE,EAAE,CAAC,CACvE,QAAQ,CAAC;IACP,QAAQ,EAAE,qBAAqB,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1D,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC5C,OAAO,EAAE,CAAC,CAAC,QAAQ;CACpB,CAAC,CACH,CAAC","sourcesContent":["import { useQuery } from '@tanstack/react-query';\nimport { getAttempts } from './api';\nimport { specialExamsQueryKeys } from './queryKeys';\nimport { AttemptsParams } from '../types';\n\nexport const useAttempts = (courseId: string, params: AttemptsParams) => (\n useQuery({\n queryKey: specialExamsQueryKeys.attempts(courseId, params),\n queryFn: () => getAttempts(courseId, params),\n enabled: !!courseId,\n })\n);\n"]}
@@ -0,0 +1,5 @@
1
+ import { AttemptsParams } from '../types';
2
+ export declare const specialExamsQueryKeys: {
3
+ all: readonly ["org.openedx.frontend.app.instructorDashboard", "specialExams"];
4
+ attempts: (courseId: string, params: AttemptsParams) => readonly ["org.openedx.frontend.app.instructorDashboard", "specialExams", "attempts", string, number, string];
5
+ };
@@ -0,0 +1,6 @@
1
+ import { appId } from '../../constants';
2
+ export const specialExamsQueryKeys = {
3
+ all: [appId, 'specialExams'],
4
+ attempts: (courseId, params) => [...specialExamsQueryKeys.all, 'attempts', courseId, params.page, params.emailOrUsername],
5
+ };
6
+ //# sourceMappingURL=queryKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryKeys.js","sourceRoot":"","sources":["../../../src/specialExams/data/queryKeys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,GAAG,EAAE,CAAC,KAAK,EAAE,cAAc,CAAU;IACrC,QAAQ,EAAE,CAAC,QAAgB,EAAE,MAAsB,EAAE,EAAE,CAAC,CAAC,GAAG,qBAAqB,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,eAAe,CAAU;CAC3J,CAAC","sourcesContent":["import { appId } from '@src/constants';\nimport { AttemptsParams } from '../types';\n\nexport const specialExamsQueryKeys = {\n all: [appId, 'specialExams'] as const,\n attempts: (courseId: string, params: AttemptsParams) => [...specialExamsQueryKeys.all, 'attempts', courseId, params.page, params.emailOrUsername] as const,\n};\n"]}
@@ -0,0 +1,58 @@
1
+ declare const messages: {
2
+ specialExamsTitle: {
3
+ id: string;
4
+ defaultMessage: string;
5
+ description: string;
6
+ };
7
+ examAttempts: {
8
+ id: string;
9
+ defaultMessage: string;
10
+ description: string;
11
+ };
12
+ allowances: {
13
+ id: string;
14
+ defaultMessage: string;
15
+ description: string;
16
+ };
17
+ username: {
18
+ id: string;
19
+ defaultMessage: string;
20
+ description: string;
21
+ };
22
+ examName: {
23
+ id: string;
24
+ defaultMessage: string;
25
+ description: string;
26
+ };
27
+ timeLimit: {
28
+ id: string;
29
+ defaultMessage: string;
30
+ description: string;
31
+ };
32
+ type: {
33
+ id: string;
34
+ defaultMessage: string;
35
+ description: string;
36
+ };
37
+ startedAt: {
38
+ id: string;
39
+ defaultMessage: string;
40
+ description: string;
41
+ };
42
+ completedAt: {
43
+ id: string;
44
+ defaultMessage: string;
45
+ description: string;
46
+ };
47
+ status: {
48
+ id: string;
49
+ defaultMessage: string;
50
+ description: string;
51
+ };
52
+ noAttempts: {
53
+ id: string;
54
+ defaultMessage: string;
55
+ description: string;
56
+ };
57
+ };
58
+ export default messages;
@@ -0,0 +1,60 @@
1
+ import { defineMessages } from '@openedx/frontend-base';
2
+ const messages = defineMessages({
3
+ specialExamsTitle: {
4
+ id: 'instruct.specialExams.title',
5
+ defaultMessage: 'Special Exams',
6
+ description: 'Title for the special exams page'
7
+ },
8
+ examAttempts: {
9
+ id: 'instruct.specialExams.examAttempts',
10
+ defaultMessage: 'Exam Attempts',
11
+ description: 'Label for the exam attempts tab'
12
+ },
13
+ allowances: {
14
+ id: 'instruct.specialExams.allowances',
15
+ defaultMessage: 'Allowances',
16
+ description: 'Label for the allowances tab'
17
+ },
18
+ username: {
19
+ id: 'instruct.specialExams.username',
20
+ defaultMessage: 'Username',
21
+ description: 'Column header for username in exam attempts list',
22
+ },
23
+ examName: {
24
+ id: 'instruct.specialExams.examName',
25
+ defaultMessage: 'Exam Name',
26
+ description: 'Column header for exam name in exam attempts list',
27
+ },
28
+ timeLimit: {
29
+ id: 'instruct.specialExams.timeLimit',
30
+ defaultMessage: 'Time Limit',
31
+ description: 'Column header for time limit in exam attempts list',
32
+ },
33
+ type: {
34
+ id: 'instruct.specialExams.type',
35
+ defaultMessage: 'Type',
36
+ description: 'Column header for type in exam attempts list',
37
+ },
38
+ startedAt: {
39
+ id: 'instruct.specialExams.startedAt',
40
+ defaultMessage: 'Started At',
41
+ description: 'Column header for started at in exam attempts list',
42
+ },
43
+ completedAt: {
44
+ id: 'instruct.specialExams.completedAt',
45
+ defaultMessage: 'Completed At',
46
+ description: 'Column header for completed at in exam attempts list',
47
+ },
48
+ status: {
49
+ id: 'instruct.specialExams.status',
50
+ defaultMessage: 'Status',
51
+ description: 'Column header for status in exam attempts list',
52
+ },
53
+ noAttempts: {
54
+ id: 'instruct.specialExams.noAttempts',
55
+ defaultMessage: 'No exam attempts found',
56
+ description: 'Message displayed when there are no exam attempts to show',
57
+ }
58
+ });
59
+ export default messages;
60
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/specialExams/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,iBAAiB,EAAE;QACjB,EAAE,EAAE,6BAA6B;QACjC,cAAc,EAAE,eAAe;QAC/B,WAAW,EAAE,kCAAkC;KAChD;IACD,YAAY,EAAE;QACZ,EAAE,EAAE,oCAAoC;QACxC,cAAc,EAAE,eAAe;QAC/B,WAAW,EAAE,iCAAiC;KAC/C;IACD,UAAU,EAAE;QACV,EAAE,EAAE,kCAAkC;QACtC,cAAc,EAAE,YAAY;QAC5B,WAAW,EAAE,8BAA8B;KAC5C;IACD,QAAQ,EAAE;QACR,EAAE,EAAE,gCAAgC;QACpC,cAAc,EAAE,UAAU;QAC1B,WAAW,EAAE,kDAAkD;KAChE;IACD,QAAQ,EAAE;QACR,EAAE,EAAE,gCAAgC;QACpC,cAAc,EAAE,WAAW;QAC3B,WAAW,EAAE,mDAAmD;KACjE;IACD,SAAS,EAAE;QACT,EAAE,EAAE,iCAAiC;QACrC,cAAc,EAAE,YAAY;QAC5B,WAAW,EAAE,oDAAoD;KAClE;IACD,IAAI,EAAE;QACJ,EAAE,EAAE,4BAA4B;QAChC,cAAc,EAAE,MAAM;QACtB,WAAW,EAAE,8CAA8C;KAC5D;IACD,SAAS,EAAE;QACT,EAAE,EAAE,iCAAiC;QACrC,cAAc,EAAE,YAAY;QAC5B,WAAW,EAAE,oDAAoD;KAClE;IACD,WAAW,EAAE;QACX,EAAE,EAAE,mCAAmC;QACvC,cAAc,EAAE,cAAc;QAC9B,WAAW,EAAE,sDAAsD;KACpE;IACD,MAAM,EAAE;QACN,EAAE,EAAE,8BAA8B;QAClC,cAAc,EAAE,QAAQ;QACxB,WAAW,EAAE,gDAAgD;KAC9D;IACD,UAAU,EAAE;QACV,EAAE,EAAE,kCAAkC;QACtC,cAAc,EAAE,wBAAwB;QACxC,WAAW,EAAE,2DAA2D;KACzE;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n specialExamsTitle: {\n id: 'instruct.specialExams.title',\n defaultMessage: 'Special Exams',\n description: 'Title for the special exams page'\n },\n examAttempts: {\n id: 'instruct.specialExams.examAttempts',\n defaultMessage: 'Exam Attempts',\n description: 'Label for the exam attempts tab'\n },\n allowances: {\n id: 'instruct.specialExams.allowances',\n defaultMessage: 'Allowances',\n description: 'Label for the allowances tab'\n },\n username: {\n id: 'instruct.specialExams.username',\n defaultMessage: 'Username',\n description: 'Column header for username in exam attempts list',\n },\n examName: {\n id: 'instruct.specialExams.examName',\n defaultMessage: 'Exam Name',\n description: 'Column header for exam name in exam attempts list',\n },\n timeLimit: {\n id: 'instruct.specialExams.timeLimit',\n defaultMessage: 'Time Limit',\n description: 'Column header for time limit in exam attempts list',\n },\n type: {\n id: 'instruct.specialExams.type',\n defaultMessage: 'Type',\n description: 'Column header for type in exam attempts list',\n },\n startedAt: {\n id: 'instruct.specialExams.startedAt',\n defaultMessage: 'Started At',\n description: 'Column header for started at in exam attempts list',\n },\n completedAt: {\n id: 'instruct.specialExams.completedAt',\n defaultMessage: 'Completed At',\n description: 'Column header for completed at in exam attempts list',\n },\n status: {\n id: 'instruct.specialExams.status',\n defaultMessage: 'Status',\n description: 'Column header for status in exam attempts list',\n },\n noAttempts: {\n id: 'instruct.specialExams.noAttempts',\n defaultMessage: 'No exam attempts found',\n description: 'Message displayed when there are no exam attempts to show',\n }\n});\n\nexport default messages;\n"]}
@@ -0,0 +1,13 @@
1
+ import { PaginationParams } from '../types';
2
+ export interface Attempt {
3
+ username: string;
4
+ examName: string;
5
+ timeLimit: number;
6
+ type: string;
7
+ startedAt: string;
8
+ completedAt: string;
9
+ status: string;
10
+ }
11
+ export interface AttemptsParams extends PaginationParams {
12
+ emailOrUsername: string;
13
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/specialExams/types.ts"],"names":[],"mappings":"","sourcesContent":["import { PaginationParams } from '@src/types';\n\nexport interface Attempt {\n username: string,\n examName: string,\n timeLimit: number,\n type: string,\n startedAt: string,\n completedAt: string,\n status: string,\n}\n\nexport interface AttemptsParams extends PaginationParams {\n emailOrUsername: string,\n}\n"]}
@@ -0,0 +1,16 @@
1
+ .toast-container {
2
+ left: unset;
3
+ right: var(--pgn-spacing-toast-container-gutter-lg);
4
+ }
5
+
6
+ .text-prewrap {
7
+ white-space: pre-wrap;
8
+ }
9
+
10
+ .username .form-control::placeholder {
11
+ font-size: var(--pgn-typography-form-input-font-size-sm);
12
+ }
13
+
14
+ .info-tooltip .tooltip-inner {
15
+ max-width: none;
16
+ }
package/dist/testUtils.js CHANGED
@@ -9,7 +9,7 @@ export const renderWithIntl = (component) => {
9
9
  return render(_jsx(IntlProvider, { locale: "en", messages: {}, children: component }));
10
10
  };
11
11
  export const renderWithAlertAndIntl = (component) => {
12
- return render(_jsx(AlertProvider, { children: _jsx(IntlProvider, { locale: "en", messages: {}, children: component }) }));
12
+ return render(_jsx(IntlProvider, { locale: "en", messages: {}, children: _jsx(AlertProvider, { children: component }) }));
13
13
  };
14
14
  export const createQueryMock = (data = undefined, isLoading = false) => ({
15
15
  data,
@@ -1 +1 @@
1
- {"version":3,"file":"testUtils.js","sourceRoot":"","sources":["../src/testUtils.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEzE,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AAEtC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,EAAsB,EAAE,EAAE,CAC9D,cAAc,CACZ,KAAC,mBAAmB,IAAC,MAAM,EAAE,WAAW,YACrC,EAAE,GACiB,CACvB,CAAC;AAEJ,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,EAAE;IAC1C,OAAO,MAAM,CAAC,KAAC,YAAY,IAAC,MAAM,EAAC,IAAI,EAAC,QAAQ,EAAE,EAAE,YAAI,SAAS,GAAiB,CAAC,CAAC;AACtF,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,SAAS,EAAE,EAAE;IAClD,OAAO,MAAM,CACX,KAAC,aAAa,cACZ,KAAC,YAAY,IAAC,MAAM,EAAC,IAAI,EAAC,QAAQ,EAAE,EAAE,YACnC,SAAS,GACG,GACD,CACjB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAY,SAAS,EAAE,SAAS,GAAG,KAAK,EAAE,EAAE,CAAC,CAAC;IAC5E,IAAI;IACJ,SAAS;IACT,KAAK,EAAE,IAAI;IACX,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,CAAC,SAAS,IAAI,IAAI,KAAK,SAAS;IAC3C,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;IACzD,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;IAC5C,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE;CACX,CAAA,CAAC","sourcesContent":["import { render } from '@testing-library/react';\nimport { IntlProvider } from '@openedx/frontend-base';\nimport { AlertProvider } from './providers/AlertProvider';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\n\nconst queryClient = new QueryClient();\n\nexport const renderWithQueryClient = (ui: React.ReactElement) =>\n renderWithIntl(\n <QueryClientProvider client={queryClient}>\n {ui}\n </QueryClientProvider>\n );\n\nexport const renderWithIntl = (component) => {\n return render(<IntlProvider locale=\"en\" messages={{}}>{ component }</IntlProvider>);\n};\n\nexport const renderWithAlertAndIntl = (component) => {\n return render(\n <AlertProvider>\n <IntlProvider locale=\"en\" messages={{}}>\n {component}\n </IntlProvider>\n </AlertProvider>\n );\n};\n\nexport const createQueryMock = (data: any = undefined, isLoading = false) => ({\n data,\n isLoading,\n error: null,\n isError: false,\n isSuccess: !isLoading && data !== undefined,\n status: isLoading ? 'loading' : data ? 'success' : 'idle',\n fetchStatus: isLoading ? 'fetching' : 'idle',\n refetch: jest.fn(),\n} as any);\n"]}
1
+ {"version":3,"file":"testUtils.js","sourceRoot":"","sources":["../src/testUtils.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEzE,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AAEtC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,EAAsB,EAAE,EAAE,CAC9D,cAAc,CACZ,KAAC,mBAAmB,IAAC,MAAM,EAAE,WAAW,YACrC,EAAE,GACiB,CACvB,CAAC;AAEJ,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,EAAE;IAC1C,OAAO,MAAM,CAAC,KAAC,YAAY,IAAC,MAAM,EAAC,IAAI,EAAC,QAAQ,EAAE,EAAE,YAAI,SAAS,GAAiB,CAAC,CAAC;AACtF,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,SAAS,EAAE,EAAE;IAClD,OAAO,MAAM,CACX,KAAC,YAAY,IAAC,MAAM,EAAC,IAAI,EAAC,QAAQ,EAAE,EAAE,YACpC,KAAC,aAAa,cACX,SAAS,GACI,GACH,CAChB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAY,SAAS,EAAE,SAAS,GAAG,KAAK,EAAE,EAAE,CAAC,CAAC;IAC5E,IAAI;IACJ,SAAS;IACT,KAAK,EAAE,IAAI;IACX,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,CAAC,SAAS,IAAI,IAAI,KAAK,SAAS;IAC3C,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;IACzD,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;IAC5C,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE;CACX,CAAA,CAAC","sourcesContent":["import { render } from '@testing-library/react';\nimport { IntlProvider } from '@openedx/frontend-base';\nimport { AlertProvider } from './providers/AlertProvider';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\n\nconst queryClient = new QueryClient();\n\nexport const renderWithQueryClient = (ui: React.ReactElement) =>\n renderWithIntl(\n <QueryClientProvider client={queryClient}>\n {ui}\n </QueryClientProvider>\n );\n\nexport const renderWithIntl = (component) => {\n return render(<IntlProvider locale=\"en\" messages={{}}>{ component }</IntlProvider>);\n};\n\nexport const renderWithAlertAndIntl = (component) => {\n return render(\n <IntlProvider locale=\"en\" messages={{}}>\n <AlertProvider>\n {component}\n </AlertProvider>\n </IntlProvider>\n );\n};\n\nexport const createQueryMock = (data: any = undefined, isLoading = false) => ({\n data,\n isLoading,\n error: null,\n isError: false,\n isSuccess: !isLoading && data !== undefined,\n status: isLoading ? 'loading' : data ? 'success' : 'idle',\n fetchStatus: isLoading ? 'fetching' : 'idle',\n refetch: jest.fn(),\n} as any);\n"]}
@@ -45,4 +45,5 @@ export interface Learner {
45
45
  }
46
46
  export interface SelectedLearner extends Learner {
47
47
  progressUrl: string;
48
+ isEnrolled: boolean;
48
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAiBC,CAAC;AAMD,CAAC;AAwBD,CAAC","sourcesContent":["export interface TableCellValue<T> {\n row: {\n original: T,\n },\n}\n\nexport interface PaginationParams {\n page: number,\n pageSize: number,\n}\n\nexport interface APIError {\n response: {\n data: {\n error: string,\n },\n },\n};\n\nexport interface DataList<T> {\n count: number,\n numPages: number,\n results: T[],\n};\n\nexport interface PendingTask {\n taskType: string,\n taskInput: Record<string, any>,\n taskId: string,\n requester: string,\n taskState: string,\n created: string,\n taskOutput: Record<string, any> | null,\n durationSec: number,\n status: string,\n taskMessage: string,\n}\n\nexport interface DataTableFetchDataProps {\n filters: { id: string, value: string }[],\n pageIndex: number,\n}\n\nexport interface Learner {\n username: string,\n fullName: string,\n email: string,\n};\n\nexport interface SelectedLearner extends Learner {\n progressUrl: string,\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAiBC,CAAC;AAMD,CAAC;AAwBD,CAAC","sourcesContent":["export interface TableCellValue<T> {\n row: {\n original: T,\n },\n}\n\nexport interface PaginationParams {\n page: number,\n pageSize: number,\n}\n\nexport interface APIError {\n response: {\n data: {\n error: string,\n },\n },\n};\n\nexport interface DataList<T> {\n count: number,\n numPages: number,\n results: T[],\n};\n\nexport interface PendingTask {\n taskType: string,\n taskInput: Record<string, any>,\n taskId: string,\n requester: string,\n taskState: string,\n created: string,\n taskOutput: Record<string, any> | null,\n durationSec: number,\n status: string,\n taskMessage: string,\n}\n\nexport interface DataTableFetchDataProps {\n filters: { id: string, value: string }[],\n pageIndex: number,\n}\n\nexport interface Learner {\n username: string,\n fullName: string,\n email: string,\n};\n\nexport interface SelectedLearner extends Learner {\n progressUrl: string,\n isEnrolled: boolean,\n}\n"]}
@@ -1 +1,6 @@
1
1
  export declare const parseObject: (input: any) => string;
2
+ export declare const parseLearnersCount: (learners: string) => number;
3
+ export declare const filterCertificates: <T extends {
4
+ username: string;
5
+ email: string;
6
+ }>(data: T[], filterFn: (item: T) => boolean, search: string) => T[];
@@ -9,4 +9,14 @@ export const parseObject = (input) => {
9
9
  return String(input);
10
10
  }
11
11
  };
12
+ export const parseLearnersCount = (learners) => learners.split(/[\n,]/).filter((l) => l.trim()).length;
13
+ export const filterCertificates = (data, filterFn, search) => {
14
+ const searchLower = search.toLowerCase();
15
+ return data.filter((item) => {
16
+ const matchesSearch = !search
17
+ || item.username.toLowerCase().includes(searchLower)
18
+ || item.email.toLowerCase().includes(searchLower);
19
+ return filterFn(item) && matchesSearch;
20
+ });
21
+ };
12
22
  //# sourceMappingURL=formatters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"formatters.js","sourceRoot":"","sources":["../../src/utils/formatters.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAU,EAAU,EAAE;IAChD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC,CAAC","sourcesContent":["export const parseObject = (input: any): string => {\n if (typeof input === 'string') {\n return input;\n }\n try {\n return JSON.stringify(input, null, 2);\n } catch {\n return String(input);\n }\n};\n"]}
1
+ {"version":3,"file":"formatters.js","sourceRoot":"","sources":["../../src/utils/formatters.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAU,EAAU,EAAE;IAChD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,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;AAEzD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,IAAS,EACT,QAA8B,EAC9B,MAAc,EACT,EAAE;IACP,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACzC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC1B,MAAM,aAAa,GAAG,CAAC,MAAM;eACxB,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;eACjD,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACpD,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC","sourcesContent":["export const parseObject = (input: any): string => {\n if (typeof input === 'string') {\n return input;\n }\n try {\n return JSON.stringify(input, null, 2);\n } catch {\n return String(input);\n }\n};\n\nexport const parseLearnersCount = (learners: string): number =>\n learners.split(/[\\n,]/).filter((l) => l.trim()).length;\n\nexport const filterCertificates = <T extends { username: string, email: string }>(\n data: T[],\n filterFn: (item: T) => boolean,\n search: string,\n): T[] => {\n const searchLower = search.toLowerCase();\n return data.filter((item) => {\n const matchesSearch = !search\n || item.username.toLowerCase().includes(searchLower)\n || item.email.toLowerCase().includes(searchLower);\n return filterFn(item) && matchesSearch;\n });\n};\n"]}
package/package.json CHANGED
@@ -1,14 +1,13 @@
1
1
  {
2
2
  "name": "@openedx/frontend-app-instructor-dashboard",
3
- "version": "1.0.0-alpha.2",
3
+ "version": "1.0.0-alpha.20",
4
4
  "description": "The Open edX Instructor Dashboard",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/openedx/frontend-app-instructor-dashboard.git"
8
8
  },
9
9
  "exports": {
10
- ".": "./dist/index.js",
11
- "./app.scss": "./dist/app.scss"
10
+ ".": "./dist/index.js"
12
11
  },
13
12
  "files": [
14
13
  "/dist"
@@ -56,13 +55,11 @@
56
55
  "url": "https://github.com/openedx/frontend-app-instructor-dashboard/issues"
57
56
  },
58
57
  "dependencies": {
59
- "@edx/brand": "npm:@openedx/brand-openedx@^1.2.3",
60
58
  "@edx/openedx-atlas": "^0.7.0",
61
59
  "lodash": "^4.17.23"
62
60
  },
63
61
  "devDependencies": {
64
62
  "@edx/browserslist-config": "^1.5.0",
65
- "@tanstack/react-query-devtools": "^5.90.2",
66
63
  "@testing-library/jest-dom": "^6.8.0",
67
64
  "@testing-library/react": "^16.3.0",
68
65
  "@testing-library/user-event": "^14.6.1",