feat: implement accordion for historical analysis with real data
- Add expandable rows in historical analysis table - Implement accordion functionality with chevron icons - Load real CPU and memory data from API endpoint - Display current, average, and peak usage with progress bars - Show recommendations based on historical data - Improve UX with inline details instead of separate cards
This commit is contained in:
@@ -516,6 +516,33 @@
|
||||
.section-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Accordion Styles */
|
||||
.expand-button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--pf-global--Color--100);
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.expand-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.workload-details-row {
|
||||
background-color: #1A1A1A;
|
||||
}
|
||||
|
||||
.workload-details-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.workload-row:hover {
|
||||
background-color: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -910,6 +937,7 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 30px;"></th>
|
||||
<th>Workload</th>
|
||||
<th>Namespace</th>
|
||||
<th>Pods</th>
|
||||
@@ -920,8 +948,13 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${data.workloads.map(workload => `
|
||||
<tr>
|
||||
${data.workloads.map((workload, index) => `
|
||||
<tr class="workload-row" data-workload="${workload.name}" data-namespace="${workload.namespace}">
|
||||
<td>
|
||||
<button class="expand-button" onclick="toggleWorkloadDetails(${index})" id="expand-btn-${index}">
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<strong style="color: var(--pf-global--Color--100);">${workload.name}</strong>
|
||||
</td>
|
||||
@@ -931,12 +964,22 @@
|
||||
<td>${workload.memory_usage || 'N/A'}</td>
|
||||
<td>${workload.last_updated ? new Date(workload.last_updated).toLocaleString() : 'N/A'}</td>
|
||||
<td>
|
||||
<button class="openshift-button" onclick="showWorkloadDetails('${workload.name}', '${workload.namespace}')">
|
||||
<i class="fas fa-eye"></i>
|
||||
View Details
|
||||
<button class="openshift-button" onclick="loadWorkloadDetails('${workload.name}', '${workload.namespace}', ${index})">
|
||||
<i class="fas fa-chart-line"></i>
|
||||
Load Details
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="workload-details-row" id="details-${index}" style="display: none;">
|
||||
<td colspan="8">
|
||||
<div class="workload-details-container" id="details-content-${index}">
|
||||
<div class="loading-spinner">
|
||||
<div class="spinner"></div>
|
||||
Loading workload details...
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -970,6 +1013,169 @@
|
||||
}
|
||||
}
|
||||
|
||||
function toggleWorkloadDetails(index) {
|
||||
const detailsRow = document.getElementById(`details-${index}`);
|
||||
const expandBtn = document.getElementById(`expand-btn-${index}`);
|
||||
const icon = expandBtn.querySelector('i');
|
||||
|
||||
if (detailsRow.style.display === 'none') {
|
||||
detailsRow.style.display = 'table-row';
|
||||
icon.classList.remove('fa-chevron-right');
|
||||
icon.classList.add('fa-chevron-down');
|
||||
} else {
|
||||
detailsRow.style.display = 'none';
|
||||
icon.classList.remove('fa-chevron-down');
|
||||
icon.classList.add('fa-chevron-right');
|
||||
}
|
||||
}
|
||||
|
||||
async function loadWorkloadDetails(workloadName, namespace, index) {
|
||||
const container = document.getElementById(`details-content-${index}`);
|
||||
|
||||
try {
|
||||
container.innerHTML = `
|
||||
<div class="loading-spinner">
|
||||
<div class="spinner"></div>
|
||||
Loading workload details...
|
||||
</div>
|
||||
`;
|
||||
|
||||
const response = await fetch(`/api/v1/historical-analysis/${namespace}/${workloadName}`);
|
||||
const data = await response.json();
|
||||
|
||||
updateWorkloadDetailsAccordion(data, index);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading workload details:', error);
|
||||
container.innerHTML = `
|
||||
<div style="text-align: center; padding: 40px; color: var(--pf-global--danger-color--100);">
|
||||
<i class="fas fa-exclamation-triangle" style="font-size: 48px; margin-bottom: 16px;"></i>
|
||||
<h3 style="margin: 0 0 8px 0; color: var(--pf-global--Color--100);">Error</h3>
|
||||
<p style="margin: 0;">Failed to load workload details</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function updateWorkloadDetailsAccordion(data, index) {
|
||||
const container = document.getElementById(`details-content-${index}`);
|
||||
|
||||
// Parse CPU and Memory data
|
||||
const cpuData = data.cpu_data || {};
|
||||
const memoryData = data.memory_data || {};
|
||||
const recommendations = data.recommendations || [];
|
||||
|
||||
container.innerHTML = `
|
||||
<div style="padding: 24px; background-color: #1E1E1E; border-radius: 8px; margin: 16px 0;">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 24px;">
|
||||
<div class="openshift-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
<i class="fas fa-microchip" style="margin-right: 8px; color: var(--pf-global--info-color--100);"></i>
|
||||
CPU Usage
|
||||
</h3>
|
||||
</div>
|
||||
<div style="padding: 20px;">
|
||||
${cpuData.current ? `
|
||||
<div style="margin-bottom: 16px;">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
|
||||
<span>Current Usage:</span>
|
||||
<strong style="color: var(--pf-global--Color--100);">${cpuData.current} cores</strong>
|
||||
</div>
|
||||
<div style="background-color: #404040; height: 8px; border-radius: 4px; overflow: hidden;">
|
||||
<div style="background-color: var(--pf-global--info-color--100); height: 100%; width: ${Math.min((cpuData.current / (cpuData.limit || 1)) * 100, 100)}%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
${cpuData.average ? `
|
||||
<div style="margin-bottom: 16px;">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
|
||||
<span>Average (24h):</span>
|
||||
<strong style="color: var(--pf-global--Color--100);">${cpuData.average} cores</strong>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
${cpuData.peak ? `
|
||||
<div style="margin-bottom: 16px;">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
|
||||
<span>Peak (24h):</span>
|
||||
<strong style="color: var(--pf-global--warning-color--100);">${cpuData.peak} cores</strong>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
${!cpuData.current && !cpuData.average && !cpuData.peak ? `
|
||||
<div style="text-align: center; color: var(--pf-global--Color--300);">
|
||||
<i class="fas fa-chart-line" style="font-size: 32px; margin-bottom: 8px; color: var(--pf-global--Color--400);"></i>
|
||||
<p>CPU usage data not available</p>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="openshift-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
<i class="fas fa-memory" style="margin-right: 8px; color: var(--pf-global--warning-color--100);"></i>
|
||||
Memory Usage
|
||||
</h3>
|
||||
</div>
|
||||
<div style="padding: 20px;">
|
||||
${memoryData.current ? `
|
||||
<div style="margin-bottom: 16px;">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
|
||||
<span>Current Usage:</span>
|
||||
<strong style="color: var(--pf-global--Color--100);">${memoryData.current}</strong>
|
||||
</div>
|
||||
<div style="background-color: #404040; height: 8px; border-radius: 4px; overflow: hidden;">
|
||||
<div style="background-color: var(--pf-global--warning-color--100); height: 100%; width: ${Math.min((memoryData.current_bytes / (memoryData.limit_bytes || 1)) * 100, 100)}%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
${memoryData.average ? `
|
||||
<div style="margin-bottom: 16px;">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
|
||||
<span>Average (24h):</span>
|
||||
<strong style="color: var(--pf-global--Color--100);">${memoryData.average}</strong>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
${memoryData.peak ? `
|
||||
<div style="margin-bottom: 16px;">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
|
||||
<span>Peak (24h):</span>
|
||||
<strong style="color: var(--pf-global--danger-color--100);">${memoryData.peak}</strong>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
${!memoryData.current && !memoryData.average && !memoryData.peak ? `
|
||||
<div style="text-align: center; color: var(--pf-global--Color--300);">
|
||||
<i class="fas fa-chart-line" style="font-size: 32px; margin-bottom: 8px; color: var(--pf-global--Color--400);"></i>
|
||||
<p>Memory usage data not available</p>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${recommendations.length > 0 ? `
|
||||
<div class="openshift-card" style="margin-top: 24px;">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
<i class="fas fa-lightbulb" style="margin-right: 8px; color: var(--pf-global--success-color--100);"></i>
|
||||
Recommendations
|
||||
</h3>
|
||||
</div>
|
||||
<div style="padding: 20px;">
|
||||
<ul style="margin: 0; padding-left: 20px;">
|
||||
${recommendations.map(rec => `<li style="margin-bottom: 8px; color: var(--pf-global--Color--200);">${rec}</li>`).join('')}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function updateWorkloadDetails(data) {
|
||||
const container = document.getElementById('workload-details-content');
|
||||
|
||||
@@ -982,20 +1188,20 @@
|
||||
<div style="padding: 20px; text-align: center; color: var(--pf-global--Color--300);">
|
||||
<i class="fas fa-microchip" style="font-size: 48px; margin-bottom: 16px; color: var(--pf-global--info-color--100);"></i>
|
||||
<p>CPU usage data will be displayed here</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openshift-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Memory Usage</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding: 20px; text-align: center; color: var(--pf-global--Color--300);">
|
||||
<i class="fas fa-memory" style="font-size: 48px; margin-bottom: 16px; color: var(--pf-global--warning-color--100);"></i>
|
||||
<p>Memory usage data will be displayed here</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function analyzeWorkload(namespace) {
|
||||
console.log('Analyzing workload:', namespace);
|
||||
|
||||
Reference in New Issue
Block a user