@jmruthers/pace-core 0.5.120 → 0.5.123
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-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
- package/dist/{DataTable-DGZDJUYM.js → DataTable-WTS4IRF2.js} +7 -8
- package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
- package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
- package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
- package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
- package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
- package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
- package/dist/{chunk-VKOCWWVY.js.map → chunk-CX5M4ZAG.js.map} +1 -1
- package/dist/{chunk-HFBOFZ3Z.js → chunk-DHMFMXFV.js} +258 -243
- package/dist/chunk-DHMFMXFV.js.map +1 -0
- package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
- package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
- package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
- package/dist/chunk-GEVIB2UB.js.map +1 -0
- package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
- package/dist/chunk-IJOZZOGT.js.map +1 -0
- package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
- package/dist/chunk-M6DDYFUD.js.map +1 -0
- package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
- package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
- package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
- package/dist/chunk-XN6GWKMV.js.map +1 -0
- package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
- package/dist/chunk-ZBLK676C.js.map +1 -0
- package/dist/{chunk-QPI2CCBA.js → chunk-ZPJMYGEP.js} +149 -96
- package/dist/chunk-ZPJMYGEP.js.map +1 -0
- package/dist/components.d.ts +1 -1
- package/dist/components.js +11 -11
- package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +9 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +19 -17
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +2 -3
- package/dist/rbac/index.js +7 -8
- package/dist/styles/index.d.ts +1 -1
- package/dist/styles/index.js +5 -3
- package/dist/theming/runtime.d.ts +73 -1
- package/dist/theming/runtime.js +5 -5
- package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +5 -5
- 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 +6 -6
- 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 +6 -6
- 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/EventAppRoleData.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 +7 -7
- package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
- package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.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/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 +140 -30
- package/docs/best-practices/README.md +1 -1
- package/docs/implementation-guides/datatable-filtering.md +313 -0
- package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
- package/docs/implementation-guides/hierarchical-datatable.md +850 -0
- package/docs/implementation-guides/large-datasets.md +281 -0
- package/docs/implementation-guides/performance.md +403 -0
- package/docs/implementation-guides/public-pages.md +4 -4
- package/docs/migration/quick-migration-guide.md +320 -0
- package/docs/rbac/quick-start.md +16 -16
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
- package/docs/troubleshooting/debugging.md +1117 -0
- package/docs/troubleshooting/migration.md +918 -0
- package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
- package/examples/public-pages/PublicEventPage.tsx +41 -41
- package/examples/public-pages/PublicPageApp.tsx +33 -33
- package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
- package/package.json +4 -4
- package/src/__tests__/hooks/usePermissions.test.ts +265 -0
- package/src/components/DataTable/DataTable.test.tsx +9 -38
- package/src/components/DataTable/DataTable.tsx +0 -7
- package/src/components/DataTable/components/DataTableCore.tsx +66 -136
- package/src/components/DataTable/components/DataTableModals.tsx +25 -22
- package/src/components/DataTable/components/EditableRow.tsx +118 -42
- package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
- package/src/components/DataTable/utils/exportUtils.ts +3 -2
- package/src/components/DataTable/utils/flexibleImport.ts +27 -6
- package/src/components/Dialog/Dialog.tsx +1 -1
- package/src/components/Dialog/README.md +24 -24
- package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
- package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
- package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
- package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
- package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
- package/src/components/PublicLayout/EventLogo.tsx +175 -0
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
- package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
- package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
- package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
- package/src/examples/PublicEventPage.tsx +41 -41
- package/src/examples/PublicPageApp.tsx +33 -33
- package/src/examples/PublicPageUsageExample.tsx +30 -30
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
- package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
- package/src/hooks/index.ts +1 -1
- package/src/hooks/public/usePublicEventLogo.ts +285 -0
- package/src/hooks/public/usePublicRouteParams.ts +21 -4
- package/src/hooks/useEventTheme.test.ts +119 -43
- package/src/hooks/useEventTheme.ts +84 -55
- package/src/index.ts +3 -1
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
- package/src/rbac/secureClient.ts +4 -2
- package/src/services/EventService.ts +0 -66
- package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
- package/src/styles/index.ts +1 -1
- package/src/theming/__tests__/parseEventColours.test.ts +209 -0
- package/src/theming/parseEventColours.ts +123 -0
- package/src/theming/runtime.ts +3 -0
- package/src/types/__tests__/file-reference.test.ts +447 -0
- package/src/types/database.generated.ts +1515 -424
- package/src/utils/formatDate.test.ts +11 -11
- package/src/utils/formatting.ts +3 -2
- package/dist/chunk-BHWIUEYH.js.map +0 -1
- package/dist/chunk-FKFHZUGF.js.map +0 -1
- package/dist/chunk-GZRXOUBE.js.map +0 -1
- package/dist/chunk-HFBOFZ3Z.js.map +0 -1
- package/dist/chunk-QPI2CCBA.js.map +0 -1
- package/dist/chunk-SMJZMKYN.js.map +0 -1
- package/dist/chunk-TDNI6ZWL.js.map +0 -1
- package/src/styles/semantic.css +0 -24
- /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-WTS4IRF2.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
- /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
- /package/dist/{chunk-CGURJ27Z.js.map → chunk-4MXVZVNS.js.map} +0 -0
- /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
- /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
- /package/dist/{chunk-NZ32EONV.js.map → chunk-QWNJCQXZ.js.map} +0 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# DataTable RBAC Usage Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The DataTable component now properly enforces page-based RBAC permissions instead of resource-based permissions. This ensures that DataTable permissions align with your application's page-level permission system.
|
|
6
|
+
|
|
7
|
+
## Correct Usage
|
|
8
|
+
|
|
9
|
+
### Basic Usage
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { DataTable } from '@jmruthers/pace-core';
|
|
13
|
+
|
|
14
|
+
function DishesPage() {
|
|
15
|
+
const dishes = [
|
|
16
|
+
{ id: '1', name: 'Pasta', category: 'Main' },
|
|
17
|
+
{ id: '2', name: 'Salad', category: 'Side' }
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const columns = [
|
|
21
|
+
{ accessorKey: 'id', header: 'ID' },
|
|
22
|
+
{ accessorKey: 'name', header: 'Name' },
|
|
23
|
+
{ accessorKey: 'category', header: 'Category' }
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<DataTable
|
|
28
|
+
data={dishes}
|
|
29
|
+
columns={columns}
|
|
30
|
+
rbac={{
|
|
31
|
+
pageName: 'dishes' // Page name for permissions (recommended)
|
|
32
|
+
}}
|
|
33
|
+
features={{
|
|
34
|
+
search: true,
|
|
35
|
+
pagination: true,
|
|
36
|
+
sorting: true,
|
|
37
|
+
filtering: true,
|
|
38
|
+
creation: true, // Will be controlled by create:page.dishes permission
|
|
39
|
+
editing: true, // Will be controlled by update:page.dishes permission
|
|
40
|
+
deletion: true, // Will be controlled by delete:page.dishes permission
|
|
41
|
+
export: true, // Will be controlled by read:page.dishes permission
|
|
42
|
+
import: true // Will be controlled by create:page.dishes permission
|
|
43
|
+
}}
|
|
44
|
+
getRowId={(row) => row.id}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Page Identification Options
|
|
51
|
+
|
|
52
|
+
The DataTable supports two ways to identify the page for RBAC permissions:
|
|
53
|
+
|
|
54
|
+
#### Option 1: Page Name (Recommended)
|
|
55
|
+
```tsx
|
|
56
|
+
<DataTable
|
|
57
|
+
data={data}
|
|
58
|
+
columns={columns}
|
|
59
|
+
rbac={{
|
|
60
|
+
pageName: 'dishes' // Will be resolved to page ID by RBAC engine
|
|
61
|
+
}}
|
|
62
|
+
features={features}
|
|
63
|
+
/>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### Option 2: Page ID (Direct)
|
|
67
|
+
```tsx
|
|
68
|
+
<DataTable
|
|
69
|
+
data={data}
|
|
70
|
+
columns={columns}
|
|
71
|
+
rbac={{
|
|
72
|
+
pageId: 'uuid-here' // Use page ID directly
|
|
73
|
+
}}
|
|
74
|
+
features={features}
|
|
75
|
+
/>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Note:** You must provide either `pageName` or `pageId`, but not both. If both are provided, `pageId` takes precedence.
|
|
79
|
+
|
|
80
|
+
### Permission Mapping
|
|
81
|
+
|
|
82
|
+
The DataTable now checks the following page-based permissions:
|
|
83
|
+
|
|
84
|
+
| DataTable Feature | Permission Checked | Description |
|
|
85
|
+
|------------------|-------------------|-------------|
|
|
86
|
+
| **Data Display** | `read:page.{pageId}` | Controls whether data is visible |
|
|
87
|
+
| **Create Button** | `create:page.{pageId}` | Controls create functionality |
|
|
88
|
+
| **Edit Actions** | `update:page.{pageId}` | Controls edit/update functionality |
|
|
89
|
+
| **Delete Actions** | `delete:page.{pageId}` | Controls delete functionality |
|
|
90
|
+
| **Export** | `read:page.{pageId}` | Controls export functionality |
|
|
91
|
+
| **Import** | `create:page.{pageId}` | Controls import functionality |
|
|
92
|
+
|
|
93
|
+
### Role-Based Examples
|
|
94
|
+
|
|
95
|
+
#### Planner Role (AJ2025)
|
|
96
|
+
```tsx
|
|
97
|
+
// For a planner on the dishes page
|
|
98
|
+
<DataTable
|
|
99
|
+
data={dishes}
|
|
100
|
+
columns={columns}
|
|
101
|
+
rbac={{
|
|
102
|
+
pageId: 'dishes' // Will check read:page.dishes, create:page.dishes, etc.
|
|
103
|
+
}}
|
|
104
|
+
features={{
|
|
105
|
+
search: true,
|
|
106
|
+
pagination: true,
|
|
107
|
+
sorting: true,
|
|
108
|
+
filtering: true,
|
|
109
|
+
creation: true, // ✅ Allowed if planner has create:page.dishes
|
|
110
|
+
editing: true, // ✅ Allowed if planner has update:page.dishes
|
|
111
|
+
deletion: false, // ❌ Disabled if planner lacks delete:page.dishes
|
|
112
|
+
export: true, // ✅ Allowed if planner has read:page.dishes
|
|
113
|
+
import: false // ❌ Disabled if planner lacks create:page.dishes
|
|
114
|
+
}}
|
|
115
|
+
getRowId={(row) => row.id}
|
|
116
|
+
/>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### Viewer Role
|
|
120
|
+
```tsx
|
|
121
|
+
// For a viewer on the dishes page
|
|
122
|
+
<DataTable
|
|
123
|
+
data={dishes}
|
|
124
|
+
columns={columns}
|
|
125
|
+
rbac={{
|
|
126
|
+
pageId: 'dishes'
|
|
127
|
+
}}
|
|
128
|
+
features={{
|
|
129
|
+
search: true,
|
|
130
|
+
pagination: true,
|
|
131
|
+
sorting: true,
|
|
132
|
+
filtering: true,
|
|
133
|
+
creation: false, // ❌ Disabled - viewer typically lacks create:page.dishes
|
|
134
|
+
editing: false, // ❌ Disabled - viewer typically lacks update:page.dishes
|
|
135
|
+
deletion: false, // ❌ Disabled - viewer typically lacks delete:page.dishes
|
|
136
|
+
export: false, // ❌ Disabled - viewer typically lacks read:page.dishes
|
|
137
|
+
import: false // ❌ Disabled - viewer typically lacks create:page.dishes
|
|
138
|
+
}}
|
|
139
|
+
getRowId={(row) => row.id}
|
|
140
|
+
/>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Database Setup
|
|
144
|
+
|
|
145
|
+
### Required Page Permissions
|
|
146
|
+
|
|
147
|
+
Ensure your `rbac_page_permissions` table has entries for each page and role:
|
|
148
|
+
|
|
149
|
+
```sql
|
|
150
|
+
-- Example: Planner role permissions for dishes page
|
|
151
|
+
INSERT INTO rbac_page_permissions (app_page_id, operation, role_name, allowed) VALUES
|
|
152
|
+
((SELECT id FROM rbac_app_pages WHERE page_name = 'dishes'), 'read', 'planner', true),
|
|
153
|
+
((SELECT id FROM rbac_app_pages WHERE page_name = 'dishes'), 'create', 'planner', true),
|
|
154
|
+
((SELECT id FROM rbac_app_pages WHERE page_name = 'dishes'), 'update', 'planner', true),
|
|
155
|
+
((SELECT id FROM rbac_app_pages WHERE page_name = 'dishes'), 'delete', 'planner', false),
|
|
156
|
+
((SELECT id FROM rbac_app_pages WHERE page_name = 'dishes'), 'manage', 'planner', true);
|
|
157
|
+
|
|
158
|
+
-- Example: Viewer role permissions for dishes page
|
|
159
|
+
INSERT INTO rbac_page_permissions (app_page_id, operation, role_name, allowed) VALUES
|
|
160
|
+
((SELECT id FROM rbac_app_pages WHERE page_name = 'dishes'), 'read', 'viewer', true),
|
|
161
|
+
((SELECT id FROM rbac_app_pages WHERE page_name = 'dishes'), 'create', 'viewer', false),
|
|
162
|
+
((SELECT id FROM rbac_app_pages WHERE page_name = 'dishes'), 'update', 'viewer', false),
|
|
163
|
+
((SELECT id FROM rbac_app_pages WHERE page_name = 'dishes'), 'delete', 'viewer', false),
|
|
164
|
+
((SELECT id FROM rbac_app_pages WHERE page_name = 'dishes'), 'manage', 'viewer', false);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Migration Guide
|
|
168
|
+
|
|
169
|
+
### From Resource-Based to Page-Based Permissions
|
|
170
|
+
|
|
171
|
+
If you're migrating from the old resource-based system:
|
|
172
|
+
|
|
173
|
+
1. **Update DataTable Usage:**
|
|
174
|
+
```tsx
|
|
175
|
+
// OLD (resource-based)
|
|
176
|
+
rbac={{
|
|
177
|
+
resource: 'dishes'
|
|
178
|
+
}}
|
|
179
|
+
|
|
180
|
+
// NEW (page-based)
|
|
181
|
+
rbac={{
|
|
182
|
+
pageId: 'dishes' // Only pageId is required for page-based permissions
|
|
183
|
+
}}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
2. **Update Database Permissions:**
|
|
187
|
+
- Ensure `rbac_app_pages` table has entries for your pages
|
|
188
|
+
- Update `rbac_page_permissions` to use page-based permissions
|
|
189
|
+
- Remove old resource-based permission entries if they exist
|
|
190
|
+
|
|
191
|
+
3. **Test Permission Scenarios:**
|
|
192
|
+
- Test with different roles (planner, viewer, admin)
|
|
193
|
+
- Verify that DataTable features are properly enabled/disabled
|
|
194
|
+
- Ensure data is still visible even when write permissions are denied
|
|
195
|
+
|
|
196
|
+
## Troubleshooting
|
|
197
|
+
|
|
198
|
+
### Common Issues
|
|
199
|
+
|
|
200
|
+
1. **DataTable shows "Access Denied" even for read-only users:**
|
|
201
|
+
- Ensure `read:page.{pageId}` permission exists for the user's role
|
|
202
|
+
- Check that the page exists in `rbac_app_pages` table
|
|
203
|
+
|
|
204
|
+
2. **Create/Edit/Delete buttons not showing:**
|
|
205
|
+
- Verify that the corresponding page permissions exist in the database
|
|
206
|
+
- Check that the user's role has the required permissions
|
|
207
|
+
|
|
208
|
+
3. **Permission checks not working:**
|
|
209
|
+
- Ensure the `pageId` is correctly set in the DataTable rbac config
|
|
210
|
+
- Verify that the user has the correct event-app role for the context
|
|
211
|
+
|
|
212
|
+
### Debugging
|
|
213
|
+
|
|
214
|
+
Enable debug logging to see permission checks:
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
// In your app setup
|
|
218
|
+
<UnifiedAuthProvider
|
|
219
|
+
supabaseClient={supabase}
|
|
220
|
+
appName="your-app"
|
|
221
|
+
enableRBAC={true}
|
|
222
|
+
debug={true} // Enable debug logging
|
|
223
|
+
>
|
|
224
|
+
<YourApp />
|
|
225
|
+
</UnifiedAuthProvider>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Best Practices
|
|
229
|
+
|
|
230
|
+
1. **Always specify pageId:** Use the actual page identifier for proper permission checking
|
|
231
|
+
2. **Consistent naming:** Use the same page ID across your app for consistency
|
|
232
|
+
3. **Test thoroughly:** Verify permissions work correctly for all roles
|
|
233
|
+
4. **Document permissions:** Keep track of which roles have which permissions for each page
|
|
234
|
+
5. **Use feature flags:** Control DataTable features based on user permissions, not hardcoded values
|
|
235
|
+
|
|
236
|
+
## Example Complete Implementation
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
// pages/DishesPage.tsx
|
|
240
|
+
import { DataTable } from '@jmruthers/pace-core';
|
|
241
|
+
import { useUnifiedAuth } from '@jmruthers/pace-core/providers';
|
|
242
|
+
|
|
243
|
+
function DishesPage() {
|
|
244
|
+
const { user } = useUnifiedAuth();
|
|
245
|
+
const [dishes, setDishes] = useState([]);
|
|
246
|
+
const [loading, setLoading] = useState(true);
|
|
247
|
+
|
|
248
|
+
// Fetch dishes data
|
|
249
|
+
useEffect(() => {
|
|
250
|
+
fetchDishes().then(setDishes).finally(() => setLoading(false));
|
|
251
|
+
}, []);
|
|
252
|
+
|
|
253
|
+
const columns = [
|
|
254
|
+
{ accessorKey: 'id', header: 'ID' },
|
|
255
|
+
{ accessorKey: 'name', header: 'Dish Name' },
|
|
256
|
+
{ accessorKey: 'category', header: 'Category' },
|
|
257
|
+
{ accessorKey: 'allergens', header: 'Allergens' }
|
|
258
|
+
];
|
|
259
|
+
|
|
260
|
+
const handleCreateDish = (data) => {
|
|
261
|
+
// Create dish logic
|
|
262
|
+
console.log('Creating dish:', data);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const handleEditDish = (row, data) => {
|
|
266
|
+
// Edit dish logic
|
|
267
|
+
console.log('Editing dish:', row, data);
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const handleDeleteDish = (row) => {
|
|
271
|
+
// Delete dish logic
|
|
272
|
+
console.log('Deleting dish:', row);
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
if (loading) return <div>Loading dishes...</div>;
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<div>
|
|
279
|
+
<h1>Dishes Management</h1>
|
|
280
|
+
<DataTable
|
|
281
|
+
data={dishes}
|
|
282
|
+
columns={columns}
|
|
283
|
+
rbac={{
|
|
284
|
+
pageId: 'dishes' // This will check read:page.dishes, create:page.dishes, etc.
|
|
285
|
+
}}
|
|
286
|
+
features={{
|
|
287
|
+
search: true,
|
|
288
|
+
pagination: true,
|
|
289
|
+
sorting: true,
|
|
290
|
+
filtering: true,
|
|
291
|
+
creation: true, // Controlled by create:page.dishes permission
|
|
292
|
+
editing: true, // Controlled by update:page.dishes permission
|
|
293
|
+
deletion: true, // Controlled by delete:page.dishes permission
|
|
294
|
+
export: true, // Controlled by read:page.dishes permission
|
|
295
|
+
import: true // Controlled by create:page.dishes permission
|
|
296
|
+
}}
|
|
297
|
+
onCreateRow={handleCreateDish}
|
|
298
|
+
onEditRow={handleEditDish}
|
|
299
|
+
onDeleteRow={handleDeleteDish}
|
|
300
|
+
getRowId={(row) => row.id}
|
|
301
|
+
title="Dishes"
|
|
302
|
+
description="Manage event dishes and meal options"
|
|
303
|
+
/>
|
|
304
|
+
</div>
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
This implementation ensures that:
|
|
310
|
+
- Users with `read:page.dishes` can see the data
|
|
311
|
+
- Users with `create:page.dishes` can create new dishes
|
|
312
|
+
- Users with `update:page.dishes` can edit existing dishes
|
|
313
|
+
- Users with `delete:page.dishes` can delete dishes
|
|
314
|
+
- Users with `read:page.dishes` can export data
|
|
315
|
+
- Users with `create:page.dishes` can import data
|
|
316
|
+
|
|
317
|
+
The DataTable will automatically show/hide features based on the user's actual permissions for the dishes page.
|