@jmruthers/pace-core 0.5.76 → 0.5.78

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 (447) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{RBACService-C4udt_Zp.d.ts → AuthService-Df3IozMG.d.ts} +10 -118
  3. package/dist/{DataTable-ntgmhO2W.d.ts → DataTable-BE0OXZKQ.d.ts} +9 -2
  4. package/dist/{DataTable-4GAVPIEG.js → DataTable-ETGVF4Y5.js} +50 -13
  5. package/dist/{PublicLoadingSpinner-BiNER8F5.d.ts → PublicLoadingSpinner-CnUaz0vG.d.ts} +5 -2
  6. package/dist/{UnifiedAuthProvider-Bj6YCf7c.d.ts → UnifiedAuthProvider-B391Aqum.d.ts} +42 -45
  7. package/dist/{UnifiedAuthProvider-3NKDOSOK.js → UnifiedAuthProvider-P5SOJAQ6.js} +4 -5
  8. package/dist/{api-DDMUKIUD.js → api-KG4A2X7P.js} +9 -3
  9. package/dist/{audit-6TOCAMKO.js → audit-65VNHEV2.js} +2 -2
  10. package/dist/{chunk-K34IM5CT.js → chunk-2OGV6IRV.js} +196 -626
  11. package/dist/chunk-2OGV6IRV.js.map +1 -0
  12. package/dist/{chunk-NTNILOBC.js → chunk-5BO3MI5Y.js} +4 -4
  13. package/dist/{chunk-XLZ7U46Z.js → chunk-CVMVPYAL.js} +9 -60
  14. package/dist/chunk-CVMVPYAL.js.map +1 -0
  15. package/dist/{chunk-URUTVZ7N.js → chunk-FL4ZCQLD.js} +2 -2
  16. package/dist/{chunk-LW7MMEAQ.js → chunk-FT2M4R4F.js} +2 -2
  17. package/dist/{chunk-5BSLGBYI.js → chunk-JCQZ6LA7.js} +2 -8
  18. package/dist/{chunk-5BSLGBYI.js.map → chunk-JCQZ6LA7.js.map} +1 -1
  19. package/dist/{chunk-KHJS6VIA.js → chunk-LRQ6RBJC.js} +157 -112
  20. package/dist/chunk-LRQ6RBJC.js.map +1 -0
  21. package/dist/{chunk-WN6XJWOS.js → chunk-MNJXXD6C.js} +274 -743
  22. package/dist/chunk-MNJXXD6C.js.map +1 -0
  23. package/dist/{chunk-KK73ZB4E.js → chunk-PTR5PMPE.js} +153 -132
  24. package/dist/chunk-PTR5PMPE.js.map +1 -0
  25. package/dist/{chunk-B2WTCLCV.js → chunk-Q7APDV6H.js} +18 -8
  26. package/dist/chunk-Q7APDV6H.js.map +1 -0
  27. package/dist/{chunk-A4FUBC7B.js → chunk-QGVSOUJ2.js} +2 -4
  28. package/dist/{chunk-A4FUBC7B.js.map → chunk-QGVSOUJ2.js.map} +1 -1
  29. package/dist/{chunk-FGMFQSHX.js → chunk-S63MFSY6.js} +500 -551
  30. package/dist/chunk-S63MFSY6.js.map +1 -0
  31. package/dist/{chunk-AFGTSUAD.js → chunk-VSOKOFRF.js} +4 -4
  32. package/dist/chunk-WUXCWRL6.js +20 -0
  33. package/dist/chunk-WUXCWRL6.js.map +1 -0
  34. package/dist/{chunk-Y6TXWPJO.js → chunk-YVVGHRGI.js} +105 -31
  35. package/dist/chunk-YVVGHRGI.js.map +1 -0
  36. package/dist/{chunk-M5IWZRBT.js → chunk-ZMNXIJP4.js} +2187 -981
  37. package/dist/chunk-ZMNXIJP4.js.map +1 -0
  38. package/dist/components.d.ts +6 -6
  39. package/dist/components.js +14 -18
  40. package/dist/components.js.map +1 -1
  41. package/dist/{database-C3Szpi5J.d.ts → database-BXAfr2Y_.d.ts} +18 -0
  42. package/dist/hooks.d.ts +5 -5
  43. package/dist/hooks.js +8 -9
  44. package/dist/hooks.js.map +1 -1
  45. package/dist/index.d.ts +19 -27
  46. package/dist/index.js +21 -29
  47. package/dist/index.js.map +1 -1
  48. package/dist/{organisation-BtshODVF.d.ts → organisation-D6qRDtbF.d.ts} +1 -1
  49. package/dist/providers.d.ts +7 -21
  50. package/dist/providers.js +3 -10
  51. package/dist/rbac/index.d.ts +71 -221
  52. package/dist/rbac/index.js +15 -16
  53. package/dist/{types-CGX9Vyf5.d.ts → types-BDg1mAGG.d.ts} +36 -6
  54. package/dist/types.d.ts +3 -3
  55. package/dist/types.js +61 -18
  56. package/dist/types.js.map +1 -1
  57. package/dist/{unified-CM7T0aTK.d.ts → unified-DQ4VcT7H.d.ts} +1 -1
  58. package/dist/{usePublicRouteParams-B-CumWRc.d.ts → usePublicRouteParams-BlgwXweB.d.ts} +3 -3
  59. package/dist/utils.d.ts +2 -2
  60. package/dist/utils.js +52 -9
  61. package/dist/utils.js.map +1 -1
  62. package/docs/CONTENT_AUDIT_REPORT.md +253 -0
  63. package/docs/DOCUMENTATION_AUDIT.md +172 -0
  64. package/docs/README.md +142 -147
  65. package/docs/STYLE_GUIDE.md +37 -0
  66. package/docs/api/classes/ColumnFactory.md +17 -17
  67. package/docs/api/classes/ErrorBoundary.md +1 -1
  68. package/docs/api/classes/InvalidScopeError.md +4 -4
  69. package/docs/api/classes/MissingUserContextError.md +4 -4
  70. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  71. package/docs/api/classes/PermissionDeniedError.md +5 -5
  72. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  73. package/docs/api/classes/RBACAuditManager.md +8 -8
  74. package/docs/api/classes/RBACCache.md +35 -5
  75. package/docs/api/classes/RBACEngine.md +49 -20
  76. package/docs/api/classes/RBACError.md +4 -4
  77. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  78. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  79. package/docs/api/classes/StorageUtils.md +1 -1
  80. package/docs/api/enums/FileCategory.md +1 -1
  81. package/docs/api/interfaces/AggregateConfig.md +4 -4
  82. package/docs/api/interfaces/ButtonProps.md +1 -1
  83. package/docs/api/interfaces/CardProps.md +1 -1
  84. package/docs/api/interfaces/ColorPalette.md +1 -1
  85. package/docs/api/interfaces/ColorShade.md +1 -1
  86. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  87. package/docs/api/interfaces/DataRecord.md +11 -0
  88. package/docs/api/interfaces/DataTableAction.md +65 -29
  89. package/docs/api/interfaces/DataTableColumn.md +36 -23
  90. package/docs/api/interfaces/DataTableProps.md +80 -38
  91. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  92. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  93. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  94. package/docs/api/interfaces/EventLogoProps.md +1 -1
  95. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  96. package/docs/api/interfaces/FileMetadata.md +1 -1
  97. package/docs/api/interfaces/FileReference.md +1 -1
  98. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  99. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  100. package/docs/api/interfaces/FileUploadProps.md +1 -1
  101. package/docs/api/interfaces/FooterProps.md +1 -1
  102. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  103. package/docs/api/interfaces/InputProps.md +1 -1
  104. package/docs/api/interfaces/LabelProps.md +1 -1
  105. package/docs/api/interfaces/LoginFormProps.md +1 -1
  106. package/docs/api/interfaces/NavigationAccessRecord.md +11 -11
  107. package/docs/api/interfaces/NavigationContextType.md +9 -9
  108. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  109. package/docs/api/interfaces/NavigationItem.md +1 -1
  110. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  111. package/docs/api/interfaces/NavigationProviderProps.md +7 -7
  112. package/docs/api/interfaces/Organisation.md +1 -1
  113. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  114. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  115. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  116. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  117. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  118. package/docs/api/interfaces/PaceLoginPageProps.md +16 -3
  119. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  120. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  121. package/docs/api/interfaces/PagePermissionGuardProps.md +2 -2
  122. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  123. package/docs/api/interfaces/PaletteData.md +1 -1
  124. package/docs/api/interfaces/PermissionEnforcerProps.md +4 -4
  125. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  126. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  127. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  128. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  129. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  130. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  131. package/docs/api/interfaces/RBACConfig.md +1 -1
  132. package/docs/api/interfaces/RBACLogger.md +1 -1
  133. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  134. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  135. package/docs/api/interfaces/RouteAccessRecord.md +2 -2
  136. package/docs/api/interfaces/RouteConfig.md +2 -2
  137. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  138. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  139. package/docs/api/interfaces/StorageConfig.md +1 -1
  140. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  141. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  142. package/docs/api/interfaces/StorageListOptions.md +1 -1
  143. package/docs/api/interfaces/StorageListResult.md +1 -1
  144. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  145. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  146. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  147. package/docs/api/interfaces/StyleImport.md +1 -1
  148. package/docs/api/interfaces/SwitchProps.md +1 -1
  149. package/docs/api/interfaces/ToastActionElement.md +1 -1
  150. package/docs/api/interfaces/ToastProps.md +1 -1
  151. package/docs/api/interfaces/UnifiedAuthContextType.md +94 -521
  152. package/docs/api/interfaces/UnifiedAuthProviderProps.md +16 -16
  153. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  154. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  155. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  156. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  157. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  158. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  159. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  160. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  161. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  162. package/docs/api/interfaces/UserEventAccess.md +11 -11
  163. package/docs/api/interfaces/UserMenuProps.md +1 -1
  164. package/docs/api/interfaces/UserProfile.md +1 -1
  165. package/docs/api/modules.md +251 -269
  166. package/docs/api-reference/components.md +193 -0
  167. package/docs/api-reference/hooks.md +265 -0
  168. package/docs/api-reference/providers.md +6 -0
  169. package/docs/api-reference/types.md +6 -0
  170. package/docs/api-reference/utilities.md +207 -0
  171. package/docs/architecture/README.md +6 -0
  172. package/docs/{database-schema-requirements.md → architecture/database-schema-requirements.md} +6 -0
  173. package/docs/architecture/rbac-security-architecture.md +258 -0
  174. package/docs/architecture/services.md +9 -1
  175. package/docs/best-practices/README.md +6 -0
  176. package/docs/best-practices/accessibility.md +6 -0
  177. package/docs/{common-patterns.md → best-practices/common-patterns.md} +6 -0
  178. package/docs/best-practices/deployment.md +6 -0
  179. package/docs/best-practices/performance.md +475 -2
  180. package/docs/best-practices/security.md +6 -0
  181. package/docs/best-practices/testing.md +6 -0
  182. package/docs/core-concepts/authentication.md +6 -0
  183. package/docs/core-concepts/events.md +6 -0
  184. package/docs/core-concepts/organisations.md +6 -0
  185. package/docs/core-concepts/permissions.md +6 -0
  186. package/docs/core-concepts/rbac-system.md +8 -0
  187. package/docs/documentation-index.md +121 -182
  188. package/docs/{consuming-app-vite-config.md → getting-started/consuming-app-vite-config.md} +6 -0
  189. package/docs/getting-started/documentation-index.md +40 -0
  190. package/docs/getting-started/examples/README.md +878 -35
  191. package/docs/{faq.md → getting-started/faq.md} +7 -1
  192. package/docs/getting-started/installation-guide.md +6 -0
  193. package/docs/{quick-reference.md → getting-started/quick-reference.md} +6 -0
  194. package/docs/implementation-guides/app-layout.md +6 -0
  195. package/docs/implementation-guides/authentication.md +1021 -0
  196. package/docs/implementation-guides/component-styling.md +6 -0
  197. package/docs/implementation-guides/data-tables.md +1264 -2076
  198. package/docs/implementation-guides/dynamic-colors.md +6 -0
  199. package/docs/implementation-guides/event-theming-summary.md +6 -0
  200. package/docs/{file-reference-system.md → implementation-guides/file-reference-system.md} +6 -0
  201. package/docs/implementation-guides/file-upload-storage.md +6 -0
  202. package/docs/implementation-guides/forms.md +6 -0
  203. package/docs/implementation-guides/inactivity-tracking.md +6 -0
  204. package/docs/implementation-guides/navigation.md +6 -0
  205. package/docs/implementation-guides/organisation-security.md +6 -0
  206. package/docs/implementation-guides/permission-enforcement.md +6 -0
  207. package/docs/implementation-guides/public-pages-advanced.md +6 -0
  208. package/docs/implementation-guides/public-pages.md +6 -0
  209. package/docs/migration/MIGRATION_GUIDE.md +827 -351
  210. package/docs/migration/README.md +7 -1
  211. package/docs/migration/organisation-context-timing-fix.md +6 -0
  212. package/docs/migration/rbac-migration.md +44 -1
  213. package/docs/migration/service-architecture.md +6 -0
  214. package/docs/migration/v0.4.15-tailwind-scanning.md +6 -0
  215. package/docs/migration/v0.4.16-css-first-approach.md +6 -0
  216. package/docs/migration/v0.4.17-source-path-fix.md +6 -0
  217. package/docs/rbac/README-rbac-rls-integration.md +6 -0
  218. package/docs/rbac/README.md +6 -0
  219. package/docs/rbac/advanced-patterns.md +6 -0
  220. package/docs/rbac/api-reference.md +7 -1
  221. package/docs/rbac/breaking-changes-v3.md +222 -0
  222. package/docs/rbac/examples/rbac-rls-integration-example.md +6 -0
  223. package/docs/rbac/examples.md +6 -0
  224. package/docs/rbac/getting-started.md +6 -0
  225. package/docs/rbac/migration-guide.md +260 -0
  226. package/docs/rbac/quick-start.md +70 -13
  227. package/docs/rbac/rbac-rls-integration.md +6 -0
  228. package/docs/rbac/super-admin-guide.md +6 -0
  229. package/docs/rbac/troubleshooting.md +6 -0
  230. package/docs/security/README.md +6 -0
  231. package/docs/security/checklist.md +6 -0
  232. package/docs/styles/README.md +7 -1
  233. package/docs/{usage.md → styles/usage.md} +6 -0
  234. package/docs/testing/README.md +6 -0
  235. package/docs/{visual-testing.md → testing/visual-testing.md} +6 -0
  236. package/docs/troubleshooting/README.md +387 -5
  237. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +6 -0
  238. package/docs/troubleshooting/common-issues.md +6 -0
  239. package/docs/troubleshooting/database-view-compatibility.md +6 -0
  240. package/docs/troubleshooting/organisation-context-setup.md +6 -0
  241. package/docs/troubleshooting/react-hooks-issue-analysis.md +6 -0
  242. package/docs/troubleshooting/styling-issues.md +6 -0
  243. package/docs/troubleshooting/tailwind-content-scanning.md +6 -0
  244. package/package.json +1 -1
  245. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -1
  246. package/src/__tests__/helpers/test-providers.tsx +3 -53
  247. package/src/components/DataTable/DataTable.test.tsx +319 -0
  248. package/src/components/DataTable/DataTable.tsx +32 -11
  249. package/src/components/DataTable/__tests__/{DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx.skip} +6 -4
  250. package/src/components/DataTable/__tests__/{DataTable.test.tsx → DataTable.test.tsx.skip} +6 -4
  251. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +31 -9
  252. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +601 -0
  253. package/src/components/DataTable/__tests__/keyboard.test.tsx +615 -0
  254. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +639 -0
  255. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx.skip +330 -0
  256. package/src/components/DataTable/components/AccessDeniedPage.tsx +2 -2
  257. package/src/components/DataTable/components/ActionButtons.tsx +88 -104
  258. package/src/components/DataTable/components/DataTableCore.tsx +309 -337
  259. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +4 -2
  260. package/src/components/DataTable/components/DataTableModals.tsx +22 -1
  261. package/src/components/DataTable/components/EditableRow.tsx +69 -84
  262. package/src/components/DataTable/components/EmptyState.tsx +5 -1
  263. package/src/components/DataTable/components/ImportModal.tsx +65 -36
  264. package/src/components/DataTable/components/PaginationControls.tsx +40 -100
  265. package/src/components/DataTable/components/UnifiedTableBody.tsx +125 -148
  266. package/src/components/DataTable/context/DataTableContext.tsx +1 -1
  267. package/src/components/DataTable/core/ColumnFactory.ts +5 -0
  268. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +12 -10
  269. package/src/components/DataTable/examples/HierarchicalExample.tsx +1 -1
  270. package/src/components/DataTable/examples/InitialPageSizeExample.tsx +1 -0
  271. package/src/components/DataTable/examples/PerformanceExample.tsx +1 -0
  272. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +1 -5
  273. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +167 -0
  274. package/src/components/DataTable/hooks/index.ts +7 -0
  275. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +32 -15
  276. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +102 -0
  277. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +89 -0
  278. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +117 -0
  279. package/src/components/DataTable/hooks/useDataTablePermissions.ts +71 -27
  280. package/src/components/DataTable/hooks/useDataTableState.ts +39 -11
  281. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +33 -0
  282. package/src/components/DataTable/hooks/useHierarchicalState.ts +15 -1
  283. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +447 -0
  284. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +94 -0
  285. package/src/components/DataTable/hooks/useTableColumns.ts +10 -7
  286. package/src/components/DataTable/hooks/useTableHandlers.ts +174 -0
  287. package/src/components/DataTable/index.ts +12 -3
  288. package/src/components/DataTable/types.ts +129 -9
  289. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +159 -22
  290. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +111 -0
  291. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +15 -29
  292. package/src/components/DataTable/utils/a11yUtils.ts +244 -0
  293. package/src/components/DataTable/utils/debugTools.ts +609 -0
  294. package/src/components/DataTable/utils/exportUtils.ts +114 -16
  295. package/src/components/DataTable/utils/flexibleImport.ts +202 -32
  296. package/src/components/DataTable/utils/hierarchicalUtils.ts +1 -1
  297. package/src/components/DataTable/utils/index.ts +2 -0
  298. package/src/components/DataTable/utils/paginationUtils.ts +350 -0
  299. package/src/components/DataTable/utils/rowUtils.ts +6 -5
  300. package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -24
  301. package/src/components/NavigationMenu/NavigationMenu.tsx +19 -8
  302. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +1 -23
  303. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +56 -6
  304. package/src/components/PaceLoginPage/PaceLoginPage.tsx +137 -13
  305. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +1 -1
  306. package/src/components/Select/Select.tsx +1 -0
  307. package/src/components/examples/PermissionExample.tsx +173 -0
  308. package/src/examples/CorrectPublicPageImplementation.tsx +301 -0
  309. package/src/examples/PublicEventPage.tsx +274 -0
  310. package/src/examples/PublicPageApp.tsx +308 -0
  311. package/src/examples/PublicPageUsageExample.tsx +216 -0
  312. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +12 -1
  313. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +129 -17
  314. package/src/hooks/__tests__/useRBAC.unit.test.ts +151 -846
  315. package/src/hooks/useOrganisationPermissions.test.ts +42 -18
  316. package/src/hooks/useOrganisationPermissions.ts +12 -6
  317. package/src/hooks/useOrganisationSecurity.test.ts +138 -85
  318. package/src/hooks/useOrganisationSecurity.ts +41 -10
  319. package/src/index.ts +0 -1
  320. package/src/providers/AuthProvider.simplified.tsx +880 -0
  321. package/src/providers/UnifiedAuthProvider.test.simple.tsx +8 -8
  322. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +29 -19
  323. package/src/providers/index.ts +0 -1
  324. package/src/providers/services/EventServiceProvider.tsx +19 -15
  325. package/src/providers/services/InactivityServiceProvider.tsx +19 -15
  326. package/src/providers/services/OrganisationServiceProvider.tsx +19 -15
  327. package/src/providers/services/UnifiedAuthProvider.tsx +156 -127
  328. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +1 -1
  329. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -3
  330. package/src/rbac/README.md +1 -1
  331. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +25 -27
  332. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +313 -0
  333. package/src/rbac/__tests__/engine.comprehensive.test.ts +114 -348
  334. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +28 -110
  335. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +33 -85
  336. package/src/rbac/__tests__/scenarios.user-role.test.tsx +2 -2
  337. package/src/rbac/adapters.tsx +26 -69
  338. package/src/rbac/api.test.ts +90 -27
  339. package/src/rbac/api.ts +61 -10
  340. package/src/rbac/audit.test.ts +33 -38
  341. package/src/rbac/audit.ts +21 -6
  342. package/src/rbac/cache.ts +33 -1
  343. package/src/rbac/components/NavigationGuard.tsx +11 -11
  344. package/src/rbac/components/NavigationProvider.test.tsx +11 -5
  345. package/src/rbac/components/NavigationProvider.tsx +37 -13
  346. package/src/rbac/components/PagePermissionGuard.tsx +111 -50
  347. package/src/rbac/components/PagePermissionProvider.tsx +5 -5
  348. package/src/rbac/components/PermissionEnforcer.tsx +11 -11
  349. package/src/rbac/components/RoleBasedRouter.tsx +5 -5
  350. package/src/rbac/components/SecureDataProvider.tsx +5 -5
  351. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +8 -8
  352. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +14 -14
  353. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +12 -12
  354. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +6 -6
  355. package/src/rbac/engine.test.simple.ts +19 -13
  356. package/src/rbac/engine.test.ts +1 -0
  357. package/src/rbac/engine.ts +330 -766
  358. package/src/rbac/errors.ts +156 -0
  359. package/src/rbac/hooks/usePermissions.ts +32 -10
  360. package/src/rbac/hooks/useRBAC.test.ts +126 -512
  361. package/src/rbac/hooks/useRBAC.ts +147 -193
  362. package/src/rbac/hooks/useResolvedScope.ts +12 -0
  363. package/src/rbac/index.ts +7 -4
  364. package/src/rbac/security.ts +109 -18
  365. package/src/rbac/types.ts +12 -1
  366. package/src/services/AuthService.ts +2 -15
  367. package/src/services/EventService.ts +43 -46
  368. package/src/services/OrganisationService.ts +51 -31
  369. package/src/services/__tests__/AuthService.test.ts +1 -1
  370. package/src/services/__tests__/EventService.test.ts +1 -1
  371. package/src/services/__tests__/OrganisationService.test.ts +1 -1
  372. package/src/services/base/BaseService.ts +8 -0
  373. package/src/styles/base.css +208 -0
  374. package/src/styles/semantic.css +24 -0
  375. package/src/types/database.generated.ts +7347 -0
  376. package/src/types/database.ts +20 -0
  377. package/src/utils/logger.ts +179 -0
  378. package/src/utils/organisationContext.ts +11 -4
  379. package/src/utils/storage/__tests__/helpers.unit.test.ts +6 -2
  380. package/dist/appNameResolver-UURKN7NF.js +0 -22
  381. package/dist/audit-6TOCAMKO.js.map +0 -1
  382. package/dist/chunk-B2WTCLCV.js.map +0 -1
  383. package/dist/chunk-FGMFQSHX.js.map +0 -1
  384. package/dist/chunk-K34IM5CT.js.map +0 -1
  385. package/dist/chunk-KHJS6VIA.js.map +0 -1
  386. package/dist/chunk-KK73ZB4E.js.map +0 -1
  387. package/dist/chunk-M5IWZRBT.js.map +0 -1
  388. package/dist/chunk-ULBI5JGB.js +0 -109
  389. package/dist/chunk-ULBI5JGB.js.map +0 -1
  390. package/dist/chunk-WN6XJWOS.js.map +0 -1
  391. package/dist/chunk-XLZ7U46Z.js.map +0 -1
  392. package/dist/chunk-Y6TXWPJO.js.map +0 -1
  393. package/docs/DOCUMENTATION_CHECKLIST.md +0 -281
  394. package/docs/TERMINOLOGY.md +0 -231
  395. package/docs/api/interfaces/RBACContextType.md +0 -468
  396. package/docs/api/interfaces/RBACProviderProps.md +0 -107
  397. package/docs/best-practices/performance-expansion.md +0 -473
  398. package/docs/breaking-changes.md +0 -179
  399. package/docs/consuming-app-example.md +0 -290
  400. package/docs/documentation-templates.md +0 -539
  401. package/docs/examples/navigation-menu-auth-fix.md +0 -344
  402. package/docs/getting-started/examples/basic-auth-app.md +0 -520
  403. package/docs/getting-started/examples/full-featured-app.md +0 -616
  404. package/docs/getting-started/quick-start.md +0 -376
  405. package/docs/implementation-guides/datatable-filtering.md +0 -313
  406. package/docs/implementation-guides/datatable-rbac-usage.md +0 -317
  407. package/docs/implementation-guides/hierarchical-datatable.md +0 -850
  408. package/docs/implementation-guides/large-datasets.md +0 -281
  409. package/docs/implementation-guides/performance.md +0 -403
  410. package/docs/migration/quick-migration-guide.md +0 -320
  411. package/docs/migration-guide.md +0 -193
  412. package/docs/migration-guides/unified-auth-provider-mandatory-timeouts.md +0 -226
  413. package/docs/performance/README.md +0 -551
  414. package/docs/style-guide.md +0 -964
  415. package/docs/troubleshooting/authentication-issues.md +0 -334
  416. package/docs/troubleshooting/debugging.md +0 -1117
  417. package/docs/troubleshooting/migration.md +0 -918
  418. package/src/__tests__/hooks/usePermissions.test.ts +0 -261
  419. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +0 -574
  420. package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -613
  421. package/src/hooks/services/__tests__/useServiceHooks.test.tsx +0 -137
  422. package/src/hooks/services/usePermissions.ts +0 -70
  423. package/src/hooks/services/useRBACService.ts +0 -30
  424. package/src/hooks/usePermissionCheck.ts +0 -150
  425. package/src/providers/__tests__/ServiceProviders.test.tsx +0 -477
  426. package/src/providers/services/RBACServiceProvider.tsx +0 -79
  427. package/src/rbac/__tests__/integration.authflow.test.tsx +0 -119
  428. package/src/rbac/__tests__/integration.navigation.test.tsx +0 -69
  429. package/src/rbac/__tests__/integration.securedata.test.tsx +0 -92
  430. package/src/rbac/__tests__/integration.smoke.test.tsx +0 -73
  431. package/src/rbac/providers/RBACProvider.tsx +0 -645
  432. package/src/rbac/providers/__tests__/RBACProvider.integration.test.tsx +0 -688
  433. package/src/rbac/providers/__tests__/RBACProvider.test.tsx +0 -1186
  434. package/src/rbac/providers/index.ts +0 -11
  435. package/src/services/RBACService.ts +0 -522
  436. package/src/services/__tests__/RBACService.test.ts +0 -492
  437. package/src/services/interfaces/IRBACService.ts +0 -62
  438. package/src/utils/appNameResolver.test 2.ts +0 -494
  439. /package/dist/{DataTable-4GAVPIEG.js.map → DataTable-ETGVF4Y5.js.map} +0 -0
  440. /package/dist/{UnifiedAuthProvider-3NKDOSOK.js.map → UnifiedAuthProvider-P5SOJAQ6.js.map} +0 -0
  441. /package/dist/{api-DDMUKIUD.js.map → api-KG4A2X7P.js.map} +0 -0
  442. /package/dist/{appNameResolver-UURKN7NF.js.map → audit-65VNHEV2.js.map} +0 -0
  443. /package/dist/{chunk-NTNILOBC.js.map → chunk-5BO3MI5Y.js.map} +0 -0
  444. /package/dist/{chunk-URUTVZ7N.js.map → chunk-FL4ZCQLD.js.map} +0 -0
  445. /package/dist/{chunk-LW7MMEAQ.js.map → chunk-FT2M4R4F.js.map} +0 -0
  446. /package/dist/{chunk-AFGTSUAD.js.map → chunk-VSOKOFRF.js.map} +0 -0
  447. /package/docs/{app.css.example → styles/app.css.example} +0 -0
@@ -12,6 +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
16
  import {
16
17
  PlusIcon,
17
18
  PencilIcon,
@@ -173,7 +174,7 @@ const hierarchicalActions: DataTableAction<Dish>[] = [
173
174
  parentLabel: 'View Dish',
174
175
  childLabel: 'View Ingredient',
175
176
  onClick: (row) => {
176
- console.log('Viewing:', row.isParent ? 'Dish' : 'Ingredient', row.name || row.item);
177
+ // View action
177
178
  },
178
179
  variant: 'default',
179
180
  testId: 'view',
@@ -188,7 +189,7 @@ const hierarchicalActions: DataTableAction<Dish>[] = [
188
189
  parentLabel: 'Edit Recipe',
189
190
  childLabel: 'Edit Ingredient',
190
191
  onClick: (row) => {
191
- console.log('Editing:', row.isParent ? 'Recipe' : 'Ingredient', row.name || row.item);
192
+ // Edit action
192
193
  },
193
194
  variant: 'default',
194
195
  testId: 'edit',
@@ -201,7 +202,7 @@ const hierarchicalActions: DataTableAction<Dish>[] = [
201
202
  parentIcon: CopyIcon,
202
203
  parentLabel: 'Duplicate Recipe',
203
204
  onClick: (row) => {
204
- console.log('Copying recipe:', row.name);
205
+ // Copy recipe action
205
206
  },
206
207
  variant: 'outline',
207
208
  testId: 'copy',
@@ -215,7 +216,7 @@ const hierarchicalActions: DataTableAction<Dish>[] = [
215
216
  parentIcon: PlusIcon,
216
217
  parentLabel: 'Add Ingredient',
217
218
  onClick: (row) => {
218
- console.log('Adding ingredient to recipe:', row.name);
219
+ // Add ingredient action
219
220
  },
220
221
  variant: 'secondary',
221
222
  testId: 'add-ingredient',
@@ -229,7 +230,7 @@ const hierarchicalActions: DataTableAction<Dish>[] = [
229
230
  childIcon: DownloadIcon,
230
231
  childLabel: 'Export Ingredient',
231
232
  onClick: (row) => {
232
- console.log('Exporting ingredient:', row.item);
233
+ // Export ingredient action
233
234
  },
234
235
  variant: 'ghost',
235
236
  testId: 'export',
@@ -245,7 +246,7 @@ const hierarchicalActions: DataTableAction<Dish>[] = [
245
246
  parentLabel: 'Favorite Recipe',
246
247
  childLabel: 'Favorite Ingredient',
247
248
  onClick: (row) => {
248
- console.log('Starring:', row.isParent ? 'Recipe' : 'Ingredient', row.name || row.item);
249
+ // Star action
249
250
  },
250
251
  variant: 'ghost',
251
252
  testId: 'star',
@@ -260,7 +261,7 @@ const hierarchicalActions: DataTableAction<Dish>[] = [
260
261
  parentLabel: 'Delete Recipe',
261
262
  childLabel: 'Remove Ingredient',
262
263
  onClick: (row) => {
263
- console.log('Deleting:', row.isParent ? 'Recipe' : 'Ingredient', row.name || row.item);
264
+ // Delete action
264
265
  },
265
266
  variant: 'destructive',
266
267
  testId: 'delete',
@@ -351,6 +352,7 @@ const columns: DataTableColumn<Dish>[] = [
351
352
  // ============================================================================
352
353
 
353
354
  export function HierarchicalActionsExample() {
355
+ const logger = createLogger('HierarchicalActionsExample');
354
356
  return (
355
357
  <div className="space-y-6">
356
358
  <div>
@@ -400,7 +402,7 @@ export function HierarchicalActionsExample() {
400
402
  enabled: true,
401
403
  defaultExpanded: false,
402
404
  onExpandedChange: (expandedIds) => {
403
- console.log('Expanded rows:', expandedIds);
405
+ // Expanded rows changed
404
406
  },
405
407
  parentRowClassName: 'bg-main-50 hover:bg-main-100 font-medium',
406
408
  childRowClassName: 'bg-sec-25 hover:bg-sec-50',
@@ -408,10 +410,10 @@ export function HierarchicalActionsExample() {
408
410
  }}
409
411
  actions={hierarchicalActions}
410
412
  onEditRow={(row, data) => {
411
- console.log('Edit row:', row, data);
413
+ // Edit row action
412
414
  }}
413
415
  onDeleteRow={(row) => {
414
- console.log('Delete row:', row);
416
+ // Delete row action
415
417
  }}
416
418
  />
417
419
  </div>
@@ -311,7 +311,7 @@ const hierarchicalConfig: HierarchicalConfig = {
311
311
  enabled: true,
312
312
  defaultExpanded: false, // Start collapsed
313
313
  onExpandedChange: (expandedIds) => {
314
- console.log('Expanded rows:', expandedIds);
314
+ // Expanded rows changed
315
315
  },
316
316
  expandButton: ExpandButton, // Use default expand button
317
317
  indentSize: 24, // 24px indentation for child rows
@@ -16,6 +16,7 @@ interface User {
16
16
  email: string;
17
17
  role: string;
18
18
  status: 'active' | 'inactive';
19
+ [key: string]: unknown;
19
20
  }
20
21
 
21
22
  const columns: DataTableColumn<User>[] = [
@@ -26,6 +26,7 @@ interface User {
26
26
  status: 'active' | 'inactive';
27
27
  lastLogin: string;
28
28
  createdAt: string;
29
+ [key: string]: unknown;
29
30
  }
30
31
 
31
32
  // Generate large dataset for testing
@@ -153,8 +153,6 @@ describe('[unit] useColumnOrderPersistence', () => {
153
153
  it('handles invalid JSON in localStorage gracefully', async () => {
154
154
  localStorage.setItem('datatable-column-order-test', 'invalid-json');
155
155
 
156
- const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
157
-
158
156
  const { result } = renderHook(() => useColumnOrderPersistence({
159
157
  tableId: 'test',
160
158
  defaultOrder: ['col1', 'col2'],
@@ -165,10 +163,8 @@ describe('[unit] useColumnOrderPersistence', () => {
165
163
  expect(result.current.isLoaded).toBe(true);
166
164
  });
167
165
 
166
+ // Should use default order when invalid JSON is encountered
168
167
  expect(result.current.columnOrder).toEqual(['col1', 'col2']);
169
- expect(consoleWarnSpy).toHaveBeenCalled();
170
-
171
- consoleWarnSpy.mockRestore();
172
168
  });
173
169
 
174
170
  it('handles localStorage quota exceeded error gracefully', async () => {
@@ -0,0 +1,167 @@
1
+ /**
2
+ * @file Unit Tests for useColumnVisibilityPersistence Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module Components/DataTable/Hooks/__tests__
5
+ */
6
+
7
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
8
+ import { renderHook, waitFor, act } from '@testing-library/react';
9
+ import { useColumnVisibilityPersistence } from '../useColumnVisibilityPersistence';
10
+
11
+ describe('[unit] useColumnVisibilityPersistence', () => {
12
+ beforeEach(() => {
13
+ localStorage.clear();
14
+ vi.clearAllMocks();
15
+ });
16
+
17
+ afterEach(() => {
18
+ vi.restoreAllMocks();
19
+ });
20
+
21
+ describe('Initialization', () => {
22
+ it('initializes with default visibility when no saved visibility exists', async () => {
23
+ const defaultVisibility = { col1: true, col2: false };
24
+ const { result } = renderHook(() => useColumnVisibilityPersistence({
25
+ tableId: 'test',
26
+ defaultVisibility,
27
+ enablePersistence: true
28
+ }));
29
+
30
+ await waitFor(() => {
31
+ expect(result.current.isLoaded).toBe(true);
32
+ });
33
+
34
+ expect(result.current.columnVisibility).toEqual(defaultVisibility);
35
+ });
36
+
37
+ it('loads saved visibility from localStorage on mount', async () => {
38
+ const savedVisibility = { col1: false, col2: true };
39
+ localStorage.setItem('datatable-column-visibility-test', JSON.stringify(savedVisibility));
40
+
41
+ const { result } = renderHook(() => useColumnVisibilityPersistence({
42
+ tableId: 'test',
43
+ defaultVisibility: { col1: true, col2: true },
44
+ enablePersistence: true
45
+ }));
46
+
47
+ await waitFor(() => {
48
+ expect(result.current.isLoaded).toBe(true);
49
+ });
50
+
51
+ expect(result.current.columnVisibility).toEqual(savedVisibility);
52
+ });
53
+
54
+ it('uses storageKey when provided', async () => {
55
+ const savedVisibility = { col1: true, col2: false };
56
+ localStorage.setItem('custom-key-column-visibility', JSON.stringify(savedVisibility));
57
+
58
+ const { result } = renderHook(() => useColumnVisibilityPersistence({
59
+ tableId: 'test',
60
+ defaultVisibility: { col1: false, col2: true },
61
+ enablePersistence: true,
62
+ storageKey: 'custom-key'
63
+ }));
64
+
65
+ await waitFor(() => {
66
+ expect(result.current.isLoaded).toBe(true);
67
+ });
68
+
69
+ expect(result.current.columnVisibility).toEqual(savedVisibility);
70
+ });
71
+ });
72
+
73
+ describe('Persistence', () => {
74
+ it('saves column visibility to localStorage when updated', async () => {
75
+ const newVisibility = { col1: false, col2: true };
76
+ const { result } = renderHook(() => useColumnVisibilityPersistence({
77
+ tableId: 'test',
78
+ defaultVisibility: { col1: true, col2: true },
79
+ enablePersistence: true
80
+ }));
81
+
82
+ await waitFor(() => {
83
+ expect(result.current.isLoaded).toBe(true);
84
+ });
85
+
86
+ act(() => {
87
+ result.current.updateColumnVisibility(newVisibility);
88
+ });
89
+
90
+ expect(result.current.columnVisibility).toEqual(newVisibility);
91
+
92
+ const saved = localStorage.getItem('datatable-column-visibility-test');
93
+ expect(saved).toBe(JSON.stringify(newVisibility));
94
+ });
95
+
96
+ it('does not persist when enablePersistence is false', async () => {
97
+ const { result } = renderHook(() => useColumnVisibilityPersistence({
98
+ tableId: 'test',
99
+ defaultVisibility: { col1: true },
100
+ enablePersistence: false
101
+ }));
102
+
103
+ await waitFor(() => {
104
+ expect(result.current.isLoaded).toBe(true);
105
+ });
106
+
107
+ act(() => {
108
+ result.current.updateColumnVisibility({ col1: false });
109
+ });
110
+
111
+ expect(result.current.columnVisibility).toEqual({ col1: false });
112
+ expect(localStorage.getItem('datatable-column-visibility-test')).toBeNull();
113
+ });
114
+ });
115
+
116
+ describe('Multi-table persistence', () => {
117
+ it('persists different visibility states for different storage keys', async () => {
118
+ // Table 1
119
+ const { result: result1 } = renderHook(() => useColumnVisibilityPersistence({
120
+ enablePersistence: true,
121
+ storageKey: 'table1',
122
+ defaultVisibility: { col1: true }
123
+ }));
124
+
125
+ await waitFor(() => {
126
+ expect(result1.current.isLoaded).toBe(true);
127
+ });
128
+
129
+ act(() => {
130
+ result1.current.updateColumnVisibility({ col1: false });
131
+ });
132
+
133
+ // Table 2
134
+ const { result: result2 } = renderHook(() => useColumnVisibilityPersistence({
135
+ enablePersistence: true,
136
+ storageKey: 'table2',
137
+ defaultVisibility: { col1: true }
138
+ }));
139
+
140
+ await waitFor(() => {
141
+ expect(result2.current.isLoaded).toBe(true);
142
+ });
143
+
144
+ act(() => {
145
+ result2.current.updateColumnVisibility({ col1: true });
146
+ });
147
+
148
+ // Both should have their own saved state
149
+ expect(localStorage.getItem('table1-column-visibility')).toBe(JSON.stringify({ col1: false }));
150
+ expect(localStorage.getItem('table2-column-visibility')).toBe(JSON.stringify({ col1: true }));
151
+
152
+ // Reload table1 and it should have false
153
+ const { result: reload1 } = renderHook(() => useColumnVisibilityPersistence({
154
+ enablePersistence: true,
155
+ storageKey: 'table1',
156
+ defaultVisibility: { col1: true }
157
+ }));
158
+
159
+ await waitFor(() => {
160
+ expect(reload1.current.isLoaded).toBe(true);
161
+ });
162
+
163
+ expect(reload1.current.columnVisibility).toEqual({ col1: false });
164
+ });
165
+ });
166
+ });
167
+
@@ -2,5 +2,12 @@ export * from './useDataTableState';
2
2
  export * from './useDataTablePermissions';
3
3
  export * from './useTableColumns';
4
4
  export * from './useColumnOrderPersistence';
5
+ export * from './useColumnVisibilityPersistence';
5
6
  export * from './useHierarchicalState';
7
+ export * from './useKeyboardNavigation';
8
+ export * from './useDataTableDataPipeline';
9
+ export * from './useServerSideDataEffect';
10
+ export * from './useEffectiveColumnOrder';
11
+ export * from './useTableHandlers';
12
+ export * from './useDataTableConfiguration';
6
13
 
@@ -1,31 +1,44 @@
1
1
  import { useState, useEffect, useCallback } from 'react';
2
+ import { createLogger } from '../../../utils/logger';
2
3
 
3
4
  interface UseColumnOrderPersistenceProps {
4
5
  tableId?: string;
5
6
  defaultOrder?: string[];
6
7
  enablePersistence?: boolean;
8
+ storageKey?: string;
7
9
  }
8
10
 
9
11
  export function useColumnOrderPersistence({
10
12
  tableId,
11
13
  defaultOrder = [],
12
14
  enablePersistence = false,
15
+ storageKey,
13
16
  }: UseColumnOrderPersistenceProps) {
17
+ const logger = createLogger('ColumnOrderPersistence');
14
18
  const [columnOrder, setColumnOrder] = useState<string[]>(defaultOrder);
15
19
  const [isLoaded, setIsLoaded] = useState(false);
16
20
 
17
21
  // Generate a unique key for this table
18
- const storageKey = tableId ? `datatable-column-order-${tableId}` : 'datatable-column-order';
22
+ const finalStorageKey = storageKey
23
+ ? `${storageKey}-column-order`
24
+ : (tableId ? `datatable-column-order-${tableId}` : 'datatable-column-order');
19
25
 
20
26
  // Load column order from localStorage on mount
21
27
  useEffect(() => {
22
- if (!enablePersistence || !tableId) {
28
+ if (!enablePersistence || typeof window === 'undefined') {
29
+ setIsLoaded(true);
30
+ return;
31
+ }
32
+
33
+ // Only load if we have a storage key (either via storageKey prop or tableId)
34
+ // This maintains backward compatibility with existing tests
35
+ if (!storageKey && !tableId) {
23
36
  setIsLoaded(true);
24
37
  return;
25
38
  }
26
39
 
27
40
  try {
28
- const savedOrder = localStorage.getItem(storageKey);
41
+ const savedOrder = localStorage.getItem(finalStorageKey);
29
42
  if (savedOrder) {
30
43
  const parsedOrder = JSON.parse(savedOrder);
31
44
  if (Array.isArray(parsedOrder)) {
@@ -33,22 +46,26 @@ export function useColumnOrderPersistence({
33
46
  }
34
47
  }
35
48
  } catch (error) {
36
- console.warn('Failed to load column order from localStorage:', error);
49
+ logger.warn('Failed to load column order from localStorage:', error);
37
50
  } finally {
38
51
  setIsLoaded(true);
39
52
  }
40
- }, [enablePersistence, tableId, storageKey]);
53
+ }, [enablePersistence, finalStorageKey, storageKey, tableId]);
41
54
 
42
55
  // Save column order to localStorage
43
56
  const saveColumnOrder = useCallback((newOrder: string[]) => {
44
- if (!enablePersistence || !tableId) return;
57
+ if (!enablePersistence || typeof window === 'undefined') return;
58
+
59
+ // Only save if we have a storage key (either via storageKey prop or tableId)
60
+ // This maintains backward compatibility with existing tests
61
+ if (!storageKey && !tableId) return;
45
62
 
46
63
  try {
47
- localStorage.setItem(storageKey, JSON.stringify(newOrder));
64
+ localStorage.setItem(finalStorageKey, JSON.stringify(newOrder));
48
65
  } catch (error) {
49
- console.warn('Failed to save column order to localStorage:', error);
66
+ logger.warn('Failed to save column order to localStorage:', error);
50
67
  }
51
- }, [enablePersistence, tableId, storageKey]);
68
+ }, [enablePersistence, finalStorageKey, storageKey, tableId]);
52
69
 
53
70
  // Update column order and save to localStorage
54
71
  const updateColumnOrder = useCallback((newOrder: string[]) => {
@@ -59,18 +76,18 @@ export function useColumnOrderPersistence({
59
76
  // Reset to default order
60
77
  const resetColumnOrder = useCallback(() => {
61
78
  setColumnOrder(defaultOrder);
62
- if (enablePersistence && tableId) {
79
+ if (enablePersistence && (storageKey || tableId) && typeof window !== 'undefined') {
63
80
  try {
64
- localStorage.removeItem(storageKey);
81
+ localStorage.removeItem(finalStorageKey);
65
82
  } catch (error) {
66
- console.warn('Failed to remove column order from localStorage:', error);
83
+ logger.warn('Failed to remove column order from localStorage:', error);
67
84
  }
68
85
  }
69
- }, [defaultOrder, enablePersistence, tableId, storageKey]);
86
+ }, [defaultOrder, enablePersistence, finalStorageKey, storageKey, tableId]);
70
87
 
71
88
  // Clear all saved preferences
72
89
  const clearAllPreferences = useCallback(() => {
73
- if (!enablePersistence) return;
90
+ if (!enablePersistence || typeof window === 'undefined') return;
74
91
 
75
92
  try {
76
93
  // Remove all datatable preferences
@@ -81,7 +98,7 @@ export function useColumnOrderPersistence({
81
98
  }
82
99
  });
83
100
  } catch (error) {
84
- console.warn('Failed to clear datatable preferences:', error);
101
+ logger.warn('Failed to clear datatable preferences:', error);
85
102
  }
86
103
  }, [enablePersistence]);
87
104
 
@@ -0,0 +1,102 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { createLogger } from '../../../utils/logger';
3
+
4
+ interface UseColumnVisibilityPersistenceProps {
5
+ tableId?: string;
6
+ defaultVisibility?: Record<string, boolean>;
7
+ enablePersistence?: boolean;
8
+ storageKey?: string;
9
+ }
10
+
11
+ export function useColumnVisibilityPersistence({
12
+ tableId,
13
+ defaultVisibility = {},
14
+ enablePersistence = false,
15
+ storageKey,
16
+ }: UseColumnVisibilityPersistenceProps) {
17
+ const logger = createLogger('ColumnVisibilityPersistence');
18
+ const [columnVisibility, setColumnVisibility] = useState<Record<string, boolean>>(defaultVisibility);
19
+ const [isLoaded, setIsLoaded] = useState(false);
20
+
21
+ // Generate a unique key for this table
22
+ const finalStorageKey = storageKey
23
+ ? `${storageKey}-column-visibility`
24
+ : (tableId ? `datatable-column-visibility-${tableId}` : 'datatable-column-visibility');
25
+
26
+ // Load column visibility from localStorage on mount
27
+ useEffect(() => {
28
+ if (!enablePersistence || typeof window === 'undefined') {
29
+ setIsLoaded(true);
30
+ return;
31
+ }
32
+
33
+ try {
34
+ const savedVisibility = localStorage.getItem(finalStorageKey);
35
+ if (savedVisibility) {
36
+ const parsedVisibility = JSON.parse(savedVisibility);
37
+ if (typeof parsedVisibility === 'object' && parsedVisibility !== null) {
38
+ setColumnVisibility(parsedVisibility);
39
+ }
40
+ }
41
+ } catch (error) {
42
+ logger.warn('Failed to load column visibility from localStorage:', error);
43
+ } finally {
44
+ setIsLoaded(true);
45
+ }
46
+ }, [enablePersistence, finalStorageKey]);
47
+
48
+ // Save column visibility to localStorage
49
+ const saveColumnVisibility = useCallback((newVisibility: Record<string, boolean>) => {
50
+ if (!enablePersistence || typeof window === 'undefined') return;
51
+
52
+ try {
53
+ localStorage.setItem(finalStorageKey, JSON.stringify(newVisibility));
54
+ } catch (error) {
55
+ logger.warn('Failed to save column visibility to localStorage:', error);
56
+ }
57
+ }, [enablePersistence, finalStorageKey]);
58
+
59
+ // Update column visibility and save to localStorage
60
+ const updateColumnVisibility = useCallback((newVisibility: Record<string, boolean>) => {
61
+ setColumnVisibility(newVisibility);
62
+ saveColumnVisibility(newVisibility);
63
+ }, [saveColumnVisibility]);
64
+
65
+ // Reset to default visibility
66
+ const resetColumnVisibility = useCallback(() => {
67
+ setColumnVisibility(defaultVisibility);
68
+ if (enablePersistence && typeof window !== 'undefined') {
69
+ try {
70
+ localStorage.removeItem(finalStorageKey);
71
+ } catch (error) {
72
+ logger.warn('Failed to remove column visibility from localStorage:', error);
73
+ }
74
+ }
75
+ }, [defaultVisibility, enablePersistence, finalStorageKey]);
76
+
77
+ // Clear all saved preferences
78
+ const clearAllPreferences = useCallback(() => {
79
+ if (!enablePersistence || typeof window === 'undefined') return;
80
+
81
+ try {
82
+ // Remove all datatable preferences
83
+ const keys = Object.keys(localStorage);
84
+ keys.forEach(key => {
85
+ if (key.startsWith('datatable-')) {
86
+ localStorage.removeItem(key);
87
+ }
88
+ });
89
+ } catch (error) {
90
+ logger.warn('Failed to clear datatable preferences:', error);
91
+ }
92
+ }, [enablePersistence]);
93
+
94
+ return {
95
+ columnVisibility,
96
+ isLoaded,
97
+ updateColumnVisibility,
98
+ resetColumnVisibility,
99
+ clearAllPreferences,
100
+ };
101
+ }
102
+
@@ -0,0 +1,89 @@
1
+ import { useMemo } from 'react';
2
+ import {
3
+ getCoreRowModel,
4
+ getExpandedRowModel,
5
+ getFilteredRowModel,
6
+ getGroupedRowModel,
7
+ getPaginationRowModel,
8
+ getSortedRowModel,
9
+ type ColumnDef,
10
+ } from '@tanstack/react-table';
11
+
12
+ import type {
13
+ DataRecord,
14
+ NormalizedDataTableFeatureConfig,
15
+ PaginationMode,
16
+ GetRowId,
17
+ } from '../types';
18
+ import type { TableHandlers, TableStateSnapshot } from './useTableHandlers';
19
+
20
+ interface UseDataTableConfigurationOptions<TData extends DataRecord> {
21
+ data: TData[];
22
+ columns: ColumnDef<TData>[];
23
+ stateSnapshot: TableStateSnapshot<TData>;
24
+ handlers: TableHandlers;
25
+ features: NormalizedDataTableFeatureConfig;
26
+ getRowId: GetRowId<TData>;
27
+ finalPaginationMode: PaginationMode;
28
+ finalDataCount: number;
29
+ pageSize: number;
30
+ }
31
+
32
+ export function useDataTableConfiguration<TData extends DataRecord>({
33
+ data,
34
+ columns,
35
+ stateSnapshot,
36
+ handlers,
37
+ features,
38
+ getRowId,
39
+ finalPaginationMode,
40
+ finalDataCount,
41
+ pageSize,
42
+ }: UseDataTableConfigurationOptions<TData>) {
43
+ return useMemo(() => ({
44
+ data,
45
+ columns,
46
+ state: {
47
+ sorting: stateSnapshot.sorting,
48
+ columnFilters: stateSnapshot.columnFilters,
49
+ columnVisibility: stateSnapshot.columnVisibility,
50
+ rowSelection: stateSnapshot.rowSelection,
51
+ grouping: stateSnapshot.grouping,
52
+ expanded: stateSnapshot.expanded,
53
+ pagination: stateSnapshot.pagination,
54
+ globalFilter: stateSnapshot.globalFilter,
55
+ columnOrder: stateSnapshot.columnOrder,
56
+ },
57
+ initialState: {
58
+ expanded: features.grouping ? {} : undefined,
59
+ },
60
+ enableRowSelection: features.selection,
61
+ enableGrouping: features.grouping,
62
+ getRowId,
63
+ ...handlers,
64
+ getCoreRowModel: getCoreRowModel(),
65
+ getFilteredRowModel: finalPaginationMode === 'client' ? getFilteredRowModel() : undefined,
66
+ getSortedRowModel: finalPaginationMode === 'client' ? getSortedRowModel() : undefined,
67
+ getPaginationRowModel: features.pagination ? getPaginationRowModel() : undefined,
68
+ getGroupedRowModel: features.grouping ? getGroupedRowModel() : undefined,
69
+ getExpandedRowModel: features.grouping ? getExpandedRowModel() : undefined,
70
+ manualSorting: finalPaginationMode === 'server',
71
+ manualFiltering: finalPaginationMode === 'server',
72
+ manualPagination: finalPaginationMode === 'server',
73
+ pageCount: finalPaginationMode === 'server'
74
+ ? Math.ceil(finalDataCount / pageSize)
75
+ : undefined,
76
+ }), [
77
+ data,
78
+ columns,
79
+ stateSnapshot,
80
+ handlers,
81
+ features.selection,
82
+ features.grouping,
83
+ features.pagination,
84
+ getRowId,
85
+ finalPaginationMode,
86
+ finalDataCount,
87
+ pageSize,
88
+ ]);
89
+ }