From 8769f3b12bfe9fd7e3dfc7d1ff3aa43085e43ff0 Mon Sep 17 00:00:00 2001 From: Home Assistant Version Control Date: Fri, 11 Sep 2026 12:11:18 +0000 Subject: [PATCH] 200 files --- .ha_run.lock | 2 +- .storage/lovelace_resources | 18 +- .../maintenance_supporter/__init__.py | 2 + .../config_flow_options_global.py | 23 + .../maintenance_supporter/coordinator.py | 18 + .../entity/triggers/base_trigger.py | 15 + .../entity/triggers/compound.py | 3 + .../maintenance_supporter/export.py | 2 + .../__tests__/task-detail-renderer.test.ts | 19 +- .../frontend-src/components/confirm-dialog.ts | 18 +- .../frontend-src/components/settings-view.ts | 4 +- .../frontend-src/components/task-dialog.ts | 12 + .../components/vacation-section-card.ts | 4 +- .../frontend-src/locales/cs.json | 9 + .../frontend-src/locales/da.json | 9 + .../frontend-src/locales/de.json | 9 + .../frontend-src/locales/en.json | 9 + .../frontend-src/locales/es.json | 9 + .../frontend-src/locales/fi.json | 9 + .../frontend-src/locales/fr.json | 9 + .../frontend-src/locales/hi.json | 9 + .../frontend-src/locales/hu.json | 9 + .../frontend-src/locales/it.json | 9 + .../frontend-src/locales/ja.json | 9 + .../frontend-src/locales/ko.json | 9 + .../frontend-src/locales/nb.json | 9 + .../frontend-src/locales/nl.json | 9 + .../frontend-src/locales/pl.json | 9 + .../frontend-src/locales/pt-br.json | 9 + .../frontend-src/locales/pt.json | 9 + .../frontend-src/locales/ru.json | 9 + .../frontend-src/locales/sv.json | 9 + .../frontend-src/locales/tr.json | 9 + .../frontend-src/locales/uk.json | 9 + .../frontend-src/locales/zh.json | 9 + .../frontend-src/maintenance-panel.ts | 28 + .../frontend-src/package-lock.json | 6 +- .../frontend-src/renderers/task-detail.ts | 6 + .../frontend-src/styles.ts | 8 + .../frontend-src/types.ts | 4 + .../frontend/locales/cs.json | 9 + .../frontend/locales/da.json | 9 + .../frontend/locales/de.json | 9 + .../frontend/locales/en.json | 9 + .../frontend/locales/es.json | 9 + .../frontend/locales/fi.json | 9 + .../frontend/locales/fr.json | 9 + .../frontend/locales/hi.json | 9 + .../frontend/locales/hu.json | 9 + .../frontend/locales/it.json | 9 + .../frontend/locales/ja.json | 9 + .../frontend/locales/ko.json | 9 + .../frontend/locales/nb.json | 9 + .../frontend/locales/nl.json | 9 + .../frontend/locales/pl.json | 9 + .../frontend/locales/pt-br.json | 9 + .../frontend/locales/pt.json | 9 + .../frontend/locales/ru.json | 9 + .../frontend/locales/sv.json | 9 + .../frontend/locales/tr.json | 9 + .../frontend/locales/uk.json | 9 + .../frontend/locales/zh.json | 9 + .../frontend/maintenance-calendar-card.js | 295 +- .../frontend/maintenance-card.js | 355 +- .../frontend/maintenance-panel.js | 895 ++--- .../frontend/maintenance-strategy-shim.js | 4 +- .../adopt-problem-sensors-dialog-ACK3BLTT.js | 250 -- ... adopt-problem-sensors-dialog-LETFD4EK.js} | 4 +- .../adopt-problem-sensors-dialog-OT2LTUC4.js | 250 -- .../frontend/panel-chunks/chunk-2AIQAMK4.js | 64 - .../{chunk-NAI3MD3R.js => chunk-4OPY4VQ5.js} | 12 +- .../frontend/panel-chunks/chunk-67JPYEU3.js | 1334 -------- .../{chunk-MESNEW3F.js => chunk-6IQODYQV.js} | 4 +- .../frontend/panel-chunks/chunk-7JWYFBIX.js | 79 - .../{chunk-PRQXFMNO.js => chunk-B4ELBSAY.js} | 4 +- .../frontend/panel-chunks/chunk-EMQQ7OLP.js | 2 - .../frontend/panel-chunks/chunk-EOLJHFO4.js | 2 - .../frontend/panel-chunks/chunk-EUJZWPBG.js | 341 -- .../frontend/panel-chunks/chunk-GJI3RTUI.js | 2 - .../frontend/panel-chunks/chunk-GV4G354Y.js | 1349 -------- .../frontend/panel-chunks/chunk-HVJHZKEQ.js | 315 -- .../{chunk-D5BU4RJG.js => chunk-IL2HOGSI.js} | 2 +- .../frontend/panel-chunks/chunk-IOW4PMB5.js | 88 + .../frontend/panel-chunks/chunk-JSPW4Q6Q.js | 2 - .../frontend/panel-chunks/chunk-KIBYSZCP.js | 153 - .../frontend/panel-chunks/chunk-KW56PUC2.js | 2 - .../frontend/panel-chunks/chunk-LCVE5PNR.js | 213 -- .../{chunk-UJ7FC2Z7.js => chunk-NP3X3ILW.js} | 4 +- .../frontend/panel-chunks/chunk-NYOACMQR.js | 2 - .../frontend/panel-chunks/chunk-O5PSKBSH.js | 2 - .../frontend/panel-chunks/chunk-O75IS22I.js | 817 ----- .../frontend/panel-chunks/chunk-OFC6OKGF.js | 79 - .../{chunk-Y2KIPCNO.js => chunk-OI2BG3RF.js} | 21 +- .../frontend/panel-chunks/chunk-PBRIQQ2X.js | 1222 ------- .../{chunk-WVQ3GLZ5.js => chunk-PTYEFLBL.js} | 10 +- .../frontend/panel-chunks/chunk-S2VAROHZ.js | 2 - .../frontend/panel-chunks/chunk-T4NXNE6P.js | 825 ----- .../frontend/panel-chunks/chunk-TNUN2A2H.js | 147 - .../{chunk-7G3267J5.js => chunk-U3UD3G6U.js} | 4 +- .../frontend/panel-chunks/chunk-VLQ4FCHW.js | 64 - .../{chunk-VRRFDTZU.js => chunk-VNJMQWX4.js} | 4 +- .../frontend/panel-chunks/chunk-WQQNFFGB.js | 2 - .../{chunk-YQMBLRSW.js => chunk-WTWETRW4.js} | 4 +- .../{chunk-3IZWSKBJ.js => chunk-XCPYIT7M.js} | 4 +- .../frontend/panel-chunks/chunk-Y2JXJRDF.js | 1222 ------- .../frontend/panel-chunks/chunk-Y7HABQI7.js | 213 -- .../frontend/panel-chunks/chunk-YP2KCO26.js | 2 - .../{chunk-XMX3E3HG.js => chunk-Z4FQHWRJ.js} | 4 +- .../{chunk-BQCLT4RW.js => chunk-ZSJQYRHU.js} | 2 +- .../panel-chunks/complete-dialog-EXSVSS4K.js | 2 - .../panel-chunks/complete-dialog-LDTK7YFG.js | 2 - .../panel-chunks/complete-dialog-N6EFNVQ2.js | 2 + .../panel-chunks/complete-dialog-RFYLAHCN.js | 2 - .../panel-chunks/dialog-mount-63ZHQOD5.js | 2 + .../panel-chunks/dialog-mount-GY4RKNUA.js | 2 - .../panel-chunks/dialog-mount-P3P7TFC2.js | 2 - .../panel-chunks/dialog-mount-ZZSGDAOS.js | 2 - .../panel-chunks/object-dialog-7DRSIILH.js | 2 + .../panel-chunks/object-dialog-C3IWZAA2.js | 2 - .../panel-chunks/object-dialog-CSLODUMN.js | 2 - .../panel-chunks/object-dialog-MSV6DBJW.js | 2 - .../panel-chunks/qr-dialog-GEVAXT3Q.js | 2 - .../panel-chunks/qr-dialog-VLJFNEK6.js | 2 + .../panel-chunks/qr-dialog-W5BRKWLF.js | 2 - .../panel-chunks/qr-dialog-YZHB6ST7.js | 2 - .../panel-chunks/settings-view-HSEAXIMH.js | 1206 ------- ...-TIMAI2CQ.js => settings-view-J5TAOE5R.js} | 34 +- .../panel-chunks/settings-view-RUUW5JZO.js | 1233 ------- .../suggested-setups-dialog-3XJSUYYN.js | 146 - ...js => suggested-setups-dialog-EYSXUVLV.js} | 4 +- .../suggested-setups-dialog-TEISNBAT.js | 146 - .../panel-chunks/task-dialog-4DL25EA3.js | 2 - .../panel-chunks/task-dialog-FOGJHCSB.js | 2 + .../panel-chunks/task-dialog-Q4PWXBS2.js | 2 - .../panel-chunks/task-dialog-UUAB6OPD.js | 2 - .../chunks/budget-section-card-CEY3GOFL.js | 125 - ...YQB.js => budget-section-card-XNGOFRAV.js} | 4 +- .../chunks/budget-section-card-ZS5NH6UV.js | 125 - .../strategy/chunks/chunk-3OUB5IHO.js | 60 - .../strategy/chunks/chunk-5CEYR4C6.js | 1281 ------- .../{chunk-2PETYFO2.js => chunk-CW4GSGTQ.js} | 4 +- .../strategy/chunks/chunk-CWJ56MWO.js | 64 - .../strategy/chunks/chunk-DEN57ILL.js | 2 - .../{chunk-HYTKA5KV.js => chunk-DNYI2KQV.js} | 2 +- .../{chunk-3YPUSKYO.js => chunk-GOJ5CE7B.js} | 2 +- .../strategy/chunks/chunk-KWP6LLK2.js | 64 - .../strategy/chunks/chunk-MKETKKBB.js | 1222 ------- .../strategy/chunks/chunk-NUYQDL2V.js | 1281 +++++++ .../strategy/chunks/chunk-PZLMPK5Y.js | 88 + .../strategy/chunks/chunk-VJ2K4NTW.js | 1222 ------- .../strategy/chunks/chunk-WJSTGOOD.js | 2 - .../strategy/chunks/chunk-WXJEZVBF.js | 60 - .../strategy/chunks/dialog-mount-3UTDIR2B.js | 2895 ---------------- ...t-MDGILK6F.js => dialog-mount-4OVR4WJA.js} | 25 +- .../strategy/chunks/dialog-mount-BLDNA6JI.js | 2950 ----------------- .../chunks/groups-section-card-45HWIJPJ.js | 137 - .../chunks/groups-section-card-QQQDDGNO.js | 137 - ...TRW.js => groups-section-card-X34HJTMC.js} | 4 +- ...O.js => vacation-section-card-2O34KKIU.js} | 10 +- .../chunks/vacation-section-card-EWJTZM6N.js | 134 - .../chunks/vacation-section-card-Z4PS42I4.js | 122 - .../maintenance-dashboard-strategy.js | 6 +- .../helpers/notification_manager.py | 29 +- .../helpers/signatures/kitchen.py | 15 +- .../maintenance_supporter/manifest.json | 2 +- .../maintenance_supporter/storage.py | 6 + .../maintenance_supporter/strings.json | 8 +- .../translations/cs.json | 8 +- .../translations/da.json | 8 +- .../translations/de.json | 8 +- .../translations/en.json | 8 +- .../translations/es.json | 8 +- .../translations/fi.json | 8 +- .../translations/fr.json | 8 +- .../translations/hi.json | 8 +- .../translations/hu.json | 8 +- .../translations/it.json | 8 +- .../translations/ja.json | 8 +- .../translations/ko.json | 8 +- .../translations/nb.json | 8 +- .../translations/nl.json | 8 +- .../translations/pl.json | 8 +- .../translations/pt-BR.json | 8 +- .../translations/pt.json | 8 +- .../translations/ru.json | 8 +- .../translations/sv.json | 8 +- .../translations/tr.json | 8 +- .../translations/uk.json | 8 +- .../translations/zh-Hans.json | 8 +- .../websocket/__init__.py | 4 + .../maintenance_supporter/websocket/io.py | 1 + .../maintenance_supporter/websocket/tasks.py | 2 + .../websocket/tasks_crud.py | 65 + .../websocket/tasks_persist.py | 87 + .../my_music_library/manifest.json | 2 +- .../www/my-music-library-card.js | 493 ++- .../simple-thermostat.debug.js | 1580 ++++++--- .../simple-thermostat.debug.js.gz | Bin 62874 -> 66965 bytes .../simple-thermostat/simple-thermostat.js | 721 ++-- .../simple-thermostat/simple-thermostat.js.gz | Bin 50219 -> 53144 bytes zigbee2mqtt/state.json | 38 +- 201 files changed, 5190 insertions(+), 24141 deletions(-) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/adopt-problem-sensors-dialog-ACK3BLTT.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{adopt-problem-sensors-dialog-2UBTVPAN.js => adopt-problem-sensors-dialog-LETFD4EK.js} (97%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/adopt-problem-sensors-dialog-OT2LTUC4.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-2AIQAMK4.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-NAI3MD3R.js => chunk-4OPY4VQ5.js} (53%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-67JPYEU3.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-MESNEW3F.js => chunk-6IQODYQV.js} (98%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-7JWYFBIX.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-PRQXFMNO.js => chunk-B4ELBSAY.js} (94%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-EMQQ7OLP.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-EOLJHFO4.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-EUJZWPBG.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-GJI3RTUI.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-GV4G354Y.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-HVJHZKEQ.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-D5BU4RJG.js => chunk-IL2HOGSI.js} (95%) create mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-IOW4PMB5.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-JSPW4Q6Q.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-KIBYSZCP.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-KW56PUC2.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-LCVE5PNR.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-UJ7FC2Z7.js => chunk-NP3X3ILW.js} (98%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-NYOACMQR.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-O5PSKBSH.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-O75IS22I.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-OFC6OKGF.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-Y2KIPCNO.js => chunk-OI2BG3RF.js} (93%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-PBRIQQ2X.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-WVQ3GLZ5.js => chunk-PTYEFLBL.js} (98%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-S2VAROHZ.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-T4NXNE6P.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-TNUN2A2H.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-7G3267J5.js => chunk-U3UD3G6U.js} (96%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-VLQ4FCHW.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-VRRFDTZU.js => chunk-VNJMQWX4.js} (99%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-WQQNFFGB.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-YQMBLRSW.js => chunk-WTWETRW4.js} (92%) rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-3IZWSKBJ.js => chunk-XCPYIT7M.js} (96%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-Y2JXJRDF.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-Y7HABQI7.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/chunk-YP2KCO26.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-XMX3E3HG.js => chunk-Z4FQHWRJ.js} (96%) rename custom_components/maintenance_supporter/frontend/panel-chunks/{chunk-BQCLT4RW.js => chunk-ZSJQYRHU.js} (92%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/complete-dialog-EXSVSS4K.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/complete-dialog-LDTK7YFG.js create mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/complete-dialog-N6EFNVQ2.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/complete-dialog-RFYLAHCN.js create mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/dialog-mount-63ZHQOD5.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/dialog-mount-GY4RKNUA.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/dialog-mount-P3P7TFC2.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/dialog-mount-ZZSGDAOS.js create mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/object-dialog-7DRSIILH.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/object-dialog-C3IWZAA2.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/object-dialog-CSLODUMN.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/object-dialog-MSV6DBJW.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/qr-dialog-GEVAXT3Q.js create mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/qr-dialog-VLJFNEK6.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/qr-dialog-W5BRKWLF.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/qr-dialog-YZHB6ST7.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/settings-view-HSEAXIMH.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{settings-view-TIMAI2CQ.js => settings-view-J5TAOE5R.js} (97%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/settings-view-RUUW5JZO.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/suggested-setups-dialog-3XJSUYYN.js rename custom_components/maintenance_supporter/frontend/panel-chunks/{suggested-setups-dialog-G5B2JOOX.js => suggested-setups-dialog-EYSXUVLV.js} (98%) delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/suggested-setups-dialog-TEISNBAT.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/task-dialog-4DL25EA3.js create mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/task-dialog-FOGJHCSB.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/task-dialog-Q4PWXBS2.js delete mode 100644 custom_components/maintenance_supporter/frontend/panel-chunks/task-dialog-UUAB6OPD.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/budget-section-card-CEY3GOFL.js rename custom_components/maintenance_supporter/frontend/strategy/chunks/{budget-section-card-LN7A7YQB.js => budget-section-card-XNGOFRAV.js} (97%) delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/budget-section-card-ZS5NH6UV.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/chunk-3OUB5IHO.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/chunk-5CEYR4C6.js rename custom_components/maintenance_supporter/frontend/strategy/chunks/{chunk-2PETYFO2.js => chunk-CW4GSGTQ.js} (94%) delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/chunk-CWJ56MWO.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/chunk-DEN57ILL.js rename custom_components/maintenance_supporter/frontend/strategy/chunks/{chunk-HYTKA5KV.js => chunk-DNYI2KQV.js} (97%) rename custom_components/maintenance_supporter/frontend/strategy/chunks/{chunk-3YPUSKYO.js => chunk-GOJ5CE7B.js} (94%) delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/chunk-KWP6LLK2.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/chunk-MKETKKBB.js create mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/chunk-NUYQDL2V.js create mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/chunk-PZLMPK5Y.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/chunk-VJ2K4NTW.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/chunk-WJSTGOOD.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/chunk-WXJEZVBF.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/dialog-mount-3UTDIR2B.js rename custom_components/maintenance_supporter/frontend/strategy/chunks/{dialog-mount-MDGILK6F.js => dialog-mount-4OVR4WJA.js} (94%) delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/dialog-mount-BLDNA6JI.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/groups-section-card-45HWIJPJ.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/groups-section-card-QQQDDGNO.js rename custom_components/maintenance_supporter/frontend/strategy/chunks/{groups-section-card-F3GLQTRW.js => groups-section-card-X34HJTMC.js} (97%) rename custom_components/maintenance_supporter/frontend/strategy/chunks/{vacation-section-card-FJ6A6EZO.js => vacation-section-card-2O34KKIU.js} (68%) delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/vacation-section-card-EWJTZM6N.js delete mode 100644 custom_components/maintenance_supporter/frontend/strategy/chunks/vacation-section-card-Z4PS42I4.js diff --git a/.ha_run.lock b/.ha_run.lock index b6e6fbf6..f1a1a7b8 100644 --- a/.ha_run.lock +++ b/.ha_run.lock @@ -1 +1 @@ -{"pid": 71, "version": 1, "ha_version": "2026.9.1", "start_ts": 1788961324.2634702} \ No newline at end of file +{"pid": 71, "version": 1, "ha_version": "2026.9.1", "start_ts": 1789128360.9194858} \ No newline at end of file diff --git a/.storage/lovelace_resources b/.storage/lovelace_resources index b86a3f85..c925d40b 100644 --- a/.storage/lovelace_resources +++ b/.storage/lovelace_resources @@ -261,7 +261,7 @@ }, { "id": "6c3f7d87683d4473b5dc8fe8177535f6", - "url": "/hacsfiles/simple-thermostat/simple-thermostat.js?hacstag=1230152807430", + "url": "/hacsfiles/simple-thermostat/simple-thermostat.js?hacstag=1230152807440", "type": "module" }, { @@ -305,19 +305,19 @@ "type": "module" }, { - "id": "75cbbb4f553146d7b9b35969734b96b8", - "url": "/album_slideshow_static/album-slideshow-card.js?v=1.9.0", + "id": "6f76aeefdbb14d87a0da4c28957efb47", + "url": "/album_slideshow_static/album-slideshow-card.js?v=1.9.1", "type": "module" }, { - "id": "2a737f5a60524eba889646bb76875dbc", - "url": "/my_music_library/my-music-library-card.js?v=3.12.5", - "type": "module" - }, - { - "id": "0dac2fceea134f918b9b93cc064a6199", + "id": "793e9c66f5e349949e23fe3e64088352", "url": "/climate_scheduler/static/climate-scheduler-card.js?v=1.15.1", "type": "module" + }, + { + "id": "aafb0bb764874be384629a0ca0a18c53", + "url": "/my_music_library/my-music-library-card.js?v=3.14.0", + "type": "module" } ] } diff --git a/custom_components/maintenance_supporter/__init__.py b/custom_components/maintenance_supporter/__init__.py index f50052f6..72a7d15c 100644 --- a/custom_components/maintenance_supporter/__init__.py +++ b/custom_components/maintenance_supporter/__init__.py @@ -383,6 +383,8 @@ async def async_maybe_send_lead_reminders(hass: HomeAssistant) -> None: continue if task_data.get("archived_at") is not None: continue + if task_data.get("notify_enabled") is False: + continue # #173: muted task — no lead reminders either task = MaintenanceTask.from_dict(task_data) days = task.days_until_due # days == 0 is a valid lead ("on the due date"); negatives are the diff --git a/custom_components/maintenance_supporter/config_flow_options_global.py b/custom_components/maintenance_supporter/config_flow_options_global.py index a4f77d62..6ce34af4 100644 --- a/custom_components/maintenance_supporter/config_flow_options_global.py +++ b/custom_components/maintenance_supporter/config_flow_options_global.py @@ -43,6 +43,8 @@ from .const import ( CONF_NOTIFICATIONS_ENABLED, CONF_NOTIFY_DUE_SOON_ENABLED, CONF_NOTIFY_DUE_SOON_INTERVAL, + CONF_NOTIFY_EVENT_ONLY, + CONF_NOTIFY_EXTRA_DATA, CONF_NOTIFY_OVERDUE_ENABLED, CONF_NOTIFY_OVERDUE_INTERVAL, CONF_NOTIFY_SERVICE, @@ -61,6 +63,7 @@ from .const import ( DEFAULT_PANEL_ENABLED, DEFAULT_SNOOZE_DURATION_HOURS, DEFAULT_WARNING_DAYS, + MAX_NOTIFY_EXTRA_DATA_LENGTH, MAX_PANEL_TITLE_LENGTH, TIME_HHMMSS_PATTERN, ) @@ -351,6 +354,10 @@ async def send_test_notification( notify_service = str(options.get(CONF_NOTIFY_SERVICE, "")) if not notify_service: + if options.get(CONF_NOTIFY_EVENT_ONLY, False): + # #173: event-only needs no service — the test fires the event + # so the user's automation can be checked from Settings. + return await _send_test_to(hass, options, [""]) return "no_service" # Format-only validation — existence is left to the async_call below so @@ -670,6 +677,10 @@ class GlobalOptionsFlow(OptionsFlow): async def async_step_notification_settings(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult: """Per-status notification toggles, intervals, quiet hours, daily limit.""" if user_input is not None: + # Same cap as the WS settings path (settings registry max_len). + extra = user_input.get(CONF_NOTIFY_EXTRA_DATA) + if isinstance(extra, str): + user_input[CONF_NOTIFY_EXTRA_DATA] = extra[:MAX_NOTIFY_EXTRA_DATA_LENGTH] return self._save_and_return(user_input) current = self._current @@ -770,6 +781,18 @@ class GlobalOptionsFlow(OptionsFlow): translation_key="notification_title_style", ) ), + # 2.80 (#165) / #173: your own notification rule — the same + # two settings the panel's Settings tab offers. + vol.Optional( + CONF_NOTIFY_EVENT_ONLY, + default=current.get(CONF_NOTIFY_EVENT_ONLY, False), + ): selector.BooleanSelector(), + vol.Optional( + CONF_NOTIFY_EXTRA_DATA, + description={"suggested_value": current.get(CONF_NOTIFY_EXTRA_DATA, "")}, + ): selector.TextSelector( + selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT, multiline=True) + ), } ), ) diff --git a/custom_components/maintenance_supporter/coordinator.py b/custom_components/maintenance_supporter/coordinator.py index dde754de..62c2dcf5 100644 --- a/custom_components/maintenance_supporter/coordinator.py +++ b/custom_components/maintenance_supporter/coordinator.py @@ -747,6 +747,11 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]): for row in notifiable if nm._is_status_enabled(row[2]) and not nm._is_snoozed(f"{self.entry.entry_id}_{row[0]}_{row[2]}") ] + # #173: a task muted in its own settings sends nothing — neither on + # its own nor inside a bundle. The flag lives in the task's config + # (entry.data), which the computed task_result (model dict) drops. + task_configs = self.entry.data.get(CONF_TASKS) or {} + notifiable = [row for row in notifiable if (task_configs.get(row[0]) or {}).get("notify_enabled") is not False] # v2.26 notification routing: a saved-view scope ("only notify about # view X") drops tasks the view's label/user filters don't match — @@ -1521,6 +1526,19 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]): ) + def note_trigger_edge(self, task_id: str) -> None: + """A trigger just latched on a REAL state edge — lift the post-completion + cooldown for that task. + + The cooldown (``_recently_completed``, 10 min) exists so the fallback + sweep does not re-activate a task off the still-low sensor value right + after a completion; the event-driven trigger itself is reset on + completion, so a new activation from it is a genuine edge. Without + this, the refresh a flip now requests (#175) — and before that, any + 5-minute tick inside the window — wiped the fresh latch again. + """ + self._recently_completed.pop(task_id, None) + async def async_refresh_now(self) -> None: """Recompute immediately — for changes a person just made. diff --git a/custom_components/maintenance_supporter/entity/triggers/base_trigger.py b/custom_components/maintenance_supporter/entity/triggers/base_trigger.py index ccd90926..badf74b7 100644 --- a/custom_components/maintenance_supporter/entity/triggers/base_trigger.py +++ b/custom_components/maintenance_supporter/entity/triggers/base_trigger.py @@ -220,6 +220,17 @@ class BaseTrigger(ABC): Returns True if trigger should be active. """ + + def _request_coordinator_refresh(self) -> None: + """#175: a trigger flip must reach the coordinator now, not on the + next 5-minute tick. Notifications (and the ``maintenance_supporter_ + notification`` event) are decided in the coordinator's refresh from the + status change, so without this the reminder trailed the flip by up to a + full update interval — 30 s once, 4 min the next time. Debounced on + purpose (HA's ten-second window): a noisy sensor must not recompute the + object on every state change; user actions use async_refresh_now.""" + self.hass.async_create_task(self._coordinator.async_request_refresh()) + def _on_trigger_activated(self, value: float) -> None: """Handle trigger activation.""" _LOGGER.info( @@ -238,6 +249,8 @@ class BaseTrigger(ABC): # Add history entry for the trigger activation self.hass.async_create_task(self._coordinator.async_add_trigger_history_entry(self._task_id, trigger_value=value)) + self._coordinator.note_trigger_edge(self._task_id) + self._request_coordinator_refresh() # Fire event self.hass.bus.async_fire( @@ -267,6 +280,8 @@ class BaseTrigger(ABC): trigger_entity_id=self.entity_id, ) + self._request_coordinator_refresh() + # Fire event self.hass.bus.async_fire( EVENT_TRIGGER_DEACTIVATED, diff --git a/custom_components/maintenance_supporter/entity/triggers/compound.py b/custom_components/maintenance_supporter/entity/triggers/compound.py index 1e4f6cef..4c867db8 100644 --- a/custom_components/maintenance_supporter/entity/triggers/compound.py +++ b/custom_components/maintenance_supporter/entity/triggers/compound.py @@ -248,6 +248,8 @@ class CompoundTrigger(BaseTrigger): trigger_entity_id=None, ) self.hass.async_create_task(self._coordinator.async_add_trigger_history_entry(self._task_id, trigger_value=None)) + self._coordinator.note_trigger_edge(self._task_id) + self._request_coordinator_refresh() self.hass.bus.async_fire( EVENT_TRIGGER_ACTIVATED, { @@ -271,6 +273,7 @@ class CompoundTrigger(BaseTrigger): current_value=None, trigger_entity_id=None, ) + self._request_coordinator_refresh() self.hass.bus.async_fire( EVENT_TRIGGER_DEACTIVATED, { diff --git a/custom_components/maintenance_supporter/export.py b/custom_components/maintenance_supporter/export.py index 81c8f0b7..c1aba9f6 100644 --- a/custom_components/maintenance_supporter/export.py +++ b/custom_components/maintenance_supporter/export.py @@ -126,6 +126,8 @@ def _build_export_object( "require_tag_scan": tdata.get("require_tag_scan"), # #150: per-task skip lock. "allow_skip": tdata.get("allow_skip"), + # #173: per-task notification mute. + "notify_enabled": tdata.get("notify_enabled"), "responsible_user_id": tdata.get("responsible_user_id"), "entity_slug": tdata.get("entity_slug"), "adaptive_config": tdata.get("adaptive_config"), diff --git a/custom_components/maintenance_supporter/frontend-src/__tests__/task-detail-renderer.test.ts b/custom_components/maintenance_supporter/frontend-src/__tests__/task-detail-renderer.test.ts index cc29316c..4043d234 100644 --- a/custom_components/maintenance_supporter/frontend-src/__tests__/task-detail-renderer.test.ts +++ b/custom_components/maintenance_supporter/frontend-src/__tests__/task-detail-renderer.test.ts @@ -186,18 +186,25 @@ describe("task-detail renderer", () => { toggleArchive: () => calls.push("archive"), })); const items = [...host.querySelectorAll(".popup-menu-item")]; - // edit, qr, worksheet, duplicate, reset, postpone, snooze, archive, delete - expect(items.length).to.equal(9); - (items[5] as HTMLElement).click(); // postpone - (items[6] as HTMLElement).click(); // snooze + // edit, qr, worksheet, duplicate, move (#23), reset, postpone, snooze, archive, delete + expect(items.length).to.equal(10); + (items[6] as HTMLElement).click(); // postpone + (items[7] as HTMLElement).click(); // snooze (items[2] as HTMLElement).click(); // work sheet (v2.21) - (items[7] as HTMLElement).click(); // archive (demoted from the header) - (items[8] as HTMLElement).click(); // delete (danger) + (items[8] as HTMLElement).click(); // archive (demoted from the header) + (items[9] as HTMLElement).click(); // delete (danger) expect(calls).to.deep.equal([ "close", "postpone", "close", "snooze", "close", "worksheet", "close", "archive", "close", "delete", ]); }); + it("shows a bell-off badge for a muted task (#173), and none otherwise", () => { + const muted = mount(task({ notify_enabled: false }), ctx()); + expect(muted.querySelector(".muted-badge")).to.exist; + const loud = mount(task(), ctx()); + expect(loud.querySelector(".muted-badge")).to.not.exist; + }); + it("shows a postponed badge when the task has a due_override, and none otherwise", () => { const plain = mount(task(), ctx()); expect(plain.querySelector(".postponed-badge")).to.be.null; diff --git a/custom_components/maintenance_supporter/frontend-src/components/confirm-dialog.ts b/custom_components/maintenance_supporter/frontend-src/components/confirm-dialog.ts index 22b6ff52..452be9ec 100644 --- a/custom_components/maintenance_supporter/frontend-src/components/confirm-dialog.ts +++ b/custom_components/maintenance_supporter/frontend-src/components/confirm-dialog.ts @@ -16,6 +16,8 @@ export interface PromptOptions extends ConfirmOptions { inputLabel?: string; inputType?: string; // "text" | "date" etc. inputValue?: string; + /** Render a (this._inputValue = (e.target as HTMLInputElement).value)} /> + ${this._options + ? html`` + : html` (this._inputValue = (e.target as HTMLInputElement).value)} />`} ` : nothing} diff --git a/custom_components/maintenance_supporter/frontend-src/components/settings-view.ts b/custom_components/maintenance_supporter/frontend-src/components/settings-view.ts index 661ff592..92ec6a93 100644 --- a/custom_components/maintenance_supporter/frontend-src/components/settings-view.ts +++ b/custom_components/maintenance_supporter/frontend-src/components/settings-view.ts @@ -982,7 +982,9 @@ export class MaintenanceSettingsView extends LitElement {
${t("settings_notify_event_only_hint", L)}
${!this._allowSkip ? html`
${t("disallow_skip_help", L)}
` : nothing} + + ${!this._notifyEnabled ? html`
${t("no_notifications_help", L)}
` : nothing}