@jmruthers/pace-core 0.5.76 → 0.5.78
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/CHANGELOG.md +8 -0
- package/dist/{RBACService-C4udt_Zp.d.ts → AuthService-Df3IozMG.d.ts} +10 -118
- package/dist/{DataTable-ntgmhO2W.d.ts → DataTable-BE0OXZKQ.d.ts} +9 -2
- package/dist/{DataTable-4GAVPIEG.js → DataTable-ETGVF4Y5.js} +50 -13
- package/dist/{PublicLoadingSpinner-BiNER8F5.d.ts → PublicLoadingSpinner-CnUaz0vG.d.ts} +5 -2
- package/dist/{UnifiedAuthProvider-Bj6YCf7c.d.ts → UnifiedAuthProvider-B391Aqum.d.ts} +42 -45
- package/dist/{UnifiedAuthProvider-3NKDOSOK.js → UnifiedAuthProvider-P5SOJAQ6.js} +4 -5
- package/dist/{api-DDMUKIUD.js → api-KG4A2X7P.js} +9 -3
- package/dist/{audit-6TOCAMKO.js → audit-65VNHEV2.js} +2 -2
- package/dist/{chunk-K34IM5CT.js → chunk-2OGV6IRV.js} +196 -626
- package/dist/chunk-2OGV6IRV.js.map +1 -0
- package/dist/{chunk-NTNILOBC.js → chunk-5BO3MI5Y.js} +4 -4
- package/dist/{chunk-XLZ7U46Z.js → chunk-CVMVPYAL.js} +9 -60
- package/dist/chunk-CVMVPYAL.js.map +1 -0
- package/dist/{chunk-URUTVZ7N.js → chunk-FL4ZCQLD.js} +2 -2
- package/dist/{chunk-LW7MMEAQ.js → chunk-FT2M4R4F.js} +2 -2
- package/dist/{chunk-5BSLGBYI.js → chunk-JCQZ6LA7.js} +2 -8
- package/dist/{chunk-5BSLGBYI.js.map → chunk-JCQZ6LA7.js.map} +1 -1
- package/dist/{chunk-KHJS6VIA.js → chunk-LRQ6RBJC.js} +157 -112
- package/dist/chunk-LRQ6RBJC.js.map +1 -0
- package/dist/{chunk-WN6XJWOS.js → chunk-MNJXXD6C.js} +274 -743
- package/dist/chunk-MNJXXD6C.js.map +1 -0
- package/dist/{chunk-KK73ZB4E.js → chunk-PTR5PMPE.js} +153 -132
- package/dist/chunk-PTR5PMPE.js.map +1 -0
- package/dist/{chunk-B2WTCLCV.js → chunk-Q7APDV6H.js} +18 -8
- package/dist/chunk-Q7APDV6H.js.map +1 -0
- package/dist/{chunk-A4FUBC7B.js → chunk-QGVSOUJ2.js} +2 -4
- package/dist/{chunk-A4FUBC7B.js.map → chunk-QGVSOUJ2.js.map} +1 -1
- package/dist/{chunk-FGMFQSHX.js → chunk-S63MFSY6.js} +500 -551
- package/dist/chunk-S63MFSY6.js.map +1 -0
- package/dist/{chunk-AFGTSUAD.js → chunk-VSOKOFRF.js} +4 -4
- package/dist/chunk-WUXCWRL6.js +20 -0
- package/dist/chunk-WUXCWRL6.js.map +1 -0
- package/dist/{chunk-Y6TXWPJO.js → chunk-YVVGHRGI.js} +105 -31
- package/dist/chunk-YVVGHRGI.js.map +1 -0
- package/dist/{chunk-M5IWZRBT.js → chunk-ZMNXIJP4.js} +2187 -981
- package/dist/chunk-ZMNXIJP4.js.map +1 -0
- package/dist/components.d.ts +6 -6
- package/dist/components.js +14 -18
- package/dist/components.js.map +1 -1
- package/dist/{database-C3Szpi5J.d.ts → database-BXAfr2Y_.d.ts} +18 -0
- package/dist/hooks.d.ts +5 -5
- package/dist/hooks.js +8 -9
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +19 -27
- package/dist/index.js +21 -29
- package/dist/index.js.map +1 -1
- package/dist/{organisation-BtshODVF.d.ts → organisation-D6qRDtbF.d.ts} +1 -1
- package/dist/providers.d.ts +7 -21
- package/dist/providers.js +3 -10
- package/dist/rbac/index.d.ts +71 -221
- package/dist/rbac/index.js +15 -16
- package/dist/{types-CGX9Vyf5.d.ts → types-BDg1mAGG.d.ts} +36 -6
- package/dist/types.d.ts +3 -3
- package/dist/types.js +61 -18
- package/dist/types.js.map +1 -1
- package/dist/{unified-CM7T0aTK.d.ts → unified-DQ4VcT7H.d.ts} +1 -1
- package/dist/{usePublicRouteParams-B-CumWRc.d.ts → usePublicRouteParams-BlgwXweB.d.ts} +3 -3
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +52 -9
- package/dist/utils.js.map +1 -1
- package/docs/CONTENT_AUDIT_REPORT.md +253 -0
- package/docs/DOCUMENTATION_AUDIT.md +172 -0
- package/docs/README.md +142 -147
- package/docs/STYLE_GUIDE.md +37 -0
- package/docs/api/classes/ColumnFactory.md +17 -17
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +4 -4
- package/docs/api/classes/MissingUserContextError.md +4 -4
- package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
- package/docs/api/classes/PermissionDeniedError.md +5 -5
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +8 -8
- package/docs/api/classes/RBACCache.md +35 -5
- package/docs/api/classes/RBACEngine.md +49 -20
- package/docs/api/classes/RBACError.md +4 -4
- package/docs/api/classes/RBACNotInitializedError.md +4 -4
- 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 +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +11 -0
- package/docs/api/interfaces/DataTableAction.md +65 -29
- package/docs/api/interfaces/DataTableColumn.md +36 -23
- package/docs/api/interfaces/DataTableProps.md +80 -38
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- 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/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 +11 -11
- package/docs/api/interfaces/NavigationContextType.md +9 -9
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- 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 +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +16 -3
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +2 -2
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +4 -4
- 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/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +2 -2
- package/docs/api/interfaces/RouteConfig.md +2 -2
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.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/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 +94 -521
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +16 -16
- 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/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- 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 +251 -269
- package/docs/api-reference/components.md +193 -0
- package/docs/api-reference/hooks.md +265 -0
- package/docs/api-reference/providers.md +6 -0
- package/docs/api-reference/types.md +6 -0
- package/docs/api-reference/utilities.md +207 -0
- package/docs/architecture/README.md +6 -0
- package/docs/{database-schema-requirements.md → architecture/database-schema-requirements.md} +6 -0
- package/docs/architecture/rbac-security-architecture.md +258 -0
- package/docs/architecture/services.md +9 -1
- package/docs/best-practices/README.md +6 -0
- package/docs/best-practices/accessibility.md +6 -0
- package/docs/{common-patterns.md → best-practices/common-patterns.md} +6 -0
- package/docs/best-practices/deployment.md +6 -0
- package/docs/best-practices/performance.md +475 -2
- package/docs/best-practices/security.md +6 -0
- package/docs/best-practices/testing.md +6 -0
- package/docs/core-concepts/authentication.md +6 -0
- package/docs/core-concepts/events.md +6 -0
- package/docs/core-concepts/organisations.md +6 -0
- package/docs/core-concepts/permissions.md +6 -0
- package/docs/core-concepts/rbac-system.md +8 -0
- package/docs/documentation-index.md +121 -182
- package/docs/{consuming-app-vite-config.md → getting-started/consuming-app-vite-config.md} +6 -0
- package/docs/getting-started/documentation-index.md +40 -0
- package/docs/getting-started/examples/README.md +878 -35
- package/docs/{faq.md → getting-started/faq.md} +7 -1
- package/docs/getting-started/installation-guide.md +6 -0
- package/docs/{quick-reference.md → getting-started/quick-reference.md} +6 -0
- package/docs/implementation-guides/app-layout.md +6 -0
- package/docs/implementation-guides/authentication.md +1021 -0
- package/docs/implementation-guides/component-styling.md +6 -0
- package/docs/implementation-guides/data-tables.md +1264 -2076
- package/docs/implementation-guides/dynamic-colors.md +6 -0
- package/docs/implementation-guides/event-theming-summary.md +6 -0
- package/docs/{file-reference-system.md → implementation-guides/file-reference-system.md} +6 -0
- package/docs/implementation-guides/file-upload-storage.md +6 -0
- package/docs/implementation-guides/forms.md +6 -0
- package/docs/implementation-guides/inactivity-tracking.md +6 -0
- package/docs/implementation-guides/navigation.md +6 -0
- package/docs/implementation-guides/organisation-security.md +6 -0
- package/docs/implementation-guides/permission-enforcement.md +6 -0
- package/docs/implementation-guides/public-pages-advanced.md +6 -0
- package/docs/implementation-guides/public-pages.md +6 -0
- package/docs/migration/MIGRATION_GUIDE.md +827 -351
- package/docs/migration/README.md +7 -1
- package/docs/migration/organisation-context-timing-fix.md +6 -0
- package/docs/migration/rbac-migration.md +44 -1
- package/docs/migration/service-architecture.md +6 -0
- package/docs/migration/v0.4.15-tailwind-scanning.md +6 -0
- package/docs/migration/v0.4.16-css-first-approach.md +6 -0
- package/docs/migration/v0.4.17-source-path-fix.md +6 -0
- package/docs/rbac/README-rbac-rls-integration.md +6 -0
- package/docs/rbac/README.md +6 -0
- package/docs/rbac/advanced-patterns.md +6 -0
- package/docs/rbac/api-reference.md +7 -1
- package/docs/rbac/breaking-changes-v3.md +222 -0
- package/docs/rbac/examples/rbac-rls-integration-example.md +6 -0
- package/docs/rbac/examples.md +6 -0
- package/docs/rbac/getting-started.md +6 -0
- package/docs/rbac/migration-guide.md +260 -0
- package/docs/rbac/quick-start.md +70 -13
- package/docs/rbac/rbac-rls-integration.md +6 -0
- package/docs/rbac/super-admin-guide.md +6 -0
- package/docs/rbac/troubleshooting.md +6 -0
- package/docs/security/README.md +6 -0
- package/docs/security/checklist.md +6 -0
- package/docs/styles/README.md +7 -1
- package/docs/{usage.md → styles/usage.md} +6 -0
- package/docs/testing/README.md +6 -0
- package/docs/{visual-testing.md → testing/visual-testing.md} +6 -0
- package/docs/troubleshooting/README.md +387 -5
- package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +6 -0
- package/docs/troubleshooting/common-issues.md +6 -0
- package/docs/troubleshooting/database-view-compatibility.md +6 -0
- package/docs/troubleshooting/organisation-context-setup.md +6 -0
- package/docs/troubleshooting/react-hooks-issue-analysis.md +6 -0
- package/docs/troubleshooting/styling-issues.md +6 -0
- package/docs/troubleshooting/tailwind-content-scanning.md +6 -0
- package/package.json +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -1
- package/src/__tests__/helpers/test-providers.tsx +3 -53
- package/src/components/DataTable/DataTable.test.tsx +319 -0
- package/src/components/DataTable/DataTable.tsx +32 -11
- package/src/components/DataTable/__tests__/{DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx.skip} +6 -4
- package/src/components/DataTable/__tests__/{DataTable.test.tsx → DataTable.test.tsx.skip} +6 -4
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +31 -9
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +601 -0
- package/src/components/DataTable/__tests__/keyboard.test.tsx +615 -0
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +639 -0
- package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx.skip +330 -0
- package/src/components/DataTable/components/AccessDeniedPage.tsx +2 -2
- package/src/components/DataTable/components/ActionButtons.tsx +88 -104
- package/src/components/DataTable/components/DataTableCore.tsx +309 -337
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +4 -2
- package/src/components/DataTable/components/DataTableModals.tsx +22 -1
- package/src/components/DataTable/components/EditableRow.tsx +69 -84
- package/src/components/DataTable/components/EmptyState.tsx +5 -1
- package/src/components/DataTable/components/ImportModal.tsx +65 -36
- package/src/components/DataTable/components/PaginationControls.tsx +40 -100
- package/src/components/DataTable/components/UnifiedTableBody.tsx +125 -148
- package/src/components/DataTable/context/DataTableContext.tsx +1 -1
- package/src/components/DataTable/core/ColumnFactory.ts +5 -0
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +12 -10
- package/src/components/DataTable/examples/HierarchicalExample.tsx +1 -1
- package/src/components/DataTable/examples/InitialPageSizeExample.tsx +1 -0
- package/src/components/DataTable/examples/PerformanceExample.tsx +1 -0
- package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +1 -5
- package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +167 -0
- package/src/components/DataTable/hooks/index.ts +7 -0
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +32 -15
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +102 -0
- package/src/components/DataTable/hooks/useDataTableConfiguration.ts +89 -0
- package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +117 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +71 -27
- package/src/components/DataTable/hooks/useDataTableState.ts +39 -11
- package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +33 -0
- package/src/components/DataTable/hooks/useHierarchicalState.ts +15 -1
- package/src/components/DataTable/hooks/useKeyboardNavigation.ts +447 -0
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +94 -0
- package/src/components/DataTable/hooks/useTableColumns.ts +10 -7
- package/src/components/DataTable/hooks/useTableHandlers.ts +174 -0
- package/src/components/DataTable/index.ts +12 -3
- package/src/components/DataTable/types.ts +129 -9
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +159 -22
- package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +111 -0
- package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +15 -29
- package/src/components/DataTable/utils/a11yUtils.ts +244 -0
- package/src/components/DataTable/utils/debugTools.ts +609 -0
- package/src/components/DataTable/utils/exportUtils.ts +114 -16
- package/src/components/DataTable/utils/flexibleImport.ts +202 -32
- package/src/components/DataTable/utils/hierarchicalUtils.ts +1 -1
- package/src/components/DataTable/utils/index.ts +2 -0
- package/src/components/DataTable/utils/paginationUtils.ts +350 -0
- package/src/components/DataTable/utils/rowUtils.ts +6 -5
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -24
- package/src/components/NavigationMenu/NavigationMenu.tsx +19 -8
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +1 -23
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +56 -6
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +137 -13
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +1 -1
- package/src/components/Select/Select.tsx +1 -0
- package/src/components/examples/PermissionExample.tsx +173 -0
- package/src/examples/CorrectPublicPageImplementation.tsx +301 -0
- package/src/examples/PublicEventPage.tsx +274 -0
- package/src/examples/PublicPageApp.tsx +308 -0
- package/src/examples/PublicPageUsageExample.tsx +216 -0
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +12 -1
- package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +129 -17
- package/src/hooks/__tests__/useRBAC.unit.test.ts +151 -846
- package/src/hooks/useOrganisationPermissions.test.ts +42 -18
- package/src/hooks/useOrganisationPermissions.ts +12 -6
- package/src/hooks/useOrganisationSecurity.test.ts +138 -85
- package/src/hooks/useOrganisationSecurity.ts +41 -10
- package/src/index.ts +0 -1
- package/src/providers/AuthProvider.simplified.tsx +880 -0
- package/src/providers/UnifiedAuthProvider.test.simple.tsx +8 -8
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +29 -19
- package/src/providers/index.ts +0 -1
- package/src/providers/services/EventServiceProvider.tsx +19 -15
- package/src/providers/services/InactivityServiceProvider.tsx +19 -15
- package/src/providers/services/OrganisationServiceProvider.tsx +19 -15
- package/src/providers/services/UnifiedAuthProvider.tsx +156 -127
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +1 -1
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -3
- package/src/rbac/README.md +1 -1
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +25 -27
- package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +313 -0
- package/src/rbac/__tests__/engine.comprehensive.test.ts +114 -348
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +28 -110
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +33 -85
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +2 -2
- package/src/rbac/adapters.tsx +26 -69
- package/src/rbac/api.test.ts +90 -27
- package/src/rbac/api.ts +61 -10
- package/src/rbac/audit.test.ts +33 -38
- package/src/rbac/audit.ts +21 -6
- package/src/rbac/cache.ts +33 -1
- package/src/rbac/components/NavigationGuard.tsx +11 -11
- package/src/rbac/components/NavigationProvider.test.tsx +11 -5
- package/src/rbac/components/NavigationProvider.tsx +37 -13
- package/src/rbac/components/PagePermissionGuard.tsx +111 -50
- package/src/rbac/components/PagePermissionProvider.tsx +5 -5
- package/src/rbac/components/PermissionEnforcer.tsx +11 -11
- package/src/rbac/components/RoleBasedRouter.tsx +5 -5
- package/src/rbac/components/SecureDataProvider.tsx +5 -5
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +8 -8
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +14 -14
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +12 -12
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +6 -6
- package/src/rbac/engine.test.simple.ts +19 -13
- package/src/rbac/engine.test.ts +1 -0
- package/src/rbac/engine.ts +330 -766
- package/src/rbac/errors.ts +156 -0
- package/src/rbac/hooks/usePermissions.ts +32 -10
- package/src/rbac/hooks/useRBAC.test.ts +126 -512
- package/src/rbac/hooks/useRBAC.ts +147 -193
- package/src/rbac/hooks/useResolvedScope.ts +12 -0
- package/src/rbac/index.ts +7 -4
- package/src/rbac/security.ts +109 -18
- package/src/rbac/types.ts +12 -1
- package/src/services/AuthService.ts +2 -15
- package/src/services/EventService.ts +43 -46
- package/src/services/OrganisationService.ts +51 -31
- package/src/services/__tests__/AuthService.test.ts +1 -1
- package/src/services/__tests__/EventService.test.ts +1 -1
- package/src/services/__tests__/OrganisationService.test.ts +1 -1
- package/src/services/base/BaseService.ts +8 -0
- package/src/styles/base.css +208 -0
- package/src/styles/semantic.css +24 -0
- package/src/types/database.generated.ts +7347 -0
- package/src/types/database.ts +20 -0
- package/src/utils/logger.ts +179 -0
- package/src/utils/organisationContext.ts +11 -4
- package/src/utils/storage/__tests__/helpers.unit.test.ts +6 -2
- package/dist/appNameResolver-UURKN7NF.js +0 -22
- package/dist/audit-6TOCAMKO.js.map +0 -1
- package/dist/chunk-B2WTCLCV.js.map +0 -1
- package/dist/chunk-FGMFQSHX.js.map +0 -1
- package/dist/chunk-K34IM5CT.js.map +0 -1
- package/dist/chunk-KHJS6VIA.js.map +0 -1
- package/dist/chunk-KK73ZB4E.js.map +0 -1
- package/dist/chunk-M5IWZRBT.js.map +0 -1
- package/dist/chunk-ULBI5JGB.js +0 -109
- package/dist/chunk-ULBI5JGB.js.map +0 -1
- package/dist/chunk-WN6XJWOS.js.map +0 -1
- package/dist/chunk-XLZ7U46Z.js.map +0 -1
- package/dist/chunk-Y6TXWPJO.js.map +0 -1
- package/docs/DOCUMENTATION_CHECKLIST.md +0 -281
- package/docs/TERMINOLOGY.md +0 -231
- package/docs/api/interfaces/RBACContextType.md +0 -468
- package/docs/api/interfaces/RBACProviderProps.md +0 -107
- package/docs/best-practices/performance-expansion.md +0 -473
- package/docs/breaking-changes.md +0 -179
- package/docs/consuming-app-example.md +0 -290
- package/docs/documentation-templates.md +0 -539
- package/docs/examples/navigation-menu-auth-fix.md +0 -344
- package/docs/getting-started/examples/basic-auth-app.md +0 -520
- package/docs/getting-started/examples/full-featured-app.md +0 -616
- package/docs/getting-started/quick-start.md +0 -376
- package/docs/implementation-guides/datatable-filtering.md +0 -313
- package/docs/implementation-guides/datatable-rbac-usage.md +0 -317
- package/docs/implementation-guides/hierarchical-datatable.md +0 -850
- package/docs/implementation-guides/large-datasets.md +0 -281
- package/docs/implementation-guides/performance.md +0 -403
- package/docs/migration/quick-migration-guide.md +0 -320
- package/docs/migration-guide.md +0 -193
- package/docs/migration-guides/unified-auth-provider-mandatory-timeouts.md +0 -226
- package/docs/performance/README.md +0 -551
- package/docs/style-guide.md +0 -964
- package/docs/troubleshooting/authentication-issues.md +0 -334
- package/docs/troubleshooting/debugging.md +0 -1117
- package/docs/troubleshooting/migration.md +0 -918
- package/src/__tests__/hooks/usePermissions.test.ts +0 -261
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +0 -574
- package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -613
- package/src/hooks/services/__tests__/useServiceHooks.test.tsx +0 -137
- package/src/hooks/services/usePermissions.ts +0 -70
- package/src/hooks/services/useRBACService.ts +0 -30
- package/src/hooks/usePermissionCheck.ts +0 -150
- package/src/providers/__tests__/ServiceProviders.test.tsx +0 -477
- package/src/providers/services/RBACServiceProvider.tsx +0 -79
- package/src/rbac/__tests__/integration.authflow.test.tsx +0 -119
- package/src/rbac/__tests__/integration.navigation.test.tsx +0 -69
- package/src/rbac/__tests__/integration.securedata.test.tsx +0 -92
- package/src/rbac/__tests__/integration.smoke.test.tsx +0 -73
- package/src/rbac/providers/RBACProvider.tsx +0 -645
- package/src/rbac/providers/__tests__/RBACProvider.integration.test.tsx +0 -688
- package/src/rbac/providers/__tests__/RBACProvider.test.tsx +0 -1186
- package/src/rbac/providers/index.ts +0 -11
- package/src/services/RBACService.ts +0 -522
- package/src/services/__tests__/RBACService.test.ts +0 -492
- package/src/services/interfaces/IRBACService.ts +0 -62
- package/src/utils/appNameResolver.test 2.ts +0 -494
- /package/dist/{DataTable-4GAVPIEG.js.map → DataTable-ETGVF4Y5.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-3NKDOSOK.js.map → UnifiedAuthProvider-P5SOJAQ6.js.map} +0 -0
- /package/dist/{api-DDMUKIUD.js.map → api-KG4A2X7P.js.map} +0 -0
- /package/dist/{appNameResolver-UURKN7NF.js.map → audit-65VNHEV2.js.map} +0 -0
- /package/dist/{chunk-NTNILOBC.js.map → chunk-5BO3MI5Y.js.map} +0 -0
- /package/dist/{chunk-URUTVZ7N.js.map → chunk-FL4ZCQLD.js.map} +0 -0
- /package/dist/{chunk-LW7MMEAQ.js.map → chunk-FT2M4R4F.js.map} +0 -0
- /package/dist/{chunk-AFGTSUAD.js.map → chunk-VSOKOFRF.js.map} +0 -0
- /package/docs/{app.css.example → styles/app.css.example} +0 -0
|
@@ -137,11 +137,12 @@ const PagePermissionGuardComponent = ({
|
|
|
137
137
|
|
|
138
138
|
|
|
139
139
|
|
|
140
|
-
const { user,
|
|
140
|
+
const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();
|
|
141
141
|
|
|
142
142
|
const [hasChecked, setHasChecked] = useState(false);
|
|
143
143
|
const [checkError, setCheckError] = useState<Error | null>(null);
|
|
144
144
|
const [resolvedScope, setResolvedScope] = useState<Scope | null>(null);
|
|
145
|
+
const scopeResolutionAbortRef = useRef<AbortController | null>(null);
|
|
145
146
|
|
|
146
147
|
// Use ref to avoid infinite re-renders from supabase dependency
|
|
147
148
|
const supabaseRef = useRef(supabase);
|
|
@@ -184,15 +185,37 @@ const PagePermissionGuardComponent = ({
|
|
|
184
185
|
|
|
185
186
|
// Resolve scope - either use provided scope or resolve from context
|
|
186
187
|
useEffect(() => {
|
|
188
|
+
const abortController = new AbortController();
|
|
189
|
+
scopeResolutionAbortRef.current?.abort();
|
|
190
|
+
scopeResolutionAbortRef.current = abortController;
|
|
191
|
+
const { signal } = abortController;
|
|
192
|
+
|
|
193
|
+
const safeSetResolvedScope = (value: Scope | null) => {
|
|
194
|
+
if (!signal.aborted) {
|
|
195
|
+
setResolvedScope(value);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const safeSetCheckError = (value: Error | null) => {
|
|
200
|
+
if (!signal.aborted) {
|
|
201
|
+
setCheckError(value);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
187
205
|
const resolveScope = async () => {
|
|
206
|
+
if (signal.aborted) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
188
210
|
if (scope) {
|
|
189
|
-
|
|
211
|
+
safeSetResolvedScope(scope);
|
|
212
|
+
safeSetCheckError(null);
|
|
190
213
|
return;
|
|
191
214
|
}
|
|
192
215
|
|
|
193
216
|
// Get app ID from package.json or environment
|
|
194
217
|
let appId: string | undefined = undefined;
|
|
195
|
-
|
|
218
|
+
|
|
196
219
|
// Try to resolve from database
|
|
197
220
|
if (supabaseRef.current) {
|
|
198
221
|
const appName = getCurrentAppName();
|
|
@@ -204,16 +227,26 @@ const PagePermissionGuardComponent = ({
|
|
|
204
227
|
.eq('name', appName)
|
|
205
228
|
.eq('is_active', true)
|
|
206
229
|
.single() as { data: { id: string; name: string; is_active: boolean } | null; error: any };
|
|
207
|
-
|
|
230
|
+
|
|
231
|
+
if (signal.aborted) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
208
235
|
if (error) {
|
|
209
236
|
console.error('[PagePermissionGuard] Database error resolving app ID:', error);
|
|
210
|
-
|
|
237
|
+
if (signal.aborted) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
211
240
|
const { data: inactiveApp } = await supabaseRef.current
|
|
212
241
|
.from('rbac_apps')
|
|
213
242
|
.select('id, name, is_active')
|
|
214
243
|
.eq('name', appName)
|
|
215
244
|
.single() as { data: { id: string; name: string; is_active: boolean } | null };
|
|
216
|
-
|
|
245
|
+
|
|
246
|
+
if (signal.aborted) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
217
250
|
if (inactiveApp) {
|
|
218
251
|
console.error(`[PagePermissionGuard] App "${appName}" exists but is inactive (is_active: ${inactiveApp.is_active})`);
|
|
219
252
|
} else {
|
|
@@ -225,6 +258,9 @@ const PagePermissionGuardComponent = ({
|
|
|
225
258
|
console.error('[PagePermissionGuard] No app data returned for:', appName);
|
|
226
259
|
}
|
|
227
260
|
} catch (error) {
|
|
261
|
+
if (signal.aborted) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
228
264
|
console.error('[PagePermissionGuard] Unexpected error resolving app ID:', error);
|
|
229
265
|
}
|
|
230
266
|
} else {
|
|
@@ -232,114 +268,139 @@ const PagePermissionGuardComponent = ({
|
|
|
232
268
|
}
|
|
233
269
|
}
|
|
234
270
|
|
|
271
|
+
if (signal.aborted) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
235
275
|
// If we have both organisation and event, use them directly
|
|
236
|
-
if (
|
|
276
|
+
if (selectedOrganisation && selectedEvent) {
|
|
237
277
|
if (!appId) {
|
|
238
|
-
// In test environments, allow undefined appId
|
|
239
278
|
if (import.meta.env.MODE === 'test') {
|
|
240
279
|
console.warn('[PagePermissionGuard] App ID not resolved in test environment, proceeding without it');
|
|
241
280
|
} else {
|
|
242
281
|
console.error('[PagePermissionGuard] CRITICAL: App ID not resolved. Check console for details.');
|
|
243
|
-
|
|
244
|
-
|
|
282
|
+
safeSetCheckError(new Error('App ID not resolved. Check console for database errors.'));
|
|
283
|
+
safeSetResolvedScope(null);
|
|
245
284
|
return;
|
|
246
285
|
}
|
|
247
286
|
}
|
|
248
|
-
|
|
249
|
-
// Validate that appId is a UUID, not an app name (only in production)
|
|
287
|
+
|
|
250
288
|
if (import.meta.env.MODE === 'production' && appId) {
|
|
251
289
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
252
290
|
if (!uuidRegex.test(appId)) {
|
|
253
291
|
console.error('[PagePermissionGuard] CRITICAL: App ID is not a valid UUID:', appId);
|
|
254
|
-
|
|
255
|
-
|
|
292
|
+
safeSetCheckError(new Error(`Invalid app ID format: ${appId}. Expected UUID.`));
|
|
293
|
+
safeSetResolvedScope(null);
|
|
256
294
|
return;
|
|
257
295
|
}
|
|
258
296
|
}
|
|
259
|
-
const
|
|
260
|
-
organisationId:
|
|
261
|
-
eventId:
|
|
297
|
+
const resolvedContext = {
|
|
298
|
+
organisationId: selectedOrganisation.id,
|
|
299
|
+
eventId: selectedEvent.event_id,
|
|
262
300
|
appId: appId
|
|
263
301
|
};
|
|
264
|
-
|
|
265
|
-
|
|
302
|
+
safeSetResolvedScope(resolvedContext);
|
|
303
|
+
safeSetCheckError(null);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (signal.aborted) {
|
|
266
308
|
return;
|
|
267
309
|
}
|
|
268
310
|
|
|
269
311
|
// If we only have organisation, use it
|
|
270
|
-
if (
|
|
312
|
+
if (selectedOrganisation) {
|
|
271
313
|
if (!appId) {
|
|
272
|
-
// In test environments, allow undefined appId
|
|
273
314
|
if (import.meta.env.MODE === 'test') {
|
|
274
315
|
console.warn('[PagePermissionGuard] App ID not resolved in test environment, proceeding without it');
|
|
275
316
|
} else {
|
|
276
317
|
console.error('[PagePermissionGuard] CRITICAL: App ID not resolved. Check console for details.');
|
|
277
|
-
|
|
278
|
-
|
|
318
|
+
safeSetCheckError(new Error('App ID not resolved. Check console for database errors.'));
|
|
319
|
+
safeSetResolvedScope(null);
|
|
279
320
|
return;
|
|
280
321
|
}
|
|
281
322
|
}
|
|
282
|
-
|
|
283
|
-
// Validate that appId is a UUID, not an app name (only in production)
|
|
323
|
+
|
|
284
324
|
if (import.meta.env.MODE === 'production' && appId) {
|
|
285
325
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
286
326
|
if (!uuidRegex.test(appId)) {
|
|
287
327
|
console.error('[PagePermissionGuard] CRITICAL: App ID is not a valid UUID:', appId);
|
|
288
|
-
|
|
289
|
-
|
|
328
|
+
safeSetCheckError(new Error(`Invalid app ID format: ${appId}. Expected UUID.`));
|
|
329
|
+
safeSetResolvedScope(null);
|
|
290
330
|
return;
|
|
291
331
|
}
|
|
292
332
|
}
|
|
293
|
-
const
|
|
294
|
-
organisationId:
|
|
295
|
-
eventId:
|
|
333
|
+
const resolvedContext = {
|
|
334
|
+
organisationId: selectedOrganisation.id,
|
|
335
|
+
eventId: selectedEvent?.event_id || undefined,
|
|
296
336
|
appId: appId
|
|
297
337
|
};
|
|
298
|
-
|
|
299
|
-
|
|
338
|
+
safeSetResolvedScope(resolvedContext);
|
|
339
|
+
safeSetCheckError(null);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (signal.aborted) {
|
|
300
344
|
return;
|
|
301
345
|
}
|
|
302
346
|
|
|
303
347
|
// If we only have event, resolve organisation from event
|
|
304
|
-
if (
|
|
348
|
+
if (selectedEvent && supabaseRef.current) {
|
|
305
349
|
try {
|
|
306
|
-
const eventScope = await createScopeFromEvent(supabaseRef.current,
|
|
350
|
+
const eventScope = await createScopeFromEvent(supabaseRef.current, selectedEvent.event_id);
|
|
351
|
+
|
|
352
|
+
if (signal.aborted) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
307
356
|
if (!eventScope) {
|
|
308
|
-
|
|
309
|
-
|
|
357
|
+
safeSetCheckError(new Error('Could not resolve organization from event context'));
|
|
358
|
+
safeSetResolvedScope(null);
|
|
310
359
|
return;
|
|
311
360
|
}
|
|
312
|
-
|
|
313
|
-
setResolvedScope({
|
|
361
|
+
safeSetResolvedScope({
|
|
314
362
|
...eventScope,
|
|
315
363
|
appId: appId || eventScope.appId
|
|
316
364
|
});
|
|
317
|
-
|
|
365
|
+
safeSetCheckError(null);
|
|
318
366
|
} catch (error) {
|
|
319
|
-
|
|
320
|
-
|
|
367
|
+
if (signal.aborted) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
safeSetCheckError(error as Error);
|
|
371
|
+
safeSetResolvedScope(null);
|
|
321
372
|
}
|
|
322
373
|
return;
|
|
323
374
|
}
|
|
324
375
|
|
|
325
|
-
|
|
326
|
-
|
|
376
|
+
if (signal.aborted) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const errorMessage = !selectedOrganisation && !selectedEvent
|
|
327
381
|
? 'Either organisation context or event context is required for page permission checking'
|
|
328
382
|
: 'Insufficient context for permission checking. Please ensure you are properly authenticated and have selected an organisation or event.';
|
|
329
|
-
|
|
383
|
+
|
|
330
384
|
console.error('[PagePermissionGuard] Context resolution failed:', {
|
|
331
|
-
|
|
332
|
-
|
|
385
|
+
selectedOrganisation: selectedOrganisation ? (selectedOrganisation as any).id : null,
|
|
386
|
+
selectedEvent: selectedEvent ? (selectedEvent as any).event_id : null,
|
|
333
387
|
appId,
|
|
334
388
|
error: errorMessage
|
|
335
389
|
});
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
390
|
+
|
|
391
|
+
safeSetCheckError(new Error(errorMessage));
|
|
392
|
+
safeSetResolvedScope(null);
|
|
339
393
|
};
|
|
340
394
|
|
|
341
395
|
resolveScope();
|
|
342
|
-
|
|
396
|
+
|
|
397
|
+
return () => {
|
|
398
|
+
abortController.abort();
|
|
399
|
+
if (scopeResolutionAbortRef.current === abortController) {
|
|
400
|
+
scopeResolutionAbortRef.current = null;
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
}, [scope, selectedOrganisation, selectedEvent]);
|
|
343
404
|
|
|
344
405
|
// Determine the page ID for permission checking
|
|
345
406
|
const effectivePageId = useMemo((): string => {
|
|
@@ -130,20 +130,20 @@ export function PagePermissionProvider({
|
|
|
130
130
|
onStrictModeViolation,
|
|
131
131
|
maxHistorySize = 1000
|
|
132
132
|
}: PagePermissionProviderProps) {
|
|
133
|
-
const { user,
|
|
133
|
+
const { user, selectedOrganisation, selectedEvent } = useUnifiedAuth();
|
|
134
134
|
const [pageAccessHistory, setPageAccessHistory] = useState<PageAccessRecord[]>([]);
|
|
135
135
|
const [isEnabled, setIsEnabled] = useState(true);
|
|
136
136
|
|
|
137
137
|
// Get current scope
|
|
138
138
|
const currentScope = useMemo((): Scope | null => {
|
|
139
|
-
if (!
|
|
139
|
+
if (!selectedOrganisation) return null;
|
|
140
140
|
|
|
141
141
|
return {
|
|
142
|
-
organisationId:
|
|
143
|
-
eventId:
|
|
142
|
+
organisationId: selectedOrganisation.id,
|
|
143
|
+
eventId: selectedEvent?.event_id || undefined,
|
|
144
144
|
appId: undefined
|
|
145
145
|
};
|
|
146
|
-
}, [
|
|
146
|
+
}, [selectedOrganisation, selectedEvent]);
|
|
147
147
|
|
|
148
148
|
// Check if user has permission for a page
|
|
149
149
|
const hasPagePermission = useCallback((
|
|
@@ -126,7 +126,7 @@ export function PermissionEnforcer({
|
|
|
126
126
|
loading = <DefaultLoading />,
|
|
127
127
|
requireAll = true
|
|
128
128
|
}: PermissionEnforcerProps) {
|
|
129
|
-
const { user,
|
|
129
|
+
const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();
|
|
130
130
|
const [hasChecked, setHasChecked] = useState(false);
|
|
131
131
|
const [checkError, setCheckError] = useState<Error | null>(null);
|
|
132
132
|
const [permissionResults, setPermissionResults] = useState<Record<string, boolean>>({});
|
|
@@ -141,29 +141,29 @@ export function PermissionEnforcer({
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
// If we have both organisation and event, use them directly
|
|
144
|
-
if (
|
|
144
|
+
if (selectedOrganisation && selectedEvent) {
|
|
145
145
|
setResolvedScope({
|
|
146
|
-
organisationId:
|
|
147
|
-
eventId:
|
|
146
|
+
organisationId: selectedOrganisation.id,
|
|
147
|
+
eventId: selectedEvent.event_id,
|
|
148
148
|
appId: undefined
|
|
149
149
|
});
|
|
150
150
|
return;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
// If we only have organisation, use it
|
|
154
|
-
if (
|
|
154
|
+
if (selectedOrganisation) {
|
|
155
155
|
setResolvedScope({
|
|
156
|
-
organisationId:
|
|
157
|
-
eventId:
|
|
156
|
+
organisationId: selectedOrganisation.id,
|
|
157
|
+
eventId: selectedEvent?.event_id || undefined,
|
|
158
158
|
appId: undefined
|
|
159
159
|
});
|
|
160
160
|
return;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
// If we only have event, resolve organisation from event
|
|
164
|
-
if (
|
|
164
|
+
if (selectedEvent && supabase) {
|
|
165
165
|
try {
|
|
166
|
-
const eventScope = await createScopeFromEvent(supabase,
|
|
166
|
+
const eventScope = await createScopeFromEvent(supabase, selectedEvent.event_id);
|
|
167
167
|
if (!eventScope) {
|
|
168
168
|
setCheckError(new Error('Could not resolve organization from event context'));
|
|
169
169
|
return;
|
|
@@ -180,14 +180,14 @@ export function PermissionEnforcer({
|
|
|
180
180
|
};
|
|
181
181
|
|
|
182
182
|
resolveScope();
|
|
183
|
-
}, [scope,
|
|
183
|
+
}, [scope, selectedOrganisation, selectedEvent, supabase]);
|
|
184
184
|
|
|
185
185
|
// Check permissions using the first permission as a representative
|
|
186
186
|
// For multiple permissions, we'll check them sequentially
|
|
187
187
|
const representativePermission = permissions[0];
|
|
188
188
|
const { can, isLoading, error } = useCan(
|
|
189
189
|
user?.id || '',
|
|
190
|
-
resolvedScope || { eventId:
|
|
190
|
+
resolvedScope || { eventId: selectedEvent?.event_id || undefined },
|
|
191
191
|
representativePermission,
|
|
192
192
|
undefined,
|
|
193
193
|
true // Use cache
|
|
@@ -186,7 +186,7 @@ export function RoleBasedRouter({
|
|
|
186
186
|
maxHistorySize = 1000,
|
|
187
187
|
unauthorizedComponent: UnauthorizedComponent = DefaultUnauthorizedComponent
|
|
188
188
|
}: RoleBasedRouterProps) {
|
|
189
|
-
const { user,
|
|
189
|
+
const { user, selectedOrganisation, selectedEvent } = useUnifiedAuth();
|
|
190
190
|
const location = useLocation();
|
|
191
191
|
const navigate = useNavigate();
|
|
192
192
|
const [routeAccessHistory, setRouteAccessHistory] = useState<RouteAccessRecord[]>([]);
|
|
@@ -194,14 +194,14 @@ export function RoleBasedRouter({
|
|
|
194
194
|
|
|
195
195
|
// Get current scope
|
|
196
196
|
const currentScope = useMemo((): Scope | null => {
|
|
197
|
-
if (!
|
|
197
|
+
if (!selectedOrganisation) return null;
|
|
198
198
|
|
|
199
199
|
return {
|
|
200
|
-
organisationId:
|
|
201
|
-
eventId:
|
|
200
|
+
organisationId: selectedOrganisation.id,
|
|
201
|
+
eventId: selectedEvent?.event_id || undefined,
|
|
202
202
|
appId: undefined
|
|
203
203
|
};
|
|
204
|
-
}, [
|
|
204
|
+
}, [selectedOrganisation, selectedEvent]);
|
|
205
205
|
|
|
206
206
|
// Get route configuration for current path
|
|
207
207
|
const currentRouteConfig = useMemo((): RouteConfig | null => {
|
|
@@ -141,21 +141,21 @@ export function SecureDataProvider({
|
|
|
141
141
|
maxHistorySize = 1000,
|
|
142
142
|
enforceRLS = true
|
|
143
143
|
}: SecureDataProviderProps) {
|
|
144
|
-
const { user,
|
|
144
|
+
const { user, selectedOrganisation, selectedEvent } = useUnifiedAuth();
|
|
145
145
|
const { validateContext } = useSecureDataAccess();
|
|
146
146
|
const [dataAccessHistory, setDataAccessHistory] = useState<DataAccessRecord[]>([]);
|
|
147
147
|
const [isEnabled, setIsEnabled] = useState(true);
|
|
148
148
|
|
|
149
149
|
// Get current scope
|
|
150
150
|
const currentScope = useMemo((): Scope | null => {
|
|
151
|
-
if (!
|
|
151
|
+
if (!selectedOrganisation) return null;
|
|
152
152
|
|
|
153
153
|
return {
|
|
154
|
-
organisationId:
|
|
155
|
-
eventId:
|
|
154
|
+
organisationId: selectedOrganisation.id,
|
|
155
|
+
eventId: selectedEvent?.event_id || undefined,
|
|
156
156
|
appId: undefined
|
|
157
157
|
};
|
|
158
|
-
}, [
|
|
158
|
+
}, [selectedOrganisation, selectedEvent]);
|
|
159
159
|
|
|
160
160
|
// Check if data access is allowed for a table and operation
|
|
161
161
|
const isDataAccessAllowed = useCallback((
|
|
@@ -78,8 +78,8 @@ describe('NavigationGuard Component', () => {
|
|
|
78
78
|
// Default mock implementations
|
|
79
79
|
mockUseUnifiedAuth.mockReturnValue({
|
|
80
80
|
user: mockUser,
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
selectedOrganisation: { id: 'org-123' },
|
|
82
|
+
selectedEvent: { event_id: 'event-123' },
|
|
83
83
|
supabase: {} as any
|
|
84
84
|
});
|
|
85
85
|
|
|
@@ -366,8 +366,8 @@ describe('NavigationGuard Component', () => {
|
|
|
366
366
|
it('resolves scope from organisation only', async () => {
|
|
367
367
|
mockUseUnifiedAuth.mockReturnValue({
|
|
368
368
|
user: mockUser,
|
|
369
|
-
|
|
370
|
-
|
|
369
|
+
selectedOrganisation: { id: 'org-123' },
|
|
370
|
+
selectedEvent: null,
|
|
371
371
|
supabase: {} as any
|
|
372
372
|
});
|
|
373
373
|
|
|
@@ -402,8 +402,8 @@ describe('NavigationGuard Component', () => {
|
|
|
402
402
|
it('resolves scope from event context when organisation not available', async () => {
|
|
403
403
|
mockUseUnifiedAuth.mockReturnValue({
|
|
404
404
|
user: mockUser,
|
|
405
|
-
|
|
406
|
-
|
|
405
|
+
selectedOrganisation: null,
|
|
406
|
+
selectedEvent: { event_id: 'event-123' },
|
|
407
407
|
supabase: {} as any
|
|
408
408
|
});
|
|
409
409
|
|
|
@@ -713,8 +713,8 @@ describe('NavigationGuard Component', () => {
|
|
|
713
713
|
it('handles missing user gracefully', async () => {
|
|
714
714
|
mockUseUnifiedAuth.mockReturnValue({
|
|
715
715
|
user: null,
|
|
716
|
-
|
|
717
|
-
|
|
716
|
+
selectedOrganisation: { id: 'org-123' },
|
|
717
|
+
selectedEvent: { event_id: 'event-123' },
|
|
718
718
|
supabase: {} as any
|
|
719
719
|
});
|
|
720
720
|
|
|
@@ -77,8 +77,8 @@ describe('PagePermissionGuard Component', () => {
|
|
|
77
77
|
// Default mock implementations
|
|
78
78
|
mockUseUnifiedAuth.mockReturnValue({
|
|
79
79
|
user: mockUser,
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
selectedOrganisation: { id: 'org-123' },
|
|
81
|
+
selectedEvent: { event_id: 'event-123' },
|
|
82
82
|
supabase: {
|
|
83
83
|
from: vi.fn().mockReturnValue({
|
|
84
84
|
select: vi.fn().mockReturnValue({
|
|
@@ -433,8 +433,8 @@ describe('PagePermissionGuard Component', () => {
|
|
|
433
433
|
// Mock database returning invalid app ID
|
|
434
434
|
mockUseUnifiedAuth.mockReturnValue({
|
|
435
435
|
user: mockUser,
|
|
436
|
-
|
|
437
|
-
|
|
436
|
+
selectedOrganisation: { id: 'org-123' },
|
|
437
|
+
selectedEvent: { event_id: 'event-123' },
|
|
438
438
|
supabase: {
|
|
439
439
|
from: vi.fn().mockReturnValue({
|
|
440
440
|
select: vi.fn().mockReturnValue({
|
|
@@ -547,8 +547,8 @@ describe('PagePermissionGuard Component', () => {
|
|
|
547
547
|
it('resolves scope from organisation only', async () => {
|
|
548
548
|
mockUseUnifiedAuth.mockReturnValue({
|
|
549
549
|
user: mockUser,
|
|
550
|
-
|
|
551
|
-
|
|
550
|
+
selectedOrganisation: { id: 'org-123' },
|
|
551
|
+
selectedEvent: null,
|
|
552
552
|
supabase: {
|
|
553
553
|
from: vi.fn().mockReturnValue({
|
|
554
554
|
select: vi.fn().mockReturnValue({
|
|
@@ -600,8 +600,8 @@ describe('PagePermissionGuard Component', () => {
|
|
|
600
600
|
it('resolves scope from event context when organisation not available', async () => {
|
|
601
601
|
mockUseUnifiedAuth.mockReturnValue({
|
|
602
602
|
user: mockUser,
|
|
603
|
-
|
|
604
|
-
|
|
603
|
+
selectedOrganisation: null,
|
|
604
|
+
selectedEvent: { event_id: 'event-123' },
|
|
605
605
|
supabase: {
|
|
606
606
|
from: vi.fn().mockReturnValue({
|
|
607
607
|
select: vi.fn().mockReturnValue({
|
|
@@ -663,8 +663,8 @@ describe('PagePermissionGuard Component', () => {
|
|
|
663
663
|
it('handles scope resolution errors', async () => {
|
|
664
664
|
mockUseUnifiedAuth.mockReturnValue({
|
|
665
665
|
user: mockUser,
|
|
666
|
-
|
|
667
|
-
|
|
666
|
+
selectedOrganisation: null,
|
|
667
|
+
selectedEvent: { event_id: 'event-123' },
|
|
668
668
|
supabase: {} as any
|
|
669
669
|
});
|
|
670
670
|
|
|
@@ -689,8 +689,8 @@ describe('PagePermissionGuard Component', () => {
|
|
|
689
689
|
it('handles missing context gracefully', async () => {
|
|
690
690
|
mockUseUnifiedAuth.mockReturnValue({
|
|
691
691
|
user: mockUser,
|
|
692
|
-
|
|
693
|
-
|
|
692
|
+
selectedOrganisation: null,
|
|
693
|
+
selectedEvent: null,
|
|
694
694
|
supabase: null
|
|
695
695
|
});
|
|
696
696
|
|
|
@@ -960,8 +960,8 @@ describe('PagePermissionGuard Component', () => {
|
|
|
960
960
|
it('handles database errors during app resolution', async () => {
|
|
961
961
|
mockUseUnifiedAuth.mockReturnValue({
|
|
962
962
|
user: mockUser,
|
|
963
|
-
|
|
964
|
-
|
|
963
|
+
selectedOrganisation: { id: 'org-123' },
|
|
964
|
+
selectedEvent: { event_id: 'event-123' },
|
|
965
965
|
supabase: {
|
|
966
966
|
from: vi.fn().mockReturnValue({
|
|
967
967
|
select: vi.fn().mockReturnValue({
|
|
@@ -70,8 +70,8 @@ describe('PermissionEnforcer Component', () => {
|
|
|
70
70
|
// Default mock implementations
|
|
71
71
|
mockUseUnifiedAuth.mockReturnValue({
|
|
72
72
|
user: mockUser,
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
selectedOrganisation: { id: 'org-123' },
|
|
74
|
+
selectedEvent: { event_id: 'event-123' },
|
|
75
75
|
supabase: {} as any
|
|
76
76
|
});
|
|
77
77
|
|
|
@@ -377,8 +377,8 @@ describe('PermissionEnforcer Component', () => {
|
|
|
377
377
|
it('resolves scope from organisation only', async () => {
|
|
378
378
|
mockUseUnifiedAuth.mockReturnValue({
|
|
379
379
|
user: mockUser,
|
|
380
|
-
|
|
381
|
-
|
|
380
|
+
selectedOrganisation: { id: 'org-123' },
|
|
381
|
+
selectedEvent: null,
|
|
382
382
|
supabase: {} as any
|
|
383
383
|
});
|
|
384
384
|
|
|
@@ -416,8 +416,8 @@ describe('PermissionEnforcer Component', () => {
|
|
|
416
416
|
it('resolves scope from event context when organisation not available', async () => {
|
|
417
417
|
mockUseUnifiedAuth.mockReturnValue({
|
|
418
418
|
user: mockUser,
|
|
419
|
-
|
|
420
|
-
|
|
419
|
+
selectedOrganisation: null,
|
|
420
|
+
selectedEvent: { event_id: 'event-123' },
|
|
421
421
|
supabase: {} as any
|
|
422
422
|
});
|
|
423
423
|
|
|
@@ -462,8 +462,8 @@ describe('PermissionEnforcer Component', () => {
|
|
|
462
462
|
it('handles scope resolution errors', async () => {
|
|
463
463
|
mockUseUnifiedAuth.mockReturnValue({
|
|
464
464
|
user: mockUser,
|
|
465
|
-
|
|
466
|
-
|
|
465
|
+
selectedOrganisation: null,
|
|
466
|
+
selectedEvent: { event_id: 'event-123' },
|
|
467
467
|
supabase: {} as any
|
|
468
468
|
});
|
|
469
469
|
|
|
@@ -488,8 +488,8 @@ describe('PermissionEnforcer Component', () => {
|
|
|
488
488
|
it('handles missing context gracefully', async () => {
|
|
489
489
|
mockUseUnifiedAuth.mockReturnValue({
|
|
490
490
|
user: mockUser,
|
|
491
|
-
|
|
492
|
-
|
|
491
|
+
selectedOrganisation: null,
|
|
492
|
+
selectedEvent: null,
|
|
493
493
|
supabase: null
|
|
494
494
|
});
|
|
495
495
|
|
|
@@ -739,8 +739,8 @@ describe('PermissionEnforcer Component', () => {
|
|
|
739
739
|
it('handles missing user gracefully', async () => {
|
|
740
740
|
mockUseUnifiedAuth.mockReturnValue({
|
|
741
741
|
user: null,
|
|
742
|
-
|
|
743
|
-
|
|
742
|
+
selectedOrganisation: { id: 'org-123' },
|
|
743
|
+
selectedEvent: { event_id: 'event-123' },
|
|
744
744
|
supabase: {} as any
|
|
745
745
|
});
|
|
746
746
|
|
|
@@ -99,8 +99,8 @@ describe('RoleBasedRouter Component', () => {
|
|
|
99
99
|
// Default mock implementations
|
|
100
100
|
mockUseUnifiedAuth.mockReturnValue({
|
|
101
101
|
user: mockUser,
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
selectedOrganisation: { id: 'org-123' },
|
|
103
|
+
selectedEvent: { event_id: 'event-123' }
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
mockUseLocation.mockReturnValue({
|
|
@@ -611,8 +611,8 @@ describe('RoleBasedRouter Component', () => {
|
|
|
611
611
|
it('handles missing user gracefully', async () => {
|
|
612
612
|
mockUseUnifiedAuth.mockReturnValue({
|
|
613
613
|
user: null,
|
|
614
|
-
|
|
615
|
-
|
|
614
|
+
selectedOrganisation: { id: 'org-123' },
|
|
615
|
+
selectedEvent: { event_id: 'event-123' }
|
|
616
616
|
});
|
|
617
617
|
|
|
618
618
|
mockUseCan.mockReturnValue({
|
|
@@ -648,8 +648,8 @@ describe('RoleBasedRouter Component', () => {
|
|
|
648
648
|
it('handles missing organisation context', async () => {
|
|
649
649
|
mockUseUnifiedAuth.mockReturnValue({
|
|
650
650
|
user: mockUser,
|
|
651
|
-
|
|
652
|
-
|
|
651
|
+
selectedOrganisation: null,
|
|
652
|
+
selectedEvent: null
|
|
653
653
|
});
|
|
654
654
|
|
|
655
655
|
mockUseCan.mockReturnValue({
|