@jmruthers/pace-core 0.5.134 → 0.5.136

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 (522) hide show
  1. package/dist/{DataTable-C7GaRZye.d.ts → DataTable-CWAZZcXC.d.ts} +1 -1
  2. package/dist/{DataTable-A36PJG6N.js → DataTable-CYOHOX3O.js} +25 -13
  3. package/dist/{PublicLoadingSpinner-CUAnTvcg.d.ts → EventLogo-801uofbR.d.ts} +51 -135
  4. package/dist/UnifiedAuthProvider-5E5TUNMS.js +17 -0
  5. package/dist/{UnifiedAuthProvider-BVKmQd9u.d.ts → UnifiedAuthProvider-DJxGTftH.d.ts} +1 -1
  6. package/dist/{api-TNIBJWLM.js → api-45XYYO2A.js} +4 -3
  7. package/dist/{audit-T36HM7IM.js → audit-64X3VJXB.js} +3 -2
  8. package/dist/{chunk-CTJRBUX2.js → chunk-2TWNJ46Y.js} +2 -2
  9. package/dist/{chunk-UJI6WSMD.js → chunk-444EZN6N.js} +3 -3
  10. package/dist/chunk-444EZN6N.js.map +1 -0
  11. package/dist/{chunk-3CG5L6RN.js → chunk-4MT5BGGL.js} +90 -73
  12. package/dist/chunk-4MT5BGGL.js.map +1 -0
  13. package/dist/{chunk-PYUXFQJ3.js → chunk-56XJ3TU6.js} +2 -2
  14. package/dist/chunk-56XJ3TU6.js.map +1 -0
  15. package/dist/chunk-5DPZ5EAT.js +60 -0
  16. package/dist/chunk-5DPZ5EAT.js.map +1 -0
  17. package/dist/{chunk-66C4BSAY.js → chunk-ANBQRTPX.js} +9 -2
  18. package/dist/chunk-ANBQRTPX.js.map +1 -0
  19. package/dist/chunk-APIBCTL2.js +670 -0
  20. package/dist/chunk-APIBCTL2.js.map +1 -0
  21. package/dist/{chunk-GKHF54DI.js → chunk-BESYRHQM.js} +10 -4
  22. package/dist/chunk-BESYRHQM.js.map +1 -0
  23. package/dist/{chunk-WP5I5GLN.js → chunk-BVYWGZVV.js} +112 -97
  24. package/dist/chunk-BVYWGZVV.js.map +1 -0
  25. package/dist/{chunk-GEVIB2UB.js → chunk-ERISIBYU.js} +14 -5
  26. package/dist/chunk-ERISIBYU.js.map +1 -0
  27. package/dist/{chunk-CQZU6TFE.js → chunk-FHWWBIHA.js} +100 -62
  28. package/dist/chunk-FHWWBIHA.js.map +1 -0
  29. package/dist/{chunk-O3NWNXDY.js → chunk-FMUCXFII.js} +2 -2
  30. package/dist/chunk-FMUCXFII.js.map +1 -0
  31. package/dist/{chunk-GVDR7WNV.js → chunk-HJGGOMQ6.js} +194 -518
  32. package/dist/chunk-HJGGOMQ6.js.map +1 -0
  33. package/dist/{chunk-BDZUMRBD.js → chunk-K2WWTH7O.js} +13 -6
  34. package/dist/chunk-K2WWTH7O.js.map +1 -0
  35. package/dist/{chunk-BYXRHAIF.js → chunk-L6PGMCMD.js} +23 -14
  36. package/dist/chunk-L6PGMCMD.js.map +1 -0
  37. package/dist/chunk-LMC26NLJ.js +84 -0
  38. package/dist/chunk-LMC26NLJ.js.map +1 -0
  39. package/dist/{chunk-M6DDYFUD.js → chunk-LS353YLY.js} +19 -16
  40. package/dist/chunk-LS353YLY.js.map +1 -0
  41. package/dist/{chunk-ZYZCRSBD.js → chunk-LTV3XIJJ.js} +16 -11
  42. package/dist/chunk-LTV3XIJJ.js.map +1 -0
  43. package/dist/{chunk-HMNOSGVA.js → chunk-NOHEVYVX.js} +377 -666
  44. package/dist/chunk-NOHEVYVX.js.map +1 -0
  45. package/dist/{chunk-JCQZ6LA7.js → chunk-Q5QRDWKI.js} +9 -3
  46. package/dist/chunk-Q5QRDWKI.js.map +1 -0
  47. package/dist/chunk-S5OFRT4M.js +94 -0
  48. package/dist/chunk-S5OFRT4M.js.map +1 -0
  49. package/dist/{chunk-3DBFLLLU.js → chunk-SBVILCCA.js} +14 -9
  50. package/dist/chunk-SBVILCCA.js.map +1 -0
  51. package/dist/{chunk-TGIY2AR2.js → chunk-SL2YQDR6.js} +4 -3
  52. package/dist/{chunk-TGIY2AR2.js.map → chunk-SL2YQDR6.js.map} +1 -1
  53. package/dist/{chunk-VZ5OR6HD.js → chunk-TVYPTYOY.js} +55 -179
  54. package/dist/chunk-TVYPTYOY.js.map +1 -0
  55. package/dist/{chunk-ZV77RZMU.js → chunk-XARJS7CD.js} +2 -2
  56. package/dist/chunk-XDNLUEXI.js +138 -0
  57. package/dist/chunk-XDNLUEXI.js.map +1 -0
  58. package/dist/{chunk-F64FFPOZ.js → chunk-YLKIDTUK.js} +26 -20
  59. package/dist/chunk-YLKIDTUK.js.map +1 -0
  60. package/dist/{chunk-5F3NDPJV.js → chunk-ZZ2SS7NI.js} +10 -5
  61. package/dist/chunk-ZZ2SS7NI.js.map +1 -0
  62. package/dist/components.d.ts +7 -287
  63. package/dist/components.js +26 -157
  64. package/dist/components.js.map +1 -1
  65. package/dist/{file-reference-C9isKNPn.d.ts → file-reference-C6Gkn77H.d.ts} +1 -1
  66. package/dist/{formatting-DFcCxUEk.d.ts → formatting-CvUXy2mF.d.ts} +1 -1
  67. package/dist/hooks.d.ts +3 -3
  68. package/dist/hooks.js +22 -16
  69. package/dist/hooks.js.map +1 -1
  70. package/dist/index.d.ts +219 -9
  71. package/dist/index.js +49 -31
  72. package/dist/index.js.map +1 -1
  73. package/dist/providers.d.ts +1 -1
  74. package/dist/providers.js +5 -4
  75. package/dist/rbac/index.js +13 -12
  76. package/dist/styles/index.js +2 -1
  77. package/dist/theming/runtime.d.ts +2 -19
  78. package/dist/theming/runtime.js +2 -1
  79. package/dist/{types-D5rqZQXk.d.ts → types-Dfz9dmVH.d.ts} +12 -1
  80. package/dist/types.d.ts +2 -2
  81. package/dist/types.js +1 -1
  82. package/dist/{useInactivityTracker-MRUU55XI.js → useInactivityTracker-TO6ZOF35.js} +3 -2
  83. package/dist/{usePublicRouteParams-Dyt1tzI9.d.ts → usePublicRouteParams-B7PabvuH.d.ts} +1 -1
  84. package/dist/utils.d.ts +195 -232
  85. package/dist/utils.js +173 -331
  86. package/dist/utils.js.map +1 -1
  87. package/dist/{validation-DnhrNMju.d.ts → validation-8npbysjg.d.ts} +26 -8
  88. package/dist/validation.d.ts +261 -10
  89. package/dist/validation.js +82 -440
  90. package/dist/validation.js.map +1 -1
  91. package/docs/api/classes/ColumnFactory.md +1 -1
  92. package/docs/api/classes/ErrorBoundary.md +6 -6
  93. package/docs/api/classes/InvalidScopeError.md +1 -1
  94. package/docs/api/classes/MissingUserContextError.md +1 -1
  95. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  96. package/docs/api/classes/PermissionDeniedError.md +1 -1
  97. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  98. package/docs/api/classes/RBACAuditManager.md +6 -6
  99. package/docs/api/classes/RBACCache.md +1 -1
  100. package/docs/api/classes/RBACEngine.md +7 -7
  101. package/docs/api/classes/RBACError.md +1 -1
  102. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  103. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  104. package/docs/api/classes/StorageUtils.md +1 -1
  105. package/docs/api/enums/FileCategory.md +1 -1
  106. package/docs/api/interfaces/AggregateConfig.md +4 -4
  107. package/docs/api/interfaces/ButtonProps.md +1 -1
  108. package/docs/api/interfaces/CardProps.md +1 -1
  109. package/docs/api/interfaces/ColorPalette.md +1 -1
  110. package/docs/api/interfaces/ColorShade.md +29 -4
  111. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  112. package/docs/api/interfaces/DataRecord.md +1 -1
  113. package/docs/api/interfaces/DataTableAction.md +18 -18
  114. package/docs/api/interfaces/DataTableColumn.md +61 -1
  115. package/docs/api/interfaces/DataTableProps.md +3 -3
  116. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  117. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  118. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +14 -14
  119. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  120. package/docs/api/interfaces/EventLogoProps.md +152 -0
  121. package/docs/api/interfaces/ExportColumn.md +90 -0
  122. package/docs/api/interfaces/ExportOptions.md +126 -0
  123. package/docs/api/interfaces/FileDisplayProps.md +15 -15
  124. package/docs/api/interfaces/FileMetadata.md +1 -1
  125. package/docs/api/interfaces/FileReference.md +1 -1
  126. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  127. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  128. package/docs/api/interfaces/FileUploadProps.md +1 -1
  129. package/docs/api/interfaces/FooterProps.md +1 -1
  130. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  131. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  132. package/docs/api/interfaces/InputProps.md +1 -1
  133. package/docs/api/interfaces/LabelProps.md +1 -1
  134. package/docs/api/interfaces/LoginFormProps.md +1 -1
  135. package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
  136. package/docs/api/interfaces/NavigationContextType.md +9 -9
  137. package/docs/api/interfaces/NavigationGuardProps.md +10 -10
  138. package/docs/api/interfaces/NavigationItem.md +1 -1
  139. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  140. package/docs/api/interfaces/NavigationProviderProps.md +7 -7
  141. package/docs/api/interfaces/Organisation.md +1 -1
  142. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  143. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  144. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  145. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  146. package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
  147. package/docs/api/interfaces/PaceLoginPageProps.md +4 -4
  148. package/docs/api/interfaces/PageAccessRecord.md +8 -8
  149. package/docs/api/interfaces/PagePermissionContextType.md +8 -8
  150. package/docs/api/interfaces/PagePermissionGuardProps.md +11 -11
  151. package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
  152. package/docs/api/interfaces/PaletteData.md +4 -4
  153. package/docs/api/interfaces/PermissionEnforcerProps.md +11 -11
  154. package/docs/api/interfaces/ProtectedRouteProps.md +6 -6
  155. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  156. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  157. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  158. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  159. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  160. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  161. package/docs/api/interfaces/RBACConfig.md +1 -1
  162. package/docs/api/interfaces/RBACLogger.md +1 -1
  163. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  164. package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
  165. package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
  166. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  167. package/docs/api/interfaces/RouteAccessRecord.md +10 -10
  168. package/docs/api/interfaces/RouteConfig.md +10 -10
  169. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  170. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  171. package/docs/api/interfaces/SessionRestorationLoaderProps.md +21 -0
  172. package/docs/api/interfaces/StorageConfig.md +1 -1
  173. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  174. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  175. package/docs/api/interfaces/StorageListOptions.md +1 -1
  176. package/docs/api/interfaces/StorageListResult.md +1 -1
  177. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  178. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  179. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  180. package/docs/api/interfaces/StyleImport.md +1 -1
  181. package/docs/api/interfaces/SwitchProps.md +1 -1
  182. package/docs/api/interfaces/ToastActionElement.md +1 -1
  183. package/docs/api/interfaces/ToastProps.md +1 -1
  184. package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
  185. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  186. package/docs/api/interfaces/UseInactivityTrackerOptions.md +9 -9
  187. package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
  188. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  189. package/docs/api/interfaces/UsePublicEventReturn.md +5 -5
  190. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
  191. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +9 -9
  192. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  193. package/docs/api/interfaces/UseResolvedScopeOptions.md +4 -4
  194. package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
  195. package/docs/api/interfaces/UserEventAccess.md +11 -11
  196. package/docs/api/interfaces/UserMenuProps.md +1 -1
  197. package/docs/api/interfaces/UserProfile.md +1 -1
  198. package/docs/api/modules.md +648 -212
  199. package/docs/api-reference/components.md +106 -26
  200. package/docs/architecture/README.md +0 -2
  201. package/docs/implementation-guides/data-tables.md +277 -13
  202. package/docs/implementation-guides/forms.md +1 -16
  203. package/docs/implementation-guides/permission-enforcement.md +8 -2
  204. package/examples/README.md +30 -14
  205. package/examples/STRUCTURE.md +125 -0
  206. package/examples/components/DataTable/HierarchicalActionsExample.tsx +421 -0
  207. package/examples/components/DataTable/HierarchicalExample.tsx +475 -0
  208. package/examples/components/DataTable/InitialPageSizeExample.tsx +177 -0
  209. package/examples/components/DataTable/PerformanceExample.tsx +506 -0
  210. package/examples/components/DataTable/index.ts +13 -0
  211. package/examples/components/Dialog/BasicHtmlTest.tsx +55 -0
  212. package/examples/components/Dialog/DebugHtmlExample.tsx +68 -0
  213. package/examples/components/Dialog/HtmlDialogExample.tsx +202 -0
  214. package/examples/components/Dialog/ScrollableDialogExample.tsx +290 -0
  215. package/examples/components/Dialog/SimpleHtmlTest.tsx +61 -0
  216. package/examples/components/Dialog/SmartDialogExample.tsx +322 -0
  217. package/examples/components/Dialog/index.ts +15 -0
  218. package/examples/components/index.ts +11 -0
  219. package/examples/features/index.ts +12 -0
  220. package/examples/{public-pages → features/public-pages}/CorrectPublicPageImplementation.tsx +1 -1
  221. package/examples/{public-pages → features/public-pages}/PublicEventPage.tsx +1 -1
  222. package/examples/{public-pages → features/public-pages}/PublicPageApp.tsx +1 -1
  223. package/examples/{public-pages → features/public-pages}/PublicPageUsageExample.tsx +1 -1
  224. package/examples/index.ts +11 -3
  225. package/package.json +30 -10
  226. package/src/components/Alert/Alert.tsx +1 -1
  227. package/src/components/Avatar/Avatar.tsx +1 -1
  228. package/src/components/Button/Button.tsx +1 -1
  229. package/src/components/Card/Card.tsx +1 -1
  230. package/src/components/Checkbox/Checkbox.tsx +1 -1
  231. package/src/components/DataTable/DataTable.test.tsx +1 -1
  232. package/src/components/DataTable/DataTable.tsx +1 -30
  233. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +562 -0
  234. package/src/components/DataTable/__tests__/styles.test.ts +2 -2
  235. package/src/components/DataTable/components/ActionButtons.tsx +0 -15
  236. package/src/components/DataTable/components/DataTableCore.tsx +4 -185
  237. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +1 -1
  238. package/src/components/DataTable/components/DataTableModals.tsx +1 -27
  239. package/src/components/DataTable/components/EditableRow.tsx +1 -1
  240. package/src/components/DataTable/components/ImportModal.tsx +2 -14
  241. package/src/components/DataTable/components/PaginationControls.tsx +1 -1
  242. package/src/components/DataTable/components/UnifiedTableBody.tsx +109 -82
  243. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +1 -1
  244. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +1 -1
  245. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +1 -1
  246. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +1 -1
  247. package/src/components/DataTable/examples/GroupingAggregationExample.tsx +273 -0
  248. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +1 -1
  249. package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +1 -1
  250. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +1 -1
  251. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +1 -1
  252. package/src/components/DataTable/hooks/useDataTablePermissions.ts +2 -23
  253. package/src/components/DataTable/index.ts +4 -0
  254. package/src/components/DataTable/styles.ts +1 -1
  255. package/src/components/DataTable/types.ts +13 -0
  256. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +1 -1
  257. package/src/components/DataTable/utils/aggregationUtils.ts +161 -0
  258. package/src/components/DataTable/utils/exportUtils.ts +1 -1
  259. package/src/components/DataTable/utils/flexibleImport.ts +1 -11
  260. package/src/components/DataTable/utils/index.ts +1 -0
  261. package/src/components/DataTable/utils/paginationUtils.ts +1 -1
  262. package/src/components/Dialog/Dialog.tsx +2 -2
  263. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +35 -7
  264. package/src/components/ErrorBoundary/ErrorBoundary.tsx +5 -4
  265. package/src/components/EventSelector/EventSelector.tsx +3 -2
  266. package/src/components/FileDisplay/FileDisplay.tsx +2 -36
  267. package/src/components/FileUpload/FileUpload.test.tsx +2 -2
  268. package/src/components/FileUpload/FileUpload.tsx +2 -2
  269. package/src/components/Footer/Footer.tsx +1 -1
  270. package/src/components/Form/Form.test.tsx +4 -509
  271. package/src/components/Form/Form.tsx +1 -1
  272. package/src/components/Form/FormField.tsx +1 -1
  273. package/src/components/Form/index.ts +0 -12
  274. package/src/components/Header/Header.tsx +1 -1
  275. package/src/components/Input/Input.tsx +1 -1
  276. package/src/components/Label/Label.tsx +1 -1
  277. package/src/components/LoginForm/LoginForm.tsx +1 -1
  278. package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -3
  279. package/src/components/NavigationMenu/NavigationMenu.tsx +9 -8
  280. package/src/components/OrganisationSelector/OrganisationSelector.tsx +4 -3
  281. package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -12
  282. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +0 -16
  283. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +0 -1
  284. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -9
  285. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +35 -3
  286. package/src/components/PaceLoginPage/PaceLoginPage.tsx +13 -12
  287. package/src/components/PasswordReset/PasswordChangeForm.tsx +1 -1
  288. package/src/components/PasswordReset/index.ts +0 -2
  289. package/src/components/Progress/Progress.tsx +1 -1
  290. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +35 -8
  291. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -2
  292. package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
  293. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +1 -1
  294. package/src/components/PublicLayout/PublicPageContextChecker.tsx +44 -43
  295. package/src/components/PublicLayout/PublicPageFooter.tsx +1 -1
  296. package/src/components/PublicLayout/PublicPageHeader.tsx +1 -15
  297. package/src/components/PublicLayout/PublicPageProvider.tsx +3 -2
  298. package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +2 -0
  299. package/src/components/PublicLayout/index.ts +4 -2
  300. package/src/components/Select/Select.tsx +1 -1
  301. package/src/components/{SessionRestorationLoader.tsx → SessionRestorationLoader/SessionRestorationLoader.tsx} +3 -2
  302. package/src/components/SessionRestorationLoader/index.ts +3 -0
  303. package/src/components/Switch/Switch.tsx +1 -1
  304. package/src/components/Table/Table.tsx +1 -1
  305. package/src/components/Toast/Toast.tsx +1 -1
  306. package/src/components/Tooltip/Tooltip.tsx +1 -1
  307. package/src/components/index.ts +4 -10
  308. package/src/hooks/__tests__/hooks.integration.test.tsx +37 -22
  309. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +33 -17
  310. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +28 -3
  311. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +36 -9
  312. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +26 -2
  313. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +19 -6
  314. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -4
  315. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +17 -4
  316. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +26 -6
  317. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +16 -6
  318. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +3 -3
  319. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +17 -3
  320. package/src/hooks/public/usePublicEvent.ts +7 -6
  321. package/src/hooks/public/usePublicEventLogo.ts +7 -4
  322. package/src/hooks/public/usePublicFileDisplay.ts +6 -150
  323. package/src/hooks/useComponentPerformance.ts +4 -1
  324. package/src/hooks/useDataTablePerformance.ts +4 -3
  325. package/src/hooks/useEventTheme.test.ts +18 -5
  326. package/src/hooks/useEventTheme.ts +4 -1
  327. package/src/hooks/useEvents.ts +2 -0
  328. package/src/hooks/useFileDisplay.ts +9 -8
  329. package/src/hooks/useFileReference.ts +4 -1
  330. package/src/hooks/useFileUrl.ts +4 -1
  331. package/src/hooks/useInactivityTracker.ts +5 -4
  332. package/src/hooks/useOrganisationSecurity.test.ts +33 -12
  333. package/src/hooks/useOrganisationSecurity.ts +8 -7
  334. package/src/hooks/usePerformanceMonitor.ts +6 -3
  335. package/src/hooks/usePermissionCache.ts +13 -6
  336. package/src/hooks/useSecureDataAccess.test.ts +2 -2
  337. package/src/hooks/useSecureDataAccess.ts +9 -8
  338. package/src/hooks/useSessionRestoration.ts +4 -1
  339. package/src/hooks/useStorage.ts +4 -1
  340. package/src/index.ts +25 -8
  341. package/src/providers/services/AuthServiceProvider.tsx +3 -2
  342. package/src/providers/services/EventServiceProvider.tsx +2 -1
  343. package/src/providers/services/InactivityServiceProvider.tsx +2 -1
  344. package/src/providers/services/OrganisationServiceProvider.tsx +2 -1
  345. package/src/providers/services/UnifiedAuthProvider.tsx +4 -3
  346. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +22 -2
  347. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +24 -2
  348. package/src/rbac/__tests__/cache-invalidation.test.ts +20 -6
  349. package/src/rbac/api.ts +5 -2
  350. package/src/rbac/audit-enhanced.ts +6 -6
  351. package/src/rbac/audit.test.ts +60 -38
  352. package/src/rbac/audit.ts +8 -8
  353. package/src/rbac/cache-invalidation.ts +7 -4
  354. package/src/rbac/components/EnhancedNavigationMenu.tsx +11 -5
  355. package/src/rbac/components/NavigationGuard.tsx +7 -3
  356. package/src/rbac/components/NavigationProvider.tsx +6 -3
  357. package/src/rbac/components/PagePermissionGuard.tsx +28 -16
  358. package/src/rbac/components/PagePermissionProvider.tsx +4 -1
  359. package/src/rbac/components/PermissionEnforcer.tsx +9 -3
  360. package/src/rbac/components/RoleBasedRouter.tsx +3 -1
  361. package/src/rbac/components/SecureDataProvider.tsx +7 -3
  362. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +87 -61
  363. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +83 -33
  364. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +36 -13
  365. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +2 -2
  366. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +22 -8
  367. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +19 -6
  368. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +43 -17
  369. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +42 -17
  370. package/src/rbac/engine.ts +15 -7
  371. package/src/rbac/hooks/usePermissions.ts +7 -3
  372. package/src/rbac/hooks/useResolvedScope.test.ts +2 -2
  373. package/src/rbac/hooks/useResolvedScope.ts +10 -7
  374. package/src/rbac/permissions.ts +5 -2
  375. package/src/rbac/security.test.ts +27 -16
  376. package/src/rbac/security.ts +5 -4
  377. package/src/services/AuthService.ts +22 -21
  378. package/src/services/EventService.ts +12 -12
  379. package/src/services/InactivityService.ts +5 -4
  380. package/src/services/OrganisationService.ts +26 -25
  381. package/src/services/__tests__/AuthService.test.ts +51 -19
  382. package/src/services/__tests__/EventService.test.ts +37 -5
  383. package/src/services/__tests__/InactivityService.test.ts +38 -4
  384. package/src/services/__tests__/OrganisationService.test.ts +3 -8
  385. package/src/services/base/BaseService.ts +3 -1
  386. package/src/theming/__tests__/runtime.test.ts +21 -12
  387. package/src/theming/parseEventColours.ts +5 -19
  388. package/src/theming/runtime.ts +8 -4
  389. package/src/types/validation.ts +2 -29
  390. package/src/utils/__tests__/appConfig.unit.test.ts +1 -1
  391. package/src/utils/__tests__/audit.unit.test.ts +1 -1
  392. package/src/utils/__tests__/auth-utils.unit.test.ts +1 -1
  393. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +19 -19
  394. package/src/utils/__tests__/cn.unit.test.ts +1 -1
  395. package/src/utils/__tests__/debugLogger.test.ts +1 -1
  396. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -1
  397. package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -1
  398. package/src/utils/__tests__/formatting.unit.test.ts +1 -1
  399. package/src/utils/__tests__/lazyLoad.unit.test.tsx +1 -1
  400. package/src/utils/__tests__/logger.unit.test.ts +1 -1
  401. package/src/utils/__tests__/organisationContext.unit.test.ts +1 -1
  402. package/src/utils/__tests__/performanceBenchmark.test.ts +1 -1
  403. package/src/utils/__tests__/performanceBudgets.unit.test.ts +1 -1
  404. package/src/utils/__tests__/permissionTypes.unit.test.ts +1 -1
  405. package/src/utils/__tests__/permissionUtils.unit.test.ts +1 -1
  406. package/src/utils/__tests__/sanitization.unit.test.ts +1 -1
  407. package/src/utils/__tests__/schemaUtils.unit.test.ts +1 -1
  408. package/src/utils/__tests__/secureDataAccess.unit.test.ts +1 -1
  409. package/src/utils/__tests__/secureErrors.unit.test.ts +33 -15
  410. package/src/utils/__tests__/secureStorage.unit.test.ts +1 -1
  411. package/src/utils/__tests__/security.unit.test.ts +40 -18
  412. package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -1
  413. package/src/utils/__tests__/sessionTracking.unit.test.ts +40 -29
  414. package/src/utils/__tests__/validationUtils.unit.test.ts +19 -6
  415. package/src/utils/{appIdResolver.test.ts → app/appIdResolver.test.ts} +28 -30
  416. package/src/utils/{appIdResolver.ts → app/appIdResolver.ts} +8 -5
  417. package/src/utils/{appNameResolver.test.ts → app/appNameResolver.test.ts} +1 -1
  418. package/src/utils/{appNameResolver.ts → app/appNameResolver.ts} +5 -1
  419. package/src/utils/{organisationContext.ts → context/organisationContext.ts} +6 -3
  420. package/src/utils/{sessionTracking.ts → context/sessionTracking.ts} +11 -12
  421. package/src/utils/{logger.ts → core/logger.ts} +4 -2
  422. package/src/utils/{deviceFingerprint.ts → device/deviceFingerprint.ts} +1 -1
  423. package/src/utils/{lazyLoad.tsx → dynamic/lazyLoad.tsx} +2 -2
  424. package/src/utils/{file-reference.test.ts → file-reference/__tests__/file-reference.test.ts} +5 -5
  425. package/src/utils/{file-reference.ts → file-reference/index.ts} +20 -38
  426. package/src/utils/index.ts +32 -54
  427. package/src/utils/{secureErrors.ts → security/secureErrors.ts} +6 -3
  428. package/src/utils/{security.ts → security/security.ts} +5 -2
  429. package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -4
  430. package/src/utils/storage/helpers.ts +15 -8
  431. package/src/{components/Dialog/utils/__tests__/safeHtml.unit.test.ts → utils/validation/__tests__/htmlSanitization.unit.test.ts} +9 -15
  432. package/src/{validation → utils/validation}/csrf.ts +1 -1
  433. package/src/{components/Dialog/utils/safeHtml.ts → utils/validation/htmlSanitization.ts} +9 -10
  434. package/src/utils/validation/index.ts +79 -0
  435. package/src/utils/{sanitization.ts → validation/sanitization.ts} +71 -2
  436. package/src/{validation/schemaUtils.ts → utils/validation/schema.ts} +11 -6
  437. package/src/{validation → utils/validation}/sqlInjectionProtection.ts +2 -0
  438. package/src/utils/{validationUtils.ts → validation/validationUtils.ts} +4 -1
  439. package/src/validation/index.ts +3 -34
  440. package/dist/UnifiedAuthProvider-CQDZRJIS.js +0 -16
  441. package/dist/chunk-24MKLB7U.js +0 -81
  442. package/dist/chunk-24MKLB7U.js.map +0 -1
  443. package/dist/chunk-3CG5L6RN.js.map +0 -1
  444. package/dist/chunk-3DBFLLLU.js.map +0 -1
  445. package/dist/chunk-5F3NDPJV.js.map +0 -1
  446. package/dist/chunk-66C4BSAY.js.map +0 -1
  447. package/dist/chunk-BDZUMRBD.js.map +0 -1
  448. package/dist/chunk-BYXRHAIF.js.map +0 -1
  449. package/dist/chunk-CDQ3PX7L.js +0 -18
  450. package/dist/chunk-CDQ3PX7L.js.map +0 -1
  451. package/dist/chunk-CQZU6TFE.js.map +0 -1
  452. package/dist/chunk-F64FFPOZ.js.map +0 -1
  453. package/dist/chunk-GEVIB2UB.js.map +0 -1
  454. package/dist/chunk-GKHF54DI.js.map +0 -1
  455. package/dist/chunk-GVDR7WNV.js.map +0 -1
  456. package/dist/chunk-HMNOSGVA.js.map +0 -1
  457. package/dist/chunk-JCQZ6LA7.js.map +0 -1
  458. package/dist/chunk-M6DDYFUD.js.map +0 -1
  459. package/dist/chunk-O3NWNXDY.js.map +0 -1
  460. package/dist/chunk-PYUXFQJ3.js.map +0 -1
  461. package/dist/chunk-UJI6WSMD.js.map +0 -1
  462. package/dist/chunk-VZ5OR6HD.js.map +0 -1
  463. package/dist/chunk-WP5I5GLN.js.map +0 -1
  464. package/dist/chunk-ZYZCRSBD.js.map +0 -1
  465. package/src/components/Dialog/README.md +0 -804
  466. package/src/components/Form/FormErrorSummary.tsx +0 -113
  467. package/src/components/Form/FormFieldset.tsx +0 -127
  468. package/src/components/Form/FormLiveRegion.tsx +0 -198
  469. package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
  470. package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
  471. package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
  472. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
  473. package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +0 -185
  474. package/src/examples/CorrectPublicPageImplementation.tsx +0 -304
  475. package/src/examples/PublicEventPage.tsx +0 -287
  476. package/src/examples/PublicPageApp.tsx +0 -321
  477. package/src/examples/PublicPageUsageExample.tsx +0 -218
  478. package/src/utils/schemaUtils.ts +0 -37
  479. package/src/validation/__tests__/common.unit.test.ts +0 -101
  480. package/src/validation/__tests__/csrf.unit.test.ts +0 -365
  481. package/src/validation/__tests__/passwordSchema.unit.test.ts +0 -203
  482. package/src/validation/__tests__/sanitization.unit.test.ts +0 -250
  483. package/src/validation/__tests__/schemaUtils.unit.test.ts +0 -451
  484. package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +0 -462
  485. package/src/validation/__tests__/user.unit.test.ts +0 -440
  486. package/src/validation/sanitization.ts +0 -96
  487. /package/dist/{DataTable-A36PJG6N.js.map → DataTable-CYOHOX3O.js.map} +0 -0
  488. /package/dist/{UnifiedAuthProvider-CQDZRJIS.js.map → UnifiedAuthProvider-5E5TUNMS.js.map} +0 -0
  489. /package/dist/{api-TNIBJWLM.js.map → api-45XYYO2A.js.map} +0 -0
  490. /package/dist/{audit-T36HM7IM.js.map → audit-64X3VJXB.js.map} +0 -0
  491. /package/dist/{chunk-CTJRBUX2.js.map → chunk-2TWNJ46Y.js.map} +0 -0
  492. /package/dist/{chunk-ZV77RZMU.js.map → chunk-XARJS7CD.js.map} +0 -0
  493. /package/dist/{useInactivityTracker-MRUU55XI.js.map → useInactivityTracker-TO6ZOF35.js.map} +0 -0
  494. /package/examples/{public-pages → features/public-pages}/index.ts +0 -0
  495. /package/examples/{RBAC → features/rbac}/CompleteRBACExample.tsx +0 -0
  496. /package/examples/{RBAC → features/rbac}/EventBasedApp.tsx +0 -0
  497. /package/examples/{RBAC → features/rbac}/PermissionExample.tsx +0 -0
  498. /package/examples/{RBAC → features/rbac}/index.ts +0 -0
  499. /package/src/utils/{appConfig.ts → app/appConfig.ts} +0 -0
  500. /package/src/utils/{appNameResolver.simple.test.ts → app/appNameResolver.simple.test.ts} +0 -0
  501. /package/src/utils/{audit.ts → audit/audit.ts} +0 -0
  502. /package/src/utils/{organisationContext.test.ts → context/organisationContext.test.ts} +0 -0
  503. /package/src/utils/{cn.ts → core/cn.ts} +0 -0
  504. /package/src/utils/{debugLogger.ts → core/debugLogger.ts} +0 -0
  505. /package/src/utils/{dynamicUtils.ts → dynamic/dynamicUtils.ts} +0 -0
  506. /package/src/utils/{formatDate.test.ts → formatting/formatDate.test.ts} +0 -0
  507. /package/src/utils/{formatting.ts → formatting/formatting.ts} +0 -0
  508. /package/src/utils/{bundleAnalysis.ts → performance/bundleAnalysis.ts} +0 -0
  509. /package/src/utils/{performanceBenchmark.ts → performance/performanceBenchmark.ts} +0 -0
  510. /package/src/utils/{performanceBudgets.ts → performance/performanceBudgets.ts} +0 -0
  511. /package/src/utils/{permissionTypes.ts → permissions/permissionTypes.ts} +0 -0
  512. /package/src/utils/{permissionUtils.test.ts → permissions/permissionUtils.test.ts} +0 -0
  513. /package/src/utils/{permissionUtils.ts → permissions/permissionUtils.ts} +0 -0
  514. /package/src/utils/{auth-utils.ts → security/auth-utils.ts} +0 -0
  515. /package/src/utils/{secureDataAccess.test.ts → security/secureDataAccess.test.ts} +0 -0
  516. /package/src/utils/{secureDataAccess.ts → security/secureDataAccess.ts} +0 -0
  517. /package/src/utils/{secureStorage.ts → security/secureStorage.ts} +0 -0
  518. /package/src/utils/{securityMonitor.ts → security/securityMonitor.ts} +0 -0
  519. /package/src/{validation → utils/validation}/common.ts +0 -0
  520. /package/src/{validation → utils/validation}/passwordSchema.ts +0 -0
  521. /package/src/{validation → utils/validation}/user.ts +0 -0
  522. /package/src/utils/{validation.ts → validation/validation.ts} +0 -0
@@ -22,11 +22,12 @@ import { EditableRow } from './EditableRow';
22
22
  import { getTableCellClasses, getTableHeadClasses, getTableRowClasses } from '../styles';
23
23
  import { Input } from '../../Input/Input';
24
24
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SelectGroup, SelectLabel, SelectSeparator } from '../../Select/Select';
25
- import { createLogger } from '../../../utils/logger';
25
+ import { createLogger } from '../../../utils/core/logger';
26
26
  import type {
27
27
  AggregateConfig,
28
28
  DataRecord,
29
29
  DataTableAction,
30
+ DataTableColumn,
30
31
  EditableColumnDef,
31
32
  EmptyStateConfig,
32
33
  HierarchicalConfig,
@@ -215,20 +216,6 @@ function SelectEditField<TData extends DataRecord>({
215
216
  // Always show create option when there's a search term (user might want to create even if matches exist)
216
217
  const shouldShow = isCreatable && !!columnDef.onCreateNew;
217
218
 
218
- // Debug logging for creatable select
219
- if (import.meta.env.MODE === 'development' && isCreatable) {
220
- logger.debug('[SelectEditField] Creatable select check:', {
221
- searchTerm: currentSearch,
222
- searchLower,
223
- hasMatch,
224
- isCreatable,
225
- hasOnCreateNew: !!columnDef.onCreateNew,
226
- shouldShow,
227
- fieldOptionsCount: columnDef.fieldOptions?.length || 0,
228
- note: 'Create option shows when search term exists, regardless of matches'
229
- });
230
- }
231
-
232
219
  setShowCreateOption(shouldShow);
233
220
  } else {
234
221
  setShowCreateOption(false);
@@ -529,6 +516,7 @@ const RowComponent = React.memo(({
529
516
  }: RowProps) => {
530
517
  const rowRef = useRef<HTMLTableRowElement>(null);
531
518
  const firstInputRef = useRef<HTMLInputElement>(null);
519
+ const logger = React.useMemo(() => createLogger('RowComponent'), []);
532
520
 
533
521
  const rowId = getRowIdSafe(row.original, row.index, getRowId);
534
522
 
@@ -577,33 +565,115 @@ const RowComponent = React.memo(({
577
565
  const groupValue = row.getValue(grouping[0]);
578
566
  const subRowsCount = row.subRows?.length || 0;
579
567
  const isExpanded = row.getIsExpanded();
568
+ const visibleCells = row.getVisibleCells();
569
+
570
+ // Get child rows for aggregation (convert TanStack Row to original data)
571
+ const childRows: DataRecord[] = row.subRows?.map((subRow: any) => subRow.original) || [];
580
572
 
581
- // Only render the group header row - sub-rows will be rendered by the standard rendering loop
573
+ // Render individual cells for each column with aggregation support
582
574
  return (
583
575
  <tr className="bg-sec-50 hover:bg-sec-100" style={style}>
584
- <td
585
- className={getTableCellClasses({
586
- isCompact: true,
587
- className: "px-3 py-2 flex items-center font-medium"
588
- })}
589
- colSpan={row.getAllCells().length}
590
- >
591
- <Button
592
- variant="ghost"
593
- size="sm"
594
- onClick={() => row.toggleExpanded()}
595
- className="p-0 h-auto mr-2"
596
- >
597
- {isExpanded ? (
598
- <ChevronDown className="h-4 w-4" />
599
- ) : (
600
- <ChevronRight className="h-4 w-4" />
601
- )}
602
- </Button>
603
- <span className="text-sm">
604
- {String(groupValue)} ({subRowsCount} items)
605
- </span>
606
- </td>
576
+ {visibleCells.map((cell: any, cellIndex: number) => {
577
+ const columnDef = cell.column.columnDef as DataTableColumn<DataRecord>;
578
+ const isGroupingColumn = cellIndex === 0 || grouping.includes(cell.column.id || '');
579
+
580
+ // For the grouping column, show the group header with expand/collapse
581
+ if (isGroupingColumn && cellIndex === 0) {
582
+ return (
583
+ <td
584
+ key={cell.id}
585
+ className={getTableCellClasses({
586
+ isCompact: true,
587
+ className: "px-3 py-2 flex items-center font-medium"
588
+ })}
589
+ >
590
+ <Button
591
+ variant="ghost"
592
+ size="sm"
593
+ onClick={() => row.toggleExpanded()}
594
+ className="p-0 h-auto mr-2"
595
+ >
596
+ {isExpanded ? (
597
+ <ChevronDown className="h-4 w-4" />
598
+ ) : (
599
+ <ChevronRight className="h-4 w-4" />
600
+ )}
601
+ </Button>
602
+ <span className="text-sm">
603
+ {String(groupValue)} ({subRowsCount} items)
604
+ </span>
605
+ </td>
606
+ );
607
+ }
608
+
609
+ // For other columns, check if they have aggregation functions
610
+ if (columnDef.aggregateFn && childRows.length > 0) {
611
+ try {
612
+ // Call the aggregation function with child rows
613
+ const aggregatedValue = columnDef.aggregateFn(childRows, columnDef);
614
+
615
+ // Use aggregateCell renderer if provided, otherwise use regular cell renderer
616
+ let cellContent: React.ReactNode;
617
+ if (columnDef.aggregateCell) {
618
+ cellContent = columnDef.aggregateCell(aggregatedValue, childRows, columnDef);
619
+ } else if (columnDef.cell) {
620
+ // Use regular cell renderer with a mock cell context
621
+ // Create a mock cell object for the aggregated value
622
+ const mockCell = {
623
+ ...cell,
624
+ getValue: () => aggregatedValue,
625
+ renderValue: () => aggregatedValue,
626
+ };
627
+ cellContent = flexRender(columnDef.cell, {
628
+ ...mockCell,
629
+ row: row,
630
+ column: cell.column,
631
+ cell: mockCell,
632
+ getValue: () => aggregatedValue,
633
+ renderValue: () => aggregatedValue,
634
+ });
635
+ } else {
636
+ // Fallback to displaying the raw value
637
+ cellContent = aggregatedValue != null ? String(aggregatedValue) : '';
638
+ }
639
+
640
+ return (
641
+ <td
642
+ key={cell.id}
643
+ className={getTableCellClasses({
644
+ isCompact: true,
645
+ className: `px-3 py-2 ${cell.column.columnDef.meta?.align === 'right' ? 'text-right' : ''}`
646
+ })}
647
+ >
648
+ {cellContent}
649
+ </td>
650
+ );
651
+ } catch (error) {
652
+ // If aggregation fails, show empty cell
653
+ logger.warn('Error in aggregation function:', error);
654
+ return (
655
+ <td
656
+ key={cell.id}
657
+ className={getTableCellClasses({
658
+ isCompact: true,
659
+ className: "px-3 py-2"
660
+ })}
661
+ />
662
+ );
663
+ }
664
+ }
665
+
666
+ // For columns without aggregation, show empty cell
667
+ return (
668
+ <td
669
+ key={cell.id}
670
+ className={getTableCellClasses({
671
+ isCompact: true,
672
+ className: "px-3 py-2"
673
+ })}
674
+ />
675
+ );
676
+ })}
607
677
  </tr>
608
678
  );
609
679
  }
@@ -774,49 +844,6 @@ export function UnifiedTableBody<TData extends Record<string, any>>({
774
844
  const rows = table.getRowModel().rows;
775
845
  const headerGroups = table.getHeaderGroups();
776
846
 
777
- // Diagnostic logging when rows are empty but data exists
778
- useEffect(() => {
779
- if (rows.length === 0 && dataLength > 0) {
780
- const tableState = table.getState();
781
- const pagination = tableState.pagination;
782
- const columnFilters = tableState.columnFilters;
783
- const globalFilter = tableState.globalFilter;
784
- const coreRows = table.getCoreRowModel().rows;
785
- const prePaginationRows = table.getPrePaginationRowModel?.()?.rows || [];
786
- const filteredRows = table.getFilteredRowModel?.()?.rows || [];
787
- const sortedRows = table.getSortedRowModel?.()?.rows || [];
788
- const rowCount = table.getRowCount();
789
- const pageCount = table.getPageCount();
790
-
791
- logger.warn('Rows empty but data exists!', {
792
- dataLength,
793
- rowsLength: rows.length,
794
- coreRowsLength: coreRows.length,
795
- prePaginationRowsLength: prePaginationRows.length,
796
- filteredRowsLength: filteredRows.length,
797
- sortedRowsLength: sortedRows.length,
798
- rowCount,
799
- pageCount,
800
- pagination: {
801
- pageIndex: pagination.pageIndex,
802
- pageSize: pagination.pageSize,
803
- },
804
- columnFilters,
805
- globalFilter,
806
- tableOptions: {
807
- getCoreRowModel: !!table.options.getCoreRowModel,
808
- getFilteredRowModel: !!table.options.getFilteredRowModel,
809
- getSortedRowModel: !!table.options.getSortedRowModel,
810
- getPaginationRowModel: !!table.options.getPaginationRowModel,
811
- manualPagination: table.options.manualPagination,
812
- manualFiltering: table.options.manualFiltering,
813
- manualSorting: table.options.manualSorting,
814
- },
815
- tableDataLength: table.options.data?.length || 0,
816
- });
817
- }
818
- }, [rows.length, dataLength, table, logger]);
819
-
820
847
  // CRITICAL FIX: Virtual scrolling requires a scroll container (parentRef).
821
848
  // If virtualization is enabled but no scroll container exists, fall back to standard rendering.
822
849
  // This fixes the bug where rows exist but nothing renders when virtualization is enabled.
@@ -28,7 +28,7 @@ vi.mock('lucide-react', async () => {
28
28
  });
29
29
 
30
30
  // Mock logger
31
- vi.mock('../../../utils/logger', () => ({
31
+ vi.mock('../../../utils/core/logger', () => ({
32
32
  createLogger: () => ({
33
33
  debug: vi.fn(),
34
34
  info: vi.fn(),
@@ -16,7 +16,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
16
16
  import { DataTableErrorBoundary, useDataTableErrorBoundary } from '../DataTableErrorBoundary';
17
17
 
18
18
  // Mock logger
19
- vi.mock('../../../utils/logger', () => ({
19
+ vi.mock('../../../utils/core/logger', () => ({
20
20
  createLogger: () => ({
21
21
  debug: vi.fn(),
22
22
  info: vi.fn(),
@@ -22,7 +22,7 @@ const mockLogger = {
22
22
  info: vi.fn(),
23
23
  };
24
24
 
25
- vi.mock('../../../utils/logger', () => ({
25
+ vi.mock('../../../utils/core/logger', () => ({
26
26
  createLogger: () => mockLogger,
27
27
  }));
28
28
 
@@ -79,7 +79,7 @@ vi.mock('lucide-react', () => ({
79
79
  }));
80
80
 
81
81
  // Mock logger
82
- vi.mock('../../../utils/logger', () => ({
82
+ vi.mock('../../../utils/core/logger', () => ({
83
83
  createLogger: () => ({
84
84
  debug: vi.fn(),
85
85
  info: vi.fn(),
@@ -0,0 +1,273 @@
1
+ /**
2
+ * @file Grouping Aggregation Example
3
+ * @package @jmruthers/pace-core
4
+ * @module Components/DataTable/Examples
5
+ * @since 0.6.0
6
+ *
7
+ * Complete example demonstrating grouped row aggregation in DataTable.
8
+ * This example shows how to use aggregation functions to display
9
+ * totals and averages in grouped rows, similar to the pace-cake diners table use case.
10
+ */
11
+
12
+ import React from 'react';
13
+ import { DataTable, sum, average, count, type DataTableColumn, type DataRecord } from '../index';
14
+
15
+ // ============================================================================
16
+ // DATA INTERFACE
17
+ // ============================================================================
18
+
19
+ interface DinerData extends DataRecord {
20
+ id: string;
21
+ unit_number: string;
22
+ unit_name: string;
23
+ diet: string;
24
+ youth: number;
25
+ adults: number;
26
+ cost: number;
27
+ [key: string]: unknown; // Index signature to satisfy DataRecord constraint
28
+ }
29
+
30
+ // ============================================================================
31
+ // SAMPLE DATA
32
+ // ============================================================================
33
+
34
+ const dinerData: DinerData[] = [
35
+ { id: '1', unit_number: '101', unit_name: 'Alpha Unit', diet: 'Standard', youth: 10, adults: 5, cost: 100.50 },
36
+ { id: '2', unit_number: '101', unit_name: 'Alpha Unit', diet: 'Standard', youth: 15, adults: 8, cost: 150.75 },
37
+ { id: '3', unit_number: '101', unit_name: 'Alpha Unit', diet: 'Gluten Free', youth: 5, adults: 3, cost: 75.25 },
38
+ { id: '4', unit_number: '102', unit_name: 'Beta Unit', diet: 'Standard', youth: 20, adults: 10, cost: 200.00 },
39
+ { id: '5', unit_number: '102', unit_name: 'Beta Unit', diet: 'Standard', youth: 12, adults: 6, cost: 120.50 },
40
+ { id: '6', unit_number: '102', unit_name: 'Beta Unit', diet: 'Vegetarian', youth: 8, adults: 4, cost: 90.00 },
41
+ { id: '7', unit_number: '103', unit_name: 'Gamma Unit', diet: 'Standard', youth: 18, adults: 9, cost: 180.25 },
42
+ { id: '8', unit_number: '103', unit_name: 'Gamma Unit', diet: 'Gluten Free', youth: 6, adults: 3, cost: 80.50 },
43
+ ];
44
+
45
+ // ============================================================================
46
+ // COLUMN DEFINITIONS
47
+ // ============================================================================
48
+
49
+ const columns: DataTableColumn<DinerData>[] = [
50
+ {
51
+ accessorKey: 'unit_number',
52
+ header: 'Unit #',
53
+ sortable: true,
54
+ enableGrouping: true,
55
+ size: 100,
56
+ },
57
+ {
58
+ accessorKey: 'unit_name',
59
+ header: 'Unit Name',
60
+ sortable: true,
61
+ enableGrouping: true,
62
+ size: 150,
63
+ },
64
+ {
65
+ accessorKey: 'diet',
66
+ header: 'Diet',
67
+ sortable: true,
68
+ enableGrouping: true,
69
+ size: 120,
70
+ cell: ({ row }: { row: { original: DinerData } }) => (
71
+ <span className="px-2 py-1 rounded text-xs font-medium bg-main-100 text-main-800 border border-main-300">
72
+ {row.original.diet}
73
+ </span>
74
+ ),
75
+ },
76
+ {
77
+ accessorKey: 'youth',
78
+ header: 'Youth',
79
+ sortable: true,
80
+ fieldType: 'number',
81
+ size: 100,
82
+ aggregateFn: sum('youth'),
83
+ aggregateCell: (value: any) => (
84
+ <div className="text-right font-semibold">
85
+ {typeof value === 'number' ? value.toLocaleString() : '0'}
86
+ </div>
87
+ ),
88
+ cell: ({ row }: { row: { original: DinerData } }) => (
89
+ <div className="text-right">
90
+ {row.original.youth.toLocaleString()}
91
+ </div>
92
+ ),
93
+ },
94
+ {
95
+ accessorKey: 'adults',
96
+ header: 'Adults',
97
+ sortable: true,
98
+ fieldType: 'number',
99
+ size: 100,
100
+ aggregateFn: sum('adults'),
101
+ aggregateCell: (value: any) => (
102
+ <div className="text-right font-semibold">
103
+ {typeof value === 'number' ? value.toLocaleString() : '0'}
104
+ </div>
105
+ ),
106
+ cell: ({ row }: { row: { original: DinerData } }) => (
107
+ <div className="text-right">
108
+ {row.original.adults.toLocaleString()}
109
+ </div>
110
+ ),
111
+ },
112
+ {
113
+ accessorKey: 'cost',
114
+ header: 'Total Cost',
115
+ sortable: true,
116
+ fieldType: 'number',
117
+ size: 120,
118
+ aggregateFn: sum('cost'),
119
+ aggregateCell: (value: any) => (
120
+ <div className="text-right font-semibold font-mono">
121
+ ${typeof value === 'number' ? value.toFixed(2) : '0.00'}
122
+ </div>
123
+ ),
124
+ cell: ({ row }: { row: { original: DinerData } }) => (
125
+ <div className="text-right font-mono">
126
+ ${row.original.cost.toFixed(2)}
127
+ </div>
128
+ ),
129
+ },
130
+ {
131
+ accessorKey: 'id',
132
+ header: 'Count',
133
+ sortable: false,
134
+ size: 80,
135
+ aggregateFn: count(),
136
+ aggregateCell: (value: any) => (
137
+ <div className="text-center font-semibold">
138
+ {typeof value === 'number' ? value : '0'}
139
+ </div>
140
+ ),
141
+ cell: () => null as React.ReactNode, // Hide count for individual rows
142
+ },
143
+ ];
144
+
145
+ // ============================================================================
146
+ // EXAMPLE COMPONENT
147
+ // ============================================================================
148
+
149
+ export function GroupingAggregationExample() {
150
+ return (
151
+ <div className="p-6 space-y-6">
152
+ <div>
153
+ <h1 className="text-2xl font-bold text-main-900 mb-2">
154
+ Grouped Row Aggregation Example
155
+ </h1>
156
+ <p className="text-sec-600">
157
+ This example demonstrates how to use aggregation functions in grouped DataTable rows.
158
+ When rows are grouped by Unit or Diet, the Youth, Adults, and Cost columns show
159
+ aggregated totals, and the Count column shows the number of records in each group.
160
+ </p>
161
+ </div>
162
+
163
+ <div className="bg-main-50 border border-main-200 rounded-md p-4 space-y-2">
164
+ <p className="font-medium text-sm">How to use:</p>
165
+ <ol className="list-decimal list-inside text-sm space-y-1 text-sec-700">
166
+ <li>Use the grouping dropdown to group by Unit #, Unit Name, or Diet</li>
167
+ <li>Notice how the Youth, Adults, and Cost columns show aggregated totals in grouped rows</li>
168
+ <li>The Count column shows the number of records in each group</li>
169
+ <li>Click the expand/collapse arrows to see individual rows within each group</li>
170
+ </ol>
171
+ </div>
172
+
173
+ <DataTable<DinerData>
174
+ data={dinerData}
175
+ columns={columns}
176
+ title="Diners by Unit and Diet"
177
+ description="Example showing aggregated values in grouped rows"
178
+ rbac={{ pageName: 'diners-example' }}
179
+ features={{
180
+ search: true,
181
+ pagination: true,
182
+ sorting: true,
183
+ filtering: true,
184
+ grouping: true,
185
+ columnVisibility: true,
186
+ columnReordering: false,
187
+ selection: false,
188
+ creation: false,
189
+ editing: false,
190
+ deletion: false,
191
+ deleteSelected: false,
192
+ import: false,
193
+ export: true,
194
+ }}
195
+ getRowId={(row: DinerData) => row.id}
196
+ variant="default"
197
+ className="border border-sec-200 rounded-lg"
198
+ />
199
+ </div>
200
+ );
201
+ }
202
+
203
+ // ============================================================================
204
+ // ALTERNATIVE EXAMPLES
205
+ // ============================================================================
206
+
207
+ /**
208
+ * Example with custom aggregation function
209
+ */
210
+ export function CustomAggregationExample() {
211
+ const customColumns: DataTableColumn<DinerData>[] = [
212
+ {
213
+ accessorKey: 'diet',
214
+ header: 'Diet',
215
+ enableGrouping: true,
216
+ },
217
+ {
218
+ accessorKey: 'youth',
219
+ header: 'Total Diners',
220
+ aggregateFn: (rows: DinerData[]) => {
221
+ // Custom: sum of youth + adults
222
+ return rows.reduce((total: number, row: DinerData) => total + (row.youth || 0) + (row.adults || 0), 0);
223
+ },
224
+ aggregateCell: (value: any) => (
225
+ <div className="text-right font-semibold">
226
+ {typeof value === 'number' ? value.toLocaleString() : '0'} total diners
227
+ </div>
228
+ ),
229
+ },
230
+ {
231
+ accessorKey: 'cost',
232
+ header: 'Avg Cost per Diner',
233
+ aggregateFn: (rows: DinerData[]) => {
234
+ const totalCost = rows.reduce((sum: number, row: DinerData) => sum + (row.cost || 0), 0);
235
+ const totalDiners = rows.reduce((sum: number, row: DinerData) => sum + (row.youth || 0) + (row.adults || 0), 0);
236
+ return totalDiners > 0 ? totalCost / totalDiners : 0;
237
+ },
238
+ aggregateCell: (value: any) => (
239
+ <div className="text-right font-semibold font-mono">
240
+ ${typeof value === 'number' ? value.toFixed(2) : '0.00'} per diner
241
+ </div>
242
+ ),
243
+ },
244
+ ];
245
+
246
+ return (
247
+ <div className="p-6 space-y-6">
248
+ <div>
249
+ <h2 className="text-xl font-bold text-main-900 mb-2">
250
+ Custom Aggregation Example
251
+ </h2>
252
+ <p className="text-sec-600">
253
+ This example shows custom aggregation functions that calculate
254
+ total diners and average cost per diner.
255
+ </p>
256
+ </div>
257
+
258
+ <DataTable<DinerData>
259
+ data={dinerData}
260
+ columns={customColumns}
261
+ rbac={{ pageName: 'diners-custom' }}
262
+ features={{
263
+ grouping: true,
264
+ sorting: true,
265
+ pagination: true,
266
+ }}
267
+ defaultGrouping={['diet']}
268
+ getRowId={(row: DinerData) => row.id}
269
+ />
270
+ </div>
271
+ );
272
+ }
273
+
@@ -12,7 +12,7 @@ import React from 'react';
12
12
  import { DataTable } from '../DataTable';
13
13
  import type { DataTableColumn, DataTableAction } from '../types';
14
14
  import { Button } from '../../Button';
15
- import { createLogger } from '../../../utils/logger';
15
+ import { createLogger } from '../../../utils/core/logger';
16
16
  import {
17
17
  PlusIcon,
18
18
  PencilIcon,
@@ -93,7 +93,7 @@ vi.mock('../../../../rbac/hooks', () => ({
93
93
  }));
94
94
 
95
95
  // Mock logger
96
- vi.mock('../../../utils/logger', () => ({
96
+ vi.mock('../../../utils/core/logger', () => ({
97
97
  createLogger: () => ({
98
98
  debug: vi.fn(),
99
99
  info: vi.fn(),
@@ -1,5 +1,5 @@
1
1
  import { useState, useEffect, useCallback } from 'react';
2
- import { createLogger } from '../../../utils/logger';
2
+ import { createLogger } from '../../../utils/core/logger';
3
3
 
4
4
  interface UseColumnOrderPersistenceProps {
5
5
  tableId?: string;
@@ -1,5 +1,5 @@
1
1
  import { useState, useEffect, useCallback } from 'react';
2
- import { createLogger } from '../../../utils/logger';
2
+ import { createLogger } from '../../../utils/core/logger';
3
3
 
4
4
  interface UseColumnVisibilityPersistenceProps {
5
5
  tableId?: string;
@@ -12,7 +12,7 @@ import { useMemo, useRef } from 'react';
12
12
  import { useUnifiedAuth } from '../../../providers/UnifiedAuthProvider';
13
13
  import { useCan, useResolvedScope } from '../../../rbac/hooks';
14
14
  import { useToast } from '../../../hooks/useToast';
15
- import { createLogger } from '../../../utils/logger';
15
+ import { createLogger } from '../../../utils/core/logger';
16
16
  import {
17
17
  normalizeDataTableFeatures,
18
18
  type DataTableFeatureConfig,
@@ -69,16 +69,7 @@ export function useDataTablePermissions<TData extends Record<string, any>>(
69
69
  */
70
70
 
71
71
  // Use shared scope resolution hook for consistent RBAC scoping
72
- const { selectedOrganisation, selectedEvent, supabase, organisations } = useUnifiedAuth();
73
-
74
- // Debug logging to understand organisation context
75
- logger.debug('Organisation context:', {
76
- hasSelectedOrg: !!selectedOrganisation,
77
- selectedOrgId: selectedOrganisation?.id,
78
- hasOrganisations: organisations?.length > 0,
79
- organisationCount: organisations?.length,
80
- selectedEvent: selectedEvent?.event_id
81
- });
72
+ const { selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();
82
73
 
83
74
  const { resolvedScope: rawResolvedScope, isLoading: scopeLoading } = useResolvedScope({
84
75
  supabase,
@@ -155,18 +146,6 @@ export function useDataTablePermissions<TData extends Record<string, any>>(
155
146
  canExport: useCan(userId, consistentScope, readPermission, effectivePageId, true), // Use read permission for export
156
147
  canImport: useCan(userId, consistentScope, createPermission, effectivePageId, true), // Use create permission for import
157
148
  };
158
-
159
- // Debug logging for permissions
160
- logger.debug('Permission check results:', {
161
- canRead: permissions.canRead.can,
162
- canReadLoading: permissions.canRead.isLoading,
163
- canReadError: permissions.canRead.error?.message,
164
- canCreate: permissions.canCreate.can,
165
- pageName: effectivePageId,
166
- scope: consistentScope,
167
- hasValidScope: !!effectiveScope,
168
- scopeLoading: scopeLoading
169
- });
170
149
 
171
150
  // MANDATORY: Features are automatically filtered by permissions
172
151
  const normalizedFeatures = useMemo(
@@ -29,6 +29,7 @@ export type { UseDataTablePerformanceOptions, UseDataTablePerformanceReturn } fr
29
29
 
30
30
  // Type definitions
31
31
  export type {
32
+ DataRecord,
32
33
  DataTableColumn,
33
34
  DataTableAction,
34
35
  DataTableToolbarButton,
@@ -66,6 +67,9 @@ export * from './components';
66
67
  // Utility functions
67
68
  export * from './utils';
68
69
 
70
+ // Aggregation utilities (explicitly exported for convenience)
71
+ export { sum, average, count, min, max } from './utils/aggregationUtils';
72
+
69
73
  // Accessibility utilities
70
74
  export { announce } from './utils/a11yUtils';
71
75
 
@@ -8,7 +8,7 @@
8
8
  * This ensures consistent styling across regular and virtualized tables.
9
9
  */
10
10
 
11
- import { cn } from '../../utils/cn';
11
+ import { cn } from '../../utils/core/cn';
12
12
 
13
13
  // ============================================================================
14
14
  // TABLE BASE STYLES
@@ -328,6 +328,19 @@ export interface DataTableColumn<TData extends DataRecord = DataRecord> extends
328
328
  hideForParent?: boolean;
329
329
  /** Hide this column for child rows */
330
330
  hideForChild?: boolean;
331
+
332
+ // Grouped row aggregation
333
+ /**
334
+ * Aggregation function for grouped rows.
335
+ * Receives all rows in the group and returns the aggregated value.
336
+ * If not provided, grouped rows will show empty/undefined for this column.
337
+ */
338
+ aggregateFn?: (rows: TData[], column: DataTableColumn<TData>) => any;
339
+ /**
340
+ * Optional: Custom cell renderer for aggregated values in grouped rows.
341
+ * If not provided, uses the column's regular cell renderer.
342
+ */
343
+ aggregateCell?: (value: any, rows: TData[], column: DataTableColumn<TData>) => React.ReactNode;
331
344
  }
332
345
 
333
346
  /**