mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 07:25:52 -05:00
Add config flow title placeholder update infrastructure (#154353)
This commit is contained in:
@@ -2859,6 +2859,29 @@ class ConfigFlow(ConfigEntryBaseFlow):
|
||||
"""Return subentries supported by this handler."""
|
||||
return {}
|
||||
|
||||
@callback
|
||||
def async_update_title_placeholders(
|
||||
self, title_placeholders: Mapping[str, str]
|
||||
) -> None:
|
||||
"""Update title placeholders for the discovery notification and notify listeners.
|
||||
|
||||
This updates the flow context title_placeholders and notifies listeners
|
||||
(such as the frontend) to reload the flow state, updating the discovery
|
||||
notification title.
|
||||
|
||||
Only call this method when the flow is not progressing to a new step
|
||||
(e.g., from a callback that receives updated data). If the flow is
|
||||
progressing to a new step, set title_placeholders directly in context
|
||||
before returning the step result, as the step change will trigger
|
||||
listener notification automatically.
|
||||
"""
|
||||
# Context is typed as TypedDict but is mutable dict at runtime
|
||||
current_placeholders = cast(
|
||||
dict[str, str], self.context.setdefault("title_placeholders", {})
|
||||
)
|
||||
current_placeholders.update(title_placeholders)
|
||||
self.async_notify_flow_changed()
|
||||
|
||||
@callback
|
||||
def _async_abort_entries_match(
|
||||
self, match_dict: dict[str, Any] | None = None
|
||||
|
||||
@@ -432,11 +432,7 @@ class FlowManager(abc.ABC, Generic[_FlowContextT, _FlowResultT, _HandlerT]):
|
||||
!= result.get("description_placeholders")
|
||||
)
|
||||
):
|
||||
# Tell frontend to reload the flow state.
|
||||
self.hass.bus.async_fire_internal(
|
||||
EVENT_DATA_ENTRY_FLOW_PROGRESSED,
|
||||
{"handler": flow.handler, "flow_id": flow_id, "refresh": True},
|
||||
)
|
||||
flow.async_notify_flow_changed()
|
||||
|
||||
return result
|
||||
|
||||
@@ -886,6 +882,17 @@ class FlowHandler(Generic[_FlowContextT, _FlowResultT, _HandlerT]):
|
||||
{"handler": self.handler, "flow_id": self.flow_id, "progress": progress},
|
||||
)
|
||||
|
||||
@callback
|
||||
def async_notify_flow_changed(self) -> None:
|
||||
"""Notify listeners that the flow has changed.
|
||||
|
||||
This notifies listeners (such as the frontend) to reload the flow state.
|
||||
"""
|
||||
self.hass.bus.async_fire_internal(
|
||||
EVENT_DATA_ENTRY_FLOW_PROGRESSED,
|
||||
{"handler": self.handler, "flow_id": self.flow_id, "refresh": True},
|
||||
)
|
||||
|
||||
@callback
|
||||
def async_show_progress_done(self, *, next_step_id: str) -> _FlowResultT:
|
||||
"""Mark the progress done."""
|
||||
|
||||
@@ -9434,3 +9434,74 @@ async def test_create_entry_existing_unique_id(
|
||||
"working in Home Assistant 2026.3, please create a bug report at https:"
|
||||
)
|
||||
assert (log_text in caplog.text) == expected_log
|
||||
|
||||
|
||||
async def test_async_update_title_placeholders(hass: HomeAssistant) -> None:
|
||||
"""Test async_update_title_placeholders updates context and notifies listeners."""
|
||||
|
||||
class TestFlow(config_entries.ConfigFlow):
|
||||
"""Test flow."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Test user step."""
|
||||
self.context["title_placeholders"] = {"initial": "value"}
|
||||
return self.async_show_form(step_id="user")
|
||||
|
||||
mock_integration(hass, MockModule("comp"))
|
||||
mock_platform(hass, "comp.config_flow", None)
|
||||
|
||||
with patch.dict(config_entries.HANDLERS, {"comp": TestFlow}):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"comp", context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
|
||||
# Get the flow to check initial title_placeholders
|
||||
flow = hass.config_entries.flow.async_get(result["flow_id"])
|
||||
assert flow["context"]["title_placeholders"] == {"initial": "value"}
|
||||
|
||||
# Get the flow instance to call methods
|
||||
flow_instance = hass.config_entries.flow._progress[result["flow_id"]]
|
||||
|
||||
# Capture events to verify frontend notification
|
||||
events = async_capture_events(
|
||||
hass, data_entry_flow.EVENT_DATA_ENTRY_FLOW_PROGRESSED
|
||||
)
|
||||
|
||||
# Update title placeholders
|
||||
flow_instance.async_update_title_placeholders({"name": "updated"})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Verify placeholders were updated (preserving existing values)
|
||||
flow = hass.config_entries.flow.async_get(result["flow_id"])
|
||||
assert flow["context"]["title_placeholders"] == {
|
||||
"initial": "value",
|
||||
"name": "updated",
|
||||
}
|
||||
|
||||
# Verify frontend was notified
|
||||
assert len(events) == 1
|
||||
assert events[0].data == {
|
||||
"handler": "comp",
|
||||
"flow_id": result["flow_id"],
|
||||
"refresh": True,
|
||||
}
|
||||
|
||||
# Update again with overlapping key
|
||||
flow_instance.async_update_title_placeholders(
|
||||
{"initial": "new_value", "another": "key"}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Verify placeholders were updated correctly
|
||||
flow = hass.config_entries.flow.async_get(result["flow_id"])
|
||||
assert flow["context"]["title_placeholders"] == {
|
||||
"initial": "new_value",
|
||||
"name": "updated",
|
||||
"another": "key",
|
||||
}
|
||||
|
||||
# Verify frontend was notified again
|
||||
assert len(events) == 2
|
||||
|
||||
Reference in New Issue
Block a user