@jmruthers/pace-core 0.5.121 → 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.
Files changed (254) hide show
  1. package/dist/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
  2. package/dist/{DataTable-DGZDJUYM.js → DataTable-WTS4IRF2.js} +7 -8
  3. package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
  4. package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
  5. package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
  6. package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
  7. package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
  8. package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
  9. package/dist/{chunk-VKOCWWVY.js 3.map → chunk-CX5M4ZAG.js.map} +1 -1
  10. package/dist/{chunk-HFBOFZ3Z.js → chunk-DHMFMXFV.js} +258 -243
  11. package/dist/chunk-DHMFMXFV.js.map +1 -0
  12. package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
  13. package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
  14. package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
  15. package/dist/chunk-GEVIB2UB.js.map +1 -0
  16. package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
  17. package/dist/chunk-IJOZZOGT.js.map +1 -0
  18. package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
  19. package/dist/chunk-M6DDYFUD.js.map +1 -0
  20. package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
  21. package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
  22. package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
  23. package/dist/chunk-XN6GWKMV.js.map +1 -0
  24. package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
  25. package/dist/chunk-ZBLK676C.js.map +1 -0
  26. package/dist/{chunk-QPI2CCBA.js → chunk-ZPJMYGEP.js} +149 -96
  27. package/dist/chunk-ZPJMYGEP.js.map +1 -0
  28. package/dist/components.d.ts +1 -1
  29. package/dist/components.js +11 -11
  30. package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
  31. package/dist/hooks.d.ts +1 -1
  32. package/dist/hooks.js +9 -8
  33. package/dist/hooks.js.map +1 -1
  34. package/dist/index.d.ts +6 -6
  35. package/dist/index.js +19 -17
  36. package/dist/index.js.map +1 -1
  37. package/dist/providers.d.ts +2 -2
  38. package/dist/providers.js +2 -3
  39. package/dist/rbac/index.js +7 -8
  40. package/dist/styles/index.d.ts +1 -1
  41. package/dist/styles/index.js +5 -3
  42. package/dist/theming/runtime.d.ts +73 -1
  43. package/dist/theming/runtime.js +5 -5
  44. package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
  45. package/dist/utils.d.ts +1 -1
  46. package/dist/utils.js +5 -5
  47. package/docs/api/classes/ColumnFactory.md +1 -1
  48. package/docs/api/classes/ErrorBoundary.md +1 -1
  49. package/docs/api/classes/InvalidScopeError.md +1 -1
  50. package/docs/api/classes/MissingUserContextError.md +1 -1
  51. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  52. package/docs/api/classes/PermissionDeniedError.md +1 -1
  53. package/docs/api/classes/PublicErrorBoundary.md +6 -6
  54. package/docs/api/classes/RBACAuditManager.md +1 -1
  55. package/docs/api/classes/RBACCache.md +1 -1
  56. package/docs/api/classes/RBACEngine.md +1 -1
  57. package/docs/api/classes/RBACError.md +1 -1
  58. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  59. package/docs/api/classes/SecureSupabaseClient.md +6 -6
  60. package/docs/api/classes/StorageUtils.md +1 -1
  61. package/docs/api/enums/FileCategory.md +1 -1
  62. package/docs/api/interfaces/AggregateConfig.md +1 -1
  63. package/docs/api/interfaces/ButtonProps.md +1 -1
  64. package/docs/api/interfaces/CardProps.md +1 -1
  65. package/docs/api/interfaces/ColorPalette.md +1 -1
  66. package/docs/api/interfaces/ColorShade.md +1 -1
  67. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  68. package/docs/api/interfaces/DataRecord.md +1 -1
  69. package/docs/api/interfaces/DataTableAction.md +1 -1
  70. package/docs/api/interfaces/DataTableColumn.md +1 -1
  71. package/docs/api/interfaces/DataTableProps.md +1 -1
  72. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  73. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  74. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  75. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  76. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  77. package/docs/api/interfaces/FileMetadata.md +1 -1
  78. package/docs/api/interfaces/FileReference.md +1 -1
  79. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  80. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  81. package/docs/api/interfaces/FileUploadProps.md +1 -1
  82. package/docs/api/interfaces/FooterProps.md +1 -1
  83. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  84. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  85. package/docs/api/interfaces/InputProps.md +1 -1
  86. package/docs/api/interfaces/LabelProps.md +1 -1
  87. package/docs/api/interfaces/LoginFormProps.md +1 -1
  88. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  89. package/docs/api/interfaces/NavigationContextType.md +1 -1
  90. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  91. package/docs/api/interfaces/NavigationItem.md +1 -1
  92. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  93. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  94. package/docs/api/interfaces/Organisation.md +1 -1
  95. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  96. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  97. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  98. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  99. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  100. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  101. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  102. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  103. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  104. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  105. package/docs/api/interfaces/PaletteData.md +1 -1
  106. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  107. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  108. package/docs/api/interfaces/PublicErrorBoundaryProps.md +7 -7
  109. package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
  110. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
  111. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  112. package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
  113. package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
  114. package/docs/api/interfaces/RBACConfig.md +1 -1
  115. package/docs/api/interfaces/RBACLogger.md +1 -1
  116. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  117. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  118. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  119. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  120. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  121. package/docs/api/interfaces/RouteConfig.md +1 -1
  122. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  123. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  124. package/docs/api/interfaces/StorageConfig.md +1 -1
  125. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  126. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  127. package/docs/api/interfaces/StorageListOptions.md +1 -1
  128. package/docs/api/interfaces/StorageListResult.md +1 -1
  129. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  130. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  131. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  132. package/docs/api/interfaces/StyleImport.md +1 -1
  133. package/docs/api/interfaces/SwitchProps.md +1 -1
  134. package/docs/api/interfaces/ToastActionElement.md +1 -1
  135. package/docs/api/interfaces/ToastProps.md +1 -1
  136. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  137. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  138. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  139. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  140. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  141. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  142. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  143. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  144. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  145. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  146. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  147. package/docs/api/interfaces/UserEventAccess.md +1 -1
  148. package/docs/api/interfaces/UserMenuProps.md +1 -1
  149. package/docs/api/interfaces/UserProfile.md +1 -1
  150. package/docs/api/modules.md +140 -30
  151. package/docs/best-practices/README.md +1 -1
  152. package/docs/implementation-guides/datatable-filtering.md +313 -0
  153. package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
  154. package/docs/implementation-guides/hierarchical-datatable.md +850 -0
  155. package/docs/implementation-guides/large-datasets.md +281 -0
  156. package/docs/implementation-guides/performance.md +403 -0
  157. package/docs/implementation-guides/public-pages.md +4 -4
  158. package/docs/migration/quick-migration-guide.md +320 -0
  159. package/docs/rbac/quick-start.md +16 -16
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
  162. package/docs/troubleshooting/debugging.md +1117 -0
  163. package/docs/troubleshooting/migration.md +918 -0
  164. package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
  165. package/examples/public-pages/PublicEventPage.tsx +41 -41
  166. package/examples/public-pages/PublicPageApp.tsx +33 -33
  167. package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
  168. package/package.json +4 -4
  169. package/src/__tests__/hooks/usePermissions.test.ts +265 -0
  170. package/src/components/DataTable/DataTable.test.tsx +9 -38
  171. package/src/components/DataTable/DataTable.tsx +0 -7
  172. package/src/components/DataTable/components/DataTableCore.tsx +66 -136
  173. package/src/components/DataTable/components/DataTableModals.tsx +25 -22
  174. package/src/components/DataTable/components/EditableRow.tsx +118 -42
  175. package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
  176. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
  177. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
  178. package/src/components/DataTable/utils/exportUtils.ts +3 -2
  179. package/src/components/Dialog/Dialog.tsx +1 -1
  180. package/src/components/Dialog/README.md +24 -24
  181. package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
  182. package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
  183. package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
  184. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
  185. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
  186. package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
  187. package/src/components/PublicLayout/EventLogo.tsx +175 -0
  188. package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
  189. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
  190. package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
  191. package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
  192. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
  193. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
  194. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
  195. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
  196. package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
  197. package/src/examples/PublicEventPage.tsx +41 -41
  198. package/src/examples/PublicPageApp.tsx +33 -33
  199. package/src/examples/PublicPageUsageExample.tsx +30 -30
  200. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
  201. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
  202. package/src/hooks/index.ts +1 -1
  203. package/src/hooks/public/usePublicEventLogo.ts +285 -0
  204. package/src/hooks/public/usePublicRouteParams.ts +21 -4
  205. package/src/hooks/useEventTheme.test.ts +119 -43
  206. package/src/hooks/useEventTheme.ts +84 -55
  207. package/src/index.ts +3 -1
  208. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
  209. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
  210. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
  211. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
  212. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
  213. package/src/rbac/secureClient.ts +4 -2
  214. package/src/services/EventService.ts +0 -66
  215. package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
  216. package/src/styles/index.ts +1 -1
  217. package/src/theming/__tests__/parseEventColours.test.ts +209 -0
  218. package/src/theming/parseEventColours.ts +123 -0
  219. package/src/theming/runtime.ts +3 -0
  220. package/src/types/__tests__/file-reference.test.ts +447 -0
  221. package/src/utils/formatDate.test.ts +11 -11
  222. package/src/utils/formatting.ts +3 -2
  223. package/dist/chunk-BDZUMRBD.js 3.map +0 -1
  224. package/dist/chunk-BHWIUEYH.js.map +0 -1
  225. package/dist/chunk-CGURJ27Z.js.map +0 -1
  226. package/dist/chunk-FKFHZUGF.js.map +0 -1
  227. package/dist/chunk-GKHF54DI 2.js +0 -619
  228. package/dist/chunk-GKHF54DI.js 2.map +0 -1
  229. package/dist/chunk-GZRXOUBE.js.map +0 -1
  230. package/dist/chunk-HFBOFZ3Z.js.map +0 -1
  231. package/dist/chunk-NZ32EONV.js.map +0 -1
  232. package/dist/chunk-O3NWNXDY 2.js +0 -76
  233. package/dist/chunk-QPI2CCBA.js.map +0 -1
  234. package/dist/chunk-SMJZMKYN.js.map +0 -1
  235. package/dist/chunk-TDNI6ZWL.js 2.map +0 -1
  236. package/dist/chunk-TDNI6ZWL.js.map +0 -1
  237. package/dist/chunk-VKOCWWVY.js.map +0 -1
  238. package/dist/chunk-WP5I5GLN 2.js +0 -1564
  239. package/dist/index 3.js +0 -856
  240. package/dist/providers 3.js +0 -38
  241. package/dist/providers.js 3.map +0 -1
  242. package/dist/types 3.js +0 -128
  243. package/dist/types.js 3.map +0 -1
  244. package/dist/useInactivityTracker-MRUU55XI.js 3.map +0 -1
  245. package/dist/utils.js 3.map +0 -1
  246. package/dist/validation 3.js +0 -479
  247. package/src/styles/semantic.css +0 -24
  248. /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-WTS4IRF2.js.map} +0 -0
  249. /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
  250. /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
  251. /package/dist/{chunk-CGURJ27Z.js 2.map → chunk-4MXVZVNS.js.map} +0 -0
  252. /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
  253. /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
  254. /package/dist/{chunk-NZ32EONV.js 2.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.