@jmruthers/pace-core 0.6.9 → 0.6.11
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 +21 -0
- package/audit-tool/00-dependencies.cjs +46 -13
- package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
- package/audit-tool/audits/02-project-structure.cjs +74 -2
- package/audit-tool/audits/03-architecture.cjs +220 -20
- package/audit-tool/audits/04-code-quality.cjs +95 -3
- package/audit-tool/audits/05-styling.cjs +19 -7
- package/audit-tool/audits/06-security-rbac.cjs +214 -25
- package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
- package/audit-tool/audits/08-testing-documentation.cjs +11 -3
- package/audit-tool/audits/09-operations.cjs +19 -7
- package/audit-tool/index.cjs +22 -11
- package/audit-tool/utils/report-utils.cjs +4 -0
- package/cursor-rules/01-pace-core-compliance.mdc +1 -0
- package/cursor-rules/02-project-structure.mdc +3 -26
- package/cursor-rules/03-architecture.mdc +3 -1
- package/cursor-rules/04-code-quality.mdc +1 -0
- package/cursor-rules/05-styling.mdc +120 -8
- package/cursor-rules/06-security-rbac.mdc +126 -2
- package/cursor-rules/07-api-tech-stack.mdc +1 -0
- package/cursor-rules/08-testing-documentation.mdc +1 -0
- package/cursor-rules/09-operations.mdc +1 -0
- package/dist/DataTable-EFYP2QLE.js +16 -0
- package/dist/InactivityServiceProvider-BbxwwDz1.d.ts +308 -0
- package/dist/UnifiedAuthProvider-Bkt_tzdS.d.ts +183 -0
- package/dist/api-BZR2CYXL.js +5 -0
- package/dist/api-result-USV1Czr-.d.ts +51 -0
- package/dist/assets/app-icons/admin_favicon.svg +462 -0
- package/dist/assets/app-icons/base_favicon.svg +85 -0
- package/dist/assets/app-icons/cake_favicon.svg +68 -0
- package/dist/assets/app-icons/core_favicon.svg +256 -0
- package/dist/assets/app-icons/gear_favicon.svg +91 -0
- package/dist/assets/app-icons/medi_favicon.svg +92 -0
- package/dist/assets/app-icons/mint_favicon.svg +83 -0
- package/dist/assets/app-icons/pace_favicon.svg +49 -0
- package/dist/assets/app-icons/pump_favicon.svg +68 -0
- package/dist/assets/app-icons/seed_favicon.svg +91 -0
- package/dist/assets/app-icons/team_favicon.svg +67 -0
- package/dist/assets/app-icons/trac_favicon.svg +112 -0
- package/dist/assets/app-icons/trip_favicon.svg +102 -0
- package/dist/audit-HI2DHUVU.js +4 -0
- package/dist/auth-JvdRVaud.d.ts +49 -0
- package/dist/chunk-2DL2WSOE.js +327 -0
- package/dist/chunk-2OEVOGGR.js +9598 -0
- package/dist/chunk-44CNXN4P.js +15 -0
- package/dist/chunk-4R3T5ENU.js +2943 -0
- package/dist/chunk-7A6IMHH2.js +2321 -0
- package/dist/chunk-BTHN5MKC.js +121 -0
- package/dist/chunk-CU2BU2MQ.js +2 -0
- package/dist/chunk-D6BMFMQZ.js +200 -0
- package/dist/chunk-DDMPHZ3D.js +58 -0
- package/dist/chunk-ENLXB7GP.js +721 -0
- package/dist/chunk-J2KQK6DG.js +2159 -0
- package/dist/chunk-KJXRL3XE.js +6434 -0
- package/dist/chunk-L5LFKKLJ.js +61 -0
- package/dist/chunk-PCSHBLPB.js +811 -0
- package/dist/chunk-QRYSEPHB.js +429 -0
- package/dist/chunk-RMLY6KB5.js +187 -0
- package/dist/chunk-SACF5YSM.js +31 -0
- package/dist/chunk-UZNAFKGW.js +125 -0
- package/dist/chunk-V7FTM2LU.js +1080 -0
- package/dist/chunk-WY6Y7KC3.js +264 -0
- package/dist/chunk-XOJME5T7.js +407 -0
- package/dist/chunk-XPFVT3GN.js +492 -0
- package/dist/chunk-YFTFFJIV.js +529 -0
- package/dist/chunk-YYTWKVHO.js +1334 -0
- package/dist/components.d.ts +12 -89
- package/dist/components.js +23 -55
- package/dist/database.generated-qkdoiVrJ.d.ts +9441 -0
- package/dist/eslint-rules/index.cjs +3 -0
- package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
- package/dist/eslint-rules/rules/05-styling.cjs +507 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +84 -0
- package/dist/event-BfCox3N2.d.ts +265 -0
- package/dist/file-reference-DU1hcawx.d.ts +164 -0
- package/dist/functions-DH45k8ec.d.ts +208 -0
- package/dist/hooks.d.ts +28 -14
- package/dist/hooks.js +90 -56
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +392 -155
- package/dist/index.js +337 -347
- package/dist/pagination-BW1mqywp.d.ts +201 -0
- package/dist/papaparseLoader-WG2UXQ22.js +7 -0
- package/dist/providers.d.ts +29 -14
- package/dist/providers.js +7 -5
- package/dist/rbac/eslint-rules.js +2 -2
- package/dist/rbac/index.d.ts +180 -351
- package/dist/rbac/index.js +13 -11
- package/dist/theming/runtime.d.ts +28 -5
- package/dist/theming/runtime.js +2 -2
- package/dist/timezone-BTWWXKVY.d.ts +696 -0
- package/dist/types-BE2sEHKd.d.ts +55 -0
- package/dist/types-CvOPXWWZ.d.ts +111 -0
- package/dist/types-Dr8sNhER.d.ts +50 -0
- package/dist/types.d.ts +20 -13
- package/dist/types.js +1 -0
- package/dist/usePublicPageContext-B91dGYW1.d.ts +4367 -0
- package/dist/usePublicRouteParams-BgV6VhMi.d.ts +946 -0
- package/dist/utils.d.ts +338 -156
- package/dist/utils.js +78 -60
- package/dist/validation-g5n0hDkh.d.ts +177 -0
- package/docs/api/modules.md +1226 -1094
- package/docs/api-reference/components.md +5 -5
- package/docs/api-reference/rpc-functions.md +12 -3
- package/docs/core-concepts/rbac-system.md +8 -0
- package/docs/getting-started/cursor-rules.md +17 -20
- package/docs/getting-started/dependencies.md +1 -1
- package/docs/getting-started/setup.md +235 -0
- package/docs/implementation-guides/authentication.md +27 -0
- package/docs/implementation-guides/data-tables.md +365 -10
- package/docs/migration/ApiResult-migration.md +25 -0
- package/docs/rbac/RBAC_CONTRACT.md +0 -12
- package/docs/rbac/api-reference.md +33 -31
- package/docs/standards/0-standards-overview.md +50 -15
- package/docs/standards/1-pace-core-compliance-standards.md +62 -57
- package/docs/standards/2-project-structure-standards.md +45 -90
- package/docs/standards/3-architecture-standards.md +41 -1
- package/docs/standards/4-code-quality-standards.md +26 -6
- package/docs/standards/5-styling-standards.md +35 -1
- package/docs/standards/6-security-rbac-standards.md +288 -7
- package/docs/standards/7-api-tech-stack-standards.md +116 -17
- package/docs/standards/8-testing-documentation-standards.md +31 -0
- package/docs/standards/9-operations-standards.md +19 -0
- package/docs/standards/README.md +20 -201
- package/docs/testing/README.md +10 -0
- package/docs/testing/test-setup-for-consumers.md +916 -0
- package/docs/troubleshooting/common-issues.md +17 -1
- package/docs/troubleshooting/organisation-context-setup.md +8 -0
- package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
- package/eslint-config-pace-core.cjs +24 -0
- package/package.json +14 -20
- package/scripts/build-docs.js +180 -0
- package/scripts/setup.cjs +536 -0
- package/scripts/validate.cjs +480 -0
- package/src/__mocks__/lucide-react.ts +0 -2
- package/src/__tests__/helpers/component-test-utils.test.tsx +260 -0
- package/src/__tests__/helpers/optimized-test-setup.test.ts +224 -0
- package/src/__tests__/helpers/supabaseMock.test.ts +273 -0
- package/src/__tests__/helpers/test-providers.test.tsx +99 -0
- package/src/__tests__/helpers/test-providers.tsx +37 -39
- package/src/__tests__/helpers/test-utils.test.tsx +447 -0
- package/src/__tests__/helpers/timer-utils.test.ts +371 -0
- package/src/assets/app-icons/admin_favicon.svg +462 -0
- package/src/assets/app-icons/base_favicon.svg +85 -0
- package/src/assets/app-icons/cake_favicon.svg +68 -0
- package/src/assets/app-icons/core_favicon.svg +256 -0
- package/src/assets/app-icons/gear_favicon.svg +91 -0
- package/src/assets/app-icons/index.test.ts +304 -0
- package/src/assets/app-icons/index.ts +83 -0
- package/src/assets/app-icons/medi_favicon.svg +92 -0
- package/src/assets/app-icons/mint_favicon.svg +83 -0
- package/src/assets/app-icons/pace_favicon.svg +49 -0
- package/src/assets/app-icons/pump_favicon.svg +68 -0
- package/src/assets/app-icons/seed_favicon.svg +91 -0
- package/src/assets/app-icons/team_favicon.svg +67 -0
- package/src/assets/app-icons/trac_favicon.svg +112 -0
- package/src/assets/app-icons/trip_favicon.svg +102 -0
- package/src/components/AddressField/AddressField.test.tsx +379 -4
- package/src/components/AddressField/AddressField.tsx +239 -213
- package/src/components/AddressField/types.ts +2 -2
- package/src/components/Alert/Alert.test.tsx +35 -25
- package/src/components/Alert/Alert.tsx +8 -8
- package/src/components/AppSwitcher/AppSwitcher.test.tsx +1250 -0
- package/src/components/AppSwitcher/AppSwitcher.tsx +315 -0
- package/src/components/Avatar/Avatar.test.tsx +11 -1
- package/src/components/Avatar/Avatar.tsx +3 -2
- package/src/components/Badge/Badge.test.tsx +11 -1
- package/src/components/Button/Button.test.tsx +13 -3
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Calendar/Calendar.test.tsx +523 -131
- package/src/components/Calendar/Calendar.tsx +107 -488
- package/src/components/Card/Card.test.tsx +384 -258
- package/src/components/Card/Card.tsx +19 -10
- package/src/components/Checkbox/Checkbox.test.tsx +58 -174
- package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
- package/src/components/ContextSelector/ContextSelector.test.tsx +360 -0
- package/src/components/ContextSelector/ContextSelector.tsx +66 -280
- package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
- package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
- package/src/components/DataTable/AUDIT_REPORT.md +59 -44
- package/src/components/DataTable/DataTable.comprehensive.test.tsx +759 -0
- package/src/components/DataTable/DataTable.default-state.test.tsx +524 -0
- package/src/components/DataTable/DataTable.export.test.tsx +705 -0
- package/src/components/DataTable/DataTable.grouping-aggregation.test.tsx +658 -0
- package/src/components/DataTable/DataTable.hooks.test.tsx +192 -0
- package/src/components/DataTable/DataTable.select-label-display.test.tsx +485 -0
- package/src/components/DataTable/DataTable.test.tsx +787 -416
- package/src/components/DataTable/DataTable.tsx +14 -14
- package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
- package/src/components/DataTable/DataTableCore.test-setup.ts +221 -0
- package/src/components/DataTable/DataTableCore.test.tsx +970 -0
- package/src/components/DataTable/README.md +155 -0
- package/src/components/DataTable/TESTING.md +101 -0
- package/src/components/DataTable/a11y.basic.test.tsx +788 -0
- package/src/components/DataTable/components/DataTableCore.tsx +126 -894
- package/src/components/DataTable/components/GroupingDropdown.test.tsx +621 -0
- package/src/components/DataTable/components/GroupingDropdown.tsx +2 -3
- package/src/components/DataTable/components/ImportModal.tsx +82 -408
- package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
- package/src/components/DataTable/context/DataTableContext.test.tsx +328 -0
- package/src/components/DataTable/context/DataTableContext.tsx +13 -13
- package/src/components/DataTable/core/ColumnFactory.test.ts +403 -0
- package/src/components/DataTable/core/ColumnFactory.ts +3 -3
- package/src/components/DataTable/hooks/useColumnOrderPersistence.test.ts +516 -0
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +12 -9
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.test.ts +256 -0
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +12 -9
- package/src/components/DataTable/hooks/useDataTableConfiguration.test.ts +297 -0
- package/src/components/DataTable/hooks/useDataTableConfiguration.ts +15 -3
- package/src/components/DataTable/hooks/useDataTableDataPipeline.test.ts +270 -0
- package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
- package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
- package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
- package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
- package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
- package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
- package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
- package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.test.ts +280 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +81 -260
- package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
- package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
- package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
- package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
- package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
- package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
- package/src/components/DataTable/hooks/useDataTableState.test.ts +733 -0
- package/src/components/DataTable/hooks/useDataTableState.ts +161 -114
- package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
- package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
- package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
- package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
- package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
- package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
- package/src/components/DataTable/hooks/useEffectiveColumnOrder.test.ts +183 -0
- package/src/components/DataTable/hooks/useHierarchicalState.test.ts +294 -0
- package/src/components/DataTable/hooks/useImportModalFocus.test.ts +184 -0
- package/src/components/DataTable/hooks/useImportModalFocus.ts +53 -0
- package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
- package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
- package/src/components/DataTable/hooks/useKeyboardNavigation.test.ts +787 -0
- package/src/components/DataTable/hooks/useKeyboardNavigation.ts +311 -271
- package/src/components/DataTable/hooks/usePermissionTracking.test.ts +381 -0
- package/src/components/DataTable/hooks/usePermissionTracking.ts +122 -0
- package/src/components/DataTable/hooks/useServerSideDataEffect.test.ts +258 -0
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +27 -4
- package/src/components/DataTable/hooks/useTableColumns.test.ts +499 -0
- package/src/components/DataTable/hooks/useTableColumns.ts +15 -39
- package/src/components/DataTable/hooks/useTableHandlers.test.ts +461 -0
- package/src/components/DataTable/hooks/useTableHandlers.ts +13 -22
- package/src/components/DataTable/index.ts +28 -5
- package/src/components/DataTable/keyboard.test.tsx +734 -0
- package/src/components/DataTable/mocks/MockRBACProvider.tsx +66 -0
- package/src/components/DataTable/pagination.modes.test.tsx +728 -0
- package/src/components/DataTable/ssr.strict-mode.test.tsx +319 -0
- package/src/components/DataTable/styles.test.ts +379 -0
- package/src/components/DataTable/styles.ts +0 -1
- package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
- package/src/components/DataTable/test-utils/dataFactories.ts +103 -0
- package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
- package/src/components/DataTable/test-utils/sharedTestUtils.ts +419 -0
- package/src/components/DataTable/test-utils.ts +94 -0
- package/src/components/DataTable/types/actions.ts +71 -0
- package/src/components/DataTable/types/base.ts +39 -0
- package/src/components/DataTable/types/columns.ts +125 -0
- package/src/components/DataTable/types/export.ts +32 -0
- package/src/components/DataTable/types/features.ts +81 -0
- package/src/components/DataTable/types/hierarchical.ts +44 -0
- package/src/components/DataTable/types/index.ts +43 -0
- package/src/components/DataTable/types/pagination.ts +85 -0
- package/src/components/DataTable/types/performance.ts +47 -0
- package/src/components/DataTable/types/props.ts +62 -0
- package/src/components/DataTable/types/rbac.ts +45 -0
- package/src/components/DataTable/ui/layout/DataTableCore.test.tsx +1194 -0
- package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
- package/src/components/DataTable/ui/layout/DataTableErrorBoundary.test.tsx +438 -0
- package/src/components/DataTable/ui/layout/DataTableErrorBoundary.tsx +225 -0
- package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
- package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
- package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
- package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
- package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
- package/src/components/DataTable/ui/modals/DataTableModals.tsx +341 -0
- package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
- package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
- package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
- package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
- package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
- package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
- package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
- package/src/components/DataTable/ui/shared/AccessDeniedPage.test.tsx +245 -0
- package/src/components/DataTable/ui/shared/AccessDeniedPage.tsx +159 -0
- package/src/components/DataTable/ui/shared/ActionButtons.test.tsx +921 -0
- package/src/components/DataTable/ui/shared/ActionButtons.tsx +195 -0
- package/src/components/DataTable/ui/shared/ColumnFilter.test.tsx +497 -0
- package/src/components/DataTable/ui/shared/ColumnFilter.tsx +113 -0
- package/src/components/DataTable/ui/shared/PaginationControls.test.tsx +451 -0
- package/src/components/DataTable/ui/shared/PaginationControls.tsx +291 -0
- package/src/components/DataTable/ui/shared/SortIndicator.test.tsx +135 -0
- package/src/components/DataTable/ui/shared/SortIndicator.tsx +50 -0
- package/src/components/DataTable/ui/table/EditFields.test.tsx +526 -0
- package/src/components/DataTable/ui/table/EditFields.tsx +355 -0
- package/src/components/DataTable/ui/table/EditableRow.test.tsx +1003 -0
- package/src/components/DataTable/ui/table/EditableRow.tsx +444 -0
- package/src/components/DataTable/ui/table/EmptyState.test.tsx +360 -0
- package/src/components/DataTable/ui/table/EmptyState.tsx +74 -0
- package/src/components/DataTable/ui/table/FilterRow.test.tsx +416 -0
- package/src/components/DataTable/ui/table/FilterRow.tsx +148 -0
- package/src/components/DataTable/ui/table/LoadingState.test.tsx +77 -0
- package/src/components/DataTable/ui/table/LoadingState.tsx +17 -0
- package/src/components/DataTable/ui/table/RowComponent.test.tsx +1024 -0
- package/src/components/DataTable/ui/table/RowComponent.tsx +429 -0
- package/src/components/DataTable/ui/table/UnifiedTableBody.test.tsx +1273 -0
- package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
- package/src/components/DataTable/ui/table/cellValueUtils.test.ts +453 -0
- package/src/components/DataTable/ui/table/cellValueUtils.ts +40 -0
- package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.test.tsx +551 -0
- package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.tsx +160 -0
- package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.test.tsx +751 -0
- package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.tsx +114 -0
- package/src/components/DataTable/ui/toolbar/DataTableToolbar.test.tsx +629 -0
- package/src/components/DataTable/ui/toolbar/DataTableToolbar.tsx +271 -0
- package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
- package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
- package/src/components/DataTable/utils/a11yUtils.test.ts +548 -0
- package/src/components/DataTable/utils/a11yUtils.ts +1 -1
- package/src/components/DataTable/utils/aggregationUtils.test.ts +288 -0
- package/src/components/DataTable/utils/aggregationUtils.ts +5 -5
- package/src/components/DataTable/utils/columnUtils.test.ts +94 -0
- package/src/components/DataTable/utils/csvParse.test.ts +74 -0
- package/src/components/DataTable/utils/csvParse.ts +65 -0
- package/src/components/DataTable/utils/errorHandling.test.ts +209 -0
- package/src/components/DataTable/utils/errorHandling.ts +3 -1
- package/src/components/DataTable/utils/exportUtils.test.ts +954 -0
- package/src/components/DataTable/utils/exportUtils.ts +1 -1
- package/src/components/DataTable/utils/flexibleImport.test.ts +573 -0
- package/src/components/DataTable/utils/flexibleImport.ts +3 -186
- package/src/components/DataTable/utils/hierarchicalSorting.test.ts +235 -0
- package/src/components/DataTable/utils/hierarchicalSorting.ts +3 -3
- package/src/components/DataTable/utils/hierarchicalUtils.test.ts +586 -0
- package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
- package/src/components/DataTable/utils/importDateParser.ts +114 -0
- package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
- package/src/components/DataTable/utils/importValueParser.ts +91 -0
- package/src/components/DataTable/utils/paginationUtils.test.ts +593 -0
- package/src/components/DataTable/utils/paginationUtils.ts +7 -4
- package/src/components/DataTable/utils/performanceUtils.test.ts +470 -0
- package/src/components/DataTable/utils/performanceUtils.ts +1 -1
- package/src/components/DataTable/utils/rowUtils.test.ts +235 -0
- package/src/components/DataTable/utils/selectFieldUtils.test.ts +271 -0
- package/src/components/DataTable/utils/selectFieldUtils.ts +97 -67
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +18 -25
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +1 -1
- package/src/components/DateTimeField/DateTimeField.test.tsx +3 -16
- package/src/components/DateTimeField/DateTimeField.tsx +1 -1
- package/src/components/Dialog/Dialog.test-utils.ts +49 -0
- package/src/components/Dialog/Dialog.test.tsx +2865 -458
- package/src/components/Dialog/Dialog.tsx +183 -986
- package/src/components/Dialog/dialogLock.test.ts +238 -0
- package/src/components/Dialog/dialogLock.ts +98 -0
- package/src/components/Dialog/index.ts +2 -0
- package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
- package/src/components/Dialog/useDialogDimensions.ts +140 -0
- package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
- package/src/components/Dialog/useDialogLifecycle.ts +135 -0
- package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
- package/src/components/Dialog/useDialogPersistence.ts +357 -0
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +2 -62
- package/src/components/ErrorBoundary/ErrorBoundaryContext.context.ts +17 -0
- package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +2 -45
- package/src/components/ErrorBoundary/ErrorBoundaryContext.types.ts +41 -0
- package/src/components/ErrorBoundary/index.ts +3 -4
- package/src/components/ErrorBoundary/useErrorBoundaryContext.ts +20 -0
- package/src/components/FileDisplay/FileDisplay.test.tsx +479 -247
- package/src/components/FileDisplay/FileDisplay.tsx +29 -659
- package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
- package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
- package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
- package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
- package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
- package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
- package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
- package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
- package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
- package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
- package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
- package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
- package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
- package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
- package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
- package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
- package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
- package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
- package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
- package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
- package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
- package/src/components/FileDisplay/fallbackUtils.ts +44 -0
- package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
- package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
- package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
- package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
- package/src/components/FileDisplay/index.tsx +1 -1
- package/src/components/FileDisplay/useFileDisplay.test.ts +538 -0
- package/src/components/FileDisplay/useFileDisplay.ts +515 -0
- package/src/components/FileDisplay/useFileDisplay.unit.test.ts +1438 -0
- package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
- package/src/components/FileDisplay/usePublicFileDisplay.test.ts +729 -0
- package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
- package/src/components/FileUpload/FileUpload.test.tsx +69 -27
- package/src/components/FileUpload/FileUpload.tsx +112 -527
- package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
- package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
- package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
- package/src/components/FileUpload/index.tsx +1 -1
- package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
- package/src/components/FileUpload/useFileUploadManager.ts +454 -0
- package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
- package/src/components/FileUpload/useResolvedAppId.ts +77 -0
- package/src/components/Footer/Footer.test.tsx +15 -382
- package/src/components/Footer/Footer.tsx +8 -125
- package/src/components/Form/Form.test.tsx +425 -88
- package/src/components/Form/Form.tsx +91 -299
- package/src/components/Form/useFormPersistence.ts +257 -0
- package/src/components/Header/Header.test.tsx +653 -163
- package/src/components/Header/Header.tsx +62 -44
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +35 -76
- package/src/components/Input/Input.test.tsx +34 -120
- package/src/components/Input/Input.tsx +1 -1
- package/src/components/Label/Label.test.tsx +46 -45
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +8 -11
- package/src/components/LoginForm/LoginForm.test.tsx +0 -1
- package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +2422 -102
- package/src/components/NavigationMenu/NavigationMenu.tsx +62 -362
- package/src/components/NavigationMenu/index.ts +6 -1
- package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
- package/src/components/NavigationMenu/useNavigationFiltering.test.ts +1949 -0
- package/src/components/NavigationMenu/useNavigationFiltering.ts +199 -308
- package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
- package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +1322 -0
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +50 -49
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +81 -38
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +103 -85
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +774 -44
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +282 -764
- package/src/components/PaceAppLayout/README.md +0 -9
- package/src/components/PaceAppLayout/test-setup.tsx +15 -9
- package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
- package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
- package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +782 -20
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +33 -125
- package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
- package/src/components/PasswordChange/PasswordChangeForm.test.tsx +1 -1
- package/src/components/Progress/Progress.test.tsx +127 -1
- package/src/components/Progress/Progress.tsx +1 -2
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +1196 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -217
- package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
- package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
- package/src/components/PublicLayout/PublicLayout.test.tsx +1640 -38
- package/src/components/PublicLayout/PublicPageContext.ts +28 -0
- package/src/components/PublicLayout/PublicPageLayout.tsx +134 -75
- package/src/components/PublicLayout/PublicPageProvider.tsx +7 -42
- package/src/components/PublicLayout/usePublicPageContext.ts +36 -0
- package/src/components/Select/Select.test.tsx +45 -8
- package/src/components/Select/Select.tsx +57 -40
- package/src/components/Select/context.test.tsx +56 -0
- package/src/components/Select/text.test.tsx +104 -0
- package/src/components/Select/text.ts +26 -0
- package/src/components/Select/types.ts +3 -0
- package/src/components/Select/useSelectEvents.test.ts +279 -0
- package/src/components/Select/useSelectEvents.ts +87 -0
- package/src/components/Select/useSelectSearch.test.tsx +295 -0
- package/src/components/Select/useSelectSearch.ts +91 -0
- package/src/components/Select/useSelectState.test.ts +268 -0
- package/src/components/Select/useSelectState.ts +104 -0
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +28 -112
- package/src/components/Switch/Switch.test.tsx +57 -153
- package/src/components/Table/Table.test.tsx +395 -317
- package/src/components/Tabs/Tabs.test.tsx +270 -0
- package/src/components/Tabs/Tabs.tsx +4 -4
- package/src/components/Textarea/Textarea.test.tsx +11 -38
- package/src/components/Toast/Toast.test.tsx +425 -496
- package/src/components/Tooltip/Tooltip.test.tsx +4 -21
- package/src/components/UserMenu/UserMenu.test.tsx +1 -21
- package/src/components/UserMenu/UserMenu.tsx +0 -1
- package/src/components/index.test.ts +346 -0
- package/src/components/index.ts +12 -1
- package/src/constants/performance.test.ts +91 -0
- package/src/hooks/ServiceHooks.test.tsx +725 -0
- package/src/hooks/hooks.integration.test.tsx +608 -0
- package/src/hooks/index.ts +18 -3
- package/src/hooks/index.unit.test.ts +220 -0
- package/src/hooks/public/usePublicEvent.test.ts +304 -0
- package/src/hooks/public/usePublicEvent.ts +11 -11
- package/src/hooks/public/usePublicEventLogo.test.ts +655 -120
- package/src/hooks/public/usePublicEventLogo.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.test.ts +595 -0
- package/src/hooks/public/usePublicRouteParams.ts +2 -2
- package/src/hooks/services/useAuth.ts +9 -7
- package/src/hooks/services/useAuthService.ts +1 -1
- package/src/hooks/services/useEventService.ts +1 -1
- package/src/hooks/useAccessibleApps.test.ts +400 -0
- package/src/hooks/useAccessibleApps.ts +264 -0
- package/src/hooks/useAddressAutocomplete.test.ts +170 -47
- package/src/hooks/useAddressAutocomplete.ts +109 -81
- package/src/hooks/useApiFetch.unit.test.ts +111 -0
- package/src/hooks/useAppConfig.ts +13 -3
- package/src/hooks/useAppConfig.unit.test.ts +712 -0
- package/src/hooks/useComponentPerformance.unit.test.tsx +314 -0
- package/src/hooks/useDataTablePerformance.ts +111 -130
- package/src/hooks/useDataTablePerformance.unit.test.ts +720 -0
- package/src/hooks/useDataTableState.test.ts +170 -0
- package/src/hooks/useDataTableState.ts +5 -5
- package/src/hooks/useDebounce.unit.test.ts +157 -0
- package/src/hooks/useEventTheme.test.ts +70 -18
- package/src/hooks/useEventTheme.ts +50 -22
- package/src/hooks/useEvents.ts +49 -2
- package/src/hooks/useEvents.unit.test.ts +227 -0
- package/src/hooks/useFileReference.test.ts +388 -107
- package/src/hooks/useFileReference.ts +184 -179
- package/src/hooks/useFileUrl.ts +1 -1
- package/src/hooks/useFileUrl.unit.test.ts +686 -0
- package/src/hooks/useFileUrlCache.test.ts +319 -0
- package/src/hooks/useFileUrlCache.ts +5 -2
- package/src/hooks/useFocusManagement.unit.test.ts +604 -0
- package/src/hooks/useFocusTrap.unit.test.tsx +613 -0
- package/src/hooks/useFormDialog.test.ts +307 -0
- package/src/hooks/useFormDialog.ts +2 -2
- package/src/hooks/useInactivityTracker.ts +141 -134
- package/src/hooks/useInactivityTracker.unit.test.ts +446 -0
- package/src/hooks/useIsMobile.unit.test.ts +317 -0
- package/src/hooks/useIsPrint.ts +62 -0
- package/src/hooks/useIsPrint.unit.test.ts +545 -0
- package/src/hooks/useKeyboardShortcuts.unit.test.ts +907 -0
- package/src/hooks/useOrganisationPermissions.test.ts +1 -2
- package/src/hooks/useOrganisationPermissions.ts +1 -4
- package/src/hooks/useOrganisationPermissions.unit.test.tsx +293 -0
- package/src/hooks/useOrganisationSecurity.test.ts +4 -33
- package/src/hooks/useOrganisationSecurity.ts +192 -203
- package/src/hooks/useOrganisationSecurity.unit.test.tsx +959 -0
- package/src/hooks/useOrganisations.ts +1 -1
- package/src/hooks/useOrganisations.unit.test.ts +369 -0
- package/src/hooks/usePerformanceMonitor.ts +1 -1
- package/src/hooks/usePerformanceMonitor.unit.test.ts +693 -0
- package/src/hooks/usePermissionCache.test.ts +298 -329
- package/src/hooks/usePermissionCache.ts +277 -276
- package/src/hooks/usePreventTabReload.test.ts +307 -0
- package/src/hooks/usePublicEvent.simple.test.ts +794 -0
- package/src/hooks/usePublicEvent.test.ts +670 -0
- package/src/hooks/usePublicEvent.unit.test.ts +638 -0
- package/src/hooks/usePublicFileDisplay.test.ts +948 -0
- package/src/hooks/usePublicRouteParams.unit.test.ts +442 -0
- package/src/hooks/useQueryCache.test.ts +391 -0
- package/src/hooks/useQueryCache.ts +7 -9
- package/src/hooks/useRBAC.unit.test.ts +253 -0
- package/src/hooks/useSessionDraft.test.ts +556 -0
- package/src/hooks/useSessionDraft.ts +14 -11
- package/src/hooks/useSessionRestoration.ts +1 -1
- package/src/hooks/useSessionRestoration.unit.test.tsx +381 -0
- package/src/hooks/useStorage.ts +94 -54
- package/src/hooks/useStorage.unit.test.ts +684 -0
- package/src/hooks/useToast.test.ts +413 -0
- package/src/hooks/useToast.ts +2 -2
- package/src/hooks/useToast.unit.test.tsx +481 -0
- package/src/hooks/useZodForm.ts +3 -3
- package/src/hooks/useZodForm.unit.test.tsx +191 -0
- package/src/icons/index.test.ts +133 -0
- package/src/icons/index.ts +3 -1
- package/src/index.test.ts +528 -0
- package/src/index.ts +56 -9
- package/src/providers/AuthProvider.test.tsx +218 -0
- package/src/providers/EventProvider.test.tsx +487 -0
- package/src/providers/InactivityProvider.test-helper.tsx +40 -0
- package/src/providers/InactivityProvider.test.tsx +421 -0
- package/src/providers/ProviderLifecycle.test.tsx +308 -0
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +7 -12
- package/src/providers/UnifiedAuthProvider.test.tsx +503 -0
- package/src/providers/index.test.ts +138 -0
- package/src/providers/services/AuthServiceContext.ts +27 -0
- package/src/providers/services/AuthServiceProvider.integration.test.tsx +229 -0
- package/src/providers/services/AuthServiceProvider.test.tsx +638 -0
- package/src/providers/services/AuthServiceProvider.tsx +81 -20
- package/src/providers/services/EventServiceContext.ts +25 -0
- package/src/providers/services/EventServiceProvider.test.tsx +839 -0
- package/src/providers/services/EventServiceProvider.tsx +11 -20
- package/src/providers/services/InactivityServiceContext.ts +25 -0
- package/src/providers/services/InactivityServiceProvider.test.tsx +662 -0
- package/src/providers/services/InactivityServiceProvider.tsx +7 -17
- package/src/providers/services/OrganisationServiceContext.ts +25 -0
- package/src/providers/services/OrganisationServiceProvider.test.tsx +440 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +7 -17
- package/src/providers/services/UnifiedAuthContext.ts +102 -0
- package/src/providers/services/UnifiedAuthProvider.advanced.test.tsx +434 -0
- package/src/providers/services/UnifiedAuthProvider.appId.test.tsx +408 -0
- package/src/providers/services/UnifiedAuthProvider.integration.test.tsx +304 -0
- package/src/providers/services/UnifiedAuthProvider.test.tsx +212 -0
- package/src/providers/services/UnifiedAuthProvider.tsx +147 -497
- package/src/providers/services/contexts.test.tsx +281 -0
- package/src/providers/services/useUnifiedAuth.test.tsx +251 -0
- package/src/providers/services/useUnifiedAuth.ts +29 -0
- package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
- package/src/providers/useInactivity.test-helper.ts +27 -0
- package/src/rbac/README.md +5 -5
- package/src/rbac/adapters.comprehensive.test.tsx +429 -0
- package/src/rbac/adapters.test.tsx +654 -0
- package/src/rbac/adapters.tsx +53 -38
- package/src/rbac/api.test.ts +986 -259
- package/src/rbac/api.ts +260 -216
- package/src/rbac/audit-batched.test.ts +550 -0
- package/src/rbac/audit-batched.ts +5 -4
- package/src/rbac/audit.test.ts +225 -28
- package/src/rbac/audit.ts +26 -18
- package/src/rbac/auth-rbac-security.integration.test.tsx +300 -0
- package/src/rbac/auth-rbac.e2e.test.tsx +510 -0
- package/src/rbac/cache-invalidation.test.ts +715 -0
- package/src/rbac/cache-invalidation.ts +18 -15
- package/src/rbac/cache.test.ts +123 -63
- package/src/rbac/cache.ts +3 -4
- package/src/rbac/components/AccessDenied.test.tsx +324 -0
- package/src/rbac/components/AccessDenied.tsx +20 -18
- package/src/rbac/components/NavigationGuard.test.tsx +1148 -0
- package/src/rbac/components/NavigationGuard.tsx +10 -8
- package/src/rbac/components/PagePermissionGuard.guard.test.tsx +236 -0
- package/src/rbac/components/PagePermissionGuard.performance.test.tsx +252 -0
- package/src/rbac/components/PagePermissionGuard.race-condition.test.tsx +243 -0
- package/src/rbac/components/PagePermissionGuard.test.tsx +1430 -0
- package/src/rbac/components/PagePermissionGuard.tsx +188 -381
- package/src/rbac/components/PagePermissionGuard.verification.test.tsx +185 -0
- package/src/rbac/config.test.ts +131 -48
- package/src/rbac/config.ts +69 -26
- package/src/rbac/docs/event-based-apps.md +26 -13
- package/src/rbac/engine.comprehensive.test.ts +808 -0
- package/src/rbac/engine.test.ts +974 -130
- package/src/rbac/engine.ts +53 -13
- package/src/rbac/errors.test.ts +99 -87
- package/src/rbac/errors.ts +89 -55
- package/src/rbac/eslint-rules.js +2 -2
- package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
- package/src/rbac/hooks/permissions/useAccessLevel.test.ts +622 -0
- package/src/rbac/hooks/permissions/useAccessLevel.ts +23 -14
- package/src/rbac/hooks/permissions/useCan.test.ts +798 -0
- package/src/rbac/hooks/permissions/useCan.ts +173 -253
- package/src/rbac/hooks/permissions/useMultiplePermissions.test.ts +843 -0
- package/src/rbac/hooks/permissions/useMultiplePermissions.ts +63 -10
- package/src/rbac/hooks/permissions/usePermissions.test.ts +543 -0
- package/src/rbac/hooks/permissions/usePermissions.ts +50 -78
- package/src/rbac/hooks/useCan.test.ts +348 -32
- package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
- package/src/rbac/hooks/usePageGuardScope.ts +117 -0
- package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
- package/src/rbac/hooks/usePermissions.integration.test.ts +427 -0
- package/src/rbac/hooks/usePermissions.stability.test.ts +268 -0
- package/src/rbac/hooks/usePermissions.test.ts +459 -33
- package/src/rbac/hooks/usePermissions.ts +5 -7
- package/src/rbac/hooks/useRBAC.test.ts +1784 -21
- package/src/rbac/hooks/useRBAC.ts +148 -88
- package/src/rbac/hooks/useResolvedScope.test.ts +442 -5
- package/src/rbac/hooks/useResolvedScope.ts +4 -1
- package/src/rbac/hooks/useResourcePermissions.test.ts +561 -24
- package/src/rbac/hooks/useResourcePermissions.ts +76 -140
- package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
- package/src/rbac/hooks/useRoleManagement.test.ts +634 -61
- package/src/rbac/hooks/useRoleManagement.ts +158 -586
- package/src/rbac/hooks/useSecureSupabase.test.ts +1179 -0
- package/src/rbac/hooks/useSecureSupabase.ts +21 -14
- package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
- package/src/rbac/index.test.ts +107 -0
- package/src/rbac/index.ts +32 -32
- package/src/rbac/performance.test.ts +451 -0
- package/src/rbac/permissions.test.ts +149 -68
- package/src/rbac/permissions.ts +0 -3
- package/src/rbac/rbac-core.test.tsx +276 -0
- package/src/rbac/rbac-engine-core-logic.test.ts +387 -0
- package/src/rbac/rbac-engine-simplified.test.ts +252 -0
- package/src/rbac/rbac-functions.test.ts +703 -0
- package/src/rbac/rbac-integration.test.ts +523 -0
- package/src/rbac/rbac-role-isolation.test.ts +456 -0
- package/src/rbac/request-deduplication.test.ts +352 -0
- package/src/rbac/request-deduplication.ts +5 -4
- package/src/rbac/scenarios.user-role.test.tsx +271 -0
- package/src/rbac/secureClient.test.ts +499 -115
- package/src/rbac/secureClient.ts +54 -28
- package/src/rbac/security.test.ts +448 -44
- package/src/rbac/security.ts +7 -6
- package/src/rbac/types/roleManagement.ts +66 -0
- package/src/rbac/types.test.ts +236 -0
- package/src/rbac/types.ts +7 -5
- package/src/rbac/utils/clientSecurity.test.ts +192 -0
- package/src/rbac/utils/clientSecurity.ts +6 -4
- package/src/rbac/utils/contextValidator.test.ts +126 -0
- package/src/rbac/utils/contextValidator.ts +6 -3
- package/src/rbac/utils/deep-equal.test.ts +76 -0
- package/src/rbac/utils/eventContext.test.ts +401 -0
- package/src/rbac/utils/eventContext.ts +38 -34
- package/src/rbac/utils/fetchPermissionMap.ts +13 -0
- package/src/rbac/utils/permissionMapHelpers.ts +34 -0
- package/src/rbac/utils/roleManagementRpc.ts +303 -0
- package/src/services/AuthService.edge-cases.test.ts +746 -0
- package/src/services/AuthService.restoreSession.test.ts +59 -0
- package/src/services/AuthService.test.ts +1362 -0
- package/src/services/AuthService.ts +197 -216
- package/src/services/BaseService.edge-cases.test.ts +506 -0
- package/src/services/BaseService.test.ts +363 -0
- package/src/services/EventService.edge-cases.test.ts +636 -0
- package/src/services/EventService.eventColours.test.ts +64 -0
- package/src/services/EventService.test.ts +1250 -0
- package/src/services/EventService.ts +244 -315
- package/src/services/InactivityService.edge-cases.test.ts +492 -0
- package/src/services/InactivityService.lifecycle.test.ts +406 -0
- package/src/services/InactivityService.test.ts +829 -0
- package/src/services/InactivityService.ts +172 -213
- package/src/services/OrganisationService.edge-cases.test.ts +633 -0
- package/src/services/OrganisationService.pagination.test.ts +409 -0
- package/src/services/OrganisationService.test.ts +1579 -0
- package/src/services/OrganisationService.ts +186 -257
- package/src/services/base/BaseService.test.ts +214 -0
- package/src/services/interfaces/IAuthService.test.ts +184 -0
- package/src/services/interfaces/IAuthService.ts +10 -9
- package/src/services/interfaces/IEventService.test.ts +176 -0
- package/src/services/interfaces/IInactivityService.test.ts +183 -0
- package/src/services/interfaces/IOrganisationService.test.ts +207 -0
- package/src/services/interfaces/IOrganisationService.ts +0 -1
- package/src/styles/core.css +244 -12
- package/src/theming/parseEventColours.test.ts +321 -0
- package/src/theming/parseEventColours.ts +18 -9
- package/src/theming/runtime.test.ts +495 -0
- package/src/theming/runtime.ts +72 -7
- package/src/types/api-result.ts +53 -0
- package/src/types/auth.ts +0 -1
- package/src/types/core.test.ts +397 -0
- package/src/types/database-generated.test.ts +78 -0
- package/src/types/database.generated.ts +45 -10
- package/src/types/event.ts +39 -19
- package/src/types/file-reference.test.ts +351 -0
- package/src/types/file-reference.ts +37 -12
- package/src/types/guards.test.ts +246 -0
- package/src/types/index.test.ts +265 -0
- package/src/types/index.ts +3 -0
- package/src/types/organisation.roles.test.ts +55 -0
- package/src/types/organisation.test.ts +1105 -0
- package/src/types/organisation.ts +15 -15
- package/src/types/rpc-responses.ts +33 -0
- package/src/types/supabase.ts +14 -6
- package/src/types/theme.test.ts +830 -0
- package/src/types/type-validation.test.ts +526 -0
- package/src/types/validation.test.ts +729 -0
- package/src/types/vitest-globals.d.ts +1 -1
- package/src/utils/app/appConfig.test.ts +235 -0
- package/src/utils/app/appIdResolver.test.ts +252 -57
- package/src/utils/app/appIdResolver.ts +31 -20
- package/src/utils/app/appNameResolver.test.ts +18 -10
- package/src/utils/app/appNameResolver.ts +11 -9
- package/src/utils/app/appPortMap.test.ts +125 -0
- package/src/utils/app/appPortMap.ts +51 -0
- package/src/utils/app/buildAppUrl.test.ts +273 -0
- package/src/utils/app/buildAppUrl.ts +114 -0
- package/src/utils/appConfig.unit.test.ts +55 -0
- package/src/utils/audit/audit.test.ts +354 -39
- package/src/utils/audit.unit.test.ts +69 -0
- package/src/utils/auth-utils.unit.test.ts +69 -0
- package/src/utils/bundleAnalysis.unit.test.ts +326 -0
- package/src/utils/cn.unit.test.ts +34 -0
- package/src/utils/context/organisationContext.test.ts +115 -95
- package/src/utils/context/organisationContext.ts +32 -43
- package/src/utils/context/sessionTracking.test.ts +354 -0
- package/src/utils/core/cn.test.ts +66 -0
- package/src/utils/core/debugLogger.test.ts +113 -0
- package/src/utils/core/debugLogger.ts +15 -8
- package/src/utils/core/logger.test.ts +217 -0
- package/src/utils/core/logger.ts +20 -16
- package/src/utils/core/mergeRefs.ts +24 -0
- package/src/utils/debugLogger.test.ts +417 -0
- package/src/utils/device/deviceFingerprint.test.ts +8 -5
- package/src/utils/device/deviceFingerprint.ts +3 -3
- package/src/utils/deviceFingerprint.unit.test.ts +818 -0
- package/src/utils/dynamic/createLazyComponent.tsx +46 -0
- package/src/utils/dynamic/dynamicUtils.test.ts +185 -0
- package/src/utils/dynamic/dynamicUtils.ts +6 -6
- package/src/utils/dynamic/lazyLoad.test.tsx +156 -0
- package/src/utils/dynamic/lazyLoad.tsx +8 -36
- package/src/utils/dynamic/papaparseLoader.ts +7 -0
- package/src/utils/dynamicUtils.unit.test.ts +331 -0
- package/src/utils/file-reference/file-reference.test.ts +1238 -0
- package/src/utils/file-reference/index.ts +330 -348
- package/src/utils/formatDate.unit.test.ts +109 -0
- package/src/utils/formatting/formatDate.test.ts +22 -148
- package/src/utils/formatting/formatDateTime.test.ts +41 -119
- package/src/utils/formatting/formatDateTimeTimezone.test.ts +41 -85
- package/src/utils/formatting/formatNumber.test.ts +259 -0
- package/src/utils/formatting/formatTime.test.ts +36 -128
- package/src/utils/formatting/formatting.ts +1 -1
- package/src/utils/formatting.unit.test.ts +99 -0
- package/src/utils/google-places/googlePlacesUtils.test.ts +127 -36
- package/src/utils/google-places/googlePlacesUtils.ts +67 -86
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +68 -8
- package/src/utils/google-places/loadGoogleMapsScript.ts +140 -118
- package/src/utils/index.ts +52 -11
- package/src/utils/index.unit.test.ts +251 -0
- package/src/utils/lazyLoad.unit.test.tsx +319 -0
- package/src/utils/location/location.test.ts +19 -116
- package/src/utils/logger.unit.test.ts +398 -0
- package/src/utils/organisationContext.unit.test.ts +180 -0
- package/src/utils/performance/bundleAnalysis.test.ts +148 -0
- package/src/utils/performance/bundleAnalysis.ts +16 -22
- package/src/utils/performance/performanceBenchmark.test.ts +251 -0
- package/src/utils/performance/performanceBenchmark.ts +12 -4
- package/src/utils/performance/performanceBudgets.test.ts +241 -0
- package/src/utils/performance/performanceBudgets.ts +9 -6
- package/src/utils/performanceBenchmark.test.ts +174 -0
- package/src/utils/performanceBudgets.unit.test.ts +288 -0
- package/src/utils/permissionTypes.unit.test.ts +250 -0
- package/src/utils/permissionUtils.unit.test.ts +362 -0
- package/src/utils/permissions/permissionTypes.test.ts +149 -0
- package/src/utils/permissions/permissionUtils.test.ts +20 -42
- package/src/utils/persistence/keyDerivation.test.ts +306 -0
- package/src/utils/persistence/sensitiveFieldDetection.test.ts +271 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +2 -2
- package/src/utils/request-deduplication.test.ts +349 -0
- package/src/utils/request-deduplication.ts +6 -4
- package/src/utils/sanitization.unit.test.ts +346 -0
- package/src/utils/schemaUtils.unit.test.ts +441 -0
- package/src/utils/secureDataAccess.unit.test.ts +334 -0
- package/src/utils/secureErrors.unit.test.ts +390 -0
- package/src/utils/secureStorage.unit.test.ts +289 -0
- package/src/utils/security/auth-utils.ts +38 -27
- package/src/utils/security/secureDataAccess.test.ts +22 -191
- package/src/utils/security/secureDataAccess.ts +241 -281
- package/src/utils/security/secureErrors.test.ts +163 -0
- package/src/utils/security/secureStorage.test.ts +156 -0
- package/src/utils/security/secureStorage.ts +1 -1
- package/src/utils/security/security.test.ts +212 -0
- package/src/utils/security/security.ts +15 -18
- package/src/utils/security/securityMonitor.test.ts +90 -0
- package/src/utils/security/securityMonitor.ts +1 -1
- package/src/utils/security.unit.test.ts +155 -0
- package/src/utils/securityMonitor.unit.test.ts +276 -0
- package/src/utils/sessionTracking.unit.test.ts +218 -0
- package/src/utils/storage/config.unit.test.ts +239 -0
- package/src/utils/storage/helpers.test.ts +769 -456
- package/src/utils/storage/helpers.ts +174 -253
- package/src/utils/storage/index.unit.test.ts +68 -0
- package/src/utils/storage/storageUtils.ts +32 -0
- package/src/utils/storage/types.ts +9 -2
- package/src/utils/supabase/createBaseClient.test.ts +201 -0
- package/src/utils/supabase/createBaseClient.ts +2 -1
- package/src/utils/timezone/timezone.test.ts +26 -44
- package/src/utils/timezone.test.ts +345 -0
- package/src/utils/validation/common.test.ts +115 -0
- package/src/utils/validation/csrf.test.ts +198 -0
- package/src/utils/validation/csrf.ts +42 -41
- package/src/utils/validation/htmlSanitization.ts +27 -31
- package/src/utils/validation/htmlSanitization.unit.test.ts +618 -0
- package/src/utils/validation/passwordSchema.test.ts +164 -0
- package/src/utils/validation/schema.test.ts +127 -0
- package/src/utils/validation/schema.ts +6 -3
- package/src/utils/validation/sqlInjectionProtection.test.ts +165 -0
- package/src/utils/validation/sqlInjectionProtection.ts +2 -2
- package/src/utils/validation/user.test.ts +173 -0
- package/src/utils/validation/validation.test.ts +197 -0
- package/src/utils/validation/validationUtils.test.ts +294 -0
- package/src/utils/validation.unit.test.ts +307 -0
- package/src/utils/validationUtils.unit.test.ts +558 -0
- package/src/vite-env.d.ts +6 -0
- package/dist/AuthService-DmfO5rGS.d.ts +0 -524
- package/dist/DataTable-DRUIgtUH.d.ts +0 -166
- package/dist/DataTable-SOAFXIWY.js +0 -15
- package/dist/PublicPageProvider-CIGSujI2.d.ts +0 -4147
- package/dist/UnifiedAuthProvider-7SNDOWYD.js +0 -7
- package/dist/UnifiedAuthProvider-CKvHP1MK.d.ts +0 -139
- package/dist/api-7P7DI652.js +0 -4
- package/dist/audit-MYQXYZFU.js +0 -3
- package/dist/auth-BZOJqrdd.d.ts +0 -49
- package/dist/chunk-4DDCYDQ3.js +0 -544
- package/dist/chunk-5HNSDQWH.js +0 -5046
- package/dist/chunk-5W2A3DRC.js +0 -164
- package/dist/chunk-6GLLNA6U.js +0 -31
- package/dist/chunk-7ILTDCL2.js +0 -80
- package/dist/chunk-A3W6LW53.js +0 -70
- package/dist/chunk-AHU7G2R5.js +0 -423
- package/dist/chunk-C7ZQ5O4C.js +0 -481
- package/dist/chunk-EF2UGZWY.js +0 -611
- package/dist/chunk-FEJLJNWA.js +0 -181
- package/dist/chunk-FYHN4DD5.js +0 -415
- package/dist/chunk-GS5672WG.js +0 -2003
- package/dist/chunk-HF6O3O37.js +0 -187
- package/dist/chunk-J2U36LHD.js +0 -8517
- package/dist/chunk-LX6U42O3.js +0 -2177
- package/dist/chunk-MPBLMWVR.js +0 -2161
- package/dist/chunk-OJ4SKRSV.js +0 -105
- package/dist/chunk-S6ZQKDY6.js +0 -62
- package/dist/chunk-S7DKJPLT.js +0 -699
- package/dist/chunk-T5CVK4R3.js +0 -2816
- package/dist/chunk-TTRFSOKR.js +0 -121
- package/dist/chunk-Z2FNRKF3.js +0 -994
- package/dist/database.generated-DT8JTZiP.d.ts +0 -9406
- package/dist/event-CW5YB_2p.d.ts +0 -239
- package/dist/file-reference-BavO2eQj.d.ts +0 -148
- package/dist/functions-lBy5L2ry.d.ts +0 -208
- package/dist/timezone-0AyangqX.d.ts +0 -697
- package/dist/types-BeoeWV5I.d.ts +0 -110
- package/dist/types-DXstZpNI.d.ts +0 -614
- package/dist/types-t9H8qKRw.d.ts +0 -55
- package/dist/usePublicRouteParams-DQLrDqDb.d.ts +0 -876
- package/dist/useToast-AyaT-x7p.d.ts +0 -68
- package/dist/validation-643vUDZW.d.ts +0 -177
- package/scripts/build-docs-incremental.js +0 -179
- package/scripts/eslint-audit.cjs +0 -123
- package/scripts/generate-docs.js +0 -157
- package/scripts/install-cursor-rules.cjs +0 -255
- package/scripts/install-eslint-config.cjs +0 -349
- package/scripts/setup-build-cache.js +0 -73
- package/scripts/validate-pre-publish.js +0 -145
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +0 -260
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +0 -224
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +0 -273
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +0 -99
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +0 -448
- package/src/__tests__/helpers/__tests__/timer-utils.test.ts +0 -371
- package/src/__tests__/hooks/usePermissions.test.ts +0 -268
- package/src/__tests__/integration/UserProfile.test.tsx +0 -124
- package/src/__tests__/public-recipe-view.test.ts +0 -228
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +0 -220
- package/src/__tests__/rls-policies.test.ts +0 -471
- package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +0 -759
- package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +0 -524
- package/src/components/DataTable/__tests__/DataTable.export.test.tsx +0 -705
- package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +0 -658
- package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +0 -192
- package/src/components/DataTable/__tests__/DataTable.select-label-display.test.tsx +0 -483
- package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
- package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +0 -220
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +0 -1474
- package/src/components/DataTable/__tests__/README.md +0 -145
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +0 -788
- package/src/components/DataTable/__tests__/keyboard.test.tsx +0 -756
- package/src/components/DataTable/__tests__/mocks/MockRBACProvider.tsx +0 -66
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +0 -730
- package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +0 -325
- package/src/components/DataTable/__tests__/styles.test.ts +0 -382
- package/src/components/DataTable/__tests__/test-utils/dataFactories.ts +0 -103
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +0 -380
- package/src/components/DataTable/__tests__/test-utils.ts +0 -94
- package/src/components/DataTable/components/AccessDeniedPage.tsx +0 -159
- package/src/components/DataTable/components/ActionButtons.tsx +0 -190
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +0 -160
- package/src/components/DataTable/components/ColumnFilter.tsx +0 -118
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +0 -114
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +0 -225
- package/src/components/DataTable/components/DataTableLayout.tsx +0 -573
- package/src/components/DataTable/components/DataTableModals.tsx +0 -245
- package/src/components/DataTable/components/DataTableToolbar.tsx +0 -271
- package/src/components/DataTable/components/EditFields.tsx +0 -327
- package/src/components/DataTable/components/EditableRow.tsx +0 -462
- package/src/components/DataTable/components/EmptyState.tsx +0 -79
- package/src/components/DataTable/components/FilterRow.tsx +0 -141
- package/src/components/DataTable/components/LoadingState.tsx +0 -17
- package/src/components/DataTable/components/PaginationControls.tsx +0 -289
- package/src/components/DataTable/components/RowComponent.tsx +0 -403
- package/src/components/DataTable/components/SortIndicator.tsx +0 -50
- package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -355
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +0 -657
- package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +0 -913
- package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +0 -572
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +0 -612
- package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +0 -708
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +0 -479
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -475
- package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +0 -157
- package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +0 -1061
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +0 -437
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +0 -474
- package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +0 -617
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -1093
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +0 -139
- package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +0 -519
- package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +0 -1004
- package/src/components/DataTable/components/cellValueUtils.ts +0 -40
- package/src/components/DataTable/components/hooks/useImportModalFocus.ts +0 -53
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -122
- package/src/components/DataTable/components/index.ts +0 -16
- package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +0 -342
- package/src/components/DataTable/core/ActionManager.ts +0 -235
- package/src/components/DataTable/core/ColumnManager.ts +0 -205
- package/src/components/DataTable/core/DataManager.ts +0 -188
- package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
- package/src/components/DataTable/core/PluginRegistry.ts +0 -229
- package/src/components/DataTable/core/StateManager.ts +0 -312
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -123
- package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +0 -305
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -84
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -115
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -100
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -120
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -104
- package/src/components/DataTable/core/index.ts +0 -1
- package/src/components/DataTable/core/interfaces.ts +0 -338
- package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +0 -521
- package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +0 -167
- package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +0 -124
- package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +0 -117
- package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +0 -102
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +0 -596
- package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +0 -53
- package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +0 -214
- package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +0 -448
- package/src/components/DataTable/hooks/index.ts +0 -13
- package/src/components/DataTable/types.ts +0 -761
- package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +0 -612
- package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +0 -94
- package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +0 -266
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +0 -954
- package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +0 -573
- package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +0 -247
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +0 -570
- package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +0 -470
- package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +0 -251
- package/src/components/DataTable/utils/__tests__/selectFieldUtils.test.ts +0 -207
- package/src/components/DataTable/utils/index.ts +0 -10
- package/src/components/PublicLayout/index.ts +0 -32
- package/src/components/Select/hooks/useSelectEvents.ts +0 -87
- package/src/components/Select/hooks/useSelectSearch.ts +0 -91
- package/src/components/Select/hooks/useSelectState.ts +0 -104
- package/src/components/Select/utils/text.ts +0 -26
- package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -615
- package/src/hooks/__tests__/hooks.integration.test.tsx +0 -607
- package/src/hooks/__tests__/index.unit.test.ts +0 -220
- package/src/hooks/__tests__/useApiFetch.unit.test.ts +0 -111
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +0 -347
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +0 -144
- package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +0 -776
- package/src/hooks/__tests__/useDataTableState.test.ts +0 -76
- package/src/hooks/__tests__/useDebounce.unit.test.ts +0 -82
- package/src/hooks/__tests__/useEvents.unit.test.ts +0 -252
- package/src/hooks/__tests__/useFileDisplay.unit.test.ts +0 -1112
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +0 -916
- package/src/hooks/__tests__/useFileUrlCache.test.ts +0 -129
- package/src/hooks/__tests__/useFocusManagement.unit.test.ts +0 -230
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +0 -828
- package/src/hooks/__tests__/useFormDialog.test.ts +0 -478
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +0 -446
- package/src/hooks/__tests__/useIsMobile.unit.test.ts +0 -317
- package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +0 -910
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -294
- package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +0 -961
- package/src/hooks/__tests__/useOrganisations.unit.test.ts +0 -369
- package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +0 -694
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
- package/src/hooks/__tests__/usePreventTabReload.test.ts +0 -88
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -785
- package/src/hooks/__tests__/usePublicEvent.test.ts +0 -678
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +0 -630
- package/src/hooks/__tests__/usePublicFileDisplay.test.ts +0 -951
- package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +0 -443
- package/src/hooks/__tests__/useQueryCache.test.ts +0 -144
- package/src/hooks/__tests__/useRBAC.unit.test.ts +0 -236
- package/src/hooks/__tests__/useSessionDraft.test.ts +0 -163
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +0 -390
- package/src/hooks/__tests__/useStorage.unit.test.ts +0 -751
- package/src/hooks/__tests__/useToast.unit.test.tsx +0 -481
- package/src/hooks/__tests__/useZodForm.unit.test.tsx +0 -37
- package/src/hooks/public/index.ts +0 -36
- package/src/hooks/public/usePublicFileDisplay.ts +0 -504
- package/src/hooks/useFileDisplay.ts +0 -715
- package/src/providers/OrganisationProvider.tsx +0 -92
- package/src/providers/__tests__/AuthProvider.test.tsx +0 -287
- package/src/providers/__tests__/EventProvider.test.tsx +0 -551
- package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
- package/src/providers/__tests__/InactivityProvider.test.tsx +0 -572
- package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -617
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +0 -424
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +0 -596
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +0 -263
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +0 -294
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +0 -434
- package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +0 -313
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +0 -486
- package/src/rbac/__tests__/cache-invalidation.test.ts +0 -399
- package/src/rbac/__tests__/engine.comprehensive.test.ts +0 -813
- package/src/rbac/__tests__/isSuperAdmin.real.test.ts +0 -82
- package/src/rbac/__tests__/rbac-core.test.tsx +0 -276
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +0 -392
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +0 -258
- package/src/rbac/__tests__/rbac-functions.test.ts +0 -647
- package/src/rbac/__tests__/rbac-integration.test.ts +0 -524
- package/src/rbac/__tests__/rbac-role-isolation.test.ts +0 -456
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +0 -282
- package/src/rbac/audit-enhanced.ts +0 -384
- package/src/rbac/compliance/database-validator.ts +0 -165
- package/src/rbac/compliance/index.ts +0 -48
- package/src/rbac/compliance/pattern-detector.ts +0 -553
- package/src/rbac/compliance/quick-fix-suggestions.ts +0 -209
- package/src/rbac/compliance/runtime-compliance.ts +0 -99
- package/src/rbac/compliance/setup-validator.ts +0 -131
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +0 -975
- package/src/rbac/components/__tests__/PagePermissionGuard.performance.test.tsx +0 -248
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +0 -242
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +0 -1107
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +0 -184
- package/src/rbac/components/index.ts +0 -26
- package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +0 -432
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +0 -579
- package/src/rbac/hooks/index.ts +0 -34
- package/src/rbac/hooks/permissions/index.ts +0 -4
- package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
- package/src/rbac/utils/__tests__/contextValidator.test.ts +0 -128
- package/src/rbac/utils/__tests__/deep-equal.test.ts +0 -53
- package/src/rbac/utils/__tests__/eventContext.test.ts +0 -433
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -490
- package/src/services/__tests__/AuthService.restoreSession.test.ts +0 -39
- package/src/services/__tests__/AuthService.test.ts +0 -1332
- package/src/services/__tests__/BaseService.test.ts +0 -314
- package/src/services/__tests__/EventService.eventColours.test.ts +0 -76
- package/src/services/__tests__/EventService.test.ts +0 -1025
- package/src/services/__tests__/InactivityService.lifecycle.test.ts +0 -411
- package/src/services/__tests__/InactivityService.test.ts +0 -654
- package/src/services/__tests__/OrganisationService.pagination.test.ts +0 -409
- package/src/services/__tests__/OrganisationService.test.ts +0 -1176
- package/src/theming/__tests__/parseEventColours.test.ts +0 -321
- package/src/theming/__tests__/runtime.test.ts +0 -569
- package/src/types/__tests__/file-reference.test.ts +0 -447
- package/src/types/__tests__/guards.test.ts +0 -246
- package/src/types/__tests__/organisation.roles.test.ts +0 -55
- package/src/types/__tests__/organisation.test.ts +0 -1133
- package/src/types/__tests__/theme.test.ts +0 -830
- package/src/types/__tests__/type-validation.test.ts +0 -526
- package/src/types/__tests__/validation.test.ts +0 -731
- package/src/utils/__tests__/appConfig.unit.test.ts +0 -55
- package/src/utils/__tests__/audit.unit.test.ts +0 -69
- package/src/utils/__tests__/auth-utils.unit.test.ts +0 -70
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +0 -339
- package/src/utils/__tests__/cn.unit.test.ts +0 -34
- package/src/utils/__tests__/debugLogger.test.ts +0 -417
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +0 -818
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +0 -318
- package/src/utils/__tests__/formatDate.unit.test.ts +0 -109
- package/src/utils/__tests__/formatting.unit.test.ts +0 -99
- package/src/utils/__tests__/index.unit.test.ts +0 -251
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -321
- package/src/utils/__tests__/logger.unit.test.ts +0 -398
- package/src/utils/__tests__/organisationContext.unit.test.ts +0 -191
- package/src/utils/__tests__/performanceBenchmark.test.ts +0 -175
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +0 -253
- package/src/utils/__tests__/permissionTypes.unit.test.ts +0 -250
- package/src/utils/__tests__/permissionUtils.unit.test.ts +0 -362
- package/src/utils/__tests__/sanitization.unit.test.ts +0 -346
- package/src/utils/__tests__/schemaUtils.unit.test.ts +0 -441
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -335
- package/src/utils/__tests__/secureErrors.unit.test.ts +0 -390
- package/src/utils/__tests__/secureStorage.unit.test.ts +0 -289
- package/src/utils/__tests__/security.unit.test.ts +0 -149
- package/src/utils/__tests__/securityMonitor.unit.test.ts +0 -276
- package/src/utils/__tests__/sessionTracking.unit.test.ts +0 -218
- package/src/utils/__tests__/timezone.test.ts +0 -345
- package/src/utils/__tests__/validation.unit.test.ts +0 -308
- package/src/utils/__tests__/validationUtils.unit.test.ts +0 -555
- package/src/utils/app/appNameResolver.simple.test.ts +0 -212
- package/src/utils/file-reference/__tests__/file-reference.test.ts +0 -875
- package/src/utils/google-places/index.ts +0 -26
- package/src/utils/location/index.ts +0 -16
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +0 -135
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +0 -123
- package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -332
- package/src/utils/storage/__tests__/index.unit.test.ts +0 -16
- package/src/utils/storage/index.ts +0 -67
- package/src/utils/timezone/index.ts +0 -17
- package/src/utils/validation/__tests__/csrf.test.ts +0 -105
- package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +0 -598
- package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +0 -92
- package/src/utils/validation/__tests__/validationUtils.test.ts +0 -72
- package/src/utils/validation/index.ts +0 -73
- /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
- /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
- /package/src/providers/{__tests__/README.md → README.md} +0 -0
- /package/src/types/{__tests__/README.md → README.md} +0 -0
|
@@ -97,113 +97,184 @@
|
|
|
97
97
|
* - Tailwind CSS - Styling
|
|
98
98
|
*/
|
|
99
99
|
|
|
100
|
-
import React, {
|
|
100
|
+
import React, { useEffect } from 'react';
|
|
101
101
|
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
|
|
102
|
+
import type { User } from '@supabase/supabase-js';
|
|
102
103
|
import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
|
|
103
104
|
import { useOrganisations } from '../../hooks/useOrganisations';
|
|
104
|
-
import {
|
|
105
|
+
import { useOptionalEvents } from '../../hooks/useEvents';
|
|
105
106
|
import { useEventTheme } from '../../hooks/useEventTheme';
|
|
106
|
-
import
|
|
107
|
-
import { useCan, useResolvedScope, useRBAC } from '../../rbac/hooks';
|
|
108
|
-
import { createScopeFromEvent } from '../../rbac/utils/eventContext';
|
|
109
|
-
import { getCurrentAppName } from '../../utils/app/appNameResolver';
|
|
110
|
-
import { isSuperAdmin as checkSuperAdminApi } from '../../rbac/api';
|
|
107
|
+
import { useRBAC } from '../../rbac/hooks/useRBAC';
|
|
111
108
|
import { logger } from '../../utils/core/logger';
|
|
112
|
-
import
|
|
113
|
-
import {
|
|
114
|
-
import {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
import { Button } from '../Button';
|
|
109
|
+
import { useSuperAdminFallback } from './useSuperAdminFallback';
|
|
110
|
+
import { useFilteredNavItems } from './useFilteredNavItems';
|
|
111
|
+
import { useRoleBasedRouteAccess } from './useRoleBasedRouteAccess';
|
|
112
|
+
import { usePaceAppLayoutConfig } from './usePaceAppLayoutConfig';
|
|
113
|
+
import { usePaceAppLayoutPermissions } from './usePaceAppLayoutPermissions';
|
|
114
|
+
import { usePaceAppLayoutGate } from './usePaceAppLayoutGate';
|
|
115
|
+
import { usePaceAppLayoutScope } from './usePaceAppLayoutScope';
|
|
120
116
|
import { Footer } from '../Footer';
|
|
121
117
|
import { Header } from '../Header';
|
|
122
118
|
import type { NavigationItem } from '../NavigationMenu/NavigationMenu';
|
|
123
|
-
import
|
|
124
|
-
|
|
125
|
-
// Define Operation type locally since old RBAC types are removed
|
|
119
|
+
import { setupPrintDateTime } from '../../theming/runtime';
|
|
120
|
+
|
|
126
121
|
type Operation = 'read' | 'create' | 'update' | 'delete' | 'manage';
|
|
122
|
+
const EMPTY_PAGE_ID_MAPPING: Record<string, string> = {};
|
|
123
|
+
const EMPTY_ROUTE_PERMISSIONS: Record<string, Operation> = {};
|
|
124
|
+
|
|
125
|
+
/** Route config item for role-based routing. */
|
|
126
|
+
export interface PaceAppLayoutRouteConfigItem {
|
|
127
|
+
path: string;
|
|
128
|
+
component: React.ComponentType;
|
|
129
|
+
permissions: string[];
|
|
130
|
+
roles?: string[];
|
|
131
|
+
accessLevel?: string;
|
|
132
|
+
pageId?: string;
|
|
133
|
+
strictMode?: boolean;
|
|
134
|
+
meta?: {
|
|
135
|
+
title?: string;
|
|
136
|
+
description?: string;
|
|
137
|
+
requiresAuth?: boolean;
|
|
138
|
+
hidden?: boolean;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
127
141
|
|
|
128
|
-
/**
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
142
|
+
/** Optional grouped permission options. When provided, overrides flat permission props. */
|
|
143
|
+
export interface PaceAppLayoutPermissionConfig {
|
|
144
|
+
enforcePermissions?: boolean;
|
|
145
|
+
defaultPermission?: Operation;
|
|
146
|
+
routePermissions?: Record<string, Operation>;
|
|
147
|
+
pageIdMapping?: Record<string, string>;
|
|
148
|
+
permissionFallback?: React.ReactNode;
|
|
149
|
+
strictMode?: boolean;
|
|
150
|
+
enforcePagePermissions?: boolean;
|
|
151
|
+
pagePermissionFallback?: React.ReactNode;
|
|
152
|
+
auditLog?: boolean;
|
|
153
|
+
onPageAccessDenied?: (pageName: string, operation: string) => void;
|
|
154
|
+
onStrictModeViolation?: (pageName: string, operation: string) => void;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Optional grouped routing options. When provided, overrides flat routing props. */
|
|
158
|
+
export interface PaceAppLayoutRoutingConfig {
|
|
159
|
+
roleBasedRouting?: boolean;
|
|
160
|
+
routeConfig?: PaceAppLayoutRouteConfigItem[];
|
|
161
|
+
fallbackRoute?: string;
|
|
162
|
+
onRouteAccessDenied?: (route: string, reason: string) => void;
|
|
163
|
+
onRouteStrictModeViolation?: (route: string, reason: string) => void;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Layout props for PaceAppLayout (ISP). */
|
|
167
|
+
export interface PaceAppLayoutPropsLayout {
|
|
134
168
|
appName: string;
|
|
135
|
-
/** Optional navigation items for the header menu. If not provided, uses default navigation. */
|
|
136
169
|
navItems?: NavigationItem[];
|
|
137
|
-
/** Show/hide unified context selector (shows all accessible orgs and events) - default: true */
|
|
138
170
|
showContextSelector?: boolean;
|
|
139
|
-
/** Show organisations in context selector - default: true */
|
|
140
171
|
showOrganisations?: boolean;
|
|
141
|
-
/** Show events in context selector - default: true */
|
|
142
172
|
showEvents?: boolean;
|
|
143
|
-
/** Custom actions to display in the header (between event selector and user menu) */
|
|
144
173
|
headerActions?: React.ReactNode;
|
|
145
|
-
/** Custom logo component (overrides default logo) */
|
|
146
|
-
customLogo?: React.ReactNode;
|
|
147
|
-
/** URL to navigate to when logo is clicked (defaults to '/dashboard') */
|
|
148
174
|
logoHref?: string;
|
|
149
|
-
/** Custom user menu component (overrides default user menu) */
|
|
150
175
|
customUserMenu?: React.ReactNode;
|
|
151
|
-
/** Custom className for the header */
|
|
152
176
|
headerClassName?: string;
|
|
153
|
-
/** Show/hide user menu */
|
|
154
177
|
showUserMenu?: boolean;
|
|
155
|
-
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Permission props for PaceAppLayout (ISP). */
|
|
181
|
+
export interface PaceAppLayoutPropsPermission {
|
|
182
|
+
permissionConfig?: PaceAppLayoutPermissionConfig;
|
|
156
183
|
enforcePermissions?: boolean;
|
|
157
|
-
/** Default permission to check for all routes (when enforcePermissions is true) */
|
|
158
184
|
defaultPermission?: Operation;
|
|
159
|
-
/** Route-specific permissions mapping */
|
|
160
185
|
routePermissions?: Record<string, Operation>;
|
|
161
|
-
/** Fallback component to show when user lacks permission */
|
|
162
186
|
permissionFallback?: React.ReactNode;
|
|
163
|
-
/** Custom permission page ID mapping */
|
|
164
187
|
pageIdMapping?: Record<string, string>;
|
|
165
|
-
|
|
166
|
-
// NEW: Phase 1 - Enhanced Security Features
|
|
167
|
-
/** Enable strict mode to prevent bypassing permission checks (default: true) */
|
|
168
188
|
strictMode?: boolean;
|
|
169
|
-
/** Enable page-level permission enforcement (default: false) */
|
|
170
189
|
enforcePagePermissions?: boolean;
|
|
171
|
-
/** Default page permission fallback component */
|
|
172
190
|
pagePermissionFallback?: React.ReactNode;
|
|
173
|
-
/** Enable audit logging for all permission checks (default: true) */
|
|
174
191
|
auditLog?: boolean;
|
|
175
|
-
/** Callback when page access is denied */
|
|
176
192
|
onPageAccessDenied?: (pageName: string, operation: string) => void;
|
|
177
|
-
/** Callback when strict mode violation occurs */
|
|
178
193
|
onStrictModeViolation?: (pageName: string, operation: string) => void;
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Routing props for PaceAppLayout (ISP). */
|
|
197
|
+
export interface PaceAppLayoutPropsRouting {
|
|
198
|
+
routingConfig?: PaceAppLayoutRoutingConfig;
|
|
182
199
|
roleBasedRouting?: boolean;
|
|
183
|
-
|
|
184
|
-
routeConfig?: Array<{
|
|
185
|
-
path: string;
|
|
186
|
-
component: React.ComponentType;
|
|
187
|
-
permissions: string[];
|
|
188
|
-
roles?: string[];
|
|
189
|
-
accessLevel?: string;
|
|
190
|
-
pageId?: string;
|
|
191
|
-
strictMode?: boolean;
|
|
192
|
-
meta?: {
|
|
193
|
-
title?: string;
|
|
194
|
-
description?: string;
|
|
195
|
-
requiresAuth?: boolean;
|
|
196
|
-
hidden?: boolean;
|
|
197
|
-
};
|
|
198
|
-
}>;
|
|
199
|
-
/** Fallback route for unauthorized access */
|
|
200
|
+
routeConfig?: PaceAppLayoutRouteConfigItem[];
|
|
200
201
|
fallbackRoute?: string;
|
|
201
|
-
/** Callback when route access is denied */
|
|
202
202
|
onRouteAccessDenied?: (route: string, reason: string) => void;
|
|
203
|
-
/** Callback when route strict mode violation occurs */
|
|
204
203
|
onRouteStrictModeViolation?: (route: string, reason: string) => void;
|
|
205
204
|
}
|
|
206
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Props for the PaceAppLayout component (ISP: composed from focused interfaces).
|
|
208
|
+
* Permission and routing options can be passed either as flat props or via permissionConfig / routingConfig.
|
|
209
|
+
*/
|
|
210
|
+
export type PaceAppLayoutProps = PaceAppLayoutPropsLayout
|
|
211
|
+
& PaceAppLayoutPropsPermission
|
|
212
|
+
& PaceAppLayoutPropsRouting;
|
|
213
|
+
|
|
214
|
+
/** Renders the main layout structure (Header + main + Footer). Extracted to keep PaceAppLayout under max-lines. */
|
|
215
|
+
function PaceAppLayoutContent({
|
|
216
|
+
appName,
|
|
217
|
+
logoHref,
|
|
218
|
+
filteredMenuItems,
|
|
219
|
+
headerActions,
|
|
220
|
+
customUserMenu,
|
|
221
|
+
user,
|
|
222
|
+
onSignOut,
|
|
223
|
+
onChangePassword,
|
|
224
|
+
headerClassName,
|
|
225
|
+
showContextSelector,
|
|
226
|
+
showOrganisations,
|
|
227
|
+
showEvents,
|
|
228
|
+
showUserMenu,
|
|
229
|
+
navigate,
|
|
230
|
+
}: {
|
|
231
|
+
appName: string;
|
|
232
|
+
logoHref: string;
|
|
233
|
+
filteredMenuItems: NavigationItem[];
|
|
234
|
+
headerActions?: React.ReactNode;
|
|
235
|
+
customUserMenu?: React.ReactNode;
|
|
236
|
+
user: User | null | undefined;
|
|
237
|
+
onSignOut: () => Promise<void>;
|
|
238
|
+
onChangePassword: (newPassword: string, confirmPassword: string) => Promise<{ error?: { message: string; code?: string } }>;
|
|
239
|
+
headerClassName?: string;
|
|
240
|
+
showContextSelector: boolean;
|
|
241
|
+
showOrganisations: boolean;
|
|
242
|
+
showEvents: boolean;
|
|
243
|
+
showUserMenu: boolean;
|
|
244
|
+
navigate: (to: string) => void;
|
|
245
|
+
}) {
|
|
246
|
+
return (
|
|
247
|
+
<>
|
|
248
|
+
<Header
|
|
249
|
+
logoUrl={`/${appName.toLowerCase()}_logo_wide.svg`}
|
|
250
|
+
logoAlt={`${appName} Logo`}
|
|
251
|
+
logoHref={logoHref}
|
|
252
|
+
navItems={filteredMenuItems}
|
|
253
|
+
actions={headerActions}
|
|
254
|
+
userMenu={customUserMenu}
|
|
255
|
+
user={user}
|
|
256
|
+
onSignOut={onSignOut}
|
|
257
|
+
onChangePassword={onChangePassword}
|
|
258
|
+
currentPath={window.location.pathname}
|
|
259
|
+
onNavigate={(item) => {
|
|
260
|
+
if (item.href) {
|
|
261
|
+
navigate(item.href);
|
|
262
|
+
}
|
|
263
|
+
}}
|
|
264
|
+
showContextSelector={showContextSelector}
|
|
265
|
+
showOrganisations={showOrganisations}
|
|
266
|
+
showEvents={showEvents}
|
|
267
|
+
showUserMenu={showUserMenu}
|
|
268
|
+
className={headerClassName || "sticky top-0 z-header w-full"}
|
|
269
|
+
/>
|
|
270
|
+
<main className="px-4 w-full max-w-app-content-max mx-auto py-8">
|
|
271
|
+
<Outlet />
|
|
272
|
+
</main>
|
|
273
|
+
<Footer />
|
|
274
|
+
</>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
207
278
|
/**
|
|
208
279
|
* A consistent layout component for all PACE suite applications that provides a standard
|
|
209
280
|
* structure with header, main content area, and footer.
|
|
@@ -352,747 +423,194 @@ export interface PaceAppLayoutProps {
|
|
|
352
423
|
*
|
|
353
424
|
* @since 0.1.0
|
|
354
425
|
*/
|
|
355
|
-
export function PaceAppLayout({
|
|
356
|
-
appName,
|
|
357
|
-
navItems,
|
|
426
|
+
export function PaceAppLayout({
|
|
427
|
+
appName,
|
|
428
|
+
navItems,
|
|
358
429
|
showContextSelector = true,
|
|
359
430
|
showOrganisations = true,
|
|
360
431
|
showEvents = true,
|
|
361
432
|
headerActions,
|
|
362
|
-
customLogo,
|
|
363
433
|
logoHref = '/dashboard',
|
|
364
434
|
customUserMenu,
|
|
365
435
|
headerClassName,
|
|
366
436
|
showUserMenu = true,
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
strictMode = true,
|
|
374
|
-
enforcePagePermissions = false,
|
|
375
|
-
pagePermissionFallback,
|
|
376
|
-
auditLog = true,
|
|
377
|
-
onPageAccessDenied,
|
|
378
|
-
onStrictModeViolation,
|
|
379
|
-
|
|
380
|
-
roleBasedRouting = false,
|
|
381
|
-
routeConfig = [],
|
|
382
|
-
fallbackRoute = '/unauthorized',
|
|
383
|
-
onRouteAccessDenied,
|
|
384
|
-
onRouteStrictModeViolation
|
|
437
|
+
permissionConfig,
|
|
438
|
+
enforcePermissions: enforcePermissionsFlat = false,
|
|
439
|
+
defaultPermission: defaultPermissionFlat = 'read',
|
|
440
|
+
routePermissions: routePermissionsFlat = EMPTY_ROUTE_PERMISSIONS,
|
|
441
|
+
permissionFallback: permissionFallbackFlat,
|
|
442
|
+
pageIdMapping: pageIdMappingFlat = EMPTY_PAGE_ID_MAPPING,
|
|
443
|
+
strictMode: strictModeFlat = true,
|
|
444
|
+
enforcePagePermissions: enforcePagePermissionsFlat = false,
|
|
445
|
+
pagePermissionFallback: pagePermissionFallbackFlat,
|
|
446
|
+
auditLog: _auditLogFlat = true,
|
|
447
|
+
onPageAccessDenied: onPageAccessDeniedFlat,
|
|
448
|
+
onStrictModeViolation: onStrictModeViolationFlat,
|
|
449
|
+
routingConfig,
|
|
450
|
+
roleBasedRouting: roleBasedRoutingFlat = false,
|
|
451
|
+
routeConfig: routeConfigFlat = [],
|
|
452
|
+
fallbackRoute: fallbackRouteFlat = '/unauthorized',
|
|
453
|
+
onRouteAccessDenied: onRouteAccessDeniedFlat,
|
|
454
|
+
onRouteStrictModeViolation: onRouteStrictModeViolationFlat,
|
|
385
455
|
}: PaceAppLayoutProps) {
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
456
|
+
const config = usePaceAppLayoutConfig({
|
|
457
|
+
permissionConfig,
|
|
458
|
+
enforcePermissions: enforcePermissionsFlat,
|
|
459
|
+
defaultPermission: defaultPermissionFlat,
|
|
460
|
+
routePermissions: routePermissionsFlat,
|
|
461
|
+
permissionFallback: permissionFallbackFlat,
|
|
462
|
+
pageIdMapping: pageIdMappingFlat,
|
|
463
|
+
strictMode: strictModeFlat,
|
|
464
|
+
enforcePagePermissions: enforcePagePermissionsFlat,
|
|
465
|
+
pagePermissionFallback: pagePermissionFallbackFlat,
|
|
466
|
+
onPageAccessDenied: onPageAccessDeniedFlat,
|
|
467
|
+
onStrictModeViolation: onStrictModeViolationFlat,
|
|
468
|
+
routingConfig,
|
|
469
|
+
roleBasedRouting: roleBasedRoutingFlat,
|
|
470
|
+
routeConfig: routeConfigFlat,
|
|
471
|
+
fallbackRoute: fallbackRouteFlat,
|
|
472
|
+
onRouteAccessDenied: onRouteAccessDeniedFlat,
|
|
473
|
+
onRouteStrictModeViolation: onRouteStrictModeViolationFlat,
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
const { user, signOut, updatePassword, supabase, appId: contextAppId, selectedOrganisationId } = useUnifiedAuth();
|
|
477
|
+
const {
|
|
478
|
+
selectedOrganisation,
|
|
479
|
+
isLoading: organisationLoading,
|
|
393
480
|
} = useOrganisations();
|
|
394
|
-
// Use useRBAC to get super admin status - it's more reliable than async check
|
|
395
|
-
// Note: isSuperAdmin might be false initially while loading, but that's OK - we'll allow rendering
|
|
396
|
-
// if organisation loading completes or if we're a super admin
|
|
397
481
|
const { isSuperAdmin: isSuperAdminFromRBAC, isLoading: rbacLoading } = useRBAC();
|
|
482
|
+
const { isSuperAdminDirect, isCheckingSuperAdminDirect } = useSuperAdminFallback(user?.id, isSuperAdminFromRBAC);
|
|
398
483
|
|
|
399
|
-
//
|
|
400
|
-
// This allows super admins to proceed even if RBAC hasn't loaded yet
|
|
401
|
-
const [isSuperAdminDirect, setIsSuperAdminDirect] = useState<boolean>(false);
|
|
402
|
-
const [isCheckingSuperAdminDirect, setIsCheckingSuperAdminDirect] = useState<boolean>(false);
|
|
403
|
-
|
|
484
|
+
// Update --print-date-time when user prints (e.g. Ctrl+P) so printed pages show current date/time
|
|
404
485
|
useEffect(() => {
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
setIsCheckingSuperAdminDirect(false);
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
486
|
+
const teardown = setupPrintDateTime();
|
|
487
|
+
return teardown;
|
|
488
|
+
}, []);
|
|
411
489
|
|
|
412
|
-
// Only skip if RBAC already confirmed super admin
|
|
413
|
-
if (isSuperAdminFromRBAC) {
|
|
414
|
-
setIsCheckingSuperAdminDirect(false);
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
setIsCheckingSuperAdminDirect(true);
|
|
419
|
-
try {
|
|
420
|
-
const superAdminStatus = await checkSuperAdminApi(user.id);
|
|
421
|
-
setIsSuperAdminDirect(superAdminStatus);
|
|
422
|
-
} catch (error) {
|
|
423
|
-
logger.error('PaceAppLayout', 'Error checking super admin status directly', { userId: user?.id, error });
|
|
424
|
-
setIsSuperAdminDirect(false);
|
|
425
|
-
} finally {
|
|
426
|
-
setIsCheckingSuperAdminDirect(false);
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
|
-
|
|
430
|
-
checkSuperAdminDirect();
|
|
431
|
-
}, [user?.id, isSuperAdminFromRBAC]);
|
|
432
|
-
|
|
433
|
-
// Use direct check if RBAC hasn't loaded yet, otherwise use RBAC result
|
|
434
490
|
const isSuperAdmin = isSuperAdminFromRBAC || isSuperAdminDirect;
|
|
435
491
|
const navigate = useNavigate();
|
|
436
492
|
const location = useLocation();
|
|
437
|
-
|
|
438
|
-
// Apply event theme colors automatically
|
|
493
|
+
|
|
439
494
|
useEventTheme();
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
selectedEvent
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// Resolve scope for permission checking
|
|
451
|
-
const { resolvedScope, isLoading: scopeLoading } = useResolvedScope({
|
|
452
|
-
supabase: supabase || null,
|
|
453
|
-
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
454
|
-
selectedEventId: selectedEvent?.event_id || null,
|
|
455
|
-
selectedEventOrganisationId: selectedEvent?.organisation_id || null
|
|
495
|
+
const { selectedEvent } = useOptionalEvents();
|
|
496
|
+
|
|
497
|
+
const { scope, resolvedAppId, scopeLoading, baseMenuItems } = usePaceAppLayoutScope({
|
|
498
|
+
supabase,
|
|
499
|
+
selectedOrganisation,
|
|
500
|
+
selectedEvent,
|
|
501
|
+
contextAppId,
|
|
502
|
+
navItems,
|
|
456
503
|
});
|
|
457
504
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
// Build scope from resolved values
|
|
463
|
-
// Preserve appId from resolvedScope or fallback to resolvedAppId
|
|
464
|
-
// CRITICAL: Always create a new scope object from primitive values to ensure stable reference
|
|
465
|
-
// This prevents useCan from re-checking permissions when resolvedScope changes reference but values are the same
|
|
466
|
-
const scopeOrgId = resolvedScope?.organisationId || selectedOrganisation?.id || '';
|
|
467
|
-
const scopeEventId = resolvedScope?.eventId || selectedEvent?.event_id || undefined;
|
|
468
|
-
const scopeAppId = resolvedScope?.appId || resolvedAppId || undefined;
|
|
469
|
-
|
|
470
|
-
const scope = useMemo<Scope>(() => {
|
|
471
|
-
const newScope: Scope = {};
|
|
472
|
-
if (scopeOrgId) {
|
|
473
|
-
newScope.organisationId = scopeOrgId;
|
|
474
|
-
}
|
|
475
|
-
if (scopeEventId) {
|
|
476
|
-
newScope.eventId = scopeEventId;
|
|
477
|
-
}
|
|
478
|
-
if (scopeAppId) {
|
|
479
|
-
newScope.appId = scopeAppId;
|
|
480
|
-
}
|
|
481
|
-
return newScope;
|
|
482
|
-
}, [scopeOrgId, scopeEventId, scopeAppId]);
|
|
483
|
-
|
|
484
|
-
// Default navigation items if none provided
|
|
485
|
-
const defaultNavItems: NavigationItem[] = useMemo(() => [
|
|
486
|
-
{ id: 'home', label: 'Home', href: '/', icon: 'Home' },
|
|
487
|
-
{ id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },
|
|
488
|
-
{ id: 'settings', label: 'Settings', href: '/settings', icon: 'Settings' },
|
|
489
|
-
{ id: 'ui-showcase', label: 'UI Showcase', href: '/ui-showcase', icon: 'Component' },
|
|
490
|
-
{ id: 'data-table-showcase', label: 'DataTable Showcase', href: '/data-table-showcase', icon: 'Table' },
|
|
491
|
-
], []);
|
|
492
|
-
|
|
493
|
-
// Use provided navItems or fall back to default
|
|
494
|
-
const baseMenuItems = useMemo(() => navItems || defaultNavItems, [navItems]);
|
|
495
|
-
|
|
496
|
-
// Get current route permission requirements
|
|
497
|
-
const currentRoutePermission = useMemo(() => {
|
|
498
|
-
const currentPath = location.pathname;
|
|
499
|
-
return routePermissions[currentPath] || defaultPermission;
|
|
500
|
-
}, [location.pathname, routePermissions, defaultPermission]);
|
|
501
|
-
|
|
502
|
-
// Get current page ID for permission checking
|
|
503
|
-
// Extract base page name (first path segment) instead of full route path
|
|
504
|
-
// Example: /organisation/scouts-victoria -> "organisation"
|
|
505
|
-
const currentPageId = useMemo(() => {
|
|
506
|
-
const currentPath = location.pathname;
|
|
507
|
-
// Use pageIdMapping if provided (takes precedence)
|
|
508
|
-
if (pageIdMapping[currentPath]) {
|
|
509
|
-
return pageIdMapping[currentPath];
|
|
510
|
-
}
|
|
511
|
-
// Extract first path segment (base page name)
|
|
512
|
-
const pathSegments = currentPath.slice(1).split('/').filter(Boolean);
|
|
513
|
-
// Only return 'home' if there's actually a path segment, otherwise return empty string
|
|
514
|
-
// This prevents checking permissions for a non-existent "home" page when the index route is used
|
|
515
|
-
return pathSegments[0] || '';
|
|
516
|
-
}, [location.pathname, pageIdMapping]);
|
|
517
|
-
|
|
518
|
-
// Build permission string in format: operation:page.pageId
|
|
519
|
-
const currentPermission = useMemo<Permission>(() => {
|
|
520
|
-
// If enforcePermissions is false, don't check any permission (return empty string)
|
|
521
|
-
// If currentPageId is empty (index route with no path segments), don't check permissions
|
|
522
|
-
if (!enforcePermissions || !currentPageId) {
|
|
523
|
-
return '' as Permission;
|
|
524
|
-
}
|
|
525
|
-
const permissionString = `${currentRoutePermission}:page.${currentPageId}`;
|
|
526
|
-
return permissionString as Permission;
|
|
527
|
-
}, [enforcePermissions, currentRoutePermission, currentPageId]);
|
|
528
|
-
|
|
529
|
-
// Check super admin status before permission enforcement
|
|
530
|
-
// Removed duplicate super admin check - using useRBAC hook instead
|
|
531
|
-
// The useRBAC hook provides isSuperAdmin which is more reliable
|
|
532
|
-
|
|
533
|
-
// Use useCan hook for permission checking (standardized approach)
|
|
534
|
-
// Note: The database function already handles super admin bypass, but we check here
|
|
535
|
-
// as an additional safety layer to prevent unnecessary permission checks
|
|
536
|
-
// Pass appName to useCan so it can be passed to isPermitted for PORTAL/ADMIN special case
|
|
537
|
-
// Only check permissions if enforcePermissions is true and we have a valid permission string
|
|
538
|
-
const shouldCheckPermission = enforcePermissions && !!currentPermission && !!currentPageId;
|
|
539
|
-
// Pass super admin status to avoid duplicate check - use null if still checking, false/true if known
|
|
540
|
-
const superAdminStatus = isSuperAdminFromRBAC ? true : (isCheckingSuperAdminDirect ? null : isSuperAdminDirect);
|
|
541
|
-
const { can: canFromHook, isLoading: isCheckingPermission, error: permissionError } = useCan(
|
|
542
|
-
user?.id || '',
|
|
505
|
+
const permissions = usePaceAppLayoutPermissions({
|
|
506
|
+
config,
|
|
507
|
+
user,
|
|
543
508
|
scope,
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
);
|
|
550
|
-
|
|
551
|
-
// Permission enforcement state - super admin bypasses all checks
|
|
552
|
-
// This ensures super admins never see permission errors even if useCan hasn't completed
|
|
553
|
-
// Use combined super admin check (RBAC + direct check)
|
|
554
|
-
const can = isSuperAdmin ? true : canFromHook;
|
|
555
|
-
const hasPermission = enforcePermissions ? can : true;
|
|
556
|
-
|
|
557
|
-
// Check if the permission error is a context error (missing event/org context)
|
|
558
|
-
// Context errors should allow the page to render so it can show helpful messaging
|
|
559
|
-
// Real permission denials should still show "Access Denied"
|
|
560
|
-
const isContextError = useMemo(() => {
|
|
561
|
-
if (!permissionError) {
|
|
562
|
-
return false;
|
|
563
|
-
}
|
|
564
|
-
return (
|
|
565
|
-
permissionError instanceof EventContextRequiredError ||
|
|
566
|
-
permissionError instanceof OrganisationContextRequiredError ||
|
|
567
|
-
permissionError.name === 'EventContextRequiredError' ||
|
|
568
|
-
permissionError.name === 'OrganisationContextRequiredError'
|
|
569
|
-
);
|
|
570
|
-
}, [permissionError]);
|
|
571
|
-
|
|
572
|
-
// Handle permission check results with audit logging and callbacks
|
|
573
|
-
useEffect(() => {
|
|
574
|
-
if (!enforcePermissions) {
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
// Only proceed when permission check is complete (not loading)
|
|
579
|
-
// Super admin status is checked via useRBAC hook (isSuperAdminFromRBAC)
|
|
580
|
-
// If RBAC is still loading, allow rendering to proceed (optimistic for super admins)
|
|
581
|
-
if (isCheckingPermission) {
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
// NEW: Phase 1 - Enhanced Security Features
|
|
586
|
-
// Handle strict mode violations - skip for super admins
|
|
587
|
-
if (strictMode && !isSuperAdmin && !can) {
|
|
588
|
-
logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: User attempted to access protected page without permission', {
|
|
589
|
-
pageName: currentPageId,
|
|
590
|
-
operation: currentRoutePermission,
|
|
591
|
-
userId: user?.id,
|
|
592
|
-
isSuperAdmin: isSuperAdmin,
|
|
593
|
-
timestamp: new Date().toISOString()
|
|
594
|
-
});
|
|
595
|
-
|
|
596
|
-
if (onStrictModeViolation) {
|
|
597
|
-
onStrictModeViolation(currentPageId, currentRoutePermission);
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Handle page access denied callback - skip for super admins
|
|
602
|
-
if (!isSuperAdmin && !can && onPageAccessDenied) {
|
|
603
|
-
onPageAccessDenied(currentPageId, currentRoutePermission);
|
|
604
|
-
}
|
|
605
|
-
}, [enforcePermissions, can, isCheckingPermission, isSuperAdmin, currentPageId, currentRoutePermission, user?.id, strictMode, auditLog, onPageAccessDenied, onStrictModeViolation]);
|
|
606
|
-
|
|
607
|
-
// Filter navigation items based on permissions
|
|
608
|
-
// Permission filtering is always enabled - users only see navigation items they have permission to access
|
|
609
|
-
const [filteredMenuItems, setFilteredMenuItems] = useState<NavigationItem[]>(baseMenuItems);
|
|
610
|
-
|
|
611
|
-
useEffect(() => {
|
|
612
|
-
let isMounted = true;
|
|
613
|
-
|
|
614
|
-
const filterItems = async () => {
|
|
615
|
-
// Wait for organisation context to be ready before filtering
|
|
616
|
-
// This prevents blocking navigation while context is loading
|
|
617
|
-
if (!user?.id) {
|
|
618
|
-
// User not loaded yet - show all items until context is ready
|
|
619
|
-
if (isMounted) {
|
|
620
|
-
setFilteredMenuItems(baseMenuItems);
|
|
621
|
-
}
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
// Use the scope from context (includes selectedOrganisation and selectedEvent)
|
|
626
|
-
// This is critical for event-based apps where event context comes from EventService, not user metadata
|
|
627
|
-
const currentScope = scope;
|
|
628
|
-
|
|
629
|
-
// Wait for scope to be fully resolved (including appId) before filtering
|
|
630
|
-
// This is important because getPermissionMap requires appId to fetch pages
|
|
631
|
-
// Check both resolvedScope.appId and resolvedAppId (fallback)
|
|
632
|
-
// appId is now resolved immediately on login in UnifiedAuthProvider, so it should be available
|
|
633
|
-
const hasAppId = currentScope.appId || resolvedAppId;
|
|
634
|
-
|
|
635
|
-
// OPTIMIZATION: Show items optimistically while permissions load
|
|
636
|
-
// This makes the menu appear immediately, then we filter when permissions are ready
|
|
637
|
-
const hasOrganisationContext = currentScope.organisationId;
|
|
638
|
-
const hasUser = !!user?.id;
|
|
639
|
-
|
|
640
|
-
// Show navigation optimistically while waiting for context selection.
|
|
641
|
-
// Only hide navigation if user is not loaded.
|
|
642
|
-
// This prevents navigation from disappearing after initial render while waiting for context.
|
|
643
|
-
if (!hasUser) {
|
|
644
|
-
// User not loaded yet - show all items until user is ready
|
|
645
|
-
if (isMounted) {
|
|
646
|
-
setFilteredMenuItems(baseMenuItems);
|
|
647
|
-
}
|
|
648
|
-
return;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// If no organisation context yet, show items optimistically
|
|
652
|
-
// This allows users to see navigation while they select a context
|
|
653
|
-
// Only proceed with permission filtering once context is selected
|
|
654
|
-
if (!hasOrganisationContext) {
|
|
655
|
-
if (isMounted) {
|
|
656
|
-
// Show items optimistically when org selector is enabled, otherwise show all items
|
|
657
|
-
// This prevents navigation from disappearing while waiting for organisation selection
|
|
658
|
-
setFilteredMenuItems(baseMenuItems);
|
|
659
|
-
}
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
// For super admins, show all items (they bypass permission checks)
|
|
664
|
-
// Gracefully handle RBAC not being initialized (e.g., in tests)
|
|
665
|
-
try {
|
|
666
|
-
const { isSuperAdmin: checkSuperAdminDynamic } = await import('../../rbac/api');
|
|
667
|
-
const isSuper = await checkSuperAdminDynamic(user.id);
|
|
668
|
-
|
|
669
|
-
if (isSuper) {
|
|
670
|
-
// Super admins see all navigation items
|
|
671
|
-
if (isMounted) {
|
|
672
|
-
setFilteredMenuItems(baseMenuItems);
|
|
673
|
-
}
|
|
674
|
-
return;
|
|
675
|
-
}
|
|
676
|
-
} catch (error) {
|
|
677
|
-
// If RBAC is not initialized (e.g., in tests), continue with normal filtering
|
|
678
|
-
// This prevents errors from breaking navigation when RBAC isn't available
|
|
679
|
-
if (error && typeof error === 'object' && 'code' in error && error.code === 'RBAC_NOT_INITIALIZED') {
|
|
680
|
-
// RBAC not available - proceed with normal filtering without super admin check
|
|
681
|
-
// In this case, we'll filter items normally based on permissions
|
|
682
|
-
} else {
|
|
683
|
-
// Re-throw unexpected errors
|
|
684
|
-
throw error;
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
// Organisation context is ready - now filter items based on permissions
|
|
689
|
-
// OPTIMIZATION: Use batch permission map instead of individual checks to avoid rate limits
|
|
690
|
-
// This makes 1 call instead of N calls (where N = number of navigation items)
|
|
691
|
-
// OPTIMIZATION: Proceed even if appId is still resolving - permission checks work with organisationId
|
|
692
|
-
try {
|
|
693
|
-
const { getPermissionMap } = await import('../../rbac/api');
|
|
694
|
-
|
|
695
|
-
// Build scope for permission check - use appId if available, but don't wait for it
|
|
696
|
-
// Permission checks will work with resource permissions even without appId
|
|
697
|
-
const permissionScope: Scope = {
|
|
698
|
-
organisationId: currentScope.organisationId,
|
|
699
|
-
eventId: currentScope.eventId,
|
|
700
|
-
appId: currentScope.appId || resolvedAppId || undefined // Use appId if available, but proceed without it
|
|
701
|
-
};
|
|
702
|
-
|
|
703
|
-
const permissionMap = await getPermissionMap({
|
|
704
|
-
userId: user.id,
|
|
705
|
-
scope: permissionScope,
|
|
706
|
-
});
|
|
707
|
-
|
|
708
|
-
// Filter items using the permission map and scope type
|
|
709
|
-
// First, get scope types for all pages (batch if possible, or individual)
|
|
710
|
-
const { getPageScopeType } = await import('../../rbac/api');
|
|
711
|
-
const effectiveAppId = currentScope.appId || resolvedAppId;
|
|
712
|
-
const effectiveAppName = appName;
|
|
713
|
-
|
|
714
|
-
// Determine current context type for scope filtering
|
|
715
|
-
const hasEventContext = !!currentScope.eventId;
|
|
716
|
-
const hasOrgContext = !!currentScope.organisationId;
|
|
717
|
-
|
|
718
|
-
// Filter items using both permission map and scope type
|
|
719
|
-
const filtered = await Promise.all(
|
|
720
|
-
baseMenuItems.map(async (item) => {
|
|
721
|
-
if (!item.href) return { item, hasAccess: true, matchesScope: true, scopeCheckError: false };
|
|
722
|
-
|
|
723
|
-
// Extract page ID from href: remove leading slash, fallback to 'dashboard' for root
|
|
724
|
-
// This matches database page names in rbac_app_pages
|
|
725
|
-
const pageId = pageIdMapping[item.href] || (item.href === '/' ? 'dashboard' : item.href.slice(1)) || 'dashboard';
|
|
726
|
-
const permission = routePermissions[item.href] || defaultPermission;
|
|
727
|
-
const fullPermission: Permission = permission.includes(':')
|
|
728
|
-
? (permission as Permission)
|
|
729
|
-
: (pageId ? `${permission}:page.${pageId}` : permission) as Permission;
|
|
730
|
-
|
|
731
|
-
// Check permission map (super admin check already handled in getPermissionMap)
|
|
732
|
-
const hasAccess = permissionMap['*'] === true || permissionMap[fullPermission] === true;
|
|
733
|
-
|
|
734
|
-
// Check scope type compatibility
|
|
735
|
-
let matchesScope = true;
|
|
736
|
-
let scopeCheckError = false;
|
|
737
|
-
if (effectiveAppId || effectiveAppName) {
|
|
738
|
-
try {
|
|
739
|
-
const pageScopeType = await getPageScopeType(
|
|
740
|
-
pageId,
|
|
741
|
-
effectiveAppId,
|
|
742
|
-
effectiveAppName
|
|
743
|
-
);
|
|
744
|
-
|
|
745
|
-
// Filter based on current context:
|
|
746
|
-
// - If event is selected: show only 'event' or 'both' pages
|
|
747
|
-
// - If only org is selected: show only 'organisation' or 'both' pages
|
|
748
|
-
if (hasEventContext) {
|
|
749
|
-
// Event context: show 'event' or 'both' pages only
|
|
750
|
-
matchesScope = pageScopeType === 'event' || pageScopeType === 'both';
|
|
751
|
-
} else if (hasOrgContext) {
|
|
752
|
-
// Organisation context only: show 'organisation' or 'both' pages only
|
|
753
|
-
matchesScope = pageScopeType === 'organisation' || pageScopeType === 'both';
|
|
754
|
-
} else {
|
|
755
|
-
// No context: show all pages (shouldn't happen, but safe fallback)
|
|
756
|
-
matchesScope = true;
|
|
757
|
-
}
|
|
758
|
-
} catch (error) {
|
|
759
|
-
// If we can't get scope type, allow the page (graceful degradation)
|
|
760
|
-
// This prevents navigation from disappearing if there's a database issue
|
|
761
|
-
scopeCheckError = true;
|
|
762
|
-
logger.warn('PaceAppLayout', 'Failed to get page scope type for navigation filtering', {
|
|
763
|
-
pageId,
|
|
764
|
-
href: item.href,
|
|
765
|
-
contextType: hasEventContext ? 'event' : (hasOrgContext ? 'organisation' : 'none'),
|
|
766
|
-
error: error instanceof Error ? error.message : String(error),
|
|
767
|
-
note: 'Allowing page to prevent navigation from disappearing - this may indicate missing scope_type in database'
|
|
768
|
-
});
|
|
769
|
-
matchesScope = true; // Default to allowing if we can't check
|
|
770
|
-
}
|
|
771
|
-
} else {
|
|
772
|
-
// No appId/appName available - can't check scope, allow the page
|
|
773
|
-
// This happens during initial load before app context is resolved
|
|
774
|
-
matchesScope = true;
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
return { item, hasAccess, matchesScope, scopeCheckError };
|
|
778
|
-
})
|
|
779
|
-
);
|
|
780
|
-
|
|
781
|
-
if (!isMounted) return;
|
|
782
|
-
|
|
783
|
-
const accessibleItems = filtered
|
|
784
|
-
.filter(({ hasAccess, matchesScope }) => hasAccess && matchesScope)
|
|
785
|
-
.map(({ item }) => item);
|
|
786
|
-
|
|
787
|
-
// If all items were filtered out, check if it's due to scope filtering
|
|
788
|
-
// This can happen if:
|
|
789
|
-
// 1. All pages are scoped for the other context type (expected behavior)
|
|
790
|
-
// 2. Scope type lookup failed for all pages (should fallback to showing items with permissions)
|
|
791
|
-
if (accessibleItems.length === 0 && filtered.length > 0) {
|
|
792
|
-
const itemsWithPermissions = filtered.filter(({ hasAccess }) => hasAccess);
|
|
793
|
-
const itemsFilteredByScope = filtered.filter(({ hasAccess, matchesScope }) => hasAccess && !matchesScope);
|
|
794
|
-
const itemsWithScopeErrors = filtered.filter(({ hasAccess, scopeCheckError }) => hasAccess && scopeCheckError);
|
|
795
|
-
|
|
796
|
-
// If scope checking failed for ALL items with permissions, fall back to showing them
|
|
797
|
-
// This prevents navigation from disappearing due to database/API issues
|
|
798
|
-
if (itemsWithPermissions.length > 0 &&
|
|
799
|
-
itemsWithScopeErrors.length === itemsWithPermissions.length) {
|
|
800
|
-
logger.warn('PaceAppLayout', 'Scope checking failed for all items - falling back to permission-only filtering', {
|
|
801
|
-
contextType: hasEventContext ? 'event' : (hasOrgContext ? 'organisation' : 'none'),
|
|
802
|
-
totalItems: baseMenuItems.length,
|
|
803
|
-
itemsWithPermissions: itemsWithPermissions.length,
|
|
804
|
-
scopeCheckErrorCount: itemsWithScopeErrors.length,
|
|
805
|
-
note: 'Showing items based on permissions only - scope filtering disabled due to errors. This may indicate database issues or missing scope_type values.'
|
|
806
|
-
});
|
|
807
|
-
|
|
808
|
-
// Fall back to showing items that have permissions (ignore scope check)
|
|
809
|
-
const fallbackItems = filtered
|
|
810
|
-
.filter(({ hasAccess }) => hasAccess)
|
|
811
|
-
.map(({ item }) => item);
|
|
812
|
-
|
|
813
|
-
if (isMounted && fallbackItems.length > 0) {
|
|
814
|
-
setFilteredMenuItems(fallbackItems);
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
} else if (itemsWithPermissions.length > 0 && itemsFilteredByScope.length === itemsWithPermissions.length) {
|
|
818
|
-
// All items were filtered by scope (not errors) - this is expected if all pages are scoped for other context
|
|
819
|
-
logger.info('PaceAppLayout', 'All navigation items filtered out by scope type', {
|
|
820
|
-
contextType: hasEventContext ? 'event' : (hasOrgContext ? 'organisation' : 'none'),
|
|
821
|
-
totalItems: baseMenuItems.length,
|
|
822
|
-
itemsWithPermissions: itemsWithPermissions.length,
|
|
823
|
-
itemsFilteredByScope: itemsFilteredByScope.length,
|
|
824
|
-
note: 'All pages appear to be scoped for a different context type - this is expected behavior. Navigation will be empty until user selects the appropriate context.'
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
// SECURITY: Never show all items if permission check fails - this would be a security risk
|
|
830
|
-
// If all items are filtered out, it means the user doesn't have permission to see any navigation
|
|
831
|
-
// OR all pages are scoped for a different context type
|
|
832
|
-
// This is the correct behavior - better to show nothing than show unauthorized items
|
|
833
|
-
setFilteredMenuItems(accessibleItems);
|
|
834
|
-
} catch (error) {
|
|
835
|
-
// On error, fall back to showing all items (graceful degradation)
|
|
836
|
-
// This prevents navigation from being empty if permission checks fail
|
|
837
|
-
logger.error('PaceAppLayout', 'Failed to load permission map for navigation filtering', { userId: user?.id, error });
|
|
838
|
-
if (isMounted) {
|
|
839
|
-
setFilteredMenuItems(baseMenuItems);
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
};
|
|
843
|
-
|
|
844
|
-
filterItems();
|
|
509
|
+
appName,
|
|
510
|
+
isSuperAdminFromRBAC,
|
|
511
|
+
isSuperAdminDirect,
|
|
512
|
+
isCheckingSuperAdminDirect,
|
|
513
|
+
isSuperAdmin,
|
|
514
|
+
});
|
|
845
515
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
516
|
+
const filteredMenuItems = useFilteredNavItems({
|
|
517
|
+
baseMenuItems,
|
|
518
|
+
user,
|
|
519
|
+
scope,
|
|
520
|
+
routePermissions: config.routePermissions,
|
|
521
|
+
defaultPermission: config.defaultPermission,
|
|
522
|
+
pageIdMapping: config.pageIdMapping,
|
|
523
|
+
appName,
|
|
524
|
+
resolvedAppId,
|
|
525
|
+
scopeLoading,
|
|
526
|
+
contextAppId,
|
|
527
|
+
resolvedScopeAppId: resolvedAppId,
|
|
528
|
+
selectedOrganisationId: selectedOrganisation?.id,
|
|
529
|
+
selectedEventId: selectedEvent?.event_id ?? null,
|
|
530
|
+
});
|
|
850
531
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
// Route not found in configuration
|
|
864
|
-
if (strictMode) {
|
|
865
|
-
logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: Route not found in configuration', {
|
|
866
|
-
route: currentPath,
|
|
867
|
-
userId: user?.id,
|
|
868
|
-
timestamp: new Date().toISOString()
|
|
869
|
-
});
|
|
870
|
-
|
|
871
|
-
if (onRouteStrictModeViolation) {
|
|
872
|
-
onRouteStrictModeViolation(currentPath, 'Route not found in configuration');
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
return;
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
// Check permissions using useCan hook result
|
|
879
|
-
let hasAccess = true; // Default to true if no permission requirements
|
|
880
|
-
|
|
881
|
-
// Check page permissions
|
|
882
|
-
if (currentRoute.pageId && currentRoute.permissions && currentRoute.permissions.length > 0) {
|
|
883
|
-
// Use the permission check result from useCan hook
|
|
884
|
-
// For now, we'll use a simple check - in future we might need useMultiplePermissions here
|
|
885
|
-
try {
|
|
886
|
-
const { isPermittedCached } = await import('../../rbac/api');
|
|
887
|
-
const hasPagePermission = await isPermittedCached({
|
|
888
|
-
userId: user?.id || '',
|
|
889
|
-
scope,
|
|
890
|
-
permission: currentRoute.permissions[0] as Permission,
|
|
891
|
-
pageId: currentRoute.pageId,
|
|
892
|
-
});
|
|
893
|
-
if (!isMounted) return;
|
|
894
|
-
hasAccess = hasPagePermission;
|
|
895
|
-
} catch (error) {
|
|
896
|
-
logger.error('PaceAppLayout', 'Failed to check page permission', { route: currentPath, pageId: currentRoute.pageId, error });
|
|
897
|
-
if (!isMounted) return;
|
|
898
|
-
hasAccess = false;
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
// If permission check passed or not required, check roles
|
|
903
|
-
if (hasAccess && currentRoute.roles && currentRoute.roles.length > 0 && user?.id) {
|
|
904
|
-
const { useUnifiedAuth } = await import('../../providers/services/UnifiedAuthProvider');
|
|
905
|
-
// Note: We're already in the component with authContext via useUnifiedAuth at top
|
|
906
|
-
// For this feature to work properly, we need the auth context
|
|
907
|
-
// This is a limitation of the current implementation
|
|
908
|
-
hasAccess = true; // Will be properly implemented when auth context is available in this effect
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
if (!isMounted) return;
|
|
912
|
-
|
|
913
|
-
if (!hasAccess) {
|
|
914
|
-
// Handle route access denied
|
|
915
|
-
if (onRouteAccessDenied) {
|
|
916
|
-
onRouteAccessDenied(currentPath, 'Insufficient permissions');
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
if (strictMode) {
|
|
920
|
-
logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: User attempted to access protected route without permission', {
|
|
921
|
-
route: currentPath,
|
|
922
|
-
userId: user?.id,
|
|
923
|
-
permissions: currentRoute.permissions,
|
|
924
|
-
roles: currentRoute.roles,
|
|
925
|
-
accessLevel: currentRoute.accessLevel,
|
|
926
|
-
timestamp: new Date().toISOString()
|
|
927
|
-
});
|
|
928
|
-
|
|
929
|
-
if (onRouteStrictModeViolation) {
|
|
930
|
-
onRouteStrictModeViolation(currentPath, 'Insufficient permissions');
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
// Redirect to fallback route
|
|
935
|
-
navigate(fallbackRoute, { replace: true });
|
|
936
|
-
return;
|
|
937
|
-
}
|
|
938
|
-
};
|
|
939
|
-
|
|
940
|
-
checkRouteAccess();
|
|
941
|
-
|
|
942
|
-
return () => {
|
|
943
|
-
isMounted = false;
|
|
944
|
-
};
|
|
945
|
-
}, [roleBasedRouting, routeConfig, location.pathname, strictMode, user?.id, fallbackRoute, scope, navigate, auditLog, onRouteAccessDenied, onRouteStrictModeViolation]);
|
|
532
|
+
useRoleBasedRouteAccess({
|
|
533
|
+
roleBasedRouting: config.roleBasedRouting,
|
|
534
|
+
routeConfig: config.routeConfig,
|
|
535
|
+
currentPath: location.pathname,
|
|
536
|
+
user,
|
|
537
|
+
scope,
|
|
538
|
+
strictMode: config.strictMode,
|
|
539
|
+
fallbackRoute: config.fallbackRoute,
|
|
540
|
+
navigate,
|
|
541
|
+
onRouteAccessDenied: config.onRouteAccessDenied,
|
|
542
|
+
onRouteStrictModeViolation: config.onRouteStrictModeViolation,
|
|
543
|
+
});
|
|
946
544
|
|
|
947
545
|
const handleSignOut = async () => {
|
|
948
546
|
try {
|
|
949
547
|
await signOut();
|
|
950
548
|
} catch (error) {
|
|
951
|
-
logger.error('PaceAppLayout', 'Failed to sign out', {
|
|
549
|
+
logger.error('PaceAppLayout', 'Failed to sign out', {
|
|
550
|
+
error: error instanceof Error ? error.message : String(error),
|
|
551
|
+
});
|
|
952
552
|
}
|
|
953
553
|
};
|
|
954
554
|
|
|
955
|
-
const handleChangePassword = async (newPassword: string,
|
|
555
|
+
const handleChangePassword = async (newPassword: string, _confirmPassword: string) => {
|
|
956
556
|
try {
|
|
957
|
-
// The form component in UserMenu already checks for matching passwords
|
|
958
557
|
const result = await updatePassword(newPassword);
|
|
959
|
-
if (result
|
|
960
|
-
// The form will display the error message
|
|
558
|
+
if (!result.ok) {
|
|
961
559
|
logger.error('PaceAppLayout', 'Failed to change password', { error: result.error.message });
|
|
962
|
-
|
|
963
|
-
return {
|
|
964
|
-
error: {
|
|
965
|
-
message: result.error.message,
|
|
966
|
-
code: result.error.name || 'PASSWORD_UPDATE_ERROR'
|
|
967
|
-
}
|
|
968
|
-
};
|
|
560
|
+
return { error: { message: result.error.message, code: result.error.code || 'PASSWORD_UPDATE_ERROR' } };
|
|
969
561
|
}
|
|
970
|
-
// The form will handle closing the modal on success
|
|
971
562
|
return {};
|
|
972
563
|
} catch (error) {
|
|
973
|
-
logger.error('PaceAppLayout', 'Failed to change password', {
|
|
564
|
+
logger.error('PaceAppLayout', 'Failed to change password', {
|
|
565
|
+
error: error instanceof Error ? error.message : String(error),
|
|
566
|
+
});
|
|
974
567
|
return {
|
|
975
568
|
error: {
|
|
976
569
|
message: error instanceof Error ? error.message : 'An unexpected error occurred',
|
|
977
|
-
code: 'PASSWORD_UPDATE_ERROR'
|
|
978
|
-
}
|
|
570
|
+
code: 'PASSWORD_UPDATE_ERROR',
|
|
571
|
+
},
|
|
979
572
|
};
|
|
980
573
|
}
|
|
981
574
|
};
|
|
982
575
|
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
return (
|
|
1001
|
-
<p className="grid place-items-center text-center size-full">
|
|
1002
|
-
<LoadingSpinner
|
|
1003
|
-
size="lg"/><br />
|
|
1004
|
-
Loading organisation context...
|
|
1005
|
-
</p>
|
|
1006
|
-
);
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
// Once loading is complete (whether success or error), allow rendering to proceed
|
|
1010
|
-
// For users without organisations, allow access to profile pages (dashboard, member-profile, medical-profile, additional-contacts)
|
|
1011
|
-
// These pages work with user context only and don't require organisation context
|
|
1012
|
-
// The app can check hasValidOrganisationContext() to determine if org context is available for org-specific features
|
|
1013
|
-
|
|
1014
|
-
// Show loading state while checking permissions
|
|
1015
|
-
// Keep loading active until permission check completes to prevent exposing protected content
|
|
1016
|
-
// Super admin status is checked via useRBAC hook (isSuperAdminFromRBAC)
|
|
1017
|
-
if (enforcePermissions && isCheckingPermission) {
|
|
1018
|
-
return (
|
|
1019
|
-
<p className="grid place-items-center text-center size-full">
|
|
1020
|
-
<LoadingSpinner
|
|
1021
|
-
size="lg"/><br />
|
|
1022
|
-
Checking permissions...
|
|
1023
|
-
</p>
|
|
1024
|
-
);
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
// Show permission error (only after check is complete)
|
|
1028
|
-
// Super admins bypass all permission checks, so don't show errors for them
|
|
1029
|
-
// Context errors (missing event/org) should allow the page to render so it can show helpful messaging
|
|
1030
|
-
// Real permission errors should still show "Access Denied"
|
|
1031
|
-
if (enforcePermissions && permissionError && !isSuperAdmin && !isContextError) {
|
|
1032
|
-
return (
|
|
1033
|
-
<hgroup className="grid place-items-center text-center size-full">
|
|
1034
|
-
<h2>Permission Error</h2>
|
|
1035
|
-
<p>{permissionError.message}</p>
|
|
1036
|
-
<Button onClick={() => navigate('/')}>Go Home</Button>
|
|
1037
|
-
</hgroup>
|
|
1038
|
-
);
|
|
1039
|
-
}
|
|
576
|
+
const { gateContent } = usePaceAppLayoutGate({
|
|
577
|
+
user,
|
|
578
|
+
organisationLoading,
|
|
579
|
+
isSuperAdmin,
|
|
580
|
+
isCheckingSuperAdminDirect,
|
|
581
|
+
rbacLoading,
|
|
582
|
+
selectedOrganisationId,
|
|
583
|
+
enforcePermissions: config.enforcePermissions,
|
|
584
|
+
isCheckingPermission: permissions.isCheckingPermission,
|
|
585
|
+
permissionError: permissions.permissionError,
|
|
586
|
+
isContextError: permissions.isContextError,
|
|
587
|
+
hasPermission: permissions.hasPermission,
|
|
588
|
+
enforcePagePermissions: config.enforcePagePermissions,
|
|
589
|
+
pagePermissionFallback: config.pagePermissionFallback,
|
|
590
|
+
permissionFallback: config.permissionFallback,
|
|
591
|
+
onSignOut: handleSignOut,
|
|
592
|
+
});
|
|
1040
593
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
// Skip if it's a context error (missing event/org) - allow page to render and show helpful messaging
|
|
1044
|
-
if (enforcePermissions && hasPermission === false && !isCheckingSuperAdminDirect && !isSuperAdmin && !isContextError) {
|
|
1045
|
-
// NEW: Phase 1 - Use page permission fallback if available
|
|
1046
|
-
if (enforcePagePermissions && pagePermissionFallback) {
|
|
1047
|
-
return <>{pagePermissionFallback}</>;
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
if (permissionFallback) {
|
|
1051
|
-
return <>{permissionFallback}</>;
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
return (
|
|
1055
|
-
<AccessDenied
|
|
1056
|
-
message="You don't have permission to access this page."
|
|
1057
|
-
onGoBack={() => navigate('/')}
|
|
1058
|
-
onSignOut={async () => {
|
|
1059
|
-
await handleSignOut();
|
|
1060
|
-
navigate('/login');
|
|
1061
|
-
}}
|
|
1062
|
-
showSignOut={true}
|
|
1063
|
-
/>
|
|
1064
|
-
);
|
|
594
|
+
if (gateContent !== null) {
|
|
595
|
+
return <>{gateContent}</>;
|
|
1065
596
|
}
|
|
1066
597
|
|
|
1067
598
|
return (
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
}
|
|
1085
|
-
}}
|
|
1086
|
-
showContextSelector={showContextSelector}
|
|
1087
|
-
showOrganisations={showOrganisations}
|
|
1088
|
-
showEvents={showEvents}
|
|
1089
|
-
showUserMenu={showUserMenu}
|
|
1090
|
-
className={headerClassName || "sticky top-0 z-[40] w-full"}
|
|
1091
|
-
/>
|
|
1092
|
-
<main className="px-4 w-[min(var(--app-width),100%)] mx-auto py-8">
|
|
1093
|
-
<Outlet />
|
|
1094
|
-
</main>
|
|
1095
|
-
<Footer />
|
|
1096
|
-
</>
|
|
599
|
+
<PaceAppLayoutContent
|
|
600
|
+
appName={appName}
|
|
601
|
+
logoHref={logoHref}
|
|
602
|
+
filteredMenuItems={filteredMenuItems}
|
|
603
|
+
headerActions={headerActions}
|
|
604
|
+
customUserMenu={customUserMenu}
|
|
605
|
+
user={user}
|
|
606
|
+
onSignOut={handleSignOut}
|
|
607
|
+
onChangePassword={handleChangePassword}
|
|
608
|
+
headerClassName={headerClassName}
|
|
609
|
+
showContextSelector={showContextSelector}
|
|
610
|
+
showOrganisations={showOrganisations}
|
|
611
|
+
showEvents={showEvents}
|
|
612
|
+
showUserMenu={showUserMenu}
|
|
613
|
+
navigate={navigate}
|
|
614
|
+
/>
|
|
1097
615
|
);
|
|
1098
616
|
}
|