Add option to ignore flows (#30008)

This commit is contained in:
Paulus Schoutsen 2019-12-18 07:41:01 +01:00 committed by GitHub
parent feb39c39a3
commit 9c7caaa142
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 132 additions and 3 deletions

View File

@ -33,6 +33,7 @@ async def async_setup(hass):
hass.components.websocket_api.async_register_command(config_entries_progress)
hass.components.websocket_api.async_register_command(system_options_list)
hass.components.websocket_api.async_register_command(system_options_update)
hass.components.websocket_api.async_register_command(ignore_config_flow)
return True
@ -284,3 +285,37 @@ async def system_options_update(hass, connection, msg):
hass.config_entries.async_update_entry(entry, system_options=changes)
connection.send_result(msg["id"], entry.system_options.as_dict())
@websocket_api.require_admin
@websocket_api.async_response
@websocket_api.websocket_command({"type": "config_entries/ignore_flow", "flow_id": str})
async def ignore_config_flow(hass, connection, msg):
"""Ignore a config flow."""
flow = next(
(
flw
for flw in hass.config_entries.flow.async_progress()
if flw["flow_id"] == msg["flow_id"]
),
None,
)
if flow is None:
connection.send_error(
msg["id"], websocket_api.const.ERR_NOT_FOUND, "Config entry not found"
)
return
if "unique_id" not in flow["context"]:
connection.send_error(
msg["id"], "no_unique_id", "Specified flow has no unique ID."
)
return
await hass.config_entries.flow.async_init(
flow["handler"],
context={"source": config_entries.SOURCE_IGNORE},
data={"unique_id": flow["context"]["unique_id"]},
)
connection.send_result(msg["id"])

View File

@ -75,7 +75,7 @@ class HueFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_abort(reason="no_bridges")
# Find already configured hosts
already_configured = self._async_current_ids()
already_configured = self._async_current_ids(False)
bridges = [bridge for bridge in bridges if bridge.id not in already_configured]
if not bridges:

View File

@ -24,6 +24,7 @@ SOURCE_IMPORT = "import"
SOURCE_SSDP = "ssdp"
SOURCE_USER = "user"
SOURCE_ZEROCONF = "zeroconf"
SOURCE_IGNORE = "ignore"
HANDLERS = Registry()
@ -157,6 +158,9 @@ class ConfigEntry:
tries: int = 0,
) -> None:
"""Set up an entry."""
if self.source == SOURCE_IGNORE:
return
if integration is None:
integration = await loader.async_get_integration(hass, self.domain)
@ -792,12 +796,13 @@ class ConfigFlow(data_entry_flow.FlowHandler):
return self.hass.config_entries.async_entries(self.handler)
@callback
def _async_current_ids(self) -> Set[Optional[str]]:
def _async_current_ids(self, include_ignore: bool = True) -> Set[Optional[str]]:
"""Return current unique IDs."""
assert self.hass is not None
return set(
entry.unique_id
for entry in self.hass.config_entries.async_entries(self.handler)
if include_ignore or entry.source != SOURCE_IGNORE
)
@callback
@ -810,6 +815,11 @@ class ConfigFlow(data_entry_flow.FlowHandler):
if flw["handler"] == self.handler and flw["flow_id"] != self.flow_id
]
async def async_step_ignore(self, user_input: Dict[str, Any]) -> Dict[str, Any]:
"""Ignore this config flow."""
await self.async_set_unique_id(user_input["unique_id"], raise_on_progress=False)
return self.async_create_entry(title="Ignored", data={})
class OptionsFlowManager:
"""Flow to set options for a configuration entry."""

View File

@ -634,3 +634,42 @@ async def test_update_system_options(hass, hass_ws_client):
assert response["success"]
assert response["result"]["disable_new_entities"]
assert entry.system_options.disable_new_entities
async def test_ignore_flow(hass, hass_ws_client):
"""Test we can ignore a flow."""
assert await async_setup_component(hass, "config", {})
mock_integration(hass, MockModule("test", async_setup_entry=mock_coro_func(True)))
mock_entity_platform(hass, "config_flow.test", None)
class TestFlow(core_ce.ConfigFlow):
VERSION = 1
async def async_step_user(self, user_input=None):
await self.async_set_unique_id("mock-unique-id")
return self.async_show_form(step_id="account", data_schema=vol.Schema({}))
ws_client = await hass_ws_client(hass)
with patch.dict(HANDLERS, {"test": TestFlow}):
result = await hass.config_entries.flow.async_init(
"test", context={"source": "user"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
await ws_client.send_json(
{
"id": 5,
"type": "config_entries/ignore_flow",
"flow_id": result["flow_id"],
}
)
response = await ws_client.receive_json()
assert response["success"]
assert len(hass.config_entries.flow.async_progress()) == 0
entry = hass.config_entries.async_entries("test")[0]
assert entry.source == "ignore"
assert entry.unique_id == "mock-unique-id"

View File

@ -6,7 +6,7 @@ import aiohue
import pytest
import voluptuous as vol
from homeassistant import data_entry_flow
from homeassistant import config_entries, data_entry_flow
from homeassistant.components.hue import config_flow, const
from tests.common import MockConfigEntry, mock_coro
@ -95,6 +95,11 @@ async def test_flow_one_bridge_discovered(hass, aioclient_mock):
async def test_flow_two_bridges_discovered(hass, aioclient_mock):
"""Test config flow discovers two bridges."""
# Add ignored config entry. Should still show up as option.
MockConfigEntry(
domain="hue", source=config_entries.SOURCE_IGNORE, unique_id="bla"
).add_to_hass(hass)
aioclient_mock.get(
const.API_NUPNP,
json=[

View File

@ -1146,3 +1146,43 @@ async def test_finish_flow_aborts_progress(hass, manager):
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert len(hass.config_entries.flow.async_progress()) == 0
async def test_unique_id_ignore(hass, manager):
"""Test that we can ignore flows that are in progress and have a unique ID."""
async_setup_entry = MagicMock(return_value=mock_coro(False))
mock_integration(hass, MockModule("comp", async_setup_entry=async_setup_entry))
mock_entity_platform(hass, "config_flow.comp", None)
class TestFlow(config_entries.ConfigFlow):
VERSION = 1
async def async_step_user(self, user_input=None):
await self.async_set_unique_id("mock-unique-id")
return self.async_show_form(step_id="discovery")
with patch.dict(config_entries.HANDLERS, {"comp": TestFlow}):
# Create one to be in progress
result = await manager.flow.async_init(
"comp", context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
result2 = await manager.flow.async_init(
"comp",
context={"source": config_entries.SOURCE_IGNORE},
data={"unique_id": "mock-unique-id"},
)
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
# assert len(hass.config_entries.flow.async_progress()) == 0
# We should never set up an ignored entry.
assert len(async_setup_entry.mock_calls) == 0
entry = hass.config_entries.async_entries("comp")[0]
assert entry.source == "ignore"
assert entry.unique_id == "mock-unique-id"