diff --git a/lib/microwaveprop_web/live/rover_planning_live/show.ex b/lib/microwaveprop_web/live/rover_planning_live/show.ex
index df906f6c..d7773899 100644
--- a/lib/microwaveprop_web/live/rover_planning_live/show.ex
+++ b/lib/microwaveprop_web/live/rover_planning_live/show.ex
@@ -253,6 +253,27 @@ defmodule MicrowavepropWeb.RoverPlanningLive.Show do
defp station_grid(_), do: nil
+ # Inline label for the "Stationary stations" summary list. Prefers the
+ # callsign (uppercased — legacy data was stored mixed-case), then the
+ # grid, then the input string when neither is set. Bare lat/lon
+ # coordinates are intentionally NOT used as a label here — the grid
+ # half (via `stationary_grid/1`) carries that location info.
+ defp stationary_label(%{callsign: c}) when is_binary(c) and c != "", do: String.upcase(c)
+ defp stationary_label(%{grid: g}) when is_binary(g) and g != "", do: g
+
+ defp stationary_label(%{input: i}) when is_binary(i) and i != "" do
+ if LocationResolver.coordinate_pair?(i), do: nil, else: String.upcase(i)
+ end
+
+ defp stationary_label(_), do: nil
+
+ defp stationary_grid(%{grid: g}) when is_binary(g) and g != "", do: g
+
+ defp stationary_grid(%{lat: lat, lon: lon}) when is_number(lat) and is_number(lon),
+ do: Maidenhead.from_latlon(lat, lon, 6)
+
+ defp stationary_grid(_), do: nil
+
# Endpoint string used for /path?destination=…. Prefers callsign, then
# any stored or derived grid (PathLive's LocationResolver re-resolves
# both back to the same point), falling back to bare coordinates only
@@ -331,10 +352,11 @@ defmodule MicrowavepropWeb.RoverPlanningLive.Show do
Stationary stations
-
- {station.callsign || station.grid || station.input}
- grid {station.grid}
-
- {Float.round(station.lat, 4)}, {Float.round(station.lon, 4)}
+
+ {stationary_label(station)}
+
+
+ {stationary_grid(station)}
diff --git a/test/microwaveprop_web/live/rover_planning_live_test.exs b/test/microwaveprop_web/live/rover_planning_live_test.exs
index 2bbf215c..fe9e28d2 100644
--- a/test/microwaveprop_web/live/rover_planning_live_test.exs
+++ b/test/microwaveprop_web/live/rover_planning_live_test.exs
@@ -231,6 +231,34 @@ defmodule MicrowavepropWeb.RoverPlanningLiveTest do
assert html =~ "Propagation"
end
+ test "stationary stations list shows uppercase callsign + grid, not bare lat/lon", %{conn: conn} do
+ import Ecto.Query, only: [from: 2]
+
+ user = AccountsFixtures.user_fixture()
+ mission = create_mission(user, "Stationary label mission")
+
+ # Backdate the station to mimic legacy data: callsign persisted in
+ # lowercase, no stored grid. The display should still render the
+ # callsign uppercase and synthesize a grid from lat/lon.
+ mission_id = mission.id
+
+ [s1] =
+ Repo.all(from s in Microwaveprop.RoverPlanning.Station, where: s.mission_id == ^mission_id)
+
+ {:ok, _} =
+ s1
+ |> Ecto.Changeset.change(%{callsign: "aa5c", grid: nil, lat: 33.1889, lon: -96.4517})
+ |> Repo.update()
+
+ {:ok, _lv, html} = live(conn, ~p"/rover-planning/#{mission.id}")
+
+ assert html =~ "AA5C"
+ # Bare lat/lon must not appear in the stationary-stations list.
+ refute html =~ "33.1889, -96.4517"
+ # A grid (derived from lat/lon when none is stored) IS shown.
+ assert html =~ Maidenhead.from_latlon(33.1889, -96.4517, 6)
+ end
+
test "rover-location group heading links to /rover-locations/:id", %{conn: conn} do
user = AccountsFixtures.user_fixture()
mission = create_mission(user, "Linked heading mission")