@jmruthers/pace-core 0.5.106 → 0.5.108
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-BE0OXZKQ.d.ts → DataTable-D5cBRca8.d.ts} +1 -1
- package/dist/{DataTable-LWHFLTEW.js → DataTable-WFCHVWTY.js} +3 -3
- package/dist/{PublicLoadingSpinner-48ewSMKK.d.ts → PublicLoadingSpinner-DgDWTFqn.d.ts} +4 -2
- package/dist/{chunk-QPCAGLUS.js → chunk-4OX5PXHX.js} +5 -2
- package/dist/chunk-4OX5PXHX.js.map +1 -0
- package/dist/{chunk-IBZBNBTE.js → chunk-B3QX32P5.js} +177 -54
- package/dist/chunk-B3QX32P5.js.map +1 -0
- package/dist/{chunk-75G3NZWN.js → chunk-IMZGJ2X7.js} +373 -95
- package/dist/chunk-IMZGJ2X7.js.map +1 -0
- package/dist/{chunk-4BWGRQBG.js → chunk-NFPV7MRN.js} +22 -2
- package/dist/chunk-NFPV7MRN.js.map +1 -0
- package/dist/components.d.ts +4 -4
- package/dist/components.js +3 -3
- package/dist/{formatting-BfDeV-ja.d.ts → formatting-BiEv5oEk.d.ts} +32 -2
- package/dist/hooks.d.ts +2 -2
- package/dist/hooks.js +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +4 -4
- package/dist/{types-BDg1mAGG.d.ts → types-D4TVpDa1.d.ts} +24 -1
- package/dist/{useToast-Bm6TnSK-.d.ts → useToast-DRah6K-g.d.ts} +5 -2
- package/dist/utils.d.ts +3 -3
- package/dist/utils.js +2 -2
- 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 +4 -4
- 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 +18 -18
- package/docs/api/interfaces/DataTableColumn.md +115 -10
- package/docs/api/interfaces/DataTableProps.md +38 -38
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EnhancedNavigationMenuProps.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/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 +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 +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 +42 -19
- package/docs/api-reference/utilities.md +26 -3
- package/docs/implementation-guides/data-tables.md +390 -0
- package/package.json +1 -1
- package/src/components/DataTable/DataTable.tsx +4 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +25 -10
- package/src/components/DataTable/components/ColumnFilter.tsx +2 -1
- package/src/components/DataTable/components/EditableRow.tsx +179 -16
- package/src/components/DataTable/components/FilterRow.tsx +22 -11
- package/src/components/DataTable/components/PaginationControls.tsx +1 -1
- package/src/components/DataTable/components/UnifiedTableBody.tsx +231 -32
- package/src/components/DataTable/types.ts +34 -4
- package/src/components/FileDisplay/FileDisplay.test.tsx +184 -201
- package/src/components/FileDisplay/FileDisplay.tsx +40 -39
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +189 -13
- package/src/components/NavigationMenu/NavigationMenu.tsx +142 -35
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +79 -10
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +4 -4
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/hooks/useEventTheme.test.ts +11 -0
- package/src/hooks/useSecureDataAccess.test.ts +22 -5
- package/src/hooks/useToast.ts +11 -2
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +67 -3
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +72 -4
- package/src/services/__tests__/OrganisationService.pagination.test.ts +10 -2
- package/src/styles/core.css +11 -0
- package/src/utils/__tests__/formatting.unit.test.ts +33 -0
- package/src/utils/file-reference.test.ts +44 -5
- package/src/utils/formatting.ts +57 -2
- package/src/validation/__tests__/passwordSchema.unit.test.ts +3 -3
- package/dist/chunk-4BWGRQBG.js.map +0 -1
- package/dist/chunk-75G3NZWN.js.map +0 -1
- package/dist/chunk-IBZBNBTE.js.map +0 -1
- package/dist/chunk-QPCAGLUS.js.map +0 -1
- /package/dist/{DataTable-LWHFLTEW.js.map → DataTable-WFCHVWTY.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React__default from 'react';
|
|
3
|
-
import { D as DataRecord, a as DataTableColumn, b as DataTableRBACConfig, c as DataTableFeatureConfig, H as HierarchicalConfig, P as PerformanceConfig, S as ServerSideConfig, d as PaginationMode, C as ChunkingConfig, e as SearchIndexConfig, G as GetRowId, E as EmptyStateConfig, A as AggregateConfig, f as DataTableAction } from './types-
|
|
3
|
+
import { D as DataRecord, a as DataTableColumn, b as DataTableRBACConfig, c as DataTableFeatureConfig, H as HierarchicalConfig, P as PerformanceConfig, S as ServerSideConfig, d as PaginationMode, C as ChunkingConfig, e as SearchIndexConfig, G as GetRowId, E as EmptyStateConfig, A as AggregateConfig, f as DataTableAction } from './types-D4TVpDa1.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Configuration interface for customizing ImportModal text content
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
sortHierarchicalDataWithSorting,
|
|
55
55
|
validateHierarchicalData,
|
|
56
56
|
validatePaginationConfig
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-IMZGJ2X7.js";
|
|
58
58
|
import "./chunk-QDDUU625.js";
|
|
59
59
|
import "./chunk-S63MFSY6.js";
|
|
60
60
|
import "./chunk-Q7APDV6H.js";
|
|
@@ -75,7 +75,7 @@ import {
|
|
|
75
75
|
safeExecute,
|
|
76
76
|
throttle,
|
|
77
77
|
useDataTablePerformance
|
|
78
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-4OX5PXHX.js";
|
|
79
79
|
import "./chunk-ZXY5NTJB.js";
|
|
80
80
|
import "./chunk-KBG34SVL.js";
|
|
81
81
|
import "./chunk-X4FRXJV6.js";
|
|
@@ -157,4 +157,4 @@ export {
|
|
|
157
157
|
validateHierarchicalData,
|
|
158
158
|
validatePaginationConfig
|
|
159
159
|
};
|
|
160
|
-
//# sourceMappingURL=DataTable-
|
|
160
|
+
//# sourceMappingURL=DataTable-WFCHVWTY.js.map
|
|
@@ -2329,7 +2329,7 @@ interface PaceAppLayoutProps {
|
|
|
2329
2329
|
*
|
|
2330
2330
|
*
|
|
2331
2331
|
* @example
|
|
2332
|
-
* Custom navigation items with permission filtering:
|
|
2332
|
+
* Custom navigation items with permission filtering (works independently of route enforcement):
|
|
2333
2333
|
* ```tsx
|
|
2334
2334
|
* import { NavigationItem } from '@jmruthers/pace-core';
|
|
2335
2335
|
*
|
|
@@ -2347,13 +2347,15 @@ interface PaceAppLayoutProps {
|
|
|
2347
2347
|
* <PaceAppLayout
|
|
2348
2348
|
* appName="My Custom App"
|
|
2349
2349
|
* navItems={customNavItems}
|
|
2350
|
-
* enforcePermissions
|
|
2350
|
+
* // Navigation filtering works independently - no need for enforcePermissions
|
|
2351
2351
|
* filterNavigationByPermissions={true}
|
|
2352
2352
|
* routePermissions={{
|
|
2353
2353
|
* '/components': 'read',
|
|
2354
2354
|
* '/styles': 'read',
|
|
2355
2355
|
* '/meals': 'read'
|
|
2356
2356
|
* }}
|
|
2357
|
+
* // Optionally enable route-level enforcement (separate from navigation filtering)
|
|
2358
|
+
* // enforcePermissions={true}
|
|
2357
2359
|
* />
|
|
2358
2360
|
* }>
|
|
2359
2361
|
* <Route path="components" element={<ComponentsPage />} />
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
var TOAST_LIMIT = 5;
|
|
4
4
|
var TOAST_REMOVE_DELAY = 1e3;
|
|
5
|
+
var DEFAULT_TOAST_DURATION = 1e4;
|
|
5
6
|
var toastTimeouts = /* @__PURE__ */ new Map();
|
|
6
7
|
var memoryState = {
|
|
7
8
|
toasts: []
|
|
@@ -71,17 +72,19 @@ function reducer(state, action) {
|
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
|
-
function toast({ ...props }) {
|
|
75
|
+
function toast({ duration, ...props }) {
|
|
75
76
|
const id = genId();
|
|
76
77
|
const update = (props2) => dispatch({
|
|
77
78
|
type: "UPDATE_TOAST",
|
|
78
79
|
toast: { ...props2, id }
|
|
79
80
|
});
|
|
80
81
|
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
|
|
82
|
+
const toastDuration = duration ?? DEFAULT_TOAST_DURATION;
|
|
81
83
|
dispatch({
|
|
82
84
|
type: "ADD_TOAST",
|
|
83
85
|
toast: {
|
|
84
86
|
...props,
|
|
87
|
+
duration: toastDuration,
|
|
85
88
|
id,
|
|
86
89
|
open: true,
|
|
87
90
|
dismiss,
|
|
@@ -614,4 +617,4 @@ export {
|
|
|
614
617
|
safeExecute,
|
|
615
618
|
useDataTablePerformance
|
|
616
619
|
};
|
|
617
|
-
//# sourceMappingURL=chunk-
|
|
620
|
+
//# sourceMappingURL=chunk-4OX5PXHX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useToast.ts","../src/components/DataTable/utils/performanceUtils.ts","../src/components/DataTable/utils/errorHandling.ts","../src/hooks/useDataTablePerformance.ts"],"sourcesContent":["\n/**\n * @file Toast hook for managing toast notifications\n * @package @jmruthers/pace-core\n * @module Hooks\n * @since 0.1.0\n * \n * Toast notifications automatically dismiss after 10 seconds by default.\n * You can customize the duration by providing a `duration` prop (in milliseconds).\n */\n\nimport * as React from \"react\"\n\n/** Maximum number of toasts to show at once */\nconst TOAST_LIMIT = 5\n/** Delay before removing a dismissed toast */\nconst TOAST_REMOVE_DELAY = 1000\n/** Default duration for auto-dismissing toasts (10 seconds) */\nconst DEFAULT_TOAST_DURATION = 10000\n\nexport interface ToastProps {\n title?: React.ReactNode;\n description?: React.ReactNode;\n variant?: 'default' | 'destructive' | 'success';\n duration?: number;\n onClose?: () => void;\n action?: React.ReactElement;\n}\n\n/**\n * Extended toast props with additional properties\n * @interface ToasterToast\n */\ntype ToasterToast = ToastProps & {\n /** Unique identifier for the toast */\n id: string\n /** Optional title content */\n title?: React.ReactNode\n /** Optional description content */\n description?: React.ReactNode\n /** Optional action button */\n action?: React.ReactElement\n /** Open state */\n open?: boolean\n /** Open change handler */\n onOpenChange?: (open: boolean) => void\n /** Dismiss function */\n dismiss?: () => void\n}\n\n/**\n * State interface for toast management\n */\ninterface State {\n /** Array of active toasts */\n toasts: ToasterToast[]\n}\n\n/** Map of toast IDs to their removal timeouts */\nconst toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()\n\n/** Current toast state */\nlet memoryState: State = {\n toasts: [],\n}\n\n/** List of state change listeners */\nconst listeners: Array<(state: State) => void> = []\n\n/**\n * Reset the toast state and clear all timeouts\n */\nexport function reset() {\n memoryState = { toasts: [] }\n toastTimeouts.forEach((timeout) => clearTimeout(timeout))\n toastTimeouts.clear()\n}\n\n/**\n * Dispatch a state change\n * @param action - Action to dispatch\n */\nfunction dispatch(action: {\n type: \"ADD_TOAST\" | \"UPDATE_TOAST\" | \"DISMISS_TOAST\" | \"REMOVE_TOAST\"\n toast?: ToasterToast\n toastId?: string\n}) {\n memoryState = reducer(memoryState, action)\n listeners.forEach((listener) => {\n listener(memoryState)\n })\n}\n\n/**\n * Generate a unique ID for a toast\n * @returns Unique ID string\n */\nfunction genId() {\n return Math.random().toString(36).substring(2, 9)\n}\n\n/**\n * Add a toast to the removal queue\n * @param toastId - ID of the toast to remove\n */\nconst addToRemoveQueue = (toastId: string) => {\n if (toastTimeouts.has(toastId)) {\n return\n }\n\n const timeout = setTimeout(() => {\n toastTimeouts.delete(toastId)\n dispatch({\n type: \"REMOVE_TOAST\",\n toastId: toastId,\n })\n }, TOAST_REMOVE_DELAY)\n\n toastTimeouts.set(toastId, timeout)\n}\n\n/**\n * State reducer for toast management\n * @param state - Current state\n * @param action - Action to process\n * @returns New state\n */\nfunction reducer(state: State, action: {\n type: \"ADD_TOAST\" | \"UPDATE_TOAST\" | \"DISMISS_TOAST\" | \"REMOVE_TOAST\"\n toast?: ToasterToast\n toastId?: string\n}): State {\n switch (action.type) {\n case \"ADD_TOAST\":\n return {\n ...state,\n toasts: [action.toast!, ...state.toasts].slice(0, TOAST_LIMIT),\n }\n\n case \"UPDATE_TOAST\":\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === action.toast?.id ? { ...t, ...action.toast } : t\n ),\n }\n\n case \"DISMISS_TOAST\": {\n const { toastId } = action\n\n if (toastId) {\n addToRemoveQueue(toastId)\n }\n\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === toastId || toastId === undefined\n ? {\n ...t,\n open: false,\n }\n : t\n ),\n }\n }\n\n case \"REMOVE_TOAST\":\n if (action.toastId === undefined) {\n return {\n ...state,\n toasts: [],\n }\n }\n return {\n ...state,\n toasts: state.toasts.filter((t) => t.id !== action.toastId),\n }\n }\n}\n\n/**\n * Toast configuration without ID\n */\ntype Toast = Omit<ToasterToast, \"id\">\n\n/**\n * Creates a new toast notification\n * @param props - Toast configuration. Duration defaults to 10 seconds (10000ms) if not provided.\n * @returns Object with toast ID and control methods\n */\nfunction toast({ duration, ...props }: Toast) {\n const id = genId()\n\n const update = (props: Partial<Omit<ToasterToast, \"id\">>) =>\n dispatch({\n type: \"UPDATE_TOAST\",\n toast: { ...props, id },\n })\n const dismiss = () => dispatch({ type: \"DISMISS_TOAST\", toastId: id })\n\n // Use provided duration or default to 10 seconds\n const toastDuration = duration ?? DEFAULT_TOAST_DURATION\n\n dispatch({\n type: \"ADD_TOAST\",\n toast: {\n ...props,\n duration: toastDuration,\n id,\n open: true,\n dismiss,\n onOpenChange: (open) => {\n if (!open) dismiss()\n },\n },\n })\n\n return {\n id: id,\n dismiss,\n update,\n }\n}\n\n/**\n * Hook for managing toast notifications\n * @returns Object with toast state and control methods\n */\nfunction useToast() {\n const [state, setState] = React.useState<State>(memoryState)\n\n React.useEffect(() => {\n listeners.push(setState)\n return () => {\n const index = listeners.indexOf(setState)\n if (index > -1) {\n listeners.splice(index, 1)\n }\n }\n }, [state])\n\n return {\n ...state,\n toast,\n dismiss: (toastId?: string) => dispatch({ type: \"DISMISS_TOAST\", toastId }),\n }\n}\n\nexport { useToast, toast }\nexport type { ToasterToast }\n","/**\n * @file Performance Utilities for DataTable\n * @package @jmruthers/pace-core\n * @module Components/DataTable/Utils/Performance\n * @since 0.3.0\n */\n\nimport type { \n DataRecord, \n PaginationMode, \n ChunkingConfig, \n SearchIndexConfig\n} from '../types';\n\n// ============================================================================\n// PAGINATION MODE DETECTION\n// ============================================================================\n\n/**\n * Determines the optimal pagination mode based on dataset size\n * \n * IMPORTANT: This function NEVER returns 'server' mode - it only returns 'client' or 'hybrid'.\n * Server mode should ONLY be used when serverSide config is explicitly provided.\n * Returning 'server' without serverSide config breaks pagination because TanStack Table\n * expects pre-paginated data but receives all client-side data.\n * \n * For large datasets (>10k rows), returns 'hybrid' which still uses client-side pagination\n * but with optimizations. If true server-side pagination is needed, serverSide config must be provided.\n */\nexport function determinePaginationMode(\n dataLength: number,\n serverSideThreshold: number = 10000\n): 'client' | 'hybrid' {\n if (dataLength <= 1000) return 'client';\n // Even for very large datasets, use 'hybrid' mode (client-side pagination with optimizations)\n // unless serverSide config is explicitly provided (handled in useDataTablePerformance)\n return 'hybrid';\n}\n\n/**\n * Gets optimal page size options based on pagination mode and dataset size\n */\nexport function getOptimalPageSizeOptions(\n mode: PaginationMode,\n dataLength: number\n): number[] {\n switch (mode) {\n case 'client':\n return dataLength <= 100 ? [10, 25, 50] : [10, 25, 50, 100];\n case 'hybrid':\n return [50, 100, 250, 500];\n case 'server':\n return [25, 50, 100, 250];\n default:\n return [10, 25, 50, 100];\n }\n}\n\n// ============================================================================\n// DATA CHUNKING\n// ============================================================================\n\n/**\n * Splits data into chunks for memory management\n */\nexport function chunkData<TData extends DataRecord>(\n data: TData[],\n chunkSize: number\n): TData[][] {\n const chunks: TData[][] = [];\n for (let i = 0; i < data.length; i += chunkSize) {\n chunks.push(data.slice(i, i + chunkSize));\n }\n return chunks;\n}\n\n/**\n * Manages data chunks with LRU cache\n */\nexport class DataChunkManager<TData extends DataRecord> {\n private chunks: Map<number, TData[]> = new Map();\n private accessOrder: number[] = [];\n private maxChunks: number;\n private chunkSize: number;\n\n constructor(config: ChunkingConfig) {\n this.maxChunks = config.maxChunksInMemory;\n this.chunkSize = config.chunkSize;\n }\n\n getChunk(chunkIndex: number, allData: TData[]): TData[] {\n // Check if chunk is already in memory\n if (this.chunks.has(chunkIndex)) {\n this.updateAccessOrder(chunkIndex);\n return this.chunks.get(chunkIndex)!;\n }\n\n // Calculate chunk bounds\n const startIndex = chunkIndex * this.chunkSize;\n const endIndex = Math.min(startIndex + this.chunkSize, allData.length);\n const chunk = allData.slice(startIndex, endIndex);\n\n // Add chunk to memory\n this.addChunk(chunkIndex, chunk);\n return chunk;\n }\n\n private addChunk(chunkIndex: number, chunk: TData[]): void {\n // Remove oldest chunk if at capacity\n if (this.chunks.size >= this.maxChunks && !this.chunks.has(chunkIndex)) {\n const oldestChunk = this.accessOrder.shift();\n if (oldestChunk !== undefined) {\n this.chunks.delete(oldestChunk);\n }\n }\n\n this.chunks.set(chunkIndex, chunk);\n this.updateAccessOrder(chunkIndex);\n }\n\n private updateAccessOrder(chunkIndex: number): void {\n const existingIndex = this.accessOrder.indexOf(chunkIndex);\n if (existingIndex > -1) {\n this.accessOrder.splice(existingIndex, 1);\n }\n this.accessOrder.push(chunkIndex);\n }\n\n clear(): void {\n this.chunks.clear();\n this.accessOrder = [];\n }\n\n getMemoryUsage(): number {\n let totalSize = 0;\n for (const chunk of this.chunks.values()) {\n totalSize += JSON.stringify(chunk).length;\n }\n return totalSize / (1024 * 1024); // Convert to MB\n }\n}\n\n// ============================================================================\n// SEARCH INDEXING\n// ============================================================================\n\n/**\n * Creates a search index for fast text searching\n */\nexport class SearchIndex<TData extends DataRecord> {\n private index: Map<string, Set<number>> = new Map();\n private data: TData[] = [];\n private indexedFields: string[];\n private fuzzySearch: boolean;\n private fuzzyThreshold: number;\n\n constructor(config: SearchIndexConfig) {\n this.indexedFields = config.indexedFields;\n this.fuzzySearch = config.fuzzySearch ?? false;\n this.fuzzyThreshold = config.fuzzyThreshold ?? 0.6;\n }\n\n buildIndex(data: TData[]): void {\n this.data = data;\n this.index.clear();\n\n data.forEach((row, rowIndex) => {\n this.indexedFields.forEach(field => {\n const value = this.getNestedValue(row, field);\n if (value != null) {\n const searchableText = String(value).toLowerCase();\n const words = this.tokenize(searchableText);\n \n words.forEach(word => {\n if (!this.index.has(word)) {\n this.index.set(word, new Set());\n }\n this.index.get(word)!.add(rowIndex);\n });\n }\n });\n });\n }\n\n search(query: string): number[] {\n if (!query.trim()) return [];\n\n const searchTerms = this.tokenize(query.toLowerCase());\n const matchingSets: Set<number>[] = [];\n\n searchTerms.forEach(term => {\n const matches = new Set<number>();\n \n // Exact matches\n if (this.index.has(term)) {\n this.index.get(term)!.forEach(index => matches.add(index));\n }\n\n // Fuzzy matches\n if (this.fuzzySearch) {\n for (const [indexedTerm, indices] of this.index.entries()) {\n if (this.calculateSimilarity(term, indexedTerm) >= this.fuzzyThreshold) {\n indices.forEach(index => matches.add(index));\n }\n }\n }\n\n matchingSets.push(matches);\n });\n\n // Find intersection of all matching sets\n if (matchingSets.length === 0) return [];\n \n let result = matchingSets[0];\n for (let i = 1; i < matchingSets.length; i++) {\n result = new Set([...result].filter(x => matchingSets[i].has(x)));\n }\n\n return Array.from(result);\n }\n\n private getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj);\n }\n\n private tokenize(text: string): string[] {\n return text\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter(word => word.length > 0);\n }\n\n private calculateSimilarity(str1: string, str2: string): number {\n const longer = str1.length > str2.length ? str1 : str2;\n const shorter = str1.length > str2.length ? str2 : str1;\n \n if (longer.length === 0) return 1.0;\n \n const editDistance = this.levenshteinDistance(longer, shorter);\n return (longer.length - editDistance) / longer.length;\n }\n\n private levenshteinDistance(str1: string, str2: string): number {\n const matrix = Array(str2.length + 1).fill(null).map(() => \n Array(str1.length + 1).fill(null)\n );\n\n for (let i = 0; i <= str1.length; i++) matrix[0][i] = i;\n for (let j = 0; j <= str2.length; j++) matrix[j][0] = j;\n\n for (let j = 1; j <= str2.length; j++) {\n for (let i = 1; i <= str1.length; i++) {\n const substitutionCost = str1[i - 1] === str2[j - 1] ? 0 : 1;\n matrix[j][i] = Math.min(\n matrix[j][i - 1] + 1, // insertion\n matrix[j - 1][i] + 1, // deletion\n matrix[j - 1][i - 1] + substitutionCost // substitution\n );\n }\n }\n\n return matrix[str2.length][str1.length];\n }\n}\n\n\n// ============================================================================\n// DEBOUNCE UTILITIES\n// ============================================================================\n\n/**\n * Creates a debounced function\n */\nexport function debounce<T extends (...args: any[]) => any>(\n func: T,\n delay: number\n): (...args: Parameters<T>) => void {\n let timeoutId: NodeJS.Timeout;\n \n return (...args: Parameters<T>) => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => func(...args), delay);\n };\n}\n\n/**\n * Creates a throttled function\n */\nexport function throttle<T extends (...args: any[]) => any>(\n func: T,\n delay: number\n): (...args: Parameters<T>) => void {\n let lastCall = 0;\n \n return (...args: Parameters<T>) => {\n const now = Date.now();\n if (now - lastCall >= delay) {\n lastCall = now;\n func(...args);\n }\n };\n}\n\n// ============================================================================\n// MEMORY MANAGEMENT\n// ============================================================================\n\n/**\n * Intersection Observer for tracking visible rows\n */\nexport class VisibilityTracker {\n private observer: IntersectionObserver | null = null;\n private visibleElements = new Set<Element>();\n private callbacks = new Set<(visibleCount: number) => void>();\n\n constructor() {\n if (typeof IntersectionObserver !== 'undefined') {\n this.observer = new IntersectionObserver(\n (entries) => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n this.visibleElements.add(entry.target);\n } else {\n this.visibleElements.delete(entry.target);\n }\n });\n \n this.callbacks.forEach(callback => {\n callback(this.visibleElements.size);\n });\n },\n { threshold: 0.1 }\n );\n }\n }\n\n observe(element: Element): void {\n this.observer?.observe(element);\n }\n\n unobserve(element: Element): void {\n this.observer?.unobserve(element);\n this.visibleElements.delete(element);\n }\n\n onVisibilityChange(callback: (visibleCount: number) => void): () => void {\n this.callbacks.add(callback);\n return () => this.callbacks.delete(callback);\n }\n\n getVisibleCount(): number {\n return this.visibleElements.size;\n }\n\n destroy(): void {\n this.observer?.disconnect();\n this.visibleElements.clear();\n this.callbacks.clear();\n }\n} ","/**\n * @file Error Handling Stubs\n * @package @jmruthers/pace-core\n * @module Components/DataTable/Utils/Stubs\n * \n * Minimal stubs for removed error handling utilities.\n * This file exists only to prevent import errors in useDataTablePerformance.\n */\n\nexport interface FallbackConfig {\n enabled: boolean;\n}\n\nexport const DEFAULT_FALLBACK_CONFIG: FallbackConfig = {\n enabled: false\n};\n\nexport enum DataTableErrorType {\n VIRTUALIZATION = 'virtualization',\n SEARCH_INDEX = 'search_index',\n DATA_CHUNK = 'data_chunk',\n SERVER_FETCH = 'server_fetch',\n MEMORY = 'memory'\n}\n\nexport class DataTableError extends Error {\n constructor(\n message: string,\n public type: DataTableErrorType,\n public recoverable: boolean = true\n ) {\n super(message);\n this.name = 'DataTableError';\n }\n}\n\nexport class ErrorRecoveryManager {\n constructor(private config: FallbackConfig) {}\n \n async handleError(error: DataTableError) {\n return { recovered: false, strategy: null };\n }\n \n clearErrorLog(): void {\n // Stub method\n }\n}\n\nexport class MemoryMonitor {\n constructor(private threshold: number = 100) {}\n \n getCurrentUsage(): number {\n return 0;\n }\n \n checkThreshold(): boolean {\n return true;\n }\n \n stopMonitoring(): void {\n // Stub method\n }\n}\n\nexport class CircuitBreaker {\n constructor() {}\n \n isOpen(): boolean {\n return false;\n }\n \n recordSuccess(): void {}\n \n recordFailure(): void {}\n \n reset(): void {}\n}\n\nexport function safeExecute<T>(fn: () => T, fallback: T): T {\n try {\n return fn();\n } catch {\n return fallback;\n }\n}\n\n","/**\n * @file DataTable Performance Hook\n * @package @jmruthers/pace-core\n * @module Hooks/DataTablePerformance\n * @since 0.3.0\n */\n\nimport { useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport type { \n DataRecord,\n PaginationMode,\n PerformanceConfig,\n ServerSideConfig,\n ServerSideParams,\n ServerSideResponse,\n ChunkingConfig,\n SearchIndexConfig,\n} from '../components/DataTable/types';\nimport {\n determinePaginationMode,\n getOptimalPageSizeOptions,\n DataChunkManager,\n SearchIndex,\n debounce,\n VisibilityTracker\n} from '../components/DataTable/utils/performanceUtils';\nimport {\n ErrorRecoveryManager,\n DataTableError,\n DataTableErrorType,\n safeExecute,\n MemoryMonitor,\n CircuitBreaker,\n DEFAULT_FALLBACK_CONFIG,\n type FallbackConfig\n} from '../components/DataTable/utils/errorHandling';\n\nexport interface UseDataTablePerformanceOptions<TData extends DataRecord> {\n data: TData[];\n performance?: PerformanceConfig;\n serverSide?: ServerSideConfig<TData>;\n chunking?: ChunkingConfig;\n searchIndex?: SearchIndexConfig;\n // Enhanced error handling options\n fallbackConfig?: FallbackConfig;\n onError?: (error: DataTableError) => void;\n enableErrorRecovery?: boolean;\n}\n\nexport interface UseDataTablePerformanceReturn<TData extends DataRecord> {\n // Performance state\n paginationMode: PaginationMode;\n isVirtualized: boolean;\n pageSizeOptions: number[];\n \n // Data management\n processedData: TData[];\n totalCount: number;\n isLoading: boolean;\n \n // Search functionality\n searchQuery: string;\n setSearchQuery: (query: string) => void;\n searchResults: number[];\n \n // Server-side functionality\n fetchServerData: (params: ServerSideParams) => Promise<void>;\n serverData: ServerSideResponse<TData> | null;\n \n // Performance monitoring\n memoryUsage: number;\n \n // Error handling and recovery\n errorState: {\n hasErrors: boolean;\n errorCount: number;\n lastError: DataTableError | null;\n fallbacksActive: string[];\n };\n retryLastOperation: () => Promise<void>;\n clearErrors: () => void;\n \n // Cleanup\n cleanup: () => void;\n}\n\n/**\n * Hook for managing DataTable performance optimizations\n */\nexport function useDataTablePerformance<TData extends DataRecord>({\n data,\n performance = {},\n serverSide,\n chunking,\n searchIndex,\n fallbackConfig = DEFAULT_FALLBACK_CONFIG,\n onError,\n enableErrorRecovery = true\n}: UseDataTablePerformanceOptions<TData>): UseDataTablePerformanceReturn<TData> {\n // ============================================================================\n // STATE MANAGEMENT\n // ============================================================================\n \n const [isLoading, setIsLoading] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n const [searchResults, setSearchResults] = useState<number[]>([]);\n const [serverData, setServerData] = useState<ServerSideResponse<TData> | null>(null);\n const [memoryUsage, setMemoryUsage] = useState(0);\n \n // Error handling state\n const [errorState, setErrorState] = useState({\n hasErrors: false,\n errorCount: 0,\n lastError: null as DataTableError | null,\n fallbacksActive: [] as string[],\n });\n const [lastFailedOperation, setLastFailedOperation] = useState<(() => Promise<any>) | null>(null);\n\n // ============================================================================\n // REFS AND MANAGERS\n // ============================================================================\n \n const chunkManagerRef = useRef<DataChunkManager<TData> | null>(null);\n const searchIndexRef = useRef<SearchIndex<TData> | null>(null);\n const visibilityTrackerRef = useRef<VisibilityTracker | null>(null);\n \n // Error handling managers\n const errorRecoveryManagerRef = useRef<ErrorRecoveryManager>(new ErrorRecoveryManager(fallbackConfig));\n const memoryMonitorRef = useRef<MemoryMonitor | null>(null);\n const circuitBreakerRef = useRef<CircuitBreaker>(new CircuitBreaker());\n\n // ============================================================================\n // COMPUTED VALUES\n // ============================================================================\n \n const paginationMode = useMemo(() => {\n // CRITICAL FIX: Only use 'server' mode if serverSide config is explicitly provided.\n // determinePaginationMode now never returns 'server' - it only returns 'client' or 'hybrid'.\n // This fixes pagination issues where large datasets would auto-detect 'server' mode\n // but have no serverSide config, causing pagination controls to break.\n if (serverSide) return 'server';\n return determinePaginationMode(data?.length || 0, performance.serverSideThreshold);\n }, [data?.length, performance.serverSideThreshold, serverSide]);\n\n // Virtualization is now handled internally by UnifiedTableBody\n const isVirtualized = false;\n\n const pageSizeOptions = useMemo(() => {\n return getOptimalPageSizeOptions(paginationMode, data?.length || 0);\n }, [paginationMode, data?.length]);\n\n // ============================================================================\n // DATA PROCESSING\n // ============================================================================\n \n const processedData = useMemo(() => {\n if (serverSide && serverData) {\n return serverData.data;\n }\n\n let filteredData = data;\n \n // Apply search filtering - ensure we don't exclude zero values\n if (searchQuery && searchResults.length > 0) {\n filteredData = searchResults.map(index => data[index]);\n }\n\n // Important: Ensure we don't accidentally filter out rows with zero values\n // This was causing \"no data\" issues when rows contained zero values in numeric columns\n // The filtering should be explicit, not implicit based on falsy values\n\n return filteredData;\n }, [data, serverData, searchQuery, searchResults, serverSide]);\n\n const totalCount = useMemo(() => {\n if (serverSide && serverData) {\n return serverData.totalCount;\n }\n return processedData?.length || 0;\n }, [serverData, processedData?.length, serverSide]);\n\n // ============================================================================\n // CHUNK MANAGEMENT\n // ============================================================================\n \n useEffect(() => {\n if (chunking && !chunkManagerRef.current) {\n chunkManagerRef.current = new DataChunkManager<TData>(chunking);\n }\n }, [chunking]);\n\n // ============================================================================\n // SEARCH INDEX MANAGEMENT\n // ============================================================================\n \n useEffect(() => {\n if (searchIndex && !searchIndexRef.current) {\n searchIndexRef.current = new SearchIndex<TData>(searchIndex);\n }\n\n if (searchIndexRef.current && data.length > 0) {\n searchIndexRef.current.buildIndex(data);\n }\n }, [searchIndex, data]);\n\n // Debounced search function\n const debouncedSearch = useCallback(\n debounce((query: string) => {\n if (!searchIndexRef.current) return;\n \n if (!query.trim()) {\n setSearchResults([]);\n return;\n }\n\n const results = searchIndexRef.current.search(query);\n setSearchResults(results);\n }, performance.debounceSearch ?? 300),\n [performance.debounceSearch]\n );\n\n // Handle search query changes\n useEffect(() => {\n debouncedSearch(searchQuery);\n }, [searchQuery, debouncedSearch]);\n\n // ============================================================================\n // SERVER-SIDE DATA FETCHING\n // ============================================================================\n \n const fetchServerData = useCallback(async (params: ServerSideParams) => {\n if (!serverSide) return;\n\n setIsLoading(true);\n try {\n const response = await serverSide.fetchData(params);\n setServerData(response);\n } catch (error) {\n console.error('Failed to fetch server data:', error);\n } finally {\n setIsLoading(false);\n }\n }, [serverSide]);\n\n // ============================================================================\n // PERFORMANCE MONITORING\n // ============================================================================\n \n useEffect(() => {\n if (!visibilityTrackerRef.current) {\n visibilityTrackerRef.current = new VisibilityTracker();\n }\n\n const tracker = visibilityTrackerRef.current;\n const unsubscribe = tracker.onVisibilityChange((visibleCount) => {\n // Performance monitoring removed\n });\n\n return unsubscribe;\n }, [totalCount, isVirtualized, paginationMode]);\n\n // Update memory usage\n useEffect(() => {\n const updateMemoryUsage = () => {\n let usage = 0;\n \n if (chunkManagerRef.current) {\n usage += chunkManagerRef.current.getMemoryUsage();\n }\n \n // Add general memory estimation\n usage += (JSON.stringify(processedData || []).length) / (1024 * 1024);\n \n setMemoryUsage(usage);\n };\n\n updateMemoryUsage();\n \n // Only set up interval in non-test environments to prevent memory leaks during testing\n const interval = import.meta.env.MODE !== 'test' \n ? setInterval(updateMemoryUsage, 5000) \n : null;\n \n return () => {\n if (interval) {\n clearInterval(interval);\n }\n };\n }, [processedData]);\n\n // ============================================================================\n // ERROR HANDLING FUNCTIONS\n // ============================================================================\n \n const handleError = useCallback(async (error: DataTableError, operation?: () => Promise<any>) => {\n if (enableErrorRecovery) {\n try {\n const recovery = await errorRecoveryManagerRef.current.handleError(error);\n setErrorState(prev => ({\n hasErrors: true,\n errorCount: prev.errorCount + 1,\n lastError: error,\n fallbacksActive: [...prev.fallbacksActive, error.type],\n }));\n \n if (operation) {\n setLastFailedOperation(() => operation);\n }\n \n onError?.(error);\n return recovery;\n } catch (recoveryError) {\n console.error('Error recovery failed:', recoveryError);\n }\n }\n throw error;\n }, [enableErrorRecovery, onError]);\n\n const retryLastOperation = useCallback(async () => {\n if (lastFailedOperation) {\n try {\n await lastFailedOperation();\n setLastFailedOperation(null);\n setErrorState(prev => ({ ...prev, hasErrors: false }));\n } catch (error) {\n console.error('Retry failed:', error);\n }\n }\n }, [lastFailedOperation]);\n\n const clearErrors = useCallback(() => {\n setErrorState({\n hasErrors: false,\n errorCount: 0,\n lastError: null,\n fallbacksActive: [],\n });\n setLastFailedOperation(null);\n errorRecoveryManagerRef.current.clearErrorLog();\n }, []);\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n \n const cleanup = useCallback(() => {\n chunkManagerRef.current?.clear();\n visibilityTrackerRef.current?.destroy();\n memoryMonitorRef.current?.stopMonitoring();\n }, []);\n\n useEffect(() => {\n return cleanup;\n }, [cleanup]);\n\n // ============================================================================\n // RETURN VALUES\n // ============================================================================\n \n return {\n // Performance state\n paginationMode,\n isVirtualized,\n pageSizeOptions,\n \n // Data management\n processedData,\n totalCount,\n isLoading,\n \n // Search functionality\n searchQuery,\n setSearchQuery,\n searchResults,\n \n // Server-side functionality\n fetchServerData,\n serverData,\n \n // Performance monitoring\n memoryUsage,\n \n // Error handling and recovery\n errorState,\n retryLastOperation,\n clearErrors,\n \n // Cleanup\n cleanup\n };\n} "],"mappings":"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","names":["props","DataTableErrorType","useState","useEffect","useState","useEffect"]}
|
|
@@ -25,7 +25,12 @@ import {
|
|
|
25
25
|
SelectSeparator,
|
|
26
26
|
SelectTrigger,
|
|
27
27
|
SelectValue
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-IMZGJ2X7.js";
|
|
29
|
+
import {
|
|
30
|
+
usePermissions,
|
|
31
|
+
useRBAC,
|
|
32
|
+
useResolvedScope
|
|
33
|
+
} from "./chunk-QDDUU625.js";
|
|
29
34
|
import {
|
|
30
35
|
isPermitted,
|
|
31
36
|
isSuperAdmin
|
|
@@ -47,7 +52,7 @@ import {
|
|
|
47
52
|
} from "./chunk-DMNMZKWS.js";
|
|
48
53
|
import {
|
|
49
54
|
useToast
|
|
50
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-4OX5PXHX.js";
|
|
51
56
|
import {
|
|
52
57
|
useEvents,
|
|
53
58
|
useOrganisations
|
|
@@ -900,34 +905,100 @@ var NavigationMenu = React9.forwardRef(({
|
|
|
900
905
|
} catch (error) {
|
|
901
906
|
console.warn("[NavigationMenu] useUnifiedAuth not available, running in unauthenticated mode");
|
|
902
907
|
}
|
|
908
|
+
let rbacContext = null;
|
|
909
|
+
try {
|
|
910
|
+
rbacContext = useRBAC();
|
|
911
|
+
} catch (error) {
|
|
912
|
+
console.warn("[NavigationMenu] useRBAC not available, permission filtering disabled");
|
|
913
|
+
}
|
|
914
|
+
const { supabase } = authContext || {};
|
|
915
|
+
const { selectedOrganisation } = authContext || {};
|
|
916
|
+
const selectedEvent = authContext?.selectedEvent || null;
|
|
917
|
+
const { resolvedScope, isLoading: scopeLoading } = useResolvedScope({
|
|
918
|
+
supabase: supabase || null,
|
|
919
|
+
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
920
|
+
selectedEventId: selectedEvent?.event_id || null
|
|
921
|
+
});
|
|
922
|
+
const userId = authContext?.user?.id || "";
|
|
923
|
+
const scope = resolvedScope || { organisationId: "", eventId: void 0, appId: void 0 };
|
|
924
|
+
const { permissions: permissionMap, hasAnyPermission, isLoading: permissionsLoading } = usePermissions(
|
|
925
|
+
userId,
|
|
926
|
+
scope
|
|
927
|
+
);
|
|
903
928
|
const filteredItems = React9.useMemo(() => {
|
|
904
|
-
if (!filterByPermissions || !authContext
|
|
929
|
+
if (!filterByPermissions || !authContext || !rbacContext || scopeLoading || permissionsLoading || !resolvedScope?.organisationId) {
|
|
930
|
+
return (items || []).filter((item) => !item.meta?.hidden);
|
|
931
|
+
}
|
|
905
932
|
return (items || []).filter((item) => {
|
|
906
933
|
if (item.meta?.hidden) return false;
|
|
907
934
|
if (item.permissions && item.permissions.length > 0) {
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
935
|
+
const permissions = item.permissions.filter((p) => typeof p === "string").map((p) => p);
|
|
936
|
+
if (permissions.length > 0) {
|
|
937
|
+
const hasPermission = hasAnyPermission(permissions);
|
|
938
|
+
if (!hasPermission) return false;
|
|
939
|
+
}
|
|
913
940
|
}
|
|
914
941
|
if (item.roles && item.roles.length > 0) {
|
|
915
942
|
const hasRole = item.roles.some((role) => {
|
|
916
943
|
if (typeof role !== "string") return true;
|
|
917
|
-
|
|
944
|
+
switch (role.toLowerCase()) {
|
|
945
|
+
case "super_admin":
|
|
946
|
+
case "super admin":
|
|
947
|
+
return rbacContext.isSuperAdmin;
|
|
948
|
+
case "org_admin":
|
|
949
|
+
case "org admin":
|
|
950
|
+
case "admin":
|
|
951
|
+
return rbacContext.isOrgAdmin || rbacContext.isSuperAdmin;
|
|
952
|
+
case "event_admin":
|
|
953
|
+
case "event admin":
|
|
954
|
+
return rbacContext.isEventAdmin || rbacContext.isSuperAdmin;
|
|
955
|
+
default:
|
|
956
|
+
return rbacContext.organisationRole === role || rbacContext.eventAppRole === role || rbacContext.isSuperAdmin;
|
|
957
|
+
}
|
|
918
958
|
});
|
|
919
959
|
if (!hasRole) return false;
|
|
920
960
|
}
|
|
921
961
|
if (item.accessLevel) {
|
|
922
962
|
if (typeof item.accessLevel === "string") {
|
|
923
|
-
const accessLevel = item.accessLevel;
|
|
924
|
-
const
|
|
925
|
-
if (
|
|
963
|
+
const accessLevel = item.accessLevel.toLowerCase();
|
|
964
|
+
const userEventRole = rbacContext.eventAppRole;
|
|
965
|
+
if (rbacContext.isSuperAdmin) {
|
|
966
|
+
} else {
|
|
967
|
+
const roleToAccessLevel = {
|
|
968
|
+
"viewer": "viewer",
|
|
969
|
+
"participant": "participant",
|
|
970
|
+
"planner": "planner",
|
|
971
|
+
"event_admin": "admin"
|
|
972
|
+
};
|
|
973
|
+
const userAccessLevel = userEventRole ? roleToAccessLevel[userEventRole] || "viewer" : null;
|
|
974
|
+
const levelHierarchy = {
|
|
975
|
+
viewer: 1,
|
|
976
|
+
participant: 2,
|
|
977
|
+
planner: 3,
|
|
978
|
+
admin: 4,
|
|
979
|
+
super: 5
|
|
980
|
+
};
|
|
981
|
+
const requiredLevel = levelHierarchy[accessLevel] || 0;
|
|
982
|
+
const userLevel = userAccessLevel ? levelHierarchy[userAccessLevel] || 0 : 0;
|
|
983
|
+
if (userLevel < requiredLevel) {
|
|
984
|
+
return false;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
926
987
|
}
|
|
927
988
|
}
|
|
928
989
|
return true;
|
|
929
990
|
});
|
|
930
|
-
}, [
|
|
991
|
+
}, [
|
|
992
|
+
items,
|
|
993
|
+
filterByPermissions,
|
|
994
|
+
authContext,
|
|
995
|
+
rbacContext,
|
|
996
|
+
permissionMap,
|
|
997
|
+
hasAnyPermission,
|
|
998
|
+
scopeLoading,
|
|
999
|
+
permissionsLoading,
|
|
1000
|
+
resolvedScope
|
|
1001
|
+
]);
|
|
931
1002
|
React9.useEffect(() => {
|
|
932
1003
|
if (auditLog && authContext) {
|
|
933
1004
|
console.log("[NavigationMenu] Navigation access attempt:", {
|
|
@@ -991,17 +1062,30 @@ var NavigationMenu = React9.forwardRef(({
|
|
|
991
1062
|
}
|
|
992
1063
|
const isItemVisible = filteredItems.some((filtered) => filtered.id === item.id);
|
|
993
1064
|
let hasPermission = true;
|
|
994
|
-
if (item.permissions && item.permissions.length > 0) {
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
}
|
|
1065
|
+
if (item.permissions && item.permissions.length > 0 && rbacContext && hasAnyPermission) {
|
|
1066
|
+
const permissions = item.permissions.filter((p) => typeof p === "string").map((p) => p);
|
|
1067
|
+
if (permissions.length > 0) {
|
|
1068
|
+
hasPermission = hasAnyPermission(permissions);
|
|
1069
|
+
}
|
|
999
1070
|
}
|
|
1000
|
-
if (!hasPermission) {
|
|
1071
|
+
if (!hasPermission && rbacContext) {
|
|
1001
1072
|
if (item.roles && item.roles.length > 0) {
|
|
1002
1073
|
hasPermission = item.roles.some((role) => {
|
|
1003
1074
|
if (typeof role !== "string") return true;
|
|
1004
|
-
|
|
1075
|
+
switch (role.toLowerCase()) {
|
|
1076
|
+
case "super_admin":
|
|
1077
|
+
case "super admin":
|
|
1078
|
+
return rbacContext.isSuperAdmin;
|
|
1079
|
+
case "org_admin":
|
|
1080
|
+
case "org admin":
|
|
1081
|
+
case "admin":
|
|
1082
|
+
return rbacContext.isOrgAdmin || rbacContext.isSuperAdmin;
|
|
1083
|
+
case "event_admin":
|
|
1084
|
+
case "event admin":
|
|
1085
|
+
return rbacContext.isEventAdmin || rbacContext.isSuperAdmin;
|
|
1086
|
+
default:
|
|
1087
|
+
return rbacContext.organisationRole === role || rbacContext.eventAppRole === role || rbacContext.isSuperAdmin;
|
|
1088
|
+
}
|
|
1005
1089
|
});
|
|
1006
1090
|
}
|
|
1007
1091
|
}
|
|
@@ -1294,10 +1378,17 @@ function PaceAppLayout({
|
|
|
1294
1378
|
eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,
|
|
1295
1379
|
appId: user.user_metadata?.appId || user.app_metadata?.appId
|
|
1296
1380
|
};
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1381
|
+
try {
|
|
1382
|
+
const { isSuperAdmin: isSuperAdmin2 } = await import("./api-KG4A2X7P.js");
|
|
1383
|
+
const isSuper = await isSuperAdmin2(user.id);
|
|
1384
|
+
if (isSuper) {
|
|
1385
|
+
return true;
|
|
1386
|
+
}
|
|
1387
|
+
} catch (error) {
|
|
1388
|
+
if (error && typeof error === "object" && "code" in error && error.code === "RBAC_NOT_INITIALIZED") {
|
|
1389
|
+
} else {
|
|
1390
|
+
throw error;
|
|
1391
|
+
}
|
|
1301
1392
|
}
|
|
1302
1393
|
if (!scope.organisationId) {
|
|
1303
1394
|
console.warn("No organisation context available for permission check, denying access");
|
|
@@ -1389,12 +1480,44 @@ function PaceAppLayout({
|
|
|
1389
1480
|
}, [enforcePermissions, currentRoutePermission, currentPageId, strictMode, user?.id]);
|
|
1390
1481
|
const [filteredMenuItems, setFilteredMenuItems] = useState5(baseMenuItems);
|
|
1391
1482
|
useEffect3(() => {
|
|
1392
|
-
if (!filterNavigationByPermissions
|
|
1483
|
+
if (!filterNavigationByPermissions) {
|
|
1393
1484
|
setFilteredMenuItems(baseMenuItems);
|
|
1394
1485
|
return;
|
|
1395
1486
|
}
|
|
1396
1487
|
let isMounted = true;
|
|
1397
1488
|
const filterItems = async () => {
|
|
1489
|
+
if (!user?.id) {
|
|
1490
|
+
if (isMounted) {
|
|
1491
|
+
setFilteredMenuItems(baseMenuItems);
|
|
1492
|
+
}
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
const scope = {
|
|
1496
|
+
organisationId: user.user_metadata?.organisationId || user.app_metadata?.organisationId,
|
|
1497
|
+
eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,
|
|
1498
|
+
appId: user.user_metadata?.appId || user.app_metadata?.appId
|
|
1499
|
+
};
|
|
1500
|
+
try {
|
|
1501
|
+
const { isSuperAdmin: isSuperAdmin2 } = await import("./api-KG4A2X7P.js");
|
|
1502
|
+
const isSuper = await isSuperAdmin2(user.id);
|
|
1503
|
+
if (isSuper) {
|
|
1504
|
+
if (isMounted) {
|
|
1505
|
+
setFilteredMenuItems(baseMenuItems);
|
|
1506
|
+
}
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
} catch (error) {
|
|
1510
|
+
if (error && typeof error === "object" && "code" in error && error.code === "RBAC_NOT_INITIALIZED") {
|
|
1511
|
+
} else {
|
|
1512
|
+
throw error;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
if (!scope.organisationId) {
|
|
1516
|
+
if (isMounted) {
|
|
1517
|
+
setFilteredMenuItems(baseMenuItems);
|
|
1518
|
+
}
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1398
1521
|
const filtered = await Promise.all(
|
|
1399
1522
|
baseMenuItems.map(async (item) => {
|
|
1400
1523
|
if (!item.href) return { item, hasAccess: true };
|
|
@@ -1416,7 +1539,7 @@ function PaceAppLayout({
|
|
|
1416
1539
|
return () => {
|
|
1417
1540
|
isMounted = false;
|
|
1418
1541
|
};
|
|
1419
|
-
}, [baseMenuItems, filterNavigationByPermissions,
|
|
1542
|
+
}, [baseMenuItems, filterNavigationByPermissions, pageIdMapping, routePermissions, defaultPermission, checkPermission, user?.id, user?.user_metadata, user?.app_metadata]);
|
|
1420
1543
|
useEffect3(() => {
|
|
1421
1544
|
if (!roleBasedRouting || routeConfig.length === 0) return;
|
|
1422
1545
|
let isMounted = true;
|
|
@@ -3138,17 +3261,16 @@ function FileDisplayContent({
|
|
|
3138
3261
|
const baseClasses = "flex items-center justify-center bg-sec-100 text-sec-600 font-semibold rounded";
|
|
3139
3262
|
return `${baseClasses} ${sizeClass} ${className}`.trim();
|
|
3140
3263
|
}, [fallbackSize, className]);
|
|
3141
|
-
useEffect8(() => {
|
|
3142
|
-
setInternalFileUrls(new Map(fileUrls));
|
|
3143
|
-
}, [fileUrls]);
|
|
3144
3264
|
useEffect8(() => {
|
|
3145
3265
|
const currentIds = fileReferences.map((f) => f.id).join(",");
|
|
3146
3266
|
const prevIds = fileReferencesRef.current.map((f) => f.id).join(",");
|
|
3147
3267
|
if (currentIds !== prevIds) {
|
|
3148
3268
|
fileReferencesRef.current = fileReferences;
|
|
3149
|
-
setInternalFileUrls(
|
|
3269
|
+
setInternalFileUrls(new Map(fileUrls));
|
|
3270
|
+
} else {
|
|
3271
|
+
setInternalFileUrls(new Map(fileUrls));
|
|
3150
3272
|
}
|
|
3151
|
-
}, [fileReferences]);
|
|
3273
|
+
}, [fileReferences, fileUrls]);
|
|
3152
3274
|
const handleDeleteClick = () => {
|
|
3153
3275
|
setDeleteDialogOpen(true);
|
|
3154
3276
|
};
|
|
@@ -3191,6 +3313,28 @@ function FileDisplayContent({
|
|
|
3191
3313
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
3192
3314
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
3193
3315
|
};
|
|
3316
|
+
if (error) {
|
|
3317
|
+
if (ErrorComponent) {
|
|
3318
|
+
return /* @__PURE__ */ jsx22(ErrorComponent, { error, retry: clearError });
|
|
3319
|
+
}
|
|
3320
|
+
if (showFallback) {
|
|
3321
|
+
return /* @__PURE__ */ jsx22("div", { className: fallbackClasses, title: "File unavailable", children: computedFallbackText });
|
|
3322
|
+
}
|
|
3323
|
+
return /* @__PURE__ */ jsxs18("div", { className: `p-4 bg-acc-50 border border-acc-200 rounded-lg ${className}`, children: [
|
|
3324
|
+
/* @__PURE__ */ jsxs18("div", { className: "text-acc-600", children: [
|
|
3325
|
+
"Error loading file: ",
|
|
3326
|
+
error instanceof Error ? error.message : String(error)
|
|
3327
|
+
] }),
|
|
3328
|
+
clearError && /* @__PURE__ */ jsx22(
|
|
3329
|
+
"button",
|
|
3330
|
+
{
|
|
3331
|
+
onClick: clearError,
|
|
3332
|
+
className: "mt-2 text-sm text-acc-700 hover:text-acc-800 underline",
|
|
3333
|
+
children: "Try again"
|
|
3334
|
+
}
|
|
3335
|
+
)
|
|
3336
|
+
] });
|
|
3337
|
+
}
|
|
3194
3338
|
if (fileCount === 0 && !isLoading) {
|
|
3195
3339
|
if (showFallback) {
|
|
3196
3340
|
return /* @__PURE__ */ jsxs18("div", { className: fallbackClasses, title: "No file", children: [
|
|
@@ -3215,28 +3359,6 @@ function FileDisplayContent({
|
|
|
3215
3359
|
}
|
|
3216
3360
|
return /* @__PURE__ */ jsx22("div", { className: `flex items-center justify-center p-4 ${className}`, children: /* @__PURE__ */ jsx22("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-main-500" }) });
|
|
3217
3361
|
}
|
|
3218
|
-
if (error) {
|
|
3219
|
-
if (ErrorComponent) {
|
|
3220
|
-
return /* @__PURE__ */ jsx22(ErrorComponent, { error, retry: clearError });
|
|
3221
|
-
}
|
|
3222
|
-
if (showFallback) {
|
|
3223
|
-
return /* @__PURE__ */ jsx22("div", { className: fallbackClasses, title: "File unavailable", children: computedFallbackText });
|
|
3224
|
-
}
|
|
3225
|
-
return /* @__PURE__ */ jsxs18("div", { className: `p-4 bg-acc-50 border border-acc-200 rounded-lg ${className}`, children: [
|
|
3226
|
-
/* @__PURE__ */ jsxs18("div", { className: "text-acc-600", children: [
|
|
3227
|
-
"Error loading file: ",
|
|
3228
|
-
error instanceof Error ? error.message : String(error)
|
|
3229
|
-
] }),
|
|
3230
|
-
clearError && /* @__PURE__ */ jsx22(
|
|
3231
|
-
"button",
|
|
3232
|
-
{
|
|
3233
|
-
onClick: clearError,
|
|
3234
|
-
className: "mt-2 text-sm text-acc-700 hover:text-acc-800 underline",
|
|
3235
|
-
children: "Try again"
|
|
3236
|
-
}
|
|
3237
|
-
)
|
|
3238
|
-
] });
|
|
3239
|
-
}
|
|
3240
3362
|
if ((category || displayOnly) && fileReference) {
|
|
3241
3363
|
const isImage = fileReference.file_metadata.fileType?.startsWith("image/");
|
|
3242
3364
|
if (displayOnly && isImage && !showDelete) {
|
|
@@ -3547,6 +3669,7 @@ function FileDisplayAuthenticated({
|
|
|
3547
3669
|
className,
|
|
3548
3670
|
children,
|
|
3549
3671
|
onDelete: showDelete ? handleDelete : void 0,
|
|
3672
|
+
clearError: refetch,
|
|
3550
3673
|
organisation_id,
|
|
3551
3674
|
loadingComponent,
|
|
3552
3675
|
errorComponent,
|
|
@@ -4273,4 +4396,4 @@ export {
|
|
|
4273
4396
|
PublicPageDiagnostic,
|
|
4274
4397
|
PublicPageContextChecker
|
|
4275
4398
|
};
|
|
4276
|
-
//# sourceMappingURL=chunk-
|
|
4399
|
+
//# sourceMappingURL=chunk-B3QX32P5.js.map
|