@jmruthers/pace-core 0.5.188 → 0.5.190
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/core-usage-manifest.json +0 -4
- package/dist/{AuthService-B-cd2MA4.d.ts → AuthService-CbP_utw2.d.ts} +7 -3
- package/dist/{DataTable-GUFUNZ3N.js → DataTable-ON3IXISJ.js} +8 -8
- package/dist/{PublicPageProvider-DrLDztHt.d.ts → PublicPageProvider-C4uxosp6.d.ts} +129 -40
- package/dist/{UnifiedAuthProvider-BG0AL5eE.d.ts → UnifiedAuthProvider-BYA9qB-o.d.ts} +4 -3
- package/dist/{UnifiedAuthProvider-643PUAIM.js → UnifiedAuthProvider-X5NXANVI.js} +4 -2
- package/dist/{api-YP7XD5L6.js → api-I6UCQ5S6.js} +4 -2
- package/dist/{chunk-DDM4CCYT.js → chunk-4QYC5L4K.js} +60 -35
- package/dist/chunk-4QYC5L4K.js.map +1 -0
- package/dist/{chunk-IM4QE42D.js → chunk-73HSNNOQ.js} +141 -326
- package/dist/chunk-73HSNNOQ.js.map +1 -0
- package/dist/{chunk-YHCN776L.js → chunk-DZWK57KZ.js} +2 -75
- package/dist/chunk-DZWK57KZ.js.map +1 -0
- package/dist/{chunk-3GOZZZYH.js → chunk-HQVPB5MZ.js} +238 -301
- package/dist/chunk-HQVPB5MZ.js.map +1 -0
- package/dist/{chunk-THRPYOFK.js → chunk-HW3OVDUF.js} +5 -5
- package/dist/chunk-HW3OVDUF.js.map +1 -0
- package/dist/{chunk-F2IMUDXZ.js → chunk-I7PSE6JW.js} +75 -2
- package/dist/chunk-I7PSE6JW.js.map +1 -0
- package/dist/{chunk-VGZZXKBR.js → chunk-J2XXC7R5.js} +280 -52
- package/dist/chunk-J2XXC7R5.js.map +1 -0
- package/dist/{chunk-UNOTYLQF.js → chunk-NIU6J6OX.js} +772 -725
- package/dist/chunk-NIU6J6OX.js.map +1 -0
- package/dist/{chunk-HESYZWZW.js → chunk-QWWZ5CAQ.js} +2 -2
- package/dist/{chunk-HEHYGYOX.js → chunk-RUYZKXOD.js} +401 -46
- package/dist/chunk-RUYZKXOD.js.map +1 -0
- package/dist/{chunk-2UUZZJFT.js → chunk-SDMHPX3X.js} +176 -160
- package/dist/{chunk-2UUZZJFT.js.map → chunk-SDMHPX3X.js.map} +1 -1
- package/dist/{chunk-IPCH26AG.js → chunk-STYK4OH2.js} +11 -11
- package/dist/chunk-STYK4OH2.js.map +1 -0
- package/dist/{chunk-EFCLXK7F.js → chunk-VVBAW5A5.js} +4201 -3809
- package/dist/chunk-VVBAW5A5.js.map +1 -0
- package/dist/chunk-Y4BUBBHD.js +614 -0
- package/dist/chunk-Y4BUBBHD.js.map +1 -0
- package/dist/{chunk-SAUPYVLF.js → chunk-ZSAAAMVR.js} +1 -1
- package/dist/chunk-ZSAAAMVR.js.map +1 -0
- package/dist/components.d.ts +3 -5
- package/dist/components.js +19 -23
- package/dist/components.js.map +1 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -2
- package/dist/{file-reference-D037xOFK.d.ts → file-reference-BavO2eQj.d.ts} +13 -10
- package/dist/hooks.d.ts +10 -5
- package/dist/hooks.js +14 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +13 -12
- package/dist/index.js +79 -73
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +3 -3
- package/dist/providers.js +3 -1
- package/dist/rbac/index.d.ts +76 -12
- package/dist/rbac/index.js +12 -9
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-CTDELQ7H.d.ts → usePublicRouteParams-DxIDS4bC.d.ts} +16 -9
- package/dist/utils.js +16 -16
- package/docs/README.md +2 -2
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +2 -2
- package/docs/api/classes/Logger.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +2 -2
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.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 +4 -4
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +2 -2
- package/docs/api/classes/SecureSupabaseClient.md +21 -16
- package/docs/api/classes/StorageUtils.md +7 -4
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/enums/LogLevel.md +1 -1
- package/docs/api/enums/RBACErrorCode.md +1 -1
- package/docs/api/enums/RPCFunction.md +1 -1
- package/docs/api/interfaces/AddressFieldProps.md +1 -1
- package/docs/api/interfaces/AddressFieldRef.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/AutocompleteOptions.md +1 -1
- package/docs/api/interfaces/AvatarProps.md +128 -0
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CalendarProps.md +20 -6
- 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/ComplianceResult.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +9 -9
- 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/DatabaseComplianceResult.md +1 -1
- package/docs/api/interfaces/DatabaseIssue.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/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +62 -16
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +2 -2
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +26 -12
- package/docs/api/interfaces/FileUploadProps.md +30 -19
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/FormFieldProps.md +1 -1
- package/docs/api/interfaces/FormProps.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/LoggerConfig.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
- package/docs/api/interfaces/NavigationContextType.md +9 -9
- 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 +7 -7
- 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 +8 -8
- package/docs/api/interfaces/PagePermissionContextType.md +8 -8
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/ParsedAddress.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProgressProps.md +3 -11
- package/docs/api/interfaces/ProtectedRouteProps.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/QuickFix.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
- package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
- package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACContext.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
- package/docs/api/interfaces/RBACResult.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
- package/docs/api/interfaces/RBACRolesListParams.md +1 -1
- package/docs/api/interfaces/RBACRolesListResult.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
- package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +10 -10
- package/docs/api/interfaces/RouteConfig.md +10 -10
- package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +9 -9
- package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/SetupIssue.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +4 -4
- package/docs/api/interfaces/StorageFileInfo.md +7 -7
- package/docs/api/interfaces/StorageFileMetadata.md +25 -14
- package/docs/api/interfaces/StorageListOptions.md +22 -9
- package/docs/api/interfaces/StorageListResult.md +4 -4
- package/docs/api/interfaces/StorageUploadOptions.md +21 -8
- package/docs/api/interfaces/StorageUploadResult.md +6 -6
- package/docs/api/interfaces/StorageUrlOptions.md +19 -6
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +1 -1
- package/docs/api/interfaces/TextareaProps.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 +53 -53
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
- package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.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 +4 -4
- package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
- package/docs/api/interfaces/UseResourcePermissionsOptions.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 +155 -135
- package/docs/api-reference/components.md +72 -29
- package/docs/api-reference/providers.md +2 -2
- package/docs/api-reference/rpc-functions.md +1 -0
- package/docs/best-practices/README.md +1 -1
- package/docs/best-practices/deployment.md +8 -8
- package/docs/getting-started/examples/README.md +2 -2
- package/docs/getting-started/installation-guide.md +4 -4
- package/docs/getting-started/quick-start.md +3 -3
- package/docs/migration/MIGRATION_GUIDE.md +3 -3
- package/docs/rbac/compliance/compliance-guide.md +2 -2
- package/docs/rbac/event-based-apps.md +2 -2
- package/docs/rbac/getting-started.md +2 -2
- package/docs/rbac/quick-start.md +2 -2
- package/docs/security/README.md +4 -4
- package/docs/standards/07-rbac-and-rls-standard.md +430 -7
- package/docs/troubleshooting/README.md +2 -2
- package/docs/troubleshooting/migration.md +3 -3
- package/package.json +1 -4
- package/scripts/check-pace-core-compliance.cjs +1 -1
- package/scripts/check-pace-core-compliance.js +1 -1
- package/src/__tests__/fixtures/supabase.ts +301 -0
- package/src/__tests__/public-recipe-view.test.ts +9 -9
- package/src/__tests__/rls-policies.test.ts +197 -61
- package/src/components/AddressField/AddressField.test.tsx +42 -0
- package/src/components/AddressField/AddressField.tsx +71 -60
- package/src/components/AddressField/README.md +1 -0
- package/src/components/Alert/Alert.test.tsx +50 -10
- package/src/components/Alert/Alert.tsx +5 -3
- package/src/components/Avatar/Avatar.test.tsx +252 -226
- package/src/components/Avatar/Avatar.tsx +179 -53
- package/src/components/Avatar/index.ts +1 -1
- package/src/components/Button/Button.test.tsx +2 -1
- package/src/components/Button/Button.tsx +3 -3
- package/src/components/Calendar/Calendar.test.tsx +53 -37
- package/src/components/Calendar/Calendar.tsx +409 -82
- package/src/components/Card/Card.test.tsx +7 -4
- package/src/components/Card/Card.tsx +3 -6
- package/src/components/Checkbox/Checkbox.tsx +2 -2
- package/src/components/DataTable/components/ActionButtons.tsx +5 -5
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
- package/src/components/DataTable/components/ColumnFilter.tsx +1 -1
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +3 -3
- package/src/components/DataTable/components/DataTableBody.tsx +12 -12
- package/src/components/DataTable/components/DataTableCore.tsx +3 -3
- package/src/components/DataTable/components/DataTableToolbar.tsx +5 -5
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +3 -3
- package/src/components/DataTable/components/EditableRow.tsx +2 -2
- package/src/components/DataTable/components/EmptyState.tsx +3 -3
- package/src/components/DataTable/components/GroupHeader.tsx +2 -2
- package/src/components/DataTable/components/GroupingDropdown.tsx +1 -1
- package/src/components/DataTable/components/ImportModal.tsx +4 -4
- package/src/components/DataTable/components/LoadingState.tsx +1 -1
- package/src/components/DataTable/components/PaginationControls.tsx +11 -11
- package/src/components/DataTable/components/UnifiedTableBody.tsx +9 -9
- package/src/components/DataTable/components/ViewRowModal.tsx +2 -2
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +11 -37
- package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +157 -0
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +2 -1
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +128 -0
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +19 -0
- package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +51 -0
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +84 -0
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +14 -0
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +136 -0
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +16 -0
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +18 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +28 -7
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +30 -1
- package/src/components/DataTable/utils/hierarchicalUtils.ts +38 -10
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -3
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +4 -4
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/EventSelector/EventSelector.tsx +7 -7
- package/src/components/FileDisplay/FileDisplay.tsx +291 -179
- package/src/components/FileUpload/FileUpload.tsx +7 -4
- package/src/components/Header/Header.test.tsx +28 -0
- package/src/components/Header/Header.tsx +22 -9
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -2
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +19 -14
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +5 -5
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +127 -1
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +8 -8
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +4 -0
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +3 -0
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +3 -0
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +16 -6
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +37 -3
- package/src/components/PaceAppLayout/test-setup.tsx +1 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +66 -45
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +6 -4
- package/src/components/Progress/Progress.test.tsx +18 -19
- package/src/components/Progress/Progress.tsx +31 -32
- package/src/components/PublicLayout/PublicLayout.test.tsx +6 -6
- package/src/components/PublicLayout/PublicPageProvider.tsx +5 -3
- package/src/components/Select/Select.tsx +5 -5
- package/src/components/Switch/Switch.test.tsx +2 -1
- package/src/components/Switch/Switch.tsx +1 -1
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Tooltip/Tooltip.test.tsx +8 -2
- package/src/components/UserMenu/UserMenu.test.tsx +7 -9
- package/src/components/UserMenu/UserMenu.tsx +10 -8
- package/src/components/index.ts +2 -1
- package/src/eslint-rules/pace-core-compliance.cjs +0 -2
- package/src/eslint-rules/pace-core-compliance.js +0 -2
- package/src/hooks/__tests__/hooks.integration.test.tsx +4 -1
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +76 -5
- package/src/hooks/__tests__/useDataTableState.test.ts +76 -0
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +25 -69
- package/src/hooks/__tests__/useFileUrlCache.test.ts +129 -0
- package/src/hooks/__tests__/usePreventTabReload.test.ts +88 -0
- package/src/hooks/__tests__/{usePublicEvent.unit.test.ts → usePublicEvent.test.ts} +28 -1
- package/src/hooks/__tests__/useQueryCache.test.ts +144 -0
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +58 -16
- package/src/hooks/index.ts +1 -1
- package/src/hooks/public/usePublicEvent.ts +2 -2
- package/src/hooks/public/usePublicFileDisplay.ts +173 -87
- package/src/hooks/useAppConfig.ts +24 -5
- package/src/hooks/useFileDisplay.ts +297 -34
- package/src/hooks/useFileReference.ts +56 -11
- package/src/hooks/useFileUrl.ts +1 -1
- package/src/hooks/useInactivityTracker.ts +16 -7
- package/src/hooks/usePermissionCache.test.ts +85 -8
- package/src/hooks/useQueryCache.ts +21 -0
- package/src/hooks/useSecureDataAccess.test.ts +80 -35
- package/src/hooks/useSecureDataAccess.ts +80 -37
- package/src/index.ts +2 -1
- package/src/providers/services/EventServiceProvider.tsx +37 -17
- package/src/providers/services/InactivityServiceProvider.tsx +4 -4
- package/src/providers/services/OrganisationServiceProvider.tsx +8 -1
- package/src/providers/services/UnifiedAuthProvider.tsx +115 -29
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +451 -0
- package/src/rbac/__tests__/engine.comprehensive.test.ts +12 -0
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +8 -0
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +4 -0
- package/src/rbac/api.ts +240 -36
- package/src/rbac/cache-invalidation.ts +21 -7
- package/src/rbac/compliance/quick-fix-suggestions.ts +1 -1
- package/src/rbac/components/NavigationGuard.tsx +23 -63
- package/src/rbac/components/NavigationProvider.test.tsx +52 -23
- package/src/rbac/components/NavigationProvider.tsx +13 -11
- package/src/rbac/components/PagePermissionGuard.tsx +77 -203
- package/src/rbac/components/PagePermissionProvider.tsx +13 -11
- package/src/rbac/components/PermissionEnforcer.tsx +24 -62
- package/src/rbac/components/RoleBasedRouter.tsx +14 -12
- package/src/rbac/components/SecureDataProvider.tsx +13 -11
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +104 -41
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +49 -12
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +22 -1
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +161 -82
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +22 -1
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +77 -30
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +39 -5
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +47 -4
- package/src/rbac/engine.ts +4 -2
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +144 -52
- package/src/rbac/hooks/index.ts +3 -0
- package/src/rbac/hooks/useCan.test.ts +101 -53
- package/src/rbac/hooks/usePermissions.ts +108 -41
- package/src/rbac/hooks/useRBAC.test.ts +11 -3
- package/src/rbac/hooks/useRBAC.ts +83 -40
- package/src/rbac/hooks/useResolvedScope.test.ts +189 -63
- package/src/rbac/hooks/useResolvedScope.ts +128 -70
- package/src/rbac/hooks/useSecureSupabase.ts +36 -19
- package/src/rbac/hooks/useSuperAdminBypass.ts +126 -0
- package/src/rbac/request-deduplication.ts +1 -1
- package/src/rbac/secureClient.ts +72 -12
- package/src/rbac/security.ts +29 -23
- package/src/rbac/types.ts +10 -0
- package/src/rbac/utils/__tests__/contextValidator.test.ts +150 -0
- package/src/rbac/utils/__tests__/deep-equal.test.ts +53 -0
- package/src/rbac/utils/__tests__/eventContext.test.ts +6 -1
- package/src/rbac/utils/contextValidator.ts +288 -0
- package/src/rbac/utils/eventContext.ts +48 -2
- package/src/services/EventService.ts +165 -21
- package/src/services/OrganisationService.ts +37 -2
- package/src/services/__tests__/EventService.test.ts +26 -21
- package/src/types/file-reference.ts +13 -10
- package/src/utils/app/appNameResolver.test.ts +346 -73
- package/src/utils/context/superAdminOverride.ts +58 -0
- package/src/utils/file-reference/index.ts +61 -33
- package/src/utils/google-places/googlePlacesUtils.test.ts +98 -0
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +83 -0
- package/src/utils/storage/helpers.test.ts +1 -1
- package/src/utils/storage/helpers.ts +38 -19
- package/src/utils/storage/types.ts +15 -8
- package/src/utils/validation/__tests__/csrf.test.ts +105 -0
- package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +92 -0
- package/src/vite-env.d.ts +2 -2
- package/dist/chunk-3GOZZZYH.js.map +0 -1
- package/dist/chunk-DDM4CCYT.js.map +0 -1
- package/dist/chunk-E7UAOUMY.js +0 -75
- package/dist/chunk-E7UAOUMY.js.map +0 -1
- package/dist/chunk-EFCLXK7F.js.map +0 -1
- package/dist/chunk-F2IMUDXZ.js.map +0 -1
- package/dist/chunk-HEHYGYOX.js.map +0 -1
- package/dist/chunk-IM4QE42D.js.map +0 -1
- package/dist/chunk-IPCH26AG.js.map +0 -1
- package/dist/chunk-SAUPYVLF.js.map +0 -1
- package/dist/chunk-THRPYOFK.js.map +0 -1
- package/dist/chunk-UNOTYLQF.js.map +0 -1
- package/dist/chunk-VGZZXKBR.js.map +0 -1
- package/dist/chunk-YHCN776L.js.map +0 -1
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -703
- package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -428
- /package/dist/{DataTable-GUFUNZ3N.js.map → DataTable-ON3IXISJ.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-643PUAIM.js.map → UnifiedAuthProvider-X5NXANVI.js.map} +0 -0
- /package/dist/{api-YP7XD5L6.js.map → api-I6UCQ5S6.js.map} +0 -0
- /package/dist/{chunk-HESYZWZW.js.map → chunk-QWWZ5CAQ.js.map} +0 -0
|
@@ -8,20 +8,34 @@ import { PublicPageContext, useIsPublicPage } from '../PublicLayout/PublicPagePr
|
|
|
8
8
|
import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
|
|
9
9
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogBody, DialogFooter } from '../Dialog/Dialog';
|
|
10
10
|
import { Button } from '../Button/Button';
|
|
11
|
+
import { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';
|
|
11
12
|
import { logger } from '../../utils/core/logger';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Size classes for fallback display
|
|
15
16
|
*/
|
|
16
17
|
const fallbackSizeClasses = {
|
|
17
|
-
xs: '
|
|
18
|
-
sm: '
|
|
19
|
-
md: '
|
|
20
|
-
lg: '
|
|
21
|
-
xl: '
|
|
22
|
-
'2xl': '
|
|
18
|
+
xs: 'size-4 text-xs',
|
|
19
|
+
sm: 'size-6 text-sm',
|
|
20
|
+
md: 'size-8 text-base',
|
|
21
|
+
lg: 'size-12 text-lg',
|
|
22
|
+
xl: 'size-16 text-xl',
|
|
23
|
+
'2xl': 'size-20 text-2xl'
|
|
23
24
|
};
|
|
24
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Base classes for fallback display
|
|
28
|
+
*/
|
|
29
|
+
const fallbackBaseClasses = 'size-full grid place-items-center text-center text-sec-600 font-semibold';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Helper function to compute fallback classes for a given size
|
|
33
|
+
*/
|
|
34
|
+
function getFallbackClasses(size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' = 'md'): string {
|
|
35
|
+
const sizeClass = fallbackSizeClasses[size];
|
|
36
|
+
return `${fallbackBaseClasses} ${sizeClass}`.trim();
|
|
37
|
+
}
|
|
38
|
+
|
|
25
39
|
/**
|
|
26
40
|
* Default fallback text generator - extracts initials from file name
|
|
27
41
|
*/
|
|
@@ -43,7 +57,13 @@ function defaultGenerateFallbackText(fileName?: string): string {
|
|
|
43
57
|
export interface FileDisplayProps {
|
|
44
58
|
table_name: string;
|
|
45
59
|
record_id: string;
|
|
46
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Optional organisation ID. When not provided (undefined), the component will automatically
|
|
62
|
+
* search for files in both user-scoped (organisation_id = null) and organisation-scoped contexts.
|
|
63
|
+
* If both types of files exist, organisation-scoped files are preferred.
|
|
64
|
+
* When explicitly set to null, only user-scoped files are searched.
|
|
65
|
+
*/
|
|
66
|
+
organisation_id?: string;
|
|
47
67
|
category?: FileCategory;
|
|
48
68
|
/** Display only a single file instead of all files. Uses first file (prefers images) from all files, without category filtering */
|
|
49
69
|
displayOnly?: boolean;
|
|
@@ -60,8 +80,18 @@ export interface FileDisplayProps {
|
|
|
60
80
|
generateFallbackText?: (fileName?: string) => string;
|
|
61
81
|
/** Explicit fallback text to display (overrides generateFallbackText) */
|
|
62
82
|
fallbackText?: string;
|
|
83
|
+
/** Source text to use for generating fallback text (overrides filename) */
|
|
84
|
+
fallbackSourceText?: string;
|
|
63
85
|
/** Size variant for fallback display (only applies when showFallback is true) */
|
|
64
86
|
fallbackSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
87
|
+
/**
|
|
88
|
+
* Enable children rendering in displayOnly mode. When true, uses standard display path
|
|
89
|
+
* (with children support) even if showDelete is false. The delete button will only appear
|
|
90
|
+
* if showDelete is also true.
|
|
91
|
+
*/
|
|
92
|
+
enableChildren?: boolean;
|
|
93
|
+
/** Whether to show metadata (filename, filesize, mimetype) in figcaption. Defaults to true. */
|
|
94
|
+
showMetadata?: boolean;
|
|
65
95
|
}
|
|
66
96
|
|
|
67
97
|
// Shared rendering logic for file display
|
|
@@ -80,13 +110,16 @@ interface FileDisplayContentProps {
|
|
|
80
110
|
children?: React.ReactNode;
|
|
81
111
|
onDelete?: () => Promise<void>;
|
|
82
112
|
clearError?: () => void;
|
|
83
|
-
organisation_id: string;
|
|
113
|
+
organisation_id: string | undefined;
|
|
84
114
|
loadingComponent?: React.ComponentType;
|
|
85
115
|
errorComponent?: React.ComponentType<{ error: Error | string | null; retry?: () => void }>;
|
|
86
116
|
showFallback?: boolean;
|
|
87
117
|
generateFallbackText?: (fileName?: string) => string;
|
|
88
118
|
fallbackText?: string;
|
|
119
|
+
fallbackSourceText?: string;
|
|
89
120
|
fallbackSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
121
|
+
enableChildren?: boolean;
|
|
122
|
+
showMetadata?: boolean;
|
|
90
123
|
}
|
|
91
124
|
|
|
92
125
|
function FileDisplayContent({
|
|
@@ -110,7 +143,10 @@ function FileDisplayContent({
|
|
|
110
143
|
showFallback = false,
|
|
111
144
|
generateFallbackText = defaultGenerateFallbackText,
|
|
112
145
|
fallbackText,
|
|
113
|
-
|
|
146
|
+
fallbackSourceText,
|
|
147
|
+
fallbackSize = 'md',
|
|
148
|
+
enableChildren = false,
|
|
149
|
+
showMetadata = true
|
|
114
150
|
}: FileDisplayContentProps) {
|
|
115
151
|
const [imageError, setImageError] = useState(false);
|
|
116
152
|
const [internalFileUrls, setInternalFileUrls] = useState<Map<string, string>>(new Map(fileUrls));
|
|
@@ -120,16 +156,15 @@ function FileDisplayContent({
|
|
|
120
156
|
// Compute fallback text
|
|
121
157
|
const computedFallbackText = useMemo(() => {
|
|
122
158
|
if (fallbackText) return fallbackText;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
159
|
+
// Use fallbackSourceText if provided, otherwise fall back to filename
|
|
160
|
+
const sourceText = fallbackSourceText ?? fileReference?.file_metadata?.fileName;
|
|
161
|
+
return generateFallbackText(sourceText);
|
|
162
|
+
}, [fallbackText, fallbackSourceText, fileReference, generateFallbackText]);
|
|
126
163
|
|
|
127
164
|
// Compute fallback classes
|
|
128
165
|
const fallbackClasses = useMemo(() => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return `${baseClasses} ${sizeClass} ${className}`.trim();
|
|
132
|
-
}, [fallbackSize, className]);
|
|
166
|
+
return getFallbackClasses(fallbackSize);
|
|
167
|
+
}, [fallbackSize]);
|
|
133
168
|
|
|
134
169
|
// Sync fileUrls prop with internal state
|
|
135
170
|
// Track file references to detect when they change and sync URLs
|
|
@@ -159,28 +194,8 @@ function FileDisplayContent({
|
|
|
159
194
|
setImageError(false);
|
|
160
195
|
};
|
|
161
196
|
|
|
162
|
-
const handleImageError = (
|
|
197
|
+
const handleImageError = () => {
|
|
163
198
|
setImageError(true);
|
|
164
|
-
|
|
165
|
-
// If fallback is enabled, show fallback UI when image fails to load
|
|
166
|
-
if (showFallback && e) {
|
|
167
|
-
const target = e.target as HTMLImageElement;
|
|
168
|
-
target.style.display = 'none';
|
|
169
|
-
|
|
170
|
-
// Check if fallback already exists
|
|
171
|
-
if (target.nextSibling && (target.nextSibling as HTMLElement).className.includes('bg-sec-100')) {
|
|
172
|
-
return; // Fallback already shown
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Create fallback element
|
|
176
|
-
const fallback = document.createElement('div');
|
|
177
|
-
fallback.className = fallbackClasses;
|
|
178
|
-
fallback.textContent = computedFallbackText;
|
|
179
|
-
fallback.title = fileReference?.file_metadata?.fileName || 'File';
|
|
180
|
-
|
|
181
|
-
// Insert fallback after the image
|
|
182
|
-
target.parentNode?.insertBefore(fallback, target.nextSibling);
|
|
183
|
-
}
|
|
184
199
|
};
|
|
185
200
|
|
|
186
201
|
const getFileIcon = (fileType: string) => {
|
|
@@ -211,27 +226,29 @@ function FileDisplayContent({
|
|
|
211
226
|
// Show fallback if enabled
|
|
212
227
|
if (showFallback) {
|
|
213
228
|
return (
|
|
214
|
-
<
|
|
215
|
-
{
|
|
216
|
-
|
|
229
|
+
<figure className={className} title="File unavailable">
|
|
230
|
+
<p className={fallbackClasses}>
|
|
231
|
+
{computedFallbackText}
|
|
232
|
+
</p>
|
|
233
|
+
</figure>
|
|
217
234
|
);
|
|
218
235
|
}
|
|
219
236
|
|
|
220
237
|
return (
|
|
221
|
-
<
|
|
222
|
-
<
|
|
238
|
+
<figure className={className} title="Error">
|
|
239
|
+
<p className={getFallbackClasses(fallbackSize || 'md')}>
|
|
223
240
|
Error loading file: {error instanceof Error ? error.message : String(error)}
|
|
224
|
-
</
|
|
241
|
+
</p>
|
|
225
242
|
{clearError && (
|
|
226
|
-
<
|
|
243
|
+
<Button
|
|
227
244
|
onClick={clearError}
|
|
228
|
-
className="mt-2
|
|
245
|
+
className="mt-2"
|
|
229
246
|
aria-label="Retry loading file"
|
|
230
247
|
>
|
|
231
248
|
Try again
|
|
232
|
-
</
|
|
249
|
+
</Button>
|
|
233
250
|
)}
|
|
234
|
-
</
|
|
251
|
+
</figure>
|
|
235
252
|
);
|
|
236
253
|
}
|
|
237
254
|
|
|
@@ -241,28 +258,32 @@ function FileDisplayContent({
|
|
|
241
258
|
// Show fallback if enabled
|
|
242
259
|
if (showFallback) {
|
|
243
260
|
return (
|
|
244
|
-
<
|
|
245
|
-
{
|
|
261
|
+
<figure className={className} title="No file">
|
|
262
|
+
<p className={fallbackClasses}>
|
|
263
|
+
{computedFallbackText}
|
|
264
|
+
</p>
|
|
246
265
|
{children}
|
|
247
|
-
</
|
|
266
|
+
</figure>
|
|
248
267
|
);
|
|
249
268
|
}
|
|
250
269
|
|
|
251
270
|
return (
|
|
252
|
-
<
|
|
253
|
-
No files found
|
|
271
|
+
<figure className={`text-sec-500 text-center p-4 ${className}`}>
|
|
272
|
+
<p>No files found</p>
|
|
254
273
|
{children}
|
|
255
|
-
</
|
|
274
|
+
</figure>
|
|
256
275
|
);
|
|
257
276
|
}
|
|
258
277
|
|
|
259
278
|
// During loading, show fallback if enabled (better UX than spinner for empty states)
|
|
260
279
|
if (isLoading && showFallback && fileCount === 0) {
|
|
261
280
|
return (
|
|
262
|
-
<
|
|
263
|
-
{
|
|
281
|
+
<figure className={className} title="Loading...">
|
|
282
|
+
<p className={fallbackClasses}>
|
|
283
|
+
{computedFallbackText}
|
|
284
|
+
</p>
|
|
264
285
|
{children}
|
|
265
|
-
</
|
|
286
|
+
</figure>
|
|
266
287
|
);
|
|
267
288
|
}
|
|
268
289
|
|
|
@@ -271,9 +292,11 @@ function FileDisplayContent({
|
|
|
271
292
|
return <LoadingComponent />;
|
|
272
293
|
}
|
|
273
294
|
return (
|
|
274
|
-
<
|
|
275
|
-
<
|
|
276
|
-
|
|
295
|
+
<figure className={className} title="Loading">
|
|
296
|
+
<p className="flex items-center justify-center p-4">
|
|
297
|
+
<LoadingSpinner />
|
|
298
|
+
</p>
|
|
299
|
+
</figure>
|
|
277
300
|
);
|
|
278
301
|
}
|
|
279
302
|
|
|
@@ -282,34 +305,39 @@ function FileDisplayContent({
|
|
|
282
305
|
const isImage = fileReference.file_metadata.fileType?.startsWith('image/');
|
|
283
306
|
|
|
284
307
|
// Simplified image-only display when displayOnly is true and it's an image
|
|
285
|
-
if
|
|
308
|
+
// Only use simplified path if enableChildren is not explicitly enabled
|
|
309
|
+
if (displayOnly && isImage && !showDelete && !enableChildren) {
|
|
286
310
|
// Show fallback if image error occurred and fallback is enabled
|
|
287
311
|
if (imageError && showFallback) {
|
|
288
312
|
return (
|
|
289
|
-
<
|
|
290
|
-
{
|
|
291
|
-
|
|
313
|
+
<figure className={className} title={fileReference.file_metadata.fileName || 'File'}>
|
|
314
|
+
<p className={fallbackClasses}>
|
|
315
|
+
{computedFallbackText}
|
|
316
|
+
</p>
|
|
317
|
+
</figure>
|
|
292
318
|
);
|
|
293
319
|
}
|
|
294
320
|
|
|
295
321
|
// Show loading skeleton if URL is not available yet
|
|
296
322
|
if (!fileUrl) {
|
|
297
323
|
return (
|
|
298
|
-
<
|
|
299
|
-
<
|
|
300
|
-
<
|
|
301
|
-
</
|
|
302
|
-
</
|
|
324
|
+
<figure className={className || "max-w-full h-48"} title="Loading">
|
|
325
|
+
<p className={fallbackClasses}>
|
|
326
|
+
<LoadingSpinner />
|
|
327
|
+
</p>
|
|
328
|
+
</figure>
|
|
303
329
|
);
|
|
304
330
|
}
|
|
305
331
|
|
|
306
332
|
return (
|
|
307
|
-
<
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
333
|
+
<figure className={className || "max-w-full h-auto"}>
|
|
334
|
+
<img
|
|
335
|
+
src={fileUrl}
|
|
336
|
+
alt={fileReference.file_metadata.fileName || 'File'}
|
|
337
|
+
className="max-w-full h-auto"
|
|
338
|
+
onError={handleImageError}
|
|
339
|
+
/>
|
|
340
|
+
</figure>
|
|
313
341
|
);
|
|
314
342
|
}
|
|
315
343
|
|
|
@@ -320,19 +348,29 @@ function FileDisplayContent({
|
|
|
320
348
|
const ariaLabel = `Open ${fileName} in new tab`;
|
|
321
349
|
|
|
322
350
|
return (
|
|
323
|
-
<
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
351
|
+
<figure className={className}>
|
|
352
|
+
<a
|
|
353
|
+
href={fileUrl}
|
|
354
|
+
target="_blank"
|
|
355
|
+
rel="noopener noreferrer"
|
|
356
|
+
aria-label={ariaLabel}
|
|
357
|
+
className="flex items-center gap-2 p-3 bg-sec-50 border border-sec-200 rounded-lg hover:bg-sec-100 transition-colors text-main-600 hover:text-main-700 focus:outline-none focus:ring-2 focus:ring-main-500 focus:ring-offset-2"
|
|
358
|
+
>
|
|
359
|
+
<FileText className="size-5 shrink-0" aria-hidden="true" />
|
|
360
|
+
<span className="flex-1 font-medium truncate">
|
|
361
|
+
{fileName}
|
|
362
|
+
</span>
|
|
363
|
+
<ExternalLink className="size-5 shrink-0" aria-hidden="true" />
|
|
364
|
+
</a>
|
|
365
|
+
{showMetadata && (
|
|
366
|
+
<figcaption>
|
|
367
|
+
<p>{fileName}</p>
|
|
368
|
+
{fileReference.file_metadata.fileSize && (
|
|
369
|
+
<p>{formatFileSize(fileReference.file_metadata.fileSize)} • {fileReference.file_metadata.fileType}</p>
|
|
370
|
+
)}
|
|
371
|
+
</figcaption>
|
|
372
|
+
)}
|
|
373
|
+
</figure>
|
|
336
374
|
);
|
|
337
375
|
}
|
|
338
376
|
|
|
@@ -340,16 +378,18 @@ function FileDisplayContent({
|
|
|
340
378
|
// For displayOnly mode, if fallback is enabled and there's no URL or image error, show fallback instead of folder icon
|
|
341
379
|
if (displayOnly && showFallback && (!fileUrl || imageError || !isImage)) {
|
|
342
380
|
return (
|
|
343
|
-
<
|
|
344
|
-
{
|
|
345
|
-
|
|
381
|
+
<figure className={className} title={fileReference.file_metadata.fileName || 'File'}>
|
|
382
|
+
<p className={fallbackClasses}>
|
|
383
|
+
{computedFallbackText}
|
|
384
|
+
</p>
|
|
385
|
+
</figure>
|
|
346
386
|
);
|
|
347
387
|
}
|
|
348
388
|
|
|
349
389
|
return (
|
|
350
|
-
<
|
|
390
|
+
<figure className={`relative ${className}`}>
|
|
351
391
|
{isImage && fileUrl && !imageError ? (
|
|
352
|
-
|
|
392
|
+
<>
|
|
353
393
|
<img
|
|
354
394
|
src={fileUrl}
|
|
355
395
|
alt={fileReference.file_metadata.fileName || 'File'}
|
|
@@ -358,14 +398,16 @@ function FileDisplayContent({
|
|
|
358
398
|
/>
|
|
359
399
|
{showDelete && (
|
|
360
400
|
<>
|
|
361
|
-
<
|
|
401
|
+
<Button
|
|
402
|
+
variant="destructive"
|
|
403
|
+
size="icon"
|
|
362
404
|
onClick={handleDeleteClick}
|
|
363
|
-
className="absolute top-2 right-2
|
|
405
|
+
className="absolute top-2 right-2"
|
|
364
406
|
title="Delete file"
|
|
365
407
|
aria-label="Delete file"
|
|
366
408
|
>
|
|
367
409
|
×
|
|
368
|
-
</
|
|
410
|
+
</Button>
|
|
369
411
|
<Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
|
|
370
412
|
<DialogContent size="sm">
|
|
371
413
|
<DialogHeader>
|
|
@@ -386,73 +428,108 @@ function FileDisplayContent({
|
|
|
386
428
|
</Dialog>
|
|
387
429
|
</>
|
|
388
430
|
)}
|
|
389
|
-
|
|
431
|
+
{children}
|
|
432
|
+
{showMetadata && (
|
|
433
|
+
<figcaption>
|
|
434
|
+
<p>{fileReference.file_metadata.fileName || 'Unknown file'}</p>
|
|
435
|
+
{(fileReference.file_metadata.fileSize || fileReference.file_metadata.fileType) && (
|
|
436
|
+
<p>
|
|
437
|
+
{fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize)}
|
|
438
|
+
{fileReference.file_metadata.fileSize && fileReference.file_metadata.fileType && ' • '}
|
|
439
|
+
{fileReference.file_metadata.fileType}
|
|
440
|
+
</p>
|
|
441
|
+
)}
|
|
442
|
+
</figcaption>
|
|
443
|
+
)}
|
|
444
|
+
</>
|
|
390
445
|
) : isImage && imageError && showFallback ? (
|
|
391
446
|
// Show fallback when image fails to load and fallback is enabled
|
|
392
|
-
|
|
393
|
-
{
|
|
394
|
-
|
|
447
|
+
<>
|
|
448
|
+
<p className={fallbackClasses} title={fileReference.file_metadata.fileName || 'File'}>
|
|
449
|
+
{computedFallbackText}
|
|
450
|
+
</p>
|
|
451
|
+
{children}
|
|
452
|
+
{showMetadata && (
|
|
453
|
+
<figcaption>
|
|
454
|
+
<p>{fileReference.file_metadata.fileName || 'Unknown file'}</p>
|
|
455
|
+
{(fileReference.file_metadata.fileSize || fileReference.file_metadata.fileType) && (
|
|
456
|
+
<p>
|
|
457
|
+
{fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize)}
|
|
458
|
+
{fileReference.file_metadata.fileSize && fileReference.file_metadata.fileType && ' • '}
|
|
459
|
+
{fileReference.file_metadata.fileType}
|
|
460
|
+
</p>
|
|
461
|
+
)}
|
|
462
|
+
</figcaption>
|
|
463
|
+
)}
|
|
464
|
+
</>
|
|
395
465
|
) : (
|
|
396
|
-
|
|
397
|
-
<
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
466
|
+
<>
|
|
467
|
+
<p className="flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200">
|
|
468
|
+
<span className="text-2xl">
|
|
469
|
+
{getFileIcon(fileReference.file_metadata.fileType || '')}
|
|
470
|
+
</span>
|
|
471
|
+
{showDelete && (
|
|
472
|
+
<>
|
|
473
|
+
<Button
|
|
474
|
+
variant="destructive"
|
|
475
|
+
size="icon"
|
|
476
|
+
onClick={handleDeleteClick}
|
|
477
|
+
className="ml-auto"
|
|
478
|
+
title="Delete file"
|
|
479
|
+
aria-label="Delete file"
|
|
480
|
+
>
|
|
481
|
+
×
|
|
482
|
+
</Button>
|
|
483
|
+
<Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
|
|
484
|
+
<DialogContent size="sm">
|
|
485
|
+
<DialogHeader>
|
|
486
|
+
<DialogTitle>Confirm Delete</DialogTitle>
|
|
487
|
+
</DialogHeader>
|
|
488
|
+
<DialogBody>
|
|
489
|
+
<p>Are you sure you want to delete this file? This action cannot be undone.</p>
|
|
490
|
+
</DialogBody>
|
|
491
|
+
<DialogFooter>
|
|
492
|
+
<Button variant="outline" onClick={() => setDeleteDialogOpen(false)}>
|
|
493
|
+
Cancel
|
|
494
|
+
</Button>
|
|
495
|
+
<Button variant="destructive" onClick={handleDeleteConfirm}>
|
|
496
|
+
Delete
|
|
497
|
+
</Button>
|
|
498
|
+
</DialogFooter>
|
|
499
|
+
</DialogContent>
|
|
500
|
+
</Dialog>
|
|
501
|
+
</>
|
|
502
|
+
)}
|
|
503
|
+
</p>
|
|
504
|
+
{children}
|
|
505
|
+
{showMetadata && (
|
|
506
|
+
<figcaption>
|
|
507
|
+
<p>{fileReference.file_metadata.fileName || 'Unknown file'}</p>
|
|
508
|
+
{(fileReference.file_metadata.fileSize || fileReference.file_metadata.fileType) && (
|
|
509
|
+
<p>
|
|
510
|
+
{fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize)}
|
|
511
|
+
{fileReference.file_metadata.fileSize && fileReference.file_metadata.fileType && ' • '}
|
|
512
|
+
{fileReference.file_metadata.fileType}
|
|
513
|
+
</p>
|
|
514
|
+
)}
|
|
515
|
+
</figcaption>
|
|
438
516
|
)}
|
|
439
|
-
|
|
517
|
+
</>
|
|
440
518
|
)}
|
|
441
|
-
|
|
442
|
-
</div>
|
|
519
|
+
</figure>
|
|
443
520
|
);
|
|
444
521
|
}
|
|
445
522
|
|
|
446
523
|
// Multiple files display
|
|
447
524
|
return (
|
|
448
|
-
<
|
|
525
|
+
<figure className={`space-y-2 ${className}`}>
|
|
449
526
|
{fileReferences.map((fileRef) => {
|
|
450
527
|
const isImage = fileRef.file_metadata.fileType?.startsWith('image/');
|
|
451
528
|
const fileUrl = internalFileUrls.get(fileRef.id) || null;
|
|
452
529
|
const canDownload = !isImage && fileUrl;
|
|
453
530
|
|
|
454
531
|
return (
|
|
455
|
-
<
|
|
532
|
+
<figure key={fileRef.id} className="flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200">
|
|
456
533
|
{isImage && fileUrl ? (
|
|
457
534
|
<img
|
|
458
535
|
src={fileUrl}
|
|
@@ -465,17 +542,23 @@ function FileDisplayContent({
|
|
|
465
542
|
{getFileIcon(fileRef.file_metadata.fileType || '')}
|
|
466
543
|
</span>
|
|
467
544
|
)}
|
|
468
|
-
|
|
469
|
-
<
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
{fileRef.file_metadata.fileSize
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
545
|
+
{showMetadata && (
|
|
546
|
+
<figcaption className="flex-1 min-w-0">
|
|
547
|
+
<p className="font-medium text-sec-900 truncate">
|
|
548
|
+
{fileRef.file_metadata.fileName || 'Unknown file'}
|
|
549
|
+
</p>
|
|
550
|
+
{(fileRef.file_metadata.fileSize || fileRef.file_metadata.fileType || fileRef.file_metadata.category) && (
|
|
551
|
+
<p className="text-sm text-sec-500">
|
|
552
|
+
{fileRef.file_metadata.fileSize && formatFileSize(fileRef.file_metadata.fileSize)}
|
|
553
|
+
{fileRef.file_metadata.fileSize && fileRef.file_metadata.fileType && ' • '}
|
|
554
|
+
{fileRef.file_metadata.fileType}
|
|
555
|
+
{(fileRef.file_metadata.fileSize || fileRef.file_metadata.fileType) && fileRef.file_metadata.category && ' • '}
|
|
556
|
+
{fileRef.file_metadata.category}
|
|
557
|
+
</p>
|
|
558
|
+
)}
|
|
559
|
+
</figcaption>
|
|
560
|
+
)}
|
|
561
|
+
<p className="flex items-center space-x-2">
|
|
479
562
|
{canDownload && (
|
|
480
563
|
<a
|
|
481
564
|
href={fileRef.file_path}
|
|
@@ -486,22 +569,23 @@ function FileDisplayContent({
|
|
|
486
569
|
↓
|
|
487
570
|
</a>
|
|
488
571
|
)}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
572
|
+
{showDelete && onDelete && (
|
|
573
|
+
<Button
|
|
574
|
+
variant="destructive"
|
|
575
|
+
size="icon"
|
|
576
|
+
onClick={handleDeleteClick}
|
|
577
|
+
title="Delete file"
|
|
578
|
+
aria-label="Delete file"
|
|
579
|
+
>
|
|
580
|
+
×
|
|
581
|
+
</Button>
|
|
582
|
+
)}
|
|
583
|
+
</p>
|
|
584
|
+
</figure>
|
|
501
585
|
);
|
|
502
586
|
})}
|
|
503
587
|
{children}
|
|
504
|
-
</
|
|
588
|
+
</figure>
|
|
505
589
|
);
|
|
506
590
|
}
|
|
507
591
|
|
|
@@ -523,7 +607,10 @@ function FileDisplayPublic({
|
|
|
523
607
|
showFallback,
|
|
524
608
|
generateFallbackText,
|
|
525
609
|
fallbackText,
|
|
526
|
-
|
|
610
|
+
fallbackSourceText,
|
|
611
|
+
fallbackSize,
|
|
612
|
+
enableChildren,
|
|
613
|
+
showMetadata
|
|
527
614
|
}: FileDisplayProps) {
|
|
528
615
|
const publicPageContext = useContext(PublicPageContext);
|
|
529
616
|
const supabase = publicPageContext?.supabase ?? null;
|
|
@@ -552,16 +639,21 @@ function FileDisplayPublic({
|
|
|
552
639
|
showFallback={showFallback}
|
|
553
640
|
generateFallbackText={generateFallbackText}
|
|
554
641
|
fallbackText={fallbackText}
|
|
642
|
+
fallbackSourceText={fallbackSourceText}
|
|
555
643
|
fallbackSize={fallbackSize}
|
|
644
|
+
enableChildren={enableChildren}
|
|
645
|
+
showMetadata={showMetadata}
|
|
556
646
|
/>
|
|
557
647
|
);
|
|
558
648
|
}
|
|
559
649
|
|
|
560
650
|
// Only show error if fallback is not enabled
|
|
561
651
|
return (
|
|
562
|
-
<
|
|
563
|
-
|
|
564
|
-
|
|
652
|
+
<figure className={className} title="Error">
|
|
653
|
+
<p className={getFallbackClasses(fallbackSize || 'md')}>
|
|
654
|
+
Supabase client not available in public context
|
|
655
|
+
</p>
|
|
656
|
+
</figure>
|
|
565
657
|
);
|
|
566
658
|
}
|
|
567
659
|
|
|
@@ -640,7 +732,10 @@ function FileDisplayPublic({
|
|
|
640
732
|
showFallback={showFallback}
|
|
641
733
|
generateFallbackText={generateFallbackText}
|
|
642
734
|
fallbackText={fallbackText}
|
|
735
|
+
fallbackSourceText={fallbackSourceText}
|
|
643
736
|
fallbackSize={fallbackSize}
|
|
737
|
+
enableChildren={enableChildren}
|
|
738
|
+
showMetadata={showMetadata}
|
|
644
739
|
/>
|
|
645
740
|
);
|
|
646
741
|
}
|
|
@@ -663,15 +758,20 @@ function FileDisplayAuthenticated({
|
|
|
663
758
|
showFallback,
|
|
664
759
|
generateFallbackText,
|
|
665
760
|
fallbackText,
|
|
666
|
-
|
|
761
|
+
fallbackSourceText,
|
|
762
|
+
fallbackSize,
|
|
763
|
+
enableChildren,
|
|
764
|
+
showMetadata
|
|
667
765
|
}: FileDisplayProps) {
|
|
668
766
|
const { supabase } = useUnifiedAuth();
|
|
669
767
|
|
|
670
768
|
if (!supabase) {
|
|
671
769
|
return (
|
|
672
|
-
<
|
|
673
|
-
|
|
674
|
-
|
|
770
|
+
<figure className={className} title="Error">
|
|
771
|
+
<p className={getFallbackClasses(fallbackSize || 'md')}>
|
|
772
|
+
Supabase client not available in authenticated context
|
|
773
|
+
</p>
|
|
774
|
+
</figure>
|
|
675
775
|
);
|
|
676
776
|
}
|
|
677
777
|
|
|
@@ -771,7 +871,10 @@ function FileDisplayAuthenticated({
|
|
|
771
871
|
showFallback={showFallback}
|
|
772
872
|
generateFallbackText={generateFallbackText}
|
|
773
873
|
fallbackText={fallbackText}
|
|
874
|
+
fallbackSourceText={fallbackSourceText}
|
|
774
875
|
fallbackSize={fallbackSize}
|
|
876
|
+
enableChildren={enableChildren}
|
|
877
|
+
showMetadata={showMetadata}
|
|
775
878
|
/>
|
|
776
879
|
);
|
|
777
880
|
}
|
|
@@ -808,7 +911,10 @@ export function FileDisplay({
|
|
|
808
911
|
showFallback,
|
|
809
912
|
generateFallbackText,
|
|
810
913
|
fallbackText,
|
|
811
|
-
|
|
914
|
+
fallbackSourceText,
|
|
915
|
+
fallbackSize,
|
|
916
|
+
enableChildren,
|
|
917
|
+
showMetadata
|
|
812
918
|
}: FileDisplayProps) {
|
|
813
919
|
// Check which context we're in and route to the appropriate component
|
|
814
920
|
const isPublicPage = useIsPublicPage();
|
|
@@ -830,7 +936,10 @@ export function FileDisplay({
|
|
|
830
936
|
showFallback={showFallback}
|
|
831
937
|
generateFallbackText={generateFallbackText}
|
|
832
938
|
fallbackText={fallbackText}
|
|
939
|
+
fallbackSourceText={fallbackSourceText}
|
|
833
940
|
fallbackSize={fallbackSize}
|
|
941
|
+
enableChildren={enableChildren}
|
|
942
|
+
showMetadata={showMetadata}
|
|
834
943
|
/>
|
|
835
944
|
);
|
|
836
945
|
}
|
|
@@ -852,7 +961,10 @@ export function FileDisplay({
|
|
|
852
961
|
showFallback={showFallback}
|
|
853
962
|
generateFallbackText={generateFallbackText}
|
|
854
963
|
fallbackText={fallbackText}
|
|
964
|
+
fallbackSourceText={fallbackSourceText}
|
|
855
965
|
fallbackSize={fallbackSize}
|
|
966
|
+
enableChildren={enableChildren}
|
|
967
|
+
showMetadata={showMetadata}
|
|
856
968
|
/>
|
|
857
969
|
);
|
|
858
970
|
}
|