@jmruthers/pace-core 0.5.135 → 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 +101 -9
- package/dist/index.js +43 -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 +1 -1
- 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 +1 -1
- package/docs/api/interfaces/ExportOptions.md +8 -8
- 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 +514 -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 +16 -7
- 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
|
@@ -68,6 +68,7 @@ import { useLocation, useNavigate, Outlet } from 'react-router-dom';
|
|
|
68
68
|
import { useCan } from '../hooks';
|
|
69
69
|
import { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';
|
|
70
70
|
import { UUID, Permission, Scope, AccessLevel } from '../types';
|
|
71
|
+
import { getRBACLogger } from '../config';
|
|
71
72
|
|
|
72
73
|
export interface RouteConfig {
|
|
73
74
|
/** Route path */
|
|
@@ -307,7 +308,8 @@ export function RoleBasedRouter({
|
|
|
307
308
|
if (!currentRouteConfig) {
|
|
308
309
|
// Route not found in configuration
|
|
309
310
|
if (strictMode) {
|
|
310
|
-
|
|
311
|
+
const logger = getRBACLogger();
|
|
312
|
+
logger.error(`STRICT MODE VIOLATION: Route not found in configuration`, {
|
|
311
313
|
route: currentPath,
|
|
312
314
|
userId: user?.id,
|
|
313
315
|
timestamp: new Date().toISOString()
|
|
@@ -60,6 +60,7 @@ import React, { createContext, useContext, useState, useCallback, useMemo, useEf
|
|
|
60
60
|
import { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';
|
|
61
61
|
import { useSecureDataAccess } from '../../hooks/useSecureDataAccess';
|
|
62
62
|
import { UUID, Scope, Permission } from '../types';
|
|
63
|
+
import { getRBACLogger } from '../config';
|
|
63
64
|
|
|
64
65
|
export interface DataAccessRecord {
|
|
65
66
|
table: string;
|
|
@@ -215,7 +216,8 @@ export function SecureDataProvider({
|
|
|
215
216
|
try {
|
|
216
217
|
validateContext();
|
|
217
218
|
} catch (error) {
|
|
218
|
-
|
|
219
|
+
const logger = getRBACLogger();
|
|
220
|
+
logger.error('Organisation context validation failed:', error);
|
|
219
221
|
return false;
|
|
220
222
|
}
|
|
221
223
|
|
|
@@ -282,14 +284,16 @@ export function SecureDataProvider({
|
|
|
282
284
|
// Log strict mode violations
|
|
283
285
|
useEffect(() => {
|
|
284
286
|
if (strictMode && auditLog) {
|
|
285
|
-
|
|
287
|
+
const logger = getRBACLogger();
|
|
288
|
+
logger.debug('Strict mode enabled - all data access attempts will be logged and enforced');
|
|
286
289
|
}
|
|
287
290
|
}, [strictMode, auditLog]);
|
|
288
291
|
|
|
289
292
|
// Log RLS enforcement
|
|
290
293
|
useEffect(() => {
|
|
291
294
|
if (enforceRLS && auditLog) {
|
|
292
|
-
|
|
295
|
+
const logger = getRBACLogger();
|
|
296
|
+
logger.debug('RLS enforcement enabled - all queries will include organisation context');
|
|
293
297
|
}
|
|
294
298
|
}, [enforceRLS, auditLog]);
|
|
295
299
|
|
|
@@ -16,8 +16,31 @@ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
|
16
16
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
17
17
|
import { MemoryRouter } from 'react-router-dom';
|
|
18
18
|
|
|
19
|
+
// Mock the RBAC logger - define outside but reference in factory
|
|
20
|
+
const mockLogger = {
|
|
21
|
+
debug: vi.fn(),
|
|
22
|
+
error: vi.fn(),
|
|
23
|
+
warn: vi.fn(),
|
|
24
|
+
info: vi.fn(),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
vi.mock('../../config', () => ({
|
|
28
|
+
getRBACLogger: vi.fn(() => mockLogger),
|
|
29
|
+
getRBACConfig: vi.fn(() => ({
|
|
30
|
+
debug: true,
|
|
31
|
+
logLevel: 'debug',
|
|
32
|
+
developmentMode: true,
|
|
33
|
+
audit: {
|
|
34
|
+
enabled: true,
|
|
35
|
+
logLevel: 'debug'
|
|
36
|
+
}
|
|
37
|
+
})),
|
|
38
|
+
isDebugMode: vi.fn(() => true),
|
|
39
|
+
isDevelopmentMode: vi.fn(() => true),
|
|
40
|
+
}));
|
|
41
|
+
|
|
19
42
|
import { EnhancedNavigationMenu, EnhancedNavigationMenuProps } from '../EnhancedNavigationMenu';
|
|
20
|
-
import { NavigationProvider, NavigationItem } from '../NavigationProvider';
|
|
43
|
+
import { NavigationProvider, NavigationItem, useNavigationPermissions } from '../NavigationProvider';
|
|
21
44
|
import { useUnifiedAuth } from '../../../providers/UnifiedAuthProvider';
|
|
22
45
|
|
|
23
46
|
// Mock the UnifiedAuthProvider
|
|
@@ -25,23 +48,26 @@ vi.mock('../../../providers/UnifiedAuthProvider', () => ({
|
|
|
25
48
|
useUnifiedAuth: vi.fn()
|
|
26
49
|
}));
|
|
27
50
|
|
|
28
|
-
// Mock the
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
// Mock only the useNavigationPermissions hook, not the provider itself
|
|
52
|
+
// This allows the real NavigationProvider to render and call logger in useEffect
|
|
53
|
+
vi.mock('../NavigationProvider', async () => {
|
|
54
|
+
const actual = await vi.importActual('../NavigationProvider');
|
|
55
|
+
return {
|
|
56
|
+
...actual,
|
|
57
|
+
useNavigationPermissions: vi.fn(() => ({
|
|
58
|
+
hasNavigationPermission: vi.fn(() => true),
|
|
59
|
+
getFilteredNavigationItems: vi.fn((items) => items),
|
|
60
|
+
isEnabled: true,
|
|
61
|
+
isStrictMode: true,
|
|
62
|
+
isAuditLogEnabled: true,
|
|
63
|
+
permissions: {},
|
|
64
|
+
navigationAccessHistory: [],
|
|
65
|
+
clearNavigationAccessHistory: vi.fn(),
|
|
66
|
+
onNavigationAccess: vi.fn(),
|
|
67
|
+
onStrictModeViolation: vi.fn()
|
|
68
|
+
}))
|
|
69
|
+
};
|
|
70
|
+
});
|
|
45
71
|
|
|
46
72
|
// Mock the NavigationGuard component
|
|
47
73
|
vi.mock('../NavigationGuard', () => ({
|
|
@@ -52,7 +78,7 @@ vi.mock('../NavigationGuard', () => ({
|
|
|
52
78
|
}));
|
|
53
79
|
|
|
54
80
|
const mockUseUnifiedAuth = useUnifiedAuth as any;
|
|
55
|
-
const mockUseNavigationPermissions =
|
|
81
|
+
const mockUseNavigationPermissions = useNavigationPermissions as any;
|
|
56
82
|
|
|
57
83
|
// Test data
|
|
58
84
|
const mockNavigationItems: NavigationItem[] = [
|
|
@@ -118,24 +144,19 @@ const TestWrapper: React.FC<{ children: React.ReactNode; navigationProps?: any }
|
|
|
118
144
|
};
|
|
119
145
|
|
|
120
146
|
describe('EnhancedNavigationMenu', () => {
|
|
121
|
-
let consoleSpy: any;
|
|
122
|
-
|
|
123
147
|
beforeEach(() => {
|
|
124
|
-
|
|
125
|
-
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
148
|
+
vi.clearAllMocks();
|
|
126
149
|
|
|
127
150
|
mockUseUnifiedAuth.mockReturnValue(mockUser);
|
|
128
151
|
mockUseNavigationPermissions.mockReturnValue(defaultNavigationPermissions);
|
|
129
152
|
|
|
130
153
|
// Reset mocks
|
|
131
154
|
defaultNavigationPermissions.hasNavigationPermission.mockReturnValue(true);
|
|
132
|
-
defaultNavigationPermissions.getFilteredNavigationItems.
|
|
155
|
+
defaultNavigationPermissions.getFilteredNavigationItems.mockImplementation((items) => items || []);
|
|
133
156
|
});
|
|
134
157
|
|
|
135
158
|
afterEach(() => {
|
|
136
|
-
|
|
137
|
-
// Don't clear mocks to preserve the mock setup
|
|
138
|
-
// vi.clearAllMocks();
|
|
159
|
+
vi.clearAllMocks();
|
|
139
160
|
});
|
|
140
161
|
|
|
141
162
|
describe('Basic Rendering', () => {
|
|
@@ -198,11 +219,10 @@ describe('EnhancedNavigationMenu', () => {
|
|
|
198
219
|
</TestWrapper>
|
|
199
220
|
);
|
|
200
221
|
|
|
201
|
-
//
|
|
202
|
-
// This test verifies the component renders without crashing
|
|
222
|
+
// Only Dashboard should be visible after filtering
|
|
203
223
|
expect(screen.getByText('Dashboard')).toBeInTheDocument();
|
|
204
|
-
expect(screen.
|
|
205
|
-
expect(screen.
|
|
224
|
+
expect(screen.queryByText('Events')).not.toBeInTheDocument();
|
|
225
|
+
expect(screen.queryByText('Users')).not.toBeInTheDocument();
|
|
206
226
|
});
|
|
207
227
|
|
|
208
228
|
it('should show all items when navigation permissions are disabled', () => {
|
|
@@ -389,14 +409,16 @@ describe('EnhancedNavigationMenu', () => {
|
|
|
389
409
|
const dashboardButton = screen.getByRole('button', { name: /dashboard/i });
|
|
390
410
|
await user.click(dashboardButton);
|
|
391
411
|
|
|
392
|
-
|
|
393
|
-
expect.
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
412
|
+
await waitFor(() => {
|
|
413
|
+
expect(mockLogger.debug).toHaveBeenCalledWith(
|
|
414
|
+
'Navigation item clicked:',
|
|
415
|
+
expect.objectContaining({
|
|
416
|
+
item: 'dashboard',
|
|
417
|
+
path: '/dashboard',
|
|
418
|
+
permissions: ['read:dashboard']
|
|
419
|
+
})
|
|
420
|
+
);
|
|
421
|
+
});
|
|
400
422
|
});
|
|
401
423
|
|
|
402
424
|
it('should not log when audit logging is disabled', async () => {
|
|
@@ -414,8 +436,9 @@ describe('EnhancedNavigationMenu', () => {
|
|
|
414
436
|
const dashboardButton = screen.getByRole('button', { name: /dashboard/i });
|
|
415
437
|
await user.click(dashboardButton);
|
|
416
438
|
|
|
417
|
-
expect(
|
|
418
|
-
|
|
439
|
+
expect(mockLogger.debug).not.toHaveBeenCalledWith(
|
|
440
|
+
'Navigation item clicked:',
|
|
441
|
+
expect.any(Object)
|
|
419
442
|
);
|
|
420
443
|
});
|
|
421
444
|
|
|
@@ -466,7 +489,6 @@ describe('EnhancedNavigationMenu', () => {
|
|
|
466
489
|
|
|
467
490
|
describe('Strict Mode', () => {
|
|
468
491
|
it('should log strict mode violations when enabled', () => {
|
|
469
|
-
const consoleErrorSpy = vi.spyOn(console, 'error');
|
|
470
492
|
defaultNavigationPermissions.hasNavigationPermission.mockReturnValue(false);
|
|
471
493
|
// Ensure the mock is applied
|
|
472
494
|
mockUseNavigationPermissions.mockReturnValue(defaultNavigationPermissions);
|
|
@@ -485,7 +507,6 @@ describe('EnhancedNavigationMenu', () => {
|
|
|
485
507
|
});
|
|
486
508
|
|
|
487
509
|
it('should not log strict mode violations when disabled', () => {
|
|
488
|
-
const consoleErrorSpy = vi.spyOn(console, 'error');
|
|
489
510
|
defaultNavigationPermissions.hasNavigationPermission.mockReturnValue(false);
|
|
490
511
|
|
|
491
512
|
render(
|
|
@@ -497,14 +518,15 @@ describe('EnhancedNavigationMenu', () => {
|
|
|
497
518
|
</TestWrapper>
|
|
498
519
|
);
|
|
499
520
|
|
|
500
|
-
expect(
|
|
501
|
-
expect.stringContaining('
|
|
521
|
+
expect(mockLogger.error).not.toHaveBeenCalledWith(
|
|
522
|
+
expect.stringContaining('STRICT MODE VIOLATION:'),
|
|
523
|
+
expect.any(Object)
|
|
502
524
|
);
|
|
503
525
|
});
|
|
504
526
|
});
|
|
505
527
|
|
|
506
528
|
describe('Initialization Logging', () => {
|
|
507
|
-
it('should log initialization when audit logging is enabled', () => {
|
|
529
|
+
it('should log initialization when audit logging is enabled', async () => {
|
|
508
530
|
render(
|
|
509
531
|
<TestWrapper>
|
|
510
532
|
<EnhancedNavigationMenu
|
|
@@ -514,17 +536,19 @@ describe('EnhancedNavigationMenu', () => {
|
|
|
514
536
|
</TestWrapper>
|
|
515
537
|
);
|
|
516
538
|
|
|
517
|
-
|
|
518
|
-
expect.
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
539
|
+
await waitFor(() => {
|
|
540
|
+
expect(mockLogger.debug).toHaveBeenCalledWith(
|
|
541
|
+
'Navigation menu initialized:',
|
|
542
|
+
expect.objectContaining({
|
|
543
|
+
totalItems: 3,
|
|
544
|
+
filteredItems: 3,
|
|
545
|
+
strictMode: true
|
|
546
|
+
})
|
|
547
|
+
);
|
|
548
|
+
});
|
|
525
549
|
});
|
|
526
550
|
|
|
527
|
-
it('should log strict mode status on mount', () => {
|
|
551
|
+
it('should log strict mode status on mount', async () => {
|
|
528
552
|
render(
|
|
529
553
|
<TestWrapper>
|
|
530
554
|
<EnhancedNavigationMenu
|
|
@@ -535,9 +559,11 @@ describe('EnhancedNavigationMenu', () => {
|
|
|
535
559
|
</TestWrapper>
|
|
536
560
|
);
|
|
537
561
|
|
|
538
|
-
|
|
539
|
-
expect.
|
|
540
|
-
|
|
562
|
+
await waitFor(() => {
|
|
563
|
+
expect(mockLogger.debug).toHaveBeenCalledWith(
|
|
564
|
+
'Strict mode enabled - all navigation access attempts will be logged and enforced'
|
|
565
|
+
);
|
|
566
|
+
});
|
|
541
567
|
});
|
|
542
568
|
});
|
|
543
569
|
|
|
@@ -545,8 +571,8 @@ describe('EnhancedNavigationMenu', () => {
|
|
|
545
571
|
it('should handle missing navigation permissions gracefully', () => {
|
|
546
572
|
mockUseNavigationPermissions.mockReturnValue({
|
|
547
573
|
...defaultNavigationPermissions,
|
|
548
|
-
hasNavigationPermission:
|
|
549
|
-
getFilteredNavigationItems:
|
|
574
|
+
hasNavigationPermission: vi.fn(() => true),
|
|
575
|
+
getFilteredNavigationItems: vi.fn((items) => items)
|
|
550
576
|
});
|
|
551
577
|
|
|
552
578
|
expect(() => {
|
|
@@ -566,7 +592,7 @@ describe('EnhancedNavigationMenu', () => {
|
|
|
566
592
|
);
|
|
567
593
|
|
|
568
594
|
expect(screen.getByRole('navigation')).toBeInTheDocument();
|
|
569
|
-
expect(screen.
|
|
595
|
+
expect(screen.queryAllByRole('button')).toHaveLength(0);
|
|
570
596
|
});
|
|
571
597
|
});
|
|
572
598
|
|
|
@@ -13,6 +13,30 @@ import { ReactNode } from 'react';
|
|
|
13
13
|
import { NavigationGuard } from '../NavigationGuard';
|
|
14
14
|
import { useMultiplePermissions } from '../../hooks/usePermissions';
|
|
15
15
|
import { useUnifiedAuth } from '../../../providers/UnifiedAuthProvider';
|
|
16
|
+
import { getRBACLogger } from '../../config';
|
|
17
|
+
|
|
18
|
+
// Mock the RBAC logger - create shared mock
|
|
19
|
+
const mockLogger = {
|
|
20
|
+
debug: vi.fn(),
|
|
21
|
+
error: vi.fn(),
|
|
22
|
+
warn: vi.fn(),
|
|
23
|
+
info: vi.fn(),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
vi.mock('../../config', () => ({
|
|
27
|
+
getRBACLogger: vi.fn(() => mockLogger),
|
|
28
|
+
getRBACConfig: vi.fn(() => ({
|
|
29
|
+
debug: true,
|
|
30
|
+
logLevel: 'debug',
|
|
31
|
+
developmentMode: true,
|
|
32
|
+
audit: {
|
|
33
|
+
enabled: true,
|
|
34
|
+
logLevel: 'debug'
|
|
35
|
+
}
|
|
36
|
+
})),
|
|
37
|
+
isDebugMode: vi.fn(() => true),
|
|
38
|
+
isDevelopmentMode: vi.fn(() => true),
|
|
39
|
+
}));
|
|
16
40
|
|
|
17
41
|
// Mock the RBAC hooks
|
|
18
42
|
vi.mock('../../hooks/usePermissions', () => ({
|
|
@@ -499,8 +523,21 @@ describe('NavigationGuard Component', () => {
|
|
|
499
523
|
});
|
|
500
524
|
|
|
501
525
|
describe('Security Features', () => {
|
|
526
|
+
|
|
502
527
|
it('prevents bypassing in strict mode', async () => {
|
|
503
|
-
|
|
528
|
+
vi.clearAllMocks();
|
|
529
|
+
|
|
530
|
+
// Create a local mock logger to ensure we can track calls
|
|
531
|
+
const localMockLogger = {
|
|
532
|
+
debug: vi.fn(),
|
|
533
|
+
error: vi.fn(),
|
|
534
|
+
warn: vi.fn(),
|
|
535
|
+
info: vi.fn(),
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
// Mock getRBACLogger to return our local mock
|
|
539
|
+
const mockGetRBACLogger = vi.mocked(getRBACLogger);
|
|
540
|
+
mockGetRBACLogger.mockReturnValue(localMockLogger);
|
|
504
541
|
|
|
505
542
|
mockUseMultiplePermissions.mockReturnValue({
|
|
506
543
|
results: { 'read:dashboard': false } as Record<string, boolean>,
|
|
@@ -513,6 +550,7 @@ describe('NavigationGuard Component', () => {
|
|
|
513
550
|
<NavigationGuard
|
|
514
551
|
navigationItem={mockNavigationItem}
|
|
515
552
|
strictMode={true}
|
|
553
|
+
auditLog={true}
|
|
516
554
|
fallback={<TestFallback />}
|
|
517
555
|
>
|
|
518
556
|
<TestComponent>Navigation Link</TestComponent>
|
|
@@ -523,20 +561,32 @@ describe('NavigationGuard Component', () => {
|
|
|
523
561
|
expect(screen.getByTestId('test-fallback')).toBeInTheDocument();
|
|
524
562
|
}, { interval: 10 });
|
|
525
563
|
|
|
526
|
-
|
|
527
|
-
expect.
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
564
|
+
await waitFor(() => {
|
|
565
|
+
expect(localMockLogger.error).toHaveBeenCalledWith(
|
|
566
|
+
expect.stringContaining('STRICT MODE VIOLATION'),
|
|
567
|
+
expect.objectContaining({
|
|
568
|
+
navigationItem: 'nav-dashboard',
|
|
569
|
+
permissions: ['read:dashboard'],
|
|
570
|
+
userId: 'user-123'
|
|
571
|
+
})
|
|
572
|
+
);
|
|
573
|
+
}, { timeout: 2000, interval: 100 });
|
|
536
574
|
});
|
|
537
575
|
|
|
538
576
|
it('logs navigation access attempts for audit', async () => {
|
|
539
|
-
|
|
577
|
+
vi.clearAllMocks();
|
|
578
|
+
|
|
579
|
+
// Create a local mock logger to ensure we can track calls
|
|
580
|
+
const localMockLogger = {
|
|
581
|
+
debug: vi.fn(),
|
|
582
|
+
error: vi.fn(),
|
|
583
|
+
warn: vi.fn(),
|
|
584
|
+
info: vi.fn(),
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
// Mock getRBACLogger to return our local mock
|
|
588
|
+
const mockGetRBACLogger = vi.mocked(getRBACLogger);
|
|
589
|
+
mockGetRBACLogger.mockReturnValue(localMockLogger);
|
|
540
590
|
|
|
541
591
|
mockUseMultiplePermissions.mockReturnValue({
|
|
542
592
|
results: { 'read:dashboard': false } as Record<string, boolean>,
|
|
@@ -559,17 +609,17 @@ describe('NavigationGuard Component', () => {
|
|
|
559
609
|
expect(screen.getByTestId('test-fallback')).toBeInTheDocument();
|
|
560
610
|
}, { interval: 10 });
|
|
561
611
|
|
|
562
|
-
|
|
563
|
-
expect.
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
612
|
+
await waitFor(() => {
|
|
613
|
+
expect(localMockLogger.debug).toHaveBeenCalledWith(
|
|
614
|
+
'Navigation access attempt:',
|
|
615
|
+
expect.objectContaining({
|
|
616
|
+
navigationItem: 'nav-dashboard',
|
|
617
|
+
permissions: ['read:dashboard'],
|
|
618
|
+
userId: 'user-123',
|
|
619
|
+
allowed: false
|
|
620
|
+
})
|
|
621
|
+
);
|
|
622
|
+
}, { timeout: 2000, interval: 100 });
|
|
573
623
|
});
|
|
574
624
|
|
|
575
625
|
it('calls onDenied callback when access is denied', async () => {
|
|
@@ -628,7 +678,7 @@ describe('NavigationGuard Component', () => {
|
|
|
628
678
|
|
|
629
679
|
describe('Configuration Options', () => {
|
|
630
680
|
it('respects strictMode setting', async () => {
|
|
631
|
-
|
|
681
|
+
vi.clearAllMocks();
|
|
632
682
|
|
|
633
683
|
mockUseMultiplePermissions.mockReturnValue({
|
|
634
684
|
results: { 'read:dashboard': false } as Record<string, boolean>,
|
|
@@ -651,15 +701,15 @@ describe('NavigationGuard Component', () => {
|
|
|
651
701
|
expect(screen.getByTestId('test-fallback')).toBeInTheDocument();
|
|
652
702
|
}, { interval: 10 });
|
|
653
703
|
|
|
654
|
-
|
|
655
|
-
|
|
704
|
+
// Strict mode is disabled, so error should not be called
|
|
705
|
+
expect(mockLogger.error).not.toHaveBeenCalledWith(
|
|
706
|
+
expect.stringContaining('STRICT MODE VIOLATION'),
|
|
707
|
+
expect.anything()
|
|
656
708
|
);
|
|
657
|
-
|
|
658
|
-
consoleSpy.mockRestore();
|
|
659
709
|
});
|
|
660
710
|
|
|
661
711
|
it('respects auditLog setting', async () => {
|
|
662
|
-
|
|
712
|
+
vi.clearAllMocks();
|
|
663
713
|
|
|
664
714
|
mockUseMultiplePermissions.mockReturnValue({
|
|
665
715
|
results: { 'read:dashboard': false } as Record<string, boolean>,
|
|
@@ -682,11 +732,11 @@ describe('NavigationGuard Component', () => {
|
|
|
682
732
|
expect(screen.getByTestId('test-fallback')).toBeInTheDocument();
|
|
683
733
|
}, { interval: 10 });
|
|
684
734
|
|
|
685
|
-
|
|
686
|
-
|
|
735
|
+
// Audit log is disabled, so debug should not be called
|
|
736
|
+
expect(mockLogger.debug).not.toHaveBeenCalledWith(
|
|
737
|
+
'Navigation access attempt:',
|
|
738
|
+
expect.anything()
|
|
687
739
|
);
|
|
688
|
-
|
|
689
|
-
consoleSpy.mockRestore();
|
|
690
740
|
});
|
|
691
741
|
|
|
692
742
|
it('respects requireAll setting', async () => {
|
|
@@ -15,6 +15,29 @@ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
|
15
15
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
16
16
|
import { renderWithProviders } from '../../../__tests__/helpers';
|
|
17
17
|
|
|
18
|
+
// Mock the RBAC logger - define inside factory to avoid hoisting issues
|
|
19
|
+
const mockLogger = {
|
|
20
|
+
debug: vi.fn(),
|
|
21
|
+
error: vi.fn(),
|
|
22
|
+
warn: vi.fn(),
|
|
23
|
+
info: vi.fn(),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
vi.mock('../../config', () => ({
|
|
27
|
+
getRBACLogger: vi.fn(() => mockLogger),
|
|
28
|
+
getRBACConfig: vi.fn(() => ({
|
|
29
|
+
debug: true,
|
|
30
|
+
logLevel: 'debug',
|
|
31
|
+
developmentMode: true,
|
|
32
|
+
audit: {
|
|
33
|
+
enabled: true,
|
|
34
|
+
logLevel: 'debug'
|
|
35
|
+
}
|
|
36
|
+
})),
|
|
37
|
+
isDebugMode: vi.fn(() => true),
|
|
38
|
+
isDevelopmentMode: vi.fn(() => true),
|
|
39
|
+
}));
|
|
40
|
+
|
|
18
41
|
import {
|
|
19
42
|
NavigationProvider,
|
|
20
43
|
NavigationProviderProps,
|
|
@@ -117,11 +140,8 @@ const TestWrapper: React.FC<{
|
|
|
117
140
|
};
|
|
118
141
|
|
|
119
142
|
describe('NavigationProvider', () => {
|
|
120
|
-
let consoleSpy: any;
|
|
121
|
-
|
|
122
143
|
beforeEach(() => {
|
|
123
|
-
|
|
124
|
-
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
144
|
+
vi.clearAllMocks();
|
|
125
145
|
|
|
126
146
|
// Set up default mock with organisation context
|
|
127
147
|
mockUseUnifiedAuth.mockReturnValue({
|
|
@@ -132,7 +152,6 @@ describe('NavigationProvider', () => {
|
|
|
132
152
|
});
|
|
133
153
|
|
|
134
154
|
afterEach(() => {
|
|
135
|
-
consoleSpy.mockRestore();
|
|
136
155
|
vi.clearAllMocks();
|
|
137
156
|
});
|
|
138
157
|
|
|
@@ -358,28 +377,32 @@ describe('NavigationProvider', () => {
|
|
|
358
377
|
});
|
|
359
378
|
|
|
360
379
|
describe('Audit Logging', () => {
|
|
361
|
-
it('should log strict mode status when enabled', () => {
|
|
380
|
+
it('should log strict mode status when enabled', async () => {
|
|
362
381
|
renderWithProviders(
|
|
363
382
|
<TestWrapper providerProps={{ strictMode: true, auditLog: true }}>
|
|
364
383
|
<TestComponent />
|
|
365
384
|
</TestWrapper>
|
|
366
385
|
);
|
|
367
386
|
|
|
368
|
-
|
|
369
|
-
expect.
|
|
370
|
-
|
|
387
|
+
await waitFor(() => {
|
|
388
|
+
expect(mockLogger.debug).toHaveBeenCalledWith(
|
|
389
|
+
'Strict mode enabled - all navigation access attempts will be logged and enforced'
|
|
390
|
+
);
|
|
391
|
+
});
|
|
371
392
|
});
|
|
372
393
|
|
|
373
|
-
it('should not log when audit logging is disabled', () => {
|
|
394
|
+
it('should not log when audit logging is disabled', async () => {
|
|
374
395
|
renderWithProviders(
|
|
375
396
|
<TestWrapper providerProps={{ auditLog: false }}>
|
|
376
397
|
<TestComponent />
|
|
377
398
|
</TestWrapper>
|
|
378
399
|
);
|
|
379
400
|
|
|
380
|
-
|
|
381
|
-
expect.
|
|
382
|
-
|
|
401
|
+
await waitFor(() => {
|
|
402
|
+
expect(mockLogger.debug).not.toHaveBeenCalledWith(
|
|
403
|
+
'Strict mode enabled - all navigation access attempts will be logged and enforced'
|
|
404
|
+
);
|
|
405
|
+
});
|
|
383
406
|
});
|
|
384
407
|
});
|
|
385
408
|
|
|
@@ -30,12 +30,12 @@ vi.mock('../../utils/eventContext', () => ({
|
|
|
30
30
|
}));
|
|
31
31
|
|
|
32
32
|
// Mock the app name resolver
|
|
33
|
-
vi.mock('../../../utils/appNameResolver', () => ({
|
|
33
|
+
vi.mock('../../../utils/app/appNameResolver', () => ({
|
|
34
34
|
getCurrentAppName: vi.fn()
|
|
35
35
|
}));
|
|
36
36
|
|
|
37
37
|
import { createScopeFromEvent } from '../../utils/eventContext';
|
|
38
|
-
import { getCurrentAppName } from '../../../utils/appNameResolver';
|
|
38
|
+
import { getCurrentAppName } from '../../../utils/app/appNameResolver';
|
|
39
39
|
|
|
40
40
|
// Mock data
|
|
41
41
|
const mockUser = {
|
|
@@ -23,6 +23,22 @@ import {
|
|
|
23
23
|
} from '../PagePermissionProvider';
|
|
24
24
|
import { useUnifiedAuth } from '../../../providers/UnifiedAuthProvider';
|
|
25
25
|
|
|
26
|
+
// Mock the Logger module
|
|
27
|
+
vi.mock('../../../utils/core/logger', () => {
|
|
28
|
+
const mockLoggerInstance = {
|
|
29
|
+
debug: vi.fn(),
|
|
30
|
+
warn: vi.fn(),
|
|
31
|
+
error: vi.fn(),
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
createLogger: vi.fn(() => mockLoggerInstance),
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Get the mock instance after mock is set up
|
|
39
|
+
import { createLogger } from '../../../utils/core/logger';
|
|
40
|
+
const getMockLogger = () => createLogger('test');
|
|
41
|
+
|
|
26
42
|
// Mock the UnifiedAuthProvider
|
|
27
43
|
vi.mock('../../../providers/UnifiedAuthProvider', () => ({
|
|
28
44
|
useUnifiedAuth: vi.fn(),
|
|
@@ -89,10 +105,7 @@ const TestWrapper: React.FC<{
|
|
|
89
105
|
};
|
|
90
106
|
|
|
91
107
|
describe('PagePermissionProvider', () => {
|
|
92
|
-
let consoleSpy: any;
|
|
93
|
-
|
|
94
108
|
beforeEach(() => {
|
|
95
|
-
consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
96
109
|
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
97
110
|
|
|
98
111
|
// Set up default mock with organisation context
|
|
@@ -104,7 +117,6 @@ describe('PagePermissionProvider', () => {
|
|
|
104
117
|
});
|
|
105
118
|
|
|
106
119
|
afterEach(() => {
|
|
107
|
-
consoleSpy.mockRestore();
|
|
108
120
|
// Don't clear mocks to preserve the mock setup
|
|
109
121
|
// vi.clearAllMocks();
|
|
110
122
|
});
|
|
@@ -338,8 +350,9 @@ describe('PagePermissionProvider', () => {
|
|
|
338
350
|
</TestWrapper>
|
|
339
351
|
);
|
|
340
352
|
|
|
341
|
-
|
|
342
|
-
|
|
353
|
+
const logger = getMockLogger();
|
|
354
|
+
expect(vi.mocked(logger.debug)).toHaveBeenCalledWith(
|
|
355
|
+
'Strict mode enabled - all page access attempts will be logged and enforced'
|
|
343
356
|
);
|
|
344
357
|
});
|
|
345
358
|
|
|
@@ -350,8 +363,9 @@ describe('PagePermissionProvider', () => {
|
|
|
350
363
|
</TestWrapper>
|
|
351
364
|
);
|
|
352
365
|
|
|
353
|
-
|
|
354
|
-
|
|
366
|
+
const logger = getMockLogger();
|
|
367
|
+
expect(vi.mocked(logger.debug)).not.toHaveBeenCalledWith(
|
|
368
|
+
expect.stringContaining('Strict mode enabled')
|
|
355
369
|
);
|
|
356
370
|
});
|
|
357
371
|
});
|