From 1c230ce0d61bef2727c684879dbebce15ce03992 Mon Sep 17 00:00:00 2001 From: Edward Betts Date: Tue, 26 May 2026 13:19:22 +0100 Subject: [PATCH 1/3] Use path segments for journey result URLs --- app.py | 50 ++++++++++++-------- tests/test_app.py | 67 ++++++++++++++++----------- tests/test_playwright_return_fares.py | 14 +++--- 3 files changed, 76 insertions(+), 55 deletions(-) diff --git a/app.py b/app.py index 1527c00..086a631 100644 --- a/app.py +++ b/app.py @@ -389,9 +389,15 @@ def _results_url( **params, ) if journey_type == "inbound": - params["journey_type"] = "inbound" + return url_for( + "back_results", + station_crs=station_crs, + slug=slug, + travel_date=travel_date, + **params, + ) return url_for( - "results", + "out_results", station_crs=station_crs, slug=slug, travel_date=travel_date, @@ -463,18 +469,17 @@ def search() -> ResponseReturnValue: return redirect(url_for("index")) -@app.route("/results///") -def results(station_crs: str, slug: str, travel_date: str) -> ResponseReturnValue: - return _results( - station_crs, - slug, - travel_date, - request.args.get("journey_type", "outbound"), - request.args.get("return_date"), - ) +@app.route("/results///out/") +def out_results(station_crs: str, slug: str, travel_date: str) -> ResponseReturnValue: + return _results(station_crs, slug, travel_date, "outbound", None) -@app.route("/results////return/") +@app.route("/results///back/") +def back_results(station_crs: str, slug: str, travel_date: str) -> ResponseReturnValue: + return _results(station_crs, slug, travel_date, "inbound", None) + + +@app.route("/results///return//") def return_results( station_crs: str, slug: str, travel_date: str, return_date: str ) -> ResponseReturnValue: @@ -1108,7 +1113,7 @@ def _results( station_crs=station_crs, slug=slug, travel_date=travel_date, - journey_type=journey_type if journey_type == "inbound" else None, + path_journey_type="back" if journey_type == "inbound" else "out", ) summary_html = _build_summary_html( @@ -1331,7 +1336,7 @@ def _results( station_crs=station_crs, slug=slug, travel_date=travel_date, - journey_type=journey_type if journey_type == "inbound" else None, + path_journey_type="back" if journey_type == "inbound" else "out", ) return render_template( @@ -1480,15 +1485,20 @@ def api_walkon_fares( return jsonify({"error": str(e)}), 500 -@app.route("/api/results_refresh///") -def api_results_refresh(station_crs: str, slug: str, travel_date: str) -> Response: - return _api_results_refresh( - station_crs, slug, travel_date, request.args.get("return_date") - ) +@app.route( + "/api/results_refresh////" +) +def api_results_refresh( + station_crs: str, slug: str, path_journey_type: str, travel_date: str +) -> Response: + if path_journey_type not in {"out", "back"}: + abort(404) + journey_type = "inbound" if path_journey_type == "back" else "outbound" + return _api_results_refresh(station_crs, slug, travel_date, None, journey_type) @app.route( - "/api/results_refresh////return/" + "/api/results_refresh///return//" ) def api_return_results_refresh( station_crs: str, slug: str, travel_date: str, return_date: str diff --git a/tests/test_app.py b/tests/test_app.py index b484e8b..5a17560 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -78,7 +78,7 @@ def test_search_redirects_to_results_with_selected_params() -> None: assert resp.status_code == 302 assert resp.headers["Location"].endswith( - "/results/BRI/rotterdam/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/rotterdam/out/2026-04-10?min_connection=60&max_connection=120" ) @@ -91,10 +91,21 @@ def test_search_redirects_return_with_return_date() -> None: assert resp.status_code == 302 assert resp.headers["Location"].endswith( - "/results/BRI/paris/2026-04-10/return/2026-04-17" + "/results/BRI/paris/return/2026-04-10/2026-04-17" ) +def test_search_redirects_inbound_to_back_path() -> None: + client = _client() + + resp = client.get( + "/search?journey_type=inbound&destination=paris&travel_date=2026-04-10&station_crs=BRI" + ) + + assert resp.status_code == 302 + assert resp.headers["Location"].endswith("/results/BRI/paris/back/2026-04-10") + + def test_nr_weekday_cache_key_includes_timetable_period() -> None: key = app_module._nr_weekday_cache_key("to_paddington", "BRI", "2026-06-22") @@ -106,7 +117,7 @@ def test_results_shows_same_day_destination_switcher(monkeypatch: Any) -> None: client = _client() resp = client.get( - "/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120" ) html = resp.get_data(as_text=True) @@ -114,11 +125,11 @@ def test_results_shows_same_day_destination_switcher(monkeypatch: Any) -> None: assert "Switch destination for Friday 10 April 2026" in html assert 'Paris Gare du Nord' in html assert ( - "/results/BRI/brussels/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/brussels/out/2026-04-10?min_connection=60&max_connection=120" in html ) assert ( - "/results/BRI/rotterdam/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/rotterdam/out/2026-04-10?min_connection=60&max_connection=120" in html ) assert "ES 9014" in html @@ -171,7 +182,7 @@ def test_results_can_render_from_weekday_timetable_cache(monkeypatch: Any) -> No client = _client() resp = client.get( - "/results/BRI/paris/2026-06-22?min_connection=60&max_connection=120" + "/results/BRI/paris/out/2026-06-22?min_connection=60&max_connection=120" ) html = resp.get_data(as_text=True) @@ -180,7 +191,7 @@ def test_results_can_render_from_weekday_timetable_cache(monkeypatch: Any) -> No assert "10:01 → 13:34" in html assert "ES 9014" in html assert "checking exact timetable" in html - assert "/api/results_refresh/BRI/paris/2026-06-22" in html + assert "/api/results_refresh/BRI/paris/out/2026-06-22" in html assert "refreshFullResults()" in html assert "window.location.reload()" not in html assert "Checking Eurostar price" in html @@ -268,7 +279,7 @@ def test_results_refresh_reloads_when_exact_timetable_differs(monkeypatch: Any) ) client = _client() - resp = client.get("/api/results_refresh/BRI/paris/2026-06-22") + resp = client.get("/api/results_refresh/BRI/paris/out/2026-06-22") body = resp.get_data(as_text=True) assert resp.status_code == 200 @@ -341,7 +352,7 @@ def test_results_refresh_streams_prices_when_timetable_matches( ) client = _client() - resp = client.get("/api/results_refresh/BRI/paris/2026-06-22") + resp = client.get("/api/results_refresh/BRI/paris/out/2026-06-22") body = resp.get_data(as_text=True) assert resp.status_code == 200 @@ -362,7 +373,7 @@ def test_results_progressive_shell_loads_without_scraping(monkeypatch: Any) -> N monkeypatch.setattr(gwr_fares_scraper, "fetch", fail_fetch) client = _client() - resp = client.get("/results/BRI/paris/2026-04-10?progressive=1") + resp = client.get("/results/BRI/paris/out/2026-04-10?progressive=1") html = resp.get_data(as_text=True) assert resp.status_code == 200 @@ -379,7 +390,7 @@ def test_return_progressive_shell_formats_return_date(monkeypatch: Any) -> None: monkeypatch.setattr(gwr_fares_scraper, "fetch", fail_fetch) client = _client() - resp = client.get("/results/BRI/paris/2026-04-10/return/2026-04-17?progressive=1") + resp = client.get("/results/BRI/paris/return/2026-04-10/2026-04-17?progressive=1") html = resp.get_data(as_text=True) assert resp.status_code == 200 @@ -392,7 +403,7 @@ def test_results_title_and_social_meta_include_destination(monkeypatch: Any) -> client = _client() resp = client.get( - "/results/BRI/lille/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/lille/out/2026-04-10?min_connection=60&max_connection=120" ) html = resp.get_data(as_text=True) @@ -407,7 +418,7 @@ def test_results_title_and_social_meta_include_destination(monkeypatch: Any) -> 'to Lille Europe on Friday 10 April 2026 via Paddington, St Pancras, and Eurostar.">' ) in html assert ( - '' + '' in html ) @@ -498,7 +509,7 @@ def test_results_marks_trips_within_five_minutes_of_fastest_and_slowest( client = _client() resp = client.get( - "/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120" ) html = resp.get_data(as_text=True) @@ -567,7 +578,7 @@ def test_results_shows_only_pre_first_reachable_unreachable_services( client = _client() resp = client.get( - "/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120" ) html = resp.get_data(as_text=True) @@ -583,7 +594,7 @@ def test_results_shows_eurostar_price_and_total(monkeypatch: Any) -> None: client = _client() resp = client.get( - "/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120" ) html = resp.get_data(as_text=True) @@ -640,7 +651,7 @@ def test_results_uses_unique_row_keys_for_same_eurostar(monkeypatch: Any) -> Non client = _client() resp = client.get( - "/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120" ) html = resp.get_data(as_text=True) @@ -685,7 +696,7 @@ def test_results_shows_unreachable_service_when_no_trips(monkeypatch: Any) -> No client = _client() resp = client.get( - "/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120" ) html = resp.get_data(as_text=True) @@ -703,7 +714,7 @@ def test_results_shows_eurostar_plus_price(monkeypatch: Any) -> None: client = _client() resp = client.get( - "/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120" ) html = resp.get_data(as_text=True) @@ -718,7 +729,7 @@ def test_results_selectors_present(monkeypatch: Any) -> None: client = _client() resp = client.get( - "/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120" ) html = resp.get_data(as_text=True) @@ -775,7 +786,7 @@ def test_results_preloads_cached_advance_fares(monkeypatch: Any) -> None: client = _client() resp = client.get( - "/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120" + "/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120" ) html = resp.get_data(as_text=True) @@ -827,7 +838,7 @@ def test_results_inbound_uses_reverse_legs(monkeypatch: Any) -> None: ) client = _client() - resp = client.get("/results/BRI/paris/2026-04-10?journey_type=inbound") + resp = client.get("/results/BRI/paris/back/2026-04-10") html = resp.get_data(as_text=True) assert resp.status_code == 200 @@ -917,7 +928,7 @@ def test_results_return_renders_outbound_and_inbound_tables(monkeypatch: Any) -> ) client = _client() - resp = client.get("/results/BRI/paris/2026-04-10/return/2026-04-17") + resp = client.get("/results/BRI/paris/return/2026-04-10/2026-04-17") html = resp.get_data(as_text=True) assert resp.status_code == 200 @@ -925,11 +936,11 @@ def test_results_return_renders_outbound_and_inbound_tables(monkeypatch: Any) -> assert "Return: Paris Gare du Nord → Bristol Temple Meads" in html assert "Friday 10 April 2026" in html assert "Friday 17 April 2026" in html - assert "/results/BRI/paris/2026-04-09/return/2026-04-17" in html - assert "/results/BRI/paris/2026-04-11/return/2026-04-17" in html - assert "/results/BRI/paris/2026-04-10/return/2026-04-16" in html - assert "/results/BRI/paris/2026-04-10/return/2026-04-18" in html - assert "/results/BRI/paris/2026-04-10/return/2026-04-17" in html + assert "/results/BRI/paris/return/2026-04-09/2026-04-17" in html + assert "/results/BRI/paris/return/2026-04-11/2026-04-17" in html + assert "/results/BRI/paris/return/2026-04-10/2026-04-16" in html + assert "/results/BRI/paris/return/2026-04-10/2026-04-18" in html + assert "/results/BRI/paris/return/2026-04-10/2026-04-17" in html assert "journey_type=return" not in html assert "return_date=2026-04-17" not in html assert "Circle 09:10 → KX 09:25" in html diff --git a/tests/test_playwright_return_fares.py b/tests/test_playwright_return_fares.py index 01205ff..3c89489 100644 --- a/tests/test_playwright_return_fares.py +++ b/tests/test_playwright_return_fares.py @@ -244,7 +244,7 @@ def test_single_advance_standard_totals_after_click(single_server: str) -> None: browser = _launch_browser(p) page = browser.new_page() page.goto( - f"{single_server}/results/BRI/paris/2026-07-20", + f"{single_server}/results/BRI/paris/out/2026-07-20", wait_until="domcontentloaded", ) @@ -344,7 +344,7 @@ def test_single_next_date_advance_standard_labels_unreachable_rows( page = browser.new_page() page.goto( f"http://127.0.0.1:{server.server_port}" - "/results/BRI/brussels/2026-06-16", + "/results/BRI/brussels/out/2026-06-16", wait_until="domcontentloaded", ) page.get_by_role("link", name="Next →").click() @@ -372,7 +372,7 @@ def test_single_advance_standard_premier_totals_on_initial_url( browser = _launch_browser(p) page = browser.new_page() page.goto( - f"{single_server}/results/BRI/paris/2026-07-20" + f"{single_server}/results/BRI/paris/out/2026-07-20" "?nr_class=advance_std&es_class=plus", wait_until="domcontentloaded", ) @@ -452,7 +452,7 @@ def test_single_advance_first_falls_back_to_walkon_when_unavailable( page = browser.new_page() page.goto( f"http://127.0.0.1:{server.server_port}" - "/results/BRI/paris/2026-07-20?nr_class=advance_1st&es_class=standard", + "/results/BRI/paris/out/2026-07-20?nr_class=advance_1st&es_class=standard", wait_until="domcontentloaded", ) @@ -496,7 +496,7 @@ def test_return_advance_first_standard_premier_totals(local_server: str) -> None timeout=10000, ) - assert "/results/BRI/paris/2026-07-20/return/2026-07-27" in page.url + assert "/results/BRI/paris/return/2026-07-20/2026-07-27" in page.url assert "journey_type=return" not in page.url assert "return_date=2026-07-27" not in page.url assert "nr_class=advance_1st" in page.url @@ -528,7 +528,7 @@ def test_return_calendar_selects_outbound_before_return(local_server: str) -> No assert "Return: Wed 17 Jun" in page.locator("#cal-hint").inner_text() page.locator('button[type="submit"]').click() - page.wait_for_url("**/results/BRI/paris/2026-06-10/return/2026-06-17", timeout=10000) + page.wait_for_url("**/results/BRI/paris/return/2026-06-10/2026-06-17", timeout=10000) browser.close() @@ -539,7 +539,7 @@ def test_return_advance_first_standard_premier_totals_on_initial_url( browser = _launch_browser(p) page = browser.new_page() page.goto( - f"{local_server}/results/BRI/paris/2026-07-20/return/2026-07-27" + f"{local_server}/results/BRI/paris/return/2026-07-20/2026-07-27" "?nr_class=advance_1st&es_class=plus", wait_until="domcontentloaded", ) From 52729560500d5ef0f4a9b5e00dcfb2c750eca374 Mon Sep 17 00:00:00 2001 From: Edward Betts Date: Wed, 27 May 2026 00:27:16 +0100 Subject: [PATCH 2/3] Remove obsolete connection template context --- app.py | 140 ++++++++----------------- config/default.py | 1 - templates/base.html | 2 +- templates/index.html | 55 ++++++++-- templates/results.html | 114 +++++++++++---------- templates/results_section.html | 15 ++- templates/results_shell.html | 114 +++++++++++---------- tests/test_app.py | 70 ++++++++++--- tests/test_playwright_return_fares.py | 141 ++++++++++++++++++++++++++ 9 files changed, 423 insertions(+), 229 deletions(-) diff --git a/app.py b/app.py index 086a631..5ae8691 100644 --- a/app.py +++ b/app.py @@ -25,7 +25,6 @@ import scraper.eurostar as eurostar_scraper import scraper.gwr_fares as gwr_fares_scraper import scraper.realtime_trains as rtt_scraper from trip_planner import ( - INBOUND_MAX_CONNECTION_MINUTES, INBOUND_MIN_CONNECTION_MINUTES, combine_inbound_trips, combine_trips, @@ -35,6 +34,8 @@ from trip_planner import ( import cache import circle_line +CONNECTION_WINDOW_MINUTES = 90 + RTT_PADDINGTON_URL = ( "https://www.realtimetrains.co.uk/search/detailed/" "gb-nr:PAD/from/gb-nr:{crs}/{date}/0000-2359" @@ -88,47 +89,31 @@ DESTINATION_OPTIONS = [ {"slug": "cologne", "city": "Cologne", "destination": "Cologne Hbf"}, ] -DESTINATIONS = { - option["slug"]: option["destination"] for option in DESTINATION_OPTIONS -} +DESTINATIONS = {option["slug"]: option["destination"] for option in DESTINATION_OPTIONS} @app.route("/") def index() -> ResponseReturnValue: today = date.today().isoformat() - default_min, default_max = _get_defaults() + default_min = _get_default_min_connection() return render_template( "index.html", destination_options=DESTINATION_OPTIONS, today=today, stations=STATIONS, default_min_connection=default_min, - default_max_connection=default_max, valid_min_connections=sorted(VALID_MIN_CONNECTIONS), - valid_max_connections=sorted(VALID_MAX_CONNECTIONS), - default_return_date=(date.today() + timedelta(days=7)).isoformat(), + default_inbound_min_connection=INBOUND_MIN_CONNECTION_MINUTES, + valid_inbound_min_connections=sorted(VALID_INBOUND_MIN_CONNECTIONS), + valid_inbound_return_min_connections=sorted( + VALID_INBOUND_RETURN_MIN_CONNECTIONS + ), ) VALID_MIN_CONNECTIONS = {45, 50, 60, 70, 80, 90, 100, 110, 120} -VALID_MAX_CONNECTIONS = {60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180} VALID_INBOUND_MIN_CONNECTIONS = {20, 30, 40, 45, 50, 60, 70, 80, 90, 100, 110, 120} VALID_INBOUND_RETURN_MIN_CONNECTIONS = {30, 40, 50, 60} -VALID_INBOUND_MAX_CONNECTIONS = { - 60, - 70, - 80, - 90, - 100, - 110, - 120, - 130, - 140, - 150, - 160, - 170, - 180, -} VALID_JOURNEY_TYPES = {"outbound", "inbound", "return"} VALID_NR_CLASSES = {"walkon", "advance_std", "advance_1st"} VALID_ES_CLASSES = {"standard", "plus"} @@ -284,11 +269,12 @@ def _eurostar_price_status(price: Any, seats: Any) -> str | None: return "price_not_returned" -def _get_defaults() -> tuple[int, int]: - return ( - app.config["DEFAULT_MIN_CONNECTION"], - app.config["DEFAULT_MAX_CONNECTION"], - ) +def _get_default_min_connection() -> int: + return app.config["DEFAULT_MIN_CONNECTION"] + + +def _max_connection_for(min_connection: int) -> int: + return min_connection + CONNECTION_WINDOW_MINUTES def _parse_connection(raw: str | None, default: int, valid_set: set[int]) -> int: @@ -417,22 +403,21 @@ def search() -> ResponseReturnValue: if station_crs not in STATION_BY_CRS: station_crs = "BRI" if journey_type == "inbound": - default_min, default_max = ( - INBOUND_MIN_CONNECTION_MINUTES, - INBOUND_MAX_CONNECTION_MINUTES, - ) - valid_min, valid_max = ( - VALID_INBOUND_MIN_CONNECTIONS, - VALID_INBOUND_MAX_CONNECTIONS, - ) + default_min = INBOUND_MIN_CONNECTION_MINUTES + valid_min = VALID_INBOUND_MIN_CONNECTIONS else: - default_min, default_max = _get_defaults() - valid_min, valid_max = VALID_MIN_CONNECTIONS, VALID_MAX_CONNECTIONS - min_conn = _parse_connection( - request.args.get("min_connection"), default_min, valid_min + default_min = _get_default_min_connection() + valid_min = VALID_MIN_CONNECTIONS + min_connection_arg = ( + request.args.get("min_connection_back") + if journey_type == "inbound" + else request.args.get("min_connection") ) - max_conn = _parse_connection( - request.args.get("max_connection"), default_max, valid_max + min_conn = _parse_connection(min_connection_arg, default_min, valid_min) + inbound_min_conn = _parse_connection( + request.args.get("min_connection_in"), + INBOUND_MIN_CONNECTION_MINUTES, + VALID_INBOUND_RETURN_MIN_CONNECTIONS, ) nr_class = request.args.get("nr_class", DEFAULT_NR_CLASS) if nr_class not in VALID_NR_CLASSES: @@ -461,7 +446,12 @@ def search() -> ResponseReturnValue: journey_type=journey_type, return_date=return_date if journey_type == "return" else None, min_connection=None if min_conn == default_min else min_conn, - max_connection=None if max_conn == default_max else max_conn, + min_connection_in=( + None + if journey_type != "return" + or inbound_min_conn == INBOUND_MIN_CONNECTION_MINUTES + else inbound_min_conn + ), nr_class=None if nr_class == DEFAULT_NR_CLASS else nr_class, es_class=None if es_class == DEFAULT_ES_CLASS else es_class, ) @@ -512,23 +502,15 @@ def _results( return redirect(url_for("index")) if journey_type == "inbound": - default_min, default_max = ( - INBOUND_MIN_CONNECTION_MINUTES, - INBOUND_MAX_CONNECTION_MINUTES, - ) - valid_min, valid_max = ( - VALID_INBOUND_MIN_CONNECTIONS, - VALID_INBOUND_MAX_CONNECTIONS, - ) + default_min = INBOUND_MIN_CONNECTION_MINUTES + valid_min = VALID_INBOUND_MIN_CONNECTIONS else: - default_min, default_max = _get_defaults() - valid_min, valid_max = VALID_MIN_CONNECTIONS, VALID_MAX_CONNECTIONS + default_min = _get_default_min_connection() + valid_min = VALID_MIN_CONNECTIONS min_connection = _parse_connection( request.args.get("min_connection"), default_min, valid_min ) - max_connection = _parse_connection( - request.args.get("max_connection"), default_max, valid_max - ) + max_connection = _max_connection_for(min_connection) nr_class = request.args.get("nr_class", DEFAULT_NR_CLASS) if nr_class not in VALID_NR_CLASSES: nr_class = DEFAULT_NR_CLASS @@ -587,7 +569,6 @@ def _results( departure_station_name=departure_station_name, journey_type=journey_type, travel_date_display=travel_date_display, - return_date=return_date, return_date_display=return_date_display, stream_url=_results_url( station_crs=station_crs, @@ -684,7 +665,7 @@ def _results( section_max_connection = max_connection if journey_type == "return" and direction == "inbound": section_min_connection = inbound_min_connection - section_max_connection = INBOUND_MAX_CONNECTION_MINUTES + section_max_connection = _max_connection_for(inbound_min_connection) rtt_direction = ( "to_paddington" if direction == "outbound" else "from_paddington" ) @@ -752,6 +733,8 @@ def _results( cached_walkon = ( exact_walkon if exact_walkon is not None else get_cached(walkon_weekday_key) ) + if isinstance(cached_walkon, dict): + gwr_fares = cached_walkon if direction == "outbound": trips = combine_trips( @@ -899,7 +882,6 @@ def _results( rtt_station_url = RTT_STATION_URL.format(crs=station_crs, date=travel_date) url_min = None if min_connection == default_min else min_connection - url_max = None if max_connection == default_max else max_connection url_nr = None if nr_class == DEFAULT_NR_CLASS else nr_class url_es = None if es_class == DEFAULT_ES_CLASS else es_class @@ -908,7 +890,6 @@ def _results( "journey_type": journey_type, "return_date": return_date, "min_connection": url_min, - "max_connection": url_max, "min_connection_in": ( None if inbound_min_connection == INBOUND_MIN_CONNECTION_MINUTES @@ -932,7 +913,6 @@ def _results( "journey_type": journey_type, "return_date": return_date, "min_connection": url_min, - "max_connection": url_max, "nr_class": url_nr, "es_class": url_es, } @@ -1005,7 +985,7 @@ def _results( "id": "inbound", "direction": "inbound", "min_connection": inbound_min_connection, - "max_connection": INBOUND_MAX_CONNECTION_MINUTES, + "max_connection": _max_connection_for(inbound_min_connection), }, ] shell_nr_classes = {"outbound": nr_class_out, "inbound": nr_class_in} @@ -1032,8 +1012,6 @@ def _results( journey_type=journey_type, destination=destination, departure_station_name=departure_station_name, - travel_date=travel_date, - return_date=return_date, travel_date_display=travel_date_display, return_date_display=return_date_display, slug=slug, @@ -1055,12 +1033,9 @@ def _results( rtt_url=rtt_url, rtt_station_url=rtt_station_url, min_connection=min_connection, - max_connection=max_connection, default_min_connection=default_min, - default_max_connection=default_max, default_inbound_min_connection=INBOUND_MIN_CONNECTION_MINUTES, valid_min_connections=sorted(valid_min), - valid_max_connections=sorted(valid_max), inbound_min_connection=inbound_min_connection, valid_inbound_return_min_connections=sorted( VALID_INBOUND_RETURN_MIN_CONNECTIONS @@ -1096,6 +1071,8 @@ def _results( section=section, destination=destination, departure_station_name=departure_station_name, + nr_classes=shell_nr_classes, + es_classes=shell_es_classes, ) yield f"data: {json.dumps({'type': 'section', 'id': section_id, 'html': section_html, 'trip_fares': _section_trip_fares(section), 'advance_fares': section['advance_fares'], 'walkon_cached_fares': section.get('cached_walkon_fares'), 'walkon_api_url': section['walkon_api_url'], 'advance_api_url': section['advance_api_url'], 'advance_stream_url': section['advance_stream_url']})}\n\n" @@ -1186,7 +1163,6 @@ def _results( rtt_station_url = RTT_STATION_URL.format(crs=station_crs, date=travel_date) url_min = None if min_connection == default_min else min_connection - url_max = None if max_connection == default_max else max_connection url_nr = None if nr_class == DEFAULT_NR_CLASS else nr_class url_es = None if es_class == DEFAULT_ES_CLASS else es_class common_url_args: dict[str, Any] @@ -1195,7 +1171,6 @@ def _results( "journey_type": journey_type, "return_date": return_date, "min_connection": url_min, - "max_connection": url_max, "min_connection_in": ( None if inbound_min_connection == INBOUND_MIN_CONNECTION_MINUTES @@ -1211,7 +1186,6 @@ def _results( "journey_type": journey_type, "return_date": return_date, "min_connection": url_min, - "max_connection": url_max, "nr_class": url_nr, "es_class": url_es, } @@ -1342,19 +1316,10 @@ def _results( return render_template( "results.html", sections=sections, - trips=sections[0]["trips"] if sections else [], - result_rows=sections[0]["rows"] if sections else [], - unreachable_morning_services=[], - destinations=DESTINATIONS, destination=destination, - travel_date=travel_date, - return_date=return_date, journey_type=journey_type, slug=slug, - station_crs=station_crs, departure_station_name=departure_station_name, - prev_date=prev_date, - next_date=next_date, prev_results_url=prev_results_url, next_results_url=next_results_url, prev_outbound_url=prev_outbound_url, @@ -1375,15 +1340,7 @@ def _results( rtt_url=rtt_url, rtt_station_url=rtt_station_url, min_connection=min_connection, - max_connection=max_connection, default_min_connection=default_min, - default_max_connection=default_max, - url_min_connection=url_min, - url_max_connection=url_max, - nr_class=nr_class, - es_class=es_class, - url_nr_class=url_nr, - url_es_class=url_es, nr_classes=nr_classes, es_classes=es_classes, nr_classes_json=json.dumps(nr_classes), @@ -1396,14 +1353,7 @@ def _results( advance_api_urls_json=json.dumps(advance_api_urls), advance_stream_urls_json=json.dumps(advance_stream_urls), timetable_refresh_url=timetable_refresh_url, - advance_fares_api_url=url_for( - "api_advance_fares", station_crs=station_crs, travel_date=travel_date - ), - advance_fares_stream_url=url_for( - "api_advance_fares_stream", station_crs=station_crs, travel_date=travel_date - ), valid_min_connections=sorted(valid_min), - valid_max_connections=sorted(valid_max), inbound_min_connection=inbound_min_connection, default_inbound_min_connection=INBOUND_MIN_CONNECTION_MINUTES, valid_inbound_return_min_connections=sorted( diff --git a/config/default.py b/config/default.py index 3d9c4e2..c249656 100644 --- a/config/default.py +++ b/config/default.py @@ -11,4 +11,3 @@ CIRCLE_LINE_XML = os.path.join(TFL_DATA_DIR, "output_txc_01CIR_.xml") # Default connection window (minutes) between Paddington arrival and St Pancras departure DEFAULT_MIN_CONNECTION = 70 -DEFAULT_MAX_CONNECTION = 150 diff --git a/templates/base.html b/templates/base.html index 5aeafa9..4afdefd 100644 --- a/templates/base.html +++ b/templates/base.html @@ -342,7 +342,7 @@ tr.row-selectable:hover:not(.row-selected) { filter: brightness(0.97); } /* Journey flow arrow between column headers */ - .results-table thead th.flow-step { position: relative; padding-right: 1.4rem; } + .results-table thead th.flow-step { position: sticky; padding-right: 1.4rem; } .results-table thead th.flow-step::after { content: '›'; position: absolute; right: 0.2rem; top: 50%; transform: translateY(-50%); diff --git a/templates/index.html b/templates/index.html index 8d29dfe..a3e495c 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,6 +1,8 @@ {% extends "base.html" %} {% block content %}