claude-usage-dashboard 1.5.4 → 1.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/public/js/app.js +47 -9
package/package.json
CHANGED
package/public/js/app.js
CHANGED
|
@@ -30,6 +30,32 @@ const state = {
|
|
|
30
30
|
let datePicker, planSelector;
|
|
31
31
|
let _cachedCycleData = null;
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Find a quota cycle whose period matches the selected date range.
|
|
35
|
+
* Returns the cycle's overall metrics, or null if no match.
|
|
36
|
+
* Tolerance: 25 hours (handles hour-level normalization and timezone offsets).
|
|
37
|
+
*/
|
|
38
|
+
function findMatchingCycle(dateRange, cycleData) {
|
|
39
|
+
if (!dateRange.from || !dateRange.to || !cycleData) return null;
|
|
40
|
+
const viewFrom = new Date(dateRange.from).getTime();
|
|
41
|
+
const viewTo = new Date(dateRange.to).getTime();
|
|
42
|
+
const tolerance = 25 * 60 * 60 * 1000;
|
|
43
|
+
|
|
44
|
+
const candidates = [];
|
|
45
|
+
if (cycleData.currentCycle) candidates.push(cycleData.currentCycle);
|
|
46
|
+
if (cycleData.history) candidates.push(...cycleData.history);
|
|
47
|
+
|
|
48
|
+
for (const c of candidates) {
|
|
49
|
+
if (!c.start || !c.resets_at || !c.overall?.tokens) continue;
|
|
50
|
+
const cStart = new Date(c.start).getTime();
|
|
51
|
+
const cEnd = new Date(c.resets_at).getTime();
|
|
52
|
+
if (Math.abs(viewFrom - cStart) < tolerance && Math.abs(viewTo - cEnd) < tolerance) {
|
|
53
|
+
return c.overall;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
33
59
|
function formatNumber(n) {
|
|
34
60
|
if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M';
|
|
35
61
|
if (n >= 1_000) return (n / 1_000).toFixed(0) + 'K';
|
|
@@ -144,18 +170,30 @@ async function loadAll() {
|
|
|
144
170
|
fetchCache(params),
|
|
145
171
|
]);
|
|
146
172
|
|
|
147
|
-
// Summary cards
|
|
173
|
+
// Summary cards — use multi-machine cycle data when date range matches a cycle
|
|
148
174
|
const t = usage.total;
|
|
149
|
-
|
|
175
|
+
let tokIn = t.input_tokens, tokOut = t.output_tokens;
|
|
176
|
+
let tokCR = t.cache_read_tokens, tokCW = t.cache_creation_tokens;
|
|
177
|
+
let apiCost = cost.api_equivalent_cost_usd;
|
|
178
|
+
const matchedCycle = findMatchingCycle(state.dateRange, _cachedCycleData);
|
|
179
|
+
if (matchedCycle?.tokens) {
|
|
180
|
+
tokIn = matchedCycle.tokens.input; tokOut = matchedCycle.tokens.output;
|
|
181
|
+
tokCR = matchedCycle.tokens.cacheRead; tokCW = matchedCycle.tokens.cacheCreation;
|
|
182
|
+
apiCost = matchedCycle.actualCost;
|
|
183
|
+
}
|
|
184
|
+
const totalAll = tokIn + tokOut + tokCR + tokCW;
|
|
150
185
|
document.getElementById('val-total-tokens').textContent = formatNumber(totalAll);
|
|
151
186
|
document.getElementById('sub-total-tokens').innerHTML =
|
|
152
|
-
`<span style="color:#4ade80">cache read:${formatNumber(
|
|
153
|
-
`<span style="color:#f59e0b">cache write:${formatNumber(
|
|
154
|
-
`<span style="color:#60a5fa">in:${formatNumber(
|
|
155
|
-
`<span style="color:#f97316">out:${formatNumber(
|
|
156
|
-
document.getElementById('val-api-cost').textContent = `$${
|
|
157
|
-
|
|
158
|
-
|
|
187
|
+
`<span style="color:#4ade80">cache read:${formatNumber(tokCR)}</span> · ` +
|
|
188
|
+
`<span style="color:#f59e0b">cache write:${formatNumber(tokCW)}</span> · ` +
|
|
189
|
+
`<span style="color:#60a5fa">in:${formatNumber(tokIn)}</span> · ` +
|
|
190
|
+
`<span style="color:#f97316">out:${formatNumber(tokOut)}</span>`;
|
|
191
|
+
document.getElementById('val-api-cost').textContent = `$${apiCost.toFixed(2)}`;
|
|
192
|
+
|
|
193
|
+
const totalInput = tokIn + tokCR + tokCW;
|
|
194
|
+
document.getElementById('val-cache-rate').textContent = totalInput > 0
|
|
195
|
+
? `${((tokCR / totalInput) * 100).toFixed(1)}%`
|
|
196
|
+
: `${(cache.cache_read_rate * 100).toFixed(1)}%`;
|
|
159
197
|
|
|
160
198
|
// Set active granularity button
|
|
161
199
|
const activeGran = usage.granularity;
|