mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 02:37:08 +00:00
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
@ -78,6 +78,8 @@ DISCOVERY_SOURCES = (
|
|||||||
SOURCE_UNIGNORE,
|
SOURCE_UNIGNORE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
RECONFIGURE_NOTIFICATION_ID = "config_entry_reconfigure"
|
||||||
|
|
||||||
EVENT_FLOW_DISCOVERED = "config_entry_discovered"
|
EVENT_FLOW_DISCOVERED = "config_entry_discovered"
|
||||||
|
|
||||||
CONN_CLASS_CLOUD_PUSH = "cloud_push"
|
CONN_CLASS_CLOUD_PUSH = "cloud_push"
|
||||||
@ -566,6 +568,15 @@ class ConfigEntriesFlowManager(data_entry_flow.FlowManager):
|
|||||||
),
|
),
|
||||||
notification_id=DISCOVERY_NOTIFICATION_ID,
|
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:
|
class ConfigEntries:
|
||||||
@ -1004,6 +1015,27 @@ class ConfigFlow(data_entry_flow.FlowHandler):
|
|||||||
await self._async_handle_discovery_without_unique_id()
|
await self._async_handle_discovery_without_unique_id()
|
||||||
return await self.async_step_user()
|
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_hassio = async_step_discovery
|
||||||
async_step_homekit = async_step_discovery
|
async_step_homekit = async_step_discovery
|
||||||
async_step_mqtt = async_step_discovery
|
async_step_mqtt = async_step_discovery
|
||||||
|
@ -261,11 +261,17 @@ class FlowHandler:
|
|||||||
@property
|
@property
|
||||||
def source(self) -> Optional[str]:
|
def source(self) -> Optional[str]:
|
||||||
"""Source that initialized the flow."""
|
"""Source that initialized the flow."""
|
||||||
|
if not hasattr(self, "context"):
|
||||||
|
return None
|
||||||
|
|
||||||
return self.context.get("source", None)
|
return self.context.get("source", None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def show_advanced_options(self) -> bool:
|
def show_advanced_options(self) -> bool:
|
||||||
"""If we should show advanced options."""
|
"""If we should show advanced options."""
|
||||||
|
if not hasattr(self, "context"):
|
||||||
|
return False
|
||||||
|
|
||||||
return self.context.get("show_advanced_options", False)
|
return self.context.get("show_advanced_options", False)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@ -609,7 +609,8 @@ async def test_discovery_notification(hass):
|
|||||||
title="Test Title", data={"token": "abcd"}
|
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}
|
"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")
|
state = hass.states.get("persistent_notification.config_entry_discovery")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
# Start a second discovery flow so we can finish the first and assert that
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
# 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()
|
await hass.async_block_till_done()
|
||||||
state = hass.states.get("persistent_notification.config_entry_discovery")
|
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
|
assert state is None
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user