mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 00:37:53 +00:00
Allow creating fixable repairs issues without flows (#76224)
* Allow creating fixable repairs issues without flows * Add test * Adjust test
This commit is contained in:
parent
861b694cff
commit
b366090175
@ -211,6 +211,16 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
translation_key="unfixable_problem",
|
||||
)
|
||||
|
||||
async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"bad_psu",
|
||||
is_fixable=True,
|
||||
learn_more_url="https://www.youtube.com/watch?v=b9rntRxLlbU",
|
||||
severity=IssueSeverity.CRITICAL,
|
||||
translation_key="bad_psu",
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant.components.repairs import RepairsFlow
|
||||
from homeassistant.components.repairs import ConfirmRepairFlow, RepairsFlow
|
||||
|
||||
|
||||
class DemoFixFlow(RepairsFlow):
|
||||
@ -23,11 +23,16 @@ class DemoFixFlow(RepairsFlow):
|
||||
) -> data_entry_flow.FlowResult:
|
||||
"""Handle the confirm step of a fix flow."""
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(title="Fixed issue", data={})
|
||||
return self.async_create_entry(title="", data={})
|
||||
|
||||
return self.async_show_form(step_id="confirm", data_schema=vol.Schema({}))
|
||||
|
||||
|
||||
async def async_create_fix_flow(hass, issue_id):
|
||||
"""Create flow."""
|
||||
if issue_id == "bad_psu":
|
||||
# The bad_psu issue doesn't have its own flow
|
||||
return ConfirmRepairFlow()
|
||||
|
||||
# Other issues have a custom flow
|
||||
return DemoFixFlow()
|
||||
|
@ -1,13 +1,24 @@
|
||||
{
|
||||
"title": "Demo",
|
||||
"issues": {
|
||||
"bad_psu": {
|
||||
"title": "The power supply is not stable",
|
||||
"fix_flow": {
|
||||
"step": {
|
||||
"confirm": {
|
||||
"title": "The power supply needs to be replaced",
|
||||
"description": "Press SUBMIT to confirm the power supply has been replaced"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"out_of_blinker_fluid": {
|
||||
"title": "The blinker fluid is empty and needs to be refilled",
|
||||
"fix_flow": {
|
||||
"step": {
|
||||
"confirm": {
|
||||
"title": "Blinker fluid needs to be refilled",
|
||||
"description": "Press OK when blinker fluid has been refilled"
|
||||
"description": "Press SUBMIT when blinker fluid has been refilled"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,21 @@
|
||||
{
|
||||
"issues": {
|
||||
"bad_psu": {
|
||||
"fix_flow": {
|
||||
"step": {
|
||||
"confirm": {
|
||||
"description": "Press SUBMIT to confirm the power supply has been replaced",
|
||||
"title": "The power supply needs to be replaced"
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "The power supply is not stable"
|
||||
},
|
||||
"out_of_blinker_fluid": {
|
||||
"fix_flow": {
|
||||
"step": {
|
||||
"confirm": {
|
||||
"description": "Press OK when blinker fluid has been refilled",
|
||||
"description": "Press SUBMIT when blinker fluid has been refilled",
|
||||
"title": "Blinker fluid needs to be refilled"
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ from homeassistant.helpers.typing import ConfigType
|
||||
from . import issue_handler, websocket_api
|
||||
from .const import DOMAIN
|
||||
from .issue_handler import (
|
||||
ConfirmRepairFlow,
|
||||
async_create_issue,
|
||||
async_delete_issue,
|
||||
create_issue,
|
||||
@ -21,6 +22,7 @@ __all__ = [
|
||||
"create_issue",
|
||||
"delete_issue",
|
||||
"DOMAIN",
|
||||
"ConfirmRepairFlow",
|
||||
"IssueSeverity",
|
||||
"RepairsFlow",
|
||||
]
|
||||
|
@ -5,6 +5,7 @@ import functools as ft
|
||||
from typing import Any
|
||||
|
||||
from awesomeversion import AwesomeVersion, AwesomeVersionStrategy
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@ -19,6 +20,26 @@ from .issue_registry import async_get as async_get_issue_registry
|
||||
from .models import IssueSeverity, RepairsFlow, RepairsProtocol
|
||||
|
||||
|
||||
class ConfirmRepairFlow(RepairsFlow):
|
||||
"""Handler for an issue fixing flow without any side effects."""
|
||||
|
||||
async def async_step_init(
|
||||
self, user_input: dict[str, str] | None = None
|
||||
) -> data_entry_flow.FlowResult:
|
||||
"""Handle the first step of a fix flow."""
|
||||
|
||||
return await (self.async_step_confirm())
|
||||
|
||||
async def async_step_confirm(
|
||||
self, user_input: dict[str, str] | None = None
|
||||
) -> data_entry_flow.FlowResult:
|
||||
"""Handle the confirm step of a fix flow."""
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(title="", data={})
|
||||
|
||||
return self.async_show_form(step_id="confirm", data_schema=vol.Schema({}))
|
||||
|
||||
|
||||
class RepairsFlowManager(data_entry_flow.FlowManager):
|
||||
"""Manage repairs flows."""
|
||||
|
||||
@ -30,14 +51,6 @@ class RepairsFlowManager(data_entry_flow.FlowManager):
|
||||
data: dict[str, Any] | None = None,
|
||||
) -> RepairsFlow:
|
||||
"""Create a flow. platform is a repairs module."""
|
||||
if "platforms" not in self.hass.data[DOMAIN]:
|
||||
await async_process_repairs_platforms(self.hass)
|
||||
|
||||
platforms: dict[str, RepairsProtocol] = self.hass.data[DOMAIN]["platforms"]
|
||||
if handler_key not in platforms:
|
||||
raise data_entry_flow.UnknownHandler
|
||||
platform = platforms[handler_key]
|
||||
|
||||
assert data and "issue_id" in data
|
||||
issue_id = data["issue_id"]
|
||||
|
||||
@ -46,6 +59,14 @@ class RepairsFlowManager(data_entry_flow.FlowManager):
|
||||
if issue is None or not issue.is_fixable:
|
||||
raise data_entry_flow.UnknownStep
|
||||
|
||||
if "platforms" not in self.hass.data[DOMAIN]:
|
||||
await async_process_repairs_platforms(self.hass)
|
||||
|
||||
platforms: dict[str, RepairsProtocol] = self.hass.data[DOMAIN]["platforms"]
|
||||
if handler_key not in platforms:
|
||||
return ConfirmRepairFlow()
|
||||
platform = platforms[handler_key]
|
||||
|
||||
return await platform.async_create_fix_flow(self.hass, issue_id)
|
||||
|
||||
async def async_finish_flow(
|
||||
|
@ -129,6 +129,20 @@ async def test_issues_created(hass, hass_client, hass_ws_client):
|
||||
"translation_key": "unfixable_problem",
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
{
|
||||
"breaks_in_ha_version": None,
|
||||
"created": ANY,
|
||||
"dismissed_version": None,
|
||||
"domain": "demo",
|
||||
"ignored": False,
|
||||
"is_fixable": True,
|
||||
"issue_domain": None,
|
||||
"issue_id": "bad_psu",
|
||||
"learn_more_url": "https://www.youtube.com/watch?v=b9rntRxLlbU",
|
||||
"severity": "critical",
|
||||
"translation_key": "bad_psu",
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@ -164,7 +178,7 @@ async def test_issues_created(hass, hass_client, hass_ws_client):
|
||||
"description_placeholders": None,
|
||||
"flow_id": flow_id,
|
||||
"handler": "demo",
|
||||
"title": "Fixed issue",
|
||||
"title": "",
|
||||
"type": "create_entry",
|
||||
"version": 1,
|
||||
}
|
||||
@ -203,5 +217,19 @@ async def test_issues_created(hass, hass_client, hass_ws_client):
|
||||
"translation_key": "unfixable_problem",
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
{
|
||||
"breaks_in_ha_version": None,
|
||||
"created": ANY,
|
||||
"dismissed_version": None,
|
||||
"domain": "demo",
|
||||
"ignored": False,
|
||||
"is_fixable": True,
|
||||
"issue_domain": None,
|
||||
"issue_id": "bad_psu",
|
||||
"learn_more_url": "https://www.youtube.com/watch?v=b9rntRxLlbU",
|
||||
"severity": "critical",
|
||||
"translation_key": "bad_psu",
|
||||
"translation_placeholders": None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -21,21 +21,24 @@ from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import mock_platform
|
||||
|
||||
DEFAULT_ISSUES = [
|
||||
{
|
||||
"breaks_in_ha_version": "2022.9",
|
||||
"domain": "fake_integration",
|
||||
"issue_id": "issue_1",
|
||||
"is_fixable": True,
|
||||
"learn_more_url": "https://theuselessweb.com",
|
||||
"severity": "error",
|
||||
"translation_key": "abc_123",
|
||||
"translation_placeholders": {"abc": "123"},
|
||||
}
|
||||
]
|
||||
|
||||
async def create_issues(hass, ws_client):
|
||||
|
||||
async def create_issues(hass, ws_client, issues=None):
|
||||
"""Create issues."""
|
||||
issues = [
|
||||
{
|
||||
"breaks_in_ha_version": "2022.9",
|
||||
"domain": "fake_integration",
|
||||
"issue_id": "issue_1",
|
||||
"is_fixable": True,
|
||||
"learn_more_url": "https://theuselessweb.com",
|
||||
"severity": "error",
|
||||
"translation_key": "abc_123",
|
||||
"translation_placeholders": {"abc": "123"},
|
||||
},
|
||||
]
|
||||
if issues is None:
|
||||
issues = DEFAULT_ISSUES
|
||||
|
||||
for issue in issues:
|
||||
async_create_issue(
|
||||
@ -79,23 +82,22 @@ class MockFixFlow(RepairsFlow):
|
||||
) -> data_entry_flow.FlowResult:
|
||||
"""Handle the first step of a fix flow."""
|
||||
|
||||
return await (self.async_step_confirm())
|
||||
return await (self.async_step_custom_step())
|
||||
|
||||
async def async_step_confirm(
|
||||
async def async_step_custom_step(
|
||||
self, user_input: dict[str, str] | None = None
|
||||
) -> data_entry_flow.FlowResult:
|
||||
"""Handle the confirm step of a fix flow."""
|
||||
"""Handle a custom_step step of a fix flow."""
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(title=None, data=None)
|
||||
return self.async_create_entry(title="", data={})
|
||||
|
||||
return self.async_show_form(step_id="confirm", data_schema=vol.Schema({}))
|
||||
return self.async_show_form(step_id="custom_step", data_schema=vol.Schema({}))
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def mock_repairs_integration(hass):
|
||||
"""Mock a repairs integration."""
|
||||
hass.config.components.add("fake_integration")
|
||||
hass.config.components.add("integration_without_diagnostics")
|
||||
|
||||
def async_create_fix_flow(hass, issue_id):
|
||||
return MockFixFlow()
|
||||
@ -107,7 +109,7 @@ async def mock_repairs_integration(hass):
|
||||
)
|
||||
mock_platform(
|
||||
hass,
|
||||
"integration_without_diagnostics.repairs",
|
||||
"integration_without_repairs.repairs",
|
||||
Mock(spec=[]),
|
||||
)
|
||||
|
||||
@ -237,7 +239,16 @@ async def test_fix_non_existing_issue(
|
||||
}
|
||||
|
||||
|
||||
async def test_fix_issue(hass: HomeAssistant, hass_client, hass_ws_client) -> None:
|
||||
@pytest.mark.parametrize(
|
||||
"domain, step",
|
||||
(
|
||||
("fake_integration", "custom_step"),
|
||||
("fake_integration_default_handler", "confirm"),
|
||||
),
|
||||
)
|
||||
async def test_fix_issue(
|
||||
hass: HomeAssistant, hass_client, hass_ws_client, domain, step
|
||||
) -> None:
|
||||
"""Test we can fix an issue."""
|
||||
assert await async_setup_component(hass, "http", {})
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
@ -245,12 +256,11 @@ async def test_fix_issue(hass: HomeAssistant, hass_client, hass_ws_client) -> No
|
||||
ws_client = await hass_ws_client(hass)
|
||||
client = await hass_client()
|
||||
|
||||
await create_issues(hass, ws_client)
|
||||
issues = [{**DEFAULT_ISSUES[0], "domain": domain}]
|
||||
await create_issues(hass, ws_client, issues=issues)
|
||||
|
||||
url = "/api/repairs/issues/fix"
|
||||
resp = await client.post(
|
||||
url, json={"handler": "fake_integration", "issue_id": "issue_1"}
|
||||
)
|
||||
resp = await client.post(url, json={"handler": domain, "issue_id": "issue_1"})
|
||||
|
||||
assert resp.status == HTTPStatus.OK
|
||||
data = await resp.json()
|
||||
@ -261,9 +271,9 @@ async def test_fix_issue(hass: HomeAssistant, hass_client, hass_ws_client) -> No
|
||||
"description_placeholders": None,
|
||||
"errors": None,
|
||||
"flow_id": ANY,
|
||||
"handler": "fake_integration",
|
||||
"handler": domain,
|
||||
"last_step": None,
|
||||
"step_id": "confirm",
|
||||
"step_id": step,
|
||||
"type": "form",
|
||||
}
|
||||
|
||||
@ -286,8 +296,8 @@ async def test_fix_issue(hass: HomeAssistant, hass_client, hass_ws_client) -> No
|
||||
"description": None,
|
||||
"description_placeholders": None,
|
||||
"flow_id": flow_id,
|
||||
"handler": "fake_integration",
|
||||
"title": None,
|
||||
"handler": domain,
|
||||
"title": "",
|
||||
"type": "create_entry",
|
||||
"version": 1,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user