@jmruthers/pace-core 0.6.4 → 0.6.6
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/core-usage-manifest.json +93 -0
- package/cursor-rules/00-pace-core-compliance.mdc +128 -26
- package/cursor-rules/01-standards-compliance.mdc +49 -8
- package/cursor-rules/02-project-structure.mdc +6 -0
- package/cursor-rules/03-solid-principles.mdc +2 -0
- package/cursor-rules/04-testing-standards.mdc +2 -0
- package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
- package/cursor-rules/06-code-quality.mdc +2 -0
- package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
- package/cursor-rules/08-markup-quality.mdc +52 -27
- package/cursor-rules/09-rbac-compliance.mdc +462 -0
- package/cursor-rules/10-error-handling-patterns.mdc +179 -0
- package/cursor-rules/11-performance-optimization.mdc +169 -0
- package/cursor-rules/12-ci-cd-integration.mdc +150 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
- package/dist/DataTable-LRJL4IRV.js +15 -0
- package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
- package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
- package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/chunk-4T7OBVTU.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-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
- package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
- package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
- package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/chunk-OHIK3MIO.js +994 -0
- package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
- package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
- package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
- package/dist/components.d.ts +6 -6
- package/dist/components.js +57 -267
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +22 -0
- package/dist/eslint-rules/rules/compliance.cjs +348 -0
- package/dist/eslint-rules/rules/components.cjs +113 -0
- package/dist/eslint-rules/rules/imports.cjs +102 -0
- package/dist/eslint-rules/rules/rbac.cjs +790 -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 +5 -5
- package/dist/hooks.js +62 -270
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +36 -26
- package/dist/index.js +87 -690
- 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 +124 -594
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- 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-B-K_5VnO.d.ts} +4 -0
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +16 -6
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +454 -930
- package/docs/api-reference/components.md +3 -1
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/best-practices/accessibility.md +6 -3
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/permission-enforcement.md +4 -0
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +12 -3
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/secure-client-protection.md +0 -34
- package/docs/standards/00-pace-core-compliance.md +967 -0
- package/docs/standards/01-standards-compliance.md +188 -0
- package/docs/standards/02-project-structure.md +985 -0
- package/docs/standards/03-solid-principles.md +39 -0
- package/docs/standards/04-testing-standards.md +36 -0
- package/docs/standards/05-bug-reports-and-features.md +27 -0
- package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
- package/docs/standards/07-tech-stack-compliance.md +30 -0
- package/docs/standards/08-markup-quality.md +345 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
- package/docs/standards/10-error-handling-patterns.md +401 -0
- package/docs/standards/11-performance-optimization.md +348 -0
- package/docs/standards/12-ci-cd-integration.md +370 -0
- package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
- package/docs/standards/README.md +62 -33
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +20 -4
- package/package.json +31 -21
- package/scripts/audit/audit-compliance.cjs +1295 -0
- package/scripts/audit/audit-components.cjs +260 -0
- package/scripts/audit/audit-dependencies.cjs +395 -0
- package/scripts/audit/audit-rbac.cjs +954 -0
- package/scripts/audit/audit-standards.cjs +1268 -0
- package/scripts/audit/index.cjs +1898 -194
- package/scripts/install-cursor-rules.cjs +259 -8
- package/scripts/validate-master.js +1 -1
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
- 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-utils.test.tsx +3 -3
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/ContextSelector/ContextSelector.tsx +42 -39
- package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
- package/src/components/DataTable/components/DataTableBody.tsx +55 -31
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +7 -2
- package/src/components/DataTable/components/ImportModal.tsx +4 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/core/DataTableContext.tsx +1 -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 -0
- package/src/components/DateTimeField/DateTimeField.tsx +20 -20
- package/src/components/DateTimeField/README.md +5 -2
- package/src/components/Dialog/Dialog.test.tsx +361 -318
- package/src/components/Dialog/Dialog.tsx +1154 -323
- package/src/components/Dialog/index.ts +3 -3
- package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
- package/src/components/FileDisplay/FileDisplay.tsx +28 -22
- package/src/components/Form/Form.test.tsx +9 -10
- package/src/components/Form/Form.tsx +369 -9
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
- package/src/components/LoginForm/LoginForm.tsx +2 -2
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
- package/src/components/PaceAppLayout/README.md +10 -9
- package/src/components/PaceAppLayout/test-setup.tsx +40 -31
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
- package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
- package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
- package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
- package/src/components/Select/Select.tsx +23 -21
- package/src/components/Select/types.ts +1 -1
- package/src/components/UserMenu/UserMenu.test.tsx +38 -6
- package/src/components/UserMenu/UserMenu.tsx +39 -34
- package/src/components/index.ts +3 -4
- package/src/eslint-rules/index.cjs +22 -0
- package/src/eslint-rules/rules/compliance.cjs +348 -0
- package/src/eslint-rules/rules/components.cjs +113 -0
- package/src/eslint-rules/rules/imports.cjs +102 -0
- package/src/eslint-rules/rules/rbac.cjs +790 -0
- package/src/eslint-rules/utils/helpers.cjs +42 -0
- package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- 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 +62 -190
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +19 -9
- package/src/hooks/useAppConfig.ts +26 -24
- package/src/hooks/useEventTheme.test.ts +211 -233
- package/src/hooks/useEventTheme.ts +19 -28
- package/src/hooks/useEvents.ts +11 -7
- package/src/hooks/useKeyboardShortcuts.ts +1 -1
- package/src/hooks/useOrganisationPermissions.ts +9 -11
- package/src/hooks/useOrganisations.ts +13 -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 +16 -1
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
- package/src/rbac/README.md +20 -20
- 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/useRBAC.test.ts +21 -3
- package/src/rbac/hooks/useRBAC.ts +4 -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 +241 -60
- package/src/rbac/hooks/useResourcePermissions.ts +182 -63
- 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/permissions.ts +17 -17
- package/src/rbac/utils/contextValidator.ts +45 -7
- package/src/services/AuthService.ts +132 -23
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +155 -58
- 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 +4 -0
- package/src/types/database.generated.ts +4733 -3809
- 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/formatting/formatTime.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/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/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-E7YQZD7D.js +0 -175
- package/dist/DataTable-E7YQZD7D.js.map +0 -1
- package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
- package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
- package/dist/api-6LVZTHDS.js +0 -52
- package/dist/api-6LVZTHDS.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-36LVWXB2.js +0 -227
- package/dist/chunk-36LVWXB2.js.map +0 -1
- package/dist/chunk-3LPHPB62.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-5EC5MEWX.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6SOIHG6Z.js.map +0 -1
- package/dist/chunk-7JPAB3T5.js.map +0 -1
- package/dist/chunk-ATKZM7RX.js +0 -2053
- package/dist/chunk-ATKZM7RX.js.map +0 -1
- package/dist/chunk-AVMLPIM7.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.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-I6DAQMWX.js.map +0 -1
- package/dist/chunk-J36DSWQK.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-NN6WWZ5U.js.map +0 -1
- package/dist/chunk-OEWDTMG7.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-YKRAFF5K.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-OOPCLPZW.js +0 -9
- package/dist/contextValidator-OOPCLPZW.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/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/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/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/eslint-rules/pace-core-compliance.cjs +0 -510
- 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
|
@@ -241,15 +241,19 @@ describe('[component] PublicPageLayout', () => {
|
|
|
241
241
|
});
|
|
242
242
|
|
|
243
243
|
it('renders loading state with proper layout classes', () => {
|
|
244
|
-
|
|
244
|
+
render(
|
|
245
245
|
<PublicPageLayout eventCode="EVENT123" isLoading={true}>
|
|
246
246
|
<div>Test Content</div>
|
|
247
247
|
</PublicPageLayout>
|
|
248
248
|
);
|
|
249
249
|
|
|
250
|
-
|
|
250
|
+
// The loading state renders a <p> tag with grid and place-items-center classes
|
|
251
|
+
// There may be multiple "Loading..." texts (from LoadingSpinner mock and actual text)
|
|
252
|
+
// So we query by the container element using getAllByText and find the one in the <p> tag
|
|
253
|
+
const loadingTexts = screen.getAllByText('Loading...');
|
|
254
|
+
const loadingContainer = loadingTexts.find(text => text.closest('p'))?.closest('p');
|
|
251
255
|
expect(loadingContainer).toBeInTheDocument();
|
|
252
|
-
expect(loadingContainer).toHaveClass('
|
|
256
|
+
expect(loadingContainer).toHaveClass('grid', 'place-items-center', 'text-center', 'size-full');
|
|
253
257
|
});
|
|
254
258
|
});
|
|
255
259
|
|
|
@@ -312,14 +312,11 @@ export function PublicPageLayout({
|
|
|
312
312
|
return <LoadingFallback />;
|
|
313
313
|
}
|
|
314
314
|
return (
|
|
315
|
-
<
|
|
316
|
-
<
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
)}
|
|
321
|
-
</div>
|
|
322
|
-
</div>
|
|
315
|
+
<p className="grid place-items-center text-center size-full">
|
|
316
|
+
<LoadingSpinner
|
|
317
|
+
size="lg"/><br />
|
|
318
|
+
{loadingMessage || 'Loading...'}
|
|
319
|
+
</p>
|
|
323
320
|
);
|
|
324
321
|
}
|
|
325
322
|
|
|
@@ -40,20 +40,20 @@ import { getTextContent } from "./utils/text";
|
|
|
40
40
|
* Provides select dropdown functionality with search, keyboard navigation, and accessibility.
|
|
41
41
|
*
|
|
42
42
|
* @param props - Select configuration
|
|
43
|
-
* @param ref - Forwarded ref to the
|
|
43
|
+
* @param ref - Forwarded ref to the fieldset element
|
|
44
44
|
* @returns The rendered select component
|
|
45
45
|
*/
|
|
46
|
-
export const Select = React.forwardRef<
|
|
46
|
+
export const Select = React.forwardRef<HTMLFieldSetElement, SelectProps & UseSelectStateProps>(
|
|
47
47
|
({
|
|
48
48
|
children,
|
|
49
49
|
className,
|
|
50
50
|
direction = 'down',
|
|
51
51
|
...selectProps
|
|
52
52
|
}, ref) => {
|
|
53
|
-
const internalRef = React.useRef<
|
|
53
|
+
const internalRef = React.useRef<HTMLFieldSetElement>(null);
|
|
54
54
|
const selectRef = React.useMemo(() => {
|
|
55
55
|
if (ref && typeof ref === 'object' && 'current' in ref) {
|
|
56
|
-
return ref as React.RefObject<
|
|
56
|
+
return ref as React.RefObject<HTMLFieldSetElement | null>;
|
|
57
57
|
}
|
|
58
58
|
return internalRef;
|
|
59
59
|
}, [ref]);
|
|
@@ -201,20 +201,16 @@ export const Select = React.forwardRef<HTMLFormElement, SelectProps & UseSelectS
|
|
|
201
201
|
}), [state, actions, registerItem, unregisterItem, direction]);
|
|
202
202
|
|
|
203
203
|
return (
|
|
204
|
-
<
|
|
204
|
+
<fieldset
|
|
205
205
|
ref={selectRef}
|
|
206
|
-
className={cn("relative", className)}
|
|
206
|
+
className={cn("relative border-0 p-0 m-0", className)}
|
|
207
207
|
data-value={state.value}
|
|
208
208
|
data-testid="select-root"
|
|
209
|
-
onSubmit={(e) => {
|
|
210
|
-
e.preventDefault();
|
|
211
|
-
e.stopPropagation();
|
|
212
|
-
}}
|
|
213
209
|
>
|
|
214
210
|
<SelectContext.Provider value={contextValue}>
|
|
215
211
|
{children}
|
|
216
212
|
</SelectContext.Provider>
|
|
217
|
-
</
|
|
213
|
+
</fieldset>
|
|
218
214
|
);
|
|
219
215
|
}
|
|
220
216
|
);
|
|
@@ -304,6 +300,18 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
|
|
|
304
300
|
...props
|
|
305
301
|
};
|
|
306
302
|
|
|
303
|
+
// Call all hooks unconditionally at the top level
|
|
304
|
+
// Hooks must be called in the same order on every render
|
|
305
|
+
// Simple ref forwarding - must be called before any early returns
|
|
306
|
+
const handleRef = React.useCallback((node: HTMLButtonElement | null) => {
|
|
307
|
+
if (typeof ref === 'function') {
|
|
308
|
+
ref(node);
|
|
309
|
+
} else if (ref) {
|
|
310
|
+
(ref as React.MutableRefObject<HTMLButtonElement | null>).current = node;
|
|
311
|
+
}
|
|
312
|
+
}, [ref]);
|
|
313
|
+
|
|
314
|
+
// Early return after all hooks have been called
|
|
307
315
|
if (asChild) {
|
|
308
316
|
const childElement = children as React.ReactElement<{ children?: React.ReactNode; [key: string]: unknown }>;
|
|
309
317
|
const childChildren = React.Children.toArray(childElement.props.children);
|
|
@@ -340,16 +348,6 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
|
|
|
340
348
|
});
|
|
341
349
|
}
|
|
342
350
|
|
|
343
|
-
|
|
344
|
-
// Simple ref forwarding
|
|
345
|
-
const handleRef = React.useCallback((node: HTMLButtonElement | null) => {
|
|
346
|
-
if (typeof ref === 'function') {
|
|
347
|
-
ref(node);
|
|
348
|
-
} else if (ref) {
|
|
349
|
-
(ref as React.MutableRefObject<HTMLButtonElement | null>).current = node;
|
|
350
|
-
}
|
|
351
|
-
}, [ref]);
|
|
352
|
-
|
|
353
351
|
return (
|
|
354
352
|
<Button
|
|
355
353
|
ref={handleRef}
|
|
@@ -574,6 +572,8 @@ export const SelectItem = React.forwardRef<HTMLLIElement, SelectItemProps>(
|
|
|
574
572
|
|
|
575
573
|
const handleMouseDown = (e: React.MouseEvent) => {
|
|
576
574
|
if (!disabled) {
|
|
575
|
+
// CRITICAL FIX: Prevent event from bubbling to avoid interference with table row interactions
|
|
576
|
+
e.stopPropagation();
|
|
577
577
|
const event = new CustomEvent('selectItemMouseDown', { detail: { value } });
|
|
578
578
|
document.dispatchEvent(event);
|
|
579
579
|
}
|
|
@@ -581,6 +581,8 @@ export const SelectItem = React.forwardRef<HTMLLIElement, SelectItemProps>(
|
|
|
581
581
|
|
|
582
582
|
const handleClick = (e: React.MouseEvent) => {
|
|
583
583
|
if (!disabled) {
|
|
584
|
+
// CRITICAL FIX: Prevent event from bubbling to avoid interference with table row clicks
|
|
585
|
+
e.stopPropagation();
|
|
584
586
|
if (onClick) {
|
|
585
587
|
onClick(e);
|
|
586
588
|
}
|
|
@@ -74,7 +74,7 @@ export interface SelectContextValue extends SelectState {
|
|
|
74
74
|
*/
|
|
75
75
|
export interface SelectProps
|
|
76
76
|
extends Omit<
|
|
77
|
-
React.HTMLAttributes<
|
|
77
|
+
React.HTMLAttributes<HTMLFieldSetElement>,
|
|
78
78
|
"onChange" | "onKeyDown" | "onFocus" | "onBlur"
|
|
79
79
|
> {
|
|
80
80
|
children: React.ReactNode;
|
|
@@ -21,7 +21,7 @@ vi.mock('lucide-react', () => ({
|
|
|
21
21
|
|
|
22
22
|
// Mock the PasswordChangeForm component
|
|
23
23
|
vi.mock('../PasswordChange/PasswordChangeForm', () => ({
|
|
24
|
-
PasswordChangeForm: ({ onSubmit }: { onSubmit: (values: { newPassword: string; confirmPassword: string }) => Promise<{ error?: { message?: string; code?: string } }
|
|
24
|
+
PasswordChangeForm: ({ onSubmit, onSuccess }: { onSubmit: (values: { newPassword: string; confirmPassword: string }) => Promise<{ error?: { message?: string; code?: string } }>; onSuccess?: () => void }) => {
|
|
25
25
|
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
26
26
|
const [error, setError] = React.useState<string | null>(null);
|
|
27
27
|
|
|
@@ -33,6 +33,9 @@ vi.mock('../PasswordChange/PasswordChangeForm', () => ({
|
|
|
33
33
|
const result = await onSubmit({ newPassword: 'newpass123', confirmPassword: 'newpass123' });
|
|
34
34
|
if (result.error) {
|
|
35
35
|
setError(result.error.message);
|
|
36
|
+
} else {
|
|
37
|
+
// Call onSuccess on successful password change
|
|
38
|
+
onSuccess?.();
|
|
36
39
|
}
|
|
37
40
|
} catch (err) {
|
|
38
41
|
const errorObj = err instanceof Error ? err : new Error('An unexpected error occurred');
|
|
@@ -92,9 +95,7 @@ vi.mock('../Select', () => ({
|
|
|
92
95
|
// Mock the Dialog components
|
|
93
96
|
vi.mock('../Dialog', () => ({
|
|
94
97
|
Dialog: ({ children, open, onOpenChange }: { children: React.ReactNode; open: boolean; onOpenChange: (open: boolean) => void }) => (
|
|
95
|
-
<div data-testid="dialog" data-open={open}>
|
|
96
|
-
{children}
|
|
97
|
-
</div>
|
|
98
|
+
open ? <div data-testid="dialog" role="dialog" data-open={open}>{children}</div> : null
|
|
98
99
|
),
|
|
99
100
|
DialogContent: ({ children, className }: { children: React.ReactNode; className?: string }) => (
|
|
100
101
|
<div data-testid="dialog-content" className={className}>
|
|
@@ -109,12 +110,17 @@ vi.mock('../Dialog', () => ({
|
|
|
109
110
|
DialogTitle: ({ children }: { children: React.ReactNode }) => (
|
|
110
111
|
<h2 data-testid="dialog-title">{children}</h2>
|
|
111
112
|
),
|
|
113
|
+
DialogDescription: ({ children }: { children: React.ReactNode }) => (
|
|
114
|
+
<p data-testid="dialog-description">{children}</p>
|
|
115
|
+
),
|
|
112
116
|
DialogTrigger: ({ children, asChild }: { children: React.ReactNode; asChild?: boolean }) => (
|
|
113
117
|
<div data-testid="dialog-trigger">
|
|
114
118
|
{asChild ? children : <button>{children}</button>}
|
|
115
119
|
</div>
|
|
116
120
|
),
|
|
117
|
-
|
|
121
|
+
DialogClose: ({ children, onClick }: { children?: React.ReactNode; onClick?: () => void }) => (
|
|
122
|
+
<button data-testid="dialog-close" onClick={onClick}>{children || 'Close'}</button>
|
|
123
|
+
),
|
|
118
124
|
}));
|
|
119
125
|
|
|
120
126
|
// Mock the Avatar component
|
|
@@ -412,6 +418,32 @@ describe('UserMenu Component', () => {
|
|
|
412
418
|
});
|
|
413
419
|
});
|
|
414
420
|
|
|
421
|
+
it('closes dialog when password change succeeds', async () => {
|
|
422
|
+
const user = createMockUser();
|
|
423
|
+
const handleChangePassword = vi.fn().mockResolvedValue({});
|
|
424
|
+
const userEventInstance = userEvent.setup();
|
|
425
|
+
|
|
426
|
+
renderWithProviders(<UserMenu user={user} onChangePassword={handleChangePassword} />);
|
|
427
|
+
|
|
428
|
+
const trigger = screen.getByRole('button', { name: 'Test User' });
|
|
429
|
+
await userEventInstance.click(trigger);
|
|
430
|
+
|
|
431
|
+
const changePasswordButton = screen.getByTestId('select-item-change-password');
|
|
432
|
+
await userEventInstance.click(changePasswordButton);
|
|
433
|
+
|
|
434
|
+
// Verify dialog is open
|
|
435
|
+
expect(screen.getByTestId('dialog-content')).toBeInTheDocument();
|
|
436
|
+
|
|
437
|
+
const submitButton = screen.getByRole('button', { name: 'Change Password' });
|
|
438
|
+
await userEventInstance.click(submitButton);
|
|
439
|
+
|
|
440
|
+
// Wait for dialog to close
|
|
441
|
+
await waitFor(() => {
|
|
442
|
+
const dialog = screen.queryByTestId('dialog-content');
|
|
443
|
+
expect(dialog).not.toBeInTheDocument();
|
|
444
|
+
}, { timeout: 3000 });
|
|
445
|
+
});
|
|
446
|
+
|
|
415
447
|
it('keeps dialog open when password change fails', async () => {
|
|
416
448
|
const user = createMockUser();
|
|
417
449
|
const handleChangePassword = vi.fn().mockResolvedValue({ error: { message: 'Password too weak' } });
|
|
@@ -434,7 +466,7 @@ describe('UserMenu Component', () => {
|
|
|
434
466
|
expect(screen.getByTestId('error-message')).toHaveTextContent('Password too weak');
|
|
435
467
|
});
|
|
436
468
|
|
|
437
|
-
// Dialog should still be open
|
|
469
|
+
// Dialog should still be open (onSuccess should not be called when there's an error)
|
|
438
470
|
expect(screen.getByTestId('dialog-content')).toBeInTheDocument();
|
|
439
471
|
});
|
|
440
472
|
|
|
@@ -117,9 +117,7 @@ import {
|
|
|
117
117
|
Dialog,
|
|
118
118
|
DialogContent,
|
|
119
119
|
DialogHeader,
|
|
120
|
-
DialogTitle
|
|
121
|
-
DialogTrigger,
|
|
122
|
-
DialogOverlay
|
|
120
|
+
DialogTitle
|
|
123
121
|
} from '../Dialog';
|
|
124
122
|
import { PasswordChangeForm, PasswordChangeFormError } from '../PasswordChange/PasswordChangeForm';
|
|
125
123
|
import { Avatar } from '../Avatar';
|
|
@@ -144,8 +142,8 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
|
|
|
144
142
|
className,
|
|
145
143
|
showAvatar = true,
|
|
146
144
|
}) {
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
// Call all hooks unconditionally at the top level
|
|
146
|
+
// Hooks must be called in the same order on every render
|
|
149
147
|
const userInfo = useMemo(() => {
|
|
150
148
|
if (!user) return null;
|
|
151
149
|
return {
|
|
@@ -160,12 +158,23 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
|
|
|
160
158
|
if (onSignOut) await onSignOut();
|
|
161
159
|
}, [onSignOut]);
|
|
162
160
|
|
|
161
|
+
// Password change dialog state and handlers - must be called before any early returns
|
|
162
|
+
const [isPasswordDialogOpen, setPasswordDialogOpen] = useState(false);
|
|
163
|
+
|
|
164
|
+
const handlePasswordChange = useCallback(async (newPassword: string, confirmPassword: string) => {
|
|
165
|
+
if (!onChangePassword) {
|
|
166
|
+
return { error: { message: 'Password change not configured' } };
|
|
167
|
+
}
|
|
168
|
+
return await onChangePassword(newPassword, confirmPassword);
|
|
169
|
+
}, [onChangePassword]);
|
|
170
|
+
|
|
171
|
+
// Early return after all hooks have been called
|
|
163
172
|
if (!user || !userInfo) {
|
|
164
173
|
return null; // Or a loading/login button
|
|
165
174
|
}
|
|
166
175
|
|
|
167
176
|
return (
|
|
168
|
-
|
|
177
|
+
<>
|
|
169
178
|
<Select className={className}>
|
|
170
179
|
<SelectTrigger asChild>
|
|
171
180
|
<Button variant="outline" className="flex items-center gap-2" aria-label={userInfo.displayName}>
|
|
@@ -185,42 +194,38 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
|
|
|
185
194
|
<SelectLabel className="font-normal">
|
|
186
195
|
<li className="pt-2">
|
|
187
196
|
{userInfo.displayName}<br/>
|
|
188
|
-
<
|
|
197
|
+
<small>{userInfo.email}</small>
|
|
189
198
|
</li>
|
|
190
199
|
</SelectLabel>
|
|
191
200
|
<SelectSeparator />
|
|
192
|
-
<
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
201
|
+
<SelectItem
|
|
202
|
+
value="change-password"
|
|
203
|
+
onClick={() => setPasswordDialogOpen(true)}
|
|
204
|
+
>
|
|
205
|
+
<KeyRound className="inline-block mr-2 size-4" />
|
|
206
|
+
Change Password
|
|
207
|
+
</SelectItem>
|
|
198
208
|
<SelectItem value="sign-out" onClick={handleSignOut}>
|
|
199
|
-
<LogOut className="mr-2 size-4" />
|
|
200
|
-
|
|
209
|
+
<LogOut className="inline-block mr-2 size-4" />
|
|
210
|
+
Sign out
|
|
201
211
|
</SelectItem>
|
|
202
212
|
</SelectContent>
|
|
203
213
|
</Select>
|
|
204
214
|
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return {};
|
|
220
|
-
}}
|
|
221
|
-
/>
|
|
222
|
-
</DialogContent>
|
|
223
|
-
</Dialog>
|
|
215
|
+
<Dialog open={isPasswordDialogOpen} onOpenChange={setPasswordDialogOpen}>
|
|
216
|
+
<DialogContent persistOpenState={false}>
|
|
217
|
+
<DialogHeader>
|
|
218
|
+
<DialogTitle>Change Password</DialogTitle>
|
|
219
|
+
</DialogHeader>
|
|
220
|
+
<PasswordChangeForm
|
|
221
|
+
onSubmit={async ({ newPassword, confirmPassword }) => {
|
|
222
|
+
return await handlePasswordChange(newPassword, confirmPassword);
|
|
223
|
+
}}
|
|
224
|
+
onSuccess={() => setPasswordDialogOpen(false)}
|
|
225
|
+
/>
|
|
226
|
+
</DialogContent>
|
|
227
|
+
</Dialog>
|
|
228
|
+
</>
|
|
224
229
|
);
|
|
225
230
|
});
|
|
226
231
|
|
package/src/components/index.ts
CHANGED
|
@@ -84,7 +84,6 @@ export {
|
|
|
84
84
|
export {
|
|
85
85
|
Dialog,
|
|
86
86
|
DialogPortal,
|
|
87
|
-
DialogOverlay,
|
|
88
87
|
DialogTrigger,
|
|
89
88
|
DialogClose,
|
|
90
89
|
DialogContent,
|
|
@@ -98,11 +97,11 @@ export type {
|
|
|
98
97
|
DialogProps,
|
|
99
98
|
DialogTriggerProps,
|
|
100
99
|
DialogContentProps,
|
|
101
|
-
|
|
100
|
+
DialogPortalProps,
|
|
101
|
+
DialogCloseProps,
|
|
102
102
|
DialogHeaderProps,
|
|
103
103
|
DialogFooterProps,
|
|
104
|
-
|
|
105
|
-
DialogDescriptionProps,
|
|
104
|
+
DialogBodyProps,
|
|
106
105
|
DialogSize
|
|
107
106
|
} from './Dialog/Dialog';
|
|
108
107
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main entry point for pace-core ESLint rules
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module ESLintRules
|
|
5
|
+
*
|
|
6
|
+
* This module exports all pace-core compliance ESLint rules organized by category.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const complianceRules = require('./rules/compliance.cjs');
|
|
10
|
+
const componentRules = require('./rules/components.cjs');
|
|
11
|
+
const rbacRules = require('./rules/rbac.cjs');
|
|
12
|
+
const importRules = require('./rules/imports.cjs');
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
rules: {
|
|
16
|
+
...complianceRules.rules,
|
|
17
|
+
...componentRules.rules,
|
|
18
|
+
...rbacRules.rules,
|
|
19
|
+
...importRules.rules,
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|