@jmruthers/pace-core 0.5.134 → 0.5.136
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.
- package/dist/{DataTable-C7GaRZye.d.ts → DataTable-CWAZZcXC.d.ts} +1 -1
- package/dist/{DataTable-A36PJG6N.js → DataTable-CYOHOX3O.js} +25 -13
- package/dist/{PublicLoadingSpinner-CUAnTvcg.d.ts → EventLogo-801uofbR.d.ts} +51 -135
- package/dist/UnifiedAuthProvider-5E5TUNMS.js +17 -0
- package/dist/{UnifiedAuthProvider-BVKmQd9u.d.ts → UnifiedAuthProvider-DJxGTftH.d.ts} +1 -1
- package/dist/{api-TNIBJWLM.js → api-45XYYO2A.js} +4 -3
- package/dist/{audit-T36HM7IM.js → audit-64X3VJXB.js} +3 -2
- package/dist/{chunk-CTJRBUX2.js → chunk-2TWNJ46Y.js} +2 -2
- package/dist/{chunk-UJI6WSMD.js → chunk-444EZN6N.js} +3 -3
- package/dist/chunk-444EZN6N.js.map +1 -0
- package/dist/{chunk-3CG5L6RN.js → chunk-4MT5BGGL.js} +90 -73
- package/dist/chunk-4MT5BGGL.js.map +1 -0
- package/dist/{chunk-PYUXFQJ3.js → chunk-56XJ3TU6.js} +2 -2
- package/dist/chunk-56XJ3TU6.js.map +1 -0
- package/dist/chunk-5DPZ5EAT.js +60 -0
- package/dist/chunk-5DPZ5EAT.js.map +1 -0
- package/dist/{chunk-66C4BSAY.js → chunk-ANBQRTPX.js} +9 -2
- package/dist/chunk-ANBQRTPX.js.map +1 -0
- package/dist/chunk-APIBCTL2.js +670 -0
- package/dist/chunk-APIBCTL2.js.map +1 -0
- package/dist/{chunk-GKHF54DI.js → chunk-BESYRHQM.js} +10 -4
- package/dist/chunk-BESYRHQM.js.map +1 -0
- package/dist/{chunk-WP5I5GLN.js → chunk-BVYWGZVV.js} +112 -97
- package/dist/chunk-BVYWGZVV.js.map +1 -0
- package/dist/{chunk-GEVIB2UB.js → chunk-ERISIBYU.js} +14 -5
- package/dist/chunk-ERISIBYU.js.map +1 -0
- package/dist/{chunk-CQZU6TFE.js → chunk-FHWWBIHA.js} +100 -62
- package/dist/chunk-FHWWBIHA.js.map +1 -0
- package/dist/{chunk-O3NWNXDY.js → chunk-FMUCXFII.js} +2 -2
- package/dist/chunk-FMUCXFII.js.map +1 -0
- package/dist/{chunk-GVDR7WNV.js → chunk-HJGGOMQ6.js} +194 -518
- package/dist/chunk-HJGGOMQ6.js.map +1 -0
- package/dist/{chunk-BDZUMRBD.js → chunk-K2WWTH7O.js} +13 -6
- package/dist/chunk-K2WWTH7O.js.map +1 -0
- package/dist/{chunk-BYXRHAIF.js → chunk-L6PGMCMD.js} +23 -14
- package/dist/chunk-L6PGMCMD.js.map +1 -0
- package/dist/chunk-LMC26NLJ.js +84 -0
- package/dist/chunk-LMC26NLJ.js.map +1 -0
- package/dist/{chunk-M6DDYFUD.js → chunk-LS353YLY.js} +19 -16
- package/dist/chunk-LS353YLY.js.map +1 -0
- package/dist/{chunk-ZYZCRSBD.js → chunk-LTV3XIJJ.js} +16 -11
- package/dist/chunk-LTV3XIJJ.js.map +1 -0
- package/dist/{chunk-HMNOSGVA.js → chunk-NOHEVYVX.js} +377 -666
- package/dist/chunk-NOHEVYVX.js.map +1 -0
- package/dist/{chunk-JCQZ6LA7.js → chunk-Q5QRDWKI.js} +9 -3
- package/dist/chunk-Q5QRDWKI.js.map +1 -0
- package/dist/chunk-S5OFRT4M.js +94 -0
- package/dist/chunk-S5OFRT4M.js.map +1 -0
- package/dist/{chunk-3DBFLLLU.js → chunk-SBVILCCA.js} +14 -9
- package/dist/chunk-SBVILCCA.js.map +1 -0
- package/dist/{chunk-TGIY2AR2.js → chunk-SL2YQDR6.js} +4 -3
- package/dist/{chunk-TGIY2AR2.js.map → chunk-SL2YQDR6.js.map} +1 -1
- package/dist/{chunk-VZ5OR6HD.js → chunk-TVYPTYOY.js} +55 -179
- package/dist/chunk-TVYPTYOY.js.map +1 -0
- package/dist/{chunk-ZV77RZMU.js → chunk-XARJS7CD.js} +2 -2
- package/dist/chunk-XDNLUEXI.js +138 -0
- package/dist/chunk-XDNLUEXI.js.map +1 -0
- package/dist/{chunk-F64FFPOZ.js → chunk-YLKIDTUK.js} +26 -20
- package/dist/chunk-YLKIDTUK.js.map +1 -0
- package/dist/{chunk-5F3NDPJV.js → chunk-ZZ2SS7NI.js} +10 -5
- package/dist/chunk-ZZ2SS7NI.js.map +1 -0
- package/dist/components.d.ts +7 -287
- package/dist/components.js +26 -157
- package/dist/components.js.map +1 -1
- package/dist/{file-reference-C9isKNPn.d.ts → file-reference-C6Gkn77H.d.ts} +1 -1
- package/dist/{formatting-DFcCxUEk.d.ts → formatting-CvUXy2mF.d.ts} +1 -1
- package/dist/hooks.d.ts +3 -3
- package/dist/hooks.js +22 -16
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +219 -9
- package/dist/index.js +49 -31
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +5 -4
- package/dist/rbac/index.js +13 -12
- package/dist/styles/index.js +2 -1
- package/dist/theming/runtime.d.ts +2 -19
- package/dist/theming/runtime.js +2 -1
- package/dist/{types-D5rqZQXk.d.ts → types-Dfz9dmVH.d.ts} +12 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/dist/{useInactivityTracker-MRUU55XI.js → useInactivityTracker-TO6ZOF35.js} +3 -2
- package/dist/{usePublicRouteParams-Dyt1tzI9.d.ts → usePublicRouteParams-B7PabvuH.d.ts} +1 -1
- package/dist/utils.d.ts +195 -232
- package/dist/utils.js +173 -331
- package/dist/utils.js.map +1 -1
- package/dist/{validation-DnhrNMju.d.ts → validation-8npbysjg.d.ts} +26 -8
- package/dist/validation.d.ts +261 -10
- package/dist/validation.js +82 -440
- package/dist/validation.js.map +1 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +6 -6
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +6 -6
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +7 -7
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +4 -4
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +29 -4
- package/docs/api/interfaces/DataAccessRecord.md +9 -9
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +18 -18
- package/docs/api/interfaces/DataTableColumn.md +61 -1
- package/docs/api/interfaces/DataTableProps.md +3 -3
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +14 -14
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +152 -0
- package/docs/api/interfaces/ExportColumn.md +90 -0
- package/docs/api/interfaces/ExportOptions.md +126 -0
- package/docs/api/interfaces/FileDisplayProps.md +15 -15
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
- package/docs/api/interfaces/NavigationContextType.md +9 -9
- package/docs/api/interfaces/NavigationGuardProps.md +10 -10
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +7 -7
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
- package/docs/api/interfaces/PaceLoginPageProps.md +4 -4
- package/docs/api/interfaces/PageAccessRecord.md +8 -8
- package/docs/api/interfaces/PagePermissionContextType.md +8 -8
- package/docs/api/interfaces/PagePermissionGuardProps.md +11 -11
- package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
- package/docs/api/interfaces/PaletteData.md +4 -4
- package/docs/api/interfaces/PermissionEnforcerProps.md +11 -11
- package/docs/api/interfaces/ProtectedRouteProps.md +6 -6
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
- package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +10 -10
- package/docs/api/interfaces/RouteConfig.md +10 -10
- package/docs/api/interfaces/SecureDataContextType.md +9 -9
- package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +21 -0
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +9 -9
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
- package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
- package/docs/api/interfaces/UsePublicEventReturn.md +5 -5
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +9 -9
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +4 -4
- package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
- package/docs/api/interfaces/UserEventAccess.md +11 -11
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +648 -212
- package/docs/api-reference/components.md +106 -26
- package/docs/architecture/README.md +0 -2
- package/docs/implementation-guides/data-tables.md +277 -13
- package/docs/implementation-guides/forms.md +1 -16
- package/docs/implementation-guides/permission-enforcement.md +8 -2
- package/examples/README.md +30 -14
- package/examples/STRUCTURE.md +125 -0
- package/examples/components/DataTable/HierarchicalActionsExample.tsx +421 -0
- package/examples/components/DataTable/HierarchicalExample.tsx +475 -0
- package/examples/components/DataTable/InitialPageSizeExample.tsx +177 -0
- package/examples/components/DataTable/PerformanceExample.tsx +506 -0
- package/examples/components/DataTable/index.ts +13 -0
- package/examples/components/Dialog/BasicHtmlTest.tsx +55 -0
- package/examples/components/Dialog/DebugHtmlExample.tsx +68 -0
- package/examples/components/Dialog/HtmlDialogExample.tsx +202 -0
- package/examples/components/Dialog/ScrollableDialogExample.tsx +290 -0
- package/examples/components/Dialog/SimpleHtmlTest.tsx +61 -0
- package/examples/components/Dialog/SmartDialogExample.tsx +322 -0
- package/examples/components/Dialog/index.ts +15 -0
- package/examples/components/index.ts +11 -0
- package/examples/features/index.ts +12 -0
- package/examples/{public-pages → features/public-pages}/CorrectPublicPageImplementation.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicEventPage.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicPageApp.tsx +1 -1
- package/examples/{public-pages → features/public-pages}/PublicPageUsageExample.tsx +1 -1
- package/examples/index.ts +11 -3
- package/package.json +30 -10
- package/src/components/Alert/Alert.tsx +1 -1
- package/src/components/Avatar/Avatar.tsx +1 -1
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Card/Card.tsx +1 -1
- package/src/components/Checkbox/Checkbox.tsx +1 -1
- package/src/components/DataTable/DataTable.test.tsx +1 -1
- package/src/components/DataTable/DataTable.tsx +1 -30
- package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +562 -0
- package/src/components/DataTable/__tests__/styles.test.ts +2 -2
- package/src/components/DataTable/components/ActionButtons.tsx +0 -15
- package/src/components/DataTable/components/DataTableCore.tsx +4 -185
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +1 -1
- package/src/components/DataTable/components/DataTableModals.tsx +1 -27
- package/src/components/DataTable/components/EditableRow.tsx +1 -1
- package/src/components/DataTable/components/ImportModal.tsx +2 -14
- package/src/components/DataTable/components/PaginationControls.tsx +1 -1
- package/src/components/DataTable/components/UnifiedTableBody.tsx +109 -82
- package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +1 -1
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +1 -1
- package/src/components/DataTable/examples/GroupingAggregationExample.tsx +273 -0
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +1 -1
- package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +1 -1
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +1 -1
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +1 -1
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +2 -23
- package/src/components/DataTable/index.ts +4 -0
- package/src/components/DataTable/styles.ts +1 -1
- package/src/components/DataTable/types.ts +13 -0
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +1 -1
- package/src/components/DataTable/utils/aggregationUtils.ts +161 -0
- package/src/components/DataTable/utils/exportUtils.ts +1 -1
- package/src/components/DataTable/utils/flexibleImport.ts +1 -11
- package/src/components/DataTable/utils/index.ts +1 -0
- package/src/components/DataTable/utils/paginationUtils.ts +1 -1
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +35 -7
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +5 -4
- package/src/components/EventSelector/EventSelector.tsx +3 -2
- package/src/components/FileDisplay/FileDisplay.tsx +2 -36
- package/src/components/FileUpload/FileUpload.test.tsx +2 -2
- package/src/components/FileUpload/FileUpload.tsx +2 -2
- package/src/components/Footer/Footer.tsx +1 -1
- package/src/components/Form/Form.test.tsx +4 -509
- package/src/components/Form/Form.tsx +1 -1
- package/src/components/Form/FormField.tsx +1 -1
- package/src/components/Form/index.ts +0 -12
- package/src/components/Header/Header.tsx +1 -1
- package/src/components/Input/Input.tsx +1 -1
- package/src/components/Label/Label.tsx +1 -1
- package/src/components/LoginForm/LoginForm.tsx +1 -1
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -3
- package/src/components/NavigationMenu/NavigationMenu.tsx +9 -8
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +4 -3
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -12
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +0 -16
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +0 -1
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -9
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +35 -3
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +13 -12
- package/src/components/PasswordReset/PasswordChangeForm.tsx +1 -1
- package/src/components/PasswordReset/index.ts +0 -2
- package/src/components/Progress/Progress.tsx +1 -1
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +35 -8
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -2
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +1 -1
- package/src/components/PublicLayout/PublicPageContextChecker.tsx +44 -43
- package/src/components/PublicLayout/PublicPageFooter.tsx +1 -1
- package/src/components/PublicLayout/PublicPageHeader.tsx +1 -15
- package/src/components/PublicLayout/PublicPageProvider.tsx +3 -2
- package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +2 -0
- package/src/components/PublicLayout/index.ts +4 -2
- package/src/components/Select/Select.tsx +1 -1
- package/src/components/{SessionRestorationLoader.tsx → SessionRestorationLoader/SessionRestorationLoader.tsx} +3 -2
- package/src/components/SessionRestorationLoader/index.ts +3 -0
- package/src/components/Switch/Switch.tsx +1 -1
- package/src/components/Table/Table.tsx +1 -1
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/components/index.ts +4 -10
- package/src/hooks/__tests__/hooks.integration.test.tsx +37 -22
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +33 -17
- package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +28 -3
- package/src/hooks/__tests__/useFileDisplay.unit.test.ts +36 -9
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +26 -2
- package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +19 -6
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -4
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +17 -4
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +26 -6
- package/src/hooks/__tests__/usePublicFileDisplay.test.ts +16 -6
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +3 -3
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +17 -3
- package/src/hooks/public/usePublicEvent.ts +7 -6
- package/src/hooks/public/usePublicEventLogo.ts +7 -4
- package/src/hooks/public/usePublicFileDisplay.ts +6 -150
- package/src/hooks/useComponentPerformance.ts +4 -1
- package/src/hooks/useDataTablePerformance.ts +4 -3
- package/src/hooks/useEventTheme.test.ts +18 -5
- package/src/hooks/useEventTheme.ts +4 -1
- package/src/hooks/useEvents.ts +2 -0
- package/src/hooks/useFileDisplay.ts +9 -8
- package/src/hooks/useFileReference.ts +4 -1
- package/src/hooks/useFileUrl.ts +4 -1
- package/src/hooks/useInactivityTracker.ts +5 -4
- package/src/hooks/useOrganisationSecurity.test.ts +33 -12
- package/src/hooks/useOrganisationSecurity.ts +8 -7
- package/src/hooks/usePerformanceMonitor.ts +6 -3
- package/src/hooks/usePermissionCache.ts +13 -6
- package/src/hooks/useSecureDataAccess.test.ts +2 -2
- package/src/hooks/useSecureDataAccess.ts +9 -8
- package/src/hooks/useSessionRestoration.ts +4 -1
- package/src/hooks/useStorage.ts +4 -1
- package/src/index.ts +25 -8
- package/src/providers/services/AuthServiceProvider.tsx +3 -2
- package/src/providers/services/EventServiceProvider.tsx +2 -1
- package/src/providers/services/InactivityServiceProvider.tsx +2 -1
- package/src/providers/services/OrganisationServiceProvider.tsx +2 -1
- package/src/providers/services/UnifiedAuthProvider.tsx +4 -3
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +22 -2
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +24 -2
- package/src/rbac/__tests__/cache-invalidation.test.ts +20 -6
- package/src/rbac/api.ts +5 -2
- package/src/rbac/audit-enhanced.ts +6 -6
- package/src/rbac/audit.test.ts +60 -38
- package/src/rbac/audit.ts +8 -8
- package/src/rbac/cache-invalidation.ts +7 -4
- package/src/rbac/components/EnhancedNavigationMenu.tsx +11 -5
- package/src/rbac/components/NavigationGuard.tsx +7 -3
- package/src/rbac/components/NavigationProvider.tsx +6 -3
- package/src/rbac/components/PagePermissionGuard.tsx +28 -16
- package/src/rbac/components/PagePermissionProvider.tsx +4 -1
- package/src/rbac/components/PermissionEnforcer.tsx +9 -3
- package/src/rbac/components/RoleBasedRouter.tsx +3 -1
- package/src/rbac/components/SecureDataProvider.tsx +7 -3
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +87 -61
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +83 -33
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +36 -13
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +2 -2
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +22 -8
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +19 -6
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +43 -17
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +42 -17
- package/src/rbac/engine.ts +15 -7
- package/src/rbac/hooks/usePermissions.ts +7 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +2 -2
- package/src/rbac/hooks/useResolvedScope.ts +10 -7
- package/src/rbac/permissions.ts +5 -2
- package/src/rbac/security.test.ts +27 -16
- package/src/rbac/security.ts +5 -4
- package/src/services/AuthService.ts +22 -21
- package/src/services/EventService.ts +12 -12
- package/src/services/InactivityService.ts +5 -4
- package/src/services/OrganisationService.ts +26 -25
- package/src/services/__tests__/AuthService.test.ts +51 -19
- package/src/services/__tests__/EventService.test.ts +37 -5
- package/src/services/__tests__/InactivityService.test.ts +38 -4
- package/src/services/__tests__/OrganisationService.test.ts +3 -8
- package/src/services/base/BaseService.ts +3 -1
- package/src/theming/__tests__/runtime.test.ts +21 -12
- package/src/theming/parseEventColours.ts +5 -19
- package/src/theming/runtime.ts +8 -4
- package/src/types/validation.ts +2 -29
- package/src/utils/__tests__/appConfig.unit.test.ts +1 -1
- package/src/utils/__tests__/audit.unit.test.ts +1 -1
- package/src/utils/__tests__/auth-utils.unit.test.ts +1 -1
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +19 -19
- package/src/utils/__tests__/cn.unit.test.ts +1 -1
- package/src/utils/__tests__/debugLogger.test.ts +1 -1
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -1
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/formatting.unit.test.ts +1 -1
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +1 -1
- package/src/utils/__tests__/logger.unit.test.ts +1 -1
- package/src/utils/__tests__/organisationContext.unit.test.ts +1 -1
- package/src/utils/__tests__/performanceBenchmark.test.ts +1 -1
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +1 -1
- package/src/utils/__tests__/permissionTypes.unit.test.ts +1 -1
- package/src/utils/__tests__/permissionUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/sanitization.unit.test.ts +1 -1
- package/src/utils/__tests__/schemaUtils.unit.test.ts +1 -1
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +1 -1
- package/src/utils/__tests__/secureErrors.unit.test.ts +33 -15
- package/src/utils/__tests__/secureStorage.unit.test.ts +1 -1
- package/src/utils/__tests__/security.unit.test.ts +40 -18
- package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -1
- package/src/utils/__tests__/sessionTracking.unit.test.ts +40 -29
- package/src/utils/__tests__/validationUtils.unit.test.ts +19 -6
- package/src/utils/{appIdResolver.test.ts → app/appIdResolver.test.ts} +28 -30
- package/src/utils/{appIdResolver.ts → app/appIdResolver.ts} +8 -5
- package/src/utils/{appNameResolver.test.ts → app/appNameResolver.test.ts} +1 -1
- package/src/utils/{appNameResolver.ts → app/appNameResolver.ts} +5 -1
- package/src/utils/{organisationContext.ts → context/organisationContext.ts} +6 -3
- package/src/utils/{sessionTracking.ts → context/sessionTracking.ts} +11 -12
- package/src/utils/{logger.ts → core/logger.ts} +4 -2
- package/src/utils/{deviceFingerprint.ts → device/deviceFingerprint.ts} +1 -1
- package/src/utils/{lazyLoad.tsx → dynamic/lazyLoad.tsx} +2 -2
- package/src/utils/{file-reference.test.ts → file-reference/__tests__/file-reference.test.ts} +5 -5
- package/src/utils/{file-reference.ts → file-reference/index.ts} +20 -38
- package/src/utils/index.ts +32 -54
- package/src/utils/{secureErrors.ts → security/secureErrors.ts} +6 -3
- package/src/utils/{security.ts → security/security.ts} +5 -2
- package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -4
- package/src/utils/storage/helpers.ts +15 -8
- package/src/{components/Dialog/utils/__tests__/safeHtml.unit.test.ts → utils/validation/__tests__/htmlSanitization.unit.test.ts} +9 -15
- package/src/{validation → utils/validation}/csrf.ts +1 -1
- package/src/{components/Dialog/utils/safeHtml.ts → utils/validation/htmlSanitization.ts} +9 -10
- package/src/utils/validation/index.ts +79 -0
- package/src/utils/{sanitization.ts → validation/sanitization.ts} +71 -2
- package/src/{validation/schemaUtils.ts → utils/validation/schema.ts} +11 -6
- package/src/{validation → utils/validation}/sqlInjectionProtection.ts +2 -0
- package/src/utils/{validationUtils.ts → validation/validationUtils.ts} +4 -1
- package/src/validation/index.ts +3 -34
- package/dist/UnifiedAuthProvider-CQDZRJIS.js +0 -16
- package/dist/chunk-24MKLB7U.js +0 -81
- package/dist/chunk-24MKLB7U.js.map +0 -1
- package/dist/chunk-3CG5L6RN.js.map +0 -1
- package/dist/chunk-3DBFLLLU.js.map +0 -1
- package/dist/chunk-5F3NDPJV.js.map +0 -1
- package/dist/chunk-66C4BSAY.js.map +0 -1
- package/dist/chunk-BDZUMRBD.js.map +0 -1
- package/dist/chunk-BYXRHAIF.js.map +0 -1
- package/dist/chunk-CDQ3PX7L.js +0 -18
- package/dist/chunk-CDQ3PX7L.js.map +0 -1
- package/dist/chunk-CQZU6TFE.js.map +0 -1
- package/dist/chunk-F64FFPOZ.js.map +0 -1
- package/dist/chunk-GEVIB2UB.js.map +0 -1
- package/dist/chunk-GKHF54DI.js.map +0 -1
- package/dist/chunk-GVDR7WNV.js.map +0 -1
- package/dist/chunk-HMNOSGVA.js.map +0 -1
- package/dist/chunk-JCQZ6LA7.js.map +0 -1
- package/dist/chunk-M6DDYFUD.js.map +0 -1
- package/dist/chunk-O3NWNXDY.js.map +0 -1
- package/dist/chunk-PYUXFQJ3.js.map +0 -1
- package/dist/chunk-UJI6WSMD.js.map +0 -1
- package/dist/chunk-VZ5OR6HD.js.map +0 -1
- package/dist/chunk-WP5I5GLN.js.map +0 -1
- package/dist/chunk-ZYZCRSBD.js.map +0 -1
- package/src/components/Dialog/README.md +0 -804
- package/src/components/Form/FormErrorSummary.tsx +0 -113
- package/src/components/Form/FormFieldset.tsx +0 -127
- package/src/components/Form/FormLiveRegion.tsx +0 -198
- package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
- package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
- package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
- package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +0 -185
- package/src/examples/CorrectPublicPageImplementation.tsx +0 -304
- package/src/examples/PublicEventPage.tsx +0 -287
- package/src/examples/PublicPageApp.tsx +0 -321
- package/src/examples/PublicPageUsageExample.tsx +0 -218
- package/src/utils/schemaUtils.ts +0 -37
- package/src/validation/__tests__/common.unit.test.ts +0 -101
- package/src/validation/__tests__/csrf.unit.test.ts +0 -365
- package/src/validation/__tests__/passwordSchema.unit.test.ts +0 -203
- package/src/validation/__tests__/sanitization.unit.test.ts +0 -250
- package/src/validation/__tests__/schemaUtils.unit.test.ts +0 -451
- package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +0 -462
- package/src/validation/__tests__/user.unit.test.ts +0 -440
- package/src/validation/sanitization.ts +0 -96
- /package/dist/{DataTable-A36PJG6N.js.map → DataTable-CYOHOX3O.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-CQDZRJIS.js.map → UnifiedAuthProvider-5E5TUNMS.js.map} +0 -0
- /package/dist/{api-TNIBJWLM.js.map → api-45XYYO2A.js.map} +0 -0
- /package/dist/{audit-T36HM7IM.js.map → audit-64X3VJXB.js.map} +0 -0
- /package/dist/{chunk-CTJRBUX2.js.map → chunk-2TWNJ46Y.js.map} +0 -0
- /package/dist/{chunk-ZV77RZMU.js.map → chunk-XARJS7CD.js.map} +0 -0
- /package/dist/{useInactivityTracker-MRUU55XI.js.map → useInactivityTracker-TO6ZOF35.js.map} +0 -0
- /package/examples/{public-pages → features/public-pages}/index.ts +0 -0
- /package/examples/{RBAC → features/rbac}/CompleteRBACExample.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/EventBasedApp.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/PermissionExample.tsx +0 -0
- /package/examples/{RBAC → features/rbac}/index.ts +0 -0
- /package/src/utils/{appConfig.ts → app/appConfig.ts} +0 -0
- /package/src/utils/{appNameResolver.simple.test.ts → app/appNameResolver.simple.test.ts} +0 -0
- /package/src/utils/{audit.ts → audit/audit.ts} +0 -0
- /package/src/utils/{organisationContext.test.ts → context/organisationContext.test.ts} +0 -0
- /package/src/utils/{cn.ts → core/cn.ts} +0 -0
- /package/src/utils/{debugLogger.ts → core/debugLogger.ts} +0 -0
- /package/src/utils/{dynamicUtils.ts → dynamic/dynamicUtils.ts} +0 -0
- /package/src/utils/{formatDate.test.ts → formatting/formatDate.test.ts} +0 -0
- /package/src/utils/{formatting.ts → formatting/formatting.ts} +0 -0
- /package/src/utils/{bundleAnalysis.ts → performance/bundleAnalysis.ts} +0 -0
- /package/src/utils/{performanceBenchmark.ts → performance/performanceBenchmark.ts} +0 -0
- /package/src/utils/{performanceBudgets.ts → performance/performanceBudgets.ts} +0 -0
- /package/src/utils/{permissionTypes.ts → permissions/permissionTypes.ts} +0 -0
- /package/src/utils/{permissionUtils.test.ts → permissions/permissionUtils.test.ts} +0 -0
- /package/src/utils/{permissionUtils.ts → permissions/permissionUtils.ts} +0 -0
- /package/src/utils/{auth-utils.ts → security/auth-utils.ts} +0 -0
- /package/src/utils/{secureDataAccess.test.ts → security/secureDataAccess.test.ts} +0 -0
- /package/src/utils/{secureDataAccess.ts → security/secureDataAccess.ts} +0 -0
- /package/src/utils/{secureStorage.ts → security/secureStorage.ts} +0 -0
- /package/src/utils/{securityMonitor.ts → security/securityMonitor.ts} +0 -0
- /package/src/{validation → utils/validation}/common.ts +0 -0
- /package/src/{validation → utils/validation}/passwordSchema.ts +0 -0
- /package/src/{validation → utils/validation}/user.ts +0 -0
- /package/src/utils/{validation.ts → validation/validation.ts} +0 -0
|
@@ -22,11 +22,12 @@ import { EditableRow } from './EditableRow';
|
|
|
22
22
|
import { getTableCellClasses, getTableHeadClasses, getTableRowClasses } from '../styles';
|
|
23
23
|
import { Input } from '../../Input/Input';
|
|
24
24
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SelectGroup, SelectLabel, SelectSeparator } from '../../Select/Select';
|
|
25
|
-
import { createLogger } from '../../../utils/logger';
|
|
25
|
+
import { createLogger } from '../../../utils/core/logger';
|
|
26
26
|
import type {
|
|
27
27
|
AggregateConfig,
|
|
28
28
|
DataRecord,
|
|
29
29
|
DataTableAction,
|
|
30
|
+
DataTableColumn,
|
|
30
31
|
EditableColumnDef,
|
|
31
32
|
EmptyStateConfig,
|
|
32
33
|
HierarchicalConfig,
|
|
@@ -215,20 +216,6 @@ function SelectEditField<TData extends DataRecord>({
|
|
|
215
216
|
// Always show create option when there's a search term (user might want to create even if matches exist)
|
|
216
217
|
const shouldShow = isCreatable && !!columnDef.onCreateNew;
|
|
217
218
|
|
|
218
|
-
// Debug logging for creatable select
|
|
219
|
-
if (import.meta.env.MODE === 'development' && isCreatable) {
|
|
220
|
-
logger.debug('[SelectEditField] Creatable select check:', {
|
|
221
|
-
searchTerm: currentSearch,
|
|
222
|
-
searchLower,
|
|
223
|
-
hasMatch,
|
|
224
|
-
isCreatable,
|
|
225
|
-
hasOnCreateNew: !!columnDef.onCreateNew,
|
|
226
|
-
shouldShow,
|
|
227
|
-
fieldOptionsCount: columnDef.fieldOptions?.length || 0,
|
|
228
|
-
note: 'Create option shows when search term exists, regardless of matches'
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
219
|
setShowCreateOption(shouldShow);
|
|
233
220
|
} else {
|
|
234
221
|
setShowCreateOption(false);
|
|
@@ -529,6 +516,7 @@ const RowComponent = React.memo(({
|
|
|
529
516
|
}: RowProps) => {
|
|
530
517
|
const rowRef = useRef<HTMLTableRowElement>(null);
|
|
531
518
|
const firstInputRef = useRef<HTMLInputElement>(null);
|
|
519
|
+
const logger = React.useMemo(() => createLogger('RowComponent'), []);
|
|
532
520
|
|
|
533
521
|
const rowId = getRowIdSafe(row.original, row.index, getRowId);
|
|
534
522
|
|
|
@@ -577,33 +565,115 @@ const RowComponent = React.memo(({
|
|
|
577
565
|
const groupValue = row.getValue(grouping[0]);
|
|
578
566
|
const subRowsCount = row.subRows?.length || 0;
|
|
579
567
|
const isExpanded = row.getIsExpanded();
|
|
568
|
+
const visibleCells = row.getVisibleCells();
|
|
569
|
+
|
|
570
|
+
// Get child rows for aggregation (convert TanStack Row to original data)
|
|
571
|
+
const childRows: DataRecord[] = row.subRows?.map((subRow: any) => subRow.original) || [];
|
|
580
572
|
|
|
581
|
-
//
|
|
573
|
+
// Render individual cells for each column with aggregation support
|
|
582
574
|
return (
|
|
583
575
|
<tr className="bg-sec-50 hover:bg-sec-100" style={style}>
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
576
|
+
{visibleCells.map((cell: any, cellIndex: number) => {
|
|
577
|
+
const columnDef = cell.column.columnDef as DataTableColumn<DataRecord>;
|
|
578
|
+
const isGroupingColumn = cellIndex === 0 || grouping.includes(cell.column.id || '');
|
|
579
|
+
|
|
580
|
+
// For the grouping column, show the group header with expand/collapse
|
|
581
|
+
if (isGroupingColumn && cellIndex === 0) {
|
|
582
|
+
return (
|
|
583
|
+
<td
|
|
584
|
+
key={cell.id}
|
|
585
|
+
className={getTableCellClasses({
|
|
586
|
+
isCompact: true,
|
|
587
|
+
className: "px-3 py-2 flex items-center font-medium"
|
|
588
|
+
})}
|
|
589
|
+
>
|
|
590
|
+
<Button
|
|
591
|
+
variant="ghost"
|
|
592
|
+
size="sm"
|
|
593
|
+
onClick={() => row.toggleExpanded()}
|
|
594
|
+
className="p-0 h-auto mr-2"
|
|
595
|
+
>
|
|
596
|
+
{isExpanded ? (
|
|
597
|
+
<ChevronDown className="h-4 w-4" />
|
|
598
|
+
) : (
|
|
599
|
+
<ChevronRight className="h-4 w-4" />
|
|
600
|
+
)}
|
|
601
|
+
</Button>
|
|
602
|
+
<span className="text-sm">
|
|
603
|
+
{String(groupValue)} ({subRowsCount} items)
|
|
604
|
+
</span>
|
|
605
|
+
</td>
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// For other columns, check if they have aggregation functions
|
|
610
|
+
if (columnDef.aggregateFn && childRows.length > 0) {
|
|
611
|
+
try {
|
|
612
|
+
// Call the aggregation function with child rows
|
|
613
|
+
const aggregatedValue = columnDef.aggregateFn(childRows, columnDef);
|
|
614
|
+
|
|
615
|
+
// Use aggregateCell renderer if provided, otherwise use regular cell renderer
|
|
616
|
+
let cellContent: React.ReactNode;
|
|
617
|
+
if (columnDef.aggregateCell) {
|
|
618
|
+
cellContent = columnDef.aggregateCell(aggregatedValue, childRows, columnDef);
|
|
619
|
+
} else if (columnDef.cell) {
|
|
620
|
+
// Use regular cell renderer with a mock cell context
|
|
621
|
+
// Create a mock cell object for the aggregated value
|
|
622
|
+
const mockCell = {
|
|
623
|
+
...cell,
|
|
624
|
+
getValue: () => aggregatedValue,
|
|
625
|
+
renderValue: () => aggregatedValue,
|
|
626
|
+
};
|
|
627
|
+
cellContent = flexRender(columnDef.cell, {
|
|
628
|
+
...mockCell,
|
|
629
|
+
row: row,
|
|
630
|
+
column: cell.column,
|
|
631
|
+
cell: mockCell,
|
|
632
|
+
getValue: () => aggregatedValue,
|
|
633
|
+
renderValue: () => aggregatedValue,
|
|
634
|
+
});
|
|
635
|
+
} else {
|
|
636
|
+
// Fallback to displaying the raw value
|
|
637
|
+
cellContent = aggregatedValue != null ? String(aggregatedValue) : '';
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
return (
|
|
641
|
+
<td
|
|
642
|
+
key={cell.id}
|
|
643
|
+
className={getTableCellClasses({
|
|
644
|
+
isCompact: true,
|
|
645
|
+
className: `px-3 py-2 ${cell.column.columnDef.meta?.align === 'right' ? 'text-right' : ''}`
|
|
646
|
+
})}
|
|
647
|
+
>
|
|
648
|
+
{cellContent}
|
|
649
|
+
</td>
|
|
650
|
+
);
|
|
651
|
+
} catch (error) {
|
|
652
|
+
// If aggregation fails, show empty cell
|
|
653
|
+
logger.warn('Error in aggregation function:', error);
|
|
654
|
+
return (
|
|
655
|
+
<td
|
|
656
|
+
key={cell.id}
|
|
657
|
+
className={getTableCellClasses({
|
|
658
|
+
isCompact: true,
|
|
659
|
+
className: "px-3 py-2"
|
|
660
|
+
})}
|
|
661
|
+
/>
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// For columns without aggregation, show empty cell
|
|
667
|
+
return (
|
|
668
|
+
<td
|
|
669
|
+
key={cell.id}
|
|
670
|
+
className={getTableCellClasses({
|
|
671
|
+
isCompact: true,
|
|
672
|
+
className: "px-3 py-2"
|
|
673
|
+
})}
|
|
674
|
+
/>
|
|
675
|
+
);
|
|
676
|
+
})}
|
|
607
677
|
</tr>
|
|
608
678
|
);
|
|
609
679
|
}
|
|
@@ -774,49 +844,6 @@ export function UnifiedTableBody<TData extends Record<string, any>>({
|
|
|
774
844
|
const rows = table.getRowModel().rows;
|
|
775
845
|
const headerGroups = table.getHeaderGroups();
|
|
776
846
|
|
|
777
|
-
// Diagnostic logging when rows are empty but data exists
|
|
778
|
-
useEffect(() => {
|
|
779
|
-
if (rows.length === 0 && dataLength > 0) {
|
|
780
|
-
const tableState = table.getState();
|
|
781
|
-
const pagination = tableState.pagination;
|
|
782
|
-
const columnFilters = tableState.columnFilters;
|
|
783
|
-
const globalFilter = tableState.globalFilter;
|
|
784
|
-
const coreRows = table.getCoreRowModel().rows;
|
|
785
|
-
const prePaginationRows = table.getPrePaginationRowModel?.()?.rows || [];
|
|
786
|
-
const filteredRows = table.getFilteredRowModel?.()?.rows || [];
|
|
787
|
-
const sortedRows = table.getSortedRowModel?.()?.rows || [];
|
|
788
|
-
const rowCount = table.getRowCount();
|
|
789
|
-
const pageCount = table.getPageCount();
|
|
790
|
-
|
|
791
|
-
logger.warn('Rows empty but data exists!', {
|
|
792
|
-
dataLength,
|
|
793
|
-
rowsLength: rows.length,
|
|
794
|
-
coreRowsLength: coreRows.length,
|
|
795
|
-
prePaginationRowsLength: prePaginationRows.length,
|
|
796
|
-
filteredRowsLength: filteredRows.length,
|
|
797
|
-
sortedRowsLength: sortedRows.length,
|
|
798
|
-
rowCount,
|
|
799
|
-
pageCount,
|
|
800
|
-
pagination: {
|
|
801
|
-
pageIndex: pagination.pageIndex,
|
|
802
|
-
pageSize: pagination.pageSize,
|
|
803
|
-
},
|
|
804
|
-
columnFilters,
|
|
805
|
-
globalFilter,
|
|
806
|
-
tableOptions: {
|
|
807
|
-
getCoreRowModel: !!table.options.getCoreRowModel,
|
|
808
|
-
getFilteredRowModel: !!table.options.getFilteredRowModel,
|
|
809
|
-
getSortedRowModel: !!table.options.getSortedRowModel,
|
|
810
|
-
getPaginationRowModel: !!table.options.getPaginationRowModel,
|
|
811
|
-
manualPagination: table.options.manualPagination,
|
|
812
|
-
manualFiltering: table.options.manualFiltering,
|
|
813
|
-
manualSorting: table.options.manualSorting,
|
|
814
|
-
},
|
|
815
|
-
tableDataLength: table.options.data?.length || 0,
|
|
816
|
-
});
|
|
817
|
-
}
|
|
818
|
-
}, [rows.length, dataLength, table, logger]);
|
|
819
|
-
|
|
820
847
|
// CRITICAL FIX: Virtual scrolling requires a scroll container (parentRef).
|
|
821
848
|
// If virtualization is enabled but no scroll container exists, fall back to standard rendering.
|
|
822
849
|
// This fixes the bug where rows exist but nothing renders when virtualization is enabled.
|
|
@@ -16,7 +16,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
|
16
16
|
import { DataTableErrorBoundary, useDataTableErrorBoundary } from '../DataTableErrorBoundary';
|
|
17
17
|
|
|
18
18
|
// Mock logger
|
|
19
|
-
vi.mock('../../../utils/logger', () => ({
|
|
19
|
+
vi.mock('../../../utils/core/logger', () => ({
|
|
20
20
|
createLogger: () => ({
|
|
21
21
|
debug: vi.fn(),
|
|
22
22
|
info: vi.fn(),
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Grouping Aggregation Example
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/DataTable/Examples
|
|
5
|
+
* @since 0.6.0
|
|
6
|
+
*
|
|
7
|
+
* Complete example demonstrating grouped row aggregation in DataTable.
|
|
8
|
+
* This example shows how to use aggregation functions to display
|
|
9
|
+
* totals and averages in grouped rows, similar to the pace-cake diners table use case.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import { DataTable, sum, average, count, type DataTableColumn, type DataRecord } from '../index';
|
|
14
|
+
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// DATA INTERFACE
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
interface DinerData extends DataRecord {
|
|
20
|
+
id: string;
|
|
21
|
+
unit_number: string;
|
|
22
|
+
unit_name: string;
|
|
23
|
+
diet: string;
|
|
24
|
+
youth: number;
|
|
25
|
+
adults: number;
|
|
26
|
+
cost: number;
|
|
27
|
+
[key: string]: unknown; // Index signature to satisfy DataRecord constraint
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// SAMPLE DATA
|
|
32
|
+
// ============================================================================
|
|
33
|
+
|
|
34
|
+
const dinerData: DinerData[] = [
|
|
35
|
+
{ id: '1', unit_number: '101', unit_name: 'Alpha Unit', diet: 'Standard', youth: 10, adults: 5, cost: 100.50 },
|
|
36
|
+
{ id: '2', unit_number: '101', unit_name: 'Alpha Unit', diet: 'Standard', youth: 15, adults: 8, cost: 150.75 },
|
|
37
|
+
{ id: '3', unit_number: '101', unit_name: 'Alpha Unit', diet: 'Gluten Free', youth: 5, adults: 3, cost: 75.25 },
|
|
38
|
+
{ id: '4', unit_number: '102', unit_name: 'Beta Unit', diet: 'Standard', youth: 20, adults: 10, cost: 200.00 },
|
|
39
|
+
{ id: '5', unit_number: '102', unit_name: 'Beta Unit', diet: 'Standard', youth: 12, adults: 6, cost: 120.50 },
|
|
40
|
+
{ id: '6', unit_number: '102', unit_name: 'Beta Unit', diet: 'Vegetarian', youth: 8, adults: 4, cost: 90.00 },
|
|
41
|
+
{ id: '7', unit_number: '103', unit_name: 'Gamma Unit', diet: 'Standard', youth: 18, adults: 9, cost: 180.25 },
|
|
42
|
+
{ id: '8', unit_number: '103', unit_name: 'Gamma Unit', diet: 'Gluten Free', youth: 6, adults: 3, cost: 80.50 },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
// ============================================================================
|
|
46
|
+
// COLUMN DEFINITIONS
|
|
47
|
+
// ============================================================================
|
|
48
|
+
|
|
49
|
+
const columns: DataTableColumn<DinerData>[] = [
|
|
50
|
+
{
|
|
51
|
+
accessorKey: 'unit_number',
|
|
52
|
+
header: 'Unit #',
|
|
53
|
+
sortable: true,
|
|
54
|
+
enableGrouping: true,
|
|
55
|
+
size: 100,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
accessorKey: 'unit_name',
|
|
59
|
+
header: 'Unit Name',
|
|
60
|
+
sortable: true,
|
|
61
|
+
enableGrouping: true,
|
|
62
|
+
size: 150,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
accessorKey: 'diet',
|
|
66
|
+
header: 'Diet',
|
|
67
|
+
sortable: true,
|
|
68
|
+
enableGrouping: true,
|
|
69
|
+
size: 120,
|
|
70
|
+
cell: ({ row }: { row: { original: DinerData } }) => (
|
|
71
|
+
<span className="px-2 py-1 rounded text-xs font-medium bg-main-100 text-main-800 border border-main-300">
|
|
72
|
+
{row.original.diet}
|
|
73
|
+
</span>
|
|
74
|
+
),
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
accessorKey: 'youth',
|
|
78
|
+
header: 'Youth',
|
|
79
|
+
sortable: true,
|
|
80
|
+
fieldType: 'number',
|
|
81
|
+
size: 100,
|
|
82
|
+
aggregateFn: sum('youth'),
|
|
83
|
+
aggregateCell: (value: any) => (
|
|
84
|
+
<div className="text-right font-semibold">
|
|
85
|
+
{typeof value === 'number' ? value.toLocaleString() : '0'}
|
|
86
|
+
</div>
|
|
87
|
+
),
|
|
88
|
+
cell: ({ row }: { row: { original: DinerData } }) => (
|
|
89
|
+
<div className="text-right">
|
|
90
|
+
{row.original.youth.toLocaleString()}
|
|
91
|
+
</div>
|
|
92
|
+
),
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
accessorKey: 'adults',
|
|
96
|
+
header: 'Adults',
|
|
97
|
+
sortable: true,
|
|
98
|
+
fieldType: 'number',
|
|
99
|
+
size: 100,
|
|
100
|
+
aggregateFn: sum('adults'),
|
|
101
|
+
aggregateCell: (value: any) => (
|
|
102
|
+
<div className="text-right font-semibold">
|
|
103
|
+
{typeof value === 'number' ? value.toLocaleString() : '0'}
|
|
104
|
+
</div>
|
|
105
|
+
),
|
|
106
|
+
cell: ({ row }: { row: { original: DinerData } }) => (
|
|
107
|
+
<div className="text-right">
|
|
108
|
+
{row.original.adults.toLocaleString()}
|
|
109
|
+
</div>
|
|
110
|
+
),
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
accessorKey: 'cost',
|
|
114
|
+
header: 'Total Cost',
|
|
115
|
+
sortable: true,
|
|
116
|
+
fieldType: 'number',
|
|
117
|
+
size: 120,
|
|
118
|
+
aggregateFn: sum('cost'),
|
|
119
|
+
aggregateCell: (value: any) => (
|
|
120
|
+
<div className="text-right font-semibold font-mono">
|
|
121
|
+
${typeof value === 'number' ? value.toFixed(2) : '0.00'}
|
|
122
|
+
</div>
|
|
123
|
+
),
|
|
124
|
+
cell: ({ row }: { row: { original: DinerData } }) => (
|
|
125
|
+
<div className="text-right font-mono">
|
|
126
|
+
${row.original.cost.toFixed(2)}
|
|
127
|
+
</div>
|
|
128
|
+
),
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
accessorKey: 'id',
|
|
132
|
+
header: 'Count',
|
|
133
|
+
sortable: false,
|
|
134
|
+
size: 80,
|
|
135
|
+
aggregateFn: count(),
|
|
136
|
+
aggregateCell: (value: any) => (
|
|
137
|
+
<div className="text-center font-semibold">
|
|
138
|
+
{typeof value === 'number' ? value : '0'}
|
|
139
|
+
</div>
|
|
140
|
+
),
|
|
141
|
+
cell: () => null as React.ReactNode, // Hide count for individual rows
|
|
142
|
+
},
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
// ============================================================================
|
|
146
|
+
// EXAMPLE COMPONENT
|
|
147
|
+
// ============================================================================
|
|
148
|
+
|
|
149
|
+
export function GroupingAggregationExample() {
|
|
150
|
+
return (
|
|
151
|
+
<div className="p-6 space-y-6">
|
|
152
|
+
<div>
|
|
153
|
+
<h1 className="text-2xl font-bold text-main-900 mb-2">
|
|
154
|
+
Grouped Row Aggregation Example
|
|
155
|
+
</h1>
|
|
156
|
+
<p className="text-sec-600">
|
|
157
|
+
This example demonstrates how to use aggregation functions in grouped DataTable rows.
|
|
158
|
+
When rows are grouped by Unit or Diet, the Youth, Adults, and Cost columns show
|
|
159
|
+
aggregated totals, and the Count column shows the number of records in each group.
|
|
160
|
+
</p>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<div className="bg-main-50 border border-main-200 rounded-md p-4 space-y-2">
|
|
164
|
+
<p className="font-medium text-sm">How to use:</p>
|
|
165
|
+
<ol className="list-decimal list-inside text-sm space-y-1 text-sec-700">
|
|
166
|
+
<li>Use the grouping dropdown to group by Unit #, Unit Name, or Diet</li>
|
|
167
|
+
<li>Notice how the Youth, Adults, and Cost columns show aggregated totals in grouped rows</li>
|
|
168
|
+
<li>The Count column shows the number of records in each group</li>
|
|
169
|
+
<li>Click the expand/collapse arrows to see individual rows within each group</li>
|
|
170
|
+
</ol>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<DataTable<DinerData>
|
|
174
|
+
data={dinerData}
|
|
175
|
+
columns={columns}
|
|
176
|
+
title="Diners by Unit and Diet"
|
|
177
|
+
description="Example showing aggregated values in grouped rows"
|
|
178
|
+
rbac={{ pageName: 'diners-example' }}
|
|
179
|
+
features={{
|
|
180
|
+
search: true,
|
|
181
|
+
pagination: true,
|
|
182
|
+
sorting: true,
|
|
183
|
+
filtering: true,
|
|
184
|
+
grouping: true,
|
|
185
|
+
columnVisibility: true,
|
|
186
|
+
columnReordering: false,
|
|
187
|
+
selection: false,
|
|
188
|
+
creation: false,
|
|
189
|
+
editing: false,
|
|
190
|
+
deletion: false,
|
|
191
|
+
deleteSelected: false,
|
|
192
|
+
import: false,
|
|
193
|
+
export: true,
|
|
194
|
+
}}
|
|
195
|
+
getRowId={(row: DinerData) => row.id}
|
|
196
|
+
variant="default"
|
|
197
|
+
className="border border-sec-200 rounded-lg"
|
|
198
|
+
/>
|
|
199
|
+
</div>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ============================================================================
|
|
204
|
+
// ALTERNATIVE EXAMPLES
|
|
205
|
+
// ============================================================================
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Example with custom aggregation function
|
|
209
|
+
*/
|
|
210
|
+
export function CustomAggregationExample() {
|
|
211
|
+
const customColumns: DataTableColumn<DinerData>[] = [
|
|
212
|
+
{
|
|
213
|
+
accessorKey: 'diet',
|
|
214
|
+
header: 'Diet',
|
|
215
|
+
enableGrouping: true,
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
accessorKey: 'youth',
|
|
219
|
+
header: 'Total Diners',
|
|
220
|
+
aggregateFn: (rows: DinerData[]) => {
|
|
221
|
+
// Custom: sum of youth + adults
|
|
222
|
+
return rows.reduce((total: number, row: DinerData) => total + (row.youth || 0) + (row.adults || 0), 0);
|
|
223
|
+
},
|
|
224
|
+
aggregateCell: (value: any) => (
|
|
225
|
+
<div className="text-right font-semibold">
|
|
226
|
+
{typeof value === 'number' ? value.toLocaleString() : '0'} total diners
|
|
227
|
+
</div>
|
|
228
|
+
),
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
accessorKey: 'cost',
|
|
232
|
+
header: 'Avg Cost per Diner',
|
|
233
|
+
aggregateFn: (rows: DinerData[]) => {
|
|
234
|
+
const totalCost = rows.reduce((sum: number, row: DinerData) => sum + (row.cost || 0), 0);
|
|
235
|
+
const totalDiners = rows.reduce((sum: number, row: DinerData) => sum + (row.youth || 0) + (row.adults || 0), 0);
|
|
236
|
+
return totalDiners > 0 ? totalCost / totalDiners : 0;
|
|
237
|
+
},
|
|
238
|
+
aggregateCell: (value: any) => (
|
|
239
|
+
<div className="text-right font-semibold font-mono">
|
|
240
|
+
${typeof value === 'number' ? value.toFixed(2) : '0.00'} per diner
|
|
241
|
+
</div>
|
|
242
|
+
),
|
|
243
|
+
},
|
|
244
|
+
];
|
|
245
|
+
|
|
246
|
+
return (
|
|
247
|
+
<div className="p-6 space-y-6">
|
|
248
|
+
<div>
|
|
249
|
+
<h2 className="text-xl font-bold text-main-900 mb-2">
|
|
250
|
+
Custom Aggregation Example
|
|
251
|
+
</h2>
|
|
252
|
+
<p className="text-sec-600">
|
|
253
|
+
This example shows custom aggregation functions that calculate
|
|
254
|
+
total diners and average cost per diner.
|
|
255
|
+
</p>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
<DataTable<DinerData>
|
|
259
|
+
data={dinerData}
|
|
260
|
+
columns={customColumns}
|
|
261
|
+
rbac={{ pageName: 'diners-custom' }}
|
|
262
|
+
features={{
|
|
263
|
+
grouping: true,
|
|
264
|
+
sorting: true,
|
|
265
|
+
pagination: true,
|
|
266
|
+
}}
|
|
267
|
+
defaultGrouping={['diet']}
|
|
268
|
+
getRowId={(row: DinerData) => row.id}
|
|
269
|
+
/>
|
|
270
|
+
</div>
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
@@ -12,7 +12,7 @@ import React from 'react';
|
|
|
12
12
|
import { DataTable } from '../DataTable';
|
|
13
13
|
import type { DataTableColumn, DataTableAction } from '../types';
|
|
14
14
|
import { Button } from '../../Button';
|
|
15
|
-
import { createLogger } from '../../../utils/logger';
|
|
15
|
+
import { createLogger } from '../../../utils/core/logger';
|
|
16
16
|
import {
|
|
17
17
|
PlusIcon,
|
|
18
18
|
PencilIcon,
|
|
@@ -12,7 +12,7 @@ import { useMemo, useRef } from 'react';
|
|
|
12
12
|
import { useUnifiedAuth } from '../../../providers/UnifiedAuthProvider';
|
|
13
13
|
import { useCan, useResolvedScope } from '../../../rbac/hooks';
|
|
14
14
|
import { useToast } from '../../../hooks/useToast';
|
|
15
|
-
import { createLogger } from '../../../utils/logger';
|
|
15
|
+
import { createLogger } from '../../../utils/core/logger';
|
|
16
16
|
import {
|
|
17
17
|
normalizeDataTableFeatures,
|
|
18
18
|
type DataTableFeatureConfig,
|
|
@@ -69,16 +69,7 @@ export function useDataTablePermissions<TData extends Record<string, any>>(
|
|
|
69
69
|
*/
|
|
70
70
|
|
|
71
71
|
// Use shared scope resolution hook for consistent RBAC scoping
|
|
72
|
-
const { selectedOrganisation, selectedEvent, supabase
|
|
73
|
-
|
|
74
|
-
// Debug logging to understand organisation context
|
|
75
|
-
logger.debug('Organisation context:', {
|
|
76
|
-
hasSelectedOrg: !!selectedOrganisation,
|
|
77
|
-
selectedOrgId: selectedOrganisation?.id,
|
|
78
|
-
hasOrganisations: organisations?.length > 0,
|
|
79
|
-
organisationCount: organisations?.length,
|
|
80
|
-
selectedEvent: selectedEvent?.event_id
|
|
81
|
-
});
|
|
72
|
+
const { selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();
|
|
82
73
|
|
|
83
74
|
const { resolvedScope: rawResolvedScope, isLoading: scopeLoading } = useResolvedScope({
|
|
84
75
|
supabase,
|
|
@@ -155,18 +146,6 @@ export function useDataTablePermissions<TData extends Record<string, any>>(
|
|
|
155
146
|
canExport: useCan(userId, consistentScope, readPermission, effectivePageId, true), // Use read permission for export
|
|
156
147
|
canImport: useCan(userId, consistentScope, createPermission, effectivePageId, true), // Use create permission for import
|
|
157
148
|
};
|
|
158
|
-
|
|
159
|
-
// Debug logging for permissions
|
|
160
|
-
logger.debug('Permission check results:', {
|
|
161
|
-
canRead: permissions.canRead.can,
|
|
162
|
-
canReadLoading: permissions.canRead.isLoading,
|
|
163
|
-
canReadError: permissions.canRead.error?.message,
|
|
164
|
-
canCreate: permissions.canCreate.can,
|
|
165
|
-
pageName: effectivePageId,
|
|
166
|
-
scope: consistentScope,
|
|
167
|
-
hasValidScope: !!effectiveScope,
|
|
168
|
-
scopeLoading: scopeLoading
|
|
169
|
-
});
|
|
170
149
|
|
|
171
150
|
// MANDATORY: Features are automatically filtered by permissions
|
|
172
151
|
const normalizedFeatures = useMemo(
|
|
@@ -29,6 +29,7 @@ export type { UseDataTablePerformanceOptions, UseDataTablePerformanceReturn } fr
|
|
|
29
29
|
|
|
30
30
|
// Type definitions
|
|
31
31
|
export type {
|
|
32
|
+
DataRecord,
|
|
32
33
|
DataTableColumn,
|
|
33
34
|
DataTableAction,
|
|
34
35
|
DataTableToolbarButton,
|
|
@@ -66,6 +67,9 @@ export * from './components';
|
|
|
66
67
|
// Utility functions
|
|
67
68
|
export * from './utils';
|
|
68
69
|
|
|
70
|
+
// Aggregation utilities (explicitly exported for convenience)
|
|
71
|
+
export { sum, average, count, min, max } from './utils/aggregationUtils';
|
|
72
|
+
|
|
69
73
|
// Accessibility utilities
|
|
70
74
|
export { announce } from './utils/a11yUtils';
|
|
71
75
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* This ensures consistent styling across regular and virtualized tables.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { cn } from '../../utils/cn';
|
|
11
|
+
import { cn } from '../../utils/core/cn';
|
|
12
12
|
|
|
13
13
|
// ============================================================================
|
|
14
14
|
// TABLE BASE STYLES
|
|
@@ -328,6 +328,19 @@ export interface DataTableColumn<TData extends DataRecord = DataRecord> extends
|
|
|
328
328
|
hideForParent?: boolean;
|
|
329
329
|
/** Hide this column for child rows */
|
|
330
330
|
hideForChild?: boolean;
|
|
331
|
+
|
|
332
|
+
// Grouped row aggregation
|
|
333
|
+
/**
|
|
334
|
+
* Aggregation function for grouped rows.
|
|
335
|
+
* Receives all rows in the group and returns the aggregated value.
|
|
336
|
+
* If not provided, grouped rows will show empty/undefined for this column.
|
|
337
|
+
*/
|
|
338
|
+
aggregateFn?: (rows: TData[], column: DataTableColumn<TData>) => any;
|
|
339
|
+
/**
|
|
340
|
+
* Optional: Custom cell renderer for aggregated values in grouped rows.
|
|
341
|
+
* If not provided, uses the column's regular cell renderer.
|
|
342
|
+
*/
|
|
343
|
+
aggregateCell?: (value: any, rows: TData[], column: DataTableColumn<TData>) => React.ReactNode;
|
|
331
344
|
}
|
|
332
345
|
|
|
333
346
|
/**
|