From 7d1105228b830605bf980702a5ece30e3687e5c9 Mon Sep 17 00:00:00 2001 From: Kevin Stillhammer Date: Wed, 11 Oct 2023 09:46:02 +0200 Subject: [PATCH] Allow resetting time in google_travel_time (#88256) Co-authored-by: Robert Resch --- .../google_travel_time/config_flow.py | 131 +++++++++++------ .../components/google_travel_time/const.py | 8 +- .../google_travel_time/strings.json | 55 ++++++- .../google_travel_time/test_config_flow.py | 138 ++++++++++++++++++ 4 files changed, 282 insertions(+), 50 deletions(-) diff --git a/homeassistant/components/google_travel_time/config_flow.py b/homeassistant/components/google_travel_time/config_flow.py index 23d4f2541bd..83e144f6bbd 100644 --- a/homeassistant/components/google_travel_time/config_flow.py +++ b/homeassistant/components/google_travel_time/config_flow.py @@ -8,12 +8,17 @@ from homeassistant.const import CONF_API_KEY, CONF_MODE, CONF_NAME from homeassistant.core import HomeAssistant, callback from homeassistant.data_entry_flow import FlowResult import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.selector import ( + SelectSelector, + SelectSelectorConfig, + SelectSelectorMode, +) from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM from .const import ( ALL_LANGUAGES, ARRIVAL_TIME, - AVOID, + AVOID_OPTIONS, CONF_ARRIVAL_TIME, CONF_AVOID, CONF_DEPARTURE_TIME, @@ -30,18 +35,87 @@ from .const import ( DEPARTURE_TIME, DOMAIN, TIME_TYPES, + TRAFFIC_MODELS, TRANSIT_PREFS, - TRANSPORT_TYPE, - TRAVEL_MODE, - TRAVEL_MODEL, + TRANSPORT_TYPES, + TRAVEL_MODES, UNITS, UNITS_IMPERIAL, UNITS_METRIC, ) from .helpers import InvalidApiKeyException, UnknownException, validate_config_entry +OPTIONS_SCHEMA = vol.Schema( + { + vol.Required(CONF_MODE): SelectSelector( + SelectSelectorConfig( + options=TRAVEL_MODES, + sort=True, + mode=SelectSelectorMode.DROPDOWN, + translation_key=CONF_MODE, + ) + ), + vol.Optional(CONF_LANGUAGE): SelectSelector( + SelectSelectorConfig( + options=sorted(ALL_LANGUAGES), + mode=SelectSelectorMode.DROPDOWN, + translation_key=CONF_LANGUAGE, + ) + ), + vol.Optional(CONF_AVOID): SelectSelector( + SelectSelectorConfig( + options=AVOID_OPTIONS, + sort=True, + mode=SelectSelectorMode.DROPDOWN, + translation_key=CONF_AVOID, + ) + ), + vol.Required(CONF_UNITS): SelectSelector( + SelectSelectorConfig( + options=UNITS, + sort=True, + mode=SelectSelectorMode.DROPDOWN, + translation_key=CONF_UNITS, + ) + ), + vol.Required(CONF_TIME_TYPE): SelectSelector( + SelectSelectorConfig( + options=TIME_TYPES, + sort=True, + mode=SelectSelectorMode.DROPDOWN, + translation_key=CONF_TIME_TYPE, + ) + ), + vol.Optional(CONF_TIME, default=""): cv.string, + vol.Optional(CONF_TRAFFIC_MODEL): SelectSelector( + SelectSelectorConfig( + options=TRAFFIC_MODELS, + sort=True, + mode=SelectSelectorMode.DROPDOWN, + translation_key=CONF_TRAFFIC_MODEL, + ) + ), + vol.Optional(CONF_TRANSIT_MODE): SelectSelector( + SelectSelectorConfig( + options=TRANSPORT_TYPES, + sort=True, + mode=SelectSelectorMode.DROPDOWN, + translation_key=CONF_TRANSIT_MODE, + ) + ), + vol.Optional(CONF_TRANSIT_ROUTING_PREFERENCE): SelectSelector( + SelectSelectorConfig( + options=TRANSIT_PREFS, + sort=True, + mode=SelectSelectorMode.DROPDOWN, + translation_key=CONF_TRANSIT_ROUTING_PREFERENCE, + ) + ), + } +) -def default_options(hass: HomeAssistant) -> dict[str, str | None]: + +def default_options(hass: HomeAssistant) -> dict[str, str]: """Get the default options.""" return { CONF_MODE: "driving", @@ -69,53 +143,20 @@ class GoogleOptionsFlow(config_entries.OptionsFlow): user_input[CONF_DEPARTURE_TIME] = time return self.async_create_entry( title="", - data={k: v for k, v in user_input.items() if v not in (None, "")}, + data=user_input, ) + options = self.config_entry.options.copy() if CONF_ARRIVAL_TIME in self.config_entry.options: - default_time_type = ARRIVAL_TIME - default_time = self.config_entry.options[CONF_ARRIVAL_TIME] + options[CONF_TIME_TYPE] = ARRIVAL_TIME + options[CONF_TIME] = self.config_entry.options[CONF_ARRIVAL_TIME] else: - default_time_type = DEPARTURE_TIME - default_time = self.config_entry.options.get(CONF_DEPARTURE_TIME, "") + options[CONF_TIME_TYPE] = DEPARTURE_TIME + options[CONF_TIME] = self.config_entry.options.get(CONF_DEPARTURE_TIME, "") return self.async_show_form( step_id="init", - data_schema=vol.Schema( - { - vol.Optional( - CONF_MODE, default=self.config_entry.options[CONF_MODE] - ): vol.In(TRAVEL_MODE), - vol.Optional( - CONF_LANGUAGE, - default=self.config_entry.options.get(CONF_LANGUAGE), - ): vol.In([None, *ALL_LANGUAGES]), - vol.Optional( - CONF_AVOID, default=self.config_entry.options.get(CONF_AVOID) - ): vol.In([None, *AVOID]), - vol.Optional( - CONF_UNITS, default=self.config_entry.options[CONF_UNITS] - ): vol.In(UNITS), - vol.Optional(CONF_TIME_TYPE, default=default_time_type): vol.In( - TIME_TYPES - ), - vol.Optional(CONF_TIME, default=default_time): cv.string, - vol.Optional( - CONF_TRAFFIC_MODEL, - default=self.config_entry.options.get(CONF_TRAFFIC_MODEL), - ): vol.In([None, *TRAVEL_MODEL]), - vol.Optional( - CONF_TRANSIT_MODE, - default=self.config_entry.options.get(CONF_TRANSIT_MODE), - ): vol.In([None, *TRANSPORT_TYPE]), - vol.Optional( - CONF_TRANSIT_ROUTING_PREFERENCE, - default=self.config_entry.options.get( - CONF_TRANSIT_ROUTING_PREFERENCE - ), - ): vol.In([None, *TRANSIT_PREFS]), - } - ), + data_schema=self.add_suggested_values_to_schema(OPTIONS_SCHEMA, options), ) diff --git a/homeassistant/components/google_travel_time/const.py b/homeassistant/components/google_travel_time/const.py index efc17b22ec1..0535e295b93 100644 --- a/homeassistant/components/google_travel_time/const.py +++ b/homeassistant/components/google_travel_time/const.py @@ -77,11 +77,11 @@ ALL_LANGUAGES = [ "zh-TW", ] -AVOID = ["tolls", "highways", "ferries", "indoor"] +AVOID_OPTIONS = ["tolls", "highways", "ferries", "indoor"] TRANSIT_PREFS = ["less_walking", "fewer_transfers"] -TRANSPORT_TYPE = ["bus", "subway", "train", "tram", "rail"] -TRAVEL_MODE = ["driving", "walking", "bicycling", "transit"] -TRAVEL_MODEL = ["best_guess", "pessimistic", "optimistic"] +TRANSPORT_TYPES = ["bus", "subway", "train", "tram", "rail"] +TRAVEL_MODES = ["driving", "walking", "bicycling", "transit"] +TRAFFIC_MODELS = ["best_guess", "pessimistic", "optimistic"] # googlemaps library uses "metric" or "imperial" terminology in distance_matrix UNITS_METRIC = "metric" diff --git a/homeassistant/components/google_travel_time/strings.json b/homeassistant/components/google_travel_time/strings.json index 270f8fe31e2..e3a13a3d2e3 100644 --- a/homeassistant/components/google_travel_time/strings.json +++ b/homeassistant/components/google_travel_time/strings.json @@ -30,12 +30,65 @@ "time_type": "Time Type", "time": "Time", "avoid": "Avoid", - "traffic_mode": "Traffic Mode", + "traffic_model": "Traffic Model", "transit_mode": "Transit Mode", "transit_routing_preference": "Transit Routing Preference", "units": "Units" } } } + }, + "selector": { + "mode": { + "options": { + "driving": "Driving", + "walking": "Walking", + "bicycling": "Bicycling", + "transit": "Transit" + } + }, + "avoid": { + "options": { + "none": "Avoid nothing", + "tolls": "Tolls", + "highways": "Highways", + "ferries": "Ferries", + "indoor": "Indoor" + } + }, + "units": { + "options": { + "metric": "Metric System", + "imperial": "Imperial System" + } + }, + "time_type": { + "options": { + "arrival_time": "Arrival Time", + "departure_time": "Departure Time" + } + }, + "traffic_model": { + "options": { + "best_guess": "Best Guess", + "pessimistic": "Pessimistic", + "optimistic": "Optimistic" + } + }, + "transit_mode": { + "options": { + "bus": "Bus", + "subway": "Subway", + "train": "Train", + "tram": "Tram", + "rail": "Rail" + } + }, + "transit_routing_preference": { + "options": { + "less_walking": "Less Walking", + "fewer_transfers": "Fewer Transfers" + } + } } } diff --git a/tests/components/google_travel_time/test_config_flow.py b/tests/components/google_travel_time/test_config_flow.py index 9fb381d7d31..15132baf25a 100644 --- a/tests/components/google_travel_time/test_config_flow.py +++ b/tests/components/google_travel_time/test_config_flow.py @@ -257,6 +257,144 @@ async def test_options_flow_departure_time(hass: HomeAssistant, mock_config) -> } +@pytest.mark.parametrize( + ("data", "options"), + [ + ( + MOCK_CONFIG, + { + CONF_MODE: "driving", + CONF_UNITS: UNITS_IMPERIAL, + CONF_DEPARTURE_TIME: "test", + }, + ), + ( + MOCK_CONFIG, + { + CONF_MODE: "driving", + CONF_UNITS: UNITS_IMPERIAL, + CONF_ARRIVAL_TIME: "test", + }, + ), + ], +) +@pytest.mark.usefixtures("validate_config_entry") +async def test_reset_departure_time(hass: HomeAssistant, mock_config) -> None: + """Test resetting departure time.""" + result = await hass.config_entries.options.async_init( + mock_config.entry_id, data=None + ) + + assert result["type"] == data_entry_flow.FlowResultType.FORM + assert result["step_id"] == "init" + + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={ + CONF_MODE: "driving", + CONF_UNITS: UNITS_IMPERIAL, + CONF_TIME_TYPE: DEPARTURE_TIME, + }, + ) + + assert mock_config.options == { + CONF_MODE: "driving", + CONF_UNITS: UNITS_IMPERIAL, + } + + +@pytest.mark.parametrize( + ("data", "options"), + [ + ( + MOCK_CONFIG, + { + CONF_MODE: "driving", + CONF_UNITS: UNITS_IMPERIAL, + CONF_ARRIVAL_TIME: "test", + }, + ), + ( + MOCK_CONFIG, + { + CONF_MODE: "driving", + CONF_UNITS: UNITS_IMPERIAL, + CONF_DEPARTURE_TIME: "test", + }, + ), + ], +) +@pytest.mark.usefixtures("validate_config_entry") +async def test_reset_arrival_time(hass: HomeAssistant, mock_config) -> None: + """Test resetting arrival time.""" + result = await hass.config_entries.options.async_init( + mock_config.entry_id, data=None + ) + + assert result["type"] == data_entry_flow.FlowResultType.FORM + assert result["step_id"] == "init" + + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={ + CONF_MODE: "driving", + CONF_UNITS: UNITS_IMPERIAL, + CONF_TIME_TYPE: ARRIVAL_TIME, + }, + ) + + assert mock_config.options == { + CONF_MODE: "driving", + CONF_UNITS: UNITS_IMPERIAL, + } + + +@pytest.mark.parametrize( + ("data", "options"), + [ + ( + MOCK_CONFIG, + { + CONF_MODE: "driving", + CONF_LANGUAGE: "en", + CONF_AVOID: "tolls", + CONF_UNITS: UNITS_IMPERIAL, + CONF_TIME_TYPE: ARRIVAL_TIME, + CONF_TIME: "test", + CONF_TRAFFIC_MODEL: "best_guess", + CONF_TRANSIT_MODE: "train", + CONF_TRANSIT_ROUTING_PREFERENCE: "less_walking", + }, + ) + ], +) +@pytest.mark.usefixtures("validate_config_entry") +async def test_reset_options_flow_fields(hass: HomeAssistant, mock_config) -> None: + """Test resetting options flow fields that are not time related to None.""" + result = await hass.config_entries.options.async_init( + mock_config.entry_id, data=None + ) + + assert result["type"] == data_entry_flow.FlowResultType.FORM + assert result["step_id"] == "init" + + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={ + CONF_MODE: "driving", + CONF_UNITS: UNITS_IMPERIAL, + CONF_TIME_TYPE: ARRIVAL_TIME, + CONF_TIME: "test", + }, + ) + + assert mock_config.options == { + CONF_MODE: "driving", + CONF_UNITS: UNITS_IMPERIAL, + CONF_ARRIVAL_TIME: "test", + } + + @pytest.mark.usefixtures("validate_config_entry", "bypass_setup") async def test_dupe(hass: HomeAssistant) -> None: """Test setting up the same entry data twice is OK."""