@jmruthers/pace-core 0.2.7 → 0.5.1
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-EEUDXPE5.js → DataTable-GX3XERFJ.js} +8 -4
- package/dist/{DataTable-C1AEm9Cx.d.ts → DataTable-ltTFXHS3.d.ts} +3 -1
- package/dist/{chunk-VYG4AXYW.js → chunk-5EL3KHOQ.js} +2 -2
- package/dist/{chunk-ETEJVKYK.js → chunk-6CR3MRZN.js} +1426 -62
- package/dist/chunk-6CR3MRZN.js.map +1 -0
- package/dist/chunk-AUE24LVR.js +268 -0
- package/dist/chunk-AUE24LVR.js.map +1 -0
- package/dist/chunk-COBPIXXQ.js +379 -0
- package/dist/chunk-COBPIXXQ.js.map +1 -0
- package/dist/{chunk-EWKPTNPO.js → chunk-GSNM5D6H.js} +388 -86
- package/dist/chunk-GSNM5D6H.js.map +1 -0
- package/dist/{chunk-2V3Y6YBC.js → chunk-OEGRKULD.js} +1 -42
- package/dist/chunk-OEGRKULD.js.map +1 -0
- package/dist/chunk-OYRY44Q2.js +62 -0
- package/dist/chunk-OYRY44Q2.js.map +1 -0
- package/dist/{chunk-RRUYHORU.js → chunk-T3XIA4AJ.js} +297 -433
- package/dist/chunk-T3XIA4AJ.js.map +1 -0
- package/dist/{chunk-HEMJ4SUJ.js → chunk-TGDCLPP2.js} +11 -7
- package/dist/{chunk-HEMJ4SUJ.js.map → chunk-TGDCLPP2.js.map} +1 -1
- package/dist/{chunk-HNDFPXUU.js → chunk-U6JDHVC2.js} +6 -4
- package/dist/{chunk-HNDFPXUU.js.map → chunk-U6JDHVC2.js.map} +1 -1
- package/dist/{chunk-TIVL4UQ7.js → chunk-XJK2J4N6.js} +6 -4
- package/dist/{chunk-TIVL4UQ7.js.map → chunk-XJK2J4N6.js.map} +1 -1
- package/dist/components.d.ts +2 -2
- package/dist/components.js +21 -20
- package/dist/components.js.map +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +7 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.js +26 -25
- package/dist/index.js.map +1 -1
- package/dist/providers.js +8 -7
- package/dist/rbac/index.d.ts +806 -806
- package/dist/rbac/index.js +937 -1179
- package/dist/rbac/index.js.map +1 -1
- package/dist/{types-DiRQsGJs.d.ts → types-BRDU7N6w.d.ts} +12 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +6 -6
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.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 +1 -1
- package/docs/api/interfaces/DataTableAction.md +21 -8
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +46 -33
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EventContextType.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +1 -1
- package/docs/api/interfaces/EventProviderProps.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.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/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +2 -2
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- 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/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/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +3 -3
- package/package.json +5 -2
- package/src/__tests__/REBUILD_PLAN.md +223 -0
- package/src/__tests__/TESTING_GUIDELINES.md +341 -0
- package/src/__tests__/fixtures/mocks.ts +93 -0
- package/src/__tests__/helpers/component-test-utils.tsx +145 -0
- package/src/__tests__/helpers/test-utils.tsx +117 -0
- package/src/__tests__/integration/UserProfile.test.tsx +128 -0
- package/src/__tests__/setup.ts +37 -225
- package/src/__tests__/templates/component.test.template.tsx +97 -75
- package/src/__tests__/templates/hook.test.template.ts +173 -0
- package/src/__tests__/types/test.types.ts +106 -0
- package/src/components/Alert/Alert.test.tsx +496 -0
- package/src/components/Avatar/Avatar.test.tsx +484 -0
- package/src/components/Button/Button.test.tsx +662 -0
- package/src/components/Card/Card.test.tsx +593 -0
- package/src/components/Checkbox/Checkbox.test.tsx +461 -0
- package/src/components/DataTable/DataTable.tsx +9 -1
- package/src/components/DataTable/components/AccessDeniedPage.tsx +168 -0
- package/src/components/DataTable/components/ActionButtons.tsx +18 -1
- package/src/components/DataTable/components/DataTableCore.tsx +97 -11
- package/src/components/DataTable/components/DataTableToolbar.tsx +22 -10
- package/src/components/DataTable/components/UnifiedTableBody.tsx +33 -4
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +1 -0
- package/src/components/DataTable/examples/HierarchicalExample.tsx +3 -0
- package/src/components/DataTable/examples/InitialPageSizeExample.tsx +3 -0
- package/src/components/DataTable/examples/PerformanceExample.tsx +3 -0
- package/src/components/DataTable/types.ts +39 -1
- package/src/components/Dialog/Dialog.test.tsx +1139 -0
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +752 -0
- package/src/components/FileUpload/FileUpload.test.tsx +665 -0
- package/src/hooks/useCounter.test.ts +135 -0
- package/src/rbac/index.ts +3 -3
- package/dist/chunk-2V3Y6YBC.js.map +0 -1
- package/dist/chunk-BEZRLNK3.js +0 -1744
- package/dist/chunk-BEZRLNK3.js.map +0 -1
- package/dist/chunk-ETEJVKYK.js.map +0 -1
- package/dist/chunk-EWKPTNPO.js.map +0 -1
- package/dist/chunk-OHXGNT3K.js +0 -21
- package/dist/chunk-OHXGNT3K.js.map +0 -1
- package/dist/chunk-RRUYHORU.js.map +0 -1
- package/src/__tests__/README.md +0 -404
- package/src/__tests__/debug-provider.unit.test.tsx +0 -67
- package/src/__tests__/e2e/workflows.test.tsx +0 -373
- package/src/__tests__/hybridPermissions.unit.test.tsx +0 -474
- package/src/__tests__/index.integration.test.ts +0 -491
- package/src/__tests__/mocks/MockAuthProvider-standalone.tsx +0 -47
- package/src/__tests__/mocks/MockAuthProvider.tsx +0 -63
- package/src/__tests__/mocks/enhancedSupabaseMock.ts +0 -252
- package/src/__tests__/mocks/index.test.ts +0 -23
- package/src/__tests__/mocks/index.ts +0 -16
- package/src/__tests__/mocks/mockAuth.ts +0 -155
- package/src/__tests__/mocks/mockSupabase.ts +0 -83
- package/src/__tests__/mocks/mockSupabaseClient.ts +0 -63
- package/src/__tests__/mocks/providers.tsx +0 -22
- package/src/__tests__/patterns/__tests__/testPatterns.test.ts +0 -394
- package/src/__tests__/patterns/testPatterns.ts +0 -124
- package/src/__tests__/performance/componentPerformance.performance.test.ts +0 -27
- package/src/__tests__/performance/index.ts +0 -24
- package/src/__tests__/performance/performanceValidation.performance.test.ts +0 -15
- package/src/__tests__/security/security.unit.test.tsx +0 -7
- package/src/__tests__/security/securityValidation.security.test.tsx +0 -153
- package/src/__tests__/setupTests.d.ts +0 -1
- package/src/__tests__/shared/componentTestUtils.tsx +0 -475
- package/src/__tests__/shared/errorHandlingTestUtils.ts +0 -107
- package/src/__tests__/shared/index.ts +0 -81
- package/src/__tests__/shared/integrationTestUtils.tsx +0 -375
- package/src/__tests__/shared/performanceTestUtils.tsx +0 -476
- package/src/__tests__/shared/testUtils.optimized.tsx +0 -685
- package/src/__tests__/simple.test.tsx +0 -20
- package/src/__tests__/test-utils/dataFactories.ts +0 -60
- package/src/__tests__/test-utils/index.ts +0 -6
- package/src/__tests__/typeSafety.unit.test.ts +0 -65
- package/src/__tests__/unifiedAuth.unit.test.tsx +0 -151
- package/src/__tests__/utils/accessibilityHelpers.ts +0 -254
- package/src/__tests__/utils/assertions.ts +0 -50
- package/src/__tests__/utils/deterministicHelpers.ts +0 -31
- package/src/__tests__/utils/edgeCaseConfig.test.ts +0 -75
- package/src/__tests__/utils/edgeCaseConfig.ts +0 -98
- package/src/__tests__/utils/mockHelpers.ts +0 -149
- package/src/__tests__/utils/mockLoader.ts +0 -101
- package/src/__tests__/utils/performanceHelpers.ts +0 -55
- package/src/__tests__/utils/performanceTestHelpers.ts +0 -68
- package/src/__tests__/utils/testDataFactories.ts +0 -28
- package/src/__tests__/utils/testIsolation.ts +0 -67
- package/src/__tests__/utils/visualTestHelpers.ts +0 -20
- package/src/__tests__/visual/__snapshots__/componentSnapshots.visual.test.tsx.snap +0 -68
- package/src/__tests__/visual/__snapshots__/componentVisuals.visual.test.tsx.snap +0 -14
- package/src/__tests__/visual/__snapshots__/visualRegression.test.tsx.snap +0 -217
- package/src/__tests__/visual/__snapshots__/visualRegression.visual.test.tsx.snap +0 -24
- package/src/__tests__/visual/componentSnapshots.visual.test.tsx +0 -33
- package/src/__tests__/visual/componentVisuals.visual.test.tsx +0 -12
- package/src/__tests__/visual/visualRegression.visual.test.tsx +0 -20
- package/src/components/Alert/__tests__/Alert.unit.test.tsx +0 -381
- package/src/components/Avatar/__tests__/Avatar.unit.test.tsx +0 -232
- package/src/components/Button/__tests__/Button.accessibility.test.tsx +0 -131
- package/src/components/Button/__tests__/Button.comprehensive.test.tsx +0 -721
- package/src/components/Button/__tests__/Button.unit.test.tsx +0 -189
- package/src/components/Button/__tests__/EventSelector.integration.test.tsx +0 -285
- package/src/components/Card/__tests__/Card.accessibility.test.tsx +0 -394
- package/src/components/Card/__tests__/Card.comprehensive.test.tsx +0 -599
- package/src/components/Card/__tests__/Card.integration.test.tsx +0 -673
- package/src/components/Card/__tests__/Card.performance.test.tsx +0 -546
- package/src/components/Card/__tests__/Card.unit.test.tsx +0 -330
- package/src/components/Card/__tests__/Card.visual.test.tsx +0 -599
- package/src/components/Card/__tests__/README.md +0 -211
- package/src/components/Checkbox/__tests__/Checkbox.unit.test.tsx +0 -520
- package/src/components/DataTable/__tests__/DataTable.errorHandling.test.tsx +0 -251
- package/src/components/DataTable/__tests__/DataTable.hierarchical.test.tsx +0 -680
- package/src/components/DataTable/__tests__/DataTable.infinite-loop.test.tsx +0 -323
- package/src/components/DataTable/__tests__/DataTable.integration.test.tsx +0 -716
- package/src/components/DataTable/__tests__/DataTable.performance.test.tsx +0 -589
- package/src/components/DataTable/__tests__/DataTable.permissions.test.tsx +0 -316
- package/src/components/DataTable/__tests__/DataTable.regressionFixes.test.tsx +0 -546
- package/src/components/DataTable/__tests__/DataTable.selection.controlled.test.tsx +0 -386
- package/src/components/DataTable/__tests__/DataTable.selection.test.tsx +0 -338
- package/src/components/DataTable/__tests__/DataTable.sorting.test.tsx +0 -321
- package/src/components/DataTable/__tests__/DataTable.userWorkflows.test.tsx +0 -320
- package/src/components/DataTable/__tests__/DataTable.workflowValidation.test.tsx +0 -583
- package/src/components/DataTable/__tests__/DataTable.workflows.test.tsx +0 -711
- package/src/components/DataTable/__tests__/performance-regression.test.tsx +0 -777
- package/src/components/DataTable/__tests__/performance.test.tsx +0 -365
- package/src/components/DataTable/components/__tests__/ActionButtons.unit.test.tsx +0 -150
- package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +0 -224
- package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.unit.test.tsx +0 -244
- package/src/components/DataTable/components/__tests__/DataTable.accessibility.test.tsx +0 -629
- package/src/components/DataTable/components/__tests__/DataTable.integration.test.tsx +0 -470
- package/src/components/DataTable/components/__tests__/DataTable.performance.test.tsx +0 -160
- package/src/components/DataTable/components/__tests__/DataTable.real.test.tsx +0 -251
- package/src/components/DataTable/components/__tests__/DataTable.security.test.tsx +0 -171
- package/src/components/DataTable/components/__tests__/DataTable.unit.test.tsx +0 -290
- package/src/components/DataTable/components/__tests__/DataTableBody.unit.test.tsx +0 -147
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.unit.test.tsx +0 -182
- package/src/components/DataTable/components/__tests__/DataTableModals.unit.test.tsx +0 -123
- package/src/components/DataTable/components/__tests__/EditableRow.unit.test.tsx +0 -660
- package/src/components/DataTable/components/__tests__/EmptyState.unit.test.tsx +0 -256
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -498
- package/src/components/DataTable/components/__tests__/FilterRow.unit.test.tsx +0 -112
- package/src/components/DataTable/components/__tests__/FilteringToggle.unit.test.tsx +0 -133
- package/src/components/DataTable/components/__tests__/GroupHeader.unit.test.tsx +0 -172
- package/src/components/DataTable/components/__tests__/GroupingDropdown.unit.test.tsx +0 -222
- package/src/components/DataTable/components/__tests__/ImportModal.unit.test.tsx +0 -780
- package/src/components/DataTable/components/__tests__/LoadingState.unit.test.tsx +0 -65
- package/src/components/DataTable/components/__tests__/PaginationControls.unit.test.tsx +0 -634
- package/src/components/DataTable/components/__tests__/StateComponents.unit.test.tsx +0 -48
- package/src/components/DataTable/components/__tests__/UnifiedTableBody.hierarchical.test.tsx +0 -541
- package/src/components/DataTable/components/__tests__/ViewRowModal.unit.test.tsx +0 -228
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.unit.test.tsx +0 -568
- package/src/components/DataTable/core/__tests__/ActionManager.unit.test.ts +0 -405
- package/src/components/DataTable/core/__tests__/ArchitectureIntegration.unit.test.tsx +0 -445
- package/src/components/DataTable/core/__tests__/ColumnFactory.unit.test.ts +0 -288
- package/src/components/DataTable/core/__tests__/ColumnManager.unit.test.ts +0 -623
- package/src/components/DataTable/core/__tests__/DataManager.unit.test.ts +0 -431
- package/src/components/DataTable/core/__tests__/DataTableContext.unit.test.tsx +0 -433
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.unit.test.ts +0 -422
- package/src/components/DataTable/core/__tests__/PluginRegistry.unit.test.tsx +0 -207
- package/src/components/DataTable/core/__tests__/StateManager.unit.test.ts +0 -278
- package/src/components/DataTable/examples/__tests__/PerformanceExample.unit.test.tsx +0 -281
- package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.unit.test.ts +0 -407
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.unit.test.ts +0 -679
- package/src/components/DataTable/utils/__tests__/debugTools.unit.test.ts +0 -267
- package/src/components/DataTable/utils/__tests__/errorHandling.unit.test.ts +0 -467
- package/src/components/DataTable/utils/__tests__/exportUtils.unit.test.ts +0 -380
- package/src/components/DataTable/utils/__tests__/flexibleImport.unit.test.ts +0 -233
- package/src/components/DataTable/utils/__tests__/performanceUtils.unit.test.ts +0 -414
- package/src/components/Dialog/__tests__/Dialog.accessibility.test.tsx +0 -521
- package/src/components/Dialog/__tests__/Dialog.auto-size.example.tsx +0 -157
- package/src/components/Dialog/__tests__/Dialog.enhanced.test.tsx +0 -538
- package/src/components/Dialog/__tests__/Dialog.unit.test.tsx +0 -1373
- package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +0 -151
- package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +0 -611
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.accessibility.test.tsx +0 -517
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.integration.test.tsx +0 -572
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.unit.test.tsx +0 -579
- package/src/components/EventSelector/__tests__/EventSelector.test.tsx +0 -528
- package/src/components/FileUpload/__tests__/FileUpload.integration.test.tsx +0 -992
- package/src/components/FileUpload/__tests__/FileUpload.real.test.tsx +0 -927
- package/src/components/FileUpload/__tests__/FileUpload.test.tsx +0 -855
- package/src/components/FileUpload/__tests__/FileUpload.unit.test.tsx +0 -1311
- package/src/components/FileUpload/__tests__/FileUpload.unmocked.test.tsx +0 -937
- package/src/components/Footer/__tests__/Footer.accessibility.test.tsx +0 -359
- package/src/components/Footer/__tests__/Footer.integration.test.tsx +0 -353
- package/src/components/Footer/__tests__/Footer.performance.test.tsx +0 -309
- package/src/components/Footer/__tests__/Footer.unit.test.tsx +0 -309
- package/src/components/Footer/__tests__/Footer.visual.test.tsx +0 -335
- package/src/components/Form/__tests__/Form.accessibility.test.tsx +0 -820
- package/src/components/Form/__tests__/Form.unit.test.tsx +0 -305
- package/src/components/Form/__tests__/FormErrorSummary.unit.test.tsx +0 -285
- package/src/components/Form/__tests__/FormFieldset.unit.test.tsx +0 -241
- package/src/components/Header/__tests__/Header.accessibility.test.tsx +0 -382
- package/src/components/Header/__tests__/Header.comprehensive.test.tsx +0 -509
- package/src/components/Header/__tests__/Header.unit.test.tsx +0 -335
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +0 -196
- package/src/components/InactivityWarningModal/__tests__/InactivityWarningModal.unit.test.tsx +0 -224
- package/src/components/Input/__tests__/Input.accessibility.test.tsx +0 -632
- package/src/components/Input/__tests__/Input.unit.test.tsx +0 -1121
- package/src/components/Label/__tests__/Label.accessibility.test.tsx +0 -239
- package/src/components/Label/__tests__/Label.unit.test.tsx +0 -331
- package/src/components/LoadingSpinner/__tests__/LoadingSpinner.accessibility.test.tsx +0 -116
- package/src/components/LoadingSpinner/__tests__/LoadingSpinner.unit.test.tsx +0 -144
- package/src/components/LoginForm/__tests__/LoginForm.accessibility.test.tsx +0 -201
- package/src/components/LoginForm/__tests__/LoginForm.unit.test.tsx +0 -119
- package/src/components/NavigationMenu/__tests__/NavigationMenu.accessibility.test.tsx +0 -378
- package/src/components/NavigationMenu/__tests__/NavigationMenu.enhanced.test.tsx +0 -768
- package/src/components/NavigationMenu/__tests__/NavigationMenu.integration.test.tsx +0 -576
- package/src/components/NavigationMenu/__tests__/NavigationMenu.performance.test.tsx +0 -585
- package/src/components/NavigationMenu/__tests__/NavigationMenu.real.component.test.tsx +0 -783
- package/src/components/NavigationMenu/__tests__/NavigationMenu.security.enhanced.test.tsx +0 -810
- package/src/components/NavigationMenu/__tests__/NavigationMenu.security.test.tsx +0 -494
- package/src/components/NavigationMenu/__tests__/NavigationMenu.unit.test.tsx +0 -331
- package/src/components/NavigationMenu/__tests__/NavigationMenu.userWorkflows.test.tsx +0 -347
- package/src/components/NavigationMenu/__tests__/NavigationMenu.workflows.test.tsx +0 -584
- package/src/components/OrganisationSelector/__tests__/OrganisationSelector.unit.test.tsx +0 -664
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +0 -288
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +0 -893
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +0 -629
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +0 -782
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -904
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.accessibility.test.tsx +0 -463
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.integration.test.tsx +0 -586
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.unit.test.tsx +0 -533
- package/src/components/PasswordReset/__tests__/PasswordChangeForm.accessibility.test.tsx +0 -408
- package/src/components/PasswordReset/__tests__/PasswordChangeForm.unit.test.tsx +0 -561
- package/src/components/PasswordReset/__tests__/PasswordReset.integration.test.tsx +0 -304
- package/src/components/PasswordReset/__tests__/PasswordResetForm.accessibility.test.tsx +0 -20
- package/src/components/PasswordReset/__tests__/PasswordResetForm.unit.test.tsx +0 -523
- package/src/components/PasswordReset/__tests__/__mocks__/UnifiedAuthProvider.ts +0 -29
- package/src/components/Print/__tests__/Print.comprehensive.test.tsx +0 -331
- package/src/components/PrintButton/__tests__/PrintButton.unit.test.tsx +0 -429
- package/src/components/PrintButton/__tests__/PrintButtonGroup.unit.test.tsx +0 -277
- package/src/components/PrintButton/__tests__/PrintToolbar.unit.test.tsx +0 -264
- package/src/components/PrintCard/__tests__/PrintCard.unit.test.tsx +0 -233
- package/src/components/PrintCard/__tests__/PrintCardContent.test.tsx +0 -284
- package/src/components/PrintCard/__tests__/PrintCardGrid.unit.test.tsx +0 -214
- package/src/components/PrintCard/__tests__/PrintCardImage.unit.test.tsx +0 -264
- package/src/components/PrintDataTable/__tests__/PrintDataTable.unit.test.tsx +0 -361
- package/src/components/PrintDataTable/__tests__/PrintTableGroup.unit.test.tsx +0 -314
- package/src/components/PrintDataTable/__tests__/PrintTableRow.unit.test.tsx +0 -362
- package/src/components/PrintFooter/__tests__/PrintFooter.unit.test.tsx +0 -500
- package/src/components/PrintFooter/__tests__/PrintFooterContent.unit.test.tsx +0 -321
- package/src/components/PrintFooter/__tests__/PrintFooterInfo.unit.test.tsx +0 -335
- package/src/components/PrintFooter/__tests__/PrintPageNumber.unit.test.tsx +0 -340
- package/src/components/PrintGrid/__tests__/PrintGrid.unit.test.tsx +0 -340
- package/src/components/PrintGrid/__tests__/PrintGridBreakpoint.unit.test.tsx +0 -261
- package/src/components/PrintGrid/__tests__/PrintGridContainer.unit.test.tsx +0 -338
- package/src/components/PrintGrid/__tests__/PrintGridItem.unit.test.tsx +0 -338
- package/src/components/PrintHeader/__tests__/PrintCoverHeader.unit.test.tsx +0 -309
- package/src/components/PrintHeader/__tests__/PrintHeader.unit.test.tsx +0 -202
- package/src/components/PrintLayout/__tests__/PrintLayout.unit.test.tsx +0 -238
- package/src/components/PrintPageBreak/__tests__/PrintPageBreak.unit.test.tsx +0 -263
- package/src/components/PrintPageBreak/__tests__/PrintPageBreakGroup.unit.test.tsx +0 -239
- package/src/components/PrintPageBreak/__tests__/PrintPageBreakIndicator.unit.test.tsx +0 -235
- package/src/components/PrintSection/__tests__/PrintColumn.unit.test.tsx +0 -385
- package/src/components/PrintSection/__tests__/PrintDivider.unit.test.tsx +0 -373
- package/src/components/PrintSection/__tests__/PrintSection.unit.test.tsx +0 -390
- package/src/components/PrintSection/__tests__/PrintSectionContent.unit.test.tsx +0 -321
- package/src/components/PrintSection/__tests__/PrintSectionHeader.unit.test.tsx +0 -334
- package/src/components/PrintText/__tests__/PrintText.unit.test.tsx +0 -351
- package/src/components/Progress/__tests__/Progress.accessibility.test.tsx +0 -240
- package/src/components/Progress/__tests__/Progress.unit.test.tsx +0 -242
- package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +0 -761
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.simplified.test.tsx +0 -228
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +0 -228
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +0 -459
- package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +0 -362
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +0 -522
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +0 -599
- package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +0 -513
- package/src/components/RBAC/__tests__/PagePermissionGuard.unit.test.tsx +0 -683
- package/src/components/RBAC/__tests__/RBAC.integration.test.tsx +0 -573
- package/src/components/RBAC/__tests__/RBACGuard.unit.test.tsx +0 -467
- package/src/components/RBAC/__tests__/RBACProvider.accessibility.test.tsx +0 -475
- package/src/components/RBAC/__tests__/RBACProvider.advanced.test.tsx +0 -569
- package/src/components/RBAC/__tests__/RBACProvider.integration.test.tsx +0 -352
- package/src/components/RBAC/__tests__/RBACProvider.unit.test.tsx +0 -128
- package/src/components/RBAC/__tests__/RoleBasedContent.unit.test.tsx +0 -657
- package/src/components/Select/__tests__/SearchableSelect.unit.test.tsx +0 -437
- package/src/components/Select/__tests__/Select.accessibility.test.tsx +0 -1202
- package/src/components/Select/__tests__/Select.actual.test.tsx +0 -774
- package/src/components/Select/__tests__/Select.comprehensive.test.tsx +0 -837
- package/src/components/Select/__tests__/Select.enhanced.test.tsx +0 -1101
- package/src/components/Select/__tests__/Select.integration.test.tsx +0 -772
- package/src/components/Select/__tests__/Select.performance.test.tsx +0 -695
- package/src/components/Select/__tests__/Select.real-world.test.tsx +0 -1046
- package/src/components/Select/__tests__/Select.search-algorithms.test.tsx +0 -968
- package/src/components/Select/__tests__/Select.unit.test.tsx +0 -647
- package/src/components/Select/__tests__/Select.utils.test.tsx +0 -890
- package/src/components/Table/__tests__/Table.accessibility.test.tsx +0 -233
- package/src/components/Table/__tests__/Table.unit.test.tsx +0 -235
- package/src/components/Toast/__tests__/Toast.accessibility.test.tsx +0 -238
- package/src/components/Toast/__tests__/Toast.integration.test.tsx +0 -699
- package/src/components/Toast/__tests__/Toast.unit.test.tsx +0 -750
- package/src/components/Tooltip/__tests__/Tooltip.accessibility.test.tsx +0 -121
- package/src/components/Tooltip/__tests__/Tooltip.unit.test.tsx +0 -185
- package/src/components/UserMenu/__tests__/UserMenu.accessibility.test.tsx +0 -139
- package/src/components/UserMenu/__tests__/UserMenu.integration.test.tsx +0 -188
- package/src/components/UserMenu/__tests__/UserMenu.unit.test.tsx +0 -458
- package/src/components/__tests__/EdgeCaseTesting.enhanced.test.tsx +0 -524
- package/src/components/__tests__/ErrorTesting.enhanced.test.tsx +0 -455
- package/src/components/__tests__/SuperAdminGuard.test.tsx +0 -456
- package/src/components/__tests__/SuperAdminGuard.unit.test.tsx +0 -456
- package/src/components/examples/__tests__/PermissionExample.unit.test.tsx +0 -360
- package/src/hooks/__tests__/hooks.integration.test.tsx +0 -575
- package/src/hooks/__tests__/useApiFetch.unit.test.ts +0 -115
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +0 -133
- package/src/hooks/__tests__/useDebounce.unit.test.ts +0 -82
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +0 -293
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +0 -385
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -286
- package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +0 -838
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -627
- package/src/hooks/__tests__/useRBAC.unit.test.ts +0 -911
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -537
- package/src/hooks/__tests__/useToast.unit.test.tsx +0 -62
- package/src/hooks/__tests__/useZodForm.unit.test.tsx +0 -37
- package/src/hooks/public/__tests__/usePublicEvent.test.tsx +0 -397
- package/src/hooks/public/__tests__/usePublicEventLogo.test.tsx +0 -690
- package/src/hooks/public/__tests__/usePublicRouteParams.test.tsx +0 -449
- package/src/providers/__tests__/EventProvider.unit.test.tsx +0 -768
- package/src/providers/__tests__/OrganisationProvider.basic.test.tsx +0 -116
- package/src/providers/__tests__/OrganisationProvider.unit.test.tsx +0 -1312
- package/src/providers/__tests__/UnifiedAuthProvider.inactivity.test.tsx +0 -601
- package/src/providers/__tests__/UnifiedAuthProvider.unit.test.tsx +0 -683
- package/src/providers/__tests__/index.unit.test.ts +0 -78
- package/src/rbac/__tests__/PagePermissionGuard.test.tsx +0 -673
- package/src/rbac/__tests__/README.md +0 -170
- package/src/rbac/__tests__/RoleBasedRouter.test.tsx +0 -709
- package/src/rbac/__tests__/TestContext.tsx +0 -72
- package/src/rbac/__tests__/__mocks__/cache.ts +0 -144
- package/src/rbac/__tests__/__mocks__/supabase.ts +0 -152
- package/src/rbac/__tests__/adapters-hooks-comprehensive.test.tsx +0 -782
- package/src/rbac/__tests__/adapters-hooks.test.tsx +0 -561
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +0 -963
- package/src/rbac/__tests__/adapters.test.tsx +0 -444
- package/src/rbac/__tests__/api.test.ts +0 -620
- package/src/rbac/__tests__/audit-observability-comprehensive.test.ts +0 -792
- package/src/rbac/__tests__/audit-observability.test.ts +0 -549
- package/src/rbac/__tests__/audit.test.ts +0 -616
- package/src/rbac/__tests__/build-contract-compliance-simple.test.ts +0 -230
- package/src/rbac/__tests__/cache-invalidation-comprehensive.test.ts +0 -889
- package/src/rbac/__tests__/cache-invalidation.test.ts +0 -457
- package/src/rbac/__tests__/cache.test.ts +0 -458
- package/src/rbac/__tests__/components-navigation-guard.enhanced.test.tsx +0 -859
- package/src/rbac/__tests__/components-navigation-guard.test.tsx +0 -895
- package/src/rbac/__tests__/components-navigation-provider.test.tsx +0 -692
- package/src/rbac/__tests__/components-page-permission-guard.test.tsx +0 -673
- package/src/rbac/__tests__/components-page-permission-provider.test.tsx +0 -614
- package/src/rbac/__tests__/components-permission-enforcer.enhanced.fixed.test.tsx +0 -836
- package/src/rbac/__tests__/components-permission-enforcer.enhanced.test.tsx +0 -837
- package/src/rbac/__tests__/components-permission-enforcer.test.tsx +0 -825
- package/src/rbac/__tests__/components-role-based-router.test.tsx +0 -709
- package/src/rbac/__tests__/components-secure-data-provider.test.tsx +0 -607
- package/src/rbac/__tests__/config.test.ts +0 -583
- package/src/rbac/__tests__/core-logic-unit.test.ts +0 -190
- package/src/rbac/__tests__/core-permission-logic-comprehensive.test.ts +0 -1467
- package/src/rbac/__tests__/core-permission-logic-fixed.test.ts +0 -151
- package/src/rbac/__tests__/core-permission-logic-simple.test.ts +0 -968
- package/src/rbac/__tests__/core-permission-logic.test.ts +0 -966
- package/src/rbac/__tests__/edge-cases-comprehensive.test.ts +0 -988
- package/src/rbac/__tests__/edge-cases.test.ts +0 -654
- package/src/rbac/__tests__/engine.test.ts +0 -361
- package/src/rbac/__tests__/engine.unit.test.ts +0 -361
- package/src/rbac/__tests__/hooks.enhanced.test.tsx +0 -979
- package/src/rbac/__tests__/hooks.fixed.test.tsx +0 -475
- package/src/rbac/__tests__/hooks.test.tsx +0 -385
- package/src/rbac/__tests__/index.test.ts +0 -269
- package/src/rbac/__tests__/integration.enhanced.test.tsx +0 -824
- package/src/rbac/__tests__/page-permission-guard-super-admin.test.tsx +0 -261
- package/src/rbac/__tests__/performance.enhanced.test.tsx +0 -724
- package/src/rbac/__tests__/permissions.test.ts +0 -383
- package/src/rbac/__tests__/requires-event.test.ts +0 -330
- package/src/rbac/__tests__/scope-isolation-comprehensive.test.ts +0 -1349
- package/src/rbac/__tests__/scope-isolation.test.ts +0 -755
- package/src/rbac/__tests__/secure-client-rls-comprehensive.test.ts +0 -592
- package/src/rbac/__tests__/secure-client-rls.test.ts +0 -377
- package/src/rbac/__tests__/security.test.ts +0 -296
- package/src/rbac/__tests__/setup.ts +0 -228
- package/src/rbac/__tests__/test-utils-enhanced.tsx +0 -400
- package/src/rbac/__tests__/types.test.ts +0 -685
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -631
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -667
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -647
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -496
- package/src/rbac/testing/__tests__/index.test.tsx +0 -342
- package/src/rbac/utils/__tests__/eventContext.test.ts +0 -428
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -428
- package/src/styles/__tests__/styles.unit.test.ts +0 -164
- package/src/test-dom-cleanup.test.tsx +0 -38
- package/src/theming/__tests__/README.md +0 -335
- package/src/theming/__tests__/runtime.accessibility.test.ts +0 -474
- package/src/theming/__tests__/runtime.error.test.ts +0 -616
- package/src/theming/__tests__/runtime.integration.test.ts +0 -376
- package/src/theming/__tests__/runtime.performance.test.ts +0 -411
- package/src/theming/__tests__/runtime.unit.test.ts +0 -470
- package/src/types/__tests__/database.unit.test.ts +0 -489
- package/src/types/__tests__/guards.unit.test.ts +0 -146
- package/src/types/__tests__/index.unit.test.ts +0 -77
- package/src/types/__tests__/organisation.unit.test.ts +0 -713
- package/src/types/__tests__/rbac.unit.test.ts +0 -621
- package/src/types/__tests__/security.unit.test.ts +0 -347
- package/src/types/__tests__/supabase.unit.test.ts +0 -658
- package/src/types/__tests__/theme.unit.test.ts +0 -218
- package/src/types/__tests__/unified.unit.test.ts +0 -537
- package/src/types/__tests__/validation.unit.test.ts +0 -616
- package/src/utils/__tests__/appConfig.unit.test.ts +0 -55
- package/src/utils/__tests__/appNameResolver.unit.test.ts +0 -137
- package/src/utils/__tests__/audit.unit.test.ts +0 -69
- package/src/utils/__tests__/auth-utils.unit.test.ts +0 -70
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +0 -317
- package/src/utils/__tests__/cn.unit.test.ts +0 -34
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +0 -480
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +0 -322
- package/src/utils/__tests__/formatDate.unit.test.ts +0 -109
- package/src/utils/__tests__/formatting.unit.test.ts +0 -66
- package/src/utils/__tests__/index.unit.test.ts +0 -251
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -304
- package/src/utils/__tests__/organisationContext.unit.test.ts +0 -192
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +0 -259
- package/src/utils/__tests__/permissionTypes.unit.test.ts +0 -250
- package/src/utils/__tests__/permissionUtils.unit.test.ts +0 -362
- package/src/utils/__tests__/sanitization.unit.test.ts +0 -346
- package/src/utils/__tests__/schemaUtils.unit.test.ts +0 -441
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -334
- package/src/utils/__tests__/secureErrors.unit.test.ts +0 -377
- package/src/utils/__tests__/secureStorage.unit.test.ts +0 -293
- package/src/utils/__tests__/security.unit.test.ts +0 -127
- package/src/utils/__tests__/securityMonitor.unit.test.ts +0 -280
- package/src/utils/__tests__/sessionTracking.unit.test.ts +0 -370
- package/src/utils/__tests__/validation.unit.test.ts +0 -84
- package/src/utils/__tests__/validationUtils.unit.test.ts +0 -571
- package/src/utils/print/__tests__/PrintDataProcessor.unit.test.ts +0 -219
- package/src/utils/print/__tests__/usePrintOptimization.unit.test.tsx +0 -353
- package/src/utils/storage/__tests__/config.unit.test.ts +0 -206
- package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -648
- package/src/utils/storage/__tests__/index.unit.test.ts +0 -167
- package/src/utils/storage/__tests__/types.unit.test.ts +0 -441
- package/src/validation/__tests__/common.unit.test.ts +0 -101
- package/src/validation/__tests__/csrf.unit.test.ts +0 -302
- package/src/validation/__tests__/passwordSchema.unit.test.ts +0 -98
- package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +0 -466
- /package/dist/{DataTable-EEUDXPE5.js.map → DataTable-GX3XERFJ.js.map} +0 -0
- /package/dist/{chunk-VYG4AXYW.js.map → chunk-5EL3KHOQ.js.map} +0 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Checkbox Component Tests
|
|
3
|
+
* @description Comprehensive tests for Checkbox component
|
|
4
|
+
* @package @jmruthers/pace-core
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { screen } from '@testing-library/react';
|
|
9
|
+
import userEvent from '@testing-library/user-event';
|
|
10
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
11
|
+
import { Checkbox } from './Checkbox';
|
|
12
|
+
import { renderWithProviders } from '../../__tests__/helpers/test-utils';
|
|
13
|
+
|
|
14
|
+
describe('Checkbox Component', () => {
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
vi.clearAllMocks();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('Rendering', () => {
|
|
20
|
+
it('renders with default props', () => {
|
|
21
|
+
renderWithProviders(<Checkbox />);
|
|
22
|
+
const checkbox = screen.getByRole('checkbox');
|
|
23
|
+
expect(checkbox).toBeInTheDocument();
|
|
24
|
+
expect(checkbox).not.toBeChecked();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('renders with custom className', () => {
|
|
28
|
+
renderWithProviders(<Checkbox className="custom-checkbox" />);
|
|
29
|
+
const checkbox = screen.getByRole('checkbox');
|
|
30
|
+
expect(checkbox).toHaveClass('custom-checkbox');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('renders with custom id', () => {
|
|
34
|
+
renderWithProviders(<Checkbox id="test-checkbox" />);
|
|
35
|
+
const checkbox = screen.getByRole('checkbox');
|
|
36
|
+
expect(checkbox).toHaveAttribute('id', 'test-checkbox');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('renders with custom name (Radix UI handles this internally)', () => {
|
|
40
|
+
renderWithProviders(<Checkbox name="test-name" />);
|
|
41
|
+
const checkbox = screen.getByRole('checkbox');
|
|
42
|
+
expect(checkbox).toBeInTheDocument();
|
|
43
|
+
// Note: Radix UI Checkbox doesn't expose name attribute directly
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('renders with value prop', () => {
|
|
47
|
+
renderWithProviders(<Checkbox value="test-value" />);
|
|
48
|
+
const checkbox = screen.getByRole('checkbox');
|
|
49
|
+
expect(checkbox).toHaveAttribute('value', 'test-value');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('forwards ref correctly', () => {
|
|
53
|
+
const ref = React.createRef<HTMLButtonElement>();
|
|
54
|
+
renderWithProviders(<Checkbox ref={ref} />);
|
|
55
|
+
expect(ref.current).toBeInstanceOf(HTMLButtonElement);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('applies all HTML attributes', () => {
|
|
59
|
+
renderWithProviders(
|
|
60
|
+
<Checkbox
|
|
61
|
+
data-testid="test-checkbox"
|
|
62
|
+
aria-label="Test checkbox"
|
|
63
|
+
title="Test title"
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
const checkbox = screen.getByRole('checkbox');
|
|
67
|
+
expect(checkbox).toHaveAttribute('data-testid', 'test-checkbox');
|
|
68
|
+
expect(checkbox).toHaveAttribute('aria-label', 'Test checkbox');
|
|
69
|
+
expect(checkbox).toHaveAttribute('title', 'Test title');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('State Management', () => {
|
|
74
|
+
it('renders as unchecked by default', () => {
|
|
75
|
+
renderWithProviders(<Checkbox />);
|
|
76
|
+
const checkbox = screen.getByRole('checkbox');
|
|
77
|
+
expect(checkbox).not.toBeChecked();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('renders as checked when checked prop is true', () => {
|
|
81
|
+
renderWithProviders(<Checkbox checked={true} />);
|
|
82
|
+
const checkbox = screen.getByRole('checkbox');
|
|
83
|
+
expect(checkbox).toBeChecked();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('renders as unchecked when checked prop is false', () => {
|
|
87
|
+
renderWithProviders(<Checkbox checked={false} />);
|
|
88
|
+
const checkbox = screen.getByRole('checkbox');
|
|
89
|
+
expect(checkbox).not.toBeChecked();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('handles controlled state changes', () => {
|
|
93
|
+
const handleCheckedChange = vi.fn();
|
|
94
|
+
renderWithProviders(
|
|
95
|
+
<Checkbox
|
|
96
|
+
checked={false}
|
|
97
|
+
onCheckedChange={handleCheckedChange}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
const checkbox = screen.getByRole('checkbox');
|
|
101
|
+
expect(checkbox).not.toBeChecked();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('handles indeterminate state', () => {
|
|
105
|
+
renderWithProviders(<Checkbox checked="indeterminate" />);
|
|
106
|
+
const checkbox = screen.getByRole('checkbox');
|
|
107
|
+
expect(checkbox).toHaveAttribute('aria-checked', 'mixed');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('Disabled State', () => {
|
|
112
|
+
it('renders as disabled when disabled prop is true', () => {
|
|
113
|
+
renderWithProviders(<Checkbox disabled={true} />);
|
|
114
|
+
const checkbox = screen.getByRole('checkbox');
|
|
115
|
+
expect(checkbox).toBeDisabled();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('renders as enabled when disabled prop is false', () => {
|
|
119
|
+
renderWithProviders(<Checkbox disabled={false} />);
|
|
120
|
+
const checkbox = screen.getByRole('checkbox');
|
|
121
|
+
expect(checkbox).not.toBeDisabled();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('applies disabled styling', () => {
|
|
125
|
+
renderWithProviders(<Checkbox disabled={true} />);
|
|
126
|
+
const checkbox = screen.getByRole('checkbox');
|
|
127
|
+
expect(checkbox).toHaveClass('disabled:cursor-not-allowed', 'disabled:opacity-50');
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('Event Handling', () => {
|
|
132
|
+
it('handles click events', async () => {
|
|
133
|
+
const handleCheckedChange = vi.fn();
|
|
134
|
+
const user = userEvent.setup();
|
|
135
|
+
|
|
136
|
+
renderWithProviders(
|
|
137
|
+
<Checkbox onCheckedChange={handleCheckedChange} />
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const checkbox = screen.getByRole('checkbox');
|
|
141
|
+
await user.click(checkbox);
|
|
142
|
+
|
|
143
|
+
expect(handleCheckedChange).toHaveBeenCalledTimes(1);
|
|
144
|
+
expect(handleCheckedChange).toHaveBeenCalledWith(true);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('handles keyboard events (Space)', async () => {
|
|
148
|
+
const handleCheckedChange = vi.fn();
|
|
149
|
+
const user = userEvent.setup();
|
|
150
|
+
|
|
151
|
+
renderWithProviders(
|
|
152
|
+
<Checkbox onCheckedChange={handleCheckedChange} />
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const checkbox = screen.getByRole('checkbox');
|
|
156
|
+
checkbox.focus();
|
|
157
|
+
await user.keyboard(' ');
|
|
158
|
+
|
|
159
|
+
expect(handleCheckedChange).toHaveBeenCalledTimes(1);
|
|
160
|
+
expect(handleCheckedChange).toHaveBeenCalledWith(true);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('handles keyboard events (Enter - Radix UI uses Space)', async () => {
|
|
164
|
+
const handleCheckedChange = vi.fn();
|
|
165
|
+
const user = userEvent.setup();
|
|
166
|
+
|
|
167
|
+
renderWithProviders(
|
|
168
|
+
<Checkbox onCheckedChange={handleCheckedChange} />
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const checkbox = screen.getByRole('checkbox');
|
|
172
|
+
checkbox.focus();
|
|
173
|
+
await user.keyboard('{Enter}');
|
|
174
|
+
|
|
175
|
+
// Note: Radix UI Checkbox primarily uses Space key, Enter may not trigger
|
|
176
|
+
// This test documents the expected behavior
|
|
177
|
+
expect(handleCheckedChange).toHaveBeenCalledTimes(0);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('toggles state on click', async () => {
|
|
181
|
+
const handleCheckedChange = vi.fn();
|
|
182
|
+
const user = userEvent.setup();
|
|
183
|
+
|
|
184
|
+
const { rerender } = renderWithProviders(
|
|
185
|
+
<Checkbox checked={false} onCheckedChange={handleCheckedChange} />
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const checkbox = screen.getByRole('checkbox');
|
|
189
|
+
await user.click(checkbox);
|
|
190
|
+
|
|
191
|
+
expect(handleCheckedChange).toHaveBeenCalledWith(true);
|
|
192
|
+
|
|
193
|
+
// Simulate state change
|
|
194
|
+
rerender(<Checkbox checked={true} onCheckedChange={handleCheckedChange} />);
|
|
195
|
+
expect(checkbox).toBeChecked();
|
|
196
|
+
|
|
197
|
+
await user.click(checkbox);
|
|
198
|
+
expect(handleCheckedChange).toHaveBeenCalledWith(false);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('does not trigger events when disabled', async () => {
|
|
202
|
+
const handleCheckedChange = vi.fn();
|
|
203
|
+
const user = userEvent.setup();
|
|
204
|
+
|
|
205
|
+
renderWithProviders(
|
|
206
|
+
<Checkbox disabled={true} onCheckedChange={handleCheckedChange} />
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const checkbox = screen.getByRole('checkbox');
|
|
210
|
+
await user.click(checkbox);
|
|
211
|
+
|
|
212
|
+
expect(handleCheckedChange).not.toHaveBeenCalled();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
describe('Accessibility', () => {
|
|
217
|
+
it('has proper ARIA attributes', () => {
|
|
218
|
+
renderWithProviders(<Checkbox />);
|
|
219
|
+
const checkbox = screen.getByRole('checkbox');
|
|
220
|
+
expect(checkbox).toHaveAttribute('type', 'button');
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('supports aria-label', () => {
|
|
224
|
+
renderWithProviders(<Checkbox aria-label="Accept terms" />);
|
|
225
|
+
const checkbox = screen.getByRole('checkbox', { name: 'Accept terms' });
|
|
226
|
+
expect(checkbox).toBeInTheDocument();
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('supports aria-labelledby', () => {
|
|
230
|
+
renderWithProviders(
|
|
231
|
+
<div>
|
|
232
|
+
<label id="terms-label">Accept terms and conditions</label>
|
|
233
|
+
<Checkbox aria-labelledby="terms-label" />
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
const checkbox = screen.getByRole('checkbox', { name: 'Accept terms and conditions' });
|
|
237
|
+
expect(checkbox).toBeInTheDocument();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('supports aria-describedby', () => {
|
|
241
|
+
renderWithProviders(
|
|
242
|
+
<div>
|
|
243
|
+
<Checkbox aria-describedby="terms-help" />
|
|
244
|
+
<div id="terms-help">Please read the terms carefully</div>
|
|
245
|
+
</div>
|
|
246
|
+
);
|
|
247
|
+
const checkbox = screen.getByRole('checkbox');
|
|
248
|
+
expect(checkbox).toHaveAttribute('aria-describedby', 'terms-help');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('announces state changes to screen readers', () => {
|
|
252
|
+
const { rerender } = renderWithProviders(<Checkbox checked={false} />);
|
|
253
|
+
let checkbox = screen.getByRole('checkbox');
|
|
254
|
+
expect(checkbox).toHaveAttribute('aria-checked', 'false');
|
|
255
|
+
|
|
256
|
+
rerender(<Checkbox checked={true} />);
|
|
257
|
+
checkbox = screen.getByRole('checkbox');
|
|
258
|
+
expect(checkbox).toHaveAttribute('aria-checked', 'true');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('is keyboard accessible', () => {
|
|
262
|
+
renderWithProviders(<Checkbox />);
|
|
263
|
+
const checkbox = screen.getByRole('checkbox');
|
|
264
|
+
expect(checkbox).not.toHaveAttribute('tabindex', '-1');
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('has focus visible styles', () => {
|
|
268
|
+
renderWithProviders(<Checkbox />);
|
|
269
|
+
const checkbox = screen.getByRole('checkbox');
|
|
270
|
+
expect(checkbox).toHaveClass('focus-visible:outline-none', 'focus-visible:ring-2');
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
describe('Visual States', () => {
|
|
275
|
+
it('applies checked state styling', () => {
|
|
276
|
+
renderWithProviders(<Checkbox checked={true} />);
|
|
277
|
+
const checkbox = screen.getByRole('checkbox');
|
|
278
|
+
expect(checkbox).toHaveClass('data-[state=checked]:bg-primary', 'data-[state=checked]:text-primary-foreground');
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('shows check icon when checked', () => {
|
|
282
|
+
renderWithProviders(<Checkbox checked={true} />);
|
|
283
|
+
const checkbox = screen.getByRole('checkbox');
|
|
284
|
+
// The check icon is rendered by Radix UI internally
|
|
285
|
+
// We can verify the checkbox is checked instead
|
|
286
|
+
expect(checkbox).toBeChecked();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('has proper sizing', () => {
|
|
290
|
+
renderWithProviders(<Checkbox />);
|
|
291
|
+
const checkbox = screen.getByRole('checkbox');
|
|
292
|
+
expect(checkbox).toHaveClass('h-4', 'w-4');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('has proper border and background styling', () => {
|
|
296
|
+
renderWithProviders(<Checkbox />);
|
|
297
|
+
const checkbox = screen.getByRole('checkbox');
|
|
298
|
+
expect(checkbox).toHaveClass('rounded-sm', 'border', 'border-primary');
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
describe('Form Integration', () => {
|
|
303
|
+
it('works with form labels', () => {
|
|
304
|
+
renderWithProviders(
|
|
305
|
+
<div>
|
|
306
|
+
<label htmlFor="terms-checkbox">Accept terms and conditions</label>
|
|
307
|
+
<Checkbox id="terms-checkbox" />
|
|
308
|
+
</div>
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
const checkbox = screen.getByRole('checkbox');
|
|
312
|
+
const label = screen.getByText('Accept terms and conditions');
|
|
313
|
+
|
|
314
|
+
expect(checkbox).toHaveAttribute('id', 'terms-checkbox');
|
|
315
|
+
expect(label).toHaveAttribute('for', 'terms-checkbox');
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('works with form submission', async () => {
|
|
319
|
+
const handleSubmit = vi.fn((e) => e.preventDefault());
|
|
320
|
+
const user = userEvent.setup();
|
|
321
|
+
|
|
322
|
+
renderWithProviders(
|
|
323
|
+
<form onSubmit={handleSubmit}>
|
|
324
|
+
<Checkbox name="terms" />
|
|
325
|
+
<button type="submit">Submit</button>
|
|
326
|
+
</form>
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
await user.click(screen.getByRole('button', { name: 'Submit' }));
|
|
330
|
+
expect(handleSubmit).toHaveBeenCalledTimes(1);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('works with form validation', () => {
|
|
334
|
+
renderWithProviders(
|
|
335
|
+
<Checkbox
|
|
336
|
+
aria-invalid={true}
|
|
337
|
+
aria-describedby="error-message"
|
|
338
|
+
/>
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
const checkbox = screen.getByRole('checkbox');
|
|
342
|
+
// Radix UI Checkbox doesn't support required attribute directly
|
|
343
|
+
expect(checkbox).toHaveAttribute('aria-invalid', 'true');
|
|
344
|
+
expect(checkbox).toHaveAttribute('aria-describedby', 'error-message');
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
describe('Error Handling', () => {
|
|
349
|
+
it('handles missing onCheckedChange gracefully', () => {
|
|
350
|
+
renderWithProviders(<Checkbox checked={true} />);
|
|
351
|
+
const checkbox = screen.getByRole('checkbox');
|
|
352
|
+
expect(checkbox).toBeChecked();
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('handles invalid props gracefully', () => {
|
|
356
|
+
// @ts-expect-error Testing invalid prop
|
|
357
|
+
renderWithProviders(<Checkbox invalidProp="test" />);
|
|
358
|
+
const checkbox = screen.getByRole('checkbox');
|
|
359
|
+
expect(checkbox).toBeInTheDocument();
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it('handles null children gracefully', () => {
|
|
363
|
+
renderWithProviders(<Checkbox>{null}</Checkbox>);
|
|
364
|
+
const checkbox = screen.getByRole('checkbox');
|
|
365
|
+
expect(checkbox).toBeInTheDocument();
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
describe('Integration', () => {
|
|
370
|
+
it('works with multiple checkboxes', () => {
|
|
371
|
+
renderWithProviders(
|
|
372
|
+
<div>
|
|
373
|
+
<Checkbox id="option1" />
|
|
374
|
+
<Checkbox id="option2" />
|
|
375
|
+
<Checkbox id="option3" />
|
|
376
|
+
</div>
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
expect(screen.getAllByRole('checkbox')).toHaveLength(3);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it('works with checkbox groups', () => {
|
|
383
|
+
renderWithProviders(
|
|
384
|
+
<fieldset>
|
|
385
|
+
<legend>Select your preferences</legend>
|
|
386
|
+
<Checkbox id="email" value="email" />
|
|
387
|
+
<label htmlFor="email">Email notifications</label>
|
|
388
|
+
<Checkbox id="sms" value="sms" />
|
|
389
|
+
<label htmlFor="sms">SMS notifications</label>
|
|
390
|
+
</fieldset>
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
const checkboxes = screen.getAllByRole('checkbox');
|
|
394
|
+
expect(checkboxes).toHaveLength(2);
|
|
395
|
+
// Radix UI Checkbox doesn't expose name attribute directly
|
|
396
|
+
expect(checkboxes[0]).toHaveAttribute('id', 'email');
|
|
397
|
+
expect(checkboxes[1]).toHaveAttribute('id', 'sms');
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it('works with controlled state management', async () => {
|
|
401
|
+
const TestComponent = () => {
|
|
402
|
+
const [checked, setChecked] = React.useState(false);
|
|
403
|
+
return (
|
|
404
|
+
<div>
|
|
405
|
+
<Checkbox
|
|
406
|
+
checked={checked}
|
|
407
|
+
onCheckedChange={setChecked}
|
|
408
|
+
/>
|
|
409
|
+
<span data-testid="status">{checked ? 'checked' : 'unchecked'}</span>
|
|
410
|
+
</div>
|
|
411
|
+
);
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const user = userEvent.setup();
|
|
415
|
+
renderWithProviders(<TestComponent />);
|
|
416
|
+
|
|
417
|
+
const checkbox = screen.getByRole('checkbox');
|
|
418
|
+
const status = screen.getByTestId('status');
|
|
419
|
+
|
|
420
|
+
expect(status).toHaveTextContent('unchecked');
|
|
421
|
+
|
|
422
|
+
await user.click(checkbox);
|
|
423
|
+
expect(status).toHaveTextContent('checked');
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it('works with external state management', async () => {
|
|
427
|
+
const externalState = { checked: false };
|
|
428
|
+
const handleChange = vi.fn((checked) => {
|
|
429
|
+
externalState.checked = checked;
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
const user = userEvent.setup();
|
|
433
|
+
renderWithProviders(
|
|
434
|
+
<Checkbox
|
|
435
|
+
checked={externalState.checked}
|
|
436
|
+
onCheckedChange={handleChange}
|
|
437
|
+
/>
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
const checkbox = screen.getByRole('checkbox');
|
|
441
|
+
await user.click(checkbox);
|
|
442
|
+
|
|
443
|
+
expect(handleChange).toHaveBeenCalledWith(true);
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
describe('Performance', () => {
|
|
448
|
+
it('renders efficiently with many checkboxes', () => {
|
|
449
|
+
const checkboxes = Array.from({ length: 100 }, (_, i) => (
|
|
450
|
+
<Checkbox key={i} id={`checkbox-${i}`} />
|
|
451
|
+
));
|
|
452
|
+
|
|
453
|
+
const startTime = performance.now();
|
|
454
|
+
renderWithProviders(<div>{checkboxes}</div>);
|
|
455
|
+
const endTime = performance.now();
|
|
456
|
+
|
|
457
|
+
expect(screen.getAllByRole('checkbox')).toHaveLength(100);
|
|
458
|
+
expect(endTime - startTime).toBeLessThan(1000); // Should render in under 1 second
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
});
|
|
@@ -278,7 +278,8 @@ import type {
|
|
|
278
278
|
SimpleColumn,
|
|
279
279
|
AggregateConfig,
|
|
280
280
|
DataTableAction,
|
|
281
|
-
HierarchicalConfig
|
|
281
|
+
HierarchicalConfig,
|
|
282
|
+
DataTableRBACConfig
|
|
282
283
|
} from './types';
|
|
283
284
|
import type { ImportModalConfig } from './components/ImportModal';
|
|
284
285
|
|
|
@@ -300,6 +301,13 @@ export interface DataTableProps<TData extends DataRecord> {
|
|
|
300
301
|
/** Column definitions for the table */
|
|
301
302
|
columns: DataTableColumn<TData>[];
|
|
302
303
|
|
|
304
|
+
// ========================================
|
|
305
|
+
// MANDATORY RBAC
|
|
306
|
+
// ========================================
|
|
307
|
+
|
|
308
|
+
/** RBAC configuration - REQUIRED for all DataTables */
|
|
309
|
+
rbac: DataTableRBACConfig;
|
|
310
|
+
|
|
303
311
|
// ========================================
|
|
304
312
|
// DISPLAY
|
|
305
313
|
// ========================================
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Access Denied Page Component
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/DataTable/Components
|
|
5
|
+
* @since 2.0.0
|
|
6
|
+
*
|
|
7
|
+
* A component displayed when users lack permission to access DataTable data.
|
|
8
|
+
* Provides clear messaging about access restrictions and next steps.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Clear access denied messaging
|
|
12
|
+
* - Resource-specific error information
|
|
13
|
+
* - Consistent styling with pace-core design system
|
|
14
|
+
* - Accessibility compliant
|
|
15
|
+
* - Actionable next steps for users
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* <AccessDeniedPage
|
|
20
|
+
* resource="users"
|
|
21
|
+
* operation="read"
|
|
22
|
+
* message="You don't have permission to view user data"
|
|
23
|
+
* />
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @accessibility
|
|
27
|
+
* - Proper ARIA labels and roles
|
|
28
|
+
* - High contrast support
|
|
29
|
+
* - Screen reader friendly
|
|
30
|
+
* - Keyboard navigation support
|
|
31
|
+
*
|
|
32
|
+
* @dependencies
|
|
33
|
+
* - Card component for layout
|
|
34
|
+
* - Button component for actions
|
|
35
|
+
* - Lucide React icons
|
|
36
|
+
* - React 18+ hooks
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
import React from 'react';
|
|
40
|
+
import { Card } from '../../Card/Card';
|
|
41
|
+
import { Button } from '../../Button/Button';
|
|
42
|
+
import { ShieldX, ArrowLeft, RefreshCw } from 'lucide-react';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Props for the AccessDeniedPage component
|
|
46
|
+
*/
|
|
47
|
+
export interface AccessDeniedPageProps {
|
|
48
|
+
/** Resource that was denied access to */
|
|
49
|
+
resource: string;
|
|
50
|
+
/** Operation that was denied */
|
|
51
|
+
operation?: string;
|
|
52
|
+
/** Custom error message */
|
|
53
|
+
message?: string;
|
|
54
|
+
/** Callback when retry is clicked */
|
|
55
|
+
onRetry?: () => void;
|
|
56
|
+
/** Callback when back is clicked */
|
|
57
|
+
onBack?: () => void;
|
|
58
|
+
/** Custom class names */
|
|
59
|
+
className?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Access denied page for DataTable when users lack permissions
|
|
64
|
+
*
|
|
65
|
+
* This component is displayed when a user attempts to access DataTable data
|
|
66
|
+
* but lacks the necessary permissions. It provides clear messaging about
|
|
67
|
+
* the access restriction and offers actionable next steps.
|
|
68
|
+
*
|
|
69
|
+
* @param props - Component configuration
|
|
70
|
+
* @returns JSX.Element - The rendered access denied page
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* <AccessDeniedPage
|
|
75
|
+
* resource="users"
|
|
76
|
+
* operation="read"
|
|
77
|
+
* onRetry={() => window.location.reload()}
|
|
78
|
+
* onBack={() => navigate('/dashboard')}
|
|
79
|
+
* />
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export function AccessDeniedPage({
|
|
83
|
+
resource,
|
|
84
|
+
operation = 'access',
|
|
85
|
+
message,
|
|
86
|
+
onRetry,
|
|
87
|
+
onBack,
|
|
88
|
+
className,
|
|
89
|
+
}: AccessDeniedPageProps) {
|
|
90
|
+
const defaultMessage = message || `You don't have permission to ${operation} ${resource} data`;
|
|
91
|
+
|
|
92
|
+
const handleRetry = () => {
|
|
93
|
+
if (onRetry) {
|
|
94
|
+
onRetry();
|
|
95
|
+
} else {
|
|
96
|
+
window.location.reload();
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const handleBack = () => {
|
|
101
|
+
if (onBack) {
|
|
102
|
+
onBack();
|
|
103
|
+
} else {
|
|
104
|
+
window.history.back();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<div className={`flex items-center justify-center min-h-[400px] p-8 ${className || ''}`}>
|
|
110
|
+
<Card className="max-w-md w-full text-center">
|
|
111
|
+
<div className="flex flex-col items-center space-y-6 p-8">
|
|
112
|
+
{/* Icon */}
|
|
113
|
+
<div className="flex items-center justify-center w-16 h-16 rounded-full bg-acc-100">
|
|
114
|
+
<ShieldX className="w-8 h-8 text-acc-600" />
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
{/* Title */}
|
|
118
|
+
<div className="space-y-2">
|
|
119
|
+
<h2 className="text-xl font-semibold text-sec-900">
|
|
120
|
+
Access Denied
|
|
121
|
+
</h2>
|
|
122
|
+
<p className="text-sec-600">
|
|
123
|
+
{defaultMessage}
|
|
124
|
+
</p>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
{/* Resource info */}
|
|
128
|
+
<div className="text-sm text-sec-500 bg-sec-50 rounded-lg p-3 w-full">
|
|
129
|
+
<strong>Resource:</strong> {resource}
|
|
130
|
+
{operation && (
|
|
131
|
+
<>
|
|
132
|
+
<br />
|
|
133
|
+
<strong>Operation:</strong> {operation}
|
|
134
|
+
</>
|
|
135
|
+
)}
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
{/* Actions */}
|
|
139
|
+
<div className="flex flex-col sm:flex-row gap-3 w-full">
|
|
140
|
+
{onRetry && (
|
|
141
|
+
<Button
|
|
142
|
+
variant="outline"
|
|
143
|
+
onClick={handleRetry}
|
|
144
|
+
className="flex-1"
|
|
145
|
+
>
|
|
146
|
+
<RefreshCw className="w-4 h-4 mr-2" />
|
|
147
|
+
Retry
|
|
148
|
+
</Button>
|
|
149
|
+
)}
|
|
150
|
+
<Button
|
|
151
|
+
variant="outline"
|
|
152
|
+
onClick={handleBack}
|
|
153
|
+
className="flex-1"
|
|
154
|
+
>
|
|
155
|
+
<ArrowLeft className="w-4 h-4 mr-2" />
|
|
156
|
+
Go Back
|
|
157
|
+
</Button>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
{/* Help text */}
|
|
161
|
+
<div className="text-xs text-sec-400">
|
|
162
|
+
If you believe this is an error, please contact your administrator.
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</Card>
|
|
166
|
+
</div>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
@@ -38,6 +38,15 @@ interface ActionButtonsProps {
|
|
|
38
38
|
// Hierarchical context
|
|
39
39
|
isParent?: boolean;
|
|
40
40
|
hierarchical?: boolean;
|
|
41
|
+
// MANDATORY RBAC
|
|
42
|
+
rbac?: {
|
|
43
|
+
resource: string;
|
|
44
|
+
pageId?: string;
|
|
45
|
+
};
|
|
46
|
+
permissions?: {
|
|
47
|
+
canUpdate: { can: boolean; isLoading: boolean };
|
|
48
|
+
canDelete: { can: boolean; isLoading: boolean };
|
|
49
|
+
};
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
export function ActionButtons({
|
|
@@ -46,6 +55,8 @@ export function ActionButtons({
|
|
|
46
55
|
isEditing = false,
|
|
47
56
|
isParent = false,
|
|
48
57
|
hierarchical = false,
|
|
58
|
+
rbac,
|
|
59
|
+
permissions,
|
|
49
60
|
}: ActionButtonsProps) {
|
|
50
61
|
// Return null if no actions are provided
|
|
51
62
|
if (actions.length === 0) {
|
|
@@ -55,10 +66,16 @@ export function ActionButtons({
|
|
|
55
66
|
// Use provided actions
|
|
56
67
|
const allActions = actions;
|
|
57
68
|
|
|
58
|
-
// Filter actions based on current mode, visibility,
|
|
69
|
+
// Filter actions based on current mode, visibility, hierarchical context, and RBAC
|
|
59
70
|
const visibleActions = allActions.filter(action => {
|
|
60
71
|
if (action.hidden) return false;
|
|
61
72
|
|
|
73
|
+
// MANDATORY: Check RBAC permissions for standard actions
|
|
74
|
+
if (permissions) {
|
|
75
|
+
if (action.label === 'Edit' && !permissions.canUpdate.can) return false;
|
|
76
|
+
if (action.label === 'Delete' && !permissions.canDelete.can) return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
62
79
|
// Check hierarchical visibility
|
|
63
80
|
if (hierarchical) {
|
|
64
81
|
if (action.showForParent && !isParent) return false;
|