Skip to content

Commit 7be6d70

Browse files
committed
resolve flight routes
1 parent f3d1d5a commit 7be6d70

File tree

3 files changed

+97
-19
lines changed

3 files changed

+97
-19
lines changed

src/local_flight_map/ui/app/data.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Handles aircraft data processing, enrichment, and conversion to GeoJSON format.
44
"""
55

6-
from typing import Dict, Any, Union
6+
from typing import Dict, Any, Union, Tuple, Optional
77
import asyncio
88

99
from ...api import ApiClients, Location
@@ -130,11 +130,12 @@ async def _process_feature(self, feature: Dict[str, Any]) -> Dict[str, Any]:
130130

131131
async with self._semaphore:
132132
try:
133-
icao24 = feature["properties"]["icao24_code"]
133+
icao24 = feature.get("properties", {}).get("icao24_code", "unknown")
134+
callsign = feature.get("properties", {}).get("callsign", "unknown")
134135
async with self._hexdb_semaphore:
135136
for result in await asyncio.gather(
136137
self._clients.hexdb_client.get_aircraft_information_from_hexdb(icao24),
137-
self._clients.hexdb_client.get_route_information_from_hexdb(icao24),
138+
self._clients.hexdb_client.get_route_information_from_hexdb(callsign),
138139
return_exceptions=True
139140
):
140141
if isinstance(result, Exception):
@@ -143,11 +144,27 @@ async def _process_feature(self, feature: Dict[str, Any]) -> Dict[str, Any]:
143144
if result:
144145
result.enrich_geojson(feature, inplace=True)
145146

147+
async def resolve_route(label: str, route: str) -> Tuple[str, Optional[Dict[str, Any]]]:
148+
airport = await self._clients.hexdb_client.get_airport_information_from_hexdb(route)
149+
return label, airport.to_geojson() if airport else None
150+
151+
for label, airport in await asyncio.gather(
152+
*[
153+
resolve_route(label, route)
154+
for label, route in zip(
155+
("origin", "destination"),
156+
feature.get("properties", {}).get("route", "-").split("-", 1)
157+
)
158+
if route
159+
]
160+
):
161+
for name, value in airport["properties"].items():
162+
feature["properties"][f"{label}_{name}"] = value
163+
146164
self._generate_tags(feature, inplace=True)
147165

148166
except Exception as e:
149-
icao24 = feature.get('properties', {}).get('icao24_code', 'unknown')
150-
logger.error(f"Error processing feature {icao24}: {str(e)}")
167+
logger.error(f"Error processing feature {icao24}/{callsign}: {str(e)}")
151168

152169
finally:
153170
return feature

src/local_flight_map/ui/app/static/css/components.css

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,11 @@
138138

139139
/* Section title styles */
140140
.section-title {
141-
margin-bottom: var(--spacing-lg);
141+
margin-top: var(--spacing-xl);
142+
margin-bottom: var(--spacing-md);
142143
font-weight: 500;
144+
display: block;
145+
position: relative;
143146
}
144147

145148
/* Cookie consent modal styles */
@@ -236,4 +239,10 @@
236239
width: 16px;
237240
height: 16px;
238241
opacity: 0.8;
242+
}
243+
244+
.aircraft-info table {
245+
width: 100%;
246+
border-collapse: collapse;
247+
margin-bottom: var(--spacing-md);
239248
}

src/local_flight_map/ui/plugins/js/realtime_point_to_layer.js

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -270,26 +270,78 @@
270270
<td class="distance-info"></td>
271271
</tr>
272272
</tbody>
273-
</table>
273+
</table>`;
274+
275+
// Add origin section if there are origin properties
276+
const originProps = Object.entries(props).filter(([key]) => key.startsWith('origin_'));
277+
if (originProps.length > 0) {
278+
content += `
279+
<div class="section-title">Origin</div>
280+
<table>
281+
<tbody>`;
282+
for (const [key, value] of originProps) {
283+
const displayKey = key.replace('origin_', '');
284+
const displayValue = typeof value === 'object' && value !== null ? JSON.stringify(value, null, 2) : value;
285+
content += `
286+
<tr>
287+
<th>${displayKey}</th>
288+
<td>${displayValue}</td>
289+
</tr>`;
290+
}
291+
content += `
292+
</tbody>
293+
</table>`;
294+
}
295+
296+
// Add destination section if there are destination properties
297+
const destinationProps = Object.entries(props).filter(([key]) => key.startsWith('destination_'));
298+
if (destinationProps.length > 0) {
299+
content += `
300+
<div class="section-title">Destination</div>
301+
<table>
302+
<tbody>`;
303+
for (const [key, value] of destinationProps) {
304+
const displayKey = key.replace('destination_', '');
305+
const displayValue = typeof value === 'object' && value !== null ? JSON.stringify(value, null, 2) : value;
306+
content += `
307+
<tr>
308+
<th>${displayKey}</th>
309+
<td>${displayValue}</td>
310+
</tr>`;
311+
}
312+
content += `
313+
</tbody>
314+
</table>`;
315+
}
316+
317+
// Add remaining properties section
318+
const remainingProps = Object.entries(props).filter(([key]) =>
319+
!key.startsWith('origin_') &&
320+
!key.startsWith('destination_') &&
321+
key !== 'tags' &&
322+
key !== 'latitude' &&
323+
key !== 'longitude'
324+
);
325+
326+
if (remainingProps.length > 0) {
327+
content += `
274328
<div class="section-title">Properties</div>
275329
<table>
276330
<tbody>`;
277-
for (var key in props) {
278-
if (key === "tags") continue;
279-
let value = props[key];
280-
// Convert objects to readable JSON strings
281-
if (typeof value === 'object' && value !== null) {
282-
value = JSON.stringify(value, null, 2);
331+
for (const [key, value] of remainingProps) {
332+
const displayValue = typeof value === 'object' && value !== null ? JSON.stringify(value, null, 2) : value;
333+
content += `
334+
<tr>
335+
<th>${key}</th>
336+
<td>${displayValue}</td>
337+
</tr>`;
283338
}
284339
content += `
285-
<tr>
286-
<th>${key}</th>
287-
<td>${value}</td>
288-
</tr>`;
340+
</tbody>
341+
</table>`;
289342
}
343+
290344
content += `
291-
</tbody>
292-
</table>
293345
</div>`;
294346
return content;
295347
}

0 commit comments

Comments
 (0)