Create issues in demo integration (#75081)
* Create issues in demo integration * Add unfixable non-expiring issue * Update test * Adjust tests * update translations * add hassfest translation schema * Update homeassistant/components/demo/translations/en.json Co-authored-by: Zack Barett <zackbarett@hey.com> * Rename Resolution Center -> Repairs * Update homeassistant/components/demo/strings.json Co-authored-by: Zack Barett <zackbarett@hey.com> * Adjust hassfest to require description or fix_flow * Update homeassistant/components/demo/repairs.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update tests/components/demo/test_init.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Add missing translation strings * black * Adjust repairs imports Co-authored-by: Bram Kragten <mail@bramkragten.nl> Co-authored-by: Franck Nijhof <git@frenck.dev> Co-authored-by: Zack Barett <zackbarett@hey.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
3920844dca
commit
fb4aff25a2
7 changed files with 266 additions and 4 deletions
|
@ -10,6 +10,7 @@ from homeassistant.components.recorder.statistics import (
|
||||||
async_add_external_statistics,
|
async_add_external_statistics,
|
||||||
get_last_statistics,
|
get_last_statistics,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.repairs import IssueSeverity, async_create_issue
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
|
@ -177,6 +178,39 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
|
|
||||||
hass.bus.async_listen(EVENT_HOMEASSISTANT_START, demo_start_listener)
|
hass.bus.async_listen(EVENT_HOMEASSISTANT_START, demo_start_listener)
|
||||||
|
|
||||||
|
# Create issues
|
||||||
|
async_create_issue(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
"transmogrifier_deprecated",
|
||||||
|
breaks_in_ha_version="2023.1.1",
|
||||||
|
is_fixable=False,
|
||||||
|
learn_more_url="https://en.wiktionary.org/wiki/transmogrifier",
|
||||||
|
severity=IssueSeverity.WARNING,
|
||||||
|
translation_key="transmogrifier_deprecated",
|
||||||
|
)
|
||||||
|
|
||||||
|
async_create_issue(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
"out_of_blinker_fluid",
|
||||||
|
breaks_in_ha_version="2023.1.1",
|
||||||
|
is_fixable=True,
|
||||||
|
learn_more_url="https://www.youtube.com/watch?v=b9rntRxLlbU",
|
||||||
|
severity=IssueSeverity.CRITICAL,
|
||||||
|
translation_key="out_of_blinker_fluid",
|
||||||
|
)
|
||||||
|
|
||||||
|
async_create_issue(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
"unfixable_problem",
|
||||||
|
is_fixable=False,
|
||||||
|
learn_more_url="https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||||
|
severity=IssueSeverity.WARNING,
|
||||||
|
translation_key="unfixable_problem",
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "Demo",
|
"name": "Demo",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/demo",
|
"documentation": "https://www.home-assistant.io/integrations/demo",
|
||||||
"after_dependencies": ["recorder"],
|
"after_dependencies": ["recorder"],
|
||||||
"dependencies": ["conversation", "group", "zone"],
|
"dependencies": ["conversation", "group", "repairs", "zone"],
|
||||||
"codeowners": ["@home-assistant/core"],
|
"codeowners": ["@home-assistant/core"],
|
||||||
"quality_scale": "internal",
|
"quality_scale": "internal",
|
||||||
"iot_class": "calculated"
|
"iot_class": "calculated"
|
||||||
|
|
33
homeassistant/components/demo/repairs.py
Normal file
33
homeassistant/components/demo/repairs.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
"""Repairs platform for the demo integration."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant import data_entry_flow
|
||||||
|
from homeassistant.components.repairs import RepairsFlow
|
||||||
|
|
||||||
|
|
||||||
|
class DemoFixFlow(RepairsFlow):
|
||||||
|
"""Handler for an issue fixing flow."""
|
||||||
|
|
||||||
|
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="Fixed issue", data={})
|
||||||
|
|
||||||
|
return self.async_show_form(step_id="confirm", data_schema=vol.Schema({}))
|
||||||
|
|
||||||
|
|
||||||
|
async def async_create_fix_flow(hass, issue_id):
|
||||||
|
"""Create flow."""
|
||||||
|
return DemoFixFlow()
|
|
@ -1,5 +1,26 @@
|
||||||
{
|
{
|
||||||
"title": "Demo",
|
"title": "Demo",
|
||||||
|
"issues": {
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transmogrifier_deprecated": {
|
||||||
|
"title": "The transmogrifier component is deprecated",
|
||||||
|
"description": "The transmogrifier component is now deprecated due to the lack of local control available in the new API"
|
||||||
|
},
|
||||||
|
"unfixable_problem": {
|
||||||
|
"title": "This is not a fixable problem",
|
||||||
|
"description": "This issue is never going to give up."
|
||||||
|
}
|
||||||
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"step": {
|
"step": {
|
||||||
"init": {
|
"init": {
|
||||||
|
|
|
@ -1,6 +1,30 @@
|
||||||
{
|
{
|
||||||
|
"issues": {
|
||||||
|
"out_of_blinker_fluid": {
|
||||||
|
"fix_flow": {
|
||||||
|
"step": {
|
||||||
|
"confirm": {
|
||||||
|
"description": "Press OK when blinker fluid has been refilled",
|
||||||
|
"title": "Blinker fluid needs to be refilled"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "The blinker fluid is empty and needs to be refilled"
|
||||||
|
},
|
||||||
|
"transmogrifier_deprecated": {
|
||||||
|
"description": "The transmogrifier component is now deprecated due to the lack of local control available in the new API",
|
||||||
|
"title": "The transmogrifier component is deprecated"
|
||||||
|
},
|
||||||
|
"unfixable_problem": {
|
||||||
|
"description": "This issue is never going to give up.",
|
||||||
|
"title": "This is not a fixable problem"
|
||||||
|
}
|
||||||
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"step": {
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {}
|
||||||
|
},
|
||||||
"options_1": {
|
"options_1": {
|
||||||
"data": {
|
"data": {
|
||||||
"bool": "Optional boolean",
|
"bool": "Optional boolean",
|
||||||
|
|
|
@ -21,7 +21,7 @@ REMOVED = 2
|
||||||
|
|
||||||
RE_REFERENCE = r"\[\%key:(.+)\%\]"
|
RE_REFERENCE = r"\[\%key:(.+)\%\]"
|
||||||
|
|
||||||
# Only allow translatino of integration names if they contain non-brand names
|
# Only allow translation of integration names if they contain non-brand names
|
||||||
ALLOW_NAME_TRANSLATION = {
|
ALLOW_NAME_TRANSLATION = {
|
||||||
"cert_expiry",
|
"cert_expiry",
|
||||||
"cpuspeed",
|
"cpuspeed",
|
||||||
|
@ -185,7 +185,7 @@ def gen_data_entry_schema(
|
||||||
return vol.All(*validators)
|
return vol.All(*validators)
|
||||||
|
|
||||||
|
|
||||||
def gen_strings_schema(config: Config, integration: Integration):
|
def gen_strings_schema(config: Config, integration: Integration) -> vol.Schema:
|
||||||
"""Generate a strings schema."""
|
"""Generate a strings schema."""
|
||||||
return vol.Schema(
|
return vol.Schema(
|
||||||
{
|
{
|
||||||
|
@ -227,6 +227,25 @@ def gen_strings_schema(config: Config, integration: Integration):
|
||||||
vol.Optional("application_credentials"): {
|
vol.Optional("application_credentials"): {
|
||||||
vol.Optional("description"): cv.string_with_no_html,
|
vol.Optional("description"): cv.string_with_no_html,
|
||||||
},
|
},
|
||||||
|
vol.Optional("issues"): {
|
||||||
|
str: vol.All(
|
||||||
|
cv.has_at_least_one_key("description", "fix_flow"),
|
||||||
|
vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required("title"): cv.string_with_no_html,
|
||||||
|
vol.Exclusive(
|
||||||
|
"description", "fixable"
|
||||||
|
): cv.string_with_no_html,
|
||||||
|
vol.Exclusive("fix_flow", "fixable"): gen_data_entry_schema(
|
||||||
|
config=config,
|
||||||
|
integration=integration,
|
||||||
|
flow_title=UNDEFINED,
|
||||||
|
require_step_title=False,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""The tests for the Demo component."""
|
"""The tests for the Demo component."""
|
||||||
|
from http import HTTPStatus
|
||||||
import json
|
import json
|
||||||
from unittest.mock import patch
|
from unittest.mock import ANY, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -69,3 +70,133 @@ async def test_demo_statistics(hass, recorder_mock):
|
||||||
"statistic_id": "demo:energy_consumption",
|
"statistic_id": "demo:energy_consumption",
|
||||||
"unit_of_measurement": "kWh",
|
"unit_of_measurement": "kWh",
|
||||||
} in statistic_ids
|
} in statistic_ids
|
||||||
|
|
||||||
|
|
||||||
|
async def test_issues_created(hass, hass_client, hass_ws_client):
|
||||||
|
"""Test issues are created and can be fixed."""
|
||||||
|
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
await hass.async_start()
|
||||||
|
|
||||||
|
ws_client = await hass_ws_client(hass)
|
||||||
|
client = await hass_client()
|
||||||
|
|
||||||
|
await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
|
||||||
|
msg = await ws_client.receive_json()
|
||||||
|
|
||||||
|
assert msg["success"]
|
||||||
|
assert msg["result"] == {
|
||||||
|
"issues": [
|
||||||
|
{
|
||||||
|
"breaks_in_ha_version": "2023.1.1",
|
||||||
|
"created": ANY,
|
||||||
|
"dismissed_version": None,
|
||||||
|
"domain": "demo",
|
||||||
|
"ignored": False,
|
||||||
|
"is_fixable": False,
|
||||||
|
"issue_id": "transmogrifier_deprecated",
|
||||||
|
"learn_more_url": "https://en.wiktionary.org/wiki/transmogrifier",
|
||||||
|
"severity": "warning",
|
||||||
|
"translation_key": "transmogrifier_deprecated",
|
||||||
|
"translation_placeholders": None,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"breaks_in_ha_version": "2023.1.1",
|
||||||
|
"created": ANY,
|
||||||
|
"dismissed_version": None,
|
||||||
|
"domain": "demo",
|
||||||
|
"ignored": False,
|
||||||
|
"is_fixable": True,
|
||||||
|
"issue_id": "out_of_blinker_fluid",
|
||||||
|
"learn_more_url": "https://www.youtube.com/watch?v=b9rntRxLlbU",
|
||||||
|
"severity": "critical",
|
||||||
|
"translation_key": "out_of_blinker_fluid",
|
||||||
|
"translation_placeholders": None,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"breaks_in_ha_version": None,
|
||||||
|
"created": ANY,
|
||||||
|
"dismissed_version": None,
|
||||||
|
"domain": "demo",
|
||||||
|
"ignored": False,
|
||||||
|
"is_fixable": False,
|
||||||
|
"issue_id": "unfixable_problem",
|
||||||
|
"learn_more_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||||
|
"severity": "warning",
|
||||||
|
"translation_key": "unfixable_problem",
|
||||||
|
"translation_placeholders": None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
url = "/api/repairs/issues/fix"
|
||||||
|
resp = await client.post(
|
||||||
|
url, json={"handler": "demo", "issue_id": "out_of_blinker_fluid"}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert resp.status == HTTPStatus.OK
|
||||||
|
data = await resp.json()
|
||||||
|
|
||||||
|
flow_id = data["flow_id"]
|
||||||
|
assert data == {
|
||||||
|
"data_schema": [],
|
||||||
|
"description_placeholders": None,
|
||||||
|
"errors": None,
|
||||||
|
"flow_id": ANY,
|
||||||
|
"handler": "demo",
|
||||||
|
"last_step": None,
|
||||||
|
"step_id": "confirm",
|
||||||
|
"type": "form",
|
||||||
|
}
|
||||||
|
|
||||||
|
url = f"/api/repairs/issues/fix/{flow_id}"
|
||||||
|
resp = await client.post(url)
|
||||||
|
|
||||||
|
assert resp.status == HTTPStatus.OK
|
||||||
|
data = await resp.json()
|
||||||
|
|
||||||
|
flow_id = data["flow_id"]
|
||||||
|
assert data == {
|
||||||
|
"description": None,
|
||||||
|
"description_placeholders": None,
|
||||||
|
"flow_id": flow_id,
|
||||||
|
"handler": "demo",
|
||||||
|
"title": "Fixed issue",
|
||||||
|
"type": "create_entry",
|
||||||
|
"version": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
await ws_client.send_json({"id": 4, "type": "repairs/list_issues"})
|
||||||
|
msg = await ws_client.receive_json()
|
||||||
|
|
||||||
|
assert msg["success"]
|
||||||
|
assert msg["result"] == {
|
||||||
|
"issues": [
|
||||||
|
{
|
||||||
|
"breaks_in_ha_version": "2023.1.1",
|
||||||
|
"created": ANY,
|
||||||
|
"dismissed_version": None,
|
||||||
|
"domain": "demo",
|
||||||
|
"ignored": False,
|
||||||
|
"is_fixable": False,
|
||||||
|
"issue_id": "transmogrifier_deprecated",
|
||||||
|
"learn_more_url": "https://en.wiktionary.org/wiki/transmogrifier",
|
||||||
|
"severity": "warning",
|
||||||
|
"translation_key": "transmogrifier_deprecated",
|
||||||
|
"translation_placeholders": None,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"breaks_in_ha_version": None,
|
||||||
|
"created": ANY,
|
||||||
|
"dismissed_version": None,
|
||||||
|
"domain": "demo",
|
||||||
|
"ignored": False,
|
||||||
|
"is_fixable": False,
|
||||||
|
"issue_id": "unfixable_problem",
|
||||||
|
"learn_more_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||||
|
"severity": "warning",
|
||||||
|
"translation_key": "unfixable_problem",
|
||||||
|
"translation_placeholders": None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue