Add browser caching
This commit is contained in:
parent
2dfcfaf48d
commit
46cacfc64b
3 changed files with 72 additions and 3 deletions
1
.cache/data.json
Normal file
1
.cache/data.json
Normal file
File diff suppressed because one or more lines are too long
BIN
.cache/timetracking.db
Normal file
BIN
.cache/timetracking.db
Normal file
Binary file not shown.
|
|
@ -156,11 +156,44 @@ const REPO_FILTER = import.meta.env.PUBLIC_REPO_FILTER || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchTimes() {
|
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 url = API_BASE + '/user/times?access_token=' + TOKEN + '&since=' + since;
|
||||||
var resp = await fetch(url);
|
var resp = await fetch(url);
|
||||||
if (!resp.ok) throw new Error('API error: ' + resp.status);
|
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() {
|
function getTodayStart() {
|
||||||
|
|
@ -180,6 +213,33 @@ const REPO_FILTER = import.meta.env.PUBLIC_REPO_FILTER || '';
|
||||||
return Date.UTC(now.getFullYear(), now.getMonth(), 1);
|
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() {
|
function getSinceDate() {
|
||||||
var now = new Date();
|
var now = new Date();
|
||||||
var d = new Date(Date.UTC(now.getFullYear(), now.getMonth(), 1));
|
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('loading').style.display = 'none';
|
||||||
document.getElementById('dashboard').style.display = 'block';
|
document.getElementById('dashboard').style.display = 'block';
|
||||||
} catch (err) {
|
} 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');
|
showError(err.message || 'Failed to fetch data');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue