@jmruthers/pace-core 0.6.5 → 0.6.7
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 +104 -0
- package/README.md +5 -403
- package/audit-tool/00-dependencies.cjs +394 -0
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/core-usage-manifest.json +93 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/01-pace-core-compliance.mdc +586 -0
- package/cursor-rules/02-project-structure.mdc +42 -4
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
- package/cursor-rules/06-security-rbac.mdc +518 -0
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
- package/dist/chunk-6F3IILHI.js +62 -0
- package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
- package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
- package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
- package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
- package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/chunk-GHYHJTYV.js +994 -0
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
- package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
- package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
- package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
- package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
- package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
- package/dist/components.d.ts +7 -5
- package/dist/components.js +46 -257
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +35 -0
- package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
- package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/eslint-rules/utils/helpers.cjs +42 -0
- package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +62 -172
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +67 -660
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +8 -35
- package/dist/rbac/eslint-rules.d.ts +46 -44
- package/dist/rbac/eslint-rules.js +7 -4
- package/dist/rbac/index.d.ts +109 -586
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +3 -19
- package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
- package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +17 -7
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +301 -871
- package/docs/api-reference/components.md +21 -21
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +5 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +17 -8
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -35
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/1-pace-core-compliance-standards.md +986 -0
- package/docs/standards/2-project-structure-standards.md +949 -0
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/5-styling-standards.md +348 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +185 -57
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +33 -6
- package/package.json +35 -23
- package/scripts/install-cursor-rules.cjs +25 -6
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +106 -119
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +12 -9
- package/src/components/DataTable/components/EmptyState.tsx +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
- package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
- package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
- package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
- package/src/components/DataTable/types.ts +5 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +10 -9
- package/src/components/Dialog/Dialog.test.tsx +128 -104
- package/src/components/Dialog/Dialog.tsx +742 -24
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
- package/src/components/FileDisplay/FileDisplay.tsx +23 -17
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Form/Form.test.tsx +6 -8
- package/src/components/Form/Form.tsx +365 -4
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +109 -98
- package/src/components/Select/types.ts +4 -1
- package/src/components/UserMenu/UserMenu.tsx +9 -6
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
- package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
- package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
- package/src/hooks/public/usePublicEvent.ts +67 -195
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +24 -14
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +28 -26
- package/src/hooks/useEventTheme.test.ts +217 -239
- package/src/hooks/useEventTheme.ts +16 -28
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useOrganisationPermissions.ts +5 -7
- package/src/hooks/useQueryCache.ts +0 -1
- package/src/hooks/useSessionDraft.ts +380 -0
- package/src/hooks/useSessionRestoration.ts +3 -1
- package/src/icons/index.ts +27 -0
- package/src/index.ts +5 -0
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
- package/src/rbac/adapters.tsx +7 -295
- package/src/rbac/api.test.ts +44 -56
- package/src/rbac/api.ts +10 -17
- package/src/rbac/cache-invalidation.ts +0 -1
- package/src/rbac/compliance/index.ts +10 -0
- package/src/rbac/compliance/pattern-detector.ts +553 -0
- package/src/rbac/compliance/runtime-compliance.ts +22 -0
- package/src/rbac/components/AccessDenied.tsx +150 -0
- package/src/rbac/components/NavigationGuard.tsx +12 -20
- package/src/rbac/components/PagePermissionGuard.tsx +4 -24
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
- package/src/rbac/components/index.ts +3 -41
- package/src/rbac/eslint-rules.js +1 -1
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/permissions/index.ts +0 -3
- package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
- package/src/rbac/hooks/usePermissions.ts +0 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
- package/src/rbac/hooks/useResourcePermissions.ts +139 -48
- package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
- package/src/rbac/hooks/useRoleManagement.ts +147 -19
- package/src/rbac/hooks/useSecureSupabase.ts +4 -8
- package/src/rbac/index.ts +7 -9
- package/src/rbac/utils/contextValidator.ts +9 -7
- package/src/services/AuthService.ts +130 -18
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +16 -0
- package/src/services/OrganisationService.ts +7 -44
- package/src/services/__tests__/OrganisationService.test.ts +26 -8
- package/src/services/base/BaseService.ts +0 -3
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
- package/src/utils/context/organisationContext.test.ts +13 -28
- package/src/utils/context/organisationContext.ts +21 -52
- package/src/utils/dynamic/dynamicUtils.ts +1 -1
- package/src/utils/file-reference/index.ts +39 -15
- package/src/utils/formatting/formatDateTime.test.ts +3 -2
- package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
- package/src/utils/index.ts +4 -1
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
- package/src/utils/persistence/keyDerivation.ts +304 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
- package/src/utils/security/secureStorage.ts +5 -5
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.ts +3 -3
- package/src/utils/supabase/createBaseClient.ts +147 -0
- package/src/utils/timezone/timezone.test.ts +1 -2
- package/src/utils/timezone/timezone.ts +1 -1
- package/src/utils/validation/csrf.ts +4 -4
- package/cursor-rules/00-pace-core-compliance.mdc +0 -331
- package/cursor-rules/01-standards-compliance.mdc +0 -244
- package/cursor-rules/04-testing-standards.mdc +0 -268
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
- package/cursor-rules/06-code-quality.mdc +0 -309
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-AOVNCPTX.js +0 -175
- package/dist/DataTable-AOVNCPTX.js.map +0 -1
- package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
- package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
- package/dist/api-O6HTBX5Y.js +0 -52
- package/dist/api-O6HTBX5Y.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6COVEUS7.js.map +0 -1
- package/dist/chunk-AFVQODI2.js +0 -263
- package/dist/chunk-AFVQODI2.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-EFN2EIMK.js.map +0 -1
- package/dist/chunk-FFQEQTNW.js.map +0 -1
- package/dist/chunk-FMUCXFII.js.map +0 -1
- package/dist/chunk-G37KK66H.js.map +0 -1
- package/dist/chunk-G7QEZTYQ.js +0 -2053
- package/dist/chunk-G7QEZTYQ.js.map +0 -1
- package/dist/chunk-HU2C6SSC.js.map +0 -1
- package/dist/chunk-IHB5DR3H.js.map +0 -1
- package/dist/chunk-IVOFDYWT.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-JGRYX5UX.js.map +0 -1
- package/dist/chunk-KQCRWDSA.js +0 -1
- package/dist/chunk-KQCRWDSA.js.map +0 -1
- package/dist/chunk-L4OXEN46.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-M43Y4SSO.js.map +0 -1
- package/dist/chunk-M7MPQISP.js.map +0 -1
- package/dist/chunk-NTM7ZSB6.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-RGAWHO7N.js.map +0 -1
- package/dist/chunk-UPPMRMYG.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-5OGXSPKS.js +0 -9
- package/dist/contextValidator-5OGXSPKS.js.map +0 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
- package/dist/hooks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers.js.map +0 -1
- package/dist/rbac/eslint-rules.js.map +0 -1
- package/dist/rbac/index.js.map +0 -1
- package/dist/styles/index.js.map +0 -1
- package/dist/theming/runtime.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -601
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-architecture-standard.md +0 -44
- package/docs/standards/02-api-and-rpc-standard.md +0 -39
- package/docs/standards/03-component-standard.md +0 -32
- package/docs/standards/04-code-style-standard.md +0 -32
- package/docs/standards/05-security-standard.md +0 -44
- package/docs/standards/06-testing-and-docs-standard.md +0 -29
- package/docs/standards/pace-core-compliance.md +0 -432
- package/scripts/audit/core/checks/accessibility.cjs +0 -197
- package/scripts/audit/core/checks/api-usage.cjs +0 -191
- package/scripts/audit/core/checks/bundle.cjs +0 -142
- package/scripts/audit/core/checks/compliance.cjs +0 -2706
- package/scripts/audit/core/checks/config.cjs +0 -54
- package/scripts/audit/core/checks/coverage.cjs +0 -84
- package/scripts/audit/core/checks/dependencies.cjs +0 -994
- package/scripts/audit/core/checks/documentation.cjs +0 -268
- package/scripts/audit/core/checks/environment.cjs +0 -116
- package/scripts/audit/core/checks/error-handling.cjs +0 -340
- package/scripts/audit/core/checks/forms.cjs +0 -172
- package/scripts/audit/core/checks/heuristics.cjs +0 -68
- package/scripts/audit/core/checks/hooks.cjs +0 -334
- package/scripts/audit/core/checks/imports.cjs +0 -244
- package/scripts/audit/core/checks/performance.cjs +0 -325
- package/scripts/audit/core/checks/routes.cjs +0 -117
- package/scripts/audit/core/checks/state.cjs +0 -130
- package/scripts/audit/core/checks/structure.cjs +0 -65
- package/scripts/audit/core/checks/style.cjs +0 -584
- package/scripts/audit/core/checks/testing.cjs +0 -122
- package/scripts/audit/core/checks/typescript.cjs +0 -61
- package/scripts/audit/core/scanner.cjs +0 -199
- package/scripts/audit/core/utils.cjs +0 -137
- package/scripts/audit/index.cjs +0 -223
- package/scripts/audit/reporters/console.cjs +0 -151
- package/scripts/audit/reporters/json.cjs +0 -54
- package/scripts/audit/reporters/markdown.cjs +0 -124
- package/scripts/audit-consuming-app.cjs +0 -86
- package/src/components/DataTable/components/DataTableBody.tsx +0 -454
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/pace-core-compliance.js +0 -638
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
- package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
- package/src/rbac/components/NavigationProvider.test.tsx +0 -481
- package/src/rbac/components/NavigationProvider.tsx +0 -345
- package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
- package/src/rbac/components/PagePermissionProvider.tsx +0 -279
- package/src/rbac/components/PermissionEnforcer.tsx +0 -312
- package/src/rbac/components/RoleBasedRouter.tsx +0 -440
- package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
- package/src/rbac/components/SecureDataProvider.tsx +0 -339
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
|
@@ -40,12 +40,15 @@
|
|
|
40
40
|
* - Missing user context results in all permissions being denied
|
|
41
41
|
*/
|
|
42
42
|
|
|
43
|
-
import { useMemo } from 'react';
|
|
43
|
+
import { useMemo, useState, useEffect, useRef } from 'react';
|
|
44
44
|
import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
|
|
45
45
|
import { useOrganisations } from '../../hooks/useOrganisations';
|
|
46
46
|
import { useEvents } from '../../hooks/useEvents';
|
|
47
|
+
import type { Event } from '../../types/event';
|
|
47
48
|
import { useResolvedScope } from './useResolvedScope';
|
|
48
49
|
import { useCan } from './usePermissions';
|
|
50
|
+
import { isSuperAdmin } from '../api';
|
|
51
|
+
import { createLogger } from '../../utils/core/logger';
|
|
49
52
|
import type { Scope, Permission } from '../types';
|
|
50
53
|
|
|
51
54
|
export interface UseResourcePermissionsOptions {
|
|
@@ -140,15 +143,80 @@ export function useResourcePermissions(
|
|
|
140
143
|
options: UseResourcePermissionsOptions = {}
|
|
141
144
|
): ResourcePermissions {
|
|
142
145
|
const { enableRead = false, requireScope = true } = options;
|
|
146
|
+
const logger = createLogger('ResourcePermissions');
|
|
143
147
|
|
|
144
148
|
// Get user and supabase client from UnifiedAuth
|
|
145
149
|
const { user, supabase } = useUnifiedAuth();
|
|
150
|
+
|
|
151
|
+
// Super admin status - check if user has super admin privileges
|
|
152
|
+
// Super admins bypass all permission checks (similar to useDataTablePermissions)
|
|
153
|
+
// PERFORMANCE OPTIMIZATION: Check super admin once and share with all useCan hooks to avoid duplicate queries
|
|
154
|
+
// Use null to indicate "not checked yet" vs false which means "checked and not super admin"
|
|
155
|
+
const [isSuperAdminUser, setIsSuperAdminUser] = useState<boolean | null>(null);
|
|
156
|
+
const [isCheckingSuperAdmin, setIsCheckingSuperAdmin] = useState<boolean>(() => !!user?.id);
|
|
157
|
+
const lastCheckedUserIdRef = useRef<string | null>(null);
|
|
158
|
+
const isCheckingRef = useRef<boolean>(false);
|
|
159
|
+
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
// Skip if already checked for this user ID
|
|
162
|
+
if (lastCheckedUserIdRef.current === user?.id && isSuperAdminUser !== null) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Skip if already checking
|
|
167
|
+
if (isCheckingRef.current) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const checkSuperAdminStatus = async () => {
|
|
172
|
+
if (!user?.id) {
|
|
173
|
+
setIsSuperAdminUser(false); // No user = not super admin
|
|
174
|
+
setIsCheckingSuperAdmin(false);
|
|
175
|
+
lastCheckedUserIdRef.current = null;
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Mark as checking and track user ID
|
|
180
|
+
isCheckingRef.current = true;
|
|
181
|
+
lastCheckedUserIdRef.current = user.id;
|
|
182
|
+
|
|
183
|
+
const startTime = Date.now();
|
|
184
|
+
setIsCheckingSuperAdmin(true);
|
|
185
|
+
|
|
186
|
+
// Add timeout to prevent infinite hanging
|
|
187
|
+
const timeoutId = setTimeout(() => {
|
|
188
|
+
logger.warn('useResourcePermissions', 'Super admin check taking longer than 5 seconds', {
|
|
189
|
+
userId: user?.id,
|
|
190
|
+
elapsedMs: Date.now() - startTime,
|
|
191
|
+
});
|
|
192
|
+
}, 5000);
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
const superAdminStatus = await isSuperAdmin(user.id);
|
|
196
|
+
setIsSuperAdminUser(superAdminStatus);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
const elapsed = Date.now() - startTime;
|
|
199
|
+
logger.error('useResourcePermissions', 'Error checking super admin status', {
|
|
200
|
+
userId: user?.id,
|
|
201
|
+
error,
|
|
202
|
+
elapsedMs: elapsed,
|
|
203
|
+
});
|
|
204
|
+
setIsSuperAdminUser(false); // Error = assume not super admin for security
|
|
205
|
+
} finally {
|
|
206
|
+
clearTimeout(timeoutId);
|
|
207
|
+
setIsCheckingSuperAdmin(false);
|
|
208
|
+
isCheckingRef.current = false;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
checkSuperAdminStatus();
|
|
213
|
+
}, [user?.id, logger]);
|
|
146
214
|
|
|
147
215
|
// Get selected organisation
|
|
148
216
|
const { selectedOrganisation } = useOrganisations();
|
|
149
217
|
|
|
150
218
|
// Get selected event (optional - wrap in try/catch)
|
|
151
|
-
let selectedEvent:
|
|
219
|
+
let selectedEvent: Event | null = null;
|
|
152
220
|
try {
|
|
153
221
|
const eventsContext = useEvents();
|
|
154
222
|
selectedEvent = eventsContext.selectedEvent;
|
|
@@ -161,7 +229,8 @@ export function useResourcePermissions(
|
|
|
161
229
|
const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
|
|
162
230
|
supabase,
|
|
163
231
|
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
164
|
-
selectedEventId: selectedEvent?.event_id || null
|
|
232
|
+
selectedEventId: selectedEvent?.event_id || null,
|
|
233
|
+
selectedEventOrganisationId: selectedEvent?.organisation_id || null
|
|
165
234
|
});
|
|
166
235
|
|
|
167
236
|
// CRITICAL FIX: Only use resolvedScope when it's available (not during loading)
|
|
@@ -192,8 +261,9 @@ export function useResourcePermissions(
|
|
|
192
261
|
const readPermission = isPagePermission ? `read:page.${resource}` : `read:${resource}`;
|
|
193
262
|
|
|
194
263
|
// Permission checks for create, update, delete
|
|
195
|
-
// Pass
|
|
196
|
-
//
|
|
264
|
+
// PERFORMANCE OPTIMIZATION: Pass precomputed super admin status to avoid duplicate checks
|
|
265
|
+
// Each useCan hook would normally check super admin separately (4+ queries), but we check once here
|
|
266
|
+
// and share the result. Pass null if not checked yet (hooks will check), false/true if checked.
|
|
197
267
|
// CRITICAL: useCan will wait for appId when pageId is provided (it checks needsAppIdForPageName)
|
|
198
268
|
// But we must ensure permission strings are correct before calling useCan
|
|
199
269
|
const { can: canCreateResult, isLoading: createLoading, error: createError } = useCan(
|
|
@@ -202,7 +272,7 @@ export function useResourcePermissions(
|
|
|
202
272
|
createPermission as Permission,
|
|
203
273
|
pageId, // Pass resource name as pageId when appId is available to enable page permission checks
|
|
204
274
|
true, // useCache
|
|
205
|
-
|
|
275
|
+
isSuperAdminUser, // precomputedSuperAdmin - null if checking, false/true if checked
|
|
206
276
|
undefined // appName
|
|
207
277
|
);
|
|
208
278
|
|
|
@@ -212,7 +282,7 @@ export function useResourcePermissions(
|
|
|
212
282
|
updatePermission as Permission,
|
|
213
283
|
pageId, // Pass resource name as pageId when appId is available to enable page permission checks
|
|
214
284
|
true, // useCache
|
|
215
|
-
|
|
285
|
+
isSuperAdminUser, // precomputedSuperAdmin - null if checking, false/true if checked
|
|
216
286
|
undefined // appName
|
|
217
287
|
);
|
|
218
288
|
|
|
@@ -222,7 +292,7 @@ export function useResourcePermissions(
|
|
|
222
292
|
deletePermission as Permission,
|
|
223
293
|
pageId, // Pass resource name as pageId when appId is available to enable page permission checks
|
|
224
294
|
true, // useCache
|
|
225
|
-
|
|
295
|
+
isSuperAdminUser, // precomputedSuperAdmin - null if checking, false/true if checked
|
|
226
296
|
undefined // appName
|
|
227
297
|
);
|
|
228
298
|
|
|
@@ -233,7 +303,7 @@ export function useResourcePermissions(
|
|
|
233
303
|
readPermission as Permission,
|
|
234
304
|
pageId, // Pass resource name as pageId when appId is available to enable page permission checks
|
|
235
305
|
true, // useCache
|
|
236
|
-
|
|
306
|
+
isSuperAdminUser, // precomputedSuperAdmin - null if checking, false/true if checked
|
|
237
307
|
undefined // appName
|
|
238
308
|
);
|
|
239
309
|
|
|
@@ -241,11 +311,14 @@ export function useResourcePermissions(
|
|
|
241
311
|
// CRITICAL: When requireScope is true, we must wait for scope resolution to complete
|
|
242
312
|
// so we can determine the correct permission format (page vs resource permissions)
|
|
243
313
|
// This prevents using wrong permission format (delete:planning instead of delete:page.planning)
|
|
314
|
+
// Also wait for super admin check to complete to ensure accurate permission results
|
|
244
315
|
const isLoading = useMemo(() => {
|
|
245
316
|
// If scope resolution is required, wait for it to complete
|
|
246
317
|
const waitingForScope = requireScope && scopeLoading;
|
|
247
|
-
|
|
248
|
-
|
|
318
|
+
// Wait for super admin check to complete (null means still checking)
|
|
319
|
+
const waitingForSuperAdmin = isSuperAdminUser === null && isCheckingSuperAdmin;
|
|
320
|
+
return waitingForScope || waitingForSuperAdmin || createLoading || updateLoading || deleteLoading || (enableRead && readLoading);
|
|
321
|
+
}, [scopeLoading, requireScope, isSuperAdminUser, isCheckingSuperAdmin, createLoading, updateLoading, deleteLoading, readLoading, enableRead]);
|
|
249
322
|
|
|
250
323
|
// Aggregate errors - prefer scope error, then any permission error
|
|
251
324
|
const error = useMemo(() => {
|
|
@@ -260,45 +333,63 @@ export function useResourcePermissions(
|
|
|
260
333
|
// Return wrapper functions that take resource name and return permission result
|
|
261
334
|
// Note: The resource parameter in the function is for consistency with the API,
|
|
262
335
|
// but we're checking permissions for the resource passed to the hook
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
canUpdate: (res: string) => {
|
|
273
|
-
if (res !== resource) {
|
|
274
|
-
return false;
|
|
275
|
-
}
|
|
276
|
-
return canUpdateResult; // canUpdateResult is already the boolean 'can' value from useCan
|
|
277
|
-
},
|
|
278
|
-
canDelete: (res: string) => {
|
|
279
|
-
if (res !== resource) {
|
|
280
|
-
return false;
|
|
281
|
-
}
|
|
282
|
-
return canDeleteResult; // canDeleteResult is already the boolean 'can' value from useCan
|
|
283
|
-
},
|
|
284
|
-
canRead: (res: string) => {
|
|
285
|
-
if (!enableRead) {
|
|
286
|
-
return true; // If read checking is disabled, allow read
|
|
287
|
-
}
|
|
288
|
-
if (res !== resource) {
|
|
289
|
-
return false;
|
|
336
|
+
// CRITICAL FIX: When isSuperAdminUser is true, immediately grant all permissions without waiting
|
|
337
|
+
// for useCan results. This ensures super admins can use resource operations immediately.
|
|
338
|
+
return useMemo(() => {
|
|
339
|
+
// Helper to create a permission result that bypasses for super admins
|
|
340
|
+
const createSuperAdminAwarePermission = (result: boolean) => {
|
|
341
|
+
// CRITICAL: If super admin is confirmed, immediately grant permission
|
|
342
|
+
// Don't wait for useCan results - super admins bypass all checks
|
|
343
|
+
if (isSuperAdminUser === true) {
|
|
344
|
+
return true;
|
|
290
345
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
346
|
+
|
|
347
|
+
// For non-super-admins or while checking, use normal permission results
|
|
348
|
+
return result;
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
return {
|
|
352
|
+
canCreate: (res: string) => {
|
|
353
|
+
// For now, we only check the resource passed to the hook
|
|
354
|
+
// Future enhancement could support checking different resources
|
|
355
|
+
if (res !== resource) {
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
return createSuperAdminAwarePermission(canCreateResult);
|
|
359
|
+
},
|
|
360
|
+
canUpdate: (res: string) => {
|
|
361
|
+
if (res !== resource) {
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
return createSuperAdminAwarePermission(canUpdateResult);
|
|
365
|
+
},
|
|
366
|
+
canDelete: (res: string) => {
|
|
367
|
+
if (res !== resource) {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
return createSuperAdminAwarePermission(canDeleteResult);
|
|
371
|
+
},
|
|
372
|
+
canRead: (res: string) => {
|
|
373
|
+
if (!enableRead) {
|
|
374
|
+
return true; // If read checking is disabled, allow read
|
|
375
|
+
}
|
|
376
|
+
if (res !== resource) {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
return createSuperAdminAwarePermission(canReadResult);
|
|
380
|
+
},
|
|
381
|
+
scope,
|
|
382
|
+
isLoading: isCheckingSuperAdmin || isLoading,
|
|
383
|
+
error
|
|
384
|
+
};
|
|
385
|
+
}, [
|
|
297
386
|
resource,
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
387
|
+
isSuperAdminUser,
|
|
388
|
+
isCheckingSuperAdmin,
|
|
389
|
+
canCreateResult,
|
|
390
|
+
canUpdateResult,
|
|
391
|
+
canDeleteResult,
|
|
392
|
+
canReadResult,
|
|
302
393
|
enableRead,
|
|
303
394
|
scope,
|
|
304
395
|
isLoading,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Tests focus on behavior: role granting, revoking, loading states, and error handling.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { renderHook, waitFor } from '@testing-library/react';
|
|
11
|
+
import { renderHook, waitFor, act } from '@testing-library/react';
|
|
12
12
|
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
13
13
|
import { useRoleManagement } from './useRoleManagement';
|
|
14
14
|
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
@@ -105,7 +105,7 @@ describe('useRoleManagement Hook', () => {
|
|
|
105
105
|
describe('revokeEventAppRole', () => {
|
|
106
106
|
it('revokes role successfully', async () => {
|
|
107
107
|
(mockSupabase.rpc as any).mockResolvedValue({
|
|
108
|
-
data: true,
|
|
108
|
+
data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
|
|
109
109
|
error: null,
|
|
110
110
|
});
|
|
111
111
|
|
|
@@ -117,19 +117,18 @@ describe('useRoleManagement Hook', () => {
|
|
|
117
117
|
expect(revokeResult.message).toBe('Role revoked successfully');
|
|
118
118
|
expect(revokeResult.error).toBeUndefined();
|
|
119
119
|
expect(result.current.error).toBeNull();
|
|
120
|
-
expect(mockSupabase.rpc).toHaveBeenCalledWith('
|
|
120
|
+
expect(mockSupabase.rpc).toHaveBeenCalledWith('rbac_role_revoke', {
|
|
121
121
|
p_user_id: 'user-456',
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
p_role: 'viewer',
|
|
122
|
+
p_role_type: 'event_app',
|
|
123
|
+
p_role_name: 'viewer',
|
|
124
|
+
p_context_id: 'event-123:app-123',
|
|
126
125
|
p_revoked_by: 'user-123',
|
|
127
126
|
});
|
|
128
127
|
});
|
|
129
128
|
|
|
130
129
|
it('handles case when role not found', async () => {
|
|
131
130
|
(mockSupabase.rpc as any).mockResolvedValue({
|
|
132
|
-
data: false,
|
|
131
|
+
data: [{ success: false, message: 'No matching role found', revoked_count: 0, error_code: 'ROLE_NOT_FOUND' }],
|
|
133
132
|
error: null,
|
|
134
133
|
});
|
|
135
134
|
|
|
@@ -138,13 +137,55 @@ describe('useRoleManagement Hook', () => {
|
|
|
138
137
|
const revokeResult = await result.current.revokeEventAppRole(mockRoleParams);
|
|
139
138
|
|
|
140
139
|
expect(revokeResult.success).toBe(false);
|
|
141
|
-
expect(revokeResult.message).toBe('No role found
|
|
140
|
+
expect(revokeResult.message).toBe('No matching role found');
|
|
142
141
|
expect(revokeResult.error).toBe('No matching role found');
|
|
143
142
|
});
|
|
144
143
|
|
|
144
|
+
it('handles empty data response', async () => {
|
|
145
|
+
(mockSupabase.rpc as any).mockResolvedValue({
|
|
146
|
+
data: [],
|
|
147
|
+
error: null,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const { result } = renderHook(() => useRoleManagement());
|
|
151
|
+
|
|
152
|
+
const revokeResult = await result.current.revokeEventAppRole(mockRoleParams);
|
|
153
|
+
|
|
154
|
+
expect(revokeResult.success).toBe(false);
|
|
155
|
+
expect(revokeResult.error).toBe('No response from database - role revocation may have failed');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('handles null data response', async () => {
|
|
159
|
+
(mockSupabase.rpc as any).mockResolvedValue({
|
|
160
|
+
data: null,
|
|
161
|
+
error: null,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const { result } = renderHook(() => useRoleManagement());
|
|
165
|
+
|
|
166
|
+
const revokeResult = await result.current.revokeEventAppRole(mockRoleParams);
|
|
167
|
+
|
|
168
|
+
expect(revokeResult.success).toBe(false);
|
|
169
|
+
expect(revokeResult.error).toBe('No response from database - role revocation may have failed');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('handles result with success false but no message', async () => {
|
|
173
|
+
(mockSupabase.rpc as any).mockResolvedValue({
|
|
174
|
+
data: [{ success: false, message: null, revoked_count: 0, error_code: 'ROLE_NOT_FOUND' }],
|
|
175
|
+
error: null,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const { result } = renderHook(() => useRoleManagement());
|
|
179
|
+
|
|
180
|
+
const revokeResult = await result.current.revokeEventAppRole(mockRoleParams);
|
|
181
|
+
|
|
182
|
+
expect(revokeResult.success).toBe(false);
|
|
183
|
+
expect(revokeResult.error).toBe('ROLE_NOT_FOUND');
|
|
184
|
+
});
|
|
185
|
+
|
|
145
186
|
it('uses provided revoked_by parameter', async () => {
|
|
146
187
|
(mockSupabase.rpc as any).mockResolvedValue({
|
|
147
|
-
data: true,
|
|
188
|
+
data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
|
|
148
189
|
error: null,
|
|
149
190
|
});
|
|
150
191
|
|
|
@@ -156,7 +197,7 @@ describe('useRoleManagement Hook', () => {
|
|
|
156
197
|
});
|
|
157
198
|
|
|
158
199
|
expect(mockSupabase.rpc).toHaveBeenCalledWith(
|
|
159
|
-
'
|
|
200
|
+
'rbac_role_revoke',
|
|
160
201
|
expect.objectContaining({
|
|
161
202
|
p_revoked_by: 'admin-789',
|
|
162
203
|
})
|
|
@@ -165,7 +206,7 @@ describe('useRoleManagement Hook', () => {
|
|
|
165
206
|
|
|
166
207
|
it('uses user ID as revoked_by when not provided', async () => {
|
|
167
208
|
(mockSupabase.rpc as any).mockResolvedValue({
|
|
168
|
-
data: true,
|
|
209
|
+
data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
|
|
169
210
|
error: null,
|
|
170
211
|
});
|
|
171
212
|
|
|
@@ -174,7 +215,7 @@ describe('useRoleManagement Hook', () => {
|
|
|
174
215
|
await result.current.revokeEventAppRole(mockRoleParams);
|
|
175
216
|
|
|
176
217
|
expect(mockSupabase.rpc).toHaveBeenCalledWith(
|
|
177
|
-
'
|
|
218
|
+
'rbac_role_revoke',
|
|
178
219
|
expect.objectContaining({
|
|
179
220
|
p_revoked_by: 'user-123',
|
|
180
221
|
})
|
|
@@ -262,7 +303,7 @@ describe('useRoleManagement Hook', () => {
|
|
|
262
303
|
);
|
|
263
304
|
|
|
264
305
|
resolvePromise!({
|
|
265
|
-
data: true,
|
|
306
|
+
data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
|
|
266
307
|
error: null,
|
|
267
308
|
});
|
|
268
309
|
|
|
@@ -461,14 +502,16 @@ describe('useRoleManagement Hook', () => {
|
|
|
461
502
|
|
|
462
503
|
const { result } = renderHook(() => useRoleManagement());
|
|
463
504
|
|
|
505
|
+
// Call grantEventAppRole - loading state is set synchronously, but React state updates are async
|
|
464
506
|
const grantPromise = result.current.grantEventAppRole(mockRoleParams);
|
|
465
507
|
|
|
466
|
-
//
|
|
508
|
+
// Wait for React to process the state update (setIsLoading(true))
|
|
509
|
+
// Increased timeout to allow React to batch and process state updates
|
|
467
510
|
await waitFor(
|
|
468
511
|
() => {
|
|
469
512
|
expect(result.current.isLoading).toBe(true);
|
|
470
513
|
},
|
|
471
|
-
{ timeout:
|
|
514
|
+
{ timeout: 1000 }
|
|
472
515
|
);
|
|
473
516
|
|
|
474
517
|
resolvePromise!({
|
|
@@ -797,9 +840,9 @@ describe('useRoleManagement Hook', () => {
|
|
|
797
840
|
});
|
|
798
841
|
|
|
799
842
|
expect(mockSupabase.rpc).toHaveBeenCalledWith(
|
|
800
|
-
'
|
|
843
|
+
'rbac_role_revoke',
|
|
801
844
|
expect.objectContaining({
|
|
802
|
-
|
|
845
|
+
p_role_name: role,
|
|
803
846
|
})
|
|
804
847
|
);
|
|
805
848
|
}
|
|
@@ -825,7 +868,7 @@ describe('useRoleManagement Hook', () => {
|
|
|
825
868
|
|
|
826
869
|
// Second call succeeds
|
|
827
870
|
(mockSupabase.rpc as any).mockResolvedValueOnce({
|
|
828
|
-
data: true,
|
|
871
|
+
data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
|
|
829
872
|
error: null,
|
|
830
873
|
});
|
|
831
874
|
|
|
@@ -850,7 +893,7 @@ describe('useRoleManagement Hook', () => {
|
|
|
850
893
|
|
|
851
894
|
// Second call succeeds
|
|
852
895
|
(mockSupabase.rpc as any).mockResolvedValueOnce({
|
|
853
|
-
data: true,
|
|
896
|
+
data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
|
|
854
897
|
error: null,
|
|
855
898
|
});
|
|
856
899
|
|
|
@@ -864,7 +907,7 @@ describe('useRoleManagement Hook', () => {
|
|
|
864
907
|
describe('Concurrent Operations', () => {
|
|
865
908
|
it('handles concurrent role operations', async () => {
|
|
866
909
|
(mockSupabase.rpc as any).mockResolvedValue({
|
|
867
|
-
data: true,
|
|
910
|
+
data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
|
|
868
911
|
error: null,
|
|
869
912
|
});
|
|
870
913
|
|
|
@@ -885,7 +928,7 @@ describe('useRoleManagement Hook', () => {
|
|
|
885
928
|
|
|
886
929
|
it('handles rapid sequential operations', async () => {
|
|
887
930
|
(mockSupabase.rpc as any).mockResolvedValue({
|
|
888
|
-
data: true,
|
|
931
|
+
data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
|
|
889
932
|
error: null,
|
|
890
933
|
});
|
|
891
934
|
|