@jmruthers/pace-core 0.6.1 → 0.6.3

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 (549) hide show
  1. package/CHANGELOG.md +88 -10
  2. package/cursor-rules/00-pace-core-compliance.mdc +46 -87
  3. package/cursor-rules/01-standards-compliance.mdc +16 -47
  4. package/cursor-rules/02-project-structure.mdc +4 -4
  5. package/cursor-rules/03-solid-principles.mdc +45 -164
  6. package/cursor-rules/04-testing-standards.mdc +22 -69
  7. package/cursor-rules/05-bug-reports-and-features.mdc +2 -2
  8. package/cursor-rules/06-code-quality.mdc +42 -125
  9. package/cursor-rules/07-tech-stack-compliance.mdc +33 -128
  10. package/cursor-rules/08-markup-quality.mdc +452 -0
  11. package/cursor-rules/CHANGELOG.md +18 -0
  12. package/cursor-rules/README.md +2 -1
  13. package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-Cb34EQs3.d.ts} +63 -1
  14. package/dist/{DataTable-CH1U5Tpy.d.ts → DataTable-BMRU8a1j.d.ts} +33 -1
  15. package/dist/{DataTable-DQ7RSOHE.js → DataTable-THFPBKTP.js} +12 -10
  16. package/dist/{PublicPageProvider-ce4xlHYA.d.ts → PublicPageProvider-DEMpysFR.d.ts} +394 -171
  17. package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CKvHP1MK.d.ts} +30 -8
  18. package/dist/{UnifiedAuthProvider-ATAP5UTR.js → UnifiedAuthProvider-KAGUYQ4J.js} +5 -4
  19. package/dist/{api-N774RPUA.js → api-IAGWF3ZG.js} +10 -10
  20. package/dist/{audit-B5P6FFIR.js → audit-V53FV5AG.js} +2 -2
  21. package/dist/{chunk-JBKQ3SAO.js → chunk-2T2IG7T7.js} +107 -57
  22. package/dist/chunk-2T2IG7T7.js.map +1 -0
  23. package/dist/{chunk-3QRJFVBR.js → chunk-6SOIHG6Z.js} +1 -1
  24. package/dist/chunk-6SOIHG6Z.js.map +1 -0
  25. package/dist/{chunk-3XTALGJF.js → chunk-6Z7LTB3D.js} +69 -240
  26. package/dist/chunk-6Z7LTB3D.js.map +1 -0
  27. package/dist/{chunk-4ZC4GX36.js → chunk-CNCQDFLN.js} +199 -46
  28. package/dist/chunk-CNCQDFLN.js.map +1 -0
  29. package/dist/chunk-DGUM43GV.js +11 -0
  30. package/dist/{chunk-BYFSK72L.js → chunk-DWUBLJJM.js} +361 -187
  31. package/dist/chunk-DWUBLJJM.js.map +1 -0
  32. package/dist/{chunk-LXQLPRQ2.js → chunk-FFQEQTNW.js} +6 -8
  33. package/dist/chunk-FFQEQTNW.js.map +1 -0
  34. package/dist/chunk-FMUCXFII.js +76 -0
  35. package/dist/chunk-FMUCXFII.js.map +1 -0
  36. package/dist/{chunk-4N5C5XZU.js → chunk-HFZBI76P.js} +4 -4
  37. package/dist/chunk-HFZBI76P.js.map +1 -0
  38. package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
  39. package/dist/chunk-L4OXEN46.js.map +1 -0
  40. package/dist/{chunk-R77UEZ4E.js → chunk-M43Y4SSO.js} +1 -1
  41. package/dist/chunk-M43Y4SSO.js.map +1 -0
  42. package/dist/{chunk-I7PSE6JW.js → chunk-M7MPQISP.js} +3 -76
  43. package/dist/chunk-M7MPQISP.js.map +1 -0
  44. package/dist/chunk-PQBSKX33.js +7793 -0
  45. package/dist/chunk-PQBSKX33.js.map +1 -0
  46. package/dist/chunk-QRPVRXYT.js +226 -0
  47. package/dist/chunk-QRPVRXYT.js.map +1 -0
  48. package/dist/{chunk-KNC55RTG.js → chunk-RWEBCB47.js} +194 -416
  49. package/dist/chunk-RWEBCB47.js.map +1 -0
  50. package/dist/{chunk-XM25TVIE.js → chunk-YDQHOZNA.js} +843 -388
  51. package/dist/chunk-YDQHOZNA.js.map +1 -0
  52. package/dist/{chunk-GLK6VM3F.js → chunk-ZNIWI3UC.js} +739 -737
  53. package/dist/chunk-ZNIWI3UC.js.map +1 -0
  54. package/dist/components.d.ts +5 -5
  55. package/dist/components.js +18 -16
  56. package/dist/components.js.map +1 -1
  57. package/dist/contextValidator-3JNZKUTX.js +9 -0
  58. package/dist/contextValidator-3JNZKUTX.js.map +1 -0
  59. package/dist/eslint-rules/pace-core-compliance.cjs +106 -0
  60. package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
  61. package/dist/hooks.d.ts +55 -122
  62. package/dist/hooks.js +10 -13
  63. package/dist/hooks.js.map +1 -1
  64. package/dist/index.d.ts +60 -13
  65. package/dist/index.js +30 -25
  66. package/dist/index.js.map +1 -1
  67. package/dist/providers.d.ts +21 -3
  68. package/dist/providers.js +4 -3
  69. package/dist/rbac/index.d.ts +210 -139
  70. package/dist/rbac/index.js +17 -13
  71. package/dist/styles/index.js +1 -1
  72. package/dist/theming/runtime.d.ts +1 -13
  73. package/dist/theming/runtime.js +2 -2
  74. package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
  75. package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
  76. package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
  77. package/dist/types.d.ts +2 -2
  78. package/dist/types.js +1 -1
  79. package/dist/{usePublicRouteParams-BJAlWfuJ.d.ts → usePublicRouteParams-i3qtoBgg.d.ts} +38 -17
  80. package/dist/utils.d.ts +4 -5
  81. package/dist/utils.js +17 -19
  82. package/dist/utils.js.map +1 -1
  83. package/docs/api/README.md +21 -17
  84. package/docs/api/modules.md +4191 -2967
  85. package/docs/architecture/database-schema-requirements.md +161 -0
  86. package/docs/components/context-selector.md +126 -0
  87. package/docs/core-concepts/rbac-system.md +3 -3
  88. package/docs/documentation-index.md +2 -4
  89. package/docs/getting-started/cursor-rules.md +2 -1
  90. package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
  91. package/docs/migration/MIGRATION_GUIDE.md +2 -24
  92. package/docs/migration/RBAC_SCOPE_MIGRATION.md +385 -0
  93. package/docs/migration/README.md +52 -6
  94. package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
  95. package/docs/migration/database-changes-december-2025.md +3 -3
  96. package/docs/pace-mint-fix-auto-selection.md +218 -0
  97. package/docs/pace-mint-rbac-setup.md +391 -0
  98. package/docs/rbac/event-based-apps.md +1 -1
  99. package/docs/rbac/getting-started.md +1 -1
  100. package/docs/rbac/quick-start.md +1 -1
  101. package/docs/rbac/secure-client-protection.md +330 -0
  102. package/docs/standards/README.md +1 -0
  103. package/package.json +4 -3
  104. package/scripts/audit/core/checks/accessibility.cjs +197 -0
  105. package/scripts/audit/core/checks/api-usage.cjs +191 -0
  106. package/scripts/audit/core/checks/bundle.cjs +142 -0
  107. package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +784 -685
  108. package/scripts/audit/core/checks/config.cjs +54 -0
  109. package/scripts/audit/core/checks/coverage.cjs +84 -0
  110. package/scripts/audit/core/checks/dependencies.cjs +985 -0
  111. package/scripts/audit/core/checks/documentation.cjs +268 -0
  112. package/scripts/audit/core/checks/environment.cjs +116 -0
  113. package/scripts/audit/core/checks/error-handling.cjs +340 -0
  114. package/scripts/audit/core/checks/forms.cjs +172 -0
  115. package/scripts/audit/core/checks/heuristics.cjs +68 -0
  116. package/scripts/audit/core/checks/hooks.cjs +334 -0
  117. package/scripts/audit/core/checks/imports.cjs +244 -0
  118. package/scripts/audit/core/checks/performance.cjs +325 -0
  119. package/scripts/audit/core/checks/routes.cjs +117 -0
  120. package/scripts/audit/core/checks/state.cjs +130 -0
  121. package/scripts/audit/core/checks/structure.cjs +65 -0
  122. package/scripts/audit/core/checks/style.cjs +584 -0
  123. package/scripts/audit/core/checks/testing.cjs +122 -0
  124. package/scripts/audit/core/checks/typescript.cjs +61 -0
  125. package/scripts/audit/core/scanner.cjs +199 -0
  126. package/scripts/audit/core/utils.cjs +137 -0
  127. package/scripts/audit/index.cjs +223 -0
  128. package/scripts/audit/reporters/console.cjs +151 -0
  129. package/scripts/audit/reporters/json.cjs +54 -0
  130. package/scripts/audit/reporters/markdown.cjs +124 -0
  131. package/scripts/audit-consuming-app.cjs +61 -936
  132. package/scripts/build-docs/build-decision.js +240 -0
  133. package/scripts/build-docs/cache-utils.js +105 -0
  134. package/scripts/build-docs/content-normalization.js +150 -0
  135. package/scripts/build-docs/file-utils.js +105 -0
  136. package/scripts/build-docs/git-utils.js +86 -0
  137. package/scripts/build-docs/hash-utils.js +116 -0
  138. package/scripts/build-docs/typedoc-runner.js +220 -0
  139. package/scripts/build-docs-incremental.js +77 -913
  140. package/scripts/utils/command-runner.js +16 -11
  141. package/scripts/validate-formats.js +61 -56
  142. package/scripts/validate-master.js +74 -69
  143. package/scripts/validate-pre-publish.js +70 -65
  144. package/src/__tests__/hooks/usePermissions.test.ts +2 -2
  145. package/src/components/Alert/Alert.test.tsx +12 -18
  146. package/src/components/Alert/Alert.tsx +5 -7
  147. package/src/components/Avatar/Avatar.test.tsx +4 -4
  148. package/src/components/Badge/Badge.tsx +14 -0
  149. package/src/components/Button/Button.tsx +22 -0
  150. package/src/components/Calendar/Calendar.tsx +8 -2
  151. package/src/components/Card/Card.tsx +4 -0
  152. package/src/components/Checkbox/Checkbox.test.tsx +12 -12
  153. package/src/components/Checkbox/Checkbox.tsx +2 -2
  154. package/src/components/ContextSelector/ContextSelector.tsx +384 -0
  155. package/src/components/ContextSelector/index.ts +3 -0
  156. package/src/components/DataTable/DataTable.tsx +38 -4
  157. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
  158. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +18 -4
  159. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
  160. package/src/components/DataTable/components/AccessDeniedPage.tsx +16 -25
  161. package/src/components/DataTable/components/ActionButtons.tsx +10 -7
  162. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
  163. package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
  164. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
  165. package/src/components/DataTable/components/DataTableBody.tsx +8 -0
  166. package/src/components/DataTable/components/DataTableCore.tsx +196 -554
  167. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
  168. package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
  169. package/src/components/DataTable/components/DataTableModals.tsx +8 -0
  170. package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
  171. package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
  172. package/src/components/DataTable/components/EditFields.tsx +307 -0
  173. package/src/components/DataTable/components/EditableRow.tsx +8 -0
  174. package/src/components/DataTable/components/EmptyState.tsx +10 -0
  175. package/src/components/DataTable/components/FilterRow.tsx +12 -0
  176. package/src/components/DataTable/components/GroupHeader.tsx +12 -0
  177. package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
  178. package/src/components/DataTable/components/ImportModal.tsx +7 -0
  179. package/src/components/DataTable/components/LoadingState.tsx +6 -0
  180. package/src/components/DataTable/components/PaginationControls.tsx +16 -1
  181. package/src/components/DataTable/components/RowComponent.tsx +391 -0
  182. package/src/components/DataTable/components/UnifiedTableBody.tsx +63 -851
  183. package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
  184. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
  185. package/src/components/DataTable/components/cellValueUtils.ts +40 -0
  186. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
  187. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
  188. package/src/components/DataTable/context/DataTableContext.tsx +50 -0
  189. package/src/components/DataTable/core/ColumnFactory.ts +31 -0
  190. package/src/components/DataTable/core/DataTableContext.tsx +32 -1
  191. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
  192. package/src/components/DataTable/hooks/useColumnReordering.ts +12 -0
  193. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
  194. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
  195. package/src/components/DataTable/hooks/useDataTablePermissions.ts +127 -33
  196. package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
  197. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
  198. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
  199. package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
  200. package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
  201. package/src/components/DataTable/styles.ts +6 -6
  202. package/src/components/DataTable/types.ts +6 -10
  203. package/src/components/DataTable/utils/a11yUtils.ts +7 -0
  204. package/src/components/DataTable/utils/debugTools.ts +18 -113
  205. package/src/components/DataTable/utils/errorHandling.ts +12 -0
  206. package/src/components/DataTable/utils/exportUtils.ts +9 -0
  207. package/src/components/DataTable/utils/flexibleImport.ts +12 -48
  208. package/src/components/DataTable/utils/paginationUtils.ts +8 -0
  209. package/src/components/DataTable/utils/performanceUtils.ts +5 -1
  210. package/src/components/Dialog/Dialog.tsx +31 -3
  211. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
  212. package/src/components/ErrorBoundary/ErrorBoundary.tsx +45 -5
  213. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
  214. package/src/components/ErrorBoundary/index.ts +27 -2
  215. package/src/components/FileDisplay/FileDisplay.tsx +74 -28
  216. package/src/components/FileUpload/FileUpload.tsx +22 -2
  217. package/src/components/Footer/Footer.test.tsx +16 -16
  218. package/src/components/Footer/Footer.tsx +14 -11
  219. package/src/components/Form/Form.tsx +1 -0
  220. package/src/components/Header/Header.test.tsx +43 -73
  221. package/src/components/Header/Header.tsx +59 -49
  222. package/src/components/Input/Input.test.tsx +2 -2
  223. package/src/components/Input/Input.tsx +8 -4
  224. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
  225. package/src/components/LoginForm/LoginForm.tsx +4 -0
  226. package/src/components/NavigationMenu/NavigationMenu.tsx +14 -513
  227. package/src/components/NavigationMenu/types.ts +56 -0
  228. package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
  229. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +10 -19
  230. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +2 -2
  231. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +5 -5
  232. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +13 -11
  233. package/src/components/PaceAppLayout/PaceAppLayout.tsx +167 -44
  234. package/src/components/PaceAppLayout/README.md +14 -17
  235. package/src/components/PaceAppLayout/test-setup.tsx +3 -4
  236. package/src/components/PaceLoginPage/PaceLoginPage.tsx +3 -0
  237. package/src/components/PasswordChange/PasswordChangeForm.tsx +9 -0
  238. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
  239. package/src/components/PublicLayout/PublicPageLayout.tsx +2 -5
  240. package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
  241. package/src/components/Select/Select.tsx +80 -434
  242. package/src/components/Select/context.ts +23 -0
  243. package/src/components/Select/hooks/useSelectEvents.ts +87 -0
  244. package/src/components/Select/hooks/useSelectSearch.ts +91 -0
  245. package/src/components/Select/hooks/useSelectState.ts +104 -0
  246. package/src/components/Select/index.ts +9 -1
  247. package/src/components/Select/types.ts +123 -0
  248. package/src/components/Select/utils/text.ts +26 -0
  249. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +4 -5
  250. package/src/components/Switch/Switch.tsx +4 -4
  251. package/src/components/Tabs/Tabs.tsx +1 -1
  252. package/src/components/Toast/Toast.tsx +4 -0
  253. package/src/components/Tooltip/Tooltip.tsx +2 -2
  254. package/src/components/UserMenu/UserMenu.test.tsx +24 -11
  255. package/src/components/UserMenu/UserMenu.tsx +21 -18
  256. package/src/components/index.ts +7 -7
  257. package/src/eslint-rules/pace-core-compliance.cjs +106 -0
  258. package/src/hooks/__tests__/index.unit.test.ts +2 -5
  259. package/src/hooks/__tests__/useAppConfig.unit.test.ts +4 -98
  260. package/src/hooks/index.ts +1 -2
  261. package/src/hooks/public/usePublicEvent.ts +4 -0
  262. package/src/hooks/public/usePublicEventLogo.ts +4 -0
  263. package/src/hooks/public/usePublicFileDisplay.ts +4 -0
  264. package/src/hooks/public/usePublicRouteParams.ts +4 -0
  265. package/src/hooks/services/useAuth.ts +32 -0
  266. package/src/hooks/services/useCurrentEvent.ts +6 -0
  267. package/src/hooks/services/useCurrentOrganisation.ts +6 -0
  268. package/src/hooks/useAppConfig.ts +15 -30
  269. package/src/hooks/useDebounce.ts +9 -0
  270. package/src/hooks/useEventTheme.ts +6 -0
  271. package/src/hooks/useFileDisplay.ts +81 -50
  272. package/src/hooks/useFileReference.ts +25 -7
  273. package/src/hooks/useFileUrl.ts +11 -1
  274. package/src/hooks/useFocusManagement.ts +14 -0
  275. package/src/hooks/useFocusTrap.ts +3 -0
  276. package/src/hooks/useInactivityTracker.ts +3 -0
  277. package/src/hooks/useKeyboardShortcuts.ts +4 -0
  278. package/src/hooks/useOrganisationPermissions.ts +4 -0
  279. package/src/hooks/useOrganisationSecurity.ts +4 -0
  280. package/src/hooks/usePerformanceMonitor.ts +4 -0
  281. package/src/hooks/usePermissionCache.ts +7 -0
  282. package/src/hooks/useQueryCache.ts +12 -1
  283. package/src/hooks/useSessionRestoration.ts +4 -0
  284. package/src/hooks/useStorage.ts +4 -0
  285. package/src/hooks/useToast.ts +1 -1
  286. package/src/index.ts +6 -6
  287. package/src/providers/__tests__/OrganisationProvider.test.tsx +92 -70
  288. package/src/providers/services/AuthServiceProvider.tsx +35 -7
  289. package/src/providers/services/EventServiceProvider.tsx +51 -5
  290. package/src/providers/services/InactivityServiceProvider.tsx +18 -0
  291. package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
  292. package/src/providers/services/UnifiedAuthProvider.tsx +126 -134
  293. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +29 -13
  294. package/src/rbac/README.md +1 -1
  295. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +1 -1
  296. package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
  297. package/src/rbac/adapters.tsx +12 -3
  298. package/src/rbac/api.test.ts +59 -51
  299. package/src/rbac/api.ts +246 -167
  300. package/src/rbac/components/NavigationProvider.tsx +4 -1
  301. package/src/rbac/components/PagePermissionGuard.tsx +185 -17
  302. package/src/rbac/components/RoleBasedRouter.tsx +5 -1
  303. package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
  304. package/src/rbac/components/SecureDataProvider.tsx +20 -5
  305. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
  306. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
  307. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
  308. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
  309. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
  310. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
  311. package/src/rbac/engine.ts +38 -14
  312. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +32 -21
  313. package/src/rbac/hooks/permissions/index.ts +7 -0
  314. package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
  315. package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
  316. package/src/rbac/hooks/permissions/useCan.ts +377 -0
  317. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
  318. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
  319. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
  320. package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
  321. package/src/rbac/hooks/useCan.test.ts +64 -66
  322. package/src/rbac/hooks/usePermissions.ts +14 -995
  323. package/src/rbac/hooks/useRBAC.test.ts +1 -5
  324. package/src/rbac/hooks/useRBAC.ts +36 -37
  325. package/src/rbac/hooks/useResolvedScope.test.ts +120 -35
  326. package/src/rbac/hooks/useResolvedScope.ts +35 -40
  327. package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
  328. package/src/rbac/hooks/useResourcePermissions.ts +14 -4
  329. package/src/rbac/hooks/useSecureSupabase.ts +27 -7
  330. package/src/rbac/index.ts +7 -0
  331. package/src/rbac/permissions.ts +0 -30
  332. package/src/rbac/secureClient.test.ts +22 -18
  333. package/src/rbac/secureClient.ts +294 -68
  334. package/src/rbac/security.ts +0 -17
  335. package/src/rbac/types.ts +9 -0
  336. package/src/rbac/utils/__tests__/contextValidator.test.ts +64 -86
  337. package/src/rbac/utils/clientSecurity.ts +93 -0
  338. package/src/rbac/utils/contextValidator.ts +77 -168
  339. package/src/services/AuthService.ts +39 -7
  340. package/src/services/EventService.ts +186 -54
  341. package/src/services/OrganisationService.ts +81 -14
  342. package/src/services/__tests__/EventService.test.ts +1 -2
  343. package/src/services/base/BaseService.ts +3 -0
  344. package/src/theming/__tests__/parseEventColours.test.ts +6 -9
  345. package/src/theming/parseEventColours.ts +5 -19
  346. package/src/types/vitest-globals.d.ts +51 -26
  347. package/src/utils/__mocks__/supabaseMock.ts +1 -3
  348. package/src/utils/__tests__/formatting.unit.test.ts +4 -4
  349. package/src/utils/__tests__/index.unit.test.ts +2 -2
  350. package/src/utils/audit/audit.ts +0 -3
  351. package/src/utils/core/cn.ts +1 -1
  352. package/src/utils/dynamic/dynamicUtils.ts +7 -4
  353. package/src/utils/file-reference/index.ts +53 -1
  354. package/src/utils/formatting/formatting.ts +8 -18
  355. package/src/utils/index.ts +0 -1
  356. package/dist/chunk-3QRJFVBR.js.map +0 -1
  357. package/dist/chunk-3XTALGJF.js.map +0 -1
  358. package/dist/chunk-4N5C5XZU.js.map +0 -1
  359. package/dist/chunk-4ZC4GX36.js.map +0 -1
  360. package/dist/chunk-7D4SUZUM.js +0 -38
  361. package/dist/chunk-BYFSK72L.js.map +0 -1
  362. package/dist/chunk-EXUD6RNJ.js +0 -451
  363. package/dist/chunk-EXUD6RNJ.js.map +0 -1
  364. package/dist/chunk-GLK6VM3F.js.map +0 -1
  365. package/dist/chunk-I7PSE6JW.js.map +0 -1
  366. package/dist/chunk-JBKQ3SAO.js.map +0 -1
  367. package/dist/chunk-KNC55RTG.js.map +0 -1
  368. package/dist/chunk-LXQLPRQ2.js.map +0 -1
  369. package/dist/chunk-R77UEZ4E.js.map +0 -1
  370. package/dist/chunk-SQGMNID3.js.map +0 -1
  371. package/dist/chunk-T33XF5ZC.js +0 -12922
  372. package/dist/chunk-T33XF5ZC.js.map +0 -1
  373. package/dist/chunk-XM25TVIE.js.map +0 -1
  374. package/docs/api/classes/ColumnFactory.md +0 -243
  375. package/docs/api/classes/ErrorBoundary.md +0 -144
  376. package/docs/api/classes/InvalidScopeError.md +0 -73
  377. package/docs/api/classes/Logger.md +0 -178
  378. package/docs/api/classes/MissingUserContextError.md +0 -66
  379. package/docs/api/classes/OrganisationContextRequiredError.md +0 -66
  380. package/docs/api/classes/PermissionDeniedError.md +0 -73
  381. package/docs/api/classes/RBACAuditManager.md +0 -297
  382. package/docs/api/classes/RBACCache.md +0 -322
  383. package/docs/api/classes/RBACEngine.md +0 -171
  384. package/docs/api/classes/RBACError.md +0 -76
  385. package/docs/api/classes/RBACNotInitializedError.md +0 -66
  386. package/docs/api/classes/SecureSupabaseClient.md +0 -160
  387. package/docs/api/classes/StorageUtils.md +0 -328
  388. package/docs/api/enums/FileCategory.md +0 -184
  389. package/docs/api/enums/LogLevel.md +0 -54
  390. package/docs/api/enums/RBACErrorCode.md +0 -228
  391. package/docs/api/enums/RPCFunction.md +0 -118
  392. package/docs/api/interfaces/AddressFieldProps.md +0 -241
  393. package/docs/api/interfaces/AddressFieldRef.md +0 -94
  394. package/docs/api/interfaces/AggregateConfig.md +0 -43
  395. package/docs/api/interfaces/AutocompleteOptions.md +0 -75
  396. package/docs/api/interfaces/AvatarProps.md +0 -128
  397. package/docs/api/interfaces/BadgeProps.md +0 -27
  398. package/docs/api/interfaces/ButtonProps.md +0 -53
  399. package/docs/api/interfaces/CalendarProps.md +0 -70
  400. package/docs/api/interfaces/CardProps.md +0 -66
  401. package/docs/api/interfaces/ColorPalette.md +0 -7
  402. package/docs/api/interfaces/ColorShade.md +0 -66
  403. package/docs/api/interfaces/ComplianceResult.md +0 -30
  404. package/docs/api/interfaces/DataAccessRecord.md +0 -96
  405. package/docs/api/interfaces/DataRecord.md +0 -11
  406. package/docs/api/interfaces/DataTableAction.md +0 -249
  407. package/docs/api/interfaces/DataTableColumn.md +0 -504
  408. package/docs/api/interfaces/DataTableProps.md +0 -625
  409. package/docs/api/interfaces/DataTableToolbarButton.md +0 -96
  410. package/docs/api/interfaces/DatabaseComplianceResult.md +0 -85
  411. package/docs/api/interfaces/DatabaseIssue.md +0 -41
  412. package/docs/api/interfaces/EmptyStateConfig.md +0 -61
  413. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +0 -235
  414. package/docs/api/interfaces/EventAppRoleData.md +0 -71
  415. package/docs/api/interfaces/ExportColumn.md +0 -90
  416. package/docs/api/interfaces/ExportOptions.md +0 -126
  417. package/docs/api/interfaces/FileDisplayProps.md +0 -249
  418. package/docs/api/interfaces/FileMetadata.md +0 -129
  419. package/docs/api/interfaces/FileReference.md +0 -118
  420. package/docs/api/interfaces/FileSizeLimits.md +0 -7
  421. package/docs/api/interfaces/FileUploadOptions.md +0 -139
  422. package/docs/api/interfaces/FileUploadProps.md +0 -293
  423. package/docs/api/interfaces/FooterProps.md +0 -105
  424. package/docs/api/interfaces/FormFieldProps.md +0 -166
  425. package/docs/api/interfaces/FormProps.md +0 -113
  426. package/docs/api/interfaces/GrantEventAppRoleParams.md +0 -122
  427. package/docs/api/interfaces/InactivityWarningModalProps.md +0 -115
  428. package/docs/api/interfaces/InputProps.md +0 -53
  429. package/docs/api/interfaces/LabelProps.md +0 -107
  430. package/docs/api/interfaces/LoggerConfig.md +0 -62
  431. package/docs/api/interfaces/LoginFormProps.md +0 -184
  432. package/docs/api/interfaces/NavigationAccessRecord.md +0 -107
  433. package/docs/api/interfaces/NavigationContextType.md +0 -164
  434. package/docs/api/interfaces/NavigationGuardProps.md +0 -139
  435. package/docs/api/interfaces/NavigationItem.md +0 -120
  436. package/docs/api/interfaces/NavigationMenuProps.md +0 -221
  437. package/docs/api/interfaces/NavigationProviderProps.md +0 -117
  438. package/docs/api/interfaces/Organisation.md +0 -140
  439. package/docs/api/interfaces/OrganisationContextType.md +0 -388
  440. package/docs/api/interfaces/OrganisationMembership.md +0 -140
  441. package/docs/api/interfaces/OrganisationProviderProps.md +0 -76
  442. package/docs/api/interfaces/OrganisationSecurityError.md +0 -62
  443. package/docs/api/interfaces/PaceAppLayoutProps.md +0 -406
  444. package/docs/api/interfaces/PaceLoginPageProps.md +0 -47
  445. package/docs/api/interfaces/PageAccessRecord.md +0 -85
  446. package/docs/api/interfaces/PagePermissionContextType.md +0 -140
  447. package/docs/api/interfaces/PagePermissionGuardProps.md +0 -153
  448. package/docs/api/interfaces/PagePermissionProviderProps.md +0 -119
  449. package/docs/api/interfaces/PaletteData.md +0 -41
  450. package/docs/api/interfaces/ParsedAddress.md +0 -120
  451. package/docs/api/interfaces/PermissionEnforcerProps.md +0 -153
  452. package/docs/api/interfaces/ProgressProps.md +0 -42
  453. package/docs/api/interfaces/ProtectedRouteProps.md +0 -97
  454. package/docs/api/interfaces/PublicPageFooterProps.md +0 -112
  455. package/docs/api/interfaces/PublicPageHeaderProps.md +0 -125
  456. package/docs/api/interfaces/PublicPageLayoutProps.md +0 -198
  457. package/docs/api/interfaces/QuickFix.md +0 -52
  458. package/docs/api/interfaces/RBACAccessValidateParams.md +0 -52
  459. package/docs/api/interfaces/RBACAccessValidateResult.md +0 -41
  460. package/docs/api/interfaces/RBACAuditLogParams.md +0 -85
  461. package/docs/api/interfaces/RBACAuditLogResult.md +0 -52
  462. package/docs/api/interfaces/RBACConfig.md +0 -133
  463. package/docs/api/interfaces/RBACContext.md +0 -52
  464. package/docs/api/interfaces/RBACLogger.md +0 -112
  465. package/docs/api/interfaces/RBACPageAccessCheckParams.md +0 -74
  466. package/docs/api/interfaces/RBACPerformanceMetrics.md +0 -138
  467. package/docs/api/interfaces/RBACPermissionCheckParams.md +0 -74
  468. package/docs/api/interfaces/RBACPermissionCheckResult.md +0 -52
  469. package/docs/api/interfaces/RBACPermissionsGetParams.md +0 -63
  470. package/docs/api/interfaces/RBACPermissionsGetResult.md +0 -63
  471. package/docs/api/interfaces/RBACResult.md +0 -58
  472. package/docs/api/interfaces/RBACRoleGrantParams.md +0 -63
  473. package/docs/api/interfaces/RBACRoleGrantResult.md +0 -52
  474. package/docs/api/interfaces/RBACRoleRevokeParams.md +0 -63
  475. package/docs/api/interfaces/RBACRoleRevokeResult.md +0 -52
  476. package/docs/api/interfaces/RBACRoleValidateParams.md +0 -52
  477. package/docs/api/interfaces/RBACRoleValidateResult.md +0 -63
  478. package/docs/api/interfaces/RBACRolesListParams.md +0 -52
  479. package/docs/api/interfaces/RBACRolesListResult.md +0 -74
  480. package/docs/api/interfaces/RBACSessionTrackParams.md +0 -74
  481. package/docs/api/interfaces/RBACSessionTrackResult.md +0 -52
  482. package/docs/api/interfaces/ResourcePermissions.md +0 -155
  483. package/docs/api/interfaces/RevokeEventAppRoleParams.md +0 -100
  484. package/docs/api/interfaces/RoleBasedRouterContextType.md +0 -151
  485. package/docs/api/interfaces/RoleBasedRouterProps.md +0 -156
  486. package/docs/api/interfaces/RoleManagementResult.md +0 -52
  487. package/docs/api/interfaces/RouteAccessRecord.md +0 -107
  488. package/docs/api/interfaces/RouteConfig.md +0 -134
  489. package/docs/api/interfaces/RuntimeComplianceResult.md +0 -55
  490. package/docs/api/interfaces/SecureDataContextType.md +0 -168
  491. package/docs/api/interfaces/SecureDataProviderProps.md +0 -132
  492. package/docs/api/interfaces/SessionRestorationLoaderProps.md +0 -34
  493. package/docs/api/interfaces/SetupIssue.md +0 -41
  494. package/docs/api/interfaces/StorageConfig.md +0 -41
  495. package/docs/api/interfaces/StorageFileInfo.md +0 -74
  496. package/docs/api/interfaces/StorageFileMetadata.md +0 -151
  497. package/docs/api/interfaces/StorageListOptions.md +0 -99
  498. package/docs/api/interfaces/StorageListResult.md +0 -41
  499. package/docs/api/interfaces/StorageUploadOptions.md +0 -101
  500. package/docs/api/interfaces/StorageUploadResult.md +0 -63
  501. package/docs/api/interfaces/StorageUrlOptions.md +0 -60
  502. package/docs/api/interfaces/StyleImport.md +0 -19
  503. package/docs/api/interfaces/SwitchProps.md +0 -34
  504. package/docs/api/interfaces/TabsContentProps.md +0 -9
  505. package/docs/api/interfaces/TabsListProps.md +0 -9
  506. package/docs/api/interfaces/TabsProps.md +0 -9
  507. package/docs/api/interfaces/TabsTriggerProps.md +0 -50
  508. package/docs/api/interfaces/TextareaProps.md +0 -53
  509. package/docs/api/interfaces/ToastActionElement.md +0 -9
  510. package/docs/api/interfaces/ToastProps.md +0 -9
  511. package/docs/api/interfaces/UnifiedAuthContextType.md +0 -820
  512. package/docs/api/interfaces/UnifiedAuthProviderProps.md +0 -171
  513. package/docs/api/interfaces/UseFormDialogOptions.md +0 -62
  514. package/docs/api/interfaces/UseFormDialogReturn.md +0 -117
  515. package/docs/api/interfaces/UseInactivityTrackerOptions.md +0 -136
  516. package/docs/api/interfaces/UseInactivityTrackerReturn.md +0 -123
  517. package/docs/api/interfaces/UsePublicEventLogoOptions.md +0 -87
  518. package/docs/api/interfaces/UsePublicEventLogoReturn.md +0 -81
  519. package/docs/api/interfaces/UsePublicEventOptions.md +0 -34
  520. package/docs/api/interfaces/UsePublicEventReturn.md +0 -68
  521. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +0 -47
  522. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +0 -120
  523. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +0 -94
  524. package/docs/api/interfaces/UseResolvedScopeOptions.md +0 -47
  525. package/docs/api/interfaces/UseResolvedScopeReturn.md +0 -47
  526. package/docs/api/interfaces/UseResourcePermissionsOptions.md +0 -34
  527. package/docs/api/interfaces/UserEventAccess.md +0 -118
  528. package/docs/api/interfaces/UserMenuProps.md +0 -86
  529. package/docs/api/interfaces/UserProfile.md +0 -63
  530. package/docs/migration/quick-migration-guide.md +0 -356
  531. package/docs/migration/service-architecture.md +0 -281
  532. package/src/components/EventSelector/EventSelector.test.tsx +0 -720
  533. package/src/components/EventSelector/EventSelector.tsx +0 -420
  534. package/src/components/EventSelector/index.ts +0 -3
  535. package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +0 -784
  536. package/src/components/OrganisationSelector/OrganisationSelector.tsx +0 -324
  537. package/src/components/OrganisationSelector/index.ts +0 -9
  538. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
  539. package/src/hooks/useSecureDataAccess.test.ts +0 -559
  540. package/src/hooks/useSecureDataAccess.ts +0 -681
  541. /package/dist/{DataTable-DQ7RSOHE.js.map → DataTable-THFPBKTP.js.map} +0 -0
  542. /package/dist/{UnifiedAuthProvider-ATAP5UTR.js.map → UnifiedAuthProvider-KAGUYQ4J.js.map} +0 -0
  543. /package/dist/{api-N774RPUA.js.map → api-IAGWF3ZG.js.map} +0 -0
  544. /package/dist/{audit-B5P6FFIR.js.map → audit-V53FV5AG.js.map} +0 -0
  545. /package/dist/{chunk-7D4SUZUM.js.map → chunk-DGUM43GV.js.map} +0 -0
  546. /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
  547. /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
  548. /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
  549. /package/docs/migration/{REACT_19_MIGRATION.md → V0.6.0_REACT_19_MIGRATION.md} +0 -0
@@ -42,6 +42,11 @@ interface DataTableErrorBoundaryProps {
42
42
  // ERROR BOUNDARY COMPONENT
43
43
  // ============================================================================
44
44
 
45
+ /**
46
+ * Error boundary component for DataTable.
47
+ * Catches errors in the DataTable component tree and displays a fallback UI.
48
+ * Provides error recovery with retry functionality.
49
+ */
45
50
  export class DataTableErrorBoundary extends Component<
46
51
  DataTableErrorBoundaryProps,
47
52
  ErrorBoundaryState
@@ -195,6 +200,12 @@ export class DataTableErrorBoundary extends Component<
195
200
  // HOOK FOR ERROR BOUNDARY
196
201
  // ============================================================================
197
202
 
203
+ /**
204
+ * Hook for programmatically triggering error boundary reset.
205
+ * Useful for error recovery in DataTable components.
206
+ *
207
+ * @returns Object with error state and reset function
208
+ */
198
209
  export function useDataTableErrorBoundary() {
199
210
  const [error, setError] = React.useState<Error | null>(null);
200
211
 
@@ -0,0 +1,559 @@
1
+ import React from 'react';
2
+ import { Edit, Trash, ChevronUp, ChevronDown, ChevronsUpDown } from 'lucide-react';
3
+ import type { Table } from '@tanstack/react-table';
4
+ import { cn } from '../../../utils/core/cn';
5
+ import { Button } from '../../Button/Button';
6
+ import { DataTableToolbar } from './DataTableToolbar';
7
+ import { UnifiedTableBody } from './UnifiedTableBody';
8
+ import { PaginationControls, EnhancedPaginationControls } from './PaginationControls';
9
+ import { DataTableModals } from './DataTableModals';
10
+ import { announceSortChange } from '../utils/a11yUtils';
11
+ import { exportToCSVWithTableRows } from '../utils/exportUtils';
12
+ import { getTableClasses } from '../styles';
13
+ import { toast } from '../../../hooks/useToast';
14
+ import type {
15
+ AggregateConfig,
16
+ DataRecord,
17
+ DataTableAction,
18
+ DataTableColumn,
19
+ DataTableRBACConfig,
20
+ EmptyStateConfig,
21
+ ExportOptions,
22
+ HierarchicalConfig,
23
+ NormalizedDataTableFeatureConfig,
24
+ PaginationMode,
25
+ } from '../types';
26
+ import type { DataTableState, DataTableStateActions } from '../hooks/useDataTableState';
27
+ import type { UseDataTablePermissionsReturn } from '../hooks/useDataTablePermissions';
28
+ import type { GetRowId } from '../types';
29
+ import type { ImportModalConfig } from './ImportModal';
30
+ import type { UseDataTableDataPipelineResult } from '../hooks/useDataTableDataPipeline';
31
+ import type { UseKeyboardNavigationReturn } from '../hooks/useKeyboardNavigation';
32
+ import type { Column } from '@tanstack/react-table';
33
+ import type { createLogger } from '../../../utils/core/logger';
34
+
35
+ interface DataTableLayoutProps<TData extends DataRecord> {
36
+ table: Table<TData>;
37
+ title?: string;
38
+ description?: string;
39
+ variant: 'default' | 'compact' | 'spacious';
40
+ className?: string;
41
+ columns: DataTableColumn<TData>[];
42
+ secureFeatures: NormalizedDataTableFeatureConfig;
43
+ enhancedPagination: boolean;
44
+ searchQuery: string;
45
+ onSearch: (value: string) => void;
46
+ state: DataTableState<TData>;
47
+ stateActions: DataTableStateActions<TData>;
48
+ rowSelection: Record<string, boolean>;
49
+ onCreateRow?: (data: Partial<TData>) => void;
50
+ onEditRow?: (row: TData, data: Partial<TData>) => void;
51
+ onImport?: (data: TData[]) => void | Promise<void>;
52
+ onExport?: (options: ExportOptions<TData>) => void | Promise<void>;
53
+ onDeleteSelected?: (selectedRows: Record<string, boolean>) => void;
54
+ rbac: DataTableRBACConfig;
55
+ permissions: UseDataTablePermissionsReturn['permissions'];
56
+ effectiveActions: DataTableAction<TData>[];
57
+ finalPageSizeOptions: number[];
58
+ finalPaginationMode: PaginationMode;
59
+ finalDataCount: number;
60
+ isLoading: boolean;
61
+ finalTableData: TData[];
62
+ aggregates: AggregateConfig[];
63
+ resolvedGetRowId: GetRowId<TData>;
64
+ data: TData[];
65
+ emptyState?: EmptyStateConfig | React.ReactElement<any>;
66
+ virtualHeight: number;
67
+ hierarchical?: HierarchicalConfig;
68
+ hierarchicalState: UseDataTableDataPipelineResult<TData>['hierarchicalState'];
69
+ logger: ReturnType<typeof createLogger>;
70
+ secureHandlers: {
71
+ onEditRow?: ((row: TData, data: Partial<TData>) => void) | undefined;
72
+ onDeleteRow?: ((row: TData) => void) | undefined;
73
+ onCreateRow?: ((data: Partial<TData>) => void) | undefined;
74
+ onImport?: ((data: TData[]) => void | Promise<void>) | undefined;
75
+ onExport?: ((options: ExportOptions<TData>) => void | Promise<void>) | undefined;
76
+ onDeleteSelected?: ((selectedRows: Record<string, boolean>) => void) | undefined;
77
+ };
78
+ importModalConfig?: ImportModalConfig;
79
+ keyboardNavigation: UseKeyboardNavigationReturn;
80
+ lastFocusedElementRef: React.RefObject<HTMLElement | null>;
81
+ }
82
+
83
+ const SYSTEM_COLUMN_IDS = new Set(['select', 'actions']);
84
+
85
+ /**
86
+ * Main layout component for DataTable.
87
+ * Orchestrates all DataTable UI components including toolbar, body, pagination, and modals.
88
+ *
89
+ * @template TData - The type of data records in the table
90
+ * @param props - DataTable layout configuration
91
+ * @returns The complete DataTable UI layout
92
+ */
93
+ export function DataTableLayout<TData extends DataRecord>({
94
+ table,
95
+ title,
96
+ description,
97
+ variant,
98
+ className,
99
+ columns,
100
+ secureFeatures,
101
+ enhancedPagination,
102
+ searchQuery,
103
+ onSearch,
104
+ state,
105
+ stateActions,
106
+ rowSelection,
107
+ onCreateRow,
108
+ onEditRow,
109
+ onImport,
110
+ onExport,
111
+ onDeleteSelected,
112
+ rbac,
113
+ permissions,
114
+ effectiveActions,
115
+ finalPageSizeOptions,
116
+ finalPaginationMode,
117
+ finalDataCount,
118
+ isLoading,
119
+ finalTableData,
120
+ aggregates,
121
+ resolvedGetRowId,
122
+ data,
123
+ emptyState,
124
+ virtualHeight,
125
+ hierarchical,
126
+ hierarchicalState,
127
+ logger,
128
+ secureHandlers,
129
+ importModalConfig,
130
+ keyboardNavigation,
131
+ lastFocusedElementRef,
132
+ }: DataTableLayoutProps<TData>) {
133
+ const handleExport = async () => {
134
+ try {
135
+ const tableRows = table.getFilteredRowModel().rows;
136
+ const tableColumns = table.getAllColumns();
137
+ const visibleTableColumns = tableColumns.filter((col) => !SYSTEM_COLUMN_IDS.has(col.id) && col.getIsVisible());
138
+
139
+ const visibleColumns: DataTableColumn<TData>[] = [];
140
+ const columnIdToTableColumn = new Map<string, Column<TData>>();
141
+
142
+ visibleTableColumns.forEach((tableCol) => {
143
+ const originalCol = columns.find((col) => {
144
+ const colId = col.id || col.accessorKey;
145
+ return colId && String(colId) === tableCol.id;
146
+ });
147
+
148
+ if (!originalCol) return;
149
+
150
+ columnIdToTableColumn.set(tableCol.id, tableCol);
151
+ visibleColumns.push(originalCol);
152
+ });
153
+
154
+ const timestamp = new Date().toISOString().split('T')[0];
155
+ const filename = title
156
+ ? `${title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}_${timestamp}.csv`
157
+ : `data_export_${timestamp}.csv`;
158
+
159
+ const exportOptions: ExportOptions<TData> = {
160
+ tableRows,
161
+ allColumns: columns,
162
+ visibleColumns,
163
+ columnIdToTableColumn,
164
+ data,
165
+ filename,
166
+ table,
167
+ };
168
+
169
+ if (secureHandlers.onExport) {
170
+ await secureHandlers.onExport(exportOptions);
171
+ return;
172
+ }
173
+
174
+ const exportColumns: Array<{
175
+ header?: string;
176
+ id?: string;
177
+ accessorKey?: string;
178
+ accessorFn?: (row: any) => any;
179
+ editAccessorKey?: string;
180
+ isIdColumn?: boolean;
181
+ }> = exportOptions.visibleColumns.map((col) => {
182
+ const colId = col.id || col.accessorKey;
183
+ const hasAccessorFn = 'accessorFn' in col && (col as any).accessorFn;
184
+
185
+ return {
186
+ ...col,
187
+ header: typeof col.header === 'string'
188
+ ? col.header
189
+ : col.accessorKey || colId || 'Column',
190
+ id: colId ? String(colId) : undefined,
191
+ accessorFn: hasAccessorFn ? (col as any).accessorFn : undefined,
192
+ };
193
+ });
194
+
195
+ await exportToCSVWithTableRows(
196
+ exportOptions.tableRows,
197
+ exportColumns,
198
+ exportOptions.columnIdToTableColumn,
199
+ exportOptions.filename
200
+ );
201
+
202
+ toast({
203
+ title: 'Export Successful',
204
+ description: `Data exported to ${exportOptions.filename}`,
205
+ variant: 'default',
206
+ });
207
+ } catch (error) {
208
+ logger.error('Failed to export data:', error);
209
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
210
+ toast({
211
+ title: 'Export Failed',
212
+ description: `Failed to export data: ${errorMessage}`,
213
+ variant: 'destructive',
214
+ });
215
+ }
216
+ };
217
+
218
+ const PaginationComponent = enhancedPagination || finalPaginationMode !== 'client'
219
+ ? EnhancedPaginationControls
220
+ : PaginationControls;
221
+
222
+ const visibleColumns = table?.getVisibleFlatColumns() || [];
223
+ const dataColumns = visibleColumns.filter((col) => !SYSTEM_COLUMN_IDS.has(col.id)).length;
224
+ const hasSelectColumn = visibleColumns.some((col) => col.id === 'select');
225
+ const hasActionsColumn = visibleColumns.some((col) => col.id === 'actions');
226
+
227
+ return (
228
+ <>
229
+ <table
230
+ className={getTableClasses({
231
+ isFixed: false,
232
+ variant,
233
+ className: cn('border-collapse relative w-full', className),
234
+ })}
235
+ aria-label={title}
236
+ aria-describedby={description ? 'table-description' : undefined}
237
+ aria-busy={isLoading ? 'true' : 'false'}
238
+ >
239
+ <caption className="text-left pb-2">
240
+ {(title || description) && (
241
+ <>
242
+ {title && <h2>{title}</h2>}
243
+ {description && <p id="table-description">{description}</p>}
244
+ </>
245
+ )}
246
+ <DataTableToolbar
247
+ features={secureFeatures}
248
+ globalFilter={searchQuery}
249
+ onGlobalFilterChange={onSearch}
250
+ columns={columns}
251
+ grouping={state.grouping}
252
+ onGroupByChange={(columnId) => {
253
+ stateActions.setGrouping(columnId ? [columnId] : []);
254
+ }}
255
+ tableColumns={table?.getAllColumns() || []}
256
+ onColumnVisibilityChange={(columnId: string, visible: boolean) => {
257
+ stateActions.setColumnVisibility({ ...state.columnVisibility, [columnId]: visible });
258
+ }}
259
+ onCreateRow={secureFeatures.creation && secureHandlers.onCreateRow ? () => stateActions.setCreating(true) : undefined}
260
+ onImportClick={() => {
261
+ if (document.activeElement instanceof HTMLElement) {
262
+ lastFocusedElementRef.current = document.activeElement;
263
+ }
264
+ stateActions.setImportModal(true);
265
+ }}
266
+ onExport={handleExport}
267
+ rowSelection={rowSelection}
268
+ onDeleteSelected={
269
+ secureHandlers.onDeleteSelected
270
+ ? async (selectedRows: Record<string, boolean>) => {
271
+ const selectedCount = Object.values(selectedRows).filter(Boolean).length;
272
+ if (selectedCount === 0) {
273
+ toast({
274
+ title: 'No Selection',
275
+ description: 'Please select at least one row to delete',
276
+ variant: 'default',
277
+ });
278
+ return;
279
+ }
280
+ try {
281
+ const result = secureHandlers.onDeleteSelected!(selectedRows) as any;
282
+ if (result !== undefined && result !== null && typeof result === 'object' && typeof result.then === 'function') {
283
+ await result;
284
+ }
285
+ toast({
286
+ title: 'Delete Successful',
287
+ description: `Successfully deleted ${selectedCount} ${selectedCount === 1 ? 'row' : 'rows'}`,
288
+ variant: 'default',
289
+ });
290
+ } catch (error) {
291
+ logger.error('Bulk delete error:', error);
292
+ toast({
293
+ title: 'Delete Failed',
294
+ description: error instanceof Error ? error.message : 'Failed to delete selected rows',
295
+ variant: 'destructive',
296
+ });
297
+ }
298
+ }
299
+ : undefined
300
+ }
301
+ onToggleFilterRow={() => stateActions.setFilterRow(!state.showFilterRow)}
302
+ showFilterRow={state.showFilterRow}
303
+ rbac={rbac}
304
+ permissions={permissions}
305
+ />
306
+ </caption>
307
+
308
+ <colgroup>
309
+ {hasSelectColumn && <col span={1} data-col-type="select" />}
310
+ <col span={dataColumns} data-col-type="data" />
311
+ {hasActionsColumn && <col span={1} data-col-type="actions" />}
312
+ </colgroup>
313
+
314
+ <thead>
315
+ {table?.getHeaderGroups().map((headerGroup) => {
316
+ const visibleHeaders = headerGroup.headers.filter((header) => {
317
+ return typeof header.column.getIsVisible === 'function'
318
+ ? header.column.getIsVisible()
319
+ : true;
320
+ });
321
+
322
+ return (
323
+ <tr key={headerGroup.id}>
324
+ {visibleHeaders.map((header, index) => {
325
+ const isFirst = index === 0;
326
+ const isLast = index === visibleHeaders.length - 1;
327
+ const isSortable = header.column.getCanSort();
328
+ const ariaSort = isSortable
329
+ ? header.column.getIsSorted() === 'asc'
330
+ ? 'ascending'
331
+ : header.column.getIsSorted() === 'desc'
332
+ ? 'descending'
333
+ : 'none'
334
+ : undefined;
335
+ const isRightAligned = header.column.columnDef.meta?.align === 'right';
336
+
337
+ const handleSortClick = (event: React.MouseEvent) => {
338
+ const originalHandler = header.column.getToggleSortingHandler();
339
+ if (originalHandler) {
340
+ originalHandler(event);
341
+ }
342
+
343
+ const columnName =
344
+ typeof header.column.columnDef.header === 'string'
345
+ ? header.column.columnDef.header
346
+ : 'column';
347
+ const currentSort = header.column.getIsSorted();
348
+ const newSort = currentSort === 'asc' ? 'desc' : currentSort === 'desc' ? null : 'asc';
349
+ announceSortChange(columnName, newSort);
350
+ };
351
+
352
+ const headerKeyboardHandlers = keyboardNavigation.getHeaderKeyboardHandlers(
353
+ header.index,
354
+ () => {
355
+ const originalHandler = header.column.getToggleSortingHandler();
356
+ if (originalHandler) {
357
+ originalHandler({} as any);
358
+ }
359
+
360
+ const columnName =
361
+ typeof header.column.columnDef.header === 'string'
362
+ ? header.column.columnDef.header
363
+ : 'column';
364
+ const currentSort = header.column.getIsSorted();
365
+ const newSort = currentSort === 'asc' ? 'desc' : currentSort === 'desc' ? null : 'asc';
366
+ announceSortChange(columnName, newSort);
367
+ }
368
+ );
369
+
370
+ return (
371
+ <th
372
+ key={header.id}
373
+ className={cn(
374
+ 'px-3 py-2 bg-main-200',
375
+ isRightAligned ? 'text-right' : 'text-left',
376
+ isFirst && 'rounded-l-md',
377
+ isLast && 'rounded-r-md'
378
+ )}
379
+ scope="col"
380
+ role="columnheader"
381
+ {...(isSortable ? { 'aria-sort': ariaSort } : {})}
382
+ {...(isSortable ? headerKeyboardHandlers : {})}
383
+ >
384
+ {header.isPlaceholder ? null : isSortable ? (
385
+ <Button
386
+ variant="ghost"
387
+ className={`h-auto p-0 font-bold hover:bg-transparent ${isRightAligned ? 'justify-end' : 'justify-start'}`}
388
+ onClick={handleSortClick}
389
+ {...headerKeyboardHandlers}
390
+ aria-label={`Sort by ${
391
+ typeof header.column.columnDef.header === 'string'
392
+ ? header.column.columnDef.header
393
+ : 'column'
394
+ }`}
395
+ tabIndex={0}
396
+ >
397
+ {typeof header.column.columnDef.header === 'function'
398
+ ? header.column.columnDef.header(header.getContext())
399
+ : header.column.columnDef.header}
400
+ {header.column.getIsSorted() === 'asc' ? (
401
+ <ChevronUp className="size-4" />
402
+ ) : header.column.getIsSorted() === 'desc' ? (
403
+ <ChevronDown className="size-4" />
404
+ ) : (
405
+ <ChevronsUpDown className="size-4" />
406
+ )}
407
+ </Button>
408
+ ) : typeof header.column.columnDef.header === 'function' ? (
409
+ header.column.columnDef.header(header.getContext())
410
+ ) : (
411
+ header.column.columnDef.header
412
+ )}
413
+ </th>
414
+ );
415
+ })}
416
+ </tr>
417
+ );
418
+ })}
419
+ </thead>
420
+
421
+ <UnifiedTableBody
422
+ table={table}
423
+ isCreating={state.isCreating}
424
+ creationData={state.creationData}
425
+ onCreationDataChange={stateActions.setCreationData}
426
+ onSaveCreation={() => {
427
+ if (onCreateRow) {
428
+ onCreateRow(state.creationData as Partial<TData>);
429
+ stateActions.clearCreationData();
430
+ stateActions.setCreating(false);
431
+ }
432
+ }}
433
+ onCancelCreation={() => {
434
+ stateActions.clearCreationData();
435
+ stateActions.setCreating(false);
436
+ }}
437
+ editingRowId={state.editingRowId}
438
+ editingData={state.editingData}
439
+ onEditingDataChange={(data) => {
440
+ if (state.editingRowId) {
441
+ stateActions.setEditingRow(state.editingRowId, data);
442
+ }
443
+ }}
444
+ onSaveEditing={() => {
445
+ if (onEditRow && state.editingRowId) {
446
+ const originalRow = data.find((row) => {
447
+ try {
448
+ const rowId = resolvedGetRowId(row, 0);
449
+ return rowId === state.editingRowId;
450
+ } catch {
451
+ return false;
452
+ }
453
+ });
454
+ if (originalRow) {
455
+ onEditRow(originalRow, state.editingData as Partial<TData>);
456
+ }
457
+ }
458
+ stateActions.clearEditing();
459
+ }}
460
+ onCancelEditing={() => {
461
+ stateActions.clearEditing();
462
+ }}
463
+ grouping={state.grouping}
464
+ aggregates={aggregates}
465
+ getRowId={resolvedGetRowId}
466
+ emptyState={React.isValidElement(emptyState) ? undefined : (emptyState as any)}
467
+ isFiltered={searchQuery !== '' || state.columnFilters.length > 0}
468
+ onClearFilters={() => {
469
+ onSearch('');
470
+ stateActions.setColumnFilters([]);
471
+ }}
472
+ enableFiltering={secureFeatures.filtering}
473
+ showFilterRow={state.showFilterRow}
474
+ dataLength={finalTableData?.length || 0}
475
+ virtualHeight={virtualHeight}
476
+ forceVirtualization={false}
477
+ hierarchical={
478
+ secureFeatures.hierarchical && hierarchical?.enabled && hierarchicalState
479
+ ? {
480
+ ...hierarchical,
481
+ state: hierarchicalState,
482
+ expandAll: hierarchicalState.expandAll,
483
+ collapseAll: hierarchicalState.collapseAll,
484
+ isAllExpanded:
485
+ hierarchicalState.getExpandedIds().length > 0 &&
486
+ hierarchicalState.getExpandedIds().length === (finalTableData as any[]).filter((row) => (row as any).isParent).length,
487
+ hasAnyChildren: (finalTableData as any[]).some((row) => (row as any).isParent),
488
+ }
489
+ : undefined
490
+ }
491
+ actions={effectiveActions}
492
+ rbac={rbac}
493
+ permissions={permissions}
494
+ />
495
+
496
+ {secureFeatures.pagination && (
497
+ <tfoot>
498
+ <tr>
499
+ <td colSpan={visibleColumns.length}>
500
+ <PaginationComponent
501
+ table={table}
502
+ pageSizeOptions={finalPageSizeOptions}
503
+ paginationMode={finalPaginationMode}
504
+ totalCount={finalDataCount}
505
+ isLoading={isLoading}
506
+ />
507
+ </td>
508
+ </tr>
509
+ </tfoot>
510
+ )}
511
+ </table>
512
+
513
+ <DataTableModals
514
+ showImportModal={state.showImportModal}
515
+ onCloseImportModal={() => stateActions.setImportModal(false)}
516
+ onImport={async (modalData: TData[]) => {
517
+ if (onImport) {
518
+ try {
519
+ const result = onImport(modalData);
520
+ if (result && typeof result.then === 'function') {
521
+ await result;
522
+ }
523
+
524
+ toast({
525
+ title: 'Import Successful',
526
+ description: `Successfully imported ${modalData.length} ${modalData.length === 1 ? 'row' : 'rows'}`,
527
+ variant: 'default',
528
+ });
529
+ } catch (error) {
530
+ logger.error('Import error:', error);
531
+ toast({
532
+ title: 'Import Failed',
533
+ description: error instanceof Error ? error.message : 'Failed to import data',
534
+ variant: 'destructive',
535
+ });
536
+ return;
537
+ }
538
+ } else {
539
+ logger.error('onImport handler not provided');
540
+ toast({
541
+ title: 'Import Not Configured',
542
+ description: 'Import functionality requires an onImport handler to be provided.',
543
+ variant: 'destructive',
544
+ });
545
+ return;
546
+ }
547
+ stateActions.setImportModal(false);
548
+ }}
549
+ importModalConfig={importModalConfig}
550
+ columns={columns.map((col) => ({
551
+ id: col.id,
552
+ accessorKey: col.accessorKey,
553
+ header: typeof col.header === 'string' ? col.header : undefined,
554
+ editAccessorKey: col.editAccessorKey,
555
+ }))}
556
+ />
557
+ </>
558
+ );
559
+ }
@@ -175,6 +175,14 @@ export interface DataTableModalsProps<TData extends Record<string, unknown> = Re
175
175
  * />
176
176
  * ```
177
177
  */
178
+ /**
179
+ * Container component for all DataTable modal dialogs.
180
+ * Manages import modals and other data table related dialogs.
181
+ *
182
+ * @template TData - The type of data records in the table
183
+ * @param props - Modal configuration and handlers
184
+ * @returns The rendered modals
185
+ */
178
186
  export function DataTableModals<TData extends Record<string, unknown> = Record<string, unknown>>({
179
187
  showImportModal,
180
188
  onCloseImportModal,
@@ -141,6 +141,14 @@ interface DataTableToolbarProps<TData extends DataRecord = DataRecord> {
141
141
  * />
142
142
  * ```
143
143
  */
144
+ /**
145
+ * Toolbar component for DataTable.
146
+ * Provides search, filters, export/import, and other table actions.
147
+ *
148
+ * @template TData - The type of data records in the table
149
+ * @param props - Toolbar configuration and handlers
150
+ * @returns The rendered toolbar
151
+ */
144
152
  export function DataTableToolbar<TData extends DataRecord>({
145
153
  features,
146
154
  rbac,
@@ -4,6 +4,10 @@ import { ChevronUp, ChevronDown,ChevronsUpDown } from 'lucide-react';
4
4
  import { cn } from '../../../utils/core/cn';
5
5
  import type { Header } from '@tanstack/react-table';
6
6
 
7
+ /**
8
+ * Props for the DraggableColumnHeader component.
9
+ * @template TData - The type of data records in the table
10
+ */
7
11
  interface DraggableColumnHeaderProps<TData> {
8
12
  header: Header<TData, unknown>;
9
13
  onMoveLeft?: () => void;
@@ -14,6 +18,14 @@ interface DraggableColumnHeaderProps<TData> {
14
18
  onColumnDrop?: (draggedColumnId: string, targetColumnId: string) => void;
15
19
  }
16
20
 
21
+ /**
22
+ * Draggable column header component for DataTable.
23
+ * Provides drag-and-drop column reordering functionality.
24
+ *
25
+ * @template TData - The type of data records in the table
26
+ * @param props - Draggable column header configuration
27
+ * @returns The rendered draggable column header
28
+ */
17
29
  export function DraggableColumnHeader<TData>({
18
30
  header,
19
31
  onMoveLeft,