fix(tours): keep the waypoints of a GPX/KML file that also holds a track

With the Tours addon on, a file picked or dropped on the places column goes
into the Tours import as soon as it holds one line, and that import reads
lines only. A Sygic or Trip-o-matic export (a route plus its stops) came in
as one tour and every place was dropped without a word.

The preview now counts a GPX file's waypoints as it already counted a KML
file's pins, and the dialog offers to add those points as places of the
trip, on by default. Confirming runs the Tours import for the lines and the
places import (points only) for the same files. A file whose tracks the
trip already holds can still bring its points.

Closes #2969
This commit is contained in:
Maurice
2026-11-03 20:19:43 +01:00
parent f8e51cb83d
commit 2e683f8609
36 changed files with 374 additions and 42 deletions
@@ -3,8 +3,9 @@
* A GPX file gives its tracks and routes, a KML or KMZ file its lines; both
* come back as the same rows, so the preview, the duplicate rule and the one
* transaction that stores them are the GPX import's own. Loose points are
* never a tour: a GPX file's waypoints are skipped as they always were, and a
* KML file's pins, areas and the rest are counted for the preview to name.
* never a tour: a GPX file's waypoints and a KML file's pins, areas and the
* rest are counted for the preview, which offers to add the points as places
* of the trip through the places import (#2969).
*/
import { DomainError } from '../common/domain-error';
import type { PlaceImportService } from '../place-import/place-import.service';
@@ -13,7 +14,7 @@ import type { TourFileLeftOut } from '@trek/shared';
type TourFileFormat = 'gpx' | 'kml' | 'kmz';
/** A file read for a Tours import: the rows it would store, and for a KML or KMZ file what it holds besides. */
/** A file read for a Tours import: the rows it would store, and what the file holds besides. */
export interface TourFileRead {
rows: PreparedGpxPlace[];
leftOut?: TourFileLeftOut;
@@ -56,7 +57,14 @@ export async function readTourFile(
importTracks: true,
defaultName: fileName,
});
return { rows };
if (rows.length === 0) return { rows };
const points = placeImport.readGpx(fileBuffer, {
importWaypoints: true,
importRoutes: false,
importTracks: false,
defaultName: fileName,
}).length;
return points > 0 ? { rows, leftOut: { points, areas: 0, other: 0 } } : { rows };
}
try {
const { tracks, leftOut } = await placeImport.readMapFileTracks(fileBuffer, fileName ?? '');
+2 -2
View File
@@ -943,8 +943,8 @@ export class ToursService {
/**
* PAD-02: what a file would import, read with the import's own parser and
* duplicate rule and written nowhere. Null when the file holds no track or
* route, the import's own refusal. A KML or KMZ file also says what it holds
* besides its lines (IO-02).
* route, the import's own refusal. The preview also says what the file holds
* besides its lines (IO-02), a GPX file its waypoints (#2969).
*/
async previewGpx(tripId: string, fileBuffer: Buffer, fileName?: string): Promise<TourGpxPreviewResponse | null> {
const { rows, leftOut } = await readTourFile(this.placeImport, fileBuffer, fileName);