feat: pass FINNHUB_API_KEY to Docker, update layer defaults, cluster APRS

- Add FINNHUB_API_KEY to docker-compose.yml so financial ticker works
  in Docker deployments
- Update default layer config: planes/ships ON, satellites only for
  space, no fire hotspots, military bases + internet outages for infra,
  all SIGINT except HF digital spots
- Add MapLibre native clustering to APRS markers (matches Meshtastic)
  with cluster radius 42, breaks apart at zoom 8
This commit is contained in:
anoracleofra-code
2026-03-26 20:16:40 -06:00
parent da09cf429e
commit c5d48aa636
3 changed files with 90 additions and 41 deletions
+1
View File
@@ -10,6 +10,7 @@ services:
- OPENSKY_CLIENT_SECRET=${OPENSKY_CLIENT_SECRET}
- LTA_ACCOUNT_KEY=${LTA_ACCOUNT_KEY}
- ADMIN_KEY=${ADMIN_KEY:-}
- FINNHUB_API_KEY=${FINNHUB_API_KEY:-}
# Override allowed CORS origins (comma-separated). Auto-detects LAN IPs if empty.
- CORS_ORIGINS=${CORS_ORIGINS:-}
# Default Infonet relay peer so fresh installs can sync immediately.
+30 -22
View File
@@ -365,47 +365,55 @@ export default function Dashboard() {
}, []);
const [activeLayers, setActiveLayers] = useState<ActiveLayers>({
// Aircraft — all ON
flights: true,
private: true,
jets: true,
military: true,
tracked: true,
satellites: true,
gps_jamming: true,
// Maritime — all ON
ships_military: true,
ships_cargo: true,
ships_civilian: true,
ships_passenger: true,
ships_tracked_yachts: true,
earthquakes: true,
cctv: true,
ukraine_frontline: true,
global_incidents: true,
day_night: true,
gps_jamming: true,
fishing_activity: true,
// Space — only satellites
satellites: true,
gibs_imagery: false,
highres_satellite: false,
sentinel_hub: false,
viirs_nightlights: false,
// Hazards — no fire, rest ON
earthquakes: true,
firms: false,
ukraine_alerts: true,
weather_alerts: true,
volcanoes: true,
air_quality: true,
// Infrastructure — military bases + internet outages only
cctv: false,
datacenters: false,
internet_outages: true,
power_plants: false,
military_bases: true,
trains: false,
// SIGINT — all ON except HF digital spots
kiwisdr: true,
psk_reporter: true,
psk_reporter: false,
satnogs: true,
tinygs: true,
scanners: true,
firms: true,
internet_outages: true,
datacenters: true,
military_bases: true,
power_plants: false,
sigint_meshtastic: true,
sigint_aprs: true,
ukraine_alerts: true,
weather_alerts: true,
air_quality: true,
volcanoes: true,
fishing_activity: true,
sentinel_hub: false,
trains: true,
shodan_overlay: false,
viirs_nightlights: false,
// Overlays
ukraine_frontline: true,
global_incidents: true,
day_night: true,
correlations: true,
// Shodan
shodan_overlay: false,
});
const [shodanResults, setShodanResults] = useState<ShodanSearchMatch[]>([]);
const [, setShodanQueryLabel] = useState('');
+59 -19
View File
@@ -1595,6 +1595,8 @@ const MaplibreViewer = ({
meshtasticGeoJSON && 'meshtastic-clusters',
meshtasticGeoJSON && 'meshtastic-cluster-count',
meshtasticGeoJSON && 'meshtastic-circles',
aprsGeoJSON && 'aprs-clusters',
aprsGeoJSON && 'aprs-cluster-count',
aprsGeoJSON && 'aprs-triangles',
ukraineAlertsGeoJSON && 'ukraine-alerts-fill',
weatherAlertsGeoJSON && 'weather-alerts-fill',
@@ -3180,44 +3182,82 @@ const MaplibreViewer = ({
/>
</Source>
{/* APRS / JS8Call — pink triangles */}
<Source id="aprs-source" type="geojson" data={EMPTY_FC}>
{/* APRS / JS8Call — pink triangles with clustering */}
<Source
id="aprs-source"
type="geojson"
data={EMPTY_FC}
cluster={true}
clusterRadius={42}
clusterMaxZoom={8}
>
<Layer
id="aprs-halo"
type="circle"
paint={{
'circle-radius': ['interpolate', ['linear'], ['zoom'], 2, 4, 6, 6, 10, 8],
'circle-color': '#f472b6',
'circle-opacity': 0.14,
'circle-stroke-width': 1,
'circle-stroke-color': '#f9a8d4',
'circle-stroke-opacity': 0.45,
}}
/>
<Layer
id="aprs-triangles"
id="aprs-clusters"
type="symbol"
filter={['has', 'point_count']}
layout={{
'icon-image': 'icon-aprs-triangle',
'icon-size': ['interpolate', ['linear'], ['zoom'], 2, 0.8, 6, 1.0, 10, 1.15],
'icon-size': [
'step',
['get', 'point_count'],
1.1,
10,
1.35,
50,
1.65,
100,
1.95,
500,
2.3,
],
'icon-allow-overlap': true,
'icon-ignore-placement': true,
}}
paint={{
'icon-opacity': 0.95,
}}
/>
<Layer
id="aprs-cluster-count"
type="symbol"
filter={['has', 'point_count']}
layout={{
'text-field': ['get', 'point_count_abbreviated'],
'text-size': 11,
'text-font': ['Noto Sans Bold'],
'text-offset': [0, 0.05],
'text-anchor': 'center',
'text-allow-overlap': true,
}}
paint={{
'text-color': '#4a0525',
'text-halo-color': '#f9a8d4',
'text-halo-width': 0.8,
}}
/>
<Layer
id="aprs-triangles"
type="symbol"
filter={['!', ['has', 'point_count']]}
layout={{
'icon-image': 'icon-aprs-triangle',
'icon-size': 0.7,
'icon-allow-overlap': true,
}}
paint={{
'icon-opacity': 0.85,
}}
/>
<Layer
id="aprs-labels"
type="symbol"
minzoom={5}
minzoom={8}
layout={{
'text-field': ['get', 'callsign'],
'text-size': 9,
'text-offset': [0, 1.2],
'text-anchor': 'top',
'text-font': ['Noto Sans Regular'],
'text-allow-overlap': true,
'text-allow-overlap': false,
}}
paint={{
'text-color': '#f9a8d4',