diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-28 10:19:15 +0200 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-28 10:19:15 +0200 |
| commit | 10806900a46b4eba197af9fc768928c57bd33982 (patch) | |
| tree | c4e69e242831dcdce962eb6e227a41557e126f14 | |
| parent | 843fd11774531a4fd22456093b112506cbffbc18 (diff) | |
Add touring ride type for cyclotourisme
| -rw-r--r-- | db/migrations/20260829000000_add_touring_ride_type.sql | 55 | ||||
| -rw-r--r-- | db/schema.sql | 5 | ||||
| -rw-r--r-- | ride/category.go | 5 | ||||
| -rw-r--r-- | web/categories.go | 3 | ||||
| -rw-r--r-- | web/frontend/analytics-logic.test.ts | 2 | ||||
| -rw-r--r-- | web/frontend/analytics-logic.ts | 3 | ||||
| -rw-r--r-- | web/ride-filters.go | 1 | ||||
| -rw-r--r-- | web/ride-filters_test.go | 3 |
8 files changed, 69 insertions, 8 deletions
diff --git a/db/migrations/20260829000000_add_touring_ride_type.sql b/db/migrations/20260829000000_add_touring_ride_type.sql new file mode 100644 index 0000000..dc1555d --- /dev/null +++ b/db/migrations/20260829000000_add_touring_ride_type.sql @@ -0,0 +1,55 @@ +-- migrate:up +CREATE TABLE rides_new ( + id integer primary key, + external_id text unique not null, + gpx_path text not null, + name text not null, + type text not null, + start_date text not null, + distance_m real not null, + external_moving_time_s integer not null, + elapsed_time_s integer not null, + total_elevation_gain_m real not null, + average_speed_mps real not null, + created_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')), + updated_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')), + cotacol_score real, + cotacol_algo_version text, + moving_time_s integer, + moving_time_algo_version text, + bike_type TEXT NOT NULL DEFAULT '' CHECK (bike_type IN ('', 'road', 'mtb')), + ride_type TEXT NOT NULL DEFAULT '' CHECK (ride_type IN ('', 'training', 'indoor', 'race', 'transport', 'touring')), + fit_path TEXT NOT NULL DEFAULT '' +); +INSERT INTO rides_new (id, external_id, gpx_path, name, type, start_date, distance_m, external_moving_time_s, elapsed_time_s, total_elevation_gain_m, average_speed_mps, created_at, updated_at, cotacol_score, cotacol_algo_version, moving_time_s, moving_time_algo_version, bike_type, ride_type, fit_path) +SELECT id, external_id, gpx_path, name, type, start_date, distance_m, external_moving_time_s, elapsed_time_s, total_elevation_gain_m, average_speed_mps, created_at, updated_at, cotacol_score, cotacol_algo_version, moving_time_s, moving_time_algo_version, bike_type, ride_type, fit_path FROM rides; +DROP TABLE rides; +ALTER TABLE rides_new RENAME TO rides; + +-- migrate:down +CREATE TABLE rides_new ( + id integer primary key, + external_id text unique not null, + gpx_path text not null, + name text not null, + type text not null, + start_date text not null, + distance_m real not null, + external_moving_time_s integer not null, + elapsed_time_s integer not null, + total_elevation_gain_m real not null, + average_speed_mps real not null, + created_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')), + updated_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')), + cotacol_score real, + cotacol_algo_version text, + moving_time_s integer, + moving_time_algo_version text, + bike_type TEXT NOT NULL DEFAULT '' CHECK (bike_type IN ('', 'road', 'mtb')), + ride_type TEXT NOT NULL DEFAULT '' CHECK (ride_type IN ('', 'training', 'indoor', 'race', 'transport')), + fit_path TEXT NOT NULL DEFAULT '' +); +INSERT INTO rides_new (id, external_id, gpx_path, name, type, start_date, distance_m, external_moving_time_s, elapsed_time_s, total_elevation_gain_m, average_speed_mps, created_at, updated_at, cotacol_score, cotacol_algo_version, moving_time_s, moving_time_algo_version, bike_type, ride_type, fit_path) +SELECT id, external_id, gpx_path, name, type, start_date, distance_m, external_moving_time_s, elapsed_time_s, total_elevation_gain_m, average_speed_mps, created_at, updated_at, cotacol_score, cotacol_algo_version, moving_time_s, moving_time_algo_version, bike_type, ride_type, fit_path FROM rides WHERE ride_type IN ('', 'training', 'indoor', 'race', 'transport'); +DROP TABLE rides; +ALTER TABLE rides_new RENAME TO rides; diff --git a/db/schema.sql b/db/schema.sql index a22e98f..79f4c62 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -13,7 +13,7 @@ CREATE TABLE rides ( average_speed_mps real not null, created_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')), updated_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')) -, cotacol_score real, cotacol_algo_version text, moving_time_s integer, moving_time_algo_version text, bike_type TEXT NOT NULL DEFAULT '' CHECK (bike_type IN ('', 'road', 'mtb')), ride_type TEXT NOT NULL DEFAULT '' CHECK (ride_type IN ('', 'training', 'indoor', 'race', 'transport')), fit_path TEXT NOT NULL DEFAULT ''); +, cotacol_score real, cotacol_algo_version text, moving_time_s integer, moving_time_algo_version text, bike_type TEXT NOT NULL DEFAULT '' CHECK (bike_type IN ('', 'road', 'mtb')), ride_type TEXT NOT NULL DEFAULT '' CHECK (ride_type IN ('', 'training', 'indoor', 'race', 'transport', 'touring')), fit_path TEXT NOT NULL DEFAULT ''); CREATE TABLE official_climbs ( id integer primary key, name text not null, @@ -43,4 +43,5 @@ INSERT INTO "schema_migrations" (version) VALUES ('20260821000000'), ('20260823000000'), ('20260827000000'), - ('20260828000000'); + ('20260828000000'), + ('20260829000000'); diff --git a/ride/category.go b/ride/category.go index 0eafcc0..6a3431c 100644 --- a/ride/category.go +++ b/ride/category.go @@ -14,6 +14,7 @@ const ( RideTypeIndoor RideType = "indoor" RideTypeRace RideType = "race" RideTypeTransport RideType = "transport" + RideTypeTouring RideType = "touring" ) var validBikeTypes = map[BikeType]struct{}{ @@ -26,10 +27,10 @@ var validRideTypes = map[RideType]struct{}{ RideTypeIndoor: {}, RideTypeRace: {}, RideTypeTransport: {}, + RideTypeTouring: {}, } -var AllBikeTypes = []BikeType{BikeTypeRoad, BikeTypeMTB} -var AllRideTypes = []RideType{RideTypeTraining, RideTypeIndoor, RideTypeRace, RideTypeTransport} +var AllRideTypes = []RideType{RideTypeTraining, RideTypeIndoor, RideTypeRace, RideTypeTransport, RideTypeTouring} func IsValidBikeType(value string) bool { _, ok := validBikeTypes[BikeType(value)] diff --git a/web/categories.go b/web/categories.go index a76fa1c..74d871c 100644 --- a/web/categories.go +++ b/web/categories.go @@ -53,7 +53,7 @@ func rideCategoriesUpdateURL(id int64) string { } var bikeTypeOptions = []ride.BikeType{ride.BikeTypeRoad, ride.BikeTypeMTB} -var rideTypeOptions = []ride.RideType{ride.RideTypeTraining, ride.RideTypeIndoor, ride.RideTypeRace, ride.RideTypeTransport} +var rideTypeOptions = []ride.RideType{ride.RideTypeTraining, ride.RideTypeIndoor, ride.RideTypeRace, ride.RideTypeTransport, ride.RideTypeTouring} var bikeTypeLabels = map[ride.BikeType]string{ ride.BikeTypeRoad: "Road", @@ -65,6 +65,7 @@ var rideTypeLabels = map[ride.RideType]string{ ride.RideTypeIndoor: "Indoor", ride.RideTypeRace: "Race", ride.RideTypeTransport: "Transport", + ride.RideTypeTouring: "Touring", } func formatCategoryOrEmpty(value string) string { diff --git a/web/frontend/analytics-logic.test.ts b/web/frontend/analytics-logic.test.ts index 0d1f789..e5c6caf 100644 --- a/web/frontend/analytics-logic.test.ts +++ b/web/frontend/analytics-logic.test.ts @@ -71,7 +71,7 @@ test("empty ride and bike types land in an Unknown group", () => { const points = [makePoint({ rideType: "" }), makePoint({ rideType: "race" })]; assert.deepEqual(groupRidePoints(points, "rideType"), [ { label: "Race", count: 1, colorIndex: 2 }, - { label: "Unknown", count: 1, colorIndex: 4 }, + { label: "Unknown", count: 1, colorIndex: 5 }, ]); const bikes = [makePoint({ bikeType: "" }), makePoint({ bikeType: "road" })]; assert.deepEqual(groupRidePoints(bikes, "bikeType"), [ diff --git a/web/frontend/analytics-logic.ts b/web/frontend/analytics-logic.ts index 5da8b80..fe1a9f9 100644 --- a/web/frontend/analytics-logic.ts +++ b/web/frontend/analytics-logic.ts @@ -65,6 +65,7 @@ const rideTypeLabels: Record<string, string> = { indoor: "Indoor", race: "Race", transport: "Transport", + touring: "Touring", }; const bikeTypeLabels: Record<string, string> = { @@ -73,7 +74,7 @@ const bikeTypeLabels: Record<string, string> = { mtb: "MTB", }; -const rideTypeOrder = ["training", "indoor", "race", "transport"]; +const rideTypeOrder = ["training", "indoor", "race", "transport", "touring"]; const bikeTypeOrder = ["road", "mtb"]; export const analyticsRideTypeLabel = (value: string): string => rideTypeLabels[value] ?? value; diff --git a/web/ride-filters.go b/web/ride-filters.go index 8535756..db925d9 100644 --- a/web/ride-filters.go +++ b/web/ride-filters.go @@ -239,6 +239,7 @@ func defaultRideTypes() []ride.RideType { ride.RideTypeTraining, ride.RideTypeIndoor, ride.RideTypeRace, + ride.RideTypeTouring, } } diff --git a/web/ride-filters_test.go b/web/ride-filters_test.go index 84c6417..b7abcf4 100644 --- a/web/ride-filters_test.go +++ b/web/ride-filters_test.go @@ -121,11 +121,12 @@ func TestFilterRidesDefaultsToAllRideTypesExceptTransport(t *testing.T) { {Name: "race", BikeType: ride.BikeTypeRoad, RideType: ride.RideTypeRace, GPXPath: "b.gpx"}, {Name: "indoor", BikeType: ride.BikeTypeRoad, RideType: ride.RideTypeIndoor, GPXPath: "c.gpx"}, {Name: "transport", BikeType: ride.BikeTypeRoad, RideType: ride.RideTypeTransport, GPXPath: "d.gpx"}, + {Name: "touring", BikeType: ride.BikeTypeRoad, RideType: ride.RideTypeTouring, GPXPath: "e.gpx"}, } filtered := filterRides(items, parseRideFilters(url.Values{})) - require.Len(t, filtered, 3) + require.Len(t, filtered, 4) assert.False(t, parseRideFilters(url.Values{}).Active()) for _, item := range filtered { assert.NotEqual(t, ride.RideTypeTransport, item.RideType) |
