155 files

This commit is contained in:
Home Assistant Version Control committed 2026-10-04 20:46:32 +00:00
1 parent a212615470
commit 0ff8c287a8
155 files changed
+19264 -3148

No files matched your search

@@ -210,6 +210,7 @@
"completed_at_optional": "Dokončeno dne (volitelné, prázdné = nyní)",
"completed_at_pick": "Nastavit datum a čas",
"completed_at_future_error": "Datum dokončení nesmí být v budoucnosti.",
"ha_time_zone_hint": "Čas v časovém pásmu Home Assistantu ({zone})",
"days": "dní",
"day": "den",
"today": "Dnes",
@@ -554,7 +555,8 @@
"cal_forward_windows": "Budoucí okna",
"history_edit_title": "Upravit záznam historie",
"history_delete_entry": "Smazat záznam",
"history_delete_confirm": "Smazat tento záznam historie? Datum posledního provedení se vrátí k předchozímu dokončení; fotografie zůstanou u objektu a spotřebované díly se nevrátí na sklad.",
"history_delete_confirm_entry": "Smazat tento záznam historie? Datum posledního provedení se vrátí na předchozí; fotky zůstanou u objektu.",
"history_delete_returns_parts": "Použité díly se vrátí do zásoby: {parts}.",
"history_edit_timestamp": "Časové razítko",
"manufacturer": "Výrobce",
"model": "Model",
@@ -848,6 +850,11 @@
"loading": "Načítání…",
"archive": "Archivovat",
"undo": "Zpět",
"task_completed_named": "Dokončeno: {task}",
"undo_done": "Dokončení vráceno zpět",
"undo_done_action_ran": "Dokončení vráceno zpět. Akce při dokončení už proběhla a nelze ji vrátit.",
"undo_nothing": "Není co vrátit. Vrátit jde jen vaše poslední dokončení, do 10 minut.",
"undo_changed": "Nelze vrátit. Úkol se mezitím změnil.",
"task_archived": "Úkol archivován",
"object_archived": "Objekt archivován",
"unarchive": "Obnovit z archivu",
@@ -212,6 +212,7 @@
"completed_at_optional": "Udført den (valgfrit, tomt = nu)",
"completed_at_pick": "Vælg dato og tidspunkt",
"completed_at_future_error": "Udførelsesdatoen må ikke ligge i fremtiden.",
"ha_time_zone_hint": "Tid i Home Assistants tidszone ({zone})",
"days": "dage",
"day": "dag",
"today": "I dag",
@@ -556,7 +557,8 @@
"cal_forward_windows": "Kommende vinduer",
"history_edit_title": "Rediger historikpost",
"history_delete_entry": "Slet post",
"history_delete_confirm": "Slet denne historikpost? Datoen for seneste udførelse falder tilbage til den forrige; fotos bliver hos objektet, og forbrugte dele lægges ikke tilbage på lager.",
"history_delete_confirm_entry": "Slet denne historikpost? Datoen for sidste udførelse falder tilbage til den forrige; billeder bliver ved objektet.",
"history_delete_returns_parts": "De brugte dele går tilbage på lager: {parts}.",
"history_edit_timestamp": "Tidsstempel",
"manufacturer": "Producent",
"model": "Model",
@@ -848,6 +850,11 @@
"loading": "Indlæser…",
"archive": "Arkivér",
"undo": "Fortryd",
"task_completed_named": "Fuldført: {task}",
"undo_done": "Udførelsen fortrudt",
"undo_done_action_ran": "Udførelsen fortrudt. Handlingen ved udførelse var allerede kørt og kan ikke fortrydes.",
"undo_nothing": "Intet at fortryde. Kun din egen seneste udførelse kan fortrydes, inden for 10 minutter.",
"undo_changed": "Kan ikke fortrydes. Opgaven er ændret siden.",
"task_archived": "Opgave arkiveret",
"object_archived": "Objekt arkiveret",
"unarchive": "Gendan",
@@ -212,6 +212,7 @@
"completed_at_optional": "Erledigt am (optional, leer = jetzt)",
"completed_at_pick": "Datum & Uhrzeit wählen",
"completed_at_future_error": "Das Erledigungsdatum darf nicht in der Zukunft liegen.",
"ha_time_zone_hint": "Uhrzeit in der Zeitzone von Home Assistant ({zone})",
"days": "Tage",
"day": "Tag",
"today": "Heute",
@@ -556,7 +557,8 @@
"cal_forward_windows": "Zukünftige Fenster",
"history_edit_title": "Verlaufseintrag bearbeiten",
"history_delete_entry": "Eintrag löschen",
"history_delete_confirm": "Diesen Verlaufseintrag löschen? Das Datum der letzten Erledigung fällt auf die vorherige zurück; Fotos bleiben beim Objekt, verbrauchte Teile werden nicht zurückgebucht.",
"history_delete_confirm_entry": "Diesen Verlaufseintrag löschen? Das Datum der letzten Erledigung fällt auf die vorherige zurück; Fotos bleiben beim Objekt.",
"history_delete_returns_parts": "Die dabei verbrauchten Teile gehen zurück in den Bestand: {parts}.",
"history_edit_timestamp": "Zeitstempel",
"manufacturer": "Hersteller",
"model": "Modell",
@@ -848,6 +850,11 @@
"loading": "Laden…",
"archive": "Archivieren",
"undo": "Rückgängig",
"task_completed_named": "Erledigt: {task}",
"undo_done": "Erledigung zurückgenommen",
"undo_done_action_ran": "Erledigung zurückgenommen. Die Aktion beim Erledigen war schon gelaufen und lässt sich nicht zurücknehmen.",
"undo_nothing": "Nichts zurückzunehmen. Nur deine eigene letzte Erledigung lässt sich zurücknehmen, innerhalb von 10 Minuten.",
"undo_changed": "Zurücknehmen nicht möglich. Die Aufgabe wurde inzwischen geändert.",
"task_archived": "Aufgabe archiviert",
"object_archived": "Objekt archiviert",
"unarchive": "Wiederherstellen",
@@ -212,6 +212,7 @@
"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",
@@ -556,7 +557,8 @@
"cal_forward_windows": "Forward windows",
"history_edit_title": "Edit history entry",
"history_delete_entry": "Delete entry",
"history_delete_confirm": "Delete this history entry? The task's last-performed date falls back to the previous completion; photos stay with the object and consumed parts are not restocked.",
"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",
@@ -855,6 +857,11 @@
"loading": "Loading…",
"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",
@@ -210,6 +210,7 @@
"completed_at_optional": "Completado el (opcional, vacío = ahora)",
"completed_at_pick": "Elegir fecha y hora",
"completed_at_future_error": "La fecha de finalización no puede estar en el futuro.",
"ha_time_zone_hint": "Hora en la zona horaria de Home Assistant ({zone})",
"days": "días",
"day": "día",
"today": "Hoy",
@@ -554,7 +555,8 @@
"cal_forward_windows": "Ventanas futuras",
"history_edit_title": "Editar entrada del historial",
"history_delete_entry": "Eliminar entrada",
"history_delete_confirm": "¿Eliminar esta entrada del historial? La fecha de última realización vuelve a la anterior; las fotos permanecen con el objeto y las piezas consumidas no se reponen.",
"history_delete_confirm_entry": "¿Eliminar esta entrada del historial? La fecha de la última realización vuelve a la anterior; las fotos se quedan con el objeto.",
"history_delete_returns_parts": "Las piezas usadas vuelven al stock: {parts}.",
"history_edit_timestamp": "Marca de tiempo",
"manufacturer": "Fabricante",
"model": "Modelo",
@@ -848,6 +850,11 @@
"loading": "Cargando…",
"archive": "Archivar",
"undo": "Deshacer",
"task_completed_named": "Completada: {task}",
"undo_done": "Realización deshecha",
"undo_done_action_ran": "Realización deshecha. La acción al completar ya se había ejecutado y no se puede deshacer.",
"undo_nothing": "No hay nada que deshacer. Solo puedes deshacer tu última realización, en un plazo de 10 minutos.",
"undo_changed": "No se puede deshacer. La tarea ha cambiado desde entonces.",
"task_archived": "Tarea archivada",
"object_archived": "Objeto archivado",
"unarchive": "Desarchivar",
@@ -212,6 +212,7 @@
"completed_at_optional": "Suoritettu (valinnainen, tyhjä = nyt)",
"completed_at_pick": "Aseta päivä ja aika",
"completed_at_future_error": "Suorituspäivä ei voi olla tulevaisuudessa.",
"ha_time_zone_hint": "Aika Home Assistantin aikavyöhykkeellä ({zone})",
"days": "päivää",
"day": "päivä",
"today": "Tänään",
@@ -556,7 +557,8 @@
"cal_forward_windows": "Tulevat jaksot",
"history_edit_title": "Muokkaa historiamerkintää",
"history_delete_entry": "Poista merkintä",
"history_delete_confirm": "Poistetaanko tämä historiamerkintä? Viimeisimmän suorituksen päivä palautuu edelliseen; kuvat jäävät kohteelle eikä kulutettuja osia palauteta varastoon.",
"history_delete_confirm_entry": "Poistetaanko tämä historiamerkintä? Viimeisin suorituspäivä palaa edelliseen; kuvat jäävät kohteelle.",
"history_delete_returns_parts": "Käytetyt osat palautuvat varastoon: {parts}.",
"history_edit_timestamp": "Aikaleima",
"manufacturer": "Valmistaja",
"model": "Malli",
@@ -848,6 +850,11 @@
"loading": "Ladataan…",
"archive": "Arkistoi",
"undo": "Kumoa",
"task_completed_named": "Suoritettu: {task}",
"undo_done": "Suoritus peruttu",
"undo_done_action_ran": "Suoritus peruttu. Suorituksen toiminto oli jo ajettu, eikä sitä voi perua.",
"undo_nothing": "Ei mitään peruttavaa. Vain oman viimeisimmän suorituksen voi perua, 10 minuutin sisällä.",
"undo_changed": "Perua ei voi. Tehtävä on muuttunut sen jälkeen.",
"task_archived": "Tehtävä arkistoitu",
"object_archived": "Kohde arkistoitu",
"unarchive": "Palauta arkistosta",
@@ -210,6 +210,7 @@
"completed_at_optional": "Effectué le (optionnel, vide = maintenant)",
"completed_at_pick": "Choisir la date et l'heure",
"completed_at_future_error": "La date d'achèvement ne peut pas être dans le futur.",
"ha_time_zone_hint": "Heure dans le fuseau horaire de Home Assistant ({zone})",
"days": "jours",
"day": "jour",
"today": "Aujourd'hui",
@@ -554,7 +555,8 @@
"cal_forward_windows": "Fenêtres à venir",
"history_edit_title": "Modifier l'entrée d'historique",
"history_delete_entry": "Supprimer l'entrée",
"history_delete_confirm": "Supprimer cette entrée d'historique ? La date de dernière réalisation revient à la précédente ; les photos restent avec l'objet et les pièces consommées ne sont pas remises en stock.",
"history_delete_confirm_entry": "Supprimer cette entrée d'historique ? La date de dernière réalisation revient à la précédente ; les photos restent avec l'objet.",
"history_delete_returns_parts": "Les pièces utilisées retournent en stock : {parts}.",
"history_edit_timestamp": "Horodatage",
"manufacturer": "Fabricant",
"model": "Modèle",
@@ -848,6 +850,11 @@
"loading": "Chargement…",
"archive": "Archiver",
"undo": "Annuler",
"task_completed_named": "Terminé : {task}",
"undo_done": "Réalisation annulée",
"undo_done_action_ran": "Réalisation annulée. L'action de fin s'était déjà exécutée et ne peut pas être annulée.",
"undo_nothing": "Rien à annuler. Seule votre dernière réalisation peut être annulée, dans les 10 minutes.",
"undo_changed": "Annulation impossible. La tâche a changé depuis.",
"task_archived": "Tâche archivée",
"object_archived": "Objet archivé",
"unarchive": "Désarchiver",
@@ -212,6 +212,7 @@
"completed_at_optional": "पूर्ण होने का समय (वैकल्पिक, खाली = अभी)",
"completed_at_pick": "तारीख और समय चुनें",
"completed_at_future_error": "पूर्णता की तारीख भविष्य में नहीं हो सकती।",
"ha_time_zone_hint": "Home Assistant के समय क्षेत्र का समय ({zone})",
"days": "दिन",
"day": "दिन",
"today": "आज",
@@ -556,7 +557,8 @@
"cal_forward_windows": "आगामी अवधियाँ",
"history_edit_title": "इतिहास प्रविष्टि संपादित करें",
"history_delete_entry": "प्रविष्टि हटाएँ",
"history_delete_confirm": "क्या यह इतिहास प्रविष्टि हटाएँ? अंतिम निष्पादन की तिथि पिछली पूर्णता पर लौट जाएगी; फ़ोटो ऑब्जेक्ट के पास रहेंगे और उपयोग किए गए पुर्जे स्टॉक में वापस नहीं जोड़े जाएँगे।",
"history_delete_confirm_entry": "यह इतिहास प्रविष्टि हटाएँ? अंतिम बार करने की तिथि पिछली पूर्णता पर लौट आएगी; फ़ोटो ऑब्जेक्ट के साथ रहेंगी।",
"history_delete_returns_parts": "इस्तेमाल किए गए पुर्ज़े स्टॉक में वापस जाएँगे: {parts}।",
"history_edit_timestamp": "टाइमस्टैम्प",
"manufacturer": "निर्माता",
"model": "मॉडल",
@@ -848,6 +850,11 @@
"loading": "लोड हो रहा है…",
"archive": "संग्रह करें",
"undo": "पूर्ववत करें",
"task_completed_named": "पूर्ण हुआ: {task}",
"undo_done": "पूर्णता वापस ली गई",
"undo_done_action_ran": "पूर्णता वापस ली गई। पूरा करने पर चलने वाली कार्रवाई पहले ही चल चुकी थी, उसे वापस नहीं लिया जा सकता।",
"undo_nothing": "वापस लेने को कुछ नहीं है। केवल आपकी अपनी पिछली पूर्णता 10 मिनट के भीतर वापस ली जा सकती है।",
"undo_changed": "वापस नहीं लिया जा सकता। तब से कार्य बदल चुका है।",
"task_archived": "कार्य संग्रहित",
"object_archived": "ऑब्जेक्ट संग्रहित",
"unarchive": "संग्रह से हटाएँ",
@@ -212,6 +212,7 @@
"completed_at_optional": "Elvégezve ekkor (opcionális, üres = most)",
"completed_at_pick": "Dátum és idő megadása",
"completed_at_future_error": "Az elvégzés dátuma nem lehet a jövőben.",
"ha_time_zone_hint": "Idő a Home Assistant időzónájában ({zone})",
"days": "nap",
"day": "nap",
"today": "Ma",
@@ -556,7 +557,8 @@
"cal_forward_windows": "Jövőbeli időszakok",
"history_edit_title": "Előzménybejegyzés szerkesztése",
"history_delete_entry": "Bejegyzés törlése",
"history_delete_confirm": "Törli ezt az előzménybejegyzést? Az utolsó elvégzés dátuma az előzőre áll vissza; a fotók az objektumnál maradnak, a felhasznált alkatrészek nem kerülnek vissza a készletbe.",
"history_delete_confirm_entry": "Törlöd ezt az előzménybejegyzést? Az utolsó elvégzés dátuma visszaáll az előzőre; a fotók az objektumnál maradnak.",
"history_delete_returns_parts": "A felhasznált alkatrészek visszakerülnek a készletbe: {parts}.",
"history_edit_timestamp": "Időbélyeg",
"manufacturer": "Gyártó",
"model": "Modell",
@@ -855,6 +857,11 @@
"loading": "Betöltés…",
"archive": "Archiválás",
"undo": "Visszavonás",
"task_completed_named": "Elvégezve: {task}",
"undo_done": "Elvégzés visszavonva",
"undo_done_action_ran": "Elvégzés visszavonva. Az elvégzéskor futó művelet már lefutott, azt nem lehet visszavonni.",
"undo_nothing": "Nincs mit visszavonni. Csak a saját legutóbbi elvégzésed vonható vissza, 10 percen belül.",
"undo_changed": "Nem vonható vissza. A feladat azóta megváltozott.",
"task_archived": "Feladat archiválva",
"object_archived": "Objektum archiválva",
"unarchive": "Archiválás visszavonása",
@@ -210,6 +210,7 @@
"completed_at_optional": "Completato il (opzionale, vuoto = adesso)",
"completed_at_pick": "Imposta data e ora",
"completed_at_future_error": "La data di completamento non può essere nel futuro.",
"ha_time_zone_hint": "Ora nel fuso orario di Home Assistant ({zone})",
"days": "giorni",
"day": "giorno",
"today": "Oggi",
@@ -554,7 +555,8 @@
"cal_forward_windows": "Finestre future",
"history_edit_title": "Modifica voce dello storico",
"history_delete_entry": "Elimina voce",
"history_delete_confirm": "Eliminare questa voce della cronologia? La data dell'ultima esecuzione torna al completamento precedente; le foto restano con l'oggetto e le parti consumate non vengono rimesse a magazzino.",
"history_delete_confirm_entry": "Eliminare questa voce della cronologia? La data dell'ultima esecuzione torna a quella precedente; le foto restano con l'oggetto.",
"history_delete_returns_parts": "I ricambi usati tornano in magazzino: {parts}.",
"history_edit_timestamp": "Data e ora",
"manufacturer": "Produttore",
"model": "Modello",
@@ -848,6 +850,11 @@
"loading": "Caricamento…",
"archive": "Archivia",
"undo": "Annulla",
"task_completed_named": "Completato: {task}",
"undo_done": "Completamento annullato",
"undo_done_action_ran": "Completamento annullato. L'azione al completamento era già stata eseguita e non si può annullare.",
"undo_nothing": "Niente da annullare. Si può annullare solo il tuo ultimo completamento, entro 10 minuti.",
"undo_changed": "Impossibile annullare. L'attività è cambiata nel frattempo.",
"task_archived": "Attività archiviata",
"object_archived": "Oggetto archiviato",
"unarchive": "Annulla archiviazione",
@@ -212,6 +212,7 @@
"completed_at_optional": "完了日時(任意・空欄 = 現在)",
"completed_at_pick": "日時を設定",
"completed_at_future_error": "完了日時に未来は指定できません。",
"ha_time_zone_hint": "Home Assistant のタイムゾーンの時刻({zone})",
"days": "日",
"day": "日",
"today": "今日",
@@ -556,7 +557,8 @@
"cal_forward_windows": "今後の期間",
"history_edit_title": "履歴項目を編集",
"history_delete_entry": "記録を削除",
"history_delete_confirm": "この履歴記録を削除しますか?最終実施日は前回の完了に戻ります。写真はオブジェクトに残り、消費した部品は在庫に戻りません。",
"history_delete_confirm_entry": "この履歴記録を削除しますか?最終実施日は前回の完了に戻ります。写真はオブジェクトに残ります。",
"history_delete_returns_parts": "使用した部品は在庫に戻ります:{parts}。",
"history_edit_timestamp": "日時",
"manufacturer": "メーカー",
"model": "型番",
@@ -848,6 +850,11 @@
"loading": "読み込み中…",
"archive": "アーカイブ",
"undo": "元に戻す",
"task_completed_named": "完了しました:{task}",
"undo_done": "完了を取り消しました",
"undo_done_action_ran": "完了を取り消しました。完了時のアクションは既に実行されており、取り消せません。",
"undo_nothing": "取り消せるものはありません。取り消せるのは自分の直近の完了だけで、10分以内です。",
"undo_changed": "取り消せません。その後タスクが変更されています。",
"task_archived": "タスクをアーカイブしました",
"object_archived": "オブジェクトをアーカイブしました",
"unarchive": "アーカイブ解除",
@@ -212,6 +212,7 @@
"completed_at_optional": "완료 시각 (선택, 비우면 지금)",
"completed_at_pick": "날짜 및 시간 설정",
"completed_at_future_error": "완료 날짜는 미래일 수 없습니다.",
"ha_time_zone_hint": "Home Assistant 시간대 기준 시간 ({zone})",
"days": "일",
"day": "일",
"today": "오늘",
@@ -556,7 +557,8 @@
"cal_forward_windows": "이후 기간",
"history_edit_title": "기록 항목 편집",
"history_delete_entry": "기록 삭제",
"history_delete_confirm": "이 기록을 삭제할까요? 마지막 수행일은 이전 완료로 되돌아가며, 사진은 개체에 남고 사용한 부품은 재고로 복구되지 않습니다.",
"history_delete_confirm_entry": "이 기록 항목을 삭제할까요? 마지막 수행 날짜가 이전 완료로 돌아갑니다. 사진은 객체에 남습니다.",
"history_delete_returns_parts": "사용한 부품은 재고로 돌아갑니다: {parts}.",
"history_edit_timestamp": "타임스탬프",
"manufacturer": "제조사",
"model": "모델",
@@ -855,6 +857,11 @@
"loading": "불러오는 중…",
"archive": "보관",
"undo": "실행 취소",
"task_completed_named": "완료됨: {task}",
"undo_done": "완료를 취소했습니다",
"undo_done_action_ran": "완료를 취소했습니다. 완료 시 동작은 이미 실행되어 되돌릴 수 없습니다.",
"undo_nothing": "취소할 항목이 없습니다. 자신의 마지막 완료만 10분 안에 취소할 수 있습니다.",
"undo_changed": "취소할 수 없습니다. 그 사이 작업이 변경되었습니다.",
"task_archived": "작업이 보관되었습니다",
"object_archived": "객체가 보관되었습니다",
"unarchive": "보관 해제",
@@ -212,6 +212,7 @@
"completed_at_optional": "Utført den (valgfritt, tomt = nå)",
"completed_at_pick": "Velg dato og klokkeslett",
"completed_at_future_error": "Fullføringsdatoen kan ikke ligge i fremtiden.",
"ha_time_zone_hint": "Tid i Home Assistants tidssone ({zone})",
"days": "dager",
"day": "dag",
"today": "I dag",
@@ -556,7 +557,8 @@
"cal_forward_windows": "Fremtidige vinduer",
"history_edit_title": "Rediger historikkoppføring",
"history_delete_entry": "Slett oppføring",
"history_delete_confirm": "Slette denne historikkoppføringen? Datoen for siste utførelse faller tilbake til den forrige; bilder blir hos objektet, og forbrukte deler legges ikke tilbake på lager.",
"history_delete_confirm_entry": "Slette denne historikkoppføringen? Datoen for siste utførelse faller tilbake til den forrige; bilder blir værende på objektet.",
"history_delete_returns_parts": "De brukte delene går tilbake på lager: {parts}.",
"history_edit_timestamp": "Tidsstempel",
"manufacturer": "Produsent",
"model": "Modell",
@@ -848,6 +850,11 @@
"loading": "Laster…",
"archive": "Arkivér",
"undo": "Angre",
"task_completed_named": "Fullført: {task}",
"undo_done": "Utførelsen angret",
"undo_done_action_ran": "Utførelsen angret. Handlingen ved utførelse hadde allerede kjørt og kan ikke angres.",
"undo_nothing": "Ingenting å angre. Bare din egen siste utførelse kan angres, innen 10 minutter.",
"undo_changed": "Kan ikke angres. Oppgaven er endret siden.",
"task_archived": "Oppgave arkivert",
"object_archived": "Objekt arkivert",
"unarchive": "Gjenopprett",
@@ -210,6 +210,7 @@
"completed_at_optional": "Voltooid op (optioneel, leeg = nu)",
"completed_at_pick": "Datum & tijd kiezen",
"completed_at_future_error": "De voltooiingsdatum mag niet in de toekomst liggen.",
"ha_time_zone_hint": "Tijd in de tijdzone van Home Assistant ({zone})",
"days": "dagen",
"day": "dag",
"today": "Vandaag",
@@ -554,7 +555,8 @@
"cal_forward_windows": "Toekomstige vensters",
"history_edit_title": "Geschiedenisitem bewerken",
"history_delete_entry": "Vermelding verwijderen",
"history_delete_confirm": "Deze geschiedenisvermelding verwijderen? De datum van laatste uitvoering valt terug op de vorige voltooiing; foto's blijven bij het object en verbruikte onderdelen worden niet teruggeboekt.",
"history_delete_confirm_entry": "Deze geschiedenisregel verwijderen? De datum van de laatste uitvoering valt terug op de vorige; foto's blijven bij het object.",
"history_delete_returns_parts": "De gebruikte onderdelen gaan terug naar de voorraad: {parts}.",
"history_edit_timestamp": "Tijdstempel",
"manufacturer": "Fabrikant",
"model": "Model",
@@ -848,6 +850,11 @@
"loading": "Laden…",
"archive": "Archiveren",
"undo": "Ongedaan maken",
"task_completed_named": "Voltooid: {task}",
"undo_done": "Afronding ongedaan gemaakt",
"undo_done_action_ran": "Afronding ongedaan gemaakt. De actie bij afronden was al uitgevoerd en kan niet worden teruggedraaid.",
"undo_nothing": "Niets om ongedaan te maken. Alleen je eigen laatste afronding kan worden teruggedraaid, binnen 10 minuten.",
"undo_changed": "Ongedaan maken kan niet. De taak is sindsdien gewijzigd.",
"task_archived": "Taak gearchiveerd",
"object_archived": "Object gearchiveerd",
"unarchive": "Dearchiveren",
@@ -210,6 +210,7 @@
"completed_at_optional": "Wykonano dnia (opcjonalne, puste = teraz)",
"completed_at_pick": "Ustaw datę i godzinę",
"completed_at_future_error": "Data wykonania nie może być w przyszłości.",
"ha_time_zone_hint": "Czas w strefie czasowej Home Assistant ({zone})",
"days": "dni",
"day": "dzień",
"today": "Dzisiaj",
@@ -554,7 +555,8 @@
"cal_forward_windows": "Przyszłe okna",
"history_edit_title": "Edytuj wpis historii",
"history_delete_entry": "Usuń wpis",
"history_delete_confirm": "Usunąć ten wpis historii? Data ostatniego wykonania cofnie się do poprzedniego; zdjęcia pozostaną przy obiekcie, a zużyte części nie wrócą na stan.",
"history_delete_confirm_entry": "Usunąć ten wpis historii? Data ostatniego wykonania wróci do poprzedniej; zdjęcia zostaną przy obiekcie.",
"history_delete_returns_parts": "Zużyte części wrócą do magazynu: {parts}.",
"history_edit_timestamp": "Znacznik czasu",
"manufacturer": "Producent",
"model": "Model",
@@ -848,6 +850,11 @@
"loading": "Ładowanie…",
"archive": "Archiwizuj",
"undo": "Cofnij",
"task_completed_named": "Wykonano: {task}",
"undo_done": "Wykonanie cofnięte",
"undo_done_action_ran": "Wykonanie cofnięte. Akcja przy wykonaniu już się odbyła i nie da się jej cofnąć.",
"undo_nothing": "Nie ma czego cofnąć. Cofnąć można tylko swoje ostatnie wykonanie, w ciągu 10 minut.",
"undo_changed": "Nie można cofnąć. Zadanie zmieniło się w międzyczasie.",
"task_archived": "Zadanie zarchiwizowane",
"object_archived": "Obiekt zarchiwizowany",
"unarchive": "Przywróć z archiwum",
@@ -212,6 +212,7 @@
"completed_at_optional": "Concluído em (opcional, vazio = agora)",
"completed_at_pick": "Definir data e hora",
"completed_at_future_error": "A data de conclusão não pode estar no futuro.",
"ha_time_zone_hint": "Horário no fuso horário do Home Assistant ({zone})",
"days": "dias",
"day": "dia",
"today": "Hoje",
@@ -556,7 +557,8 @@
"cal_forward_windows": "Janelas futuras",
"history_edit_title": "Editar entrada do histórico",
"history_delete_entry": "Excluir entrada",
"history_delete_confirm": "Excluir esta entrada do histórico? A data da última execução volta para a conclusão anterior; as fotos permanecem com o objeto e as peças consumidas não são repostas.",
"history_delete_confirm_entry": "Excluir esta entrada do histórico? A data da última realização volta para a anterior; as fotos continuam com o objeto.",
"history_delete_returns_parts": "As peças usadas voltam ao estoque: {parts}.",
"history_edit_timestamp": "Data e hora",
"manufacturer": "Fabricante",
"model": "Modelo",
@@ -855,6 +857,11 @@
"loading": "Carregando…",
"archive": "Arquivar",
"undo": "Desfazer",
"task_completed_named": "Concluída: {task}",
"undo_done": "Conclusão desfeita",
"undo_done_action_ran": "Conclusão desfeita. A ação de conclusão já tinha sido executada e não pode ser revertida.",
"undo_nothing": "Nada para desfazer. Só a sua última conclusão pode ser desfeita, em até 10 minutos.",
"undo_changed": "Não é possível desfazer. A tarefa mudou desde então.",
"task_archived": "Tarefa arquivada",
"object_archived": "Objeto arquivado",
"unarchive": "Desarquivar",
@@ -210,6 +210,7 @@
"completed_at_optional": "Concluído em (opcional, vazio = agora)",
"completed_at_pick": "Definir data e hora",
"completed_at_future_error": "A data de conclusão não pode estar no futuro.",
"ha_time_zone_hint": "Hora no fuso horário do Home Assistant ({zone})",
"days": "dias",
"day": "dia",
"today": "Hoje",
@@ -554,7 +555,8 @@
"cal_forward_windows": "Janelas futuras",
"history_edit_title": "Editar entrada do histórico",
"history_delete_entry": "Eliminar entrada",
"history_delete_confirm": "Eliminar esta entrada do histórico? A data da última execução recua para a conclusão anterior; as fotos ficam com o objeto e as peças consumidas não são repostas.",
"history_delete_confirm_entry": "Eliminar esta entrada do histórico? A data da última realização volta à anterior; as fotos ficam com o objeto.",
"history_delete_returns_parts": "As peças usadas voltam ao stock: {parts}.",
"history_edit_timestamp": "Carimbo de data/hora",
"manufacturer": "Fabricante",
"model": "Modelo",
@@ -848,6 +850,11 @@
"loading": "A carregar…",
"archive": "Arquivar",
"undo": "Desfazer",
"task_completed_named": "Concluída: {task}",
"undo_done": "Conclusão anulada",
"undo_done_action_ran": "Conclusão anulada. A ação de conclusão já tinha sido executada e não pode ser revertida.",
"undo_nothing": "Nada para anular. Só a sua última conclusão pode ser anulada, dentro de 10 minutos.",
"undo_changed": "Não é possível anular. A tarefa mudou entretanto.",
"task_archived": "Tarefa arquivada",
"object_archived": "Objeto arquivado",
"unarchive": "Desarquivar",
@@ -210,6 +210,7 @@
"completed_at_optional": "Выполнено (необязательно, пусто = сейчас)",
"completed_at_pick": "Указать дату и время",
"completed_at_future_error": "Дата выполнения не может быть в будущем.",
"ha_time_zone_hint": "Время в часовом поясе Home Assistant ({zone})",
"days": "дней",
"day": "день",
"today": "Сегодня",
@@ -554,7 +555,8 @@
"cal_forward_windows": "Будущие окна",
"history_edit_title": "Редактировать запись истории",
"history_delete_entry": "Удалить запись",
"history_delete_confirm": "Удалить эту запись истории? Дата последнего выполнения вернётся к предыдущему; фотографии останутся у объекта, а израсходованные детали не будут возвращены на склад.",
"history_delete_confirm_entry": "Удалить эту запись истории? Дата последнего выполнения вернётся к предыдущей; фото останутся у объекта.",
"history_delete_returns_parts": "Использованные запчасти вернутся на склад: {parts}.",
"history_edit_timestamp": "Метка времени",
"manufacturer": "Производитель",
"model": "Модель",
@@ -848,6 +850,11 @@
"loading": "Загрузка…",
"archive": "Архивировать",
"undo": "Отменить",
"task_completed_named": "Выполнено: {task}",
"undo_done": "Выполнение отменено",
"undo_done_action_ran": "Выполнение отменено. Действие при выполнении уже сработало, его нельзя отменить.",
"undo_nothing": "Нечего отменять. Можно отменить только своё последнее выполнение, в течение 10 минут.",
"undo_changed": "Отменить нельзя. Задача с тех пор изменилась.",
"task_archived": "Задача архивирована",
"object_archived": "Объект архивирован",
"unarchive": "Разархивировать",
@@ -210,6 +210,7 @@
"completed_at_optional": "Utförd den (valfritt, tomt = nu)",
"completed_at_pick": "Ange datum och tid",
"completed_at_future_error": "Slutförandedatumet får inte ligga i framtiden.",
"ha_time_zone_hint": "Tid i Home Assistants tidszon ({zone})",
"days": "dagar",
"day": "dag",
"today": "Idag",
@@ -554,7 +555,8 @@
"cal_forward_windows": "Kommande fönster",
"history_edit_title": "Redigera historikpost",
"history_delete_entry": "Ta bort post",
"history_delete_confirm": "Ta bort den här historikposten? Datumet för senaste utförande faller tillbaka till det föregående; foton stannar hos objektet och förbrukade delar läggs inte tillbaka i lager.",
"history_delete_confirm_entry": "Ta bort den här historikposten? Datumet för senaste utförandet faller tillbaka på det föregående; foton finns kvar på objektet.",
"history_delete_returns_parts": "De använda delarna går tillbaka till lagret: {parts}.",
"history_edit_timestamp": "Tidsstämpel",
"manufacturer": "Tillverkare",
"model": "Modell",
@@ -848,6 +850,11 @@
"loading": "Laddar…",
"archive": "Arkivera",
"undo": "Ångra",
"task_completed_named": "Slutförd: {task}",
"undo_done": "Utförandet ångrat",
"undo_done_action_ran": "Utförandet ångrat. Åtgärden vid utförande hade redan körts och kan inte ångras.",
"undo_nothing": "Inget att ångra. Bara ditt eget senaste utförande kan ångras, inom 10 minuter.",
"undo_changed": "Kan inte ångras. Uppgiften har ändrats sedan dess.",
"task_archived": "Uppgift arkiverad",
"object_archived": "Objekt arkiverat",
"unarchive": "Återställ",
@@ -212,6 +212,7 @@
"completed_at_optional": "Tamamlanma zamanı (isteğe bağlı, boş = şimdi)",
"completed_at_pick": "Tarih ve saat seç",
"completed_at_future_error": "Tamamlanma tarihi gelecekte olamaz.",
"ha_time_zone_hint": "Home Assistant saat dilimindeki saat ({zone})",
"days": "gün",
"day": "gün",
"today": "Bugün",
@@ -556,7 +557,8 @@
"cal_forward_windows": "Gelecek dönemler",
"history_edit_title": "Geçmiş kaydını düzenle",
"history_delete_entry": "Kaydı sil",
"history_delete_confirm": "Bu geçmiş kaydı silinsin mi? Son yapılma tarihi bir önceki tamamlamaya döner; fotoğraflar nesnede kalır, kullanılan parçalar stoğa geri eklenmez.",
"history_delete_confirm_entry": "Bu geçmiş kaydı silinsin mi? Son yapılma tarihi bir önceki tamamlamaya geri döner; fotoğraflar nesnede kalır.",
"history_delete_returns_parts": "Kullanılan parçalar stoğa geri döner: {parts}.",
"history_edit_timestamp": "Zaman damgası",
"manufacturer": "Üretici",
"model": "Model",
@@ -855,6 +857,11 @@
"loading": "Yükleniyor…",
"archive": "Arşivle",
"undo": "Geri al",
"task_completed_named": "Tamamlandı: {task}",
"undo_done": "Tamamlama geri alındı",
"undo_done_action_ran": "Tamamlama geri alındı. Tamamlama eylemi zaten çalışmıştı ve geri alınamaz.",
"undo_nothing": "Geri alınacak bir şey yok. Yalnızca kendi son tamamlamanızı 10 dakika içinde geri alabilirsiniz.",
"undo_changed": "Geri alınamıyor. Görev o zamandan beri değişti.",
"task_archived": "Görev arşivlendi",
"object_archived": "Nesne arşivlendi",
"unarchive": "Arşivden çıkar",
@@ -210,6 +210,7 @@
"completed_at_optional": "Виконано (необов'язково, порожньо = зараз)",
"completed_at_pick": "Вказати дату й час",
"completed_at_future_error": "Дата виконання не може бути в майбутньому.",
"ha_time_zone_hint": "Час у часовому поясі Home Assistant ({zone})",
"days": "днів",
"day": "день",
"today": "Сьогодні",
@@ -554,7 +555,8 @@
"cal_forward_windows": "Майбутні вікна",
"history_edit_title": "Редагувати запис історії",
"history_delete_entry": "Видалити запис",
"history_delete_confirm": "Видалити цей запис історії? Дата останнього виконання повернеться до попереднього; фотографії залишаться в об'єкта, а витрачені деталі не повернуться на склад.",
"history_delete_confirm_entry": "Видалити цей запис історії? Дата останнього виконання повернеться до попередньої; фото залишаться в об'єкта.",
"history_delete_returns_parts": "Використані запчастини повернуться на склад: {parts}.",
"history_edit_timestamp": "Позначка часу",
"manufacturer": "Виробник",
"model": "Модель",
@@ -848,6 +850,11 @@
"loading": "Завантаження…",
"archive": "Архівувати",
"undo": "Скасувати",
"task_completed_named": "Виконано: {task}",
"undo_done": "Виконання скасовано",
"undo_done_action_ran": "Виконання скасовано. Дія під час виконання вже спрацювала, її не можна скасувати.",
"undo_nothing": "Нічого скасовувати. Можна скасувати лише своє останнє виконання, протягом 10 хвилин.",
"undo_changed": "Скасувати не можна. Завдання відтоді змінилося.",
"task_archived": "Завдання архівовано",
"object_archived": "Об'єкт архівовано",
"unarchive": "Розархівувати",
@@ -212,6 +212,7 @@
"completed_at_optional": "完成时间(可选,留空 = 现在)",
"completed_at_pick": "设置日期和时间",
"completed_at_future_error": "完成日期不能是未来时间。",
"ha_time_zone_hint": "Home Assistant 时区的时间({zone})",
"days": "天",
"day": "天",
"today": "今天",
@@ -556,7 +557,8 @@
"cal_forward_windows": "未来的窗口",
"history_edit_title": "编辑历史记录",
"history_delete_entry": "删除记录",
"history_delete_confirm": "删除此历史记录?上次完成日期将回退到前一次完成;照片仍保留在对象中,已消耗的配件不会退回库存。",
"history_delete_confirm_entry": "删除此历史记录?上次执行日期将退回到上一次完成;照片仍保留在对象中。",
"history_delete_returns_parts": "所用的配件将退回库存:{parts}。",
"history_edit_timestamp": "时间戳",
"manufacturer": "制造商",
"model": "型号",
@@ -848,6 +850,11 @@
"loading": "加载中…",
"archive": "归档",
"undo": "撤销",
"task_completed_named": "已完成:{task}",
"undo_done": "已撤销完成",
"undo_done_action_ran": "已撤销完成。完成时的操作已经执行,无法撤销。",
"undo_nothing": "没有可撤销的内容。只能在 10 分钟内撤销你自己最近一次完成。",
"undo_changed": "无法撤销。此后任务已发生变化。",
"task_archived": "任务已归档",
"object_archived": "对象已归档",
"unarchive": "取消归档",
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1,2 +1,2 @@
/*! maintenance_supporter frontend 2.97.1 */
var v="2.97.1";var f="maintenance-supporter",L=`ll-strategy-dashboard-${f}`,C="hui-maintenance-supporter-strategy-editor",M=["maintenance-supporter-section","maintenance-supporter-vacation","maintenance-supporter-budget","maintenance-supporter-groups"],D=`/maintenance_supporter_strategy/maintenance-dashboard-strategy.js?v=${v}`,w=null;function h(){return w||(w=import(D)),w}async function I(){let e=await h();if(!e.MaintenanceDashboardStrategy)throw new Error("[maintenance-supporter] strategy bundle loaded but did not export MaintenanceDashboardStrategy");return e.MaintenanceDashboardStrategy}async function P(e){let i=(await h()).SECTION_STRATEGIES?.[e];if(!i)throw new Error(`[maintenance-supporter] strategy bundle loaded but has no section strategy "${e}"`);return i}function B(e){return class extends HTMLElement{static async generate(i,l){return(await P(e)).generate(i,l)}}}var y=class extends HTMLElement{static getCreateSuggestions(s){return{title:"Maintenance Supporter",icon:"mdi:wrench-clock"}}static async getConfigElement(){return await h(),document.createElement(C)}static async generate(s,i){return(await I()).generate(s,i)}};function O(){try{customElements.define(L,y)}catch{}for(let e of M)try{customElements.define(`ll-strategy-section-${e}`,B(e))}catch{}}O();var m=window;m.customStrategies=m.customStrategies||[];var U=[{type:f,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentationURL:"https://github.com/iluebbe/maintenance_supporter/blob/master/docs/EXAMPLES.md#dashboard-strategy"},{type:"maintenance-supporter-section",strategyType:"section",name:"Maintenance Supporter \u2014 Section",description:"Embed maintenance tasks (filterable by area, status, due date) as a section in any dashboard view.",documentationURL:"https://github.com/iluebbe/maintenance_supporter/blob/master/docs/EXAMPLES.md#section-strategy"},{type:"maintenance-supporter-vacation",strategyType:"section",name:"Maintenance Supporter \u2014 Vacation Status",description:"Compact vacation-mode status banner. Tap to open settings in the panel."},{type:"maintenance-supporter-budget",strategyType:"section",name:"Maintenance Supporter \u2014 Budget Status",description:"Monthly + yearly maintenance budget overview. Tap for details."},{type:"maintenance-supporter-groups",strategyType:"section",name:"Maintenance Supporter \u2014 Groups",description:"List of configured task groups with member counts."}];for(let e of U)m.customStrategies.some(s=>s.type===e.type&&s.strategyType===e.strategyType)||m.customStrategies.push(e);(()=>{let e=window;if(e.__msStrategyHealActive)return;e.__msStrategyHealActive=!0;let s=/^\/(auth|config|developer-tools|profile|hassio|history|logbook|map|media-browser|energy|todo|calendar)\b/,i=/Timeout waiting for strategy element ll-strategy-(dashboard-)?maintenance-supporter/i,l=`custom:${f}`;function S(r){let t=[document.documentElement],a=0;for(;t.length&&a<9e3;){let o=t.pop();if(a++,!o)continue;let n=o;if(n.nodeType===1&&n.tagName&&n.tagName.toLowerCase()===r)return n;n.shadowRoot&&t.push(n.shadowRoot);let u=o.children;if(u)for(let p of Array.from(u))t.push(p)}return null}function R(r){let t=r?.views;if(!Array.isArray(t)||!t.length)return null;let a=window.location.pathname.split("/").filter(Boolean).pop()||"",o=t.find(u=>u?.path===a);if(o)return o;let n=Number(a);return Number.isInteger(n)&&t[n]?t[n]:t[0]}function k(){try{let t=S("ha-panel-lovelace")?.lovelace;if(!t)return!1;let a=o=>o?.type;for(let o of[t.config,t.rawConfig]){if(!o)continue;if(a(o.strategy)===l)return!0;let n=R(o);if(n&&a(n.strategy)===l)return!0}return!1}catch{return!1}}function T(){let r=!1,t=0,a=!1,o=!1,n=[document.documentElement],u=0;for(;n.length&&u<9e3;){let p=n.pop();if(u++,!p)continue;let d=p;if(d.nodeType===1&&d.tagName){let c=d.tagName.toLowerCase();(c==="hui-view"||c==="hui-sections-view")&&(r=!0),(c==="ha-card"||c==="hui-card")&&t++,c==="hui-empty-state-card"&&(o=!0),c==="hui-error-card"&&i.test(d.textContent||"")&&(a=!0)}d.shadowRoot&&n.push(d.shadowRoot);let _=p.children;if(_)for(let c of Array.from(_))n.push(c)}return a?!0:o?!1:r&&t<3&&k()}let N="/maintenance_supporter_strategy_shim.js",E=0,b=0;function A(){let r=Date.now();r-b<5e3||E>=3||(b=r,E+=1,import(`${N}?heal=${r}`).catch(()=>{}).finally(()=>{let t=window.location.pathname+window.location.search;history.pushState(null,"","/lovelace"),window.dispatchEvent(new CustomEvent("location-changed")),window.setTimeout(()=>{history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed"))},200)}))}function g(){if(s.test(window.location.pathname))return;let r=0,t=Date.now(),a=window.setInterval(()=>{r++;try{if(Date.now()-t<6e3)return;if(s.test(window.location.pathname)){window.clearInterval(a);return}T()?A():window.clearInterval(a),r>=30&&window.clearInterval(a)}catch{window.clearInterval(a)}},500)}try{document.readyState==="loLine truncated
/*! maintenance_supporter frontend 2.98.0 */
var v="2.98.0";var f="maintenance-supporter",L=`ll-strategy-dashboard-${f}`,C="hui-maintenance-supporter-strategy-editor",M=["maintenance-supporter-section","maintenance-supporter-vacation","maintenance-supporter-budget","maintenance-supporter-groups"],D=`/maintenance_supporter_strategy/maintenance-dashboard-strategy.js?v=${v}`,w=null;function h(){return w||(w=import(D)),w}async function I(){let e=await h();if(!e.MaintenanceDashboardStrategy)throw new Error("[maintenance-supporter] strategy bundle loaded but did not export MaintenanceDashboardStrategy");return e.MaintenanceDashboardStrategy}async function P(e){let i=(await h()).SECTION_STRATEGIES?.[e];if(!i)throw new Error(`[maintenance-supporter] strategy bundle loaded but has no section strategy "${e}"`);return i}function B(e){return class extends HTMLElement{static async generate(i,l){return(await P(e)).generate(i,l)}}}var y=class extends HTMLElement{static getCreateSuggestions(s){return{title:"Maintenance Supporter",icon:"mdi:wrench-clock"}}static async getConfigElement(){return await h(),document.createElement(C)}static async generate(s,i){return(await I()).generate(s,i)}};function O(){try{customElements.define(L,y)}catch{}for(let e of M)try{customElements.define(`ll-strategy-section-${e}`,B(e))}catch{}}O();var m=window;m.customStrategies=m.customStrategies||[];var U=[{type:f,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentationURL:"https://github.com/iluebbe/maintenance_supporter/blob/master/docs/EXAMPLES.md#dashboard-strategy"},{type:"maintenance-supporter-section",strategyType:"section",name:"Maintenance Supporter \u2014 Section",description:"Embed maintenance tasks (filterable by area, status, due date) as a section in any dashboard view.",documentationURL:"https://github.com/iluebbe/maintenance_supporter/blob/master/docs/EXAMPLES.md#section-strategy"},{type:"maintenance-supporter-vacation",strategyType:"section",name:"Maintenance Supporter \u2014 Vacation Status",description:"Compact vacation-mode status banner. Tap to open settings in the panel."},{type:"maintenance-supporter-budget",strategyType:"section",name:"Maintenance Supporter \u2014 Budget Status",description:"Monthly + yearly maintenance budget overview. Tap for details."},{type:"maintenance-supporter-groups",strategyType:"section",name:"Maintenance Supporter \u2014 Groups",description:"List of configured task groups with member counts."}];for(let e of U)m.customStrategies.some(s=>s.type===e.type&&s.strategyType===e.strategyType)||m.customStrategies.push(e);(()=>{let e=window;if(e.__msStrategyHealActive)return;e.__msStrategyHealActive=!0;let s=/^\/(auth|config|developer-tools|profile|hassio|history|logbook|map|media-browser|energy|todo|calendar)\b/,i=/Timeout waiting for strategy element ll-strategy-(dashboard-)?maintenance-supporter/i,l=`custom:${f}`;function S(r){let t=[document.documentElement],a=0;for(;t.length&&a<9e3;){let o=t.pop();if(a++,!o)continue;let n=o;if(n.nodeType===1&&n.tagName&&n.tagName.toLowerCase()===r)return n;n.shadowRoot&&t.push(n.shadowRoot);let u=o.children;if(u)for(let p of Array.from(u))t.push(p)}return null}function R(r){let t=r?.views;if(!Array.isArray(t)||!t.length)return null;let a=window.location.pathname.split("/").filter(Boolean).pop()||"",o=t.find(u=>u?.path===a);if(o)return o;let n=Number(a);return Number.isInteger(n)&&t[n]?t[n]:t[0]}function k(){try{let t=S("ha-panel-lovelace")?.lovelace;if(!t)return!1;let a=o=>o?.type;for(let o of[t.config,t.rawConfig]){if(!o)continue;if(a(o.strategy)===l)return!0;let n=R(o);if(n&&a(n.strategy)===l)return!0}return!1}catch{return!1}}function T(){let r=!1,t=0,a=!1,o=!1,n=[document.documentElement],u=0;for(;n.length&&u<9e3;){let p=n.pop();if(u++,!p)continue;let d=p;if(d.nodeType===1&&d.tagName){let c=d.tagName.toLowerCase();(c==="hui-view"||c==="hui-sections-view")&&(r=!0),(c==="ha-card"||c==="hui-card")&&t++,c==="hui-empty-state-card"&&(o=!0),c==="hui-error-card"&&i.test(d.textContent||"")&&(a=!0)}d.shadowRoot&&n.push(d.shadowRoot);let _=p.children;if(_)for(let c of Array.from(_))n.push(c)}return a?!0:o?!1:r&&t<3&&k()}let N="/maintenance_supporter_strategy_shim.js",E=0,b=0;function A(){let r=Date.now();r-b<5e3||E>=3||(b=r,E+=1,import(`${N}?heal=${r}`).catch(()=>{}).finally(()=>{let t=window.location.pathname+window.location.search;history.pushState(null,"","/lovelace"),window.dispatchEvent(new CustomEvent("location-changed")),window.setTimeout(()=>{history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed"))},200)}))}function g(){if(s.test(window.location.pathname))return;let r=0,t=Date.now(),a=window.setInterval(()=>{r++;try{if(Date.now()-t<6e3)return;if(s.test(window.location.pathname)){window.clearInterval(a);return}T()?A():window.clearInterval(a),r>=30&&window.clearInterval(a)}catch{window.clearInterval(a)}},500)}try{document.readyState==="loLine truncated
@@ -0,0 +1,301 @@
/*! maintenance_supporter frontend 2.98.0 */
import{e as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-FFPNBBZ6.js";import{d as m}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-QFIANZWP.js";import{a as h}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-MN2RZ73S.js";import{H as b,a as o,b as u,c as n,f as l,h as v,l as g,m as d,s as r,u as f}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var a=class extends v{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._adopting=!1;this._error="";this._sensors=[];this._selected=new Set;this._objectNames={};this._objects=[];this._covered={};this._users=[];this._responsible="";this._forMinutes="0";this._localeReady=!1;this._userService=null;this._toggle=t=>{let i=new Set(this._selected);i.has(t)?i.delete(t):i.add(t),this._selected=i};this._toggleAll=()=>{this._selected.size===this._sensors.length?this._selected=new Set:this._selected=new Set(this._sensors.map(t=>t.entity_id))};this._adopt=async()=>{if(this._selected.size===0||this._adopting)return;this._error="";let t=this._sensors.filter(e=>this._selected.has(e.entity_id)).map(e=>({entity_id:e.entity_id,name:e.name,entry_id:this._existingEntryFor(e)??void 0,object_name:this._effectiveName(e),device_id:e.device_id??void 0,part_id:e.suggested_part_id??void 0,responsible_user_id:this._responsible||void 0,for_minutes:parseInt(this._forMinutes,10)>0?parseInt(this._forMinutes,10):void 0})),i=await h(this,{type:"maintenance_supporter/problem_sensors/adopt",selections:t},{busy:e=>{this._adopting=e},onError:e=>{this._error=e}});i!==void 0&&(this.dispatchEvent(new CustomEvent("problem-sensors-adopted",{bubbles:!0,composed:!0,detail:i})),this._open=!1)}}get _lang(){return b(this.hass)}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,f(this._lang).then(()=>this.requestUpdate()))}async open(){this._open=!0,this._loading=!0,this._error="",this._sensors=[],this._selected=new Set,this._objectNames={},this._responsible="",this._forMinutes="0",this._userService?this._userService.updateHass(this.hass):this._userService=new y(this.hass);let[t,i,e]=await Promise.all([h(this,{type:"maintenance_supporter/problem_sensors/discover"},{onError:s=>{this._error=s}}),this._userService.getUsers().catch(()=>[]),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}).catch(()=>({objects:[]}))]);this._loading=!1,t!==void 0&&(this._objects=(e?.objects||[]).filter(s=>!s.object.archived_at).map(s=>({entry_id:s.entry_id,name:s.object.name,tasks:(s.tasks||[]).length})),this._sensors=t?.sensors||[],this._covered=Object.fromEntries(this._sensors.map(s=>[s.entity_id,s.covered_by??null])),this._selected=new Set(this._sensors.filter(s=>!s.covered_by).map(s=>s.entity_id)),this._users=i)}_defaultName(t){return t.suggested_entry_id?t.suggested_object_name:t.candidate?.name??t.suggested_object_name}_effectiveName(t){return(this._objectNames[t.entity_id]??"").trim()||this._defaultName(t)}_existingEntryFor(t){let i=this._effectiveName(t),e=t.suggested_entry_id||t.target_entry_id||null;if(i===this._defaultName(t)&&e)return e;let s=this._objects.find(c=>c.name.trim().toLowerCase()===i.toLowerCase());return s?s.entry_id:null}_schedulePreview(){clearTimeout(this._previewTimer),this._previewTimer=setTimeout(()=>{this._preview()},350)}async _preview(){let t=this._sensors.map(e=>({entity_id:e.entity_id,name:e.name,entry_id:this._existingEntryFor(e)})),i=await h(this,{type:"maintenance_supporter/problem_sensors/preview",selections:t},{onError:()=>{}});i?.covered&&(this._covered={...this._covered,...i.covered})}_summary(t){let i=new Map;for(let e of this._sensors){if(!this._selected.has(e.entity_id))continue;let s=this._existingEntryFor(e),c=this._effectiveName(e),_=s??`new:${c.toLowerCase()}`,p=i.get(_)??{name:c,entry:s,adding:0};p.adding+=1,i.set(_,p)}return i.size===0?l:n`
<div class="summary">
<div class="summary-title">${r("adopt_summary_title",t)}</div>
${[...i.values()].map(e=>{if(!e.entry)return n`<div class="summary-line new">
${r("setups_new_object_count",t).replace("{name}",e.name).replace("{count}",String(e.adding))}
</div>`;let s=this._objects.find(c=>c.entry_id===e.entry)?.tasks??0;return n`<div class="summary-line">
${r("adopt_summary_existing",t).replace("{name}",e.name).replace("{before}",String(s)).replace("{after}",String(s+e.adding))}
</div>`})}
</div>
`}_close(){clearTimeout(this._previewTimer),this._open=!1}_targetLabel(t,i){if(t.candidate&&this._existingEntryFor(t)===t.candidate.entry_id){let e=t.candidate.reasons.map(s=>r(`setups_reason_${s}`,i)).join(", ");return r("setups_target_match",i).replace("{name}",t.candidate.name).replace("{reasons}",e)}return this._effectiveName(t)}render(){if(!this._open)return n``;let t=this._lang,i=this._sensors.length>0&&this._selected.size===this._sensors.length;return n`
<div class="overlay" @click=${this._close}>
<div class="card" @click=${e=>e.stopPropagation()}>
<div class="title">${r("adopt_problem_title",t)}</div>
<div class="hint">${r("adopt_problem_hint",t)}</div>
${this._error?n`<div class="error">${this._error}</div>`:l}
${this._loading?n`<div class="loading">…</div>`:this._sensors.length===0?n`<div class="empty">${r("adopt_problem_none",t)}</div>`:n`
<label class="select-all">
<input
type="checkbox"
.checked=${i}
@change=${this._toggleAll}
/>
<span>${r("selected",t)}: ${this._selected.size} / ${this._sensors.length}</span>
</label>
<div class="row-sub adopt-object-hint">${r("adopt_object_hint",t)}</div>
<datalist id="adopt-object-names">
${this._objects.map(e=>n`<option value=${e.name}></option>`)}
</datalist>
<div class="list">
${this._sensors.map(e=>{let s=this._selected.has(e.entity_id),c=e.state==="on",_=[e.device_name,e.area_name].filter(Boolean).join(" \xB7 ");return n`
<label class="row">
<input
type="checkbox"
.checked=${s}
@change=${()=>this._toggle(e.entity_id)}
/>
<div class="row-main">
<div class="row-top">
<span class="row-name">${e.name}</span>
<span class="chip ${c?"chip-active":"chip-ok"}">
${c?r("adopt_problem_active",t):r("adopt_problem_ok",t)}
</span>
</div>
${_?n`<div class="row-sub">${_}</div>`:l}
${s?n`<div class="row-object" @click=${p=>p.stopPropagation()}>
<input
class="adopt-object"
list="adopt-object-names"
aria-label=${r("object",t)}
placeholder=${this._defaultName(e)}
.value=${this._objectNames[e.entity_id]??this._defaultName(e)}
@input=${p=>{this._objectNames={...this._objectNames,[e.entity_id]:p.target.value},this._schedulePreview()}}
/>
</div>`:l}
<div class="row-target">
→ ${this._targetLabel(e,t)}${this._existingEntryFor(e)?l:n` <span class="new-tag">${r("adopt_problem_new_object",t)}</span>`}
</div>
${this._covered[e.entity_id]?n`<div class="maybe">
${r("setups_maybe_covered",t).replace("{name}",this._covered[e.entity_id].name)}
</div>`:l}
${e.suggested_part_name?n`<div class="row-part">
<ha-icon icon="mdi:package-variant-closed"></ha-icon>
${r("adopt_problem_part",t).replace("{name}",e.suggested_part_name)}
</div>`:l}
</div>
</label>
`})}
</div>
`}
${!this._loading&&this._sensors.length>0?this._summary(t):l}
${!this._loading&&this._sensors.length>0?n`
<label class="responsible">
<span>${r("for_at_least_minutes",t)}</span>
<input
class="for-input"
type="number"
min=${m[0]}
max=${m[1]}
.value=${this._forMinutes}
@input=${e=>this._forMinutes=e.target.value}
/>
</label>
<div class="for-hint">${r("adopt_for_minutes_hint",t)}</div>
`:l}
${!this._loading&&this._sensors.length>0&&this._users.length>0?n`
<label class="responsible">
<span>${r("adopt_problem_responsible",t)}</span>
<select
.value=${this._responsible}
@change=${e=>{this._responsible=e.target.value}}
>
<option value="" ?selected=${!this._responsible}>${r("no_user_assigned",t)}</option>
${this._users.map(e=>n`<option value=${e.id} ?selected=${e.id===this._responsible}>${e.name}</option>`)}
</select>
</label>
`:l}
<div class="actions">
<ha-button appearance="plain" @click=${this._close}>
${r("cancel",t)}
</ha-button>
<ha-button
@click=${this._adopt}
.disabled=${this._selected.size===0||this._adopting}
>
${r("adopt_problem_adopt",t)}
</ha-button>
</div>
</div>
</div>
`}};a.styles=u`
.overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.card {
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
border-radius: 12px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 12px;
min-width: min(360px, calc(100vw - 24px));
max-width: 560px;
width: 90vw;
max-height: 80vh;
overflow: hidden;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}
.title {
font-size: 18px;
font-weight: 500;
}
.hint {
color: var(--secondary-text-color);
font-size: 13px;
}
.error {
color: var(--error-color, #f44336);
font-size: 13px;
}
.loading,
.empty {
color: var(--secondary-text-color);
font-size: 14px;
padding: 12px 0;
}
.select-all {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: var(--secondary-text-color);
cursor: pointer;
}
.select-all input {
cursor: pointer;
}
.list {
display: flex;
flex-direction: column;
gap: 6px;
overflow-y: auto;
max-height: 50vh;
}
.row {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 8px;
border: 1px solid var(--divider-color);
border-radius: 6px;
cursor: pointer;
}
.row input {
margin-top: 2px;
cursor: pointer;
}
.row-main {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
flex: 1;
}
.row-top {
display: flex;
align-items: center;
gap: 8px;
}
.row-name {
font-weight: 500;
font-size: 13px;
}
.row-sub {
color: var(--secondary-text-color);
font-size: 12px;
}
.row-object { margin-top: 6px; }
.row-object input {
width: 100%; box-sizing: border-box; padding: 6px 8px; font: inherit;
border: 1px solid var(--divider-color); border-radius: 6px;
background: var(--card-background-color); color: var(--primary-text-color);
}
.adopt-object-hint { margin: 0 0 8px; }
.row-target {
color: var(--secondary-text-color);
font-size: 12px;
}
.row-part {
color: var(--secondary-text-color);
font-size: 12px;
display: flex;
align-items: center;
gap: 4px;
}
.row-part ha-icon {
--mdc-icon-size: 14px;
}
.new-tag {
font-style: italic;
}
.maybe {
font-size: 11px;
color: var(--warning-color, #ff9800);
}
.summary {
font-size: 12px;
border-top: 1px dashed var(--divider-color);
padding-top: 6px;
}
.summary-title {
font-weight: 500;
margin-bottom: 2px;
}
.summary-line {
color: var(--primary-color);
}
.chip {
font-size: 11px;
padding: 1px 8px;
border-radius: 10px;
white-space: nowrap;
}
.chip-active {
background: var(--error-color, #f44336);
color: #fff;
}
.chip-ok {
background: var(--divider-color);
color: var(--secondary-text-color);
}
.responsible {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: var(--secondary-text-color);
flex-wrap: wrap;
}
.for-input {
width: 70px;
background: var(--card-background-color);
color: var(--primary-text-color);
border: 1px solid var(--divider-color);
border-radius: 4px;
padding: 4px 6px;
}
.for-hint {
font-size: 11px;
color: var(--secondary-text-color);
margin: -4px 0 2px;
}
.responsible select {
flex: 1;
min-width: 140px;
padding: 4px 6px;
border-radius: 4px;
border: 1px solid var(--divider-color);
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
font-size: 13px;
}
.actions {
display: flex;
justify-content: flex-end;
gap: 8px;
padding-top: 8px;
}
`,o([g({attribute:!1})],a.prototype,"hass",2),o([d()],a.prototype,"_open",2),o([d()],a.prototype,"_loading",2),o([d()],a.prototype,"_adopting",2),o([d()],a.prototype,"_error",2),o([d()],a.prototype,"_sensors",2),o([d()],a.prototype,"_selected",2),o([d()],a.prototype,"_objectNames",2),o([d()],a.prototype,"_objects",2),o([d()],a.prototype,"_covered",2),o([d()],a.prototype,"_users",2),o([d()],a.prototype,"_responsible",2),o([d()],a.prototype,"_forMinutes",2);customElements.get("maintenance-adopt-problem-sensors-dialog")||customElements.define("maintenance-adopt-problem-sensors-dialog",a);export{a as MaintenanceAdoptProblemSensorsDialog};
@@ -0,0 +1,279 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as X}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WH65ZHYZ.js";import{a as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DY5FF6TM.js";import{f as E,g as M,h as z,i as Q,j as U,k as Y,l as q,m as G,n as R,o as A,p as W}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-S7XZBRRU.js";import{a as B}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GGO5IKKD.js";import{e as P,f as K}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DLWOWMV7.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-4PKMHUVO.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-NEWWPCTD.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-QKEXGIRG.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-OUHDI2FL.js";import{B as S,H as F,K as g,L as v,O as N,P as I,T as w,V as T,a as $,c as p,f as y,h as H,l as k,m as j,n as C,q as D,s as a,u as L,y as O}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";function J(b,i,t,s){let l=b.entries.filter(e=>e.type==="completed").sort((e,n)=>e.ts-n.ts),d=`${b.from?t.date(b.from):"\u2026"} \u2013 ${b.to?t.date(b.to):"\u2026"}`,r=b.totals,h=[[i.completions,t.number(r.completions)],[i.totalCost,t.cost(r.totalCost)],[i.avgCost,r.avgCost!=null?t.cost(r.avgCost):i.none],[i.totalTime,r.totalDuration?t.duration(r.totalDuration):i.none]].map(([e,n])=>`<div class="kpi"><div class="k">${o(e)}</div><div class="v">${o(n)}</div></div>`).join(""),u=b.byObject.map(e=>`<tr>
<td>${o(e.objectName)}</td>
<td class="num">${o(t.number(e.completions))}</td>
<td class="num">${o(t.cost(e.cost))}</td>
<td class="num">${o(t.share(e.share))}</td>
</tr>`).join(""),f=b.buckets.buckets.reduce((e,n)=>Math.max(e,n.cost),0),c=b.buckets.buckets.map(e=>{let n=f>0?Math.round(e.cost/f*100):0;return`<tr>
<td class="nowrap">${o(t.bucket(e))}</td>
<td class="num">${o(t.number(e.completions))}</td>
<td class="bar-cell">${n>0?`<span class="bar" style="width:${n}%"></span>`:""}</td>
<td class="num">${o(t.cost(e.cost))}</td>
</tr>`}).join(""),m=l.map(e=>{let n=[e.notes,e.completedBy?`${i.completedBy}: ${e.completedBy}`:null].filter(Boolean).join(" \xB7 "),x=e.phaseName?`${e.taskName} \xB7 ${e.phaseName}`:e.taskName;return`<tr>
<td class="nowrap">${o(t.date(e.timestamp))}</td>
<td>${o(e.objectName)}</td>
<td>${o(x)}</td>
<td class="num">${e.cost!=null?o(t.cost(e.cost)):o(i.none)}</td>
<td class="num">${e.duration!=null?o(t.duration(e.duration)):o(i.none)}</td>
<td class="notes">${o(n)||o(i.none)}</td>
</tr>`}).join(`
`);return`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light">
<title>${o(i.title)} \u2014 ${o(b.areaName)}</title>
<style>
/* Printable sheet: it opens as a blob in whatever viewer the OS supplies
(Companion = WebView, dark phones paint a dark default canvas), so the
document states its own light scheme and paints its background. */
:root { color-scheme: light; }
* { box-sizing: border-box; }
body { font: 13px/1.5 -apple-system, Segoe UI, Roboto, sans-serif; color: #1a1a1a; background: #fff; margin: 32px; }
h1 { font-size: 22px; margin: 0 0 2px; }
h2 { font-size: 15px; margin: 24px 0 8px; }
.sub { color: #666; margin: 0 0 16px; }
.kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin: 0 0 8px; }
.kpi { border: 1px solid #ddd; border-radius: 6px; padding: 8px 10px; }
.kpi .k { color: #777; font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; }
.kpi .v { font-size: 16px; font-weight: 600; }
table { border-collapse: collapse; width: 100%; }
th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: #666; border-bottom: 2px solid #ccc; padding: 6px 8px; }
td { border-bottom: 1px solid #e5e5e5; padding: 6px 8px; vertical-align: top; }
td.num, th.num { text-align: right; white-space: nowrap; }
td.nowrap { white-space: nowrap; }
td.notes { color: #444; white-space: pre-wrap; }
td.bar-cell { width: 40%; vertical-align: middle; }
.bar { display: block; height: 10px; background: #9aa7b8; border-radius: 0 3px 3px 0;
-webkit-print-color-adjust: exact; print-color-adjust: exact; }
tfoot td { border-bottom: none; border-top: 2px solid #ccc; font-weight: 600; }
tr { break-inside: avoid; }
.cap-note { margin-top: 14px; color: #888; font-size: 11px; }
@media print { body { margin: 12mm; } }
</style>
</head>
<body>
<h1>${o(i.title)} \u2014 ${o(b.areaName)}</h1>
<p class="sub">${o(i.period)}: ${o(d)} \xB7 ${o(i.generated)} ${o(t.date(s))}</p>
<div class="kpis">${h}</div>
<h2>${o(i.costPerObject)}</h2>
<table>
<thead><tr>
<th>${o(i.colObject)}</th><th class="num">${o(i.completions)}</th>
<th class="num">${o(i.colCost)}</th><th class="num">${o(i.share)}</th>
</tr></thead>
<tbody>${u||`<tr><td colspan="4">${o(i.none)}</td></tr>`}</tbody>
<tfoot><tr>
<td>${o(i.totalCost)}</td><td class="num">${o(t.number(r.completions))}</td>
<td class="num">${o(t.cost(r.totalCost))}</td><td></td>
</tr></tfoot>
</table>
<h2>${o(i.costPerBucket)}</h2>
<table>
<thead><tr>
<th>${o(i.period)}</th><th class="num">${o(i.completions)}</th>
<th></th><th class="num">${o(i.colCost)}</th>
</tr></thead>
<tbody>${c||`<tr><td colspan="4">${o(i.none)}</td></tr>`}</tbody>
</table>
<h2>${o(i.historyHeading)} (${o(t.number(l.length))})</h2>
<table>
<thead><tr>
<th>${o(i.colDate)}</th><th>${o(i.colObject)}</th><th>${o(i.colTask)}</th>
<th class="num">${o(i.colCost)}</th><th class="num">${o(i.colDuration)}</th><th>${o(i.colNotes)}</th>
</tr></thead>
<tbody>
${m||`<tr><td colspan="6">${o(i.none)}</td></tr>`}
</tbody>
<tfoot><tr>
<td colspan="3">${o(i.totalCost)}</td>
<td class="num">${o(t.cost(r.totalCost))}</td>
<td class="num">${r.totalDuration?o(t.duration(r.totalDuration)):""}</td><td></td>
</tr></tfoot>
</table>
${b.capped?`<p class="cap-note">${o(i.capNote)}</p>`:""}
</body>
</html>`}var Z=25,V=5,tt={completed:C.ok,missed:C.overdue,reset:C.paused,skipped:"var(--secondary-text-color)"},_=class extends H{constructor(){super(...arguments);this.areaKey="";this.objects=[];this.showArchived=!1;this.currencySymbol="";this.userName=()=>null;this._from="";this._to="";this._entryFilter="";this._taskQuery="";this._expanded=!1;this._printing=!1;this._histories=new X(this);this._localeReady=!1;this._filtersFor=null;this._memo=null}createRenderRoot(){return this}get _lang(){return F(this.hass)}willUpdate(t){if(super.willUpdate(t),t.has("areaKey")&&this._filtersFor!==this.areaKey){this._filtersFor=this.areaKey;let s=R();this._from=s.from,this._to=s.to,this._entryFilter="",this._taskQuery="",this._expanded=!1}if(t.has("objects")||t.has("areaKey")||t.has("showArchived")||t.has("hass")&&t.get("hass")===void 0){let s=this._areaObjects().flatMap(l=>l.tasks.map(d=>({entryId:l.entry_id,task:d})));this._histories.sync(this.hass,s)}}updated(t){super.updated(t),!this._localeReady&&this.hass&&(this._localeReady=!0,L(this._lang).then(()=>this.requestUpdate()))}_areaObjects(){return z(this.objects,this.areaKey,this.showArchived).sort((t,s)=>t.object.name.localeCompare(s.object.name))}_entries(t){let s=[this.objects,this.areaKey,this.showArchived,this._histories.version];if(this._memo&&this._memo.deps.every((d,r)=>d===s[r]))return this._memo.entries;let l=Q(t,(d,r)=>this._histories.historyOf(d,r));return this._memo={deps:s,entries:l},l}_figures(){let t=this._areaObjects(),s=this._entries(t),l={from:this._from||null,to:this._to||null},d=U(s,{...l,entryId:this._entryFilter||null,taskQuery:this._taskQuery}),r=this._entryFilter?t.filter(h=>h.entry_id===this._entryFilter):t;return{objects:t,entries:s,filtered:d,totals:Y(d),buckets:G(d,l),byObject:q(d,r)}}_setRange(t){this._from=t.from,this._to=t.to,this._expanded=!1}_openObject(t){this.dispatchEvent(new CustomEvent("open-object",{detail:{entryId:t},bubbles:!0,composed:!0}))}_openTask(t,s){this.dispatchEvent(new CustomEvent("open-task",{detail:{entryId:t,taskId:s},bubbles:!0,composed:!0}))}_bucketLabel(t,s){return t.month==null?String(t.year):`${T(t.month,this._lang,s)} ${t.year}`}_countText(t,s,l){let d=this._lang;return l===1?a(s,d):a(t,d).replace("{n}",g(l,d))}async _print(){if(this._printing)return;let t=K();this._printing=!0;try{await this._histories.settled()}finally{this._printing=!1}let s=this._lang,l=this.currencySymbol,{filtered:d,totals:r,buckets:h,byObject:u}=this._figures(),f={title:a("area_report_title",s),generated:a("report_generated",s),period:a("area_report_period",s),completions:a("area_kpi_completions",s),totalCost:a("total_cost",s),avgCost:a("avg_cost",s),totalTime:a("area_kpi_total_time",s),costPerObject:a("area_cost_per_object",s),costPerBucket:h.unit==="month"?a("area_cost_per_month",s):a("area_cost_per_year",s),share:a("area_cost_share",s),historyHeading:a("area_history_section",s),colDate:a("date",s),colObject:a("object",s),colTask:a("task_name",s),colCost:a("cost",s),colDuration:a("duration",s),colNotes:a("notes_label",s),completedBy:a("completed_by",s),capNote:a("object_history_cap_note",s),none:"\u2014"},c=d.filter(n=>n.type==="completed"),m=d.map(n=>({...n,completedBy:n.completedBy?this.userName(n.completedBy):null,notes:n.notes?B(n.notes,s):null})),e=J({areaName:E(this.areaKey,this.hass?.areas,a("no_area",s)),from:this._from||S(c[c.length-1]?.timestamp)||null,to:this._to||O(),totals:r,byObject:u,buckets:h,entries:m,capped:this._histories.capped},f,{date:n=>N(n,s),cost:n=>v(n,l,s),duration:n=>w(n,s),bucket:n=>this._bucketLabel(n,"long"),share:n=>`${g(n*100,s,0)} %`,number:n=>g(n,s)},new Date().toISOString());P(e,t)}_renderRangeChips(t){let s=this._lang,l=O(),d=R(l),r=u=>this._from===u.from&&this._to===u.to,h=W(t,Number(l.slice(0,4))).slice(0,V);return p`
<div class="filter-chips area-range-chips">
<button class="filter-chip ${r(d)?"active":""}" @click=${()=>this._setRange(R())}>
${a("area_range_12m",s)}
</button>
${h.map(u=>p`
<button class="filter-chip ${r(A(u))?"active":""}" @click=${()=>this._setRange(A(u))}>${u}</button>
`)}
<button class="filter-chip ${!this._from&&!this._to?"active":""}" @click=${()=>this._setRange({from:"",to:""})}>
${a("area_range_all",s)}
</button>
</div>
`}_renderChart(t){let s=this._lang,l=this.currencySymbol,d=t.reduce((c,m)=>Math.max(c,m.cost),0),r=t.reduce((c,m)=>Math.min(c,m.cost),0);if(d<=0&&r>=0)return p`<p class="area-empty">${a("area_no_costs",s)}</p>`;let h=c=>Math.round(c/(d-r)*1e3)/10,u=Math.max(1,Math.ceil(t.length/12)),f=t.map((c,m)=>({b:c,i:m})).filter(({i:c})=>c%u===0);return p`
<div class="area-chart">
<div class="area-chart-max">${v(d,l,s)}</div>
<div class="area-chart-bars">
${r<0?p`<div class="area-chart-zero" style="bottom: ${h(-r)}%"></div>`:y}
${t.map(c=>{let m=`${this._bucketLabel(c,"long")}: ${v(c.cost,l,s)} \xB7 ${a("area_kpi_completions",s)}: ${g(c.completions,s)}`,e=c.cost<0?h(c.cost-r):h(-r);return p`<div class="area-bar" title=${m} aria-label=${m}>
${c.cost!==0?p`<div class="area-bar-fill ${c.cost<0?"credit":""}" style="height: ${h(Math.abs(c.cost))}%${e?`; bottom: ${e}%`:""}"></div>`:y}
</div>`})}
</div>
${r<0?p`<div class="area-chart-min">${v(r,l,s)}</div>`:y}
<div class="area-chart-axis ${u>1?"grouped":""}">
${f.map(({b:c,i:m})=>p`<span class="area-bar-label" style="flex-grow: ${Math.min(u,t.length-m)}">${c.month==null?String(c.year):p`${T(c.month,s,"short")}${c.month===0||m===0?p`<br />${c.year}`:y}`}</span>`)}
</div>
</div>
`}render(){if(!this.hass||!this.areaKey)return y;let t=this._lang,s=this.currencySymbol,{objects:l,entries:d,filtered:r,totals:h,buckets:u,byObject:f}=this._figures(),c=l.reduce((e,n)=>e+n.tasks.filter(x=>this.showArchived||!x.archived).length,0),m=this._expanded?r:r.slice(0,Z);return p`
<div class="detail-section area-view">
<div class="detail-header">
<h2 class="area-title">
<ha-icon .icon=${M(this.areaKey,this.hass.areas)}></ha-icon>
${E(this.areaKey,this.hass.areas,a("no_area",t))}
</h2>
<div class="action-buttons">
<ha-button appearance="plain" class="area-print" .disabled=${this._printing} @click=${()=>this._print()}>
<ha-icon icon="mdi:printer-outline"></ha-icon>
${this._printing?a("loading",t):a("area_report_print",t)}
</ha-button>
</div>
</div>
<p class="meta">
${this._countText("area_object_count","area_object_count_one",l.length)} ·
${this._countText("templates_task_count","templates_task_count_one",c)}
${this._histories.loading?p` · <span class="area-loading">${a("loading",t)}</span>`:y}
</p>
${this._renderRangeChips(d)}
<div class="filter-bar area-filters">
<ms-date-field
kind="date"
clearable
.hass=${this.hass}
.lang=${t}
.label=${a("date_from",t)}
.value=${this._from}
@value-changed=${e=>{this._from=e.detail.value}}
></ms-date-field>
<ms-date-field
kind="date"
clearable
.hass=${this.hass}
.lang=${t}
.label=${a("date_to",t)}
.value=${this._to}
@value-changed=${e=>{this._to=e.detail.value}}
></ms-date-field>
<label class="filter-field">
<span class="filter-label">${a("object",t)}</span>
<select class="area-object-filter" .value=${this._entryFilter}
@change=${e=>{this._entryFilter=e.target.value}}>
<option value="" ?selected=${!this._entryFilter}>${a("all_objects",t)}</option>
${l.map(e=>p`<option value=${e.entry_id} ?selected=${e.entry_id===this._entryFilter}>${e.object.name}</option>`)}
</select>
</label>
<input
type="search"
class="search-input area-task-filter"
aria-label=${a("area_task_filter",t)}
placeholder=${a("area_task_filter",t)}
.value=${this._taskQuery}
@input=${e=>{this._taskQuery=e.target.value}}
/>
</div>
<div class="kpi-bar area-kpis">
<div class="kpi-card">
<div class="kpi-label">${a("area_kpi_completions",t)}</div>
<div class="kpi-value-large area-kpi-completions">${g(h.completions,t)}</div>
</div>
<div class="kpi-card">
<div class="kpi-label">${a("total_cost",t)}</div>
<div class="kpi-value-large area-kpi-cost">${v(h.totalCost,s,t)}</div>
</div>
<div class="kpi-card">
<div class="kpi-label">${a("avg_cost",t)}</div>
<div class="kpi-value-large">${h.avgCost!=null?v(h.avgCost,s,t):"\u2014"}</div>
</div>
<div class="kpi-card">
<div class="kpi-label">${a("area_kpi_total_time",t)}</div>
<div class="kpi-value-large">${h.totalDuration?w(h.totalDuration,t):"\u2014"}</div>
</div>
</div>
<h3>${u.unit==="month"?a("area_cost_per_month",t):a("area_cost_per_year",t)}</h3>
${this._renderChart(u.buckets)}
<h3>${a("area_cost_per_object",t)}</h3>
<div class="objects-table-wrap">
<table class="objects-table area-object-table">
<thead>
<tr>
<th>${a("object",t)}</th>
<th class="num">${a("area_kpi_completions",t)}</th>
<th class="num">${a("cost",t)}</th>
<th class="num">${a("area_cost_share",t)}</th>
</tr>
</thead>
<tbody>
${f.map(e=>p`
<tr class="objects-table-row" @click=${()=>this._openObject(e.entryId)}>
<td><span class="objects-table-name">${e.objectName}</span></td>
<td class="num">${g(e.completions,t)}</td>
<td class="num">${v(e.cost,s,t)}</td>
<td class="num">
<span class="area-share"><span class="area-share-fill" style="width: ${Math.round(e.share*100)}%"></span></span>
${g(e.share*100,t,0)} %
</td>
</tr>
`)}
</tbody>
</table>
</div>
<h3>
${a("area_history_section",t)}
<span class="area-count">${g(r.length,t)}</span>
</h3>
${r.length===0?p`<p class="area-empty">${a("object_history_empty",t)}</p>`:p`
<div class="objects-table-wrap">
<table class="objects-table area-history-table">
<thead>
<tr>
<th>${a("date",t)}</th>
<th></th>
<th>${a("object",t)}</th>
<th>${a("task_name",t)}</th>
<th class="num">${a("cost",t)}</th>
<th class="num">${a("duration",t)}</th>
<th>${a("notes_label",t)}</th>
</tr>
</thead>
<tbody>
${m.map(e=>{let n=e.notes?B(e.notes,t):"";return p`
<tr class="objects-table-row area-history-row" @click=${()=>this._openTask(e.entryId,e.taskId)}>
<td title=${I(e.timestamp,t)}>${N(e.timestamp,t)}</td>
<td>
<span class="area-entry-type" style="color: ${tt[e.type]??"inherit"}">
<ha-icon .icon=${D[e.type]||"mdi:circle"}></ha-icon>${a(e.type,t)}
</span>
</td>
<td>
<button class="area-object-link" @click=${x=>{x.stopPropagation(),this._openObject(e.entryId)}}>
${e.objectName}
</button>
</td>
<td><button class="area-task-link">${e.taskName}${e.phaseName?` \xB7 ${e.phaseName}`:""}</button></td>
<td class="num">${e.cost!=null?v(e.cost,s,t):"\u2014"}</td>
<td class="num">${e.duration!=null?w(e.duration,t):"\u2014"}</td>
<td class="oc-notes" title=${n}>${n||"\u2014"}</td>
</tr>
`})}
</tbody>
</table>
</div>
${r.length>m.length?p`<ha-button appearance="plain" class="area-more" @click=${()=>{this._expanded=!0}}>
${a("show_all",t)} (${g(r.length,t)})
</ha-button>`:y}
`}
${this._histories.capped?p`<p class="area-cap-note">${a("object_history_cap_note",t)}</p>`:y}
</div>
`}};$([k({attribute:!1})],_.prototype,"hass",2),$([k()],_.prototype,"areaKey",2),$([k({attribute:!1})],_.prototype,"objects",2),$([k({type:Boolean})],_.prototype,"showArchived",2),$([k()],_.prototype,"currencySymbol",2),$([k({attribute:!1})],_.prototype,"userName",2),$([j()],_.prototype,"_from",2),$([j()],_.prototype,"_to",2),$([j()],_.prototype,"_entryFilter",2),$([j()],_.prototype,"_taskQuery",2),$([j()],_.prototype,"_expanded",2),$([j()],_.prototype,"_printing",2);customElements.get("maintenance-area-view")||customElements.define("maintenance-area-view",_);export{_ as MaintenanceAreaView};
@@ -0,0 +1,54 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as O}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WH65ZHYZ.js";import{q as j,r as E,s as L,t as R,u as C}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-S7XZBRRU.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-4PKMHUVO.js";import{a as _,b as S,c as A}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-KKVMZFOV.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-NEWWPCTD.js";import{H as g,K as k,L as v,O as w,a as l,c as a,f as m,h as y,l as p,m as b,s as r,u as $,y as f}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var q=[{key:"name",label:"area",num:!1},{key:"objects",label:"objects",num:!0},{key:"tasks",label:"tasks",num:!0},{key:"overdue",label:"overdue",num:!0},{key:"due_soon",label:"due_soon",num:!0},{key:"cost_year",label:"area_cost_year",num:!0},{key:"cost_total",label:"total_cost",num:!0},{key:"last",label:"last_performed",num:!1}],i=class extends y{constructor(){super(...arguments);this.objects=[];this.showArchived=!1;this.currencySymbol="";this._query="";this._sort=E(S(_.areaSort));this._histories=new O(this);this._localeReady=!1;this._memo=null}createRenderRoot(){return this}get _lang(){return g(this.hass)}willUpdate(t){if(super.willUpdate(t),t.has("objects")||t.has("showArchived")||t.has("hass")&&t.get("hass")===void 0){let o=this.objects.filter(s=>this.showArchived||!s.object.archived).flatMap(s=>s.tasks.map(n=>({entryId:s.entry_id,task:n})));this._histories.sync(this.hass,o)}}updated(t){super.updated(t),!this._localeReady&&this.hass&&(this._localeReady=!0,$(this._lang).then(()=>this.requestUpdate()))}_rows(t){let o=this._lang,s=[this.objects,this.showArchived,this._histories.version,this.hass?.areas,o,t];if(this._memo&&this._memo.deps.every((c,h)=>c===s[h]))return this._memo.rows;let n=j(this.objects,{showArchived:this.showArchived,areas:this.hass?.areas,noAreaLabel:r("no_area",o),year:t,historyOf:(c,h)=>this._histories.historyOf(c,h)});return this._memo={deps:s,rows:n},n}_setSort(t){this._sort=L(this._sort,t),A(_.areaSort,`${this._sort.key}:${this._sort.dir}`)}_open(t){this.dispatchEvent(new CustomEvent("open-area",{detail:{areaKey:t},bubbles:!0,composed:!0}))}_toggleArchived(){this.dispatchEvent(new CustomEvent("archived-toggle",{bubbles:!0,composed:!0}))}_headerLabel(t,o,s){return t==="area_cost_year"?r("area_cost_year",s).replace("{year}",String(o)):r(t,s)}render(){if(!this.hass)return m;let t=this._lang,o=Number(f().slice(0,4)),s=this.currencySymbol,n=this._rows(o),c=R(C(n,this._query),this._sort),h=this.objects.filter(e=>e.object.archived).length,d=e=>k(e,t);return a`
<div class="filter-bar area-filter-bar">
<input
type="search"
class="search-input"
aria-label=${r("areas_filter",t)}
placeholder=${r("areas_filter",t)}
.value=${this._query}
@input=${e=>{this._query=e.target.value}}
/>
${this._histories.loading?a`<span class="area-loading">${r("loading",t)}</span>`:m}
${h>0?a`<ha-button class="archived-toggle ${this.showArchived?"active":""}" @click=${()=>this._toggleArchived()}>
<ha-icon icon="mdi:archive-outline"></ha-icon>
${this.showArchived?r("hide_archived",t):`${r("show_archived",t)} (${h})`}
</ha-button>`:m}
</div>
${n.length===0?a`<div class="empty-state">${r("no_objects",t)}</div>`:c.length===0?a`<div class="empty-state">${r("areas_filter_none",t)}</div>`:a`
<div class="objects-table-wrap">
<table class="objects-table areas-table">
<thead>
<tr>
${q.map(e=>{let u=this._sort.key===e.key;return a`<th class=${e.num?"num":""}
aria-sort=${u?this._sort.dir==="asc"?"ascending":"descending":"none"}>
<button class="area-sort ${u?"active":""}" title=${r("sort_label",t)} @click=${()=>this._setSort(e.key)}>
${this._headerLabel(e.label,o,t)}
${u?a`<ha-icon icon=${this._sort.dir==="asc"?"mdi:arrow-up":"mdi:arrow-down"}></ha-icon>`:m}
</button>
</th>`})}
</tr>
</thead>
<tbody>
${c.map(e=>a`
<tr class="objects-table-row" tabindex="0"
@click=${()=>this._open(e.key)}
@keydown=${u=>{u.key==="Enter"&&this._open(e.key)}}>
<td>
<ha-icon class="area-row-icon" .icon=${e.icon}></ha-icon>
<span class="objects-table-name">${e.name}</span>
</td>
<td class="num">${d(e.objects)}</td>
<td class="num">${d(e.tasks)}</td>
<td class="num">${e.overdue?a`<span class="area-count overdue">${d(e.overdue)}</span>`:d(0)}</td>
<td class="num">${e.dueSoon?a`<span class="area-count due-soon">${d(e.dueSoon)}</span>`:d(0)}</td>
<td class="num">${v(e.costYear,s,t)}</td>
<td class="num">${v(e.costTotal,s,t)}</td>
<td>${e.lastCompletion?w(e.lastCompletion,t):"\u2014"}</td>
</tr>
`)}
</tbody>
</table>
</div>
`}
`}};l([p({attribute:!1})],i.prototype,"hass",2),l([p({attribute:!1})],i.prototype,"objects",2),l([p({type:Boolean})],i.prototype,"showArchived",2),l([p()],i.prototype,"currencySymbol",2),l([b()],i.prototype,"_query",2),l([b()],i.prototype,"_sort",2);customElements.get("maintenance-areas-view")||customElements.define("maintenance-areas-view",i);export{i as MaintenanceAreasView};
@@ -0,0 +1,113 @@
/*! maintenance_supporter frontend 2.98.0 */
import"/maintenance_supporter_panelfiles/panel-chunks/chunk-ISGNEPYP.js";import{H as u,a as n,b as _,c as o,f as p,h as c,l as g,m as a,s}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var d=["round_robin","least_completed","random"],v=["low","normal","high"],m=365,i=class extends c{constructor(){super(...arguments);this._open=!1;this._mode="assign";this._count=0;this._users=[];this._present=[];this._assignKind="one";this._person="";this._pool=new Set;this._rotation=d[0];this._addText="";this._remove=new Set;this._setWarning=!1;this._warning=7;this._setPriority=!1;this._priority="normal";this._setMute=!1;this._mute=!1;this._resolve=null}get _lang(){return u(this.hass)}open(t,e,r){return this._resolve?.(null),this._mode=t,this._count=e.length,this._users=[...r].sort((l,h)=>l.name.localeCompare(h.name)),this._present=[...new Set(e.flatMap(l=>l.labels||[]))].sort((l,h)=>l.localeCompare(h)),this._assignKind="one",this._person="",this._pool=new Set,this._rotation=d[0],this._addText="",this._remove=new Set,this._setWarning=!1,this._warning=7,this._setPriority=!1,this._priority="normal",this._setMute=!1,this._mute=!1,this._open=!0,new Promise(l=>{this._resolve=l})}_finish(t){this._open=!1;let e=this._resolve;this._resolve=null,e?.(t)}changes(){if(this._mode==="assign"){if(this._assignKind==="one")return{responsible_user_id:this._person||null,assignee_pool:null,rotation_strategy:null};let e=this._users.map(r=>r.id).filter(r=>this._pool.has(r));return e.length<2?null:{assignee_pool:e,rotation_strategy:this._rotation,responsible_user_id:null}}if(this._mode==="labels"){let e=[...new Set(this._addText.split(",").map(l=>l.trim()).filter(Boolean))],r=[...this._remove];return e.length||r.length?{labels_add:e,labels_remove:r}:null}let t={};return this._setWarning&&(t.warning_days=this._warning),this._setPriority&&(t.priority=this._priority),this._setMute&&(t.notify_enabled=!this._mute),Object.keys(t).length?t:null}_toggle(t,e){let r=new Set(t);return r.has(e)?r.delete(e):r.add(e),r}_renderAssign(t){return o`
<div class="hint">${s("bulk_assign_hint",t)}</div>
<label class="choice">
<input type="radio" name="kind" .checked=${this._assignKind==="one"} @change=${()=>this._assignKind="one"} />
${s("bulk_assign_one",t)}
</label>
${this._assignKind==="one"?o`<select class="person" .value=${this._person} @change=${e=>this._person=e.target.value}>
<option value="" ?selected=${!this._person}>${s("unassigned",t)}</option>
${this._users.map(e=>o`<option value=${e.id} ?selected=${this._person===e.id}>${e.name}</option>`)}
</select>`:p}
<label class="choice">
<input type="radio" name="kind" .checked=${this._assignKind==="rotate"} @change=${()=>this._assignKind="rotate"} />
${s("bulk_assign_rotate",t)}
</label>
${this._assignKind==="rotate"?o`<div class="pool">
${this._users.map(e=>o`<label class="row">
<input type="checkbox" .checked=${this._pool.has(e.id)} @change=${()=>this._pool=this._toggle(this._pool,e.id)} />
${e.name}
</label>`)}
</div>
<label class="field">
<span>${s("rotation_strategy",t)}</span>
<select class="rotation" .value=${this._rotation} @change=${e=>this._rotation=e.target.value}>
${d.map(e=>o`<option value=${e} ?selected=${this._rotation===e}>${s(`rotation_${e}`,t)}</option>`)}
</select>
</label>
${this._pool.size<2?o`<div class="hint">${s("bulk_rotation_min_two",t)}</div>`:p}`:p}
`}_renderLabels(t){return o`
<ms-textfield
class="labels-add"
label=${s("bulk_labels_add",t)}
.helper=${s("labels_help",t)}
.value=${this._addText}
@input=${e=>this._addText=e.target.value}
></ms-textfield>
${this._present.length?o`<div class="section-title">${s("bulk_labels_remove",t)}</div>
<div class="pool">
${this._present.map(e=>o`<label class="row">
<input type="checkbox" .checked=${this._remove.has(e)} @change=${()=>this._remove=this._toggle(this._remove,e)} />
${e}
</label>`)}
</div>`:p}
`}_renderEdit(t){return o`
<div class="hint">${s("bulk_edit_hint",t)}</div>
<div class="row edit-row">
<input type="checkbox" class="set-warning" .checked=${this._setWarning} @change=${e=>this._setWarning=e.target.checked} />
<span class="grow">${s("warning_days",t)}</span>
<input type="number" class="warning" min="0" max=${m} .value=${String(this._warning)} ?disabled=${!this._setWarning}
@change=${e=>{let r=parseInt(e.target.value,10);this._warning=Number.isInteger(r)?Math.min(Math.max(r,0),m):this._warning}} />
</div>
<div class="row edit-row">
<input type="checkbox" class="set-priority" .checked=${this._setPriority} @change=${e=>this._setPriority=e.target.checked} />
<span class="grow">${s("priority",t)}</span>
<select class="priority" .value=${this._priority} ?disabled=${!this._setPriority} @change=${e=>this._priority=e.target.value}>
${v.map(e=>o`<option value=${e} ?selected=${this._priority===e}>${s(`priority_${e}`,t)}</option>`)}
</select>
</div>
<div class="row edit-row">
<input type="checkbox" class="set-mute" .checked=${this._setMute} @change=${e=>this._setMute=e.target.checked} />
<span class="grow">${s("bulk_no_notifications",t)}</span>
<input type="checkbox" class="mute" .checked=${this._mute} ?disabled=${!this._setMute} @change=${e=>this._mute=e.target.checked} />
</div>
`}render(){if(!this._open)return o``;let t=this._lang,e=this._mode==="assign"?s("bulk_assign",t):this._mode==="labels"?s("labels",t):s("edit",t),r=this.changes()!==null;return o`
<ha-dialog open @closed=${()=>this._finish(null)}>
<div class="dialog-title">${e}</div>
<div class="content">
<div class="count">${s("bulk_n_selected",t).replace("{n}",String(this._count))}</div>
${this._mode==="assign"?this._renderAssign(t):this._mode==="labels"?this._renderLabels(t):this._renderEdit(t)}
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${()=>this._finish(null)}>${s("cancel",t)}</ha-button>
<ha-button class="apply" .disabled=${!r} @click=${()=>this._finish(this.changes())}>${s("save",t)}</ha-button>
</div>
</ha-dialog>
`}};i.styles=_`
.dialog-title { font-size: 18px; font-weight: 500; padding-bottom: 12px; }
.content {
display: flex;
flex-direction: column;
gap: 10px;
min-width: min(360px, calc(100vw - 24px));
max-width: 520px;
max-height: 60vh;
overflow-y: auto;
}
@media (max-width: 600px) {
.content { min-width: 0; max-width: none; max-height: none; }
}
.count, .hint { color: var(--secondary-text-color); font-size: 13px; }
.section-title {
font-size: 14px;
font-weight: 500;
padding-bottom: 4px;
border-bottom: 1px solid var(--divider-color);
}
.choice, .row { display: flex; align-items: center; gap: 8px; font-size: 14px; cursor: pointer; }
.pool { display: flex; flex-direction: column; gap: 4px; padding-left: 26px; }
.field { display: flex; align-items: center; gap: 8px; justify-content: space-between; font-size: 14px; }
.grow { flex: 1; min-width: 0; }
select, input[type="number"] {
font: inherit;
padding: 4px 6px;
border: 1px solid var(--divider-color);
border-radius: 4px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
max-width: 100%;
}
input[type="number"] { width: 72px; }
select.person { margin-left: 26px; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 8px; padding-top: 16px; }
`,n([g({attribute:!1})],i.prototype,"hass",2),n([a()],i.prototype,"_open",2),n([a()],i.prototype,"_mode",2),n([a()],i.prototype,"_count",2),n([a()],i.prototype,"_users",2),n([a()],i.prototype,"_present",2),n([a()],i.prototype,"_assignKind",2),n([a()],i.prototype,"_person",2),n([a()],i.prototype,"_pool",2),n([a()],i.prototype,"_rotation",2),n([a()],i.prototype,"_addText",2),n([a()],i.prototype,"_remove",2),n([a()],i.prototype,"_setWarning",2),n([a()],i.prototype,"_warning",2),n([a()],i.prototype,"_setPriority",2),n([a()],i.prototype,"_priority",2),n([a()],i.prototype,"_setMute",2),n([a()],i.prototype,"_mute",2);customElements.get("maintenance-bulk-edit-dialog")||customElements.define("maintenance-bulk-edit-dialog",i);export{i as MaintenanceBulkEditDialog};
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
var E={\u00DF:"s","\u1E9E":"s",\u00E6:"a",\u0153:"o",\u00F8:"o",\u0111:"d",\u00F0:"d",\u00FE:"t",\u0142:"l",\u0131:"i"},d=10,R=7,g=4,h=2,S=5,x=3,_=/[a-z0-9]+/g;function u(r){let e="";for(let t of r.toLowerCase()){if(t.charCodeAt(0)<128&&t.length===1){e+=t;continue}let n=E[t];if(n){e+=n;continue}let o=t.normalize("NFKD")[0]||t;e+=o.charCodeAt(0)<128?o:t}return e}function m(r){return u(r).match(_)||[]}function C(r){return u(r).replace(/[^a-z0-9]+/g,"")}function b(r){return r.replace(/ue/g,"u").replace(/oe/g,"o").replace(/ae/g,"a").replace(/ss/g,"s")}function F(r){let e=[];for(let t of m(r)){let n=[t],o=b(t);o&&o!==t&&n.push(o),e.push(n)}return e}function p(r,e){if(r===e)return!0;let t=r.length,n=e.length;if(Math.abs(t-n)>1)return!1;if(t===n){let l=[];for(let i=0;i<t;i++)r[i]!==e[i]&&l.push(i);if(l.length===1)return!0;if(l.length===2&&l[1]===l[0]+1){let i=l[0];return r[i]===e[i+1]&&r[i+1]===e[i]}return!1}let[o,s]=t>n?[r,e]:[e,r],c=0,f=0,a=!1;for(;c<o.length&&f<s.length;)if(o[c]===s[f])c++,f++;else{if(a)return!1;a=!0,c++}return!0}function N(r,e){let t=0;for(let n of r)if(n){if(e===n)return d;if(e.startsWith(n)){t=Math.max(t,R);continue}if(n.length>=x&&e.includes(n)){t=Math.max(t,g);continue}n.length>=S&&t<h&&(p(n,e)||e.length>n.length&&p(n,e.slice(0,n.length)))&&(t=h)}return t}function I(r,e){let t=0;for(let n of m(e))if(t=Math.max(t,N(r,n)),t===d)return t;if(t<g){let n=C(e);for(let o of r)if(o.length>=x&&n.includes(o))return g}return t}function O(r,e){if(!r)return!1;let t=F(e);if(!t.length){let n=u(e.trim());return n.length>0&&u(r).includes(n)}return M(t,[{text:r,weight:1}])>0}function M(r,e){if(!r.length)return 0;let t=e.filter(o=>o.text),n=0;for(let o of r){let s=0;for(let c of t){let f=I(o,c.text)*c.weight;f>s&&(s=f)}if(s===0)return 0;n+=s}return n}export{F as a,O as b,M as c};
@@ -0,0 +1,37 @@
/*! maintenance_supporter frontend 2.98.0 */
import{$ as w,A as k,K as R,M as x,a as m,b as h,c as g,f as v,h as b,l as y,m as _,s as l}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";function E(i){return`${i.entry_id??""}\0${i.part_id}`}function S(i,t,e,o){let n=!!i.entry_id&&i.entry_id!==t,r=n?i.entry_id:t,s=e.find(p=>p.entry_id===r),a=(s?.parts||[]).find(p=>p.id===i.part_id)||null,c=n&&s?.object?.name||"",u=a?.name||l("shared_part_unknown",o);return{part:a,foreign:n,ownerName:c,label:c?`${u} (${c})`:u}}function N(i,t,e,o){let{part:n,label:r}=S(i,t,e,o),s=n&&n.stock!==null&&n.stock!==void 0?` (${x(n.stock,n.unit,o)})`:"",a=n?.storage_location?` \u2014 ${n.storage_location}`:"";return`${R(i.quantity,o)}\xD7 ${r}${s}${a}`}function V(i,t,e,o){let r=(e.find(a=>a.entry_id===t)?.parts||[]).map(a=>({...a})),s=new Set(r.map(a=>E({part_id:a.id})));for(let a of i?.consumes_parts||[]){if(!a.entry_id||a.entry_id===t)continue;let c=E(a);if(s.has(c))continue;s.add(c);let{part:u,ownerName:p}=S(a,t,e,o);r.push({id:a.part_id,name:u?.name||l("shared_part_unknown",o),unit:u?.unit,stock:u?.stock??null,storage_location:u?.storage_location,entry_id:a.entry_id,owner_name:p})}return r}var L=20;function T(){let i=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:t=>t.map(()=>Math.floor(Math.random()*256))}).getRandomValues(i),Array.from(i,t=>t.toString(16).padStart(2,"0")).join("")}function f(i){let t=i?.reading_values;if(!Array.isArray(t))return[];let e=[],o=new Set;for(let n of t){if(!n||typeof n!="object")continue;let r=n;typeof r.id!="string"||!r.id||o.has(r.id)||typeof r.value!="number"||!Number.isFinite(r.value)||(o.add(r.id),e.push({id:r.id,name:typeof r.name=="string"?r.name:r.id,unit:typeof r.unit=="string"?r.unit:null,value:r.value}))}return e}function P(i){return i.filter(t=>t.type==="completed"&&(t.reading_value!=null||f(t).length>0)).sort((t,e)=>t.timestamp.localeCompare(e.timestamp))}function M(i){return P(i??[]).map(t=>({timestamp:t.timestamp,values:f(t)})).filter(t=>t.values.length>0)}function A(i,t,e){let o;for(let n of i){if(e!==void 0){let s=k(n.timestamp);if(!isNaN(s)&&s>=e)break}let r=n.values.find(s=>s.id===t);r&&(o=r)}return o}function C(i,t,e){let o=f(t).find(r=>r.id===e);if(!o)return null;let n=null;for(let r of P(i)){if(r.timestamp>=t.timestamp)break;let s=f(r).find(a=>a.id===e);s&&(n=s.value)}return n==null?null:o.value-n}function D(i){let t=new Set,e=new Set;for(let o of i){let n=(o.name||"").trim().toLowerCase();n&&(t.has(n)?e.add(o.id):t.add(n))}return e}function F(i){let t=[],e=new Set,o=new Set;for(let n of i){let r=(n.name||"").trim();if(!(!r||e.has(n.id)||o.has(r.toLowerCase()))&&(e.add(n.id),o.add(r.toLowerCase()),t.push({id:n.id,name:r,unit:(n.unit||"").trim()||null}),t.length>=L))break}return t}function j(i){let t=(i??"").trim();if(t==="")return null;let e=Number(t.replace(",","."));return!Number.isFinite(e)||e<0?null:Math.round(e)}var B=["notes","cost","duration","photo","user"],I={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"};var d=class extends b{constructor(){super(...arguments);this.value="";this.lang="en";this._credit=!1;this._amount=""}willUpdate(e){if(!e.has("value"))return;let o=(this.value??"").trim();if(o===this._signed())return;let n=parseFloat(o);if(o===""||Number.isNaN(n)){this._amount="",this._credit=!1;return}this._credit=n<0,this._amount=String(Math.abs(n))}_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 o=e.target.value;o.startsWith("-")&&(this._credit=!0),this._amount=o.replace(/^-+/,""),this._emit()}render(){let e=this.lang;return g`
<div class="wrap">
<div class="sign" role="group">
<button type="button" class="kind cost ${this._credit?"":"on"}" aria-pressed=${String(!this._credit)}
@click=${()=>this._setCredit(!1)}>${l("cost",e)}</button>
<button type="button" class="kind credit ${this._credit?"on":""}" aria-pressed=${String(this._credit)}
@click=${()=>this._setCredit(!0)}>${l("cost_kind_credit",e)}</button>
</div>
<input type="number" step="0.01" min="0" inputmode="decimal" class="field-input amount"
.value=${this._amount} @input=${this._onInput} />
</div>
${this._credit?g`<div class="hint">${l("cost_credit_hint",e)}</div>`:v}
`}};d.styles=[w,h`
:host { display: block; }
.wrap { display: flex; gap: 8px; align-items: stretch; }
.sign {
display: inline-flex;
flex: none;
border: 1px solid var(--divider-color);
border-radius: 6px;
overflow: hidden;
}
.kind {
font: inherit;
font-size: 13px;
padding: 0 10px;
border: none;
background: transparent;
color: var(--secondary-text-color);
cursor: pointer;
}
.kind.on { background: var(--primary-color); color: var(--text-primary-color, #fff); }
.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); }
`],m([y()],d.prototype,"value",2),m([y()],d.prototype,"lang",2),m([_()],d.prototype,"_credit",2),m([_()],d.prototype,"_amount",2);customElements.get("ms-cost-input")||customElements.define("ms-cost-input",d);export{E as a,N as b,V as c,L as d,T as e,f,M as g,A as h,C as i,D as j,F as k,j as l,B as m,I as n};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{s as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var _=[{key:"name",labelKey:"name",required:!0},{key:"ref_no",labelKey:"ref_number"},{key:"manufacturer",labelKey:"manufacturer"},{key:"model",labelKey:"model"},{key:"serial_number",labelKey:"serial_number_label"},{key:"installation_date",labelKey:"installed"},{key:"warranty_expiry",labelKey:"warranty"},{key:"area_id",labelKey:"area"},{key:"documentation_url",labelKey:"documentation_url_label"},{key:"notes",labelKey:"object_notes_label"},{key:"task_count",labelKey:"tasks"},{key:"actions",labelKey:"actions"}],u=_.map(e=>e.key),i=["name","manufacturer","model","serial_number","installation_date","warranty_expiry","area_id","task_count","actions"];function g(e){if(!Array.isArray(e))return[...i];let n=new Set,r=[];for(let t of e)typeof t=="string"&&u.includes(t)&&!n.has(t)&&(n.add(t),r.push(t));return r.length?(r.includes("name")||r.unshift("name"),r):[...i]}function f(e,n){return a(`home_dwelling_${e==="house"||e==="apartment"?e:"unknown"}`,n)}function m(e,n){if(!e)return"";try{return new Intl.DisplayNames([n],{type:"region"}).of(e)||e}catch{return e}}var l={floors:"home_reason_floors",basement_floor:"home_reason_basement",area_basement:"home_reason_basement",area_garden:"home_reason_garden",area_shed:"home_reason_shed",area_driveway:"home_reason_driveway",area_garage:"home_reason_garage",entity_garage:"home_reason_garage",area_attic:"home_reason_attic",entity_lawn_mower:"home_reason_lawn_mower",entity_gate:"home_reason_gate",area_balcony:"home_reason_balcony",small_home:"home_reason_small_home"},c={ups:"home_reason_ups"};function d(e,n){let r=[];for(let t of e){let o=l[t];if(!o)continue;let s=a(o,n);r.includes(s)||r.push(s)}return r.join(", ")}function b(e,n,r){if(e==="starter")return a("home_reason_starter",n);if(e==="country")return a("home_reason_country",n).replace("{country}",m(r,n));if(e.startsWith("feature_")){let t=e.slice(8),o=l[`area_${t}`]??c[t];return a("home_reason_feature",n).replace("{feature}",o?a(o,n):e)}return a(`home_trait_${e}`,n)}export{_ as a,i as b,g as c,f as d,m as e,d as f,b as g};
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,488 @@
/*! maintenance_supporter frontend 2.98.0 */
import{d as M,e as R}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-W3CDWY4U.js";import{a as L,b as z,c as O}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-KKVMZFOV.js";import{c as U}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NEWWPCTD.js";import{a as I,h as H,l as V,n as B}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-5SEU5WUY.js";import{j as Q,k as w}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-QFIANZWP.js";import{a as j}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-MN2RZ73S.js";import{$ as C,A,K as E,L as q,M as F,Q as N,a,b as x,c as l,f,h as k,l as h,m as _,s as o,z as P}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var T=class{constructor(p,e){this.host=p;this.opts=e;this.photos=[];this.uploadedIds=[];this.uploading=!1;this.errorKey="";this._session=0;this._uploadEntry=new Map;this.max=e.max??10,p.addController(this)}hostConnected(){}get ids(){return this.photos.map(p=>p.id)}get remaining(){return Math.max(this.max-this.photos.length,0)}get full(){return this.remaining===0}errorText(p){return this.errorKey?o(this.errorKey,p).replace("{max}",String(this.max)):""}clearError(){this.errorKey=""}reset(p=[]){this._endSession(),this._revokeAll(),this.photos=p.map(e=>({id:e,preview:""})),this.uploadedIds=[],this._uploadEntry.clear(),this.errorKey="",this.host.requestUpdate()}async addFiles(p){if(p.length===0)return;let e=this._session,i=this.opts.hass(),t=this.opts.entryId(),r=p.slice(0,this.remaining);this.uploading=!0,this.errorKey="",this.host.requestUpdate();try{for(let n of r){let s=await M(i,t,n);if(e!==this._session){R(i,t,[s]);return}this.uploadedIds=[...this.uploadedIds,s],this._uploadEntry.set(s,t),this.photos=[...this.photos,{id:s,preview:URL.createObjectURL(n)}],this.host.requestUpdate()}p.length>r.length&&(this.errorKey="photos_limit")}catch(n){if(e!==this._session)return;this.errorKey=n instanceof Error&&n.message==="doc_too_large"?"doc_too_large":"doc_upload_failed"}finally{e===this._session&&(this.uploading=!1,this.host.requestUpdate())}}remove(p){let e=this.photos.find(i=>i.id===p);e?.preview&&URL.revokeObjectURL(e.preview),this.photos=this.photos.filter(i=>i.id!==p),this.uploadedIds.includes(p)&&(this.uploadedIds=this.uploadedIds.filter(i=>i!==p),this._discard([p])),this.host.requestUpdate()}discardOrphans(){if(this._endSession(),this.uploadedIds.length===0)return;let p=this.uploadedIds;this.uploadedIds=[],this._discard(p)}markAttached(){this._endSession(),this.uploadedIds=[],this._uploadEntry.clear()}_endSession(){this._session++,this.uploading=!1}_discard(p){let e=new Map;for(let t of p){let r=this._uploadEntry.get(t)??this.opts.entryId();this._uploadEntry.delete(t),e.set(r,[...e.get(r)??[],t])}let i=this.opts.hass();for(let[t,r]of e)R(i,t,r)}_revokeAll(){for(let p of this.photos)p.preview&&URL.revokeObjectURL(p.preview)}};function S(){if(window.externalApp!==void 0)return!0;let p=typeof navigator<"u"&&navigator.userAgent||"";return/Home Assistant\//.test(p)&&/Android/.test(p)}function W(){if(!S())return!1;let g=typeof navigator<"u"?navigator.mediaDevices:void 0;return!!g&&typeof g.getUserMedia=="function"}var te=1920,ie=.88,se={retryMs:500,windowMs:5e3},re=new Set(["NotReadableError","AbortError","TrackStartError"]),K=80,J=/back|rear|environment|rück|hinten/i,G=/front|user|selfie|vorne/i;function Y(g){let p=/camera2?\s*(\d+)/i.exec(g);return p?Number(p[1]):Number.MAX_SAFE_INTEGER}function D(g,p){if(p){let i=g.find(t=>t.label===p);if(i)return i}return g.filter(i=>i.label&&J.test(i.label)).sort((i,t)=>Y(i.label)-Y(t.label))[0]??null}var X=g=>g?.name||"Error",ae=g=>g?.message||"",b=class extends k{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={...se};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 i=typeof navigator<"u"?navigator.mediaDevices:void 0;if(!i||typeof i.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 t=z(L.cameraLabel),r=await this._enumerate(i);if(!this._live(e))return;let n=D(r,t),s="refused";if(n&&(s=await this._openPatiently(i,e,this._byDevice(n))),s==="cancelled")return;if(s!=="ok"){if(s=await this._openPatiently(i,e,{video:{facingMode:{ideal:"environment"}},what:"facing environment"}),s==="cancelled")return;if(s!=="ok"){this._unavailable(this._lastError||"camera_unavailable");return}if(r=await this._enumerate(i),!this._live(e)){this._stopStream();return}}if(this._devLine truncated
`),i=!1;try{navigator.clipboard?.writeText&&(await navigator.clipboard.writeText(e),i=!0)}catch{}if(!i){let t=this.shadowRoot?.querySelector(".details textarea");if(t){t.focus(),t.select();try{i=document.execCommand("copy")}catch{i=!1}}}this._copied=i}async _shoot(){let e=this._video;if(!(!e||this._busy||this._switching)){this._busy=!0;try{let i=e.videoWidth||640,t=e.videoHeight||480,r=Math.min(1,te/Math.max(i,t)),n=document.createElement("canvas");n.width=Math.round(i*r),n.height=Math.round(t*r);let s=n.getContext("2d");if(!s)throw new Error("no_canvas");s.drawImage(e,0,0,n.width,n.height);let d=await new Promise(v=>n.toBlob(v,"image/jpeg",ie));if(!d)throw new Error("no_blob");let m=new Date().toISOString().replace(/[-:]/g,"").slice(0,15),u=new File([d],`photo-${m}.jpg`,{type:"image/jpeg"});this.close(),this.dispatchEvent(new CustomEvent("photo-captured",{detail:{file:u},bubbles:!0,composed:!0}))}catch(i){this._unavailable(i instanceof Error?i.message:String(i))}finally{this._busy=!1}}}render(){if(!this._open)return f;let e=this.lang,i=this._busy||this._switching;return l`
<div class="overlay" role="dialog" aria-modal="true" aria-label=${o("doc_camera",e)}>
<video autoplay playsinline muted></video>
${this._switching?l`<div class="switching" role="status">${o("camera_switching",e)}</div>`:f}
${this._switchFailed?l`<div class="switch-note" role="status">
<div>${o("camera_not_answered",e)}</div>
<details class="details">
<summary>${o("camera_diagnostics",e)}</summary>
<textarea readonly rows="6" .value=${this._log.join(`
`)}></textarea>
<button type="button" class="copy" @click=${this._copyLog}>${o(this._copied?"camera_copied":"camera_copy",e)}</button>
</details>
</div>`:f}
<div class="bar">
<button type="button" class="cancel" @click=${this.close}>${o("cancel",e)}</button>
${this._devices.length>1?l`<button type="button" class="switch" ?disabled=${i} title=${o("camera_switch_lens",e)} aria-label=${o("camera_switch_lens",e)} @click=${this._switchCamera}>
<ha-icon icon="mdi:camera-flip-outline"></ha-icon>
<span class="switch-pos">${this._deviceIndex>=0?`${this._deviceIndex+1}/${this._devices.length}`:`?/${this._devices.length}`}</span>
</button>`:f}
<button type="button" class="shoot" ?disabled=${i} @click=${this._shoot}>
<ha-icon icon="mdi:camera"></ha-icon><span>${o("camera_capture_shoot",e)}</span>
</button>
</div>
</div>
`}};b.styles=x`
:host { display: contents; }
.overlay {
position: fixed; inset: 0; z-index: 10000;
background: #000; color: #fff;
display: flex; flex-direction: column;
}
video { flex: 1; min-height: 0; width: 100%; object-fit: contain; background: #000; }
.bar {
display: flex; justify-content: space-between; align-items: center; gap: 16px;
padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
background: rgba(0, 0, 0, 0.8);
}
button {
font: inherit; border-radius: 24px; padding: 10px 18px; cursor: pointer;
display: inline-flex; align-items: center; gap: 8px;
}
.cancel { background: transparent; color: #fff; border: 1px solid rgba(255, 255, 255, 0.6); }
.switch { background: transparent; color: #fff; border: 1px solid rgba(255, 255, 255, 0.6); padding: 10px 12px; }
.switch[disabled] { opacity: 0.5; cursor: default; }
.switch ha-icon { --mdc-icon-size: 22px; }
.switch-pos { font-size: 12px; opacity: 0.85; }
.switching {
position: absolute; top: 45%; left: 50%; transform: translate(-50%, -50%);
padding: 8px 16px; border-radius: 16px; background: rgba(0, 0, 0, 0.6); font-size: 14px;
}
.switch-note {
position: absolute; left: 12px; right: 12px; bottom: 84px; max-height: 60%; overflow: auto;
text-align: center; color: #fff; font-size: 13px; text-shadow: 0 1px 2px #000;
}
.details { margin-top: 6px; text-align: start; text-shadow: none; }
.details summary { cursor: pointer; text-align: center; opacity: 0.85; }
.details textarea {
display: block; box-sizing: border-box; width: 100%; margin: 6px 0;
font: 11px/1.35 monospace; color: #fff; background: rgba(255, 255, 255, 0.12);
border: 1px solid rgba(255, 255, 255, 0.3); border-radius: 6px; padding: 6px; resize: vertical;
}
.copy { background: transparent; color: #fff; border: 1px solid rgba(255, 255, 255, 0.6); padding: 6px 14px; font-size: 13px; }
.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; }
`,a([h({type:String})],b.prototype,"lang",2),a([_()],b.prototype,"_open",2),a([_()],b.prototype,"_busy",2),a([_()],b.prototype,"_switching",2),a([_()],b.prototype,"_devices",2),a([_()],b.prototype,"_deviceIndex",2),a([_()],b.prototype,"_switchFailed",2),a([_()],b.prototype,"_copied",2);customElements.get("ms-camera-capture")||customElements.define("ms-camera-capture",b);var Z=x`
ms-photo-picker { display: contents; }
.photo-pickers {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.photo-pick {
display: inline-flex;
flex-direction: row;
align-items: center;
gap: 8px;
padding: 8px 12px;
border: 1px dashed var(--divider-color);
border-radius: 8px;
cursor: pointer;
font-size: 13px;
color: var(--secondary-text-color);
width: fit-content;
}
.photo-pick:hover { border-color: var(--primary-color); }
.photo-pick:focus-visible { outline: 2px solid var(--primary-color); outline-offset: 2px; }
.photo-pick.disabled { opacity: 0.6; cursor: default; }
.photo-pick input[type="file"] { display: none; }
.photo-android-hint {
font-size: 12px;
color: var(--secondary-text-color);
margin-top: 4px;
}
`,y=class extends k{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=S();this._inAppCamera=W()}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 i=e.target,t=Array.from(i.files??[]);i.value="",this._emit(t)}_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 f;let e=this.lang,i=this._locked?"disabled":"",t=this.busy?o("uploading",e):o("doc_camera",e),r=o(this._singlePick?"choose_photo":"choose_photos",e);return l`
<div class="photo-pickers">
${this.showCamera?l`<label class="photo-pick photo-pick-camera ${i}" role="button" tabindex="0"
aria-label=${t} title=${this.compact?t:f}
@click=${this._onCameraClick} @keydown=${this._onKeydown}>
<ha-icon icon="mdi:camera"></ha-icon>
${this.compact?f:l`<span>${t}</span>`}
<input type="file" accept=${this.accept} capture="environment"
?disabled=${this._locked} @change=${this._onInput} />
</label>`:f}
${this.showGallery?l`<label class="photo-pick photo-pick-gallery ${i}" role="button" tabindex="0"
aria-label=${r} title=${this.compact?r:f}
@keydown=${this._onKeydown}>
<ha-icon icon="mdi:image-multiple"></ha-icon>
${this.compact?f:l`<span>${r}</span>`}
<input type="file" accept=${this.accept} ?multiple=${!this._singlePick}
?disabled=${this._locked} @change=${this._onInput} />
</label>`:f}
</div>
${this.showGallery&&this._singlePick?l`<div class="photo-android-hint">${o("photos_android_hint",e)}</div>`:f}
${this.showCamera&&this._inAppCamera?l`<ms-camera-capture .lang=${e}
@photo-captured=${n=>this._emit([n.detail.file])}
@capture-unavailable=${this._onCameraUnavailable}></ms-camera-capture>`:f}
`}};a([h({type:String})],y.prototype,"lang",2),a([h({type:Boolean})],y.prototype,"disabled",2),a([h({type:Boolean})],y.prototype,"busy",2),a([h({type:String})],y.prototype,"accept",2),a([h({type:Boolean})],y.prototype,"showCamera",2),a([h({type:Boolean})],y.prototype,"showGallery",2),a([h({type:Boolean})],y.prototype,"compact",2),a([h({type:Number})],y.prototype,"remaining",2),a([_()],y.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",y);var $=Q,c=class extends k{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 T(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((i,t)=>[String(t),!!this.checklistPrefill[i]]).filter(([,i])=>i)),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(i=>[I(i),{...i}])),this._usedQtyText={})}_rangeError(e,i){let t=this.lang;return o("settings_value_out_of_range",t).replace("{min}",E(e,t,{maximumFractionDigits:2})).replace("{max}",E(i,t,{maximumFractionDigits:2}))}_toggleCheck(e){let i=String(e);this._checklistState={...this._checklistState,[i]:!this._checklistState[i]}}_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},i=this._notes.trim();if(i&&(e.notes=i),this._cost){let s=parseFloat(this._cost);isNaN(s)||(e.cost=s)}let t=V(this._duration);if(t!==null&&(e.duration=t),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(A(this._completedAt)>Date.now()){this._error=o("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 s={};for(let d of this.readings){let m=(this._readingValues[d.id]??"").trim();if(m==="")continue;let u=parseFloat(m.replace(",","."));isNaN(u)||(s[d.id]=u)}Object.keys(s).length>0&&(e.reading_values=s)}else if(this._readingValue!==""){let s=parseFloat(this._readingValue);isNaN(s)||(e.reading_value=s)}if(this.restockDefault!==null&&this._restockQty.trim()!==""){let s=parseFloat(this._restockQty.replace(",","."));if(!Number.isFinite(s)||s<w[0]||s>w[1]){this._error=this._rangeError(...w);return}e.restock_quantity=s}if(this.parts.length>0){let s=[];for(let[d,m]of Object.entries(this._usedParts)){let u=this._usedQtyText[d],v=u===void 0?m.quantity:parseFloat(u.replace(",","."));if(!Number.isFinite(v)||v<$[0]||v>$[1]){this._error=this._rangeError(...$);return}s.push({...m,quantity:v})}e.used_parts=s.map(d=>d.entry_id?{part_id:d.part_id,quantity:d.quantity,entry_id:d.entry_id}:{part_id:d.part_id,quantity:d.quantity})}let r=await j(this,e,{busy:s=>{this._loading=s},lang:this.lang,fallbackKey:"save_error",onError:s=>{this._error=s}});if(r===void 0)return;this._photos.markAttached(),this._open=!1;let n={entryId:this.entryId,taskId:this.taskId,taskName:this.taskName,undo:r?.undo===!0};this.dispatchEvent(new CustomEvent("task-completed",{detail:n}))}_renderReadingField(e,i){let t=this._completedAt?A(this._completedAt):NaN,r=H(this.readingHistory,e.id,isNaN(t)?void 0:t),n=e.unit||this.readingUnit,s=(this._readingValues[e.id]??"").trim(),d=s===""?NaN:parseFloat(s.replace(",",".")),m=r!==void 0&&!isNaN(d)&&d<r.value,u=r!==void 0?E(r.value,i,{maximumFractionDigits:3}):"";return l`
<label class="field reading-field">
<span class="field-label">${e.name}${n?` (${n})`:""}</span>
<input type="text" inputmode="decimal" class="field-input"
placeholder=${r!==void 0?o("reading_last",i).replace("{value}",u):""}
.value=${this._readingValues[e.id]??""}
@input=${v=>{this._readingValues={...this._readingValues,[e.id]:v.target.value}}} />
${m?l`<span class="reading-warn">${o("reading_below_last",i).replace("{value}",u)}</span>`:f}
</label>`}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(i=>!e[i])}_demands(e){return this.requiredFields.includes(e)}_req(e){return this._demands(e)?l`<span class="req-mark" aria-hidden="true">*</span>`:f}_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,i=!1;for(let t of Object.values(this._usedParts)){let r=this.parts.find(s=>I({part_id:s.id,entry_id:s.entry_id})===I(t)),n=U(r);n!==null&&(e+=n*(t.quantity||1),i=!0)}return i?Math.round(e*100)/100:null}_renderCostSuggestion(e){let i=this._purchaseSuggestion();if(this.restockDefault!==null){let s=this.partsCostMode==="use"?l`<div class="cost-note">${o("cost_purchase_use_hint",e)}</div>`:f;if(this._cost.trim()!==""||i==null||i<=0)return s;let d=q(i,this.currencySymbol,e);return l`<button
type="button"
class="cost-suggestion"
@click=${()=>this._cost=String(Math.round(i*100)/100)}
>${o("cost_from_parts",e).replace("{amount}",d)}</button>${s}`}let t=this._partsValue();if(t==null||t<=0)return f;let r=q(t,this.currencySymbol,e),n=this.partsCostMode==="use"?"cost_parts_booked":"cost_parts_info";return l`<div class="cost-note">${o(n,e).replace("{amount}",r)}</div>`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=`${P()}:00`}render(){if(!this._open)return l``;let e=this.lang||this.hass?.language||"en",i=this._error||this._photos.errorText(e);return l`
<ha-dialog open @closed=${this._close}>
<div class="dialog-title">${o("complete_title",e)}${this.taskName}</div>
${this.phaseLabel?l`<div class="phase-line">${o("phase_current",e)}: ${this.phaseLabel}</div>`:f}
${this.requireTagScan&&!this.viaTagScan?l`<div class="scan-required-note">${o("require_tag_scan_hint",e)}</div>`:f}
<div class="content">
${i?l`<div class="error">${i}</div>`:f}
${this.checklist.length>0?l`
<div class="checklist-section">
<label class="checklist-label">${o("checklist",e)}</label>
${this.checklist.map((t,r)=>l`
<label class="checklist-item" @click=${()=>this._toggleCheck(r)}>
<input type="checkbox" .checked=${!!this._checklistState[String(r)]} />
<span>${t}</span>
</label>
`)}
</div>
`:f}
${this.readings.length>0?l`<div class="readings-block">
<span class="field-label">${o("readings_section",e)}</span>
${this.readings.map(t=>this._renderReadingField(t,e))}
</div>`:this.taskType==="reading"?l`
<label class="field">
<span class="field-label">${o("reading_value_label",e)}${this.readingUnit?` (${this.readingUnit})`:""}</span>
<input type="number" step="any" class="field-input"
.value=${this._readingValue}
@input=${t=>this._readingValue=t.target.value} />
</label>`:f}
${this.parts.length?l`<div class="used-parts">
<span class="field-label">${o("complete_parts_used",e)}</span>
${this.parts.map(t=>{let r=I({part_id:t.id,entry_id:t.entry_id}),n=this._usedParts[r],s=n!==void 0,d=t.entry_id?{part_id:t.id,quantity:1,entry_id:t.entry_id}:{part_id:t.id,quantity:1};return l`<div class="used-part-row">
<label class="used-part-check">
<input type="checkbox" .checked=${s}
@change=${m=>{let u={...this._usedParts};if(m.target.checked)u[r]=u[r]||d;else{delete u[r];let v={...this._usedQtyText};delete v[r],this._usedQtyText=v}this._usedParts=u}} />
<span
>${t.name}${t.owner_name?l`<span class="used-part-owner"> (${t.owner_name})</span>`:f}${t.stock!==null&&t.stock!==void 0?` (${F(t.stock,t.unit,e)})`:""}</span
>
</label>
${s?l`<input class="used-part-qty" type="number" min=${$[0]} max=${$[1]} step="0.01"
.value=${this._usedQtyText[r]??String(n.quantity)}
@input=${m=>{let u=m.target.value;this._usedQtyText={...this._usedQtyText,[r]:u};let v=parseFloat(u.replace(",","."));Number.isFinite(v)&&v>=$[0]&&(this._usedParts={...this._usedParts,[r]:{...d,quantity:v}})}} />`:f}
</div>`})}
</div>`:this.consumesInfo.length?l`<div class="consumes-hint">
${this.consumesInfo.map(t=>l`<div>${t}</div>`)}
</div>`:f}
${this.restockDefault!==null?l`
<label class="field">
<span class="field-label">${o("restock_quantity_label",e)}${this.restockPackage?` (\xD7 ${this.restockPackage})`:""}</span>
<input type="number" step="0.01" min=${w[0]} max=${w[1]} class="field-input"
.value=${this._restockQty}
@input=${t=>this._restockQty=t.target.value} />
</label>`:f}
<!-- Native <input>s rather than <ha-textfield>: when this dialog
is opened from a Lovelace card via dialog-mount, ha-textfield
isn't yet registered (HA loads it lazily when its own panels
need it) so the elements render with zero height and the user
only sees the title + Cancel/Complete buttons — the original
bug report. Native inputs always render. -->
<label class="field">
<span class="field-label">${this._demands("notes")?o("notes_label",e):o("notes_optional",e)}${this._req("notes")}</span>
<!-- Several lines (#202): what was done, one line each. The
history and the printouts keep the line breaks; they show
notes as plain text, so no Markdown hint here. -->
<textarea class="field-input notes-input" rows="3"
.value=${this._notes}
@input=${t=>this._notes=t.target.value}></textarea>
</label>
<div class="field">
<span class="field-label">${this._demands("cost")?o("cost",e):o("cost_optional",e)}${this._req("cost")}</span>
<ms-cost-input .lang=${e} .value=${this._cost}
@value-changed=${t=>this._cost=t.detail.value}></ms-cost-input>
${this._renderCostSuggestion(e)}
</div>
<label class="field">
<span class="field-label">${this._demands("duration")?o("quick_complete_defaults_duration",e):o("duration_minutes",e)}${this._req("duration")}</span>
<input type="number" step="1" min="0" inputmode="numeric" class="field-input"
.value=${this._duration}
@input=${t=>this._duration=t.target.value} />
</label>
<div class="field">
<span class="field-label">${o("completed_at_optional",e)}</span>
${this._completedAt?l`<ms-date-field
kind="datetime"
clearable
.hass=${this.hass}
.lang=${e}
.value=${this._completedAt}
.helper=${N(e)}
@value-changed=${t=>this._completedAt=t.detail.value}
></ms-date-field>`:l`<button type="button" class="backdate-pick" @click=${this._pickCompletedAt}>
<ha-icon icon="mdi:calendar-clock"></ha-icon>${o("completed_at_pick",e)}
</button>`}
</div>
<div class="field">
<span class="field-label">${this._demands("photo")?o("completion_photos",e):o("completion_photos_optional",e)}${this._req("photo")}</span>
${this._photos.photos.length>0?l`<div class="photo-strip">
${this._photos.photos.map(t=>l`
<div class="photo-preview">
<img src=${t.preview} alt="" />
<button type="button" class="photo-remove" @click=${()=>this._photos.remove(t.id)}
title="${o("remove",e)}">✕</button>
</div>`)}
</div>`:f}
${this._photos.full?l`<div class="photo-limit">${o("photos_limit",e).replace("{max}",String(this._photos.max))}</div>`:l`<ms-photo-picker .lang=${e} .busy=${this._photos.uploading} .remaining=${this._photos.remaining}
@files-picked=${t=>this._photos.addFiles(t.detail.files)}
></ms-photo-picker>`}
</div>
${this.adaptiveEnabled?l`
<div class="feedback-section">
<label class="feedback-label">${o("was_maintenance_needed",e)}</label>
<div class="feedback-buttons">
<button
class="feedback-btn ${this._feedback==="needed"?"selected":""}"
@click=${()=>this._setFeedback("needed")}
>${o("feedback_needed",e)}</button>
<button
class="feedback-btn ${this._feedback==="not_needed"?"selected":""}"
@click=${()=>this._setFeedback("not_needed")}
>${o("feedback_not_needed",e)}</button>
<button
class="feedback-btn ${this._feedback==="not_sure"?"selected":""}"
@click=${()=>this._setFeedback("not_sure")}
>${o("feedback_not_sure",e)}</button>
</div>
</div>
`:f}
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._close}>
${o("cancel",e)}
</ha-button>
<ha-button
@click=${this._complete}
.disabled=${this._loading||this._photos.uploading||this._missingRequired.length>0}
title=${this._photos.uploading?o("uploading",e):this._missingRequired.length?this._missingRequired.map(t=>o("err_required",e).replace("{field}",o(B[t]??t,e))).join(" \xB7 "):""}
>
${this._loading?o("completing",e):o("complete",e)}
</ha-button>
</div>
</ha-dialog>
`}};c.styles=[C,Z,x`
.req-mark {
color: var(--error-color, #f44336);
margin-left: 2px;
font-weight: 600;
}
.notes-input { resize: vertical; line-height: 1.4; }
/* #104: one-click cost suggestion from parts — quiet link-style chip. */
.cost-note {
font-size: 12px;
color: var(--secondary-text-color);
margin-top: 4px;
line-height: 1.4;
}
.cost-suggestion {
align-self: flex-start;
margin-top: 4px;
padding: 0;
border: none;
background: none;
color: var(--primary-color);
font-size: 12.5px;
cursor: pointer;
text-decoration: underline dotted;
text-underline-offset: 2px;
}
.dialog-title {
font-size: 18px;
font-weight: 500;
padding-bottom: 12px;
}
.scan-required-note {
margin: -4px 0 12px;
padding: 8px 10px;
border-radius: 6px;
background: rgba(255, 152, 0, 0.12);
color: var(--primary-text-color);
font-size: 13px;
}
.phase-line {
margin-top: -8px;
padding-bottom: 12px;
font-size: 13px;
color: var(--secondary-text-color);
}
.content {
display: flex;
flex-direction: column;
gap: 16px;
min-width: 300px;
}
.dialog-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
padding-top: 16px;
}
.consumes-hint {
font-size: 13px;
color: var(--secondary-text-color);
border-left: 3px solid var(--primary-color);
padding: 4px 8px;
margin: 4px 0 8px;
}
/* #99: editable per-completion parts selection */
.used-parts { margin: 4px 0 8px; display: flex; flex-direction: column; gap: 4px; }
.used-part-row { display: flex; align-items: center; gap: 8px; }
.used-part-check {
display: flex; align-items: center; gap: 6px; flex: 1;
font-size: 13px; cursor: pointer;
}
.used-part-check input { cursor: pointer; }
/* #111: whose stock this row draws on. Muted but never omitted — an
unlabelled foreign pool is indistinguishable from an own part. */
.used-part-owner { color: var(--secondary-text-color); }
.used-part-qty {
width: 76px; padding: 4px 6px; border-radius: 4px; font: inherit; font-size: 13px;
border: 1px solid var(--divider-color);
background: var(--card-background-color);
color: var(--primary-text-color);
}
.error {
color: var(--error-color, #f44336);
font-size: 13px;
}
/* .field/.field-label/.field-input come from nativeFieldStyles */
/* #161 phase 2: the per-slot reading fields */
.readings-block { display: flex; flex-direction: column; gap: 8px; }
.readings-block > .field-label { margin-bottom: -4px; }
.reading-warn {
font-size: 12px;
color: var(--warning-color, #ff9800);
}
/* .photo-pick / .photo-pickers / .photo-android-hint come from photoPickerStyles */
/* #163: the backdate moment starts EMPTY (= now); the button seeds the
HA date+time picker with the current minute instead of the picker's
own 00:00 default, so a backdated completion never lands at midnight
by accident. */
.backdate-pick {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
border: 1px dashed var(--divider-color);
border-radius: 8px;
background: transparent;
cursor: pointer;
font: inherit;
font-size: 13px;
color: var(--secondary-text-color);
width: fit-content;
--mdc-icon-size: 18px;
}
.backdate-pick:hover { border-color: var(--primary-color); }
/* #161: several photos per completion — tiles wrap into a strip,
the two pickers (camera / gallery) sit underneath while there is
room left under the cap. */
.photo-strip {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin: 8px 0; /* room for the remove badges above the tiles */
}
.photo-limit {
font-size: 12px;
color: var(--secondary-text-color);
}
.photo-preview {
position: relative;
width: fit-content;
}
/* Uniform tiles: a tiny or portrait shot must not collapse the strip. */
.photo-preview img {
width: 96px;
height: 96px;
object-fit: cover;
border-radius: 8px;
display: block;
background: var(--secondary-background-color, rgba(0,0,0,0.06));
}
.photo-remove {
position: absolute;
top: -8px;
right: -8px;
width: 24px;
height: 24px;
border-radius: 50%;
border: none;
background: var(--error-color, #db4437);
color: #fff;
cursor: pointer;
font-size: 12px;
line-height: 1;
}
.checklist-section {
display: flex;
flex-direction: column;
gap: 8px;
padding: 8px 0;
border-bottom: 1px solid var(--divider-color);
margin-bottom: 4px;
}
.checklist-label {
font-weight: 500;
font-size: 13px;
color: var(--secondary-text-color);
}
.checklist-item {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
padding: 4px 0;
font-size: 14px;
}
.checklist-item input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
.feedback-section {
display: flex;
flex-direction: column;
gap: 8px;
padding: 8px 0;
border-top: 1px solid var(--divider-color);
}
.feedback-label {
font-weight: 500;
font-size: 13px;
color: var(--secondary-text-color);
}
.feedback-buttons {
display: flex;
gap: 8px;
}
.feedback-btn {
flex: 1;
padding: 8px 12px;
border: 1px solid var(--divider-color);
border-radius: 8px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
font-size: 13px;
cursor: pointer;
text-align: center;
transition: all 0.2s;
}
.feedback-btn:hover {
background: var(--secondary-background-color, #f5f5f5);
}
.feedback-btn.selected {
background: var(--primary-color);
color: var(--text-primary-color, #fff);
border-color: var(--primary-color);
}
`],a([h({attribute:!1})],c.prototype,"hass",2),a([h()],c.prototype,"entryId",2),a([h()],c.prototype,"taskId",2),a([h()],c.prototype,"taskName",2),a([h()],c.prototype,"lang",2),a([h({type:Array})],c.prototype,"checklist",2),a([h({type:Boolean})],c.prototype,"adaptiveEnabled",2),a([h()],c.prototype,"taskType",2),a([h()],c.prototype,"readingUnit",2),a([h({attribute:!1})],c.prototype,"readings",2),a([h({attribute:!1})],c.prototype,"readingHistory",2),a([h({attribute:!1})],c.prototype,"restockDefault",2),a([h({attribute:!1})],c.prototype,"restockUnitCost",2),a([h({attribute:!1})],c.prototype,"restockPackage",2),a([h()],c.prototype,"currencySymbol",2),a([h({attribute:!1})],c.prototype,"partsCostMode",2),a([h({attribute:!1})],c.prototype,"parts",2),a([h({attribute:!1})],c.prototype,"consumesParts",2),a([h({type:Array})],c.prototype,"consumesInfo",2),a([h({type:Array})],c.prototype,"requiredFields",2),a([h()],c.prototype,"phaseLabel",2),a([h({type:Boolean})],c.prototype,"requireTagScan",2),a([h({type:Boolean})],c.prototype,"viaTagScan",2),a([_()],c.prototype,"_open",2),a([_()],c.prototype,"_notes",2),a([_()],c.prototype,"_cost",2),a([_()],c.prototype,"_duration",2),a([_()],c.prototype,"_loading",2),a([_()],c.prototype,"_error",2),a([_()],c.prototype,"_checklistState",2),a([_()],c.prototype,"_feedback",2),a([_()],c.prototype,"_readingValue",2),a([_()],c.prototype,"_readingValues",2),a([_()],c.prototype,"_restockQty",2),a([_()],c.prototype,"_completedAt",2),a([_()],c.prototype,"_usedParts",2),a([_()],c.prototype,"_usedQtyText",2),a([h({attribute:!1})],c.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",c);export{S as a,Z as b,T as c,c as d};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{b as s}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OUHDI2FL.js";async function a(o,n,t=300){return(await o.connection.sendMessagePromise({type:"auth/sign_path",path:n,expires:t})).path}async function r(o,n,t=300){return a(o,`/api/maintenance_supporter/document/${n}`,t)}async function p(o,n,t=""){let e=window.open("about:blank","_blank");try{let i=await r(o,n);e&&(e.location.href=new URL(i+t,window.location.origin).href)}catch(i){throw e&&e.close(),i}}async function l(o,n,t){s(await r(o,n,30),t)}function m(o,n=null){let t=URL.createObjectURL(new Blob([o],{type:"text/html"}));n&&!n.closed?n.location.href=t:window.open(t,"_blank"),setTimeout(()=>URL.revokeObjectURL(t),6e4)}function u(){return window.open("about:blank","_blank")}export{a,r as b,p as c,l as d,m as e,u as f};
@@ -0,0 +1,234 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OUHDI2FL.js";import{H as k,a,b as f,c as n,f as u,h as x,l as h,m as c,s as e}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";function d(r){return r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function _(r){return!r.startsWith("data:image/svg+xml,")&&!r.startsWith("data:image/png;base64,")?"":d(r)}function y(r){return r.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var l=class extends x{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||k(this.hass)}openForObject(t,i){this._entryId=t,this._taskId=null,this._objectName=i,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}openForTask(t,i,s,o){this._entryId=t,this._taskId=i,this._objectName=s,this._taskName=o,this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}async _generate(){let t=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null;try{let i={type:"maintenance_supporter/qr/generate",entry_id:this._entryId,url_mode:this._urlMode};this._taskId&&(i.task_id=this._taskId);let s=[this.hass.connection.sendMessagePromise({...i,action:"view"})];this._taskId&&(s.push(this.hass.connection.sendMessagePromise({...i,action:"complete"})),await this._hasQuickCompleteDefaults()&&s.push(this.hass.connection.sendMessagePromise({...i,action:"quick_complete"})));let o=await Promise.all(s);if(t!==this._generateSeq)return;this._viewResult=o[0],o.length>1&&(this._completeResult=o[1]),o.length>2&&(this._quickResult=o[2])}catch(i){if(t!==this._generateSeq)return;let s=i?.code,o=i?.message;this._error=s==="no_url"||typeof o=="string"&&o.includes("No Home Assistant URL")?e("qr_error_no_url",this._dialogLang):e("qr_error",this._dialogLang)}finally{t===this._generateSeq&&(this._loading=!1)}}async _hasQuickCompleteDefaults(){try{let i=((await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId})).tasks||[]).find(s=>s.id===this._taskId);return!!i?.quick_complete_defaults&&Object.keys(i.quick_complete_defaults).length>0}catch{return!1}}_setUrlMode(t){this._urlMode!==t&&(this._urlMode=t,this._generate())}_print(){if(!this._viewResult)return;let t=this._viewResult,i=t.label.task_name?`${t.label.object_name} \u2014 ${t.label.task_name}`:t.label.object_name,s=[t.label.manufacturer,t.label.model].filter(Boolean).join(" "),o=window.open("","_blank","width=600,height=500");if(!o)return;let p=this._dialogLang,m=d(i),g=d(s),v=!!this._completeResult,b=!!this._quickResult,w=d(e("qr_action_view",p)),$=d(e("qr_action_complete",p)),R=d(e("qr_action_quick_complete",p));o.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
<meta name="color-scheme" content="light">
<title>${m}</title>
<style>
/* Printable sheet \u2014 must not inherit the phone's dark theme. The QR images
carry their own white quiet zone and stay scannable either way, but the
labels below are explicit dark greys and would vanish on a WebView's dark
canvas. Same reasoning as helpers/report.ts. */
:root{color-scheme:light}
body{font-family:sans-serif;text-align:center;padding:20px;background:#fff;color:#1a1a1a}
h2{margin:0 0 4px}
.sub{color:#666;font-size:14px;margin-bottom:16px}
.qr-row{display:flex;justify-content:center;gap:24px;margin:12px 0}
.qr-col{display:flex;flex-direction:column;align-items:center;gap:6px}
.qr-col img{width:${b?"170px":v?"200px":"280px"}}
.qr-label{font-size:13px;font-weight:500;color:#333}
.url{font-size:10px;color:#999;word-break:break-all;margin-top:8px;max-width:480px}
</style></head><body>
<h2>${m}</h2>
${g?`<div class="sub">${g}</div>`:""}
<div class="qr-row">
<div class="qr-col">
<img src="${_(this._viewResult.svg_data_uri)}" alt="QR Info" />
<div class="qr-label">${w}</div>
</div>
${v?`<div class="qr-col">
<img src="${_(this._completeResult.svg_data_uri)}" alt="QR Complete" />
<div class="qr-label">${$}</div>
</div>`:""}
${b?`<div class="qr-col">
<img src="${_(this._quickResult.svg_data_uri)}" alt="QR Quick-complete" />
<div class="qr-label">${R}</div>
</div>`:""}
</div>
<div class="url">${d(this._viewResult.url)}</div>
<script>setTimeout(()=>window.print(),300)<\/script>
</body></html>`),o.document.close()}_downloadSvg(t,i){let s=decodeURIComponent(t.svg_data_uri.replace("data:image/svg+xml,","")),o=this._taskName?`${this._objectName}-${this._taskName}`:this._objectName;q(s,`qr-${y(o)}-${i}.svg`,"image/svg+xml")}_close(){this._open=!1,this._viewResult=null,this._completeResult=null,this._quickResult=null,this._error="",this._loading=!1}render(){if(!this._open)return n``;let t=this._dialogLang,i=this._taskName?`${e("qr_code",t)}: ${this._objectName} \u2014 ${this._taskName}`:`${e("qr_code",t)}: ${this._objectName}`,s=!!this._viewResult;return n`
<ha-dialog open @closed=${this._close}>
<div class="dialog-title">${i}</div>
<div class="content">
${this._loading?n`<div class="loading">${e("qr_generating",t)}</div>`:this._error?n`<div class="error">${this._error}</div>`:s?n`
<div class="qr-pair">
<div class="qr-item">
<img
class="qr-image ${this._completeResult?"small":""}"
src="${this._viewResult.svg_data_uri}"
alt="QR Info"
/>
<div class="qr-item-label">${e("qr_action_view",t)}</div>
<button class="dl-btn"
@click=${()=>this._downloadSvg(this._viewResult,"info")}>
<ha-icon icon="mdi:download"></ha-icon>
${e("qr_download",t)}
</button>
</div>
${this._completeResult?n`
<div class="qr-item">
<img
class="qr-image small"
src="${this._completeResult.svg_data_uri}"
alt="QR Complete"
/>
<div class="qr-item-label">${e("qr_action_complete",t)}</div>
<button class="dl-btn"
@click=${()=>this._downloadSvg(this._completeResult,"complete")}>
<ha-icon icon="mdi:download"></ha-icon>
${e("qr_download",t)}
</button>
</div>
`:u}
${this._quickResult?n`
<div class="qr-item quick">
<img
class="qr-image small"
src="${this._quickResult.svg_data_uri}"
alt="QR Quick-complete"
/>
<div class="qr-item-label">${e("qr_action_quick_complete",t)}</div>
<button class="dl-btn"
@click=${()=>this._downloadSvg(this._quickResult,"quick-complete")}>
<ha-icon icon="mdi:download"></ha-icon>
${e("qr_download",t)}
</button>
</div>
`:u}
</div>
<div class="url-display">${this._viewResult.url}</div>
`:u}
<div class="action-row">
<label>${e("qr_url_mode",t)}</label>
<div class="action-toggle">
<button class="toggle-btn ${this._urlMode==="companion"?"active":""}"
@click=${()=>this._setUrlMode("companion")}>${e("qr_mode_companion",t)}</button>
<button class="toggle-btn ${this._urlMode==="local"?"active":""}"
@click=${()=>this._setUrlMode("local")}>${e("qr_mode_local",t)}</button>
<button class="toggle-btn ${this._urlMode==="server"?"active":""}"
@click=${()=>this._setUrlMode("server")}>${e("qr_mode_server",t)}</button>
</div>
</div>
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._close}>
${e("cancel",t)}
</ha-button>
<ha-button
@click=${this._print}
.disabled=${!s}
>
${e("qr_print",t)}
</ha-button>
</div>
</ha-dialog>
`}};l.styles=f`
.dialog-title {
font-size: 18px;
font-weight: 500;
padding-bottom: 12px;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
min-width: 300px;
}
.dialog-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
padding-top: 16px;
}
.qr-pair {
display: flex;
flex-wrap: wrap; /* three codes (quick-complete, #192) wrap on a phone */
gap: 20px;
justify-content: center;
width: 100%;
}
.qr-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
}
.qr-image {
width: 240px;
height: 240px;
image-rendering: pixelated;
}
.qr-image.small {
width: 180px;
height: 180px;
}
.qr-item-label {
max-width: 180px;
font-size: 12px;
font-weight: 500;
color: var(--secondary-text-color);
text-align: center;
}
.dl-btn {
display: inline-flex;
align-items: center;
gap: 6px;
background: none;
border: 1px solid var(--divider-color, #e0e0e0);
cursor: pointer;
font-size: 13px;
color: var(--primary-text-color);
padding: 6px 14px;
border-radius: 18px;
transition: background 0.2s, border-color 0.2s;
}
.dl-btn:hover {
background: var(--secondary-background-color, #f5f5f5);
border-color: var(--primary-color);
}
.dl-btn ha-icon {
--mdc-icon-size: 18px;
}
.url-display {
font-size: 11px;
color: var(--secondary-text-color);
word-break: break-all;
text-align: center;
max-width: 400px;
}
.loading {
padding: 40px 0;
color: var(--secondary-text-color);
}
.error {
padding: 20px 0;
color: var(--error-color, #f44336);
}
.action-row {
display: flex;
flex-direction: column;
gap: 6px;
width: 100%;
}
.action-row label {
font-size: 13px;
color: var(--secondary-text-color);
}
.action-toggle {
display: flex;
gap: 4px;
background: var(--divider-color, #e0e0e0);
border-radius: 6px;
padding: 3px;
}
.toggle-btn {
flex: 1;
padding: 8px 12px;
border: none;
background: transparent;
color: var(--primary-text-color);
cursor: pointer;
border-radius: 4px;
font-size: 13px;
transition: all 0.2s;
line-height: 1.3;
}
.toggle-btn:hover {
background: rgba(0, 0, 0, 0.05);
}
.toggle-btn.active {
background: var(--primary-color);
color: var(--text-primary-color, #fff);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}
`,a([h({attribute:!1})],l.prototype,"hass",2),a([h()],l.prototype,"lang",2),a([c()],l.prototype,"_open",2),a([c()],l.prototype,"_loading",2),a([c()],l.prototype,"_error",2),a([c()],l.prototype,"_viewResult",2),a([c()],l.prototype,"_completeResult",2),a([c()],l.prototype,"_quickResult",2),a([c()],l.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",l);export{l as a};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
function r(t){return String(t??"").replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}export{r as a};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{c as r,f as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var a=["#c62828","#ad1457","#6a1b9a","#4527a0","#283593","#1565c0","#00838f","#2e7d32","#558b2f","#ef6c00","#6d4c41","#546e7a"];function u(e){let s=(e||"").split(/\s+/).filter(Boolean);return s.length===0?"?":s.length===1?s[0][0].toUpperCase():(s[0][0]+s[s.length-1][0]).toUpperCase()}function c(e){let s=0;for(let n of e)s=s*31+n.charCodeAt(0)>>>0;return a[s%a.length]}function o(e){return e?{id:e.id,name:e.name,initials:e.initials||u(e.name),color:e.color||c(e.id)}:null}function h(e){return e?r`<span class="person-avatar" style="--person-color: ${e.color}" title=${e.name}>${e.initials}</span>`:i}function m(e,s=""){return e?r`<span class="person-chip ${s}" title=${e.name}>${h(e)}<span class="person-name">${e.name}</span></span>`:i}var l=class{constructor(s){this.usersCache=null;this.cacheTimestamp=0;this.CACHE_TTL_MS=6e4;this.hass=s}updateHass(s){this.hass=s}async getUsers(s=!1){let n=Date.now();if(!s&&this.usersCache&&n-this.cacheTimestamp<this.CACHE_TTL_MS)return this.usersCache;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/users/list"});return this.usersCache=t.users,this.cacheTimestamp=n,this.usersCache}catch(t){return console.error("Failed to fetch users:",t),this.usersCache||[]}}async assignUser(s,n,t){await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/assign_user",entry_id:s,task_id:n,user_id:t})}async getTasksByUser(s){return(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/tasks/by_user",user_id:s})).tasks}getUserName(s){return!s||!this.usersCache?null:this.usersCache.find(t=>t.id===s)?.name||null}getPerson(s){return o(this.getUser(s))}getUser(s){return!s||!this.usersCache?null:this.usersCache.find(n=>n.id===s)||null}getCurrentUserId(){return this.hass.user?.id||null}isCurrentUser(s){return s?s===this.getCurrentUserId():!1}clearCache(){this.usersCache=null,this.cacheTimestamp=0}};export{a,o as b,h as c,m as d,l as e};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{O as n,s as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var l={"Completed from dashboard button":"hist_note_button","Completed from the To-do list":"hist_note_todo","Completed by voice":"hist_note_voice","Completed from the notification":"hist_note_notification","Completed via NFC tag":"hist_note_nfc","Completed from the shopping list":"hist_note_shopping_list","Completed from a mirrored to-do list":"hist_note_todo_mirror","Skipped from notification":"hist_note_skipped_notification","Skipped from dashboard button":"hist_note_skipped_button","Sensor trigger activated":"hist_note_sensor_triggered","Initial value set during task creation":"hist_note_initial"},m=[[/^Auto-completed: sensor recovered \((.+)\)$/,"hist_note_auto_recovered",t=>({value:t[1]})],[/^Reset to (\d{4}-\d{2}-\d{2})$/,"hist_note_reset",(t,e)=>({date:n(t[1],e)})],[/^Trigger entity replaced: (.+) → (.+)$/,"hist_note_trigger_replaced",t=>({old:t[1],new:t[2]})],[/^Sensor trigger removed \(entity was: (.+)\)\. Schedule converted to (\w+)\.$/,"hist_note_trigger_removed",(t,e)=>({entity:t[1],schedule:o(t[2],e)})],[/^Entity (.+) removed from compound trigger; (\d+) conditions remain\.$/,"hist_note_compound_removed",t=>({entity:t[1],count:t[2]})]];function h(t,e){if(!t)return"";let i=l[t.trim()];if(i)return o(i,e);for(let[s,d,_]of m){let r=t.trim().match(s);if(r){let c=_(r,e);return o(d,e).replace(/\{(\w+)\}/g,(a,g)=>c[g]??a)}}return t}export{h as a};
@@ -0,0 +1,79 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as r,b as l,c as i,f as o,h as n,l as t}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var e=class extends n{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(s){let a=s.target.value;this.value=a,this.dispatchEvent(new CustomEvent("input",{bubbles:!0,composed:!0,detail:{value:a}}))}render(){return i`
<label class="field">
${this.label?i`<span class="label">${this.label}${this.required?i`<span class="req">*</span>`:o}</span>`:o}
${this.multiline?i`
<textarea
.value=${this.value??""}
rows=${this.rows}
?required=${this.required}
?disabled=${this.disabled}
placeholder=${this.placeholder}
@input=${this._onInput}
@change=${this._onInput}
></textarea>`:i`
<input
.value=${this.value??""}
.type=${this.type}
?required=${this.required}
?disabled=${this.disabled}
placeholder=${this.placeholder}
step=${this.step??o}
min=${this.min??o}
max=${this.max??o}
pattern=${this.pattern??o}
@input=${this._onInput}
@change=${this._onInput}
/>`}
${this.helper?i`<span class="helper">${this.helper}</span>`:o}
</label>
`}};e.styles=l`
:host { display: block; }
.field {
display: flex;
flex-direction: column;
gap: 4px;
}
.label {
font-size: 12px;
color: var(--secondary-text-color, #888);
font-weight: 500;
}
.req { color: var(--error-color, #f44336); margin-left: 2px; }
input {
padding: 8px 10px;
font-size: 14px;
background: var(--secondary-background-color, rgba(0,0,0,0.06));
color: var(--primary-text-color);
border: 1px solid var(--divider-color, rgba(255,255,255,0.12));
border-radius: 6px;
font-family: inherit;
width: 100%;
box-sizing: border-box;
outline: none;
}
input:focus {
border-color: var(--primary-color);
}
input:disabled { opacity: 0.5; cursor: not-allowed; }
textarea {
padding: 8px 10px;
font-size: 14px;
background: var(--secondary-background-color, rgba(0,0,0,0.06));
color: var(--primary-text-color);
border: 1px solid var(--divider-color, rgba(255,255,255,0.12));
border-radius: 6px;
font-family: inherit;
width: 100%;
box-sizing: border-box;
outline: none;
resize: vertical;
}
textarea:focus { border-color: var(--primary-color); }
textarea:disabled { opacity: 0.5; cursor: not-allowed; }
.helper {
font-size: 11px;
color: var(--secondary-text-color);
font-style: italic;
}
`,r([t()],e.prototype,"label",2),r([t()],e.prototype,"value",2),r([t()],e.prototype,"placeholder",2),r([t()],e.prototype,"type",2),r([t({type:Boolean})],e.prototype,"required",2),r([t({type:Boolean})],e.prototype,"disabled",2),r([t()],e.prototype,"step",2),r([t()],e.prototype,"min",2),r([t()],e.prototype,"max",2),r([t()],e.prototype,"pattern",2),r([t()],e.prototype,"helper",2),r([t({type:Boolean})],e.prototype,"multiline",2),r([t({type:Number})],e.prototype,"rows",2);customElements.get("ms-textfield")||customElements.define("ms-textfield",e);
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
var r={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 s(t){try{return localStorage.getItem(t)}catch{return null}}function o(t,e){try{localStorage.setItem(t,e)}catch{}}export{r as a,s as b,o as c};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{b as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NEWWPCTD.js";import{a as l}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-QFIANZWP.js";var a={operatorWriteEnabled:!1,operatorIds:[]};function m(e,t=a){return e?e.is_admin?!0:t.operatorWriteEnabled&&t.operatorIds.includes(e.id):!1}var _=["buttons_compact","buttons","icons"];function p(e){let[t,n]=l.default_warning_days,s=e?.general?.default_warning_days,r=e?.general?.row_action_style;return{features:{...o.features,...e?.features??{}},defaultWarningDays:typeof s=="number"&&Number.isFinite(s)&&s>=t&&s<=n?s:o.defaultWarningDays,rowActionStyle:_.includes(r??"")?r:o.rowActionStyle,access:{operatorWriteEnabled:e?.operator_write_enabled===!0,operatorIds:Array.isArray(e?.admin_panel_user_ids)?e.admin_panel_user_ids.filter(d=>typeof d=="string"):[]},budget:e?.budget??null,rowActionNoticePending:e?.general?.row_action_notice_pending===!0,refsInLists:e?.general?.ref_numbers_in_lists===!0,objectsTableColumns:Array.isArray(e?.objects_table_columns)?e.objects_table_columns:void 0,partsCostMode:i(e?.budget?.parts_cost_mode)}}var o={features:{adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1},defaultWarningDays:7,rowActionStyle:"buttons_compact",access:a,budget:null,rowActionNoticePending:!1,refsInLists:!1,objectsTableColumns:void 0,partsCostMode:"purchase"};function c(){let e=window;return e.__msSettingsCache??={promise:null}}function S(e){let t=c();if(t.promise)return t.promise;let n=e.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(s=>p(s)).catch(()=>(t.promise===n&&(t.promise=null),o));return t.promise=n,n}function y(){c().promise=null}var u=class{constructor(){this._handle=null}schedule(t,n=4e3){this.clear(),this._handle=setTimeout(()=>{this._handle=null,t()},n)}clear(){this._handle!==null&&(clearTimeout(this._handle),this._handle=null)}get pending(){return this._handle!==null}};export{a,m as b,_ as c,p as d,S as e,y as f,u as g};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{H as p,r as g,s as o,v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var w={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"},h={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"};function y(n){let t=n.replace(/_ids?$/,"").split("_").filter(Boolean);if(t.length===0)return n;let e=t.join(" ");return e.charAt(0).toUpperCase()+e.slice(1)}function b(n,t){let e=h[n];if(e){let r=o(e,t);if(r&&r!==e)return r}return y(n)}function k(n){let t=[...n.matchAll(/\['([^']+)'\]/g)].map(i=>i[1]),e=t.length?t[t.length-1]:void 0,r;return(r=n.match(/length of value must be at most (\d+)/))?{field:e,rule:"too_long",param:r[1]}:(r=n.match(/length of value must be at least (\d+)/))?{field:e,rule:"too_short",param:r[1]}:(r=n.match(/value must be at most (\S+)/))?{field:e,rule:"value_too_high",param:r[1]}:(r=n.match(/value must be at least (\S+)/))?{field:e,rule:"value_too_low",param:r[1]}:/required key not provided/.test(n)?{field:e,rule:"required"}:(r=n.match(/expected (\w+)/))?{field:e,rule:"wrong_type",param:r[1]}:/value must be one of/.test(n)?{field:e,rule:"invalid_choice"}:/not a valid value/.test(n)?{field:e,rule:"invalid_value"}:{field:e,rule:"unknown"}}var f=n=>n.toLowerCase().split(/[^a-z0-9]+/).filter(t=>t.length>1);function E(n,t){let e=new Set(f(t));return f(n).every(r=>e.has(r))}function c(n,t,e){if(e=e??o("action_error",t),typeof n=="string")return n;if(typeof n!="object"||n===null)return e;let r=n,i=r.message||r.error?.message||"",_=r.code||r.error?.code||"",l=_?w[_]:void 0,d=v(r.translation_domain??r.error?.translation_domain,r.translation_key??r.error?.translation_key,r.translation_placeholders??r.error?.translation_placeholders);if(d)return d;if(!i&&!l)return e;let s=k(i),m=s.field?b(s.field,t):"",a=u=>o(u,t).replace("{field}",m).replace("{n}",s.param??"");switch(s.rule){case"too_long":return a("err_too_long");case"too_short":return a("err_too_short");case"value_too_high":return a("err_value_too_high");case"value_too_low":return a("err_value_too_low");case"required":return a("err_required");case"wrong_type":return a("err_wrong_type").replace("{type}",s.param??"");case"invalid_choice":return a("err_invalid_choice");case"invalid_value":return a("err_invalid_value");default:if(l){let u=o(l,t);return g(t)==="en"&&i&&!E(i,_)?`${u} (${i})`:u}return i||e}}async function W(n,t,e={}){e.busy?.(!0);try{let r=typeof t=="function"?await t():await n.hass.coLine truncated
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
function c(n){return n==="use"?"use":"purchase"}var s=n=>typeof n=="number"&&Number.isFinite(n)?n:null;function a(n){let t=s(n?.cost);if(t===null)return null;let o=s(n?.package_size);return o&&o>0?t/o:t}function p(n,t){let o=s(t)&&t>0?t:s(n.restock_quantity)||1,e=s(n.package_size);return Math.round(o*(e&&e>0?e:1)*100)/100}function l(n){let t=s(n.cost);if(n.cost_basis!=="use")return t;let o=s(n.parts_cost),e=n.purchase?null:t;return e===null&&o===null?null:(e??0)+(o??0)}function _(n){if(!n)return[];let t=[],o=n.photo_doc_id;typeof o=="string"&&t.push(o);let e=n.photo_doc_ids;Array.isArray(e)&&t.push(...e);let r=[];for(let u of t){if(typeof u!="string")continue;let i=u.trim();if(!(!i||r.includes(i))&&(r.push(i),r.length>=10))break}return r}export{_ as a,c as b,a as c,p as d,l as e};
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
function c(o,t,e){let l=new Blob([o],{type:e}),d=URL.createObjectURL(l),n=document.createElement("a");n.href=d,n.download=t,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(d),6e4)}function r(o,t){let e=document.createElement("a");e.href=o,e.download=t,e.target="_blank",e.rel="noopener",e.style.display="none",document.body.appendChild(e),e.dispatchEvent(new MouseEvent("click")),document.body.removeChild(e)}export{c as a,r as b};
@@ -0,0 +1,217 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as _}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-MN2RZ73S.js";import{H as v,a as s,b as p,c as l,f as o,h,l as c,m as n,s as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var r=class extends h{constructor(){super(...arguments);this.objects=[];this._open=!1;this._loading=!1;this._error="";this._name="";this._manufacturer="";this._model="";this._serialNumber="";this._areaId="";this._installationDate="";this._warrantyExpiry="";this._documentationUrl="";this._notes="";this._haDeviceId="";this._parentEntryId="";this._entryId=null;this._replacing=!1;this._oldDeviceId="";this._replaceDevice="keep"}get _lang(){return v(this.hass)}openCreate(){this._entryId=null,this._name="",this._manufacturer="",this._model="",this._serialNumber="",this._areaId="",this._installationDate="",this._warrantyExpiry="",this._documentationUrl="",this._notes="",this._haDeviceId="",this._parentEntryId="",this._replacing=!1,this._error="",this._open=!0}openReplace(e,a){this._entryId=e,this._replacing=!0,this._name=a.name||"",this._oldDeviceId=a.ha_device_id||"",this._haDeviceId="",this._replaceDevice="keep",this._error="",this._open=!0}openEdit(e,a){this._entryId=e,this._name=a.name||"",this._manufacturer=a.manufacturer||"",this._model=a.model||"",this._serialNumber=a.serial_number||"",this._areaId=a.area_id||"",this._installationDate=a.installation_date||"",this._warrantyExpiry=a.warranty_expiry||"",this._documentationUrl=a.documentation_url||"",this._notes=a.notes||"",this._haDeviceId=a.ha_device_id||"",this._parentEntryId=a.parent_entry_id||"",this._replacing=!1,this._error="",this._open=!0}async _replace(){if(this._loading||!this._entryId)return;let e={type:"maintenance_supporter/object/replace",entry_id:this._entryId,name:this._name.trim()||null};this._oldDeviceId?(this._replaceDevice==="other"&&(e.ha_device_id=this._haDeviceId),this._replaceDevice==="none"&&(e.ha_device_id=null)):this._haDeviceId&&(e.ha_device_id=this._haDeviceId);let a=await _(this,e,{busy:t=>{this._loading=t},fallbackKey:"save_error",onError:t=>{this._error=t}});a!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("object-replaced",{detail:{entry_id:a?.entry_id,device_swap:a?.device_swap}})))}_deviceName(e){let t=this.hass?.devices?.[e];return t?.name_by_user||t?.name||e}_deviceSelector(e){return l`<ha-form
.hass=${this.hass}
.data=${{device:this._haDeviceId||void 0}}
.schema=${[{name:"device",selector:{device:{}}}]}
.computeLabel=${()=>e}
@value-changed=${a=>this._haDeviceId=a.detail.value?.device||""}
></ha-form>`}_renderReplace(){let e=this._lang,a=(d,u)=>l`<label class="radio-row">
<input
type="radio"
name="replace-device"
.checked=${this._replaceDevice===d}
@change=${()=>{this._replaceDevice=d}}
/>
<span>${u}</span>
</label>`,t=this._replaceDevice==="other"&&!this._haDeviceId;return l`
<ha-dialog open @closed=${this._close}>
<div class="dialog-title">${i("replace_object",e)}</div>
<div class="content">
${this._error?l`<div class="error">${this._error}</div>`:o}
<div class="hint">${i("replace_object_prompt",e)}</div>
<ms-textfield
label="${i("replace_name_label",e)}"
.value=${this._name}
@input=${d=>this._name=d.target.value}
></ms-textfield>
${this._oldDeviceId?l`<div class="radio-group" role="radiogroup" aria-label=${i("replace_device_heading",e)}>
<div class="textarea-label">${i("replace_device_heading",e)}</div>
${a("keep",i("replace_device_keep",e).replace("{device}",this._deviceName(this._oldDeviceId)))}
${this._replaceDevice==="keep"?l`<div class="hint">${i("replace_device_keep_hint",e)}</div>`:o}
${a("other",i("replace_device_other",e))}
${this._replaceDevice==="other"?l`${this._deviceSelector(i("replace_device_pick",e))}
<div class="hint">${i("replace_device_other_hint",e)}</div>`:o}
${a("none",i("replace_device_none",e))}
</div>`:this._deviceSelector(i("link_device_optional",e))}
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._close}>
${i("cancel",e)}
</ha-button>
<ha-button @click=${this._replace} .disabled=${this._loading||t}>
${this._loading?i("saving",e):i("replace_object",e)}
</ha-button>
</div>
</ha-dialog>
`}async _save(){if(this._loading||!this._name.trim())return;this._error="";let e={name:this._name,manufacturer:this._manufacturer||null,model:this._model||null,serial_number:this._serialNumber||null,area_id:this._areaId||null,installation_date:this._installationDate||null,warranty_expiry:this._warrantyExpiry||null,documentation_url:this._documentationUrl.trim()||null,notes:this._notes.trim()||null,ha_device_id:this._haDeviceId||null,parent_entry_id:this._parentEntryId||null},a=await _(this,this._entryId?{type:"maintenance_supporter/object/update",entry_id:this._entryId,...e}:{type:"maintenance_supporter/object/create",...e},{busy:t=>{this._loading=t},fallbackKey:"save_error",onError:t=>{this._error=t}});a!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("object-saved",{detail:{device_swap:a?.device_swap}})))}_parentChoices(){return(this.objects||[]).filter(e=>e.entry_id!==this._entryId)}_close(){this._open=!1}render(){if(!this._open)return l``;if(this._replacing)return this._renderReplace();let e=this._lang,a=this._entryId?i("edit_object",e):i("new_object",e);return l`
<ha-dialog open @closed=${this._close}>
<div class="dialog-title">${a}</div>
<div class="content">
${this._error?l`<div class="error">${this._error}</div>`:o}
<ms-textfield
label="${i("name",e)}"
required
.value=${this._name}
@input=${t=>this._name=t.target.value}
></ms-textfield>
<ms-textfield
label="${i("manufacturer_optional",e)}"
.value=${this._manufacturer}
@input=${t=>this._manufacturer=t.target.value}
></ms-textfield>
<ms-textfield
label="${i("model_optional",e)}"
.value=${this._model}
@input=${t=>this._model=t.target.value}
></ms-textfield>
<ms-textfield
label="${i("serial_number_optional",e)}"
.value=${this._serialNumber}
@input=${t=>this._serialNumber=t.target.value}
></ms-textfield>
<ms-textfield
label="${i("documentation_url_optional",e)}"
type="url"
.value=${this._documentationUrl}
@input=${t=>this._documentationUrl=t.target.value}
></ms-textfield>
<ha-area-picker
.hass=${this.hass}
label="${i("area_id_optional",e)}"
.value=${this._areaId}
@value-changed=${t=>this._areaId=t.detail.value||""}
></ha-area-picker>
<ms-date-field
kind="date"
clearable
.hass=${this.hass}
.lang=${e}
label="${i("installation_date_optional",e)}"
.value=${this._installationDate}
@value-changed=${t=>this._installationDate=t.detail.value}
></ms-date-field>
<ms-date-field
kind="date"
clearable
.hass=${this.hass}
.lang=${e}
label="${i("warranty_expiry_optional",e)}"
.value=${this._warrantyExpiry}
@value-changed=${t=>this._warrantyExpiry=t.detail.value}
></ms-date-field>
<ha-form
.hass=${this.hass}
.data=${{device:this._haDeviceId||void 0}}
.schema=${[{name:"device",selector:{device:{}}}]}
.computeLabel=${()=>i("link_device_optional",e)}
@value-changed=${t=>this._haDeviceId=t.detail.value?.device||""}
></ha-form>
${this._parentChoices().length?l`<label class="textarea-field">
<span class="textarea-label">${i("parent_object_optional",e)}</span>
<select
class="parent-select"
.value=${this._parentEntryId}
@change=${t=>this._parentEntryId=t.target.value}
>
<option value="" ?selected=${!this._parentEntryId}>
${i("parent_none",e)}
</option>
${this._parentChoices().map(t=>l`<option
value=${t.entry_id}
?selected=${this._parentEntryId===t.entry_id}
>${t.object.name}</option>`)}
</select>
</label>`:o}
<label class="textarea-field">
<span class="textarea-label">${i("object_notes_optional",e)}</span>
<textarea
rows="3"
.value=${this._notes}
@input=${t=>this._notes=t.target.value}
></textarea>
<span class="md-hint">${i("notes_markdown_hint",e)}</span>
</label>
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._close}>
${i("cancel",this._lang)}
</ha-button>
<ha-button
@click=${this._save}
.disabled=${this._loading||!this._name.trim()}
>
${this._loading?i("saving",this._lang):i("save",this._lang)}
</ha-button>
</div>
</ha-dialog>
`}};r.styles=p`
.dialog-title {
font-size: 18px;
font-weight: 500;
padding-bottom: 12px;
}
.content {
display: flex;
flex-direction: column;
gap: 16px;
min-width: 300px;
}
.dialog-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
padding-top: 16px;
}
ms-textfield {
display: block;
}
.textarea-field {
display: flex; flex-direction: column; gap: 4px;
}
.textarea-label {
font-size: 12px; color: var(--secondary-text-color, #888); font-weight: 500;
}
.textarea-field textarea {
padding: 8px 10px; font-size: 14px; font-family: inherit;
background: var(--secondary-background-color, rgba(0,0,0,0.06));
color: var(--primary-text-color);
border: 1px solid var(--divider-color); border-radius: 6px;
resize: vertical;
}
.textarea-field textarea:focus {
outline: none; border-color: var(--primary-color);
}
.md-hint {
font-size: 11px; color: var(--secondary-text-color); font-style: italic;
}
.parent-select {
padding: 8px 10px; font-size: 14px; font-family: inherit;
background: var(--secondary-background-color, rgba(0,0,0,0.06));
color: var(--primary-text-color);
border: 1px solid var(--divider-color); border-radius: 6px;
}
.error {
color: var(--error-color, #f44336);
font-size: 13px;
}
.hint {
font-size: 13px;
color: var(--secondary-text-color);
line-height: 1.4;
}
.radio-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.radio-row {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
cursor: pointer;
}
.radio-row input {
margin: 0;
}
`,s([c({attribute:!1})],r.prototype,"hass",2),s([c({attribute:!1})],r.prototype,"objects",2),s([n()],r.prototype,"_open",2),s([n()],r.prototype,"_loading",2),s([n()],r.prototype,"_error",2),s([n()],r.prototype,"_name",2),s([n()],r.prototype,"_manufacturer",2),s([n()],r.prototype,"_model",2),s([n()],r.prototype,"_serialNumber",2),s([n()],r.prototype,"_areaId",2),s([n()],r.prototype,"_installationDate",2),s([n()],r.prototype,"_warrantyExpiry",2),s([n()],r.prototype,"_documentationUrl",2),s([n()],r.prototype,"_notes",2),s([n()],r.prototype,"_haDeviceId",2),s([n()],r.prototype,"_parentEntryId",2),s([n()],r.prototype,"_entryId",2),s([n()],r.prototype,"_replacing",2),s([n()],r.prototype,"_oldDeviceId",2),s([n()],r.prototype,"_replaceDevice",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",r);export{r as a};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
var n={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]};function o(e){let r=n[e];if(!r)throw new Error(`not an int-ranged setting: ${e}`);return r}var t=[0,14],_=[0,1440],u=[1,1e4],a=[0,365],d=15,s=[.1,.9],b=[0,365],A=[.01,1e4],E=[.01,1e5],i=[.1,5];export{n as a,o as b,t as c,_ as d,u as e,a as f,d as g,s as h,b as i,A as j,E as k,i as l};
@@ -0,0 +1,88 @@
/*! maintenance_supporter frontend 2.98.0 */
import{O as m,a,b as y,c as s,f as l,h as g,l as o,m as f,s as d}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";function $(n){let t=m("2001-02-03",n).match(/\d+/g)||[],e=v=>t.findIndex(_=>Number(_)===v),h=e(2001),c=e(2),u=e(3);return h===0?"YMD":c>=0&&u>=0&&c<u?"MDY":"DMY"}function p(n,i,t){if(n<1e3||n>9999||i<1||i>12||t<1||t>31)return null;let e=new Date(n,i-1,t);return e.getFullYear()!==n||e.getMonth()!==i-1||e.getDate()!==t?null:`${n}-${String(i).padStart(2,"0")}-${String(t).padStart(2,"0")}`}function b(n,i){let t=n.trim(),e;if(e=t.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/))return p(+e[1],+e[2],+e[3]);if(e=t.match(/^(\d{4})$/))return p(+e[1],1,1);if(e=t.match(/^(\d{1,2})[./](\d{4})$/))return p(+e[2],+e[1],1);if(e=t.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/))return p(+e[3],+e[2],+e[1]);if(e=t.match(/^(\d{1,2})[/-](\d{1,2})[/-](\d{4})$/)){let h=+e[1],c=+e[2],u=+e[3];return $(i)==="MDY"?p(u,h,c):p(u,c,h)}return null}function x(n,i){if(i)switch(n){case"date":return i.split("T")[0];case"time":return i.length===5?`${i}:00`:i;case"datetime":{let[t,e="00:00:00"]=i.split("T");return`${t} ${e.length===5?`${e}:00`:e}`}}}function k(n,i){if(typeof i!="string"||!i)return"";switch(n){case"date":return i.slice(0,10);case"time":return i.slice(0,5);case"datetime":{let[t,e="00:00:00"]=i.split(" ");return`${t}T${e.length===5?`${e}:00`:e}`}}}var r=class extends g{constructor(){super(...arguments);this.kind="date";this.label="";this.value="";this.clearable=!1;this.disabled=!1;this.required=!1;this.lang="en";this._typing=!1;this._typed="";this._typedInvalid=!1}_startTyping(){this._typed=this.value,this._typedInvalid=!1,this._typing=!0,this.updateComplete.then(()=>this.shadowRoot?.querySelector("input.typed")?.focus())}_commitTyped(){if(!this._typed.trim()){this._typing=!1;return}let t=b(this._typed,this.lang);if(!t){this._typedInvalid=!0;return}this._typing=!1,this._typedInvalid=!1,this._emit(t)}_onTypedKey(t){t.key==="Enter"?(t.preventDefault(),this._commitTyped()):t.key==="Escape"&&(t.preventDefault(),this._typing=!1,this._typedInvalid=!1)}_selector(){switch(this.kind){case"date":return{date:{}};case"time":return{time:{no_second:!0}};case"datetime":return{datetime:{}}}}_onSelectorChange(t){t.stopPropagation(),this._emit(k(this.kind,t.detail?.value))}_clear(){this._emit("")}_emit(t){t!==this.value&&(this.value=t,this.dispatchEvent(new CustomEvent("value-changed",{bubbles:!0,composed:!0,detail:{value:t}})))}render(){return s`
<div class="field">
${this.label?s`<span class="label">${this.label}${this.required?s`<span class="req">*</span>`:l}</span>`:l}
<div class="row">
${this._typing?s`<input class="typed" type="text" inputmode="numeric" autocomplete="off"
.value=${this._typed}
placeholder=${m("1978-03-15",this.lang)}
aria-invalid=${this._typedInvalid?"true":"false"}
@input=${t=>{this._typed=t.target.value,this._typedInvalid=!1}}
@keydown=${this._onTypedKey}
@blur=${this._commitTyped} />`:s`<ha-selector
.hass=${this.hass}
.selector=${this._selector()}
.value=${x(this.kind,this.value)}
.required=${this.required}
.disabled=${this.disabled}
@value-changed=${this._onSelectorChange}
></ha-selector>`}
${this.kind==="date"&&!this.disabled&&!this._typing?s`<button type="button" class="type-toggle" title=${d("date_type_toggle",this.lang)} aria-label=${d("date_type_toggle",this.lang)} @click=${this._startTyping}>
<ha-icon icon="mdi:keyboard-outline"></ha-icon>
</button>`:l}
${this.clearable&&this.value&&!this.disabled&&!this._typing?s`<button type="button" class="clear" title=${d("clear",this.lang)} aria-label=${d("clear",this.lang)} @click=${this._clear}>
<ha-icon icon="mdi:close"></ha-icon>
</button>`:l}
</div>
${this._typedInvalid?s`<span class="helper invalid">${d("date_type_invalid",this.lang)}</span>`:this.helper?s`<span class="helper">${this.helper}</span>`:l}
</div>
`}};r.styles=y`
:host { display: block; }
.field {
display: flex;
flex-direction: column;
gap: 4px;
}
.label {
font-size: 12px;
color: var(--secondary-text-color, #888);
font-weight: 500;
}
.req { color: var(--error-color, #f44336); margin-left: 2px; }
.row {
display: flex;
align-items: center;
gap: 4px;
}
ha-selector {
flex: 1;
min-width: 0;
}
.clear, .type-toggle {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
padding: 0;
border: none;
border-radius: 50%;
background: transparent;
color: var(--secondary-text-color);
cursor: pointer;
--mdc-icon-size: 20px;
}
.clear:hover, .type-toggle:hover { background: rgba(var(--rgb-primary-text-color, 0, 0, 0), 0.08); }
.clear:focus-visible, .type-toggle:focus-visible { outline: 2px solid var(--primary-color); }
.helper {
font-size: 11px;
color: var(--secondary-text-color);
font-style: italic;
}
.helper.invalid { color: var(--error-color, #f44336); font-style: normal; }
input.typed {
flex: 1;
min-width: 0;
height: 40px;
box-sizing: border-box;
padding: 0 12px;
border: 1px solid var(--divider-color, #ccc);
border-radius: 4px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
font: inherit;
}
input.typed[aria-invalid="true"] { border-color: var(--error-color, #f44336); }
input.typed:focus { outline: 2px solid var(--primary-color); outline-offset: -1px; }
`,a([o({attribute:!1})],r.prototype,"hass",2),a([o()],r.prototype,"kind",2),a([o()],r.prototype,"label",2),a([o()],r.prototype,"value",2),a([o()],r.prototype,"helper",2),a([o({type:Boolean})],r.prototype,"clearable",2),a([o({type:Boolean})],r.prototype,"disabled",2),a([o({type:Boolean})],r.prototype,"required",2),a([o()],r.prototype,"lang",2),a([f()],r.prototype,"_typing",2),a([f()],r.prototype,"_typed",2),a([f()],r.prototype,"_typedInvalid",2);customElements.get("ms-date-field")||customElements.define("ms-date-field",r);
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{b as x}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4PKMHUVO.js";import{a as H,e as S}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NEWWPCTD.js";import{A as k,B as A,y as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var V=500,B=new Set(["completed","skipped","reset","missed"]);function M(r,e){let o=r.reading_values||[];return o.length?o.filter(n=>typeof n.value=="number").map(n=>({id:n.id,name:n.name||"",value:n.value,unit:n.unit||""})):typeof r.reading_value=="number"?[{id:"",name:"",value:r.reading_value,unit:e||""}]:[]}function O(r){let e=[];for(let o of r){let n=[...o.history??[]].map(t=>({h:t,ts:k(t.timestamp)})).filter(t=>Number.isFinite(t.ts)).sort((t,a)=>t.ts-a.ts),s=new Map;for(let{h:t,ts:a}of n){let y=M(t,o.reading_unit).map(u=>{let f=s.get(u.id);return s.set(u.id,u.value),{name:u.name,value:u.value,unit:u.unit,delta:f==null?null:u.value-f}});if(!B.has(t.type))continue;let c=t.checklist_state&&typeof t.checklist_state=="object"?Object.values(t.checklist_state):null;e.push({ts:a,timestamp:t.timestamp,taskId:o.id,taskName:o.name,type:t.type,cost:S(t),partsCost:typeof t.parts_cost=="number"?t.parts_cost:null,partsCounted:t.cost_basis==="use",purchaseCost:t.cost_basis==="use"&&t.purchase&&typeof t.cost=="number"?t.cost:null,duration:typeof t.duration=="number"?t.duration:null,notes:t.notes??null,completedBy:t.completed_by??null,phaseName:t.phase_id&&o.phases?.[t.phase_id]?.name||null,refNo:typeof t.ref_no=="number"?t.ref_no:null,taskRefNo:typeof o.ref_no=="number"?o.ref_no:null,readings:y,parts:(t.used_parts||[]).filter(u=>u&&(u.name||u.part_id)).map(u=>({name:u.name||u.part_id,quantity:typeof u.quantity=="number"?u.quantity:1})),photoIds:H(t),checklist:c&&c.length?{done:c.filter(Boolean).length,total:c.length}:null})}}return e.sort((o,n)=>n.ts-o.ts||o.taskName.localeCompare(n.taskName)),e}function R(r,e){return r.filter(o=>{if(e.taskId&&o.taskId!==e.taskId)return!1;if(!e.from&&!e.to)return!0;let n=A(o.timestamp);return!(!n||e.from&&n<e.from||e.to&&n>e.to)})}function E(r){let e=0,o=0;for(let n of r)n.type==="completed"&&(e++,n.cost!=null&&(o+=n.cost));return{completed:e,totalCost:o}}var d="__none__",L=36;function T(r){return r.area_id||d}function K(r,e,o){return r===d?o:e?.[r]?.name||r}function Y(r,e){return r===d?"mdi:map-marker-off-outline":e?.[r]?.icon||"mdi:map-marker-outline"}function J(r,e,o){return r.filter(n=>(o||!n.object.archived)&&T(n.object)===e)}function D(r,e){let o=[];for(let n of r){let s=O(n.tasks.map(t=>({id:t.id,name:t.name,history:e(n.entry_id,t),phases:t.phases,ref_no:t.ref_no,reading_unit:t.reading_unit})));for(let t of s)o.push({...t,entryId:n.entry_id,objectName:n.object.name})}return o.sort((n,s)=>s.ts-n.ts||n.objectName.localeCompare(s.objectName)||n.taskName.localeCompare(s.taskName)),o}function W(r,e){let o=(e.taskQuery??"").trim();return R(r,{from:e.from,to:e.to}).filter(n=>(!e.entryId||n.entryId===e.entryId)&&(!o||x(n.taskName,o)))}function Z(r){let{completed:e,totalCost:o}=E(r),n=0,s=0,t=0;for(let a of r)a.type==="completed"&&(a.duration!=null&&(n+=a.duration),!((a.cost??0)<0)&&(s++,t+=a.cost??0));return{completions:e,totalCost:o,avgCost:s?t/s:null,totalDuration:n}}function tt(r,e){let o=new Map;for(let t of e)o.set(t.entry_id,{entryId:t.entry_id,objectName:t.object.name,completions:0,cost:0,share:0});for(let t of r){if(t.type!=="completed")continue;let a=o.get(t.entryId);a&&(a.completions++,t.cost!=null&&(a.cost+=t.cost))}let n=[...o.values()].reduce((t,a)=>t+Math.max(a.cost,0),0),s=[...o.values()].map(t=>({...t,share:n>0?Math.max(t.cost,0)/n:0}));return s.sort((t,a)=>a.cost-t.cost||a.completions-t.completions||t.objectName.localeCompare(a.objectName)),s}function C(r){let[e,o]=r.split("-").map(Number);return[e,o-1]}function I(r,e){return`${r}-${String(e+1).padStart(2,"0")}`}function et(r,e,o=v()){let n=r.filter(i=>i.type==="completed"),s=n.map(i=>A(i.timestamp)),t=s.filter(i=>i!==null),a=t.reduce((i,m)=>m<i?m:i,o),y=t.reduce((i,m)=>m>i?m:i,o),[c,u]=C(e.from||a),[f,h]=C(e.to||y),l=f*12+h-(c*12+u)+1;if(l<=0)return{unit:"month",buckets:[]};let g=l>L?"year":"month",_=[],j=new Map;if(g==="month")for(let i=0;i<l;i++){let m=c+Math.floor((u+i)/12),b=(u+i)%12,p={key:I(m,b),year:m,month:b,cost:0,completions:0};_.push(p),j.set(p.key,p)}else for(let i=c;i<=f;i++){let m={key:String(i),year:i,month:null,cost:0,completions:0};_.push(m),j.set(m.key,m)}return n.forEach((i,m)=>{let b=s[m];if(!b)return;let p=j.get(g==="month"?b.slice(0,7):b.slice(0,4));p&&(p.completions++,i.cost!=null&&(p.cost+=i.cost))}),{unit:g,buckets:_}}function rt(r=v()){let[e,o]=C(r),n=e*12+o-11;return{from:`${I(Math.floor(n/12),n%12)}-01`,to:r}}function nt(r){return{from:`${r}-01-01`,to:`${r}-12-31`}}function w(r){let e=A(r.timestamp);return e?Number(e.slice(0,4)):null}function ot(r,e){let o=new Set([e]);for(let n of r){let s=n.type==="completed"?w(n):null;s!==null&&o.add(s)}return[...o].sort((n,s)=>s-n)}function st(r,e){let o=new Map;for(let s of r){if(!Line truncated
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
async function i(o,n,e){let t=o.auth;if(t?.expired&&t.refreshAccessToken)try{await t.refreshAccessToken()}catch{}return fetch(n,{...e,headers:{...e.headers??{},Authorization:`Bearer ${t?.data?.access_token??""}`}})}var u=500*1024*1024;async function d(o,n,e,t="doc_too_large",s=[]){let r=await i(o,n,{method:"POST",body:e});if(r.status===413)throw new Error(t);if(!r.ok){let a=await r.json().catch(()=>null);throw typeof a?.code=="string"&&s.includes(a.code)?new Error(a.code):new Error("doc_upload_failed")}return await r.json()}async function c(o,n,e,t){let s=new FormData;s.append("entry_id",n);for(let a of t)s.append("tags",a);s.append("file",e,e.name);let r=await d(o,"/api/maintenance_supporter/document/upload",s);if(!r.id)throw new Error("doc_upload_failed");return{id:r.id,deduped:!!r.deduped,duplicate_in_object:r.duplicate_in_object??null}}async function l(o,n,e){return(await c(o,n,e,["photo"])).id}async function m(o,n,e){await Promise.all(e.map(t=>o.connection.sendMessagePromise({type:"maintenance_supporter/documents/discard_upload",entry_id:n,doc_id:t}).catch(()=>{})))}export{u as a,d as b,c,l as d,m as e};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-S7XZBRRU.js";var l=6;async function g(e,i,n){let r=new Array(e.length),a=0,t=async()=>{for(;a<e.length;){let s=a++;r[s]=await n(e[s],s)}},o=Math.min(Math.max(1,i),e.length);return await Promise.all(Array.from({length:o},t)),r}function u(e){let i=e.history?.length??0;return typeof e.history_count!="number"||e.history_count>i}function d(e){return JSON.stringify([e.history_count??null,e.history??[]])}function h(e,i){return`${e}:${i}`}var c=class{constructor(i){this._host=i;this._cache=new Map;this._inFlight=new Map;this._running=0;this._pending=Promise.resolve();this.version=0;i.addController(this)}hostConnected(){}get loading(){return this._running>0}get capped(){for(let i of this._cache.values())if(i.entries.length>=y)return!0;return!1}historyOf(i,n){return this._cache.get(h(i,n.id))?.entries??n.history??[]}sync(i,n){if(!i?.connection)return this._pending;let r=n.filter(t=>u(t.task)).map(t=>({...t,key:h(t.entryId,t.task.id),sig:d(t.task)})).filter(t=>this._cache.get(t.key)?.sig!==t.sig&&this._inFlight.get(t.key)!==t.sig);if(!r.length)return this._pending;for(let t of r)this._inFlight.set(t.key,t.sig);this._running++,this._host.requestUpdate();let a=g(r,l,async t=>{let o;try{let s=await i.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:t.entryId,task_id:t.task.id});o=Array.isArray(s?.history)?s.history:t.task.history??[]}catch{o=t.task.history??[]}this._inFlight.get(t.key)===t.sig&&(this._inFlight.delete(t.key),this._cache.set(t.key,{sig:t.sig,entries:o}))}).then(()=>{this._running--,this.version++,this._host.requestUpdate()});return this._pending=Promise.all([this._pending,a]).then(()=>{}),this._pending}settled(){return this._pending}};export{c as a};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{d as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-CH2AE3ZD.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-W3CDWY4U.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-KKVMZFOV.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-NEWWPCTD.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-5SEU5WUY.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-QKEXGIRG.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-QFIANZWP.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-MN2RZ73S.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";export{a as MaintenanceCompleteDialog};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{G as a,H as b,I as c,J as d,K as e,L as f,M as g,N as h,O as i,P as j,Q as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A67W7HRQ.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-L3B7M7JO.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-GGO5IKKD.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-DLWOWMV7.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-4PKMHUVO.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-PTBWEHAJ.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-NWQLM4GV.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-ISGNEPYP.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-CH2AE3ZD.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-W3CDWY4U.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-KKVMZFOV.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-NEWWPCTD.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-5SEU5WUY.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-QKEXGIRG.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-DRDJQAJ6.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-OUHDI2FL.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-FFPNBBZ6.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-QFIANZWP.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-MN2RZ73S.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";export{b as __resetSettingsCacheForTests,a as getRowActionStyle,h as openCompleteDialog,c as openCreateObjectDialog,e as openCreateTaskDialog,d as openEditObjectDialog,f as openEditTaskDialog,g as openHistoryEditDialog,k as openObjectQuickActions,i as openQrDialog,j as openTaskQuickActions};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-PTBWEHAJ.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-ISGNEPYP.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-QKEXGIRG.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-MN2RZ73S.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";export{a as MaintenanceObjectDialog};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DRDJQAJ6.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-OUHDI2FL.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";export{a as MaintenanceQrDialog};
@@ -0,0 +1,184 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as g}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-MN2RZ73S.js";import{H as k,a as d,b,c as n,f as p,h as x,l as y,m as l,s as r,u as w}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";var m=u=>`${u.entry_id}/${u.task_id}`,_="__new__",o=class extends x{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._adopting=!1;this._error="";this._setups=[];this._selected=new Set;this._baselines=new Map;this._targets=new Map;this._tasks=new Map;this._objects=[];this._offers=[];this._offerTicks=new Set;this._wiring=!1;this._localeReady=!1;this._wire=async()=>{if(this._wiring)return;let e=this._offers.filter(s=>this._offerTicks.has(m(s))).map(s=>({entry_id:s.entry_id,task_id:s.task_id}));if(e.length===0)return;this._error="";let t=await g(this,{type:"maintenance_supporter/integration_setups/wire_resets",items:e},{busy:s=>{this._wiring=s},onError:s=>{this._error=s}});t!==void 0&&(this.dispatchEvent(new CustomEvent("reset-counters-wired",{bubbles:!0,composed:!0,detail:t})),await this._loadOffers())};this._toggle=e=>{let t=new Set(this._selected);t.has(e)?t.delete(e):t.add(e),this._selected=t};this._adopt=async()=>{if(this._adopting)return;this._error="";let e=[...this._selected].map(s=>{let a=[...this._tasks.get(s)??[]],c={device_id:s,task_names:a},i=this._targets.get(s);i&&i!==_&&(c.entry_id=i);for(let f of a){let h=this._baselines.get(`${s} ${f}`),v=h?parseFloat(h):NaN;!isNaN(v)&&v>=0&&((c.baselines??={})[f]=v)}return c}).filter(s=>s.task_names.length>0);if(e.length===0)return;let t=await g(this,{type:"maintenance_supporter/integration_setups/adopt",selections:e},{busy:s=>{this._adopting=s},onError:s=>{this._error=s}});t!==void 0&&(this.dispatchEvent(new CustomEvent("integration-setups-adopted",{bubbles:!0,composed:!0,detail:t})),this._open=!1)}}get _lang(){return k(this.hass)}updated(e){e.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,w(this._lang).then(()=>this.requestUpdate()))}_defaultTicks(e){return new Set(e.tasks.filter(t=>!t.covered_by).map(t=>t.task_name))}async open(){this._open=!0,this._loading=!0,this._error="",this._setups=[],this._selected=new Set,this._offers=[],this._loadOffers();let e=await g(this,{type:"maintenance_supporter/integration_setups/discover"},{onError:t=>{this._error=t}});if(e!==void 0){this._setups=e?.setups||[],this._selected=new Set(this._setups.map(t=>t.device_id)),this._baselines=new Map,this._targets=new Map(this._setups.map(t=>[t.device_id,t.target_entry_id||_])),this._tasks=new Map(this._setups.map(t=>[t.device_id,this._defaultTicks(t)]));try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"});this._objects=(t.objects||[]).filter(s=>!s.object?.archived_at).map(s=>({entry_id:s.entry_id,name:s.object?.name||s.entry_id})).sort((s,a)=>s.name.localeCompare(a.name))}catch{this._objects=[]}}this._loading=!1}_close(){this._open=!1}async _loadOffers(){try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/integration_setups/reset_offers"});this._offers=e.offers||[],this._offerTicks=new Set(this._offers.filter(t=>!t.renamed).map(m))}catch{this._offers=[]}}_toggleOffer(e){let t=new Set(this._offerTicks),s=m(e);t.has(s)?t.delete(s):t.add(s),this._offerTicks=t}_renderOffers(e){if(this._offers.length===0)return p;let t=this._offers.filter(s=>this._offerTicks.has(m(s))).length;return n`
<div class="offers">
<div class="offers-title">${r("reset_offers_title",e)}</div>
<div class="hint">${r("reset_offers_hint",e)}</div>
${this._offers.map(s=>n`
<label class="offer" data-task=${s.task_id}>
<input type="checkbox" class="offer-check" .checked=${this._offerTicks.has(m(s))} @change=${()=>this._toggleOffer(s)} />
<span class="task-text">
<span>${s.task_name} · ${s.object_name}</span>
${s.renamed?n`<span class="offer-renamed">${r("reset_offers_renamed",e)}</span>`:p}
<span class="offer-before">${r("reset_offers_before",e).replace("{integration}",s.integration_name)}</span>
<span class="offer-after">
${r("reset_offers_after",e).replace("{button}",s.button_name)}${s.button_disabled?` ${r("setups_reset_enable",e)}`:""}
</span>
</span>
</label>
`)}
<div class="offers-actions">
<ha-button @click=${this._wire} .disabled=${t===0||this._wiring}>${r("reset_offers_apply",e)}</ha-button>
</div>
</div>
`}_toggleTask(e,t){let s=new Set(this._tasks.get(e)??[]);s.has(t)?s.delete(t):s.add(t),this._tasks=new Map(this._tasks).set(e,s)}async _retarget(e,t){this._targets=new Map(this._targets).set(e.device_id,t);let s=await g(this,{type:"maintenance_supporter/integration_setups/preview",device_id:e.device_id,entry_id:t===_?null:t},{onError:a=>{this._error=a}});!s||!Array.isArray(s.tasks)||(this._setups=this._setups.map(a=>a.device_id===e.device_id?{...a,...s}:a),this._tasks=new Map(this._tasks).set(e.device_id,this._defaultTicks(s)))}get _anythingTicked(){return[...this._selected].some(e=>(this._tasks.get(e)?.size??0)>0)}_targetOptions(e,t){let s=this._targets.get(e.device_id)??_,a=[];if(e.suggested_entry_id)a.push({value:e.suggested_entry_id,label:e.suggested_object_name});else{if(e.candidate){let i=e.candidate.reasons.map(f=>r(`setups_reason_${f}`,t)).join(", ");a.push({value:e.candidate.entry_id,label:r("setups_target_match",t).replace("{name}",e.candidate.name).replace("{reasons}",i)})}a.push({value:_,label:r("setups_target_new",t).replace("{name}",e.device_name)})}let c=new Set(a.map(i=>i.value));for(let i of this._objects)c.has(i.entry_id)||a.push({value:i.entry_id,label:i.name});return n`
<select
class="target-select"
@click=${i=>i.stopPropagation()}
@change=${i=>{this._retarget(e,i.target.value)}}
>
${a.map(i=>n`<option value=${i.value} ?selected=${i.value===s}>${i.label}</option>`)}
</select>
`}_beforeAfter(e,t){let s=this._tasks.get(e.device_id)?.size??0;if((this._targets.get(e.device_id)??_)===_)return r("setups_new_object_count",t).replace("{name}",e.device_name).replace("{count}",String(s));let c=e.target_task_count??0;return r("setups_before_after",t).replace("{before}",String(c)).replace("{after}",String(c+s))}render(){if(!this._open)return n``;let e=this._lang;return n`
<div class="overlay" @click=${this._close}>
<div class="card" @click=${t=>t.stopPropagation()}>
<div class="title">${r("setups_title",e)}</div>
<div class="hint">${r("setups_hint",e)}</div>
${this._error?n`<div class="error">${this._error}</div>`:p}
${this._renderOffers(e)}
${this._loading?n`<div class="loading">…</div>`:this._setups.length===0?this._offers.length===0?n`<div class="empty">${r("setups_none",e)}</div>`:p:n`
<div class="list">
${this._setups.map(t=>{let s=this._selected.has(t.device_id),a=[t.integration_name,t.area_name].filter(Boolean).join(" \xB7 "),c=this._tasks.get(t.device_id)??new Set;return n`
<div class="row ${s?"":"off"}" data-device=${t.device_id}>
<input
type="checkbox"
class="device-check"
.checked=${s}
@change=${()=>this._toggle(t.device_id)}
/>
<div class="row-main">
<div class="row-top">
<span class="row-name">${t.device_name}</span>
</div>
<div class="row-sub">${a}</div>
<div class="row-target">→ ${this._targetOptions(t,e)}</div>
${s?n`
<div class="task-list">
${t.tasks.map(i=>n`
<label class="task" title=${i.entity_ids.join(", ")}>
<input
type="checkbox"
class="task-check"
.checked=${c.has(i.task_name)}
@change=${()=>this._toggleTask(t.device_id,i.task_name)}
/>
<span class="task-text">
<span>${i.task_name_localized||i.task_name}</span>
${i.covered_by?n`<span class="maybe">${r("setups_maybe_covered",e).replace("{name}",i.covered_by.name)}</span>`:p}
${i.reset?n`<span class="reset">↻ ${r("setups_reset_line",e).replace("{button}",i.reset.name)}${i.reset.disabled?` ${r("setups_reset_enable",e)}`:""}</span>`:p}
</span>
</label>
${i.direction==="usage_delta"&&c.has(i.task_name)?n`
<div class="baseline-field">
<span class="baseline-label">${r("setups_baseline_hint",e)}</span>
<input
type="number"
step="any"
min="0"
.value=${this._baselines.get(`${t.device_id} ${i.task_name}`)??""}
@input=${f=>{let h=new Map(this._baselines);h.set(`${t.device_id} ${i.task_name}`,f.target.value),this._baselines=h}}
/>
</div>
`:p}
`)}
${t.already?.length?n`<div class="already">
${r("setups_already",e).replace("{names}",t.already.map(i=>i.existing_name).join(", "))}
</div>`:p}
</div>
<div class="before-after">${this._beforeAfter(t,e)}</div>
`:p}
</div>
</div>
`})}
</div>
`}
<div class="actions">
<ha-button appearance="plain" @click=${this._close}>
${r("cancel",e)}
</ha-button>
<ha-button @click=${this._adopt} .disabled=${!this._anythingTicked||this._adopting}>
${r("setups_adopt",e)}
</ha-button>
</div>
</div>
</div>
`}};o.styles=b`
.overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.card {
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
border-radius: 12px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 12px;
min-width: min(360px, calc(100vw - 24px));
max-width: 560px;
width: 90vw;
max-height: 80vh;
overflow: hidden;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}
.title { font-size: 18px; font-weight: 500; }
.hint { color: var(--secondary-text-color); font-size: 13px; }
.error { color: var(--error-color, #f44336); font-size: 13px; }
.loading, .empty { color: var(--secondary-text-color); font-size: 14px; padding: 12px 0; }
.list { display: flex; flex-direction: column; gap: 6px; overflow-y: auto; max-height: 55vh; }
.row {
display: flex; align-items: flex-start; gap: 10px; padding: 8px;
border: 1px solid var(--divider-color); border-radius: 6px;
}
.row.off .row-main { opacity: 0.6; }
.row input { margin-top: 2px; cursor: pointer; }
.row-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1; }
.row-name { font-weight: 500; font-size: 13px; }
.row-sub, .row-target { color: var(--secondary-text-color); font-size: 12px; }
.row-target { display: flex; align-items: center; gap: 6px; min-width: 0; }
.target-select {
font-size: 12px; padding: 2px 4px; min-width: 0; max-width: 100%; flex: 1 1 auto;
border: 1px solid var(--divider-color); border-radius: 4px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
}
.task-list { display: flex; flex-direction: column; gap: 2px; margin-top: 2px; }
.task { display: flex; align-items: flex-start; gap: 6px; font-size: 13px; cursor: pointer; }
.task-text { display: flex; flex-direction: column; min-width: 0; }
.maybe { font-size: 11px; color: var(--warning-color, #ff9800); }
.already { font-size: 11px; color: var(--secondary-text-color); margin-top: 2px; }
.reset { font-size: 11px; color: var(--secondary-text-color); }
.offers {
display: flex; flex-direction: column; gap: 6px; padding: 8px;
border: 1px solid var(--primary-color); border-radius: 6px;
overflow-y: auto; max-height: 40vh; flex-shrink: 0;
}
.offers-title { font-weight: 500; font-size: 14px; }
.offer { display: flex; align-items: flex-start; gap: 6px; font-size: 13px; cursor: pointer; }
.offer-before { font-size: 11px; color: var(--secondary-text-color); }
.offer-after { font-size: 11px; color: var(--primary-color); }
.offer-renamed { font-size: 11px; color: var(--warning-color, #ff9800); }
.offers-actions { display: flex; justify-content: flex-end; }
.before-after {
font-size: 12px; font-weight: 500; color: var(--primary-color);
border-top: 1px dashed var(--divider-color); padding-top: 4px; margin-top: 2px;
}
.baseline-field {
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
margin: 0 0 2px 24px; font-size: 12px; color: var(--secondary-text-color);
}
.baseline-field input {
width: 110px; padding: 3px 6px; font-size: 12px;
border: 1px solid var(--divider-color); border-radius: 4px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
}
.actions { display: flex; justify-content: flex-end; gap: 8px; padding-top: 8px; }
`,d([y({attribute:!1})],o.prototype,"hass",2),d([l()],o.prototype,"_open",2),d([l()],o.prototype,"_loading",2),d([l()],o.prototype,"_adopting",2),d([l()],o.prototype,"_error",2),d([l()],o.prototype,"_setups",2),d([l()],o.prototype,"_selected",2),d([l()],o.prototype,"_baselines",2),d([l()],o.prototype,"_targets",2),d([l()],o.prototype,"_tasks",2),d([l()],o.prototype,"_objects",2),d([l()],o.prototype,"_offers",2),d([l()],o.prototype,"_offerTicks",2),d([l()],o.prototype,"_wiring",2);customElements.get("maintenance-suggested-setups-dialog")||customElements.define("maintenance-suggested-setups-dialog",o);export{o as MaintenanceSuggestedSetupsDialog};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a,b,c}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NWQLM4GV.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-ISGNEPYP.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-5SEU5WUY.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-QKEXGIRG.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-FFPNBBZ6.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-QFIANZWP.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-MN2RZ73S.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-27MZ7YLE.js";export{c as MaintenanceTaskDialog,b as applyTypeFields,a as typeFieldsFromConfig};
@@ -0,0 +1,127 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as w,b as $}from"./chunk-57NIXD73.js";import{B as u,a as h,b as o,d as m,e as y,f as v,g as l,h as g,i as _,j as f,k as x,n as p}from"./chunk-RRH35HQD.js";import{a as n,g as i}from"./chunk-MOOOMPKN.js";var E=80,s=class extends y{constructor(){super(...arguments);this._config={type:""};this._status=null;this._busy=!1;this._error="";this._localMonthly="";this._localYearly="";this._dirty=!1;this._loaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return f(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),_(this,t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load())}async _load(){let t=await u(this,{type:"maintenance_supporter/budget_status"},{onError:e=>{this._error=e}});t&&(this._status=t,x(t),this._localMonthly=t.monthly_budget?String(t.monthly_budget):"",this._localYearly=t.yearly_budget?String(t.yearly_budget):"",this._dirty=!1)}async _save(){if(!this._isAdmin)return;this._error="";let t=this._localMonthly.trim()===""?0:parseFloat(this._localMonthly),e=this._localYearly.trim()===""?0:parseFloat(this._localYearly),a={};!isNaN(t)&&t>=0&&(a.budget_monthly=t),!isNaN(e)&&e>=0&&(a.budget_yearly=e),await u(this,{type:"maintenance_supporter/global/update",settings:a},{busy:d=>{this._busy=d},reload:()=>this._load(),onError:d=>{this._error=d}})}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_budget"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,e=this._status;if(!e)return o`<ha-card><div class="loading">${i("loading",t)}</div></ha-card>`;let a=g(e),d=e.alert_threshold_pct??E,k=[{label:i("budget_monthly",t),spent:e.monthly_spent||0,budget:e.monthly_budget||0},{label:i("budget_yearly",t),spent:e.yearly_spent||0,budget:e.yearly_budget||0}];return o`
<ha-card>
<div class="card-content">
<div class="header">
<div class="title">
<span class="emoji">💰</span>
<span>${this._config.title||i("settings_budget",t)}</span>
</div>
<span class="currency">${a}</span>
</div>
${this._error?o`<div class="error">${this._error}</div>`:m}
${k.map(r=>{if(!(r.budget>0))return o`
<div class="track spent-only">
<div class="track-label-row">
<label>${r.label}</label>
<span class="track-numbers ok">${p(r.spent,a,t)}</span>
</div>
</div>
`;let c=Math.min(100,Math.max(0,r.spent/r.budget*100)),b=c>=100?"danger":c>=d?"warning":"ok";return o`
<div class="track">
<div class="track-label-row">
<label>${r.label}</label>
<span class="track-numbers ${b}">
${p(r.spent,void 0,t)} / ${p(r.budget,a,t)}
</span>
</div>
<div class="bar"><div class="bar-fill ${b}" style="width:${c}%"></div></div>
</div>
`})}
${this._isAdmin?o`
<div class="inputs-row">
<div class="input-field">
<label>${i("budget_monthly_set",t)}</label>
<div class="input-wrap">
<input type="number" min="0" step="1"
.value=${this._localMonthly}
?disabled=${this._busy}
@input=${r=>{this._localMonthly=r.target.value,this._dirty=!0}} />
<span class="input-suffix">${a}</span>
</div>
</div>
<div class="input-field">
<label>${i("budget_yearly_set",t)}</label>
<div class="input-wrap">
<input type="number" min="0" step="1"
.value=${this._localYearly}
?disabled=${this._busy}
@input=${r=>{this._localYearly=r.target.value,this._dirty=!0}} />
<span class="input-suffix">${a}</span>
</div>
</div>
</div>
<div class="actions">
<button class="btn ${this._dirty?"primary":"muted"}"
@click=${this._save}
?disabled=${this._busy||!this._dirty}>
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
${this._dirty?i("save",t):i("saved",t)}
</button>
<button class="btn link" @click=${this._onDeepLink}>
${i("budget_advanced",t)}
</button>
</div>
`:o`
<button class="btn link" @click=${this._onDeepLink}>
${i("budget_open_panel",t)}
</button>
`}
</div>
</ha-card>
`}};s.styles=[$,h`
.currency {
font-size: 14px; font-weight: 600;
color: var(--secondary-text-color);
background: var(--secondary-background-color);
padding: 2px 10px; border-radius: 999px;
}
.track { display: flex; flex-direction: column; gap: 4px; }
.track-label-row {
display: flex; align-items: center; justify-content: space-between;
}
.track-label-row label {
font-size: 12px; color: var(--secondary-text-color);
text-transform: uppercase; letter-spacing: 0.5px;
}
.track-numbers { font-size: 13px; font-weight: 600; }
.track-numbers.ok { color: var(--primary-text-color); }
.track-numbers.warning { color: #ff9800; }
.track-numbers.danger { color: var(--error-color, #f44336); }
.bar {
height: 6px; background: var(--secondary-background-color);
border-radius: 3px; overflow: hidden;
}
.bar-fill { height: 100%; transition: width 0.3s; border-radius: 3px; }
.bar-fill.ok { background: var(--primary-color); }
.bar-fill.warning { background: #ff9800; }
.bar-fill.danger { background: var(--error-color, #f44336); }
/* minmax(0, …): a bare 1fr never shrinks below the number inputs'
natural width — the row was 420 px wide on a phone (2026-09-27). */
.inputs-row {
display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px;
padding-top: 4px; border-top: 1px solid var(--divider-color);
}
.input-field { display: flex; flex-direction: column; gap: 4px; }
.input-field label {
font-size: 11px; color: var(--secondary-text-color);
text-transform: uppercase; letter-spacing: 0.3px;
}
.input-wrap { position: relative; display: flex; align-items: center; }
.input-wrap input {
flex: 1; min-width: 0; width: 100%; box-sizing: border-box; padding: 6px 32px 6px 8px; font-size: 13px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color); border-radius: 6px;
font-family: inherit;
}
.input-suffix {
position: absolute; right: 8px;
color: var(--secondary-text-color); font-size: 13px;
pointer-events: none;
}
.actions { display: flex; gap: 8px; align-items: center; }
`],n([v({attribute:!1})],s.prototype,"hass",2),n([l()],s.prototype,"_config",2),n([l()],s.prototype,"_status",2),n([l()],s.prototype,"_busy",2),n([l()],s.prototype,"_error",2),n([l()],s.prototype,"_localMonthly",2),n([l()],s.prototype,"_localYearly",2),n([l()],s.prototype,"_dirty",2);customElements.get("maintenance-budget-section-card")||customElements.define("maintenance-budget-section-card",s);w({type:"maintenance-budget-section-card",name:"Maintenance Supporter \u2014 Budget",description:"Edit the monthly and yearly budget right on the dashboard.",preview:!1});export{s as MaintenanceBudgetSectionCard};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as i}from"./chunk-O6THLHMN.js";var r={operatorWriteEnabled:!1,operatorIds:[]};function m(e,t=r){return e?e.is_admin?!0:t.operatorWriteEnabled&&t.operatorIds.includes(e.id):!1}function l(e){return e==="use"?"use":"purchase"}var c=e=>typeof e=="number"&&Number.isFinite(e)?e:null;function b(e){let t=c(e?.cost);if(t===null)return null;let n=c(e?.package_size);return n&&n>0?t/n:t}var d=["buttons_compact","buttons","icons"];function _(e){let[t,n]=i.default_warning_days,s=e?.general?.default_warning_days,a=e?.general?.row_action_style;return{features:{...o.features,...e?.features??{}},defaultWarningDays:typeof s=="number"&&Number.isFinite(s)&&s>=t&&s<=n?s:o.defaultWarningDays,rowActionStyle:d.includes(a??"")?a:o.rowActionStyle,access:{operatorWriteEnabled:e?.operator_write_enabled===!0,operatorIds:Array.isArray(e?.admin_panel_user_ids)?e.admin_panel_user_ids.filter(p=>typeof p=="string"):[]},budget:e?.budget??null,rowActionNoticePending:e?.general?.row_action_notice_pending===!0,refsInLists:e?.general?.ref_numbers_in_lists===!0,objectsTableColumns:Array.isArray(e?.objects_table_columns)?e.objects_table_columns:void 0,partsCostMode:l(e?.budget?.parts_cost_mode)}}var o={features:{adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1},defaultWarningDays:7,rowActionStyle:"buttons_compact",access:r,budget:null,rowActionNoticePending:!1,refsInLists:!1,objectsTableColumns:void 0,partsCostMode:"purchase"};function u(){let e=window;return e.__msSettingsCache??={promise:null}}function w(e){let t=u();if(t.promise)return t.promise;let n=e.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(s=>_(s)).catch(()=>(t.promise===n&&(t.promise=null),o));return t.promise=n,n}function h(){u().promise=null}export{r as a,m as b,b as c,w as d,h as e};
@@ -0,0 +1,60 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as t}from"./chunk-RRH35HQD.js";function e(o){let r=window;r.customCards=r.customCards||[],r.customCards.some(a=>a.type===o.type)||r.customCards.push(o)}var d=t`
ha-card { overflow: hidden; }
.card-content {
padding: 16px;
display: flex; flex-direction: column;
gap: 12px;
}
.header {
display: flex; align-items: center; justify-content: space-between;
gap: 12px;
}
.title {
display: flex; align-items: center; gap: 8px;
font-size: 16px; font-weight: 500;
}
.emoji { font-size: 20px; }
/* Button family — primary action / muted-saved-state / link / icon-with-text */
.btn {
padding: 6px 12px; font-size: 13px;
border-radius: 6px; cursor: pointer;
border: 1px solid var(--divider-color);
background: var(--secondary-background-color, transparent);
color: var(--primary-text-color);
font-weight: 500;
display: inline-flex; align-items: center; gap: 4px;
}
.btn:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.btn.primary {
background: var(--primary-color);
color: var(--text-primary-color, white);
border-color: var(--primary-color);
}
.btn.primary[disabled] { opacity: 0.6; }
.btn.muted {
background: transparent;
color: var(--secondary-text-color);
border-style: dashed;
}
.btn.muted[disabled] { opacity: 1; cursor: default; }
.btn.muted ha-icon, .btn.primary ha-icon { --mdc-icon-size: 14px; }
.btn.link {
background: transparent; border: none; padding: 6px 4px;
color: var(--primary-color); margin-left: auto;
}
.btn.link:hover { background: transparent; text-decoration: underline; }
/* Error + loading states */
.error {
padding: 8px; border-radius: 6px;
background: rgba(211, 47, 47, 0.1);
color: var(--error-color, #d32f2f); font-size: 13px;
}
.loading {
padding: 24px; text-align: center;
color: var(--secondary-text-color);
}
`;export{e as a,d as b};
@@ -0,0 +1,88 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as y,b as s,d,e as g,f as o,g as f,q as m}from"./chunk-RRH35HQD.js";import{a,g as l}from"./chunk-MOOOMPKN.js";function $(n){let t=m("2001-02-03",n).match(/\d+/g)||[],e=v=>t.findIndex(_=>Number(_)===v),h=e(2001),c=e(2),u=e(3);return h===0?"YMD":c>=0&&u>=0&&c<u?"MDY":"DMY"}function p(n,i,t){if(n<1e3||n>9999||i<1||i>12||t<1||t>31)return null;let e=new Date(n,i-1,t);return e.getFullYear()!==n||e.getMonth()!==i-1||e.getDate()!==t?null:`${n}-${String(i).padStart(2,"0")}-${String(t).padStart(2,"0")}`}function b(n,i){let t=n.trim(),e;if(e=t.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/))return p(+e[1],+e[2],+e[3]);if(e=t.match(/^(\d{4})$/))return p(+e[1],1,1);if(e=t.match(/^(\d{1,2})[./](\d{4})$/))return p(+e[2],+e[1],1);if(e=t.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/))return p(+e[3],+e[2],+e[1]);if(e=t.match(/^(\d{1,2})[/-](\d{1,2})[/-](\d{4})$/)){let h=+e[1],c=+e[2],u=+e[3];return $(i)==="MDY"?p(u,h,c):p(u,c,h)}return null}function x(n,i){if(i)switch(n){case"date":return i.split("T")[0];case"time":return i.length===5?`${i}:00`:i;case"datetime":{let[t,e="00:00:00"]=i.split("T");return`${t} ${e.length===5?`${e}:00`:e}`}}}function k(n,i){if(typeof i!="string"||!i)return"";switch(n){case"date":return i.slice(0,10);case"time":return i.slice(0,5);case"datetime":{let[t,e="00:00:00"]=i.split(" ");return`${t}T${e.length===5?`${e}:00`:e}`}}}var r=class extends g{constructor(){super(...arguments);this.kind="date";this.label="";this.value="";this.clearable=!1;this.disabled=!1;this.required=!1;this.lang="en";this._typing=!1;this._typed="";this._typedInvalid=!1}_startTyping(){this._typed=this.value,this._typedInvalid=!1,this._typing=!0,this.updateComplete.then(()=>this.shadowRoot?.querySelector("input.typed")?.focus())}_commitTyped(){if(!this._typed.trim()){this._typing=!1;return}let t=b(this._typed,this.lang);if(!t){this._typedInvalid=!0;return}this._typing=!1,this._typedInvalid=!1,this._emit(t)}_onTypedKey(t){t.key==="Enter"?(t.preventDefault(),this._commitTyped()):t.key==="Escape"&&(t.preventDefault(),this._typing=!1,this._typedInvalid=!1)}_selector(){switch(this.kind){case"date":return{date:{}};case"time":return{time:{no_second:!0}};case"datetime":return{datetime:{}}}}_onSelectorChange(t){t.stopPropagation(),this._emit(k(this.kind,t.detail?.value))}_clear(){this._emit("")}_emit(t){t!==this.value&&(this.value=t,this.dispatchEvent(new CustomEvent("value-changed",{bubbles:!0,composed:!0,detail:{value:t}})))}render(){return s`
<div class="field">
${this.label?s`<span class="label">${this.label}${this.required?s`<span class="req">*</span>`:d}</span>`:d}
<div class="row">
${this._typing?s`<input class="typed" type="text" inputmode="numeric" autocomplete="off"
.value=${this._typed}
placeholder=${m("1978-03-15",this.lang)}
aria-invalid=${this._typedInvalid?"true":"false"}
@input=${t=>{this._typed=t.target.value,this._typedInvalid=!1}}
@keydown=${this._onTypedKey}
@blur=${this._commitTyped} />`:s`<ha-selector
.hass=${this.hass}
.selector=${this._selector()}
.value=${x(this.kind,this.value)}
.required=${this.required}
.disabled=${this.disabled}
@value-changed=${this._onSelectorChange}
></ha-selector>`}
${this.kind==="date"&&!this.disabled&&!this._typing?s`<button type="button" class="type-toggle" title=${l("date_type_toggle",this.lang)} aria-label=${l("date_type_toggle",this.lang)} @click=${this._startTyping}>
<ha-icon icon="mdi:keyboard-outline"></ha-icon>
</button>`:d}
${this.clearable&&this.value&&!this.disabled&&!this._typing?s`<button type="button" class="clear" title=${l("clear",this.lang)} aria-label=${l("clear",this.lang)} @click=${this._clear}>
<ha-icon icon="mdi:close"></ha-icon>
</button>`:d}
</div>
${this._typedInvalid?s`<span class="helper invalid">${l("date_type_invalid",this.lang)}</span>`:this.helper?s`<span class="helper">${this.helper}</span>`:d}
</div>
`}};r.styles=y`
:host { display: block; }
.field {
display: flex;
flex-direction: column;
gap: 4px;
}
.label {
font-size: 12px;
color: var(--secondary-text-color, #888);
font-weight: 500;
}
.req { color: var(--error-color, #f44336); margin-left: 2px; }
.row {
display: flex;
align-items: center;
gap: 4px;
}
ha-selector {
flex: 1;
min-width: 0;
}
.clear, .type-toggle {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
padding: 0;
border: none;
border-radius: 50%;
background: transparent;
color: var(--secondary-text-color);
cursor: pointer;
--mdc-icon-size: 20px;
}
.clear:hover, .type-toggle:hover { background: rgba(var(--rgb-primary-text-color, 0, 0, 0), 0.08); }
.clear:focus-visible, .type-toggle:focus-visible { outline: 2px solid var(--primary-color); }
.helper {
font-size: 11px;
color: var(--secondary-text-color);
font-style: italic;
}
.helper.invalid { color: var(--error-color, #f44336); font-style: normal; }
input.typed {
flex: 1;
min-width: 0;
height: 40px;
box-sizing: border-box;
padding: 0 12px;
border: 1px solid var(--divider-color, #ccc);
border-radius: 4px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
font: inherit;
}
input.typed[aria-invalid="true"] { border-color: var(--error-color, #f44336); }
input.typed:focus { outline: 2px solid var(--primary-color); outline-offset: -1px; }
`,a([o({attribute:!1})],r.prototype,"hass",2),a([o()],r.prototype,"kind",2),a([o()],r.prototype,"label",2),a([o()],r.prototype,"value",2),a([o()],r.prototype,"helper",2),a([o({type:Boolean})],r.prototype,"clearable",2),a([o({type:Boolean})],r.prototype,"disabled",2),a([o({type:Boolean})],r.prototype,"required",2),a([o()],r.prototype,"lang",2),a([f()],r.prototype,"_typing",2),a([f()],r.prototype,"_typed",2),a([f()],r.prototype,"_typedInvalid",2);customElements.get("ms-date-field")||customElements.define("ms-date-field",r);
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
var w=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var B=(n,e,t,r)=>{for(var o=r>1?void 0:r?y(e,t):e,i=n.length-1,s;i>=0;i--)(s=n[i])&&(o=(r?s(e,t,o):s(o))||o);return r&&o&&w(e,t,o),o};var W={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)"},C=["overdue","triggered","due_soon","ok"],j=["overdue","triggered","due_soon"],Y=Object.fromEntries(C.map((n,e)=>[n,e]));var z={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"};var D="2.98.0";var b="en",x=(()=>{let n=window;return n.__msLocales||(n.__msLocales={store:{},inflight:{}}),n.__msLocales})(),l=x.store,m=x.inflight;function q(n){l.en=Object.assign({},n,l.en??{})}var O=new Set(["de","nl","fr","it","es","pt","pt-br","ru","uk","pl","cs","sv","zh","da","fi","nb","ja","hi","hu","ko","tr"]),R="/maintenance_supporter_locales";function _(n){let e=(n||b).toLowerCase();return e.startsWith("pt")&&e.endsWith("br")?"pt-br":e.substring(0,2)}function J(n,e,t){let r=_(e);return l[r]?.[n]??l.en?.[n]??t??n}function Q(n){let e=_(n);return e===b||e in l}function X(n){let e=_(n);return e===b||e in l||!O.has(e)?Promise.resolve():(e in m||(m[e]=fetch(`${R}/${e}.json?v=${D}`).then(t=>t.ok?t.json():null).then(t=>{t?l[e]=t:delete m[e]}).catch(()=>{delete m[e]})),m[e])}var L=window.__msDateTimePrefs??={},$=864e5,a=(n,e=2)=>String(n).padStart(e,"0"),A=new Map;function d(n){let e=A.get(n);if(e===void 0){try{e=new Intl.DateTimeFormat("en-US",{timeZone:n,hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch{e=null}A.set(n,e)}return e}var S;function v(){if(S===void 0){let n;try{n=new Intl.DateTimeFormat().resolvedOptions().timeZone}catch{}S=n&&d(n)?n:null}return S}function E(){return v()??"UTC"}function f(){let n=L.serverTimeZone;return n&&d(n)?n:E()}function en(){let n=v();return L.timeZone!=="server"&&n?n:f()}function p(n,e){let t=d(e)??d(E())??d("UTC"),r={};for(let o of t.formatToParts(n))o.type!=="literal"&&(r[o.type]=Number(o.value));return{y:r.year,mo:r.month,d:r.day,h:r.hour%24,mi:r.minute,s:r.second}}var N=n=>`${a(n.y,4)}-${a(n.mo)}-${a(n.d)}`;function M(n,e){return N(p(+n,e))}function I(n,e){let t=p(+n,e);return`${N(t)}T${a(t.h)}:${a(t.mi)}`}function tn(){return M(Date.now(),f())}function rn(){return I(Date.now(),f())}function h(n,e){let t=p(n,e);return Date.UTC(t.y,t.mo-1,t.d,t.h,t.mi,t.s)-Math.floor(n/1e3)*1e3}function P(n,e,t,r,o,i,s){let u=Date.UTC(n,e-1,t,r,o,i),c=h(u-$,s),g=h(u+$,s);for(let T of c===g?[c]:[c,g])if(h(u-T,s)===T)return u-T;return u-c}var U=/^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?)?$/;var Z=new Map,F=2e4;function k(n,e,t){if(n.has(e))return n.get(e);n.size>=F&&n.clear();let r=t();return n.set(e,r),r}function on(n){if(typeof n!="string"||!n)return NaN;let e=U.exec(n);if(!e)return Date.parse(n);let t=f();return k(Z,`${t}|${n}`,()=>{let[r,o,i,s,u,c]=[e[1],e[2],e[3],e[4]??"0",e[5]??"0",e[6]??"0"].map(Number);if(o<1||o>12||new Date(Date.UTC(r,o-1,i)).getUTCDate()!==i||s>23||u>59||c>59)return NaN;let g=e[7]?Math.floor(+`0.${e[7]}`*1e3):0;return P(r,o,i,s,u,c,t)+g})}function sn(n){if(typeof n!="string"||!n)return"";let e=U.exec(n);if(e)return`${e[1]}-${e[2]}-${e[3]}T${e[4]??"00"}:${e[5]??"00"}:${e[6]??"00"}`;let t=Date.parse(n);if(!Number.isFinite(t))return"";let r=p(t,f());return`${N(r)}T${a(r.h)}:${a(r.mi)}:${a(r.s)}`}export{B as a,W as b,j as c,z as d,q as e,_ as f,J as g,Q as h,X as i,f as j,en as k,M as l,I as m,tn as n,rn as o,on as p,sn as q};
@@ -0,0 +1,66 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as u,b as s,d as r,e as _,f as m,g as o,j as d,z as c}from"./chunk-RRH35HQD.js";import{a as i,g as p}from"./chunk-MOOOMPKN.js";var g={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]};var b=[0,14],x=[0,1440],y=[1,1e4],R=[0,365],A=15,E=[.1,.9],T=[0,365],$=[.01,1e4],G=[.01,1e5];var n=class extends _{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 r;let e=d(this.hass);return s`
<ha-dialog open @closed=${this._cancel}>
<div class="dialog-title">${this._title}</div>
<div class="content">
${this._message}
${this._inputLabel?s`
<!-- Native <input> rather than <ha-textfield>: HA loads
ha-textfield lazily for its own panels, so inside this custom
panel it can be unregistered and render with zero height —
the prompt then shows no field at all (caught live testing
the pause/replace prompts; same fix as complete-dialog). -->
<label class="field">
<span class="field-label">${this._inputLabel}</span>
${this._options?s`<select class="field-input field-select"
@change=${t=>this._inputValue=t.target.value}>
${this._options.map(t=>s`<option value=${t.value} ?selected=${t.value===this._inputValue}>${t.label}</option>`)}
</select>`:s`<input class="field-input"
type="${this._inputType||"text"}"
.value=${this._inputValue}
@input=${t=>this._inputValue=t.target.value} />`}
</label>
`:r}
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._cancel}>
${p("cancel",e)}
</ha-button>
<ha-button
class="${this._danger?"danger":""}"
@click=${this._confirmAction}
>
${this._confirmText}
</ha-button>
</div>
</ha-dialog>
`}};n.styles=[c,u`
.dialog-title {
font-size: 18px;
font-weight: 500;
padding-bottom: 12px;
}
/* shared native-field scaffold from nativeFieldStyles; the prompt input
follows the message text, hence the extra top margin here */
.field { margin-top: 12px; }
.content {
padding: 8px 0;
min-width: 280px;
line-height: 1.5;
display: flex;
flex-direction: column;
gap: 12px;
}
.dialog-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
padding-top: 16px;
}
ha-textfield {
display: block;
}
ha-button.danger {
--mdc-theme-primary: var(--error-color, #f44336);
}
`],i([m({attribute:!1})],n.prototype,"hass",2),i([o()],n.prototype,"_open",2),i([o()],n.prototype,"_title",2),i([o()],n.prototype,"_message",2),i([o()],n.prototype,"_confirmText",2),i([o()],n.prototype,"_danger",2),i([o()],n.prototype,"_inputLabel",2),i([o()],n.prototype,"_inputType",2),i([o()],n.prototype,"_options",2),i([o()],n.prototype,"_inputValue",2);customElements.get("maintenance-confirm-dialog")||customElements.define("maintenance-confirm-dialog",n);var h="maintenance-confirm-dialog",f="data-ms-lovelace-confirm";function v(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function V(l,a){let e=v(),t=e.querySelector(`${h}[${f}]`);return t||(t=document.createElement(h),t.setAttribute(f,""),e.appendChild(t)),t.hass=l,t.confirm(a)}export{g as a,b,x as c,y as d,R as e,A as f,E as g,T as h,$ as i,G as j,V as k};
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.98.0 */
import{p as l}from"./chunk-MOOOMPKN.js";function c(r){if(!r)return[];let n=[],i=r.photo_doc_id;typeof i=="string"&&n.push(i);let o=r.photo_doc_ids;Array.isArray(o)&&n.push(...o);let t=[];for(let e of n){if(typeof e!="string")continue;let s=e.trim();if(!(!s||t.includes(s))&&(t.push(s),t.length>=10))break}return t}var f=20;function _(){let r=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:n=>n.map(()=>Math.floor(Math.random()*256))}).getRandomValues(r),Array.from(r,n=>n.toString(16).padStart(2,"0")).join("")}function d(r){let n=r?.reading_values;if(!Array.isArray(n))return[];let i=[],o=new Set;for(let t of n){if(!t||typeof t!="object")continue;let e=t;typeof e.id!="string"||!e.id||o.has(e.id)||typeof e.value!="number"||!Number.isFinite(e.value)||(o.add(e.id),i.push({id:e.id,name:typeof e.name=="string"?e.name:e.id,unit:typeof e.unit=="string"?e.unit:null,value:e.value}))}return i}function y(r){return r.filter(n=>n.type==="completed"&&(n.reading_value!=null||d(n).length>0)).sort((n,i)=>n.timestamp.localeCompare(i.timestamp))}function R(r){return y(r??[]).map(n=>({timestamp:n.timestamp,values:d(n)})).filter(n=>n.values.length>0)}function h(r,n,i){let o;for(let t of r){if(i!==void 0){let s=l(t.timestamp);if(!isNaN(s)&&s>=i)break}let e=t.values.find(s=>s.id===n);e&&(o=e)}return o}function k(r,n,i){let o=d(n).find(e=>e.id===i);if(!o)return null;let t=null;for(let e of y(r)){if(e.timestamp>=n.timestamp)break;let s=d(e).find(a=>a.id===i);s&&(t=s.value)}return t==null?null:o.value-t}function w(r){let n=new Set,i=new Set;for(let o of r){let t=(o.name||"").trim().toLowerCase();t&&(n.has(t)?i.add(o.id):n.add(t))}return i}function S(r){let n=[],i=new Set,o=new Set;for(let t of r){let e=(t.name||"").trim();if(!(!e||i.has(t.id)||o.has(e.toLowerCase()))&&(i.add(t.id),o.add(e.toLowerCase()),n.push({id:t.id,name:e,unit:(t.unit||"").trim()||null}),n.length>=f))break}return n}function g(r,n,i,o){let t=i,e=u=>typeof u=="string"?u:null,s=u=>typeof u=="number"?u:null,a=e(t.timestamp)??"";return{entry_id:r,task_id:n,original_timestamp:a,type:e(t.type)||"completed",timestamp:a,notes:e(t.notes),cost:s(t.cost),duration:s(t.duration),completed_by:e(t.completed_by),used_parts:Array.isArray(t.used_parts)?t.used_parts:null,photo_doc_ids:c(t),reading_value:s(t.reading_value),reading_values:d(t),readings:o?.readings??[],task_type:o?.type??null,reading_unit:o?.reading_unit??null}}async function v(r,n,i,o){let e=(await r.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:n})).tasks?.find(a=>a.id===i);if(!e)return null;let s=e.history?.find(a=>a.timestamp===o);return s||(s=(await r.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:n,task_id:i})).history?.find(u=>u.timestamp===o)),s?g(n,i,s,e):null}export{c as a,f as b,_ as c,d,R as e,h as f,k as g,w as h,S as i,g as j,v as k};
@@ -0,0 +1,137 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as v,b as y}from"./chunk-57NIXD73.js";import{a as f,b as x,d as k}from"./chunk-3HW5KZUG.js";import{k as b}from"./chunk-O6THLHMN.js";import{B as l,a as h,b as a,d as c,e as g,f as _,g as o,j as m}from"./chunk-RRH35HQD.js";import{a as n,g as i,i as u}from"./chunk-MOOOMPKN.js";var e=class extends g{constructor(){super(...arguments);this._config={type:""};this._groups={};this._loaded=!1;this._busy=!1;this._error="";this._newName="";this._editingId=null;this._editingName="";this._access=f;this._hasInitiallyLoaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return m(this.hass)}get _canWrite(){return x(this.hass?.user,this._access)}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._hasInitiallyLoaded&&(this._hasInitiallyLoaded=!0,this._load(),k(this.hass).then(r=>{this._access=r.access}),u(this._lang).then(()=>this.requestUpdate()))}async _load(){let t=await l(this,{type:"maintenance_supporter/groups"},{onError:r=>{this._error=r}});t!==void 0&&(this._groups=t?.groups||{},this._loaded=!0)}async _act(t,r){this._error="",await l(this,t,{busy:s=>{this._busy=s},reload:async()=>{r?.(),await this._load()},onError:s=>{this._error=s}})}async _addGroup(){if(!this._canWrite)return;let t=this._newName.trim();t&&await this._act({type:"maintenance_supporter/group/create",name:t},()=>{this._newName=""})}_startEdit(t){this._editingId=t,this._editingName=this._groups[t]?.name||""}async _saveEdit(){if(!this._canWrite||!this._editingId)return;let t=this._editingName.trim();t&&await this._act({type:"maintenance_supporter/group/update",group_id:this._editingId,name:t},()=>{this._editingId=null,this._editingName=""})}async _deleteGroup(t,r){!this._canWrite||!await b(this.hass,{title:i("delete",this._lang),message:i("delete_group_confirm",this._lang).replace("{name}",r),confirmText:i("delete",this._lang),danger:!0})||await this._act({type:"maintenance_supporter/group/delete",group_id:t})}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_groups"),window.dispatchEvent(new CustomEvent("location-changed"))}_onKeyDown(t,r){t.key==="Enter"?(t.preventDefault(),r()):t.key==="Escape"&&(t.preventDefault(),this._editingId=null,this._editingName="")}render(){let t=this._lang;if(!this._loaded)return a`<ha-card><div class="loading">${i("loading",t)}</div></ha-card>`;let r=Object.keys(this._groups);return a`
<ha-card>
<div class="card-content">
<div class="header">
<div class="title">
<span class="emoji">🏷️</span>
<span>${this._config.title||i("groups",t)}</span>
<span class="count">${r.length}</span>
</div>
</div>
${this._error?a`<div class="error">${this._error}</div>`:c}
${r.length===0?a`<div class="empty">${i("groups_empty",t)}</div>`:a`
<div class="group-list">
${r.map(s=>{let d=this._groups[s],$=d.task_refs?.length??0,w=this._editingId===s;return a`
<div class="group-row">
${w?a`
<input class="edit-input" type="text"
.value=${this._editingName}
?disabled=${this._busy}
@input=${p=>{this._editingName=p.target.value}}
@keydown=${p=>this._onKeyDown(p,this._saveEdit.bind(this))} />
<button class="btn small primary"
@click=${this._saveEdit}
?disabled=${this._busy||!this._editingName.trim()}>
${i("save",t)}
</button>
<button class="btn small"
@click=${()=>{this._editingId=null}}>
${i("cancel",t)}
</button>
`:a`
<span class="group-name">${d.name||"Unnamed"}</span>
<span class="task-count">${$}</span>
${this._canWrite?a`
<button class="icon-btn"
title="${i("edit",t)}"
@click=${()=>this._startEdit(s)}
?disabled=${this._busy}>
<ha-icon icon="mdi:pencil"></ha-icon>
</button>
<button class="icon-btn danger"
title="${i("delete",t)}"
@click=${()=>this._deleteGroup(s,d.name||"Unnamed")}
?disabled=${this._busy}>
<ha-icon icon="mdi:delete"></ha-icon>
</button>
`:c}
`}
</div>
`})}
</div>
`}
${this._canWrite?a`
<div class="add-row">
<input type="text"
placeholder="${i("group_new_placeholder",t)}"
.value=${this._newName}
?disabled=${this._busy}
@input=${s=>{this._newName=s.target.value}}
@keydown=${s=>this._onKeyDown(s,this._addGroup.bind(this))} />
<button class="btn primary"
@click=${this._addGroup}
?disabled=${this._busy||!this._newName.trim()}>
<ha-icon icon="mdi:plus"></ha-icon>
${i("add",t)}
</button>
</div>
<button class="btn link" @click=${this._onDeepLink}>
${i("groups_manage_tasks",t)}
</button>
`:a`
<button class="btn link" @click=${this._onDeepLink}>
${i("groups_open_panel",t)}
</button>
`}
</div>
</ha-card>
`}};e.styles=[y,h`
.count {
font-size: 12px; color: var(--secondary-text-color);
background: var(--secondary-background-color);
padding: 2px 8px; border-radius: 999px;
}
.empty {
padding: 16px; text-align: center;
color: var(--secondary-text-color); font-style: italic;
}
.group-list { display: flex; flex-direction: column; gap: 4px; }
.group-row {
display: flex; align-items: center; gap: 8px;
padding: 6px 8px; border-radius: 6px;
background: var(--secondary-background-color, rgba(255,255,255,0.03));
}
.group-name { flex: 1; font-size: 14px; }
.task-count {
font-size: 11px; color: var(--secondary-text-color);
background: var(--card-background-color, rgba(0,0,0,0.2));
padding: 1px 8px; border-radius: 999px;
font-weight: 500;
}
.edit-input {
flex: 1; padding: 4px 8px; font-size: 14px;
background: var(--card-background-color, #1c1c1c);
color: var(--primary-text-color);
border: 1px solid var(--primary-color); border-radius: 4px;
font-family: inherit;
}
.icon-btn {
background: transparent; border: none; cursor: pointer;
color: var(--secondary-text-color); padding: 4px;
border-radius: 4px;
}
.icon-btn:hover {
background: var(--state-icon-color, rgba(255,255,255,0.06));
color: var(--primary-text-color);
}
.icon-btn.danger:hover { color: var(--error-color); }
.icon-btn ha-icon { --mdc-icon-size: 18px; }
.add-row {
display: flex; gap: 6px;
padding-top: 8px; border-top: 1px solid var(--divider-color);
}
.add-row input {
flex: 1; padding: 6px 8px; font-size: 13px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color); border-radius: 6px;
font-family: inherit;
}
/* Card-specific overrides on the shared .btn */
.btn.small { padding: 4px 8px; font-size: 12px; }
.btn ha-icon { --mdc-icon-size: 16px; }
`],n([_({attribute:!1})],e.prototype,"hass",2),n([o()],e.prototype,"_config",2),n([o()],e.prototype,"_groups",2),n([o()],e.prototype,"_loaded",2),n([o()],e.prototype,"_busy",2),n([o()],e.prototype,"_error",2),n([o()],e.prototype,"_newName",2),n([o()],e.prototype,"_editingId",2),n([o()],e.prototype,"_editingName",2),n([o()],e.prototype,"_access",2);customElements.get("maintenance-groups-section-card")||customElements.define("maintenance-groups-section-card",e);v({type:"maintenance-groups-section-card",name:"Maintenance Supporter \u2014 Groups",description:"Create, rename and delete task groups right on the dashboard.",preview:!1});export{e as MaintenanceGroupsSectionCard};
@@ -0,0 +1,134 @@
/*! maintenance_supporter frontend 2.98.0 */
import{a as y,b as x}from"./chunk-57NIXD73.js";import"./chunk-DHVNCFIC.js";import{b as p,k as $}from"./chunk-O6THLHMN.js";import{B as u,a as v,b as r,d as c,e as f,f as m,g as n,i as b,j as g}from"./chunk-RRH35HQD.js";import{a as s,g as a,i as h}from"./chunk-MOOOMPKN.js";var i=class extends f{constructor(){super(...arguments);this._config={type:""};this._state=null;this._busy=!1;this._error="";this._localStart="";this._localEnd="";this._localBuffer="3";this._dirty=!1;this._loaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return g(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),b(this,t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load(),h(this._lang).then(()=>this.requestUpdate()))}async _load(){let t=await u(this,{type:"maintenance_supporter/vacation/state"},{onError:e=>{this._error=e}});t&&(this._state=t,this._localStart=t.start||"",this._localEnd=t.end||"",this._localBuffer=String(t.buffer_days??3),this._dirty=!1)}_act(t){return this._error="",u(this,t,{busy:e=>{this._busy=e},onError:e=>{this._error=e}})}async _toggleEnabled(t){let e=await this._act({type:"maintenance_supporter/vacation/update",enabled:t});e&&(this._state=e)}async _save(){if(!this._isAdmin)return;let[t,e]=p,o=Number(this._localBuffer);if(this._localBuffer.trim()===""||!Number.isInteger(o)||o<t||o>e){this._error=a("settings_value_out_of_range",this._lang).replace("{min}",String(t)).replace("{max}",String(e));return}let l=await this._act({type:"maintenance_supporter/vacation/update",start:this._localStart||null,end:this._localEnd||null,buffer_days:o});l&&(this._state=l,this._dirty=!1)}async _endNow(){if(!this._isAdmin||!await $(this.hass,{title:a("vacation_end_now",this._lang),message:a("vacation_end_now_confirm",this._lang),confirmText:a("vacation_end_now",this._lang)}))return;let e=await this._act({type:"maintenance_supporter/vacation/end_now"});e&&(this._state=e,this._localStart=e.start||"",this._localEnd=e.end||"")}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_vacation"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,e=this._state;if(!e)return r`<ha-card><div class="loading">${a("loading",t)}</div></ha-card>`;let o=e.is_active===!0,l=e.enabled===!0,_=e.exempt_task_ids?.length??0,w=o?a("vacation_status_active",t):l?a("vacation_status_scheduled",t):a("vacation_status_inactive",t),k=o?"active":l?"scheduled":"inactive";return r`
<ha-card>
<div class="card-content">
<div class="header">
<div class="title">
<span class="emoji">🏖️</span>
<span>${this._config.title||a("vacation_mode",t)}</span>
</div>
<span class="status-pill ${k}">${w}</span>
</div>
${this._error?r`<div class="error">${this._error}</div>`:c}
${this._isAdmin?r`
<div class="row toggle-row">
<label>${a("enable",t)}</label>
<ha-switch
.checked=${l}
.disabled=${this._busy}
@change=${d=>this._toggleEnabled(d.target.checked)}
></ha-switch>
</div>
<div class="dates-row">
<div class="date-field">
<label>${a("vacation_start",t)}</label>
<ms-date-field
kind="date"
clearable
.hass=${this.hass}
.lang=${t}
.value=${this._localStart}
.disabled=${this._busy}
@value-changed=${d=>{this._localStart=d.detail.value,this._dirty=!0}}
></ms-date-field>
</div>
<div class="date-field">
<label>${a("vacation_end",t)}</label>
<ms-date-field
kind="date"
clearable
.hass=${this.hass}
.lang=${t}
.value=${this._localEnd}
.disabled=${this._busy}
@value-changed=${d=>{this._localEnd=d.detail.value,this._dirty=!0}}
></ms-date-field>
</div>
<div class="date-field buffer">
<label>${a("vacation_buffer",t)}</label>
<input type="number" min=${p[0]} max=${p[1]}
.value=${this._localBuffer}
?disabled=${this._busy}
@input=${d=>{this._localBuffer=d.target.value,this._dirty=!0}} />
</div>
</div>
<div class="actions">
<button class="btn ${this._dirty?"primary":"muted"}"
@click=${this._save}
?disabled=${this._busy||!this._dirty}>
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
${this._dirty?a("save",t):a("saved",t)}
</button>
${o?r`<button class="btn"
@click=${this._endNow}
?disabled=${this._busy}>
${a("vacation_end_now",t)}
</button>`:c}
${_>0?r`<button class="btn link"
@click=${this._onDeepLink}>
${_} ${a("vacation_exempt_count",t)}…
</button>`:r`<button class="btn link"
@click=${this._onDeepLink}>
${a("vacation_advanced",t)}
</button>`}
</div>
`:r`
<div class="readonly">
${l&&e.start&&e.end?r`<div>${e.start} → ${e.end}</div>`:c}
<button class="btn link" @click=${this._onDeepLink}>
${a("vacation_open_panel",t)}
</button>
</div>
`}
</div>
</ha-card>
`}};i.styles=[x,v`
.status-pill {
font-size: 11px; font-weight: 600;
padding: 3px 8px; border-radius: 999px;
text-transform: uppercase; letter-spacing: 0.5px;
}
.status-pill.active {
background: rgba(76, 175, 80, 0.15);
color: #4caf50;
}
.status-pill.scheduled {
background: rgba(255, 152, 0, 0.15);
color: #ff9800;
}
.status-pill.inactive {
background: rgba(158, 158, 158, 0.15);
color: var(--secondary-text-color);
}
.row.toggle-row {
display: flex; align-items: center; justify-content: space-between;
}
.row.toggle-row label {
font-size: 14px; color: var(--primary-text-color);
}
.dates-row {
display: grid; grid-template-columns: 1fr 1fr 100px; gap: 10px;
}
.date-field.buffer label { white-space: nowrap; }
.date-field { display: flex; flex-direction: column; gap: 4px; }
.date-field label {
font-size: 11px; color: var(--secondary-text-color);
text-transform: uppercase; letter-spacing: 0.3px;
}
.date-field input {
padding: 6px 8px; font-size: 13px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color); border-radius: 6px;
font-family: inherit;
}
.date-field input:disabled { opacity: 0.5; cursor: not-allowed; }
.actions {
display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.readonly { display: flex; flex-direction: column; gap: 8px; }
`],s([m({attribute:!1})],i.prototype,"hass",2),s([n()],i.prototype,"_config",2),s([n()],i.prototype,"_state",2),s([n()],i.prototype,"_busy",2),s([n()],i.prototype,"_error",2),s([n()],i.prototype,"_localStart",2),s([n()],i.prototype,"_localEnd",2),s([n()],i.prototype,"_localBuffer",2),s([n()],i.prototype,"_dirty",2);customElements.get("maintenance-vacation-section-card")||customElements.define("maintenance-vacation-section-card",i);y({type:"maintenance-vacation-section-card",name:"Maintenance Supporter \u2014 Vacation",description:"Switch vacation mode on or off and set its dates right on the dashboard.",preview:!1});export{i as MaintenanceVacationSectionCard};
@@ -1,5 +1,5 @@
/*! maintenance_supporter frontend 2.97.1 */
import{j as O}from"./chunks/chunk-IPUKIEZ2.js";import{c as A,d as p,g as j,i as L}from"./chunks/chunk-G7Y44K4C.js";var Y={maintenance:"Maintenance",overview:"Overview",overdue:"Overdue",triggered:"Triggered",due_soon:"Due Soon",ok:"OK",today:"Today",today_this_week:"This week",unassigned:"Unassigned",tasks:"Tasks",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.'},h="en",c=t=>j(t,h,Y[t]);async function $(t){h=t?.language||"en",await L(h)}var V="maintenance-supporter",W=`ll-strategy-dashboard-${V}`,B="hui-maintenance-supporter-strategy-editor",F="NOT_RUNNING",q=[{status:"overdue",title:"overdue",icon:p.overdue,path:"overdue"},{status:"triggered",title:"triggered",icon:p.triggered,path:"triggered"},{status:"due_soon",title:"due_soon",icon:p.due_soon,path:"due-soon"},{status:"ok",title:"ok",icon:p.ok,path:"ok"}],x=[{title:"overdue",icon:p.overdue,path:"overdue",filter:{filter_due_max_days:-1},matches:t=>t<=-1},{title:"today",icon:"mdi:calendar-today",path:"today",filter:{filter_due_min_days:0,filter_due_max_days:0},matches:t=>t===0},{title:"today_this_week",icon:"mdi:calendar-week",path:"this-week",filter:{filter_due_min_days:1,filter_due_max_days:7},matches:t=>t>=1&&t<=7},{title:"strat_this_month",icon:"mdi:calendar-month",path:"this-month",filter:{filter_due_min_days:8,filter_due_max_days:30},matches:t=>t>=8&&t<=30},{title:"strat_later",icon:"mdi:calendar-clock",path:"later",filter:{filter_due_min_days:31},matches:t=>t>=31}];function l(t){return{type:"grid",cards:[t]}}var X={condition:"view_columns",min:2};function _(t,n,e){let s=n[t];if(s)return`{{ states('${s}') }}`;let r=e[t];return r==null?"\u2014":String(r)}function z(t={},n={}){return{type:"markdown",text_only:!0,content:[`\u{1F534} **${_("overdue",t,n)}** ${c("overdue")}`,`\u26A1 **${_("triggered",t,n)}** ${c("triggered")}`,`\u{1F7E1} **${_("due_soon",t,n)}** ${c("due_soon")}`,`\u{1F7E2} **${_("ok",t,n)}** ${c("ok")}`].join(" \xB7 ")}}function Q(){return{title:c("maintenance"),type:"panel",cards:[{type:"empty-state",icon:"mdi:wrench-clock",icon_color:"primary",content_only:!0,title:c("strat_empty_title"),content:c("strat_empty_content"),buttons:[{icon:"mdi:wrench",text:c("strat_open_panel"),appearance:"filled",variant:"brand",tap_action:{action:"navigate",navigation_path:"/maintenance-supporter"}},{icon:"mdi:plus",text:c("strat_add_object"),appearance:"outlined",variant:"brand",tap_action:{action:"fire-dom-event",ll_custom:{type:"maintenance-supporter:add-object"}}}]}]}}function J(t={},n={}){let e=z(t,n);return{title:c("overview"),icon:"mdi:wrench-clock",path:"overview",type:"sections",header:{layout:"responsive",card:e},sidebar:{sections:[{type:"grid",cards:[{type:"heading",heading:c("strat_status"),heading_style:"title"},e]}],visibility:[X],content_label:c("tasks"),sidebar_label:c("strat_status")},sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:[...A]})]}}function Z(t,n){let e=new Map;for(let a of t){let i=a.object.area_id||null;e.has(i)||e.set(i,[]),e.get(i).push(a)}let s=Array.from(e.keys()).filter(a=>a!==null);s.sort((a,i)=>{let u=n[a]?.name||a,d=n[i]?.name||i;return u.localeCompare(d)});let r=[];for(let a of s){let i=e.get(a);if(i.length===0)continue;let u=n[a];r.push({title:u?.name||a,icon:u?.icon||"mdi:floor-plan",path:`area-${a}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:i.map(d=>d.object.name)})]})}let o=e.get(null);return o&&o.length>0&&r.push({title:c("unassigned"),icon:"mdi:help-circle-outline",path:"unassigned",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:o.map(a=>a.object.name)})]}),r}function ee(t){let n=new Set;for(let s of t)for(let r of s.tasks||[])r.status&&n.add(r.status);let e=[];for(let s of q)n.has(s.status)&&e.push({title:c(s.title),icon:s.icon,path:s.path,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:[s.status]})]});return e}function te(t,n,e){let s=new Map;for(let i of t){let u=i.object.area_id,d=u&&n[u]?.floor_id||null;s.has(d)||s.seLine truncated
/*! maintenance_supporter frontend 2.98.0 */
import{k as O}from"./chunks/chunk-XIZY2KN7.js";import{c as A,d as p,g as j,i as L}from"./chunks/chunk-MOOOMPKN.js";var Y={maintenance:"Maintenance",overview:"Overview",overdue:"Overdue",triggered:"Triggered",due_soon:"Due Soon",ok:"OK",today:"Today",today_this_week:"This week",unassigned:"Unassigned",tasks:"Tasks",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.'},h="en",c=t=>j(t,h,Y[t]);async function $(t){h=t?.language||"en",await L(h)}var V="maintenance-supporter",W=`ll-strategy-dashboard-${V}`,B="hui-maintenance-supporter-strategy-editor",F="NOT_RUNNING",q=[{status:"overdue",title:"overdue",icon:p.overdue,path:"overdue"},{status:"triggered",title:"triggered",icon:p.triggered,path:"triggered"},{status:"due_soon",title:"due_soon",icon:p.due_soon,path:"due-soon"},{status:"ok",title:"ok",icon:p.ok,path:"ok"}],x=[{title:"overdue",icon:p.overdue,path:"overdue",filter:{filter_due_max_days:-1},matches:t=>t<=-1},{title:"today",icon:"mdi:calendar-today",path:"today",filter:{filter_due_min_days:0,filter_due_max_days:0},matches:t=>t===0},{title:"today_this_week",icon:"mdi:calendar-week",path:"this-week",filter:{filter_due_min_days:1,filter_due_max_days:7},matches:t=>t>=1&&t<=7},{title:"strat_this_month",icon:"mdi:calendar-month",path:"this-month",filter:{filter_due_min_days:8,filter_due_max_days:30},matches:t=>t>=8&&t<=30},{title:"strat_later",icon:"mdi:calendar-clock",path:"later",filter:{filter_due_min_days:31},matches:t=>t>=31}];function l(t){return{type:"grid",cards:[t]}}var X={condition:"view_columns",min:2};function _(t,n,e){let s=n[t];if(s)return`{{ states('${s}') }}`;let r=e[t];return r==null?"\u2014":String(r)}function z(t={},n={}){return{type:"markdown",text_only:!0,content:[`\u{1F534} **${_("overdue",t,n)}** ${c("overdue")}`,`\u26A1 **${_("triggered",t,n)}** ${c("triggered")}`,`\u{1F7E1} **${_("due_soon",t,n)}** ${c("due_soon")}`,`\u{1F7E2} **${_("ok",t,n)}** ${c("ok")}`].join(" \xB7 ")}}function Q(){return{title:c("maintenance"),type:"panel",cards:[{type:"empty-state",icon:"mdi:wrench-clock",icon_color:"primary",content_only:!0,title:c("strat_empty_title"),content:c("strat_empty_content"),buttons:[{icon:"mdi:wrench",text:c("strat_open_panel"),appearance:"filled",variant:"brand",tap_action:{action:"navigate",navigation_path:"/maintenance-supporter"}},{icon:"mdi:plus",text:c("strat_add_object"),appearance:"outlined",variant:"brand",tap_action:{action:"fire-dom-event",ll_custom:{type:"maintenance-supporter:add-object"}}}]}]}}function J(t={},n={}){let e=z(t,n);return{title:c("overview"),icon:"mdi:wrench-clock",path:"overview",type:"sections",header:{layout:"responsive",card:e},sidebar:{sections:[{type:"grid",cards:[{type:"heading",heading:c("strat_status"),heading_style:"title"},e]}],visibility:[X],content_label:c("tasks"),sidebar_label:c("strat_status")},sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:[...A]})]}}function Z(t,n){let e=new Map;for(let a of t){let i=a.object.area_id||null;e.has(i)||e.set(i,[]),e.get(i).push(a)}let s=Array.from(e.keys()).filter(a=>a!==null);s.sort((a,i)=>{let u=n[a]?.name||a,d=n[i]?.name||i;return u.localeCompare(d)});let r=[];for(let a of s){let i=e.get(a);if(i.length===0)continue;let u=n[a];r.push({title:u?.name||a,icon:u?.icon||"mdi:floor-plan",path:`area-${a}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:i.map(d=>d.object.name)})]})}let o=e.get(null);return o&&o.length>0&&r.push({title:c("unassigned"),icon:"mdi:help-circle-outline",path:"unassigned",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:o.map(a=>a.object.name)})]}),r}function ee(t){let n=new Set;for(let s of t)for(let r of s.tasks||[])r.status&&n.add(r.status);let e=[];for(let s of q)n.has(s.status)&&e.push({title:c(s.title),icon:s.icon,path:s.path,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:[s.status]})]});return e}function te(t,n,e){let s=new Map;for(let i of t){let u=i.object.area_id,d=u&&n[u]?.floor_id||null;s.has(d)||s.seLine truncated
<style>
:host, .editor { display: block; padding: 16px 0; }
label { display: block; font-weight: 500; margin-bottom: 8px; }
@@ -20,4 +20,4 @@ import{j as O}from"./chunks/chunk-IPUKIEZ2.js";import{c as A,d as p,g as j,i as
<select id="group-by">${s}</select>
<div class="help">${k(c("strat_editor_help"))}</div>
</div>
`;let r=this.querySelector("#group-by");r?.addEventListener("change",()=>{let o={...this._config,group_by:r.value};this._config=o,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:o},bubbles:!0,composed:!0}))})}},T="maintenance-supporter-section",ae=`ll-strategy-section-${T}`,b=class extends HTMLElement{static async generate(n,e){let s={type:"custom:maintenance-supporter-card",show_header:!1};n?.filter_status?.length&&(s.filter_status=n.filter_status),n?.max_items&&(s.max_items=n.max_items),n?.filter_due_min_days!==void 0&&(s.filter_due_min_days=n.filter_due_min_days),n?.filter_due_max_days!==void 0&&(s.filter_due_max_days=n.filter_due_max_days),n?.filter_objects?.length?s.filter_objects=n.filter_objects:n?.area_id&&(s.filter_areas=[n.area_id]);let r=[];return n?.title&&r.push({type:"heading",heading:n.title,heading_style:"title"}),r.push(s),{type:"grid",cards:r}}},U="2.3.6",ie="[maintenance-supporter]";function D(t,n){try{return customElements.get(t)?"skipped":(customElements.define(t,n),"ok")}catch(e){return`ERROR: ${String(e)}`}}var K={editor:D(B,E),section:D(ae,b)};console.log(`${ie} strategy bundle v${U} loaded \u2014 registrations:`,K,"\u2014 run maintenanceSupporterDiagnose() in console for full state");window.maintenanceSupporterDiagnose=async()=>{let t=W,n=[];try{let e=document.querySelector("home-assistant");e?.hass&&(n=(await e.hass.connection.sendMessagePromise({type:"lovelace/resources"})).resources||[])}catch(e){n=[{url:`<error: ${String(e)}>`}]}return{version:U,el_registered:!!customElements.get(t),el_class_excerpt:customElements.get(t)?.toString().slice(0,100)||null,customStrategies_dashboard:window.customStrategies?.filter(e=>e.strategyType==="dashboard").map(e=>e.type)||[],scriptTagsInPage:Array.from(document.querySelectorAll("script[type=module]")).map(e=>e.src).filter(e=>/maint|strateg/i.test(e)),lovelaceResources_matching:n.filter(e=>/maint|strateg/i.test(e.url||"")).map(e=>e.url),registrations:K}};var w=class extends HTMLElement{static async generate(n,e){return await import("./chunks/vacation-section-card-R5YCE3CM.js"),{type:"grid",cards:[{type:"custom:maintenance-vacation-section-card",title:n?.title}]}}},v=class extends HTMLElement{static async generate(n,e){return await import("./chunks/budget-section-card-TNXX4ZSN.js"),{type:"grid",cards:[{type:"custom:maintenance-budget-section-card",title:n?.title}]}}},S=class extends HTMLElement{static async generate(n,e){return await import("./chunks/groups-section-card-FW4PWBGZ.js"),{type:"grid",cards:[{type:"custom:maintenance-groups-section-card",title:n?.title}]}}},P="ll-strategy-section-maintenance-supporter-vacation",G="ll-strategy-section-maintenance-supporter-budget",N="ll-strategy-section-maintenance-supporter-groups";customElements.get(P)||customElements.define(P,w);customElements.get(G)||customElements.define(G,v);customElements.get(N)||customElements.define(N,S);var pe={[T]:b,"maintenance-supporter-vacation":w,"maintenance-supporter-budget":v,"maintenance-supporter-groups":S},f=null;function oe(){return f||(f=import("./chunks/dialog-mount-JZ3NZ27Q.js").catch(t=>{throw f=null,t})),f}var H="_msSupporterLlCustomBound";function m(t){history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed"))}function ce(){let t=window;t[H]||(t[H]=!0,document.addEventListener("ll-custom",n=>{let e=n.detail;if(!e||typeof e!="object")return;let s=e.ll_custom,r=s&&typeof s=="object"?s:e;if(!r||typeof r.type!="string"||!r.type.startsWith("maintenance-supporter:"))return;let o=r.type.slice(22);if(o==="deep-link"&&typeof r.path=="string"){m(r.path);return}(async()=>{let a;try{a=await oe()}catch{m("/maintenance-supporter");return}if(o==="add-object"){if(a.openCreateObjectDialog())return;m("/maintenance-supporter?ms_action=add_object");return}if(o==="open-task"&&typeof r.entry_id=="string"&&typeof r.task_id=="string"){if(a.openTaskQuickActions(r.entry_id,r.task_id)||a.openEditTaskDialog(r.entry_id,r.task_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(r.entry_id)}&task_id=${encodeURIComponent(r.task_id)}`);return}if(o==="open-object"&&typeof r.entry_id=="string"){if(a.openObjectQuickActions(r.entry_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(r.entry_id)}`);return}if(o==="edit-history"&&typeof r.entry_id=="string"&&typeof r.task_id=="string"&&typeof r.original_timestamp=="string"){let u=document.querySelector("home-assistant")?.hass;if(!u)return;try{let d=await O(u,r.entry_id,r.task_id,r.original_timestamp);if(!d)return;a.openHistoryEditDialog(d)}catch{m("/maintenance-supporter")}}})()}))}ce();var C=window;C.customStrategies=C.customStrategies||[];function g(t){C.customStrategies.some(e=>e.type===t.type&&e.strategyType===t.strategyType)||C.customStrategies.push(t)}g({type:V,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentati Line truncated
`;let r=this.querySelector("#group-by");r?.addEventListener("change",()=>{let o={...this._config,group_by:r.value};this._config=o,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:o},bubbles:!0,composed:!0}))})}},T="maintenance-supporter-section",ae=`ll-strategy-section-${T}`,b=class extends HTMLElement{static async generate(n,e){let s={type:"custom:maintenance-supporter-card",show_header:!1};n?.filter_status?.length&&(s.filter_status=n.filter_status),n?.max_items&&(s.max_items=n.max_items),n?.filter_due_min_days!==void 0&&(s.filter_due_min_days=n.filter_due_min_days),n?.filter_due_max_days!==void 0&&(s.filter_due_max_days=n.filter_due_max_days),n?.filter_objects?.length?s.filter_objects=n.filter_objects:n?.area_id&&(s.filter_areas=[n.area_id]);let r=[];return n?.title&&r.push({type:"heading",heading:n.title,heading_style:"title"}),r.push(s),{type:"grid",cards:r}}},U="2.3.6",ie="[maintenance-supporter]";function D(t,n){try{return customElements.get(t)?"skipped":(customElements.define(t,n),"ok")}catch(e){return`ERROR: ${String(e)}`}}var K={editor:D(B,E),section:D(ae,b)};console.log(`${ie} strategy bundle v${U} loaded \u2014 registrations:`,K,"\u2014 run maintenanceSupporterDiagnose() in console for full state");window.maintenanceSupporterDiagnose=async()=>{let t=W,n=[];try{let e=document.querySelector("home-assistant");e?.hass&&(n=(await e.hass.connection.sendMessagePromise({type:"lovelace/resources"})).resources||[])}catch(e){n=[{url:`<error: ${String(e)}>`}]}return{version:U,el_registered:!!customElements.get(t),el_class_excerpt:customElements.get(t)?.toString().slice(0,100)||null,customStrategies_dashboard:window.customStrategies?.filter(e=>e.strategyType==="dashboard").map(e=>e.type)||[],scriptTagsInPage:Array.from(document.querySelectorAll("script[type=module]")).map(e=>e.src).filter(e=>/maint|strateg/i.test(e)),lovelaceResources_matching:n.filter(e=>/maint|strateg/i.test(e.url||"")).map(e=>e.url),registrations:K}};var w=class extends HTMLElement{static async generate(n,e){return await import("./chunks/vacation-section-card-UQT2GD5E.js"),{type:"grid",cards:[{type:"custom:maintenance-vacation-section-card",title:n?.title}]}}},v=class extends HTMLElement{static async generate(n,e){return await import("./chunks/budget-section-card-IXKXHLWN.js"),{type:"grid",cards:[{type:"custom:maintenance-budget-section-card",title:n?.title}]}}},S=class extends HTMLElement{static async generate(n,e){return await import("./chunks/groups-section-card-3MFDN7CA.js"),{type:"grid",cards:[{type:"custom:maintenance-groups-section-card",title:n?.title}]}}},P="ll-strategy-section-maintenance-supporter-vacation",G="ll-strategy-section-maintenance-supporter-budget",N="ll-strategy-section-maintenance-supporter-groups";customElements.get(P)||customElements.define(P,w);customElements.get(G)||customElements.define(G,v);customElements.get(N)||customElements.define(N,S);var pe={[T]:b,"maintenance-supporter-vacation":w,"maintenance-supporter-budget":v,"maintenance-supporter-groups":S},f=null;function oe(){return f||(f=import("./chunks/dialog-mount-WHAZWA5V.js").catch(t=>{throw f=null,t})),f}var H="_msSupporterLlCustomBound";function m(t){history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed"))}function ce(){let t=window;t[H]||(t[H]=!0,document.addEventListener("ll-custom",n=>{let e=n.detail;if(!e||typeof e!="object")return;let s=e.ll_custom,r=s&&typeof s=="object"?s:e;if(!r||typeof r.type!="string"||!r.type.startsWith("maintenance-supporter:"))return;let o=r.type.slice(22);if(o==="deep-link"&&typeof r.path=="string"){m(r.path);return}(async()=>{let a;try{a=await oe()}catch{m("/maintenance-supporter");return}if(o==="add-object"){if(a.openCreateObjectDialog())return;m("/maintenance-supporter?ms_action=add_object");return}if(o==="open-task"&&typeof r.entry_id=="string"&&typeof r.task_id=="string"){if(a.openTaskQuickActions(r.entry_id,r.task_id)||a.openEditTaskDialog(r.entry_id,r.task_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(r.entry_id)}&task_id=${encodeURIComponent(r.task_id)}`);return}if(o==="open-object"&&typeof r.entry_id=="string"){if(a.openObjectQuickActions(r.entry_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(r.entry_id)}`);return}if(o==="edit-history"&&typeof r.entry_id=="string"&&typeof r.task_id=="string"&&typeof r.original_timestamp=="string"){let u=document.querySelector("home-assistant")?.hass;if(!u)return;try{let d=await O(u,r.entry_id,r.task_id,r.original_timestamp);if(!d)return;a.openHistoryEditDialog(d)}catch{m("/maintenance-supporter")}}})()}))}ce();var C=window;C.customStrategies=C.customStrategies||[];function g(t){C.customStrategies.some(e=>e.type===t.type&&e.strategyType===t.strategyType)||C.customStrategies.push(t)}g({type:V,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentati Line truncated