@jmruthers/pace-core 0.5.75 → 0.5.76
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-HWZQGASI.js → DataTable-4GAVPIEG.js} +48 -30
- package/dist/{PublicLoadingSpinner-BKNBT6b6.d.ts → PublicLoadingSpinner-BiNER8F5.d.ts} +28 -17
- package/dist/{chunk-33PHABLB.js → chunk-AFGTSUAD.js} +10 -127
- package/dist/chunk-AFGTSUAD.js.map +1 -0
- package/dist/{chunk-2DFZ432F.js → chunk-K34IM5CT.js} +3 -5
- package/dist/{chunk-2DFZ432F.js.map → chunk-K34IM5CT.js.map} +1 -1
- package/dist/{chunk-2CHATWBF.js → chunk-KHJS6VIA.js} +199 -35
- package/dist/chunk-KHJS6VIA.js.map +1 -0
- package/dist/{chunk-ZTT2AXMX.js → chunk-KK73ZB4E.js} +2 -2
- package/dist/{chunk-CY3AHGO4.js → chunk-M5IWZRBT.js} +1750 -2815
- package/dist/chunk-M5IWZRBT.js.map +1 -0
- package/dist/{chunk-DAXLNIDY.js → chunk-Y6TXWPJO.js} +6 -4
- package/dist/{chunk-DAXLNIDY.js.map → chunk-Y6TXWPJO.js.map} +1 -1
- package/dist/{chunk-YNUBMSMV.js → chunk-YCKPEMJA.js} +186 -263
- package/dist/chunk-YCKPEMJA.js.map +1 -0
- package/dist/components.d.ts +1 -1
- package/dist/components.js +7 -6
- package/dist/components.js.map +1 -1
- package/dist/hooks.d.ts +17 -40
- package/dist/hooks.js +6 -6
- package/dist/index.d.ts +3 -3
- package/dist/index.js +12 -10
- package/dist/index.js.map +1 -1
- package/dist/rbac/index.d.ts +54 -1
- package/dist/rbac/index.js +5 -4
- package/dist/utils.js +1 -1
- package/docs/TERMINOLOGY.md +231 -0
- 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/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +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/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/RBACContextType.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACProviderProps.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/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/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +47 -0
- package/docs/api/interfaces/UseResolvedScopeReturn.md +47 -0
- 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 +57 -11
- package/docs/api-reference/providers.md +26 -7
- package/docs/best-practices/README.md +20 -0
- package/docs/best-practices/accessibility.md +566 -0
- package/docs/best-practices/performance-expansion.md +473 -0
- package/docs/core-concepts/authentication.md +15 -7
- package/docs/documentation-index.md +1 -1
- package/docs/documentation-templates.md +539 -0
- package/docs/getting-started/quick-start.md +16 -66
- package/docs/implementation-guides/component-styling.md +410 -0
- package/docs/implementation-guides/data-tables.md +1 -1
- package/docs/style-guide.md +39 -0
- package/package.json +1 -1
- package/src/__tests__/TEST_GUIDE_CURSOR.md +290 -0
- package/src/__tests__/helpers/supabaseMock.ts +48 -2
- package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +17 -6
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +73 -9
- package/src/components/DataTable/components/DataTableCore.tsx +280 -475
- package/src/components/DataTable/components/UnifiedTableBody.tsx +120 -153
- package/src/components/DataTable/components/index.ts +1 -2
- package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +208 -275
- package/src/components/DataTable/core/index.ts +1 -8
- package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +525 -0
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +570 -0
- package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +214 -0
- package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +224 -0
- package/src/components/DataTable/hooks/index.ts +6 -0
- package/src/components/DataTable/hooks/useColumnReordering.ts +1 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +149 -0
- package/src/components/DataTable/hooks/useDataTableState.ts +12 -6
- package/src/components/DataTable/hooks/useHierarchicalState.ts +26 -8
- package/src/components/DataTable/hooks/useTableColumns.ts +153 -0
- package/src/components/DataTable/index.ts +1 -9
- package/src/components/DataTable/utils/__tests__/COVERAGE_NOTE.md +89 -0
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +3 -6
- package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +462 -0
- package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +247 -0
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +8 -6
- package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +466 -0
- package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +265 -0
- package/src/components/DataTable/utils/errorHandling.ts +52 -460
- package/src/components/DataTable/utils/exportUtils.ts +46 -15
- package/src/components/DataTable/utils/hierarchicalSorting.ts +50 -3
- package/src/components/DataTable/utils/hierarchicalUtils.ts +167 -34
- package/src/components/DataTable/utils/index.ts +5 -0
- package/src/components/DataTable/utils/rowUtils.ts +68 -0
- package/src/components/EventSelector/EventSelector.test.tsx +672 -0
- package/src/components/Label/__tests__/Label.test.tsx +434 -0
- package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +190 -0
- package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +185 -0
- package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +313 -0
- package/src/components/Select/Select.test.tsx +143 -120
- package/src/components/Select/Select.tsx +47 -212
- package/src/components/Select/hooks.ts +36 -1
- package/src/components/Select/index.ts +2 -1
- package/src/hooks/services/__tests__/useServiceHooks.test.tsx +137 -0
- package/src/hooks/useSecureDataAccess.test.ts +32 -29
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +341 -0
- package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +437 -0
- package/src/rbac/hooks/index.ts +2 -0
- package/src/rbac/hooks/useResolvedScope.ts +232 -0
- package/src/services/__tests__/InactivityService.lifecycle.test.ts +411 -0
- package/src/services/__tests__/OrganisationService.pagination.test.ts +375 -0
- package/src/types/__tests__/README.md +114 -0
- package/src/types/__tests__/validation.test.ts +731 -0
- package/src/utils/__tests__/file-reference.test.ts +383 -0
- package/src/utils/__tests__/performanceBenchmark.test.ts +175 -0
- package/src/utils/appNameResolver.test.ts +54 -0
- package/src/validation/__tests__/csrf.unit.test.ts +63 -0
- package/src/validation/__tests__/passwordSchema.unit.test.ts +105 -0
- package/dist/chunk-2CHATWBF.js.map +0 -1
- package/dist/chunk-33PHABLB.js.map +0 -1
- package/dist/chunk-CY3AHGO4.js.map +0 -1
- package/dist/chunk-TYHR5X4W.js +0 -33
- package/dist/chunk-TYHR5X4W.js.map +0 -1
- package/dist/chunk-YNUBMSMV.js.map +0 -1
- package/dist/eventContext-BBA42P6G.js +0 -14
- package/dist/eventContext-BBA42P6G.js.map +0 -1
- package/docs/documentation-style-checklist.md +0 -294
- package/src/components/DataTable/components/DataTableBody.tsx +0 -488
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -144
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -515
- package/src/components/DataTable/core/ActionManager.ts +0 -235
- package/src/components/DataTable/core/ColumnManager.ts +0 -215
- package/src/components/DataTable/core/DataManager.ts +0 -188
- package/src/components/DataTable/core/DataTableContext.tsx +0 -181
- package/src/components/DataTable/core/LocalDataAdapter.ts +0 -264
- package/src/components/DataTable/core/PluginRegistry.ts +0 -229
- package/src/components/DataTable/core/StateManager.ts +0 -311
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -634
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -193
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -519
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -714
- package/src/components/DataTable/core/interfaces.ts +0 -338
- package/src/components/DataTable/utils/debugTools.ts +0 -583
- package/src/components/Select/Select.bug-test.tsx +0 -69
- package/src/components/Select/Select.refactored.tsx +0 -497
- /package/dist/{DataTable-HWZQGASI.js.map → DataTable-4GAVPIEG.js.map} +0 -0
- /package/dist/{chunk-ZTT2AXMX.js.map → chunk-KK73ZB4E.js.map} +0 -0
|
@@ -1,583 +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
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Debug levels for controlling verbosity
|
|
17
|
-
*/
|
|
18
|
-
export enum DebugLevel {
|
|
19
|
-
NONE = 0,
|
|
20
|
-
ERROR = 1,
|
|
21
|
-
WARN = 2,
|
|
22
|
-
INFO = 3,
|
|
23
|
-
DEBUG = 4,
|
|
24
|
-
TRACE = 5,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Performance debug configuration
|
|
29
|
-
*/
|
|
30
|
-
export interface DebugConfig {
|
|
31
|
-
enabled: boolean;
|
|
32
|
-
level: DebugLevel;
|
|
33
|
-
logToConsole: boolean;
|
|
34
|
-
logToStorage: boolean;
|
|
35
|
-
maxLogEntries: number;
|
|
36
|
-
enablePerformanceMarks: boolean;
|
|
37
|
-
enableMemoryTracking: boolean;
|
|
38
|
-
enableRenderTracking: boolean;
|
|
39
|
-
enableNetworkTracking: boolean;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Default debug configuration
|
|
44
|
-
*/
|
|
45
|
-
export const DEFAULT_DEBUG_CONFIG: DebugConfig = {
|
|
46
|
-
enabled: import.meta.env.MODE === 'development',
|
|
47
|
-
level: DebugLevel.INFO,
|
|
48
|
-
logToConsole: true,
|
|
49
|
-
logToStorage: false,
|
|
50
|
-
maxLogEntries: 1000,
|
|
51
|
-
enablePerformanceMarks: true,
|
|
52
|
-
enableMemoryTracking: true,
|
|
53
|
-
enableRenderTracking: true,
|
|
54
|
-
enableNetworkTracking: true,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Debug log entry interface
|
|
59
|
-
*/
|
|
60
|
-
export interface DebugLogEntry {
|
|
61
|
-
timestamp: number;
|
|
62
|
-
level: DebugLevel;
|
|
63
|
-
category: string;
|
|
64
|
-
message: string;
|
|
65
|
-
data?: any;
|
|
66
|
-
stackTrace?: string;
|
|
67
|
-
performanceMarks?: string[];
|
|
68
|
-
memoryUsage?: number;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Performance timeline entry
|
|
73
|
-
*/
|
|
74
|
-
export interface PerformanceTimelineEntry {
|
|
75
|
-
id: string;
|
|
76
|
-
operation: string;
|
|
77
|
-
startTime: number;
|
|
78
|
-
endTime?: number;
|
|
79
|
-
duration?: number;
|
|
80
|
-
metadata?: Record<string, any>;
|
|
81
|
-
children?: PerformanceTimelineEntry[];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Memory snapshot
|
|
86
|
-
*/
|
|
87
|
-
export interface MemorySnapshot {
|
|
88
|
-
timestamp: number;
|
|
89
|
-
heapUsed: number;
|
|
90
|
-
heapTotal: number;
|
|
91
|
-
external: number;
|
|
92
|
-
arrayBuffers?: number;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Render performance data
|
|
97
|
-
*/
|
|
98
|
-
export interface RenderPerformanceData {
|
|
99
|
-
componentName: string;
|
|
100
|
-
renderCount: number;
|
|
101
|
-
totalRenderTime: number;
|
|
102
|
-
averageRenderTime: number;
|
|
103
|
-
lastRenderTime: number;
|
|
104
|
-
propsChanges: number;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Advanced DataTable debugger
|
|
109
|
-
*/
|
|
110
|
-
export class DataTableDebugger {
|
|
111
|
-
private config: DebugConfig;
|
|
112
|
-
private logEntries: DebugLogEntry[] = [];
|
|
113
|
-
private performanceTimeline: Map<string, PerformanceTimelineEntry> = new Map();
|
|
114
|
-
private memorySnapshots: MemorySnapshot[] = [];
|
|
115
|
-
private renderPerformance: Map<string, RenderPerformanceData> = new Map();
|
|
116
|
-
private activeOperations: Set<string> = new Set();
|
|
117
|
-
|
|
118
|
-
constructor(config: Partial<DebugConfig> = {}) {
|
|
119
|
-
this.config = { ...DEFAULT_DEBUG_CONFIG, ...config };
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Log a debug message
|
|
124
|
-
*/
|
|
125
|
-
log(
|
|
126
|
-
level: DebugLevel,
|
|
127
|
-
category: string,
|
|
128
|
-
message: string,
|
|
129
|
-
data?: any,
|
|
130
|
-
includeStackTrace: boolean = false
|
|
131
|
-
): void {
|
|
132
|
-
if (!this.config.enabled || level > this.config.level) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const entry: DebugLogEntry = {
|
|
137
|
-
timestamp: Date.now(),
|
|
138
|
-
level,
|
|
139
|
-
category,
|
|
140
|
-
message,
|
|
141
|
-
data,
|
|
142
|
-
stackTrace: includeStackTrace ? new Error().stack : undefined,
|
|
143
|
-
memoryUsage: this.config.enableMemoryTracking ? this.getCurrentMemoryUsage() : undefined,
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
this.logEntries.push(entry);
|
|
147
|
-
|
|
148
|
-
// Maintain log size
|
|
149
|
-
if (this.logEntries.length > this.config.maxLogEntries) {
|
|
150
|
-
this.logEntries.shift();
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Console logging
|
|
154
|
-
if (this.config.logToConsole) {
|
|
155
|
-
this.logToConsole(entry);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Storage logging
|
|
159
|
-
if (this.config.logToStorage) {
|
|
160
|
-
this.logToStorage(entry);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Start performance tracking for an operation
|
|
166
|
-
*/
|
|
167
|
-
startOperation(operationId: string, operation: string, metadata?: Record<string, any>): void {
|
|
168
|
-
if (!this.config.enabled || !this.config.enableRenderTracking) return;
|
|
169
|
-
|
|
170
|
-
const entry: PerformanceTimelineEntry = {
|
|
171
|
-
id: operationId,
|
|
172
|
-
operation,
|
|
173
|
-
startTime: performance.now(),
|
|
174
|
-
metadata,
|
|
175
|
-
children: [],
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
this.performanceTimeline.set(operationId, entry);
|
|
179
|
-
this.activeOperations.add(operationId);
|
|
180
|
-
|
|
181
|
-
// Performance marks
|
|
182
|
-
if (this.config.enablePerformanceMarks) {
|
|
183
|
-
performance.mark(`${operationId}_start`);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
this.log(DebugLevel.DEBUG, 'Performance', `Started operation: ${operation}`, { operationId, metadata });
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* End performance tracking for an operation
|
|
191
|
-
*/
|
|
192
|
-
endOperation(operationId: string, metadata?: Record<string, any>): void {
|
|
193
|
-
if (!this.config.enabled || !this.config.enableRenderTracking) return;
|
|
194
|
-
|
|
195
|
-
const entry = this.performanceTimeline.get(operationId);
|
|
196
|
-
if (!entry) {
|
|
197
|
-
this.log(DebugLevel.WARN, 'Performance', `Operation not found: ${operationId}`);
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
entry.endTime = performance.now();
|
|
202
|
-
entry.duration = entry.endTime - entry.startTime;
|
|
203
|
-
if (metadata) {
|
|
204
|
-
entry.metadata = { ...entry.metadata, ...metadata };
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
this.activeOperations.delete(operationId);
|
|
208
|
-
|
|
209
|
-
// Performance marks and measures
|
|
210
|
-
if (this.config.enablePerformanceMarks) {
|
|
211
|
-
performance.mark(`${operationId}_end`);
|
|
212
|
-
performance.measure(operationId, `${operationId}_start`, `${operationId}_end`);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
this.log(DebugLevel.DEBUG, 'Performance', `Completed operation: ${entry.operation}`, {
|
|
216
|
-
operationId,
|
|
217
|
-
duration: entry.duration,
|
|
218
|
-
metadata: entry.metadata,
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Track render performance
|
|
224
|
-
*/
|
|
225
|
-
trackRender(componentName: string, renderTime: number, propsChanged: boolean = false): void {
|
|
226
|
-
if (!this.config.enabled || !this.config.enableRenderTracking) return;
|
|
227
|
-
|
|
228
|
-
const existing = this.renderPerformance.get(componentName) || {
|
|
229
|
-
componentName,
|
|
230
|
-
renderCount: 0,
|
|
231
|
-
totalRenderTime: 0,
|
|
232
|
-
averageRenderTime: 0,
|
|
233
|
-
lastRenderTime: 0,
|
|
234
|
-
propsChanges: 0,
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
existing.renderCount++;
|
|
238
|
-
existing.totalRenderTime += renderTime;
|
|
239
|
-
existing.averageRenderTime = existing.totalRenderTime / existing.renderCount;
|
|
240
|
-
existing.lastRenderTime = renderTime;
|
|
241
|
-
|
|
242
|
-
if (propsChanged) {
|
|
243
|
-
existing.propsChanges++;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
this.renderPerformance.set(componentName, existing);
|
|
247
|
-
|
|
248
|
-
this.log(DebugLevel.TRACE, 'Render', `Component rendered: ${componentName}`, {
|
|
249
|
-
renderTime,
|
|
250
|
-
propsChanged,
|
|
251
|
-
averageRenderTime: existing.averageRenderTime,
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Take a memory snapshot
|
|
257
|
-
*/
|
|
258
|
-
takeMemorySnapshot(label?: string): MemorySnapshot {
|
|
259
|
-
const snapshot: MemorySnapshot = {
|
|
260
|
-
timestamp: Date.now(),
|
|
261
|
-
heapUsed: 0,
|
|
262
|
-
heapTotal: 0,
|
|
263
|
-
external: 0,
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
if ('memory' in performance) {
|
|
267
|
-
const memory = (performance as any).memory;
|
|
268
|
-
snapshot.heapUsed = memory.usedJSHeapSize;
|
|
269
|
-
snapshot.heapTotal = memory.totalJSHeapSize;
|
|
270
|
-
snapshot.external = memory.usedJSHeapSize;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
this.memorySnapshots.push(snapshot);
|
|
274
|
-
|
|
275
|
-
// Keep last 100 snapshots
|
|
276
|
-
if (this.memorySnapshots.length > 100) {
|
|
277
|
-
this.memorySnapshots.shift();
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
this.log(DebugLevel.DEBUG, 'Memory', `Memory snapshot${label ? ` (${label})` : ''}`, snapshot);
|
|
281
|
-
|
|
282
|
-
return snapshot;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Analyze performance bottlenecks
|
|
287
|
-
*/
|
|
288
|
-
analyzePerformance(): {
|
|
289
|
-
slowestOperations: PerformanceTimelineEntry[];
|
|
290
|
-
memoryTrends: { increasing: boolean; trend: number };
|
|
291
|
-
renderHotspots: RenderPerformanceData[];
|
|
292
|
-
recommendations: string[];
|
|
293
|
-
} {
|
|
294
|
-
const timeline = Array.from(this.performanceTimeline.values())
|
|
295
|
-
.filter(entry => entry.duration !== undefined)
|
|
296
|
-
.sort((a, b) => (b.duration || 0) - (a.duration || 0));
|
|
297
|
-
|
|
298
|
-
const slowestOperations = timeline.slice(0, 10);
|
|
299
|
-
|
|
300
|
-
// Memory trend analysis
|
|
301
|
-
const recentSnapshots = this.memorySnapshots.slice(-10);
|
|
302
|
-
const memoryTrend = recentSnapshots.length > 1
|
|
303
|
-
? (recentSnapshots[recentSnapshots.length - 1].heapUsed - recentSnapshots[0].heapUsed) / recentSnapshots.length
|
|
304
|
-
: 0;
|
|
305
|
-
|
|
306
|
-
// Render hotspots
|
|
307
|
-
const renderHotspots = Array.from(this.renderPerformance.values())
|
|
308
|
-
.sort((a, b) => b.averageRenderTime - a.averageRenderTime)
|
|
309
|
-
.slice(0, 5);
|
|
310
|
-
|
|
311
|
-
// Generate recommendations
|
|
312
|
-
const recommendations: string[] = [];
|
|
313
|
-
|
|
314
|
-
if (slowestOperations.length > 0 && slowestOperations[0].duration! > 100) {
|
|
315
|
-
recommendations.push(`Consider optimizing ${slowestOperations[0].operation} (${slowestOperations[0].duration!.toFixed(2)}ms)`);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (memoryTrend > 1024 * 1024) { // 1MB increase per snapshot
|
|
319
|
-
recommendations.push('Memory usage is increasing rapidly - check for memory leaks');
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
if (renderHotspots.length > 0 && renderHotspots[0].averageRenderTime > 16.67) { // 60fps threshold
|
|
323
|
-
recommendations.push(`${renderHotspots[0].componentName} is rendering slowly - consider memoization`);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
return {
|
|
327
|
-
slowestOperations,
|
|
328
|
-
memoryTrends: {
|
|
329
|
-
increasing: memoryTrend > 0,
|
|
330
|
-
trend: memoryTrend,
|
|
331
|
-
},
|
|
332
|
-
renderHotspots,
|
|
333
|
-
recommendations,
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Generate performance report
|
|
339
|
-
*/
|
|
340
|
-
generateReport(): {
|
|
341
|
-
summary: {
|
|
342
|
-
totalOperations: number;
|
|
343
|
-
averageOperationTime: number;
|
|
344
|
-
totalRenders: number;
|
|
345
|
-
memorySnapshots: number;
|
|
346
|
-
logEntries: number;
|
|
347
|
-
};
|
|
348
|
-
performance: {
|
|
349
|
-
slowestOperations: PerformanceTimelineEntry[];
|
|
350
|
-
memoryTrends: { increasing: boolean; trend: number };
|
|
351
|
-
renderHotspots: RenderPerformanceData[];
|
|
352
|
-
recommendations: string[];
|
|
353
|
-
};
|
|
354
|
-
logs: DebugLogEntry[];
|
|
355
|
-
timeline: PerformanceTimelineEntry[];
|
|
356
|
-
} {
|
|
357
|
-
const completedOperations = Array.from(this.performanceTimeline.values())
|
|
358
|
-
.filter(op => op.duration !== undefined);
|
|
359
|
-
|
|
360
|
-
const averageOperationTime = completedOperations.length > 0
|
|
361
|
-
? completedOperations.reduce((sum, op) => sum + (op.duration || 0), 0) / completedOperations.length
|
|
362
|
-
: 0;
|
|
363
|
-
|
|
364
|
-
const totalRenders = Array.from(this.renderPerformance.values())
|
|
365
|
-
.reduce((sum, data) => sum + data.renderCount, 0);
|
|
366
|
-
|
|
367
|
-
return {
|
|
368
|
-
summary: {
|
|
369
|
-
totalOperations: completedOperations.length,
|
|
370
|
-
averageOperationTime,
|
|
371
|
-
totalRenders,
|
|
372
|
-
memorySnapshots: this.memorySnapshots.length,
|
|
373
|
-
logEntries: this.logEntries.length,
|
|
374
|
-
},
|
|
375
|
-
performance: this.analyzePerformance(),
|
|
376
|
-
logs: this.logEntries.slice(-50), // Last 50 logs
|
|
377
|
-
timeline: Array.from(this.performanceTimeline.values()),
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Export debug data
|
|
383
|
-
*/
|
|
384
|
-
exportDebugData(): string {
|
|
385
|
-
const report = this.generateReport();
|
|
386
|
-
return JSON.stringify(report, null, 2);
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Clear all debug data
|
|
391
|
-
*/
|
|
392
|
-
clear(): void {
|
|
393
|
-
this.logEntries = [];
|
|
394
|
-
this.performanceTimeline.clear();
|
|
395
|
-
this.memorySnapshots = [];
|
|
396
|
-
this.renderPerformance.clear();
|
|
397
|
-
this.activeOperations.clear();
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* Get current memory usage
|
|
402
|
-
*/
|
|
403
|
-
private getCurrentMemoryUsage(): number {
|
|
404
|
-
if ('memory' in performance) {
|
|
405
|
-
const memory = (performance as any).memory;
|
|
406
|
-
return memory.usedJSHeapSize / (1024 * 1024); // MB
|
|
407
|
-
}
|
|
408
|
-
return 0;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* Log to console with appropriate styling
|
|
413
|
-
*/
|
|
414
|
-
private logToConsole(entry: DebugLogEntry): void {
|
|
415
|
-
const timestamp = new Date(entry.timestamp).toISOString();
|
|
416
|
-
const levelName = DebugLevel[entry.level];
|
|
417
|
-
const message = `[${timestamp}] [${levelName}] [${entry.category}] ${entry.message}`;
|
|
418
|
-
|
|
419
|
-
switch (entry.level) {
|
|
420
|
-
case DebugLevel.ERROR:
|
|
421
|
-
console.error(message, entry.data);
|
|
422
|
-
break;
|
|
423
|
-
case DebugLevel.WARN:
|
|
424
|
-
console.warn(message, entry.data);
|
|
425
|
-
break;
|
|
426
|
-
case DebugLevel.INFO:
|
|
427
|
-
console.info(message, entry.data);
|
|
428
|
-
break;
|
|
429
|
-
case DebugLevel.DEBUG:
|
|
430
|
-
case DebugLevel.TRACE:
|
|
431
|
-
console.debug(message, entry.data);
|
|
432
|
-
break;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
/**
|
|
437
|
-
* Log to local storage
|
|
438
|
-
*/
|
|
439
|
-
private logToStorage(entry: DebugLogEntry): void {
|
|
440
|
-
try {
|
|
441
|
-
const stored = localStorage.getItem('datatable-debug-logs');
|
|
442
|
-
const logs = stored ? JSON.parse(stored) : [];
|
|
443
|
-
logs.push(entry);
|
|
444
|
-
|
|
445
|
-
// Keep last 500 entries
|
|
446
|
-
if (logs.length > 500) {
|
|
447
|
-
logs.splice(0, logs.length - 500);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
localStorage.setItem('datatable-debug-logs', JSON.stringify(logs));
|
|
451
|
-
} catch (error) {
|
|
452
|
-
console.warn('Failed to store debug log:', error);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* Global debugger instance
|
|
459
|
-
*/
|
|
460
|
-
export const dataTableDebugger = new DataTableDebugger();
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* Performance profiler decorator
|
|
464
|
-
*/
|
|
465
|
-
export function profile(operation: string) {
|
|
466
|
-
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
|
467
|
-
const originalMethod = descriptor.value;
|
|
468
|
-
|
|
469
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
470
|
-
descriptor.value = async function (this: any, ...args: any[]) {
|
|
471
|
-
const operationId = `${target.constructor.name}.${propertyKey}_${Date.now()}`;
|
|
472
|
-
|
|
473
|
-
dataTableDebugger.startOperation(operationId, operation, {
|
|
474
|
-
className: target.constructor.name,
|
|
475
|
-
methodName: propertyKey,
|
|
476
|
-
args: args.length,
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
try {
|
|
480
|
-
const result = await originalMethod.apply(this, args);
|
|
481
|
-
dataTableDebugger.endOperation(operationId, { success: true });
|
|
482
|
-
return result;
|
|
483
|
-
} catch (error) {
|
|
484
|
-
dataTableDebugger.endOperation(operationId, { success: false, error: error instanceof Error ? error.message : String(error) });
|
|
485
|
-
dataTableDebugger.log(DebugLevel.ERROR, 'Performance', `Operation failed: ${operation}`, error);
|
|
486
|
-
throw error;
|
|
487
|
-
}
|
|
488
|
-
};
|
|
489
|
-
|
|
490
|
-
return descriptor;
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
/**
|
|
495
|
-
* Memory monitoring utility
|
|
496
|
-
*/
|
|
497
|
-
export class MemoryMonitor {
|
|
498
|
-
private debuggerInstance: DataTableDebugger;
|
|
499
|
-
private intervalId: NodeJS.Timeout | null = null;
|
|
500
|
-
|
|
501
|
-
constructor(debuggerInstance: DataTableDebugger = dataTableDebugger) {
|
|
502
|
-
this.debuggerInstance = debuggerInstance;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
start(interval: number = 5000): void {
|
|
506
|
-
this.stop(); // Stop any existing monitoring
|
|
507
|
-
|
|
508
|
-
this.intervalId = setInterval(() => {
|
|
509
|
-
this.debuggerInstance.takeMemorySnapshot('periodic');
|
|
510
|
-
}, interval);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
stop(): void {
|
|
514
|
-
if (this.intervalId) {
|
|
515
|
-
clearInterval(this.intervalId);
|
|
516
|
-
this.intervalId = null;
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* Performance monitoring React hook
|
|
523
|
-
*/
|
|
524
|
-
export function usePerformanceDebugger(componentName: string) {
|
|
525
|
-
const startTime = React.useRef<number>(0);
|
|
526
|
-
|
|
527
|
-
React.useEffect(() => {
|
|
528
|
-
startTime.current = performance.now();
|
|
529
|
-
|
|
530
|
-
return () => {
|
|
531
|
-
const renderTime = performance.now() - startTime.current;
|
|
532
|
-
dataTableDebugger.trackRender(componentName, renderTime);
|
|
533
|
-
};
|
|
534
|
-
});
|
|
535
|
-
|
|
536
|
-
const trackOperation = React.useCallback((operation: string, fn: () => any) => {
|
|
537
|
-
const operationId = `${componentName}_${operation}_${Date.now()}`;
|
|
538
|
-
dataTableDebugger.startOperation(operationId, operation);
|
|
539
|
-
|
|
540
|
-
try {
|
|
541
|
-
const result = fn();
|
|
542
|
-
dataTableDebugger.endOperation(operationId);
|
|
543
|
-
return result;
|
|
544
|
-
} catch (error) {
|
|
545
|
-
dataTableDebugger.endOperation(operationId, { error: error instanceof Error ? error.message : String(error) });
|
|
546
|
-
throw error;
|
|
547
|
-
}
|
|
548
|
-
}, [componentName]);
|
|
549
|
-
|
|
550
|
-
return {
|
|
551
|
-
trackOperation,
|
|
552
|
-
log: (level: DebugLevel, message: string, data?: any) =>
|
|
553
|
-
dataTableDebugger.log(level, componentName, message, data),
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
/**
|
|
558
|
-
* Development tools integration
|
|
559
|
-
*/
|
|
560
|
-
export function setupDevTools(): void {
|
|
561
|
-
if (typeof window === 'undefined' || import.meta.env.MODE !== 'development') {
|
|
562
|
-
return;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// Expose debugger to global scope for browser dev tools
|
|
566
|
-
(window as any).__DATATABLE_DEBUGGER__ = dataTableDebugger;
|
|
567
|
-
|
|
568
|
-
// Add console commands
|
|
569
|
-
(window as any).dataTableDebug = {
|
|
570
|
-
getReport: () => dataTableDebugger.generateReport(),
|
|
571
|
-
exportData: () => dataTableDebugger.exportDebugData(),
|
|
572
|
-
clear: () => dataTableDebugger.clear(),
|
|
573
|
-
takeSnapshot: (label?: string) => dataTableDebugger.takeMemorySnapshot(label),
|
|
574
|
-
analyze: () => dataTableDebugger.analyzePerformance(),
|
|
575
|
-
};
|
|
576
|
-
|
|
577
|
-
console.log('DataTable Debug Tools loaded. Use window.dataTableDebug for debugging.');
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
/**
|
|
581
|
-
* Initialize debugging tools
|
|
582
|
-
*/
|
|
583
|
-
setupDevTools();
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Select Component Bug Reproduction Test
|
|
3
|
-
* @description Test to reproduce the search functionality bug
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import React from 'react';
|
|
7
|
-
import { screen, waitFor } from '@testing-library/react';
|
|
8
|
-
import userEvent from '@testing-library/user-event';
|
|
9
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
10
|
-
import {
|
|
11
|
-
Select,
|
|
12
|
-
SelectTrigger,
|
|
13
|
-
SelectValue,
|
|
14
|
-
SelectContent,
|
|
15
|
-
SelectItem
|
|
16
|
-
} from './Select';
|
|
17
|
-
import { renderWithProviders } from '../../__tests__/helpers/test-utils';
|
|
18
|
-
|
|
19
|
-
// Mock lucide-react icons
|
|
20
|
-
vi.mock('lucide-react', () => ({
|
|
21
|
-
Search: ({ className, ...props }: any) => <div data-testid="search-icon" className={className} {...props} />,
|
|
22
|
-
X: ({ className, ...props }: any) => <div data-testid="x-icon" className={className} {...props} />,
|
|
23
|
-
ChevronDown: ({ className, ...props }: any) => <div data-testid="chevron-down" className={className} {...props} />,
|
|
24
|
-
Check: ({ className, ...props }: any) => <div data-testid="check-icon" className={className} {...props} />,
|
|
25
|
-
}));
|
|
26
|
-
|
|
27
|
-
// Mock Button component
|
|
28
|
-
vi.mock('../Button/Button', () => ({
|
|
29
|
-
Button: React.forwardRef<HTMLButtonElement, any>(({ children, ...props }, ref) => (
|
|
30
|
-
<button ref={ref} {...props}>
|
|
31
|
-
{children}
|
|
32
|
-
</button>
|
|
33
|
-
)),
|
|
34
|
-
}));
|
|
35
|
-
|
|
36
|
-
// Mock cn utility
|
|
37
|
-
vi.mock('../../utils/cn', () => ({
|
|
38
|
-
cn: (...classes: any[]) => classes.filter(Boolean).join(' '),
|
|
39
|
-
}));
|
|
40
|
-
|
|
41
|
-
describe('Select Component Bug Reproduction', () => {
|
|
42
|
-
it('should open dropdown when searchable is true', async () => {
|
|
43
|
-
const user = userEvent.setup();
|
|
44
|
-
|
|
45
|
-
renderWithProviders(
|
|
46
|
-
<Select>
|
|
47
|
-
<SelectTrigger>
|
|
48
|
-
<SelectValue />
|
|
49
|
-
</SelectTrigger>
|
|
50
|
-
<SelectContent searchable>
|
|
51
|
-
<SelectItem value="test">Test Option</SelectItem>
|
|
52
|
-
</SelectContent>
|
|
53
|
-
</Select>
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const trigger = screen.getByTestId('select-trigger');
|
|
57
|
-
|
|
58
|
-
// Click to open the dropdown
|
|
59
|
-
await user.click(trigger);
|
|
60
|
-
|
|
61
|
-
// Wait for dropdown to open
|
|
62
|
-
await waitFor(() => {
|
|
63
|
-
expect(screen.getByTestId('select-content')).toBeInTheDocument();
|
|
64
|
-
}, { timeout: 2000 });
|
|
65
|
-
|
|
66
|
-
// Check if search input is rendered
|
|
67
|
-
expect(screen.getByTestId('select-search-input')).toBeInTheDocument();
|
|
68
|
-
});
|
|
69
|
-
});
|