@jmruthers/pace-core 0.5.127 → 0.5.129
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-QZH6SEUM.js → DataTable-O2COE77K.js} +2 -2
- package/dist/{PublicLoadingSpinner-qqvM-NUe.d.ts → PublicLoadingSpinner-CUAnTvcg.d.ts} +7 -0
- package/dist/{chunk-JDBO5NCG.js → chunk-BJ7MCGY6.js} +66 -18
- package/dist/chunk-BJ7MCGY6.js.map +1 -0
- package/dist/{chunk-TMUNK34W.js → chunk-MOOJ2TK6.js} +37 -9
- package/dist/chunk-MOOJ2TK6.js.map +1 -0
- package/dist/components.d.ts +1 -1
- package/dist/components.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/utils.d.ts +1 -1
- 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/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 +27 -27
- 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/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 +10 -3
- package/docs/api-reference/components.md +24 -0
- package/docs/api-reference/types.md +28 -0
- package/docs/implementation-guides/data-tables.md +93 -10
- package/docs/implementation-guides/permission-enforcement.md +4 -0
- package/docs/rbac/super-admin-guide.md +43 -5
- package/package.json +1 -1
- package/src/components/DataTable/__tests__/DataTable.export.test.tsx +702 -0
- package/src/components/DataTable/components/DataTableCore.tsx +90 -39
- package/src/components/DataTable/index.ts +3 -1
- package/src/components/DataTable/types.ts +68 -0
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +60 -11
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +81 -1
- package/dist/chunk-JDBO5NCG.js.map +0 -1
- package/dist/chunk-TMUNK34W.js.map +0 -1
- /package/dist/{DataTable-QZH6SEUM.js.map → DataTable-O2COE77K.js.map} +0 -0
package/docs/api/modules.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
[@jmruthers/pace-core - v0.5.
|
|
1
|
+
[@jmruthers/pace-core - v0.5.129](README.md) / Exports
|
|
2
2
|
|
|
3
|
-
# @jmruthers/pace-core - v0.5.
|
|
3
|
+
# @jmruthers/pace-core - v0.5.129
|
|
4
4
|
|
|
5
5
|
**`File`**
|
|
6
6
|
|
|
@@ -2309,6 +2309,12 @@ This component is designed to work with React Router's nested routing pattern us
|
|
|
2309
2309
|
Outlet to render child routes. It provides integrated authentication, navigation,
|
|
2310
2310
|
and user management functionality.
|
|
2311
2311
|
|
|
2312
|
+
**Super Admin Access:** When `enforcePermissions={true}`, PaceAppLayout automatically
|
|
2313
|
+
checks if the user is a super admin before enforcing permissions. Super admins bypass
|
|
2314
|
+
all permission checks and can access any route without violations. The component extracts
|
|
2315
|
+
base page names from route paths (e.g., `/organisation/scouts-victoria` → `"organisation"`)
|
|
2316
|
+
for permission checking, which can be overridden using `pageIdMapping`.
|
|
2317
|
+
|
|
2312
2318
|
**Important:** The appName prop should use an APP_NAME constant declared in your App.tsx
|
|
2313
2319
|
file. This ensures consistency with public pages (via PublicPageProvider) which should
|
|
2314
2320
|
also receive the same APP_NAME constant. The logo URL is automatically constructed as
|
|
@@ -2325,6 +2331,7 @@ Features:
|
|
|
2325
2331
|
- Layout-level permission enforcement
|
|
2326
2332
|
- Permission-based navigation filtering
|
|
2327
2333
|
- Automatic page permission validation
|
|
2334
|
+
- Super admin bypass (super admins automatically bypass all permission checks)
|
|
2328
2335
|
|
|
2329
2336
|
#### Parameters
|
|
2330
2337
|
|
|
@@ -2455,7 +2462,7 @@ function AdminApp() {
|
|
|
2455
2462
|
|
|
2456
2463
|
#### Defined in
|
|
2457
2464
|
|
|
2458
|
-
[packages/core/src/components/PaceAppLayout/PaceAppLayout.tsx:
|
|
2465
|
+
[packages/core/src/components/PaceAppLayout/PaceAppLayout.tsx:344](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PaceAppLayout/PaceAppLayout.tsx#L344)
|
|
2459
2466
|
|
|
2460
2467
|
___
|
|
2461
2468
|
|
|
@@ -123,6 +123,12 @@ interface DataTableProps<TData extends DataRecord> {
|
|
|
123
123
|
onDeleteRow?: (row: TData) => void;
|
|
124
124
|
onCreateRow?: (data: Partial<TData>) => void;
|
|
125
125
|
onImport?: (data: TData[]) => void | Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* Custom export handler - allows full control over export columns and filename
|
|
128
|
+
* Receives ExportOptions with tableRows, allColumns, visibleColumns, and more
|
|
129
|
+
* If not provided, defaults to exporting all visible columns
|
|
130
|
+
*/
|
|
131
|
+
onExport?: (options: ExportOptions<TData>) => void | Promise<void>;
|
|
126
132
|
onDeleteSelected?: (selectedRows: Record<string, boolean>) => void;
|
|
127
133
|
|
|
128
134
|
// Performance
|
|
@@ -276,6 +282,24 @@ const columns: DataTableColumn<User>[] = [
|
|
|
276
282
|
onEditRow={handleEdit}
|
|
277
283
|
onDeleteRow={handleDelete}
|
|
278
284
|
onCreateRow={handleCreate}
|
|
285
|
+
onExport={async (options) => {
|
|
286
|
+
// Custom export with specific columns
|
|
287
|
+
const exportColumns = options.allColumns
|
|
288
|
+
.filter(col => ['name', 'email'].includes(col.accessorKey || ''))
|
|
289
|
+
.map(col => ({
|
|
290
|
+
header: col.header || col.accessorKey,
|
|
291
|
+
id: col.id || col.accessorKey,
|
|
292
|
+
accessorKey: col.accessorKey,
|
|
293
|
+
accessorFn: 'accessorFn' in col ? col.accessorFn : undefined,
|
|
294
|
+
}));
|
|
295
|
+
|
|
296
|
+
await exportToCSVWithTableRows(
|
|
297
|
+
options.tableRows,
|
|
298
|
+
exportColumns,
|
|
299
|
+
options.columnIdToTableColumn,
|
|
300
|
+
'users-export.csv'
|
|
301
|
+
);
|
|
302
|
+
}}
|
|
279
303
|
/>
|
|
280
304
|
```
|
|
281
305
|
|
|
@@ -334,6 +334,33 @@ interface ButtonProps {
|
|
|
334
334
|
}
|
|
335
335
|
```
|
|
336
336
|
|
|
337
|
+
### ExportOptions
|
|
338
|
+
|
|
339
|
+
Options provided to the `onExport` handler for custom export functionality.
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
interface ExportOptions<TData extends DataRecord> {
|
|
343
|
+
/** Filtered table rows with getValue() method for proper accessorFn evaluation */
|
|
344
|
+
tableRows: Array<{
|
|
345
|
+
original: TData;
|
|
346
|
+
getValue: (columnId: string) => any;
|
|
347
|
+
id: string;
|
|
348
|
+
}>;
|
|
349
|
+
/** All column definitions passed to the DataTable */
|
|
350
|
+
allColumns: DataTableColumn<TData>[];
|
|
351
|
+
/** Currently visible columns in the table */
|
|
352
|
+
visibleColumns: DataTableColumn<TData>[];
|
|
353
|
+
/** Mapping of column IDs to TanStack table column instances (for getValue() calls) */
|
|
354
|
+
columnIdToTableColumn: Map<string, any>;
|
|
355
|
+
/** Raw data array (unfiltered) */
|
|
356
|
+
data: TData[];
|
|
357
|
+
/** Default filename generated from table title */
|
|
358
|
+
filename: string;
|
|
359
|
+
/** TanStack table instance for advanced operations */
|
|
360
|
+
table: any;
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
337
364
|
### DataTableProps
|
|
338
365
|
|
|
339
366
|
Props for the DataTable component.
|
|
@@ -948,6 +975,7 @@ export type {
|
|
|
948
975
|
// UI Components
|
|
949
976
|
ButtonProps,
|
|
950
977
|
DataTableProps,
|
|
978
|
+
ExportOptions,
|
|
951
979
|
ColumnDef,
|
|
952
980
|
PaginationConfig,
|
|
953
981
|
SortingConfig,
|
|
@@ -1746,35 +1746,118 @@ The import automatically recognizes and maps:
|
|
|
1746
1746
|
/>
|
|
1747
1747
|
```
|
|
1748
1748
|
|
|
1749
|
-
### Custom Export
|
|
1749
|
+
### Custom Export
|
|
1750
1750
|
|
|
1751
1751
|
The export filename is automatically generated from the table `title` prop:
|
|
1752
1752
|
|
|
1753
1753
|
- If `title` is provided: `{title}_{date}.csv` (e.g., `meals_2024-04-11.csv`)
|
|
1754
1754
|
- If no `title`: `data_export_{date}.csv`
|
|
1755
1755
|
|
|
1756
|
-
To customize the filename, you can provide a custom `onExport` handler:
|
|
1756
|
+
By default, the DataTable exports all **visible columns**. To customize the export (different columns, custom filename, etc.), you can provide a custom `onExport` handler:
|
|
1757
1757
|
|
|
1758
1758
|
```tsx
|
|
1759
|
+
import { DataTable, type ExportOptions, exportToCSVWithTableRows, type ExportColumn } from '@jmruthers/pace-core';
|
|
1760
|
+
|
|
1759
1761
|
<DataTable
|
|
1760
1762
|
title="Meals"
|
|
1761
1763
|
columns={columns}
|
|
1762
1764
|
features={{ export: true }}
|
|
1763
|
-
onExport={async () => {
|
|
1764
|
-
//
|
|
1765
|
-
const
|
|
1766
|
-
|
|
1765
|
+
onExport={async (options: ExportOptions<Meal>) => {
|
|
1766
|
+
// Export only specific columns (different from visible columns)
|
|
1767
|
+
const exportColumnIds = ['name', 'email', 'role'];
|
|
1768
|
+
|
|
1769
|
+
const exportColumns: ExportColumn[] = exportColumnIds
|
|
1770
|
+
.map(columnId => {
|
|
1771
|
+
// Find the column definition
|
|
1772
|
+
const column = options.allColumns.find(col =>
|
|
1773
|
+
col.id === columnId || col.accessorKey === columnId
|
|
1774
|
+
);
|
|
1775
|
+
if (!column) return null;
|
|
1776
|
+
|
|
1777
|
+
// CRITICAL: The id must match the key in columnIdToTableColumn
|
|
1778
|
+
// TanStack Table uses String(column.id || column.accessorKey) as the column ID
|
|
1779
|
+
const tableColumnId = String(column.id || column.accessorKey);
|
|
1780
|
+
|
|
1781
|
+
// Verify this column ID exists in the mapping (for getValue() to work)
|
|
1782
|
+
if (!options.columnIdToTableColumn.has(tableColumnId)) {
|
|
1783
|
+
console.warn(`Column ID ${tableColumnId} not found in columnIdToTableColumn map`);
|
|
1784
|
+
return null;
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
return {
|
|
1788
|
+
header: column.header || column.accessorKey,
|
|
1789
|
+
id: tableColumnId, // Must be string and match columnIdToTableColumn key
|
|
1790
|
+
accessorKey: column.accessorKey,
|
|
1791
|
+
accessorFn: 'accessorFn' in column ? column.accessorFn : undefined,
|
|
1792
|
+
};
|
|
1793
|
+
})
|
|
1794
|
+
.filter((col): col is ExportColumn => col !== null);
|
|
1795
|
+
|
|
1796
|
+
// Use the provided table rows and column mapping for proper accessorFn evaluation
|
|
1797
|
+
await exportToCSVWithTableRows(
|
|
1798
|
+
options.tableRows,
|
|
1799
|
+
exportColumns,
|
|
1800
|
+
options.columnIdToTableColumn,
|
|
1801
|
+
'custom-export-name.csv'
|
|
1802
|
+
);
|
|
1767
1803
|
}}
|
|
1768
1804
|
/>
|
|
1769
1805
|
```
|
|
1770
1806
|
|
|
1807
|
+
### Export Options
|
|
1808
|
+
|
|
1809
|
+
The `onExport` handler receives an `ExportOptions` object with:
|
|
1810
|
+
|
|
1811
|
+
- `tableRows` - Filtered table rows with `getValue()` method for proper `accessorFn` evaluation
|
|
1812
|
+
- `allColumns` - All column definitions passed to the DataTable
|
|
1813
|
+
- `visibleColumns` - Currently visible columns in the table
|
|
1814
|
+
- `columnIdToTableColumn` - Mapping of column IDs to TanStack table column instances (for `getValue()` calls)
|
|
1815
|
+
- `data` - Raw data array (unfiltered)
|
|
1816
|
+
- `filename` - Default filename generated from table title
|
|
1817
|
+
- `table` - TanStack table instance for advanced operations
|
|
1818
|
+
|
|
1771
1819
|
### Export Column Selection
|
|
1772
1820
|
|
|
1773
|
-
**
|
|
1821
|
+
**Default Behavior**: Only **visible columns** are exported. If a column is hidden (via column visibility controls), it will not be included in the export.
|
|
1822
|
+
|
|
1823
|
+
**Custom Export**: Use the `onExport` handler to export different columns than what's visible in the table:
|
|
1824
|
+
|
|
1825
|
+
```tsx
|
|
1826
|
+
onExport={async (options) => {
|
|
1827
|
+
// Export all columns (including hidden ones)
|
|
1828
|
+
const allExportColumns: ExportColumn[] = options.allColumns
|
|
1829
|
+
.map(col => {
|
|
1830
|
+
// Get the table column ID (must match columnIdToTableColumn key)
|
|
1831
|
+
const tableColumnId = String(col.id || col.accessorKey);
|
|
1832
|
+
|
|
1833
|
+
// Only include columns that exist in the table mapping
|
|
1834
|
+
if (!options.columnIdToTableColumn.has(tableColumnId)) {
|
|
1835
|
+
return null;
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
return {
|
|
1839
|
+
header: col.header || col.accessorKey,
|
|
1840
|
+
id: tableColumnId, // Must be string and match columnIdToTableColumn key
|
|
1841
|
+
accessorKey: col.accessorKey,
|
|
1842
|
+
accessorFn: 'accessorFn' in col ? col.accessorFn : undefined,
|
|
1843
|
+
};
|
|
1844
|
+
})
|
|
1845
|
+
.filter((col): col is ExportColumn => col !== null);
|
|
1846
|
+
|
|
1847
|
+
await exportToCSVWithTableRows(
|
|
1848
|
+
options.tableRows,
|
|
1849
|
+
allExportColumns,
|
|
1850
|
+
options.columnIdToTableColumn,
|
|
1851
|
+
'all-columns-export.csv'
|
|
1852
|
+
);
|
|
1853
|
+
}}
|
|
1854
|
+
```
|
|
1774
1855
|
|
|
1775
|
-
|
|
1776
|
-
-
|
|
1777
|
-
-
|
|
1856
|
+
**Important Notes:**
|
|
1857
|
+
- The `id` field in `ExportColumn` **must** be a string and must exactly match a key in `columnIdToTableColumn`
|
|
1858
|
+
- Use `String(column.id || column.accessorKey)` to get the correct table column ID
|
|
1859
|
+
- Always verify the column ID exists in `columnIdToTableColumn` before using it
|
|
1860
|
+
- This ensures `getValue()` works correctly for columns with `accessorFn`
|
|
1778
1861
|
|
|
1779
1862
|
### Import Column Mapping
|
|
1780
1863
|
|
|
@@ -53,6 +53,8 @@ setupRBAC(supabase);
|
|
|
53
53
|
|
|
54
54
|
Layout-level enforcement provides a safety net that prevents consuming apps from forgetting to implement permission checks. It ensures that every route is automatically validated for permissions.
|
|
55
55
|
|
|
56
|
+
**Note:** Super admins automatically bypass all permission checks in PaceAppLayout. The component checks super admin status before enforcing permissions, ensuring super admins can access any route without violations.
|
|
57
|
+
|
|
56
58
|
### Basic Implementation
|
|
57
59
|
|
|
58
60
|
```tsx
|
|
@@ -107,6 +109,8 @@ Configure different permissions for different routes:
|
|
|
107
109
|
/>
|
|
108
110
|
```
|
|
109
111
|
|
|
112
|
+
**Page Name Mapping:** PaceAppLayout automatically extracts the base page name from route paths. For nested routes like `/organisation/scouts-victoria`, it uses `"organisation"` (the first path segment) as the page name. You can override this using `pageIdMapping` to provide custom page IDs for specific routes.
|
|
113
|
+
|
|
110
114
|
### Navigation Filtering
|
|
111
115
|
|
|
112
116
|
Filter navigation items based on user permissions:
|
|
@@ -260,7 +260,45 @@ function FilteredDataTable() {
|
|
|
260
260
|
}
|
|
261
261
|
```
|
|
262
262
|
|
|
263
|
-
## 8.
|
|
263
|
+
## 8. PaceAppLayout Super Admin Bypass
|
|
264
|
+
|
|
265
|
+
When using `PaceAppLayout` with `enforcePermissions={true}`, super admins automatically bypass all permission checks:
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
import { PaceAppLayout } from '@jmruthers/pace-core';
|
|
269
|
+
|
|
270
|
+
function App() {
|
|
271
|
+
return (
|
|
272
|
+
<UnifiedAuthProvider supabaseClient={supabase} appName="My App">
|
|
273
|
+
<Router>
|
|
274
|
+
<Routes>
|
|
275
|
+
<Route path="/" element={
|
|
276
|
+
<PaceAppLayout
|
|
277
|
+
appName="My Application"
|
|
278
|
+
enforcePermissions={true}
|
|
279
|
+
defaultPermission="read"
|
|
280
|
+
/>
|
|
281
|
+
}>
|
|
282
|
+
<Route index element={<HomePage />} />
|
|
283
|
+
<Route path="dashboard" element={<DashboardPage />} />
|
|
284
|
+
<Route path="organisation/:orgSlug" element={<OrganisationPage />} />
|
|
285
|
+
</Route>
|
|
286
|
+
</Routes>
|
|
287
|
+
</Router>
|
|
288
|
+
</UnifiedAuthProvider>
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Key Features:**
|
|
294
|
+
- Super admins bypass all permission checks automatically
|
|
295
|
+
- No strict mode violations logged for super admins
|
|
296
|
+
- Page name extraction: nested routes like `/organisation/scouts-victoria` use `"organisation"` as the page name
|
|
297
|
+
- Custom page IDs can be provided via `pageIdMapping` prop
|
|
298
|
+
|
|
299
|
+
**Note:** PaceAppLayout checks super admin status before enforcing permissions, ensuring super admins can access any route without violations or access denied errors.
|
|
300
|
+
|
|
301
|
+
## 9. Navigation Guards
|
|
264
302
|
|
|
265
303
|
Protect entire routes for super admins:
|
|
266
304
|
|
|
@@ -303,7 +341,7 @@ function AdminRoutes() {
|
|
|
303
341
|
}
|
|
304
342
|
```
|
|
305
343
|
|
|
306
|
-
##
|
|
344
|
+
## 10. Environment-Specific Configuration
|
|
307
345
|
|
|
308
346
|
You can also check for super admin access in your environment configuration:
|
|
309
347
|
|
|
@@ -321,7 +359,7 @@ const appConfig = {
|
|
|
321
359
|
};
|
|
322
360
|
```
|
|
323
361
|
|
|
324
|
-
##
|
|
362
|
+
## 11. Best Practices
|
|
325
363
|
|
|
326
364
|
### ✅ Do:
|
|
327
365
|
- Always check `isSuperAdmin` first for performance
|
|
@@ -336,7 +374,7 @@ const appConfig = {
|
|
|
336
374
|
- Skip permission checks assuming super admin status
|
|
337
375
|
- Use anon key for super admin operations
|
|
338
376
|
|
|
339
|
-
##
|
|
377
|
+
## 12. Testing Super Admin Access
|
|
340
378
|
|
|
341
379
|
```tsx
|
|
342
380
|
import { render, screen } from '@testing-library/react';
|
|
@@ -373,7 +411,7 @@ test('shows regular content for non-super admin users', () => {
|
|
|
373
411
|
});
|
|
374
412
|
```
|
|
375
413
|
|
|
376
|
-
##
|
|
414
|
+
## 13. Practical Examples
|
|
377
415
|
|
|
378
416
|
### Basic Super Admin Check
|
|
379
417
|
|