@jmruthers/pace-core 0.5.110 → 0.5.112
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/dist/{AuthService-DrHrvXNZ.d.ts → AuthService-CVgsgtaZ.d.ts} +8 -0
- package/dist/{DataTable-D3BK2FCN.js → DataTable-3D3BUZDV.js} +8 -8
- package/dist/{UnifiedAuthProvider-A7I23UCN.js → UnifiedAuthProvider-KZZUO27W.js} +3 -3
- package/dist/{api-PIE4JRFS.js → api-QPMBZZUZ.js} +5 -3
- package/dist/{audit-65VNHEV2.js → audit-H4YJJF7R.js} +2 -2
- package/dist/{chunk-Q7APDV6H.js → chunk-3OGQLOJM.js} +23 -7
- package/dist/chunk-3OGQLOJM.js.map +1 -0
- package/dist/{chunk-EYSXQ756.js → chunk-7H75SHXZ.js} +2 -2
- package/dist/{chunk-D6MEKC27.js → chunk-BUN7NMV7.js} +2 -2
- package/dist/{chunk-AWK2FAUN.js → chunk-C5RN4TE5.js} +7 -7
- package/dist/{chunk-3J5N2T2N.js → chunk-EKVVTPIF.js} +183 -127
- package/dist/chunk-EKVVTPIF.js.map +1 -0
- package/dist/{chunk-2W4WKJVF.js → chunk-F6QB26OS.js} +290 -255
- package/dist/chunk-F6QB26OS.js.map +1 -0
- package/dist/{chunk-HADXAZT3.js → chunk-I7JC7PTJ.js} +54 -92
- package/dist/chunk-I7JC7PTJ.js.map +1 -0
- package/dist/{chunk-EZ64QG2I.js → chunk-L36JW4KV.js} +2 -2
- package/dist/{chunk-7GBEBJLR.js → chunk-MNSGWRPB.js} +45 -37
- package/dist/chunk-MNSGWRPB.js.map +1 -0
- package/dist/{chunk-YFMENCR4.js → chunk-NEONKMTU.js} +3 -3
- package/dist/{chunk-AUXS7XSO.js → chunk-OO3V7W4H.js} +35 -11
- package/dist/chunk-OO3V7W4H.js.map +1 -0
- package/dist/{chunk-XRSP3H52.js → chunk-TAJRS6YB.js} +57 -23
- package/dist/chunk-TAJRS6YB.js.map +1 -0
- package/dist/{chunk-HGZSO43Y.js → chunk-WMPZY26G.js} +8 -4
- package/dist/{chunk-HGZSO43Y.js.map → chunk-WMPZY26G.js.map} +1 -1
- package/dist/components.js +10 -10
- package/dist/hooks.d.ts +11 -1
- package/dist/hooks.js +9 -7
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +13 -13
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +2 -2
- package/dist/rbac/index.d.ts +13 -8
- package/dist/rbac/index.js +9 -9
- package/dist/utils.js +1 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +4 -4
- package/docs/api/classes/MissingUserContextError.md +4 -4
- package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
- package/docs/api/classes/PermissionDeniedError.md +4 -4
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +8 -8
- package/docs/api/classes/RBACCache.md +8 -8
- package/docs/api/classes/RBACEngine.md +4 -4
- package/docs/api/classes/RBACError.md +4 -4
- package/docs/api/classes/RBACNotInitializedError.md +4 -4
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
- package/docs/api/interfaces/PaceLoginPageProps.md +4 -4
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
- package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
- package/docs/api/interfaces/RouteAccessRecord.md +10 -10
- package/docs/api/interfaces/RouteConfig.md +19 -6
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +36 -36
- package/docs/api-reference/hooks.md +8 -4
- package/docs/architecture/rpc-function-standards.md +3 -1
- package/docs/best-practices/common-patterns.md +3 -3
- package/docs/best-practices/deployment.md +10 -4
- package/docs/best-practices/performance.md +11 -3
- package/docs/core-concepts/organisations.md +8 -8
- package/docs/core-concepts/permissions.md +133 -72
- package/docs/migration/rbac-migration.md +65 -66
- package/docs/rbac/advanced-patterns.md +15 -22
- package/docs/rbac/examples.md +12 -12
- package/docs/rbac/getting-started.md +3 -3
- package/docs/rbac/troubleshooting.md +2 -1
- package/package.json +1 -1
- package/src/components/DataTable/DataTable.test.tsx +405 -154
- package/src/components/DataTable/components/DataTableCore.tsx +6 -1
- package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +913 -0
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +609 -0
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +434 -0
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +120 -0
- package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +519 -0
- package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +316 -0
- package/src/components/DataTable/examples/__tests__/InitialPageSizeExample.test.tsx +211 -0
- package/src/components/EventSelector/EventSelector.tsx +32 -2
- package/src/components/FileUpload/FileUpload.tsx +2 -8
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +56 -8
- package/src/components/NavigationMenu/NavigationMenu.tsx +75 -12
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +193 -63
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +102 -135
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +41 -2
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +61 -6
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +71 -21
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +113 -41
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +155 -45
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +30 -1
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +63 -5
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +156 -72
- package/src/hooks/__tests__/useRBAC.unit.test.ts +4 -38
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useFileDisplay.ts +51 -0
- package/src/hooks/usePermissionCache.test.ts +112 -68
- package/src/hooks/usePermissionCache.ts +55 -15
- package/src/rbac/README.md +81 -39
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +3 -3
- package/src/rbac/__tests__/engine.comprehensive.test.ts +15 -6
- package/src/rbac/__tests__/rbac-core.test.tsx +1 -1
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +57 -4
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +3 -2
- package/src/rbac/adapters.tsx +4 -4
- package/src/rbac/api.test.ts +37 -13
- package/src/rbac/api.ts +25 -8
- package/src/rbac/audit-enhanced.ts +14 -2
- package/src/rbac/audit.test.ts +18 -8
- package/src/rbac/audit.ts +25 -6
- package/src/rbac/cache.test.ts +12 -0
- package/src/rbac/cache.ts +29 -9
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +1 -1
- package/src/rbac/components/NavigationGuard.tsx +14 -14
- package/src/rbac/components/NavigationProvider.test.tsx +1 -1
- package/src/rbac/components/PagePermissionGuard.tsx +4 -3
- package/src/rbac/components/PagePermissionProvider.test.tsx +1 -1
- package/src/rbac/components/PermissionEnforcer.tsx +19 -15
- package/src/rbac/components/RoleBasedRouter.tsx +16 -9
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +123 -107
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +1 -1
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +121 -103
- package/src/rbac/docs/event-based-apps.md +6 -6
- package/src/rbac/engine.ts +12 -2
- package/src/rbac/hooks/useCan.test.ts +29 -2
- package/src/rbac/hooks/usePermissions.test.ts +25 -25
- package/src/rbac/hooks/usePermissions.ts +65 -25
- package/src/rbac/hooks/useRBAC.simple.test.ts +1 -8
- package/src/rbac/hooks/useRBAC.test.ts +3 -40
- package/src/rbac/hooks/useRBAC.ts +0 -55
- package/src/rbac/hooks/useResolvedScope.ts +23 -31
- package/src/rbac/permissions.test.ts +11 -7
- package/src/rbac/security.test.ts +2 -2
- package/src/rbac/security.ts +22 -7
- package/src/rbac/types.test.ts +2 -2
- package/src/rbac/types.ts +1 -2
- package/src/services/EventService.ts +42 -13
- package/src/services/__tests__/EventService.test.ts +25 -4
- package/src/services/interfaces/IEventService.ts +1 -0
- package/src/utils/file-reference.ts +9 -0
- package/dist/chunk-2W4WKJVF.js.map +0 -1
- package/dist/chunk-3J5N2T2N.js.map +0 -1
- package/dist/chunk-7GBEBJLR.js.map +0 -1
- package/dist/chunk-AUXS7XSO.js.map +0 -1
- package/dist/chunk-HADXAZT3.js.map +0 -1
- package/dist/chunk-Q7APDV6H.js.map +0 -1
- package/dist/chunk-XRSP3H52.js.map +0 -1
- /package/dist/{DataTable-D3BK2FCN.js.map → DataTable-3D3BUZDV.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-A7I23UCN.js.map → UnifiedAuthProvider-KZZUO27W.js.map} +0 -0
- /package/dist/{api-PIE4JRFS.js.map → api-QPMBZZUZ.js.map} +0 -0
- /package/dist/{audit-65VNHEV2.js.map → audit-H4YJJF7R.js.map} +0 -0
- /package/dist/{chunk-EYSXQ756.js.map → chunk-7H75SHXZ.js.map} +0 -0
- /package/dist/{chunk-D6MEKC27.js.map → chunk-BUN7NMV7.js.map} +0 -0
- /package/dist/{chunk-AWK2FAUN.js.map → chunk-C5RN4TE5.js.map} +0 -0
- /package/dist/{chunk-EZ64QG2I.js.map → chunk-L36JW4KV.js.map} +0 -0
- /package/dist/{chunk-YFMENCR4.js.map → chunk-NEONKMTU.js.map} +0 -0
|
@@ -25,16 +25,16 @@ import {
|
|
|
25
25
|
SelectSeparator,
|
|
26
26
|
SelectTrigger,
|
|
27
27
|
SelectValue
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-WMPZY26G.js";
|
|
29
29
|
import {
|
|
30
|
+
useCan,
|
|
30
31
|
usePermissions,
|
|
31
32
|
useRBAC,
|
|
32
33
|
useResolvedScope
|
|
33
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-I7JC7PTJ.js";
|
|
34
35
|
import {
|
|
35
|
-
isPermitted,
|
|
36
36
|
isSuperAdmin
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-TAJRS6YB.js";
|
|
38
38
|
import {
|
|
39
39
|
OrganisationProvider_exports,
|
|
40
40
|
PublicErrorBoundary,
|
|
@@ -49,18 +49,19 @@ import {
|
|
|
49
49
|
useIsPublicPage,
|
|
50
50
|
usePublicFileDisplay,
|
|
51
51
|
usePublicPageContext
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-F6QB26OS.js";
|
|
53
53
|
import {
|
|
54
54
|
useToast
|
|
55
55
|
} from "./chunk-4OX5PXHX.js";
|
|
56
56
|
import {
|
|
57
|
+
init_useOrganisations,
|
|
57
58
|
useEvents,
|
|
58
59
|
useOrganisations
|
|
59
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-L36JW4KV.js";
|
|
60
61
|
import {
|
|
61
62
|
UnifiedAuthProvider_exports,
|
|
62
63
|
init_UnifiedAuthProvider as init_UnifiedAuthProvider2
|
|
63
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-7H75SHXZ.js";
|
|
64
65
|
import {
|
|
65
66
|
EventServiceContext,
|
|
66
67
|
EventServiceProvider,
|
|
@@ -70,7 +71,7 @@ import {
|
|
|
70
71
|
useEventService,
|
|
71
72
|
useSessionRestoration,
|
|
72
73
|
useUnifiedAuth
|
|
73
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-OO3V7W4H.js";
|
|
74
75
|
import {
|
|
75
76
|
LoadingSpinner
|
|
76
77
|
} from "./chunk-CDQ3PX7L.js";
|
|
@@ -584,7 +585,23 @@ function EventSelector({
|
|
|
584
585
|
return [...events].sort((a, b) => getTime(b) - getTime(a));
|
|
585
586
|
}, [events]);
|
|
586
587
|
useEffect(() => {
|
|
587
|
-
if (!selectedEvent && events.length > 0) {
|
|
588
|
+
if (!selectedEvent && events.length > 0 && !isLoading) {
|
|
589
|
+
const persistedEventId = localStorage.getItem("pace-core-selected-event") || sessionStorage.getItem("pace-core-selected-event");
|
|
590
|
+
if (persistedEventId) {
|
|
591
|
+
const persistedEvent = events.find((e) => e.event_id === persistedEventId);
|
|
592
|
+
if (persistedEvent) {
|
|
593
|
+
console.debug("[EventSelector] Persisted event found in storage but not selected:", persistedEventId);
|
|
594
|
+
return;
|
|
595
|
+
} else {
|
|
596
|
+
localStorage.removeItem("pace-core-selected-event");
|
|
597
|
+
sessionStorage.removeItem("pace-core-selected-event");
|
|
598
|
+
autoSelectEvent();
|
|
599
|
+
}
|
|
600
|
+
} else {
|
|
601
|
+
autoSelectEvent();
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
function autoSelectEvent() {
|
|
588
605
|
const today = /* @__PURE__ */ new Date();
|
|
589
606
|
const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
|
|
590
607
|
const next = [...events].filter((e) => e.event_date && new Date(e.event_date).getTime() >= startOfToday).sort((a, b) => new Date(a.event_date).getTime() - new Date(b.event_date).getTime())[0];
|
|
@@ -604,7 +621,7 @@ function EventSelector({
|
|
|
604
621
|
}
|
|
605
622
|
}
|
|
606
623
|
}
|
|
607
|
-
}, [events, selectedEvent, setSelectedEvent, onEventChange]);
|
|
624
|
+
}, [events, selectedEvent, setSelectedEvent, onEventChange, isLoading]);
|
|
608
625
|
if (isLoading) {
|
|
609
626
|
return /* @__PURE__ */ jsxs4("div", { className: `flex items-center gap-2 ${className}`, children: [
|
|
610
627
|
/* @__PURE__ */ jsx8(LoadingSpinner, { size: "sm" }),
|
|
@@ -919,14 +936,50 @@ var NavigationMenu = React9.forwardRef(({
|
|
|
919
936
|
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
920
937
|
selectedEventId: selectedEvent?.event_id || null
|
|
921
938
|
});
|
|
939
|
+
const stableScopeRef = React9.useRef({
|
|
940
|
+
organisationId: "",
|
|
941
|
+
eventId: void 0,
|
|
942
|
+
appId: void 0
|
|
943
|
+
});
|
|
944
|
+
if (resolvedScope?.organisationId) {
|
|
945
|
+
const newOrgId = resolvedScope.organisationId;
|
|
946
|
+
const newEventId = resolvedScope.eventId;
|
|
947
|
+
const newAppId = resolvedScope.appId;
|
|
948
|
+
if (stableScopeRef.current.organisationId !== newOrgId || stableScopeRef.current.eventId !== newEventId || stableScopeRef.current.appId !== newAppId) {
|
|
949
|
+
stableScopeRef.current = {
|
|
950
|
+
organisationId: newOrgId,
|
|
951
|
+
eventId: newEventId,
|
|
952
|
+
appId: newAppId
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
} else if (!resolvedScope) {
|
|
956
|
+
if (stableScopeRef.current.organisationId !== "") {
|
|
957
|
+
stableScopeRef.current = {
|
|
958
|
+
organisationId: "",
|
|
959
|
+
eventId: void 0,
|
|
960
|
+
appId: void 0
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
const stableScope = stableScopeRef.current;
|
|
922
965
|
const userId = authContext?.user?.id || "";
|
|
923
|
-
const
|
|
924
|
-
const { permissions: permissionMap, hasAnyPermission, isLoading: permissionsLoading } = usePermissions(
|
|
966
|
+
const { permissions: permissionMap, hasAnyPermission, isLoading: permissionsLoading, error: permissionsError } = usePermissions(
|
|
925
967
|
userId,
|
|
926
|
-
|
|
968
|
+
stableScope
|
|
927
969
|
);
|
|
928
970
|
const filteredItems = React9.useMemo(() => {
|
|
929
|
-
if (
|
|
971
|
+
if (filterByPermissions) {
|
|
972
|
+
if (!authContext || !rbacContext || scopeLoading || permissionsLoading || !resolvedScope?.organisationId) {
|
|
973
|
+
return [];
|
|
974
|
+
}
|
|
975
|
+
if (permissionsError || !permissionMap || Object.keys(permissionMap).length === 0) {
|
|
976
|
+
console.warn("[NavigationMenu] Permission map is empty or has error - showing no items for security", {
|
|
977
|
+
permissionsError: permissionsError?.message,
|
|
978
|
+
permissionMapSize: permissionMap ? Object.keys(permissionMap).length : 0
|
|
979
|
+
});
|
|
980
|
+
return [];
|
|
981
|
+
}
|
|
982
|
+
} else {
|
|
930
983
|
return (items || []).filter((item) => !item.meta?.hidden);
|
|
931
984
|
}
|
|
932
985
|
const getPageIdFromHref = (href) => {
|
|
@@ -990,19 +1043,25 @@ var NavigationMenu = React9.forwardRef(({
|
|
|
990
1043
|
}
|
|
991
1044
|
}
|
|
992
1045
|
}
|
|
993
|
-
if (item.href
|
|
1046
|
+
if (item.href) {
|
|
994
1047
|
const pageId = item.pageId || getPageIdFromHref(item.href);
|
|
995
1048
|
if (pageId) {
|
|
996
1049
|
const pagePermission = `read:page.${pageId}`;
|
|
997
|
-
const
|
|
998
|
-
|
|
1050
|
+
const isSuperAdmin2 = permissionMap["*"] === true;
|
|
1051
|
+
const hasPagePermission = permissionMap[pagePermission] === true;
|
|
1052
|
+
const finalHasPermission = isSuperAdmin2 || hasPagePermission;
|
|
1053
|
+
if (!finalHasPermission) {
|
|
999
1054
|
if (auditLog) {
|
|
1000
1055
|
console.log(`[NavigationMenu] Filtering out navigation item "${item.label}" - no page permission:`, {
|
|
1001
1056
|
itemId: item.id,
|
|
1002
1057
|
href: item.href,
|
|
1003
1058
|
pageId,
|
|
1004
1059
|
permission: pagePermission,
|
|
1005
|
-
hasPermission:
|
|
1060
|
+
hasPermission: finalHasPermission,
|
|
1061
|
+
isSuperAdmin: isSuperAdmin2,
|
|
1062
|
+
permissionMapValue: permissionMap[pagePermission],
|
|
1063
|
+
permissionMapKeys: Object.keys(permissionMap).slice(0, 10)
|
|
1064
|
+
// Show first 10 keys for debugging
|
|
1006
1065
|
});
|
|
1007
1066
|
}
|
|
1008
1067
|
return false;
|
|
@@ -1026,7 +1085,8 @@ var NavigationMenu = React9.forwardRef(({
|
|
|
1026
1085
|
children: filteredChildren
|
|
1027
1086
|
};
|
|
1028
1087
|
};
|
|
1029
|
-
|
|
1088
|
+
const filtered = (items || []).map((item) => filterItem(item)).filter((item) => item !== null);
|
|
1089
|
+
return filtered;
|
|
1030
1090
|
}, [
|
|
1031
1091
|
items,
|
|
1032
1092
|
filterByPermissions,
|
|
@@ -1372,7 +1432,8 @@ Footer.displayName = "Footer";
|
|
|
1372
1432
|
|
|
1373
1433
|
// src/components/PaceAppLayout/PaceAppLayout.tsx
|
|
1374
1434
|
init_UnifiedAuthProvider2();
|
|
1375
|
-
|
|
1435
|
+
init_useOrganisations();
|
|
1436
|
+
import { useState as useState5, useEffect as useEffect3, useMemo as useMemo5 } from "react";
|
|
1376
1437
|
import { Outlet, useNavigate, useLocation } from "react-router-dom";
|
|
1377
1438
|
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1378
1439
|
var EMPTY_PAGE_ID_MAPPING = {};
|
|
@@ -1407,48 +1468,31 @@ function PaceAppLayout({
|
|
|
1407
1468
|
onRouteAccessDenied,
|
|
1408
1469
|
onRouteStrictModeViolation
|
|
1409
1470
|
}) {
|
|
1410
|
-
const { user, signOut, updatePassword } = useUnifiedAuth();
|
|
1471
|
+
const { user, signOut, updatePassword, supabase } = useUnifiedAuth();
|
|
1472
|
+
const { selectedOrganisation } = useOrganisations();
|
|
1411
1473
|
const navigate = useNavigate();
|
|
1412
1474
|
const location = useLocation();
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1475
|
+
let selectedEvent = null;
|
|
1476
|
+
try {
|
|
1477
|
+
const eventsContext = useEvents();
|
|
1478
|
+
selectedEvent = eventsContext.selectedEvent;
|
|
1479
|
+
} catch (error) {
|
|
1480
|
+
}
|
|
1481
|
+
const { resolvedScope } = useResolvedScope({
|
|
1482
|
+
supabase: supabase || null,
|
|
1483
|
+
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
1484
|
+
selectedEventId: selectedEvent?.event_id || null
|
|
1485
|
+
});
|
|
1486
|
+
const scope = useMemo5(() => {
|
|
1487
|
+
if (!resolvedScope?.organisationId) {
|
|
1488
|
+
return {
|
|
1489
|
+
organisationId: selectedOrganisation?.id || "",
|
|
1490
|
+
eventId: selectedEvent?.event_id || void 0,
|
|
1491
|
+
appId: void 0
|
|
1420
1492
|
};
|
|
1421
|
-
try {
|
|
1422
|
-
const { isSuperAdmin: isSuperAdmin2 } = await import("./api-PIE4JRFS.js");
|
|
1423
|
-
const isSuper = await isSuperAdmin2(user.id);
|
|
1424
|
-
if (isSuper) {
|
|
1425
|
-
return true;
|
|
1426
|
-
}
|
|
1427
|
-
} catch (error) {
|
|
1428
|
-
if (error && typeof error === "object" && "code" in error && error.code === "RBAC_NOT_INITIALIZED") {
|
|
1429
|
-
} else {
|
|
1430
|
-
throw error;
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
if (!scope.organisationId) {
|
|
1434
|
-
console.warn("No organisation context available for permission check, denying access");
|
|
1435
|
-
return false;
|
|
1436
|
-
}
|
|
1437
|
-
const fullPermission = permission.includes(":") ? permission : pageId ? `${permission}:page.${pageId}` : permission;
|
|
1438
|
-
return await isPermitted({
|
|
1439
|
-
userId: user.id,
|
|
1440
|
-
scope,
|
|
1441
|
-
permission: fullPermission,
|
|
1442
|
-
pageId
|
|
1443
|
-
});
|
|
1444
|
-
} catch (error) {
|
|
1445
|
-
console.error("Permission check failed:", error);
|
|
1446
|
-
throw error;
|
|
1447
1493
|
}
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
const [isCheckingPermission, setIsCheckingPermission] = useState5(false);
|
|
1451
|
-
const [permissionError, setPermissionError] = useState5(null);
|
|
1494
|
+
return resolvedScope;
|
|
1495
|
+
}, [resolvedScope, selectedOrganisation?.id, selectedEvent?.event_id]);
|
|
1452
1496
|
const defaultNavItems = useMemo5(() => [
|
|
1453
1497
|
{ id: "home", label: "Home", href: "/", icon: "Home" },
|
|
1454
1498
|
{ id: "dashboard", label: "Dashboard", href: "/dashboard", icon: "LayoutDashboard" },
|
|
@@ -1465,60 +1509,54 @@ function PaceAppLayout({
|
|
|
1465
1509
|
const currentPath = location.pathname;
|
|
1466
1510
|
return pageIdMapping[currentPath] || currentPath.slice(1) || "home";
|
|
1467
1511
|
}, [location.pathname, pageIdMapping]);
|
|
1512
|
+
const currentPermission = useMemo5(() => {
|
|
1513
|
+
if (!enforcePermissions) {
|
|
1514
|
+
return "read:page.home";
|
|
1515
|
+
}
|
|
1516
|
+
const permissionString = `${currentRoutePermission}:page.${currentPageId}`;
|
|
1517
|
+
return permissionString;
|
|
1518
|
+
}, [enforcePermissions, currentRoutePermission, currentPageId]);
|
|
1519
|
+
const { can, isLoading: isCheckingPermission, error: permissionError } = useCan(
|
|
1520
|
+
user?.id || "",
|
|
1521
|
+
scope,
|
|
1522
|
+
currentPermission,
|
|
1523
|
+
currentPageId,
|
|
1524
|
+
true
|
|
1525
|
+
// useCache
|
|
1526
|
+
);
|
|
1527
|
+
const hasPermission = enforcePermissions ? can : true;
|
|
1468
1528
|
useEffect3(() => {
|
|
1469
1529
|
if (!enforcePermissions) {
|
|
1470
|
-
setHasPermission(true);
|
|
1471
1530
|
return;
|
|
1472
1531
|
}
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
operation: currentRoutePermission,
|
|
1496
|
-
userId: user?.id,
|
|
1497
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1498
|
-
});
|
|
1499
|
-
if (onStrictModeViolation) {
|
|
1500
|
-
onStrictModeViolation(currentPageId, currentRoutePermission);
|
|
1501
|
-
}
|
|
1502
|
-
}
|
|
1503
|
-
if (!hasAccess && onPageAccessDenied) {
|
|
1504
|
-
onPageAccessDenied(currentPageId, currentRoutePermission);
|
|
1505
|
-
}
|
|
1506
|
-
} catch (error) {
|
|
1507
|
-
if (!isMounted) return;
|
|
1508
|
-
console.error(`[PaceAppLayout] Permission check failed for ${currentPageId}:`, error);
|
|
1509
|
-
setPermissionError(error instanceof Error ? error : new Error("Permission check failed"));
|
|
1510
|
-
setHasPermission(false);
|
|
1511
|
-
} finally {
|
|
1512
|
-
if (isMounted) {
|
|
1513
|
-
setIsCheckingPermission(false);
|
|
1514
|
-
}
|
|
1532
|
+
if (isCheckingPermission) {
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
if (auditLog) {
|
|
1536
|
+
console.log(`[PaceAppLayout] Page access attempt:`, {
|
|
1537
|
+
pageName: currentPageId,
|
|
1538
|
+
operation: currentRoutePermission,
|
|
1539
|
+
userId: user?.id,
|
|
1540
|
+
allowed: can,
|
|
1541
|
+
strictMode,
|
|
1542
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1545
|
+
if (strictMode && !can) {
|
|
1546
|
+
console.error(`[PaceAppLayout] STRICT MODE VIOLATION: User attempted to access protected page without permission`, {
|
|
1547
|
+
pageName: currentPageId,
|
|
1548
|
+
operation: currentRoutePermission,
|
|
1549
|
+
userId: user?.id,
|
|
1550
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1551
|
+
});
|
|
1552
|
+
if (onStrictModeViolation) {
|
|
1553
|
+
onStrictModeViolation(currentPageId, currentRoutePermission);
|
|
1515
1554
|
}
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
}, [enforcePermissions, currentRoutePermission, currentPageId, strictMode, user?.id]);
|
|
1555
|
+
}
|
|
1556
|
+
if (!can && onPageAccessDenied) {
|
|
1557
|
+
onPageAccessDenied(currentPageId, currentRoutePermission);
|
|
1558
|
+
}
|
|
1559
|
+
}, [enforcePermissions, can, isCheckingPermission, currentPageId, currentRoutePermission, user?.id, strictMode, auditLog, onPageAccessDenied, onStrictModeViolation]);
|
|
1522
1560
|
const [filteredMenuItems, setFilteredMenuItems] = useState5(baseMenuItems);
|
|
1523
1561
|
useEffect3(() => {
|
|
1524
1562
|
if (!filterNavigationByPermissions) {
|
|
@@ -1533,13 +1571,13 @@ function PaceAppLayout({
|
|
|
1533
1571
|
}
|
|
1534
1572
|
return;
|
|
1535
1573
|
}
|
|
1536
|
-
const
|
|
1574
|
+
const scope2 = {
|
|
1537
1575
|
organisationId: user.user_metadata?.organisationId || user.app_metadata?.organisationId,
|
|
1538
1576
|
eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,
|
|
1539
1577
|
appId: user.user_metadata?.appId || user.app_metadata?.appId
|
|
1540
1578
|
};
|
|
1541
1579
|
try {
|
|
1542
|
-
const { isSuperAdmin: isSuperAdmin2 } = await import("./api-
|
|
1580
|
+
const { isSuperAdmin: isSuperAdmin2 } = await import("./api-QPMBZZUZ.js");
|
|
1543
1581
|
const isSuper = await isSuperAdmin2(user.id);
|
|
1544
1582
|
if (isSuper) {
|
|
1545
1583
|
if (isMounted) {
|
|
@@ -1553,17 +1591,17 @@ function PaceAppLayout({
|
|
|
1553
1591
|
throw error;
|
|
1554
1592
|
}
|
|
1555
1593
|
}
|
|
1556
|
-
if (!
|
|
1594
|
+
if (!scope2.organisationId) {
|
|
1557
1595
|
if (isMounted) {
|
|
1558
1596
|
setFilteredMenuItems(baseMenuItems);
|
|
1559
1597
|
}
|
|
1560
1598
|
return;
|
|
1561
1599
|
}
|
|
1562
1600
|
try {
|
|
1563
|
-
const { getPermissionMap } = await import("./api-
|
|
1601
|
+
const { getPermissionMap } = await import("./api-QPMBZZUZ.js");
|
|
1564
1602
|
const permissionMap = await getPermissionMap({
|
|
1565
1603
|
userId: user.id,
|
|
1566
|
-
scope
|
|
1604
|
+
scope: scope2
|
|
1567
1605
|
});
|
|
1568
1606
|
const filtered = baseMenuItems.map((item) => {
|
|
1569
1607
|
if (!item.href) return { item, hasAccess: true };
|
|
@@ -1596,7 +1634,7 @@ function PaceAppLayout({
|
|
|
1596
1634
|
return () => {
|
|
1597
1635
|
isMounted = false;
|
|
1598
1636
|
};
|
|
1599
|
-
}, [baseMenuItems, filterNavigationByPermissions, pageIdMapping, routePermissions, defaultPermission,
|
|
1637
|
+
}, [baseMenuItems, filterNavigationByPermissions, pageIdMapping, routePermissions, defaultPermission, can, user?.id, user?.user_metadata, user?.app_metadata]);
|
|
1600
1638
|
useEffect3(() => {
|
|
1601
1639
|
if (!roleBasedRouting || routeConfig.length === 0) return;
|
|
1602
1640
|
let isMounted = true;
|
|
@@ -1619,7 +1657,13 @@ function PaceAppLayout({
|
|
|
1619
1657
|
let hasAccess = true;
|
|
1620
1658
|
if (currentRoute.pageId && currentRoute.permissions && currentRoute.permissions.length > 0) {
|
|
1621
1659
|
try {
|
|
1622
|
-
const
|
|
1660
|
+
const { isPermittedCached } = await import("./api-QPMBZZUZ.js");
|
|
1661
|
+
const hasPagePermission = await isPermittedCached({
|
|
1662
|
+
userId: user?.id || "",
|
|
1663
|
+
scope,
|
|
1664
|
+
permission: currentRoute.permissions[0],
|
|
1665
|
+
pageId: currentRoute.pageId
|
|
1666
|
+
});
|
|
1623
1667
|
if (!isMounted) return;
|
|
1624
1668
|
hasAccess = hasPagePermission;
|
|
1625
1669
|
} catch (error) {
|
|
@@ -1629,7 +1673,7 @@ function PaceAppLayout({
|
|
|
1629
1673
|
}
|
|
1630
1674
|
}
|
|
1631
1675
|
if (hasAccess && currentRoute.roles && currentRoute.roles.length > 0 && user?.id) {
|
|
1632
|
-
const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-
|
|
1676
|
+
const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-KZZUO27W.js");
|
|
1633
1677
|
hasAccess = true;
|
|
1634
1678
|
}
|
|
1635
1679
|
if (!isMounted) return;
|
|
@@ -1669,7 +1713,7 @@ function PaceAppLayout({
|
|
|
1669
1713
|
return () => {
|
|
1670
1714
|
isMounted = false;
|
|
1671
1715
|
};
|
|
1672
|
-
}, [roleBasedRouting, routeConfig, location.pathname, strictMode, user?.id, fallbackRoute,
|
|
1716
|
+
}, [roleBasedRouting, routeConfig, location.pathname, strictMode, user?.id, fallbackRoute, scope, navigate, auditLog, onRouteAccessDenied, onRouteStrictModeViolation]);
|
|
1673
1717
|
const handleSignOut = async () => {
|
|
1674
1718
|
await signOut();
|
|
1675
1719
|
};
|
|
@@ -1737,9 +1781,10 @@ function PaceAppLayout({
|
|
|
1737
1781
|
}
|
|
1738
1782
|
|
|
1739
1783
|
// src/components/PaceLoginPage/PaceLoginPage.tsx
|
|
1740
|
-
import { useEffect as useEffect4, useState as useState6 } from "react";
|
|
1784
|
+
import { useEffect as useEffect4, useState as useState6, useContext } from "react";
|
|
1741
1785
|
import { useNavigate as useNavigate2 } from "react-router-dom";
|
|
1742
1786
|
init_runtime();
|
|
1787
|
+
init_EventServiceProvider();
|
|
1743
1788
|
import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1744
1789
|
var PaceLoginPage = ({
|
|
1745
1790
|
appName = "Pace",
|
|
@@ -1751,9 +1796,27 @@ var PaceLoginPage = ({
|
|
|
1751
1796
|
const [isSigningIn, setIsSigningIn] = useState6(false);
|
|
1752
1797
|
const [accessError, setAccessError] = useState6(null);
|
|
1753
1798
|
const [isCheckingAccess, setIsCheckingAccess] = useState6(false);
|
|
1799
|
+
const eventServiceContext = useContext(EventServiceContext);
|
|
1800
|
+
const eventService = eventServiceContext?.eventService || null;
|
|
1754
1801
|
useEffect4(() => {
|
|
1755
1802
|
clearPalette();
|
|
1756
1803
|
}, []);
|
|
1804
|
+
useEffect4(() => {
|
|
1805
|
+
const restoreEvent = async () => {
|
|
1806
|
+
try {
|
|
1807
|
+
const isOnLoginPage = window.location.pathname === "/login" || window.location.pathname.startsWith("/login");
|
|
1808
|
+
if (isOnLoginPage && eventService) {
|
|
1809
|
+
await eventService.restorePersistedEvent();
|
|
1810
|
+
}
|
|
1811
|
+
} catch (error) {
|
|
1812
|
+
console.debug("[PaceLoginPage] Could not restore persisted event (service may not be ready):", error);
|
|
1813
|
+
}
|
|
1814
|
+
};
|
|
1815
|
+
const timeoutId = setTimeout(() => {
|
|
1816
|
+
restoreEvent();
|
|
1817
|
+
}, 100);
|
|
1818
|
+
return () => clearTimeout(timeoutId);
|
|
1819
|
+
}, [eventService]);
|
|
1757
1820
|
useEffect4(() => {
|
|
1758
1821
|
if (!requireAppAccess || !isAuthenticated || isLoading || !user || !supabase) {
|
|
1759
1822
|
return;
|
|
@@ -2990,13 +3053,6 @@ function FileUpload({
|
|
|
2990
3053
|
};
|
|
2991
3054
|
onProgress?.(finalProgress);
|
|
2992
3055
|
onUploadSuccess?.(result);
|
|
2993
|
-
setTimeout(() => {
|
|
2994
|
-
setUploadStates((prev) => {
|
|
2995
|
-
const updated = new Map(prev);
|
|
2996
|
-
updated.delete(fileId);
|
|
2997
|
-
return updated;
|
|
2998
|
-
});
|
|
2999
|
-
}, 3e3);
|
|
3000
3056
|
} else {
|
|
3001
3057
|
setUploadStates((prev) => {
|
|
3002
3058
|
const updated = new Map(prev);
|
|
@@ -3191,7 +3247,7 @@ function FileUpload({
|
|
|
3191
3247
|
}
|
|
3192
3248
|
|
|
3193
3249
|
// src/components/FileDisplay/FileDisplay.tsx
|
|
3194
|
-
import { useState as useState12, useEffect as useEffect8, useRef as useRef5, useContext, useMemo as useMemo9 } from "react";
|
|
3250
|
+
import { useState as useState12, useEffect as useEffect8, useRef as useRef5, useContext as useContext2, useMemo as useMemo9 } from "react";
|
|
3195
3251
|
|
|
3196
3252
|
// src/hooks/useFileUrl.ts
|
|
3197
3253
|
import { useState as useState11, useEffect as useEffect7, useCallback as useCallback7, useRef as useRef4 } from "react";
|
|
@@ -3571,7 +3627,7 @@ function FileDisplayPublic({
|
|
|
3571
3627
|
fallbackText,
|
|
3572
3628
|
fallbackSize
|
|
3573
3629
|
}) {
|
|
3574
|
-
const publicPageContext =
|
|
3630
|
+
const publicPageContext = useContext2(PublicPageContext);
|
|
3575
3631
|
const supabase = publicPageContext?.supabase ?? null;
|
|
3576
3632
|
if (!supabase) {
|
|
3577
3633
|
return /* @__PURE__ */ jsx22("div", { className: `text-sec-500 text-center p-4 ${className}`, children: "Supabase client not available in public context" });
|
|
@@ -4453,4 +4509,4 @@ export {
|
|
|
4453
4509
|
PublicPageDiagnostic,
|
|
4454
4510
|
PublicPageContextChecker
|
|
4455
4511
|
};
|
|
4456
|
-
//# sourceMappingURL=chunk-
|
|
4512
|
+
//# sourceMappingURL=chunk-EKVVTPIF.js.map
|