@jmruthers/pace-core 0.5.118 → 0.5.120
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-ZOAKQ3SU.js → DataTable-DGZDJUYM.js} +7 -7
- package/dist/{UnifiedAuthProvider-YFN7YGVN.js → UnifiedAuthProvider-UACKFATV.js} +3 -3
- package/dist/{chunk-7OTQLFVI.js → chunk-B4GZ2BXO.js} +3 -3
- package/dist/{chunk-KA3PSVNV.js → chunk-BHWIUEYH.js} +2 -1
- package/dist/chunk-BHWIUEYH.js.map +1 -0
- package/dist/{chunk-LFS45U62.js → chunk-CGURJ27Z.js} +2 -2
- package/dist/{chunk-PHDAXDHB.js → chunk-D6BOFXYR.js} +3 -3
- package/dist/{chunk-P3PUOL6B.js → chunk-FKFHZUGF.js} +4 -4
- package/dist/{chunk-2GJ5GL77.js → chunk-GKHF54DI.js} +2 -2
- package/dist/chunk-GKHF54DI.js.map +1 -0
- package/dist/{chunk-UKZWNQMB.js → chunk-HFBOFZ3Z.js} +5 -18
- package/dist/chunk-HFBOFZ3Z.js.map +1 -0
- package/dist/{chunk-O3FTRYEU.js → chunk-NZ32EONV.js} +2 -2
- package/dist/{chunk-2LM4QQGH.js → chunk-QPI2CCBA.js} +9 -9
- package/dist/chunk-QPI2CCBA.js.map +1 -0
- package/dist/{chunk-ECOVPXYS.js → chunk-RIEJGKD3.js} +4 -4
- package/dist/{chunk-HIWXXDXO.js → chunk-TDNI6ZWL.js} +5 -5
- package/dist/{chunk-VN3OOE35.js → chunk-ZYJ6O5CA.js} +2 -2
- package/dist/components.d.ts +1 -1
- package/dist/components.js +9 -9
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +8 -8
- package/dist/index.d.ts +1 -1
- package/dist/index.js +12 -12
- package/dist/providers.js +2 -2
- package/dist/rbac/index.js +7 -7
- package/dist/{useToast-Cs_g32bg.d.ts → useToast-C8gR5ir4.d.ts} +2 -2
- package/dist/utils.js +1 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +2 -2
- package/package.json +1 -1
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +697 -0
- package/src/components/DataTable/components/DataTableCore.tsx +5 -0
- package/src/components/DataTable/components/EditableRow.tsx +9 -18
- package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +616 -9
- package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +1004 -0
- package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +612 -0
- package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +266 -0
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +455 -1
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/hooks/__tests__/index.unit.test.ts +223 -0
- package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +748 -0
- package/src/hooks/__tests__/useEvents.unit.test.ts +251 -0
- package/src/hooks/__tests__/useFileDisplay.unit.test.ts +1060 -0
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +958 -0
- package/src/hooks/__tests__/useFocusManagement.unit.test.ts +19 -9
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +540 -1
- package/src/hooks/__tests__/useIsMobile.unit.test.ts +205 -5
- package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +616 -1
- package/src/hooks/__tests__/useOrganisations.unit.test.ts +369 -0
- package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +661 -0
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +2 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +371 -0
- package/src/hooks/__tests__/useToast.unit.test.tsx +449 -30
- package/src/hooks/useSecureDataAccess.test.ts +1 -0
- package/src/hooks/useToast.ts +4 -4
- package/src/rbac/audit-enhanced.ts +339 -0
- package/src/services/EventService.ts +1 -0
- package/src/services/__tests__/AuthService.test.ts +473 -0
- package/src/services/__tests__/EventService.test.ts +390 -0
- package/src/services/__tests__/InactivityService.test.ts +217 -0
- package/src/services/__tests__/OrganisationService.test.ts +371 -0
- package/src/styles/core.css +1 -0
- package/dist/chunk-2GJ5GL77.js.map +0 -1
- package/dist/chunk-2LM4QQGH.js.map +0 -1
- package/dist/chunk-KA3PSVNV.js.map +0 -1
- package/dist/chunk-UKZWNQMB.js.map +0 -1
- package/src/components/DataTable/utils/debugTools.ts +0 -609
- package/src/rbac/testing/index.tsx +0 -340
- /package/dist/{DataTable-ZOAKQ3SU.js.map → DataTable-DGZDJUYM.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-YFN7YGVN.js.map → UnifiedAuthProvider-UACKFATV.js.map} +0 -0
- /package/dist/{chunk-7OTQLFVI.js.map → chunk-B4GZ2BXO.js.map} +0 -0
- /package/dist/{chunk-LFS45U62.js.map → chunk-CGURJ27Z.js.map} +0 -0
- /package/dist/{chunk-PHDAXDHB.js.map → chunk-D6BOFXYR.js.map} +0 -0
- /package/dist/{chunk-P3PUOL6B.js.map → chunk-FKFHZUGF.js.map} +0 -0
- /package/dist/{chunk-O3FTRYEU.js.map → chunk-NZ32EONV.js.map} +0 -0
- /package/dist/{chunk-ECOVPXYS.js.map → chunk-RIEJGKD3.js.map} +0 -0
- /package/dist/{chunk-HIWXXDXO.js.map → chunk-TDNI6ZWL.js.map} +0 -0
- /package/dist/{chunk-VN3OOE35.js.map → chunk-ZYJ6O5CA.js.map} +0 -0
|
@@ -1,609 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Advanced Debugging Tools for DataTable Performance
|
|
3
|
-
* @package @jmruthers/pace-core
|
|
4
|
-
* @module Components/DataTable/Utils/DebugTools
|
|
5
|
-
* @since 0.3.0
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import type {
|
|
10
|
-
DataRecord,
|
|
11
|
-
PaginationMode,
|
|
12
|
-
ServerSideParams
|
|
13
|
-
} from '../types';
|
|
14
|
-
import { createLogger } from '../../../utils/logger';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Debug levels for controlling verbosity
|
|
18
|
-
*/
|
|
19
|
-
export enum DebugLevel {
|
|
20
|
-
NONE = 0,
|
|
21
|
-
ERROR = 1,
|
|
22
|
-
WARN = 2,
|
|
23
|
-
INFO = 3,
|
|
24
|
-
DEBUG = 4,
|
|
25
|
-
TRACE = 5,
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Performance debug configuration
|
|
30
|
-
*/
|
|
31
|
-
export interface DebugConfig {
|
|
32
|
-
enabled: boolean;
|
|
33
|
-
level: DebugLevel;
|
|
34
|
-
logToConsole: boolean;
|
|
35
|
-
logToStorage: boolean;
|
|
36
|
-
maxLogEntries: number;
|
|
37
|
-
enablePerformanceMarks: boolean;
|
|
38
|
-
enableMemoryTracking: boolean;
|
|
39
|
-
enableRenderTracking: boolean;
|
|
40
|
-
enableNetworkTracking: boolean;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Default debug configuration
|
|
45
|
-
*/
|
|
46
|
-
export const DEFAULT_DEBUG_CONFIG: DebugConfig = {
|
|
47
|
-
enabled: import.meta.env.MODE === 'development',
|
|
48
|
-
level: DebugLevel.INFO,
|
|
49
|
-
logToConsole: true,
|
|
50
|
-
logToStorage: false,
|
|
51
|
-
maxLogEntries: 1000,
|
|
52
|
-
enablePerformanceMarks: true,
|
|
53
|
-
enableMemoryTracking: true,
|
|
54
|
-
enableRenderTracking: true,
|
|
55
|
-
enableNetworkTracking: true,
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Debug log entry interface
|
|
60
|
-
*/
|
|
61
|
-
export interface DebugLogEntry {
|
|
62
|
-
timestamp: number;
|
|
63
|
-
level: DebugLevel;
|
|
64
|
-
category: string;
|
|
65
|
-
message: string;
|
|
66
|
-
data?: unknown;
|
|
67
|
-
stackTrace?: string;
|
|
68
|
-
performanceMarks?: string[];
|
|
69
|
-
memoryUsage?: number;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Performance timeline entry
|
|
74
|
-
*/
|
|
75
|
-
export interface PerformanceTimelineEntry {
|
|
76
|
-
id: string;
|
|
77
|
-
operation: string;
|
|
78
|
-
startTime: number;
|
|
79
|
-
endTime?: number;
|
|
80
|
-
duration?: number;
|
|
81
|
-
metadata?: Record<string, unknown>;
|
|
82
|
-
children?: PerformanceTimelineEntry[];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Memory snapshot
|
|
87
|
-
*/
|
|
88
|
-
export interface MemorySnapshot {
|
|
89
|
-
timestamp: number;
|
|
90
|
-
heapUsed: number;
|
|
91
|
-
heapTotal: number;
|
|
92
|
-
external: number;
|
|
93
|
-
arrayBuffers?: number;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Render performance data
|
|
98
|
-
*/
|
|
99
|
-
export interface RenderPerformanceData {
|
|
100
|
-
componentName: string;
|
|
101
|
-
renderCount: number;
|
|
102
|
-
totalRenderTime: number;
|
|
103
|
-
averageRenderTime: number;
|
|
104
|
-
lastRenderTime: number;
|
|
105
|
-
propsChanges: number;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Advanced DataTable debugger
|
|
110
|
-
*/
|
|
111
|
-
export class DataTableDebugger {
|
|
112
|
-
private config: DebugConfig
|
|
113
|
-
private logger = createLogger('DataTableDebugger');
|
|
114
|
-
private logEntries: DebugLogEntry[] = [];
|
|
115
|
-
private performanceTimeline: Map<string, PerformanceTimelineEntry> = new Map();
|
|
116
|
-
private memorySnapshots: MemorySnapshot[] = [];
|
|
117
|
-
private renderPerformance: Map<string, RenderPerformanceData> = new Map();
|
|
118
|
-
private activeOperations: Set<string> = new Set();
|
|
119
|
-
|
|
120
|
-
constructor(config: Partial<DebugConfig> = {}) {
|
|
121
|
-
this.config = { ...DEFAULT_DEBUG_CONFIG, ...config };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Log a debug message
|
|
126
|
-
*/
|
|
127
|
-
log(
|
|
128
|
-
level: DebugLevel,
|
|
129
|
-
category: string,
|
|
130
|
-
message: string,
|
|
131
|
-
data?: unknown,
|
|
132
|
-
includeStackTrace: boolean = false
|
|
133
|
-
): void {
|
|
134
|
-
if (!this.config.enabled || level > this.config.level) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const entry: DebugLogEntry = {
|
|
139
|
-
timestamp: Date.now(),
|
|
140
|
-
level,
|
|
141
|
-
category,
|
|
142
|
-
message,
|
|
143
|
-
data,
|
|
144
|
-
stackTrace: includeStackTrace ? new Error().stack : undefined,
|
|
145
|
-
memoryUsage: this.config.enableMemoryTracking ? this.getCurrentMemoryUsage() : undefined,
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
this.logEntries.push(entry);
|
|
149
|
-
|
|
150
|
-
// Maintain log size
|
|
151
|
-
if (this.logEntries.length > this.config.maxLogEntries) {
|
|
152
|
-
this.logEntries.shift();
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Console logging
|
|
156
|
-
if (this.config.logToConsole) {
|
|
157
|
-
this.logToConsole(entry);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Storage logging
|
|
161
|
-
if (this.config.logToStorage) {
|
|
162
|
-
this.logToStorage(entry);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Start performance tracking for an operation
|
|
168
|
-
*/
|
|
169
|
-
startOperation(operationId: string, operation: string, metadata?: Record<string, unknown>): void {
|
|
170
|
-
if (!this.config.enabled || !this.config.enableRenderTracking) return;
|
|
171
|
-
|
|
172
|
-
const entry: PerformanceTimelineEntry = {
|
|
173
|
-
id: operationId,
|
|
174
|
-
operation,
|
|
175
|
-
startTime: performance.now(),
|
|
176
|
-
metadata,
|
|
177
|
-
children: [],
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
this.performanceTimeline.set(operationId, entry);
|
|
181
|
-
this.activeOperations.add(operationId);
|
|
182
|
-
|
|
183
|
-
// Performance marks
|
|
184
|
-
if (this.config.enablePerformanceMarks) {
|
|
185
|
-
performance.mark(`${operationId}_start`);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
this.log(DebugLevel.DEBUG, 'Performance', `Started operation: ${operation}`, { operationId, metadata });
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* End performance tracking for an operation
|
|
193
|
-
*/
|
|
194
|
-
endOperation(operationId: string, metadata?: Record<string, unknown>): void {
|
|
195
|
-
if (!this.config.enabled || !this.config.enableRenderTracking) return;
|
|
196
|
-
|
|
197
|
-
const entry = this.performanceTimeline.get(operationId);
|
|
198
|
-
if (!entry) {
|
|
199
|
-
this.log(DebugLevel.WARN, 'Performance', `Operation not found: ${operationId}`);
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
entry.endTime = performance.now();
|
|
204
|
-
entry.duration = entry.endTime - entry.startTime;
|
|
205
|
-
if (metadata) {
|
|
206
|
-
entry.metadata = { ...entry.metadata, ...metadata };
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
this.activeOperations.delete(operationId);
|
|
210
|
-
|
|
211
|
-
// Performance marks and measures
|
|
212
|
-
if (this.config.enablePerformanceMarks) {
|
|
213
|
-
performance.mark(`${operationId}_end`);
|
|
214
|
-
performance.measure(operationId, `${operationId}_start`, `${operationId}_end`);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
this.log(DebugLevel.DEBUG, 'Performance', `Completed operation: ${entry.operation}`, {
|
|
218
|
-
operationId,
|
|
219
|
-
duration: entry.duration,
|
|
220
|
-
metadata: entry.metadata,
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Track render performance
|
|
226
|
-
*/
|
|
227
|
-
trackRender(componentName: string, renderTime: number, propsChanged: boolean = false): void {
|
|
228
|
-
if (!this.config.enabled || !this.config.enableRenderTracking) return;
|
|
229
|
-
|
|
230
|
-
const existing = this.renderPerformance.get(componentName) || {
|
|
231
|
-
componentName,
|
|
232
|
-
renderCount: 0,
|
|
233
|
-
totalRenderTime: 0,
|
|
234
|
-
averageRenderTime: 0,
|
|
235
|
-
lastRenderTime: 0,
|
|
236
|
-
propsChanges: 0,
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
existing.renderCount++;
|
|
240
|
-
existing.totalRenderTime += renderTime;
|
|
241
|
-
existing.averageRenderTime = existing.totalRenderTime / existing.renderCount;
|
|
242
|
-
existing.lastRenderTime = renderTime;
|
|
243
|
-
|
|
244
|
-
if (propsChanged) {
|
|
245
|
-
existing.propsChanges++;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
this.renderPerformance.set(componentName, existing);
|
|
249
|
-
|
|
250
|
-
this.log(DebugLevel.TRACE, 'Render', `Component rendered: ${componentName}`, {
|
|
251
|
-
renderTime,
|
|
252
|
-
propsChanged,
|
|
253
|
-
averageRenderTime: existing.averageRenderTime,
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Take a memory snapshot
|
|
259
|
-
*/
|
|
260
|
-
takeMemorySnapshot(label?: string): MemorySnapshot {
|
|
261
|
-
const snapshot: MemorySnapshot = {
|
|
262
|
-
timestamp: Date.now(),
|
|
263
|
-
heapUsed: 0,
|
|
264
|
-
heapTotal: 0,
|
|
265
|
-
external: 0,
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
if ('memory' in performance) {
|
|
269
|
-
interface PerformanceMemory {
|
|
270
|
-
usedJSHeapSize: number;
|
|
271
|
-
totalJSHeapSize: number;
|
|
272
|
-
jsHeapSizeLimit: number;
|
|
273
|
-
}
|
|
274
|
-
const memory = (performance as unknown as { memory: PerformanceMemory }).memory;
|
|
275
|
-
snapshot.heapUsed = memory.usedJSHeapSize;
|
|
276
|
-
snapshot.heapTotal = memory.totalJSHeapSize;
|
|
277
|
-
snapshot.external = memory.usedJSHeapSize;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
this.memorySnapshots.push(snapshot);
|
|
281
|
-
|
|
282
|
-
// Keep last 100 snapshots
|
|
283
|
-
if (this.memorySnapshots.length > 100) {
|
|
284
|
-
this.memorySnapshots.shift();
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
this.log(DebugLevel.DEBUG, 'Memory', `Memory snapshot${label ? ` (${label})` : ''}`, snapshot);
|
|
288
|
-
|
|
289
|
-
return snapshot;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Analyze performance bottlenecks
|
|
294
|
-
*/
|
|
295
|
-
analyzePerformance(): {
|
|
296
|
-
slowestOperations: PerformanceTimelineEntry[];
|
|
297
|
-
memoryTrends: { increasing: boolean; trend: number };
|
|
298
|
-
renderHotspots: RenderPerformanceData[];
|
|
299
|
-
recommendations: string[];
|
|
300
|
-
} {
|
|
301
|
-
const timeline = Array.from(this.performanceTimeline.values())
|
|
302
|
-
.filter(entry => entry.duration !== undefined)
|
|
303
|
-
.sort((a, b) => (b.duration || 0) - (a.duration || 0));
|
|
304
|
-
|
|
305
|
-
const slowestOperations = timeline.slice(0, 10);
|
|
306
|
-
|
|
307
|
-
// Memory trend analysis
|
|
308
|
-
const recentSnapshots = this.memorySnapshots.slice(-10);
|
|
309
|
-
const memoryTrend = recentSnapshots.length > 1
|
|
310
|
-
? (recentSnapshots[recentSnapshots.length - 1].heapUsed - recentSnapshots[0].heapUsed) / recentSnapshots.length
|
|
311
|
-
: 0;
|
|
312
|
-
|
|
313
|
-
// Render hotspots
|
|
314
|
-
const renderHotspots = Array.from(this.renderPerformance.values())
|
|
315
|
-
.sort((a, b) => b.averageRenderTime - a.averageRenderTime)
|
|
316
|
-
.slice(0, 5);
|
|
317
|
-
|
|
318
|
-
// Generate recommendations
|
|
319
|
-
const recommendations: string[] = [];
|
|
320
|
-
|
|
321
|
-
if (slowestOperations.length > 0 && slowestOperations[0].duration! > 100) {
|
|
322
|
-
recommendations.push(`Consider optimizing ${slowestOperations[0].operation} (${slowestOperations[0].duration!.toFixed(2)}ms)`);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (memoryTrend > 1024 * 1024) { // 1MB increase per snapshot
|
|
326
|
-
recommendations.push('Memory usage is increasing rapidly - check for memory leaks');
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if (renderHotspots.length > 0 && renderHotspots[0].averageRenderTime > 16.67) { // 60fps threshold
|
|
330
|
-
recommendations.push(`${renderHotspots[0].componentName} is rendering slowly - consider memoization`);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return {
|
|
334
|
-
slowestOperations,
|
|
335
|
-
memoryTrends: {
|
|
336
|
-
increasing: memoryTrend > 0,
|
|
337
|
-
trend: memoryTrend,
|
|
338
|
-
},
|
|
339
|
-
renderHotspots,
|
|
340
|
-
recommendations,
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Generate performance report
|
|
346
|
-
*/
|
|
347
|
-
generateReport(): {
|
|
348
|
-
summary: {
|
|
349
|
-
totalOperations: number;
|
|
350
|
-
averageOperationTime: number;
|
|
351
|
-
totalRenders: number;
|
|
352
|
-
memorySnapshots: number;
|
|
353
|
-
logEntries: number;
|
|
354
|
-
};
|
|
355
|
-
performance: {
|
|
356
|
-
slowestOperations: PerformanceTimelineEntry[];
|
|
357
|
-
memoryTrends: { increasing: boolean; trend: number };
|
|
358
|
-
renderHotspots: RenderPerformanceData[];
|
|
359
|
-
recommendations: string[];
|
|
360
|
-
};
|
|
361
|
-
logs: DebugLogEntry[];
|
|
362
|
-
timeline: PerformanceTimelineEntry[];
|
|
363
|
-
} {
|
|
364
|
-
const completedOperations = Array.from(this.performanceTimeline.values())
|
|
365
|
-
.filter(op => op.duration !== undefined);
|
|
366
|
-
|
|
367
|
-
const averageOperationTime = completedOperations.length > 0
|
|
368
|
-
? completedOperations.reduce((sum, op) => sum + (op.duration || 0), 0) / completedOperations.length
|
|
369
|
-
: 0;
|
|
370
|
-
|
|
371
|
-
const totalRenders = Array.from(this.renderPerformance.values())
|
|
372
|
-
.reduce((sum, data) => sum + data.renderCount, 0);
|
|
373
|
-
|
|
374
|
-
return {
|
|
375
|
-
summary: {
|
|
376
|
-
totalOperations: completedOperations.length,
|
|
377
|
-
averageOperationTime,
|
|
378
|
-
totalRenders,
|
|
379
|
-
memorySnapshots: this.memorySnapshots.length,
|
|
380
|
-
logEntries: this.logEntries.length,
|
|
381
|
-
},
|
|
382
|
-
performance: this.analyzePerformance(),
|
|
383
|
-
logs: this.logEntries.slice(-50), // Last 50 logs
|
|
384
|
-
timeline: Array.from(this.performanceTimeline.values()),
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Export debug data
|
|
390
|
-
*/
|
|
391
|
-
exportDebugData(): string {
|
|
392
|
-
const report = this.generateReport();
|
|
393
|
-
return JSON.stringify(report, null, 2);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Clear all debug data
|
|
398
|
-
*/
|
|
399
|
-
clear(): void {
|
|
400
|
-
this.logEntries = [];
|
|
401
|
-
this.performanceTimeline.clear();
|
|
402
|
-
this.memorySnapshots = [];
|
|
403
|
-
this.renderPerformance.clear();
|
|
404
|
-
this.activeOperations.clear();
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Get current memory usage
|
|
409
|
-
*/
|
|
410
|
-
private getCurrentMemoryUsage(): number {
|
|
411
|
-
if ('memory' in performance) {
|
|
412
|
-
interface PerformanceMemory {
|
|
413
|
-
usedJSHeapSize: number;
|
|
414
|
-
totalJSHeapSize: number;
|
|
415
|
-
jsHeapSizeLimit: number;
|
|
416
|
-
}
|
|
417
|
-
const memory = (performance as unknown as { memory: PerformanceMemory }).memory;
|
|
418
|
-
return memory.usedJSHeapSize / (1024 * 1024); // MB
|
|
419
|
-
}
|
|
420
|
-
return 0;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Log to console with appropriate styling
|
|
425
|
-
*/
|
|
426
|
-
private logToConsole(entry: DebugLogEntry): void {
|
|
427
|
-
const timestamp = new Date(entry.timestamp).toISOString();
|
|
428
|
-
const levelName = DebugLevel[entry.level];
|
|
429
|
-
const message = `[${timestamp}] [${levelName}] [${entry.category}] ${entry.message}`;
|
|
430
|
-
|
|
431
|
-
switch (entry.level) {
|
|
432
|
-
case DebugLevel.ERROR:
|
|
433
|
-
this.logger.error(message, entry.data);
|
|
434
|
-
break;
|
|
435
|
-
case DebugLevel.WARN:
|
|
436
|
-
this.logger.warn(message, entry.data);
|
|
437
|
-
break;
|
|
438
|
-
case DebugLevel.INFO:
|
|
439
|
-
this.logger.info(message, entry.data);
|
|
440
|
-
break;
|
|
441
|
-
case DebugLevel.DEBUG:
|
|
442
|
-
case DebugLevel.TRACE:
|
|
443
|
-
this.logger.debug(message, entry.data);
|
|
444
|
-
break;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
/**
|
|
449
|
-
* Log to local storage
|
|
450
|
-
*/
|
|
451
|
-
private logToStorage(entry: DebugLogEntry): void {
|
|
452
|
-
if (typeof window === 'undefined') return;
|
|
453
|
-
|
|
454
|
-
try {
|
|
455
|
-
const stored = localStorage.getItem('datatable-debug-logs');
|
|
456
|
-
const logs = stored ? JSON.parse(stored) : [];
|
|
457
|
-
logs.push(entry);
|
|
458
|
-
|
|
459
|
-
// Keep last 500 entries
|
|
460
|
-
if (logs.length > 500) {
|
|
461
|
-
logs.splice(0, logs.length - 500);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
localStorage.setItem('datatable-debug-logs', JSON.stringify(logs));
|
|
465
|
-
} catch (error) {
|
|
466
|
-
this.logger.warn('Failed to store debug log:', error);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/**
|
|
472
|
-
* Global debugger instance
|
|
473
|
-
*/
|
|
474
|
-
export const dataTableDebugger = new DataTableDebugger();
|
|
475
|
-
|
|
476
|
-
/**
|
|
477
|
-
* Performance profiler decorator
|
|
478
|
-
*/
|
|
479
|
-
export function profile(operation: string) {
|
|
480
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
481
|
-
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
|
482
|
-
const originalMethod = descriptor.value;
|
|
483
|
-
|
|
484
|
-
descriptor.value = async function (this: unknown, ...args: unknown[]) {
|
|
485
|
-
const operationId = `${target.constructor.name}.${propertyKey}_${Date.now()}`;
|
|
486
|
-
|
|
487
|
-
dataTableDebugger.startOperation(operationId, operation, {
|
|
488
|
-
className: target.constructor.name,
|
|
489
|
-
methodName: propertyKey,
|
|
490
|
-
args: args.length,
|
|
491
|
-
});
|
|
492
|
-
|
|
493
|
-
try {
|
|
494
|
-
const result = await originalMethod.apply(this, args);
|
|
495
|
-
dataTableDebugger.endOperation(operationId, { success: true });
|
|
496
|
-
return result;
|
|
497
|
-
} catch (error) {
|
|
498
|
-
dataTableDebugger.endOperation(operationId, { success: false, error: error instanceof Error ? error.message : String(error) });
|
|
499
|
-
dataTableDebugger.log(DebugLevel.ERROR, 'Performance', `Operation failed: ${operation}`, error);
|
|
500
|
-
throw error;
|
|
501
|
-
}
|
|
502
|
-
};
|
|
503
|
-
|
|
504
|
-
return descriptor;
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Memory monitoring utility
|
|
510
|
-
*/
|
|
511
|
-
export class MemoryMonitor {
|
|
512
|
-
private debuggerInstance: DataTableDebugger;
|
|
513
|
-
private intervalId: NodeJS.Timeout | null = null;
|
|
514
|
-
|
|
515
|
-
constructor(debuggerInstance: DataTableDebugger = dataTableDebugger) {
|
|
516
|
-
this.debuggerInstance = debuggerInstance;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
start(interval: number = 5000): void {
|
|
520
|
-
this.stop(); // Stop any existing monitoring
|
|
521
|
-
|
|
522
|
-
this.intervalId = setInterval(() => {
|
|
523
|
-
this.debuggerInstance.takeMemorySnapshot('periodic');
|
|
524
|
-
}, interval);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
stop(): void {
|
|
528
|
-
if (this.intervalId) {
|
|
529
|
-
clearInterval(this.intervalId);
|
|
530
|
-
this.intervalId = null;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
/**
|
|
536
|
-
* Performance monitoring React hook
|
|
537
|
-
*/
|
|
538
|
-
export function usePerformanceDebugger(componentName: string) {
|
|
539
|
-
const startTime = React.useRef<number>(0);
|
|
540
|
-
|
|
541
|
-
React.useEffect(() => {
|
|
542
|
-
startTime.current = performance.now();
|
|
543
|
-
|
|
544
|
-
return () => {
|
|
545
|
-
const renderTime = performance.now() - startTime.current;
|
|
546
|
-
dataTableDebugger.trackRender(componentName, renderTime);
|
|
547
|
-
};
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
const trackOperation = React.useCallback((operation: string, fn: () => unknown) => {
|
|
551
|
-
const operationId = `${componentName}_${operation}_${Date.now()}`;
|
|
552
|
-
dataTableDebugger.startOperation(operationId, operation);
|
|
553
|
-
|
|
554
|
-
try {
|
|
555
|
-
const result = fn();
|
|
556
|
-
dataTableDebugger.endOperation(operationId);
|
|
557
|
-
return result;
|
|
558
|
-
} catch (error) {
|
|
559
|
-
dataTableDebugger.endOperation(operationId, { error: error instanceof Error ? error.message : String(error) });
|
|
560
|
-
throw error;
|
|
561
|
-
}
|
|
562
|
-
}, [componentName]);
|
|
563
|
-
|
|
564
|
-
return {
|
|
565
|
-
trackOperation,
|
|
566
|
-
log: (level: DebugLevel, message: string, data?: unknown) =>
|
|
567
|
-
dataTableDebugger.log(level, componentName, message, data),
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
/**
|
|
572
|
-
* Development tools integration
|
|
573
|
-
*/
|
|
574
|
-
export function setupDevTools(): void {
|
|
575
|
-
if (typeof window === 'undefined' || import.meta.env.MODE !== 'development') {
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
// Expose debugger to global scope for browser dev tools
|
|
580
|
-
interface WindowWithDataTableDebugger extends Window {
|
|
581
|
-
__DATATABLE_DEBUGGER__: typeof dataTableDebugger;
|
|
582
|
-
dataTableDebug: {
|
|
583
|
-
getReport: () => ReturnType<typeof dataTableDebugger.generateReport>;
|
|
584
|
-
exportData: () => ReturnType<typeof dataTableDebugger.exportDebugData>;
|
|
585
|
-
clearLogs: () => void;
|
|
586
|
-
takeSnapshot: (label?: string) => ReturnType<typeof dataTableDebugger.takeMemorySnapshot>;
|
|
587
|
-
analyze: () => ReturnType<typeof dataTableDebugger.analyzePerformance>;
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
const windowWithDebugger = window as unknown as WindowWithDataTableDebugger;
|
|
592
|
-
windowWithDebugger.__DATATABLE_DEBUGGER__ = dataTableDebugger;
|
|
593
|
-
|
|
594
|
-
// Add console commands
|
|
595
|
-
windowWithDebugger.dataTableDebug = {
|
|
596
|
-
getReport: () => dataTableDebugger.generateReport(),
|
|
597
|
-
exportData: () => dataTableDebugger.exportDebugData(),
|
|
598
|
-
clearLogs: () => dataTableDebugger.clear(),
|
|
599
|
-
takeSnapshot: (label?: string) => dataTableDebugger.takeMemorySnapshot(label),
|
|
600
|
-
analyze: () => dataTableDebugger.analyzePerformance(),
|
|
601
|
-
};
|
|
602
|
-
|
|
603
|
-
createLogger('DataTableDebugTools').info('Debug Tools loaded. Use window.dataTableDebug for debugging.');
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
/**
|
|
607
|
-
* Initialize debugging tools
|
|
608
|
-
*/
|
|
609
|
-
setupDevTools();
|