@jmruthers/pace-core 0.5.177 → 0.5.179
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/{chunk-2W3CH222.js → chunk-PJEVDATQ.js} +34 -10
- package/dist/chunk-PJEVDATQ.js.map +1 -0
- package/dist/components.js +1 -1
- package/dist/index.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 +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- 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/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CalendarProps.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/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +1 -1
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.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/GrantEventAppRoleParams.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 +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- 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/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/SessionRestorationLoaderProps.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/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +1 -1
- package/docs/api/interfaces/TextareaProps.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/UseResourcePermissionsOptions.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 +2 -2
- package/package.json +1 -1
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +46 -10
- package/src/rbac/hooks/useResourcePermissions.test.ts +26 -3
- package/dist/chunk-2W3CH222.js.map +0 -1
package/docs/api/modules.md
CHANGED
package/package.json
CHANGED
|
@@ -390,7 +390,7 @@ export function PaceAppLayout({
|
|
|
390
390
|
}
|
|
391
391
|
|
|
392
392
|
// Resolve scope for permission checking
|
|
393
|
-
const { resolvedScope } = useResolvedScope({
|
|
393
|
+
const { resolvedScope, isLoading: scopeLoading } = useResolvedScope({
|
|
394
394
|
supabase: supabase || null,
|
|
395
395
|
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
396
396
|
selectedEventId: selectedEvent?.event_id || null
|
|
@@ -550,12 +550,19 @@ export function PaceAppLayout({
|
|
|
550
550
|
return;
|
|
551
551
|
}
|
|
552
552
|
|
|
553
|
-
//
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
553
|
+
// Use the scope from context (includes selectedOrganisation and selectedEvent)
|
|
554
|
+
// This is critical for event-based apps where event context comes from EventService, not user metadata
|
|
555
|
+
const currentScope = scope;
|
|
556
|
+
|
|
557
|
+
// Wait for scope to be fully resolved (including appId) before filtering
|
|
558
|
+
// This is important because getPermissionMap requires appId to fetch pages
|
|
559
|
+
if (scopeLoading || !currentScope.appId) {
|
|
560
|
+
// Scope still loading or appId not resolved yet - show all items until ready
|
|
561
|
+
if (isMounted) {
|
|
562
|
+
setFilteredMenuItems(baseMenuItems);
|
|
563
|
+
}
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
559
566
|
|
|
560
567
|
// For super admins, show all items (they bypass permission checks)
|
|
561
568
|
// Gracefully handle RBAC not being initialized (e.g., in tests)
|
|
@@ -584,7 +591,7 @@ export function PaceAppLayout({
|
|
|
584
591
|
|
|
585
592
|
// If no organisation context yet, show all items until context is ready
|
|
586
593
|
// This prevents navigation from being empty while context loads
|
|
587
|
-
if (!
|
|
594
|
+
if (!currentScope.organisationId) {
|
|
588
595
|
if (isMounted) {
|
|
589
596
|
setFilteredMenuItems(baseMenuItems);
|
|
590
597
|
}
|
|
@@ -596,9 +603,27 @@ export function PaceAppLayout({
|
|
|
596
603
|
// This makes 1 call instead of N calls (where N = number of navigation items)
|
|
597
604
|
try {
|
|
598
605
|
const { getPermissionMap } = await import('../../rbac/api');
|
|
606
|
+
|
|
607
|
+
// Log scope for debugging
|
|
608
|
+
logger.debug('PaceAppLayout', 'Filtering navigation with scope', {
|
|
609
|
+
organisationId: currentScope.organisationId,
|
|
610
|
+
eventId: currentScope.eventId,
|
|
611
|
+
appId: currentScope.appId,
|
|
612
|
+
hasOrganisationId: !!currentScope.organisationId,
|
|
613
|
+
hasEventId: !!currentScope.eventId,
|
|
614
|
+
hasAppId: !!currentScope.appId
|
|
615
|
+
});
|
|
616
|
+
|
|
599
617
|
const permissionMap = await getPermissionMap({
|
|
600
618
|
userId: user.id,
|
|
601
|
-
scope,
|
|
619
|
+
scope: currentScope,
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
// Log permission map for debugging
|
|
623
|
+
logger.debug('PaceAppLayout', 'Permission map received', {
|
|
624
|
+
permissionCount: Object.keys(permissionMap).length,
|
|
625
|
+
permissions: Object.keys(permissionMap),
|
|
626
|
+
hasWildcard: permissionMap['*'] === true
|
|
602
627
|
});
|
|
603
628
|
|
|
604
629
|
// Filter items using the permission map (synchronous, no rate limit issues)
|
|
@@ -614,6 +639,17 @@ export function PaceAppLayout({
|
|
|
614
639
|
// Check permission map (super admin check already handled in getPermissionMap)
|
|
615
640
|
const hasAccess = permissionMap['*'] === true || permissionMap[fullPermission] === true;
|
|
616
641
|
|
|
642
|
+
// Log each item's permission check for debugging
|
|
643
|
+
logger.debug('PaceAppLayout', 'Checking navigation item permission', {
|
|
644
|
+
itemId: item.id,
|
|
645
|
+
href: item.href,
|
|
646
|
+
pageId,
|
|
647
|
+
permission,
|
|
648
|
+
fullPermission,
|
|
649
|
+
hasAccess,
|
|
650
|
+
permissionInMap: permissionMap[fullPermission]
|
|
651
|
+
});
|
|
652
|
+
|
|
617
653
|
return { item, hasAccess };
|
|
618
654
|
});
|
|
619
655
|
|
|
@@ -639,7 +675,7 @@ export function PaceAppLayout({
|
|
|
639
675
|
return () => {
|
|
640
676
|
isMounted = false;
|
|
641
677
|
};
|
|
642
|
-
}, [baseMenuItems, filterNavigationByPermissions, pageIdMapping, routePermissions, defaultPermission, can, user?.id,
|
|
678
|
+
}, [baseMenuItems, filterNavigationByPermissions, pageIdMapping, routePermissions, defaultPermission, can, user?.id, scope, scopeLoading]);
|
|
643
679
|
|
|
644
680
|
// NEW: Phase 2 - Enhanced Routing Features
|
|
645
681
|
// Check route access for role-based routing
|
|
@@ -390,11 +390,34 @@ describe('useResourcePermissions Hook', () => {
|
|
|
390
390
|
|
|
391
391
|
const { result } = renderHook(() => useResourcePermissions('contacts'));
|
|
392
392
|
|
|
393
|
+
// When user is null, userId is empty string, but scope and permissions are still checked
|
|
394
|
+
// Since mockScope has appId, pageId will be the resource name ('contacts')
|
|
393
395
|
expect(mockUseCan).toHaveBeenCalledWith(
|
|
394
396
|
'',
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
397
|
+
mockScope,
|
|
398
|
+
'create:contacts',
|
|
399
|
+
'contacts', // pageId is resource name when appId is available in scope
|
|
400
|
+
true
|
|
401
|
+
);
|
|
402
|
+
expect(mockUseCan).toHaveBeenCalledWith(
|
|
403
|
+
'',
|
|
404
|
+
mockScope,
|
|
405
|
+
'update:contacts',
|
|
406
|
+
'contacts',
|
|
407
|
+
true
|
|
408
|
+
);
|
|
409
|
+
expect(mockUseCan).toHaveBeenCalledWith(
|
|
410
|
+
'',
|
|
411
|
+
mockScope,
|
|
412
|
+
'delete:contacts',
|
|
413
|
+
'contacts',
|
|
414
|
+
true
|
|
415
|
+
);
|
|
416
|
+
expect(mockUseCan).toHaveBeenCalledWith(
|
|
417
|
+
'',
|
|
418
|
+
mockScope,
|
|
419
|
+
'read:contacts',
|
|
420
|
+
'contacts',
|
|
398
421
|
true
|
|
399
422
|
);
|
|
400
423
|
});
|