many updates
This commit is contained in:
@@ -56,6 +56,12 @@
|
||||
<button class="btn btn-primary" id="download-btn">
|
||||
<i class="bi bi-download"></i> Download
|
||||
</button>
|
||||
<button class="btn btn-outline-warning" id="refresh-btn" onclick="refreshActivity()">
|
||||
<i class="bi bi-arrow-clockwise"></i> Refresh & Match
|
||||
</button>
|
||||
<button class="btn btn-warning" id="estimate-power-btn" onclick="estimatePower()">
|
||||
<i class="bi bi-lightning-fill"></i> Estimate Power
|
||||
</button>
|
||||
<button class="btn btn-success" id="create-segment-btn" onclick="toggleSegmentMode()">
|
||||
<i class="bi bi-bezier2"></i> Create Segment
|
||||
</button>
|
||||
@@ -228,7 +234,10 @@
|
||||
<!-- Bike Info (New) -->
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 metric-card border-light shadow-sm">
|
||||
<div class="card-header bg-light text-dark">Bike Setup</div>
|
||||
<div class="card-header bg-light text-dark d-flex justify-content-between align-items-center">
|
||||
<span>Bike Setup</span>
|
||||
<button class="btn btn-sm btn-link p-0 text-decoration-none" onclick="editBikeSetup()">Edit</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="m-bike-info" class="text-center text-muted">No Setup</div>
|
||||
</div>
|
||||
@@ -647,6 +656,132 @@
|
||||
setupDrag(endMarker, false);
|
||||
}
|
||||
|
||||
async function refreshActivity() {
|
||||
if (!confirm("Are you sure you want to re-download this activity from Garmin and run bike matching? This will overwrite any manual bike selection.")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const btn = document.getElementById('refresh-btn');
|
||||
const origHtml = btn.innerHTML;
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Refreshing...';
|
||||
|
||||
// Helper toast fallback if showToast not defined in this view (it inherits from base.html usually?)
|
||||
// base.html usually has showToast.
|
||||
if (typeof showToast === 'function') showToast("Processing...", "Refreshing activity data...", "info");
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/activities/${activityId}/redownload`, { method: 'POST' });
|
||||
const data = await res.json();
|
||||
|
||||
if (res.ok) {
|
||||
if (typeof showToast === 'function') showToast("Success", data.message, "success");
|
||||
else alert(data.message);
|
||||
|
||||
// Reload details
|
||||
loadDetails();
|
||||
loadCharts();
|
||||
} else {
|
||||
throw new Error(data.detail || "Refresh failed");
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (typeof showToast === 'function') showToast("Error", e.message, "error");
|
||||
else alert("Error: " + e.message);
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = origHtml;
|
||||
}
|
||||
}
|
||||
|
||||
let allBikes = [];
|
||||
async function fetchAllBikes() {
|
||||
try {
|
||||
const res = await fetch('/api/bike-setups');
|
||||
if (res.ok) allBikes = await res.json();
|
||||
} catch (e) { console.error(e); }
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', fetchAllBikes);
|
||||
|
||||
function editBikeSetup() {
|
||||
const container = document.getElementById('m-bike-info');
|
||||
if (container.querySelector('select')) return;
|
||||
|
||||
// Current text
|
||||
const currentHtml = container.innerHTML;
|
||||
|
||||
let initialSelect = `<div class="input-group input-group-sm">
|
||||
<select class="form-select" id="bike-select">
|
||||
<option value="">-- No Bike --</option>`;
|
||||
|
||||
allBikes.forEach(b => {
|
||||
initialSelect += `<option value="${b.id}">${b.name || b.frame} (${b.chainring}/${b.rear_cog})</option>`;
|
||||
});
|
||||
|
||||
initialSelect += `</select>
|
||||
<button class="btn btn-success" onclick="saveBikeSetup()"><i class="bi bi-check"></i></button>
|
||||
<button class="btn btn-outline-secondary" onclick="loadDetails()"><i class="bi bi-x"></i></button>
|
||||
</div>`;
|
||||
|
||||
container.innerHTML = initialSelect;
|
||||
}
|
||||
|
||||
async function saveBikeSetup() {
|
||||
const sel = document.getElementById('bike-select');
|
||||
const newId = sel.value ? parseInt(sel.value) : null;
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/activities/${activityId}/bike`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ bike_setup_id: newId, manual_override: true })
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
if (typeof showToast === 'function') showToast("Success", "Bike setup updated", "success");
|
||||
else alert("Bike setup updated");
|
||||
loadDetails();
|
||||
} else {
|
||||
const err = await res.json();
|
||||
alert("Error: " + err.detail);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
alert("Save failed");
|
||||
}
|
||||
}
|
||||
|
||||
async function estimatePower() {
|
||||
if (!confirm("Estimate power for this activity using physics usage calculation? This will update average/max power stats.")) return;
|
||||
|
||||
const btn = document.getElementById('estimate-power-btn');
|
||||
const origText = btn.innerHTML;
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Estimating...';
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/activities/${window.currentDbId}/estimate_power`, {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
alert("Power estimation complete! Avg: " + data.stats.avg_power + " W");
|
||||
loadDetails(); // Refresh stats
|
||||
loadCharts(); // Refresh charts if stream updated (Service returns stream but we'd need to reload)
|
||||
} else {
|
||||
const err = await res.json();
|
||||
alert("Error: " + err.detail);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
alert("Estimate failed: " + e.message);
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = origText;
|
||||
}
|
||||
}
|
||||
|
||||
async function saveSegment() {
|
||||
if (startIndex >= endIndex) {
|
||||
alert("Start point must be before End point.");
|
||||
|
||||
Reference in New Issue
Block a user