@jmruthers/pace-core 0.5.126 → 0.5.127
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-6FN7XDXA.js → DataTable-QZH6SEUM.js} +6 -6
- package/dist/{PublicLoadingSpinner-CaoRbHvJ.d.ts → PublicLoadingSpinner-qqvM-NUe.d.ts} +34 -21
- package/dist/{UnifiedAuthProvider-6C47WIML.js → UnifiedAuthProvider-CQDZRJIS.js} +3 -3
- package/dist/{chunk-ZBLK676C.js → chunk-3CG5L6RN.js} +1 -19
- package/dist/chunk-3CG5L6RN.js.map +1 -0
- package/dist/{chunk-35ZDPMBM.js → chunk-BYXRHAIF.js} +3 -3
- package/dist/{chunk-IJOZZOGT.js → chunk-CQZU6TFE.js} +5 -5
- package/dist/{chunk-C43QIDN3.js → chunk-CTJRBUX2.js} +2 -2
- package/dist/{chunk-ESJTIADP.js → chunk-F64FFPOZ.js} +5 -15
- package/dist/{chunk-ESJTIADP.js.map → chunk-F64FFPOZ.js.map} +1 -1
- package/dist/{chunk-QXGLU2O5.js → chunk-JDBO5NCG.js} +249 -132
- package/dist/chunk-JDBO5NCG.js.map +1 -0
- package/dist/{chunk-4MXVZVNS.js → chunk-TGIY2AR2.js} +2 -2
- package/dist/{chunk-R4CRQUJJ.js → chunk-TMUNK34W.js} +428 -446
- package/dist/chunk-TMUNK34W.js.map +1 -0
- package/dist/{chunk-XN6GWKMV.js → chunk-VZ5OR6HD.js} +161 -14
- package/dist/chunk-VZ5OR6HD.js.map +1 -0
- package/dist/{chunk-QWNJCQXZ.js → chunk-ZV77RZMU.js} +2 -2
- package/dist/{chunk-NZGLXZGP.js → chunk-ZYZCRSBD.js} +3 -54
- package/dist/chunk-ZYZCRSBD.js.map +1 -0
- package/dist/components.d.ts +1 -1
- package/dist/components.js +9 -9
- package/dist/hooks.js +7 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +12 -12
- package/dist/providers.js +2 -2
- package/dist/rbac/index.js +7 -7
- 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 +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 +10 -62
- 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 +46 -28
- package/docs/architecture/rpc-function-standards.md +39 -5
- package/package.json +1 -1
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/DataTable/components/ImportModal.tsx +134 -2
- package/src/components/Dialog/Dialog.tsx +0 -13
- package/src/components/FileDisplay/FileDisplay.tsx +76 -0
- package/src/components/Header/Header.tsx +5 -0
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -39
- package/src/components/PublicLayout/PublicPageFooter.tsx +1 -1
- package/src/components/PublicLayout/PublicPageHeader.tsx +69 -128
- package/src/components/PublicLayout/PublicPageLayout.tsx +4 -4
- package/src/components/PublicLayout/PublicPageProvider.tsx +12 -3
- package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +1 -1
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +3 -18
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +3 -1
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +11 -5
- package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +8 -7
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +41 -46
- package/src/hooks/public/usePublicFileDisplay.ts +176 -7
- package/src/hooks/public/usePublicRouteParams.ts +0 -12
- package/src/hooks/useAppConfig.ts +15 -6
- package/src/hooks/usePermissionCache.test.ts +12 -4
- package/src/hooks/usePermissionCache.ts +3 -19
- package/src/hooks/useSecureDataAccess.ts +0 -63
- package/src/services/EventService.ts +0 -19
- package/dist/chunk-NZGLXZGP.js.map +0 -1
- package/dist/chunk-QXGLU2O5.js.map +0 -1
- package/dist/chunk-R4CRQUJJ.js.map +0 -1
- package/dist/chunk-XN6GWKMV.js.map +0 -1
- package/dist/chunk-ZBLK676C.js.map +0 -1
- /package/dist/{DataTable-6FN7XDXA.js.map → DataTable-QZH6SEUM.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-6C47WIML.js.map → UnifiedAuthProvider-CQDZRJIS.js.map} +0 -0
- /package/dist/{chunk-35ZDPMBM.js.map → chunk-BYXRHAIF.js.map} +0 -0
- /package/dist/{chunk-IJOZZOGT.js.map → chunk-CQZU6TFE.js.map} +0 -0
- /package/dist/{chunk-C43QIDN3.js.map → chunk-CTJRBUX2.js.map} +0 -0
- /package/dist/{chunk-4MXVZVNS.js.map → chunk-TGIY2AR2.js.map} +0 -0
- /package/dist/{chunk-QWNJCQXZ.js.map → chunk-ZV77RZMU.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.127](README.md) / Exports
|
|
2
2
|
|
|
3
|
-
# @jmruthers/pace-core - v0.5.
|
|
3
|
+
# @jmruthers/pace-core - v0.5.127
|
|
4
4
|
|
|
5
5
|
**`File`**
|
|
6
6
|
|
|
@@ -1558,7 +1558,7 @@ JSX.Element - The dialog footer container using semantic <footer> element
|
|
|
1558
1558
|
|
|
1559
1559
|
#### Defined in
|
|
1560
1560
|
|
|
1561
|
-
[packages/core/src/components/Dialog/Dialog.tsx:
|
|
1561
|
+
[packages/core/src/components/Dialog/Dialog.tsx:677](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Dialog/Dialog.tsx#L677)
|
|
1562
1562
|
|
|
1563
1563
|
___
|
|
1564
1564
|
|
|
@@ -1578,7 +1578,7 @@ ___
|
|
|
1578
1578
|
|
|
1579
1579
|
#### Defined in
|
|
1580
1580
|
|
|
1581
|
-
[packages/core/src/components/Dialog/Dialog.tsx:
|
|
1581
|
+
[packages/core/src/components/Dialog/Dialog.tsx:694](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Dialog/Dialog.tsx#L694)
|
|
1582
1582
|
|
|
1583
1583
|
___
|
|
1584
1584
|
|
|
@@ -1598,7 +1598,7 @@ ___
|
|
|
1598
1598
|
|
|
1599
1599
|
#### Defined in
|
|
1600
1600
|
|
|
1601
|
-
[packages/core/src/components/Dialog/Dialog.tsx:
|
|
1601
|
+
[packages/core/src/components/Dialog/Dialog.tsx:729](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Dialog/Dialog.tsx#L729)
|
|
1602
1602
|
|
|
1603
1603
|
___
|
|
1604
1604
|
|
|
@@ -1668,7 +1668,7 @@ React element with file display
|
|
|
1668
1668
|
|
|
1669
1669
|
#### Defined in
|
|
1670
1670
|
|
|
1671
|
-
[packages/core/src/components/FileDisplay/FileDisplay.tsx:
|
|
1671
|
+
[packages/core/src/components/FileDisplay/FileDisplay.tsx:803](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/FileDisplay/FileDisplay.tsx#L803)
|
|
1672
1672
|
|
|
1673
1673
|
___
|
|
1674
1674
|
|
|
@@ -1767,6 +1767,11 @@ and customizable branding support.
|
|
|
1767
1767
|
A flexible header component that supports various configurations including custom logos,
|
|
1768
1768
|
navigation menus, user authentication, event selection, and custom actions.
|
|
1769
1769
|
|
|
1770
|
+
**Logo Display:** When used via PaceAppLayout, the logo URL is automatically constructed
|
|
1771
|
+
from the appName prop as `/${appName.toLowerCase()}_logo_wide.svg`. The appName should
|
|
1772
|
+
come from an APP_NAME constant declared in your App.tsx file to ensure consistency across
|
|
1773
|
+
authenticated and public pages.
|
|
1774
|
+
|
|
1770
1775
|
Features:
|
|
1771
1776
|
- Customizable logo (URL or custom component)
|
|
1772
1777
|
- Clickable logo that automatically routes to dashboard (configurable via logoHref)
|
|
@@ -1872,7 +1877,7 @@ function MinimalHeader() {
|
|
|
1872
1877
|
|
|
1873
1878
|
#### Defined in
|
|
1874
1879
|
|
|
1875
|
-
[packages/core/src/components/Header/Header.tsx:
|
|
1880
|
+
[packages/core/src/components/Header/Header.tsx:234](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Header/Header.tsx#L234)
|
|
1876
1881
|
|
|
1877
1882
|
___
|
|
1878
1883
|
|
|
@@ -2304,6 +2309,11 @@ This component is designed to work with React Router's nested routing pattern us
|
|
|
2304
2309
|
Outlet to render child routes. It provides integrated authentication, navigation,
|
|
2305
2310
|
and user management functionality.
|
|
2306
2311
|
|
|
2312
|
+
**Important:** The appName prop should use an APP_NAME constant declared in your App.tsx
|
|
2313
|
+
file. This ensures consistency with public pages (via PublicPageProvider) which should
|
|
2314
|
+
also receive the same APP_NAME constant. The logo URL is automatically constructed as
|
|
2315
|
+
`/${appName.toLowerCase()}_logo_wide.svg` from the public folder.
|
|
2316
|
+
|
|
2307
2317
|
Features:
|
|
2308
2318
|
- React Router v6 integration with nested routing
|
|
2309
2319
|
- Unified authentication integration
|
|
@@ -2334,17 +2344,20 @@ Basic React Router setup with permission enforcement (RECOMMENDED):
|
|
|
2334
2344
|
```tsx
|
|
2335
2345
|
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
|
2336
2346
|
import { UnifiedAuthProvider } from '@jmruthers/pace-core/providers';
|
|
2337
|
-
import { PaceAppLayout, PaceLoginPage } from '@jmruthers/pace-core';
|
|
2347
|
+
import { PaceAppLayout, PaceLoginPage, PublicPageApp } from '@jmruthers/pace-core';
|
|
2348
|
+
|
|
2349
|
+
const APP_NAME = 'CORE';
|
|
2338
2350
|
|
|
2339
2351
|
function App() {
|
|
2340
2352
|
return (
|
|
2341
|
-
<UnifiedAuthProvider supabaseClient={supabase} appName=
|
|
2353
|
+
<UnifiedAuthProvider supabaseClient={supabase} appName={APP_NAME}>
|
|
2342
2354
|
<Router>
|
|
2343
2355
|
<Routes>
|
|
2344
|
-
<Route path="/login" element={<PaceLoginPage appName=
|
|
2356
|
+
<Route path="/login" element={<PaceLoginPage appName={APP_NAME} />} />
|
|
2357
|
+
<Route path="/events/*" element={<PublicPageApp appName={APP_NAME} />} />
|
|
2345
2358
|
<Route path="/" element={
|
|
2346
2359
|
<PaceAppLayout
|
|
2347
|
-
appName=
|
|
2360
|
+
appName={APP_NAME}
|
|
2348
2361
|
enforcePermissions={true}
|
|
2349
2362
|
defaultPermission="read"
|
|
2350
2363
|
/>
|
|
@@ -2442,7 +2455,7 @@ function AdminApp() {
|
|
|
2442
2455
|
|
|
2443
2456
|
#### Defined in
|
|
2444
2457
|
|
|
2445
|
-
[packages/core/src/components/PaceAppLayout/PaceAppLayout.tsx:
|
|
2458
|
+
[packages/core/src/components/PaceAppLayout/PaceAppLayout.tsx:336](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PaceAppLayout/PaceAppLayout.tsx#L336)
|
|
2446
2459
|
|
|
2447
2460
|
___
|
|
2448
2461
|
|
|
@@ -2823,14 +2836,18 @@ Header component for public pages with event-specific branding
|
|
|
2823
2836
|
This component displays the app logo, event logo, and event information
|
|
2824
2837
|
in a clean, accessible layout suitable for public pages.
|
|
2825
2838
|
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2839
|
+
The app logo is automatically generated from the appName using the pattern:
|
|
2840
|
+
`/{appName.toLowerCase()}_logo_wide.svg` from the public folder.
|
|
2841
|
+
|
|
2842
|
+
**Important:** The appName is obtained from PublicPageProvider context, which should
|
|
2843
|
+
receive the APP_NAME constant from your App.tsx file. This ensures consistency with
|
|
2844
|
+
authenticated pages that use the same APP_NAME constant.
|
|
2831
2845
|
|
|
2832
|
-
|
|
2833
|
-
|
|
2846
|
+
**Event Logo Requirements:**
|
|
2847
|
+
- Event logo files must be marked as `is_public = true` in the `file_references` table
|
|
2848
|
+
- The RPC function `data_file_reference_by_category_list` must be accessible to the anonymous/public role
|
|
2849
|
+
- Storage bucket must allow public read access for logo files
|
|
2850
|
+
- If no public logo is available, a fallback UI with event initials will be displayed
|
|
2834
2851
|
|
|
2835
2852
|
#### Parameters
|
|
2836
2853
|
|
|
@@ -2846,7 +2863,7 @@ React element with public page header
|
|
|
2846
2863
|
|
|
2847
2864
|
#### Defined in
|
|
2848
2865
|
|
|
2849
|
-
[packages/core/src/components/PublicLayout/PublicPageHeader.tsx:
|
|
2866
|
+
[packages/core/src/components/PublicLayout/PublicPageHeader.tsx:103](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageHeader.tsx#L103)
|
|
2850
2867
|
|
|
2851
2868
|
___
|
|
2852
2869
|
|
|
@@ -2922,6 +2939,7 @@ This provider:
|
|
|
2922
2939
|
- Provides environment variables for public data access
|
|
2923
2940
|
- Includes error boundary for graceful error handling
|
|
2924
2941
|
- Is completely separate from the main app context
|
|
2942
|
+
- Provides appName for consistent logo display
|
|
2925
2943
|
|
|
2926
2944
|
#### Parameters
|
|
2927
2945
|
|
|
@@ -2935,7 +2953,7 @@ This provider:
|
|
|
2935
2953
|
|
|
2936
2954
|
#### Defined in
|
|
2937
2955
|
|
|
2938
|
-
[packages/core/src/components/PublicLayout/PublicPageProvider.tsx:
|
|
2956
|
+
[packages/core/src/components/PublicLayout/PublicPageProvider.tsx:70](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageProvider.tsx#L70)
|
|
2939
2957
|
|
|
2940
2958
|
___
|
|
2941
2959
|
|
|
@@ -2953,7 +2971,7 @@ Public page context with environment variables
|
|
|
2953
2971
|
|
|
2954
2972
|
#### Defined in
|
|
2955
2973
|
|
|
2956
|
-
[packages/core/src/components/PublicLayout/PublicPageProvider.tsx:
|
|
2974
|
+
[packages/core/src/components/PublicLayout/PublicPageProvider.tsx:128](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageProvider.tsx#L128)
|
|
2957
2975
|
|
|
2958
2976
|
___
|
|
2959
2977
|
|
|
@@ -2971,7 +2989,7 @@ True if we're in a public page context
|
|
|
2971
2989
|
|
|
2972
2990
|
#### Defined in
|
|
2973
2991
|
|
|
2974
|
-
[packages/core/src/components/PublicLayout/PublicPageProvider.tsx:
|
|
2992
|
+
[packages/core/src/components/PublicLayout/PublicPageProvider.tsx:143](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageProvider.tsx#L143)
|
|
2975
2993
|
|
|
2976
2994
|
___
|
|
2977
2995
|
|
|
@@ -3858,7 +3876,7 @@ Useful for testing or when you need to force refresh all data
|
|
|
3858
3876
|
|
|
3859
3877
|
#### Defined in
|
|
3860
3878
|
|
|
3861
|
-
[packages/core/src/hooks/public/usePublicFileDisplay.ts:
|
|
3879
|
+
[packages/core/src/hooks/public/usePublicFileDisplay.ts:542](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicFileDisplay.ts#L542)
|
|
3862
3880
|
|
|
3863
3881
|
___
|
|
3864
3882
|
|
|
@@ -3879,7 +3897,7 @@ Get cache statistics for debugging
|
|
|
3879
3897
|
|
|
3880
3898
|
#### Defined in
|
|
3881
3899
|
|
|
3882
|
-
[packages/core/src/hooks/public/usePublicFileDisplay.ts:
|
|
3900
|
+
[packages/core/src/hooks/public/usePublicFileDisplay.ts:553](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicFileDisplay.ts#L553)
|
|
3883
3901
|
|
|
3884
3902
|
___
|
|
3885
3903
|
|
|
@@ -3935,7 +3953,7 @@ Useful when you only need the event code and will fetch data separately
|
|
|
3935
3953
|
|
|
3936
3954
|
#### Defined in
|
|
3937
3955
|
|
|
3938
|
-
[packages/core/src/hooks/public/usePublicRouteParams.ts:
|
|
3956
|
+
[packages/core/src/hooks/public/usePublicRouteParams.ts:212](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicRouteParams.ts#L212)
|
|
3939
3957
|
|
|
3940
3958
|
___
|
|
3941
3959
|
|
|
@@ -3958,7 +3976,7 @@ Utility function to generate public route paths
|
|
|
3958
3976
|
|
|
3959
3977
|
#### Defined in
|
|
3960
3978
|
|
|
3961
|
-
[packages/core/src/hooks/public/usePublicRouteParams.ts:
|
|
3979
|
+
[packages/core/src/hooks/public/usePublicRouteParams.ts:248](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicRouteParams.ts#L248)
|
|
3962
3980
|
|
|
3963
3981
|
___
|
|
3964
3982
|
|
|
@@ -3981,7 +3999,7 @@ Supports 2-50 character event codes
|
|
|
3981
3999
|
|
|
3982
4000
|
#### Defined in
|
|
3983
4001
|
|
|
3984
|
-
[packages/core/src/hooks/public/usePublicRouteParams.ts:
|
|
4002
|
+
[packages/core/src/hooks/public/usePublicRouteParams.ts:263](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicRouteParams.ts#L263)
|
|
3985
4003
|
|
|
3986
4004
|
___
|
|
3987
4005
|
|
|
@@ -75,8 +75,9 @@ get_cake_meals -- Wrong: wrong prefix order
|
|
|
75
75
|
|
|
76
76
|
```sql
|
|
77
77
|
CREATE OR REPLACE FUNCTION public.<family>_<domain>_<verb>(
|
|
78
|
-
p_param1
|
|
79
|
-
p_param2
|
|
78
|
+
p_param1 TEXT, -- ⚠️ Use TEXT for strings, NOT CHARACTER VARYING
|
|
79
|
+
p_param2 INTEGER DEFAULT NULL, -- Use INTEGER, DOUBLE PRECISION, SMALLINT for numbers
|
|
80
|
+
p_param3 BOOLEAN DEFAULT NULL, -- Use BOOLEAN for boolean values
|
|
80
81
|
p_user_id UUID DEFAULT auth.uid(),
|
|
81
82
|
p_organisation_id UUID DEFAULT NULL
|
|
82
83
|
)
|
|
@@ -150,11 +151,23 @@ $$;
|
|
|
150
151
|
|
|
151
152
|
2. **Always set `SET search_path TO 'public'`** - Prevents SQL injection attacks
|
|
152
153
|
|
|
153
|
-
3. **Parameter Naming**:
|
|
154
|
+
3. **Parameter Naming and Types**:
|
|
154
155
|
- Prefix all parameters with `p_` (e.g., `p_event_id`, `p_user_id`)
|
|
155
156
|
- Use `p_user_id UUID DEFAULT auth.uid()` for user context
|
|
156
157
|
- Use `p_organisation_id UUID DEFAULT NULL` for organisation context
|
|
157
158
|
- Use descriptive names
|
|
159
|
+
- **⚠️ CRITICAL: Parameter Type Requirements**:
|
|
160
|
+
- **String parameters MUST use `TEXT`**, NOT `CHARACTER VARYING` or `VARCHAR`
|
|
161
|
+
- **Numeric parameters**: Use `DOUBLE PRECISION` for decimal numbers, `INTEGER` for whole numbers, `SMALLINT` for small integers
|
|
162
|
+
- **Boolean parameters**: Use `BOOLEAN`
|
|
163
|
+
- **Date/Time parameters**: Use `DATE`, `TIMESTAMP`, or `TIMESTAMPTZ` as appropriate
|
|
164
|
+
- **UUID parameters**: Use `UUID`
|
|
165
|
+
- **Why TEXT instead of CHARACTER VARYING?**
|
|
166
|
+
- Application code calls functions with TEXT parameters
|
|
167
|
+
- PostgreSQL cannot automatically choose between TEXT and CHARACTER VARYING versions
|
|
168
|
+
- Having both creates ambiguity errors: "Could not choose the best candidate function"
|
|
169
|
+
- TEXT is the standard PostgreSQL type for string parameters in RPC functions
|
|
170
|
+
- Even though database columns may use CHARACTER VARYING, function parameters should use TEXT
|
|
158
171
|
|
|
159
172
|
4. **Variable Naming**:
|
|
160
173
|
- Prefix local variables with `v_` (e.g., `v_is_super_admin`, `v_event_exists`)
|
|
@@ -710,7 +723,22 @@ rbac_check_permission_simplified(
|
|
|
710
723
|
|
|
711
724
|
3. **Missing page_id parameter**: Always provide the page name as the last parameter (e.g., `'dishes'`, `'meals'`, `'distribution'`)
|
|
712
725
|
|
|
713
|
-
4. **
|
|
726
|
+
4. **Using CHARACTER VARYING instead of TEXT for string parameters**:
|
|
727
|
+
- ❌ **WRONG**: `p_unit_id CHARACTER VARYING` or `p_dish_name VARCHAR`
|
|
728
|
+
- ✅ **CORRECT**: `p_unit_id TEXT` or `p_dish_name TEXT`
|
|
729
|
+
- **CRITICAL**: All string parameters MUST use `TEXT`, NOT `CHARACTER VARYING` or `VARCHAR`
|
|
730
|
+
- Having both TEXT and CHARACTER VARYING versions causes "Could not choose the best candidate function" errors
|
|
731
|
+
- Application code calls functions with TEXT parameters, so functions must accept TEXT
|
|
732
|
+
- Even though database columns may use CHARACTER VARYING, function parameters should use TEXT
|
|
733
|
+
|
|
734
|
+
5. **Creating duplicate function versions**:
|
|
735
|
+
- ❌ **WRONG**: Creating both `app_cake_unit_update(TEXT, ...)` and `app_cake_unit_update(CHARACTER VARYING, ...)`
|
|
736
|
+
- ✅ **CORRECT**: Only create `app_cake_unit_update(TEXT, ...)`
|
|
737
|
+
- Before creating a new function, check if a version already exists
|
|
738
|
+
- If updating a function, use `CREATE OR REPLACE FUNCTION` to update the existing version
|
|
739
|
+
- If you need to change parameter types, drop the old version first: `DROP FUNCTION IF EXISTS ... CASCADE;`
|
|
740
|
+
|
|
741
|
+
6. **Ambiguous column references**:
|
|
714
742
|
- ❌ **WRONG**: `SELECT mealtype_name FROM cake_mealtype`
|
|
715
743
|
- ✅ **CORRECT**: `SELECT cake_mealtype.mealtype_name FROM cake_mealtype`
|
|
716
744
|
- Always fully qualify table names when there might be ambiguity
|
|
@@ -718,7 +746,7 @@ rbac_check_permission_simplified(
|
|
|
718
746
|
- Common ambiguous columns: `organisation_id`, `created_by`, `updated_by`, `created_at`, `updated_at`
|
|
719
747
|
- See "Avoiding Ambiguous Column References" section below for detailed guidance
|
|
720
748
|
|
|
721
|
-
|
|
749
|
+
7. **Not checking existing migrations**: Before creating a new migration, check if a similar one already exists to avoid duplicates
|
|
722
750
|
|
|
723
751
|
### Updating Existing Functions
|
|
724
752
|
|
|
@@ -1046,6 +1074,12 @@ When creating or reviewing an RPC function, ensure:
|
|
|
1046
1074
|
- ✅ Includes `GRANT EXECUTE` statement
|
|
1047
1075
|
- ✅ Tested with various scenarios
|
|
1048
1076
|
|
|
1077
|
+
### ⚠️ Critical Parameter Type Requirements
|
|
1078
|
+
- ✅ **String parameters use TEXT**: All string parameters MUST use `TEXT`, NOT `CHARACTER VARYING` or `VARCHAR`
|
|
1079
|
+
- ✅ **No duplicate function versions**: Only one version of each function exists (TEXT version, not CHARACTER VARYING)
|
|
1080
|
+
- ✅ **Numeric parameters use correct types**: `DOUBLE PRECISION` for decimals, `INTEGER` for whole numbers, `SMALLINT` for small integers
|
|
1081
|
+
- ✅ **Why TEXT?**: Application code calls with TEXT parameters; having both TEXT and CHARACTER VARYING versions causes ambiguity errors
|
|
1082
|
+
|
|
1049
1083
|
### ⚠️ Critical Permission Format
|
|
1050
1084
|
- ✅ **Permission format is correct**: `'operation:page.{pageName}'` (e.g., `'create:page.dishes'`, `'read:page.meals'`)
|
|
1051
1085
|
- ✅ **NOT using wrong format**: `'operation:resource'` (e.g., `'create:dishes'`, `'read:meals'`)
|
package/package.json
CHANGED
|
@@ -74,7 +74,7 @@ function getButtonClasses(variant: ButtonProps['variant'] = 'default', size: But
|
|
|
74
74
|
outline: 'border border-main-300 bg-background shadow-sm hover:bg-acc-400',
|
|
75
75
|
secondary: 'bg-sec-100 text-sec-900 shadow-sm hover:bg-acc-400',
|
|
76
76
|
ghost: 'hover:bg-acc-400',
|
|
77
|
-
link: 'text-
|
|
77
|
+
link: 'text-main-700 underline-offset-4 hover:underline hover:drop-shadow-lg hover:drop-shadow-acc-400',
|
|
78
78
|
};
|
|
79
79
|
|
|
80
80
|
const sizeClasses = {
|
|
@@ -39,6 +39,7 @@ import React, { useState, useRef, useEffect } from 'react';
|
|
|
39
39
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../Dialog';
|
|
40
40
|
import { Button } from '../../Button/Button';
|
|
41
41
|
import { Input } from '../../Input/Input';
|
|
42
|
+
import { Progress } from '../../Progress/Progress';
|
|
42
43
|
import { Upload, FileText, AlertCircle } from 'lucide-react';
|
|
43
44
|
import { createLogger } from '../../../utils/logger';
|
|
44
45
|
|
|
@@ -115,6 +116,7 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
|
|
|
115
116
|
const [previewData, setPreviewData] = useState<Array<Record<string, unknown>> | null>(null);
|
|
116
117
|
const [totalCount, setTotalCount] = useState<number>(0);
|
|
117
118
|
const [validationErrors, setValidationErrors] = useState<Array<{row: number; field: string; message: string}>>([]);
|
|
119
|
+
const [importProgress, setImportProgress] = useState<{ current: number; total: number; stage: 'parsing' | 'importing' } | null>(null);
|
|
118
120
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
119
121
|
const isMountedRef = useRef(true);
|
|
120
122
|
|
|
@@ -135,6 +137,7 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
|
|
|
135
137
|
setError(null);
|
|
136
138
|
setValidationErrors([]);
|
|
137
139
|
setIsProcessing(false);
|
|
140
|
+
setImportProgress(null);
|
|
138
141
|
// Reset file input
|
|
139
142
|
if (fileInputRef.current) {
|
|
140
143
|
fileInputRef.current.value = '';
|
|
@@ -211,24 +214,126 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
|
|
|
211
214
|
|
|
212
215
|
setIsProcessing(true);
|
|
213
216
|
setError(null);
|
|
217
|
+
setImportProgress({ current: 0, total: 0, stage: 'parsing' });
|
|
214
218
|
|
|
215
219
|
try {
|
|
220
|
+
// Step 1: Parse CSV with progress indication
|
|
216
221
|
const text = await file.text();
|
|
217
|
-
const
|
|
222
|
+
const lines = text.split('\n').filter(line => line.trim());
|
|
223
|
+
const totalLines = lines.length;
|
|
224
|
+
|
|
225
|
+
if (totalLines < 2) {
|
|
226
|
+
throw new Error('CSV must have at least a header row and one data row');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// For large files, process in chunks to show progress
|
|
230
|
+
const CHUNK_SIZE = 1000; // Process 1000 rows at a time
|
|
231
|
+
const data: Array<Record<string, unknown>> = [];
|
|
232
|
+
|
|
233
|
+
if (totalLines > CHUNK_SIZE) {
|
|
234
|
+
// Large file - process in chunks with progress
|
|
235
|
+
const parseCSVLine = (line: string): string[] => {
|
|
236
|
+
const result: string[] = [];
|
|
237
|
+
let current = '';
|
|
238
|
+
let inQuotes = false;
|
|
239
|
+
|
|
240
|
+
for (let i = 0; i < line.length; i++) {
|
|
241
|
+
const char = line[i];
|
|
242
|
+
|
|
243
|
+
if (char === '"') {
|
|
244
|
+
inQuotes = !inQuotes;
|
|
245
|
+
} else if (char === ',' && !inQuotes) {
|
|
246
|
+
result.push(current.trim());
|
|
247
|
+
current = '';
|
|
248
|
+
} else {
|
|
249
|
+
current += char;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
result.push(current.trim());
|
|
253
|
+
return result;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const headers = parseCSVLine(lines[0]).map(h => h.replace(/"/g, '').trim());
|
|
257
|
+
|
|
258
|
+
// Process data rows in chunks
|
|
259
|
+
for (let i = 1; i < totalLines; i += CHUNK_SIZE) {
|
|
260
|
+
const chunkEnd = Math.min(i + CHUNK_SIZE, totalLines);
|
|
261
|
+
const chunk = lines.slice(i, chunkEnd);
|
|
262
|
+
|
|
263
|
+
chunk.forEach((line, index) => {
|
|
264
|
+
const values = parseCSVLine(line).map(v => v.replace(/"/g, '').trim());
|
|
265
|
+
const row: Record<string, unknown> = {};
|
|
266
|
+
headers.forEach((header, colIndex) => {
|
|
267
|
+
row[header] = values[colIndex] || '';
|
|
268
|
+
});
|
|
269
|
+
data.push(row);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Update progress
|
|
273
|
+
const processed = Math.min(chunkEnd - 1, totalLines - 1);
|
|
274
|
+
if (isMountedRef.current) {
|
|
275
|
+
setImportProgress({
|
|
276
|
+
current: processed,
|
|
277
|
+
total: totalLines - 1,
|
|
278
|
+
stage: 'parsing'
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Yield to browser to update UI
|
|
283
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
284
|
+
}
|
|
285
|
+
} else {
|
|
286
|
+
// Small file - process normally
|
|
287
|
+
const parsedData = processCSV(text);
|
|
288
|
+
data.push(...parsedData);
|
|
289
|
+
if (isMountedRef.current) {
|
|
290
|
+
setImportProgress({
|
|
291
|
+
current: totalLines - 1,
|
|
292
|
+
total: totalLines - 1,
|
|
293
|
+
stage: 'parsing'
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Step 2: Import data with progress indication
|
|
299
|
+
if (isMountedRef.current) {
|
|
300
|
+
setImportProgress({
|
|
301
|
+
current: 0,
|
|
302
|
+
total: data.length,
|
|
303
|
+
stage: 'importing'
|
|
304
|
+
});
|
|
305
|
+
}
|
|
218
306
|
|
|
219
307
|
// Await the onImport callback in case it returns a promise
|
|
220
308
|
const result = onImport(data);
|
|
221
309
|
if (result && typeof result.then === 'function') {
|
|
310
|
+
// For async imports, we can't track exact progress, but we show it's processing
|
|
311
|
+
// The progress will remain at 0 until the import completes
|
|
222
312
|
await result;
|
|
223
313
|
}
|
|
314
|
+
// Note: For synchronous imports, the progress stays at 0 until we mark it complete
|
|
315
|
+
|
|
316
|
+
// Mark as complete
|
|
317
|
+
if (isMountedRef.current) {
|
|
318
|
+
setImportProgress({
|
|
319
|
+
current: data.length,
|
|
320
|
+
total: data.length,
|
|
321
|
+
stage: 'importing'
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Small delay to show completion
|
|
326
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
224
327
|
|
|
225
328
|
onClose();
|
|
226
329
|
setFile(null);
|
|
227
330
|
} catch (err) {
|
|
228
331
|
setError(err instanceof Error ? err.message : 'Failed to process file');
|
|
332
|
+
setImportProgress(null);
|
|
229
333
|
} finally {
|
|
230
334
|
if (isMountedRef.current) {
|
|
231
335
|
setIsProcessing(false);
|
|
336
|
+
setImportProgress(null);
|
|
232
337
|
}
|
|
233
338
|
}
|
|
234
339
|
};
|
|
@@ -239,6 +344,7 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
|
|
|
239
344
|
setPreviewData(null);
|
|
240
345
|
setTotalCount(0);
|
|
241
346
|
setValidationErrors([]);
|
|
347
|
+
setImportProgress(null);
|
|
242
348
|
onClose();
|
|
243
349
|
};
|
|
244
350
|
|
|
@@ -338,7 +444,33 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
|
|
|
338
444
|
)}
|
|
339
445
|
|
|
340
446
|
|
|
341
|
-
{
|
|
447
|
+
{importProgress && isProcessing && (
|
|
448
|
+
<div className="space-y-2 p-4 bg-sec-50 rounded-lg border border-sec-200">
|
|
449
|
+
<div className="flex items-center justify-between">
|
|
450
|
+
<span className="text-sm font-medium text-sec-900">
|
|
451
|
+
{importProgress.stage === 'parsing' ? 'Parsing CSV file...' : 'Importing data...'}
|
|
452
|
+
</span>
|
|
453
|
+
<span className="text-sm text-sec-600">
|
|
454
|
+
{importProgress.current.toLocaleString()} / {importProgress.total.toLocaleString()} rows
|
|
455
|
+
</span>
|
|
456
|
+
</div>
|
|
457
|
+
<Progress
|
|
458
|
+
value={importProgress.total > 0 ? (importProgress.current / importProgress.total) * 100 : 0}
|
|
459
|
+
className="h-2 bg-sec-200"
|
|
460
|
+
/>
|
|
461
|
+
<p className="text-xs text-sec-500">
|
|
462
|
+
{importProgress.total > 0 && importProgress.current < importProgress.total
|
|
463
|
+
? `${Math.round((importProgress.current / importProgress.total) * 100)}% complete`
|
|
464
|
+
: importProgress.stage === 'importing' && importProgress.current === 0
|
|
465
|
+
? 'Processing your data...'
|
|
466
|
+
: importProgress.current === importProgress.total
|
|
467
|
+
? 'Complete!'
|
|
468
|
+
: 'Processing...'}
|
|
469
|
+
</p>
|
|
470
|
+
</div>
|
|
471
|
+
)}
|
|
472
|
+
|
|
473
|
+
{file && previewData && previewData.length > 0 && !isProcessing ? (
|
|
342
474
|
<div className="space-y-3">
|
|
343
475
|
<h4 className="text-sec-900">{previewHeaderText}</h4>
|
|
344
476
|
<div className="border rounded-lg overflow-hidden">
|