@jmruthers/pace-core 0.6.6 → 0.6.8
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/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +227 -22
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +240 -0
- package/audit-tool/audits/03-architecture.cjs +224 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +554 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +355 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +295 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +380 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/{00-pace-core-compliance.mdc → 01-pace-core-compliance.mdc} +187 -34
- package/cursor-rules/02-project-structure.mdc +37 -5
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +125 -11
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +55 -10
- package/cursor-rules/{09-rbac-compliance.mdc → 06-security-rbac.mdc} +62 -6
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/DataTable-6RMSCQJ6.js +15 -0
- package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-CIGSujI2.d.ts} +40 -24
- package/dist/{UnifiedAuthProvider-ZT6TIGM7.js → UnifiedAuthProvider-7SNDOWYD.js} +2 -2
- package/dist/{api-Y4MQWOFW.js → api-7P7DI652.js} +1 -1
- package/dist/{chunk-MAGBIDNS.js → chunk-4DDCYDQ3.js} +8 -7
- package/dist/{chunk-BVP2BCJF.js → chunk-5W2A3DRC.js} +10 -9
- package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
- package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
- package/dist/{chunk-3O3WHILE.js → chunk-EF2UGZWY.js} +239 -63
- package/dist/{chunk-LAZMKTTF.js → chunk-EURB7QFZ.js} +341 -337
- package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
- package/dist/{chunk-7TYHROIV.js → chunk-GS5672WG.js} +55 -13
- package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
- package/dist/{chunk-ZFYPMX46.js → chunk-LX6U42O3.js} +1 -1
- package/dist/{chunk-FENMYN2U.js → chunk-MPBLMWVR.js} +3 -3
- package/dist/{chunk-ZS5VO5JB.js → chunk-NKHKXPI4.js} +408 -453
- package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
- package/dist/{chunk-4T7OBVTU.js → chunk-S6ZQKDY6.js} +1 -1
- package/dist/{chunk-FTCRZOG2.js → chunk-T5CVK4R3.js} +5 -5
- package/dist/{chunk-OHIK3MIO.js → chunk-Z2FNRKF3.js} +13 -13
- package/dist/components.d.ts +5 -4
- package/dist/components.js +29 -34
- package/dist/eslint-rules/index.cjs +22 -9
- package/{src/eslint-rules/rules/compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +184 -23
- package/dist/eslint-rules/rules/04-code-quality.cjs +346 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/{rbac.cjs → 06-security-rbac.cjs} +34 -13
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +385 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/{functions-DHebl8-F.d.ts → functions-lBy5L2ry.d.ts} +1 -1
- package/dist/hooks.d.ts +5 -5
- package/dist/hooks.js +8 -8
- package/dist/index.d.ts +7 -7
- package/dist/index.js +21 -20
- package/dist/providers.js +2 -2
- package/dist/rbac/index.d.ts +1 -1
- package/dist/rbac/index.js +8 -8
- package/dist/theming/runtime.d.ts +61 -1
- package/dist/theming/runtime.js +1 -1
- package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
- package/dist/types.d.ts +2 -2
- package/dist/{usePublicRouteParams-COZ28Mvq.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +19 -19
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +8 -8
- package/docs/README.md +1 -1
- package/docs/api/modules.md +106 -41
- package/docs/api-reference/components.md +18 -20
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/dependencies.md +23 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/implementation-guides/app-layout.md +1 -1
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +127 -34
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +1 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/README.md +5 -5
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -1
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/{00-pace-core-compliance.md → 1-pace-core-compliance-standards.md} +241 -185
- package/docs/standards/{02-project-structure.md → 2-project-structure-standards.md} +11 -47
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/{08-markup-quality.md → 5-styling-standards.md} +12 -9
- package/docs/standards/{09-rbac-compliance.md → 6-security-rbac-standards.md} +126 -18
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +203 -104
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/eslint-config-pace-core.cjs +50 -20
- package/package.json +50 -19
- package/scripts/eslint-audit.cjs +123 -0
- package/scripts/install-cursor-rules.cjs +11 -243
- package/scripts/install-eslint-config.cjs +349 -0
- package/scripts/validate-dependencies.cjs +248 -0
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +30 -18
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +10 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/AddressField/AddressField.tsx +26 -1
- package/src/components/Alert/Alert.test.tsx +86 -22
- package/src/components/Alert/Alert.tsx +19 -11
- package/src/components/Badge/Badge.tsx +1 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/Checkbox/Checkbox.test.tsx +2 -1
- package/src/components/ContextSelector/ContextSelector.tsx +108 -126
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/DataTable.tsx +1 -19
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +6 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +21 -6
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +3 -2
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +5 -16
- package/src/components/DataTable/components/EditableRow.tsx +5 -7
- package/src/components/DataTable/components/EmptyState.tsx +11 -10
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +45 -27
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/types.ts +0 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +7 -8
- package/src/components/Dialog/Dialog.test.tsx +1 -0
- package/src/components/Dialog/Dialog.tsx +25 -8
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileUpload/FileUpload.test.tsx +45 -16
- package/src/components/FileUpload/FileUpload.tsx +141 -130
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +48 -12
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +9 -9
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +30 -30
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +4 -4
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +7 -1
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +86 -77
- package/src/components/Select/types.ts +3 -0
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +49 -49
- package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +8 -5
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +4 -0
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +99 -99
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +45 -8
- package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +22 -2
- package/src/hooks/public/usePublicEvent.ts +5 -5
- package/src/hooks/public/usePublicEventLogo.ts +5 -5
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +13 -9
- package/src/hooks/useAddressAutocomplete.test.ts +18 -18
- package/src/hooks/useAppConfig.ts +2 -2
- package/src/hooks/useEventTheme.test.ts +7 -7
- package/src/hooks/useEventTheme.ts +2 -1
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useFileUrl.ts +52 -8
- package/src/hooks/useOrganisationSecurity.test.ts +2 -1
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +38 -38
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +15 -6
- package/src/rbac/__tests__/rbac-functions.test.ts +3 -3
- package/src/rbac/api.test.ts +104 -0
- package/src/rbac/engine.ts +1 -1
- package/src/rbac/hooks/useCan.test.ts +2 -2
- package/src/rbac/secureClient.ts +1 -1
- package/src/rbac/types/functions.ts +1 -1
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +118 -3
- package/src/theming/parseEventColours.ts +77 -11
- package/src/types/supabase.ts +2 -3
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +9 -9
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/file-reference/__tests__/file-reference.test.ts +4 -0
- package/src/utils/formatting/formatDate.test.ts +3 -2
- package/src/utils/formatting/formatDateTime.test.ts +2 -2
- package/src/utils/google-places/googlePlacesUtils.test.ts +36 -24
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/__tests__/helpers.unit.test.ts +19 -12
- package/src/utils/storage/helpers.test.ts +69 -3
- package/cursor-rules/01-standards-compliance.mdc +0 -285
- package/cursor-rules/04-testing-standards.mdc +0 -270
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -248
- package/cursor-rules/06-code-quality.mdc +0 -311
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -216
- package/cursor-rules/10-error-handling-patterns.mdc +0 -179
- package/cursor-rules/11-performance-optimization.mdc +0 -169
- package/cursor-rules/12-ci-cd-integration.mdc +0 -150
- package/dist/DataTable-LRJL4IRV.js +0 -15
- package/dist/eslint-rules/rules/compliance.cjs +0 -348
- package/dist/eslint-rules/rules/components.cjs +0 -113
- package/dist/eslint-rules/rules/imports.cjs +0 -102
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -604
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-standards-compliance.md +0 -188
- package/docs/standards/03-solid-principles.md +0 -39
- package/docs/standards/04-testing-standards.md +0 -36
- package/docs/standards/05-bug-reports-and-features.md +0 -27
- package/docs/standards/06-code-quality.md +0 -34
- package/docs/standards/07-tech-stack-compliance.md +0 -30
- package/docs/standards/10-error-handling-patterns.md +0 -401
- package/docs/standards/11-performance-optimization.md +0 -348
- package/docs/standards/12-ci-cd-integration.md +0 -370
- package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +0 -192
- package/scripts/audit/audit-compliance.cjs +0 -1295
- package/scripts/audit/audit-components.cjs +0 -260
- package/scripts/audit/audit-rbac.cjs +0 -954
- package/scripts/audit/audit-standards.cjs +0 -1268
- package/scripts/audit/index.cjs +0 -1927
- package/src/components/DataTable/components/DataTableBody.tsx +0 -478
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/index.cjs +0 -22
- package/src/eslint-rules/rules/components.cjs +0 -113
- package/src/eslint-rules/rules/imports.cjs +0 -102
- package/src/eslint-rules/rules/rbac.cjs +0 -790
- package/src/eslint-rules/utils/helpers.cjs +0 -42
- package/src/eslint-rules/utils/manifest-loader.cjs +0 -75
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React from 'react';
|
|
7
|
-
import { screen, waitFor } from '@testing-library/react';
|
|
7
|
+
import { screen, waitFor, act } from '@testing-library/react';
|
|
8
8
|
import userEvent from '@testing-library/user-event';
|
|
9
9
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
10
10
|
import { NavigationMenu } from './NavigationMenu';
|
|
@@ -716,7 +716,7 @@ describe('NavigationMenu Component', () => {
|
|
|
716
716
|
expect(screen.getByText('Home')).toBeInTheDocument();
|
|
717
717
|
}, { interval: 10 });
|
|
718
718
|
|
|
719
|
-
const homeItem = screen.
|
|
719
|
+
const homeItem = screen.getByRole('option', { name: 'Home' });
|
|
720
720
|
await user.click(homeItem);
|
|
721
721
|
|
|
722
722
|
expect(mockNavigate).toHaveBeenCalledWith(
|
|
@@ -748,7 +748,7 @@ describe('NavigationMenu Component', () => {
|
|
|
748
748
|
expect(screen.getByText('Home')).toBeInTheDocument();
|
|
749
749
|
}, { interval: 10 });
|
|
750
750
|
|
|
751
|
-
const homeItem = screen.
|
|
751
|
+
const homeItem = screen.getByRole('option', { name: 'Home' });
|
|
752
752
|
await user.click(homeItem);
|
|
753
753
|
|
|
754
754
|
expect(window.location.href).toBe('/');
|
|
@@ -1350,14 +1350,16 @@ describe('NavigationMenu Component', () => {
|
|
|
1350
1350
|
items={basicNavItems}
|
|
1351
1351
|
onNavigate={mockNavigate}
|
|
1352
1352
|
buttonText="Menu"
|
|
1353
|
+
itemsPreFiltered={true}
|
|
1353
1354
|
/>
|
|
1354
1355
|
);
|
|
1355
1356
|
|
|
1356
1357
|
const openMenu = async () => {
|
|
1357
1358
|
await user.click(screen.getByRole('combobox'));
|
|
1358
1359
|
await waitFor(() => {
|
|
1359
|
-
|
|
1360
|
-
|
|
1360
|
+
// Items should appear as options in the listbox
|
|
1361
|
+
expect(screen.getByRole('option', { name: 'Home' })).toBeInTheDocument();
|
|
1362
|
+
}, { interval: 10, timeout: 3000 });
|
|
1361
1363
|
};
|
|
1362
1364
|
|
|
1363
1365
|
await openMenu();
|
|
@@ -1367,10 +1369,38 @@ describe('NavigationMenu Component', () => {
|
|
|
1367
1369
|
items={basicNavItems}
|
|
1368
1370
|
onNavigate={mockNavigate}
|
|
1369
1371
|
buttonText="Menu"
|
|
1372
|
+
itemsPreFiltered={true}
|
|
1370
1373
|
/>
|
|
1371
1374
|
);
|
|
1372
1375
|
|
|
1373
|
-
|
|
1376
|
+
// Wait for rerender to complete and component to be ready
|
|
1377
|
+
await waitFor(() => {
|
|
1378
|
+
const combobox = screen.getByRole('combobox');
|
|
1379
|
+
expect(combobox).toBeInTheDocument();
|
|
1380
|
+
expect(combobox).not.toBeDisabled();
|
|
1381
|
+
}, { interval: 10, timeout: 1000 });
|
|
1382
|
+
|
|
1383
|
+
// The Select component may keep the menu open after rerender
|
|
1384
|
+
// Check if menu is still open, and if so, verify items are still visible
|
|
1385
|
+
// If closed, open it again to verify items remain visible
|
|
1386
|
+
const combobox = screen.getByRole('combobox');
|
|
1387
|
+
const isOpen = combobox.getAttribute('aria-expanded') === 'true';
|
|
1388
|
+
|
|
1389
|
+
if (!isOpen) {
|
|
1390
|
+
// Menu closed, open it again
|
|
1391
|
+
await user.click(combobox);
|
|
1392
|
+
await waitFor(() => {
|
|
1393
|
+
const updatedCombobox = screen.getByRole('combobox');
|
|
1394
|
+
expect(updatedCombobox).toHaveAttribute('aria-expanded', 'true');
|
|
1395
|
+
}, { interval: 10, timeout: 3000 });
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
// Now wait for items to appear as options in the visible listbox
|
|
1399
|
+
// This verifies that items remain visible after rerender during permission reload
|
|
1400
|
+
await waitFor(() => {
|
|
1401
|
+
// Items should appear as options in the listbox after rerender
|
|
1402
|
+
expect(screen.getByRole('option', { name: 'Home' })).toBeInTheDocument();
|
|
1403
|
+
}, { interval: 10, timeout: 3000 });
|
|
1374
1404
|
});
|
|
1375
1405
|
|
|
1376
1406
|
it('renders no selectable items when auth and RBAC providers are unavailable', async () => {
|
|
@@ -1423,14 +1453,16 @@ describe('NavigationMenu Component', () => {
|
|
|
1423
1453
|
items={basicNavItems}
|
|
1424
1454
|
onNavigate={mockNavigate}
|
|
1425
1455
|
buttonText="Menu"
|
|
1456
|
+
itemsPreFiltered={true}
|
|
1426
1457
|
/>
|
|
1427
1458
|
);
|
|
1428
1459
|
|
|
1429
1460
|
await user.click(screen.getByRole('combobox'));
|
|
1430
1461
|
|
|
1431
1462
|
await waitFor(() => {
|
|
1432
|
-
|
|
1433
|
-
expect(screen.
|
|
1463
|
+
// Items should appear as options in the listbox
|
|
1464
|
+
expect(screen.getByRole('option', { name: 'Home' })).toBeInTheDocument();
|
|
1465
|
+
expect(screen.getByRole('option', { name: 'Dashboard' })).toBeInTheDocument();
|
|
1434
1466
|
}, { interval: 10 });
|
|
1435
1467
|
});
|
|
1436
1468
|
});
|
|
@@ -1445,6 +1477,7 @@ describe('NavigationMenu Component', () => {
|
|
|
1445
1477
|
onNavigate={mockNavigate}
|
|
1446
1478
|
auditLog={true}
|
|
1447
1479
|
buttonText="Menu"
|
|
1480
|
+
itemsPreFiltered={true}
|
|
1448
1481
|
/>
|
|
1449
1482
|
);
|
|
1450
1483
|
|
|
@@ -1452,10 +1485,11 @@ describe('NavigationMenu Component', () => {
|
|
|
1452
1485
|
await user.click(trigger);
|
|
1453
1486
|
|
|
1454
1487
|
await waitFor(() => {
|
|
1455
|
-
|
|
1488
|
+
// Items should appear as options in the listbox
|
|
1489
|
+
expect(screen.getByRole('option', { name: 'Home' })).toBeInTheDocument();
|
|
1456
1490
|
}, { interval: 10 });
|
|
1457
1491
|
|
|
1458
|
-
const homeItem = screen.
|
|
1492
|
+
const homeItem = screen.getByRole('option', { name: 'Home' });
|
|
1459
1493
|
await user.click(homeItem);
|
|
1460
1494
|
|
|
1461
1495
|
// Note: NavigationMenu audit logging is currently commented out in the component
|
|
@@ -1479,6 +1513,7 @@ describe('NavigationMenu Component', () => {
|
|
|
1479
1513
|
onNavigate={mockNavigate}
|
|
1480
1514
|
auditLog={false}
|
|
1481
1515
|
buttonText="Menu"
|
|
1516
|
+
itemsPreFiltered={true}
|
|
1482
1517
|
/>
|
|
1483
1518
|
);
|
|
1484
1519
|
|
|
@@ -1486,10 +1521,11 @@ describe('NavigationMenu Component', () => {
|
|
|
1486
1521
|
await user.click(trigger);
|
|
1487
1522
|
|
|
1488
1523
|
await waitFor(() => {
|
|
1489
|
-
|
|
1524
|
+
// Items should appear as options in the listbox
|
|
1525
|
+
expect(screen.getByRole('option', { name: 'Home' })).toBeInTheDocument();
|
|
1490
1526
|
}, { interval: 10 });
|
|
1491
1527
|
|
|
1492
|
-
const homeItem = screen.
|
|
1528
|
+
const homeItem = screen.getByRole('option', { name: 'Home' });
|
|
1493
1529
|
await user.click(homeItem);
|
|
1494
1530
|
|
|
1495
1531
|
// Logger.debug should not be called when auditLog is disabled
|
|
@@ -439,7 +439,7 @@ const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
|
439
439
|
});
|
|
440
440
|
|
|
441
441
|
describe('Permission Check Performance', () => {
|
|
442
|
-
it('performs permission checks within threshold', async () => {
|
|
442
|
+
it('performs permission checks within threshold', { timeout: 6000 }, async () => {
|
|
443
443
|
// Ensure super admin check resolves immediately for performance testing
|
|
444
444
|
mockIsSuperAdmin.mockResolvedValue(false);
|
|
445
445
|
|
|
@@ -452,7 +452,7 @@ const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
|
452
452
|
// Wait for permission check to complete and component to render
|
|
453
453
|
await waitFor(() => {
|
|
454
454
|
expect(screen.getByTestId('mock-header')).toBeInTheDocument();
|
|
455
|
-
}
|
|
455
|
+
});
|
|
456
456
|
|
|
457
457
|
// Use real performance.now() for accurate timing (temporarily restore the spy)
|
|
458
458
|
// Note: We're measuring after mount, so this should be very fast
|
|
@@ -476,9 +476,9 @@ const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
|
476
476
|
// In coverage mode, just verify the component rendered successfully
|
|
477
477
|
expect(screen.getByTestId('mock-header')).toBeInTheDocument();
|
|
478
478
|
}
|
|
479
|
-
}
|
|
479
|
+
});
|
|
480
480
|
|
|
481
|
-
it('handles multiple permission checks efficiently', async () => {
|
|
481
|
+
it('handles multiple permission checks efficiently', { timeout: 6000 }, async () => {
|
|
482
482
|
// Ensure super admin check resolves immediately for performance testing
|
|
483
483
|
mockIsSuperAdmin.mockResolvedValue(false);
|
|
484
484
|
|
|
@@ -501,7 +501,7 @@ const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
|
501
501
|
// Wait for component to fully mount (including super admin check)
|
|
502
502
|
await waitFor(() => {
|
|
503
503
|
expect(screen.getByTestId('mock-header')).toBeInTheDocument();
|
|
504
|
-
}
|
|
504
|
+
});
|
|
505
505
|
|
|
506
506
|
// Use real performance.now() for accurate timing (temporarily restore the spy)
|
|
507
507
|
performanceNowSpy?.mockRestore();
|
|
@@ -527,7 +527,7 @@ const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
|
527
527
|
// In coverage mode, just verify the component rendered successfully
|
|
528
528
|
expect(screen.getByTestId('mock-header')).toBeInTheDocument();
|
|
529
529
|
}
|
|
530
|
-
}
|
|
530
|
+
});
|
|
531
531
|
|
|
532
532
|
it('handles permission check errors efficiently', async () => {
|
|
533
533
|
mockUseCanFn.mockReturnValue({
|
|
@@ -545,7 +545,7 @@ const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
|
545
545
|
|
|
546
546
|
await waitFor(() => {
|
|
547
547
|
expect(screen.getByText('Permission check failed')).toBeInTheDocument();
|
|
548
|
-
}
|
|
548
|
+
});
|
|
549
549
|
});
|
|
550
550
|
});
|
|
551
551
|
|
|
@@ -939,7 +939,7 @@ const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
|
939
939
|
await waitFor(() => {
|
|
940
940
|
expect(screen.getByTestId('header-actions')).toBeInTheDocument();
|
|
941
941
|
expect(screen.getByTestId('custom-user-menu')).toBeInTheDocument();
|
|
942
|
-
}
|
|
942
|
+
});
|
|
943
943
|
|
|
944
944
|
const endTime = performance.now();
|
|
945
945
|
const renderTime = endTime - startTime;
|
|
@@ -953,6 +953,6 @@ const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
|
953
953
|
// In coverage mode, verify component renders successfully (behavioral check)
|
|
954
954
|
expect(screen.getByTestId('mock-header')).toBeInTheDocument();
|
|
955
955
|
}
|
|
956
|
-
}
|
|
956
|
+
});
|
|
957
957
|
});
|
|
958
958
|
});
|
|
@@ -444,7 +444,7 @@ describe('PaceAppLayout Security', () => {
|
|
|
444
444
|
});
|
|
445
445
|
});
|
|
446
446
|
|
|
447
|
-
it('prevents access when user lacks permission', async () => {
|
|
447
|
+
it('prevents access when user lacks permission', { timeout: 3000 }, async () => {
|
|
448
448
|
// Ensure super admin check completes first
|
|
449
449
|
mockIsSuperAdmin.mockResolvedValueOnce(false);
|
|
450
450
|
|
|
@@ -465,7 +465,7 @@ describe('PaceAppLayout Security', () => {
|
|
|
465
465
|
// Wait for super admin check to complete and component to re-render
|
|
466
466
|
await waitFor(() => {
|
|
467
467
|
expect(mockIsSuperAdmin).toHaveBeenCalled();
|
|
468
|
-
}
|
|
468
|
+
});
|
|
469
469
|
|
|
470
470
|
// Wait a bit for the component to process the super admin check result
|
|
471
471
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
@@ -474,8 +474,8 @@ describe('PaceAppLayout Security', () => {
|
|
|
474
474
|
await waitFor(() => {
|
|
475
475
|
expect(screen.getByText('Access Denied')).toBeInTheDocument();
|
|
476
476
|
expect(screen.getByText("You don't have permission to access this page.")).toBeInTheDocument();
|
|
477
|
-
}
|
|
478
|
-
}
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
479
|
|
|
480
480
|
it('enforces route-specific permissions', async () => {
|
|
481
481
|
const routePermissions: Record<string, Operation> = {
|
|
@@ -501,7 +501,7 @@ describe('PaceAppLayout Security', () => {
|
|
|
501
501
|
});
|
|
502
502
|
});
|
|
503
503
|
|
|
504
|
-
it('handles permission check failures securely', async () => {
|
|
504
|
+
it('handles permission check failures securely', { timeout: 3000 }, async () => {
|
|
505
505
|
// Ensure super admin check completes first
|
|
506
506
|
mockIsSuperAdmin.mockResolvedValueOnce(false);
|
|
507
507
|
|
|
@@ -522,7 +522,7 @@ describe('PaceAppLayout Security', () => {
|
|
|
522
522
|
// Wait for super admin check to complete and component to re-render
|
|
523
523
|
await waitFor(() => {
|
|
524
524
|
expect(mockIsSuperAdmin).toHaveBeenCalled();
|
|
525
|
-
}
|
|
525
|
+
});
|
|
526
526
|
|
|
527
527
|
// Wait a bit for the component to process the super admin check result
|
|
528
528
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
@@ -531,8 +531,8 @@ describe('PaceAppLayout Security', () => {
|
|
|
531
531
|
// When permission check throws an error, should show Permission Error page
|
|
532
532
|
expect(screen.getByText('Permission Error')).toBeInTheDocument();
|
|
533
533
|
expect(screen.getByText('Permission check failed')).toBeInTheDocument();
|
|
534
|
-
}
|
|
535
|
-
}
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
536
|
|
|
537
537
|
it('prevents bypassing permission checks', async () => {
|
|
538
538
|
// Test that permission checks cannot be bypassed by manipulating props
|
|
@@ -562,7 +562,7 @@ describe('PaceAppLayout Security', () => {
|
|
|
562
562
|
});
|
|
563
563
|
|
|
564
564
|
describe('Navigation Security', () => {
|
|
565
|
-
it('filters navigation items based on permissions', async () => {
|
|
565
|
+
it('filters navigation items based on permissions', { timeout: 3000 }, async () => {
|
|
566
566
|
// Mock permission check to allow all permissions for navigation filtering
|
|
567
567
|
// The navigation filtering uses getPermissionMap which is already mocked
|
|
568
568
|
render(
|
|
@@ -582,8 +582,8 @@ describe('PaceAppLayout Security', () => {
|
|
|
582
582
|
// With permission enforcement enabled, the component should render normally
|
|
583
583
|
expect(screen.getByTestId('mock-header')).toBeInTheDocument();
|
|
584
584
|
expect(screen.getByTestId('mock-outlet')).toBeInTheDocument();
|
|
585
|
-
}
|
|
586
|
-
}
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
587
|
|
|
588
588
|
it('prevents navigation to unauthorized routes', () => {
|
|
589
589
|
render(
|
|
@@ -843,7 +843,7 @@ describe('PaceAppLayout Security', () => {
|
|
|
843
843
|
});
|
|
844
844
|
});
|
|
845
845
|
|
|
846
|
-
it('handles permission errors securely', async () => {
|
|
846
|
+
it('handles permission errors securely', { timeout: 3000 }, async () => {
|
|
847
847
|
// Ensure super admin check completes first
|
|
848
848
|
mockIsSuperAdmin.mockResolvedValueOnce(false);
|
|
849
849
|
|
|
@@ -864,17 +864,17 @@ describe('PaceAppLayout Security', () => {
|
|
|
864
864
|
// Wait for super admin check to complete and component to re-render
|
|
865
865
|
await waitFor(() => {
|
|
866
866
|
expect(mockIsSuperAdmin).toHaveBeenCalled();
|
|
867
|
-
}
|
|
867
|
+
});
|
|
868
868
|
|
|
869
869
|
// Wait a bit for the component to process the super admin check result
|
|
870
870
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
871
871
|
|
|
872
872
|
await waitFor(() => {
|
|
873
873
|
expect(screen.getByText('Access Denied')).toBeInTheDocument();
|
|
874
|
-
}
|
|
875
|
-
}
|
|
874
|
+
});
|
|
875
|
+
});
|
|
876
876
|
|
|
877
|
-
it('prevents information leakage in error messages', async () => {
|
|
877
|
+
it('prevents information leakage in error messages', { timeout: 3000 }, async () => {
|
|
878
878
|
// Ensure super admin check completes first
|
|
879
879
|
mockIsSuperAdmin.mockResolvedValueOnce(false);
|
|
880
880
|
|
|
@@ -902,7 +902,7 @@ describe('PaceAppLayout Security', () => {
|
|
|
902
902
|
// Wait for super admin check to complete and component to re-render
|
|
903
903
|
await waitFor(() => {
|
|
904
904
|
expect(mockIsSuperAdmin).toHaveBeenCalled();
|
|
905
|
-
}
|
|
905
|
+
});
|
|
906
906
|
|
|
907
907
|
// Wait a bit for the component to process the super admin check result
|
|
908
908
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
@@ -911,8 +911,8 @@ describe('PaceAppLayout Security', () => {
|
|
|
911
911
|
expect(screen.getByText('Permission Error')).toBeInTheDocument();
|
|
912
912
|
// Should not expose sensitive information
|
|
913
913
|
expect(screen.queryByText('password=secret123')).not.toBeInTheDocument();
|
|
914
|
-
}
|
|
915
|
-
}
|
|
914
|
+
});
|
|
915
|
+
});
|
|
916
916
|
});
|
|
917
917
|
|
|
918
918
|
describe('Session Security', () => {
|
|
@@ -987,7 +987,7 @@ describe('PaceAppLayout Security', () => {
|
|
|
987
987
|
});
|
|
988
988
|
});
|
|
989
989
|
|
|
990
|
-
it('allows super admin to bypass all permission checks', async () => {
|
|
990
|
+
it('allows super admin to bypass all permission checks', { timeout: 3000 }, async () => {
|
|
991
991
|
// Mock super admin status
|
|
992
992
|
mockIsSuperAdmin.mockResolvedValueOnce(true);
|
|
993
993
|
|
|
@@ -1017,10 +1017,10 @@ describe('PaceAppLayout Security', () => {
|
|
|
1017
1017
|
expect(screen.getByTestId('mock-outlet')).toBeInTheDocument();
|
|
1018
1018
|
// Should NOT show access denied
|
|
1019
1019
|
expect(screen.queryByText('Access Denied')).not.toBeInTheDocument();
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1020
|
+
});
|
|
1021
|
+
});
|
|
1022
1022
|
|
|
1023
|
-
it('does not log strict mode violations for super admins', async () => {
|
|
1023
|
+
it('does not log strict mode violations for super admins', { timeout: 5000 }, async () => {
|
|
1024
1024
|
// Mock super admin status (resolve immediately)
|
|
1025
1025
|
mockIsSuperAdmin.mockResolvedValueOnce(true);
|
|
1026
1026
|
|
|
@@ -1052,12 +1052,12 @@ describe('PaceAppLayout Security', () => {
|
|
|
1052
1052
|
// Wait for super admin check to complete
|
|
1053
1053
|
await waitFor(() => {
|
|
1054
1054
|
expect(mockIsSuperAdmin).toHaveBeenCalled();
|
|
1055
|
-
}
|
|
1055
|
+
});
|
|
1056
1056
|
|
|
1057
1057
|
// Wait for component to fully render (super admin should bypass checks)
|
|
1058
1058
|
await waitFor(() => {
|
|
1059
1059
|
expect(screen.getByTestId('mock-header')).toBeInTheDocument();
|
|
1060
|
-
}
|
|
1060
|
+
});
|
|
1061
1061
|
|
|
1062
1062
|
// Clear any violations that might have been logged before super admin check completed
|
|
1063
1063
|
consoleSpy.mockClear();
|
|
@@ -1073,9 +1073,9 @@ describe('PaceAppLayout Security', () => {
|
|
|
1073
1073
|
expect(violationLogs).toHaveLength(0);
|
|
1074
1074
|
|
|
1075
1075
|
consoleSpy.mockRestore();
|
|
1076
|
-
}
|
|
1076
|
+
});
|
|
1077
1077
|
|
|
1078
|
-
it('prevents privilege escalation', async () => {
|
|
1078
|
+
it('prevents privilege escalation', { timeout: 3000 }, async () => {
|
|
1079
1079
|
// Test that users cannot escalate their privileges
|
|
1080
1080
|
// Create a test wrapper with admin path for privilege escalation test
|
|
1081
1081
|
const AdminTestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
@@ -1115,7 +1115,7 @@ describe('PaceAppLayout Security', () => {
|
|
|
1115
1115
|
// Wait for super admin check to complete and component to re-render
|
|
1116
1116
|
await waitFor(() => {
|
|
1117
1117
|
expect(mockIsSuperAdmin).toHaveBeenCalled();
|
|
1118
|
-
}
|
|
1118
|
+
});
|
|
1119
1119
|
|
|
1120
1120
|
// Wait a bit for the component to process the super admin check result
|
|
1121
1121
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
@@ -1124,7 +1124,7 @@ describe('PaceAppLayout Security', () => {
|
|
|
1124
1124
|
// With privilege escalation prevention, should show access denied for admin
|
|
1125
1125
|
expect(screen.getByText('Access Denied')).toBeInTheDocument();
|
|
1126
1126
|
expect(screen.getByText("You don't have permission to access this page.")).toBeInTheDocument();
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1127
|
+
});
|
|
1128
|
+
});
|
|
1129
1129
|
});
|
|
1130
1130
|
});
|
|
@@ -873,7 +873,7 @@ describe('PaceAppLayout Component', () => {
|
|
|
873
873
|
});
|
|
874
874
|
|
|
875
875
|
describe('Route-Specific Permissions', () => {
|
|
876
|
-
it('uses route-specific permissions when provided', async () => {
|
|
876
|
+
it('uses route-specific permissions when provided', { timeout: 3000 }, async () => {
|
|
877
877
|
renderWithProviders(
|
|
878
878
|
<TestWrapper>
|
|
879
879
|
<PaceAppLayout
|
|
@@ -906,9 +906,9 @@ describe('PaceAppLayout Component', () => {
|
|
|
906
906
|
'Test App'
|
|
907
907
|
);
|
|
908
908
|
}, { timeout: 2000 });
|
|
909
|
-
}
|
|
909
|
+
});
|
|
910
910
|
|
|
911
|
-
it('uses default permission when route not in routePermissions', async () => {
|
|
911
|
+
it('uses default permission when route not in routePermissions', { timeout: 3000 }, async () => {
|
|
912
912
|
renderWithProviders(
|
|
913
913
|
<TestWrapper>
|
|
914
914
|
<PaceAppLayout
|
|
@@ -940,7 +940,7 @@ describe('PaceAppLayout Component', () => {
|
|
|
940
940
|
'Test App'
|
|
941
941
|
);
|
|
942
942
|
}, { timeout: 2000 });
|
|
943
|
-
}
|
|
943
|
+
});
|
|
944
944
|
});
|
|
945
945
|
|
|
946
946
|
describe('Super Admin Bypass', () => {
|
|
@@ -673,7 +673,9 @@ describe('PaceLoginPage Component', () => {
|
|
|
673
673
|
});
|
|
674
674
|
|
|
675
675
|
it('shows access error when required app configuration is missing', async () => {
|
|
676
|
+
vi.mocked(isSuperAdmin).mockResolvedValue(false);
|
|
676
677
|
mockAuthContext.isAuthenticated = true;
|
|
678
|
+
mockAuthContext.isLoading = false;
|
|
677
679
|
mockAuthContext.user = { id: 'user-1' } as User;
|
|
678
680
|
const missingAppSupabase = {
|
|
679
681
|
from: vi.fn((table: string) => {
|
|
@@ -707,12 +709,15 @@ describe('PaceLoginPage Component', () => {
|
|
|
707
709
|
);
|
|
708
710
|
|
|
709
711
|
await waitFor(() => {
|
|
712
|
+
// Error message format: Application "${appName}" is not configured. Please contact your administrator.
|
|
710
713
|
expect(screen.getByText(/is not configured/i)).toBeInTheDocument();
|
|
711
|
-
});
|
|
714
|
+
}, { timeout: 5000 });
|
|
712
715
|
});
|
|
713
716
|
|
|
714
717
|
it('shows organisation access error when user lacks active organisations', async () => {
|
|
718
|
+
vi.mocked(isSuperAdmin).mockResolvedValue(false);
|
|
715
719
|
mockAuthContext.isAuthenticated = true;
|
|
720
|
+
mockAuthContext.isLoading = false;
|
|
716
721
|
mockAuthContext.user = { id: 'user-2' } as User;
|
|
717
722
|
|
|
718
723
|
const createOrganisationRolesQuery = (result: { data: unknown; error: unknown }) => {
|
|
@@ -779,6 +784,7 @@ describe('PaceLoginPage Component', () => {
|
|
|
779
784
|
);
|
|
780
785
|
|
|
781
786
|
await waitFor(() => {
|
|
787
|
+
// Error message format: You do not have permission to access ${appName}. You are not assigned to any organisation. Please contact your administrator.
|
|
782
788
|
expect(screen.getByText(/not assigned to any organisation/i)).toBeInTheDocument();
|
|
783
789
|
}, { timeout: 5000 });
|
|
784
790
|
});
|
|
@@ -97,10 +97,8 @@ const Progress = React.forwardRef<
|
|
|
97
97
|
<progress
|
|
98
98
|
ref={ref}
|
|
99
99
|
className={cn(
|
|
100
|
-
'appearance-none border-0 h-2 w-full rounded-full overflow-hidden transition-all accent-
|
|
101
|
-
isIndeterminate
|
|
102
|
-
? 'bg-gradient-to-r from-primary/10 via-primary/90 to-primary/10'
|
|
103
|
-
: 'bg-primary/20',
|
|
100
|
+
'appearance-none border-0 h-2 w-full rounded-full overflow-hidden transition-all accent-main-800',
|
|
101
|
+
!isIndeterminate && 'bg-sec-600/50',
|
|
104
102
|
className
|
|
105
103
|
)}
|
|
106
104
|
{...(isIndeterminate ? {} : { value })}
|
|
@@ -260,9 +260,9 @@ export function ProtectedRoute({
|
|
|
260
260
|
// Use isLoading (combined loading state) for consistency with simpler implementations
|
|
261
261
|
if (isLoading && !sessionRestoration.hasTimedOut) {
|
|
262
262
|
return loadingFallback || (
|
|
263
|
-
<
|
|
263
|
+
<main className="grid place-items-center size-full">
|
|
264
264
|
<LoadingSpinner />
|
|
265
|
-
</
|
|
265
|
+
</main>
|
|
266
266
|
);
|
|
267
267
|
}
|
|
268
268
|
|
|
@@ -294,9 +294,9 @@ export function ProtectedRoute({
|
|
|
294
294
|
const isTabVisible = typeof document !== 'undefined' && !document.hidden;
|
|
295
295
|
if (tabJustBecameVisibleRef.current || (isTabVisible && wasAuthenticatedRef.current && isLoading)) {
|
|
296
296
|
return loadingFallback || (
|
|
297
|
-
<
|
|
297
|
+
<main className="grid place-items-center size-full">
|
|
298
298
|
<LoadingSpinner />
|
|
299
|
-
</
|
|
299
|
+
</main>
|
|
300
300
|
);
|
|
301
301
|
}
|
|
302
302
|
|
|
@@ -309,9 +309,9 @@ export function ProtectedRoute({
|
|
|
309
309
|
// Show loading state while we wait for session refresh (unless we're not loading)
|
|
310
310
|
if (isLoading) {
|
|
311
311
|
return loadingFallback || (
|
|
312
|
-
<
|
|
312
|
+
<main className="grid place-items-center size-full">
|
|
313
313
|
<LoadingSpinner />
|
|
314
|
-
</
|
|
314
|
+
</main>
|
|
315
315
|
);
|
|
316
316
|
}
|
|
317
317
|
|
|
@@ -333,14 +333,14 @@ export function ProtectedRoute({
|
|
|
333
333
|
// If no events are available, show error message
|
|
334
334
|
if (!events || events.length === 0) {
|
|
335
335
|
return noEventsFallback || (
|
|
336
|
-
<
|
|
336
|
+
<main className="grid place-items-center text-center min-h-screen p-8">
|
|
337
337
|
<Alert variant="destructive" className="max-w-md">
|
|
338
338
|
<AlertTitle>No Events Available</AlertTitle>
|
|
339
339
|
<AlertDescription>
|
|
340
340
|
You don't have access to any events. Please contact your administrator if you believe this is an error.
|
|
341
341
|
</AlertDescription>
|
|
342
342
|
</Alert>
|
|
343
|
-
</
|
|
343
|
+
</main>
|
|
344
344
|
);
|
|
345
345
|
}
|
|
346
346
|
|