fix(weather-map): default timeline cursor to the hour closest to now
Previously the map loaded the latest cached valid_time from GridCache, which can be any +Nh forecast hour the worker has written while walking f00-f18. Users expect to see current conditions on load, not a forecast that's ~11 hours out.
This commit is contained in:
parent
d22a0bba36
commit
c09446a517
2 changed files with 54 additions and 9 deletions
|
|
@ -143,14 +143,25 @@ defmodule MicrowavepropWeb.WeatherMapLive do
|
|||
Phoenix.PubSub.subscribe(Microwaveprop.PubSub, "propagation:pipeline")
|
||||
end
|
||||
|
||||
# Hot-path mount: use the cache-only latest_weather_grid for the
|
||||
# initial payload so mount stays under the LV socket join timeout
|
||||
# (~10s). Reading and deriving the full 92k-point ProfilesFile
|
||||
# synchronously pushes mount past that window on a cold pod,
|
||||
# which makes the LV client fall back to a full page reload.
|
||||
data = Weather.latest_weather_grid(@initial_bounds)
|
||||
latest_vt = if data == [], do: Weather.latest_grid_valid_time(), else: hd(data).valid_time
|
||||
# Default the timeline cursor to the valid_time closest to "now" so
|
||||
# users land on current conditions, not a +11h forecast hour (which
|
||||
# the underlying cache can advance to while the worker is walking
|
||||
# f00→f18).
|
||||
#
|
||||
# Hot-path mount: when the closest-to-now time happens to be the
|
||||
# cached latest, use `latest_weather_grid/1` so mount stays under
|
||||
# the LV socket join timeout (~10s). A ProfilesFile read for any
|
||||
# other hour is a single ~2 MB ETF decode, also fine for mount.
|
||||
valid_times = Weather.available_weather_valid_times()
|
||||
latest_vt = Weather.latest_grid_valid_time()
|
||||
initial_vt = pick_initial_valid_time(valid_times)
|
||||
|
||||
data =
|
||||
cond do
|
||||
is_nil(initial_vt) -> []
|
||||
initial_vt == latest_vt -> Weather.latest_weather_grid(@initial_bounds)
|
||||
true -> Weather.weather_grid_at(initial_vt, @initial_bounds)
|
||||
end
|
||||
|
||||
{:ok,
|
||||
assign(socket,
|
||||
|
|
@ -158,10 +169,10 @@ defmodule MicrowavepropWeb.WeatherMapLive do
|
|||
layers: @layers,
|
||||
selected_layer: "refractivity_gradient",
|
||||
initial_data_json: Jason.encode!(data),
|
||||
valid_time: latest_vt,
|
||||
valid_time: initial_vt,
|
||||
valid_times: valid_times,
|
||||
initial_valid_times_json: Jason.encode!(Enum.map(valid_times, &DateTime.to_iso8601/1)),
|
||||
initial_selected_time: latest_vt && DateTime.to_iso8601(latest_vt),
|
||||
initial_selected_time: initial_vt && DateTime.to_iso8601(initial_vt),
|
||||
initial_utc_clock: Calendar.strftime(DateTime.utc_now(), "%H:%M UTC"),
|
||||
bounds: @initial_bounds,
|
||||
grid_visible: false,
|
||||
|
|
@ -169,6 +180,13 @@ defmodule MicrowavepropWeb.WeatherMapLive do
|
|||
)}
|
||||
end
|
||||
|
||||
defp pick_initial_valid_time([]), do: nil
|
||||
|
||||
defp pick_initial_valid_time(valid_times) do
|
||||
now = DateTime.utc_now()
|
||||
Enum.min_by(valid_times, fn vt -> abs(DateTime.diff(vt, now, :second)) end)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("select_layer", %{"layer" => layer_id}, socket) do
|
||||
{:noreply, assign(socket, :selected_layer, layer_id)}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,33 @@ defmodule MicrowavepropWeb.WeatherMapLiveTest do
|
|||
end)
|
||||
end
|
||||
|
||||
test "mount defaults to the valid_time closest to now, not the latest forecast hour",
|
||||
%{conn: conn} do
|
||||
base =
|
||||
DateTime.utc_now()
|
||||
|> DateTime.truncate(:second)
|
||||
|> Map.put(:minute, 0)
|
||||
|> Map.put(:second, 0)
|
||||
|
||||
# Seed f00 (now) and f11 (+11h). The worker walks forecast hours
|
||||
# sequentially so `latest_grid_valid_time` can point to f11 even
|
||||
# though the user expects the map to show "Now" by default.
|
||||
now_t = base
|
||||
future_t = DateTime.add(base, 11 * 3600, :second)
|
||||
|
||||
write_profile(now_t, 33.0, -97.0)
|
||||
write_profile(future_t, 33.0, -97.0)
|
||||
|
||||
{:ok, _lv, html} = live(conn, ~p"/weather")
|
||||
|
||||
now_iso = DateTime.to_iso8601(now_t)
|
||||
future_iso = DateTime.to_iso8601(future_t)
|
||||
|
||||
# The map element's data-selected-time attribute should be f00, not f11.
|
||||
assert html =~ ~s(data-selected-time="#{now_iso}")
|
||||
refute html =~ ~s(data-selected-time="#{future_iso}")
|
||||
end
|
||||
|
||||
test "select_time replaces the rendered weather data with the new hour's grid", %{conn: conn} do
|
||||
base =
|
||||
DateTime.utc_now()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue