window.Stats = { init: function () { this.update(History.entries); }, update: function (entries) { var stats = this.calculate(entries); this.render(stats); }, calculate: function (entries) { if (!entries || entries.length === 0) return null; var successful = entries.filter(function (e) { return e.status === 'success'; }); var total = entries.length; var durationValues = entries.map(function (e) { return e.duration || 0; }); // Count pass/fail/inconclusive var passCount = successful.filter(function (e) { return e.overallResult === 'pass'; }).length; var failCount = successful.filter(function (e) { return e.overallResult === 'fail'; }).length; // Collect all field keys seen across results var allFieldKeys = {}; for (var i = 0; i < successful.length; i++) { var fields = successful[i].result && successful[i].result.fields ? successful[i].result.fields : {}; var keys = Object.keys(fields); for (var k = 0; k < keys.length; k++) { allFieldKeys[keys[k]] = true; } } var fieldRates = {}; var fieldKeyList = Object.keys(allFieldKeys); for (var j = 0; j < fieldKeyList.length; j++) { var key = fieldKeyList[j]; fieldRates[key] = this._rate(successful, function (e) { return e.result && e.result.fields && e.result.fields[key] != null && e.result.fields[key] !== ''; }); } return { totalProcessed: total, successCount: successful.length, errorCount: total - successful.length, passCount: passCount, failCount: failCount, successRate: total > 0 ? successful.length / total : 0, avgDuration: this._avg(durationValues), fieldRates: fieldRates, fieldKeyList: fieldKeyList, }; }, _avg: function (values) { if (!values.length) return 0; return values.reduce(function (a, b) { return a + b; }, 0) / values.length; }, _rate: function (entries, predicate) { if (!entries.length) return 0; return entries.filter(predicate).length / entries.length; }, render: function (stats) { var hasStats = stats !== null; Utils.$('#stats-empty').classList.toggle('hidden', hasStats); Utils.$('#stats-data').classList.toggle('hidden', !hasStats); if (!hasStats) return; // Stat cards var cardsContainer = Utils.$('#stat-cards'); cardsContainer.innerHTML = ''; var cards = [ { value: stats.totalProcessed, label: 'Total Processed' }, { value: stats.passCount, label: 'Passed' }, { value: stats.failCount, label: 'Failed' }, { value: (stats.avgDuration / 1000).toFixed(1) + 's', label: 'Avg Duration' }, ]; for (var i = 0; i < cards.length; i++) { var card = document.createElement('div'); card.className = 'stat-card'; var val = document.createElement('div'); val.className = 'stat-value'; val.textContent = cards[i].value; var lbl = document.createElement('div'); lbl.className = 'stat-label'; lbl.textContent = cards[i].label; card.appendChild(val); card.appendChild(lbl); cardsContainer.appendChild(card); } // Field extraction rates var ratesContainer = Utils.$('#field-rates'); ratesContainer.innerHTML = ''; var fieldKeys = stats.fieldKeyList || []; for (var j = 0; j < fieldKeys.length; j++) { var key = fieldKeys[j]; var rate = stats.fieldRates[key] || 0; var row = document.createElement('div'); row.className = 'confidence-row'; var label = document.createElement('span'); label.className = 'confidence-label'; label.textContent = Utils.fieldLabel(key); var bar = document.createElement('div'); bar.className = 'confidence-bar'; var fill = document.createElement('div'); fill.className = 'confidence-fill ' + Utils.confidenceLevel(rate); fill.style.width = Utils.formatConfidence(rate); fill.textContent = Utils.formatConfidence(rate); bar.appendChild(fill); row.appendChild(label); row.appendChild(bar); ratesContainer.appendChild(row); } }, };