diff --git a/homeassistant/components/analytics_insights/__init__.py b/homeassistant/components/analytics_insights/__init__.py index 2078d9715f4..1c5118ca004 100644 --- a/homeassistant/components/analytics_insights/__init__.py +++ b/homeassistant/components/analytics_insights/__init__.py @@ -46,6 +46,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + entry.async_on_unload(entry.add_update_listener(update_listener)) return True @@ -56,3 +57,8 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.data[DOMAIN].pop(entry.entry_id) return unload_ok + + +async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Handle options update.""" + await hass.config_entries.async_reload(entry.entry_id) diff --git a/homeassistant/components/analytics_insights/config_flow.py b/homeassistant/components/analytics_insights/config_flow.py index afa6b2bac38..eb6d0f87079 100644 --- a/homeassistant/components/analytics_insights/config_flow.py +++ b/homeassistant/components/analytics_insights/config_flow.py @@ -10,7 +10,13 @@ from python_homeassistant_analytics import ( from python_homeassistant_analytics.models import IntegrationType import voluptuous as vol -from homeassistant.config_entries import ConfigFlow +from homeassistant.config_entries import ( + ConfigEntry, + ConfigFlow, + OptionsFlow, + OptionsFlowWithConfigEntry, +) +from homeassistant.core import callback from homeassistant.data_entry_flow import FlowResult from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.selector import ( @@ -31,6 +37,12 @@ INTEGRATION_TYPES_WITHOUT_ANALYTICS = ( class HomeassistantAnalyticsConfigFlow(ConfigFlow, domain=DOMAIN): """Handle a config flow for Homeassistant Analytics.""" + @staticmethod + @callback + def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow: + """Get the options flow for this handler.""" + return HomeassistantAnalyticsOptionsFlowHandler(config_entry) + async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> FlowResult: @@ -72,3 +84,49 @@ class HomeassistantAnalyticsConfigFlow(ConfigFlow, domain=DOMAIN): } ), ) + + +class HomeassistantAnalyticsOptionsFlowHandler(OptionsFlowWithConfigEntry): + """Handle Homeassistant Analytics options.""" + + async def async_step_init( + self, user_input: dict[str, Any] | None = None + ) -> FlowResult: + """Manage the options.""" + if user_input: + return self.async_create_entry(title="", data=user_input) + + client = HomeassistantAnalyticsClient( + session=async_get_clientsession(self.hass) + ) + try: + integrations = await client.get_integrations() + except HomeassistantAnalyticsConnectionError: + LOGGER.exception("Error connecting to Home Assistant analytics") + return self.async_abort(reason="cannot_connect") + + options = [ + SelectOptionDict( + value=domain, + label=integration.title, + ) + for domain, integration in integrations.items() + if integration.integration_type not in INTEGRATION_TYPES_WITHOUT_ANALYTICS + ] + return self.async_show_form( + step_id="init", + data_schema=self.add_suggested_values_to_schema( + vol.Schema( + { + vol.Required(CONF_TRACKED_INTEGRATIONS): SelectSelector( + SelectSelectorConfig( + options=options, + multiple=True, + sort=True, + ) + ), + }, + ), + self.options, + ), + ) diff --git a/homeassistant/components/analytics_insights/strings.json b/homeassistant/components/analytics_insights/strings.json index c6890524a6b..5c249a1cd5a 100644 --- a/homeassistant/components/analytics_insights/strings.json +++ b/homeassistant/components/analytics_insights/strings.json @@ -7,12 +7,21 @@ } } }, - "error": { + "abort": { "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", - "unknown": "[%key:common::config_flow::error::unknown%]" + "already_configured": "[%key:common::config_flow::abort::already_configured_service%]" + } + }, + "options": { + "step": { + "init": { + "data": { + "tracked_integrations": "[%key:component::analytics_insights::config::step::user::data::tracked_integrations%]" + } + } }, "abort": { - "already_configured": "[%key:common::config_flow::abort::already_configured_service%]" + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]" } } } diff --git a/tests/components/analytics_insights/fixtures/integrations.json b/tests/components/analytics_insights/fixtures/integrations.json index eb42216c232..d43f75ab32e 100644 --- a/tests/components/analytics_insights/fixtures/integrations.json +++ b/tests/components/analytics_insights/fixtures/integrations.json @@ -5,5 +5,12 @@ "quality_scale": "", "iot_class": "Cloud Polling", "integration_type": "service" + }, + "hue": { + "title": "Philips Hue", + "description": "Instructions on setting up Philips Hue within Home Assistant.", + "quality_scale": "platinum", + "iot_class": "Local Push", + "integration_type": "hub" } } diff --git a/tests/components/analytics_insights/test_config_flow.py b/tests/components/analytics_insights/test_config_flow.py index 4046bd040df..a93290745f2 100644 --- a/tests/components/analytics_insights/test_config_flow.py +++ b/tests/components/analytics_insights/test_config_flow.py @@ -12,6 +12,7 @@ from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType from tests.common import MockConfigEntry +from tests.components.analytics_insights import setup_integration async def test_form( @@ -68,3 +69,48 @@ async def test_form_already_configured( ) assert result["type"] == FlowResultType.ABORT assert result["reason"] == "already_configured" + + +async def test_options_flow( + hass: HomeAssistant, + mock_analytics_client: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test options flow.""" + await setup_integration(hass, mock_config_entry) + result = await hass.config_entries.options.async_init(mock_config_entry.entry_id) + await hass.async_block_till_done() + assert result["type"] == FlowResultType.FORM + + mock_analytics_client.get_integrations.reset_mock() + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={ + CONF_TRACKED_INTEGRATIONS: ["youtube", "hue"], + }, + ) + await hass.async_block_till_done() + + assert result["type"] == FlowResultType.CREATE_ENTRY + assert result["data"] == { + CONF_TRACKED_INTEGRATIONS: ["youtube", "hue"], + } + await hass.async_block_till_done() + mock_analytics_client.get_integrations.assert_called_once() + + +async def test_options_flow_cannot_connect( + hass: HomeAssistant, + mock_analytics_client: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test we handle cannot connect error.""" + + mock_analytics_client.get_integrations.side_effect = ( + HomeassistantAnalyticsConnectionError + ) + mock_config_entry.add_to_hass(hass) + result = await hass.config_entries.options.async_init(mock_config_entry.entry_id) + await hass.async_block_till_done() + assert result["type"] == FlowResultType.ABORT + assert result["reason"] == "cannot_connect"