Updated Scheduler and Maintainance Apps
This commit is contained in:
@@ -180,6 +180,9 @@ def _build_task_summary(
|
||||
# local state for the action fields is empty (writes back null).
|
||||
"on_complete_action": task_data.get("on_complete_action"),
|
||||
"quick_complete_defaults": task_data.get("quick_complete_defaults"),
|
||||
# Per-occurrence postpone: the active override date (or null) so the
|
||||
# panel can badge "postponed to …" and offer to clear it.
|
||||
"due_override": task_data.get("due_override"),
|
||||
# Computed fields from coordinator
|
||||
"status": ct.get("_status", "ok"),
|
||||
"is_done": ct.get("_is_done", False),
|
||||
@@ -439,6 +442,7 @@ def async_register_commands(hass: HomeAssistant) -> None:
|
||||
ws_delete_task,
|
||||
ws_duplicate_task,
|
||||
ws_list_tasks,
|
||||
ws_postpone_task,
|
||||
ws_quick_complete_task,
|
||||
ws_reset_task,
|
||||
ws_skip_task,
|
||||
@@ -481,6 +485,7 @@ def async_register_commands(hass: HomeAssistant) -> None:
|
||||
websocket_api.async_register_command(hass, ws_skip_task)
|
||||
websocket_api.async_register_command(hass, ws_reset_task)
|
||||
websocket_api.async_register_command(hass, ws_snooze_task)
|
||||
websocket_api.async_register_command(hass, ws_postpone_task)
|
||||
websocket_api.async_register_command(hass, ws_update_history_entry)
|
||||
websocket_api.async_register_command(hass, ws_get_templates)
|
||||
websocket_api.async_register_command(hass, ws_export_data)
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -69,6 +69,7 @@ from ..const import (
|
||||
DEFAULT_WARNING_DAYS,
|
||||
DEFAULT_WARRANTY_REMINDER_DAYS,
|
||||
DOMAIN,
|
||||
GLOBAL_UNIQUE_ID,
|
||||
KNOWN_OBJECT_TABLE_COLUMNS,
|
||||
MAX_PANEL_TITLE_LENGTH,
|
||||
MAX_REMINDER_LEADS,
|
||||
@@ -242,9 +243,25 @@ async def ws_get_statistics(
|
||||
# Counts come from the shared aggregator (single source of truth) so the
|
||||
# panel/card chips and the global summary sensors can never diverge.
|
||||
counts = compute_status_counts(hass)
|
||||
|
||||
# (#86) Registry-resolved entity_ids of the four summary sensors. The
|
||||
# dashboard strategy's KPI chips used to hardcode
|
||||
# sensor.maintenance_supporter_<key>, which breaks whenever the actual id
|
||||
# differs (renamed by the user, a _2 collision suffix, or a pre-pinning
|
||||
# install that registered localized ids) — the chips then read "unknown"
|
||||
# forever. unique_ids are stable, so resolve through the registry.
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
ent_reg = er.async_get(hass)
|
||||
summary_entity_ids = {
|
||||
key: ent_reg.async_get_entity_id("sensor", DOMAIN, f"{GLOBAL_UNIQUE_ID}_summary_{key}")
|
||||
for key in ("overdue", "due_soon", "triggered", "ok")
|
||||
}
|
||||
|
||||
connection.send_result(
|
||||
msg["id"],
|
||||
{
|
||||
"summary_entity_ids": summary_entity_ids,
|
||||
"total_objects": counts["total_objects"],
|
||||
"total_tasks": counts["total_tasks"],
|
||||
"overdue": counts["overdue"],
|
||||
|
||||
@@ -374,6 +374,8 @@ async def ws_import_json(
|
||||
"due_date",
|
||||
"interval_anchor",
|
||||
"last_planned_due",
|
||||
# per-occurrence postpone (round-trips like last_planned_due)
|
||||
"due_override",
|
||||
# nested recurrence (calendar kinds) — config-flow normalize
|
||||
# treats it as authoritative when present.
|
||||
"schedule",
|
||||
@@ -388,6 +390,16 @@ async def ws_import_json(
|
||||
"adaptive_config",
|
||||
"checklist",
|
||||
"schedule_time",
|
||||
# v2.17+ / #83 fields — mirror the export builder so a JSON
|
||||
# backup round-trips them (validated/clamped just below).
|
||||
"priority",
|
||||
"labels",
|
||||
"earliest_completion_days",
|
||||
"on_complete_action",
|
||||
"quick_complete_defaults",
|
||||
"assignee_pool",
|
||||
"rotation_strategy",
|
||||
"reading_unit",
|
||||
):
|
||||
val = task_entry.get(key)
|
||||
if val is not None:
|
||||
|
||||
@@ -9,6 +9,7 @@ production modules. ``__all__`` makes the re-exports explicit for mypy --strict.
|
||||
|
||||
from .tasks_actions import (
|
||||
ws_complete_task,
|
||||
ws_postpone_task,
|
||||
ws_quick_complete_task,
|
||||
ws_reset_task,
|
||||
ws_skip_task,
|
||||
@@ -62,6 +63,7 @@ __all__ = [
|
||||
"ws_delete_task",
|
||||
"ws_duplicate_task",
|
||||
"ws_list_tasks",
|
||||
"ws_postpone_task",
|
||||
"ws_quick_complete_task",
|
||||
"ws_reset_task",
|
||||
"ws_skip_task",
|
||||
|
||||
@@ -246,6 +246,43 @@ async def ws_reset_task(
|
||||
connection.send_result(msg["id"], {"success": True})
|
||||
|
||||
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required("type"): "maintenance_supporter/task/postpone",
|
||||
vol.Required("entry_id"): vol.All(str, vol.Length(max=MAX_ID_LENGTH)),
|
||||
vol.Required("task_id"): vol.All(str, vol.Length(max=MAX_ID_LENGTH)),
|
||||
vol.Required("until"): vol.All(str, vol.Length(max=MAX_DATE_LENGTH)),
|
||||
}
|
||||
)
|
||||
@websocket_api.async_response
|
||||
async def ws_postpone_task(
|
||||
hass: HomeAssistant,
|
||||
connection: websocket_api.ActiveConnection,
|
||||
msg: dict[str, Any],
|
||||
) -> None:
|
||||
"""Postpone the current occurrence to a chosen date (per-occurrence defer)."""
|
||||
from datetime import date as date_cls
|
||||
|
||||
rd = _get_runtime_data(hass, msg["entry_id"])
|
||||
if rd is None or rd.coordinator is None:
|
||||
connection.send_error(msg["id"], "not_found", "Coordinator not found")
|
||||
return
|
||||
|
||||
entry = hass.config_entries.async_get_entry(msg["entry_id"])
|
||||
if entry is None or msg["task_id"] not in entry.data.get(CONF_TASKS, {}):
|
||||
connection.send_error(msg["id"], "not_found", "Task not found")
|
||||
return
|
||||
|
||||
try:
|
||||
until = date_cls.fromisoformat(msg["until"])
|
||||
except ValueError:
|
||||
connection.send_error(msg["id"], "invalid_date", "Invalid date format")
|
||||
return
|
||||
|
||||
await rd.coordinator.async_postpone_task(msg["task_id"], until)
|
||||
connection.send_result(msg["id"], {"success": True})
|
||||
|
||||
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required("type"): "maintenance_supporter/task/snooze",
|
||||
|
||||
Reference in New Issue
Block a user