@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
|
@@ -10,6 +10,10 @@ import { renderHook, act } from '@testing-library/react';
|
|
|
10
10
|
import { useDataTableState, dataTableReducer } from '../useDataTableState';
|
|
11
11
|
import type { DataRecord, SortingState, ColumnFiltersState, VisibilityState, GroupingState, ExpandedState, PaginationState } from '../../types';
|
|
12
12
|
|
|
13
|
+
// Following testing standards: use timeout parameter to prevent hanging
|
|
14
|
+
// See: packages/core/docs/standards/04-testing-standards.md
|
|
15
|
+
const TEST_TIMEOUT = 10000; // 10 seconds per test
|
|
16
|
+
|
|
13
17
|
interface TestData extends DataRecord {
|
|
14
18
|
id: string;
|
|
15
19
|
name: string;
|
|
@@ -51,7 +55,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
51
55
|
|
|
52
56
|
expect(result.sorting).toEqual(newSorting);
|
|
53
57
|
expect(result).toEqual({ ...initialState, sorting: newSorting });
|
|
54
|
-
});
|
|
58
|
+
}, TEST_TIMEOUT);
|
|
55
59
|
|
|
56
60
|
it('handles SET_COLUMN_FILTERS action', () => {
|
|
57
61
|
const newFilters: ColumnFiltersState = [{ id: 'name', value: 'John' }];
|
|
@@ -60,7 +64,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
60
64
|
const result = dataTableReducer(initialState, action);
|
|
61
65
|
|
|
62
66
|
expect(result.columnFilters).toEqual(newFilters);
|
|
63
|
-
});
|
|
67
|
+
}, TEST_TIMEOUT);
|
|
64
68
|
|
|
65
69
|
it('handles SET_COLUMN_VISIBILITY action', () => {
|
|
66
70
|
const newVisibility: VisibilityState = { name: false, email: true };
|
|
@@ -69,7 +73,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
69
73
|
const result = dataTableReducer(initialState, action);
|
|
70
74
|
|
|
71
75
|
expect(result.columnVisibility).toEqual(newVisibility);
|
|
72
|
-
});
|
|
76
|
+
}, TEST_TIMEOUT);
|
|
73
77
|
|
|
74
78
|
it('handles SET_GROUPING action', () => {
|
|
75
79
|
const newGrouping: GroupingState = ['name'];
|
|
@@ -78,7 +82,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
78
82
|
const result = dataTableReducer(initialState, action);
|
|
79
83
|
|
|
80
84
|
expect(result.grouping).toEqual(newGrouping);
|
|
81
|
-
});
|
|
85
|
+
}, TEST_TIMEOUT);
|
|
82
86
|
|
|
83
87
|
it('handles SET_EXPANDED action', () => {
|
|
84
88
|
const newExpanded: ExpandedState = { '1': true };
|
|
@@ -87,7 +91,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
87
91
|
const result = dataTableReducer(initialState, action);
|
|
88
92
|
|
|
89
93
|
expect(result.expanded).toEqual(newExpanded);
|
|
90
|
-
});
|
|
94
|
+
}, TEST_TIMEOUT);
|
|
91
95
|
|
|
92
96
|
it('handles SET_PAGINATION action', () => {
|
|
93
97
|
const newPagination: PaginationState = { pageIndex: 2, pageSize: 25 };
|
|
@@ -96,7 +100,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
96
100
|
const result = dataTableReducer(initialState, action);
|
|
97
101
|
|
|
98
102
|
expect(result.pagination).toEqual(newPagination);
|
|
99
|
-
});
|
|
103
|
+
}, TEST_TIMEOUT);
|
|
100
104
|
|
|
101
105
|
it('handles SET_COLUMN_ORDER action', () => {
|
|
102
106
|
const newOrder = ['name', 'id', 'email'];
|
|
@@ -105,7 +109,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
105
109
|
const result = dataTableReducer(initialState, action);
|
|
106
110
|
|
|
107
111
|
expect(result.columnOrder).toEqual(newOrder);
|
|
108
|
-
});
|
|
112
|
+
}, TEST_TIMEOUT);
|
|
109
113
|
|
|
110
114
|
it('handles SET_ROW_SELECTION action', () => {
|
|
111
115
|
const newSelection = { '1': true, '2': false };
|
|
@@ -114,7 +118,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
114
118
|
const result = dataTableReducer(initialState, action);
|
|
115
119
|
|
|
116
120
|
expect(result.rowSelection).toEqual(newSelection);
|
|
117
|
-
});
|
|
121
|
+
}, TEST_TIMEOUT);
|
|
118
122
|
|
|
119
123
|
it('handles TOGGLE_ROW_SELECTION action', () => {
|
|
120
124
|
const initialStateWithSelection = { ...initialState, rowSelection: { '1': true } };
|
|
@@ -123,7 +127,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
123
127
|
const result = dataTableReducer(initialStateWithSelection, action);
|
|
124
128
|
|
|
125
129
|
expect(result.rowSelection).toEqual({ '1': true, '2': true });
|
|
126
|
-
});
|
|
130
|
+
}, TEST_TIMEOUT);
|
|
127
131
|
|
|
128
132
|
it('handles CLEAR_ROW_SELECTION action', () => {
|
|
129
133
|
const initialStateWithSelection = { ...initialState, rowSelection: { '1': true, '2': true } };
|
|
@@ -132,7 +136,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
132
136
|
const result = dataTableReducer(initialStateWithSelection, action);
|
|
133
137
|
|
|
134
138
|
expect(result.rowSelection).toEqual({});
|
|
135
|
-
});
|
|
139
|
+
}, TEST_TIMEOUT);
|
|
136
140
|
|
|
137
141
|
it('handles SET_CREATING action', () => {
|
|
138
142
|
const action = { type: 'SET_CREATING' as const, payload: true };
|
|
@@ -140,7 +144,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
140
144
|
const result = dataTableReducer(initialState, action);
|
|
141
145
|
|
|
142
146
|
expect(result.isCreating).toBe(true);
|
|
143
|
-
});
|
|
147
|
+
}, TEST_TIMEOUT);
|
|
144
148
|
|
|
145
149
|
it('handles SET_CREATION_DATA action', () => {
|
|
146
150
|
const creationData = { name: 'New User', email: 'new@example.com' };
|
|
@@ -149,7 +153,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
149
153
|
const result = dataTableReducer(initialState, action);
|
|
150
154
|
|
|
151
155
|
expect(result.creationData).toEqual(creationData);
|
|
152
|
-
});
|
|
156
|
+
}, TEST_TIMEOUT);
|
|
153
157
|
|
|
154
158
|
it('handles CLEAR_CREATION_DATA action', () => {
|
|
155
159
|
const initialStateWithCreationData = { ...initialState, creationData: { name: 'Test' } };
|
|
@@ -158,7 +162,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
158
162
|
const result = dataTableReducer(initialStateWithCreationData, action);
|
|
159
163
|
|
|
160
164
|
expect(result.creationData).toEqual({});
|
|
161
|
-
});
|
|
165
|
+
}, TEST_TIMEOUT);
|
|
162
166
|
|
|
163
167
|
it('handles SET_EDITING_ROW action', () => {
|
|
164
168
|
const editingData = { rowId: '1', data: { name: 'Updated Name' } };
|
|
@@ -168,7 +172,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
168
172
|
|
|
169
173
|
expect(result.editingRowId).toBe('1');
|
|
170
174
|
expect(result.editingData).toEqual({ name: 'Updated Name' });
|
|
171
|
-
});
|
|
175
|
+
}, TEST_TIMEOUT);
|
|
172
176
|
|
|
173
177
|
it('handles CLEAR_EDITING action', () => {
|
|
174
178
|
const initialStateWithEditing = {
|
|
@@ -182,7 +186,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
182
186
|
|
|
183
187
|
expect(result.editingRowId).toBe(null);
|
|
184
188
|
expect(result.editingData).toEqual({});
|
|
185
|
-
});
|
|
189
|
+
}, TEST_TIMEOUT);
|
|
186
190
|
|
|
187
191
|
it('handles SET_IMPORT_MODAL action', () => {
|
|
188
192
|
const action = { type: 'SET_IMPORT_MODAL' as const, payload: true };
|
|
@@ -190,7 +194,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
190
194
|
const result = dataTableReducer(initialState, action);
|
|
191
195
|
|
|
192
196
|
expect(result.showImportModal).toBe(true);
|
|
193
|
-
});
|
|
197
|
+
}, TEST_TIMEOUT);
|
|
194
198
|
|
|
195
199
|
it('handles SET_FILTER_ROW action', () => {
|
|
196
200
|
const action = { type: 'SET_FILTER_ROW' as const, payload: true };
|
|
@@ -198,7 +202,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
198
202
|
const result = dataTableReducer(initialState, action);
|
|
199
203
|
|
|
200
204
|
expect(result.showFilterRow).toBe(true);
|
|
201
|
-
});
|
|
205
|
+
}, TEST_TIMEOUT);
|
|
202
206
|
|
|
203
207
|
it('handles SET_SEARCH_QUERY action', () => {
|
|
204
208
|
const action = { type: 'SET_SEARCH_QUERY' as const, payload: 'search term' };
|
|
@@ -206,7 +210,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
206
210
|
const result = dataTableReducer(initialState, action);
|
|
207
211
|
|
|
208
212
|
expect(result.searchQuery).toBe('search term');
|
|
209
|
-
});
|
|
213
|
+
}, TEST_TIMEOUT);
|
|
210
214
|
|
|
211
215
|
it('handles RESET_STATE action', () => {
|
|
212
216
|
const modifiedState = {
|
|
@@ -229,7 +233,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
229
233
|
expect(result.rowSelection).toEqual({});
|
|
230
234
|
expect(result.isCreating).toBe(false);
|
|
231
235
|
expect(result.searchQuery).toBe('');
|
|
232
|
-
});
|
|
236
|
+
}, TEST_TIMEOUT);
|
|
233
237
|
|
|
234
238
|
it('handles INITIALIZE_STATE action', () => {
|
|
235
239
|
const partialState = {
|
|
@@ -244,7 +248,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
244
248
|
expect(result.sorting).toEqual(partialState.sorting);
|
|
245
249
|
expect(result.searchQuery).toBe(partialState.searchQuery);
|
|
246
250
|
expect(result.columnFilters).toEqual(initialState.columnFilters); // Should remain unchanged
|
|
247
|
-
});
|
|
251
|
+
}, TEST_TIMEOUT);
|
|
248
252
|
|
|
249
253
|
it('returns same state for unknown action', () => {
|
|
250
254
|
const unknownAction = { type: 'UNKNOWN_ACTION' as any, payload: null };
|
|
@@ -252,7 +256,7 @@ describe('[unit] dataTableReducer', () => {
|
|
|
252
256
|
const result = dataTableReducer(initialState, unknownAction);
|
|
253
257
|
|
|
254
258
|
expect(result).toBe(initialState);
|
|
255
|
-
});
|
|
259
|
+
}, TEST_TIMEOUT);
|
|
256
260
|
});
|
|
257
261
|
|
|
258
262
|
describe('[unit] useDataTableState', () => {
|
|
@@ -274,7 +278,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
274
278
|
expect(result.current.state.showImportModal).toBe(false);
|
|
275
279
|
expect(result.current.state.showFilterRow).toBe(false);
|
|
276
280
|
expect(result.current.state.searchQuery).toBe('');
|
|
277
|
-
});
|
|
281
|
+
}, TEST_TIMEOUT);
|
|
278
282
|
|
|
279
283
|
it('initializes with custom options', () => {
|
|
280
284
|
const options = {
|
|
@@ -288,7 +292,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
288
292
|
expect(result.current.state.pagination.pageSize).toBe(25);
|
|
289
293
|
expect(result.current.state.columnOrder).toEqual(['id', 'name', 'email']);
|
|
290
294
|
expect(result.current.state.rowSelection).toEqual({ '1': true });
|
|
291
|
-
});
|
|
295
|
+
}, TEST_TIMEOUT);
|
|
292
296
|
|
|
293
297
|
it('provides action creators', () => {
|
|
294
298
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -312,7 +316,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
312
316
|
expect(typeof result.current.actions.setFilterRow).toBe('function');
|
|
313
317
|
expect(typeof result.current.actions.setSearchQuery).toBe('function');
|
|
314
318
|
expect(typeof result.current.actions.resetState).toBe('function');
|
|
315
|
-
});
|
|
319
|
+
}, TEST_TIMEOUT);
|
|
316
320
|
|
|
317
321
|
it('updates state when actions are called', () => {
|
|
318
322
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -322,7 +326,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
322
326
|
});
|
|
323
327
|
|
|
324
328
|
expect(result.current.state.sorting).toEqual([{ id: 'name', desc: false }]);
|
|
325
|
-
});
|
|
329
|
+
}, TEST_TIMEOUT);
|
|
326
330
|
|
|
327
331
|
it('updates column filters', () => {
|
|
328
332
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -332,7 +336,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
332
336
|
});
|
|
333
337
|
|
|
334
338
|
expect(result.current.state.columnFilters).toEqual([{ id: 'name', value: 'John' }]);
|
|
335
|
-
});
|
|
339
|
+
}, TEST_TIMEOUT);
|
|
336
340
|
|
|
337
341
|
it('updates column visibility', () => {
|
|
338
342
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -342,7 +346,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
342
346
|
});
|
|
343
347
|
|
|
344
348
|
expect(result.current.state.columnVisibility).toEqual({ name: false, email: true });
|
|
345
|
-
});
|
|
349
|
+
}, TEST_TIMEOUT);
|
|
346
350
|
|
|
347
351
|
it('updates grouping', () => {
|
|
348
352
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -352,7 +356,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
352
356
|
});
|
|
353
357
|
|
|
354
358
|
expect(result.current.state.grouping).toEqual(['name']);
|
|
355
|
-
});
|
|
359
|
+
}, TEST_TIMEOUT);
|
|
356
360
|
|
|
357
361
|
it('updates expanded state', () => {
|
|
358
362
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -362,7 +366,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
362
366
|
});
|
|
363
367
|
|
|
364
368
|
expect(result.current.state.expanded).toEqual({ '1': true });
|
|
365
|
-
});
|
|
369
|
+
}, TEST_TIMEOUT);
|
|
366
370
|
|
|
367
371
|
it('updates pagination', () => {
|
|
368
372
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -372,7 +376,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
372
376
|
});
|
|
373
377
|
|
|
374
378
|
expect(result.current.state.pagination).toEqual({ pageIndex: 2, pageSize: 25 });
|
|
375
|
-
});
|
|
379
|
+
}, TEST_TIMEOUT);
|
|
376
380
|
|
|
377
381
|
it('updates column order', () => {
|
|
378
382
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -382,7 +386,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
382
386
|
});
|
|
383
387
|
|
|
384
388
|
expect(result.current.state.columnOrder).toEqual(['name', 'id', 'email']);
|
|
385
|
-
});
|
|
389
|
+
}, TEST_TIMEOUT);
|
|
386
390
|
|
|
387
391
|
it('updates row selection', () => {
|
|
388
392
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -392,7 +396,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
392
396
|
});
|
|
393
397
|
|
|
394
398
|
expect(result.current.state.rowSelection).toEqual({ '1': true, '2': false });
|
|
395
|
-
});
|
|
399
|
+
}, TEST_TIMEOUT);
|
|
396
400
|
|
|
397
401
|
it('toggles row selection', () => {
|
|
398
402
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -408,7 +412,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
408
412
|
});
|
|
409
413
|
|
|
410
414
|
expect(result.current.state.rowSelection).toEqual({ '1': false });
|
|
411
|
-
});
|
|
415
|
+
}, TEST_TIMEOUT);
|
|
412
416
|
|
|
413
417
|
it('clears row selection', () => {
|
|
414
418
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -424,7 +428,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
424
428
|
});
|
|
425
429
|
|
|
426
430
|
expect(result.current.state.rowSelection).toEqual({});
|
|
427
|
-
});
|
|
431
|
+
}, TEST_TIMEOUT);
|
|
428
432
|
|
|
429
433
|
it('updates creating state', () => {
|
|
430
434
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -434,7 +438,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
434
438
|
});
|
|
435
439
|
|
|
436
440
|
expect(result.current.state.isCreating).toBe(true);
|
|
437
|
-
});
|
|
441
|
+
}, TEST_TIMEOUT);
|
|
438
442
|
|
|
439
443
|
it('updates creation data', () => {
|
|
440
444
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -445,7 +449,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
445
449
|
});
|
|
446
450
|
|
|
447
451
|
expect(result.current.state.creationData).toEqual(creationData);
|
|
448
|
-
});
|
|
452
|
+
}, TEST_TIMEOUT);
|
|
449
453
|
|
|
450
454
|
it('clears creation data', () => {
|
|
451
455
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -461,7 +465,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
461
465
|
});
|
|
462
466
|
|
|
463
467
|
expect(result.current.state.creationData).toEqual({});
|
|
464
|
-
});
|
|
468
|
+
}, TEST_TIMEOUT);
|
|
465
469
|
|
|
466
470
|
it('updates editing row', () => {
|
|
467
471
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -472,7 +476,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
472
476
|
|
|
473
477
|
expect(result.current.state.editingRowId).toBe('1');
|
|
474
478
|
expect(result.current.state.editingData).toEqual({ name: 'Updated Name' });
|
|
475
|
-
});
|
|
479
|
+
}, TEST_TIMEOUT);
|
|
476
480
|
|
|
477
481
|
it('clears editing state', () => {
|
|
478
482
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -489,7 +493,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
489
493
|
|
|
490
494
|
expect(result.current.state.editingRowId).toBe(null);
|
|
491
495
|
expect(result.current.state.editingData).toEqual({});
|
|
492
|
-
});
|
|
496
|
+
}, TEST_TIMEOUT);
|
|
493
497
|
|
|
494
498
|
it('updates import modal state', () => {
|
|
495
499
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -499,7 +503,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
499
503
|
});
|
|
500
504
|
|
|
501
505
|
expect(result.current.state.showImportModal).toBe(true);
|
|
502
|
-
});
|
|
506
|
+
}, TEST_TIMEOUT);
|
|
503
507
|
|
|
504
508
|
it('updates filter row state', () => {
|
|
505
509
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -509,7 +513,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
509
513
|
});
|
|
510
514
|
|
|
511
515
|
expect(result.current.state.showFilterRow).toBe(true);
|
|
512
|
-
});
|
|
516
|
+
}, TEST_TIMEOUT);
|
|
513
517
|
|
|
514
518
|
it('updates search query', () => {
|
|
515
519
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -519,7 +523,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
519
523
|
});
|
|
520
524
|
|
|
521
525
|
expect(result.current.state.searchQuery).toBe('search term');
|
|
522
|
-
});
|
|
526
|
+
}, TEST_TIMEOUT);
|
|
523
527
|
|
|
524
528
|
it('resets state to initial values', () => {
|
|
525
529
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -546,7 +550,7 @@ describe('[unit] useDataTableState', () => {
|
|
|
546
550
|
expect(result.current.state.columnFilters).toEqual([]);
|
|
547
551
|
expect(result.current.state.rowSelection).toEqual({});
|
|
548
552
|
expect(result.current.state.searchQuery).toBe('');
|
|
549
|
-
});
|
|
553
|
+
}, TEST_TIMEOUT);
|
|
550
554
|
|
|
551
555
|
it('calls onRowSelectionChange callback when provided', () => {
|
|
552
556
|
const onRowSelectionChange = vi.fn();
|
|
@@ -559,20 +563,20 @@ describe('[unit] useDataTableState', () => {
|
|
|
559
563
|
});
|
|
560
564
|
|
|
561
565
|
expect(onRowSelectionChange).toHaveBeenCalledWith({ '1': true });
|
|
562
|
-
});
|
|
566
|
+
}, TEST_TIMEOUT);
|
|
563
567
|
|
|
564
568
|
it('provides computed values', () => {
|
|
565
569
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
566
570
|
|
|
567
571
|
expect(result.current.computed).toBeDefined();
|
|
568
572
|
expect(typeof result.current.computed).toBe('object');
|
|
569
|
-
});
|
|
573
|
+
}, TEST_TIMEOUT);
|
|
570
574
|
|
|
571
575
|
it('provides clearFilters function', () => {
|
|
572
576
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
573
577
|
|
|
574
578
|
expect(typeof result.current.clearFilters).toBe('function');
|
|
575
|
-
});
|
|
579
|
+
}, TEST_TIMEOUT);
|
|
576
580
|
|
|
577
581
|
it('maintains state consistency across multiple actions', () => {
|
|
578
582
|
const { result } = renderHook(() => useDataTableState<TestData>());
|
|
@@ -588,5 +592,5 @@ describe('[unit] useDataTableState', () => {
|
|
|
588
592
|
expect(result.current.state.columnFilters).toEqual([{ id: 'name', value: 'John' }]);
|
|
589
593
|
expect(result.current.state.pagination).toEqual({ pageIndex: 1, pageSize: 25 });
|
|
590
594
|
expect(result.current.state.rowSelection).toEqual({ '1': true, '2': false });
|
|
591
|
-
});
|
|
595
|
+
}, TEST_TIMEOUT);
|
|
592
596
|
});
|
|
@@ -100,14 +100,7 @@ export function useDataTablePermissions<TData extends DataRecord>(
|
|
|
100
100
|
}, 5000);
|
|
101
101
|
|
|
102
102
|
try {
|
|
103
|
-
logger.debug('useDataTablePermissions', 'Starting super admin check', { userId: user?.id });
|
|
104
103
|
const superAdminStatus = await isSuperAdmin(user.id);
|
|
105
|
-
const elapsed = Date.now() - startTime;
|
|
106
|
-
logger.debug('useDataTablePermissions', 'Super admin check completed', {
|
|
107
|
-
userId: user?.id,
|
|
108
|
-
isSuperAdmin: superAdminStatus,
|
|
109
|
-
elapsedMs: elapsed,
|
|
110
|
-
});
|
|
111
104
|
setIsSuperAdminUser(superAdminStatus);
|
|
112
105
|
} catch (error) {
|
|
113
106
|
const elapsed = Date.now() - startTime;
|
|
@@ -159,7 +152,8 @@ export function useDataTablePermissions<TData extends DataRecord>(
|
|
|
159
152
|
const { resolvedScope: rawResolvedScope, isLoading: scopeLoading } = useResolvedScope({
|
|
160
153
|
supabase,
|
|
161
154
|
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
162
|
-
selectedEventId: selectedEvent?.event_id || null
|
|
155
|
+
selectedEventId: selectedEvent?.event_id || null,
|
|
156
|
+
selectedEventOrganisationId: selectedEvent?.organisation_id || null
|
|
163
157
|
});
|
|
164
158
|
|
|
165
159
|
/**
|
|
@@ -277,24 +271,33 @@ export function useDataTablePermissions<TData extends DataRecord>(
|
|
|
277
271
|
// to maintain consistent API with useCan return type
|
|
278
272
|
// React 19 fix: Read isLoading directly from result objects to ensure we get the latest state
|
|
279
273
|
// instead of relying on memoized object references which may not update properly in React 19
|
|
274
|
+
// CRITICAL FIX: When isSuperAdminUser is true, immediately grant all permissions without waiting
|
|
275
|
+
// for useCan results. This ensures super admins can use DataTable features immediately.
|
|
280
276
|
const permissions = useMemo(() => {
|
|
281
277
|
// Helper to create a permission result that bypasses for super admins
|
|
282
278
|
// If super admin check is still loading, we show loading state to prevent premature "Access Denied"
|
|
283
279
|
// Once super admin check completes, if user is super admin, all permissions are true
|
|
284
280
|
// Otherwise, use the normal permission check results
|
|
285
|
-
const createSuperAdminAwarePermission = (result: ReturnType<typeof useCan>) =>
|
|
286
|
-
// If super admin
|
|
287
|
-
//
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
281
|
+
const createSuperAdminAwarePermission = (result: ReturnType<typeof useCan>) => {
|
|
282
|
+
// CRITICAL: If super admin is confirmed, immediately grant permission
|
|
283
|
+
// Don't wait for useCan results - super admins bypass all checks
|
|
284
|
+
if (isSuperAdminUser === true) {
|
|
285
|
+
return {
|
|
286
|
+
can: true,
|
|
287
|
+
isLoading: false,
|
|
288
|
+
error: null,
|
|
289
|
+
refetch: result.refetch,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// For non-super-admins or while checking, use normal permission results
|
|
294
|
+
return {
|
|
295
|
+
can: result.can,
|
|
296
|
+
isLoading: (isSuperAdminUser === null && isCheckingSuperAdmin) || result.isLoading,
|
|
297
|
+
error: result.error,
|
|
298
|
+
refetch: result.refetch,
|
|
299
|
+
};
|
|
300
|
+
};
|
|
298
301
|
|
|
299
302
|
return {
|
|
300
303
|
canRead: createSuperAdminAwarePermission(canReadResult),
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* This replaces the scattered useState calls with a single, predictable state management system.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { useReducer, useCallback, useMemo } from 'react';
|
|
11
|
+
import { useReducer, useCallback, useMemo, useEffect } from 'react';
|
|
12
12
|
import type {
|
|
13
13
|
SortingState,
|
|
14
14
|
ColumnFiltersState,
|
|
@@ -18,6 +18,10 @@ import type {
|
|
|
18
18
|
PaginationState
|
|
19
19
|
} from '@tanstack/react-table';
|
|
20
20
|
import type { DataRecord, CellValue, RowId } from '../types';
|
|
21
|
+
import { useSessionDraft } from '../../../hooks/useSessionDraft';
|
|
22
|
+
import { deriveDataTableKey } from '../../../utils/persistence/keyDerivation';
|
|
23
|
+
import { filterSensitiveFields } from '../../../utils/persistence/sensitiveFieldDetection';
|
|
24
|
+
import { useUnifiedAuth } from '../../../providers/services/UnifiedAuthProvider';
|
|
21
25
|
|
|
22
26
|
// Re-export types for external use
|
|
23
27
|
export type { DataRecord, CellValue, RowId };
|
|
@@ -265,6 +269,11 @@ export interface UseDataTableStateOptions<TData extends DataRecord> {
|
|
|
265
269
|
onRowSelectionChange?: (selection: Record<string, boolean>) => void;
|
|
266
270
|
defaultSorting?: SortingState;
|
|
267
271
|
defaultGrouping?: GroupingState;
|
|
272
|
+
// Persistence options
|
|
273
|
+
rbacPageId?: string;
|
|
274
|
+
title?: string;
|
|
275
|
+
location?: { pathname: string } | null;
|
|
276
|
+
columnFieldNames?: string[]; // Field names for sensitive field filtering
|
|
268
277
|
}
|
|
269
278
|
|
|
270
279
|
export function useDataTableState<TData extends DataRecord>({
|
|
@@ -273,18 +282,78 @@ export function useDataTableState<TData extends DataRecord>({
|
|
|
273
282
|
initialRowSelection = {},
|
|
274
283
|
onRowSelectionChange,
|
|
275
284
|
defaultSorting,
|
|
276
|
-
defaultGrouping
|
|
285
|
+
defaultGrouping,
|
|
286
|
+
rbacPageId,
|
|
287
|
+
title,
|
|
288
|
+
location,
|
|
289
|
+
columnFieldNames = [],
|
|
277
290
|
}: UseDataTableStateOptions<TData> = {}) {
|
|
278
291
|
|
|
279
|
-
|
|
292
|
+
// Call all hooks unconditionally at the top level
|
|
293
|
+
// Hooks must be called in the same order on every render
|
|
294
|
+
// Get user ID for scoping persistence (prevents data leakage between users)
|
|
295
|
+
// If provider is missing, it will throw - errors should be handled by error boundaries
|
|
296
|
+
const auth = useUnifiedAuth();
|
|
297
|
+
const userId = auth.user?.id || null;
|
|
298
|
+
|
|
299
|
+
const persistenceKey = useMemo(() => {
|
|
300
|
+
return deriveDataTableKey(
|
|
301
|
+
{
|
|
302
|
+
rbacPageId,
|
|
303
|
+
title,
|
|
304
|
+
columnIds,
|
|
305
|
+
},
|
|
306
|
+
location,
|
|
307
|
+
userId
|
|
308
|
+
);
|
|
309
|
+
}, [rbacPageId, title, columnIds, location, userId]);
|
|
310
|
+
|
|
311
|
+
// Create initial state
|
|
312
|
+
const baseInitialState = useMemo(() =>
|
|
280
313
|
createInitialState<TData>(initialPageSize, columnIds, defaultSorting, defaultGrouping),
|
|
281
314
|
[initialPageSize, columnIds, defaultSorting, defaultGrouping]
|
|
282
315
|
);
|
|
283
316
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
317
|
+
// Define state subset to persist (excluding sensitive fields from editing/creation data)
|
|
318
|
+
type PersistedState = Omit<DataTableState<TData>, 'editingData' | 'creationData'> & {
|
|
319
|
+
editingData: Partial<Record<string, CellValue>>;
|
|
320
|
+
creationData: Partial<Record<string, CellValue>>;
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// Use session draft for persistence
|
|
324
|
+
const { state: persistedState, setState: setPersistedState, clearDraft } = useSessionDraft<PersistedState>(
|
|
325
|
+
persistenceKey || 'datatable:no-key',
|
|
326
|
+
{
|
|
327
|
+
...baseInitialState,
|
|
328
|
+
rowSelection: initialRowSelection,
|
|
329
|
+
editingData: {},
|
|
330
|
+
creationData: {},
|
|
331
|
+
} as PersistedState,
|
|
332
|
+
{
|
|
333
|
+
enabled: Boolean(persistenceKey),
|
|
334
|
+
debounceMs: 300,
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
// Merge persisted state with initial state (persisted takes precedence)
|
|
339
|
+
const initialState = useMemo(() => {
|
|
340
|
+
if (!persistenceKey || !persistedState) {
|
|
341
|
+
return {
|
|
342
|
+
...baseInitialState,
|
|
343
|
+
rowSelection: initialRowSelection,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Merge persisted state with initial state
|
|
348
|
+
return {
|
|
349
|
+
...baseInitialState,
|
|
350
|
+
...persistedState,
|
|
351
|
+
// Ensure rowSelection is merged properly
|
|
352
|
+
rowSelection: persistedState.rowSelection || initialRowSelection,
|
|
353
|
+
};
|
|
354
|
+
}, [baseInitialState, persistedState, initialRowSelection, persistenceKey]);
|
|
355
|
+
|
|
356
|
+
const [state, dispatch] = useReducer(dataTableReducer<TData>, initialState);
|
|
288
357
|
|
|
289
358
|
// ============================================================================
|
|
290
359
|
// ACTION CREATORS
|
|
@@ -384,10 +453,57 @@ export function useDataTableState<TData extends DataRecord>({
|
|
|
384
453
|
dispatch({ type: 'SET_SEARCH_QUERY', payload: '' });
|
|
385
454
|
}, []);
|
|
386
455
|
|
|
456
|
+
// Persist state changes (debounced)
|
|
457
|
+
useEffect(() => {
|
|
458
|
+
if (!persistenceKey) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Filter sensitive fields from editingData and creationData
|
|
463
|
+
const filteredEditingData = columnFieldNames.length > 0
|
|
464
|
+
? filterSensitiveFields(state.editingData, columnFieldNames)
|
|
465
|
+
: state.editingData;
|
|
466
|
+
|
|
467
|
+
const filteredCreationData = columnFieldNames.length > 0
|
|
468
|
+
? filterSensitiveFields(state.creationData, columnFieldNames)
|
|
469
|
+
: state.creationData;
|
|
470
|
+
|
|
471
|
+
// Persist state subset
|
|
472
|
+
const stateToPersist: PersistedState = {
|
|
473
|
+
sorting: state.sorting,
|
|
474
|
+
columnFilters: state.columnFilters,
|
|
475
|
+
columnVisibility: state.columnVisibility,
|
|
476
|
+
grouping: state.grouping,
|
|
477
|
+
expanded: state.expanded,
|
|
478
|
+
pagination: state.pagination,
|
|
479
|
+
columnOrder: state.columnOrder,
|
|
480
|
+
rowSelection: state.rowSelection,
|
|
481
|
+
isCreating: state.isCreating,
|
|
482
|
+
creationData: filteredCreationData,
|
|
483
|
+
editingRowId: state.editingRowId,
|
|
484
|
+
editingData: filteredEditingData,
|
|
485
|
+
showImportModal: state.showImportModal,
|
|
486
|
+
showFilterRow: state.showFilterRow,
|
|
487
|
+
searchQuery: state.searchQuery,
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
setPersistedState(stateToPersist);
|
|
491
|
+
}, [
|
|
492
|
+
state,
|
|
493
|
+
persistenceKey,
|
|
494
|
+
columnFieldNames,
|
|
495
|
+
setPersistedState,
|
|
496
|
+
]);
|
|
497
|
+
|
|
498
|
+
// Enhanced actions - no need to modify, persistence happens automatically via useEffect
|
|
499
|
+
const enhancedActions = actions;
|
|
500
|
+
|
|
387
501
|
return {
|
|
388
502
|
state,
|
|
389
|
-
actions,
|
|
503
|
+
actions: enhancedActions,
|
|
390
504
|
computed,
|
|
391
|
-
clearFilters
|
|
505
|
+
clearFilters,
|
|
506
|
+
// Expose clearDraft for external use (e.g., on successful submit)
|
|
507
|
+
clearDraft: persistenceKey ? clearDraft : undefined,
|
|
392
508
|
};
|
|
393
509
|
}
|