@jmruthers/pace-core 0.5.121 → 0.5.123

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 (254) hide show
  1. package/dist/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
  2. package/dist/{DataTable-DGZDJUYM.js → DataTable-WTS4IRF2.js} +7 -8
  3. package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
  4. package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
  5. package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
  6. package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
  7. package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
  8. package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
  9. package/dist/{chunk-VKOCWWVY.js 3.map → chunk-CX5M4ZAG.js.map} +1 -1
  10. package/dist/{chunk-HFBOFZ3Z.js → chunk-DHMFMXFV.js} +258 -243
  11. package/dist/chunk-DHMFMXFV.js.map +1 -0
  12. package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
  13. package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
  14. package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
  15. package/dist/chunk-GEVIB2UB.js.map +1 -0
  16. package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
  17. package/dist/chunk-IJOZZOGT.js.map +1 -0
  18. package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
  19. package/dist/chunk-M6DDYFUD.js.map +1 -0
  20. package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
  21. package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
  22. package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
  23. package/dist/chunk-XN6GWKMV.js.map +1 -0
  24. package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
  25. package/dist/chunk-ZBLK676C.js.map +1 -0
  26. package/dist/{chunk-QPI2CCBA.js → chunk-ZPJMYGEP.js} +149 -96
  27. package/dist/chunk-ZPJMYGEP.js.map +1 -0
  28. package/dist/components.d.ts +1 -1
  29. package/dist/components.js +11 -11
  30. package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
  31. package/dist/hooks.d.ts +1 -1
  32. package/dist/hooks.js +9 -8
  33. package/dist/hooks.js.map +1 -1
  34. package/dist/index.d.ts +6 -6
  35. package/dist/index.js +19 -17
  36. package/dist/index.js.map +1 -1
  37. package/dist/providers.d.ts +2 -2
  38. package/dist/providers.js +2 -3
  39. package/dist/rbac/index.js +7 -8
  40. package/dist/styles/index.d.ts +1 -1
  41. package/dist/styles/index.js +5 -3
  42. package/dist/theming/runtime.d.ts +73 -1
  43. package/dist/theming/runtime.js +5 -5
  44. package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
  45. package/dist/utils.d.ts +1 -1
  46. package/dist/utils.js +5 -5
  47. package/docs/api/classes/ColumnFactory.md +1 -1
  48. package/docs/api/classes/ErrorBoundary.md +1 -1
  49. package/docs/api/classes/InvalidScopeError.md +1 -1
  50. package/docs/api/classes/MissingUserContextError.md +1 -1
  51. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  52. package/docs/api/classes/PermissionDeniedError.md +1 -1
  53. package/docs/api/classes/PublicErrorBoundary.md +6 -6
  54. package/docs/api/classes/RBACAuditManager.md +1 -1
  55. package/docs/api/classes/RBACCache.md +1 -1
  56. package/docs/api/classes/RBACEngine.md +1 -1
  57. package/docs/api/classes/RBACError.md +1 -1
  58. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  59. package/docs/api/classes/SecureSupabaseClient.md +6 -6
  60. package/docs/api/classes/StorageUtils.md +1 -1
  61. package/docs/api/enums/FileCategory.md +1 -1
  62. package/docs/api/interfaces/AggregateConfig.md +1 -1
  63. package/docs/api/interfaces/ButtonProps.md +1 -1
  64. package/docs/api/interfaces/CardProps.md +1 -1
  65. package/docs/api/interfaces/ColorPalette.md +1 -1
  66. package/docs/api/interfaces/ColorShade.md +1 -1
  67. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  68. package/docs/api/interfaces/DataRecord.md +1 -1
  69. package/docs/api/interfaces/DataTableAction.md +1 -1
  70. package/docs/api/interfaces/DataTableColumn.md +1 -1
  71. package/docs/api/interfaces/DataTableProps.md +1 -1
  72. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  73. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  74. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  75. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  76. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  77. package/docs/api/interfaces/FileMetadata.md +1 -1
  78. package/docs/api/interfaces/FileReference.md +1 -1
  79. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  80. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  81. package/docs/api/interfaces/FileUploadProps.md +1 -1
  82. package/docs/api/interfaces/FooterProps.md +1 -1
  83. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  84. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  85. package/docs/api/interfaces/InputProps.md +1 -1
  86. package/docs/api/interfaces/LabelProps.md +1 -1
  87. package/docs/api/interfaces/LoginFormProps.md +1 -1
  88. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  89. package/docs/api/interfaces/NavigationContextType.md +1 -1
  90. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  91. package/docs/api/interfaces/NavigationItem.md +1 -1
  92. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  93. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  94. package/docs/api/interfaces/Organisation.md +1 -1
  95. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  96. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  97. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  98. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  99. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  100. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  101. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  102. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  103. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  104. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  105. package/docs/api/interfaces/PaletteData.md +1 -1
  106. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  107. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  108. package/docs/api/interfaces/PublicErrorBoundaryProps.md +7 -7
  109. package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
  110. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
  111. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  112. package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
  113. package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
  114. package/docs/api/interfaces/RBACConfig.md +1 -1
  115. package/docs/api/interfaces/RBACLogger.md +1 -1
  116. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  117. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  118. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  119. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  120. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  121. package/docs/api/interfaces/RouteConfig.md +1 -1
  122. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  123. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  124. package/docs/api/interfaces/StorageConfig.md +1 -1
  125. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  126. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  127. package/docs/api/interfaces/StorageListOptions.md +1 -1
  128. package/docs/api/interfaces/StorageListResult.md +1 -1
  129. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  130. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  131. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  132. package/docs/api/interfaces/StyleImport.md +1 -1
  133. package/docs/api/interfaces/SwitchProps.md +1 -1
  134. package/docs/api/interfaces/ToastActionElement.md +1 -1
  135. package/docs/api/interfaces/ToastProps.md +1 -1
  136. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  137. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  138. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  139. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  140. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  141. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  142. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  143. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  144. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  145. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  146. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  147. package/docs/api/interfaces/UserEventAccess.md +1 -1
  148. package/docs/api/interfaces/UserMenuProps.md +1 -1
  149. package/docs/api/interfaces/UserProfile.md +1 -1
  150. package/docs/api/modules.md +140 -30
  151. package/docs/best-practices/README.md +1 -1
  152. package/docs/implementation-guides/datatable-filtering.md +313 -0
  153. package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
  154. package/docs/implementation-guides/hierarchical-datatable.md +850 -0
  155. package/docs/implementation-guides/large-datasets.md +281 -0
  156. package/docs/implementation-guides/performance.md +403 -0
  157. package/docs/implementation-guides/public-pages.md +4 -4
  158. package/docs/migration/quick-migration-guide.md +320 -0
  159. package/docs/rbac/quick-start.md +16 -16
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
  162. package/docs/troubleshooting/debugging.md +1117 -0
  163. package/docs/troubleshooting/migration.md +918 -0
  164. package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
  165. package/examples/public-pages/PublicEventPage.tsx +41 -41
  166. package/examples/public-pages/PublicPageApp.tsx +33 -33
  167. package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
  168. package/package.json +4 -4
  169. package/src/__tests__/hooks/usePermissions.test.ts +265 -0
  170. package/src/components/DataTable/DataTable.test.tsx +9 -38
  171. package/src/components/DataTable/DataTable.tsx +0 -7
  172. package/src/components/DataTable/components/DataTableCore.tsx +66 -136
  173. package/src/components/DataTable/components/DataTableModals.tsx +25 -22
  174. package/src/components/DataTable/components/EditableRow.tsx +118 -42
  175. package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
  176. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
  177. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
  178. package/src/components/DataTable/utils/exportUtils.ts +3 -2
  179. package/src/components/Dialog/Dialog.tsx +1 -1
  180. package/src/components/Dialog/README.md +24 -24
  181. package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
  182. package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
  183. package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
  184. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
  185. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
  186. package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
  187. package/src/components/PublicLayout/EventLogo.tsx +175 -0
  188. package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
  189. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
  190. package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
  191. package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
  192. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
  193. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
  194. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
  195. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
  196. package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
  197. package/src/examples/PublicEventPage.tsx +41 -41
  198. package/src/examples/PublicPageApp.tsx +33 -33
  199. package/src/examples/PublicPageUsageExample.tsx +30 -30
  200. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
  201. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
  202. package/src/hooks/index.ts +1 -1
  203. package/src/hooks/public/usePublicEventLogo.ts +285 -0
  204. package/src/hooks/public/usePublicRouteParams.ts +21 -4
  205. package/src/hooks/useEventTheme.test.ts +119 -43
  206. package/src/hooks/useEventTheme.ts +84 -55
  207. package/src/index.ts +3 -1
  208. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
  209. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
  210. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
  211. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
  212. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
  213. package/src/rbac/secureClient.ts +4 -2
  214. package/src/services/EventService.ts +0 -66
  215. package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
  216. package/src/styles/index.ts +1 -1
  217. package/src/theming/__tests__/parseEventColours.test.ts +209 -0
  218. package/src/theming/parseEventColours.ts +123 -0
  219. package/src/theming/runtime.ts +3 -0
  220. package/src/types/__tests__/file-reference.test.ts +447 -0
  221. package/src/utils/formatDate.test.ts +11 -11
  222. package/src/utils/formatting.ts +3 -2
  223. package/dist/chunk-BDZUMRBD.js 3.map +0 -1
  224. package/dist/chunk-BHWIUEYH.js.map +0 -1
  225. package/dist/chunk-CGURJ27Z.js.map +0 -1
  226. package/dist/chunk-FKFHZUGF.js.map +0 -1
  227. package/dist/chunk-GKHF54DI 2.js +0 -619
  228. package/dist/chunk-GKHF54DI.js 2.map +0 -1
  229. package/dist/chunk-GZRXOUBE.js.map +0 -1
  230. package/dist/chunk-HFBOFZ3Z.js.map +0 -1
  231. package/dist/chunk-NZ32EONV.js.map +0 -1
  232. package/dist/chunk-O3NWNXDY 2.js +0 -76
  233. package/dist/chunk-QPI2CCBA.js.map +0 -1
  234. package/dist/chunk-SMJZMKYN.js.map +0 -1
  235. package/dist/chunk-TDNI6ZWL.js 2.map +0 -1
  236. package/dist/chunk-TDNI6ZWL.js.map +0 -1
  237. package/dist/chunk-VKOCWWVY.js.map +0 -1
  238. package/dist/chunk-WP5I5GLN 2.js +0 -1564
  239. package/dist/index 3.js +0 -856
  240. package/dist/providers 3.js +0 -38
  241. package/dist/providers.js 3.map +0 -1
  242. package/dist/types 3.js +0 -128
  243. package/dist/types.js 3.map +0 -1
  244. package/dist/useInactivityTracker-MRUU55XI.js 3.map +0 -1
  245. package/dist/utils.js 3.map +0 -1
  246. package/dist/validation 3.js +0 -479
  247. package/src/styles/semantic.css +0 -24
  248. /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-WTS4IRF2.js.map} +0 -0
  249. /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
  250. /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
  251. /package/dist/{chunk-CGURJ27Z.js 2.map → chunk-4MXVZVNS.js.map} +0 -0
  252. /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
  253. /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
  254. /package/dist/{chunk-NZ32EONV.js 2.map → chunk-QWNJCQXZ.js.map} +0 -0
@@ -53,6 +53,7 @@ import { useTableColumns } from '../hooks/useTableColumns';
53
53
  import { initializeLiveRegion, announceSortChange } from '../utils/a11yUtils';
54
54
  import { useKeyboardNavigation } from '../hooks/useKeyboardNavigation';
55
55
  import { getRowIdSafe } from '../utils/rowUtils';
56
+ import { createLogger } from '../../../utils/logger';
56
57
 
57
58
  import { normalizeDataTableFeatures } from '../types';
58
59
  import type {
@@ -216,13 +217,7 @@ function DataTableInternal<TData extends DataRecord>({
216
217
  storageKey,
217
218
  onLayoutChange,
218
219
  }: DataTableCoreProps<TData>) {
219
- // CRITICAL DEBUG: Log immediately when component renders
220
- console.log('[DataTable] 🚀 DataTableInternal RENDERED:', {
221
- dataLength: data.length,
222
- columnsCount: columns.length,
223
- isLoading: externalIsLoading,
224
- pageName: rbac?.pageName || rbac?.pageId,
225
- });
220
+ const logger = React.useMemo(() => createLogger('DataTableCore'), []);
226
221
 
227
222
  // ============================================================================
228
223
  // ALL HOOKS MUST BE CALLED IN THE SAME ORDER EVERY RENDER
@@ -420,16 +415,15 @@ function DataTableInternal<TData extends DataRecord>({
420
415
  });
421
416
 
422
417
  useEffect(() => {
423
- if (!hierarchicalValidation.isValid && import.meta.env?.MODE === 'development') {
424
- console.error('[DataTable] Hierarchical data validation failed:', hierarchicalValidation.errors);
418
+ if (!hierarchicalValidation.isValid) {
419
+ logger.error('Hierarchical data validation failed:', hierarchicalValidation.errors);
425
420
  }
426
- }, [hierarchicalValidation]);
421
+ }, [hierarchicalValidation, logger]);
427
422
 
428
- // CRITICAL DEBUG: Log when finalTableData is empty but input data exists
429
- // This helps diagnose the "record count shows but no rows" bug
423
+ // Diagnostic logging when finalTableData is empty but input data exists
430
424
  useEffect(() => {
431
- if (import.meta.env?.MODE === 'development' && finalTableData.length === 0 && data.length > 0) {
432
- console.warn('[DataTable] Diagnostic: finalTableData empty but input data exists', {
425
+ if (finalTableData.length === 0 && data.length > 0) {
426
+ logger.warn('Diagnostic: finalTableData empty but input data exists', {
433
427
  inputDataLength: data.length,
434
428
  finalTableDataLength: finalTableData.length,
435
429
  dataCount: finalDataCount,
@@ -440,7 +434,7 @@ function DataTableInternal<TData extends DataRecord>({
440
434
  hierarchicalValid: hierarchicalValidation.isValid,
441
435
  });
442
436
  }
443
- }, [finalTableData.length, data.length, finalDataCount, finalPaginationMode, serverData, secureFeatures.hierarchical, hierarchical, hierarchicalValidation.isValid]);
437
+ }, [finalTableData.length, data.length, finalDataCount, finalPaginationMode, serverData, secureFeatures.hierarchical, hierarchical, hierarchicalValidation.isValid, logger]);
444
438
 
445
439
  const {
446
440
  columnOrder: savedColumnOrder,
@@ -473,19 +467,17 @@ function DataTableInternal<TData extends DataRecord>({
473
467
  useEffect(() => {
474
468
  if (secureFeatures.selection && state.columnOrder.includes('select') && state.columnOrder[0] !== 'select') {
475
469
  const normalizedOrder = ['select', ...state.columnOrder.filter(id => id !== 'select')];
476
- if (import.meta.env?.MODE === 'development') {
477
- console.warn('[DataTable] Correcting column order state - moving select to first position:', {
478
- before: state.columnOrder,
479
- after: normalizedOrder
480
- });
481
- }
470
+ logger.warn('Correcting column order state - moving select to first position:', {
471
+ before: state.columnOrder,
472
+ after: normalizedOrder
473
+ });
482
474
  stateActions.setColumnOrder(normalizedOrder);
483
475
  // Also update persisted order if persistence is enabled
484
476
  if (secureFeatures.columnReordering) {
485
477
  updateColumnOrder(normalizedOrder);
486
478
  }
487
479
  }
488
- }, [secureFeatures.selection, secureFeatures.columnReordering, state.columnOrder, stateActions, updateColumnOrder]);
480
+ }, [secureFeatures.selection, secureFeatures.columnReordering, state.columnOrder, stateActions, updateColumnOrder, logger]);
489
481
 
490
482
  // ============================================================================
491
483
  // CONFIGURATION RESOLUTION - ALWAYS call these hooks
@@ -507,14 +499,12 @@ function DataTableInternal<TData extends DataRecord>({
507
499
  Math.abs(curr - initialPageSize) < Math.abs(prev - initialPageSize) ? curr : prev
508
500
  );
509
501
 
510
- if (import.meta.env?.MODE === 'development') {
511
- console.warn(
512
- `DataTable: initialPageSize ${initialPageSize} is not available in page size options [${finalPageSizeOptions.join(', ')}]. Using closest option: ${closestOption}`
513
- );
514
- }
502
+ logger.warn(
503
+ `initialPageSize ${initialPageSize} is not available in page size options [${finalPageSizeOptions.join(', ')}]. Using closest option: ${closestOption}`
504
+ );
515
505
 
516
506
  return closestOption;
517
- }, [initialPageSize, finalPageSizeOptions, secureFeatures.pagination]);
507
+ }, [initialPageSize, finalPageSizeOptions, secureFeatures.pagination, logger]);
518
508
 
519
509
  // Determine the effective pageSize to use (validated or current state)
520
510
  // CRITICAL: This ensures we always pass a valid pageSize to TanStack Table configuration.
@@ -664,24 +654,22 @@ function DataTableInternal<TData extends DataRecord>({
664
654
  // Create a new array to avoid mutating the original
665
655
  const result = [...actions];
666
656
 
667
- // DEBUG: Log action configuration
668
- if (import.meta.env.MODE === 'development') {
669
- console.log('[DataTable] Action Configuration Debug:', {
670
- originalActions: actions.length,
671
- secureFeatures: {
672
- editing: secureFeatures.editing,
673
- deletion: secureFeatures.deletion
674
- },
675
- secureHandlers: {
676
- onEditRow: !!secureHandlers.onEditRow,
677
- onDeleteRow: !!secureHandlers.onDeleteRow
678
- },
679
- permissions: {
680
- canUpdate: permissions.canUpdate.can,
681
- canDelete: permissions.canDelete.can
682
- }
683
- });
684
- }
657
+ // Log action configuration in development
658
+ logger.debug('Action Configuration Debug:', {
659
+ originalActions: actions.length,
660
+ secureFeatures: {
661
+ editing: secureFeatures.editing,
662
+ deletion: secureFeatures.deletion
663
+ },
664
+ secureHandlers: {
665
+ onEditRow: !!secureHandlers.onEditRow,
666
+ onDeleteRow: !!secureHandlers.onDeleteRow
667
+ },
668
+ permissions: {
669
+ canUpdate: permissions.canUpdate.can,
670
+ canDelete: permissions.canDelete.can
671
+ }
672
+ });
685
673
 
686
674
  // Add Edit action with RBAC check
687
675
  if (secureFeatures.editing && secureHandlers.onEditRow && !result.some(a => a.label === 'Edit')) {
@@ -730,7 +718,7 @@ function DataTableInternal<TData extends DataRecord>({
730
718
  variant: "default"
731
719
  });
732
720
  } catch (error) {
733
- console.error('[DataTable] Delete error:', error);
721
+ logger.error('Delete error:', error);
734
722
  toast({
735
723
  title: "Delete Failed",
736
724
  description: error instanceof Error ? error.message : 'Failed to delete row',
@@ -745,14 +733,12 @@ function DataTableInternal<TData extends DataRecord>({
745
733
  });
746
734
  }
747
735
 
748
- // DEBUG: Log final actions
749
- if (import.meta.env.MODE === 'development') {
750
- console.log('[DataTable] Final Actions:', {
751
- totalActions: result.length,
752
- actionLabels: result.map(a => a.label),
753
- hiddenActions: result.filter(a => a.hidden).map(a => a.label)
754
- });
755
- }
736
+ // Log final actions in development
737
+ logger.debug('Final Actions:', {
738
+ totalActions: result.length,
739
+ actionLabels: result.map(a => a.label),
740
+ hiddenActions: result.filter(a => a.hidden).map(a => a.label)
741
+ });
756
742
 
757
743
  return result;
758
744
  }, [actions, secureFeatures, permissions, secureHandlers, resolvedGetRowId, stateActions, data]);
@@ -785,16 +771,14 @@ function DataTableInternal<TData extends DataRecord>({
785
771
  ? ['select', ...state.columnOrder.filter(id => id !== 'select')]
786
772
  : state.columnOrder;
787
773
 
788
- // Debug logging in dev mode
789
- if (import.meta.env?.MODE === 'development' && secureFeatures.selection) {
790
- if (state.columnOrder[0] !== 'select') {
791
- console.warn('[DataTable] Column order normalized:', {
792
- original: state.columnOrder,
793
- normalized: normalizedColumnOrder,
794
- firstColumnOriginal: state.columnOrder[0],
795
- firstColumnNormalized: normalizedColumnOrder[0]
796
- });
797
- }
774
+ // Log column order normalization in development
775
+ if (secureFeatures.selection && state.columnOrder[0] !== 'select') {
776
+ logger.warn('Column order normalized:', {
777
+ original: state.columnOrder,
778
+ normalized: normalizedColumnOrder,
779
+ firstColumnOriginal: state.columnOrder[0],
780
+ firstColumnNormalized: normalizedColumnOrder[0]
781
+ });
798
782
  }
799
783
 
800
784
  return {
@@ -848,59 +832,21 @@ function DataTableInternal<TData extends DataRecord>({
848
832
  hasServerSideConfig: !!serverSide,
849
833
  });
850
834
 
851
- // CRITICAL DEBUG: Always log table configuration state
852
- useEffect(() => {
853
- console.log('[DataTable] 🔍 Table Config Created:', {
854
- finalTableDataLength: finalTableData.length,
855
- configDataLength: tableConfig.data?.length || 0,
856
- columnsCount: enhancedColumns.length,
857
- finalPaginationMode,
858
- hasServerSideConfig: !!serverSide,
859
- manualPagination: tableConfig.manualPagination,
860
- hasGetPaginationRowModel: !!tableConfig.getPaginationRowModel,
861
- effectivePageSize,
862
- paginationState: tableStateSnapshot.pagination,
863
- });
864
- }, [finalTableData.length, tableConfig.data, tableConfig.manualPagination, tableConfig.getPaginationRowModel, finalPaginationMode, serverSide, effectivePageSize, tableStateSnapshot.pagination, enhancedColumns.length]);
865
835
 
866
836
  const table = useReactTable(tableConfig);
867
837
 
868
- // CRITICAL DEBUG: Always log table state immediately after creation
838
+ // Diagnostic logging when table is created but rows are empty
869
839
  useEffect(() => {
870
840
  const rows = table.getRowModel().rows;
871
- const coreRows = table.getCoreRowModel().rows;
872
- const prePaginationRows = table.getPrePaginationRowModel?.()?.rows || [];
873
- const filteredRows = table.getFilteredRowModel?.()?.rows || [];
874
- const sortedRows = table.getSortedRowModel?.()?.rows || [];
875
- const tableState = table.getState();
876
-
877
- console.log('[DataTable] 🔍 Table Created - Row Counts:', {
878
- finalTableDataLength: finalTableData.length,
879
- tableConfigDataLength: tableConfig.data?.length || 0,
880
- coreRowsLength: coreRows.length,
881
- prePaginationRowsLength: prePaginationRows.length,
882
- filteredRowsLength: filteredRows.length,
883
- sortedRowsLength: sortedRows.length,
884
- finalRowsLength: rows.length,
885
- pagination: tableState.pagination,
886
- finalPaginationMode,
887
- hasServerSideConfig: !!serverSide,
888
- tableOptions: {
889
- getCoreRowModel: !!tableConfig.getCoreRowModel,
890
- getFilteredRowModel: !!tableConfig.getFilteredRowModel,
891
- getSortedRowModel: !!tableConfig.getSortedRowModel,
892
- getPaginationRowModel: !!tableConfig.getPaginationRowModel,
893
- manualPagination: tableConfig.manualPagination,
894
- manualFiltering: tableConfig.manualFiltering,
895
- manualSorting: tableConfig.manualSorting,
896
- pageCount: tableConfig.pageCount,
897
- },
898
- hasRowId: !!resolvedGetRowId,
899
- effectivePageSize,
900
- });
901
841
 
902
842
  if (rows.length === 0 && finalTableData.length > 0) {
903
- console.warn('[DataTable] ⚠️ CRITICAL: Table created but rows are empty!', {
843
+ const coreRows = table.getCoreRowModel().rows;
844
+ const prePaginationRows = table.getPrePaginationRowModel?.()?.rows || [];
845
+ const filteredRows = table.getFilteredRowModel?.()?.rows || [];
846
+ const sortedRows = table.getSortedRowModel?.()?.rows || [];
847
+ const tableState = table.getState();
848
+
849
+ logger.warn('Table created but rows are empty!', {
904
850
  finalTableDataLength: finalTableData.length,
905
851
  tableConfigDataLength: tableConfig.data?.length || 0,
906
852
  coreRowsLength: coreRows.length,
@@ -925,7 +871,7 @@ function DataTableInternal<TData extends DataRecord>({
925
871
  effectivePageSize,
926
872
  });
927
873
  }
928
- }, [table, finalTableData.length, tableConfig, resolvedGetRowId, finalPaginationMode, serverSide, effectivePageSize]);
874
+ }, [table, finalTableData.length, tableConfig, resolvedGetRowId, finalPaginationMode, serverSide, effectivePageSize, logger]);
929
875
 
930
876
  // ============================================================================
931
877
  // RBAC VALIDATION AND EARLY RETURNS - AFTER ALL HOOKS
@@ -938,36 +884,26 @@ function DataTableInternal<TData extends DataRecord>({
938
884
 
939
885
  // Wait for permission check to complete before making access decisions
940
886
  if (permissions.canRead.isLoading) {
941
- console.log('[DataTable] ⏳ Permission check in progress - showing loading state');
942
887
  return <LoadingComponent />;
943
888
  }
944
889
 
945
890
  // MANDATORY: No data access without read permission (only check after loading completes)
946
891
  if (!permissions.canRead.can) {
947
- console.warn('[DataTable] 🚫 Access denied - no read permission:', {
892
+ logger.warn('Access denied - no read permission:', {
948
893
  canRead: permissions.canRead,
949
894
  pageId: effectivePageId,
950
895
  isLoading: permissions.canRead.isLoading,
951
896
  });
952
897
  return <AccessDeniedPage resource={effectivePageId || 'unknown-page'} operation="read" />;
953
898
  }
954
-
955
- console.log('[DataTable] ✅ Permission check passed - rendering table');
956
899
 
957
900
  // ============================================================================
958
901
  // RENDER
959
902
  // ============================================================================
960
903
 
961
904
  if (isLoading) {
962
- console.log('[DataTable] ⏳ Loading state - showing loading component');
963
905
  return <LoadingComponent />;
964
906
  }
965
-
966
- console.log('[DataTable] 📊 About to render table with data:', {
967
- finalTableDataLength: finalTableData.length,
968
- tableExists: !!table,
969
- canGetRows: !!table?.getRowModel,
970
- });
971
907
 
972
908
  const PaginationComponent = enhancedPagination || finalPaginationMode !== 'client'
973
909
  ? EnhancedPaginationControls
@@ -1104,11 +1040,9 @@ function DataTableInternal<TData extends DataRecord>({
1104
1040
  variant: "default"
1105
1041
  });
1106
1042
 
1107
- if (import.meta.env.MODE === 'development') {
1108
- console.log('DataTable: Export completed successfully');
1109
- }
1043
+ logger.debug('Export completed successfully');
1110
1044
  } catch (error) {
1111
- console.error('DataTable: Failed to export data:', error);
1045
+ logger.error('Failed to export data:', error);
1112
1046
 
1113
1047
  // Show error toast notification to user
1114
1048
  const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
@@ -1117,10 +1051,6 @@ function DataTableInternal<TData extends DataRecord>({
1117
1051
  description: `Failed to export data: ${errorMessage}`,
1118
1052
  variant: "destructive"
1119
1053
  });
1120
-
1121
- if (import.meta.env.MODE === 'development') {
1122
- console.error('DataTable: Export error details:', error);
1123
- }
1124
1054
  }
1125
1055
  })}
1126
1056
  rowSelection={rowSelection}
@@ -1146,7 +1076,7 @@ function DataTableInternal<TData extends DataRecord>({
1146
1076
  variant: "default"
1147
1077
  });
1148
1078
  } catch (error) {
1149
- console.error('[DataTable] Bulk delete error:', error);
1079
+ logger.error('Bulk delete error:', error);
1150
1080
  toast({
1151
1081
  title: "Delete Failed",
1152
1082
  description: error instanceof Error ? error.message : 'Failed to delete selected rows',
@@ -1380,12 +1310,12 @@ function DataTableInternal<TData extends DataRecord>({
1380
1310
  onImport={async (data: TData[]) => {
1381
1311
  if (onImport) {
1382
1312
  try {
1383
- console.log('[DataTableCore] onImport called with', data.length, 'rows');
1313
+ logger.debug('onImport called with', data.length, 'rows');
1384
1314
  const result = onImport(data);
1385
1315
  if (result && typeof result.then === 'function') {
1386
1316
  await result;
1387
1317
  }
1388
- console.log('[DataTableCore] onImport completed successfully');
1318
+ logger.debug('onImport completed successfully');
1389
1319
 
1390
1320
  // Show success toast
1391
1321
  // NOTE: Toast notifications use default timeout (5 seconds) - do not set duration property
@@ -1395,7 +1325,7 @@ function DataTableInternal<TData extends DataRecord>({
1395
1325
  variant: "default"
1396
1326
  });
1397
1327
  } catch (error) {
1398
- console.error('[DataTableCore] Import error:', error);
1328
+ logger.error('Import error:', error);
1399
1329
  toast({
1400
1330
  title: "Import Failed",
1401
1331
  description: error instanceof Error ? error.message : 'Failed to import data',
@@ -1405,7 +1335,7 @@ function DataTableInternal<TData extends DataRecord>({
1405
1335
  return;
1406
1336
  }
1407
1337
  } else {
1408
- console.error('[DataTableCore] onImport handler not provided');
1338
+ logger.error('onImport handler not provided');
1409
1339
  toast({
1410
1340
  title: "Import Not Configured",
1411
1341
  description: "Import functionality requires an onImport handler to be provided.",
@@ -23,6 +23,7 @@
23
23
 
24
24
  import React, { useEffect } from 'react';
25
25
  import { ImportModal, type ImportModalConfig } from './ImportModal';
26
+ import { createLogger } from '../../../utils/logger';
26
27
 
27
28
  /**
28
29
  * Maps CSV column data to table column structure
@@ -37,11 +38,12 @@ function mapCSVToTableColumns<TData extends Record<string, unknown> = Record<str
37
38
  editAccessorKey?: string;
38
39
  }>
39
40
  ): TData[] {
41
+ const logger = createLogger('mapCSVToTableColumns');
40
42
  // Create a mapping from CSV headers to table field names
41
43
  // Priority: editAccessorKey > accessorKey > id
42
44
  const columnMap = new Map<string, string>();
43
45
 
44
- console.log('[mapCSVToTableColumns] Building column map from', columns.length, 'column definitions');
46
+ logger.debug('Building column map from', columns.length, 'column definitions');
45
47
 
46
48
  columns.forEach(col => {
47
49
  const fieldName = col.editAccessorKey || col.accessorKey || col.id;
@@ -51,13 +53,13 @@ function mapCSVToTableColumns<TData extends Record<string, unknown> = Record<str
51
53
  const headerLower = header.toLowerCase();
52
54
  // Map header to field name (case-insensitive)
53
55
  columnMap.set(headerLower, fieldName);
54
- console.log(`[mapCSVToTableColumns] Mapped "${header}" -> "${fieldName}"`);
56
+ logger.debug(`Mapped "${header}" -> "${fieldName}"`);
55
57
 
56
58
  // Also map id/accessorKey if different from header
57
59
  const colId = col.id || col.accessorKey;
58
60
  if (colId && colId !== header && colId !== fieldName) {
59
61
  columnMap.set(colId.toLowerCase(), fieldName);
60
- console.log(`[mapCSVToTableColumns] Also mapped "${colId}" -> "${fieldName}"`);
62
+ logger.debug(`Also mapped "${colId}" -> "${fieldName}"`);
61
63
  }
62
64
 
63
65
  // For reference fields with editAccessorKey, also map the ID column header
@@ -66,24 +68,24 @@ function mapCSVToTableColumns<TData extends Record<string, unknown> = Record<str
66
68
  const editAccessorKey = col.editAccessorKey; // Store in const for proper type narrowing
67
69
  const idColumnHeader = `${header} (ID)`;
68
70
  columnMap.set(idColumnHeader.toLowerCase(), editAccessorKey);
69
- console.log(`[mapCSVToTableColumns] Mapped ID column "${idColumnHeader}" -> "${editAccessorKey}"`);
71
+ logger.debug(`Mapped ID column "${idColumnHeader}" -> "${editAccessorKey}"`);
70
72
  // Also map the editAccessorKey directly (in case CSV uses the field name)
71
73
  columnMap.set(editAccessorKey.toLowerCase(), editAccessorKey);
72
- console.log(`[mapCSVToTableColumns] Also mapped "${editAccessorKey}" -> "${editAccessorKey}"`);
74
+ logger.debug(`Also mapped "${editAccessorKey}" -> "${editAccessorKey}"`);
73
75
  }
74
76
  } else {
75
- console.warn('[mapCSVToTableColumns] Skipping column with missing fieldName or header:', col);
77
+ logger.warn('Skipping column with missing fieldName or header:', col);
76
78
  }
77
79
  });
78
80
 
79
81
  if (csvData.length === 0) {
80
- console.warn('[mapCSVToTableColumns] No CSV data to map');
82
+ logger.warn('No CSV data to map');
81
83
  return [];
82
84
  }
83
85
 
84
86
  const csvHeaders = Object.keys(csvData[0]);
85
- console.log('[mapCSVToTableColumns] CSV headers found:', csvHeaders);
86
- console.log('[mapCSVToTableColumns] Column map size:', columnMap.size);
87
+ logger.debug('CSV headers found:', csvHeaders);
88
+ logger.debug('Column map size:', columnMap.size);
87
89
 
88
90
  // Transform CSV data using the mapping
89
91
  const mappedData = csvData.map((row, index) => {
@@ -107,7 +109,7 @@ function mapCSVToTableColumns<TData extends Record<string, unknown> = Record<str
107
109
  if (csvHeaderLower === mapKey || csvHeaderLower.endsWith(keyWithSpace)) {
108
110
  fieldName = mapValue;
109
111
  if (index === 0) {
110
- console.log(`[mapCSVToTableColumns] Flexible match: "${csvHeader}" -> "${mapValue}" (matched "${mapKey}")`);
112
+ logger.debug(`Flexible match: "${csvHeader}" -> "${mapValue}" (matched "${mapKey}")`);
111
113
  }
112
114
  break; // Found a match, stop searching
113
115
  }
@@ -117,13 +119,13 @@ function mapCSVToTableColumns<TData extends Record<string, unknown> = Record<str
117
119
  if (fieldName) {
118
120
  mappedRow[fieldName] = row[csvHeader];
119
121
  if (index === 0) {
120
- console.log(`[mapCSVToTableColumns] Row 0: "${csvHeader}" -> "${fieldName}"`);
122
+ logger.debug(`Row 0: "${csvHeader}" -> "${fieldName}"`);
121
123
  }
122
124
  } else {
123
125
  // If no mapping found, use the CSV header as-is (lowercase)
124
126
  mappedRow[csvHeaderLower] = row[csvHeader];
125
127
  if (index === 0) {
126
- console.warn(`[mapCSVToTableColumns] No mapping found for "${csvHeader}", using as-is`);
128
+ logger.warn(`No mapping found for "${csvHeader}", using as-is`);
127
129
  }
128
130
  }
129
131
  });
@@ -131,9 +133,9 @@ function mapCSVToTableColumns<TData extends Record<string, unknown> = Record<str
131
133
  return mappedRow as TData;
132
134
  });
133
135
 
134
- console.log('[mapCSVToTableColumns] Mapped', mappedData.length, 'rows');
136
+ logger.debug('Mapped', mappedData.length, 'rows');
135
137
  if (mappedData.length > 0) {
136
- console.log('[mapCSVToTableColumns] First mapped row keys:', Object.keys(mappedData[0]));
138
+ logger.debug('First mapped row keys:', Object.keys(mappedData[0]));
137
139
  }
138
140
 
139
141
  return mappedData;
@@ -203,6 +205,7 @@ export function DataTableModals<TData extends Record<string, unknown> = Record<s
203
205
  onStoreFocus,
204
206
  onRestoreFocus,
205
207
  }: DataTableModalsProps<TData>) {
208
+ const logger = React.useMemo(() => createLogger('DataTableModals'), []);
206
209
  // Handle focus management for import modal
207
210
  useEffect(() => {
208
211
  if (showImportModal) {
@@ -227,28 +230,28 @@ export function DataTableModals<TData extends Record<string, unknown> = Record<s
227
230
  // Automatically map CSV columns to table columns based on column definitions
228
231
  let mappedData: TData[];
229
232
  if (columns && columns.length > 0) {
230
- console.log('[DataTableModals] Mapping CSV data with', columns.length, 'column definitions');
231
- console.log('[DataTableModals] Raw CSV headers:', rawData.length > 0 ? Object.keys(rawData[0]) : []);
233
+ logger.debug('Mapping CSV data with', columns.length, 'column definitions');
234
+ logger.debug('Raw CSV headers:', rawData.length > 0 ? Object.keys(rawData[0]) : []);
232
235
  mappedData = mapCSVToTableColumns<TData>(rawData, columns);
233
- console.log('[DataTableModals] Mapped data sample:', mappedData.length > 0 ? mappedData[0] : null);
236
+ logger.debug('Mapped data sample:', mappedData.length > 0 ? mappedData[0] : null);
234
237
  } else {
235
- console.warn('[DataTableModals] No columns provided for mapping, using raw data');
238
+ logger.warn('No columns provided for mapping, using raw data');
236
239
  mappedData = rawData as TData[];
237
240
  }
238
241
 
239
242
  if (!onImport) {
240
- console.error('[DataTableModals] onImport callback is not provided');
243
+ logger.error('onImport callback is not provided');
241
244
  throw new Error('Import handler is not configured. Please provide an onImport callback.');
242
245
  }
243
246
 
244
- console.log('[DataTableModals] Calling onImport with', mappedData.length, 'rows');
247
+ logger.debug('Calling onImport with', mappedData.length, 'rows');
245
248
  const result = onImport(mappedData);
246
249
  if (result && typeof result.then === 'function') {
247
250
  await result;
248
251
  }
249
- console.log('[DataTableModals] Import completed successfully');
252
+ logger.debug('Import completed successfully');
250
253
  } catch (error) {
251
- console.error('[DataTableModals] Import error:', error);
254
+ logger.error('Import error:', error);
252
255
  throw error; // Re-throw to let ImportModal handle it
253
256
  }
254
257
  }}