diff --git a/.storage/lovelace_resources b/.storage/lovelace_resources index 09c61c12..b8f57f9b 100644 --- a/.storage/lovelace_resources +++ b/.storage/lovelace_resources @@ -256,7 +256,7 @@ }, { "id": "8713ea9c008e4270bb28085eed5be959", - "url": "/hacsfiles/Statistics-Graph-Chart-Card/statistics-graph-chart-card.js?hacstag=1034932856405", + "url": "/hacsfiles/Statistics-Graph-Chart-Card/statistics-graph-chart-card.js?hacstag=1034932856406", "type": "module" }, { diff --git a/custom_components/maintenance_supporter/__init__.py b/custom_components/maintenance_supporter/__init__.py index 9ae2d46e..5ef9c165 100644 --- a/custom_components/maintenance_supporter/__init__.py +++ b/custom_components/maintenance_supporter/__init__.py @@ -102,6 +102,7 @@ from .frontend import async_register_card from .helpers.aggregate import iter_live_tasks from .helpers.aggregate import object_name as aggregate_object_name from .helpers.aggregate import task_sensor_entity_id as aggregate_task_sensor_entity_id +from .helpers.assignees import person_of_user, shared_user_ids, task_is_for, task_user_ids from .helpers.assist_sentences import async_sync as async_sync_assist_sentences from .helpers.dates import INTERVAL_UNITS, local_date_from_iso from .helpers.documents import DocumentStore @@ -279,6 +280,8 @@ SERVICE_LIST_TASKS_SCHEMA = vol.Schema( { vol.Optional("entry_id"): cv.string, vol.Optional("status"): vol.In(["ok", "due_soon", "overdue", "triggered", "paused"]), + # #210: only the tasks meant for this person (helpers/assignees). + vol.Optional("person"): cv.entity_id, } ) @@ -869,6 +872,7 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool: """Handle list_tasks — a queryable snapshot for automations/voice.""" wanted_entry = call.data.get("entry_id") wanted_status = call.data.get("status") + wanted_user = _resolve_person_user_id(call.data["person"]) if call.data.get("person") else None tasks: list[dict[str, Any]] = [] # The shared cross-object walk (loaded objects, archived tasks left # out) — the Assist snapshot uses the same one (DRY audit 2026-09-26 B). @@ -876,8 +880,11 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool: status = str(task.get("_status", "")) if wanted_status and status != wanted_status: continue + if wanted_user and not task_is_for(task, wanted_user): + continue # #151: last completion + live trigger reading, so # notification automations don't need extra lookups. + responsible = task.get("responsible_user_id") or None lp = task.get("last_performed") days_since: int | None = None if lp: @@ -911,6 +918,13 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool: "trigger_current_delta": task.get("_trigger_current_delta"), "trigger_target": trigger_target, "trigger_unit": trigger_unit, + # #210: who does it, as the user id and as the person + # entity (what update_task takes as responsible_user); + # shared_with is everyone under "Shared with" (on a + # rotation, the people it rotates between). + "responsible_user_id": responsible, + "responsible_user": person_of_user(hass, responsible), + "shared_with": [p for u in shared_user_ids(task) if (p := person_of_user(hass, u))], } ) return {"tasks": tasks, "count": len(tasks)} @@ -1005,7 +1019,7 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool: if nm is not None: cfg_entry = hass.config_entries.async_get_entry(entry_id) task_cfg = ((cfg_entry.data.get(CONF_TASKS) or {}).get(task_id) or {}) if cfg_entry is not None else {} - await nm.async_dismiss_task_notification(task_id, responsible_user_id=task_cfg.get("responsible_user_id")) + await nm.async_dismiss_task_notification(task_id, user_ids=task_user_ids(task_cfg)) nm.clear_task_state(entry_id, task_id) unsub_notification = hass.bus.async_listen("mobile_app_notification_action", _handle_notification_action) diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/cs.json b/custom_components/maintenance_supporter/assist_sentences/responses/cs.json index 93fe595a..3ec2be94 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/cs.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/cs.json @@ -68,6 +68,7 @@ "turn_user": "Teď je na řadě: {user} — '{task}' u zařízení {object}.", "turn_you": "Teď jsi na řadě ty: '{task}' u zařízení {object}.", "turn_nobody": "K úkolu '{task}' u zařízení {object} není nikdo přiřazen.", + "turn_shared": "K úkolu '{task}' u zařízení {object} teď není nikdo přiřazen; je sdílený s: {users}.", "buy_none": "Nic nedochází — není potřeba kupovat díly.", "buy_list": "Docházejí díly, celkem {count}: {items}.", "buy_list_one": "Dochází jeden díl: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/da.json b/custom_components/maintenance_supporter/assist_sentences/responses/da.json index 57c72cc4..3346665f 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/da.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/da.json @@ -68,6 +68,7 @@ "turn_user": "{user} har tur: '{task}' på {object}.", "turn_you": "Det er din tur: '{task}' på {object}.", "turn_nobody": "Ingen er tildelt '{task}' på {object}.", + "turn_shared": "Ingen er tildelt '{task}' på {object} lige nu; den er delt med {users}.", "buy_none": "Intet er ved at slippe op — der skal ikke købes reservedele.", "buy_list": "{count} reservedele er ved at slippe op: {items}.", "buy_list_one": "Én reservedel er ved at slippe op: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/de.json b/custom_components/maintenance_supporter/assist_sentences/responses/de.json index bc4ef0a7..df805f9a 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/de.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/de.json @@ -68,6 +68,7 @@ "turn_user": "{user} ist dran: '{task}' an {object}.", "turn_you": "Du bist dran: '{task}' an {object}.", "turn_nobody": "Für '{task}' an {object} ist niemand eingetragen.", + "turn_shared": "Für '{task}' an {object} ist gerade niemand eingetragen; geteilt mit {users}.", "buy_none": "Nichts wird knapp — es müssen keine Ersatzteile gekauft werden.", "buy_list": "{count} Ersatzteile werden knapp: {items}.", "buy_list_one": "Ein Ersatzteil wird knapp: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/en.json b/custom_components/maintenance_supporter/assist_sentences/responses/en.json index d12de4c0..c4ed01a3 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/en.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/en.json @@ -68,6 +68,7 @@ "turn_user": "It's {user}'s turn: '{task}' on {object}.", "turn_you": "It's your turn: '{task}' on {object}.", "turn_nobody": "Nobody is assigned to '{task}' on {object}.", + "turn_shared": "Nobody is assigned to '{task}' on {object} right now; it is shared with {users}.", "buy_none": "Nothing is running low — no spare parts need buying.", "buy_list": "{count} spare parts are running low: {items}.", "buy_list_one": "One spare part is running low: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/es.json b/custom_components/maintenance_supporter/assist_sentences/responses/es.json index 01360311..3bbc1ba8 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/es.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/es.json @@ -68,6 +68,7 @@ "turn_user": "Le toca a {user}: '{task}' en {object}.", "turn_you": "Te toca a ti: '{task}' en {object}.", "turn_nobody": "Nadie tiene asignada '{task}' en {object}.", + "turn_shared": "Ahora nadie tiene asignada '{task}' en {object}; está compartida con {users}.", "buy_none": "No se está acabando nada: no hay que comprar repuestos.", "buy_list": "Se están acabando {count} repuestos: {items}.", "buy_list_one": "Se está acabando un repuesto: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/fi.json b/custom_components/maintenance_supporter/assist_sentences/responses/fi.json index 78da77d5..812fde7f 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/fi.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/fi.json @@ -68,6 +68,7 @@ "turn_user": "Vuorossa on {user}: '{task}' kohteessa {object}.", "turn_you": "Sinä olet vuorossa: '{task}' kohteessa {object}.", "turn_nobody": "Tehtävälle '{task}' kohteessa {object} ei ole määritetty ketään.", + "turn_shared": "Tehtävälle '{task}' kohteessa {object} ei ole nyt määritetty ketään; se on jaettu: {users}.", "buy_none": "Mikään ei ole loppumassa — varaosia ei tarvitse ostaa.", "buy_list": "Varaosia on loppumassa, yhteensä {count}: {items}.", "buy_list_one": "Yksi varaosa on loppumassa: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/fr.json b/custom_components/maintenance_supporter/assist_sentences/responses/fr.json index 4af90ca6..b89b079e 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/fr.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/fr.json @@ -68,6 +68,7 @@ "turn_user": "C'est au tour de {user} : '{task}' sur {object}.", "turn_you": "C'est ton tour : '{task}' sur {object}.", "turn_nobody": "Personne n'est assigné à '{task}' sur {object}.", + "turn_shared": "Personne n'est assigné à '{task}' sur {object} pour le moment ; la tâche est partagée avec {users}.", "buy_none": "Rien ne manque — aucune pièce à acheter.", "buy_list": "{count} pièces arrivent en rupture : {items}.", "buy_list_one": "Une pièce arrive en rupture : {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/hi.json b/custom_components/maintenance_supporter/assist_sentences/responses/hi.json index 9cc86f11..e2ba6d78 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/hi.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/hi.json @@ -68,6 +68,7 @@ "turn_user": "अभी बारी है: {user} — {object} पर '{task}'।", "turn_you": "अभी आपकी बारी है: {object} पर '{task}'।", "turn_nobody": "{object} पर '{task}' किसी को सौंपा नहीं गया है।", + "turn_shared": "{object} पर '{task}' अभी किसी को सौंपा नहीं गया है; यह इनके साथ साझा है: {users}।", "buy_none": "कुछ भी ख़त्म नहीं हो रहा — कोई स्पेयर पार्ट ख़रीदने की ज़रूरत नहीं है।", "buy_list": "{count} स्पेयर पार्ट ख़त्म होने वाले हैं: {items}।", "buy_list_one": "एक स्पेयर पार्ट ख़त्म होने वाला है: {items}।", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/hu.json b/custom_components/maintenance_supporter/assist_sentences/responses/hu.json index c058abcc..19ea74f8 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/hu.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/hu.json @@ -68,6 +68,7 @@ "turn_user": "Most {user} következik: '{task}' – {object}.", "turn_you": "Most te következel: '{task}' – {object}.", "turn_nobody": "Senki sincs hozzárendelve ehhez: '{task}' – {object}.", + "turn_shared": "Jelenleg senki sincs hozzárendelve ehhez: '{task}' – {object}; megosztva: {users}.", "buy_none": "Semmi sem fogy ki — nem kell alkatrészt venni.", "buy_list": "Kifogyóban lévő alkatrészek, összesen {count}: {items}.", "buy_list_one": "Egy alkatrész fogyóban van: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/it.json b/custom_components/maintenance_supporter/assist_sentences/responses/it.json index 700f0b60..37710921 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/it.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/it.json @@ -68,6 +68,7 @@ "turn_user": "Tocca a {user}: '{task}' su {object}.", "turn_you": "Tocca a te: '{task}' su {object}.", "turn_nobody": "Nessuno è assegnato a '{task}' su {object}.", + "turn_shared": "Al momento nessuno è assegnato a '{task}' su {object}; è condivisa con {users}.", "buy_none": "Non sta finendo niente: non serve comprare ricambi.", "buy_list": "Stanno finendo {count} ricambi: {items}.", "buy_list_one": "Sta finendo un ricambio: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/ja.json b/custom_components/maintenance_supporter/assist_sentences/responses/ja.json index c7ad6f38..fa76879f 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/ja.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/ja.json @@ -68,6 +68,7 @@ "turn_user": "今の担当は{user}です:{object}の「{task}」。", "turn_you": "今の担当はあなたです:{object}の「{task}」。", "turn_nobody": "{object}の「{task}」には担当者がいません。", + "turn_shared": "{object}の「{task}」には今は担当者がいません。共有相手:{users}。", "buy_none": "残り少ないものはありません。交換部品を買う必要はありません。", "buy_list": "残り少ない交換部品が{count}件あります:{items}。", "buy_list_one": "残り少ない交換部品が1件あります:{items}。", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/ko.json b/custom_components/maintenance_supporter/assist_sentences/responses/ko.json index e5382fe0..8a6aa169 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/ko.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/ko.json @@ -68,6 +68,7 @@ "turn_user": "지금 차례: {user} — {object}의 '{task}'.", "turn_you": "지금은 당신 차례예요: {object}의 '{task}'.", "turn_nobody": "{object}의 '{task}' 작업에는 담당자가 없어요.", + "turn_shared": "{object}의 '{task}' 작업에는 지금 담당자가 없어요. 공유 대상: {users}.", "buy_none": "떨어져 가는 게 없어요. 예비 부품을 살 필요가 없어요.", "buy_list": "떨어져 가는 예비 부품이 {count}개 있어요: {items}.", "buy_list_one": "떨어져 가는 예비 부품이 1개 있어요: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/nb.json b/custom_components/maintenance_supporter/assist_sentences/responses/nb.json index 31379c57..e7a90d69 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/nb.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/nb.json @@ -68,6 +68,7 @@ "turn_user": "{user} har tur: '{task}' på {object}.", "turn_you": "Det er din tur: '{task}' på {object}.", "turn_nobody": "Ingen er tildelt '{task}' på {object}.", + "turn_shared": "Ingen er tildelt '{task}' på {object} akkurat nå; den er delt med {users}.", "buy_none": "Ingenting holder på å gå tomt — ingen reservedeler må kjøpes.", "buy_list": "{count} reservedeler holder på å gå tomme: {items}.", "buy_list_one": "Én reservedel holder på å gå tom: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/nl.json b/custom_components/maintenance_supporter/assist_sentences/responses/nl.json index 1fe171b8..72e4b682 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/nl.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/nl.json @@ -68,6 +68,7 @@ "turn_user": "{user} is aan de beurt: '{task}' bij {object}.", "turn_you": "Jij bent aan de beurt: '{task}' bij {object}.", "turn_nobody": "Niemand is toegewezen aan '{task}' bij {object}.", + "turn_shared": "Niemand is op dit moment toegewezen aan '{task}' bij {object}; de taak is gedeeld met {users}.", "buy_none": "Er raakt niets op — er hoeven geen onderdelen gekocht te worden.", "buy_list": "{count} onderdelen raken op: {items}.", "buy_list_one": "Eén onderdeel raakt op: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/pl.json b/custom_components/maintenance_supporter/assist_sentences/responses/pl.json index 476c6d95..3e35629f 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/pl.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/pl.json @@ -68,6 +68,7 @@ "turn_user": "Teraz kolej: {user} — '{task}' na urządzeniu {object}.", "turn_you": "Teraz twoja kolej: '{task}' na urządzeniu {object}.", "turn_nobody": "Nikt nie jest przypisany do zadania '{task}' na urządzeniu {object}.", + "turn_shared": "Nikt nie jest teraz przypisany do zadania '{task}' na urządzeniu {object}; jest udostępnione: {users}.", "buy_none": "Nic się nie kończy — nie trzeba kupować części.", "buy_list": "Kończą się części, łącznie {count}: {items}.", "buy_list_one": "Kończy się jedna część: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/pt-br.json b/custom_components/maintenance_supporter/assist_sentences/responses/pt-br.json index ea031215..457b5984 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/pt-br.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/pt-br.json @@ -68,6 +68,7 @@ "turn_user": "É a vez de {user}: '{task}' em {object}.", "turn_you": "É a sua vez: '{task}' em {object}.", "turn_nobody": "Ninguém está designado para '{task}' em {object}.", + "turn_shared": "Ninguém está designado para '{task}' em {object} no momento; está compartilhada com {users}.", "buy_none": "Nada está acabando — não é preciso comprar peças.", "buy_list": "{count} peças estão acabando: {items}.", "buy_list_one": "Uma peça está acabando: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/pt.json b/custom_components/maintenance_supporter/assist_sentences/responses/pt.json index d4bf7cbe..93dd7eb9 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/pt.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/pt.json @@ -68,6 +68,7 @@ "turn_user": "É a vez de {user}: '{task}' em {object}.", "turn_you": "É a tua vez: '{task}' em {object}.", "turn_nobody": "Ninguém está atribuído a '{task}' em {object}.", + "turn_shared": "Ninguém está atribuído a '{task}' em {object} neste momento; está partilhada com {users}.", "buy_none": "Nada está a acabar — não é preciso comprar peças.", "buy_list": "Estão a acabar {count} peças: {items}.", "buy_list_one": "Está a acabar uma peça: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/ru.json b/custom_components/maintenance_supporter/assist_sentences/responses/ru.json index e8630871..6a340543 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/ru.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/ru.json @@ -68,6 +68,7 @@ "turn_user": "Сейчас очередь: {user} — '{task}' у устройства {object}.", "turn_you": "Сейчас твоя очередь: '{task}' у устройства {object}.", "turn_nobody": "За задачу '{task}' у устройства {object} никто не отвечает.", + "turn_shared": "За задачу '{task}' у устройства {object} сейчас никто не отвечает; она общая для: {users}.", "buy_none": "Ничего не заканчивается — покупать запчасти не нужно.", "buy_list": "Заканчиваются запчасти, всего {count}: {items}.", "buy_list_one": "Заканчивается одна запчасть: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/sv.json b/custom_components/maintenance_supporter/assist_sentences/responses/sv.json index 3bc855bc..b88e39e7 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/sv.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/sv.json @@ -68,6 +68,7 @@ "turn_user": "{user} har turen: '{task}' på {object}.", "turn_you": "Det är din tur: '{task}' på {object}.", "turn_nobody": "Ingen är tilldelad '{task}' på {object}.", + "turn_shared": "Ingen är tilldelad '{task}' på {object} just nu; den delas med {users}.", "buy_none": "Inget håller på att ta slut — inga reservdelar behöver köpas.", "buy_list": "{count} reservdelar håller på att ta slut: {items}.", "buy_list_one": "En reservdel håller på att ta slut: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/tr.json b/custom_components/maintenance_supporter/assist_sentences/responses/tr.json index 39b39389..740e19a8 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/tr.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/tr.json @@ -68,6 +68,7 @@ "turn_user": "Sıradaki kişi: {user} — {object} için '{task}'.", "turn_you": "Sıra sende: {object} için '{task}'.", "turn_nobody": "{object} için '{task}' görevine kimse atanmamış.", + "turn_shared": "{object} için '{task}' görevine şu anda kimse atanmamış; paylaşılanlar: {users}.", "buy_none": "Tükenmek üzere olan bir şey yok — yedek parça almaya gerek yok.", "buy_list": "{count} yedek parça tükenmek üzere: {items}.", "buy_list_one": "Bir yedek parça tükenmek üzere: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/uk.json b/custom_components/maintenance_supporter/assist_sentences/responses/uk.json index 269e4a17..77b4cf55 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/uk.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/uk.json @@ -68,6 +68,7 @@ "turn_user": "Зараз черга: {user} — '{task}' на пристрої {object}.", "turn_you": "Зараз твоя черга: '{task}' на пристрої {object}.", "turn_nobody": "За завдання '{task}' на пристрої {object} ніхто не відповідає.", + "turn_shared": "За завдання '{task}' на пристрої {object} зараз ніхто не відповідає; воно спільне для: {users}.", "buy_none": "Нічого не закінчується — купувати запчастини не потрібно.", "buy_list": "Закінчуються запчастини, усього {count}: {items}.", "buy_list_one": "Закінчується одна запчастина: {items}.", diff --git a/custom_components/maintenance_supporter/assist_sentences/responses/zh.json b/custom_components/maintenance_supporter/assist_sentences/responses/zh.json index 8afbd6df..caaf98fa 100644 --- a/custom_components/maintenance_supporter/assist_sentences/responses/zh.json +++ b/custom_components/maintenance_supporter/assist_sentences/responses/zh.json @@ -68,6 +68,7 @@ "turn_user": "现在轮到{user}:{object}的“{task}”。", "turn_you": "现在轮到你:{object}的“{task}”。", "turn_nobody": "{object}的“{task}”没有指派任何人。", + "turn_shared": "{object}的“{task}”目前没有指派任何人;共享给:{users}。", "buy_none": "没有快用完的东西,不需要买备件。", "buy_list": "有{count}个备件快用完了:{items}。", "buy_list_one": "有1个备件快用完了:{items}。", diff --git a/custom_components/maintenance_supporter/config_flow.py b/custom_components/maintenance_supporter/config_flow.py index e65bd68b..c4ae5a06 100644 --- a/custom_components/maintenance_supporter/config_flow.py +++ b/custom_components/maintenance_supporter/config_flow.py @@ -540,6 +540,10 @@ class MaintenanceSupporterConfigFlow(ScheduleStepsMixin, TriggerConfigMixin, Con stock = praw.get("stock") if isinstance(praw, dict) else None if isinstance(stock, (int, float)) and not isinstance(stock, bool) and stock >= 0: part["stock"] = stock + # #208: and a reusable part's used ones waiting. + waiting = praw.get("restoring") + if part.get("reuse") and isinstance(waiting, (int, float)) and not isinstance(waiting, bool) and waiting > 0: + part["restoring"] = waiting parts[part["id"]] = part data: dict[str, Any] = { diff --git a/custom_components/maintenance_supporter/export.py b/custom_components/maintenance_supporter/export.py index e8572b82..382de771 100644 --- a/custom_components/maintenance_supporter/export.py +++ b/custom_components/maintenance_supporter/export.py @@ -252,9 +252,14 @@ def _build_export_object( "tasks": tasks, "documents": documents, # Spare parts: full static definition + the tracked stock (dynamic, - # read from the Store) so a backup/restore keeps the shelf state. + # read from the Store) so a backup/restore keeps the shelf state — + # with a reusable part's used ones waiting to be ready again (#208). "parts": [ - {**part, "stock": store.get_part_stock(part["id"]) if store is not None else None} + { + **part, + "stock": store.get_part_stock(part["id"]) if store is not None else None, + **({"restoring": store.get_part_restoring(part["id"])} if store is not None and part.get("reuse") else {}), + } for part in (entry.data.get("parts") or {}).values() ], } diff --git a/custom_components/maintenance_supporter/frontend-src/__tests__/documents-section.test.ts b/custom_components/maintenance_supporter/frontend-src/__tests__/documents-section.test.ts index 939a7ab4..952a6c4a 100644 --- a/custom_components/maintenance_supporter/frontend-src/__tests__/documents-section.test.ts +++ b/custom_components/maintenance_supporter/frontend-src/__tests__/documents-section.test.ts @@ -9,6 +9,7 @@ import { expect, fixture, html } from "@open-wc/testing"; import "../components/documents-section.js"; import type { MaintenanceDocumentsSection } from "../components/documents-section"; +import { DOC_MAX_BYTES } from "../helpers/photo-upload.js"; import { createMockHass } from "./_test-utils.js"; const FILE_DOC = { @@ -198,6 +199,62 @@ describe("documents-section", () => { } }); + describe("a refused upload says so and keeps saying it (#209)", () => { + const origFetch = window.fetch; + afterEach(() => { window.fetch = origFetch; }); + const pdf = (name: string, size = 1) => { + const f = new File(["x"], name, { type: "application/pdf" }); + Object.defineProperty(f, "size", { value: size }); + return f; + }; + const upload = async (el: MaintenanceDocumentsSection, files: File[]) => { + (el.hass as unknown as { auth: unknown }).auth = { data: { access_token: "tok" } }; + await (el as unknown as { _uploadFiles: (f: File[]) => Promise })._uploadFiles.call(el, files); + await el.updateComplete; + return el.shadowRoot!.querySelector(".doc-msg.error")?.textContent?.trim() ?? ""; + }; + + it("a 413 is still on the error line after the list reloaded", async () => { + const { el, sent } = await mount(true, [FILE_DOC]); + window.fetch = (async () => new Response("{}", { status: 413 })) as typeof fetch; + const lists = () => sent.filter((m) => m.type === "maintenance_supporter/documents/list").length; + const before = lists(); + const shown = await upload(el, [pdf("hvac.pdf")]); + expect(lists(), "the list reloaded").to.equal(before + 1); + expect(shown).to.equal("hvac.pdf: File is too large (max 100 MB)."); + }); + + it("a file over the limit is refused without being sent", async () => { + const { el } = await mount(true, [FILE_DOC]); + const posted: string[] = []; + window.fetch = (async (_u: string, o: { body: FormData }) => { + posted.push((o.body.get("file") as File).name); + return new Response(JSON.stringify({ id: "n", deduped: false }), { status: 200 }); + }) as unknown as typeof fetch; + const shown = await upload(el, [pdf("manual.pdf", DOC_MAX_BYTES + 1), pdf("invoice.pdf", DOC_MAX_BYTES)]); + expect(posted, "only the file within the limit went up").to.deep.equal(["invoice.pdf"]); + expect(shown).to.equal("manual.pdf: File is too large (max 100 MB)."); + }); + + it("a dropped connection is named per file and the rest still go up", async () => { + const { el } = await mount(true, [FILE_DOC]); + let calls = 0; + window.fetch = (async () => { + if (calls++ === 0) throw new TypeError("Failed to fetch"); + return new Response(JSON.stringify({ id: "n", deduped: false }), { status: 200 }); + }) as typeof fetch; + const shown = await upload(el, [pdf("a.pdf"), pdf("b.pdf")]); + expect(calls).to.equal(2); + expect(shown).to.equal("a.pdf: Upload failed."); + }); + + it("an upload without a refusal leaves no error behind", async () => { + const { el } = await mount(true, [FILE_DOC]); + window.fetch = (async () => new Response(JSON.stringify({ id: "n", deduped: false }), { status: 200 })) as typeof fetch; + expect(await upload(el, [pdf("ok.pdf")])).to.equal(""); + }); + }); + it("opens the file picker via keyboard on the upload label (a11y)", async () => { const { el } = await mount(); const label = [...el.shadowRoot!.querySelectorAll("label.btn")].find( diff --git a/custom_components/maintenance_supporter/frontend-src/components/battery-fleet-section.ts b/custom_components/maintenance_supporter/frontend-src/components/battery-fleet-section.ts index d10937b0..842a0958 100644 --- a/custom_components/maintenance_supporter/frontend-src/components/battery-fleet-section.ts +++ b/custom_components/maintenance_supporter/frontend-src/components/battery-fleet-section.ts @@ -75,6 +75,8 @@ interface Overview { available: boolean; configured: boolean; task_ok?: boolean; + /** The fleet object's entry (its parts are the battery types). */ + entry_id?: string | null; total: number; low: BatteryRow[]; soon: BatteryRow[]; @@ -84,6 +86,9 @@ interface Overview { needs_now: Record; needs_soon: Record; types: string[]; + // #208: the counted rechargeable spares — charged (stock) and waiting to + // be charged (restoring). An older backend omits it. + charging?: { part_id: string; name: string; reuse: string; stock: number; restoring: number }[]; excluded?: { entity_id: string; device_name: string }[]; // #135 follow-up: fleet-wide "track self-charging devices" opt-in. track_self_charging?: boolean; @@ -550,6 +555,34 @@ export class MaintenanceBatteryFleetSection extends LitElement { : nothing} `} + ${ov.charging?.length + ? html` +
+ ${t("battery_fleet_charging", L)} + ${ov.charging.map( + (c) => html` + ${c.name} + ${t("battery_fleet_ready", L).replace("{count}", String(c.stock))} + ${c.restoring > 0 + ? html`${t(`part_waiting_${c.reuse}`, L).replace("{count}", String(c.restoring))} + ${this._canWrite + ? html`` + : nothing}` + : nothing} + `, + )} +
+ ` + : nothing} ${ov.soon.length ? html`
@@ -730,6 +763,46 @@ export class MaintenanceBatteryFleetSection extends LitElement { align-items: baseline; gap: 8px; } + .bf-charging { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + margin: 8px 0; + } + .bf-charge-item { + display: inline-flex; + flex-wrap: wrap; + align-items: center; + gap: 6px; + padding: 2px 8px; + border-radius: 12px; + background: var(--secondary-background-color, #eee); + font-size: 13px; + } + .bf-charge-name { + font-weight: 500; + } + .bf-charge-waiting { + color: var(--warning-color, #f57c00); + } + .bf-charged { + display: inline-flex; + align-items: center; + gap: 4px; + font: inherit; + font-size: 12px; + min-height: 28px; + padding: 2px 10px; + border-radius: 14px; + border: 1px solid var(--primary-color); + background: transparent; + color: var(--primary-color); + cursor: pointer; + } + .bf-charged ha-icon { + --mdc-icon-size: 16px; + } .bf-label { font-size: 12px; text-transform: uppercase; diff --git a/custom_components/maintenance_supporter/frontend-src/components/documents-section.ts b/custom_components/maintenance_supporter/frontend-src/components/documents-section.ts index cccbc78f..8d654f17 100644 --- a/custom_components/maintenance_supporter/frontend-src/components/documents-section.ts +++ b/custom_components/maintenance_supporter/frontend-src/components/documents-section.ts @@ -8,7 +8,7 @@ */ import { LitElement, html, css, nothing } from "lit"; -import { isSafeHttpUrl } from "../helpers/url"; +import { isSafeLink } from "../helpers/url"; import { property, state } from "lit/decorators.js"; import { t, ensureLocale, langOf } from "../styles"; import { runWs } from "../helpers/ws-run"; @@ -230,17 +230,18 @@ export class MaintenanceDocumentsSection extends LitElement { this._hint = ""; let deduped = 0; let dupInObject = 0; + const refused: string[] = []; try { - // Bulk upload: one refused file (too large, rejected) is noted and - // the rest still go up — unlike the photo dialogs, which stop. + // Bulk upload: one refused file (too large, rejected, the connection + // dropped) is noted by name and the rest still go up — unlike the + // photo dialogs, which stop. for (const file of files) { let doc; try { doc = await uploadDocument(this.hass, entryId, file, [cat]); } catch (e) { - const key = e instanceof Error ? e.message : ""; - if (key !== "doc_too_large" && key !== "doc_upload_failed") throw e; - this._error = t(key, this._lang); + const key = e instanceof Error && e.message === "doc_too_large" ? "doc_too_large" : "doc_upload_failed"; + refused.push(`${file.name}: ${t(key, this._lang)}`); continue; } if (doc.duplicate_in_object) dupInObject++; @@ -250,9 +251,10 @@ export class MaintenanceDocumentsSection extends LitElement { if (dupInObject) this._hint = t("doc_dup_in_object", this._lang); else if (deduped) this._hint = t("doc_deduped", this._lang); await this._load(); - } catch { - this._error = t("doc_upload_failed", this._lang); } finally { + // Said AFTER the reload: _load() clears the error line, so a refusal + // set before it flashed for a moment and was gone (#209). + if (refused.length && entryId === this.entryId) this._error = refused.join(" · "); this._busy = false; } } @@ -277,7 +279,7 @@ export class MaintenanceDocumentsSection extends LitElement { if (doc.kind === "file") void this._preview(doc); // Only open http(s) links — never a javascript:/data: URL (the same scheme // guard the rest of the panel applies before opening user-supplied URLs). - else if (isSafeHttpUrl(doc.url)) window.open(doc.url, "_blank", "noopener"); + else if (isSafeLink(doc.url)) window.open(doc.url, "_blank", "noopener"); } private _startEdit(doc: MaintenanceDocument): void { @@ -340,7 +342,7 @@ export class MaintenanceDocumentsSection extends LitElement { this._linkDescription = ""; this._addingLink = false; }, - "doc_link_invalid", + "doc_link_not_allowed", ); } @@ -521,7 +523,7 @@ export class MaintenanceDocumentsSection extends LitElement { ` : html` = []; + const items: Array<[string, string, boolean?]> = []; if (obj.area_id) items.push([t("area", L), obj.area_id]); if (obj.manufacturer) items.push([t("manufacturer", L), obj.manufacturer]); if (obj.model) items.push([t("model", L), obj.model]); if (obj.serial_number) items.push([t("serial_number_label", L), obj.serial_number]); if (obj.installation_date) items.push([t("installed", L), obj.installation_date]); if (obj.warranty_expiry) items.push([t("warranty", L), obj.warranty_expiry]); - if (obj.documentation_url) items.push([t("documentation_url_label", L), obj.documentation_url]); + // The documentation link may also open an app (#207). + if (obj.documentation_url) items.push([t("documentation_url_label", L), obj.documentation_url, isSafeLink(obj.documentation_url)]); if (items.length === 0) return nothing; return html`
${items.map( - ([label, value]) => html` + ([label, value, docLink]) => html`
${label} ${ // Only render http(s) values as links (never javascript:/data:); // value-based so it works in every UI language, not just English. - isSafeHttpUrl(value) + // The documentation link was checked by the app-link rule above. + docLink || isSafeHttpUrl(value) ? html`${value}` : value } diff --git a/custom_components/maintenance_supporter/frontend-src/components/parts-section.ts b/custom_components/maintenance_supporter/frontend-src/components/parts-section.ts index 7d66883d..8af72c5f 100644 --- a/custom_components/maintenance_supporter/frontend-src/components/parts-section.ts +++ b/custom_components/maintenance_supporter/frontend-src/components/parts-section.ts @@ -22,6 +22,9 @@ import { restockUnits, unitPrice } from "../helpers/parts-cost"; // Per-part document links (v2.26) — the task-documents component in part mode. import "./task-documents"; +/** #208: what readies a used part again (helpers/parts.py REUSE_KINDS). */ +export const REUSE_KINDS = ["charge", "sharpen", "clean", "dry", "refill", "restore"] as const; + interface PartForm { id?: string; name: string; @@ -33,6 +36,9 @@ interface PartForm { unit: string; cost: string; stock: string; + /** #208: "" = used up, else what readies a used one again. */ + reuse: string; + restoring: string; reorder_threshold: string; restock_quantity: string; package_size: string; @@ -50,6 +56,8 @@ const EMPTY_FORM: PartForm = { unit: "", cost: "", stock: "", + reuse: "", + restoring: "", reorder_threshold: "", restock_quantity: "", package_size: "", @@ -112,6 +120,8 @@ export class MaintenancePartsSection extends LitElement { unit: part.unit || "", cost: part.cost != null ? String(part.cost) : "", stock: part.stock != null ? String(part.stock) : "", + reuse: part.reuse || "", + restoring: part.restoring ? String(part.restoring) : "", reorder_threshold: part.reorder_threshold != null ? String(part.reorder_threshold) : "", restock_quantity: part.restock_quantity != null ? String(part.restock_quantity) : "", package_size: part.package_size != null ? String(part.package_size) : "", @@ -133,6 +143,8 @@ export class MaintenancePartsSection extends LitElement { unit: f.unit.trim() || null, cost: num(f.cost), stock: num(f.stock), + reuse: f.reuse || null, + ...(f.reuse ? { restoring: num(f.restoring) ?? 0 } : {}), reorder_threshold: num(f.reorder_threshold), restock_quantity: num(f.restock_quantity), package_size: num(f.package_size), @@ -193,6 +205,23 @@ export class MaintenancePartsSection extends LitElement { } } + /** #208: the used ones of a reusable part are ready again (charged, + * sharpened, ...) — back from the pile to the stock. */ + private async _readyAgain(part: MaintenancePart): Promise { + if (this._busy) return; + const result = await this._send<{ stock: number; restoring: number }>({ + type: "maintenance_supporter/part/ready_again", + entry_id: this.entryId, + part_id: part.id, + }); + if (result) { + part.stock = result.stock; + part.restoring = result.restoring; + this.requestUpdate(); + this._notifyChanged(); + } + } + private _identLine(part: MaintenancePart): string { return [part.vendor, part.mpn ? `MPN: ${part.mpn}` : "", part.gtin ? `GTIN: ${part.gtin}` : ""] .filter(Boolean) @@ -220,6 +249,17 @@ export class MaintenancePartsSection extends LitElement { >` : nothing}
+ ${tracked && part.reuse && (part.restoring ?? 0) > 0 + ? html`
+ ${t(`part_waiting_${part.reuse}`, L).replace("{count}", formatNumber(part.restoring!, L))} + ${this.canWrite + ? html`` + : nothing} +
` + : nothing}
${ident ? html`${ident}` : nothing} ${part.storage_location @@ -322,6 +362,23 @@ export class MaintenancePartsSection extends LitElement { ${this._field(t("part_unit", L), "unit")} ${this._field(t("part_cost", L), "cost", { type: "number" })} ${this._field(t("part_stock", L), "stock", { type: "number" })} + + ${f.reuse ? this._field(t("part_restoring", L), "restoring", { type: "number" }) : nothing} + ${f.reuse ? html`
${t("part_reuse_hint", L)}
` : nothing} ${this._field(t("part_reorder_threshold", L), "reorder_threshold", { type: "number" })} ${this._field(t("part_package_size", L), "package_size", { type: "number" })} ${this._field( @@ -477,6 +534,45 @@ export class MaintenancePartsSection extends LitElement { .part-meta .loc ha-icon { --mdc-icon-size: 13px; } + .part-waiting { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 8px; + margin-top: 4px; + } + .waiting-badge { + font-size: 12px; + padding: 1px 8px; + border-radius: 10px; + background: var(--secondary-background-color, #eee); + color: var(--primary-text-color); + } + .ready-again { + display: inline-flex; + align-items: center; + gap: 4px; + font: inherit; + font-size: 12px; + padding: 2px 10px; + min-height: 28px; + border-radius: 14px; + border: 1px solid var(--primary-color); + background: transparent; + color: var(--primary-color); + cursor: pointer; + } + .ready-again ha-icon { + --mdc-icon-size: 16px; + } + .reuse-select { + font: inherit; + padding: 6px; + border-radius: 4px; + border: 1px solid var(--divider-color, #ccc); + background: var(--card-background-color, #fff); + color: var(--primary-text-color); + } .restock-input { width: 64px; padding: 4px; diff --git a/custom_components/maintenance_supporter/frontend-src/components/storage-section-card.ts b/custom_components/maintenance_supporter/frontend-src/components/storage-section-card.ts index f9b9e25b..00e461f4 100644 --- a/custom_components/maintenance_supporter/frontend-src/components/storage-section-card.ts +++ b/custom_components/maintenance_supporter/frontend-src/components/storage-section-card.ts @@ -12,7 +12,7 @@ import { property, state } from "lit/decorators.js"; import { t, ensureLocale, langOf } from "../styles"; import { runWs } from "../helpers/ws-run"; import { openSignedDocument } from "../helpers/document-url"; -import { isSafeHttpUrl } from "../helpers/url"; +import { isSafeLink } from "../helpers/url"; import { formatBytes } from "../helpers/format-bytes"; import type { HomeAssistant } from "../types"; @@ -145,7 +145,7 @@ export class MaintenanceStorageSectionCard extends LitElement { // Defense-in-depth (mirrors task-documents/documents-section): never // hand a non-http(s) weblink to window.open, even though the WS add // path already rejects such schemes. - if (isSafeHttpUrl(doc.url)) window.open(doc.url, "_blank", "noopener"); + if (isSafeLink(doc.url)) window.open(doc.url, "_blank", "noopener"); return; } await runWs(this, () => openSignedDocument(this.hass, doc.id), { onError: (m) => { this._error = m; } }); diff --git a/custom_components/maintenance_supporter/frontend-src/components/task-documents.ts b/custom_components/maintenance_supporter/frontend-src/components/task-documents.ts index 1fc41199..7b1813fa 100644 --- a/custom_components/maintenance_supporter/frontend-src/components/task-documents.ts +++ b/custom_components/maintenance_supporter/frontend-src/components/task-documents.ts @@ -15,7 +15,7 @@ import { t, ensureLocale, langOf } from "../styles"; import { runWs } from "../helpers/ws-run"; import { downloadUrl } from "../helpers/download"; import { downloadSignedDocument, openSignedDocument } from "../helpers/document-url"; -import { isSafeHttpUrl } from "../helpers/url"; +import { isSafeLink } from "../helpers/url"; import { formatBytes } from "../helpers/format-bytes"; import { docCategory, docDisplayName, CATEGORY_ICONS } from "../helpers/document-categories"; import { DOC_FILTER_MIN, filterDocuments } from "../helpers/document-filter"; @@ -152,7 +152,7 @@ export class MaintenanceTaskDocuments extends LitElement { // schemes, but a weblink stored before that check (or via a future // path) must never reach window.open as javascript:/data: — guard the // sink too, like documents-section does. - if (isSafeHttpUrl(doc.url)) window.open(doc.url, "_blank", "noopener"); + if (isSafeLink(doc.url)) window.open(doc.url, "_blank", "noopener"); return; } // A per-task page hint jumps straight to the relevant page via the PDF diff --git a/custom_components/maintenance_supporter/frontend-src/helpers/calendar-bucket.ts b/custom_components/maintenance_supporter/frontend-src/helpers/calendar-bucket.ts index 7210338c..6d8ea52b 100644 --- a/custom_components/maintenance_supporter/frontend-src/helpers/calendar-bucket.ts +++ b/custom_components/maintenance_supporter/frontend-src/helpers/calendar-bucket.ts @@ -18,6 +18,7 @@ import type { HistoryEntry, MaintenanceObjectResponse } from "../types"; import { entrySpend } from "./parts-cost"; import { intervalSpanDays } from "./interval"; import { statusRank } from "../status-constants"; +import { taskIsFor } from "./assignees"; import { addDaysIso, stampDate } from "./ha-time"; export const MAX_OCCURRENCES_PER_TASK = 5; @@ -201,7 +202,8 @@ function projectTask(input: ProjectionInput): CalendarEvent[] { * next_due and the overdue status count from that day, * not from the browser's). * @param windowDays Number of days to include (7 / 14 / 30). - * @param userFilter null/empty = all; otherwise filter tasks by responsible_user_id. + * @param userFilter null/empty = all; otherwise only the tasks meant for that + * user (helpers/assignees: theirs, or shared with nobody on duty). */ export function buildCalendarBuckets( objects: MaintenanceObjectResponse[], @@ -220,7 +222,7 @@ export function buildCalendarBuckets( const tasks = obj.tasks || []; for (const task of tasks) { // User filter - if (userFilter && task.responsible_user_id !== userFilter) continue; + if (userFilter && !taskIsFor(task, userFilter)) continue; // Disabled tasks never produce calendar events if (task.enabled === false) continue; const projected = projectTask({ @@ -368,7 +370,7 @@ export function buildPastBuckets( const entryId = obj.entry_id; const tasks = obj.tasks || []; for (const task of tasks) { - if (userFilter && task.responsible_user_id !== userFilter) continue; + if (userFilter && !taskIsFor(task, userFilter)) continue; const history = fullHistory[pastHistoryKey(entryId, task.id)] ?? ((task.history || []) as HistoryEntryShape[]); for (const h of history) { if (typeof h?.timestamp !== "string") continue; diff --git a/custom_components/maintenance_supporter/frontend-src/helpers/url.ts b/custom_components/maintenance_supporter/frontend-src/helpers/url.ts index ef264365..c3b05512 100644 --- a/custom_components/maintenance_supporter/frontend-src/helpers/url.ts +++ b/custom_components/maintenance_supporter/frontend-src/helpers/url.ts @@ -1,11 +1,62 @@ /** Shared URL-safety guard for rendering user-supplied links. * * A user-entered URL (object/task documentation, spare-part shopping link, - * document weblink) must only ever be linkified when it is an absolute http(s) - * URL — never `javascript:`/`data:`/protocol-relative — else it is a stored-XSS - * vector. The `X && /^https?:\/\//i.test(X)` idiom was inlined at ~8 render - * sites; one forgotten copy is a hole, so it lives here once. + * document weblink) must never be linkified as `javascript:`/`data:`/ + * protocol-relative, else it is a stored-XSS vector. The + * `X && /^https?:\/\//i.test(X)` idiom was inlined at ~8 render sites; one + * forgotten copy is a hole, so it lives here once. + * + * Since #207 a documentation link or a document's web link may also open an + * app (`obsidian://`, `onenote:`, `mailto:`): every scheme passes except the + * blocked ones, the twin of `helpers/url_safety.py` (a tripwire pins the two). */ + +/** Schemes a link may never use: they run code in the page, open the + * device's own files or the browser's internals, or start Windows handlers + * attackers have abused. */ +export const BLOCKED_LINK_SCHEMES: ReadonlySet = new Set([ + "about", + "blob", + "data", + "file", + "filesystem", + "javascript", + "livescript", + "ms-appinstaller", + "ms-cxh", + "ms-cxh-full", + "ms-msdt", + "ms-officecmd", + "search", + "search-ms", + "view-source", + "vbscript", +]); + +/** The link as a browser reads it before looking at the scheme: ASCII tabs + * and newlines anywhere dropped, control characters and spaces at either + * end trimmed ("java\tscript:" is javascript:). */ +export function cleanLink(url: string): string { + // eslint-disable-next-line no-control-regex + return url.replace(/[\t\n\r]/g, "").replace(/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g, ""); +} + +/** The lower-cased scheme of an absolute link, else null. Two characters at + * least: "C:\manual.pdf" is a drive path, not a link. */ +export function linkScheme(url: string | null | undefined): string | null { + const match = /^([a-z][a-z0-9+.-]+):/i.exec(cleanLink(url || "")); + return match ? match[1].toLowerCase() : null; +} + +/** An absolute link safe to open: http(s) or an app link — never one of the + * blocked schemes, never relative. */ +export function isSafeLink(url: string | null | undefined): url is string { + const scheme = linkScheme(url); + return scheme !== null && !BLOCKED_LINK_SCHEMES.has(scheme); +} + +/** Only an absolute http(s) URL — for links that must be web pages (a + * spare part's shop page). */ export function isSafeHttpUrl(url: string | null | undefined): url is string { return !!url && /^https?:\/\//i.test(url); } diff --git a/custom_components/maintenance_supporter/frontend-src/locales/cs.json b/custom_components/maintenance_supporter/frontend-src/locales/cs.json index f454e5f4..8c0365f8 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/cs.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/cs.json @@ -888,7 +888,7 @@ "doc_link_title": "Název (nepovinné)", "doc_open": "Otevřít", "doc_delete_confirm": "Smazat „{name}“?", - "doc_too_large": "Soubor je příliš velký (max. 25 MB).", + "doc_too_large": "Soubor je příliš velký (max. 100 MB).", "doc_upload_failed": "Nahrání selhalo.", "docs_archive_too_large": "Archiv je příliš velký (max. {max}).", "docs_archive_no_manifest": "Tento ZIP neobsahuje manifest.json, takže obnovení neví, ke kterému dokumentu soubor patří. Při opětovném zabalení ponechte manifest.json vedle složek.", @@ -903,7 +903,7 @@ "remove": "Odebrat", "doc_deduped": "Již uloženo jinde — sdíleno, bez dalšího místa.", "doc_dup_in_object": "Tento soubor je již připojen k tomuto objektu.", - "doc_link_invalid": "Povoleny jsou pouze odkazy http/https.", + "doc_link_not_allowed": "Tento odkaz není povolen: odkazy, které spouštějí skripty nebo otevírají místní soubory (javascript:, data:, file: …), jsou odmítnuty.", "doc_cat_manual": "Návod", "doc_cat_warranty": "Záruka", "doc_cat_invoice": "Faktura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Množství k doplnění (balení)", "part_package_hint": "Kupuje se po baleních, spotřebovává po jednotkách: zásoba, spotřeba na úkol a hranice objednání počítají jednotky; množství k doplnění a cena platí za balení.", "part_auto_buy": "Úkol nákupu při nízké zásobě", + "part_reuse": "Po použití", + "part_reuse_none": "Spotřebován", + "part_reuse_charge": "Nabito", + "part_reuse_sharpen": "Nabroušeno", + "part_reuse_clean": "Vyčištěno", + "part_reuse_dry": "Vysušeno", + "part_reuse_refill": "Doplněno", + "part_reuse_restore": "Obnoveno", + "part_waiting_charge": "{count} k nabití", + "part_waiting_sharpen": "{count} k nabroušení", + "part_waiting_clean": "{count} k vyčištění", + "part_waiting_dry": "{count} k vysušení", + "part_waiting_refill": "{count} k doplnění", + "part_waiting_restore": "{count} k obnovení", + "part_restoring": "Použité, zatím nepřipravené", + "part_ready_again_hint": "Všechny použité jsou opět připravené", + "part_reuse_hint": "Použitý kus nezmizí: čeká, až bude znovu připravený, a dál se počítá jako vlastněný, takže se znovu nekupuje.", "part_restock": "Upravit zásobu", "parts_used_by": "Používá", "restock_quantity_label": "Zakoupené množství", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Řadit podle názvu", "battery_fleet_sort_urgency": "Řadit podle naléhavosti", "battery_fleet_mark_recharged": "Označit jako nabitou", + "battery_fleet_charging": "Náhradní akumulátory", + "battery_fleet_ready": "{count} připraveno", "battery_fleet_sparkline_hint": "Stav baterie za posledních 30 dní — tečkovaně: projekce k prahu vybití", "battery_fleet_filter_type": "Zobrazit pouze tento typ baterie", "battery_fleet_record_replacement": "Stav poskočil kolem {date} — zaznamenat tuto výměnu do Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/da.json b/custom_components/maintenance_supporter/frontend-src/locales/da.json index d7fccd5b..7a0b8cf9 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/da.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/da.json @@ -888,7 +888,7 @@ "doc_link_title": "Titel (valgfri)", "doc_open": "Åbn", "doc_delete_confirm": "Slet \"{name}\"?", - "doc_too_large": "Filen er for stor (maks. 25 MB).", + "doc_too_large": "Filen er for stor (maks. 100 MB).", "doc_upload_failed": "Upload mislykkedes.", "docs_archive_too_large": "Arkivet er for stort (maks. {max}).", "docs_archive_no_manifest": "Denne ZIP har ingen manifest.json, så gendannelsen ved ikke, hvilket dokument en fil hører til. Lad manifest.json ligge ved siden af mapperne, når du zipper igen.", @@ -903,7 +903,7 @@ "remove": "Fjern", "doc_deduped": "Allerede gemt et andet sted — delt, ingen ekstra plads.", "doc_dup_in_object": "Denne fil er allerede vedhæftet dette objekt.", - "doc_link_invalid": "Kun http/https-links er tilladt.", + "doc_link_not_allowed": "Dette link er ikke tilladt: links, der kører scripts eller åbner lokale filer (javascript:, data:, file: …), afvises.", "doc_cat_manual": "Vejledning", "doc_cat_warranty": "Garanti", "doc_cat_invoice": "Faktura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Genopfyldningsmængde (pakninger)", "part_package_hint": "Købes i pakninger, bruges i enheden: lager, forbrug pr. opgave og genbestillingsgrænse tæller enheder; genopfyldningsmængde og pris gælder pr. pakning.", "part_auto_buy": "Købsopgave ved lav beholdning", + "part_reuse": "Efter brug", + "part_reuse_none": "Brugt op", + "part_reuse_charge": "Opladet", + "part_reuse_sharpen": "Slebet", + "part_reuse_clean": "Rengjort", + "part_reuse_dry": "Tørret", + "part_reuse_refill": "Genopfyldt", + "part_reuse_restore": "Istandsat", + "part_waiting_charge": "{count} skal oplades", + "part_waiting_sharpen": "{count} skal slibes", + "part_waiting_clean": "{count} skal rengøres", + "part_waiting_dry": "{count} skal tørres", + "part_waiting_refill": "{count} skal genopfyldes", + "part_waiting_restore": "{count} skal istandsættes", + "part_restoring": "Brugte, ikke klar endnu", + "part_ready_again_hint": "Alle brugte er klar igen", + "part_reuse_hint": "En brugt er ikke væk: den venter, til den er klar igen, og tæller stadig som ejet, så den bliver ikke købt igen.", "part_restock": "Justér lager", "parts_used_by": "Bruges af", "restock_quantity_label": "Købt mængde", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sortér efter navn", "battery_fleet_sort_urgency": "Sortér efter hastende grad", "battery_fleet_mark_recharged": "Markér som genopladet", + "battery_fleet_charging": "Genopladelige reserver", + "battery_fleet_ready": "{count} klar", "battery_fleet_sparkline_hint": "Batteriniveau de seneste 30 dage — stiplet: fremskrivning ned til lav-tærsklen", "battery_fleet_filter_type": "Vis kun denne batteritype", "battery_fleet_record_replacement": "Niveauet sprang omkring {date} — registrér denne udskiftning i Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/de.json b/custom_components/maintenance_supporter/frontend-src/locales/de.json index 675d9d0c..3db9c433 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/de.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/de.json @@ -888,7 +888,7 @@ "doc_link_title": "Titel (optional)", "doc_open": "Öffnen", "doc_delete_confirm": "„{name}“ löschen?", - "doc_too_large": "Datei ist zu groß (max. 25 MB).", + "doc_too_large": "Datei ist zu groß (max. 100 MB).", "doc_upload_failed": "Upload fehlgeschlagen.", "docs_archive_too_large": "Das Archiv ist zu groß (max. {max}).", "docs_archive_no_manifest": "Dieses ZIP enthält keine manifest.json, daher weiß die Wiederherstellung nicht, zu welchem Dokument eine Datei gehört. Lass die manifest.json beim erneuten Zippen neben den Ordnern liegen.", @@ -903,7 +903,7 @@ "remove": "Entfernen", "doc_deduped": "Bereits anderswo gespeichert — geteilt, kein zusätzlicher Speicher.", "doc_dup_in_object": "Diese Datei ist bereits an diesem Objekt angehängt.", - "doc_link_invalid": "Nur http/https-Links sind erlaubt.", + "doc_link_not_allowed": "Dieser Link ist nicht erlaubt: Links, die Skripte ausführen oder lokale Dateien öffnen (javascript:, data:, file: …), werden abgelehnt.", "doc_cat_manual": "Anleitung", "doc_cat_warranty": "Garantie", "doc_cat_invoice": "Rechnung", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Nachkaufmenge (Packungen)", "part_package_hint": "Gekauft in Packungen, verbraucht in der Einheit: Bestand, Verbrauch pro Aufgabe und Nachbestellgrenze zählen Einheiten; Nachkaufmenge und Preis gelten pro Packung.", "part_auto_buy": "Kauf-Task bei Niedrigbestand", + "part_reuse": "Nach Gebrauch", + "part_reuse_none": "Verbraucht", + "part_reuse_charge": "Geladen", + "part_reuse_sharpen": "Geschärft", + "part_reuse_clean": "Gereinigt", + "part_reuse_dry": "Getrocknet", + "part_reuse_refill": "Nachgefüllt", + "part_reuse_restore": "Aufbereitet", + "part_waiting_charge": "{count} zu laden", + "part_waiting_sharpen": "{count} zu schärfen", + "part_waiting_clean": "{count} zu reinigen", + "part_waiting_dry": "{count} zu trocknen", + "part_waiting_refill": "{count} nachzufüllen", + "part_waiting_restore": "{count} aufzubereiten", + "part_restoring": "Gebraucht, noch nicht bereit", + "part_ready_again_hint": "Alle gebrauchten sind wieder bereit", + "part_reuse_hint": "Ein gebrauchtes ist nicht weg: Es wartet, bis es wieder bereit ist, und zählt weiter zum Bestand, wird also nicht neu gekauft.", "part_restock": "Bestand anpassen", "parts_used_by": "Verwendet von", "restock_quantity_label": "Gekaufte Menge", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Nach Name sortieren", "battery_fleet_sort_urgency": "Nach Dringlichkeit sortieren", "battery_fleet_mark_recharged": "Als aufgeladen markieren", + "battery_fleet_charging": "Akku-Vorrat", + "battery_fleet_ready": "{count} bereit", "battery_fleet_sparkline_hint": "Batteriestand der letzten 30 Tage — gepunktet: Prognose bis zur Low-Schwelle", "battery_fleet_filter_type": "Nur diesen Batterietyp anzeigen", "battery_fleet_record_replacement": "Der Batteriestand ist um den {date} gesprungen — diesen Wechsel in Battery Notes nachtragen", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/en.json b/custom_components/maintenance_supporter/frontend-src/locales/en.json index 60a4e026..14e58e17 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/en.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/en.json @@ -895,7 +895,7 @@ "doc_link_title": "Title (optional)", "doc_open": "Open", "doc_delete_confirm": "Delete \"{name}\"?", - "doc_too_large": "File is too large (max 25 MB).", + "doc_too_large": "File is too large (max 100 MB).", "doc_upload_failed": "Upload failed.", "docs_archive_too_large": "The archive is too large (max {max}).", "docs_archive_no_manifest": "This ZIP has no manifest.json, so the restore cannot tell which document a file belongs to. Keep manifest.json next to the folders when zipping again.", @@ -910,7 +910,7 @@ "remove": "Remove", "doc_deduped": "Already stored elsewhere — shared, no extra space used.", "doc_dup_in_object": "This file is already attached to this object.", - "doc_link_invalid": "Only http/https links are allowed.", + "doc_link_not_allowed": "This link is not allowed: links that run scripts or open local files (javascript:, data:, file: …) are refused.", "doc_cat_manual": "Manual", "doc_cat_warranty": "Warranty", "doc_cat_invoice": "Invoice", @@ -1085,6 +1085,23 @@ "part_restock_packages": "Restock amount (packages)", "part_package_hint": "Bought in packages, used in the unit: stock, the amount a task uses and the reorder threshold count units; the restock amount and the price are per package.", "part_auto_buy": "Auto-create buy task when low", + "part_reuse": "After use", + "part_reuse_none": "Used up", + "part_reuse_charge": "Charged", + "part_reuse_sharpen": "Sharpened", + "part_reuse_clean": "Cleaned", + "part_reuse_dry": "Dried", + "part_reuse_refill": "Refilled", + "part_reuse_restore": "Restored", + "part_waiting_charge": "{count} to charge", + "part_waiting_sharpen": "{count} to sharpen", + "part_waiting_clean": "{count} to clean", + "part_waiting_dry": "{count} to dry", + "part_waiting_refill": "{count} to refill", + "part_waiting_restore": "{count} to restore", + "part_restoring": "Used, not ready yet", + "part_ready_again_hint": "All used ones are ready again", + "part_reuse_hint": "A used one is not gone: it waits until it is ready again and still counts as owned, so it is not bought again.", "part_restock": "Adjust stock", "parts_used_by": "Used by", "restock_quantity_label": "Quantity bought", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sort by name", "battery_fleet_sort_urgency": "Sort by urgency", "battery_fleet_mark_recharged": "Mark as recharged", + "battery_fleet_charging": "Rechargeable spares", + "battery_fleet_ready": "{count} ready", "battery_fleet_sparkline_hint": "Battery level over the last 30 days — dotted: projected until the low threshold", "battery_fleet_filter_type": "Show only this battery type", "battery_fleet_record_replacement": "The level jumped around {date} — record this replacement in Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/es.json b/custom_components/maintenance_supporter/frontend-src/locales/es.json index e2659163..027410f5 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/es.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/es.json @@ -888,7 +888,7 @@ "doc_link_title": "Título (opcional)", "doc_open": "Abrir", "doc_delete_confirm": "¿Eliminar «{name}»?", - "doc_too_large": "El archivo es demasiado grande (máx. 25 MB).", + "doc_too_large": "El archivo es demasiado grande (máx. 100 MB).", "doc_upload_failed": "Error al subir.", "docs_archive_too_large": "El archivo comprimido es demasiado grande (máx. {max}).", "docs_archive_no_manifest": "Este ZIP no contiene manifest.json, así que la restauración no sabe a qué documento pertenece cada archivo. Deja manifest.json junto a las carpetas al volver a comprimir.", @@ -903,7 +903,7 @@ "remove": "Quitar", "doc_deduped": "Ya almacenado en otro lugar — compartido, sin espacio adicional.", "doc_dup_in_object": "Este archivo ya está adjunto a este objeto.", - "doc_link_invalid": "Solo se permiten enlaces http/https.", + "doc_link_not_allowed": "Este enlace no está permitido: se rechazan los enlaces que ejecutan scripts o abren archivos locales (javascript:, data:, file: …).", "doc_cat_manual": "Manual", "doc_cat_warranty": "Garantía", "doc_cat_invoice": "Factura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Cantidad de reposición (envases)", "part_package_hint": "Se compra por envases y se usa por unidades: el stock, el consumo por tarea y el umbral de pedido cuentan unidades; la cantidad de reposición y el precio son por envase.", "part_auto_buy": "Crear tarea de compra si bajo", + "part_reuse": "Tras el uso", + "part_reuse_none": "Consumido", + "part_reuse_charge": "Recargado", + "part_reuse_sharpen": "Afilado", + "part_reuse_clean": "Limpiado", + "part_reuse_dry": "Secado", + "part_reuse_refill": "Rellenado", + "part_reuse_restore": "Restaurado", + "part_waiting_charge": "{count} por recargar", + "part_waiting_sharpen": "{count} por afilar", + "part_waiting_clean": "{count} por limpiar", + "part_waiting_dry": "{count} por secar", + "part_waiting_refill": "{count} por rellenar", + "part_waiting_restore": "{count} por restaurar", + "part_restoring": "Usados, aún no listos", + "part_ready_again_hint": "Todos los usados vuelven a estar listos", + "part_reuse_hint": "Una pieza usada no se pierde: espera hasta estar lista de nuevo y sigue contando como propia, así que no se vuelve a comprar.", "part_restock": "Ajustar existencias", "parts_used_by": "Usado por", "restock_quantity_label": "Cantidad comprada", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Ordenar por nombre", "battery_fleet_sort_urgency": "Ordenar por urgencia", "battery_fleet_mark_recharged": "Marcar como recargada", + "battery_fleet_charging": "Repuestos recargables", + "battery_fleet_ready": "{count} listas", "battery_fleet_sparkline_hint": "Nivel de batería de los últimos 30 días — punteado: proyección hasta el umbral bajo", "battery_fleet_filter_type": "Mostrar solo este tipo de pila", "battery_fleet_record_replacement": "El nivel dio un salto hacia el {date} — registrar esta sustitución en Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/fi.json b/custom_components/maintenance_supporter/frontend-src/locales/fi.json index 7a3e0dc9..24eec475 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/fi.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/fi.json @@ -888,7 +888,7 @@ "doc_link_title": "Otsikko (valinnainen)", "doc_open": "Avaa", "doc_delete_confirm": "Poistetaanko \"{name}\"?", - "doc_too_large": "Tiedosto on liian suuri (enint. 25 Mt).", + "doc_too_large": "Tiedosto on liian suuri (enint. 100 Mt).", "doc_upload_failed": "Lataus epäonnistui.", "docs_archive_too_large": "Arkisto on liian suuri (enintään {max}).", "docs_archive_no_manifest": "Tässä ZIP-tiedostossa ei ole manifest.json-tiedostoa, joten palautus ei tiedä, mihin asiakirjaan tiedosto kuuluu. Pidä manifest.json kansioiden vieressä, kun pakkaat uudelleen.", @@ -903,7 +903,7 @@ "remove": "Poista", "doc_deduped": "Jo tallennettu muualle — jaettu, ei lisätilaa.", "doc_dup_in_object": "Tämä tiedosto on jo liitetty tähän kohteeseen.", - "doc_link_invalid": "Vain http/https-linkit ovat sallittuja.", + "doc_link_not_allowed": "Tämä linkki ei ole sallittu: linkit, jotka suorittavat skriptejä tai avaavat paikallisia tiedostoja (javascript:, data:, file: …), hylätään.", "doc_cat_manual": "Käyttöohje", "doc_cat_warranty": "Takuu", "doc_cat_invoice": "Lasku", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Täydennysmäärä (pakkausta)", "part_package_hint": "Ostetaan pakkauksina, kulutetaan yksikköinä: varasto, tehtävän kulutus ja tilausraja lasketaan yksikköinä; täydennysmäärä ja hinta ovat pakkauskohtaisia.", "part_auto_buy": "Ostotehtävä kun vähissä", + "part_reuse": "Käytön jälkeen", + "part_reuse_none": "Kulutettu", + "part_reuse_charge": "Ladattu", + "part_reuse_sharpen": "Teroitettu", + "part_reuse_clean": "Puhdistettu", + "part_reuse_dry": "Kuivattu", + "part_reuse_refill": "Täytetty", + "part_reuse_restore": "Kunnostettu", + "part_waiting_charge": "{count} ladattavana", + "part_waiting_sharpen": "{count} teroitettavana", + "part_waiting_clean": "{count} puhdistettavana", + "part_waiting_dry": "{count} kuivattavana", + "part_waiting_refill": "{count} täytettävänä", + "part_waiting_restore": "{count} kunnostettavana", + "part_restoring": "Käytetyt, ei vielä valmiina", + "part_ready_again_hint": "Kaikki käytetyt ovat taas valmiina", + "part_reuse_hint": "Käytetty ei katoa: se odottaa, kunnes se on taas valmiina, ja lasketaan yhä omistetuksi, joten sitä ei osteta uudelleen.", "part_restock": "Muuta varastoa", "parts_used_by": "Käyttäjät", "restock_quantity_label": "Ostettu määrä", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Lajittele nimen mukaan", "battery_fleet_sort_urgency": "Lajittele kiireellisyyden mukaan", "battery_fleet_mark_recharged": "Merkitse ladatuksi", + "battery_fleet_charging": "Ladattavat varaosat", + "battery_fleet_ready": "{count} valmiina", "battery_fleet_sparkline_hint": "Akun varaustaso viimeisten 30 päivän ajalta — pisteviiva: ennuste alarajaan asti", "battery_fleet_filter_type": "Näytä vain tämä paristotyyppi", "battery_fleet_record_replacement": "Varaustaso hyppäsi noin {date} — kirjaa tämä vaihto Battery Notesiin", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/fr.json b/custom_components/maintenance_supporter/frontend-src/locales/fr.json index 0e741a8f..1ed05282 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/fr.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/fr.json @@ -888,7 +888,7 @@ "doc_link_title": "Titre (facultatif)", "doc_open": "Ouvrir", "doc_delete_confirm": "Supprimer « {name} » ?", - "doc_too_large": "Fichier trop volumineux (max. 25 Mo).", + "doc_too_large": "Fichier trop volumineux (max. 100 Mo).", "doc_upload_failed": "Échec du téléversement.", "docs_archive_too_large": "Archive trop volumineuse (max. {max}).", "docs_archive_no_manifest": "Ce ZIP ne contient pas de manifest.json : la restauration ne peut pas savoir à quel document appartient un fichier. Gardez manifest.json à côté des dossiers lorsque vous recompressez.", @@ -903,7 +903,7 @@ "remove": "Retirer", "doc_deduped": "Déjà stocké ailleurs — partagé, aucun espace supplémentaire.", "doc_dup_in_object": "Ce fichier est déjà attaché à cet objet.", - "doc_link_invalid": "Seuls les liens http/https sont autorisés.", + "doc_link_not_allowed": "Ce lien n'est pas autorisé : les liens qui exécutent des scripts ou ouvrent des fichiers locaux (javascript:, data:, file: …) sont refusés.", "doc_cat_manual": "Manuel", "doc_cat_warranty": "Garantie", "doc_cat_invoice": "Facture", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Quantité de réapprovisionnement (conditionnements)", "part_package_hint": "Acheté par conditionnement, utilisé à l'unité : le stock, la quantité utilisée par tâche et le seuil de réapprovisionnement comptent des unités ; la quantité de réapprovisionnement et le prix sont par conditionnement.", "part_auto_buy": "Tâche d'achat auto si bas", + "part_reuse": "Après usage", + "part_reuse_none": "Consommé", + "part_reuse_charge": "Rechargé", + "part_reuse_sharpen": "Affûté", + "part_reuse_clean": "Nettoyé", + "part_reuse_dry": "Séché", + "part_reuse_refill": "Rempli", + "part_reuse_restore": "Remis en état", + "part_waiting_charge": "{count} à recharger", + "part_waiting_sharpen": "{count} à affûter", + "part_waiting_clean": "{count} à nettoyer", + "part_waiting_dry": "{count} à sécher", + "part_waiting_refill": "{count} à remplir", + "part_waiting_restore": "{count} à remettre en état", + "part_restoring": "Utilisés, pas encore prêts", + "part_ready_again_hint": "Tous les usagés sont de nouveau prêts", + "part_reuse_hint": "Un exemplaire utilisé n'est pas perdu : il attend d'être de nouveau prêt et compte toujours comme possédé, il n'est donc pas racheté.", "part_restock": "Ajuster le stock", "parts_used_by": "Utilisé par", "restock_quantity_label": "Quantité achetée", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Trier par nom", "battery_fleet_sort_urgency": "Trier par urgence", "battery_fleet_mark_recharged": "Marquer comme rechargée", + "battery_fleet_charging": "Piles rechargeables de réserve", + "battery_fleet_ready": "{count} prêtes", "battery_fleet_sparkline_hint": "Niveau de batterie des 30 derniers jours — pointillé : projection jusqu'au seuil bas", "battery_fleet_filter_type": "Afficher uniquement ce type de pile", "battery_fleet_record_replacement": "Le niveau a bondi vers le {date} — enregistrer ce remplacement dans Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/hi.json b/custom_components/maintenance_supporter/frontend-src/locales/hi.json index 281d6abd..450bc667 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/hi.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/hi.json @@ -888,7 +888,7 @@ "doc_link_title": "शीर्षक (वैकल्पिक)", "doc_open": "खोलें", "doc_delete_confirm": "\"{name}\" हटाएँ?", - "doc_too_large": "फ़ाइल बहुत बड़ी है (अधिकतम 25 MB)।", + "doc_too_large": "फ़ाइल बहुत बड़ी है (अधिकतम 100 MB)।", "doc_upload_failed": "अपलोड विफल रहा।", "docs_archive_too_large": "आर्काइव बहुत बड़ा है (अधिकतम {max})।", "docs_archive_no_manifest": "इस ZIP में manifest.json नहीं है, इसलिए पुनर्स्थापना यह नहीं जान सकती कि कोई फ़ाइल किस दस्तावेज़ की है। दोबारा ज़िप करते समय manifest.json को फ़ोल्डरों के साथ रखें।", @@ -903,7 +903,7 @@ "remove": "हटाएँ", "doc_deduped": "पहले से कहीं और संग्रहीत — साझा, कोई अतिरिक्त स्थान नहीं।", "doc_dup_in_object": "यह फ़ाइल पहले से इस ऑब्जेक्ट से जुड़ी है।", - "doc_link_invalid": "केवल http/https लिंक की अनुमति है।", + "doc_link_not_allowed": "यह लिंक अनुमत नहीं है: स्क्रिप्ट चलाने वाले या स्थानीय फ़ाइलें खोलने वाले लिंक (javascript:, data:, file: …) अस्वीकार किए जाते हैं।", "doc_cat_manual": "मैनुअल", "doc_cat_warranty": "वारंटी", "doc_cat_invoice": "चालान", @@ -1078,6 +1078,23 @@ "part_restock_packages": "दोबारा भरने की मात्रा (पैकेट)", "part_package_hint": "पैकेट में खरीदा, इकाई में इस्तेमाल: स्टॉक, हर काम की खपत और दोबारा मंगाने की सीमा इकाइयों में गिनी जाती हैं; दोबारा भरने की मात्रा और कीमत प्रति पैकेट हैं।", "part_auto_buy": "कम होने पर खरीद कार्य", + "part_reuse": "उपयोग के बाद", + "part_reuse_none": "खत्म", + "part_reuse_charge": "चार्ज किया गया", + "part_reuse_sharpen": "धार लगाई गई", + "part_reuse_clean": "साफ किया गया", + "part_reuse_dry": "सुखाया गया", + "part_reuse_refill": "फिर से भरा गया", + "part_reuse_restore": "फिर से तैयार", + "part_waiting_charge": "{count} चार्ज करने हैं", + "part_waiting_sharpen": "{count} पर धार लगानी है", + "part_waiting_clean": "{count} साफ करने हैं", + "part_waiting_dry": "{count} सुखाने हैं", + "part_waiting_refill": "{count} फिर से भरने हैं", + "part_waiting_restore": "{count} फिर से तैयार करने हैं", + "part_restoring": "इस्तेमाल हुए, अभी तैयार नहीं", + "part_ready_again_hint": "सभी इस्तेमाल हुए फिर से तैयार हैं", + "part_reuse_hint": "इस्तेमाल किया हुआ खत्म नहीं होता: यह फिर से तैयार होने तक इंतज़ार करता है और आपके पास गिना जाता है, इसलिए दोबारा नहीं खरीदा जाता।", "part_restock": "स्टॉक समायोजित करें", "parts_used_by": "द्वारा उपयोग", "restock_quantity_label": "खरीदी गई मात्रा", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "नाम के अनुसार क्रमबद्ध करें", "battery_fleet_sort_urgency": "तात्कालिकता के अनुसार क्रमबद्ध करें", "battery_fleet_mark_recharged": "रिचार्ज हो गई के रूप में चिह्नित करें", + "battery_fleet_charging": "रिचार्जेबल अतिरिक्त", + "battery_fleet_ready": "{count} तैयार", "battery_fleet_sparkline_hint": "पिछले 30 दिनों का बैटरी स्तर — बिंदीदार: लो थ्रेशोल्ड तक का अनुमान", "battery_fleet_filter_type": "केवल यही बैटरी प्रकार दिखाएँ", "battery_fleet_record_replacement": "स्तर लगभग {date} को उछला — इस बदलाव को Battery Notes में दर्ज करें", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/hu.json b/custom_components/maintenance_supporter/frontend-src/locales/hu.json index 10e6934b..a759175c 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/hu.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/hu.json @@ -895,7 +895,7 @@ "doc_link_title": "Cím (opcionális)", "doc_open": "Megnyitás", "doc_delete_confirm": "Törli a(z) „{name}” elemet?", - "doc_too_large": "A fájl túl nagy (max. 25 MB).", + "doc_too_large": "A fájl túl nagy (max. 100 MB).", "doc_upload_failed": "A feltöltés nem sikerült.", "docs_archive_too_large": "Az archívum túl nagy (max. {max}).", "docs_archive_no_manifest": "Ebben a ZIP-ben nincs manifest.json, ezért a visszaállítás nem tudja, melyik dokumentumhoz tartozik egy fájl. Újratömörítéskor hagyd a manifest.json fájlt a mappák mellett.", @@ -910,7 +910,7 @@ "remove": "Eltávolítás", "doc_deduped": "Már máshol is tárolva — megosztott, nem foglal extra helyet.", "doc_dup_in_object": "Ez a fájl már csatolva van ehhez az objektumhoz.", - "doc_link_invalid": "Csak http/https hivatkozás engedélyezett.", + "doc_link_not_allowed": "Ez a hivatkozás nem engedélyezett: a szkripteket futtató vagy helyi fájlokat megnyitó hivatkozásokat (javascript:, data:, file: …) elutasítjuk.", "doc_cat_manual": "Kézikönyv", "doc_cat_warranty": "Garancia", "doc_cat_invoice": "Számla", @@ -1085,6 +1085,23 @@ "part_restock_packages": "Utántöltési mennyiség (kiszerelés)", "part_package_hint": "Kiszerelésben vásárolva, egységben felhasználva: a készlet, a feladatonkénti fogyás és az újrarendelési küszöb egységet számol; az utántöltési mennyiség és az ár kiszerelésenként értendő.", "part_auto_buy": "Vásárlási feladat automatikus létrehozása, ha kevés van", + "part_reuse": "Használat után", + "part_reuse_none": "Elhasználva", + "part_reuse_charge": "Feltöltve", + "part_reuse_sharpen": "Megélezve", + "part_reuse_clean": "Megtisztítva", + "part_reuse_dry": "Kiszárítva", + "part_reuse_refill": "Utántöltve", + "part_reuse_restore": "Felújítva", + "part_waiting_charge": "{count} töltendő", + "part_waiting_sharpen": "{count} élezendő", + "part_waiting_clean": "{count} tisztítandó", + "part_waiting_dry": "{count} szárítandó", + "part_waiting_refill": "{count} utántöltendő", + "part_waiting_restore": "{count} felújítandó", + "part_restoring": "Használt, még nem kész", + "part_ready_again_hint": "Az összes használt újra kész", + "part_reuse_hint": "A használt darab nem vész el: megvárja, amíg újra kész, és továbbra is a készlethez számít, így nem kell újra megvenni.", "part_restock": "Készlet módosítása", "parts_used_by": "Használja", "restock_quantity_label": "Vásárolt mennyiség", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Rendezés név szerint", "battery_fleet_sort_urgency": "Rendezés sürgősség szerint", "battery_fleet_mark_recharged": "Megjelölés feltöltöttként", + "battery_fleet_charging": "Tartalék akkuk", + "battery_fleet_ready": "{count} kész", "battery_fleet_sparkline_hint": "Akkumulátorszint az elmúlt 30 napban — pontozott: előrejelzés az alacsony küszöbig", "battery_fleet_filter_type": "Csak ez az elemtípus megjelenítése", "battery_fleet_record_replacement": "A szint {date} körül megugrott — rögzítse ezt a cserét a Battery Notes-ban", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/it.json b/custom_components/maintenance_supporter/frontend-src/locales/it.json index b973aaf9..e138ef8c 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/it.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/it.json @@ -888,7 +888,7 @@ "doc_link_title": "Titolo (facoltativo)", "doc_open": "Apri", "doc_delete_confirm": "Eliminare «{name}»?", - "doc_too_large": "File troppo grande (max 25 MB).", + "doc_too_large": "File troppo grande (max 100 MB).", "doc_upload_failed": "Caricamento non riuscito.", "docs_archive_too_large": "L'archivio è troppo grande (max {max}).", "docs_archive_no_manifest": "Questo ZIP non contiene manifest.json, quindi il ripristino non sa a quale documento appartiene un file. Lascia manifest.json accanto alle cartelle quando lo comprimi di nuovo.", @@ -903,7 +903,7 @@ "remove": "Rimuovi", "doc_deduped": "Già archiviato altrove — condiviso, nessuno spazio aggiuntivo.", "doc_dup_in_object": "Questo file è già allegato a questo oggetto.", - "doc_link_invalid": "Sono consentiti solo link http/https.", + "doc_link_not_allowed": "Questo link non è consentito: i link che eseguono script o aprono file locali (javascript:, data:, file: …) vengono rifiutati.", "doc_cat_manual": "Manuale", "doc_cat_warranty": "Garanzia", "doc_cat_invoice": "Fattura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Quantità di riordino (confezioni)", "part_package_hint": "Acquistato a confezioni, usato a unità: scorte, consumo per attività e soglia di riordino contano unità; quantità di riordino e prezzo sono per confezione.", "part_auto_buy": "Task d'acquisto se scarso", + "part_reuse": "Dopo l'uso", + "part_reuse_none": "Consumato", + "part_reuse_charge": "Ricaricato", + "part_reuse_sharpen": "Affilato", + "part_reuse_clean": "Pulito", + "part_reuse_dry": "Asciugato", + "part_reuse_refill": "Riempito", + "part_reuse_restore": "Ripristinato", + "part_waiting_charge": "{count} da ricaricare", + "part_waiting_sharpen": "{count} da affilare", + "part_waiting_clean": "{count} da pulire", + "part_waiting_dry": "{count} da asciugare", + "part_waiting_refill": "{count} da riempire", + "part_waiting_restore": "{count} da ripristinare", + "part_restoring": "Usati, non ancora pronti", + "part_ready_again_hint": "Tutti quelli usati sono di nuovo pronti", + "part_reuse_hint": "Un pezzo usato non è perso: aspetta di essere di nuovo pronto e conta ancora come posseduto, quindi non viene ricomprato.", "part_restock": "Correggi scorta", "parts_used_by": "Usato da", "restock_quantity_label": "Quantità acquistata", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Ordina per nome", "battery_fleet_sort_urgency": "Ordina per urgenza", "battery_fleet_mark_recharged": "Segna come ricaricata", + "battery_fleet_charging": "Ricambi ricaricabili", + "battery_fleet_ready": "{count} pronte", "battery_fleet_sparkline_hint": "Livello batteria degli ultimi 30 giorni — tratteggiato: proiezione fino alla soglia di batteria scarica", "battery_fleet_filter_type": "Mostra solo questo tipo di batteria", "battery_fleet_record_replacement": "Il livello è balzato intorno al {date} — registra questa sostituzione in Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/ja.json b/custom_components/maintenance_supporter/frontend-src/locales/ja.json index 4ea5d375..189950ec 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/ja.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/ja.json @@ -888,7 +888,7 @@ "doc_link_title": "タイトル(任意)", "doc_open": "開く", "doc_delete_confirm": "「{name}」を削除しますか?", - "doc_too_large": "ファイルが大きすぎます(最大 25 MB)。", + "doc_too_large": "ファイルが大きすぎます(最大 100 MB)。", "doc_upload_failed": "アップロードに失敗しました。", "docs_archive_too_large": "アーカイブが大きすぎます(最大 {max})。", "docs_archive_no_manifest": "この ZIP には manifest.json がないため、復元時にファイルがどのドキュメントのものか判断できません。再度圧縮するときは manifest.json をフォルダーと同じ場所に置いてください。", @@ -903,7 +903,7 @@ "remove": "削除", "doc_deduped": "既に別の場所に保存済み — 共有され、追加容量はかかりません。", "doc_dup_in_object": "このファイルは既にこのオブジェクトに添付されています。", - "doc_link_invalid": "http/https のリンクのみ許可されています。", + "doc_link_not_allowed": "このリンクは使用できません。スクリプトを実行したりローカルファイルを開いたりするリンク(javascript:、data:、file: …)は拒否されます。", "doc_cat_manual": "取扱説明書", "doc_cat_warranty": "保証書", "doc_cat_invoice": "請求書", @@ -1078,6 +1078,23 @@ "part_restock_packages": "補充数(包装単位)", "part_package_hint": "包装単位で購入し、単位で使います。在庫、タスクごとの使用量、発注しきい値は単位で数え、補充数と価格は包装単位です。", "part_auto_buy": "在庫少で購入タスク", + "part_reuse": "使用後", + "part_reuse_none": "使い切り", + "part_reuse_charge": "充電済み", + "part_reuse_sharpen": "研ぎ済み", + "part_reuse_clean": "清掃済み", + "part_reuse_dry": "乾燥済み", + "part_reuse_refill": "補充済み", + "part_reuse_restore": "再生済み", + "part_waiting_charge": "充電待ち {count}", + "part_waiting_sharpen": "研ぎ待ち {count}", + "part_waiting_clean": "清掃待ち {count}", + "part_waiting_dry": "乾燥待ち {count}", + "part_waiting_refill": "補充待ち {count}", + "part_waiting_restore": "再生待ち {count}", + "part_restoring": "使用済み・未準備", + "part_ready_again_hint": "使用済みのものがすべて再び使えます", + "part_reuse_hint": "使用済みのものはなくなりません。再び使えるようになるまで待機し、所有数に含まれるため、買い直しは不要です。", "part_restock": "在庫を調整", "parts_used_by": "使用タスク", "restock_quantity_label": "購入数量", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "名前順に並べ替え", "battery_fleet_sort_urgency": "緊急度順に並べ替え", "battery_fleet_mark_recharged": "充電済みにする", + "battery_fleet_charging": "予備の充電池", + "battery_fleet_ready": "準備済み {count}", "battery_fleet_sparkline_hint": "過去30日間のバッテリー残量——点線:低残量しきい値までの予測", "battery_fleet_filter_type": "この電池タイプのみ表示", "battery_fleet_record_replacement": "{date}頃に残量が急上昇——この交換をBattery Notesに記録する", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/ko.json b/custom_components/maintenance_supporter/frontend-src/locales/ko.json index 6a3d4669..055e116b 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/ko.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/ko.json @@ -895,7 +895,7 @@ "doc_link_title": "제목 (선택)", "doc_open": "열기", "doc_delete_confirm": "\"{name}\"을(를) 삭제할까요?", - "doc_too_large": "파일이 너무 큽니다 (최대 25 MB).", + "doc_too_large": "파일이 너무 큽니다 (최대 100 MB).", "doc_upload_failed": "업로드에 실패했습니다.", "docs_archive_too_large": "아카이브가 너무 큽니다(최대 {max}).", "docs_archive_no_manifest": "이 ZIP에는 manifest.json이 없어 복원 시 파일이 어느 문서에 속하는지 알 수 없습니다. 다시 압축할 때 manifest.json을 폴더 옆에 두세요.", @@ -910,7 +910,7 @@ "remove": "제거", "doc_deduped": "이미 다른 곳에 저장됨 — 공유되어 추가 공간을 쓰지 않습니다.", "doc_dup_in_object": "이 파일은 이미 이 객체에 첨부되어 있습니다.", - "doc_link_invalid": "http/https 링크만 허용됩니다.", + "doc_link_not_allowed": "이 링크는 허용되지 않습니다. 스크립트를 실행하거나 로컬 파일을 여는 링크(javascript:, data:, file: …)는 거부됩니다.", "doc_cat_manual": "설명서", "doc_cat_warranty": "보증서", "doc_cat_invoice": "영수증", @@ -1085,6 +1085,23 @@ "part_restock_packages": "보충 수량(포장)", "part_package_hint": "포장 단위로 사고 단위로 씁니다. 재고, 작업당 사용량, 재주문 기준은 단위로 세고, 보충 수량과 가격은 포장 기준입니다.", "part_auto_buy": "재고 부족 시 구매 작업 자동 생성", + "part_reuse": "사용 후", + "part_reuse_none": "소모됨", + "part_reuse_charge": "충전됨", + "part_reuse_sharpen": "연마됨", + "part_reuse_clean": "세척됨", + "part_reuse_dry": "건조됨", + "part_reuse_refill": "리필됨", + "part_reuse_restore": "복원됨", + "part_waiting_charge": "충전 대기 {count}", + "part_waiting_sharpen": "연마 대기 {count}", + "part_waiting_clean": "세척 대기 {count}", + "part_waiting_dry": "건조 대기 {count}", + "part_waiting_refill": "리필 대기 {count}", + "part_waiting_restore": "복원 대기 {count}", + "part_restoring": "사용됨, 아직 준비 안 됨", + "part_ready_again_hint": "사용한 것이 모두 다시 준비됨", + "part_reuse_hint": "사용한 것은 없어지지 않습니다. 다시 준비될 때까지 대기하며 보유 수량에 계속 포함되므로 다시 구매하지 않습니다.", "part_restock": "재고 조정", "parts_used_by": "사용처", "restock_quantity_label": "구매 수량", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "이름순 정렬", "battery_fleet_sort_urgency": "긴급도순 정렬", "battery_fleet_mark_recharged": "충전 완료로 표시", + "battery_fleet_charging": "예비 충전지", + "battery_fleet_ready": "준비됨 {count}", "battery_fleet_sparkline_hint": "지난 30일간의 배터리 잔량 — 점선: 낮음 임계값까지의 예측", "battery_fleet_filter_type": "이 배터리 유형만 표시", "battery_fleet_record_replacement": "{date}쯤 잔량이 급상승했습니다 — 이 교체를 Battery Notes에 기록", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/nb.json b/custom_components/maintenance_supporter/frontend-src/locales/nb.json index 77b795bd..0812410d 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/nb.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/nb.json @@ -888,7 +888,7 @@ "doc_link_title": "Tittel (valgfritt)", "doc_open": "Åpne", "doc_delete_confirm": "Slette \"{name}\"?", - "doc_too_large": "Filen er for stor (maks. 25 MB).", + "doc_too_large": "Filen er for stor (maks. 100 MB).", "doc_upload_failed": "Opplasting mislyktes.", "docs_archive_too_large": "Arkivet er for stort (maks. {max}).", "docs_archive_no_manifest": "Denne ZIP-filen har ingen manifest.json, så gjenopprettingen vet ikke hvilket dokument en fil hører til. La manifest.json ligge ved siden av mappene når du zipper på nytt.", @@ -903,7 +903,7 @@ "remove": "Fjern", "doc_deduped": "Allerede lagret et annet sted — delt, ingen ekstra plass.", "doc_dup_in_object": "Denne filen er allerede knyttet til dette objektet.", - "doc_link_invalid": "Kun http/https-lenker er tillatt.", + "doc_link_not_allowed": "Denne lenken er ikke tillatt: lenker som kjører skript eller åpner lokale filer (javascript:, data:, file: …), avvises.", "doc_cat_manual": "Bruksanvisning", "doc_cat_warranty": "Garanti", "doc_cat_invoice": "Faktura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Påfyllingsmengde (pakninger)", "part_package_hint": "Kjøpes i pakninger, brukes i enheten: lager, forbruk per oppgave og bestillingsgrense teller enheter; påfyllingsmengde og pris gjelder per pakning.", "part_auto_buy": "Kjøpsoppgave ved lavt lager", + "part_reuse": "Etter bruk", + "part_reuse_none": "Brukt opp", + "part_reuse_charge": "Ladet", + "part_reuse_sharpen": "Slipt", + "part_reuse_clean": "Rengjort", + "part_reuse_dry": "Tørket", + "part_reuse_refill": "Etterfylt", + "part_reuse_restore": "Satt i stand", + "part_waiting_charge": "{count} skal lades", + "part_waiting_sharpen": "{count} skal slipes", + "part_waiting_clean": "{count} skal rengjøres", + "part_waiting_dry": "{count} skal tørkes", + "part_waiting_refill": "{count} skal etterfylles", + "part_waiting_restore": "{count} skal settes i stand", + "part_restoring": "Brukte, ikke klare ennå", + "part_ready_again_hint": "Alle brukte er klare igjen", + "part_reuse_hint": "En brukt er ikke borte: den venter til den er klar igjen og teller fortsatt som eid, så den kjøpes ikke på nytt.", "part_restock": "Juster lager", "parts_used_by": "Brukes av", "restock_quantity_label": "Kjøpt mengde", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sorter etter navn", "battery_fleet_sort_urgency": "Sorter etter hastegrad", "battery_fleet_mark_recharged": "Merk som oppladet", + "battery_fleet_charging": "Oppladbare reserver", + "battery_fleet_ready": "{count} klare", "battery_fleet_sparkline_hint": "Batterinivå de siste 30 dagene — stiplet: fremskrevet ned til lavnivåterskelen", "battery_fleet_filter_type": "Vis bare denne batteritypen", "battery_fleet_record_replacement": "Nivået hoppet rundt {date} — registrer dette byttet i Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/nl.json b/custom_components/maintenance_supporter/frontend-src/locales/nl.json index 58ccf04c..9d6188e5 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/nl.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/nl.json @@ -888,7 +888,7 @@ "doc_link_title": "Titel (optioneel)", "doc_open": "Openen", "doc_delete_confirm": "\"{name}\" verwijderen?", - "doc_too_large": "Bestand is te groot (max. 25 MB).", + "doc_too_large": "Bestand is te groot (max. 100 MB).", "doc_upload_failed": "Uploaden mislukt.", "docs_archive_too_large": "Het archief is te groot (max. {max}).", "docs_archive_no_manifest": "Deze ZIP bevat geen manifest.json, dus het herstel weet niet bij welk document een bestand hoort. Laat manifest.json naast de mappen staan als je opnieuw zipt.", @@ -903,7 +903,7 @@ "remove": "Weghalen", "doc_deduped": "Al elders opgeslagen — gedeeld, geen extra ruimte.", "doc_dup_in_object": "Dit bestand is al aan dit object gekoppeld.", - "doc_link_invalid": "Alleen http/https-links zijn toegestaan.", + "doc_link_not_allowed": "Deze link is niet toegestaan: links die scripts uitvoeren of lokale bestanden openen (javascript:, data:, file: …) worden geweigerd.", "doc_cat_manual": "Handleiding", "doc_cat_warranty": "Garantie", "doc_cat_invoice": "Factuur", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Bijvulhoeveelheid (verpakkingen)", "part_package_hint": "Gekocht per verpakking, gebruikt per eenheid: voorraad, verbruik per taak en bestelgrens tellen eenheden; bijvulhoeveelheid en prijs gelden per verpakking.", "part_auto_buy": "Kooptaak bij lage voorraad", + "part_reuse": "Na gebruik", + "part_reuse_none": "Verbruikt", + "part_reuse_charge": "Opgeladen", + "part_reuse_sharpen": "Geslepen", + "part_reuse_clean": "Gereinigd", + "part_reuse_dry": "Gedroogd", + "part_reuse_refill": "Bijgevuld", + "part_reuse_restore": "Opgeknapt", + "part_waiting_charge": "{count} op te laden", + "part_waiting_sharpen": "{count} te slijpen", + "part_waiting_clean": "{count} te reinigen", + "part_waiting_dry": "{count} te drogen", + "part_waiting_refill": "{count} bij te vullen", + "part_waiting_restore": "{count} op te knappen", + "part_restoring": "Gebruikt, nog niet klaar", + "part_ready_again_hint": "Alle gebruikte zijn weer klaar", + "part_reuse_hint": "Een gebruikt exemplaar is niet weg: het wacht tot het weer klaar is en telt nog mee als bezit, dus het wordt niet opnieuw gekocht.", "part_restock": "Voorraad aanpassen", "parts_used_by": "Gebruikt door", "restock_quantity_label": "Gekochte hoeveelheid", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sorteren op naam", "battery_fleet_sort_urgency": "Sorteren op urgentie", "battery_fleet_mark_recharged": "Markeren als opgeladen", + "battery_fleet_charging": "Oplaadbare reserves", + "battery_fleet_ready": "{count} klaar", "battery_fleet_sparkline_hint": "Batterijniveau van de afgelopen 30 dagen — gestippeld: prognose tot de lage drempel", "battery_fleet_filter_type": "Alleen dit batterijtype tonen", "battery_fleet_record_replacement": "Het niveau maakte rond {date} een sprong — deze vervanging vastleggen in Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/pl.json b/custom_components/maintenance_supporter/frontend-src/locales/pl.json index 6a003bc6..8cc593a9 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/pl.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/pl.json @@ -888,7 +888,7 @@ "doc_link_title": "Tytuł (opcjonalnie)", "doc_open": "Otwórz", "doc_delete_confirm": "Usunąć „{name}”?", - "doc_too_large": "Plik jest za duży (maks. 25 MB).", + "doc_too_large": "Plik jest za duży (maks. 100 MB).", "doc_upload_failed": "Przesyłanie nie powiodło się.", "docs_archive_too_large": "Archiwum jest za duże (maks. {max}).", "docs_archive_no_manifest": "Ten ZIP nie zawiera pliku manifest.json, więc przywracanie nie wie, do którego dokumentu należy plik. Przy ponownym pakowaniu zostaw manifest.json obok folderów.", @@ -903,7 +903,7 @@ "remove": "Usuń", "doc_deduped": "Już zapisany gdzie indziej — współdzielony, bez dodatkowego miejsca.", "doc_dup_in_object": "Ten plik jest już dołączony do tego obiektu.", - "doc_link_invalid": "Dozwolone są tylko linki http/https.", + "doc_link_not_allowed": "Ten link jest niedozwolony: linki uruchamiające skrypty lub otwierające pliki lokalne (javascript:, data:, file: …) są odrzucane.", "doc_cat_manual": "Instrukcja", "doc_cat_warranty": "Gwarancja", "doc_cat_invoice": "Faktura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Ilość uzupełnienia (opakowania)", "part_package_hint": "Kupowane w opakowaniach, zużywane w jednostkach: stan, zużycie na zadanie i próg zamówienia liczą jednostki; ilość uzupełnienia i cena dotyczą opakowania.", "part_auto_buy": "Zadanie zakupu przy niskim stanie", + "part_reuse": "Po użyciu", + "part_reuse_none": "Zużyty", + "part_reuse_charge": "Naładowany", + "part_reuse_sharpen": "Naostrzony", + "part_reuse_clean": "Wyczyszczony", + "part_reuse_dry": "Wysuszony", + "part_reuse_refill": "Napełniony", + "part_reuse_restore": "Odnowiony", + "part_waiting_charge": "{count} do naładowania", + "part_waiting_sharpen": "{count} do naostrzenia", + "part_waiting_clean": "{count} do wyczyszczenia", + "part_waiting_dry": "{count} do wysuszenia", + "part_waiting_refill": "{count} do napełnienia", + "part_waiting_restore": "{count} do odnowienia", + "part_restoring": "Zużyte, jeszcze niegotowe", + "part_ready_again_hint": "Wszystkie zużyte są znów gotowe", + "part_reuse_hint": "Zużyta część nie przepada: czeka, aż znów będzie gotowa, i nadal liczy się jako posiadana, więc nie kupuje się jej ponownie.", "part_restock": "Koryguj stan", "parts_used_by": "Używane przez", "restock_quantity_label": "Kupiona ilość", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sortuj według nazwy", "battery_fleet_sort_urgency": "Sortuj według pilności", "battery_fleet_mark_recharged": "Oznacz jako naładowaną", + "battery_fleet_charging": "Zapasowe akumulatorki", + "battery_fleet_ready": "{count} gotowe", "battery_fleet_sparkline_hint": "Poziom baterii z ostatnich 30 dni — kropkowana linia: prognoza do progu niskiego poziomu", "battery_fleet_filter_type": "Pokaż tylko ten typ baterii", "battery_fleet_record_replacement": "Poziom skoczył około {date} — zapisz tę wymianę w Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/pt-br.json b/custom_components/maintenance_supporter/frontend-src/locales/pt-br.json index 858cfb39..40644d8a 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/pt-br.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/pt-br.json @@ -895,7 +895,7 @@ "doc_link_title": "Título (opcional)", "doc_open": "Abrir", "doc_delete_confirm": "Excluir \"{name}\"?", - "doc_too_large": "O arquivo é muito grande (máx. 25 MB).", + "doc_too_large": "O arquivo é muito grande (máx. 100 MB).", "doc_upload_failed": "Falha no envio.", "docs_archive_too_large": "O arquivo é grande demais (máx. {max}).", "docs_archive_no_manifest": "Este ZIP não tem manifest.json, então a restauração não sabe a qual documento cada arquivo pertence. Mantenha o manifest.json junto às pastas ao compactar de novo.", @@ -910,7 +910,7 @@ "remove": "Remover", "doc_deduped": "Já armazenado em outro lugar — compartilhado, sem uso de espaço extra.", "doc_dup_in_object": "Este arquivo já está anexado a este objeto.", - "doc_link_invalid": "Apenas links http/https são permitidos.", + "doc_link_not_allowed": "Este link não é permitido: links que executam scripts ou abrem arquivos locais (javascript:, data:, file: …) são recusados.", "doc_cat_manual": "Manual", "doc_cat_warranty": "Garantia", "doc_cat_invoice": "Nota fiscal", @@ -1085,6 +1085,23 @@ "part_restock_packages": "Quantidade de reposição (embalagens)", "part_package_hint": "Comprado em embalagens, usado por unidade: estoque, consumo por tarefa e limite de reposição contam unidades; quantidade de reposição e preço são por embalagem.", "part_auto_buy": "Criar tarefa de compra automaticamente quando estiver baixo", + "part_reuse": "Após o uso", + "part_reuse_none": "Consumido", + "part_reuse_charge": "Carregado", + "part_reuse_sharpen": "Afiado", + "part_reuse_clean": "Limpo", + "part_reuse_dry": "Seco", + "part_reuse_refill": "Reabastecido", + "part_reuse_restore": "Restaurado", + "part_waiting_charge": "{count} para carregar", + "part_waiting_sharpen": "{count} para afiar", + "part_waiting_clean": "{count} para limpar", + "part_waiting_dry": "{count} para secar", + "part_waiting_refill": "{count} para reabastecer", + "part_waiting_restore": "{count} para restaurar", + "part_restoring": "Usados, ainda não prontos", + "part_ready_again_hint": "Todos os usados estão prontos de novo", + "part_reuse_hint": "Uma peça usada não se perde: aguarda até ficar pronta de novo e continua contando como sua, então não é comprada de novo.", "part_restock": "Ajustar estoque", "parts_used_by": "Usado por", "restock_quantity_label": "Quantidade comprada", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Ordenar por nome", "battery_fleet_sort_urgency": "Ordenar por urgência", "battery_fleet_mark_recharged": "Marcar como recarregada", + "battery_fleet_charging": "Reservas recarregáveis", + "battery_fleet_ready": "{count} prontas", "battery_fleet_sparkline_hint": "Nível da bateria dos últimos 30 dias — pontilhado: projeção até o limite baixo", "battery_fleet_filter_type": "Mostrar apenas este tipo de pilha", "battery_fleet_record_replacement": "O nível deu um salto por volta de {date} — registrar esta substituição no Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/pt.json b/custom_components/maintenance_supporter/frontend-src/locales/pt.json index ceed3852..ba450d3c 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/pt.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/pt.json @@ -888,7 +888,7 @@ "doc_link_title": "Título (opcional)", "doc_open": "Abrir", "doc_delete_confirm": "Eliminar «{name}»?", - "doc_too_large": "Ficheiro demasiado grande (máx. 25 MB).", + "doc_too_large": "Ficheiro demasiado grande (máx. 100 MB).", "doc_upload_failed": "Falha no carregamento.", "docs_archive_too_large": "O arquivo é demasiado grande (máx. {max}).", "docs_archive_no_manifest": "Este ZIP não contém manifest.json, pelo que o restauro não sabe a que documento pertence cada ficheiro. Mantenha o manifest.json junto às pastas ao comprimir novamente.", @@ -903,7 +903,7 @@ "remove": "Remover", "doc_deduped": "Já armazenado noutro local — partilhado, sem espaço extra.", "doc_dup_in_object": "Este ficheiro já está anexado a este objeto.", - "doc_link_invalid": "Apenas ligações http/https são permitidas.", + "doc_link_not_allowed": "Esta ligação não é permitida: ligações que executam scripts ou abrem ficheiros locais (javascript:, data:, file: …) são recusadas.", "doc_cat_manual": "Manual", "doc_cat_warranty": "Garantia", "doc_cat_invoice": "Fatura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Quantidade de reposição (embalagens)", "part_package_hint": "Comprado em embalagens, usado à unidade: o stock, o consumo por tarefa e o limite de encomenda contam unidades; a quantidade de reposição e o preço são por embalagem.", "part_auto_buy": "Tarefa de compra se baixo", + "part_reuse": "Após o uso", + "part_reuse_none": "Consumido", + "part_reuse_charge": "Carregado", + "part_reuse_sharpen": "Afiado", + "part_reuse_clean": "Limpo", + "part_reuse_dry": "Seco", + "part_reuse_refill": "Reabastecido", + "part_reuse_restore": "Restaurado", + "part_waiting_charge": "{count} por carregar", + "part_waiting_sharpen": "{count} por afiar", + "part_waiting_clean": "{count} por limpar", + "part_waiting_dry": "{count} por secar", + "part_waiting_refill": "{count} por reabastecer", + "part_waiting_restore": "{count} por restaurar", + "part_restoring": "Usados, ainda não prontos", + "part_ready_again_hint": "Todos os usados estão prontos de novo", + "part_reuse_hint": "Uma peça usada não se perde: aguarda até estar pronta de novo e continua a contar como sua, por isso não volta a ser comprada.", "part_restock": "Ajustar estoque", "parts_used_by": "Usado por", "restock_quantity_label": "Quantidade comprada", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Ordenar por nome", "battery_fleet_sort_urgency": "Ordenar por urgência", "battery_fleet_mark_recharged": "Marcar como recarregada", + "battery_fleet_charging": "Sobressalentes recarregáveis", + "battery_fleet_ready": "{count} prontas", "battery_fleet_sparkline_hint": "Nível da bateria dos últimos 30 dias — pontilhado: projeção até ao limiar baixo", "battery_fleet_filter_type": "Mostrar apenas este tipo de pilha", "battery_fleet_record_replacement": "O nível deu um salto por volta de {date} — registar esta substituição no Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/ru.json b/custom_components/maintenance_supporter/frontend-src/locales/ru.json index fd4d3ca0..ee380d4e 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/ru.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/ru.json @@ -888,7 +888,7 @@ "doc_link_title": "Название (необязательно)", "doc_open": "Открыть", "doc_delete_confirm": "Удалить «{name}»?", - "doc_too_large": "Файл слишком большой (макс. 25 МБ).", + "doc_too_large": "Файл слишком большой (макс. 100 МБ).", "doc_upload_failed": "Не удалось загрузить.", "docs_archive_too_large": "Архив слишком большой (макс. {max}).", "docs_archive_no_manifest": "В этом ZIP нет manifest.json, поэтому при восстановлении неизвестно, к какому документу относится файл. При повторной упаковке оставляйте manifest.json рядом с папками.", @@ -903,7 +903,7 @@ "remove": "Убрать", "doc_deduped": "Уже сохранён в другом месте — общий, без доп. места.", "doc_dup_in_object": "Этот файл уже прикреплён к этому объекту.", - "doc_link_invalid": "Разрешены только ссылки http/https.", + "doc_link_not_allowed": "Эта ссылка не разрешена: ссылки, которые запускают скрипты или открывают локальные файлы (javascript:, data:, file: …), отклоняются.", "doc_cat_manual": "Инструкция", "doc_cat_warranty": "Гарантия", "doc_cat_invoice": "Счёт", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Количество для пополнения (упаковок)", "part_package_hint": "Покупается упаковками, расходуется единицами: запас, расход на задачу и порог дозаказа считаются в единицах; количество для пополнения и цена — за упаковку.", "part_auto_buy": "Задача покупки при малом запасе", + "part_reuse": "После использования", + "part_reuse_none": "Израсходован", + "part_reuse_charge": "Заряжен", + "part_reuse_sharpen": "Заточен", + "part_reuse_clean": "Очищен", + "part_reuse_dry": "Высушен", + "part_reuse_refill": "Заправлен", + "part_reuse_restore": "Восстановлен", + "part_waiting_charge": "{count} на зарядку", + "part_waiting_sharpen": "{count} на заточку", + "part_waiting_clean": "{count} на очистку", + "part_waiting_dry": "{count} на сушку", + "part_waiting_refill": "{count} на заправку", + "part_waiting_restore": "{count} на восстановление", + "part_restoring": "Использованы, ещё не готовы", + "part_ready_again_hint": "Все использованные снова готовы", + "part_reuse_hint": "Использованная деталь не пропадает: она ждёт, пока снова будет готова, и по-прежнему считается в наличии, поэтому её не покупают заново.", "part_restock": "Изменить запас", "parts_used_by": "Используется", "restock_quantity_label": "Куплено, шт.", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Сортировать по имени", "battery_fleet_sort_urgency": "Сортировать по срочности", "battery_fleet_mark_recharged": "Отметить как заряженную", + "battery_fleet_charging": "Запасные аккумуляторы", + "battery_fleet_ready": "{count} готово", "battery_fleet_sparkline_hint": "Уровень заряда за последние 30 дней — пунктир: прогноз до порога разряда", "battery_fleet_filter_type": "Показать только этот тип батарей", "battery_fleet_record_replacement": "Уровень резко вырос примерно {date} — записать эту замену в Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/sv.json b/custom_components/maintenance_supporter/frontend-src/locales/sv.json index 8cd11e51..de74e3ac 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/sv.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/sv.json @@ -888,7 +888,7 @@ "doc_link_title": "Titel (valfritt)", "doc_open": "Öppna", "doc_delete_confirm": "Ta bort \"{name}\"?", - "doc_too_large": "Filen är för stor (max 25 MB).", + "doc_too_large": "Filen är för stor (max 100 MB).", "doc_upload_failed": "Uppladdningen misslyckades.", "docs_archive_too_large": "Arkivet är för stort (max {max}).", "docs_archive_no_manifest": "Den här ZIP-filen saknar manifest.json, så återställningen vet inte vilket dokument en fil hör till. Låt manifest.json ligga bredvid mapparna när du zippar igen.", @@ -903,7 +903,7 @@ "remove": "Ta bort", "doc_deduped": "Redan lagrad någon annanstans — delad, inget extra utrymme.", "doc_dup_in_object": "Den här filen är redan kopplad till detta objekt.", - "doc_link_invalid": "Endast http/https-länkar tillåts.", + "doc_link_not_allowed": "Den här länken är inte tillåten: länkar som kör skript eller öppnar lokala filer (javascript:, data:, file: …) avvisas.", "doc_cat_manual": "Manual", "doc_cat_warranty": "Garanti", "doc_cat_invoice": "Faktura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Påfyllningsmängd (förpackningar)", "part_package_hint": "Köps i förpackningar, används i enheten: lager, åtgång per uppgift och beställningsgräns räknar enheter; påfyllningsmängd och pris gäller per förpackning.", "part_auto_buy": "Köpuppgift vid lågt lager", + "part_reuse": "Efter användning", + "part_reuse_none": "Förbrukad", + "part_reuse_charge": "Laddad", + "part_reuse_sharpen": "Slipad", + "part_reuse_clean": "Rengjord", + "part_reuse_dry": "Torkad", + "part_reuse_refill": "Påfylld", + "part_reuse_restore": "Återställd", + "part_waiting_charge": "{count} att ladda", + "part_waiting_sharpen": "{count} att slipa", + "part_waiting_clean": "{count} att rengöra", + "part_waiting_dry": "{count} att torka", + "part_waiting_refill": "{count} att fylla på", + "part_waiting_restore": "{count} att återställa", + "part_restoring": "Använda, inte klara än", + "part_ready_again_hint": "Alla använda är klara igen", + "part_reuse_hint": "En använd är inte borta: den väntar tills den är klar igen och räknas fortfarande som ägd, så den köps inte igen.", "part_restock": "Justera lager", "parts_used_by": "Används av", "restock_quantity_label": "Köpt antal", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sortera efter namn", "battery_fleet_sort_urgency": "Sortera efter angelägenhet", "battery_fleet_mark_recharged": "Markera som uppladdad", + "battery_fleet_charging": "Laddbara reserver", + "battery_fleet_ready": "{count} klara", "battery_fleet_sparkline_hint": "Batterinivå de senaste 30 dagarna — prickad: prognos ner till lågnivåtröskeln", "battery_fleet_filter_type": "Visa endast denna batterityp", "battery_fleet_record_replacement": "Nivån hoppade omkring {date} — registrera detta byte i Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/tr.json b/custom_components/maintenance_supporter/frontend-src/locales/tr.json index b6194e71..ab761230 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/tr.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/tr.json @@ -895,7 +895,7 @@ "doc_link_title": "Başlık (isteğe bağlı)", "doc_open": "Aç", "doc_delete_confirm": "\"{name}\" silinsin mi?", - "doc_too_large": "Dosya çok büyük (en fazla 25 MB).", + "doc_too_large": "Dosya çok büyük (en fazla 100 MB).", "doc_upload_failed": "Yükleme başarısız oldu.", "docs_archive_too_large": "Arşiv çok büyük (en fazla {max}).", "docs_archive_no_manifest": "Bu ZIP'te manifest.json yok, bu yüzden geri yükleme bir dosyanın hangi belgeye ait olduğunu bilemez. Yeniden sıkıştırırken manifest.json dosyasını klasörlerin yanında tutun.", @@ -910,7 +910,7 @@ "remove": "Kaldır", "doc_deduped": "Zaten başka bir yerde saklı — paylaşıldı, ek alan kullanılmadı.", "doc_dup_in_object": "Bu dosya zaten bu nesneye ekli.", - "doc_link_invalid": "Yalnızca http/https bağlantılarına izin verilir.", + "doc_link_not_allowed": "Bu bağlantıya izin verilmiyor: betik çalıştıran veya yerel dosyaları açan bağlantılar (javascript:, data:, file: …) reddedilir.", "doc_cat_manual": "Kılavuz", "doc_cat_warranty": "Garanti", "doc_cat_invoice": "Fatura", @@ -1085,6 +1085,23 @@ "part_restock_packages": "Yeniden stok miktarı (paket)", "part_package_hint": "Paketle alınır, birimle kullanılır: stok, görev başına kullanım ve yeniden sipariş eşiği birim sayar; yeniden stok miktarı ve fiyat paket başınadır.", "part_auto_buy": "Azaldığında otomatik satın alma görevi oluştur", + "part_reuse": "Kullanımdan sonra", + "part_reuse_none": "Tükendi", + "part_reuse_charge": "Şarj edildi", + "part_reuse_sharpen": "Bilendi", + "part_reuse_clean": "Temizlendi", + "part_reuse_dry": "Kurutuldu", + "part_reuse_refill": "Yeniden dolduruldu", + "part_reuse_restore": "Yenilendi", + "part_waiting_charge": "{count} şarj edilecek", + "part_waiting_sharpen": "{count} bilenecek", + "part_waiting_clean": "{count} temizlenecek", + "part_waiting_dry": "{count} kurutulacak", + "part_waiting_refill": "{count} doldurulacak", + "part_waiting_restore": "{count} yenilenecek", + "part_restoring": "Kullanılmış, henüz hazır değil", + "part_ready_again_hint": "Kullanılanların hepsi yeniden hazır", + "part_reuse_hint": "Kullanılan parça kaybolmaz: yeniden hazır olana kadar bekler ve hâlâ sahip olunan sayılır, bu yüzden yeniden satın alınmaz.", "part_restock": "Stoku ayarla", "parts_used_by": "Kullanan", "restock_quantity_label": "Satın alınan miktar", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Ada göre sırala", "battery_fleet_sort_urgency": "Aciliyete göre sırala", "battery_fleet_mark_recharged": "Şarj edildi olarak işaretle", + "battery_fleet_charging": "Yedek şarjlı piller", + "battery_fleet_ready": "{count} hazır", "battery_fleet_sparkline_hint": "Son 30 günün pil seviyesi — noktalı: düşük eşiğe kadar projeksiyon", "battery_fleet_filter_type": "Yalnızca bu pil türünü göster", "battery_fleet_record_replacement": "Seviye {date} civarında sıçradı — bu değişimi Battery Notes'a kaydet", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/uk.json b/custom_components/maintenance_supporter/frontend-src/locales/uk.json index 4d36319a..687df054 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/uk.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/uk.json @@ -888,7 +888,7 @@ "doc_link_title": "Назва (необов'язково)", "doc_open": "Відкрити", "doc_delete_confirm": "Видалити «{name}»?", - "doc_too_large": "Файл завеликий (макс. 25 МБ).", + "doc_too_large": "Файл завеликий (макс. 100 МБ).", "doc_upload_failed": "Не вдалося завантажити.", "docs_archive_too_large": "Архів завеликий (макс. {max}).", "docs_archive_no_manifest": "У цьому ZIP немає manifest.json, тому під час відновлення невідомо, до якого документа належить файл. Під час повторного пакування залишайте manifest.json поруч із теками.", @@ -903,7 +903,7 @@ "remove": "Прибрати", "doc_deduped": "Уже збережено в іншому місці — спільний, без додаткового місця.", "doc_dup_in_object": "Цей файл уже прикріплено до цього об'єкта.", - "doc_link_invalid": "Дозволені лише посилання http/https.", + "doc_link_not_allowed": "Це посилання не дозволено: посилання, які запускають скрипти або відкривають локальні файли (javascript:, data:, file: …), відхиляються.", "doc_cat_manual": "Інструкція", "doc_cat_warranty": "Гарантія", "doc_cat_invoice": "Рахунок", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Кількість для поповнення (упаковок)", "part_package_hint": "Купується упаковками, витрачається одиницями: запас, витрата на завдання та поріг дозамовлення рахуються в одиницях; кількість для поповнення та ціна — за упаковку.", "part_auto_buy": "Завдання купівлі при малому запасі", + "part_reuse": "Після використання", + "part_reuse_none": "Витрачено", + "part_reuse_charge": "Заряджено", + "part_reuse_sharpen": "Заточено", + "part_reuse_clean": "Очищено", + "part_reuse_dry": "Висушено", + "part_reuse_refill": "Заправлено", + "part_reuse_restore": "Відновлено", + "part_waiting_charge": "{count} на заряджання", + "part_waiting_sharpen": "{count} на заточування", + "part_waiting_clean": "{count} на очищення", + "part_waiting_dry": "{count} на сушіння", + "part_waiting_refill": "{count} на заправку", + "part_waiting_restore": "{count} на відновлення", + "part_restoring": "Використані, ще не готові", + "part_ready_again_hint": "Усі використані знову готові", + "part_reuse_hint": "Використана деталь не зникає: вона чекає, доки знову буде готова, і далі рахується як наявна, тож її не купують знову.", "part_restock": "Змінити запас", "parts_used_by": "Використовується", "restock_quantity_label": "Куплена кількість", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Сортувати за назвою", "battery_fleet_sort_urgency": "Сортувати за терміновістю", "battery_fleet_mark_recharged": "Позначити як заряджену", + "battery_fleet_charging": "Запасні акумулятори", + "battery_fleet_ready": "{count} готово", "battery_fleet_sparkline_hint": "Рівень заряду за останні 30 днів — пунктир: прогноз до порогу розряду", "battery_fleet_filter_type": "Показати лише цей тип батарей", "battery_fleet_record_replacement": "Рівень різко зріс приблизно {date} — записати цю заміну в Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/locales/zh.json b/custom_components/maintenance_supporter/frontend-src/locales/zh.json index 1f642541..8df8effd 100644 --- a/custom_components/maintenance_supporter/frontend-src/locales/zh.json +++ b/custom_components/maintenance_supporter/frontend-src/locales/zh.json @@ -888,7 +888,7 @@ "doc_link_title": "标题(可选)", "doc_open": "打开", "doc_delete_confirm": "删除“{name}”?", - "doc_too_large": "文件过大(最大 25 MB)。", + "doc_too_large": "文件过大(最大 100 MB)。", "doc_upload_failed": "上传失败。", "docs_archive_too_large": "压缩包过大(最大 {max})。", "docs_archive_no_manifest": "此 ZIP 中没有 manifest.json,因此恢复时无法判断文件属于哪个文档。重新压缩时请把 manifest.json 放在各文件夹旁边。", @@ -903,7 +903,7 @@ "remove": "移除", "doc_deduped": "已在别处存储——共享,不占用额外空间。", "doc_dup_in_object": "此文件已附加到该对象。", - "doc_link_invalid": "仅允许 http/https 链接。", + "doc_link_not_allowed": "不允许使用此链接:运行脚本或打开本地文件的链接(javascript:、data:、file: …)会被拒绝。", "doc_cat_manual": "手册", "doc_cat_warranty": "保修", "doc_cat_invoice": "发票", @@ -1078,6 +1078,23 @@ "part_restock_packages": "补货数量(包)", "part_package_hint": "按包购买、按单位使用:库存、每项任务用量和补货阈值都按单位计;补货数量和价格按包计。", "part_auto_buy": "库存低时自动建购买任务", + "part_reuse": "使用后", + "part_reuse_none": "已用完", + "part_reuse_charge": "已充电", + "part_reuse_sharpen": "已磨利", + "part_reuse_clean": "已清洁", + "part_reuse_dry": "已烘干", + "part_reuse_refill": "已重新灌装", + "part_reuse_restore": "已修复", + "part_waiting_charge": "{count} 个待充电", + "part_waiting_sharpen": "{count} 个待磨利", + "part_waiting_clean": "{count} 个待清洁", + "part_waiting_dry": "{count} 个待烘干", + "part_waiting_refill": "{count} 个待灌装", + "part_waiting_restore": "{count} 个待修复", + "part_restoring": "已用,尚未就绪", + "part_ready_again_hint": "所有已用的都已重新就绪", + "part_reuse_hint": "用过的不会消失:它会等待重新就绪,并仍计入已有数量,因此不会被再次购买。", "part_restock": "调整库存", "parts_used_by": "使用于", "restock_quantity_label": "购买数量", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "按名称排序", "battery_fleet_sort_urgency": "按紧急程度排序", "battery_fleet_mark_recharged": "标记为已充电", + "battery_fleet_charging": "备用充电电池", + "battery_fleet_ready": "{count} 个就绪", "battery_fleet_sparkline_hint": "过去 30 天的电池电量——虚线:外推至低电量阈值", "battery_fleet_filter_type": "仅显示此电池类型", "battery_fleet_record_replacement": "电量在 {date} 前后跳升——将此次更换记录到 Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend-src/maintenance-card.ts b/custom_components/maintenance_supporter/frontend-src/maintenance-card.ts index 741d2799..15ecfbaa 100644 --- a/custom_components/maintenance_supporter/frontend-src/maintenance-card.ts +++ b/custom_components/maintenance_supporter/frontend-src/maintenance-card.ts @@ -3,11 +3,12 @@ import { LitElement, html, css, nothing } from "lit"; import { applySubscriptionEvent, type SubscriptionEvent } from "./helpers/subscription-merge"; import { hydrateObjects } from "./helpers/hydrate-objects"; +import { taskIsFor } from "./helpers/assignees"; import { property, state } from "lit/decorators.js"; import { syncLocaleFromHass, sharedStyles, STATUS_COLORS, t, ensureLocale, isLocaleLoaded, setProfilePrefs, formatDueDays, formatLastDone, formatDate, langOf, currencySymbolOf, syncCurrencyDecimals} from "./styles"; import { openSignedDocument } from "./helpers/document-url"; import { isPhotoDocument } from "./helpers/document-categories"; -import { isSafeHttpUrl } from "./helpers/url"; +import { isSafeLink } from "./helpers/url"; import { registerCustomCard } from "./helpers/register-card"; import { healCardRegistry } from "./helpers/registry-heal"; import { localizePickerWhenReady } from "./helpers/picker-i18n"; @@ -315,9 +316,9 @@ export class MaintenanceSupporterCard extends LitElement { private async _openDoc(doc: CardDoc): Promise { if (doc.kind === "weblink" && doc.url) { // Same guarded sink as every other weblink opener: never hand a - // non-http(s) URL to window.open (defense-in-depth against a link + // blocked scheme to window.open (defense-in-depth against a link // stored before the server-side scheme check existed). - if (isSafeHttpUrl(doc.url)) window.open(doc.url, "_blank", "noopener"); + if (isSafeLink(doc.url)) window.open(doc.url, "_blank", "noopener"); return; } try { @@ -439,7 +440,7 @@ export class MaintenanceSupporterCard extends LitElement { if (vf.status && task.status !== vf.status) continue; if (vf.label && !(task.labels || []).includes(vf.label)) continue; if (vf.priority && (task.priority || "normal") !== vf.priority) continue; - if (viewUser && task.responsible_user_id !== viewUser) continue; + if (viewUser && !taskIsFor(task, viewUser)) continue; } tasks.push({ entry_id: obj.entry_id, object_name: obj.object.name, task }); } diff --git a/custom_components/maintenance_supporter/frontend-src/maintenance-panel.ts b/custom_components/maintenance_supporter/frontend-src/maintenance-panel.ts index 85fc6491..7a5e64c0 100644 --- a/custom_components/maintenance_supporter/frontend-src/maintenance-panel.ts +++ b/custom_components/maintenance_supporter/frontend-src/maintenance-panel.ts @@ -1,7 +1,7 @@ /** Maintenance Supporter Sidebar Panel. */ import { LitElement, html, nothing, type TemplateResult } from "lit"; -import { isSafeHttpUrl } from "./helpers/url"; +import { isSafeLink } from "./helpers/url"; import { queryTokens, scoreFields } from "./helpers/search-match"; import { objectRef, parseRef, renderRefChip, taskRef, type HasRef } from "./helpers/reference"; import { applySubscriptionEvent, type SubscriptionEvent } from "./helpers/subscription-merge"; @@ -13,6 +13,7 @@ import { LS_KEYS, lsGet, lsSet } from "./helpers/storage-keys"; import { openHtmlInNewTab, openSignedDocument, preopenTab, signApiPath } from "./helpers/document-url"; import { readObjectsCache, writeObjectsCache } from "./helpers/objects-cache"; import { hydrateObjects } from "./helpers/hydrate-objects"; +import { taskIsFor, taskUserIds } from "./helpers/assignees"; import { daysProgress } from "./helpers/interval"; import { buildObjectReportHtml, type ReportLabels } from "./helpers/report"; import { warrantyStatus } from "./helpers/warranty"; @@ -1215,7 +1216,8 @@ export class MaintenanceSupporterPanel extends LitElement { const userId = this._filterUser === "current_user" ? this._userService?.getCurrentUserId() : this._filterUser; - if (task.responsible_user_id !== userId) continue; + // Theirs, or shared with them while nobody is responsible. + if (!taskIsFor(task, userId)) continue; } // Label filter (v2.26 — also captured by saved views) @@ -1907,7 +1909,7 @@ export class MaintenanceSupporterPanel extends LitElement { case "document": case "content": if (r.docKind === "weblink") { - if (isSafeHttpUrl(r.url)) window.open(r.url!, "_blank", "noopener"); + if (isSafeLink(r.url)) window.open(r.url!, "_blank", "noopener"); } else if (r.docId) { // A content hit opens the PDF on the matching page (browser viewers // honour #page=N; the Companion app's external viewer may not). @@ -3044,7 +3046,7 @@ export class MaintenanceSupporterPanel extends LitElement { * Companion-safe recipe as the documents section). */ private _openManualDoc(doc: ManualDocRef): void { if (doc.kind !== "file") { - if (isSafeHttpUrl(doc.url)) window.open(doc.url!, "_blank", "noopener"); + if (isSafeLink(doc.url)) window.open(doc.url!, "_blank", "noopener"); return; } void openSignedDocument(this.hass, doc.id).catch(() => { @@ -3544,12 +3546,12 @@ export class MaintenanceSupporterPanel extends LitElement { const archivedCount = this._objects.reduce( (n, o) => n + o.tasks.filter((tk) => tk.archived).length, 0, ); - // The people someone can filter by: everyone responsible for a task, plus + // The people someone can filter by: everyone a task is meant for, plus // the person a saved view narrows to — otherwise that view leaves the // select blank while it filters. const filterPeople = new Set(); for (const o of this._objects) { - for (const tk of o.tasks) if (tk.responsible_user_id) filterPeople.add(tk.responsible_user_id); + for (const tk of o.tasks) for (const id of taskUserIds(tk)) filterPeople.add(id); } if (this._filterUser && this._filterUser !== "current_user") filterPeople.add(this._filterUser); const personOptions = [...filterPeople] @@ -4411,7 +4413,7 @@ export class MaintenanceSupporterPanel extends LitElement { // handbook attached must not render "—" here (prod: Easee vs Epson). const manualDoc = (o.manual_docs || [])[0]; return html`${ - isSafeHttpUrl(o.documentation_url) + isSafeLink(o.documentation_url) ? html` e.stopPropagation()}>` : manualDoc @@ -4789,7 +4791,7 @@ export class MaintenanceSupporterPanel extends LitElement { ${o.place_missing ? html`${t("place_missing", L)}` : nothing}

` : nothing} - ${isSafeHttpUrl(o.documentation_url) + ${isSafeLink(o.documentation_url) ? html`

${t("documentation_url_label", L)}: ${o.documentation_url}

` diff --git a/custom_components/maintenance_supporter/frontend-src/renderers/task-detail.ts b/custom_components/maintenance_supporter/frontend-src/renderers/task-detail.ts index 828cade0..7439899e 100644 --- a/custom_components/maintenance_supporter/frontend-src/renderers/task-detail.ts +++ b/custom_components/maintenance_supporter/frontend-src/renderers/task-detail.ts @@ -10,7 +10,7 @@ */ import { html, nothing } from "lit"; -import { isSafeHttpUrl } from "../helpers/url"; +import { isSafeLink } from "../helpers/url"; import { renderNotesMarkdown } from "../helpers/notes-markdown"; import { renderPersonAvatar, type PersonDisplay } from "../helpers/person"; import { t, formatDate, formatRecurrence, formatCost, formatDuration } from "../styles"; @@ -310,9 +310,9 @@ function renderChecklistCard(task: MaintenanceTask, ctx: TaskDetailContext) { * documentation_url for quick access to the device manual without having to * navigate back to the object detail. */ function renderTaskMeta(task: MaintenanceTask, ctx: TaskDetailContext) { - const safeTaskUrl = isSafeHttpUrl(task.documentation_url) + const safeTaskUrl = isSafeLink(task.documentation_url) ? task.documentation_url : null; - const safeObjUrl = isSafeHttpUrl(ctx.objectDocUrl) ? ctx.objectDocUrl : null; + const safeObjUrl = isSafeLink(ctx.objectDocUrl) ? ctx.objectDocUrl : null; // Same fallback rule as the objects table: an UPLOADED manual (category // "manual") stands in when the object's URL field is empty. const manualDoc = safeObjUrl ? null : (ctx.objectManualDocs || [])[0]; diff --git a/custom_components/maintenance_supporter/frontend-src/styles.ts b/custom_components/maintenance_supporter/frontend-src/styles.ts index 00411c8f..519c6aa2 100644 --- a/custom_components/maintenance_supporter/frontend-src/styles.ts +++ b/custom_components/maintenance_supporter/frontend-src/styles.ts @@ -1274,10 +1274,13 @@ export const sharedStyles = css` font-weight: 500; font-size: 14px; margin-bottom: 4px; + min-width: 0; + overflow-wrap: anywhere; } .group-card-actions { display: flex; + flex-shrink: 0; gap: 0; } .group-card-actions ha-icon-button { @@ -1324,6 +1327,8 @@ export const sharedStyles = css` border-radius: 10px; background: var(--secondary-background-color, #f5f5f5); color: var(--primary-text-color); + max-width: 100%; + overflow-wrap: anywhere; } /* Adaptive scheduling suggestion badge */ @@ -1712,7 +1717,19 @@ export const sharedStyles = css` suffix is hidden instead — the bar and the title carry the ratio. */ .budget-tile-max { display: none; } - .group-card { min-width: 0; max-width: 100%; } + /* #206 — one group per row. flex: 1 with min-width 0 put every group + into ONE row: three groups were 96 px each on a 360 px phone, and the + delete button of one lay over the next group. The buttons get the + same 44 px targets as the task rows, apart from each other; the + negative margin lets them reach into the card's padding instead of + pushing the tasks down. */ + .group-card { flex: 1 1 100%; min-width: 0; max-width: 100%; } + .group-card-actions { gap: 8px; margin: -8px -8px -8px 0; } + .group-card-actions ha-icon-button { + --ha-icon-button-size: 44px; + --mdc-icon-button-size: 44px; + --mdc-icon-size: 22px; + } .filter-chip { padding: 6px 12px; font-size: 13px; } diff --git a/custom_components/maintenance_supporter/frontend-src/types.ts b/custom_components/maintenance_supporter/frontend-src/types.ts index 1727c61f..9e9260d3 100644 --- a/custom_components/maintenance_supporter/frontend-src/types.ts +++ b/custom_components/maintenance_supporter/frontend-src/types.ts @@ -427,8 +427,14 @@ export interface MaintenancePart { package_size?: number | null; auto_buy_task?: boolean; doc_id?: string | null; - /** Tracked on-hand count; null = catalog-only (not tracked). */ + /** #208: what readies a used one again (charge, sharpen, clean, dry, + * refill, restore); null/absent = the part is used up. */ + reuse?: string | null; + /** Tracked on-hand count; null = catalog-only (not tracked). For a + * reusable part: the ready ones. */ stock?: number | null; + /** #208: used ones of a reusable part waiting to be ready again. */ + restoring?: number; /** Derived: tracked stock at/below the reorder threshold. */ is_low?: boolean; /** Derived: product_url or the configured shopping-search link. */ diff --git a/custom_components/maintenance_supporter/frontend/locales/cs.json b/custom_components/maintenance_supporter/frontend/locales/cs.json index f454e5f4..8c0365f8 100644 --- a/custom_components/maintenance_supporter/frontend/locales/cs.json +++ b/custom_components/maintenance_supporter/frontend/locales/cs.json @@ -888,7 +888,7 @@ "doc_link_title": "Název (nepovinné)", "doc_open": "Otevřít", "doc_delete_confirm": "Smazat „{name}“?", - "doc_too_large": "Soubor je příliš velký (max. 25 MB).", + "doc_too_large": "Soubor je příliš velký (max. 100 MB).", "doc_upload_failed": "Nahrání selhalo.", "docs_archive_too_large": "Archiv je příliš velký (max. {max}).", "docs_archive_no_manifest": "Tento ZIP neobsahuje manifest.json, takže obnovení neví, ke kterému dokumentu soubor patří. Při opětovném zabalení ponechte manifest.json vedle složek.", @@ -903,7 +903,7 @@ "remove": "Odebrat", "doc_deduped": "Již uloženo jinde — sdíleno, bez dalšího místa.", "doc_dup_in_object": "Tento soubor je již připojen k tomuto objektu.", - "doc_link_invalid": "Povoleny jsou pouze odkazy http/https.", + "doc_link_not_allowed": "Tento odkaz není povolen: odkazy, které spouštějí skripty nebo otevírají místní soubory (javascript:, data:, file: …), jsou odmítnuty.", "doc_cat_manual": "Návod", "doc_cat_warranty": "Záruka", "doc_cat_invoice": "Faktura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Množství k doplnění (balení)", "part_package_hint": "Kupuje se po baleních, spotřebovává po jednotkách: zásoba, spotřeba na úkol a hranice objednání počítají jednotky; množství k doplnění a cena platí za balení.", "part_auto_buy": "Úkol nákupu při nízké zásobě", + "part_reuse": "Po použití", + "part_reuse_none": "Spotřebován", + "part_reuse_charge": "Nabito", + "part_reuse_sharpen": "Nabroušeno", + "part_reuse_clean": "Vyčištěno", + "part_reuse_dry": "Vysušeno", + "part_reuse_refill": "Doplněno", + "part_reuse_restore": "Obnoveno", + "part_waiting_charge": "{count} k nabití", + "part_waiting_sharpen": "{count} k nabroušení", + "part_waiting_clean": "{count} k vyčištění", + "part_waiting_dry": "{count} k vysušení", + "part_waiting_refill": "{count} k doplnění", + "part_waiting_restore": "{count} k obnovení", + "part_restoring": "Použité, zatím nepřipravené", + "part_ready_again_hint": "Všechny použité jsou opět připravené", + "part_reuse_hint": "Použitý kus nezmizí: čeká, až bude znovu připravený, a dál se počítá jako vlastněný, takže se znovu nekupuje.", "part_restock": "Upravit zásobu", "parts_used_by": "Používá", "restock_quantity_label": "Zakoupené množství", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Řadit podle názvu", "battery_fleet_sort_urgency": "Řadit podle naléhavosti", "battery_fleet_mark_recharged": "Označit jako nabitou", + "battery_fleet_charging": "Náhradní akumulátory", + "battery_fleet_ready": "{count} připraveno", "battery_fleet_sparkline_hint": "Stav baterie za posledních 30 dní — tečkovaně: projekce k prahu vybití", "battery_fleet_filter_type": "Zobrazit pouze tento typ baterie", "battery_fleet_record_replacement": "Stav poskočil kolem {date} — zaznamenat tuto výměnu do Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/da.json b/custom_components/maintenance_supporter/frontend/locales/da.json index d7fccd5b..7a0b8cf9 100644 --- a/custom_components/maintenance_supporter/frontend/locales/da.json +++ b/custom_components/maintenance_supporter/frontend/locales/da.json @@ -888,7 +888,7 @@ "doc_link_title": "Titel (valgfri)", "doc_open": "Åbn", "doc_delete_confirm": "Slet \"{name}\"?", - "doc_too_large": "Filen er for stor (maks. 25 MB).", + "doc_too_large": "Filen er for stor (maks. 100 MB).", "doc_upload_failed": "Upload mislykkedes.", "docs_archive_too_large": "Arkivet er for stort (maks. {max}).", "docs_archive_no_manifest": "Denne ZIP har ingen manifest.json, så gendannelsen ved ikke, hvilket dokument en fil hører til. Lad manifest.json ligge ved siden af mapperne, når du zipper igen.", @@ -903,7 +903,7 @@ "remove": "Fjern", "doc_deduped": "Allerede gemt et andet sted — delt, ingen ekstra plads.", "doc_dup_in_object": "Denne fil er allerede vedhæftet dette objekt.", - "doc_link_invalid": "Kun http/https-links er tilladt.", + "doc_link_not_allowed": "Dette link er ikke tilladt: links, der kører scripts eller åbner lokale filer (javascript:, data:, file: …), afvises.", "doc_cat_manual": "Vejledning", "doc_cat_warranty": "Garanti", "doc_cat_invoice": "Faktura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Genopfyldningsmængde (pakninger)", "part_package_hint": "Købes i pakninger, bruges i enheden: lager, forbrug pr. opgave og genbestillingsgrænse tæller enheder; genopfyldningsmængde og pris gælder pr. pakning.", "part_auto_buy": "Købsopgave ved lav beholdning", + "part_reuse": "Efter brug", + "part_reuse_none": "Brugt op", + "part_reuse_charge": "Opladet", + "part_reuse_sharpen": "Slebet", + "part_reuse_clean": "Rengjort", + "part_reuse_dry": "Tørret", + "part_reuse_refill": "Genopfyldt", + "part_reuse_restore": "Istandsat", + "part_waiting_charge": "{count} skal oplades", + "part_waiting_sharpen": "{count} skal slibes", + "part_waiting_clean": "{count} skal rengøres", + "part_waiting_dry": "{count} skal tørres", + "part_waiting_refill": "{count} skal genopfyldes", + "part_waiting_restore": "{count} skal istandsættes", + "part_restoring": "Brugte, ikke klar endnu", + "part_ready_again_hint": "Alle brugte er klar igen", + "part_reuse_hint": "En brugt er ikke væk: den venter, til den er klar igen, og tæller stadig som ejet, så den bliver ikke købt igen.", "part_restock": "Justér lager", "parts_used_by": "Bruges af", "restock_quantity_label": "Købt mængde", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sortér efter navn", "battery_fleet_sort_urgency": "Sortér efter hastende grad", "battery_fleet_mark_recharged": "Markér som genopladet", + "battery_fleet_charging": "Genopladelige reserver", + "battery_fleet_ready": "{count} klar", "battery_fleet_sparkline_hint": "Batteriniveau de seneste 30 dage — stiplet: fremskrivning ned til lav-tærsklen", "battery_fleet_filter_type": "Vis kun denne batteritype", "battery_fleet_record_replacement": "Niveauet sprang omkring {date} — registrér denne udskiftning i Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/de.json b/custom_components/maintenance_supporter/frontend/locales/de.json index 675d9d0c..3db9c433 100644 --- a/custom_components/maintenance_supporter/frontend/locales/de.json +++ b/custom_components/maintenance_supporter/frontend/locales/de.json @@ -888,7 +888,7 @@ "doc_link_title": "Titel (optional)", "doc_open": "Öffnen", "doc_delete_confirm": "„{name}“ löschen?", - "doc_too_large": "Datei ist zu groß (max. 25 MB).", + "doc_too_large": "Datei ist zu groß (max. 100 MB).", "doc_upload_failed": "Upload fehlgeschlagen.", "docs_archive_too_large": "Das Archiv ist zu groß (max. {max}).", "docs_archive_no_manifest": "Dieses ZIP enthält keine manifest.json, daher weiß die Wiederherstellung nicht, zu welchem Dokument eine Datei gehört. Lass die manifest.json beim erneuten Zippen neben den Ordnern liegen.", @@ -903,7 +903,7 @@ "remove": "Entfernen", "doc_deduped": "Bereits anderswo gespeichert — geteilt, kein zusätzlicher Speicher.", "doc_dup_in_object": "Diese Datei ist bereits an diesem Objekt angehängt.", - "doc_link_invalid": "Nur http/https-Links sind erlaubt.", + "doc_link_not_allowed": "Dieser Link ist nicht erlaubt: Links, die Skripte ausführen oder lokale Dateien öffnen (javascript:, data:, file: …), werden abgelehnt.", "doc_cat_manual": "Anleitung", "doc_cat_warranty": "Garantie", "doc_cat_invoice": "Rechnung", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Nachkaufmenge (Packungen)", "part_package_hint": "Gekauft in Packungen, verbraucht in der Einheit: Bestand, Verbrauch pro Aufgabe und Nachbestellgrenze zählen Einheiten; Nachkaufmenge und Preis gelten pro Packung.", "part_auto_buy": "Kauf-Task bei Niedrigbestand", + "part_reuse": "Nach Gebrauch", + "part_reuse_none": "Verbraucht", + "part_reuse_charge": "Geladen", + "part_reuse_sharpen": "Geschärft", + "part_reuse_clean": "Gereinigt", + "part_reuse_dry": "Getrocknet", + "part_reuse_refill": "Nachgefüllt", + "part_reuse_restore": "Aufbereitet", + "part_waiting_charge": "{count} zu laden", + "part_waiting_sharpen": "{count} zu schärfen", + "part_waiting_clean": "{count} zu reinigen", + "part_waiting_dry": "{count} zu trocknen", + "part_waiting_refill": "{count} nachzufüllen", + "part_waiting_restore": "{count} aufzubereiten", + "part_restoring": "Gebraucht, noch nicht bereit", + "part_ready_again_hint": "Alle gebrauchten sind wieder bereit", + "part_reuse_hint": "Ein gebrauchtes ist nicht weg: Es wartet, bis es wieder bereit ist, und zählt weiter zum Bestand, wird also nicht neu gekauft.", "part_restock": "Bestand anpassen", "parts_used_by": "Verwendet von", "restock_quantity_label": "Gekaufte Menge", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Nach Name sortieren", "battery_fleet_sort_urgency": "Nach Dringlichkeit sortieren", "battery_fleet_mark_recharged": "Als aufgeladen markieren", + "battery_fleet_charging": "Akku-Vorrat", + "battery_fleet_ready": "{count} bereit", "battery_fleet_sparkline_hint": "Batteriestand der letzten 30 Tage — gepunktet: Prognose bis zur Low-Schwelle", "battery_fleet_filter_type": "Nur diesen Batterietyp anzeigen", "battery_fleet_record_replacement": "Der Batteriestand ist um den {date} gesprungen — diesen Wechsel in Battery Notes nachtragen", diff --git a/custom_components/maintenance_supporter/frontend/locales/en.json b/custom_components/maintenance_supporter/frontend/locales/en.json index 60a4e026..14e58e17 100644 --- a/custom_components/maintenance_supporter/frontend/locales/en.json +++ b/custom_components/maintenance_supporter/frontend/locales/en.json @@ -895,7 +895,7 @@ "doc_link_title": "Title (optional)", "doc_open": "Open", "doc_delete_confirm": "Delete \"{name}\"?", - "doc_too_large": "File is too large (max 25 MB).", + "doc_too_large": "File is too large (max 100 MB).", "doc_upload_failed": "Upload failed.", "docs_archive_too_large": "The archive is too large (max {max}).", "docs_archive_no_manifest": "This ZIP has no manifest.json, so the restore cannot tell which document a file belongs to. Keep manifest.json next to the folders when zipping again.", @@ -910,7 +910,7 @@ "remove": "Remove", "doc_deduped": "Already stored elsewhere — shared, no extra space used.", "doc_dup_in_object": "This file is already attached to this object.", - "doc_link_invalid": "Only http/https links are allowed.", + "doc_link_not_allowed": "This link is not allowed: links that run scripts or open local files (javascript:, data:, file: …) are refused.", "doc_cat_manual": "Manual", "doc_cat_warranty": "Warranty", "doc_cat_invoice": "Invoice", @@ -1085,6 +1085,23 @@ "part_restock_packages": "Restock amount (packages)", "part_package_hint": "Bought in packages, used in the unit: stock, the amount a task uses and the reorder threshold count units; the restock amount and the price are per package.", "part_auto_buy": "Auto-create buy task when low", + "part_reuse": "After use", + "part_reuse_none": "Used up", + "part_reuse_charge": "Charged", + "part_reuse_sharpen": "Sharpened", + "part_reuse_clean": "Cleaned", + "part_reuse_dry": "Dried", + "part_reuse_refill": "Refilled", + "part_reuse_restore": "Restored", + "part_waiting_charge": "{count} to charge", + "part_waiting_sharpen": "{count} to sharpen", + "part_waiting_clean": "{count} to clean", + "part_waiting_dry": "{count} to dry", + "part_waiting_refill": "{count} to refill", + "part_waiting_restore": "{count} to restore", + "part_restoring": "Used, not ready yet", + "part_ready_again_hint": "All used ones are ready again", + "part_reuse_hint": "A used one is not gone: it waits until it is ready again and still counts as owned, so it is not bought again.", "part_restock": "Adjust stock", "parts_used_by": "Used by", "restock_quantity_label": "Quantity bought", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sort by name", "battery_fleet_sort_urgency": "Sort by urgency", "battery_fleet_mark_recharged": "Mark as recharged", + "battery_fleet_charging": "Rechargeable spares", + "battery_fleet_ready": "{count} ready", "battery_fleet_sparkline_hint": "Battery level over the last 30 days — dotted: projected until the low threshold", "battery_fleet_filter_type": "Show only this battery type", "battery_fleet_record_replacement": "The level jumped around {date} — record this replacement in Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/es.json b/custom_components/maintenance_supporter/frontend/locales/es.json index e2659163..027410f5 100644 --- a/custom_components/maintenance_supporter/frontend/locales/es.json +++ b/custom_components/maintenance_supporter/frontend/locales/es.json @@ -888,7 +888,7 @@ "doc_link_title": "Título (opcional)", "doc_open": "Abrir", "doc_delete_confirm": "¿Eliminar «{name}»?", - "doc_too_large": "El archivo es demasiado grande (máx. 25 MB).", + "doc_too_large": "El archivo es demasiado grande (máx. 100 MB).", "doc_upload_failed": "Error al subir.", "docs_archive_too_large": "El archivo comprimido es demasiado grande (máx. {max}).", "docs_archive_no_manifest": "Este ZIP no contiene manifest.json, así que la restauración no sabe a qué documento pertenece cada archivo. Deja manifest.json junto a las carpetas al volver a comprimir.", @@ -903,7 +903,7 @@ "remove": "Quitar", "doc_deduped": "Ya almacenado en otro lugar — compartido, sin espacio adicional.", "doc_dup_in_object": "Este archivo ya está adjunto a este objeto.", - "doc_link_invalid": "Solo se permiten enlaces http/https.", + "doc_link_not_allowed": "Este enlace no está permitido: se rechazan los enlaces que ejecutan scripts o abren archivos locales (javascript:, data:, file: …).", "doc_cat_manual": "Manual", "doc_cat_warranty": "Garantía", "doc_cat_invoice": "Factura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Cantidad de reposición (envases)", "part_package_hint": "Se compra por envases y se usa por unidades: el stock, el consumo por tarea y el umbral de pedido cuentan unidades; la cantidad de reposición y el precio son por envase.", "part_auto_buy": "Crear tarea de compra si bajo", + "part_reuse": "Tras el uso", + "part_reuse_none": "Consumido", + "part_reuse_charge": "Recargado", + "part_reuse_sharpen": "Afilado", + "part_reuse_clean": "Limpiado", + "part_reuse_dry": "Secado", + "part_reuse_refill": "Rellenado", + "part_reuse_restore": "Restaurado", + "part_waiting_charge": "{count} por recargar", + "part_waiting_sharpen": "{count} por afilar", + "part_waiting_clean": "{count} por limpiar", + "part_waiting_dry": "{count} por secar", + "part_waiting_refill": "{count} por rellenar", + "part_waiting_restore": "{count} por restaurar", + "part_restoring": "Usados, aún no listos", + "part_ready_again_hint": "Todos los usados vuelven a estar listos", + "part_reuse_hint": "Una pieza usada no se pierde: espera hasta estar lista de nuevo y sigue contando como propia, así que no se vuelve a comprar.", "part_restock": "Ajustar existencias", "parts_used_by": "Usado por", "restock_quantity_label": "Cantidad comprada", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Ordenar por nombre", "battery_fleet_sort_urgency": "Ordenar por urgencia", "battery_fleet_mark_recharged": "Marcar como recargada", + "battery_fleet_charging": "Repuestos recargables", + "battery_fleet_ready": "{count} listas", "battery_fleet_sparkline_hint": "Nivel de batería de los últimos 30 días — punteado: proyección hasta el umbral bajo", "battery_fleet_filter_type": "Mostrar solo este tipo de pila", "battery_fleet_record_replacement": "El nivel dio un salto hacia el {date} — registrar esta sustitución en Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/fi.json b/custom_components/maintenance_supporter/frontend/locales/fi.json index 7a3e0dc9..24eec475 100644 --- a/custom_components/maintenance_supporter/frontend/locales/fi.json +++ b/custom_components/maintenance_supporter/frontend/locales/fi.json @@ -888,7 +888,7 @@ "doc_link_title": "Otsikko (valinnainen)", "doc_open": "Avaa", "doc_delete_confirm": "Poistetaanko \"{name}\"?", - "doc_too_large": "Tiedosto on liian suuri (enint. 25 Mt).", + "doc_too_large": "Tiedosto on liian suuri (enint. 100 Mt).", "doc_upload_failed": "Lataus epäonnistui.", "docs_archive_too_large": "Arkisto on liian suuri (enintään {max}).", "docs_archive_no_manifest": "Tässä ZIP-tiedostossa ei ole manifest.json-tiedostoa, joten palautus ei tiedä, mihin asiakirjaan tiedosto kuuluu. Pidä manifest.json kansioiden vieressä, kun pakkaat uudelleen.", @@ -903,7 +903,7 @@ "remove": "Poista", "doc_deduped": "Jo tallennettu muualle — jaettu, ei lisätilaa.", "doc_dup_in_object": "Tämä tiedosto on jo liitetty tähän kohteeseen.", - "doc_link_invalid": "Vain http/https-linkit ovat sallittuja.", + "doc_link_not_allowed": "Tämä linkki ei ole sallittu: linkit, jotka suorittavat skriptejä tai avaavat paikallisia tiedostoja (javascript:, data:, file: …), hylätään.", "doc_cat_manual": "Käyttöohje", "doc_cat_warranty": "Takuu", "doc_cat_invoice": "Lasku", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Täydennysmäärä (pakkausta)", "part_package_hint": "Ostetaan pakkauksina, kulutetaan yksikköinä: varasto, tehtävän kulutus ja tilausraja lasketaan yksikköinä; täydennysmäärä ja hinta ovat pakkauskohtaisia.", "part_auto_buy": "Ostotehtävä kun vähissä", + "part_reuse": "Käytön jälkeen", + "part_reuse_none": "Kulutettu", + "part_reuse_charge": "Ladattu", + "part_reuse_sharpen": "Teroitettu", + "part_reuse_clean": "Puhdistettu", + "part_reuse_dry": "Kuivattu", + "part_reuse_refill": "Täytetty", + "part_reuse_restore": "Kunnostettu", + "part_waiting_charge": "{count} ladattavana", + "part_waiting_sharpen": "{count} teroitettavana", + "part_waiting_clean": "{count} puhdistettavana", + "part_waiting_dry": "{count} kuivattavana", + "part_waiting_refill": "{count} täytettävänä", + "part_waiting_restore": "{count} kunnostettavana", + "part_restoring": "Käytetyt, ei vielä valmiina", + "part_ready_again_hint": "Kaikki käytetyt ovat taas valmiina", + "part_reuse_hint": "Käytetty ei katoa: se odottaa, kunnes se on taas valmiina, ja lasketaan yhä omistetuksi, joten sitä ei osteta uudelleen.", "part_restock": "Muuta varastoa", "parts_used_by": "Käyttäjät", "restock_quantity_label": "Ostettu määrä", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Lajittele nimen mukaan", "battery_fleet_sort_urgency": "Lajittele kiireellisyyden mukaan", "battery_fleet_mark_recharged": "Merkitse ladatuksi", + "battery_fleet_charging": "Ladattavat varaosat", + "battery_fleet_ready": "{count} valmiina", "battery_fleet_sparkline_hint": "Akun varaustaso viimeisten 30 päivän ajalta — pisteviiva: ennuste alarajaan asti", "battery_fleet_filter_type": "Näytä vain tämä paristotyyppi", "battery_fleet_record_replacement": "Varaustaso hyppäsi noin {date} — kirjaa tämä vaihto Battery Notesiin", diff --git a/custom_components/maintenance_supporter/frontend/locales/fr.json b/custom_components/maintenance_supporter/frontend/locales/fr.json index 0e741a8f..1ed05282 100644 --- a/custom_components/maintenance_supporter/frontend/locales/fr.json +++ b/custom_components/maintenance_supporter/frontend/locales/fr.json @@ -888,7 +888,7 @@ "doc_link_title": "Titre (facultatif)", "doc_open": "Ouvrir", "doc_delete_confirm": "Supprimer « {name} » ?", - "doc_too_large": "Fichier trop volumineux (max. 25 Mo).", + "doc_too_large": "Fichier trop volumineux (max. 100 Mo).", "doc_upload_failed": "Échec du téléversement.", "docs_archive_too_large": "Archive trop volumineuse (max. {max}).", "docs_archive_no_manifest": "Ce ZIP ne contient pas de manifest.json : la restauration ne peut pas savoir à quel document appartient un fichier. Gardez manifest.json à côté des dossiers lorsque vous recompressez.", @@ -903,7 +903,7 @@ "remove": "Retirer", "doc_deduped": "Déjà stocké ailleurs — partagé, aucun espace supplémentaire.", "doc_dup_in_object": "Ce fichier est déjà attaché à cet objet.", - "doc_link_invalid": "Seuls les liens http/https sont autorisés.", + "doc_link_not_allowed": "Ce lien n'est pas autorisé : les liens qui exécutent des scripts ou ouvrent des fichiers locaux (javascript:, data:, file: …) sont refusés.", "doc_cat_manual": "Manuel", "doc_cat_warranty": "Garantie", "doc_cat_invoice": "Facture", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Quantité de réapprovisionnement (conditionnements)", "part_package_hint": "Acheté par conditionnement, utilisé à l'unité : le stock, la quantité utilisée par tâche et le seuil de réapprovisionnement comptent des unités ; la quantité de réapprovisionnement et le prix sont par conditionnement.", "part_auto_buy": "Tâche d'achat auto si bas", + "part_reuse": "Après usage", + "part_reuse_none": "Consommé", + "part_reuse_charge": "Rechargé", + "part_reuse_sharpen": "Affûté", + "part_reuse_clean": "Nettoyé", + "part_reuse_dry": "Séché", + "part_reuse_refill": "Rempli", + "part_reuse_restore": "Remis en état", + "part_waiting_charge": "{count} à recharger", + "part_waiting_sharpen": "{count} à affûter", + "part_waiting_clean": "{count} à nettoyer", + "part_waiting_dry": "{count} à sécher", + "part_waiting_refill": "{count} à remplir", + "part_waiting_restore": "{count} à remettre en état", + "part_restoring": "Utilisés, pas encore prêts", + "part_ready_again_hint": "Tous les usagés sont de nouveau prêts", + "part_reuse_hint": "Un exemplaire utilisé n'est pas perdu : il attend d'être de nouveau prêt et compte toujours comme possédé, il n'est donc pas racheté.", "part_restock": "Ajuster le stock", "parts_used_by": "Utilisé par", "restock_quantity_label": "Quantité achetée", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Trier par nom", "battery_fleet_sort_urgency": "Trier par urgence", "battery_fleet_mark_recharged": "Marquer comme rechargée", + "battery_fleet_charging": "Piles rechargeables de réserve", + "battery_fleet_ready": "{count} prêtes", "battery_fleet_sparkline_hint": "Niveau de batterie des 30 derniers jours — pointillé : projection jusqu'au seuil bas", "battery_fleet_filter_type": "Afficher uniquement ce type de pile", "battery_fleet_record_replacement": "Le niveau a bondi vers le {date} — enregistrer ce remplacement dans Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/hi.json b/custom_components/maintenance_supporter/frontend/locales/hi.json index 281d6abd..450bc667 100644 --- a/custom_components/maintenance_supporter/frontend/locales/hi.json +++ b/custom_components/maintenance_supporter/frontend/locales/hi.json @@ -888,7 +888,7 @@ "doc_link_title": "शीर्षक (वैकल्पिक)", "doc_open": "खोलें", "doc_delete_confirm": "\"{name}\" हटाएँ?", - "doc_too_large": "फ़ाइल बहुत बड़ी है (अधिकतम 25 MB)।", + "doc_too_large": "फ़ाइल बहुत बड़ी है (अधिकतम 100 MB)।", "doc_upload_failed": "अपलोड विफल रहा।", "docs_archive_too_large": "आर्काइव बहुत बड़ा है (अधिकतम {max})।", "docs_archive_no_manifest": "इस ZIP में manifest.json नहीं है, इसलिए पुनर्स्थापना यह नहीं जान सकती कि कोई फ़ाइल किस दस्तावेज़ की है। दोबारा ज़िप करते समय manifest.json को फ़ोल्डरों के साथ रखें।", @@ -903,7 +903,7 @@ "remove": "हटाएँ", "doc_deduped": "पहले से कहीं और संग्रहीत — साझा, कोई अतिरिक्त स्थान नहीं।", "doc_dup_in_object": "यह फ़ाइल पहले से इस ऑब्जेक्ट से जुड़ी है।", - "doc_link_invalid": "केवल http/https लिंक की अनुमति है।", + "doc_link_not_allowed": "यह लिंक अनुमत नहीं है: स्क्रिप्ट चलाने वाले या स्थानीय फ़ाइलें खोलने वाले लिंक (javascript:, data:, file: …) अस्वीकार किए जाते हैं।", "doc_cat_manual": "मैनुअल", "doc_cat_warranty": "वारंटी", "doc_cat_invoice": "चालान", @@ -1078,6 +1078,23 @@ "part_restock_packages": "दोबारा भरने की मात्रा (पैकेट)", "part_package_hint": "पैकेट में खरीदा, इकाई में इस्तेमाल: स्टॉक, हर काम की खपत और दोबारा मंगाने की सीमा इकाइयों में गिनी जाती हैं; दोबारा भरने की मात्रा और कीमत प्रति पैकेट हैं।", "part_auto_buy": "कम होने पर खरीद कार्य", + "part_reuse": "उपयोग के बाद", + "part_reuse_none": "खत्म", + "part_reuse_charge": "चार्ज किया गया", + "part_reuse_sharpen": "धार लगाई गई", + "part_reuse_clean": "साफ किया गया", + "part_reuse_dry": "सुखाया गया", + "part_reuse_refill": "फिर से भरा गया", + "part_reuse_restore": "फिर से तैयार", + "part_waiting_charge": "{count} चार्ज करने हैं", + "part_waiting_sharpen": "{count} पर धार लगानी है", + "part_waiting_clean": "{count} साफ करने हैं", + "part_waiting_dry": "{count} सुखाने हैं", + "part_waiting_refill": "{count} फिर से भरने हैं", + "part_waiting_restore": "{count} फिर से तैयार करने हैं", + "part_restoring": "इस्तेमाल हुए, अभी तैयार नहीं", + "part_ready_again_hint": "सभी इस्तेमाल हुए फिर से तैयार हैं", + "part_reuse_hint": "इस्तेमाल किया हुआ खत्म नहीं होता: यह फिर से तैयार होने तक इंतज़ार करता है और आपके पास गिना जाता है, इसलिए दोबारा नहीं खरीदा जाता।", "part_restock": "स्टॉक समायोजित करें", "parts_used_by": "द्वारा उपयोग", "restock_quantity_label": "खरीदी गई मात्रा", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "नाम के अनुसार क्रमबद्ध करें", "battery_fleet_sort_urgency": "तात्कालिकता के अनुसार क्रमबद्ध करें", "battery_fleet_mark_recharged": "रिचार्ज हो गई के रूप में चिह्नित करें", + "battery_fleet_charging": "रिचार्जेबल अतिरिक्त", + "battery_fleet_ready": "{count} तैयार", "battery_fleet_sparkline_hint": "पिछले 30 दिनों का बैटरी स्तर — बिंदीदार: लो थ्रेशोल्ड तक का अनुमान", "battery_fleet_filter_type": "केवल यही बैटरी प्रकार दिखाएँ", "battery_fleet_record_replacement": "स्तर लगभग {date} को उछला — इस बदलाव को Battery Notes में दर्ज करें", diff --git a/custom_components/maintenance_supporter/frontend/locales/hu.json b/custom_components/maintenance_supporter/frontend/locales/hu.json index 10e6934b..a759175c 100644 --- a/custom_components/maintenance_supporter/frontend/locales/hu.json +++ b/custom_components/maintenance_supporter/frontend/locales/hu.json @@ -895,7 +895,7 @@ "doc_link_title": "Cím (opcionális)", "doc_open": "Megnyitás", "doc_delete_confirm": "Törli a(z) „{name}” elemet?", - "doc_too_large": "A fájl túl nagy (max. 25 MB).", + "doc_too_large": "A fájl túl nagy (max. 100 MB).", "doc_upload_failed": "A feltöltés nem sikerült.", "docs_archive_too_large": "Az archívum túl nagy (max. {max}).", "docs_archive_no_manifest": "Ebben a ZIP-ben nincs manifest.json, ezért a visszaállítás nem tudja, melyik dokumentumhoz tartozik egy fájl. Újratömörítéskor hagyd a manifest.json fájlt a mappák mellett.", @@ -910,7 +910,7 @@ "remove": "Eltávolítás", "doc_deduped": "Már máshol is tárolva — megosztott, nem foglal extra helyet.", "doc_dup_in_object": "Ez a fájl már csatolva van ehhez az objektumhoz.", - "doc_link_invalid": "Csak http/https hivatkozás engedélyezett.", + "doc_link_not_allowed": "Ez a hivatkozás nem engedélyezett: a szkripteket futtató vagy helyi fájlokat megnyitó hivatkozásokat (javascript:, data:, file: …) elutasítjuk.", "doc_cat_manual": "Kézikönyv", "doc_cat_warranty": "Garancia", "doc_cat_invoice": "Számla", @@ -1085,6 +1085,23 @@ "part_restock_packages": "Utántöltési mennyiség (kiszerelés)", "part_package_hint": "Kiszerelésben vásárolva, egységben felhasználva: a készlet, a feladatonkénti fogyás és az újrarendelési küszöb egységet számol; az utántöltési mennyiség és az ár kiszerelésenként értendő.", "part_auto_buy": "Vásárlási feladat automatikus létrehozása, ha kevés van", + "part_reuse": "Használat után", + "part_reuse_none": "Elhasználva", + "part_reuse_charge": "Feltöltve", + "part_reuse_sharpen": "Megélezve", + "part_reuse_clean": "Megtisztítva", + "part_reuse_dry": "Kiszárítva", + "part_reuse_refill": "Utántöltve", + "part_reuse_restore": "Felújítva", + "part_waiting_charge": "{count} töltendő", + "part_waiting_sharpen": "{count} élezendő", + "part_waiting_clean": "{count} tisztítandó", + "part_waiting_dry": "{count} szárítandó", + "part_waiting_refill": "{count} utántöltendő", + "part_waiting_restore": "{count} felújítandó", + "part_restoring": "Használt, még nem kész", + "part_ready_again_hint": "Az összes használt újra kész", + "part_reuse_hint": "A használt darab nem vész el: megvárja, amíg újra kész, és továbbra is a készlethez számít, így nem kell újra megvenni.", "part_restock": "Készlet módosítása", "parts_used_by": "Használja", "restock_quantity_label": "Vásárolt mennyiség", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Rendezés név szerint", "battery_fleet_sort_urgency": "Rendezés sürgősség szerint", "battery_fleet_mark_recharged": "Megjelölés feltöltöttként", + "battery_fleet_charging": "Tartalék akkuk", + "battery_fleet_ready": "{count} kész", "battery_fleet_sparkline_hint": "Akkumulátorszint az elmúlt 30 napban — pontozott: előrejelzés az alacsony küszöbig", "battery_fleet_filter_type": "Csak ez az elemtípus megjelenítése", "battery_fleet_record_replacement": "A szint {date} körül megugrott — rögzítse ezt a cserét a Battery Notes-ban", diff --git a/custom_components/maintenance_supporter/frontend/locales/it.json b/custom_components/maintenance_supporter/frontend/locales/it.json index b973aaf9..e138ef8c 100644 --- a/custom_components/maintenance_supporter/frontend/locales/it.json +++ b/custom_components/maintenance_supporter/frontend/locales/it.json @@ -888,7 +888,7 @@ "doc_link_title": "Titolo (facoltativo)", "doc_open": "Apri", "doc_delete_confirm": "Eliminare «{name}»?", - "doc_too_large": "File troppo grande (max 25 MB).", + "doc_too_large": "File troppo grande (max 100 MB).", "doc_upload_failed": "Caricamento non riuscito.", "docs_archive_too_large": "L'archivio è troppo grande (max {max}).", "docs_archive_no_manifest": "Questo ZIP non contiene manifest.json, quindi il ripristino non sa a quale documento appartiene un file. Lascia manifest.json accanto alle cartelle quando lo comprimi di nuovo.", @@ -903,7 +903,7 @@ "remove": "Rimuovi", "doc_deduped": "Già archiviato altrove — condiviso, nessuno spazio aggiuntivo.", "doc_dup_in_object": "Questo file è già allegato a questo oggetto.", - "doc_link_invalid": "Sono consentiti solo link http/https.", + "doc_link_not_allowed": "Questo link non è consentito: i link che eseguono script o aprono file locali (javascript:, data:, file: …) vengono rifiutati.", "doc_cat_manual": "Manuale", "doc_cat_warranty": "Garanzia", "doc_cat_invoice": "Fattura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Quantità di riordino (confezioni)", "part_package_hint": "Acquistato a confezioni, usato a unità: scorte, consumo per attività e soglia di riordino contano unità; quantità di riordino e prezzo sono per confezione.", "part_auto_buy": "Task d'acquisto se scarso", + "part_reuse": "Dopo l'uso", + "part_reuse_none": "Consumato", + "part_reuse_charge": "Ricaricato", + "part_reuse_sharpen": "Affilato", + "part_reuse_clean": "Pulito", + "part_reuse_dry": "Asciugato", + "part_reuse_refill": "Riempito", + "part_reuse_restore": "Ripristinato", + "part_waiting_charge": "{count} da ricaricare", + "part_waiting_sharpen": "{count} da affilare", + "part_waiting_clean": "{count} da pulire", + "part_waiting_dry": "{count} da asciugare", + "part_waiting_refill": "{count} da riempire", + "part_waiting_restore": "{count} da ripristinare", + "part_restoring": "Usati, non ancora pronti", + "part_ready_again_hint": "Tutti quelli usati sono di nuovo pronti", + "part_reuse_hint": "Un pezzo usato non è perso: aspetta di essere di nuovo pronto e conta ancora come posseduto, quindi non viene ricomprato.", "part_restock": "Correggi scorta", "parts_used_by": "Usato da", "restock_quantity_label": "Quantità acquistata", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Ordina per nome", "battery_fleet_sort_urgency": "Ordina per urgenza", "battery_fleet_mark_recharged": "Segna come ricaricata", + "battery_fleet_charging": "Ricambi ricaricabili", + "battery_fleet_ready": "{count} pronte", "battery_fleet_sparkline_hint": "Livello batteria degli ultimi 30 giorni — tratteggiato: proiezione fino alla soglia di batteria scarica", "battery_fleet_filter_type": "Mostra solo questo tipo di batteria", "battery_fleet_record_replacement": "Il livello è balzato intorno al {date} — registra questa sostituzione in Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/ja.json b/custom_components/maintenance_supporter/frontend/locales/ja.json index 4ea5d375..189950ec 100644 --- a/custom_components/maintenance_supporter/frontend/locales/ja.json +++ b/custom_components/maintenance_supporter/frontend/locales/ja.json @@ -888,7 +888,7 @@ "doc_link_title": "タイトル(任意)", "doc_open": "開く", "doc_delete_confirm": "「{name}」を削除しますか?", - "doc_too_large": "ファイルが大きすぎます(最大 25 MB)。", + "doc_too_large": "ファイルが大きすぎます(最大 100 MB)。", "doc_upload_failed": "アップロードに失敗しました。", "docs_archive_too_large": "アーカイブが大きすぎます(最大 {max})。", "docs_archive_no_manifest": "この ZIP には manifest.json がないため、復元時にファイルがどのドキュメントのものか判断できません。再度圧縮するときは manifest.json をフォルダーと同じ場所に置いてください。", @@ -903,7 +903,7 @@ "remove": "削除", "doc_deduped": "既に別の場所に保存済み — 共有され、追加容量はかかりません。", "doc_dup_in_object": "このファイルは既にこのオブジェクトに添付されています。", - "doc_link_invalid": "http/https のリンクのみ許可されています。", + "doc_link_not_allowed": "このリンクは使用できません。スクリプトを実行したりローカルファイルを開いたりするリンク(javascript:、data:、file: …)は拒否されます。", "doc_cat_manual": "取扱説明書", "doc_cat_warranty": "保証書", "doc_cat_invoice": "請求書", @@ -1078,6 +1078,23 @@ "part_restock_packages": "補充数(包装単位)", "part_package_hint": "包装単位で購入し、単位で使います。在庫、タスクごとの使用量、発注しきい値は単位で数え、補充数と価格は包装単位です。", "part_auto_buy": "在庫少で購入タスク", + "part_reuse": "使用後", + "part_reuse_none": "使い切り", + "part_reuse_charge": "充電済み", + "part_reuse_sharpen": "研ぎ済み", + "part_reuse_clean": "清掃済み", + "part_reuse_dry": "乾燥済み", + "part_reuse_refill": "補充済み", + "part_reuse_restore": "再生済み", + "part_waiting_charge": "充電待ち {count}", + "part_waiting_sharpen": "研ぎ待ち {count}", + "part_waiting_clean": "清掃待ち {count}", + "part_waiting_dry": "乾燥待ち {count}", + "part_waiting_refill": "補充待ち {count}", + "part_waiting_restore": "再生待ち {count}", + "part_restoring": "使用済み・未準備", + "part_ready_again_hint": "使用済みのものがすべて再び使えます", + "part_reuse_hint": "使用済みのものはなくなりません。再び使えるようになるまで待機し、所有数に含まれるため、買い直しは不要です。", "part_restock": "在庫を調整", "parts_used_by": "使用タスク", "restock_quantity_label": "購入数量", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "名前順に並べ替え", "battery_fleet_sort_urgency": "緊急度順に並べ替え", "battery_fleet_mark_recharged": "充電済みにする", + "battery_fleet_charging": "予備の充電池", + "battery_fleet_ready": "準備済み {count}", "battery_fleet_sparkline_hint": "過去30日間のバッテリー残量——点線:低残量しきい値までの予測", "battery_fleet_filter_type": "この電池タイプのみ表示", "battery_fleet_record_replacement": "{date}頃に残量が急上昇——この交換をBattery Notesに記録する", diff --git a/custom_components/maintenance_supporter/frontend/locales/ko.json b/custom_components/maintenance_supporter/frontend/locales/ko.json index 6a3d4669..055e116b 100644 --- a/custom_components/maintenance_supporter/frontend/locales/ko.json +++ b/custom_components/maintenance_supporter/frontend/locales/ko.json @@ -895,7 +895,7 @@ "doc_link_title": "제목 (선택)", "doc_open": "열기", "doc_delete_confirm": "\"{name}\"을(를) 삭제할까요?", - "doc_too_large": "파일이 너무 큽니다 (최대 25 MB).", + "doc_too_large": "파일이 너무 큽니다 (최대 100 MB).", "doc_upload_failed": "업로드에 실패했습니다.", "docs_archive_too_large": "아카이브가 너무 큽니다(최대 {max}).", "docs_archive_no_manifest": "이 ZIP에는 manifest.json이 없어 복원 시 파일이 어느 문서에 속하는지 알 수 없습니다. 다시 압축할 때 manifest.json을 폴더 옆에 두세요.", @@ -910,7 +910,7 @@ "remove": "제거", "doc_deduped": "이미 다른 곳에 저장됨 — 공유되어 추가 공간을 쓰지 않습니다.", "doc_dup_in_object": "이 파일은 이미 이 객체에 첨부되어 있습니다.", - "doc_link_invalid": "http/https 링크만 허용됩니다.", + "doc_link_not_allowed": "이 링크는 허용되지 않습니다. 스크립트를 실행하거나 로컬 파일을 여는 링크(javascript:, data:, file: …)는 거부됩니다.", "doc_cat_manual": "설명서", "doc_cat_warranty": "보증서", "doc_cat_invoice": "영수증", @@ -1085,6 +1085,23 @@ "part_restock_packages": "보충 수량(포장)", "part_package_hint": "포장 단위로 사고 단위로 씁니다. 재고, 작업당 사용량, 재주문 기준은 단위로 세고, 보충 수량과 가격은 포장 기준입니다.", "part_auto_buy": "재고 부족 시 구매 작업 자동 생성", + "part_reuse": "사용 후", + "part_reuse_none": "소모됨", + "part_reuse_charge": "충전됨", + "part_reuse_sharpen": "연마됨", + "part_reuse_clean": "세척됨", + "part_reuse_dry": "건조됨", + "part_reuse_refill": "리필됨", + "part_reuse_restore": "복원됨", + "part_waiting_charge": "충전 대기 {count}", + "part_waiting_sharpen": "연마 대기 {count}", + "part_waiting_clean": "세척 대기 {count}", + "part_waiting_dry": "건조 대기 {count}", + "part_waiting_refill": "리필 대기 {count}", + "part_waiting_restore": "복원 대기 {count}", + "part_restoring": "사용됨, 아직 준비 안 됨", + "part_ready_again_hint": "사용한 것이 모두 다시 준비됨", + "part_reuse_hint": "사용한 것은 없어지지 않습니다. 다시 준비될 때까지 대기하며 보유 수량에 계속 포함되므로 다시 구매하지 않습니다.", "part_restock": "재고 조정", "parts_used_by": "사용처", "restock_quantity_label": "구매 수량", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "이름순 정렬", "battery_fleet_sort_urgency": "긴급도순 정렬", "battery_fleet_mark_recharged": "충전 완료로 표시", + "battery_fleet_charging": "예비 충전지", + "battery_fleet_ready": "준비됨 {count}", "battery_fleet_sparkline_hint": "지난 30일간의 배터리 잔량 — 점선: 낮음 임계값까지의 예측", "battery_fleet_filter_type": "이 배터리 유형만 표시", "battery_fleet_record_replacement": "{date}쯤 잔량이 급상승했습니다 — 이 교체를 Battery Notes에 기록", diff --git a/custom_components/maintenance_supporter/frontend/locales/nb.json b/custom_components/maintenance_supporter/frontend/locales/nb.json index 77b795bd..0812410d 100644 --- a/custom_components/maintenance_supporter/frontend/locales/nb.json +++ b/custom_components/maintenance_supporter/frontend/locales/nb.json @@ -888,7 +888,7 @@ "doc_link_title": "Tittel (valgfritt)", "doc_open": "Åpne", "doc_delete_confirm": "Slette \"{name}\"?", - "doc_too_large": "Filen er for stor (maks. 25 MB).", + "doc_too_large": "Filen er for stor (maks. 100 MB).", "doc_upload_failed": "Opplasting mislyktes.", "docs_archive_too_large": "Arkivet er for stort (maks. {max}).", "docs_archive_no_manifest": "Denne ZIP-filen har ingen manifest.json, så gjenopprettingen vet ikke hvilket dokument en fil hører til. La manifest.json ligge ved siden av mappene når du zipper på nytt.", @@ -903,7 +903,7 @@ "remove": "Fjern", "doc_deduped": "Allerede lagret et annet sted — delt, ingen ekstra plass.", "doc_dup_in_object": "Denne filen er allerede knyttet til dette objektet.", - "doc_link_invalid": "Kun http/https-lenker er tillatt.", + "doc_link_not_allowed": "Denne lenken er ikke tillatt: lenker som kjører skript eller åpner lokale filer (javascript:, data:, file: …), avvises.", "doc_cat_manual": "Bruksanvisning", "doc_cat_warranty": "Garanti", "doc_cat_invoice": "Faktura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Påfyllingsmengde (pakninger)", "part_package_hint": "Kjøpes i pakninger, brukes i enheten: lager, forbruk per oppgave og bestillingsgrense teller enheter; påfyllingsmengde og pris gjelder per pakning.", "part_auto_buy": "Kjøpsoppgave ved lavt lager", + "part_reuse": "Etter bruk", + "part_reuse_none": "Brukt opp", + "part_reuse_charge": "Ladet", + "part_reuse_sharpen": "Slipt", + "part_reuse_clean": "Rengjort", + "part_reuse_dry": "Tørket", + "part_reuse_refill": "Etterfylt", + "part_reuse_restore": "Satt i stand", + "part_waiting_charge": "{count} skal lades", + "part_waiting_sharpen": "{count} skal slipes", + "part_waiting_clean": "{count} skal rengjøres", + "part_waiting_dry": "{count} skal tørkes", + "part_waiting_refill": "{count} skal etterfylles", + "part_waiting_restore": "{count} skal settes i stand", + "part_restoring": "Brukte, ikke klare ennå", + "part_ready_again_hint": "Alle brukte er klare igjen", + "part_reuse_hint": "En brukt er ikke borte: den venter til den er klar igjen og teller fortsatt som eid, så den kjøpes ikke på nytt.", "part_restock": "Juster lager", "parts_used_by": "Brukes av", "restock_quantity_label": "Kjøpt mengde", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sorter etter navn", "battery_fleet_sort_urgency": "Sorter etter hastegrad", "battery_fleet_mark_recharged": "Merk som oppladet", + "battery_fleet_charging": "Oppladbare reserver", + "battery_fleet_ready": "{count} klare", "battery_fleet_sparkline_hint": "Batterinivå de siste 30 dagene — stiplet: fremskrevet ned til lavnivåterskelen", "battery_fleet_filter_type": "Vis bare denne batteritypen", "battery_fleet_record_replacement": "Nivået hoppet rundt {date} — registrer dette byttet i Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/nl.json b/custom_components/maintenance_supporter/frontend/locales/nl.json index 58ccf04c..9d6188e5 100644 --- a/custom_components/maintenance_supporter/frontend/locales/nl.json +++ b/custom_components/maintenance_supporter/frontend/locales/nl.json @@ -888,7 +888,7 @@ "doc_link_title": "Titel (optioneel)", "doc_open": "Openen", "doc_delete_confirm": "\"{name}\" verwijderen?", - "doc_too_large": "Bestand is te groot (max. 25 MB).", + "doc_too_large": "Bestand is te groot (max. 100 MB).", "doc_upload_failed": "Uploaden mislukt.", "docs_archive_too_large": "Het archief is te groot (max. {max}).", "docs_archive_no_manifest": "Deze ZIP bevat geen manifest.json, dus het herstel weet niet bij welk document een bestand hoort. Laat manifest.json naast de mappen staan als je opnieuw zipt.", @@ -903,7 +903,7 @@ "remove": "Weghalen", "doc_deduped": "Al elders opgeslagen — gedeeld, geen extra ruimte.", "doc_dup_in_object": "Dit bestand is al aan dit object gekoppeld.", - "doc_link_invalid": "Alleen http/https-links zijn toegestaan.", + "doc_link_not_allowed": "Deze link is niet toegestaan: links die scripts uitvoeren of lokale bestanden openen (javascript:, data:, file: …) worden geweigerd.", "doc_cat_manual": "Handleiding", "doc_cat_warranty": "Garantie", "doc_cat_invoice": "Factuur", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Bijvulhoeveelheid (verpakkingen)", "part_package_hint": "Gekocht per verpakking, gebruikt per eenheid: voorraad, verbruik per taak en bestelgrens tellen eenheden; bijvulhoeveelheid en prijs gelden per verpakking.", "part_auto_buy": "Kooptaak bij lage voorraad", + "part_reuse": "Na gebruik", + "part_reuse_none": "Verbruikt", + "part_reuse_charge": "Opgeladen", + "part_reuse_sharpen": "Geslepen", + "part_reuse_clean": "Gereinigd", + "part_reuse_dry": "Gedroogd", + "part_reuse_refill": "Bijgevuld", + "part_reuse_restore": "Opgeknapt", + "part_waiting_charge": "{count} op te laden", + "part_waiting_sharpen": "{count} te slijpen", + "part_waiting_clean": "{count} te reinigen", + "part_waiting_dry": "{count} te drogen", + "part_waiting_refill": "{count} bij te vullen", + "part_waiting_restore": "{count} op te knappen", + "part_restoring": "Gebruikt, nog niet klaar", + "part_ready_again_hint": "Alle gebruikte zijn weer klaar", + "part_reuse_hint": "Een gebruikt exemplaar is niet weg: het wacht tot het weer klaar is en telt nog mee als bezit, dus het wordt niet opnieuw gekocht.", "part_restock": "Voorraad aanpassen", "parts_used_by": "Gebruikt door", "restock_quantity_label": "Gekochte hoeveelheid", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sorteren op naam", "battery_fleet_sort_urgency": "Sorteren op urgentie", "battery_fleet_mark_recharged": "Markeren als opgeladen", + "battery_fleet_charging": "Oplaadbare reserves", + "battery_fleet_ready": "{count} klaar", "battery_fleet_sparkline_hint": "Batterijniveau van de afgelopen 30 dagen — gestippeld: prognose tot de lage drempel", "battery_fleet_filter_type": "Alleen dit batterijtype tonen", "battery_fleet_record_replacement": "Het niveau maakte rond {date} een sprong — deze vervanging vastleggen in Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/pl.json b/custom_components/maintenance_supporter/frontend/locales/pl.json index 6a003bc6..8cc593a9 100644 --- a/custom_components/maintenance_supporter/frontend/locales/pl.json +++ b/custom_components/maintenance_supporter/frontend/locales/pl.json @@ -888,7 +888,7 @@ "doc_link_title": "Tytuł (opcjonalnie)", "doc_open": "Otwórz", "doc_delete_confirm": "Usunąć „{name}”?", - "doc_too_large": "Plik jest za duży (maks. 25 MB).", + "doc_too_large": "Plik jest za duży (maks. 100 MB).", "doc_upload_failed": "Przesyłanie nie powiodło się.", "docs_archive_too_large": "Archiwum jest za duże (maks. {max}).", "docs_archive_no_manifest": "Ten ZIP nie zawiera pliku manifest.json, więc przywracanie nie wie, do którego dokumentu należy plik. Przy ponownym pakowaniu zostaw manifest.json obok folderów.", @@ -903,7 +903,7 @@ "remove": "Usuń", "doc_deduped": "Już zapisany gdzie indziej — współdzielony, bez dodatkowego miejsca.", "doc_dup_in_object": "Ten plik jest już dołączony do tego obiektu.", - "doc_link_invalid": "Dozwolone są tylko linki http/https.", + "doc_link_not_allowed": "Ten link jest niedozwolony: linki uruchamiające skrypty lub otwierające pliki lokalne (javascript:, data:, file: …) są odrzucane.", "doc_cat_manual": "Instrukcja", "doc_cat_warranty": "Gwarancja", "doc_cat_invoice": "Faktura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Ilość uzupełnienia (opakowania)", "part_package_hint": "Kupowane w opakowaniach, zużywane w jednostkach: stan, zużycie na zadanie i próg zamówienia liczą jednostki; ilość uzupełnienia i cena dotyczą opakowania.", "part_auto_buy": "Zadanie zakupu przy niskim stanie", + "part_reuse": "Po użyciu", + "part_reuse_none": "Zużyty", + "part_reuse_charge": "Naładowany", + "part_reuse_sharpen": "Naostrzony", + "part_reuse_clean": "Wyczyszczony", + "part_reuse_dry": "Wysuszony", + "part_reuse_refill": "Napełniony", + "part_reuse_restore": "Odnowiony", + "part_waiting_charge": "{count} do naładowania", + "part_waiting_sharpen": "{count} do naostrzenia", + "part_waiting_clean": "{count} do wyczyszczenia", + "part_waiting_dry": "{count} do wysuszenia", + "part_waiting_refill": "{count} do napełnienia", + "part_waiting_restore": "{count} do odnowienia", + "part_restoring": "Zużyte, jeszcze niegotowe", + "part_ready_again_hint": "Wszystkie zużyte są znów gotowe", + "part_reuse_hint": "Zużyta część nie przepada: czeka, aż znów będzie gotowa, i nadal liczy się jako posiadana, więc nie kupuje się jej ponownie.", "part_restock": "Koryguj stan", "parts_used_by": "Używane przez", "restock_quantity_label": "Kupiona ilość", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sortuj według nazwy", "battery_fleet_sort_urgency": "Sortuj według pilności", "battery_fleet_mark_recharged": "Oznacz jako naładowaną", + "battery_fleet_charging": "Zapasowe akumulatorki", + "battery_fleet_ready": "{count} gotowe", "battery_fleet_sparkline_hint": "Poziom baterii z ostatnich 30 dni — kropkowana linia: prognoza do progu niskiego poziomu", "battery_fleet_filter_type": "Pokaż tylko ten typ baterii", "battery_fleet_record_replacement": "Poziom skoczył około {date} — zapisz tę wymianę w Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/pt-br.json b/custom_components/maintenance_supporter/frontend/locales/pt-br.json index 858cfb39..40644d8a 100644 --- a/custom_components/maintenance_supporter/frontend/locales/pt-br.json +++ b/custom_components/maintenance_supporter/frontend/locales/pt-br.json @@ -895,7 +895,7 @@ "doc_link_title": "Título (opcional)", "doc_open": "Abrir", "doc_delete_confirm": "Excluir \"{name}\"?", - "doc_too_large": "O arquivo é muito grande (máx. 25 MB).", + "doc_too_large": "O arquivo é muito grande (máx. 100 MB).", "doc_upload_failed": "Falha no envio.", "docs_archive_too_large": "O arquivo é grande demais (máx. {max}).", "docs_archive_no_manifest": "Este ZIP não tem manifest.json, então a restauração não sabe a qual documento cada arquivo pertence. Mantenha o manifest.json junto às pastas ao compactar de novo.", @@ -910,7 +910,7 @@ "remove": "Remover", "doc_deduped": "Já armazenado em outro lugar — compartilhado, sem uso de espaço extra.", "doc_dup_in_object": "Este arquivo já está anexado a este objeto.", - "doc_link_invalid": "Apenas links http/https são permitidos.", + "doc_link_not_allowed": "Este link não é permitido: links que executam scripts ou abrem arquivos locais (javascript:, data:, file: …) são recusados.", "doc_cat_manual": "Manual", "doc_cat_warranty": "Garantia", "doc_cat_invoice": "Nota fiscal", @@ -1085,6 +1085,23 @@ "part_restock_packages": "Quantidade de reposição (embalagens)", "part_package_hint": "Comprado em embalagens, usado por unidade: estoque, consumo por tarefa e limite de reposição contam unidades; quantidade de reposição e preço são por embalagem.", "part_auto_buy": "Criar tarefa de compra automaticamente quando estiver baixo", + "part_reuse": "Após o uso", + "part_reuse_none": "Consumido", + "part_reuse_charge": "Carregado", + "part_reuse_sharpen": "Afiado", + "part_reuse_clean": "Limpo", + "part_reuse_dry": "Seco", + "part_reuse_refill": "Reabastecido", + "part_reuse_restore": "Restaurado", + "part_waiting_charge": "{count} para carregar", + "part_waiting_sharpen": "{count} para afiar", + "part_waiting_clean": "{count} para limpar", + "part_waiting_dry": "{count} para secar", + "part_waiting_refill": "{count} para reabastecer", + "part_waiting_restore": "{count} para restaurar", + "part_restoring": "Usados, ainda não prontos", + "part_ready_again_hint": "Todos os usados estão prontos de novo", + "part_reuse_hint": "Uma peça usada não se perde: aguarda até ficar pronta de novo e continua contando como sua, então não é comprada de novo.", "part_restock": "Ajustar estoque", "parts_used_by": "Usado por", "restock_quantity_label": "Quantidade comprada", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Ordenar por nome", "battery_fleet_sort_urgency": "Ordenar por urgência", "battery_fleet_mark_recharged": "Marcar como recarregada", + "battery_fleet_charging": "Reservas recarregáveis", + "battery_fleet_ready": "{count} prontas", "battery_fleet_sparkline_hint": "Nível da bateria dos últimos 30 dias — pontilhado: projeção até o limite baixo", "battery_fleet_filter_type": "Mostrar apenas este tipo de pilha", "battery_fleet_record_replacement": "O nível deu um salto por volta de {date} — registrar esta substituição no Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/pt.json b/custom_components/maintenance_supporter/frontend/locales/pt.json index ceed3852..ba450d3c 100644 --- a/custom_components/maintenance_supporter/frontend/locales/pt.json +++ b/custom_components/maintenance_supporter/frontend/locales/pt.json @@ -888,7 +888,7 @@ "doc_link_title": "Título (opcional)", "doc_open": "Abrir", "doc_delete_confirm": "Eliminar «{name}»?", - "doc_too_large": "Ficheiro demasiado grande (máx. 25 MB).", + "doc_too_large": "Ficheiro demasiado grande (máx. 100 MB).", "doc_upload_failed": "Falha no carregamento.", "docs_archive_too_large": "O arquivo é demasiado grande (máx. {max}).", "docs_archive_no_manifest": "Este ZIP não contém manifest.json, pelo que o restauro não sabe a que documento pertence cada ficheiro. Mantenha o manifest.json junto às pastas ao comprimir novamente.", @@ -903,7 +903,7 @@ "remove": "Remover", "doc_deduped": "Já armazenado noutro local — partilhado, sem espaço extra.", "doc_dup_in_object": "Este ficheiro já está anexado a este objeto.", - "doc_link_invalid": "Apenas ligações http/https são permitidas.", + "doc_link_not_allowed": "Esta ligação não é permitida: ligações que executam scripts ou abrem ficheiros locais (javascript:, data:, file: …) são recusadas.", "doc_cat_manual": "Manual", "doc_cat_warranty": "Garantia", "doc_cat_invoice": "Fatura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Quantidade de reposição (embalagens)", "part_package_hint": "Comprado em embalagens, usado à unidade: o stock, o consumo por tarefa e o limite de encomenda contam unidades; a quantidade de reposição e o preço são por embalagem.", "part_auto_buy": "Tarefa de compra se baixo", + "part_reuse": "Após o uso", + "part_reuse_none": "Consumido", + "part_reuse_charge": "Carregado", + "part_reuse_sharpen": "Afiado", + "part_reuse_clean": "Limpo", + "part_reuse_dry": "Seco", + "part_reuse_refill": "Reabastecido", + "part_reuse_restore": "Restaurado", + "part_waiting_charge": "{count} por carregar", + "part_waiting_sharpen": "{count} por afiar", + "part_waiting_clean": "{count} por limpar", + "part_waiting_dry": "{count} por secar", + "part_waiting_refill": "{count} por reabastecer", + "part_waiting_restore": "{count} por restaurar", + "part_restoring": "Usados, ainda não prontos", + "part_ready_again_hint": "Todos os usados estão prontos de novo", + "part_reuse_hint": "Uma peça usada não se perde: aguarda até estar pronta de novo e continua a contar como sua, por isso não volta a ser comprada.", "part_restock": "Ajustar estoque", "parts_used_by": "Usado por", "restock_quantity_label": "Quantidade comprada", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Ordenar por nome", "battery_fleet_sort_urgency": "Ordenar por urgência", "battery_fleet_mark_recharged": "Marcar como recarregada", + "battery_fleet_charging": "Sobressalentes recarregáveis", + "battery_fleet_ready": "{count} prontas", "battery_fleet_sparkline_hint": "Nível da bateria dos últimos 30 dias — pontilhado: projeção até ao limiar baixo", "battery_fleet_filter_type": "Mostrar apenas este tipo de pilha", "battery_fleet_record_replacement": "O nível deu um salto por volta de {date} — registar esta substituição no Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/ru.json b/custom_components/maintenance_supporter/frontend/locales/ru.json index fd4d3ca0..ee380d4e 100644 --- a/custom_components/maintenance_supporter/frontend/locales/ru.json +++ b/custom_components/maintenance_supporter/frontend/locales/ru.json @@ -888,7 +888,7 @@ "doc_link_title": "Название (необязательно)", "doc_open": "Открыть", "doc_delete_confirm": "Удалить «{name}»?", - "doc_too_large": "Файл слишком большой (макс. 25 МБ).", + "doc_too_large": "Файл слишком большой (макс. 100 МБ).", "doc_upload_failed": "Не удалось загрузить.", "docs_archive_too_large": "Архив слишком большой (макс. {max}).", "docs_archive_no_manifest": "В этом ZIP нет manifest.json, поэтому при восстановлении неизвестно, к какому документу относится файл. При повторной упаковке оставляйте manifest.json рядом с папками.", @@ -903,7 +903,7 @@ "remove": "Убрать", "doc_deduped": "Уже сохранён в другом месте — общий, без доп. места.", "doc_dup_in_object": "Этот файл уже прикреплён к этому объекту.", - "doc_link_invalid": "Разрешены только ссылки http/https.", + "doc_link_not_allowed": "Эта ссылка не разрешена: ссылки, которые запускают скрипты или открывают локальные файлы (javascript:, data:, file: …), отклоняются.", "doc_cat_manual": "Инструкция", "doc_cat_warranty": "Гарантия", "doc_cat_invoice": "Счёт", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Количество для пополнения (упаковок)", "part_package_hint": "Покупается упаковками, расходуется единицами: запас, расход на задачу и порог дозаказа считаются в единицах; количество для пополнения и цена — за упаковку.", "part_auto_buy": "Задача покупки при малом запасе", + "part_reuse": "После использования", + "part_reuse_none": "Израсходован", + "part_reuse_charge": "Заряжен", + "part_reuse_sharpen": "Заточен", + "part_reuse_clean": "Очищен", + "part_reuse_dry": "Высушен", + "part_reuse_refill": "Заправлен", + "part_reuse_restore": "Восстановлен", + "part_waiting_charge": "{count} на зарядку", + "part_waiting_sharpen": "{count} на заточку", + "part_waiting_clean": "{count} на очистку", + "part_waiting_dry": "{count} на сушку", + "part_waiting_refill": "{count} на заправку", + "part_waiting_restore": "{count} на восстановление", + "part_restoring": "Использованы, ещё не готовы", + "part_ready_again_hint": "Все использованные снова готовы", + "part_reuse_hint": "Использованная деталь не пропадает: она ждёт, пока снова будет готова, и по-прежнему считается в наличии, поэтому её не покупают заново.", "part_restock": "Изменить запас", "parts_used_by": "Используется", "restock_quantity_label": "Куплено, шт.", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Сортировать по имени", "battery_fleet_sort_urgency": "Сортировать по срочности", "battery_fleet_mark_recharged": "Отметить как заряженную", + "battery_fleet_charging": "Запасные аккумуляторы", + "battery_fleet_ready": "{count} готово", "battery_fleet_sparkline_hint": "Уровень заряда за последние 30 дней — пунктир: прогноз до порога разряда", "battery_fleet_filter_type": "Показать только этот тип батарей", "battery_fleet_record_replacement": "Уровень резко вырос примерно {date} — записать эту замену в Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/sv.json b/custom_components/maintenance_supporter/frontend/locales/sv.json index 8cd11e51..de74e3ac 100644 --- a/custom_components/maintenance_supporter/frontend/locales/sv.json +++ b/custom_components/maintenance_supporter/frontend/locales/sv.json @@ -888,7 +888,7 @@ "doc_link_title": "Titel (valfritt)", "doc_open": "Öppna", "doc_delete_confirm": "Ta bort \"{name}\"?", - "doc_too_large": "Filen är för stor (max 25 MB).", + "doc_too_large": "Filen är för stor (max 100 MB).", "doc_upload_failed": "Uppladdningen misslyckades.", "docs_archive_too_large": "Arkivet är för stort (max {max}).", "docs_archive_no_manifest": "Den här ZIP-filen saknar manifest.json, så återställningen vet inte vilket dokument en fil hör till. Låt manifest.json ligga bredvid mapparna när du zippar igen.", @@ -903,7 +903,7 @@ "remove": "Ta bort", "doc_deduped": "Redan lagrad någon annanstans — delad, inget extra utrymme.", "doc_dup_in_object": "Den här filen är redan kopplad till detta objekt.", - "doc_link_invalid": "Endast http/https-länkar tillåts.", + "doc_link_not_allowed": "Den här länken är inte tillåten: länkar som kör skript eller öppnar lokala filer (javascript:, data:, file: …) avvisas.", "doc_cat_manual": "Manual", "doc_cat_warranty": "Garanti", "doc_cat_invoice": "Faktura", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Påfyllningsmängd (förpackningar)", "part_package_hint": "Köps i förpackningar, används i enheten: lager, åtgång per uppgift och beställningsgräns räknar enheter; påfyllningsmängd och pris gäller per förpackning.", "part_auto_buy": "Köpuppgift vid lågt lager", + "part_reuse": "Efter användning", + "part_reuse_none": "Förbrukad", + "part_reuse_charge": "Laddad", + "part_reuse_sharpen": "Slipad", + "part_reuse_clean": "Rengjord", + "part_reuse_dry": "Torkad", + "part_reuse_refill": "Påfylld", + "part_reuse_restore": "Återställd", + "part_waiting_charge": "{count} att ladda", + "part_waiting_sharpen": "{count} att slipa", + "part_waiting_clean": "{count} att rengöra", + "part_waiting_dry": "{count} att torka", + "part_waiting_refill": "{count} att fylla på", + "part_waiting_restore": "{count} att återställa", + "part_restoring": "Använda, inte klara än", + "part_ready_again_hint": "Alla använda är klara igen", + "part_reuse_hint": "En använd är inte borta: den väntar tills den är klar igen och räknas fortfarande som ägd, så den köps inte igen.", "part_restock": "Justera lager", "parts_used_by": "Används av", "restock_quantity_label": "Köpt antal", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Sortera efter namn", "battery_fleet_sort_urgency": "Sortera efter angelägenhet", "battery_fleet_mark_recharged": "Markera som uppladdad", + "battery_fleet_charging": "Laddbara reserver", + "battery_fleet_ready": "{count} klara", "battery_fleet_sparkline_hint": "Batterinivå de senaste 30 dagarna — prickad: prognos ner till lågnivåtröskeln", "battery_fleet_filter_type": "Visa endast denna batterityp", "battery_fleet_record_replacement": "Nivån hoppade omkring {date} — registrera detta byte i Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/tr.json b/custom_components/maintenance_supporter/frontend/locales/tr.json index b6194e71..ab761230 100644 --- a/custom_components/maintenance_supporter/frontend/locales/tr.json +++ b/custom_components/maintenance_supporter/frontend/locales/tr.json @@ -895,7 +895,7 @@ "doc_link_title": "Başlık (isteğe bağlı)", "doc_open": "Aç", "doc_delete_confirm": "\"{name}\" silinsin mi?", - "doc_too_large": "Dosya çok büyük (en fazla 25 MB).", + "doc_too_large": "Dosya çok büyük (en fazla 100 MB).", "doc_upload_failed": "Yükleme başarısız oldu.", "docs_archive_too_large": "Arşiv çok büyük (en fazla {max}).", "docs_archive_no_manifest": "Bu ZIP'te manifest.json yok, bu yüzden geri yükleme bir dosyanın hangi belgeye ait olduğunu bilemez. Yeniden sıkıştırırken manifest.json dosyasını klasörlerin yanında tutun.", @@ -910,7 +910,7 @@ "remove": "Kaldır", "doc_deduped": "Zaten başka bir yerde saklı — paylaşıldı, ek alan kullanılmadı.", "doc_dup_in_object": "Bu dosya zaten bu nesneye ekli.", - "doc_link_invalid": "Yalnızca http/https bağlantılarına izin verilir.", + "doc_link_not_allowed": "Bu bağlantıya izin verilmiyor: betik çalıştıran veya yerel dosyaları açan bağlantılar (javascript:, data:, file: …) reddedilir.", "doc_cat_manual": "Kılavuz", "doc_cat_warranty": "Garanti", "doc_cat_invoice": "Fatura", @@ -1085,6 +1085,23 @@ "part_restock_packages": "Yeniden stok miktarı (paket)", "part_package_hint": "Paketle alınır, birimle kullanılır: stok, görev başına kullanım ve yeniden sipariş eşiği birim sayar; yeniden stok miktarı ve fiyat paket başınadır.", "part_auto_buy": "Azaldığında otomatik satın alma görevi oluştur", + "part_reuse": "Kullanımdan sonra", + "part_reuse_none": "Tükendi", + "part_reuse_charge": "Şarj edildi", + "part_reuse_sharpen": "Bilendi", + "part_reuse_clean": "Temizlendi", + "part_reuse_dry": "Kurutuldu", + "part_reuse_refill": "Yeniden dolduruldu", + "part_reuse_restore": "Yenilendi", + "part_waiting_charge": "{count} şarj edilecek", + "part_waiting_sharpen": "{count} bilenecek", + "part_waiting_clean": "{count} temizlenecek", + "part_waiting_dry": "{count} kurutulacak", + "part_waiting_refill": "{count} doldurulacak", + "part_waiting_restore": "{count} yenilenecek", + "part_restoring": "Kullanılmış, henüz hazır değil", + "part_ready_again_hint": "Kullanılanların hepsi yeniden hazır", + "part_reuse_hint": "Kullanılan parça kaybolmaz: yeniden hazır olana kadar bekler ve hâlâ sahip olunan sayılır, bu yüzden yeniden satın alınmaz.", "part_restock": "Stoku ayarla", "parts_used_by": "Kullanan", "restock_quantity_label": "Satın alınan miktar", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Ada göre sırala", "battery_fleet_sort_urgency": "Aciliyete göre sırala", "battery_fleet_mark_recharged": "Şarj edildi olarak işaretle", + "battery_fleet_charging": "Yedek şarjlı piller", + "battery_fleet_ready": "{count} hazır", "battery_fleet_sparkline_hint": "Son 30 günün pil seviyesi — noktalı: düşük eşiğe kadar projeksiyon", "battery_fleet_filter_type": "Yalnızca bu pil türünü göster", "battery_fleet_record_replacement": "Seviye {date} civarında sıçradı — bu değişimi Battery Notes'a kaydet", diff --git a/custom_components/maintenance_supporter/frontend/locales/uk.json b/custom_components/maintenance_supporter/frontend/locales/uk.json index 4d36319a..687df054 100644 --- a/custom_components/maintenance_supporter/frontend/locales/uk.json +++ b/custom_components/maintenance_supporter/frontend/locales/uk.json @@ -888,7 +888,7 @@ "doc_link_title": "Назва (необов'язково)", "doc_open": "Відкрити", "doc_delete_confirm": "Видалити «{name}»?", - "doc_too_large": "Файл завеликий (макс. 25 МБ).", + "doc_too_large": "Файл завеликий (макс. 100 МБ).", "doc_upload_failed": "Не вдалося завантажити.", "docs_archive_too_large": "Архів завеликий (макс. {max}).", "docs_archive_no_manifest": "У цьому ZIP немає manifest.json, тому під час відновлення невідомо, до якого документа належить файл. Під час повторного пакування залишайте manifest.json поруч із теками.", @@ -903,7 +903,7 @@ "remove": "Прибрати", "doc_deduped": "Уже збережено в іншому місці — спільний, без додаткового місця.", "doc_dup_in_object": "Цей файл уже прикріплено до цього об'єкта.", - "doc_link_invalid": "Дозволені лише посилання http/https.", + "doc_link_not_allowed": "Це посилання не дозволено: посилання, які запускають скрипти або відкривають локальні файли (javascript:, data:, file: …), відхиляються.", "doc_cat_manual": "Інструкція", "doc_cat_warranty": "Гарантія", "doc_cat_invoice": "Рахунок", @@ -1078,6 +1078,23 @@ "part_restock_packages": "Кількість для поповнення (упаковок)", "part_package_hint": "Купується упаковками, витрачається одиницями: запас, витрата на завдання та поріг дозамовлення рахуються в одиницях; кількість для поповнення та ціна — за упаковку.", "part_auto_buy": "Завдання купівлі при малому запасі", + "part_reuse": "Після використання", + "part_reuse_none": "Витрачено", + "part_reuse_charge": "Заряджено", + "part_reuse_sharpen": "Заточено", + "part_reuse_clean": "Очищено", + "part_reuse_dry": "Висушено", + "part_reuse_refill": "Заправлено", + "part_reuse_restore": "Відновлено", + "part_waiting_charge": "{count} на заряджання", + "part_waiting_sharpen": "{count} на заточування", + "part_waiting_clean": "{count} на очищення", + "part_waiting_dry": "{count} на сушіння", + "part_waiting_refill": "{count} на заправку", + "part_waiting_restore": "{count} на відновлення", + "part_restoring": "Використані, ще не готові", + "part_ready_again_hint": "Усі використані знову готові", + "part_reuse_hint": "Використана деталь не зникає: вона чекає, доки знову буде готова, і далі рахується як наявна, тож її не купують знову.", "part_restock": "Змінити запас", "parts_used_by": "Використовується", "restock_quantity_label": "Куплена кількість", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "Сортувати за назвою", "battery_fleet_sort_urgency": "Сортувати за терміновістю", "battery_fleet_mark_recharged": "Позначити як заряджену", + "battery_fleet_charging": "Запасні акумулятори", + "battery_fleet_ready": "{count} готово", "battery_fleet_sparkline_hint": "Рівень заряду за останні 30 днів — пунктир: прогноз до порогу розряду", "battery_fleet_filter_type": "Показати лише цей тип батарей", "battery_fleet_record_replacement": "Рівень різко зріс приблизно {date} — записати цю заміну в Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/locales/zh.json b/custom_components/maintenance_supporter/frontend/locales/zh.json index 1f642541..8df8effd 100644 --- a/custom_components/maintenance_supporter/frontend/locales/zh.json +++ b/custom_components/maintenance_supporter/frontend/locales/zh.json @@ -888,7 +888,7 @@ "doc_link_title": "标题(可选)", "doc_open": "打开", "doc_delete_confirm": "删除“{name}”?", - "doc_too_large": "文件过大(最大 25 MB)。", + "doc_too_large": "文件过大(最大 100 MB)。", "doc_upload_failed": "上传失败。", "docs_archive_too_large": "压缩包过大(最大 {max})。", "docs_archive_no_manifest": "此 ZIP 中没有 manifest.json,因此恢复时无法判断文件属于哪个文档。重新压缩时请把 manifest.json 放在各文件夹旁边。", @@ -903,7 +903,7 @@ "remove": "移除", "doc_deduped": "已在别处存储——共享,不占用额外空间。", "doc_dup_in_object": "此文件已附加到该对象。", - "doc_link_invalid": "仅允许 http/https 链接。", + "doc_link_not_allowed": "不允许使用此链接:运行脚本或打开本地文件的链接(javascript:、data:、file: …)会被拒绝。", "doc_cat_manual": "手册", "doc_cat_warranty": "保修", "doc_cat_invoice": "发票", @@ -1078,6 +1078,23 @@ "part_restock_packages": "补货数量(包)", "part_package_hint": "按包购买、按单位使用:库存、每项任务用量和补货阈值都按单位计;补货数量和价格按包计。", "part_auto_buy": "库存低时自动建购买任务", + "part_reuse": "使用后", + "part_reuse_none": "已用完", + "part_reuse_charge": "已充电", + "part_reuse_sharpen": "已磨利", + "part_reuse_clean": "已清洁", + "part_reuse_dry": "已烘干", + "part_reuse_refill": "已重新灌装", + "part_reuse_restore": "已修复", + "part_waiting_charge": "{count} 个待充电", + "part_waiting_sharpen": "{count} 个待磨利", + "part_waiting_clean": "{count} 个待清洁", + "part_waiting_dry": "{count} 个待烘干", + "part_waiting_refill": "{count} 个待灌装", + "part_waiting_restore": "{count} 个待修复", + "part_restoring": "已用,尚未就绪", + "part_ready_again_hint": "所有已用的都已重新就绪", + "part_reuse_hint": "用过的不会消失:它会等待重新就绪,并仍计入已有数量,因此不会被再次购买。", "part_restock": "调整库存", "parts_used_by": "使用于", "restock_quantity_label": "购买数量", @@ -1255,6 +1272,8 @@ "battery_fleet_sort_name": "按名称排序", "battery_fleet_sort_urgency": "按紧急程度排序", "battery_fleet_mark_recharged": "标记为已充电", + "battery_fleet_charging": "备用充电电池", + "battery_fleet_ready": "{count} 个就绪", "battery_fleet_sparkline_hint": "过去 30 天的电池电量——虚线:外推至低电量阈值", "battery_fleet_filter_type": "仅显示此电池类型", "battery_fleet_record_replacement": "电量在 {date} 前后跳升——将此次更换记录到 Battery Notes", diff --git a/custom_components/maintenance_supporter/frontend/maintenance-calendar-card.js b/custom_components/maintenance_supporter/frontend/maintenance-calendar-card.js index ff12cc99..d0685e60 100644 --- a/custom_components/maintenance_supporter/frontend/maintenance-calendar-card.js +++ b/custom_components/maintenance_supporter/frontend/maintenance-calendar-card.js @@ -1,9 +1,9 @@ -/*! maintenance_supporter frontend 2.100.0 */ -var vr=Object.defineProperty;var va=Object.getOwnPropertyDescriptor;var y=(s,r,e)=>()=>{if(e)throw e[0];try{return s&&(r=s(s=0)),r}catch(t){throw e=[t],t}};var ya=(s,r)=>{for(var e in r)vr(s,e,{get:r[e],enumerable:!0})};var c=(s,r,e,t)=>{for(var i=t>1?void 0:t?va(r,e):r,a=s.length-1,o;a>=0;a--)(o=s[a])&&(i=(t?o(r,e,i):o(i))||i);return t&&i&&vr(r,e,i),i};var Pt,Lt,fi,yr,ct,br,E,xr,vi,yi=y(()=>{Pt=globalThis,Lt=Pt.ShadowRoot&&(Pt.ShadyCSS===void 0||Pt.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,fi=Symbol(),yr=new WeakMap,ct=class{constructor(r,e,t){if(this._$cssResult$=!0,t!==fi)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=r,this.t=e}get styleSheet(){let r=this.o,e=this.t;if(Lt&&r===void 0){let t=e!==void 0&&e.length===1;t&&(r=yr.get(e)),r===void 0&&((this.o=r=new CSSStyleSheet).replaceSync(this.cssText),t&&yr.set(e,r))}return r}toString(){return this.cssText}},br=s=>new ct(typeof s=="string"?s:s+"",void 0,fi),E=(s,...r)=>{let e=s.length===1?s[0]:r.reduce((t,i,a)=>t+(o=>{if(o._$cssResult$===!0)return o.cssText;if(typeof o=="number")return o;throw Error("Value passed to 'css' function must be a 'css' function result: "+o+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+s[a+1],s[0]);return new ct(e,s,fi)},xr=(s,r)=>{if(Lt)s.adoptedStyleSheets=r.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of r){let t=document.createElement("style"),i=Pt.litNonce;i!==void 0&&t.setAttribute("nonce",i),t.textContent=e.cssText,s.appendChild(t)}},vi=Lt?s=>s:s=>s instanceof CSSStyleSheet?(r=>{let e="";for(let t of r.cssRules)e+=t.cssText;return br(e)})(s):s});var ba,xa,wa,ka,$a,Ea,Nt,wr,Sa,Ta,dt,pt,qt,kr,ce,ut=y(()=>{yi();yi();({is:ba,defineProperty:xa,getOwnPropertyDescriptor:wa,getOwnPropertyNames:ka,getOwnPropertySymbols:$a,getPrototypeOf:Ea}=Object),Nt=globalThis,wr=Nt.trustedTypes,Sa=wr?wr.emptyScript:"",Ta=Nt.reactiveElementPolyfillSupport,dt=(s,r)=>s,pt={toAttribute(s,r){switch(r){case Boolean:s=s?Sa:null;break;case Object:case Array:s=s==null?s:JSON.stringify(s)}return s},fromAttribute(s,r){let e=s;switch(r){case Boolean:e=s!==null;break;case Number:e=s===null?null:Number(s);break;case Object:case Array:try{e=JSON.parse(s)}catch{e=null}}return e}},qt=(s,r)=>!ba(s,r),kr={attribute:!0,type:String,converter:pt,reflect:!1,useDefault:!1,hasChanged:qt};Symbol.metadata??=Symbol("metadata"),Nt.litPropertyMetadata??=new WeakMap;ce=class extends HTMLElement{static addInitializer(r){this._$Ei(),(this.l??=[]).push(r)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(r,e=kr){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(r)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(r,e),!e.noAccessor){let t=Symbol(),i=this.getPropertyDescriptor(r,t,e);i!==void 0&&xa(this.prototype,r,i)}}static getPropertyDescriptor(r,e,t){let{get:i,set:a}=wa(this.prototype,r)??{get(){return this[e]},set(o){this[e]=o}};return{get:i,set(o){let d=i?.call(this);a?.call(this,o),this.requestUpdate(r,d,t)},configurable:!0,enumerable:!0}}static getPropertyOptions(r){return this.elementProperties.get(r)??kr}static _$Ei(){if(this.hasOwnProperty(dt("elementProperties")))return;let r=Ea(this);r.finalize(),r.l!==void 0&&(this.l=[...r.l]),this.elementProperties=new Map(r.elementProperties)}static finalize(){if(this.hasOwnProperty(dt("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(dt("properties"))){let e=this.properties,t=[...ka(e),...$a(e)];for(let i of t)this.createProperty(i,e[i])}let r=this[Symbol.metadata];if(r!==null){let e=litPropertyMetadata.get(r);if(e!==void 0)for(let[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(let[e,t]of this.elementProperties){let i=this._$Eu(e,t);i!==void 0&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(r){let e=[];if(Array.isArray(r)){let t=new Set(r.flat(1/0).reverse());for(let i of t)e.unshift(vi(i))}else r!==void 0&&e.push(vi(r));return e}static _$Eu(r,e){let t=e.attribute;return t===!1?void 0:typeof t=="string"?t:typeof r=="string"?r.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(r=>this.enableUpdating=r),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(r=>r(this))}addController(r){(this._$EO??=new Set).add(r),this.renderRoot!==void 0&&this.isConnected&&r.hostConnected?.()}removeController(r){this._$EO?.delete(r)}_$E_(){let r=new Map,e=this.constructor.elementProperties;for(let t of e.keys())this.hasOwnProperty(t)&&(r.set(t,this[t]),delete this[t]);r.size>0&&(this._$Ep=r)}createRenderRoot(){let r=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return xr(r,this.constructor.elementStyles),r}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(r=>r.hostConnected?.())}enableUpdating(r){}disconnectedCallback(){this._$EO?.forEach(r=>r.hostDisconnected?.())}attributeChangedCallback(r,e,t){this._$AK(r,t)}_$ET(r,e){let t=this.constructor.elementProperties.get(r),i=this.constructor._$Eu(r,t);if(i!==void 0&&t.reflect===!0){let a=(t.converter?.toAttribute!==void 0?t.converter:pt).toAttribute(e,t.type);this._$Em=r,a==null?this.removeAttribute(i):this.setAttribute(i,a),this._$Em=null}}_$AK(r,e){let t=this.constructor,i=t._$Eh.get(r);if(i!==void 0&&this._$Em!==i){let a=t.getPropertyOptions(i),o=typeof a.converter=="function"?{fromAttribute:a.converter}:a.converter?.fromAttribute!==void 0?a.converter:pt;this._$Em=i;let d=o.fromAttribute(e,a.type);this[i]=d??this._$Ej?.get(i)??d,this._$Em=null}}requestUpdate(r,e,t,i=!1,a){if(r!==void 0){let o=this.constructor;if(i===!1&&(a=this[r]),t??=o.getPropertyOptions(r),!((t.hasChanged??qt)(a,e)||t.useDefault&&t.reflect&&a===this._$Ej?.get(r)&&!this.hasAttribute(o._$Eu(r,t))))return;this.C(r,e,t)}this.isUpdatePending===!1&&(this._$ES=this._$EP())}C(r,e,{useDefault:t,reflect:i,wrapped:a},o){t&&!(this._$Ej??=new Map).has(r)&&(this._$Ej.set(r,o??e??this[r]),a!==!0||o!==void 0)||(this._$AL.has(r)||(this.hasUpdated||t||(e=void 0),this._$AL.set(r,e)),i===!0&&this._$Em!==r&&(this._$Eq??=new Set).add(r))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}let r=this.scheduleUpdate();return r!=null&&await r,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(let[i,a]of this._$Ep)this[i]=a;this._$Ep=void 0}let t=this.constructor.elementProperties;if(t.size>0)for(let[i,a]of t){let{wrapped:o}=a,d=this[i];o!==!0||this._$AL.has(i)||d===void 0||this.C(i,void 0,a,d)}}let r=!1,e=this._$AL;try{r=this.shouldUpdate(e),r?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(t){throw r=!1,this._$EM(),t}r&&this._$AE(e)}willUpdate(r){}_$AE(r){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(r)),this.updated(r)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(r){return!0}update(r){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(r){}firstUpdated(r){}};ce.elementStyles=[],ce.shadowRootOptions={mode:"open"},ce[dt("elementProperties")]=new Map,ce[dt("finalized")]=new Map,Ta?.({ReactiveElement:ce}),(Nt.reactiveElementVersions??=[]).push("2.1.2")});function Nr(s,r){if(!Ti(s)||!s.hasOwnProperty("raw"))throw Error("invalid template strings array");return Er!==void 0?Er.createHTML(r):r}function Ue(s,r,e=s,t){if(r===Ie)return r;let i=t!==void 0?e._$Co?.[t]:e._$Cl,a=mt(r)?void 0:r._$litDirective$;return i?.constructor!==a&&(i?._$AO?.(!1),a===void 0?i=void 0:(i=new a(s),i._$AT(s,e,t)),t!==void 0?(e._$Co??=[])[t]=i:e._$Cl=i),i!==void 0&&(r=Ue(s,i._$AS(s,r.values),i,t)),r}var Si,$r,Ht,Er,Rr,me,Pr,Aa,Ce,_t,mt,Ti,Ca,bi,ht,Sr,Tr,Te,Ar,Cr,Lr,Ai,l,We,$l,Ie,h,Ir,Ae,Ia,gt,xi,ft,Be,wi,ki,$i,Ei,Ra,qr,Ot=y(()=>{Si=globalThis,$r=s=>s,Ht=Si.trustedTypes,Er=Ht?Ht.createPolicy("lit-html",{createHTML:s=>s}):void 0,Rr="$lit$",me=`lit$${Math.random().toFixed(9).slice(2)}$`,Pr="?"+me,Aa=`<${Pr}>`,Ce=document,_t=()=>Ce.createComment(""),mt=s=>s===null||typeof s!="object"&&typeof s!="function",Ti=Array.isArray,Ca=s=>Ti(s)||typeof s?.[Symbol.iterator]=="function",bi=`[ -\f\r]`,ht=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Sr=/-->/g,Tr=/>/g,Te=RegExp(`>|${bi}(?:([^\\s"'>=/]+)(${bi}*=${bi}*(?:[^ -\f\r"'\`<>=]|("|')|))|$)`,"g"),Ar=/'/g,Cr=/"/g,Lr=/^(?:script|style|textarea|title)$/i,Ai=s=>(r,...e)=>({_$litType$:s,strings:r,values:e}),l=Ai(1),We=Ai(2),$l=Ai(3),Ie=Symbol.for("lit-noChange"),h=Symbol.for("lit-nothing"),Ir=new WeakMap,Ae=Ce.createTreeWalker(Ce,129);Ia=(s,r)=>{let e=s.length-1,t=[],i,a=r===2?"":r===3?"":"",o=ht;for(let d=0;d"?(o=i??ht,f=-1):m[1]===void 0?f=-2:(f=o.lastIndex-m[2].length,_=m[1],o=m[3]===void 0?Te:m[3]==='"'?Cr:Ar):o===Cr||o===Ar?o=Te:o===Sr||o===Tr?o=ht:(o=Te,i=void 0);let w=o===Te&&s[d+1].startsWith("/>")?" ":"";a+=o===ht?p+Aa:f>=0?(t.push(_),p.slice(0,f)+Rr+p.slice(f)+me+w):p+me+(f===-2?d:w)}return[Nr(s,a+(s[e]||"")+(r===2?"":r===3?"":"")),t]},gt=class s{constructor({strings:r,_$litType$:e},t){let i;this.parts=[];let a=0,o=0,d=r.length-1,p=this.parts,[_,m]=Ia(r,e);if(this.el=s.createElement(_,t),Ae.currentNode=this.el.content,e===2||e===3){let f=this.el.content.firstChild;f.replaceWith(...f.childNodes)}for(;(i=Ae.nextNode())!==null&&p.length0){i.textContent=Ht?Ht.emptyScript:"";for(let w=0;w2||t[0]!==""||t[1]!==""?(this._$AH=Array(t.length-1).fill(new String),this.strings=t):this._$AH=h}_$AI(r,e=this,t,i){let a=this.strings,o=!1;if(a===void 0)r=Ue(this,r,e,0),o=!mt(r)||r!==this._$AH&&r!==Ie,o&&(this._$AH=r);else{let d=r,p,_;for(r=a[0],p=0;p{let t=e?.renderBefore??r,i=t._$litPart$;if(i===void 0){let a=e?.renderBefore??null;t._$litPart$=i=new ft(r.insertBefore(_t(),a),a,void 0,e??{})}return i._$AI(s),i}});var Ci,S,Pa,Hr=y(()=>{ut();ut();Ot();Ot();Ci=globalThis,S=class extends ce{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){let r=super.createRenderRoot();return this.renderOptions.renderBefore??=r.firstChild,r}update(r){let e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(r),this._$Do=qr(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return Ie}};S._$litElement$=!0,S.finalized=!0,Ci.litElementHydrateSupport?.({LitElement:S});Pa=Ci.litElementPolyfillSupport;Pa?.({LitElement:S});(Ci.litElementVersions??=[]).push("4.2.2")});var Or=y(()=>{});var I=y(()=>{ut();Ot();Hr();Or()});var jr=y(()=>{});function v(s){return(r,e)=>typeof e=="object"?Na(s,r,e):((t,i,a)=>{let o=i.hasOwnProperty(a);return i.constructor.createProperty(a,t),o?Object.getOwnPropertyDescriptor(i,a):void 0})(s,r,e)}var La,Na,Ii=y(()=>{ut();La={attribute:!0,type:String,converter:pt,reflect:!1,hasChanged:qt},Na=(s=La,r,e)=>{let{kind:t,metadata:i}=e,a=globalThis.litPropertyMetadata.get(i);if(a===void 0&&globalThis.litPropertyMetadata.set(i,a=new Map),t==="setter"&&((s=Object.create(s)).wrapped=!0),a.set(e.name,s),t==="accessor"){let{name:o}=e;return{set(d){let p=r.get.call(this);r.set.call(this,d),this.requestUpdate(o,p,s,!0,d)},init(d){return d!==void 0&&this.C(o,void 0,s,d),d}}}if(t==="setter"){let{name:o}=e;return function(d){let p=this[o];r.call(this,d),this.requestUpdate(o,p,s,!0,d)}}throw Error("Unsupported decorator location: "+t)}});function u(s){return v({...s,state:!0,attribute:!1})}var Dr=y(()=>{Ii();});var Mr=y(()=>{});var Ve=y(()=>{});var zr=y(()=>{Ve();});var Fr=y(()=>{Ve();});var Ur=y(()=>{Ve();});var Br=y(()=>{Ve();});var Wr=y(()=>{Ve();});var F=y(()=>{jr();Ii();Dr();Mr();zr();Fr();Ur();Br();Wr()});function Vr(s){return s==="use"?"use":"purchase"}function Gr(s){let r=Dt(s?.cost);if(r===null)return null;let e=Dt(s?.package_size);return e&&e>0?r/e:r}function Mt(s){let r=Dt(s.cost);if(s.cost_basis!=="use")return r;let e=Dt(s.parts_cost),t=s.purchase?null:r;return t===null&&e===null?null:(t??0)+(e??0)}var Dt,zt=y(()=>{"use strict";Dt=s=>typeof s=="number"&&Number.isFinite(s)?s:null});function Pi(s){return Ha[s??""]??Yr.length}var Ri,Yr,Ha,vt,Ft=y(()=>{"use strict";Ri={ok:"var(--success-color, #4caf50)",due_soon:"var(--warning-color, #ff9800)",overdue:"var(--error-color, #f44336)",triggered:"var(--deep-orange-color, #ff5722)",archived:"var(--disabled-color, #9e9e9e)",paused:"var(--info-color, #2196f3)"},Yr=["overdue","triggered","due_soon","ok"],Ha=Object.fromEntries(Yr.map((s,r)=>[s,r]));vt={ok:"mdi:check-circle",due_soon:"mdi:alert-circle",overdue:"mdi:alert-octagon",triggered:"mdi:bell-alert",archived:"mdi:archive-outline",paused:"mdi:pause-circle-outline",completed:"mdi:check-circle",skipped:"mdi:skip-next",missed:"mdi:calendar-remove",reset:"mdi:refresh"}});function yt(s){let r=Zr.get(s);if(r===void 0){try{r=new Intl.DateTimeFormat("en-US",{timeZone:s,hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch{r=null}Zr.set(s,r)}return r}function Xr(){if(Li===void 0){let s;try{s=new Intl.DateTimeFormat().resolvedOptions().timeZone}catch{}Li=s&&yt(s)?s:null}return Li}function es(){return Xr()??"UTC"}function ge(){let s=Jr.serverTimeZone;return s&&yt(s)?s:es()}function fe(){let s=Xr();return Jr.timeZone!=="server"&&s?s:ge()}function Ut(s,r){let e=yt(r)??yt(es())??yt("UTC"),t={};for(let i of e.formatToParts(s))i.type!=="literal"&&(t[i.type]=Number(i.value));return{y:t.year,mo:t.month,d:t.day,h:t.hour%24,mi:t.minute,s:t.second}}function ve(s,r){return qi(Ut(+s,r))}function Bt(s,r){let e=Ut(+s,r);return`${qi(e)}T${te(e.h)}:${te(e.mi)}`}function ye(){return ve(Date.now(),ge())}function ts(){return Bt(Date.now(),ge())}function Ni(s,r){let e=Ut(s,r);return Date.UTC(e.y,e.mo-1,e.d,e.h,e.mi,e.s)-Math.floor(s/1e3)*1e3}function Oa(s,r,e,t,i,a,o){let d=Date.UTC(s,r-1,e,t,i,a),p=Ni(d-Qr,o),_=Ni(d+Qr,o);for(let m of p===_?[p]:[p,_])if(Ni(d-m,o)===m)return d-m;return d-p}function is(s,r,e){if(s.has(r))return s.get(r);s.size>=Ma&&s.clear();let t=e();return s.set(r,t),t}function Q(s){if(typeof s!="string"||!s)return NaN;let r=Hi.exec(s);if(!r)return Date.parse(s);let e=ge();return is(Da,`${e}|${s}`,()=>{let[t,i,a,o,d,p]=[r[1],r[2],r[3],r[4]??"0",r[5]??"0",r[6]??"0"].map(Number);if(i<1||i>12||new Date(Date.UTC(t,i-1,a)).getUTCDate()!==a||o>23||d>59||p>59)return NaN;let _=r[7]?Math.floor(+`0.${r[7]}`*1e3):0;return Oa(t,i,a,o,d,p,e)+_})}function Wt(s){if(typeof s!="string"||!s)return null;let r=Hi.exec(s);if(r)return`${r[1]}-${r[2]}-${r[3]}`;let e=ge();return is(ja,`${e}|${s}`,()=>{let t=Date.parse(s);return Number.isFinite(t)?ve(t,e):/^\d{4}-\d{2}-\d{2}/.test(s)?s.slice(0,10):null})}function rs(s){if(typeof s!="string"||!s)return"";let r=Hi.exec(s);if(r)return`${r[1]}-${r[2]}-${r[3]}T${r[4]??"00"}:${r[5]??"00"}:${r[6]??"00"}`;let e=Date.parse(s);if(!Number.isFinite(e))return"";let t=Ut(e,ge());return`${qi(t)}T${te(t.h)}:${te(t.mi)}:${te(t.s)}`}function Re(s,r){let e=za.exec(s);if(!e)return s;let t=new Date(Date.UTC(Number(e[1]),Number(e[2])-1,Number(e[3])+Math.round(r)));return`${te(t.getUTCFullYear(),4)}-${te(t.getUTCMonth()+1)}-${te(t.getUTCDate())}`}var Jr,Qr,te,Zr,Li,qi,Hi,ja,Da,Ma,za,Z=y(()=>{"use strict";Jr=window.__msDateTimePrefs??={},Qr=864e5,te=(s,r=2)=>String(s).padStart(r,"0"),Zr=new Map;qi=s=>`${te(s.y,4)}-${te(s.mo)}-${te(s.d)}`;Hi=/^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?)?$/,ja=new Map,Da=new Map,Ma=2e4;za=/^(\d{4})-(\d{2})-(\d{2})$/});var ps,ds=y(()=>{ps={maintenance:"Maintenance",objects:"Objects",tasks:"Tasks",overdue:"Overdue",due_soon:"Due Soon",triggered:"Triggered",trigger_replaced:"Trigger replaced",trigger_removed:"Trigger removed",ok:"OK",all:"All",new_object:"+ New Object",templates_from:"From template",templates_title:"Start from a template",templates_task_count:"{n} tasks",templates_task_count_one:"1 task",template_created:"Created from template",onboard_hint:"Add your first object to start tracking maintenance.",edit:"Edit",duplicate:"Duplicate",task_duplicated:"Task duplicated",task_moved:"Task moved",move_task_target:"Target object",move_task_message:"Choose the object this task should belong to. Its history, readings and trigger state move with it; it gets a new reference number and its entities are recreated under the new object. Linked documents stay with the current object.",bulk_move_message:"Choose the object the selected tasks should belong to. Tasks that already live there are skipped; history, readings and trigger state move along.",bulk_moved:"{n} tasks moved",more_actions:"More actions",move_task_title:"Move task",move_task:"Move to another object\u2026",object_duplicated:"Object duplicated",delete:"Delete",add_task:"+ Add Task",complete:"Complete",completed:"Completed",skip:"Skip",skipped:"Skipped",missed:"Missed",reset:"Reset",snooze:"Snooze",snoozed:"Snoozed",snoozed_for:"Reminders muted for {hours} hours \u2014 until {until}",snoozed_for_one:"Reminders muted for one hour \u2014 until {until}",cancel:"Cancel",bulk_select:"Select",bulk_select_all:"Select all",bulk_n_selected:"{n} selected",bulk_completed:"{n} tasks completed",bulk_archived:"{n} tasks archived",bulk_delete_objects_confirm:"Delete {n} objects and all their tasks? Archiving keeps their history instead.",bulk_objects_deleted:"{n} objects deleted",bulk_objects_archived:"{n} objects archived",bulk_assign:"Assign",bulk_assign_one:"One person",bulk_assign_rotate:"Several people, in turns",bulk_assign_hint:"Replaces who is assigned to the selected tasks \u2014 a rotation included.",bulk_rotation_min_two:"Pick at least two people.",bulk_labels_add:"Add labels",bulk_labels_remove:"Remove labels",bulk_edit_hint:"Only the ticked settings change; everything else stays as it is.",bulk_no_notifications:"No notifications for these tasks",bulk_updated:"{n} tasks updated",bulk_paused:"{n} tasks paused",bulk_resumed:"{n} tasks resumed",bulk_objects_area:"Area set for {n} objects",bulk_failed:"{n} failed: {reason}",completing:"Completing\u2026",interval:"Interval",warning:"Warning",last_performed:"Last performed",last_done_days_ago:"done {n} d ago",last_done_today:"done today",next_due:"Next due",days_until_due:"Days until due",avg_duration:"Avg duration",trigger:"Trigger",trigger_type:"Trigger type",threshold_above:"Upper limit",threshold_below:"Lower limit",threshold:"Threshold",counter:"Counter",state_change:"State change",runtime:"Runtime",trigger_type_due_date:"Date from a sensor",runtime_hours:"Target runtime (hours)",days_before:"Days before the date",days_before_help:`For a sensor that reports when the maintenance is due (a date or timestamp). 0 = on the date itself. The device's own "done" button moves the date forward, which clears the trigger \u2014 make it the completion action.`,target_value:"Target value",target_changes:"Target changes",for_minutes:"For (minutes)",time_based:"Time-based",sensor_based:"Sensor-based",manual:"Manual",one_time:"One-time",weekdays:"Weekdays",nth_weekday:"Nth weekday of month",day_of_month:"Day of month",calendar:"Calendar entity",calendar_entity_label:"Calendar",calendar_entity_hint:"Due once per event of this calendar, on the event's start date \u2014 the next event after the last completion.",calendar_entity_required:"Choose a calendar entity.",recurrence_on_days:"Repeat on",recurrence_occurrence:"Occurrence",recurrence_weekday:"Weekday",recurrence_day:"Day of month (1\u201331)",recurrence_last_day:"Last day of the month",recurrence_business_day:"Business days only (roll back from weekend)",recurrence_offset:"Offset (days, \xB1)",recurrence_offset_help:"Shift the date by \xB1N days, e.g. -2 = two days before.",last_day_month:"Last day of month",last_business_day_month:"Last business day",ord_1:"1st",ord_2:"2nd",ord_3:"3rd",ord_4:"4th",ord_5:"5th",ord_last:"Last",day_word:"Day",interval_value:"Interval",interval_unit:"Unit",unit_days:"Days",unit_weeks:"Weeks",unit_months:"Months",unit_years:"Years",due_date:"Due date",cleaning:"Cleaning",inspection:"Inspection",replacement:"Replacement",calibration:"Calibration",service:"Service",reading:"Reading",custom:"Custom",history:"History",cost:"Cost",cost_kind_credit:"Credit",cost_credit_hint:"Money back \u2014 a sale, a refund. It lowers the totals; the average per completion leaves it out.",report_button:"Report",report_title:"Maintenance report",report_generated:"Generated",report_times_done:"Done",report_total_cost:"Total cost",report_notes:"Notes",report_col_type:"Type",report_col_status:"Status",report_col_schedule:"Schedule",duration:"Duration",minutes_short:"min",both:"Both",trigger_val:"Trigger value",complete_title:"Complete: ",checklist:"Checklist",require_on_completion:"Require on completion",checklist_steps_optional:"Checklist steps (optional)",checklist_placeholder:`Clean filter +/*! maintenance_supporter frontend 2.102.0 */ +var Hr=Object.defineProperty;var Ba=Object.getOwnPropertyDescriptor;var y=(s,r,e)=>()=>{if(e)throw e[0];try{return s&&(r=s(s=0)),r}catch(t){throw e=[t],t}};var Wa=(s,r)=>{for(var e in r)Hr(s,e,{get:r[e],enumerable:!0})};var c=(s,r,e,t)=>{for(var i=t>1?void 0:t?Ba(r,e):r,n=s.length-1,o;n>=0;n--)(o=s[n])&&(i=(t?o(r,e,i):o(i))||i);return t&&i&&Hr(r,e,i),i};var Nt,Ht,Ci,qr,pt,Or,E,Dr,Ii,Ri=y(()=>{Nt=globalThis,Ht=Nt.ShadowRoot&&(Nt.ShadyCSS===void 0||Nt.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Ci=Symbol(),qr=new WeakMap,pt=class{constructor(r,e,t){if(this._$cssResult$=!0,t!==Ci)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=r,this.t=e}get styleSheet(){let r=this.o,e=this.t;if(Ht&&r===void 0){let t=e!==void 0&&e.length===1;t&&(r=qr.get(e)),r===void 0&&((this.o=r=new CSSStyleSheet).replaceSync(this.cssText),t&&qr.set(e,r))}return r}toString(){return this.cssText}},Or=s=>new pt(typeof s=="string"?s:s+"",void 0,Ci),E=(s,...r)=>{let e=s.length===1?s[0]:r.reduce((t,i,n)=>t+(o=>{if(o._$cssResult$===!0)return o.cssText;if(typeof o=="number")return o;throw Error("Value passed to 'css' function must be a 'css' function result: "+o+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+s[n+1],s[0]);return new pt(e,s,Ci)},Dr=(s,r)=>{if(Ht)s.adoptedStyleSheets=r.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of r){let t=document.createElement("style"),i=Nt.litNonce;i!==void 0&&t.setAttribute("nonce",i),t.textContent=e.cssText,s.appendChild(t)}},Ii=Ht?s=>s:s=>s instanceof CSSStyleSheet?(r=>{let e="";for(let t of r.cssRules)e+=t.cssText;return Or(e)})(s):s});var Va,Ga,Ka,Ya,Qa,Za,qt,jr,Ja,Xa,ut,ht,Ot,Mr,ce,_t=y(()=>{Ri();Ri();({is:Va,defineProperty:Ga,getOwnPropertyDescriptor:Ka,getOwnPropertyNames:Ya,getOwnPropertySymbols:Qa,getPrototypeOf:Za}=Object),qt=globalThis,jr=qt.trustedTypes,Ja=jr?jr.emptyScript:"",Xa=qt.reactiveElementPolyfillSupport,ut=(s,r)=>s,ht={toAttribute(s,r){switch(r){case Boolean:s=s?Ja:null;break;case Object:case Array:s=s==null?s:JSON.stringify(s)}return s},fromAttribute(s,r){let e=s;switch(r){case Boolean:e=s!==null;break;case Number:e=s===null?null:Number(s);break;case Object:case Array:try{e=JSON.parse(s)}catch{e=null}}return e}},Ot=(s,r)=>!Va(s,r),Mr={attribute:!0,type:String,converter:ht,reflect:!1,useDefault:!1,hasChanged:Ot};Symbol.metadata??=Symbol("metadata"),qt.litPropertyMetadata??=new WeakMap;ce=class extends HTMLElement{static addInitializer(r){this._$Ei(),(this.l??=[]).push(r)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(r,e=Mr){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(r)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(r,e),!e.noAccessor){let t=Symbol(),i=this.getPropertyDescriptor(r,t,e);i!==void 0&&Ga(this.prototype,r,i)}}static getPropertyDescriptor(r,e,t){let{get:i,set:n}=Ka(this.prototype,r)??{get(){return this[e]},set(o){this[e]=o}};return{get:i,set(o){let d=i?.call(this);n?.call(this,o),this.requestUpdate(r,d,t)},configurable:!0,enumerable:!0}}static getPropertyOptions(r){return this.elementProperties.get(r)??Mr}static _$Ei(){if(this.hasOwnProperty(ut("elementProperties")))return;let r=Za(this);r.finalize(),r.l!==void 0&&(this.l=[...r.l]),this.elementProperties=new Map(r.elementProperties)}static finalize(){if(this.hasOwnProperty(ut("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(ut("properties"))){let e=this.properties,t=[...Ya(e),...Qa(e)];for(let i of t)this.createProperty(i,e[i])}let r=this[Symbol.metadata];if(r!==null){let e=litPropertyMetadata.get(r);if(e!==void 0)for(let[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(let[e,t]of this.elementProperties){let i=this._$Eu(e,t);i!==void 0&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(r){let e=[];if(Array.isArray(r)){let t=new Set(r.flat(1/0).reverse());for(let i of t)e.unshift(Ii(i))}else r!==void 0&&e.push(Ii(r));return e}static _$Eu(r,e){let t=e.attribute;return t===!1?void 0:typeof t=="string"?t:typeof r=="string"?r.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(r=>this.enableUpdating=r),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(r=>r(this))}addController(r){(this._$EO??=new Set).add(r),this.renderRoot!==void 0&&this.isConnected&&r.hostConnected?.()}removeController(r){this._$EO?.delete(r)}_$E_(){let r=new Map,e=this.constructor.elementProperties;for(let t of e.keys())this.hasOwnProperty(t)&&(r.set(t,this[t]),delete this[t]);r.size>0&&(this._$Ep=r)}createRenderRoot(){let r=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return Dr(r,this.constructor.elementStyles),r}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(r=>r.hostConnected?.())}enableUpdating(r){}disconnectedCallback(){this._$EO?.forEach(r=>r.hostDisconnected?.())}attributeChangedCallback(r,e,t){this._$AK(r,t)}_$ET(r,e){let t=this.constructor.elementProperties.get(r),i=this.constructor._$Eu(r,t);if(i!==void 0&&t.reflect===!0){let n=(t.converter?.toAttribute!==void 0?t.converter:ht).toAttribute(e,t.type);this._$Em=r,n==null?this.removeAttribute(i):this.setAttribute(i,n),this._$Em=null}}_$AK(r,e){let t=this.constructor,i=t._$Eh.get(r);if(i!==void 0&&this._$Em!==i){let n=t.getPropertyOptions(i),o=typeof n.converter=="function"?{fromAttribute:n.converter}:n.converter?.fromAttribute!==void 0?n.converter:ht;this._$Em=i;let d=o.fromAttribute(e,n.type);this[i]=d??this._$Ej?.get(i)??d,this._$Em=null}}requestUpdate(r,e,t,i=!1,n){if(r!==void 0){let o=this.constructor;if(i===!1&&(n=this[r]),t??=o.getPropertyOptions(r),!((t.hasChanged??Ot)(n,e)||t.useDefault&&t.reflect&&n===this._$Ej?.get(r)&&!this.hasAttribute(o._$Eu(r,t))))return;this.C(r,e,t)}this.isUpdatePending===!1&&(this._$ES=this._$EP())}C(r,e,{useDefault:t,reflect:i,wrapped:n},o){t&&!(this._$Ej??=new Map).has(r)&&(this._$Ej.set(r,o??e??this[r]),n!==!0||o!==void 0)||(this._$AL.has(r)||(this.hasUpdated||t||(e=void 0),this._$AL.set(r,e)),i===!0&&this._$Em!==r&&(this._$Eq??=new Set).add(r))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}let r=this.scheduleUpdate();return r!=null&&await r,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(let[i,n]of this._$Ep)this[i]=n;this._$Ep=void 0}let t=this.constructor.elementProperties;if(t.size>0)for(let[i,n]of t){let{wrapped:o}=n,d=this[i];o!==!0||this._$AL.has(i)||d===void 0||this.C(i,void 0,n,d)}}let r=!1,e=this._$AL;try{r=this.shouldUpdate(e),r?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(t){throw r=!1,this._$EM(),t}r&&this._$AE(e)}willUpdate(r){}_$AE(r){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(r)),this.updated(r)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(r){return!0}update(r){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(r){}firstUpdated(r){}};ce.elementStyles=[],ce.shadowRootOptions={mode:"open"},ce[ut("elementProperties")]=new Map,ce[ut("finalized")]=new Map,Xa?.({ReactiveElement:ce}),(qt.reactiveElementVersions??=[]).push("2.1.2")});function Qr(s,r){if(!qi(s)||!s.hasOwnProperty("raw"))throw Error("invalid template strings array");return Fr!==void 0?Fr.createHTML(r):r}function Re(s,r,e=s,t){if(r===Ie)return r;let i=t!==void 0?e._$Co?.[t]:e._$Cl,n=ft(r)?void 0:r._$litDirective$;return i?.constructor!==n&&(i?._$AO?.(!1),n===void 0?i=void 0:(i=new n(s),i._$AT(s,e,t)),t!==void 0?(e._$Co??=[])[t]=i:e._$Cl=i),i!==void 0&&(r=Re(s,i._$AS(s,r.values),i,t)),r}var Li,zr,Dt,Fr,Ni,de,Hi,eo,Ce,gt,ft,qi,Kr,Pi,mt,Ur,Br,Te,Wr,Vr,Yr,Oi,l,Ve,sc,Ie,u,Gr,Ae,Zr,vt,jt,We,Pe,Mt,zt,Ft,Ut,Jr,to,Xr,Ge=y(()=>{Li=globalThis,zr=s=>s,Dt=Li.trustedTypes,Fr=Dt?Dt.createPolicy("lit-html",{createHTML:s=>s}):void 0,Ni="$lit$",de=`lit$${Math.random().toFixed(9).slice(2)}$`,Hi="?"+de,eo=`<${Hi}>`,Ce=document,gt=()=>Ce.createComment(""),ft=s=>s===null||typeof s!="object"&&typeof s!="function",qi=Array.isArray,Kr=s=>qi(s)||typeof s?.[Symbol.iterator]=="function",Pi=`[ +\f\r]`,mt=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Ur=/-->/g,Br=/>/g,Te=RegExp(`>|${Pi}(?:([^\\s"'>=/]+)(${Pi}*=${Pi}*(?:[^ +\f\r"'\`<>=]|("|')|))|$)`,"g"),Wr=/'/g,Vr=/"/g,Yr=/^(?:script|style|textarea|title)$/i,Oi=s=>(r,...e)=>({_$litType$:s,strings:r,values:e}),l=Oi(1),Ve=Oi(2),sc=Oi(3),Ie=Symbol.for("lit-noChange"),u=Symbol.for("lit-nothing"),Gr=new WeakMap,Ae=Ce.createTreeWalker(Ce,129);Zr=(s,r)=>{let e=s.length-1,t=[],i,n=r===2?"":r===3?"":"",o=mt;for(let d=0;d"?(o=i??mt,f=-1):m[1]===void 0?f=-2:(f=o.lastIndex-m[2].length,_=m[1],o=m[3]===void 0?Te:m[3]==='"'?Vr:Wr):o===Vr||o===Wr?o=Te:o===Ur||o===Br?o=mt:(o=Te,i=void 0);let w=o===Te&&s[d+1].startsWith("/>")?" ":"";n+=o===mt?p+eo:f>=0?(t.push(_),p.slice(0,f)+Ni+p.slice(f)+de+w):p+de+(f===-2?d:w)}return[Qr(s,n+(s[e]||"")+(r===2?"":r===3?"":"")),t]},vt=class s{constructor({strings:r,_$litType$:e},t){let i;this.parts=[];let n=0,o=0,d=r.length-1,p=this.parts,[_,m]=Zr(r,e);if(this.el=s.createElement(_,t),Ae.currentNode=this.el.content,e===2||e===3){let f=this.el.content.firstChild;f.replaceWith(...f.childNodes)}for(;(i=Ae.nextNode())!==null&&p.length0){i.textContent=Dt?Dt.emptyScript:"";for(let w=0;w2||t[0]!==""||t[1]!==""?(this._$AH=Array(t.length-1).fill(new String),this.strings=t):this._$AH=u}_$AI(r,e=this,t,i){let n=this.strings,o=!1;if(n===void 0)r=Re(this,r,e,0),o=!ft(r)||r!==this._$AH&&r!==Ie,o&&(this._$AH=r);else{let d=r,p,_;for(r=n[0],p=0;p{let t=e?.renderBefore??r,i=t._$litPart$;if(i===void 0){let n=e?.renderBefore??null;t._$litPart$=i=new We(r.insertBefore(gt(),n),n,void 0,e??{})}return i._$AI(s),i}});var Di,S,io,es=y(()=>{_t();_t();Ge();Ge();Di=globalThis,S=class extends ce{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){let r=super.createRenderRoot();return this.renderOptions.renderBefore??=r.firstChild,r}update(r){let e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(r),this._$Do=Xr(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return Ie}};S._$litElement$=!0,S.finalized=!0,Di.litElementHydrateSupport?.({LitElement:S});io=Di.litElementPolyfillSupport;io?.({LitElement:S});(Di.litElementVersions??=[]).push("4.2.2")});var ts=y(()=>{});var I=y(()=>{_t();Ge();es();ts()});var is=y(()=>{});function v(s){return(r,e)=>typeof e=="object"?so(s,r,e):((t,i,n)=>{let o=i.hasOwnProperty(n);return i.constructor.createProperty(n,t),o?Object.getOwnPropertyDescriptor(i,n):void 0})(s,r,e)}var ro,so,ji=y(()=>{_t();ro={attribute:!0,type:String,converter:ht,reflect:!1,hasChanged:Ot},so=(s=ro,r,e)=>{let{kind:t,metadata:i}=e,n=globalThis.litPropertyMetadata.get(i);if(n===void 0&&globalThis.litPropertyMetadata.set(i,n=new Map),t==="setter"&&((s=Object.create(s)).wrapped=!0),n.set(e.name,s),t==="accessor"){let{name:o}=e;return{set(d){let p=r.get.call(this);r.set.call(this,d),this.requestUpdate(o,p,s,!0,d)},init(d){return d!==void 0&&this.C(o,void 0,s,d),d}}}if(t==="setter"){let{name:o}=e;return function(d){let p=this[o];r.call(this,d),this.requestUpdate(o,p,s,!0,d)}}throw Error("Unsupported decorator location: "+t)}});function h(s){return v({...s,state:!0,attribute:!1})}var rs=y(()=>{ji();});var ss=y(()=>{});var Ke=y(()=>{});var ns=y(()=>{Ke();});var as=y(()=>{Ke();});var os=y(()=>{Ke();});var ls=y(()=>{Ke();});var cs=y(()=>{Ke();});var F=y(()=>{is();ji();rs();ss();ns();as();os();ls();cs()});function ds(s){return s==="use"?"use":"purchase"}function ps(s){let r=Wt(s?.cost);if(r===null)return null;let e=Wt(s?.package_size);return e&&e>0?r/e:r}function Vt(s){let r=Wt(s.cost);if(s.cost_basis!=="use")return r;let e=Wt(s.parts_cost),t=s.purchase?null:r;return t===null&&e===null?null:(t??0)+(e??0)}var Wt,Gt=y(()=>{"use strict";Wt=s=>typeof s=="number"&&Number.isFinite(s)?s:null});function zi(s){return ao[s??""]??hs.length}var Mi,hs,ao,yt,Kt=y(()=>{"use strict";Mi={ok:"var(--success-color, #4caf50)",due_soon:"var(--warning-color, #ff9800)",overdue:"var(--error-color, #f44336)",triggered:"var(--deep-orange-color, #ff5722)",archived:"var(--disabled-color, #9e9e9e)",paused:"var(--info-color, #2196f3)"},hs=["overdue","triggered","due_soon","ok"],ao=Object.fromEntries(hs.map((s,r)=>[s,r]));yt={ok:"mdi:check-circle",due_soon:"mdi:alert-circle",overdue:"mdi:alert-octagon",triggered:"mdi:bell-alert",archived:"mdi:archive-outline",paused:"mdi:pause-circle-outline",completed:"mdi:check-circle",skipped:"mdi:skip-next",missed:"mdi:calendar-remove",reset:"mdi:refresh"}});function bt(s){let r=ms.get(s);if(r===void 0){try{r=new Intl.DateTimeFormat("en-US",{timeZone:s,hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch{r=null}ms.set(s,r)}return r}function fs(){if(Ui===void 0){let s;try{s=new Intl.DateTimeFormat().resolvedOptions().timeZone}catch{}Ui=s&&bt(s)?s:null}return Ui}function vs(){return fs()??"UTC"}function ge(){let s=gs.serverTimeZone;return s&&bt(s)?s:vs()}function fe(){let s=fs();return gs.timeZone!=="server"&&s?s:ge()}function Yt(s,r){let e=bt(r)??bt(vs())??bt("UTC"),t={};for(let i of e.formatToParts(s))i.type!=="literal"&&(t[i.type]=Number(i.value));return{y:t.year,mo:t.month,d:t.day,h:t.hour%24,mi:t.minute,s:t.second}}function ve(s,r){return Wi(Yt(+s,r))}function Qt(s,r){let e=Yt(+s,r);return`${Wi(e)}T${te(e.h)}:${te(e.mi)}`}function ye(){return ve(Date.now(),ge())}function ys(){return Qt(Date.now(),ge())}function Bi(s,r){let e=Yt(s,r);return Date.UTC(e.y,e.mo-1,e.d,e.h,e.mi,e.s)-Math.floor(s/1e3)*1e3}function lo(s,r,e,t,i,n,o){let d=Date.UTC(s,r-1,e,t,i,n),p=Bi(d-_s,o),_=Bi(d+_s,o);for(let m of p===_?[p]:[p,_])if(Bi(d-m,o)===m)return d-m;return d-p}function bs(s,r,e){if(s.has(r))return s.get(r);s.size>=uo&&s.clear();let t=e();return s.set(r,t),t}function Q(s){if(typeof s!="string"||!s)return NaN;let r=Vi.exec(s);if(!r)return Date.parse(s);let e=ge();return bs(po,`${e}|${s}`,()=>{let[t,i,n,o,d,p]=[r[1],r[2],r[3],r[4]??"0",r[5]??"0",r[6]??"0"].map(Number);if(i<1||i>12||new Date(Date.UTC(t,i-1,n)).getUTCDate()!==n||o>23||d>59||p>59)return NaN;let _=r[7]?Math.floor(+`0.${r[7]}`*1e3):0;return lo(t,i,n,o,d,p,e)+_})}function Zt(s){if(typeof s!="string"||!s)return null;let r=Vi.exec(s);if(r)return`${r[1]}-${r[2]}-${r[3]}`;let e=ge();return bs(co,`${e}|${s}`,()=>{let t=Date.parse(s);return Number.isFinite(t)?ve(t,e):/^\d{4}-\d{2}-\d{2}/.test(s)?s.slice(0,10):null})}function xs(s){if(typeof s!="string"||!s)return"";let r=Vi.exec(s);if(r)return`${r[1]}-${r[2]}-${r[3]}T${r[4]??"00"}:${r[5]??"00"}:${r[6]??"00"}`;let e=Date.parse(s);if(!Number.isFinite(e))return"";let t=Yt(e,ge());return`${Wi(t)}T${te(t.h)}:${te(t.mi)}:${te(t.s)}`}function Le(s,r){let e=ho.exec(s);if(!e)return s;let t=new Date(Date.UTC(Number(e[1]),Number(e[2])-1,Number(e[3])+Math.round(r)));return`${te(t.getUTCFullYear(),4)}-${te(t.getUTCMonth()+1)}-${te(t.getUTCDate())}`}var gs,_s,te,ms,Ui,Wi,Vi,co,po,uo,ho,Z=y(()=>{"use strict";gs=window.__msDateTimePrefs??={},_s=864e5,te=(s,r=2)=>String(s).padStart(r,"0"),ms=new Map;Wi=s=>`${te(s.y,4)}-${te(s.mo)}-${te(s.d)}`;Vi=/^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?)?$/,co=new Map,po=new Map,uo=2e4;ho=/^(\d{4})-(\d{2})-(\d{2})$/});var Cs,As=y(()=>{Cs={maintenance:"Maintenance",objects:"Objects",tasks:"Tasks",overdue:"Overdue",due_soon:"Due Soon",triggered:"Triggered",trigger_replaced:"Trigger replaced",trigger_removed:"Trigger removed",ok:"OK",all:"All",new_object:"+ New Object",templates_from:"From template",templates_title:"Start from a template",templates_task_count:"{n} tasks",templates_task_count_one:"1 task",template_created:"Created from template",onboard_hint:"Add your first object to start tracking maintenance.",edit:"Edit",duplicate:"Duplicate",task_duplicated:"Task duplicated",task_moved:"Task moved",move_task_target:"Target object",move_task_message:"Choose the object this task should belong to. Its history, readings and trigger state move with it; it gets a new reference number and its entities are recreated under the new object. Linked documents stay with the current object.",bulk_move_message:"Choose the object the selected tasks should belong to. Tasks that already live there are skipped; history, readings and trigger state move along.",bulk_moved:"{n} tasks moved",more_actions:"More actions",move_task_title:"Move task",move_task:"Move to another object\u2026",object_duplicated:"Object duplicated",delete:"Delete",add_task:"+ Add Task",complete:"Complete",completed:"Completed",skip:"Skip",skipped:"Skipped",missed:"Missed",reset:"Reset",snooze:"Snooze",snoozed:"Snoozed",snoozed_for:"Reminders muted for {hours} hours \u2014 until {until}",snoozed_for_one:"Reminders muted for one hour \u2014 until {until}",cancel:"Cancel",bulk_select:"Select",bulk_select_all:"Select all",bulk_n_selected:"{n} selected",bulk_completed:"{n} tasks completed",bulk_archived:"{n} tasks archived",bulk_delete_objects_confirm:"Delete {n} objects and all their tasks? Archiving keeps their history instead.",bulk_objects_deleted:"{n} objects deleted",bulk_objects_archived:"{n} objects archived",bulk_assign:"Assign",bulk_assign_one:"One person",bulk_assign_rotate:"Several people, in turns",bulk_assign_hint:"Replaces who is assigned to the selected tasks \u2014 a rotation included.",bulk_rotation_min_two:"Pick at least two people.",bulk_labels_add:"Add labels",bulk_labels_remove:"Remove labels",bulk_edit_hint:"Only the ticked settings change; everything else stays as it is.",bulk_no_notifications:"No notifications for these tasks",bulk_updated:"{n} tasks updated",bulk_paused:"{n} tasks paused",bulk_resumed:"{n} tasks resumed",bulk_objects_area:"Area set for {n} objects",bulk_failed:"{n} failed: {reason}",completing:"Completing\u2026",interval:"Interval",warning:"Warning",last_performed:"Last performed",last_done_days_ago:"done {n} d ago",last_done_today:"done today",next_due:"Next due",days_until_due:"Days until due",avg_duration:"Avg duration",trigger:"Trigger",trigger_type:"Trigger type",threshold_above:"Upper limit",threshold_below:"Lower limit",threshold:"Threshold",counter:"Counter",state_change:"State change",runtime:"Runtime",trigger_type_due_date:"Date from a sensor",runtime_hours:"Target runtime (hours)",days_before:"Days before the date",days_before_help:`For a sensor that reports when the maintenance is due (a date or timestamp). 0 = on the date itself. The device's own "done" button moves the date forward, which clears the trigger \u2014 make it the completion action.`,target_value:"Target value",target_changes:"Target changes",for_minutes:"For (minutes)",time_based:"Time-based",sensor_based:"Sensor-based",manual:"Manual",one_time:"One-time",weekdays:"Weekdays",nth_weekday:"Nth weekday of month",day_of_month:"Day of month",calendar:"Calendar entity",calendar_entity_label:"Calendar",calendar_entity_hint:"Due once per event of this calendar, on the event's start date \u2014 the next event after the last completion.",calendar_entity_required:"Choose a calendar entity.",recurrence_on_days:"Repeat on",recurrence_occurrence:"Occurrence",recurrence_weekday:"Weekday",recurrence_day:"Day of month (1\u201331)",recurrence_last_day:"Last day of the month",recurrence_business_day:"Business days only (roll back from weekend)",recurrence_offset:"Offset (days, \xB1)",recurrence_offset_help:"Shift the date by \xB1N days, e.g. -2 = two days before.",last_day_month:"Last day of month",last_business_day_month:"Last business day",ord_1:"1st",ord_2:"2nd",ord_3:"3rd",ord_4:"4th",ord_5:"5th",ord_last:"Last",day_word:"Day",interval_value:"Interval",interval_unit:"Unit",unit_days:"Days",unit_weeks:"Weeks",unit_months:"Months",unit_years:"Years",due_date:"Due date",cleaning:"Cleaning",inspection:"Inspection",replacement:"Replacement",calibration:"Calibration",service:"Service",reading:"Reading",custom:"Custom",history:"History",cost:"Cost",cost_kind_credit:"Credit",cost_credit_hint:"Money back \u2014 a sale, a refund. It lowers the totals; the average per completion leaves it out.",report_button:"Report",report_title:"Maintenance report",report_generated:"Generated",report_times_done:"Done",report_total_cost:"Total cost",report_notes:"Notes",report_col_type:"Type",report_col_status:"Status",report_col_schedule:"Schedule",duration:"Duration",minutes_short:"min",both:"Both",trigger_val:"Trigger value",complete_title:"Complete: ",checklist:"Checklist",require_on_completion:"Require on completion",checklist_steps_optional:"Checklist steps (optional)",checklist_placeholder:`Clean filter Replace seal -Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",ws_err_not_found:"Not found \u2014 it may have been deleted meanwhile",ws_err_invalid_input:"Invalid input",ws_err_invalid_date:"Invalid date",ws_err_invalid_format:"Invalid format",ws_err_invalid_url:"Invalid link",ws_err_invalid_mirror_todo:"Invalid to-do list",ws_err_not_configured:"Not set up yet",ws_err_not_loaded:"Not loaded yet \u2014 try again in a moment",ws_err_limit_reached:"Limit reached",ws_err_too_many:"Too many entries",ws_err_too_large:"Too large",ws_err_not_archived:"Not archived",ws_err_invalid_target:"Invalid target",ws_err_create_failed:"Could not be created",ws_err_archived:"Archived \u2014 restore it first",ws_err_already_archived:"Already archived",ws_err_unavailable:"Currently unavailable",ws_err_unauthorized:"Not permitted for your user",ws_err_too_many_views:"Too many saved views",ws_err_storage_unavailable:"Storage is not available",ws_err_replace_failed:"Replacement failed",ws_err_not_paused:"Not paused",ws_err_not_available:"Nothing available",ws_err_no_url:"No link given",ws_err_no_phases:"This task has no phases",ws_err_invalid_view:"Invalid view",ws_err_invalid_user:"Unknown user",ws_err_invalid_range:"Invalid range",ws_err_invalid_parent:"Invalid parent object",ws_err_invalid_device:"Unknown device",ws_err_empty_csv:"The CSV file is empty",ws_err_empty:"Nothing to import",ws_err_duplicate_failed:"Could not duplicate",ws_err_already_paused:"Already paused",ws_err_invalid_cursor:"Invalid phase position",ws_err_invalid_entity_slug:"Invalid entity name",ws_err_invalid_trigger_config:"Invalid trigger configuration",ws_err_no_defaults:"No quick-complete defaults set",ws_err_self_link_device:"An object cannot be linked to itself",ws_err_too_early:"Too early \u2014 this task can only be completed closer to its due date",ws_err_invalid_search_template:"The search link must be an http(s) URL containing {q}",ws_err_invalid_icon:"The notification icon must be an mdi: name, e.g. mdi:air-filter",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_toggle:"Due at a specific time",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",notes_markdown_hint:"Markdown is supported \u2014 **bold**, lists, [links](\u2026)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",completed_at_optional:"Completed at (optional, empty = now)",completed_at_pick:"Set date & time",completed_at_future_error:"The completion date cannot be in the future.",ha_time_zone_hint:"Time in Home Assistant's time zone ({zone})",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",task_mirror_todo:"Mirror into to-do lists",task_mirror_todo_hint:"The task appears in these lists while it is due; checking it off there completes it here.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",all_priorities:"All priorities",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",object_replaces:"Replaces",object_replaced_by:"Replaced by",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",all_parts:"All parts",all_areas:"All areas",areas_filter:"Filter areas\u2026",areas_filter_none:"No area matches the filter.",area_cost_year:"Cost {year}",area_object_count:"{n} objects",area_object_count_one:"1 object",area_range_12m:"Last 12 months",area_range_all:"All time",area_task_filter:"Filter by task\u2026",area_kpi_completions:"Completions",area_kpi_total_time:"Total time",area_cost_per_month:"Cost per month",area_cost_per_year:"Cost per year",area_cost_per_object:"Cost per object",area_cost_share:"Share",area_history_section:"History (all objects)",area_report_print:"Area report (PDF)",area_report_title:"Area report",area_report_period:"Period",area_no_costs:"No costs recorded in this period.",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",trigger_equals:"Trigger when equal to (=)",trigger_not_equals:"Trigger when different from (\u2260)",for_at_least_minutes:"For at least (minutes)",safety_interval:"Safety interval (optional)",trigger_combinator:"Combine trigger and interval",trigger_combinator_any:"Trigger or interval (whichever first)",trigger_combinator_all:"Trigger and interval (both required)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",adaptive_prediction_enabled:"Enable sensor-driven predictions",adaptive_seasonal_enabled:"Enable seasonal awareness",adaptive_max_interval:"Maximum interval (days)",adaptive_min_interval:"Minimum interval (days)",adaptive_ewa_alpha:"Learning rate (alpha)",adaptive_enabled:"Enable adaptive scheduling",adaptive_section_title:"Adaptive Scheduling",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:"Calendar",cal_no_events:"No maintenance",cal_every_n_days:"every {n} days",cal_every_day:"every day",cal_source_time:"Time-based",cal_source_time_adaptive:"Time-based (adaptive)",cal_source_sensor:"Sensor-based",cal_predicted:"predicted",cal_confidence_high:"high confidence",cal_confidence_medium:"medium confidence",cal_confidence_low:"low confidence",budget_monthly:"Monthly budget",budget_yearly:"Yearly budget",groups:"Groups",new_group:"New group",edit_group:"Edit group",no_groups:"No groups yet",delete_group:"Delete group",delete_group_confirm:"Delete group '{name}'?",group_select_tasks:"Select tasks",group_name_required:"Name is required",description_optional:"Description (optional)",selected:"Selected",loading_chart:"Loading chart data...",hide_outliers:"Hide outliers (sensor glitches)",was_maintenance_needed:"Was this maintenance needed?",feedback_needed:"Needed",feedback_not_needed:"Not needed",feedback_not_sure:"Not sure",suggested_interval:"Suggested interval",apply_suggestion:"Apply",reanalyze:"Re-analyze",reanalyze_result:"New analysis",reanalyze_insufficient_data:"Not enough data to produce a recommendation",data_points:"data points",dismiss_suggestion:"Dismiss",confidence_low:"Low",confidence_medium:"Medium",confidence_high:"High",recommended:"recommended",seasonal_awareness:"Seasonal Awareness",edit_seasonal_overrides:"Edit seasonal factors",seasonal_overrides_title:"Seasonal factors (override)",seasonal_overrides_hint:"Factor per month (0.1\u20135.0). Empty = learned automatically.",seasonal_override_invalid:"Invalid value",seasonal_override_range:"Factor must be between 0.1 and 5.0",clear_all:"Clear all",clear:"Clear",date_type_toggle:"Type the date",date_type_invalid:"Not a valid date \u2014 try 1978-03-15, a year like 1978, or your own date format",seasonal_chart_title:"Seasonal Factors",seasonal_learned:"Learned",seasonal_manual:"Manual",month_jan:"Jan",month_feb:"Feb",month_mar:"Mar",month_apr:"Apr",month_may:"May",month_jun:"Jun",month_jul:"Jul",month_aug:"Aug",month_sep:"Sep",month_oct:"Oct",month_nov:"Nov",month_dec:"Dec",sensor_prediction:"Sensor Prediction",degradation_trend:"Trend",trend_rising:"Rising",trend_falling:"Falling",trend_stable:"Stable",trend_insufficient_data:"Insufficient data",days_until_threshold:"Days until threshold",threshold_exceeded:"Threshold exceeded",environmental_adjustment:"Environmental factor",sensor_prediction_urgency:"Sensor predicts threshold in ~{days} days",day_short:"day",weibull_reliability_curve:"Reliability Curve",weibull_failure_probability:"Failure Probability",weibull_r_squared:"Fit R\xB2",beta_early_failures:"Early Failures",beta_random_failures:"Random Failures",beta_wear_out:"Wear-out",beta_highly_predictable:"Highly Predictable",confidence_interval:"Confidence Interval",confidence_conservative:"Conservative",confidence_aggressive:"Optimistic",current_interval_marker:"Current interval",recommended_marker:"Recommended",characteristic_life:"Characteristic life",chart_mini_sparkline:"Trend sparkline",chart_history:"Cost and duration history",chart_seasonal:"Seasonal factors, 12 months",chart_weibull:"Weibull reliability curve",chart_sparkline:"Sensor trigger value chart",days_progress:"Days progress",qr_code:"QR Code",qr_generating:"Generating QR code\u2026",qr_error:"Failed to generate QR code.",qr_error_no_url:"No HA URL configured. Please set an external or internal URL in Settings \u2192 System \u2192 Network.",save_error:"Failed to save. Please try again.",subsave_warning:"Saved, but one setting was rejected: {detail}",qr_print:"Print",qr_download:"Download SVG",qr_action_view:"View maintenance info",qr_action_complete:"Mark maintenance as complete",qr_action_quick_complete:"Quick-complete \u2014 no dialog",qr_print_quick_none:"Quick-complete codes need quick-complete defaults on a task (Settings \u2192 Advanced Features \u2192 Completion actions; task dialog \u2192 Quick-complete defaults) \u2014 none of the chosen objects' tasks has them yet.",qr_url_mode:"Link type",qr_mode_companion:"Companion App",qr_mode_local:"Local (mDNS)",qr_mode_server:"Server URL",overview:"Overview",strat_this_month:"This Month",strat_later:"Later",strat_week:"Week",strat_fortnight:"Fortnight",strat_month:"Month",strat_year:"Year",strat_other:"Other",strat_status:"Status",strat_empty_title:"No maintenance objects yet",strat_empty_content:"Open the Maintenance panel to add your first object \u2014 pool pump, HVAC filter, vehicle, anything that needs scheduled care.",strat_open_panel:"Open Maintenance panel",strat_add_object:"Add object",strat_not_loaded:"**Maintenance Supporter** is not loaded. Install/enable the integration first.",strat_group_by:"Group views by",strat_group_area:"By area (default)",strat_group_status:"By status (Overdue / Triggered / Due Soon / OK)",strat_group_floor:"By floor (uses HA floors)",strat_group_due_date:"By due date (Overdue / Today / Week / Month / Later)",strat_group_calendar:"Rolling calendar (Week / Fortnight / Month / Year)",strat_editor_help:'The "Overview" view is always first. Empty groups are skipped.',picker_name_calendar:"Maintenance Supporter \u2014 Calendar",picker_name_panel:"Maintenance Supporter \u2014 Panel",picker_name_budget:"Maintenance Supporter \u2014 Budget",picker_name_groups:"Maintenance Supporter \u2014 Groups",picker_name_vacation:"Maintenance Supporter \u2014 Vacation",picker_name_battery_fleet:"Battery Fleet",picker_name_section:"Maintenance Supporter \u2014 Section",picker_name_vacation_status:"Maintenance Supporter \u2014 Vacation Status",picker_name_budget_status:"Maintenance Supporter \u2014 Budget Status",picker_desc_card:"Overview of your maintenance tasks with quick actions.",picker_desc_calendar:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",picker_desc_panel:"The complete Maintenance Supporter panel as a card \u2014 for a panel view / dashboard subview without the sidebar entry.",picker_desc_budget:"Edit the monthly and yearly budget right on the dashboard.",picker_desc_groups:"Create, rename and delete task groups right on the dashboard.",picker_desc_vacation:"Switch vacation mode on or off and set its dates right on the dashboard.",picker_desc_battery_fleet:"All tracked batteries: what is low now, what runs out soon, and what to buy.",picker_desc_dashboard:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",picker_desc_section:"Embed maintenance tasks (filterable by area, status, due date) as a section in any dashboard view.",picker_desc_vacation_status:"Compact vacation-mode status banner. Tap to open settings in the panel.",picker_desc_budget_status:"Monthly + yearly maintenance budget overview. Tap for details.",picker_desc_groups_status:"List of configured task groups with member counts.",hist_note_button:"Completed from dashboard button",hist_note_todo:"Completed from the To-do list",hist_note_voice:"Completed by voice",hist_note_notification:"Completed from the notification",hist_note_nfc:"Completed via NFC tag",hist_note_shopping_list:"Completed from the shopping list",hist_note_todo_mirror:"Completed from a mirrored to-do list",hist_note_skipped_notification:"Skipped from notification",hist_note_skipped_button:"Skipped from dashboard button",hist_note_sensor_triggered:"Sensor trigger activated",hist_note_initial:"Initial value set during task creation",hist_note_auto_recovered:"Auto-completed: sensor recovered ({value})",hist_note_reset:"Reset to {date}",hist_note_trigger_replaced:"Trigger entity replaced: {old} \u2192 {new}",hist_note_trigger_removed:"Sensor trigger removed (entity was: {entity}). Schedule converted to {schedule}.",hist_note_compound_removed:"Entity {entity} removed from compound trigger; {count} conditions remain.",recent_activities:"Recent Activities",search_notes:"Search notes",avg_cost:"Avg Cost",current:"Current",shorter:"Shorter",longer:"Longer",normal:"Normal",disabled:"Disabled",compound_logic:"Compound logic",compound:"Compound (multiple conditions)",compound_logic_and:"AND \u2014 all conditions must trigger",compound_logic_or:"OR \u2014 any condition triggers",compound_help:"Combine several sensor conditions into one trigger.",compound_no_conditions:"No conditions yet \u2014 add at least one.",compound_add_condition:"Add condition",compound_condition:"Condition",compound_remove_condition:"Remove condition",card_title:"Title",card_show_header:"Show header with statistics",card_show_actions:"Show action buttons",card_action_style:"Complete button style",card_compact:"Compact mode",card_max_items:"Max items (0 = all)",card_filter_status:"Filter by status",card_filter_status_help:"Empty = show all statuses.",card_filter_objects:"Filter by objects",card_filter_objects_help:"Empty = show all objects.",card_filter_areas:"Filter by areas",card_filter_areas_help:"Empty = show all areas.",card_filter_priority_help:"Empty = show all priorities. Tasks without an explicit priority count as Normal.",card_filter_entities:"Filter by entities (entity_ids)",card_filter_entities_help:"Pick sensor / binary_sensor entities from this integration. Empty = all.",card_loading_objects:"Loading objects\u2026",card_load_error:"Could not load objects \u2014 check the WebSocket connection.",card_no_tasks_title:"No maintenance tasks yet",card_no_tasks_cta:"\u2192 Create one in the Maintenance panel",no_objects:"No objects yet.",action_error:"Action failed. Please try again.",area_id_optional:"Area (optional)",place_optional:"Place (zone, optional)",remind_on_site:"Remind only while somebody is there",remind_on_site_hint:"Reminders wait until somebody is in this zone. Whoever arrives there gets a message with what is due.",place_missing:"Zone not found: reminders as at home",place_home:"Home",installation_date_optional:"Installation date (optional)",warranty_expiry_optional:"Warranty expiry (optional)",warranty:"Warranty",warranty_valid_until:"valid until {date}",warranty_expires_in:"expires in {days} days",warranty_expired:"expired",cal_past_windows:"Past windows",cal_forward_windows:"Forward windows",history_edit_title:"Edit history entry",history_delete_entry:"Delete entry",history_delete_confirm_entry:"Delete this history entry? The task's last-performed date falls back to the previous completion; photos stay with the object.",history_delete_returns_parts:"The parts it used go back to stock: {parts}.",history_edit_timestamp:"Timestamp",manufacturer:"Manufacturer",model:"Model",area:"Area",actions:"Actions",view_mode_label:"View",view_cards:"Card view",view_table:"Table view",objects_table_columns_label:"Objects table columns",objects_table_columns_hint:"Choose which columns appear in the objects table view.",custom_icon_optional:"Icon (optional, e.g. mdi:wrench)",notify_icon:"Notification icon",notify_icon_hint:"Shown by the Companion app on Android. Empty = the icon of this task's maintenance type ({default}).",task_enabled:"Task enabled",skip_reason_prompt:"Skip this task?",reason_optional:"Reason (optional)",reset_date_prompt:"Mark task as performed?",reset_date_optional:"Last performed date (optional, defaults to today)",notes_label:"Notes",documentation_label:"Documentation",no_nfc_tag:"\u2014 No tag \u2014",dashboard:"Dashboard",tab_today:"Today",palette_placeholder:"Search objects, tasks, spare parts, documents, notes\u2026",palette_no_results:"No matches",palette_hint:"\u2191\u2193 to navigate \xB7 Enter to open \xB7 Esc to close \xB7 / opens the search anywhere",search_open:"Search",search_group_parts:"Spare parts",search_group_content:"In documents",search_group_history:"History notes",search_page:"Page {page}",search_empty_hint:"Type to search objects, tasks, spare parts, documents and notes",search_searching:"Searching documents and notes\u2026",search_index_status:"Full-text search: {indexed} of {total} files indexed \xB7 {no_text} without text layer \xB7 {pending} pending",today_all_caught_up:"All caught up! Nothing due this week.",today_overdue:"Overdue",today_due_today:"Due today",today_this_week:"This week",settings:"Settings",settings_features:"Advanced Features",settings_features_desc:"Enable or disable advanced features. Disabling hides them from the UI but does not delete data.",feat_adaptive:"Adaptive Scheduling",feat_adaptive_desc:"Learn optimal intervals from maintenance history",feat_seasonal:"Seasonal Adjustments",feat_seasonal_desc:"Adjust intervals based on seasonal patterns",feat_environmental:"Environmental Correlation",feat_environmental_desc:"Correlate intervals with temperature/humidity",feat_budget:"Budget Tracking",feat_budget_desc:"Track monthly and yearly maintenance spending",feat_groups:"Task Groups",feat_groups_desc:"Organize tasks into logical groups",feat_checklists:"Checklists",feat_checklists_desc:"Multi-step procedures for task completion",settings_general:"General",settings_default_warning:"Default warning days",settings_consumable_threshold:"Consumable low threshold (%)",settings_battery_low_percent:"Battery low threshold (%)",settings_battery_recovered_percent:"Battery counts as replaced above (%)",settings_battery_recovered_percent_hint:"A low battery stays counted as low until its level rises above this value or a replacement is recorded \u2014 so a level hovering around the low threshold cannot complete the fleet task again and again.",settings_battery_auto_record:"Record a replacement automatically when a low battery recovers",settings_battery_auto_record_hint:"When a battery that was low rises above the recovery threshold, the replacement date is recorded in Battery Notes and the spare cells are taken from stock \u2014 no tap needed.",settings_battery_lifetimes:"Typical battery lifetimes",settings_battery_lifetimes_hint:'Only used for batteries without a percentage: a Battery Notes note that has just a type and a last-replaced date, or a sensor that only reports "low". Their due date is last replaced + this lifetime. Batteries that report a level get their forecast from the measured discharge instead. Once the fleet has seen three replacements of a type, the median interval takes over from the built-in value \u2014 your own value always wins.',settings_battery_lifetime_months:"months",settings_battery_lifetime_reset:"Use default",settings_battery_lifetime_in_fleet:"in your fleet",settings_battery_lifetime_learned_models:"Learned per model: {list}",settings_thresholds_hint:"Defaults for new Suggested setups (percent-remaining consumables) and for fleet batteries without their own Battery Notes threshold. Existing tasks keep their value.",settings_part_search_url:"Shopping search link",settings_part_search_url_hint:"URL with {q} in place of the search terms, used for parts without a product link. Leave empty for the automatic store (by country, then by language).",settings_value_out_of_range:"Value must be between {min} and {max}",bn_summary:"{name}: {pct} % for {n} batteries",bn_floor_decides:"Your {floor} % floor decides for all of them; the higher of the two thresholds counts per battery.",bn_above_floor:"That is above your {floor} % floor, so {name} decides for all noted batteries.",bn_overrides:"{n} devices with their own threshold:",bn_more:"+ {n} more",settings_row_actions:"Task row actions",settings_ref_numbers_in_lists:"Reference numbers in lists",settings_ref_numbers_in_lists_hint:"Show the #8 / #8.3 chips in front of object and task names in the Today list, the task table, the object cards and the objects table.",settings_compact_refs:"Compact reference numbers",settings_compact_refs_hint:"Renumbers all objects, tasks and completions in order (1, 2, 3 \u2026) and closes the gaps left by deletions. Numbers already printed on service booklets, photos or notes will no longer match.",settings_compact_refs_confirm:"Renumber every object, task and completion sequentially in creation order? Numbers already written on printed service booklets, photos or notes will no longer match. This cannot be undone.",settings_compact_refs_done:"Renumbered {objects} objects, {tasks} tasks and {completions} completions.",row_actions_buttons_compact:"Buttons (icons only on phones)",row_actions_buttons:"Buttons with text",row_actions_icons:"Icons (classic)",row_actions_follow:"Follow the household setting",settings_panel_enabled:"Sidebar panel",settings_panel_title:"Sidebar panel title",settings_notifications:"Notifications",settings_notify_service:"Notification service",settings_shopping_list:"Shopping list (buy tasks)",settings_shopping_list_help:"Low-part buy reminders appear in this to-do list; checking one off restocks the part.",shopping_list_none:"Off \u2014 no shopping list",settings_install_assist_sentences:"Install Assist sentences",settings_install_assist_sentences_hint:"Copies the voice sentences into your configuration so the classic Assist agent recognises them. A file you edited yourself is never overwritten.",test_notification:"Test notification",send_test:"Send test",testing:"Sending\u2026",test_notification_success:"Test notification sent",test_notification_failed:"Test notification failed",notify_per_person:"Per-person delivery",member_avatars:"Member avatars",member_avatars_hint:"Shown next to assigned tasks \u2014 initials in the member's colour. Defaults come from the name; set your own initials or pick a colour to tell members apart.",member_initials:"Initials",member_color:"Colour",member_avatar_reset:"Reset",notify_no_own_device:"No own device \u2014 uses the household service",settings_notify_due_soon:"Notify when due soon",settings_notify_overdue:"Notify when overdue",settings_notify_triggered:"Notify when triggered",settings_interval_hours:"Repeat interval (hours, 0 = once)",settings_quiet_hours:"Quiet hours",settings_quiet_start:"Start",settings_quiet_end:"End",settings_max_per_day:"Max notifications per day (0 = unlimited)",settings_bundling:"Bundle notifications",settings_bundle_threshold:"Bundle threshold",settings_reminder_leads:"Extra reminders (days before due)",settings_reminder_leads_hint:"Comma-separated lead times, e.g. 14, 3, 0 \u2014 one extra reminder fires on each matching day. Empty = off.",settings_actions:"Mobile Action Buttons",settings_action_complete:"Show 'Complete' button",settings_action_skip:"Show 'Skip' button",settings_action_snooze:"Show 'Snooze' button",settings_weekly_digest:"Weekly digest",settings_weekly_digest_hint:"A single summary notification on Monday morning when tasks are due.",settings_warranty_reminder:"Warranty expiry reminder",settings_warranty_reminder_days:"Days before expiry",settings_warranty_reminder_hint:"Notify once when an object's warranty is this many days from expiring.",settings_snooze_hours:"Snooze duration (hours)",settings_snooze_hours_hint:"How long Snooze mutes a task's reminders \u2014 from the task menu, a card, voice or the phone's Snooze button. The due date stays as it is.",settings_budget:"Budget",settings_currency:"Currency",settings_currency_decimals:"Decimal places for amounts",settings_currency_decimals_hint:"How many decimals every amount shows: KPIs, budgets, costs in lists and reports, budget alerts. 0 = whole numbers.",settings_parts_cost_mode:"Spare parts count as spending",settings_parts_cost_purchase:"When bought",settings_parts_cost_use:"When used",settings_parts_cost_mode_hint:"When bought: a buy reminder's cost counts, and the parts a job uses are shown as information. When used: every completion books the value of the parts it used, and a purchase sets the part's price instead of counting. Applies to completions from now on \u2014 history keeps how it was booked.",settings_budget_monthly:"Monthly budget",settings_budget_yearly:"Yearly budget",settings_budget_alerts:"Budget alerts",settings_budget_threshold:"Alert threshold (%)",settings_import_export:"Import / Export",settings_export_json:"Export JSON",settings_export_yaml:"Export YAML",settings_export_csv:"Export CSV",settings_export_settings:"Export settings (JSON)",settings_import_placeholder:"Paste JSON or CSV content here\u2026",settings_import_btn:"Import",settings_import_success:"{count} objects imported successfully.",settings_import_unmatched_users:"Not found on this instance: {names}. Their task assignments were removed \u2014 add people with the same names in Home Assistant and import again to keep them.",settings_export_success:"Export downloaded.",settings_saved:"Setting saved.",settings_include_history:"Include history",settings_export_selection:"Limit to selected objects (optional)",settings_docs_archive:"Documents archive (with files)",settings_docs_archive_hint:"The JSON and YAML exports list your documents but not their files; CSV leaves documents out. This ZIP holds the uploaded files \u2014 restore it after importing the JSON and nothing is missing.",settings_docs_export_btn:"Download documents ZIP",settings_docs_import_btn:"Restore documents ZIP",settings_docs_import_success:"Restored: {blobs} files, {docs} documents",settings_docs_import_missing:"{n} skipped \u2014 their files were not in the ZIP",sort_alphabetical:"Alphabetical",sort_due_soonest:"Due soonest",sort_task_count:"Task count",sort_area:"Area",sort_assigned_user:"Assigned user",sort_group:"Group",groupby_none:"No grouping",groupby_area:"By area",groupby_group:"By group",groupby_user:"By user",groupby_object:"By object",filter_label:"Filter",user_label:"User",photo_label:"Photo",sort_label:"Sort",group_by_label:"Group by",state_value_help:'Use the HA state value (usually lowercase, e.g. "on"/"off"). Case is normalised on save.',target_changes_help:"Number of matching transitions before the trigger fires (default: 1).",state_latch_help:"With 1 transition the trigger is a latch: it recovers when the entity leaves the To-state \u2014 or, with only a From-state set, when it returns to that state.",for_minutes_state_help:"0 counts every change immediately. Set minutes and the new state must hold that long first \u2014 brief flickers then neither trigger nor count.",qr_print_title:"Print QR codes",qr_print_desc:"Generate a printable page of QR codes to cut out and stick on your equipment.",qr_print_load:"Load objects",qr_print_filter:"Filter",qr_print_objects:"Objects",qr_print_actions:"Actions",qr_print_url_mode:"Link type",qr_print_estimate:"Estimated QR codes",qr_print_over_limit:"cap is 200, narrow the filter",qr_print_generate:"Generate QR codes",qr_print_generating:"Generating\u2026",qr_print_ready:"QR codes ready",qr_print_print_button:"Print",qr_print_empty:"Nothing to generate",qr_action_skip:"Skip",vacation_title:"Vacation mode",vacation_active:"active",vacation_ended:"ended",vacation_desc:"Plan a vacation: notifications are paused during the period plus a buffer of days. You can opt specific tasks back in.",vacation_enable:"Enable vacation mode",vacation_start:"Start",vacation_end:"End",vacation_buffer:"Buffer (days)",vacation_exempt_title:"Notify anyway during vacation",vacation_exempt_desc:"Pick tasks that should still notify during vacation (e.g. critical pool chemistry).",vacation_load_tasks:"Load tasks",vacation_preview_btn:"Show preview",vacation_preview_affected:"tasks affected",vacation_event_due_soon:"becomes due soon",vacation_event_overdue:"becomes overdue",vacation_event_triggered_est:"sensor trigger possible",vacation_sensor_based:"(sensor-based)",vacation_action_notify:"Notify anyway",vacation_action_unsilence:"Silence again",vacation_marked_complete:"Marked complete",vacation_marked_skip:"Skipped",vacation_end_now:"End vacation now",add:"Add",show_stats:"Show stats + graphs",hide_stats:"Hide stats",adaptive_no_data:"Not enough completion history yet for adaptive analysis. Complete this task a few more times to unlock interval recommendations and reliability charts.",suggestion_applied:"Suggested interval applied",vacation_mode:"Vacation mode",vacation_status_active:"Active now",vacation_status_scheduled:"Scheduled",vacation_status_inactive:"Inactive",vacation_end_now_confirm:"End vacation immediately?",vacation_exempt_count:"exempt",vacation_advanced:"Advanced\u2026",vacation_open_panel:"Open in panel",enable:"Enable",saved:"Saved",budget_monthly_set:"Set monthly",budget_yearly_set:"Set yearly",budget_advanced:"Currency, alerts\u2026",budget_open_panel:"Open in panel",groups_empty:"No groups yet.",group_new_placeholder:"Add group\u2026",groups_manage_tasks:"Manage task assignments\u2026",groups_open_panel:"Open in panel",unassigned:"Unassigned",no_area:"No area",has_overdue:"Has overdue tasks",object:"Object",settings_panel_access:"Panel access",settings_panel_access_desc:"Admins always have full access. To delegate create, edit and delete to specific non-admins, switch this on and pick them below \u2014 everyone else only gets Complete, Skip, Reset, Postpone and Snooze.",settings_operator_write:"Allow selected users to create, edit & delete",settings_operator_write_desc:"Off: only admins can change content. On: the selected users below get full access too.",no_non_admin_users:"No non-admin users found. Add some in Settings \u2192 People.",owner_label:"Owner",feat_completion_actions:"Completion actions",feat_completion_actions_desc:"Per-task HA action on complete + quick-complete QR with pre-set values.",feat_places:"Places",feat_places_desc:"Objects maintained at another place (a Home Assistant zone): reminders only while somebody is there, and a message on arrival.",on_complete_action_title:"On complete: trigger HA action (optional)",on_complete_action_desc:"Calls an HA service when the task is completed \u2014 e.g. reset a counter on the device.",on_complete_action_target:"Target entity",on_complete_action_target_hint:"Note: the entity domain must match the service \u2014 e.g. 'button.press' only works on button.*, 'counter.increment' only on counter.*, 'input_button.press' only on input_button.* etc. On a mismatch the action will silently fail (HA logs 'Referenced entities ... missing or not currently available').",on_complete_action_target_more:"This action targets more than this field shows: {targets}. That is kept as it is \u2014 choosing another entity here replaces the whole target.",on_complete_action_skip_auto:"Not when the task completes itself (its sensor recovered)",on_complete_action_data:"Data (JSON, optional)",on_complete_action_test:"Validate configuration",on_complete_action_test_success:"\u2713 Configuration valid (action will fire only on task completion)",on_complete_action_test_failed:"Failed",action_test_bad_format:"Invalid service format (expected 'domain.service')",action_test_unknown_service:'Service "{service}" is not registered in Home Assistant. Check the spelling and that the integration providing it is loaded.',action_test_domain_mismatch:`Service "{service}" only works on {domain}.* entities; entity "{entity}" is in {entity_domain}.* \u2014 pick a service that matches the entity's domain (e.g. {suggestion})`,action_test_entity_missing:'Target entity "{entity}" was not found in Home Assistant \u2014 it may have been renamed or its integration removed.',quick_complete_defaults_title:"Quick-complete defaults (for QR scans, optional)",quick_complete_defaults_desc:"Pre-set values for quick-complete QR scans. Without these, the QR opens the complete dialog.",quick_complete_defaults_notes:"Notes",quick_complete_defaults_cost:"Cost",quick_complete_defaults_duration:"Duration (minutes)",quick_complete_defaults_feedback_none:"No feedback",quick_complete_defaults_feedback_needed:"Was needed",quick_complete_defaults_feedback_not_needed:"Not needed",quick_complete_success:"Quickly marked complete",show_all_objects:"Show all objects",show_all_tasks:"Clear filter \u2014 show all tasks",filter_to_overdue:"Filter task list to overdue only",filter_to_due_soon:"Filter task list to due-soon only",filter_to_triggered:"Filter task list to triggered only",open_task:"Open task",show_details:"Show history + stats",hide_details:"Hide details",history_empty:"No history yet.",history_edit_button:"Edit entry",total_cost:"Total cost",times_performed:"Performed",older_entries:"older",open_in_panel:"Open in Maintenance panel",skip_reason:"Skip reason (optional)",reset_to_date:"Reset last_performed to",delete_task_confirm:"Delete this task and its history?",delete_object_confirm:"Delete this object and all its tasks?",loading:"Loading\u2026",archive:"Archive",undo:"Undo",task_completed_named:"Completed: {task}",undo_done:"Completion undone",undo_done_action_ran:"Completion undone. Its completion action had already run and cannot be taken back.",undo_nothing:"Nothing to undo. Only your own last completion can be taken back, within 10 minutes.",undo_changed:"Can't undo. The task has changed since.",task_archived:"Task archived",object_archived:"Object archived",unarchive:"Unarchive",archived:"Archived",show_archived:"Show archived",hide_archived:"Hide archived",section_collapse:"Collapse section",section_expand:"Expand section",confirm_archive_object:"Archive this object and its tasks? They keep their history and can be unarchived later.",settings_archive:"Archive & Retention",settings_archive_desc:"Retire completed one-off tasks without deleting them. Archived items are hidden and inert but keep their history and cost.",settings_archive_oneoff_days:"Auto-archive completed one-off tasks after (days, 0 = off)",settings_delete_archived_oneoff_days:"Auto-delete archived one-off tasks after (days, 0 = never)",archive_object:"Archive object",unarchive_object:"Unarchive object",documents:"Documents",documents_empty:"No documents yet.",doc_upload:"Upload file",doc_uploading:"Uploading\u2026",doc_add_link:"Add link",doc_link_url:"URL (https://\u2026)",doc_link_title:"Title (optional)",doc_open:"Open",doc_delete_confirm:'Delete "{name}"?',doc_too_large:"File is too large (max 25 MB).",doc_upload_failed:"Upload failed.",docs_archive_too_large:"The archive is too large (max {max}).",docs_archive_no_manifest:"This ZIP has no manifest.json, so the restore cannot tell which document a file belongs to. Keep manifest.json next to the folders when zipping again.",completion_photos_optional:"Completion photos (optional)",completion_photos:"Completion photos",choose_photos:"Choose photos",choose_photo:"Choose photo",photos_android_hint:"The Android app hands over one photo per pick \u2014 each pick is added.",photos_limit:"Up to {max} photos per completion",history_edit_photos_hint:"Removing a photo here keeps the file in the object's documents.",uploading:"Uploading\u2026",remove:"Remove",doc_deduped:"Already stored elsewhere \u2014 shared, no extra space used.",doc_dup_in_object:"This file is already attached to this object.",doc_link_invalid:"Only http/https links are allowed.",doc_cat_manual:"Manual",doc_cat_warranty:"Warranty",doc_cat_invoice:"Invoice",doc_cat_spare_parts:"Spare parts",doc_cat_photo:"Photo",doc_cat_other:"Other",doc_link_badge:"Link",doc_storage_title:"Document storage",doc_storage_saved:"Saved via deduplication",doc_storage_refresh:"Refresh",doc_download:"Download",doc_close:"Close",doc_camera:"Take photo",camera_capture_shoot:"Capture",camera_switch_lens:"Switch camera",camera_switching:"Switching camera\u2026",camera_not_answered:"This camera did not answer. Tap the switch again to try the next one, or use the file picker.",camera_diagnostics:"Details for a bug report",camera_copy:"Copy",camera_copied:"Copied",doc_drop_hint:"Drop files here",doc_task_none:"No documents linked to this task.",doc_link_existing:"Link a document\u2026",doc_attach:"Link",doc_unlink:"Unlink",doc_page:"Page",chart_range_7d:"7d",chart_range_30d:"30d",chart_range_90d:"90d",chart_range_1y:"1y",chart_since_service:"since last service",chart_no_stats:"No long-term statistics for this entity \u2014 showing maintenance-event values only",auto_complete_on_recovery:"Auto-complete when the sensor recovers",auto_complete_on_recovery_help:"Records a completion (sets last performed) when the trigger clears itself \u2014 e.g. salt refilled, filter replaced.",doc_search:"Search documents\u2026",doc_search_none:"No matching documents",doc_description:"Description (optional)",doc_sort:"Sort documents",doc_sort_newest:"Newest first",doc_sort_oldest:"Oldest first",doc_sort_title:"By title (1, 2, 3 \u2026)",doc_sort_category:"By category",link_device_optional:"Link to existing device (optional)",parent_object_optional:"Parent object (optional)",parent_none:"(No parent)",paused:"Paused",pause_object:"Pause",resume_object:"Resume",pause_task:"Pause",resume_task:"Resume",pause_task_prompt:"Freeze this task's schedule \u2014 it does not become due and does not notify until you resume it, and resuming starts a fresh cycle from that day. The object's other tasks keep running. Optionally set a date to resume by itself.",task_paused:"Task paused",task_resumed:"Task resumed \u2014 its schedule restarted",pause_until_prompt:"Freeze this object's schedules \u2014 nothing becomes due and nothing notifies until it is resumed. Optionally set an auto-resume date.",pause_until_label:"Resume on (optional)",object_paused:"Object paused",object_resumed:"Object resumed \u2014 schedules restarted",object_paused_badge:"Paused",paused_until_label:"until",replace_object:"Replace\u2026",replace_object_prompt:"Retire this object and create a successor. History and costs stay archived on the old one; tasks and documents carry over to the new one, counters start fresh.",replace_name_label:"Successor name",replace_device_heading:"Device in Home Assistant",replace_device_keep:"Same device as before ({device})",replace_device_keep_hint:"Also the choice when the new unit is not in Home Assistant yet: once it is, pick it as the object's device in its settings \u2014 the sensor triggers move along then.",replace_device_other:"The new unit is another device",replace_device_pick:"Device of the new unit",replace_device_other_hint:"Sensor triggers, completion actions and the counter reset move to the matching entities of that device.",replace_device_none:"No device",object_replaced:"Object replaced \u2014 successor created",device_swap_moved:"{count} sensor links moved to the new device.",device_swap_moved_one:"One sensor link moved to the new device.",device_swap_unmatched:"{count} could not be matched \u2014 check those tasks' sensor triggers.",device_swap_unmatched_one:"One could not be matched \u2014 check that task's sensor trigger.",reading_unit_label:"Reading unit (e.g. kWh, m\xB3)",reading_unit_help:"Shown next to the recorded value when completing this task.",reading_value_label:"Reading value",reading_label:"Reading",readings_section:"Readings",readings_hint:"Several named values per completion \u2014 one row per meter. Leave empty to record a single value.",reading_name_label:"Reading name",reading_unit_short:"Unit",reading_add:"Add reading",reading_duplicate_name:"Name already used",reading_last:"last: {value}",reading_below_last:"Lower than the last reading ({value})",settings_templates_label:"Template gallery",settings_templates_hint:`Untick templates you'll never need \u2014 they disappear from the "From template" pickers (panel and config flow). Nothing else changes; you can re-enable them any time.`,home_profile_title:"Home profile",home_profile_hint:"Recommends templates and sets seasonal windows for your climate and hemisphere. Everything is worked out locally from your floors, areas and home location.",home_type_label:"Home type",home_type_auto:"Automatic ({detected})",home_region_label:"State, province or region",home_region_none:"not found",home_region_hint:"Some rules differ within a country \u2014 a yearly vehicle inspection in one state, none in the next. Found from your home location.",home_dwelling_house:"House",home_dwelling_apartment:"Apartment",home_dwelling_unknown:"not recognised",home_detected_from:"Detected from: {reasons}",home_reason_floors:"several floors",home_reason_basement:"a basement",home_reason_garden:"a garden",home_reason_shed:"a shed",home_reason_driveway:"a driveway",home_reason_garage:"a garage",home_reason_attic:"an attic",home_reason_lawn_mower:"a lawn mower",home_reason_gate:"a gate",home_reason_balcony:"a balcony",home_reason_small_home:"few rooms on one floor",home_reason_ups:"a UPS",home_climate_label:"Climate",home_climate_value:"K\xF6ppen {koppen} \xB7 coldest month {cold} \xB0C \xB7 warmest month {warm} \xB0C",home_climate_unknown:"No home location set in Home Assistant",home_hemisphere_south:"Southern hemisphere \u2014 seasonal windows are mirrored",home_trait_freeze:"Frost in winter",home_trait_snow:"Snowy winters",home_trait_severe_winter:"Severe winters",home_trait_damp:"Damp climate",home_trait_mediterranean:"Mediterranean climate",home_trait_earthquake:"Earthquake region",home_trait_hot_summer:"Hot summers",home_trait_hot_humid:"Hot and humid",home_trait_hot_dry:"Hot and dry",home_trait_termites:"Termite region",home_trait_wildfire:"Wildfire risk",home_trait_cyclone:"Hurricane / typhoon region",home_trait_tropical:"Tropical climate",home_trait_radon:"Radon test recommended",home_reason_starter:"Basics for your home",home_reason_country:"Common in {country}",home_reason_feature:"Found in your home: {feature}",templates_recommended_title:"Recommended for your home",templates_recommended_hint:"Based on your home profile \u2014 adjust it in Settings.",templates_legal_hint:"Notes on legal duties and intervals are guidance, not legal advice. Rules vary by region and change over time \u2014 local regulations and the manufacturer's instructions take precedence.",templates_not_typical:"Not typical for your home type",templates_set_up:"Already set up",worksheet:"Work sheet",worksheet_scan_view:"Scan to open the task",worksheet_scan_complete:"Scan to complete",worksheet_manual_excerpt:"Manual excerpt",worksheet_pages:"pages",worksheet_printed:"Printed",worksheet_never:"Never",card_all_caught_up:"All caught up \u2014 nothing needs attention",postpone:"Postpone",postpone_date_prompt:"Postpone this occurrence to which date?",postpone_date_label:"New due date",postponed:"Postponed",postponed_to:"Postponed to",season_window_label:"Seasonal window (months)",season_window_hint:"Only due in the selected months; off-season dates roll to the next active month. None = all year.",series_end_label:"Ends",series_end_never:"Never (repeats indefinitely)",series_end_after_count:"After a number of times",series_end_until:"On a date",series_end_count_label:"Number of times",series_end_until_label:"End date",parts_section:"Parts & consumables",parts_inventory_value:"Inventory value",part_add:"Add part",part_name:"Name",part_vendor:"Manufacturer",part_storage_location:"Storage location",part_product_url:"Product URL",part_unit:"Unit",part_cost:"Unit price",part_stock:"Stock",part_reorder_threshold:"Reorder at",part_restock_quantity:"Restock quantity",part_package_size:"Package size (units)",part_restock_packages:"Restock amount (packages)",part_package_hint:"Bought in packages, used in the unit: stock, the amount a task uses and the reorder threshold count units; the restock amount and the price are per package.",part_auto_buy:"Auto-create buy task when low",part_restock:"Adjust stock",parts_used_by:"Used by",restock_quantity_label:"Quantity bought",consumes_parts_label:"Consumes parts",task_parts_fleet_hint:"Battery quantities come from Battery Notes per device \u2014 nothing to link here.",shared_parts_other_objects:"Parts from other objects",shared_parts_help:"Several objects can share one stock. Completing this task takes from the owning object.",shared_part_unknown:"Unknown part",parts_load_failed:"Couldn't load this object's parts \u2014 the consumes-parts options are unavailable right now.",adopt_problem_button:"Adopt problem sensors",adopt_problem_title:"Adopt problem sensors",adopt_problem_hint:"Turn HA problem sensors (printer errors, filter warnings, low battery) into maintenance tasks that trigger while the problem is active and clear themselves when it resolves.",adopt_problem_none:"No problem sensors found that aren't already tracked.",adopt_problem_active:"active",adopt_problem_ok:"ok",adopt_problem_new_object:"(new)",adopt_object_hint:"Give several sensors the same object name and they become one object; type an existing object's name to add them there.",adopt_summary_title:"What adopting changes",adopt_summary_existing:'"{name}": tasks {before} \u2192 {after}',adopt_problem_adopt:"Adopt selected",adopt_problem_done:"Adopted {tasks} problem sensor(s)",adopt_problem_done_one:"Adopted 1 problem sensor",views_label:"Views",views_none:"\u2014 No view \u2014",views_manage:"Save / manage views",views_dialog_title:"Saved views",views_dialog_hint:"Save the current filters as a named view everyone can reuse.",views_name_placeholder:"View name",views_save_current:"Save current filters",views_none_yet:"No saved views yet.",close:"Close",trigger_hint_now:"The sensor reads {value} right now.",trigger_hint_above:"The task triggers once it rises above {target}.",trigger_hint_below:"It triggers once it falls below {target}.",trigger_hint_overlap:"These limits overlap: every reading triggers the task and it can never recover. Leave one of them empty.",trigger_hint_counter_delta:"Counts from the current reading ({value}): due at {due} (+{target}), and the count restarts after each completion.",trigger_hint_counter_delta_edit:"Counts usage since the last completion: due after +{target}; the count restarts after each completion.",trigger_hint_counter_abs:"The task becomes due once the sensor reaches {target}.",trigger_hint_runtime:"The task becomes due after {hours} h of accumulated on-time; the counter restarts after each completion.",trigger_hint_due_date:"The task becomes due {days} days before the date the sensor reports.",trigger_hint_due_date_one:"The task becomes due one day before the date the sensor reports.",trigger_hint_due_date_same_day:"The task becomes due on the date the sensor reports.",trigger_hint_due_date_now:"Reported date: {date}.",trigger_hint_state_change:"The task becomes due after {count} state change(s).",trigger_hint_state_change_to:"The task becomes due after {count} change(s) to \u201C{state}\u201D.",trigger_hint_state_now:"Current state: {value}.",adopt_problem_part:"Uses part: {name}",label_filter:"Label",all_labels:"All labels",filter_place:"Place",filter_place_all:"All places",settings_notify_scope:"Notify only for view",settings_notify_scope_all:"All tasks",settings_notify_scope_hint:"Only tasks matching the selected saved view's label/user filters send reminders. Status, sorting and grouping of the view are ignored here.",settings_notify_completed:"Completion notifications",settings_notify_completed_hint:`Household news when a task is completed, with the reason and who did it. "Automatic only" announces just the completions nobody made on the spot: sensor recovery, shopping-list check-off, an automation's service call. Sent to the household service only; quiet hours and the daily cap apply.`,settings_title_style:"Notification title style",settings_title_style_hint:"What appears as the notification's TITLE. Default keeps the per-status text (e.g. 'Maintenance overdue!'). Object name / Task name help when phone notifications stack.",title_style_default:"Default (per-status title)",title_style_object_name:"Object name as title",title_style_task_name:"Task name as title",notify_completed_off:"Off",notify_completed_automatic:"Automatic completions only",notify_completed_all:"All completions",settings_notify_rule:"Your own notification rule",settings_notify_rule_hint:"Every notification also fires the event maintenance_supporter_notification (kind, status, object, task, reference numbers, priority, deep link, the payload). Route it with an automation \u2014 e.g. into Ticker, Telegram or Pushover.",settings_notify_event_only:"Only fire the event, send nothing myself",settings_notify_event_only_hint:"Your automation is the whole delivery. Rate limits, quiet hours and the daily cap still apply to when the event fires.",settings_notify_extra_data:"Extra notification data (template)",settings_notify_extra_data_hint:"JSON or YAML, Jinja allowed; merged into the notify call's data (your keys win). Variables: kind, status, priority, labels, notes, area_name, object_name, task_name, object_ref, task_ref, days_until_due, next_due, last_performed, responsible_user_id, sensor_entity_id, url, target, title, message. Test it with the Send test button.",card_saved_view:"Saved view",card_saved_view_none:"None",card_saved_view_help:"Applies the view's status, user, label and priority filters on top of the filters above. The view's sorting and grouping are panel display settings and are not applied on the card.",panel_card_tab:"Open on tab",panel_card_tab_default:"Remembered tab (as in the panel)",panel_card_view:"Open with saved view",panel_card_height:"Height",panel_card_height_help:"Empty = fill the screen below the card (panel view). Otherwise a CSS length such as 600px or 80vh for views with other cards.",panel_card_not_registered:"The Maintenance Supporter panel is not available \u2014 is the integration set up?",panel_card_load_failed:"The Maintenance Supporter panel could not be loaded \u2014 reload the page (after an update: clear the browser cache).",doc_part_none:"No documents linked to this part.",settings_templates_toggle_group:"Enable or disable all templates in this group",setups_button:"Suggested setups",setups_title:"Suggested setups (Beta)",setups_hint:"Devices of supported integrations whose consumable sensors can drive maintenance tasks. Adopting creates the object and wires each task to its sensor \u2014 it triggers when the consumable runs low and resolves itself after replacement.",setups_none:"No supported devices with unwired consumable sensors found.",setups_adopt:"Set up selected",setups_done:"{tasks} sensor-wired tasks created.",setups_done_one:"1 sensor-wired task created.",complete_parts_used:"Parts used this time",part_delete_confirm:"Delete part '{name}'? Its stock tracking, task links and any open buy reminder will be removed.",baseline_start_value:"Start reading (optional)",baseline_start_help:"Counting starts from this reading. Leave empty to count from the current value; enter the reading at the last service so usage since then already counts.",setups_baseline_hint:"reading at last service (optional)",baseline_start_help_edit:"Leave empty to keep the existing counting. Entering a value re-anchors the counting (e.g. the reading at the last service).",baseline_current_effective:"Currently effective start value: {value}",runtime_on_states:"Active states",runtime_on_states_help:"States that count as running \u2014 default: on. E.g. mowing, cleaning, printing. With an attribute selected, its values are matched instead.",runtime_max_session:"Max session runtime (seconds)",runtime_max_session_help:"A single run counts at most this many seconds \u2014 protects against a sensor stuck ON (lost connection, restart). Empty = no cap.",trend_approaching:"Heading toward the threshold",trend_easing:"Easing away from the threshold",split_select_hint:"Select a task to see its details here",setups_target_new:"Create new: {name}",setups_target_match:"{name} \u2014 matches: {reasons}",setups_reason_model:"model number",setups_reason_name:"name",setups_reason_area:"area",setups_reason_sibling:"same model on another device",setups_maybe_covered:'Probably there already as "{name}"',setups_already:"Already there: {names}",setups_reset_line:"Completing it also resets the counter in the integration (\u201C{button}\u201D)",setups_reset_enable:"\u2014 the button gets switched on for this",reset_offers_title:"Reset counters on completion",reset_offers_hint:"These tasks watch a counter the integration keeps itself. Connected, completing the task here also presses the integration's reset button \u2014 otherwise the counter keeps running and the task falls due again right away.",reset_offers_before:"Now: completing it leaves the counter in {integration} running",reset_offers_after:"Then: it also presses \u201C{button}\u201D",reset_offers_renamed:"Renamed since it was set up \u2014 check that this task is for this part",reset_offers_apply:"Connect resets",reset_offers_done:"{count} tasks now reset their counter on completion",reset_offers_done_one:"1 task now resets its counter on completion",setups_before_after:"Tasks on the object: {before} \u2192 {after}",setups_new_object_count:'New object "{name}" \xB7 tasks: {count}',schedule_preview_title:"Next dates",schedule_preview_ontime:"Assuming on-time completion.",schedule_preview_ends:"(series ends)",adopt_problem_responsible:"Responsible user for all adopted tasks (optional)",adopt_for_minutes_hint:"Only trigger once the problem has persisted this long \u2014 0 reacts to the first flicker.",adopt_problem_configure:"Configure",history_auto:"Automatic",battery_fleet_title:"Battery fleet",battery_fleet_none_low:"All batteries OK \u2014 nothing to replace.",battery_fleet_progress:"{n} to replace",battery_fleet_buy_now:"Buy now",battery_fleet_soon:"Needed soon",battery_fleet_soon_hint:"Predicted from the last replacement date \u2014 order ahead.",battery_fleet_mark_all:"Mark all replaced",battery_fleet_mark_one:"Mark this battery replaced",battery_fleet_offline:"offline",battery_fleet_no_sensor:"No sensor",battery_fleet_trigger_lost:"This task's sensor trigger was lost \u2014 it will not fire or auto-complete.",battery_fleet_repair:"Repair",battery_fleet_exclude:"Exclude from the fleet",battery_fleet_excluded:"Excluded",battery_fleet_include:"Track again",battery_fleet_all:"All tracked batteries",battery_fleet_all_hint:"Exclude a device here to drop it from the fleet before it ever reports low \u2014 a vacuum that recharges itself, or a phone that warns you on its own.",battery_fleet_add:"Add a battery",battery_fleet_add_hint:"Pick a battery sensor the automatic discovery missed \u2014 it joins the roster immediately.",battery_fleet_track_self:"Track self-charging batteries",battery_fleet_track_self_hint:"Phones, vacuums and other devices that recharge themselves appear as rechargeables \u2014 a low one asks for a charge, never for new cells.",battery_fleet_due_without_sensor:"Treat a passed forecast as due when a battery has no sensor",battery_fleet_due_without_sensor_hint:"Some devices report no battery level at all \u2014 Battery Notes only knows the type and the last replacement. Once the typical lifetime has passed, such a battery counts as low and the fleet task reminds you; marking it replaced resets the forecast.",battery_fleet_status_low:"Low",battery_fleet_status_soon:"Soon",battery_fleet_status_ok:"Healthy",battery_fleet_status_due:"Due",battery_fleet_predicted_on:"Expected around {date}",battery_fleet_predicted_typical:"Expected around {date} \u2014 {months} months typical for {type} ({source})",lifetime_source_default:"built-in default",lifetime_source_table:"built-in table",lifetime_source_learned:"learned from {n} replacements",lifetime_source_override:"your setting",lifetime_source_learned_device:"learned from this device's {n} replacements",lifetime_source_learned_model:"learned from {n} replacements on devices of this model",battery_fleet_predicted_trend:"Predicted from this battery's discharge trend: around {date} ({confidence})",battery_fleet_rechargeable:"Rechargeable: charge instead of replacing \u2014 never on the shopping list",battery_fleet_sort_name:"Sort by name",battery_fleet_sort_urgency:"Sort by urgency",battery_fleet_mark_recharged:"Mark as recharged",battery_fleet_sparkline_hint:"Battery level over the last 30 days \u2014 dotted: projected until the low threshold",battery_fleet_filter_type:"Show only this battery type",battery_fleet_record_replacement:"The level jumped around {date} \u2014 record this replacement in Battery Notes",battery_fleet_total:"{n} batteries tracked",battery_fleet_setup_button:"Battery fleet",battery_fleet_setup_done:"Battery fleet set up \u2014 one task tracks all your batteries.",update_banner:"A newer version of Maintenance Supporter is on the server \u2014 reload to update the panel.",update_reload:"Reload",row_actions_banner:"Complete and Skip in task rows are now buttons. Prefer the old icons?",row_actions_keep:"Keep buttons",row_actions_back:"Back to icons",battery_fleet_forecast_overdue:"Predicted date passed \u2014 the battery still reports healthy. If you swapped it, record the replacement; otherwise the forecast was off.",cost_from_parts:"Use \u2248 {amount} from parts",cost_parts_booked:"Parts used \u2248 {amount} are booked automatically \u2014 enter only additional costs.",cost_parts_info:"Parts used \u2248 {amount} \u2014 counted when they were bought, not here.",cost_purchase_use_hint:"The price paid becomes the part's price \u2014 spare parts count when they are used.",history_parts_counted:"Parts: {amount}",history_parts_counted_hint:"Value of the parts used \u2014 counted as spending",history_parts_info:"Parts \u2248 {amount}",history_parts_info_hint:"Value of the parts used \u2014 information only; the money counted when they were bought",history_purchase_stock:"Bought for {amount} (counted when used)",dismiss:"Dismiss",gs_label:"Getting started \u2014 these hints retire as your setup grows",gs_setups_chip:"Suggested setups found {n} devices with pre-wired triggers",gs_setups_chip_one:"Suggested setups found 1 device with pre-wired triggers",gs_adopt_chip:"{n} problem sensors can become maintenance tasks",gs_adopt_chip_one:"1 problem sensor can become a maintenance task",gs_fleet_chip:"One click sets up the battery fleet",gs_reset_chip:"{n} tasks can reset their counter in the integration",gs_reset_chip_one:"1 task can reset its counter in the integration",cal_editor_window:"Default window",cal_editor_window_week:"Week (7 days)",cal_editor_window_fortnight:"Fortnight (14 days)",cal_editor_window_month:"Month (30 days, default)",cal_editor_window_year:"Year (365 days, empty days collapsed)",cal_editor_window_past_30:"Past 30 days (history)",cal_editor_window_past_90:"Past 90 days (history)",cal_editor_show_chips:"Show window chips inside the card",cal_editor_chips_hint:"Hide the chips when the card is embedded in a strategy view that already serves as the window selector.",cal_editor_show_user_filter:"Show user filter dropdown",cal_editor_default_user:"Default user filter",cal_editor_my_tasks:"My tasks (current user)",cal_editor_show_object_filter:"Show object filter dropdown",cal_editor_object_hint:'Pre-select one object via YAML: object_filter: "" \u2014 or a list of names to restrict the card to several objects.',object_history_section:"History (all tasks)",object_history_all_tasks:"All tasks",object_history_empty:"No entries in this range.",object_history_cap_note:"History keeps up to 500 entries per task \u2014 very old entries may be missing.",service_record_title:"Service record",service_record_print:"Service record (PDF)",date:"Date",service_record_entries:"entries",ref_number:"Reference number",print_options_title:"Print service record",print_layout:"Layout",print_layout_chronological:"Chronological",print_layout_by_task:"By task",print_include:"Include",print_inc_readings:"Readings",print_inc_parts:"Parts used",print_inc_photos:"Photos",print_inc_documents:"Linked documents",print_inc_doc_desc:"Document descriptions",print_inc_checklist:"Checklist",print_inc_notes:"Notes",print_inc_costs:"Cost and duration",print_inc_person:"Completed by",print_inc_refs:"Reference numbers",print_inc_bare:"Completions without details",print_inc_qr:"QR code per task",print_button:"Print",report_scan_hint:"Scan to open the task",completed_by:"Completed by",date_from:"From",date_to:"To",phases_section:"Cycle phases (optional)",phases_hint:"Different work on one shared schedule \u2014 each completion moves to the next step (e.g. small service, small service, big service).",phase_add:"Add phase",phase_name:"Phase name",phase_sequence_label:"Cycle order",phase_sequence_add_step:"Add step",phase_current:"Current phase",phase_set:"Set as current",chart_history_fallback:"No long-term statistics for this entity \u2014 showing recorder state history (typically the last ~10 days)",chart_history_alarm:"Trigger view from recorder state history: 1 = alert state held for the hold time, 0 = fine (typically the last ~10 days)",chart_history_count:"Change count rebuilt from recorder state history since the last service (typically the last ~10 days)",prediction_cycles:"Learned from cycles",phase_require_override:"Override \u201CRequire on completion\u201D for this phase",history_add_past:"Add past completion",require_tag_scan:"Only complete by scanning the tag",require_tag_scan_help:"Proof of presence: Done is blocked on every surface until the NFC tag or QR code on the thing itself is scanned. Automations can pass 'via_tag_scan' to the complete service.",disallow_skip:"Don't allow skipping",disallow_skip_help:"The Skip action disappears from every surface, and the server refuses a skip from automations and voice too.",no_notifications:"No notifications for this task",no_notifications_help:"No reminders for this task \u2014 no status notifications, repeats, lead-time reminders or bundles. It still shows on the dashboard and in its entities; the weekly digest still counts it.",require_tag_scan_hint:"This task completes only by scanning its NFC tag or QR code on the thing itself \u2014 saving here will be refused."}});var us,hs=y(()=>{"use strict";us="2.100.0"});function ji(s){Pe.en=Object.assign({},s,Pe.en??{})}function be(s){let r=(s||Oi).toLowerCase();return r.startsWith("pt")&&r.endsWith("br")?"pt-br":r.substring(0,2)}function n(s,r,e){let t=be(r);return Pe[t]?.[s]??Pe.en?.[s]??e??s}function Le(s){let r=be(s);return r===Oi||r in Pe}function Ne(s){let r=be(s);return r===Oi||r in Pe||!Ka.has(r)?Promise.resolve():(r in bt||(bt[r]=fetch(`${Ya}/${r}.json?v=${us}`).then(e=>e.ok?e.json():null).then(e=>{e?Pe[r]=e:delete bt[r]}).catch(()=>{delete bt[r]})),bt[r])}var Oi,_s,Pe,bt,Ka,Ya,Gt=y(()=>{"use strict";hs();Oi="en",_s=(()=>{let s=window;return s.__msLocales||(s.__msLocales={store:{},inflight:{}}),s.__msLocales})(),Pe=_s.store,bt=_s.inflight;Ka=new Set(["de","nl","fr","it","es","pt","pt-br","ru","uk","pl","cs","sv","zh","da","fi","nb","ja","hi","hu","ko","tr"]),Ya="/maintenance_supporter_locales"});function ms(s){let r=s?.language;!r||typeof s?.loadBackendTranslation!="function"||ie.lang===r&&(ie.localize||ie.inflight)||(ie.lang=r,ie.localize=null,ie.inflight=s.loadBackendTranslation("exceptions",Di).then(e=>{ie.lang===r&&(ie.localize=e)}).catch(()=>{}).finally(()=>{ie.inflight=null}))}function gs(s,r,e){if(!r||!ie.localize||s&&s!==Di)return null;let t=`component.${Di}.exceptions.${r}.message`,i=ie.localize(t,e??void 0);return i&&i!==t?i:null}var Di,ie,Mi=y(()=>{"use strict";Di="maintenance_supporter",ie=(()=>{let s=window;return s.__msBackendErrors??={lang:"",localize:null,inflight:null}})()});function He(s){return s?.currency_symbol||Qa}function fs(s,r){r.has("hass")&&Fi(s.hass?.locale,s.hass?.config?.country,s.hass?.config?.time_zone);let e=s.hass?.language;e&&!Le(e)&&Ne(e).then(()=>s.requestUpdate()),ms(s.hass)}function N(s){return s?.language||"en"}function vs(s){let r=be(s);return{de:"de-DE",en:"en-US",nl:"nl-NL",fr:"fr-FR",it:"it-IT",es:"es-ES",pt:"pt-PT",ru:"ru-RU",uk:"uk-UA",zh:"zh-CN",da:"da-DK",fi:"fi-FI",nb:"nb-NO",ja:"ja-JP",hi:"hi-IN",pl:"pl-PL",cs:"cs-CZ",sv:"sv-SE","pt-br":"pt-BR",hu:"hu-HU",ko:"ko-KR",tr:"tr-TR"}[r]??"en-US"}function Za(s){bs.decimals=typeof s=="number"&&Number.isInteger(s)&&s>=0&&s<=3?s:0}function Ja(){return bs.decimals??0}function Kt(s){s&&s.currency_decimals!==void 0&&s.currency_decimals!==null&&Za(Number(s.currency_decimals))}function Fi(s,r,e){e!==void 0&&(re.serverTimeZone=e||void 0),s&&(re.date=s.date_format,re.time=s.time_format,re.number=s.number_format,re.timeZone=s.time_zone,r!==void 0&&(re.country=r||void 0))}function Xa(s){switch(re.number){case"comma_decimal":return["en-US","en"];case"decimal_comma":return["de","es","it"];case"space_comma":return["fr","sv","cs"];case"system":return;default:return vs(s)}}function C(s,r,e){if(!Number.isFinite(s))return String(s);let t=typeof e=="number"?{minimumFractionDigits:e,maximumFractionDigits:e}:{maximumFractionDigits:2,...e};if(re.number==="none"){let i=Math.pow(10,t.maximumFractionDigits??2);return String(Math.round(s*i)/i)}try{return new Intl.NumberFormat(Xa(r),t).format(s)}catch{return new Intl.NumberFormat(void 0,t).format(s)}}function J(s,r,e,t){let i=t??Ja(),a=Math.abs(s)<.5/Math.pow(10,i)?0:s,o=C(a,e,i);return r?`${o} ${r}`:o}function Ye(s,r,e){let t=C(s,e);return r?`${t} ${r}`:t}function Ge(s){let r=vs(s),e=re.country;if(e&&/^[A-Za-z]{2}$/.test(e)){let t=`${be(s).split("-")[0]}-${e.toUpperCase()}`;try{return new Intl.DateTimeFormat(t),t}catch{}}return r}function zi(s,r,e){let t=re.date;if(t==="DMY"||t==="MDY"||t==="YMD"){let[a,o,d]=ve(s,e).split("-");return t==="DMY"?`${d}/${o}/${a}`:t==="MDY"?`${o}/${d}/${a}`:`${a}-${o}-${d}`}let i=t==="system"?void 0:Ge(r);return s.toLocaleDateString(i,{day:"2-digit",month:"2-digit",year:"numeric",timeZone:e})}function Yt(s,r){let e=fe();switch(re.time){case"12":return s.toLocaleTimeString(Ge(r),{hour:"2-digit",minute:"2-digit",hour12:!0,timeZone:e});case"24":return s.toLocaleTimeString(Ge(r),{hour:"2-digit",minute:"2-digit",hour12:!1,timeZone:e});case"system":return s.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",timeZone:e});default:return s.toLocaleTimeString(Ge(r),{hour:"2-digit",minute:"2-digit",timeZone:e})}}function O(s,r){if(!s)return"\u2014";try{let e=xs.exec(s);return e?zi(new Date(Date.UTC(+e[1],+e[2]-1,+e[3])),r,"UTC"):zi(new Date(Q(s)),r,fe())}catch{return s}}function Qt(s,r){if(!s)return"\u2014";if(xs.test(s))return O(s,r);try{let e=new Date(Q(s));return zi(e,r,fe())+" "+Yt(e,r)}catch{return s}}function Zt(s,r=Date.now()){let e=ge();return Bt(r,e)===Bt(r,fe())?"":n("ha_time_zone_hint",s).replace("{zone}",e)}function ws(s,r){if(s==null)return"\u2014";let e=r||"en";return s<0?`${Math.abs(s)} ${n("d_overdue",e)}`:s===0?n("today",e):`${s} ${s===1?n("day",e):n("days",e)}`}function qe(s,r,e){return s==null?"\u2014":`${s} ${n("unit_"+(r||"days"),e)}`}function Jt(s,r){return s==null?"\u2014":`${C(s,r,{maximumFractionDigits:1})} ${n("minutes_short",r)}`}function Ke(s,r,e="long"){return new Date(Date.UTC(2024,0,1+s)).toLocaleDateString(Ge(r),{weekday:e,timeZone:"UTC"})}function Ui(s,r,e="long"){return new Date(Date.UTC(2024,s,1)).toLocaleDateString(Ge(r),{month:e,timeZone:"UTC"})}function ks(s,r,e="long"){return Ke((s.getDay()+6)%7,r,e)}function $s(s,r,e="long"){return Ui(s.getMonth(),r,e)}function Es(s,r){let e=s.schedule;if(s.schedule_type==="sensor_based"){let i=n("sensor_based",r),a=e&&e.kind==="interval"&&e.every?e.every:s.interval_days;return a?`${i} \xB7 ${qe(a,(e&&e.kind==="interval"?e.unit:s.interval_unit)||"days",r)}`:i}let t=e?.offset?` ${e.offset>0?"+":"\u2212"}${Math.abs(e.offset)}d`:"";switch(e?.kind){case"weekdays":return((e.weekdays||[]).map(i=>Ke(i,r,"short")).join(" & ")||"\u2014")+t;case"nth_weekday":return e.weekday==null||e.nth==null?"\u2014":`${e.nth===-1?n("ord_last",r):n("ord_"+e.nth,r)} ${Ke(e.weekday,r,"long")}${t}`;case"day_of_month":return e.day==null?"\u2014":(e.day===-1?n(e.business?"last_business_day_month":"last_day_month",r):`${n("day_word",r)} ${e.day}`)+t;case"calendar":return`${n("calendar_entity_label",r)}: ${s.schedule_entity_name||e.entity_id||"\u2014"}${t}`;case"one_time":return s.due_date?O(s.due_date,r):n("one_time",r);case"manual":return n("manual",r);case"interval":return qe(e.every,e.unit,r)}return s.schedule_type==="one_time"?s.due_date?O(s.due_date,r):n("one_time",r):s.schedule_type==="manual"?n("manual",r):s.schedule_type==="sensor_based"?n("sensor_based",r):s.interval_days!=null?qe(s.interval_days,s.interval_unit,r):"\u2014"}function Ss(s,r){s.currentTarget.dispatchEvent(new CustomEvent("hass-more-info",{detail:{entityId:r},bubbles:!0,composed:!0}))}var Qa,ys,re,bs,xs,Qe,eo,to,Xt,T=y(()=>{"use strict";I();ds();Ft();Gt();Mi();Z();Gt();Qa="\u20AC";ji(ps);ys=window,re=ys.__msDateTimePrefs??={},bs=ys.__msMoneyPrefs??={};xs=/^(\d{4})-(\d{2})-(\d{2})$/;Qe=E` +Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",ws_err_not_found:"Not found \u2014 it may have been deleted meanwhile",ws_err_invalid_input:"Invalid input",ws_err_invalid_date:"Invalid date",ws_err_invalid_format:"Invalid format",ws_err_invalid_url:"Invalid link",ws_err_invalid_mirror_todo:"Invalid to-do list",ws_err_not_configured:"Not set up yet",ws_err_not_loaded:"Not loaded yet \u2014 try again in a moment",ws_err_limit_reached:"Limit reached",ws_err_too_many:"Too many entries",ws_err_too_large:"Too large",ws_err_not_archived:"Not archived",ws_err_invalid_target:"Invalid target",ws_err_create_failed:"Could not be created",ws_err_archived:"Archived \u2014 restore it first",ws_err_already_archived:"Already archived",ws_err_unavailable:"Currently unavailable",ws_err_unauthorized:"Not permitted for your user",ws_err_too_many_views:"Too many saved views",ws_err_storage_unavailable:"Storage is not available",ws_err_replace_failed:"Replacement failed",ws_err_not_paused:"Not paused",ws_err_not_available:"Nothing available",ws_err_no_url:"No link given",ws_err_no_phases:"This task has no phases",ws_err_invalid_view:"Invalid view",ws_err_invalid_user:"Unknown user",ws_err_invalid_range:"Invalid range",ws_err_invalid_parent:"Invalid parent object",ws_err_invalid_device:"Unknown device",ws_err_empty_csv:"The CSV file is empty",ws_err_empty:"Nothing to import",ws_err_duplicate_failed:"Could not duplicate",ws_err_already_paused:"Already paused",ws_err_invalid_cursor:"Invalid phase position",ws_err_invalid_entity_slug:"Invalid entity name",ws_err_invalid_trigger_config:"Invalid trigger configuration",ws_err_no_defaults:"No quick-complete defaults set",ws_err_self_link_device:"An object cannot be linked to itself",ws_err_too_early:"Too early \u2014 this task can only be completed closer to its due date",ws_err_invalid_search_template:"The search link must be an http(s) URL containing {q}",ws_err_invalid_icon:"The notification icon must be an mdi: name, e.g. mdi:air-filter",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_toggle:"Due at a specific time",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",notes_markdown_hint:"Markdown is supported \u2014 **bold**, lists, [links](\u2026)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",completed_at_optional:"Completed at (optional, empty = now)",completed_at_pick:"Set date & time",completed_at_future_error:"The completion date cannot be in the future.",ha_time_zone_hint:"Time in Home Assistant's time zone ({zone})",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",task_mirror_todo:"Mirror into to-do lists",task_mirror_todo_hint:"The task appears in these lists while it is due; checking it off there completes it here.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",all_priorities:"All priorities",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",object_replaces:"Replaces",object_replaced_by:"Replaced by",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",all_parts:"All parts",all_areas:"All areas",areas_filter:"Filter areas\u2026",areas_filter_none:"No area matches the filter.",area_cost_year:"Cost {year}",area_object_count:"{n} objects",area_object_count_one:"1 object",area_range_12m:"Last 12 months",area_range_all:"All time",area_task_filter:"Filter by task\u2026",area_kpi_completions:"Completions",area_kpi_total_time:"Total time",area_cost_per_month:"Cost per month",area_cost_per_year:"Cost per year",area_cost_per_object:"Cost per object",area_cost_share:"Share",area_history_section:"History (all objects)",area_report_print:"Area report (PDF)",area_report_title:"Area report",area_report_period:"Period",area_no_costs:"No costs recorded in this period.",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",trigger_equals:"Trigger when equal to (=)",trigger_not_equals:"Trigger when different from (\u2260)",for_at_least_minutes:"For at least (minutes)",safety_interval:"Safety interval (optional)",trigger_combinator:"Combine trigger and interval",trigger_combinator_any:"Trigger or interval (whichever first)",trigger_combinator_all:"Trigger and interval (both required)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",adaptive_prediction_enabled:"Enable sensor-driven predictions",adaptive_seasonal_enabled:"Enable seasonal awareness",adaptive_max_interval:"Maximum interval (days)",adaptive_min_interval:"Minimum interval (days)",adaptive_ewa_alpha:"Learning rate (alpha)",adaptive_enabled:"Enable adaptive scheduling",adaptive_section_title:"Adaptive Scheduling",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:"Calendar",cal_no_events:"No maintenance",cal_every_n_days:"every {n} days",cal_every_day:"every day",cal_source_time:"Time-based",cal_source_time_adaptive:"Time-based (adaptive)",cal_source_sensor:"Sensor-based",cal_predicted:"predicted",cal_confidence_high:"high confidence",cal_confidence_medium:"medium confidence",cal_confidence_low:"low confidence",budget_monthly:"Monthly budget",budget_yearly:"Yearly budget",groups:"Groups",new_group:"New group",edit_group:"Edit group",no_groups:"No groups yet",delete_group:"Delete group",delete_group_confirm:"Delete group '{name}'?",group_select_tasks:"Select tasks",group_name_required:"Name is required",description_optional:"Description (optional)",selected:"Selected",loading_chart:"Loading chart data...",hide_outliers:"Hide outliers (sensor glitches)",was_maintenance_needed:"Was this maintenance needed?",feedback_needed:"Needed",feedback_not_needed:"Not needed",feedback_not_sure:"Not sure",suggested_interval:"Suggested interval",apply_suggestion:"Apply",reanalyze:"Re-analyze",reanalyze_result:"New analysis",reanalyze_insufficient_data:"Not enough data to produce a recommendation",data_points:"data points",dismiss_suggestion:"Dismiss",confidence_low:"Low",confidence_medium:"Medium",confidence_high:"High",recommended:"recommended",seasonal_awareness:"Seasonal Awareness",edit_seasonal_overrides:"Edit seasonal factors",seasonal_overrides_title:"Seasonal factors (override)",seasonal_overrides_hint:"Factor per month (0.1\u20135.0). Empty = learned automatically.",seasonal_override_invalid:"Invalid value",seasonal_override_range:"Factor must be between 0.1 and 5.0",clear_all:"Clear all",clear:"Clear",date_type_toggle:"Type the date",date_type_invalid:"Not a valid date \u2014 try 1978-03-15, a year like 1978, or your own date format",seasonal_chart_title:"Seasonal Factors",seasonal_learned:"Learned",seasonal_manual:"Manual",month_jan:"Jan",month_feb:"Feb",month_mar:"Mar",month_apr:"Apr",month_may:"May",month_jun:"Jun",month_jul:"Jul",month_aug:"Aug",month_sep:"Sep",month_oct:"Oct",month_nov:"Nov",month_dec:"Dec",sensor_prediction:"Sensor Prediction",degradation_trend:"Trend",trend_rising:"Rising",trend_falling:"Falling",trend_stable:"Stable",trend_insufficient_data:"Insufficient data",days_until_threshold:"Days until threshold",threshold_exceeded:"Threshold exceeded",environmental_adjustment:"Environmental factor",sensor_prediction_urgency:"Sensor predicts threshold in ~{days} days",day_short:"day",weibull_reliability_curve:"Reliability Curve",weibull_failure_probability:"Failure Probability",weibull_r_squared:"Fit R\xB2",beta_early_failures:"Early Failures",beta_random_failures:"Random Failures",beta_wear_out:"Wear-out",beta_highly_predictable:"Highly Predictable",confidence_interval:"Confidence Interval",confidence_conservative:"Conservative",confidence_aggressive:"Optimistic",current_interval_marker:"Current interval",recommended_marker:"Recommended",characteristic_life:"Characteristic life",chart_mini_sparkline:"Trend sparkline",chart_history:"Cost and duration history",chart_seasonal:"Seasonal factors, 12 months",chart_weibull:"Weibull reliability curve",chart_sparkline:"Sensor trigger value chart",days_progress:"Days progress",qr_code:"QR Code",qr_generating:"Generating QR code\u2026",qr_error:"Failed to generate QR code.",qr_error_no_url:"No HA URL configured. Please set an external or internal URL in Settings \u2192 System \u2192 Network.",save_error:"Failed to save. Please try again.",subsave_warning:"Saved, but one setting was rejected: {detail}",qr_print:"Print",qr_download:"Download SVG",qr_action_view:"View maintenance info",qr_action_complete:"Mark maintenance as complete",qr_action_quick_complete:"Quick-complete \u2014 no dialog",qr_print_quick_none:"Quick-complete codes need quick-complete defaults on a task (Settings \u2192 Advanced Features \u2192 Completion actions; task dialog \u2192 Quick-complete defaults) \u2014 none of the chosen objects' tasks has them yet.",qr_url_mode:"Link type",qr_mode_companion:"Companion App",qr_mode_local:"Local (mDNS)",qr_mode_server:"Server URL",overview:"Overview",strat_this_month:"This Month",strat_later:"Later",strat_week:"Week",strat_fortnight:"Fortnight",strat_month:"Month",strat_year:"Year",strat_other:"Other",strat_status:"Status",strat_empty_title:"No maintenance objects yet",strat_empty_content:"Open the Maintenance panel to add your first object \u2014 pool pump, HVAC filter, vehicle, anything that needs scheduled care.",strat_open_panel:"Open Maintenance panel",strat_add_object:"Add object",strat_not_loaded:"**Maintenance Supporter** is not loaded. Install/enable the integration first.",strat_group_by:"Group views by",strat_group_area:"By area (default)",strat_group_status:"By status (Overdue / Triggered / Due Soon / OK)",strat_group_floor:"By floor (uses HA floors)",strat_group_due_date:"By due date (Overdue / Today / Week / Month / Later)",strat_group_calendar:"Rolling calendar (Week / Fortnight / Month / Year)",strat_editor_help:'The "Overview" view is always first. Empty groups are skipped.',picker_name_calendar:"Maintenance Supporter \u2014 Calendar",picker_name_panel:"Maintenance Supporter \u2014 Panel",picker_name_budget:"Maintenance Supporter \u2014 Budget",picker_name_groups:"Maintenance Supporter \u2014 Groups",picker_name_vacation:"Maintenance Supporter \u2014 Vacation",picker_name_battery_fleet:"Battery Fleet",picker_name_section:"Maintenance Supporter \u2014 Section",picker_name_vacation_status:"Maintenance Supporter \u2014 Vacation Status",picker_name_budget_status:"Maintenance Supporter \u2014 Budget Status",picker_desc_card:"Overview of your maintenance tasks with quick actions.",picker_desc_calendar:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",picker_desc_panel:"The complete Maintenance Supporter panel as a card \u2014 for a panel view / dashboard subview without the sidebar entry.",picker_desc_budget:"Edit the monthly and yearly budget right on the dashboard.",picker_desc_groups:"Create, rename and delete task groups right on the dashboard.",picker_desc_vacation:"Switch vacation mode on or off and set its dates right on the dashboard.",picker_desc_battery_fleet:"All tracked batteries: what is low now, what runs out soon, and what to buy.",picker_desc_dashboard:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",picker_desc_section:"Embed maintenance tasks (filterable by area, status, due date) as a section in any dashboard view.",picker_desc_vacation_status:"Compact vacation-mode status banner. Tap to open settings in the panel.",picker_desc_budget_status:"Monthly + yearly maintenance budget overview. Tap for details.",picker_desc_groups_status:"List of configured task groups with member counts.",hist_note_button:"Completed from dashboard button",hist_note_todo:"Completed from the To-do list",hist_note_voice:"Completed by voice",hist_note_notification:"Completed from the notification",hist_note_nfc:"Completed via NFC tag",hist_note_shopping_list:"Completed from the shopping list",hist_note_todo_mirror:"Completed from a mirrored to-do list",hist_note_skipped_notification:"Skipped from notification",hist_note_skipped_button:"Skipped from dashboard button",hist_note_sensor_triggered:"Sensor trigger activated",hist_note_initial:"Initial value set during task creation",hist_note_auto_recovered:"Auto-completed: sensor recovered ({value})",hist_note_reset:"Reset to {date}",hist_note_trigger_replaced:"Trigger entity replaced: {old} \u2192 {new}",hist_note_trigger_removed:"Sensor trigger removed (entity was: {entity}). Schedule converted to {schedule}.",hist_note_compound_removed:"Entity {entity} removed from compound trigger; {count} conditions remain.",recent_activities:"Recent Activities",search_notes:"Search notes",avg_cost:"Avg Cost",current:"Current",shorter:"Shorter",longer:"Longer",normal:"Normal",disabled:"Disabled",compound_logic:"Compound logic",compound:"Compound (multiple conditions)",compound_logic_and:"AND \u2014 all conditions must trigger",compound_logic_or:"OR \u2014 any condition triggers",compound_help:"Combine several sensor conditions into one trigger.",compound_no_conditions:"No conditions yet \u2014 add at least one.",compound_add_condition:"Add condition",compound_condition:"Condition",compound_remove_condition:"Remove condition",card_title:"Title",card_show_header:"Show header with statistics",card_show_actions:"Show action buttons",card_action_style:"Complete button style",card_compact:"Compact mode",card_max_items:"Max items (0 = all)",card_filter_status:"Filter by status",card_filter_status_help:"Empty = show all statuses.",card_filter_objects:"Filter by objects",card_filter_objects_help:"Empty = show all objects.",card_filter_areas:"Filter by areas",card_filter_areas_help:"Empty = show all areas.",card_filter_priority_help:"Empty = show all priorities. Tasks without an explicit priority count as Normal.",card_filter_entities:"Filter by entities (entity_ids)",card_filter_entities_help:"Pick sensor / binary_sensor entities from this integration. Empty = all.",card_loading_objects:"Loading objects\u2026",card_load_error:"Could not load objects \u2014 check the WebSocket connection.",card_no_tasks_title:"No maintenance tasks yet",card_no_tasks_cta:"\u2192 Create one in the Maintenance panel",no_objects:"No objects yet.",action_error:"Action failed. Please try again.",area_id_optional:"Area (optional)",place_optional:"Place (zone, optional)",remind_on_site:"Remind only while somebody is there",remind_on_site_hint:"Reminders wait until somebody is in this zone. Whoever arrives there gets a message with what is due.",place_missing:"Zone not found: reminders as at home",place_home:"Home",installation_date_optional:"Installation date (optional)",warranty_expiry_optional:"Warranty expiry (optional)",warranty:"Warranty",warranty_valid_until:"valid until {date}",warranty_expires_in:"expires in {days} days",warranty_expired:"expired",cal_past_windows:"Past windows",cal_forward_windows:"Forward windows",history_edit_title:"Edit history entry",history_delete_entry:"Delete entry",history_delete_confirm_entry:"Delete this history entry? The task's last-performed date falls back to the previous completion; photos stay with the object.",history_delete_returns_parts:"The parts it used go back to stock: {parts}.",history_edit_timestamp:"Timestamp",manufacturer:"Manufacturer",model:"Model",area:"Area",actions:"Actions",view_mode_label:"View",view_cards:"Card view",view_table:"Table view",objects_table_columns_label:"Objects table columns",objects_table_columns_hint:"Choose which columns appear in the objects table view.",custom_icon_optional:"Icon (optional, e.g. mdi:wrench)",notify_icon:"Notification icon",notify_icon_hint:"Shown by the Companion app on Android. Empty = the icon of this task's maintenance type ({default}).",task_enabled:"Task enabled",skip_reason_prompt:"Skip this task?",reason_optional:"Reason (optional)",reset_date_prompt:"Mark task as performed?",reset_date_optional:"Last performed date (optional, defaults to today)",notes_label:"Notes",documentation_label:"Documentation",no_nfc_tag:"\u2014 No tag \u2014",dashboard:"Dashboard",tab_today:"Today",palette_placeholder:"Search objects, tasks, spare parts, documents, notes\u2026",palette_no_results:"No matches",palette_hint:"\u2191\u2193 to navigate \xB7 Enter to open \xB7 Esc to close \xB7 / opens the search anywhere",search_open:"Search",search_group_parts:"Spare parts",search_group_content:"In documents",search_group_history:"History notes",search_page:"Page {page}",search_empty_hint:"Type to search objects, tasks, spare parts, documents and notes",search_searching:"Searching documents and notes\u2026",search_index_status:"Full-text search: {indexed} of {total} files indexed \xB7 {no_text} without text layer \xB7 {pending} pending",today_all_caught_up:"All caught up! Nothing due this week.",today_overdue:"Overdue",today_due_today:"Due today",today_this_week:"This week",settings:"Settings",settings_features:"Advanced Features",settings_features_desc:"Enable or disable advanced features. Disabling hides them from the UI but does not delete data.",feat_adaptive:"Adaptive Scheduling",feat_adaptive_desc:"Learn optimal intervals from maintenance history",feat_seasonal:"Seasonal Adjustments",feat_seasonal_desc:"Adjust intervals based on seasonal patterns",feat_environmental:"Environmental Correlation",feat_environmental_desc:"Correlate intervals with temperature/humidity",feat_budget:"Budget Tracking",feat_budget_desc:"Track monthly and yearly maintenance spending",feat_groups:"Task Groups",feat_groups_desc:"Organize tasks into logical groups",feat_checklists:"Checklists",feat_checklists_desc:"Multi-step procedures for task completion",settings_general:"General",settings_default_warning:"Default warning days",settings_consumable_threshold:"Consumable low threshold (%)",settings_battery_low_percent:"Battery low threshold (%)",settings_battery_recovered_percent:"Battery counts as replaced above (%)",settings_battery_recovered_percent_hint:"A low battery stays counted as low until its level rises above this value or a replacement is recorded \u2014 so a level hovering around the low threshold cannot complete the fleet task again and again.",settings_battery_auto_record:"Record a replacement automatically when a low battery recovers",settings_battery_auto_record_hint:"When a battery that was low rises above the recovery threshold, the replacement date is recorded in Battery Notes and the spare cells are taken from stock \u2014 no tap needed.",settings_battery_lifetimes:"Typical battery lifetimes",settings_battery_lifetimes_hint:'Only used for batteries without a percentage: a Battery Notes note that has just a type and a last-replaced date, or a sensor that only reports "low". Their due date is last replaced + this lifetime. Batteries that report a level get their forecast from the measured discharge instead. Once the fleet has seen three replacements of a type, the median interval takes over from the built-in value \u2014 your own value always wins.',settings_battery_lifetime_months:"months",settings_battery_lifetime_reset:"Use default",settings_battery_lifetime_in_fleet:"in your fleet",settings_battery_lifetime_learned_models:"Learned per model: {list}",settings_thresholds_hint:"Defaults for new Suggested setups (percent-remaining consumables) and for fleet batteries without their own Battery Notes threshold. Existing tasks keep their value.",settings_part_search_url:"Shopping search link",settings_part_search_url_hint:"URL with {q} in place of the search terms, used for parts without a product link. Leave empty for the automatic store (by country, then by language).",settings_value_out_of_range:"Value must be between {min} and {max}",bn_summary:"{name}: {pct} % for {n} batteries",bn_floor_decides:"Your {floor} % floor decides for all of them; the higher of the two thresholds counts per battery.",bn_above_floor:"That is above your {floor} % floor, so {name} decides for all noted batteries.",bn_overrides:"{n} devices with their own threshold:",bn_more:"+ {n} more",settings_row_actions:"Task row actions",settings_ref_numbers_in_lists:"Reference numbers in lists",settings_ref_numbers_in_lists_hint:"Show the #8 / #8.3 chips in front of object and task names in the Today list, the task table, the object cards and the objects table.",settings_compact_refs:"Compact reference numbers",settings_compact_refs_hint:"Renumbers all objects, tasks and completions in order (1, 2, 3 \u2026) and closes the gaps left by deletions. Numbers already printed on service booklets, photos or notes will no longer match.",settings_compact_refs_confirm:"Renumber every object, task and completion sequentially in creation order? Numbers already written on printed service booklets, photos or notes will no longer match. This cannot be undone.",settings_compact_refs_done:"Renumbered {objects} objects, {tasks} tasks and {completions} completions.",row_actions_buttons_compact:"Buttons (icons only on phones)",row_actions_buttons:"Buttons with text",row_actions_icons:"Icons (classic)",row_actions_follow:"Follow the household setting",settings_panel_enabled:"Sidebar panel",settings_panel_title:"Sidebar panel title",settings_notifications:"Notifications",settings_notify_service:"Notification service",settings_shopping_list:"Shopping list (buy tasks)",settings_shopping_list_help:"Low-part buy reminders appear in this to-do list; checking one off restocks the part.",shopping_list_none:"Off \u2014 no shopping list",settings_install_assist_sentences:"Install Assist sentences",settings_install_assist_sentences_hint:"Copies the voice sentences into your configuration so the classic Assist agent recognises them. A file you edited yourself is never overwritten.",test_notification:"Test notification",send_test:"Send test",testing:"Sending\u2026",test_notification_success:"Test notification sent",test_notification_failed:"Test notification failed",notify_per_person:"Per-person delivery",member_avatars:"Member avatars",member_avatars_hint:"Shown next to assigned tasks \u2014 initials in the member's colour. Defaults come from the name; set your own initials or pick a colour to tell members apart.",member_initials:"Initials",member_color:"Colour",member_avatar_reset:"Reset",notify_no_own_device:"No own device \u2014 uses the household service",settings_notify_due_soon:"Notify when due soon",settings_notify_overdue:"Notify when overdue",settings_notify_triggered:"Notify when triggered",settings_interval_hours:"Repeat interval (hours, 0 = once)",settings_quiet_hours:"Quiet hours",settings_quiet_start:"Start",settings_quiet_end:"End",settings_max_per_day:"Max notifications per day (0 = unlimited)",settings_bundling:"Bundle notifications",settings_bundle_threshold:"Bundle threshold",settings_reminder_leads:"Extra reminders (days before due)",settings_reminder_leads_hint:"Comma-separated lead times, e.g. 14, 3, 0 \u2014 one extra reminder fires on each matching day. Empty = off.",settings_actions:"Mobile Action Buttons",settings_action_complete:"Show 'Complete' button",settings_action_skip:"Show 'Skip' button",settings_action_snooze:"Show 'Snooze' button",settings_weekly_digest:"Weekly digest",settings_weekly_digest_hint:"A single summary notification on Monday morning when tasks are due.",settings_warranty_reminder:"Warranty expiry reminder",settings_warranty_reminder_days:"Days before expiry",settings_warranty_reminder_hint:"Notify once when an object's warranty is this many days from expiring.",settings_snooze_hours:"Snooze duration (hours)",settings_snooze_hours_hint:"How long Snooze mutes a task's reminders \u2014 from the task menu, a card, voice or the phone's Snooze button. The due date stays as it is.",settings_budget:"Budget",settings_currency:"Currency",settings_currency_decimals:"Decimal places for amounts",settings_currency_decimals_hint:"How many decimals every amount shows: KPIs, budgets, costs in lists and reports, budget alerts. 0 = whole numbers.",settings_parts_cost_mode:"Spare parts count as spending",settings_parts_cost_purchase:"When bought",settings_parts_cost_use:"When used",settings_parts_cost_mode_hint:"When bought: a buy reminder's cost counts, and the parts a job uses are shown as information. When used: every completion books the value of the parts it used, and a purchase sets the part's price instead of counting. Applies to completions from now on \u2014 history keeps how it was booked.",settings_budget_monthly:"Monthly budget",settings_budget_yearly:"Yearly budget",settings_budget_alerts:"Budget alerts",settings_budget_threshold:"Alert threshold (%)",settings_import_export:"Import / Export",settings_export_json:"Export JSON",settings_export_yaml:"Export YAML",settings_export_csv:"Export CSV",settings_export_settings:"Export settings (JSON)",settings_import_placeholder:"Paste JSON or CSV content here\u2026",settings_import_btn:"Import",settings_import_success:"{count} objects imported successfully.",settings_import_unmatched_users:"Not found on this instance: {names}. Their task assignments were removed \u2014 add people with the same names in Home Assistant and import again to keep them.",settings_export_success:"Export downloaded.",settings_saved:"Setting saved.",settings_include_history:"Include history",settings_export_selection:"Limit to selected objects (optional)",settings_docs_archive:"Documents archive (with files)",settings_docs_archive_hint:"The JSON and YAML exports list your documents but not their files; CSV leaves documents out. This ZIP holds the uploaded files \u2014 restore it after importing the JSON and nothing is missing.",settings_docs_export_btn:"Download documents ZIP",settings_docs_import_btn:"Restore documents ZIP",settings_docs_import_success:"Restored: {blobs} files, {docs} documents",settings_docs_import_missing:"{n} skipped \u2014 their files were not in the ZIP",sort_alphabetical:"Alphabetical",sort_due_soonest:"Due soonest",sort_task_count:"Task count",sort_area:"Area",sort_assigned_user:"Assigned user",sort_group:"Group",groupby_none:"No grouping",groupby_area:"By area",groupby_group:"By group",groupby_user:"By user",groupby_object:"By object",filter_label:"Filter",user_label:"User",photo_label:"Photo",sort_label:"Sort",group_by_label:"Group by",state_value_help:'Use the HA state value (usually lowercase, e.g. "on"/"off"). Case is normalised on save.',target_changes_help:"Number of matching transitions before the trigger fires (default: 1).",state_latch_help:"With 1 transition the trigger is a latch: it recovers when the entity leaves the To-state \u2014 or, with only a From-state set, when it returns to that state.",for_minutes_state_help:"0 counts every change immediately. Set minutes and the new state must hold that long first \u2014 brief flickers then neither trigger nor count.",qr_print_title:"Print QR codes",qr_print_desc:"Generate a printable page of QR codes to cut out and stick on your equipment.",qr_print_load:"Load objects",qr_print_filter:"Filter",qr_print_objects:"Objects",qr_print_actions:"Actions",qr_print_url_mode:"Link type",qr_print_estimate:"Estimated QR codes",qr_print_over_limit:"cap is 200, narrow the filter",qr_print_generate:"Generate QR codes",qr_print_generating:"Generating\u2026",qr_print_ready:"QR codes ready",qr_print_print_button:"Print",qr_print_empty:"Nothing to generate",qr_action_skip:"Skip",vacation_title:"Vacation mode",vacation_active:"active",vacation_ended:"ended",vacation_desc:"Plan a vacation: notifications are paused during the period plus a buffer of days. You can opt specific tasks back in.",vacation_enable:"Enable vacation mode",vacation_start:"Start",vacation_end:"End",vacation_buffer:"Buffer (days)",vacation_exempt_title:"Notify anyway during vacation",vacation_exempt_desc:"Pick tasks that should still notify during vacation (e.g. critical pool chemistry).",vacation_load_tasks:"Load tasks",vacation_preview_btn:"Show preview",vacation_preview_affected:"tasks affected",vacation_event_due_soon:"becomes due soon",vacation_event_overdue:"becomes overdue",vacation_event_triggered_est:"sensor trigger possible",vacation_sensor_based:"(sensor-based)",vacation_action_notify:"Notify anyway",vacation_action_unsilence:"Silence again",vacation_marked_complete:"Marked complete",vacation_marked_skip:"Skipped",vacation_end_now:"End vacation now",add:"Add",show_stats:"Show stats + graphs",hide_stats:"Hide stats",adaptive_no_data:"Not enough completion history yet for adaptive analysis. Complete this task a few more times to unlock interval recommendations and reliability charts.",suggestion_applied:"Suggested interval applied",vacation_mode:"Vacation mode",vacation_status_active:"Active now",vacation_status_scheduled:"Scheduled",vacation_status_inactive:"Inactive",vacation_end_now_confirm:"End vacation immediately?",vacation_exempt_count:"exempt",vacation_advanced:"Advanced\u2026",vacation_open_panel:"Open in panel",enable:"Enable",saved:"Saved",budget_monthly_set:"Set monthly",budget_yearly_set:"Set yearly",budget_advanced:"Currency, alerts\u2026",budget_open_panel:"Open in panel",groups_empty:"No groups yet.",group_new_placeholder:"Add group\u2026",groups_manage_tasks:"Manage task assignments\u2026",groups_open_panel:"Open in panel",unassigned:"Unassigned",no_area:"No area",has_overdue:"Has overdue tasks",object:"Object",settings_panel_access:"Panel access",settings_panel_access_desc:"Admins always have full access. To delegate create, edit and delete to specific non-admins, switch this on and pick them below \u2014 everyone else only gets Complete, Skip, Reset, Postpone and Snooze.",settings_operator_write:"Allow selected users to create, edit & delete",settings_operator_write_desc:"Off: only admins can change content. On: the selected users below get full access too.",no_non_admin_users:"No non-admin users found. Add some in Settings \u2192 People.",owner_label:"Owner",feat_completion_actions:"Completion actions",feat_completion_actions_desc:"Per-task HA action on complete + quick-complete QR with pre-set values.",feat_places:"Places",feat_places_desc:"Objects maintained at another place (a Home Assistant zone): reminders only while somebody is there, and a message on arrival.",on_complete_action_title:"On complete: trigger HA action (optional)",on_complete_action_desc:"Calls an HA service when the task is completed \u2014 e.g. reset a counter on the device.",on_complete_action_target:"Target entity",on_complete_action_target_hint:"Note: the entity domain must match the service \u2014 e.g. 'button.press' only works on button.*, 'counter.increment' only on counter.*, 'input_button.press' only on input_button.* etc. On a mismatch the action will silently fail (HA logs 'Referenced entities ... missing or not currently available').",on_complete_action_target_more:"This action targets more than this field shows: {targets}. That is kept as it is \u2014 choosing another entity here replaces the whole target.",on_complete_action_skip_auto:"Not when the task completes itself (its sensor recovered)",on_complete_action_data:"Data (JSON, optional)",on_complete_action_test:"Validate configuration",on_complete_action_test_success:"\u2713 Configuration valid (action will fire only on task completion)",on_complete_action_test_failed:"Failed",action_test_bad_format:"Invalid service format (expected 'domain.service')",action_test_unknown_service:'Service "{service}" is not registered in Home Assistant. Check the spelling and that the integration providing it is loaded.',action_test_domain_mismatch:`Service "{service}" only works on {domain}.* entities; entity "{entity}" is in {entity_domain}.* \u2014 pick a service that matches the entity's domain (e.g. {suggestion})`,action_test_entity_missing:'Target entity "{entity}" was not found in Home Assistant \u2014 it may have been renamed or its integration removed.',quick_complete_defaults_title:"Quick-complete defaults (for QR scans, optional)",quick_complete_defaults_desc:"Pre-set values for quick-complete QR scans. Without these, the QR opens the complete dialog.",quick_complete_defaults_notes:"Notes",quick_complete_defaults_cost:"Cost",quick_complete_defaults_duration:"Duration (minutes)",quick_complete_defaults_feedback_none:"No feedback",quick_complete_defaults_feedback_needed:"Was needed",quick_complete_defaults_feedback_not_needed:"Not needed",quick_complete_success:"Quickly marked complete",show_all_objects:"Show all objects",show_all_tasks:"Clear filter \u2014 show all tasks",filter_to_overdue:"Filter task list to overdue only",filter_to_due_soon:"Filter task list to due-soon only",filter_to_triggered:"Filter task list to triggered only",open_task:"Open task",show_details:"Show history + stats",hide_details:"Hide details",history_empty:"No history yet.",history_edit_button:"Edit entry",total_cost:"Total cost",times_performed:"Performed",older_entries:"older",open_in_panel:"Open in Maintenance panel",skip_reason:"Skip reason (optional)",reset_to_date:"Reset last_performed to",delete_task_confirm:"Delete this task and its history?",delete_object_confirm:"Delete this object and all its tasks?",loading:"Loading\u2026",archive:"Archive",undo:"Undo",task_completed_named:"Completed: {task}",undo_done:"Completion undone",undo_done_action_ran:"Completion undone. Its completion action had already run and cannot be taken back.",undo_nothing:"Nothing to undo. Only your own last completion can be taken back, within 10 minutes.",undo_changed:"Can't undo. The task has changed since.",task_archived:"Task archived",object_archived:"Object archived",unarchive:"Unarchive",archived:"Archived",show_archived:"Show archived",hide_archived:"Hide archived",section_collapse:"Collapse section",section_expand:"Expand section",confirm_archive_object:"Archive this object and its tasks? They keep their history and can be unarchived later.",settings_archive:"Archive & Retention",settings_archive_desc:"Retire completed one-off tasks without deleting them. Archived items are hidden and inert but keep their history and cost.",settings_archive_oneoff_days:"Auto-archive completed one-off tasks after (days, 0 = off)",settings_delete_archived_oneoff_days:"Auto-delete archived one-off tasks after (days, 0 = never)",archive_object:"Archive object",unarchive_object:"Unarchive object",documents:"Documents",documents_empty:"No documents yet.",doc_upload:"Upload file",doc_uploading:"Uploading\u2026",doc_add_link:"Add link",doc_link_url:"URL (https://\u2026)",doc_link_title:"Title (optional)",doc_open:"Open",doc_delete_confirm:'Delete "{name}"?',doc_too_large:"File is too large (max 100 MB).",doc_upload_failed:"Upload failed.",docs_archive_too_large:"The archive is too large (max {max}).",docs_archive_no_manifest:"This ZIP has no manifest.json, so the restore cannot tell which document a file belongs to. Keep manifest.json next to the folders when zipping again.",completion_photos_optional:"Completion photos (optional)",completion_photos:"Completion photos",choose_photos:"Choose photos",choose_photo:"Choose photo",photos_android_hint:"The Android app hands over one photo per pick \u2014 each pick is added.",photos_limit:"Up to {max} photos per completion",history_edit_photos_hint:"Removing a photo here keeps the file in the object's documents.",uploading:"Uploading\u2026",remove:"Remove",doc_deduped:"Already stored elsewhere \u2014 shared, no extra space used.",doc_dup_in_object:"This file is already attached to this object.",doc_link_not_allowed:"This link is not allowed: links that run scripts or open local files (javascript:, data:, file: \u2026) are refused.",doc_cat_manual:"Manual",doc_cat_warranty:"Warranty",doc_cat_invoice:"Invoice",doc_cat_spare_parts:"Spare parts",doc_cat_photo:"Photo",doc_cat_other:"Other",doc_link_badge:"Link",doc_storage_title:"Document storage",doc_storage_saved:"Saved via deduplication",doc_storage_refresh:"Refresh",doc_download:"Download",doc_close:"Close",doc_camera:"Take photo",camera_capture_shoot:"Capture",camera_switch_lens:"Switch camera",camera_switching:"Switching camera\u2026",camera_not_answered:"This camera did not answer. Tap the switch again to try the next one, or use the file picker.",camera_diagnostics:"Details for a bug report",camera_copy:"Copy",camera_copied:"Copied",doc_drop_hint:"Drop files here",doc_task_none:"No documents linked to this task.",doc_link_existing:"Link a document\u2026",doc_attach:"Link",doc_unlink:"Unlink",doc_page:"Page",chart_range_7d:"7d",chart_range_30d:"30d",chart_range_90d:"90d",chart_range_1y:"1y",chart_since_service:"since last service",chart_no_stats:"No long-term statistics for this entity \u2014 showing maintenance-event values only",auto_complete_on_recovery:"Auto-complete when the sensor recovers",auto_complete_on_recovery_help:"Records a completion (sets last performed) when the trigger clears itself \u2014 e.g. salt refilled, filter replaced.",doc_search:"Search documents\u2026",doc_search_none:"No matching documents",doc_description:"Description (optional)",doc_sort:"Sort documents",doc_sort_newest:"Newest first",doc_sort_oldest:"Oldest first",doc_sort_title:"By title (1, 2, 3 \u2026)",doc_sort_category:"By category",link_device_optional:"Link to existing device (optional)",parent_object_optional:"Parent object (optional)",parent_none:"(No parent)",paused:"Paused",pause_object:"Pause",resume_object:"Resume",pause_task:"Pause",resume_task:"Resume",pause_task_prompt:"Freeze this task's schedule \u2014 it does not become due and does not notify until you resume it, and resuming starts a fresh cycle from that day. The object's other tasks keep running. Optionally set a date to resume by itself.",task_paused:"Task paused",task_resumed:"Task resumed \u2014 its schedule restarted",pause_until_prompt:"Freeze this object's schedules \u2014 nothing becomes due and nothing notifies until it is resumed. Optionally set an auto-resume date.",pause_until_label:"Resume on (optional)",object_paused:"Object paused",object_resumed:"Object resumed \u2014 schedules restarted",object_paused_badge:"Paused",paused_until_label:"until",replace_object:"Replace\u2026",replace_object_prompt:"Retire this object and create a successor. History and costs stay archived on the old one; tasks and documents carry over to the new one, counters start fresh.",replace_name_label:"Successor name",replace_device_heading:"Device in Home Assistant",replace_device_keep:"Same device as before ({device})",replace_device_keep_hint:"Also the choice when the new unit is not in Home Assistant yet: once it is, pick it as the object's device in its settings \u2014 the sensor triggers move along then.",replace_device_other:"The new unit is another device",replace_device_pick:"Device of the new unit",replace_device_other_hint:"Sensor triggers, completion actions and the counter reset move to the matching entities of that device.",replace_device_none:"No device",object_replaced:"Object replaced \u2014 successor created",device_swap_moved:"{count} sensor links moved to the new device.",device_swap_moved_one:"One sensor link moved to the new device.",device_swap_unmatched:"{count} could not be matched \u2014 check those tasks' sensor triggers.",device_swap_unmatched_one:"One could not be matched \u2014 check that task's sensor trigger.",reading_unit_label:"Reading unit (e.g. kWh, m\xB3)",reading_unit_help:"Shown next to the recorded value when completing this task.",reading_value_label:"Reading value",reading_label:"Reading",readings_section:"Readings",readings_hint:"Several named values per completion \u2014 one row per meter. Leave empty to record a single value.",reading_name_label:"Reading name",reading_unit_short:"Unit",reading_add:"Add reading",reading_duplicate_name:"Name already used",reading_last:"last: {value}",reading_below_last:"Lower than the last reading ({value})",settings_templates_label:"Template gallery",settings_templates_hint:`Untick templates you'll never need \u2014 they disappear from the "From template" pickers (panel and config flow). Nothing else changes; you can re-enable them any time.`,home_profile_title:"Home profile",home_profile_hint:"Recommends templates and sets seasonal windows for your climate and hemisphere. Everything is worked out locally from your floors, areas and home location.",home_type_label:"Home type",home_type_auto:"Automatic ({detected})",home_region_label:"State, province or region",home_region_none:"not found",home_region_hint:"Some rules differ within a country \u2014 a yearly vehicle inspection in one state, none in the next. Found from your home location.",home_dwelling_house:"House",home_dwelling_apartment:"Apartment",home_dwelling_unknown:"not recognised",home_detected_from:"Detected from: {reasons}",home_reason_floors:"several floors",home_reason_basement:"a basement",home_reason_garden:"a garden",home_reason_shed:"a shed",home_reason_driveway:"a driveway",home_reason_garage:"a garage",home_reason_attic:"an attic",home_reason_lawn_mower:"a lawn mower",home_reason_gate:"a gate",home_reason_balcony:"a balcony",home_reason_small_home:"few rooms on one floor",home_reason_ups:"a UPS",home_climate_label:"Climate",home_climate_value:"K\xF6ppen {koppen} \xB7 coldest month {cold} \xB0C \xB7 warmest month {warm} \xB0C",home_climate_unknown:"No home location set in Home Assistant",home_hemisphere_south:"Southern hemisphere \u2014 seasonal windows are mirrored",home_trait_freeze:"Frost in winter",home_trait_snow:"Snowy winters",home_trait_severe_winter:"Severe winters",home_trait_damp:"Damp climate",home_trait_mediterranean:"Mediterranean climate",home_trait_earthquake:"Earthquake region",home_trait_hot_summer:"Hot summers",home_trait_hot_humid:"Hot and humid",home_trait_hot_dry:"Hot and dry",home_trait_termites:"Termite region",home_trait_wildfire:"Wildfire risk",home_trait_cyclone:"Hurricane / typhoon region",home_trait_tropical:"Tropical climate",home_trait_radon:"Radon test recommended",home_reason_starter:"Basics for your home",home_reason_country:"Common in {country}",home_reason_feature:"Found in your home: {feature}",templates_recommended_title:"Recommended for your home",templates_recommended_hint:"Based on your home profile \u2014 adjust it in Settings.",templates_legal_hint:"Notes on legal duties and intervals are guidance, not legal advice. Rules vary by region and change over time \u2014 local regulations and the manufacturer's instructions take precedence.",templates_not_typical:"Not typical for your home type",templates_set_up:"Already set up",worksheet:"Work sheet",worksheet_scan_view:"Scan to open the task",worksheet_scan_complete:"Scan to complete",worksheet_manual_excerpt:"Manual excerpt",worksheet_pages:"pages",worksheet_printed:"Printed",worksheet_never:"Never",card_all_caught_up:"All caught up \u2014 nothing needs attention",postpone:"Postpone",postpone_date_prompt:"Postpone this occurrence to which date?",postpone_date_label:"New due date",postponed:"Postponed",postponed_to:"Postponed to",season_window_label:"Seasonal window (months)",season_window_hint:"Only due in the selected months; off-season dates roll to the next active month. None = all year.",series_end_label:"Ends",series_end_never:"Never (repeats indefinitely)",series_end_after_count:"After a number of times",series_end_until:"On a date",series_end_count_label:"Number of times",series_end_until_label:"End date",parts_section:"Parts & consumables",parts_inventory_value:"Inventory value",part_add:"Add part",part_name:"Name",part_vendor:"Manufacturer",part_storage_location:"Storage location",part_product_url:"Product URL",part_unit:"Unit",part_cost:"Unit price",part_stock:"Stock",part_reorder_threshold:"Reorder at",part_restock_quantity:"Restock quantity",part_package_size:"Package size (units)",part_restock_packages:"Restock amount (packages)",part_package_hint:"Bought in packages, used in the unit: stock, the amount a task uses and the reorder threshold count units; the restock amount and the price are per package.",part_auto_buy:"Auto-create buy task when low",part_reuse:"After use",part_reuse_none:"Used up",part_reuse_charge:"Charged",part_reuse_sharpen:"Sharpened",part_reuse_clean:"Cleaned",part_reuse_dry:"Dried",part_reuse_refill:"Refilled",part_reuse_restore:"Restored",part_waiting_charge:"{count} to charge",part_waiting_sharpen:"{count} to sharpen",part_waiting_clean:"{count} to clean",part_waiting_dry:"{count} to dry",part_waiting_refill:"{count} to refill",part_waiting_restore:"{count} to restore",part_restoring:"Used, not ready yet",part_ready_again_hint:"All used ones are ready again",part_reuse_hint:"A used one is not gone: it waits until it is ready again and still counts as owned, so it is not bought again.",part_restock:"Adjust stock",parts_used_by:"Used by",restock_quantity_label:"Quantity bought",consumes_parts_label:"Consumes parts",task_parts_fleet_hint:"Battery quantities come from Battery Notes per device \u2014 nothing to link here.",shared_parts_other_objects:"Parts from other objects",shared_parts_help:"Several objects can share one stock. Completing this task takes from the owning object.",shared_part_unknown:"Unknown part",parts_load_failed:"Couldn't load this object's parts \u2014 the consumes-parts options are unavailable right now.",adopt_problem_button:"Adopt problem sensors",adopt_problem_title:"Adopt problem sensors",adopt_problem_hint:"Turn HA problem sensors (printer errors, filter warnings, low battery) into maintenance tasks that trigger while the problem is active and clear themselves when it resolves.",adopt_problem_none:"No problem sensors found that aren't already tracked.",adopt_problem_active:"active",adopt_problem_ok:"ok",adopt_problem_new_object:"(new)",adopt_object_hint:"Give several sensors the same object name and they become one object; type an existing object's name to add them there.",adopt_summary_title:"What adopting changes",adopt_summary_existing:'"{name}": tasks {before} \u2192 {after}',adopt_problem_adopt:"Adopt selected",adopt_problem_done:"Adopted {tasks} problem sensor(s)",adopt_problem_done_one:"Adopted 1 problem sensor",views_label:"Views",views_none:"\u2014 No view \u2014",views_manage:"Save / manage views",views_dialog_title:"Saved views",views_dialog_hint:"Save the current filters as a named view everyone can reuse.",views_name_placeholder:"View name",views_save_current:"Save current filters",views_none_yet:"No saved views yet.",close:"Close",trigger_hint_now:"The sensor reads {value} right now.",trigger_hint_above:"The task triggers once it rises above {target}.",trigger_hint_below:"It triggers once it falls below {target}.",trigger_hint_overlap:"These limits overlap: every reading triggers the task and it can never recover. Leave one of them empty.",trigger_hint_counter_delta:"Counts from the current reading ({value}): due at {due} (+{target}), and the count restarts after each completion.",trigger_hint_counter_delta_edit:"Counts usage since the last completion: due after +{target}; the count restarts after each completion.",trigger_hint_counter_abs:"The task becomes due once the sensor reaches {target}.",trigger_hint_runtime:"The task becomes due after {hours} h of accumulated on-time; the counter restarts after each completion.",trigger_hint_due_date:"The task becomes due {days} days before the date the sensor reports.",trigger_hint_due_date_one:"The task becomes due one day before the date the sensor reports.",trigger_hint_due_date_same_day:"The task becomes due on the date the sensor reports.",trigger_hint_due_date_now:"Reported date: {date}.",trigger_hint_state_change:"The task becomes due after {count} state change(s).",trigger_hint_state_change_to:"The task becomes due after {count} change(s) to \u201C{state}\u201D.",trigger_hint_state_now:"Current state: {value}.",adopt_problem_part:"Uses part: {name}",label_filter:"Label",all_labels:"All labels",filter_place:"Place",filter_place_all:"All places",settings_notify_scope:"Notify only for view",settings_notify_scope_all:"All tasks",settings_notify_scope_hint:"Only tasks matching the selected saved view's label/user filters send reminders. Status, sorting and grouping of the view are ignored here.",settings_notify_completed:"Completion notifications",settings_notify_completed_hint:`Household news when a task is completed, with the reason and who did it. "Automatic only" announces just the completions nobody made on the spot: sensor recovery, shopping-list check-off, an automation's service call. Sent to the household service only; quiet hours and the daily cap apply.`,settings_title_style:"Notification title style",settings_title_style_hint:"What appears as the notification's TITLE. Default keeps the per-status text (e.g. 'Maintenance overdue!'). Object name / Task name help when phone notifications stack.",title_style_default:"Default (per-status title)",title_style_object_name:"Object name as title",title_style_task_name:"Task name as title",notify_completed_off:"Off",notify_completed_automatic:"Automatic completions only",notify_completed_all:"All completions",settings_notify_rule:"Your own notification rule",settings_notify_rule_hint:"Every notification also fires the event maintenance_supporter_notification (kind, status, object, task, reference numbers, priority, deep link, the payload). Route it with an automation \u2014 e.g. into Ticker, Telegram or Pushover.",settings_notify_event_only:"Only fire the event, send nothing myself",settings_notify_event_only_hint:"Your automation is the whole delivery. Rate limits, quiet hours and the daily cap still apply to when the event fires.",settings_notify_extra_data:"Extra notification data (template)",settings_notify_extra_data_hint:"JSON or YAML, Jinja allowed; merged into the notify call's data (your keys win). Variables: kind, status, priority, labels, notes, area_name, object_name, task_name, object_ref, task_ref, days_until_due, next_due, last_performed, responsible_user_id, sensor_entity_id, url, target, title, message. Test it with the Send test button.",card_saved_view:"Saved view",card_saved_view_none:"None",card_saved_view_help:"Applies the view's status, user, label and priority filters on top of the filters above. The view's sorting and grouping are panel display settings and are not applied on the card.",panel_card_tab:"Open on tab",panel_card_tab_default:"Remembered tab (as in the panel)",panel_card_view:"Open with saved view",panel_card_height:"Height",panel_card_height_help:"Empty = fill the screen below the card (panel view). Otherwise a CSS length such as 600px or 80vh for views with other cards.",panel_card_not_registered:"The Maintenance Supporter panel is not available \u2014 is the integration set up?",panel_card_load_failed:"The Maintenance Supporter panel could not be loaded \u2014 reload the page (after an update: clear the browser cache).",doc_part_none:"No documents linked to this part.",settings_templates_toggle_group:"Enable or disable all templates in this group",setups_button:"Suggested setups",setups_title:"Suggested setups (Beta)",setups_hint:"Devices of supported integrations whose consumable sensors can drive maintenance tasks. Adopting creates the object and wires each task to its sensor \u2014 it triggers when the consumable runs low and resolves itself after replacement.",setups_none:"No supported devices with unwired consumable sensors found.",setups_adopt:"Set up selected",setups_done:"{tasks} sensor-wired tasks created.",setups_done_one:"1 sensor-wired task created.",complete_parts_used:"Parts used this time",part_delete_confirm:"Delete part '{name}'? Its stock tracking, task links and any open buy reminder will be removed.",baseline_start_value:"Start reading (optional)",baseline_start_help:"Counting starts from this reading. Leave empty to count from the current value; enter the reading at the last service so usage since then already counts.",setups_baseline_hint:"reading at last service (optional)",baseline_start_help_edit:"Leave empty to keep the existing counting. Entering a value re-anchors the counting (e.g. the reading at the last service).",baseline_current_effective:"Currently effective start value: {value}",runtime_on_states:"Active states",runtime_on_states_help:"States that count as running \u2014 default: on. E.g. mowing, cleaning, printing. With an attribute selected, its values are matched instead.",runtime_max_session:"Max session runtime (seconds)",runtime_max_session_help:"A single run counts at most this many seconds \u2014 protects against a sensor stuck ON (lost connection, restart). Empty = no cap.",trend_approaching:"Heading toward the threshold",trend_easing:"Easing away from the threshold",split_select_hint:"Select a task to see its details here",setups_target_new:"Create new: {name}",setups_target_match:"{name} \u2014 matches: {reasons}",setups_reason_model:"model number",setups_reason_name:"name",setups_reason_area:"area",setups_reason_sibling:"same model on another device",setups_maybe_covered:'Probably there already as "{name}"',setups_already:"Already there: {names}",setups_reset_line:"Completing it also resets the counter in the integration (\u201C{button}\u201D)",setups_reset_enable:"\u2014 the button gets switched on for this",reset_offers_title:"Reset counters on completion",reset_offers_hint:"These tasks watch a counter the integration keeps itself. Connected, completing the task here also presses the integration's reset button \u2014 otherwise the counter keeps running and the task falls due again right away.",reset_offers_before:"Now: completing it leaves the counter in {integration} running",reset_offers_after:"Then: it also presses \u201C{button}\u201D",reset_offers_renamed:"Renamed since it was set up \u2014 check that this task is for this part",reset_offers_apply:"Connect resets",reset_offers_done:"{count} tasks now reset their counter on completion",reset_offers_done_one:"1 task now resets its counter on completion",setups_before_after:"Tasks on the object: {before} \u2192 {after}",setups_new_object_count:'New object "{name}" \xB7 tasks: {count}',schedule_preview_title:"Next dates",schedule_preview_ontime:"Assuming on-time completion.",schedule_preview_ends:"(series ends)",adopt_problem_responsible:"Responsible user for all adopted tasks (optional)",adopt_for_minutes_hint:"Only trigger once the problem has persisted this long \u2014 0 reacts to the first flicker.",adopt_problem_configure:"Configure",history_auto:"Automatic",battery_fleet_title:"Battery fleet",battery_fleet_none_low:"All batteries OK \u2014 nothing to replace.",battery_fleet_progress:"{n} to replace",battery_fleet_buy_now:"Buy now",battery_fleet_soon:"Needed soon",battery_fleet_soon_hint:"Predicted from the last replacement date \u2014 order ahead.",battery_fleet_mark_all:"Mark all replaced",battery_fleet_mark_one:"Mark this battery replaced",battery_fleet_offline:"offline",battery_fleet_no_sensor:"No sensor",battery_fleet_trigger_lost:"This task's sensor trigger was lost \u2014 it will not fire or auto-complete.",battery_fleet_repair:"Repair",battery_fleet_exclude:"Exclude from the fleet",battery_fleet_excluded:"Excluded",battery_fleet_include:"Track again",battery_fleet_all:"All tracked batteries",battery_fleet_all_hint:"Exclude a device here to drop it from the fleet before it ever reports low \u2014 a vacuum that recharges itself, or a phone that warns you on its own.",battery_fleet_add:"Add a battery",battery_fleet_add_hint:"Pick a battery sensor the automatic discovery missed \u2014 it joins the roster immediately.",battery_fleet_track_self:"Track self-charging batteries",battery_fleet_track_self_hint:"Phones, vacuums and other devices that recharge themselves appear as rechargeables \u2014 a low one asks for a charge, never for new cells.",battery_fleet_due_without_sensor:"Treat a passed forecast as due when a battery has no sensor",battery_fleet_due_without_sensor_hint:"Some devices report no battery level at all \u2014 Battery Notes only knows the type and the last replacement. Once the typical lifetime has passed, such a battery counts as low and the fleet task reminds you; marking it replaced resets the forecast.",battery_fleet_status_low:"Low",battery_fleet_status_soon:"Soon",battery_fleet_status_ok:"Healthy",battery_fleet_status_due:"Due",battery_fleet_predicted_on:"Expected around {date}",battery_fleet_predicted_typical:"Expected around {date} \u2014 {months} months typical for {type} ({source})",lifetime_source_default:"built-in default",lifetime_source_table:"built-in table",lifetime_source_learned:"learned from {n} replacements",lifetime_source_override:"your setting",lifetime_source_learned_device:"learned from this device's {n} replacements",lifetime_source_learned_model:"learned from {n} replacements on devices of this model",battery_fleet_predicted_trend:"Predicted from this battery's discharge trend: around {date} ({confidence})",battery_fleet_rechargeable:"Rechargeable: charge instead of replacing \u2014 never on the shopping list",battery_fleet_sort_name:"Sort by name",battery_fleet_sort_urgency:"Sort by urgency",battery_fleet_mark_recharged:"Mark as recharged",battery_fleet_charging:"Rechargeable spares",battery_fleet_ready:"{count} ready",battery_fleet_sparkline_hint:"Battery level over the last 30 days \u2014 dotted: projected until the low threshold",battery_fleet_filter_type:"Show only this battery type",battery_fleet_record_replacement:"The level jumped around {date} \u2014 record this replacement in Battery Notes",battery_fleet_total:"{n} batteries tracked",battery_fleet_setup_button:"Battery fleet",battery_fleet_setup_done:"Battery fleet set up \u2014 one task tracks all your batteries.",update_banner:"A newer version of Maintenance Supporter is on the server \u2014 reload to update the panel.",update_reload:"Reload",row_actions_banner:"Complete and Skip in task rows are now buttons. Prefer the old icons?",row_actions_keep:"Keep buttons",row_actions_back:"Back to icons",battery_fleet_forecast_overdue:"Predicted date passed \u2014 the battery still reports healthy. If you swapped it, record the replacement; otherwise the forecast was off.",cost_from_parts:"Use \u2248 {amount} from parts",cost_parts_booked:"Parts used \u2248 {amount} are booked automatically \u2014 enter only additional costs.",cost_parts_info:"Parts used \u2248 {amount} \u2014 counted when they were bought, not here.",cost_purchase_use_hint:"The price paid becomes the part's price \u2014 spare parts count when they are used.",history_parts_counted:"Parts: {amount}",history_parts_counted_hint:"Value of the parts used \u2014 counted as spending",history_parts_info:"Parts \u2248 {amount}",history_parts_info_hint:"Value of the parts used \u2014 information only; the money counted when they were bought",history_purchase_stock:"Bought for {amount} (counted when used)",dismiss:"Dismiss",gs_label:"Getting started \u2014 these hints retire as your setup grows",gs_setups_chip:"Suggested setups found {n} devices with pre-wired triggers",gs_setups_chip_one:"Suggested setups found 1 device with pre-wired triggers",gs_adopt_chip:"{n} problem sensors can become maintenance tasks",gs_adopt_chip_one:"1 problem sensor can become a maintenance task",gs_fleet_chip:"One click sets up the battery fleet",gs_reset_chip:"{n} tasks can reset their counter in the integration",gs_reset_chip_one:"1 task can reset its counter in the integration",cal_editor_window:"Default window",cal_editor_window_week:"Week (7 days)",cal_editor_window_fortnight:"Fortnight (14 days)",cal_editor_window_month:"Month (30 days, default)",cal_editor_window_year:"Year (365 days, empty days collapsed)",cal_editor_window_past_30:"Past 30 days (history)",cal_editor_window_past_90:"Past 90 days (history)",cal_editor_show_chips:"Show window chips inside the card",cal_editor_chips_hint:"Hide the chips when the card is embedded in a strategy view that already serves as the window selector.",cal_editor_show_user_filter:"Show user filter dropdown",cal_editor_default_user:"Default user filter",cal_editor_my_tasks:"My tasks (current user)",cal_editor_show_object_filter:"Show object filter dropdown",cal_editor_object_hint:'Pre-select one object via YAML: object_filter: "" \u2014 or a list of names to restrict the card to several objects.',object_history_section:"History (all tasks)",object_history_all_tasks:"All tasks",object_history_empty:"No entries in this range.",object_history_cap_note:"History keeps up to 500 entries per task \u2014 very old entries may be missing.",service_record_title:"Service record",service_record_print:"Service record (PDF)",date:"Date",service_record_entries:"entries",ref_number:"Reference number",print_options_title:"Print service record",print_layout:"Layout",print_layout_chronological:"Chronological",print_layout_by_task:"By task",print_include:"Include",print_inc_readings:"Readings",print_inc_parts:"Parts used",print_inc_photos:"Photos",print_inc_documents:"Linked documents",print_inc_doc_desc:"Document descriptions",print_inc_checklist:"Checklist",print_inc_notes:"Notes",print_inc_costs:"Cost and duration",print_inc_person:"Completed by",print_inc_refs:"Reference numbers",print_inc_bare:"Completions without details",print_inc_qr:"QR code per task",print_button:"Print",report_scan_hint:"Scan to open the task",completed_by:"Completed by",date_from:"From",date_to:"To",phases_section:"Cycle phases (optional)",phases_hint:"Different work on one shared schedule \u2014 each completion moves to the next step (e.g. small service, small service, big service).",phase_add:"Add phase",phase_name:"Phase name",phase_sequence_label:"Cycle order",phase_sequence_add_step:"Add step",phase_current:"Current phase",phase_set:"Set as current",chart_history_fallback:"No long-term statistics for this entity \u2014 showing recorder state history (typically the last ~10 days)",chart_history_alarm:"Trigger view from recorder state history: 1 = alert state held for the hold time, 0 = fine (typically the last ~10 days)",chart_history_count:"Change count rebuilt from recorder state history since the last service (typically the last ~10 days)",prediction_cycles:"Learned from cycles",phase_require_override:"Override \u201CRequire on completion\u201D for this phase",history_add_past:"Add past completion",require_tag_scan:"Only complete by scanning the tag",require_tag_scan_help:"Proof of presence: Done is blocked on every surface until the NFC tag or QR code on the thing itself is scanned. Automations can pass 'via_tag_scan' to the complete service.",disallow_skip:"Don't allow skipping",disallow_skip_help:"The Skip action disappears from every surface, and the server refuses a skip from automations and voice too.",no_notifications:"No notifications for this task",no_notifications_help:"No reminders for this task \u2014 no status notifications, repeats, lead-time reminders or bundles. It still shows on the dashboard and in its entities; the weekly digest still counts it.",require_tag_scan_hint:"This task completes only by scanning its NFC tag or QR code on the thing itself \u2014 saving here will be refused."}});var Is,Rs=y(()=>{"use strict";Is="2.102.0"});function Ki(s){Ne.en=Object.assign({},s,Ne.en??{})}function be(s){let r=(s||Gi).toLowerCase();return r.startsWith("pt")&&r.endsWith("br")?"pt-br":r.substring(0,2)}function a(s,r,e){let t=be(r);return Ne[t]?.[s]??Ne.en?.[s]??e??s}function He(s){let r=be(s);return r===Gi||r in Ne}function qe(s){let r=be(s);return r===Gi||r in Ne||!bo.has(r)?Promise.resolve():(r in xt||(xt[r]=fetch(`${xo}/${r}.json?v=${Is}`).then(e=>e.ok?e.json():null).then(e=>{e?Ne[r]=e:delete xt[r]}).catch(()=>{delete xt[r]})),xt[r])}var Gi,Ps,Ne,xt,bo,xo,Xt=y(()=>{"use strict";Rs();Gi="en",Ps=(()=>{let s=window;return s.__msLocales||(s.__msLocales={store:{},inflight:{}}),s.__msLocales})(),Ne=Ps.store,xt=Ps.inflight;bo=new Set(["de","nl","fr","it","es","pt","pt-br","ru","uk","pl","cs","sv","zh","da","fi","nb","ja","hi","hu","ko","tr"]),xo="/maintenance_supporter_locales"});function Ls(s){let r=s?.language;!r||typeof s?.loadBackendTranslation!="function"||ie.lang===r&&(ie.localize||ie.inflight)||(ie.lang=r,ie.localize=null,ie.inflight=s.loadBackendTranslation("exceptions",Yi).then(e=>{ie.lang===r&&(ie.localize=e)}).catch(()=>{}).finally(()=>{ie.inflight=null}))}function Ns(s,r,e){if(!r||!ie.localize||s&&s!==Yi)return null;let t=`component.${Yi}.exceptions.${r}.message`,i=ie.localize(t,e??void 0);return i&&i!==t?i:null}var Yi,ie,Qi=y(()=>{"use strict";Yi="maintenance_supporter",ie=(()=>{let s=window;return s.__msBackendErrors??={lang:"",localize:null,inflight:null}})()});function De(s){return s?.currency_symbol||wo}function Hs(s,r){r.has("hass")&&Ji(s.hass?.locale,s.hass?.config?.country,s.hass?.config?.time_zone);let e=s.hass?.language;e&&!He(e)&&qe(e).then(()=>s.requestUpdate()),Ls(s.hass)}function N(s){return s?.language||"en"}function qs(s){let r=be(s);return{de:"de-DE",en:"en-US",nl:"nl-NL",fr:"fr-FR",it:"it-IT",es:"es-ES",pt:"pt-PT",ru:"ru-RU",uk:"uk-UA",zh:"zh-CN",da:"da-DK",fi:"fi-FI",nb:"nb-NO",ja:"ja-JP",hi:"hi-IN",pl:"pl-PL",cs:"cs-CZ",sv:"sv-SE","pt-br":"pt-BR",hu:"hu-HU",ko:"ko-KR",tr:"tr-TR"}[r]??"en-US"}function ko(s){Ds.decimals=typeof s=="number"&&Number.isInteger(s)&&s>=0&&s<=3?s:0}function $o(){return Ds.decimals??0}function ei(s){s&&s.currency_decimals!==void 0&&s.currency_decimals!==null&&ko(Number(s.currency_decimals))}function Ji(s,r,e){e!==void 0&&(re.serverTimeZone=e||void 0),s&&(re.date=s.date_format,re.time=s.time_format,re.number=s.number_format,re.timeZone=s.time_zone,r!==void 0&&(re.country=r||void 0))}function Eo(s){switch(re.number){case"comma_decimal":return["en-US","en"];case"decimal_comma":return["de","es","it"];case"space_comma":return["fr","sv","cs"];case"system":return;default:return qs(s)}}function C(s,r,e){if(!Number.isFinite(s))return String(s);let t=typeof e=="number"?{minimumFractionDigits:e,maximumFractionDigits:e}:{maximumFractionDigits:2,...e};if(re.number==="none"){let i=Math.pow(10,t.maximumFractionDigits??2);return String(Math.round(s*i)/i)}try{return new Intl.NumberFormat(Eo(r),t).format(s)}catch{return new Intl.NumberFormat(void 0,t).format(s)}}function J(s,r,e,t){let i=t??$o(),n=Math.abs(s)<.5/Math.pow(10,i)?0:s,o=C(n,e,i);return r?`${o} ${r}`:o}function Ze(s,r,e){let t=C(s,e);return r?`${t} ${r}`:t}function Ye(s){let r=qs(s),e=re.country;if(e&&/^[A-Za-z]{2}$/.test(e)){let t=`${be(s).split("-")[0]}-${e.toUpperCase()}`;try{return new Intl.DateTimeFormat(t),t}catch{}}return r}function Zi(s,r,e){let t=re.date;if(t==="DMY"||t==="MDY"||t==="YMD"){let[n,o,d]=ve(s,e).split("-");return t==="DMY"?`${d}/${o}/${n}`:t==="MDY"?`${o}/${d}/${n}`:`${n}-${o}-${d}`}let i=t==="system"?void 0:Ye(r);return s.toLocaleDateString(i,{day:"2-digit",month:"2-digit",year:"numeric",timeZone:e})}function ti(s,r){let e=fe();switch(re.time){case"12":return s.toLocaleTimeString(Ye(r),{hour:"2-digit",minute:"2-digit",hour12:!0,timeZone:e});case"24":return s.toLocaleTimeString(Ye(r),{hour:"2-digit",minute:"2-digit",hour12:!1,timeZone:e});case"system":return s.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",timeZone:e});default:return s.toLocaleTimeString(Ye(r),{hour:"2-digit",minute:"2-digit",timeZone:e})}}function O(s,r){if(!s)return"\u2014";try{let e=js.exec(s);return e?Zi(new Date(Date.UTC(+e[1],+e[2]-1,+e[3])),r,"UTC"):Zi(new Date(Q(s)),r,fe())}catch{return s}}function ii(s,r){if(!s)return"\u2014";if(js.test(s))return O(s,r);try{let e=new Date(Q(s));return Zi(e,r,fe())+" "+ti(e,r)}catch{return s}}function ri(s,r=Date.now()){let e=ge();return Qt(r,e)===Qt(r,fe())?"":a("ha_time_zone_hint",s).replace("{zone}",e)}function Ms(s,r){if(s==null)return"\u2014";let e=r||"en";return s<0?`${Math.abs(s)} ${a("d_overdue",e)}`:s===0?a("today",e):`${s} ${s===1?a("day",e):a("days",e)}`}function Oe(s,r,e){return s==null?"\u2014":`${s} ${a("unit_"+(r||"days"),e)}`}function si(s,r){return s==null?"\u2014":`${C(s,r,{maximumFractionDigits:1})} ${a("minutes_short",r)}`}function Qe(s,r,e="long"){return new Date(Date.UTC(2024,0,1+s)).toLocaleDateString(Ye(r),{weekday:e,timeZone:"UTC"})}function Xi(s,r,e="long"){return new Date(Date.UTC(2024,s,1)).toLocaleDateString(Ye(r),{month:e,timeZone:"UTC"})}function zs(s,r,e="long"){return Qe((s.getDay()+6)%7,r,e)}function Fs(s,r,e="long"){return Xi(s.getMonth(),r,e)}function Us(s,r){let e=s.schedule;if(s.schedule_type==="sensor_based"){let i=a("sensor_based",r),n=e&&e.kind==="interval"&&e.every?e.every:s.interval_days;return n?`${i} \xB7 ${Oe(n,(e&&e.kind==="interval"?e.unit:s.interval_unit)||"days",r)}`:i}let t=e?.offset?` ${e.offset>0?"+":"\u2212"}${Math.abs(e.offset)}d`:"";switch(e?.kind){case"weekdays":return((e.weekdays||[]).map(i=>Qe(i,r,"short")).join(" & ")||"\u2014")+t;case"nth_weekday":return e.weekday==null||e.nth==null?"\u2014":`${e.nth===-1?a("ord_last",r):a("ord_"+e.nth,r)} ${Qe(e.weekday,r,"long")}${t}`;case"day_of_month":return e.day==null?"\u2014":(e.day===-1?a(e.business?"last_business_day_month":"last_day_month",r):`${a("day_word",r)} ${e.day}`)+t;case"calendar":return`${a("calendar_entity_label",r)}: ${s.schedule_entity_name||e.entity_id||"\u2014"}${t}`;case"one_time":return s.due_date?O(s.due_date,r):a("one_time",r);case"manual":return a("manual",r);case"interval":return Oe(e.every,e.unit,r)}return s.schedule_type==="one_time"?s.due_date?O(s.due_date,r):a("one_time",r):s.schedule_type==="manual"?a("manual",r):s.schedule_type==="sensor_based"?a("sensor_based",r):s.interval_days!=null?Oe(s.interval_days,s.interval_unit,r):"\u2014"}function Bs(s,r){s.currentTarget.dispatchEvent(new CustomEvent("hass-more-info",{detail:{entityId:r},bubbles:!0,composed:!0}))}var wo,Os,re,Ds,js,Je,So,To,ni,T=y(()=>{"use strict";I();As();Kt();Xt();Qi();Z();Xt();wo="\u20AC";Ki(Cs);Os=window,re=Os.__msDateTimePrefs??={},Ds=Os.__msMoneyPrefs??={};js=/^(\d{4})-(\d{2})-(\d{2})$/;Je=E` .field { display: flex; flex-direction: column; gap: 4px; } .field-label { font-size: 12px; color: var(--secondary-text-color); } .field-input { @@ -14,7 +14,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" font-family: inherit; width: 100%; box-sizing: border-box; } .field-input:focus { outline: none; border-color: var(--primary-color); } -`,eo=E` +`,So=E` .person-chip { display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; vertical-align: middle; } .person-avatar { width: 22px; height: 22px; border-radius: 50%; flex: none; @@ -24,7 +24,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" font-variant-numeric: tabular-nums; } .person-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; } -`,to=E` +`,To=E` .ref-chip { display: inline-block; font-size: 11.5px; font-weight: 500; line-height: 1; padding: 3px 6px; border-radius: 6px; border: 1px solid var(--divider-color); color: var(--secondary-text-color); @@ -33,9 +33,9 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" } /* #189: "· Residual waste, Paper" after a calendar-driven task's name. */ .event-titles { color: var(--secondary-text-color); font-weight: 400; } -`,Xt=E` - ${eo} - ${to} +`,ni=E` + ${So} + ${To} :host { --maint-ok-color: var(--success-color, #4caf50); --maint-due-soon-color: var(--warning-color, #ff9800); @@ -806,10 +806,13 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" font-weight: 500; font-size: 14px; margin-bottom: 4px; + min-width: 0; + overflow-wrap: anywhere; } .group-card-actions { display: flex; + flex-shrink: 0; gap: 0; } .group-card-actions ha-icon-button { @@ -856,6 +859,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" border-radius: 10px; background: var(--secondary-background-color, #f5f5f5); color: var(--primary-text-color); + max-width: 100%; + overflow-wrap: anywhere; } /* Adaptive scheduling suggestion badge */ @@ -1244,7 +1249,19 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" suffix is hidden instead — the bar and the title carry the ratio. */ .budget-tile-max { display: none; } - .group-card { min-width: 0; max-width: 100%; } + /* #206 — one group per row. flex: 1 with min-width 0 put every group + into ONE row: three groups were 96 px each on a 360 px phone, and the + delete button of one lay over the next group. The buttons get the + same 44 px targets as the task rows, apart from each other; the + negative margin lets them reach into the card's padding instead of + pushing the tasks down. */ + .group-card { flex: 1 1 100%; min-width: 0; max-width: 100%; } + .group-card-actions { gap: 8px; margin: -8px -8px -8px 0; } + .group-card-actions ha-icon-button { + --ha-icon-button-size: 44px; + --mdc-icon-button-size: 44px; + --mdc-icon-size: 22px; + } .filter-chip { padding: 6px 12px; font-size: 13px; } @@ -1273,9 +1290,9 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .stat-item .stat-label { font-size: 11px; white-space: normal; text-align: center; line-height: 1.2; hyphens: auto; overflow-wrap: anywhere; } .stat-value { font-size: 20px; } } -`});function ei(s){if(!s)return[];let r=[],e=s.photo_doc_id;typeof e=="string"&&r.push(e);let t=s.photo_doc_ids;Array.isArray(t)&&r.push(...t);let i=[];for(let a of r){if(typeof a!="string")continue;let o=a.trim();if(!(!o||i.includes(o))&&(i.push(o),i.length>=10))break}return i}var ti=y(()=>{"use strict"});function Cs(){let s=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:r=>r.map(()=>Math.floor(Math.random()*256))}).getRandomValues(s),Array.from(s,r=>r.toString(16).padStart(2,"0")).join("")}function xe(s){let r=s?.reading_values;if(!Array.isArray(r))return[];let e=[],t=new Set;for(let i of r){if(!i||typeof i!="object")continue;let a=i;typeof a.id!="string"||!a.id||t.has(a.id)||typeof a.value!="number"||!Number.isFinite(a.value)||(t.add(a.id),e.push({id:a.id,name:typeof a.name=="string"?a.name:a.id,unit:typeof a.unit=="string"?a.unit:null,value:a.value}))}return e}function Is(s){return s.filter(r=>r.type==="completed"&&(r.reading_value!=null||xe(r).length>0)).sort((r,e)=>r.timestamp.localeCompare(e.timestamp))}function Rs(s){return Is(s??[]).map(r=>({timestamp:r.timestamp,values:xe(r)})).filter(r=>r.values.length>0)}function Ps(s,r,e){let t;for(let i of s){if(e!==void 0){let o=Q(i.timestamp);if(!isNaN(o)&&o>=e)break}let a=i.values.find(o=>o.id===r);a&&(t=a)}return t}function Ls(s,r,e){let t=xe(r).find(a=>a.id===e);if(!t)return null;let i=null;for(let a of Is(s)){if(a.timestamp>=r.timestamp)break;let o=xe(a).find(d=>d.id===e);o&&(i=o.value)}return i==null?null:t.value-i}function Ns(s){let r=new Set,e=new Set;for(let t of s){let i=(t.name||"").trim().toLowerCase();i&&(r.has(i)?e.add(t.id):r.add(i))}return e}function qs(s){let r=[],e=new Set,t=new Set;for(let i of s){let a=(i.name||"").trim();if(!(!a||e.has(i.id)||t.has(a.toLowerCase()))&&(e.add(i.id),t.add(a.toLowerCase()),r.push({id:i.id,name:a,unit:(i.unit||"").trim()||null}),r.length>=Bi))break}return r}var Bi,Oe=y(()=>{"use strict";Z();Bi=20});function Wi(s,r,e,t){let i=e,a=p=>typeof p=="string"?p:null,o=p=>typeof p=="number"?p:null,d=a(i.timestamp)??"";return{entry_id:s,task_id:r,original_timestamp:d,type:a(i.type)||"completed",timestamp:d,notes:a(i.notes),cost:o(i.cost),duration:o(i.duration),completed_by:a(i.completed_by),used_parts:Array.isArray(i.used_parts)?i.used_parts:null,photo_doc_ids:ei(i),reading_value:o(i.reading_value),reading_values:xe(i),readings:t?.readings??[],task_type:t?.type??null,reading_unit:t?.reading_unit??null}}async function Hs(s,r,e,t){let a=(await s.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:r})).tasks?.find(d=>d.id===e);if(!a)return null;let o=a.history?.find(d=>d.timestamp===t);return o||(o=(await s.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:r,task_id:e})).history?.find(p=>p.timestamp===t)),o?Wi(r,e,o,a):null}var Vi=y(()=>{"use strict";ti();Oe()});function we(s,r=je){return s?s.is_admin?!0:r.operatorWriteEnabled&&r.operatorIds.includes(s.id):!1}var je,xt=y(()=>{"use strict";je={operatorWriteEnabled:!1,operatorIds:[]}});var Os,js,Ds,wt,kt,$t,Gi,ke,Ze,Et=y(()=>{"use strict";Os={default_warning_days:[0,365],default_consumable_threshold:[1,90],battery_low_percent:[1,90],battery_recovered_percent:[20,100],archive_oneoff_days:[0,3650],delete_archived_oneoff_days:[0,3650],notify_due_soon_interval_hours:[0,720],notify_overdue_interval_hours:[0,720],notify_triggered_interval_hours:[0,720],max_notifications_per_day:[0,1e3],notification_bundle_threshold:[2,20],snooze_duration_hours:[1,168],warranty_reminder_days:[1,365],budget_alert_threshold:[10,100],currency_decimals:[0,3]},js=[0,1440],Ds=[1,1e4],wt=[0,365],kt=15,$t=[.1,.9],Gi=[0,365],ke=[.01,1e4],Ze=[.01,1e5]});function ro(s){let[r,e]=Os.default_warning_days,t=s?.general?.default_warning_days,i=s?.general?.row_action_style;return{features:{...ii.features,...s?.features??{}},defaultWarningDays:typeof t=="number"&&Number.isFinite(t)&&t>=r&&t<=e?t:ii.defaultWarningDays,rowActionStyle:io.includes(i??"")?i:ii.rowActionStyle,access:{operatorWriteEnabled:s?.operator_write_enabled===!0,operatorIds:Array.isArray(s?.admin_panel_user_ids)?s.admin_panel_user_ids.filter(a=>typeof a=="string"):[]},budget:s?.budget??null,rowActionNoticePending:s?.general?.row_action_notice_pending===!0,refsInLists:s?.general?.ref_numbers_in_lists===!0,objectsTableColumns:Array.isArray(s?.objects_table_columns)?s.objects_table_columns:void 0,partsCostMode:Vr(s?.budget?.parts_cost_mode)}}function Ms(){let s=window;return s.__msSettingsCache??={promise:null}}function se(s){let r=Ms();if(r.promise)return r.promise;let e=s.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(t=>ro(t)).catch(()=>(r.promise===e&&(r.promise=null),ii));return r.promise=e,e}function zs(){Ms().promise=null}var io,ii,St=y(()=>{"use strict";xt();Et();zt();io=["buttons_compact","buttons","icons"];ii={features:{adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1,places:!1},defaultWarningDays:7,rowActionStyle:"buttons_compact",access:je,budget:null,rowActionNoticePending:!1,refsInLists:!1,objectsTableColumns:void 0,partsCostMode:"purchase"}});function ao(s){let r=s.replace(/_ids?$/,"").split("_").filter(Boolean);if(r.length===0)return s;let e=r.join(" ");return e.charAt(0).toUpperCase()+e.slice(1)}function oo(s,r){let e=no[s];if(e){let t=n(e,r);if(t&&t!==e)return t}return ao(s)}function lo(s){let r=[...s.matchAll(/\['([^']+)'\]/g)].map(i=>i[1]),e=r.length?r[r.length-1]:void 0,t;return(t=s.match(/length of value must be at most (\d+)/))?{field:e,rule:"too_long",param:t[1]}:(t=s.match(/length of value must be at least (\d+)/))?{field:e,rule:"too_short",param:t[1]}:(t=s.match(/value must be at most (\S+)/))?{field:e,rule:"value_too_high",param:t[1]}:(t=s.match(/value must be at least (\S+)/))?{field:e,rule:"value_too_low",param:t[1]}:/required key not provided/.test(s)?{field:e,rule:"required"}:(t=s.match(/expected (\w+)/))?{field:e,rule:"wrong_type",param:t[1]}:/value must be one of/.test(s)?{field:e,rule:"invalid_choice"}:/not a valid value/.test(s)?{field:e,rule:"invalid_value"}:{field:e,rule:"unknown"}}function co(s,r){let e=new Set(Fs(r));return Fs(s).every(t=>e.has(t))}function Us(s,r,e){if(e=e??n("action_error",r),typeof s=="string")return s;if(typeof s!="object"||s===null)return e;let t=s,i=t.message||t.error?.message||"",a=t.code||t.error?.code||"",o=a?so[a]:void 0,d=gs(t.translation_domain??t.error?.translation_domain,t.translation_key??t.error?.translation_key,t.translation_placeholders??t.error?.translation_placeholders);if(d)return d;if(!i&&!o)return e;let p=lo(i),_=p.field?oo(p.field,r):"",m=f=>n(f,r).replace("{field}",_).replace("{n}",p.param??"");switch(p.rule){case"too_long":return m("err_too_long");case"too_short":return m("err_too_short");case"value_too_high":return m("err_value_too_high");case"value_too_low":return m("err_value_too_low");case"required":return m("err_required");case"wrong_type":return m("err_wrong_type").replace("{type}",p.param??"");case"invalid_choice":return m("err_invalid_choice");case"invalid_value":return m("err_invalid_value");default:if(o){let f=n(o,r);return be(r)==="en"&&i&&!co(i,a)?`${f} (${i})`:f}return i||e}}var so,no,Fs,Bs=y(()=>{"use strict";T();Mi();Gt();so={already_archived:"ws_err_already_archived",already_paused:"ws_err_already_paused",archived:"ws_err_archived",changed_since:"undo_changed",create_failed:"ws_err_create_failed",duplicate_failed:"ws_err_duplicate_failed",empty:"ws_err_empty",empty_csv:"ws_err_empty_csv",invalid_cursor:"ws_err_invalid_cursor",invalid_date:"ws_err_invalid_date",invalid_device:"ws_err_invalid_device",invalid_entity_slug:"ws_err_invalid_entity_slug",invalid_format:"ws_err_invalid_format",invalid_input:"ws_err_invalid_input",invalid_mirror_todo:"ws_err_invalid_mirror_todo",invalid_parent:"ws_err_invalid_parent",invalid_icon:"ws_err_invalid_icon",invalid_range:"ws_err_invalid_range",invalid_search_template:"ws_err_invalid_search_template",invalid_target:"ws_err_invalid_target",invalid_trigger_config:"ws_err_invalid_trigger_config",invalid_url:"ws_err_invalid_url",invalid_user:"ws_err_invalid_user",invalid_view:"ws_err_invalid_view",limit_reached:"ws_err_limit_reached",no_defaults:"ws_err_no_defaults",no_phases:"ws_err_no_phases",no_url:"ws_err_no_url",not_archived:"ws_err_not_archived",not_available:"ws_err_not_available",not_configured:"ws_err_not_configured",not_found:"ws_err_not_found",not_loaded:"ws_err_not_loaded",not_paused:"ws_err_not_paused",nothing_to_undo:"undo_nothing",replace_failed:"ws_err_replace_failed",self_link_device:"ws_err_self_link_device",storage_unavailable:"ws_err_storage_unavailable",too_early:"ws_err_too_early",too_large:"ws_err_too_large",too_many:"ws_err_too_many",too_many_views:"ws_err_too_many_views",unauthorized:"ws_err_unauthorized",unavailable:"ws_err_unavailable"},no={entry_id:"object",name:"name",task_type:"maintenance_type",schedule_type:"schedule_type",interval_days:"interval_days",interval_anchor:"interval_anchor",warning_days:"warning_days",last_performed:"last_performed_optional",notes:"notes_optional",documentation_url:"documentation_url_optional",custom_icon:"custom_icon_optional",nfc_tag_id:"nfc_tag_id_optional",responsible_user_id:"responsible_user",entity_slug:"entity_slug",entity_id:"entity_id",area_id:"area_id_optional",manufacturer:"manufacturer_optional",model:"model_optional",serial_number:"serial_number_optional",installation_date:"installation_date_optional",warranty_expiry:"warranty_expiry_optional",checklist:"checklist_steps_optional",reason:"reason",feedback:"feedback",cost:"cost",duration:"duration",description:"description_optional",environmental_entity:"environmental_entity_optional",environmental_attribute:"environmental_attribute_optional",trigger_above:"trigger_above",trigger_below:"trigger_below",trigger_equals:"trigger_equals",trigger_not_equals:"trigger_not_equals",trigger_for_minutes:"trigger_for_minutes"};Fs=s=>s.toLowerCase().split(/[^a-z0-9]+/).filter(r=>r.length>1)});async function j(s,r,e={}){e.busy?.(!0);try{let t=typeof r=="function"?await r():await s.hass.connection.sendMessagePromise(r);return e.reload&&await e.reload(),e.successToast&&e.onSuccess?.(e.successToast),t===void 0?null:t}catch(t){let i=e.lang||N(s.hass);e.onError?.(Us(t,i,e.fallbackKey?n(e.fallbackKey,i):void 0),t);return}finally{e.busy?.(!1)}}var De=y(()=>{"use strict";Bs();T()});var D,Ki=y(()=>{"use strict";I();F();D=class extends S{constructor(){super(...arguments);this.label="";this.value="";this.placeholder="";this.type="text";this.required=!1;this.disabled=!1;this.multiline=!1;this.rows=3}_onInput(e){let t=e.target.value;this.value=t,this.dispatchEvent(new CustomEvent("input",{bubbles:!0,composed:!0,detail:{value:t}}))}render(){return l` +`});function ai(s){if(!s)return[];let r=[],e=s.photo_doc_id;typeof e=="string"&&r.push(e);let t=s.photo_doc_ids;Array.isArray(t)&&r.push(...t);let i=[];for(let n of r){if(typeof n!="string")continue;let o=n.trim();if(!(!o||i.includes(o))&&(i.push(o),i.length>=10))break}return i}var oi=y(()=>{"use strict"});function Gs(){let s=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:r=>r.map(()=>Math.floor(Math.random()*256))}).getRandomValues(s),Array.from(s,r=>r.toString(16).padStart(2,"0")).join("")}function xe(s){let r=s?.reading_values;if(!Array.isArray(r))return[];let e=[],t=new Set;for(let i of r){if(!i||typeof i!="object")continue;let n=i;typeof n.id!="string"||!n.id||t.has(n.id)||typeof n.value!="number"||!Number.isFinite(n.value)||(t.add(n.id),e.push({id:n.id,name:typeof n.name=="string"?n.name:n.id,unit:typeof n.unit=="string"?n.unit:null,value:n.value}))}return e}function Ks(s){return s.filter(r=>r.type==="completed"&&(r.reading_value!=null||xe(r).length>0)).sort((r,e)=>r.timestamp.localeCompare(e.timestamp))}function Ys(s){return Ks(s??[]).map(r=>({timestamp:r.timestamp,values:xe(r)})).filter(r=>r.values.length>0)}function Qs(s,r,e){let t;for(let i of s){if(e!==void 0){let o=Q(i.timestamp);if(!isNaN(o)&&o>=e)break}let n=i.values.find(o=>o.id===r);n&&(t=n)}return t}function Zs(s,r,e){let t=xe(r).find(n=>n.id===e);if(!t)return null;let i=null;for(let n of Ks(s)){if(n.timestamp>=r.timestamp)break;let o=xe(n).find(d=>d.id===e);o&&(i=o.value)}return i==null?null:t.value-i}function Js(s){let r=new Set,e=new Set;for(let t of s){let i=(t.name||"").trim().toLowerCase();i&&(r.has(i)?e.add(t.id):r.add(i))}return e}function Xs(s){let r=[],e=new Set,t=new Set;for(let i of s){let n=(i.name||"").trim();if(!(!n||e.has(i.id)||t.has(n.toLowerCase()))&&(e.add(i.id),t.add(n.toLowerCase()),r.push({id:i.id,name:n,unit:(i.unit||"").trim()||null}),r.length>=er))break}return r}var er,je=y(()=>{"use strict";Z();er=20});function tr(s,r,e,t){let i=e,n=p=>typeof p=="string"?p:null,o=p=>typeof p=="number"?p:null,d=n(i.timestamp)??"";return{entry_id:s,task_id:r,original_timestamp:d,type:n(i.type)||"completed",timestamp:d,notes:n(i.notes),cost:o(i.cost),duration:o(i.duration),completed_by:n(i.completed_by),used_parts:Array.isArray(i.used_parts)?i.used_parts:null,photo_doc_ids:ai(i),reading_value:o(i.reading_value),reading_values:xe(i),readings:t?.readings??[],task_type:t?.type??null,reading_unit:t?.reading_unit??null}}async function en(s,r,e,t){let n=(await s.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:r})).tasks?.find(d=>d.id===e);if(!n)return null;let o=n.history?.find(d=>d.timestamp===t);return o||(o=(await s.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:r,task_id:e})).history?.find(p=>p.timestamp===t)),o?tr(r,e,o,n):null}var ir=y(()=>{"use strict";oi();je()});function we(s,r=Me){return s?s.is_admin?!0:r.operatorWriteEnabled&&r.operatorIds.includes(s.id):!1}var Me,wt=y(()=>{"use strict";Me={operatorWriteEnabled:!1,operatorIds:[]}});var tn,rn,sn,kt,$t,Et,rr,ke,Xe,St=y(()=>{"use strict";tn={default_warning_days:[0,365],default_consumable_threshold:[1,90],battery_low_percent:[1,90],battery_recovered_percent:[20,100],archive_oneoff_days:[0,3650],delete_archived_oneoff_days:[0,3650],notify_due_soon_interval_hours:[0,720],notify_overdue_interval_hours:[0,720],notify_triggered_interval_hours:[0,720],max_notifications_per_day:[0,1e3],notification_bundle_threshold:[2,20],snooze_duration_hours:[1,168],warranty_reminder_days:[1,365],budget_alert_threshold:[10,100],currency_decimals:[0,3]},rn=[0,1440],sn=[1,1e4],kt=[0,365],$t=15,Et=[.1,.9],rr=[0,365],ke=[.01,1e4],Xe=[.01,1e5]});function Co(s){let[r,e]=tn.default_warning_days,t=s?.general?.default_warning_days,i=s?.general?.row_action_style;return{features:{...li.features,...s?.features??{}},defaultWarningDays:typeof t=="number"&&Number.isFinite(t)&&t>=r&&t<=e?t:li.defaultWarningDays,rowActionStyle:Ao.includes(i??"")?i:li.rowActionStyle,access:{operatorWriteEnabled:s?.operator_write_enabled===!0,operatorIds:Array.isArray(s?.admin_panel_user_ids)?s.admin_panel_user_ids.filter(n=>typeof n=="string"):[]},budget:s?.budget??null,rowActionNoticePending:s?.general?.row_action_notice_pending===!0,refsInLists:s?.general?.ref_numbers_in_lists===!0,objectsTableColumns:Array.isArray(s?.objects_table_columns)?s.objects_table_columns:void 0,partsCostMode:ds(s?.budget?.parts_cost_mode)}}function nn(){let s=window;return s.__msSettingsCache??={promise:null}}function se(s){let r=nn();if(r.promise)return r.promise;let e=s.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(t=>Co(t)).catch(()=>(r.promise===e&&(r.promise=null),li));return r.promise=e,e}function an(){nn().promise=null}var Ao,li,Tt=y(()=>{"use strict";wt();St();Gt();Ao=["buttons_compact","buttons","icons"];li={features:{adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1,places:!1},defaultWarningDays:7,rowActionStyle:"buttons_compact",access:Me,budget:null,rowActionNoticePending:!1,refsInLists:!1,objectsTableColumns:void 0,partsCostMode:"purchase"}});function Po(s){let r=s.replace(/_ids?$/,"").split("_").filter(Boolean);if(r.length===0)return s;let e=r.join(" ");return e.charAt(0).toUpperCase()+e.slice(1)}function Lo(s,r){let e=Ro[s];if(e){let t=a(e,r);if(t&&t!==e)return t}return Po(s)}function No(s){let r=[...s.matchAll(/\['([^']+)'\]/g)].map(i=>i[1]),e=r.length?r[r.length-1]:void 0,t;return(t=s.match(/length of value must be at most (\d+)/))?{field:e,rule:"too_long",param:t[1]}:(t=s.match(/length of value must be at least (\d+)/))?{field:e,rule:"too_short",param:t[1]}:(t=s.match(/value must be at most (\S+)/))?{field:e,rule:"value_too_high",param:t[1]}:(t=s.match(/value must be at least (\S+)/))?{field:e,rule:"value_too_low",param:t[1]}:/required key not provided/.test(s)?{field:e,rule:"required"}:(t=s.match(/expected (\w+)/))?{field:e,rule:"wrong_type",param:t[1]}:/value must be one of/.test(s)?{field:e,rule:"invalid_choice"}:/not a valid value/.test(s)?{field:e,rule:"invalid_value"}:{field:e,rule:"unknown"}}function Ho(s,r){let e=new Set(on(r));return on(s).every(t=>e.has(t))}function ln(s,r,e){if(e=e??a("action_error",r),typeof s=="string")return s;if(typeof s!="object"||s===null)return e;let t=s,i=t.message||t.error?.message||"",n=t.code||t.error?.code||"",o=n?Io[n]:void 0,d=Ns(t.translation_domain??t.error?.translation_domain,t.translation_key??t.error?.translation_key,t.translation_placeholders??t.error?.translation_placeholders);if(d)return d;if(!i&&!o)return e;let p=No(i),_=p.field?Lo(p.field,r):"",m=f=>a(f,r).replace("{field}",_).replace("{n}",p.param??"");switch(p.rule){case"too_long":return m("err_too_long");case"too_short":return m("err_too_short");case"value_too_high":return m("err_value_too_high");case"value_too_low":return m("err_value_too_low");case"required":return m("err_required");case"wrong_type":return m("err_wrong_type").replace("{type}",p.param??"");case"invalid_choice":return m("err_invalid_choice");case"invalid_value":return m("err_invalid_value");default:if(o){let f=a(o,r);return be(r)==="en"&&i&&!Ho(i,n)?`${f} (${i})`:f}return i||e}}var Io,Ro,on,cn=y(()=>{"use strict";T();Qi();Xt();Io={already_archived:"ws_err_already_archived",already_paused:"ws_err_already_paused",archived:"ws_err_archived",changed_since:"undo_changed",create_failed:"ws_err_create_failed",duplicate_failed:"ws_err_duplicate_failed",empty:"ws_err_empty",empty_csv:"ws_err_empty_csv",invalid_cursor:"ws_err_invalid_cursor",invalid_date:"ws_err_invalid_date",invalid_device:"ws_err_invalid_device",invalid_entity_slug:"ws_err_invalid_entity_slug",invalid_format:"ws_err_invalid_format",invalid_input:"ws_err_invalid_input",invalid_mirror_todo:"ws_err_invalid_mirror_todo",invalid_parent:"ws_err_invalid_parent",invalid_icon:"ws_err_invalid_icon",invalid_range:"ws_err_invalid_range",invalid_search_template:"ws_err_invalid_search_template",invalid_target:"ws_err_invalid_target",invalid_trigger_config:"ws_err_invalid_trigger_config",invalid_url:"ws_err_invalid_url",invalid_user:"ws_err_invalid_user",invalid_view:"ws_err_invalid_view",limit_reached:"ws_err_limit_reached",no_defaults:"ws_err_no_defaults",no_phases:"ws_err_no_phases",no_url:"ws_err_no_url",not_archived:"ws_err_not_archived",not_available:"ws_err_not_available",not_configured:"ws_err_not_configured",not_found:"ws_err_not_found",not_loaded:"ws_err_not_loaded",not_paused:"ws_err_not_paused",nothing_to_undo:"undo_nothing",replace_failed:"ws_err_replace_failed",self_link_device:"ws_err_self_link_device",storage_unavailable:"ws_err_storage_unavailable",too_early:"ws_err_too_early",too_large:"ws_err_too_large",too_many:"ws_err_too_many",too_many_views:"ws_err_too_many_views",unauthorized:"ws_err_unauthorized",unavailable:"ws_err_unavailable"},Ro={entry_id:"object",name:"name",task_type:"maintenance_type",schedule_type:"schedule_type",interval_days:"interval_days",interval_anchor:"interval_anchor",warning_days:"warning_days",last_performed:"last_performed_optional",notes:"notes_optional",documentation_url:"documentation_url_optional",custom_icon:"custom_icon_optional",nfc_tag_id:"nfc_tag_id_optional",responsible_user_id:"responsible_user",entity_slug:"entity_slug",entity_id:"entity_id",area_id:"area_id_optional",manufacturer:"manufacturer_optional",model:"model_optional",serial_number:"serial_number_optional",installation_date:"installation_date_optional",warranty_expiry:"warranty_expiry_optional",checklist:"checklist_steps_optional",reason:"reason",feedback:"feedback",cost:"cost",duration:"duration",description:"description_optional",environmental_entity:"environmental_entity_optional",environmental_attribute:"environmental_attribute_optional",trigger_above:"trigger_above",trigger_below:"trigger_below",trigger_equals:"trigger_equals",trigger_not_equals:"trigger_not_equals",trigger_for_minutes:"trigger_for_minutes"};on=s=>s.toLowerCase().split(/[^a-z0-9]+/).filter(r=>r.length>1)});async function D(s,r,e={}){e.busy?.(!0);try{let t=typeof r=="function"?await r():await s.hass.connection.sendMessagePromise(r);return e.reload&&await e.reload(),e.successToast&&e.onSuccess?.(e.successToast),t===void 0?null:t}catch(t){let i=e.lang||N(s.hass);e.onError?.(ln(t,i,e.fallbackKey?a(e.fallbackKey,i):void 0),t);return}finally{e.busy?.(!1)}}var ze=y(()=>{"use strict";cn();T()});var j,sr=y(()=>{"use strict";I();F();j=class extends S{constructor(){super(...arguments);this.label="";this.value="";this.placeholder="";this.type="text";this.required=!1;this.disabled=!1;this.multiline=!1;this.rows=3}_onInput(e){let t=e.target.value;this.value=t,this.dispatchEvent(new CustomEvent("input",{bubbles:!0,composed:!0,detail:{value:t}}))}render(){return l`
- ${n("cancel",this._lang)} + ${a("cancel",this._lang)} - ${this._loading?n("saving",this._lang):n("save",this._lang)} + ${this._loading?a("saving",this._lang):a("save",this._lang)}
@@ -1690,19 +1707,19 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .radio-row input { margin: 0; } - `,c([v({attribute:!1})],R.prototype,"hass",2),c([v({attribute:!1})],R.prototype,"objects",2),c([v({type:Boolean})],R.prototype,"placesEnabled",2),c([u()],R.prototype,"_open",2),c([u()],R.prototype,"_loading",2),c([u()],R.prototype,"_error",2),c([u()],R.prototype,"_name",2),c([u()],R.prototype,"_manufacturer",2),c([u()],R.prototype,"_model",2),c([u()],R.prototype,"_serialNumber",2),c([u()],R.prototype,"_areaId",2),c([u()],R.prototype,"_installationDate",2),c([u()],R.prototype,"_warrantyExpiry",2),c([u()],R.prototype,"_documentationUrl",2),c([u()],R.prototype,"_notes",2),c([u()],R.prototype,"_haDeviceId",2),c([u()],R.prototype,"_parentEntryId",2),c([u()],R.prototype,"_place",2),c([u()],R.prototype,"_remindOnSite",2),c([u()],R.prototype,"_entryId",2),c([u()],R.prototype,"_replacing",2),c([u()],R.prototype,"_oldDeviceId",2),c([u()],R.prototype,"_replaceDevice",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",R)});function _o(s){let r=(s||"").split(/\s+/).filter(Boolean);return r.length===0?"?":r.length===1?r[0][0].toUpperCase():(r[0][0]+r[r.length-1][0]).toUpperCase()}function mo(s){let r=0;for(let e of s)r=r*31+e.charCodeAt(0)>>>0;return Ks[r%Ks.length]}function Ys(s){return s?{id:s.id,name:s.name,initials:s.initials||_o(s.name),color:s.color||mo(s.id)}:null}var Ks,Qs=y(()=>{"use strict";I();Ks=["#c62828","#ad1457","#6a1b9a","#4527a0","#283593","#1565c0","#00838f","#2e7d32","#558b2f","#ef6c00","#6d4c41","#546e7a"]});var ri,Zs=y(()=>{"use strict";Qs();ri=class{constructor(r){this.usersCache=null;this.cacheTimestamp=0;this.CACHE_TTL_MS=6e4;this.hass=r}updateHass(r){this.hass=r}async getUsers(r=!1){let e=Date.now();if(!r&&this.usersCache&&e-this.cacheTimestampt.id===r)?.name||null}getPerson(r){return Ys(this.getUser(r))}getUser(r){return!r||!this.usersCache?null:this.usersCache.find(e=>e.id===r)||null}getCurrentUserId(){return this.hass.user?.id||null}isCurrentUser(r){return r?r===this.getCurrentUserId():!1}clearCache(){this.usersCache=null,this.cacheTimestamp=0}}});function ae(s){return`${s.entry_id??""}\0${s.part_id}`}function Js(s,r,e,t){let i=!!s.entry_id&&s.entry_id!==r,a=i?s.entry_id:r,o=e.find(m=>m.entry_id===a),d=(o?.parts||[]).find(m=>m.id===s.part_id)||null,p=i&&o?.object?.name||"",_=d?.name||n("shared_part_unknown",t);return{part:d,foreign:i,ownerName:p,label:p?`${_} (${p})`:_}}function Xs(s,r,e,t){let{part:i,label:a}=Js(s,r,e,t),o=i&&i.stock!==null&&i.stock!==void 0?` (${Ye(i.stock,i.unit,t)})`:"",d=i?.storage_location?` \u2014 ${i.storage_location}`:"";return`${C(s.quantity,t)}\xD7 ${a}${o}${d}`}function en(s,r,e,t){let a=(e.find(d=>d.entry_id===r)?.parts||[]).map(d=>({...d})),o=new Set(a.map(d=>ae({part_id:d.id})));for(let d of s?.consumes_parts||[]){if(!d.entry_id||d.entry_id===r)continue;let p=ae(d);if(o.has(p))continue;o.add(p);let{part:_,ownerName:m}=Js(d,r,e,t);a.push({id:d.part_id,name:_?.name||n("shared_part_unknown",t),unit:_?.unit,stock:_?.stock??null,storage_location:_?.storage_location,entry_id:d.entry_id,owner_name:m})}return a}var si=y(()=>{"use strict";T()});var Yi,tn,rn,sn=y(()=>{"use strict";Yi=["sensor","binary_sensor","number","input_number","input_boolean","switch","climate","vacuum","cover","fan","light","water_heater","humidifier","media_player","weather","air_quality","valve","lawn_mower","lock","plant"],tn=["sensor"],rn=["temperature","humidity","pressure"]});function et(s){let r=(s??"").trim();if(r==="")return null;let e=Number(r.replace(",","."));return!Number.isFinite(e)||e<0?null:Math.round(e)}var ni=y(()=>{"use strict"});var Qi,Tt,Zi=y(()=>{"use strict";Qi=["notes","cost","duration","photo","user"],Tt={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"}});var go,fo,Ji,nn=y(()=>{"use strict";go={cleaning:"mdi:broom",inspection:"mdi:magnify",replacement:"mdi:swap-horizontal",calibration:"mdi:tune",service:"mdi:wrench",reading:"mdi:counter",custom:"mdi:wrench-clock"},fo="mdi:wrench-clock",Ji=s=>s&&go[s]||fo});function ai(s){return s?Array.isArray(s.entity_ids)&&s.entity_ids.length>0?[...s.entity_ids]:s.entity_id?[s.entity_id]:[]:[]}function an(s){if(!(!s||s.type==="compound"))return ai(s)[0]}var on=y(()=>{"use strict"});var $e,oi=y(()=>{"use strict";I();F();T();$e=class extends S{constructor(){super(...arguments);this.value="";this.lang="en";this._credit=!1;this._amount=""}willUpdate(e){if(!e.has("value"))return;let t=(this.value??"").trim();if(t===this._signed())return;let i=parseFloat(t);if(t===""||Number.isNaN(i)){this._amount="",this._credit=!1;return}this._credit=i<0,this._amount=String(Math.abs(i))}_signed(){let e=this._amount.trim();return e===""?"":this._credit?`-${e}`:e}_emit(){this.value=this._signed(),this.dispatchEvent(new CustomEvent("value-changed",{detail:{value:this.value},bubbles:!0,composed:!0}))}_setCredit(e){this._credit!==e&&(this._credit=e,this._emit())}_onInput(e){let t=e.target.value;t.startsWith("-")&&(this._credit=!0),this._amount=t.replace(/^-+/,""),this._emit()}render(){let e=this.lang;return l` + `,c([v({attribute:!1})],R.prototype,"hass",2),c([v({attribute:!1})],R.prototype,"objects",2),c([v({type:Boolean})],R.prototype,"placesEnabled",2),c([h()],R.prototype,"_open",2),c([h()],R.prototype,"_loading",2),c([h()],R.prototype,"_error",2),c([h()],R.prototype,"_name",2),c([h()],R.prototype,"_manufacturer",2),c([h()],R.prototype,"_model",2),c([h()],R.prototype,"_serialNumber",2),c([h()],R.prototype,"_areaId",2),c([h()],R.prototype,"_installationDate",2),c([h()],R.prototype,"_warrantyExpiry",2),c([h()],R.prototype,"_documentationUrl",2),c([h()],R.prototype,"_notes",2),c([h()],R.prototype,"_haDeviceId",2),c([h()],R.prototype,"_parentEntryId",2),c([h()],R.prototype,"_place",2),c([h()],R.prototype,"_remindOnSite",2),c([h()],R.prototype,"_entryId",2),c([h()],R.prototype,"_replacing",2),c([h()],R.prototype,"_oldDeviceId",2),c([h()],R.prototype,"_replaceDevice",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",R)});function jo(s){let r=(s||"").split(/\s+/).filter(Boolean);return r.length===0?"?":r.length===1?r[0][0].toUpperCase():(r[0][0]+r[r.length-1][0]).toUpperCase()}function Mo(s){let r=0;for(let e of s)r=r*31+e.charCodeAt(0)>>>0;return hn[r%hn.length]}function _n(s){return s?{id:s.id,name:s.name,initials:s.initials||jo(s.name),color:s.color||Mo(s.id)}:null}var hn,mn=y(()=>{"use strict";I();hn=["#c62828","#ad1457","#6a1b9a","#4527a0","#283593","#1565c0","#00838f","#2e7d32","#558b2f","#ef6c00","#6d4c41","#546e7a"]});var ci,gn=y(()=>{"use strict";mn();ci=class{constructor(r){this.usersCache=null;this.cacheTimestamp=0;this.CACHE_TTL_MS=6e4;this.hass=r}updateHass(r){this.hass=r}async getUsers(r=!1){let e=Date.now();if(!r&&this.usersCache&&e-this.cacheTimestampt.id===r)?.name||null}getPerson(r){return _n(this.getUser(r))}getUser(r){return!r||!this.usersCache?null:this.usersCache.find(e=>e.id===r)||null}getCurrentUserId(){return this.hass.user?.id||null}isCurrentUser(r){return r?r===this.getCurrentUserId():!1}clearCache(){this.usersCache=null,this.cacheTimestamp=0}}});function ae(s){return`${s.entry_id??""}\0${s.part_id}`}function fn(s,r,e,t){let i=!!s.entry_id&&s.entry_id!==r,n=i?s.entry_id:r,o=e.find(m=>m.entry_id===n),d=(o?.parts||[]).find(m=>m.id===s.part_id)||null,p=i&&o?.object?.name||"",_=d?.name||a("shared_part_unknown",t);return{part:d,foreign:i,ownerName:p,label:p?`${_} (${p})`:_}}function vn(s,r,e,t){let{part:i,label:n}=fn(s,r,e,t),o=i&&i.stock!==null&&i.stock!==void 0?` (${Ze(i.stock,i.unit,t)})`:"",d=i?.storage_location?` \u2014 ${i.storage_location}`:"";return`${C(s.quantity,t)}\xD7 ${n}${o}${d}`}function yn(s,r,e,t){let n=(e.find(d=>d.entry_id===r)?.parts||[]).map(d=>({...d})),o=new Set(n.map(d=>ae({part_id:d.id})));for(let d of s?.consumes_parts||[]){if(!d.entry_id||d.entry_id===r)continue;let p=ae(d);if(o.has(p))continue;o.add(p);let{part:_,ownerName:m}=fn(d,r,e,t);n.push({id:d.part_id,name:_?.name||a("shared_part_unknown",t),unit:_?.unit,stock:_?.stock??null,storage_location:_?.storage_location,entry_id:d.entry_id,owner_name:m})}return n}var di=y(()=>{"use strict";T()});var nr,bn,xn,wn=y(()=>{"use strict";nr=["sensor","binary_sensor","number","input_number","input_boolean","switch","climate","vacuum","cover","fan","light","water_heater","humidifier","media_player","weather","air_quality","valve","lawn_mower","lock","plant"],bn=["sensor"],xn=["temperature","humidity","pressure"]});function it(s){let r=(s??"").trim();if(r==="")return null;let e=Number(r.replace(",","."));return!Number.isFinite(e)||e<0?null:Math.round(e)}var pi=y(()=>{"use strict"});var ar,At,or=y(()=>{"use strict";ar=["notes","cost","duration","photo","user"],At={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"}});var zo,Fo,lr,kn=y(()=>{"use strict";zo={cleaning:"mdi:broom",inspection:"mdi:magnify",replacement:"mdi:swap-horizontal",calibration:"mdi:tune",service:"mdi:wrench",reading:"mdi:counter",custom:"mdi:wrench-clock"},Fo="mdi:wrench-clock",lr=s=>s&&zo[s]||Fo});function ui(s){return s?Array.isArray(s.entity_ids)&&s.entity_ids.length>0?[...s.entity_ids]:s.entity_id?[s.entity_id]:[]:[]}function $n(s){if(!(!s||s.type==="compound"))return ui(s)[0]}var En=y(()=>{"use strict"});var $e,hi=y(()=>{"use strict";I();F();T();$e=class extends S{constructor(){super(...arguments);this.value="";this.lang="en";this._credit=!1;this._amount=""}willUpdate(e){if(!e.has("value"))return;let t=(this.value??"").trim();if(t===this._signed())return;let i=parseFloat(t);if(t===""||Number.isNaN(i)){this._amount="",this._credit=!1;return}this._credit=i<0,this._amount=String(Math.abs(i))}_signed(){let e=this._amount.trim();return e===""?"":this._credit?`-${e}`:e}_emit(){this.value=this._signed(),this.dispatchEvent(new CustomEvent("value-changed",{detail:{value:this.value},bubbles:!0,composed:!0}))}_setCredit(e){this._credit!==e&&(this._credit=e,this._emit())}_onInput(e){let t=e.target.value;t.startsWith("-")&&(this._credit=!0),this._amount=t.replace(/^-+/,""),this._emit()}render(){let e=this.lang;return l`
+ @click=${()=>this._setCredit(!1)}>${a("cost",e)} + @click=${()=>this._setCredit(!0)}>${a("cost_kind_credit",e)}
- ${this._credit?l`
${n("cost_credit_hint",e)}
`:h} - `}};$e.styles=[Qe,E` + ${this._credit?l`
${a("cost_credit_hint",e)}
`:u} + `}};$e.styles=[Je,E` :host { display: block; } .wrap { display: flex; gap: 8px; align-items: stretch; } .sign { @@ -1725,32 +1742,32 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .kind.credit.on { background: var(--success-color, #43a047); } .amount { flex: 1; min-width: 0; } .hint { margin-top: 4px; font-size: 12px; color: var(--secondary-text-color); } - `],c([v()],$e.prototype,"value",2),c([v()],$e.prototype,"lang",2),c([u()],$e.prototype,"_credit",2),c([u()],$e.prototype,"_amount",2);customElements.get("ms-cost-input")||customElements.define("ms-cost-input",$e)});function dn(){return{entityIds:"",type:"threshold",attribute:"",above:"",below:"",equals:"",notEquals:"",forMinutes:"0",targetValue:"",deltaMode:!1,fromState:"",toState:"",targetChanges:"",runtimeHours:"",onStates:"",daysBefore:"0",carry:{}}}function un(s){return{type:s.type||"threshold",attribute:s.attribute||"",above:s.trigger_above?.toString()??"",below:s.trigger_below?.toString()??"",equals:s.trigger_equals?.toString()??"",notEquals:s.trigger_not_equals?.toString()??"",forMinutes:s.trigger_for_minutes?.toString()??"0",targetValue:s.trigger_target_value?.toString()??"",deltaMode:s.trigger_delta_mode||!1,fromState:s.trigger_from_state||"",toState:s.trigger_to_state||"",targetChanges:s.trigger_target_changes?.toString()??"",runtimeHours:s.trigger_runtime_hours?.toString()??"",onStates:(s.trigger_on_states||[]).join(", "),daysBefore:s.trigger_days_before?.toString()??"0"}}function hn(s,r){r.attribute&&(s.attribute=r.attribute);let e=parseInt(r.forMinutes,10);if(r.type==="threshold"){let t=parseFloat(r.above);isNaN(t)||(s.trigger_above=t);let i=parseFloat(r.below);isNaN(i)||(s.trigger_below=i);let a=parseFloat(r.equals);isNaN(a)||(s.trigger_equals=a);let o=parseFloat(r.notEquals);isNaN(o)||(s.trigger_not_equals=o),isNaN(e)||(s.trigger_for_minutes=e)}else if(r.type==="counter"){let t=parseFloat(r.targetValue);isNaN(t)||(s.trigger_target_value=t),s.trigger_delta_mode=r.deltaMode}else if(r.type==="state_change"){r.fromState&&(s.trigger_from_state=r.fromState),r.toState&&(s.trigger_to_state=r.toState);let t=parseInt(r.targetChanges,10);isNaN(t)||(s.trigger_target_changes=t),isNaN(e)||(s.trigger_for_minutes=e)}else if(r.type==="runtime"){let t=parseFloat(r.runtimeHours);isNaN(t)||(s.trigger_runtime_hours=t);let i=(r.onStates||"").split(",").map(a=>a.trim()).filter(Boolean);i.length>0&&(s.trigger_on_states=i)}else if(r.type==="due_date"){let t=parseInt(r.daysBefore,10);s.trigger_days_before=isNaN(t)?0:t}}function ko(s){return{entityIds:ai(s).join(", "),...un(s),carry:Object.fromEntries(Object.entries(s).filter(([e])=>!wo.has(e)&&!e.startsWith("_")))}}function $o(s){let r=s.entityIds.split(",").map(t=>t.trim()).filter(Boolean);if(r.length===0)return null;let e={...s.carry||{},entity_id:r[0],entity_ids:r,type:s.type};return hn(e,s),e}function Eo(s){return Array.from({length:7},(r,e)=>Ke(e,s,"short"))}function So(s){return Array.from({length:12},(r,e)=>Ui(e,s,"short"))}var vo,yo,bo,li,ln,pn,cn,xo,de,Me,wo,g,Xi,_n=y(()=>{"use strict";I();F();T();Zs();si();Oe();sn();De();Et();ni();Zi();Ki();nn();on();Xe();oi();vo=["cleaning","inspection","replacement","calibration","service","reading","custom"],yo=["low","normal","high"],bo=["time_based","weekdays","nth_weekday","day_of_month","calendar","sensor_based","one_time","manual"],li=["weekdays","nth_weekday","day_of_month","calendar"],ln=["time_based","one_time",...li],pn=["threshold","counter","state_change","runtime","due_date"],cn=(s,r)=>n(s==="due_date"?"trigger_type_due_date":s,r),xo=[...pn,"compound"],de={alpha:"0.3",min:"7",max:"365"},Me=ke;wo=new Set(["entity_id","entity_ids","type","attribute","trigger_above","trigger_below","trigger_equals","trigger_not_equals","trigger_for_minutes","trigger_target_value","trigger_delta_mode","trigger_from_state","trigger_to_state","trigger_target_changes","trigger_runtime_hours","trigger_on_states","trigger_days_before"]);g=class g extends S{constructor(){super(...arguments);this.checklistsEnabled=!1;this.scheduleTimeEnabled=!1;this.completionActionsEnabled=!1;this.adaptiveFeature=!1;this.seasonalFeature=!1;this.environmentalFeature=!1;this.defaultWarningDays=7;this.parts=[];this._foreignOwners=[];this._open=!1;this._entityPickerFallback=!1;this._pickerProbeStrikes=0;this._loading=!1;this._error="";this._warning="";this._entryId="";this._taskId=null;this._isFleetTask=!1;this._objectChoices=[];this._name="";this._type="custom";this._scheduleType="time_based";this._intervalDays="30";this._intervalUnit="days";this._dueDate="";this._warningDays="7";this._earliestCompletionDays="";this._intervalAnchor="completion";this._weekdays=[];this._nth="1";this._nthWeekday="5";this._domDay="1";this._domLastDay=!1;this._domBusiness=!1;this._calOffset="0";this._calendarEntity="";this._seasonMonths=[];this._endsMode="never";this._endsCount="";this._endsUntil="";this._schedulePreview=[];this._schedulePreviewEnded=!1;this._previewSeq=0;this._notes="";this._documentationUrl="";this._customIcon="";this._notifyIcon="";this._priority="normal";this._labels="";this._mirrorTodoEntities=[];this._enabled=!0;this._triggerEntityId="";this._triggerEntityIds=[];this._triggerEntityLogic="any";this._triggerAttribute="";this._triggerType="threshold";this._triggerAbove="";this._triggerBelow="";this._triggerEquals="";this._triggerNotEquals="";this._triggerForMinutes="0";this._triggerCombinator="any";this._triggerTargetValue="";this._triggerDeltaMode=!1;this._triggerBaselineValue="";this._liveBaselineValue=null;this._autoCompleteOnRecovery=!1;this._triggerFromState="";this._triggerToState="";this._triggerTargetChanges="";this._triggerRuntimeHours="";this._triggerDaysBefore="0";this._triggerRuntimeMaxSession="";this._triggerOnStates="";this._compoundLogic="AND";this._compoundConditions=[];this._suggestedAttributes=[];this._availableAttributes=[];this._entityDomain="";this._lastPerformed="";this._nfcTagId="";this._requireTagScan=!1;this._allowSkip=!0;this._notifyEnabled=!0;this._readingUnit="";this._readings=[];this._consumesParts={};this._consumesQtyText={};this._partsLoadFailed=!1;this._availableTags=[];this._responsibleUserId=null;this._loadedLastPerformed="";this._loadedResponsibleUserId=null;this._assigneePool=[];this._rotationStrategy="";this._availableUsers=[];this._checklistText="";this._phaseDefs=[];this._phaseSeq=[];this._requiredCompletion=[];this._scheduleTime="";this._scheduleTimeOn=!1;this._actionService="";this._actionTargetEntity="";this._actionTargetStored=null;this._actionTargetInitial="";this._actionSkipAuto=!1;this._actionPresent=!1;this._actionData={};this._actionDataJsonFallback="";this._actionTesting=!1;this._actionTestResult="";this._actionTestError="";this._qcNotes="";this._qcCost="";this._qcDuration="";this._qcFeedback="";this._environmentalEntity="";this._environmentalAttribute="";this._environmentalInitial="";this._environmentalAttributeInitial="";this._adaptiveEnabled=!1;this._adaptiveAlpha=de.alpha;this._adaptiveMin=de.min;this._adaptiveMax=de.max;this._adaptiveSeasonal=!0;this._adaptivePrediction=!0;this._adaptiveInitial="";this._adaptiveWasEnabled=!1;this._userService=null;this._conditionAttrOptions={};this._conditionAttrPending=new Set}_adaptiveSnapshot(){return JSON.stringify([this._adaptiveEnabled,this._adaptiveAlpha,this._adaptiveMin,this._adaptiveMax,this._adaptiveSeasonal,this._adaptivePrediction])}get _lang(){return N(this.hass)}async openCreate(e,t){this._entryId=e,this._taskId=null,this._isFleetTask=!1,this._error="",this._warning="",!e&&t&&t.length>0?(this._objectChoices=t.map(i=>({entry_id:i.entry_id,name:i.object.name})).sort((i,a)=>i.name.localeCompare(a.name)),this._entryId=this._objectChoices[0].entry_id):this._objectChoices=[],this._resetFields(),await Promise.all([this._loadUsers(),this._loadTags(),this._loadParts(),this._loadForeignPools()]),this._open=!0}async openEdit(e,t){this._entryId=e,this._taskId=t.id,this._error="",this._warning="",this._objectChoices=[],this._isFleetTask=t.battery_fleet_task===!0,this._name=t.name,this._type=t.type,this._scheduleType=t.schedule_type,this._intervalDays=t.interval_days!=null?String(t.interval_days):"",this._intervalUnit=t.interval_unit||"days",this._dueDate=t.due_date||"";let i=t.schedule;this._weekdays=i?.kind==="weekdays"?[...i.weekdays??[]]:[],this._nth=i?.kind==="nth_weekday"?String(i.nth??1):"1",this._nthWeekday=i?.kind==="nth_weekday"?String(i.weekday??5):"5",this._domDay=i?.kind==="day_of_month"&&(i.day??1)>=1?String(i.day??1):"1",this._domLastDay=i?.kind==="day_of_month"&&i.day===-1,this._domBusiness=i?.kind==="day_of_month"&&i.business===!0,this._calendarEntity=i?.kind==="calendar"&&i.entity_id||"",this._calOffset=i?.offset?String(i.offset):"0",this._seasonMonths=Array.isArray(i?.season_months)?[...i.season_months]:[];let a=i?.ends;a&&typeof a.count=="number"?(this._endsMode="count",this._endsCount=String(a.count),this._endsUntil=""):a&&typeof a.until=="string"?(this._endsMode="until",this._endsUntil=a.until,this._endsCount=""):(this._endsMode="never",this._endsCount="",this._endsUntil=""),this._warningDays=t.warning_days.toString(),this._earliestCompletionDays=t.earliest_completion_days!=null?String(t.earliest_completion_days):"",this._intervalAnchor=t.interval_anchor||"completion",this._notes=t.notes||"",this._documentationUrl=t.documentation_url||"",this._customIcon=t.custom_icon||"",this._notifyIcon=t.notify_icon||"",this._priority=t.priority||"normal",this._labels=(t.labels||[]).join(", "),this._mirrorTodoEntities=[...t.mirror_todo_entities||[]],this._enabled=t.enabled!==!1,this._lastPerformed=t.last_performed||"",this._loadedLastPerformed=this._lastPerformed,this._nfcTagId=t.nfc_tag_id||"",this._requireTagScan=!!t.require_tag_scan,this._allowSkip=t.allow_skip!==!1,this._notifyEnabled=t.notify_enabled!==!1,this._readingUnit=t.reading_unit||"",this._readings=(t.readings||[]).map(_=>({..._})),this._consumesParts=Object.fromEntries((t.consumes_parts||[]).map(_=>[ae(_),{..._}])),this._consumesQtyText={},this._responsibleUserId=t.responsible_user_id||null,this._loadedResponsibleUserId=this._responsibleUserId,this._assigneePool=[...t.assignee_pool||[]],this._rotationStrategy=t.rotation_strategy||"",this._checklistText=(t.checklist||[]).join(` -`),this._phaseDefs=Object.entries(t.phases||{}).map(([_,m])=>{let{name:f,checklist:x,consumes_parts:w,required_completion_fields:k,...q}=m,L=m.consumes_parts||[],M=L.findIndex(W=>!W.entry_id),B=M>=0?L[M]:void 0;return{id:_,name:m.name||_,checklistText:(m.checklist||[]).join(` -`),partId:B?.part_id||"",partQty:B?.quantity!=null?String(B.quantity):"",reqOverride:m.required_completion_fields!==void 0,reqFields:[...m.required_completion_fields||[]],extraParts:L.filter((W,b)=>b!==M).map(W=>({...W})),carry:q}}),this._phaseSeq=[...t.phase_sequence||[]],this._requiredCompletion=[...t.required_completion_fields||[]],this._scheduleTime=t.schedule_time||"",this._scheduleTimeOn=!!t.schedule_time;let o=t.on_complete_action;if(o&&o.service){this._actionService=o.service;let _=o.target?.entity_id;this._actionTargetEntity=Array.isArray(_)?_[0]||"":_||"",this._actionTargetStored=o.target&&typeof o.target=="object"?JSON.parse(JSON.stringify(o.target)):null,this._actionTargetInitial=this._actionTargetEntity,this._actionData=o.data&&typeof o.data=="object"?{...o.data}:{},this._actionDataJsonFallback="",this._actionSkipAuto=o.skip_auto===!0,this._actionPresent=!0}else this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1;let d=t.quick_complete_defaults;this._qcNotes=d?.notes||"",this._qcCost=d?.cost!=null?String(d.cost):"",this._qcDuration=d?.duration!=null?String(d.duration):"",this._qcFeedback=d?.feedback||"";let p=t.adaptive_config||{};if(this._environmentalEntity=p.environmental_entity||"",this._environmentalAttribute=p.environmental_attribute||"",this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute,this._adaptiveEnabled=!!p.enabled,this._adaptiveAlpha=p.ewa_alpha?.toString()??de.alpha,this._adaptiveMin=p.min_interval_days?.toString()??de.min,this._adaptiveMax=p.max_interval_days?.toString()??de.max,this._adaptiveSeasonal=p.seasonal_enabled!==!1,this._adaptivePrediction=p.sensor_prediction_enabled!==!1,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=this._adaptiveEnabled,t.trigger_config){let _=t.trigger_config;this._triggerEntityId=an(_)||"",this._triggerEntityIds=ai(_),this._triggerEntityLogic=_.entity_logic||"any",this._setTypeFields(un(_)),this._triggerCombinator=_.trigger_combinator==="all"?"all":"any",this._triggerBaselineValue=_.trigger_baseline_value?.toString()||"",this._liveBaselineValue=t.trigger_baseline_value??null,this._autoCompleteOnRecovery=_.auto_complete_on_recovery||!1,this._triggerRuntimeMaxSession=_.trigger_runtime_max_session_seconds?.toString()||"",_.type==="compound"?(this._compoundLogic=_.compound_logic==="OR"?"OR":"AND",this._compoundConditions=(_.conditions||[]).map(ko)):(this._compoundLogic="AND",this._compoundConditions=[])}else this._resetTriggerFields();this._triggerEntityId&&this._fetchEntityAttributes(this._triggerEntityId),await Promise.all([this._loadUsers(),this._loadTags(),this._loadParts(),this._loadForeignPools()]),this._open=!0}_resetFields(){this._name="",this._type="custom",this._scheduleType="time_based",this._intervalDays="30",this._intervalUnit="days",this._dueDate="",this._warningDays=String(this.defaultWarningDays),this._earliestCompletionDays="",this._intervalAnchor="completion",this._weekdays=[],this._nth="1",this._nthWeekday="5",this._domDay="1",this._domLastDay=!1,this._domBusiness=!1,this._calOffset="0",this._seasonMonths=[],this._endsMode="never",this._endsCount="",this._endsUntil="",this._notes="",this._documentationUrl="",this._customIcon="",this._notifyIcon="",this._priority="normal",this._labels="",this._mirrorTodoEntities=[],this._enabled=!0,this._lastPerformed="",this._nfcTagId="",this._requireTagScan=!1,this._allowSkip=!0,this._readingUnit="",this._readings=[],this._consumesParts={},this._consumesQtyText={},this._responsibleUserId=null,this._assigneePool=[],this._rotationStrategy="",this._checklistText="",this._phaseDefs=[],this._phaseSeq=[],this._requiredCompletion=[],this._scheduleTime="",this._scheduleTimeOn=!1,this._environmentalEntity="",this._environmentalAttribute="",this._environmentalInitial="",this._environmentalAttributeInitial="",this._adaptiveEnabled=!1,this._adaptiveAlpha=de.alpha,this._adaptiveMin=de.min,this._adaptiveMax=de.max,this._adaptiveSeasonal=!0,this._adaptivePrediction=!0,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=!1,this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1,this._actionTesting=!1,this._actionTestResult="",this._qcNotes="",this._qcCost="",this._qcDuration="",this._qcFeedback="",this._resetTriggerFields()}_typeFields(){return{type:this._triggerType,attribute:this._triggerAttribute,above:this._triggerAbove,below:this._triggerBelow,equals:this._triggerEquals,notEquals:this._triggerNotEquals,forMinutes:this._triggerForMinutes,targetValue:this._triggerTargetValue,deltaMode:this._triggerDeltaMode,fromState:this._triggerFromState,toState:this._triggerToState,targetChanges:this._triggerTargetChanges,runtimeHours:this._triggerRuntimeHours,onStates:this._triggerOnStates,daysBefore:this._triggerDaysBefore}}_setTypeFields(e){this._triggerType=e.type,this._triggerAttribute=e.attribute,this._triggerAbove=e.above,this._triggerBelow=e.below,this._triggerEquals=e.equals,this._triggerNotEquals=e.notEquals,this._triggerForMinutes=e.forMinutes,this._triggerTargetValue=e.targetValue,this._triggerDeltaMode=e.deltaMode,this._triggerFromState=e.fromState,this._triggerToState=e.toState,this._triggerTargetChanges=e.targetChanges,this._triggerRuntimeHours=e.runtimeHours,this._triggerOnStates=e.onStates,this._triggerDaysBefore=e.daysBefore}_resetTriggerFields(){this._triggerEntityId="",this._triggerEntityIds=[],this._triggerEntityLogic="any",this._suggestedAttributes=[],this._availableAttributes=[],this._entityDomain="",this._setTypeFields(dn()),this._triggerCombinator="any",this._triggerBaselineValue="",this._liveBaselineValue=null,this._autoCompleteOnRecovery=!1,this._triggerRuntimeMaxSession="",this._compoundLogic="AND",this._compoundConditions=[]}async _loadUsers(){this._userService||(this._userService=new ri(this.hass));try{this._availableUsers=await this._userService.getUsers()}catch(e){console.error("Failed to load users:",e),this._availableUsers=[]}}_toggleAssignee(e){this._assigneePool=this._assigneePool.includes(e)?this._assigneePool.filter(t=>t!==e):[...this._assigneePool,e]}async _testAction(){let e=this._actionService.trim();if(!e||!/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(e)){this._actionTestResult="error",this._actionTestError=n("action_test_bad_format",this._lang),setTimeout(()=>{this._actionTestResult="",this._actionTestError=""},5e3);return}let[t,i]=e.split(".");if(!this.hass?.services?.[t]?.[i]){this._actionTestResult="error",this._actionTestError=n("action_test_unknown_service",this._lang).replace("{service}",e),setTimeout(()=>{this._actionTestResult="",this._actionTestError=""},8e3);return}let a=this._actionTargetEntity.trim();if(a){let o=a.split(".")[0];if(o!==t&&!new Set(["homeassistant","scene","notify","persistent_notification"]).has(t)){this._actionTestResult="error",this._actionTestError=n("action_test_domain_mismatch",this._lang).replace("{service}",e).replace("{domain}",t).replace("{entity}",a).replace("{entity_domain}",o).replace("{suggestion}",`${o}.${i}`),setTimeout(()=>{this._actionTestResult="",this._actionTestError=""},8e3);return}if(!this.hass.states?.[a]){this._actionTestResult="error",this._actionTestError=n("action_test_entity_missing",this._lang).replace("{entity}",a),setTimeout(()=>{this._actionTestResult="",this._actionTestError=""},8e3);return}}this._actionTestResult="ok",setTimeout(()=>{this._actionTestResult="",this._actionTestError=""},5e3)}_buildActionData(){if(this._actionDataJsonFallback.trim())try{let e=JSON.parse(this._actionDataJsonFallback);if(e&&typeof e=="object"&&!Array.isArray(e))return e}catch{}return{...this._actionData}}_serviceSchema(){let e=this._actionService.trim();if(!e||!/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(e))return null;let[t,i]=e.split("."),a=this.hass?.services?.[t]?.[i]?.fields;return!a||Object.keys(a).length===0?null:Object.entries(a).map(([o,d])=>({name:o,required:!!d.required,selector:d.selector||{text:{}}}))}_actionTargetExtended(){let e=this._actionTargetStored;return e?Object.entries(e).some(([t,i])=>t==="entity_id"?Array.isArray(i)&&i.length>1:Array.isArray(i)?i.length>0:!!i):!1}_actionTargetSummary(){let e=this._actionTargetStored||{},t=a=>(Array.isArray(a)?a:[a]).filter(o=>typeof o=="string"&&!!o),i=this.hass;return[...t(e.entity_id).map(a=>i.states?.[a]?.attributes?.friendly_name||a),...t(e.device_id).map(a=>i.devices?.[a]?.name_by_user||i.devices?.[a]?.name||a),...t(e.area_id).map(a=>i.areas?.[a]?.name||a),...t(e.floor_id).map(a=>i.floors?.[a]?.name||a),...t(e.label_id)].join(", ")}_renderCompletionActionsSection(e){if(!this.completionActionsEnabled&&!this._actionPresent)return h;let t=this._serviceSchema();return l` + `],c([v()],$e.prototype,"value",2),c([v()],$e.prototype,"lang",2),c([h()],$e.prototype,"_credit",2),c([h()],$e.prototype,"_amount",2);customElements.get("ms-cost-input")||customElements.define("ms-cost-input",$e)});function An(){return{entityIds:"",type:"threshold",attribute:"",above:"",below:"",equals:"",notEquals:"",forMinutes:"0",targetValue:"",deltaMode:!1,fromState:"",toState:"",targetChanges:"",runtimeHours:"",onStates:"",daysBefore:"0",carry:{}}}function In(s){return{type:s.type||"threshold",attribute:s.attribute||"",above:s.trigger_above?.toString()??"",below:s.trigger_below?.toString()??"",equals:s.trigger_equals?.toString()??"",notEquals:s.trigger_not_equals?.toString()??"",forMinutes:s.trigger_for_minutes?.toString()??"0",targetValue:s.trigger_target_value?.toString()??"",deltaMode:s.trigger_delta_mode||!1,fromState:s.trigger_from_state||"",toState:s.trigger_to_state||"",targetChanges:s.trigger_target_changes?.toString()??"",runtimeHours:s.trigger_runtime_hours?.toString()??"",onStates:(s.trigger_on_states||[]).join(", "),daysBefore:s.trigger_days_before?.toString()??"0"}}function Rn(s,r){r.attribute&&(s.attribute=r.attribute);let e=parseInt(r.forMinutes,10);if(r.type==="threshold"){let t=parseFloat(r.above);isNaN(t)||(s.trigger_above=t);let i=parseFloat(r.below);isNaN(i)||(s.trigger_below=i);let n=parseFloat(r.equals);isNaN(n)||(s.trigger_equals=n);let o=parseFloat(r.notEquals);isNaN(o)||(s.trigger_not_equals=o),isNaN(e)||(s.trigger_for_minutes=e)}else if(r.type==="counter"){let t=parseFloat(r.targetValue);isNaN(t)||(s.trigger_target_value=t),s.trigger_delta_mode=r.deltaMode}else if(r.type==="state_change"){r.fromState&&(s.trigger_from_state=r.fromState),r.toState&&(s.trigger_to_state=r.toState);let t=parseInt(r.targetChanges,10);isNaN(t)||(s.trigger_target_changes=t),isNaN(e)||(s.trigger_for_minutes=e)}else if(r.type==="runtime"){let t=parseFloat(r.runtimeHours);isNaN(t)||(s.trigger_runtime_hours=t);let i=(r.onStates||"").split(",").map(n=>n.trim()).filter(Boolean);i.length>0&&(s.trigger_on_states=i)}else if(r.type==="due_date"){let t=parseInt(r.daysBefore,10);s.trigger_days_before=isNaN(t)?0:t}}function Ko(s){return{entityIds:ui(s).join(", "),...In(s),carry:Object.fromEntries(Object.entries(s).filter(([e])=>!Go.has(e)&&!e.startsWith("_")))}}function Yo(s){let r=s.entityIds.split(",").map(t=>t.trim()).filter(Boolean);if(r.length===0)return null;let e={...s.carry||{},entity_id:r[0],entity_ids:r,type:s.type};return Rn(e,s),e}function Qo(s){return Array.from({length:7},(r,e)=>Qe(e,s,"short"))}function Zo(s){return Array.from({length:12},(r,e)=>Xi(e,s,"short"))}var Uo,Bo,Wo,_i,Sn,Cn,Tn,Vo,pe,Fe,Go,g,cr,Pn=y(()=>{"use strict";I();F();T();gn();di();je();wn();ze();St();pi();or();sr();kn();En();tt();hi();Uo=["cleaning","inspection","replacement","calibration","service","reading","custom"],Bo=["low","normal","high"],Wo=["time_based","weekdays","nth_weekday","day_of_month","calendar","sensor_based","one_time","manual"],_i=["weekdays","nth_weekday","day_of_month","calendar"],Sn=["time_based","one_time",..._i],Cn=["threshold","counter","state_change","runtime","due_date"],Tn=(s,r)=>a(s==="due_date"?"trigger_type_due_date":s,r),Vo=[...Cn,"compound"],pe={alpha:"0.3",min:"7",max:"365"},Fe=ke;Go=new Set(["entity_id","entity_ids","type","attribute","trigger_above","trigger_below","trigger_equals","trigger_not_equals","trigger_for_minutes","trigger_target_value","trigger_delta_mode","trigger_from_state","trigger_to_state","trigger_target_changes","trigger_runtime_hours","trigger_on_states","trigger_days_before"]);g=class g extends S{constructor(){super(...arguments);this.checklistsEnabled=!1;this.scheduleTimeEnabled=!1;this.completionActionsEnabled=!1;this.adaptiveFeature=!1;this.seasonalFeature=!1;this.environmentalFeature=!1;this.defaultWarningDays=7;this.parts=[];this._foreignOwners=[];this._open=!1;this._entityPickerFallback=!1;this._pickerProbeStrikes=0;this._loading=!1;this._error="";this._warning="";this._entryId="";this._taskId=null;this._isFleetTask=!1;this._objectChoices=[];this._name="";this._type="custom";this._scheduleType="time_based";this._intervalDays="30";this._intervalUnit="days";this._dueDate="";this._warningDays="7";this._earliestCompletionDays="";this._intervalAnchor="completion";this._weekdays=[];this._nth="1";this._nthWeekday="5";this._domDay="1";this._domLastDay=!1;this._domBusiness=!1;this._calOffset="0";this._calendarEntity="";this._seasonMonths=[];this._endsMode="never";this._endsCount="";this._endsUntil="";this._schedulePreview=[];this._schedulePreviewEnded=!1;this._previewSeq=0;this._notes="";this._documentationUrl="";this._customIcon="";this._notifyIcon="";this._priority="normal";this._labels="";this._mirrorTodoEntities=[];this._enabled=!0;this._triggerEntityId="";this._triggerEntityIds=[];this._triggerEntityLogic="any";this._triggerAttribute="";this._triggerType="threshold";this._triggerAbove="";this._triggerBelow="";this._triggerEquals="";this._triggerNotEquals="";this._triggerForMinutes="0";this._triggerCombinator="any";this._triggerTargetValue="";this._triggerDeltaMode=!1;this._triggerBaselineValue="";this._liveBaselineValue=null;this._autoCompleteOnRecovery=!1;this._triggerFromState="";this._triggerToState="";this._triggerTargetChanges="";this._triggerRuntimeHours="";this._triggerDaysBefore="0";this._triggerRuntimeMaxSession="";this._triggerOnStates="";this._compoundLogic="AND";this._compoundConditions=[];this._suggestedAttributes=[];this._availableAttributes=[];this._entityDomain="";this._lastPerformed="";this._nfcTagId="";this._requireTagScan=!1;this._allowSkip=!0;this._notifyEnabled=!0;this._readingUnit="";this._readings=[];this._consumesParts={};this._consumesQtyText={};this._partsLoadFailed=!1;this._availableTags=[];this._responsibleUserId=null;this._loadedLastPerformed="";this._loadedResponsibleUserId=null;this._assigneePool=[];this._rotationStrategy="";this._availableUsers=[];this._checklistText="";this._phaseDefs=[];this._phaseSeq=[];this._requiredCompletion=[];this._scheduleTime="";this._scheduleTimeOn=!1;this._actionService="";this._actionTargetEntity="";this._actionTargetStored=null;this._actionTargetInitial="";this._actionSkipAuto=!1;this._actionPresent=!1;this._actionData={};this._actionDataJsonFallback="";this._actionTesting=!1;this._actionTestResult="";this._actionTestError="";this._qcNotes="";this._qcCost="";this._qcDuration="";this._qcFeedback="";this._environmentalEntity="";this._environmentalAttribute="";this._environmentalInitial="";this._environmentalAttributeInitial="";this._adaptiveEnabled=!1;this._adaptiveAlpha=pe.alpha;this._adaptiveMin=pe.min;this._adaptiveMax=pe.max;this._adaptiveSeasonal=!0;this._adaptivePrediction=!0;this._adaptiveInitial="";this._adaptiveWasEnabled=!1;this._userService=null;this._conditionAttrOptions={};this._conditionAttrPending=new Set}_adaptiveSnapshot(){return JSON.stringify([this._adaptiveEnabled,this._adaptiveAlpha,this._adaptiveMin,this._adaptiveMax,this._adaptiveSeasonal,this._adaptivePrediction])}get _lang(){return N(this.hass)}async openCreate(e,t){this._entryId=e,this._taskId=null,this._isFleetTask=!1,this._error="",this._warning="",!e&&t&&t.length>0?(this._objectChoices=t.map(i=>({entry_id:i.entry_id,name:i.object.name})).sort((i,n)=>i.name.localeCompare(n.name)),this._entryId=this._objectChoices[0].entry_id):this._objectChoices=[],this._resetFields(),await Promise.all([this._loadUsers(),this._loadTags(),this._loadParts(),this._loadForeignPools()]),this._open=!0}async openEdit(e,t){this._entryId=e,this._taskId=t.id,this._error="",this._warning="",this._objectChoices=[],this._isFleetTask=t.battery_fleet_task===!0,this._name=t.name,this._type=t.type,this._scheduleType=t.schedule_type,this._intervalDays=t.interval_days!=null?String(t.interval_days):"",this._intervalUnit=t.interval_unit||"days",this._dueDate=t.due_date||"";let i=t.schedule;this._weekdays=i?.kind==="weekdays"?[...i.weekdays??[]]:[],this._nth=i?.kind==="nth_weekday"?String(i.nth??1):"1",this._nthWeekday=i?.kind==="nth_weekday"?String(i.weekday??5):"5",this._domDay=i?.kind==="day_of_month"&&(i.day??1)>=1?String(i.day??1):"1",this._domLastDay=i?.kind==="day_of_month"&&i.day===-1,this._domBusiness=i?.kind==="day_of_month"&&i.business===!0,this._calendarEntity=i?.kind==="calendar"&&i.entity_id||"",this._calOffset=i?.offset?String(i.offset):"0",this._seasonMonths=Array.isArray(i?.season_months)?[...i.season_months]:[];let n=i?.ends;n&&typeof n.count=="number"?(this._endsMode="count",this._endsCount=String(n.count),this._endsUntil=""):n&&typeof n.until=="string"?(this._endsMode="until",this._endsUntil=n.until,this._endsCount=""):(this._endsMode="never",this._endsCount="",this._endsUntil=""),this._warningDays=t.warning_days.toString(),this._earliestCompletionDays=t.earliest_completion_days!=null?String(t.earliest_completion_days):"",this._intervalAnchor=t.interval_anchor||"completion",this._notes=t.notes||"",this._documentationUrl=t.documentation_url||"",this._customIcon=t.custom_icon||"",this._notifyIcon=t.notify_icon||"",this._priority=t.priority||"normal",this._labels=(t.labels||[]).join(", "),this._mirrorTodoEntities=[...t.mirror_todo_entities||[]],this._enabled=t.enabled!==!1,this._lastPerformed=t.last_performed||"",this._loadedLastPerformed=this._lastPerformed,this._nfcTagId=t.nfc_tag_id||"",this._requireTagScan=!!t.require_tag_scan,this._allowSkip=t.allow_skip!==!1,this._notifyEnabled=t.notify_enabled!==!1,this._readingUnit=t.reading_unit||"",this._readings=(t.readings||[]).map(_=>({..._})),this._consumesParts=Object.fromEntries((t.consumes_parts||[]).map(_=>[ae(_),{..._}])),this._consumesQtyText={},this._responsibleUserId=t.responsible_user_id||null,this._loadedResponsibleUserId=this._responsibleUserId,this._assigneePool=[...t.assignee_pool||[]],this._rotationStrategy=t.rotation_strategy||"",this._checklistText=(t.checklist||[]).join(` +`),this._phaseDefs=Object.entries(t.phases||{}).map(([_,m])=>{let{name:f,checklist:x,consumes_parts:w,required_completion_fields:k,...H}=m,L=m.consumes_parts||[],M=L.findIndex(W=>!W.entry_id),B=M>=0?L[M]:void 0;return{id:_,name:m.name||_,checklistText:(m.checklist||[]).join(` +`),partId:B?.part_id||"",partQty:B?.quantity!=null?String(B.quantity):"",reqOverride:m.required_completion_fields!==void 0,reqFields:[...m.required_completion_fields||[]],extraParts:L.filter((W,b)=>b!==M).map(W=>({...W})),carry:H}}),this._phaseSeq=[...t.phase_sequence||[]],this._requiredCompletion=[...t.required_completion_fields||[]],this._scheduleTime=t.schedule_time||"",this._scheduleTimeOn=!!t.schedule_time;let o=t.on_complete_action;if(o&&o.service){this._actionService=o.service;let _=o.target?.entity_id;this._actionTargetEntity=Array.isArray(_)?_[0]||"":_||"",this._actionTargetStored=o.target&&typeof o.target=="object"?JSON.parse(JSON.stringify(o.target)):null,this._actionTargetInitial=this._actionTargetEntity,this._actionData=o.data&&typeof o.data=="object"?{...o.data}:{},this._actionDataJsonFallback="",this._actionSkipAuto=o.skip_auto===!0,this._actionPresent=!0}else this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1;let d=t.quick_complete_defaults;this._qcNotes=d?.notes||"",this._qcCost=d?.cost!=null?String(d.cost):"",this._qcDuration=d?.duration!=null?String(d.duration):"",this._qcFeedback=d?.feedback||"";let p=t.adaptive_config||{};if(this._environmentalEntity=p.environmental_entity||"",this._environmentalAttribute=p.environmental_attribute||"",this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute,this._adaptiveEnabled=!!p.enabled,this._adaptiveAlpha=p.ewa_alpha?.toString()??pe.alpha,this._adaptiveMin=p.min_interval_days?.toString()??pe.min,this._adaptiveMax=p.max_interval_days?.toString()??pe.max,this._adaptiveSeasonal=p.seasonal_enabled!==!1,this._adaptivePrediction=p.sensor_prediction_enabled!==!1,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=this._adaptiveEnabled,t.trigger_config){let _=t.trigger_config;this._triggerEntityId=$n(_)||"",this._triggerEntityIds=ui(_),this._triggerEntityLogic=_.entity_logic||"any",this._setTypeFields(In(_)),this._triggerCombinator=_.trigger_combinator==="all"?"all":"any",this._triggerBaselineValue=_.trigger_baseline_value?.toString()||"",this._liveBaselineValue=t.trigger_baseline_value??null,this._autoCompleteOnRecovery=_.auto_complete_on_recovery||!1,this._triggerRuntimeMaxSession=_.trigger_runtime_max_session_seconds?.toString()||"",_.type==="compound"?(this._compoundLogic=_.compound_logic==="OR"?"OR":"AND",this._compoundConditions=(_.conditions||[]).map(Ko)):(this._compoundLogic="AND",this._compoundConditions=[])}else this._resetTriggerFields();this._triggerEntityId&&this._fetchEntityAttributes(this._triggerEntityId),await Promise.all([this._loadUsers(),this._loadTags(),this._loadParts(),this._loadForeignPools()]),this._open=!0}_resetFields(){this._name="",this._type="custom",this._scheduleType="time_based",this._intervalDays="30",this._intervalUnit="days",this._dueDate="",this._warningDays=String(this.defaultWarningDays),this._earliestCompletionDays="",this._intervalAnchor="completion",this._weekdays=[],this._nth="1",this._nthWeekday="5",this._domDay="1",this._domLastDay=!1,this._domBusiness=!1,this._calOffset="0",this._seasonMonths=[],this._endsMode="never",this._endsCount="",this._endsUntil="",this._notes="",this._documentationUrl="",this._customIcon="",this._notifyIcon="",this._priority="normal",this._labels="",this._mirrorTodoEntities=[],this._enabled=!0,this._lastPerformed="",this._nfcTagId="",this._requireTagScan=!1,this._allowSkip=!0,this._readingUnit="",this._readings=[],this._consumesParts={},this._consumesQtyText={},this._responsibleUserId=null,this._assigneePool=[],this._rotationStrategy="",this._checklistText="",this._phaseDefs=[],this._phaseSeq=[],this._requiredCompletion=[],this._scheduleTime="",this._scheduleTimeOn=!1,this._environmentalEntity="",this._environmentalAttribute="",this._environmentalInitial="",this._environmentalAttributeInitial="",this._adaptiveEnabled=!1,this._adaptiveAlpha=pe.alpha,this._adaptiveMin=pe.min,this._adaptiveMax=pe.max,this._adaptiveSeasonal=!0,this._adaptivePrediction=!0,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=!1,this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1,this._actionTesting=!1,this._actionTestResult="",this._qcNotes="",this._qcCost="",this._qcDuration="",this._qcFeedback="",this._resetTriggerFields()}_typeFields(){return{type:this._triggerType,attribute:this._triggerAttribute,above:this._triggerAbove,below:this._triggerBelow,equals:this._triggerEquals,notEquals:this._triggerNotEquals,forMinutes:this._triggerForMinutes,targetValue:this._triggerTargetValue,deltaMode:this._triggerDeltaMode,fromState:this._triggerFromState,toState:this._triggerToState,targetChanges:this._triggerTargetChanges,runtimeHours:this._triggerRuntimeHours,onStates:this._triggerOnStates,daysBefore:this._triggerDaysBefore}}_setTypeFields(e){this._triggerType=e.type,this._triggerAttribute=e.attribute,this._triggerAbove=e.above,this._triggerBelow=e.below,this._triggerEquals=e.equals,this._triggerNotEquals=e.notEquals,this._triggerForMinutes=e.forMinutes,this._triggerTargetValue=e.targetValue,this._triggerDeltaMode=e.deltaMode,this._triggerFromState=e.fromState,this._triggerToState=e.toState,this._triggerTargetChanges=e.targetChanges,this._triggerRuntimeHours=e.runtimeHours,this._triggerOnStates=e.onStates,this._triggerDaysBefore=e.daysBefore}_resetTriggerFields(){this._triggerEntityId="",this._triggerEntityIds=[],this._triggerEntityLogic="any",this._suggestedAttributes=[],this._availableAttributes=[],this._entityDomain="",this._setTypeFields(An()),this._triggerCombinator="any",this._triggerBaselineValue="",this._liveBaselineValue=null,this._autoCompleteOnRecovery=!1,this._triggerRuntimeMaxSession="",this._compoundLogic="AND",this._compoundConditions=[]}async _loadUsers(){this._userService||(this._userService=new ci(this.hass));try{this._availableUsers=await this._userService.getUsers()}catch(e){console.error("Failed to load users:",e),this._availableUsers=[]}}_toggleAssignee(e){this._assigneePool=this._assigneePool.includes(e)?this._assigneePool.filter(t=>t!==e):[...this._assigneePool,e]}async _testAction(){let e=this._actionService.trim();if(!e||!/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(e)){this._actionTestResult="error",this._actionTestError=a("action_test_bad_format",this._lang),setTimeout(()=>{this._actionTestResult="",this._actionTestError=""},5e3);return}let[t,i]=e.split(".");if(!this.hass?.services?.[t]?.[i]){this._actionTestResult="error",this._actionTestError=a("action_test_unknown_service",this._lang).replace("{service}",e),setTimeout(()=>{this._actionTestResult="",this._actionTestError=""},8e3);return}let n=this._actionTargetEntity.trim();if(n){let o=n.split(".")[0];if(o!==t&&!new Set(["homeassistant","scene","notify","persistent_notification"]).has(t)){this._actionTestResult="error",this._actionTestError=a("action_test_domain_mismatch",this._lang).replace("{service}",e).replace("{domain}",t).replace("{entity}",n).replace("{entity_domain}",o).replace("{suggestion}",`${o}.${i}`),setTimeout(()=>{this._actionTestResult="",this._actionTestError=""},8e3);return}if(!this.hass.states?.[n]){this._actionTestResult="error",this._actionTestError=a("action_test_entity_missing",this._lang).replace("{entity}",n),setTimeout(()=>{this._actionTestResult="",this._actionTestError=""},8e3);return}}this._actionTestResult="ok",setTimeout(()=>{this._actionTestResult="",this._actionTestError=""},5e3)}_buildActionData(){if(this._actionDataJsonFallback.trim())try{let e=JSON.parse(this._actionDataJsonFallback);if(e&&typeof e=="object"&&!Array.isArray(e))return e}catch{}return{...this._actionData}}_serviceSchema(){let e=this._actionService.trim();if(!e||!/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(e))return null;let[t,i]=e.split("."),n=this.hass?.services?.[t]?.[i]?.fields;return!n||Object.keys(n).length===0?null:Object.entries(n).map(([o,d])=>({name:o,required:!!d.required,selector:d.selector||{text:{}}}))}_actionTargetExtended(){let e=this._actionTargetStored;return e?Object.entries(e).some(([t,i])=>t==="entity_id"?Array.isArray(i)&&i.length>1:Array.isArray(i)?i.length>0:!!i):!1}_actionTargetSummary(){let e=this._actionTargetStored||{},t=n=>(Array.isArray(n)?n:[n]).filter(o=>typeof o=="string"&&!!o),i=this.hass;return[...t(e.entity_id).map(n=>i.states?.[n]?.attributes?.friendly_name||n),...t(e.device_id).map(n=>i.devices?.[n]?.name_by_user||i.devices?.[n]?.name||n),...t(e.area_id).map(n=>i.areas?.[n]?.name||n),...t(e.floor_id).map(n=>i.floors?.[n]?.name||n),...t(e.label_id)].join(", ")}_renderCompletionActionsSection(e){if(!this.completionActionsEnabled&&!this._actionPresent)return u;let t=this._serviceSchema();return l`
- ${n("on_complete_action_title",e)} -

${n("on_complete_action_desc",e)}

+ ${a("on_complete_action_title",e)} +

${a("on_complete_action_desc",e)}

{this._actionService=i.detail.value||"";let a=this._serviceSchema();if(a){let o=new Set(a.map(d=>d.name));this._actionData=Object.fromEntries(Object.entries(this._actionData).filter(([d])=>o.has(d)))}}} + @value-changed=${i=>{this._actionService=i.detail.value||"";let n=this._serviceSchema();if(n){let o=new Set(n.map(d=>d.name));this._actionData=Object.fromEntries(Object.entries(this._actionData).filter(([d])=>o.has(d)))}}} > n("on_complete_action_target",e)} - @value-changed=${i=>{let a=i.detail.value;this._actionTargetEntity=a.target_entity||""}} + .computeLabel=${()=>a("on_complete_action_target",e)} + @value-changed=${i=>{let n=i.detail.value;this._actionTargetEntity=n.target_entity||""}} > - ${this._actionTargetExtended()&&this._actionTargetEntity.trim()===this._actionTargetInitial?l`

${n("on_complete_action_target_more",e).replace("{targets}",this._actionTargetSummary())}

`:h} + ${this._actionTargetExtended()&&this._actionTargetEntity.trim()===this._actionTargetInitial?l`

${a("on_complete_action_target_more",e).replace("{targets}",this._actionTargetSummary())}

`:u}

- ${n("on_complete_action_target_hint",e)} + ${a("on_complete_action_target_hint",e)}

${t?l` `:l` {this._actionDataJsonFallback=i.target.value}} @@ -1771,31 +1788,31 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
- ${this._actionTestResult==="ok"?l`${n("on_complete_action_test_success",e)}`:h} + ${this._actionTestResult==="ok"?l`${a("on_complete_action_test_success",e)}`:u} ${this._actionTestResult==="error"?l`
- ${n("on_complete_action_test_failed",e)} - ${this._actionTestError?l`
${this._actionTestError}
`:h} -
`:h} + ${a("on_complete_action_test_failed",e)} + ${this._actionTestError?l`
${this._actionTestError}
`:u} +
`:u}
${this.completionActionsEnabled?l`
- ${n("quick_complete_defaults_title",e)} -

${n("quick_complete_defaults_desc",e)}

+ ${a("quick_complete_defaults_title",e)} +

${a("quick_complete_defaults_desc",e)}

{this._qcNotes=i.target.value}} >
- ${n("quick_complete_defaults_cost",e)} + ${a("quick_complete_defaults_cost",e)} {this._qcCost=i.detail.value}}>
{this._qcDuration=i.target.value}} @@ -1803,90 +1820,90 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" -
`:h} - `}async _loadParts(){if(this.parts=[],!!this._entryId)try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId});this.parts=e.parts||[],this._partsLoadFailed=!1}catch{this.parts=[],this._partsLoadFailed=!0}}async _loadForeignPools(){if(this._foreignOwners=[],!!this._entryId)try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"});this._foreignOwners=(e.objects||[]).filter(t=>t.entry_id!==this._entryId&&(t.parts||[]).length>0).map(t=>({entry_id:t.entry_id,name:t.object?.name||t.entry_id,parts:t.parts||[]})).sort((t,i)=>t.name.localeCompare(i.name))}catch{this._foreignOwners=[]}}async _loadTags(){try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/tags/list"});this._availableTags=e.tags||[]}catch{this._availableTags=[]}}_fetchConditionAttributes(e){!e||!this.hass||this._conditionAttrOptions[e]||this._conditionAttrPending.has(e)||(this._conditionAttrPending.add(e),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/entity/attributes",entity_id:e}).then(t=>{let i=t;this._conditionAttrOptions={...this._conditionAttrOptions,[e]:{suggested:i.suggested_attributes||[],available:i.available_attributes||[]}}}).catch(()=>{this._conditionAttrOptions={...this._conditionAttrOptions,[e]:{suggested:[],available:[]}}}))}async _fetchEntityAttributes(e){if(!e||!this.hass){this._suggestedAttributes=[],this._availableAttributes=[],this._entityDomain="";return}try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/entity/attributes",entity_id:e});this._entityDomain=t.domain||"",this._suggestedAttributes=t.suggested_attributes||[],this._availableAttributes=t.available_attributes||[]}catch{this._suggestedAttributes=[],this._availableAttributes=[],this._entityDomain=""}}get _hasForeignPick(){return Object.values(this._consumesParts).some(e=>!!e.entry_id)}_renderConsumesRow(e,t){let i=ae({part_id:e.id,entry_id:t}),a=this._consumesParts[i],o=t?{part_id:e.id,quantity:1,entry_id:t}:{part_id:e.id,quantity:1};return l` + `:u} + `}async _loadParts(){if(this.parts=[],!!this._entryId)try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId});this.parts=e.parts||[],this._partsLoadFailed=!1}catch{this.parts=[],this._partsLoadFailed=!0}}async _loadForeignPools(){if(this._foreignOwners=[],!!this._entryId)try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"});this._foreignOwners=(e.objects||[]).filter(t=>t.entry_id!==this._entryId&&(t.parts||[]).length>0).map(t=>({entry_id:t.entry_id,name:t.object?.name||t.entry_id,parts:t.parts||[]})).sort((t,i)=>t.name.localeCompare(i.name))}catch{this._foreignOwners=[]}}async _loadTags(){try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/tags/list"});this._availableTags=e.tags||[]}catch{this._availableTags=[]}}_fetchConditionAttributes(e){!e||!this.hass||this._conditionAttrOptions[e]||this._conditionAttrPending.has(e)||(this._conditionAttrPending.add(e),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/entity/attributes",entity_id:e}).then(t=>{let i=t;this._conditionAttrOptions={...this._conditionAttrOptions,[e]:{suggested:i.suggested_attributes||[],available:i.available_attributes||[]}}}).catch(()=>{this._conditionAttrOptions={...this._conditionAttrOptions,[e]:{suggested:[],available:[]}}}))}async _fetchEntityAttributes(e){if(!e||!this.hass){this._suggestedAttributes=[],this._availableAttributes=[],this._entityDomain="";return}try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/entity/attributes",entity_id:e});this._entityDomain=t.domain||"",this._suggestedAttributes=t.suggested_attributes||[],this._availableAttributes=t.available_attributes||[]}catch{this._suggestedAttributes=[],this._availableAttributes=[],this._entityDomain=""}}get _hasForeignPick(){return Object.values(this._consumesParts).some(e=>!!e.entry_id)}_renderConsumesRow(e,t){let i=ae({part_id:e.id,entry_id:t}),n=this._consumesParts[i],o=t?{part_id:e.id,quantity:1,entry_id:t}:{part_id:e.id,quantity:1};return l`
- ${a!==void 0?l`{let p=d.target.value;this._consumesQtyText={...this._consumesQtyText,[i]:p};let _=parseFloat(p.replace(",","."));Number.isFinite(_)&&_>=Me[0]&&(this._consumesParts={...this._consumesParts,[i]:{...o,quantity:_}})}} - />`:h} + .value=${this._consumesQtyText[i]??String(n.quantity)} + @input=${d=>{let p=d.target.value;this._consumesQtyText={...this._consumesQtyText,[i]:p};let _=parseFloat(p.replace(",","."));Number.isFinite(_)&&_>=Fe[0]&&(this._consumesParts={...this._consumesParts,[i]:{...o,quantity:_}})}} + />`:u}
- `}_applyConsumesQtyText(){let e={...this._consumesParts};for(let t of Object.keys(e)){let i=this._consumesQtyText[t];if(i===void 0)continue;let a=parseFloat(i.replace(",","."));if(!Number.isFinite(a)||aMe[1]){let o=d=>C(d,this._lang,{maximumFractionDigits:2});return this._error=n("settings_value_out_of_range",this._lang).replace("{min}",o(Me[0])).replace("{max}",o(Me[1])),!1}e[t]={...e[t],quantity:a}}return this._consumesParts=e,!0}_toggleRequired(e,t){let i=new Set(this._requiredCompletion);t?i.add(e):i.delete(e),this._requiredCompletion=[...i]}_patchReading(e,t){this._readings=this._readings.map(i=>i.id===e?{...i,...t}:i)}_renderReadingsEditor(e){let t=Ns(this._readings);return l` + `}_applyConsumesQtyText(){let e={...this._consumesParts};for(let t of Object.keys(e)){let i=this._consumesQtyText[t];if(i===void 0)continue;let n=parseFloat(i.replace(",","."));if(!Number.isFinite(n)||nFe[1]){let o=d=>C(d,this._lang,{maximumFractionDigits:2});return this._error=a("settings_value_out_of_range",this._lang).replace("{min}",o(Fe[0])).replace("{max}",o(Fe[1])),!1}e[t]={...e[t],quantity:n}}return this._consumesParts=e,!0}_toggleRequired(e,t){let i=new Set(this._requiredCompletion);t?i.add(e):i.delete(e),this._requiredCompletion=[...i]}_patchReading(e,t){this._readings=this._readings.map(i=>i.id===e?{...i,...t}:i)}_renderReadingsEditor(e){let t=Js(this._readings);return l`
-
${n("readings_section",e)}
-
${n("readings_hint",e)}
+
${a("readings_section",e)}
+
${a("readings_hint",e)}
${this._readings.map(i=>l` - ${t.has(i.id)?l`
${n("reading_duplicate_name",e)}
`:h} + ${t.has(i.id)?l`
${a("reading_duplicate_name",e)}
`:u}
this._patchReading(i.id,{name:a.target.value})} + @input=${n=>this._patchReading(i.id,{name:n.target.value})} > this._patchReading(i.id,{unit:a.target.value})} + @input=${n=>this._patchReading(i.id,{unit:n.target.value})} > - this._readings=this._readings.filter(a=>a.id!==i.id)}> + this._readings=this._readings.filter(n=>n.id!==i.id)}>
`)} - ${this._readings.lengththis._readings=[...this._readings,{id:Cs(),name:"",unit:this._readings.length?this._readings[this._readings.length-1].unit:this._readingUnit}]}> - ${n("reading_add",e)} - `:h} + @click=${()=>this._readings=[...this._readings,{id:Gs(),name:"",unit:this._readings.length?this._readings[this._readings.length-1].unit:this._readingUnit}]}> + ${a("reading_add",e)} + `:u}
- `}_phaseSlug(e){let t=e.toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,24)||"phase",i=t,a=2;for(;this._phaseDefs.some(o=>o.id===i);)i=`${t}-${a++}`;return i}_addPhaseDef(){let e=this._phaseSlug(`phase-${this._phaseDefs.length+1}`);this._phaseDefs=[...this._phaseDefs,{id:e,name:"",checklistText:"",partId:"",partQty:"",reqOverride:!1,reqFields:[],extraParts:[],carry:{}}]}_removePhaseDef(e){this._phaseDefs=this._phaseDefs.filter(t=>t.id!==e),this._phaseSeq=this._phaseSeq.filter(t=>t!==e)}_patchPhaseDef(e,t){this._phaseDefs=this._phaseDefs.map(i=>i.id===e?{...i,...t}:i)}_renderPhasesEditor(e){let t=i=>this._phaseDefs.find(a=>a.id===i)?.name||i;return l` -

${n("phases_section",e)}

-
${n("phases_hint",e)}
+ `}_phaseSlug(e){let t=e.toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,24)||"phase",i=t,n=2;for(;this._phaseDefs.some(o=>o.id===i);)i=`${t}-${n++}`;return i}_addPhaseDef(){let e=this._phaseSlug(`phase-${this._phaseDefs.length+1}`);this._phaseDefs=[...this._phaseDefs,{id:e,name:"",checklistText:"",partId:"",partQty:"",reqOverride:!1,reqFields:[],extraParts:[],carry:{}}]}_removePhaseDef(e){this._phaseDefs=this._phaseDefs.filter(t=>t.id!==e),this._phaseSeq=this._phaseSeq.filter(t=>t!==e)}_patchPhaseDef(e,t){this._phaseDefs=this._phaseDefs.map(i=>i.id===e?{...i,...t}:i)}_renderPhasesEditor(e){let t=i=>this._phaseDefs.find(n=>n.id===i)?.name||i;return l` +

${a("phases_section",e)}

+
${a("phases_hint",e)}
${this._phaseDefs.map(i=>l`
this._patchPhaseDef(i.id,{name:a.target.value})} + @input=${n=>this._patchPhaseDef(i.id,{name:n.target.value})} > ${this.parts.length?l` ${i.partId?l` this._patchPhaseDef(i.id,{partQty:a.target.value})} /> - `:h} - `:h} + @input=${n=>this._patchPhaseDef(i.id,{partQty:n.target.value})} /> + `:u} + `:u} this._removePhaseDef(i.id)}> @@ -1895,74 +1912,74 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" - `:h} + `:u} ${i.reqOverride?l`
- ${Qi.map(a=>l` + ${ar.map(n=>l` `)}
- `:h} + `:u}
`)} - ${n("phase_add",e)} + ${a("phase_add",e)} ${this._phaseDefs.some(i=>i.name.trim())?l` -
${n("phase_sequence_label",e)}
+
${a("phase_sequence_label",e)}
- ${this._phaseSeq.map((i,a)=>l` + ${this._phaseSeq.map((i,n)=>l` - ${a+1}. ${t(i)} - + ${n+1}. ${t(i)} + `)}
- `:h} - `}async _save(){if(!this._loading&&this._name.trim()){if(this._adaptiveSnapshot()!==this._adaptiveInitial){let e=parseInt(this._adaptiveMin,10),t=parseInt(this._adaptiveMax,10);if(!isNaN(e)&&!isNaN(t)&&e>t){this._error=`${n("adaptive_min_interval",this._lang)} > ${n("adaptive_max_interval",this._lang)}`;return}}if(this._triggerType==="threshold"&&this._thresholdLimitsOverlap()){this._error=n("trigger_hint_overlap",this._lang);return}if(this._scheduleType==="calendar"&&!this._calendarEntity.trim().startsWith("calendar.")){this._error=n("calendar_entity_required",this._lang);return}if(this._applyConsumesQtyText()){this._loading=!0,this._error="";try{let e=await j(this,()=>this.hass.connection.sendMessagePromise(this._savePayload()),{fallbackKey:"save_error",onError:o=>{this._error=o}});if(e===void 0)return;let t=this._taskId||e?.task_id,i=this._environmentalEntity!==this._environmentalInitial||this._environmentalAttribute!==this._environmentalAttributeInitial;this._warning="";let a=o=>{this._warning=n("subsave_warning",this._lang).replace("{detail}",o)};if(t&&this._scheduleType==="sensor_based"&&i&&await j(this,{type:"maintenance_supporter/task/set_environmental_entity",entry_id:this._entryId,task_id:t,environmental_entity:this._environmentalEntity||null,environmental_attribute:this._environmentalAttribute||null},{onError:a})!==void 0&&(this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute),t&&this._adaptiveSnapshot()!==this._adaptiveInitial){let o=parseFloat(this._adaptiveAlpha),d=parseInt(this._adaptiveMin,10),p=parseInt(this._adaptiveMax,10);await j(this,{type:"maintenance_supporter/task/set_adaptive",entry_id:this._entryId,task_id:t,enabled:this._adaptiveEnabled,...o>=$t[0]&&o<=$t[1]?{ewa_alpha:o}:{},...!isNaN(d)&&d>=1?{min_interval_days:d}:{},...!isNaN(p)&&p>=1?{max_interval_days:p}:{},seasonal_enabled:this._adaptiveSeasonal,sensor_prediction_enabled:this._adaptivePrediction},{onError:a})!==void 0&&(this._adaptiveInitial=this._adaptiveSnapshot())}this._warning?t&&(this._taskId=t):this._open=!1,this.dispatchEvent(new CustomEvent("task-saved"))}finally{this._loading=!1}}}}_savePayload(){let e={type:this._taskId?"maintenance_supporter/task/update":"maintenance_supporter/task/create",entry_id:this._entryId,name:this._name,task_type:this._type,schedule_type:this._scheduleType,warning_days:Number.isNaN(parseInt(this._warningDays,10))?this.defaultWarningDays:Math.max(0,parseInt(this._warningDays,10))},t=this._earliestCompletionDays.trim();e.earliest_completion_days=t===""?null:Math.max(0,parseInt(t,10)||0),this._taskId&&(e.task_id=this._taskId),this._scheduleType==="one_time"?(e.due_date=this._dueDate||null,e.interval_days=null):li.includes(this._scheduleType)?(e.schedule={...this._buildSchedule(),...this._recurrenceExtras()},e.interval_days=null,this._taskId&&(e.due_date=null)):(this._taskId&&(e.due_date=null),this._scheduleType!=="manual"&&this._intervalDays?(e.interval_days=parseInt(this._intervalDays,10),e.interval_unit=this._intervalUnit,e.interval_anchor=this._intervalAnchor,this._scheduleType==="time_based"&&(e.schedule={kind:"interval",...this._recurrenceExtras()})):this._taskId&&(e.interval_days=null,e.interval_anchor="completion")),e.notes=this._notes||null,e.documentation_url=this._documentationUrl||null,e.custom_icon=this._customIcon||null,e.notify_icon=this._notifyIcon.trim()||null,e.priority=this._priority,e.labels=this._labels.split(",").map(i=>i.trim()).filter(Boolean),e.mirror_todo_entities=this._mirrorTodoEntities.filter(Boolean),e.enabled=this._enabled,(!this._taskId||this._lastPerformed!==this._loadedLastPerformed)&&(e.last_performed=this._lastPerformed||null),e.nfc_tag_id=this._nfcTagId||null,e.require_tag_scan=this._requireTagScan,e.allow_skip=this._allowSkip,e.notify_enabled=this._notifyEnabled,e.reading_unit=this._readingUnit.trim()||null,e.readings=qs(this._readings);{let i={};for(let o of this._phaseDefs){if(!o.name.trim())continue;let d={...o.carry,name:o.name.trim()},p=o.checklistText.split(` -`).map(m=>m.trim()).filter(Boolean);p.length&&(d.checklist=p);let _=[];if(o.partId){let m=parseFloat(o.partQty);_.push({part_id:o.partId,quantity:Number.isFinite(m)&&m>0?m:1})}for(let m of o.extraParts)_.push(m.entry_id?{part_id:m.part_id,quantity:m.quantity,entry_id:m.entry_id}:{part_id:m.part_id,quantity:m.quantity});_.length&&(d.consumes_parts=_),o.reqOverride&&(d.required_completion_fields=[...o.reqFields]),i[o.id]=d}let a=this._phaseSeq.filter(o=>o in i);e.phases=Object.keys(i).length&&a.length?i:null,e.phase_sequence=e.phases?a:null}if((this.parts.length||this._foreignOwners.length)&&(e.consumes_parts=Object.values(this._consumesParts).map(i=>i.entry_id?{part_id:i.part_id,quantity:i.quantity,entry_id:i.entry_id}:{part_id:i.part_id,quantity:i.quantity})),(!this._taskId||this._responsibleUserId!==this._loadedResponsibleUserId)&&(e.responsible_user_id=this._responsibleUserId),e.assignee_pool=this._assigneePool,e.required_completion_fields=this._requiredCompletion,e.rotation_strategy=this._assigneePool.length>=2&&this._rotationStrategy?this._rotationStrategy:null,this._scheduleType==="sensor_based"&&this._triggerType==="compound"){let i=this._compoundConditions.map($o).filter(a=>a!==null);if(i.length>0){let a={type:"compound",compound_logic:this._compoundLogic,conditions:i};this._autoCompleteOnRecovery&&(a.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(a.trigger_combinator="all"),e.trigger_config=a}else this._taskId&&(e.trigger_config=null)}else if(this._scheduleType==="sensor_based"&&this._triggerEntityId){let i=this._triggerEntityIds.length>0?this._triggerEntityIds:[this._triggerEntityId],a={entity_id:i[0],entity_ids:i,type:this._triggerType};if(hn(a,this._typeFields()),this._autoCompleteOnRecovery&&(a.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(a.trigger_combinator="all"),i.length>1&&(a.entity_logic=this._triggerEntityLogic),this._triggerType==="counter"&&this._triggerDeltaMode&&this._triggerBaselineValue){let o=parseFloat(this._triggerBaselineValue);!isNaN(o)&&o>=0&&(a.trigger_baseline_value=o)}else if(this._triggerType==="runtime"&&this._triggerRuntimeMaxSession){let o=parseInt(this._triggerRuntimeMaxSession,10);!isNaN(o)&&o>0&&(a.trigger_runtime_max_session_seconds=o)}e.trigger_config=a}else this._taskId&&(e.trigger_config=null);if(this.scheduleTimeEnabled&&ln.includes(this._scheduleType)){let i=this._scheduleTimeOn?this._scheduleTime.trim():"";e.schedule_time=/^([01]\d|2[0-3]):[0-5]\d$/.test(i)?i:null}if(this.checklistsEnabled){let i=this._checklistText.split(` -`).map(a=>a.trim()).filter(Boolean).slice(0,100);e.checklist=i.length?i:null}if(this.completionActionsEnabled||this._actionPresent){let i=this._actionService.trim();if(i&&/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(i)){let a={service:i},o=this._actionTargetEntity.trim();this._actionTargetStored&&o===this._actionTargetInitial?a.target=JSON.parse(JSON.stringify(this._actionTargetStored)):o&&(a.target={entity_id:o});let d=this._buildActionData();Object.keys(d).length>0&&(a.data=d),this._actionSkipAuto&&(a.skip_auto=!0),e.on_complete_action=a}else e.on_complete_action=null}if(this.completionActionsEnabled){let i={};this._qcNotes.trim()&&(i.notes=this._qcNotes.trim());let a=parseFloat(this._qcCost);isNaN(a)||(i.cost=a);let o=et(this._qcDuration);o!==null&&(i.duration=o),this._qcFeedback&&(i.feedback=this._qcFeedback),e.quick_complete_defaults=Object.keys(i).length?i:null}return e}_close(){this._open=!1,this._warning="",this._pickerProbeTimer!==void 0&&(clearTimeout(this._pickerProbeTimer),this._pickerProbeTimer=void 0),this._pickerProbeStrikes=0}_renderTriggerFields(){if(this._scheduleType!=="sensor_based")return h;let e=this._lang,t=this._triggerType==="compound";return l` -

${n("trigger_configuration",e)}

+ `:u} + `}async _save(){if(!this._loading&&this._name.trim()){if(this._adaptiveSnapshot()!==this._adaptiveInitial){let e=parseInt(this._adaptiveMin,10),t=parseInt(this._adaptiveMax,10);if(!isNaN(e)&&!isNaN(t)&&e>t){this._error=`${a("adaptive_min_interval",this._lang)} > ${a("adaptive_max_interval",this._lang)}`;return}}if(this._triggerType==="threshold"&&this._thresholdLimitsOverlap()){this._error=a("trigger_hint_overlap",this._lang);return}if(this._scheduleType==="calendar"&&!this._calendarEntity.trim().startsWith("calendar.")){this._error=a("calendar_entity_required",this._lang);return}if(this._applyConsumesQtyText()){this._loading=!0,this._error="";try{let e=await D(this,()=>this.hass.connection.sendMessagePromise(this._savePayload()),{fallbackKey:"save_error",onError:o=>{this._error=o}});if(e===void 0)return;let t=this._taskId||e?.task_id,i=this._environmentalEntity!==this._environmentalInitial||this._environmentalAttribute!==this._environmentalAttributeInitial;this._warning="";let n=o=>{this._warning=a("subsave_warning",this._lang).replace("{detail}",o)};if(t&&this._scheduleType==="sensor_based"&&i&&await D(this,{type:"maintenance_supporter/task/set_environmental_entity",entry_id:this._entryId,task_id:t,environmental_entity:this._environmentalEntity||null,environmental_attribute:this._environmentalAttribute||null},{onError:n})!==void 0&&(this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute),t&&this._adaptiveSnapshot()!==this._adaptiveInitial){let o=parseFloat(this._adaptiveAlpha),d=parseInt(this._adaptiveMin,10),p=parseInt(this._adaptiveMax,10);await D(this,{type:"maintenance_supporter/task/set_adaptive",entry_id:this._entryId,task_id:t,enabled:this._adaptiveEnabled,...o>=Et[0]&&o<=Et[1]?{ewa_alpha:o}:{},...!isNaN(d)&&d>=1?{min_interval_days:d}:{},...!isNaN(p)&&p>=1?{max_interval_days:p}:{},seasonal_enabled:this._adaptiveSeasonal,sensor_prediction_enabled:this._adaptivePrediction},{onError:n})!==void 0&&(this._adaptiveInitial=this._adaptiveSnapshot())}this._warning?t&&(this._taskId=t):this._open=!1,this.dispatchEvent(new CustomEvent("task-saved"))}finally{this._loading=!1}}}}_savePayload(){let e={type:this._taskId?"maintenance_supporter/task/update":"maintenance_supporter/task/create",entry_id:this._entryId,name:this._name,task_type:this._type,schedule_type:this._scheduleType,warning_days:Number.isNaN(parseInt(this._warningDays,10))?this.defaultWarningDays:Math.max(0,parseInt(this._warningDays,10))},t=this._earliestCompletionDays.trim();e.earliest_completion_days=t===""?null:Math.max(0,parseInt(t,10)||0),this._taskId&&(e.task_id=this._taskId),this._scheduleType==="one_time"?(e.due_date=this._dueDate||null,e.interval_days=null):_i.includes(this._scheduleType)?(e.schedule={...this._buildSchedule(),...this._recurrenceExtras()},e.interval_days=null,this._taskId&&(e.due_date=null)):(this._taskId&&(e.due_date=null),this._scheduleType!=="manual"&&this._intervalDays?(e.interval_days=parseInt(this._intervalDays,10),e.interval_unit=this._intervalUnit,e.interval_anchor=this._intervalAnchor,this._scheduleType==="time_based"&&(e.schedule={kind:"interval",...this._recurrenceExtras()})):this._taskId&&(e.interval_days=null,e.interval_anchor="completion")),e.notes=this._notes||null,e.documentation_url=this._documentationUrl||null,e.custom_icon=this._customIcon||null,e.notify_icon=this._notifyIcon.trim()||null,e.priority=this._priority,e.labels=this._labels.split(",").map(i=>i.trim()).filter(Boolean),e.mirror_todo_entities=this._mirrorTodoEntities.filter(Boolean),e.enabled=this._enabled,(!this._taskId||this._lastPerformed!==this._loadedLastPerformed)&&(e.last_performed=this._lastPerformed||null),e.nfc_tag_id=this._nfcTagId||null,e.require_tag_scan=this._requireTagScan,e.allow_skip=this._allowSkip,e.notify_enabled=this._notifyEnabled,e.reading_unit=this._readingUnit.trim()||null,e.readings=Xs(this._readings);{let i={};for(let o of this._phaseDefs){if(!o.name.trim())continue;let d={...o.carry,name:o.name.trim()},p=o.checklistText.split(` +`).map(m=>m.trim()).filter(Boolean);p.length&&(d.checklist=p);let _=[];if(o.partId){let m=parseFloat(o.partQty);_.push({part_id:o.partId,quantity:Number.isFinite(m)&&m>0?m:1})}for(let m of o.extraParts)_.push(m.entry_id?{part_id:m.part_id,quantity:m.quantity,entry_id:m.entry_id}:{part_id:m.part_id,quantity:m.quantity});_.length&&(d.consumes_parts=_),o.reqOverride&&(d.required_completion_fields=[...o.reqFields]),i[o.id]=d}let n=this._phaseSeq.filter(o=>o in i);e.phases=Object.keys(i).length&&n.length?i:null,e.phase_sequence=e.phases?n:null}if((this.parts.length||this._foreignOwners.length)&&(e.consumes_parts=Object.values(this._consumesParts).map(i=>i.entry_id?{part_id:i.part_id,quantity:i.quantity,entry_id:i.entry_id}:{part_id:i.part_id,quantity:i.quantity})),(!this._taskId||this._responsibleUserId!==this._loadedResponsibleUserId)&&(e.responsible_user_id=this._responsibleUserId),e.assignee_pool=this._assigneePool,e.required_completion_fields=this._requiredCompletion,e.rotation_strategy=this._assigneePool.length>=2&&this._rotationStrategy?this._rotationStrategy:null,this._scheduleType==="sensor_based"&&this._triggerType==="compound"){let i=this._compoundConditions.map(Yo).filter(n=>n!==null);if(i.length>0){let n={type:"compound",compound_logic:this._compoundLogic,conditions:i};this._autoCompleteOnRecovery&&(n.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(n.trigger_combinator="all"),e.trigger_config=n}else this._taskId&&(e.trigger_config=null)}else if(this._scheduleType==="sensor_based"&&this._triggerEntityId){let i=this._triggerEntityIds.length>0?this._triggerEntityIds:[this._triggerEntityId],n={entity_id:i[0],entity_ids:i,type:this._triggerType};if(Rn(n,this._typeFields()),this._autoCompleteOnRecovery&&(n.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(n.trigger_combinator="all"),i.length>1&&(n.entity_logic=this._triggerEntityLogic),this._triggerType==="counter"&&this._triggerDeltaMode&&this._triggerBaselineValue){let o=parseFloat(this._triggerBaselineValue);!isNaN(o)&&o>=0&&(n.trigger_baseline_value=o)}else if(this._triggerType==="runtime"&&this._triggerRuntimeMaxSession){let o=parseInt(this._triggerRuntimeMaxSession,10);!isNaN(o)&&o>0&&(n.trigger_runtime_max_session_seconds=o)}e.trigger_config=n}else this._taskId&&(e.trigger_config=null);if(this.scheduleTimeEnabled&&Sn.includes(this._scheduleType)){let i=this._scheduleTimeOn?this._scheduleTime.trim():"";e.schedule_time=/^([01]\d|2[0-3]):[0-5]\d$/.test(i)?i:null}if(this.checklistsEnabled){let i=this._checklistText.split(` +`).map(n=>n.trim()).filter(Boolean).slice(0,100);e.checklist=i.length?i:null}if(this.completionActionsEnabled||this._actionPresent){let i=this._actionService.trim();if(i&&/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(i)){let n={service:i},o=this._actionTargetEntity.trim();this._actionTargetStored&&o===this._actionTargetInitial?n.target=JSON.parse(JSON.stringify(this._actionTargetStored)):o&&(n.target={entity_id:o});let d=this._buildActionData();Object.keys(d).length>0&&(n.data=d),this._actionSkipAuto&&(n.skip_auto=!0),e.on_complete_action=n}else e.on_complete_action=null}if(this.completionActionsEnabled){let i={};this._qcNotes.trim()&&(i.notes=this._qcNotes.trim());let n=parseFloat(this._qcCost);isNaN(n)||(i.cost=n);let o=it(this._qcDuration);o!==null&&(i.duration=o),this._qcFeedback&&(i.feedback=this._qcFeedback),e.quick_complete_defaults=Object.keys(i).length?i:null}return e}_close(){this._open=!1,this._warning="",this._pickerProbeTimer!==void 0&&(clearTimeout(this._pickerProbeTimer),this._pickerProbeTimer=void 0),this._pickerProbeStrikes=0}_renderTriggerFields(){if(this._scheduleType!=="sensor_based")return u;let e=this._lang,t=this._triggerType==="compound";return l` +

${a("trigger_configuration",e)}

- +
${t?this._renderCompoundEditor():l` ${this._entityPickerFallback?l` 0?this._triggerEntityIds.join(", "):this._triggerEntityId} @input=${i=>{let o=i.target.value.split(",").map(d=>d.trim()).filter(Boolean);this._triggerEntityId=o[0]||"",this._triggerEntityIds=o,o[0]&&this._fetchEntityAttributes(o[0])}} > @@ -1970,24 +1987,24 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" 0?this._triggerEntityIds:this._triggerEntityId?[this._triggerEntityId]:[]}} - .computeLabel=${()=>n("entity_id",e)} - @value-changed=${i=>{let a=(i.detail.value.trigger_entities||[]).filter(Boolean);this._triggerEntityId=a[0]||"",this._triggerEntityIds=a,a[0]?this._fetchEntityAttributes(a[0]):this._fetchEntityAttributes("")}} + .computeLabel=${()=>a("entity_id",e)} + @value-changed=${i=>{let n=(i.detail.value.trigger_entities||[]).filter(Boolean);this._triggerEntityId=n[0]||"",this._triggerEntityIds=n,n[0]?this._fetchEntityAttributes(n[0]):this._fetchEntityAttributes("")}} >`} ${this._triggerEntityIds.length>1?l`
- +
- `:h} - ${this._renderAttributeSelect({label:n("attribute_optional",e),value:this._triggerAttribute,suggested:this._suggestedAttributes,available:this._availableAttributes,onSelect:i=>this._triggerAttribute=i})} + `:u} + ${this._renderAttributeSelect({label:a("attribute_optional",e),value:this._triggerAttribute,suggested:this._suggestedAttributes,available:this._availableAttributes,onSelect:i=>this._triggerAttribute=i})} ${this._renderTriggerTypeFields()} ${this._renderTriggerLiveHint()} `} @@ -1997,57 +2014,57 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .checked=${this._autoCompleteOnRecovery} @change=${i=>this._autoCompleteOnRecovery=i.target.checked} /> - ${n("auto_complete_on_recovery",e)} + ${a("auto_complete_on_recovery",e)} -
${n("auto_complete_on_recovery_help",e)}
+
${a("auto_complete_on_recovery_help",e)}
this._intervalDays=i.target.value} > - ${this._intervalDays?this._renderUnitSelect():h} + ${this._intervalDays?this._renderUnitSelect():u} ${this._intervalDays?l`
- +
- `:h} - `}_patchCondition(e,t){this._compoundConditions=this._compoundConditions.map((i,a)=>a===e?{...i,...t}:i)}_addCondition(){this._compoundConditions=[...this._compoundConditions,dn()]}_removeCondition(e){this._compoundConditions=this._compoundConditions.filter((t,i)=>i!==e)}_renderCompoundEditor(){let e=this._lang;return l` + `:u} + `}_patchCondition(e,t){this._compoundConditions=this._compoundConditions.map((i,n)=>n===e?{...i,...t}:i)}_addCondition(){this._compoundConditions=[...this._compoundConditions,An()]}_removeCondition(e){this._compoundConditions=this._compoundConditions.filter((t,i)=>i!==e)}_renderCompoundEditor(){let e=this._lang;return l`
- +
-
${n("compound_help",e)}
- ${this._compoundConditions.length===0?l`
${n("compound_no_conditions",e)}
`:this._compoundConditions.map((t,i)=>this._renderCondition(t,i))} +
${a("compound_help",e)}
+ ${this._compoundConditions.length===0?l`
${a("compound_no_conditions",e)}
`:this._compoundConditions.map((t,i)=>this._renderCondition(t,i))} - `}_renderCondition(e,t){let i=this._lang,a=t+1;return l` + `}_renderCondition(e,t){let i=this._lang,n=t+1;return l`
- ${n("compound_condition",i)} ${a} + ${a("compound_condition",i)} ${n}
${this._entityPickerFallback?l` this._patchCondition(t,{entityIds:o.target.value})} > @@ -2055,19 +2072,19 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" o.trim()).filter(Boolean)}} - .computeLabel=${()=>n("entity_id",i)} + .computeLabel=${()=>a("entity_id",i)} @value-changed=${o=>{let d=(o.detail.value.condition_entities||[]).filter(Boolean);this._patchCondition(t,{entityIds:d.join(", ")})}} >`} ${this._renderConditionAttribute(e,t)}
- +
${this._renderConditionTypeFields(e,t)} @@ -2089,7 +2106,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" > `}_renderOnStatesField(e){let t=this._lang;return this._entityPickerFallback||!e.entityId?l` e.onInput(i.target.value)} @@ -2100,40 +2117,40 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .hass=${this.hass} .schema=${[{name:"s",selector:{state:{entity_id:e.entityId,multiple:!0}}}]} .data=${{s:(e.value||"").split(",").map(i=>i.trim()).filter(Boolean)}} - .computeLabel=${()=>n("runtime_on_states",t)} + .computeLabel=${()=>a("runtime_on_states",t)} @value-changed=${i=>e.onInput((i.detail.value.s||[]).join(", "))} > - `}_renderAdaptiveSection(e){return this._scheduleType==="one_time"||this._scheduleType==="manual"?h:!this.adaptiveFeature&&!this._adaptiveWasEnabled?h:l` + `}_renderAdaptiveSection(e){return this._scheduleType==="one_time"||this._scheduleType==="manual"?u:!this.adaptiveFeature&&!this._adaptiveWasEnabled?u:l`
- ${n("adaptive_section_title",e)} + ${a("adaptive_section_title",e)} ${this._adaptiveEnabled?l` this._adaptiveMin=t.target.value} > this._adaptiveMax=t.target.value} > this._adaptiveAlpha=t.target.value} @@ -2144,17 +2161,17 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .checked=${this._adaptiveSeasonal} @change=${t=>this._adaptiveSeasonal=t.target.checked} /> - ${n("adaptive_seasonal_enabled",e)} - `:h} + ${a("adaptive_seasonal_enabled",e)} + `:u} - `:h} + `:u}
`}_renderAttributeSelect(e){let t=this._lang;return e.available.length>0?l`
@@ -2163,7 +2180,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .value=${e.value} @change=${i=>e.onSelect(i.target.value)} > - + ${e.suggested.map(i=>l``)} ${e.available.filter(i=>!e.suggested.includes(i.name)).map(i=>l``)} @@ -2174,119 +2191,119 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .value=${e.value} @input=${i=>e.onSelect(i.target.value.trim())} > - `}_renderEnvironmentalAttribute(e){this._fetchConditionAttributes(this._environmentalEntity);let t=this._conditionAttrOptions[this._environmentalEntity];return this._renderAttributeSelect({label:n("environmental_attribute_optional",e),value:this._environmentalAttribute,suggested:t?.suggested??[],available:t?.available??[],onSelect:i=>this._environmentalAttribute=i})}_renderConditionAttribute(e,t){let i=e.entityIds.split(",")[0]?.trim()||"";i&&this._fetchConditionAttributes(i);let a=i?this._conditionAttrOptions[i]:void 0;return this._renderAttributeSelect({label:n("attribute_optional",this._lang),value:e.attribute,suggested:a?.suggested??[],available:a?.available??[],onSelect:o=>this._patchCondition(t,{attribute:o})})}_renderConditionTypeFields(e,t){let i=this._lang;if(e.type==="threshold")return l` - this._patchCondition(t,{above:a.target.value})}> - this._patchCondition(t,{below:a.target.value})}> - this._patchCondition(t,{equals:a.target.value})}> - this._patchCondition(t,{notEquals:a.target.value})}> - this._patchCondition(t,{forMinutes:a.target.value})}> + `}_renderEnvironmentalAttribute(e){this._fetchConditionAttributes(this._environmentalEntity);let t=this._conditionAttrOptions[this._environmentalEntity];return this._renderAttributeSelect({label:a("environmental_attribute_optional",e),value:this._environmentalAttribute,suggested:t?.suggested??[],available:t?.available??[],onSelect:i=>this._environmentalAttribute=i})}_renderConditionAttribute(e,t){let i=e.entityIds.split(",")[0]?.trim()||"";i&&this._fetchConditionAttributes(i);let n=i?this._conditionAttrOptions[i]:void 0;return this._renderAttributeSelect({label:a("attribute_optional",this._lang),value:e.attribute,suggested:n?.suggested??[],available:n?.available??[],onSelect:o=>this._patchCondition(t,{attribute:o})})}_renderConditionTypeFields(e,t){let i=this._lang;if(e.type==="threshold")return l` + this._patchCondition(t,{above:n.target.value})}> + this._patchCondition(t,{below:n.target.value})}> + this._patchCondition(t,{equals:n.target.value})}> + this._patchCondition(t,{notEquals:n.target.value})}> + this._patchCondition(t,{forMinutes:n.target.value})}> `;if(e.type==="counter")return l` - this._patchCondition(t,{targetValue:a.target.value})}> + this._patchCondition(t,{targetValue:n.target.value})}> - `;if(e.type==="state_change"){let a=e.entityIds.split(",")[0]?.trim()||"";return l` - ${this._renderStateField({label:n("from_state_optional",i),value:e.fromState,entityId:a,onInput:o=>this._patchCondition(t,{fromState:o})})} - ${this._renderStateField({label:n("to_state_optional",i),value:e.toState,entityId:a,onInput:o=>this._patchCondition(t,{toState:o})})} - this._patchCondition(t,{fromState:o})})} + ${this._renderStateField({label:a("to_state_optional",i),value:e.toState,entityId:n,onInput:o=>this._patchCondition(t,{toState:o})})} + this._patchCondition(t,{targetChanges:o.target.value})}> - this._patchCondition(t,{forMinutes:o.target.value})}> - `}if(e.type==="runtime"){let a=e.entityIds.split(",")[0]?.trim()||"";return l` - this._patchCondition(t,{runtimeHours:o.target.value})}> - ${this._renderOnStatesField({value:e.onStates,entityId:a,onInput:o=>this._patchCondition(t,{onStates:o})})} + ${this._renderOnStatesField({value:e.onStates,entityId:n,onInput:o=>this._patchCondition(t,{onStates:o})})} `}return e.type==="due_date"?l` - this._patchCondition(t,{daysBefore:a.target.value})}> - `:h}_renderUnitSelect(){let e=this._lang;return l` + this._patchCondition(t,{daysBefore:n.target.value})}> + `:u}_renderUnitSelect(){let e=this._lang;return l`
- + -
`}_toggleWeekday(e){this._weekdays=this._weekdays.includes(e)?this._weekdays.filter(t=>t!==e):[...this._weekdays,e]}_previewScheduleDict(){if(this._scheduleType==="one_time")return this._dueDate?{kind:"one_time",due_date:this._dueDate}:null;if(this._scheduleType==="calendar"&&!this._calendarEntity.trim())return null;if(li.includes(this._scheduleType))return{...this._buildSchedule(),...this._recurrenceExtras()};let e=parseInt(this._intervalDays,10);return this._scheduleType==="manual"||!e||e<=0?null:{kind:"interval",every:e,unit:this._intervalUnit,anchor:this._intervalAnchor,...this._recurrenceExtras()}}updated(e){super.updated?.(e),this._scheduleEntityPickerProbe();for(let t of e.keys())if(g._PREVIEW_RELEVANT.has(String(t))){this._schedulePreviewRefresh();return}}_scheduleEntityPickerProbe(){this._entityPickerFallback||this._pickerProbeTimer!==void 0||!this._open||this._scheduleType!=="sensor_based"||(this._pickerProbeTimer=setTimeout(()=>this._probeEntityPickers(),1500))}_probeEntityPickers(){if(this._pickerProbeTimer=void 0,this._entityPickerFallback||!this._open)return;let e=this.shadowRoot?.querySelector("ha-form.entity-picker-form"),t=(this.shadowRoot?.querySelector(".content")?.offsetHeight??0)>0;if(!e||!t){this._pickerProbeStrikes=0;return}let i=(p,_,m=0)=>{if(!(!p||m>10)){(p.tagName?.toLowerCase()??"")==="ha-entity-picker"&&_.push(p);for(let f of[p.shadowRoot,p])if(f)for(let x of Array.from(f.children??[]))i(x,_,m+1)}},a=[...this.shadowRoot?.querySelectorAll("ha-form.entity-picker-form")??[]],o=[];for(let p of a)i(p,o);let d=o.length===0||o.some(p=>p.offsetHeight===0);if(e.offsetHeight===0||d){if(this._pickerProbeStrikes+=1,this._pickerProbeStrikes>=2){this._entityPickerFallback=!0;return}this._pickerProbeTimer=setTimeout(()=>this._probeEntityPickers(),700)}else this._pickerProbeStrikes=0}_schedulePreviewRefresh(){this._previewTimer&&clearTimeout(this._previewTimer),this._previewTimer=setTimeout(()=>{this._fetchSchedulePreview()},300)}async _fetchSchedulePreview(){let e=this._open?this._previewScheduleDict():null;if(!e){this._schedulePreview=[],this._schedulePreviewEnded=!1;return}let t=++this._previewSeq;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/schedule/preview",schedule:e,...this._lastPerformed?{last_performed:this._lastPerformed}:{}});if(t!==this._previewSeq)return;this._schedulePreview=i.occurrences||[],this._schedulePreviewEnded=!!i.series_ended}catch{}}_renderSchedulePreview(){if(this._schedulePreview.length===0)return h;let e=this._lang,t=this.scheduleTimeEnabled&&this._scheduleTimeOn&&this._scheduleTime?` ${this._scheduleTime}`:"",i=this._schedulePreview.map((o,d)=>{let p=new Date(`${o}T12:00:00`).getDay();return`${Ke(p===0?6:p-1,e,"short")} ${O(o,e)}${d===0?t:""}`}).join(" \xB7 "),a=this._scheduleType==="time_based"&&this._intervalAnchor==="completion"?l`
${n("schedule_preview_ontime",e)}
`:h;return l` +
`}_toggleWeekday(e){this._weekdays=this._weekdays.includes(e)?this._weekdays.filter(t=>t!==e):[...this._weekdays,e]}_previewScheduleDict(){if(this._scheduleType==="one_time")return this._dueDate?{kind:"one_time",due_date:this._dueDate}:null;if(this._scheduleType==="calendar"&&!this._calendarEntity.trim())return null;if(_i.includes(this._scheduleType))return{...this._buildSchedule(),...this._recurrenceExtras()};let e=parseInt(this._intervalDays,10);return this._scheduleType==="manual"||!e||e<=0?null:{kind:"interval",every:e,unit:this._intervalUnit,anchor:this._intervalAnchor,...this._recurrenceExtras()}}updated(e){super.updated?.(e),this._scheduleEntityPickerProbe();for(let t of e.keys())if(g._PREVIEW_RELEVANT.has(String(t))){this._schedulePreviewRefresh();return}}_scheduleEntityPickerProbe(){this._entityPickerFallback||this._pickerProbeTimer!==void 0||!this._open||this._scheduleType!=="sensor_based"||(this._pickerProbeTimer=setTimeout(()=>this._probeEntityPickers(),1500))}_probeEntityPickers(){if(this._pickerProbeTimer=void 0,this._entityPickerFallback||!this._open)return;let e=this.shadowRoot?.querySelector("ha-form.entity-picker-form"),t=(this.shadowRoot?.querySelector(".content")?.offsetHeight??0)>0;if(!e||!t){this._pickerProbeStrikes=0;return}let i=(p,_,m=0)=>{if(!(!p||m>10)){(p.tagName?.toLowerCase()??"")==="ha-entity-picker"&&_.push(p);for(let f of[p.shadowRoot,p])if(f)for(let x of Array.from(f.children??[]))i(x,_,m+1)}},n=[...this.shadowRoot?.querySelectorAll("ha-form.entity-picker-form")??[]],o=[];for(let p of n)i(p,o);let d=o.length===0||o.some(p=>p.offsetHeight===0);if(e.offsetHeight===0||d){if(this._pickerProbeStrikes+=1,this._pickerProbeStrikes>=2){this._entityPickerFallback=!0;return}this._pickerProbeTimer=setTimeout(()=>this._probeEntityPickers(),700)}else this._pickerProbeStrikes=0}_schedulePreviewRefresh(){this._previewTimer&&clearTimeout(this._previewTimer),this._previewTimer=setTimeout(()=>{this._fetchSchedulePreview()},300)}async _fetchSchedulePreview(){let e=this._open?this._previewScheduleDict():null;if(!e){this._schedulePreview=[],this._schedulePreviewEnded=!1;return}let t=++this._previewSeq;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/schedule/preview",schedule:e,...this._lastPerformed?{last_performed:this._lastPerformed}:{}});if(t!==this._previewSeq)return;this._schedulePreview=i.occurrences||[],this._schedulePreviewEnded=!!i.series_ended}catch{}}_renderSchedulePreview(){if(this._schedulePreview.length===0)return u;let e=this._lang,t=this.scheduleTimeEnabled&&this._scheduleTimeOn&&this._scheduleTime?` ${this._scheduleTime}`:"",i=this._schedulePreview.map((o,d)=>{let p=new Date(`${o}T12:00:00`).getDay();return`${Qe(p===0?6:p-1,e,"short")} ${O(o,e)}${d===0?t:""}`}).join(" \xB7 "),n=this._scheduleType==="time_based"&&this._intervalAnchor==="completion"?l`
${a("schedule_preview_ontime",e)}
`:u;return l`
- ${n("schedule_preview_title",e)}: ${i}${this._schedulePreviewEnded?l` ${n("schedule_preview_ends",e)}`:h} - ${a} + ${a("schedule_preview_title",e)}: ${i}${this._schedulePreviewEnded?l` ${a("schedule_preview_ends",e)}`:u} + ${n}
- `}_buildSchedule(){let e=i=>{let a=parseInt(this._calOffset,10)||0;return a&&(i.offset=Math.max(-kt,Math.min(a,kt))),i};if(this._scheduleType==="weekdays")return e({kind:"weekdays",weekdays:[...this._weekdays].sort((i,a)=>i-a)});if(this._scheduleType==="nth_weekday")return e({kind:"nth_weekday",nth:parseInt(this._nth,10),weekday:parseInt(this._nthWeekday,10)});if(this._scheduleType==="calendar")return e({kind:"calendar",entity_id:this._calendarEntity.trim()});let t={kind:"day_of_month",day:this._domLastDay?-1:parseInt(this._domDay,10)||1};return this._domBusiness&&(t.business=!0),e(t)}_recurrenceExtras(){let e={};if(this._seasonMonths.length&&(e.season_months=[...this._seasonMonths].sort((t,i)=>t-i)),this._endsMode==="count"){let t=parseInt(this._endsCount,10);t>=1&&(e.ends={count:t})}else this._endsMode==="until"&&this._endsUntil&&(e.ends={until:this._endsUntil});return e}_toggleSeasonMonth(e){this._seasonMonths=this._seasonMonths.includes(e)?this._seasonMonths.filter(t=>t!==e):[...this._seasonMonths,e]}_renderRecurrenceExtras(){let e=this._lang;if(!(this._scheduleType==="time_based"||li.includes(this._scheduleType)))return h;let i=So(e);return l` - -
${n("season_window_hint",e)}
+ `}_buildSchedule(){let e=i=>{let n=parseInt(this._calOffset,10)||0;return n&&(i.offset=Math.max(-$t,Math.min(n,$t))),i};if(this._scheduleType==="weekdays")return e({kind:"weekdays",weekdays:[...this._weekdays].sort((i,n)=>i-n)});if(this._scheduleType==="nth_weekday")return e({kind:"nth_weekday",nth:parseInt(this._nth,10),weekday:parseInt(this._nthWeekday,10)});if(this._scheduleType==="calendar")return e({kind:"calendar",entity_id:this._calendarEntity.trim()});let t={kind:"day_of_month",day:this._domLastDay?-1:parseInt(this._domDay,10)||1};return this._domBusiness&&(t.business=!0),e(t)}_recurrenceExtras(){let e={};if(this._seasonMonths.length&&(e.season_months=[...this._seasonMonths].sort((t,i)=>t-i)),this._endsMode==="count"){let t=parseInt(this._endsCount,10);t>=1&&(e.ends={count:t})}else this._endsMode==="until"&&this._endsUntil&&(e.ends={until:this._endsUntil});return e}_toggleSeasonMonth(e){this._seasonMonths=this._seasonMonths.includes(e)?this._seasonMonths.filter(t=>t!==e):[...this._seasonMonths,e]}_renderRecurrenceExtras(){let e=this._lang;if(!(this._scheduleType==="time_based"||_i.includes(this._scheduleType)))return u;let i=Zo(e);return l` + +
${a("season_window_hint",e)}
- ${i.map((a,o)=>l` + ${i.map((n,o)=>l` `)} + >${n}`)}
- +
${this._endsMode==="count"?l` this._endsCount=a.target.value} - >`:h} + @input=${n=>this._endsCount=n.target.value} + >
`:u} ${this._endsMode==="until"?l` this._endsUntil=a.detail.value} - >`:h} - `}_renderCalendarFields(){let e=this._lang,t=Eo(e);if(this._scheduleType==="weekdays")return l` - + @value-changed=${n=>this._endsUntil=n.detail.value} + >`:u} + `}_renderCalendarFields(){let e=this._lang,t=Qo(e);if(this._scheduleType==="weekdays")return l` +
- ${t.map((i,a)=>l` + ${t.map((i,n)=>l` `)}
- ${this._renderCalOffsetField()}`;if(this._scheduleType==="nth_weekday"){let i=[["1",n("ord_1",e)],["2",n("ord_2",e)],["3",n("ord_3",e)],["4",n("ord_4",e)],["5",n("ord_5",e)],["-1",n("ord_last",e)]];return l` + ${this._renderCalOffsetField()}`;if(this._scheduleType==="nth_weekday"){let i=[["1",a("ord_1",e)],["2",a("ord_2",e)],["3",a("ord_3",e)],["4",a("ord_4",e)],["5",a("ord_5",e)],["-1",a("ord_last",e)]];return l`
- - this._nth=n.target.value}> + ${i.map(([n,o])=>l``)}
- - this._nthWeekday=n.target.value}> + ${t.map((n,o)=>l``)}
${this._renderCalOffsetField()}`}return this._scheduleType==="calendar"?l` ${this._entityPickerFallback?l` this._calendarEntity=i.target.value.trim()} > @@ -2296,14 +2313,14 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .hass=${this.hass} .schema=${[{name:"calendar_entity",selector:{entity:{domain:"calendar"}}}]} .data=${{calendar_entity:this._calendarEntity}} - .computeLabel=${()=>n("calendar_entity_label",e)} - .computeHelper=${()=>n("calendar_entity_hint",e)} + .computeLabel=${()=>a("calendar_entity_label",e)} + .computeHelper=${()=>a("calendar_entity_hint",e)} @value-changed=${i=>{this._calendarEntity=(i.detail.value.calendar_entity||"").trim()}} >`} ${this._renderCalOffsetField()}`:this._scheduleType==="day_of_month"?l` - ${this._domLastDay?h:l` + ${this._domLastDay?u:l` this._domLastDay=i.target.checked} /> - ${n("recurrence_last_day",e)} + ${a("recurrence_last_day",e)} - ${this._renderCalOffsetField()}`:h}_renderCalOffsetField(){let e=this._lang;return l` + ${this._renderCalOffsetField()}`:u}_renderCalOffsetField(){let e=this._lang;return l` this._calOffset=t.target.value} - >`}_thresholdLimitsOverlap(){let e=parseFloat(this._triggerAbove),t=parseFloat(this._triggerBelow);return!isNaN(e)&&!isNaN(t)&&t>e}_renderTriggerLiveHint(){if(this._triggerType==="compound")return h;let e=this._triggerType==="threshold"&&this._thresholdLimitsOverlap()?l`
${n("trigger_hint_overlap",this._lang)}
`:h,t=this._triggerEntityId||this._triggerEntityIds[0];if(!t||!this.hass?.states)return e;let i=this.hass.states[t];if(!i)return e;let a=this._lang,o=i.attributes?.unit_of_measurement,d=typeof o=="string"&&o?` ${o}`:"",p=this._triggerAttribute?i.attributes?.[this._triggerAttribute]:i.state,_=typeof p=="number"?p:parseFloat(String(p)),m=p!=="unknown"&&p!=="unavailable"&&p!=null&&!isNaN(_),f=w=>C(w,a,{maximumFractionDigits:1}),x=[];if(this._triggerType==="threshold"){let w=parseFloat(this._triggerAbove),k=parseFloat(this._triggerBelow);if(isNaN(w)&&isNaN(k))return h;m&&x.push(n("trigger_hint_now",a).replace("{value}",f(_)+d)),isNaN(w)||x.push(n("trigger_hint_above",a).replace("{target}",f(w)+d)),isNaN(k)||x.push(n("trigger_hint_below",a).replace("{target}",f(k)+d))}else if(this._triggerType==="counter"){let w=parseFloat(this._triggerTargetValue);if(isNaN(w))return h;this._triggerDeltaMode?this._taskId?x.push(n("trigger_hint_counter_delta_edit",a).replace("{target}",f(w)+d)):m?x.push(n("trigger_hint_counter_delta",a).replace("{value}",f(_)+d).replace("{due}",f(_+w)+d).replace("{target}",f(w)+d)):x.push(n("trigger_hint_counter_delta_edit",a).replace("{target}",f(w)+d)):(m&&x.push(n("trigger_hint_now",a).replace("{value}",f(_)+d)),x.push(n("trigger_hint_counter_abs",a).replace("{target}",f(w)+d)))}else if(this._triggerType==="runtime"){let w=parseFloat(this._triggerRuntimeHours);if(isNaN(w))return h;x.push(n("trigger_hint_runtime",a).replace("{hours}",f(w))),x.push(n("trigger_hint_state_now",a).replace("{value}",String(i.state)))}else if(this._triggerType==="state_change"){let w=parseInt(this._triggerTargetChanges,10)||1,k=this._triggerToState.trim();x.push((k?n("trigger_hint_state_change_to",a).replace("{state}",k):n("trigger_hint_state_change",a)).replace("{count}",String(w))),x.push(n("trigger_hint_state_now",a).replace("{value}",String(i.state)))}else if(this._triggerType==="due_date"){let w=parseInt(this._triggerDaysBefore,10)||0;x.push(w===0?n("trigger_hint_due_date_same_day",a):w===1?n("trigger_hint_due_date_one",a):n("trigger_hint_due_date",a).replace("{days}",String(w)));let k=p==null?"":String(p);k&&!isNaN(Date.parse(k))&&x.push(n("trigger_hint_due_date_now",a).replace("{date}",O(k,a)))}return x.length?l`
${x.join(" ")}
${e}`:e}_renderTriggerTypeFields(){let e=this._lang;return this._triggerType==="threshold"?l` + >
`}_thresholdLimitsOverlap(){let e=parseFloat(this._triggerAbove),t=parseFloat(this._triggerBelow);return!isNaN(e)&&!isNaN(t)&&t>e}_renderTriggerLiveHint(){if(this._triggerType==="compound")return u;let e=this._triggerType==="threshold"&&this._thresholdLimitsOverlap()?l`
${a("trigger_hint_overlap",this._lang)}
`:u,t=this._triggerEntityId||this._triggerEntityIds[0];if(!t||!this.hass?.states)return e;let i=this.hass.states[t];if(!i)return e;let n=this._lang,o=i.attributes?.unit_of_measurement,d=typeof o=="string"&&o?` ${o}`:"",p=this._triggerAttribute?i.attributes?.[this._triggerAttribute]:i.state,_=typeof p=="number"?p:parseFloat(String(p)),m=p!=="unknown"&&p!=="unavailable"&&p!=null&&!isNaN(_),f=w=>C(w,n,{maximumFractionDigits:1}),x=[];if(this._triggerType==="threshold"){let w=parseFloat(this._triggerAbove),k=parseFloat(this._triggerBelow);if(isNaN(w)&&isNaN(k))return u;m&&x.push(a("trigger_hint_now",n).replace("{value}",f(_)+d)),isNaN(w)||x.push(a("trigger_hint_above",n).replace("{target}",f(w)+d)),isNaN(k)||x.push(a("trigger_hint_below",n).replace("{target}",f(k)+d))}else if(this._triggerType==="counter"){let w=parseFloat(this._triggerTargetValue);if(isNaN(w))return u;this._triggerDeltaMode?this._taskId?x.push(a("trigger_hint_counter_delta_edit",n).replace("{target}",f(w)+d)):m?x.push(a("trigger_hint_counter_delta",n).replace("{value}",f(_)+d).replace("{due}",f(_+w)+d).replace("{target}",f(w)+d)):x.push(a("trigger_hint_counter_delta_edit",n).replace("{target}",f(w)+d)):(m&&x.push(a("trigger_hint_now",n).replace("{value}",f(_)+d)),x.push(a("trigger_hint_counter_abs",n).replace("{target}",f(w)+d)))}else if(this._triggerType==="runtime"){let w=parseFloat(this._triggerRuntimeHours);if(isNaN(w))return u;x.push(a("trigger_hint_runtime",n).replace("{hours}",f(w))),x.push(a("trigger_hint_state_now",n).replace("{value}",String(i.state)))}else if(this._triggerType==="state_change"){let w=parseInt(this._triggerTargetChanges,10)||1,k=this._triggerToState.trim();x.push((k?a("trigger_hint_state_change_to",n).replace("{state}",k):a("trigger_hint_state_change",n)).replace("{count}",String(w))),x.push(a("trigger_hint_state_now",n).replace("{value}",String(i.state)))}else if(this._triggerType==="due_date"){let w=parseInt(this._triggerDaysBefore,10)||0;x.push(w===0?a("trigger_hint_due_date_same_day",n):w===1?a("trigger_hint_due_date_one",n):a("trigger_hint_due_date",n).replace("{days}",String(w)));let k=p==null?"":String(p);k&&!isNaN(Date.parse(k))&&x.push(a("trigger_hint_due_date_now",n).replace("{date}",O(k,n)))}return x.length?l`
${x.join(" ")}
${e}`:e}_renderTriggerTypeFields(){let e=this._lang;return this._triggerType==="threshold"?l` this._triggerAbove=t.target.value} > this._triggerBelow=t.target.value} > this._triggerEquals=t.target.value} > this._triggerNotEquals=t.target.value} > this._triggerForMinutes=t.target.value} > `:this._triggerType==="counter"?l` this._triggerDeltaMode=t.target.checked} /> - ${n("delta_mode",e)} + ${a("delta_mode",e)} ${this._triggerDeltaMode?l` this._triggerBaselineValue=t.target.value} >
- ${this._taskId?n("baseline_start_help_edit",e):n("baseline_start_help",e)} + ${this._taskId?a("baseline_start_help_edit",e):a("baseline_start_help",e)} ${this._taskId&&this._liveBaselineValue!=null?l`
- ${n("baseline_current_effective",e).replace("{value}",String(this._liveBaselineValue))} -
`:h} + ${a("baseline_current_effective",e).replace("{value}",String(this._liveBaselineValue))} +
`:u}
- `:h} + `:u} `:this._triggerType==="state_change"?l` - ${this._renderStateField({label:n("from_state_optional",e),value:this._triggerFromState,entityId:this._triggerEntityId,onInput:t=>this._triggerFromState=t})} -
${n("state_value_help",e)}
- ${this._renderStateField({label:n("to_state_optional",e),value:this._triggerToState,entityId:this._triggerEntityId,onInput:t=>this._triggerToState=t})} + ${this._renderStateField({label:a("from_state_optional",e),value:this._triggerFromState,entityId:this._triggerEntityId,onInput:t=>this._triggerFromState=t})} +
${a("state_value_help",e)}
+ ${this._renderStateField({label:a("to_state_optional",e),value:this._triggerToState,entityId:this._triggerEntityId,onInput:t=>this._triggerToState=t})} this._triggerTargetChanges=t.target.value} > -
${n("target_changes_help",e)}
- ${(this._triggerTargetChanges||"1")==="1"&&(this._triggerFromState||this._triggerToState)?l`
${n("state_latch_help",e)}
`:h} +
${a("target_changes_help",e)}
+ ${(this._triggerTargetChanges||"1")==="1"&&(this._triggerFromState||this._triggerToState)?l`
${a("state_latch_help",e)}
`:u} this._triggerForMinutes=t.target.value} > -
${n("for_minutes_state_help",e)}
+
${a("for_minutes_state_help",e)}
`:this._triggerType==="runtime"?l` this._triggerRuntimeHours=t.target.value} > this._triggerRuntimeMaxSession=t.target.value} > -
${n("runtime_max_session_help",e)}
+
${a("runtime_max_session_help",e)}
${this._renderOnStatesField({value:this._triggerOnStates,entityId:this._triggerEntityId,onInput:t=>this._triggerOnStates=t})} -
${n("runtime_on_states_help",e)}
+
${a("runtime_on_states_help",e)}
`:this._triggerType==="due_date"?l` this._triggerDaysBefore=t.target.value} > -
${n("days_before_help",e)}
- `:h}render(){if(!this._open)return l``;let e=this._lang,t=this._taskId?n("edit_task",e):n("new_task",e);return l` +
${a("days_before_help",e)}
+ `:u}render(){if(!this._open)return l``;let e=this._lang,t=this._taskId?a("edit_task",e):a("new_task",e);return l`
${t}
- ${this._error?l`
${this._error}
`:h} - ${this._warning?l`
${this._warning}
`:h} + ${this._error?l`
${this._error}
`:u} + ${this._warning?l`
${this._warning}
`:u} ${this._taskId===null&&this._objectChoices.length>0?l`
- +
- `:h} + `:u} this._name=i.target.value} >
- +
${this._type==="reading"?l` this._readingUnit=i.target.value} > -
${n("reading_unit_help",e)}
+
${a("reading_unit_help",e)}
${this._renderReadingsEditor(e)} - `:h} - ${this._partsLoadFailed?l`
${n("parts_load_failed",e)}
`:h} - ${this._isFleetTask?l`
${n("task_parts_fleet_hint",e)}
`:this.parts.length||this._foreignOwners.length?l` + `:u} + ${this._partsLoadFailed?l`
${a("parts_load_failed",e)}
`:u} + ${this._isFleetTask?l`
${a("task_parts_fleet_hint",e)}
`:this.parts.length||this._foreignOwners.length?l`
- + ${this.parts.map(i=>this._renderConsumesRow(i))} ${this._foreignOwners.length?l`
- ${n("shared_parts_other_objects",e)} -
${n("shared_parts_help",e)}
+ ${a("shared_parts_other_objects",e)} +
${a("shared_parts_help",e)}
${this._foreignOwners.map(i=>l`
${i.name}
- ${i.parts.map(a=>this._renderConsumesRow(a,i.entry_id))} + ${i.parts.map(n=>this._renderConsumesRow(n,i.entry_id))} `)}
- `:h} + `:u}
- `:h} + `:u}
- +
- + this._labels=i.target.value} /> -
${n("labels_help",e)}
+
${a("labels_help",e)}
${this._entityPickerFallback?l` {this._mirrorTodoEntities=i.target.value.split(",").map(a=>a.trim()).filter(Boolean)}} + @input=${i=>{this._mirrorTodoEntities=i.target.value.split(",").map(n=>n.trim()).filter(Boolean)}} > `:l` n("task_mirror_todo",e)} - @value-changed=${i=>{let a=(i.detail.value.mirror_todo_entities||[]).filter(Boolean);this._mirrorTodoEntities=a}} + .computeLabel=${()=>a("task_mirror_todo",e)} + @value-changed=${i=>{let n=(i.detail.value.mirror_todo_entities||[]).filter(Boolean);this._mirrorTodoEntities=n}} >`} -
${n("task_mirror_todo_hint",e)}
+
${a("task_mirror_todo_hint",e)}
- +
${this._scheduleType==="time_based"?l` this._intervalDays=i.target.value} > ${this._renderUnitSelect()}
- +
- `:h} + `:u} ${this._renderCalendarFields()} ${this._scheduleType==="one_time"?l` this._dueDate=i.detail.value} > - `:h} - ${this.scheduleTimeEnabled&&ln.includes(this._scheduleType)?l` + `:u} + ${this.scheduleTimeEnabled&&Sn.includes(this._scheduleType)?l` ${this._scheduleTimeOn?l` this._scheduleTime=i.detail.value} > - `:h} - `:h} + `:u} + `:u} ${this._renderRecurrenceExtras()} ${this._renderSchedulePreview()} this._warningDays=i.target.value} > this._earliestCompletionDays=i.target.value} > ${this.checklistsEnabled?l` -

${n("checklist_steps_optional",e)}

+

${a("checklist_steps_optional",e)}

-
${n("checklist_help",e)}
- `:h} +
${a("checklist_help",e)}
+ `:u} ${this._renderPhasesEditor(e)} -

${n("require_on_completion",e)}

+

${a("require_on_completion",e)}

- ${Qi.map(i=>l` + ${ar.map(i=>l` `)}
@@ -2645,24 +2662,24 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" clearable .hass=${this.hass} .lang=${e} - label="${n("last_performed_optional",e)}" + label="${a("last_performed_optional",e)}" .value=${this._lastPerformed} @value-changed=${i=>this._lastPerformed=i.detail.value} >
- +
${this._availableUsers.length>=2?l`
- -
${n("shared_with_help",e)}
+ +
${a("shared_with_help",e)}
${this._availableUsers.map(i=>l`
${this._assigneePool.length>=2?l`
- + -
`:h} - `:h} +
`:u} + `:u} ${this._renderTriggerFields()} ${this._scheduleType==="sensor_based"&&(this.environmentalFeature||this._environmentalInitial)?l` ${this._entityPickerFallback?l` this._environmentalEntity=i.target.value.trim()} > @@ -2698,70 +2715,70 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" n("environmental_entity_optional",e)} - .computeHelper=${()=>n("environmental_entity_helper",e)} + .computeLabel=${()=>a("environmental_entity_optional",e)} + .computeHelper=${()=>a("environmental_entity_helper",e)} @value-changed=${i=>{this._environmentalEntity=(i.detail.value.environmental_entity||"").trim()}} >`} - ${this._environmentalEntity?this._renderEnvironmentalAttribute(e):h} - `:h} + ${this._environmentalEntity?this._renderEnvironmentalAttribute(e):u} + `:u} ${this._renderAdaptiveSection(e)} this._notes=i.target.value} > this._documentationUrl=i.target.value} > this._customIcon=i.detail.value||""} > this._notifyIcon=i.detail.value||""} >
- - ${n("notify_icon_hint",e).replace("{default}",Ji(this._type))} + + ${a("notify_icon_hint",e).replace("{default}",lr(this._type))}
${this._availableTags.length>0?l`
- + + title="${a("nfc_tags_refresh",e)}">↻
`:l` this._nfcTagId=i.target.value} >
- ${n("nfc_tags_empty_help",e)} - ${n("nfc_tags_open_settings",e)} + ${a("nfc_tags_empty_help",e)} + ${a("nfc_tags_open_settings",e)} ·
`} @@ -2771,44 +2788,44 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .checked=${this._requireTagScan} @change=${i=>this._requireTagScan=i.target.checked} /> - ${n("require_tag_scan",e)} + ${a("require_tag_scan",e)} - ${this._requireTagScan?l`
${n("require_tag_scan_help",e)}
`:h} + ${this._requireTagScan?l`
${a("require_tag_scan_help",e)}
`:u} - ${this._allowSkip?h:l`
${n("disallow_skip_help",e)}
`} + ${this._allowSkip?u:l`
${a("disallow_skip_help",e)}
`} - ${this._notifyEnabled?h:l`
${n("no_notifications_help",e)}
`} + ${this._notifyEnabled?u:l`
${a("no_notifications_help",e)}
`} ${this._renderCompletionActionsSection(e)}
- ${n("cancel",e)} + ${a("cancel",e)} - ${this._loading?n("saving",e):n("save",e)} + ${this._loading?a("saving",e):a("save",e)}
@@ -3213,28 +3230,28 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" font-size: 14px; cursor: pointer; } - `,c([v({attribute:!1})],g.prototype,"hass",2),c([v({type:Boolean,attribute:"checklists-enabled"})],g.prototype,"checklistsEnabled",2),c([v({type:Boolean,attribute:"schedule-time-enabled"})],g.prototype,"scheduleTimeEnabled",2),c([v({type:Boolean,attribute:"completion-actions-enabled"})],g.prototype,"completionActionsEnabled",2),c([v({type:Boolean,attribute:"adaptive-feature"})],g.prototype,"adaptiveFeature",2),c([v({type:Boolean,attribute:"seasonal-feature"})],g.prototype,"seasonalFeature",2),c([v({type:Boolean,attribute:"environmental-feature"})],g.prototype,"environmentalFeature",2),c([v({type:Number,attribute:"default-warning-days"})],g.prototype,"defaultWarningDays",2),c([u()],g.prototype,"parts",2),c([u()],g.prototype,"_foreignOwners",2),c([u()],g.prototype,"_open",2),c([u()],g.prototype,"_entityPickerFallback",2),c([u()],g.prototype,"_loading",2),c([u()],g.prototype,"_error",2),c([u()],g.prototype,"_warning",2),c([u()],g.prototype,"_entryId",2),c([u()],g.prototype,"_taskId",2),c([u()],g.prototype,"_isFleetTask",2),c([u()],g.prototype,"_objectChoices",2),c([u()],g.prototype,"_name",2),c([u()],g.prototype,"_type",2),c([u()],g.prototype,"_scheduleType",2),c([u()],g.prototype,"_intervalDays",2),c([u()],g.prototype,"_intervalUnit",2),c([u()],g.prototype,"_dueDate",2),c([u()],g.prototype,"_warningDays",2),c([u()],g.prototype,"_earliestCompletionDays",2),c([u()],g.prototype,"_intervalAnchor",2),c([u()],g.prototype,"_weekdays",2),c([u()],g.prototype,"_nth",2),c([u()],g.prototype,"_nthWeekday",2),c([u()],g.prototype,"_domDay",2),c([u()],g.prototype,"_domLastDay",2),c([u()],g.prototype,"_domBusiness",2),c([u()],g.prototype,"_calOffset",2),c([u()],g.prototype,"_calendarEntity",2),c([u()],g.prototype,"_seasonMonths",2),c([u()],g.prototype,"_endsMode",2),c([u()],g.prototype,"_endsCount",2),c([u()],g.prototype,"_endsUntil",2),c([u()],g.prototype,"_schedulePreview",2),c([u()],g.prototype,"_schedulePreviewEnded",2),c([u()],g.prototype,"_notes",2),c([u()],g.prototype,"_documentationUrl",2),c([u()],g.prototype,"_customIcon",2),c([u()],g.prototype,"_notifyIcon",2),c([u()],g.prototype,"_priority",2),c([u()],g.prototype,"_labels",2),c([u()],g.prototype,"_mirrorTodoEntities",2),c([u()],g.prototype,"_enabled",2),c([u()],g.prototype,"_triggerEntityId",2),c([u()],g.prototype,"_triggerEntityIds",2),c([u()],g.prototype,"_triggerEntityLogic",2),c([u()],g.prototype,"_triggerAttribute",2),c([u()],g.prototype,"_triggerType",2),c([u()],g.prototype,"_triggerAbove",2),c([u()],g.prototype,"_triggerBelow",2),c([u()],g.prototype,"_triggerEquals",2),c([u()],g.prototype,"_triggerNotEquals",2),c([u()],g.prototype,"_triggerForMinutes",2),c([u()],g.prototype,"_triggerCombinator",2),c([u()],g.prototype,"_triggerTargetValue",2),c([u()],g.prototype,"_triggerDeltaMode",2),c([u()],g.prototype,"_triggerBaselineValue",2),c([u()],g.prototype,"_liveBaselineValue",2),c([u()],g.prototype,"_autoCompleteOnRecovery",2),c([u()],g.prototype,"_triggerFromState",2),c([u()],g.prototype,"_triggerToState",2),c([u()],g.prototype,"_triggerTargetChanges",2),c([u()],g.prototype,"_triggerRuntimeHours",2),c([u()],g.prototype,"_triggerDaysBefore",2),c([u()],g.prototype,"_triggerRuntimeMaxSession",2),c([u()],g.prototype,"_triggerOnStates",2),c([u()],g.prototype,"_compoundLogic",2),c([u()],g.prototype,"_compoundConditions",2),c([u()],g.prototype,"_suggestedAttributes",2),c([u()],g.prototype,"_availableAttributes",2),c([u()],g.prototype,"_entityDomain",2),c([u()],g.prototype,"_lastPerformed",2),c([u()],g.prototype,"_nfcTagId",2),c([u()],g.prototype,"_requireTagScan",2),c([u()],g.prototype,"_allowSkip",2),c([u()],g.prototype,"_notifyEnabled",2),c([u()],g.prototype,"_readingUnit",2),c([u()],g.prototype,"_readings",2),c([u()],g.prototype,"_consumesParts",2),c([u()],g.prototype,"_consumesQtyText",2),c([u()],g.prototype,"_partsLoadFailed",2),c([u()],g.prototype,"_availableTags",2),c([u()],g.prototype,"_responsibleUserId",2),c([u()],g.prototype,"_assigneePool",2),c([u()],g.prototype,"_rotationStrategy",2),c([u()],g.prototype,"_availableUsers",2),c([u()],g.prototype,"_checklistText",2),c([u()],g.prototype,"_phaseDefs",2),c([u()],g.prototype,"_phaseSeq",2),c([u()],g.prototype,"_requiredCompletion",2),c([u()],g.prototype,"_scheduleTime",2),c([u()],g.prototype,"_scheduleTimeOn",2),c([u()],g.prototype,"_actionService",2),c([u()],g.prototype,"_actionTargetEntity",2),c([u()],g.prototype,"_actionSkipAuto",2),c([u()],g.prototype,"_actionPresent",2),c([u()],g.prototype,"_actionData",2),c([u()],g.prototype,"_actionDataJsonFallback",2),c([u()],g.prototype,"_actionTesting",2),c([u()],g.prototype,"_actionTestResult",2),c([u()],g.prototype,"_actionTestError",2),c([u()],g.prototype,"_qcNotes",2),c([u()],g.prototype,"_qcCost",2),c([u()],g.prototype,"_qcDuration",2),c([u()],g.prototype,"_qcFeedback",2),c([u()],g.prototype,"_environmentalEntity",2),c([u()],g.prototype,"_environmentalAttribute",2),c([u()],g.prototype,"_adaptiveEnabled",2),c([u()],g.prototype,"_adaptiveAlpha",2),c([u()],g.prototype,"_adaptiveMin",2),c([u()],g.prototype,"_adaptiveMax",2),c([u()],g.prototype,"_adaptiveSeasonal",2),c([u()],g.prototype,"_adaptivePrediction",2),c([u()],g.prototype,"_conditionAttrOptions",2);Xi=g;customElements.get("maintenance-task-dialog")||customElements.define("maintenance-task-dialog",Xi)});async function To(s,r,e){let t=s.auth;if(t?.expired&&t.refreshAccessToken)try{await t.refreshAccessToken()}catch{}return fetch(r,{...e,headers:{...e.headers??{},Authorization:`Bearer ${t?.data?.access_token??""}`}})}async function Ao(s,r,e,t="doc_too_large",i=[]){let a=await To(s,r,{method:"POST",body:e});if(a.status===413)throw new Error(t);if(!a.ok){let o=await a.json().catch(()=>null);throw typeof o?.code=="string"&&i.includes(o.code)?new Error(o.code):new Error("doc_upload_failed")}return await a.json()}async function Co(s,r,e,t){let i=new FormData;i.append("entry_id",r);for(let o of t)i.append("tags",o);i.append("file",e,e.name);let a=await Ao(s,"/api/maintenance_supporter/document/upload",i);if(!a.id)throw new Error("doc_upload_failed");return{id:a.id,deduped:!!a.deduped,duplicate_in_object:a.duplicate_in_object??null}}async function gn(s,r,e){return(await Co(s,r,e,["photo"])).id}async function er(s,r,e){await Promise.all(e.map(t=>s.connection.sendMessagePromise({type:"maintenance_supporter/documents/discard_upload",entry_id:r,doc_id:t}).catch(()=>{})))}var rp,fn=y(()=>{"use strict";ti();rp=500*1024*1024});var tt,tr=y(()=>{"use strict";T();fn();tt=class{constructor(r,e){this.host=r;this.opts=e;this.photos=[];this.uploadedIds=[];this.uploading=!1;this.errorKey="";this._session=0;this._uploadEntry=new Map;this.max=e.max??10,r.addController(this)}hostConnected(){}get ids(){return this.photos.map(r=>r.id)}get remaining(){return Math.max(this.max-this.photos.length,0)}get full(){return this.remaining===0}errorText(r){return this.errorKey?n(this.errorKey,r).replace("{max}",String(this.max)):""}clearError(){this.errorKey=""}reset(r=[]){this._endSession(),this._revokeAll(),this.photos=r.map(e=>({id:e,preview:""})),this.uploadedIds=[],this._uploadEntry.clear(),this.errorKey="",this.host.requestUpdate()}async addFiles(r){if(r.length===0)return;let e=this._session,t=this.opts.hass(),i=this.opts.entryId(),a=r.slice(0,this.remaining);this.uploading=!0,this.errorKey="",this.host.requestUpdate();try{for(let o of a){let d=await gn(t,i,o);if(e!==this._session){er(t,i,[d]);return}this.uploadedIds=[...this.uploadedIds,d],this._uploadEntry.set(d,i),this.photos=[...this.photos,{id:d,preview:URL.createObjectURL(o)}],this.host.requestUpdate()}r.length>a.length&&(this.errorKey="photos_limit")}catch(o){if(e!==this._session)return;this.errorKey=o instanceof Error&&o.message==="doc_too_large"?"doc_too_large":"doc_upload_failed"}finally{e===this._session&&(this.uploading=!1,this.host.requestUpdate())}}remove(r){let e=this.photos.find(t=>t.id===r);e?.preview&&URL.revokeObjectURL(e.preview),this.photos=this.photos.filter(t=>t.id!==r),this.uploadedIds.includes(r)&&(this.uploadedIds=this.uploadedIds.filter(t=>t!==r),this._discard([r])),this.host.requestUpdate()}discardOrphans(){if(this._endSession(),this.uploadedIds.length===0)return;let r=this.uploadedIds;this.uploadedIds=[],this._discard(r)}markAttached(){this._endSession(),this.uploadedIds=[],this._uploadEntry.clear()}_endSession(){this._session++,this.uploading=!1}_discard(r){let e=new Map;for(let i of r){let a=this._uploadEntry.get(i)??this.opts.entryId();this._uploadEntry.delete(i),e.set(a,[...e.get(a)??[],i])}let t=this.opts.hass();for(let[i,a]of e)er(t,i,a)}_revokeAll(){for(let r of this.photos)r.preview&&URL.revokeObjectURL(r.preview)}}});function ci(){if(window.externalApp!==void 0)return!0;let r=typeof navigator<"u"&&navigator.userAgent||"";return/Home Assistant\//.test(r)&&/Android/.test(r)}var ir=y(()=>{"use strict"});function vn(s){try{return localStorage.getItem(s)}catch{return null}}function yn(s,r){try{localStorage.setItem(s,r)}catch{}}var rr,bn=y(()=>{"use strict";rr={objectSections:"msp-object-sections",printOptions:"msp-print-options",batteryRosterOpen:"msp-bf-roster-open",docSort:"msp-doc-sort",cameraLabel:"msp-camera-label",overviewTab:"msp-overview-tab",collapsedSections:"msp-collapsed-sections",chartRange:"msp-chart-range",chartHideOutliers:"msp-chart-hide-outliers",taskSort:"maintenance_supporter_sort",objectSort:"maintenance_supporter_object_sort",groupBy:"maintenance_supporter_groupby",objectView:"maintenance_supporter_object_view",objectsCache:"msp-objects-cache",gettingStartedDismissed:"msp-gs-dismissed",batteryRosterSort:"ms_bf_roster_sort",areaSort:"msp-area-sort"}});function Sn(){if(!ci())return!1;let s=typeof navigator<"u"?navigator.mediaDevices:void 0;return!!s&&typeof s.getUserMedia=="function"}function kn(s){let r=/camera2?\s*(\d+)/i.exec(s);return r?Number(r[1]):Number.MAX_SAFE_INTEGER}function $n(s,r){if(r){let t=s.find(i=>i.label===r);if(t)return t}return s.filter(t=>t.label&&Tn.test(t.label)).sort((t,i)=>kn(t.label)-kn(i.label))[0]??null}var Io,Ro,Po,Lo,xn,Tn,wn,En,No,X,sr=y(()=>{"use strict";I();F();T();ir();bn();Io=1920,Ro=.88,Po={retryMs:500,windowMs:5e3},Lo=new Set(["NotReadableError","AbortError","TrackStartError"]),xn=80,Tn=/back|rear|environment|rück|hinten/i,wn=/front|user|selfie|vorne/i;En=s=>s?.name||"Error",No=s=>s?.message||"",X=class extends S{constructor(){super(...arguments);this.lang="en";this._open=!1;this._busy=!1;this._switching=!1;this._devices=[];this._deviceIndex=-1;this._switchFailed=!1;this._copied=!1;this.timing={...Po};this._facing="environment";this._stream=null;this._opening=!1;this._gen=0;this._refused=new Set;this._log=[];this._t0=0;this._lastError=""}async open(){if(this._open||this._opening)return;this._opening=!0;let e=++this._gen;try{await this._acquireAndShow(e)}finally{this._opening=!1}}_live(e){return e===this._gen&&this.isConnected}async _acquireAndShow(e){let t=typeof navigator<"u"?navigator.mediaDevices:void 0;if(!t||typeof t.getUserMedia!="function"){this._unavailable("no_media_devices");return}this._log=[],this._t0=Date.now(),this._lastError="",this._refused.clear(),this._switchFailed=!1,this._copied=!1,this._note(navigator.userAgent);let i=vn(rr.cameraLabel),a=await this._enumerate(t);if(!this._live(e))return;let o=$n(a,i),d="refused";if(o&&(d=await this._openPatiently(t,e,this._byDevice(o))),d==="cancelled")return;if(d!=="ok"){if(d=await this._openPatiently(t,e,{video:{facingMode:{ideal:"environment"}},what:"facing environment"}),d==="cancelled")return;if(d!=="ok"){this._unavailable(this._lastError||"camera_unavailable");return}if(a=await this._enumerate(t),!this._live(e)){this._stopStream();return}}if(this._devices=a,this._deviceIndex=this._indexOfCurrent(),this._facing=this._currentFacing(),this._open=!0,await this.updateComplete,!this._live(e)){this._stopStream(),this._open=!1;return}await this._attach();let p=o?null:$n(a,i),_=this._deviceIndex>=0?a[this._deviceIndex]:void 0;if(!p||p.deviceId===_?.deviceId)return;let m=await this._replace(t,e,[this._byDevice(p)],this._restoreCandidates(_));if(m!=="cancelled"){if(m==="lost"){this._unavailable("camera_lost");return}this._settle(m)}}async _openPatiently(e,t,i){let a=Date.now();for(;;){let o;try{o=await e.getUserMedia({video:i.video,audio:!1})}catch(d){let p=En(d),_=No(d);if(this._lastError=p,this._note(`${i.what} \u2192 ${p}${_&&_!==p?`: ${_}`:""}`),!this._live(t))return"cancelled";if(!Lo.has(p))return"refused";if(Date.now()-a+this.timing.retryMs>this.timing.windowMs)return"busy";if(await new Promise(m=>setTimeout(m,this.timing.retryMs)),!this._live(t))return"cancelled";continue}if(!this._live(t)){for(let d of o.getTracks())d.stop();return"cancelled"}return this._stream=o,this._note(`${i.what} \u2192 ok (${this._describeTrack()})`),"ok"}}async _replace(e,t,i,a){this._switching=!0,this._stopStream();try{for(let o of i){let d=await this._openPatiently(e,t,o);if(d==="ok")return o;if(d==="cancelled")return d;if(d==="busy"){o.deviceId&&this._refused.add(o.deviceId);break}}for(let o of a){let d=await this._openPatiently(e,t,o);if(d==="ok")return"restored";if(d==="cancelled")return d}return"lost"}finally{this._switching=!1}}_settle(e){if(e==="restored"){this._switchFailed=!0;let i=this._indexOfCurrent();return i>=0&&(this._deviceIndex=i),this._attach(),!1}this._switchFailed=!1;let t=e.deviceId?this._devices.findIndex(i=>i.deviceId===e.deviceId):-1;return this._deviceIndex=t>=0?t:this._indexOfCurrent(),this._facing=this._currentFacing(),this._attach(),!0}_byDevice(e){return{video:{deviceId:{exact:e.deviceId}},what:e.label||"camera (no label)",deviceId:e.deviceId}}_restoreCandidates(e,t){let i=[],a=e?.deviceId||t;return a&&i.push({video:{deviceId:{exact:a}},what:`${e?.label||"previous camera"} (back again)`,deviceId:a}),i.push({video:{facingMode:{ideal:this._facing}},what:`facing ${this._facing} (back again)`}),i}async _attach(){let e=this._video;if(!(!e||!this._stream)){e.srcObject=this._stream;try{await e.play()}catch{}}}async _enumerate(e){if(typeof e.enumerateDevices!="function")return[];try{let t=(await e.enumerateDevices()).filter(i=>i.kind==="videoinput"&&!!i.deviceId);return this._note(`cameras: ${t.map(i=>i.label||"(no label)").join(" | ")||"none listed"}`),t}catch(t){return this._note(`enumerateDevices \u2192 ${En(t)}`),[]}}_indexOfCurrent(){let e=this._stream?.getVideoTracks()[0];if(!e)return-1;let t=e.getSettings().deviceId,i=t?this._devices.findIndex(a=>a.deviceId===t):-1;return i>=0?i:e.label?this._devices.findIndex(a=>a.label===e.label):-1}_currentFacing(){let e=this._stream?.getVideoTracks()[0],t=e?.getSettings().facingMode;if(t==="user"||t==="environment")return t;let i=(this._deviceIndex>=0?this._devices[this._deviceIndex]?.label:"")||e?.label||"";return wn.test(i)?"user":Tn.test(i)?"environment":this._facing}_describeTrack(){let e=this._stream?.getVideoTracks()[0];if(!e)return"no track";let t=e.getSettings(),i=t.width&&t.height?`${t.width}\xD7${t.height}`:"size ?";return[e.label||"no label",i,t.facingMode].filter(Boolean).join(", ")}_note(e){this._log.push(`+${Date.now()-this._t0} ms ${e}`),this._log.length>xn&&this._log.splice(1,this._log.length-xn)}async _switchCamera(){let e=typeof navigator<"u"?navigator.mediaDevices:void 0;if(!e||this._devices.length<2||this._busy||this._switching)return;let t=this._gen,i=this._deviceIndex,a=i>=0?this._devices[i]:void 0,o=this._stream?.getVideoTracks()[0]?.getSettings().deviceId||a?.deviceId,d=this._facing==="user"?"environment":"user",p=this._nextCameras(i,o);!p.length&&this._refused.size&&(this._refused.clear(),p=this._nextCameras(i,o)),this._note(`switch from ${a?.label||"unknown camera"}`);let _=[...p.map(m=>this._byDevice(this._devices[m])),{video:{facingMode:{exact:d}},what:`facing ${d} (exact)`},{video:{facingMode:{ideal:d}},what:`facing ${d}`}];this._busy=!0,this._switchFailed=!1,this._copied=!1;try{let m=await this._replace(e,t,_,this._restoreCandidates(a,o));if(m==="cancelled")return;if(m==="lost"){this._unavailable("camera_lost");return}if(m!=="restored"&&!m.deviceId){if(this._isCamera(o,this._facing)){this._switchFailed=!0,await this._attach();return}this._facing=d}if(this._settle(m)&&m!=="restored"&&m.deviceId){let f=this._devices[this._deviceIndex]?.label??"";f&&yn(rr.cameraLabel,wn.test(f)?"":f)}}finally{this._busy=!1}}_nextCameras(e,t){let i=this._devices.length,a=[];for(let o=1;o<=(e<0?i:i-1);o++){let d=(e+o)%i,p=this._devices[d].deviceId;p===t||this._refused.has(p)||a.push(d)}return a}_isCamera(e,t){let i=this._stream?.getVideoTracks()[0]?.getSettings();return e&&i?.deviceId?i.deviceId===e:!!i?.facingMode&&i.facingMode===t}close(){this._gen++,this._stopStream(),this._open=!1,this._busy=!1,this._switching=!1}disconnectedCallback(){super.disconnectedCallback(),this._gen++,this._stopStream()}get _video(){return this.shadowRoot?.querySelector("video")??null}_stopStream(){for(let t of this._stream?.getTracks()??[])t.stop();this._stream=null;let e=this._video;e&&(e.srcObject=null)}_unavailable(e){this._stopStream(),this._open=!1,this.dispatchEvent(new CustomEvent("capture-unavailable",{detail:{reason:e},bubbles:!0,composed:!0}))}async _copyLog(){let e=this._log.join(` -`),t=!1;try{navigator.clipboard?.writeText&&(await navigator.clipboard.writeText(e),t=!0)}catch{}if(!t){let i=this.shadowRoot?.querySelector(".details textarea");if(i){i.focus(),i.select();try{t=document.execCommand("copy")}catch{t=!1}}}this._copied=t}async _shoot(){let e=this._video;if(!(!e||this._busy||this._switching)){this._busy=!0;try{let t=e.videoWidth||640,i=e.videoHeight||480,a=Math.min(1,Io/Math.max(t,i)),o=document.createElement("canvas");o.width=Math.round(t*a),o.height=Math.round(i*a);let d=o.getContext("2d");if(!d)throw new Error("no_canvas");d.drawImage(e,0,0,o.width,o.height);let p=await new Promise(f=>o.toBlob(f,"image/jpeg",Ro));if(!p)throw new Error("no_blob");let _=new Date().toISOString().replace(/[-:]/g,"").slice(0,15),m=new File([p],`photo-${_}.jpg`,{type:"image/jpeg"});this.close(),this.dispatchEvent(new CustomEvent("photo-captured",{detail:{file:m},bubbles:!0,composed:!0}))}catch(t){this._unavailable(t instanceof Error?t.message:String(t))}finally{this._busy=!1}}}render(){if(!this._open)return h;let e=this.lang,t=this._busy||this._switching;return l` - @@ -3279,7 +3296,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .shoot { background: var(--primary-color, #03a9f4); color: #fff; border: none; font-weight: 600; } .shoot[disabled] { opacity: 0.6; cursor: default; } .shoot ha-icon { --mdc-icon-size: 22px; } - `,c([v({type:String})],X.prototype,"lang",2),c([u()],X.prototype,"_open",2),c([u()],X.prototype,"_busy",2),c([u()],X.prototype,"_switching",2),c([u()],X.prototype,"_devices",2),c([u()],X.prototype,"_deviceIndex",2),c([u()],X.prototype,"_switchFailed",2),c([u()],X.prototype,"_copied",2);customElements.get("ms-camera-capture")||customElements.define("ms-camera-capture",X)});var di,ee,At=y(()=>{"use strict";I();F();T();ir();sr();sr();di=E` + `,c([v({type:String})],X.prototype,"lang",2),c([h()],X.prototype,"_open",2),c([h()],X.prototype,"_busy",2),c([h()],X.prototype,"_switching",2),c([h()],X.prototype,"_devices",2),c([h()],X.prototype,"_deviceIndex",2),c([h()],X.prototype,"_switchFailed",2),c([h()],X.prototype,"_copied",2);customElements.get("ms-camera-capture")||customElements.define("ms-camera-capture",X)});var gi,ee,Ct=y(()=>{"use strict";I();F();T();ur();_r();_r();gi=E` ms-photo-picker { display: contents; } .photo-pickers { display: flex; @@ -3308,93 +3325,93 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" color: var(--secondary-text-color); margin-top: 4px; } -`,ee=class extends S{constructor(){super(...arguments);this.lang="en";this.disabled=!1;this.busy=!1;this.accept="image/*";this.showCamera=!0;this.showGallery=!0;this.compact=!1;this.remaining=1/0;this._singlePick=ci();this._inAppCamera=Sn()}createRenderRoot(){return this}get _locked(){return this.disabled||this.busy}_emit(e){e.length!==0&&this.dispatchEvent(new CustomEvent("files-picked",{detail:{files:e},bubbles:!0,composed:!0}))}_onInput(e){let t=e.target,i=Array.from(t.files??[]);t.value="",this._emit(i)}_onCameraClick(e){!this._inAppCamera||this._locked||(e.preventDefault(),this.querySelector("ms-camera-capture")?.open())}_onCameraUnavailable(){this._inAppCamera=!1,this.querySelector(".photo-pick-camera input")?.click()}_onKeydown(e){e.key!=="Enter"&&e.key!==" "||(e.preventDefault(),!this._locked&&e.currentTarget.click())}render(){if(this.remaining<=0||!this.showCamera&&!this.showGallery)return h;let e=this.lang,t=this._locked?"disabled":"",i=this.busy?n("uploading",e):n("doc_camera",e),a=n(this._singlePick?"choose_photo":"choose_photos",e);return l` +`,ee=class extends S{constructor(){super(...arguments);this.lang="en";this.disabled=!1;this.busy=!1;this.accept="image/*";this.showCamera=!0;this.showGallery=!0;this.compact=!1;this.remaining=1/0;this._singlePick=mi();this._inAppCamera=Bn()}createRenderRoot(){return this}get _locked(){return this.disabled||this.busy}_emit(e){e.length!==0&&this.dispatchEvent(new CustomEvent("files-picked",{detail:{files:e},bubbles:!0,composed:!0}))}_onInput(e){let t=e.target,i=Array.from(t.files??[]);t.value="",this._emit(i)}_onCameraClick(e){!this._inAppCamera||this._locked||(e.preventDefault(),this.querySelector("ms-camera-capture")?.open())}_onCameraUnavailable(){this._inAppCamera=!1,this.querySelector(".photo-pick-camera input")?.click()}_onKeydown(e){e.key!=="Enter"&&e.key!==" "||(e.preventDefault(),!this._locked&&e.currentTarget.click())}render(){if(this.remaining<=0||!this.showCamera&&!this.showGallery)return u;let e=this.lang,t=this._locked?"disabled":"",i=this.busy?a("uploading",e):a("doc_camera",e),n=a(this._singlePick?"choose_photo":"choose_photos",e);return l`
${this.showCamera?l``:h} + `:u} ${this.showGallery?l``:h} + `:u}
- ${this.showGallery&&this._singlePick?l`
${n("photos_android_hint",e)}
`:h} + ${this.showGallery&&this._singlePick?l`
${a("photos_android_hint",e)}
`:u} ${this.showCamera&&this._inAppCamera?l`this._emit([o.detail.file])} - @capture-unavailable=${this._onCameraUnavailable}>`:h} - `}};c([v({type:String})],ee.prototype,"lang",2),c([v({type:Boolean})],ee.prototype,"disabled",2),c([v({type:Boolean})],ee.prototype,"busy",2),c([v({type:String})],ee.prototype,"accept",2),c([v({type:Boolean})],ee.prototype,"showCamera",2),c([v({type:Boolean})],ee.prototype,"showGallery",2),c([v({type:Boolean})],ee.prototype,"compact",2),c([v({type:Number})],ee.prototype,"remaining",2),c([u()],ee.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",ee)});var it,$,An=y(()=>{"use strict";I();F();Oe();T();De();Z();Et();si();zt();Zi();tr();ni();Xe();oi();At();At();it=ke,$=class extends S{constructor(){super(...arguments);this.entryId="";this.taskId="";this.taskName="";this.lang="en";this.checklist=[];this.adaptiveEnabled=!1;this.taskType="";this.readingUnit="";this.readings=[];this.readingHistory=[];this.restockDefault=null;this.restockUnitCost=null;this.restockPackage="";this.currencySymbol="";this.partsCostMode="purchase";this.parts=[];this.consumesParts=[];this.consumesInfo=[];this.requiredFields=[];this.phaseLabel="";this.requireTagScan=!1;this.viaTagScan=!1;this._open=!1;this._notes="";this._cost="";this._duration="";this._loading=!1;this._error="";this._checklistState={};this._feedback="needed";this._photos=new tt(this,{entryId:()=>this.entryId,hass:()=>this.hass});this._readingValue="";this._readingValues={};this._restockQty="";this._completedAt="";this._usedParts={};this._usedQtyText={};this.checklistPrefill={}}open(e={}){this._open||(this._open=!0,this.viaTagScan=!!e.viaTagScan,this._notes="",this._cost="",this._duration="",this._error="",this._checklistState=Object.fromEntries(this.checklist.map((t,i)=>[String(i),!!this.checklistPrefill[t]]).filter(([,t])=>t)),this._feedback="needed",this._photos.reset(),this._readingValue="",this._readingValues={},this._restockQty=this.restockDefault!==null?String(this.restockDefault):"",this._completedAt="",this._usedParts=Object.fromEntries(this.consumesParts.map(t=>[ae(t),{...t}])),this._usedQtyText={})}_rangeError(e,t){let i=this.lang;return n("settings_value_out_of_range",i).replace("{min}",C(e,i,{maximumFractionDigits:2})).replace("{max}",C(t,i,{maximumFractionDigits:2}))}_toggleCheck(e){let t=String(e);this._checklistState={...this._checklistState,[t]:!this._checklistState[t]}}_setFeedback(e){this._feedback=e}async _complete(){if(this._loading||this._photos.uploading)return;this._error="",this._photos.clearError();let e={type:"maintenance_supporter/task/complete",entry_id:this.entryId,task_id:this.taskId},t=this._notes.trim();if(t&&(e.notes=t),this._cost){let d=parseFloat(this._cost);isNaN(d)||(e.cost=d)}let i=et(this._duration);if(i!==null&&(e.duration=i),this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photos.photos.length>0&&(e.photo_doc_ids=this._photos.ids),this.viaTagScan&&(e.via_tag_scan=!0),this._completedAt){if(Q(this._completedAt)>Date.now()){this._error=n("completed_at_future_error",this.lang);return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let d={};for(let p of this.readings){let _=(this._readingValues[p.id]??"").trim();if(_==="")continue;let m=parseFloat(_.replace(",","."));isNaN(m)||(d[p.id]=m)}Object.keys(d).length>0&&(e.reading_values=d)}else if(this._readingValue!==""){let d=parseFloat(this._readingValue);isNaN(d)||(e.reading_value=d)}if(this.restockDefault!==null&&this._restockQty.trim()!==""){let d=parseFloat(this._restockQty.replace(",","."));if(!Number.isFinite(d)||dZe[1]){this._error=this._rangeError(...Ze);return}e.restock_quantity=d}if(this.parts.length>0){let d=[];for(let[p,_]of Object.entries(this._usedParts)){let m=this._usedQtyText[p],f=m===void 0?_.quantity:parseFloat(m.replace(",","."));if(!Number.isFinite(f)||fit[1]){this._error=this._rangeError(...it);return}d.push({..._,quantity:f})}e.used_parts=d.map(p=>p.entry_id?{part_id:p.part_id,quantity:p.quantity,entry_id:p.entry_id}:{part_id:p.part_id,quantity:p.quantity})}let a=await j(this,e,{busy:d=>{this._loading=d},lang:this.lang,fallbackKey:"save_error",onError:d=>{this._error=d}});if(a===void 0)return;this._photos.markAttached(),this._open=!1;let o={entryId:this.entryId,taskId:this.taskId,taskName:this.taskName,undo:a?.undo===!0};this.dispatchEvent(new CustomEvent("task-completed",{detail:o}))}_renderReadingField(e,t){let i=this._completedAt?Q(this._completedAt):NaN,a=Ps(this.readingHistory,e.id,isNaN(i)?void 0:i),o=e.unit||this.readingUnit,d=(this._readingValues[e.id]??"").trim(),p=d===""?NaN:parseFloat(d.replace(",",".")),_=a!==void 0&&!isNaN(p)&&p`:u} + `}};c([v({type:String})],ee.prototype,"lang",2),c([v({type:Boolean})],ee.prototype,"disabled",2),c([v({type:Boolean})],ee.prototype,"busy",2),c([v({type:String})],ee.prototype,"accept",2),c([v({type:Boolean})],ee.prototype,"showCamera",2),c([v({type:Boolean})],ee.prototype,"showGallery",2),c([v({type:Boolean})],ee.prototype,"compact",2),c([v({type:Number})],ee.prototype,"remaining",2),c([h()],ee.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",ee)});var st,$,Vn=y(()=>{"use strict";I();F();je();T();ze();Z();St();di();Gt();or();pr();pi();tt();hi();Ct();Ct();st=ke,$=class extends S{constructor(){super(...arguments);this.entryId="";this.taskId="";this.taskName="";this.lang="en";this.checklist=[];this.adaptiveEnabled=!1;this.taskType="";this.readingUnit="";this.readings=[];this.readingHistory=[];this.restockDefault=null;this.restockUnitCost=null;this.restockPackage="";this.currencySymbol="";this.partsCostMode="purchase";this.parts=[];this.consumesParts=[];this.consumesInfo=[];this.requiredFields=[];this.phaseLabel="";this.requireTagScan=!1;this.viaTagScan=!1;this._open=!1;this._notes="";this._cost="";this._duration="";this._loading=!1;this._error="";this._checklistState={};this._feedback="needed";this._photos=new rt(this,{entryId:()=>this.entryId,hass:()=>this.hass});this._readingValue="";this._readingValues={};this._restockQty="";this._completedAt="";this._usedParts={};this._usedQtyText={};this.checklistPrefill={}}open(e={}){this._open||(this._open=!0,this.viaTagScan=!!e.viaTagScan,this._notes="",this._cost="",this._duration="",this._error="",this._checklistState=Object.fromEntries(this.checklist.map((t,i)=>[String(i),!!this.checklistPrefill[t]]).filter(([,t])=>t)),this._feedback="needed",this._photos.reset(),this._readingValue="",this._readingValues={},this._restockQty=this.restockDefault!==null?String(this.restockDefault):"",this._completedAt="",this._usedParts=Object.fromEntries(this.consumesParts.map(t=>[ae(t),{...t}])),this._usedQtyText={})}_rangeError(e,t){let i=this.lang;return a("settings_value_out_of_range",i).replace("{min}",C(e,i,{maximumFractionDigits:2})).replace("{max}",C(t,i,{maximumFractionDigits:2}))}_toggleCheck(e){let t=String(e);this._checklistState={...this._checklistState,[t]:!this._checklistState[t]}}_setFeedback(e){this._feedback=e}async _complete(){if(this._loading||this._photos.uploading)return;this._error="",this._photos.clearError();let e={type:"maintenance_supporter/task/complete",entry_id:this.entryId,task_id:this.taskId},t=this._notes.trim();if(t&&(e.notes=t),this._cost){let d=parseFloat(this._cost);isNaN(d)||(e.cost=d)}let i=it(this._duration);if(i!==null&&(e.duration=i),this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photos.photos.length>0&&(e.photo_doc_ids=this._photos.ids),this.viaTagScan&&(e.via_tag_scan=!0),this._completedAt){if(Q(this._completedAt)>Date.now()){this._error=a("completed_at_future_error",this.lang);return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let d={};for(let p of this.readings){let _=(this._readingValues[p.id]??"").trim();if(_==="")continue;let m=parseFloat(_.replace(",","."));isNaN(m)||(d[p.id]=m)}Object.keys(d).length>0&&(e.reading_values=d)}else if(this._readingValue!==""){let d=parseFloat(this._readingValue);isNaN(d)||(e.reading_value=d)}if(this.restockDefault!==null&&this._restockQty.trim()!==""){let d=parseFloat(this._restockQty.replace(",","."));if(!Number.isFinite(d)||dXe[1]){this._error=this._rangeError(...Xe);return}e.restock_quantity=d}if(this.parts.length>0){let d=[];for(let[p,_]of Object.entries(this._usedParts)){let m=this._usedQtyText[p],f=m===void 0?_.quantity:parseFloat(m.replace(",","."));if(!Number.isFinite(f)||fst[1]){this._error=this._rangeError(...st);return}d.push({..._,quantity:f})}e.used_parts=d.map(p=>p.entry_id?{part_id:p.part_id,quantity:p.quantity,entry_id:p.entry_id}:{part_id:p.part_id,quantity:p.quantity})}let n=await D(this,e,{busy:d=>{this._loading=d},lang:this.lang,fallbackKey:"save_error",onError:d=>{this._error=d}});if(n===void 0)return;this._photos.markAttached(),this._open=!1;let o={entryId:this.entryId,taskId:this.taskId,taskName:this.taskName,undo:n?.undo===!0};this.dispatchEvent(new CustomEvent("task-completed",{detail:o}))}_renderReadingField(e,t){let i=this._completedAt?Q(this._completedAt):NaN,n=Qs(this.readingHistory,e.id,isNaN(i)?void 0:i),o=e.unit||this.readingUnit,d=(this._readingValues[e.id]??"").trim(),p=d===""?NaN:parseFloat(d.replace(",",".")),_=n!==void 0&&!isNaN(p)&&p ${e.name}${o?` (${o})`:""} {this._readingValues={...this._readingValues,[e.id]:f.target.value}}} /> - ${_?l`${n("reading_below_last",t).replace("{value}",m)}`:h} - `}get _missingRequired(){let e={notes:this._notes.trim()!=="",cost:this._cost.trim()!=="",duration:this._duration.trim()!=="",photo:this._photos.photos.length>0,user:!!this.hass?.user};return this.requiredFields.filter(t=>!e[t])}_demands(e){return this.requiredFields.includes(e)}_req(e){return this._demands(e)?l``:h}_purchaseSuggestion(){if(this.restockDefault===null)return null;let e=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(e)||e<=0?null:Math.round(this.restockUnitCost*e*100)/100}_partsValue(){if(this.restockDefault!==null||!this.parts.length)return null;let e=0,t=!1;for(let i of Object.values(this._usedParts)){let a=this.parts.find(d=>ae({part_id:d.id,entry_id:d.entry_id})===ae(i)),o=Gr(a);o!==null&&(e+=o*(i.quantity||1),t=!0)}return t?Math.round(e*100)/100:null}_renderCostSuggestion(e){let t=this._purchaseSuggestion();if(this.restockDefault!==null){let d=this.partsCostMode==="use"?l`
${n("cost_purchase_use_hint",e)}
`:h;if(this._cost.trim()!==""||t==null||t<=0)return d;let p=J(t,this.currencySymbol,e);return l`${d}`}let i=this._partsValue();if(i==null||i<=0)return h;let a=J(i,this.currencySymbol,e),o=this.partsCostMode==="use"?"cost_parts_booked":"cost_parts_info";return l`
${n(o,e).replace("{amount}",a)}
`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=`${ts()}:00`}render(){if(!this._open)return l``;let e=this.lang||this.hass?.language||"en",t=this._error||this._photos.errorText(e);return l` + >${a("cost_from_parts",e).replace("{amount}",p)}${d}`}let i=this._partsValue();if(i==null||i<=0)return u;let n=J(i,this.currencySymbol,e),o=this.partsCostMode==="use"?"cost_parts_booked":"cost_parts_info";return l`
${a(o,e).replace("{amount}",n)}
`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=`${ys()}:00`}render(){if(!this._open)return l``;let e=this.lang||this.hass?.language||"en",t=this._error||this._photos.errorText(e);return l` -
${n("complete_title",e)}${this.taskName}
- ${this.phaseLabel?l`
${n("phase_current",e)}: ${this.phaseLabel}
`:h} - ${this.requireTagScan&&!this.viaTagScan?l`
${n("require_tag_scan_hint",e)}
`:h} +
${a("complete_title",e)}${this.taskName}
+ ${this.phaseLabel?l`
${a("phase_current",e)}: ${this.phaseLabel}
`:u} + ${this.requireTagScan&&!this.viaTagScan?l`
${a("require_tag_scan_hint",e)}
`:u}
- ${t?l`
${t}
`:h} + ${t?l`
${t}
`:u} ${this.checklist.length>0?l`
- - ${this.checklist.map((i,a)=>l` -
- `:h} + `:u} ${this.readings.length>0?l`
- ${n("readings_section",e)} + ${a("readings_section",e)} ${this.readings.map(i=>this._renderReadingField(i,e))}
`:this.taskType==="reading"?l` `:h} + `:u} ${this.parts.length?l`
- ${n("complete_parts_used",e)} - ${this.parts.map(i=>{let a=ae({part_id:i.id,entry_id:i.entry_id}),o=this._usedParts[a],d=o!==void 0,p=i.entry_id?{part_id:i.id,quantity:1,entry_id:i.entry_id}:{part_id:i.id,quantity:1};return l`
+ ${a("complete_parts_used",e)} + ${this.parts.map(i=>{let n=ae({part_id:i.id,entry_id:i.entry_id}),o=this._usedParts[n],d=o!==void 0,p=i.entry_id?{part_id:i.id,quantity:1,entry_id:i.entry_id}:{part_id:i.id,quantity:1};return l`
- ${d?l`{let m=_.target.value;this._usedQtyText={...this._usedQtyText,[a]:m};let f=parseFloat(m.replace(",","."));Number.isFinite(f)&&f>=it[0]&&(this._usedParts={...this._usedParts,[a]:{...p,quantity:f}})}} />`:h} + ${d?l`{let m=_.target.value;this._usedQtyText={...this._usedQtyText,[n]:m};let f=parseFloat(m.replace(",","."));Number.isFinite(f)&&f>=st[0]&&(this._usedParts={...this._usedParts,[n]:{...p,quantity:f}})}} />`:u}
`})}
`:this.consumesInfo.length?l`
${this.consumesInfo.map(i=>l`
${i}
`)} -
`:h} +
`:u} ${this.restockDefault!==null?l` `:h} + `:u}
- ${this._demands("cost")?n("cost",e):n("cost_optional",e)}${this._req("cost")} + ${this._demands("cost")?a("cost",e):a("cost_optional",e)}${this._req("cost")} this._cost=i.detail.value}> ${this._renderCostSuggestion(e)}
- ${n("completed_at_optional",e)} + ${a("completed_at_optional",e)} ${this._completedAt?l`this._completedAt=i.detail.value} >`:l``}
- ${this._demands("photo")?n("completion_photos",e):n("completion_photos_optional",e)}${this._req("photo")} + ${this._demands("photo")?a("completion_photos",e):a("completion_photos_optional",e)}${this._req("photo")} ${this._photos.photos.length>0?l`
${this._photos.photos.map(i=>l`
+ title="${a("remove",e)}">✕
`)} -
`:h} - ${this._photos.full?l`
${n("photos_limit",e).replace("{max}",String(this._photos.max))}
`:l``:u} + ${this._photos.full?l`
${a("photos_limit",e).replace("{max}",String(this._photos.max))}
`:l`this._photos.addFiles(i.detail.files)} >`}
${this.adaptiveEnabled?l` - `:h} + `:u}
- ${n("cancel",e)} + ${a("cancel",e)} 0} - title=${this._photos.uploading?n("uploading",e):this._missingRequired.length?this._missingRequired.map(i=>n("err_required",e).replace("{field}",n(Tt[i]??i,e))).join(" \xB7 "):""} + title=${this._photos.uploading?a("uploading",e):this._missingRequired.length?this._missingRequired.map(i=>a("err_required",e).replace("{field}",a(At[i]??i,e))).join(" \xB7 "):""} > - ${this._loading?n("completing",e):n("complete",e)} + ${this._loading?a("completing",e):a("complete",e)}
- `}};$.styles=[Qe,di,E` + `}};$.styles=[Je,gi,E` .req-mark { color: var(--error-color, #f44336); margin-left: 2px; @@ -3699,11 +3716,11 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" color: var(--text-primary-color, #fff); border-color: var(--primary-color); } - `],c([v({attribute:!1})],$.prototype,"hass",2),c([v()],$.prototype,"entryId",2),c([v()],$.prototype,"taskId",2),c([v()],$.prototype,"taskName",2),c([v()],$.prototype,"lang",2),c([v({type:Array})],$.prototype,"checklist",2),c([v({type:Boolean})],$.prototype,"adaptiveEnabled",2),c([v()],$.prototype,"taskType",2),c([v()],$.prototype,"readingUnit",2),c([v({attribute:!1})],$.prototype,"readings",2),c([v({attribute:!1})],$.prototype,"readingHistory",2),c([v({attribute:!1})],$.prototype,"restockDefault",2),c([v({attribute:!1})],$.prototype,"restockUnitCost",2),c([v({attribute:!1})],$.prototype,"restockPackage",2),c([v()],$.prototype,"currencySymbol",2),c([v({attribute:!1})],$.prototype,"partsCostMode",2),c([v({attribute:!1})],$.prototype,"parts",2),c([v({attribute:!1})],$.prototype,"consumesParts",2),c([v({type:Array})],$.prototype,"consumesInfo",2),c([v({type:Array})],$.prototype,"requiredFields",2),c([v()],$.prototype,"phaseLabel",2),c([v({type:Boolean})],$.prototype,"requireTagScan",2),c([v({type:Boolean})],$.prototype,"viaTagScan",2),c([u()],$.prototype,"_open",2),c([u()],$.prototype,"_notes",2),c([u()],$.prototype,"_cost",2),c([u()],$.prototype,"_duration",2),c([u()],$.prototype,"_loading",2),c([u()],$.prototype,"_error",2),c([u()],$.prototype,"_checklistState",2),c([u()],$.prototype,"_feedback",2),c([u()],$.prototype,"_readingValue",2),c([u()],$.prototype,"_readingValues",2),c([u()],$.prototype,"_restockQty",2),c([u()],$.prototype,"_completedAt",2),c([u()],$.prototype,"_usedParts",2),c([u()],$.prototype,"_usedQtyText",2),c([v({attribute:!1})],$.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",$)});function qo(s,r){s.key!=="Escape"||s.defaultPrevented||s.composedPath().some(e=>e instanceof Element&&e.localName==="ms-camera-capture")||(s.preventDefault(),s.stopPropagation(),r())}function st(s,r){return l` + `],c([v({attribute:!1})],$.prototype,"hass",2),c([v()],$.prototype,"entryId",2),c([v()],$.prototype,"taskId",2),c([v()],$.prototype,"taskName",2),c([v()],$.prototype,"lang",2),c([v({type:Array})],$.prototype,"checklist",2),c([v({type:Boolean})],$.prototype,"adaptiveEnabled",2),c([v()],$.prototype,"taskType",2),c([v()],$.prototype,"readingUnit",2),c([v({attribute:!1})],$.prototype,"readings",2),c([v({attribute:!1})],$.prototype,"readingHistory",2),c([v({attribute:!1})],$.prototype,"restockDefault",2),c([v({attribute:!1})],$.prototype,"restockUnitCost",2),c([v({attribute:!1})],$.prototype,"restockPackage",2),c([v()],$.prototype,"currencySymbol",2),c([v({attribute:!1})],$.prototype,"partsCostMode",2),c([v({attribute:!1})],$.prototype,"parts",2),c([v({attribute:!1})],$.prototype,"consumesParts",2),c([v({type:Array})],$.prototype,"consumesInfo",2),c([v({type:Array})],$.prototype,"requiredFields",2),c([v()],$.prototype,"phaseLabel",2),c([v({type:Boolean})],$.prototype,"requireTagScan",2),c([v({type:Boolean})],$.prototype,"viaTagScan",2),c([h()],$.prototype,"_open",2),c([h()],$.prototype,"_notes",2),c([h()],$.prototype,"_cost",2),c([h()],$.prototype,"_duration",2),c([h()],$.prototype,"_loading",2),c([h()],$.prototype,"_error",2),c([h()],$.prototype,"_checklistState",2),c([h()],$.prototype,"_feedback",2),c([h()],$.prototype,"_readingValue",2),c([h()],$.prototype,"_readingValues",2),c([h()],$.prototype,"_restockQty",2),c([h()],$.prototype,"_completedAt",2),c([h()],$.prototype,"_usedParts",2),c([h()],$.prototype,"_usedQtyText",2),c([v({attribute:!1})],$.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",$)});function ol(s,r){s.key!=="Escape"||s.defaultPrevented||s.composedPath().some(e=>e instanceof Element&&e.localName==="ms-camera-capture")||(s.preventDefault(),s.stopPropagation(),r())}function at(s,r){return l`
- `}function nt(s){s?.querySelector(".dialog")?.focus({preventScroll:!0})}var rt,pi=y(()=>{"use strict";I();rt=E` + @keydown=${e=>ol(e,s)}>${r}
+ `}function ot(s){s?.querySelector(".dialog")?.focus({preventScroll:!0})}var nt,fi=y(()=>{"use strict";I();nt=E` .backdrop { position: fixed; inset: 0; z-index: 100; background: rgba(0,0,0,0.5); @@ -3723,7 +3740,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" } /* Focused programmatically on open (so Escape works at once) — no ring. */ .dialog:focus { outline: none; } -`});var V,Cn=y(()=>{"use strict";I();F();T();V=class extends S{constructor(){super(...arguments);this._open=!1;this._title="";this._message="";this._confirmText="";this._danger=!1;this._inputLabel="";this._inputType="";this._options=null;this._inputValue="";this._resolve=null;this._promptResolve=null}confirm(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel="",this._inputType="",this._options=null,this._inputValue="",this._open=!0,new Promise(t=>{this._resolve=t,this._promptResolve=null})}prompt(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel=e.inputLabel||"",this._inputType=e.inputType||"text",this._options=e.options&&e.options.length?e.options:null,this._inputValue=e.inputValue||"",this._open=!0,new Promise(t=>{this._promptResolve=t,this._resolve=null})}_cancel(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!1,value:""}),this._promptResolve=null),this._resolve?.(!1),this._resolve=null}_confirmAction(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!0,value:this._inputValue}),this._promptResolve=null),this._resolve?.(!0),this._resolve=null}render(){if(!this._open)return h;let e=N(this.hass);return l` +`});var V,Gn=y(()=>{"use strict";I();F();T();V=class extends S{constructor(){super(...arguments);this._open=!1;this._title="";this._message="";this._confirmText="";this._danger=!1;this._inputLabel="";this._inputType="";this._options=null;this._inputValue="";this._resolve=null;this._promptResolve=null}confirm(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel="",this._inputType="",this._options=null,this._inputValue="",this._open=!0,new Promise(t=>{this._resolve=t,this._promptResolve=null})}prompt(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel=e.inputLabel||"",this._inputType=e.inputType||"text",this._options=e.options&&e.options.length?e.options:null,this._inputValue=e.inputValue||"",this._open=!0,new Promise(t=>{this._promptResolve=t,this._resolve=null})}_cancel(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!1,value:""}),this._promptResolve=null),this._resolve?.(!1),this._resolve=null}_confirmAction(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!0,value:this._inputValue}),this._promptResolve=null),this._resolve?.(!0),this._resolve=null}render(){if(!this._open)return u;let e=N(this.hass);return l`
${this._title}
@@ -3744,11 +3761,11 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" .value=${this._inputValue} @input=${t=>this._inputValue=t.target.value} />`} - `:h} + `:u}
- ${n("cancel",e)} + ${a("cancel",e)}
- `}};V.styles=[Qe,E` + `}};V.styles=[Je,E` .dialog-title { font-size: 18px; font-weight: 500; @@ -3787,7 +3804,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" ha-button.danger { --mdc-theme-primary: var(--error-color, #f44336); } - `],c([v({attribute:!1})],V.prototype,"hass",2),c([u()],V.prototype,"_open",2),c([u()],V.prototype,"_title",2),c([u()],V.prototype,"_message",2),c([u()],V.prototype,"_confirmText",2),c([u()],V.prototype,"_danger",2),c([u()],V.prototype,"_inputLabel",2),c([u()],V.prototype,"_inputType",2),c([u()],V.prototype,"_options",2),c([u()],V.prototype,"_inputValue",2);customElements.get("maintenance-confirm-dialog")||customElements.define("maintenance-confirm-dialog",V)});function Ho(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function ze(s,r){let e=Ho(),t=e.querySelector(`${In}[${Rn}]`);return t||(t=document.createElement(In),t.setAttribute(Rn,""),e.appendChild(t)),t.hass=s,t.confirm(r)}var In,Rn,ui=y(()=>{"use strict";Cn();In="maintenance-confirm-dialog",Rn="data-ms-lovelace-confirm"});function Pn(s,r,e){let t=new Blob([s],{type:e}),i=URL.createObjectURL(t),a=document.createElement("a");a.href=i,a.download=r,a.target="_blank",a.rel="noopener",a.style.display="none",document.body.appendChild(a),a.dispatchEvent(new MouseEvent("click")),document.body.removeChild(a),setTimeout(()=>URL.revokeObjectURL(i),6e4)}var nr=y(()=>{"use strict"});async function Oo(s,r,e=300){return(await s.connection.sendMessagePromise({type:"auth/sign_path",path:r,expires:e})).path}async function Ln(s,r,e=300){return Oo(s,`/api/maintenance_supporter/document/${r}`,e)}var Nn=y(()=>{"use strict";nr()});var Ee,ar=y(()=>{"use strict";I();F();Nn();Ee=class extends S{constructor(){super(...arguments);this.docId="";this._url="";this._failed=!1;this._signedFor=""}updated(){this.hass&&this.docId&&this._signedFor!==this.docId&&(this._signedFor=this.docId,this._url="",this._failed=!1,this._sign())}async _sign(){try{this._url=await Ln(this.hass,this.docId)}catch{this._failed=!0}}render(){return this._failed||!this.docId?h:this._url?l` + `],c([v({attribute:!1})],V.prototype,"hass",2),c([h()],V.prototype,"_open",2),c([h()],V.prototype,"_title",2),c([h()],V.prototype,"_message",2),c([h()],V.prototype,"_confirmText",2),c([h()],V.prototype,"_danger",2),c([h()],V.prototype,"_inputLabel",2),c([h()],V.prototype,"_inputType",2),c([h()],V.prototype,"_options",2),c([h()],V.prototype,"_inputValue",2);customElements.get("maintenance-confirm-dialog")||customElements.define("maintenance-confirm-dialog",V)});function ll(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function Ue(s,r){let e=ll(),t=e.querySelector(`${Kn}[${Yn}]`);return t||(t=document.createElement(Kn),t.setAttribute(Yn,""),e.appendChild(t)),t.hass=s,t.confirm(r)}var Kn,Yn,vi=y(()=>{"use strict";Gn();Kn="maintenance-confirm-dialog",Yn="data-ms-lovelace-confirm"});function Qn(s,r,e){let t=new Blob([s],{type:e}),i=URL.createObjectURL(t),n=document.createElement("a");n.href=i,n.download=r,n.target="_blank",n.rel="noopener",n.style.display="none",document.body.appendChild(n),n.dispatchEvent(new MouseEvent("click")),document.body.removeChild(n),setTimeout(()=>URL.revokeObjectURL(i),6e4)}var mr=y(()=>{"use strict"});async function cl(s,r,e=300){return(await s.connection.sendMessagePromise({type:"auth/sign_path",path:r,expires:e})).path}async function Zn(s,r,e=300){return cl(s,`/api/maintenance_supporter/document/${r}`,e)}var Jn=y(()=>{"use strict";mr()});var Ee,gr=y(()=>{"use strict";I();F();Jn();Ee=class extends S{constructor(){super(...arguments);this.docId="";this._url="";this._failed=!1;this._signedFor=""}updated(){this.hass&&this.docId&&this._signedFor!==this.docId&&(this._signedFor=this.docId,this._url="",this._failed=!1,this._sign())}async _sign(){try{this._url=await Zn(this.hass,this.docId)}catch{this._failed=!0}}render(){return this._failed||!this.docId?u:this._url?l` this._failed=!0} /> @@ -3811,107 +3828,107 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" background: var(--secondary-background-color, rgba(0,0,0,0.06)); margin-top: 4px; } - `,c([v({attribute:!1})],Ee.prototype,"hass",2),c([v()],Ee.prototype,"docId",2),c([u()],Ee.prototype,"_url",2),c([u()],Ee.prototype,"_failed",2);customElements.get("maintenance-history-photo")||customElements.define("maintenance-history-photo",Ee)});var K,qn=y(()=>{"use strict";I();F();T();De();Z();Et();pi();tr();ni();ui();Xe();oi();ar();At();At();K=class extends S{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null;this._partOptions=null;this._partQty={};this._partQtyOriginal="";this._openGen=0;this._photos=new tt(this,{entryId:()=>this._draft?.entry_id??"",hass:()=>this.hass});this._photosOriginal="";this._readingRows=[];this._readingText={};this._readingsOriginal=""}get _lang(){return N(this.hass)}openEdit(e){this._openGen++,this._draft={...e},this._originalSnapshot={...e},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._photos.reset(e.photo_doc_ids??[]),this._photosOriginal=JSON.stringify(this._photos.ids),this._seedReadings(e),this._loadPartOptions()}_seedReadings(e){let t=[],i=new Set;for(let o of e.readings??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));for(let o of e.reading_values??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));this._readingRows=t;let a={};for(let o of e.reading_values??[])a[o.id]=String(o.value);this._readingText=a,this._readingsOriginal=JSON.stringify(this._readingNumbers())}_readingNumbers(){let e={};for(let t of this._readingRows){let i=(this._readingText[t.id]??"").trim();if(i==="")continue;let a=parseFloat(i.replace(",","."));isNaN(a)||(e[t.id]=a)}return e}async _loadPartOptions(){let e=this._draft;if(!e)return;let t=this._openGen;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"});if(t!==this._openGen)return;let a=[];for(let d of i.parts||[]){let p=d.entry_id===e.entry_id,_=d.consumers.some(m=>m.entry_id===e.entry_id&&m.task_id===e.task_id);!p&&!_||a.push({part_id:d.part_id,name:d.name,entry_id:d.entry_id,foreign:!p,object_name:d.object_name})}for(let d of e.used_parts||[]){let p=d.entry_id||e.entry_id;a.some(_=>_.part_id===d.part_id&&_.entry_id===p)||a.push({part_id:d.part_id,name:d.name||d.part_id,entry_id:p,foreign:p!==e.entry_id,object_name:null})}let o={};for(let d of e.used_parts||[])o[`${d.entry_id||e.entry_id}:${d.part_id}`]=d.quantity??1;this._partOptions=a,this._partQty=o,this._partQtyOriginal=this._partSelectionKey()}catch{if(t!==this._openGen)return;this._partOptions=[]}}_partSelectionKey(){return JSON.stringify(Object.entries(this._partQty).filter(([,e])=>e>0).sort(([e],[t])=>e.localeCompare(t)))}close(){this._openGen++,this._open=!1,this._error="",this._draft=null,this._originalSnapshot=null,this._photos.discardOrphans()}_set(e,t){this._draft&&(this._draft={...this._draft,[e]:t})}async _delete(){if(!this._draft||!this._originalSnapshot)return;let e=this._lang,i=(this._originalSnapshot.used_parts||[]).filter(p=>p.quantity>0).map(p=>`${C(p.quantity,e)}\xD7 ${p.name||p.part_id}`).join(", ");if(!await ze(this.hass,{title:n("history_delete_entry",e),message:i?`${n("history_delete_confirm_entry",e)} ${n("history_delete_returns_parts",e).replace("{parts}",i)}`:n("history_delete_confirm_entry",e),confirmText:n("delete",e),danger:!0})||!this._draft||!this._originalSnapshot)return;let o=this._draft;this._error="",await this._runWs({type:"maintenance_supporter/task/history/delete",entry_id:o.entry_id,task_id:o.task_id,timestamp:this._originalSnapshot.original_timestamp})!==void 0&&(this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:o.entry_id,task_id:o.task_id,deleted:!0},bubbles:!0,composed:!0})),this.close())}_runWs(e){return j(this,e,{busy:t=>{this._saving=t},onError:t=>{this._error=t}})}async _save(){if(!this._draft||!this._originalSnapshot||this._saving||this._photos.uploading)return;this._error="",this._photos.clearError();let e=this._draft,t=this._originalSnapshot,i={type:"maintenance_supporter/task/history/update",entry_id:e.entry_id,task_id:e.task_id,original_timestamp:t.original_timestamp};if(e.timestamp!==t.timestamp&&(i.timestamp=e.timestamp),e.notes!==t.notes&&(i.notes=e.notes),e.cost!==t.cost&&(i.cost=e.cost),e.duration!==t.duration&&(i.duration=e.duration),e.completed_by!==t.completed_by&&(i.completed_by=e.completed_by),this._partOptions!==null&&this._partSelectionKey()!==this._partQtyOriginal&&(i.used_parts=(this._partOptions||[]).filter(o=>(this._partQty[`${o.entry_id}:${o.part_id}`]||0)>0).map(o=>({part_id:o.part_id,quantity:this._partQty[`${o.entry_id}:${o.part_id}`],...o.foreign?{entry_id:o.entry_id}:{}}))),e.reading_value!==t.reading_value&&(i.reading_value=e.reading_value??null),this._readingRows.length>0&&JSON.stringify(this._readingNumbers())!==this._readingsOriginal){let o=this._readingNumbers(),d={};for(let p of this._readingRows)d[p.id]=o[p.id]??null;i.reading_values=d}if(JSON.stringify(this._photos.ids)!==this._photosOriginal&&(i.photo_doc_ids=this._photos.ids),Object.keys(i).filter(o=>!["type","entry_id","task_id","original_timestamp"].includes(o)).length===0){this.close();return}await this._runWs(i)!==void 0&&(this._photos.markAttached(),this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:e.entry_id,task_id:e.task_id,new_timestamp:e.timestamp},bubbles:!0,composed:!0})),this.close())}render(){if(!this._open||!this._draft)return h;let e=this._lang,t=this._draft,i=this._error||this._photos.errorText(e);return st(()=>this.close(),l` -

${n("history_edit_title",e)}

+ `,c([v({attribute:!1})],Ee.prototype,"hass",2),c([v()],Ee.prototype,"docId",2),c([h()],Ee.prototype,"_url",2),c([h()],Ee.prototype,"_failed",2);customElements.get("maintenance-history-photo")||customElements.define("maintenance-history-photo",Ee)});var K,Xn=y(()=>{"use strict";I();F();T();ze();Z();St();fi();pr();pi();vi();tt();hi();gr();Ct();Ct();K=class extends S{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null;this._partOptions=null;this._partQty={};this._partQtyOriginal="";this._openGen=0;this._photos=new rt(this,{entryId:()=>this._draft?.entry_id??"",hass:()=>this.hass});this._photosOriginal="";this._readingRows=[];this._readingText={};this._readingsOriginal=""}get _lang(){return N(this.hass)}openEdit(e){this._openGen++,this._draft={...e},this._originalSnapshot={...e},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._photos.reset(e.photo_doc_ids??[]),this._photosOriginal=JSON.stringify(this._photos.ids),this._seedReadings(e),this._loadPartOptions()}_seedReadings(e){let t=[],i=new Set;for(let o of e.readings??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));for(let o of e.reading_values??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));this._readingRows=t;let n={};for(let o of e.reading_values??[])n[o.id]=String(o.value);this._readingText=n,this._readingsOriginal=JSON.stringify(this._readingNumbers())}_readingNumbers(){let e={};for(let t of this._readingRows){let i=(this._readingText[t.id]??"").trim();if(i==="")continue;let n=parseFloat(i.replace(",","."));isNaN(n)||(e[t.id]=n)}return e}async _loadPartOptions(){let e=this._draft;if(!e)return;let t=this._openGen;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"});if(t!==this._openGen)return;let n=[];for(let d of i.parts||[]){let p=d.entry_id===e.entry_id,_=d.consumers.some(m=>m.entry_id===e.entry_id&&m.task_id===e.task_id);!p&&!_||n.push({part_id:d.part_id,name:d.name,entry_id:d.entry_id,foreign:!p,object_name:d.object_name})}for(let d of e.used_parts||[]){let p=d.entry_id||e.entry_id;n.some(_=>_.part_id===d.part_id&&_.entry_id===p)||n.push({part_id:d.part_id,name:d.name||d.part_id,entry_id:p,foreign:p!==e.entry_id,object_name:null})}let o={};for(let d of e.used_parts||[])o[`${d.entry_id||e.entry_id}:${d.part_id}`]=d.quantity??1;this._partOptions=n,this._partQty=o,this._partQtyOriginal=this._partSelectionKey()}catch{if(t!==this._openGen)return;this._partOptions=[]}}_partSelectionKey(){return JSON.stringify(Object.entries(this._partQty).filter(([,e])=>e>0).sort(([e],[t])=>e.localeCompare(t)))}close(){this._openGen++,this._open=!1,this._error="",this._draft=null,this._originalSnapshot=null,this._photos.discardOrphans()}_set(e,t){this._draft&&(this._draft={...this._draft,[e]:t})}async _delete(){if(!this._draft||!this._originalSnapshot)return;let e=this._lang,i=(this._originalSnapshot.used_parts||[]).filter(p=>p.quantity>0).map(p=>`${C(p.quantity,e)}\xD7 ${p.name||p.part_id}`).join(", ");if(!await Ue(this.hass,{title:a("history_delete_entry",e),message:i?`${a("history_delete_confirm_entry",e)} ${a("history_delete_returns_parts",e).replace("{parts}",i)}`:a("history_delete_confirm_entry",e),confirmText:a("delete",e),danger:!0})||!this._draft||!this._originalSnapshot)return;let o=this._draft;this._error="",await this._runWs({type:"maintenance_supporter/task/history/delete",entry_id:o.entry_id,task_id:o.task_id,timestamp:this._originalSnapshot.original_timestamp})!==void 0&&(this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:o.entry_id,task_id:o.task_id,deleted:!0},bubbles:!0,composed:!0})),this.close())}_runWs(e){return D(this,e,{busy:t=>{this._saving=t},onError:t=>{this._error=t}})}async _save(){if(!this._draft||!this._originalSnapshot||this._saving||this._photos.uploading)return;this._error="",this._photos.clearError();let e=this._draft,t=this._originalSnapshot,i={type:"maintenance_supporter/task/history/update",entry_id:e.entry_id,task_id:e.task_id,original_timestamp:t.original_timestamp};if(e.timestamp!==t.timestamp&&(i.timestamp=e.timestamp),e.notes!==t.notes&&(i.notes=e.notes),e.cost!==t.cost&&(i.cost=e.cost),e.duration!==t.duration&&(i.duration=e.duration),e.completed_by!==t.completed_by&&(i.completed_by=e.completed_by),this._partOptions!==null&&this._partSelectionKey()!==this._partQtyOriginal&&(i.used_parts=(this._partOptions||[]).filter(o=>(this._partQty[`${o.entry_id}:${o.part_id}`]||0)>0).map(o=>({part_id:o.part_id,quantity:this._partQty[`${o.entry_id}:${o.part_id}`],...o.foreign?{entry_id:o.entry_id}:{}}))),e.reading_value!==t.reading_value&&(i.reading_value=e.reading_value??null),this._readingRows.length>0&&JSON.stringify(this._readingNumbers())!==this._readingsOriginal){let o=this._readingNumbers(),d={};for(let p of this._readingRows)d[p.id]=o[p.id]??null;i.reading_values=d}if(JSON.stringify(this._photos.ids)!==this._photosOriginal&&(i.photo_doc_ids=this._photos.ids),Object.keys(i).filter(o=>!["type","entry_id","task_id","original_timestamp"].includes(o)).length===0){this.close();return}await this._runWs(i)!==void 0&&(this._photos.markAttached(),this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:e.entry_id,task_id:e.task_id,new_timestamp:e.timestamp},bubbles:!0,composed:!0})),this.close())}render(){if(!this._open||!this._draft)return u;let e=this._lang,t=this._draft,i=this._error||this._photos.errorText(e);return at(()=>this.close(),l` +

${a("history_edit_title",e)}

- ${n(t.type,e)||t.type} + ${a(t.type,e)||t.type}
{let o=a.detail.value;o&&this._set("timestamp",o)}} + .label=${a("history_edit_timestamp",e)} + .helper=${ri(e)} + .value=${xs(t.timestamp)} + @value-changed=${n=>{let o=n.detail.value;o&&this._set("timestamp",o)}} >
- ${n("cost",e)} + ${a("cost",e)} {let o=a.detail.value;this._set("cost",o?Number(o):null)}}> + @value-changed=${n=>{let o=n.detail.value;this._set("cost",o?Number(o):null)}}>
${this._renderReadings(t,e)} ${this._partOptions&&this._partOptions.length>0?l`
- ${n("complete_parts_used",e)} - ${this._partOptions.map(a=>{let o=`${a.entry_id}:${a.part_id}`,d=this._partQty[o]||0;return l` + ${a("complete_parts_used",e)} + ${this._partOptions.map(n=>{let o=`${n.entry_id}:${n.part_id}`,d=this._partQty[o]||0;return l` `})}
- `:h} + `:u}
- ${n("completion_photos",e)} + ${a("completion_photos",e)} ${this._photos.photos.length>0?l`
- ${this._photos.photos.map(a=>l` + ${this._photos.photos.map(n=>l`
- - + +
`)} -
`:h} - ${this._photos.full?l`${n("photos_limit",e).replace("{max}",String(this._photos.max))}`:l`this._photos.addFiles(a.detail.files)} +
`:u} + ${this._photos.full?l`${a("photos_limit",e).replace("{max}",String(this._photos.max))}`:l`this._photos.addFiles(n.detail.files)} >`} - ${n("history_edit_photos_hint",e)} + ${a("history_edit_photos_hint",e)} - ${i?l`
${i}
`:h} + ${i?l`
${i}
`:u}
-
- `)}updated(e){e.has("_open")&&this._open&&nt(this.shadowRoot)}_renderReadings(e,t){return this._readingRows.length>0?l` + `)}updated(e){e.has("_open")&&this._open&&ot(this.shadowRoot)}_renderReadings(e,t){return this._readingRows.length>0?l`
- ${n("readings_section",t)} + ${a("readings_section",t)} ${this._readingRows.map(i=>l` `)} -
`:e.reading_value==null&&e.task_type!=="reading"?h:l` + `:e.reading_value==null&&e.task_type!=="reading"?u:l` `}};K.styles=[di,rt,E` + @input=${i=>{let n=i.target.value,o=n===""?NaN:Number(n);this._set("reading_value",isNaN(o)?null:o)}} /> + `}};K.styles=[gi,nt,E` :host { display: contents; --ms-modal-max-height: 90vh; --ms-modal-gap: 12px; } h2 { margin: 0; font-size: 18px; } .entry-type { @@ -4001,7 +4018,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:" } /* the camera / gallery pickers come from photoPickerStyles (ms-photo-picker) */ .photos-hint { font-size: 12px; color: var(--secondary-text-color); } - `],c([v({attribute:!1})],K.prototype,"hass",2),c([u()],K.prototype,"_open",2),c([u()],K.prototype,"_saving",2),c([u()],K.prototype,"_error",2),c([u()],K.prototype,"_draft",2),c([u()],K.prototype,"_partOptions",2),c([u()],K.prototype,"_partQty",2),c([u()],K.prototype,"_readingRows",2),c([u()],K.prototype,"_readingText",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",K)});function Fe(s){return s.replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function or(s){return!s.startsWith("data:image/svg+xml,")&&!s.startsWith("data:image/png;base64,")?"":Fe(s)}function jo(s){return s.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var Y,Hn=y(()=>{"use strict";I();F();T();nr();Y=class extends S{constructor(){super(...arguments);this.lang="";this._open=!1;this._loading=!1;this._error="";this._viewResult=null;this._completeResult=null;this._quickResult=null;this._urlMode="companion";this._entryId="";this._taskId=null;this._objectName="";this._taskName="";this._generateSeq=0}get _dialogLang(){return this.lang||N(this.hass)}openForObject(e,t){this._entryId=e,this._taskId=null,this._objectName=t,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}openForTask(e,t,i,a){this._entryId=e,this._taskId=t,this._objectName=i,this._taskName=a,this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}async _generate(){let e=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null;try{let t={type:"maintenance_supporter/qr/generate",entry_id:this._entryId,url_mode:this._urlMode};this._taskId&&(t.task_id=this._taskId);let i=[this.hass.connection.sendMessagePromise({...t,action:"view"})];this._taskId&&(i.push(this.hass.connection.sendMessagePromise({...t,action:"complete"})),await this._hasQuickCompleteDefaults()&&i.push(this.hass.connection.sendMessagePromise({...t,action:"quick_complete"})));let a=await Promise.all(i);if(e!==this._generateSeq)return;this._viewResult=a[0],a.length>1&&(this._completeResult=a[1]),a.length>2&&(this._quickResult=a[2])}catch(t){if(e!==this._generateSeq)return;let i=t?.code,a=t?.message;this._error=i==="no_url"||typeof a=="string"&&a.includes("No Home Assistant URL")?n("qr_error_no_url",this._dialogLang):n("qr_error",this._dialogLang)}finally{e===this._generateSeq&&(this._loading=!1)}}async _hasQuickCompleteDefaults(){try{let t=((await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId})).tasks||[]).find(i=>i.id===this._taskId);return!!t?.quick_complete_defaults&&Object.keys(t.quick_complete_defaults).length>0}catch{return!1}}_setUrlMode(e){this._urlMode!==e&&(this._urlMode=e,this._generate())}_print(){if(!this._viewResult)return;let e=this._viewResult,t=e.label.task_name?`${e.label.object_name} \u2014 ${e.label.task_name}`:e.label.object_name,i=[e.label.manufacturer,e.label.model].filter(Boolean).join(" "),a=window.open("","_blank","width=600,height=500");if(!a)return;let o=this._dialogLang,d=Fe(t),p=Fe(i),_=!!this._completeResult,m=!!this._quickResult,f=Fe(n("qr_action_view",o)),x=Fe(n("qr_action_complete",o)),w=Fe(n("qr_action_quick_complete",o));a.document.write(` + `],c([v({attribute:!1})],K.prototype,"hass",2),c([h()],K.prototype,"_open",2),c([h()],K.prototype,"_saving",2),c([h()],K.prototype,"_error",2),c([h()],K.prototype,"_draft",2),c([h()],K.prototype,"_partOptions",2),c([h()],K.prototype,"_partQty",2),c([h()],K.prototype,"_readingRows",2),c([h()],K.prototype,"_readingText",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",K)});function Be(s){return s.replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function fr(s){return!s.startsWith("data:image/svg+xml,")&&!s.startsWith("data:image/png;base64,")?"":Be(s)}function dl(s){return s.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var Y,ea=y(()=>{"use strict";I();F();T();mr();Y=class extends S{constructor(){super(...arguments);this.lang="";this._open=!1;this._loading=!1;this._error="";this._viewResult=null;this._completeResult=null;this._quickResult=null;this._urlMode="companion";this._entryId="";this._taskId=null;this._objectName="";this._taskName="";this._generateSeq=0}get _dialogLang(){return this.lang||N(this.hass)}openForObject(e,t){this._entryId=e,this._taskId=null,this._objectName=t,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}openForTask(e,t,i,n){this._entryId=e,this._taskId=t,this._objectName=i,this._taskName=n,this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}async _generate(){let e=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null;try{let t={type:"maintenance_supporter/qr/generate",entry_id:this._entryId,url_mode:this._urlMode};this._taskId&&(t.task_id=this._taskId);let i=[this.hass.connection.sendMessagePromise({...t,action:"view"})];this._taskId&&(i.push(this.hass.connection.sendMessagePromise({...t,action:"complete"})),await this._hasQuickCompleteDefaults()&&i.push(this.hass.connection.sendMessagePromise({...t,action:"quick_complete"})));let n=await Promise.all(i);if(e!==this._generateSeq)return;this._viewResult=n[0],n.length>1&&(this._completeResult=n[1]),n.length>2&&(this._quickResult=n[2])}catch(t){if(e!==this._generateSeq)return;let i=t?.code,n=t?.message;this._error=i==="no_url"||typeof n=="string"&&n.includes("No Home Assistant URL")?a("qr_error_no_url",this._dialogLang):a("qr_error",this._dialogLang)}finally{e===this._generateSeq&&(this._loading=!1)}}async _hasQuickCompleteDefaults(){try{let t=((await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId})).tasks||[]).find(i=>i.id===this._taskId);return!!t?.quick_complete_defaults&&Object.keys(t.quick_complete_defaults).length>0}catch{return!1}}_setUrlMode(e){this._urlMode!==e&&(this._urlMode=e,this._generate())}_print(){if(!this._viewResult)return;let e=this._viewResult,t=e.label.task_name?`${e.label.object_name} \u2014 ${e.label.task_name}`:e.label.object_name,i=[e.label.manufacturer,e.label.model].filter(Boolean).join(" "),n=window.open("","_blank","width=600,height=500");if(!n)return;let o=this._dialogLang,d=Be(t),p=Be(i),_=!!this._completeResult,m=!!this._quickResult,f=Be(a("qr_action_view",o)),x=Be(a("qr_action_complete",o)),w=Be(a("qr_action_quick_complete",o));n.document.write(` ${d}

${$(l.name)}

-

${$(t.title)} \xB7 ${$(t.generated)}: ${$(e(a))}

- ${r.length?`
${r.map(([u,d])=>`
${$(u)}
${$(d)}
`).join("")}
`:""} -

${$(t.tasksHeading)} (${p.length})

+

${$(e.title)} \xB7 ${$(e.generated)}: ${$(t(a))}

+ ${r.length?`
${r.map(([u,p])=>`
${$(u)}
${$(p)}
`).join("")}
`:""} +

${$(e.tasksHeading)} (${d.length})

- - - + + + - ${c||``} - + ${c||``} +
${$(t.colTask)}${$(t.colType)}${$(t.colStatus)}${$(t.colSchedule)}${$(t.colLastDone)}${$(t.colNextDue)}${$(t.colTimes)}${$(t.colCost)}${$(e.colTask)}${$(e.colType)}${$(e.colStatus)}${$(e.colSchedule)}${$(e.colLastDone)}${$(e.colNextDue)}${$(e.colTimes)}${$(e.colCost)}
${$(t.none)}
${$(t.totalCost)}${$(i(n))}
${$(e.none)}
${$(e.totalCost)}${$(i(o))}
- ${l.notes?`
${$(t.notes)}: + ${l.notes?`
${$(e.notes)}: ${$(l.notes)}
`:""} -`}var Bs=60;function qe(l,p=yt()){if(!l)return{kind:"none",days:null,date:null};let t=ri(p,l);return Number.isFinite(t)?t<0?{kind:"expired",days:t,date:l}:t<=Bs?{kind:"expiring",days:t,date:l}:{kind:"valid",days:t,date:l}:{kind:"none",days:null,date:null}}function Ns(l,p){let t=Date.parse(l);return Number.isNaN(t)?l.slice(0,10):p(ai(t,si()))}var L=l=>String(l??"").replace(/[&<>"']/g,p=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[p]);function es(l,p,t,e,i,a,r,c,n,u=[],d=null){let g=[[t.object,L(p)],[t.type,L(t.typeLabel(l.type))],[t.interval,L(i(l))],[t.nextDue,l.next_due?L(e(l.next_due)):"\u2014"],[t.lastDone,l.last_performed?L(e(l.last_performed)):L(t.never)]];l.priority&&l.priority!=="normal"&&g.push([t.priority,L(l.priority)]);let m=(l.checklist||[]).map(y=>`
  • ${L(y)}
  • `).join(""),v=(y,E)=>y?`
    ${L(E)}
    `:"";return` +`}var Fs=60;function Ut(l,d=ye()){if(!l)return{kind:"none",days:null,date:null};let e=li(d,l);return Number.isFinite(e)?e<0?{kind:"expired",days:e,date:l}:e<=Fs?{kind:"expiring",days:e,date:l}:{kind:"valid",days:e,date:l}:{kind:"none",days:null,date:null}}function Us(l,d){let e=Date.parse(l);return Number.isNaN(e)?l.slice(0,10):d(oi(e,ni()))}var L=l=>String(l??"").replace(/[&<>"']/g,d=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[d]);function as(l,d,e,t,i,a,r,c,o,u=[],p=null){let g=[[e.object,L(d)],[e.type,L(e.typeLabel(l.type))],[e.interval,L(i(l))],[e.nextDue,l.next_due?L(t(l.next_due)):"\u2014"],[e.lastDone,l.last_performed?L(t(l.last_performed)):L(e.never)]];l.priority&&l.priority!=="normal"&&g.push([e.priority,L(l.priority)]);let m=(l.checklist||[]).map(y=>`
  • ${L(y)}
  • `).join(""),v=(y,E)=>y?`
    ${L(E)}
    `:"";return` -${L(l.name)} \u2014 ${L(t.title)} +${L(l.name)} \u2014 ${L(e.title)} -

    ${$(t.title)} \u2014 ${$(l.name)}

    -

    ${$(t.generated)} ${$(e(r))} \xB7 ${$(t.entriesLabel(g.length))}

    +

    ${$(e.title)} \u2014 ${$(l.name)}

    +

    ${$(e.generated)} ${$(t(r))} \xB7 ${$(e.entriesLabel(g.length))}

    ${E?`
    ${E}
    `:""} -${pt} -${c.capped?`

    ${$(t.capNote)}

    `:""} +${pe} +${c.capped?`

    ${$(e.capNote)}

    `:""} -`}var Vs=60,tt=class extends N{constructor(){super(...arguments);this.entryId="";this.object=null;this.tasks=[];this.currencySymbol="\u20AC";this.userName=()=>null;this._full={};this._loading=!1;this._filterTask="";this._from="";this._to="";this._expanded=!1;this._printOpen=!1;this._printLayout="chronological";this._printInclude={...$e};this._printing=!1;this._loadedFor=null;this._loadedSignature="";this._loadSeq=0;this._localeReady=!1}connectedCallback(){super.connectedCallback();try{let t=JSON.parse(Z(A.printOptions)||"null");(t?.layout==="by_task"||t?.layout==="chronological")&&(this._printLayout=t.layout),t?.include&&typeof t.include=="object"&&(this._printInclude={...$e,...t.include})}catch{}}_savePrintOptions(){V(A.printOptions,JSON.stringify({layout:this._printLayout,include:this._printInclude}))}_toggleInclude(t,e){this._printInclude={...this._printInclude,[t]:e},this._savePrintOptions()}get _lang(){return K(this.hass)}updated(t){if(super.updated(t),!this._localeReady&&this.hass&&(this._localeReady=!0,ot(this._lang).then(()=>this.requestUpdate())),this.entryId&&this._loadedFor!==this.entryId)this._loadedFor=this.entryId,this._full={},this._filterTask="",this._from="",this._to="",this._loadedSignature=this._historySignature(),this._loadFullHistories();else if(this.entryId&&t.has("tasks")){let e=this._historySignature();e!==this._loadedSignature&&(this._loadedSignature=e,this._loadFullHistories())}}_historySignature(){return JSON.stringify(this.tasks.map(t=>[t.id,t.history_count??null,t.history??[]]))}async _loadFullHistories(){let t=this.entryId,e=this.tasks,i=++this._loadSeq;if(!e.length){this._full={},this._loading=!1;return}this._loading=!0;let a=await Promise.all(e.map(async r=>{try{let c=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:t,task_id:r.id});return[r.id,c.history??[]]}catch{return[r.id,r.history??[]]}}));this.entryId!==t||i!==this._loadSeq||(this._full=Object.fromEntries(a),this._loading=!1)}get _entries(){return ji(this.tasks.map(t=>({id:t.id,name:t.name,history:this._full[t.id]??t.history??[],ref_no:t.ref_no,reading_unit:t.reading_unit})))}get _capped(){return Object.values(this._full).some(t=>t.length>=$i)}_openTask(t){this.dispatchEvent(new CustomEvent("open-task",{detail:{taskId:t},bubbles:!0,composed:!0}))}async _bookletData(t){let e=this._printInclude,i=this._lang,a=[];if(e.documents||e.photos)try{a=(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/list",entry_id:this.entryId})).documents||[]}catch{a=[]}let r=new Map;e.qr&&this._printLayout==="by_task"&&await Promise.all(this.tasks.map(async u=>{try{let d=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/qr/generate",entry_id:this.entryId,task_id:u.id,url_mode:"server",action:"view"});d.svg_data_uri&&r.set(u.id,d.svg_data_uri)}catch{}}));let c=this.tasks.map(u=>({id:u.id,name:u.name,ref:St(this.object,u),schedule:It(u,i)||null,documents:a.filter(d=>(d.task_ids||[]).includes(u.id)&&!is(d)).map(d=>({title:nt(d),page:d.task_pages?.[u.id]??null,description:d.description||null})),qrDataUri:r.get(u.id)??null})),n={};if(e.photos){let u=[...new Set(t.filter(g=>g.type==="completed").flatMap(g=>g.photoIds))].slice(0,Vs),d=new Map(a.map(g=>[g.id,g]));await Promise.all(u.map(async g=>{let m=d.get(g),v=m&&nt(m)||g.slice(0,8);try{n[g]={name:v,url:new URL(await le(this.hass,g),window.location.origin).href}}catch{n[g]={name:v,url:null}}}))}return{tasks:c,photos:n}}async _print(t){let e=this._lang,i=this.object;if(!i||this._printing)return;let a=de();this._printing=!0;let r;try{r=await this._bookletData(t)}catch(d){throw a?.close(),d}finally{this._printing=!1}this._printOpen=!1;let c={title:s("service_record_title",e),generated:s("report_generated",e),manufacturer:s("manufacturer",e),model:s("model",e),serial:s("serial_number_label",e),installed:s("installed",e),colDate:s("date",e),colTask:s("task_name",e),colCost:s("cost",e),colDuration:s("duration",e),colNotes:s("notes_label",e),completedBy:s("completed_by",e),totalLabel:s("report_total_cost",e),entriesLabel:d=>`${d} ${s("service_record_entries",e)}`,capNote:s("object_history_cap_note",e),none:"\u2014",readings:s("print_inc_readings",e),parts:s("print_inc_parts",e),photos:s("print_inc_photos",e),documents:s("print_inc_documents",e),checklist:s("print_inc_checklist",e),refNumber:s("ref_number",e),scanHint:s("report_scan_hint",e),page:d=>s("search_page",e).replace("{page}",String(d))},n=t.map(d=>({...d,completedBy:d.completedBy?this.userName(d.completedBy):null,notes:d.notes?ge(d.notes,e):null})),u=rs(i,n,c,d=>d?q(d,e):"",d=>Yt(d,e),d=>U(d,this.currencySymbol,e),new Date().toISOString(),{capped:this._capped,options:{layout:this._printLayout,include:this._printInclude},data:{objectRef:jt(i),tasks:r.tasks,photos:r.photos,fmtNumber:d=>Y(d,e)}});Jt(u,a)}_renderPrintOptions(t){let e=this._lang,i=this._printInclude,a=(c,n,u=!1)=>o` +`}var Ys=60,ee=class extends N{constructor(){super(...arguments);this.entryId="";this.object=null;this.tasks=[];this.currencySymbol="\u20AC";this.userName=()=>null;this._full={};this._loading=!1;this._filterTask="";this._from="";this._to="";this._expanded=!1;this._printOpen=!1;this._printLayout="chronological";this._printInclude={...jt};this._printing=!1;this._loadedFor=null;this._loadedSignature="";this._loadSeq=0;this._localeReady=!1}connectedCallback(){super.connectedCallback();try{let e=JSON.parse(Z(A.printOptions)||"null");(e?.layout==="by_task"||e?.layout==="chronological")&&(this._printLayout=e.layout),e?.include&&typeof e.include=="object"&&(this._printInclude={...jt,...e.include})}catch{}}_savePrintOptions(){V(A.printOptions,JSON.stringify({layout:this._printLayout,include:this._printInclude}))}_toggleInclude(e,t){this._printInclude={...this._printInclude,[e]:t},this._savePrintOptions()}get _lang(){return K(this.hass)}updated(e){if(super.updated(e),!this._localeReady&&this.hass&&(this._localeReady=!0,re(this._lang).then(()=>this.requestUpdate())),this.entryId&&this._loadedFor!==this.entryId)this._loadedFor=this.entryId,this._full={},this._filterTask="",this._from="",this._to="",this._loadedSignature=this._historySignature(),this._loadFullHistories();else if(this.entryId&&e.has("tasks")){let t=this._historySignature();t!==this._loadedSignature&&(this._loadedSignature=t,this._loadFullHistories())}}_historySignature(){return JSON.stringify(this.tasks.map(e=>[e.id,e.history_count??null,e.history??[]]))}async _loadFullHistories(){let e=this.entryId,t=this.tasks,i=++this._loadSeq;if(!t.length){this._full={},this._loading=!1;return}this._loading=!0;let a=await Promise.all(t.map(async r=>{try{let c=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:e,task_id:r.id});return[r.id,c.history??[]]}catch{return[r.id,r.history??[]]}}));this.entryId!==e||i!==this._loadSeq||(this._full=Object.fromEntries(a),this._loading=!1)}get _entries(){return Ei(this.tasks.map(e=>({id:e.id,name:e.name,history:this._full[e.id]??e.history??[],ref_no:e.ref_no,reading_unit:e.reading_unit})))}get _capped(){return Object.values(this._full).some(e=>e.length>=Ti)}_openTask(e){this.dispatchEvent(new CustomEvent("open-task",{detail:{taskId:e},bubbles:!0,composed:!0}))}async _bookletData(e){let t=this._printInclude,i=this._lang,a=[];if(t.documents||t.photos)try{a=(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/list",entry_id:this.entryId})).documents||[]}catch{a=[]}let r=new Map;t.qr&&this._printLayout==="by_task"&&await Promise.all(this.tasks.map(async u=>{try{let p=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/qr/generate",entry_id:this.entryId,task_id:u.id,url_mode:"server",action:"view"});p.svg_data_uri&&r.set(u.id,p.svg_data_uri)}catch{}}));let c=this.tasks.map(u=>({id:u.id,name:u.name,ref:Se(this.object,u),schedule:Ie(u,i)||null,documents:a.filter(p=>(p.task_ids||[]).includes(u.id)&&!rs(p)).map(p=>({title:ne(p),page:p.task_pages?.[u.id]??null,description:p.description||null})),qrDataUri:r.get(u.id)??null})),o={};if(t.photos){let u=[...new Set(e.filter(g=>g.type==="completed").flatMap(g=>g.photoIds))].slice(0,Ys),p=new Map(a.map(g=>[g.id,g]));await Promise.all(u.map(async g=>{let m=p.get(g),v=m&&ne(m)||g.slice(0,8);try{o[g]={name:v,url:new URL(await ct(this.hass,g),window.location.origin).href}}catch{o[g]={name:v,url:null}}}))}return{tasks:c,photos:o}}async _print(e){let t=this._lang,i=this.object;if(!i||this._printing)return;let a=pt();this._printing=!0;let r;try{r=await this._bookletData(e)}catch(p){throw a?.close(),p}finally{this._printing=!1}this._printOpen=!1;let c={title:s("service_record_title",t),generated:s("report_generated",t),manufacturer:s("manufacturer",t),model:s("model",t),serial:s("serial_number_label",t),installed:s("installed",t),colDate:s("date",t),colTask:s("task_name",t),colCost:s("cost",t),colDuration:s("duration",t),colNotes:s("notes_label",t),completedBy:s("completed_by",t),totalLabel:s("report_total_cost",t),entriesLabel:p=>`${p} ${s("service_record_entries",t)}`,capNote:s("object_history_cap_note",t),none:"\u2014",readings:s("print_inc_readings",t),parts:s("print_inc_parts",t),photos:s("print_inc_photos",t),documents:s("print_inc_documents",t),checklist:s("print_inc_checklist",t),refNumber:s("ref_number",t),scanHint:s("report_scan_hint",t),page:p=>s("search_page",t).replace("{page}",String(p))},o=e.map(p=>({...p,completedBy:p.completedBy?this.userName(p.completedBy):null,notes:p.notes?_t(p.notes,t):null})),u=ls(i,o,c,p=>p?q(p,t):"",p=>Ye(p,t),p=>U(p,this.currencySymbol,t),new Date().toISOString(),{capped:this._capped,options:{layout:this._printLayout,include:this._printInclude},data:{objectRef:je(i),tasks:r.tasks,photos:r.photos,fmtNumber:p=>G(p,t)}});Je(u,a)}_renderPrintOptions(e){let t=this._lang,i=this._printInclude,a=(c,o,u=!1)=>n` `,r=this._printLayout==="by_task";return o` - `}render(){let e=this._lang,t=this._entries;if(!t.length&&!this._loading)return h;let i=Ri(t,{taskId:this._filterTask||null,from:this._from||null,to:this._to||null}),{completed:a,totalCost:r}=gt(i),c=this._expanded?i:i.slice(0,15);return n`

    - ${s("object_history_section",t)} + ${s("object_history_section",e)} ${i.length} - ${this._loading?o`${s("loading",t)}`:h} + ${this._loading?n`${s("loading",e)}`:h} {this._printOpen=!this._printOpen}}> - ${s("service_record_print",t)} + ${s("service_record_print",e)}

    ${this._printOpen?this._renderPrintOptions(i):h}
    - {this._filterTask=o.target.value}}> + + ${this.tasks.map(o=>n``)} {this._from=n.detail.value}} + @value-changed=${o=>{this._from=o.detail.value}} > {this._to=n.detail.value}} + @value-changed=${o=>{this._to=o.detail.value}} >
    - ${i.length===0?o`

    ${s("object_history_empty",t)}

    `:o` + ${i.length===0?n`

    ${s("object_history_empty",e)}

    `:n`
    - ${c.map(n=>o` + ${c.map(o=>n`
    - ${q(n.timestamp,t)} - ${s(n.type,t)} - + ${q(o.timestamp,e)} + ${s(o.type,e)} + - ${n.cost!=null?o`${U(n.cost,this.currencySymbol,t)}`:h} - ${n.partsCost!=null?o`${s(n.partsCounted?"history_parts_counted":"history_parts_info",t).replace("{amount}",U(n.partsCost,this.currencySymbol,t))}`:h} - ${n.purchaseCost!=null?o`${s("history_purchase_stock",t).replace("{amount}",U(n.purchaseCost,this.currencySymbol,t))}`:h} - ${n.duration!=null?o`${Yt(n.duration,t)}`:h} + ${o.cost!=null?n`${U(o.cost,this.currencySymbol,e)}`:h} + ${o.partsCost!=null?n`${s(o.partsCounted?"history_parts_counted":"history_parts_info",e).replace("{amount}",U(o.partsCost,this.currencySymbol,e))}`:h} + ${o.purchaseCost!=null?n`${s("history_purchase_stock",e).replace("{amount}",U(o.purchaseCost,this.currencySymbol,e))}`:h} + ${o.duration!=null?n`${Ye(o.duration,e)}`:h} - ${n.notes?o`${ge(n.notes,t)}`:h} + ${o.notes?n`${_t(o.notes,e)}`:h}
    `)}
    - ${i.length>c.length?o`{this._expanded=!0}}> - ${s("show_all",t)} (${i.length}) + ${i.length>c.length?n`{this._expanded=!0}}> + ${s("show_all",e)} (${i.length}) `:h}
    - ${a} ${s("service_record_entries",t)} · ${s("report_total_cost",t)}: - ${U(r,this.currencySymbol,t)} + ${a} ${s("service_record_entries",e)} · ${s("report_total_cost",e)}: + ${U(r,this.currencySymbol,e)}
    - ${this._capped?o`

    ${s("object_history_cap_note",t)}

    `:h} + ${this._capped?n`

    ${s("object_history_cap_note",e)}

    `:h} `}
    - `}};tt.styles=B` + `}};ee.styles=B` .section { margin-top: 28px; } h3 { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; } .count { @@ -3276,7 +3335,7 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} @media (max-width: 640px) { .notes { padding-left: 0; } } - `,_([R({attribute:!1})],tt.prototype,"hass",2),_([R()],tt.prototype,"entryId",2),_([R({attribute:!1})],tt.prototype,"object",2),_([R({attribute:!1})],tt.prototype,"tasks",2),_([R()],tt.prototype,"currencySymbol",2),_([R({attribute:!1})],tt.prototype,"userName",2),_([f()],tt.prototype,"_full",2),_([f()],tt.prototype,"_loading",2),_([f()],tt.prototype,"_filterTask",2),_([f()],tt.prototype,"_from",2),_([f()],tt.prototype,"_to",2),_([f()],tt.prototype,"_expanded",2),_([f()],tt.prototype,"_printOpen",2),_([f()],tt.prototype,"_printLayout",2),_([f()],tt.prototype,"_printInclude",2),_([f()],tt.prototype,"_printing",2);customElements.get("maintenance-object-history-section")||customElements.define("maintenance-object-history-section",tt);async function os(l,p,t,e){try{let i=await l.connection.sendMessagePromise({type:"maintenance_supporter/task/undo",entry_id:p,task_id:t});return{ok:!0,message:s(i?.action_ran?"undo_done_action_ran":"undo_done",e)}}catch(i){let a=i?.code;return a==="changed_since"?{ok:!1,message:s("undo_changed",e)}:a==="nothing_to_undo"?{ok:!1,message:s("undo_nothing",e)}:{ok:!1,message:s("action_error",e)}}}var dt=class dt extends N{constructor(){super(...arguments);this.flat=!1;this._ov=null;this._loading=!1;this._marking=!1;this._error="";this._history=null;this._rosterSort=dt._storedSort();this._typeFilter=null;this._recorded=[];this._access=Ii;this._historyRequested=!1;this._localeReady=!1;this._markAll=async()=>{await this._mark(void 0)};this._repair=async()=>{await this._act({type:"maintenance_supporter/battery_fleet/setup",language:this._lang})};this._loadHistory=async t=>{let e=t.target.open;if(V(A.batteryRosterOpen,e?"1":"0"),!(!e||this._historyRequested)){this._historyRequested=!0;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/overview_history"});this._history=i.series}catch{this._history=null}}}}get _lang(){return K(this.hass)}get _canWrite(){return Nt(this.hass?.user,this._access)}connectedCallback(){super.connectedCallback(),this.hass&&this._load()}updated(t){Bt(this,t),t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,ot(this._lang).then(()=>this.requestUpdate()),_e(this.hass).then(e=>{this._access=e.access}),this._ov===null&&!this._loading&&this._load())}async _load(){this._error="";let t=await P(this,{type:"maintenance_supporter/battery_fleet/overview"},{busy:e=>{this._loading=e},onError:e=>{this._error=e}});t!==void 0&&(this._ov=t)}async _act(t,e){this._marking||(this._error="",await P(this,t,{busy:i=>{this._marking=i},reload:async()=>{e?.(),await this._load()},onError:i=>{this._error=i}}))}async _mark(t){await this._act({type:"maintenance_supporter/battery_fleet/mark_replaced",...t?{entity_ids:t}:{}})}async _setExcluded(t,e){await this._act({type:"maintenance_supporter/battery_fleet/set_excluded",entity_id:t,excluded:e})}async _addBattery(t){let e=t.detail?.value;e&&await this._act({type:"maintenance_supporter/battery_fleet/set_included",entity_id:e,included:!0})}async _setTrackSelf(t){await this._setFleetOption("set_track_self_charging",t.target.checked)}async _setDueWithoutSensor(t){await this._setFleetOption("set_due_without_sensor",t.target.checked)}async _setFleetOption(t,e){await this._act({type:`maintenance_supporter/battery_fleet/${t}`,enabled:e})}_rosterOpen(){return Z(A.batteryRosterOpen)!=="0"}_predictedTitle(t,e){if(t.forecast_overdue)return s("battery_fleet_forecast_overdue",e);let i=this._predictedDate(t.days_until??0);if(t.predicted_source==="trend")return s("battery_fleet_predicted_trend",e).replace("{date}",i).replace("{confidence}",s("cal_confidence_"+(t.prediction_confidence||"medium"),e));if(t.lifetime_months!=null&&t.lifetime_source){let a=s("lifetime_source_"+t.lifetime_source,e).replace("{n}",String(t.lifetime_samples??0));return s("battery_fleet_predicted_typical",e).replace("{date}",i).replace("{months}",String(t.lifetime_months)).replace("{type}",t.battery_type).replace("{source}",a)}return s("battery_fleet_predicted_on",e).replace("{date}",i)}_sparkline(t){let e=this._history?.[t.entity_id];if(!e||e.points.length<2)return h;let i=110,a=24,r=2,c=e.points[0][0],n=e.points[e.points.length-1][0],u=Date.now()/1e3,d=t.status!=="low"&&t.predicted_source==="trend"&&t.days_until!=null?u+t.days_until*86400:null,g=Math.max(n,d??n),m=j=>g===c?r:r+(j-c)/(g-c)*(i-2*r),v=j=>r+(1-Math.min(100,Math.max(0,j))/100)*(a-2*r),y=e.points.map(([j,x])=>`${O(m(j))},${O(v(x))}`).join(" "),E=e.points[e.points.length-1][1],w=O(v(e.threshold));return o`{await this._mark(void 0)};this._repair=async()=>{await this._act({type:"maintenance_supporter/battery_fleet/setup",language:this._lang})};this._loadHistory=async e=>{let t=e.target.open;if(V(A.batteryRosterOpen,t?"1":"0"),!(!t||this._historyRequested)){this._historyRequested=!0;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/overview_history"});this._history=i.series}catch{this._history=null}}}}get _lang(){return K(this.hass)}get _canWrite(){return Ne(this.hass?.user,this._access)}connectedCallback(){super.connectedCallback(),this.hass&&this._load()}updated(e){Be(this,e),e.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,re(this._lang).then(()=>this.requestUpdate()),mt(this.hass).then(t=>{this._access=t.access}),this._ov===null&&!this._loading&&this._load())}async _load(){this._error="";let e=await P(this,{type:"maintenance_supporter/battery_fleet/overview"},{busy:t=>{this._loading=t},onError:t=>{this._error=t}});e!==void 0&&(this._ov=e)}async _act(e,t){this._marking||(this._error="",await P(this,e,{busy:i=>{this._marking=i},reload:async()=>{t?.(),await this._load()},onError:i=>{this._error=i}}))}async _mark(e){await this._act({type:"maintenance_supporter/battery_fleet/mark_replaced",...e?{entity_ids:e}:{}})}async _setExcluded(e,t){await this._act({type:"maintenance_supporter/battery_fleet/set_excluded",entity_id:e,excluded:t})}async _addBattery(e){let t=e.detail?.value;t&&await this._act({type:"maintenance_supporter/battery_fleet/set_included",entity_id:t,included:!0})}async _setTrackSelf(e){await this._setFleetOption("set_track_self_charging",e.target.checked)}async _setDueWithoutSensor(e){await this._setFleetOption("set_due_without_sensor",e.target.checked)}async _setFleetOption(e,t){await this._act({type:`maintenance_supporter/battery_fleet/${e}`,enabled:t})}_rosterOpen(){return Z(A.batteryRosterOpen)!=="0"}_predictedTitle(e,t){if(e.forecast_overdue)return s("battery_fleet_forecast_overdue",t);let i=this._predictedDate(e.days_until??0);if(e.predicted_source==="trend")return s("battery_fleet_predicted_trend",t).replace("{date}",i).replace("{confidence}",s("cal_confidence_"+(e.prediction_confidence||"medium"),t));if(e.lifetime_months!=null&&e.lifetime_source){let a=s("lifetime_source_"+e.lifetime_source,t).replace("{n}",String(e.lifetime_samples??0));return s("battery_fleet_predicted_typical",t).replace("{date}",i).replace("{months}",String(e.lifetime_months)).replace("{type}",e.battery_type).replace("{source}",a)}return s("battery_fleet_predicted_on",t).replace("{date}",i)}_sparkline(e){let t=this._history?.[e.entity_id];if(!t||t.points.length<2)return h;let i=110,a=24,r=2,c=t.points[0][0],o=t.points[t.points.length-1][0],u=Date.now()/1e3,p=e.status!=="low"&&e.predicted_source==="trend"&&e.days_until!=null?u+e.days_until*86400:null,g=Math.max(o,p??o),m=j=>g===c?r:r+(j-c)/(g-c)*(i-2*r),v=j=>r+(1-Math.min(100,Math.max(0,j))/100)*(a-2*r),y=t.points.map(([j,x])=>`${O(m(j))},${O(v(x))}`).join(" "),E=t.points[t.points.length-1][1],w=O(v(t.threshold));return n`${$(t.capNote)}

    `:""} ${s("battery_fleet_sparkline_hint",this._lang)} - ${d!==null?o``:h} -
    `}static _storedSort(){return Z(A.batteryRosterSort)==="name"?"name":"urgency"}_setSort(t){this._rosterSort=t,V(A.batteryRosterSort,t)}_sortedRoster(t){let e=this._typeFilter===null?t:t.filter(a=>a.battery_type===this._typeFilter);if(this._rosterSort==="name")return e;let i=a=>a.status==="low"?-1e3+(a.level??101)/101:a.days_until??1/0;return[...e].sort((a,r)=>i(a)-i(r)||a.device_name.localeCompare(r.device_name))}_predictedDate(t){return q(Tt(yt(),t),this._lang)}_fmtDate(t){return Number.isFinite(t)?q(new Date(t).toISOString(),this._lang):"\u2014"}_shoppingLine(t){return Object.entries(t).map(([e,i])=>o`
    `}_jumpButton(t,e){let i=this._history?.[t.entity_id]?.jump;return!i||this._recorded.includes(t.entity_id)?h:o``}_renderRow(t,e,i){let a=t.available===!1?o`${s("battery_fleet_offline",e)}`:t.no_sensor?o`${s("battery_fleet_no_sensor",e)}`:h,r=`${t.quantity}\xD7 ${t.battery_type}`,c=o`${r}`,n=this._canWrite,u=n&&(i.mark==="always"||t.no_sensor||t.can_mark_replaced);return o` + `}_renderRow(e,t,i){let a=e.available===!1?n`${s("battery_fleet_offline",t)}`:e.no_sensor?n`${s("battery_fleet_no_sensor",t)}`:h,r=`${e.quantity}\xD7 ${e.battery_type}`,c=n`${r}`,o=this._canWrite,u=o&&(i.mark==="always"||e.no_sensor||e.can_mark_replaced);return n`
    - ${t.device_name} - ${i.status?o`${t.no_sensor&&t.status==="low"?s("battery_fleet_status_due",e):s("battery_fleet_status_"+t.status,e)}${c}${a}`:o`${a}${c}`} - ${i.recharge&&t.rechargeable?o`${e.device_name} + ${i.status?n`${e.no_sensor&&e.status==="low"?s("battery_fleet_status_due",t):s("battery_fleet_status_"+e.status,t)}${c}${a}`:n`${a}${c}`} + ${i.recharge&&e.rechargeable?n``:h} - ${i.sparkline?this._sparkline(t):h} - ${this._levelBar(t)} - ${t.level!=null?o`${t.level}%`:h} - ${u?o``:h} - ${i.jump&&n?this._jumpButton(t,e):h} - ${i.predicted&&t.days_until!=null?o`${t.forecast_overdue?o``:h}~${this._predictedDate(t.days_until)}${e.forecast_overdue?n``:h}~${this._predictedDate(e.days_until)}`:h} - ${i.exclude&&n?o``:h}
    - `}render(){let t=this._lang;if(this._loading&&this._ov===null)return o`
    …
    `;let e=this._ov;if(!e)return this._error?o`
    ${this._error}
    `:h;let i=e.low.length;return o` + `}render(){let e=this._lang;if(this._loading&&this._ov===null)return n`
    …
    `;let t=this._ov;if(!t)return this._error?n`
    ${this._error}
    `:h;let i=t.low.length;return n`
    - ${s("battery_fleet_title",t)} + ${s("battery_fleet_title",e)} ${i}
    - ${this._error?o`
    ${this._error}
    `:h} + ${this._error?n`
    ${this._error}
    `:h} - ${e.configured&&e.task_ok===!1?o` + ${t.configured&&t.task_ok===!1?n`
    - ${s("battery_fleet_trigger_lost",t)} - ${this._canWrite?o` - ${s("battery_fleet_repair",t)} + ${s("battery_fleet_trigger_lost",e)} + ${this._canWrite?n` + ${s("battery_fleet_repair",e)} `:h}
    `:h} - ${i===0?o`
    ${s("battery_fleet_none_low",t)}
    `:o` + ${i===0?n`
    ${s("battery_fleet_none_low",e)}
    `:n`
    - ${s("battery_fleet_buy_now",t)} - ${this._shoppingLine(e.needs_now)} + ${s("battery_fleet_buy_now",e)} + ${this._shoppingLine(t.needs_now)}
    - ${e.low.map(a=>this._renderRow(a,t,{recharge:!0,mark:"always",exclude:!0}))} + ${t.low.map(a=>this._renderRow(a,e,{recharge:!0,mark:"always",exclude:!0}))}
    - ${this._canWrite?o`
    + ${this._canWrite?n`
    - ${s("battery_fleet_mark_all",t)} + ${s("battery_fleet_mark_all",e)}
    `:h} `} - ${e.soon.length?o` -
    - ${s("battery_fleet_soon",t)} - ${this._shoppingLine(e.needs_soon)} -
    ${s("battery_fleet_soon_hint",t)}
    -
    -
    - ${e.soon.map(a=>this._renderRow(a,t,{mark:"replaced",predicted:!0}))} + ${t.charging?.length?n` +
    + ${s("battery_fleet_charging",e)} + ${t.charging.map(a=>n` + ${a.name} + ${s("battery_fleet_ready",e).replace("{count}",String(a.stock))} + ${a.restoring>0?n`${s(`part_waiting_${a.reuse}`,e).replace("{count}",String(a.restoring))} + ${this._canWrite?n``:h}`:h} + `)}
    `:h} - ${e.all?.length?o` + ${t.soon.length?n` +
    + ${s("battery_fleet_soon",e)} + ${this._shoppingLine(t.needs_soon)} +
    ${s("battery_fleet_soon_hint",e)}
    +
    +
    + ${t.soon.map(a=>this._renderRow(a,e,{mark:"replaced",predicted:!0}))} +
    + `:h} + ${t.all?.length?n`
    - ${s("battery_fleet_all",t)} (${e.all.length}) + ${s("battery_fleet_all",e)} (${t.all.length})
    - ${this._sortedRoster(e.all).map(a=>this._renderRow(a,t,{status:!0,recharge:!0,sparkline:!0,mark:"replaced",jump:!0,predicted:!0,exclude:!0}))} + ${this._sortedRoster(t.all).map(a=>this._renderRow(a,e,{status:!0,recharge:!0,sparkline:!0,mark:"replaced",jump:!0,predicted:!0,exclude:!0}))}
    -
    ${s("battery_fleet_all_hint",t)}
    - ${this._canWrite?this._renderRosterSettings(e,t):h} +
    ${s("battery_fleet_all_hint",e)}
    + ${this._canWrite?this._renderRosterSettings(t,e):h}
    `:h} - ${this._renderExcluded(e,t)} -
    ${s("battery_fleet_total",t).replace("{n}",String(e.total))}
    + ${this._renderExcluded(t,e)} +
    ${s("battery_fleet_total",e).replace("{n}",String(t.total))}
    - `}_renderRosterSettings(t,e){return o` + `}_renderRosterSettings(e,t){return n`
    - ${s("battery_fleet_add",e)} + ${s("battery_fleet_add",t)} -
    ${s("battery_fleet_add_hint",e)}
    +
    ${s("battery_fleet_add_hint",t)}
    -
    ${s("battery_fleet_track_self_hint",e)}
    +
    ${s("battery_fleet_track_self_hint",t)}
    -
    ${s("battery_fleet_due_without_sensor_hint",e)}
    - `}_renderExcluded(t,e){return o` - ${t.excluded?.length?o` +
    ${s("battery_fleet_due_without_sensor_hint",t)}
    + `}_renderExcluded(e,t){return n` + ${e.excluded?.length?n`
    - ${s("battery_fleet_excluded",e)} - ${t.excluded.map(i=>o` + ${s("battery_fleet_excluded",t)} + ${e.excluded.map(i=>n` ${i.device_name} - ${this._canWrite?o`
    `:h} - `}};dt.styles=B` + `}};de.styles=B` /* The query container of the row layout (see "In a narrow list" below): * the list's own width, not the screen's. */ .bf-card { @@ -3530,6 +3605,46 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} align-items: baseline; gap: 8px; } + .bf-charging { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + margin: 8px 0; + } + .bf-charge-item { + display: inline-flex; + flex-wrap: wrap; + align-items: center; + gap: 6px; + padding: 2px 8px; + border-radius: 12px; + background: var(--secondary-background-color, #eee); + font-size: 13px; + } + .bf-charge-name { + font-weight: 500; + } + .bf-charge-waiting { + color: var(--warning-color, #f57c00); + } + .bf-charged { + display: inline-flex; + align-items: center; + gap: 4px; + font: inherit; + font-size: 12px; + min-height: 28px; + padding: 2px 10px; + border-radius: 14px; + border: 1px solid var(--primary-color); + background: transparent; + color: var(--primary-color); + cursor: pointer; + } + .bf-charged ha-icon { + --mdc-icon-size: 16px; + } .bf-label { font-size: 12px; text-transform: uppercase; @@ -3933,7 +4048,7 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} accent-color: var(--primary-color); margin: 0; } - `,_([R({attribute:!1})],dt.prototype,"hass",2),_([R({type:Boolean})],dt.prototype,"flat",2),_([f()],dt.prototype,"_ov",2),_([f()],dt.prototype,"_loading",2),_([f()],dt.prototype,"_marking",2),_([f()],dt.prototype,"_error",2),_([f()],dt.prototype,"_history",2),_([f()],dt.prototype,"_rosterSort",2),_([f()],dt.prototype,"_typeFilter",2),_([f()],dt.prototype,"_recorded",2),_([f()],dt.prototype,"_access",2);var Ve=dt;customElements.get("maintenance-battery-fleet-section")||customElements.define("maintenance-battery-fleet-section",Ve);var ns=5;function Ws(l,p){let t=[];for(let e=0;eRt(t)).filter(t=>t!==null&&t>=0);return p.length===0?null:p.reduce((t,e)=>t+e,0)/p.length}function Gs(l){let{windowStart:p,windowEnd:t,task:e,entryId:i,objectName:a}=l,r=[],c=(g,m)=>({date:g,entry_id:i,task_id:e.id,task_name:e.name,object_name:a,status:m&&(e.status==="overdue"||e.status==="triggered")?"ok":e.status,days_until_due:m?null:e.days_until_due??null,projected:m,schedule_type:e.schedule_type,interval_days:e.interval_days??null,interval_unit:e.interval_unit??null,responsible_user_id:e.responsible_user_id??null,avg_cost:Ks(e.history),adaptive_enabled:!!e.adaptive_config?.enabled,prediction_confidence:e.threshold_prediction_confidence??null}),n=Math.max(1,Math.round(Ne(e.interval_days,e.interval_unit)));if(e.status==="overdue"||e.status==="triggered"){if(r.push(c(p,!1)),e.schedule_type==="time_based"&&e.interval_days&&e.interval_days>0){let g=Tt(p,n),m=1;for(;g<=t&&m=p&&d<=t)r.push(c(d,!1));else if(d>t)return r;if(e.schedule_type==="time_based"&&e.interval_days&&e.interval_days>0){let g=Tt(d,n),m=r.length;for(;g<=t&&m=p&&(r.push(c(g,!0)),m++),g=Tt(g,n)}return r}function ls(l,p,t,e=null){let i=Ws(p,t),a=i[0],r=i[i.length-1],c=[];for(let u of l){let d=u.object?.name||"",g=u.entry_id,m=u.tasks||[];for(let v of m){if(e&&v.responsible_user_id!==e||v.enabled===!1)continue;let y=Gs({windowStart:a,windowEnd:r,task:v,entryId:g,objectName:d});c.push(...y)}}let n=new Map;for(let u of i)n.set(u,[]);for(let u of c){let d=n.get(u.date);d&&d.push(u)}for(let[,u]of n)u.sort((d,g)=>{let m=Mt(d.status),v=Mt(g.status);if(m!==v)return m-v;if(d.projected!==g.projected)return d.projected?1:-1;let y=d.object_name.localeCompare(g.object_name);return y!==0?y:d.task_name.localeCompare(g.task_name)});return i.map(u=>({date:u,events:n.get(u)??[]}))}var Ys={completed:"ok",reset:"ok",skipped:"due_soon",missed:"overdue",triggered:"triggered",trigger_replaced:"triggered",trigger_removed:"ok"};function je(l,p){return`${l}/${p}`}function cs(l,p,t){let e=ds(p,t)[0],i=[];for(let a of l)for(let r of a.tasks||[]){let c=r.history||[],n=r.history_count??c.length;if(n<=c.length)continue;let u=c.map(m=>Ce(m?.timestamp)).filter(m=>!!m),d=u.length?u.reduce((m,v)=>m>>0).toString(36)}function ds(l,p){let t=[];for(let e=p-1;e>=0;e--)t.push(Tt(l,-e));return t}function ps(l,p,t,e=null,i={}){let a=ds(p,t),r=a[0],c=a[a.length-1],n=new Map;for(let d of a)n.set(d,[]);for(let d of l){let g=d.object?.name||"",m=d.entry_id,v=d.tasks||[];for(let y of v){if(e&&y.responsible_user_id!==e)continue;let E=i[je(m,y.id)]??(y.history||[]);for(let w of E){if(typeof w?.timestamp!="string")continue;let j=Ce(w.timestamp);if(!j||jc)continue;let x=n.get(j);if(!x)continue;let M=w.type??"completed";x.push({date:j,entry_id:m,task_id:y.id,task_name:y.name,object_name:g,status:Ys[M]??"ok",days_until_due:null,projected:!1,schedule_type:y.schedule_type,interval_days:y.interval_days??null,responsible_user_id:y.responsible_user_id??null,avg_cost:Rt(w),adaptive_enabled:!!y.adaptive_config?.enabled,prediction_confidence:null,history_timestamp:w.timestamp,history_type:M,history_cost:Rt(w),history_notes:typeof w.notes=="string"?w.notes:null,history_duration:typeof w.duration=="number"?w.duration:null})}}}let u={completed:0,reset:1,skipped:2,triggered:3,trigger_replaced:4};for(let[,d]of n)d.sort((g,m)=>{let v=u[g.history_type??""]??99,y=u[m.history_type??""]??99;if(v!==y)return v-y;let E=g.object_name.localeCompare(m.object_name);return E!==0?E:g.task_name.localeCompare(m.task_name)});return a.map(d=>({date:d,events:n.get(d)??[]}))}var hs=B` + `,_([R({attribute:!1})],de.prototype,"hass",2),_([R({type:Boolean})],de.prototype,"flat",2),_([f()],de.prototype,"_ov",2),_([f()],de.prototype,"_loading",2),_([f()],de.prototype,"_marking",2),_([f()],de.prototype,"_error",2),_([f()],de.prototype,"_history",2),_([f()],de.prototype,"_rosterSort",2),_([f()],de.prototype,"_typeFilter",2),_([f()],de.prototype,"_recorded",2),_([f()],de.prototype,"_access",2);var Kt=de;customElements.get("maintenance-battery-fleet-section")||customElements.define("maintenance-battery-fleet-section",Kt);var ds=5;function Qs(l,d){let e=[];for(let t=0;tRe(e)).filter(e=>e!==null&&e>=0);return d.length===0?null:d.reduce((e,t)=>e+t,0)/d.length}function Xs(l){let{windowStart:d,windowEnd:e,task:t,entryId:i,objectName:a}=l,r=[],c=(g,m)=>({date:g,entry_id:i,task_id:t.id,task_name:t.name,object_name:a,status:m&&(t.status==="overdue"||t.status==="triggered")?"ok":t.status,days_until_due:m?null:t.days_until_due??null,projected:m,schedule_type:t.schedule_type,interval_days:t.interval_days??null,interval_unit:t.interval_unit??null,responsible_user_id:t.responsible_user_id??null,avg_cost:Js(t.history),adaptive_enabled:!!t.adaptive_config?.enabled,prediction_confidence:t.threshold_prediction_confidence??null}),o=Math.max(1,Math.round(Ft(t.interval_days,t.interval_unit)));if(t.status==="overdue"||t.status==="triggered"){if(r.push(c(d,!1)),t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let g=Te(d,o),m=1;for(;g<=e&&m=d&&p<=e)r.push(c(p,!1));else if(p>e)return r;if(t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let g=Te(p,o),m=r.length;for(;g<=e&&m=d&&(r.push(c(g,!0)),m++),g=Te(g,o)}return r}function ps(l,d,e,t=null){let i=Qs(d,e),a=i[0],r=i[i.length-1],c=[];for(let u of l){let p=u.object?.name||"",g=u.entry_id,m=u.tasks||[];for(let v of m){if(t&&!tt(v,t)||v.enabled===!1)continue;let y=Xs({windowStart:a,windowEnd:r,task:v,entryId:g,objectName:p});c.push(...y)}}let o=new Map;for(let u of i)o.set(u,[]);for(let u of c){let p=o.get(u.date);p&&p.push(u)}for(let[,u]of o)u.sort((p,g)=>{let m=Me(p.status),v=Me(g.status);if(m!==v)return m-v;if(p.projected!==g.projected)return p.projected?1:-1;let y=p.object_name.localeCompare(g.object_name);return y!==0?y:p.task_name.localeCompare(g.task_name)});return i.map(u=>({date:u,events:o.get(u)??[]}))}var Zs={completed:"ok",reset:"ok",skipped:"due_soon",missed:"overdue",triggered:"triggered",trigger_replaced:"triggered",trigger_removed:"ok"};function St(l,d){return`${l}/${d}`}function hs(l,d,e){let t=us(d,e)[0],i=[];for(let a of l)for(let r of a.tasks||[]){let c=r.history||[],o=r.history_count??c.length;if(o<=c.length)continue;let u=c.map(m=>Mt(m?.timestamp)).filter(m=>!!m),p=u.length?u.reduce((m,v)=>m>>0).toString(36)}function us(l,d){let e=[];for(let t=d-1;t>=0;t--)e.push(Te(l,-t));return e}function gs(l,d,e,t=null,i={}){let a=us(d,e),r=a[0],c=a[a.length-1],o=new Map;for(let p of a)o.set(p,[]);for(let p of l){let g=p.object?.name||"",m=p.entry_id,v=p.tasks||[];for(let y of v){if(t&&!tt(y,t))continue;let E=i[St(m,y.id)]??(y.history||[]);for(let w of E){if(typeof w?.timestamp!="string")continue;let j=Mt(w.timestamp);if(!j||jc)continue;let x=o.get(j);if(!x)continue;let M=w.type??"completed";x.push({date:j,entry_id:m,task_id:y.id,task_name:y.name,object_name:g,status:Zs[M]??"ok",days_until_due:null,projected:!1,schedule_type:y.schedule_type,interval_days:y.interval_days??null,responsible_user_id:y.responsible_user_id??null,avg_cost:Re(w),adaptive_enabled:!!y.adaptive_config?.enabled,prediction_confidence:null,history_timestamp:w.timestamp,history_type:M,history_cost:Re(w),history_notes:typeof w.notes=="string"?w.notes:null,history_duration:typeof w.duration=="number"?w.duration:null})}}}let u={completed:0,reset:1,skipped:2,triggered:3,trigger_replaced:4};for(let[,p]of o)p.sort((g,m)=>{let v=u[g.history_type??""]??99,y=u[m.history_type??""]??99;if(v!==y)return v-y;let E=g.object_name.localeCompare(m.object_name);return E!==0?E:g.task_name.localeCompare(m.task_name)});return a.map(p=>({date:p,events:o.get(p)??[]}))}var _s=B` .cal-controls { display: flex; gap: 12px; @@ -4130,24 +4245,24 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} .cal-pill-day { font-size: 17px; } .cal-user-filter { margin-left: 0; width: 100%; } } -`;function us(l){let p=window;p.customCards=p.customCards||[],p.customCards.some(t=>t.type===l.type)||p.customCards.push(l)}function gs(l,p,t=e=>import(e)){let e=window,i;try{let d=new URL(p);i=d.origin+d.pathname}catch{return}let a=`__msCardHeal:${l[0]}:${i}`;if(e[a])return;e[a]=!0;let r=0,c=0,n=!1,u=()=>{if(r+=1,l.some(g=>!customElements.get(g))&&c<3&&!n){c+=1,n=!0;try{let g=new URL(p);g.searchParams.set("heal",`${Date.now()}`),t(g.href).catch(()=>{}).finally(()=>{n=!1})}catch{return}}r<20&&window.setTimeout(u,r<8?500:2e3)};window.setTimeout(u,250)}var ut=class extends N{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"};this._objects=[];this._stats=null;this._windowDays=30;this._pastDays=0;this._userFilter="";this._objectFilter="";this._configuredObjects=[];this._unsub=null;this._pastHistory={};this._pastHistorySig="";this._pastSeq=0;this._dataLoaded=!1;this._lastConnection=null;this._onHistorySaved=t=>{let e=t.detail;!e?.entry_id||!e.task_id||!(je(e.entry_id,e.task_id)in this._pastHistory)||(this._pastHistorySig="",this._loadPastHistories())}}static getConfigElement(){return document.createElement("maintenance-supporter-calendar-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-calendar-card",window_days:30,show_window_chips:!0,show_user_filter:!0}}setConfig(t){if(this._config={...t},this._windowDays=t.window_days&&[7,14,30,365].includes(t.window_days)?t.window_days:30,this._pastDays=t.past_days&&[30,90].includes(t.past_days)?t.past_days:0,this._userFilter=typeof t.user_filter=="string"?t.user_filter:"",typeof t.object_filter=="string")this._objectFilter=t.object_filter,this._configuredObjects=[];else if(Array.isArray(t.object_filter)){let e=t.object_filter.filter(i=>typeof i=="string"&&i!=="");this._objectFilter=e.length===1?e[0]:"",this._configuredObjects=e.length>1?e:[]}else this._objectFilter="",this._configuredObjects=[]}getCardSize(){return 6}get _lang(){return K(this.hass)}connectedCallback(){super.connectedCallback(),window.addEventListener("history-entry-saved",this._onHistorySaved)}disconnectedCallback(){if(super.disconnectedCallback(),window.removeEventListener("history-entry-saved",this._onHistorySaved),this._unsub){try{this._unsub()}catch{}this._unsub=null}this._dataLoaded=!1,this._lastConnection=null}updated(t){if(super.updated(t),Bt(this,t),this.hass&&this._pastDays>0&&(t.has("_objects")||t.has("_pastDays"))&&this._loadPastHistories(),t.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){try{let[t,e]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=t.objects,this._stats=e,Kt(this._stats.budget)}catch{}}async _loadPastHistories(){let t=cs(this._objects,yt(),this._pastDays||30),e=t.map(r=>r.sig).join("|");if(e===this._pastHistorySig)return;this._pastHistorySig=e;let i=++this._pastSeq,a=await Promise.all(t.map(async r=>{try{let c=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:r.entryId,task_id:r.taskId});return[r.key,c.history??[]]}catch{return null}}));i===this._pastSeq&&(this._pastHistory=Object.fromEntries(a.filter(r=>r!==null)))}async _subscribe(){try{let t=await this.hass.connection.subscribeMessage(e=>{let i=e;this._objects=i.objects},{type:"maintenance_supporter/subscribe"});if(!this.isConnected){t();return}this._unsub=t}catch{}}_onEventClick(t){if(t.history_timestamp){this._openHistoryEntry(t);return}this._openTask(t)}_openTask(t){Ji(t.entry_id,t.task_id)||this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:open-task",entry_id:t.entry_id,task_id:t.task_id},bubbles:!0,composed:!0}))}async _openHistoryEntry(t){try{let e=await _e(this.hass);if(!Nt(this.hass?.user,e.access)){this._openTask(t);return}}catch{}try{let e=await Hi(this.hass,t.entry_id,t.task_id,t.history_timestamp);if(!e||Qi(e))return}catch{}this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:edit-history",entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.history_timestamp},bubbles:!0,composed:!0}))}render(){if(!this.hass)return h;let t=this._lang,e=this._config.show_window_chips!==!1,i=this._config.show_user_filter!==!1,a=this._config.title,r=null;this._userFilter&&(r=this._userFilter==="current_user"?this.hass?.user?.id??null:this._userFilter);let c=b=>{let D=b.toLowerCase();return this._objects.find(pt=>pt.entry_id===b||pt.object.name.toLowerCase()===D)?.entry_id??null},n=new Set(this._configuredObjects.map(c).filter(b=>b!==null)),u=n.size?this._objects.filter(b=>n.has(b.entry_id)):this._objects,d=this._config.show_object_filter!==!1&&u.length>1,g=this._objectFilter?c(this._objectFilter):null,m=g&&u.some(b=>b.entry_id===g)?u.filter(b=>b.entry_id===g):u,v=yt(),y=this._pastDays>0,E=y?ps(m,v,this._pastDays,r,this._pastHistory):ls(m,v,this._windowDays,r),w=this._windowDays===365||y,j=w?E.filter(b=>b.events.length>0):E,x=b=>{let D=`cal-status-${b.status}`,at=b.projected?"cal-event-projected":"",pt=b.status==="overdue"&&b.days_until_due!=null?` (${xt(b.days_until_due,t)})`:"",T=b.projected&&b.interval_days?o`${b.interval_unit&&b.interval_unit!=="days"?li(b.interval_days,b.interval_unit,t):b.interval_days===1?s("cal_every_day",t):s("cal_every_n_days",t).replace("{n}",String(b.interval_days))}`:h,z=b.schedule_type==="sensor_based",H=z?o``:o``,I=z&&b.prediction_confidence&&b.status!=="triggered"&&!b.projected?o` - ${s("cal_predicted",t)} · ${s(`cal_confidence_${b.prediction_confidence}`,t)} - `:h,W=oe(this._stats?.budget),Q=b.history_type?s(b.history_type,t):s(b.status,t);return o` -
    e.type===l.type)||d.customCards.push(l)}function fs(l,d,e=t=>import(t)){let t=window,i;try{let p=new URL(d);i=p.origin+p.pathname}catch{return}let a=`__msCardHeal:${l[0]}:${i}`;if(t[a])return;t[a]=!0;let r=0,c=0,o=!1,u=()=>{if(r+=1,l.some(g=>!customElements.get(g))&&c<3&&!o){c+=1,o=!0;try{let g=new URL(d);g.searchParams.set("heal",`${Date.now()}`),e(g.href).catch(()=>{}).finally(()=>{o=!1})}catch{return}}r<20&&window.setTimeout(u,r<8?500:2e3)};window.setTimeout(u,250)}var ue=class extends N{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"};this._objects=[];this._stats=null;this._windowDays=30;this._pastDays=0;this._userFilter="";this._objectFilter="";this._configuredObjects=[];this._unsub=null;this._pastHistory={};this._pastHistorySig="";this._pastSeq=0;this._dataLoaded=!1;this._lastConnection=null;this._onHistorySaved=e=>{let t=e.detail;!t?.entry_id||!t.task_id||!(St(t.entry_id,t.task_id)in this._pastHistory)||(this._pastHistorySig="",this._loadPastHistories())}}static getConfigElement(){return document.createElement("maintenance-supporter-calendar-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-calendar-card",window_days:30,show_window_chips:!0,show_user_filter:!0}}setConfig(e){if(this._config={...e},this._windowDays=e.window_days&&[7,14,30,365].includes(e.window_days)?e.window_days:30,this._pastDays=e.past_days&&[30,90].includes(e.past_days)?e.past_days:0,this._userFilter=typeof e.user_filter=="string"?e.user_filter:"",typeof e.object_filter=="string")this._objectFilter=e.object_filter,this._configuredObjects=[];else if(Array.isArray(e.object_filter)){let t=e.object_filter.filter(i=>typeof i=="string"&&i!=="");this._objectFilter=t.length===1?t[0]:"",this._configuredObjects=t.length>1?t:[]}else this._objectFilter="",this._configuredObjects=[]}getCardSize(){return 6}get _lang(){return K(this.hass)}connectedCallback(){super.connectedCallback(),window.addEventListener("history-entry-saved",this._onHistorySaved)}disconnectedCallback(){if(super.disconnectedCallback(),window.removeEventListener("history-entry-saved",this._onHistorySaved),this._unsub){try{this._unsub()}catch{}this._unsub=null}this._dataLoaded=!1,this._lastConnection=null}updated(e){if(super.updated(e),Be(this,e),this.hass&&this._pastDays>0&&(e.has("_objects")||e.has("_pastDays"))&&this._loadPastHistories(),e.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){try{let[e,t]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=e.objects,this._stats=t,Ke(this._stats.budget)}catch{}}async _loadPastHistories(){let e=hs(this._objects,ye(),this._pastDays||30),t=e.map(r=>r.sig).join("|");if(t===this._pastHistorySig)return;this._pastHistorySig=t;let i=++this._pastSeq,a=await Promise.all(e.map(async r=>{try{let c=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:r.entryId,task_id:r.taskId});return[r.key,c.history??[]]}catch{return null}}));i===this._pastSeq&&(this._pastHistory=Object.fromEntries(a.filter(r=>r!==null)))}async _subscribe(){try{let e=await this.hass.connection.subscribeMessage(t=>{let i=t;this._objects=i.objects},{type:"maintenance_supporter/subscribe"});if(!this.isConnected){e();return}this._unsub=e}catch{}}_onEventClick(e){if(e.history_timestamp){this._openHistoryEntry(e);return}this._openTask(e)}_openTask(e){es(e.entry_id,e.task_id)||this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:open-task",entry_id:e.entry_id,task_id:e.task_id},bubbles:!0,composed:!0}))}async _openHistoryEntry(e){try{let t=await mt(this.hass);if(!Ne(this.hass?.user,t.access)){this._openTask(e);return}}catch{}try{let t=await qi(this.hass,e.entry_id,e.task_id,e.history_timestamp);if(!t||Zi(t))return}catch{}this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:edit-history",entry_id:e.entry_id,task_id:e.task_id,original_timestamp:e.history_timestamp},bubbles:!0,composed:!0}))}render(){if(!this.hass)return h;let e=this._lang,t=this._config.show_window_chips!==!1,i=this._config.show_user_filter!==!1,a=this._config.title,r=null;this._userFilter&&(r=this._userFilter==="current_user"?this.hass?.user?.id??null:this._userFilter);let c=b=>{let D=b.toLowerCase();return this._objects.find(pe=>pe.entry_id===b||pe.object.name.toLowerCase()===D)?.entry_id??null},o=new Set(this._configuredObjects.map(c).filter(b=>b!==null)),u=o.size?this._objects.filter(b=>o.has(b.entry_id)):this._objects,p=this._config.show_object_filter!==!1&&u.length>1,g=this._objectFilter?c(this._objectFilter):null,m=g&&u.some(b=>b.entry_id===g)?u.filter(b=>b.entry_id===g):u,v=ye(),y=this._pastDays>0,E=y?gs(m,v,this._pastDays,r,this._pastHistory):ps(m,v,this._windowDays,r),w=this._windowDays===365||y,j=w?E.filter(b=>b.events.length>0):E,x=b=>{let D=`cal-status-${b.status}`,se=b.projected?"cal-event-projected":"",pe=b.status==="overdue"&&b.days_until_due!=null?` (${xe(b.days_until_due,e)})`:"",T=b.projected&&b.interval_days?n`${b.interval_unit&&b.interval_unit!=="days"?pi(b.interval_days,b.interval_unit,e):b.interval_days===1?s("cal_every_day",e):s("cal_every_n_days",e).replace("{n}",String(b.interval_days))}`:h,z=b.schedule_type==="sensor_based",H=z?n``:n``,I=z&&b.prediction_confidence&&b.status!=="triggered"&&!b.projected?n` + ${s("cal_predicted",e)} · ${s(`cal_confidence_${b.prediction_confidence}`,e)} + `:h,W=ot(this._stats?.budget),Q=b.history_type?s(b.history_type,e):s(b.status,e);return n` +
    this._onEventClick(b)}> ${H} ${Q}
    -
    ${b.object_name} · ${b.task_name}${pt}
    +
    ${b.object_name} · ${b.task_name}${pe}
    ${I} ${T}
    - ${b.avg_cost!=null&&b.avg_cost!==0?o`${U(b.avg_cost,W,t)}`:h} + ${b.avg_cost!=null&&b.avg_cost!==0?n`${U(b.avg_cost,W,e)}`:h}
    - `},M=b=>{let[D,at,pt]=b.date.split("-").map(Number),T=new Date(D,at-1,pt),z=b.date===v,H=ci(T,t,"short"),I=di(T,t,"long");return o` + `},M=b=>{let[D,se,pe]=b.date.split("-").map(Number),T=new Date(D,se-1,pe),z=b.date===v,H=hi(T,e,"short"),I=ui(T,e,"long");return n`
    ${H} @@ -4156,18 +4271,18 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""}
    ${I} - ${z?o`${s("today",t)}`:h} + ${z?n`${s("today",e)}`:h}
    - ${b.events.length===0?o`
    ${s("cal_no_events",t)}
    `:b.events.map(x)} + ${b.events.length===0?n`
    ${s("cal_no_events",e)}
    `:b.events.map(x)}
    - `};return o` + `};return n` - ${e||i||d?o` + ${t||i||p?n`
    - ${e?o` -
    - ${[30,90].map(b=>o` + ${t?n` +
    + ${[30,90].map(b=>n`
    -
    - ${[7,14,30,365].map(b=>o` +
    + ${[7,14,30,365].map(b=>n`
    `:h} - ${i?o` + ${i?n` `:h} - ${d?o` + ${p?n` `:h}
    `:h}
    - ${j.length===0&&w?o`
    ${s("cal_no_events",t)}
    `:j.map(M)} + ${j.length===0&&w?n`
    ${s("cal_no_events",e)}
    `:j.map(M)}
    - `}};ut.styles=[ne,hs,B` + `}};ue.styles=[lt,_s,B` :host { display: block; } ha-card { padding: 0; overflow: hidden; } - `],_([R({attribute:!1})],ut.prototype,"hass",2),_([f()],ut.prototype,"_config",2),_([f()],ut.prototype,"_objects",2),_([f()],ut.prototype,"_stats",2),_([f()],ut.prototype,"_windowDays",2),_([f()],ut.prototype,"_pastDays",2),_([f()],ut.prototype,"_userFilter",2),_([f()],ut.prototype,"_objectFilter",2),_([f()],ut.prototype,"_unsub",2),_([f()],ut.prototype,"_pastHistory",2);var Js=[{value:7,key:"cal_editor_window_week"},{value:14,key:"cal_editor_window_fortnight"},{value:30,key:"cal_editor_window_month"},{value:365,key:"cal_editor_window_year"}],Xs=[{value:30,key:"cal_editor_window_past_30"},{value:90,key:"cal_editor_window_past_90"}],Vt=class extends N{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"}}get _lang(){return K(this.hass)}setConfig(t){this._config={...t}}updated(){let t=this._lang;t&&!ii(t)&&ot(t).then(()=>this.requestUpdate())}_valueChanged(t,e){let i={...this._config,[t]:e};t==="show_window_chips"&&e===!0&&delete i.show_window_chips,t==="show_user_filter"&&e===!0&&delete i.show_user_filter,t==="show_object_filter"&&e===!0&&delete i.show_object_filter,t==="title"&&(!e||typeof e=="string"&&e.trim()==="")&&delete i.title,t==="user_filter"&&e===""&&delete i.user_filter,this._emit(i)}_windowChanged(t){let e={...this._config};t.startsWith("past-")?(e.past_days=Number(t.slice(5)),delete e.window_days):(e.window_days=Number(t),delete e.past_days),this._emit(e)}_emit(t){this._config=t,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:t},bubbles:!0,composed:!0}))}render(){let t=this._lang,e=this._config.past_days?`past-${this._config.past_days}`:`${this._config.window_days??30}`,i=this._config.show_window_chips!==!1,a=this._config.show_user_filter!==!1,r=this._config.user_filter??"",c=this._config.title??"";return o` + `],_([R({attribute:!1})],ue.prototype,"hass",2),_([f()],ue.prototype,"_config",2),_([f()],ue.prototype,"_objects",2),_([f()],ue.prototype,"_stats",2),_([f()],ue.prototype,"_windowDays",2),_([f()],ue.prototype,"_pastDays",2),_([f()],ue.prototype,"_userFilter",2),_([f()],ue.prototype,"_objectFilter",2),_([f()],ue.prototype,"_unsub",2),_([f()],ue.prototype,"_pastHistory",2);var ta=[{value:7,key:"cal_editor_window_week"},{value:14,key:"cal_editor_window_fortnight"},{value:30,key:"cal_editor_window_month"},{value:365,key:"cal_editor_window_year"}],ia=[{value:30,key:"cal_editor_window_past_30"},{value:90,key:"cal_editor_window_past_90"}],Ve=class extends N{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"}}get _lang(){return K(this.hass)}setConfig(e){this._config={...e}}updated(){let e=this._lang;e&&!ri(e)&&re(e).then(()=>this.requestUpdate())}_valueChanged(e,t){let i={...this._config,[e]:t};e==="show_window_chips"&&t===!0&&delete i.show_window_chips,e==="show_user_filter"&&t===!0&&delete i.show_user_filter,e==="show_object_filter"&&t===!0&&delete i.show_object_filter,e==="title"&&(!t||typeof t=="string"&&t.trim()==="")&&delete i.title,e==="user_filter"&&t===""&&delete i.user_filter,this._emit(i)}_windowChanged(e){let t={...this._config};e.startsWith("past-")?(t.past_days=Number(e.slice(5)),delete t.window_days):(t.window_days=Number(e),delete t.past_days),this._emit(t)}_emit(e){this._config=e,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:e},bubbles:!0,composed:!0}))}render(){let e=this._lang,t=this._config.past_days?`past-${this._config.past_days}`:`${this._config.window_days??30}`,i=this._config.show_window_chips!==!1,a=this._config.show_user_filter!==!1,r=this._config.user_filter??"",c=this._config.title??"";return n`
    - + this._valueChanged("title",n.target.value)} + @input=${o=>this._valueChanged("title",o.target.value)} />
    - +
    - + this._valueChanged("show_window_chips",n.target.checked)} + @change=${o=>this._valueChanged("show_window_chips",o.target.checked)} />
    -
    ${s("cal_editor_chips_hint",t)}
    +
    ${s("cal_editor_chips_hint",e)}
    - + this._valueChanged("show_user_filter",n.target.checked)} + @change=${o=>this._valueChanged("show_user_filter",o.target.checked)} />
    - +
    - + this._valueChanged("show_object_filter",n.target.checked)} + @change=${o=>this._valueChanged("show_object_filter",o.target.checked)} />
    -
    ${s("cal_editor_object_hint",t)}
    +
    ${s("cal_editor_object_hint",e)}
    - `}};Vt.styles=B` + `}};Ve.styles=B` :host { display: block; padding: 8px 0; } .editor { display: flex; flex-direction: column; gap: 12px; } .row { display: flex; flex-direction: column; gap: 4px; } @@ -4296,16 +4411,16 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} font-size: 12px; color: var(--secondary-text-color, #666); } - `,_([R({attribute:!1})],Vt.prototype,"hass",2),_([f()],Vt.prototype,"_config",2);customElements.get("maintenance-supporter-calendar-card")||customElements.define("maintenance-supporter-calendar-card",ut);customElements.get("maintenance-supporter-calendar-card-editor")||customElements.define("maintenance-supporter-calendar-card-editor",Vt);gs(["maintenance-supporter-calendar-card"],import.meta.url);us({type:"maintenance-supporter-calendar-card",name:"Maintenance Supporter \u2014 Calendar",description:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",preview:!0});var _t=class extends N{constructor(){super(...arguments);this.objects=[];this._summary=null;this._loaded=!1;this._busy=!1;this._error="";this._query="";this._results=[];this._expanded=!1;this._initiallyLoaded=!1;this._searchTimer=0;this._searchSeq=0}get _lang(){return K(this.hass)}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._initiallyLoaded&&(this._initiallyLoaded=!0,this._load(),ot(this._lang).then(()=>this.requestUpdate()))}async _load(){let t=await P(this,{type:"maintenance_supporter/documents/storage"},{busy:e=>{this._busy=e},onError:e=>{this._error=e}});this._loaded=!0,t!==void 0&&(this._summary=t,this._error="")}_nameFor(t){return this.objects.find(i=>i.object?.id===t)?.object?.name||t.slice(0,8)}_entryFor(t){return this.objects.find(e=>e.object?.id===t)?.entry_id}_toggle(){this._expanded=!this._expanded}_openObject(t){this.dispatchEvent(new CustomEvent("open-object",{detail:{entry_id:t},bubbles:!0,composed:!0}))}_onSearch(t){this._query=t.target.value,clearTimeout(this._searchTimer),this._searchTimer=window.setTimeout(()=>{this._doSearch()},250)}async _doSearch(){let t=this._query.trim(),e=++this._searchSeq;if(!t){this._results=[];return}let i="",a=await P(this,{type:"maintenance_supporter/documents/search",query:t},{onError:r=>{i=r}});if(e===this._searchSeq){if(a===void 0){this._error=i,this._results=[];return}this._results=a?.results||[]}}async _openResult(t){if(t.kind==="weblink"){st(t.url)&&window.open(t.url,"_blank","noopener");return}await P(this,()=>Et(this.hass,t.id),{onError:e=>{this._error=e}})}_renderResult(t,e){return o` -
    this._openResult(t)}> - + `,_([R({attribute:!1})],Ve.prototype,"hass",2),_([f()],Ve.prototype,"_config",2);customElements.get("maintenance-supporter-calendar-card")||customElements.define("maintenance-supporter-calendar-card",ue);customElements.get("maintenance-supporter-calendar-card-editor")||customElements.define("maintenance-supporter-calendar-card-editor",Ve);fs(["maintenance-supporter-calendar-card"],import.meta.url);ms({type:"maintenance-supporter-calendar-card",name:"Maintenance Supporter \u2014 Calendar",description:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",preview:!0});var _e=class extends N{constructor(){super(...arguments);this.objects=[];this._summary=null;this._loaded=!1;this._busy=!1;this._error="";this._query="";this._results=[];this._expanded=!1;this._initiallyLoaded=!1;this._searchTimer=0;this._searchSeq=0}get _lang(){return K(this.hass)}updated(e){super.updated(e),e.has("hass")&&this.hass&&!this._initiallyLoaded&&(this._initiallyLoaded=!0,this._load(),re(this._lang).then(()=>this.requestUpdate()))}async _load(){let e=await P(this,{type:"maintenance_supporter/documents/storage"},{busy:t=>{this._busy=t},onError:t=>{this._error=t}});this._loaded=!0,e!==void 0&&(this._summary=e,this._error="")}_nameFor(e){return this.objects.find(i=>i.object?.id===e)?.object?.name||e.slice(0,8)}_entryFor(e){return this.objects.find(t=>t.object?.id===e)?.entry_id}_toggle(){this._expanded=!this._expanded}_openObject(e){this.dispatchEvent(new CustomEvent("open-object",{detail:{entry_id:e},bubbles:!0,composed:!0}))}_onSearch(e){this._query=e.target.value,clearTimeout(this._searchTimer),this._searchTimer=window.setTimeout(()=>{this._doSearch()},250)}async _doSearch(){let e=this._query.trim(),t=++this._searchSeq;if(!e){this._results=[];return}let i="",a=await P(this,{type:"maintenance_supporter/documents/search",query:e},{onError:r=>{i=r}});if(t===this._searchSeq){if(a===void 0){this._error=i,this._results=[];return}this._results=a?.results||[]}}async _openResult(e){if(e.kind==="weblink"){le(e.url)&&window.open(e.url,"_blank","noopener");return}await P(this,()=>Ee(this.hass,e.id),{onError:t=>{this._error=t}})}_renderResult(e,t){return n` +
    this._openResult(e)}> +
    -
    ${nt(t)}
    -
    ${t.object_name}
    +
    ${ne(e)}
    +
    ${e.object_name}
    - +
    - `}render(){if(!this._loaded||!this._summary)return h;let t=this._summary;if(!t.document_count)return h;let e=this._lang,i=Object.entries(t.by_object??{}).filter(([,a])=>a.files>0||a.links>0).map(([a,r])=>({id:a,name:this._nameFor(a),entry:this._entryFor(a),...r})).sort((a,r)=>r.bytes-a.bytes);return o` + `}render(){if(!this._loaded||!this._summary)return h;let e=this._summary;if(!e.document_count)return h;let t=this._lang,i=Object.entries(e.by_object??{}).filter(([,a])=>a.files>0||a.links>0).map(([a,r])=>({id:a,name:this._nameFor(a),entry:this._entryFor(a),...r})).sort((a,r)=>r.bytes-a.bytes);return n`
    @@ -4313,19 +4428,19 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} class="toggle" @click=${this._toggle} aria-expanded=${this._expanded?"true":"false"} - aria-label=${s("doc_storage_title",e)} + aria-label=${s("doc_storage_title",t)} > 🗄️ - ${s("doc_storage_title",e)} + ${s("doc_storage_title",t)} - ${wt(t.total_bytes,e)} - ${t.dedup_savings_bytes>0?o`−${wt(t.dedup_savings_bytes,e)}`:h} + ${we(e.total_bytes,t)} + ${e.dedup_savings_bytes>0?n`−${we(e.dedup_savings_bytes,t)}`:h}
    - ${this._expanded?o` + ${this._expanded?n`
    -
    ${wt(t.total_bytes,e)}
    +
    ${we(e.total_bytes,t)}
    - ${t.file_count} - ${t.link_count} + ${e.file_count} + ${e.link_count}
    - ${t.dedup_savings_bytes>0?o`
    -
    −${wt(t.dedup_savings_bytes,e)}
    -
    ${s("doc_storage_saved",e)}
    + ${e.dedup_savings_bytes>0?n`
    +
    −${we(e.dedup_savings_bytes,t)}
    +
    ${s("doc_storage_saved",t)}
    `:h}
    - ${t.search_index&&t.search_index.total>0?o`
    + ${e.search_index&&e.search_index.total>0?n`
    - ${s("search_index_status",e).replace("{indexed}",String(t.search_index.indexed)).replace("{total}",String(t.search_index.total)).replace("{no_text}",String(t.search_index.no_text+t.search_index.unsupported)).replace("{pending}",String(t.search_index.pending))} + ${s("search_index_status",t).replace("{indexed}",String(e.search_index.indexed)).replace("{total}",String(e.search_index.total)).replace("{no_text}",String(e.search_index.no_text+e.search_index.unsupported)).replace("{pending}",String(e.search_index.pending))}
    `:h} - ${this._error?o`
    ${this._error}
    `:h} + ${this._error?n`
    ${this._error}
    `:h} - ${this._query.trim()?this._results.length?o`
    ${this._results.map(a=>this._renderResult(a,e))}
    `:o`
    ${s("doc_search_none",e)}
    `:i.length?o`
    ${i.map(a=>this._renderObjRow(a,e))}
    `:h} + ${this._query.trim()?this._results.length?n`
    ${this._results.map(a=>this._renderResult(a,t))}
    `:n`
    ${s("doc_search_none",t)}
    `:i.length?n`
    ${i.map(a=>this._renderObjRow(a,t))}
    `:h}
    `:h}
    - `}_renderObjRow(t,e){let i=t.entry;return o` + `}_renderObjRow(e,t){let i=e.entry;return n`
    this._openObject(i):void 0} @keydown=${i?a=>{(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),this._openObject(i))}:void 0} > - ${t.name} + ${e.name} - ${t.files>0?o`${t.files}`:h} - ${t.links>0?o`${t.links}`:h} + ${e.files>0?n`${e.files}`:h} + ${e.links>0?n`${e.links}`:h} - ${wt(t.bytes,e)} - ${i?o``:h} + ${we(e.bytes,t)} + ${i?n``:h}
    - `}};_t.styles=B` + `}};_e.styles=B` ha-card { margin-top: 16px; } .card-content { padding: 16px; } .index-status { @@ -4468,17 +4583,17 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} .icon-btn:hover { background: var(--secondary-background-color, rgba(0,0,0,0.06)); } .icon-btn[disabled] { opacity: 0.4; pointer-events: none; } .error { color: var(--error-color, #f44336); font-size: 13px; margin-top: 6px; } - `,_([R({attribute:!1})],_t.prototype,"hass",2),_([R({attribute:!1})],_t.prototype,"objects",2),_([f()],_t.prototype,"_summary",2),_([f()],_t.prototype,"_loaded",2),_([f()],_t.prototype,"_busy",2),_([f()],_t.prototype,"_error",2),_([f()],_t.prototype,"_query",2),_([f()],_t.prototype,"_results",2),_([f()],_t.prototype,"_expanded",2);customElements.get("maintenance-storage-section-card")||customElements.define("maintenance-storage-section-card",_t);var Zs=["month_jan","month_feb","month_mar","month_apr","month_may","month_jun","month_jul","month_aug","month_sep","month_oct","month_nov","month_dec"],vt=class extends N{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._error="";this._entryId="";this._taskId="";this._values=new Array(12).fill("");this._save=async()=>{let t=this._buildOverrides();t!==null&&await this._send(t)!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("overrides-saved")))};this._clearAll=async()=>{await this._send({})!==void 0&&(this._values=new Array(12).fill(""),this._open=!1,this.dispatchEvent(new CustomEvent("overrides-saved")))}}get _lang(){return K(this.hass)}open(t,e,i){if(this._entryId=t,this._taskId=e,this._values=new Array(12).fill(""),i)for(let[a,r]of Object.entries(i)){let c=parseInt(a,10);c>=1&&c<=12&&typeof r=="number"&&(this._values[c-1]=r.toString())}this._error="",this._open=!0}_close(){this._open=!1}_buildOverrides(){let t={};for(let e=0;e<12;e++){let i=this._values[e].trim();if(!i)continue;let a=parseFloat(i);if(Number.isNaN(a))return this._error=`${s("month_"+["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"][e],this._lang)}: ${s("seasonal_override_invalid",this._lang)}`,null;if(aXt[1])return this._error=s("seasonal_override_range",this._lang),null;t[e+1]=a}return t}_send(t){return this._error="",P(this,{type:"maintenance_supporter/task/seasonal_overrides",entry_id:this._entryId,task_id:this._taskId,overrides:t},{busy:e=>{this._loading=e},fallbackKey:"save_error",onError:e=>{this._error=e}})}render(){if(!this._open)return o``;let t=this._lang;return o` + `,_([R({attribute:!1})],_e.prototype,"hass",2),_([R({attribute:!1})],_e.prototype,"objects",2),_([f()],_e.prototype,"_summary",2),_([f()],_e.prototype,"_loaded",2),_([f()],_e.prototype,"_busy",2),_([f()],_e.prototype,"_error",2),_([f()],_e.prototype,"_query",2),_([f()],_e.prototype,"_results",2),_([f()],_e.prototype,"_expanded",2);customElements.get("maintenance-storage-section-card")||customElements.define("maintenance-storage-section-card",_e);var sa=["month_jan","month_feb","month_mar","month_apr","month_may","month_jun","month_jul","month_aug","month_sep","month_oct","month_nov","month_dec"],ve=class extends N{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._error="";this._entryId="";this._taskId="";this._values=new Array(12).fill("");this._save=async()=>{let e=this._buildOverrides();e!==null&&await this._send(e)!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("overrides-saved")))};this._clearAll=async()=>{await this._send({})!==void 0&&(this._values=new Array(12).fill(""),this._open=!1,this.dispatchEvent(new CustomEvent("overrides-saved")))}}get _lang(){return K(this.hass)}open(e,t,i){if(this._entryId=e,this._taskId=t,this._values=new Array(12).fill(""),i)for(let[a,r]of Object.entries(i)){let c=parseInt(a,10);c>=1&&c<=12&&typeof r=="number"&&(this._values[c-1]=r.toString())}this._error="",this._open=!0}_close(){this._open=!1}_buildOverrides(){let e={};for(let t=0;t<12;t++){let i=this._values[t].trim();if(!i)continue;let a=parseFloat(i);if(Number.isNaN(a))return this._error=`${s("month_"+["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"][t],this._lang)}: ${s("seasonal_override_invalid",this._lang)}`,null;if(aXe[1])return this._error=s("seasonal_override_range",this._lang),null;e[t+1]=a}return e}_send(e){return this._error="",P(this,{type:"maintenance_supporter/task/seasonal_overrides",entry_id:this._entryId,task_id:this._taskId,overrides:e},{busy:t=>{this._loading=t},fallbackKey:"save_error",onError:t=>{this._error=t}})}render(){if(!this._open)return n``;let e=this._lang;return n` -
    ${s("seasonal_overrides_title",t)}
    +
    ${s("seasonal_overrides_title",e)}
    -

    ${s("seasonal_overrides_hint",t)}

    - ${this._error?o`
    ${this._error}
    `:h} +

    ${s("seasonal_overrides_hint",e)}

    + ${this._error?n`
    ${this._error}
    `:h}
    - ${Zs.map((e,i)=>o` + ${sa.map((t,i)=>n`
    - ${s("clear_all",t)} + ${s("clear_all",e)}
    - ${s("cancel",t)} + ${s("cancel",e)} - ${this._loading?s("saving",t):s("save",t)} + ${this._loading?s("saving",e):s("save",e)}
    - `}};vt.styles=B` + `}};ve.styles=B` .dialog-title { font-size: 18px; font-weight: 500; padding-bottom: 12px; } .content { min-width: 320px; @@ -4545,30 +4660,30 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} padding-top: 16px; } .spacer { flex: 1; } - `,_([R({attribute:!1})],vt.prototype,"hass",2),_([f()],vt.prototype,"_open",2),_([f()],vt.prototype,"_loading",2),_([f()],vt.prototype,"_error",2),_([f()],vt.prototype,"_entryId",2),_([f()],vt.prototype,"_taskId",2),_([f()],vt.prototype,"_values",2);customElements.get("maintenance-seasonal-overrides-dialog")||customElements.define("maintenance-seasonal-overrides-dialog",vt);var mt=class extends N{constructor(){super(...arguments);this.objects=[];this._open=!1;this._loading=!1;this._error="";this._groupId=null;this._name="";this._description="";this._selected=new Set;this._toggleTask=(t,e)=>{let i=`${t}:${e}`,a=new Set(this._selected);a.has(i)?a.delete(i):a.add(i),this._selected=a};this._save=async()=>{let t=this._name.trim();if(!t){this._error=s("group_name_required",this._lang);return}this._error="";let e=this._buildTaskRefs();await P(this,this._groupId?{type:"maintenance_supporter/group/update",group_id:this._groupId,name:t,description:this._description,task_refs:e}:{type:"maintenance_supporter/group/create",name:t,description:this._description,task_refs:e},{busy:a=>{this._loading=a},fallbackKey:"save_error",onError:a=>{this._error=a}})!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("group-saved")))}}get _lang(){return K(this.hass)}openCreate(){this._reset(),this._open=!0}openEdit(t,e){this._reset(),this._groupId=t,this._name=e.name,this._description=e.description||"",this._selected=new Set(e.task_refs.map(i=>`${i.entry_id}:${i.task_id}`)),this._open=!0}_reset(){this._groupId=null,this._name="",this._description="",this._selected=new Set,this._error=""}_close(){this._open=!1}_buildTaskRefs(){return[...this._selected].map(t=>{let[e,i]=t.split(":",2);return{entry_id:e,task_id:i}})}render(){if(!this._open)return o``;let t=this._lang,e=this._groupId?s("edit_group",t):s("new_group",t);return o` + `,_([R({attribute:!1})],ve.prototype,"hass",2),_([f()],ve.prototype,"_open",2),_([f()],ve.prototype,"_loading",2),_([f()],ve.prototype,"_error",2),_([f()],ve.prototype,"_entryId",2),_([f()],ve.prototype,"_taskId",2),_([f()],ve.prototype,"_values",2);customElements.get("maintenance-seasonal-overrides-dialog")||customElements.define("maintenance-seasonal-overrides-dialog",ve);var me=class extends N{constructor(){super(...arguments);this.objects=[];this._open=!1;this._loading=!1;this._error="";this._groupId=null;this._name="";this._description="";this._selected=new Set;this._toggleTask=(e,t)=>{let i=`${e}:${t}`,a=new Set(this._selected);a.has(i)?a.delete(i):a.add(i),this._selected=a};this._save=async()=>{let e=this._name.trim();if(!e){this._error=s("group_name_required",this._lang);return}this._error="";let t=this._buildTaskRefs();await P(this,this._groupId?{type:"maintenance_supporter/group/update",group_id:this._groupId,name:e,description:this._description,task_refs:t}:{type:"maintenance_supporter/group/create",name:e,description:this._description,task_refs:t},{busy:a=>{this._loading=a},fallbackKey:"save_error",onError:a=>{this._error=a}})!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("group-saved")))}}get _lang(){return K(this.hass)}openCreate(){this._reset(),this._open=!0}openEdit(e,t){this._reset(),this._groupId=e,this._name=t.name,this._description=t.description||"",this._selected=new Set(t.task_refs.map(i=>`${i.entry_id}:${i.task_id}`)),this._open=!0}_reset(){this._groupId=null,this._name="",this._description="",this._selected=new Set,this._error=""}_close(){this._open=!1}_buildTaskRefs(){return[...this._selected].map(e=>{let[t,i]=e.split(":",2);return{entry_id:t,task_id:i}})}render(){if(!this._open)return n``;let e=this._lang,t=this._groupId?s("edit_group",e):s("new_group",e);return n` -
    ${e}
    +
    ${t}
    - ${this._error?o`
    ${this._error}
    `:h} + ${this._error?n`
    ${this._error}
    `:h} this._name=i.target.value} > this._description=i.target.value} > -
    ${s("group_select_tasks",t)}
    - ${this.objects.length===0?o`
    ${s("no_objects",t)}
    `:o` +
    ${s("group_select_tasks",e)}
    + ${this.objects.length===0?n`
    ${s("no_objects",e)}
    `:n`
    - ${[...this.objects].sort((i,a)=>i.object.name.localeCompare(a.object.name)).map(i=>o` + ${[...this.objects].sort((i,a)=>i.object.name.localeCompare(a.object.name)).map(i=>n`
    ${i.object.name}
    - ${i.tasks.length===0?o`
    ${s("no_tasks_short",t)}
    `:[...i.tasks].sort((a,r)=>a.name.localeCompare(r.name)).map(a=>{let r=`${i.entry_id}:${a.id}`,c=this._selected.has(r);return o` + ${i.tasks.length===0?n`
    ${s("no_tasks_short",e)}
    `:[...i.tasks].sort((a,r)=>a.name.localeCompare(r.name)).map(a=>{let r=`${i.entry_id}:${a.id}`,c=this._selected.has(r);return n`
    `}
    - ${s("selected",t)}: ${this._selected.size} + ${s("selected",e)}: ${this._selected.size}
    - ${s("cancel",t)} + ${s("cancel",e)} - ${this._loading?s("saving",t):s("save",t)} + ${this._loading?s("saving",e):s("save",e)}
    - `}};mt.styles=B` + `}};me.styles=B` .dialog-title { font-size: 18px; font-weight: 500; padding-bottom: 12px; } .content { display: flex; @@ -4658,37 +4773,37 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} gap: 8px; padding-top: 16px; } - `,_([R({attribute:!1})],mt.prototype,"hass",2),_([R({attribute:!1})],mt.prototype,"objects",2),_([f()],mt.prototype,"_open",2),_([f()],mt.prototype,"_loading",2),_([f()],mt.prototype,"_error",2),_([f()],mt.prototype,"_groupId",2),_([f()],mt.prototype,"_name",2),_([f()],mt.prototype,"_description",2),_([f()],mt.prototype,"_selected",2);customElements.get("maintenance-group-dialog")||customElements.define("maintenance-group-dialog",mt);var $t=class extends N{constructor(){super(...arguments);this._open=!1;this._busy=!1;this._error="";this._name="";this._views=[];this._filters=null;this._localeReady=!1;this._save=async()=>{let t=this._name.trim();if(!t||this._busy||!this._filters)return;let e=await this._runWs({type:"maintenance_supporter/views/save",name:t,filters:this._filters});e!==void 0&&(this._name="",this._emitChanged(e?.views||[]))};this._delete=async t=>{if(this._busy)return;let e=await this._runWs({type:"maintenance_supporter/views/delete",view_id:t});e!==void 0&&this._emitChanged(e?.views||[])}}get _lang(){return K(this.hass)}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,ot(this._lang).then(()=>this.requestUpdate()))}async open(t,e){this._open=!0,this._error="",this._name="",this._filters=t,this._views=e}_close(){this._open=!1}_emitChanged(t){this._views=t,this.dispatchEvent(new CustomEvent("saved-views-changed",{bubbles:!0,composed:!0,detail:{views:t}}))}_runWs(t){return this._error="",P(this,t,{busy:e=>{this._busy=e},onError:e=>{this._error=e}})}render(){if(!this._open)return o``;let t=this._lang;return o` + `,_([R({attribute:!1})],me.prototype,"hass",2),_([R({attribute:!1})],me.prototype,"objects",2),_([f()],me.prototype,"_open",2),_([f()],me.prototype,"_loading",2),_([f()],me.prototype,"_error",2),_([f()],me.prototype,"_groupId",2),_([f()],me.prototype,"_name",2),_([f()],me.prototype,"_description",2),_([f()],me.prototype,"_selected",2);customElements.get("maintenance-group-dialog")||customElements.define("maintenance-group-dialog",me);var $e=class extends N{constructor(){super(...arguments);this._open=!1;this._busy=!1;this._error="";this._name="";this._views=[];this._filters=null;this._localeReady=!1;this._save=async()=>{let e=this._name.trim();if(!e||this._busy||!this._filters)return;let t=await this._runWs({type:"maintenance_supporter/views/save",name:e,filters:this._filters});t!==void 0&&(this._name="",this._emitChanged(t?.views||[]))};this._delete=async e=>{if(this._busy)return;let t=await this._runWs({type:"maintenance_supporter/views/delete",view_id:e});t!==void 0&&this._emitChanged(t?.views||[])}}get _lang(){return K(this.hass)}updated(e){e.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,re(this._lang).then(()=>this.requestUpdate()))}async open(e,t){this._open=!0,this._error="",this._name="",this._filters=e,this._views=t}_close(){this._open=!1}_emitChanged(e){this._views=e,this.dispatchEvent(new CustomEvent("saved-views-changed",{bubbles:!0,composed:!0,detail:{views:e}}))}_runWs(e){return this._error="",P(this,e,{busy:t=>{this._busy=t},onError:t=>{this._error=t}})}render(){if(!this._open)return n``;let e=this._lang;return n`
    -
    e.stopPropagation()}> -
    ${s("views_dialog_title",t)}
    -
    ${s("views_dialog_hint",t)}
    - ${this._error?o`
    ${this._error}
    `:h} +
    t.stopPropagation()}> +
    ${s("views_dialog_title",e)}
    +
    ${s("views_dialog_hint",e)}
    + ${this._error?n`
    ${this._error}
    `:h}
    this._name=e.target.value} - @keydown=${e=>{e.key==="Enter"&&this._save()}} + @input=${t=>this._name=t.target.value} + @keydown=${t=>{t.key==="Enter"&&this._save()}} /> - ${s("views_save_current",t)} + ${s("views_save_current",e)}
    - ${this._views.length===0?o`
    ${s("views_none_yet",t)}
    `:o` + ${this._views.length===0?n`
    ${s("views_none_yet",e)}
    `:n`
    - ${this._views.map(e=>o` + ${this._views.map(t=>n`
    - ${e.name} + ${t.name} this._delete(e.id)} + .label=${s("delete",e)} + @click=${()=>this._delete(t.id)} >
    `)} @@ -4696,11 +4811,11 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} `}
    - ${s("close",t)} + ${s("close",e)}
    - `}};$t.styles=B` + `}};$e.styles=B` .overlay { position: fixed; inset: 0; @@ -4786,63 +4901,63 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} gap: 8px; padding-top: 8px; } - `,_([R({attribute:!1})],$t.prototype,"hass",2),_([f()],$t.prototype,"_open",2),_([f()],$t.prototype,"_busy",2),_([f()],$t.prototype,"_error",2),_([f()],$t.prototype,"_name",2),_([f()],$t.prototype,"_views",2);customElements.get("maintenance-saved-views-dialog")||customElements.define("maintenance-saved-views-dialog",$t);var ta=60,ea=20,_s=30,ia={approaching:"\u2197",stable:"\u2192",easing:"\u2198"};function We(l,p){let t=l.trigger_config,e=gt(t);if(!t||!e||l.battery_fleet_task)return null;let i,a=t.type||"threshold";if(a==="threshold")if(t.trigger_above!=null)i=1;else if(t.trigger_below!=null)i=-1;else return null;else if(a==="counter"||a==="runtime"||a==="state_change")i=1;else return null;let r=p.get(e)||[],c=a==="runtime"||a==="state_change",n=r.length>=2?r.map(E=>({ts:E.ts,val:E.val})):c?[]:(l.history||[]).filter(E=>E.trigger_value!=null).map(E=>({ts:ft(E.timestamp),val:E.trigger_value}));if(l.trigger_current_value!=null&&(n=[...n,{ts:Date.now(),val:l.trigger_current_value}]),n.length<2)return null;n.sort((E,w)=>E.ts-w.ts);let u=n.map(E=>E.val),d=Math.max(...u)-Math.min(...u),g=u[u.length-1]-u[0],m=t.trigger_delta_mode&&l.trigger_baseline_value!=null&&t.trigger_target_value!=null?l.trigger_baseline_value+t.trigger_target_value:t.trigger_target_value,v=a==="threshold"?t.trigger_above??t.trigger_below:a==="counter"?m:a==="runtime"?t.trigger_runtime_hours:t.trigger_target_changes,y=typeof v=="number"?Math.max(Math.abs(v-u[0]),d):d;return y===0||Math.abs(g)0?Math.ceil(l):Math.trunc(l)||0}function Ge(l,p){let t=l.trigger_config??null;if(!t)return h;let e=t.type||"threshold",i=l.trigger_entity_info?.unit_of_measurement??"",a=0,r="";if(e==="threshold"){let u=l.trigger_current_value??null;if(u==null)return h;let d=t.trigger_above,g=t.trigger_below;if(d!=null&&g!=null){let m=(d+g)/2,v=Math.abs(d-g)/2||1;a=Math.min(100,Math.max(0,Math.abs(u-m)/v*100));let y=Math.abs(u-d)<=Math.abs(u-g)?d:g;r=`${Y(u,p?.lang,1)} / ${Y(y,p?.lang)} ${i}`}else if(d!=null){let m=l.trigger_entity_info?.min,v=d>0?0:m!=null&&mg?m:g>0?g*2:g<0?0:100,y=v-g||1;a=Math.min(100,Math.max(0,(v-u)/y*100)),r=`${Y(u,p?.lang,1)} / ${Y(g,p?.lang)} ${i}`}else if(t.trigger_equals!=null||t.trigger_not_equals!=null){let m=t.trigger_equals!=null?`= ${t.trigger_equals}`:`\u2260 ${t.trigger_not_equals}`;r=`${Y(u,p?.lang,1)} (${m}${i?` ${i}`:""})`,a=l.trigger_active?100:0}else return h}else if(e==="counter"){let u=t.trigger_target_value||1,d;if(t.trigger_delta_mode?(d=l.trigger_current_delta??null,d==null&&l.trigger_baseline_value!=null&&l.trigger_current_value!=null&&(d=l.trigger_current_value-l.trigger_baseline_value)):d=l.trigger_current_value??null,d==null)return h;a=Math.min(100,Math.max(0,d/u*100)),r=`${Y(d,p?.lang,1)} / ${Y(u,p?.lang)} ${i}`}else if(e==="state_change"){let u=t.trigger_target_changes||1,d=l.trigger_current_value??null;if(d==null)return h;a=Math.min(100,Math.max(0,d/u*100)),r=`${Y(d,p?.lang,0)} / ${Y(u,p?.lang,0)}`}else if(e==="runtime"){let u=t.trigger_runtime_hours||100,d=l.trigger_current_value??null;if(d==null)return h;a=Math.min(100,Math.max(0,d/u*100)),r=`${Y(d,p?.lang,1)}h / ${Y(u,p?.lang)}h`}else if(e==="due_date"){let u=l.trigger_current_value??null;if(u==null)return h;let d=t.trigger_days_before??0;a=u<=d?100:Math.max(0,100-(u-d)/30*100),r=xt(Ke(u),p?.lang)}else if(e==="compound"){let u=t.compound_logic||t.operator||"AND",d=t.conditions?.length||0;r=`${u} (${d})`,a=l.trigger_active?100:0}else return h;if(l.battery_fleet_task&&e==="threshold"&&l.trigger_current_value!=null){let u=Math.round(l.trigger_current_value),d=t.trigger_above??0;a=u>d?100:d>0?Math.max(0,u/(d+1)*100):0,r=s("battery_fleet_progress",p?.lang??"en").replace("{n}",Y(u,p?.lang,0))}let c=a>=100,n=a>90?"var(--error-color, #f44336)":a>70?"var(--warning-color, #ff9800)":"var(--primary-color)";return o` + `,_([R({attribute:!1})],$e.prototype,"hass",2),_([f()],$e.prototype,"_open",2),_([f()],$e.prototype,"_busy",2),_([f()],$e.prototype,"_error",2),_([f()],$e.prototype,"_name",2),_([f()],$e.prototype,"_views",2);customElements.get("maintenance-saved-views-dialog")||customElements.define("maintenance-saved-views-dialog",$e);var aa=60,ra=20,vs=30,na={approaching:"\u2197",stable:"\u2192",easing:"\u2198"};function Gt(l,d){let e=l.trigger_config,t=ge(e);if(!e||!t||l.battery_fleet_task)return null;let i,a=e.type||"threshold";if(a==="threshold")if(e.trigger_above!=null)i=1;else if(e.trigger_below!=null)i=-1;else return null;else if(a==="counter"||a==="runtime"||a==="state_change")i=1;else return null;let r=d.get(t)||[],c=a==="runtime"||a==="state_change",o=r.length>=2?r.map(E=>({ts:E.ts,val:E.val})):c?[]:(l.history||[]).filter(E=>E.trigger_value!=null).map(E=>({ts:fe(E.timestamp),val:E.trigger_value}));if(l.trigger_current_value!=null&&(o=[...o,{ts:Date.now(),val:l.trigger_current_value}]),o.length<2)return null;o.sort((E,w)=>E.ts-w.ts);let u=o.map(E=>E.val),p=Math.max(...u)-Math.min(...u),g=u[u.length-1]-u[0],m=e.trigger_delta_mode&&l.trigger_baseline_value!=null&&e.trigger_target_value!=null?l.trigger_baseline_value+e.trigger_target_value:e.trigger_target_value,v=a==="threshold"?e.trigger_above??e.trigger_below:a==="counter"?m:a==="runtime"?e.trigger_runtime_hours:e.trigger_target_changes,y=typeof v=="number"?Math.max(Math.abs(v-u[0]),p):p;return y===0||Math.abs(g)0?Math.ceil(l):Math.trunc(l)||0}function Qt(l,d){let e=l.trigger_config??null;if(!e)return h;let t=e.type||"threshold",i=l.trigger_entity_info?.unit_of_measurement??"",a=0,r="";if(t==="threshold"){let u=l.trigger_current_value??null;if(u==null)return h;let p=e.trigger_above,g=e.trigger_below;if(p!=null&&g!=null){let m=(p+g)/2,v=Math.abs(p-g)/2||1;a=Math.min(100,Math.max(0,Math.abs(u-m)/v*100));let y=Math.abs(u-p)<=Math.abs(u-g)?p:g;r=`${G(u,d?.lang,1)} / ${G(y,d?.lang)} ${i}`}else if(p!=null){let m=l.trigger_entity_info?.min,v=p>0?0:m!=null&&mg?m:g>0?g*2:g<0?0:100,y=v-g||1;a=Math.min(100,Math.max(0,(v-u)/y*100)),r=`${G(u,d?.lang,1)} / ${G(g,d?.lang)} ${i}`}else if(e.trigger_equals!=null||e.trigger_not_equals!=null){let m=e.trigger_equals!=null?`= ${e.trigger_equals}`:`\u2260 ${e.trigger_not_equals}`;r=`${G(u,d?.lang,1)} (${m}${i?` ${i}`:""})`,a=l.trigger_active?100:0}else return h}else if(t==="counter"){let u=e.trigger_target_value||1,p;if(e.trigger_delta_mode?(p=l.trigger_current_delta??null,p==null&&l.trigger_baseline_value!=null&&l.trigger_current_value!=null&&(p=l.trigger_current_value-l.trigger_baseline_value)):p=l.trigger_current_value??null,p==null)return h;a=Math.min(100,Math.max(0,p/u*100)),r=`${G(p,d?.lang,1)} / ${G(u,d?.lang)} ${i}`}else if(t==="state_change"){let u=e.trigger_target_changes||1,p=l.trigger_current_value??null;if(p==null)return h;a=Math.min(100,Math.max(0,p/u*100)),r=`${G(p,d?.lang,0)} / ${G(u,d?.lang,0)}`}else if(t==="runtime"){let u=e.trigger_runtime_hours||100,p=l.trigger_current_value??null;if(p==null)return h;a=Math.min(100,Math.max(0,p/u*100)),r=`${G(p,d?.lang,1)}h / ${G(u,d?.lang)}h`}else if(t==="due_date"){let u=l.trigger_current_value??null;if(u==null)return h;let p=e.trigger_days_before??0;a=u<=p?100:Math.max(0,100-(u-p)/30*100),r=xe(Yt(u),d?.lang)}else if(t==="compound"){let u=e.compound_logic||e.operator||"AND",p=e.conditions?.length||0;r=`${u} (${p})`,a=l.trigger_active?100:0}else return h;if(l.battery_fleet_task&&t==="threshold"&&l.trigger_current_value!=null){let u=Math.round(l.trigger_current_value),p=e.trigger_above??0;a=u>p?100:p>0?Math.max(0,u/(p+1)*100):0,r=s("battery_fleet_progress",d?.lang??"en").replace("{n}",G(u,d?.lang,0))}let c=a>=100,o=a>90?"var(--error-color, #f44336)":a>70?"var(--warning-color, #ff9800)":"var(--primary-color)";return n`
    -
    +
    - ${r}${p?.trend?o` ${ia[p.trend]}`:h} + ${r}${d?.trend?n` ${na[d.trend]}`:h}
    - `}function Ye(l,p,t){let e=gt(l.trigger_config);if(!e||l.battery_fleet_task)return h;let i=p.get(e)||[],a=[];if(i.length>=2)a=i.map(b=>({ts:b.ts,val:b.val}));else{if(!l.history)return h;for(let b of l.history)b.trigger_value!=null&&a.push({ts:ft(b.timestamp),val:b.trigger_value})}if(l.trigger_current_value!=null&&a.push({ts:Date.now(),val:l.trigger_current_value}),a.length<2)return h;a.sort((b,D)=>b.ts-D.ts);let r=ta,c=ea,n=a.map(b=>b.val),u=Math.min(...n),d=Math.max(...n),g=d-u||1;u-=g*.1,d+=g*.1;let m=a[0].ts,y=a[a.length-1].ts-m||1,E=b=>(b-m)/y*r,w=b=>2+(1-(b-u)/(d-u))*(c-4),j=a;if(j.length>_s){let b=Math.ceil(j.length/_s);j=j.filter((D,at)=>at%b===0||at===j.length-1)}let x=j.map(b=>`${O(E(b.ts))},${O(w(b.val))}`).join(" "),M=l.trigger_active?"var(--error-color, #f44336)":"var(--primary-color)";return o` - + `}function Jt(l,d,e){let t=ge(l.trigger_config);if(!t||l.battery_fleet_task)return h;let i=d.get(t)||[],a=[];if(i.length>=2)a=i.map(b=>({ts:b.ts,val:b.val}));else{if(!l.history)return h;for(let b of l.history)b.trigger_value!=null&&a.push({ts:fe(b.timestamp),val:b.trigger_value})}if(l.trigger_current_value!=null&&a.push({ts:Date.now(),val:l.trigger_current_value}),a.length<2)return h;a.sort((b,D)=>b.ts-D.ts);let r=aa,c=ra,o=a.map(b=>b.val),u=Math.min(...o),p=Math.max(...o),g=p-u||1;u-=g*.1,p+=g*.1;let m=a[0].ts,y=a[a.length-1].ts-m||1,E=b=>(b-m)/y*r,w=b=>2+(1-(b-u)/(p-u))*(c-4),j=a;if(j.length>vs){let b=Math.ceil(j.length/vs);j=j.filter((D,se)=>se%b===0||se===j.length-1)}let x=j.map(b=>`${O(E(b.ts))},${O(w(b.val))}`).join(" "),M=l.trigger_active?"var(--error-color, #f44336)":"var(--primary-color)";return n` + - `}function Qe(l,p,t,e="due-text"){if(l==null){let i=ni(p,t);if(i)return o`${i}`}return o`${xt(l,t)}`}function ms(l,p){let t=p;if(l.days_until_due==null||!l.interval_days||l.interval_days<=0)return h;let{pct:e,overflow:i}=be(l.interval_days,l.days_until_due,l.interval_unit),a="var(--success-color, #4caf50)";return l.status==="overdue"?a="var(--error-color, #f44336)":l.status==="due_soon"&&(a="var(--warning-color, #ff9800)"),o` + `}function Xt(l,d,e,t="due-text"){if(l==null){let i=di(d,e);if(i)return n`${i}`}return n`${xe(l,e)}`}function bs(l,d){let e=d;if(l.days_until_due==null||!l.interval_days||l.interval_days<=0)return h;let{pct:t,overflow:i}=yt(l.interval_days,l.days_until_due,l.interval_unit),a="var(--success-color, #4caf50)";return l.status==="overdue"?a="var(--error-color, #f44336)":l.status==="due_soon"&&(a="var(--warning-color, #ff9800)"),n`
    - ${l.last_performed?`${s("last_performed",t)}: ${q(l.last_performed,t)}`:""} - ${l.next_due?`${s("next_due",t)}: ${q(l.next_due,t)}`:""} + ${l.last_performed?`${s("last_performed",e)}: ${q(l.last_performed,e)}`:""} + ${l.next_due?`${s("next_due",e)}: ${q(l.next_due,e)}`:""}
    -
    -
    +
    +
    -
    ${xt(l.days_until_due,t)}
    +
    ${xe(l.days_until_due,e)}
    - `}var Se=210,bt=46,Ot=14,Ct=12,fs=14,sa=20+fs,aa=[{days:7,key:"chart_range_7d"},{days:30,key:"chart_range_30d"},{days:90,key:"chart_range_90d"},{days:365,key:"chart_range_1y"}],et=class extends N{constructor(){super(...arguments);this.points=[];this.events=[];this.unit="";this.lang="en";this.thresholdAbove=null;this.thresholdBelow=null;this.targetValue=null;this.forceZero=!1;this.projection=null;this.rangeDays=30;this.showRange=!0;this.busy=!1;this.hideOutliers=!1;this.showOutlierToggle=!0;this._width=0;this._hover=null;this._ro=null}connectedCallback(){super.connectedCallback(),this._ro=new ResizeObserver(t=>{let e=Math.floor(t[0]?.contentRect?.width||0);e&&Math.abs(e-this._width)>2&&(this._width=e)}),this._ro.observe(this)}disconnectedCallback(){super.disconnectedCallback(),this._ro?.disconnect(),this._ro=null}_emitRange(t){t!==this.rangeDays&&this.dispatchEvent(new CustomEvent("range-change",{detail:{days:t},bubbles:!0,composed:!0}))}_toggleOutliers(){this.dispatchEvent(new CustomEvent("outlier-toggle",{detail:{hide:!this.hideOutliers},bubbles:!0,composed:!0}))}render(){let t=this._width||320,e=[...this.points].sort((a,r)=>a.ts-r.ts),i=this.lang;return o` + `}var Tt=210,be=46,Oe=14,Ce=12,ys=14,oa=20+ys,la=[{days:7,key:"chart_range_7d"},{days:30,key:"chart_range_30d"},{days:90,key:"chart_range_90d"},{days:365,key:"chart_range_1y"}],te=class extends N{constructor(){super(...arguments);this.points=[];this.events=[];this.unit="";this.lang="en";this.thresholdAbove=null;this.thresholdBelow=null;this.targetValue=null;this.forceZero=!1;this.projection=null;this.rangeDays=30;this.showRange=!0;this.busy=!1;this.hideOutliers=!1;this.showOutlierToggle=!0;this._width=0;this._hover=null;this._ro=null}connectedCallback(){super.connectedCallback(),this._ro=new ResizeObserver(e=>{let t=Math.floor(e[0]?.contentRect?.width||0);t&&Math.abs(t-this._width)>2&&(this._width=t)}),this._ro.observe(this)}disconnectedCallback(){super.disconnectedCallback(),this._ro?.disconnect(),this._ro=null}_emitRange(e){e!==this.rangeDays&&this.dispatchEvent(new CustomEvent("range-change",{detail:{days:e},bubbles:!0,composed:!0}))}_toggleOutliers(){this.dispatchEvent(new CustomEvent("outlier-toggle",{detail:{hide:!this.hideOutliers},bubbles:!0,composed:!0}))}render(){let e=this._width||320,t=[...this.points].sort((a,r)=>a.ts-r.ts),i=this.lang;return n`
    - ${this.showRange?o`
    - ${this.showOutlierToggle?o``:h} - ${aa.map(a=>o``)}
    `:h} - ${e.length<2?o`
    + ${t.length<2?n`
    ${s("loading_chart",i)} -
    `:this._renderSvg(t,e)} +
    `:this._renderSvg(e,t)}
    - `}_renderSvg(t,e){let i=this.lang,a=t-bt-Ot,r=Se-sa,c=r-Ct,n=1/0,u=-1/0;for(let S of e)n=Math.min(n,S.min??S.val),u=Math.max(u,S.max??S.val);this.thresholdAbove!=null&&(n=Math.min(n,this.thresholdAbove),u=Math.max(u,this.thresholdAbove)),this.thresholdBelow!=null&&(n=Math.min(n,this.thresholdBelow),u=Math.max(u,this.thresholdBelow)),this.targetValue!=null&&(n=Math.min(n,this.targetValue),u=Math.max(u,this.targetValue)),this.forceZero&&(n=Math.min(n,0));let d=(u-n||1)*.06,g=this.forceZero&&n>=0?0:n-d,{ticks:m,niceMin:v,niceMax:y}=Zt(g,u+d,4);this.forceZero&&n>=0&&v<0&&(v=0,m=m.filter(S=>S>=0));let E=e[0].ts,w=this.projection&&this.projection.length===2?this.projection[1].ts:null,j=w!=null?Math.max(e[e.length-1].ts,w):e[e.length-1].ts,x=j-E||1,M=me(E,j),b=S=>bt+(S-E)/x*a,D=S=>Ct+(1-(S-v)/(y-v||1))*c,at=e.map(S=>`${O(b(S.ts))},${O(D(S.val))}`).join(" "),pt=`M${O(b(e[0].ts))},${r} `+e.map(S=>`L${O(b(S.ts))},${O(D(S.val))}`).join(" ")+` L${O(b(e[e.length-1].ts))},${r} Z`,T="",z=e.filter(S=>S.min!=null&&S.max!=null);if(z.length>=2){let S=z.map(rt=>`${O(b(rt.ts))},${O(D(rt.max))}`),X=[...z].reverse().map(rt=>`${O(b(rt.ts))},${O(D(rt.min))}`);T=`M${S[0]} `+S.slice(1).map(rt=>`L${rt}`).join(" ")+` L${X.join(" L")} Z`}let H=[];if(this.thresholdBelow!=null){let S=D(this.thresholdBelow);H.push({y:S,h:Math.max(0,r-S),lineY:S,label:`\u25BC ${kt(this.thresholdBelow,i)}`,labelY:Math.min(r-4,S+13)})}if(this.thresholdAbove!=null){let S=D(this.thresholdAbove);H.push({y:Ct,h:Math.max(0,S-Ct),lineY:S,label:`\u25B2 ${kt(this.thresholdAbove,i)}`,labelY:Math.max(Ct+11,S-5)})}let I=e[e.length-1],W=(this.events||[]).filter(S=>S.ts>=E&&S.ts<=j),Q=fe(E,j,Math.max(2,Math.min(5,Math.floor(a/110)+1))),J=this._hover;return o` + `}_renderSvg(e,t){let i=this.lang,a=e-be-Oe,r=Tt-oa,c=r-Ce,o=1/0,u=-1/0;for(let S of t)o=Math.min(o,S.min??S.val),u=Math.max(u,S.max??S.val);this.thresholdAbove!=null&&(o=Math.min(o,this.thresholdAbove),u=Math.max(u,this.thresholdAbove)),this.thresholdBelow!=null&&(o=Math.min(o,this.thresholdBelow),u=Math.max(u,this.thresholdBelow)),this.targetValue!=null&&(o=Math.min(o,this.targetValue),u=Math.max(u,this.targetValue)),this.forceZero&&(o=Math.min(o,0));let p=(u-o||1)*.06,g=this.forceZero&&o>=0?0:o-p,{ticks:m,niceMin:v,niceMax:y}=Ze(g,u+p,4);this.forceZero&&o>=0&&v<0&&(v=0,m=m.filter(S=>S>=0));let E=t[0].ts,w=this.projection&&this.projection.length===2?this.projection[1].ts:null,j=w!=null?Math.max(t[t.length-1].ts,w):t[t.length-1].ts,x=j-E||1,M=ft(E,j),b=S=>be+(S-E)/x*a,D=S=>Ce+(1-(S-v)/(y-v||1))*c,se=t.map(S=>`${O(b(S.ts))},${O(D(S.val))}`).join(" "),pe=`M${O(b(t[0].ts))},${r} `+t.map(S=>`L${O(b(S.ts))},${O(D(S.val))}`).join(" ")+` L${O(b(t[t.length-1].ts))},${r} Z`,T="",z=t.filter(S=>S.min!=null&&S.max!=null);if(z.length>=2){let S=z.map(ae=>`${O(b(ae.ts))},${O(D(ae.max))}`),X=[...z].reverse().map(ae=>`${O(b(ae.ts))},${O(D(ae.min))}`);T=`M${S[0]} `+S.slice(1).map(ae=>`L${ae}`).join(" ")+` L${X.join(" L")} Z`}let H=[];if(this.thresholdBelow!=null){let S=D(this.thresholdBelow);H.push({y:S,h:Math.max(0,r-S),lineY:S,label:`\u25BC ${ke(this.thresholdBelow,i)}`,labelY:Math.min(r-4,S+13)})}if(this.thresholdAbove!=null){let S=D(this.thresholdAbove);H.push({y:Ce,h:Math.max(0,S-Ce),lineY:S,label:`\u25B2 ${ke(this.thresholdAbove,i)}`,labelY:Math.max(Ce+11,S-5)})}let I=t[t.length-1],W=(this.events||[]).filter(S=>S.ts>=E&&S.ts<=j),Q=vt(E,j,Math.max(2,Math.min(5,Math.floor(a/110)+1))),J=this._hover;return n`
    this._onPointer(S,e,b,D,t)} - @pointerdown=${S=>this._onPointer(S,e,b,D,t)} + @pointermove=${S=>this._onPointer(S,t,b,D,e)} + @pointerdown=${S=>this._onPointer(S,t,b,D,e)} @pointerleave=${()=>this._hover=null} > - - ${H.length?G`${H.map(S=>G``)}`:h} + + ${H.length?Y`${H.map(S=>Y``)}`:h} @@ -4851,63 +4966,63 @@ ${c.capped?`

    ${$(t.capNote)}

    `:""} - ${m.map(S=>{let X=D(S);return Xr+1?h:G` - {let X=D(S);return Xr+1?h:Y` + - ${kt(S,i)}`})} + ${ke(S,i)}`})} - ${H.map(S=>G`Y``)} - ${T?G``:h} - - `:h} + + - ${H.length?G``:h} - ${H.map(S=>G` - Y` + - ${S.label}`)} + ${S.label}`)} - ${this.targetValue!=null?G` - ◆ ${kt(this.targetValue,i)} ${this.unit}`:h} + ◆ ${ke(this.targetValue,i)} ${this.unit}`:h} - ${this.projection&&this.projection.length===2?G``:h} - ${Q.map((S,X)=>{let rt=b(S),At=X===0?"start":X===Q.length-1?"end":"middle";return G`${qt(S,i,M)}`})} + ${Q.map((S,X)=>{let ae=b(S),Ae=X===0?"start":X===Q.length-1?"end":"middle";return Y`${qe(S,i,M)}`})} - + - ${W.map(S=>{let X=b(S.ts),rt=S.type==="completed"?"var(--success-color, #4caf50)":S.type==="skipped"?"var(--warning-color, #ff9800)":"var(--info-color, #2196f3)";return G` - - - ${ze(S.ts,i)} + ${W.map(S=>{let X=b(S.ts),ae=S.type==="completed"?"var(--success-color, #4caf50)":S.type==="skipped"?"var(--warning-color, #ff9800)":"var(--info-color, #2196f3)";return Y` + + + ${Pt(S.ts,i)} `})} - ${J?G` - `:G``:Y``} - ${J?o`
    -
    ${ze(J.p.ts,i)}
    +
    ${Pt(J.p.ts,i)}
    - ${zt(J.p.val,this.unit,i)} - ${J.p.min!=null&&J.p.max!=null?o`(${kt(J.p.min,i)}–${kt(J.p.max,i)})`:h} + ${ze(J.p.val,this.unit,i)} + ${J.p.min!=null&&J.p.max!=null?n`(${ke(J.p.min,i)}–${ke(J.p.max,i)})`:h}
    `:h}
    - `}_onPointer(t,e,i,a,r){let n=t.currentTarget.getBoundingClientRect(),u=(t.clientX-n.left)/n.width*r;if(ur-Ot+8){this._hover=null;return}let d=e[0],g=1/0;for(let m of e){let v=Math.abs(i(m.ts)-u);vr-Oe+8){this._hover=null;return}let p=t[0],g=1/0;for(let m of t){let v=Math.abs(i(m.ts)-u);v${$(t.capNote)}

    `:""} .hover-date { font-size: 10.5px; color: var(--secondary-text-color); } .hover-val { font-size: 12.5px; font-weight: 600; color: var(--primary-text-color); } .hover-range { font-weight: 400; color: var(--secondary-text-color); font-size: 11px; } - `,_([R({attribute:!1})],et.prototype,"points",2),_([R({attribute:!1})],et.prototype,"events",2),_([R()],et.prototype,"unit",2),_([R()],et.prototype,"lang",2),_([R({attribute:!1})],et.prototype,"thresholdAbove",2),_([R({attribute:!1})],et.prototype,"thresholdBelow",2),_([R({attribute:!1})],et.prototype,"targetValue",2),_([R({type:Boolean})],et.prototype,"forceZero",2),_([R({attribute:!1})],et.prototype,"projection",2),_([R({attribute:!1})],et.prototype,"rangeDays",2),_([R({type:Boolean})],et.prototype,"showRange",2),_([R({type:Boolean})],et.prototype,"busy",2),_([R({type:Boolean})],et.prototype,"hideOutliers",2),_([R({type:Boolean})],et.prototype,"showOutlierToggle",2),_([f()],et.prototype,"_width",2),_([f()],et.prototype,"_hover",2);customElements.get("maintenance-trigger-chart")||customElements.define("maintenance-trigger-chart",et);function vs(l){let p=(l??"").trim().toLowerCase();return p==="on"||p==="open"||p==="true"?1:p==="off"||p==="closed"||p==="false"?0:null}function ra(l,p,t){if(l.length<2)return null;let e=t.now??Date.now(),i=Math.max(0,p.trigger_for_minutes??0)*6e4,a=p.trigger_from_state?vs(p.trigger_from_state):null,r=p.trigger_to_state?vs(p.trigger_to_state):null;if(p.trigger_from_state&&a===null||p.trigger_to_state&&r===null)return null;let c=[...l].sort((x,M)=>x.ts-M.ts),n=[];for(let x of c){let M=n[n.length-1];(!M||M.level!==x.val)&&n.push({start:x.ts,level:x.val})}let u=x=>(x+1=i,d=(x,M,b)=>{let D=x[x.length-1];D&&D.val!==b&&x.push({ts:M,val:D.val}),x.push({ts:M,val:b})};if((p.trigger_target_changes??1)===1&&r!==null){let x=[];n.forEach((b,D)=>d(x,b.start,b.level===r&&u(D)?1:0));let M=x[x.length-1]?.val??0;return x.push({ts:e,val:M}),{points:x,mode:"alarm"}}let m=t.since??n[0].start,v=0,y=[];for(let x=1;xu.val).sort((u,d)=>u-d),t=u=>{let d=(p.length-1)*u,g=Math.floor(d),m=Math.ceil(d);return p[g]+(p[m]-p[g])*(d-g)},e=t(.25),i=t(.75),a=i-e;if(a===0)return l;let r=e-1.5*a,c=i+1.5*a,n=l.filter(u=>u.val>=r&&u.val<=c);return n.length>=2?n:l}function bs(l,p){let t=l.trigger_config;if(!t)return h;let e=p.lang,i=l.trigger_entity_info,a=l.trigger_entity_infos,r=gt(t)||"",c=i?.friendly_name||r||"\u2014",n=Pe(t),u=i?.unit_of_measurement||"",d=l.trigger_current_value,g=t.type||"threshold",m=n.length>1,v=na(l,u,p);return o` -

    ${s("trigger",e)}

    + `,_([R({attribute:!1})],te.prototype,"points",2),_([R({attribute:!1})],te.prototype,"events",2),_([R()],te.prototype,"unit",2),_([R()],te.prototype,"lang",2),_([R({attribute:!1})],te.prototype,"thresholdAbove",2),_([R({attribute:!1})],te.prototype,"thresholdBelow",2),_([R({attribute:!1})],te.prototype,"targetValue",2),_([R({type:Boolean})],te.prototype,"forceZero",2),_([R({attribute:!1})],te.prototype,"projection",2),_([R({attribute:!1})],te.prototype,"rangeDays",2),_([R({type:Boolean})],te.prototype,"showRange",2),_([R({type:Boolean})],te.prototype,"busy",2),_([R({type:Boolean})],te.prototype,"hideOutliers",2),_([R({type:Boolean})],te.prototype,"showOutlierToggle",2),_([f()],te.prototype,"_width",2),_([f()],te.prototype,"_hover",2);customElements.get("maintenance-trigger-chart")||customElements.define("maintenance-trigger-chart",te);function xs(l){let d=(l??"").trim().toLowerCase();return d==="on"||d==="open"||d==="true"?1:d==="off"||d==="closed"||d==="false"?0:null}function ca(l,d,e){if(l.length<2)return null;let t=e.now??Date.now(),i=Math.max(0,d.trigger_for_minutes??0)*6e4,a=d.trigger_from_state?xs(d.trigger_from_state):null,r=d.trigger_to_state?xs(d.trigger_to_state):null;if(d.trigger_from_state&&a===null||d.trigger_to_state&&r===null)return null;let c=[...l].sort((x,M)=>x.ts-M.ts),o=[];for(let x of c){let M=o[o.length-1];(!M||M.level!==x.val)&&o.push({start:x.ts,level:x.val})}let u=x=>(x+1=i,p=(x,M,b)=>{let D=x[x.length-1];D&&D.val!==b&&x.push({ts:M,val:D.val}),x.push({ts:M,val:b})};if((d.trigger_target_changes??1)===1&&r!==null){let x=[];o.forEach((b,D)=>p(x,b.start,b.level===r&&u(D)?1:0));let M=x[x.length-1]?.val??0;return x.push({ts:t,val:M}),{points:x,mode:"alarm"}}let m=e.since??o[0].start,v=0,y=[];for(let x=1;xu.val).sort((u,p)=>u-p),e=u=>{let p=(d.length-1)*u,g=Math.floor(p),m=Math.ceil(p);return d[g]+(d[m]-d[g])*(p-g)},t=e(.25),i=e(.75),a=i-t;if(a===0)return l;let r=t-1.5*a,c=i+1.5*a,o=l.filter(u=>u.val>=r&&u.val<=c);return o.length>=2?o:l}function ks(l,d){let e=l.trigger_config;if(!e)return h;let t=d.lang,i=l.trigger_entity_info,a=l.trigger_entity_infos,r=ge(e)||"",c=i?.friendly_name||r||"\u2014",o=Lt(e),u=i?.unit_of_measurement||"",p=l.trigger_current_value,g=e.type||"threshold",m=o.length>1,v=pa(l,u,d);return n` +

    ${s("trigger",t)}

    - ${m?o` -
    ${n.length} ${s("entities",e)} (${t.entity_logic||"any"})
    -
    ${n.map((y,E)=>o`${E>0?", ":""}Qt(w,y)}>${y}`)}${t.attribute?` \u2192 ${t.attribute}`:""}
    - `:o` + ${m?n` +
    ${o.length} ${s("entities",t)} (${e.entity_logic||"any"})
    +
    ${o.map((y,E)=>n`${E>0?", ":""}Qe(w,y)}>${y}`)}${e.attribute?` \u2192 ${e.attribute}`:""}
    + `:n`
    ${c}
    -
    ${r?o`Qt(y,r)}>${r}`:""}${t.attribute?` \u2192 ${t.attribute}`:""}
    +
    ${r?n`Qe(y,r)}>${r}`:""}${e.attribute?` \u2192 ${e.attribute}`:""}
    `}
    - ${l.trigger_active?s("triggered",e):s("ok",e)} + ${l.trigger_active?s("triggered",t):s("ok",t)}
    - ${v?la(v,e):d!=null?o` + ${v?ha(v,t):p!=null?n`
    - ${g==="due_date"&&typeof d=="number"?xt(Ke(d),e):typeof d=="number"?zt(d,"",e):d} - ${u?o`${u}`:h} + ${g==="due_date"&&typeof p=="number"?xe(Yt(p),t):typeof p=="number"?ze(p,"",t):p} + ${u?n`${u}`:h}
    `:h}
    - ${g==="threshold"?o` - ${t.trigger_above!=null?o` ${s("threshold_above",e)}: ${t.trigger_above} ${u}`:h} - ${t.trigger_below!=null?o` ${s("threshold_below",e)}: ${t.trigger_below} ${u}`:h} - ${t.trigger_equals!=null?o` = ${t.trigger_equals} ${u}`:h} - ${t.trigger_not_equals!=null?o` ≠ ${t.trigger_not_equals} ${u}`:h} - ${t.trigger_for_minutes?o` ${s("for_minutes",e)}: ${t.trigger_for_minutes}`:h} + ${g==="threshold"?n` + ${e.trigger_above!=null?n` ${s("threshold_above",t)}: ${e.trigger_above} ${u}`:h} + ${e.trigger_below!=null?n` ${s("threshold_below",t)}: ${e.trigger_below} ${u}`:h} + ${e.trigger_equals!=null?n` = ${e.trigger_equals} ${u}`:h} + ${e.trigger_not_equals!=null?n` ≠ ${e.trigger_not_equals} ${u}`:h} + ${e.trigger_for_minutes?n` ${s("for_minutes",t)}: ${e.trigger_for_minutes}`:h} `:h} - ${g==="state_change"?o` - ${t.trigger_target_changes!=null?o` ${s("target_changes",e)}: ${t.trigger_target_changes}`:h} + ${g==="state_change"?n` + ${e.trigger_target_changes!=null?n` ${s("target_changes",t)}: ${e.trigger_target_changes}`:h} `:h} - ${g==="runtime"?o` - ${t.trigger_runtime_hours!=null?o` ${s("runtime_hours",e)}: ${t.trigger_runtime_hours}h`:h} + ${g==="runtime"?n` + ${e.trigger_runtime_hours!=null?n` ${s("runtime_hours",t)}: ${e.trigger_runtime_hours}h`:h} `:h} - ${g==="due_date"?o` - ${s("days_before",e)}: ${t.trigger_days_before??0} + ${g==="due_date"?n` + ${s("days_before",t)}: ${e.trigger_days_before??0} `:h} - ${g==="compound"?o` - ${s("compound_logic",e)}: ${t.compound_logic||t.operator||"AND"} - ${(t.conditions||[]).map((y,E)=>o` - ${E+1}. ${s(y.type==="due_date"?"trigger_type_due_date":y.type||"unknown",e)}: ${Pe(y).map((w,j)=>o`${j>0?", ":""}Qt(x,w)}>${w}`)} + ${g==="compound"?n` + ${s("compound_logic",t)}: ${e.compound_logic||e.operator||"AND"} + ${(e.conditions||[]).map((y,E)=>n` + ${E+1}. ${s(y.type==="due_date"?"trigger_type_due_date":y.type||"unknown",t)}: ${Lt(y).map((w,j)=>n`${j>0?", ":""}Qe(x,w)}>${w}`)} `)} `:h}
    - ${a&&a.length>1?o` + ${a&&a.length>1?n`
    - ${a.map(y=>o` - ${y.friendly_name} (Qt(E,y.entity_id)}>${y.entity_id}) + ${a.map(y=>n` + ${y.friendly_name} (Qe(E,y.entity_id)}>${y.entity_id}) `)}
    `:h} - ${ca(l,u,p)} + ${ua(l,u,d)}
    - `}function na(l,p,t){let e=l.trigger_config,i=l.trigger_current_value;if(!e||i==null)return null;switch(e.type||"threshold"){case"counter":{let a=e.trigger_target_value;if(a==null||a<=0)return null;if(!e.trigger_delta_mode)return{progress:Math.max(0,i),target:a,unit:p,meter:null};let r=ys(l,xs(l,t));return{progress:Math.max(0,i-(r?.value??i)),target:a,unit:p,meter:i}}case"state_change":{let a=e.trigger_target_changes;return a==null||a<=0?null:{progress:Math.max(0,i),target:a,unit:"",meter:null}}case"runtime":{let a=e.trigger_runtime_hours;return a==null||a<=0?null:{progress:Math.max(0,i),target:a,unit:"h",meter:null}}}return null}function ys(l,p){if(l.trigger_baseline_value!=null)return{value:l.trigger_baseline_value,ts:Te(l)};if(!p.length)return null;let t=Te(l);if(t==null)return{value:p[0].val,ts:null};let e=p[0],i=Math.abs(p[0].ts-t);for(let a of p){let r=Math.abs(a.ts-t);rt.type==="completed"||t.type==="reset").sort((t,e)=>ft(e.timestamp)-ft(t.timestamp))[0];return p?ft(p.timestamp):null}function la(l,p){let t=Math.min(999,Math.round(l.progress/l.target*100)),e=t>=100?"over":t>=75?"near":"ok";return o` + `}function pa(l,d,e){let t=l.trigger_config,i=l.trigger_current_value;if(!t||i==null)return null;switch(t.type||"threshold"){case"counter":{let a=t.trigger_target_value;if(a==null||a<=0)return null;if(!t.trigger_delta_mode)return{progress:Math.max(0,i),target:a,unit:d,meter:null};let r=ws(l,$s(l,e));return{progress:Math.max(0,i-(r?.value??i)),target:a,unit:d,meter:i}}case"state_change":{let a=t.trigger_target_changes;return a==null||a<=0?null:{progress:Math.max(0,i),target:a,unit:"",meter:null}}case"runtime":{let a=t.trigger_runtime_hours;return a==null||a<=0?null:{progress:Math.max(0,i),target:a,unit:"h",meter:null}}}return null}function ws(l,d){if(l.trigger_baseline_value!=null)return{value:l.trigger_baseline_value,ts:Et(l)};if(!d.length)return null;let e=Et(l);if(e==null)return{value:d[0].val,ts:null};let t=d[0],i=Math.abs(d[0].ts-e);for(let a of d){let r=Math.abs(a.ts-e);re.type==="completed"||e.type==="reset").sort((e,t)=>fe(t.timestamp)-fe(e.timestamp))[0];return d?fe(d.timestamp):null}function ha(l,d){let e=Math.min(999,Math.round(l.progress/l.target*100)),t=e>=100?"over":e>=75?"near":"ok";return n`
    - ${zt(l.progress,"",p)} / ${zt(l.target,l.unit,p)} - ${t} % + ${ze(l.progress,"",d)} / ${ze(l.target,l.unit,d)} + ${e} %
    -
    -
    +
    +
    - ${s("chart_since_service",p)}${l.meter!=null?o` · ${s("current",p)}: ${zt(l.meter,l.unit,p)}`:h} + ${s("chart_since_service",d)}${l.meter!=null?n` · ${s("current",d)}: ${ze(l.meter,l.unit,d)}`:h}
    - `}function xs(l,p){let t=l.trigger_config;if(!t)return[];let e=t.type||"threshold",i=gt(t)||"",a=e==="runtime"?[]:p.detailStatsData.get(i)||[],r=p.isCounterEntity(t),c=[];if(a.length>=2)for(let u of a){let d={ts:u.ts,val:u.val};!r&&u.min!=null&&u.max!=null&&(d.min=u.min,d.max=u.max),c.push(d)}else for(let u of l.history)u.trigger_value!=null&&c.push({ts:ft(u.timestamp),val:u.trigger_value});let n=!!i&&!!p.historyFallbackIds?.has(i)&&a.length>=2;return l.trigger_current_value!=null&&!n&&c.push({ts:Date.now(),val:l.trigger_current_value}),c.sort((u,d)=>u.ts-d.ts),c}function ca(l,p,t){let e=l.trigger_config;if(!e)return h;let i=e.type||"threshold",a=gt(e)||"";if(i==="due_date")return h;let r=xs(l,t),c=null;i==="state_change"&&a&&t.historyFallbackIds?.has(a)&&(c=ra(r,e,{since:Te(l),current:l.trigger_current_value??null}),c&&(r=c.points)),i==="runtime"&&e.trigger_runtime_hours&&l.trigger_current_value!=null&&(r=[{ts:Te(l)??r[0]?.ts??Date.now()-864e5,val:0},{ts:Date.now(),val:Math.max(0,l.trigger_current_value)}]),t.hideOutliers&&(r=oa(r));let n=r.length<2&&!!a&&t.hasStatsService&&!t.detailStatsData.has(a);if(r.length<2&&!n)return h;let u=!!a&&t.detailStatsData.has(a)&&(t.detailStatsData.get(a)?.length??0)<2,d=Date.now()-t.rangeDays*864e5,g=r.filter(x=>x.ts>=d);g.length>=2&&(r=g);let m=null,v=!1;if(i==="counter"&&e.trigger_target_value!=null&&r.length){if(e.trigger_delta_mode){let x=ys(l,r);if(x){if(x.ts!=null){let M=r.filter(b=>b.ts>=x.ts);M.length>=2&&(r=M)}r=r.map(M=>({...M,val:Math.max(0,M.val-x.value)}))}}m=e.trigger_target_value,v=!0}else i==="state_change"&&e.trigger_target_changes&&c?.mode!=="alarm"?(m=e.trigger_target_changes,v=!0):i==="runtime"&&e.trigger_runtime_hours&&(m=e.trigger_runtime_hours,v=!0);let y=null,E=l.degradation_rate,w=E!=null&&(e.trigger_below!=null&&e.trigger_above==null&&E>0||e.trigger_above!=null&&e.trigger_below==null&&E<0);if(m==null&&E!=null&&!w&&(l.degradation_trend!=="stable"||l.days_until_threshold!=null)&&l.degradation_trend!=="insufficient_data"&&r.length>=2){let x=r[r.length-1];y=[x,{ts:x.ts+30*864e5,val:x.val+E*30}]}let j=l.history.filter(x=>["completed","skipped","reset"].includes(x.type)).map(x=>({ts:ft(x.timestamp),type:x.type}));return o` + `}function $s(l,d){let e=l.trigger_config;if(!e)return[];let t=e.type||"threshold",i=ge(e)||"",a=t==="runtime"?[]:d.detailStatsData.get(i)||[],r=d.isCounterEntity(e),c=[];if(a.length>=2)for(let u of a){let p={ts:u.ts,val:u.val};!r&&u.min!=null&&u.max!=null&&(p.min=u.min,p.max=u.max),c.push(p)}else for(let u of l.history)u.trigger_value!=null&&c.push({ts:fe(u.timestamp),val:u.trigger_value});let o=!!i&&!!d.historyFallbackIds?.has(i)&&a.length>=2;return l.trigger_current_value!=null&&!o&&c.push({ts:Date.now(),val:l.trigger_current_value}),c.sort((u,p)=>u.ts-p.ts),c}function ua(l,d,e){let t=l.trigger_config;if(!t)return h;let i=t.type||"threshold",a=ge(t)||"";if(i==="due_date")return h;let r=$s(l,e),c=null;i==="state_change"&&a&&e.historyFallbackIds?.has(a)&&(c=ca(r,t,{since:Et(l),current:l.trigger_current_value??null}),c&&(r=c.points)),i==="runtime"&&t.trigger_runtime_hours&&l.trigger_current_value!=null&&(r=[{ts:Et(l)??r[0]?.ts??Date.now()-864e5,val:0},{ts:Date.now(),val:Math.max(0,l.trigger_current_value)}]),e.hideOutliers&&(r=da(r));let o=r.length<2&&!!a&&e.hasStatsService&&!e.detailStatsData.has(a);if(r.length<2&&!o)return h;let u=!!a&&e.detailStatsData.has(a)&&(e.detailStatsData.get(a)?.length??0)<2,p=Date.now()-e.rangeDays*864e5,g=r.filter(x=>x.ts>=p);g.length>=2&&(r=g);let m=null,v=!1;if(i==="counter"&&t.trigger_target_value!=null&&r.length){if(t.trigger_delta_mode){let x=ws(l,r);if(x){if(x.ts!=null){let M=r.filter(b=>b.ts>=x.ts);M.length>=2&&(r=M)}r=r.map(M=>({...M,val:Math.max(0,M.val-x.value)}))}}m=t.trigger_target_value,v=!0}else i==="state_change"&&t.trigger_target_changes&&c?.mode!=="alarm"?(m=t.trigger_target_changes,v=!0):i==="runtime"&&t.trigger_runtime_hours&&(m=t.trigger_runtime_hours,v=!0);let y=null,E=l.degradation_rate,w=E!=null&&(t.trigger_below!=null&&t.trigger_above==null&&E>0||t.trigger_above!=null&&t.trigger_below==null&&E<0);if(m==null&&E!=null&&!w&&(l.degradation_trend!=="stable"||l.days_until_threshold!=null)&&l.degradation_trend!=="insufficient_data"&&r.length>=2){let x=r[r.length-1];y=[x,{ts:x.ts+30*864e5,val:x.val+E*30}]}let j=l.history.filter(x=>["completed","skipped","reset"].includes(x.type)).map(x=>({ts:fe(x.timestamp),type:x.type}));return n` t.setRangeDays(x.detail.days)} - @outlier-toggle=${x=>t.setHideOutliers(x.detail.hide)} + .rangeDays=${e.rangeDays} + .hideOutliers=${e.hideOutliers} + .busy=${o} + @range-change=${x=>e.setRangeDays(x.detail.days)} + @outlier-toggle=${x=>e.setHideOutliers(x.detail.hide)} > - ${n?h:a&&t.historyFallbackIds?.has(a)&&!u?o`
    + ${o?h:a&&e.historyFallbackIds?.has(a)&&!u?n`
    - ${s(c?.mode==="alarm"?"chart_history_alarm":c?.mode==="count"?"chart_history_count":"chart_history_fallback",t.lang)} -
    `:u?o`
    + ${s(c?.mode==="alarm"?"chart_history_alarm":c?.mode==="count"?"chart_history_count":"chart_history_fallback",e.lang)} +
    `:u?n`
    - ${s("chart_no_stats",t.lang)} + ${s("chart_no_stats",e.lang)}
    `:h} - `}var da=200,ee=10,pa=22;function ks(l,p,t,e,i){let a=l.history.filter(n=>n.type==="completed"&&(Rt(n)!=null||n.duration!=null));if(a.length<2)return h;let r=a.some(n=>(Rt(n)??0)!==0),c=a.some(n=>(n.duration??0)>0);return!r&&!c?h:o` + `}var ga=200,it=10,_a=22;function js(l,d,e,t,i){let a=l.history.filter(o=>o.type==="completed"&&(Re(o)!=null||o.duration!=null));if(a.length<2)return h;let r=a.some(o=>(Re(o)??0)!==0),c=a.some(o=>(o.duration??0)>0);return!r&&!c?h:n`
    -

    ${s("cost_duration_chart",p)}

    +

    ${s("cost_duration_chart",d)}

    - ${r?o``:h} - ${r&&c?o``:h} - ${c?o``:h}
    - ${ha(l,p,t,i)} + ${ma(l,d,e,i)}
    - `}function ha(l,p,t,e){let i=l.history.filter(C=>C.type==="completed"&&(Rt(C)!=null||C.duration!=null)).map(C=>({ts:ft(C.timestamp),cost:Rt(C)??0,duration:C.duration??0})).sort((C,it)=>C.ts-it.ts);if(i.length<2)return h;let a=i.some(C=>C.cost!==0),r=i.some(C=>C.cost<0),c=i.some(C=>C.duration>0);if(!a&&!c)return h;let n=t!=="duration"&&a,u=t!=="cost"&&c,d=n||!u&&a,g=u||!n&&c,m=640,v=da,y=d?44:12,E=g?44:12,w=m-y-E,j=v-pa,x=j-ee,M=i[0].ts,b=i[i.length-1].ts,D=(b-M||864e5)*.05,at=M-D,pt=b+D,T=me(M,b),z=C=>y+(C-at)/(pt-at)*w,H=Math.min(0,...i.map(C=>C.cost)),I=Math.max(0,...i.map(C=>C.cost)),W=Zt(H,I>H?I:H+1,3),Q=Zt(0,Math.max(...i.map(C=>C.duration))||1,3),J=W.niceMax-W.niceMin||1,S=C=>ee+(1-(C-W.niceMin)/J)*x,X=C=>ee+(1-C/(Q.niceMax||1))*x,rt=i.length>1?Math.min(...i.slice(1).map((C,it)=>z(C.ts)-z(i[it].ts))):w,At=Math.max(6,Math.min(22,rt*.55)),ht=fe(M,b,Math.max(2,Math.min(4,i.length)));return o` + `}function ma(l,d,e,t){let i=l.history.filter(C=>C.type==="completed"&&(Re(C)!=null||C.duration!=null)).map(C=>({ts:fe(C.timestamp),cost:Re(C)??0,duration:C.duration??0})).sort((C,ie)=>C.ts-ie.ts);if(i.length<2)return h;let a=i.some(C=>C.cost!==0),r=i.some(C=>C.cost<0),c=i.some(C=>C.duration>0);if(!a&&!c)return h;let o=e!=="duration"&&a,u=e!=="cost"&&c,p=o||!u&&a,g=u||!o&&c,m=640,v=ga,y=p?44:12,E=g?44:12,w=m-y-E,j=v-_a,x=j-it,M=i[0].ts,b=i[i.length-1].ts,D=(b-M||864e5)*.05,se=M-D,pe=b+D,T=ft(M,b),z=C=>y+(C-se)/(pe-se)*w,H=Math.min(0,...i.map(C=>C.cost)),I=Math.max(0,...i.map(C=>C.cost)),W=Ze(H,I>H?I:H+1,3),Q=Ze(0,Math.max(...i.map(C=>C.duration))||1,3),J=W.niceMax-W.niceMin||1,S=C=>it+(1-(C-W.niceMin)/J)*x,X=C=>it+(1-C/(Q.niceMax||1))*x,ae=i.length>1?Math.min(...i.slice(1).map((C,ie)=>z(C.ts)-z(i[ie].ts))):w,Ae=Math.max(6,Math.min(22,ae*.55)),he=vt(M,b,Math.max(2,Math.min(4,i.length)));return n`
    - - ${d?W.ticks.map(C=>{let it=S(C);return itj+1?h:G` - - ${kt(C,p)}${e}`}):h} - ${g?Q.ticks.map(C=>{let it=X(C);return itj+1?h:G`${kt(C,p)}m`}):h} + + ${p?W.ticks.map(C=>{let ie=S(C);return iej+1?h:Y` + + ${ke(C,d)}${t}`}):h} + ${g?Q.ticks.map(C=>{let ie=X(C);return iej+1?h:Y`${ke(C,d)}m`}):h} - ${d&&W.niceMin<0?G` + ${p&&W.niceMin<0?Y` `:h} - ${d?i.filter(C=>C.cost!==0).map(C=>{let it=S(Math.max(C.cost,0)),Wt=C.cost<0;return G` - - ${qt(C.ts,p,!0)}: ${Wt?`${s("cost_kind_credit",p)} `:""}${U(Math.abs(C.cost),e,p)}${C.duration?` \xB7 ${C.duration}m`:""} + ${p?i.filter(C=>C.cost!==0).map(C=>{let ie=S(Math.max(C.cost,0)),We=C.cost<0;return Y` + + ${qe(C.ts,d,!0)}: ${We?`${s("cost_kind_credit",d)} `:""}${U(Math.abs(C.cost),t,d)}${C.duration?` \xB7 ${C.duration}m`:""} `}):h} - ${g?G` + ${g?Y` - ${i.map(C=>G` + ${i.map(C=>Y` - ${qt(C.ts,p,!0)}: ${C.duration}m${C.cost?` \xB7 ${U(C.cost,e,p)}`:""} + ${qe(C.ts,d,!0)}: ${C.duration}m${C.cost?` \xB7 ${U(C.cost,t,d)}`:""} `)} `:h} - ${ht.map((C,it)=>{let Wt=it===0?"start":it===ht.length-1?"end":"middle";return G`${qt(C,p,T)}`})} + ${he.map((C,ie)=>{let We=ie===0?"start":ie===he.length-1?"end":"middle";return Y`${qe(C,d,T)}`})}
    - ${d?o`${s("cost",p)}`:h} - ${d&&r?o`${s("cost_kind_credit",p)}`:h} - ${g?o`${s("duration",p)}`:h} + ${p?n`${s("cost",d)}`:h} + ${p&&r?n`${s("cost_kind_credit",d)}`:h} + ${g?n`${s("duration",d)}`:h}
    - `}function Je(l,p,t){if(!l.responsible_user_id)return h;let e=t?.(l.responsible_user_id)??null;if(e)return o`${Ei(e)}${e.name}`;let i=p(l.responsible_user_id);return i?o` + `}function Zt(l,d,e){if(!l.responsible_user_id)return h;let t=e?.(l.responsible_user_id)??null;if(t)return n`${Ci(t)}${t.name}`;let i=d(l.responsible_user_id);return i?n` ${i} - `:h}function ua(l,p){let t=p.lang,e=p.isOperator;return o` + `:h}function fa(l,d){let e=d.lang,t=d.isOperator;return n`
    - p.showTaskView()}>${l.name}${Ut(l.next_event_titles)} - ${Ht(p.taskRef??null,s("ref_number",t))} + d.showTaskView()}>${l.name}${Ue(l.next_event_titles)} + ${He(d.taskRef??null,s("ref_number",e))} · - p.showObject()}>${p.objectName} - ${ve(l,t,"chip")} - ${l.paused&&l.paused_until?o` - ${s("paused_until_label",t)} ${q(l.paused_until,t)} + d.showObject()}>${d.objectName} + ${bt(l,e,"chip")} + ${l.paused&&l.paused_until?n` + ${s("paused_until_label",e)} ${q(l.paused_until,e)} `:h} - ${l.due_override?o` - ${q(l.due_override,t)} + ${l.due_override?n` + ${q(l.due_override,e)} `:h} - ${Je(l,p.getUserName,p.getPerson)} - ${l.notify_enabled===!1?o``:h} - ${l.mirror_todo_entities?.length?o`String(p.hass?.states?.[i]?.attributes?.friendly_name??i)).join(", ")}">`:h} - ${l.nfc_tag_id?o` NFC`:e?h:o`p.openEdit(l)}> + ${Zt(l,d.getUserName,d.getPerson)} + ${l.notify_enabled===!1?n``:h} + ${l.mirror_todo_entities?.length?n`String(d.hass?.states?.[i]?.attributes?.friendly_name??i)).join(", ")}">`:h} + ${l.nfc_tag_id?n` NFC`:t?h:n`d.openEdit(l)}> `}
    - p.openComplete(l)}>${s("complete",t)} - ${l.allow_skip!==!1?o`p.promptSkip()}>${s("skip",t)}`:h} + d.openComplete(l)}>${s("complete",e)} + ${l.allow_skip!==!1?n`d.promptSkip()}>${s("skip",e)}`:h}
    - p.toggleMoreMenu()}> - ${p.moreMenuOpen?o` + d.toggleMoreMenu()}> + ${d.moreMenuOpen?n` `:h}
    - `}function ga(l){let p=l.lang;return o` + `}function va(l){let d=l.lang;return n`
    l.setActiveTab("overview")}> - ${s("overview",p)} + ${s("overview",d)}
    l.setActiveTab("history")}> - ${s("history",p)} + ${s("history",d)}
    - `}function ws(l,p,t,e){let i=e.collapsedSections.has(l);return o` + `}function Ss(l,d,e,t){let i=t.collapsedSections.has(l);return n`
    - - ${i?h:o`
    ${t}
    `} + ${i?h:n`
    ${e}
    `}
    - `}function _a(l,p){if(!fi(l))return h;let t=p.lang,e=l.phase_sequence,i=mi(l.phase_cursor,e.length),a=new Map;for(let r=l.history.length-1;r>=0;r--){let c=l.history[r];c.phase_id&&c.type==="completed"&&!a.has(c.phase_id)&&a.set(c.phase_id,c.timestamp)}return o` + `}function ba(l,d){if(!yi(l))return h;let e=d.lang,t=l.phase_sequence,i=bi(l.phase_cursor,t.length),a=new Map;for(let r=l.history.length-1;r>=0;r--){let c=l.history[r];c.phase_id&&c.type==="completed"&&!a.has(c.phase_id)&&a.set(c.phase_id,c.timestamp)}return n`
    - ${s("phase_sequence_label",t)} + ${s("phase_sequence_label",e)}
    - ${e.map((r,c)=>{let n=l.phases?.[r]?.name||r,u=a.get(r);return o` + ${t.map((r,c)=>{let o=l.phases?.[r]?.name||r,u=a.get(r);return n`
    {c!==i&&p.setPhaseCursor(c)}}> - ${c+1}. ${n} - ${u?o`${q(u,t)}`:h} + title=${c===i?s("phase_current",e):s("phase_set",e)} + @click=${()=>{c!==i&&d.setPhaseCursor(c)}}> + ${c+1}. ${o} + ${u?n`${q(u,e)}`:h}
    `})}
    - `}function ma(l,p){if(!p.features.checklists)return h;let t=he(l)?.checklist??(l.checklist||[]);if(t.length===0)return h;let e=p.lang,i=l.checklist_progress||{},a=t.filter(r=>i[r]).length;return o` + `}function ya(l,d){if(!d.features.checklists)return h;let e=ut(l)?.checklist??(l.checklist||[]);if(e.length===0)return h;let t=d.lang,i=l.checklist_progress||{},a=e.filter(r=>i[r]).length;return n`
    - ${s("checklist",e)} (${a}/${t.length}) + ${s("checklist",t)} (${a}/${e.length})
      - ${t.map(r=>o` + ${e.map(r=>n`
    1. @@ -5221,222 +5336,222 @@ ${c.capped?`

      ${$(t.capNote)}

      `:""} `)}
    - `}function fa(l,p){let t=st(l.documentation_url)?l.documentation_url:null,e=st(p.objectDocUrl)?p.objectDocUrl:null,i=e?null:(p.objectManualDocs||[])[0];if(!l.notes&&!t&&!e&&!i)return h;let a=p.lang;return o` + `}function xa(l,d){let e=le(l.documentation_url)?l.documentation_url:null,t=le(d.objectDocUrl)?d.objectDocUrl:null,i=t?null:(d.objectManualDocs||[])[0];if(!l.notes&&!e&&!t&&!i)return h;let a=d.lang;return n`
    - `}function va(l,p){let t=p.lang,e=l.average_cost!==void 0?l.average_cost??0:l.times_performed>0?l.total_cost/l.times_performed:0,i=l.days_until_due!==null&&l.days_until_due!==void 0?l.days_until_due<0?"overdue":l.days_until_due<=l.warning_days?"warning":"":"";return o` + `}function ka(l,d){let e=d.lang,t=l.average_cost!==void 0?l.average_cost??0:l.times_performed>0?l.total_cost/l.times_performed:0,i=l.days_until_due!==null&&l.days_until_due!==void 0?l.days_until_due<0?"overdue":l.days_until_due<=l.warning_days?"warning":"":"";return n`
    -
    ${s("next_due",t)}
    -
    ${l.next_due?q(l.next_due,t):"\u2014"}
    - ${p.features.schedule_time&&l.schedule_time?o`
    ${s("at_time",t)} ${l.schedule_time}
    `:h} +
    ${s("next_due",e)}
    +
    ${l.next_due?q(l.next_due,e):"\u2014"}
    + ${d.features.schedule_time&&l.schedule_time?n`
    ${s("at_time",e)} ${l.schedule_time}
    `:h}
    -
    ${s("days_until_due",t)}
    +
    ${s("days_until_due",e)}
    ${l.days_until_due!==null&&l.days_until_due!==void 0?l.days_until_due:"\u2014"}
    -
    ${s("interval",t)}
    -
    ${It(l,t)}
    - ${p.features.adaptive&&l.suggested_interval&&l.suggested_interval!==l.interval_days?o` -
    ${s("recommended",t)}: ${l.suggested_interval}${l.interval_analysis?.confidence_interval_low!=null?` (${l.interval_analysis.confidence_interval_low}\u2013${l.interval_analysis.confidence_interval_high})`:""}
    +
    ${s("interval",e)}
    +
    ${Ie(l,e)}
    + ${d.features.adaptive&&l.suggested_interval&&l.suggested_interval!==l.interval_days?n` +
    ${s("recommended",e)}: ${l.suggested_interval}${l.interval_analysis?.confidence_interval_low!=null?` (${l.interval_analysis.confidence_interval_low}\u2013${l.interval_analysis.confidence_interval_high})`:""}
    `:h}
    -
    ${s("warning",t)}
    -
    ${l.warning_days} ${s("days",t)}
    +
    ${s("warning",e)}
    +
    ${l.warning_days} ${s("days",e)}
    -
    ${s("last_performed",t)}
    -
    ${l.last_performed?q(l.last_performed,t):"\u2014"}
    +
    ${s("last_performed",e)}
    +
    ${l.last_performed?q(l.last_performed,e):"\u2014"}
    -
    ${s("avg_cost",t)}
    -
    ${U(e,p.currencySymbol,t)}
    +
    ${s("avg_cost",e)}
    +
    ${U(t,d.currencySymbol,e)}
    -
    ${s("avg_duration",t)}
    -
    ${l.average_duration?Yt(Math.round(l.average_duration),t):"\u2014"}
    +
    ${s("avg_duration",e)}
    +
    ${l.average_duration?Ye(Math.round(l.average_duration),e):"\u2014"}
    - `}function ba(l,p){let t=p.lang;if(!p.features.adaptive||!l.suggested_interval||l.suggested_interval===l.interval_days)return h;if(p.suggestionDismissed)return h;let e=l.suggested_interval;return o` + `}function wa(l,d){let e=d.lang;if(!d.features.adaptive||!l.suggested_interval||l.suggested_interval===l.interval_days)return h;if(d.suggestionDismissed)return h;let t=l.suggested_interval;return n`
    -

    ${s("suggested_interval",t)}

    - ${Ki(l.interval_days,e,l.interval_confidence||"medium",t)} +

    ${s("suggested_interval",e)}

    + ${Qi(l.interval_days,t,l.interval_confidence||"medium",e)}
    - ${p.isOperator?h:o`p.applySuggestion(e)}> - ${s("apply_suggestion",t)} + ${d.isOperator?h:n`d.applySuggestion(t)}> + ${s("apply_suggestion",e)} `} p.reanalyze()}> - ${s("reanalyze",t)} + @click=${()=>d.reanalyze()}> + ${s("reanalyze",e)} p.dismissSuggestion()}> - ${s("dismiss_suggestion",t)} + @click=${()=>d.dismissSuggestion()}> + ${s("dismiss_suggestion",e)}
    - `}function ya(l,p){let t=p.lang,e=Ni(l.history).slice(0,3);return e.length===0?h:o` + `}function $a(l,d){let e=d.lang,t=Ui(l.history).slice(0,3);return t.length===0?h:n`
    -

    ${s("recent_activities",t)}

    - ${e.map(i=>Ui(i,p.history,{compact:!0,showEdit:!1}))} +

    ${s("recent_activities",e)}

    + ${t.map(i=>Ki(i,d.history,{compact:!0,showEdit:!1}))}
    - p.setActiveTab("history")}>${s("show_all",t)} → + d.setActiveTab("history")}>${s("show_all",e)} →
    - `}function xa(l,p){let t=p.lang,e=p.features.adaptive&&l.suggested_interval&&l.suggested_interval!==l.interval_days,i=p.features.seasonal&&l.seasonal_factor&&l.seasonal_factor!==1,a=e||i,r=p.features.adaptive&&l.interval_analysis?.weibull_beta!=null&&l.interval_analysis?.weibull_eta!=null,c=p.features.seasonal&&(l.seasonal_factors?.length===12||l.interval_analysis?.seasonal_factors?.length===12);return o` + `}function ja(l,d){let e=d.lang,t=d.features.adaptive&&l.suggested_interval&&l.suggested_interval!==l.interval_days,i=d.features.seasonal&&l.seasonal_factor&&l.seasonal_factor!==1,a=t||i,r=d.features.adaptive&&l.interval_analysis?.weibull_beta!=null&&l.interval_analysis?.weibull_eta!=null,c=d.features.seasonal&&(l.seasonal_factors?.length===12||l.interval_analysis?.seasonal_factors?.length===12);return n`
    - ${l.battery_fleet_task?o``:h} - ${va(l,p)} - ${fa(l,p)} - ${l.battery_fleet_task?h:o` - ${ms(l,p.lang)} - ${bs(l,p.sparkline)} - ${Wi(l,t,p.features)} + ${l.battery_fleet_task?n``:h} + ${ka(l,d)} + ${xa(l,d)} + ${l.battery_fleet_task?h:n` + ${bs(l,d.lang)} + ${ks(l,d.sparkline)} + ${Yi(l,e,d.features)} `}
    - ${a?o` + ${a?n`
    - ${ba(l,p)} - ${Gi(l,t,p.features)} + ${wa(l,d)} + ${Ji(l,e,d.features)}
    `:h}
    - ${ks(l,t,p.costDurationToggle,n=>p.setCostDurationToggle(n),p.currencySymbol)} + ${js(l,e,d.costDurationToggle,o=>d.setCostDurationToggle(o),d.currencySymbol)}
    - ${r?ws("weibull","weibull_reliability_curve",Vi(l,t),p):h} - ${c?ws("seasonal","seasonal_chart_title",o` - ${Yi(l,t)} + ${r?Ss("weibull","weibull_reliability_curve",Gi(l,e),d):h} + ${c?Ss("seasonal","seasonal_chart_title",n` + ${Xi(l,e)}
    - p.openSeasonalOverrides(l)}> - ${s("edit_seasonal_overrides",t)} + d.openSeasonalOverrides(l)}> + ${s("edit_seasonal_overrides",e)}
    - `,p):h} - ${_a(l,p)} - ${ma(l,p)} - ${ya(l,p)} + `,d):h} + ${ba(l,d)} + ${ya(l,d)} + ${$a(l,d)}
    - `}function ka(l,p){return o` + `}function Sa(l,d){return n`
    - p.openComplete(l)}> + d.openComplete(l)}> - ${s("history_add_past",p.lang)} + ${s("history_add_past",d.lang)}
    - ${qi(l,p.history)} - ${Fi(l,p.history)} + ${Vi(l,d.history)} + ${Wi(l,d.history)}
    - `}function wa(l,p){switch(p.activeTab){case"overview":return xa(l,p);case"history":return ka(l,p);default:return h}}function $s(l,p){return o` + `}function Ta(l,d){switch(d.activeTab){case"overview":return ja(l,d);case"history":return Sa(l,d);default:return h}}function Ts(l,d){return n`
    - ${ua(l,p)} - ${ga(p)} - ${wa(l,p)} + ${fa(l,d)} + ${va(d)} + ${Ta(l,d)}
    - `}var ie=class extends N{createRenderRoot(){return this}render(){return!this.task||!this.ctx?h:o`${$s(this.task,this.ctx)}`}};_([R({attribute:!1})],ie.prototype,"task",2),_([R({attribute:!1})],ie.prototype,"ctx",2);customElements.get("maintenance-task-detail-view")||customElements.define("maintenance-task-detail-view",ie);function js(l){if(l.total<=0)return{start:0,end:0,padTop:0,padBottom:0};let p=l.overscan??12,t=Math.max(1,l.step??6),e=Math.max(1,l.rowHeight),i=Math.floor((l.scrollTop-l.listTop)/e),a=Math.ceil(l.viewportHeight/e)+1,r=Math.max(0,i-p);r=Math.floor(r/t)*t;let c=Math.min(l.total,Math.max(i,0)+a+p);return c=Math.min(l.total,Math.ceil(c/t)*t),r>=c&&(r=Math.min(r,Math.max(0,l.total-1)),c=Math.min(l.total,r+Math.max(a,1))),{start:r,end:c,padTop:r*e,padBottom:(l.total-c)*e}}var Ee={mode:"top",marginTop:0,lastScrollTop:0};function Ss(l,p){return l==="top"?8:p.viewH-p.paneH-8}function Ts(l){let p=l.scrollTop+8-l.layoutTop,t=Math.max(0,l.listH-l.paneH);return{mode:"top",marginTop:p>t?Math.max(0,p):0,lastScrollTop:l.scrollTop}}function Es(l,p){let t=p.scrollTop,e=p.scrollTop>l.lastScrollTop?"down":p.scrollTop0&&e==="up")c=Math.max(0,Math.min(c,p.scrollTop+8-p.layoutTop)),c<=i&&(c=0);else if(!a&&e==="down"&&r==="top"){let n=p.renderedTop-p.layoutTop;n<=i&&(r="bottom",c=Math.max(0,n))}else!a&&e==="up"&&r==="bottom"&&(c=Math.min(Math.max(0,p.renderedTop-p.layoutTop),i),p.scrollTop+8<=p.layoutTop+c&&(r="top",c=0));return{mode:r,marginTop:c,lastScrollTop:t}}var Re=2,Ta=250,Pt={objects:6,tasks:10,parts:6,documents:8,history:6},Ea="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z",Xe=["due_date","object","type","task_name","area","assigned_user","group"],Rs=["none","area","group","user","object"],Os=ei,Cs=["tasks","documents","parts","history"],k=class extends N{constructor(){super(...arguments);this.narrow=!1;this.tight=!1;this.split=!1;this._tightObserver=null;this.panel={};this.embedded=!1;this.presets={};this._presetsApplied=!1;this._mountPath=null;this._objects=[];this._stats=null;this._view="overview";this._allParts=null;this._selectedEntryId=null;this._selectedTaskId=null;this._selectedAreaId=null;this._filterStatus="";this._filterUser=null;this._filterLabel=null;this._filterPlace="";this._filterPriority="";this._savedViews=[];this._activeViewId="";this._unsub=null;this._chartRangeDays=(()=>{try{let t=parseInt(Z(A.chartRange)||"",10);return[7,30,90,365].includes(t)?t:30}catch{return 30}})();this._hideOutliers=(()=>{try{return Z(A.chartHideOutliers)==="1"}catch{return!1}})();this._historyFilter=null;this._budget=null;this._groups={};this._detailStatsData=new Map;this._miniStatsData=new Map;this._features={adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1,places:!1};this._adminPanelUserIds=[];this._operatorWriteEnabled=!1;this._defaultWarningDays=7;this._rowActionStyle="buttons_compact";this._refsInLists=!1;this._partsCostMode="purchase";this._rowActionNotice=!1;this._actionLoading=!1;this._moreMenuOpen=!1;this._objMenuOpen=!1;this._toastMessage="";this._toastKind="error";this._toastUndo=null;this._toastActionLabel="";this._filtersOpen=!1;this._newMenuOpen=!1;this._gsSetupsCount=0;this._gsAdoptCount=0;this._gsLoaded=!1;this._resetOffersLoaded=!1;this._resetOffersCount=0;this._batteryFleetSetupAvailable=!1;this._staleBundle=!1;this._staleChecked=!1;this._toastTimer=null;this._dismissedSuggestions=new Set;this._overviewTab=(()=>{try{let t=Z(A.overviewTab);return t==="today"||t==="calendar"?t:"dashboard"}catch{return"dashboard"}})();this._activeTab="overview";this._costDurationToggle="both";this._historySearch="";this._sortMode="due_date";this._objectSortMode="alphabetical";this._groupByMode="none";this._objectViewMode="cards";this._objectsTableColumns=ui;this._showArchived=!1;this._bulkMode=!1;this._bulkSelected=new Set;this._objBulkMode=!1;this._objBulkSelected=new Set;this._bulkMenuOpen=!1;this._virtStart=0;this._virtEnd=0;this._virtRowHeight=53;this._virtTotalRows=0;this._virtScrollAttached=!1;this._virtRaf=0;this._stickyState=Ee;this._stickySelectPending=!1;this._stickyRaf=0;this._stickyAttached=!1;this._stickyObserver=null;this._collapsedGroups=new Set;this._collapsedSections=(()=>{try{return new Set(JSON.parse(Z(A.collapsedSections)||"[]"))}catch{return new Set}})();this._objectSectionsCollapsed=(()=>{try{let t=JSON.parse(Z(A.objectSections)||"[]");return new Set((Array.isArray(t)?t:[]).filter(e=>Cs.includes(e)))}catch{return new Set}})();this._objectSectionOverride=null;this._paletteOpen=!1;this._paletteQuery="";this._paletteActive=0;this._searchRemote=null;this._searchTimer=null;this._searchSeq=0;this._templateGalleryOpen=!1;this._templates=[];this._homeProfile=null;this._templateCategories={};this._templateBusy=!1;this._statsService=null;this._userService=null;this._dataLoaded=!1;this._lastConnection=null;this._popstateHandler=t=>this._onPopState(t);this._locationChangedHandler=()=>this._onLocationChanged();this._lazyUi=null;this._onStickyScroll=()=>{this._stickyRaf||(this._stickyRaf=requestAnimationFrame(()=>{this._stickyRaf=0,this._updateStickyPane()}))};this._onVirtualScroll=()=>{this._virtRaf||(this._virtRaf=requestAnimationFrame(()=>{this._virtRaf=0,this._updateVirtualWindow()}))};this._deepLinkHandled=!1;this._deepLinkInPlace=!1;this._initialLoadDone=!1;this._detailStatsSeq=new Map;this._kpiRefreshInFlight=!1;this._kpiRefreshPending=!1;this._areaUi=null;this._paletteKeydown=t=>{if(t.key==="/"&&!t.ctrlKey&&!t.metaKey&&!t.altKey&&!this._paletteOpen){let i=t.composedPath()[0];if(i instanceof HTMLElement&&(i.tagName==="INPUT"||i.tagName==="TEXTAREA"||i.tagName==="SELECT"||i.isContentEditable))return;t.preventDefault(),this._openPalette();return}if(!this._paletteOpen)return;let e=this._paletteResults;if(t.key==="Escape")t.preventDefault(),this._closePalette();else if(t.key==="ArrowDown")t.preventDefault(),this._paletteActive=Math.min(this._paletteActive+1,e.length-1);else if(t.key==="ArrowUp")t.preventDefault(),this._paletteActive=Math.max(this._paletteActive-1,0);else if(t.key==="Enter"){t.preventDefault();let i=e[this._paletteActive];i&&this._selectPaletteResult(i)}};this._onObjectReplaced=async t=>{this._showToast([s("object_replaced",this._lang),this._deviceSwapText(t.detail.device_swap)].filter(Boolean).join(" \xB7 "),"info");try{await this._loadData()}catch{}t.detail.entry_id&&this._showObject(t.detail.entry_id)};this._onObjectSaved=async t=>{let e=this._deviceSwapText(t.detail?.device_swap);e&&this._showToast(e,"info"),await this._onDialogEvent()};this._checklistPending=new Map;this._checklistChain=Promise.resolve();this._onDialogEvent=async()=>{try{await this._loadData()}catch{}};this._onTaskCompleted=async t=>{await this._onDialogEvent();let e=t.detail;e?.undo&&this._offerUndo(e.entryId,e.taskId,s("task_completed_named",this._lang).replace("{task}",e.taskName))};this._onCalendarLlCustom=t=>{let e=t.detail;e?.type==="maintenance-supporter:open-task"&&e.entry_id&&e.task_id&&(t.stopPropagation(),this._showTask(e.entry_id,e.task_id))};this._fullHistory=null;this._onHistoryEntrySaved=async()=>{await this._loadData()}}get _currencySymbol(){return oe(this._budget)}get _lang(){return K(this.hass)}get _isOperator(){return!Nt(this.hass?.user,{operatorWriteEnabled:this._operatorWriteEnabled,operatorIds:this._adminPanelUserIds})}_ensureLazyUi(){return this._lazyUi||(this._lazyUi=Promise.all([import("/maintenance_supporter_panelfiles/panel-chunks/object-dialog-2L247AYZ.js"),import("/maintenance_supporter_panelfiles/panel-chunks/task-dialog-JWFLROKL.js"),import("/maintenance_supporter_panelfiles/panel-chunks/complete-dialog-6V6BEYNC.js"),import("/maintenance_supporter_panelfiles/panel-chunks/qr-dialog-V7XYHE5H.js"),import("/maintenance_supporter_panelfiles/panel-chunks/adopt-problem-sensors-dialog-SC7CI7XE.js"),import("/maintenance_supporter_panelfiles/panel-chunks/suggested-setups-dialog-SATYFGPB.js"),import("/maintenance_supporter_panelfiles/panel-chunks/settings-view-LWHVKKSZ.js"),import("/maintenance_supporter_panelfiles/panel-chunks/bulk-edit-dialog-3WMP5FUP.js")]).then(()=>this.updateComplete)),this._lazyUi}async _ui(t){return await this._ensureLazyUi(),this.shadowRoot?.querySelector(t)??null}connectedCallback(){super.connectedCallback(),this._mountPath=window.location.pathname;let t=window.requestIdleCallback,e=()=>this._ensureLazyUi();t?t(e,{timeout:3e3}):window.setTimeout(e,1500),window.addEventListener("popstate",this._popstateHandler),window.addEventListener("location-changed",this._locationChangedHandler),window.addEventListener("keydown",this._paletteKeydown),typeof ResizeObserver<"u"&&(this._tightObserver=new ResizeObserver(i=>{let a=i[0]?.contentRect.width??0;a>0&&(this.tight=a<1e3),a>0&&(this.split=a>=1500)}),this._tightObserver.observe(this)),window.addEventListener("resize",this._onVirtualScroll,{passive:!0});try{let i=Z(A.taskSort);i&&Xe.includes(i)&&(this._sortMode=i);let a=Z(A.objectSort);a&&["alphabetical","due_soonest","task_count"].includes(a)&&(this._objectSortMode=a);let r=Z(A.groupBy);r&&Rs.includes(r)&&(this._groupByMode=r);let c=Z(A.objectView);(c==="cards"||c==="table")&&(this._objectViewMode=c)}catch{}if(this._objects.length===0){let i=Zi();i&&(this._objects=i.objects,i.stats&&(this._stats=i.stats))}}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("popstate",this._popstateHandler),window.removeEventListener("location-changed",this._locationChangedHandler),window.removeEventListener("keydown",this._paletteKeydown),this._tightObserver?.disconnect(),this._tightObserver=null,window.removeEventListener("resize",this._onVirtualScroll),this.shadowRoot?.querySelector(".content")?.removeEventListener("scroll",this._onVirtualScroll),this._virtScrollAttached=!1,this._virtRaf&&cancelAnimationFrame(this._virtRaf),this._detachStickyPane(),this._unsub&&(this._unsub(),this._unsub=null),this._dataLoaded=!1,this._initialLoadDone=!1,this._lastConnection=null,this._deepLinkHandled=!1,this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=null),this._toastTimer&&(clearTimeout(this._toastTimer),this._toastTimer=null),this._toastMessage="",this._toastUndo=null,this._toastActionLabel="",this._statsService?.clearCache(),this._statsService=null}willUpdate(t){super.willUpdate(t),t.has("_groupByMode")&&this._collapsedGroups.size>0&&(this._collapsedGroups=new Set)}updated(t){if(super.updated(t),Bt(this,t),t.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,history.replaceState({msp_view:"overview",msp_entry:null,msp_task:null},""),this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}this._statsService?this._statsService.updateHass(this.hass):(this._statsService=new xe(this.hass),this._fetchMiniStatsForOverview()),this._userService?this._userService.updateHass(this.hass):(this._userService=new Ri(this.hass),this._userService.getUsers().then(()=>this.requestUpdate()))}let e=this.shadowRoot?.querySelector(".content");e&&!this._virtScrollAttached&&(e.addEventListener("scroll",this._onVirtualScroll,{passive:!0}),this._virtScrollAttached=!0),this._updateVirtualWindow(),this._syncStickyPane(e)}_syncStickyPane(t){let e=this.shadowRoot?.querySelector(".split-pane");if(!e||!t){this._stickyAttached&&this._detachStickyPane();return}this._stickyAttached||(t.addEventListener("scroll",this._onStickyScroll,{passive:!0}),window.addEventListener("resize",this._onStickyScroll),typeof ResizeObserver<"u"&&(this._stickyObserver=new ResizeObserver(this._onStickyScroll)),this._stickyAttached=!0),this._stickyObserver?.observe(e),this._updateStickyPane()}_detachStickyPane(){this.shadowRoot?.querySelector(".content")?.removeEventListener("scroll",this._onStickyScroll),window.removeEventListener("resize",this._onStickyScroll),this._stickyObserver?.disconnect(),this._stickyObserver=null,this._stickyRaf&&cancelAnimationFrame(this._stickyRaf),this._stickyRaf=0,this._stickyAttached=!1,this._stickyState=Ee,this._stickySelectPending=!1}_updateStickyPane(){let t=this.shadowRoot,e=t?.querySelector(".content"),i=t?.querySelector(".split-pane"),a=t?.querySelector(".split-layout"),r=t?.querySelector(".split-list");if(!e||!i||!a||!r)return;let c=e.getBoundingClientRect().top-e.scrollTop,n={scrollTop:e.scrollTop,viewH:e.clientHeight,paneH:i.offsetHeight,listH:r.offsetHeight,layoutTop:a.getBoundingClientRect().top-c,renderedTop:i.getBoundingClientRect().top-c};this._stickySelectPending&&n.scrollTop===this._stickyState.lastScrollTop?this._stickyState=Ts(n):(this._stickySelectPending=!1,this._stickyState=Es(this._stickyState,n));let u=this._stickyState;i.style.top=`${Ss(u.mode,n)}px`,i.style.marginTop=u.marginTop>0?`${u.marginTop}px`:""}_resetStickyPane(){let t=this.shadowRoot?.querySelector(".content");this._stickyState={...Ee,lastScrollTop:t?.scrollTop??0},this._stickySelectPending=!0}_updateVirtualWindow(){let t=this.shadowRoot?.querySelector(".content"),e=this.shadowRoot?.querySelector(".task-table.virtual");if(!t||!e)return;let i=e.querySelector(".task-row:not(.virt-sizer)");i&&i.offsetHeight>20&&(this._virtRowHeight=i.offsetHeight);let a=e.getBoundingClientRect().top-t.getBoundingClientRect().top+t.scrollTop,r=js({scrollTop:t.scrollTop,viewportHeight:t.clientHeight,listTop:a,rowHeight:this._virtRowHeight,total:this._virtTotalRows});(r.start!==this._virtStart||r.end!==this._virtEnd)&&(this._virtStart=r.start,this._virtEnd=r.end)}async _loadData(){let[t,e,i,a,r,c]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/budget_status"}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/groups"}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/views/list"}).catch(()=>null)]);if(c&&(this._savedViews=c.views||[]),t&&(this._objects=te(t.objects),Be(this._objects,e??this._stats??null),this._maybeLoadGettingStarted()),this._detailOpen()&&this._fetchFullHistory(this._selectedEntryId,this._selectedTaskId),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/status"}).then(n=>{this._batteryFleetSetupAvailable=!!n.available&&!n.configured}).catch(()=>{this._batteryFleetSetupAvailable=!1}),this._staleChecked||(this._staleChecked=!0,this.hass.connection.sendMessagePromise({type:"maintenance_supporter/version"}).then(n=>{this._staleBundle=Ze(n?.version)}).catch(()=>{})),e&&(this._stats=e),i&&(this._budget=i,Kt(this._budget)),a&&(this._groups=a.groups||{}),r){let n=zi(r);this._features=n.features,this._adminPanelUserIds=[...n.access.operatorIds],this._operatorWriteEnabled=n.access.operatorWriteEnabled,this._defaultWarningDays=n.defaultWarningDays,this._rowActionStyle=n.rowActionStyle,this._rowActionNotice=n.rowActionNoticePending,this._refsInLists=n.refsInLists,this._objectsTableColumns=gi(n.objectsTableColumns),this._partsCostMode=n.partsCostMode}this._fetchMiniStatsForOverview(),this._initialLoadDone=!0,this._handleDeepLink()}_onLocationChanged(){if(!this._initialLoadDone||!window.location.search||this.embedded&&this._mountPath!==null&&window.location.pathname!==this._mountPath)return;if(!this.embedded){let e=`/${typeof this.panel?.url_path=="string"?this.panel.url_path:"maintenance-supporter"}`,i=window.location.pathname;if(i!==e&&!i.startsWith(`${e}/`))return}this._deepLinkHandled=!1,this._deepLinkInPlace=!0;try{this._handleDeepLink()}finally{this._deepLinkInPlace=!1}history.state?.msp_view||history.replaceState({msp_view:this._view,msp_entry:this._selectedEntryId,msp_task:this._selectedTaskId,msp_area:this._selectedAreaId},"")}_handleDeepLink(){if(this._deepLinkHandled)return;let t=new URLSearchParams(window.location.search),e=t.get("ms_action"),i=()=>{let j=window.location.pathname+window.location.hash;history.replaceState(history.state,"",j)};if(e==="add_object"){this._deepLinkHandled=!0,i(),this._ui("maintenance-object-dialog").then(j=>j?.openCreate());return}if(e==="open_vacation"||e==="open_budget"||e==="open_groups"||e==="open_settings"){if(this._deepLinkHandled=!0,i(),!this.hass?.user?.is_admin)return;this._overviewTab="settings",this._ensureLazyUi().then(()=>requestAnimationFrame(()=>{let j=this.shadowRoot?.querySelector("maintenance-settings-view"),x=e.replace("open_","");j?.scrollToSection?.(x)}));return}if(this.embedded&&!this._presetsApplied){this._presetsApplied=!0;let j=this.presets?.tab??"",x=(this.presets?.view??"").trim();if(!t.has("tab")&&He.includes(j)&&(j!=="settings"||this.hass?.user?.is_admin)&&(this._overviewTab=j),!t.has("view")&&x){let M=x.toLowerCase(),b=this._savedViews.find(D=>D.id===x)??this._savedViews.find(D=>D.name.trim().toLowerCase()===M);b&&(this._overviewTab="dashboard",this._applyView(b.id))}}let a=t.get("tab"),r=t.get("view"),c=t.get("sort"),n=t.get("status");if(a!==null||r!==null||c!==null||n!==null){if(i(),this._view!=="overview"&&(this._view="overview",this._selectedEntryId=null,this._selectedTaskId=null,this._moreMenuOpen=!1,this._scrollContentToTop()),He.includes(a??"")&&(a!=="settings"||this.hass?.user?.is_admin)&&this._setOverviewTab(a),r!==null){let j=r.trim().toLowerCase(),x=this._savedViews.find(M=>M.id===r)??this._savedViews.find(M=>M.name.trim().toLowerCase()===j);x&&(this._overviewTab!=="dashboard"&&this._setOverviewTab("dashboard"),this._applyView(x.id))}Xe.includes(c??"")&&(this._sortMode=c,this._activeViewId="",V(A.taskSort,this._sortMode)),Os.includes(n??"")&&(this._overviewTab!=="dashboard"&&this._setOverviewTab("dashboard"),this._filterByStatus(n))}let u=t.get("area");if(u&&!t.get("entry_id")){this._deepLinkHandled=!0,i(),this._objects.some(j=>Ti(j.object)===u)?this._showArea(u):this._showAllAreas();return}let d=t.get("entry_id");if(!d)return;this._deepLinkHandled=!0;let g=t.get("task_id"),m=t.get("action"),v=t.get("section"),y=Cs.includes(v??"")?v:null,E=window.location.pathname+window.location.hash;history.replaceState(history.state,"",E);let w=this._getObject(d);if(!w){this._showOverview();return}if(g){let j=w.tasks.find(x=>x.id===g);if(!j){this._showObject(d,y);return}this._showTask(d,g),m==="complete"?requestAnimationFrame(()=>{this._openCompleteDialog(d,g,j.name,this._features.checklists?j.checklist:void 0,this._features.adaptive&&!!j.adaptive_config?.enabled,{viaTagScan:!0})}):m==="skip"?requestAnimationFrame(()=>{j.allow_skip!==!1&&this._promptSkipTask(d,g)}):m==="quick_complete"&&requestAnimationFrame(()=>{this._handleQuickComplete(d,g,j)})}else this._showObject(d,y)}_isCounterEntity(t){if(!t)return!1;let e=t.type||"threshold";return e==="counter"||e==="state_change"}async _fetchDetailStats(t,e){if(!this._statsService)return;let i=(this._detailStatsSeq.get(t)??0)+1;this._detailStatsSeq.set(t,i);let a=await this._statsService.getDetailStats(t,e,this._chartRangeDays);if(this._detailStatsSeq.get(t)!==i)return;let r=new Map(this._detailStatsData);r.set(t,a),this._detailStatsData=r}_setChartRange(t){if(t===this._chartRangeDays)return;this._chartRangeDays=t;try{V(A.chartRange,String(t))}catch{}let e=this._selectedEntryId&&this._selectedTaskId?this._getTask(this._selectedEntryId,this._selectedTaskId):null,i=gt(e?.trigger_config);if(i){let a=new Map(this._detailStatsData);a.delete(i),this._detailStatsData=a,this._fetchDetailStats(i,this._isCounterEntity(e.trigger_config))}}_setHideOutliers(t){if(t!==this._hideOutliers){this._hideOutliers=t;try{V(A.chartHideOutliers,t?"1":"0")}catch{}}}async _fetchMiniStatsForOverview(){if(!this._statsService)return;let t=[];for(let i of this._objects)for(let a of i.tasks){let r=a.battery_fleet_task?void 0:gt(a.trigger_config);r&&t.push({entityId:r,isCounter:this._isCounterEntity(a.trigger_config)})}if(t.length===0)return;let e=await this._statsService.getBatchMiniStats(t);this._miniStatsData=new Map([...this._miniStatsData,...e])}async _subscribe(){try{let t=await this.hass.connection.subscribeMessage(e=>{let i=e,a=Xi(this._objects,i);a!==null&&(this._objects=a,e.objects&&Be(a,this._stats??null),this._refreshKpis(),this._detailOpen()&&(i.objects||(i.delta||[]).some(r=>r.entry_id===this._selectedEntryId))&&this._fetchFullHistory(this._selectedEntryId,this._selectedTaskId))},{type:"maintenance_supporter/subscribe",deltas:!0,compact:!0});if(!this.isConnected){t();return}this._unsub=t}catch{}}async _refreshKpis(){if(this._kpiRefreshInFlight){this._kpiRefreshPending=!0;return}this._kpiRefreshInFlight=!0;try{do{this._kpiRefreshPending=!1;let[t,e]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/budget_status"}).catch(()=>null)]);if(!this.isConnected)return;t&&(this._stats=t),e&&(this._budget=e,Kt(this._budget))}while(this._kpiRefreshPending)}finally{this._kpiRefreshInFlight=!1}}get _taskRows(){let t=[];for(let d of this._objects)for(let g of d.tasks){if(!this._showArchived&&g.archived||this._filterStatus&&g.status!==this._filterStatus)continue;if(this._filterUser){let v=this._filterUser==="current_user"?this._userService?.getCurrentUserId():this._filterUser;if(g.responsible_user_id!==v)continue}if(this._filterLabel&&!(g.labels||[]).includes(this._filterLabel)||this._filterPlace&&(d.object.place||"home")!==this._filterPlace||this._filterPriority&&(g.priority||"normal")!==this._filterPriority)continue;let m=[];for(let v of Object.values(this._groups))v.task_refs?.some(y=>y.entry_id===d.entry_id&&y.task_id===g.id)&&m.push(v.name);t.push({entry_id:d.entry_id,task_id:g.id,object_name:d.object.name,allow_skip:g.allow_skip!==!1,notify_enabled:g.notify_enabled!==!1,task_name:g.name,type:g.type,schedule_type:g.schedule_type,status:g.status,days_until_due:g.days_until_due??null,next_due:g.next_due??null,last_performed:g.last_performed??null,next_event_titles:g.next_event_titles??[],trigger_active:g.trigger_active,trigger_current_value:g.trigger_current_value??null,trigger_current_delta:g.trigger_current_delta??null,trigger_config:g.trigger_config??null,trigger_entity_info:g.trigger_entity_info??null,battery_fleet_task:g.battery_fleet_task===!0,times_performed:g.times_performed,total_cost:g.total_cost,interval_days:g.interval_days??null,interval_unit:g.interval_unit??null,interval_anchor:g.interval_anchor??null,is_done:g.is_done??!1,archived:g.archived??!1,history:g.history||[],enabled:g.enabled,nfc_tag_id:g.nfc_tag_id??null,priority:g.priority??"normal",labels:g.labels??[],area_id:d.object.area_id??null,responsible_user_id:g.responsible_user_id??null,group_names:m})}let e=(d,g)=>Mt(d.status)-Mt(g.status),i=(d,g)=>(d.days_until_due??99999)-(g.days_until_due??99999),a=(d,g)=>e(d,g)||i(d,g),r=d=>d.area_id&&this.hass?.areas?.[d.area_id]?.name||"",c=d=>d.responsible_user_id&&this._userService?.getUserName(d.responsible_user_id)||"",n=d=>d.group_names[0]||"",u={due_date:a,object:(d,g)=>d.object_name.localeCompare(g.object_name)||a(d,g),type:(d,g)=>d.type.localeCompare(g.type)||a(d,g),task_name:(d,g)=>d.task_name.localeCompare(g.task_name),area:(d,g)=>{let m=r(d),v=r(g);return!m&&v?1:m&&!v?-1:m.localeCompare(v)||a(d,g)},assigned_user:(d,g)=>{let m=c(d),v=c(g);return!m&&v?1:m&&!v?-1:m.localeCompare(v)||a(d,g)},group:(d,g)=>{let m=n(d),v=n(g);return!m&&v?1:m&&!v?-1:m.localeCompare(v)||a(d,g)}};return t.sort(u[this._sortMode]),t}_getObject(t){return this._objects.find(e=>e.entry_id===t)}_getTask(t,e){return this._getObject(t)?.tasks.find(a=>a.id===e)}_listRef(t,e){if(!this._refsInLists)return h;let i=this._getObject(t);return Ht(St(i?.object,i?.tasks.find(a=>a.id===e)))}_objRef(t){return this._refsInLists?Ht(jt(t)):h}_pushPanelState(t,e,i,a){let r={msp_view:t,msp_entry:e||null,msp_task:i||null,msp_area:a||null};this._deepLinkInPlace?history.replaceState(r,""):history.pushState(r,"")}_onPopState(t){let e=t.state;if(e?.msp_view&&(this._view=e.msp_view,this._selectedEntryId=e.msp_entry||null,this._selectedTaskId=e.msp_task||null,this._selectedAreaId=e.msp_area||null,this._moreMenuOpen=!1,this._objectSectionOverride=null,e.msp_view==="all_parts"&&this._loadAllParts(),e.msp_view==="task"&&e.msp_entry&&e.msp_task)){this._historyFilter=null;let i=this._getTask(e.msp_entry,e.msp_task),a=gt(i?.trigger_config);i&&a&&this._fetchDetailStats(a,this._isCounterEntity(i.trigger_config))}}_showOverview(){this._pushPanelState("overview"),this._view="overview",this._selectedEntryId=null,this._selectedTaskId=null,this._moreMenuOpen=!1,this._scrollContentToTop()}_showAllObjects(){this._pushPanelState("all_objects"),this._view="all_objects",this._objBulkMode=!1,this._objBulkSelected=new Set,this._selectedEntryId=null,this._selectedTaskId=null,this._scrollContentToTop()}_showAllParts(){this._pushPanelState("all_parts"),this._view="all_parts",this._selectedEntryId=null,this._selectedTaskId=null,this._scrollContentToTop(),this._loadAllParts()}async _loadAllParts(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"});this._allParts=t.parts||[]}catch{this._allParts=[]}}_showAllAreas(){this._pushPanelState("all_areas"),this._view="all_areas",this._selectedEntryId=null,this._selectedTaskId=null,this._scrollContentToTop()}_showArea(t){this._pushPanelState("area",null,null,t),this._view="area",this._selectedAreaId=t,this._selectedEntryId=null,this._selectedTaskId=null,this._scrollContentToTop()}_ensureAreaUi(){this._areaUi??=Promise.all([import("/maintenance_supporter_panelfiles/panel-chunks/areas-view-EJGYRTVQ.js"),import("/maintenance_supporter_panelfiles/panel-chunks/area-view-ZILZT22Q.js")]).catch(()=>{this._areaUi=null})}_filterByStatus(t){this._filterStatus=t,this._activeViewId="",this._overviewTab!=="dashboard"&&(this._overviewTab="dashboard"),this._scrollContentToTop()}get _allLabels(){let t=new Set;for(let e of this._objects)for(let i of e.tasks)for(let a of i.labels||[])t.add(a);return[...t].sort((e,i)=>e.localeCompare(i))}get _allPlaces(){let t=new Map;for(let e of this._objects){let i=e.object;i.place&&!t.has(i.place)&&t.set(i.place,i.place_name||i.place)}return[...t].map(([e,i])=>({id:e,name:i})).sort((e,i)=>e.name.localeCompare(i.name))}get _currentFilters(){return{status:this._filterStatus,user_id:this._filterUser,label:this._filterLabel,priority:this._filterPriority,archived:this._showArchived,sort_mode:this._sortMode,group_by:this._groupByMode}}_applyView(t){if(this._activeViewId=t,!t)return;let e=this._savedViews.find(a=>a.id===t);if(!e)return;let i=e.filters;this._filterStatus=i.status||"",this._filterUser=i.user_id||null,this._filterLabel=i.label||null,this._filterPriority=i.priority||"",this._showArchived=!!i.archived,Xe.includes(i.sort_mode)&&(this._sortMode=i.sort_mode),Rs.includes(i.group_by)&&(this._groupByMode=i.group_by);try{V(A.taskSort,this._sortMode),V(A.groupBy,this._groupByMode)}catch{}this._overviewTab!=="dashboard"&&(this._overviewTab="dashboard")}_openSavedViewsDialog(){this.shadowRoot.querySelector("maintenance-saved-views-dialog")?.open(this._currentFilters,this._savedViews)}_onSavedViewsChanged(t){this._savedViews=t.detail.views||[],this._activeViewId&&!this._savedViews.some(e=>e.id===this._activeViewId)&&(this._activeViewId="")}_scrollContentToTop(){requestAnimationFrame(()=>{let t=this.shadowRoot?.querySelector(".content");t&&t.scrollTo({top:0,behavior:"smooth"})})}_renderLineageLink(t,e){let i=t?this._objects.find(a=>a.entry_id===t):void 0;return i?o`

    ${e}: + `}var st=class extends N{createRenderRoot(){return this}render(){return!this.task||!this.ctx?h:n`${Ts(this.task,this.ctx)}`}};_([R({attribute:!1})],st.prototype,"task",2),_([R({attribute:!1})],st.prototype,"ctx",2);customElements.get("maintenance-task-detail-view")||customElements.define("maintenance-task-detail-view",st);function Es(l){if(l.total<=0)return{start:0,end:0,padTop:0,padBottom:0};let d=l.overscan??12,e=Math.max(1,l.step??6),t=Math.max(1,l.rowHeight),i=Math.floor((l.scrollTop-l.listTop)/t),a=Math.ceil(l.viewportHeight/t)+1,r=Math.max(0,i-d);r=Math.floor(r/e)*e;let c=Math.min(l.total,Math.max(i,0)+a+d);return c=Math.min(l.total,Math.ceil(c/e)*e),r>=c&&(r=Math.min(r,Math.max(0,l.total-1)),c=Math.min(l.total,r+Math.max(a,1))),{start:r,end:c,padTop:r*t,padBottom:(l.total-c)*t}}var Rt={mode:"top",marginTop:0,lastScrollTop:0};function Rs(l,d){return l==="top"?8:d.viewH-d.paneH-8}function Os(l){let d=l.scrollTop+8-l.layoutTop,e=Math.max(0,l.listH-l.paneH);return{mode:"top",marginTop:d>e?Math.max(0,d):0,lastScrollTop:l.scrollTop}}function Cs(l,d){let e=d.scrollTop,t=d.scrollTop>l.lastScrollTop?"down":d.scrollTop0&&t==="up")c=Math.max(0,Math.min(c,d.scrollTop+8-d.layoutTop)),c<=i&&(c=0);else if(!a&&t==="down"&&r==="top"){let o=d.renderedTop-d.layoutTop;o<=i&&(r="bottom",c=Math.max(0,o))}else!a&&t==="up"&&r==="bottom"&&(c=Math.min(Math.max(0,d.renderedTop-d.layoutTop),i),d.scrollTop+8<=d.layoutTop+c&&(r="top",c=0));return{mode:r,marginTop:c,lastScrollTop:e}}var Ot=2,Ca=250,Pe={objects:6,tasks:10,parts:6,documents:8,history:6},Ma="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z",ei=["due_date","object","type","task_name","area","assigned_user","group"],Ms=["none","area","group","user","object"],Ds=ai,As=["tasks","documents","parts","history"],k=class extends N{constructor(){super(...arguments);this.narrow=!1;this.tight=!1;this.split=!1;this._tightObserver=null;this.panel={};this.embedded=!1;this.presets={};this._presetsApplied=!1;this._mountPath=null;this._objects=[];this._stats=null;this._view="overview";this._allParts=null;this._selectedEntryId=null;this._selectedTaskId=null;this._selectedAreaId=null;this._filterStatus="";this._filterUser=null;this._filterLabel=null;this._filterPlace="";this._filterPriority="";this._savedViews=[];this._activeViewId="";this._unsub=null;this._chartRangeDays=(()=>{try{let e=parseInt(Z(A.chartRange)||"",10);return[7,30,90,365].includes(e)?e:30}catch{return 30}})();this._hideOutliers=(()=>{try{return Z(A.chartHideOutliers)==="1"}catch{return!1}})();this._historyFilter=null;this._budget=null;this._groups={};this._detailStatsData=new Map;this._miniStatsData=new Map;this._features={adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1,places:!1};this._adminPanelUserIds=[];this._operatorWriteEnabled=!1;this._defaultWarningDays=7;this._rowActionStyle="buttons_compact";this._refsInLists=!1;this._partsCostMode="purchase";this._rowActionNotice=!1;this._actionLoading=!1;this._moreMenuOpen=!1;this._objMenuOpen=!1;this._toastMessage="";this._toastKind="error";this._toastUndo=null;this._toastActionLabel="";this._filtersOpen=!1;this._newMenuOpen=!1;this._gsSetupsCount=0;this._gsAdoptCount=0;this._gsLoaded=!1;this._resetOffersLoaded=!1;this._resetOffersCount=0;this._batteryFleetSetupAvailable=!1;this._staleBundle=!1;this._staleChecked=!1;this._toastTimer=null;this._dismissedSuggestions=new Set;this._overviewTab=(()=>{try{let e=Z(A.overviewTab);return e==="today"||e==="calendar"?e:"dashboard"}catch{return"dashboard"}})();this._activeTab="overview";this._costDurationToggle="both";this._historySearch="";this._sortMode="due_date";this._objectSortMode="alphabetical";this._groupByMode="none";this._objectViewMode="cards";this._objectsTableColumns=mi;this._showArchived=!1;this._bulkMode=!1;this._bulkSelected=new Set;this._objBulkMode=!1;this._objBulkSelected=new Set;this._bulkMenuOpen=!1;this._virtStart=0;this._virtEnd=0;this._virtRowHeight=53;this._virtTotalRows=0;this._virtScrollAttached=!1;this._virtRaf=0;this._stickyState=Rt;this._stickySelectPending=!1;this._stickyRaf=0;this._stickyAttached=!1;this._stickyObserver=null;this._collapsedGroups=new Set;this._collapsedSections=(()=>{try{return new Set(JSON.parse(Z(A.collapsedSections)||"[]"))}catch{return new Set}})();this._objectSectionsCollapsed=(()=>{try{let e=JSON.parse(Z(A.objectSections)||"[]");return new Set((Array.isArray(e)?e:[]).filter(t=>As.includes(t)))}catch{return new Set}})();this._objectSectionOverride=null;this._paletteOpen=!1;this._paletteQuery="";this._paletteActive=0;this._searchRemote=null;this._searchTimer=null;this._searchSeq=0;this._templateGalleryOpen=!1;this._templates=[];this._homeProfile=null;this._templateCategories={};this._templateBusy=!1;this._statsService=null;this._userService=null;this._dataLoaded=!1;this._lastConnection=null;this._popstateHandler=e=>this._onPopState(e);this._locationChangedHandler=()=>this._onLocationChanged();this._lazyUi=null;this._onStickyScroll=()=>{this._stickyRaf||(this._stickyRaf=requestAnimationFrame(()=>{this._stickyRaf=0,this._updateStickyPane()}))};this._onVirtualScroll=()=>{this._virtRaf||(this._virtRaf=requestAnimationFrame(()=>{this._virtRaf=0,this._updateVirtualWindow()}))};this._deepLinkHandled=!1;this._deepLinkInPlace=!1;this._initialLoadDone=!1;this._detailStatsSeq=new Map;this._kpiRefreshInFlight=!1;this._kpiRefreshPending=!1;this._areaUi=null;this._paletteKeydown=e=>{if(e.key==="/"&&!e.ctrlKey&&!e.metaKey&&!e.altKey&&!this._paletteOpen){let i=e.composedPath()[0];if(i instanceof HTMLElement&&(i.tagName==="INPUT"||i.tagName==="TEXTAREA"||i.tagName==="SELECT"||i.isContentEditable))return;e.preventDefault(),this._openPalette();return}if(!this._paletteOpen)return;let t=this._paletteResults;if(e.key==="Escape")e.preventDefault(),this._closePalette();else if(e.key==="ArrowDown")e.preventDefault(),this._paletteActive=Math.min(this._paletteActive+1,t.length-1);else if(e.key==="ArrowUp")e.preventDefault(),this._paletteActive=Math.max(this._paletteActive-1,0);else if(e.key==="Enter"){e.preventDefault();let i=t[this._paletteActive];i&&this._selectPaletteResult(i)}};this._onObjectReplaced=async e=>{this._showToast([s("object_replaced",this._lang),this._deviceSwapText(e.detail.device_swap)].filter(Boolean).join(" \xB7 "),"info");try{await this._loadData()}catch{}e.detail.entry_id&&this._showObject(e.detail.entry_id)};this._onObjectSaved=async e=>{let t=this._deviceSwapText(e.detail?.device_swap);t&&this._showToast(t,"info"),await this._onDialogEvent()};this._checklistPending=new Map;this._checklistChain=Promise.resolve();this._onDialogEvent=async()=>{try{await this._loadData()}catch{}};this._onTaskCompleted=async e=>{await this._onDialogEvent();let t=e.detail;t?.undo&&this._offerUndo(t.entryId,t.taskId,s("task_completed_named",this._lang).replace("{task}",t.taskName))};this._onCalendarLlCustom=e=>{let t=e.detail;t?.type==="maintenance-supporter:open-task"&&t.entry_id&&t.task_id&&(e.stopPropagation(),this._showTask(t.entry_id,t.task_id))};this._fullHistory=null;this._onHistoryEntrySaved=async()=>{await this._loadData()}}get _currencySymbol(){return ot(this._budget)}get _lang(){return K(this.hass)}get _isOperator(){return!Ne(this.hass?.user,{operatorWriteEnabled:this._operatorWriteEnabled,operatorIds:this._adminPanelUserIds})}_ensureLazyUi(){return this._lazyUi||(this._lazyUi=Promise.all([import("/maintenance_supporter_panelfiles/panel-chunks/object-dialog-LVQ66XFQ.js"),import("/maintenance_supporter_panelfiles/panel-chunks/task-dialog-YLJMXLIE.js"),import("/maintenance_supporter_panelfiles/panel-chunks/complete-dialog-BNENVZWN.js"),import("/maintenance_supporter_panelfiles/panel-chunks/qr-dialog-K2UAEOON.js"),import("/maintenance_supporter_panelfiles/panel-chunks/adopt-problem-sensors-dialog-EIOG5AWG.js"),import("/maintenance_supporter_panelfiles/panel-chunks/suggested-setups-dialog-JI2FIW3T.js"),import("/maintenance_supporter_panelfiles/panel-chunks/settings-view-4SWT5FDJ.js"),import("/maintenance_supporter_panelfiles/panel-chunks/bulk-edit-dialog-JTKDUPIU.js")]).then(()=>this.updateComplete)),this._lazyUi}async _ui(e){return await this._ensureLazyUi(),this.shadowRoot?.querySelector(e)??null}connectedCallback(){super.connectedCallback(),this._mountPath=window.location.pathname;let e=window.requestIdleCallback,t=()=>this._ensureLazyUi();e?e(t,{timeout:3e3}):window.setTimeout(t,1500),window.addEventListener("popstate",this._popstateHandler),window.addEventListener("location-changed",this._locationChangedHandler),window.addEventListener("keydown",this._paletteKeydown),typeof ResizeObserver<"u"&&(this._tightObserver=new ResizeObserver(i=>{let a=i[0]?.contentRect.width??0;a>0&&(this.tight=a<1e3),a>0&&(this.split=a>=1500)}),this._tightObserver.observe(this)),window.addEventListener("resize",this._onVirtualScroll,{passive:!0});try{let i=Z(A.taskSort);i&&ei.includes(i)&&(this._sortMode=i);let a=Z(A.objectSort);a&&["alphabetical","due_soonest","task_count"].includes(a)&&(this._objectSortMode=a);let r=Z(A.groupBy);r&&Ms.includes(r)&&(this._groupByMode=r);let c=Z(A.objectView);(c==="cards"||c==="table")&&(this._objectViewMode=c)}catch{}if(this._objects.length===0){let i=is();i&&(this._objects=i.objects,i.stats&&(this._stats=i.stats))}}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("popstate",this._popstateHandler),window.removeEventListener("location-changed",this._locationChangedHandler),window.removeEventListener("keydown",this._paletteKeydown),this._tightObserver?.disconnect(),this._tightObserver=null,window.removeEventListener("resize",this._onVirtualScroll),this.shadowRoot?.querySelector(".content")?.removeEventListener("scroll",this._onVirtualScroll),this._virtScrollAttached=!1,this._virtRaf&&cancelAnimationFrame(this._virtRaf),this._detachStickyPane(),this._unsub&&(this._unsub(),this._unsub=null),this._dataLoaded=!1,this._initialLoadDone=!1,this._lastConnection=null,this._deepLinkHandled=!1,this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=null),this._toastTimer&&(clearTimeout(this._toastTimer),this._toastTimer=null),this._toastMessage="",this._toastUndo=null,this._toastActionLabel="",this._statsService?.clearCache(),this._statsService=null}willUpdate(e){super.willUpdate(e),e.has("_groupByMode")&&this._collapsedGroups.size>0&&(this._collapsedGroups=new Set)}updated(e){if(super.updated(e),Be(this,e),e.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,history.replaceState({msp_view:"overview",msp_entry:null,msp_task:null},""),this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}this._statsService?this._statsService.updateHass(this.hass):(this._statsService=new kt(this.hass),this._fetchMiniStatsForOverview()),this._userService?this._userService.updateHass(this.hass):(this._userService=new Mi(this.hass),this._userService.getUsers().then(()=>this.requestUpdate()))}let t=this.shadowRoot?.querySelector(".content");t&&!this._virtScrollAttached&&(t.addEventListener("scroll",this._onVirtualScroll,{passive:!0}),this._virtScrollAttached=!0),this._updateVirtualWindow(),this._syncStickyPane(t)}_syncStickyPane(e){let t=this.shadowRoot?.querySelector(".split-pane");if(!t||!e){this._stickyAttached&&this._detachStickyPane();return}this._stickyAttached||(e.addEventListener("scroll",this._onStickyScroll,{passive:!0}),window.addEventListener("resize",this._onStickyScroll),typeof ResizeObserver<"u"&&(this._stickyObserver=new ResizeObserver(this._onStickyScroll)),this._stickyAttached=!0),this._stickyObserver?.observe(t),this._updateStickyPane()}_detachStickyPane(){this.shadowRoot?.querySelector(".content")?.removeEventListener("scroll",this._onStickyScroll),window.removeEventListener("resize",this._onStickyScroll),this._stickyObserver?.disconnect(),this._stickyObserver=null,this._stickyRaf&&cancelAnimationFrame(this._stickyRaf),this._stickyRaf=0,this._stickyAttached=!1,this._stickyState=Rt,this._stickySelectPending=!1}_updateStickyPane(){let e=this.shadowRoot,t=e?.querySelector(".content"),i=e?.querySelector(".split-pane"),a=e?.querySelector(".split-layout"),r=e?.querySelector(".split-list");if(!t||!i||!a||!r)return;let c=t.getBoundingClientRect().top-t.scrollTop,o={scrollTop:t.scrollTop,viewH:t.clientHeight,paneH:i.offsetHeight,listH:r.offsetHeight,layoutTop:a.getBoundingClientRect().top-c,renderedTop:i.getBoundingClientRect().top-c};this._stickySelectPending&&o.scrollTop===this._stickyState.lastScrollTop?this._stickyState=Os(o):(this._stickySelectPending=!1,this._stickyState=Cs(this._stickyState,o));let u=this._stickyState;i.style.top=`${Rs(u.mode,o)}px`,i.style.marginTop=u.marginTop>0?`${u.marginTop}px`:""}_resetStickyPane(){let e=this.shadowRoot?.querySelector(".content");this._stickyState={...Rt,lastScrollTop:e?.scrollTop??0},this._stickySelectPending=!0}_updateVirtualWindow(){let e=this.shadowRoot?.querySelector(".content"),t=this.shadowRoot?.querySelector(".task-table.virtual");if(!e||!t)return;let i=t.querySelector(".task-row:not(.virt-sizer)");i&&i.offsetHeight>20&&(this._virtRowHeight=i.offsetHeight);let a=t.getBoundingClientRect().top-e.getBoundingClientRect().top+e.scrollTop,r=Es({scrollTop:e.scrollTop,viewportHeight:e.clientHeight,listTop:a,rowHeight:this._virtRowHeight,total:this._virtTotalRows});(r.start!==this._virtStart||r.end!==this._virtEnd)&&(this._virtStart=r.start,this._virtEnd=r.end)}async _loadData(){let[e,t,i,a,r,c]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/budget_status"}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/groups"}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/views/list"}).catch(()=>null)]);if(c&&(this._savedViews=c.views||[]),e&&(this._objects=et(e.objects),Nt(this._objects,t??this._stats??null),this._maybeLoadGettingStarted()),this._detailOpen()&&this._fetchFullHistory(this._selectedEntryId,this._selectedTaskId),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/status"}).then(o=>{this._batteryFleetSetupAvailable=!!o.available&&!o.configured}).catch(()=>{this._batteryFleetSetupAvailable=!1}),this._staleChecked||(this._staleChecked=!0,this.hass.connection.sendMessagePromise({type:"maintenance_supporter/version"}).then(o=>{this._staleBundle=ii(o?.version)}).catch(()=>{})),t&&(this._stats=t),i&&(this._budget=i,Ke(this._budget)),a&&(this._groups=a.groups||{}),r){let o=Hi(r);this._features=o.features,this._adminPanelUserIds=[...o.access.operatorIds],this._operatorWriteEnabled=o.access.operatorWriteEnabled,this._defaultWarningDays=o.defaultWarningDays,this._rowActionStyle=o.rowActionStyle,this._rowActionNotice=o.rowActionNoticePending,this._refsInLists=o.refsInLists,this._objectsTableColumns=fi(o.objectsTableColumns),this._partsCostMode=o.partsCostMode}this._fetchMiniStatsForOverview(),this._initialLoadDone=!0,this._handleDeepLink()}_onLocationChanged(){if(!this._initialLoadDone||!window.location.search||this.embedded&&this._mountPath!==null&&window.location.pathname!==this._mountPath)return;if(!this.embedded){let t=`/${typeof this.panel?.url_path=="string"?this.panel.url_path:"maintenance-supporter"}`,i=window.location.pathname;if(i!==t&&!i.startsWith(`${t}/`))return}this._deepLinkHandled=!1,this._deepLinkInPlace=!0;try{this._handleDeepLink()}finally{this._deepLinkInPlace=!1}history.state?.msp_view||history.replaceState({msp_view:this._view,msp_entry:this._selectedEntryId,msp_task:this._selectedTaskId,msp_area:this._selectedAreaId},"")}_handleDeepLink(){if(this._deepLinkHandled)return;let e=new URLSearchParams(window.location.search),t=e.get("ms_action"),i=()=>{let j=window.location.pathname+window.location.hash;history.replaceState(history.state,"",j)};if(t==="add_object"){this._deepLinkHandled=!0,i(),this._ui("maintenance-object-dialog").then(j=>j?.openCreate());return}if(t==="open_vacation"||t==="open_budget"||t==="open_groups"||t==="open_settings"){if(this._deepLinkHandled=!0,i(),!this.hass?.user?.is_admin)return;this._overviewTab="settings",this._ensureLazyUi().then(()=>requestAnimationFrame(()=>{let j=this.shadowRoot?.querySelector("maintenance-settings-view"),x=t.replace("open_","");j?.scrollToSection?.(x)}));return}if(this.embedded&&!this._presetsApplied){this._presetsApplied=!0;let j=this.presets?.tab??"",x=(this.presets?.view??"").trim();if(!e.has("tab")&&Bt.includes(j)&&(j!=="settings"||this.hass?.user?.is_admin)&&(this._overviewTab=j),!e.has("view")&&x){let M=x.toLowerCase(),b=this._savedViews.find(D=>D.id===x)??this._savedViews.find(D=>D.name.trim().toLowerCase()===M);b&&(this._overviewTab="dashboard",this._applyView(b.id))}}let a=e.get("tab"),r=e.get("view"),c=e.get("sort"),o=e.get("status");if(a!==null||r!==null||c!==null||o!==null){if(i(),this._view!=="overview"&&(this._view="overview",this._selectedEntryId=null,this._selectedTaskId=null,this._moreMenuOpen=!1,this._scrollContentToTop()),Bt.includes(a??"")&&(a!=="settings"||this.hass?.user?.is_admin)&&this._setOverviewTab(a),r!==null){let j=r.trim().toLowerCase(),x=this._savedViews.find(M=>M.id===r)??this._savedViews.find(M=>M.name.trim().toLowerCase()===j);x&&(this._overviewTab!=="dashboard"&&this._setOverviewTab("dashboard"),this._applyView(x.id))}ei.includes(c??"")&&(this._sortMode=c,this._activeViewId="",V(A.taskSort,this._sortMode)),Ds.includes(o??"")&&(this._overviewTab!=="dashboard"&&this._setOverviewTab("dashboard"),this._filterByStatus(o))}let u=e.get("area");if(u&&!e.get("entry_id")){this._deepLinkHandled=!0,i(),this._objects.some(j=>Oi(j.object)===u)?this._showArea(u):this._showAllAreas();return}let p=e.get("entry_id");if(!p)return;this._deepLinkHandled=!0;let g=e.get("task_id"),m=e.get("action"),v=e.get("section"),y=As.includes(v??"")?v:null,E=window.location.pathname+window.location.hash;history.replaceState(history.state,"",E);let w=this._getObject(p);if(!w){this._showOverview();return}if(g){let j=w.tasks.find(x=>x.id===g);if(!j){this._showObject(p,y);return}this._showTask(p,g),m==="complete"?requestAnimationFrame(()=>{this._openCompleteDialog(p,g,j.name,this._features.checklists?j.checklist:void 0,this._features.adaptive&&!!j.adaptive_config?.enabled,{viaTagScan:!0})}):m==="skip"?requestAnimationFrame(()=>{j.allow_skip!==!1&&this._promptSkipTask(p,g)}):m==="quick_complete"&&requestAnimationFrame(()=>{this._handleQuickComplete(p,g,j)})}else this._showObject(p,y)}_isCounterEntity(e){if(!e)return!1;let t=e.type||"threshold";return t==="counter"||t==="state_change"}async _fetchDetailStats(e,t){if(!this._statsService)return;let i=(this._detailStatsSeq.get(e)??0)+1;this._detailStatsSeq.set(e,i);let a=await this._statsService.getDetailStats(e,t,this._chartRangeDays);if(this._detailStatsSeq.get(e)!==i)return;let r=new Map(this._detailStatsData);r.set(e,a),this._detailStatsData=r}_setChartRange(e){if(e===this._chartRangeDays)return;this._chartRangeDays=e;try{V(A.chartRange,String(e))}catch{}let t=this._selectedEntryId&&this._selectedTaskId?this._getTask(this._selectedEntryId,this._selectedTaskId):null,i=ge(t?.trigger_config);if(i){let a=new Map(this._detailStatsData);a.delete(i),this._detailStatsData=a,this._fetchDetailStats(i,this._isCounterEntity(t.trigger_config))}}_setHideOutliers(e){if(e!==this._hideOutliers){this._hideOutliers=e;try{V(A.chartHideOutliers,e?"1":"0")}catch{}}}async _fetchMiniStatsForOverview(){if(!this._statsService)return;let e=[];for(let i of this._objects)for(let a of i.tasks){let r=a.battery_fleet_task?void 0:ge(a.trigger_config);r&&e.push({entityId:r,isCounter:this._isCounterEntity(a.trigger_config)})}if(e.length===0)return;let t=await this._statsService.getBatchMiniStats(e);this._miniStatsData=new Map([...this._miniStatsData,...t])}async _subscribe(){try{let e=await this.hass.connection.subscribeMessage(t=>{let i=t,a=ts(this._objects,i);a!==null&&(this._objects=a,t.objects&&Nt(a,this._stats??null),this._refreshKpis(),this._detailOpen()&&(i.objects||(i.delta||[]).some(r=>r.entry_id===this._selectedEntryId))&&this._fetchFullHistory(this._selectedEntryId,this._selectedTaskId))},{type:"maintenance_supporter/subscribe",deltas:!0,compact:!0});if(!this.isConnected){e();return}this._unsub=e}catch{}}async _refreshKpis(){if(this._kpiRefreshInFlight){this._kpiRefreshPending=!0;return}this._kpiRefreshInFlight=!0;try{do{this._kpiRefreshPending=!1;let[e,t]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"}).catch(()=>null),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/budget_status"}).catch(()=>null)]);if(!this.isConnected)return;e&&(this._stats=e),t&&(this._budget=t,Ke(this._budget))}while(this._kpiRefreshPending)}finally{this._kpiRefreshInFlight=!1}}get _taskRows(){let e=[];for(let p of this._objects)for(let g of p.tasks){if(!this._showArchived&&g.archived||this._filterStatus&&g.status!==this._filterStatus)continue;if(this._filterUser){let v=this._filterUser==="current_user"?this._userService?.getCurrentUserId():this._filterUser;if(!tt(g,v))continue}if(this._filterLabel&&!(g.labels||[]).includes(this._filterLabel)||this._filterPlace&&(p.object.place||"home")!==this._filterPlace||this._filterPriority&&(g.priority||"normal")!==this._filterPriority)continue;let m=[];for(let v of Object.values(this._groups))v.task_refs?.some(y=>y.entry_id===p.entry_id&&y.task_id===g.id)&&m.push(v.name);e.push({entry_id:p.entry_id,task_id:g.id,object_name:p.object.name,allow_skip:g.allow_skip!==!1,notify_enabled:g.notify_enabled!==!1,task_name:g.name,type:g.type,schedule_type:g.schedule_type,status:g.status,days_until_due:g.days_until_due??null,next_due:g.next_due??null,last_performed:g.last_performed??null,next_event_titles:g.next_event_titles??[],trigger_active:g.trigger_active,trigger_current_value:g.trigger_current_value??null,trigger_current_delta:g.trigger_current_delta??null,trigger_config:g.trigger_config??null,trigger_entity_info:g.trigger_entity_info??null,battery_fleet_task:g.battery_fleet_task===!0,times_performed:g.times_performed,total_cost:g.total_cost,interval_days:g.interval_days??null,interval_unit:g.interval_unit??null,interval_anchor:g.interval_anchor??null,is_done:g.is_done??!1,archived:g.archived??!1,history:g.history||[],enabled:g.enabled,nfc_tag_id:g.nfc_tag_id??null,priority:g.priority??"normal",labels:g.labels??[],area_id:p.object.area_id??null,responsible_user_id:g.responsible_user_id??null,group_names:m})}let t=(p,g)=>Me(p.status)-Me(g.status),i=(p,g)=>(p.days_until_due??99999)-(g.days_until_due??99999),a=(p,g)=>t(p,g)||i(p,g),r=p=>p.area_id&&this.hass?.areas?.[p.area_id]?.name||"",c=p=>p.responsible_user_id&&this._userService?.getUserName(p.responsible_user_id)||"",o=p=>p.group_names[0]||"",u={due_date:a,object:(p,g)=>p.object_name.localeCompare(g.object_name)||a(p,g),type:(p,g)=>p.type.localeCompare(g.type)||a(p,g),task_name:(p,g)=>p.task_name.localeCompare(g.task_name),area:(p,g)=>{let m=r(p),v=r(g);return!m&&v?1:m&&!v?-1:m.localeCompare(v)||a(p,g)},assigned_user:(p,g)=>{let m=c(p),v=c(g);return!m&&v?1:m&&!v?-1:m.localeCompare(v)||a(p,g)},group:(p,g)=>{let m=o(p),v=o(g);return!m&&v?1:m&&!v?-1:m.localeCompare(v)||a(p,g)}};return e.sort(u[this._sortMode]),e}_getObject(e){return this._objects.find(t=>t.entry_id===e)}_getTask(e,t){return this._getObject(e)?.tasks.find(a=>a.id===t)}_listRef(e,t){if(!this._refsInLists)return h;let i=this._getObject(e);return He(Se(i?.object,i?.tasks.find(a=>a.id===t)))}_objRef(e){return this._refsInLists?He(je(e)):h}_pushPanelState(e,t,i,a){let r={msp_view:e,msp_entry:t||null,msp_task:i||null,msp_area:a||null};this._deepLinkInPlace?history.replaceState(r,""):history.pushState(r,"")}_onPopState(e){let t=e.state;if(t?.msp_view&&(this._view=t.msp_view,this._selectedEntryId=t.msp_entry||null,this._selectedTaskId=t.msp_task||null,this._selectedAreaId=t.msp_area||null,this._moreMenuOpen=!1,this._objectSectionOverride=null,t.msp_view==="all_parts"&&this._loadAllParts(),t.msp_view==="task"&&t.msp_entry&&t.msp_task)){this._historyFilter=null;let i=this._getTask(t.msp_entry,t.msp_task),a=ge(i?.trigger_config);i&&a&&this._fetchDetailStats(a,this._isCounterEntity(i.trigger_config))}}_showOverview(){this._pushPanelState("overview"),this._view="overview",this._selectedEntryId=null,this._selectedTaskId=null,this._moreMenuOpen=!1,this._scrollContentToTop()}_showAllObjects(){this._pushPanelState("all_objects"),this._view="all_objects",this._objBulkMode=!1,this._objBulkSelected=new Set,this._selectedEntryId=null,this._selectedTaskId=null,this._scrollContentToTop()}_showAllParts(){this._pushPanelState("all_parts"),this._view="all_parts",this._selectedEntryId=null,this._selectedTaskId=null,this._scrollContentToTop(),this._loadAllParts()}async _loadAllParts(){try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"});this._allParts=e.parts||[]}catch{this._allParts=[]}}_showAllAreas(){this._pushPanelState("all_areas"),this._view="all_areas",this._selectedEntryId=null,this._selectedTaskId=null,this._scrollContentToTop()}_showArea(e){this._pushPanelState("area",null,null,e),this._view="area",this._selectedAreaId=e,this._selectedEntryId=null,this._selectedTaskId=null,this._scrollContentToTop()}_ensureAreaUi(){this._areaUi??=Promise.all([import("/maintenance_supporter_panelfiles/panel-chunks/areas-view-5II3GSSX.js"),import("/maintenance_supporter_panelfiles/panel-chunks/area-view-RXPIOB3Q.js")]).catch(()=>{this._areaUi=null})}_filterByStatus(e){this._filterStatus=e,this._activeViewId="",this._overviewTab!=="dashboard"&&(this._overviewTab="dashboard"),this._scrollContentToTop()}get _allLabels(){let e=new Set;for(let t of this._objects)for(let i of t.tasks)for(let a of i.labels||[])e.add(a);return[...e].sort((t,i)=>t.localeCompare(i))}get _allPlaces(){let e=new Map;for(let t of this._objects){let i=t.object;i.place&&!e.has(i.place)&&e.set(i.place,i.place_name||i.place)}return[...e].map(([t,i])=>({id:t,name:i})).sort((t,i)=>t.name.localeCompare(i.name))}get _currentFilters(){return{status:this._filterStatus,user_id:this._filterUser,label:this._filterLabel,priority:this._filterPriority,archived:this._showArchived,sort_mode:this._sortMode,group_by:this._groupByMode}}_applyView(e){if(this._activeViewId=e,!e)return;let t=this._savedViews.find(a=>a.id===e);if(!t)return;let i=t.filters;this._filterStatus=i.status||"",this._filterUser=i.user_id||null,this._filterLabel=i.label||null,this._filterPriority=i.priority||"",this._showArchived=!!i.archived,ei.includes(i.sort_mode)&&(this._sortMode=i.sort_mode),Ms.includes(i.group_by)&&(this._groupByMode=i.group_by);try{V(A.taskSort,this._sortMode),V(A.groupBy,this._groupByMode)}catch{}this._overviewTab!=="dashboard"&&(this._overviewTab="dashboard")}_openSavedViewsDialog(){this.shadowRoot.querySelector("maintenance-saved-views-dialog")?.open(this._currentFilters,this._savedViews)}_onSavedViewsChanged(e){this._savedViews=e.detail.views||[],this._activeViewId&&!this._savedViews.some(t=>t.id===this._activeViewId)&&(this._activeViewId="")}_scrollContentToTop(){requestAnimationFrame(()=>{let e=this.shadowRoot?.querySelector(".content");e&&e.scrollTo({top:0,behavior:"smooth"})})}_renderLineageLink(e,t){let i=e?this._objects.find(a=>a.entry_id===e):void 0;return i?n`

    ${t}: {a.preventDefault(),this._showObject(i.entry_id)}} - >${i.object.name}

    `:h}_showObject(t,e=null){this._pushPanelState("object",t),this._view="object",this._selectedEntryId=t,this._selectedTaskId=null,this._objectSectionOverride=e,e?this._scrollToObjectSection(e):this._scrollContentToTop()}_scrollToObjectSection(t){this.updateComplete.then(()=>requestAnimationFrame(()=>{let e=this.shadowRoot?.querySelector(`.obj-section[data-section="${t}"]`);e?e.scrollIntoView({block:"start",behavior:"smooth"}):this._scrollContentToTop()}))}_toggleObjectSection(t){let e=new Set(this._objectSectionsCollapsed);this._objectSectionOverride===t||!e.has(t)?e.add(t):e.delete(t),this._objectSectionOverride===t&&(this._objectSectionOverride=null),this._objectSectionsCollapsed=e,V(A.objectSections,JSON.stringify([...e]))}_splitActive(){return this.split&&!this.narrow&&!this.tight&&this._view==="overview"&&this._overviewTab==="dashboard"&&!this._bulkMode}_detailOpen(){return(this._view==="task"||this._splitActive())&&!!this._selectedEntryId&&!!this._selectedTaskId}_showFullTaskPage(t,e){this._view!=="task"&&(this._pushPanelState("task",t,e),this._view="task",this._selectedEntryId=t,this._selectedTaskId=e,this._scrollContentToTop())}_showTask(t,e){if(this._splitActive()){this._selectedEntryId=t,this._selectedTaskId=e,this._activeTab="overview",this._historyFilter=null,this._historySearch="",this._resetStickyPane(),this._fetchFullHistory(t,e);let r=this._getTask(t,e),c=gt(r?.trigger_config);r&&c&&this._fetchDetailStats(c,this._isCounterEntity(r.trigger_config));return}this._pushPanelState("task",t,e),this._view="task",this._selectedEntryId=t,this._selectedTaskId=e,this._activeTab="overview",this._historyFilter=null,this._historySearch="",this._scrollContentToTop(),this._fetchFullHistory(t,e);let i=this._getTask(t,e),a=gt(i?.trigger_config);i&&a&&this._fetchDetailStats(a,this._isCounterEntity(i.trigger_config))}_countText(t,e,i,a,r=this._lang){return a===1?s(e,r):s(t,r).replace(`{${i}}`,String(a))}_showToast(t,e="error"){this._toastTimer&&clearTimeout(this._toastTimer),this._toastKind=e,this._toastUndo=null,this._toastActionLabel="",this._toastMessage=t,this._toastTimer=setTimeout(()=>{this._toastMessage="",this._toastTimer=null},4e3)}_showActionToast(t,e,i){this._showUndoToast(t,i),this._toastActionLabel=e}_showUndoToast(t,e){this._toastTimer&&clearTimeout(this._toastTimer),this._toastKind="info",this._toastActionLabel="",this._toastMessage=t,this._toastUndo=e,this._toastTimer=setTimeout(()=>{this._toastMessage="",this._toastUndo=null,this._toastTimer=null},7e3)}_runToastUndo(){let t=this._toastUndo;this._toastTimer&&clearTimeout(this._toastTimer),this._toastMessage="",this._toastUndo=null,this._toastTimer=null,t?.()}_openPalette(){this._paletteQuery="",this._paletteActive=0,this._paletteOpen=!0,this._searchRemote=null,this.updateComplete.then(()=>{this.shadowRoot?.querySelector(".palette-input")?.focus()})}_closePalette(){this._paletteOpen=!1,this._paletteQuery="",this._searchRemote=null,this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=null)}_onPaletteInput(t){this._paletteQuery=t,this._paletteActive=0,this._searchTimer&&clearTimeout(this._searchTimer);let e=t.trim();if(e.length{this._searchTimer=null;let i=++this._searchSeq;this.hass.connection.sendMessagePromise({type:"maintenance_supporter/search",query:e,limit:Pt.documents}).then(a=>{i!==this._searchSeq||!this._paletteOpen||(this._searchRemote={query:e,documents:a.documents||[],history:a.history||[]})}).catch(()=>{i!==this._searchSeq||!this._paletteOpen||(this._searchRemote={query:e,documents:[],history:[]})})},Ta)}get _paletteResults(){let t=this._lang,e=this._paletteQuery.trim();if(e.lengthw?[j,s("archived",t)].filter(Boolean).join(" \xB7 "):j;n.task==null&&a.push({kind:"object",entryId:m.entry_id,label:v.name||"",sub:E(v.archived,s("object",t)),score:1e3,icon:"mdi:package-variant-closed",ref:y});for(let w of m.tasks)n.task!=null&&w.ref_no!==n.task||r.push({kind:"task",entryId:m.entry_id,taskId:w.id,label:w.name||"",sub:E(w.archived||v.archived,v.name||""),score:n.task==null?900:1e3,icon:"mdi:clipboard-check-outline",ref:St(v,w)})}if(a.length||r.length){let m=this._searchRemote&&this._searchRemote.query===e?this._searchRemote:null,v=[...a,...r.slice(0,Pt.tasks)];for(let y of m?.history.slice(0,1)??[])v.push({kind:"history",entryId:y.entry_id,taskId:y.task_id,label:y.task_name||"",sub:[y.object_name,y.timestamp?q(y.timestamp,t):""].filter(Boolean).join(" \xB7 "),snippet:y.snippet||"",score:y.score,icon:"mdi:note-text-outline",ref:y.ref??null});return v}}for(let m of this._objects){let v=m.object;if(v.archived)continue;let y=v.name||"",E=Lt(i,[{text:y,weight:3},{text:v.manufacturer,weight:2},{text:v.model,weight:2},{text:v.serial_number,weight:2},{text:v.notes,weight:1}]);if(E>0){let w=[v.manufacturer,v.model].filter(Boolean).join(" ");a.push({kind:"object",entryId:m.entry_id,label:y,sub:w||s("object",t),score:E,icon:"mdi:package-variant-closed",ref:jt(v)})}for(let w of m.tasks){if(w.archived)continue;let j=(w.labels||[]).join(" "),x=Lt(i,[{text:w.name,weight:3},{text:y,weight:2},{text:j,weight:2},{text:w.notes,weight:1}]);if(x>0){let M=(w.labels||[]).length?` #${(w.labels||[]).join(" #")}`:"";r.push({kind:"task",entryId:m.entry_id,taskId:w.id,label:w.name||"",sub:y+M,score:x,icon:"mdi:clipboard-check-outline",ref:St(v,w)})}}for(let w of m.parts||[]){let j=Lt(i,[{text:w.name,weight:3},{text:w.mpn,weight:2},{text:w.vendor,weight:1},{text:w.storage_location,weight:1},{text:w.notes,weight:1}]);j>0&&c.push({kind:"part",entryId:m.entry_id,label:w.name||"",sub:[y,w.mpn].filter(Boolean).join(" \xB7 "),score:j,icon:"mdi:cog-outline"})}}let u=(m,v)=>v.score-m.score||m.label.localeCompare(v.label),d=[...a.sort(u).slice(0,Pt.objects),...r.sort(u).slice(0,Pt.tasks),...c.sort(u).slice(0,Pt.parts)],g=this._searchRemote&&this._searchRemote.query===e?this._searchRemote:null;if(g){let m=g.documents.slice(0,Pt.documents);for(let v of[...m.filter(y=>y.match!=="content"),...m.filter(y=>y.match==="content")])d.push({kind:v.match==="content"?"content":"document",entryId:v.entry_id,docId:v.id,docKind:v.kind,url:v.url,page:v.page??null,label:nt(v),sub:v.object_name||"",snippet:v.snippet||"",score:v.score,icon:v.kind==="weblink"?"mdi:link-variant":"mdi:file-document-outline"});for(let v of g.history.slice(0,Pt.history))d.push({kind:"history",entryId:v.entry_id,taskId:v.task_id,label:v.task_name||"",ref:v.ref??null,sub:[v.object_name,v.timestamp?q(v.timestamp,t):""].filter(Boolean).join(" \xB7 "),snippet:v.snippet||"",score:v.score,icon:v.type==="skipped"?"mdi:skip-next-circle-outline":"mdi:note-text-outline"})}return d}_selectPaletteResult(t){let e=this._paletteQuery.trim();switch(this._closePalette(),t.kind){case"task":t.taskId&&this._showTask(t.entryId,t.taskId);return;case"history":if(!t.taskId)return;this._showTask(t.entryId,t.taskId),this._activeTab="history",this._historySearch=e;return;case"document":case"content":t.docKind==="weblink"?st(t.url)&&window.open(t.url,"_blank","noopener"):t.docId&&Et(this.hass,t.docId,t.page?`#page=${t.page}`:"").catch(()=>{}),this._showObject(t.entryId,"documents");return;case"part":this._showObject(t.entryId,"parts");return;default:this._showObject(t.entryId)}}_renderPalette(){if(!this._paletteOpen)return h;let t=this._lang,e=this._paletteResults,i=this._paletteQuery.trim(),a={object:s("objects",t),task:s("tasks",t),part:s("search_group_parts",t),document:s("documents",t),content:s("search_group_content",t),history:s("search_group_history",t)},r=i.length>=Re&&(!this._searchRemote||this._searchRemote.query!==i),c=null;return o` + >${i.object.name}

    `:h}_showObject(e,t=null){this._pushPanelState("object",e),this._view="object",this._selectedEntryId=e,this._selectedTaskId=null,this._objectSectionOverride=t,t?this._scrollToObjectSection(t):this._scrollContentToTop()}_scrollToObjectSection(e){this.updateComplete.then(()=>requestAnimationFrame(()=>{let t=this.shadowRoot?.querySelector(`.obj-section[data-section="${e}"]`);t?t.scrollIntoView({block:"start",behavior:"smooth"}):this._scrollContentToTop()}))}_toggleObjectSection(e){let t=new Set(this._objectSectionsCollapsed);this._objectSectionOverride===e||!t.has(e)?t.add(e):t.delete(e),this._objectSectionOverride===e&&(this._objectSectionOverride=null),this._objectSectionsCollapsed=t,V(A.objectSections,JSON.stringify([...t]))}_splitActive(){return this.split&&!this.narrow&&!this.tight&&this._view==="overview"&&this._overviewTab==="dashboard"&&!this._bulkMode}_detailOpen(){return(this._view==="task"||this._splitActive())&&!!this._selectedEntryId&&!!this._selectedTaskId}_showFullTaskPage(e,t){this._view!=="task"&&(this._pushPanelState("task",e,t),this._view="task",this._selectedEntryId=e,this._selectedTaskId=t,this._scrollContentToTop())}_showTask(e,t){if(this._splitActive()){this._selectedEntryId=e,this._selectedTaskId=t,this._activeTab="overview",this._historyFilter=null,this._historySearch="",this._resetStickyPane(),this._fetchFullHistory(e,t);let r=this._getTask(e,t),c=ge(r?.trigger_config);r&&c&&this._fetchDetailStats(c,this._isCounterEntity(r.trigger_config));return}this._pushPanelState("task",e,t),this._view="task",this._selectedEntryId=e,this._selectedTaskId=t,this._activeTab="overview",this._historyFilter=null,this._historySearch="",this._scrollContentToTop(),this._fetchFullHistory(e,t);let i=this._getTask(e,t),a=ge(i?.trigger_config);i&&a&&this._fetchDetailStats(a,this._isCounterEntity(i.trigger_config))}_countText(e,t,i,a,r=this._lang){return a===1?s(t,r):s(e,r).replace(`{${i}}`,String(a))}_showToast(e,t="error"){this._toastTimer&&clearTimeout(this._toastTimer),this._toastKind=t,this._toastUndo=null,this._toastActionLabel="",this._toastMessage=e,this._toastTimer=setTimeout(()=>{this._toastMessage="",this._toastTimer=null},4e3)}_showActionToast(e,t,i){this._showUndoToast(e,i),this._toastActionLabel=t}_showUndoToast(e,t){this._toastTimer&&clearTimeout(this._toastTimer),this._toastKind="info",this._toastActionLabel="",this._toastMessage=e,this._toastUndo=t,this._toastTimer=setTimeout(()=>{this._toastMessage="",this._toastUndo=null,this._toastTimer=null},7e3)}_runToastUndo(){let e=this._toastUndo;this._toastTimer&&clearTimeout(this._toastTimer),this._toastMessage="",this._toastUndo=null,this._toastTimer=null,e?.()}_openPalette(){this._paletteQuery="",this._paletteActive=0,this._paletteOpen=!0,this._searchRemote=null,this.updateComplete.then(()=>{this.shadowRoot?.querySelector(".palette-input")?.focus()})}_closePalette(){this._paletteOpen=!1,this._paletteQuery="",this._searchRemote=null,this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=null)}_onPaletteInput(e){this._paletteQuery=e,this._paletteActive=0,this._searchTimer&&clearTimeout(this._searchTimer);let t=e.trim();if(t.length{this._searchTimer=null;let i=++this._searchSeq;this.hass.connection.sendMessagePromise({type:"maintenance_supporter/search",query:t,limit:Pe.documents}).then(a=>{i!==this._searchSeq||!this._paletteOpen||(this._searchRemote={query:t,documents:a.documents||[],history:a.history||[]})}).catch(()=>{i!==this._searchSeq||!this._paletteOpen||(this._searchRemote={query:t,documents:[],history:[]})})},Ca)}get _paletteResults(){let e=this._lang,t=this._paletteQuery.trim();if(t.lengthw?[j,s("archived",e)].filter(Boolean).join(" \xB7 "):j;o.task==null&&a.push({kind:"object",entryId:m.entry_id,label:v.name||"",sub:E(v.archived,s("object",e)),score:1e3,icon:"mdi:package-variant-closed",ref:y});for(let w of m.tasks)o.task!=null&&w.ref_no!==o.task||r.push({kind:"task",entryId:m.entry_id,taskId:w.id,label:w.name||"",sub:E(w.archived||v.archived,v.name||""),score:o.task==null?900:1e3,icon:"mdi:clipboard-check-outline",ref:Se(v,w)})}if(a.length||r.length){let m=this._searchRemote&&this._searchRemote.query===t?this._searchRemote:null,v=[...a,...r.slice(0,Pe.tasks)];for(let y of m?.history.slice(0,1)??[])v.push({kind:"history",entryId:y.entry_id,taskId:y.task_id,label:y.task_name||"",sub:[y.object_name,y.timestamp?q(y.timestamp,e):""].filter(Boolean).join(" \xB7 "),snippet:y.snippet||"",score:y.score,icon:"mdi:note-text-outline",ref:y.ref??null});return v}}for(let m of this._objects){let v=m.object;if(v.archived)continue;let y=v.name||"",E=Le(i,[{text:y,weight:3},{text:v.manufacturer,weight:2},{text:v.model,weight:2},{text:v.serial_number,weight:2},{text:v.notes,weight:1}]);if(E>0){let w=[v.manufacturer,v.model].filter(Boolean).join(" ");a.push({kind:"object",entryId:m.entry_id,label:y,sub:w||s("object",e),score:E,icon:"mdi:package-variant-closed",ref:je(v)})}for(let w of m.tasks){if(w.archived)continue;let j=(w.labels||[]).join(" "),x=Le(i,[{text:w.name,weight:3},{text:y,weight:2},{text:j,weight:2},{text:w.notes,weight:1}]);if(x>0){let M=(w.labels||[]).length?` #${(w.labels||[]).join(" #")}`:"";r.push({kind:"task",entryId:m.entry_id,taskId:w.id,label:w.name||"",sub:y+M,score:x,icon:"mdi:clipboard-check-outline",ref:Se(v,w)})}}for(let w of m.parts||[]){let j=Le(i,[{text:w.name,weight:3},{text:w.mpn,weight:2},{text:w.vendor,weight:1},{text:w.storage_location,weight:1},{text:w.notes,weight:1}]);j>0&&c.push({kind:"part",entryId:m.entry_id,label:w.name||"",sub:[y,w.mpn].filter(Boolean).join(" \xB7 "),score:j,icon:"mdi:cog-outline"})}}let u=(m,v)=>v.score-m.score||m.label.localeCompare(v.label),p=[...a.sort(u).slice(0,Pe.objects),...r.sort(u).slice(0,Pe.tasks),...c.sort(u).slice(0,Pe.parts)],g=this._searchRemote&&this._searchRemote.query===t?this._searchRemote:null;if(g){let m=g.documents.slice(0,Pe.documents);for(let v of[...m.filter(y=>y.match!=="content"),...m.filter(y=>y.match==="content")])p.push({kind:v.match==="content"?"content":"document",entryId:v.entry_id,docId:v.id,docKind:v.kind,url:v.url,page:v.page??null,label:ne(v),sub:v.object_name||"",snippet:v.snippet||"",score:v.score,icon:v.kind==="weblink"?"mdi:link-variant":"mdi:file-document-outline"});for(let v of g.history.slice(0,Pe.history))p.push({kind:"history",entryId:v.entry_id,taskId:v.task_id,label:v.task_name||"",ref:v.ref??null,sub:[v.object_name,v.timestamp?q(v.timestamp,e):""].filter(Boolean).join(" \xB7 "),snippet:v.snippet||"",score:v.score,icon:v.type==="skipped"?"mdi:skip-next-circle-outline":"mdi:note-text-outline"})}return p}_selectPaletteResult(e){let t=this._paletteQuery.trim();switch(this._closePalette(),e.kind){case"task":e.taskId&&this._showTask(e.entryId,e.taskId);return;case"history":if(!e.taskId)return;this._showTask(e.entryId,e.taskId),this._activeTab="history",this._historySearch=t;return;case"document":case"content":e.docKind==="weblink"?le(e.url)&&window.open(e.url,"_blank","noopener"):e.docId&&Ee(this.hass,e.docId,e.page?`#page=${e.page}`:"").catch(()=>{}),this._showObject(e.entryId,"documents");return;case"part":this._showObject(e.entryId,"parts");return;default:this._showObject(e.entryId)}}_renderPalette(){if(!this._paletteOpen)return h;let e=this._lang,t=this._paletteResults,i=this._paletteQuery.trim(),a={object:s("objects",e),task:s("tasks",e),part:s("search_group_parts",e),document:s("documents",e),content:s("search_group_content",e),history:s("search_group_history",e)},r=i.length>=Ot&&(!this._searchRemote||this._searchRemote.query!==i),c=null;return n`
    this._closePalette()}> -
    - `}_openAdoptProblemSensors(){this._ui("maintenance-adopt-problem-sensors-dialog").then(t=>t?.open())}async _onProblemSensorsAdopted(t){let e=t.detail?.tasks_created??0,i=t.detail?.created??[];await this._loadData();let a=this._countText("adopt_problem_done","adopt_problem_done_one","tasks",e);i.length>0?this._showActionToast(a,s("adopt_problem_configure",this._lang),()=>{let r=i[0],c=this._objects.find(u=>u.entry_id===r.entry_id),n=c?.tasks.find(u=>u.id===r.task_id);c&&n&&this._ui("maintenance-task-dialog").then(u=>u?.openEdit(r.entry_id,n))}):this._showToast(a,"info")}async _setupBatteryFleet(){let t=await P(this,{type:"maintenance_supporter/battery_fleet/setup",language:this.hass.language||"en"},{reload:async()=>{this._batteryFleetSetupAvailable=!1,await this._loadData()},onError:a=>this._showToast(a)});if(t===void 0)return;let e=this._objects.find(a=>a.entry_id===t?.entry_id),i=e?.tasks.find(a=>a.id===t?.task_id)||e?.tasks[0];e&&i&&this._showTask(e.entry_id,i.id),this._showToast(s("battery_fleet_setup_done",this._lang),"info")}_openSuggestedSetups(){this._ui("maintenance-suggested-setups-dialog").then(t=>t?.open())}_onResetsWired(t){let e=t.detail?.wired??0;this._showToast(this._countText("reset_offers_done","reset_offers_done_one","count",e),"info"),this._resetOffersLoaded=!1,this._resetOffersCount=0,this._maybeLoadResetOffers(),this._loadData()}_onSetupsAdopted(t){let e=t.detail?.tasks_created??0;this._showToast(this._countText("setups_done","setups_done_one","tasks",e),"info"),this._loadData()}async _openTemplateGallery(){this._templateGalleryOpen=!0;let t=await P(this,{type:"maintenance_supporter/templates",language:this._lang},{onError:e=>this._showToast(e)});t!==void 0&&(this._templateCategories=t?.categories||{},this._templates=(t?.templates||[]).filter(e=>!e.disabled),this._homeProfile=t?.profile??null)}async _createFromTemplate(t){let e=await P(this,{type:"maintenance_supporter/object/from_template",language:this._lang,template_id:t},{busy:i=>{this._templateBusy=i},reload:async()=>{this._templateGalleryOpen=!1,await this._loadData()},successToast:s("template_created",this._lang),onSuccess:i=>this._showToast(i,"info"),onError:i=>this._showToast(i)});e?.entry_id&&this._showObject(e.entry_id)}_categoryName(t){let e=this._templateCategories[t];return e&&(e[`name_${this._lang}`]||e.name_en)||t}_renderTemplateCard(t,e=!1){let i=this._lang,a=this._homeProfile?.country??null;return o` - - `}_renderTemplateGallery(){if(!this._templateGalleryOpen)return h;let t=this._lang,e=new Map;for(let a of this._templates)e.has(a.category)||e.set(a.category,[]),e.get(a.category).push(a);for(let a of e.values())a.sort((r,c)=>+!!r.dwelling_mismatch-+!!c.dwelling_mismatch);let i=this._templates.filter(a=>a.recommended&&!a.set_up);return o` + `}_renderTemplateGallery(){if(!this._templateGalleryOpen)return h;let e=this._lang,t=new Map;for(let a of this._templates)t.has(a.category)||t.set(a.category,[]),t.get(a.category).push(a);for(let a of t.values())a.sort((r,c)=>+!!r.dwelling_mismatch-+!!c.dwelling_mismatch);let i=this._templates.filter(a=>a.recommended&&!a.set_up);return n`
    {this._templateGalleryOpen=!1}}>