@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
@@ -10,6 +10,7 @@
10
10
  import React, { Component, ErrorInfo, ReactNode } from 'react';
11
11
  import { Alert, AlertDescription, AlertTitle } from '../../Alert/Alert';
12
12
  import { Button } from '../../Button/Button';
13
+ import { createLogger } from '../../../utils/logger';
13
14
  // Icons removed to avoid test mocking issues
14
15
 
15
16
  // ============================================================================
@@ -45,6 +46,7 @@ export class DataTableErrorBoundary extends Component<
45
46
  DataTableErrorBoundaryProps,
46
47
  ErrorBoundaryState
47
48
  > {
49
+ private logger = createLogger('DataTableErrorBoundary');
48
50
  private retryTimeoutId: NodeJS.Timeout | null = null;
49
51
 
50
52
  constructor(props: DataTableErrorBoundaryProps) {
@@ -74,7 +76,7 @@ export class DataTableErrorBoundary extends Component<
74
76
  this.props.onError?.(error, errorInfo);
75
77
 
76
78
  // Log error for debugging
77
- console.error('DataTable Error Boundary caught an error:', error, errorInfo);
79
+ this.logger.error('Error Boundary caught an error:', error, errorInfo);
78
80
  }
79
81
 
80
82
  componentWillUnmount() {
@@ -88,7 +90,7 @@ export class DataTableErrorBoundary extends Component<
88
90
  const { retryCount } = this.state;
89
91
 
90
92
  if (retryCount >= maxRetries) {
91
- console.warn('DataTable Error Boundary: Maximum retry attempts reached');
93
+ this.logger.warn('Error Boundary: Maximum retry attempts reached');
92
94
  return;
93
95
  }
94
96
 
@@ -21,7 +21,7 @@
21
21
  * ```
22
22
  */
23
23
 
24
- import React from 'react';
24
+ import React, { useEffect } from 'react';
25
25
  import { ImportModal, type ImportModalConfig } from './ImportModal';
26
26
 
27
27
  /**
@@ -39,6 +39,11 @@ export interface DataTableModalsProps {
39
39
  /** Configuration object for customizing import modal text content */
40
40
  importModalConfig?: ImportModalConfig;
41
41
 
42
+ // Focus management
43
+ /** Function to store focus before opening modal */
44
+ onStoreFocus?: () => void;
45
+ /** Function to restore focus after closing modal */
46
+ onRestoreFocus?: () => void;
42
47
  }
43
48
 
44
49
  /**
@@ -72,7 +77,23 @@ export function DataTableModals({
72
77
  onCloseImportModal,
73
78
  onImport,
74
79
  importModalConfig,
80
+ onStoreFocus,
81
+ onRestoreFocus,
75
82
  }: DataTableModalsProps) {
83
+ // Handle focus management for import modal
84
+ useEffect(() => {
85
+ if (showImportModal) {
86
+ onStoreFocus?.();
87
+ } else {
88
+ // Restore focus when modal closes
89
+ const timeoutId = setTimeout(() => {
90
+ onRestoreFocus?.();
91
+ }, 100); // Small delay to ensure modal is fully closed
92
+
93
+ return () => clearTimeout(timeoutId);
94
+ }
95
+ }, [showImportModal, onStoreFocus, onRestoreFocus]);
96
+
76
97
  return (
77
98
  <>
78
99
  <ImportModal
@@ -1,15 +1,22 @@
1
1
  import React from 'react';
2
- import { flexRender } from '@tanstack/react-table';
3
- import { ActionButtons } from './ActionButtons';
4
- import { Input } from '../../Input/Input';
5
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../Select/Select';
2
+ import { flexRender, type Row, type Column } from '@tanstack/react-table';
3
+
6
4
  import { Button } from '../../Button/Button';
7
- import type { DataTableAction, DataRecord } from '../types';
5
+ import { Input } from '../../Input/Input';
6
+ import {
7
+ Select,
8
+ SelectContent,
9
+ SelectItem,
10
+ SelectTrigger,
11
+ SelectValue,
12
+ } from '../../Select/Select';
13
+ import { ActionButtons } from './ActionButtons';
14
+ import type { CellValue, DataRecord, DataTableAction, EditableColumnDef } from '../types';
8
15
 
9
16
  interface EditableRowProps<TData extends DataRecord> {
10
- row: any;
11
- editingData: Record<string, any>;
12
- onEditingDataChange: (data: Record<string, any>) => void;
17
+ row: Row<TData>;
18
+ editingData: Record<string, CellValue>;
19
+ onEditingDataChange: (data: Record<string, CellValue>) => void;
13
20
  onSave: () => void;
14
21
  onCancel: () => void;
15
22
  actions: DataTableAction<TData>[];
@@ -18,45 +25,32 @@ interface EditableRowProps<TData extends DataRecord> {
18
25
  hierarchical?: boolean;
19
26
  }
20
27
 
21
- // Helper function to render the appropriate input type based on column configuration
22
- const renderEditField = (
23
- column: any,
24
- value: any,
25
- onChange: (value: any) => void,
26
- editingData: Record<string, any> = {},
27
- placeholder?: string
28
+ const renderEditField = <TData extends DataRecord>(
29
+ column: Column<TData, unknown>,
30
+ value: CellValue,
31
+ onChange: (value: CellValue | Record<string, CellValue>) => void,
32
+ editingData: Record<string, CellValue> = {}
28
33
  ) => {
29
- const columnDef = column.columnDef;
30
-
31
- // Check if column is editable (default: true)
34
+ const columnDef = column.columnDef as EditableColumnDef<TData>;
35
+
32
36
  if (columnDef.editable === false) {
33
- // Return the original value as text if column is not editable
34
- return <span className="text-sm text-gray-600">{value || ''}</span>;
37
+ return <span className="text-sm text-gray-600">{String(value ?? '')}</span>;
35
38
  }
36
-
37
- // Check for custom field type
39
+
38
40
  if (columnDef.fieldType === 'select' && columnDef.fieldOptions) {
39
- // Use editAccessorKey if specified, otherwise use the column id
40
- const editKey = columnDef.editAccessorKey || column.id;
41
- const editValue = editingData[editKey] || value;
42
-
41
+ const accessorKey = columnDef.editAccessorKey || column.id;
42
+ const currentValue = editingData[accessorKey] ?? value ?? '';
43
+
43
44
  return (
44
45
  <Select
45
- value={String(editValue || '')}
46
- onValueChange={(newValue) => {
47
- // If editAccessorKey is specified, update that field instead
48
- if (columnDef.editAccessorKey) {
49
- onChange({ [columnDef.editAccessorKey]: Number(newValue) });
50
- } else {
51
- onChange(newValue);
52
- }
53
- }}
46
+ value={String(currentValue)}
47
+ onValueChange={(newValue) => onChange({ [accessorKey]: newValue as CellValue })}
54
48
  >
55
49
  <SelectTrigger className="w-full h-7">
56
- <SelectValue placeholder={placeholder || `Select ${column.id}`} />
50
+ <SelectValue placeholder={`Select ${column.id}`} />
57
51
  </SelectTrigger>
58
52
  <SelectContent>
59
- {columnDef.fieldOptions.map((option: any) => (
53
+ {columnDef.fieldOptions.map(option => (
60
54
  <SelectItem key={option.value} value={String(option.value)}>
61
55
  {option.label}
62
56
  </SelectItem>
@@ -65,26 +59,36 @@ const renderEditField = (
65
59
  </Select>
66
60
  );
67
61
  }
68
-
62
+
69
63
  if (columnDef.fieldType === 'date') {
70
64
  return (
71
65
  <Input
72
66
  type="date"
73
- value={value || ''}
74
- onChange={(e) => onChange(e.target.value)}
67
+ value={String(value ?? '')}
68
+ onChange={(e) => onChange(e.target.value as unknown as CellValue)}
75
69
  className="w-full h-7"
76
70
  />
77
71
  );
78
72
  }
79
-
80
- // Default to text input
73
+
74
+ if (columnDef.fieldType === 'number') {
75
+ return (
76
+ <Input
77
+ type="number"
78
+ value={String(value ?? '')}
79
+ onChange={(e) => onChange(e.target.value as unknown as CellValue)}
80
+ className="w-full h-7"
81
+ />
82
+ );
83
+ }
84
+
81
85
  return (
82
86
  <Input
83
87
  type="text"
84
- value={value || ''}
85
- onChange={(e) => onChange(e.target.value)}
88
+ value={String(value ?? '')}
89
+ onChange={(e) => onChange(e.target.value as unknown as CellValue)}
86
90
  className="w-full h-7"
87
- placeholder={placeholder || `Enter ${column.id}`}
91
+ placeholder={`Enter ${column.id}`}
88
92
  />
89
93
  );
90
94
  };
@@ -102,62 +106,43 @@ export function EditableRow<TData extends DataRecord>({
102
106
  }: EditableRowProps<TData>) {
103
107
  const rowId = getRowId ? getRowId(row.original, row.index) : String(row.id);
104
108
 
105
- // Convert DataTableAction to ActionButtons format with proper disabled handling
106
- const convertedActions = actions.map(action => ({
107
- label: action.label,
108
- onClick: action.onClick,
109
- icon: action.icon,
110
- variant: action.variant === 'destructive' ? 'destructive' as const : 'default' as const,
111
- disabled: action.disabled ? ((row?: any) => action.disabled!(row)) : false,
112
- testId: action.testId || `action-${action.label.toLowerCase().replace(/\s+/g, '-')}-${rowId}`,
113
- visible: true,
114
- }));
115
-
116
109
  return (
117
- <tr>
118
- {row.getVisibleCells().map((cell: any) => (
119
- <td key={cell.id}>
110
+ <tr
111
+ role="row"
112
+ aria-selected={typeof row.getIsSelected === 'function' ? (row.getIsSelected() ? 'true' : 'false') : 'false'}
113
+ aria-rowindex={row.index + 1}
114
+ >
115
+ {row.getVisibleCells().map(cell => (
116
+ <td key={cell.id} role="cell">
120
117
  <div className={cell.column.columnDef.meta?.align === 'right' ? 'text-right' : ''}>
121
118
  {cell.column.id !== 'actions' ? (
122
- // Check if column has a custom cell renderer - if so, use it in edit mode
123
119
  cell.column.columnDef.cell ? (
124
120
  flexRender(cell.column.columnDef.cell, {
125
121
  ...cell.getContext(),
126
- getIsEditing: () => true, // Always true in edit mode
127
- setValue: (value: any) => {
128
- if (typeof value === 'object' && value !== null) {
129
- onEditingDataChange({ ...editingData, ...value });
122
+ getIsEditing: () => true,
123
+ setValue: (value: CellValue | Record<string, CellValue>) => {
124
+ if (typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
125
+ onEditingDataChange({ ...editingData, ...(value as Record<string, CellValue>) });
130
126
  } else {
131
- onEditingDataChange({ ...editingData, [cell.column.id]: value });
127
+ onEditingDataChange({ ...editingData, [cell.column.id]: value as CellValue });
132
128
  }
133
129
  }
134
130
  })
135
131
  ) : (
136
- // Fall back to default edit field rendering when no custom cell renderer
137
132
  renderEditField(cell.column, editingData[cell.column.id], (value) => {
138
- if (typeof value === 'object' && value !== null) {
139
- // Handle editAccessorKey case
140
- onEditingDataChange({ ...editingData, ...value });
133
+ if (typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
134
+ onEditingDataChange({ ...editingData, ...(value as Record<string, CellValue>) });
141
135
  } else {
142
- // Handle simple value case
143
- onEditingDataChange({ ...editingData, [cell.column.id]: value });
136
+ onEditingDataChange({ ...editingData, [cell.column.id]: value as CellValue });
144
137
  }
145
138
  }, editingData)
146
139
  )
147
140
  ) : (
148
141
  <div className="flex gap-1">
149
- <Button
150
- onClick={onSave}
151
- size="sm"
152
- variant="default"
153
- >
142
+ <Button onClick={onSave} size="sm" variant="default">
154
143
  Save
155
144
  </Button>
156
- <Button
157
- onClick={onCancel}
158
- size="sm"
159
- variant="outline"
160
- >
145
+ <Button onClick={onCancel} size="sm" variant="outline">
161
146
  Cancel
162
147
  </Button>
163
148
  </div>
@@ -168,11 +153,11 @@ export function EditableRow<TData extends DataRecord>({
168
153
  {actions.length > 0 && (
169
154
  <td>
170
155
  <ActionButtons
171
- row={row.original}
156
+ row={row}
172
157
  rowId={rowId}
173
158
  index={row.index}
174
- actions={convertedActions}
175
- isEditing={true}
159
+ actions={actions}
160
+ isEditing
176
161
  isParent={isParent}
177
162
  hierarchical={hierarchical}
178
163
  />
@@ -28,7 +28,11 @@ export function EmptyState({
28
28
  : "Get started by adding your first entry";
29
29
 
30
30
  return (
31
- <div className="flex flex-col items-center justify-center p-8 text-center">
31
+ <div
32
+ role="status"
33
+ aria-live="polite"
34
+ className="flex flex-col items-center justify-center p-8 text-center"
35
+ >
32
36
  <Icon
33
37
  role="img"
34
38
  aria-hidden="true"
@@ -40,6 +40,7 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } f
40
40
  import { Button } from '../../Button/Button';
41
41
  import { Input } from '../../Input/Input';
42
42
  import { Upload, FileText, AlertCircle } from 'lucide-react';
43
+ import { createLogger } from '../../../utils/logger';
43
44
 
44
45
  /**
45
46
  * Configuration interface for customizing ImportModal text content
@@ -76,7 +77,7 @@ interface ImportModalProps {
76
77
  /** Callback function when the modal is closed */
77
78
  onClose: () => void;
78
79
  /** Callback function when data is imported successfully */
79
- onImport: (data: any[]) => void | Promise<void>;
80
+ onImport: (data: Array<Record<string, unknown>>) => void | Promise<void>;
80
81
  /** Configuration object for customizing modal text content */
81
82
  config?: ImportModalConfig;
82
83
  }
@@ -107,11 +108,13 @@ interface ImportModalProps {
107
108
  * ```
108
109
  */
109
110
  export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportModalProps) {
111
+ const logger = createLogger('ImportModal');
110
112
  const [file, setFile] = useState<File | null>(null);
111
113
  const [isProcessing, setIsProcessing] = useState(false);
112
114
  const [error, setError] = useState<string | null>(null);
113
- const [previewData, setPreviewData] = useState<any[] | null>(null);
115
+ const [previewData, setPreviewData] = useState<Array<Record<string, unknown>> | null>(null);
114
116
  const [totalCount, setTotalCount] = useState<number>(0);
117
+ const [validationErrors, setValidationErrors] = useState<Array<{row: number; field: string; message: string}>>([]);
115
118
  const fileInputRef = useRef<HTMLInputElement>(null);
116
119
  const isMountedRef = useRef(true);
117
120
 
@@ -135,38 +138,13 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
135
138
  totalRowsText = 'Total rows to import: {count}'
136
139
  } = config;
137
140
 
138
- const handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {
139
- const selectedFile = event.target.files?.[0];
140
- console.log('📁 File selected:', selectedFile?.name);
141
- if (selectedFile) {
142
- setFile(selectedFile);
143
- setError(null);
144
-
145
- // Generate preview
146
- try {
147
- const text = await selectedFile.text();
148
- console.log('📄 File content length:', text.length);
149
- const data = processCSV(text);
150
- console.log('📊 Parsed CSV data:', data.length, 'rows');
151
- console.log('👀 Setting preview data:', data.slice(0, 5));
152
- setPreviewData(data.slice(0, 5)); // Show first 5 rows as preview
153
- setTotalCount(data.length); // Store total count
154
- console.log('👀 Preview data state should be updated');
155
- } catch (err) {
156
- console.error('❌ CSV parsing error:', err);
157
- setError(err instanceof Error ? err.message : 'Failed to preview file');
158
- setPreviewData(null);
159
- setTotalCount(0);
160
- }
161
- }
162
- };
163
141
 
164
- const processCSV = (csvText: string): any[] => {
165
- console.log('📄 Raw CSV text:', csvText.substring(0, 200) + '...');
142
+ const processCSV = (csvText: string): Array<Record<string, unknown>> => {
143
+ logger.debug('Raw CSV text:', csvText.substring(0, 200) + '...');
166
144
 
167
145
  const lines = csvText.split('\n').filter(line => line.trim());
168
- console.log('📄 CSV lines count:', lines.length);
169
- console.log('📄 First few lines:', lines.slice(0, 3));
146
+ logger.debug('CSV lines count:', lines.length);
147
+ logger.debug('First few lines:', lines.slice(0, 3));
170
148
 
171
149
  if (lines.length < 2) {
172
150
  throw new Error('CSV must have at least a header row and one data row');
@@ -195,19 +173,19 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
195
173
  };
196
174
 
197
175
  const headers = parseCSVLine(lines[0]).map(h => h.replace(/"/g, '').trim());
198
- console.log('📄 Parsed headers:', headers);
176
+ logger.debug('Parsed headers:', headers);
199
177
 
200
178
  const data = lines.slice(1).map((line, index) => {
201
179
  const values = parseCSVLine(line).map(v => v.replace(/"/g, '').trim());
202
- const row: any = {};
180
+ const row: Record<string, unknown> = {};
203
181
  headers.forEach((header, colIndex) => {
204
182
  row[header] = values[colIndex] || '';
205
183
  });
206
- console.log(`📄 Row ${index + 1}:`, row);
184
+ logger.debug(`Row ${index + 1}:`, row);
207
185
  return row;
208
186
  });
209
187
 
210
- console.log('📄 Final parsed data:', data);
188
+ logger.debug('Final parsed data:', data);
211
189
  return data;
212
190
  };
213
191
 
@@ -243,8 +221,36 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
243
221
  setError(null);
244
222
  setPreviewData(null);
245
223
  setTotalCount(0);
224
+ setValidationErrors([]);
246
225
  onClose();
247
226
  };
227
+
228
+ const handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {
229
+ const selectedFile = event.target.files?.[0];
230
+ logger.debug('File selected:', selectedFile?.name);
231
+ if (selectedFile) {
232
+ setFile(selectedFile);
233
+ setError(null);
234
+ setValidationErrors([]);
235
+
236
+ // Generate preview
237
+ try {
238
+ const text = await selectedFile.text();
239
+ logger.debug('File content length:', text.length);
240
+ const data = processCSV(text);
241
+ logger.debug('Parsed CSV data:', data.length, 'rows');
242
+ logger.debug('Setting preview data:', data.slice(0, 5));
243
+ setPreviewData(data.slice(0, 5)); // Show first 5 rows as preview
244
+ setTotalCount(data.length); // Store total count
245
+ logger.debug('Preview data state should be updated');
246
+ } catch (err) {
247
+ logger.error('CSV parsing error:', err);
248
+ setError(err instanceof Error ? err.message : 'Failed to preview file');
249
+ setPreviewData(null);
250
+ setTotalCount(0);
251
+ }
252
+ }
253
+ };
248
254
 
249
255
  return (
250
256
  <Dialog open={isOpen} onOpenChange={handleClose}>
@@ -290,6 +296,29 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
290
296
  <span className="text-sm">{error}</span>
291
297
  </div>
292
298
  )}
299
+
300
+ {validationErrors.length > 0 && (
301
+ <div className="space-y-2">
302
+ <div className="flex items-center gap-2 p-3 bg-acc-50 border border-acc-200 rounded text-acc-700">
303
+ <AlertCircle className="h-4 w-4" />
304
+ <span className="text-sm font-medium">
305
+ {validationErrors.length} validation error{validationErrors.length !== 1 ? 's' : ''} found
306
+ </span>
307
+ </div>
308
+ <div className="max-h-32 overflow-y-auto space-y-1">
309
+ {validationErrors.slice(0, 10).map((err, idx) => (
310
+ <div key={idx} className="text-xs text-acc-600 p-2 bg-acc-50 border border-acc-200 rounded">
311
+ <span className="font-medium">Row {err.row}</span> • {err.field}: {err.message}
312
+ </div>
313
+ ))}
314
+ {validationErrors.length > 10 && (
315
+ <div className="text-xs text-sec-500 italic">
316
+ ... and {validationErrors.length - 10} more errors
317
+ </div>
318
+ )}
319
+ </div>
320
+ </div>
321
+ )}
293
322
 
294
323
 
295
324
  {previewData && previewData.length > 0 && (
@@ -310,7 +339,7 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
310
339
  <tbody>
311
340
  {previewData.map((row, index) => (
312
341
  <tr key={index} className={index % 2 === 0 ? 'bg-app-main-50' : 'bg-sec-50'}>
313
- {Object.values(row).map((value: any, cellIndex) => (
342
+ {Object.values(row).map((value, cellIndex) => (
314
343
  <td key={cellIndex} className="px-2 py-1 text-sec-700 border-b">
315
344
  {String(value)}
316
345
  </td>