@jmruthers/pace-core 0.6.5 → 0.6.7

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 (473) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/audit-tool/00-dependencies.cjs +394 -0
  4. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  5. package/audit-tool/audits/02-project-structure.cjs +255 -0
  6. package/audit-tool/audits/03-architecture.cjs +196 -0
  7. package/audit-tool/audits/04-code-quality.cjs +149 -0
  8. package/audit-tool/audits/05-styling.cjs +224 -0
  9. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  10. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  11. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  12. package/audit-tool/audits/09-operations.cjs +208 -0
  13. package/audit-tool/index.cjs +291 -0
  14. package/audit-tool/utils/code-utils.cjs +218 -0
  15. package/audit-tool/utils/file-utils.cjs +230 -0
  16. package/audit-tool/utils/report-utils.cjs +241 -0
  17. package/core-usage-manifest.json +93 -0
  18. package/cursor-rules/00-standards-overview.mdc +156 -0
  19. package/cursor-rules/01-pace-core-compliance.mdc +586 -0
  20. package/cursor-rules/02-project-structure.mdc +42 -4
  21. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
  22. package/cursor-rules/04-code-quality.mdc +419 -0
  23. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
  24. package/cursor-rules/06-security-rbac.mdc +518 -0
  25. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  26. package/cursor-rules/08-testing-documentation.mdc +324 -0
  27. package/cursor-rules/09-operations.mdc +365 -0
  28. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  29. package/dist/DataTable-7PMH7XN7.js +15 -0
  30. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  31. package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
  32. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  33. package/dist/api-Y4MQWOFW.js +4 -0
  34. package/dist/audit-MYQXYZFU.js +3 -0
  35. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  36. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  37. package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
  38. package/dist/chunk-6F3IILHI.js +62 -0
  39. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  40. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  41. package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
  42. package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
  43. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  44. package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
  45. package/dist/chunk-C7NSAPTL.js +1 -0
  46. package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
  47. package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
  48. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  49. package/dist/chunk-GHYHJTYV.js +994 -0
  50. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  51. package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
  52. package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
  53. package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
  54. package/dist/chunk-MBADTM7L.js +64 -0
  55. package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
  56. package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
  57. package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
  58. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  59. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  60. package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
  61. package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
  62. package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
  63. package/dist/components.d.ts +7 -5
  64. package/dist/components.js +46 -257
  65. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  66. package/dist/eslint-rules/index.cjs +35 -0
  67. package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
  68. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  69. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  70. package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
  71. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  72. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  73. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  74. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  75. package/dist/hooks.d.ts +6 -6
  76. package/dist/hooks.js +62 -172
  77. package/dist/icons/index.d.ts +1 -0
  78. package/dist/icons/index.js +1 -0
  79. package/dist/index.d.ts +12 -11
  80. package/dist/index.js +67 -660
  81. package/dist/providers.d.ts +2 -2
  82. package/dist/providers.js +8 -35
  83. package/dist/rbac/eslint-rules.d.ts +46 -44
  84. package/dist/rbac/eslint-rules.js +7 -4
  85. package/dist/rbac/index.d.ts +109 -586
  86. package/dist/rbac/index.js +14 -207
  87. package/dist/styles/index.js +2 -12
  88. package/dist/theming/runtime.d.ts +14 -1
  89. package/dist/theming/runtime.js +3 -19
  90. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  91. package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
  92. package/dist/types-t9H8qKRw.d.ts +55 -0
  93. package/dist/types.d.ts +1 -1
  94. package/dist/types.js +7 -94
  95. package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
  96. package/dist/utils.d.ts +24 -117
  97. package/dist/utils.js +54 -392
  98. package/docs/README.md +17 -7
  99. package/docs/api/README.md +4 -402
  100. package/docs/api/modules.md +301 -871
  101. package/docs/api-reference/components.md +21 -21
  102. package/docs/api-reference/deprecated.md +31 -6
  103. package/docs/api-reference/hooks.md +80 -80
  104. package/docs/api-reference/rpc-functions.md +78 -3
  105. package/docs/api-reference/types.md +1 -1
  106. package/docs/api-reference/utilities.md +1 -1
  107. package/docs/architecture/README.md +1 -1
  108. package/docs/core-concepts/events.md +3 -3
  109. package/docs/core-concepts/organisations.md +6 -6
  110. package/docs/core-concepts/permissions.md +6 -6
  111. package/docs/documentation-index.md +12 -18
  112. package/docs/getting-started/cursor-rules.md +3 -23
  113. package/docs/getting-started/dependencies.md +650 -0
  114. package/docs/getting-started/documentation-index.md +1 -1
  115. package/docs/getting-started/examples/README.md +4 -4
  116. package/docs/getting-started/examples/full-featured-app.md +1 -1
  117. package/docs/getting-started/faq.md +2 -2
  118. package/docs/getting-started/installation-guide.md +20 -7
  119. package/docs/getting-started/quick-reference.md +4 -4
  120. package/docs/getting-started/quick-start.md +23 -12
  121. package/docs/implementation-guides/authentication.md +15 -15
  122. package/docs/implementation-guides/component-styling.md +1 -1
  123. package/docs/implementation-guides/data-tables.md +126 -33
  124. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  125. package/docs/implementation-guides/dynamic-colors.md +3 -3
  126. package/docs/implementation-guides/file-upload-storage.md +2 -2
  127. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  128. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  129. package/docs/implementation-guides/large-datasets.md +3 -2
  130. package/docs/implementation-guides/organisation-security.md +2 -2
  131. package/docs/implementation-guides/performance.md +2 -2
  132. package/docs/implementation-guides/permission-enforcement.md +5 -1
  133. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  134. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  135. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  136. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  137. package/docs/rbac/README.md +17 -8
  138. package/docs/rbac/advanced-patterns.md +6 -6
  139. package/docs/rbac/api-reference.md +20 -20
  140. package/docs/rbac/edge-functions-guide.md +376 -0
  141. package/docs/rbac/event-based-apps.md +3 -3
  142. package/docs/rbac/examples.md +41 -41
  143. package/docs/rbac/getting-started.md +37 -37
  144. package/docs/rbac/performance.md +1 -1
  145. package/docs/rbac/quick-start.md +52 -52
  146. package/docs/rbac/secure-client-protection.md +1 -35
  147. package/docs/rbac/troubleshooting.md +1 -1
  148. package/docs/security/README.md +5 -5
  149. package/docs/standards/0-standards-overview.md +220 -0
  150. package/docs/standards/1-pace-core-compliance-standards.md +986 -0
  151. package/docs/standards/2-project-structure-standards.md +949 -0
  152. package/docs/standards/3-architecture-standards.md +606 -0
  153. package/docs/standards/4-code-quality-standards.md +728 -0
  154. package/docs/standards/5-styling-standards.md +348 -0
  155. package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
  156. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  157. package/docs/standards/8-testing-documentation-standards.md +401 -0
  158. package/docs/standards/9-operations-standards.md +1102 -0
  159. package/docs/standards/README.md +185 -57
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/common-issues.md +2 -2
  162. package/docs/troubleshooting/debugging.md +9 -9
  163. package/docs/troubleshooting/migration.md +4 -4
  164. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  165. package/eslint-config-pace-core.cjs +33 -6
  166. package/package.json +35 -23
  167. package/scripts/install-cursor-rules.cjs +25 -6
  168. package/scripts/install-eslint-config.cjs +284 -0
  169. package/src/__tests__/fixtures/supabase.ts +1 -1
  170. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
  171. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  172. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  173. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  174. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
  175. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  176. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  177. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  178. package/src/__tests__/public-recipe-view.test.ts +38 -9
  179. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  180. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  181. package/src/__tests__/templates/component.test.template.tsx +18 -15
  182. package/src/components/Button/Button.tsx +5 -1
  183. package/src/components/Calendar/Calendar.tsx +201 -47
  184. package/src/components/ContextSelector/ContextSelector.tsx +106 -119
  185. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  186. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  187. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  188. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  189. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  190. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  191. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  192. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  193. package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
  194. package/src/components/DataTable/components/EditFields.tsx +23 -3
  195. package/src/components/DataTable/components/EditableRow.tsx +12 -9
  196. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  197. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  198. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  199. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  200. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  201. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  202. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  203. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  204. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  205. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  206. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  207. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  208. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  209. package/src/components/DataTable/components/index.ts +2 -1
  210. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  211. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  212. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  213. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  214. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  215. package/src/components/DataTable/types.ts +5 -18
  216. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  217. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  218. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  219. package/src/components/DateTimeField/DateTimeField.tsx +10 -9
  220. package/src/components/Dialog/Dialog.test.tsx +128 -104
  221. package/src/components/Dialog/Dialog.tsx +742 -24
  222. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  223. package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
  224. package/src/components/FileDisplay/FileDisplay.tsx +23 -17
  225. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  226. package/src/components/FileUpload/FileUpload.tsx +112 -130
  227. package/src/components/Form/Form.test.tsx +6 -8
  228. package/src/components/Form/Form.tsx +365 -4
  229. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  230. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  231. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  232. package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
  233. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  234. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  235. package/src/components/Progress/Progress.tsx +2 -4
  236. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  237. package/src/components/Select/Select.tsx +109 -98
  238. package/src/components/Select/types.ts +4 -1
  239. package/src/components/UserMenu/UserMenu.tsx +9 -6
  240. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  241. package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
  242. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  243. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  244. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  245. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  246. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  247. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  248. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  249. package/src/hooks/public/usePublicEvent.ts +67 -195
  250. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  251. package/src/hooks/public/usePublicEventLogo.ts +24 -14
  252. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  253. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  254. package/src/hooks/useAppConfig.ts +28 -26
  255. package/src/hooks/useEventTheme.test.ts +217 -239
  256. package/src/hooks/useEventTheme.ts +16 -28
  257. package/src/hooks/useFileDisplay.ts +2 -2
  258. package/src/hooks/useOrganisationPermissions.ts +5 -7
  259. package/src/hooks/useQueryCache.ts +0 -1
  260. package/src/hooks/useSessionDraft.ts +380 -0
  261. package/src/hooks/useSessionRestoration.ts +3 -1
  262. package/src/icons/index.ts +27 -0
  263. package/src/index.ts +5 -0
  264. package/src/providers/OrganisationProvider.tsx +23 -14
  265. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  266. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  267. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  268. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  269. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  270. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  271. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  272. package/src/providers/services/EventServiceProvider.tsx +1 -24
  273. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  274. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  275. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
  276. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  277. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  278. package/src/rbac/adapters.tsx +7 -295
  279. package/src/rbac/api.test.ts +44 -56
  280. package/src/rbac/api.ts +10 -17
  281. package/src/rbac/cache-invalidation.ts +0 -1
  282. package/src/rbac/compliance/index.ts +10 -0
  283. package/src/rbac/compliance/pattern-detector.ts +553 -0
  284. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  285. package/src/rbac/components/AccessDenied.tsx +150 -0
  286. package/src/rbac/components/NavigationGuard.tsx +12 -20
  287. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  288. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  289. package/src/rbac/components/index.ts +3 -41
  290. package/src/rbac/eslint-rules.js +1 -1
  291. package/src/rbac/hooks/index.ts +0 -3
  292. package/src/rbac/hooks/permissions/index.ts +0 -3
  293. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  294. package/src/rbac/hooks/usePermissions.ts +0 -3
  295. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  296. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  297. package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
  298. package/src/rbac/hooks/useResourcePermissions.ts +139 -48
  299. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  300. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  301. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  302. package/src/rbac/index.ts +7 -9
  303. package/src/rbac/utils/contextValidator.ts +9 -7
  304. package/src/services/AuthService.ts +130 -18
  305. package/src/services/EventService.ts +4 -97
  306. package/src/services/InactivityService.ts +16 -0
  307. package/src/services/OrganisationService.ts +7 -44
  308. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  309. package/src/services/base/BaseService.ts +0 -3
  310. package/src/styles/core.css +7 -0
  311. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  312. package/src/theming/parseEventColours.ts +22 -10
  313. package/src/types/database.generated.ts +4733 -3809
  314. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  315. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  316. package/src/utils/context/organisationContext.test.ts +13 -28
  317. package/src/utils/context/organisationContext.ts +21 -52
  318. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  319. package/src/utils/file-reference/index.ts +39 -15
  320. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  321. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  322. package/src/utils/index.ts +4 -1
  323. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  324. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  325. package/src/utils/persistence/keyDerivation.ts +304 -0
  326. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  327. package/src/utils/security/secureStorage.ts +5 -5
  328. package/src/utils/storage/README.md +1 -1
  329. package/src/utils/storage/helpers.ts +3 -3
  330. package/src/utils/supabase/createBaseClient.ts +147 -0
  331. package/src/utils/timezone/timezone.test.ts +1 -2
  332. package/src/utils/timezone/timezone.ts +1 -1
  333. package/src/utils/validation/csrf.ts +4 -4
  334. package/cursor-rules/00-pace-core-compliance.mdc +0 -331
  335. package/cursor-rules/01-standards-compliance.mdc +0 -244
  336. package/cursor-rules/04-testing-standards.mdc +0 -268
  337. package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
  338. package/cursor-rules/06-code-quality.mdc +0 -309
  339. package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
  340. package/cursor-rules/CHANGELOG.md +0 -119
  341. package/cursor-rules/README.md +0 -192
  342. package/dist/DataTable-AOVNCPTX.js +0 -175
  343. package/dist/DataTable-AOVNCPTX.js.map +0 -1
  344. package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
  345. package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
  346. package/dist/api-O6HTBX5Y.js +0 -52
  347. package/dist/api-O6HTBX5Y.js.map +0 -1
  348. package/dist/audit-V53FV5AG.js +0 -17
  349. package/dist/audit-V53FV5AG.js.map +0 -1
  350. package/dist/chunk-5DRSZLL2.js.map +0 -1
  351. package/dist/chunk-63FOKYGO.js.map +0 -1
  352. package/dist/chunk-6COVEUS7.js.map +0 -1
  353. package/dist/chunk-AFVQODI2.js +0 -263
  354. package/dist/chunk-AFVQODI2.js.map +0 -1
  355. package/dist/chunk-DGUM43GV.js.map +0 -1
  356. package/dist/chunk-E66EQZE6.js.map +0 -1
  357. package/dist/chunk-EFN2EIMK.js.map +0 -1
  358. package/dist/chunk-FFQEQTNW.js.map +0 -1
  359. package/dist/chunk-FMUCXFII.js.map +0 -1
  360. package/dist/chunk-G37KK66H.js.map +0 -1
  361. package/dist/chunk-G7QEZTYQ.js +0 -2053
  362. package/dist/chunk-G7QEZTYQ.js.map +0 -1
  363. package/dist/chunk-HU2C6SSC.js.map +0 -1
  364. package/dist/chunk-IHB5DR3H.js.map +0 -1
  365. package/dist/chunk-IVOFDYWT.js.map +0 -1
  366. package/dist/chunk-J36DSWQK.js.map +0 -1
  367. package/dist/chunk-JGRYX5UX.js.map +0 -1
  368. package/dist/chunk-KQCRWDSA.js +0 -1
  369. package/dist/chunk-KQCRWDSA.js.map +0 -1
  370. package/dist/chunk-L4OXEN46.js.map +0 -1
  371. package/dist/chunk-LMC26NLJ.js +0 -84
  372. package/dist/chunk-LMC26NLJ.js.map +0 -1
  373. package/dist/chunk-M43Y4SSO.js.map +0 -1
  374. package/dist/chunk-M7MPQISP.js.map +0 -1
  375. package/dist/chunk-NTM7ZSB6.js.map +0 -1
  376. package/dist/chunk-PWLANIRT.js.map +0 -1
  377. package/dist/chunk-QXHPKYJV.js.map +0 -1
  378. package/dist/chunk-RGAWHO7N.js.map +0 -1
  379. package/dist/chunk-UPPMRMYG.js.map +0 -1
  380. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  381. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  382. package/dist/components.js.map +0 -1
  383. package/dist/contextValidator-5OGXSPKS.js +0 -9
  384. package/dist/contextValidator-5OGXSPKS.js.map +0 -1
  385. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  386. package/dist/hooks.js.map +0 -1
  387. package/dist/index.js.map +0 -1
  388. package/dist/providers.js.map +0 -1
  389. package/dist/rbac/eslint-rules.js.map +0 -1
  390. package/dist/rbac/index.js.map +0 -1
  391. package/dist/styles/index.js.map +0 -1
  392. package/dist/theming/runtime.js.map +0 -1
  393. package/dist/types.js.map +0 -1
  394. package/dist/utils.js.map +0 -1
  395. package/docs/best-practices/README.md +0 -472
  396. package/docs/best-practices/accessibility.md +0 -601
  397. package/docs/best-practices/common-patterns.md +0 -516
  398. package/docs/best-practices/deployment.md +0 -1103
  399. package/docs/best-practices/performance.md +0 -1328
  400. package/docs/best-practices/security.md +0 -940
  401. package/docs/best-practices/testing.md +0 -1034
  402. package/docs/rbac/compliance/compliance-guide.md +0 -544
  403. package/docs/standards/01-architecture-standard.md +0 -44
  404. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  405. package/docs/standards/03-component-standard.md +0 -32
  406. package/docs/standards/04-code-style-standard.md +0 -32
  407. package/docs/standards/05-security-standard.md +0 -44
  408. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  409. package/docs/standards/pace-core-compliance.md +0 -432
  410. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  411. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  412. package/scripts/audit/core/checks/bundle.cjs +0 -142
  413. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  414. package/scripts/audit/core/checks/config.cjs +0 -54
  415. package/scripts/audit/core/checks/coverage.cjs +0 -84
  416. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  417. package/scripts/audit/core/checks/documentation.cjs +0 -268
  418. package/scripts/audit/core/checks/environment.cjs +0 -116
  419. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  420. package/scripts/audit/core/checks/forms.cjs +0 -172
  421. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  422. package/scripts/audit/core/checks/hooks.cjs +0 -334
  423. package/scripts/audit/core/checks/imports.cjs +0 -244
  424. package/scripts/audit/core/checks/performance.cjs +0 -325
  425. package/scripts/audit/core/checks/routes.cjs +0 -117
  426. package/scripts/audit/core/checks/state.cjs +0 -130
  427. package/scripts/audit/core/checks/structure.cjs +0 -65
  428. package/scripts/audit/core/checks/style.cjs +0 -584
  429. package/scripts/audit/core/checks/testing.cjs +0 -122
  430. package/scripts/audit/core/checks/typescript.cjs +0 -61
  431. package/scripts/audit/core/scanner.cjs +0 -199
  432. package/scripts/audit/core/utils.cjs +0 -137
  433. package/scripts/audit/index.cjs +0 -223
  434. package/scripts/audit/reporters/console.cjs +0 -151
  435. package/scripts/audit/reporters/json.cjs +0 -54
  436. package/scripts/audit/reporters/markdown.cjs +0 -124
  437. package/scripts/audit-consuming-app.cjs +0 -86
  438. package/src/components/DataTable/components/DataTableBody.tsx +0 -454
  439. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  440. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  441. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  442. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  443. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  444. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  445. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  446. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  447. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  448. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  449. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  450. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  451. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  452. package/src/components/DataTable/utils/debugTools.ts +0 -514
  453. package/src/eslint-rules/pace-core-compliance.js +0 -638
  454. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  455. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  456. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  457. package/src/rbac/components/NavigationProvider.tsx +0 -345
  458. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  459. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  460. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  461. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  462. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  463. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  464. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  465. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  466. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  467. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  468. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  469. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  470. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  471. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  472. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  473. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -9,7 +9,7 @@
9
9
 
10
10
  import React, { Component, ErrorInfo, ReactNode } from 'react';
11
11
  import { Alert, AlertDescription, AlertTitle } from '../../Alert/Alert';
12
- import { Button } from '../../Button/Button';
12
+ import { Button, ButtonGroup } from '../../Button/Button';
13
13
  import { createLogger } from '../../../utils/core/logger';
14
14
  // Icons removed to avoid test mocking issues
15
15
 
@@ -142,8 +142,7 @@ export class DataTableErrorBoundary extends Component<
142
142
 
143
143
  // Default error UI
144
144
  return (
145
- <div className="flex items-center justify-center p-8">
146
- <Alert variant="destructive" className="max-w-md">
145
+ <Alert variant="destructive">
147
146
  <AlertTitle>DataTable Error</AlertTitle>
148
147
  <AlertDescription className="mt-2">
149
148
  <span>Something went wrong</span>
@@ -164,17 +163,16 @@ export class DataTableErrorBoundary extends Component<
164
163
  </pre>
165
164
  </details>
166
165
  ) : (
167
- <div className="mt-2">
168
- <span>An unexpected error occurred</span>
169
- </div>
166
+ <Alert variant="destructive">
167
+ <AlertDescription>An unexpected error occurred</AlertDescription>
168
+ </Alert>
170
169
  )}
171
- <div className="mt-4 flex gap-2">
170
+ <ButtonGroup>
172
171
  {showRetryButton && retryCount < maxRetries && (
173
172
  <Button
174
173
  variant="outline"
175
174
  size="sm"
176
- onClick={this.handleRetry}
177
- className="flex items-center gap-2"
175
+ onClick={this.handleRetry}
178
176
  >
179
177
  Retry ({retryCount + 1}/{maxRetries})
180
178
  </Button>
@@ -186,9 +184,9 @@ export class DataTableErrorBoundary extends Component<
186
184
  >
187
185
  Reset
188
186
  </Button>
189
- </div>
187
+ </ButtonGroup>
190
188
  </Alert>
191
- </div>
189
+
192
190
  );
193
191
  }
194
192
 
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import { Edit, Trash, ChevronUp, ChevronDown, ChevronsUpDown } from 'lucide-react';
2
+ import { Edit, Trash } from 'lucide-react';
3
+ import { SortIndicator } from './SortIndicator';
3
4
  import type { Table } from '@tanstack/react-table';
4
5
  import { cn } from '../../../utils/core/cn';
5
6
  import { Button } from '../../Button/Button';
@@ -7,12 +8,13 @@ import { DataTableToolbar } from './DataTableToolbar';
7
8
  import { UnifiedTableBody } from './UnifiedTableBody';
8
9
  import { PaginationControls, EnhancedPaginationControls } from './PaginationControls';
9
10
  import { DataTableModals } from './DataTableModals';
10
- import { announceSortChange } from '../utils/a11yUtils';
11
+ import { announceSortChange, getAriaSortState } from '../utils/a11yUtils';
11
12
  import { exportToCSVWithTableRows } from '../utils/exportUtils';
12
13
  import { getTableClasses } from '../styles';
13
14
  import { toast } from '../../../hooks/useToast';
14
15
  import type {
15
16
  AggregateConfig,
17
+ CellValue,
16
18
  DataRecord,
17
19
  DataTableAction,
18
20
  DataTableColumn,
@@ -130,6 +132,12 @@ export function DataTableLayout<TData extends DataRecord>({
130
132
  keyboardNavigation,
131
133
  lastFocusedElementRef,
132
134
  }: DataTableLayoutProps<TData>) {
135
+ // CRITICAL FIX: Use a ref to track the latest editingData to avoid stale closure issues
136
+ // The ref is always kept in sync with state.editingData via useEffect
137
+ const editingDataRef = React.useRef(state.editingData);
138
+ React.useEffect(() => {
139
+ editingDataRef.current = state.editingData;
140
+ }, [state.editingData]);
133
141
  const handleExport = async () => {
134
142
  try {
135
143
  const tableRows = table.getFilteredRowModel().rows;
@@ -282,6 +290,8 @@ export function DataTableLayout<TData extends DataRecord>({
282
290
  if (result !== undefined && result !== null && typeof result === 'object' && typeof result.then === 'function') {
283
291
  await result;
284
292
  }
293
+ // Clear selection after successful deletion
294
+ stateActions.clearRowSelection();
285
295
  toast({
286
296
  title: 'Delete Successful',
287
297
  description: `Successfully deleted ${selectedCount} ${selectedCount === 1 ? 'row' : 'rows'}`,
@@ -325,13 +335,7 @@ export function DataTableLayout<TData extends DataRecord>({
325
335
  const isFirst = index === 0;
326
336
  const isLast = index === visibleHeaders.length - 1;
327
337
  const isSortable = header.column.getCanSort();
328
- const ariaSort = isSortable
329
- ? header.column.getIsSorted() === 'asc'
330
- ? 'ascending'
331
- : header.column.getIsSorted() === 'desc'
332
- ? 'descending'
333
- : 'none'
334
- : undefined;
338
+ const ariaSort = getAriaSortState(header.column);
335
339
  const isRightAligned = header.column.columnDef.meta?.align === 'right';
336
340
 
337
341
  const handleSortClick = (event: React.MouseEvent) => {
@@ -397,13 +401,7 @@ export function DataTableLayout<TData extends DataRecord>({
397
401
  {typeof header.column.columnDef.header === 'function'
398
402
  ? header.column.columnDef.header(header.getContext())
399
403
  : header.column.columnDef.header}
400
- {header.column.getIsSorted() === 'asc' ? (
401
- <ChevronUp className="size-4" />
402
- ) : header.column.getIsSorted() === 'desc' ? (
403
- <ChevronDown className="size-4" />
404
- ) : (
405
- <ChevronsUpDown className="size-4" />
406
- )}
404
+ <SortIndicator sortState={header.column.getIsSorted() || false} />
407
405
  </Button>
408
406
  ) : typeof header.column.columnDef.header === 'function' ? (
409
407
  header.column.columnDef.header(header.getContext())
@@ -424,8 +422,18 @@ export function DataTableLayout<TData extends DataRecord>({
424
422
  creationData={state.creationData}
425
423
  onCreationDataChange={stateActions.setCreationData}
426
424
  onSaveCreation={() => {
425
+ const creationDataToUse = state.creationData;
426
+ // CRITICAL FIX: Ensure status field is included with default value "active" if not already set
427
+ // This ensures new rows are created with the correct status
428
+ const finalCreationData = {
429
+ ...creationDataToUse,
430
+ // Only set status to "active" if it's not already set and if status is a column in the table
431
+ ...(creationDataToUse.status === undefined && table.getAllColumns().some(col => col.id === 'status')
432
+ ? { status: 'active' as CellValue }
433
+ : {}),
434
+ };
427
435
  if (onCreateRow) {
428
- onCreateRow(state.creationData as Partial<TData>);
436
+ onCreateRow(finalCreationData as Partial<TData>);
429
437
  stateActions.clearCreationData();
430
438
  stateActions.setCreating(false);
431
439
  }
@@ -442,17 +450,23 @@ export function DataTableLayout<TData extends DataRecord>({
442
450
  }
443
451
  }}
444
452
  onSaveEditing={() => {
453
+ // CRITICAL FIX: Use ref to get the latest editingData to avoid stale closure issues
454
+ // The ref is always kept in sync with state.editingData, so it should always have the correct value
455
+ const latestEditingData = editingDataRef.current;
445
456
  if (onEditRow && state.editingRowId) {
446
- const originalRow = data.find((row) => {
457
+ // CRITICAL FIX: Use findIndex to get the actual index, then use that index for getRowId
458
+ const originalRowIndex = data.findIndex((row, index) => {
447
459
  try {
448
- const rowId = resolvedGetRowId(row, 0);
460
+ const rowId = resolvedGetRowId(row, index);
449
461
  return rowId === state.editingRowId;
450
462
  } catch {
451
463
  return false;
452
464
  }
453
465
  });
454
- if (originalRow) {
455
- onEditRow(originalRow, state.editingData as Partial<TData>);
466
+
467
+ if (originalRowIndex >= 0) {
468
+ const originalRow = data[originalRowIndex];
469
+ onEditRow(originalRow, latestEditingData as Partial<TData>);
456
470
  }
457
471
  }
458
472
  stateActions.clearEditing();
@@ -33,7 +33,7 @@ export function SelectEditField<TData extends DataRecord>({
33
33
  const logger = createLogger('SelectEditField');
34
34
  const isSearchable = columnDef.selectSearchable !== false;
35
35
  const isCreatable = columnDef.creatable === true;
36
- const selectRef = React.useRef<HTMLFormElement>(null);
36
+ const selectRef = React.useRef<HTMLFieldSetElement>(null);
37
37
  const [searchTerm, setSearchTerm] = React.useState('');
38
38
  const [isOpen, setIsOpen] = React.useState(false);
39
39
  const [showCreateOption, setShowCreateOption] = React.useState(false);
@@ -258,7 +258,27 @@ export const renderEditField = <TData extends DataRecord>(
258
258
 
259
259
  if (columnDef.fieldType === 'select' && columnDef.fieldOptions) {
260
260
  const accessorKey = columnDef.editAccessorKey || column.id;
261
- const currentValue = editingData[accessorKey] ?? value ?? '';
261
+ // CRITICAL FIX: Ensure we use the value from editingData first, then fall back to the passed value
262
+ // Convert to string to match Select component's string-based value system
263
+ // Always prioritize editingData[accessorKey] to ensure we use the most recent value
264
+ const rawValue = editingData[accessorKey] !== undefined && editingData[accessorKey] !== null
265
+ ? editingData[accessorKey]
266
+ : (value !== undefined && value !== null ? value : '');
267
+ const currentValue = rawValue !== null && rawValue !== undefined ? String(rawValue) : '';
268
+
269
+ // Create onChange handler that immediately updates state
270
+ const handleValueChange = (newValue: CellValue) => {
271
+ // Store the new value - preserve original type if option values are numbers
272
+ // Check if any option has a numeric value to determine if we should convert
273
+ const hasNumericValues = columnDef.fieldOptions?.some((opt: any) =>
274
+ 'value' in opt && !('type' in opt) && typeof opt.value === 'number'
275
+ );
276
+ const finalValue = hasNumericValues && !isNaN(Number(newValue)) && newValue !== ''
277
+ ? Number(newValue)
278
+ : newValue;
279
+ // Immediately update state - this happens synchronously
280
+ onChange({ [accessorKey]: finalValue });
281
+ };
262
282
 
263
283
  return (
264
284
  <SelectEditField
@@ -266,7 +286,7 @@ export const renderEditField = <TData extends DataRecord>(
266
286
  accessorKey={accessorKey}
267
287
  currentValue={currentValue}
268
288
  placeholder={placeholder}
269
- onChange={(newValue) => onChange({ [accessorKey]: newValue })}
289
+ onChange={handleValueChange}
270
290
  />
271
291
  );
272
292
  }
@@ -51,7 +51,7 @@ function SelectEditField<TData extends DataRecord>({
51
51
  // When selectSearchable is false, hide the search input (type-to-search still works via SelectContent internals)
52
52
  const isSearchable = columnDef.selectSearchable !== false;
53
53
  const isCreatable = columnDef.creatable === true;
54
- const selectRef = React.useRef<HTMLFormElement>(null);
54
+ const selectRef = React.useRef<HTMLFieldSetElement>(null);
55
55
  const [searchTerm, setSearchTerm] = React.useState('');
56
56
  const [isOpen, setIsOpen] = React.useState(false);
57
57
  const [showCreateOption, setShowCreateOption] = React.useState(false);
@@ -379,19 +379,18 @@ export function EditableRow<TData extends DataRecord>({
379
379
  const isSystemColumn = cell.column.id === 'select' || cell.column.id === 'actions';
380
380
 
381
381
  return (
382
- <td key={cell.id} role="cell">
383
- <div className={cell.column.columnDef.meta?.align === 'right' ? 'text-right' : ''}>
384
- {isSystemColumn ? (
382
+ <td key={cell.id} role="cell" className={cell.column.columnDef.meta?.align === 'right' ? 'text-right' : ''}>
383
+ {isSystemColumn ? (
385
384
  // System columns: render their normal cell content (checkbox for select, buttons for actions)
386
385
  cell.column.id === 'actions' ? (
387
- <div className="flex gap-1">
388
- <Button onClick={onSave} size="sm" variant="default" aria-label="Save changes">
386
+ <>
387
+ <Button onClick={onSave} size="sm" variant="default" aria-label="Save changes" className="mr-1">
389
388
  <Check className="size-4" />
390
389
  </Button>
391
390
  <Button onClick={onCancel} size="sm" variant="outline" aria-label="Cancel editing">
392
391
  <X className="size-4" />
393
392
  </Button>
394
- </div>
393
+ </>
395
394
  ) : (
396
395
  // Select column: render the checkbox normally
397
396
  flexRender(cell.column.columnDef.cell, cell.getContext())
@@ -434,9 +433,14 @@ export function EditableRow<TData extends DataRecord>({
434
433
  hasAssignedRef.current = true;
435
434
  }
436
435
 
436
+ // CRITICAL FIX: Use the correct accessor key (editAccessorKey or column.id) to get the value
437
+ // This ensures that when editAccessorKey is different from column.id, we use the correct key
438
+ const accessorKey = columnDef.editAccessorKey || cell.column.id;
439
+ const currentValue = editingData[accessorKey] ?? (cell.getValue() as CellValue);
440
+
437
441
  return renderEditField(
438
442
  cell.column,
439
- editingData[cell.column.id] ?? (cell.getValue() as CellValue),
443
+ currentValue,
440
444
  (value) => {
441
445
  if (typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
442
446
  onEditingDataChange({ ...editingData, ...(value as Record<string, CellValue>) });
@@ -450,7 +454,6 @@ export function EditableRow<TData extends DataRecord>({
450
454
  );
451
455
  })()
452
456
  )}
453
- </div>
454
457
  </td>
455
458
  );
456
459
  })}
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { Database, Search, Plus, User } from 'lucide-react';
3
3
  import { Button } from '../../Button/Button';
4
+ import { Alert, AlertTitle, AlertDescription } from '../../Alert/Alert';
4
5
 
5
6
  /**
6
7
  * Props for the EmptyState component.
@@ -38,10 +39,10 @@ export function EmptyState({
38
39
  : "Get started by adding your first entry";
39
40
 
40
41
  return (
41
- <div
42
+ <Alert
42
43
  role="status"
43
44
  aria-live="polite"
44
- className="flex flex-col items-center justify-center p-8 text-center"
45
+ className="grid place-items-center text-center max-w-lg mx-auto"
45
46
  >
46
47
  <Icon
47
48
  role="img"
@@ -49,15 +50,15 @@ export function EmptyState({
49
50
  className="size-12 text-muted-foreground mb-4"
50
51
  data-testid={Icon === Database ? 'lucide-database' : Icon === User ? 'lucide-user' : 'custom-icon'}
51
52
  />
52
- <h3 className="text-lg font-semibold mb-2">
53
+ <AlertTitle className="text-lg font-semibold mb-2">
53
54
  {title || defaultTitle}
54
- </h3>
55
- <p className="text-sm text-muted-foreground mb-4 max-w-sm">
55
+ </AlertTitle>
56
+ <AlertDescription className="text-sm text-muted-foreground mb-4 max-w-sm">
56
57
  {description || defaultDescription}
57
- </p>
58
+ </AlertDescription>
58
59
 
59
60
  {(isFiltered && onClearFilters) || action ? (
60
- <div className="flex gap-2">
61
+ <>
61
62
  {isFiltered && onClearFilters && (
62
63
  <Button variant="outline" onClick={onClearFilters}>
63
64
  <Search className="size-4 mr-2" />
@@ -71,8 +72,8 @@ export function EmptyState({
71
72
  {action.label}
72
73
  </Button>
73
74
  )}
74
- </div>
75
+ </>
75
76
  ) : null}
76
- </div>
77
+ </Alert>
77
78
  );
78
79
  }
@@ -121,7 +121,7 @@ export function FilterRow<TData>({ table, visibleColumns }: FilterRowProps<TData
121
121
  return (
122
122
  <td
123
123
  key={header.id}
124
- className="px-4 py-2"
124
+ className="p-1"
125
125
  >
126
126
  {canFilter ? (
127
127
  <ColumnFilter
@@ -131,9 +131,7 @@ export function FilterRow<TData>({ table, visibleColumns }: FilterRowProps<TData
131
131
  placeholder={`Filter ${getColumnHeaderText(column as unknown as Column<DataRecord, unknown>)}...`}
132
132
  />
133
133
  ) : (
134
- <div className="h-8 flex items-center text-sec-400 text-sm">
135
- No filter
136
- </div>
134
+ <>&nbsp;</>
137
135
  )}
138
136
  </td>
139
137
  );
@@ -36,10 +36,12 @@
36
36
  * - Customizable text content
37
37
  */
38
38
  import React, { useState, useRef, useEffect } from 'react';
39
- import { Dialog, DialogContent, DialogHeader } from '../../Dialog';
39
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '../../Dialog';
40
40
  import { Button } from '../../Button/Button';
41
41
  import { Input } from '../../Input/Input';
42
42
  import { Progress } from '../../Progress';
43
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../Table/Table';
44
+ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '../../Card/Card';
43
45
  import { Upload, FileText, AlertCircle } from 'lucide-react';
44
46
  import { createLogger } from '../../../utils/core/logger';
45
47
 
@@ -372,150 +374,146 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
372
374
 
373
375
  return (
374
376
  <Dialog open={isOpen} onOpenChange={handleClose}>
375
- <DialogContent className="sm:max-w-2xl bg-main-50" title={title} description={description}>
377
+ <DialogContent
378
+ maxWidthPercent={95}
379
+ className="w-auto"
380
+ title={title}
381
+ description={description}
382
+ >
376
383
  <DialogHeader>
377
- <h2>{title}</h2>
378
- <p>{description}</p>
384
+ <DialogTitle>{title}</DialogTitle>
385
+ <DialogDescription>{description}</DialogDescription>
379
386
  </DialogHeader>
380
387
 
381
- <div className="space-y-4">
382
- <div className="border-2 border-dashed border-sec-200 rounded-lg p-6 text-center">
383
- <FileText className="size-8 mx-auto text-sec-400 mb-2" />
384
- <p className="text-sec-600 mb-2">
388
+ <Card className="text-center">
389
+ <CardHeader>
390
+ <FileText className="size-8 mx-auto text-sec-400 mb-2" />
391
+ </CardHeader>
392
+ <CardDescription>
385
393
  {file ? `Selected: ${file.name}` : uploadText}
386
- </p>
387
- {file && (
388
- <p className="text-xs text-sec-500">
389
- File selected, processing preview...
390
- </p>
391
- )}
392
- <Button
393
- variant="outline"
394
- size="sm"
395
- onClick={() => fileInputRef.current?.click()}
396
- >
397
- <Upload className="size-4 mr-2" />
398
- {selectFileButtonText}
399
- </Button>
400
- <Input
401
- ref={fileInputRef}
402
- type="file"
403
- accept=".csv"
404
- onChange={handleFileSelect}
405
- className="hidden"
406
- />
407
- </div>
408
-
409
- {error && (
410
- <div className="flex items-center gap-2 p-3 bg-acc-50 border border-acc-200 rounded text-acc-700">
411
- <AlertCircle className="size-4" />
412
- <span className="text-sm">{error}</span>
413
- </div>
414
- )}
415
-
416
- {validationErrors.length > 0 && (
417
- <div className="space-y-2">
418
- <div className="flex items-center gap-2 p-3 bg-acc-50 border border-acc-200 rounded text-acc-700">
419
- <AlertCircle className="size-4" />
420
- <span className="text-sm font-medium">
421
- {validationErrors.length} validation error{validationErrors.length !== 1 ? 's' : ''} found
394
+ {file && (
395
+ <span className="block text-xs text-sec-500 mt-1">
396
+ File selected, processing preview...
422
397
  </span>
423
- </div>
424
- <div className="max-h-32 overflow-y-auto space-y-1">
425
- {validationErrors.slice(0, 10).map((err, idx) => (
426
- <div key={idx} className="text-xs text-acc-600 p-2 bg-acc-50 border border-acc-200 rounded">
427
- <span className="font-medium">Row {err.row}</span> • {err.field}: {err.message}
428
- </div>
429
- ))}
430
- {validationErrors.length > 10 && (
431
- <div className="text-xs text-sec-500 italic">
432
- ... and {validationErrors.length - 10} more errors
433
- </div>
434
- )}
435
- </div>
436
- </div>
437
- )}
438
-
398
+ )}
399
+ </CardDescription>
400
+ <CardContent className="text-center">
401
+ {error && (
402
+ <>
403
+ <AlertCircle className="inline-block size-4 mr-2" />
404
+ <span className="text-sm">{error}</span>
405
+ </>
406
+ )}
407
+
408
+ {validationErrors.length > 0 && (
409
+ <>
410
+ <AlertCircle className="size-4" />
411
+ <span className="text-sm font-medium">
412
+ {validationErrors.length} validation error{validationErrors.length !== 1 ? 's' : ''} found
413
+ </span>
414
+ {validationErrors.slice(0, 10).map((err, idx) => (
415
+ <p key={idx} className="text-xs text-acc-600 p-2 bg-acc-50 border border-acc-200 rounded">
416
+ <span className="font-medium">Row {err.row}</span> • {err.field}: {err.message}
417
+ </p>
418
+ ))}
419
+ {validationErrors.length > 10 && (
420
+ <p className="text-xs text-sec-500 italic">
421
+ ... and {validationErrors.length - 10} more errors
422
+ </p>
423
+ )}
424
+ </>
425
+ )}
439
426
 
440
- {importProgress && isProcessing && (
441
- <div className="space-y-2 p-4 bg-sec-50 rounded-lg border border-sec-200">
442
- <div className="flex items-center justify-between">
443
- <span className="text-sm font-medium text-sec-900">
444
- {importProgress.stage === 'parsing' ? 'Parsing CSV file...' : 'Importing data...'}
445
- </span>
446
- <span className="text-sm text-sec-600">
447
- {importProgress.current.toLocaleString()} / {importProgress.total.toLocaleString()} rows
448
- </span>
449
- </div>
450
- <Progress
451
- value={importProgress.total > 0 ? (importProgress.current / importProgress.total) * 100 : 0}
452
- className="h-2 bg-sec-200"
427
+ {importProgress && isProcessing && (
428
+ <>
429
+ <span className="text-sm font-medium text-sec-900">
430
+ {importProgress.stage === 'parsing' ? 'Parsing CSV file...' : 'Importing data...'}
431
+ </span>
432
+ <span className="text-sm text-sec-600">
433
+ {importProgress.current.toLocaleString()} / {importProgress.total.toLocaleString()} rows
434
+ </span>
435
+ <Progress
436
+ value={importProgress.total > 0 ? (importProgress.current / importProgress.total) * 100 : 0}
437
+ className="h-2 bg-sec-200"
438
+ />
439
+ <p className="text-xs text-sec-500">
440
+ {importProgress.total > 0 && importProgress.current < importProgress.total
441
+ ? `${Math.round((importProgress.current / importProgress.total) * 100)}% complete`
442
+ : importProgress.stage === 'importing' && importProgress.current === 0
443
+ ? 'Processing your data...'
444
+ : importProgress.current === importProgress.total
445
+ ? 'Complete!'
446
+ : 'Processing...'}
447
+ </p>
448
+ </>
449
+ )}
450
+ </CardContent>
451
+ <CardFooter>
452
+ <Button
453
+ variant="outline"
454
+ size="sm"
455
+ onClick={() => fileInputRef.current?.click()}
456
+ >
457
+ <Upload className="size-4 mr-2" />
458
+ {selectFileButtonText}
459
+ </Button>
460
+ <Input
461
+ ref={fileInputRef}
462
+ type="file"
463
+ accept=".csv"
464
+ onChange={handleFileSelect}
465
+ className="hidden"
453
466
  />
454
- <p className="text-xs text-sec-500">
455
- {importProgress.total > 0 && importProgress.current < importProgress.total
456
- ? `${Math.round((importProgress.current / importProgress.total) * 100)}% complete`
457
- : importProgress.stage === 'importing' && importProgress.current === 0
458
- ? 'Processing your data...'
459
- : importProgress.current === importProgress.total
460
- ? 'Complete!'
461
- : 'Processing...'}
462
- </p>
463
- </div>
464
- )}
467
+ </CardFooter>
468
+ </Card>
465
469
 
466
470
  {file && previewData && previewData.length > 0 && !isProcessing ? (
467
- <div className="space-y-3">
468
- <h4 className="text-sec-900">{previewHeaderText}</h4>
469
- <div className="border rounded-lg overflow-hidden">
470
- <div className="overflow-x-auto max-h-48">
471
- <table className="min-w-full text-xs">
472
- <thead className="bg-sec-50">
473
- <tr>
471
+ <Card>
472
+ <CardHeader>
473
+ <CardTitle>{previewHeaderText}</CardTitle>
474
+ </CardHeader>
475
+ <CardContent className="overflow-x-auto">
476
+ <Table className="text-xs min-w-full">
477
+ <TableHeader>
478
+ <TableRow>
474
479
  {Object.keys(previewData[0]).map((header) => (
475
- <th key={header} className="px-2 py-1 text-left font-medium text-sec-900 border-b">
480
+ <TableHead key={header} >
476
481
  {header}
477
- </th>
482
+ </TableHead>
478
483
  ))}
479
- </tr>
480
- </thead>
481
- <tbody>
484
+ </TableRow>
485
+ </TableHeader>
486
+ <TableBody>
482
487
  {previewData.map((row, index) => (
483
- <tr key={index} className={index % 2 === 0 ? 'bg-app-main-50' : 'bg-sec-50'}>
488
+ <TableRow key={index} >
484
489
  {Object.values(row).map((value, cellIndex) => (
485
- <td key={cellIndex} className="px-2 py-1 text-sec-700 border-b">
490
+ <TableCell key={cellIndex} >
486
491
  {String(value)}
487
- </td>
492
+ </TableCell>
488
493
  ))}
489
- </tr>
494
+ </TableRow>
490
495
  ))}
491
- </tbody>
492
- </table>
493
- </div>
494
- </div>
495
- <p className="text-sec-500">
496
- {totalRowsText.replace('{count}', totalCount.toString())}
497
- </p>
498
- </div>
499
- ) : !file ? (
500
- <div className="border rounded-lg p-6 text-center bg-sec-50">
501
- <p className="text-sec-500">
502
- Select a CSV file to preview
503
- </p>
504
- </div>
496
+ </TableBody>
497
+ </Table>
498
+ </CardContent>
499
+ <CardFooter>
500
+ {totalRowsText.replace('{count}', totalCount.toString())}
501
+ </CardFooter>
502
+ </Card>
505
503
  ) : null}
506
504
 
507
- <div className="flex justify-end gap-2">
508
- <Button variant="outline" onClick={handleClose}>
509
- {cancelButtonText}
510
- </Button>
511
- <Button
512
- onClick={handleImport}
513
- disabled={!file || isProcessing}
514
- >
515
- {isProcessing ? importButtonProcessingText : importButtonText}
516
- </Button>
517
- </div>
518
- </div>
505
+
506
+ <DialogFooter>
507
+ <Button variant="outline" onClick={handleClose}>
508
+ {cancelButtonText}
509
+ </Button>
510
+ <Button
511
+ onClick={handleImport}
512
+ disabled={!file || isProcessing}
513
+ >
514
+ {isProcessing ? importButtonProcessingText : importButtonText}
515
+ </Button>
516
+ </DialogFooter>
519
517
  </DialogContent>
520
518
  </Dialog>
521
519
  );