diff --git a/app/api/routes.py b/app/api/routes.py index f7755a9..74db50c 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -744,6 +744,16 @@ async def get_workload_historical_metrics( "limits_percent": round(memory_limits_percent, 2), "efficiency_percent": round(memory_efficiency, 1) } + }, + "promql_queries": { + "cluster_cpu_total": cluster_cpu_query, + "cluster_memory_total": cluster_memory_query, + "cpu_usage": cpu_usage_query, + "memory_usage": memory_usage_query, + "cpu_requests": cpu_requests_query, + "memory_requests": memory_requests_query, + "cpu_limits": cpu_limits_query, + "memory_limits": memory_limits_query } } except Exception as e: diff --git a/app/static/index.html b/app/static/index.html index 1e6dfb2..4be5a1d 100644 --- a/app/static/index.html +++ b/app/static/index.html @@ -781,6 +781,86 @@ flex-direction: column; } } + + /* PromQL Queries Styles */ + .promql-queries { + margin-top: 30px; + padding: 20px; + background: #f8f9fa; + border-radius: 8px; + border: 1px solid #dee2e6; + } + + .promql-queries h4 { + color: #495057; + margin-bottom: 15px; + font-size: 1.1rem; + } + + .promql-queries h5 { + color: #6c757d; + margin: 20px 0 10px 0; + font-size: 1rem; + font-weight: 600; + } + + .query-section { + margin-bottom: 25px; + } + + .query-item { + margin-bottom: 15px; + } + + .query-item label { + display: block; + font-weight: 600; + color: #495057; + margin-bottom: 5px; + font-size: 0.9rem; + } + + .query-box { + display: flex; + align-items: center; + background: white; + border: 1px solid #ced4da; + border-radius: 4px; + padding: 8px 12px; + gap: 10px; + } + + .query-box code { + flex: 1; + background: none; + border: none; + padding: 0; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 0.85rem; + color: #e83e8c; + word-break: break-all; + white-space: pre-wrap; + } + + .copy-btn { + background: #007bff; + color: white; + border: none; + border-radius: 4px; + padding: 6px 12px; + font-size: 0.8rem; + cursor: pointer; + transition: background-color 0.2s; + white-space: nowrap; + } + + .copy-btn:hover { + background: #0056b3; + } + + .copy-btn:active { + background: #004085; + } @@ -1614,6 +1694,85 @@ + + ${data.promql_queries ? ` +
+

🔍 PromQL Queries Used

+

Copy these queries to validate in OpenShift Console → Monitoring → Metrics:

+ +
+
Cluster Total Resources:
+
+ +
+ ${data.promql_queries.cluster_cpu_total} + +
+
+
+ +
+ ${data.promql_queries.cluster_memory_total} + +
+
+
+ +
+
Workload Resource Usage:
+
+ +
+ ${data.promql_queries.cpu_usage} + +
+
+
+ +
+ ${data.promql_queries.memory_usage} + +
+
+
+ +
+
Workload Resource Requests:
+
+ +
+ ${data.promql_queries.cpu_requests} + +
+
+
+ +
+ ${data.promql_queries.memory_requests} + +
+
+
+ +
+
Workload Resource Limits:
+
+ +
+ ${data.promql_queries.cpu_limits} + +
+
+
+ +
+ ${data.promql_queries.memory_limits} + +
+
+
+
+ ` : ''} `; } @@ -1644,6 +1803,40 @@ URL.revokeObjectURL(url); } + // Copy to clipboard function for PromQL queries + async function copyToClipboard(text) { + try { + await navigator.clipboard.writeText(text); + // Show a brief success message + const button = event.target; + const originalText = button.textContent; + button.textContent = '✅ Copied!'; + button.style.background = '#28a745'; + setTimeout(() => { + button.textContent = originalText; + button.style.background = ''; + }, 2000); + } catch (err) { + console.error('Failed to copy text: ', err); + // Fallback for older browsers + const textArea = document.createElement('textarea'); + textArea.value = text; + document.body.appendChild(textArea); + textArea.select(); + document.execCommand('copy'); + document.body.removeChild(textArea); + + const button = event.target; + const originalText = button.textContent; + button.textContent = '✅ Copied!'; + button.style.background = '#28a745'; + setTimeout(() => { + button.textContent = originalText; + button.style.background = ''; + }, 2000); + } + } + // Utility functions function showLoading() { document.getElementById('problemTableBody').innerHTML =