63 lines
4.5 KiB
JavaScript
63 lines
4.5 KiB
JavaScript
(() => {
|
|
'use strict';
|
|
const root = document.getElementById('stats-studio');
|
|
if (!root) return;
|
|
const status = document.getElementById('studio-status');
|
|
const data = document.getElementById('stats-data');
|
|
if (!data || typeof Chart === 'undefined') return;
|
|
const chartData = JSON.parse(data.textContent);
|
|
const clear = document.getElementById('clear-selection');
|
|
const tbody = document.getElementById('evidence-body');
|
|
let selectionScope = 'trend';
|
|
const original = [...tbody.children].map(row => row.cloneNode(true));
|
|
const pagination = root.querySelector('.studio-pagination');
|
|
const period = document.getElementById('evidence-period');
|
|
const originalPagination = [...pagination.children].map(node => node.cloneNode(true));
|
|
let pending = null;
|
|
clear.onclick = () => { pending?.abort(); period.value = ''; tbody.replaceChildren(...original.map(row => row.cloneNode(true))); pagination.replaceChildren(...originalPagination.map(node => node.cloneNode(true))); clear.hidden = true; document.getElementById('evidence-heading').textContent = `Contributing ${root.dataset.source}`; status.textContent = ''; };
|
|
period.onchange = () => { if (period.value) loadBucket(period.value,1,selectionScope); else clear.click(); };
|
|
async function loadBucket(bucket, page = 1, scope = 'trend') {
|
|
selectionScope=scope;
|
|
pending?.abort();
|
|
const controller = new AbortController(); pending = controller;
|
|
const url = new URL('/stats/runs', location.origin);
|
|
url.search = new URLSearchParams({query:root.dataset.query,bucket,page,scope});
|
|
status.textContent = 'Loading contributing runs…';
|
|
try {
|
|
const response = await fetch(url, {signal:controller.signal});
|
|
if (!response.ok) throw new Error();
|
|
const result = await response.json();
|
|
tbody.replaceChildren();
|
|
result.rows.forEach(row => {
|
|
const tr = document.createElement('tr'); const td = document.createElement('td');
|
|
const a = document.createElement(row.id?'a':'span'); if(row.id)a.href = `/activities/${row.id}`; a.textContent = `${row.title} · ${row.date}`;
|
|
td.append(a); tr.append(td);
|
|
(row.activity_ids||[]).forEach(id=>{const link=document.createElement('a');link.href=`/activities/${id}`;link.textContent=` · Run #${id}`;td.append(link);});
|
|
if (root.dataset.showPrevious === 'true') {
|
|
const detail=document.createElement('small');detail.className='previous-run';
|
|
detail.append('Previous: ');
|
|
if(row.previous_run){const previous=document.createElement('a');previous.href=`/activities/${row.previous_run.id}`;previous.textContent=`${row.previous_run.date} · ${row.previous_run.title}`;detail.append(previous);}else detail.append('No earlier recorded run');
|
|
td.append(detail);
|
|
}
|
|
[`${row.distance} km`, ...row.values].forEach(text => { const cell = document.createElement('td'); cell.textContent = text; tr.append(cell); });
|
|
tbody.append(tr);
|
|
});
|
|
document.getElementById('evidence-heading').textContent = `${bucket} · ${result.count} ${root.dataset.source}`;
|
|
period.value = bucket;
|
|
pagination.replaceChildren();
|
|
const label = document.createElement('span'); label.textContent = `Page ${result.page} of ${result.pages} · selected period`; pagination.append(label);
|
|
[[result.page > 1, 'Previous', result.page - 1], [result.page < result.pages, 'Next', result.page + 1]].forEach(([show, name, target]) => {
|
|
if (!show) return; const button = document.createElement('button'); button.type = 'button'; button.className = 'button secondary'; button.textContent = name; button.onclick = () => loadBucket(bucket, target, scope); pagination.append(button);
|
|
});
|
|
clear.hidden = false; status.textContent = 'Selected period loaded.';
|
|
} catch (error) { if (error.name !== 'AbortError') status.textContent = 'Could not load this period. Try again.'; }
|
|
}
|
|
root.querySelectorAll('[data-bucket]').forEach(button=>button.onclick=()=>loadBucket(button.dataset.bucket,1,'group'));
|
|
const plots=document.getElementById('analysis-plots');
|
|
if(plots)StrideCharts.render(plots,chartData,bucket=>loadBucket(bucket));
|
|
const insightPanel=document.getElementById('analysis-insights');
|
|
if(insightPanel)StrideCharts.insights(insightPanel,JSON.parse(document.getElementById('insights-data').textContent),bucket=>loadBucket(bucket,1,'group'));
|
|
const initialBucket=new URL(location.href).searchParams.get('bucket');
|
|
if(initialBucket)loadBucket(initialBucket,1,new URL(location.href).searchParams.get('scope')||'trend');
|
|
})();
|