ui: cache derived usage views

This commit is contained in:
a.tolmachev
2026-05-02 15:02:28 +00:00
parent 9a83cee84d
commit 6c98cc6917
+40 -13
View File
@@ -3,6 +3,12 @@ document.addEventListener('DOMContentLoaded', function () {
period: '7d',
workspaceId: null,
usage: null,
derived: {
localizedOperations: [],
normalizedTimeline: [],
timelineMaxValue: 0,
totalCalls: 0,
},
loading: false,
loadError: '',
};
@@ -203,6 +209,29 @@ document.addEventListener('DOMContentLoaded', function () {
return normalized;
}
function recomputeDerivedState() {
var operations = state.usage ? (state.usage.operations || []) : [];
var timeline = state.usage ? normalizeTimeline(state.usage.timeline || [], state.period) : [];
var totalCalls = operations.reduce(function (sum, operation) {
return sum + operation.calls_total;
}, 0);
var timelineMaxValue = timeline.reduce(function (maxValue, point) {
return Math.max(maxValue, point.calls_ok + point.calls_error);
}, 0);
state.derived = {
localizedOperations: operations.map(function (operation) {
return {
operation: operation,
localized: localizedUsageOperation(operation),
};
}),
normalizedTimeline: timeline,
timelineMaxValue: timelineMaxValue,
totalCalls: totalCalls,
};
}
function buildEmptyState(title, message, compact) {
var empty = element('div', 'empty-state');
if (compact) {
@@ -263,7 +292,7 @@ document.addEventListener('DOMContentLoaded', function () {
}
function renderChart() {
var timeline = state.usage ? normalizeTimeline(state.usage.timeline || [], state.period) : [];
var timeline = state.derived.normalizedTimeline;
chartWrap.innerHTML = '';
if (!timeline.length) {
@@ -277,9 +306,7 @@ document.addEventListener('DOMContentLoaded', function () {
return;
}
var maxValue = Math.max.apply(null, timeline.map(function (point) {
return point.calls_ok + point.calls_error;
}));
var maxValue = state.derived.timelineMaxValue;
timeline.forEach(function (point, index) {
var node = chartTemplate.content.cloneNode(true);
@@ -301,7 +328,7 @@ document.addEventListener('DOMContentLoaded', function () {
}
function renderTable() {
var operations = state.usage ? state.usage.operations : [];
var operations = state.derived.localizedOperations;
tableBody.innerHTML = '';
if (!operations.length) {
@@ -321,19 +348,16 @@ document.addEventListener('DOMContentLoaded', function () {
return;
}
var totalCalls = operations.reduce(function (sum, operation) {
return sum + operation.calls_total;
}, 0);
operations.forEach(function (operation) {
var localizedOperation = localizedUsageOperation(operation);
operations.forEach(function (entry) {
var operation = entry.operation;
var localizedOperation = entry.localized;
var node = rowTemplate.content.cloneNode(true);
var errorRate = operation.calls_total === 0
? 0
: ((operation.calls_error / operation.calls_total) * 100);
var share = totalCalls === 0
var share = state.derived.totalCalls === 0
? 0
: ((operation.calls_total / totalCalls) * 100);
: ((operation.calls_total / state.derived.totalCalls) * 100);
node.querySelector('.col-name').textContent = localizedOperation.operation_display_name || operation.operation_display_name;
node.querySelector('.col-op-slug').textContent = operation.operation_name;
@@ -404,8 +428,11 @@ document.addEventListener('DOMContentLoaded', function () {
try {
state.usage = await window.CrankApi.getUsageOverview(state.workspaceId, { period: state.period });
recomputeDerivedState();
} catch (error) {
state.loadError = error.message || tKey('usage.error.load');
state.usage = null;
recomputeDerivedState();
} finally {
state.loading = false;
renderUsage();