Add browser caching

This commit is contained in:
Oracle 2026-07-13 17:31:09 +02:00
parent 2dfcfaf48d
commit 46cacfc64b
Signed by: Oracle
SSH key fingerprint: SHA256:x4/RtnjUyuHkdvmwNDsWSfcfF1V5PNr3OpriZqOvCX8
3 changed files with 72 additions and 3 deletions

1
.cache/data.json Normal file

File diff suppressed because one or more lines are too long

BIN
.cache/timetracking.db Normal file

Binary file not shown.

View file

@ -156,11 +156,44 @@ const REPO_FILTER = import.meta.env.PUBLIC_REPO_FILTER || '';
}
async function fetchTimes() {
var since = getSinceDate();
var cached = loadCachedEntries();
var since;
if (cached && cached.length > 0) {
var latest = cached.reduce(function(max, e) {
return e.created > max ? e.created : max;
}, cached[0].created);
var d = new Date(latest);
d.setSeconds(d.getSeconds() - 1);
since = d.toISOString();
console.log('[fetch] latest cached entry: ' + latest + ', fetching since: ' + since);
} else {
since = getSinceDate();
console.log('[fetch] no cache, fetching full 12 months since: ' + since);
}
var url = API_BASE + '/user/times?access_token=' + TOKEN + '&since=' + since;
var resp = await fetch(url);
if (!resp.ok) throw new Error('API error: ' + resp.status);
return resp.json();
var newEntries = await resp.json();
console.log('[fetch] received ' + newEntries.length + ' entries from API');
if (cached && cached.length > 0) {
var before = cached.length;
var existingIds = {};
for (var i = 0; i < cached.length; i++) {
if (cached[i].id) existingIds[cached[i].id] = true;
}
for (var i = 0; i < newEntries.length; i++) {
if (!newEntries[i].id || !existingIds[newEntries[i].id]) {
cached.push(newEntries[i]);
}
}
console.log('[fetch] merged: ' + cached.length + ' total (' + (cached.length - before) + ' new)');
saveCachedEntries(cached);
return cached;
} else {
console.log('[fetch] storing ' + newEntries.length + ' entries as fresh cache');
saveCachedEntries(newEntries);
return newEntries;
}
}
function getTodayStart() {
@ -180,6 +213,33 @@ const REPO_FILTER = import.meta.env.PUBLIC_REPO_FILTER || '';
return Date.UTC(now.getFullYear(), now.getMonth(), 1);
}
const CACHE_KEY = 'timeTrackingEntries';
function loadCachedEntries() {
try {
var raw = localStorage.getItem(CACHE_KEY);
if (raw) {
var entries = JSON.parse(raw);
console.log('[cache] loaded ' + entries.length + ' entries from localStorage');
return entries;
}
console.log('[cache] no cached data found');
return null;
} catch(e) {
console.log('[cache] load error:', e);
return null;
}
}
function saveCachedEntries(entries) {
try {
localStorage.setItem(CACHE_KEY, JSON.stringify(entries));
console.log('[cache] saved ' + entries.length + ' entries to localStorage');
} catch(e) {
console.log('[cache] save error:', e);
}
}
function getSinceDate() {
var now = new Date();
var d = new Date(Date.UTC(now.getFullYear(), now.getMonth(), 1));
@ -421,7 +481,15 @@ const REPO_FILTER = import.meta.env.PUBLIC_REPO_FILTER || '';
document.getElementById('loading').style.display = 'none';
document.getElementById('dashboard').style.display = 'block';
} catch (err) {
console.error(err);
console.error('[fetch] API error:', err);
var cached = loadCachedEntries();
if (cached && cached.length > 0) {
console.log('[app] falling back to ' + cached.length + ' cached entries');
renderCharts(cached);
document.getElementById('loading').style.display = 'none';
document.getElementById('dashboard').style.display = 'block';
return;
}
showError(err.message || 'Failed to fetch data');
}
}