@jmruthers/pace-core 0.5.87 → 0.5.88
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-Df3IozMG.d.ts → AuthService-DcTI5Ov4.d.ts} +9 -0
- package/dist/{DataTable-FA6EUX5M.js → DataTable-PWBMKMOG.js} +7 -7
- package/dist/{PublicLoadingSpinner-DecuJBX0.d.ts → PublicLoadingSpinner-BQXD1fbO.d.ts} +160 -130
- package/dist/{UnifiedAuthProvider-K2IZAY5F.js → UnifiedAuthProvider-5D3HEQND.js} +4 -4
- package/dist/{UnifiedAuthProvider-B391Aqum.d.ts → UnifiedAuthProvider-BVKmQd9u.d.ts} +4 -0
- package/dist/auth-DReDSLq9.d.ts +16 -0
- package/dist/{chunk-CBSD3BZ3.js → chunk-3RZBKQ5Y.js} +2 -6
- package/dist/{chunk-CBSD3BZ3.js.map → chunk-3RZBKQ5Y.js.map} +1 -1
- package/dist/{chunk-NTW3KGS4.js → chunk-6UHXQH7P.js} +5 -5
- package/dist/{chunk-YVUZWLQG.js → chunk-AQGF5OG7.js} +3 -3
- package/dist/{chunk-CVMVPYAL.js → chunk-BDZUMRBD.js} +3 -5
- package/dist/chunk-BDZUMRBD.js.map +1 -0
- package/dist/{chunk-KAY3K5TP.js → chunk-BNXBJOGL.js} +4 -4
- package/dist/{chunk-I7O3RSMN.js → chunk-CJIZS3UE.js} +1298 -769
- package/dist/chunk-CJIZS3UE.js.map +1 -0
- package/dist/{chunk-S3JKDMD5.js → chunk-CXKMRKRF.js} +4 -4
- package/dist/{chunk-5BN3YGNK.js → chunk-DP5X5ORK.js} +217 -27
- package/dist/chunk-DP5X5ORK.js.map +1 -0
- package/dist/{chunk-ZFLOV3OM.js → chunk-H3P2RGKZ.js} +352 -16
- package/dist/chunk-H3P2RGKZ.js.map +1 -0
- package/dist/{chunk-RIXPZJUB.js → chunk-KTPG5VCH.js} +2 -2
- package/dist/{chunk-WUXCWRL6.js → chunk-XJ2HZOBU.js} +6 -1
- package/dist/chunk-XJ2HZOBU.js.map +1 -0
- package/dist/{chunk-2FQEQUJT.js → chunk-XXVM53P4.js} +4 -4
- package/dist/{chunk-I2VVV5PQ.js → chunk-YY4YYM3E.js} +2 -2
- package/dist/components.d.ts +6 -55
- package/dist/components.js +24 -205
- package/dist/components.js.map +1 -1
- package/dist/{file-reference-9xUOnwyt.d.ts → file-reference-C9isKNPn.d.ts} +67 -2
- package/dist/hooks.js +9 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +152 -26
- package/dist/index.js +64 -194
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +5 -3
- package/dist/providers.js +3 -3
- package/dist/rbac/index.js +8 -8
- package/dist/types.d.ts +2 -1
- package/dist/types.js +3 -3
- package/dist/utils.js +2 -2
- package/docs/DOCUMENTATION_AUDIT.md +6 -6
- package/docs/DOCUMENTATION_STANDARD.md +137 -0
- package/docs/README.md +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 +83 -40
- package/docs/api/enums/FileCategory.md +56 -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/EventLogoProps.md +11 -11
- package/docs/api/interfaces/FileDisplayProps.md +10 -10
- 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 +8 -8
- package/docs/api/interfaces/FileUploadProps.md +137 -42
- package/docs/api/interfaces/FooterProps.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/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/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.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 +83 -50
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseEventLogoOptions.md +74 -0
- package/docs/api/interfaces/UseEventLogoReturn.md +81 -0
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +6 -6
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +6 -6
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.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 +11 -11
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +290 -95
- package/docs/api-reference/components.md +1 -18
- package/docs/api-reference/hooks.md +1 -4
- package/docs/best-practices/testing.md +2 -0
- package/docs/documentation-index.md +1 -1
- package/docs/getting-started/faq.md +1 -1
- package/docs/implementation-guides/file-reference-system.md +592 -58
- package/docs/implementation-guides/file-upload-storage.md +137 -73
- package/docs/rbac/super-admin-guide.md +18 -70
- package/docs/testing/README.md +2 -0
- package/package.json +1 -1
- package/src/__tests__/TEST_STANDARD.md +674 -0
- package/src/__tests__/helpers/test-utils.tsx +3 -2
- package/src/components/DataTable/__tests__/{DataTable.comprehensive.test.tsx.skip → DataTable.comprehensive.test.tsx} +17 -18
- package/src/components/DataTable/__tests__/{DataTable.test.tsx.skip → DataTable.test.tsx} +14 -22
- package/src/components/DataTable/__tests__/{ssr.strict-mode.test.tsx.skip → ssr.strict-mode.test.tsx} +42 -47
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +1 -1
- package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +13 -4
- package/src/components/DataTable/utils/__tests__/COVERAGE_NOTE.md +1 -1
- package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +10 -6
- package/src/components/FileDisplay/FileDisplay.test.tsx +257 -0
- package/src/components/{FileDisplay.tsx → FileDisplay/FileDisplay.tsx} +111 -10
- package/src/components/FileDisplay/index.tsx +4 -0
- package/src/components/FileUpload/FileUpload.test.tsx +171 -621
- package/src/components/FileUpload/FileUpload.tsx +512 -168
- package/src/components/FileUpload/index.tsx +4 -0
- package/src/components/Progress/Progress.test.tsx +38 -0
- package/src/components/PublicLayout/EventLogo.tsx +6 -4
- package/src/components/Select/Select.test.tsx +1 -1
- package/src/components/SessionRestorationLoader.tsx +48 -0
- package/src/components/Toast/Toast.tsx +13 -8
- package/src/components/index.ts +16 -16
- package/src/hooks/__tests__/ServiceHooks.test.tsx +615 -0
- package/src/hooks/public/usePublicEventLogo.ts +16 -20
- package/src/hooks/useEventLogo.ts +316 -0
- package/src/hooks/useEvents.ts +0 -5
- package/src/hooks/useFileReference.test.ts +659 -0
- package/src/hooks/useFileReference.ts +207 -3
- package/src/hooks/useSessionRestoration.ts +64 -0
- package/src/index.ts +17 -5
- package/src/providers/{UnifiedAuthProvider.test.simple.tsx → UnifiedAuthProvider.smoke.test.tsx} +81 -60
- package/src/providers/services/AuthServiceProvider.tsx +27 -3
- package/src/providers/services/UnifiedAuthProvider.tsx +34 -5
- package/src/rbac/{engine.test.simple.ts → RBACEngine.smoke.test.ts} +17 -12
- package/src/services/AuthService.ts +142 -20
- package/src/services/EventService.ts +0 -4
- package/src/types/auth.ts +15 -0
- package/src/types/file-reference.ts +73 -1
- package/src/types/index.ts +1 -0
- package/src/utils/__tests__/organisationContext.unit.test.ts +2 -4
- package/src/utils/appNameResolver.simple.test.ts +99 -29
- package/src/utils/file-reference.test.ts +535 -0
- package/src/utils/file-reference.ts +200 -30
- package/src/utils/organisationContext.test.ts +5 -19
- package/src/utils/organisationContext.ts +3 -5
- package/src/utils/storage/README.md +269 -262
- package/src/utils/storage/config.ts +9 -0
- package/src/utils/storage/helpers.test.ts +631 -0
- package/src/utils/storage/helpers.ts +112 -14
- package/src/utils/storage/index.ts +3 -0
- package/src/validation/__tests__/sanitization.unit.test.ts +1 -1
- package/src/validation/__tests__/schemaUtils.unit.test.ts +1 -1
- package/src/validation/__tests__/user.unit.test.ts +1 -1
- package/dist/chunk-5BN3YGNK.js.map +0 -1
- package/dist/chunk-CVMVPYAL.js.map +0 -1
- package/dist/chunk-I7O3RSMN.js.map +0 -1
- package/dist/chunk-WUXCWRL6.js.map +0 -1
- package/dist/chunk-ZFLOV3OM.js.map +0 -1
- package/docs/CONTENT_AUDIT_REPORT.md +0 -253
- package/docs/STYLE_GUIDE.md +0 -37
- package/examples/RBAC/__tests__/PermissionExample.test.tsx +0 -150
- package/examples/public-pages/__tests__/PublicPageUsageExample.test.tsx +0 -159
- package/src/__tests__/TEST_GUIDE_CURSOR.md +0 -1605
- package/src/__tests__/TEST_GUIDE_HUMAN.md +0 -103
- package/src/components/FileUpload/FileUpload.example.tsx +0 -218
- package/src/components/FileUpload/index.ts +0 -6
- package/src/components/FileUpload.tsx +0 -176
- package/src/components/Progress/index.ts +0 -3
- package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +0 -666
- package/src/components/SuperAdminGuard.tsx +0 -116
- package/src/components/__tests__/FileDisplay.test.tsx +0 -575
- package/src/components/__tests__/FileUpload.test.tsx +0 -446
- package/src/components/__tests__/SuperAdminGuard.test.tsx +0 -627
- package/src/components/examples/PermissionExample.tsx +0 -173
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +0 -583
- package/src/hooks/__tests__/usePublicEventLogo.unit.test.ts +0 -640
- package/src/types/__tests__/file-reference.test.ts +0 -447
- package/src/utils/__tests__/file-reference.test.ts +0 -383
- /package/dist/{DataTable-FA6EUX5M.js.map → DataTable-PWBMKMOG.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-K2IZAY5F.js.map → UnifiedAuthProvider-5D3HEQND.js.map} +0 -0
- /package/dist/{chunk-NTW3KGS4.js.map → chunk-6UHXQH7P.js.map} +0 -0
- /package/dist/{chunk-YVUZWLQG.js.map → chunk-AQGF5OG7.js.map} +0 -0
- /package/dist/{chunk-KAY3K5TP.js.map → chunk-BNXBJOGL.js.map} +0 -0
- /package/dist/{chunk-S3JKDMD5.js.map → chunk-CXKMRKRF.js.map} +0 -0
- /package/dist/{chunk-RIXPZJUB.js.map → chunk-KTPG5VCH.js.map} +0 -0
- /package/dist/{chunk-2FQEQUJT.js.map → chunk-XXVM53P4.js.map} +0 -0
- /package/dist/{chunk-I2VVV5PQ.js.map → chunk-YY4YYM3E.js.map} +0 -0
- /package/src/providers/{OrganisationProvider.test.simple.tsx → OrganisationProvider.context.test.tsx} +0 -0
|
@@ -38,31 +38,27 @@ graph TD
|
|
|
38
38
|
|
|
39
39
|
```tsx
|
|
40
40
|
import { FileUpload, FileCategory } from '@jmruthers/pace-core';
|
|
41
|
-
import { useFileReference } from '@jmruthers/pace-core';
|
|
42
41
|
|
|
43
42
|
function MyFileUpload() {
|
|
44
|
-
const { uploadFile, getFileUrl, deleteFile, isLoading, error } = useFileReference(supabase);
|
|
45
|
-
|
|
46
|
-
const handleUpload = async (file: File) => {
|
|
47
|
-
try {
|
|
48
|
-
const fileRef = await uploadFile({
|
|
49
|
-
file,
|
|
50
|
-
category: FileCategory.DOCUMENT,
|
|
51
|
-
description: 'User uploaded document'
|
|
52
|
-
});
|
|
53
|
-
console.log('File uploaded:', fileRef);
|
|
54
|
-
} catch (err) {
|
|
55
|
-
console.error('Upload failed:', err);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
43
|
return (
|
|
60
44
|
<FileUpload
|
|
61
45
|
supabase={supabase}
|
|
62
|
-
|
|
63
|
-
|
|
46
|
+
table_name="person"
|
|
47
|
+
record_id="person-123"
|
|
48
|
+
organisation_id="org-123"
|
|
49
|
+
// app_id auto-resolved from app name
|
|
50
|
+
category={FileCategory.GENERAL_DOCUMENTS}
|
|
64
51
|
accept=".pdf,.doc,.docx"
|
|
65
52
|
maxSize={5 * 1024 * 1024} // 5MB
|
|
53
|
+
showProgress={true}
|
|
54
|
+
showPreview={false}
|
|
55
|
+
onUploadSuccess={(result) => {
|
|
56
|
+
console.log('File uploaded:', result.file_reference);
|
|
57
|
+
console.log('Available at:', result.file_url);
|
|
58
|
+
}}
|
|
59
|
+
onUploadError={(error, file) => {
|
|
60
|
+
console.error(`Upload failed for ${file?.name}:`, error);
|
|
61
|
+
}}
|
|
66
62
|
>
|
|
67
63
|
<div className="border-2 border-dashed border-main-300 rounded-lg p-8 text-center">
|
|
68
64
|
<p>Drag and drop files here or click to browse</p>
|
|
@@ -79,7 +75,7 @@ import { FileDisplay, FileCategory } from '@jmruthers/pace-core';
|
|
|
79
75
|
import { useFileReferenceForRecord } from '@jmruthers/pace-core';
|
|
80
76
|
|
|
81
77
|
function UserProfile({ userId }: { userId: string }) {
|
|
82
|
-
const { fileUrl,
|
|
78
|
+
const { fileUrl, fileReference, isLoading, error } = useFileReferenceForRecord(
|
|
83
79
|
supabase,
|
|
84
80
|
'pace_person',
|
|
85
81
|
userId,
|
|
@@ -91,15 +87,25 @@ function UserProfile({ userId }: { userId: string }) {
|
|
|
91
87
|
<h2>Profile Documents</h2>
|
|
92
88
|
<FileDisplay
|
|
93
89
|
supabase={supabase}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
category={FileCategory.
|
|
98
|
-
onUpload={uploadFile}
|
|
99
|
-
onDelete={deleteFile}
|
|
90
|
+
table_name="pace_person"
|
|
91
|
+
record_id={userId}
|
|
92
|
+
organisation_id="org-123"
|
|
93
|
+
category={FileCategory.GENERAL_DOCUMENTS}
|
|
100
94
|
showUpload={true}
|
|
101
95
|
showDelete={true}
|
|
102
|
-
|
|
96
|
+
className="space-y-4"
|
|
97
|
+
>
|
|
98
|
+
{/* Optional: Add custom upload component */}
|
|
99
|
+
<FileUpload
|
|
100
|
+
supabase={supabase}
|
|
101
|
+
table_name="pace_person"
|
|
102
|
+
record_id={userId}
|
|
103
|
+
organisation_id="org-123"
|
|
104
|
+
category={FileCategory.GENERAL_DOCUMENTS}
|
|
105
|
+
accept=".pdf,.doc,.docx"
|
|
106
|
+
maxSize={10 * 1024 * 1024}
|
|
107
|
+
/>
|
|
108
|
+
</FileDisplay>
|
|
103
109
|
</div>
|
|
104
110
|
);
|
|
105
111
|
}
|
|
@@ -116,15 +122,22 @@ A comprehensive file upload component with drag-and-drop support, validation, an
|
|
|
116
122
|
```typescript
|
|
117
123
|
interface FileUploadProps {
|
|
118
124
|
supabase: SupabaseClient;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
table_name: string;
|
|
126
|
+
record_id: string;
|
|
127
|
+
organisation_id: string;
|
|
128
|
+
app_id?: string; // Optional - will be resolved from app name if not provided
|
|
129
|
+
category: FileCategory;
|
|
123
130
|
accept?: string;
|
|
124
131
|
maxSize?: number;
|
|
125
132
|
multiple?: boolean;
|
|
126
133
|
disabled?: boolean;
|
|
134
|
+
isPublic?: boolean; // Whether files should be uploaded to public-files bucket
|
|
127
135
|
className?: string;
|
|
136
|
+
showPreview?: boolean; // Show image preview for accepted files
|
|
137
|
+
showProgress?: boolean; // Show upload progress bar
|
|
138
|
+
onUploadSuccess?: (result: FileUploadResult) => void;
|
|
139
|
+
onUploadError?: (error: string, file?: File) => void;
|
|
140
|
+
onProgress?: (progress: UploadProgress) => void;
|
|
128
141
|
children?: React.ReactNode;
|
|
129
142
|
}
|
|
130
143
|
```
|
|
@@ -135,11 +148,13 @@ interface FileUploadProps {
|
|
|
135
148
|
```tsx
|
|
136
149
|
<FileUpload
|
|
137
150
|
supabase={supabase}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
151
|
+
table_name="person"
|
|
152
|
+
record_id="person-123"
|
|
153
|
+
organisation_id={organisationId}
|
|
154
|
+
category={FileCategory.PROFILE_PHOTOS}
|
|
141
155
|
accept="image/*"
|
|
142
156
|
maxSize={2 * 1024 * 1024} // 2MB
|
|
157
|
+
onUploadSuccess={(result) => console.log('Uploaded:', result.file_reference)}
|
|
143
158
|
>
|
|
144
159
|
<Button>Upload Image</Button>
|
|
145
160
|
</FileUpload>
|
|
@@ -149,11 +164,14 @@ interface FileUploadProps {
|
|
|
149
164
|
```tsx
|
|
150
165
|
<FileUpload
|
|
151
166
|
supabase={supabase}
|
|
152
|
-
|
|
153
|
-
|
|
167
|
+
table_name="person"
|
|
168
|
+
record_id="person-123"
|
|
169
|
+
organisation_id={organisationId}
|
|
170
|
+
category={FileCategory.GENERAL_DOCUMENTS}
|
|
154
171
|
multiple={true}
|
|
155
172
|
accept=".pdf,.doc,.docx"
|
|
156
|
-
|
|
173
|
+
showProgress={true}
|
|
174
|
+
onUploadSuccess={(result) => addToFileList(result.file_reference)}
|
|
157
175
|
>
|
|
158
176
|
<div className="upload-area">
|
|
159
177
|
<UploadIcon className="w-8 h-8" />
|
|
@@ -188,17 +206,14 @@ A component for displaying and managing files associated with database records.
|
|
|
188
206
|
```typescript
|
|
189
207
|
interface FileDisplayProps {
|
|
190
208
|
supabase: SupabaseClient;
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
recordId: string;
|
|
209
|
+
table_name: string;
|
|
210
|
+
record_id: string;
|
|
211
|
+
organisation_id: string;
|
|
195
212
|
category?: FileCategory;
|
|
196
|
-
onUpload?: (file: File) => Promise<FileReference>;
|
|
197
|
-
onDelete?: (fileRef: FileReference) => Promise<void>;
|
|
198
213
|
showUpload?: boolean;
|
|
199
214
|
showDelete?: boolean;
|
|
200
|
-
showPreview?: boolean;
|
|
201
215
|
className?: string;
|
|
216
|
+
children?: React.ReactNode;
|
|
202
217
|
}
|
|
203
218
|
```
|
|
204
219
|
|
|
@@ -208,11 +223,10 @@ interface FileDisplayProps {
|
|
|
208
223
|
```tsx
|
|
209
224
|
<FileDisplay
|
|
210
225
|
supabase={supabase}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
category={FileCategory.DOCUMENT}
|
|
226
|
+
table_name="pace_person"
|
|
227
|
+
record_id={personId}
|
|
228
|
+
organisation_id={organisationId}
|
|
229
|
+
category={FileCategory.GENERAL_DOCUMENTS}
|
|
216
230
|
showUpload={false}
|
|
217
231
|
showDelete={false}
|
|
218
232
|
/>
|
|
@@ -222,17 +236,25 @@ interface FileDisplayProps {
|
|
|
222
236
|
```tsx
|
|
223
237
|
<FileDisplay
|
|
224
238
|
supabase={supabase}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
category={FileCategory.IMAGE}
|
|
230
|
-
onUpload={handleUpload}
|
|
231
|
-
onDelete={handleDelete}
|
|
239
|
+
table_name="pace_person"
|
|
240
|
+
record_id={personId}
|
|
241
|
+
organisation_id={organisationId}
|
|
242
|
+
category={FileCategory.IMAGES}
|
|
232
243
|
showUpload={true}
|
|
233
244
|
showDelete={true}
|
|
234
|
-
|
|
235
|
-
|
|
245
|
+
className="space-y-4"
|
|
246
|
+
>
|
|
247
|
+
{/* Optional: Custom upload component */}
|
|
248
|
+
<FileUpload
|
|
249
|
+
supabase={supabase}
|
|
250
|
+
table_name="pace_person"
|
|
251
|
+
record_id={personId}
|
|
252
|
+
organisation_id={organisationId}
|
|
253
|
+
category={FileCategory.IMAGES}
|
|
254
|
+
accept="image/*"
|
|
255
|
+
showPreview={true}
|
|
256
|
+
/>
|
|
257
|
+
</FileDisplay>
|
|
236
258
|
```
|
|
237
259
|
|
|
238
260
|
## Hooks
|
|
@@ -359,14 +381,24 @@ PACE Core supports predefined file categories for better organization:
|
|
|
359
381
|
|
|
360
382
|
```typescript
|
|
361
383
|
enum FileCategory {
|
|
362
|
-
|
|
363
|
-
|
|
384
|
+
PROFILE_PHOTOS = 'profile_photos',
|
|
385
|
+
ID_DOCUMENTS = 'id_documents',
|
|
386
|
+
QUALIFICATIONS = 'qualifications',
|
|
387
|
+
MEDICAL_DOCUMENTS = 'medical_documents',
|
|
388
|
+
DISH_IMAGES = 'dish_images',
|
|
389
|
+
EVENT_LOGOS = 'event_logos',
|
|
390
|
+
GENERAL_DOCUMENTS = 'general_documents',
|
|
391
|
+
IMAGES = 'images',
|
|
364
392
|
AUDIO = 'audio',
|
|
365
393
|
VIDEO = 'video',
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
394
|
+
ARCHIVES = 'archives',
|
|
395
|
+
// CAKE-specific categories
|
|
396
|
+
CAKE_DISH = 'cake_dish',
|
|
397
|
+
// TRAC-specific categories
|
|
398
|
+
TRAC_ACCOMMODATION = 'trac_accommodation',
|
|
399
|
+
TRAC_ACTIVITY = 'trac_activity',
|
|
400
|
+
TRAC_JOURNAL = 'trac_journal',
|
|
401
|
+
TRAC_TRANSPORT = 'trac_transport'
|
|
370
402
|
}
|
|
371
403
|
```
|
|
372
404
|
|
|
@@ -377,17 +409,23 @@ import { FileCategory } from '@jmruthers/pace-core';
|
|
|
377
409
|
|
|
378
410
|
// Upload a document
|
|
379
411
|
await uploadFile({
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
412
|
+
table_name: 'person',
|
|
413
|
+
record_id: 'person-123',
|
|
414
|
+
organisation_id: 'org-123',
|
|
415
|
+
app_id: 'app-123',
|
|
416
|
+
category: FileCategory.GENERAL_DOCUMENTS,
|
|
417
|
+
is_public: false
|
|
418
|
+
}, pdfFile);
|
|
419
|
+
|
|
420
|
+
// Upload a profile photo
|
|
386
421
|
await uploadFile({
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
422
|
+
table_name: 'person',
|
|
423
|
+
record_id: 'person-123',
|
|
424
|
+
organisation_id: 'org-123',
|
|
425
|
+
app_id: 'app-123',
|
|
426
|
+
category: FileCategory.PROFILE_PHOTOS,
|
|
427
|
+
is_public: false
|
|
428
|
+
}, imageFile);
|
|
391
429
|
```
|
|
392
430
|
|
|
393
431
|
## Database Schema
|
|
@@ -536,6 +574,32 @@ function FileUpload() {
|
|
|
536
574
|
}
|
|
537
575
|
```
|
|
538
576
|
|
|
577
|
+
## Recent Improvements
|
|
578
|
+
|
|
579
|
+
### Performance & Memory Management
|
|
580
|
+
- **Fixed infinite logging loops**: Removed debug logging that was causing performance issues in event services
|
|
581
|
+
- **Memory leak prevention**: Added automatic cleanup in hooks and components to prevent memory accumulation
|
|
582
|
+
- **Cache management**: Implemented cache size limits and TTL for event logos with automatic cleanup
|
|
583
|
+
- **Optimized re-renders**: Fixed infinite re-render loops in FileDisplay component using refs for state tracking
|
|
584
|
+
|
|
585
|
+
### Enhanced User Experience
|
|
586
|
+
- **App ID auto-resolution**: FileUpload component now automatically resolves app_id from app name configuration
|
|
587
|
+
- **Better error handling**: More descriptive error messages and graceful failure handling with user-friendly toasts
|
|
588
|
+
- **Progress tracking**: Enhanced upload progress with visual feedback and file previews
|
|
589
|
+
- **Event context integration**: Event logos now automatically sync with selected events from the event selector
|
|
590
|
+
|
|
591
|
+
### Security & Reliability
|
|
592
|
+
- **RLS policy fixes**: Resolved permission issues for file uploads with proper organisation context setting
|
|
593
|
+
- **Organisation context**: Proper database session context setting via `app.current_organisation_id`
|
|
594
|
+
- **Super admin support**: Enhanced permissions for administrative users with dedicated RLS policies
|
|
595
|
+
- **Bucket validation**: Improved bucket selection and validation logic for public vs private files
|
|
596
|
+
|
|
597
|
+
### Developer Experience
|
|
598
|
+
- **Comprehensive documentation**: Updated all documentation to reflect current API and best practices
|
|
599
|
+
- **Better TypeScript support**: Improved type definitions and interfaces
|
|
600
|
+
- **Enhanced debugging**: Better error messages and debugging tools for troubleshooting
|
|
601
|
+
- **Legacy system removal**: Completely removed legacy file upload system to eliminate tech debt
|
|
602
|
+
|
|
539
603
|
## Migration from Old File Columns
|
|
540
604
|
|
|
541
605
|
If you're migrating from direct file columns to the file reference system:
|
|
@@ -396,33 +396,9 @@ function MyComponent() {
|
|
|
396
396
|
}
|
|
397
397
|
```
|
|
398
398
|
|
|
399
|
-
###
|
|
399
|
+
### Super Admin UI Considerations
|
|
400
400
|
|
|
401
|
-
|
|
402
|
-
import { SuperAdminGuard, SuperAdminBadge } from '@jmruthers/pace-core/components';
|
|
403
|
-
|
|
404
|
-
function AdminDashboard() {
|
|
405
|
-
return (
|
|
406
|
-
<div>
|
|
407
|
-
<header>
|
|
408
|
-
<h1>Admin Dashboard</h1>
|
|
409
|
-
<SuperAdminBadge />
|
|
410
|
-
</header>
|
|
411
|
-
|
|
412
|
-
<SuperAdminGuard
|
|
413
|
-
fallback={<div>You need super admin access to view this content</div>}
|
|
414
|
-
>
|
|
415
|
-
<div className="super-admin-content">
|
|
416
|
-
<h2>Super Admin Tools</h2>
|
|
417
|
-
<button>Manage All Organisations</button>
|
|
418
|
-
<button>View System Logs</button>
|
|
419
|
-
<button>Access All User Data</button>
|
|
420
|
-
</div>
|
|
421
|
-
</SuperAdminGuard>
|
|
422
|
-
</div>
|
|
423
|
-
);
|
|
424
|
-
}
|
|
425
|
-
```
|
|
401
|
+
Prefer enforcing super-admin-only behavior using RBAC hooks (e.g., `useRBAC`) and server-side policies. Avoid bespoke guard components.
|
|
426
402
|
|
|
427
403
|
### Data Table with Super Admin Access
|
|
428
404
|
|
|
@@ -493,11 +469,7 @@ import {
|
|
|
493
469
|
PermissionEnforcer,
|
|
494
470
|
PagePermissionGuard
|
|
495
471
|
} from '@jmruthers/pace-core/rbac';
|
|
496
|
-
|
|
497
|
-
SuperAdminGuard,
|
|
498
|
-
SuperAdminBadge,
|
|
499
|
-
SuperAdminDebugPanel
|
|
500
|
-
} from '@jmruthers/pace-core/components';
|
|
472
|
+
// (Super admin UI helpers previously documented have been removed.)
|
|
501
473
|
|
|
502
474
|
function AdminLayout({ children }) {
|
|
503
475
|
const { isSuperAdmin } = useRBAC();
|
|
@@ -515,11 +487,14 @@ function AdminLayout({ children }) {
|
|
|
515
487
|
<li><Link to="/admin/users">Users</Link></li>
|
|
516
488
|
<li><Link to="/admin/events">Events</Link></li>
|
|
517
489
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
490
|
+
{/* Gate links using app logic based on isSuperAdmin instead of a guard component */}
|
|
491
|
+
{isSuperAdmin && (
|
|
492
|
+
<>
|
|
493
|
+
<li><Link to="/admin/super-admin">Super Admin</Link></li>
|
|
494
|
+
<li><Link to="/admin/system-logs">System Logs</Link></li>
|
|
495
|
+
<li><Link to="/admin/all-organisations">All Organisations</Link></li>
|
|
496
|
+
</>
|
|
497
|
+
)}
|
|
523
498
|
</ul>
|
|
524
499
|
</nav>
|
|
525
500
|
|
|
@@ -528,8 +503,9 @@ function AdminLayout({ children }) {
|
|
|
528
503
|
</main>
|
|
529
504
|
|
|
530
505
|
<footer className="admin-footer">
|
|
506
|
+
{/* Optional: inline debug in development */}
|
|
531
507
|
{process.env.NODE_ENV === 'development' && (
|
|
532
|
-
<
|
|
508
|
+
<div>Debug: {String(isSuperAdmin)}</div>
|
|
533
509
|
)}
|
|
534
510
|
</footer>
|
|
535
511
|
</div>
|
|
@@ -542,46 +518,18 @@ function AdminLayout({ children }) {
|
|
|
542
518
|
```tsx
|
|
543
519
|
import { render, screen } from '@testing-library/react';
|
|
544
520
|
import { useRBAC } from '@jmruthers/pace-core';
|
|
545
|
-
|
|
521
|
+
// SuperAdminGuard removed; use conditional rendering in tests
|
|
546
522
|
|
|
547
523
|
// Mock the hook
|
|
548
524
|
jest.mock('@jmruthers/pace-core/rbac', () => ({
|
|
549
525
|
useRBAC: jest.fn()
|
|
550
526
|
}));
|
|
551
527
|
|
|
552
|
-
describe('
|
|
553
|
-
test('renders
|
|
554
|
-
(useRBAC as jest.Mock).mockReturnValue({
|
|
555
|
-
|
|
556
|
-
hasGlobalPermission: jest.fn().mockReturnValue(true),
|
|
557
|
-
isLoading: false
|
|
558
|
-
});
|
|
559
|
-
|
|
560
|
-
render(
|
|
561
|
-
<SuperAdminGuard fallback={<div>Access Denied</div>}>
|
|
562
|
-
<div>Super Admin Content</div>
|
|
563
|
-
</SuperAdminGuard>
|
|
564
|
-
);
|
|
565
|
-
|
|
528
|
+
describe('Super Admin conditional rendering', () => {
|
|
529
|
+
test('renders content for super admin users', () => {
|
|
530
|
+
(useRBAC as jest.Mock).mockReturnValue({ isSuperAdmin: true });
|
|
531
|
+
render(<div>{true && <div>Super Admin Content</div>}</div>);
|
|
566
532
|
expect(screen.getByText('Super Admin Content')).toBeInTheDocument();
|
|
567
|
-
expect(screen.queryByText('Access Denied')).not.toBeInTheDocument();
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
test('renders fallback for non-super admin users', () => {
|
|
571
|
-
(useRBAC as jest.Mock).mockReturnValue({
|
|
572
|
-
isSuperAdmin: false,
|
|
573
|
-
hasGlobalPermission: jest.fn().mockReturnValue(false),
|
|
574
|
-
isLoading: false
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
render(
|
|
578
|
-
<SuperAdminGuard fallback={<div>Access Denied</div>}>
|
|
579
|
-
<div>Super Admin Content</div>
|
|
580
|
-
</SuperAdminGuard>
|
|
581
|
-
);
|
|
582
|
-
|
|
583
|
-
expect(screen.getByText('Access Denied')).toBeInTheDocument();
|
|
584
|
-
expect(screen.queryByText('Super Admin Content')).not.toBeInTheDocument();
|
|
585
533
|
});
|
|
586
534
|
});
|
|
587
535
|
```
|
package/docs/testing/README.md
CHANGED
|
@@ -8,6 +8,8 @@ reviewedBy: content-audit
|
|
|
8
8
|
|
|
9
9
|
This guide covers testing strategies, patterns, and best practices for applications built with PACE Core.
|
|
10
10
|
|
|
11
|
+
> 📖 **For comprehensive testing standards and patterns**, see the [Testing Standard](../../src/__tests__/TEST_STANDARD.md) - the authoritative guide for writing world-class tests in pace-core.
|
|
12
|
+
|
|
11
13
|
## Overview
|
|
12
14
|
|
|
13
15
|
PACE Core provides comprehensive testing support with:
|