From b4d70a9e198fab7fd401d85f416f15e57d6b3280 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 3 Jul 2024 13:49:36 -0400 Subject: [PATCH 01/30] Added field to struct. --- lib/screens/stops/parser.ex | 9 +++++++-- lib/screens/stops/stop.ex | 6 ++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/screens/stops/parser.ex b/lib/screens/stops/parser.ex index 00bec837d..0821ce17a 100644 --- a/lib/screens/stops/parser.ex +++ b/lib/screens/stops/parser.ex @@ -3,12 +3,17 @@ defmodule Screens.Stops.Parser do def parse_stop(%{ "id" => id, - "attributes" => %{"name" => name, "platform_code" => platform_code} + "attributes" => %{ + "name" => name, + "platform_code" => platform_code, + "platform_name" => platform_name + } }) do %Screens.Stops.Stop{ id: id, name: name, - platform_code: platform_code + platform_code: platform_code, + platform_name: platform_name } end end diff --git a/lib/screens/stops/stop.ex b/lib/screens/stops/stop.ex index bda4d6b9e..40ae2a9b6 100644 --- a/lib/screens/stops/stop.ex +++ b/lib/screens/stops/stop.ex @@ -22,14 +22,16 @@ defmodule Screens.Stops.Stop do defstruct id: nil, name: nil, - platform_code: nil + platform_code: nil, + platform_name: nil @type id :: String.t() @type t :: %__MODULE__{ id: id, name: String.t(), - platform_code: String.t() | nil + platform_code: String.t() | nil, + platform_name: String.t() | nil } @type screen_type :: BusEink | BusShelter | GlEink | PreFare | Dup | Triptych From 4e4410d2d8435442f7bd3318519ae4f732a010ca Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 3 Jul 2024 13:49:56 -0400 Subject: [PATCH 02/30] Added fetch for all platform IDs at a station. --- lib/screens/stops/stop.ex | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/screens/stops/stop.ex b/lib/screens/stops/stop.ex index 40ae2a9b6..d4c4c276b 100644 --- a/lib/screens/stops/stop.ex +++ b/lib/screens/stops/stop.ex @@ -12,7 +12,7 @@ defmodule Screens.Stops.Stop do alias Screens.LocationContext alias Screens.RoutePatterns.RoutePattern - alias Screens.Routes + alias Screens.{Routes, Stops} alias Screens.Routes.Route alias Screens.RouteType alias Screens.Stops.StationsWithRoutesAgent @@ -363,6 +363,21 @@ defmodule Screens.Stops.Stop do end end + def fetch_subway_platforms_for_stop(stop_id) do + case Screens.V3Api.get_json("stops/" <> stop_id, %{"include" => "child_stops"}) do + {:ok, %{"included" => child_stop_data}} -> + Enum.filter(child_stop_data, fn %{ + "attributes" => %{ + "location_type" => location_type, + "vehicle_type" => vehicle_type + } + } -> + location_type == 0 and vehicle_type == 1 + end) + |> Enum.map(&Stops.Parser.parse_stop/1) + end + end + # --- END API functions --- def stop_on_route?(stop_id, stop_sequence) when not is_nil(stop_id) do From 57c3c0dd8aedbf69a71401834be73f90f31f4f3e Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 3 Jul 2024 15:05:20 -0400 Subject: [PATCH 03/30] Added edge cases so widgets can handle single platform closures. --- lib/screens/alerts/alert.ex | 12 ++++++ .../widgets/reconstructed_alert.ex | 31 ++++++++++++-- .../v2/widget_instance/reconstructed_alert.ex | 42 ++++++++++++++++++- .../v2/widget_instance/subway_status.ex | 18 +++++--- 4 files changed, 92 insertions(+), 11 deletions(-) diff --git a/lib/screens/alerts/alert.ex b/lib/screens/alerts/alert.ex index b14b05879..db6f3e333 100644 --- a/lib/screens/alerts/alert.ex +++ b/lib/screens/alerts/alert.ex @@ -592,4 +592,16 @@ defmodule Screens.Alerts.Alert do def direction_id(%__MODULE__{informed_entities: informed_entities}), do: List.first(informed_entities).direction_id + + def is_child_stop_closure?(%__MODULE__{ + effect: :station_closure, + informed_entities: informed_entities + }) do + affected_platform_ids = + Enum.reject(informed_entities, &String.starts_with?(&1.stop, "place-")) + + length(affected_platform_ids) == 1 + end + + def is_child_stop_closure?(_), do: false end diff --git a/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex b/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex index ff4382d0f..f21e70040 100644 --- a/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex +++ b/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex @@ -53,7 +53,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlert do now \\ DateTime.utc_now(), fetch_alerts_fn \\ &Alert.fetch/1, fetch_stop_name_fn \\ &Stop.fetch_stop_name/1, - fetch_location_context_fn \\ &Stop.fetch_location_context/3 + fetch_location_context_fn \\ &Stop.fetch_location_context/3, + fetch_subway_platforms_for_stop_fn \\ &Stop.fetch_subway_platforms_for_stop/1 ) do %PreFare{ reconstructed_alert_widget: %CurrentStopId{stop_id: stop_id} @@ -75,7 +76,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlert do location_context: location_context, fetch_stop_name_fn: fetch_stop_name_fn, is_terminal_station: is_terminal_station, - now: now + now: now, + fetch_subway_platforms_for_stop_fn: fetch_subway_platforms_for_stop_fn ] cond do @@ -157,9 +159,12 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlert do location_context: location_context, fetch_stop_name_fn: fetch_stop_name_fn, is_terminal_station: is_terminal_station, - now: now + now: now, + fetch_subway_platforms_for_stop_fn: fetch_subway_platforms_for_stop_fn ) do Enum.map(alerts, fn alert -> + is_child_stop_closure? = Alert.is_child_stop_closure?(alert) + %ReconstructedAlert{ screen: config, alert: alert, @@ -167,11 +172,29 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlert do location_context: location_context, informed_stations: get_stations(alert, fetch_stop_name_fn), is_terminal_station: is_terminal_station, - is_full_screen: is_full_screen + is_full_screen: is_full_screen, + use_fallback_layout: is_child_stop_closure?, + informed_platform: + get_closed_platform(alert, is_child_stop_closure?, fetch_subway_platforms_for_stop_fn) } end) end + defp get_closed_platform(_, false, _), do: nil + + defp get_closed_platform( + %{effect: :station_closure, informed_entities: informed_entities}, + true, + fetch_subway_platforms_for_stop_fn + ) do + {[informed_parent_station], [informed_platform]} = + Enum.split_with(informed_entities, &String.starts_with?(&1.stop, "place-")) + + informed_parent_station.stop + |> fetch_subway_platforms_for_stop_fn.() + |> Enum.find(&(&1.id == informed_platform.stop)) + end + defp find_closest_downstream_alerts(alerts, stop_id, stop_sequences) do home_stop_distance_map = build_distance_map(stop_id, stop_sequences) # Map each alert with its distance from home. diff --git a/lib/screens/v2/widget_instance/reconstructed_alert.ex b/lib/screens/v2/widget_instance/reconstructed_alert.ex index 5549313d2..1dc441b03 100644 --- a/lib/screens/v2/widget_instance/reconstructed_alert.ex +++ b/lib/screens/v2/widget_instance/reconstructed_alert.ex @@ -23,7 +23,9 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do informed_stations: nil, is_terminal_station: false, # Full screen alert, whether that's a single or dual screen alert - is_full_screen: false + is_full_screen: false, + use_fallback_layout: false, + informed_platform: nil @type stop_id :: String.t() @@ -36,7 +38,9 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do location_context: LocationContext.t(), informed_stations: list(String.t()), is_terminal_station: boolean(), - is_full_screen: boolean() + is_full_screen: boolean(), + use_fallback_layout: boolean(), + informed_platform: Stop.t() | nil } @type serialized_response :: @@ -1024,6 +1028,27 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do end end + # We assume this alert affects only one platform at one station. + defp serialize_outside_alert( + %__MODULE__{ + use_fallback_layout: true, + alert: %Alert{effect: :station_closure}, + informed_stations: [informed_station], + informed_platform: informed_platform + } = t, + _location + ) do + %{ + issue: "Bypassing #{informed_platform.platform_name} platform at #{informed_station}", + remedy: nil, + location: "", + cause: nil, + routes: get_route_pills(t), + effect: :station_closure, + urgent: false + } + end + defp serialize_outside_alert( %__MODULE__{alert: %Alert{effect: :station_closure}} = t, _location @@ -1165,6 +1190,14 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do def serialize(widget, log_fn \\ &Logger.warning/1) + def serialize(%__MODULE__{is_full_screen: true, use_fallback_layout: true} = t, _log_fn) do + location = LocalizedAlert.location(t) + + t + |> serialize_single_screen_fallback_alert(location) + |> Map.merge(%{effect: :fallback}) + end + def serialize(%__MODULE__{is_full_screen: true, alert: %Alert{effect: effect}} = t, log_fn) do diagram_data = serialize_diagram(t, log_fn) @@ -1233,6 +1266,9 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do def slot_names(%__MODULE__{is_full_screen: false}), do: [:large] + def slot_names(%__MODULE__{use_fallback_layout: true, alert: %{effect: :station_closure}}), + do: [:paged_main_content_left] + def slot_names(%__MODULE__{} = t) do if dual_screen_alert?(t), do: [:full_body], @@ -1241,6 +1277,8 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do def widget_type(%__MODULE__{is_full_screen: false}), do: :reconstructed_large_alert + def widget_type(%__MODULE__{use_fallback_layout: true}), do: :single_screen_alert + def widget_type(%__MODULE__{} = t) do if dual_screen_alert?(t), do: :reconstructed_takeover, diff --git a/lib/screens/v2/widget_instance/subway_status.ex b/lib/screens/v2/widget_instance/subway_status.ex index f78e76487..004fd7b54 100644 --- a/lib/screens/v2/widget_instance/subway_status.ex +++ b/lib/screens/v2/widget_instance/subway_status.ex @@ -380,15 +380,23 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do end defp serialize_alert( - %Alert{effect: :station_closure, informed_entities: informed_entities}, + %Alert{effect: :station_closure, informed_entities: informed_entities} = alert, route_id ) do - # Get closed station names from informed entities - stop_names = get_stop_names_from_informed_entities(informed_entities, route_id) + if Alert.is_child_stop_closure?(alert) do + %{ + status: "Bypassing 1 stop", + location: %{full: "mbta.com/alerts", abbrev: "mbta.com/alerts"}, + station_count: 1 + } + else + # Get closed station names from informed entities + stop_names = get_stop_names_from_informed_entities(informed_entities, route_id) - {status, location} = format_station_closure(stop_names) + {status, location} = format_station_closure(stop_names) - %{status: status, location: location, station_count: length(stop_names)} + %{status: status, location: location, station_count: length(stop_names)} + end end defp serialize_alert( From 2926d705d7e3d7b26b3af128a2f7c7a7e8399309 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 3 Jul 2024 15:05:47 -0400 Subject: [PATCH 04/30] Added PreFare alert tests. --- .../reconstructed_alert_test.exs | 142 +++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) diff --git a/test/screens/v2/widget_instance/reconstructed_alert_test.exs b/test/screens/v2/widget_instance/reconstructed_alert_test.exs index b37bcbf6d..a43eb7f43 100644 --- a/test/screens/v2/widget_instance/reconstructed_alert_test.exs +++ b/test/screens/v2/widget_instance/reconstructed_alert_test.exs @@ -129,6 +129,14 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do } end + defp put_use_fallback_layout(widget, use_fallback_layout) do + %{widget | use_fallback_layout: use_fallback_layout} + end + + defp put_informed_platform(widget, informed_platform) do + %{widget | informed_platform: informed_platform} + end + defp ie(opts) do %{ stop: opts[:stop], @@ -519,6 +527,21 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do assert [:large] == WidgetInstance.slot_names(widget) assert :reconstructed_large_alert == WidgetInstance.widget_type(widget) end + + test "returns :paged_main_content_left for full screen single platform closures", %{ + widget: widget + } do + widget = + widget + |> put_home_stop(PreFare, "place-forhl") + |> put_effect(:station_closure) + |> put_is_full_screen(true) + |> put_use_fallback_layout(true) + + assert [1] == WidgetInstance.priority(widget) + assert [:paged_main_content_left] == WidgetInstance.slot_names(widget) + assert :single_screen_alert == WidgetInstance.widget_type(widget) + end end describe "serialize_dual_screen_alert/1 single line station" do @@ -1042,6 +1065,90 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do assert expected == ReconstructedAlert.serialize(widget, &fake_log/1) end + + test "handles platform closure at home station", %{widget: widget} do + widget = + widget + |> put_home_stop(PreFare, "place-portr") + |> put_effect(:station_closure) + |> put_informed_entities([ + ie(stop: "place-portr", route: "Red", route_type: 1), + ie(stop: "70065", route: "Red", route_type: 1) + ]) + |> put_tagged_stop_sequences(%{ + "Red" => [["place-portr", "place-asmnl"]] + }) + |> put_cause(:unknown) + |> put_is_full_screen(true) + |> put_use_fallback_layout(true) + |> put_alert_header("Test Alert") + |> put_routes_at_stop([ + %{ + route_id: "Red", + active?: true, + direction_destinations: nil, + long_name: nil, + short_name: nil, + type: :subway + } + ]) + + expected = %{ + issue: nil, + remedy: nil, + remedy_bold: "Test Alert", + location: nil, + cause: nil, + routes: [%{route_id: "Red", svg_name: "rl"}], + effect: :fallback, + updated_at: "Friday, 5:00 am", + region: :here + } + + assert expected == ReconstructedAlert.serialize(widget, &fake_log/1) + end + + test "handles downstream platform closure", %{widget: widget} do + widget = + widget + |> put_home_stop(PreFare, "place-asmnl") + |> put_effect(:station_closure) + |> put_informed_entities([ + ie(stop: "place-portr", route: "Red", route_type: 1), + ie(stop: "70065", route: "Red", route_type: 1) + ]) + |> put_tagged_stop_sequences(%{ + "Red" => [["place-portr", "place-asmnl"]] + }) + |> put_cause(:unknown) + |> put_is_full_screen(true) + |> put_use_fallback_layout(true) + |> put_alert_header("Test Alert") + |> put_routes_at_stop([ + %{ + route_id: "Red", + active?: true, + direction_destinations: nil, + long_name: nil, + short_name: nil, + type: :subway + } + ]) + + expected = %{ + issue: nil, + remedy: nil, + remedy_bold: "Test Alert", + location: nil, + cause: nil, + routes: [%{route_id: "Red", svg_name: "rl-alewife", headsign: "Alewife"}], + effect: :fallback, + updated_at: "Friday, 5:00 am", + region: :outside + } + + assert expected == ReconstructedAlert.serialize(widget, &fake_log/1) + end end describe "serialize_fullscreen_alert/1 transfer station" do @@ -1473,7 +1580,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do assert expected == ReconstructedAlert.serialize(widget, &fake_log/1) end - test "handles station closure", %{widget: widget} do + test "handles full station closure", %{widget: widget} do widget = widget |> put_effect(:station_closure) @@ -1499,6 +1606,39 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do assert expected == ReconstructedAlert.serialize(widget, &fake_log/1) end + test "handles platform closure", %{widget: widget} do + widget = + widget + |> put_home_stop(PreFare, "place-asmnl") + |> put_effect(:station_closure) + |> put_informed_entities([ + ie(stop: "place-portr", route: "Red", route_type: 1), + ie(stop: "70065", route: "Red", route_type: 1) + ]) + |> put_tagged_stop_sequences(%{ + "Red" => [["place-portr", "place-asmnl"]] + }) + |> put_cause(:unknown) + |> put_informed_stations(["Porter"]) + |> put_use_fallback_layout(true) + |> put_informed_platform(%{id: "70065", platform_name: "Ashmont/Braintree"}) + + expected = %{ + issue: "Bypassing Ashmont/Braintree platform at Porter", + location: "", + cause: nil, + routes: [ + %{color: :red, text: "RED LINE", type: :text} + ], + effect: :station_closure, + urgent: false, + region: :outside, + remedy: nil + } + + assert expected == ReconstructedAlert.serialize(widget, &fake_log/1) + end + test "handles delay", %{widget: widget} do widget = widget From f1bb921652f07b49fa217b475126f42c32c4ac16 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 3 Jul 2024 15:11:29 -0400 Subject: [PATCH 05/30] Added SubwayStatus tests. --- .../v2/widget_instance/subway_status.ex | 3 +- .../v2/widget_instance/subway_status_test.exs | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/lib/screens/v2/widget_instance/subway_status.ex b/lib/screens/v2/widget_instance/subway_status.ex index 004fd7b54..5bd820bca 100644 --- a/lib/screens/v2/widget_instance/subway_status.ex +++ b/lib/screens/v2/widget_instance/subway_status.ex @@ -386,8 +386,7 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do if Alert.is_child_stop_closure?(alert) do %{ status: "Bypassing 1 stop", - location: %{full: "mbta.com/alerts", abbrev: "mbta.com/alerts"}, - station_count: 1 + location: %{full: "mbta.com/alerts", abbrev: "mbta.com/alerts"} } else # Get closed station names from informed entities diff --git a/test/screens/v2/widget_instance/subway_status_test.exs b/test/screens/v2/widget_instance/subway_status_test.exs index 6bd35b8a7..54cfe1645 100644 --- a/test/screens/v2/widget_instance/subway_status_test.exs +++ b/test/screens/v2/widget_instance/subway_status_test.exs @@ -1319,6 +1319,60 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do assert expected == WidgetInstance.serialize(instance) end + test "handles 1 platform closure alert" do + instance = %SubwayStatus{ + subway_alerts: [ + %Alert{ + effect: :station_closure, + informed_entities: [ + %{stop: "place-portr", route: "Red", route_type: 1}, + %{stop: "70065", route: "Red", route_type: 1} + ] + } + ] + } + + expected = %{ + blue: %{ + type: :contracted, + alerts: [ + %{ + route_pill: %{type: :text, text: "BL", color: :blue}, + status: "Normal Service" + } + ] + }, + orange: %{ + type: :contracted, + alerts: [ + %{ + route_pill: %{type: :text, text: "OL", color: :orange}, + status: "Normal Service" + } + ] + }, + red: %{ + type: :extended, + alert: %{ + status: "Bypassing 1 stop", + location: %{full: "mbta.com/alerts", abbrev: "mbta.com/alerts"}, + route_pill: %{type: :text, text: "RL", color: :red} + } + }, + green: %{ + type: :contracted, + alerts: [ + %{ + route_pill: %{type: :text, text: "GL", color: :green}, + status: "Normal Service" + } + ] + } + } + + assert expected == WidgetInstance.serialize(instance) + end + test "uses 'Entire line' location text for whole-line shuttles" do instance = %SubwayStatus{ subway_alerts: [ From c1b1e08e803909061e8cca5762a5f5061efe40fb Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 3 Jul 2024 15:12:06 -0400 Subject: [PATCH 06/30] Credo. --- lib/screens/stops/stop.ex | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/screens/stops/stop.ex b/lib/screens/stops/stop.ex index d4c4c276b..38ad5c4f8 100644 --- a/lib/screens/stops/stop.ex +++ b/lib/screens/stops/stop.ex @@ -366,12 +366,13 @@ defmodule Screens.Stops.Stop do def fetch_subway_platforms_for_stop(stop_id) do case Screens.V3Api.get_json("stops/" <> stop_id, %{"include" => "child_stops"}) do {:ok, %{"included" => child_stop_data}} -> - Enum.filter(child_stop_data, fn %{ - "attributes" => %{ - "location_type" => location_type, - "vehicle_type" => vehicle_type - } - } -> + child_stop_data + |> Enum.filter(fn %{ + "attributes" => %{ + "location_type" => location_type, + "vehicle_type" => vehicle_type + } + } -> location_type == 0 and vehicle_type == 1 end) |> Enum.map(&Stops.Parser.parse_stop/1) From 58bcfc787f168eaa1c837638b7c292b6283a5d63 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Mon, 8 Jul 2024 12:11:46 -0400 Subject: [PATCH 07/30] Fixed check so function can be used by WidgetInstances. --- lib/screens/alerts/alert.ex | 33 +++- .../widgets/reconstructed_alert.ex | 29 +-- .../v2/widget_instance/reconstructed_alert.ex | 165 +++++++++++------- .../widgets/reconstructed_alert_test.exs | 32 ++-- .../reconstructed_alert_test.exs | 40 +++-- 5 files changed, 187 insertions(+), 112 deletions(-) diff --git a/lib/screens/alerts/alert.ex b/lib/screens/alerts/alert.ex index db6f3e333..0c7b02976 100644 --- a/lib/screens/alerts/alert.ex +++ b/lib/screens/alerts/alert.ex @@ -593,15 +593,36 @@ defmodule Screens.Alerts.Alert do def direction_id(%__MODULE__{informed_entities: informed_entities}), do: List.first(informed_entities).direction_id - def is_child_stop_closure?(%__MODULE__{ - effect: :station_closure, + def informed_platforms(%__MODULE__{ informed_entities: informed_entities }) do - affected_platform_ids = - Enum.reject(informed_entities, &String.starts_with?(&1.stop, "place-")) + Enum.reject( + informed_entities, + &(String.starts_with?(&1.stop, "place-") or &1.route_type != 1) + ) + end + + def informed_parent_stations(%__MODULE__{ + informed_entities: informed_entities + }) do + Enum.filter(informed_entities, &String.starts_with?(&1.stop, "place-")) + end - length(affected_platform_ids) == 1 + @spec is_child_stop_closure?(__MODULE__.t(), list(Stop.t())) :: boolean() + def is_child_stop_closure?( + %__MODULE__{effect: :station_closure} = alert, + all_platforms_at_informed_station + ) do + informed_parent_stations = informed_parent_stations(alert) + + case informed_parent_stations do + [_] -> + length(informed_platforms(alert)) != length(all_platforms_at_informed_station) + + _ -> + false + end end - def is_child_stop_closure?(_), do: false + def is_child_stop_closure?(_, _), do: false end diff --git a/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex b/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex index f21e70040..831628c8e 100644 --- a/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex +++ b/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex @@ -163,7 +163,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlert do fetch_subway_platforms_for_stop_fn: fetch_subway_platforms_for_stop_fn ) do Enum.map(alerts, fn alert -> - is_child_stop_closure? = Alert.is_child_stop_closure?(alert) + all_platforms_at_informed_station = + get_platforms_at_informed_station(alert, fetch_subway_platforms_for_stop_fn) %ReconstructedAlert{ screen: config, @@ -173,28 +174,28 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlert do informed_stations: get_stations(alert, fetch_stop_name_fn), is_terminal_station: is_terminal_station, is_full_screen: is_full_screen, - use_fallback_layout: is_child_stop_closure?, - informed_platform: - get_closed_platform(alert, is_child_stop_closure?, fetch_subway_platforms_for_stop_fn) + all_platforms_at_informed_station: all_platforms_at_informed_station } end) end - defp get_closed_platform(_, false, _), do: nil - - defp get_closed_platform( - %{effect: :station_closure, informed_entities: informed_entities}, - true, + defp get_platforms_at_informed_station( + %{effect: :station_closure} = alert, fetch_subway_platforms_for_stop_fn ) do - {[informed_parent_station], [informed_platform]} = - Enum.split_with(informed_entities, &String.starts_with?(&1.stop, "place-")) + informed_parent_stations = Alert.informed_parent_stations(alert) + + case informed_parent_stations do + [informed_parent_station] -> + fetch_subway_platforms_for_stop_fn.(informed_parent_station.stop) - informed_parent_station.stop - |> fetch_subway_platforms_for_stop_fn.() - |> Enum.find(&(&1.id == informed_platform.stop)) + _ -> + [] + end end + defp get_platforms_at_informed_station(_, _), do: [] + defp find_closest_downstream_alerts(alerts, stop_id, stop_sequences) do home_stop_distance_map = build_distance_map(stop_id, stop_sequences) # Map each alert with its distance from home. diff --git a/lib/screens/v2/widget_instance/reconstructed_alert.ex b/lib/screens/v2/widget_instance/reconstructed_alert.ex index 1dc441b03..1adf9dae3 100644 --- a/lib/screens/v2/widget_instance/reconstructed_alert.ex +++ b/lib/screens/v2/widget_instance/reconstructed_alert.ex @@ -24,8 +24,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do is_terminal_station: false, # Full screen alert, whether that's a single or dual screen alert is_full_screen: false, - use_fallback_layout: false, - informed_platform: nil + all_platforms_at_informed_station: [] @type stop_id :: String.t() @@ -39,8 +38,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do informed_stations: list(String.t()), is_terminal_station: boolean(), is_full_screen: boolean(), - use_fallback_layout: boolean(), - informed_platform: Stop.t() | nil + all_platforms_at_informed_station: list(Stop.t()) } @type serialized_response :: @@ -1028,60 +1026,76 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do end end - # We assume this alert affects only one platform at one station. defp serialize_outside_alert( %__MODULE__{ - use_fallback_layout: true, - alert: %Alert{effect: :station_closure}, - informed_stations: [informed_station], - informed_platform: informed_platform + alert: %Alert{effect: :station_closure} = alert, + all_platforms_at_informed_station: all_platforms_at_informed_station } = t, _location ) do - %{ - issue: "Bypassing #{informed_platform.platform_name} platform at #{informed_station}", - remedy: nil, - location: "", - cause: nil, - routes: get_route_pills(t), - effect: :station_closure, - urgent: false - } + if Alert.is_child_stop_closure?(alert, all_platforms_at_informed_station) do + serialize_outside_platform_closure(t) + else + %{alert: %{cause: cause}, informed_stations: informed_stations} = t + cause_text = Alert.get_cause_string(cause) + + informed_stations_string = Util.format_name_list_to_string(informed_stations) + + %{ + issue: "Trains will bypass #{informed_stations_string}", + remedy: "Seek alternate route", + location: "", + cause: cause_text, + routes: get_route_pills(t), + effect: :station_closure, + urgent: false + } + end end defp serialize_outside_alert( - %__MODULE__{alert: %Alert{effect: :station_closure}} = t, + %__MODULE__{alert: %Alert{effect: :delay}} = t, _location ) do - %{alert: %{cause: cause}, informed_stations: informed_stations} = t - cause_text = Alert.get_cause_string(cause) - - informed_stations_string = Util.format_name_list_to_string(informed_stations) + %{alert: %{header: header}} = t %{ - issue: "Trains will bypass #{informed_stations_string}", - remedy: "Seek alternate route", + issue: header, + remedy: "", location: "", - cause: cause_text, + cause: "", routes: get_route_pills(t), - effect: :station_closure, + effect: :delay, urgent: false } end - defp serialize_outside_alert( - %__MODULE__{alert: %Alert{effect: :delay}} = t, - _location + defp serialize_outside_platform_closure( + %__MODULE__{ + alert: alert, + informed_stations: [informed_station], + all_platforms_at_informed_station: all_platforms_at_informed_station + } = t ) do - %{alert: %{header: header}} = t + issue = + case Alert.informed_platforms(alert) do + [informed_platform] -> + platform = + Enum.find(all_platforms_at_informed_station, &(&1.id == informed_platform.stop)) + + "Bypassing #{platform.platform_name} platform at #{informed_station}" + + informed_platforms -> + "Bypassing #{length(informed_platforms)} platform at #{informed_station}" + end %{ - issue: header, - remedy: "", + issue: issue, + remedy: nil, location: "", - cause: "", + cause: nil, routes: get_route_pills(t), - effect: :delay, + effect: :fallback, urgent: false } end @@ -1190,20 +1204,25 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do def serialize(widget, log_fn \\ &Logger.warning/1) - def serialize(%__MODULE__{is_full_screen: true, use_fallback_layout: true} = t, _log_fn) do + def serialize( + %__MODULE__{ + is_full_screen: true, + alert: %Alert{effect: effect} = alert, + all_platforms_at_informed_station: all_platforms_at_informed_station + } = t, + log_fn + ) do location = LocalizedAlert.location(t) - t - |> serialize_single_screen_fallback_alert(location) - |> Map.merge(%{effect: :fallback}) - end - - def serialize(%__MODULE__{is_full_screen: true, alert: %Alert{effect: effect}} = t, log_fn) do - diagram_data = serialize_diagram(t, log_fn) + if Alert.is_child_stop_closure?(alert, all_platforms_at_informed_station) do + t |> serialize_single_screen_fallback_alert(location) + else + diagram_data = serialize_diagram(t, log_fn) - main_data = pick_layout_serializer(t, diagram_data, effect, dual_screen_alert?(t)) + main_data = pick_layout_serializer(t, diagram_data, effect, location, dual_screen_alert?(t)) - Map.merge(main_data, diagram_data) + Map.merge(main_data, diagram_data) + end end def serialize(%__MODULE__{is_terminal_station: is_terminal_station} = t, _log_fn) do @@ -1235,19 +1254,20 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do end end - def pick_layout_serializer(t, diagram, effect, true) when diagram == %{} and effect != :delay, - do: serialize_dual_screen_fallback_alert(t) + def pick_layout_serializer(t, diagram, effect, location, is_dual_screen_alert) + + def pick_layout_serializer(t, diagram, effect, _, true) + when diagram == %{} and effect != :delay, + do: serialize_dual_screen_fallback_alert(t) - def pick_layout_serializer(t, diagram, effect, false) + def pick_layout_serializer(t, diagram, effect, location, false) when diagram == %{} and effect != :delay do - location = LocalizedAlert.location(t) serialize_single_screen_fallback_alert(t, location) end - def pick_layout_serializer(t, _, _, true), do: serialize_dual_screen_alert(t) + def pick_layout_serializer(t, _, _, _, true), do: serialize_dual_screen_alert(t) - def pick_layout_serializer(t, _, _, _) do - location = LocalizedAlert.location(t) + def pick_layout_serializer(t, _, _, location, _) do serialize_single_screen_alert(t, location) end @@ -1266,23 +1286,42 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do def slot_names(%__MODULE__{is_full_screen: false}), do: [:large] - def slot_names(%__MODULE__{use_fallback_layout: true, alert: %{effect: :station_closure}}), - do: [:paged_main_content_left] + def slot_names( + %__MODULE__{ + alert: alert, + all_platforms_at_informed_station: all_platforms_at_informed_station + } = t + ) do + cond do + Alert.is_child_stop_closure?(alert, all_platforms_at_informed_station) -> + [:paged_main_content_left] + + dual_screen_alert?(t) -> + [:full_body] - def slot_names(%__MODULE__{} = t) do - if dual_screen_alert?(t), - do: [:full_body], - else: [:paged_main_content_left] + true -> + [:paged_main_content_left] + end end def widget_type(%__MODULE__{is_full_screen: false}), do: :reconstructed_large_alert - def widget_type(%__MODULE__{use_fallback_layout: true}), do: :single_screen_alert + def widget_type( + %__MODULE__{ + alert: alert, + all_platforms_at_informed_station: all_platforms_at_informed_station + } = t + ) do + cond do + Alert.is_child_stop_closure?(alert, all_platforms_at_informed_station) -> + :single_screen_alert + + dual_screen_alert?(t) -> + :reconstructed_takeover - def widget_type(%__MODULE__{} = t) do - if dual_screen_alert?(t), - do: :reconstructed_takeover, - else: :single_screen_alert + true -> + :single_screen_alert + end end def alert_ids(%__MODULE__{} = t), do: [t.alert.id] diff --git a/test/screens/v2/candidate_generator/widgets/reconstructed_alert_test.exs b/test/screens/v2/candidate_generator/widgets/reconstructed_alert_test.exs index dbf083a05..df78c7f14 100644 --- a/test/screens/v2/candidate_generator/widgets/reconstructed_alert_test.exs +++ b/test/screens/v2/candidate_generator/widgets/reconstructed_alert_test.exs @@ -125,6 +125,7 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do fetch_directional_alerts_fn: fn _ -> {:ok, directional_alerts} end, fetch_stop_name_fn: fetch_stop_name_fn, fetch_location_context_fn: fn _, _, _ -> {:ok, location_context} end, + fetch_subway_platforms_for_stop_fn: fn _ -> [] end, x_fetch_alerts_fn: fn _ -> :error end, x_fetch_stop_name_fn: fn _ -> :error end, x_fetch_location_context_fn: fn _, _, _ -> :error end @@ -138,7 +139,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do now: now, happening_now_active_period: happening_now_active_period, fetch_stop_name_fn: fetch_stop_name_fn, - fetch_location_context_fn: fetch_location_context_fn + fetch_location_context_fn: fetch_location_context_fn, + fetch_subway_platforms_for_stop_fn: fetch_subway_platforms_for_stop_fn } = context alerts = [ @@ -168,7 +170,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do screen: config, location_context: location_context, now: now, - is_terminal_station: true + is_terminal_station: true, + all_platforms_at_informed_station: [] } expected_widgets = [ @@ -218,7 +221,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do now, fetch_alerts_fn, fetch_stop_name_fn, - fetch_location_context_fn + fetch_location_context_fn, + fetch_subway_platforms_for_stop_fn ) end @@ -230,7 +234,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do now: now, happening_now_active_period: happening_now_active_period, fetch_stop_name_fn: fetch_stop_name_fn, - fetch_location_context_fn: fetch_location_context_fn + fetch_location_context_fn: fetch_location_context_fn, + fetch_subway_platforms_for_stop_fn: fetch_subway_platforms_for_stop_fn } = context alerts = [ @@ -260,7 +265,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do screen: config, location_context: location_context, now: now, - is_terminal_station: true + is_terminal_station: true, + all_platforms_at_informed_station: [] } expected_widgets = [ @@ -310,7 +316,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do now, fetch_alerts_fn, fetch_stop_name_fn, - fetch_location_context_fn + fetch_location_context_fn, + fetch_subway_platforms_for_stop_fn ) end @@ -341,7 +348,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do screen: config, location_context: location_context, now: now, - is_terminal_station: true + is_terminal_station: true, + all_platforms_at_informed_station: [] } expected_widgets = [ @@ -428,7 +436,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do now: now, fetch_location_context_fn: fetch_location_context_fn, fetch_alerts_fn: fetch_alerts_fn, - x_fetch_stop_name_fn: x_fetch_stop_name_fn + x_fetch_stop_name_fn: x_fetch_stop_name_fn, + fetch_subway_platforms_for_stop_fn: fetch_subway_platforms_for_stop_fn } = context expected_common_data = %{ @@ -436,6 +445,7 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do location_context: location_context, now: now, informed_stations: [], + all_platforms_at_informed_station: [], is_terminal_station: true } @@ -483,7 +493,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do now, fetch_alerts_fn, x_fetch_stop_name_fn, - fetch_location_context_fn + fetch_location_context_fn, + fetch_subway_platforms_for_stop_fn ) end @@ -502,7 +513,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlertTest do location_context: location_context, now: now, is_terminal_station: true, - is_full_screen: true + is_full_screen: true, + all_platforms_at_informed_station: [] } expected_widgets = [ diff --git a/test/screens/v2/widget_instance/reconstructed_alert_test.exs b/test/screens/v2/widget_instance/reconstructed_alert_test.exs index a43eb7f43..3d4d74a68 100644 --- a/test/screens/v2/widget_instance/reconstructed_alert_test.exs +++ b/test/screens/v2/widget_instance/reconstructed_alert_test.exs @@ -28,7 +28,8 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do downstream_stops: nil, routes: nil, alert_route_types: nil - } + }, + all_platforms_at_informed_station: [] } } end @@ -129,12 +130,8 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do } end - defp put_use_fallback_layout(widget, use_fallback_layout) do - %{widget | use_fallback_layout: use_fallback_layout} - end - - defp put_informed_platform(widget, informed_platform) do - %{widget | informed_platform: informed_platform} + defp put_all_platforms_at_informed_station(widget, all_platforms_at_informed_station) do + %{widget | all_platforms_at_informed_station: all_platforms_at_informed_station} end defp ie(opts) do @@ -381,8 +378,8 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do test "returns takeover for a suspension that affects all station trips", %{widget: widget} do widget = put_informed_entities(widget, [ - ie(route: "Red", route_type: 1), - ie(route: "Orange", route_type: 1) + ie(route: "Red", route_type: 1, stop: "place-dwnxg"), + ie(route: "Orange", route_type: 1, stop: "place-dwnxg") ]) |> put_is_full_screen(true) @@ -536,7 +533,6 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do |> put_home_stop(PreFare, "place-forhl") |> put_effect(:station_closure) |> put_is_full_screen(true) - |> put_use_fallback_layout(true) assert [1] == WidgetInstance.priority(widget) assert [:paged_main_content_left] == WidgetInstance.slot_names(widget) @@ -1080,7 +1076,6 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do }) |> put_cause(:unknown) |> put_is_full_screen(true) - |> put_use_fallback_layout(true) |> put_alert_header("Test Alert") |> put_routes_at_stop([ %{ @@ -1100,7 +1095,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do location: nil, cause: nil, routes: [%{route_id: "Red", svg_name: "rl"}], - effect: :fallback, + effect: :station_closure, updated_at: "Friday, 5:00 am", region: :here } @@ -1122,7 +1117,6 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do }) |> put_cause(:unknown) |> put_is_full_screen(true) - |> put_use_fallback_layout(true) |> put_alert_header("Test Alert") |> put_routes_at_stop([ %{ @@ -1142,7 +1136,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do location: nil, cause: nil, routes: [%{route_id: "Red", svg_name: "rl-alewife", headsign: "Alewife"}], - effect: :fallback, + effect: :station_closure, updated_at: "Friday, 5:00 am", region: :outside } @@ -1620,8 +1614,10 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do }) |> put_cause(:unknown) |> put_informed_stations(["Porter"]) - |> put_use_fallback_layout(true) - |> put_informed_platform(%{id: "70065", platform_name: "Ashmont/Braintree"}) + |> put_all_platforms_at_informed_station([ + %{id: "70065", platform_name: "Ashmont/Braintree"}, + %{id: "70066", platform_name: "Alewife"} + ]) expected = %{ issue: "Bypassing Ashmont/Braintree platform at Porter", @@ -1630,7 +1626,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do routes: [ %{color: :red, text: "RED LINE", type: :text} ], - effect: :station_closure, + effect: :fallback, urgent: false, region: :outside, remedy: nil @@ -2679,13 +2675,16 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do }} end + fetch_subway_platforms_for_stop_fn = fn _ -> [] end + alert_widget = config |> CandidateGenerator.Widgets.ReconstructedAlert.reconstructed_alert_instances( now, fetch_alerts_fn, fetch_stop_name_fn, - fetch_location_context_fn + fetch_location_context_fn, + fetch_subway_platforms_for_stop_fn ) |> List.first() @@ -3093,13 +3092,16 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do }} end + fetch_subway_platforms_for_stop_fn = fn _ -> [] end + alert_widget = config |> CandidateGenerator.Widgets.ReconstructedAlert.reconstructed_alert_instances( now, fetch_alerts_fn, fetch_stop_name_fn, - fetch_location_context_fn + fetch_location_context_fn, + fetch_subway_platforms_for_stop_fn ) |> List.first() From 28ac71f939fd7d30c2e216bba6fe63cab731b6e1 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Mon, 8 Jul 2024 13:18:52 -0400 Subject: [PATCH 08/30] Fixed platform closure logic for SubwayStatus. --- .../widgets/subway_status.ex | 38 +- .../v2/widget_instance/subway_status.ex | 43 +- .../v2/widget_instance/subway_status_test.exs | 846 +++++++++--------- 3 files changed, 503 insertions(+), 424 deletions(-) diff --git a/lib/screens/v2/candidate_generator/widgets/subway_status.ex b/lib/screens/v2/candidate_generator/widgets/subway_status.ex index e703c99d9..a3010f396 100644 --- a/lib/screens/v2/candidate_generator/widgets/subway_status.ex +++ b/lib/screens/v2/candidate_generator/widgets/subway_status.ex @@ -2,14 +2,23 @@ defmodule Screens.V2.CandidateGenerator.Widgets.SubwayStatus do @moduledoc false alias Screens.Alerts.Alert + alias Screens.Stops.Stop alias Screens.V2.WidgetInstance.SubwayStatus - def subway_status_instances(config, now \\ DateTime.utc_now()) do + def subway_status_instances( + config, + now \\ DateTime.utc_now(), + fetch_subway_platforms_for_stop_fn \\ &Stop.fetch_subway_platforms_for_stop/1 + ) do route_ids = ["Blue", "Orange", "Red", "Green-B", "Green-C", "Green-D", "Green-E"] case Screens.Alerts.Alert.fetch(route_ids: route_ids) do {:ok, alerts} -> - relevant_alerts = Enum.filter(alerts, &relevant?(&1, now)) + relevant_alerts = + alerts + |> Enum.filter(&relevant?(&1, now)) + |> Enum.map(&append_context(&1, fetch_subway_platforms_for_stop_fn)) + [%SubwayStatus{screen: config, subway_alerts: relevant_alerts}] :error -> @@ -27,5 +36,28 @@ defmodule Screens.V2.CandidateGenerator.Widgets.SubwayStatus do defp relevant_effect?(%Alert{effect: effect}), do: effect in [:suspension, :shuttle, :station_closure] - defp suppressed?(alert), do: alert.id == "529291" + defp suppressed?(_alert), do: false + + defp append_context( + %Alert{effect: :station_closure} = alert, + fetch_subway_platforms_for_stop_fn + ) do + informed_parent_stations = Alert.informed_parent_stations(alert) + + all_platforms_at_informed_station = + case informed_parent_stations do + [informed_parent_station] -> + fetch_subway_platforms_for_stop_fn.(informed_parent_station.stop) + + _ -> + [] + end + + %{ + alert: alert, + context: %{all_platforms_at_informed_station: all_platforms_at_informed_station} + } + end + + defp append_context(alert, _), do: %{alert: alert, context: %{}} end diff --git a/lib/screens/v2/widget_instance/subway_status.ex b/lib/screens/v2/widget_instance/subway_status.ex index 5bd820bca..636bc1354 100644 --- a/lib/screens/v2/widget_instance/subway_status.ex +++ b/lib/screens/v2/widget_instance/subway_status.ex @@ -13,7 +13,7 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do @type t :: %__MODULE__{ screen: Screen.t(), - subway_alerts: list(Alert.t()) + subway_alerts: list(%{alert: Alert.t(), context: %{}}) } @type serialized_response :: %{ @@ -153,7 +153,7 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do ) end - defp alert_routes(%Alert{informed_entities: entities}) do + defp alert_routes(%{alert: %Alert{informed_entities: entities}}) do entities |> Enum.map(fn e -> Map.get(e, :route) end) |> Enum.reject(&is_nil/1) @@ -364,12 +364,15 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do %{status: "Normal Service"} end - defp serialize_alert(%Alert{effect: :shuttle, informed_entities: informed_entities}, route_id) do + defp serialize_alert( + %{alert: %Alert{effect: :shuttle, informed_entities: informed_entities}}, + route_id + ) do %{status: "Shuttle Bus", location: get_location(informed_entities, route_id)} end defp serialize_alert( - %Alert{effect: :suspension, informed_entities: informed_entities}, + %{alert: %Alert{effect: :suspension, informed_entities: informed_entities}}, route_id ) do location = get_location(informed_entities, route_id) @@ -380,12 +383,17 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do end defp serialize_alert( - %Alert{effect: :station_closure, informed_entities: informed_entities} = alert, + %{ + alert: %Alert{effect: :station_closure, informed_entities: informed_entities} = alert, + context: %{all_platforms_at_informed_station: all_platforms_at_informed_station} + }, route_id ) do - if Alert.is_child_stop_closure?(alert) do + if Alert.is_child_stop_closure?(alert, all_platforms_at_informed_station) do + informed_platforms = Alert.informed_platforms(alert) + %{ - status: "Bypassing 1 stop", + status: "Bypassing #{length(informed_platforms)} stop", location: %{full: "mbta.com/alerts", abbrev: "mbta.com/alerts"} } else @@ -399,10 +407,12 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do end defp serialize_alert( - %Alert{ - effect: :delay, - severity: severity, - informed_entities: informed_entities + %{ + alert: %Alert{ + effect: :delay, + severity: severity, + informed_entities: informed_entities + } }, route_id ) do @@ -428,9 +438,11 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do end def serialize_green_line_branch_alert( - %Alert{ - effect: :station_closure, - informed_entities: informed_entities + %{ + alert: %Alert{ + effect: :station_closure, + informed_entities: informed_entities + } }, route_ids ) do @@ -513,7 +525,7 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do end end - defp alert_affects_gl_trunk_or_whole_line?(alert, gl_stop_sets) do + defp alert_affects_gl_trunk_or_whole_line?(%{alert: alert}, gl_stop_sets) do alert_affects_gl_trunk?(alert, gl_stop_sets) or alert_affects_whole_green_line?(alert) end @@ -731,6 +743,7 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do def get_total_alerts(alerts) do total_affected_routes = alerts + |> Enum.map(& &1.alert) |> Enum.uniq_by(& &1.id) |> Enum.map(&get_total_affected_routes_for_alert/1) |> Enum.sum() diff --git a/test/screens/v2/widget_instance/subway_status_test.exs b/test/screens/v2/widget_instance/subway_status_test.exs index 54cfe1645..ff36b4d85 100644 --- a/test/screens/v2/widget_instance/subway_status_test.exs +++ b/test/screens/v2/widget_instance/subway_status_test.exs @@ -7,6 +7,9 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do alias Screens.V2.WidgetInstance alias Screens.V2.WidgetInstance.SubwayStatus + defp subway_alerts(alerts), + do: Enum.map(alerts, &%{alert: &1, context: %{all_platforms_at_informed_station: []}}) + describe "priority/1" do test "returns high priority for a flex zone widget" do instance = %SubwayStatus{subway_alerts: []} @@ -64,17 +67,18 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles station closure alert with 4+ stops" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Blue", stop: "place-aport"}, - %{route: "Blue", stop: "place-mvbcl"}, - %{route: "Blue", stop: "place-aqucl"}, - %{route: "Blue", stop: "place-state"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Blue", stop: "place-aport"}, + %{route: "Blue", stop: "place-mvbcl"}, + %{route: "Blue", stop: "place-aqucl"}, + %{route: "Blue", stop: "place-state"} + ] + } + ]) } expected = %{ @@ -124,16 +128,17 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles station closure alert with 3 stops" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Blue", stop: "place-aport"}, - %{route: "Blue", stop: "place-mvbcl"}, - %{route: "Blue", stop: "place-aqucl"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Blue", stop: "place-aport"}, + %{route: "Blue", stop: "place-mvbcl"}, + %{route: "Blue", stop: "place-aqucl"} + ] + } + ]) } expected = %{ @@ -183,15 +188,16 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 1 alert" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Blue", stop: "place-aport"}, - %{route: "Blue", stop: "place-mvbcl"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Blue", stop: "place-aport"}, + %{route: "Blue", stop: "place-mvbcl"} + ] + } + ]) } expected = %{ @@ -238,26 +244,27 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 2 alerts, 2 routes" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :suspension, - informed_entities: [ - %{route: "Blue", stop: "place-aport"}, - %{route: "Blue", stop: "place-mvbcl"}, - %{route: "Blue", stop: "place-aqucl"} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Green-B", stop: nil}, - %{route: "Green-C", stop: nil}, - %{route: "Green-D", stop: nil}, - %{route: "Green-E", stop: nil} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :suspension, + informed_entities: [ + %{route: "Blue", stop: "place-aport"}, + %{route: "Blue", stop: "place-mvbcl"}, + %{route: "Blue", stop: "place-aqucl"} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Green-B", stop: nil}, + %{route: "Green-C", stop: nil}, + %{route: "Green-D", stop: nil}, + %{route: "Green-E", stop: nil} + ] + } + ]) } expected = %{ @@ -302,23 +309,24 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 2 alerts, 1 non-GL route" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :suspension, - informed_entities: [ - %{route: "Blue", stop: "place-aport"} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Blue", stop: "place-aport"}, - %{route: "Blue", stop: "place-mvbcl"}, - %{route: "Blue", stop: "place-aqucl"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :suspension, + informed_entities: [ + %{route: "Blue", stop: "place-aport"} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Blue", stop: "place-aport"}, + %{route: "Blue", stop: "place-mvbcl"}, + %{route: "Blue", stop: "place-aqucl"} + ] + } + ]) } expected = %{ @@ -370,42 +378,43 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 4 alerts, 2 non-GL routes" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :suspension, - informed_entities: [ - %{route: "Blue", stop: "place-aport"}, - %{route: "Blue", stop: "place-mvbcl"}, - %{route: "Blue", stop: "place-aqucl"} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Blue", stop: "place-aport"}, - %{route: "Blue", stop: "place-mvbcl"}, - %{route: "Blue", stop: "place-aqucl"} - ] - }, - %Alert{ - effect: :suspension, - informed_entities: [ - %{route: "Orange", stop: "place-ogmnl"}, - %{route: "Orange", stop: "place-mlmnl"}, - %{route: "Orange", stop: "place-welln"} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Orange", stop: "place-ogmnl"}, - %{route: "Orange", stop: "place-mlmnl"}, - %{route: "Orange", stop: "place-welln"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :suspension, + informed_entities: [ + %{route: "Blue", stop: "place-aport"}, + %{route: "Blue", stop: "place-mvbcl"}, + %{route: "Blue", stop: "place-aqucl"} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Blue", stop: "place-aport"}, + %{route: "Blue", stop: "place-mvbcl"}, + %{route: "Blue", stop: "place-aqucl"} + ] + }, + %Alert{ + effect: :suspension, + informed_entities: [ + %{route: "Orange", stop: "place-ogmnl"}, + %{route: "Orange", stop: "place-mlmnl"}, + %{route: "Orange", stop: "place-welln"} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Orange", stop: "place-ogmnl"}, + %{route: "Orange", stop: "place-mlmnl"}, + %{route: "Orange", stop: "place-welln"} + ] + } + ]) } expected = %{ @@ -454,31 +463,32 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 3 alerts, 2 non-GL routes" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Blue", stop: "place-aport"} - ] - }, - %Alert{ - effect: :suspension, - informed_entities: [ - %{route: "Orange", stop: "place-ogmnl"}, - %{route: "Orange", stop: "place-mlmnl"}, - %{route: "Orange", stop: "place-welln"} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Orange", stop: "place-ogmnl"}, - %{route: "Orange", stop: "place-mlmnl"}, - %{route: "Orange", stop: "place-welln"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Blue", stop: "place-aport"} + ] + }, + %Alert{ + effect: :suspension, + informed_entities: [ + %{route: "Orange", stop: "place-ogmnl"}, + %{route: "Orange", stop: "place-mlmnl"}, + %{route: "Orange", stop: "place-welln"} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Orange", stop: "place-ogmnl"}, + %{route: "Orange", stop: "place-mlmnl"}, + %{route: "Orange", stop: "place-welln"} + ] + } + ]) } expected = %{ @@ -532,23 +542,24 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 1 alert on GL trunk and 1 alert on GL branch" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :suspension, - informed_entities: [ - %{route: "Green-C", stop: "place-hwsst"}, - %{route: "Green-C", stop: "place-kntst"}, - %{route: "Green-C", stop: "place-stpul"} - ] - }, - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Green-D", stop: "place-gover"}, - %{route: "Green-D", stop: "place-river"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :suspension, + informed_entities: [ + %{route: "Green-C", stop: "place-hwsst"}, + %{route: "Green-C", stop: "place-kntst"}, + %{route: "Green-C", stop: "place-stpul"} + ] + }, + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Green-D", stop: "place-gover"}, + %{route: "Green-D", stop: "place-river"} + ] + } + ]) } expected = %{ @@ -608,33 +619,34 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 1 alert on GL trunk and 2 alerts on GL branch" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :suspension, - informed_entities: [ - %{route: "Green-C", stop: "place-hwsst"}, - %{route: "Green-C", stop: "place-kntst"}, - %{route: "Green-C", stop: "place-stpul"} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Green-B", stop: nil} - ] - }, - %Alert{ - effect: :delay, - severity: 6, - informed_entities: [ - %{route: "Green-B", stop: nil}, - %{route: "Green-C", stop: nil}, - %{route: "Green-D", stop: nil}, - %{route: "Green-E", stop: nil} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :suspension, + informed_entities: [ + %{route: "Green-C", stop: "place-hwsst"}, + %{route: "Green-C", stop: "place-kntst"}, + %{route: "Green-C", stop: "place-stpul"} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Green-B", stop: nil} + ] + }, + %Alert{ + effect: :delay, + severity: 6, + informed_entities: [ + %{route: "Green-B", stop: nil}, + %{route: "Green-C", stop: nil}, + %{route: "Green-D", stop: nil}, + %{route: "Green-E", stop: nil} + ] + } + ]) } expected = %{ @@ -687,25 +699,26 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 2 alerts on GL trunk" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :suspension, - informed_entities: [ - %{route: "Green-C", stop: "place-gover"}, - %{route: "Green-C", stop: "place-pktrm"} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Green-B", stop: nil}, - %{route: "Green-C", stop: nil}, - %{route: "Green-D", stop: nil}, - %{route: "Green-E", stop: nil} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :suspension, + informed_entities: [ + %{route: "Green-C", stop: "place-gover"}, + %{route: "Green-C", stop: "place-pktrm"} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Green-B", stop: nil}, + %{route: "Green-C", stop: nil}, + %{route: "Green-D", stop: nil}, + %{route: "Green-E", stop: nil} + ] + } + ]) } expected = %{ @@ -761,22 +774,23 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 2 alerts on GL branches" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :delay, - severity: 9, - informed_entities: [ - %{route: "Green-C", stop: nil} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Green-B", stop: nil} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :delay, + severity: 9, + informed_entities: [ + %{route: "Green-C", stop: nil} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Green-B", stop: nil} + ] + } + ]) } expected = %{ @@ -829,29 +843,30 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 3+ alerts on GL branches" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :delay, - severity: 9, - informed_entities: [ - %{route: "Green-C", stop: nil} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Green-B", stop: nil} - ] - }, - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Green-E", stop: "place-symcl"}, - %{route: "Green-E", stop: "place-nuniv"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :delay, + severity: 9, + informed_entities: [ + %{route: "Green-C", stop: nil} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Green-B", stop: nil} + ] + }, + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Green-E", stop: "place-symcl"}, + %{route: "Green-E", stop: "place-nuniv"} + ] + } + ]) } expected = %{ @@ -899,28 +914,29 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 2 alerts on GL branches and 1 alert on non-GL route" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :delay, - severity: 9, - informed_entities: [ - %{route: "Green-C", stop: nil} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Green-B", stop: nil} - ] - }, - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Orange", stop: "place-ogmnl"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :delay, + severity: 9, + informed_entities: [ + %{route: "Green-C", stop: nil} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Green-B", stop: nil} + ] + }, + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Orange", stop: "place-ogmnl"} + ] + } + ]) } expected = %{ @@ -975,31 +991,32 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 2 alerts on GL trunk and 1 alert on GL branch" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :delay, - severity: 9, - informed_entities: [ - %{route: "Green-C", stop: nil} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Green-B", stop: nil}, - %{route: "Green-C", stop: nil}, - %{route: "Green-D", stop: nil}, - %{route: "Green-E", stop: nil} - ] - }, - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Green-D", stop: "place-kencl"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :delay, + severity: 9, + informed_entities: [ + %{route: "Green-C", stop: nil} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Green-B", stop: nil}, + %{route: "Green-C", stop: nil}, + %{route: "Green-D", stop: nil}, + %{route: "Green-E", stop: nil} + ] + }, + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Green-D", stop: "place-kencl"} + ] + } + ]) } expected = %{ @@ -1047,35 +1064,36 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 2 alerts on GL branches and 2 alerts on non-GL route" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :delay, - severity: 9, - informed_entities: [ - %{route: "Green-C", stop: nil} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Green-B", stop: nil} - ] - }, - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Orange", stop: "place-ogmnl"} - ] - }, - %Alert{ - effect: :delay, - severity: 5, - informed_entities: [ - %{route: "Orange", stop: nil} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :delay, + severity: 9, + informed_entities: [ + %{route: "Green-C", stop: nil} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Green-B", stop: nil} + ] + }, + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Orange", stop: "place-ogmnl"} + ] + }, + %Alert{ + effect: :delay, + severity: 5, + informed_entities: [ + %{route: "Orange", stop: nil} + ] + } + ]) } expected = %{ @@ -1129,27 +1147,28 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 1 alert on GL trunk and 2 alerts on non-GL route" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Green-D", stop: "place-lech"}, - %{route: "Green-E", stop: "place-lech"} - ] - }, - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Orange", stop: "place-ogmnl"} - ] - }, - %Alert{ - effect: :suspension, - informed_entities: [ - %{route: "Blue", stop: "place-bmmnl"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Green-D", stop: "place-lech"}, + %{route: "Green-E", stop: "place-lech"} + ] + }, + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Orange", stop: "place-ogmnl"} + ] + }, + %Alert{ + effect: :suspension, + informed_entities: [ + %{route: "Blue", stop: "place-bmmnl"} + ] + } + ]) } expected = %{ @@ -1201,21 +1220,22 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 1 alert on GL branch and 1 alert on non-GL route" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :delay, - severity: 9, - informed_entities: [ - %{route: "Green-C", stop: nil} - ] - }, - %Alert{ - effect: :station_closure, - informed_entities: [ - %{route: "Orange", stop: "place-ogmnl"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :delay, + severity: 9, + informed_entities: [ + %{route: "Green-C", stop: nil} + ] + }, + %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Orange", stop: "place-ogmnl"} + ] + } + ]) } expected = %{ @@ -1261,17 +1281,18 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 1 alert affecting 3 routes" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :delay, - severity: 9, - informed_entities: [ - %{route: "Green-C", stop: nil}, - %{route: "Blue", stop: nil}, - %{route: "Orange", stop: nil} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :delay, + severity: 9, + informed_entities: [ + %{route: "Green-C", stop: nil}, + %{route: "Blue", stop: nil}, + %{route: "Orange", stop: nil} + ] + } + ]) } expected = %{ @@ -1322,12 +1343,20 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "handles 1 platform closure alert" do instance = %SubwayStatus{ subway_alerts: [ - %Alert{ - effect: :station_closure, - informed_entities: [ - %{stop: "place-portr", route: "Red", route_type: 1}, - %{stop: "70065", route: "Red", route_type: 1} - ] + %{ + alert: %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Red", stop: "place-portr", route_type: 1}, + %{route: "Red", stop: "70065", route_type: 1} + ] + }, + context: %{ + all_platforms_at_informed_station: [ + %{id: "70065", platform_name: "Ashmont/Braintree"}, + %{id: "70066", platform_name: "Alewife"} + ] + } } ] } @@ -1375,14 +1404,15 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "uses 'Entire line' location text for whole-line shuttles" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :shuttle, - informed_entities: [ - %{route: "Blue", route_type: 1, direction_id: nil, stop: nil} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :shuttle, + informed_entities: [ + %{route: "Blue", route_type: 1, direction_id: nil, stop: nil} + ] + } + ]) } expected = %{ @@ -1419,14 +1449,15 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "uses 'Entire line' location text for whole-line suspensions" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :suspension, - informed_entities: [ - %{route: "Blue", route_type: 1, direction_id: nil, stop: nil} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :suspension, + informed_entities: [ + %{route: "Blue", route_type: 1, direction_id: nil, stop: nil} + ] + } + ]) } expected = %{ @@ -1463,17 +1494,18 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "uses 'Entire line' location text for whole-Green Line suspensions" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :suspension, - informed_entities: [ - %{route: "Green-B", route_type: 0, direction_id: nil, stop: nil}, - %{route: "Green-C", route_type: 0, direction_id: nil, stop: nil}, - %{route: "Green-D", route_type: 0, direction_id: nil, stop: nil}, - %{route: "Green-E", route_type: 0, direction_id: nil, stop: nil} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :suspension, + informed_entities: [ + %{route: "Green-B", route_type: 0, direction_id: nil, stop: nil}, + %{route: "Green-C", route_type: 0, direction_id: nil, stop: nil}, + %{route: "Green-D", route_type: 0, direction_id: nil, stop: nil}, + %{route: "Green-E", route_type: 0, direction_id: nil, stop: nil} + ] + } + ]) } expected = %{ @@ -1510,15 +1542,16 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "does _not_ use 'Entire line' location text for whole-line delays" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :delay, - severity: 9, - informed_entities: [ - %{route: "Blue", route_type: 1, direction_id: nil, stop: nil} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :delay, + severity: 9, + informed_entities: [ + %{route: "Blue", route_type: 1, direction_id: nil, stop: nil} + ] + } + ]) } expected = %{ @@ -1555,17 +1588,18 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do test "finds correct endpoints if shuttle starts on trunk" do instance = %SubwayStatus{ - subway_alerts: [ - %Alert{ - effect: :shuttle, - informed_entities: [ - %{direction_id: nil, route: "Green-C", route_type: 0, stop: "place-kencl"}, - %{direction_id: nil, route: "Green-C", route_type: 0, stop: "place-smary"}, - %{direction_id: nil, route: "Green-C", route_type: 0, stop: "place-hwsst"}, - %{direction_id: nil, route: "Green-C", route_type: 0, stop: "place-kntst"} - ] - } - ] + subway_alerts: + subway_alerts([ + %Alert{ + effect: :shuttle, + informed_entities: [ + %{direction_id: nil, route: "Green-C", route_type: 0, stop: "place-kencl"}, + %{direction_id: nil, route: "Green-C", route_type: 0, stop: "place-smary"}, + %{direction_id: nil, route: "Green-C", route_type: 0, stop: "place-hwsst"}, + %{direction_id: nil, route: "Green-C", route_type: 0, stop: "place-kntst"} + ] + } + ]) } expected = %{ From cdaa97fdf42707c7639f4c0148d5ffe10c708a76 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Mon, 8 Jul 2024 13:21:11 -0400 Subject: [PATCH 09/30] Name changes. --- lib/screens/alerts/alert.ex | 10 +++++----- .../v2/widget_instance/reconstructed_alert.ex | 14 +++++++------- lib/screens/v2/widget_instance/subway_status.ex | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/screens/alerts/alert.ex b/lib/screens/alerts/alert.ex index 0c7b02976..c3aa1895a 100644 --- a/lib/screens/alerts/alert.ex +++ b/lib/screens/alerts/alert.ex @@ -593,7 +593,7 @@ defmodule Screens.Alerts.Alert do def direction_id(%__MODULE__{informed_entities: informed_entities}), do: List.first(informed_entities).direction_id - def informed_platforms(%__MODULE__{ + def informed_subway_platforms(%__MODULE__{ informed_entities: informed_entities }) do Enum.reject( @@ -608,8 +608,8 @@ defmodule Screens.Alerts.Alert do Enum.filter(informed_entities, &String.starts_with?(&1.stop, "place-")) end - @spec is_child_stop_closure?(__MODULE__.t(), list(Stop.t())) :: boolean() - def is_child_stop_closure?( + @spec is_partial_station_closure?(__MODULE__.t(), list(Stop.t())) :: boolean() + def is_partial_station_closure?( %__MODULE__{effect: :station_closure} = alert, all_platforms_at_informed_station ) do @@ -617,12 +617,12 @@ defmodule Screens.Alerts.Alert do case informed_parent_stations do [_] -> - length(informed_platforms(alert)) != length(all_platforms_at_informed_station) + length(informed_subway_platforms(alert)) != length(all_platforms_at_informed_station) _ -> false end end - def is_child_stop_closure?(_, _), do: false + def is_partial_station_closure?(_, _), do: false end diff --git a/lib/screens/v2/widget_instance/reconstructed_alert.ex b/lib/screens/v2/widget_instance/reconstructed_alert.ex index 1adf9dae3..0f6dc908c 100644 --- a/lib/screens/v2/widget_instance/reconstructed_alert.ex +++ b/lib/screens/v2/widget_instance/reconstructed_alert.ex @@ -1033,7 +1033,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do } = t, _location ) do - if Alert.is_child_stop_closure?(alert, all_platforms_at_informed_station) do + if Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) do serialize_outside_platform_closure(t) else %{alert: %{cause: cause}, informed_stations: informed_stations} = t @@ -1078,15 +1078,15 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do } = t ) do issue = - case Alert.informed_platforms(alert) do + case Alert.informed_subway_platforms(alert) do [informed_platform] -> platform = Enum.find(all_platforms_at_informed_station, &(&1.id == informed_platform.stop)) "Bypassing #{platform.platform_name} platform at #{informed_station}" - informed_platforms -> - "Bypassing #{length(informed_platforms)} platform at #{informed_station}" + informed_subway_platforms -> + "Bypassing #{length(informed_subway_platforms)} platform at #{informed_station}" end %{ @@ -1214,7 +1214,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do ) do location = LocalizedAlert.location(t) - if Alert.is_child_stop_closure?(alert, all_platforms_at_informed_station) do + if Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) do t |> serialize_single_screen_fallback_alert(location) else diagram_data = serialize_diagram(t, log_fn) @@ -1293,7 +1293,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do } = t ) do cond do - Alert.is_child_stop_closure?(alert, all_platforms_at_informed_station) -> + Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) -> [:paged_main_content_left] dual_screen_alert?(t) -> @@ -1313,7 +1313,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do } = t ) do cond do - Alert.is_child_stop_closure?(alert, all_platforms_at_informed_station) -> + Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) -> :single_screen_alert dual_screen_alert?(t) -> diff --git a/lib/screens/v2/widget_instance/subway_status.ex b/lib/screens/v2/widget_instance/subway_status.ex index 636bc1354..7e11b68c8 100644 --- a/lib/screens/v2/widget_instance/subway_status.ex +++ b/lib/screens/v2/widget_instance/subway_status.ex @@ -389,8 +389,8 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do }, route_id ) do - if Alert.is_child_stop_closure?(alert, all_platforms_at_informed_station) do - informed_platforms = Alert.informed_platforms(alert) + if Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) do + informed_platforms = Alert.informed_subway_platforms(alert) %{ status: "Bypassing #{length(informed_platforms)} stop", From c54d5181ee7adfd9ca29c897caaf9e5056a73ab6 Mon Sep 17 00:00:00 2001 From: Christian Maddox Date: Tue, 9 Jul 2024 13:30:49 -0400 Subject: [PATCH 10/30] Refactor to pattern match Co-authored-by: sloane <1699281+sloanelybutsurely@users.noreply.github.com> --- lib/screens/stops/stop.ex | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/screens/stops/stop.ex b/lib/screens/stops/stop.ex index 38ad5c4f8..aac14bdfa 100644 --- a/lib/screens/stops/stop.ex +++ b/lib/screens/stops/stop.ex @@ -367,14 +367,12 @@ defmodule Screens.Stops.Stop do case Screens.V3Api.get_json("stops/" <> stop_id, %{"include" => "child_stops"}) do {:ok, %{"included" => child_stop_data}} -> child_stop_data - |> Enum.filter(fn %{ - "attributes" => %{ - "location_type" => location_type, - "vehicle_type" => vehicle_type - } - } -> - location_type == 0 and vehicle_type == 1 - end) + |> Enum.filter(&match?(%{ + "attributes" => %{ + "location_type" => 0, + "vehicle_type" => 1 + } + }, &1)) |> Enum.map(&Stops.Parser.parse_stop/1) end end From 220c6109930e4e1f8c1eaefe697bd89105d5bdb4 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Tue, 9 Jul 2024 13:38:57 -0400 Subject: [PATCH 11/30] Changed reject to filter. --- lib/screens/alerts/alert.ex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/screens/alerts/alert.ex b/lib/screens/alerts/alert.ex index c3aa1895a..a491c3b89 100644 --- a/lib/screens/alerts/alert.ex +++ b/lib/screens/alerts/alert.ex @@ -593,12 +593,13 @@ defmodule Screens.Alerts.Alert do def direction_id(%__MODULE__{informed_entities: informed_entities}), do: List.first(informed_entities).direction_id + # Subway platform IDs are always integers def informed_subway_platforms(%__MODULE__{ informed_entities: informed_entities }) do - Enum.reject( + Enum.filter( informed_entities, - &(String.starts_with?(&1.stop, "place-") or &1.route_type != 1) + &(match?({_n, ""}, Integer.parse(&1.stop)) and &1.route_type == 1) ) end From b6f0a66166aa8841e8f0fa09d097050ff40d4139 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Tue, 9 Jul 2024 13:39:03 -0400 Subject: [PATCH 12/30] Formatting. --- lib/screens/stops/stop.ex | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/screens/stops/stop.ex b/lib/screens/stops/stop.ex index aac14bdfa..a67a3c380 100644 --- a/lib/screens/stops/stop.ex +++ b/lib/screens/stops/stop.ex @@ -367,12 +367,17 @@ defmodule Screens.Stops.Stop do case Screens.V3Api.get_json("stops/" <> stop_id, %{"include" => "child_stops"}) do {:ok, %{"included" => child_stop_data}} -> child_stop_data - |> Enum.filter(&match?(%{ - "attributes" => %{ - "location_type" => 0, - "vehicle_type" => 1 - } - }, &1)) + |> Enum.filter( + &match?( + %{ + "attributes" => %{ + "location_type" => 0, + "vehicle_type" => 1 + } + }, + &1 + ) + ) |> Enum.map(&Stops.Parser.parse_stop/1) end end From 0b057cb7655b61aa3b269fb594cebd34a44176ed Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 10 Jul 2024 08:49:32 -0400 Subject: [PATCH 13/30] Fixed route selection for station closures at JFK. --- .../v2/widget_instance/reconstructed_alert.ex | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/screens/v2/widget_instance/reconstructed_alert.ex b/lib/screens/v2/widget_instance/reconstructed_alert.ex index 0f6dc908c..3ef01718c 100644 --- a/lib/screens/v2/widget_instance/reconstructed_alert.ex +++ b/lib/screens/v2/widget_instance/reconstructed_alert.ex @@ -145,7 +145,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do # and their affiliated route id list_of_directions_and_routes = informed_entities - |> Enum.map(fn entity -> get_direction_and_route_from_entity(entity, location) end) + |> Enum.map(&get_direction_and_route_from_entity(&1, alert.effect, location)) |> Enum.filter(& &1) |> Enum.uniq() @@ -179,14 +179,19 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do # Given an entity and the directionality of the alert from the home stop, # return a tuple with the affected direction_id and route_id + defp get_direction_and_route_from_entity(%{stop: "place-jfk"}, :station_closure, _location), + do: {nil, "Red"} + # Skip processing JFK, because it is a branching node station. The other stations in the alert # will determine the destination needed for this alert - defp get_direction_and_route_from_entity(%{stop: "place-jfk"}, _location), do: nil + defp get_direction_and_route_from_entity(%{stop: "place-jfk"}, _, _location), + do: nil # If the route is red and the alert is downstream, we have to figure out whether the alert # only affects one branch or both defp get_direction_and_route_from_entity( %{direction_id: nil, route: "Red", stop: stop_id}, + _, location ) when stop_id != nil and location in [:downstream, :boundary_downstream] do @@ -205,6 +210,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do # Same with RL upstream alerts defp get_direction_and_route_from_entity( %{direction_id: nil, route: "Red", stop: stop_id}, + _, location ) when stop_id != nil and location in [:upstream, :boundary_upstream] do @@ -220,15 +226,15 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do end end - defp get_direction_and_route_from_entity(%{direction_id: nil, route: route}, location) + defp get_direction_and_route_from_entity(%{direction_id: nil, route: route}, _, location) when location in [:downstream, :boundary_downstream], do: {0, route} - defp get_direction_and_route_from_entity(%{direction_id: nil, route: route}, location) + defp get_direction_and_route_from_entity(%{direction_id: nil, route: route}, _, location) when location in [:upstream, :boundary_upstream], do: {1, route} - defp get_direction_and_route_from_entity(%{direction_id: direction_id, route: route}, _), + defp get_direction_and_route_from_entity(%{direction_id: direction_id, route: route}, _, _), do: {direction_id, route} # Select 1 direction + route from this list of directions + routes for multiple branches From d5275ba9ea12796cbec906db00d9e2ae018cf961 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 10 Jul 2024 08:50:21 -0400 Subject: [PATCH 14/30] Added cldr_messages to help with pluralizing strings. --- config/config.exs | 5 +++++ lib/screens/cldr.ex | 12 ++++++++++++ mix.exs | 3 ++- mix.lock | 8 ++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 lib/screens/cldr.ex diff --git a/config/config.exs b/config/config.exs index 1dc4b7d27..23bc7ab57 100644 --- a/config/config.exs +++ b/config/config.exs @@ -56,6 +56,11 @@ config :ueberauth, Ueberauth, keycloak: nil ] +config :ex_cldr, + default_locale: "en", + default_backend: Screens.Cldr, + json_library: Jason + config :screens, gds_dms_username: "mbtadata@gmail.com", config_fetcher: Screens.Config.Fetch.S3, diff --git a/lib/screens/cldr.ex b/lib/screens/cldr.ex new file mode 100644 index 000000000..363d470ee --- /dev/null +++ b/lib/screens/cldr.ex @@ -0,0 +1,12 @@ +defmodule Screens.Cldr do + @moduledoc """ + Define a backend module that will host our + Cldr configuration and public API. + + Most function calls in Cldr will be calls + to functions on this module. + """ + use Cldr, + locales: ["en"], + default_locale: "en" +end diff --git a/mix.exs b/mix.exs index 460df579c..06540abfc 100644 --- a/mix.exs +++ b/mix.exs @@ -91,7 +91,8 @@ defmodule Screens.MixProject do ref: "25fb47c58fc0b485c8c6df78fe94914292856903"}, {:nebulex, "~> 2.6"}, {:remote_ip, "~> 1.2"}, - {:hackney_telemetry, "~> 0.1.1"} + {:hackney_telemetry, "~> 0.1.1"}, + {:ex_cldr_messages, "~> 1.0"} ] end end diff --git a/mix.lock b/mix.lock index 0150e0e75..dfefe0b9b 100644 --- a/mix.lock +++ b/mix.lock @@ -3,6 +3,7 @@ "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"}, "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, + "cldr_utils": {:hex, :cldr_utils, "2.27.0", "a75d5cdaaf6b7432eb10f547e6abe635c94746985c5b78e35bbbd08b16473b6c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "516f601e28da10b8f1f3af565321c4e3da3b898a0b50a5e5be425eff76d587e1"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "corsica": {:hex, :corsica, "2.1.3", "dccd094ffce38178acead9ae743180cdaffa388f35f0461ba1e8151d32e190e6", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "616c08f61a345780c2cf662ff226816f04d8868e12054e68963e95285b5be8bc"}, @@ -10,13 +11,19 @@ "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, "credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"}, + "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, + "digital_token": {:hex, :digital_token, "0.6.0", "13e6de581f0b1f6c686f7c7d12ab11a84a7b22fa79adeb4b50eec1a2d278d258", [:mix], [{:cldr_utils, "~> 2.17", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "2455d626e7c61a128b02a4a8caddb092548c3eb613ac6f6a85e4cbb6caddc4d1"}, "ehmon": {:git, "https://github.com/mbta/ehmon.git", "1fb603262bd02d74a16183bd8f344dcace9d7561", []}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "ex_aws": {:hex, :ex_aws, "2.5.4", "86c5bb870a49e0ab6f5aa5dd58cf505f09d2624ebe17530db3c1b61c88a673af", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e82bd0091bb9a5bb190139599f922ff3fc7aebcca4374d65c99c4e23aa6d1625"}, "ex_aws_polly": {:hex, :ex_aws_polly, "0.5.0", "277662ce3f4203eef352ae0ea37df1feb54c291d8717cc6c241575e25c861c4c", [:mix], [{:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: false]}], "hexpm", "a021192995409c103b927c75d1d1d2e892f2bb23a0c0063bc85355907b600ca3"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.5.3", "422468e5c3e1a4da5298e66c3468b465cfd354b842e512cb1f6fbbe4e2f5bdaf", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "4f09dd372cc386550e484808c5ac5027766c8d0cd8271ccc578b82ee6ef4f3b8"}, "ex_aws_secretsmanager": {:hex, :ex_aws_secretsmanager, "2.0.0", "deff8c12335f0160882afeb9687e55a97fddcd7d9a82fc3a6fbb270797374773", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}], "hexpm", "8b2838af536c32263ff797012b29e87bad73ef34f43cfa60ebca8e84576f6d45"}, + "ex_cldr": {:hex, :ex_cldr, "2.39.2", "4a3a77797da8f900369822ea9353adfa035a5bbbbfff09b2d3d1b6fa461768e3", [:mix], [{:cldr_utils, "~> 2.25", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "02fd8913ef28d1b2a4190fd8016c2dec1f2291c9ce56c17d7649848c0261a6eb"}, + "ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.16.1", "29317f533cb5ec046d04523256cca4090291e9157028f28731395149b06ff8b2", [:mix], [{:ex_cldr, "~> 2.38", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "095d5e973bf0ee066dd1153990d10cb6fa6d8ff0e028295bdce7a7821c70a0e4"}, + "ex_cldr_messages": {:hex, :ex_cldr_messages, "1.0.2", "9909829e8cdb4eeb6d5b4dbe76b8e07ae39d2d2254fb943ff74dd9ace55a9120", [:mix], [{:ex_cldr_dates_times, "~> 2.13", [hex: :ex_cldr_dates_times, repo: "hexpm", optional: true]}, {:ex_cldr_lists, "~> 2.10", [hex: :ex_cldr_lists, repo: "hexpm", optional: true]}, {:ex_cldr_numbers, "~> 2.28", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_cldr_units, "~> 3.12", [hex: :ex_cldr_units, repo: "hexpm", optional: true]}, {:ex_doc, "~> 0.20", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:ex_money, "~> 5.9", [hex: :ex_money, repo: "hexpm", optional: true]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "3805a92f5ff64ee951f3a0174a85221af0117276ac794638df25b845edf431fa"}, + "ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.33.1", "49dc6e77e6d9ad22660aaa2480a7408ad3aedfbe517e4e83e5fe3a7bf5345770", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.38", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, "~> 2.16", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "c003bfaa3fdee6bab5195f128b94038c2ce1cf4879a759eef431dd075d9a5dac"}, "expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "gettext": {:hex, :gettext, "0.22.3", "c8273e78db4a0bb6fba7e9f0fd881112f349a3117f7f7c598fa18c66c888e524", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "935f23447713954a6866f1bb28c3a878c4c011e802bcd68a726f5e558e4b64bd"}, @@ -36,6 +43,7 @@ "nebulex": {:hex, :nebulex, "2.6.2", "0874989db4e382362884662d2ee9f31b4c4862595f4ec300bd279068729dd2d0", [:mix], [{:decorator, "~> 1.4", [hex: :decorator, repo: "hexpm", optional: true]}, {:shards, "~> 1.1", [hex: :shards, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "002a1774d5a187eb631ae4006db13df4bb6b325fe2a3c14cb14a1f3e989042b4"}, "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"}, "nimble_ownership": {:hex, :nimble_ownership, "0.3.1", "99d5244672fafdfac89bfad3d3ab8f0d367603ce1dc4855f86a1c75008bce56f", [:mix], [], "hexpm", "4bf510adedff0449a1d6e200e43e57a814794c8b5b6439071274d248d272a549"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "oidcc": {:hex, :oidcc, "3.1.2", "54dd00ebfb3f92aaa410535a725058e43205f01cf7a07b500163d714426300c2", [:mix, :rebar3], [{:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_registry, "~> 0.3.1", [hex: :telemetry_registry, repo: "hexpm", optional: false]}], "hexpm", "50b8d8e2c1c3ef7f593a4d465c2fc64302c01c940d4a3d7f588ad5260190bedc"}, "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "phoenix": {:hex, :phoenix, "1.6.16", "e5bdd18c7a06da5852a25c7befb72246de4ddc289182285f8685a40b7b5f5451", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e15989ff34f670a96b95ef6d1d25bad0d9c50df5df40b671d8f4a669e050ac39"}, From 2af409e1d2104e3a15cb37601cb9de0bff5cadb9 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 10 Jul 2024 08:50:36 -0400 Subject: [PATCH 15/30] Pluralized strings. --- lib/screens/v2/widget_instance/reconstructed_alert.ex | 7 ++++++- lib/screens/v2/widget_instance/subway_status.ex | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/screens/v2/widget_instance/reconstructed_alert.ex b/lib/screens/v2/widget_instance/reconstructed_alert.ex index 3ef01718c..4495b154e 100644 --- a/lib/screens/v2/widget_instance/reconstructed_alert.ex +++ b/lib/screens/v2/widget_instance/reconstructed_alert.ex @@ -1092,7 +1092,12 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do "Bypassing #{platform.platform_name} platform at #{informed_station}" informed_subway_platforms -> - "Bypassing #{length(informed_subway_platforms)} platform at #{informed_station}" + Cldr.Message.format!("Bypassing {num_platforms, plural, + =1 {1 platform} + other {# platforms}} at {informed_station}", + num_platforms: length(informed_subway_platforms), + informed_station: informed_station + ) end %{ diff --git a/lib/screens/v2/widget_instance/subway_status.ex b/lib/screens/v2/widget_instance/subway_status.ex index 7e11b68c8..acd2cf6e1 100644 --- a/lib/screens/v2/widget_instance/subway_status.ex +++ b/lib/screens/v2/widget_instance/subway_status.ex @@ -393,7 +393,12 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do informed_platforms = Alert.informed_subway_platforms(alert) %{ - status: "Bypassing #{length(informed_platforms)} stop", + status: + Cldr.Message.format!("Bypassing {num_informed_platforms, plural, + =1 {1 stop} + other {# stops}}", + num_informed_platforms: length(informed_platforms) + ), location: %{full: "mbta.com/alerts", abbrev: "mbta.com/alerts"} } else From 038742c57bbe0cfa773dcb215a58a1a19fe58d8f Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 10 Jul 2024 08:52:54 -0400 Subject: [PATCH 16/30] Added more tests. --- .../reconstructed_alert_test.exs | 38 +++++++++++ .../v2/widget_instance/subway_status_test.exs | 65 +++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/test/screens/v2/widget_instance/reconstructed_alert_test.exs b/test/screens/v2/widget_instance/reconstructed_alert_test.exs index 3d4d74a68..b67c7088a 100644 --- a/test/screens/v2/widget_instance/reconstructed_alert_test.exs +++ b/test/screens/v2/widget_instance/reconstructed_alert_test.exs @@ -1635,6 +1635,44 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do assert expected == ReconstructedAlert.serialize(widget, &fake_log/1) end + test "handles multiple platform closures at same station", %{widget: widget} do + widget = + widget + |> put_home_stop(PreFare, "place-andrw") + |> put_effect(:station_closure) + |> put_informed_entities([ + ie(stop: "place-jfk", route: "Red", route_type: 1), + ie(stop: "70085", route: "Red", route_type: 1), + ie(stop: "70095", route: "Red", route_type: 1) + ]) + |> put_tagged_stop_sequences(%{ + "Red" => [["place-jfk", "place-andrw"]] + }) + |> put_cause(:unknown) + |> put_informed_stations(["JFK/UMass"]) + |> put_all_platforms_at_informed_station([ + %{id: "70085", platform_name: "Ashmont"}, + %{id: "70086", platform_name: "Ashmont"}, + %{id: "70095", platform_name: "Braintree"}, + %{id: "70096", platform_name: "Braintree"} + ]) + + expected = %{ + issue: "Bypassing 2 platforms at JFK/UMass", + location: "", + cause: nil, + routes: [ + %{color: :red, text: "RED LINE", type: :text} + ], + effect: :fallback, + urgent: false, + region: :outside, + remedy: nil + } + + assert expected == ReconstructedAlert.serialize(widget, &fake_log/1) + end + test "handles delay", %{widget: widget} do widget = widget diff --git a/test/screens/v2/widget_instance/subway_status_test.exs b/test/screens/v2/widget_instance/subway_status_test.exs index ff36b4d85..61eaf9961 100644 --- a/test/screens/v2/widget_instance/subway_status_test.exs +++ b/test/screens/v2/widget_instance/subway_status_test.exs @@ -1402,6 +1402,71 @@ defmodule Screens.V2.WidgetInstance.SubwayStatusTest do assert expected == WidgetInstance.serialize(instance) end + test "handles alert closing multiple platforms at one station" do + instance = %SubwayStatus{ + subway_alerts: [ + %{ + alert: %Alert{ + effect: :station_closure, + informed_entities: [ + %{route: "Red", stop: "place-jfk", route_type: 1}, + %{route: "Red", stop: "70085", route_type: 1}, + %{route: "Red", stop: "70095", route_type: 1} + ] + }, + context: %{ + all_platforms_at_informed_station: [ + %{id: "70085", platform_name: "Ashmont"}, + %{id: "70086", platform_name: "Alewife (from Ashmont)"}, + %{id: "70095", platform_name: "Braintree"}, + %{id: "70096", platform_name: "Alewife (from Braintree)"} + ] + } + } + ] + } + + expected = %{ + blue: %{ + type: :contracted, + alerts: [ + %{ + route_pill: %{type: :text, text: "BL", color: :blue}, + status: "Normal Service" + } + ] + }, + orange: %{ + type: :contracted, + alerts: [ + %{ + route_pill: %{type: :text, text: "OL", color: :orange}, + status: "Normal Service" + } + ] + }, + red: %{ + type: :extended, + alert: %{ + status: "Bypassing 2 stops", + location: %{full: "mbta.com/alerts", abbrev: "mbta.com/alerts"}, + route_pill: %{type: :text, text: "RL", color: :red} + } + }, + green: %{ + type: :contracted, + alerts: [ + %{ + route_pill: %{type: :text, text: "GL", color: :green}, + status: "Normal Service" + } + ] + } + } + + assert expected == WidgetInstance.serialize(instance) + end + test "uses 'Entire line' location text for whole-line shuttles" do instance = %SubwayStatus{ subway_alerts: From 0973d2d826b42f1dc7aaa46c5dbbc7e60d4f0f67 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 10 Jul 2024 15:10:05 -0400 Subject: [PATCH 17/30] Fixed platform names. --- test/screens/v2/widget_instance/reconstructed_alert_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/screens/v2/widget_instance/reconstructed_alert_test.exs b/test/screens/v2/widget_instance/reconstructed_alert_test.exs index b67c7088a..21e46a19b 100644 --- a/test/screens/v2/widget_instance/reconstructed_alert_test.exs +++ b/test/screens/v2/widget_instance/reconstructed_alert_test.exs @@ -1652,9 +1652,9 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do |> put_informed_stations(["JFK/UMass"]) |> put_all_platforms_at_informed_station([ %{id: "70085", platform_name: "Ashmont"}, - %{id: "70086", platform_name: "Ashmont"}, + %{id: "70086", platform_name: "Alewife (from Ashmont)"}, %{id: "70095", platform_name: "Braintree"}, - %{id: "70096", platform_name: "Braintree"} + %{id: "70096", platform_name: "Alewife (from Braintree)"} ]) expected = %{ From a010dfd77413a9a3ff48e5b09adcd251e1692614 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Fri, 12 Jul 2024 09:08:40 -0400 Subject: [PATCH 18/30] Changed how we determine if ie is for a subway platform. --- lib/screens/alerts/alert.ex | 16 ++++------------ .../v2/widget_instance/reconstructed_alert.ex | 6 ++++-- lib/screens/v2/widget_instance/subway_status.ex | 3 ++- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/lib/screens/alerts/alert.ex b/lib/screens/alerts/alert.ex index a491c3b89..467f35301 100644 --- a/lib/screens/alerts/alert.ex +++ b/lib/screens/alerts/alert.ex @@ -593,16 +593,6 @@ defmodule Screens.Alerts.Alert do def direction_id(%__MODULE__{informed_entities: informed_entities}), do: List.first(informed_entities).direction_id - # Subway platform IDs are always integers - def informed_subway_platforms(%__MODULE__{ - informed_entities: informed_entities - }) do - Enum.filter( - informed_entities, - &(match?({_n, ""}, Integer.parse(&1.stop)) and &1.route_type == 1) - ) - end - def informed_parent_stations(%__MODULE__{ informed_entities: informed_entities }) do @@ -611,14 +601,16 @@ defmodule Screens.Alerts.Alert do @spec is_partial_station_closure?(__MODULE__.t(), list(Stop.t())) :: boolean() def is_partial_station_closure?( - %__MODULE__{effect: :station_closure} = alert, + %__MODULE__{effect: :station_closure, informed_entities: informed_entities} = alert, all_platforms_at_informed_station ) do informed_parent_stations = informed_parent_stations(alert) case informed_parent_stations do [_] -> - length(informed_subway_platforms(alert)) != length(all_platforms_at_informed_station) + platform_ids = Enum.map(all_platforms_at_informed_station, & &1.id) + informed_platforms = Enum.filter(informed_entities, &(&1.stop in platform_ids)) + length(informed_platforms) != length(all_platforms_at_informed_station) _ -> false diff --git a/lib/screens/v2/widget_instance/reconstructed_alert.ex b/lib/screens/v2/widget_instance/reconstructed_alert.ex index 4495b154e..7946770e3 100644 --- a/lib/screens/v2/widget_instance/reconstructed_alert.ex +++ b/lib/screens/v2/widget_instance/reconstructed_alert.ex @@ -1078,13 +1078,15 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do defp serialize_outside_platform_closure( %__MODULE__{ - alert: alert, + alert: %{informed_entities: informed_entities}, informed_stations: [informed_station], all_platforms_at_informed_station: all_platforms_at_informed_station } = t ) do + platform_ids = Enum.map(all_platforms_at_informed_station, & &1.id) + issue = - case Alert.informed_subway_platforms(alert) do + case Enum.filter(informed_entities, &(&1.stop in platform_ids)) do [informed_platform] -> platform = Enum.find(all_platforms_at_informed_station, &(&1.id == informed_platform.stop)) diff --git a/lib/screens/v2/widget_instance/subway_status.ex b/lib/screens/v2/widget_instance/subway_status.ex index acd2cf6e1..14416cb0c 100644 --- a/lib/screens/v2/widget_instance/subway_status.ex +++ b/lib/screens/v2/widget_instance/subway_status.ex @@ -390,7 +390,8 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do route_id ) do if Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) do - informed_platforms = Alert.informed_subway_platforms(alert) + platform_ids = Enum.map(all_platforms_at_informed_station, & &1.id) + informed_platforms = Enum.filter(informed_entities, &(&1.stop in platform_ids)) %{ status: From 288958ab56590f92becccd910ab47f4e91deb9aa Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Fri, 12 Jul 2024 09:09:11 -0400 Subject: [PATCH 19/30] Fixed tests. --- .../v2/widget_instance/reconstructed_alert_test.exs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/screens/v2/widget_instance/reconstructed_alert_test.exs b/test/screens/v2/widget_instance/reconstructed_alert_test.exs index 21e46a19b..2481075af 100644 --- a/test/screens/v2/widget_instance/reconstructed_alert_test.exs +++ b/test/screens/v2/widget_instance/reconstructed_alert_test.exs @@ -1087,6 +1087,10 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do type: :subway } ]) + |> put_all_platforms_at_informed_station([ + %{id: "70065", platform_name: "Ashmont/Braintree"}, + %{id: "70066", platform_name: "Alewife"} + ]) expected = %{ issue: nil, @@ -1128,6 +1132,10 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do type: :subway } ]) + |> put_all_platforms_at_informed_station([ + %{id: "70065", platform_name: "Ashmont/Braintree"}, + %{id: "70066", platform_name: "Alewife"} + ]) expected = %{ issue: nil, From 3296956f2c74469287df0d1b5d4230a375b32ab2 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Tue, 16 Jul 2024 08:36:08 -0400 Subject: [PATCH 20/30] Added platform support for GL. --- lib/screens/stops/stop.ex | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/screens/stops/stop.ex b/lib/screens/stops/stop.ex index a67a3c380..75bb2faea 100644 --- a/lib/screens/stops/stop.ex +++ b/lib/screens/stops/stop.ex @@ -367,17 +367,14 @@ defmodule Screens.Stops.Stop do case Screens.V3Api.get_json("stops/" <> stop_id, %{"include" => "child_stops"}) do {:ok, %{"included" => child_stop_data}} -> child_stop_data - |> Enum.filter( - &match?( - %{ - "attributes" => %{ - "location_type" => 0, - "vehicle_type" => 1 - } - }, - &1 - ) - ) + |> Enum.filter(fn %{ + "attributes" => %{ + "location_type" => location_type, + "vehicle_type" => vehicle_type + } + } -> + location_type == 0 and vehicle_type in [0, 1] + end) |> Enum.map(&Stops.Parser.parse_stop/1) end end From 11613b66a8f2f80e7504de21179e9758cbe70796 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Tue, 16 Jul 2024 08:38:51 -0400 Subject: [PATCH 21/30] Use existing function. --- lib/screens/alerts/alert.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/screens/alerts/alert.ex b/lib/screens/alerts/alert.ex index 467f35301..ce9076c1d 100644 --- a/lib/screens/alerts/alert.ex +++ b/lib/screens/alerts/alert.ex @@ -1,6 +1,7 @@ defmodule Screens.Alerts.Alert do @moduledoc false + alias Screens.Alerts.InformedEntity alias Screens.Routes.Route alias Screens.RouteType alias Screens.Stops.Stop @@ -596,7 +597,7 @@ defmodule Screens.Alerts.Alert do def informed_parent_stations(%__MODULE__{ informed_entities: informed_entities }) do - Enum.filter(informed_entities, &String.starts_with?(&1.stop, "place-")) + Enum.filter(informed_entities, &InformedEntity.parent_station?/1) end @spec is_partial_station_closure?(__MODULE__.t(), list(Stop.t())) :: boolean() From 9f72d40eed9e9ef4ae1b4f311e3dfb5989549598 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Tue, 16 Jul 2024 08:41:00 -0400 Subject: [PATCH 22/30] No single pipes. --- lib/screens/v2/widget_instance/reconstructed_alert.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/screens/v2/widget_instance/reconstructed_alert.ex b/lib/screens/v2/widget_instance/reconstructed_alert.ex index 7946770e3..733c28c6e 100644 --- a/lib/screens/v2/widget_instance/reconstructed_alert.ex +++ b/lib/screens/v2/widget_instance/reconstructed_alert.ex @@ -1228,7 +1228,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do location = LocalizedAlert.location(t) if Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) do - t |> serialize_single_screen_fallback_alert(location) + serialize_single_screen_fallback_alert(t, location) else diagram_data = serialize_diagram(t, log_fn) From ed575ed71a966e5541586366309d31b9c4caf351 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Tue, 16 Jul 2024 08:45:23 -0400 Subject: [PATCH 23/30] Exclude partial closures from dual_screen_alert?. --- .../v2/widget_instance/reconstructed_alert.ex | 49 ++++++------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/lib/screens/v2/widget_instance/reconstructed_alert.ex b/lib/screens/v2/widget_instance/reconstructed_alert.ex index 733c28c6e..f10a5449b 100644 --- a/lib/screens/v2/widget_instance/reconstructed_alert.ex +++ b/lib/screens/v2/widget_instance/reconstructed_alert.ex @@ -393,8 +393,15 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do }), do: false - def dual_screen_alert?(%__MODULE__{is_terminal_station: is_terminal_station, alert: alert} = t) do + def dual_screen_alert?( + %__MODULE__{ + is_terminal_station: is_terminal_station, + alert: alert, + all_platforms_at_informed_station: all_platforms_at_informed_station + } = t + ) do Alert.effect(alert) in [:station_closure, :suspension, :shuttle] and + not Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) and LocalizedAlert.location(t, is_terminal_station) == :inside and LocalizedAlert.informs_all_active_routes_at_home_stop?(t) and (is_nil(Alert.direction_id(t.alert)) or is_terminal_station) @@ -1299,42 +1306,18 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do def slot_names(%__MODULE__{is_full_screen: false}), do: [:large] - def slot_names( - %__MODULE__{ - alert: alert, - all_platforms_at_informed_station: all_platforms_at_informed_station - } = t - ) do - cond do - Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) -> - [:paged_main_content_left] - - dual_screen_alert?(t) -> - [:full_body] - - true -> - [:paged_main_content_left] - end + def slot_names(%__MODULE__{} = t) do + if dual_screen_alert?(t), + do: [:full_body], + else: [:paged_main_content_left] end def widget_type(%__MODULE__{is_full_screen: false}), do: :reconstructed_large_alert - def widget_type( - %__MODULE__{ - alert: alert, - all_platforms_at_informed_station: all_platforms_at_informed_station - } = t - ) do - cond do - Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) -> - :single_screen_alert - - dual_screen_alert?(t) -> - :reconstructed_takeover - - true -> - :single_screen_alert - end + def widget_type(%__MODULE__{} = t) do + if dual_screen_alert?(t), + do: :reconstructed_takeover, + else: :single_screen_alert end def alert_ids(%__MODULE__{} = t), do: [t.alert.id] From d8fd5a5204fcc36ffdaf3ee9713dc17e8636dc71 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Tue, 16 Jul 2024 08:51:52 -0400 Subject: [PATCH 24/30] Added typespecs. --- .../v2/widget_instance/subway_status.ex | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/screens/v2/widget_instance/subway_status.ex b/lib/screens/v2/widget_instance/subway_status.ex index 14416cb0c..5da377363 100644 --- a/lib/screens/v2/widget_instance/subway_status.ex +++ b/lib/screens/v2/widget_instance/subway_status.ex @@ -360,6 +360,9 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do Map.merge(%{route_pill: serialize_route_pill(route_id)}, serialize_alert(alert, route_id)) end + @spec serialize_alert(Alert.t() | nil, String.t()) :: alert() + defp serialize_alert(alert, route_id) + defp serialize_alert(nil, _route_id) do %{status: "Normal Service"} end @@ -443,15 +446,19 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do } end - def serialize_green_line_branch_alert( - %{ - alert: %Alert{ - effect: :station_closure, - informed_entities: informed_entities - } - }, - route_ids - ) do + @spec serialize_green_line_branch_alert(%{alert: Alert.t(), context: %{}}, list(String.t())) :: + alert() + defp serialize_green_line_branch_alert(alert, route_ids) + + defp serialize_green_line_branch_alert( + %{ + alert: %Alert{ + effect: :station_closure, + informed_entities: informed_entities + } + }, + route_ids + ) do stop_names = Enum.flat_map(route_ids, &get_stop_names_from_informed_entities(informed_entities, &1)) @@ -467,7 +474,7 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do # If only one branch is affected, we can still determine a stop # range to show, for applicable alert types - def serialize_green_line_branch_alert(alert, [route_id]) do + defp serialize_green_line_branch_alert(alert, [route_id]) do Map.merge( %{route_pill: serialize_gl_pill_with_branches([route_id])}, serialize_alert(alert, route_id) @@ -475,7 +482,7 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do end # Otherwise, give up on determining a stop range. - def serialize_green_line_branch_alert(alert, route_ids) do + defp serialize_green_line_branch_alert(alert, route_ids) do Map.merge( %{route_pill: serialize_gl_pill_with_branches(route_ids)}, serialize_alert(alert, "Green") From 02e7fbd07bd9bf306f3b8a83d6024b85baa761ab Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Tue, 16 Jul 2024 09:05:55 -0400 Subject: [PATCH 25/30] Added a struct to describe alerts WidgetInstance.SubwayStatus expects. --- .../widgets/subway_status.ex | 4 ++-- .../v2/widget_instance/subway_status.ex | 20 +++++++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/screens/v2/candidate_generator/widgets/subway_status.ex b/lib/screens/v2/candidate_generator/widgets/subway_status.ex index a3010f396..cafadea45 100644 --- a/lib/screens/v2/candidate_generator/widgets/subway_status.ex +++ b/lib/screens/v2/candidate_generator/widgets/subway_status.ex @@ -53,11 +53,11 @@ defmodule Screens.V2.CandidateGenerator.Widgets.SubwayStatus do [] end - %{ + %SubwayStatus.SubwayStatusAlert{ alert: alert, context: %{all_platforms_at_informed_station: all_platforms_at_informed_station} } end - defp append_context(alert, _), do: %{alert: alert, context: %{}} + defp append_context(alert, _), do: struct(SubwayStatus.SubwayStatusAlert, alert: alert) end diff --git a/lib/screens/v2/widget_instance/subway_status.ex b/lib/screens/v2/widget_instance/subway_status.ex index 5da377363..ff6df51ab 100644 --- a/lib/screens/v2/widget_instance/subway_status.ex +++ b/lib/screens/v2/widget_instance/subway_status.ex @@ -1,5 +1,7 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do - @moduledoc false + @moduledoc """ + A flex-zone widget that displays a brief status of each subway line. + """ alias Screens.Alerts.Alert alias Screens.Alerts.InformedEntity @@ -8,12 +10,26 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do alias ScreensConfig.Screen alias ScreensConfig.V2.{Footer, GlEink, PreFare} + defmodule SubwayStatusAlert do + @type t :: %__MODULE__{ + alert: Alert.t(), + context: context() + } + + @enforce_keys [:alert] + defstruct @enforce_keys ++ [context: nil] + + @type context :: %{ + optional(:all_platforms_at_informed_station) => list(String.t()) + } + end + defstruct screen: nil, subway_alerts: nil @type t :: %__MODULE__{ screen: Screen.t(), - subway_alerts: list(%{alert: Alert.t(), context: %{}}) + subway_alerts: list(SubwayStatusAlert.t()) } @type serialized_response :: %{ From 286a0a7672211fd6d19db5ca27fd8556576231df Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Tue, 16 Jul 2024 10:43:34 -0400 Subject: [PATCH 26/30] Added provider so we don't see warnings. --- lib/screens/cldr.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/screens/cldr.ex b/lib/screens/cldr.ex index 363d470ee..de942548a 100644 --- a/lib/screens/cldr.ex +++ b/lib/screens/cldr.ex @@ -8,5 +8,6 @@ defmodule Screens.Cldr do """ use Cldr, locales: ["en"], - default_locale: "en" + default_locale: "en", + providers: [Cldr.Number] end From cd4a08a04a4ea61d420d21ffde54e75fdf062a5f Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 17 Jul 2024 08:19:13 -0400 Subject: [PATCH 27/30] Moved partial closure logic to CG. --- .../widgets/reconstructed_alert.ex | 27 ++-- .../v2/widget_instance/reconstructed_alert.ex | 143 +++++++++--------- .../v2/widget_instance/subway_status.ex | 2 + .../reconstructed_alert_test.exs | 32 ++-- 4 files changed, 97 insertions(+), 107 deletions(-) diff --git a/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex b/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex index 831628c8e..6f78d94ca 100644 --- a/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex +++ b/lib/screens/v2/candidate_generator/widgets/reconstructed_alert.ex @@ -163,8 +163,8 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlert do fetch_subway_platforms_for_stop_fn: fetch_subway_platforms_for_stop_fn ) do Enum.map(alerts, fn alert -> - all_platforms_at_informed_station = - get_platforms_at_informed_station(alert, fetch_subway_platforms_for_stop_fn) + all_platforms_names_at_informed_station = + get_platform_names_at_informed_station(alert, fetch_subway_platforms_for_stop_fn) %ReconstructedAlert{ screen: config, @@ -174,27 +174,26 @@ defmodule Screens.V2.CandidateGenerator.Widgets.ReconstructedAlert do informed_stations: get_stations(alert, fetch_stop_name_fn), is_terminal_station: is_terminal_station, is_full_screen: is_full_screen, - all_platforms_at_informed_station: all_platforms_at_informed_station + partial_closure_platform_names: all_platforms_names_at_informed_station } end) end - defp get_platforms_at_informed_station( - %{effect: :station_closure} = alert, + defp get_platform_names_at_informed_station( + %Alert{effect: :station_closure, informed_entities: informed_entities} = alert, fetch_subway_platforms_for_stop_fn ) do - informed_parent_stations = Alert.informed_parent_stations(alert) - - case informed_parent_stations do - [informed_parent_station] -> - fetch_subway_platforms_for_stop_fn.(informed_parent_station.stop) - - _ -> - [] + with [informed_parent_station] <- Alert.informed_parent_stations(alert), + platforms <- fetch_subway_platforms_for_stop_fn.(informed_parent_station.stop), + true <- Alert.is_partial_station_closure?(alert, platforms) do + informed_stop_ids = Enum.map(informed_entities, & &1.stop) + platforms |> Enum.filter(&(&1.id in informed_stop_ids)) |> Enum.map(& &1.platform_name) + else + _ -> [] end end - defp get_platforms_at_informed_station(_, _), do: [] + defp get_platform_names_at_informed_station(_, _), do: [] defp find_closest_downstream_alerts(alerts, stop_id, stop_sequences) do home_stop_distance_map = build_distance_map(stop_id, stop_sequences) diff --git a/lib/screens/v2/widget_instance/reconstructed_alert.ex b/lib/screens/v2/widget_instance/reconstructed_alert.ex index f10a5449b..47eabb8ba 100644 --- a/lib/screens/v2/widget_instance/reconstructed_alert.ex +++ b/lib/screens/v2/widget_instance/reconstructed_alert.ex @@ -24,7 +24,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do is_terminal_station: false, # Full screen alert, whether that's a single or dual screen alert is_full_screen: false, - all_platforms_at_informed_station: [] + partial_closure_platform_names: [] @type stop_id :: String.t() @@ -38,7 +38,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do informed_stations: list(String.t()), is_terminal_station: boolean(), is_full_screen: boolean(), - all_platforms_at_informed_station: list(Stop.t()) + partial_closure_platform_names: list(String.t()) } @type serialized_response :: @@ -393,15 +393,20 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do }), do: false + def dual_screen_alert?(%__MODULE__{ + alert: %Alert{effect: :station_closure}, + partial_closure_platform_names: partial_closure_platform_names + }) + when partial_closure_platform_names != [], + do: false + def dual_screen_alert?( %__MODULE__{ is_terminal_station: is_terminal_station, - alert: alert, - all_platforms_at_informed_station: all_platforms_at_informed_station + alert: alert } = t ) do Alert.effect(alert) in [:station_closure, :suspension, :shuttle] and - not Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) and LocalizedAlert.location(t, is_terminal_station) == :inside and LocalizedAlert.informs_all_active_routes_at_home_stop?(t) and (is_nil(Alert.direction_id(t.alert)) or is_terminal_station) @@ -1039,83 +1044,76 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do end end + # Partial closure defp serialize_outside_alert( %__MODULE__{ - alert: %Alert{effect: :station_closure} = alert, - all_platforms_at_informed_station: all_platforms_at_informed_station + informed_stations: [informed_station], + partial_closure_platform_names: partial_closure_platform_names } = t, _location - ) do - if Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) do - serialize_outside_platform_closure(t) - else - %{alert: %{cause: cause}, informed_stations: informed_stations} = t - cause_text = Alert.get_cause_string(cause) + ) + when partial_closure_platform_names != [] do + issue = + case partial_closure_platform_names do + [informed_platform_name] -> + "Bypassing #{informed_platform_name} platform at #{informed_station}" - informed_stations_string = Util.format_name_list_to_string(informed_stations) + informed_subway_platforms -> + Cldr.Message.format!("Bypassing {num_platforms, plural, + =1 {1 platform} + other {# platforms}} at {informed_station}", + num_platforms: length(informed_subway_platforms), + informed_station: informed_station + ) + end - %{ - issue: "Trains will bypass #{informed_stations_string}", - remedy: "Seek alternate route", - location: "", - cause: cause_text, - routes: get_route_pills(t), - effect: :station_closure, - urgent: false - } - end + %{ + issue: issue, + remedy: nil, + location: "", + cause: nil, + routes: get_route_pills(t), + effect: :station_closure, + urgent: false + } end + # Full closure defp serialize_outside_alert( - %__MODULE__{alert: %Alert{effect: :delay}} = t, + %__MODULE__{ + alert: %Alert{effect: :station_closure} + } = t, _location ) do - %{alert: %{header: header}} = t + %{alert: %{cause: cause}, informed_stations: informed_stations} = t + cause_text = Alert.get_cause_string(cause) + + informed_stations_string = Util.format_name_list_to_string(informed_stations) %{ - issue: header, - remedy: "", + issue: "Trains will bypass #{informed_stations_string}", + remedy: "Seek alternate route", location: "", - cause: "", + cause: cause_text, routes: get_route_pills(t), - effect: :delay, + effect: :station_closure, urgent: false } end - defp serialize_outside_platform_closure( - %__MODULE__{ - alert: %{informed_entities: informed_entities}, - informed_stations: [informed_station], - all_platforms_at_informed_station: all_platforms_at_informed_station - } = t + defp serialize_outside_alert( + %__MODULE__{alert: %Alert{effect: :delay}} = t, + _location ) do - platform_ids = Enum.map(all_platforms_at_informed_station, & &1.id) - - issue = - case Enum.filter(informed_entities, &(&1.stop in platform_ids)) do - [informed_platform] -> - platform = - Enum.find(all_platforms_at_informed_station, &(&1.id == informed_platform.stop)) - - "Bypassing #{platform.platform_name} platform at #{informed_station}" - - informed_subway_platforms -> - Cldr.Message.format!("Bypassing {num_platforms, plural, - =1 {1 platform} - other {# platforms}} at {informed_station}", - num_platforms: length(informed_subway_platforms), - informed_station: informed_station - ) - end + %{alert: %{header: header}} = t %{ - issue: issue, - remedy: nil, + issue: header, + remedy: "", location: "", - cause: nil, + cause: "", routes: get_route_pills(t), - effect: :fallback, + effect: :delay, urgent: false } end @@ -1227,22 +1225,27 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlert do def serialize( %__MODULE__{ is_full_screen: true, - alert: %Alert{effect: effect} = alert, - all_platforms_at_informed_station: all_platforms_at_informed_station + alert: %Alert{effect: :station_closure}, + partial_closure_platform_names: partial_closure_platform_names + } = t, + _log_fn + ) + when partial_closure_platform_names != [] do + location = LocalizedAlert.location(t) + serialize_single_screen_fallback_alert(t, location) + end + + def serialize( + %__MODULE__{ + is_full_screen: true, + alert: %Alert{effect: effect} } = t, log_fn ) do location = LocalizedAlert.location(t) - - if Alert.is_partial_station_closure?(alert, all_platforms_at_informed_station) do - serialize_single_screen_fallback_alert(t, location) - else - diagram_data = serialize_diagram(t, log_fn) - - main_data = pick_layout_serializer(t, diagram_data, effect, location, dual_screen_alert?(t)) - - Map.merge(main_data, diagram_data) - end + diagram_data = serialize_diagram(t, log_fn) + main_data = pick_layout_serializer(t, diagram_data, effect, location, dual_screen_alert?(t)) + Map.merge(main_data, diagram_data) end def serialize(%__MODULE__{is_terminal_station: is_terminal_station} = t, _log_fn) do diff --git a/lib/screens/v2/widget_instance/subway_status.ex b/lib/screens/v2/widget_instance/subway_status.ex index ff6df51ab..d449675bf 100644 --- a/lib/screens/v2/widget_instance/subway_status.ex +++ b/lib/screens/v2/widget_instance/subway_status.ex @@ -11,6 +11,8 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do alias ScreensConfig.V2.{Footer, GlEink, PreFare} defmodule SubwayStatusAlert do + @moduledoc false + @type t :: %__MODULE__{ alert: Alert.t(), context: context() diff --git a/test/screens/v2/widget_instance/reconstructed_alert_test.exs b/test/screens/v2/widget_instance/reconstructed_alert_test.exs index 2481075af..f4ce0727e 100644 --- a/test/screens/v2/widget_instance/reconstructed_alert_test.exs +++ b/test/screens/v2/widget_instance/reconstructed_alert_test.exs @@ -29,7 +29,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do routes: nil, alert_route_types: nil }, - all_platforms_at_informed_station: [] + partial_closure_platform_names: [] } } end @@ -130,8 +130,8 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do } end - defp put_all_platforms_at_informed_station(widget, all_platforms_at_informed_station) do - %{widget | all_platforms_at_informed_station: all_platforms_at_informed_station} + defp put_partial_closure_platform_names(widget, partial_closure_platform_names) do + %{widget | partial_closure_platform_names: partial_closure_platform_names} end defp ie(opts) do @@ -1087,10 +1087,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do type: :subway } ]) - |> put_all_platforms_at_informed_station([ - %{id: "70065", platform_name: "Ashmont/Braintree"}, - %{id: "70066", platform_name: "Alewife"} - ]) + |> put_partial_closure_platform_names(["Ashmont/Braintree", "Alewife"]) expected = %{ issue: nil, @@ -1132,10 +1129,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do type: :subway } ]) - |> put_all_platforms_at_informed_station([ - %{id: "70065", platform_name: "Ashmont/Braintree"}, - %{id: "70066", platform_name: "Alewife"} - ]) + |> put_partial_closure_platform_names(["Ashmont/Braintree", "Alewife"]) expected = %{ issue: nil, @@ -1622,10 +1616,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do }) |> put_cause(:unknown) |> put_informed_stations(["Porter"]) - |> put_all_platforms_at_informed_station([ - %{id: "70065", platform_name: "Ashmont/Braintree"}, - %{id: "70066", platform_name: "Alewife"} - ]) + |> put_partial_closure_platform_names(["Ashmont/Braintree"]) expected = %{ issue: "Bypassing Ashmont/Braintree platform at Porter", @@ -1634,7 +1625,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do routes: [ %{color: :red, text: "RED LINE", type: :text} ], - effect: :fallback, + effect: :station_closure, urgent: false, region: :outside, remedy: nil @@ -1658,12 +1649,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do }) |> put_cause(:unknown) |> put_informed_stations(["JFK/UMass"]) - |> put_all_platforms_at_informed_station([ - %{id: "70085", platform_name: "Ashmont"}, - %{id: "70086", platform_name: "Alewife (from Ashmont)"}, - %{id: "70095", platform_name: "Braintree"}, - %{id: "70096", platform_name: "Alewife (from Braintree)"} - ]) + |> put_partial_closure_platform_names(["Ashmont", "Braintree"]) expected = %{ issue: "Bypassing 2 platforms at JFK/UMass", @@ -1672,7 +1658,7 @@ defmodule Screens.V2.WidgetInstance.ReconstructedAlertTest do routes: [ %{color: :red, text: "RED LINE", type: :text} ], - effect: :fallback, + effect: :station_closure, urgent: false, region: :outside, remedy: nil From 112d98baf279fa25860e4094df8d3416e4349d19 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Wed, 17 Jul 2024 10:15:16 -0400 Subject: [PATCH 28/30] Added a comment. --- lib/screens/alerts/alert.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/screens/alerts/alert.ex b/lib/screens/alerts/alert.ex index ce9076c1d..6480905ea 100644 --- a/lib/screens/alerts/alert.ex +++ b/lib/screens/alerts/alert.ex @@ -600,6 +600,8 @@ defmodule Screens.Alerts.Alert do Enum.filter(informed_entities, &InformedEntity.parent_station?/1) end + # Although Alerts UI allows you to create partial closures affecting multiple stations, + # we are assuming that will never happen. @spec is_partial_station_closure?(__MODULE__.t(), list(Stop.t())) :: boolean() def is_partial_station_closure?( %__MODULE__{effect: :station_closure, informed_entities: informed_entities} = alert, From 0876ad65432db76d9d2c314bdf818a780126d082 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Thu, 18 Jul 2024 14:11:52 -0400 Subject: [PATCH 29/30] Added better type. --- lib/screens/v2/widget_instance/subway_status.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/screens/v2/widget_instance/subway_status.ex b/lib/screens/v2/widget_instance/subway_status.ex index d449675bf..8fa90caba 100644 --- a/lib/screens/v2/widget_instance/subway_status.ex +++ b/lib/screens/v2/widget_instance/subway_status.ex @@ -5,6 +5,7 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do alias Screens.Alerts.Alert alias Screens.Alerts.InformedEntity + alias Screens.Routes.Route alias Screens.Stops.Stop alias Screens.V2.WidgetInstance.SubwayStatus alias ScreensConfig.Screen @@ -378,7 +379,7 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do Map.merge(%{route_pill: serialize_route_pill(route_id)}, serialize_alert(alert, route_id)) end - @spec serialize_alert(Alert.t() | nil, String.t()) :: alert() + @spec serialize_alert(Alert.t() | nil, Route.id()) :: alert() defp serialize_alert(alert, route_id) defp serialize_alert(nil, _route_id) do From 776f82281d5c5eef6b147b4c6b07e1c1d807e520 Mon Sep 17 00:00:00 2001 From: cmaddox5 Date: Thu, 18 Jul 2024 14:21:10 -0400 Subject: [PATCH 30/30] Fixed default. --- lib/screens/v2/widget_instance/subway_status.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/screens/v2/widget_instance/subway_status.ex b/lib/screens/v2/widget_instance/subway_status.ex index 8fa90caba..fe2d3aaed 100644 --- a/lib/screens/v2/widget_instance/subway_status.ex +++ b/lib/screens/v2/widget_instance/subway_status.ex @@ -20,7 +20,7 @@ defmodule Screens.V2.WidgetInstance.SubwayStatus do } @enforce_keys [:alert] - defstruct @enforce_keys ++ [context: nil] + defstruct @enforce_keys ++ [context: %{}] @type context :: %{ optional(:all_platforms_at_informed_station) => list(String.t())