mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-13 02:41:50 +08:00
feat: Enhance progress tracking and UI updates for dimension loading
This commit is contained in:
@@ -1953,20 +1953,101 @@
|
|||||||
if (!response.ok) throw new Error('Progress file not found');
|
if (!response.ok) throw new Error('Progress file not found');
|
||||||
|
|
||||||
const progress = await response.json();
|
const progress = await response.json();
|
||||||
updateProgressUI(progress);
|
|
||||||
|
|
||||||
// If complete, stop polling and load final results
|
// ✨ NEW: Load available dimensions incrementally and get actual count
|
||||||
|
const loadedCount = await loadAvailableDimensions();
|
||||||
|
|
||||||
|
// ✨ NEW: Update progress UI with actual file count
|
||||||
|
updateProgressUI(progress, loadedCount);
|
||||||
|
|
||||||
|
// If complete, stop polling
|
||||||
if (progress.phase === 'complete') {
|
if (progress.phase === 'complete') {
|
||||||
stopPolling();
|
stopPolling();
|
||||||
await loadFinalResults();
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading progress:', error);
|
console.error('Error loading progress:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✨ NEW: Load all available dimension files (even if review not complete)
|
||||||
|
async function loadAvailableDimensions() {
|
||||||
|
try {
|
||||||
|
// Load review state to get expected dimensions
|
||||||
|
const stateResponse = await fetch('./review-state.json');
|
||||||
|
if (!stateResponse.ok) return;
|
||||||
|
|
||||||
|
reviewState = await stateResponse.json();
|
||||||
|
document.getElementById('sessionId').textContent = reviewState.session_id;
|
||||||
|
|
||||||
|
// Try to load all expected dimensions
|
||||||
|
const allDimensions = reviewState.metadata?.dimensions ||
|
||||||
|
Object.keys(dimensionConfig);
|
||||||
|
|
||||||
|
const dimensionPromises = allDimensions.map(dim =>
|
||||||
|
fetch(`./dimensions/${dim}.json`)
|
||||||
|
.then(r => {
|
||||||
|
if (r.ok) return r.json();
|
||||||
|
return null; // Dimension not ready yet
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
// Silently skip dimensions that don't exist yet
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const dimensions = await Promise.all(dimensionPromises);
|
||||||
|
|
||||||
|
// Aggregate findings from completed dimensions
|
||||||
|
allFindings = [];
|
||||||
|
const loadedDimensions = [];
|
||||||
|
const severityCounts = { critical: 0, high: 0, medium: 0, low: 0 };
|
||||||
|
|
||||||
|
dimensions.forEach(dim => {
|
||||||
|
if (dim) {
|
||||||
|
// Handle both array and object formats
|
||||||
|
const dimData = Array.isArray(dim) ? dim[0] : dim;
|
||||||
|
|
||||||
|
if (dimData && dimData.findings) {
|
||||||
|
loadedDimensions.push(dimData.dimension);
|
||||||
|
|
||||||
|
// Aggregate findings
|
||||||
|
allFindings.push(...dimData.findings.map(f => ({
|
||||||
|
...f,
|
||||||
|
dimension: dimData.dimension
|
||||||
|
})));
|
||||||
|
|
||||||
|
// Aggregate severity counts
|
||||||
|
if (dimData.summary) {
|
||||||
|
severityCounts.critical += dimData.summary.critical || 0;
|
||||||
|
severityCounts.high += dimData.summary.high || 0;
|
||||||
|
severityCounts.medium += dimData.summary.medium || 0;
|
||||||
|
severityCounts.low += dimData.summary.low || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update severity counts with real data
|
||||||
|
if (loadedDimensions.length > 0) {
|
||||||
|
updateSeverityCounts(severityCounts);
|
||||||
|
updateDimensionSummary();
|
||||||
|
renderFindings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✨ NEW: Return loaded count for progress calculation
|
||||||
|
return {
|
||||||
|
loaded: loadedDimensions.length,
|
||||||
|
total: allDimensions.length,
|
||||||
|
findings: allFindings.length
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading available dimensions:', error);
|
||||||
|
return { loaded: 0, total: 7, findings: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update progress UI
|
// Update progress UI
|
||||||
function updateProgressUI(progress) {
|
function updateProgressUI(progress, loadedCount) {
|
||||||
document.getElementById('reviewId').textContent = progress.review_id || 'N/A';
|
document.getElementById('reviewId').textContent = progress.review_id || 'N/A';
|
||||||
document.getElementById('lastUpdate').textContent = new Date(progress.last_update).toLocaleString();
|
document.getElementById('lastUpdate').textContent = new Date(progress.last_update).toLocaleString();
|
||||||
|
|
||||||
@@ -1977,6 +2058,24 @@
|
|||||||
let percentComplete = 0;
|
let percentComplete = 0;
|
||||||
let progressText = '';
|
let progressText = '';
|
||||||
|
|
||||||
|
// ✨ NEW: Calculate progress based on actual loaded dimension files
|
||||||
|
if (loadedCount && loadedCount.total > 0) {
|
||||||
|
percentComplete = Math.round((loadedCount.loaded / loadedCount.total) * 100);
|
||||||
|
|
||||||
|
if (progress.phase === 'parallel' || progress.phase === 'aggregate') {
|
||||||
|
progressText = `Parallel Review: ${loadedCount.loaded}/${loadedCount.total} dimensions completed`;
|
||||||
|
if (loadedCount.findings > 0) {
|
||||||
|
progressText += ` • ${loadedCount.findings} finding${loadedCount.findings !== 1 ? 's' : ''} discovered`;
|
||||||
|
}
|
||||||
|
} else if (progress.phase === 'iterate' && progress.progress.deep_dive) {
|
||||||
|
percentComplete = progress.progress.deep_dive.percent_complete;
|
||||||
|
progressText = `Deep-Dive: ${progress.progress.deep_dive.analyzed}/${progress.progress.deep_dive.total_findings} findings analyzed`;
|
||||||
|
} else if (progress.phase === 'complete') {
|
||||||
|
percentComplete = 100;
|
||||||
|
progressText = `Review Complete • ${loadedCount.findings} total finding${loadedCount.findings !== 1 ? 's' : ''}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Fallback to original logic if loadedCount not available
|
||||||
if (progress.progress.parallel_review) {
|
if (progress.progress.parallel_review) {
|
||||||
percentComplete = progress.progress.parallel_review.percent_complete;
|
percentComplete = progress.progress.parallel_review.percent_complete;
|
||||||
progressText = `Parallel Review: ${progress.progress.parallel_review.completed}/${progress.progress.parallel_review.total_dimensions} dimensions`;
|
progressText = `Parallel Review: ${progress.progress.parallel_review.completed}/${progress.progress.parallel_review.total_dimensions} dimensions`;
|
||||||
@@ -1991,53 +2090,17 @@
|
|||||||
percentComplete = 100;
|
percentComplete = 100;
|
||||||
progressText = 'Review Complete';
|
progressText = 'Review Complete';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('progressFill').style.width = `${percentComplete}%`;
|
document.getElementById('progressFill').style.width = `${percentComplete}%`;
|
||||||
document.getElementById('progressText').textContent = progressText;
|
document.getElementById('progressText').textContent = progressText;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load final results
|
// Load final results (now delegates to loadAvailableDimensions)
|
||||||
async function loadFinalResults() {
|
async function loadFinalResults() {
|
||||||
try {
|
// ✨ NEW: This function now just ensures one final load
|
||||||
// Load review state
|
// since loadAvailableDimensions() handles all the heavy lifting
|
||||||
const stateResponse = await fetch('./review-state.json');
|
await loadAvailableDimensions();
|
||||||
reviewState = await stateResponse.json();
|
|
||||||
|
|
||||||
document.getElementById('sessionId').textContent = reviewState.session_id;
|
|
||||||
|
|
||||||
// Update severity counts
|
|
||||||
updateSeverityCounts(reviewState.severity_distribution);
|
|
||||||
|
|
||||||
// Load all dimension files
|
|
||||||
const dimensionPromises = reviewState.dimensions_reviewed.map(dim =>
|
|
||||||
fetch(`./dimensions/${dim}.json`)
|
|
||||||
.then(r => r.json())
|
|
||||||
.catch(err => {
|
|
||||||
console.error(`Failed to load ${dim}:`, err);
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const dimensions = await Promise.all(dimensionPromises);
|
|
||||||
|
|
||||||
// Aggregate all findings
|
|
||||||
allFindings = [];
|
|
||||||
dimensions.forEach(dim => {
|
|
||||||
if (dim && dim.findings) {
|
|
||||||
allFindings.push(...dim.findings.map(f => ({
|
|
||||||
...f,
|
|
||||||
dimension: dim.dimension
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update dimension summary table
|
|
||||||
updateDimensionSummary();
|
|
||||||
|
|
||||||
renderFindings();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error loading final results:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update severity counts
|
// Update severity counts
|
||||||
@@ -2082,10 +2145,12 @@
|
|||||||
dimensionStats[dim][severity]++;
|
dimensionStats[dim][severity]++;
|
||||||
}
|
}
|
||||||
dimensionStats[dim].total++;
|
dimensionStats[dim].total++;
|
||||||
|
// ✨ NEW: Mark as reviewed if we have findings from this dimension
|
||||||
|
dimensionStats[dim].reviewed = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check reviewed status from reviewState
|
// Also check reviewed status from reviewState (backward compatibility)
|
||||||
if (reviewState && reviewState.dimensions_reviewed) {
|
if (reviewState && reviewState.dimensions_reviewed) {
|
||||||
reviewState.dimensions_reviewed.forEach(dim => {
|
reviewState.dimensions_reviewed.forEach(dim => {
|
||||||
if (dimensionStats[dim]) {
|
if (dimensionStats[dim]) {
|
||||||
@@ -2106,9 +2171,21 @@
|
|||||||
return `<span class="count-badge ${severity}${zeroClass}">${count}</span>`;
|
return `<span class="count-badge ${severity}${zeroClass}">${count}</span>`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Status indicator
|
// ✨ NEW: Enhanced status indicator with 3 states
|
||||||
const statusClass = stats.reviewed ? 'reviewed' : 'pending';
|
let statusClass, statusIcon, statusTooltip;
|
||||||
const statusIcon = stats.reviewed ? '✓' : '○';
|
if (stats.reviewed && hasFindings) {
|
||||||
|
statusClass = 'reviewed';
|
||||||
|
statusIcon = '✓';
|
||||||
|
statusTooltip = 'Completed';
|
||||||
|
} else if (stats.reviewed && !hasFindings) {
|
||||||
|
statusClass = 'reviewed';
|
||||||
|
statusIcon = '✓';
|
||||||
|
statusTooltip = 'Completed (no findings)';
|
||||||
|
} else {
|
||||||
|
statusClass = 'pending';
|
||||||
|
statusIcon = '⏳';
|
||||||
|
statusTooltip = 'Processing...';
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<tr onclick="filterByDimension('${dim}')" style="cursor: pointer;">
|
<tr onclick="filterByDimension('${dim}')" style="cursor: pointer;">
|
||||||
@@ -2123,7 +2200,7 @@
|
|||||||
<td>${createCountBadge(stats.medium, 'medium')}</td>
|
<td>${createCountBadge(stats.medium, 'medium')}</td>
|
||||||
<td>${createCountBadge(stats.low, 'low')}</td>
|
<td>${createCountBadge(stats.low, 'low')}</td>
|
||||||
<td><span class="count-badge total">${stats.total}</span></td>
|
<td><span class="count-badge total">${stats.total}</span></td>
|
||||||
<td><span class="status-indicator ${statusClass}">${statusIcon}</span></td>
|
<td><span class="status-indicator ${statusClass}" title="${statusTooltip}">${statusIcon}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|||||||
Reference in New Issue
Block a user