diff --git a/src/Managing.WebApp/src/pages/settingsPage/sqlmonitoring/sqlMonitoring.tsx b/src/Managing.WebApp/src/pages/settingsPage/sqlmonitoring/sqlMonitoring.tsx index 66a6750b..c8971164 100644 --- a/src/Managing.WebApp/src/pages/settingsPage/sqlmonitoring/sqlMonitoring.tsx +++ b/src/Managing.WebApp/src/pages/settingsPage/sqlmonitoring/sqlMonitoring.tsx @@ -16,42 +16,55 @@ const SqlMonitoring: React.FC = () => { const isLoading = isLoadingStats || isLoadingAlerts || isLoadingHealth - // Prepare statistics data for table - const statisticsData = React.useMemo(() => { - if (!statistics) return [] + // Prepare loop detection statistics data for table + const loopDetectionData = React.useMemo(() => { + if (!statistics?.loopDetectionStats) return [] - const stats: Array<{ - type: string - key: string - value: string - timestamp: string - }> = [] + return Object.entries(statistics.loopDetectionStats).map(([key, stat]) => { + // Helper function to safely convert time values to milliseconds + const getTimeInMs = (timeValue: any): number => { + if (typeof timeValue === 'number') return timeValue + if (typeof timeValue === 'string') { + // Handle TimeSpan serialization from C# (e.g., "00:00:01.234") + const match = timeValue.match(/(\d+):(\d+):(\d+)\.(\d+)/) + if (match) { + const [, hours, minutes, seconds, milliseconds] = match + return (parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseInt(seconds)) * 1000 + parseInt(milliseconds) + } + // Try to parse as number + const parsed = parseFloat(timeValue) + return isNaN(parsed) ? 0 : parsed + } + return 0 + } + + return { + id: key, + repository: stat.repositoryName || 'Unknown', + method: stat.methodName || 'Unknown', + queryPattern: stat.queryPattern || 'Unknown', + executionCount: Number(stat.executionCount) || 0, + executionsPerMinute: Number(stat.executionsPerMinute) || 0, + averageExecutionTime: getTimeInMs(stat.averageExecutionTime), + minExecutionTime: getTimeInMs(stat.minExecutionTime), + maxExecutionTime: getTimeInMs(stat.maxExecutionTime), + firstExecution: stat.firstExecution || '', + lastExecution: stat.lastExecution || '', + isActive: Boolean(stat.isActive), + } + }) + }, [statistics]) + + // Prepare context statistics data for table + const contextStatsData = React.useMemo(() => { + if (!statistics?.contextStats) return [] - // Add loop detection stats - if (statistics.loopDetectionStats) { - Object.entries(statistics.loopDetectionStats).forEach(([key, value]) => { - stats.push({ - type: 'Loop Detection', - key, - value: typeof value === 'object' ? JSON.stringify(value) : String(value), - timestamp: statistics.timestamp, - }) - }) - } - - // Add context stats - if (statistics.contextStats) { - Object.entries(statistics.contextStats).forEach(([key, value]) => { - stats.push({ - type: 'Context', - key, - value: String(value), - timestamp: statistics.timestamp, - }) - }) - } - - return stats + return Object.entries(statistics.contextStats).map(([queryPattern, count]) => ({ + id: queryPattern, + queryPattern: queryPattern.length > 50 ? `${queryPattern.substring(0, 50)}...` : queryPattern, + executionCount: count, + timestamp: statistics.timestamp, + })) }, [statistics]) // Prepare alerts data for table @@ -68,30 +81,132 @@ const SqlMonitoring: React.FC = () => { })) }, [alerts]) - // Define columns for statistics table - const statisticsColumns = React.useMemo( + // Define columns for loop detection table + const loopDetectionColumns = React.useMemo( () => [ { - Header: 'Type', - accessor: 'type', + Header: 'Repository', + accessor: 'repository', disableSortBy: true, disableFilters: true, }, { - Header: 'Key', - accessor: 'key', + Header: 'Method', + accessor: 'method', disableSortBy: true, disableFilters: true, }, { - Header: 'Value', - accessor: 'value', + Header: 'Query Pattern', + accessor: 'queryPattern', + Cell: ({ value }: { value: string }) => ( +
+ Simple execution count tracking for all query patterns +
+ {contextStatsData.length === 0 ? ( +