From 827b55f610119d553b965ceb4d3631f0481bbb3b Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Fri, 28 Aug 2026 22:38:57 +0200 Subject: Rename rides.type to external_sport_type, infer bike type from Strava sport type and display categories in UI --- web/categories.go | 21 ++++ web/ride-filters_test.go | 94 +++++++++--------- web/server_test.go | 242 +++++++++++++++++++++++------------------------ web/sync.go | 8 +- web/templates.templ | 6 +- 5 files changed, 198 insertions(+), 173 deletions(-) (limited to 'web') diff --git a/web/categories.go b/web/categories.go index 74d871c..6ef8c10 100644 --- a/web/categories.go +++ b/web/categories.go @@ -74,3 +74,24 @@ func formatCategoryOrEmpty(value string) string { } return value } + +func formatRideCategories(r ride.StoredRide) string { + bikeLabel, hasBike := bikeTypeLabels[r.BikeType] + rideLabel, hasRide := rideTypeLabels[r.RideType] + switch { + case hasBike && hasRide: + return bikeLabel + " · " + rideLabel + case hasBike: + return bikeLabel + case hasRide: + return rideLabel + default: + if r.BikeType != "" { + return string(r.BikeType) + } + if r.RideType != "" { + return string(r.RideType) + } + return "—" + } +} diff --git a/web/ride-filters_test.go b/web/ride-filters_test.go index b7abcf4..5075925 100644 --- a/web/ride-filters_test.go +++ b/web/ride-filters_test.go @@ -169,33 +169,33 @@ func TestFilterRidesByRideType(t *testing.T) { func TestFilterRidesByCotacolExcludesUnavailableScores(t *testing.T) { _, db := newWebTestServer(t) current := ride.StoredRide{ - ExternalID: "strava:550e8400-e29b-41d4-a716-446655440000", - GPXPath: testGPXPath(t, "current-cotacol.gpx"), - Name: "Current score", - Type: "Ride", - BikeType: ride.BikeTypeRoad, - RideType: ride.RideTypeTraining, - StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), - DistanceM: 20_000, + ExternalID: "strava:550e8400-e29b-41d4-a716-446655440000", + GPXPath: testGPXPath(t, "current-cotacol.gpx"), + Name: "Current score", + ExternalSportType: "Ride", + BikeType: ride.BikeTypeRoad, + RideType: ride.RideTypeTraining, + StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), + DistanceM: 20_000, } stale := ride.StoredRide{ - ExternalID: "strava:6ba7b810-9dad-41d1-80b4-00c04fd430c8", - GPXPath: testGPXPath(t, "stale-cotacol.gpx"), - Name: "Stale score", - Type: "Ride", - BikeType: ride.BikeTypeRoad, - RideType: ride.RideTypeTraining, - StartDate: time.Date(2026, 8, 2, 7, 0, 0, 0, time.UTC), - DistanceM: 20_000, + ExternalID: "strava:6ba7b810-9dad-41d1-80b4-00c04fd430c8", + GPXPath: testGPXPath(t, "stale-cotacol.gpx"), + Name: "Stale score", + ExternalSportType: "Ride", + BikeType: ride.BikeTypeRoad, + RideType: ride.RideTypeTraining, + StartDate: time.Date(2026, 8, 2, 7, 0, 0, 0, time.UTC), + DistanceM: 20_000, } unavailable := ride.StoredRide{ - ExternalID: "strava:7ba7b810-9dad-41d1-80b4-00c04fd430c8", - Name: "No score", - Type: "VirtualRide", - BikeType: ride.BikeTypeRoad, - RideType: ride.RideTypeTraining, - StartDate: time.Date(2026, 8, 3, 7, 0, 0, 0, time.UTC), - DistanceM: 20_000, + ExternalID: "strava:7ba7b810-9dad-41d1-80b4-00c04fd430c8", + Name: "No score", + ExternalSportType: "VirtualRide", + BikeType: ride.BikeTypeRoad, + RideType: ride.RideTypeTraining, + StartDate: time.Date(2026, 8, 3, 7, 0, 0, 0, time.UTC), + DistanceM: 20_000, } require.NoError(t, ride.Save(db, current)) require.NoError(t, ride.Save(db, stale)) @@ -248,14 +248,14 @@ func TestHandlerHidesTransportRidesByDefault(t *testing.T) { server, db := newWebTestServer(t) save := func(externalID, name string, rideType ride.RideType) { require.NoError(t, ride.Save(db, ride.StoredRide{ - ExternalID: externalID, - GPXPath: testGPXPath(t, externalID+".gpx"), - Name: name, - Type: "Ride", - BikeType: ride.BikeTypeRoad, - RideType: rideType, - StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), - DistanceM: 20_000, + ExternalID: externalID, + GPXPath: testGPXPath(t, externalID+".gpx"), + Name: name, + ExternalSportType: "Ride", + BikeType: ride.BikeTypeRoad, + RideType: rideType, + StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), + DistanceM: 20_000, })) } save("strava:550e8400-e29b-41d4-a716-446655440000", "Training Ride", ride.RideTypeTraining) @@ -297,14 +297,14 @@ func TestHandlerFiltersRidesBeforeRenderingSortedResults(t *testing.T) { server, db := newWebTestServer(t) save := func(externalID, name, path string, distance float64) { require.NoError(t, ride.Save(db, ride.StoredRide{ - ExternalID: externalID, - GPXPath: testGPXPath(t, path), - Name: name, - Type: "Ride", - BikeType: ride.BikeTypeRoad, - RideType: ride.RideTypeTraining, - StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), - DistanceM: distance, + ExternalID: externalID, + GPXPath: testGPXPath(t, path), + Name: name, + ExternalSportType: "Ride", + BikeType: ride.BikeTypeRoad, + RideType: ride.RideTypeTraining, + StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), + DistanceM: distance, })) } save("strava:550e8400-e29b-41d4-a716-446655440000", "Long Ride", "long-filtered.gpx", 40_000) @@ -324,14 +324,14 @@ func TestHandlerFiltersRidesBeforeRenderingSortedResults(t *testing.T) { func TestHandlerRendersFilteredEmptyState(t *testing.T) { server, db := newWebTestServer(t) require.NoError(t, ride.Save(db, ride.StoredRide{ - ExternalID: "strava:8ba7b810-9dad-41d1-80b4-00c04fd430c8", - GPXPath: testGPXPath(t, "empty-filter.gpx"), - Name: "Short Ride", - Type: "Ride", - BikeType: ride.BikeTypeRoad, - RideType: ride.RideTypeTraining, - StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), - DistanceM: 20_000, + ExternalID: "strava:8ba7b810-9dad-41d1-80b4-00c04fd430c8", + GPXPath: testGPXPath(t, "empty-filter.gpx"), + Name: "Short Ride", + ExternalSportType: "Ride", + BikeType: ride.BikeTypeRoad, + RideType: ride.RideTypeTraining, + StartDate: time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC), + DistanceM: 20_000, })) request := httptest.NewRequest(http.MethodGet, "/?distance_min=300&distance_max=300", nil) diff --git a/web/server_test.go b/web/server_test.go index d75628d..2e9a332 100644 --- a/web/server_test.go +++ b/web/server_test.go @@ -89,24 +89,24 @@ const officialClimbTrackGPX = ` for _, item := range data.Items { - { item.Ride.Name }
{ item.Ride.Type }{ formatRideDate(item.Ride.StartDate) }{ formatDistance(item.Ride.DistanceM) }{ item.MovingTime }{ formatSpeed(item.Ride.AverageSpeedMps) }{ formatElevation(item.Ride.TotalElevationGainM) }{ item.Cotacol }{ item.CotacolPer100Km } + { item.Ride.Name }
{ formatRideCategories(item.Ride) }{ formatRideDate(item.Ride.StartDate) }{ formatDistance(item.Ride.DistanceM) }{ item.MovingTime }{ formatSpeed(item.Ride.AverageSpeedMps) }{ formatElevation(item.Ride.TotalElevationGainM) }{ item.Cotacol }{ item.CotacolPer100Km } } @@ -206,7 +206,7 @@ templ RideDetailPage(data RideDetailView) { templ RideDetailContent(data RideDetailView) {
-

{ data.Ride.Name }

{ data.Ride.Type } · { formatRideDate(data.Ride.StartDate) }

+

{ data.Ride.Name }

{ formatRideCategories(data.Ride) } · { formatRideDate(data.Ride.StartDate) }

if data.ExternalURL != "" { View on Strava @@ -448,7 +448,7 @@ templ DataQualityContent(data DataQualityPageData) { for _, item := range data.Items { - { item.Ride.Name }
{ item.Ride.Type } + { item.Ride.Name }
{ formatRideCategories(item.Ride) } { formatRideDate(item.Ride.StartDate) } { formatDistance(item.Ride.DistanceM) } { formatCategoryOrEmpty(string(item.Ride.BikeType)) } -- cgit v1.3