@jmruthers/pace-core 0.5.145 → 0.5.147
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/{DataTable-AKZ6GRWF.js → DataTable-VWAHYZAB.js} +3 -3
- package/dist/{chunk-NVVYDA5H.js → chunk-B6R63NR5.js} +2 -2
- package/dist/{chunk-E2LWA55X.js → chunk-GROECFVN.js} +3 -3
- package/dist/{chunk-WBK6ZKTF.js → chunk-M57AT6C2.js} +2 -2
- package/dist/{chunk-4LTN3DVN.js → chunk-MYLOSYK5.js} +42 -6
- package/dist/chunk-MYLOSYK5.js.map +1 -0
- package/dist/components.js +3 -3
- package/dist/index.js +4 -4
- package/dist/rbac/index.js +2 -2
- 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 +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/docs/rbac/RBAC_EVENT_CONTEXT_LOADING.md +222 -0
- package/docs/rbac/RBAC_V0.5.147_FIX.md +117 -0
- package/package.json +1 -1
- package/src/rbac/hooks/useRBAC.ts +51 -5
- package/dist/chunk-4LTN3DVN.js.map +0 -1
- /package/dist/{DataTable-AKZ6GRWF.js.map → DataTable-VWAHYZAB.js.map} +0 -0
- /package/dist/{chunk-NVVYDA5H.js.map → chunk-B6R63NR5.js.map} +0 -0
- /package/dist/{chunk-E2LWA55X.js.map → chunk-GROECFVN.js.map} +0 -0
- /package/dist/{chunk-WBK6ZKTF.js.map → chunk-M57AT6C2.js.map} +0 -0
package/docs/api/modules.md
CHANGED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# RBAC Event Context Loading - How It Works
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
For event-based apps (`requires_event: true`), RBAC waits for event context to be ready before loading permissions. This document explains how this works and answers common questions.
|
|
6
|
+
|
|
7
|
+
## How RBAC Detects Event Context Availability
|
|
8
|
+
|
|
9
|
+
### Automatic Detection via React Hooks
|
|
10
|
+
|
|
11
|
+
RBAC uses React's dependency system to automatically detect when event context becomes available:
|
|
12
|
+
|
|
13
|
+
1. **`useRBAC` hook watches event state**:
|
|
14
|
+
- `eventLoading` - boolean indicating if events are loading
|
|
15
|
+
- `selectedEvent` - the currently selected event object (or null)
|
|
16
|
+
|
|
17
|
+
2. **`loadRBACContext` callback depends on event state**:
|
|
18
|
+
```typescript
|
|
19
|
+
const loadRBACContext = useCallback(async () => {
|
|
20
|
+
// ... loading logic
|
|
21
|
+
}, [selectedEvent, eventLoading, ...other dependencies]);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
3. **`useEffect` automatically re-runs when callback changes**:
|
|
25
|
+
```typescript
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
loadRBACContext();
|
|
28
|
+
}, [loadRBACContext]);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Flow Diagram
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
1. Component mounts → useRBAC called
|
|
35
|
+
2. loadRBACContext created (depends on eventLoading, selectedEvent)
|
|
36
|
+
3. useEffect runs → calls loadRBACContext()
|
|
37
|
+
4. If eventLoading=true OR selectedEvent=null:
|
|
38
|
+
→ Log: "Waiting for event context"
|
|
39
|
+
→ Set isLoading=true
|
|
40
|
+
→ Return early (don't load RBAC)
|
|
41
|
+
5. When eventLoading changes to false AND selectedEvent becomes available:
|
|
42
|
+
→ loadRBACContext callback is recreated (dependency changed)
|
|
43
|
+
→ useEffect detects callback changed → re-runs
|
|
44
|
+
→ loadRBACContext() called again
|
|
45
|
+
→ This time: eventLoading=false AND selectedEvent exists
|
|
46
|
+
→ Proceeds to load RBAC context
|
|
47
|
+
→ Log: "Loading RBAC context"
|
|
48
|
+
→ Log: "RBAC context loaded successfully"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Should You See the "Waiting for Event Context" Log?
|
|
52
|
+
|
|
53
|
+
**Yes, you should see this log** when:
|
|
54
|
+
- App has `requires_event: true`
|
|
55
|
+
- Event context is loading (`eventLoading: true`) OR no event selected (`selectedEvent: null`)
|
|
56
|
+
|
|
57
|
+
**Log level**: `INFO` (should be visible in console)
|
|
58
|
+
|
|
59
|
+
**Log message**:
|
|
60
|
+
```
|
|
61
|
+
[useRBAC] Waiting for event context before loading RBAC context
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**If you don't see this log**, it might mean:
|
|
65
|
+
1. App doesn't have `requires_event: true` configured
|
|
66
|
+
2. Event context loads too quickly (race condition)
|
|
67
|
+
3. Log level is set too high (unlikely, as it's INFO level)
|
|
68
|
+
|
|
69
|
+
## Is RBAC Loading Automatic?
|
|
70
|
+
|
|
71
|
+
**Yes, RBAC loading is completely automatic**. You don't need to call anything explicitly.
|
|
72
|
+
|
|
73
|
+
### How It Works Automatically
|
|
74
|
+
|
|
75
|
+
1. **`useRBAC` hook is called automatically** when:
|
|
76
|
+
- Component using RBAC mounts (e.g., `NavigationMenu`, `PagePermissionGuard`)
|
|
77
|
+
- Or when you explicitly call `useRBAC()` in a component
|
|
78
|
+
|
|
79
|
+
2. **React's dependency system triggers re-runs**:
|
|
80
|
+
- When `eventLoading` changes from `true` → `false`
|
|
81
|
+
- When `selectedEvent` changes from `null` → object
|
|
82
|
+
- The `loadRBACContext` callback is recreated
|
|
83
|
+
- The `useEffect` detects the change and re-runs
|
|
84
|
+
- RBAC context loads automatically
|
|
85
|
+
|
|
86
|
+
### What You Need to Do
|
|
87
|
+
|
|
88
|
+
**Nothing!** Just ensure:
|
|
89
|
+
- ✅ `setupRBAC(supabase)` is called in your app initialization
|
|
90
|
+
- ✅ `UnifiedAuthProvider` has `appConfig={{ requires_event: true }}` for event-based apps
|
|
91
|
+
- ✅ `EventProvider` is wrapping your app (for event-based apps)
|
|
92
|
+
- ✅ Event context is loading correctly
|
|
93
|
+
|
|
94
|
+
## How to Manually Trigger RBAC Loading (For Testing)
|
|
95
|
+
|
|
96
|
+
### Option 1: Force Re-render
|
|
97
|
+
|
|
98
|
+
If you need to manually trigger RBAC loading for testing:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { useRBAC } from '@jmruthers/pace-core/rbac';
|
|
102
|
+
|
|
103
|
+
function TestComponent() {
|
|
104
|
+
const { isLoading, error, permissionMap } = useRBAC();
|
|
105
|
+
const [forceReload, setForceReload] = useState(0);
|
|
106
|
+
|
|
107
|
+
const manualReload = () => {
|
|
108
|
+
setForceReload(prev => prev + 1);
|
|
109
|
+
// This will cause useRBAC to re-run
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div>
|
|
114
|
+
<button onClick={manualReload}>Reload RBAC</button>
|
|
115
|
+
<div>Loading: {isLoading ? 'Yes' : 'No'}</div>
|
|
116
|
+
<div>Permissions: {Object.keys(permissionMap).length}</div>
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Option 2: Call RPC Directly (Advanced)
|
|
123
|
+
|
|
124
|
+
For debugging, you can call the RPC function directly:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { getEngine } from '@jmruthers/pace-core/rbac';
|
|
128
|
+
|
|
129
|
+
async function testRBAC() {
|
|
130
|
+
const engine = getEngine();
|
|
131
|
+
|
|
132
|
+
// Test app resolution
|
|
133
|
+
const appContext = await engine.resolveAppContext({
|
|
134
|
+
userId: 'your-user-id',
|
|
135
|
+
appName: 'TRAC'
|
|
136
|
+
});
|
|
137
|
+
console.log('App context:', appContext);
|
|
138
|
+
|
|
139
|
+
// Test permission map
|
|
140
|
+
const permissionMap = await engine.getPermissionMap({
|
|
141
|
+
userId: 'your-user-id',
|
|
142
|
+
scope: {
|
|
143
|
+
organisationId: 'your-org-id',
|
|
144
|
+
eventId: 'your-event-id',
|
|
145
|
+
appId: appContext?.appId
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
console.log('Permission map:', permissionMap);
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Option 3: Check Console Logs
|
|
153
|
+
|
|
154
|
+
The fix includes detailed logging:
|
|
155
|
+
|
|
156
|
+
1. **When waiting**: `[useRBAC] Waiting for event context before loading RBAC context`
|
|
157
|
+
2. **When loading**: `[useRBAC] Loading RBAC context`
|
|
158
|
+
3. **When successful**: `[useRBAC] RBAC context loaded successfully` (with permission count)
|
|
159
|
+
|
|
160
|
+
## Troubleshooting
|
|
161
|
+
|
|
162
|
+
### RBAC Not Loading After Event Context Ready
|
|
163
|
+
|
|
164
|
+
**Symptoms**:
|
|
165
|
+
- Event context loads (`eventLoading: false`, `selectedEvent` set)
|
|
166
|
+
- No RBAC loading logs appear
|
|
167
|
+
- Permission map remains empty
|
|
168
|
+
|
|
169
|
+
**Check**:
|
|
170
|
+
1. ✅ Verify `appConfig={{ requires_event: true }}` in `UnifiedAuthProvider`
|
|
171
|
+
2. ✅ Verify database has `requires_event: true` for your app
|
|
172
|
+
3. ✅ Check console for "Waiting for event context" log (should appear first)
|
|
173
|
+
4. ✅ Check console for "Loading RBAC context" log (should appear after event ready)
|
|
174
|
+
5. ✅ Verify `selectedEvent` is actually set (not null)
|
|
175
|
+
6. ✅ Verify `eventLoading` is actually `false` (not `true`)
|
|
176
|
+
|
|
177
|
+
**If still not working**:
|
|
178
|
+
- Check browser console for any errors
|
|
179
|
+
- Verify `setupRBAC(supabase)` was called
|
|
180
|
+
- Check that `useRBAC` hook is being called somewhere (NavigationMenu calls it automatically)
|
|
181
|
+
|
|
182
|
+
### Logs Not Appearing
|
|
183
|
+
|
|
184
|
+
**If you don't see any logs**:
|
|
185
|
+
1. Check log level - logs are `INFO` level, should be visible
|
|
186
|
+
2. Check browser console filter settings
|
|
187
|
+
3. Verify RBAC logger is configured correctly
|
|
188
|
+
|
|
189
|
+
### Permission Map Still Empty
|
|
190
|
+
|
|
191
|
+
**If permission map is empty after RBAC loads**:
|
|
192
|
+
1. Check "RBAC context loaded successfully" log - what's the `permissionCount`?
|
|
193
|
+
2. If `permissionCount: 0`, check:
|
|
194
|
+
- User has event-app role assigned
|
|
195
|
+
- Permissions exist for that role in database
|
|
196
|
+
- Event ID matches the selected event
|
|
197
|
+
- Organisation ID matches user's organisation
|
|
198
|
+
|
|
199
|
+
## Expected Console Log Sequence
|
|
200
|
+
|
|
201
|
+
For event-based apps, you should see this sequence:
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
1. [RBAC INFO] RBAC system initialized successfully
|
|
205
|
+
2. [useRBAC] Waiting for event context before loading RBAC context
|
|
206
|
+
{ eventLoading: true, hasSelectedEvent: false, appName: "TRAC" }
|
|
207
|
+
3. [useRBAC] Loading RBAC context
|
|
208
|
+
{ appName: "TRAC", requiresEvent: true, hasSelectedEvent: true, ... }
|
|
209
|
+
4. [useRBAC] RBAC context loaded successfully
|
|
210
|
+
{ appName: "TRAC", permissionCount: 32, ... }
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Summary
|
|
214
|
+
|
|
215
|
+
- ✅ **RBAC detection is automatic** - React hooks handle it
|
|
216
|
+
- ✅ **You should see "Waiting" log** - when event is loading
|
|
217
|
+
- ✅ **RBAC loads automatically** - when event context becomes ready
|
|
218
|
+
- ✅ **No manual triggering needed** - but you can force re-render for testing
|
|
219
|
+
- ✅ **Detailed logs included** - to help debug issues
|
|
220
|
+
|
|
221
|
+
The fix ensures RBAC waits for event context before loading, preventing NetworkError and ensuring permissions load correctly for event-based apps.
|
|
222
|
+
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# RBAC v0.5.147 Fix - Event Context Loading
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
RBAC wasn't loading for event-based apps because:
|
|
6
|
+
1. **Logger filtering**: Critical logs were using `logger.info()` but RBAC logger defaults to `logLevel: 'warn'`, so logs were filtered out
|
|
7
|
+
2. **Missing dependencies**: `appConfig` wasn't in `loadRBACContext` dependencies, so callback wasn't recreated when appConfig changed
|
|
8
|
+
3. **No visibility**: No way to verify if `useRBAC` hook was being called
|
|
9
|
+
|
|
10
|
+
## Fixes Applied
|
|
11
|
+
|
|
12
|
+
### 1. Changed Log Levels to `warn`
|
|
13
|
+
|
|
14
|
+
All critical logs now use `logger.warn()` instead of `logger.info()` so they're always visible:
|
|
15
|
+
|
|
16
|
+
- `[useRBAC] Hook initialized` - Shows when hook is called
|
|
17
|
+
- `[useRBAC] Waiting for event context before loading RBAC context` - Shows when waiting
|
|
18
|
+
- `[useRBAC] Loading RBAC context` - Shows when loading starts
|
|
19
|
+
- `[useRBAC] RBAC context loaded successfully` - Shows when loading completes
|
|
20
|
+
|
|
21
|
+
### 2. Added Direct Console Logging
|
|
22
|
+
|
|
23
|
+
Added direct `console.warn()` at hook initialization as a fallback to ensure visibility:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
console.warn('[useRBAC] Hook initialized (direct log)', hookInitLog);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This ensures logs are visible even if logger configuration is incorrect.
|
|
30
|
+
|
|
31
|
+
### 3. Added `appConfig` to Dependencies
|
|
32
|
+
|
|
33
|
+
Added `appConfig` to `loadRBACContext` callback dependencies so it recreates when appConfig changes:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
}, [appName, logger, resetState, selectedEvent, selectedEvent?.event_id, selectedOrganisation?.id, session, user, requiresEvent, eventLoading, appConfig]);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 4. Improved `requiresEvent` Logic
|
|
40
|
+
|
|
41
|
+
Changed default behavior when `appConfig` is `null`:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// If appConfig is null initially, default to true (safer for event-based apps)
|
|
45
|
+
const requiresEvent = appConfig?.requires_event ?? (appConfig === null ? true : false);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This prevents premature loading when appConfig hasn't loaded yet.
|
|
49
|
+
|
|
50
|
+
### 5. Added useEffect Logging
|
|
51
|
+
|
|
52
|
+
Added logging in `useEffect` to track when it runs:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
logger.warn('[useRBAC] useEffect triggered - calling loadRBACContext', { ... });
|
|
57
|
+
loadRBACContext();
|
|
58
|
+
}, [loadRBACContext, appName, requiresEvent, eventLoading, selectedEvent, user, session]);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 6. Added Explicit useEffect Dependencies
|
|
62
|
+
|
|
63
|
+
Added explicit dependencies to `useEffect` so it re-runs when event context changes:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
}, [loadRBACContext, appName, requiresEvent, eventLoading, selectedEvent, user, session]);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Expected Console Logs
|
|
70
|
+
|
|
71
|
+
After this fix, you should see this sequence:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
1. [useRBAC] Hook initialized (direct log)
|
|
75
|
+
{ appName: "TRAC", requiresEvent: true, ... }
|
|
76
|
+
|
|
77
|
+
2. [useRBAC] useEffect triggered - calling loadRBACContext
|
|
78
|
+
{ appName: "TRAC", requiresEvent: true, eventLoading: true, ... }
|
|
79
|
+
|
|
80
|
+
3. [useRBAC] Waiting for event context before loading RBAC context
|
|
81
|
+
{ eventLoading: true, hasSelectedEvent: false, appName: "TRAC" }
|
|
82
|
+
|
|
83
|
+
4. [useRBAC] useEffect triggered - calling loadRBACContext
|
|
84
|
+
{ appName: "TRAC", requiresEvent: true, eventLoading: false, hasSelectedEvent: true, ... }
|
|
85
|
+
|
|
86
|
+
5. [useRBAC] Loading RBAC context
|
|
87
|
+
{ appName: "TRAC", requiresEvent: true, hasSelectedEvent: true, ... }
|
|
88
|
+
|
|
89
|
+
6. [useRBAC] RBAC context loaded successfully
|
|
90
|
+
{ appName: "TRAC", permissionCount: 32, ... }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Debugging Steps
|
|
94
|
+
|
|
95
|
+
If you still don't see logs:
|
|
96
|
+
|
|
97
|
+
1. **Check if hook is called**: Look for `[useRBAC] Hook initialized (direct log)` - this uses direct `console.warn()` so it should always appear
|
|
98
|
+
2. **Check if effect runs**: Look for `[useRBAC] useEffect triggered` - this shows when the effect runs
|
|
99
|
+
3. **Check event context**: Verify `eventLoading: false` and `hasSelectedEvent: true` in logs
|
|
100
|
+
4. **Check appConfig**: Verify `appConfig` is not `null` and `requiresEvent: true` in logs
|
|
101
|
+
|
|
102
|
+
## Testing
|
|
103
|
+
|
|
104
|
+
To test the fix:
|
|
105
|
+
|
|
106
|
+
1. Clear browser cache
|
|
107
|
+
2. Restart dev server
|
|
108
|
+
3. Open browser console
|
|
109
|
+
4. Navigate to app
|
|
110
|
+
5. Look for the log sequence above
|
|
111
|
+
|
|
112
|
+
## Related Issues
|
|
113
|
+
|
|
114
|
+
- Fixes: RBAC not loading for event-based apps
|
|
115
|
+
- Related: NavigationMenu empty when `filterNavigationByPermissions={true}`
|
|
116
|
+
- Related: RBAC logs not appearing
|
|
117
|
+
|
package/package.json
CHANGED
|
@@ -64,7 +64,25 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
// Check if app requires event context
|
|
67
|
-
|
|
67
|
+
// IMPORTANT: If appConfig is null initially, default to true (safer for event-based apps)
|
|
68
|
+
// This prevents premature loading when appConfig hasn't loaded yet
|
|
69
|
+
const requiresEvent = appConfig?.requires_event ?? (appConfig === null ? true : false);
|
|
70
|
+
|
|
71
|
+
// Log hook initialization for debugging (use warn level so it's always visible)
|
|
72
|
+
// Also use direct console.log as fallback to ensure visibility
|
|
73
|
+
const hookInitLog = {
|
|
74
|
+
appName,
|
|
75
|
+
requiresEvent,
|
|
76
|
+
appConfig: appConfig ? JSON.stringify(appConfig) : 'null',
|
|
77
|
+
hasUser: !!user,
|
|
78
|
+
hasSession: !!session,
|
|
79
|
+
hasSelectedEvent: !!selectedEvent,
|
|
80
|
+
eventLoading,
|
|
81
|
+
selectedEventId: selectedEvent?.event_id
|
|
82
|
+
};
|
|
83
|
+
logger.warn('[useRBAC] Hook initialized', hookInitLog);
|
|
84
|
+
// Direct console.log as fallback to ensure we can see if hook is called
|
|
85
|
+
console.warn('[useRBAC] Hook initialized (direct log)', hookInitLog);
|
|
68
86
|
|
|
69
87
|
const [globalRole, setGlobalRole] = useState<GlobalRole | null>(null);
|
|
70
88
|
const [organisationRole, setOrganisationRole] = useState<OrganisationRole | null>(null);
|
|
@@ -94,10 +112,13 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
94
112
|
if (eventLoading || !selectedEvent) {
|
|
95
113
|
// Event context not ready yet - don't load RBAC yet
|
|
96
114
|
// This prevents premature RPC calls that can cause NetworkError
|
|
97
|
-
|
|
115
|
+
// Set loading state so React knows we're waiting
|
|
116
|
+
setIsLoading(true);
|
|
117
|
+
logger.warn('[useRBAC] Waiting for event context before loading RBAC context', {
|
|
98
118
|
eventLoading,
|
|
99
119
|
hasSelectedEvent: !!selectedEvent,
|
|
100
|
-
appName
|
|
120
|
+
appName,
|
|
121
|
+
selectedEventId: selectedEvent?.event_id
|
|
101
122
|
});
|
|
102
123
|
return;
|
|
103
124
|
}
|
|
@@ -106,6 +127,14 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
106
127
|
setIsLoading(true);
|
|
107
128
|
setError(null);
|
|
108
129
|
|
|
130
|
+
logger.warn('[useRBAC] Loading RBAC context', {
|
|
131
|
+
appName,
|
|
132
|
+
requiresEvent,
|
|
133
|
+
hasSelectedEvent: !!selectedEvent,
|
|
134
|
+
selectedEventId: selectedEvent?.event_id,
|
|
135
|
+
organisationId: selectedOrganisation?.id
|
|
136
|
+
});
|
|
137
|
+
|
|
109
138
|
try {
|
|
110
139
|
let appId: UUID | undefined;
|
|
111
140
|
if (appName) {
|
|
@@ -152,6 +181,14 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
152
181
|
setGlobalRole(roleContext.globalRole);
|
|
153
182
|
setOrganisationRole(roleContext.organisationRole);
|
|
154
183
|
setEventAppRole(roleContext.eventAppRole || mapAccessLevelToEventRole(accessLevel));
|
|
184
|
+
|
|
185
|
+
logger.warn('[useRBAC] RBAC context loaded successfully', {
|
|
186
|
+
appName,
|
|
187
|
+
permissionCount: Object.keys(map).length,
|
|
188
|
+
globalRole: roleContext.globalRole,
|
|
189
|
+
organisationRole: roleContext.organisationRole,
|
|
190
|
+
eventAppRole: roleContext.eventAppRole || mapAccessLevelToEventRole(accessLevel)
|
|
191
|
+
});
|
|
155
192
|
} catch (err) {
|
|
156
193
|
const handledError = err instanceof Error ? err : new Error('Failed to load RBAC context');
|
|
157
194
|
logger.error('[useRBAC] Error loading RBAC context:', handledError);
|
|
@@ -160,7 +197,7 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
160
197
|
} finally {
|
|
161
198
|
setIsLoading(false);
|
|
162
199
|
}
|
|
163
|
-
}, [appName, logger, resetState, selectedEvent?.event_id, selectedOrganisation?.id, session, user, requiresEvent, eventLoading]);
|
|
200
|
+
}, [appName, logger, resetState, selectedEvent, selectedEvent?.event_id, selectedOrganisation?.id, session, user, requiresEvent, eventLoading, appConfig]);
|
|
164
201
|
|
|
165
202
|
const hasGlobalPermission = useCallback(
|
|
166
203
|
(permission: string): boolean => {
|
|
@@ -188,8 +225,17 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
188
225
|
const canManageEvent = useMemo(() => isSuperAdmin || eventAppRole === 'event_admin', [isSuperAdmin, eventAppRole]);
|
|
189
226
|
|
|
190
227
|
useEffect(() => {
|
|
228
|
+
// Log when effect runs to help debug
|
|
229
|
+
logger.warn('[useRBAC] useEffect triggered - calling loadRBACContext', {
|
|
230
|
+
appName,
|
|
231
|
+
requiresEvent,
|
|
232
|
+
eventLoading,
|
|
233
|
+
hasSelectedEvent: !!selectedEvent,
|
|
234
|
+
hasUser: !!user,
|
|
235
|
+
hasSession: !!session
|
|
236
|
+
});
|
|
191
237
|
loadRBACContext();
|
|
192
|
-
}, [loadRBACContext]);
|
|
238
|
+
}, [loadRBACContext, appName, requiresEvent, eventLoading, selectedEvent, user, session]);
|
|
193
239
|
|
|
194
240
|
return {
|
|
195
241
|
user,
|