Add persistent notification for reauth config flows (#41811)
* add persistent notification for reauth config flow * remove log * Update homeassistant/config_entries.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/config_entries.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * fix logic for determining when to dismiss notification * add comment * improve tests to ensure notifications only get dismissed when all in progress config flows of a given type are complete * Update homeassistant/config_entries.py Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io> * handle context is None when accessing source * add guard to show_advanced_options * Apply suggestions from code review Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io> Co-authored-by: Chris Talkington <chris@talkingtontech.com>
This commit is contained in:
parent
a220e74154
commit
0e20bba40a
3 changed files with 123 additions and 3 deletions
|
@ -78,6 +78,8 @@ DISCOVERY_SOURCES = (
|
|||
SOURCE_UNIGNORE,
|
||||
)
|
||||
|
||||
RECONFIGURE_NOTIFICATION_ID = "config_entry_reconfigure"
|
||||
|
||||
EVENT_FLOW_DISCOVERED = "config_entry_discovered"
|
||||
|
||||
CONN_CLASS_CLOUD_PUSH = "cloud_push"
|
||||
|
@ -566,6 +568,15 @@ class ConfigEntriesFlowManager(data_entry_flow.FlowManager):
|
|||
),
|
||||
notification_id=DISCOVERY_NOTIFICATION_ID,
|
||||
)
|
||||
elif source == SOURCE_REAUTH:
|
||||
self.hass.components.persistent_notification.async_create(
|
||||
title="Integration requires reconfiguration",
|
||||
message=(
|
||||
"At least one of your integrations requires reconfiguration to "
|
||||
"continue functioning. [Check it out](/config/integrations)"
|
||||
),
|
||||
notification_id=RECONFIGURE_NOTIFICATION_ID,
|
||||
)
|
||||
|
||||
|
||||
class ConfigEntries:
|
||||
|
@ -1004,6 +1015,27 @@ class ConfigFlow(data_entry_flow.FlowHandler):
|
|||
await self._async_handle_discovery_without_unique_id()
|
||||
return await self.async_step_user()
|
||||
|
||||
@callback
|
||||
def async_abort(
|
||||
self, *, reason: str, description_placeholders: Optional[Dict] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""Abort the config flow."""
|
||||
assert self.hass
|
||||
|
||||
# Remove reauth notification if no reauth flows are in progress
|
||||
if self.source == SOURCE_REAUTH and not any(
|
||||
ent["context"]["source"] == SOURCE_REAUTH
|
||||
for ent in self.hass.config_entries.flow.async_progress()
|
||||
if ent["flow_id"] != self.flow_id
|
||||
):
|
||||
self.hass.components.persistent_notification.async_dismiss(
|
||||
RECONFIGURE_NOTIFICATION_ID
|
||||
)
|
||||
|
||||
return super().async_abort(
|
||||
reason=reason, description_placeholders=description_placeholders
|
||||
)
|
||||
|
||||
async_step_hassio = async_step_discovery
|
||||
async_step_homekit = async_step_discovery
|
||||
async_step_mqtt = async_step_discovery
|
||||
|
|
|
@ -261,11 +261,17 @@ class FlowHandler:
|
|||
@property
|
||||
def source(self) -> Optional[str]:
|
||||
"""Source that initialized the flow."""
|
||||
if not hasattr(self, "context"):
|
||||
return None
|
||||
|
||||
return self.context.get("source", None)
|
||||
|
||||
@property
|
||||
def show_advanced_options(self) -> bool:
|
||||
"""If we should show advanced options."""
|
||||
if not hasattr(self, "context"):
|
||||
return False
|
||||
|
||||
return self.context.get("show_advanced_options", False)
|
||||
|
||||
@callback
|
||||
|
|
|
@ -609,7 +609,8 @@ async def test_discovery_notification(hass):
|
|||
title="Test Title", data={"token": "abcd"}
|
||||
)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
# Start first discovery flow to assert that reconfigure notification fires
|
||||
flow1 = await hass.config_entries.flow.async_init(
|
||||
"test", context={"source": config_entries.SOURCE_DISCOVERY}
|
||||
)
|
||||
|
||||
|
@ -617,11 +618,92 @@ async def test_discovery_notification(hass):
|
|||
state = hass.states.get("persistent_notification.config_entry_discovery")
|
||||
assert state is not None
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
# Start a second discovery flow so we can finish the first and assert that
|
||||
# the discovery notification persists until the second one is complete
|
||||
flow2 = await hass.config_entries.flow.async_init(
|
||||
"test", context={"source": config_entries.SOURCE_DISCOVERY}
|
||||
)
|
||||
|
||||
flow1 = await hass.config_entries.flow.async_configure(flow1["flow_id"], {})
|
||||
assert flow1["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("persistent_notification.config_entry_discovery")
|
||||
assert state is not None
|
||||
|
||||
flow2 = await hass.config_entries.flow.async_configure(flow2["flow_id"], {})
|
||||
assert flow2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("persistent_notification.config_entry_discovery")
|
||||
assert state is None
|
||||
|
||||
|
||||
async def test_reauth_notification(hass):
|
||||
"""Test that we create/dismiss a notification when source is reauth."""
|
||||
mock_integration(hass, MockModule("test"))
|
||||
mock_entity_platform(hass, "config_flow.test", None)
|
||||
await async_setup_component(hass, "persistent_notification", {})
|
||||
|
||||
with patch.dict(config_entries.HANDLERS):
|
||||
|
||||
class TestFlow(config_entries.ConfigFlow, domain="test"):
|
||||
"""Test flow."""
|
||||
|
||||
VERSION = 5
|
||||
|
||||
async def async_step_user(self, user_input):
|
||||
"""Test user step."""
|
||||
return self.async_show_form(step_id="user_confirm")
|
||||
|
||||
async def async_step_user_confirm(self, user_input):
|
||||
"""Test user confirm step."""
|
||||
return self.async_show_form(step_id="user_confirm")
|
||||
|
||||
async def async_step_reauth(self, user_input):
|
||||
"""Test reauth step."""
|
||||
return self.async_show_form(step_id="reauth_confirm")
|
||||
|
||||
async def async_step_reauth_confirm(self, user_input):
|
||||
"""Test reauth confirm step."""
|
||||
return self.async_abort(reason="test")
|
||||
|
||||
# Start user flow to assert that reconfigure notification doesn't fire
|
||||
await hass.config_entries.flow.async_init(
|
||||
"test", context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("persistent_notification.config_entry_reconfigure")
|
||||
assert state is None
|
||||
|
||||
# Start first reauth flow to assert that reconfigure notification fires
|
||||
flow1 = await hass.config_entries.flow.async_init(
|
||||
"test", context={"source": config_entries.SOURCE_REAUTH}
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("persistent_notification.config_entry_reconfigure")
|
||||
assert state is not None
|
||||
|
||||
# Start a second reauth flow so we can finish the first and assert that
|
||||
# the reconfigure notification persists until the second one is complete
|
||||
flow2 = await hass.config_entries.flow.async_init(
|
||||
"test", context={"source": config_entries.SOURCE_REAUTH}
|
||||
)
|
||||
|
||||
flow1 = await hass.config_entries.flow.async_configure(flow1["flow_id"], {})
|
||||
assert flow1["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("persistent_notification.config_entry_reconfigure")
|
||||
assert state is not None
|
||||
|
||||
flow2 = await hass.config_entries.flow.async_configure(flow2["flow_id"], {})
|
||||
assert flow2["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("persistent_notification.config_entry_reconfigure")
|
||||
assert state is None
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue