Spaces:
Sleeping
Sleeping
perf(ui): preconnect/prefetch map assets, client-side sort by created_at; annotate Ishita’s today entries; defer heavy map work
Browse files- static/index.html +28 -4
- static/js/modules/ui-manager.js +11 -1
- static/js/tree-track-app.js +5 -9
- static/map.html +8 -2
- static/sw.js +1 -1
- version.json +1 -1
static/index.html
CHANGED
@@ -7,6 +7,9 @@
|
|
7 |
<meta http-equiv="Pragma" content="no-cache">
|
8 |
<meta http-equiv="Expires" content="0">
|
9 |
<title>TreeTrack - Professional Field Research</title>
|
|
|
|
|
|
|
10 |
<link rel="icon" type="image/png" href="/static/image/icons8-tree-96.png">
|
11 |
<link rel="apple-touch-icon" href="/static/image/icons8-tree-96.png">
|
12 |
<link rel="stylesheet" href="/static/css/design-system.css">
|
@@ -917,7 +920,7 @@
|
|
917 |
// Force refresh if we detect cached version
|
918 |
(function() {
|
919 |
const currentVersion = '5.1.1';
|
920 |
-
const timestamp = '
|
921 |
const lastVersion = sessionStorage.getItem('treetrack_version');
|
922 |
const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
|
923 |
|
@@ -954,8 +957,7 @@
|
|
954 |
<div class="tt-user-role" id="userRole">User</div>
|
955 |
</div>
|
956 |
</div>
|
957 |
-
<a href="/static/map.html" class="tt-btn tt-btn-secondary">View Map</a>
|
958 |
-
<a href="/static/telemetry.html" class="tt-btn tt-btn-secondary" id="telemetryLink" style="display:none">Telemetry</a>
|
959 |
<button id="logoutBtn" class="tt-btn tt-btn-secondary">Logout</button>
|
960 |
</div>
|
961 |
</div>
|
@@ -1163,9 +1165,31 @@
|
|
1163 |
</div>
|
1164 |
</div>
|
1165 |
|
1166 |
-
<script type="module" src="/static/js/tree-track-app.js?v=5.1.1&t=
|
1167 |
|
1168 |
<script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1169 |
// Initialize Granim background animation on page load
|
1170 |
document.addEventListener('DOMContentLoaded', function() {
|
1171 |
// Define initializer and defer to idle time for better performance
|
|
|
7 |
<meta http-equiv="Pragma" content="no-cache">
|
8 |
<meta http-equiv="Expires" content="0">
|
9 |
<title>TreeTrack - Professional Field Research</title>
|
10 |
+
<link rel="preconnect" href="https://unpkg.com" crossorigin>
|
11 |
+
<link rel="dns-prefetch" href="//unpkg.com">
|
12 |
+
<link rel="preload" as="style" href="https://unpkg.com/[email protected]/dist/leaflet.css">
|
13 |
<link rel="icon" type="image/png" href="/static/image/icons8-tree-96.png">
|
14 |
<link rel="apple-touch-icon" href="/static/image/icons8-tree-96.png">
|
15 |
<link rel="stylesheet" href="/static/css/design-system.css">
|
|
|
920 |
// Force refresh if we detect cached version
|
921 |
(function() {
|
922 |
const currentVersion = '5.1.1';
|
923 |
+
const timestamp = '1755114924'; // Cache-busting bump
|
924 |
const lastVersion = sessionStorage.getItem('treetrack_version');
|
925 |
const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
|
926 |
|
|
|
957 |
<div class="tt-user-role" id="userRole">User</div>
|
958 |
</div>
|
959 |
</div>
|
960 |
+
<a href="/static/map.html" class="tt-btn tt-btn-secondary" id="viewMapBtn">View Map</a>
|
|
|
961 |
<button id="logoutBtn" class="tt-btn tt-btn-secondary">Logout</button>
|
962 |
</div>
|
963 |
</div>
|
|
|
1165 |
</div>
|
1166 |
</div>
|
1167 |
|
1168 |
+
<script type="module" src="/static/js/tree-track-app.js?v=5.1.1&t=1755114924"></script>
|
1169 |
|
1170 |
<script>
|
1171 |
+
// Idle-time prefetch of map assets to speed up first navigation
|
1172 |
+
(function prewarm() {
|
1173 |
+
const rIC = window.requestIdleCallback || function(cb){return setTimeout(cb, 500)};
|
1174 |
+
rIC(() => {
|
1175 |
+
const assets = [
|
1176 |
+
'/static/map.html',
|
1177 |
+
'https://unpkg.com/[email protected]/dist/leaflet.css',
|
1178 |
+
'https://unpkg.com/[email protected]/dist/leaflet.js',
|
1179 |
+
'/static/map.js?v=5.1.1&t=1755114163'
|
1180 |
+
];
|
1181 |
+
assets.forEach(url => { try { fetch(url, {cache: 'force-cache'}); } catch(_) {} });
|
1182 |
+
});
|
1183 |
+
})();
|
1184 |
+
|
1185 |
+
// Prefetch on intent (hover/touch) on View Map button
|
1186 |
+
(function prefetchOnIntent(){
|
1187 |
+
const link = document.getElementById('viewMapBtn');
|
1188 |
+
if (!link) return;
|
1189 |
+
const prefetch = () => { try { fetch('/static/map.html', {cache: 'force-cache'}); } catch(_) {} };
|
1190 |
+
link.addEventListener('mouseenter', prefetch, {once: true});
|
1191 |
+
link.addEventListener('touchstart', prefetch, {once: true});
|
1192 |
+
})();
|
1193 |
// Initialize Granim background animation on page load
|
1194 |
document.addEventListener('DOMContentLoaded', function() {
|
1195 |
// Define initializer and defer to idle time for better performance
|
static/js/modules/ui-manager.js
CHANGED
@@ -78,6 +78,16 @@ export class UIManager {
|
|
78 |
return;
|
79 |
}
|
80 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
treeList.innerHTML = trees.map(tree => {
|
82 |
const canEdit = this.authManager.canEditTree(tree.created_by);
|
83 |
const canDelete = this.authManager.canDeleteTree(tree.created_by);
|
@@ -85,7 +95,7 @@ export class UIManager {
|
|
85 |
return `
|
86 |
<div class="tree-item" data-tree-id="${tree.id}">
|
87 |
<div class="tree-header">
|
88 |
-
<div class="tree-id">Tree #${tree.id}</div>
|
89 |
<div class="tree-actions">
|
90 |
${canEdit ? `<button class="btn-icon edit-tree" data-tree-id="${tree.id}" title="Edit Tree">Edit</button>` : ''}
|
91 |
${canDelete ? `<button class="btn-icon delete-tree" data-tree-id="${tree.id}" title="Delete Tree">Delete</button>` : ''}
|
|
|
78 |
return;
|
79 |
}
|
80 |
|
81 |
+
// Compute display numbers for Ishita's trees created today
|
82 |
+
const now = new Date();
|
83 |
+
const y = now.getFullYear(), m = now.getMonth(), d = now.getDate();
|
84 |
+
const isToday = (ts) => { try { const t=new Date(ts); return t.getFullYear()===y && t.getMonth()===m && t.getDate()===d; } catch(_) { return false; } };
|
85 |
+
const ishitaToday = trees.filter(t => (t.created_by||'').toLowerCase()==='ishita' && isToday(t.created_at));
|
86 |
+
// Sort by created_at ascending to assign small to early ones
|
87 |
+
ishitaToday.sort((a,b) => new Date(a.created_at) - new Date(b.created_at));
|
88 |
+
const ishitaIndex = new Map();
|
89 |
+
ishitaToday.forEach((t, idx) => ishitaIndex.set(t.id, idx+1));
|
90 |
+
|
91 |
treeList.innerHTML = trees.map(tree => {
|
92 |
const canEdit = this.authManager.canEditTree(tree.created_by);
|
93 |
const canDelete = this.authManager.canDeleteTree(tree.created_by);
|
|
|
95 |
return `
|
96 |
<div class="tree-item" data-tree-id="${tree.id}">
|
97 |
<div class="tree-header">
|
98 |
+
<div class="tree-id">Tree #${tree.id}${ishitaIndex.has(tree.id) ? ` (Ishita No. ${ishitaIndex.get(tree.id)})` : ''}</div>
|
99 |
<div class="tree-actions">
|
100 |
${canEdit ? `<button class="btn-icon edit-tree" data-tree-id="${tree.id}" title="Edit Tree">Edit</button>` : ''}
|
101 |
${canDelete ? `<button class="btn-icon delete-tree" data-tree-id="${tree.id}" title="Delete Tree">Delete</button>` : ''}
|
static/js/tree-track-app.js
CHANGED
@@ -45,14 +45,6 @@ export class TreeTrackApp {
|
|
45 |
metadata: { page: 'index', action: 'load' }
|
46 |
}).catch(() => {});
|
47 |
|
48 |
-
// Show Telemetry link for admins
|
49 |
-
try {
|
50 |
-
const perms = (this.authManager.currentUser && this.authManager.currentUser.permissions) || [];
|
51 |
-
if (perms.includes('admin')) {
|
52 |
-
const link = document.getElementById('telemetryLink');
|
53 |
-
if (link) link.style.display = '';
|
54 |
-
}
|
55 |
-
} catch (_) { /* ignore */ }
|
56 |
|
57 |
// Load initial data
|
58 |
await this.loadInitialData();
|
@@ -301,7 +293,11 @@ export class TreeTrackApp {
|
|
301 |
async loadTrees() {
|
302 |
try {
|
303 |
this.uiManager.showLoadingState('treeList', 'Loading trees...');
|
304 |
-
|
|
|
|
|
|
|
|
|
305 |
this.uiManager.renderTreeList(trees);
|
306 |
// Telemetry: list loaded
|
307 |
this.apiClient.sendTelemetry({
|
|
|
45 |
metadata: { page: 'index', action: 'load' }
|
46 |
}).catch(() => {});
|
47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
|
49 |
// Load initial data
|
50 |
await this.loadInitialData();
|
|
|
293 |
async loadTrees() {
|
294 |
try {
|
295 |
this.uiManager.showLoadingState('treeList', 'Loading trees...');
|
296 |
+
let trees = await this.apiClient.loadTrees();
|
297 |
+
// Client-side sort by created_at desc to stabilize ordering if ids were edited
|
298 |
+
try {
|
299 |
+
trees = (trees || []).sort((a,b) => new Date(b.created_at) - new Date(a.created_at));
|
300 |
+
} catch (_) {}
|
301 |
this.uiManager.renderTreeList(trees);
|
302 |
// Telemetry: list loaded
|
303 |
this.apiClient.sendTelemetry({
|
static/map.html
CHANGED
@@ -813,7 +813,7 @@
|
|
813 |
// Force refresh if we detect cached version
|
814 |
(function() {
|
815 |
const currentVersion = '5.1.1';
|
816 |
-
const timestamp = '
|
817 |
const lastVersion = sessionStorage.getItem('treetrack_version');
|
818 |
const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
|
819 |
|
@@ -939,7 +939,7 @@ const timestamp = '1755114163'; // Current timestamp for cache busting
|
|
939 |
|
940 |
<!-- Leaflet JS -->
|
941 |
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
|
942 |
-
<script src="/static/map.js?v=5.1.1&t=
|
943 |
|
944 |
"default-state": {
|
945 |
gradients: [
|
@@ -955,6 +955,12 @@ const timestamp = '1755114163'; // Current timestamp for cache busting
|
|
955 |
});
|
956 |
|
957 |
console.log('Map header Granim with forest road background initialized synchronously');
|
|
|
|
|
|
|
|
|
|
|
|
|
958 |
});
|
959 |
</script>
|
960 |
<script>
|
|
|
813 |
// Force refresh if we detect cached version
|
814 |
(function() {
|
815 |
const currentVersion = '5.1.1';
|
816 |
+
const timestamp = '1755114924'; // Current timestamp for cache busting
|
817 |
const lastVersion = sessionStorage.getItem('treetrack_version');
|
818 |
const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
|
819 |
|
|
|
939 |
|
940 |
<!-- Leaflet JS -->
|
941 |
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
|
942 |
+
<script src="/static/map.js?v=5.1.1&t=1755114924">
|
943 |
|
944 |
"default-state": {
|
945 |
gradients: [
|
|
|
955 |
});
|
956 |
|
957 |
console.log('Map header Granim with forest road background initialized synchronously');
|
958 |
+
// Defer any heavy data fetch; ensure map shell is visible first
|
959 |
+
if (window.requestAnimationFrame) {
|
960 |
+
requestAnimationFrame(() => setTimeout(() => {
|
961 |
+
try { if (window.MapApp && window.MapApp.loadVisibleTrees) { window.MapApp.loadVisibleTrees(); } } catch(_) {}
|
962 |
+
}, 0));
|
963 |
+
}
|
964 |
});
|
965 |
</script>
|
966 |
<script>
|
static/sw.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
// TreeTrack Service Worker - PWA and Offline Support
|
2 |
-
const VERSION =
|
3 |
const CACHE_NAME = `treetrack-v${VERSION}`;
|
4 |
const STATIC_CACHE = `static-v${VERSION}`;
|
5 |
const API_CACHE = `api-v${VERSION}`;
|
|
|
1 |
// TreeTrack Service Worker - PWA and Offline Support
|
2 |
+
const VERSION = 1755114924; // Cache busting bump - force clients to fetch new static assets and header image change
|
3 |
const CACHE_NAME = `treetrack-v${VERSION}`;
|
4 |
const STATIC_CACHE = `static-v${VERSION}`;
|
5 |
const API_CACHE = `api-v${VERSION}`;
|
version.json
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
{
|
2 |
"version": "5.1.1",
|
3 |
-
"timestamp":
|
4 |
}
|
|
|
1 |
{
|
2 |
"version": "5.1.1",
|
3 |
+
"timestamp": 1755114924
|
4 |
}
|