aboutsummaryrefslogtreecommitdiff
path: root/web/templates.templ
diff options
context:
space:
mode:
Diffstat (limited to 'web/templates.templ')
-rw-r--r--web/templates.templ67
1 files changed, 66 insertions, 1 deletions
diff --git a/web/templates.templ b/web/templates.templ
index d1719b8..6c3b09d 100644
--- a/web/templates.templ
+++ b/web/templates.templ
@@ -13,7 +13,7 @@ templ Layout(title string, content templ.Component) {
<body>
<header class="site-header">
<a class="brand" href="/">biking_home</a>
- <nav class="nav"><a href="/">Rides</a><a href="/analytics">Analytics</a><a href="/sync">Sync Strava</a></nav>
+ <nav class="nav"><a href="/">Rides</a><a href="/analytics">Analytics</a><a href="/data-quality">Data quality</a><a href="/sync">Sync Strava</a></nav>
</header>
<main class="container">
@content
@@ -359,3 +359,68 @@ templ SyncContent(data SyncPageData) {
</section>
<script type="module" src="/static/sync.js"></script>
}
+
+templ DataQualityPage(data DataQualityPageData) {
+ @Layout("Data quality", DataQualityContent(data))
+}
+
+templ DataQualityContent(data DataQualityPageData) {
+ <p class="eyebrow">Curation</p>
+ <h1>Data quality</h1>
+ <p class="lead">Categorise rides that are missing bike or ride type. Select rides, pick categories, and apply in bulk.</p>
+ if data.Notice != "" {
+ <div class="notice">{ data.Notice }</div>
+ }
+ <section class="panel">
+ <div class="section-heading">
+ <div><p class="eyebrow">Todo</p><h2>Uncategorised rides</h2></div>
+ <span class="section-count">{ formatRideCount(data.Total) }</span>
+ </div>
+ if data.Total == 0 {
+ <div class="empty">All rides are categorised.</div>
+ } else if len(data.Items) == 0 {
+ <div class="empty">No uncategorised rides match the current view.</div>
+ } else {
+ <form method="post" action="/data-quality/categories" id="data-quality-form">
+ <div class="data-quality-bulk">
+ <label for="bulk-bike-type">Bike type
+ <select id="bulk-bike-type" name="bike_type" required>
+ <option value="">—</option>
+ for _, opt := range bikeTypeOptions {
+ <option value={ string(opt) }>{ bikeTypeLabels[opt] }</option>
+ }
+ </select>
+ </label>
+ <label for="bulk-ride-type">Ride type
+ <select id="bulk-ride-type" name="ride_type" required>
+ <option value="">—</option>
+ for _, opt := range rideTypeOptions {
+ <option value={ string(opt) }>{ rideTypeLabels[opt] }</option>
+ }
+ </select>
+ </label>
+ <button class="button" type="submit">Apply to selected</button>
+ <span class="data-quality-selected" id="data-quality-selected">0 selected</span>
+ </div>
+ <div class="data-quality-table-wrap">
+ <table>
+ <thead><tr><th><input type="checkbox" id="data-quality-select-all" aria-label="Select all rides"/></th><th>Ride</th><th>Started</th><th class="numeric">Distance</th><th>Bike</th><th>Ride type</th></tr></thead>
+ <tbody>
+ for _, item := range data.Items {
+ <tr>
+ <td><input type="checkbox" name="ride_ids" value={ formatRideID(item.Ride.ID) } class="data-quality-checkbox"/></td>
+ <td><strong><a href={ templ.URL(rideDetailURL(item.Ride.ID)) }>{ item.Ride.Name }</a></strong><br/><small>{ item.Ride.Type }</small></td>
+ <td>{ formatRideDate(item.Ride.StartDate) }</td>
+ <td class="numeric">{ formatDistance(item.Ride.DistanceM) }</td>
+ <td>{ formatCategoryOrEmpty(string(item.Ride.BikeType)) }</td>
+ <td>{ formatCategoryOrEmpty(string(item.Ride.RideType)) }</td>
+ </tr>
+ }
+ </tbody>
+ </table>
+ </div>
+ </form>
+ <script type="module" src="/static/data-quality.js"></script>
+ }
+ </section>
+}