@jmruthers/pace-core 0.6.10 → 0.6.11

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 (726) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/audit-tool/00-dependencies.cjs +46 -13
  3. package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
  4. package/audit-tool/audits/02-project-structure.cjs +13 -3
  5. package/audit-tool/audits/03-architecture.cjs +78 -4
  6. package/audit-tool/audits/04-code-quality.cjs +9 -2
  7. package/audit-tool/audits/05-styling.cjs +19 -7
  8. package/audit-tool/audits/06-security-rbac.cjs +105 -14
  9. package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
  10. package/audit-tool/audits/08-testing-documentation.cjs +11 -3
  11. package/audit-tool/audits/09-operations.cjs +19 -7
  12. package/audit-tool/index.cjs +22 -11
  13. package/audit-tool/utils/report-utils.cjs +4 -0
  14. package/cursor-rules/01-pace-core-compliance.mdc +1 -0
  15. package/cursor-rules/02-project-structure.mdc +1 -0
  16. package/cursor-rules/03-architecture.mdc +3 -1
  17. package/cursor-rules/04-code-quality.mdc +1 -0
  18. package/cursor-rules/05-styling.mdc +41 -7
  19. package/cursor-rules/06-security-rbac.mdc +2 -1
  20. package/cursor-rules/07-api-tech-stack.mdc +1 -0
  21. package/cursor-rules/08-testing-documentation.mdc +1 -0
  22. package/cursor-rules/09-operations.mdc +1 -0
  23. package/dist/{DataTable-SAXFG4XI.js → DataTable-EFYP2QLE.js} +10 -7
  24. package/dist/{InactivityServiceProvider-DHryoh6K.d.ts → InactivityServiceProvider-BbxwwDz1.d.ts} +10 -1
  25. package/dist/{UnifiedAuthProvider-CiBAl9-s.d.ts → UnifiedAuthProvider-Bkt_tzdS.d.ts} +56 -24
  26. package/dist/{api-F47QJ7FX.js → api-BZR2CYXL.js} +3 -2
  27. package/dist/api-result-USV1Czr-.d.ts +51 -0
  28. package/dist/{audit-Z6ZZBWLU.js → audit-HI2DHUVU.js} +2 -1
  29. package/dist/{auth-BZOJqrdd.d.ts → auth-JvdRVaud.d.ts} +1 -1
  30. package/dist/{chunk-KSNLMI7N.js → chunk-2DL2WSOE.js} +1 -155
  31. package/dist/{chunk-MPY44PWB.js → chunk-2OEVOGGR.js} +4648 -3560
  32. package/dist/chunk-44CNXN4P.js +15 -0
  33. package/dist/{chunk-Y4PF6HIM.js → chunk-4R3T5ENU.js} +867 -786
  34. package/dist/{chunk-LNHFAF4X.js → chunk-7A6IMHH2.js} +289 -247
  35. package/dist/chunk-CU2BU2MQ.js +2 -0
  36. package/dist/{chunk-JJEYZ3DX.js → chunk-D6BMFMQZ.js} +37 -2
  37. package/dist/{chunk-BCTXBU6U.js → chunk-ENLXB7GP.js} +88 -71
  38. package/dist/{chunk-FBZ7U3ID.js → chunk-J2KQK6DG.js} +937 -987
  39. package/dist/{chunk-TFIPNIPE.js → chunk-KJXRL3XE.js} +3300 -2245
  40. package/dist/{chunk-3GWSPISD.js → chunk-L5LFKKLJ.js} +1 -1
  41. package/dist/{chunk-X5EAU5G7.js → chunk-PCSHBLPB.js} +132 -114
  42. package/dist/{chunk-NIU6DPQV.js → chunk-QRYSEPHB.js} +2 -0
  43. package/dist/{chunk-KYURMOQM.js → chunk-V7FTM2LU.js} +423 -320
  44. package/dist/chunk-WY6Y7KC3.js +264 -0
  45. package/dist/{chunk-FN52B75D.js → chunk-XOJME5T7.js} +176 -15
  46. package/dist/{chunk-7YDC7LMU.js → chunk-XPFVT3GN.js} +71 -66
  47. package/dist/{chunk-66R6RLUZ.js → chunk-YFTFFJIV.js} +3 -3
  48. package/dist/{chunk-W46INAVW.js → chunk-YYTWKVHO.js} +688 -570
  49. package/dist/components.d.ts +8 -7
  50. package/dist/components.js +17 -15
  51. package/dist/{database.generated-DT8JTZiP.d.ts → database.generated-qkdoiVrJ.d.ts} +45 -10
  52. package/dist/eslint-rules/index.cjs +3 -0
  53. package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
  54. package/dist/eslint-rules/rules/06-security-rbac.cjs +74 -0
  55. package/dist/{event-WTAQuGcq.d.ts → event-BfCox3N2.d.ts} +36 -10
  56. package/dist/{file-reference-BavO2eQj.d.ts → file-reference-DU1hcawx.d.ts} +29 -13
  57. package/dist/hooks.d.ts +22 -9
  58. package/dist/hooks.js +34 -25
  59. package/dist/icons/index.d.ts +1 -0
  60. package/dist/icons/index.js +1 -0
  61. package/dist/index.d.ts +66 -177
  62. package/dist/index.js +316 -340
  63. package/dist/pagination-BW1mqywp.d.ts +201 -0
  64. package/dist/providers.d.ts +6 -5
  65. package/dist/providers.js +5 -3
  66. package/dist/rbac/index.d.ts +123 -138
  67. package/dist/rbac/index.js +10 -8
  68. package/dist/theming/runtime.d.ts +19 -2
  69. package/dist/theming/runtime.js +1 -1
  70. package/dist/{timezone-K-ptz3HO.d.ts → timezone-BTWWXKVY.d.ts} +1 -1
  71. package/dist/types.d.ts +17 -10
  72. package/dist/types.js +1 -0
  73. package/dist/{usePublicPageContext-vxBlEHO9.d.ts → usePublicPageContext-B91dGYW1.d.ts} +433 -356
  74. package/dist/{usePublicRouteParams-G3Ks53mk.d.ts → usePublicRouteParams-BgV6VhMi.d.ts} +73 -4
  75. package/dist/utils.d.ts +163 -145
  76. package/dist/utils.js +42 -25
  77. package/docs/api/modules.md +782 -643
  78. package/docs/api-reference/rpc-functions.md +12 -3
  79. package/docs/core-concepts/rbac-system.md +8 -0
  80. package/docs/getting-started/cursor-rules.md +17 -20
  81. package/docs/getting-started/dependencies.md +1 -1
  82. package/docs/getting-started/setup.md +235 -0
  83. package/docs/implementation-guides/authentication.md +27 -0
  84. package/docs/implementation-guides/data-tables.md +176 -3
  85. package/docs/migration/ApiResult-migration.md +25 -0
  86. package/docs/rbac/api-reference.md +33 -31
  87. package/docs/standards/0-standards-overview.md +50 -15
  88. package/docs/standards/1-pace-core-compliance-standards.md +62 -57
  89. package/docs/standards/2-project-structure-standards.md +33 -16
  90. package/docs/standards/3-architecture-standards.md +41 -1
  91. package/docs/standards/4-code-quality-standards.md +26 -6
  92. package/docs/standards/5-styling-standards.md +35 -1
  93. package/docs/standards/6-security-rbac-standards.md +66 -0
  94. package/docs/standards/7-api-tech-stack-standards.md +25 -14
  95. package/docs/standards/8-testing-documentation-standards.md +31 -0
  96. package/docs/standards/9-operations-standards.md +19 -0
  97. package/docs/standards/README.md +20 -201
  98. package/docs/testing/test-setup-for-consumers.md +2 -0
  99. package/docs/troubleshooting/common-issues.md +17 -1
  100. package/docs/troubleshooting/organisation-context-setup.md +8 -0
  101. package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
  102. package/eslint-config-pace-core.cjs +20 -0
  103. package/package.json +14 -20
  104. package/scripts/{build-docs-incremental.js → build-docs.js} +3 -2
  105. package/scripts/setup.cjs +536 -0
  106. package/scripts/validate.cjs +480 -0
  107. package/src/__tests__/helpers/{__tests__/component-test-utils.test.tsx → component-test-utils.test.tsx} +3 -3
  108. package/src/__tests__/helpers/{__tests__/optimized-test-setup.test.ts → optimized-test-setup.test.ts} +2 -2
  109. package/src/__tests__/helpers/{__tests__/supabaseMock.test.ts → supabaseMock.test.ts} +2 -2
  110. package/src/__tests__/helpers/{__tests__/test-providers.test.tsx → test-providers.test.tsx} +1 -1
  111. package/src/__tests__/helpers/test-providers.tsx +37 -39
  112. package/src/__tests__/helpers/{__tests__/test-utils.test.tsx → test-utils.test.tsx} +4 -3
  113. package/src/__tests__/helpers/{__tests__/timer-utils.test.ts → timer-utils.test.ts} +2 -2
  114. package/src/assets/app-icons/index.test.ts +304 -0
  115. package/src/components/AddressField/AddressField.test.tsx +1 -1
  116. package/src/components/AddressField/AddressField.tsx +238 -212
  117. package/src/components/Button/Button.tsx +1 -1
  118. package/src/components/Card/Card.test.tsx +172 -17
  119. package/src/components/Card/Card.tsx +19 -10
  120. package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
  121. package/src/components/ContextSelector/{__tests__/ContextSelector.test.tsx → ContextSelector.test.tsx} +6 -6
  122. package/src/components/ContextSelector/ContextSelector.tsx +66 -280
  123. package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
  124. package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
  125. package/src/components/DataTable/AUDIT_REPORT.md +59 -44
  126. package/src/components/DataTable/{__tests__/DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx} +6 -6
  127. package/src/components/DataTable/{__tests__/DataTable.default-state.test.tsx → DataTable.default-state.test.tsx} +5 -5
  128. package/src/components/DataTable/{__tests__/DataTable.export.test.tsx → DataTable.export.test.tsx} +10 -10
  129. package/src/components/DataTable/{__tests__/DataTable.grouping-aggregation.test.tsx → DataTable.grouping-aggregation.test.tsx} +6 -6
  130. package/src/components/DataTable/{__tests__/DataTable.hooks.test.tsx → DataTable.hooks.test.tsx} +6 -6
  131. package/src/components/DataTable/{__tests__/DataTable.select-label-display.test.tsx → DataTable.select-label-display.test.tsx} +6 -6
  132. package/src/components/DataTable/DataTable.test.tsx +787 -416
  133. package/src/components/DataTable/DataTable.tsx +12 -12
  134. package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
  135. package/src/components/DataTable/{__tests__/DataTableCore.test-setup.ts → DataTableCore.test-setup.ts} +10 -9
  136. package/src/components/DataTable/{__tests__/DataTableCore.test.tsx → DataTableCore.test.tsx} +8 -8
  137. package/src/components/DataTable/{__tests__/README.md → README.md} +17 -7
  138. package/src/components/DataTable/TESTING.md +101 -0
  139. package/src/components/DataTable/{__tests__/a11y.basic.test.tsx → a11y.basic.test.tsx} +34 -34
  140. package/src/components/DataTable/components/DataTableCore.tsx +104 -864
  141. package/src/components/DataTable/components/{__tests__/GroupingDropdown.test.tsx → GroupingDropdown.test.tsx} +17 -8
  142. package/src/components/DataTable/components/GroupingDropdown.tsx +2 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +61 -559
  144. package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
  145. package/src/components/DataTable/context/{__tests__/DataTableContext.test.tsx → DataTableContext.test.tsx} +2 -2
  146. package/src/components/DataTable/context/DataTableContext.tsx +7 -6
  147. package/src/components/DataTable/core/{__tests__/ColumnFactory.test.ts → ColumnFactory.test.ts} +2 -2
  148. package/src/components/DataTable/hooks/{__tests__/useColumnOrderPersistence.test.ts → useColumnOrderPersistence.test.ts} +2 -2
  149. package/src/components/DataTable/hooks/{__tests__/useColumnVisibilityPersistence.test.ts → useColumnVisibilityPersistence.test.ts} +2 -2
  150. package/src/components/DataTable/hooks/{__tests__/useDataTableConfiguration.test.ts → useDataTableConfiguration.test.ts} +3 -3
  151. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +14 -2
  152. package/src/components/DataTable/hooks/{__tests__/useDataTableDataPipeline.test.ts → useDataTableDataPipeline.test.ts} +6 -6
  153. package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
  154. package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
  155. package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
  156. package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
  157. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
  158. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
  159. package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
  160. package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
  161. package/src/components/DataTable/hooks/{__tests__/useDataTablePermissions.test.ts → useDataTablePermissions.test.ts} +11 -11
  162. package/src/components/DataTable/hooks/useDataTablePermissions.ts +79 -247
  163. package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
  164. package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
  165. package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
  166. package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
  167. package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
  168. package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
  169. package/src/components/DataTable/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +47 -5
  170. package/src/components/DataTable/hooks/useDataTableState.ts +145 -94
  171. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
  172. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
  173. package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
  174. package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
  175. package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
  176. package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
  177. package/src/components/DataTable/hooks/{__tests__/useEffectiveColumnOrder.test.ts → useEffectiveColumnOrder.test.ts} +2 -2
  178. package/src/components/DataTable/hooks/{__tests__/useHierarchicalState.test.ts → useHierarchicalState.test.ts} +2 -2
  179. package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.test.ts +3 -3
  180. package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.ts +2 -2
  181. package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
  182. package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
  183. package/src/components/DataTable/hooks/{__tests__/useKeyboardNavigation.test.ts → useKeyboardNavigation.test.ts} +3 -3
  184. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +309 -269
  185. package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.test.ts +3 -3
  186. package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.ts +3 -3
  187. package/src/components/DataTable/hooks/{__tests__/useServerSideDataEffect.test.ts → useServerSideDataEffect.test.ts} +2 -2
  188. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +14 -3
  189. package/src/components/DataTable/hooks/{__tests__/useTableColumns.test.ts → useTableColumns.test.ts} +2 -2
  190. package/src/components/DataTable/hooks/{__tests__/useTableHandlers.test.ts → useTableHandlers.test.ts} +25 -4
  191. package/src/components/DataTable/hooks/useTableHandlers.ts +5 -2
  192. package/src/components/DataTable/index.ts +18 -17
  193. package/src/components/DataTable/{__tests__/keyboard.test.tsx → keyboard.test.tsx} +41 -63
  194. package/src/components/DataTable/{__tests__/mocks → mocks}/MockRBACProvider.tsx +1 -1
  195. package/src/components/DataTable/{__tests__/pagination.modes.test.tsx → pagination.modes.test.tsx} +6 -6
  196. package/src/components/DataTable/{__tests__/ssr.strict-mode.test.tsx → ssr.strict-mode.test.tsx} +2 -2
  197. package/src/components/DataTable/{__tests__/styles.test.ts → styles.test.ts} +1 -4
  198. package/src/components/DataTable/styles.ts +0 -1
  199. package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
  200. package/src/components/DataTable/{__tests__/test-utils → test-utils}/dataFactories.ts +2 -2
  201. package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
  202. package/src/components/DataTable/{__tests__/test-utils/sharedTestUtils.tsx → test-utils/sharedTestUtils.ts} +97 -66
  203. package/src/components/DataTable/{__tests__/test-utils.ts → test-utils.ts} +1 -1
  204. package/src/components/DataTable/types/actions.ts +71 -0
  205. package/src/components/DataTable/types/base.ts +39 -0
  206. package/src/components/DataTable/types/columns.ts +125 -0
  207. package/src/components/DataTable/types/export.ts +32 -0
  208. package/src/components/DataTable/types/features.ts +81 -0
  209. package/src/components/DataTable/types/hierarchical.ts +44 -0
  210. package/src/components/DataTable/types/index.ts +43 -0
  211. package/src/components/DataTable/types/pagination.ts +85 -0
  212. package/src/components/DataTable/types/performance.ts +47 -0
  213. package/src/components/DataTable/types/props.ts +62 -0
  214. package/src/components/DataTable/types/rbac.ts +45 -0
  215. package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableCore.test.tsx +430 -28
  216. package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
  217. package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableErrorBoundary.test.tsx +4 -4
  218. package/src/components/DataTable/{components → ui/layout}/DataTableErrorBoundary.tsx +7 -7
  219. package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
  220. package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
  221. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
  222. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
  223. package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
  224. package/src/components/DataTable/{components → ui/modals}/DataTableModals.tsx +36 -28
  225. package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
  226. package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
  227. package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
  228. package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
  229. package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
  230. package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
  231. package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
  232. package/src/components/DataTable/{components/__tests__ → ui/shared}/AccessDeniedPage.test.tsx +2 -2
  233. package/src/components/DataTable/{components → ui/shared}/AccessDeniedPage.tsx +2 -2
  234. package/src/components/DataTable/{components/__tests__ → ui/shared}/ActionButtons.test.tsx +6 -4
  235. package/src/components/DataTable/{components → ui/shared}/ActionButtons.tsx +4 -4
  236. package/src/components/DataTable/{components/__tests__ → ui/shared}/ColumnFilter.test.tsx +29 -16
  237. package/src/components/DataTable/{components → ui/shared}/ColumnFilter.tsx +4 -4
  238. package/src/components/DataTable/{components/__tests__ → ui/shared}/PaginationControls.test.tsx +38 -16
  239. package/src/components/DataTable/{components → ui/shared}/PaginationControls.tsx +21 -15
  240. package/src/components/DataTable/{components/__tests__ → ui/shared}/SortIndicator.test.tsx +2 -2
  241. package/src/components/DataTable/{components → ui/shared}/SortIndicator.tsx +1 -1
  242. package/src/components/DataTable/{components/__tests__ → ui/table}/EditFields.test.tsx +3 -3
  243. package/src/components/DataTable/{components → ui/table}/EditFields.tsx +138 -69
  244. package/src/components/DataTable/{components/__tests__ → ui/table}/EditableRow.test.tsx +36 -27
  245. package/src/components/DataTable/{components → ui/table}/EditableRow.tsx +86 -104
  246. package/src/components/DataTable/{components/__tests__ → ui/table}/EmptyState.test.tsx +2 -62
  247. package/src/components/DataTable/{components → ui/table}/EmptyState.tsx +7 -15
  248. package/src/components/DataTable/{components/__tests__ → ui/table}/FilterRow.test.tsx +5 -4
  249. package/src/components/DataTable/{components → ui/table}/FilterRow.tsx +3 -3
  250. package/src/components/DataTable/{components/__tests__ → ui/table}/LoadingState.test.tsx +6 -10
  251. package/src/components/DataTable/{components → ui/table}/LoadingState.tsx +4 -4
  252. package/src/components/DataTable/{components/__tests__ → ui/table}/RowComponent.test.tsx +412 -17
  253. package/src/components/DataTable/{components → ui/table}/RowComponent.tsx +183 -177
  254. package/src/components/DataTable/{components/__tests__ → ui/table}/UnifiedTableBody.test.tsx +425 -16
  255. package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
  256. package/src/components/DataTable/{components/__tests__ → ui/table}/cellValueUtils.test.ts +2 -2
  257. package/src/components/DataTable/{components → ui/table}/cellValueUtils.ts +1 -1
  258. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/BulkOperationsDropdown.test.tsx +12 -5
  259. package/src/components/DataTable/{components → ui/toolbar}/BulkOperationsDropdown.tsx +3 -3
  260. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/ColumnVisibilityDropdown.test.tsx +7 -4
  261. package/src/components/DataTable/{components → ui/toolbar}/ColumnVisibilityDropdown.tsx +7 -7
  262. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/DataTableToolbar.test.tsx +4 -4
  263. package/src/components/DataTable/{components → ui/toolbar}/DataTableToolbar.tsx +4 -4
  264. package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
  265. package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
  266. package/src/components/DataTable/utils/{__tests__/a11yUtils.test.ts → a11yUtils.test.ts} +2 -2
  267. package/src/components/DataTable/utils/{__tests__/aggregationUtils.test.ts → aggregationUtils.test.ts} +3 -3
  268. package/src/components/DataTable/utils/{__tests__/columnUtils.test.ts → columnUtils.test.ts} +2 -2
  269. package/src/components/DataTable/utils/csvParse.test.ts +74 -0
  270. package/src/components/DataTable/utils/csvParse.ts +65 -0
  271. package/src/components/DataTable/utils/{__tests__/errorHandling.test.ts → errorHandling.test.ts} +2 -2
  272. package/src/components/DataTable/utils/{__tests__/exportUtils.test.ts → exportUtils.test.ts} +3 -3
  273. package/src/components/DataTable/utils/{__tests__/flexibleImport.test.ts → flexibleImport.test.ts} +2 -2
  274. package/src/components/DataTable/utils/flexibleImport.ts +3 -186
  275. package/src/components/DataTable/utils/{__tests__/hierarchicalSorting.test.ts → hierarchicalSorting.test.ts} +3 -3
  276. package/src/components/DataTable/utils/{__tests__/hierarchicalUtils.test.ts → hierarchicalUtils.test.ts} +3 -3
  277. package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
  278. package/src/components/DataTable/utils/importDateParser.ts +114 -0
  279. package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
  280. package/src/components/DataTable/utils/importValueParser.ts +91 -0
  281. package/src/components/DataTable/utils/{__tests__/paginationUtils.test.ts → paginationUtils.test.ts} +2 -2
  282. package/src/components/DataTable/utils/paginationUtils.ts +6 -3
  283. package/src/components/DataTable/utils/{__tests__/performanceUtils.test.ts → performanceUtils.test.ts} +3 -3
  284. package/src/components/DataTable/utils/{__tests__/rowUtils.test.ts → rowUtils.test.ts} +3 -3
  285. package/src/components/DataTable/utils/{__tests__/selectFieldUtils.test.ts → selectFieldUtils.test.ts} +66 -3
  286. package/src/components/DataTable/utils/selectFieldUtils.ts +97 -60
  287. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
  288. package/src/components/DateTimeField/DateTimeField.test.tsx +1 -1
  289. package/src/components/Dialog/Dialog.test-utils.ts +49 -0
  290. package/src/components/Dialog/Dialog.test.tsx +896 -89
  291. package/src/components/Dialog/Dialog.tsx +174 -882
  292. package/src/components/Dialog/dialogLock.test.ts +238 -0
  293. package/src/components/Dialog/dialogLock.ts +98 -0
  294. package/src/components/Dialog/index.ts +2 -0
  295. package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
  296. package/src/components/Dialog/useDialogDimensions.ts +140 -0
  297. package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
  298. package/src/components/Dialog/useDialogLifecycle.ts +135 -0
  299. package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
  300. package/src/components/Dialog/useDialogPersistence.ts +357 -0
  301. package/src/components/FileDisplay/FileDisplay.test.tsx +40 -40
  302. package/src/components/FileDisplay/FileDisplay.tsx +24 -656
  303. package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
  304. package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
  305. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
  306. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
  307. package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
  308. package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
  309. package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
  310. package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
  311. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
  312. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
  313. package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
  314. package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
  315. package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
  316. package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
  317. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
  318. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
  319. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
  320. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
  321. package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
  322. package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
  323. package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
  324. package/src/components/FileDisplay/fallbackUtils.ts +44 -0
  325. package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
  326. package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
  327. package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
  328. package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
  329. package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.test.ts +40 -42
  330. package/src/components/FileDisplay/useFileDisplay.ts +515 -0
  331. package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.unit.test.ts +406 -77
  332. package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
  333. package/src/{hooks/public → components/FileDisplay}/usePublicFileDisplay.test.ts +94 -88
  334. package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
  335. package/src/components/FileUpload/FileUpload.test.tsx +16 -10
  336. package/src/components/FileUpload/FileUpload.tsx +107 -525
  337. package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
  338. package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
  339. package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
  340. package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
  341. package/src/components/FileUpload/useFileUploadManager.ts +454 -0
  342. package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
  343. package/src/components/FileUpload/useResolvedAppId.ts +77 -0
  344. package/src/components/Footer/Footer.test.tsx +6 -292
  345. package/src/components/Footer/Footer.tsx +8 -125
  346. package/src/components/Form/Form.test.tsx +44 -27
  347. package/src/components/Form/Form.tsx +64 -287
  348. package/src/components/Form/useFormPersistence.ts +257 -0
  349. package/src/components/Header/Header.test.tsx +17 -18
  350. package/src/components/Header/Header.tsx +10 -1
  351. package/src/components/Input/Input.tsx +1 -1
  352. package/src/components/Label/Label.test.tsx +1 -1
  353. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +1 -1
  354. package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
  355. package/src/components/NavigationMenu/NavigationMenu.test.tsx +1029 -26
  356. package/src/components/NavigationMenu/NavigationMenu.tsx +61 -361
  357. package/src/components/NavigationMenu/index.ts +6 -1
  358. package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
  359. package/src/components/NavigationMenu/{__tests__/useNavigationFiltering.test.ts → useNavigationFiltering.test.ts} +68 -53
  360. package/src/components/NavigationMenu/useNavigationFiltering.ts +197 -296
  361. package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
  362. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +77 -62
  363. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +3 -3
  364. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +16 -19
  365. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +529 -5
  366. package/src/components/PaceAppLayout/PaceAppLayout.tsx +280 -756
  367. package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
  368. package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
  369. package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
  370. package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
  371. package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
  372. package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
  373. package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
  374. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +31 -25
  375. package/src/components/PaceLoginPage/PaceLoginPage.tsx +31 -122
  376. package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
  377. package/src/components/Progress/Progress.tsx +1 -2
  378. package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -235
  379. package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
  380. package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
  381. package/src/components/PublicLayout/PublicLayout.test.tsx +217 -36
  382. package/src/components/PublicLayout/PublicPageLayout.tsx +132 -73
  383. package/src/components/PublicLayout/PublicPageProvider.tsx +5 -1
  384. package/src/components/Select/Select.test.tsx +1 -1
  385. package/src/components/Select/Select.tsx +28 -18
  386. package/src/components/Select/{__tests__/context.test.tsx → context.test.tsx} +3 -3
  387. package/src/components/Select/{utils/__tests__/text.test.tsx → text.test.tsx} +2 -2
  388. package/src/components/Select/{utils/text.ts → text.ts} +1 -1
  389. package/src/components/Select/{hooks/__tests__/useSelectEvents.test.ts → useSelectEvents.test.ts} +5 -5
  390. package/src/components/Select/{hooks/useSelectEvents.ts → useSelectEvents.ts} +2 -2
  391. package/src/components/Select/{hooks/__tests__/useSelectSearch.test.tsx → useSelectSearch.test.tsx} +7 -7
  392. package/src/components/Select/{hooks/useSelectSearch.ts → useSelectSearch.ts} +2 -2
  393. package/src/components/Select/{hooks/__tests__/useSelectState.test.ts → useSelectState.test.ts} +16 -2
  394. package/src/components/Select/{hooks/useSelectState.ts → useSelectState.ts} +3 -3
  395. package/src/components/Table/Table.test.tsx +348 -0
  396. package/src/components/Tabs/Tabs.test.tsx +270 -0
  397. package/src/components/Tabs/Tabs.tsx +1 -1
  398. package/src/components/Toast/Toast.test.tsx +420 -0
  399. package/src/components/{__tests__/index.test.ts → index.test.ts} +2 -2
  400. package/src/constants/{__tests__/performance.test.ts → performance.test.ts} +2 -2
  401. package/src/hooks/{__tests__/ServiceHooks.test.tsx → ServiceHooks.test.tsx} +8 -8
  402. package/src/hooks/{__tests__/hooks.integration.test.tsx → hooks.integration.test.tsx} +11 -11
  403. package/src/hooks/index.ts +7 -4
  404. package/src/hooks/{__tests__/index.unit.test.ts → index.unit.test.ts} +2 -2
  405. package/src/hooks/public/usePublicEvent.test.ts +1 -1
  406. package/src/hooks/public/usePublicEventLogo.test.ts +1 -1
  407. package/src/hooks/public/usePublicRouteParams.test.ts +1 -1
  408. package/src/hooks/services/useAuth.ts +9 -7
  409. package/src/hooks/useAddressAutocomplete.test.ts +22 -22
  410. package/src/hooks/useAddressAutocomplete.ts +90 -75
  411. package/src/hooks/{__tests__/useAppConfig.unit.test.ts → useAppConfig.unit.test.ts} +328 -22
  412. package/src/hooks/{__tests__/useComponentPerformance.unit.test.tsx → useComponentPerformance.unit.test.tsx} +27 -41
  413. package/src/hooks/useDataTablePerformance.ts +100 -120
  414. package/src/hooks/{__tests__/useDataTablePerformance.unit.test.ts → useDataTablePerformance.unit.test.ts} +5 -5
  415. package/src/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +2 -2
  416. package/src/hooks/{__tests__/useDebounce.unit.test.ts → useDebounce.unit.test.ts} +2 -2
  417. package/src/hooks/useEventTheme.test.ts +4 -1
  418. package/src/hooks/useEventTheme.ts +49 -21
  419. package/src/hooks/useEvents.ts +41 -1
  420. package/src/hooks/{__tests__/useEvents.unit.test.ts → useEvents.unit.test.ts} +5 -5
  421. package/src/hooks/useFileReference.test.ts +44 -41
  422. package/src/hooks/useFileReference.ts +182 -173
  423. package/src/hooks/useFileUrl.ts +1 -1
  424. package/src/hooks/{__tests__/useFileUrl.unit.test.ts → useFileUrl.unit.test.ts} +26 -36
  425. package/src/hooks/{__tests__/useFileUrlCache.test.ts → useFileUrlCache.test.ts} +8 -8
  426. package/src/hooks/useFileUrlCache.ts +1 -1
  427. package/src/hooks/{__tests__/useFocusManagement.unit.test.ts → useFocusManagement.unit.test.ts} +2 -2
  428. package/src/hooks/{__tests__/useFocusTrap.unit.test.tsx → useFocusTrap.unit.test.tsx} +2 -2
  429. package/src/hooks/{__tests__/useFormDialog.test.ts → useFormDialog.test.ts} +2 -2
  430. package/src/hooks/useInactivityTracker.ts +138 -131
  431. package/src/hooks/{__tests__/useInactivityTracker.unit.test.ts → useInactivityTracker.unit.test.ts} +3 -3
  432. package/src/hooks/{__tests__/useIsMobile.unit.test.ts → useIsMobile.unit.test.ts} +2 -2
  433. package/src/hooks/useIsPrint.ts +62 -0
  434. package/src/hooks/useIsPrint.unit.test.ts +545 -0
  435. package/src/hooks/{__tests__/useKeyboardShortcuts.unit.test.ts → useKeyboardShortcuts.unit.test.ts} +2 -2
  436. package/src/hooks/{__tests__/useOrganisationPermissions.unit.test.tsx → useOrganisationPermissions.unit.test.tsx} +4 -4
  437. package/src/hooks/useOrganisationSecurity.test.ts +3 -3
  438. package/src/hooks/useOrganisationSecurity.ts +190 -201
  439. package/src/hooks/{__tests__/useOrganisationSecurity.unit.test.tsx → useOrganisationSecurity.unit.test.tsx} +61 -63
  440. package/src/hooks/{__tests__/useOrganisations.unit.test.ts → useOrganisations.unit.test.ts} +5 -5
  441. package/src/hooks/{__tests__/usePerformanceMonitor.unit.test.ts → usePerformanceMonitor.unit.test.ts} +13 -14
  442. package/src/hooks/{__tests__/usePermissionCache.test.ts → usePermissionCache.test.ts} +26 -27
  443. package/src/hooks/usePermissionCache.ts +276 -271
  444. package/src/hooks/{__tests__/usePreventTabReload.test.ts → usePreventTabReload.test.ts} +2 -2
  445. package/src/hooks/{__tests__/usePublicEvent.simple.test.ts → usePublicEvent.simple.test.ts} +4 -4
  446. package/src/hooks/{__tests__/usePublicEvent.test.ts → usePublicEvent.test.ts} +4 -4
  447. package/src/hooks/{__tests__/usePublicEvent.unit.test.ts → usePublicEvent.unit.test.ts} +4 -4
  448. package/src/hooks/{__tests__/usePublicFileDisplay.test.ts → usePublicFileDisplay.test.ts} +12 -12
  449. package/src/hooks/{__tests__/usePublicRouteParams.unit.test.ts → usePublicRouteParams.unit.test.ts} +3 -3
  450. package/src/hooks/{__tests__/useQueryCache.test.ts → useQueryCache.test.ts} +2 -2
  451. package/src/hooks/useQueryCache.ts +0 -2
  452. package/src/hooks/{__tests__/useRBAC.unit.test.ts → useRBAC.unit.test.ts} +55 -38
  453. package/src/hooks/{__tests__/useSessionDraft.test.ts → useSessionDraft.test.ts} +2 -2
  454. package/src/hooks/{__tests__/useSessionRestoration.unit.test.tsx → useSessionRestoration.unit.test.tsx} +10 -19
  455. package/src/hooks/useStorage.ts +21 -16
  456. package/src/hooks/{__tests__/useStorage.unit.test.ts → useStorage.unit.test.ts} +38 -75
  457. package/src/hooks/{__tests__/useToast.test.ts → useToast.test.ts} +2 -2
  458. package/src/hooks/{__tests__/useToast.unit.test.tsx → useToast.unit.test.tsx} +2 -2
  459. package/src/hooks/{__tests__/useZodForm.unit.test.tsx → useZodForm.unit.test.tsx} +2 -2
  460. package/src/icons/{__tests__/index.test.ts → index.test.ts} +2 -2
  461. package/src/icons/index.ts +2 -0
  462. package/src/{__tests__/index.test.ts → index.test.ts} +3 -7
  463. package/src/index.ts +15 -7
  464. package/src/providers/{__tests__/AuthProvider.test.tsx → AuthProvider.test.tsx} +3 -3
  465. package/src/providers/{__tests__/EventProvider.test.tsx → EventProvider.test.tsx} +3 -3
  466. package/src/providers/InactivityProvider.test-helper.tsx +40 -0
  467. package/src/providers/{__tests__/InactivityProvider.test.tsx → InactivityProvider.test.tsx} +14 -21
  468. package/src/providers/{__tests__/ProviderLifecycle.test.tsx → ProviderLifecycle.test.tsx} +4 -4
  469. package/src/providers/{__tests__/UnifiedAuthProvider.test.tsx → UnifiedAuthProvider.test.tsx} +1 -1
  470. package/src/providers/{__tests__/index.test.ts → index.test.ts} +2 -2
  471. package/src/providers/services/{__tests__/AuthServiceProvider.integration.test.tsx → AuthServiceProvider.integration.test.tsx} +4 -4
  472. package/src/providers/services/{__tests__/AuthServiceProvider.test.tsx → AuthServiceProvider.test.tsx} +7 -7
  473. package/src/providers/services/{__tests__/EventServiceProvider.test.tsx → EventServiceProvider.test.tsx} +7 -7
  474. package/src/providers/services/{__tests__/InactivityServiceProvider.test.tsx → InactivityServiceProvider.test.tsx} +5 -5
  475. package/src/providers/services/{__tests__/OrganisationServiceProvider.test.tsx → OrganisationServiceProvider.test.tsx} +6 -6
  476. package/src/providers/services/UnifiedAuthContext.ts +30 -27
  477. package/src/providers/services/{__tests__/UnifiedAuthProvider.advanced.test.tsx → UnifiedAuthProvider.advanced.test.tsx} +8 -9
  478. package/src/providers/services/{__tests__/UnifiedAuthProvider.appId.test.tsx → UnifiedAuthProvider.appId.test.tsx} +25 -25
  479. package/src/providers/services/{__tests__/UnifiedAuthProvider.integration.test.tsx → UnifiedAuthProvider.integration.test.tsx} +14 -11
  480. package/src/providers/services/UnifiedAuthProvider.tsx +115 -360
  481. package/src/providers/services/{__tests__/contexts.test.tsx → contexts.test.tsx} +6 -6
  482. package/src/providers/services/{__tests__/useUnifiedAuth.test.tsx → useUnifiedAuth.test.tsx} +6 -6
  483. package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
  484. package/src/providers/useInactivity.test-helper.ts +27 -0
  485. package/src/rbac/{__tests__/adapters.comprehensive.test.tsx → adapters.comprehensive.test.tsx} +24 -24
  486. package/src/rbac/adapters.test.tsx +22 -22
  487. package/src/rbac/adapters.tsx +29 -29
  488. package/src/rbac/api.test.ts +973 -42
  489. package/src/rbac/api.ts +228 -253
  490. package/src/rbac/{__tests__/audit-batched.test.ts → audit-batched.test.ts} +6 -6
  491. package/src/rbac/audit.ts +4 -1
  492. package/src/rbac/{__tests__/auth-rbac-security.integration.test.tsx → auth-rbac-security.integration.test.tsx} +1 -1
  493. package/src/rbac/{__tests__/auth-rbac.e2e.test.tsx → auth-rbac.e2e.test.tsx} +27 -34
  494. package/src/rbac/cache-invalidation.test.ts +715 -0
  495. package/src/rbac/components/{__tests__/AccessDenied.test.tsx → AccessDenied.test.tsx} +3 -3
  496. package/src/rbac/components/{__tests__/NavigationGuard.test.tsx → NavigationGuard.test.tsx} +13 -11
  497. package/src/{__tests__/rbac/PagePermissionGuard.test.tsx → rbac/components/PagePermissionGuard.guard.test.tsx} +33 -19
  498. package/src/rbac/components/{__tests__/PagePermissionGuard.performance.test.tsx → PagePermissionGuard.performance.test.tsx} +30 -9
  499. package/src/rbac/components/{__tests__/PagePermissionGuard.race-condition.test.tsx → PagePermissionGuard.race-condition.test.tsx} +7 -7
  500. package/src/rbac/components/{__tests__/PagePermissionGuard.test.tsx → PagePermissionGuard.test.tsx} +10 -10
  501. package/src/rbac/components/PagePermissionGuard.tsx +177 -372
  502. package/src/rbac/components/{__tests__/PagePermissionGuard.verification.test.tsx → PagePermissionGuard.verification.test.tsx} +7 -7
  503. package/src/rbac/config.ts +58 -18
  504. package/src/rbac/{__tests__/engine.comprehensive.test.ts → engine.comprehensive.test.ts} +3 -3
  505. package/src/rbac/engine.test.ts +494 -0
  506. package/src/rbac/errors.ts +89 -55
  507. package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
  508. package/src/rbac/hooks/permissions/{__tests__/useAccessLevel.test.ts → useAccessLevel.test.ts} +40 -40
  509. package/src/rbac/hooks/permissions/useAccessLevel.ts +16 -6
  510. package/src/rbac/hooks/permissions/{__tests__/useCan.test.ts → useCan.test.ts} +41 -41
  511. package/src/rbac/hooks/permissions/useCan.ts +170 -252
  512. package/src/rbac/hooks/permissions/{__tests__/useMultiplePermissions.test.ts → useMultiplePermissions.test.ts} +49 -49
  513. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +6 -2
  514. package/src/rbac/hooks/permissions/{__tests__/usePermissions.test.ts → usePermissions.test.ts} +10 -12
  515. package/src/rbac/hooks/permissions/usePermissions.ts +36 -65
  516. package/src/rbac/hooks/useCan.test.ts +42 -42
  517. package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
  518. package/src/rbac/hooks/usePageGuardScope.ts +117 -0
  519. package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
  520. package/src/rbac/hooks/{__tests__/usePermissions.integration.test.ts → usePermissions.integration.test.ts} +9 -9
  521. package/src/{__tests__/hooks/usePermissions.test.ts → rbac/hooks/usePermissions.stability.test.ts} +18 -18
  522. package/src/rbac/hooks/usePermissions.test.ts +54 -54
  523. package/src/rbac/hooks/useRBAC.test.ts +313 -217
  524. package/src/rbac/hooks/useRBAC.ts +145 -81
  525. package/src/rbac/hooks/useResourcePermissions.test.ts +25 -25
  526. package/src/rbac/hooks/useResourcePermissions.ts +68 -134
  527. package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
  528. package/src/rbac/hooks/useRoleManagement.test.ts +27 -112
  529. package/src/rbac/hooks/useRoleManagement.ts +153 -585
  530. package/src/rbac/hooks/{__tests__/useSecureSupabase.test.ts → useSecureSupabase.test.ts} +17 -17
  531. package/src/rbac/hooks/useSecureSupabase.ts +10 -2
  532. package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
  533. package/src/rbac/{__tests__/performance.test.ts → performance.test.ts} +1 -1
  534. package/src/rbac/{__tests__/rbac-core.test.tsx → rbac-core.test.tsx} +3 -3
  535. package/src/rbac/{__tests__/rbac-engine-core-logic.test.ts → rbac-engine-core-logic.test.ts} +2 -2
  536. package/src/rbac/{__tests__/rbac-engine-simplified.test.ts → rbac-engine-simplified.test.ts} +3 -3
  537. package/src/rbac/{__tests__/rbac-functions.test.ts → rbac-functions.test.ts} +57 -0
  538. package/src/rbac/{__tests__/rbac-role-isolation.test.ts → rbac-role-isolation.test.ts} +2 -2
  539. package/src/rbac/request-deduplication.test.ts +14 -9
  540. package/src/rbac/request-deduplication.ts +5 -4
  541. package/src/rbac/{__tests__/scenarios.user-role.test.tsx → scenarios.user-role.test.tsx} +23 -23
  542. package/src/rbac/secureClient.test.ts +514 -83
  543. package/src/rbac/secureClient.ts +8 -2
  544. package/src/rbac/security.test.ts +323 -0
  545. package/src/rbac/types/roleManagement.ts +66 -0
  546. package/src/rbac/utils/{__tests__/clientSecurity.test.ts → clientSecurity.test.ts} +4 -4
  547. package/src/rbac/utils/{__tests__/contextValidator.test.ts → contextValidator.test.ts} +4 -4
  548. package/src/rbac/utils/contextValidator.ts +5 -1
  549. package/src/rbac/utils/{__tests__/deep-equal.test.ts → deep-equal.test.ts} +1 -1
  550. package/src/rbac/utils/{__tests__/eventContext.test.ts → eventContext.test.ts} +36 -21
  551. package/src/rbac/utils/eventContext.ts +37 -33
  552. package/src/rbac/utils/fetchPermissionMap.ts +13 -0
  553. package/src/rbac/utils/permissionMapHelpers.ts +34 -0
  554. package/src/rbac/utils/roleManagementRpc.ts +303 -0
  555. package/src/services/{__tests__/AuthService.edge-cases.test.ts → AuthService.edge-cases.test.ts} +19 -19
  556. package/src/services/{__tests__/AuthService.restoreSession.test.ts → AuthService.restoreSession.test.ts} +2 -2
  557. package/src/services/{__tests__/AuthService.test.ts → AuthService.test.ts} +89 -55
  558. package/src/services/AuthService.ts +184 -205
  559. package/src/services/{__tests__/BaseService.edge-cases.test.ts → BaseService.edge-cases.test.ts} +3 -3
  560. package/src/services/{__tests__/BaseService.test.ts → BaseService.test.ts} +2 -2
  561. package/src/services/{__tests__/EventService.edge-cases.test.ts → EventService.edge-cases.test.ts} +27 -24
  562. package/src/services/{__tests__/EventService.eventColours.test.ts → EventService.eventColours.test.ts} +1 -1
  563. package/src/services/{__tests__/EventService.test.ts → EventService.test.ts} +256 -24
  564. package/src/services/EventService.ts +242 -312
  565. package/src/services/{__tests__/InactivityService.edge-cases.test.ts → InactivityService.edge-cases.test.ts} +3 -3
  566. package/src/services/{__tests__/InactivityService.lifecycle.test.ts → InactivityService.lifecycle.test.ts} +2 -2
  567. package/src/services/{__tests__/InactivityService.test.ts → InactivityService.test.ts} +179 -4
  568. package/src/services/InactivityService.ts +172 -213
  569. package/src/services/{__tests__/OrganisationService.edge-cases.test.ts → OrganisationService.edge-cases.test.ts} +5 -5
  570. package/src/services/{__tests__/OrganisationService.pagination.test.ts → OrganisationService.pagination.test.ts} +4 -4
  571. package/src/services/{__tests__/OrganisationService.test.ts → OrganisationService.test.ts} +410 -7
  572. package/src/services/OrganisationService.ts +184 -238
  573. package/src/services/base/BaseService.test.ts +1 -1
  574. package/src/services/interfaces/{__tests__/IAuthService.test.ts → IAuthService.test.ts} +21 -27
  575. package/src/services/interfaces/IAuthService.ts +10 -9
  576. package/src/services/interfaces/{__tests__/IEventService.test.ts → IEventService.test.ts} +4 -4
  577. package/src/services/interfaces/{__tests__/IInactivityService.test.ts → IInactivityService.test.ts} +3 -3
  578. package/src/services/interfaces/{__tests__/IOrganisationService.test.ts → IOrganisationService.test.ts} +3 -3
  579. package/src/styles/core.css +243 -12
  580. package/src/theming/{__tests__/parseEventColours.test.ts → parseEventColours.test.ts} +1 -1
  581. package/src/theming/{__tests__/runtime.test.ts → runtime.test.ts} +8 -17
  582. package/src/theming/runtime.ts +71 -2
  583. package/src/types/api-result.ts +53 -0
  584. package/src/types/{__tests__/core.test.ts → core.test.ts} +2 -2
  585. package/src/types/{__tests__/database-generated.test.ts → database-generated.test.ts} +3 -3
  586. package/src/types/database.generated.ts +45 -10
  587. package/src/types/event.ts +38 -18
  588. package/src/types/{__tests__/file-reference.test.ts → file-reference.test.ts} +13 -13
  589. package/src/types/file-reference.ts +37 -12
  590. package/src/types/{__tests__/guards.test.ts → guards.test.ts} +2 -2
  591. package/src/types/{__tests__/index.test.ts → index.test.ts} +2 -2
  592. package/src/types/index.ts +3 -0
  593. package/src/types/{__tests__/organisation.roles.test.ts → organisation.roles.test.ts} +1 -1
  594. package/src/types/{__tests__/organisation.test.ts → organisation.test.ts} +3 -31
  595. package/src/types/organisation.ts +15 -15
  596. package/src/types/supabase.ts +13 -4
  597. package/src/types/{__tests__/theme.test.ts → theme.test.ts} +1 -1
  598. package/src/types/{__tests__/type-validation.test.ts → type-validation.test.ts} +1 -1
  599. package/src/types/{__tests__/validation.test.ts → validation.test.ts} +2 -2
  600. package/src/utils/app/appIdResolver.test.ts +98 -71
  601. package/src/utils/app/appIdResolver.ts +31 -20
  602. package/src/utils/{__tests__/appConfig.unit.test.ts → appConfig.unit.test.ts} +1 -1
  603. package/src/utils/{__tests__/audit.unit.test.ts → audit.unit.test.ts} +1 -1
  604. package/src/utils/{__tests__/auth-utils.unit.test.ts → auth-utils.unit.test.ts} +16 -17
  605. package/src/utils/{__tests__/bundleAnalysis.unit.test.ts → bundleAnalysis.unit.test.ts} +35 -35
  606. package/src/utils/{__tests__/cn.unit.test.ts → cn.unit.test.ts} +1 -1
  607. package/src/utils/context/organisationContext.test.ts +105 -91
  608. package/src/utils/context/organisationContext.ts +29 -40
  609. package/src/utils/core/{__tests__/cn.test.ts → cn.test.ts} +3 -3
  610. package/src/utils/core/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +2 -2
  611. package/src/utils/core/{__tests__/logger.test.ts → logger.test.ts} +2 -2
  612. package/src/utils/core/mergeRefs.ts +24 -0
  613. package/src/utils/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +1 -1
  614. package/src/utils/{__tests__/deviceFingerprint.unit.test.ts → deviceFingerprint.unit.test.ts} +1 -1
  615. package/src/utils/dynamic/createLazyComponent.tsx +9 -1
  616. package/src/utils/dynamic/{__tests__/dynamicUtils.test.ts → dynamicUtils.test.ts} +2 -2
  617. package/src/utils/dynamic/{__tests__/lazyLoad.test.tsx → lazyLoad.test.tsx} +2 -2
  618. package/src/utils/{__tests__/dynamicUtils.unit.test.ts → dynamicUtils.unit.test.ts} +1 -1
  619. package/src/utils/file-reference/{__tests__/file-reference.test.ts → file-reference.test.ts} +214 -289
  620. package/src/utils/file-reference/index.ts +330 -347
  621. package/src/utils/{__tests__/formatDate.unit.test.ts → formatDate.unit.test.ts} +2 -2
  622. package/src/utils/formatting/formatDateTimeTimezone.test.ts +1 -1
  623. package/src/utils/formatting/formatNumber.test.ts +1 -1
  624. package/src/utils/{__tests__/formatting.unit.test.ts → formatting.unit.test.ts} +1 -1
  625. package/src/utils/google-places/googlePlacesUtils.test.ts +70 -48
  626. package/src/utils/google-places/googlePlacesUtils.ts +67 -99
  627. package/src/utils/google-places/loadGoogleMapsScript.test.ts +25 -22
  628. package/src/utils/google-places/loadGoogleMapsScript.ts +138 -117
  629. package/src/utils/{__tests__/index.unit.test.ts → index.unit.test.ts} +1 -1
  630. package/src/utils/{__tests__/lazyLoad.unit.test.tsx → lazyLoad.unit.test.tsx} +13 -14
  631. package/src/utils/location/location.test.ts +1 -1
  632. package/src/utils/{__tests__/logger.unit.test.ts → logger.unit.test.ts} +1 -1
  633. package/src/utils/{__tests__/organisationContext.unit.test.ts → organisationContext.unit.test.ts} +37 -48
  634. package/src/utils/performance/{__tests__/bundleAnalysis.test.ts → bundleAnalysis.test.ts} +2 -2
  635. package/src/utils/performance/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
  636. package/src/utils/performance/{__tests__/performanceBudgets.test.ts → performanceBudgets.test.ts} +2 -2
  637. package/src/utils/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
  638. package/src/utils/{__tests__/performanceBudgets.unit.test.ts → performanceBudgets.unit.test.ts} +2 -2
  639. package/src/utils/{__tests__/permissionTypes.unit.test.ts → permissionTypes.unit.test.ts} +1 -1
  640. package/src/utils/{__tests__/permissionUtils.unit.test.ts → permissionUtils.unit.test.ts} +1 -1
  641. package/src/utils/permissions/{__tests__/permissionTypes.test.ts → permissionTypes.test.ts} +2 -2
  642. package/src/utils/persistence/{__tests__/keyDerivation.test.ts → keyDerivation.test.ts} +2 -2
  643. package/src/utils/persistence/{__tests__/sensitiveFieldDetection.test.ts → sensitiveFieldDetection.test.ts} +2 -2
  644. package/src/utils/{__tests__/request-deduplication.test.ts → request-deduplication.test.ts} +2 -2
  645. package/src/utils/{__tests__/sanitization.unit.test.ts → sanitization.unit.test.ts} +1 -1
  646. package/src/utils/{__tests__/schemaUtils.unit.test.ts → schemaUtils.unit.test.ts} +1 -1
  647. package/src/utils/{__tests__/secureDataAccess.unit.test.ts → secureDataAccess.unit.test.ts} +2 -2
  648. package/src/utils/{__tests__/secureErrors.unit.test.ts → secureErrors.unit.test.ts} +4 -4
  649. package/src/utils/{__tests__/secureStorage.unit.test.ts → secureStorage.unit.test.ts} +1 -1
  650. package/src/utils/security/auth-utils.ts +34 -23
  651. package/src/utils/security/secureDataAccess.ts +241 -281
  652. package/src/utils/security/secureErrors.test.ts +1 -1
  653. package/src/utils/security/secureStorage.test.ts +1 -1
  654. package/src/utils/security/security.test.ts +25 -17
  655. package/src/utils/security/security.ts +15 -18
  656. package/src/utils/security/securityMonitor.test.ts +1 -1
  657. package/src/utils/{__tests__/security.unit.test.ts → security.unit.test.ts} +21 -15
  658. package/src/utils/{__tests__/securityMonitor.unit.test.ts → securityMonitor.unit.test.ts} +1 -1
  659. package/src/utils/{__tests__/sessionTracking.unit.test.ts → sessionTracking.unit.test.ts} +12 -12
  660. package/src/utils/storage/{__tests__/config.unit.test.ts → config.unit.test.ts} +2 -2
  661. package/src/utils/storage/helpers.test.ts +88 -102
  662. package/src/utils/storage/helpers.ts +173 -251
  663. package/src/utils/storage/{__tests__/index.unit.test.ts → index.unit.test.ts} +3 -3
  664. package/src/utils/storage/types.ts +7 -0
  665. package/src/utils/supabase/createBaseClient.test.ts +1 -1
  666. package/src/utils/timezone/timezone.test.ts +1 -1
  667. package/src/utils/{__tests__/timezone.test.ts → timezone.test.ts} +2 -2
  668. package/src/utils/validation/{__tests__/common.test.ts → common.test.ts} +2 -2
  669. package/src/utils/validation/{__tests__/csrf.test.ts → csrf.test.ts} +56 -28
  670. package/src/utils/validation/csrf.ts +42 -41
  671. package/src/utils/validation/{__tests__/htmlSanitization.unit.test.ts → htmlSanitization.unit.test.ts} +2 -2
  672. package/src/utils/validation/{__tests__/passwordSchema.test.ts → passwordSchema.test.ts} +2 -2
  673. package/src/utils/validation/{__tests__/schema.test.ts → schema.test.ts} +2 -2
  674. package/src/utils/validation/{__tests__/sqlInjectionProtection.test.ts → sqlInjectionProtection.test.ts} +2 -2
  675. package/src/utils/validation/{__tests__/user.test.ts → user.test.ts} +2 -2
  676. package/src/utils/validation/{__tests__/validation.test.ts → validation.test.ts} +2 -2
  677. package/src/utils/validation/{__tests__/validationUtils.test.ts → validationUtils.test.ts} +2 -2
  678. package/src/utils/{__tests__/validation.unit.test.ts → validation.unit.test.ts} +1 -1
  679. package/src/utils/{__tests__/validationUtils.unit.test.ts → validationUtils.unit.test.ts} +5 -2
  680. package/dist/UnifiedAuthProvider-BBD2PS3Q.js +0 -7
  681. package/dist/chunk-KPYQWGFQ.js +0 -183
  682. package/dist/types-D05dCGma.d.ts +0 -521
  683. package/scripts/eslint-audit.cjs +0 -222
  684. package/scripts/generate-docs.js +0 -157
  685. package/scripts/install-cursor-rules.cjs +0 -255
  686. package/scripts/install-eslint-config.cjs +0 -349
  687. package/scripts/setup-build-cache.js +0 -73
  688. package/scripts/validate-pre-publish.js +0 -145
  689. package/src/__tests__/integration/UserProfile.test.tsx +0 -124
  690. package/src/__tests__/public-recipe-view.test.ts +0 -228
  691. package/src/__tests__/rls-policies.test.ts +0 -472
  692. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
  693. package/src/components/DataTable/components/DataTableLayout.tsx +0 -584
  694. package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -395
  695. package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +0 -467
  696. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -358
  697. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -957
  698. package/src/components/DataTable/core/ActionManager.ts +0 -235
  699. package/src/components/DataTable/core/ColumnManager.ts +0 -204
  700. package/src/components/DataTable/core/DataManager.ts +0 -190
  701. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
  702. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  703. package/src/components/DataTable/core/StateManager.ts +0 -312
  704. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -235
  705. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -141
  706. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -178
  707. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -133
  708. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -142
  709. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -158
  710. package/src/components/DataTable/core/interfaces.ts +0 -338
  711. package/src/components/DataTable/types.ts +0 -764
  712. package/src/hooks/public/usePublicFileDisplay.ts +0 -534
  713. package/src/hooks/useFileDisplay.ts +0 -748
  714. package/src/providers/OrganisationProvider.test.tsx +0 -40
  715. package/src/providers/OrganisationProvider.tsx +0 -92
  716. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
  717. package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -616
  718. package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +0 -591
  719. package/src/rbac/__tests__/cache-invalidation.test.ts +0 -393
  720. /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
  721. /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
  722. /package/src/hooks/{__tests__/useApiFetch.unit.test.ts → useApiFetch.unit.test.ts} +0 -0
  723. /package/src/providers/{__tests__/README.md → README.md} +0 -0
  724. /package/src/rbac/{__tests__/index.test.ts → index.test.ts} +0 -0
  725. /package/src/rbac/{__tests__/rbac-integration.test.ts → rbac-integration.test.ts} +0 -0
  726. /package/src/types/{__tests__/README.md → README.md} +0 -0
@@ -146,7 +146,7 @@ Documented in [RBAC API Reference](../rbac/api-reference.md):
146
146
  **Data Access (RBAC-protected):**
147
147
  - `data_user_organisations_get` - Get all organisations for a user
148
148
  - `data_user_organisation_roles_get` - Get user roles in organisations
149
- - `get_organisation_members` - (exception to naming standard) Returns distinct active organisation role assignments for dashboard statistics. Enforces `check_user_organisation_access` so only super admins or organisation members can call it.
149
+ - `data_rbac_roles_list` - List all roles (global, organisation, event-app) for a user. **Explicit parameters are the source of truth:** the function uses only `p_user_id`, `p_organisation_id`, `p_event_id`, `p_app_id`; it does **not** use `x-organisation-id` or request/session org. RLS on `rbac_organisation_roles` and `rbac_event_app_roles` uses caller identity (JWT) via `app.current_user_id` set by the RPC. **Note:** This RPC returns roles for **one** user (the caller when `p_user_id` is null, or the given `p_user_id`). It does **not** return `user_id` and does **not** support "list all users in org X". For that, see "User list for one organisation" below.
150
150
  - `data_user_events_get` - Get events accessible to a user
151
151
  - `data_cake_meals_get` - Get cake meals for an event (application-specific, RBAC-protected)
152
152
 
@@ -168,6 +168,16 @@ Documented in [RBAC API Reference](../rbac/api-reference.md):
168
168
 
169
169
  **Note**: For public event access, use `usePublicEvent()` hook from pace-core, which handles direct table queries internally.
170
170
 
171
+ ### User list for one organisation
172
+
173
+ Apps that need to show **all users (or user IDs) in a given organisation** have two options:
174
+
175
+ 1. **Direct query (recommended):** Query the `rbac_organisation_roles` table with a filter on `organisation_id`. Use the secure client from `useSecureSupabase()`. When the "current org" is derived from the URL (e.g. `/users?org=scouts-victoria`), ensure the secure client has that organisation context for the request (e.g. keep `selectedOrganisation` in sync with the URL, or use a client created with that org via `withContext({ organisationId: urlOrgId })`). The caller must have access to that org (or be a super admin). Select distinct `user_id` (and optionally `role`, etc.) as needed.
176
+
177
+ 2. **Alternative:** If pace-core adds a dedicated RPC that returns `(user_id, role, ...)` for a given `p_organisation_id`, use that and pass the org ID explicitly; such an RPC would use only explicit parameters and caller auth/RLS.
178
+
179
+ **Not supported:** Calling `data_rbac_roles_list` with only `p_organisation_id` does **not** return "all users in the org". It returns the **caller's** roles in that org (when `p_user_id` is null), and the return type has no `user_id` column.
180
+
171
181
  ## Removed Legacy RPC Functions
172
182
 
173
183
  The following RPC functions have been **removed** in v0.6.x. All consuming apps have been migrated to modern alternatives.
@@ -233,8 +243,7 @@ These functions are used internally by pace-core and should **NOT** be called di
233
243
  - ~~`get_organisation_context`~~ - **REMOVED** - No longer needed
234
244
  - ~~`get_page_scope_type`~~ - **REMOVED** - Replaced with direct table queries
235
245
 
236
- **Active Functions** (pace-core internal, do not call directly):
237
- - `grant_event_app_role` - Used by `useRoleManagement` hook (use hook instead)
246
+ **Event-app role grants:** Use `rbac_role_grant` with `p_role_type: 'event_app'` and `p_context_id: '<event_id>:<app_id>'`. The `useRoleManagement().grantEventAppRole` hook calls this RPC.
238
247
 
239
248
  **Note**: The removed functions have been replaced with direct table queries or are no longer needed. Organisation context is automatically handled by the secure Supabase client from `useSecureSupabase()` hook.
240
249
 
@@ -236,6 +236,14 @@ SELECT rbac_role_grant(
236
236
 
237
237
  For complete documentation on role management functions, see **[Role Management Functions](../rbac/role-management-functions.md)**.
238
238
 
239
+ ### Required migrations for role management
240
+
241
+ Granting roles (including event-app roles) requires the **`rbac_role_grant`** RPC to exist in the database. The Supabase project must have the migration that creates or updates this function applied.
242
+
243
+ - **Migration:** `20260109112708_fix_rbac_role_grant_reactivate_inactive_roles.sql` (or a later migration that defines `public.rbac_role_grant`).
244
+ - **Symptom:** If `POST …/rest/v1/rpc/rbac_role_grant` returns **404**, the function is missing — apply pending Supabase migrations to the project.
245
+ - Consuming apps (e.g. pace-admin) that use `useRoleManagement().grantEventAppRole` call this RPC; ensure the project’s migrations are applied before using role grant features.
246
+
239
247
  ## RBAC Compliance & Recent Changes
240
248
 
241
249
  ### Database-Driven Permissions
@@ -18,26 +18,21 @@ npm install @jmruthers/pace-core
18
18
 
19
19
  ### Step 2: Install Cursor Rules
20
20
 
21
- Run the installation script from your app root:
21
+ Run the combined setup script from your app root:
22
22
 
23
23
  ```bash
24
- node node_modules/@jmruthers/pace-core/scripts/install-cursor-rules.cjs
24
+ npm run setup
25
25
  ```
26
26
 
27
- Or add to your `package.json`:
27
+ This will install:
28
+ - Cursor rules for AI-assisted enforcement
29
+ - ESLint configuration for real-time linting
30
+ - Standards documentation to `docs/standards/`
28
31
 
29
- ```json
30
- {
31
- "scripts": {
32
- "setup:cursor-rules": "node node_modules/@jmruthers/pace-core/scripts/install-cursor-rules.cjs"
33
- }
34
- }
35
- ```
36
-
37
- Then run:
32
+ Or to force update existing configs:
38
33
 
39
34
  ```bash
40
- npm run setup:cursor-rules
35
+ npm run setup -- --force
41
36
  ```
42
37
 
43
38
  The script will:
@@ -131,18 +126,20 @@ Content with examples and guidelines.
131
126
 
132
127
  ### Compliance Check
133
128
 
134
- For a quick compliance check:
129
+ For full validation including the pace-core audit:
135
130
 
136
131
  ```bash
137
- node node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs
132
+ npm run validate
138
133
  ```
139
134
 
135
+ Review `audit/<timestamp>-pace-core-audit.md` for pace-core compliance and other standards.
136
+
140
137
  ## Updating Rules
141
138
 
142
- When pace-core is updated, run the installation script again:
139
+ When pace-core is updated, run the setup script again:
143
140
 
144
141
  ```bash
145
- npm run setup:cursor-rules
142
+ npm run setup
146
143
  ```
147
144
 
148
145
  The script will:
@@ -155,7 +152,7 @@ The script will:
155
152
  To force update all rules (even when versions match):
156
153
 
157
154
  ```bash
158
- node node_modules/@jmruthers/pace-core/scripts/install-cursor-rules.cjs --force
155
+ npm run setup -- --force
159
156
  ```
160
157
 
161
158
  **Note**: Normally, pace-core rules are automatically updated when they change. The `--force` flag forces an update even when versions match (useful if content changed but version metadata wasn't updated).
@@ -210,7 +207,7 @@ Each app maintains its own `.cursor/rules/` directory.
210
207
  1. **Initial Setup:**
211
208
  ```bash
212
209
  npm install @jmruthers/pace-core
213
- npm run setup:cursor-rules
210
+ npm run setup
214
211
  ```
215
212
 
216
213
  2. **Daily Development:**
@@ -225,7 +222,7 @@ Each app maintains its own `.cursor/rules/` directory.
225
222
  4. **After pace-core Updates:**
226
223
  ```bash
227
224
  npm update @jmruthers/pace-core
228
- npm run setup:cursor-rules
225
+ npm run setup
229
226
  ```
230
227
 
231
228
  ## Related Documentation
@@ -48,7 +48,7 @@ reviewedBy: dependency-clarity-audit
48
48
  - Validation runs automatically before publishing via `prepublishOnly` hook
49
49
 
50
50
  **For consuming apps:**
51
- - Use the audit tool (`npm run audit:pace-core`) to check your dependencies
51
+ - Use the pace-core Audit step in `npm run validate` to check your dependencies
52
52
  - The audit tool reads the current `package.json` from the installed pace-core package
53
53
  - Version requirements shown by the audit tool come directly from `package.json`
54
54
 
@@ -0,0 +1,235 @@
1
+ # pace-core Setup Guide
2
+
3
+ This guide explains how to set up pace-core in your consuming app with a single command.
4
+
5
+ ## Quick Start
6
+
7
+ After installing `@jmruthers/pace-core`, run:
8
+
9
+ ```bash
10
+ npm run setup
11
+ ```
12
+
13
+ This single command will:
14
+ - ✅ Set up ESLint configuration for real-time compliance checking
15
+ - ✅ Install Cursor rules for AI-assisted enforcement
16
+ - ✅ Copy standards documentation to `docs/standards/`
17
+
18
+ ## Installation
19
+
20
+ ### Step 1: Install pace-core
21
+
22
+ ```bash
23
+ npm install @jmruthers/pace-core
24
+ ```
25
+
26
+ ### Step 2: Add Setup Scripts to package.json
27
+
28
+ **Important:** Add the setup and validate scripts to your consuming app's `package.json`. Do NOT create local script files.
29
+
30
+ ```json
31
+ {
32
+ "scripts": {
33
+ "setup": "node node_modules/@jmruthers/pace-core/scripts/setup.cjs",
34
+ "validate": "node node_modules/@jmruthers/pace-core/scripts/validate.cjs"
35
+ }
36
+ }
37
+ ```
38
+
39
+ **Note:** These scripts come from the `@jmruthers/pace-core` package, not from your local project. Make sure you're pointing to `node_modules/@jmruthers/pace-core/scripts/`.
40
+
41
+ ### Step 3: Run Setup
42
+
43
+ ```bash
44
+ npm run setup
45
+ ```
46
+
47
+ That's it! All pace-core tools are now configured.
48
+
49
+ ### Step 4: Run Validation (Optional)
50
+
51
+ After setup, you can run quick validation checks:
52
+
53
+ ```bash
54
+ npm run validate
55
+ ```
56
+
57
+ This runs (in order, when the corresponding script exists):
58
+ - **Type check** – summary in terminal
59
+ - **Lint** – summary in terminal, full output in `audit/<timestamp>-eslint-report.md`
60
+ - **Build** – summary in terminal
61
+ - **Tests** – summary in terminal (runs `test:coverage` if present, otherwise `test`; add `test:coverage` to generate `coverage/index.html`)
62
+ - **pace-core Audit** – standards audit; report in `audit/<timestamp>-pace-core-audit.md`
63
+
64
+ Reports are written to the `audit/` directory. To get a coverage report during validate, add a `test:coverage` script to your `package.json` (e.g. with Vitest: `vitest run --coverage`).
65
+
66
+ ## What Gets Set Up
67
+
68
+ ### 1. ESLint Configuration
69
+
70
+ The setup script automatically:
71
+ - Finds your ESLint config file (supports `.js`, `.cjs`, `.mjs`, `.json`, `.yaml`, `.yml`)
72
+ - Adds pace-core ESLint rules to your config
73
+ - Creates a backup of your existing config
74
+ - Handles both ES modules and CommonJS formats
75
+ - Supports `tseslint.config()` wrapper
76
+
77
+ ### 2. Cursor Rules
78
+
79
+ The setup script:
80
+ - Creates `.cursor/rules/` directory if it doesn't exist
81
+ - Copies all pace-core rules (00-09) to your project
82
+ - **Automatically updates** pace-core rules when they change
83
+ - Preserves your custom rules (50+)
84
+ - Skips files that are already up to date
85
+
86
+ ### 3. Standards Documentation
87
+
88
+ The setup script:
89
+ - Copies `packages/core/docs/standards/` to `docs/standards/` in your app
90
+ - Provides offline access to all pace-core standards
91
+ - Updates when you run setup again
92
+
93
+ ## Force Update
94
+
95
+ To force update all configurations (overwrites existing):
96
+
97
+ ```bash
98
+ npm run setup -- --force
99
+ ```
100
+
101
+ Use this when:
102
+ - You want to update to the latest pace-core rules
103
+ - Your ESLint config needs to be regenerated
104
+ - You want to refresh the standards documentation
105
+
106
+ ## Manual Setup
107
+
108
+ The setup script handles all three tasks (ESLint, Cursor rules, and standards docs) in one command. There are no separate scripts for individual components - use `npm run setup` for everything.
109
+
110
+ ## Verification
111
+
112
+ After running setup, verify everything is working:
113
+
114
+ ### Run Validation
115
+
116
+ The easiest way to verify everything is working:
117
+
118
+ ```bash
119
+ npm run validate
120
+ ```
121
+
122
+ This runs all available checks (type-check, lint, tests, pace-core audit).
123
+
124
+ ### Manual Verification
125
+
126
+ You can also check individual components:
127
+
128
+ **Check ESLint:**
129
+ ```bash
130
+ npm run lint
131
+ ```
132
+
133
+ **Check Cursor Rules:**
134
+ 1. Restart Cursor
135
+ 2. Open a file that matches the rule patterns
136
+ 3. Rules should be automatically loaded
137
+
138
+ **Check Standards:**
139
+ ```bash
140
+ ls docs/standards/
141
+ ```
142
+
143
+ You should see all the standards markdown files.
144
+
145
+ ## Troubleshooting
146
+
147
+ ### Error: Cannot find module 'scripts/setup.cjs'
148
+
149
+ **Problem:** Your `package.json` has a `setup` script pointing to a local file that doesn't exist:
150
+ ```json
151
+ {
152
+ "scripts": {
153
+ "setup": "node scripts/setup.cjs" // ❌ WRONG - This file doesn't exist in consuming apps
154
+ }
155
+ }
156
+ ```
157
+
158
+ **Solution:** Update your `package.json` to use the script from the pace-core package:
159
+ ```json
160
+ {
161
+ "scripts": {
162
+ "setup": "node node_modules/@jmruthers/pace-core/scripts/setup.cjs" // ✅ CORRECT
163
+ }
164
+ }
165
+ ```
166
+
167
+ **Important:** The setup script comes from `@jmruthers/pace-core`, not from your local project. You should NOT create a local `scripts/setup.cjs` file.
168
+
169
+ ### Setup Script Not Found
170
+
171
+ If you get an error that the script can't be found:
172
+
173
+ 1. Verify pace-core is installed:
174
+ ```bash
175
+ npm list @jmruthers/pace-core
176
+ ```
177
+
178
+ 2. Check the script path:
179
+ ```bash
180
+ ls node_modules/@jmruthers/pace-core/scripts/setup.cjs
181
+ ```
182
+
183
+ 3. If the file doesn't exist, you may need to update pace-core:
184
+ ```bash
185
+ npm update @jmruthers/pace-core
186
+ ```
187
+
188
+ 4. Make sure your `package.json` script points to `node_modules/@jmruthers/pace-core/scripts/setup.cjs`, not a local `scripts/setup.cjs`
189
+
190
+ ### ESLint Config Issues
191
+
192
+ If ESLint setup fails:
193
+
194
+ 1. Check your ESLint config file exists
195
+ 2. Try with `--force` flag:
196
+ ```bash
197
+ npm run setup -- --force
198
+ ```
199
+ 3. Check the backup file created (`.backup.{timestamp}`)
200
+ 4. See [ESLint Setup Troubleshooting](../standards/1-pace-core-compliance-standards.md#eslint-setup-issues)
201
+
202
+ ### Cursor Rules Not Loading
203
+
204
+ 1. Verify rules are in `.cursor/rules/` directory
205
+ 2. Check file extensions are `.mdc`
206
+ 3. Restart Cursor
207
+ 4. Check rule frontmatter is valid YAML
208
+
209
+ ### Standards Not Copied
210
+
211
+ If standards aren't copied:
212
+
213
+ 1. Check pace-core package has docs:
214
+ ```bash
215
+ ls node_modules/@jmruthers/pace-core/docs/standards/
216
+ ```
217
+ 2. Try with `--force` flag:
218
+ ```bash
219
+ npm run setup -- --force
220
+ ```
221
+
222
+ ## Next Steps
223
+
224
+ After setup:
225
+
226
+ 1. **Restart Cursor** to load the new rules
227
+ 2. **Run validation**: `npm run validate` (type-check, lint, build, tests, pace-core audit; reports in `audit/`)
228
+ 3. **Review standards** in `docs/standards/` for complete documentation
229
+
230
+ ## Related Documentation
231
+
232
+ - [Cursor Rules Guide](./cursor-rules.md) - Using Cursor rules effectively
233
+ - [Standards Documentation](../standards/README.md) - Complete standards reference
234
+ - [pace-core Compliance](../standards/1-pace-core-compliance-standards.md) - Compliance requirements
235
+ - [Local Development](./local-development.md) - Using pace-core locally
@@ -263,6 +263,22 @@ function App() {
263
263
 
264
264
  **Important:** The `ProtectedRoute` component solves the common chicken-and-egg problem where apps check for `selectedEvent` before rendering, which blocks the event selector (typically in the `PaceAppLayout` header) from being visible. The component allows rendering when events exist but none is selected, enabling users to see and use the event selector dropdown.
265
265
 
266
+ ### Critical: Auth routing pattern
267
+
268
+ To avoid "login succeeds but redirect doesn't happen" or the login form resetting after submit, follow this pattern:
269
+
270
+ - **MUST** use a single public `/login` route and wrap all other routes in **ProtectedRoute**. Do not wrap the whole app in a custom "auth gate" that redirects when `!isAuthenticated`.
271
+ - **MUST NOT** wrap `<Routes>` in a component that, when `!isAuthenticated`, renders `<Navigate to="/login" />` for non-login paths. That races with post-login context updates and can send the user back to the login page with a reset form.
272
+ - **SHOULD** avoid `BrowserRouter` `future: { v7_startTransition: true, v7_relativeSplatPath: true }` until compatibility with auth context updates is verified; use plain `<BrowserRouter>`.
273
+
274
+ See [Redirect not happening after login](#1-login-not-working) in Troubleshooting if you see this behaviour.
275
+
276
+ **Auth and routing checklist (new apps):**
277
+ - [ ] `/login` is a public route; all other routes are under `<Route element={<ProtectedRoute />}>` (or `requireEvent={false}` variant).
278
+ - [ ] No wrapper component that redirects to `/login` when `!isAuthenticated` for the whole app.
279
+ - [ ] `BrowserRouter` used without `future` flags (or login and logout verified if using them).
280
+ - [ ] Verify login and logout in the app after setup.
281
+
266
282
  ## Configuration Options
267
283
 
268
284
  ### UnifiedAuthProvider Props
@@ -801,6 +817,7 @@ function App() {
801
817
  - [ ] User credentials are valid in Supabase
802
818
  - [ ] Network connectivity working
803
819
  - [ ] Browser not blocking cookies
820
+ - [ ] **Auth routing pattern**: You use a public `/login` route and wrap other routes in `ProtectedRoute`; you do not use a global auth gate that redirects to `/login` when `!isAuthenticated`. See [Critical: Auth routing pattern](#critical-auth-routing-pattern) above.
804
821
 
805
822
  #### 2. Session Not Persisting
806
823
 
@@ -858,6 +875,16 @@ function AuthTest() {
858
875
  }
859
876
  ```
860
877
 
878
+ #### 4. Logout does nothing / 403 on logout
879
+
880
+ **Symptoms:**
881
+ - Logout button does nothing; user stays on the app
882
+ - Network tab shows `POST .../auth/v1/logout` returning 403
883
+
884
+ **Cause:** Supabase sign-out with default (global) scope can return 403 in some environments (e.g. cookie domain, CORS). pace-core handles this by clearing local auth state and calling `signOut({ scope: 'local' })`, so the UI should still show the user as logged out and redirect to login.
885
+
886
+ **If logout still does nothing:** Check cookie domain and CORS for your Supabase project and app origin. The app should still clear local state; if it does not, ensure you are on a version of pace-core that includes the signOut error-handling fix.
887
+
861
888
  ### Detailed Solutions
862
889
 
863
890
  #### Wrong Supabase Configuration
@@ -38,6 +38,10 @@ The PACE Core DataTable is an enterprise-grade data table component built on Tan
38
38
  >
39
39
  > The component uses pace-core's internal toast system to provide consistent user feedback. Your `onDeleteRow`, `onDeleteSelected`, `onImport`, and `onExport` handlers should focus on the data operations themselves - the UI feedback is handled for you.
40
40
 
41
+ ### Bulk delete confirmation
42
+
43
+ When `deleteSelected` is enabled, a **confirmation dialog** is shown by pace-core before the app's `onDeleteSelected` is called. The dialog displays the number of selected rows and warns that the action cannot be undone. You do not need to show your own confirmation (e.g. `window.confirm`) for the same bulk-delete action. If your app has additional, domain-specific warnings (e.g. "this will also delete related diners and menus"), you may show those after the user has confirmed in the pace-core dialog.
44
+
41
45
  ### Audit Logging
42
46
 
43
47
  > **ℹ️ Audit Logging**: The DataTable component **does NOT** automatically create audit entries for CRUD operations. Audit logging must be handled by either:
@@ -1985,6 +1989,47 @@ When `export: true` and `import: true` are enabled in features, the DataTable au
1985
1989
  - Case-insensitive header matching
1986
1990
  - Supports both display names and field names
1987
1991
 
1992
+ #### Import result contract (required for correct modal summary)
1993
+
1994
+ For the Import modal to show accurate success/failed counts, your `onImport` handler **must return** a result in the standard shape. The modal only recognises this contract; it does not accept app-specific or RPC-specific shapes.
1995
+
1996
+ **Standard shape** (exported as `ImportSummary` from `@jmruthers/pace-core`):
1997
+
1998
+ ```ts
1999
+ interface ImportSummary {
2000
+ successCount: number; // number of rows imported successfully
2001
+ totalCount: number; // total rows in this chunk (or full import)
2002
+ failedCount: number; // number of rows that failed
2003
+ failedRows?: Array<{ row: number; reason: string }>; // optional details for failed rows
2004
+ }
2005
+ ```
2006
+
2007
+ **Return type**: `onImport` may return `void`, `Promise<void>`, `ImportSummary`, or `Promise<ImportSummary>`. The layout passes your handler's return value through to the modal. If you return anything other than a valid `ImportSummary` (including returning nothing), the modal treats the chunk as fully failed and shows incorrect counts (e.g. 0 successful, all rows failed). For accurate counts and failure details, you **must** return `ImportSummary` per chunk.
2008
+
2009
+ **Guidance for consuming apps**:
2010
+
2011
+ 1. **Return `ImportSummary` from your handler.** After your import logic runs (RPC, API, or local), map the result into `ImportSummary` and return it.
2012
+ 2. **Chunking**: The DataTable calls `onImport` once per chunk. Return a summary **per chunk** (e.g. `successCount` and `totalCount` for that chunk). The modal merges chunk results automatically.
2013
+ 3. **Mapping from RPC/app shapes**: If your RPC returns e.g. `{ imported: 48, failed: 0 }` or `{ importedDiners: 100, totalRowsProcessed: 100, skippedRows: [] }`, map it before returning:
2014
+
2015
+ ```ts
2016
+ import type { ImportSummary } from '@jmruthers/pace-core';
2017
+
2018
+ onImport={async (chunk) => {
2019
+ const result = await myRpcOrImport(chunk); // your app-specific result
2020
+ return {
2021
+ successCount: result.imported ?? result.importedDiners ?? 0,
2022
+ totalCount: result.totalRowsProcessed ?? chunk.length,
2023
+ failedCount: result.failed ?? result.skippedRows?.length ?? 0,
2024
+ failedRows: result.skippedRows?.map(({ row, reason }) => ({ row, reason })),
2025
+ } satisfies ImportSummary;
2026
+ }}
2027
+ ```
2028
+
2029
+ 4. **Do not return** app-specific shapes (e.g. `importedUnits`, `importedDiners`, RPC table rows) and expect the modal to interpret them. Always map to `ImportSummary` at the boundary.
2030
+ 5. **Populate `failedRows` from validation and RPC.** Include exact failure reasons from your validation (e.g. "Could not find meal for date X, type Y for the selected event") and from the database/RPC (e.g. per-row error messages). The modal displays these as-is so users can pinpoint issues. Do not replace or correct the summary after the fact; the only source of truth is what your handler returns per chunk.
2031
+ 6. **Reject invalid rows in validation.** If some rows would be inserted but not visible (e.g. due to event or RLS), reject them in validation with a clear reason so they appear in `failedRows` instead of being inserted and then missing from the list.
2032
+
1988
2033
  ### Export/Import with Reference Fields
1989
2034
 
1990
2035
  For columns that display related data (using `accessorFn` with `editAccessorKey`), the export includes both the display value and the ID value for seamless round-trip import/export.
@@ -2074,7 +2119,135 @@ The import automatically recognizes and maps:
2074
2119
  />
2075
2120
  ```
2076
2121
 
2077
- > **📚 Import Function Guide**: For detailed guidance on implementing performant, reliable `onImport` handlers, see the [DataTable Import Function Guide](./data-table-import-guide.md). This guide covers batch operations, error handling, validation, performance optimization, and best practices for large imports.
2122
+ > **📚 Import result contract**: Ensure your `onImport` handler returns [ImportSummary](#import-result-contract-required-for-correct-modal-summary) so the modal shows correct success/failed counts. Map RPC or app-specific results to that shape at the boundary.
2123
+
2124
+ #### Using Bulk Import RPCs
2125
+
2126
+ For large imports (100+ rows), use bulk import RPC functions for better performance. CAKE app provides bulk import RPCs that use `SECURITY DEFINER` and automatically retrieve the authenticated user via `auth.uid()`.
2127
+
2128
+ **Benefits:**
2129
+ - No session timeout issues during long imports (user authentication never expires mid-call)
2130
+ - Simplified client code (no need to manage user session state)
2131
+ - Better performance (single upfront permission check instead of per-row RLS, 60-70% faster)
2132
+ - User-friendly error messages
2133
+
2134
+ **Example: Bulk Import Mealplans**
2135
+
2136
+ ```tsx
2137
+ import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
2138
+ import type { ImportSummary } from '@jmruthers/pace-core';
2139
+
2140
+ function MealplansTable() {
2141
+ const supabase = useSecureSupabase();
2142
+ const { selectedOrganisation } = useOrganisations();
2143
+ const { selectedEvent } = useEvents();
2144
+
2145
+ const handleImport = async (importedData: any[]): Promise<ImportSummary> => {
2146
+ // No need to check user session - auth.uid() handles it automatically
2147
+ const { data, error } = await supabase.rpc('app_cake_mealplans_bulk_import', {
2148
+ p_mealplans_data: importedData,
2149
+ p_organisation_id: selectedOrganisation.id,
2150
+ p_event_id: selectedEvent?.id // Optional
2151
+ });
2152
+
2153
+ if (error) {
2154
+ // Error messages are user-friendly and specific
2155
+ toast.error(error.message);
2156
+ return {
2157
+ successCount: 0,
2158
+ totalCount: importedData.length,
2159
+ failedCount: importedData.length,
2160
+ };
2161
+ }
2162
+
2163
+ const result = data[0];
2164
+ return {
2165
+ successCount: result.imported,
2166
+ totalCount: importedData.length,
2167
+ failedCount: result.failed,
2168
+ failedRows: result.errors ? JSON.parse(result.errors as string) : [],
2169
+ };
2170
+ };
2171
+
2172
+ return (
2173
+ <DataTable
2174
+ data={mealplans}
2175
+ columns={columns}
2176
+ features={{ import: true }}
2177
+ onImport={handleImport}
2178
+ rbac={{ pageName: 'units' }} // Mealplans managed through units
2179
+ />
2180
+ );
2181
+ }
2182
+ ```
2183
+
2184
+ **Available Bulk Import RPCs:**
2185
+
2186
+ | RPC Function | Purpose | Permission Required |
2187
+ |-------------|---------|---------------------|
2188
+ | `app_cake_mealplans_bulk_import` | Bulk import mealplans | `create:page.units` |
2189
+ | `app_cake_units_bulk_import` | Bulk import units | `create:page.units` |
2190
+ | `app_cake_diners_bulk_import` | Bulk import diners | `create:page.units` |
2191
+ | `app_cake_meals_bulk_import` | Bulk import meals | `create:page.meals` |
2192
+ | `app_cake_mealplan_bulk_delete` | Bulk delete mealplans for a unit | `delete:page.units` |
2193
+
2194
+ **RPC Parameters (all bulk import functions):**
2195
+
2196
+ - `p_[resource]_data` (required): JSONB array of records to import
2197
+ - `p_organisation_id` (required): Organisation context UUID
2198
+ - `p_event_id` (optional): Event context for additional validation
2199
+
2200
+ **Note:** You do **not** need to pass `p_user_id` - authentication is handled automatically via the JWT token in the request. The RPC will:
2201
+ 1. Verify user is authenticated
2202
+ 2. Check user has access to the organisation
2203
+ 3. Verify user has the required permission
2204
+ 4. Perform the bulk import if all checks pass
2205
+
2206
+ This eliminates session timeout issues and simplifies client code.
2207
+
2208
+ ##### Menus import: why some rows don't appear in the list
2209
+
2210
+ The menus list is driven by `data_cake_mealplans_list`, which **filters by event**: it only returns mealplans whose meal's `meal_event_id` matches the **selected event**. If your import handler resolves (Meal Date, Meal Type) to a `meal_id` from a **different event** (e.g. same org, same date/type in another event), those rows are inserted successfully but **never shown** in the list, so the UI shows fewer rows than the import count.
2211
+
2212
+ **Required:** When building the payload for `app_cake_mealplans_bulk_import`, resolve `meal_id` using **the selected event**: e.g. look up meal by `(event_id, meal_date, meal_type)` (or equivalent), not by `(meal_date, meal_type)` alone. That way every imported row uses a meal for the current event and will appear in the list.
2213
+
2214
+ **To identify which rows are "missing" (inserted but not visible):**
2215
+
2216
+ 1. **CSV diagnosis:** Run `node scripts/diagnose-menus-import.js "<path-to-menus.csv>"` to confirm row count and check for duplicate (Unit Number, Meal Date, Meal Type, Dish Code) keys.
2217
+ 2. **DB diagnosis:** In Supabase SQL Editor, run the query in `scripts/sql/mealplans_not_visible_for_event.sql` after replacing `YOUR_EVENT_ID` and the unit_ids array. It returns mealplans for those units whose meal is not in the selected event (the difference between import count and list count).
2218
+
2219
+ **Troubleshooting: rows reported as failed (e.g. "Could not find meal" or "Unit not found")**
2220
+
2221
+ The import only uses **units, meals and dishes that belong to the event currently selected** in the page header. If the failed-rows table shows reasons like "Could not find meal for date X, type Y for the selected event" or "Unit N not found for the selected event", then:
2222
+
2223
+ 1. **Confirm the event** – Ensure the correct event is selected in the header before starting the import. The same unit number (e.g. 115) or meal (same date and type) can exist under different events; the import only sees data for the selected event.
2224
+ 2. **Match CSV to that event** – The CSV Unit Number must match `cake_unit.unit_number` for a unit that has `unit_event_id` = selected event. Meals and dishes are matched by `meal_event_id` / `dish_event_id` = selected event. If the CSV was exported from another event, re-export for the selected event or switch event to match the CSV.
2225
+ 3. **Meal date and type** – Meal is matched by date (parsed from the CSV Meal Date column, e.g. DD/MM/YYYY → YYYY-MM-DD), meal type name (case-insensitive, from Meal Type column), and event. Ensure the meal exists for that exact date and type for the selected event.
2226
+ 4. **Dish code** – Dish is matched by code (Dish Code column) and event. Check for typos or extra spaces; the code must exist for the selected event.
2227
+
2228
+ #### Advanced Import Configuration
2229
+
2230
+ The DataTable import feature supports configuration through the `importModalConfig` prop to customize modal text only. The summary shown in the modal is the merge of the `ImportSummary` values returned by your `onImport` handler per chunk; do not correct or replace it after the fact.
2231
+
2232
+ ##### Available Configuration Options
2233
+
2234
+ ```tsx
2235
+ interface ImportModalConfig {
2236
+ title?: string;
2237
+ description?: string;
2238
+ uploadText?: string;
2239
+ selectFileButtonText?: string;
2240
+ importButtonText?: string;
2241
+ importButtonProcessingText?: string;
2242
+ cancelButtonText?: string;
2243
+ previewHeaderText?: string;
2244
+ totalRowsText?: string; // Use {count} as placeholder
2245
+ /** When true, send the entire file in one chunk. Required for handlers that delete-then-insert per unit/entity (e.g. menus), so later chunks do not overwrite earlier ones. */
2246
+ singleChunk?: boolean;
2247
+ }
2248
+ ```
2249
+
2250
+ **Menus import:** Use `singleChunk: true` for menus (mealplans) import. The handler deletes all mealplans for each unit then inserts the chunk's rows; with multiple chunks, later chunks would delete and replace earlier chunks' data for the same unit, so the reported count would be wrong and many rows would be missing. With `singleChunk: true`, the whole file is sent in one call and the summary matches the actual result.
2078
2251
 
2079
2252
  ### Custom Export
2080
2253
 
@@ -2460,7 +2633,7 @@ function UserForm({ user, onSubmit, onCancel }) {
2460
2633
  <button
2461
2634
  type="submit"
2462
2635
  disabled={isSubmitting}
2463
- className="px-4 py-2 bg-main-600 text-white rounded hover:bg-main-700 disabled:opacity-50"
2636
+ className="px-4 py-2 bg-main-600 text-main-50 rounded hover:bg-main-700 disabled:opacity-50"
2464
2637
  >
2465
2638
  {isSubmitting ? 'Saving...' : 'Save'}
2466
2639
  </button>
@@ -2515,7 +2688,7 @@ function UserForm({ user, onSubmit, onCancel }) {
2515
2688
 
2516
2689
  #### 7. Delete selected rows not working
2517
2690
  - **Check feature configuration**: Ensure `features={{ selection: true, deletion: true, deleteSelected: true }}`
2518
- - **Provide onDeleteSelected callback**: Implement the callback to handle bulk deletion
2691
+ - **Provide onDeleteSelected callback**: Implement the callback to handle bulk deletion. A confirmation dialog is shown by pace-core before your handler is called; do not add a separate confirm step for the same action.
2519
2692
  - **Verify getRowId function**: Ensure you provide a `getRowId` function that returns unique IDs
2520
2693
  - **Check button visibility**: The delete button only appears when all three features are enabled and rows are selected
2521
2694
  - **Debug selection state**: Add console logs to verify `onRowSelectionChange` is being called with correct data
@@ -0,0 +1,25 @@
1
+ # ApiResult migration
2
+
3
+ Async API-style functions in `@jmruthers/pace-core` now return a consistent **`ApiResult<T>`** shape instead of throwing or returning raw values. This document points to the CHANGELOG and standards for the type and migration.
4
+
5
+ ## Summary
6
+
7
+ - **Type**: `ApiResult<T> = { ok: true; data: T } | { ok: false; error: ApiError }`
8
+ - **Error type**: `ApiError = { code: string; message: string; details?: object }`
9
+ - **Helpers**: `ok(data)`, `err(error)`, `isOk(result)`, `isErr(result)` — exported from the package.
10
+
11
+ ## Where to look
12
+
13
+ 1. **CHANGELOG** — [packages/core/CHANGELOG.md](../../CHANGELOG.md) (Unreleased → Breaking Changes → “Async API-style functions now return ApiResult<T>”) for the list of affected surfaces and a short before/after.
14
+ 2. **Standards** — [7-api-tech-stack-standards.md](../standards/7-api-tech-stack-standards.md) and [3-architecture-standards.md](../standards/3-architecture-standards.md) for the ApiResult contract and usage.
15
+
16
+ ## Affected surfaces
17
+
18
+ - RBAC (e.g. `isPermitted`, `getAccessLevel`, audit, eventContext)
19
+ - Auth (auth-utils, `IAuthService` / `AuthService`)
20
+ - File-reference service and storage helpers (`extractFileMetadata`, `getSignedUrl`, `listFiles`, `downloadFile`, `generateFileUrlsBatch`, etc.)
21
+ - Context and app utilities (`organisationContext`, `appIdResolver`)
22
+ - Google Places and CSRF
23
+ - Security (`validateUserSession`, etc.)
24
+
25
+ At each call site, check `result.ok` and use `result.data` or `result.error` accordingly.