diff --git a/client/scripts/size-baseline.json b/client/scripts/size-baseline.json index a69f961ca..423ad10d4 100644 --- a/client/scripts/size-baseline.json +++ b/client/scripts/size-baseline.json @@ -24,7 +24,7 @@ "src/mobile/screens/admin/MAdminPluginsPanel.tsx": 1507, "src/pages/JourneyDetailPage.test.tsx": 4030, "src/pages/LoginPage.tsx": 1348, - "src/pages/TripPlannerPage.tsx": 1147, + "src/pages/TripPlannerPage.tsx": 1142, "src/pages/atlas/useAtlas.ts": 1287, "src/pages/tripPlanner/useTripPlanner.roadtrip.test.tsx": 3518, "src/pages/tripPlanner/useTripPlanner.test.tsx": 3309, diff --git a/client/src/components/Tours/paddle/PaddleWaypointParts.tsx b/client/src/components/Tours/paddle/PaddleWaypointParts.tsx index 8db1a47d0..bd96674bb 100644 --- a/client/src/components/Tours/paddle/PaddleWaypointParts.tsx +++ b/client/src/components/Tours/paddle/PaddleWaypointParts.tsx @@ -36,7 +36,7 @@ export function PaddleRolePill({ role }: { role: PaddleRole }) { * whole number of minutes in range is dropped on leaving the field, and the * value before it stays. */ -export function MinutesInput({ +function MinutesInput({ label, value, placeholder, diff --git a/client/src/components/Tours/paddle/paddleObstacleModel.ts b/client/src/components/Tours/paddle/paddleObstacleModel.ts index 3f11901be..9fd9c457e 100644 --- a/client/src/components/Tours/paddle/paddleObstacleModel.ts +++ b/client/src/components/Tours/paddle/paddleObstacleModel.ts @@ -26,7 +26,7 @@ export const OBSTACLE_FACT_KEYS = [ 'fee', 'operator', ] as const; -export type ObstacleFactKey = (typeof OBSTACLE_FACT_KEYS)[number]; +type ObstacleFactKey = (typeof OBSTACLE_FACT_KEYS)[number]; /** The access values the card puts into words; any other value is shown as OSM has it. */ export const KNOWN_ACCESS_VALUES = ['yes', 'no', 'private', 'permissive', 'designated'] as const; diff --git a/client/src/components/Tours/paddle/paddlePaint.ts b/client/src/components/Tours/paddle/paddlePaint.ts index 380ab3447..4d78382ca 100644 --- a/client/src/components/Tours/paddle/paddlePaint.ts +++ b/client/src/components/Tours/paddle/paddlePaint.ts @@ -7,7 +7,7 @@ import { useMapPaint } from '../../Map/mapPaint'; * reads them resolved (`usePaddlePaint`); markup on the page takes the CSS * variable itself (`paddleKindCss`), which follows the theme on its own. */ -export const PADDLE_PAINT_TOKENS = { +const PADDLE_PAINT_TOKENS = { obstacle: '--map-paddle-obstacle', access: '--map-paddle-access', landing: '--map-paddle-landing', diff --git a/server/src/db/repositories/PaddleRegions.repository.ts b/server/src/db/repositories/PaddleRegions.repository.ts index 677a75fdb..5fac10db4 100644 --- a/server/src/db/repositories/PaddleRegions.repository.ts +++ b/server/src/db/repositories/PaddleRegions.repository.ts @@ -1,10 +1,8 @@ -import type { PaddleRegions } from '../entities/PaddleRegions.entity'; +import { type PaddleRegions, PaddleRegionsStatus, type TPaddleRegionsStatus } from '../entities/PaddleRegions.entity'; import type { DB } from '../kysely/db'; import type { Box } from './PaddleFeatures.repository'; import { TrekRepository } from './_shared/trek-repository'; -export type PaddleRegionStatus = 'queued' | 'importing' | 'ready' | 'failed'; - /** One region an admin chose, as stored; the boundary is still GeoJSON text. */ export interface PaddleRegionRow { id: string; @@ -14,7 +12,7 @@ export interface PaddleRegionRow { min_lng: number | null; max_lat: number | null; max_lng: number | null; - status: PaddleRegionStatus; + status: TPaddleRegionsStatus; source_timestamp: string | null; imported_at: string | null; feature_count: number; @@ -23,7 +21,7 @@ export interface PaddleRegionRow { /** `status` narrowed to the four values the column's CHECK constraint allows. */ type RegionsDB = { - paddle_regions: Omit & { status: PaddleRegionStatus }; + paddle_regions: Omit & { status: TPaddleRegionsStatus }; }; const COLUMNS = [ @@ -78,7 +76,7 @@ export class PaddleRegionsRepository extends TrekRepository { return await this.db() .selectFrom('paddle_regions') .select(COLUMNS) - .where('status', '=', 'queued') + .where('status', '=', PaddleRegionsStatus.QUEUED) .orderBy('created_at', 'asc') .executeTakeFirst(); } @@ -88,7 +86,7 @@ export class PaddleRegionsRepository extends TrekRepository { ): Promise { await this.db() .insertInto('paddle_regions') - .values({ ...row, status: 'queued', feature_count: 0 }) + .values({ ...row, status: PaddleRegionsStatus.QUEUED, feature_count: 0 }) .onConflict((oc) => oc.column('id').doNothing()) .execute(); } @@ -117,15 +115,19 @@ export class PaddleRegionsRepository extends TrekRepository { async queueReady(): Promise { const result = await this.db() .updateTable('paddle_regions') - .set({ status: 'queued', error: null }) - .where('status', 'in', ['ready', 'failed']) + .set({ status: PaddleRegionsStatus.QUEUED, error: null }) + .where('status', 'in', [PaddleRegionsStatus.READY, PaddleRegionsStatus.FAILED]) .executeTakeFirst(); return Number(result.numUpdatedRows ?? 0); } /** A region left half read by a restart goes back to the queue. */ async requeueInterrupted(): Promise { - await this.db().updateTable('paddle_regions').set({ status: 'queued' }).where('status', '=', 'importing').execute(); + await this.db() + .updateTable('paddle_regions') + .set({ status: PaddleRegionsStatus.QUEUED }) + .where('status', '=', PaddleRegionsStatus.IMPORTING) + .execute(); } async deleteRegion(id: string): Promise { diff --git a/server/tests/unit/nest/weather/wind.service.test.ts b/server/tests/unit/nest/weather/wind.service.test.ts index 651d26b19..bb40f004a 100644 --- a/server/tests/unit/nest/weather/wind.service.test.ts +++ b/server/tests/unit/nest/weather/wind.service.test.ts @@ -6,7 +6,7 @@ * request is a 502 of its own rather than an empty forecast. */ import { DomainError } from '../../../../src/nest/common/domain-error'; -import { WindService } from '../../../../src/nest/weather/wind.service'; +import { WIND_UNAVAILABLE_MESSAGE, WindService } from '../../../../src/nest/weather/wind.service'; import { afterEach, describe, expect, it, vi } from 'vitest'; @@ -97,6 +97,8 @@ describe('WindService', () => { vi.stubGlobal('fetch', answer({ hourly: 'nonsense' })); await expect(service.forecast({ lat: 47, lng: 9, date: '2026-10-19' }, NOW)).rejects.toMatchObject({ code: 'wind_unavailable', + status: 502, + publicMessage: WIND_UNAVAILABLE_MESSAGE, }); });