Queue UI fixes: disable would-409 controls, hover trace from landing airport, grounded queues draw dotted lines (ISS-077, v0.41.0)
CI / build + unit + e2e (pull_request) Successful in 9m11s

This commit is contained in:
2026-09-21 13:29:27 +00:00
parent 4a6a8592e0
commit 68cfad434b
8 changed files with 190 additions and 49 deletions
+18 -8
View File
@@ -116,7 +116,10 @@ export function hoverRouteGeoJson(
// ISS-040 (v0.23.2): the on-board package hover trace — same shape as hoverRouteGeoJson but the
// start is a live COORDINATE (the carrier plane's current position), not an airport ICAO: once the
// plane has departed with cargo still loaded, the preview must begin where it actually is. Empty
// collection when the destination is missing from the dataset — never guessed.
// collection when the destination is missing from the dataset — never guessed. ISS-077 (v0.41.0):
// also empty when the start point IS the destination airport itself (a flying carrier's trace now
// starts at its landing airport, which can equal the package's dest) — nothing to draw there; the
// solid active-leg layer covers that case.
export function hoverTraceGeoJson(
from: AirportCoord,
toIcao: string,
@@ -124,6 +127,7 @@ export function hoverTraceGeoJson(
): FeatureCollection<MapLineFeature> {
const to = airportsByIcao.get(toIcao);
if (!to) return EMPTY_LINES;
if (from.lat === to.lat && from.lon === to.lon) return EMPTY_LINES; // start == dest — zero-length trace
return {
type: 'FeatureCollection',
features: [
@@ -166,19 +170,25 @@ export function routesGeoJson(
return { type: 'FeatureCollection', features };
}
// ISS-043 (v0.26.0): the dotted queue line — one LineString per FLYING plane with a non-empty
// queue, chaining dest → queue[0] → … → queue[n−1]: ONLY the not-yet-started legs (the active
// leg locationIcao→dest stays in routesGeoJson's solid layer). Arcs are concatenated with the
// shared joint point dropped once. A plane is skipped — never guessed — when its dest or any
// queued ICAO is missing from the airport index; empty collection when nothing qualifies.
// ISS-043 (v0.26.0): the dotted queue line — one LineString per plane with a non-empty queue,
// chaining the not-yet-started legs: a FLYING plane starts at its active leg's destination
// (dest → queue[0] → …; the active leg locationIcao→dest stays in routesGeoJson's solid layer),
// and ISS-077 (v0.41.0) extends it to GROUNDED ('available') planes, which start at their current
// airport (locationIcao → queue[0] → …). 'repairing' planes draw nothing — they can't fly. Arcs are
// concatenated with the shared joint point dropped once. A plane is skipped — never guessed — when
// its first point or any queued ICAO is missing from the airport index; empty collection when
// nothing qualifies.
export function queuedRoutesGeoJson(
planes: PlaneState[],
airportsByIcao: ReadonlyMap<string, AirportCoord>,
): FeatureCollection<MapLineFeature> {
const features: MapLineFeature[] = [];
for (const p of planes) {
if (p.status !== 'flying' || !p.destIcao || p.queue.length === 0) continue;
const pts = [p.destIcao, ...p.queue].map((icao) => airportsByIcao.get(icao));
if (p.queue.length === 0) continue;
// First point of the chain: a flying plane's landing airport, a grounded one's current airport.
const firstIcao = p.status === 'flying' ? p.destIcao : p.status === 'available' ? p.locationIcao : null;
if (!firstIcao) continue;
const pts = [firstIcao, ...p.queue].map((icao) => airportsByIcao.get(icao));
if (pts.some((c) => c === undefined)) continue; // an endpoint is missing from the dataset — skip
const coords: [number, number][] = [];
for (let i = 0; i < pts.length - 1; i++) {