Add matched training signals, daily recovery and performance analysis

This commit is contained in:
Peter Stockings
2026-10-03 13:22:32 +10:00
parent e6e2f22479
commit 418e03583a
37 changed files with 1380 additions and 47 deletions
+3 -2
View File
@@ -11,7 +11,7 @@
const url=(bucket,scope='group')=>'/stats?'+new URLSearchParams({analysis:id,query:result.analysis.query,...(bucket?{bucket,scope}:{})})+'#studio-evidence';
const data=result.results;
let dispose=null;
if(!data.count)body.append(el('p','field-help','No runs match this analysis yet. Explore to adjust the filters.'));
if(!data.count)body.append(el('p','field-help','No observations match this analysis yet. Explore to adjust the filters.'));
else if(widget.dataset.view==='chart'&&(data.chart.type!=='none'||data.chart.scatter))dispose=StrideCharts.render(body,data.chart,bucket=>location.assign(url(bucket,'trend')),{compact:true});
else if(widget.dataset.view==='value'||(widget.dataset.view==='chart'&&data.chart.type==='none')){
const values=el('div','live-widget-values');data.cards.forEach(card=>{const item=el('div');item.append(el('span','eyebrow',card.label),el('strong','',`${card.value} ${card.unit}`),el('small','field-help',`${card.coverage} of ${data.count} usable ${data.source}`));values.append(item);});body.append(values);
@@ -19,7 +19,8 @@
const wrap=el('div','activity-table-wrap'),table=el('table','activity-table'),head=el('thead'),tr=el('tr');['Group',data.source,...data.cards.map(c=>`${c.label} · ${c.unit}`)].forEach(t=>tr.append(el('th','',t)));head.append(tr);table.append(head);const tbody=el('tbody');data.groups.slice(-12).forEach(group=>{const row=el('tr'),cell=el('td'),a=el('a','',group.label);a.href=url(group.label);cell.append(a);row.append(cell);[group.count,...group.values].forEach(v=>row.append(el('td','',v)));tbody.append(row);});table.append(tbody);wrap.append(table);body.append(wrap);if(data.groups.length>12)body.append(el('p','field-help','Last 12 displayed groups · Explore for all results.'));
}
StrideCharts.insights(insights,data.insights,bucket=>location.assign(url(bucket)));
widget.querySelector('.widget-status').textContent=`${data.count} matching ${data.source} · ${data.start} – ${data.end} · updated ${new Date().toLocaleTimeString([], {hour:'2-digit',minute:'2-digit'})}`;
const coverage=data.coverage;
widget.querySelector('.widget-status').textContent=`${data.count} qualifying ${data.source==='matched runs'?'runs':data.source}${coverage?` · ${coverage.sessions} independent sessions · ${coverage.minutes} usable minutes`:''} · ${data.start} – ${data.end} · updated ${new Date().toLocaleTimeString([], {hour:'2-digit',minute:'2-digit'})}`;
states.set(id,{result,dispose});
}
async function refresh(){