@jmruthers/pace-core 0.5.121 → 0.5.124

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 (255) hide show
  1. package/dist/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
  2. package/dist/{DataTable-DGZDJUYM.js → DataTable-OKDYRW2S.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-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
  11. package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
  12. package/dist/{chunk-HFBOFZ3Z.js → chunk-GBGYYMC6.js} +317 -251
  13. package/dist/chunk-GBGYYMC6.js.map +1 -0
  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-QPI2CCBA.js → chunk-VPUCTHTY.js} +149 -96
  23. package/dist/chunk-VPUCTHTY.js.map +1 -0
  24. package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
  25. package/dist/chunk-XN6GWKMV.js.map +1 -0
  26. package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
  27. package/dist/chunk-ZBLK676C.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 +125 -144
  173. package/src/components/DataTable/components/DataTableModals.tsx +25 -22
  174. package/src/components/DataTable/components/DataTableToolbar.tsx +14 -1
  175. package/src/components/DataTable/components/EditableRow.tsx +118 -42
  176. package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
  177. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
  178. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
  179. package/src/components/DataTable/utils/exportUtils.ts +3 -2
  180. package/src/components/Dialog/Dialog.tsx +1 -1
  181. package/src/components/Dialog/README.md +24 -24
  182. package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
  183. package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
  184. package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
  185. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
  186. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
  187. package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
  188. package/src/components/PublicLayout/EventLogo.tsx +175 -0
  189. package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
  190. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
  191. package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
  192. package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
  193. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
  194. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
  195. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
  196. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
  197. package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
  198. package/src/examples/PublicEventPage.tsx +41 -41
  199. package/src/examples/PublicPageApp.tsx +33 -33
  200. package/src/examples/PublicPageUsageExample.tsx +30 -30
  201. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
  202. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
  203. package/src/hooks/index.ts +1 -1
  204. package/src/hooks/public/usePublicEventLogo.ts +285 -0
  205. package/src/hooks/public/usePublicRouteParams.ts +21 -4
  206. package/src/hooks/useEventTheme.test.ts +119 -43
  207. package/src/hooks/useEventTheme.ts +84 -55
  208. package/src/index.ts +3 -1
  209. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
  210. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
  211. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
  212. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
  213. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
  214. package/src/rbac/secureClient.ts +4 -2
  215. package/src/services/EventService.ts +0 -66
  216. package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
  217. package/src/styles/index.ts +1 -1
  218. package/src/theming/__tests__/parseEventColours.test.ts +209 -0
  219. package/src/theming/parseEventColours.ts +123 -0
  220. package/src/theming/runtime.ts +3 -0
  221. package/src/types/__tests__/file-reference.test.ts +447 -0
  222. package/src/utils/formatDate.test.ts +11 -11
  223. package/src/utils/formatting.ts +3 -2
  224. package/dist/chunk-BDZUMRBD.js 3.map +0 -1
  225. package/dist/chunk-BHWIUEYH.js.map +0 -1
  226. package/dist/chunk-CGURJ27Z.js.map +0 -1
  227. package/dist/chunk-FKFHZUGF.js.map +0 -1
  228. package/dist/chunk-GKHF54DI 2.js +0 -619
  229. package/dist/chunk-GKHF54DI.js 2.map +0 -1
  230. package/dist/chunk-GZRXOUBE.js.map +0 -1
  231. package/dist/chunk-HFBOFZ3Z.js.map +0 -1
  232. package/dist/chunk-NZ32EONV.js.map +0 -1
  233. package/dist/chunk-O3NWNXDY 2.js +0 -76
  234. package/dist/chunk-QPI2CCBA.js.map +0 -1
  235. package/dist/chunk-SMJZMKYN.js.map +0 -1
  236. package/dist/chunk-TDNI6ZWL.js 2.map +0 -1
  237. package/dist/chunk-TDNI6ZWL.js.map +0 -1
  238. package/dist/chunk-VKOCWWVY.js.map +0 -1
  239. package/dist/chunk-WP5I5GLN 2.js +0 -1564
  240. package/dist/index 3.js +0 -856
  241. package/dist/providers 3.js +0 -38
  242. package/dist/providers.js 3.map +0 -1
  243. package/dist/types 3.js +0 -128
  244. package/dist/types.js 3.map +0 -1
  245. package/dist/useInactivityTracker-MRUU55XI.js 3.map +0 -1
  246. package/dist/utils.js 3.map +0 -1
  247. package/dist/validation 3.js +0 -479
  248. package/src/styles/semantic.css +0 -24
  249. /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-OKDYRW2S.js.map} +0 -0
  250. /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
  251. /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
  252. /package/dist/{chunk-CGURJ27Z.js 2.map → chunk-4MXVZVNS.js.map} +0 -0
  253. /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
  254. /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
  255. /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
@@ -239,6 +234,17 @@ function DataTableInternal<TData extends DataRecord>({
239
234
  // MANDATORY: Get permissions and secure features
240
235
  const { permissions, secureFeatures, effectivePageId } = useDataTablePermissions(rbac, requestedFeatures);
241
236
 
237
+ // Debug logging for creation feature
238
+ if (import.meta.env.MODE === 'development') {
239
+ logger.debug('[DataTableCore] Creation feature check:', {
240
+ 'incomingFeatures.creation': incomingFeatures.creation,
241
+ 'requestedFeatures.creation': requestedFeatures.creation,
242
+ 'secureFeatures.creation': secureFeatures.creation,
243
+ 'permissions.canCreate.can': permissions.canCreate.can,
244
+ 'onCreateRow prop provided': !!onCreateRow
245
+ });
246
+ }
247
+
242
248
  // ============================================================================
243
249
  // UNIFIED STATE MANAGEMENT - Use ONLY useDataTableState for all state
244
250
  // ============================================================================
@@ -420,16 +426,15 @@ function DataTableInternal<TData extends DataRecord>({
420
426
  });
421
427
 
422
428
  useEffect(() => {
423
- if (!hierarchicalValidation.isValid && import.meta.env?.MODE === 'development') {
424
- console.error('[DataTable] Hierarchical data validation failed:', hierarchicalValidation.errors);
429
+ if (!hierarchicalValidation.isValid) {
430
+ logger.error('Hierarchical data validation failed:', hierarchicalValidation.errors);
425
431
  }
426
- }, [hierarchicalValidation]);
432
+ }, [hierarchicalValidation, logger]);
427
433
 
428
- // CRITICAL DEBUG: Log when finalTableData is empty but input data exists
429
- // This helps diagnose the "record count shows but no rows" bug
434
+ // Diagnostic logging when finalTableData is empty but input data exists
430
435
  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', {
436
+ if (finalTableData.length === 0 && data.length > 0) {
437
+ logger.warn('Diagnostic: finalTableData empty but input data exists', {
433
438
  inputDataLength: data.length,
434
439
  finalTableDataLength: finalTableData.length,
435
440
  dataCount: finalDataCount,
@@ -440,7 +445,7 @@ function DataTableInternal<TData extends DataRecord>({
440
445
  hierarchicalValid: hierarchicalValidation.isValid,
441
446
  });
442
447
  }
443
- }, [finalTableData.length, data.length, finalDataCount, finalPaginationMode, serverData, secureFeatures.hierarchical, hierarchical, hierarchicalValidation.isValid]);
448
+ }, [finalTableData.length, data.length, finalDataCount, finalPaginationMode, serverData, secureFeatures.hierarchical, hierarchical, hierarchicalValidation.isValid, logger]);
444
449
 
445
450
  const {
446
451
  columnOrder: savedColumnOrder,
@@ -473,19 +478,17 @@ function DataTableInternal<TData extends DataRecord>({
473
478
  useEffect(() => {
474
479
  if (secureFeatures.selection && state.columnOrder.includes('select') && state.columnOrder[0] !== 'select') {
475
480
  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
- }
481
+ logger.warn('Correcting column order state - moving select to first position:', {
482
+ before: state.columnOrder,
483
+ after: normalizedOrder
484
+ });
482
485
  stateActions.setColumnOrder(normalizedOrder);
483
486
  // Also update persisted order if persistence is enabled
484
487
  if (secureFeatures.columnReordering) {
485
488
  updateColumnOrder(normalizedOrder);
486
489
  }
487
490
  }
488
- }, [secureFeatures.selection, secureFeatures.columnReordering, state.columnOrder, stateActions, updateColumnOrder]);
491
+ }, [secureFeatures.selection, secureFeatures.columnReordering, state.columnOrder, stateActions, updateColumnOrder, logger]);
489
492
 
490
493
  // ============================================================================
491
494
  // CONFIGURATION RESOLUTION - ALWAYS call these hooks
@@ -507,14 +510,12 @@ function DataTableInternal<TData extends DataRecord>({
507
510
  Math.abs(curr - initialPageSize) < Math.abs(prev - initialPageSize) ? curr : prev
508
511
  );
509
512
 
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
- }
513
+ logger.warn(
514
+ `initialPageSize ${initialPageSize} is not available in page size options [${finalPageSizeOptions.join(', ')}]. Using closest option: ${closestOption}`
515
+ );
515
516
 
516
517
  return closestOption;
517
- }, [initialPageSize, finalPageSizeOptions, secureFeatures.pagination]);
518
+ }, [initialPageSize, finalPageSizeOptions, secureFeatures.pagination, logger]);
518
519
 
519
520
  // Determine the effective pageSize to use (validated or current state)
520
521
  // CRITICAL: This ensures we always pass a valid pageSize to TanStack Table configuration.
@@ -650,38 +651,76 @@ function DataTableInternal<TData extends DataRecord>({
650
651
  // ============================================================================
651
652
 
652
653
  // MANDATORY: Handlers are automatically secured
653
- const secureHandlers = useMemo(() => ({
654
- onEditRow: permissions.canUpdate.can ? onEditRow : undefined,
655
- onDeleteRow: permissions.canDelete.can ? onDeleteRow : undefined,
656
- onCreateRow: permissions.canCreate.can ? onCreateRow : undefined,
657
- onImport: permissions.canImport.can ? onImport : undefined,
658
- onExport: permissions.canExport.can ? onExport : undefined,
659
- onDeleteSelected: permissions.canDelete.can ? onDeleteSelected : undefined,
660
- }), [permissions.canUpdate.can, permissions.canDelete.can, permissions.canCreate.can, permissions.canImport.can, permissions.canExport.can, onEditRow, onDeleteRow, onCreateRow, onImport, onExport, onDeleteSelected]);
654
+ const secureHandlers = useMemo(() => {
655
+ const handlers = {
656
+ onEditRow: permissions.canUpdate.can ? onEditRow : undefined,
657
+ onDeleteRow: permissions.canDelete.can ? onDeleteRow : undefined,
658
+ onCreateRow: permissions.canCreate.can ? onCreateRow : undefined,
659
+ onImport: permissions.canImport.can ? onImport : undefined,
660
+ onExport: permissions.canExport.can ? onExport : undefined,
661
+ onDeleteSelected: permissions.canDelete.can ? onDeleteSelected : undefined,
662
+ };
663
+
664
+ // Debug logging for creation handler
665
+ if (import.meta.env.MODE === 'development') {
666
+ logger.debug('[DataTableCore] Creation handler check:', {
667
+ 'permissions.canCreate.can': permissions.canCreate.can,
668
+ 'onCreateRow prop provided': !!onCreateRow,
669
+ 'secureHandlers.onCreateRow': !!handlers.onCreateRow,
670
+ 'secureFeatures.creation': secureFeatures.creation,
671
+ 'will pass onCreateRow to toolbar': secureFeatures.creation && !!handlers.onCreateRow
672
+ });
673
+ }
674
+
675
+ return handlers;
676
+ }, [permissions.canUpdate.can, permissions.canDelete.can, permissions.canCreate.can, permissions.canImport.can, permissions.canExport.can, onEditRow, onDeleteRow, onCreateRow, onImport, onExport, onDeleteSelected, secureFeatures.creation, logger]);
677
+
678
+ // Explicit debug log for creation button visibility (easier to spot)
679
+ if (import.meta.env.MODE === 'development') {
680
+ logger.debug('[DataTableCore] ⚠️ CREATION BUTTON DIAGNOSIS:', {
681
+ '✅ permissions.canCreate.can': permissions.canCreate.can,
682
+ '❓ features.creation enabled': secureFeatures.creation,
683
+ '❓ onCreateRow handler provided': !!onCreateRow,
684
+ '❓ secureHandlers.onCreateRow': !!secureHandlers.onCreateRow,
685
+ '🔍 WILL SHOW BUTTON': secureFeatures.creation && permissions.canCreate.can && !!onCreateRow,
686
+ '💡 SOLUTION': !secureFeatures.creation
687
+ ? 'Enable features={{ creation: true }} in DataTable props'
688
+ : !onCreateRow
689
+ ? 'Provide onCreateRow handler in DataTable props'
690
+ : 'All conditions met - button should be visible'
691
+ });
692
+ }
661
693
 
662
694
  // MANDATORY: Process actions with RBAC checks
663
695
  const effectiveActions = useMemo(() => {
664
696
  // Create a new array to avoid mutating the original
665
697
  const result = [...actions];
666
698
 
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
- }
699
+ // Log action configuration in development
700
+ logger.debug('Action Configuration Debug:', {
701
+ originalActions: actions.length,
702
+ secureFeatures: {
703
+ editing: secureFeatures.editing,
704
+ deletion: secureFeatures.deletion,
705
+ creation: secureFeatures.creation,
706
+ import: secureFeatures.import,
707
+ export: secureFeatures.export
708
+ },
709
+ secureHandlers: {
710
+ onEditRow: !!secureHandlers.onEditRow,
711
+ onDeleteRow: !!secureHandlers.onDeleteRow,
712
+ onCreateRow: !!secureHandlers.onCreateRow,
713
+ onImport: !!secureHandlers.onImport,
714
+ onExport: !!secureHandlers.onExport
715
+ },
716
+ permissions: {
717
+ canUpdate: permissions.canUpdate.can,
718
+ canDelete: permissions.canDelete.can,
719
+ canCreate: permissions.canCreate.can,
720
+ canImport: permissions.canImport.can,
721
+ canExport: permissions.canExport.can
722
+ }
723
+ });
685
724
 
686
725
  // Add Edit action with RBAC check
687
726
  if (secureFeatures.editing && secureHandlers.onEditRow && !result.some(a => a.label === 'Edit')) {
@@ -730,7 +769,7 @@ function DataTableInternal<TData extends DataRecord>({
730
769
  variant: "default"
731
770
  });
732
771
  } catch (error) {
733
- console.error('[DataTable] Delete error:', error);
772
+ logger.error('Delete error:', error);
734
773
  toast({
735
774
  title: "Delete Failed",
736
775
  description: error instanceof Error ? error.message : 'Failed to delete row',
@@ -745,14 +784,12 @@ function DataTableInternal<TData extends DataRecord>({
745
784
  });
746
785
  }
747
786
 
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
- }
787
+ // Log final actions in development
788
+ logger.debug('Final Actions:', {
789
+ totalActions: result.length,
790
+ actionLabels: result.map(a => a.label),
791
+ hiddenActions: result.filter(a => a.hidden).map(a => a.label)
792
+ });
756
793
 
757
794
  return result;
758
795
  }, [actions, secureFeatures, permissions, secureHandlers, resolvedGetRowId, stateActions, data]);
@@ -785,16 +822,14 @@ function DataTableInternal<TData extends DataRecord>({
785
822
  ? ['select', ...state.columnOrder.filter(id => id !== 'select')]
786
823
  : state.columnOrder;
787
824
 
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
- }
825
+ // Log column order normalization in development
826
+ if (secureFeatures.selection && state.columnOrder[0] !== 'select') {
827
+ logger.warn('Column order normalized:', {
828
+ original: state.columnOrder,
829
+ normalized: normalizedColumnOrder,
830
+ firstColumnOriginal: state.columnOrder[0],
831
+ firstColumnNormalized: normalizedColumnOrder[0]
832
+ });
798
833
  }
799
834
 
800
835
  return {
@@ -848,59 +883,21 @@ function DataTableInternal<TData extends DataRecord>({
848
883
  hasServerSideConfig: !!serverSide,
849
884
  });
850
885
 
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
886
 
866
887
  const table = useReactTable(tableConfig);
867
888
 
868
- // CRITICAL DEBUG: Always log table state immediately after creation
889
+ // Diagnostic logging when table is created but rows are empty
869
890
  useEffect(() => {
870
891
  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
892
 
902
893
  if (rows.length === 0 && finalTableData.length > 0) {
903
- console.warn('[DataTable] ⚠️ CRITICAL: Table created but rows are empty!', {
894
+ const coreRows = table.getCoreRowModel().rows;
895
+ const prePaginationRows = table.getPrePaginationRowModel?.()?.rows || [];
896
+ const filteredRows = table.getFilteredRowModel?.()?.rows || [];
897
+ const sortedRows = table.getSortedRowModel?.()?.rows || [];
898
+ const tableState = table.getState();
899
+
900
+ logger.warn('Table created but rows are empty!', {
904
901
  finalTableDataLength: finalTableData.length,
905
902
  tableConfigDataLength: tableConfig.data?.length || 0,
906
903
  coreRowsLength: coreRows.length,
@@ -925,7 +922,7 @@ function DataTableInternal<TData extends DataRecord>({
925
922
  effectivePageSize,
926
923
  });
927
924
  }
928
- }, [table, finalTableData.length, tableConfig, resolvedGetRowId, finalPaginationMode, serverSide, effectivePageSize]);
925
+ }, [table, finalTableData.length, tableConfig, resolvedGetRowId, finalPaginationMode, serverSide, effectivePageSize, logger]);
929
926
 
930
927
  // ============================================================================
931
928
  // RBAC VALIDATION AND EARLY RETURNS - AFTER ALL HOOKS
@@ -938,36 +935,26 @@ function DataTableInternal<TData extends DataRecord>({
938
935
 
939
936
  // Wait for permission check to complete before making access decisions
940
937
  if (permissions.canRead.isLoading) {
941
- console.log('[DataTable] ⏳ Permission check in progress - showing loading state');
942
938
  return <LoadingComponent />;
943
939
  }
944
940
 
945
941
  // MANDATORY: No data access without read permission (only check after loading completes)
946
942
  if (!permissions.canRead.can) {
947
- console.warn('[DataTable] 🚫 Access denied - no read permission:', {
943
+ logger.warn('Access denied - no read permission:', {
948
944
  canRead: permissions.canRead,
949
945
  pageId: effectivePageId,
950
946
  isLoading: permissions.canRead.isLoading,
951
947
  });
952
948
  return <AccessDeniedPage resource={effectivePageId || 'unknown-page'} operation="read" />;
953
949
  }
954
-
955
- console.log('[DataTable] ✅ Permission check passed - rendering table');
956
950
 
957
951
  // ============================================================================
958
952
  // RENDER
959
953
  // ============================================================================
960
954
 
961
955
  if (isLoading) {
962
- console.log('[DataTable] ⏳ Loading state - showing loading component');
963
956
  return <LoadingComponent />;
964
957
  }
965
-
966
- console.log('[DataTable] 📊 About to render table with data:', {
967
- finalTableDataLength: finalTableData.length,
968
- tableExists: !!table,
969
- canGetRows: !!table?.getRowModel,
970
- });
971
958
 
972
959
  const PaginationComponent = enhancedPagination || finalPaginationMode !== 'client'
973
960
  ? EnhancedPaginationControls
@@ -1104,11 +1091,9 @@ function DataTableInternal<TData extends DataRecord>({
1104
1091
  variant: "default"
1105
1092
  });
1106
1093
 
1107
- if (import.meta.env.MODE === 'development') {
1108
- console.log('DataTable: Export completed successfully');
1109
- }
1094
+ logger.debug('Export completed successfully');
1110
1095
  } catch (error) {
1111
- console.error('DataTable: Failed to export data:', error);
1096
+ logger.error('Failed to export data:', error);
1112
1097
 
1113
1098
  // Show error toast notification to user
1114
1099
  const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
@@ -1117,10 +1102,6 @@ function DataTableInternal<TData extends DataRecord>({
1117
1102
  description: `Failed to export data: ${errorMessage}`,
1118
1103
  variant: "destructive"
1119
1104
  });
1120
-
1121
- if (import.meta.env.MODE === 'development') {
1122
- console.error('DataTable: Export error details:', error);
1123
- }
1124
1105
  }
1125
1106
  })}
1126
1107
  rowSelection={rowSelection}
@@ -1146,7 +1127,7 @@ function DataTableInternal<TData extends DataRecord>({
1146
1127
  variant: "default"
1147
1128
  });
1148
1129
  } catch (error) {
1149
- console.error('[DataTable] Bulk delete error:', error);
1130
+ logger.error('Bulk delete error:', error);
1150
1131
  toast({
1151
1132
  title: "Delete Failed",
1152
1133
  description: error instanceof Error ? error.message : 'Failed to delete selected rows',
@@ -1380,12 +1361,12 @@ function DataTableInternal<TData extends DataRecord>({
1380
1361
  onImport={async (data: TData[]) => {
1381
1362
  if (onImport) {
1382
1363
  try {
1383
- console.log('[DataTableCore] onImport called with', data.length, 'rows');
1364
+ logger.debug('onImport called with', data.length, 'rows');
1384
1365
  const result = onImport(data);
1385
1366
  if (result && typeof result.then === 'function') {
1386
1367
  await result;
1387
1368
  }
1388
- console.log('[DataTableCore] onImport completed successfully');
1369
+ logger.debug('onImport completed successfully');
1389
1370
 
1390
1371
  // Show success toast
1391
1372
  // NOTE: Toast notifications use default timeout (5 seconds) - do not set duration property
@@ -1395,7 +1376,7 @@ function DataTableInternal<TData extends DataRecord>({
1395
1376
  variant: "default"
1396
1377
  });
1397
1378
  } catch (error) {
1398
- console.error('[DataTableCore] Import error:', error);
1379
+ logger.error('Import error:', error);
1399
1380
  toast({
1400
1381
  title: "Import Failed",
1401
1382
  description: error instanceof Error ? error.message : 'Failed to import data',
@@ -1405,7 +1386,7 @@ function DataTableInternal<TData extends DataRecord>({
1405
1386
  return;
1406
1387
  }
1407
1388
  } else {
1408
- console.error('[DataTableCore] onImport handler not provided');
1389
+ logger.error('onImport handler not provided');
1409
1390
  toast({
1410
1391
  title: "Import Not Configured",
1411
1392
  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
  }}
@@ -212,7 +212,20 @@ export function DataTableToolbar<TData extends DataRecord>({
212
212
  )}
213
213
 
214
214
  {/* Row Creation - ONLY if user has create permission */}
215
- {features.creation && permissions.canCreate.can && onCreateRow && (
215
+ {(() => {
216
+ // Debug logging for creation button visibility
217
+ if (import.meta.env.MODE === 'development') {
218
+ const logger = console;
219
+ logger.debug('[DataTableToolbar] Creation button check:', {
220
+ 'features.creation': features.creation,
221
+ 'permissions.canCreate.can': permissions.canCreate.can,
222
+ 'onCreateRow provided': !!onCreateRow,
223
+ 'will show button': features.creation && permissions.canCreate.can && onCreateRow
224
+ });
225
+ }
226
+
227
+ return features.creation && permissions.canCreate.can && onCreateRow;
228
+ })() && (
216
229
  <Button
217
230
  variant="outline"
218
231
  onClick={onCreateRow}