331 files

This commit is contained in:
Home Assistant Version Control committed 2026-10-04 05:26:42 +00:00
1 parent 22ba8b4648
commit c4d601bfba
331 files changed
+10227 -50159

No files matched your search

@@ -47,6 +47,19 @@
"bulk_delete_objects_confirm": "Smazat {n} objektů včetně všech jejich úkolů? Archivace místo toho zachová historii.",
"bulk_objects_deleted": "Smazáno objektů: {n}",
"bulk_objects_archived": "Archivováno objektů: {n}",
"bulk_assign": "Přiřadit",
"bulk_assign_one": "Jedna osoba",
"bulk_assign_rotate": "Více lidí, střídavě",
"bulk_assign_hint": "Nahradí přiřazení vybraných úkolů — včetně rotace.",
"bulk_rotation_min_two": "Vyberte alespoň dvě osoby.",
"bulk_labels_add": "Přidat štítky",
"bulk_labels_remove": "Odebrat štítky",
"bulk_edit_hint": "Změní se jen zaškrtnutá nastavení, vše ostatní zůstane beze změny.",
"bulk_no_notifications": "Bez oznámení pro tyto úkoly",
"bulk_updated": "Aktualizováno {n} úkolů",
"bulk_paused": "Pozastaveno {n} úkolů",
"bulk_resumed": "Obnoveno {n} úkolů",
"bulk_objects_area": "Oblast nastavena pro objekty: {n}",
"bulk_failed": "Nezdařilo se: {n} — {reason}",
"completing": "Dokončování…",
"interval": "Interval",
@@ -114,6 +127,8 @@
"custom": "Vlastní",
"history": "Historie",
"cost": "Náklady",
"cost_kind_credit": "Dobropis",
"cost_credit_hint": "Peníze zpět — prodej, vrácení. Snižuje součty; průměr na dokončení ho nezapočítává.",
"report_button": "Zpráva",
"report_title": "Zpráva o údržbě",
"report_generated": "Vytvořeno",
@@ -670,6 +685,7 @@
"settings_warranty_reminder_days": "Dny před vypršením",
"settings_warranty_reminder_hint": "Upozornit jednou, když do vypršení záruky objektu zbývá tolik dní.",
"settings_snooze_hours": "Doba odložení (hodiny)",
"settings_snooze_hours_hint": "Jak dlouho „Odložit“ ztiší připomínky úkolu — z nabídky úkolu, z karty, hlasem nebo tlačítkem Odložit v telefonu. Termín zůstává beze změny.",
"settings_budget": "Rozpočet",
"settings_currency": "Měna",
"settings_currency_decimals": "Desetinná místa částek",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "Slet {n} objekter og alle deres opgaver? Arkivering bevarer i stedet historikken.",
"bulk_objects_deleted": "{n} objekter slettet",
"bulk_objects_archived": "{n} objekter arkiveret",
"bulk_assign": "Tildel",
"bulk_assign_one": "Én person",
"bulk_assign_rotate": "Flere personer, på skift",
"bulk_assign_hint": "Erstatter, hvem de valgte opgaver er tildelt — også en rotation.",
"bulk_rotation_min_two": "Vælg mindst to personer.",
"bulk_labels_add": "Tilføj etiketter",
"bulk_labels_remove": "Fjern etiketter",
"bulk_edit_hint": "Kun de afkrydsede indstillinger ændres; alt andet forbliver som det er.",
"bulk_no_notifications": "Ingen notifikationer for disse opgaver",
"bulk_updated": "{n} opgaver opdateret",
"bulk_paused": "{n} opgaver sat på pause",
"bulk_resumed": "{n} opgaver genoptaget",
"bulk_objects_area": "Område angivet for {n} objekter",
"bulk_failed": "{n} mislykkedes: {reason}",
"completing": "Fuldfører…",
"interval": "Interval",
@@ -116,6 +129,8 @@
"custom": "Tilpasset",
"history": "Historik",
"cost": "Omkostning",
"cost_kind_credit": "Kreditering",
"cost_credit_hint": "Penge tilbage — et salg, en refusion. Sænker totalerne; gennemsnittet pr. udførelse medregner det ikke.",
"report_button": "Rapport",
"report_title": "Vedligeholdelsesrapport",
"report_generated": "Genereret",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "Dage før udløb",
"settings_warranty_reminder_hint": "Giv besked én gang, når et objekts garanti udløber om så mange dage.",
"settings_snooze_hours": "Udsættelsesvarighed (timer)",
"settings_snooze_hours_hint": "Hvor længe „Udsæt“ gør en opgaves påmindelser tavse — fra opgavemenuen, et kort, stemmen eller telefonens Udsæt-knap. Forfaldsdatoen forbliver uændret.",
"settings_budget": "Budget",
"settings_currency": "Valuta",
"settings_currency_decimals": "Decimaler for beløb",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "{n} Objekte mit allen ihren Aufgaben löschen? Archivieren behält stattdessen die Historie.",
"bulk_objects_deleted": "{n} Objekte gelöscht",
"bulk_objects_archived": "{n} Objekte archiviert",
"bulk_assign": "Zuweisen",
"bulk_assign_one": "Eine Person",
"bulk_assign_rotate": "Mehrere Personen, abwechselnd",
"bulk_assign_hint": "Ersetzt, wem die ausgewählten Aufgaben zugewiesen sind — eine Rotation eingeschlossen.",
"bulk_rotation_min_two": "Mindestens zwei Personen auswählen.",
"bulk_labels_add": "Labels hinzufügen",
"bulk_labels_remove": "Labels entfernen",
"bulk_edit_hint": "Nur die angehakten Einstellungen ändern sich, alles andere bleibt, wie es ist.",
"bulk_no_notifications": "Keine Benachrichtigungen für diese Aufgaben",
"bulk_updated": "{n} Aufgaben aktualisiert",
"bulk_paused": "{n} Aufgaben pausiert",
"bulk_resumed": "{n} Aufgaben fortgesetzt",
"bulk_objects_area": "Bereich für {n} Objekte gesetzt",
"bulk_failed": "{n} fehlgeschlagen: {reason}",
"completing": "Wird erledigt…",
"interval": "Intervall",
@@ -116,6 +129,8 @@
"custom": "Benutzerdefiniert",
"history": "Verlauf",
"cost": "Kosten",
"cost_kind_credit": "Gutschrift",
"cost_credit_hint": "Geld zurück – ein Verkauf, eine Erstattung. Senkt die Summen; der Durchschnitt pro Erledigung lässt es weg.",
"report_button": "Bericht",
"report_title": "Wartungsbericht",
"report_generated": "Erstellt",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "Tage vor Ablauf",
"settings_warranty_reminder_hint": "Einmal benachrichtigen, wenn die Garantie eines Objekts so viele Tage vor Ablauf steht.",
"settings_snooze_hours": "Schlummerdauer (Stunden)",
"settings_snooze_hours_hint": "Wie lange „Schlummern“ die Erinnerungen einer Aufgabe stummschaltet — im Aufgabenmenü, auf einer Karte, per Sprache oder mit der Schlummern-Taste am Handy. Das Fälligkeitsdatum bleibt, wie es ist.",
"settings_budget": "Budget",
"settings_currency": "Währung",
"settings_currency_decimals": "Nachkommastellen für Beträge",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "Delete {n} objects and all their tasks? Archiving keeps their history instead.",
"bulk_objects_deleted": "{n} objects deleted",
"bulk_objects_archived": "{n} objects archived",
"bulk_assign": "Assign",
"bulk_assign_one": "One person",
"bulk_assign_rotate": "Several people, in turns",
"bulk_assign_hint": "Replaces who is assigned to the selected tasks — a rotation included.",
"bulk_rotation_min_two": "Pick at least two people.",
"bulk_labels_add": "Add labels",
"bulk_labels_remove": "Remove labels",
"bulk_edit_hint": "Only the ticked settings change; everything else stays as it is.",
"bulk_no_notifications": "No notifications for these tasks",
"bulk_updated": "{n} tasks updated",
"bulk_paused": "{n} tasks paused",
"bulk_resumed": "{n} tasks resumed",
"bulk_objects_area": "Area set for {n} objects",
"bulk_failed": "{n} failed: {reason}",
"completing": "Completing…",
"interval": "Interval",
@@ -116,6 +129,8 @@
"custom": "Custom",
"history": "History",
"cost": "Cost",
"cost_kind_credit": "Credit",
"cost_credit_hint": "Money back — a sale, a refund. It lowers the totals; the average per completion leaves it out.",
"report_button": "Report",
"report_title": "Maintenance report",
"report_generated": "Generated",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "Days before expiry",
"settings_warranty_reminder_hint": "Notify once when an object's warranty is this many days from expiring.",
"settings_snooze_hours": "Snooze duration (hours)",
"settings_snooze_hours_hint": "How long Snooze mutes a task's reminders — from the task menu, a card, voice or the phone's Snooze button. The due date stays as it is.",
"settings_budget": "Budget",
"settings_currency": "Currency",
"settings_currency_decimals": "Decimal places for amounts",
@@ -47,6 +47,19 @@
"bulk_delete_objects_confirm": "¿Eliminar {n} objetos y todas sus tareas? Archivar conserva su historial.",
"bulk_objects_deleted": "{n} objetos eliminados",
"bulk_objects_archived": "{n} objetos archivados",
"bulk_assign": "Asignar",
"bulk_assign_one": "Una persona",
"bulk_assign_rotate": "Varias personas, por turnos",
"bulk_assign_hint": "Sustituye a quién están asignadas las tareas seleccionadas, incluida una rotación.",
"bulk_rotation_min_two": "Elige al menos dos personas.",
"bulk_labels_add": "Añadir etiquetas",
"bulk_labels_remove": "Quitar etiquetas",
"bulk_edit_hint": "Solo cambian los ajustes marcados; todo lo demás se queda como está.",
"bulk_no_notifications": "Sin notificaciones para estas tareas",
"bulk_updated": "{n} tareas actualizadas",
"bulk_paused": "{n} tareas pausadas",
"bulk_resumed": "{n} tareas reanudadas",
"bulk_objects_area": "Área asignada a {n} objetos",
"bulk_failed": "{n} fallidos: {reason}",
"completing": "Completando…",
"interval": "Intervalo",
@@ -114,6 +127,8 @@
"custom": "Personalizado",
"history": "Historial",
"cost": "Coste",
"cost_kind_credit": "Abono",
"cost_credit_hint": "Dinero que vuelve — una venta, un reembolso. Reduce los totales; la media por realización lo excluye.",
"report_button": "Informe",
"report_title": "Informe de mantenimiento",
"report_generated": "Generado",
@@ -670,6 +685,7 @@
"settings_warranty_reminder_days": "Días antes del vencimiento",
"settings_warranty_reminder_hint": "Notificar una vez cuando a la garantía de un objeto le queden estos días para vencer.",
"settings_snooze_hours": "Duración de posposición (horas)",
"settings_snooze_hours_hint": "Cuánto tiempo «Posponer» silencia los recordatorios de una tarea: desde el menú de la tarea, una tarjeta, la voz o el botón Posponer del teléfono. La fecha de vencimiento no cambia.",
"settings_budget": "Presupuesto",
"settings_currency": "Moneda",
"settings_currency_decimals": "Decimales de los importes",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "Poistetaanko {n} kohdetta kaikkine tehtävineen? Arkistointi säilyttää historian.",
"bulk_objects_deleted": "{n} kohdetta poistettu",
"bulk_objects_archived": "{n} kohdetta arkistoitu",
"bulk_assign": "Määritä",
"bulk_assign_one": "Yksi henkilö",
"bulk_assign_rotate": "Useita henkilöitä vuorotellen",
"bulk_assign_hint": "Korvaa valittujen tehtävien määritykset — myös kierron.",
"bulk_rotation_min_two": "Valitse vähintään kaksi henkilöä.",
"bulk_labels_add": "Lisää tunnisteita",
"bulk_labels_remove": "Poista tunnisteita",
"bulk_edit_hint": "Vain valitut asetukset muuttuvat; kaikki muu pysyy ennallaan.",
"bulk_no_notifications": "Ei ilmoituksia näistä tehtävistä",
"bulk_updated": "{n} tehtävää päivitetty",
"bulk_paused": "{n} tehtävää keskeytetty",
"bulk_resumed": "{n} tehtävää jatkettu",
"bulk_objects_area": "Alue asetettu {n} kohteelle",
"bulk_failed": "{n} epäonnistui: {reason}",
"completing": "Suoritetaan…",
"interval": "Väli",
@@ -116,6 +129,8 @@
"custom": "Mukautettu",
"history": "Historia",
"cost": "Kustannus",
"cost_kind_credit": "Hyvitys",
"cost_credit_hint": "Takaisin saatu raha — myynti, palautus. Pienentää summia; keskiarvo suoritusta kohden jättää sen pois.",
"report_button": "Raportti",
"report_title": "Huoltoraportti",
"report_generated": "Luotu",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "Päivää ennen päättymistä",
"settings_warranty_reminder_hint": "Ilmoita kerran, kun objektin takuun päättymiseen on näin monta päivää.",
"settings_snooze_hours": "Torkun kesto (tuntia)",
"settings_snooze_hours_hint": "Kuinka kauan Torkku mykistää tehtävän muistutukset — tehtävävalikosta, kortilta, äänellä tai puhelimen Torkku-painikkeella. Eräpäivä pysyy ennallaan.",
"settings_budget": "Budjetti",
"settings_currency": "Valuutta",
"settings_currency_decimals": "Summien desimaalit",
@@ -47,6 +47,19 @@
"bulk_delete_objects_confirm": "Supprimer {n} objets et toutes leurs tâches ? L'archivage conserve leur historique.",
"bulk_objects_deleted": "{n} objets supprimés",
"bulk_objects_archived": "{n} objets archivés",
"bulk_assign": "Assigner",
"bulk_assign_one": "Une personne",
"bulk_assign_rotate": "Plusieurs personnes, à tour de rôle",
"bulk_assign_hint": "Remplace l'attribution des tâches sélectionnées — rotation comprise.",
"bulk_rotation_min_two": "Choisissez au moins deux personnes.",
"bulk_labels_add": "Ajouter des étiquettes",
"bulk_labels_remove": "Retirer des étiquettes",
"bulk_edit_hint": "Seuls les réglages cochés changent ; tout le reste reste tel quel.",
"bulk_no_notifications": "Aucune notification pour ces tâches",
"bulk_updated": "{n} tâches mises à jour",
"bulk_paused": "{n} tâches mises en pause",
"bulk_resumed": "{n} tâches reprises",
"bulk_objects_area": "Zone définie pour {n} objets",
"bulk_failed": "{n} en échec : {reason}",
"completing": "En cours…",
"interval": "Intervalle",
@@ -114,6 +127,8 @@
"custom": "Personnalisé",
"history": "Historique",
"cost": "Coût",
"cost_kind_credit": "Crédit",
"cost_credit_hint": "Argent récupéré — une vente, un remboursement. Réduit les totaux ; la moyenne par réalisation l'ignore.",
"report_button": "Rapport",
"report_title": "Rapport d'entretien",
"report_generated": "Généré",
@@ -670,6 +685,7 @@
"settings_warranty_reminder_days": "Jours avant l'expiration",
"settings_warranty_reminder_hint": "Notifier une fois lorsque la garantie d'un objet expire dans ce nombre de jours.",
"settings_snooze_hours": "Durée de report (heures)",
"settings_snooze_hours_hint": "Durée pendant laquelle « Mettre en attente » coupe les rappels d'une tâche — depuis le menu de la tâche, une carte, la voix ou le bouton du téléphone. La date d'échéance ne change pas.",
"settings_budget": "Budget",
"settings_currency": "Devise",
"settings_currency_decimals": "Décimales des montants",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "{n} ऑब्जेक्ट और उनके सभी कार्य हटाएँ? संग्रहित करने से उनका इतिहास बना रहता है।",
"bulk_objects_deleted": "{n} ऑब्जेक्ट हटाए गए",
"bulk_objects_archived": "{n} ऑब्जेक्ट संग्रहित किए गए",
"bulk_assign": "असाइन करें",
"bulk_assign_one": "एक व्यक्ति",
"bulk_assign_rotate": "कई लोग, बारी-बारी से",
"bulk_assign_hint": "चुने गए कार्यों का असाइनमेंट बदल देता है — रोटेशन सहित।",
"bulk_rotation_min_two": "कम से कम दो लोग चुनें।",
"bulk_labels_add": "लेबल जोड़ें",
"bulk_labels_remove": "लेबल हटाएँ",
"bulk_edit_hint": "केवल चुनी गई सेटिंग्स बदलती हैं; बाकी सब वैसा ही रहता है।",
"bulk_no_notifications": "इन कार्यों के लिए कोई सूचना नहीं",
"bulk_updated": "{n} कार्य अपडेट किए गए",
"bulk_paused": "{n} कार्य रोके गए",
"bulk_resumed": "{n} कार्य फिर से शुरू किए गए",
"bulk_objects_area": "{n} ऑब्जेक्ट के लिए क्षेत्र सेट किया गया",
"bulk_failed": "{n} विफल: {reason}",
"completing": "पूर्ण किया जा रहा है…",
"interval": "अंतराल",
@@ -116,6 +129,8 @@
"custom": "कस्टम",
"history": "इतिहास",
"cost": "लागत",
"cost_kind_credit": "वापसी",
"cost_credit_hint": "वापस मिला पैसा — बिक्री, रिफ़ंड। यह कुल योग घटाता है; प्रति पूर्णता औसत में शामिल नहीं होता।",
"report_button": "रिपोर्ट",
"report_title": "रखरखाव रिपोर्ट",
"report_generated": "जनरेट किया गया",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "समाप्ति से पहले के दिन",
"settings_warranty_reminder_hint": "जब किसी वस्तु की वारंटी समाप्त होने में इतने दिन बचें तो एक बार सूचित करें।",
"settings_snooze_hours": "स्नूज़ अवधि (घंटे)",
"settings_snooze_hours_hint": "स्नूज़ किसी कार्य के रिमाइंडर कितनी देर तक बंद रखता है — कार्य मेनू, कार्ड, आवाज़ या फ़ोन के स्नूज़ बटन से। नियत तिथि नहीं बदलती।",
"settings_budget": "बजट",
"settings_currency": "मुद्रा",
"settings_currency_decimals": "राशियों के दशमलव स्थान",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "Törli a(z) {n} objektumot az összes feladatával együtt? Az archiválás ehelyett megőrzi az előzményeket.",
"bulk_objects_deleted": "{n} objektum törölve",
"bulk_objects_archived": "{n} objektum archiválva",
"bulk_assign": "Hozzárendelés",
"bulk_assign_one": "Egy személy",
"bulk_assign_rotate": "Több személy, felváltva",
"bulk_assign_hint": "Lecseréli, kihez vannak rendelve a kijelölt feladatok — a rotációt is.",
"bulk_rotation_min_two": "Válassz legalább két személyt.",
"bulk_labels_add": "Címkék hozzáadása",
"bulk_labels_remove": "Címkék eltávolítása",
"bulk_edit_hint": "Csak a bejelölt beállítások változnak, minden más marad.",
"bulk_no_notifications": "Nincs értesítés ezekhez a feladatokhoz",
"bulk_updated": "{n} feladat frissítve",
"bulk_paused": "{n} feladat szüneteltetve",
"bulk_resumed": "{n} feladat folytatva",
"bulk_objects_area": "Terület beállítva {n} objektumhoz",
"bulk_failed": "{n} sikertelen: {reason}",
"completing": "Elvégzés…",
"interval": "Intervallum",
@@ -116,6 +129,8 @@
"custom": "Egyéni",
"history": "Előzmények",
"cost": "Költség",
"cost_kind_credit": "Jóváírás",
"cost_credit_hint": "Visszakapott pénz — eladás, visszatérítés. Csökkenti az összegeket; az elvégzésenkénti átlag nem számolja.",
"report_button": "Jelentés",
"report_title": "Karbantartási jelentés",
"report_generated": "Létrehozva",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "Nappal a lejárat előtt",
"settings_warranty_reminder_hint": "Egyszeri értesítés, amikor egy objektum garanciája ennyi napra van a lejárattól.",
"settings_snooze_hours": "Szundi időtartama (óra)",
"settings_snooze_hours_hint": "Mennyi ideig némítja a Szundi egy feladat emlékeztetőit — a feladat menüjéből, egy kártyáról, hanggal vagy a telefon Szundi gombjával. A határidő nem változik.",
"settings_budget": "Költségkeret",
"settings_currency": "Pénznem",
"settings_currency_decimals": "Összegek tizedesjegyei",
@@ -47,6 +47,19 @@
"bulk_delete_objects_confirm": "Eliminare {n} oggetti con tutte le loro attività? L'archiviazione conserva invece la cronologia.",
"bulk_objects_deleted": "{n} oggetti eliminati",
"bulk_objects_archived": "{n} oggetti archiviati",
"bulk_assign": "Assegna",
"bulk_assign_one": "Una persona",
"bulk_assign_rotate": "Più persone, a turno",
"bulk_assign_hint": "Sostituisce a chi sono assegnate le attività selezionate, rotazione compresa.",
"bulk_rotation_min_two": "Scegli almeno due persone.",
"bulk_labels_add": "Aggiungi etichette",
"bulk_labels_remove": "Rimuovi etichette",
"bulk_edit_hint": "Cambiano solo le impostazioni spuntate; tutto il resto resta com'è.",
"bulk_no_notifications": "Nessuna notifica per queste attività",
"bulk_updated": "{n} attività aggiornate",
"bulk_paused": "{n} attività in pausa",
"bulk_resumed": "{n} attività riprese",
"bulk_objects_area": "Area impostata per {n} oggetti",
"bulk_failed": "{n} non riusciti: {reason}",
"completing": "Completamento…",
"interval": "Intervallo",
@@ -114,6 +127,8 @@
"custom": "Personalizzato",
"history": "Cronologia",
"cost": "Costo",
"cost_kind_credit": "Accredito",
"cost_credit_hint": "Denaro rientrato — una vendita, un rimborso. Riduce i totali; la media per completamento lo esclude.",
"report_button": "Report",
"report_title": "Report di manutenzione",
"report_generated": "Generato",
@@ -670,6 +685,7 @@
"settings_warranty_reminder_days": "Giorni prima della scadenza",
"settings_warranty_reminder_hint": "Notifica una volta quando alla garanzia di un oggetto mancano questi giorni alla scadenza.",
"settings_snooze_hours": "Durata posticipo (ore)",
"settings_snooze_hours_hint": "Per quanto tempo «Posponi» silenzia i promemoria di un'attività — dal menu dell'attività, da una scheda, con la voce o con il pulsante del telefono. La scadenza resta invariata.",
"settings_budget": "Budget",
"settings_currency": "Valuta",
"settings_currency_decimals": "Decimali degli importi",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "{n} 件のオブジェクトとそのすべてのタスクを削除しますか?アーカイブなら履歴が残ります。",
"bulk_objects_deleted": "{n} 件のオブジェクトを削除しました",
"bulk_objects_archived": "{n} 件のオブジェクトをアーカイブしました",
"bulk_assign": "割り当て",
"bulk_assign_one": "1人",
"bulk_assign_rotate": "複数人で交代制",
"bulk_assign_hint": "選択したタスクの担当者を置き換えます(ローテーションを含む)。",
"bulk_rotation_min_two": "2人以上を選んでください。",
"bulk_labels_add": "ラベルを追加",
"bulk_labels_remove": "ラベルを削除",
"bulk_edit_hint": "チェックした設定だけが変わり、それ以外はそのままです。",
"bulk_no_notifications": "これらのタスクは通知しない",
"bulk_updated": "{n} 件のタスクを更新しました",
"bulk_paused": "{n} 件のタスクを一時停止しました",
"bulk_resumed": "{n} 件のタスクを再開しました",
"bulk_objects_area": "{n} 件のオブジェクトにエリアを設定しました",
"bulk_failed": "{n} 件失敗:{reason}",
"completing": "完了処理中…",
"interval": "間隔",
@@ -116,6 +129,8 @@
"custom": "カスタム",
"history": "履歴",
"cost": "費用",
"cost_kind_credit": "収入",
"cost_credit_hint": "戻ってきたお金(売却、返金など)。合計を減らしますが、1回あたりの平均には含まれません。",
"report_button": "レポート",
"report_title": "メンテナンスレポート",
"report_generated": "作成日",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "期限切れ前の日数",
"settings_warranty_reminder_hint": "オブジェクトの保証期限までこの日数になったら一度通知します。",
"settings_snooze_hours": "スヌーズ時間(時間)",
"settings_snooze_hours_hint": "スヌーズでタスクのリマインダーを止める時間です。タスクのメニュー、カード、音声、スマートフォンのスヌーズボタンのどこから操作しても同じです。期日は変わりません。",
"settings_budget": "予算",
"settings_currency": "通貨",
"settings_currency_decimals": "金額の小数点以下の桁数",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "개체 {n}개와 모든 작업을 삭제할까요? 보관하면 기록이 유지됩니다.",
"bulk_objects_deleted": "개체 {n}개 삭제됨",
"bulk_objects_archived": "개체 {n}개 보관됨",
"bulk_assign": "배정",
"bulk_assign_one": "한 사람",
"bulk_assign_rotate": "여러 사람, 번갈아",
"bulk_assign_hint": "선택한 작업의 담당자를 바꿉니다 — 교대 방식 포함.",
"bulk_rotation_min_two": "두 명 이상 선택하세요.",
"bulk_labels_add": "라벨 추가",
"bulk_labels_remove": "라벨 제거",
"bulk_edit_hint": "체크한 설정만 바뀌고 나머지는 그대로입니다.",
"bulk_no_notifications": "이 작업들은 알림 없음",
"bulk_updated": "작업 {n}개 업데이트됨",
"bulk_paused": "작업 {n}개 일시 중지됨",
"bulk_resumed": "작업 {n}개 재개됨",
"bulk_objects_area": "개체 {n}개의 구역을 설정함",
"bulk_failed": "{n}개 실패: {reason}",
"completing": "완료 처리 중…",
"interval": "주기",
@@ -116,6 +129,8 @@
"custom": "사용자 지정",
"history": "기록",
"cost": "비용",
"cost_kind_credit": "수입",
"cost_credit_hint": "돌려받은 돈(판매, 환불 등). 합계를 줄이며, 완료당 평균에는 포함되지 않습니다.",
"report_button": "보고서",
"report_title": "유지보수 보고서",
"report_generated": "생성일",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "만료 전 일수",
"settings_warranty_reminder_hint": "객체의 보증 만료가 설정한 일수만큼 남았을 때 한 번 알립니다.",
"settings_snooze_hours": "다시 알림 대기 시간 (시간)",
"settings_snooze_hours_hint": "다시 알림이 작업 알림을 끄는 시간입니다 — 작업 메뉴, 카드, 음성, 휴대폰의 다시 알림 버튼 어디에서 해도 같습니다. 기한은 바뀌지 않습니다.",
"settings_budget": "예산",
"settings_currency": "통화",
"settings_currency_decimals": "금액 소수 자릿수",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "Slette {n} objekter og alle oppgavene deres? Arkivering beholder historikken i stedet.",
"bulk_objects_deleted": "{n} objekter slettet",
"bulk_objects_archived": "{n} objekter arkivert",
"bulk_assign": "Tildel",
"bulk_assign_one": "Én person",
"bulk_assign_rotate": "Flere personer, på omgang",
"bulk_assign_hint": "Erstatter hvem de valgte oppgavene er tildelt — også en rotasjon.",
"bulk_rotation_min_two": "Velg minst to personer.",
"bulk_labels_add": "Legg til etiketter",
"bulk_labels_remove": "Fjern etiketter",
"bulk_edit_hint": "Bare de avkryssede innstillingene endres; alt annet forblir som det er.",
"bulk_no_notifications": "Ingen varsler for disse oppgavene",
"bulk_updated": "{n} oppgaver oppdatert",
"bulk_paused": "{n} oppgaver satt på pause",
"bulk_resumed": "{n} oppgaver gjenopptatt",
"bulk_objects_area": "Område satt for {n} objekter",
"bulk_failed": "{n} mislyktes: {reason}",
"completing": "Fullfører…",
"interval": "Intervall",
@@ -116,6 +129,8 @@
"custom": "Egendefinert",
"history": "Historikk",
"cost": "Kostnad",
"cost_kind_credit": "Kreditering",
"cost_credit_hint": "Penger tilbake — et salg, en refusjon. Senker summene; snittet per utførelse tar det ikke med.",
"report_button": "Rapport",
"report_title": "Vedlikeholdsrapport",
"report_generated": "Generert",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "Dager før utløp",
"settings_warranty_reminder_hint": "Varsle én gang når garantien til et objekt utløper om så mange dager.",
"settings_snooze_hours": "Slumrevarighet (timer)",
"settings_snooze_hours_hint": "Hvor lenge «Slumre» demper en oppgaves påminnelser — fra oppgavemenyen, et kort, stemmen eller telefonens Slumre-knapp. Forfallsdatoen forblir uendret.",
"settings_budget": "Budsjett",
"settings_currency": "Valuta",
"settings_currency_decimals": "Desimaler for beløp",
@@ -47,6 +47,19 @@
"bulk_delete_objects_confirm": "{n} objecten met al hun taken verwijderen? Archiveren bewaart in plaats daarvan de geschiedenis.",
"bulk_objects_deleted": "{n} objecten verwijderd",
"bulk_objects_archived": "{n} objecten gearchiveerd",
"bulk_assign": "Toewijzen",
"bulk_assign_one": "Eén persoon",
"bulk_assign_rotate": "Meerdere personen, om de beurt",
"bulk_assign_hint": "Vervangt aan wie de geselecteerde taken zijn toegewezen — een rotatie inbegrepen.",
"bulk_rotation_min_two": "Kies ten minste twee personen.",
"bulk_labels_add": "Labels toevoegen",
"bulk_labels_remove": "Labels verwijderen",
"bulk_edit_hint": "Alleen de aangevinkte instellingen veranderen; al het andere blijft zoals het is.",
"bulk_no_notifications": "Geen notificaties voor deze taken",
"bulk_updated": "{n} taken bijgewerkt",
"bulk_paused": "{n} taken gepauzeerd",
"bulk_resumed": "{n} taken hervat",
"bulk_objects_area": "Gebied ingesteld voor {n} objecten",
"bulk_failed": "{n} mislukt: {reason}",
"completing": "Wordt voltooid…",
"interval": "Interval",
@@ -114,6 +127,8 @@
"custom": "Aangepast",
"history": "Geschiedenis",
"cost": "Kosten",
"cost_kind_credit": "Tegoed",
"cost_credit_hint": "Geld terug — een verkoop, een terugbetaling. Verlaagt de totalen; het gemiddelde per voltooiing laat het weg.",
"report_button": "Rapport",
"report_title": "Onderhoudsrapport",
"report_generated": "Gegenereerd",
@@ -670,6 +685,7 @@
"settings_warranty_reminder_days": "Dagen vóór afloop",
"settings_warranty_reminder_hint": "Eén keer melden wanneer de garantie van een object over zoveel dagen afloopt.",
"settings_snooze_hours": "Snoozeduur (uren)",
"settings_snooze_hours_hint": "Hoe lang ‘Sluimeren’ de herinneringen van een taak dempt — vanuit het taakmenu, een kaart, spraak of de sluimerknop op de telefoon. De vervaldatum blijft zoals hij is.",
"settings_budget": "Budget",
"settings_currency": "Valuta",
"settings_currency_decimals": "Decimalen voor bedragen",
@@ -47,6 +47,19 @@
"bulk_delete_objects_confirm": "Usunąć {n} obiektów wraz ze wszystkimi zadaniami? Archiwizacja zachowa ich historię.",
"bulk_objects_deleted": "Usunięto obiektów: {n}",
"bulk_objects_archived": "Zarchiwizowano obiektów: {n}",
"bulk_assign": "Przypisz",
"bulk_assign_one": "Jedna osoba",
"bulk_assign_rotate": "Kilka osób, na zmianę",
"bulk_assign_hint": "Zastępuje przypisanie wybranych zadań — łącznie z rotacją.",
"bulk_rotation_min_two": "Wybierz co najmniej dwie osoby.",
"bulk_labels_add": "Dodaj etykiety",
"bulk_labels_remove": "Usuń etykiety",
"bulk_edit_hint": "Zmieniają się tylko zaznaczone ustawienia; wszystko inne pozostaje bez zmian.",
"bulk_no_notifications": "Bez powiadomień dla tych zadań",
"bulk_updated": "Zaktualizowano {n} zadań",
"bulk_paused": "Wstrzymano {n} zadań",
"bulk_resumed": "Wznowiono {n} zadań",
"bulk_objects_area": "Ustawiono obszar dla obiektów: {n}",
"bulk_failed": "Nieudane: {n} — {reason}",
"completing": "Wykonywanie…",
"interval": "Interwał",
@@ -114,6 +127,8 @@
"custom": "Niestandardowy",
"history": "Historia",
"cost": "Koszt",
"cost_kind_credit": "Zwrot",
"cost_credit_hint": "Odzyskane pieniądze — sprzedaż, zwrot. Obniża sumy; średnia na wykonanie go pomija.",
"report_button": "Raport",
"report_title": "Raport konserwacji",
"report_generated": "Wygenerowano",
@@ -670,6 +685,7 @@
"settings_warranty_reminder_days": "Dni przed wygaśnięciem",
"settings_warranty_reminder_hint": "Powiadom raz, gdy do wygaśnięcia gwarancji obiektu pozostanie tyle dni.",
"settings_snooze_hours": "Czas drzemki (godziny)",
"settings_snooze_hours_hint": "Jak długo „Drzemka” wycisza przypomnienia zadania — z menu zadania, z karty, głosem lub przyciskiem Drzemka w telefonie. Termin pozostaje bez zmian.",
"settings_budget": "Budżet",
"settings_currency": "Waluta",
"settings_currency_decimals": "Miejsca po przecinku w kwotach",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "Excluir {n} objetos e todas as suas tarefas? Arquivar mantém o histórico.",
"bulk_objects_deleted": "{n} objetos excluídos",
"bulk_objects_archived": "{n} objetos arquivados",
"bulk_assign": "Atribuir",
"bulk_assign_one": "Uma pessoa",
"bulk_assign_rotate": "Várias pessoas, em rodízio",
"bulk_assign_hint": "Substitui a quem as tarefas selecionadas estão atribuídas — incluindo um rodízio.",
"bulk_rotation_min_two": "Escolha pelo menos duas pessoas.",
"bulk_labels_add": "Adicionar etiquetas",
"bulk_labels_remove": "Remover etiquetas",
"bulk_edit_hint": "Só as configurações marcadas mudam; todo o resto continua como está.",
"bulk_no_notifications": "Sem notificações para estas tarefas",
"bulk_updated": "{n} tarefas atualizadas",
"bulk_paused": "{n} tarefas pausadas",
"bulk_resumed": "{n} tarefas retomadas",
"bulk_objects_area": "Área definida para {n} objetos",
"bulk_failed": "{n} falharam: {reason}",
"completing": "Concluindo…",
"interval": "Intervalo",
@@ -116,6 +129,8 @@
"custom": "Personalizado",
"history": "Histórico",
"cost": "Custo",
"cost_kind_credit": "Crédito",
"cost_credit_hint": "Dinheiro de volta — uma venda, um reembolso. Reduz os totais; a média por conclusão não o conta.",
"report_button": "Relatório",
"report_title": "Relatório de manutenção",
"report_generated": "Gerado em",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "Dias antes do vencimento",
"settings_warranty_reminder_hint": "Notifica uma vez quando faltar este número de dias para a garantia de um objeto expirar.",
"settings_snooze_hours": "Duração da soneca (horas)",
"settings_snooze_hours_hint": "Por quanto tempo a Soneca silencia os lembretes de uma tarefa — pelo menu da tarefa, por um cartão, pela voz ou pelo botão Soneca do celular. A data de vencimento não muda.",
"settings_budget": "Orçamento",
"settings_currency": "Moeda",
"settings_currency_decimals": "Casas decimais dos valores",
@@ -47,6 +47,19 @@
"bulk_delete_objects_confirm": "Eliminar {n} objetos e todas as suas tarefas? Arquivar mantém o histórico.",
"bulk_objects_deleted": "{n} objetos eliminados",
"bulk_objects_archived": "{n} objetos arquivados",
"bulk_assign": "Atribuir",
"bulk_assign_one": "Uma pessoa",
"bulk_assign_rotate": "Várias pessoas, à vez",
"bulk_assign_hint": "Substitui a quem as tarefas selecionadas estão atribuídas — incluindo uma rotação.",
"bulk_rotation_min_two": "Escolha pelo menos duas pessoas.",
"bulk_labels_add": "Adicionar etiquetas",
"bulk_labels_remove": "Remover etiquetas",
"bulk_edit_hint": "Só as definições assinaladas mudam; tudo o resto fica como está.",
"bulk_no_notifications": "Sem notificações para estas tarefas",
"bulk_updated": "{n} tarefas atualizadas",
"bulk_paused": "{n} tarefas pausadas",
"bulk_resumed": "{n} tarefas retomadas",
"bulk_objects_area": "Área definida para {n} objetos",
"bulk_failed": "{n} falharam: {reason}",
"completing": "A concluir…",
"interval": "Intervalo",
@@ -114,6 +127,8 @@
"custom": "Personalizado",
"history": "Histórico",
"cost": "Custo",
"cost_kind_credit": "Crédito",
"cost_credit_hint": "Dinheiro que regressa — uma venda, um reembolso. Reduz os totais; a média por conclusão não o conta.",
"report_button": "Relatório",
"report_title": "Relatório de manutenção",
"report_generated": "Gerado",
@@ -670,6 +685,7 @@
"settings_warranty_reminder_days": "Dias antes do fim",
"settings_warranty_reminder_hint": "Notificar uma vez quando faltarem estes dias para a garantia de um objeto expirar.",
"settings_snooze_hours": "Duração do adiamento (horas)",
"settings_snooze_hours_hint": "Durante quanto tempo «Adiar» silencia os lembretes de uma tarefa — a partir do menu da tarefa, de um cartão, por voz ou do botão Adiar do telemóvel. A data limite mantém-se.",
"settings_budget": "Orçamento",
"settings_currency": "Moeda",
"settings_currency_decimals": "Casas decimais dos montantes",
@@ -47,6 +47,19 @@
"bulk_delete_objects_confirm": "Удалить {n} объектов со всеми их задачами? Архивация вместо этого сохранит историю.",
"bulk_objects_deleted": "Удалено объектов: {n}",
"bulk_objects_archived": "Архивировано объектов: {n}",
"bulk_assign": "Назначить",
"bulk_assign_one": "Один человек",
"bulk_assign_rotate": "Несколько человек по очереди",
"bulk_assign_hint": "Заменяет назначение выбранных задач — включая ротацию.",
"bulk_rotation_min_two": "Выберите не менее двух человек.",
"bulk_labels_add": "Добавить метки",
"bulk_labels_remove": "Удалить метки",
"bulk_edit_hint": "Меняются только отмеченные настройки, всё остальное остаётся как есть.",
"bulk_no_notifications": "Без уведомлений для этих задач",
"bulk_updated": "Обновлено задач: {n}",
"bulk_paused": "Приостановлено задач: {n}",
"bulk_resumed": "Возобновлено задач: {n}",
"bulk_objects_area": "Зона задана для объектов: {n}",
"bulk_failed": "Не удалось: {n} — {reason}",
"completing": "Выполнение…",
"interval": "Интервал",
@@ -114,6 +127,8 @@
"custom": "Своё",
"history": "История",
"cost": "Стоимость",
"cost_kind_credit": "Возврат",
"cost_credit_hint": "Деньги вернулись — продажа, возврат. Уменьшает итоги; среднее за выполнение его не учитывает.",
"report_button": "Отчёт",
"report_title": "Отчёт об обслуживании",
"report_generated": "Создан",
@@ -670,6 +685,7 @@
"settings_warranty_reminder_days": "Дней до окончания",
"settings_warranty_reminder_hint": "Уведомить один раз, когда до окончания гарантии объекта останется столько дней.",
"settings_snooze_hours": "Длительность откладывания (часы)",
"settings_snooze_hours_hint": "Как долго «Отложить» глушит напоминания задачи — из меню задачи, с карточки, голосом или кнопкой «Отложить» на телефоне. Срок выполнения не меняется.",
"settings_budget": "Бюджет",
"settings_currency": "Валюта",
"settings_currency_decimals": "Знаков после запятой в суммах",
@@ -47,6 +47,19 @@
"bulk_delete_objects_confirm": "Ta bort {n} objekt och alla deras uppgifter? Arkivering behåller historiken i stället.",
"bulk_objects_deleted": "{n} objekt borttagna",
"bulk_objects_archived": "{n} objekt arkiverade",
"bulk_assign": "Tilldela",
"bulk_assign_one": "En person",
"bulk_assign_rotate": "Flera personer, turvis",
"bulk_assign_hint": "Ersätter vem de valda uppgifterna är tilldelade — även en rotation.",
"bulk_rotation_min_two": "Välj minst två personer.",
"bulk_labels_add": "Lägg till etiketter",
"bulk_labels_remove": "Ta bort etiketter",
"bulk_edit_hint": "Bara de markerade inställningarna ändras; allt annat förblir som det är.",
"bulk_no_notifications": "Inga aviseringar för de här uppgifterna",
"bulk_updated": "{n} uppgifter uppdaterade",
"bulk_paused": "{n} uppgifter pausade",
"bulk_resumed": "{n} uppgifter återupptagna",
"bulk_objects_area": "Område angivet för {n} objekt",
"bulk_failed": "{n} misslyckades: {reason}",
"completing": "Slutför…",
"interval": "Intervall",
@@ -114,6 +127,8 @@
"custom": "Anpassad",
"history": "Historik",
"cost": "Kostnad",
"cost_kind_credit": "Kreditering",
"cost_credit_hint": "Pengar tillbaka — en försäljning, en återbetalning. Sänker summorna; snittet per utförande räknar inte med det.",
"report_button": "Rapport",
"report_title": "Underhållsrapport",
"report_generated": "Genererad",
@@ -670,6 +685,7 @@
"settings_warranty_reminder_days": "Dagar före utgång",
"settings_warranty_reminder_hint": "Meddela en gång när ett objekts garanti har så här många dagar kvar.",
"settings_snooze_hours": "Snooza-tid (timmar)",
"settings_snooze_hours_hint": "Hur länge ”Snooza” tystar en uppgifts påminnelser — från uppgiftsmenyn, ett kort, rösten eller telefonens Snooza-knapp. Förfallodatumet ändras inte.",
"settings_budget": "Budget",
"settings_currency": "Valuta",
"settings_currency_decimals": "Decimaler för belopp",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "{n} nesne ve tüm görevleri silinsin mi? Arşivlemek geçmişi korur.",
"bulk_objects_deleted": "{n} nesne silindi",
"bulk_objects_archived": "{n} nesne arşivlendi",
"bulk_assign": "Ata",
"bulk_assign_one": "Bir kişi",
"bulk_assign_rotate": "Birden çok kişi, sırayla",
"bulk_assign_hint": "Seçili görevlerin kime atandığını değiştirir — rotasyon dahil.",
"bulk_rotation_min_two": "En az iki kişi seçin.",
"bulk_labels_add": "Etiket ekle",
"bulk_labels_remove": "Etiketleri kaldır",
"bulk_edit_hint": "Yalnızca işaretli ayarlar değişir; geri kalan her şey olduğu gibi kalır.",
"bulk_no_notifications": "Bu görevler için bildirim yok",
"bulk_updated": "{n} görev güncellendi",
"bulk_paused": "{n} görev duraklatıldı",
"bulk_resumed": "{n} göreve devam edildi",
"bulk_objects_area": "{n} nesne için alan ayarlandı",
"bulk_failed": "{n} başarısız: {reason}",
"completing": "Tamamlanıyor…",
"interval": "Aralık",
@@ -116,6 +129,8 @@
"custom": "Özel",
"history": "Geçmiş",
"cost": "Maliyet",
"cost_kind_credit": "İade",
"cost_credit_hint": "Geri gelen para — bir satış, bir iade. Toplamları düşürür; tamamlama başına ortalamaya katılmaz.",
"report_button": "Rapor",
"report_title": "Bakım raporu",
"report_generated": "Oluşturulma",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "Bitişten gün önce",
"settings_warranty_reminder_hint": "Bir nesnenin garantisinin bitmesine bu kadar gün kaldığında bir kez bildir.",
"settings_snooze_hours": "Erteleme süresi (saat)",
"settings_snooze_hours_hint": "Ertele'nin bir görevin hatırlatmalarını ne kadar süre sessize aldığı — görev menüsünden, bir karttan, sesle veya telefondaki Ertele düğmesiyle. Son tarih değişmez.",
"settings_budget": "Bütçe",
"settings_currency": "Para birimi",
"settings_currency_decimals": "Tutarlarda ondalık basamak",
@@ -47,6 +47,19 @@
"bulk_delete_objects_confirm": "Видалити {n} об'єктів з усіма їхніми завданнями? Архівування натомість збереже історію.",
"bulk_objects_deleted": "Видалено об'єктів: {n}",
"bulk_objects_archived": "Архівовано об'єктів: {n}",
"bulk_assign": "Призначити",
"bulk_assign_one": "Одна людина",
"bulk_assign_rotate": "Кілька людей по черзі",
"bulk_assign_hint": "Замінює призначення вибраних завдань — разом із ротацією.",
"bulk_rotation_min_two": "Виберіть щонайменше двох людей.",
"bulk_labels_add": "Додати мітки",
"bulk_labels_remove": "Вилучити мітки",
"bulk_edit_hint": "Змінюються лише позначені налаштування, усе інше лишається як є.",
"bulk_no_notifications": "Без сповіщень для цих завдань",
"bulk_updated": "Оновлено завдань: {n}",
"bulk_paused": "Призупинено завдань: {n}",
"bulk_resumed": "Відновлено завдань: {n}",
"bulk_objects_area": "Зону задано для об'єктів: {n}",
"bulk_failed": "Не вдалося: {n} — {reason}",
"completing": "Виконується…",
"interval": "Інтервал",
@@ -114,6 +127,8 @@
"custom": "Власний",
"history": "Історія",
"cost": "Вартість",
"cost_kind_credit": "Повернення",
"cost_credit_hint": "Гроші повернулися — продаж, відшкодування. Зменшує підсумки; середнє за виконання його не враховує.",
"report_button": "Звіт",
"report_title": "Звіт про обслуговування",
"report_generated": "Створено",
@@ -670,6 +685,7 @@
"settings_warranty_reminder_days": "Днів до завершення",
"settings_warranty_reminder_hint": "Сповістити один раз, коли до завершення гарантії об'єкта залишиться стільки днів.",
"settings_snooze_hours": "Тривалість відкладення (години)",
"settings_snooze_hours_hint": "Як довго «Відкласти» вимикає нагадування завдання — з меню завдання, картки, голосом або кнопкою «Відкласти» на телефоні. Термін не змінюється.",
"settings_budget": "Бюджет",
"settings_currency": "Валюта",
"settings_currency_decimals": "Знаків після коми в сумах",
@@ -49,6 +49,19 @@
"bulk_delete_objects_confirm": "删除 {n} 个对象及其全部任务?归档则会保留其历史记录。",
"bulk_objects_deleted": "已删除 {n} 个对象",
"bulk_objects_archived": "已归档 {n} 个对象",
"bulk_assign": "分配",
"bulk_assign_one": "一个人",
"bulk_assign_rotate": "多人轮流",
"bulk_assign_hint": "替换所选任务的负责人——包括轮换。",
"bulk_rotation_min_two": "请至少选择两个人。",
"bulk_labels_add": "添加标签",
"bulk_labels_remove": "移除标签",
"bulk_edit_hint": "只有勾选的设置会改变,其余保持不变。",
"bulk_no_notifications": "这些任务不发送通知",
"bulk_updated": "已更新 {n} 个任务",
"bulk_paused": "已暂停 {n} 个任务",
"bulk_resumed": "已继续 {n} 个任务",
"bulk_objects_area": "已为 {n} 个对象设置区域",
"bulk_failed": "{n} 项失败:{reason}",
"completing": "正在完成…",
"interval": "间隔",
@@ -116,6 +129,8 @@
"custom": "自定义",
"history": "历史记录",
"cost": "成本",
"cost_kind_credit": "收入",
"cost_credit_hint": "回收的钱——出售、退款。会降低总计;每次完成的平均值不计入。",
"report_button": "报告",
"report_title": "维护报告",
"report_generated": "生成于",
@@ -672,6 +687,7 @@
"settings_warranty_reminder_days": "到期前天数",
"settings_warranty_reminder_hint": "当物品保修距到期还有这么多天时通知一次。",
"settings_snooze_hours": "稍后提醒间隔 (小时)",
"settings_snooze_hours_hint": "“稍后提醒”让任务提醒静音的时长——无论来自任务菜单、卡片、语音还是手机上的稍后提醒按钮。截止日期保持不变。",
"settings_budget": "预算",
"settings_currency": "货币单位",
"settings_currency_decimals": "金额小数位数",
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.96.0 */
var v="2.96.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
/*! 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
@@ -1,250 +0,0 @@
/*! maintenance_supporter frontend 2.88.0 */
import{e as f}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-Z4FODB56.js";import{a as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-XRSEIZKJ.js";import{a as o,b as _,c as i,f as l,h,l as g,m as n,q as t,s as u,u as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OXPKT66L.js";var r=class extends h{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._adopting=!1;this._error="";this._sensors=[];this._selected=new Set;this._users=[];this._responsible="";this._forMinutes="0";this._localeReady=!1;this._userService=null;this._toggle=s=>{let a=new Set(this._selected);a.has(s)?a.delete(s):a.add(s),this._selected=a};this._toggleAll=()=>{this._selected.size===this._sensors.length?this._selected=new Set:this._selected=new Set(this._sensors.map(s=>s.entity_id))};this._adopt=async()=>{if(!(this._selected.size===0||this._adopting)){this._adopting=!0,this._error="";try{let s=this._sensors.filter(e=>this._selected.has(e.entity_id)).map(e=>({entity_id:e.entity_id,name:e.name,entry_id:e.suggested_entry_id??void 0,object_name:e.suggested_object_name,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})),a=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/problem_sensors/adopt",selections:s});this.dispatchEvent(new CustomEvent("problem-sensors-adopted",{bubbles:!0,composed:!0,detail:a})),this._open=!1}catch(s){this._error=p(s,this._lang)}finally{this._adopting=!1}}}}get _lang(){return u(this.hass)}updated(s){s.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,v(this._lang).then(()=>this.requestUpdate()))}async open(){this._open=!0,this._loading=!0,this._error="",this._sensors=[],this._selected=new Set,this._responsible="",this._forMinutes="0";try{this._userService?this._userService.updateHass(this.hass):this._userService=new f(this.hass);let[s,a]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/problem_sensors/discover"}),this._userService.getUsers().catch(()=>[])]);this._sensors=s.sensors||[],this._selected=new Set(this._sensors.map(e=>e.entity_id)),this._users=a}catch(s){this._error=p(s,this._lang)}finally{this._loading=!1}}_close(){this._open=!1}render(){if(!this._open)return i``;let s=this._lang,a=this._sensors.length>0&&this._selected.size===this._sensors.length;return i`
<div class="overlay" @click=${this._close}>
<div class="card" @click=${e=>e.stopPropagation()}>
<div class="title">${t("adopt_problem_title",s)}</div>
<div class="hint">${t("adopt_problem_hint",s)}</div>
${this._error?i`<div class="error">${this._error}</div>`:l}
${this._loading?i`<div class="loading">…</div>`:this._sensors.length===0?i`<div class="empty">${t("adopt_problem_none",s)}</div>`:i`
<label class="select-all">
<input
type="checkbox"
.checked=${a}
@change=${this._toggleAll}
/>
<span>${t("selected",s)}: ${this._selected.size} / ${this._sensors.length}</span>
</label>
<div class="list">
${this._sensors.map(e=>{let m=this._selected.has(e.entity_id),d=e.state==="on",c=[e.device_name,e.area_name].filter(Boolean).join(" \xB7 ");return i`
<label class="row">
<input
type="checkbox"
.checked=${m}
@change=${()=>this._toggle(e.entity_id)}
/>
<div class="row-main">
<div class="row-top">
<span class="row-name">${e.name}</span>
<span class="chip ${d?"chip-active":"chip-ok"}">
${d?t("adopt_problem_active",s):t("adopt_problem_ok",s)}
</span>
</div>
${c?i`<div class="row-sub">${c}</div>`:l}
<div class="row-target">
→ ${e.suggested_object_name}${e.suggested_entry_id?l:i` <span class="new-tag">${t("adopt_problem_new_object",s)}</span>`}
</div>
${e.suggested_part_name?i`<div class="row-part">
<ha-icon icon="mdi:package-variant-closed"></ha-icon>
${t("adopt_problem_part",s).replace("{name}",e.suggested_part_name)}
</div>`:l}
</div>
</label>
`})}
</div>
`}
${!this._loading&&this._sensors.length>0?i`
<label class="responsible">
<span>${t("for_at_least_minutes",s)}</span>
<input
class="for-input"
type="number"
min="0"
max="1440"
.value=${this._forMinutes}
@input=${e=>this._forMinutes=e.target.value}
/>
</label>
<div class="for-hint">${t("adopt_for_minutes_hint",s)}</div>
`:l}
${!this._loading&&this._sensors.length>0&&this._users.length>0?i`
<label class="responsible">
<span>${t("adopt_problem_responsible",s)}</span>
<select
.value=${this._responsible}
@change=${e=>{this._responsible=e.target.value}}
>
<option value="" ?selected=${!this._responsible}>${t("no_user_assigned",s)}</option>
${this._users.map(e=>i`<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}>
${t("cancel",s)}
</ha-button>
<ha-button
@click=${this._adopt}
.disabled=${this._selected.size===0||this._adopting}
>
${t("adopt_problem_adopt",s)}
</ha-button>
</div>
</div>
</div>
`}};r.styles=_`
.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-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;
}
.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})],r.prototype,"hass",2),o([n()],r.prototype,"_open",2),o([n()],r.prototype,"_loading",2),o([n()],r.prototype,"_adopting",2),o([n()],r.prototype,"_error",2),o([n()],r.prototype,"_sensors",2),o([n()],r.prototype,"_selected",2),o([n()],r.prototype,"_users",2),o([n()],r.prototype,"_responsible",2),o([n()],r.prototype,"_forMinutes",2);customElements.get("maintenance-adopt-problem-sensors-dialog")||customElements.define("maintenance-adopt-problem-sensors-dialog",r);export{r as MaintenanceAdoptProblemSensorsDialog};
@@ -1,301 +0,0 @@
/*! maintenance_supporter frontend 2.94.0 */
import{e as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-6LZYA7IL.js";import{d as m}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-63C4ZGBD.js";import{a as h}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-K4SNNHPR.js";import{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,w as b}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-JE577H3E.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 f(this.hass)}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,b(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};
@@ -1,301 +0,0 @@
/*! maintenance_supporter frontend 2.95.0 */
import{e as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-UJICOAU3.js";import{d as m}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-LEWJHPDY.js";import{a as h}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GGJ6YWZO.js";import{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,y as b}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4XNVTWGC.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};
@@ -1,5 +1,5 @@
/*! maintenance_supporter frontend 2.96.0 */
import{e as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4PTWLV7V.js";import{d as m}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WJT4RRLS.js";import{a as h}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-BFBOHWBW.js";import{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,y as b}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-N6F5RX6S.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`
/*! maintenance_supporter frontend 2.97.1 */
import{e as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-D4KM62SJ.js";import{d as m}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GSRF4WCQ.js";import{a as h}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GVLO7RZ4.js";import{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,y as b}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YJXVPPWG.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">
@@ -1,271 +0,0 @@
/*! maintenance_supporter frontend 2.90.0 */
import{e as f}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-73EHFI76.js";import{a as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WQXORDNI.js";import{a,b as g,c as i,f as c,h as u,l as v,m as n,q as s,s as m,u as b}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";var r=class extends u{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._users=[];this._responsible="";this._forMinutes="0";this._localeReady=!1;this._userService=null;this._toggle=e=>{let o=new Set(this._selected);o.has(e)?o.delete(e):o.add(e),this._selected=o};this._toggleAll=()=>{this._selected.size===this._sensors.length?this._selected=new Set:this._selected=new Set(this._sensors.map(e=>e.entity_id))};this._adopt=async()=>{if(!(this._selected.size===0||this._adopting)){this._adopting=!0,this._error="";try{let e=this._sensors.filter(t=>this._selected.has(t.entity_id)).map(t=>({entity_id:t.entity_id,name:t.name,entry_id:this._existingEntryFor(t)??void 0,object_name:this._effectiveName(t),device_id:t.device_id??void 0,part_id:t.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})),o=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/problem_sensors/adopt",selections:e});this.dispatchEvent(new CustomEvent("problem-sensors-adopted",{bubbles:!0,composed:!0,detail:o})),this._open=!1}catch(e){this._error=p(e,this._lang)}finally{this._adopting=!1}}}}get _lang(){return m(this.hass)}updated(e){e.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,b(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";try{this._userService?this._userService.updateHass(this.hass):this._userService=new f(this.hass);let[e,o,t]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/problem_sensors/discover"}),this._userService.getUsers().catch(()=>[]),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}).catch(()=>({objects:[]}))]);this._objects=(t.objects||[]).filter(l=>!l.object.archived_at).map(l=>({entry_id:l.entry_id,name:l.object.name})),this._sensors=e.sensors||[],this._selected=new Set(this._sensors.map(l=>l.entity_id)),this._users=o}catch(e){this._error=p(e,this._lang)}finally{this._loading=!1}}_effectiveName(e){return(this._objectNames[e.entity_id]??"").trim()||e.suggested_object_name}_existingEntryFor(e){let o=this._effectiveName(e);if(o===e.suggested_object_name&&e.suggested_entry_id)return e.suggested_entry_id;let t=this._objects.find(l=>l.name.trim().toLowerCase()===o.toLowerCase());return t?t.entry_id:null}_close(){this._open=!1}render(){if(!this._open)return i``;let e=this._lang,o=this._sensors.length>0&&this._selected.size===this._sensors.length;return i`
<div class="overlay" @click=${this._close}>
<div class="card" @click=${t=>t.stopPropagation()}>
<div class="title">${s("adopt_problem_title",e)}</div>
<div class="hint">${s("adopt_problem_hint",e)}</div>
${this._error?i`<div class="error">${this._error}</div>`:c}
${this._loading?i`<div class="loading">…</div>`:this._sensors.length===0?i`<div class="empty">${s("adopt_problem_none",e)}</div>`:i`
<label class="select-all">
<input
type="checkbox"
.checked=${o}
@change=${this._toggleAll}
/>
<span>${s("selected",e)}: ${this._selected.size} / ${this._sensors.length}</span>
</label>
<div class="row-sub adopt-object-hint">${s("adopt_object_hint",e)}</div>
<datalist id="adopt-object-names">
${this._objects.map(t=>i`<option value=${t.name}></option>`)}
</datalist>
<div class="list">
${this._sensors.map(t=>{let l=this._selected.has(t.entity_id),_=t.state==="on",h=[t.device_name,t.area_name].filter(Boolean).join(" \xB7 ");return i`
<label class="row">
<input
type="checkbox"
.checked=${l}
@change=${()=>this._toggle(t.entity_id)}
/>
<div class="row-main">
<div class="row-top">
<span class="row-name">${t.name}</span>
<span class="chip ${_?"chip-active":"chip-ok"}">
${_?s("adopt_problem_active",e):s("adopt_problem_ok",e)}
</span>
</div>
${h?i`<div class="row-sub">${h}</div>`:c}
${l?i`<div class="row-object" @click=${d=>d.stopPropagation()}>
<input
class="adopt-object"
list="adopt-object-names"
aria-label=${s("object",e)}
placeholder=${t.suggested_object_name}
.value=${this._objectNames[t.entity_id]??t.suggested_object_name}
@input=${d=>{this._objectNames={...this._objectNames,[t.entity_id]:d.target.value}}}
/>
</div>`:c}
<div class="row-target">
→ ${this._effectiveName(t)}${this._existingEntryFor(t)?c:i` <span class="new-tag">${s("adopt_problem_new_object",e)}</span>`}
</div>
${t.suggested_part_name?i`<div class="row-part">
<ha-icon icon="mdi:package-variant-closed"></ha-icon>
${s("adopt_problem_part",e).replace("{name}",t.suggested_part_name)}
</div>`:c}
</div>
</label>
`})}
</div>
`}
${!this._loading&&this._sensors.length>0?i`
<label class="responsible">
<span>${s("for_at_least_minutes",e)}</span>
<input
class="for-input"
type="number"
min="0"
max="1440"
.value=${this._forMinutes}
@input=${t=>this._forMinutes=t.target.value}
/>
</label>
<div class="for-hint">${s("adopt_for_minutes_hint",e)}</div>
`:c}
${!this._loading&&this._sensors.length>0&&this._users.length>0?i`
<label class="responsible">
<span>${s("adopt_problem_responsible",e)}</span>
<select
.value=${this._responsible}
@change=${t=>{this._responsible=t.target.value}}
>
<option value="" ?selected=${!this._responsible}>${s("no_user_assigned",e)}</option>
${this._users.map(t=>i`<option value=${t.id} ?selected=${t.id===this._responsible}>${t.name}</option>`)}
</select>
</label>
`:c}
<div class="actions">
<ha-button appearance="plain" @click=${this._close}>
${s("cancel",e)}
</ha-button>
<ha-button
@click=${this._adopt}
.disabled=${this._selected.size===0||this._adopting}
>
${s("adopt_problem_adopt",e)}
</ha-button>
</div>
</div>
</div>
`}};r.styles=g`
.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;
}
.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;
}
`,a([v({attribute:!1})],r.prototype,"hass",2),a([n()],r.prototype,"_open",2),a([n()],r.prototype,"_loading",2),a([n()],r.prototype,"_adopting",2),a([n()],r.prototype,"_error",2),a([n()],r.prototype,"_sensors",2),a([n()],r.prototype,"_selected",2),a([n()],r.prototype,"_objectNames",2),a([n()],r.prototype,"_objects",2),a([n()],r.prototype,"_users",2),a([n()],r.prototype,"_responsible",2),a([n()],r.prototype,"_forMinutes",2);customElements.get("maintenance-adopt-problem-sensors-dialog")||customElements.define("maintenance-adopt-problem-sensors-dialog",r);export{r as MaintenanceAdoptProblemSensorsDialog};
@@ -1,277 +0,0 @@
/*! maintenance_supporter frontend 2.95.0 */
import{a as W}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-APJICCRG.js";import{a as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-XSFV5MUM.js";import{f as T,g as K,h as z,i as M,j as Y,k as Q,l as U,m as q,n as R,o as E,p as G}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YKVD2DJ5.js";import{a as A}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-E7KPGZZO.js";import{e as F,f as I}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-S7ZP4PVX.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-ODPGZXCU.js";import{b as P}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-JEWIFUZC.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-UVBHIULM.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-WUMSAU4G.js";import{B as $,C as g,F as O,G as S,J as w,L as N,a as b,c as p,f as y,h as B,l as v,m as k,n as C,q as D,s as a,u as H,y as L}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4XNVTWGC.js";function X(_,r,t,s){let d=_.entries.filter(e=>e.type==="completed").sort((e,i)=>e.ts-i.ts),l=`${_.from?t.date(_.from):"\u2026"} \u2013 ${_.to?t.date(_.to):"\u2026"}`,n=_.totals,h=[[r.completions,t.number(n.completions)],[r.totalCost,t.cost(n.totalCost)],[r.avgCost,n.avgCost!=null?t.cost(n.avgCost):r.none],[r.totalTime,n.totalDuration?t.duration(n.totalDuration):r.none]].map(([e,i])=>`<div class="kpi"><div class="k">${o(e)}</div><div class="v">${o(i)}</div></div>`).join(""),c=_.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(""),m=_.buckets.buckets.reduce((e,i)=>Math.max(e,i.cost),0),f=_.buckets.buckets.map(e=>{let i=m>0?Math.round(e.cost/m*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">${i>0?`<span class="bar" style="width:${i}%"></span>`:""}</td>
<td class="num">${o(t.cost(e.cost))}</td>
</tr>`}).join(""),j=d.map(e=>{let i=[e.notes,e.completedBy?`${r.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(r.none)}</td>
<td class="num">${e.duration!=null?o(t.duration(e.duration)):o(r.none)}</td>
<td class="notes">${o(i)||o(r.none)}</td>
</tr>`}).join(`
`);return`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light">
<title>${o(r.title)} \u2014 ${o(_.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; }
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(r.title)} \u2014 ${o(_.areaName)}</h1>
<p class="sub">${o(r.period)}: ${o(l)} \xB7 ${o(r.generated)} ${o(t.date(s))}</p>
<div class="kpis">${h}</div>
<h2>${o(r.costPerObject)}</h2>
<table>
<thead><tr>
<th>${o(r.colObject)}</th><th class="num">${o(r.completions)}</th>
<th class="num">${o(r.colCost)}</th><th class="num">${o(r.share)}</th>
</tr></thead>
<tbody>${c||`<tr><td colspan="4">${o(r.none)}</td></tr>`}</tbody>
<tfoot><tr>
<td>${o(r.totalCost)}</td><td class="num">${o(t.number(n.completions))}</td>
<td class="num">${o(t.cost(n.totalCost))}</td><td></td>
</tr></tfoot>
</table>
<h2>${o(r.costPerBucket)}</h2>
<table>
<thead><tr>
<th>${o(r.period)}</th><th class="num">${o(r.completions)}</th>
<th></th><th class="num">${o(r.colCost)}</th>
</tr></thead>
<tbody>${f||`<tr><td colspan="4">${o(r.none)}</td></tr>`}</tbody>
</table>
<h2>${o(r.historyHeading)} (${o(t.number(d.length))})</h2>
<table>
<thead><tr>
<th>${o(r.colDate)}</th><th>${o(r.colObject)}</th><th>${o(r.colTask)}</th>
<th class="num">${o(r.colCost)}</th><th class="num">${o(r.colDuration)}</th><th>${o(r.colNotes)}</th>
</tr></thead>
<tbody>
${j||`<tr><td colspan="6">${o(r.none)}</td></tr>`}
</tbody>
<tfoot><tr>
<td colspan="3">${o(r.totalCost)}</td>
<td class="num">${o(t.cost(n.totalCost))}</td>
<td class="num">${n.totalDuration?o(t.duration(n.totalDuration)):""}</td><td></td>
</tr></tfoot>
</table>
${_.capped?`<p class="cap-note">${o(r.capNote)}</p>`:""}
</body>
</html>`}var J=25,Z=5,V={completed:C.ok,missed:C.overdue,reset:C.paused,skipped:"var(--secondary-text-color)"},u=class extends B{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 W(this);this._localeReady=!1;this._filtersFor=null;this._memo=null}createRenderRoot(){return this}get _lang(){return L(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(d=>d.tasks.map(l=>({entryId:d.entry_id,task:l})));this._histories.sync(this.hass,s)}}updated(t){super.updated(t),!this._localeReady&&this.hass&&(this._localeReady=!0,H(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((l,n)=>l===s[n]))return this._memo.entries;let d=M(t,(l,n)=>this._histories.historyOf(l,n));return this._memo={deps:s,entries:d},d}_figures(){let t=this._areaObjects(),s=this._entries(t),d={from:this._from||null,to:this._to||null},l=Y(s,{...d,entryId:this._entryFilter||null,taskQuery:this._taskQuery}),n=this._entryFilter?t.filter(h=>h.entry_id===this._entryFilter):t;return{objects:t,entries:s,filtered:l,totals:Q(l),buckets:q(l,d),byObject:U(l,n)}}_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):`${N(t.month,this._lang,s)} ${t.year}`}_countText(t,s,d){let l=this._lang;return d===1?a(s,l):a(t,l).replace("{n}",$(d,l))}async _print(){if(this._printing)return;let t=I();this._printing=!0;try{await this._histories.settled()}finally{this._printing=!1}let s=this._lang,d=this.currencySymbol,{filtered:l,totals:n,buckets:h,byObject:c}=this._figures(),m={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"},f=l.filter(i=>i.type==="completed"),j=l.map(i=>({...i,completedBy:i.completedBy?this.userName(i.completedBy):null,notes:i.notes?A(i.notes,s):null})),e=X({areaName:T(this.areaKey,this.hass?.areas,a("no_area",s)),from:this._from||f[f.length-1]?.timestamp||null,to:this._to||P(new Date),totals:n,byObject:c,buckets:h,entries:j,capped:this._histories.capped},m,{date:i=>O(i,s),cost:i=>g(i,d,s),duration:i=>w(i,s),bucket:i=>this._bucketLabel(i,"long"),share:i=>`${$(i*100,s,0)} %`,number:i=>$(i,s)},new Date().toISOString());F(e,t)}_renderRangeChips(t){let s=this._lang,d=new Date,l=R(d),n=c=>this._from===c.from&&this._to===c.to,h=G(t,d.getFullYear()).slice(0,Z);return p`
<div class="filter-chips area-range-chips">
<button class="filter-chip ${n(l)?"active":""}" @click=${()=>this._setRange(R())}>
${a("area_range_12m",s)}
</button>
${h.map(c=>p`
<button class="filter-chip ${n(E(c))?"active":""}" @click=${()=>this._setRange(E(c))}>${c}</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,d=this.currencySymbol,l=t.reduce((c,m)=>Math.max(c,m.cost),0);if(l<=0)return p`<p class="area-empty">${a("area_no_costs",s)}</p>`;let n=Math.max(1,Math.ceil(t.length/12)),h=t.map((c,m)=>({b:c,i:m})).filter(({i:c})=>c%n===0);return p`
<div class="area-chart">
<div class="area-chart-max">${g(l,d,s)}</div>
<div class="area-chart-bars">
${t.map(c=>{let m=`${this._bucketLabel(c,"long")}: ${g(c.cost,d,s)} \xB7 ${a("area_kpi_completions",s)}: ${$(c.completions,s)}`;return p`<div class="area-bar" title=${m} aria-label=${m}>
${c.cost>0?p`<div class="area-bar-fill" style="height: ${Math.round(c.cost/l*1e3)/10}%"></div>`:y}
</div>`})}
</div>
<div class="area-chart-axis ${n>1?"grouped":""}">
${h.map(({b:c,i:m})=>p`<span class="area-bar-label" style="flex-grow: ${Math.min(n,t.length-m)}">${c.month==null?String(c.year):p`${N(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:d,entries:l,filtered:n,totals:h,buckets:c,byObject:m}=this._figures(),f=d.reduce((e,i)=>e+i.tasks.filter(x=>this.showArchived||!x.archived).length,0),j=this._expanded?n:n.slice(0,J);return p`
<div class="detail-section area-view">
<div class="detail-header">
<h2 class="area-title">
<ha-icon .icon=${K(this.areaKey,this.hass.areas)}></ha-icon>
${T(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",d.length)} ·
${this._countText("templates_task_count","templates_task_count_one",f)}
${this._histories.loading?p` · <span class="area-loading">${a("loading",t)}</span>`:y}
</p>
${this._renderRangeChips(l)}
<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>
${d.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">${$(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">${g(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?g(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>${c.unit==="month"?a("area_cost_per_month",t):a("area_cost_per_year",t)}</h3>
${this._renderChart(c.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>
${m.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">${$(e.completions,t)}</td>
<td class="num">${g(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>
${$(e.share*100,t,0)} %
</td>
</tr>
`)}
</tbody>
</table>
</div>
<h3>
${a("area_history_section",t)}
<span class="area-count">${$(n.length,t)}</span>
</h3>
${n.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>
${j.map(e=>{let i=e.notes?A(e.notes,t):"";return p`
<tr class="objects-table-row area-history-row" @click=${()=>this._openTask(e.entryId,e.taskId)}>
<td title=${S(e.timestamp,t)}>${O(e.timestamp,t)}</td>
<td>
<span class="area-entry-type" style="color: ${V[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?g(e.cost,s,t):"\u2014"}</td>
<td class="num">${e.duration!=null?w(e.duration,t):"\u2014"}</td>
<td class="oc-notes" title=${i}>${i||"\u2014"}</td>
</tr>
`})}
</tbody>
</table>
</div>
${n.length>j.length?p`<ha-button appearance="plain" class="area-more" @click=${()=>{this._expanded=!0}}>
${a("show_all",t)} (${$(n.length,t)})
</ha-button>`:y}
`}
${this._histories.capped?p`<p class="area-cap-note">${a("object_history_cap_note",t)}</p>`:y}
</div>
`}};b([v({attribute:!1})],u.prototype,"hass",2),b([v()],u.prototype,"areaKey",2),b([v({attribute:!1})],u.prototype,"objects",2),b([v({type:Boolean})],u.prototype,"showArchived",2),b([v()],u.prototype,"currencySymbol",2),b([v({attribute:!1})],u.prototype,"userName",2),b([k()],u.prototype,"_from",2),b([k()],u.prototype,"_to",2),b([k()],u.prototype,"_entryFilter",2),b([k()],u.prototype,"_taskQuery",2),b([k()],u.prototype,"_expanded",2),b([k()],u.prototype,"_printing",2);customElements.get("maintenance-area-view")||customElements.define("maintenance-area-view",u);export{u as MaintenanceAreaView};
@@ -1,28 +1,28 @@
/*! maintenance_supporter frontend 2.96.0 */
import{a as W}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-I7NCFUZX.js";import{a as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-VZYRPSO6.js";import{f as T,g as K,h as z,i as M,j as Y,k as Q,l as U,m as q,n as R,o as E,p as G}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-PWKMLGJR.js";import{a as A}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RJY4VEHX.js";import{e as F,f as I}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-3VJOJBZ5.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-4OFQFCKD.js";import{f as P}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-BYGTDXRD.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-QLW72JHE.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-2U4DNN5T.js";import{B as $,C as g,F as O,G as S,J as w,L as N,a as b,c as p,f as y,h as B,l as v,m as k,n as C,q as D,s as a,u as H,y as L}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-N6F5RX6S.js";function X(_,r,t,s){let d=_.entries.filter(e=>e.type==="completed").sort((e,i)=>e.ts-i.ts),l=`${_.from?t.date(_.from):"\u2026"} \u2013 ${_.to?t.date(_.to):"\u2026"}`,n=_.totals,h=[[r.completions,t.number(n.completions)],[r.totalCost,t.cost(n.totalCost)],[r.avgCost,n.avgCost!=null?t.cost(n.avgCost):r.none],[r.totalTime,n.totalDuration?t.duration(n.totalDuration):r.none]].map(([e,i])=>`<div class="kpi"><div class="k">${o(e)}</div><div class="v">${o(i)}</div></div>`).join(""),c=_.byObject.map(e=>`<tr>
/*! maintenance_supporter frontend 2.97.1 */
import{a as W}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-AKHM2FQS.js";import{a as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-R3GKJJ55.js";import{f as T,g as K,h as M,i as z,j as Y,k as Q,l as U,m as q,n as R,o as E,p as G}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-BEGYKXHI.js";import{a as A}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-5ROMA2NQ.js";import{e as F,f as I}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-Z5US4BJZ.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-O7BSORZB.js";import{f as P}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-5SGCD2J3.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-HVQDZ5QR.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-KV46GCLQ.js";import{B as g,C as y,F as O,G as S,J as C,L as N,a as b,c as p,f as v,h as B,l as k,m as j,n as w,q as D,s as a,u as H,y as L}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YJXVPPWG.js";function X($,i,t,s){let l=$.entries.filter(e=>e.type==="completed").sort((e,n)=>e.ts-n.ts),d=`${$.from?t.date($.from):"\u2026"} \u2013 ${$.to?t.date($.to):"\u2026"}`,r=$.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=$.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(""),m=_.buckets.buckets.reduce((e,i)=>Math.max(e,i.cost),0),f=_.buckets.buckets.map(e=>{let i=m>0?Math.round(e.cost/m*100):0;return`<tr>
</tr>`).join(""),f=$.buckets.buckets.reduce((e,n)=>Math.max(e,n.cost),0),c=$.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">${i>0?`<span class="bar" style="width:${i}%"></span>`:""}</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(""),j=d.map(e=>{let i=[e.notes,e.completedBy?`${r.completedBy}: ${e.completedBy}`:null].filter(Boolean).join(" \xB7 "),x=e.phaseName?`${e.taskName} \xB7 ${e.phaseName}`:e.taskName;return`<tr>
</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(r.none)}</td>
<td class="num">${e.duration!=null?o(t.duration(e.duration)):o(r.none)}</td>
<td class="notes">${o(i)||o(r.none)}</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(r.title)} \u2014 ${o(_.areaName)}</title>
<title>${o(i.title)} \u2014 ${o($.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
@@ -42,7 +42,7 @@ import{a as W}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-I7NCFUZX
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; }
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; }
@@ -53,74 +53,76 @@ import{a as W}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-I7NCFUZX
</style>
</head>
<body>
<h1>${o(r.title)} \u2014 ${o(_.areaName)}</h1>
<p class="sub">${o(r.period)}: ${o(l)} \xB7 ${o(r.generated)} ${o(t.date(s))}</p>
<h1>${o(i.title)} \u2014 ${o($.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(r.costPerObject)}</h2>
<h2>${o(i.costPerObject)}</h2>
<table>
<thead><tr>
<th>${o(r.colObject)}</th><th class="num">${o(r.completions)}</th>
<th class="num">${o(r.colCost)}</th><th class="num">${o(r.share)}</th>
<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>${c||`<tr><td colspan="4">${o(r.none)}</td></tr>`}</tbody>
<tbody>${u||`<tr><td colspan="4">${o(i.none)}</td></tr>`}</tbody>
<tfoot><tr>
<td>${o(r.totalCost)}</td><td class="num">${o(t.number(n.completions))}</td>
<td class="num">${o(t.cost(n.totalCost))}</td><td></td>
<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(r.costPerBucket)}</h2>
<h2>${o(i.costPerBucket)}</h2>
<table>
<thead><tr>
<th>${o(r.period)}</th><th class="num">${o(r.completions)}</th>
<th></th><th class="num">${o(r.colCost)}</th>
<th>${o(i.period)}</th><th class="num">${o(i.completions)}</th>
<th></th><th class="num">${o(i.colCost)}</th>
</tr></thead>
<tbody>${f||`<tr><td colspan="4">${o(r.none)}</td></tr>`}</tbody>
<tbody>${c||`<tr><td colspan="4">${o(i.none)}</td></tr>`}</tbody>
</table>
<h2>${o(r.historyHeading)} (${o(t.number(d.length))})</h2>
<h2>${o(i.historyHeading)} (${o(t.number(l.length))})</h2>
<table>
<thead><tr>
<th>${o(r.colDate)}</th><th>${o(r.colObject)}</th><th>${o(r.colTask)}</th>
<th class="num">${o(r.colCost)}</th><th class="num">${o(r.colDuration)}</th><th>${o(r.colNotes)}</th>
<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>
${j||`<tr><td colspan="6">${o(r.none)}</td></tr>`}
${m||`<tr><td colspan="6">${o(i.none)}</td></tr>`}
</tbody>
<tfoot><tr>
<td colspan="3">${o(r.totalCost)}</td>
<td class="num">${o(t.cost(n.totalCost))}</td>
<td class="num">${n.totalDuration?o(t.duration(n.totalDuration)):""}</td><td></td>
<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>
${_.capped?`<p class="cap-note">${o(r.capNote)}</p>`:""}
${$.capped?`<p class="cap-note">${o(i.capNote)}</p>`:""}
</body>
</html>`}var J=25,Z=5,V={completed:C.ok,missed:C.overdue,reset:C.paused,skipped:"var(--secondary-text-color)"},u=class extends B{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 W(this);this._localeReady=!1;this._filtersFor=null;this._memo=null}createRenderRoot(){return this}get _lang(){return L(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(d=>d.tasks.map(l=>({entryId:d.entry_id,task:l})));this._histories.sync(this.hass,s)}}updated(t){super.updated(t),!this._localeReady&&this.hass&&(this._localeReady=!0,H(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((l,n)=>l===s[n]))return this._memo.entries;let d=M(t,(l,n)=>this._histories.historyOf(l,n));return this._memo={deps:s,entries:d},d}_figures(){let t=this._areaObjects(),s=this._entries(t),d={from:this._from||null,to:this._to||null},l=Y(s,{...d,entryId:this._entryFilter||null,taskQuery:this._taskQuery}),n=this._entryFilter?t.filter(h=>h.entry_id===this._entryFilter):t;return{objects:t,entries:s,filtered:l,totals:Q(l),buckets:q(l,d),byObject:U(l,n)}}_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):`${N(t.month,this._lang,s)} ${t.year}`}_countText(t,s,d){let l=this._lang;return d===1?a(s,l):a(t,l).replace("{n}",$(d,l))}async _print(){if(this._printing)return;let t=I();this._printing=!0;try{await this._histories.settled()}finally{this._printing=!1}let s=this._lang,d=this.currencySymbol,{filtered:l,totals:n,buckets:h,byObject:c}=this._figures(),m={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"},f=l.filter(i=>i.type==="completed"),j=l.map(i=>({...i,completedBy:i.completedBy?this.userName(i.completedBy):null,notes:i.notes?A(i.notes,s):null})),e=X({areaName:T(this.areaKey,this.hass?.areas,a("no_area",s)),from:this._from||f[f.length-1]?.timestamp||null,to:this._to||P(new Date),totals:n,byObject:c,buckets:h,entries:j,capped:this._histories.capped},m,{date:i=>O(i,s),cost:i=>g(i,d,s),duration:i=>w(i,s),bucket:i=>this._bucketLabel(i,"long"),share:i=>`${$(i*100,s,0)} %`,number:i=>$(i,s)},new Date().toISOString());F(e,t)}_renderRangeChips(t){let s=this._lang,d=new Date,l=R(d),n=c=>this._from===c.from&&this._to===c.to,h=G(t,d.getFullYear()).slice(0,Z);return p`
</html>`}var J=25,Z=5,V={completed:w.ok,missed:w.overdue,reset:w.paused,skipped:"var(--secondary-text-color)"},_=class extends B{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 W(this);this._localeReady=!1;this._filtersFor=null;this._memo=null}createRenderRoot(){return this}get _lang(){return L(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,H(this._lang).then(()=>this.requestUpdate()))}_areaObjects(){return M(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=z(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=Y(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:Q(d),buckets:q(d,l),byObject:U(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):`${N(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=I();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?A(n.notes,s):null})),e=X({areaName:T(this.areaKey,this.hass?.areas,a("no_area",s)),from:this._from||c[c.length-1]?.timestamp||null,to:this._to||P(new Date),totals:r,byObject:u,buckets:h,entries:m,capped:this._histories.capped},f,{date:n=>O(n,s),cost:n=>y(n,l,s),duration:n=>C(n,s),bucket:n=>this._bucketLabel(n,"long"),share:n=>`${g(n*100,s,0)} %`,number:n=>g(n,s)},new Date().toISOString());F(e,t)}_renderRangeChips(t){let s=this._lang,l=new Date,d=R(l),r=u=>this._from===u.from&&this._to===u.to,h=G(t,l.getFullYear()).slice(0,Z);return p`
<div class="filter-chips area-range-chips">
<button class="filter-chip ${n(l)?"active":""}" @click=${()=>this._setRange(R())}>
<button class="filter-chip ${r(d)?"active":""}" @click=${()=>this._setRange(R())}>
${a("area_range_12m",s)}
</button>
${h.map(c=>p`
<button class="filter-chip ${n(E(c))?"active":""}" @click=${()=>this._setRange(E(c))}>${c}</button>
${h.map(u=>p`
<button class="filter-chip ${r(E(u))?"active":""}" @click=${()=>this._setRange(E(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,d=this.currencySymbol,l=t.reduce((c,m)=>Math.max(c,m.cost),0);if(l<=0)return p`<p class="area-empty">${a("area_no_costs",s)}</p>`;let n=Math.max(1,Math.ceil(t.length/12)),h=t.map((c,m)=>({b:c,i:m})).filter(({i:c})=>c%n===0);return p`
`}_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">${g(l,d,s)}</div>
<div class="area-chart-max">${y(d,l,s)}</div>
<div class="area-chart-bars">
${t.map(c=>{let m=`${this._bucketLabel(c,"long")}: ${g(c.cost,d,s)} \xB7 ${a("area_kpi_completions",s)}: ${$(c.completions,s)}`;return p`<div class="area-bar" title=${m} aria-label=${m}>
${c.cost>0?p`<div class="area-bar-fill" style="height: ${Math.round(c.cost/l*1e3)/10}%"></div>`:y}
${r<0?p`<div class="area-chart-zero" style="bottom: ${h(-r)}%"></div>`:v}
${t.map(c=>{let m=`${this._bucketLabel(c,"long")}: ${y(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>`:v}
</div>`})}
</div>
<div class="area-chart-axis ${n>1?"grouped":""}">
${h.map(({b:c,i:m})=>p`<span class="area-bar-label" style="flex-grow: ${Math.min(n,t.length-m)}">${c.month==null?String(c.year):p`${N(c.month,s,"short")}${c.month===0||m===0?p`<br />${c.year}`:y}`}</span>`)}
${r<0?p`<div class="area-chart-min">${y(r,l,s)}</div>`:v}
<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`${N(c.month,s,"short")}${c.month===0||m===0?p`<br />${c.year}`:v}`}</span>`)}
</div>
</div>
`}render(){if(!this.hass||!this.areaKey)return y;let t=this._lang,s=this.currencySymbol,{objects:d,entries:l,filtered:n,totals:h,buckets:c,byObject:m}=this._figures(),f=d.reduce((e,i)=>e+i.tasks.filter(x=>this.showArchived||!x.archived).length,0),j=this._expanded?n:n.slice(0,J);return p`
`}render(){if(!this.hass||!this.areaKey)return v;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,J);return p`
<div class="detail-section area-view">
<div class="detail-header">
<h2 class="area-title">
@@ -135,12 +137,12 @@ ${_.capped?`<p class="cap-note">${o(r.capNote)}</p>`:""}
</div>
</div>
<p class="meta">
${this._countText("area_object_count","area_object_count_one",d.length)} ·
${this._countText("templates_task_count","templates_task_count_one",f)}
${this._histories.loading?p` · <span class="area-loading">${a("loading",t)}</span>`:y}
${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>`:v}
</p>
${this._renderRangeChips(l)}
${this._renderRangeChips(d)}
<div class="filter-bar area-filters">
<ms-date-field
kind="date"
@@ -165,7 +167,7 @@ ${_.capped?`<p class="cap-note">${o(r.capNote)}</p>`:""}
<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>
${d.map(e=>p`<option value=${e.entry_id} ?selected=${e.entry_id===this._entryFilter}>${e.object.name}</option>`)}
${l.map(e=>p`<option value=${e.entry_id} ?selected=${e.entry_id===this._entryFilter}>${e.object.name}</option>`)}
</select>
</label>
<input
@@ -181,24 +183,24 @@ ${_.capped?`<p class="cap-note">${o(r.capNote)}</p>`:""}
<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">${$(h.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">${g(h.totalCost,s,t)}</div>
<div class="kpi-value-large area-kpi-cost">${y(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?g(h.avgCost,s,t):"\u2014"}</div>
<div class="kpi-value-large">${h.avgCost!=null?y(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 class="kpi-value-large">${h.totalDuration?C(h.totalDuration,t):"\u2014"}</div>
</div>
</div>
<h3>${c.unit==="month"?a("area_cost_per_month",t):a("area_cost_per_year",t)}</h3>
${this._renderChart(c.buckets)}
<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">
@@ -212,14 +214,14 @@ ${_.capped?`<p class="cap-note">${o(r.capNote)}</p>`:""}
</tr>
</thead>
<tbody>
${m.map(e=>p`
${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">${$(e.completions,t)}</td>
<td class="num">${g(e.cost,s,t)}</td>
<td class="num">${g(e.completions,t)}</td>
<td class="num">${y(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>
${$(e.share*100,t,0)} %
${g(e.share*100,t,0)} %
</td>
</tr>
`)}
@@ -229,9 +231,9 @@ ${_.capped?`<p class="cap-note">${o(r.capNote)}</p>`:""}
<h3>
${a("area_history_section",t)}
<span class="area-count">${$(n.length,t)}</span>
<span class="area-count">${g(r.length,t)}</span>
</h3>
${n.length===0?p`<p class="area-empty">${a("object_history_empty",t)}</p>`:p`
${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>
@@ -246,7 +248,7 @@ ${_.capped?`<p class="cap-note">${o(r.capNote)}</p>`:""}
</tr>
</thead>
<tbody>
${j.map(e=>{let i=e.notes?A(e.notes,t):"";return p`
${m.map(e=>{let n=e.notes?A(e.notes,t):"";return p`
<tr class="objects-table-row area-history-row" @click=${()=>this._openTask(e.entryId,e.taskId)}>
<td title=${S(e.timestamp,t)}>${O(e.timestamp,t)}</td>
<td>
@@ -260,18 +262,18 @@ ${_.capped?`<p class="cap-note">${o(r.capNote)}</p>`:""}
</button>
</td>
<td><button class="area-task-link">${e.taskName}${e.phaseName?` \xB7 ${e.phaseName}`:""}</button></td>
<td class="num">${e.cost!=null?g(e.cost,s,t):"\u2014"}</td>
<td class="num">${e.duration!=null?w(e.duration,t):"\u2014"}</td>
<td class="oc-notes" title=${i}>${i||"\u2014"}</td>
<td class="num">${e.cost!=null?y(e.cost,s,t):"\u2014"}</td>
<td class="num">${e.duration!=null?C(e.duration,t):"\u2014"}</td>
<td class="oc-notes" title=${n}>${n||"\u2014"}</td>
</tr>
`})}
</tbody>
</table>
</div>
${n.length>j.length?p`<ha-button appearance="plain" class="area-more" @click=${()=>{this._expanded=!0}}>
${a("show_all",t)} (${$(n.length,t)})
</ha-button>`:y}
${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>`:v}
`}
${this._histories.capped?p`<p class="area-cap-note">${a("object_history_cap_note",t)}</p>`:y}
${this._histories.capped?p`<p class="area-cap-note">${a("object_history_cap_note",t)}</p>`:v}
</div>
`}};b([v({attribute:!1})],u.prototype,"hass",2),b([v()],u.prototype,"areaKey",2),b([v({attribute:!1})],u.prototype,"objects",2),b([v({type:Boolean})],u.prototype,"showArchived",2),b([v()],u.prototype,"currencySymbol",2),b([v({attribute:!1})],u.prototype,"userName",2),b([k()],u.prototype,"_from",2),b([k()],u.prototype,"_to",2),b([k()],u.prototype,"_entryFilter",2),b([k()],u.prototype,"_taskQuery",2),b([k()],u.prototype,"_expanded",2),b([k()],u.prototype,"_printing",2);customElements.get("maintenance-area-view")||customElements.define("maintenance-area-view",u);export{u as MaintenanceAreaView};
`}};b([k({attribute:!1})],_.prototype,"hass",2),b([k()],_.prototype,"areaKey",2),b([k({attribute:!1})],_.prototype,"objects",2),b([k({type:Boolean})],_.prototype,"showArchived",2),b([k()],_.prototype,"currencySymbol",2),b([k({attribute:!1})],_.prototype,"userName",2),b([j()],_.prototype,"_from",2),b([j()],_.prototype,"_to",2),b([j()],_.prototype,"_entryFilter",2),b([j()],_.prototype,"_taskQuery",2),b([j()],_.prototype,"_expanded",2),b([j()],_.prototype,"_printing",2);customElements.get("maintenance-area-view")||customElements.define("maintenance-area-view",_);export{_ as MaintenanceAreaView};
@@ -1,5 +1,5 @@
/*! maintenance_supporter frontend 2.95.0 */
import{a as C}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-APJICCRG.js";import{q as A,r as j,s as E,t as L,u as R}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YKVD2DJ5.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-ODPGZXCU.js";import{a as _,b as w,c as S}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YQT7IJJB.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-JEWIFUZC.js";import{B as g,C as v,F as k,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-4XNVTWGC.js";var O=[{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=j(w(_.areaSort));this._histories=new C(this);this._localeReady=!1;this._memo=null}createRenderRoot(){return this}get _lang(){return f(this.hass)}willUpdate(e){if(super.willUpdate(e),e.has("objects")||e.has("showArchived")||e.has("hass")&&e.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(e){super.updated(e),!this._localeReady&&this.hass&&(this._localeReady=!0,$(this._lang).then(()=>this.requestUpdate()))}_rows(e){let o=this._lang,s=[this.objects,this.showArchived,this._histories.version,this.hass?.areas,o,e];if(this._memo&&this._memo.deps.every((c,h)=>c===s[h]))return this._memo.rows;let n=A(this.objects,{showArchived:this.showArchived,areas:this.hass?.areas,noAreaLabel:r("no_area",o),year:e,historyOf:(c,h)=>this._histories.historyOf(c,h)});return this._memo={deps:s,rows:n},n}_setSort(e){this._sort=E(this._sort,e),S(_.areaSort,`${this._sort.key}:${this._sort.dir}`)}_open(e){this.dispatchEvent(new CustomEvent("open-area",{detail:{areaKey:e},bubbles:!0,composed:!0}))}_toggleArchived(){this.dispatchEvent(new CustomEvent("archived-toggle",{bubbles:!0,composed:!0}))}_headerLabel(e,o,s){return e==="area_cost_year"?r("area_cost_year",s).replace("{year}",String(o)):r(e,s)}render(){if(!this.hass)return m;let e=this._lang,o=new Date().getFullYear(),s=this.currencySymbol,n=this._rows(o),c=L(R(n,this._query),this._sort),h=this.objects.filter(t=>t.object.archived).length,d=t=>g(t,e);return a`
/*! maintenance_supporter frontend 2.97.1 */
import{a as C}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-AKHM2FQS.js";import{q as A,r as j,s as E,t as L,u as R}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-BEGYKXHI.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-O7BSORZB.js";import{a as _,b as w,c as S}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-EPK25IMX.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-5SGCD2J3.js";import{B as g,C as v,F as k,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-YJXVPPWG.js";var O=[{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=j(w(_.areaSort));this._histories=new C(this);this._localeReady=!1;this._memo=null}createRenderRoot(){return this}get _lang(){return f(this.hass)}willUpdate(e){if(super.willUpdate(e),e.has("objects")||e.has("showArchived")||e.has("hass")&&e.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(e){super.updated(e),!this._localeReady&&this.hass&&(this._localeReady=!0,$(this._lang).then(()=>this.requestUpdate()))}_rows(e){let o=this._lang,s=[this.objects,this.showArchived,this._histories.version,this.hass?.areas,o,e];if(this._memo&&this._memo.deps.every((c,h)=>c===s[h]))return this._memo.rows;let n=A(this.objects,{showArchived:this.showArchived,areas:this.hass?.areas,noAreaLabel:r("no_area",o),year:e,historyOf:(c,h)=>this._histories.historyOf(c,h)});return this._memo={deps:s,rows:n},n}_setSort(e){this._sort=E(this._sort,e),S(_.areaSort,`${this._sort.key}:${this._sort.dir}`)}_open(e){this.dispatchEvent(new CustomEvent("open-area",{detail:{areaKey:e},bubbles:!0,composed:!0}))}_toggleArchived(){this.dispatchEvent(new CustomEvent("archived-toggle",{bubbles:!0,composed:!0}))}_headerLabel(e,o,s){return e==="area_cost_year"?r("area_cost_year",s).replace("{year}",String(o)):r(e,s)}render(){if(!this.hass)return m;let e=this._lang,o=new Date().getFullYear(),s=this.currencySymbol,n=this._rows(o),c=L(R(n,this._query),this._sort),h=this.objects.filter(t=>t.object.archived).length,d=t=>g(t,e);return a`
<div class="filter-bar area-filter-bar">
<input
type="search"
@@ -1,54 +0,0 @@
/*! maintenance_supporter frontend 2.96.0 */
import{a as C}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-I7NCFUZX.js";import{q as A,r as j,s as E,t as L,u as R}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-PWKMLGJR.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-4OFQFCKD.js";import{a as _,b as w,c as S}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-5YKNSANW.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-BYGTDXRD.js";import{B as g,C as v,F as k,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-N6F5RX6S.js";var O=[{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=j(w(_.areaSort));this._histories=new C(this);this._localeReady=!1;this._memo=null}createRenderRoot(){return this}get _lang(){return f(this.hass)}willUpdate(e){if(super.willUpdate(e),e.has("objects")||e.has("showArchived")||e.has("hass")&&e.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(e){super.updated(e),!this._localeReady&&this.hass&&(this._localeReady=!0,$(this._lang).then(()=>this.requestUpdate()))}_rows(e){let o=this._lang,s=[this.objects,this.showArchived,this._histories.version,this.hass?.areas,o,e];if(this._memo&&this._memo.deps.every((c,h)=>c===s[h]))return this._memo.rows;let n=A(this.objects,{showArchived:this.showArchived,areas:this.hass?.areas,noAreaLabel:r("no_area",o),year:e,historyOf:(c,h)=>this._histories.historyOf(c,h)});return this._memo={deps:s,rows:n},n}_setSort(e){this._sort=E(this._sort,e),S(_.areaSort,`${this._sort.key}:${this._sort.dir}`)}_open(e){this.dispatchEvent(new CustomEvent("open-area",{detail:{areaKey:e},bubbles:!0,composed:!0}))}_toggleArchived(){this.dispatchEvent(new CustomEvent("archived-toggle",{bubbles:!0,composed:!0}))}_headerLabel(e,o,s){return e==="area_cost_year"?r("area_cost_year",s).replace("{year}",String(o)):r(e,s)}render(){if(!this.hass)return m;let e=this._lang,o=new Date().getFullYear(),s=this.currencySymbol,n=this._rows(o),c=L(R(n,this._query),this._sort),h=this.objects.filter(t=>t.object.archived).length,d=t=>g(t,e);return a`
<div class="filter-bar area-filter-bar">
<input
type="search"
class="search-input"
aria-label=${r("areas_filter",e)}
placeholder=${r("areas_filter",e)}
.value=${this._query}
@input=${t=>{this._query=t.target.value}}
/>
${this._histories.loading?a`<span class="area-loading">${r("loading",e)}</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",e):`${r("show_archived",e)} (${h})`}
</ha-button>`:m}
</div>
${n.length===0?a`<div class="empty-state">${r("no_objects",e)}</div>`:c.length===0?a`<div class="empty-state">${r("areas_filter_none",e)}</div>`:a`
<div class="objects-table-wrap">
<table class="objects-table areas-table">
<thead>
<tr>
${O.map(t=>{let u=this._sort.key===t.key;return a`<th class=${t.num?"num":""}
aria-sort=${u?this._sort.dir==="asc"?"ascending":"descending":"none"}>
<button class="area-sort ${u?"active":""}" title=${r("sort_label",e)} @click=${()=>this._setSort(t.key)}>
${this._headerLabel(t.label,o,e)}
${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(t=>a`
<tr class="objects-table-row" tabindex="0"
@click=${()=>this._open(t.key)}
@keydown=${u=>{u.key==="Enter"&&this._open(t.key)}}>
<td>
<ha-icon class="area-row-icon" .icon=${t.icon}></ha-icon>
<span class="objects-table-name">${t.name}</span>
</td>
<td class="num">${d(t.objects)}</td>
<td class="num">${d(t.tasks)}</td>
<td class="num">${t.overdue?a`<span class="area-count overdue">${d(t.overdue)}</span>`:d(0)}</td>
<td class="num">${t.dueSoon?a`<span class="area-count due-soon">${d(t.dueSoon)}</span>`:d(0)}</td>
<td class="num">${v(t.costYear,s,e)}</td>
<td class="num">${v(t.costTotal,s,e)}</td>
<td>${t.lastCompletion?k(t.lastCompletion,e):"\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.97.1 */
import"/maintenance_supporter_panelfiles/panel-chunks/chunk-4CRDSGBT.js";import{a as n,b as _,c as o,f as p,h as c,l as g,m as a,s,y as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YJXVPPWG.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};
@@ -0,0 +1,37 @@
/*! maintenance_supporter frontend 2.97.1 */
import{B as R,D as k,R 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-YJXVPPWG.js";function w(i){return`${i.entry_id??""}\0${i.part_id}`}function E(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 L(i,t,e,o){let{part:n,label:r}=E(i,t,e,o),s=n&&n.stock!==null&&n.stock!==void 0?` (${k(n.stock,n.unit,o)})`:"",a=n?.storage_location?` \u2014 ${n.storage_location}`:"";return`${R(i.quantity,o)}\xD7 ${r}${s}${a}`}function $(i,t,e,o){let r=(e.find(a=>a.entry_id===t)?.parts||[]).map(a=>({...a})),s=new Set(r.map(a=>w({part_id:a.id})));for(let a of i?.consumes_parts||[]){if(!a.entry_id||a.entry_id===t)continue;let c=w(a);if(s.has(c))continue;s.add(c);let{part:u,ownerName:p}=E(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}function O(){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 S(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 V(i){return S(i??[]).map(t=>({timestamp:t.timestamp,values:f(t)})).filter(t=>t.values.length>0)}function H(i,t,e){let o;for(let n of i){if(e!==void 0){let s=new Date(n.timestamp).getTime();if(!isNaN(s)&&s>=e)break}let r=n.values.find(s=>s.id===t);r&&(o=r)}return o}function T(i,t,e){let o=f(t).find(r=>r.id===e);if(!o)return null;let n=null;for(let r of S(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 A(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 M(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>=20))break}return t}function C(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 U=["notes","cost","duration","photo","user"],j={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=[x,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{w as a,L as b,$ as c,O as d,f as e,V as f,H as g,T as h,A as i,M as j,C as k,U as l,j as m};
@@ -1,153 +0,0 @@
/*! maintenance_supporter frontend 2.90.0 */
import{a as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WQXORDNI.js";import{a as r,b as _,c as l,f as o,h,l as d,m as s,q as i,s as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";var a=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}get _lang(){return p(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._error="",this._open=!0}openEdit(e,n){this._entryId=e,this._name=n.name||"",this._manufacturer=n.manufacturer||"",this._model=n.model||"",this._serialNumber=n.serial_number||"",this._areaId=n.area_id||"",this._installationDate=n.installation_date||"",this._warrantyExpiry=n.warranty_expiry||"",this._documentationUrl=n.documentation_url||"",this._notes=n.notes||"",this._haDeviceId=n.ha_device_id||"",this._parentEntryId=n.parent_entry_id||"",this._error="",this._open=!0}async _save(){if(!this._loading&&this._name.trim()){this._loading=!0,this._error="";try{this._entryId?await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/update",entry_id:this._entryId,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}):await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/create",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}),this._open=!1,this.dispatchEvent(new CustomEvent("object-saved"))}catch(e){this._error=u(e,this._lang,i("save_error",this._lang))}finally{this._loading=!1}}}_parentChoices(){return(this.objects||[]).filter(e=>e.entry_id!==this._entryId)}_close(){this._open=!1}render(){if(!this._open)return l``;let e=this._lang,n=this._entryId?i("edit_object",e):i("new_object",e);return l`
<ha-dialog open @closed=${this._close}>
<div class="dialog-title">${n}</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>
`}};a.styles=_`
.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;
}
`,r([d({attribute:!1})],a.prototype,"hass",2),r([d({attribute:!1})],a.prototype,"objects",2),r([s()],a.prototype,"_open",2),r([s()],a.prototype,"_loading",2),r([s()],a.prototype,"_error",2),r([s()],a.prototype,"_name",2),r([s()],a.prototype,"_manufacturer",2),r([s()],a.prototype,"_model",2),r([s()],a.prototype,"_serialNumber",2),r([s()],a.prototype,"_areaId",2),r([s()],a.prototype,"_installationDate",2),r([s()],a.prototype,"_warrantyExpiry",2),r([s()],a.prototype,"_documentationUrl",2),r([s()],a.prototype,"_notes",2),r([s()],a.prototype,"_haDeviceId",2),r([s()],a.prototype,"_parentEntryId",2),r([s()],a.prototype,"_entryId",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",a);export{a};
@@ -1,88 +0,0 @@
/*! maintenance_supporter frontend 2.90.0 */
import{A as m,a,b as y,c as s,f as l,h as g,l as o,m as f,q as d}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.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);
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.88.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};
@@ -1,153 +0,0 @@
/*! maintenance_supporter frontend 2.95.0 */
import{a as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GGJ6YWZO.js";import{a as r,b as _,c as l,f as o,h as p,l as d,m as s,s as i,y as h}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4XNVTWGC.js";var a=class extends p{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}get _lang(){return h(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._error="",this._open=!0}openEdit(e,n){this._entryId=e,this._name=n.name||"",this._manufacturer=n.manufacturer||"",this._model=n.model||"",this._serialNumber=n.serial_number||"",this._areaId=n.area_id||"",this._installationDate=n.installation_date||"",this._warrantyExpiry=n.warranty_expiry||"",this._documentationUrl=n.documentation_url||"",this._notes=n.notes||"",this._haDeviceId=n.ha_device_id||"",this._parentEntryId=n.parent_entry_id||"",this._error="",this._open=!0}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};await u(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}})!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("object-saved")))}_parentChoices(){return(this.objects||[]).filter(e=>e.entry_id!==this._entryId)}_close(){this._open=!1}render(){if(!this._open)return l``;let e=this._lang,n=this._entryId?i("edit_object",e):i("new_object",e);return l`
<ha-dialog open @closed=${this._close}>
<div class="dialog-title">${n}</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>
`}};a.styles=_`
.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;
}
`,r([d({attribute:!1})],a.prototype,"hass",2),r([d({attribute:!1})],a.prototype,"objects",2),r([s()],a.prototype,"_open",2),r([s()],a.prototype,"_loading",2),r([s()],a.prototype,"_error",2),r([s()],a.prototype,"_name",2),r([s()],a.prototype,"_manufacturer",2),r([s()],a.prototype,"_model",2),r([s()],a.prototype,"_serialNumber",2),r([s()],a.prototype,"_areaId",2),r([s()],a.prototype,"_installationDate",2),r([s()],a.prototype,"_warrantyExpiry",2),r([s()],a.prototype,"_documentationUrl",2),r([s()],a.prototype,"_notes",2),r([s()],a.prototype,"_haDeviceId",2),r([s()],a.prototype,"_parentEntryId",2),r([s()],a.prototype,"_entryId",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",a);export{a};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.95.0 */
import{a as r}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-LEWJHPDY.js";var a={operatorWriteEnabled:!1,operatorIds:[]};function p(e,t=a){return e?e.is_admin?!0:t.operatorWriteEnabled&&t.operatorIds.includes(e.id):!1}var d=["buttons_compact","buttons","icons"];function _(e){let[t,n]=r.default_warning_days,s=e?.general?.default_warning_days,i=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(i??"")?i:o.rowActionStyle,access:{operatorWriteEnabled:e?.operator_write_enabled===!0,operatorIds:Array.isArray(e?.admin_panel_user_ids)?e.admin_panel_user_ids.filter(u=>typeof u=="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}}var o={features:{adaptive:!1,predictions:!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};function l(){let e=window;return e.__msSettingsCache??={promise:null}}function b(e){let t=l();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(){l().promise=null}var c=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,p as b,d as c,_ as d,b as e,h as f,c as g};
@@ -1,5 +1,5 @@
/*! maintenance_supporter frontend 2.96.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-N6F5RX6S.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`
/*! maintenance_supporter frontend 2.97.1 */
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-YJXVPPWG.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`
File diff suppressed because it is too large. Load diff
@@ -1,2 +1,2 @@
/*! maintenance_supporter frontend 2.95.0 */
import{F as n,s as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4XNVTWGC.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};
/*! maintenance_supporter frontend 2.97.1 */
import{F as n,s as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YJXVPPWG.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,2 @@
/*! maintenance_supporter frontend 2.97.1 */
import{p as w}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YJXVPPWG.js";var C={days:1,weeks:7,months:30.4368,years:365.25};function S(n,e){return!n||n<=0?0:n*(C[e||"days"]??1)}function R(n,e,s){let t=S(n,s);if(t<=0||e==null)return{pct:0,overflow:!1};let r=(t-e)/t*100;return{pct:Math.max(0,Math.min(100,r)),overflow:r>100}}function B(n){return n==="use"?"use":"purchase"}var y=n=>typeof n=="number"&&Number.isFinite(n)?n:null;function N(n){let e=y(n?.cost);if(e===null)return null;let s=y(n?.package_size);return s&&s>0?e/s:e}function $(n,e){let s=y(e)&&e>0?e:y(n.restock_quantity)||1,t=y(n.package_size);return Math.round(s*(t&&t>0?t:1)*100)/100}function b(n){let e=y(n.cost);if(n.cost_basis!=="use")return e;let s=y(n.parts_cost),t=n.purchase?null:e;return t===null&&s===null?null:(t??0)+(s??0)}var j=5;function v(n){let e=n.getFullYear(),s=String(n.getMonth()+1).padStart(2,"0"),t=String(n.getDate()).padStart(2,"0");return`${e}-${s}-${t}`}function U(n){let e=String(n.getHours()).padStart(2,"0"),s=String(n.getMinutes()).padStart(2,"0");return`${v(n)}T${e}:${s}:00`}function M(n,e){let s=[];for(let t=0;t<e;t++){let r=new Date(n);r.setDate(r.getDate()+t),r.setHours(0,0,0,0),s.push(v(r))}return s}function k(n,e){let[s,t,r]=n.split("-").map(Number),l=new Date(s,t-1,r);return l.setDate(l.getDate()+e),v(l)}function I(n){if(!n||n.length===0)return null;let e=n.map(s=>b(s)).filter(s=>s!==null&&s>=0);return e.length===0?null:e.reduce((s,t)=>s+t,0)/e.length}function A(n){let{windowStart:e,windowEnd:s,task:t,entryId:r,objectName:l}=n,c=[],_=(i,a)=>({date:i,entry_id:r,task_id:t.id,task_name:t.name,object_name:l,status:a&&(t.status==="overdue"||t.status==="triggered")?"ok":t.status,days_until_due:a?null:t.days_until_due??null,projected:a,schedule_type:t.schedule_type,interval_days:t.interval_days??null,interval_unit:t.interval_unit??null,responsible_user_id:t.responsible_user_id??null,avg_cost:I(t.history),adaptive_enabled:!!t.adaptive_config?.enabled,prediction_confidence:t.threshold_prediction_confidence??null}),d=Math.max(1,Math.round(S(t.interval_days,t.interval_unit)));if(t.status==="overdue"||t.status==="triggered"){if(c.push(_(e,!1)),t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let i=k(e,d),a=1;for(;i<=s&&a<j;)c.push(_(i,!0)),a++,i=k(i,d)}return c}let u=t.next_due;if(typeof u!="string"||!u)return c;let o=u.slice(0,10);if(o>=e&&o<=s)c.push(_(o,!1));else if(o>s)return c;if(t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let i=k(o,d),a=c.length;for(;i<=s&&a<j;)i>=e&&(c.push(_(i,!0)),a++),i=k(i,d)}return c}function X(n,e,s,t=null){let r=M(e,s),l=r[0],c=r[r.length-1],_=[];for(let u of n){let o=u.object?.name||"",i=u.entry_id,a=u.tasks||[];for(let g of a){if(t&&g.responsible_user_id!==t||g.enabled===!1)continue;let p=A({windowStart:l,windowEnd:c,task:g,entryId:i,objectName:o});_.push(...p)}}let d=new Map;for(let u of r)d.set(u,[]);for(let u of _){let o=d.get(u.date);o&&o.push(u)}for(let[,u]of d)u.sort((o,i)=>{let a=w(o.status),g=w(i.status);if(a!==g)return a-g;if(o.projected!==i.projected)return o.projected?1:-1;let p=o.object_name.localeCompare(i.object_name);return p!==0?p:o.task_name.localeCompare(i.task_name)});return r.map(u=>({date:u,events:d.get(u)??[]}))}var H={completed:"ok",reset:"ok",skipped:"due_soon",missed:"overdue",triggered:"triggered",trigger_replaced:"triggered",trigger_removed:"ok"};function x(n,e){return`${n}/${e}`}function q(n,e,s){let t=P(e,s)[0],r=[];for(let l of n)for(let c of l.tasks||[]){let _=c.history||[],d=c.history_count??_.length;if(d<=_.length)continue;let u=_.map(a=>typeof a?.timestamp=="string"?a.timestamp:"").filter(Boolean),o=u.length?u.reduce((a,g)=>a<g?a:g).slice(0,10):"";if(o&&o<t)continue;let i=x(l.entry_id,c.id);r.push({entryId:l.entry_id,taskId:c.id,key:i,sig:`${i}:${d}:${O(JSON.stringify(_))}`})}return r}function O(n){let e=2166136261;for(let s=0;s<n.length;s++)e^=n.charCodeAt(s),e=Math.imul(e,16777619);return(e>>>0).toString(36)}function P(n,e){let s=[];for(let t=e-1;t>=0;t--){let r=new Date(n);r.setDate(r.getDate()-t),r.setHours(0,0,0,0),s.push(v(r))}return s}function W(n,e,s,t=null,r={}){let l=P(e,s),c=l[0],_=l[l.length-1],d=new Map;for(let o of l)d.set(o,[]);for(let o of n){let i=o.object?.name||"",a=o.entry_id,g=o.tasks||[];for(let p of g){if(t&&p.responsible_user_id!==t)continue;let m=r[x(a,p.id)]??(p.history||[]);for(let f of m){if(typeof f?.timestamp!="string")continue;let h=f.timestamp.slice(0,10);if(h<c||h>_)continue;let D=d.get(h);if(!D)continue;let E=f.type??"completed";D.push({date:h,entry_id:a,task_id:p.id,task_name:p.name,object_name:i,status:H[E]??"ok",days_until_due:null,projected:!1,schedule_type:p.schedule_type,interval_days:p.interval_days??null,responsible_user_id:p.responsible_user_id??null,avg_cost:b(f),adaptive_enabled:!!p.adaptive_config?.enabled,prediction_confidence:null,history_timestamp:f.timestamp,history_type:E,history_cost:b(f),history_notes:typeof f.notes=="string"?f.notes:null,history_duration:typeoLine truncated
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.90.0 */
import{q as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";function f(r){return`${r.entry_id??""}\0${r.part_id}`}function g(r,n,i,o){let t=!!r.entry_id&&r.entry_id!==n,e=t?r.entry_id:n,s=i.find(l=>l.entry_id===e),a=(s?.parts||[]).find(l=>l.id===r.part_id)||null,u=t&&s?.object?.name||"",d=a?.name||p("shared_part_unknown",o);return{part:a,foreign:t,ownerName:u,label:u?`${d} (${u})`:d}}function _(r,n,i,o){let{part:t,label:e}=g(r,n,i,o),s=t&&t.stock!==null&&t.stock!==void 0?` (${t.stock}${t.unit?" "+t.unit:""})`:"",a=t?.storage_location?` \u2014 ${t.storage_location}`:"";return`${r.quantity}\xD7 ${e}${s}${a}`}function R(r,n,i,o){let e=(i.find(a=>a.entry_id===n)?.parts||[]).map(a=>({...a})),s=new Set(e.map(a=>f({part_id:a.id})));for(let a of r?.consumes_parts||[]){if(!a.entry_id||a.entry_id===n)continue;let u=f(a);if(s.has(u))continue;s.add(u);let{part:d,ownerName:l}=g(a,n,i,o);e.push({id:a.part_id,name:d?.name||p("shared_part_unknown",o),unit:d?.unit,stock:d?.stock??null,storage_location:d?.storage_location,entry_id:a.entry_id,owner_name:l})}return e}function w(){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 c(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||c(n).length>0)).sort((n,i)=>n.timestamp.localeCompare(i.timestamp))}function S(r){return y(r??[]).map(n=>({timestamp:n.timestamp,values:c(n)})).filter(n=>n.values.length>0)}function P(r,n,i){let o;for(let t of r){if(i!==void 0){let s=new Date(t.timestamp).getTime();if(!isNaN(s)&&s>=i)break}let e=t.values.find(s=>s.id===n);e&&(o=e)}return o}function b(r,n,i){let o=c(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=c(e).find(a=>a.id===i);s&&(t=s.value)}return t==null?null:o.value-t}function E(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 v(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>=20))break}return n}var x=["notes","cost","duration","photo","user"],h={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"};export{f as a,_ as b,R as c,w as d,c as e,S as f,P as g,b as h,E as i,v as j,x as k,h as l};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.94.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],a=[1,1e4],u=15,d=[.1,.9],s=[0,365],i=[.01,999],b=[.01,9999],A=[.1,5];export{n as a,o as b,t as c,_ as d,a as e,u as f,d as g,s as h,i,b as j,A as k};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.94.0 */
import{c as r,f as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-JE577H3E.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};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.88.0 */
import{b as S}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-3UVOHVFS.js";async function x(n,t,s=300){return(await n.connection.sendMessagePromise({type:"auth/sign_path",path:t,expires:s})).path}async function C(n,t,s=300){return x(n,`/api/maintenance_supporter/document/${t}`,s)}async function N(n,t,s=""){let e=window.open("about:blank","_blank");try{let o=await C(n,t);e&&(e.location.href=new URL(o+s,window.location.origin).href)}catch(o){throw e&&e.close(),o}}async function B(n,t,s){S(await C(n,t,30),s)}function O(n){let t=URL.createObjectURL(new Blob([n],{type:"text/html"}));window.open(t,"_blank"),setTimeout(()=>URL.revokeObjectURL(t),6e4)}var E={days:1,weeks:7,months:30.4368,years:365.25};function b(n,t){return!n||n<=0?0:n*(E[t||"days"]??1)}function L(n,t,s){let e=b(n,s);if(e<=0||t==null)return{pct:0,overflow:!1};let o=(e-t)/e*100;return{pct:Math.max(0,Math.min(100,o)),overflow:o>100}}var D=5;function h(n){let t=n.getFullYear(),s=String(n.getMonth()+1).padStart(2,"0"),e=String(n.getDate()).padStart(2,"0");return`${t}-${s}-${e}`}function P(n,t){let s=[];for(let e=0;e<t;e++){let o=new Date(n);o.setDate(o.getDate()+e),o.setHours(0,0,0,0),s.push(h(o))}return s}function y(n,t){let[s,e,o]=n.split("-").map(Number),g=new Date(s,e-1,o);return g.setDate(g.getDate()+t),h(g)}function R(n){if(!n||n.length===0)return null;let t=n.map(s=>s.cost).filter(s=>typeof s=="number");return t.length===0?null:t.reduce((s,e)=>s+e,0)/t.length}function T(n){let{windowStart:t,windowEnd:s,task:e,entryId:o,objectName:g}=n,u=[],d=(a,c)=>({date:a,entry_id:o,task_id:e.id,task_name:e.name,object_name:g,status:c&&(e.status==="overdue"||e.status==="triggered")?"ok":e.status,days_until_due:c?null:e.days_until_due??null,projected:c,schedule_type:e.schedule_type,interval_days:e.interval_days??null,interval_unit:e.interval_unit??null,responsible_user_id:e.responsible_user_id??null,avg_cost:R(e.history),adaptive_enabled:!!e.adaptive_config?.enabled,prediction_confidence:e.threshold_prediction_confidence??null}),p=Math.max(1,Math.round(b(e.interval_days,e.interval_unit)));if(e.status==="overdue"||e.status==="triggered"){if(u.push(d(t,!1)),e.schedule_type==="time_based"&&e.interval_days&&e.interval_days>0){let a=y(t,p),c=1;for(;a<=s&&c<D;)u.push(d(a,!0)),c++,a=y(a,p)}return u}let r=e.next_due;if(typeof r!="string"||!r)return u;let i=r.slice(0,10);if(i>=t&&i<=s)u.push(d(i,!1));else if(i>s)return u;if(e.schedule_type==="time_based"&&e.interval_days&&e.interval_days>0){let a=y(i,p),c=u.length;for(;a<=s&&c<D;)a>=t&&(u.push(d(a,!0)),c++),a=y(a,p)}return u}var j={overdue:0,triggered:1,due_soon:2,ok:3};function Y(n,t,s,e=null){let o=P(t,s),g=o[0],u=o[o.length-1],d=[];for(let r of n){let i=r.object?.name||"",a=r.entry_id,c=r.tasks||[];for(let l of c){if(e&&l.responsible_user_id!==e||l.enabled===!1)continue;let _=T({windowStart:g,windowEnd:u,task:l,entryId:a,objectName:i});d.push(..._)}}let p=new Map;for(let r of o)p.set(r,[]);for(let r of d){let i=p.get(r.date);i&&i.push(r)}for(let[,r]of p)r.sort((i,a)=>{let c=j[i.status]??99,l=j[a.status]??99;if(c!==l)return c-l;if(i.projected!==a.projected)return i.projected?1:-1;let _=i.object_name.localeCompare(a.object_name);return _!==0?_:i.task_name.localeCompare(a.task_name)});return o.map(r=>({date:r,events:p.get(r)??[]}))}var H={completed:"ok",reset:"ok",skipped:"due_soon",missed:"overdue",triggered:"triggered",trigger_replaced:"triggered",trigger_removed:"ok"};function M(n,t){let s=[];for(let e=t-1;e>=0;e--){let o=new Date(n);o.setDate(o.getDate()-e),o.setHours(0,0,0,0),s.push(h(o))}return s}function $(n,t,s,e=null){let o=M(t,s),g=o[0],u=o[o.length-1],d=new Map;for(let r of o)d.set(r,[]);for(let r of n){let i=r.object?.name||"",a=r.entry_id,c=r.tasks||[];for(let l of c){if(e&&l.responsible_user_id!==e)continue;let _=l.history||[];for(let m of _){if(typeof m?.timestamp!="string")continue;let f=m.timestamp.slice(0,10);if(f<g||f>u)continue;let w=d.get(f);if(!w)continue;let k=m.type??"completed";w.push({date:f,entry_id:a,task_id:l.id,task_name:l.name,object_name:i,status:H[k]??"ok",days_until_due:null,projected:!1,schedule_type:l.schedule_type,interval_days:l.interval_days??null,responsible_user_id:l.responsible_user_id??null,avg_cost:typeof m.cost=="number"?m.cost:null,adaptive_enabled:!!l.adaptive_config?.enabled,prediction_confidence:null,history_timestamp:m.timestamp,history_type:k,history_cost:typeof m.cost=="number"?m.cost:null,history_notes:typeof m.notes=="string"?m.notes:null,history_duration:typeof m.duration=="number"?m.duration:null})}}}let p={completed:0,reset:1,skipped:2,triggered:3,trigger_replaced:4};for(let[,r]of d)r.sort((i,a)=>{let c=p[i.history_type??""]??99,l=p[a.history_type??""]??99;if(c!==l)return c-l;let _=i.object_name.localeCompare(a.object_name);return _!==0?_:i.task_name.localeCompare(a.task_name)});return o.map(r=>({date:r,events:d.get(r)??[]}))}var v={features:{adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,complLine truncated
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.90.0 */
import{c as r,f as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.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};
@@ -1,88 +0,0 @@
/*! maintenance_supporter frontend 2.94.0 */
import{D 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-JE577H3E.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);
@@ -1,234 +0,0 @@
/*! maintenance_supporter frontend 2.95.0 */
import{a as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WUMSAU4G.js";import{a as r,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-4XNVTWGC.js";function d(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function _(a){return!a.startsWith("data:image/svg+xml,")&&!a.startsWith("data:image/png;base64,")?"":d(a)}function R(a){return a.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var l=class extends x{constructor(){super(...arguments);this.lang="en";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}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.lang):e("qr_error",this.lang)}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.lang||"en",m=d(i),g=d(s),v=!!this._completeResult,b=!!this._quickResult,q=d(e("qr_action_view",p)),w=d(e("qr_action_complete",p)),$=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">${q}</div>
</div>
${v?`<div class="qr-col">
<img src="${_(this._completeResult.svg_data_uri)}" alt="QR Complete" />
<div class="qr-label">${w}</div>
</div>`:""}
${b?`<div class="qr-col">
<img src="${_(this._quickResult.svg_data_uri)}" alt="QR Quick-complete" />
<div class="qr-label">${$}</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;k(s,`qr-${R(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.lang||this.hass?.language||"en",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);
}
`,r([h({attribute:!1})],l.prototype,"hass",2),r([h()],l.prototype,"lang",2),r([c()],l.prototype,"_open",2),r([c()],l.prototype,"_loading",2),r([c()],l.prototype,"_error",2),r([c()],l.prototype,"_viewResult",2),r([c()],l.prototype,"_completeResult",2),r([c()],l.prototype,"_quickResult",2),r([c()],l.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",l);export{l as a};
@@ -1,2 +1,2 @@
/*! maintenance_supporter frontend 2.95.0 */
import{a as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YKVD2DJ5.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};
/*! maintenance_supporter frontend 2.97.1 */
import{a as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-BEGYKXHI.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.97.1 */
import{b as j}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-O7BSORZB.js";import{e as x,f as A,l as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-5SGCD2J3.js";var q=500,E=new Set(["completed","skipped","reset","missed"]);function N(r,e){let n=r.reading_values||[];return n.length?n.filter(o=>typeof o.value=="number").map(o=>({id:o.id,name:o.name||"",value:o.value,unit:o.unit||""})):typeof r.reading_value=="number"?[{id:"",name:"",value:r.reading_value,unit:e||""}]:[]}function C(r){let e=[];for(let n of r){let o=[...n.history??[]].map(t=>({h:t,ts:new Date(t.timestamp).getTime()})).filter(t=>Number.isFinite(t.ts)).sort((t,a)=>t.ts-a.ts),s=new Map;for(let{h:t,ts:a}of o){let y=N(t,n.reading_unit).map(i=>{let f=s.get(i.id);return s.set(i.id,i.value),{name:i.name,value:i.value,unit:i.unit,delta:f==null?null:i.value-f}});if(!E.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:n.id,taskName:n.name,type:t.type,cost:x(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&&n.phases?.[t.phase_id]?.name||null,refNo:typeof t.ref_no=="number"?t.ref_no:null,taskRefNo:typeof n.ref_no=="number"?n.ref_no:null,readings:y,parts:(t.used_parts||[]).filter(i=>i&&(i.name||i.part_id)).map(i=>({name:i.name||i.part_id,quantity:typeof i.quantity=="number"?i.quantity:1})),photoIds:v(t),checklist:c&&c.length?{done:c.filter(Boolean).length,total:c.length}:null})}}return e.sort((n,o)=>o.ts-n.ts||n.taskName.localeCompare(o.taskName)),e}function H(r,e){let n=e.from?new Date(`${e.from}T00:00:00`).getTime():null,o=e.to?new Date(`${e.to}T00:00:00`).getTime()+864e5:null;return r.filter(s=>!(e.taskId&&s.taskId!==e.taskId||n!=null&&s.ts<n||o!=null&&s.ts>=o))}function S(r){let e=0,n=0;for(let o of r)o.type==="completed"&&(e++,o.cost!=null&&(n+=o.cost));return{completed:e,totalCost:n}}var p="__none__",I=36;function T(r){return r.area_id||p}function w(r,e,n){return r===p?n:e?.[r]?.name||r}function D(r,e){return r===p?"mdi:map-marker-off-outline":e?.[r]?.icon||"mdi:map-marker-outline"}function U(r,e,n){return r.filter(o=>(n||!o.object.archived)&&T(o.object)===e)}function B(r,e){let n=[];for(let o of r){let s=C(o.tasks.map(t=>({id:t.id,name:t.name,history:e(o.entry_id,t),phases:t.phases,ref_no:t.ref_no,reading_unit:t.reading_unit})));for(let t of s)n.push({...t,entryId:o.entry_id,objectName:o.object.name})}return n.sort((o,s)=>s.ts-o.ts||o.objectName.localeCompare(s.objectName)||o.taskName.localeCompare(s.taskName)),n}function z(r,e){let n=(e.taskQuery??"").trim();return H(r,{from:e.from,to:e.to}).filter(o=>(!e.entryId||o.entryId===e.entryId)&&(!n||j(o.taskName,n)))}function X(r){let{completed:e,totalCost:n}=S(r),o=0,s=0,t=0;for(let a of r)a.type==="completed"&&(a.duration!=null&&(o+=a.duration),!((a.cost??0)<0)&&(s++,t+=a.cost??0));return{completions:e,totalCost:n,avgCost:s?t/s:null,totalDuration:o}}function G(r,e){let n=new Map;for(let t of e)n.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=n.get(t.entryId);a&&(a.completions++,t.cost!=null&&(a.cost+=t.cost))}let o=[...n.values()].reduce((t,a)=>t+Math.max(a.cost,0),0),s=[...n.values()].map(t=>({...t,share:o>0?Math.max(t.cost,0)/o:0}));return s.sort((t,a)=>a.cost-t.cost||a.completions-t.completions||t.objectName.localeCompare(a.objectName)),s}function R(r){let[e,n]=r.split("-").map(Number);return[e,n-1]}function L(r,e){return`${r}-${String(e+1).padStart(2,"0")}`}function J(r,e,n=new Date){let o=r.filter(u=>u.type==="completed"),s=o.map(u=>A(new Date(u.ts))),t=A(n),a=s.reduce((u,m)=>m<u?m:u,t),y=s.reduce((u,m)=>m>u?m:u,t),[c,i]=R(e.from||a),[f,h]=R(e.to||y),l=f*12+h-(c*12+i)+1;if(l<=0)return{unit:"month",buckets:[]};let g=l>I?"year":"month",k=[],_=new Map;if(g==="month")for(let u=0;u<l;u++){let m=c+Math.floor((i+u)/12),b=(i+u)%12,d={key:L(m,b),year:m,month:b,cost:0,completions:0};k.push(d),_.set(d.key,d)}else for(let u=c;u<=f;u++){let m={key:String(u),year:u,month:null,cost:0,completions:0};k.push(m),_.set(m.key,m)}return o.forEach((u,m)=>{let b=s[m],d=_.get(g==="month"?b.slice(0,7):b.slice(0,4));d&&(d.completions++,u.cost!=null&&(d.cost+=u.cost))}),{unit:g,buckets:k}}function W(r=new Date){return{from:A(new Date(r.getFullYear(),r.getMonth()-11,1)),to:A(r)}}function Z(r){return{from:`${r}-01-01`,to:`${r}-12-31`}}function tt(r,e){let n=new Set([e]);for(let o of r)o.type==="completed"&&n.add(new Date(o.ts).getFullYear());return[...n].sort((o,s)=>s-o)}function et(r,e){let n=new Map;for(let s of r){if(!e.showArchived&&s.object.archived)continue;let t=T(s.object),a=n.get(t);a?a.push(s):n.set(t,[s])}let o=[];for(let[s,t]of n){let a=Line truncated
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.96.0 */
import{r as c,s as o,v as g,y as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-N6F5RX6S.js";var w={already_archived:"ws_err_already_archived",already_paused:"ws_err_already_paused",archived:"ws_err_archived",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",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 r=t.join(" ");return r.charAt(0).toUpperCase()+r.slice(1)}function b(n,t){let r=h[n];if(r){let e=o(r,t);if(e&&e!==r)return e}return y(n)}function k(n){let t=[...n.matchAll(/\['([^']+)'\]/g)].map(i=>i[1]),r=t.length?t[t.length-1]:void 0,e;return(e=n.match(/length of value must be at most (\d+)/))?{field:r,rule:"too_long",param:e[1]}:(e=n.match(/length of value must be at least (\d+)/))?{field:r,rule:"too_short",param:e[1]}:(e=n.match(/value must be at most (\S+)/))?{field:r,rule:"value_too_high",param:e[1]}:(e=n.match(/value must be at least (\S+)/))?{field:r,rule:"value_too_low",param:e[1]}:/required key not provided/.test(n)?{field:r,rule:"required"}:(e=n.match(/expected (\w+)/))?{field:r,rule:"wrong_type",param:e[1]}:/value must be one of/.test(n)?{field:r,rule:"invalid_choice"}:/not a valid value/.test(n)?{field:r,rule:"invalid_value"}:{field:r,rule:"unknown"}}var p=n=>n.toLowerCase().split(/[^a-z0-9]+/).filter(t=>t.length>1);function E(n,t){let r=new Set(p(t));return p(n).every(e=>r.has(e))}function f(n,t,r){if(r=r??o("action_error",t),typeof n=="string")return n;if(typeof n!="object"||n===null)return r;let e=n,i=e.message||e.error?.message||"",_=e.code||e.error?.code||"",l=_?w[_]:void 0,d=g(e.translation_domain??e.error?.translation_domain,e.translation_key??e.error?.translation_key,e.translation_placeholders??e.error?.translation_placeholders);if(d)return d;if(!i&&!l)return r;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 c(t)==="en"&&i&&!E(i,_)?`${u} (${i})`:u}return i||r}}async function W(n,t,r={}){r.busy?.(!0);try{let e=typeof t=="function"?await t():await n.hass.connection.sendMessagePromise(t);return r.reload&&await rLine truncated
@@ -1,153 +0,0 @@
/*! maintenance_supporter frontend 2.94.0 */
import{a as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-K4SNNHPR.js";import{a as r,b as _,c as l,f as o,h as p,l as d,m as s,s as i,u as h}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-JE577H3E.js";var a=class extends p{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}get _lang(){return h(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._error="",this._open=!0}openEdit(e,n){this._entryId=e,this._name=n.name||"",this._manufacturer=n.manufacturer||"",this._model=n.model||"",this._serialNumber=n.serial_number||"",this._areaId=n.area_id||"",this._installationDate=n.installation_date||"",this._warrantyExpiry=n.warranty_expiry||"",this._documentationUrl=n.documentation_url||"",this._notes=n.notes||"",this._haDeviceId=n.ha_device_id||"",this._parentEntryId=n.parent_entry_id||"",this._error="",this._open=!0}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};await u(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}})!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("object-saved")))}_parentChoices(){return(this.objects||[]).filter(e=>e.entry_id!==this._entryId)}_close(){this._open=!1}render(){if(!this._open)return l``;let e=this._lang,n=this._entryId?i("edit_object",e):i("new_object",e);return l`
<ha-dialog open @closed=${this._close}>
<div class="dialog-title">${n}</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>
`}};a.styles=_`
.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;
}
`,r([d({attribute:!1})],a.prototype,"hass",2),r([d({attribute:!1})],a.prototype,"objects",2),r([s()],a.prototype,"_open",2),r([s()],a.prototype,"_loading",2),r([s()],a.prototype,"_error",2),r([s()],a.prototype,"_name",2),r([s()],a.prototype,"_manufacturer",2),r([s()],a.prototype,"_model",2),r([s()],a.prototype,"_serialNumber",2),r([s()],a.prototype,"_areaId",2),r([s()],a.prototype,"_installationDate",2),r([s()],a.prototype,"_warrantyExpiry",2),r([s()],a.prototype,"_documentationUrl",2),r([s()],a.prototype,"_notes",2),r([s()],a.prototype,"_haDeviceId",2),r([s()],a.prototype,"_parentEntryId",2),r([s()],a.prototype,"_entryId",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",a);export{a};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.96.0 */
import{p as w}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-N6F5RX6S.js";var C={days:1,weeks:7,months:30.4368,years:365.25};function S(n,e){return!n||n<=0?0:n*(C[e||"days"]??1)}function R(n,e,s){let t=S(n,s);if(t<=0||e==null)return{pct:0,overflow:!1};let r=(t-e)/t*100;return{pct:Math.max(0,Math.min(100,r)),overflow:r>100}}function B(n){return n==="use"?"use":"purchase"}var y=n=>typeof n=="number"&&Number.isFinite(n)?n:null;function N(n){let e=y(n?.cost);if(e===null)return null;let s=y(n?.package_size);return s&&s>0?e/s:e}function $(n,e){let s=y(e)&&e>0?e:y(n.restock_quantity)||1,t=y(n.package_size);return Math.round(s*(t&&t>0?t:1)*100)/100}function b(n){let e=y(n.cost);if(n.cost_basis!=="use")return e;let s=y(n.parts_cost),t=n.purchase?null:e;return t===null&&s===null?null:(t??0)+(s??0)}var j=5;function v(n){let e=n.getFullYear(),s=String(n.getMonth()+1).padStart(2,"0"),t=String(n.getDate()).padStart(2,"0");return`${e}-${s}-${t}`}function U(n){let e=String(n.getHours()).padStart(2,"0"),s=String(n.getMinutes()).padStart(2,"0");return`${v(n)}T${e}:${s}:00`}function M(n,e){let s=[];for(let t=0;t<e;t++){let r=new Date(n);r.setDate(r.getDate()+t),r.setHours(0,0,0,0),s.push(v(r))}return s}function k(n,e){let[s,t,r]=n.split("-").map(Number),l=new Date(s,t-1,r);return l.setDate(l.getDate()+e),v(l)}function I(n){if(!n||n.length===0)return null;let e=n.map(s=>b(s)).filter(s=>s!==null);return e.length===0?null:e.reduce((s,t)=>s+t,0)/e.length}function A(n){let{windowStart:e,windowEnd:s,task:t,entryId:r,objectName:l}=n,c=[],_=(i,a)=>({date:i,entry_id:r,task_id:t.id,task_name:t.name,object_name:l,status:a&&(t.status==="overdue"||t.status==="triggered")?"ok":t.status,days_until_due:a?null:t.days_until_due??null,projected:a,schedule_type:t.schedule_type,interval_days:t.interval_days??null,interval_unit:t.interval_unit??null,responsible_user_id:t.responsible_user_id??null,avg_cost:I(t.history),adaptive_enabled:!!t.adaptive_config?.enabled,prediction_confidence:t.threshold_prediction_confidence??null}),d=Math.max(1,Math.round(S(t.interval_days,t.interval_unit)));if(t.status==="overdue"||t.status==="triggered"){if(c.push(_(e,!1)),t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let i=k(e,d),a=1;for(;i<=s&&a<j;)c.push(_(i,!0)),a++,i=k(i,d)}return c}let u=t.next_due;if(typeof u!="string"||!u)return c;let o=u.slice(0,10);if(o>=e&&o<=s)c.push(_(o,!1));else if(o>s)return c;if(t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let i=k(o,d),a=c.length;for(;i<=s&&a<j;)i>=e&&(c.push(_(i,!0)),a++),i=k(i,d)}return c}function X(n,e,s,t=null){let r=M(e,s),l=r[0],c=r[r.length-1],_=[];for(let u of n){let o=u.object?.name||"",i=u.entry_id,a=u.tasks||[];for(let g of a){if(t&&g.responsible_user_id!==t||g.enabled===!1)continue;let p=A({windowStart:l,windowEnd:c,task:g,entryId:i,objectName:o});_.push(...p)}}let d=new Map;for(let u of r)d.set(u,[]);for(let u of _){let o=d.get(u.date);o&&o.push(u)}for(let[,u]of d)u.sort((o,i)=>{let a=w(o.status),g=w(i.status);if(a!==g)return a-g;if(o.projected!==i.projected)return o.projected?1:-1;let p=o.object_name.localeCompare(i.object_name);return p!==0?p:o.task_name.localeCompare(i.task_name)});return r.map(u=>({date:u,events:d.get(u)??[]}))}var H={completed:"ok",reset:"ok",skipped:"due_soon",missed:"overdue",triggered:"triggered",trigger_replaced:"triggered",trigger_removed:"ok"};function x(n,e){return`${n}/${e}`}function q(n,e,s){let t=P(e,s)[0],r=[];for(let l of n)for(let c of l.tasks||[]){let _=c.history||[],d=c.history_count??_.length;if(d<=_.length)continue;let u=_.map(a=>typeof a?.timestamp=="string"?a.timestamp:"").filter(Boolean),o=u.length?u.reduce((a,g)=>a<g?a:g).slice(0,10):"";if(o&&o<t)continue;let i=x(l.entry_id,c.id);r.push({entryId:l.entry_id,taskId:c.id,key:i,sig:`${i}:${d}:${O(JSON.stringify(_))}`})}return r}function O(n){let e=2166136261;for(let s=0;s<n.length;s++)e^=n.charCodeAt(s),e=Math.imul(e,16777619);return(e>>>0).toString(36)}function P(n,e){let s=[];for(let t=e-1;t>=0;t--){let r=new Date(n);r.setDate(r.getDate()-t),r.setHours(0,0,0,0),s.push(v(r))}return s}function W(n,e,s,t=null,r={}){let l=P(e,s),c=l[0],_=l[l.length-1],d=new Map;for(let o of l)d.set(o,[]);for(let o of n){let i=o.object?.name||"",a=o.entry_id,g=o.tasks||[];for(let p of g){if(t&&p.responsible_user_id!==t)continue;let m=r[x(a,p.id)]??(p.history||[]);for(let f of m){if(typeof f?.timestamp!="string")continue;let h=f.timestamp.slice(0,10);if(h<c||h>_)continue;let D=d.get(h);if(!D)continue;let E=f.type??"completed";D.push({date:h,entry_id:a,task_id:p.id,task_name:p.name,object_name:i,status:H[E]??"ok",days_until_due:null,projected:!1,schedule_type:p.schedule_type,interval_days:p.interval_days??null,responsible_user_id:p.responsible_user_id??null,avg_cost:b(f),adaptive_enabled:!!p.adaptive_config?.enabled,prediction_confidence:null,history_timestamp:f.timestamp,history_type:E,history_cost:b(f),history_notes:typeof f.notes=="string"?f.notes:null,history_duration:typeof f.duLine truncated
@@ -1,79 +0,0 @@
/*! maintenance_supporter frontend 2.88.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-OXPKT66L.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);
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.90.0 */
import{b as S}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-XB4BHMUS.js";async function x(n,t,s=300){return(await n.connection.sendMessagePromise({type:"auth/sign_path",path:t,expires:s})).path}async function C(n,t,s=300){return x(n,`/api/maintenance_supporter/document/${t}`,s)}async function N(n,t,s=""){let e=window.open("about:blank","_blank");try{let o=await C(n,t);e&&(e.location.href=new URL(o+s,window.location.origin).href)}catch(o){throw e&&e.close(),o}}async function B(n,t,s){S(await C(n,t,30),s)}function O(n){let t=URL.createObjectURL(new Blob([n],{type:"text/html"}));window.open(t,"_blank"),setTimeout(()=>URL.revokeObjectURL(t),6e4)}var E={days:1,weeks:7,months:30.4368,years:365.25};function b(n,t){return!n||n<=0?0:n*(E[t||"days"]??1)}function L(n,t,s){let e=b(n,s);if(e<=0||t==null)return{pct:0,overflow:!1};let o=(e-t)/e*100;return{pct:Math.max(0,Math.min(100,o)),overflow:o>100}}var D=5;function h(n){let t=n.getFullYear(),s=String(n.getMonth()+1).padStart(2,"0"),e=String(n.getDate()).padStart(2,"0");return`${t}-${s}-${e}`}function P(n,t){let s=[];for(let e=0;e<t;e++){let o=new Date(n);o.setDate(o.getDate()+e),o.setHours(0,0,0,0),s.push(h(o))}return s}function y(n,t){let[s,e,o]=n.split("-").map(Number),g=new Date(s,e-1,o);return g.setDate(g.getDate()+t),h(g)}function R(n){if(!n||n.length===0)return null;let t=n.map(s=>s.cost).filter(s=>typeof s=="number");return t.length===0?null:t.reduce((s,e)=>s+e,0)/t.length}function T(n){let{windowStart:t,windowEnd:s,task:e,entryId:o,objectName:g}=n,u=[],d=(a,c)=>({date:a,entry_id:o,task_id:e.id,task_name:e.name,object_name:g,status:c&&(e.status==="overdue"||e.status==="triggered")?"ok":e.status,days_until_due:c?null:e.days_until_due??null,projected:c,schedule_type:e.schedule_type,interval_days:e.interval_days??null,interval_unit:e.interval_unit??null,responsible_user_id:e.responsible_user_id??null,avg_cost:R(e.history),adaptive_enabled:!!e.adaptive_config?.enabled,prediction_confidence:e.threshold_prediction_confidence??null}),p=Math.max(1,Math.round(b(e.interval_days,e.interval_unit)));if(e.status==="overdue"||e.status==="triggered"){if(u.push(d(t,!1)),e.schedule_type==="time_based"&&e.interval_days&&e.interval_days>0){let a=y(t,p),c=1;for(;a<=s&&c<D;)u.push(d(a,!0)),c++,a=y(a,p)}return u}let r=e.next_due;if(typeof r!="string"||!r)return u;let i=r.slice(0,10);if(i>=t&&i<=s)u.push(d(i,!1));else if(i>s)return u;if(e.schedule_type==="time_based"&&e.interval_days&&e.interval_days>0){let a=y(i,p),c=u.length;for(;a<=s&&c<D;)a>=t&&(u.push(d(a,!0)),c++),a=y(a,p)}return u}var j={overdue:0,triggered:1,due_soon:2,ok:3};function Y(n,t,s,e=null){let o=P(t,s),g=o[0],u=o[o.length-1],d=[];for(let r of n){let i=r.object?.name||"",a=r.entry_id,c=r.tasks||[];for(let l of c){if(e&&l.responsible_user_id!==e||l.enabled===!1)continue;let _=T({windowStart:g,windowEnd:u,task:l,entryId:a,objectName:i});d.push(..._)}}let p=new Map;for(let r of o)p.set(r,[]);for(let r of d){let i=p.get(r.date);i&&i.push(r)}for(let[,r]of p)r.sort((i,a)=>{let c=j[i.status]??99,l=j[a.status]??99;if(c!==l)return c-l;if(i.projected!==a.projected)return i.projected?1:-1;let _=i.object_name.localeCompare(a.object_name);return _!==0?_:i.task_name.localeCompare(a.task_name)});return o.map(r=>({date:r,events:p.get(r)??[]}))}var H={completed:"ok",reset:"ok",skipped:"due_soon",missed:"overdue",triggered:"triggered",trigger_replaced:"triggered",trigger_removed:"ok"};function M(n,t){let s=[];for(let e=t-1;e>=0;e--){let o=new Date(n);o.setDate(o.getDate()-e),o.setHours(0,0,0,0),s.push(h(o))}return s}function $(n,t,s,e=null){let o=M(t,s),g=o[0],u=o[o.length-1],d=new Map;for(let r of o)d.set(r,[]);for(let r of n){let i=r.object?.name||"",a=r.entry_id,c=r.tasks||[];for(let l of c){if(e&&l.responsible_user_id!==e)continue;let _=l.history||[];for(let m of _){if(typeof m?.timestamp!="string")continue;let f=m.timestamp.slice(0,10);if(f<g||f>u)continue;let w=d.get(f);if(!w)continue;let k=m.type??"completed";w.push({date:f,entry_id:a,task_id:l.id,task_name:l.name,object_name:i,status:H[k]??"ok",days_until_due:null,projected:!1,schedule_type:l.schedule_type,interval_days:l.interval_days??null,responsible_user_id:l.responsible_user_id??null,avg_cost:typeof m.cost=="number"?m.cost:null,adaptive_enabled:!!l.adaptive_config?.enabled,prediction_confidence:null,history_timestamp:m.timestamp,history_type:k,history_cost:typeof m.cost=="number"?m.cost:null,history_notes:typeof m.notes=="string"?m.notes:null,history_duration:typeof m.duration=="number"?m.duration:null})}}}let p={completed:0,reset:1,skipped:2,triggered:3,trigger_replaced:4};for(let[,r]of d)r.sort((i,a)=>{let c=p[i.history_type??""]??99,l=p[a.history_type??""]??99;if(c!==l)return c-l;let _=i.object_name.localeCompare(a.object_name);return _!==0?_:i.task_name.localeCompare(a.task_name)});return o.map(r=>({date:r,events:d.get(r)??[]}))}var v={features:{adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,complLine truncated
@@ -1,2 +1,2 @@
/*! maintenance_supporter frontend 2.96.0 */
import{c as r,f as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-N6F5RX6S.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};
/*! maintenance_supporter frontend 2.97.1 */
import{c as r,f as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YJXVPPWG.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};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.94.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};
@@ -1,79 +0,0 @@
/*! maintenance_supporter frontend 2.90.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-RAW6RFRE.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);
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.90.0 */
var l=[{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"}],i=l.map(a=>a.key),r=["name","manufacturer","model","serial_number","installation_date","warranty_expiry","area_id","task_count","actions"];function o(a){if(!Array.isArray(a))return[...r];let t=new Set,e=[];for(let n of a)typeof n=="string"&&i.includes(n)&&!t.has(n)&&(t.add(n),e.push(n));return e.length?(e.includes("name")||e.unshift("name"),e):[...r]}export{l as a,r as b,o as c};
@@ -1,2 +1,2 @@
/*! maintenance_supporter frontend 2.96.0 */
/*! maintenance_supporter frontend 2.97.1 */
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};
@@ -1,213 +0,0 @@
/*! maintenance_supporter frontend 2.90.0 */
import{a as x}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-XB4BHMUS.js";import{a,b as v,c as n,f as p,h as b,l as h,m as c,q as t}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";function d(l){return l.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function f(l){return!l.startsWith("data:image/svg+xml,")&&!l.startsWith("data:image/png;base64,")?"":d(l)}function q(l){return l.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var o=class extends b{constructor(){super(...arguments);this.lang="en";this._open=!1;this._loading=!1;this._error="";this._viewResult=null;this._completeResult=null;this._urlMode="companion";this._entryId="";this._taskId=null;this._objectName="";this._taskName="";this._generateSeq=0}openForObject(e,i){this._entryId=e,this._taskId=null,this._objectName=i,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._open=!0,this._generate()}openForTask(e,i,r,s){this._entryId=e,this._taskId=i,this._objectName=r,this._taskName=s,this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._open=!0,this._generate()}async _generate(){let e=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=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 r=[this.hass.connection.sendMessagePromise({...i,action:"view"})];this._taskId&&r.push(this.hass.connection.sendMessagePromise({...i,action:"complete"}));let s=await Promise.all(r);if(e!==this._generateSeq)return;this._viewResult=s[0],s.length>1&&(this._completeResult=s[1])}catch(i){if(e!==this._generateSeq)return;let r=i?.code,s=i?.message;this._error=r==="no_url"||typeof s=="string"&&s.includes("No Home Assistant URL")?t("qr_error_no_url",this.lang):t("qr_error",this.lang)}finally{e===this._generateSeq&&(this._loading=!1)}}_setUrlMode(e){this._urlMode!==e&&(this._urlMode=e,this._generate())}_print(){if(!this._viewResult)return;let e=this._viewResult,i=e.label.task_name?`${e.label.object_name} \u2014 ${e.label.task_name}`:e.label.object_name,r=[e.label.manufacturer,e.label.model].filter(Boolean).join(" "),s=window.open("","_blank","width=600,height=500");if(!s)return;let g=this.lang||"en",u=d(i),m=d(r),_=!!this._completeResult,w=d(t("qr_action_view",g)),$=d(t("qr_action_complete",g));s.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
<meta name="color-scheme" content="light">
<title>${u}</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:${_?"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>${u}</h2>
${m?`<div class="sub">${m}</div>`:""}
<div class="qr-row">
<div class="qr-col">
<img src="${f(this._viewResult.svg_data_uri)}" alt="QR Info" />
<div class="qr-label">${w}</div>
</div>
${_?`<div class="qr-col">
<img src="${f(this._completeResult.svg_data_uri)}" alt="QR Complete" />
<div class="qr-label">${$}</div>
</div>`:""}
</div>
<div class="url">${d(this._viewResult.url)}</div>
<script>setTimeout(()=>window.print(),300)<\/script>
</body></html>`),s.document.close()}_downloadSvg(e,i){let r=decodeURIComponent(e.svg_data_uri.replace("data:image/svg+xml,","")),s=this._taskName?`${this._objectName}-${this._taskName}`:this._objectName;x(r,`qr-${q(s)}-${i}.svg`,"image/svg+xml")}_close(){this._open=!1,this._viewResult=null,this._completeResult=null,this._error="",this._loading=!1}render(){if(!this._open)return n``;let e=this.lang||this.hass?.language||"en",i=this._taskName?`${t("qr_code",e)}: ${this._objectName} \u2014 ${this._taskName}`:`${t("qr_code",e)}: ${this._objectName}`,r=!!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">${t("qr_generating",e)}</div>`:this._error?n`<div class="error">${this._error}</div>`:r?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">${t("qr_action_view",e)}</div>
<button class="dl-btn"
@click=${()=>this._downloadSvg(this._viewResult,"info")}>
<ha-icon icon="mdi:download"></ha-icon>
${t("qr_download",e)}
</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">${t("qr_action_complete",e)}</div>
<button class="dl-btn"
@click=${()=>this._downloadSvg(this._completeResult,"complete")}>
<ha-icon icon="mdi:download"></ha-icon>
${t("qr_download",e)}
</button>
</div>
`:p}
</div>
<div class="url-display">${this._viewResult.url}</div>
`:p}
<div class="action-row">
<label>${t("qr_url_mode",e)}</label>
<div class="action-toggle">
<button class="toggle-btn ${this._urlMode==="companion"?"active":""}"
@click=${()=>this._setUrlMode("companion")}>${t("qr_mode_companion",e)}</button>
<button class="toggle-btn ${this._urlMode==="local"?"active":""}"
@click=${()=>this._setUrlMode("local")}>${t("qr_mode_local",e)}</button>
<button class="toggle-btn ${this._urlMode==="server"?"active":""}"
@click=${()=>this._setUrlMode("server")}>${t("qr_mode_server",e)}</button>
</div>
</div>
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._close}>
${t("cancel",e)}
</ha-button>
<ha-button
@click=${this._print}
.disabled=${!r}
>
${t("qr_print",e)}
</ha-button>
</div>
</ha-dialog>
`}};o.styles=v`
.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;
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 {
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})],o.prototype,"hass",2),a([h()],o.prototype,"lang",2),a([c()],o.prototype,"_open",2),a([c()],o.prototype,"_loading",2),a([c()],o.prototype,"_error",2),a([c()],o.prototype,"_viewResult",2),a([c()],o.prototype,"_completeResult",2),a([c()],o.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",o);export{o as a};
@@ -1,79 +0,0 @@
/*! maintenance_supporter frontend 2.95.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-4XNVTWGC.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);
@@ -1,478 +0,0 @@
/*! maintenance_supporter frontend 2.94.0 */
import{c as P,l as O,m as A}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-IRVVKPDP.js";import{a as E,g as N,k as H,m as U}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-ZA53FZUW.js";import{i as z,j as w}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-63C4ZGBD.js";import{a as C}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-K4SNNHPR.js";import{A as R,B as q,P as F,a,b as x,c,f as h,h as k,l as p,m as _,s as n,z as I}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-JE577H3E.js";var S=class{constructor(d,e){this.host=d;this.opts=e;this.photos=[];this.uploadedIds=[];this.uploading=!1;this.errorKey="";this._session=0;this._uploadEntry=new Map;this.max=e.max??10,d.addController(this)}hostConnected(){}get ids(){return this.photos.map(d=>d.id)}get remaining(){return Math.max(this.max-this.photos.length,0)}get full(){return this.remaining===0}errorText(d){return this.errorKey?n(this.errorKey,d).replace("{max}",String(this.max)):""}clearError(){this.errorKey=""}reset(d=[]){this._endSession(),this._revokeAll(),this.photos=d.map(e=>({id:e,preview:""})),this.uploadedIds=[],this._uploadEntry.clear(),this.errorKey="",this.host.requestUpdate()}async addFiles(d){if(d.length===0)return;let e=this._session,i=this.opts.hass(),t=this.opts.entryId(),s=d.slice(0,this.remaining);this.uploading=!0,this.errorKey="",this.host.requestUpdate();try{for(let r of s){let o=await O(i,t,r);if(e!==this._session){A(i,t,[o]);return}this.uploadedIds=[...this.uploadedIds,o],this._uploadEntry.set(o,t),this.photos=[...this.photos,{id:o,preview:URL.createObjectURL(r)}],this.host.requestUpdate()}d.length>s.length&&(this.errorKey="photos_limit")}catch(r){if(e!==this._session)return;this.errorKey=r instanceof Error&&r.message==="doc_too_large"?"doc_too_large":"doc_upload_failed"}finally{e===this._session&&(this.uploading=!1,this.host.requestUpdate())}}remove(d){let e=this.photos.find(i=>i.id===d);e?.preview&&URL.revokeObjectURL(e.preview),this.photos=this.photos.filter(i=>i.id!==d),this.uploadedIds.includes(d)&&(this.uploadedIds=this.uploadedIds.filter(i=>i!==d),this._discard([d])),this.host.requestUpdate()}discardOrphans(){if(this._endSession(),this.uploadedIds.length===0)return;let d=this.uploadedIds;this.uploadedIds=[],this._discard(d)}markAttached(){this._endSession(),this.uploadedIds=[],this._uploadEntry.clear()}_endSession(){this._session++,this.uploading=!1}_discard(d){let e=new Map;for(let t of d){let s=this._uploadEntry.get(t)??this.opts.entryId();this._uploadEntry.delete(t),e.set(s,[...e.get(s)??[],t])}let i=this.opts.hass();for(let[t,s]of e)A(i,t,s)}_revokeAll(){for(let d of this.photos)d.preview&&URL.revokeObjectURL(d.preview)}};function T(){if(window.externalApp!==void 0)return!0;let d=typeof navigator<"u"&&navigator.userAgent||"";return/Home Assistant\//.test(d)&&/Android/.test(d)}var L={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"};function j(g){try{return localStorage.getItem(g)}catch{return null}}function Q(g,d){try{localStorage.setItem(g,d)}catch{}}function Y(){if(!T())return!1;let g=typeof navigator<"u"?navigator.mediaDevices:void 0;return!!g&&typeof g.getUserMedia=="function"}var J=1920,Z=.88,ee={retryMs:500,windowMs:5e3},te=new Set(["NotReadableError","AbortError","TrackStartError"]),V=80,D=/back|rear|environment|rück|hinten/i,B=/front|user|selfie|vorne/i;function K(g){let d=/camera2?\s*(\d+)/i.exec(g);return d?Number(d[1]):Number.MAX_SAFE_INTEGER}function M(g,d){if(d){let i=g.find(t=>t.label===d);if(i)return i}return g.filter(i=>i.label&&D.test(i.label)).sort((i,t)=>K(i.label)-K(t.label))[0]??null}var G=g=>g?.name||"Error",ie=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={...ee};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,thLine 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,s=Math.min(1,J/Math.max(i,t)),r=document.createElement("canvas");r.width=Math.round(i*s),r.height=Math.round(t*s);let o=r.getContext("2d");if(!o)throw new Error("no_canvas");o.drawImage(e,0,0,r.width,r.height);let u=await new Promise(v=>r.toBlob(v,"image/jpeg",Z));if(!u)throw new Error("no_blob");let m=new Date().toISOString().replace(/[-:]/g,"").slice(0,15),f=new File([u],`photo-${m}.jpg`,{type:"image/jpeg"});this.close(),this.dispatchEvent(new CustomEvent("photo-captured",{detail:{file:f},bubbles:!0,composed:!0}))}catch(i){this._unavailable(i instanceof Error?i.message:String(i))}finally{this._busy=!1}}}render(){if(!this._open)return h;let e=this.lang,i=this._busy||this._switching;return c`
<div class="overlay" role="dialog" aria-modal="true" aria-label=${n("doc_camera",e)}>
<video autoplay playsinline muted></video>
${this._switching?c`<div class="switching" role="status">${n("camera_switching",e)}</div>`:h}
${this._switchFailed?c`<div class="switch-note" role="status">
<div>${n("camera_not_answered",e)}</div>
<details class="details">
<summary>${n("camera_diagnostics",e)}</summary>
<textarea readonly rows="6" .value=${this._log.join(`
`)}></textarea>
<button type="button" class="copy" @click=${this._copyLog}>${n(this._copied?"camera_copied":"camera_copy",e)}</button>
</details>
</div>`:h}
<div class="bar">
<button type="button" class="cancel" @click=${this.close}>${n("cancel",e)}</button>
${this._devices.length>1?c`<button type="button" class="switch" ?disabled=${i} title=${n("camera_switch_lens",e)} aria-label=${n("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>`:h}
<button type="button" class="shoot" ?disabled=${i} @click=${this._shoot}>
<ha-icon icon="mdi:camera"></ha-icon><span>${n("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([p({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 X=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=T();this._inAppCamera=Y()}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 h;let e=this.lang,i=this._locked?"disabled":"",t=this.busy?n("uploading",e):n("doc_camera",e),s=n(this._singlePick?"choose_photo":"choose_photos",e);return c`
<div class="photo-pickers">
${this.showCamera?c`<label class="photo-pick photo-pick-camera ${i}" role="button" tabindex="0"
aria-label=${t} title=${this.compact?t:h}
@click=${this._onCameraClick} @keydown=${this._onKeydown}>
<ha-icon icon="mdi:camera"></ha-icon>
${this.compact?h:c`<span>${t}</span>`}
<input type="file" accept=${this.accept} capture="environment"
?disabled=${this._locked} @change=${this._onInput} />
</label>`:h}
${this.showGallery?c`<label class="photo-pick photo-pick-gallery ${i}" role="button" tabindex="0"
aria-label=${s} title=${this.compact?s:h}
@keydown=${this._onKeydown}>
<ha-icon icon="mdi:image-multiple"></ha-icon>
${this.compact?h:c`<span>${s}</span>`}
<input type="file" accept=${this.accept} ?multiple=${!this._singlePick}
?disabled=${this._locked} @change=${this._onInput} />
</label>`:h}
</div>
${this.showGallery&&this._singlePick?c`<div class="photo-android-hint">${n("photos_android_hint",e)}</div>`:h}
${this.showCamera&&this._inAppCamera?c`<ms-camera-capture .lang=${e}
@photo-captured=${r=>this._emit([r.detail.file])}
@capture-unavailable=${this._onCameraUnavailable}></ms-camera-capture>`:h}
`}};a([p({type:String})],y.prototype,"lang",2),a([p({type:Boolean})],y.prototype,"disabled",2),a([p({type:Boolean})],y.prototype,"busy",2),a([p({type:String})],y.prototype,"accept",2),a([p({type:Boolean})],y.prototype,"showCamera",2),a([p({type:Boolean})],y.prototype,"showGallery",2),a([p({type:Boolean})],y.prototype,"compact",2),a([p({type:Number})],y.prototype,"remaining",2),a([_()],y.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",y);var $=z,l=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.currencySymbol="";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 S(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=>[E(i),{...i}])),this._usedQtyText={})}_rangeError(e,i){let t=this.lang;return n("settings_value_out_of_range",t).replace("{min}",I(e,t,{maximumFractionDigits:2})).replace("{max}",I(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};if(this._notes&&(e.notes=this._notes),this._cost){let s=parseFloat(this._cost);!isNaN(s)&&s>=0&&(e.cost=s)}let i=H(this._duration);if(i!==null&&(e.duration=i),this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photos.photos.length>0&&(e.photo_doc_ids=this._photos.ids),this.viaTagScan&&(e.via_tag_scan=!0),this._completedAt){if(new Date(this._completedAt).getTime()>Date.now()){this._error=n("completed_at_future_error",this.lang);return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let s={};for(let r of this.readings){let o=(this._readingValues[r.id]??"").trim();if(o==="")continue;let u=parseFloat(o.replace(",","."));isNaN(u)||(s[r.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[r,o]of Object.entries(this._usedParts)){let u=this._usedQtyText[r],m=u===void 0?o.quantity:parseFloat(u.replace(",","."));if(!Number.isFinite(m)||m<$[0]||m>$[1]){this._error=this._rangeError(...$);return}s.push({...o,quantity:m})}e.used_parts=s.map(r=>r.entry_id?{part_id:r.part_id,quantity:r.quantity,entry_id:r.entry_id}:{part_id:r.part_id,quantity:r.quantity})}await C(this,e,{busy:s=>{this._loading=s},lang:this.lang,fallbackKey:"save_error",onError:s=>{this._error=s}})!==void 0&&(this._photos.markAttached(),this._open=!1,this.dispatchEvent(new CustomEvent("task-completed")))}_renderReadingField(e,i){let t=this._completedAt?new Date(this._completedAt).getTime():NaN,s=N(this.readingHistory,e.id,isNaN(t)?void 0:t),r=e.unit||this.readingUnit,o=(this._readingValues[e.id]??"").trim(),u=o===""?NaN:parseFloat(o.replace(",",".")),m=s!==void 0&&!isNaN(u)&&u<s.value,f=s!==void 0?I(s.value,i,{maximumFractionDigits:3}):"";return c`
<label class="field reading-field">
<span class="field-label">${e.name}${r?` (${r})`:""}</span>
<input type="text" inputmode="decimal" class="field-input"
placeholder=${s!==void 0?n("reading_last",i).replace("{value}",f):""}
.value=${this._readingValues[e.id]??""}
@input=${v=>{this._readingValues={...this._readingValues,[e.id]:v.target.value}}} />
${m?c`<span class="reading-warn">${n("reading_below_last",i).replace("{value}",f)}</span>`:h}
</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])}_req(e){return this.requiredFields.includes(e)?c`<span class="req-mark" aria-hidden="true">*</span>`:h}_partsCostSuggestion(){if(this.restockDefault!==null){let t=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(t)||t<=0?null:Math.round(this.restockUnitCost*t*100)/100}if(!this.parts.length)return null;let e=0,i=!1;for(let t of Object.values(this._usedParts)){let s=this.parts.find(r=>E({part_id:r.id,entry_id:r.entry_id})===E(t));s?.cost!=null&&(e+=s.cost*(t.quantity||1),i=!0)}return i?Math.round(e*100)/100:null}_renderCostSuggestion(e){if(this._cost.trim()!=="")return h;let i=this._partsCostSuggestion();if(i==null||i<=0)return h;let t=R(i,this.currencySymbol,e);return c`<button
type="button"
class="cost-suggestion"
@click=${()=>this._cost=String(Math.round(i*100)/100)}
>${n("cost_from_parts",e).replace("{amount}",t)}</button>`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=P(new Date)}render(){if(!this._open)return c``;let e=this.lang||this.hass?.language||"en",i=this._error||this._photos.errorText(e);return c`
<ha-dialog open @closed=${this._close}>
<div class="dialog-title">${n("complete_title",e)}${this.taskName}</div>
${this.phaseLabel?c`<div class="phase-line">${n("phase_current",e)}: ${this.phaseLabel}</div>`:h}
${this.requireTagScan&&!this.viaTagScan?c`<div class="scan-required-note">${n("require_tag_scan_hint",e)}</div>`:h}
<div class="content">
${i?c`<div class="error">${i}</div>`:h}
${this.checklist.length>0?c`
<div class="checklist-section">
<label class="checklist-label">${n("checklist",e)}</label>
${this.checklist.map((t,s)=>c`
<label class="checklist-item" @click=${()=>this._toggleCheck(s)}>
<input type="checkbox" .checked=${!!this._checklistState[String(s)]} />
<span>${t}</span>
</label>
`)}
</div>
`:h}
${this.readings.length>0?c`<div class="readings-block">
<span class="field-label">${n("readings_section",e)}</span>
${this.readings.map(t=>this._renderReadingField(t,e))}
</div>`:this.taskType==="reading"?c`
<label class="field">
<span class="field-label">${n("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>`:h}
${this.parts.length?c`<div class="used-parts">
<span class="field-label">${n("complete_parts_used",e)}</span>
${this.parts.map(t=>{let s=E({part_id:t.id,entry_id:t.entry_id}),r=this._usedParts[s],o=r!==void 0,u=t.entry_id?{part_id:t.id,quantity:1,entry_id:t.entry_id}:{part_id:t.id,quantity:1};return c`<div class="used-part-row">
<label class="used-part-check">
<input type="checkbox" .checked=${o}
@change=${m=>{let f={...this._usedParts};if(m.target.checked)f[s]=f[s]||u;else{delete f[s];let v={...this._usedQtyText};delete v[s],this._usedQtyText=v}this._usedParts=f}} />
<span
>${t.name}${t.owner_name?c`<span class="used-part-owner"> (${t.owner_name})</span>`:h}${t.stock!==null&&t.stock!==void 0?` (${q(t.stock,t.unit,e)})`:""}</span
>
</label>
${o?c`<input class="used-part-qty" type="number" min=${$[0]} max=${$[1]} step="0.01"
.value=${this._usedQtyText[s]??String(r.quantity)}
@input=${m=>{let f=m.target.value;this._usedQtyText={...this._usedQtyText,[s]:f};let v=parseFloat(f.replace(",","."));Number.isFinite(v)&&v>=$[0]&&(this._usedParts={...this._usedParts,[s]:{...u,quantity:v}})}} />`:h}
</div>`})}
</div>`:this.consumesInfo.length?c`<div class="consumes-hint">
${this.consumesInfo.map(t=>c`<div>${t}</div>`)}
</div>`:h}
${this.restockDefault!==null?c`
<label class="field">
<span class="field-label">${n("restock_quantity_label",e)}</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>`:h}
<!-- 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">${n("notes_optional",e)}${this._req("notes")}</span>
<input type="text" class="field-input"
.value=${this._notes}
@input=${t=>this._notes=t.target.value} />
</label>
<label class="field">
<span class="field-label">${n("cost_optional",e)}${this._req("cost")}</span>
<input type="number" step="0.01" min="0" class="field-input"
.value=${this._cost}
@input=${t=>this._cost=t.target.value} />
${this._renderCostSuggestion(e)}
</label>
<label class="field">
<span class="field-label">${n("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">${n("completed_at_optional",e)}</span>
${this._completedAt?c`<ms-date-field
kind="datetime"
clearable
.hass=${this.hass}
.lang=${e}
.value=${this._completedAt}
@value-changed=${t=>this._completedAt=t.detail.value}
></ms-date-field>`:c`<button type="button" class="backdate-pick" @click=${this._pickCompletedAt}>
<ha-icon icon="mdi:calendar-clock"></ha-icon>${n("completed_at_pick",e)}
</button>`}
</div>
<div class="field">
<span class="field-label">${n("completion_photos_optional",e)}${this._req("photo")}</span>
${this._photos.photos.length>0?c`<div class="photo-strip">
${this._photos.photos.map(t=>c`
<div class="photo-preview">
<img src=${t.preview} alt="" />
<button type="button" class="photo-remove" @click=${()=>this._photos.remove(t.id)}
title="${n("remove",e)}">✕</button>
</div>`)}
</div>`:h}
${this._photos.full?c`<div class="photo-limit">${n("photos_limit",e).replace("{max}",String(this._photos.max))}</div>`:c`<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?c`
<div class="feedback-section">
<label class="feedback-label">${n("was_maintenance_needed",e)}</label>
<div class="feedback-buttons">
<button
class="feedback-btn ${this._feedback==="needed"?"selected":""}"
@click=${()=>this._setFeedback("needed")}
>${n("feedback_needed",e)}</button>
<button
class="feedback-btn ${this._feedback==="not_needed"?"selected":""}"
@click=${()=>this._setFeedback("not_needed")}
>${n("feedback_not_needed",e)}</button>
<button
class="feedback-btn ${this._feedback==="not_sure"?"selected":""}"
@click=${()=>this._setFeedback("not_sure")}
>${n("feedback_not_sure",e)}</button>
</div>
</div>
`:h}
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._close}>
${n("cancel",e)}
</ha-button>
<ha-button
@click=${this._complete}
.disabled=${this._loading||this._photos.uploading||this._missingRequired.length>0}
title=${this._photos.uploading?n("uploading",e):this._missingRequired.length?this._missingRequired.map(t=>n("err_required",e).replace("{field}",n(U[t]??t,e))).join(" \xB7 "):""}
>
${this._loading?n("completing",e):n("complete",e)}
</ha-button>
</div>
</ha-dialog>
`}};l.styles=[F,X,x`
.req-mark {
color: var(--error-color, #f44336);
margin-left: 2px;
font-weight: 600;
}
/* #104: one-click cost suggestion from parts — quiet link-style chip. */
.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([p({attribute:!1})],l.prototype,"hass",2),a([p()],l.prototype,"entryId",2),a([p()],l.prototype,"taskId",2),a([p()],l.prototype,"taskName",2),a([p()],l.prototype,"lang",2),a([p({type:Array})],l.prototype,"checklist",2),a([p({type:Boolean})],l.prototype,"adaptiveEnabled",2),a([p()],l.prototype,"taskType",2),a([p()],l.prototype,"readingUnit",2),a([p({attribute:!1})],l.prototype,"readings",2),a([p({attribute:!1})],l.prototype,"readingHistory",2),a([p({attribute:!1})],l.prototype,"restockDefault",2),a([p({attribute:!1})],l.prototype,"restockUnitCost",2),a([p()],l.prototype,"currencySymbol",2),a([p({attribute:!1})],l.prototype,"parts",2),a([p({attribute:!1})],l.prototype,"consumesParts",2),a([p({type:Array})],l.prototype,"consumesInfo",2),a([p({type:Array})],l.prototype,"requiredFields",2),a([p()],l.prototype,"phaseLabel",2),a([p({type:Boolean})],l.prototype,"requireTagScan",2),a([p({type:Boolean})],l.prototype,"viaTagScan",2),a([_()],l.prototype,"_open",2),a([_()],l.prototype,"_notes",2),a([_()],l.prototype,"_cost",2),a([_()],l.prototype,"_duration",2),a([_()],l.prototype,"_loading",2),a([_()],l.prototype,"_error",2),a([_()],l.prototype,"_checklistState",2),a([_()],l.prototype,"_feedback",2),a([_()],l.prototype,"_readingValue",2),a([_()],l.prototype,"_readingValues",2),a([_()],l.prototype,"_restockQty",2),a([_()],l.prototype,"_completedAt",2),a([_()],l.prototype,"_usedParts",2),a([_()],l.prototype,"_usedQtyText",2),a([p({attribute:!1})],l.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",l);export{L as a,j as b,Q as c,T as d,X as e,S as f,l as g};
File diff suppressed because it is too large. Load diff
@@ -1,5 +1,5 @@
/*! maintenance_supporter frontend 2.96.0 */
import{a as _}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-BFBOHWBW.js";import{a as s,b as p,c as l,f as o,h,l as c,m as n,s as i,y as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-N6F5RX6S.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
/*! maintenance_supporter frontend 2.97.1 */
import{a as _}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GVLO7RZ4.js";import{a as s,b as p,c as l,f as o,h,l as c,m as n,s as i,y as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YJXVPPWG.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:{}}}]}
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.95.0 */
import{r as c,s as o,v as g,y as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4XNVTWGC.js";var w={already_archived:"ws_err_already_archived",already_paused:"ws_err_already_paused",archived:"ws_err_archived",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",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 r=t.join(" ");return r.charAt(0).toUpperCase()+r.slice(1)}function b(n,t){let r=h[n];if(r){let e=o(r,t);if(e&&e!==r)return e}return y(n)}function k(n){let t=[...n.matchAll(/\['([^']+)'\]/g)].map(i=>i[1]),r=t.length?t[t.length-1]:void 0,e;return(e=n.match(/length of value must be at most (\d+)/))?{field:r,rule:"too_long",param:e[1]}:(e=n.match(/length of value must be at least (\d+)/))?{field:r,rule:"too_short",param:e[1]}:(e=n.match(/value must be at most (\S+)/))?{field:r,rule:"value_too_high",param:e[1]}:(e=n.match(/value must be at least (\S+)/))?{field:r,rule:"value_too_low",param:e[1]}:/required key not provided/.test(n)?{field:r,rule:"required"}:(e=n.match(/expected (\w+)/))?{field:r,rule:"wrong_type",param:e[1]}:/value must be one of/.test(n)?{field:r,rule:"invalid_choice"}:/not a valid value/.test(n)?{field:r,rule:"invalid_value"}:{field:r,rule:"unknown"}}var p=n=>n.toLowerCase().split(/[^a-z0-9]+/).filter(t=>t.length>1);function E(n,t){let r=new Set(p(t));return p(n).every(e=>r.has(e))}function f(n,t,r){if(r=r??o("action_error",t),typeof n=="string")return n;if(typeof n!="object"||n===null)return r;let e=n,i=e.message||e.error?.message||"",_=e.code||e.error?.code||"",l=_?w[_]:void 0,d=g(e.translation_domain??e.error?.translation_domain,e.translation_key??e.error?.translation_key,e.translation_placeholders??e.error?.translation_placeholders);if(d)return d;if(!i&&!l)return r;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 c(t)==="en"&&i&&!E(i,_)?`${u} (${i})`:u}return i||r}}async function W(n,t,r={}){r.busy?.(!0);try{let e=typeof t=="function"?await t():await n.hass.connection.sendMessagePromise(t);return r.reload&&await rLine truncated
@@ -1,2 +1,2 @@
/*! maintenance_supporter frontend 2.96.0 */
/*! maintenance_supporter frontend 2.97.1 */
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};
@@ -1,478 +0,0 @@
/*! maintenance_supporter frontend 2.95.0 */
import{d as H,e as L}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-XCDM7D5I.js";import{a as A,b as P,c as N}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YQT7IJJB.js";import{c as C}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-JEWIFUZC.js";import{a as E,g as z,k as j,m as Q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-ZCC7RQPW.js";import{i as U,j as w}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-LEWJHPDY.js";import{a as O}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GGJ6YWZO.js";import{B as I,C as q,D as R,R as F,a,b as x,c as l,f as h,h as k,l as p,m as _,s as n}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4XNVTWGC.js";var T=class{constructor(d,e){this.host=d;this.opts=e;this.photos=[];this.uploadedIds=[];this.uploading=!1;this.errorKey="";this._session=0;this._uploadEntry=new Map;this.max=e.max??10,d.addController(this)}hostConnected(){}get ids(){return this.photos.map(d=>d.id)}get remaining(){return Math.max(this.max-this.photos.length,0)}get full(){return this.remaining===0}errorText(d){return this.errorKey?n(this.errorKey,d).replace("{max}",String(this.max)):""}clearError(){this.errorKey=""}reset(d=[]){this._endSession(),this._revokeAll(),this.photos=d.map(e=>({id:e,preview:""})),this.uploadedIds=[],this._uploadEntry.clear(),this.errorKey="",this.host.requestUpdate()}async addFiles(d){if(d.length===0)return;let e=this._session,i=this.opts.hass(),t=this.opts.entryId(),s=d.slice(0,this.remaining);this.uploading=!0,this.errorKey="",this.host.requestUpdate();try{for(let r of s){let o=await H(i,t,r);if(e!==this._session){L(i,t,[o]);return}this.uploadedIds=[...this.uploadedIds,o],this._uploadEntry.set(o,t),this.photos=[...this.photos,{id:o,preview:URL.createObjectURL(r)}],this.host.requestUpdate()}d.length>s.length&&(this.errorKey="photos_limit")}catch(r){if(e!==this._session)return;this.errorKey=r instanceof Error&&r.message==="doc_too_large"?"doc_too_large":"doc_upload_failed"}finally{e===this._session&&(this.uploading=!1,this.host.requestUpdate())}}remove(d){let e=this.photos.find(i=>i.id===d);e?.preview&&URL.revokeObjectURL(e.preview),this.photos=this.photos.filter(i=>i.id!==d),this.uploadedIds.includes(d)&&(this.uploadedIds=this.uploadedIds.filter(i=>i!==d),this._discard([d])),this.host.requestUpdate()}discardOrphans(){if(this._endSession(),this.uploadedIds.length===0)return;let d=this.uploadedIds;this.uploadedIds=[],this._discard(d)}markAttached(){this._endSession(),this.uploadedIds=[],this._uploadEntry.clear()}_endSession(){this._session++,this.uploading=!1}_discard(d){let e=new Map;for(let t of d){let s=this._uploadEntry.get(t)??this.opts.entryId();this._uploadEntry.delete(t),e.set(s,[...e.get(s)??[],t])}let i=this.opts.hass();for(let[t,s]of e)L(i,t,s)}_revokeAll(){for(let d of this.photos)d.preview&&URL.revokeObjectURL(d.preview)}};function S(){if(window.externalApp!==void 0)return!0;let d=typeof navigator<"u"&&navigator.userAgent||"";return/Home Assistant\//.test(d)&&/Android/.test(d)}function Y(){if(!S())return!1;let g=typeof navigator<"u"?navigator.mediaDevices:void 0;return!!g&&typeof g.getUserMedia=="function"}var J=1920,Z=.88,ee={retryMs:500,windowMs:5e3},te=new Set(["NotReadableError","AbortError","TrackStartError"]),V=80,D=/back|rear|environment|rück|hinten/i,B=/front|user|selfie|vorne/i;function K(g){let d=/camera2?\s*(\d+)/i.exec(g);return d?Number(d[1]):Number.MAX_SAFE_INTEGER}function M(g,d){if(d){let i=g.find(t=>t.label===d);if(i)return i}return g.filter(i=>i.label&&D.test(i.label)).sort((i,t)=>K(i.label)-K(t.label))[0]??null}var G=g=>g?.name||"Error",ie=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={...ee};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=P(A.cameraLabel),s=await this._enumerate(i);if(!this._live(e))return;let r=M(s,t),o="refused";if(r&&(o=await this._openPatiently(i,e,this._byDevice(r))),o==="cancelled")return;if(o!=="ok"){if(o=await this._openPatiently(i,e,{video:{facingMode:{ideal:"environment"}},what:"facing environment"}),o==="cancelled")return;if(o!=="ok"){this._unavailable(this._lastError||"camera_unavailable");return}if(s=await this._enumerate(i),!this._live(e)){this._stopStream();return}}if(this._devices=s,this._Line 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,s=Math.min(1,J/Math.max(i,t)),r=document.createElement("canvas");r.width=Math.round(i*s),r.height=Math.round(t*s);let o=r.getContext("2d");if(!o)throw new Error("no_canvas");o.drawImage(e,0,0,r.width,r.height);let u=await new Promise(v=>r.toBlob(v,"image/jpeg",Z));if(!u)throw new Error("no_blob");let m=new Date().toISOString().replace(/[-:]/g,"").slice(0,15),f=new File([u],`photo-${m}.jpg`,{type:"image/jpeg"});this.close(),this.dispatchEvent(new CustomEvent("photo-captured",{detail:{file:f},bubbles:!0,composed:!0}))}catch(i){this._unavailable(i instanceof Error?i.message:String(i))}finally{this._busy=!1}}}render(){if(!this._open)return h;let e=this.lang,i=this._busy||this._switching;return l`
<div class="overlay" role="dialog" aria-modal="true" aria-label=${n("doc_camera",e)}>
<video autoplay playsinline muted></video>
${this._switching?l`<div class="switching" role="status">${n("camera_switching",e)}</div>`:h}
${this._switchFailed?l`<div class="switch-note" role="status">
<div>${n("camera_not_answered",e)}</div>
<details class="details">
<summary>${n("camera_diagnostics",e)}</summary>
<textarea readonly rows="6" .value=${this._log.join(`
`)}></textarea>
<button type="button" class="copy" @click=${this._copyLog}>${n(this._copied?"camera_copied":"camera_copy",e)}</button>
</details>
</div>`:h}
<div class="bar">
<button type="button" class="cancel" @click=${this.close}>${n("cancel",e)}</button>
${this._devices.length>1?l`<button type="button" class="switch" ?disabled=${i} title=${n("camera_switch_lens",e)} aria-label=${n("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>`:h}
<button type="button" class="shoot" ?disabled=${i} @click=${this._shoot}>
<ha-icon icon="mdi:camera"></ha-icon><span>${n("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([p({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 X=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=Y()}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 h;let e=this.lang,i=this._locked?"disabled":"",t=this.busy?n("uploading",e):n("doc_camera",e),s=n(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:h}
@click=${this._onCameraClick} @keydown=${this._onKeydown}>
<ha-icon icon="mdi:camera"></ha-icon>
${this.compact?h:l`<span>${t}</span>`}
<input type="file" accept=${this.accept} capture="environment"
?disabled=${this._locked} @change=${this._onInput} />
</label>`:h}
${this.showGallery?l`<label class="photo-pick photo-pick-gallery ${i}" role="button" tabindex="0"
aria-label=${s} title=${this.compact?s:h}
@keydown=${this._onKeydown}>
<ha-icon icon="mdi:image-multiple"></ha-icon>
${this.compact?h:l`<span>${s}</span>`}
<input type="file" accept=${this.accept} ?multiple=${!this._singlePick}
?disabled=${this._locked} @change=${this._onInput} />
</label>`:h}
</div>
${this.showGallery&&this._singlePick?l`<div class="photo-android-hint">${n("photos_android_hint",e)}</div>`:h}
${this.showCamera&&this._inAppCamera?l`<ms-camera-capture .lang=${e}
@photo-captured=${r=>this._emit([r.detail.file])}
@capture-unavailable=${this._onCameraUnavailable}></ms-camera-capture>`:h}
`}};a([p({type:String})],y.prototype,"lang",2),a([p({type:Boolean})],y.prototype,"disabled",2),a([p({type:Boolean})],y.prototype,"busy",2),a([p({type:String})],y.prototype,"accept",2),a([p({type:Boolean})],y.prototype,"showCamera",2),a([p({type:Boolean})],y.prototype,"showGallery",2),a([p({type:Boolean})],y.prototype,"compact",2),a([p({type:Number})],y.prototype,"remaining",2),a([_()],y.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",y);var $=U,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.currencySymbol="";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=>[E(i),{...i}])),this._usedQtyText={})}_rangeError(e,i){let t=this.lang;return n("settings_value_out_of_range",t).replace("{min}",I(e,t,{maximumFractionDigits:2})).replace("{max}",I(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};if(this._notes&&(e.notes=this._notes),this._cost){let s=parseFloat(this._cost);!isNaN(s)&&s>=0&&(e.cost=s)}let i=j(this._duration);if(i!==null&&(e.duration=i),this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photos.photos.length>0&&(e.photo_doc_ids=this._photos.ids),this.viaTagScan&&(e.via_tag_scan=!0),this._completedAt){if(new Date(this._completedAt).getTime()>Date.now()){this._error=n("completed_at_future_error",this.lang);return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let s={};for(let r of this.readings){let o=(this._readingValues[r.id]??"").trim();if(o==="")continue;let u=parseFloat(o.replace(",","."));isNaN(u)||(s[r.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[r,o]of Object.entries(this._usedParts)){let u=this._usedQtyText[r],m=u===void 0?o.quantity:parseFloat(u.replace(",","."));if(!Number.isFinite(m)||m<$[0]||m>$[1]){this._error=this._rangeError(...$);return}s.push({...o,quantity:m})}e.used_parts=s.map(r=>r.entry_id?{part_id:r.part_id,quantity:r.quantity,entry_id:r.entry_id}:{part_id:r.part_id,quantity:r.quantity})}await O(this,e,{busy:s=>{this._loading=s},lang:this.lang,fallbackKey:"save_error",onError:s=>{this._error=s}})!==void 0&&(this._photos.markAttached(),this._open=!1,this.dispatchEvent(new CustomEvent("task-completed")))}_renderReadingField(e,i){let t=this._completedAt?new Date(this._completedAt).getTime():NaN,s=z(this.readingHistory,e.id,isNaN(t)?void 0:t),r=e.unit||this.readingUnit,o=(this._readingValues[e.id]??"").trim(),u=o===""?NaN:parseFloat(o.replace(",",".")),m=s!==void 0&&!isNaN(u)&&u<s.value,f=s!==void 0?I(s.value,i,{maximumFractionDigits:3}):"";return l`
<label class="field reading-field">
<span class="field-label">${e.name}${r?` (${r})`:""}</span>
<input type="text" inputmode="decimal" class="field-input"
placeholder=${s!==void 0?n("reading_last",i).replace("{value}",f):""}
.value=${this._readingValues[e.id]??""}
@input=${v=>{this._readingValues={...this._readingValues,[e.id]:v.target.value}}} />
${m?l`<span class="reading-warn">${n("reading_below_last",i).replace("{value}",f)}</span>`:h}
</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])}_req(e){return this.requiredFields.includes(e)?l`<span class="req-mark" aria-hidden="true">*</span>`:h}_partsCostSuggestion(){if(this.restockDefault!==null){let t=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(t)||t<=0?null:Math.round(this.restockUnitCost*t*100)/100}if(!this.parts.length)return null;let e=0,i=!1;for(let t of Object.values(this._usedParts)){let s=this.parts.find(r=>E({part_id:r.id,entry_id:r.entry_id})===E(t));s?.cost!=null&&(e+=s.cost*(t.quantity||1),i=!0)}return i?Math.round(e*100)/100:null}_renderCostSuggestion(e){if(this._cost.trim()!=="")return h;let i=this._partsCostSuggestion();if(i==null||i<=0)return h;let t=q(i,this.currencySymbol,e);return l`<button
type="button"
class="cost-suggestion"
@click=${()=>this._cost=String(Math.round(i*100)/100)}
>${n("cost_from_parts",e).replace("{amount}",t)}</button>`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=C(new Date)}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">${n("complete_title",e)}${this.taskName}</div>
${this.phaseLabel?l`<div class="phase-line">${n("phase_current",e)}: ${this.phaseLabel}</div>`:h}
${this.requireTagScan&&!this.viaTagScan?l`<div class="scan-required-note">${n("require_tag_scan_hint",e)}</div>`:h}
<div class="content">
${i?l`<div class="error">${i}</div>`:h}
${this.checklist.length>0?l`
<div class="checklist-section">
<label class="checklist-label">${n("checklist",e)}</label>
${this.checklist.map((t,s)=>l`
<label class="checklist-item" @click=${()=>this._toggleCheck(s)}>
<input type="checkbox" .checked=${!!this._checklistState[String(s)]} />
<span>${t}</span>
</label>
`)}
</div>
`:h}
${this.readings.length>0?l`<div class="readings-block">
<span class="field-label">${n("readings_section",e)}</span>
${this.readings.map(t=>this._renderReadingField(t,e))}
</div>`:this.taskType==="reading"?l`
<label class="field">
<span class="field-label">${n("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>`:h}
${this.parts.length?l`<div class="used-parts">
<span class="field-label">${n("complete_parts_used",e)}</span>
${this.parts.map(t=>{let s=E({part_id:t.id,entry_id:t.entry_id}),r=this._usedParts[s],o=r!==void 0,u=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=${o}
@change=${m=>{let f={...this._usedParts};if(m.target.checked)f[s]=f[s]||u;else{delete f[s];let v={...this._usedQtyText};delete v[s],this._usedQtyText=v}this._usedParts=f}} />
<span
>${t.name}${t.owner_name?l`<span class="used-part-owner"> (${t.owner_name})</span>`:h}${t.stock!==null&&t.stock!==void 0?` (${R(t.stock,t.unit,e)})`:""}</span
>
</label>
${o?l`<input class="used-part-qty" type="number" min=${$[0]} max=${$[1]} step="0.01"
.value=${this._usedQtyText[s]??String(r.quantity)}
@input=${m=>{let f=m.target.value;this._usedQtyText={...this._usedQtyText,[s]:f};let v=parseFloat(f.replace(",","."));Number.isFinite(v)&&v>=$[0]&&(this._usedParts={...this._usedParts,[s]:{...u,quantity:v}})}} />`:h}
</div>`})}
</div>`:this.consumesInfo.length?l`<div class="consumes-hint">
${this.consumesInfo.map(t=>l`<div>${t}</div>`)}
</div>`:h}
${this.restockDefault!==null?l`
<label class="field">
<span class="field-label">${n("restock_quantity_label",e)}</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>`:h}
<!-- 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">${n("notes_optional",e)}${this._req("notes")}</span>
<input type="text" class="field-input"
.value=${this._notes}
@input=${t=>this._notes=t.target.value} />
</label>
<label class="field">
<span class="field-label">${n("cost_optional",e)}${this._req("cost")}</span>
<input type="number" step="0.01" min="0" class="field-input"
.value=${this._cost}
@input=${t=>this._cost=t.target.value} />
${this._renderCostSuggestion(e)}
</label>
<label class="field">
<span class="field-label">${n("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">${n("completed_at_optional",e)}</span>
${this._completedAt?l`<ms-date-field
kind="datetime"
clearable
.hass=${this.hass}
.lang=${e}
.value=${this._completedAt}
@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>${n("completed_at_pick",e)}
</button>`}
</div>
<div class="field">
<span class="field-label">${n("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="${n("remove",e)}">✕</button>
</div>`)}
</div>`:h}
${this._photos.full?l`<div class="photo-limit">${n("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">${n("was_maintenance_needed",e)}</label>
<div class="feedback-buttons">
<button
class="feedback-btn ${this._feedback==="needed"?"selected":""}"
@click=${()=>this._setFeedback("needed")}
>${n("feedback_needed",e)}</button>
<button
class="feedback-btn ${this._feedback==="not_needed"?"selected":""}"
@click=${()=>this._setFeedback("not_needed")}
>${n("feedback_not_needed",e)}</button>
<button
class="feedback-btn ${this._feedback==="not_sure"?"selected":""}"
@click=${()=>this._setFeedback("not_sure")}
>${n("feedback_not_sure",e)}</button>
</div>
</div>
`:h}
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._close}>
${n("cancel",e)}
</ha-button>
<ha-button
@click=${this._complete}
.disabled=${this._loading||this._photos.uploading||this._missingRequired.length>0}
title=${this._photos.uploading?n("uploading",e):this._missingRequired.length?this._missingRequired.map(t=>n("err_required",e).replace("{field}",n(Q[t]??t,e))).join(" \xB7 "):""}
>
${this._loading?n("completing",e):n("complete",e)}
</ha-button>
</div>
</ha-dialog>
`}};c.styles=[F,X,x`
.req-mark {
color: var(--error-color, #f44336);
margin-left: 2px;
font-weight: 600;
}
/* #104: one-click cost suggestion from parts — quiet link-style chip. */
.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([p({attribute:!1})],c.prototype,"hass",2),a([p()],c.prototype,"entryId",2),a([p()],c.prototype,"taskId",2),a([p()],c.prototype,"taskName",2),a([p()],c.prototype,"lang",2),a([p({type:Array})],c.prototype,"checklist",2),a([p({type:Boolean})],c.prototype,"adaptiveEnabled",2),a([p()],c.prototype,"taskType",2),a([p()],c.prototype,"readingUnit",2),a([p({attribute:!1})],c.prototype,"readings",2),a([p({attribute:!1})],c.prototype,"readingHistory",2),a([p({attribute:!1})],c.prototype,"restockDefault",2),a([p({attribute:!1})],c.prototype,"restockUnitCost",2),a([p()],c.prototype,"currencySymbol",2),a([p({attribute:!1})],c.prototype,"parts",2),a([p({attribute:!1})],c.prototype,"consumesParts",2),a([p({type:Array})],c.prototype,"consumesInfo",2),a([p({type:Array})],c.prototype,"requiredFields",2),a([p()],c.prototype,"phaseLabel",2),a([p({type:Boolean})],c.prototype,"requireTagScan",2),a([p({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([p({attribute:!1})],c.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",c);export{S as a,X as b,T as c,c as d};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.97.1 */
import{r as g,s as o,v,y as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YJXVPPWG.js";var w={already_archived:"ws_err_already_archived",already_paused:"ws_err_already_paused",archived:"ws_err_archived",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",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.connection.sendMessagePromise(t);return e.reload&&await e.reloLine truncated
@@ -1,5 +1,5 @@
/*! maintenance_supporter frontend 2.96.0 */
import{F 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-N6F5RX6S.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`
/*! maintenance_supporter frontend 2.97.1 */
import{F 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-YJXVPPWG.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">
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.96.0 */
import{a as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-PWKMLGJR.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};
@@ -1,9 +1,9 @@
/*! maintenance_supporter frontend 2.96.0 */
import{d as U,e as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-AU57O2BC.js";import{a as L,b as F,c as N}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-5YKNSANW.js";import{c as C,g as z}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-BYGTDXRD.js";import{a as E,g as O,k as Q,m as V}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-MHBW3M6D.js";import{j,k as w}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WJT4RRLS.js";import{a as H}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-BFBOHWBW.js";import{B as I,C as A,D as R,R as P,a,b as x,c,f as u,h as k,l as p,m as _,s as n}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-N6F5RX6S.js";var S=class{constructor(d,e){this.host=d;this.opts=e;this.photos=[];this.uploadedIds=[];this.uploading=!1;this.errorKey="";this._session=0;this._uploadEntry=new Map;this.max=e.max??10,d.addController(this)}hostConnected(){}get ids(){return this.photos.map(d=>d.id)}get remaining(){return Math.max(this.max-this.photos.length,0)}get full(){return this.remaining===0}errorText(d){return this.errorKey?n(this.errorKey,d).replace("{max}",String(this.max)):""}clearError(){this.errorKey=""}reset(d=[]){this._endSession(),this._revokeAll(),this.photos=d.map(e=>({id:e,preview:""})),this.uploadedIds=[],this._uploadEntry.clear(),this.errorKey="",this.host.requestUpdate()}async addFiles(d){if(d.length===0)return;let e=this._session,i=this.opts.hass(),t=this.opts.entryId(),s=d.slice(0,this.remaining);this.uploading=!0,this.errorKey="",this.host.requestUpdate();try{for(let r of s){let o=await U(i,t,r);if(e!==this._session){q(i,t,[o]);return}this.uploadedIds=[...this.uploadedIds,o],this._uploadEntry.set(o,t),this.photos=[...this.photos,{id:o,preview:URL.createObjectURL(r)}],this.host.requestUpdate()}d.length>s.length&&(this.errorKey="photos_limit")}catch(r){if(e!==this._session)return;this.errorKey=r instanceof Error&&r.message==="doc_too_large"?"doc_too_large":"doc_upload_failed"}finally{e===this._session&&(this.uploading=!1,this.host.requestUpdate())}}remove(d){let e=this.photos.find(i=>i.id===d);e?.preview&&URL.revokeObjectURL(e.preview),this.photos=this.photos.filter(i=>i.id!==d),this.uploadedIds.includes(d)&&(this.uploadedIds=this.uploadedIds.filter(i=>i!==d),this._discard([d])),this.host.requestUpdate()}discardOrphans(){if(this._endSession(),this.uploadedIds.length===0)return;let d=this.uploadedIds;this.uploadedIds=[],this._discard(d)}markAttached(){this._endSession(),this.uploadedIds=[],this._uploadEntry.clear()}_endSession(){this._session++,this.uploading=!1}_discard(d){let e=new Map;for(let t of d){let s=this._uploadEntry.get(t)??this.opts.entryId();this._uploadEntry.delete(t),e.set(s,[...e.get(s)??[],t])}let i=this.opts.hass();for(let[t,s]of e)q(i,t,s)}_revokeAll(){for(let d of this.photos)d.preview&&URL.revokeObjectURL(d.preview)}};function T(){if(window.externalApp!==void 0)return!0;let d=typeof navigator<"u"&&navigator.userAgent||"";return/Home Assistant\//.test(d)&&/Android/.test(d)}function D(){if(!T())return!1;let g=typeof navigator<"u"?navigator.mediaDevices:void 0;return!!g&&typeof g.getUserMedia=="function"}var Z=1920,ee=.88,te={retryMs:500,windowMs:5e3},ie=new Set(["NotReadableError","AbortError","TrackStartError"]),M=80,X=/back|rear|environment|rück|hinten/i,B=/front|user|selfie|vorne/i;function K(g){let d=/camera2?\s*(\d+)/i.exec(g);return d?Number(d[1]):Number.MAX_SAFE_INTEGER}function G(g,d){if(d){let i=g.find(t=>t.label===d);if(i)return i}return g.filter(i=>i.label&&X.test(i.label)).sort((i,t)=>K(i.label)-K(t.label))[0]??null}var Y=g=>g?.name||"Error",se=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={...te};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=F(L.cameraLabel),s=await this._enumerate(i);if(!this._live(e))return;let r=G(s,t),o="refused";if(r&&(o=await this._openPatiently(i,e,this._byDevice(r))),o==="cancelled")return;if(o!=="ok"){if(o=await this._openPatiently(i,e,{video:{facingMode:{ideal:"environment"}},what:"facing environment"}),o==="cancelled")return;if(o!=="ok"){this._unavailable(this._lastError||"camera_unavailable");return}if(s=await this._enumerate(i),!this._live(e)){this._stopStream();return}}if(this._devices=s,this._deLine 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,s=Math.min(1,Z/Math.max(i,t)),r=document.createElement("canvas");r.width=Math.round(i*s),r.height=Math.round(t*s);let o=r.getContext("2d");if(!o)throw new Error("no_canvas");o.drawImage(e,0,0,r.width,r.height);let h=await new Promise(v=>r.toBlob(v,"image/jpeg",ee));if(!h)throw new Error("no_blob");let m=new Date().toISOString().replace(/[-:]/g,"").slice(0,15),f=new File([h],`photo-${m}.jpg`,{type:"image/jpeg"});this.close(),this.dispatchEvent(new CustomEvent("photo-captured",{detail:{file:f},bubbles:!0,composed:!0}))}catch(i){this._unavailable(i instanceof Error?i.message:String(i))}finally{this._busy=!1}}}render(){if(!this._open)return u;let e=this.lang,i=this._busy||this._switching;return c`
/*! maintenance_supporter frontend 2.97.1 */
import{d as H,e as L}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-QEKEY7ZD.js";import{a as q,b as F,c as N}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-EPK25IMX.js";import{c as C,g as z}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-5SGCD2J3.js";import{a as E,g as O,k as Q,m as V}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-2CZ4LD2Q.js";import{j,k as w}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GSRF4WCQ.js";import{a as U}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GVLO7RZ4.js";import{B as I,C as A,D as R,R as P,a as o,b as x,c,f,h as k,l as p,m as _,s as n}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YJXVPPWG.js";var S=class{constructor(d,e){this.host=d;this.opts=e;this.photos=[];this.uploadedIds=[];this.uploading=!1;this.errorKey="";this._session=0;this._uploadEntry=new Map;this.max=e.max??10,d.addController(this)}hostConnected(){}get ids(){return this.photos.map(d=>d.id)}get remaining(){return Math.max(this.max-this.photos.length,0)}get full(){return this.remaining===0}errorText(d){return this.errorKey?n(this.errorKey,d).replace("{max}",String(this.max)):""}clearError(){this.errorKey=""}reset(d=[]){this._endSession(),this._revokeAll(),this.photos=d.map(e=>({id:e,preview:""})),this.uploadedIds=[],this._uploadEntry.clear(),this.errorKey="",this.host.requestUpdate()}async addFiles(d){if(d.length===0)return;let e=this._session,i=this.opts.hass(),t=this.opts.entryId(),r=d.slice(0,this.remaining);this.uploading=!0,this.errorKey="",this.host.requestUpdate();try{for(let s of r){let a=await H(i,t,s);if(e!==this._session){L(i,t,[a]);return}this.uploadedIds=[...this.uploadedIds,a],this._uploadEntry.set(a,t),this.photos=[...this.photos,{id:a,preview:URL.createObjectURL(s)}],this.host.requestUpdate()}d.length>r.length&&(this.errorKey="photos_limit")}catch(s){if(e!==this._session)return;this.errorKey=s instanceof Error&&s.message==="doc_too_large"?"doc_too_large":"doc_upload_failed"}finally{e===this._session&&(this.uploading=!1,this.host.requestUpdate())}}remove(d){let e=this.photos.find(i=>i.id===d);e?.preview&&URL.revokeObjectURL(e.preview),this.photos=this.photos.filter(i=>i.id!==d),this.uploadedIds.includes(d)&&(this.uploadedIds=this.uploadedIds.filter(i=>i!==d),this._discard([d])),this.host.requestUpdate()}discardOrphans(){if(this._endSession(),this.uploadedIds.length===0)return;let d=this.uploadedIds;this.uploadedIds=[],this._discard(d)}markAttached(){this._endSession(),this.uploadedIds=[],this._uploadEntry.clear()}_endSession(){this._session++,this.uploading=!1}_discard(d){let e=new Map;for(let t of d){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)L(i,t,r)}_revokeAll(){for(let d of this.photos)d.preview&&URL.revokeObjectURL(d.preview)}};function T(){if(window.externalApp!==void 0)return!0;let d=typeof navigator<"u"&&navigator.userAgent||"";return/Home Assistant\//.test(d)&&/Android/.test(d)}function D(){if(!T())return!1;let v=typeof navigator<"u"?navigator.mediaDevices:void 0;return!!v&&typeof v.getUserMedia=="function"}var Z=1920,ee=.88,te={retryMs:500,windowMs:5e3},ie=new Set(["NotReadableError","AbortError","TrackStartError"]),M=80,X=/back|rear|environment|rück|hinten/i,B=/front|user|selfie|vorne/i;function K(v){let d=/camera2?\s*(\d+)/i.exec(v);return d?Number(d[1]):Number.MAX_SAFE_INTEGER}function G(v,d){if(d){let i=v.find(t=>t.label===d);if(i)return i}return v.filter(i=>i.label&&X.test(i.label)).sort((i,t)=>K(i.label)-K(t.label))[0]??null}var Y=v=>v?.name||"Error",se=v=>v?.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={...te};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=F(q.cameraLabel),r=await this._enumerate(i);if(!this._live(e))return;let s=G(r,t),a="refused";if(s&&(a=await this._openPatiently(i,e,this._byDevice(s))),a==="cancelled")return;if(a!=="ok"){if(a=await this._openPatiently(i,e,{video:{facingMode:{ideal:"environment"}},what:"facing environment"}),a==="cancelled")return;if(a!=="ok"){this._unavailable(this._lastError||"camera_unavailable");return}if(r=await this._enumerate(i),!this._live(e)){this._stopStream();return}}if(this._devices=r,this._deLine 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,Z/Math.max(i,t)),s=document.createElement("canvas");s.width=Math.round(i*r),s.height=Math.round(t*r);let a=s.getContext("2d");if(!a)throw new Error("no_canvas");a.drawImage(e,0,0,s.width,s.height);let u=await new Promise(g=>s.toBlob(g,"image/jpeg",ee));if(!u)throw new Error("no_blob");let m=new Date().toISOString().replace(/[-:]/g,"").slice(0,15),h=new File([u],`photo-${m}.jpg`,{type:"image/jpeg"});this.close(),this.dispatchEvent(new CustomEvent("photo-captured",{detail:{file:h},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 c`
<div class="overlay" role="dialog" aria-modal="true" aria-label=${n("doc_camera",e)}>
<video autoplay playsinline muted></video>
${this._switching?c`<div class="switching" role="status">${n("camera_switching",e)}</div>`:u}
${this._switching?c`<div class="switching" role="status">${n("camera_switching",e)}</div>`:f}
${this._switchFailed?c`<div class="switch-note" role="status">
<div>${n("camera_not_answered",e)}</div>
<details class="details">
@@ -12,13 +12,13 @@ import{d as U,e as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A
`)}></textarea>
<button type="button" class="copy" @click=${this._copyLog}>${n(this._copied?"camera_copied":"camera_copy",e)}</button>
</details>
</div>`:u}
</div>`:f}
<div class="bar">
<button type="button" class="cancel" @click=${this.close}>${n("cancel",e)}</button>
${this._devices.length>1?c`<button type="button" class="switch" ?disabled=${i} title=${n("camera_switch_lens",e)} aria-label=${n("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>`:u}
</button>`:f}
<button type="button" class="shoot" ?disabled=${i} @click=${this._shoot}>
<ha-icon icon="mdi:camera"></ha-icon><span>${n("camera_capture_shoot",e)}</span>
</button>
@@ -65,7 +65,7 @@ import{d as U,e as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A
.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([p({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 W=x`
`,o([p({type:String})],b.prototype,"lang",2),o([_()],b.prototype,"_open",2),o([_()],b.prototype,"_busy",2),o([_()],b.prototype,"_switching",2),o([_()],b.prototype,"_devices",2),o([_()],b.prototype,"_deviceIndex",2),o([_()],b.prototype,"_switchFailed",2),o([_()],b.prototype,"_copied",2);customElements.get("ms-camera-capture")||customElements.define("ms-camera-capture",b);var W=x`
ms-photo-picker { display: contents; }
.photo-pickers {
display: flex;
@@ -94,59 +94,59 @@ import{d as U,e as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A
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=T();this._inAppCamera=D()}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 u;let e=this.lang,i=this._locked?"disabled":"",t=this.busy?n("uploading",e):n("doc_camera",e),s=n(this._singlePick?"choose_photo":"choose_photos",e);return c`
`,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=T();this._inAppCamera=D()}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?n("uploading",e):n("doc_camera",e),r=n(this._singlePick?"choose_photo":"choose_photos",e);return c`
<div class="photo-pickers">
${this.showCamera?c`<label class="photo-pick photo-pick-camera ${i}" role="button" tabindex="0"
aria-label=${t} title=${this.compact?t:u}
aria-label=${t} title=${this.compact?t:f}
@click=${this._onCameraClick} @keydown=${this._onKeydown}>
<ha-icon icon="mdi:camera"></ha-icon>
${this.compact?u:c`<span>${t}</span>`}
${this.compact?f:c`<span>${t}</span>`}
<input type="file" accept=${this.accept} capture="environment"
?disabled=${this._locked} @change=${this._onInput} />
</label>`:u}
</label>`:f}
${this.showGallery?c`<label class="photo-pick photo-pick-gallery ${i}" role="button" tabindex="0"
aria-label=${s} title=${this.compact?s:u}
aria-label=${r} title=${this.compact?r:f}
@keydown=${this._onKeydown}>
<ha-icon icon="mdi:image-multiple"></ha-icon>
${this.compact?u:c`<span>${s}</span>`}
${this.compact?f:c`<span>${r}</span>`}
<input type="file" accept=${this.accept} ?multiple=${!this._singlePick}
?disabled=${this._locked} @change=${this._onInput} />
</label>`:u}
</label>`:f}
</div>
${this.showGallery&&this._singlePick?c`<div class="photo-android-hint">${n("photos_android_hint",e)}</div>`:u}
${this.showGallery&&this._singlePick?c`<div class="photo-android-hint">${n("photos_android_hint",e)}</div>`:f}
${this.showCamera&&this._inAppCamera?c`<ms-camera-capture .lang=${e}
@photo-captured=${r=>this._emit([r.detail.file])}
@capture-unavailable=${this._onCameraUnavailable}></ms-camera-capture>`:u}
`}};a([p({type:String})],y.prototype,"lang",2),a([p({type:Boolean})],y.prototype,"disabled",2),a([p({type:Boolean})],y.prototype,"busy",2),a([p({type:String})],y.prototype,"accept",2),a([p({type:Boolean})],y.prototype,"showCamera",2),a([p({type:Boolean})],y.prototype,"showGallery",2),a([p({type:Boolean})],y.prototype,"compact",2),a([p({type:Number})],y.prototype,"remaining",2),a([_()],y.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",y);var $=j,l=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 S(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=>[E(i),{...i}])),this._usedQtyText={})}_rangeError(e,i){let t=this.lang;return n("settings_value_out_of_range",t).replace("{min}",I(e,t,{maximumFractionDigits:2})).replace("{max}",I(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};if(this._notes&&(e.notes=this._notes),this._cost){let s=parseFloat(this._cost);!isNaN(s)&&s>=0&&(e.cost=s)}let i=Q(this._duration);if(i!==null&&(e.duration=i),this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photos.photos.length>0&&(e.photo_doc_ids=this._photos.ids),this.viaTagScan&&(e.via_tag_scan=!0),this._completedAt){if(new Date(this._completedAt).getTime()>Date.now()){this._error=n("completed_at_future_error",this.lang);return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let s={};for(let r of this.readings){let o=(this._readingValues[r.id]??"").trim();if(o==="")continue;let h=parseFloat(o.replace(",","."));isNaN(h)||(s[r.id]=h)}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[r,o]of Object.entries(this._usedParts)){let h=this._usedQtyText[r],m=h===void 0?o.quantity:parseFloat(h.replace(",","."));if(!Number.isFinite(m)||m<$[0]||m>$[1]){this._error=this._rangeError(...$);return}s.push({...o,quantity:m})}e.used_parts=s.map(r=>r.entry_id?{part_id:r.part_id,quantity:r.quantity,entry_id:r.entry_id}:{part_id:r.part_id,quantity:r.quantity})}await H(this,e,{busy:s=>{this._loading=s},lang:this.lang,fallbackKey:"save_error",onError:s=>{this._error=s}})!==void 0&&(this._photos.markAttached(),this._open=!1,this.dispatchEvent(new CustomEvent("task-completed")))}_renderReadingField(e,i){let t=this._completedAt?new Date(this._completedAt).getTime():NaN,s=O(this.readingHistory,e.id,isNaN(t)?void 0:t),r=e.unit||this.readingUnit,o=(this._readingValues[e.id]??"").trim(),h=o===""?NaN:parseFloat(o.replace(",",".")),m=s!==void 0&&!isNaN(h)&&h<s.value,f=s!==void 0?I(s.value,i,{maximumFractionDigits:3}):"";return c`
@photo-captured=${s=>this._emit([s.detail.file])}
@capture-unavailable=${this._onCameraUnavailable}></ms-camera-capture>`:f}
`}};o([p({type:String})],y.prototype,"lang",2),o([p({type:Boolean})],y.prototype,"disabled",2),o([p({type:Boolean})],y.prototype,"busy",2),o([p({type:String})],y.prototype,"accept",2),o([p({type:Boolean})],y.prototype,"showCamera",2),o([p({type:Boolean})],y.prototype,"showGallery",2),o([p({type:Boolean})],y.prototype,"compact",2),o([p({type:Number})],y.prototype,"remaining",2),o([_()],y.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",y);var $=j,l=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 S(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=>[E(i),{...i}])),this._usedQtyText={})}_rangeError(e,i){let t=this.lang;return n("settings_value_out_of_range",t).replace("{min}",I(e,t,{maximumFractionDigits:2})).replace("{max}",I(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=Q(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(new Date(this._completedAt).getTime()>Date.now()){this._error=n("completed_at_future_error",this.lang);return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let s={};for(let a of this.readings){let u=(this._readingValues[a.id]??"").trim();if(u==="")continue;let m=parseFloat(u.replace(",","."));isNaN(m)||(s[a.id]=m)}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[a,u]of Object.entries(this._usedParts)){let m=this._usedQtyText[a],h=m===void 0?u.quantity:parseFloat(m.replace(",","."));if(!Number.isFinite(h)||h<$[0]||h>$[1]){this._error=this._rangeError(...$);return}s.push({...u,quantity:h})}e.used_parts=s.map(a=>a.entry_id?{part_id:a.part_id,quantity:a.quantity,entry_id:a.entry_id}:{part_id:a.part_id,quantity:a.quantity})}await U(this,e,{busy:s=>{this._loading=s},lang:this.lang,fallbackKey:"save_error",onError:s=>{this._error=s}})!==void 0&&(this._photos.markAttached(),this._open=!1,this.dispatchEvent(new CustomEvent("task-completed")))}_renderReadingField(e,i){let t=this._completedAt?new Date(this._completedAt).getTime():NaN,r=O(this.readingHistory,e.id,isNaN(t)?void 0:t),s=e.unit||this.readingUnit,a=(this._readingValues[e.id]??"").trim(),u=a===""?NaN:parseFloat(a.replace(",",".")),m=r!==void 0&&!isNaN(u)&&u<r.value,h=r!==void 0?I(r.value,i,{maximumFractionDigits:3}):"";return c`
<label class="field reading-field">
<span class="field-label">${e.name}${r?` (${r})`:""}</span>
<span class="field-label">${e.name}${s?` (${s})`:""}</span>
<input type="text" inputmode="decimal" class="field-input"
placeholder=${s!==void 0?n("reading_last",i).replace("{value}",f):""}
placeholder=${r!==void 0?n("reading_last",i).replace("{value}",h):""}
.value=${this._readingValues[e.id]??""}
@input=${v=>{this._readingValues={...this._readingValues,[e.id]:v.target.value}}} />
${m?c`<span class="reading-warn">${n("reading_below_last",i).replace("{value}",f)}</span>`:u}
</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])}_req(e){return this.requiredFields.includes(e)?c`<span class="req-mark" aria-hidden="true">*</span>`:u}_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 s=this.parts.find(o=>E({part_id:o.id,entry_id:o.entry_id})===E(t)),r=C(s);r!==null&&(e+=r*(t.quantity||1),i=!0)}return i?Math.round(e*100)/100:null}_renderCostSuggestion(e){let i=this._purchaseSuggestion();if(this.restockDefault!==null){let o=this.partsCostMode==="use"?c`<div class="cost-note">${n("cost_purchase_use_hint",e)}</div>`:u;if(this._cost.trim()!==""||i==null||i<=0)return o;let h=A(i,this.currencySymbol,e);return c`<button
@input=${g=>{this._readingValues={...this._readingValues,[e.id]:g.target.value}}} />
${m?c`<span class="reading-warn">${n("reading_below_last",i).replace("{value}",h)}</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)?c`<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(a=>E({part_id:a.id,entry_id:a.entry_id})===E(t)),s=C(r);s!==null&&(e+=s*(t.quantity||1),i=!0)}return i?Math.round(e*100)/100:null}_renderCostSuggestion(e){let i=this._purchaseSuggestion();if(this.restockDefault!==null){let a=this.partsCostMode==="use"?c`<div class="cost-note">${n("cost_purchase_use_hint",e)}</div>`:f;if(this._cost.trim()!==""||i==null||i<=0)return a;let u=A(i,this.currencySymbol,e);return c`<button
type="button"
class="cost-suggestion"
@click=${()=>this._cost=String(Math.round(i*100)/100)}
>${n("cost_from_parts",e).replace("{amount}",h)}</button>${o}`}let t=this._partsValue();if(t==null||t<=0)return u;let s=A(t,this.currencySymbol,e),r=this.partsCostMode==="use"?"cost_parts_booked":"cost_parts_info";return c`<div class="cost-note">${n(r,e).replace("{amount}",s)}</div>`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=z(new Date)}render(){if(!this._open)return c``;let e=this.lang||this.hass?.language||"en",i=this._error||this._photos.errorText(e);return c`
>${n("cost_from_parts",e).replace("{amount}",u)}</button>${a}`}let t=this._partsValue();if(t==null||t<=0)return f;let r=A(t,this.currencySymbol,e),s=this.partsCostMode==="use"?"cost_parts_booked":"cost_parts_info";return c`<div class="cost-note">${n(s,e).replace("{amount}",r)}</div>`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=z(new Date)}render(){if(!this._open)return c``;let e=this.lang||this.hass?.language||"en",i=this._error||this._photos.errorText(e);return c`
<ha-dialog open @closed=${this._close}>
<div class="dialog-title">${n("complete_title",e)}${this.taskName}</div>
${this.phaseLabel?c`<div class="phase-line">${n("phase_current",e)}: ${this.phaseLabel}</div>`:u}
${this.requireTagScan&&!this.viaTagScan?c`<div class="scan-required-note">${n("require_tag_scan_hint",e)}</div>`:u}
${this.phaseLabel?c`<div class="phase-line">${n("phase_current",e)}: ${this.phaseLabel}</div>`:f}
${this.requireTagScan&&!this.viaTagScan?c`<div class="scan-required-note">${n("require_tag_scan_hint",e)}</div>`:f}
<div class="content">
${i?c`<div class="error">${i}</div>`:u}
${i?c`<div class="error">${i}</div>`:f}
${this.checklist.length>0?c`
<div class="checklist-section">
<label class="checklist-label">${n("checklist",e)}</label>
${this.checklist.map((t,s)=>c`
<label class="checklist-item" @click=${()=>this._toggleCheck(s)}>
<input type="checkbox" .checked=${!!this._checklistState[String(s)]} />
${this.checklist.map((t,r)=>c`
<label class="checklist-item" @click=${()=>this._toggleCheck(r)}>
<input type="checkbox" .checked=${!!this._checklistState[String(r)]} />
<span>${t}</span>
</label>
`)}
</div>
`:u}
`:f}
${this.readings.length>0?c`<div class="readings-block">
<span class="field-label">${n("readings_section",e)}</span>
${this.readings.map(t=>this._renderReadingField(t,e))}
@@ -156,31 +156,31 @@ import{d as U,e as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A
<input type="number" step="any" class="field-input"
.value=${this._readingValue}
@input=${t=>this._readingValue=t.target.value} />
</label>`:u}
</label>`:f}
${this.parts.length?c`<div class="used-parts">
<span class="field-label">${n("complete_parts_used",e)}</span>
${this.parts.map(t=>{let s=E({part_id:t.id,entry_id:t.entry_id}),r=this._usedParts[s],o=r!==void 0,h=t.entry_id?{part_id:t.id,quantity:1,entry_id:t.entry_id}:{part_id:t.id,quantity:1};return c`<div class="used-part-row">
${this.parts.map(t=>{let r=E({part_id:t.id,entry_id:t.entry_id}),s=this._usedParts[r],a=s!==void 0,u=t.entry_id?{part_id:t.id,quantity:1,entry_id:t.entry_id}:{part_id:t.id,quantity:1};return c`<div class="used-part-row">
<label class="used-part-check">
<input type="checkbox" .checked=${o}
@change=${m=>{let f={...this._usedParts};if(m.target.checked)f[s]=f[s]||h;else{delete f[s];let v={...this._usedQtyText};delete v[s],this._usedQtyText=v}this._usedParts=f}} />
<input type="checkbox" .checked=${a}
@change=${m=>{let h={...this._usedParts};if(m.target.checked)h[r]=h[r]||u;else{delete h[r];let g={...this._usedQtyText};delete g[r],this._usedQtyText=g}this._usedParts=h}} />
<span
>${t.name}${t.owner_name?c`<span class="used-part-owner"> (${t.owner_name})</span>`:u}${t.stock!==null&&t.stock!==void 0?` (${R(t.stock,t.unit,e)})`:""}</span
>${t.name}${t.owner_name?c`<span class="used-part-owner"> (${t.owner_name})</span>`:f}${t.stock!==null&&t.stock!==void 0?` (${R(t.stock,t.unit,e)})`:""}</span
>
</label>
${o?c`<input class="used-part-qty" type="number" min=${$[0]} max=${$[1]} step="0.01"
.value=${this._usedQtyText[s]??String(r.quantity)}
@input=${m=>{let f=m.target.value;this._usedQtyText={...this._usedQtyText,[s]:f};let v=parseFloat(f.replace(",","."));Number.isFinite(v)&&v>=$[0]&&(this._usedParts={...this._usedParts,[s]:{...h,quantity:v}})}} />`:u}
${a?c`<input class="used-part-qty" type="number" min=${$[0]} max=${$[1]} step="0.01"
.value=${this._usedQtyText[r]??String(s.quantity)}
@input=${m=>{let h=m.target.value;this._usedQtyText={...this._usedQtyText,[r]:h};let g=parseFloat(h.replace(",","."));Number.isFinite(g)&&g>=$[0]&&(this._usedParts={...this._usedParts,[r]:{...u,quantity:g}})}} />`:f}
</div>`})}
</div>`:this.consumesInfo.length?c`<div class="consumes-hint">
${this.consumesInfo.map(t=>c`<div>${t}</div>`)}
</div>`:u}
</div>`:f}
${this.restockDefault!==null?c`
<label class="field">
<span class="field-label">${n("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>`:u}
</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
@@ -188,20 +188,22 @@ import{d as U,e as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A
only sees the title + Cancel/Complete buttons — the original
bug report. Native inputs always render. -->
<label class="field">
<span class="field-label">${n("notes_optional",e)}${this._req("notes")}</span>
<input type="text" class="field-input"
<span class="field-label">${this._demands("notes")?n("notes_label",e):n("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} />
@input=${t=>this._notes=t.target.value}></textarea>
</label>
<label class="field">
<span class="field-label">${n("cost_optional",e)}${this._req("cost")}</span>
<input type="number" step="0.01" min="0" class="field-input"
.value=${this._cost}
@input=${t=>this._cost=t.target.value} />
<div class="field">
<span class="field-label">${this._demands("cost")?n("cost",e):n("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)}
</label>
</div>
<label class="field">
<span class="field-label">${n("duration_minutes",e)}${this._req("duration")}</span>
<span class="field-label">${this._demands("duration")?n("quick_complete_defaults_duration",e):n("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} />
@@ -220,7 +222,7 @@ import{d as U,e as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A
</button>`}
</div>
<div class="field">
<span class="field-label">${n("completion_photos_optional",e)}${this._req("photo")}</span>
<span class="field-label">${this._demands("photo")?n("completion_photos",e):n("completion_photos_optional",e)}${this._req("photo")}</span>
${this._photos.photos.length>0?c`<div class="photo-strip">
${this._photos.photos.map(t=>c`
<div class="photo-preview">
@@ -228,7 +230,7 @@ import{d as U,e as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A
<button type="button" class="photo-remove" @click=${()=>this._photos.remove(t.id)}
title="${n("remove",e)}">✕</button>
</div>`)}
</div>`:u}
</div>`:f}
${this._photos.full?c`<div class="photo-limit">${n("photos_limit",e).replace("{max}",String(this._photos.max))}</div>`:c`<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>`}
@@ -251,7 +253,7 @@ import{d as U,e as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A
>${n("feedback_not_sure",e)}</button>
</div>
</div>
`:u}
`:f}
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._close}>
@@ -272,6 +274,7 @@ import{d as U,e as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A
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;
@@ -481,4 +484,4 @@ import{d as U,e as q}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A
color: var(--text-primary-color, #fff);
border-color: var(--primary-color);
}
`],a([p({attribute:!1})],l.prototype,"hass",2),a([p()],l.prototype,"entryId",2),a([p()],l.prototype,"taskId",2),a([p()],l.prototype,"taskName",2),a([p()],l.prototype,"lang",2),a([p({type:Array})],l.prototype,"checklist",2),a([p({type:Boolean})],l.prototype,"adaptiveEnabled",2),a([p()],l.prototype,"taskType",2),a([p()],l.prototype,"readingUnit",2),a([p({attribute:!1})],l.prototype,"readings",2),a([p({attribute:!1})],l.prototype,"readingHistory",2),a([p({attribute:!1})],l.prototype,"restockDefault",2),a([p({attribute:!1})],l.prototype,"restockUnitCost",2),a([p({attribute:!1})],l.prototype,"restockPackage",2),a([p()],l.prototype,"currencySymbol",2),a([p({attribute:!1})],l.prototype,"partsCostMode",2),a([p({attribute:!1})],l.prototype,"parts",2),a([p({attribute:!1})],l.prototype,"consumesParts",2),a([p({type:Array})],l.prototype,"consumesInfo",2),a([p({type:Array})],l.prototype,"requiredFields",2),a([p()],l.prototype,"phaseLabel",2),a([p({type:Boolean})],l.prototype,"requireTagScan",2),a([p({type:Boolean})],l.prototype,"viaTagScan",2),a([_()],l.prototype,"_open",2),a([_()],l.prototype,"_notes",2),a([_()],l.prototype,"_cost",2),a([_()],l.prototype,"_duration",2),a([_()],l.prototype,"_loading",2),a([_()],l.prototype,"_error",2),a([_()],l.prototype,"_checklistState",2),a([_()],l.prototype,"_feedback",2),a([_()],l.prototype,"_readingValue",2),a([_()],l.prototype,"_readingValues",2),a([_()],l.prototype,"_restockQty",2),a([_()],l.prototype,"_completedAt",2),a([_()],l.prototype,"_usedParts",2),a([_()],l.prototype,"_usedQtyText",2),a([p({attribute:!1})],l.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",l);export{T as a,W as b,S as c,l as d};
`],o([p({attribute:!1})],l.prototype,"hass",2),o([p()],l.prototype,"entryId",2),o([p()],l.prototype,"taskId",2),o([p()],l.prototype,"taskName",2),o([p()],l.prototype,"lang",2),o([p({type:Array})],l.prototype,"checklist",2),o([p({type:Boolean})],l.prototype,"adaptiveEnabled",2),o([p()],l.prototype,"taskType",2),o([p()],l.prototype,"readingUnit",2),o([p({attribute:!1})],l.prototype,"readings",2),o([p({attribute:!1})],l.prototype,"readingHistory",2),o([p({attribute:!1})],l.prototype,"restockDefault",2),o([p({attribute:!1})],l.prototype,"restockUnitCost",2),o([p({attribute:!1})],l.prototype,"restockPackage",2),o([p()],l.prototype,"currencySymbol",2),o([p({attribute:!1})],l.prototype,"partsCostMode",2),o([p({attribute:!1})],l.prototype,"parts",2),o([p({attribute:!1})],l.prototype,"consumesParts",2),o([p({type:Array})],l.prototype,"consumesInfo",2),o([p({type:Array})],l.prototype,"requiredFields",2),o([p()],l.prototype,"phaseLabel",2),o([p({type:Boolean})],l.prototype,"requireTagScan",2),o([p({type:Boolean})],l.prototype,"viaTagScan",2),o([_()],l.prototype,"_open",2),o([_()],l.prototype,"_notes",2),o([_()],l.prototype,"_cost",2),o([_()],l.prototype,"_duration",2),o([_()],l.prototype,"_loading",2),o([_()],l.prototype,"_error",2),o([_()],l.prototype,"_checklistState",2),o([_()],l.prototype,"_feedback",2),o([_()],l.prototype,"_readingValue",2),o([_()],l.prototype,"_readingValues",2),o([_()],l.prototype,"_restockQty",2),o([_()],l.prototype,"_completedAt",2),o([_()],l.prototype,"_usedParts",2),o([_()],l.prototype,"_usedQtyText",2),o([p({attribute:!1})],l.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",l);export{T as a,W as b,S as c,l as d};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.94.0 */
import{p as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-JE577H3E.js";var E={days:1,weeks:7,months:30.4368,years:365.25};function w(e,n){return!e||e<=0?0:e*(E[n||"days"]??1)}function R(e,n,s){let t=w(e,s);if(t<=0||n==null)return{pct:0,overflow:!1};let o=(t-n)/t*100;return{pct:Math.max(0,Math.min(100,o)),overflow:o>100}}var S=5;function b(e){let n=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),t=String(e.getDate()).padStart(2,"0");return`${n}-${s}-${t}`}function U(e){let n=String(e.getHours()).padStart(2,"0"),s=String(e.getMinutes()).padStart(2,"0");return`${b(e)}T${n}:${s}:00`}function P(e,n){let s=[];for(let t=0;t<n;t++){let o=new Date(e);o.setDate(o.getDate()+t),o.setHours(0,0,0,0),s.push(b(o))}return s}function h(e,n){let[s,t,o]=e.split("-").map(Number),c=new Date(s,t-1,o);return c.setDate(c.getDate()+n),b(c)}function A(e){if(!e||e.length===0)return null;let n=e.map(s=>s.cost).filter(s=>typeof s=="number");return n.length===0?null:n.reduce((s,t)=>s+t,0)/n.length}function C(e){let{windowStart:n,windowEnd:s,task:t,entryId:o,objectName:c}=e,u=[],_=(i,a)=>({date:i,entry_id:o,task_id:t.id,task_name:t.name,object_name:c,status:a&&(t.status==="overdue"||t.status==="triggered")?"ok":t.status,days_until_due:a?null:t.days_until_due??null,projected:a,schedule_type:t.schedule_type,interval_days:t.interval_days??null,interval_unit:t.interval_unit??null,responsible_user_id:t.responsible_user_id??null,avg_cost:A(t.history),adaptive_enabled:!!t.adaptive_config?.enabled,prediction_confidence:t.threshold_prediction_confidence??null}),l=Math.max(1,Math.round(w(t.interval_days,t.interval_unit)));if(t.status==="overdue"||t.status==="triggered"){if(u.push(_(n,!1)),t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let i=h(n,l),a=1;for(;i<=s&&a<S;)u.push(_(i,!0)),a++,i=h(i,l)}return u}let d=t.next_due;if(typeof d!="string"||!d)return u;let r=d.slice(0,10);if(r>=n&&r<=s)u.push(_(r,!1));else if(r>s)return u;if(t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let i=h(r,l),a=u.length;for(;i<=s&&a<S;)i>=n&&(u.push(_(i,!0)),a++),i=h(i,l)}return u}function Y(e,n,s,t=null){let o=P(n,s),c=o[0],u=o[o.length-1],_=[];for(let d of e){let r=d.object?.name||"",i=d.entry_id,a=d.tasks||[];for(let g of a){if(t&&g.responsible_user_id!==t||g.enabled===!1)continue;let p=C({windowStart:c,windowEnd:u,task:g,entryId:i,objectName:r});_.push(...p)}}let l=new Map;for(let d of o)l.set(d,[]);for(let d of _){let r=l.get(d.date);r&&r.push(d)}for(let[,d]of l)d.sort((r,i)=>{let a=k(r.status),g=k(i.status);if(a!==g)return a-g;if(r.projected!==i.projected)return r.projected?1:-1;let p=r.object_name.localeCompare(i.object_name);return p!==0?p:r.task_name.localeCompare(i.task_name)});return o.map(d=>({date:d,events:l.get(d)??[]}))}var T={completed:"ok",reset:"ok",skipped:"due_soon",missed:"overdue",triggered:"triggered",trigger_replaced:"triggered",trigger_removed:"ok"};function j(e,n){return`${e}/${n}`}function L(e,n,s){let t=x(n,s)[0],o=[];for(let c of e)for(let u of c.tasks||[]){let _=u.history||[],l=u.history_count??_.length;if(l<=_.length)continue;let d=_.map(a=>typeof a?.timestamp=="string"?a.timestamp:"").filter(Boolean),r=d.length?d.reduce((a,g)=>a<g?a:g).slice(0,10):"";if(r&&r<t)continue;let i=j(c.entry_id,u.id);o.push({entryId:c.entry_id,taskId:u.id,key:i,sig:`${i}:${l}:${M(JSON.stringify(_))}`})}return o}function M(e){let n=2166136261;for(let s=0;s<e.length;s++)n^=e.charCodeAt(s),n=Math.imul(n,16777619);return(n>>>0).toString(36)}function x(e,n){let s=[];for(let t=n-1;t>=0;t--){let o=new Date(e);o.setDate(o.getDate()-t),o.setHours(0,0,0,0),s.push(b(o))}return s}function X(e,n,s,t=null,o={}){let c=x(n,s),u=c[0],_=c[c.length-1],l=new Map;for(let r of c)l.set(r,[]);for(let r of e){let i=r.object?.name||"",a=r.entry_id,g=r.tasks||[];for(let p of g){if(t&&p.responsible_user_id!==t)continue;let m=o[j(a,p.id)]??(p.history||[]);for(let f of m){if(typeof f?.timestamp!="string")continue;let y=f.timestamp.slice(0,10);if(y<u||y>_)continue;let v=l.get(y);if(!v)continue;let D=f.type??"completed";v.push({date:y,entry_id:a,task_id:p.id,task_name:p.name,object_name:i,status:T[D]??"ok",days_until_due:null,projected:!1,schedule_type:p.schedule_type,interval_days:p.interval_days??null,responsible_user_id:p.responsible_user_id??null,avg_cost:typeof f.cost=="number"?f.cost:null,adaptive_enabled:!!p.adaptive_config?.enabled,prediction_confidence:null,history_timestamp:f.timestamp,history_type:D,history_cost:typeof f.cost=="number"?f.cost:null,history_notes:typeof f.notes=="string"?f.notes:null,history_duration:typeof f.duration=="number"?f.duration:null})}}}let d={completed:0,reset:1,skipped:2,triggered:3,trigger_replaced:4};for(let[,r]of l)r.sort((i,a)=>{let g=d[i.history_type??""]??99,p=d[a.history_type??""]??99;if(g!==p)return g-p;let m=i.object_name.localeCompare(a.object_name);return m!==0?m:i.task_name.localeCompare(a.task_name)});return c.map(r=>({date:r,events:l.get(r)??[]}))}function K(e){if(!e)return[];lLine truncated
File diff suppressed because it is too large. Load diff
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.95.0 */
import{p as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4XNVTWGC.js";var C={days:1,weeks:7,months:30.4368,years:365.25};function v(e,n){return!e||e<=0?0:e*(C[n||"days"]??1)}function O(e,n,s){let t=v(e,s);if(t<=0||n==null)return{pct:0,overflow:!1};let r=(t-n)/t*100;return{pct:Math.max(0,Math.min(100,r)),overflow:r>100}}var D=5;function b(e){let n=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),t=String(e.getDate()).padStart(2,"0");return`${n}-${s}-${t}`}function B(e){let n=String(e.getHours()).padStart(2,"0"),s=String(e.getMinutes()).padStart(2,"0");return`${b(e)}T${n}:${s}:00`}function x(e,n){let s=[];for(let t=0;t<n;t++){let r=new Date(e);r.setDate(r.getDate()+t),r.setHours(0,0,0,0),s.push(b(r))}return s}function h(e,n){let[s,t,r]=e.split("-").map(Number),l=new Date(s,t-1,r);return l.setDate(l.getDate()+n),b(l)}function M(e){if(!e||e.length===0)return null;let n=e.map(s=>s.cost).filter(s=>typeof s=="number");return n.length===0?null:n.reduce((s,t)=>s+t,0)/n.length}function I(e){let{windowStart:n,windowEnd:s,task:t,entryId:r,objectName:l}=e,c=[],g=(i,a)=>({date:i,entry_id:r,task_id:t.id,task_name:t.name,object_name:l,status:a&&(t.status==="overdue"||t.status==="triggered")?"ok":t.status,days_until_due:a?null:t.days_until_due??null,projected:a,schedule_type:t.schedule_type,interval_days:t.interval_days??null,interval_unit:t.interval_unit??null,responsible_user_id:t.responsible_user_id??null,avg_cost:M(t.history),adaptive_enabled:!!t.adaptive_config?.enabled,prediction_confidence:t.threshold_prediction_confidence??null}),d=Math.max(1,Math.round(v(t.interval_days,t.interval_unit)));if(t.status==="overdue"||t.status==="triggered"){if(c.push(g(n,!1)),t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let i=h(n,d),a=1;for(;i<=s&&a<D;)c.push(g(i,!0)),a++,i=h(i,d)}return c}let u=t.next_due;if(typeof u!="string"||!u)return c;let o=u.slice(0,10);if(o>=n&&o<=s)c.push(g(o,!1));else if(o>s)return c;if(t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let i=h(o,d),a=c.length;for(;i<=s&&a<D;)i>=n&&(c.push(g(i,!0)),a++),i=h(i,d)}return c}function N(e,n,s,t=null){let r=x(n,s),l=r[0],c=r[r.length-1],g=[];for(let u of e){let o=u.object?.name||"",i=u.entry_id,a=u.tasks||[];for(let _ of a){if(t&&_.responsible_user_id!==t||_.enabled===!1)continue;let p=I({windowStart:l,windowEnd:c,task:_,entryId:i,objectName:o});g.push(...p)}}let d=new Map;for(let u of r)d.set(u,[]);for(let u of g){let o=d.get(u.date);o&&o.push(u)}for(let[,u]of d)u.sort((o,i)=>{let a=k(o.status),_=k(i.status);if(a!==_)return a-_;if(o.projected!==i.projected)return o.projected?1:-1;let p=o.object_name.localeCompare(i.object_name);return p!==0?p:o.task_name.localeCompare(i.task_name)});return r.map(u=>({date:u,events:d.get(u)??[]}))}var P={completed:"ok",reset:"ok",skipped:"due_soon",missed:"overdue",triggered:"triggered",trigger_replaced:"triggered",trigger_removed:"ok"};function j(e,n){return`${e}/${n}`}function $(e,n,s){let t=E(n,s)[0],r=[];for(let l of e)for(let c of l.tasks||[]){let g=c.history||[],d=c.history_count??g.length;if(d<=g.length)continue;let u=g.map(a=>typeof a?.timestamp=="string"?a.timestamp:"").filter(Boolean),o=u.length?u.reduce((a,_)=>a<_?a:_).slice(0,10):"";if(o&&o<t)continue;let i=j(l.entry_id,c.id);r.push({entryId:l.entry_id,taskId:c.id,key:i,sig:`${i}:${d}:${A(JSON.stringify(g))}`})}return r}function A(e){let n=2166136261;for(let s=0;s<e.length;s++)n^=e.charCodeAt(s),n=Math.imul(n,16777619);return(n>>>0).toString(36)}function E(e,n){let s=[];for(let t=n-1;t>=0;t--){let r=new Date(e);r.setDate(r.getDate()-t),r.setHours(0,0,0,0),s.push(b(r))}return s}function Y(e,n,s,t=null,r={}){let l=E(n,s),c=l[0],g=l[l.length-1],d=new Map;for(let o of l)d.set(o,[]);for(let o of e){let i=o.object?.name||"",a=o.entry_id,_=o.tasks||[];for(let p of _){if(t&&p.responsible_user_id!==t)continue;let y=r[j(a,p.id)]??(p.history||[]);for(let f of y){if(typeof f?.timestamp!="string")continue;let m=f.timestamp.slice(0,10);if(m<c||m>g)continue;let w=d.get(m);if(!w)continue;let S=f.type??"completed";w.push({date:m,entry_id:a,task_id:p.id,task_name:p.name,object_name:i,status:P[S]??"ok",days_until_due:null,projected:!1,schedule_type:p.schedule_type,interval_days:p.interval_days??null,responsible_user_id:p.responsible_user_id??null,avg_cost:typeof f.cost=="number"?f.cost:null,adaptive_enabled:!!p.adaptive_config?.enabled,prediction_confidence:null,history_timestamp:f.timestamp,history_type:S,history_cost:typeof f.cost=="number"?f.cost:null,history_notes:typeof f.notes=="string"?f.notes:null,history_duration:typeof f.duration=="number"?f.duration:null})}}}let u={completed:0,reset:1,skipped:2,triggered:3,trigger_replaced:4};for(let[,o]of d)o.sort((i,a)=>{let _=u[i.history_type??""]??99,p=u[a.history_type??""]??99;if(_!==p)return _-p;let y=i.object_name.localeCompare(a.object_name);return y!==0?y:i.task_name.localeCompare(a.task_name)});return l.map(o=>({date:o,events:d.get(o)??[]}))}function L(e){if(!e)return[];lLine truncated
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.94.0 */
import{s as o,u as c}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-JE577H3E.js";var f={already_archived:"ws_err_already_archived",already_paused:"ws_err_already_paused",archived:"ws_err_archived",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",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"},p={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 w(r){let t=r.replace(/_ids?$/,"").split("_").filter(Boolean);if(t.length===0)return r;let e=t.join(" ");return e.charAt(0).toUpperCase()+e.slice(1)}function m(r,t){let e=p[r];if(e){let n=o(e,t);if(n&&n!==e)return n}return w(r)}function h(r){let t=[...r.matchAll(/\['([^']+)'\]/g)].map(i=>i[1]),e=t.length?t[t.length-1]:void 0,n;return(n=r.match(/length of value must be at most (\d+)/))?{field:e,rule:"too_long",param:n[1]}:(n=r.match(/length of value must be at least (\d+)/))?{field:e,rule:"too_short",param:n[1]}:(n=r.match(/value must be at most (\S+)/))?{field:e,rule:"value_too_high",param:n[1]}:(n=r.match(/value must be at least (\S+)/))?{field:e,rule:"value_too_low",param:n[1]}:/required key not provided/.test(r)?{field:e,rule:"required"}:(n=r.match(/expected (\w+)/))?{field:e,rule:"wrong_type",param:n[1]}:/value must be one of/.test(r)?{field:e,rule:"invalid_choice"}:/not a valid value/.test(r)?{field:e,rule:"invalid_value"}:{field:e,rule:"unknown"}}var g=r=>r.toLowerCase().split(/[^a-z0-9]+/).filter(t=>t.length>1);function y(r,t){let e=new Set(g(t));return g(r).every(n=>e.has(n))}function v(r,t,e){if(e=e??o("action_error",t),typeof r=="string")return r;if(typeof r!="object"||r===null)return e;let n=r,i=n.message||n.error?.message||"",_=n.code||n.error?.code||"",s=_?f[_]:void 0;if(!i&&!s)return e;let l=h(i),d=l.field?m(l.field,t):"",a=u=>o(u,t).replace("{field}",d).replace("{n}",l.param??"");switch(l.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}",l.param??"");case"invalid_choice":return a("err_invalid_choice");case"invalid_value":return a("err_invalid_value");default:if(s){let u=o(s,t);return i&&!y(i,_)?`${u} (${i})`:u}return i||e}}async function b(r,t,e={}){e.busy?.(!0);try{let n=typeof t=="function"?await t():await r.hass.connection.sendMessagePromise(t);return e.reload&&await e.reload(),e.successToast&&e.onSuccess?.(e.successToast),n===void 0?null:n}catch(n){let i=e.lang||c(r.hass);e.onError?.(v(n,i,e.fallbackKey?o(e.fallbackKey,i):void 0),n);return}finally{e.busy?.(!1)}}asynLine truncated
@@ -1,969 +0,0 @@
/*! maintenance_supporter frontend 2.94.0 */
import{b as St,g as it,h as q,k as M,l as Ct,m as Nt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-P3JMRZOA.js";import{e as Dt,f as jt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-FR6WMAD6.js";import{b as Rt,h as nt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-IRVVKPDP.js";import{b as Ht,c as Pt,e as et,f as It,h as Mt,k as Ot}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-ZA53FZUW.js";import{i as dt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-63C4ZGBD.js";import{a as I}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-K4SNNHPR.js";import{A as X,C as $t,D as G,E as kt,G as wt,H as tt,M as lt,N as Tt,O as Et,P as At,R as Lt,a as p,b as $,c as o,d as N,f as c,h as L,l as w,m,n as gt,q as Q,r as U,s as r,u as T,v as yt,w as vt,x as bt,y as xt,z as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-JE577H3E.js";var z=$`
.backdrop {
position: fixed; inset: 0; z-index: 100;
background: rgba(0,0,0,0.5);
}
.dialog {
position: fixed; left: 50%; top: 50%;
transform: translate(-50%, -50%);
width: 95vw; max-width: var(--ms-modal-max-width, 480px);
max-height: var(--ms-modal-max-height, 92vh); overflow: auto;
background: var(--card-background-color, var(--ha-card-background, #1c1c1c));
color: var(--primary-text-color);
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
padding: 20px;
display: flex; flex-direction: column; gap: var(--ms-modal-gap, 14px);
z-index: 101;
}
/* Focused programmatically on open (so Escape works at once) — no ring. */
.dialog:focus { outline: none; }
`;function fe(e,i){e.key!=="Escape"||e.defaultPrevented||e.composedPath().some(t=>t instanceof Element&&t.localName==="ms-camera-capture")||(e.preventDefault(),e.stopPropagation(),i())}function F(e,i){return o`
<div class="backdrop" @click=${e}></div>
<div class="dialog" role="dialog" aria-modal="true" tabindex="-1"
@keydown=${t=>fe(t,e)}>${i}</div>
`}function W(e){e?.querySelector(".dialog")?.focus({preventScroll:!0})}var v=class extends L{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(t){return this._title=t.title,this._message=t.message,this._confirmText=t.confirmText||"OK",this._danger=t.danger||!1,this._inputLabel="",this._inputType="",this._options=null,this._inputValue="",this._open=!0,new Promise(n=>{this._resolve=n,this._promptResolve=null})}prompt(t){return this._title=t.title,this._message=t.message,this._confirmText=t.confirmText||"OK",this._danger=t.danger||!1,this._inputLabel=t.inputLabel||"",this._inputType=t.inputType||"text",this._options=t.options&&t.options.length?t.options:null,this._inputValue=t.inputValue||"",this._open=!0,new Promise(n=>{this._promptResolve=n,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 c;let t=T(this.hass);return o`
<ha-dialog open @closed=${this._cancel}>
<div class="dialog-title">${this._title}</div>
<div class="content">
${this._message}
${this._inputLabel?o`
<!-- 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?o`<select class="field-input field-select"
@change=${n=>this._inputValue=n.target.value}>
${this._options.map(n=>o`<option value=${n.value} ?selected=${n.value===this._inputValue}>${n.label}</option>`)}
</select>`:o`<input class="field-input"
type="${this._inputType||"text"}"
.value=${this._inputValue}
@input=${n=>this._inputValue=n.target.value} />`}
</label>
`:c}
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._cancel}>
${r("cancel",t)}
</ha-button>
<ha-button
class="${this._danger?"danger":""}"
@click=${this._confirmAction}
>
${this._confirmText}
</ha-button>
</div>
</ha-dialog>
`}};v.styles=[At,$`
.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);
}
`],p([w({attribute:!1})],v.prototype,"hass",2),p([m()],v.prototype,"_open",2),p([m()],v.prototype,"_title",2),p([m()],v.prototype,"_message",2),p([m()],v.prototype,"_confirmText",2),p([m()],v.prototype,"_danger",2),p([m()],v.prototype,"_inputLabel",2),p([m()],v.prototype,"_inputType",2),p([m()],v.prototype,"_options",2),p([m()],v.prototype,"_inputValue",2);customElements.get("maintenance-confirm-dialog")||customElements.define("maintenance-confirm-dialog",v);var qt="maintenance-confirm-dialog",zt="data-ms-lovelace-confirm";function ge(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function O(e,i){let t=ge(),n=t.querySelector(`${qt}[${zt}]`);return n||(n=document.createElement(qt),n.setAttribute(zt,""),t.appendChild(n)),n.hass=e,n.confirm(i)}var D=class extends L{constructor(){super(...arguments);this.docId="";this._url="";this._failed=!1;this._signedFor=""}updated(){this.hass&&this.docId&&this._signedFor!==this.docId&&(this._signedFor=this.docId,this._url="",this._failed=!1,this._sign())}async _sign(){try{this._url=await St(this.hass,this.docId)}catch{this._failed=!0}}render(){return this._failed||!this.docId?c:this._url?o`
<a href=${this._url} target="_blank" rel="noopener" class="wrap">
<img src=${this._url} alt="" loading="lazy"
@error=${()=>this._failed=!0} />
</a>`:o`<div class="ph"></div>`}};D.styles=$`
.wrap { display: inline-block; margin-top: 4px; }
/* #161: uniform 96px tiles — several photos sit in a strip, so a
tiny or portrait shot must not collapse its slot. */
img {
width: 96px;
height: 96px;
object-fit: cover;
border-radius: 6px;
display: block;
border: 1px solid var(--divider-color);
box-sizing: border-box;
}
.ph {
width: 96px;
height: 96px;
border-radius: 6px;
background: var(--secondary-background-color, rgba(0,0,0,0.06));
margin-top: 4px;
}
`,p([w({attribute:!1})],D.prototype,"hass",2),p([w()],D.prototype,"docId",2),p([m()],D.prototype,"_url",2),p([m()],D.prototype,"_failed",2);customElements.get("maintenance-history-photo")||customElements.define("maintenance-history-photo",D);var b=class extends L{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null;this._partOptions=null;this._partQty={};this._partQtyOriginal="";this._openGen=0;this._photos=new jt(this,{entryId:()=>this._draft?.entry_id??"",hass:()=>this.hass});this._photosOriginal="";this._readingRows=[];this._readingText={};this._readingsOriginal=""}get _lang(){return T(this.hass)}openEdit(t){this._openGen++,this._draft={...t},this._originalSnapshot={...t},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._photos.reset(t.photo_doc_ids??[]),this._photosOriginal=JSON.stringify(this._photos.ids),this._seedReadings(t),this._loadPartOptions()}_seedReadings(t){let n=[],s=new Set;for(let l of t.readings??[])s.has(l.id)||(s.add(l.id),n.push({id:l.id,name:l.name,unit:l.unit??null}));for(let l of t.reading_values??[])s.has(l.id)||(s.add(l.id),n.push({id:l.id,name:l.name,unit:l.unit??null}));this._readingRows=n;let a={};for(let l of t.reading_values??[])a[l.id]=String(l.value);this._readingText=a,this._readingsOriginal=JSON.stringify(this._readingNumbers())}_readingNumbers(){let t={};for(let n of this._readingRows){let s=(this._readingText[n.id]??"").trim();if(s==="")continue;let a=parseFloat(s.replace(",","."));isNaN(a)||(t[n.id]=a)}return t}async _loadPartOptions(){let t=this._draft;if(!t)return;let n=this._openGen;try{let s=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"});if(n!==this._openGen)return;let a=[];for(let d of s.parts||[]){let u=d.entry_id===t.entry_id,h=d.consumers.some(f=>f.entry_id===t.entry_id&&f.task_id===t.task_id);!u&&!h||a.push({part_id:d.part_id,name:d.name,entry_id:d.entry_id,foreign:!u,object_name:d.object_name})}for(let d of t.used_parts||[]){let u=d.entry_id||t.entry_id;a.some(h=>h.part_id===d.part_id&&h.entry_id===u)||a.push({part_id:d.part_id,name:d.name||d.part_id,entry_id:u,foreign:u!==t.entry_id,object_name:null})}let l={};for(let d of t.used_parts||[])l[`${d.entry_id||t.entry_id}:${d.part_id}`]=d.quantity??1;this._partOptions=a,this._partQty=l,this._partQtyOriginal=this._partSelectionKey()}catch{if(n!==this._openGen)return;this._partOptions=[]}}_partSelectionKey(){return JSON.stringify(Object.entries(this._partQty).filter(([,t])=>t>0).sort(([t],[n])=>t.localeCompare(n)))}close(){this._openGen++,this._open=!1,this._error="",this._draft=null,this._originalSnapshot=null,this._photos.discardOrphans()}_set(t,n){this._draft&&(this._draft={...this._draft,[t]:n})}async _delete(){if(!this._draft||!this._originalSnapshot)return;let t=this._lang;if(!await O(this.hass,{title:r("history_delete_entry",t),message:r("history_delete_confirm",t),confirmText:r("delete",t),danger:!0})||!this._draft||!this._originalSnapshot)return;let s=this._draft;this._error="",await this._runWs({type:"maintenance_supporter/task/history/delete",entry_id:s.entry_id,task_id:s.task_id,timestamp:this._originalSnapshot.original_timestamp})!==void 0&&(this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:s.entry_id,task_id:s.task_id,deleted:!0},bubbles:!0,composed:!0})),this.close())}_runWs(t){return I(this,t,{busy:n=>{this._saving=n},onError:n=>{this._error=n}})}async _save(){if(!this._draft||!this._originalSnapshot||this._saving||this._photos.uploading)return;this._error="",this._photos.clearError();let t=this._draft,n=this._originalSnapshot,s={type:"maintenance_supporter/task/history/update",entry_id:t.entry_id,task_id:t.task_id,original_timestamp:n.original_timestamp};if(t.timestamp!==n.timestamp&&(s.timestamp=t.timestamp),t.notes!==n.notes&&(s.notes=t.notes),t.cost!==n.cost&&(s.cost=t.cost),t.duration!==n.duration&&(s.duration=t.duration),t.completed_by!==n.completed_by&&(s.completed_by=t.completed_by),this._partOptions!==null&&this._partSelectionKey()!==this._partQtyOriginal&&(s.used_parts=(this._partOptions||[]).filter(l=>(this._partQty[`${l.entry_id}:${l.part_id}`]||0)>0).map(l=>({part_id:l.part_id,quantity:this._partQty[`${l.entry_id}:${l.part_id}`],...l.foreign?{entry_id:l.entry_id}:{}}))),t.reading_value!==n.reading_value&&(s.reading_value=t.reading_value??null),this._readingRows.length>0&&JSON.stringify(this._readingNumbers())!==this._readingsOriginal){let l=this._readingNumbers(),d={};for(let u of this._readingRows)d[u.id]=l[u.id]??null;s.reading_values=d}if(JSON.stringify(this._photos.ids)!==this._photosOriginal&&(s.photo_doc_ids=this._photos.ids),Object.keys(s).filter(l=>!["type","entry_id","task_id","original_timestamp"].includes(l)).length===0){this.close();return}await this._runWs(s)!==void 0&&(this._photos.markAttached(),this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:t.entry_id Line truncated
<h2>${r("history_edit_title",t)}</h2>
<div class="entry-type">
<ha-icon icon="mdi:tag-outline"></ha-icon>
<span>${r(n.type,t)||n.type}</span>
</div>
<ms-date-field
kind="datetime"
required
.hass=${this.hass}
.lang=${t}
.label=${r("history_edit_timestamp",t)}
.value=${n.timestamp.slice(0,19)}
@value-changed=${a=>{let l=a.detail.value;l&&this._set("timestamp",l)}}
></ms-date-field>
<label>
<span>${r("notes_label",t)}</span>
<textarea
rows="3"
@input=${a=>{let l=a.target.value;this._set("notes",l||null)}}
.value=${n.notes??""}></textarea>
</label>
<div class="row">
<label>
<span>${r("cost",t)}</span>
<input type="number" min="0" step="0.01"
.value=${n.cost!=null?String(n.cost):""}
@input=${a=>{let l=a.target.value;this._set("cost",l?Number(l):null)}} />
</label>
<label>
<span>${r("duration",t)}</span>
<input type="number" min="0" step="1" inputmode="numeric"
.value=${n.duration!=null?String(n.duration):""}
@input=${a=>{this._set("duration",Ot(a.target.value))}} />
</label>
</div>
${this._renderReadings(n,t)}
${this._partOptions&&this._partOptions.length>0?o`
<div class="parts-block">
<span class="parts-title">${r("complete_parts_used",t)}</span>
${this._partOptions.map(a=>{let l=`${a.entry_id}:${a.part_id}`,d=this._partQty[l]||0;return o`
<label class="part-row-edit">
<input type="checkbox" .checked=${d>0}
@change=${u=>{let h=u.target.checked;this._partQty={...this._partQty,[l]:h?1:0}}} />
<span class="part-label">${a.name}${a.foreign&&a.object_name?` (${a.object_name})`:""}</span>
${d>0?o`
<input class="part-qty" type="number" min=${dt[0]} max=${dt[1]} step="0.01"
.value=${String(d)}
@input=${u=>{let h=parseFloat(u.target.value);!isNaN(h)&&h>0&&(this._partQty={...this._partQty,[l]:h})}} />
`:c}
</label>
`})}
</div>
`:c}
<div class="photos-block">
<span class="parts-title">${r("completion_photos",t)}</span>
${this._photos.photos.length>0?o`
<div class="photo-strip">
${this._photos.photos.map(a=>o`
<div class="photo-tile">
<maintenance-history-photo .hass=${this.hass} .docId=${a.id}></maintenance-history-photo>
<button type="button" class="photo-remove" title=${r("remove",t)}
@click=${()=>this._photos.remove(a.id)}>✕</button>
</div>`)}
</div>`:c}
${this._photos.full?o`<span class="photos-hint">${r("photos_limit",t).replace("{max}",String(this._photos.max))}</span>`:o`<ms-photo-picker .lang=${t} .busy=${this._photos.uploading} .remaining=${this._photos.remaining}
@files-picked=${a=>this._photos.addFiles(a.detail.files)}
></ms-photo-picker>`}
<span class="photos-hint">${r("history_edit_photos_hint",t)}</span>
</div>
${s?o`<div class="error">${s}</div>`:c}
<div class="actions">
<button class="delete-entry" @click=${this._delete} ?disabled=${this._saving} title=${r("history_delete_entry",t)}>
<ha-icon icon="mdi:delete-outline"></ha-icon> ${r("history_delete_entry",t)}
</button>
<button class="cancel" @click=${this.close} ?disabled=${this._saving}>
${r("cancel",t)}
</button>
<button class="save" @click=${this._save} ?disabled=${this._saving||this._photos.uploading}
title=${this._photos.uploading?r("uploading",t):""}>
${this._saving?r("saving",t):r("save",t)}
</button>
</div>
`)}updated(t){t.has("_open")&&this._open&&W(this.shadowRoot)}_renderReadings(t,n){return this._readingRows.length>0?o`
<div class="readings-block">
<span class="parts-title">${r("readings_section",n)}</span>
${this._readingRows.map(s=>o`
<label class="reading-row-edit">
<span class="reading-row-name">${s.name}${s.unit?` (${s.unit})`:""}</span>
<input type="text" inputmode="decimal" class="reading-row-input"
.value=${this._readingText[s.id]??""}
@input=${a=>{this._readingText={...this._readingText,[s.id]:a.target.value}}} />
</label>
`)}
</div>`:t.reading_value==null&&t.task_type!=="reading"?c:o`
<label>
<span>${r("reading_value_label",n)}${t.reading_unit?` (${t.reading_unit})`:""}</span>
<input type="number" step="any"
.value=${t.reading_value!=null?String(t.reading_value):""}
@input=${s=>{let a=s.target.value,l=a===""?NaN:Number(a);this._set("reading_value",isNaN(l)?null:l)}} />
</label>`}};b.styles=[Dt,z,$`
:host { display: contents; --ms-modal-max-height: 90vh; --ms-modal-gap: 12px; }
h2 { margin: 0; font-size: 18px; }
.entry-type {
display: flex; align-items: center; gap: 6px;
color: var(--secondary-text-color); font-size: 13px;
}
label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
label span { color: var(--secondary-text-color); }
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
input, textarea {
padding: 8px; font-size: 14px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color, #444);
border-radius: 6px;
width: 100%; box-sizing: border-box;
font-family: inherit;
}
.delete-entry { margin-right: auto; color: var(--error-color, #d32f2f); background: transparent; border: 1px solid var(--error-color, #d32f2f); border-radius: 6px; padding: 6px 10px; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; }
.delete-entry ha-icon { --mdc-icon-size: 18px; }
.actions {
display: flex; gap: 8px; justify-content: flex-end;
margin-top: 8px;
}
button {
padding: 8px 16px; font-size: 14px;
border-radius: 6px; cursor: pointer;
border: none; font-weight: 500;
}
button.cancel {
background: transparent;
color: var(--primary-text-color);
border: 1px solid var(--divider-color);
}
button.save {
background: var(--primary-color);
color: var(--text-primary-color, white);
}
button[disabled] { opacity: 0.5; cursor: wait; }
.error {
color: var(--error-color, #d32f2f);
font-size: 13px; padding: 8px;
background: rgba(211,47,47,0.1);
border-radius: 6px;
}
/* #130: parts on the entry */
.parts-block {
display: flex; flex-direction: column; gap: 6px;
border: 1px solid var(--divider-color, #444);
border-radius: 6px; padding: 8px;
}
.parts-title { color: var(--secondary-text-color); font-size: 13px; }
.part-row-edit {
display: flex; flex-direction: row; align-items: center; gap: 8px;
font-size: 14px;
}
.part-row-edit input[type="checkbox"] { width: auto; }
.part-label { flex: 1; color: var(--primary-text-color); }
.part-qty { width: 76px; }
/* #161 phase 2: readings on the entry */
.readings-block {
display: flex; flex-direction: column; gap: 6px;
border: 1px solid var(--divider-color, #444);
border-radius: 6px; padding: 8px;
}
.reading-row-edit {
display: flex; flex-direction: row; align-items: center; gap: 8px;
font-size: 14px;
}
.reading-row-name { flex: 1; color: var(--primary-text-color); min-width: 0; }
.reading-row-input { width: 140px; font-variant-numeric: tabular-nums; }
/* #161: photos on the entry */
.photos-block {
display: flex; flex-direction: column; gap: 6px;
border: 1px solid var(--divider-color, #444);
border-radius: 6px; padding: 8px;
}
.photo-strip { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 6px; }
.photo-tile { position: relative; width: fit-content; }
.photo-remove {
position: absolute; top: -4px; right: -8px;
width: 22px; height: 22px; border-radius: 50%; border: none;
background: var(--error-color, #db4437); color: #fff;
cursor: pointer; font-size: 11px; line-height: 1; padding: 0;
}
/* the camera / gallery pickers come from photoPickerStyles (ms-photo-picker) */
.photos-hint { font-size: 12px; color: var(--secondary-text-color); }
`],p([w({attribute:!1})],b.prototype,"hass",2),p([m()],b.prototype,"_open",2),p([m()],b.prototype,"_saving",2),p([m()],b.prototype,"_error",2),p([m()],b.prototype,"_draft",2),p([m()],b.prototype,"_partOptions",2),p([m()],b.prototype,"_partQty",2),p([m()],b.prototype,"_readingRows",2),p([m()],b.prototype,"_readingText",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",b);function ye(e,i){if(i<=0)return 0;let t=typeof e=="number"&&Number.isFinite(e)?Math.trunc(e):0;return t<0?0:t%i}function ve(e){return!!(e?.phases&&e.phase_sequence&&e.phase_sequence.length>0)}function ct(e){if(!e||!ve(e))return null;let i=e.phase_sequence,t=ye(e.phase_cursor,i.length),n=i[t],s=e.phases?.[n];return s?{id:n,name:s.name,index:t,count:i.length,notes:s.notes,checklist:s.checklist!==void 0?s.checklist:e.checklist??[],consumesParts:s.consumes_parts!==void 0?s.consumes_parts:e.consumes_parts??[],requiredFields:s.required_completion_fields!==void 0?s.required_completion_fields:e.required_completion_fields??[]}:null}function B(e){let i=ct(e);return i?`${i.index+1}/${i.count} \xB7 ${i.name}`:""}function be(e,i){return typeof e=="number"&&Number.isFinite(e)&&e>=.01?e:i}function Ft(e){let i=e.task??null,t=i?ct(i):null,n=t?t.consumesParts:i?.consumes_parts||[],s=!!i?.part_ref,a=e.objects.find(f=>f.entry_id===e.entryId)?.parts||[],l=s?a.find(f=>f.id===i.part_ref.part_id):void 0,d=e.features?e.features.checklists:e.checklistsEnabled??!0,u=e.features?e.features.checklists?e.checklist??i?.checklist??[]:[]:e.checklist??[],h=e.features?e.features.adaptive&&(e.adaptiveEnabled??!!i?.adaptive_config?.enabled):!!e.adaptiveEnabled;return{entry_id:e.entryId,task_id:e.taskId,task_name:e.taskName,checklist:t?d?t.checklist:[]:u,adaptive_enabled:h,required_completion_fields:t?t.requiredFields:i?.required_completion_fields||[],task_type:i?.type||"",reading_unit:i?.reading_unit||"",readings:i?.readings||[],reading_history:It(i?.history),parts:s?[]:Pt({consumes_parts:n},e.entryId,e.objects,e.lang),consumes_parts:s?[]:n,phase_label:t?B(i):"",require_tag_scan:!!i?.require_tag_scan,restock_default:s?be(l?.restock_quantity,1):null,restock_unit_cost:s?l?.cost??null:null,currency_symbol:U({currency_symbol:e.currencySymbol}),consumes_info:n.map(f=>Ht(f,e.entryId,e.objects,e.lang)),checklist_prefill:i?.checklist_progress||{},via_tag_scan:!!e.viaTagScan}}function Wt(e,i,t){e.entryId=i.entry_id,e.taskId=i.task_id,e.taskName=i.task_name,e.lang=t,e.checklist=i.checklist??[],e.adaptiveEnabled=!!i.adaptive_enabled,e.requiredFields=i.required_completion_fields??[],e.taskType=i.task_type??"",e.readingUnit=i.reading_unit??"",e.readings=i.readings??[],e.readingHistory=i.reading_history??[],e.parts=i.parts??[],e.consumesParts=i.consumes_parts??[],e.phaseLabel=i.phase_label??"",e.requireTagScan=!!i.require_tag_scan,e.restockDefault=i.restock_default??null,e.restockUnitCost=i.restock_unit_cost??null,e.currencySymbol=U(i),e.consumesInfo=i.consumes_info??[],e.checklistPrefill=i.checklist_prefill??{},e.viaTagScan=!!i.via_tag_scan,e.open({viaTagScan:!!i.via_tag_scan})}function pt(e,i,t,n){let s=t,a=u=>typeof u=="string"?u:null,l=u=>typeof u=="number"?u:null,d=a(s.timestamp)??"";return{entry_id:e,task_id:i,original_timestamp:d,type:a(s.type)||"completed",timestamp:d,notes:a(s.notes),cost:l(s.cost),duration:l(s.duration),completed_by:a(s.completed_by),used_parts:Array.isArray(s.used_parts)?s.used_parts:null,photo_doc_ids:nt(s),reading_value:l(s.reading_value),reading_values:et(s),readings:n?.readings??[],task_type:n?.type??null,reading_unit:n?.reading_unit??null}}async function Mn(e,i,t,n){let a=(await e.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:i})).tasks?.find(d=>d.id===t);if(!a)return null;let l=a.history?.find(d=>d.timestamp===n);return l||(l=(await e.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:i,task_id:t})).history?.find(u=>u.timestamp===n)),l?pt(i,t,l,a):null}var Vt=e=>typeof e=="number"&&Number.isInteger(e)&&e>0;function xe(e){return e&&Vt(e.ref_no)?String(e.ref_no):null}function Ut(e,i){let t=xe(e);return t&&i&&Vt(i.ref_no)?`${t}.${i.ref_no}`:null}function On(e){let i=/^(\d+)(?:\.(\d+)(?:-(\d+))?)?$/.exec(e.trim());return i?{object:Number(i[1]),task:i[2]?Number(i[2]):null,entry:i[3]?Number(i[3]):null}:null}function Gt(e,i){return e?o`<span class="ref-chip" title=${i??""}>#${e}</span>`:c}var $e={\u00DF:"s","\u1E9E":"s",\u00E6:"a",\u0153:"o",\u00F8:"o",\u0111:"d",\u00F0:"d",\u00FE:"t",\u0142:"l",\u0131:"i"},Zt=10,ke=7,ut=4,Bt=2,we=5,Yt=3,Te=/[a-z0-9]+/g;function st(e){let i="";for(let t of e.toLowerCase()){if(t.charCodeAt(0)<128&&t.length===1){i+=t;continue}let n=$e[t];if(n){i+=n;continue}let s=t.normalize("NFKD")[0]||t;i+=s.charCodeAt(0)<128?s:t}return i}function Jt(e){return st(e).match(Te)||[]}function Ee(e){return st(e).replace(/[^a-z0-9]+/g,"")}function Ae(e){return e.replace(/ue/g,"u").replace(/oe/g,"o").replace(/ae/g,"a").replace(/ssLine truncated
<div class="history-filters-new">
<div class="filter-chips">
${Ie.map(n=>{let s=e.history.filter(a=>a.type===n).length;return s===0?c:o`
<span class="filter-chip ${i.filter===n?"active":""}"
@click=${()=>i.setFilter(i.filter===n?null:n)}>
${r(n,t)} (${s})
</span>
`})}
${i.filter?o`<span class="filter-chip clear" @click=${()=>i.setFilter(null)}>${r("show_all",t)}</span>`:c}
</div>
<div class="filter-controls">
<input type="text" class="search-input" placeholder="${r("search_notes",t)}..." .value=${i.search} @input=${n=>i.setSearch(n.target.value)} />
</div>
</div>
`}function Kn(e,i){let t=i.lang,n=i.filter?e.history.filter(s=>s.type===i.filter):e.history;if(i.search){let s=i.search.toLowerCase();n=n.filter(a=>Qt(a.notes,i.search)||(Xt(i,a)??"").toLowerCase().endsWith(s))}return n.length===0?o`<p class="empty">${r("no_history",t)}</p>`:o`
<div class="history-timeline">
${ht(n).map(s=>mt(s,i))}
</div>
`}function Xt(e,i){return e.taskRef&&i.ref_no?`${e.taskRef}-${i.ref_no}`:null}function Me(e,i){let t=nt(i);return t.length>0?o`<div class="history-photos">
${t.map(n=>o`<maintenance-history-photo .hass=${e} .docId=${n}></maintenance-history-photo>`)}
</div>`:c}function De(e,i){let t=i.lang,n=l=>y(l,t,{maximumFractionDigits:3}),s=l=>l==null?"":` (${l>=0?"+":""}${n(l)})`,a=et(e);return a.length>0?o`<div class="history-readings">
${a.map(l=>o`<span class="history-reading">
<span class="history-reading-name">${l.name}</span>
<span class="history-reading-value">${n(l.value)}${l.unit?` ${l.unit}`:""}${s(i.readingSlotDelta?.(e,l.id))}</span>
</span>`)}
</div>`:e.reading_value!=null?o`<div class="history-readings"><span class="history-reading">
<span class="history-reading-name">${r("reading_label",t)}</span>
<span class="history-reading-value">${n(e.reading_value)}${i.readingUnit?` ${i.readingUnit}`:""}${s(i.readingDelta?.(e))}</span>
</span></div>`:c}function mt(e,i,t={}){let n=i.lang,{compact:s=!1,showRef:a=!0,showBadges:l=!0,showEdit:d=!0}=t,u=i.openEdit,h=d&&!!u&&Pe.includes(e.type);return o`
<div class="history-entry${s?" compact":""}">
${s?c:o`<div class="history-icon ${e.type}">
<ha-icon .icon=${Q[e.type]||"mdi:circle"}></ha-icon>
</div>`}
<div class="history-content">
<div class="history-row">
<strong>${r(e.type,n)}</strong>
${a?Gt(Xt(i,e),r("ref_number",n)):c}
${l&&e.phase_id?o`<span class="history-phase-badge">${i.phaseNames?.[e.phase_id]||e.phase_id}</span>`:c}
${l&&e.auto?o`<span class="history-auto-badge">${r("history_auto",n)}</span>`:c}
${h?o`<button class="history-edit-btn"
title=${r("history_edit_button",n)}
@click=${()=>u(e)}>
<ha-icon icon="mdi:pencil"></ha-icon>
</button>`:c}
</div>
<div class="history-date">${kt(e.timestamp,n)}</div>
${e.notes?o`<div>${e.notes}</div>`:c}
${Me(i.hass,e)}
${De(e,i)}
${e.cost!=null||e.duration!=null||e.trigger_value!=null?o`<div class="history-details">
${e.cost!=null?o`<span>${r("cost",n)}: ${X(e.cost,i.currencySymbol,n)}</span>`:c}
${e.duration!=null?o`<span>${r("duration",n)}: ${tt(e.duration,n)}</span>`:c}
${e.trigger_value!=null?o`<span>${r("trigger_val",n)}: ${e.trigger_value}</span>`:c}
</div>`:c}
</div>
</div>
`}var Ce="var(--maint-done-color, #78909c)";function K(e){return e.archived?"archived":e.is_done?"done":e.status||"ok"}function _t(e,i){return r(e==="done"?"completed":e,i)}function rt(e){let i=K(e);return i==="done"?Ce:gt[i]||"var(--disabled-color, #9e9e9e)"}function Oe(e){return Q[e==="done"?"completed":e]||"mdi:circle-medium"}function te(e,i,t="pill"){let n=K(e),s=_t(n,i);return t==="chip"?o`<span class="status-chip ${n}">${s}</span>`:o`<span class="status-badge ${n}" role="img" title="${s}" aria-label="${s}"><ha-icon icon="${Oe(n)}"></ha-icon><span class="status-label">${s}</span></span>`}function _(e){return e.toFixed(1)}function ei(e,i,t=4){if(!isFinite(e)||!isFinite(i))return{ticks:[],niceMin:0,niceMax:1};if(e===i){let h=Math.abs(e)*.1||1;e-=h,i+=h}let n=i-e,s=Math.pow(10,Math.floor(Math.log10(n/Math.max(1,t)))),a=s;for(let h of[1,2,5,10])if(a=s*h,n/a<=t+.5)break;let l=Math.floor(e/a)*a,d=Math.ceil(i/a)*a,u=[];for(let h=l;h<=d+a*1e-6;h+=a)u.push(Math.abs(h)<a*1e-9?0:h);return{ticks:u,niceMin:l,niceMax:d}}function ni(e,i){let t=Math.abs(e),n=s=>({maximumFractionDigits:s});return t>=1e6?y(e/1e6,i,n(t>=1e7?0:1))+"M":t>=1e4?y(e/1e3,i,n(0))+"k":t>=1e3?y(e/1e3,i,n(1))+"k":t>=100?y(e,i,n(0)):t>=1?y(e,i,n(1)):t===0?"0":y(e,i,n(2))}function ii(e,i,t){let n=y(e,t,{maximumFractionDigits:Math.abs(e)>=100?0:1});return i?`${n} ${i}`:n}function si(e,i,t){return lt(new Date(e),i,t)}function ri(e,i){let t=new Date(e);return`${lt(t,i)}, ${$t(t,i)}`}function ai(e,i){return new Date(e).getFullYear()!==new Date(i).getFullYear()}function oi(e,i,t){if(t<2||i<=e)return[e,i];let n=[];for(let s=0;s<t;s++)n.push(e+(i-e)*s/(t-1));return n}function ee(e,i){let t=e.interval_analysis,n=t?.weibull_beta,s=t?.weibull_eta;if(n==null||s==null||s<=0)return c;let a=e.interval_days??0,l=e.suggested_interval??a;return o`
<div class="weibull-section">
<div class="weibull-title">
<ha-svg-icon aria-hidden="true" path="M3,14L3.5,14.07L8.07,9.5C7.89,8.85 8.06,8.11 8.59,7.59C9.37,6.8 10.63,6.8 11.41,7.59C11.94,8.11 12.11,8.85 11.93,9.5L14.5,12.07L15,12C15.18,12 15.35,12 15.5,12.07L19.07,8.5C19,8.35 19,8.18 19,8A2,2 0 0,1 21,6A2,2 0 0,1 23,8A2,2 0 0,1 21,10C20.82,10 20.65,10 20.5,9.93L16.93,13.5C17,13.65 17,13.82 17,14A2,2 0 0,1 15,16A2,2 0 0,1 13,14L13.07,13.5L10.5,10.93C10.18,11 9.82,11 9.5,10.93L4.93,15.5L5,16A2,2 0 0,1 3,18A2,2 0 0,1 1,16A2,2 0 0,1 3,14Z"></ha-svg-icon>
${r("weibull_reliability_curve",i)}
${je(n,i)}
</div>
${Ne(n,s,a,l,i)}
${qe(t,i)}
${t?.confidence_interval_low!=null?ze(t,e,i):c}
</div>
`}function je(e,i){let t,n,s;return e<.8?(t="early_failures",n="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z",s="beta_early_failures"):e<=1.2?(t="random_failures",n="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,17H11V15H13V17M13,13H11V7H13V13Z",s="beta_random_failures"):e<=3.5?(t="wear_out",n="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4M12,6A6,6 0 0,1 18,12H12V6Z",s="beta_wear_out"):(t="highly_predictable",n="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M11,16.5L18,9.5L16.59,8.09L11,13.67L7.91,10.59L6.5,12L11,16.5Z",s="beta_highly_predictable"),o`
<span class="beta-badge ${t}">
<ha-svg-icon path="${n}"></ha-svg-icon>
${r(s,i)} (\u03B2=${y(e,i,2)})
</span>
`}function Ne(e,i,t,n,s){let x=Math.max(t,n,i,1)*1.3,S=50,R=[];for(let k=0;k<=S;k++){let A=k/S*x,he=1-Math.exp(-Math.pow(A/i,e)),me=32+A/x*260,_e=136-he*128;R.push([me,_e])}let Z=R.map(([k,A])=>`${_(k)},${_(A)}`).join(" "),ot="M32,136 "+R.map(([k,A])=>`L${_(k)},${_(A)}`).join(" ")+` L${_(R[S][0])},136 Z`,j=32+t/x*260,Y=1-Math.exp(-Math.pow(t/i,e)),J=136-Y*128,pe=y((1-Y)*100,s,0),ft=32+n/x*260,ue=[0,.25,.5,.75,1];return o`
<div class="weibull-chart">
<svg viewBox="0 0 ${300} ${160}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${r("chart_weibull",s)}">
${ue.map(k=>{let A=136-k*128;return N`
<line x1="${32}" y1="${_(A)}" x2="${292}" y2="${_(A)}"
stroke="var(--divider-color)" stroke-width="0.5" stroke-dasharray="${k===.5?"4,3":c}" />
<text x="${28}" y="${_(A+3)}" fill="var(--secondary-text-color)"
font-size="8" text-anchor="end">${y(k*100,s,0)}%</text>
`})}
<text x="${32}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">0</text>
<text x="${324/2}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">${Math.round(x/2)}</text>
<text x="${292}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">${Math.round(x)}</text>
<path d="${ot}" fill="var(--primary-color, #03a9f4)" opacity="0.08" />
<polyline points="${Z}" fill="none"
stroke="var(--primary-color, #03a9f4)" stroke-width="2" />
${t>0?N`
<line x1="${_(j)}" y1="${8}" x2="${_(j)}" y2="${_(136)}"
stroke="var(--primary-color, #03a9f4)" stroke-width="1.5" stroke-dasharray="4,3" />
<circle cx="${_(j)}" cy="${_(J)}" r="3"
fill="var(--primary-color, #03a9f4)" />
<text x="${_(j+4)}" y="${_(J-6)}" fill="var(--primary-color, #03a9f4)"
font-size="9" font-weight="600">R=${pe}%</text>
`:c}
${n>0&&n!==t?N`
<line x1="${_(ft)}" y1="${8}" x2="${_(ft)}" y2="${_(136)}"
stroke="var(--success-color, #4caf50)" stroke-width="1.5" stroke-dasharray="4,3" />
`:c}
<line x1="${32}" y1="${8}" x2="${32}" y2="${136}"
stroke="var(--secondary-text-color)" stroke-width="1" />
<line x1="${32}" y1="${136}" x2="${292}" y2="${136}"
stroke="var(--secondary-text-color)" stroke-width="1" />
</svg>
</div>
<div class="chart-legend">
<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color, #03a9f4)"></span> ${r("weibull_failure_probability",s)}</span>
${t>0?o`<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color, #03a9f4); opacity:0.5"></span> ${r("current_interval_marker",s)}</span>`:c}
${n>0&&n!==t?o`<span class="legend-item"><span class="legend-swatch" style="background:var(--success-color, #4caf50)"></span> ${r("recommended_marker",s)}</span>`:c}
</div>
`}function qe(e,i){return o`
<div class="weibull-info-row">
<div class="weibull-info-item">
<span>${r("characteristic_life",i)}</span>
<span class="weibull-info-value">${Math.round(e.weibull_eta)} ${r("days",i)}</span>
</div>
${e.weibull_r_squared!=null?o`
<div class="weibull-info-item">
<span>${r("weibull_r_squared",i)}</span>
<span class="weibull-info-value">${y(e.weibull_r_squared,i,3)}</span>
</div>
`:c}
</div>
`}function ze(e,i,t){let n=e.confidence_interval_low,s=e.confidence_interval_high,a=i.suggested_interval??i.interval_days??0,l=i.interval_days??0,d=Math.max(0,n-5),h=s+5-d,f=(n-d)/h*100,C=(s-n)/h*100,V=(a-d)/h*100,x=l>0?(l-d)/h*100:-1;return o`
<div class="confidence-range">
<div class="confidence-range-title">
${r("confidence_interval",t)}: ${a} ${r("days",t)} (${n}\u2013${s})
</div>
<div class="confidence-bar">
<div class="confidence-fill" style="left:${_(f)}%;width:${_(C)}%"></div>
${x>=0?o`<div class="confidence-marker current" style="left:${_(x)}%"></div>`:c}
<div class="confidence-marker recommended" style="left:${_(V)}%"></div>
</div>
<div class="confidence-labels">
<span class="confidence-text low">${r("confidence_conservative",t)} (${n}${r("days",t).charAt(0)})</span>
<span class="confidence-text high">${r("confidence_aggressive",t)} (${s}${r("days",t).charAt(0)})</span>
</div>
</div>
`}function ne(e,i,t){let n=e.degradation_trend!=null&&e.degradation_trend!=="insufficient_data",s=e.days_until_threshold!=null,a=e.environmental_factor!=null&&e.environmental_factor!==1;if(!n&&!s&&!a)return c;let l=e.degradation_trend==="rising"?"M16,6L18.29,8.29L13.41,13.17L9.41,9.17L2,16.59L3.41,18L9.41,12L13.41,16L19.71,9.71L22,12V6H16Z":e.degradation_trend==="falling"?"M16,18L18.29,15.71L13.41,10.83L9.41,14.83L2,7.41L3.41,6L9.41,12L13.41,8L19.71,14.29L22,12V18H16Z":"M22,12L18,8V11H3V13H18V16L22,12Z";return o`
<div class="prediction-section">
${e.sensor_prediction_urgency?o`
<div class="prediction-urgency-banner">
<ha-svg-icon path="M1,21H23L12,2L1,21M12,18A1,1 0 0,1 11,17A1,1 0 0,1 12,16A1,1 0 0,1 13,17A1,1 0 0,1 12,18M13,15H11V10H13V15Z"></ha-svg-icon>
${r("sensor_prediction_urgency",i).replace("{days}",String(Math.round(e.days_until_threshold||0)))}
</div>
`:c}
<div class="prediction-title">
<ha-svg-icon path="M2,2V4H7V2H2M22,2V4H13V2H22M7,7V9H2V7H7M22,7V9H13V7H22M7,12V14H2V12H7M22,12V14H13V12H22M7,17V19H2V17H7M22,17V19H13V17H22M9,2V19L12,22L15,19V2H9M11,4H13V17.17L12,18.17L11,17.17V4Z"></ha-svg-icon>
${r("sensor_prediction",i)}
</div>
<div class="prediction-grid">
${n?o`
<div class="prediction-item">
<ha-svg-icon path="${l}"></ha-svg-icon>
<span class="prediction-label">${r("degradation_trend",i)}</span>
<span class="prediction-value ${e.degradation_trend}">${r("trend_"+e.degradation_trend,i)}</span>
${e.degradation_rate!=null?o`<span class="prediction-rate">${e.degradation_rate>0?"+":""}${y(e.degradation_rate,i,Math.abs(e.degradation_rate)>=10?0:1)} ${e.trigger_entity_info?.unit_of_measurement||""}/${r("day_short",i)}</span>`:c}
</div>
`:c}
${s?o`
<div class="prediction-item">
<ha-svg-icon path="M12,20A7,7 0 0,1 5,13A7,7 0 0,1 12,6A7,7 0 0,1 19,13A7,7 0 0,1 12,20M12,4A9,9 0 0,0 3,13A9,9 0 0,0 12,22A9,9 0 0,0 21,13A9,9 0 0,0 12,4M12.5,8H11V14L15.75,16.85L16.5,15.62L12.5,13.25V8M7.88,3.39L6.6,1.86L2,5.71L3.29,7.24L7.88,3.39M22,5.72L17.4,1.86L16.11,3.39L20.71,7.25L22,5.72Z"></ha-svg-icon>
<span class="prediction-label">${r("days_until_threshold",i)}</span>
<span class="prediction-value prediction-days${e.days_until_threshold===0?" exceeded":e.sensor_prediction_urgency?" urgent":""}">${e.days_until_threshold===0?r("threshold_exceeded",i):"~"+Math.round(e.days_until_threshold)+" "+r("days",i)}</span>
${e.threshold_prediction_date?o`<span class="prediction-date">${G(e.threshold_prediction_date,i)}</span>`:c}
${e.threshold_prediction_confidence?o`<span class="confidence-dot ${e.threshold_prediction_confidence}"></span>`:c}
${(e.prediction_cycles??0)>0?o`<span class="prediction-cycles">${r("prediction_cycles",i)}: ${e.prediction_cycles}</span>`:c}
</div>
`:c}
${a&&t.environmental?o`
<div class="prediction-item">
<ha-svg-icon path="M15,13V5A3,3 0 0,0 12,2A3,3 0 0,0 9,5V13A5,5 0 0,0 7,17A5,5 0 0,0 12,22A5,5 0 0,0 17,17A5,5 0 0,0 15,13M12,4A1,1 0 0,1 13,5V8H11V5A1,1 0 0,1 12,4Z"></ha-svg-icon>
<span class="prediction-label">${r("environmental_adjustment",i)}</span>
<span class="prediction-value">${y(e.environmental_factor,i,2)}x</span>
${e.environmental_entity?o`<span class="prediction-entity entity-link" @click=${d=>Et(d,e.environmental_entity)}>${e.environmental_entity}</span>`:c}
</div>
`:c}
</div>
</div>
`}function ie(e,i,t,n){let s=Math.max(e||1,i);return o`
<div class="interval-comparison">
<div class="interval-bar">
<div class="interval-label">
${r("current",n)}: ${e??"\u2014"} ${e!=null?r("days",n):""}
</div>
<div class="interval-visual current"
style="width: ${e!=null?Math.min(e/s*100,100):0}%"></div>
</div>
<div class="interval-bar">
<div class="interval-label">
${r("recommended",n)}: ${i} ${r("days",n)}
<span class="confidence-badge ${t}">${r(`confidence_${t}`,n)}</span>
</div>
<div class="interval-visual suggested"
style="width: ${Math.min(i/s*100,100)}%"></div>
</div>
</div>
`}var se=["month_jan","month_feb","month_mar","month_apr","month_may","month_jun","month_jul","month_aug","month_sep","month_oct","month_nov","month_dec"];function re(e,i,t){if(!t.seasonal||!e.seasonal_factor||e.seasonal_factor===1)return c;let n=se.map(d=>r(d,i)),s=new Date().getMonth(),a=e.seasonal_factors||e.interval_analysis?.seasonal_factors||null,l=a&&a.length===12?a:n.map((d,u)=>{let h=e.seasonal_factor||1,f=Math.sin((u-6)*Math.PI/6)*.3;return Math.max(.7,Math.min(1.3,h+f))});return o`
<div class="seasonal-card-compact">
<h4>${r("seasonal_awareness",i)}</h4>
<div class="seasonal-mini-chart">
${l.map((d,u)=>{let h=d*40,f=d<.9?"low":d>1.1?"high":"normal";return o`
<div class="seasonal-bar ${f} ${u===s?"current":""}"
style="height: ${h}px"
title="${n[u]}: ${y(d,i,2)}x">
</div>
`})}
</div>
<div class="seasonal-legend">
<span class="legend-item"><span class="dot low"></span> ${r("shorter",i)}</span>
<span class="legend-item"><span class="dot normal"></span> ${r("normal",i)}</span>
<span class="legend-item"><span class="dot high"></span> ${r("longer",i)}</span>
</div>
</div>
`}function ae(e,i){return Fe(e,i)}function Fe(e,i){let t=e.seasonal_factors??e.interval_analysis?.seasonal_factors;if(!t||t.length!==12)return c;let n=e.interval_analysis?.seasonal_reason,s=new Date().getMonth(),a=300,l=100,d=8,h=l-d-4,f=Math.max(...t,1.5),C=a/12,V=C*.65,x=d+h-1/f*h;return o`
<div class="seasonal-chart">
<div class="seasonal-chart-title">
<ha-svg-icon aria-hidden="true" path="M17.75 4.09L15.22 6.03L16.13 9.09L13.5 7.28L10.87 9.09L11.78 6.03L9.25 4.09L12.44 4L13.5 1L14.56 4L17.75 4.09M21.25 11L19.61 12.25L20.2 14.23L18.5 13.06L16.8 14.23L17.39 12.25L15.75 11L17.81 10.95L18.5 9L19.19 10.95L21.25 11M18.97 15.95C19.8 15.87 20.69 17.05 20.16 17.8C19.84 18.25 19.5 18.67 19.08 19.07C15.17 23 8.84 23 4.94 19.07C1.03 15.17 1.03 8.83 4.94 4.93C5.34 4.53 5.76 4.17 6.21 3.85C6.96 3.32 8.14 4.21 8.06 5.04C7.79 7.9 8.75 10.87 10.95 13.06C13.14 15.26 16.1 16.22 18.97 15.95Z"></ha-svg-icon>
${r("seasonal_chart_title",i)}
${n?o`<span class="source-tag">${n==="learned"?r("seasonal_learned",i):r("seasonal_manual",i)}</span>`:c}
</div>
<svg viewBox="0 0 ${a} ${l}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${r("chart_seasonal",i)}">
<line x1="0" y1="${_(x)}" x2="${a}" y2="${_(x)}"
stroke="var(--divider-color)" stroke-width="1" stroke-dasharray="4,3" />
${t.map((S,R)=>{let Z=S/f*h,ot=R*C+(C-V)/2,j=d+h-Z,Y=R===s,J=S<1?"var(--success-color, #4caf50)":S>1?"var(--warning-color, #ff9800)":"var(--secondary-text-color)";return N`
<rect x="${_(ot)}" y="${_(j)}"
width="${_(V)}" height="${_(Z)}"
fill="${J}" opacity="${Y?1:.5}" rx="2" />
`})}
</svg>
<div class="seasonal-labels">
${se.map((S,R)=>o`<span class="seasonal-label ${R===s?"active-month":""}">${r(S,i)}</span>`)}
</div>
</div>
`}var g=class extends L{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._taskId=null;this._task=null;this._objectName="";this._taskRef=null;this._busy=!1;this._error="";this._showSkip=!1;this._showReset=!1;this._showDetails=!1;this._showAdaptive=!1;this._skipReason="";this._resetDate="";this._features={adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1};this._toast="";this._toastTimer=new Nt;this._access=it;this._currencySymbol="";this._loadSeq=0}get _lang(){return T(this.hass)}async openFor(t,n){(t!==this._entryId||n!==this._taskId)&&(this._task=null),this._entryId=t,this._taskId=n,this._error="",this._showSkip=!1,this._showReset=!1,this._showAdaptive=!1,this._skipReason="",this._resetDate=Rt(new Date),this._open=!0,await Promise.all([this._loadTask(),this._loadFeatures()])}async _loadFeatures(){let t=await M(this.hass);this._features={...this._features,...t.features},this._access=t.access,this._currencySymbol=U(t.budget??void 0),bt(t.budget??void 0)}close(){this._loadSeq++,this._open=!1,this._task=null,this._error="",this._toastTimer.clear(),this._toast=""}_showToast(t,n){this._toast=t,this._toastTimer.schedule(()=>{this._toast=""},n)}async _loadTask(){let t=this._entryId,n=this._taskId;if(!t||!n)return;let s=++this._loadSeq,a="",l=await I(this,{type:"maintenance_supporter/object",entry_id:t},{onError:u=>{a=u}});if(s!==this._loadSeq)return;if(l===void 0){this._error=a;return}this._objectName=l?.object?.name||"";let d=(l?.tasks||[]).find(u=>u.id===n);this._task=d??null,this._taskRef=Ut(l?.object,d),d||(this._error=r("ws_err_not_found",this._lang))}_runWs(t){return this._error="",I(this,t,{busy:n=>{this._busy=n},onError:n=>{this._error=n}})}_notifyChanged(t){this.dispatchEvent(new CustomEvent("task-action-fired",{detail:{entry_id:this._entryId,task_id:this._taskId,action:t},bubbles:!0,composed:!0}))}_onComplete(){!this._entryId||!this._taskId||!this._task||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-H6J55EII.js").then(async({openCompleteDialog:t})=>{let n=this._task,s=[];try{s=(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0})).objects||[]}catch{}t(Ft({entryId:this._entryId,taskId:this._taskId,taskName:n.name,task:n,objects:s,lang:this._lang,features:this._features,currencySymbol:this._currencySymbol}))&&(this._notifyChanged("complete"),this.close())})}async _onSkipConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/skip",entry_id:this._entryId,task_id:this._taskId,reason:this._skipReason.trim()||null})!==void 0&&(this._notifyChanged("skip"),this.close())}async _onResetConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/reset",entry_id:this._entryId,task_id:this._taskId,date:this._resetDate||void 0})!==void 0&&(this._notifyChanged("reset"),this.close())}_onEdit(){!this._entryId||!this._taskId||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-H6J55EII.js").then(({openEditTaskDialog:t})=>{t(this._entryId,this._taskId),this.close()})}_onQr(){!this._entryId||!this._taskId||!this._task||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-H6J55EII.js").then(({openQrDialog:t})=>{t({entry_id:this._entryId,task_id:this._taskId,task_name:this._task.name,object_name:this._objectName}),this.close()})}async _onDelete(){if(!this._entryId||!this._taskId||!await O(this.hass,{title:r("delete",this._lang),message:r("delete_task_confirm",this._lang),confirmText:r("delete",this._lang),danger:!0}))return;await this._runWs({type:"maintenance_supporter/task/delete",entry_id:this._entryId,task_id:this._taskId})!==void 0&&(this._notifyChanged("delete"),this.close())}async _onArchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/archive",entry_id:this._entryId,task_id:this._taskId})!==void 0&&(this._notifyChanged("archive"),this.close())}async _onUnarchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/unarchive",entry_id:this._entryId,task_id:this._taskId})!==void 0&&(this._notifyChanged("unarchive"),this.close())}_onOpenInPanel(){if(!this._entryId||!this._taskId)return;let t=`/maintenance-supporter?entry_id=${encodeURIComponent(this._entryId)}&task_id=${encodeURIComponent(this._taskId)}`;history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed")),this.close()}async _applySuggestion(){if(!this._entryId||!this._taskId||!this._task?.suggested_interval)return;await this._runWs({type:"maintenance_supporter/task/apply_suggestion",entry_id:this._entryId,task_id:this._taskId,interval:this._task.suggested_interval})!==void 0&&(this._showToast(r("suggestion_applied",this._lang)),this._notifyChanged("apply_suggestion"),await this._loadTask())}async _reanalyzeInterval(){if(!this._entryId||!this._taskId)return;let t=aw Line truncated
<div class="recommendation-card">
<h4>${r("suggested_interval",n)}</h4>
${ie(t.interval_days,t.suggested_interval,t.interval_confidence||"medium",n)}
<div class="recommendation-actions">
${q(this.hass?.user,this._access)?o`<button class="btn primary qa-apply-suggestion"
@click=${this._applySuggestion} ?disabled=${this._busy}>
<ha-icon icon="mdi:check"></ha-icon>
${r("apply_suggestion",n)}
</button>`:c}
<button class="btn"
@click=${this._reanalyzeInterval} ?disabled=${this._busy}>
<ha-icon icon="mdi:refresh"></ha-icon>
${r("reanalyze",n)}
</button>
</div>
</div>
`}_renderAdaptive(t){let n=this._lang,s=this._features.adaptive&&t.suggested_interval&&t.suggested_interval!==t.interval_days,a=t.degradation_trend!=null&&t.degradation_trend!=="insufficient_data"||t.days_until_threshold!=null||t.environmental_factor!=null&&t.environmental_factor!==1,l=this._features.adaptive&&t.interval_analysis?.weibull_beta!=null&&t.interval_analysis?.weibull_eta!=null,d=this._features.seasonal&&t.seasonal_factor&&t.seasonal_factor!==1;return!s&&!a&&!l&&!d?o`<div class="adaptive-empty">
${r("adaptive_no_data",n)}
</div>`:o`
<div class="adaptive-stack">
${this._toast?o`<div class="toast">${this._toast}</div>`:c}
${s?this._renderRecommendation(t):c}
${a?ne(t,n,this._features):c}
${l?ee(t,n):c}
${d?o`
${re(t,n,this._features)}
${t.seasonal_factors?.length===12||t.interval_analysis?.seasonal_factors?.length===12?ae(t,n):c}
`:c}
</div>
`}_renderDetails(t){let n=this._lang,s=t.history||[],a=t.history_count??s.length,l=ht(s).slice(0,20);return o`
<div class="details">
<div class="stats-grid">
<div class="stat">
<span class="stat-label">${r("times_performed",n)}</span>
<span class="stat-value">${t.times_performed??0}</span>
</div>
<div class="stat">
<span class="stat-label">${r("total_cost",n)}</span>
<span class="stat-value">${X(t.total_cost??0,this._currencySymbol,n)}</span>
</div>
<div class="stat">
<span class="stat-label">${r("avg_duration",n)}</span>
<span class="stat-value">${tt(t.average_duration!=null?Math.round(t.average_duration):null,n)}</span>
</div>
</div>
<div class="history-header">
<strong>${r("history",n)}</strong>
<span class="history-count">${a}</span>
</div>
${s.length===0?o`<div class="history-empty">${r("history_empty",n)}</div>`:o`
<div class="history-list">
${l.map(d=>mt(d,{lang:n,hass:this.hass,currencySymbol:this._currencySymbol,openEdit:q(this.hass?.user,this._access)?u=>this._onEditHistoryEntry(u):void 0,readingUnit:t.reading_unit,readingSlotDelta:(u,h)=>Mt(s,u,h),taskRef:this._taskRef},{compact:!0}))}
${a>l.length?o`<div class="history-more">… +${a-l.length} ${r("older_entries",n)}</div>`:c}
</div>
`}
</div>
`}render(){if(!this._open)return c;let t=this._lang,n=this._task,s=q(this.hass?.user,this._access);return F(()=>this.close(),o`
${n?o`
<div class="header">
<div class="title">
<span class="status-dot" style="background: ${rt(n)}"></span>
<span class="task-name">${n.name}</span>
${te(n,t)}
</div>
<div class="object">
<button class="link-inline" @click=${()=>{this._entryId&&import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-H6J55EII.js").then(({openObjectQuickActions:a})=>{a(this._entryId),this.close()})}}>${this._objectName}</button>
</div>
<div class="quick-info">
${n.next_due?o`<span><strong>${r("next_due",t)}:</strong> ${G(n.next_due,t)}</span>`:c}
${n.last_performed?o`<span><strong>${r("last_performed",t)}:</strong> ${G(n.last_performed,t)}</span>`:c}
${n.schedule?.kind&&!["manual","one_time"].includes(n.schedule.kind)||n.interval_days!=null?o`<span><strong>${r("interval",t)}:</strong> ${Tt(n,t)}</span>`:c}
${B(n)?o`<span><strong>${r("phase_current",t)}:</strong> ${B(n)}</span>`:c}
</div>
</div>
${this._error?o`<div class="error">${this._error}</div>`:c}
${this._showSkip?o`
<div class="inline-form">
<label>${r("skip_reason",t)}</label>
<input type="text" .value=${this._skipReason}
@input=${a=>{this._skipReason=a.target.value}} />
<div class="inline-actions">
<button class="btn cancel" @click=${()=>{this._showSkip=!1}} ?disabled=${this._busy}>
${r("cancel",t)}
</button>
<button class="btn primary" @click=${this._onSkipConfirm} ?disabled=${this._busy}>
${r("skip",t)}
</button>
</div>
</div>
`:this._showReset?o`
<div class="inline-form">
<label>${r("reset_to_date",t)}</label>
<ms-date-field
kind="date"
.hass=${this.hass}
.lang=${t}
.value=${this._resetDate}
@value-changed=${a=>{this._resetDate=a.detail.value}}
></ms-date-field>
<div class="inline-actions">
<button class="btn cancel" @click=${()=>{this._showReset=!1}} ?disabled=${this._busy}>
${r("cancel",t)}
</button>
<button class="btn primary" @click=${this._onResetConfirm} ?disabled=${this._busy}>
${r("reset",t)}
</button>
</div>
</div>
`:o`
<div class="actions primary-row">
<ha-button appearance="accent" variant="success" @click=${this._onComplete} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:check"></ha-icon>
${r("complete",t)}
</ha-button>
${n.allow_skip!==!1?o`
<ha-button appearance="outlined" variant="warning" @click=${()=>{this._showSkip=!0}} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:skip-next"></ha-icon>
${r("skip",t)}
</ha-button>
`:c}
<ha-button appearance="outlined" variant="neutral" @click=${()=>{this._showReset=!0}} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:restart"></ha-icon>
${r("reset",t)}
</ha-button>
</div>
<!-- QR is read tier (the panel offers it to operators too);
Edit / Archive / Delete follow canWrite() — the panel's
operator delegation, not is_admin alone. -->
<div class="actions secondary-row">
${s?o`<ha-button size="small" appearance="outlined" variant="neutral" class="qa-edit" @click=${this._onEdit} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:pencil"></ha-icon>
${r("edit",t)}
</ha-button>`:c}
<ha-button size="small" appearance="outlined" variant="neutral" class="qa-qr" @click=${this._onQr} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:qrcode"></ha-icon>
${r("qr_code",t)}
</ha-button>
${s?o`<ha-button size="small" appearance="outlined" variant="neutral" class="qa-archive"
@click=${n.archived?this._onUnarchive:this._onArchive}
.disabled=${this._busy}>
<ha-icon slot="start" icon="${n.archived?"mdi:archive-arrow-up-outline":"mdi:archive-outline"}"></ha-icon>
${n.archived?r("unarchive",t):r("archive",t)}
</ha-button>
<ha-button size="small" appearance="outlined" variant="danger" class="danger qa-delete" @click=${this._onDelete} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:delete"></ha-icon>
${r("delete",t)}
</ha-button>`:c}
</div>
<div class="details-toggle">
<button class="link" @click=${()=>{this._showDetails=!this._showDetails}}>
<ha-icon icon="${this._showDetails?"mdi:chevron-up":"mdi:chevron-down"}"></ha-icon>
${this._showDetails?r("hide_details",t):r("show_details",t)}
</button>
${this._features.adaptive||this._features.seasonal||this._features.environmental?o`<button class="link" @click=${()=>{this._showAdaptive=!this._showAdaptive}}>
<ha-icon icon="${this._showAdaptive?"mdi:chart-line":"mdi:chart-line-variant"}"></ha-icon>
${this._showAdaptive?r("hide_stats",t):r("show_stats",t)}
</button>`:c}
</div>
${this._showDetails?this._renderDetails(n):c}
${this._showAdaptive?this._renderAdaptive(n):c}
<div class="footer">
<button class="link" @click=${this._onOpenInPanel}>
<ha-icon icon="mdi:open-in-new"></ha-icon>
${r("open_in_panel",t)}
</button>
</div>
`}
`:this._error?o`<div class="error">${this._error}</div>`:o`<div class="loading">${r("loading",t)}</div>`}
`)}updated(t){t.has("_open")&&this._open&&W(this.shadowRoot)}};g.styles=[Lt,z,$`
:host { display: contents; --ms-modal-max-width: 460px; }
.header { display: flex; flex-direction: column; gap: 6px; }
.title { display: flex; align-items: center; gap: 10px; }
.status-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
.task-name { font-size: 18px; font-weight: 600; }
.object { font-size: 13px; color: var(--secondary-text-color); }
.link-inline {
background: transparent; border: none; padding: 0; cursor: pointer;
color: var(--primary-color); font-size: inherit; font-family: inherit;
}
.link-inline:hover { text-decoration: underline; }
.quick-info {
display: flex; flex-wrap: wrap; gap: 12px;
font-size: 12px; color: var(--secondary-text-color);
padding-top: 4px; border-top: 1px solid var(--divider-color);
}
.quick-info strong { color: var(--primary-text-color); font-weight: 500; }
.actions { display: flex; gap: 8px; }
.actions.primary-row { gap: 6px; }
.actions.primary-row .btn { flex: 1; }
.actions.primary-row ha-button { flex: 1; }
/* Edit + QR are admin-tools — left-align as a group; Delete is destructive
so it gets pushed to the far right with margin-left:auto for visual
separation. Earlier this row was flex-end which left a strange empty
gap on the left (user feedback). */
.actions.secondary-row {
padding-top: 8px; border-top: 1px solid var(--divider-color);
justify-content: flex-start;
}
.actions.secondary-row .btn.danger,
.actions.secondary-row ha-button.danger {
margin-left: auto;
}
.actions.secondary-row ha-button { --ha-button-font-size: 13px; }
.btn {
padding: 8px 12px; font-size: 14px;
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: 6px;
transition: background 0.12s;
}
.btn:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
.btn[disabled] { opacity: 0.5; cursor: wait; }
.btn.primary {
background: var(--primary-color);
color: var(--text-primary-color, white);
border-color: var(--primary-color);
}
.btn.cancel { background: transparent; }
.btn.ghost { padding: 6px 10px; font-size: 13px; }
.btn.danger { color: var(--error-color); }
.btn ha-icon { --mdc-icon-size: 18px; }
.inline-form { display: flex; flex-direction: column; gap: 8px; }
.inline-form label { font-size: 13px; color: var(--secondary-text-color); }
.inline-form input {
padding: 8px; font-size: 14px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color, #444);
border-radius: 6px;
}
.inline-actions { display: flex; gap: 8px; justify-content: flex-end; }
.footer { display: flex; justify-content: center; padding-top: 4px; }
.link {
background: transparent; border: none; cursor: pointer;
color: var(--primary-color); font-size: 13px;
display: inline-flex; align-items: center; gap: 4px;
}
.link:hover { text-decoration: underline; }
.link ha-icon { --mdc-icon-size: 14px; }
.loading { padding: 24px; text-align: center; color: var(--secondary-text-color); }
.error {
padding: 8px; border-radius: 6px;
background: rgba(211,47,47,0.1);
color: var(--error-color, #d32f2f); font-size: 13px;
}
/* Details (expandable Show details section) */
.details-toggle { display: flex; justify-content: center; margin-top: 4px; }
.details {
display: flex; flex-direction: column; gap: 12px;
border-top: 1px solid var(--divider-color);
padding-top: 12px;
}
.stats-grid {
display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px;
}
.stat {
display: flex; flex-direction: column; gap: 2px;
background: var(--secondary-background-color, rgba(255,255,255,0.04));
padding: 8px; border-radius: 6px;
align-items: center;
}
.stat-label { font-size: 11px; color: var(--secondary-text-color); text-transform: uppercase; letter-spacing: 0.5px; }
.stat-value { font-size: 16px; font-weight: 600; }
.history-header {
display: flex; align-items: baseline; gap: 8px;
font-size: 14px;
}
.history-count {
font-size: 12px; color: var(--secondary-text-color);
background: var(--secondary-background-color); padding: 2px 8px; border-radius: 999px;
}
.history-empty { color: var(--secondary-text-color); font-style: italic; font-size: 13px; }
/* The rows themselves are the shared renderer's (.history-entry.compact
+ the history-* classes from sharedStyles); only the list chrome is
local. */
.history-list { display: flex; flex-direction: column; max-height: 280px; overflow: auto; }
.history-list .history-entry {
padding: 6px 8px; border-radius: 6px; border-bottom: none; margin-bottom: 6px;
background: var(--secondary-background-color, rgba(255,255,255,0.03));
}
.history-list .history-date { font-size: 11px; }
.history-list .history-details { font-size: 11px; }
.history-more { padding: 8px; text-align: center; font-size: 12px; color: var(--secondary-text-color); font-style: italic; }
/* Adaptive section — wraps the panel renderers (which assume sharedStyles
are present) and adds dialog-specific layout. */
.adaptive-stack {
display: flex; flex-direction: column; gap: 12px;
border-top: 1px solid var(--divider-color);
padding-top: 12px;
}
.adaptive-empty {
padding: 16px; text-align: center;
color: var(--secondary-text-color);
font-style: italic; font-size: 13px;
border-top: 1px solid var(--divider-color);
}
.toast {
padding: 8px 12px; border-radius: 6px;
background: rgba(76, 175, 80, 0.15);
color: #4caf50; font-size: 13px; font-weight: 500;
}
/* The panel's recommendation-card uses ha-button. We use plain <button>
in this dialog's button styles. Re-style the action row to match. */
.recommendation-actions {
display: flex; gap: 8px; margin-top: 8px;
}
/* Constrain SVG charts so they fit the dialog width even on mobile. */
.weibull-section, .seasonal-card-compact { max-width: 100%; }
.weibull-chart svg { max-width: 100%; height: auto; }
.details-toggle { gap: 12px; flex-wrap: wrap; }
`],p([w({attribute:!1})],g.prototype,"hass",2),p([m()],g.prototype,"_open",2),p([m()],g.prototype,"_entryId",2),p([m()],g.prototype,"_taskId",2),p([m()],g.prototype,"_task",2),p([m()],g.prototype,"_objectName",2),p([m()],g.prototype,"_taskRef",2),p([m()],g.prototype,"_busy",2),p([m()],g.prototype,"_error",2),p([m()],g.prototype,"_showSkip",2),p([m()],g.prototype,"_showReset",2),p([m()],g.prototype,"_showDetails",2),p([m()],g.prototype,"_showAdaptive",2),p([m()],g.prototype,"_skipReason",2),p([m()],g.prototype,"_resetDate",2),p([m()],g.prototype,"_features",2),p([m()],g.prototype,"_toast",2),p([m()],g.prototype,"_access",2);customElements.get("maintenance-task-quick-actions-dialog")||customElements.define("maintenance-task-quick-actions-dialog",g);function oe(e){return!!e&&/^https?:\/\//i.test(e)}function le(e){return e?customElements.get("ha-markdown")?o`<ha-markdown class="notes-md" .content=${e} breaks></ha-markdown>`:o`${e}`:c}var E=class extends L{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._data=null;this._busy=!1;this._error="";this._access=it}get _lang(){return T(this.hass)}async openFor(t){this._entryId=t,this._error="",this._open=!0,await Promise.all([this._load(),M(this.hass).then(n=>{this._access=n.access})])}close(){this._open=!1,this._data=null,this._error=""}async _load(){if(!this._entryId)return;let t=await I(this,{type:"maintenance_supporter/object",entry_id:this._entryId},{onError:n=>{this._error=n}});t!==void 0&&(this._data=t)}_runWs(t){return this._error="",I(this,t,{busy:n=>{this._busy=n},onError:n=>{this._error=n}})}_onEditObject(){!this._entryId||!this._data||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-H6J55EII.js").then(({openEditObjectDialog:t})=>{t(this._entryId,this._data.object),this.close()})}_onAddTask(){this._entryId&&import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-H6J55EII.js").then(({openCreateTaskDialog:t})=>{t(this._entryId),this.close()})}async _onDelete(){if(!this._entryId||!this._data||!await O(this.hass,{title:r("delete",this._lang),message:r("delete_object_confirm",this._lang),confirmText:r("delete",this._lang),danger:!0}))return;let n=this._entryId;await this._runWs({type:"maintenance_supporter/object/delete",entry_id:n})!==void 0&&(this.dispatchEvent(new CustomEvent("object-deleted",{detail:{entry_id:n},bubbles:!0,composed:!0})),this.close())}async _onArchiveObject(){if(!this._entryId||!this._data)return;let t=!!this._data.object.archived;if(!t&&!await O(this.hass,{title:r("archive_object",this._lang),message:r("confirm_archive_object",this._lang),confirmText:r("archive_object",this._lang)}))return;let n=this._entryId;await this._runWs({type:t?"maintenance_supporter/object/unarchive":"maintenance_supporter/object/archive",entry_id:n})!==void 0&&(this.dispatchEvent(new CustomEvent("object-changed",{detail:{entry_id:n},bubbles:!0,composed:!0})),this.close())}_onTaskClick(t){this._entryId&&import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-H6J55EII.js").then(({openTaskQuickActions:n})=>{n(this._entryId,t)})}render(){if(!this._open)return c;let t=this._lang,n=this._data,s=n?.object,a=n?.tasks||[],l=q(this.hass?.user,this._access);return F(()=>this.close(),o`
${n&&s?o`
<div class="header">
<div class="title">${s.name}</div>
${this._renderMetaRow(s)}
</div>
${this._error?o`<div class="error">${this._error}</div>`:c}
<div class="tasks-section">
<div class="section-header">
<strong>${r("tasks",t)}</strong>
<span class="count">${a.length}</span>
</div>
${a.length===0?o`<div class="empty">${r("no_tasks",t)}</div>`:o`
<div class="task-list">
${a.map(d=>o`
<div class="task-row" @click=${()=>this._onTaskClick(d.id)}>
<span class="status-dot" style="background: ${rt(d)}"></span>
<span class="task-name">${d.name}</span>
<span class="task-status ${K(d)}">${_t(K(d),t)}</span>
</div>
`)}
</div>
`}
</div>
${s.notes?o`
<div class="notes-section">
<strong>${r("object_notes_label",t)}</strong>
<div class="notes-body">${le(s.notes)}</div>
</div>
`:c}
${l?o`
<div class="actions">
<button class="btn primary" @click=${this._onAddTask} ?disabled=${this._busy}>
<ha-icon icon="mdi:plus"></ha-icon>
${r("add_task",t)}
</button>
<button class="btn" @click=${this._onEditObject} ?disabled=${this._busy}>
<ha-icon icon="mdi:pencil"></ha-icon>
${r("edit",t)}
</button>
<button class="btn" @click=${this._onArchiveObject} ?disabled=${this._busy}>
<ha-icon icon="${s.archived?"mdi:archive-arrow-up-outline":"mdi:archive-outline"}"></ha-icon>
${s.archived?r("unarchive_object",t):r("archive_object",t)}
</button>
<button class="btn danger" @click=${this._onDelete} ?disabled=${this._busy}>
<ha-icon icon="mdi:delete"></ha-icon>
${r("delete",t)}
</button>
</div>
`:c}
`:o`<div class="loading">${r("loading",t)}</div>`}
`)}updated(t){t.has("_open")&&this._open&&W(this.shadowRoot)}_renderMetaRow(t){let n=this._lang,s=[];return t.area_id&&s.push([r("area",n),t.area_id]),t.manufacturer&&s.push([r("manufacturer",n),t.manufacturer]),t.model&&s.push([r("model",n),t.model]),t.serial_number&&s.push([r("serial_number_label",n),t.serial_number]),t.installation_date&&s.push([r("installed",n),t.installation_date]),t.warranty_expiry&&s.push([r("warranty",n),t.warranty_expiry]),t.documentation_url&&s.push([r("documentation_url_label",n),t.documentation_url]),s.length===0?c:o`
<div class="meta">
${s.map(([a,l])=>o`
<div class="meta-item">
<span class="meta-label">${a}</span>
<span class="meta-value">${oe(l)?o`<a href="${l}" target="_blank" rel="noopener noreferrer">${l}</a>`:l}</span>
</div>
`)}
</div>
`}};E.styles=[z,$`
:host { display: contents; }
.header { display: flex; flex-direction: column; gap: 6px; }
.title { font-size: 20px; font-weight: 600; }
.meta { display: flex; flex-direction: column; gap: 4px; padding-top: 4px; border-top: 1px solid var(--divider-color); }
.meta-item { display: flex; gap: 8px; font-size: 12px; }
.meta-label { color: var(--secondary-text-color); min-width: 100px; }
.meta-value { color: var(--primary-text-color); flex: 1; word-break: break-word; }
.meta-value a { color: var(--primary-color); }
.tasks-section, .notes-section { display: flex; flex-direction: column; gap: 6px; }
.section-header { display: flex; align-items: baseline; gap: 8px; }
.count {
font-size: 11px; color: var(--secondary-text-color);
background: var(--secondary-background-color); padding: 2px 8px; border-radius: 999px;
}
.empty { color: var(--secondary-text-color); font-style: italic; font-size: 13px; padding: 8px 0; }
.task-list { display: flex; flex-direction: column; gap: 4px; max-height: 200px; overflow: auto; }
.task-row {
display: flex; align-items: center; gap: 10px;
padding: 8px; border-radius: 6px; cursor: pointer;
background: var(--secondary-background-color, rgba(255,255,255,0.03));
transition: background 0.12s;
}
.task-row:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
.status-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.task-name { flex: 1; font-size: 14px; }
.task-status { font-size: 11px; color: var(--secondary-text-color); text-transform: uppercase; }
.notes-body { white-space: pre-wrap; font-size: 13px; padding: 8px; background: var(--secondary-background-color); border-radius: 6px; }
.notes-body ha-markdown { white-space: normal; }
.actions { display: flex; gap: 8px; padding-top: 8px; border-top: 1px solid var(--divider-color); }
.actions .btn { flex: 1; }
.btn {
padding: 8px; 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; justify-content: center; gap: 6px;
}
.btn:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
.btn[disabled] { opacity: 0.5; cursor: wait; }
.btn.primary { background: var(--primary-color); color: var(--text-primary-color, white); border-color: var(--primary-color); }
.btn.danger { color: var(--error-color); }
.btn ha-icon { --mdc-icon-size: 16px; }
.loading { padding: 24px; text-align: center; color: var(--secondary-text-color); }
.error { padding: 8px; border-radius: 6px; background: rgba(211,47,47,0.1); color: var(--error-color); font-size: 13px; }
`],p([w({attribute:!1})],E.prototype,"hass",2),p([m()],E.prototype,"_open",2),p([m()],E.prototype,"_entryId",2),p([m()],E.prototype,"_data",2),p([m()],E.prototype,"_busy",2),p([m()],E.prototype,"_error",2),p([m()],E.prototype,"_access",2);customElements.get("maintenance-object-quick-actions-dialog")||customElements.define("maintenance-object-quick-actions-dialog",E);var de="maintenance-object-dialog",ce="maintenance-task-dialog",We="maintenance-history-edit-dialog",Ve="maintenance-complete-dialog",Ue="maintenance-qr-dialog",Ge="maintenance-task-quick-actions-dialog",Be="maintenance-object-quick-actions-dialog";function at(){return document.querySelector("home-assistant")?.hass}function Ke(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function H(e){let i=Ke(),t=i.querySelector(e)??document.body.querySelector(e);return t?t.parentNode!==i&&i.appendChild(t):(t=document.createElement(e),i.appendChild(t)),t}function P(e){let i=at();if(!i)return!1;e.hass=i;let t=T(i);return yt(t)||vt(t).then(()=>{e.requestUpdate?.()}),xt(i.locale,i.config?.country),!0}function vs(e){return M(e).then(i=>i.rowActionStyle)}function bs(){Ct()}function xs(){let e=H(de);return P(e)?(e.openCreate(),!0):!1}function $s(e,i){let t=H(de);return P(t)?(t.openEdit(e,i),!0):!1}function ks(e="",i){let t=H(ce);if(!P(t))return!1;let n=at();return n?((async()=>{let s=await M(n),a=t;a.checklistsEnabled=s.features.checklists,a.scheduleTimeEnabled=s.features.schedule_time,a.completionActionsEnabled=s.features.completion_actions,a.defaultWarningDays=s.defaultWarningDays,a.openCreate(e,i)})(),!0):!1}function ws(e,i){let t=H(ce);if(!P(t))return!1;let n=at();return n?((async()=>{try{let[s,a]=await Promise.all([n.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:e}),M(n)]),l=(s.tasks||[]).find(u=>u.id===i);if(!l){console.warn(`openEditTaskDialog: task ${i} not found in entry ${e}`);return}let d=t;d.checklistsEnabled=a.features.checklists,d.scheduleTimeEnabled=a.features.schedule_time,d.completionActionsEnabled=a.features.completion_actions,d.defaultWarningDays=a.defaultWarningDays,await d.openEdit(e,l)}catch(s){console.warn("openEditTaskDialog: failed to load task/features",s)}})(),!0):!1}function Ts(e){let i=H(We);return P(i)?(i.openEdit(e),!0):!1}function Es(e){let i=H(Ve);return P(i)?(Wt(i,e,T(at())),!0):!1}function As(e){let i=H(Ue);return P(i)?(i.openForTask(e.entry_id,e.task_id,e.object_name,e.task_name),!0):!1}function Ls(e,i){let t=H(Ge);return P(t)?(t.openFor(e,i),!0):!1}function Ss(e){let i=H(Be);return P(i)?(i.openFor(e),!0):!1}export{oe as a,Le as b,He as c,xe as d,Ut as e,On as f,Gt as g,le as h,ye as i,ve as j,ct as k,Ft as l,Wt as m,_ as n,ei as o,ni as p,ii as q,si as r,ri as s,ai as t,oi as u,pt as v,Mn as w,ht as x,Bn as y,Kn as z,mt as A,te as B,ee as C,ne as D,ie as E,re as F,ae as G,vs as H,bs as I,xs as J,$s as K,ks as L,ws as M,Ts as N,Es as O,As as P,Ls as Q,Ss as R};
@@ -1,2 +1,2 @@
/*! maintenance_supporter frontend 2.94.0 */
import{s as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-JE577H3E.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};
/*! maintenance_supporter frontend 2.97.1 */
import{s as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YJXVPPWG.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};
@@ -1,5 +1,5 @@
/*! maintenance_supporter frontend 2.96.0 */
import{a as F,d as Q,i as K,j as Y,k as ee,l as M,m as U}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-MHBW3M6D.js";import{e as J}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4PTWLV7V.js";import{d as X,e as Z,f as T,g as w,h as I,i as H,j as O}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WJT4RRLS.js";import{a as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-BFBOHWBW.js";import{B as L,F as N,K as R,L as W,a as o,b as z,c as l,f as h,h as V,l as $,m as d,s,y as G}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-N6F5RX6S.js";var B=["sensor","binary_sensor","number","input_number","input_boolean","switch","climate","vacuum","cover","fan","light","water_heater","humidifier","media_player","weather","air_quality","valve","lawn_mower","lock"],te=["sensor"],ie=["temperature","humidity","pressure"];var _e={cleaning:"mdi:broom",inspection:"mdi:magnify",replacement:"mdi:swap-horizontal",calibration:"mdi:tune",service:"mdi:wrench",reading:"mdi:counter",custom:"mdi:wrench-clock"},ce="mdi:wrench-clock",D=c=>c&&_e[c]||ce;var ue=["cleaning","inspection","replacement","calibration","service","reading","custom"],ge=["low","normal","high"],me=["time_based","weekdays","nth_weekday","day_of_month","calendar","sensor_based","one_time","manual"],C=["weekdays","nth_weekday","day_of_month","calendar"],se=["time_based","one_time",...C],ne=["threshold","counter","state_change","runtime","due_date"],re=(c,g)=>s(c==="due_date"?"trigger_type_due_date":c,g),ve=[...ne,"compound"],E={alpha:"0.3",min:"7",max:"365"},x=O;function ae(){return{entityIds:"",type:"threshold",attribute:"",above:"",below:"",equals:"",notEquals:"",forMinutes:"0",targetValue:"",deltaMode:!1,fromState:"",toState:"",targetChanges:"",runtimeHours:"",onStates:"",daysBefore:"0",carry:{}}}var fe=new Set(["entity_id","entity_ids","type","attribute","trigger_above","trigger_below","trigger_equals","trigger_not_equals","trigger_for_minutes","trigger_target_value","trigger_delta_mode","trigger_from_state","trigger_to_state","trigger_target_changes","trigger_runtime_hours","trigger_on_states","trigger_days_before"]);function oe(c){return{type:c.type||"threshold",attribute:c.attribute||"",above:c.trigger_above?.toString()??"",below:c.trigger_below?.toString()??"",equals:c.trigger_equals?.toString()??"",notEquals:c.trigger_not_equals?.toString()??"",forMinutes:c.trigger_for_minutes?.toString()??"0",targetValue:c.trigger_target_value?.toString()??"",deltaMode:c.trigger_delta_mode||!1,fromState:c.trigger_from_state||"",toState:c.trigger_to_state||"",targetChanges:c.trigger_target_changes?.toString()??"",runtimeHours:c.trigger_runtime_hours?.toString()??"",onStates:(c.trigger_on_states||[]).join(", "),daysBefore:c.trigger_days_before?.toString()??"0"}}function le(c,g){g.attribute&&(c.attribute=g.attribute);let e=parseInt(g.forMinutes,10);if(g.type==="threshold"){let i=parseFloat(g.above);isNaN(i)||(c.trigger_above=i);let t=parseFloat(g.below);isNaN(t)||(c.trigger_below=t);let r=parseFloat(g.equals);isNaN(r)||(c.trigger_equals=r);let a=parseFloat(g.notEquals);isNaN(a)||(c.trigger_not_equals=a),isNaN(e)||(c.trigger_for_minutes=e)}else if(g.type==="counter"){let i=parseFloat(g.targetValue);isNaN(i)||(c.trigger_target_value=i),c.trigger_delta_mode=g.deltaMode}else if(g.type==="state_change"){g.fromState&&(c.trigger_from_state=g.fromState),g.toState&&(c.trigger_to_state=g.toState);let i=parseInt(g.targetChanges,10);isNaN(i)||(c.trigger_target_changes=i),isNaN(e)||(c.trigger_for_minutes=e)}else if(g.type==="runtime"){let i=parseFloat(g.runtimeHours);isNaN(i)||(c.trigger_runtime_hours=i);let t=(g.onStates||"").split(",").map(r=>r.trim()).filter(Boolean);t.length>0&&(c.trigger_on_states=t)}else if(g.type==="due_date"){let i=parseInt(g.daysBefore,10);c.trigger_days_before=isNaN(i)?0:i}}function ye(c){return{entityIds:(c.entity_ids||(c.entity_id?[c.entity_id]:[])).join(", "),...oe(c),carry:Object.fromEntries(Object.entries(c).filter(([e])=>!fe.has(e)&&!e.startsWith("_")))}}function be(c){let g=c.entityIds.split(",").map(i=>i.trim()).filter(Boolean);if(g.length===0)return null;let e={...c.carry||{},entity_id:g[0],entity_ids:g,type:c.type};return le(e,c),e}function $e(c){return Array.from({length:7},(g,e)=>R(e,c,"short"))}function Ee(c){return Array.from({length:12},(g,e)=>W(e,c,"short"))}var n=class n extends V{constructor(){super(...arguments);this.checklistsEnabled=!1;this.scheduleTimeEnabled=!1;this.completionActionsEnabled=!1;this.adaptiveFeature=!1;this.seasonalFeature=!1;this.environmentalFeature=!1;this.defaultWarningDays=7;this.parts=[];this._foreignOwners=[];this._open=!1;this._entityPickerFallback=!1;this._pickerProbeStrikes=0;this._loading=!1;this._error="";this._warning="";this._entryId="";this._taskId=null;this._isFleetTask=!1;this._objectChoices=[];this._name="";this._type="custom";this._scheduleType="time_based";this._intervalDays="30";this._intervalUnit="days";this._dueDate="";this._warningDays="7";this._earliestCompLine truncated
/*! maintenance_supporter frontend 2.97.1 */
import{a as F,d as Q,i as K,j as Y,k as ee,l as M,m as U}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-2CZ4LD2Q.js";import{e as J}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-D4KM62SJ.js";import{d as X,e as Z,f as T,g as w,h as I,i as H,j as O}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GSRF4WCQ.js";import{a as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GVLO7RZ4.js";import{B as L,F as N,K as R,L as W,a as o,b as z,c as l,f as h,h as V,l as $,m as d,s,y as G}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YJXVPPWG.js";var B=["sensor","binary_sensor","number","input_number","input_boolean","switch","climate","vacuum","cover","fan","light","water_heater","humidifier","media_player","weather","air_quality","valve","lawn_mower","lock"],te=["sensor"],ie=["temperature","humidity","pressure"];var _e={cleaning:"mdi:broom",inspection:"mdi:magnify",replacement:"mdi:swap-horizontal",calibration:"mdi:tune",service:"mdi:wrench",reading:"mdi:counter",custom:"mdi:wrench-clock"},ce="mdi:wrench-clock",D=c=>c&&_e[c]||ce;var ue=["cleaning","inspection","replacement","calibration","service","reading","custom"],ge=["low","normal","high"],me=["time_based","weekdays","nth_weekday","day_of_month","calendar","sensor_based","one_time","manual"],C=["weekdays","nth_weekday","day_of_month","calendar"],se=["time_based","one_time",...C],ne=["threshold","counter","state_change","runtime","due_date"],re=(c,g)=>s(c==="due_date"?"trigger_type_due_date":c,g),ve=[...ne,"compound"],E={alpha:"0.3",min:"7",max:"365"},x=O;function ae(){return{entityIds:"",type:"threshold",attribute:"",above:"",below:"",equals:"",notEquals:"",forMinutes:"0",targetValue:"",deltaMode:!1,fromState:"",toState:"",targetChanges:"",runtimeHours:"",onStates:"",daysBefore:"0",carry:{}}}var fe=new Set(["entity_id","entity_ids","type","attribute","trigger_above","trigger_below","trigger_equals","trigger_not_equals","trigger_for_minutes","trigger_target_value","trigger_delta_mode","trigger_from_state","trigger_to_state","trigger_target_changes","trigger_runtime_hours","trigger_on_states","trigger_days_before"]);function oe(c){return{type:c.type||"threshold",attribute:c.attribute||"",above:c.trigger_above?.toString()??"",below:c.trigger_below?.toString()??"",equals:c.trigger_equals?.toString()??"",notEquals:c.trigger_not_equals?.toString()??"",forMinutes:c.trigger_for_minutes?.toString()??"0",targetValue:c.trigger_target_value?.toString()??"",deltaMode:c.trigger_delta_mode||!1,fromState:c.trigger_from_state||"",toState:c.trigger_to_state||"",targetChanges:c.trigger_target_changes?.toString()??"",runtimeHours:c.trigger_runtime_hours?.toString()??"",onStates:(c.trigger_on_states||[]).join(", "),daysBefore:c.trigger_days_before?.toString()??"0"}}function le(c,g){g.attribute&&(c.attribute=g.attribute);let e=parseInt(g.forMinutes,10);if(g.type==="threshold"){let i=parseFloat(g.above);isNaN(i)||(c.trigger_above=i);let t=parseFloat(g.below);isNaN(t)||(c.trigger_below=t);let r=parseFloat(g.equals);isNaN(r)||(c.trigger_equals=r);let a=parseFloat(g.notEquals);isNaN(a)||(c.trigger_not_equals=a),isNaN(e)||(c.trigger_for_minutes=e)}else if(g.type==="counter"){let i=parseFloat(g.targetValue);isNaN(i)||(c.trigger_target_value=i),c.trigger_delta_mode=g.deltaMode}else if(g.type==="state_change"){g.fromState&&(c.trigger_from_state=g.fromState),g.toState&&(c.trigger_to_state=g.toState);let i=parseInt(g.targetChanges,10);isNaN(i)||(c.trigger_target_changes=i),isNaN(e)||(c.trigger_for_minutes=e)}else if(g.type==="runtime"){let i=parseFloat(g.runtimeHours);isNaN(i)||(c.trigger_runtime_hours=i);let t=(g.onStates||"").split(",").map(r=>r.trim()).filter(Boolean);t.length>0&&(c.trigger_on_states=t)}else if(g.type==="due_date"){let i=parseInt(g.daysBefore,10);c.trigger_days_before=isNaN(i)?0:i}}function ye(c){return{entityIds:(c.entity_ids||(c.entity_id?[c.entity_id]:[])).join(", "),...oe(c),carry:Object.fromEntries(Object.entries(c).filter(([e])=>!fe.has(e)&&!e.startsWith("_")))}}function be(c){let g=c.entityIds.split(",").map(i=>i.trim()).filter(Boolean);if(g.length===0)return null;let e={...c.carry||{},entity_id:g[0],entity_ids:g,type:c.type};return le(e,c),e}function $e(c){return Array.from({length:7},(g,e)=>R(e,c,"short"))}function Ee(c){return Array.from({length:12},(g,e)=>W(e,c,"short"))}var n=class n extends V{constructor(){super(...arguments);this.checklistsEnabled=!1;this.scheduleTimeEnabled=!1;this.completionActionsEnabled=!1;this.adaptiveFeature=!1;this.seasonalFeature=!1;this.environmentalFeature=!1;this.defaultWarningDays=7;this.parts=[];this._foreignOwners=[];this._open=!1;this._entityPickerFallback=!1;this._pickerProbeStrikes=0;this._loading=!1;this._error="";this._warning="";this._entryId="";this._taskId=null;this._isFleetTask=!1;this._objectChoices=[];this._name="";this._type="custom";this._scheduleType="time_based";this._intervalDays="30";this._intervalUnit="days";this._dueDate="";this._warningDays="7";this._earliestCompLine truncated
`),this._phaseDefs=Object.entries(i.phases||{}).map(([p,m])=>{let{name:y,checklist:f,consumes_parts:v,required_completion_fields:b,...de}=m,A=m.consumes_parts||[],q=A.findIndex(S=>!S.entry_id),P=q>=0?A[q]:void 0;return{id:p,name:m.name||p,checklistText:(m.checklist||[]).join(`
`),partId:P?.part_id||"",partQty:P?.quantity!=null?String(P.quantity):"",reqOverride:m.required_completion_fields!==void 0,reqFields:[...m.required_completion_fields||[]],extraParts:A.filter((S,he)=>he!==q).map(S=>({...S})),carry:de}}),this._phaseSeq=[...i.phase_sequence||[]],this._requiredCompletion=[...i.required_completion_fields||[]],this._scheduleTime=i.schedule_time||"",this._scheduleTimeOn=!!i.schedule_time;let a=i.on_complete_action;if(a&&a.service){this._actionService=a.service;let p=a.target?.entity_id;this._actionTargetEntity=Array.isArray(p)?p[0]||"":p||"",this._actionTargetStored=a.target&&typeof a.target=="object"?JSON.parse(JSON.stringify(a.target)):null,this._actionTargetInitial=this._actionTargetEntity,this._actionData=a.data&&typeof a.data=="object"?{...a.data}:{},this._actionDataJsonFallback="",this._actionSkipAuto=a.skip_auto===!0,this._actionPresent=!0}else this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1;let _=i.quick_complete_defaults;this._qcNotes=_?.notes||"",this._qcCost=_?.cost!=null?String(_.cost):"",this._qcDuration=_?.duration!=null?String(_.duration):"",this._qcFeedback=_?.feedback||"";let u=i.adaptive_config||{};if(this._environmentalEntity=u.environmental_entity||"",this._environmentalAttribute=u.environmental_attribute||"",this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute,this._adaptiveEnabled=!!u.enabled,this._adaptiveAlpha=u.ewa_alpha?.toString()??E.alpha,this._adaptiveMin=u.min_interval_days?.toString()??E.min,this._adaptiveMax=u.max_interval_days?.toString()??E.max,this._adaptiveSeasonal=u.seasonal_enabled!==!1,this._adaptivePrediction=u.sensor_prediction_enabled!==!1,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=this._adaptiveEnabled,i.trigger_config){let p=i.trigger_config;this._triggerEntityId=p.entity_id||p.entity_ids&&p.entity_ids[0]||"",this._triggerEntityIds=p.entity_ids||(p.entity_id?[p.entity_id]:[]),this._triggerEntityLogic=p.entity_logic||"any",this._setTypeFields(oe(p)),this._triggerCombinator=p.trigger_combinator==="all"?"all":"any",this._triggerBaselineValue=p.trigger_baseline_value?.toString()||"",this._liveBaselineValue=i.trigger_baseline_value??null,this._autoCompleteOnRecovery=p.auto_complete_on_recovery||!1,this._triggerRuntimeMaxSession=p.trigger_runtime_max_session_seconds?.toString()||"",p.type==="compound"?(this._compoundLogic=p.compound_logic==="OR"?"OR":"AND",this._compoundConditions=(p.conditions||[]).map(ye)):(this._compoundLogic="AND",this._compoundConditions=[])}else this._resetTriggerFields();this._triggerEntityId&&this._fetchEntityAttributes(this._triggerEntityId),await Promise.all([this._loadUsers(),this._loadTags(),this._loadParts(),this._loadForeignPools()]),this._open=!0}_resetFields(){this._name="",this._type="custom",this._scheduleType="time_based",this._intervalDays="30",this._intervalUnit="days",this._dueDate="",this._warningDays=String(this.defaultWarningDays),this._earliestCompletionDays="",this._intervalAnchor="completion",this._weekdays=[],this._nth="1",this._nthWeekday="5",this._domDay="1",this._domLastDay=!1,this._domBusiness=!1,this._calOffset="0",this._seasonMonths=[],this._endsMode="never",this._endsCount="",this._endsUntil="",this._notes="",this._documentationUrl="",this._customIcon="",this._notifyIcon="",this._priority="normal",this._labels="",this._mirrorTodoEntities=[],this._enabled=!0,this._lastPerformed="",this._nfcTagId="",this._requireTagScan=!1,this._allowSkip=!0,this._readingUnit="",this._readings=[],this._consumesParts={},this._consumesQtyText={},this._responsibleUserId=null,this._assigneePool=[],this._rotationStrategy="",this._checklistText="",this._phaseDefs=[],this._phaseSeq=[],this._requiredCompletion=[],this._scheduleTime="",this._scheduleTimeOn=!1,this._environmentalEntity="",this._environmentalAttribute="",this._environmentalInitial="",this._environmentalAttributeInitial="",this._adaptiveEnabled=!1,this._adaptiveAlpha=E.alpha,this._adaptiveMin=E.min,this._adaptiveMax=E.max,this._adaptiveSeasonal=!0,this._adaptivePrediction=!0,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=!1,this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1,this._actionTesting=!1,this._actionTestResult="",this._qcNotes="",this._qcCost="",this._qcDuration="",this._qcFeedback="",this._resetTriggerFields()}_typeFields(){return{type:this._triggerType,attribute:this._triggerAttribute,above:this._triggerAbove,below:this._triggerBelow,equals:this._triggerEquals,notEquals:this._triggerNotEquals,forMinutes:this._triggerForMinutes,targetValue:this._triggerTargetValue,deltaMode:this._triggerDeltaMode,fromState:this._tr Line truncated
<details class="ca-section">
@@ -63,12 +63,11 @@ import{a as F,d as Q,i as K,j as Y,k as ee,l as M,m as U}from"/maintenance_suppo
.value=${this._qcNotes}
@input=${t=>{this._qcNotes=t.target.value}}
></ms-textfield>
<ms-textfield
label="${s("quick_complete_defaults_cost",e)}"
type="number" min="0" step="0.01"
.value=${this._qcCost}
@input=${t=>{this._qcCost=t.target.value}}
></ms-textfield>
<div class="qc-cost">
<span class="qc-cost-label">${s("quick_complete_defaults_cost",e)}</span>
<ms-cost-input .lang=${e} .value=${this._qcCost}
@value-changed=${t=>{this._qcCost=t.detail.value}}></ms-cost-input>
</div>
<ms-textfield
label="${s("quick_complete_defaults_duration",e)}"
type="number" min="0" step="1"
@@ -223,7 +222,7 @@ import{a as F,d as Q,i as K,j as Y,k as ee,l as M,m as U}from"/maintenance_suppo
`:h}
`}async _save(){if(!this._loading&&this._name.trim()){if(this._adaptiveSnapshot()!==this._adaptiveInitial){let e=parseInt(this._adaptiveMin,10),i=parseInt(this._adaptiveMax,10);if(!isNaN(e)&&!isNaN(i)&&e>i){this._error=`${s("adaptive_min_interval",this._lang)} > ${s("adaptive_max_interval",this._lang)}`;return}}if(this._triggerType==="threshold"&&this._thresholdLimitsOverlap()){this._error=s("trigger_hint_overlap",this._lang);return}if(this._scheduleType==="calendar"&&!this._calendarEntity.trim().startsWith("calendar.")){this._error=s("calendar_entity_required",this._lang);return}if(this._applyConsumesQtyText()){this._loading=!0,this._error="";try{let e=await k(this,()=>this.hass.connection.sendMessagePromise(this._savePayload()),{fallbackKey:"save_error",onError:a=>{this._error=a}});if(e===void 0)return;let i=this._taskId||e?.task_id,t=this._environmentalEntity!==this._environmentalInitial||this._environmentalAttribute!==this._environmentalAttributeInitial;this._warning="";let r=a=>{this._warning=s("subsave_warning",this._lang).replace("{detail}",a)};if(i&&this._scheduleType==="sensor_based"&&t&&await k(this,{type:"maintenance_supporter/task/set_environmental_entity",entry_id:this._entryId,task_id:i,environmental_entity:this._environmentalEntity||null,environmental_attribute:this._environmentalAttribute||null},{onError:r})!==void 0&&(this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute),i&&this._adaptiveSnapshot()!==this._adaptiveInitial){let a=parseFloat(this._adaptiveAlpha),_=parseInt(this._adaptiveMin,10),u=parseInt(this._adaptiveMax,10);await k(this,{type:"maintenance_supporter/task/set_adaptive",entry_id:this._entryId,task_id:i,enabled:this._adaptiveEnabled,...a>=I[0]&&a<=I[1]?{ewa_alpha:a}:{},...!isNaN(_)&&_>=1?{min_interval_days:_}:{},...!isNaN(u)&&u>=1?{max_interval_days:u}:{},seasonal_enabled:this._adaptiveSeasonal,sensor_prediction_enabled:this._adaptivePrediction},{onError:r})!==void 0&&(this._adaptiveInitial=this._adaptiveSnapshot())}this._warning?i&&(this._taskId=i):this._open=!1,this.dispatchEvent(new CustomEvent("task-saved"))}finally{this._loading=!1}}}}_savePayload(){let e={type:this._taskId?"maintenance_supporter/task/update":"maintenance_supporter/task/create",entry_id:this._entryId,name:this._name,task_type:this._type,schedule_type:this._scheduleType,warning_days:Number.isNaN(parseInt(this._warningDays,10))?this.defaultWarningDays:Math.max(0,parseInt(this._warningDays,10))},i=this._earliestCompletionDays.trim();e.earliest_completion_days=i===""?null:Math.max(0,parseInt(i,10)||0),this._taskId&&(e.task_id=this._taskId),this._scheduleType==="one_time"?(e.due_date=this._dueDate||null,e.interval_days=null):C.includes(this._scheduleType)?(e.schedule={...this._buildSchedule(),...this._recurrenceExtras()},e.interval_days=null,this._taskId&&(e.due_date=null)):(this._taskId&&(e.due_date=null),this._scheduleType!=="manual"&&this._intervalDays?(e.interval_days=parseInt(this._intervalDays,10),e.interval_unit=this._intervalUnit,e.interval_anchor=this._intervalAnchor,this._scheduleType==="time_based"&&(e.schedule={kind:"interval",...this._recurrenceExtras()})):this._taskId&&(e.interval_days=null,e.interval_anchor="completion")),e.notes=this._notes||null,e.documentation_url=this._documentationUrl||null,e.custom_icon=this._customIcon||null,e.notify_icon=this._notifyIcon.trim()||null,e.priority=this._priority,e.labels=this._labels.split(",").map(t=>t.trim()).filter(Boolean),e.mirror_todo_entities=this._mirrorTodoEntities.filter(Boolean),e.enabled=this._enabled,(!this._taskId||this._lastPerformed!==this._loadedLastPerformed)&&(e.last_performed=this._lastPerformed||null),e.nfc_tag_id=this._nfcTagId||null,e.require_tag_scan=this._requireTagScan,e.allow_skip=this._allowSkip,e.notify_enabled=this._notifyEnabled,e.reading_unit=this._readingUnit.trim()||null,e.readings=Y(this._readings);{let t={};for(let a of this._phaseDefs){if(!a.name.trim())continue;let _={...a.carry,name:a.name.trim()},u=a.checklistText.split(`
`).map(m=>m.trim()).filter(Boolean);u.length&&(_.checklist=u);let p=[];if(a.partId){let m=parseFloat(a.partQty);p.push({part_id:a.partId,quantity:Number.isFinite(m)&&m>0?m:1})}for(let m of a.extraParts)p.push(m.entry_id?{part_id:m.part_id,quantity:m.quantity,entry_id:m.entry_id}:{part_id:m.part_id,quantity:m.quantity});p.length&&(_.consumes_parts=p),a.reqOverride&&(_.required_completion_fields=[...a.reqFields]),t[a.id]=_}let r=this._phaseSeq.filter(a=>a in t);e.phases=Object.keys(t).length&&r.length?t:null,e.phase_sequence=e.phases?r:null}if((this.parts.length||this._foreignOwners.length)&&(e.consumes_parts=Object.values(this._consumesParts).map(t=>t.entry_id?{part_id:t.part_id,quantity:t.quantity,entry_id:t.entry_id}:{part_id:t.part_id,quantity:t.quantity})),(!this._taskId||this._responsibleUserId!==this._loadedResponsibleUserId)&&(e.responsible_user_id=this._responsibleUserId),e.assignee_pool=this._assigneePool,e.required_completion_fields=this._requiredCompletion,e.rotation_strategy=this._assigneePool.length>=2&&this._rotationStrategy?this._rotationStrategy:null,this._scheduleType==="sensor_based"&&this._triggerType==="compound"){let t=this._compoundConditions.map(be).filter(r=>r!==null);if(t.length>0){let r={type:"compound",compound_logic:this._compoundLogic,conditions:t};this._autoCompleteOnRecovery&&(r.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(r.trigger_combinator="all"),e.trigger_config=r}else this._taskId&&(e.trigger_config=null)}else if(this._scheduleType==="sensor_based"&&this._triggerEntityId){let t=this._triggerEntityIds.length>0?this._triggerEntityIds:[this._triggerEntityId],r={entity_id:t[0],entity_ids:t,type:this._triggerType};if(le(r,this._typeFields()),this._autoCompleteOnRecovery&&(r.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(r.trigger_combinator="all"),t.length>1&&(r.entity_logic=this._triggerEntityLogic),this._triggerType==="counter"&&this._triggerDeltaMode&&this._triggerBaselineValue){let a=parseFloat(this._triggerBaselineValue);!isNaN(a)&&a>=0&&(r.trigger_baseline_value=a)}else if(this._triggerType==="runtime"&&this._triggerRuntimeMaxSession){let a=parseInt(this._triggerRuntimeMaxSession,10);!isNaN(a)&&a>0&&(r.trigger_runtime_max_session_seconds=a)}e.trigger_config=r}else this._taskId&&(e.trigger_config=null);if(this.scheduleTimeEnabled&&se.includes(this._scheduleType)){let t=this._scheduleTimeOn?this._scheduleTime.trim():"";e.schedule_time=/^([01]\d|2[0-3]):[0-5]\d$/.test(t)?t:null}if(this.checklistsEnabled){let t=this._checklistText.split(`
`).map(r=>r.trim()).filter(Boolean).slice(0,100);e.checklist=t.length?t:null}if(this.completionActionsEnabled||this._actionPresent){let t=this._actionService.trim();if(t&&/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(t)){let r={service:t},a=this._actionTargetEntity.trim();this._actionTargetStored&&a===this._actionTargetInitial?r.target=JSON.parse(JSON.stringify(this._actionTargetStored)):a&&(r.target={entity_id:a});let _=this._buildActionData();Object.keys(_).length>0&&(r.data=_),this._actionSkipAuto&&(r.skip_auto=!0),e.on_complete_action=r}else e.on_complete_action=null}if(this.completionActionsEnabled){let t={};this._qcNotes.trim()&&(t.notes=this._qcNotes.trim());let r=parseFloat(this._qcCost);!isNaN(r)&&r>=0&&(t.cost=r);let a=ee(this._qcDuration);a!==null&&(t.duration=a),this._qcFeedback&&(t.feedback=this._qcFeedback),e.quick_complete_defaults=Object.keys(t).length?t:null}return e}_close(){this._open=!1,this._warning="",this._pickerProbeTimer!==void 0&&(clearTimeout(this._pickerProbeTimer),this._pickerProbeTimer=void 0),this._pickerProbeStrikes=0}_renderTriggerFields(){if(this._scheduleType!=="sensor_based")return h;let e=this._lang,i=this._triggerType==="compound";return l`
`).map(r=>r.trim()).filter(Boolean).slice(0,100);e.checklist=t.length?t:null}if(this.completionActionsEnabled||this._actionPresent){let t=this._actionService.trim();if(t&&/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(t)){let r={service:t},a=this._actionTargetEntity.trim();this._actionTargetStored&&a===this._actionTargetInitial?r.target=JSON.parse(JSON.stringify(this._actionTargetStored)):a&&(r.target={entity_id:a});let _=this._buildActionData();Object.keys(_).length>0&&(r.data=_),this._actionSkipAuto&&(r.skip_auto=!0),e.on_complete_action=r}else e.on_complete_action=null}if(this.completionActionsEnabled){let t={};this._qcNotes.trim()&&(t.notes=this._qcNotes.trim());let r=parseFloat(this._qcCost);isNaN(r)||(t.cost=r);let a=ee(this._qcDuration);a!==null&&(t.duration=a),this._qcFeedback&&(t.feedback=this._qcFeedback),e.quick_complete_defaults=Object.keys(t).length?t:null}return e}_close(){this._open=!1,this._warning="",this._pickerProbeTimer!==void 0&&(clearTimeout(this._pickerProbeTimer),this._pickerProbeTimer=void 0),this._pickerProbeStrikes=0}_renderTriggerFields(){if(this._scheduleType!=="sensor_based")return h;let e=this._lang,i=this._triggerType==="compound";return l`
<h3>${s("trigger_configuration",e)}</h3>
<div class="select-row">
<label>${s("trigger_type",e)}</label>
@@ -1331,6 +1330,8 @@ import{a as F,d as Q,i as K,j as Y,k as ee,l as M,m as U}from"/maintenance_suppo
font-weight: 500;
color: var(--secondary-text-color);
}
.qc-cost { display: flex; flex-direction: column; gap: 4px; margin: 8px 0; }
.qc-cost-label { font-size: 12px; color: var(--secondary-text-color); }
.field-help {
font-size: 12px;
color: var(--secondary-text-color);
@@ -1,2 +1,2 @@
/*! maintenance_supporter frontend 2.96.0 */
/*! maintenance_supporter frontend 2.97.1 */
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};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.95.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],a=[1,1e4],u=15,d=[.1,.9],s=[0,365],i=[.01,999],b=[.01,9999],A=[.1,5];export{n as a,o as b,t as c,_ as d,a as e,u as f,d as g,s as h,i,b as j,A as k};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.88.0 */
var l=[{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"}],i=l.map(a=>a.key),r=["name","manufacturer","model","serial_number","installation_date","warranty_expiry","area_id","task_count","actions"];function o(a){if(!Array.isArray(a))return[...r];let t=new Set,e=[];for(let n of a)typeof n=="string"&&i.includes(n)&&!t.has(n)&&(t.add(n),e.push(n));return e.length?(e.includes("name")||e.unshift("name"),e):[...r]}export{l as a,r as b,o as c};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.96.0 */
import{B as f,D as g,s as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-N6F5RX6S.js";function m(r){return`${r.entry_id??""}\0${r.part_id}`}function y(r,n,i,o){let e=!!r.entry_id&&r.entry_id!==n,t=e?r.entry_id:n,s=i.find(l=>l.entry_id===t),a=(s?.parts||[]).find(l=>l.id===r.part_id)||null,d=e&&s?.object?.name||"",u=a?.name||p("shared_part_unknown",o);return{part:a,foreign:e,ownerName:d,label:d?`${u} (${d})`:u}}function k(r,n,i,o){let{part:e,label:t}=y(r,n,i,o),s=e&&e.stock!==null&&e.stock!==void 0?` (${g(e.stock,e.unit,o)})`:"",a=e?.storage_location?` \u2014 ${e.storage_location}`:"";return`${f(r.quantity,o)}\xD7 ${t}${s}${a}`}function b(r,n,i,o){let t=(i.find(a=>a.entry_id===n)?.parts||[]).map(a=>({...a})),s=new Set(t.map(a=>m({part_id:a.id})));for(let a of r?.consumes_parts||[]){if(!a.entry_id||a.entry_id===n)continue;let d=m(a);if(s.has(d))continue;s.add(d);let{part:u,ownerName:l}=y(a,n,i,o);t.push({id:a.part_id,name:u?.name||p("shared_part_unknown",o),unit:u?.unit,stock:u?.stock??null,storage_location:u?.storage_location,entry_id:a.entry_id,owner_name:l})}return t}function S(){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 c(r){let n=r?.reading_values;if(!Array.isArray(n))return[];let i=[],o=new Set;for(let e of n){if(!e||typeof e!="object")continue;let t=e;typeof t.id!="string"||!t.id||o.has(t.id)||typeof t.value!="number"||!Number.isFinite(t.value)||(o.add(t.id),i.push({id:t.id,name:typeof t.name=="string"?t.name:t.id,unit:typeof t.unit=="string"?t.unit:null,value:t.value}))}return i}function _(r){return r.filter(n=>n.type==="completed"&&(n.reading_value!=null||c(n).length>0)).sort((n,i)=>n.timestamp.localeCompare(i.timestamp))}function P(r){return _(r??[]).map(n=>({timestamp:n.timestamp,values:c(n)})).filter(n=>n.values.length>0)}function v(r,n,i){let o;for(let e of r){if(i!==void 0){let s=new Date(e.timestamp).getTime();if(!isNaN(s)&&s>=i)break}let t=e.values.find(s=>s.id===n);t&&(o=t)}return o}function x(r,n,i){let o=c(n).find(t=>t.id===i);if(!o)return null;let e=null;for(let t of _(r)){if(t.timestamp>=n.timestamp)break;let s=c(t).find(a=>a.id===i);s&&(e=s.value)}return e==null?null:o.value-e}function E(r){let n=new Set,i=new Set;for(let o of r){let e=(o.name||"").trim().toLowerCase();e&&(n.has(e)?i.add(o.id):n.add(e))}return i}function L(r){let n=[],i=new Set,o=new Set;for(let e of r){let t=(e.name||"").trim();if(!(!t||i.has(e.id)||o.has(t.toLowerCase()))&&(i.add(e.id),o.add(t.toLowerCase()),n.push({id:e.id,name:t,unit:(e.unit||"").trim()||null}),n.length>=20))break}return n}function N(r){let n=(r??"").trim();if(n==="")return null;let i=Number(n.replace(",","."));return!Number.isFinite(i)||i<0?null:Math.round(i)}var M=["notes","cost","duration","photo","user"],H={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"};export{m as a,k as b,b as c,S as d,c as e,P as f,v as g,x as h,E as i,L as j,N as k,M as l,H as m};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.96.0 */
import{s as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-N6F5RX6S.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};
@@ -1,2 +1,2 @@
/*! maintenance_supporter frontend 2.96.0 */
import{b as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-BYGTDXRD.js";import{a as l}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WJT4RRLS.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};
/*! maintenance_supporter frontend 2.97.1 */
import{b as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-5SGCD2J3.js";import{a as l}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GSRF4WCQ.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};
@@ -1,937 +0,0 @@
/*! maintenance_supporter frontend 2.88.0 */
import{b as ft,g as $t,j as Y,k as wt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-6RV6BU2W.js";import{e as Z,g as xt,h as kt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-SBK5UZCL.js";import{b as gt,c as yt,e as G,f as vt,h as bt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OTS5U34S.js";import{a as $}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-XRSEIZKJ.js";import{A as z,B as pt,D as ut,E as B,J as X,K as ht,L as _t,O as mt,a as h,b as M,c as l,d as C,f as d,h as D,l as L,m as _,n as W,o as st,p as j,q as s,s as T,t as at,u as ot,v as lt,w as dt,x as y,y as U,z as ct}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OXPKT66L.js";var P=class extends D{constructor(){super(...arguments);this.docId="";this._url="";this._failed=!1;this._signedFor=""}updated(){this.hass&&this.docId&&this._signedFor!==this.docId&&(this._signedFor=this.docId,this._url="",this._failed=!1,this._sign())}async _sign(){try{this._url=await ft(this.hass,this.docId)}catch{this._failed=!0}}render(){return this._failed||!this.docId?d:this._url?l`
<a href=${this._url} target="_blank" rel="noopener" class="wrap">
<img src=${this._url} alt="" loading="lazy"
@error=${()=>this._failed=!0} />
</a>`:l`<div class="ph"></div>`}};P.styles=M`
.wrap { display: inline-block; margin-top: 4px; }
/* #161: uniform 96px tiles — several photos sit in a strip, so a
tiny or portrait shot must not collapse its slot. */
img {
width: 96px;
height: 96px;
object-fit: cover;
border-radius: 6px;
display: block;
border: 1px solid var(--divider-color);
box-sizing: border-box;
}
.ph {
width: 96px;
height: 96px;
border-radius: 6px;
background: var(--secondary-background-color, rgba(0,0,0,0.06));
margin-top: 4px;
}
`,h([L({attribute:!1})],P.prototype,"hass",2),h([L()],P.prototype,"docId",2),h([_()],P.prototype,"_url",2),h([_()],P.prototype,"_failed",2);customElements.get("maintenance-history-photo")||customElements.define("maintenance-history-photo",P);var v=class extends D{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null;this._partOptions=null;this._partQty={};this._partQtyOriginal="";this._photos=new kt(this,{entryId:()=>this._draft?.entry_id??"",hass:()=>this.hass});this._photosOriginal="";this._readingRows=[];this._readingText={};this._readingsOriginal=""}get _lang(){return T(this.hass)}openEdit(t){this._draft={...t},this._originalSnapshot={...t},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._photos.reset(t.photo_doc_ids??[]),this._photosOriginal=JSON.stringify(this._photos.ids),this._seedReadings(t),this._loadPartOptions()}_seedReadings(t){let n=[],r=new Set;for(let o of t.readings??[])r.has(o.id)||(r.add(o.id),n.push({id:o.id,name:o.name,unit:o.unit??null}));for(let o of t.reading_values??[])r.has(o.id)||(r.add(o.id),n.push({id:o.id,name:o.name,unit:o.unit??null}));this._readingRows=n;let a={};for(let o of t.reading_values??[])a[o.id]=String(o.value);this._readingText=a,this._readingsOriginal=JSON.stringify(this._readingNumbers())}_readingNumbers(){let t={};for(let n of this._readingRows){let r=(this._readingText[n.id]??"").trim();if(r==="")continue;let a=parseFloat(r.replace(",","."));isNaN(a)||(t[n.id]=a)}return t}async _loadPartOptions(){let t=this._draft;if(t)try{let n=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"}),r=[];for(let o of n.parts||[]){let c=o.entry_id===t.entry_id,u=o.consumers.some(p=>p.entry_id===t.entry_id&&p.task_id===t.task_id);!c&&!u||r.push({part_id:o.part_id,name:o.name,entry_id:o.entry_id,foreign:!c,object_name:o.object_name})}for(let o of t.used_parts||[]){let c=o.entry_id||t.entry_id;r.some(u=>u.part_id===o.part_id&&u.entry_id===c)||r.push({part_id:o.part_id,name:o.name||o.part_id,entry_id:c,foreign:c!==t.entry_id,object_name:null})}let a={};for(let o of t.used_parts||[])a[`${o.entry_id||t.entry_id}:${o.part_id}`]=o.quantity??1;this._partOptions=r,this._partQty=a,this._partQtyOriginal=this._partSelectionKey()}catch{this._partOptions=[]}}_partSelectionKey(){return JSON.stringify(Object.entries(this._partQty).filter(([,t])=>t>0).sort(([t],[n])=>t.localeCompare(n)))}close(){this._open=!1,this._error="",this._draft=null,this._originalSnapshot=null,this._photos.discardOrphans()}_set(t,n){this._draft&&(this._draft={...this._draft,[t]:n})}async _delete(){if(!this._draft||!this._originalSnapshot)return;let t=this._lang;if(window.confirm(s("history_delete_confirm",t))){this._saving=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/history/delete",entry_id:this._draft.entry_id,task_id:this._draft.task_id,timestamp:this._originalSnapshot.original_timestamp}),this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:this._draft.entry_id,task_id:this._draft.task_id,deleted:!0},bubbles:!0,composed:!0})),this.close()}catch(n){this._error=$(n,t)}finally{this._saving=!1}}}async _save(){if(!(!this._draft||!this._originalSnapshot)){this._saving=!0,this._error="",this._photos.clearError();try{let t={type:"maintenance_supporter/task/history/update",entry_id:this._draft.entry_id,task_id:this._draft.task_id,original_timestamp:this._originalSnapshot.original_timestamp};if(this._draft.timestamp!==this._originalSnapshot.timestamp&&(t.timestamp=this._draft.timestamp),this._draft.notes!==this._originalSnapshot.notes&&(t.notes=this._draft.notes),this._draft.cost!==this._originalSnapshot.cost&&(t.cost=this._draft.cost),this._draft.duration!==this._originalSnapshot.duration&&(t.duration=this._draft.duration),this._draft.completed_by!==this._originalSnapshot.completed_by&&(t.completed_by=this._draft.completed_by),this._partOptions!==null&&this._partSelectionKey()!==this._partQtyOriginal&&(t.used_parts=(this._partOptions||[]).filter(r=>(this._partQty[`${r.entry_id}:${r.part_id}`]||0)>0).map(r=>({part_id:r.part_id,quantity:this._partQty[`${r.entry_id}:${r.part_id}`],...r.foreign?{entry_id:r.entry_id}:{}}))),this._draft.reading_value!==this._originalSnapshot.reading_value&&(t.reading_value=this._draft.reading_value??null),this._readingRows.length>0&&JSON.stringify(this._readingNumbers())!==this._readingsOriginal){let r=this._readingNumbers(),a={};for(let o of this._readingRows)a[o.id]=r[o.id]??null;t.reading_values=a}if(JSON.stringify(this._photos.ids)!==this._photosOriginal&&(t.photo_doc_ids=this._photos.ids),Object.keys(t).filter(r=>!["type","entry_id","task_id","original_timestamp"].includes(r)).length===0){this.close();return}await this.hass.connection.sendMessagePromise(t),this._photos.markAttached(),this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id: Line truncated
<div class="backdrop" @click=${this.close}></div>
<div class="dialog" role="dialog" aria-modal="true">
<h2>${s("history_edit_title",t)}</h2>
<div class="entry-type">
<ha-icon icon="mdi:tag-outline"></ha-icon>
<span>${s(n.type,t)||n.type}</span>
</div>
<ms-date-field
kind="datetime"
required
.hass=${this.hass}
.lang=${t}
.label=${s("history_edit_timestamp",t)}
.value=${n.timestamp.slice(0,19)}
@value-changed=${a=>{let o=a.detail.value;o&&this._set("timestamp",o)}}
></ms-date-field>
<label>
<span>${s("notes_label",t)}</span>
<textarea
rows="3"
@input=${a=>{let o=a.target.value;this._set("notes",o||null)}}
.value=${n.notes??""}></textarea>
</label>
<div class="row">
<label>
<span>${s("cost",t)}</span>
<input type="number" min="0" step="0.01"
.value=${n.cost!=null?String(n.cost):""}
@input=${a=>{let o=a.target.value;this._set("cost",o?Number(o):null)}} />
</label>
<label>
<span>${s("duration",t)}</span>
<input type="number" min="0"
.value=${n.duration!=null?String(n.duration):""}
@input=${a=>{let o=a.target.value;this._set("duration",o?Number(o):null)}} />
</label>
</div>
${this._renderReadings(n,t)}
${this._partOptions&&this._partOptions.length>0?l`
<div class="parts-block">
<span class="parts-title">${s("complete_parts_used",t)}</span>
${this._partOptions.map(a=>{let o=`${a.entry_id}:${a.part_id}`,c=this._partQty[o]||0;return l`
<label class="part-row-edit">
<input type="checkbox" .checked=${c>0}
@change=${u=>{let p=u.target.checked;this._partQty={...this._partQty,[o]:p?1:0}}} />
<span class="part-label">${a.name}${a.foreign&&a.object_name?` (${a.object_name})`:""}</span>
${c>0?l`
<input class="part-qty" type="number" min="0.01" max="999" step="0.01"
.value=${String(c)}
@input=${u=>{let p=parseFloat(u.target.value);!isNaN(p)&&p>0&&(this._partQty={...this._partQty,[o]:p})}} />
`:d}
</label>
`})}
</div>
`:d}
<div class="photos-block">
<span class="parts-title">${s("completion_photos",t)}</span>
${this._photos.photos.length>0?l`
<div class="photo-strip">
${this._photos.photos.map(a=>l`
<div class="photo-tile">
<maintenance-history-photo .hass=${this.hass} .docId=${a.id}></maintenance-history-photo>
<button type="button" class="photo-remove" title=${s("remove",t)}
@click=${()=>this._photos.remove(a.id)}>✕</button>
</div>`)}
</div>`:d}
${this._photos.full?l`<span class="photos-hint">${s("photos_limit",t).replace("{max}",String(this._photos.max))}</span>`:l`<ms-photo-picker .lang=${t} .busy=${this._photos.uploading} .remaining=${this._photos.remaining}
@files-picked=${a=>this._photos.addFiles(a.detail.files)}
></ms-photo-picker>`}
<span class="photos-hint">${s("history_edit_photos_hint",t)}</span>
</div>
${r?l`<div class="error">${r}</div>`:d}
<div class="actions">
<button class="delete-entry" @click=${this._delete} ?disabled=${this._saving} title=${s("history_delete_entry",t)}>
<ha-icon icon="mdi:delete-outline"></ha-icon> ${s("history_delete_entry",t)}
</button>
<button class="cancel" @click=${this.close} ?disabled=${this._saving}>
${s("cancel",t)}
</button>
<button class="save" @click=${this._save} ?disabled=${this._saving}>
${this._saving?s("saving",t):s("save",t)}
</button>
</div>
</div>
`}_renderReadings(t,n){return this._readingRows.length>0?l`
<div class="readings-block">
<span class="parts-title">${s("readings_section",n)}</span>
${this._readingRows.map(r=>l`
<label class="reading-row-edit">
<span class="reading-row-name">${r.name}${r.unit?` (${r.unit})`:""}</span>
<input type="text" inputmode="decimal" class="reading-row-input"
.value=${this._readingText[r.id]??""}
@input=${a=>{this._readingText={...this._readingText,[r.id]:a.target.value}}} />
</label>
`)}
</div>`:t.reading_value==null&&t.task_type!=="reading"?d:l`
<label>
<span>${s("reading_value_label",n)}${t.reading_unit?` (${t.reading_unit})`:""}</span>
<input type="number" step="any"
.value=${t.reading_value!=null?String(t.reading_value):""}
@input=${r=>{let a=r.target.value,o=a===""?NaN:Number(a);this._set("reading_value",isNaN(o)?null:o)}} />
</label>`}};v.styles=[xt,M`
:host { display: contents; }
.backdrop {
position: fixed; inset: 0;
background: rgba(0,0,0,0.5);
z-index: 100;
}
.dialog {
position: fixed; left: 50%; top: 50%;
transform: translate(-50%, -50%);
width: 95vw; max-width: 480px;
background: var(--card-background-color, var(--ha-card-background, #1c1c1c));
color: var(--primary-text-color);
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
padding: 20px;
display: flex; flex-direction: column; gap: 12px;
z-index: 101;
max-height: 90vh; overflow: auto;
}
h2 { margin: 0; font-size: 18px; }
.entry-type {
display: flex; align-items: center; gap: 6px;
color: var(--secondary-text-color); font-size: 13px;
}
label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
label span { color: var(--secondary-text-color); }
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
input, textarea {
padding: 8px; font-size: 14px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color, #444);
border-radius: 6px;
width: 100%; box-sizing: border-box;
font-family: inherit;
}
.delete-entry { margin-right: auto; color: var(--error-color, #d32f2f); background: transparent; border: 1px solid var(--error-color, #d32f2f); border-radius: 6px; padding: 6px 10px; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; }
.delete-entry ha-icon { --mdc-icon-size: 18px; }
.actions {
display: flex; gap: 8px; justify-content: flex-end;
margin-top: 8px;
}
button {
padding: 8px 16px; font-size: 14px;
border-radius: 6px; cursor: pointer;
border: none; font-weight: 500;
}
button.cancel {
background: transparent;
color: var(--primary-text-color);
border: 1px solid var(--divider-color);
}
button.save {
background: var(--primary-color);
color: var(--text-primary-color, white);
}
button[disabled] { opacity: 0.5; cursor: wait; }
.error {
color: var(--error-color, #d32f2f);
font-size: 13px; padding: 8px;
background: rgba(211,47,47,0.1);
border-radius: 6px;
}
/* #130: parts on the entry */
.parts-block {
display: flex; flex-direction: column; gap: 6px;
border: 1px solid var(--divider-color, #444);
border-radius: 6px; padding: 8px;
}
.parts-title { color: var(--secondary-text-color); font-size: 13px; }
.part-row-edit {
display: flex; flex-direction: row; align-items: center; gap: 8px;
font-size: 14px;
}
.part-row-edit input[type="checkbox"] { width: auto; }
.part-label { flex: 1; color: var(--primary-text-color); }
.part-qty { width: 76px; }
/* #161 phase 2: readings on the entry */
.readings-block {
display: flex; flex-direction: column; gap: 6px;
border: 1px solid var(--divider-color, #444);
border-radius: 6px; padding: 8px;
}
.reading-row-edit {
display: flex; flex-direction: row; align-items: center; gap: 8px;
font-size: 14px;
}
.reading-row-name { flex: 1; color: var(--primary-text-color); min-width: 0; }
.reading-row-input { width: 140px; font-variant-numeric: tabular-nums; }
/* #161: photos on the entry */
.photos-block {
display: flex; flex-direction: column; gap: 6px;
border: 1px solid var(--divider-color, #444);
border-radius: 6px; padding: 8px;
}
.photo-strip { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 6px; }
.photo-tile { position: relative; width: fit-content; }
.photo-remove {
position: absolute; top: -4px; right: -8px;
width: 22px; height: 22px; border-radius: 50%; border: none;
background: var(--error-color, #db4437); color: #fff;
cursor: pointer; font-size: 11px; line-height: 1; padding: 0;
}
/* the camera / gallery pickers come from photoPickerStyles (ms-photo-picker) */
.photos-hint { font-size: 12px; color: var(--secondary-text-color); }
`],h([L({attribute:!1})],v.prototype,"hass",2),h([_()],v.prototype,"_open",2),h([_()],v.prototype,"_saving",2),h([_()],v.prototype,"_error",2),h([_()],v.prototype,"_draft",2),h([_()],v.prototype,"_partOptions",2),h([_()],v.prototype,"_partQty",2),h([_()],v.prototype,"_readingRows",2),h([_()],v.prototype,"_readingText",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",v);function Qt(e,i){if(i<=0)return 0;let t=typeof e=="number"&&Number.isFinite(e)?Math.trunc(e):0;return t<0?0:t%i}function Xt(e){return!!(e?.phases&&e.phase_sequence&&e.phase_sequence.length>0)}function tt(e){if(!e||!Xt(e))return null;let i=e.phase_sequence,t=Qt(e.phase_cursor,i.length),n=i[t],r=e.phases?.[n];return r?{id:n,name:r.name,index:t,count:i.length,notes:r.notes,checklist:r.checklist!==void 0?r.checklist:e.checklist??[],consumesParts:r.consumes_parts!==void 0?r.consumes_parts:e.consumes_parts??[],requiredFields:r.required_completion_fields!==void 0?r.required_completion_fields:e.required_completion_fields??[]}:null}function N(e){let i=tt(e);return i?`${i.index+1}/${i.count} \xB7 ${i.name}`:""}function At(e){let i=e.task??null,t=i?tt(i):null,n=t?t.consumesParts:i?.consumes_parts||[],r=!!i?.part_ref,a=e.objects.find(u=>u.entry_id===e.entryId)?.parts||[],o=r?a.find(u=>u.id===i.part_ref.part_id):void 0,c=e.checklistsEnabled??!0;return{entry_id:e.entryId,task_id:e.taskId,task_name:e.taskName,checklist:t?c?t.checklist:[]:e.checklist??[],adaptive_enabled:!!e.adaptiveEnabled,required_completion_fields:t?t.requiredFields:i?.required_completion_fields||[],task_type:i?.type||"",reading_unit:i?.reading_unit||"",readings:i?.readings||[],reading_history:vt(i?.history),parts:r?[]:yt({consumes_parts:n},e.entryId,e.objects,e.lang),consumes_parts:r?[]:n,phase_label:t?N(i):"",require_tag_scan:!!i?.require_tag_scan,restock_default:r?o?.restock_quantity??1:null,restock_unit_cost:r?o?.cost??null:null,currency_symbol:j({currency_symbol:e.currencySymbol}),consumes_info:n.map(u=>gt(u,e.entryId,e.objects,e.lang)),checklist_prefill:i?.checklist_progress||{},via_tag_scan:!!e.viaTagScan}}function Et(e,i,t){e.entryId=i.entry_id,e.taskId=i.task_id,e.taskName=i.task_name,e.lang=t,e.checklist=i.checklist??[],e.adaptiveEnabled=!!i.adaptive_enabled,e.requiredFields=i.required_completion_fields??[],e.taskType=i.task_type??"",e.readingUnit=i.reading_unit??"",e.readings=i.readings??[],e.readingHistory=i.reading_history??[],e.parts=i.parts??[],e.consumesParts=i.consumes_parts??[],e.phaseLabel=i.phase_label??"",e.requireTagScan=!!i.require_tag_scan,e.restockDefault=i.restock_default??null,e.restockUnitCost=i.restock_unit_cost??null,e.currencySymbol=j(i),e.consumesInfo=i.consumes_info??[],e.checklistPrefill=i.checklist_prefill??{},e.viaTagScan=!!i.via_tag_scan,e.open({viaTagScan:!!i.via_tag_scan})}function et(e,i,t,n){let r=t,a=u=>typeof u=="string"?u:null,o=u=>typeof u=="number"?u:null,c=a(r.timestamp)??"";return{entry_id:e,task_id:i,original_timestamp:c,type:a(r.type)||"completed",timestamp:c,notes:a(r.notes),cost:o(r.cost),duration:o(r.duration),completed_by:a(r.completed_by),used_parts:Array.isArray(r.used_parts)?r.used_parts:null,photo_doc_ids:Z(r),reading_value:o(r.reading_value),reading_values:G(r),readings:n?.readings??[],task_type:n?.type??null,reading_unit:n?.reading_unit??null}}async function Je(e,i,t,n){let a=(await e.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:i})).tasks?.find(c=>c.id===t),o=a?.history?.find(c=>c.timestamp===n);return!a||!o?null:et(i,t,o,a)}var Lt=e=>typeof e=="number"&&Number.isInteger(e)&&e>0;function te(e){return e&&Lt(e.ref_no)?String(e.ref_no):null}function Tt(e,i){let t=te(e);return t&&i&&Lt(i.ref_no)?`${t}.${i.ref_no}`:null}function ti(e){let i=/^(\d+)(?:\.(\d+)(?:-(\d+))?)?$/.exec(e.trim());return i?{object:Number(i[1]),task:i[2]?Number(i[2]):null,entry:i[3]?Number(i[3]):null}:null}function Ht(e,i){return e?l`<span class="ref-chip" title=${i??""}>#${e}</span>`:d}var ee={\u00DF:"s","\u1E9E":"s",\u00E6:"a",\u0153:"o",\u00F8:"o",\u0111:"d",\u00F0:"d",\u00FE:"t",\u0142:"l",\u0131:"i"},Dt=10,ie=7,it=4,It=2,ne=5,Pt=3,re=/[a-z0-9]+/g;function K(e){let i="";for(let t of e.toLowerCase()){if(t.charCodeAt(0)<128&&t.length===1){i+=t;continue}let n=ee[t];if(n){i+=n;continue}let r=t.normalize("NFKD")[0]||t;i+=r.charCodeAt(0)<128?r:t}return i}function St(e){return K(e).match(re)||[]}function se(e){return K(e).replace(/[^a-z0-9]+/g,"")}function ae(e){return e.replace(/ue/g,"u").replace(/oe/g,"o").replace(/ae/g,"a").replace(/ss/g,"s")}function oe(e){let i=[];for(let t of St(e)){let n=[t],r=ae(t);r&&r!==t&&n.push(r),i.push(n)}return i}function Mt(e,i){if(e===i)return!0;let t=e.length,n=i.length;if(Math.abs(t-n)>1)return!1;if(t===n){let p=[];for(let f=0;f<t;f++)e[f]!==i[f]&&p.push(f);if(p.length===1)return!0;if(p.length===2&&p[1]===p[0]+1){let f=p[0];return e[f]===i[f+1]&&e[f+1]===i[f]}return!1}let[r,a]=t>n?[e,i]:[i,e],o=0,c=0,u=!1;for(;o<r.length&&c<a.lengtLine truncated
<div class="history-filters-new">
<div class="filter-chips">
${ue.map(n=>{let r=e.history.filter(a=>a.type===n).length;return r===0?d:l`
<span class="filter-chip ${i.filter===n?"active":""}"
@click=${()=>i.setFilter(i.filter===n?null:n)}>
${s(n,t)} (${r})
</span>
`})}
${i.filter?l`<span class="filter-chip clear" @click=${()=>i.setFilter(null)}>${s("show_all",t)}</span>`:d}
</div>
<div class="filter-controls">
<input type="text" class="search-input" placeholder="${s("search_notes",t)}..." .value=${i.search} @input=${n=>i.setSearch(n.target.value)} />
</div>
</div>
`}function pi(e,i){let t=i.lang,n=i.filter?e.history.filter(r=>r.type===i.filter):e.history;if(i.search){let r=i.search.toLowerCase();n=n.filter(a=>Rt(a.notes,i.search)||(Ct(i,a)??"").toLowerCase().endsWith(r))}return n.length===0?l`<p class="empty">${s("no_history",t)}</p>`:l`
<div class="history-timeline">
${[...n].reverse().map(r=>nt(r,i))}
</div>
`}function Ct(e,i){return e.taskRef&&i.ref_no?`${e.taskRef}-${i.ref_no}`:null}function he(e,i){let t=Z(i);return t.length>0?l`<div class="history-photos">
${t.map(n=>l`<maintenance-history-photo .hass=${e} .docId=${n}></maintenance-history-photo>`)}
</div>`:d}function _e(e,i){let t=i.lang,n=o=>y(o,t,{maximumFractionDigits:3}),r=o=>o==null?"":` (${o>=0?"+":""}${n(o)})`,a=G(e);return a.length>0?l`<div class="history-readings">
${a.map(o=>l`<span class="history-reading">
<span class="history-reading-name">${o.name}</span>
<span class="history-reading-value">${n(o.value)}${o.unit?` ${o.unit}`:""}${r(i.readingSlotDelta?.(e,o.id))}</span>
</span>`)}
</div>`:e.reading_value!=null?l`<div class="history-readings"><span class="history-reading">
<span class="history-reading-name">${s("reading_label",t)}</span>
<span class="history-reading-value">${n(e.reading_value)}${i.readingUnit?` ${i.readingUnit}`:""}${r(i.readingDelta?.(e))}</span>
</span></div>`:d}function nt(e,i,t={}){let n=i.lang,{compact:r=!1,showRef:a=!0,showBadges:o=!0,showEdit:c=!0}=t,u=c&&pe.includes(e.type);return l`
<div class="history-entry${r?" compact":""}">
${r?d:l`<div class="history-icon ${e.type}">
<ha-icon .icon=${st[e.type]||"mdi:circle"}></ha-icon>
</div>`}
<div class="history-content">
<div class="history-row">
<strong>${s(e.type,n)}</strong>
${a?Ht(Ct(i,e),s("ref_number",n)):d}
${o&&e.phase_id?l`<span class="history-phase-badge">${i.phaseNames?.[e.phase_id]||e.phase_id}</span>`:d}
${o&&e.auto?l`<span class="history-auto-badge">${s("history_auto",n)}</span>`:d}
${u?l`<button class="history-edit-btn"
title=${s("history_edit_button",n)}
@click=${()=>i.openEdit(e)}>
<ha-icon icon="mdi:pencil"></ha-icon>
</button>`:d}
</div>
<div class="history-date">${pt(e.timestamp,n)}</div>
${e.notes?l`<div>${e.notes}</div>`:d}
${he(i.hass,e)}
${_e(e,i)}
${e.cost!=null||e.duration!=null||e.trigger_value!=null?l`<div class="history-details">
${e.cost!=null?l`<span>${s("cost",n)}: ${U(e.cost,i.currencySymbol,n)}</span>`:d}
${e.duration!=null?l`<span>${s("duration",n)}: ${B(e.duration,n)}</span>`:d}
${e.trigger_value!=null?l`<span>${s("trigger_val",n)}: ${e.trigger_value}</span>`:d}
</div>`:d}
</div>
</div>
`}function m(e){return e.toFixed(1)}function _i(e,i,t=4){if(!isFinite(e)||!isFinite(i))return{ticks:[],niceMin:0,niceMax:1};if(e===i){let p=Math.abs(e)*.1||1;e-=p,i+=p}let n=i-e,r=Math.pow(10,Math.floor(Math.log10(n/Math.max(1,t)))),a=r;for(let p of[1,2,5,10])if(a=r*p,n/a<=t+.5)break;let o=Math.floor(e/a)*a,c=Math.ceil(i/a)*a,u=[];for(let p=o;p<=c+a*1e-6;p+=a)u.push(Math.abs(p)<a*1e-9?0:p);return{ticks:u,niceMin:o,niceMax:c}}function mi(e,i){let t=Math.abs(e),n=r=>({maximumFractionDigits:r});return t>=1e6?y(e/1e6,i,n(t>=1e7?0:1))+"M":t>=1e4?y(e/1e3,i,n(0))+"k":t>=1e3?y(e/1e3,i,n(1))+"k":t>=100?y(e,i,n(0)):t>=1?y(e,i,n(1)):t===0?"0":y(e,i,n(2))}function fi(e,i,t){let n=y(e,t,{maximumFractionDigits:Math.abs(e)>=100?0:1});return i?`${n} ${i}`:n}function gi(e,i,t){return X(new Date(e),i,t)}function yi(e,i){let t=new Date(e);return`${X(t,i)}, ${ct(t,i)}`}function vi(e,i){return new Date(e).getFullYear()!==new Date(i).getFullYear()}function bi(e,i,t){if(t<2||i<=e)return[e,i];let n=[];for(let r=0;r<t;r++)n.push(e+(i-e)*r/(t-1));return n}function Ot(e,i){let t=e.interval_analysis,n=t?.weibull_beta,r=t?.weibull_eta;if(n==null||r==null||r<=0)return d;let a=e.interval_days??0,o=e.suggested_interval??a;return l`
<div class="weibull-section">
<div class="weibull-title">
<ha-svg-icon aria-hidden="true" path="M3,14L3.5,14.07L8.07,9.5C7.89,8.85 8.06,8.11 8.59,7.59C9.37,6.8 10.63,6.8 11.41,7.59C11.94,8.11 12.11,8.85 11.93,9.5L14.5,12.07L15,12C15.18,12 15.35,12 15.5,12.07L19.07,8.5C19,8.35 19,8.18 19,8A2,2 0 0,1 21,6A2,2 0 0,1 23,8A2,2 0 0,1 21,10C20.82,10 20.65,10 20.5,9.93L16.93,13.5C17,13.65 17,13.82 17,14A2,2 0 0,1 15,16A2,2 0 0,1 13,14L13.07,13.5L10.5,10.93C10.18,11 9.82,11 9.5,10.93L4.93,15.5L5,16A2,2 0 0,1 3,18A2,2 0 0,1 1,16A2,2 0 0,1 3,14Z"></ha-svg-icon>
${s("weibull_reliability_curve",i)}
${me(n,i)}
</div>
${fe(n,r,a,o,i)}
${ge(t,i)}
${t?.confidence_interval_low!=null?ye(t,e,i):d}
</div>
`}function me(e,i){let t,n,r;return e<.8?(t="early_failures",n="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z",r="beta_early_failures"):e<=1.2?(t="random_failures",n="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,17H11V15H13V17M13,13H11V7H13V13Z",r="beta_random_failures"):e<=3.5?(t="wear_out",n="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4M12,6A6,6 0 0,1 18,12H12V6Z",r="beta_wear_out"):(t="highly_predictable",n="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M11,16.5L18,9.5L16.59,8.09L11,13.67L7.91,10.59L6.5,12L11,16.5Z",r="beta_highly_predictable"),l`
<span class="beta-badge ${t}">
<ha-svg-icon path="${n}"></ha-svg-icon>
${s(r,i)} (\u03B2=${y(e,i,2)})
</span>
`}function fe(e,i,t,n,r){let b=Math.max(t,n,i,1)*1.3,A=50,E=[];for(let x=0;x<=A;x++){let k=x/A*b,Yt=1-Math.exp(-Math.pow(k/i,e)),Kt=32+k/b*260,Jt=136-Yt*128;E.push([Kt,Jt])}let q=E.map(([x,k])=>`${m(x)},${m(k)}`).join(" "),Q="M32,136 "+E.map(([x,k])=>`L${m(x)},${m(k)}`).join(" ")+` L${m(E[A][0])},136 Z`,R=32+t/b*260,F=1-Math.exp(-Math.pow(t/i,e)),V=136-F*128,Gt=y((1-F)*100,r,0),rt=32+n/b*260,Zt=[0,.25,.5,.75,1];return l`
<div class="weibull-chart">
<svg viewBox="0 0 ${300} ${160}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${s("chart_weibull",r)}">
${Zt.map(x=>{let k=136-x*128;return C`
<line x1="${32}" y1="${m(k)}" x2="${292}" y2="${m(k)}"
stroke="var(--divider-color)" stroke-width="0.5" stroke-dasharray="${x===.5?"4,3":d}" />
<text x="${28}" y="${m(k+3)}" fill="var(--secondary-text-color)"
font-size="8" text-anchor="end">${y(x*100,r,0)}%</text>
`})}
<text x="${32}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">0</text>
<text x="${324/2}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">${Math.round(b/2)}</text>
<text x="${292}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">${Math.round(b)}</text>
<path d="${Q}" fill="var(--primary-color, #03a9f4)" opacity="0.08" />
<polyline points="${q}" fill="none"
stroke="var(--primary-color, #03a9f4)" stroke-width="2" />
${t>0?C`
<line x1="${m(R)}" y1="${8}" x2="${m(R)}" y2="${m(136)}"
stroke="var(--primary-color, #03a9f4)" stroke-width="1.5" stroke-dasharray="4,3" />
<circle cx="${m(R)}" cy="${m(V)}" r="3"
fill="var(--primary-color, #03a9f4)" />
<text x="${m(R+4)}" y="${m(V-6)}" fill="var(--primary-color, #03a9f4)"
font-size="9" font-weight="600">R=${Gt}%</text>
`:d}
${n>0&&n!==t?C`
<line x1="${m(rt)}" y1="${8}" x2="${m(rt)}" y2="${m(136)}"
stroke="var(--success-color, #4caf50)" stroke-width="1.5" stroke-dasharray="4,3" />
`:d}
<line x1="${32}" y1="${8}" x2="${32}" y2="${136}"
stroke="var(--secondary-text-color)" stroke-width="1" />
<line x1="${32}" y1="${136}" x2="${292}" y2="${136}"
stroke="var(--secondary-text-color)" stroke-width="1" />
</svg>
</div>
<div class="chart-legend">
<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color, #03a9f4)"></span> ${s("weibull_failure_probability",r)}</span>
${t>0?l`<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color, #03a9f4); opacity:0.5"></span> ${s("current_interval_marker",r)}</span>`:d}
${n>0&&n!==t?l`<span class="legend-item"><span class="legend-swatch" style="background:var(--success-color, #4caf50)"></span> ${s("recommended_marker",r)}</span>`:d}
</div>
`}function ge(e,i){return l`
<div class="weibull-info-row">
<div class="weibull-info-item">
<span>${s("characteristic_life",i)}</span>
<span class="weibull-info-value">${Math.round(e.weibull_eta)} ${s("days",i)}</span>
</div>
${e.weibull_r_squared!=null?l`
<div class="weibull-info-item">
<span>${s("weibull_r_squared",i)}</span>
<span class="weibull-info-value">${y(e.weibull_r_squared,i,3)}</span>
</div>
`:d}
</div>
`}function ye(e,i,t){let n=e.confidence_interval_low,r=e.confidence_interval_high,a=i.suggested_interval??i.interval_days??0,o=i.interval_days??0,c=Math.max(0,n-5),p=r+5-c,f=(n-c)/p*100,S=(r-n)/p*100,O=(a-c)/p*100,b=o>0?(o-c)/p*100:-1;return l`
<div class="confidence-range">
<div class="confidence-range-title">
${s("confidence_interval",t)}: ${a} ${s("days",t)} (${n}\u2013${r})
</div>
<div class="confidence-bar">
<div class="confidence-fill" style="left:${m(f)}%;width:${m(S)}%"></div>
${b>=0?l`<div class="confidence-marker current" style="left:${m(b)}%"></div>`:d}
<div class="confidence-marker recommended" style="left:${m(O)}%"></div>
</div>
<div class="confidence-labels">
<span class="confidence-text low">${s("confidence_conservative",t)} (${n}${s("days",t).charAt(0)})</span>
<span class="confidence-text high">${s("confidence_aggressive",t)} (${r}${s("days",t).charAt(0)})</span>
</div>
</div>
`}function jt(e,i,t){let n=e.degradation_trend!=null&&e.degradation_trend!=="insufficient_data",r=e.days_until_threshold!=null,a=e.environmental_factor!=null&&e.environmental_factor!==1;if(!n&&!r&&!a)return d;let o=e.degradation_trend==="rising"?"M16,6L18.29,8.29L13.41,13.17L9.41,9.17L2,16.59L3.41,18L9.41,12L13.41,16L19.71,9.71L22,12V6H16Z":e.degradation_trend==="falling"?"M16,18L18.29,15.71L13.41,10.83L9.41,14.83L2,7.41L3.41,6L9.41,12L13.41,8L19.71,14.29L22,12V18H16Z":"M22,12L18,8V11H3V13H18V16L22,12Z";return l`
<div class="prediction-section">
${e.sensor_prediction_urgency?l`
<div class="prediction-urgency-banner">
<ha-svg-icon path="M1,21H23L12,2L1,21M12,18A1,1 0 0,1 11,17A1,1 0 0,1 12,16A1,1 0 0,1 13,17A1,1 0 0,1 12,18M13,15H11V10H13V15Z"></ha-svg-icon>
${s("sensor_prediction_urgency",i).replace("{days}",String(Math.round(e.days_until_threshold||0)))}
</div>
`:d}
<div class="prediction-title">
<ha-svg-icon path="M2,2V4H7V2H2M22,2V4H13V2H22M7,7V9H2V7H7M22,7V9H13V7H22M7,12V14H2V12H7M22,12V14H13V12H22M7,17V19H2V17H7M22,17V19H13V17H22M9,2V19L12,22L15,19V2H9M11,4H13V17.17L12,18.17L11,17.17V4Z"></ha-svg-icon>
${s("sensor_prediction",i)}
</div>
<div class="prediction-grid">
${n?l`
<div class="prediction-item">
<ha-svg-icon path="${o}"></ha-svg-icon>
<span class="prediction-label">${s("degradation_trend",i)}</span>
<span class="prediction-value ${e.degradation_trend}">${s("trend_"+e.degradation_trend,i)}</span>
${e.degradation_rate!=null?l`<span class="prediction-rate">${e.degradation_rate>0?"+":""}${y(e.degradation_rate,i,Math.abs(e.degradation_rate)>=10?0:1)} ${e.trigger_entity_info?.unit_of_measurement||""}/${s("day_short",i)}</span>`:d}
</div>
`:d}
${r?l`
<div class="prediction-item">
<ha-svg-icon path="M12,20A7,7 0 0,1 5,13A7,7 0 0,1 12,6A7,7 0 0,1 19,13A7,7 0 0,1 12,20M12,4A9,9 0 0,0 3,13A9,9 0 0,0 12,22A9,9 0 0,0 21,13A9,9 0 0,0 12,4M12.5,8H11V14L15.75,16.85L16.5,15.62L12.5,13.25V8M7.88,3.39L6.6,1.86L2,5.71L3.29,7.24L7.88,3.39M22,5.72L17.4,1.86L16.11,3.39L20.71,7.25L22,5.72Z"></ha-svg-icon>
<span class="prediction-label">${s("days_until_threshold",i)}</span>
<span class="prediction-value prediction-days${e.days_until_threshold===0?" exceeded":e.sensor_prediction_urgency?" urgent":""}">${e.days_until_threshold===0?s("threshold_exceeded",i):"~"+Math.round(e.days_until_threshold)+" "+s("days",i)}</span>
${e.threshold_prediction_date?l`<span class="prediction-date">${z(e.threshold_prediction_date,i)}</span>`:d}
${e.threshold_prediction_confidence?l`<span class="confidence-dot ${e.threshold_prediction_confidence}"></span>`:d}
${(e.prediction_cycles??0)>0?l`<span class="prediction-cycles">${s("prediction_cycles",i)}: ${e.prediction_cycles}</span>`:d}
</div>
`:d}
${a&&t.environmental?l`
<div class="prediction-item">
<ha-svg-icon path="M15,13V5A3,3 0 0,0 12,2A3,3 0 0,0 9,5V13A5,5 0 0,0 7,17A5,5 0 0,0 12,22A5,5 0 0,0 17,17A5,5 0 0,0 15,13M12,4A1,1 0 0,1 13,5V8H11V5A1,1 0 0,1 12,4Z"></ha-svg-icon>
<span class="prediction-label">${s("environmental_adjustment",i)}</span>
<span class="prediction-value">${y(e.environmental_factor,i,2)}x</span>
${e.environmental_entity?l`<span class="prediction-entity entity-link" @click=${c=>_t(c,e.environmental_entity)}>${e.environmental_entity}</span>`:d}
</div>
`:d}
</div>
</div>
`}function zt(e,i,t,n){let r=Math.max(e||1,i);return l`
<div class="interval-comparison">
<div class="interval-bar">
<div class="interval-label">
${s("current",n)}: ${e??"\u2014"} ${e!=null?s("days",n):""}
</div>
<div class="interval-visual current"
style="width: ${e!=null?Math.min(e/r*100,100):0}%"></div>
</div>
<div class="interval-bar">
<div class="interval-label">
${s("recommended",n)}: ${i} ${s("days",n)}
<span class="confidence-badge ${t}">${s(`confidence_${t}`,n)}</span>
</div>
<div class="interval-visual suggested"
style="width: ${Math.min(i/r*100,100)}%"></div>
</div>
</div>
`}var Nt=["month_jan","month_feb","month_mar","month_apr","month_may","month_jun","month_jul","month_aug","month_sep","month_oct","month_nov","month_dec"];function qt(e,i,t){if(!t.seasonal||!e.seasonal_factor||e.seasonal_factor===1)return d;let n=Nt.map(c=>s(c,i)),r=new Date().getMonth(),a=e.seasonal_factors||e.interval_analysis?.seasonal_factors||null,o=a&&a.length===12?a:n.map((c,u)=>{let p=e.seasonal_factor||1,f=Math.sin((u-6)*Math.PI/6)*.3;return Math.max(.7,Math.min(1.3,p+f))});return l`
<div class="seasonal-card-compact">
<h4>${s("seasonal_awareness",i)}</h4>
<div class="seasonal-mini-chart">
${o.map((c,u)=>{let p=c*40,f=c<.9?"low":c>1.1?"high":"normal";return l`
<div class="seasonal-bar ${f} ${u===r?"current":""}"
style="height: ${p}px"
title="${n[u]}: ${y(c,i,2)}x">
</div>
`})}
</div>
<div class="seasonal-legend">
<span class="legend-item"><span class="dot low"></span> ${s("shorter",i)}</span>
<span class="legend-item"><span class="dot normal"></span> ${s("normal",i)}</span>
<span class="legend-item"><span class="dot high"></span> ${s("longer",i)}</span>
</div>
</div>
`}function Ft(e,i){return ve(e,i)}function ve(e,i){let t=e.seasonal_factors??e.interval_analysis?.seasonal_factors;if(!t||t.length!==12)return d;let n=e.interval_analysis?.seasonal_reason,r=new Date().getMonth(),a=300,o=100,c=8,p=o-c-4,f=Math.max(...t,1.5),S=a/12,O=S*.65,b=c+p-1/f*p;return l`
<div class="seasonal-chart">
<div class="seasonal-chart-title">
<ha-svg-icon aria-hidden="true" path="M17.75 4.09L15.22 6.03L16.13 9.09L13.5 7.28L10.87 9.09L11.78 6.03L9.25 4.09L12.44 4L13.5 1L14.56 4L17.75 4.09M21.25 11L19.61 12.25L20.2 14.23L18.5 13.06L16.8 14.23L17.39 12.25L15.75 11L17.81 10.95L18.5 9L19.19 10.95L21.25 11M18.97 15.95C19.8 15.87 20.69 17.05 20.16 17.8C19.84 18.25 19.5 18.67 19.08 19.07C15.17 23 8.84 23 4.94 19.07C1.03 15.17 1.03 8.83 4.94 4.93C5.34 4.53 5.76 4.17 6.21 3.85C6.96 3.32 8.14 4.21 8.06 5.04C7.79 7.9 8.75 10.87 10.95 13.06C13.14 15.26 16.1 16.22 18.97 15.95Z"></ha-svg-icon>
${s("seasonal_chart_title",i)}
${n?l`<span class="source-tag">${n==="learned"?s("seasonal_learned",i):s("seasonal_manual",i)}</span>`:d}
</div>
<svg viewBox="0 0 ${a} ${o}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${s("chart_seasonal",i)}">
<line x1="0" y1="${m(b)}" x2="${a}" y2="${m(b)}"
stroke="var(--divider-color)" stroke-width="1" stroke-dasharray="4,3" />
${t.map((A,E)=>{let q=A/f*p,Q=E*S+(S-O)/2,R=c+p-q,F=E===r,V=A<1?"var(--success-color, #4caf50)":A>1?"var(--warning-color, #ff9800)":"var(--secondary-text-color)";return C`
<rect x="${m(Q)}" y="${m(R)}"
width="${m(O)}" height="${m(q)}"
fill="${V}" opacity="${F?1:.5}" rx="2" />
`})}
</svg>
<div class="seasonal-labels">
${Nt.map((A,E)=>l`<span class="seasonal-label ${E===r?"active-month":""}">${s(A,i)}</span>`)}
</div>
</div>
`}var g=class extends D{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._taskId=null;this._task=null;this._objectName="";this._taskRef=null;this._busy=!1;this._error="";this._showSkip=!1;this._showReset=!1;this._showDetails=!1;this._showAdaptive=!1;this._skipReason="";this._resetDate="";this._features={adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1};this._toast="";this._featuresLoaded=!1;this._currencySymbol=""}get _lang(){return T(this.hass)}async openFor(t,n){this._entryId=t,this._taskId=n,this._error="",this._showSkip=!1,this._showReset=!1,this._showAdaptive=!1,this._skipReason="",this._resetDate=$t(new Date),this._open=!0,await Promise.all([this._loadTask(),this._loadFeatures()])}async _loadFeatures(){if(!this._featuresLoaded)try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/settings"});t?.features&&(this._features={...this._features,...t.features}),this._currencySymbol=j(t?.budget),lt(t?.budget),this._featuresLoaded=!0}catch{}}close(){this._open=!1,this._task=null,this._error=""}async _loadTask(){if(!(!this._entryId||!this._taskId))try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId});this._objectName=t.object?.name||"";let n=(t.tasks||[]).find(r=>r.id===this._taskId);this._task=n??null,this._taskRef=Tt(t.object,n)}catch(t){this._error=$(t,this._lang)}}async _runWs(t){this._busy=!0,this._error="";try{return await this.hass.connection.sendMessagePromise(t),this._busy=!1,!0}catch(n){return this._error=$(n,this._lang),this._busy=!1,!1}}_notifyChanged(t){this.dispatchEvent(new CustomEvent("task-action-fired",{detail:{entry_id:this._entryId,task_id:this._taskId,action:t},bubbles:!0,composed:!0}))}_onComplete(){!this._entryId||!this._taskId||!this._task||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-DACUEWGB.js").then(async({openCompleteDialog:t})=>{let n=this._task,r=[];try{r=(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0})).objects||[]}catch{}t(At({entryId:this._entryId,taskId:this._taskId,taskName:n.name,task:n,objects:r,lang:this._lang,checklist:n.checklist||[],adaptiveEnabled:!!n.adaptive_config?.enabled,currencySymbol:this._currencySymbol}))&&(this._notifyChanged("complete"),this.close())})}async _onSkipConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/skip",entry_id:this._entryId,task_id:this._taskId,reason:this._skipReason.trim()||null})&&(this._notifyChanged("skip"),this.close())}async _onResetConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/reset",entry_id:this._entryId,task_id:this._taskId,date:this._resetDate||void 0})&&(this._notifyChanged("reset"),this.close())}_onEdit(){!this._entryId||!this._taskId||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-DACUEWGB.js").then(({openEditTaskDialog:t})=>{t(this._entryId,this._taskId),this.close()})}_onQr(){!this._entryId||!this._taskId||!this._task||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-DACUEWGB.js").then(({openQrDialog:t})=>{t({entry_id:this._entryId,task_id:this._taskId,task_name:this._task.name,object_name:this._objectName}),this.close()})}async _onDelete(){if(!this._entryId||!this._taskId)return;let t=s("delete_task_confirm",this._lang)||`Delete "${this._task?.name}"?`;if(!window.confirm(t))return;await this._runWs({type:"maintenance_supporter/task/delete",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("delete"),this.close())}async _onArchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/archive",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("archive"),this.close())}async _onUnarchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/unarchive",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("unarchive"),this.close())}_onOpenInPanel(){if(!this._entryId||!this._taskId)return;let t=`/maintenance-supporter?entry_id=${encodeURIComponent(this._entryId)}&task_id=${encodeURIComponent(this._taskId)}`;history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed")),this.close()}async _applySuggestion(){if(!this._entryId||!this._taskId||!this._task?.suggested_interval)return;await this._runWs({type:"maintenance_supporter/task/apply_suggestion",entry_id:this._entryId,task_id:this._taskId,interval:this._task.suggested_interval})&&(this._toast=s("suggestion_applied",this._lang),this._notifyChanged("apply_suggestion"),await this._loadTask(),setTimeout(()=>{this._toast=""},2500))}async _reanalyzeInterval(){if(!(!this._entryId||!this._taskId)){this._busy=!0,this._error="";try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/analyze Line truncated
<div class="recommendation-card">
<h4>${s("suggested_interval",n)}</h4>
${zt(t.interval_days,t.suggested_interval,t.interval_confidence||"medium",n)}
<div class="recommendation-actions">
<button class="btn primary"
@click=${this._applySuggestion} ?disabled=${this._busy}>
<ha-icon icon="mdi:check"></ha-icon>
${s("apply_suggestion",n)}
</button>
<button class="btn"
@click=${this._reanalyzeInterval} ?disabled=${this._busy}>
<ha-icon icon="mdi:refresh"></ha-icon>
${s("reanalyze",n)}
</button>
</div>
</div>
`}_renderAdaptive(t){let n=this._lang,r=this._features.adaptive&&t.suggested_interval&&t.suggested_interval!==t.interval_days,a=t.degradation_trend!=null&&t.degradation_trend!=="insufficient_data"||t.days_until_threshold!=null||t.environmental_factor!=null&&t.environmental_factor!==1,o=this._features.adaptive&&t.interval_analysis?.weibull_beta!=null&&t.interval_analysis?.weibull_eta!=null,c=this._features.seasonal&&t.seasonal_factor&&t.seasonal_factor!==1;return!r&&!a&&!o&&!c?l`<div class="adaptive-empty">
${s("adaptive_no_data",n)}
</div>`:l`
<div class="adaptive-stack">
${this._toast?l`<div class="toast">${this._toast}</div>`:d}
${r?this._renderRecommendation(t):d}
${a?jt(t,n,this._features):d}
${o?Ot(t,n):d}
${c?l`
${qt(t,n,this._features)}
${t.seasonal_factors?.length===12||t.interval_analysis?.seasonal_factors?.length===12?Ft(t,n):d}
`:d}
</div>
`}_renderDetails(t){let n=this._lang,r=t.history||[],a=r.filter(u=>u.type==="completed"),o=a.reduce((u,p)=>u+(typeof p.cost=="number"?p.cost:0),0),c=(()=>{let u=a.map(p=>typeof p.duration=="number"?p.duration:null).filter(p=>p!=null);return u.length?Math.round(u.reduce((p,f)=>p+f,0)/u.length):null})();return l`
<div class="details">
<div class="stats-grid">
<div class="stat">
<span class="stat-label">${s("times_performed",n)}</span>
<span class="stat-value">${a.length}</span>
</div>
<div class="stat">
<span class="stat-label">${s("total_cost",n)}</span>
<span class="stat-value">${U(o,this._currencySymbol,n)}</span>
</div>
<div class="stat">
<span class="stat-label">${s("avg_duration",n)}</span>
<span class="stat-value">${B(c,n)}</span>
</div>
</div>
<div class="history-header">
<strong>${s("history",n)}</strong>
<span class="history-count">${r.length}</span>
</div>
${r.length===0?l`<div class="history-empty">${s("history_empty",n)}</div>`:l`
<div class="history-list">
${[...r].reverse().slice(0,20).map(u=>nt(u,{lang:n,hass:this.hass,currencySymbol:this._currencySymbol,openEdit:p=>this._onEditHistoryEntry(p),readingUnit:t.reading_unit,readingSlotDelta:(p,f)=>bt(r,p,f),taskRef:this._taskRef},{compact:!0}))}
${r.length>20?l`<div class="history-more">… +${r.length-20} ${s("older_entries",n)}</div>`:d}
</div>
`}
</div>
`}render(){if(!this._open)return d;let t=this._lang,n=this._task,r=this.hass?.user?.is_admin??!0;return l`
<div class="backdrop" @click=${this.close}></div>
<div class="dialog" role="dialog" aria-modal="true">
${n?l`
<div class="header">
<div class="title">
<span class="status-dot" style="background: ${W[n.status]||"#ccc"}"></span>
<span class="task-name">${n.name}</span>
</div>
<div class="object">
<button class="link-inline" @click=${()=>{this._entryId&&import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-DACUEWGB.js").then(({openObjectQuickActions:a})=>{a(this._entryId),this.close()})}}>${this._objectName}</button>
</div>
<div class="quick-info">
${n.next_due?l`<span><strong>${s("next_due",t)}:</strong> ${z(n.next_due,t)}</span>`:d}
${n.last_performed?l`<span><strong>${s("last_performed",t)}:</strong> ${z(n.last_performed,t)}</span>`:d}
${n.schedule?.kind&&!["manual","one_time"].includes(n.schedule.kind)||n.interval_days!=null?l`<span><strong>${s("interval",t)}:</strong> ${ht(n,t)}</span>`:d}
${N(n)?l`<span><strong>${s("phase_current",t)}:</strong> ${N(n)}</span>`:d}
</div>
</div>
${this._error?l`<div class="error">${this._error}</div>`:d}
${this._showSkip?l`
<div class="inline-form">
<label>${s("skip_reason",t)}</label>
<input type="text" .value=${this._skipReason}
@input=${a=>{this._skipReason=a.target.value}} />
<div class="inline-actions">
<button class="btn cancel" @click=${()=>{this._showSkip=!1}} ?disabled=${this._busy}>
${s("cancel",t)}
</button>
<button class="btn primary" @click=${this._onSkipConfirm} ?disabled=${this._busy}>
${s("skip",t)}
</button>
</div>
</div>
`:this._showReset?l`
<div class="inline-form">
<label>${s("reset_to_date",t)}</label>
<ms-date-field
kind="date"
.hass=${this.hass}
.lang=${t}
.value=${this._resetDate}
@value-changed=${a=>{this._resetDate=a.detail.value}}
></ms-date-field>
<div class="inline-actions">
<button class="btn cancel" @click=${()=>{this._showReset=!1}} ?disabled=${this._busy}>
${s("cancel",t)}
</button>
<button class="btn primary" @click=${this._onResetConfirm} ?disabled=${this._busy}>
${s("reset",t)}
</button>
</div>
</div>
`:l`
<div class="actions primary-row">
<ha-button appearance="accent" variant="success" @click=${this._onComplete} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:check"></ha-icon>
${s("complete",t)}
</ha-button>
${n.allow_skip!==!1?l`
<ha-button appearance="outlined" variant="warning" @click=${()=>{this._showSkip=!0}} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:skip-next"></ha-icon>
${s("skip",t)}
</ha-button>
`:d}
<ha-button appearance="outlined" variant="neutral" @click=${()=>{this._showReset=!0}} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:restart"></ha-icon>
${s("reset",t)}
</ha-button>
</div>
${r?l`
<div class="actions secondary-row">
<ha-button size="small" appearance="outlined" variant="neutral" @click=${this._onEdit} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:pencil"></ha-icon>
${s("edit",t)}
</ha-button>
<ha-button size="small" appearance="outlined" variant="neutral" @click=${this._onQr} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:qrcode"></ha-icon>
${s("qr_code",t)}
</ha-button>
<ha-button size="small" appearance="outlined" variant="neutral"
@click=${n.archived?this._onUnarchive:this._onArchive}
.disabled=${this._busy}>
<ha-icon slot="start" icon="${n.archived?"mdi:archive-arrow-up-outline":"mdi:archive-outline"}"></ha-icon>
${n.archived?s("unarchive",t):s("archive",t)}
</ha-button>
<ha-button size="small" appearance="outlined" variant="danger" class="danger" @click=${this._onDelete} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:delete"></ha-icon>
${s("delete",t)}
</ha-button>
</div>
`:d}
<div class="details-toggle">
<button class="link" @click=${()=>{this._showDetails=!this._showDetails}}>
<ha-icon icon="${this._showDetails?"mdi:chevron-up":"mdi:chevron-down"}"></ha-icon>
${this._showDetails?s("hide_details",t):s("show_details",t)}
</button>
${this._features.adaptive||this._features.seasonal||this._features.environmental?l`<button class="link" @click=${()=>{this._showAdaptive=!this._showAdaptive}}>
<ha-icon icon="${this._showAdaptive?"mdi:chart-line":"mdi:chart-line-variant"}"></ha-icon>
${this._showAdaptive?s("hide_stats",t):s("show_stats",t)}
</button>`:d}
</div>
${this._showDetails?this._renderDetails(n):d}
${this._showAdaptive?this._renderAdaptive(n):d}
<div class="footer">
<button class="link" @click=${this._onOpenInPanel}>
<ha-icon icon="mdi:open-in-new"></ha-icon>
${s("open_in_panel",t)}
</button>
</div>
`}
`:l`<div class="loading">${s("loading",t)}</div>`}
</div>
`}};g.styles=[mt,M`
:host { display: contents; }
.backdrop {
position: fixed; inset: 0; z-index: 100;
background: rgba(0,0,0,0.5);
}
.dialog {
position: fixed; left: 50%; top: 50%;
transform: translate(-50%, -50%);
width: 95vw; max-width: 460px;
max-height: 92vh; overflow: auto;
background: var(--card-background-color, var(--ha-card-background, #1c1c1c));
color: var(--primary-text-color);
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
padding: 20px;
display: flex; flex-direction: column; gap: 14px;
z-index: 101;
}
.header { display: flex; flex-direction: column; gap: 6px; }
.title { display: flex; align-items: center; gap: 10px; }
.status-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
.task-name { font-size: 18px; font-weight: 600; }
.object { font-size: 13px; color: var(--secondary-text-color); }
.link-inline {
background: transparent; border: none; padding: 0; cursor: pointer;
color: var(--primary-color); font-size: inherit; font-family: inherit;
}
.link-inline:hover { text-decoration: underline; }
.quick-info {
display: flex; flex-wrap: wrap; gap: 12px;
font-size: 12px; color: var(--secondary-text-color);
padding-top: 4px; border-top: 1px solid var(--divider-color);
}
.quick-info strong { color: var(--primary-text-color); font-weight: 500; }
.actions { display: flex; gap: 8px; }
.actions.primary-row { gap: 6px; }
.actions.primary-row .btn { flex: 1; }
.actions.primary-row ha-button { flex: 1; }
/* Edit + QR are admin-tools — left-align as a group; Delete is destructive
so it gets pushed to the far right with margin-left:auto for visual
separation. Earlier this row was flex-end which left a strange empty
gap on the left (user feedback). */
.actions.secondary-row {
padding-top: 8px; border-top: 1px solid var(--divider-color);
justify-content: flex-start;
}
.actions.secondary-row .btn.danger,
.actions.secondary-row ha-button.danger {
margin-left: auto;
}
.actions.secondary-row ha-button { --ha-button-font-size: 13px; }
.btn {
padding: 8px 12px; font-size: 14px;
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: 6px;
transition: background 0.12s;
}
.btn:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
.btn[disabled] { opacity: 0.5; cursor: wait; }
.btn.primary {
background: var(--primary-color);
color: var(--text-primary-color, white);
border-color: var(--primary-color);
}
.btn.cancel { background: transparent; }
.btn.ghost { padding: 6px 10px; font-size: 13px; }
.btn.danger { color: var(--error-color); }
.btn ha-icon { --mdc-icon-size: 18px; }
.inline-form { display: flex; flex-direction: column; gap: 8px; }
.inline-form label { font-size: 13px; color: var(--secondary-text-color); }
.inline-form input {
padding: 8px; font-size: 14px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color, #444);
border-radius: 6px;
}
.inline-actions { display: flex; gap: 8px; justify-content: flex-end; }
.footer { display: flex; justify-content: center; padding-top: 4px; }
.link {
background: transparent; border: none; cursor: pointer;
color: var(--primary-color); font-size: 13px;
display: inline-flex; align-items: center; gap: 4px;
}
.link:hover { text-decoration: underline; }
.link ha-icon { --mdc-icon-size: 14px; }
.loading { padding: 24px; text-align: center; color: var(--secondary-text-color); }
.error {
padding: 8px; border-radius: 6px;
background: rgba(211,47,47,0.1);
color: var(--error-color, #d32f2f); font-size: 13px;
}
/* Details (expandable Show details section) */
.details-toggle { display: flex; justify-content: center; margin-top: 4px; }
.details {
display: flex; flex-direction: column; gap: 12px;
border-top: 1px solid var(--divider-color);
padding-top: 12px;
}
.stats-grid {
display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px;
}
.stat {
display: flex; flex-direction: column; gap: 2px;
background: var(--secondary-background-color, rgba(255,255,255,0.04));
padding: 8px; border-radius: 6px;
align-items: center;
}
.stat-label { font-size: 11px; color: var(--secondary-text-color); text-transform: uppercase; letter-spacing: 0.5px; }
.stat-value { font-size: 16px; font-weight: 600; }
.history-header {
display: flex; align-items: baseline; gap: 8px;
font-size: 14px;
}
.history-count {
font-size: 12px; color: var(--secondary-text-color);
background: var(--secondary-background-color); padding: 2px 8px; border-radius: 999px;
}
.history-empty { color: var(--secondary-text-color); font-style: italic; font-size: 13px; }
/* The rows themselves are the shared renderer's (.history-entry.compact
+ the history-* classes from sharedStyles); only the list chrome is
local. */
.history-list { display: flex; flex-direction: column; max-height: 280px; overflow: auto; }
.history-list .history-entry {
padding: 6px 8px; border-radius: 6px; border-bottom: none; margin-bottom: 6px;
background: var(--secondary-background-color, rgba(255,255,255,0.03));
}
.history-list .history-date { font-size: 11px; }
.history-list .history-details { font-size: 11px; }
.history-more { padding: 8px; text-align: center; font-size: 12px; color: var(--secondary-text-color); font-style: italic; }
/* Adaptive section — wraps the panel renderers (which assume sharedStyles
are present) and adds dialog-specific layout. */
.adaptive-stack {
display: flex; flex-direction: column; gap: 12px;
border-top: 1px solid var(--divider-color);
padding-top: 12px;
}
.adaptive-empty {
padding: 16px; text-align: center;
color: var(--secondary-text-color);
font-style: italic; font-size: 13px;
border-top: 1px solid var(--divider-color);
}
.toast {
padding: 8px 12px; border-radius: 6px;
background: rgba(76, 175, 80, 0.15);
color: #4caf50; font-size: 13px; font-weight: 500;
}
/* The panel's recommendation-card uses ha-button. We use plain <button>
in this dialog's button styles. Re-style the action row to match. */
.recommendation-actions {
display: flex; gap: 8px; margin-top: 8px;
}
/* Constrain SVG charts so they fit the dialog width even on mobile. */
.weibull-section, .seasonal-card-compact { max-width: 100%; }
.weibull-chart svg { max-width: 100%; height: auto; }
.details-toggle { gap: 12px; flex-wrap: wrap; }
`],h([L({attribute:!1})],g.prototype,"hass",2),h([_()],g.prototype,"_open",2),h([_()],g.prototype,"_entryId",2),h([_()],g.prototype,"_taskId",2),h([_()],g.prototype,"_task",2),h([_()],g.prototype,"_objectName",2),h([_()],g.prototype,"_taskRef",2),h([_()],g.prototype,"_busy",2),h([_()],g.prototype,"_error",2),h([_()],g.prototype,"_showSkip",2),h([_()],g.prototype,"_showReset",2),h([_()],g.prototype,"_showDetails",2),h([_()],g.prototype,"_showAdaptive",2),h([_()],g.prototype,"_skipReason",2),h([_()],g.prototype,"_resetDate",2),h([_()],g.prototype,"_features",2),h([_()],g.prototype,"_toast",2);customElements.get("maintenance-task-quick-actions-dialog")||customElements.define("maintenance-task-quick-actions-dialog",g);function Vt(e){return!!e&&/^https?:\/\//i.test(e)}function Wt(e){return e?customElements.get("ha-markdown")?l`<ha-markdown class="notes-md" .content=${e} breaks></ha-markdown>`:l`${e}`:d}var w=class extends D{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._data=null;this._busy=!1;this._error=""}get _lang(){return T(this.hass)}async openFor(t){this._entryId=t,this._error="",this._open=!0,await this._load()}close(){this._open=!1,this._data=null,this._error=""}async _load(){if(this._entryId)try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId});this._data=t}catch(t){this._error=$(t,this._lang)}}_onEditObject(){!this._entryId||!this._data||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-DACUEWGB.js").then(({openEditObjectDialog:t})=>{t(this._entryId,this._data.object),this.close()})}_onAddTask(){this._entryId&&import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-DACUEWGB.js").then(({openCreateTaskDialog:t})=>{t(this._entryId),this.close()})}async _onDelete(){if(!this._entryId||!this._data)return;let t=s("delete_object_confirm",this._lang)||`Delete "${this._data.object.name}" and all its tasks?`;if(window.confirm(t)){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/delete",entry_id:this._entryId}),this.dispatchEvent(new CustomEvent("object-deleted",{detail:{entry_id:this._entryId},bubbles:!0,composed:!0})),this.close()}catch(n){this._error=$(n,this._lang)}finally{this._busy=!1}}}async _onArchiveObject(){if(!this._entryId||!this._data)return;let t=!!this._data.object.archived;if(!t){let n=s("confirm_archive_object",this._lang);if(!window.confirm(n))return}this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:t?"maintenance_supporter/object/unarchive":"maintenance_supporter/object/archive",entry_id:this._entryId}),this.dispatchEvent(new CustomEvent("object-changed",{detail:{entry_id:this._entryId},bubbles:!0,composed:!0})),this.close()}catch(n){this._error=$(n,this._lang)}finally{this._busy=!1}}_onTaskClick(t){this._entryId&&import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-DACUEWGB.js").then(({openTaskQuickActions:n})=>{n(this._entryId,t)})}render(){if(!this._open)return d;let t=this._lang,n=this._data,r=n?.object,a=n?.tasks||[],o=this.hass?.user?.is_admin??!0;return l`
<div class="backdrop" @click=${this.close}></div>
<div class="dialog" role="dialog" aria-modal="true">
${n&&r?l`
<div class="header">
<div class="title">${r.name}</div>
${this._renderMetaRow(r)}
</div>
${this._error?l`<div class="error">${this._error}</div>`:d}
<div class="tasks-section">
<div class="section-header">
<strong>${s("tasks",t)}</strong>
<span class="count">${a.length}</span>
</div>
${a.length===0?l`<div class="empty">${s("no_tasks",t)}</div>`:l`
<div class="task-list">
${a.map(c=>l`
<div class="task-row" @click=${()=>this._onTaskClick(c.id)}>
<span class="status-dot" style="background: ${W[c.status]||"#ccc"}"></span>
<span class="task-name">${c.name}</span>
<span class="task-status">${s(c.status||"ok",t)}</span>
</div>
`)}
</div>
`}
</div>
${r.notes?l`
<div class="notes-section">
<strong>${s("object_notes_label",t)}</strong>
<div class="notes-body">${Wt(r.notes)}</div>
</div>
`:d}
${o?l`
<div class="actions">
<button class="btn primary" @click=${this._onAddTask} ?disabled=${this._busy}>
<ha-icon icon="mdi:plus"></ha-icon>
${s("add_task",t)}
</button>
<button class="btn" @click=${this._onEditObject} ?disabled=${this._busy}>
<ha-icon icon="mdi:pencil"></ha-icon>
${s("edit",t)}
</button>
<button class="btn" @click=${this._onArchiveObject} ?disabled=${this._busy}>
<ha-icon icon="${r.archived?"mdi:archive-arrow-up-outline":"mdi:archive-outline"}"></ha-icon>
${r.archived?s("unarchive_object",t):s("archive_object",t)}
</button>
<button class="btn danger" @click=${this._onDelete} ?disabled=${this._busy}>
<ha-icon icon="mdi:delete"></ha-icon>
${s("delete",t)}
</button>
</div>
`:d}
`:l`<div class="loading">${s("loading",t)}</div>`}
</div>
`}_renderMetaRow(t){let n=this._lang,r=[];return t.area_id&&r.push([s("area",n),t.area_id]),t.manufacturer&&r.push([s("manufacturer",n),t.manufacturer]),t.model&&r.push([s("model",n),t.model]),t.serial_number&&r.push([s("serial_number_label",n),t.serial_number]),t.installation_date&&r.push([s("installed",n),t.installation_date]),t.warranty_expiry&&r.push([s("warranty",n),t.warranty_expiry]),t.documentation_url&&r.push([s("documentation_url_label",n),t.documentation_url]),r.length===0?d:l`
<div class="meta">
${r.map(([a,o])=>l`
<div class="meta-item">
<span class="meta-label">${a}</span>
<span class="meta-value">${Vt(o)?l`<a href="${o}" target="_blank" rel="noopener noreferrer">${o}</a>`:o}</span>
</div>
`)}
</div>
`}};w.styles=M`
:host { display: contents; }
.backdrop {
position: fixed; inset: 0; z-index: 100; background: rgba(0,0,0,0.5);
}
.dialog {
position: fixed; left: 50%; top: 50%;
transform: translate(-50%, -50%);
width: 95vw; max-width: 480px;
max-height: 92vh; overflow: auto;
background: var(--card-background-color, var(--ha-card-background, #1c1c1c));
color: var(--primary-text-color);
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
padding: 20px; z-index: 101;
display: flex; flex-direction: column; gap: 14px;
}
.header { display: flex; flex-direction: column; gap: 6px; }
.title { font-size: 20px; font-weight: 600; }
.meta { display: flex; flex-direction: column; gap: 4px; padding-top: 4px; border-top: 1px solid var(--divider-color); }
.meta-item { display: flex; gap: 8px; font-size: 12px; }
.meta-label { color: var(--secondary-text-color); min-width: 100px; }
.meta-value { color: var(--primary-text-color); flex: 1; word-break: break-word; }
.meta-value a { color: var(--primary-color); }
.tasks-section, .notes-section { display: flex; flex-direction: column; gap: 6px; }
.section-header { display: flex; align-items: baseline; gap: 8px; }
.count {
font-size: 11px; color: var(--secondary-text-color);
background: var(--secondary-background-color); padding: 2px 8px; border-radius: 999px;
}
.empty { color: var(--secondary-text-color); font-style: italic; font-size: 13px; padding: 8px 0; }
.task-list { display: flex; flex-direction: column; gap: 4px; max-height: 200px; overflow: auto; }
.task-row {
display: flex; align-items: center; gap: 10px;
padding: 8px; border-radius: 6px; cursor: pointer;
background: var(--secondary-background-color, rgba(255,255,255,0.03));
transition: background 0.12s;
}
.task-row:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
.status-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.task-name { flex: 1; font-size: 14px; }
.task-status { font-size: 11px; color: var(--secondary-text-color); text-transform: uppercase; }
.notes-body { white-space: pre-wrap; font-size: 13px; padding: 8px; background: var(--secondary-background-color); border-radius: 6px; }
.notes-body ha-markdown { white-space: normal; }
.actions { display: flex; gap: 8px; padding-top: 8px; border-top: 1px solid var(--divider-color); }
.actions .btn { flex: 1; }
.btn {
padding: 8px; 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; justify-content: center; gap: 6px;
}
.btn:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
.btn[disabled] { opacity: 0.5; cursor: wait; }
.btn.primary { background: var(--primary-color); color: var(--text-primary-color, white); border-color: var(--primary-color); }
.btn.danger { color: var(--error-color); }
.btn ha-icon { --mdc-icon-size: 16px; }
.loading { padding: 24px; text-align: center; color: var(--secondary-text-color); }
.error { padding: 8px; border-radius: 6px; background: rgba(211,47,47,0.1); color: var(--error-color); font-size: 13px; }
`,h([L({attribute:!1})],w.prototype,"hass",2),h([_()],w.prototype,"_open",2),h([_()],w.prototype,"_entryId",2),h([_()],w.prototype,"_data",2),h([_()],w.prototype,"_busy",2),h([_()],w.prototype,"_error",2);customElements.get("maintenance-object-quick-actions-dialog")||customElements.define("maintenance-object-quick-actions-dialog",w);var Ut="maintenance-object-dialog",Bt="maintenance-task-dialog",be="maintenance-history-edit-dialog",xe="maintenance-complete-dialog",$e="maintenance-qr-dialog",ke="maintenance-task-quick-actions-dialog",we="maintenance-object-quick-actions-dialog";function J(){return document.querySelector("home-assistant")?.hass}function Ae(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function H(e){let i=Ae(),t=i.querySelector(e)??document.body.querySelector(e);return t?t.parentNode!==i&&i.appendChild(t):(t=document.createElement(e),i.appendChild(t)),t}function I(e){let i=J();if(!i)return!1;e.hass=i;let t=T(i);return at(t)||ot(t).then(()=>{e.requestUpdate?.()}),dt(i.locale,i.config?.country),!0}function $n(e){return Y(e).then(i=>i.rowActionStyle)}function kn(){wt()}function wn(){let e=H(Ut);return I(e)?(e.openCreate(),!0):!1}function An(e,i){let t=H(Ut);return I(t)?(t.openEdit(e,i),!0):!1}function En(e="",i){let t=H(Bt);if(!I(t))return!1;let n=J();return n?((async()=>{let r=await Y(n),a=t;a.checklistsEnabled=r.features.checklists,a.scheduleTimeEnabled=r.features.schedule_time,a.completionActionsEnabled=r.features.completion_actions,a.defaultWarningDays=r.defaultWarningDays,a.openCreate(e,i)})(),!0):!1}function Ln(e,i){let t=H(Bt);if(!I(t))return!1;let n=J();return n?((async()=>{try{let[r,a]=await Promise.all([n.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:e}),Y(n)]),o=(r.tasks||[]).find(u=>u.id===i);if(!o){console.warn(`openEditTaskDialog: task ${i} not found in entry ${e}`);return}let c=t;c.checklistsEnabled=a.features.checklists,c.scheduleTimeEnabled=a.features.schedule_time,c.completionActionsEnabled=a.features.completion_actions,c.defaultWarningDays=a.defaultWarningDays,await c.openEdit(e,o)}catch(r){console.warn("openEditTaskDialog: failed to load task/features",r)}})(),!0):!1}function Tn(e){let i=H(be);return I(i)?(i.openEdit(e),!0):!1}function Hn(e){let i=H(xe);return I(i)?(Et(i,e,T(J())),!0):!1}function In(e){let i=H($e);return I(i)?(i.openForTask(e.entry_id,e.task_id,e.object_name,e.task_name),!0):!1}function Mn(e,i){let t=H(ke);return I(t)?(t.openFor(e,i),!0):!1}function Dn(e){let i=H(we);return I(i)?(i.openFor(e),!0):!1}export{Vt as a,oe as b,ce as c,te as d,Tt as e,ti as f,Ht as g,Wt as h,Qt as i,Xt as j,tt as k,At as l,Et as m,m as n,_i as o,mi as p,fi as q,gi as r,yi as s,vi as t,bi as u,et as v,Je as w,ci as x,pi as y,nt as z,Ot as A,jt as B,zt as C,qt as D,Ft as E,$n as F,kn as G,wn as H,An as I,En as J,Ln as K,Tn as L,Hn as M,In as N,Mn as O,Dn as P};
@@ -1,2 +1,2 @@
/*! maintenance_supporter frontend 2.96.0 */
/*! maintenance_supporter frontend 2.97.1 */
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};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.95.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};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.88.0 */
import{q as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OXPKT66L.js";function f(r){return`${r.entry_id??""}\0${r.part_id}`}function g(r,n,i,o){let t=!!r.entry_id&&r.entry_id!==n,e=t?r.entry_id:n,s=i.find(l=>l.entry_id===e),a=(s?.parts||[]).find(l=>l.id===r.part_id)||null,u=t&&s?.object?.name||"",d=a?.name||p("shared_part_unknown",o);return{part:a,foreign:t,ownerName:u,label:u?`${d} (${u})`:d}}function _(r,n,i,o){let{part:t,label:e}=g(r,n,i,o),s=t&&t.stock!==null&&t.stock!==void 0?` (${t.stock}${t.unit?" "+t.unit:""})`:"",a=t?.storage_location?` \u2014 ${t.storage_location}`:"";return`${r.quantity}\xD7 ${e}${s}${a}`}function R(r,n,i,o){let e=(i.find(a=>a.entry_id===n)?.parts||[]).map(a=>({...a})),s=new Set(e.map(a=>f({part_id:a.id})));for(let a of r?.consumes_parts||[]){if(!a.entry_id||a.entry_id===n)continue;let u=f(a);if(s.has(u))continue;s.add(u);let{part:d,ownerName:l}=g(a,n,i,o);e.push({id:a.part_id,name:d?.name||p("shared_part_unknown",o),unit:d?.unit,stock:d?.stock??null,storage_location:d?.storage_location,entry_id:a.entry_id,owner_name:l})}return e}function w(){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 c(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||c(n).length>0)).sort((n,i)=>n.timestamp.localeCompare(i.timestamp))}function S(r){return y(r??[]).map(n=>({timestamp:n.timestamp,values:c(n)})).filter(n=>n.values.length>0)}function P(r,n,i){let o;for(let t of r){if(i!==void 0){let s=new Date(t.timestamp).getTime();if(!isNaN(s)&&s>=i)break}let e=t.values.find(s=>s.id===n);e&&(o=e)}return o}function b(r,n,i){let o=c(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=c(e).find(a=>a.id===i);s&&(t=s.value)}return t==null?null:o.value-t}function E(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 v(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>=20))break}return n}var x=["notes","cost","duration","photo","user"],h={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"};export{f as a,_ as b,R as c,w as d,c as e,S as f,P as g,b as h,E as i,v as j,x as k,h as l};
File diff suppressed because it is too large. Load diff
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.94.0 */
import{b as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DTRCTWKY.js";import{a as l}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-63C4ZGBD.js";async function _(e,t,n=300){return(await e.connection.sendMessagePromise({type:"auth/sign_path",path:t,expires:n})).path}async function c(e,t,n=300){return _(e,`/api/maintenance_supporter/document/${t}`,n)}async function b(e,t,n=""){let o=window.open("about:blank","_blank");try{let s=await c(e,t);o&&(o.location.href=new URL(s+n,window.location.origin).href)}catch(s){throw o&&o.close(),s}}async function h(e,t,n){a(await c(e,t,30),n)}function w(e,t=null){let n=URL.createObjectURL(new Blob([e],{type:"text/html"}));t&&!t.closed?t.location.href=n:window.open(n,"_blank"),setTimeout(()=>URL.revokeObjectURL(n),6e4)}function y(){return window.open("about:blank","_blank")}var r={operatorWriteEnabled:!1,operatorIds:[]};function A(e,t=r){return e?e.is_admin?!0:t.operatorWriteEnabled&&t.operatorIds.includes(e.id):!1}var m=["buttons_compact","buttons","icons"];function g(e){let[t,n]=l.default_warning_days,o=e?.general?.default_warning_days,s=e?.general?.row_action_style;return{features:{...i.features,...e?.features??{}},defaultWarningDays:typeof o=="number"&&Number.isFinite(o)&&o>=t&&o<=n?o:i.defaultWarningDays,rowActionStyle:m.includes(s??"")?s:i.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}}var i={features:{adaptive:!1,predictions:!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};function u(){let e=window;return e.__msSettingsCache??={promise:null}}function C(e){let t=u();if(t.promise)return t.promise;let n=e.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(o=>g(o)).catch(()=>(t.promise===n&&(t.promise=null),i));return t.promise=n,n}function W(){u().promise=null}var d=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{_ as a,c as b,b as c,h as d,w as e,y as f,r as g,A as h,m as i,g as j,C as k,W as l,d as m};
@@ -1,452 +0,0 @@
/*! maintenance_supporter frontend 2.90.0 */
import{a as x,g as q,l as L}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-5XRT3AM7.js";import{a as O}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WQXORDNI.js";import{M as P,a as o,b as y,c,f as p,h as k,l,m as u,q as a,x as T,y as A}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";function V(m){if(!m)return[];let n=[],t=m.photo_doc_id;typeof t=="string"&&n.push(t);let e=m.photo_doc_ids;Array.isArray(e)&&n.push(...e);let i=[];for(let s of n){if(typeof s!="string")continue;let r=s.trim();if(!(!r||i.includes(r))&&(i.push(r),i.length>=10))break}return i}async function j(m,n,t,e){let i=new FormData;i.append("entry_id",n);for(let f of e)i.append("tags",f);i.append("file",t,t.name);let s=await fetch("/api/maintenance_supporter/document/upload",{method:"POST",headers:{Authorization:`Bearer ${m.auth?.data?.access_token??""}`},body:i});if(s.status===413)throw new Error("doc_too_large");if(!s.ok)throw new Error("doc_upload_failed");let r=await s.json();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 H(m,n,t){return(await j(m,n,t,["photo"])).id}async function S(m,n){await Promise.all(n.map(t=>m.connection.sendMessagePromise({type:"maintenance_supporter/documents/delete",doc_id:t}).catch(()=>{})))}var w=class{constructor(n,t){this.host=n;this.opts=t;this.photos=[];this.uploadedIds=[];this.uploading=!1;this.errorKey="";this.max=t.max??10,n.addController(this)}hostConnected(){}get ids(){return this.photos.map(n=>n.id)}get remaining(){return Math.max(this.max-this.photos.length,0)}get full(){return this.remaining===0}errorText(n){return this.errorKey?a(this.errorKey,n).replace("{max}",String(this.max)):""}clearError(){this.errorKey=""}reset(n=[]){this._revokeAll(),this.photos=n.map(t=>({id:t,preview:""})),this.uploadedIds=[],this.uploading=!1,this.errorKey="",this.host.requestUpdate()}async addFiles(n){if(n.length===0)return;let t=n.slice(0,this.remaining);this.uploading=!0,this.errorKey="",this.host.requestUpdate();try{for(let e of t){let i=await H(this.opts.hass(),this.opts.entryId(),e);this.uploadedIds=[...this.uploadedIds,i],this.photos=[...this.photos,{id:i,preview:URL.createObjectURL(e)}],this.host.requestUpdate()}n.length>t.length&&(this.errorKey="photos_limit")}catch(e){this.errorKey=e instanceof Error&&e.message==="doc_too_large"?"doc_too_large":"doc_upload_failed"}finally{this.uploading=!1,this.host.requestUpdate()}}remove(n){let t=this.photos.find(e=>e.id===n);t?.preview&&URL.revokeObjectURL(t.preview),this.photos=this.photos.filter(e=>e.id!==n),this.uploadedIds.includes(n)&&(this.uploadedIds=this.uploadedIds.filter(e=>e!==n),S(this.opts.hass(),[n])),this.host.requestUpdate()}discardOrphans(){if(this.uploadedIds.length===0)return;let n=this.uploadedIds;this.uploadedIds=[],S(this.opts.hass(),n)}markAttached(){this.uploadedIds=[]}_revokeAll(){for(let n of this.photos)n.preview&&URL.revokeObjectURL(n.preview)}};function $(){if(window.externalApp!==void 0)return!0;let n=typeof navigator<"u"&&navigator.userAgent||"";return/Home Assistant\//.test(n)&&/Android/.test(n)}var I={objectSections:"msp-object-sections",printOptions:"msp-print-options",batteryRosterOpen:"msp-bf-roster-open",docSort:"msp-doc-sort",cameraDevice:"msp-camera-device",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"};function R(m){try{return localStorage.getItem(m)}catch{return null}}function N(m,n){try{localStorage.setItem(m,n)}catch{}}function U(){if(!$())return!1;let m=typeof navigator<"u"?navigator.mediaDevices:void 0;return!!m&&typeof m.getUserMedia=="function"}var C=1920,B=.88,b=class extends k{constructor(){super(...arguments);this.lang="en";this._open=!1;this._busy=!1;this._devices=[];this._deviceIndex=-1;this._switchFailed=!1;this._facing="environment";this._stream=null}async open(){if(this._open)return;let t=typeof navigator<"u"?navigator.mediaDevices:void 0;if(!t||typeof t.getUserMedia!="function"){this._unavailable("no_media_devices");return}let e=R(I.cameraDevice),i=!1;if(e)try{this._stream=await t.getUserMedia({video:{deviceId:{exact:e}},audio:!1}),i=!0}catch{}if(!i){try{this._stream=await t.getUserMedia({video:{facingMode:{ideal:"environment"},zoom:1,advanced:[{zoom:1}]},audio:!1})}catch(r){this._unavailable(r instanceof Error?r.name||r.message:String(r));return}await this._preferMainBackCamera(t)}await this._applyZoomOne(),await this._listDevices(t),this._deviceIndex=this._indexOfCurrent(e&&i?e:null),this._switchFailed=!1,this._facing=this._stream?.getVideoTracks()[0]?.getSettings().facingMode??"environment",this._Line truncated
<div class="overlay" role="dialog" aria-modal="true" aria-label=${a("doc_camera",t)}>
<video autoplay playsinline muted></video>
${this._switchFailed?c`<div class="switch-note" role="status">${a("camera_switch_failed",t)}</div>`:p}
<div class="bar">
<button type="button" class="cancel" @click=${this.close}>${a("cancel",t)}</button>
${this._devices.length>1?c`<button type="button" class="switch" ?disabled=${this._busy} title=${a("camera_switch_lens",t)} aria-label=${a("camera_switch_lens",t)} @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>`:p}
<button type="button" class="shoot" ?disabled=${this._busy} @click=${this._shoot}>
<ha-icon icon="mdi:camera"></ha-icon><span>${a("camera_capture_shoot",t)}</span>
</button>
</div>
</div>
`}};b.styles=y`
: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 ha-icon { --mdc-icon-size: 22px; }
.switch-pos { font-size: 12px; opacity: 0.85; }
.switch-note { position: absolute; left: 12px; right: 12px; bottom: 84px; text-align: center; color: #fff; font-size: 13px; text-shadow: 0 1px 2px #000; }
.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; }
`,o([l({type:String})],b.prototype,"lang",2),o([u()],b.prototype,"_open",2),o([u()],b.prototype,"_busy",2),o([u()],b.prototype,"_devices",2),o([u()],b.prototype,"_deviceIndex",2),o([u()],b.prototype,"_switchFailed",2);customElements.get("ms-camera-capture")||customElements.define("ms-camera-capture",b);var z=y`
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;
}
`,v=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=$();this._inAppCamera=U()}createRenderRoot(){return this}get _locked(){return this.disabled||this.busy}_emit(t){t.length!==0&&this.dispatchEvent(new CustomEvent("files-picked",{detail:{files:t},bubbles:!0,composed:!0}))}_onInput(t){let e=t.target,i=Array.from(e.files??[]);e.value="",this._emit(i)}_onCameraClick(t){!this._inAppCamera||this._locked||(t.preventDefault(),this.querySelector("ms-camera-capture")?.open())}_onCameraUnavailable(){this._inAppCamera=!1,this.querySelector(".photo-pick-camera input")?.click()}_onKeydown(t){t.key!=="Enter"&&t.key!==" "||(t.preventDefault(),!this._locked&&t.currentTarget.click())}render(){if(this.remaining<=0||!this.showCamera&&!this.showGallery)return p;let t=this.lang,e=this._locked?"disabled":"",i=this.busy?a("uploading",t):a("doc_camera",t),s=a(this._singlePick?"choose_photo":"choose_photos",t);return c`
<div class="photo-pickers">
${this.showCamera?c`<label class="photo-pick photo-pick-camera ${e}" role="button" tabindex="0"
aria-label=${i} title=${this.compact?i:p}
@click=${this._onCameraClick} @keydown=${this._onKeydown}>
<ha-icon icon="mdi:camera"></ha-icon>
${this.compact?p:c`<span>${i}</span>`}
<input type="file" accept=${this.accept} capture="environment"
?disabled=${this._locked} @change=${this._onInput} />
</label>`:p}
${this.showGallery?c`<label class="photo-pick photo-pick-gallery ${e}" role="button" tabindex="0"
aria-label=${s} title=${this.compact?s:p}
@keydown=${this._onKeydown}>
<ha-icon icon="mdi:image-multiple"></ha-icon>
${this.compact?p:c`<span>${s}</span>`}
<input type="file" accept=${this.accept} ?multiple=${!this._singlePick}
?disabled=${this._locked} @change=${this._onInput} />
</label>`:p}
</div>
${this.showGallery&&this._singlePick?c`<div class="photo-android-hint">${a("photos_android_hint",t)}</div>`:p}
${this.showCamera&&this._inAppCamera?c`<ms-camera-capture .lang=${t}
@photo-captured=${r=>this._emit([r.detail.file])}
@capture-unavailable=${this._onCameraUnavailable}></ms-camera-capture>`:p}
`}};o([l({type:String})],v.prototype,"lang",2),o([l({type:Boolean})],v.prototype,"disabled",2),o([l({type:Boolean})],v.prototype,"busy",2),o([l({type:String})],v.prototype,"accept",2),o([l({type:Boolean})],v.prototype,"showCamera",2),o([l({type:Boolean})],v.prototype,"showGallery",2),o([l({type:Boolean})],v.prototype,"compact",2),o([l({type:Number})],v.prototype,"remaining",2),o([u()],v.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",v);var d=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.currencySymbol="";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 w(this,{entryId:()=>this.entryId,hass:()=>this.hass});this._readingValue="";this._readingValues={};this._restockQty="";this._completedAt="";this._usedParts={};this.checklistPrefill={}}open(t={}){this._open||(this._open=!0,this.viaTagScan=!!t.viaTagScan,this._notes="",this._cost="",this._duration="",this._error="",this._checklistState=Object.fromEntries(this.checklist.map((e,i)=>[String(i),!!this.checklistPrefill[e]]).filter(([,e])=>e)),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(e=>[x(e),{...e}])))}_toggleCheck(t){let e=String(t);this._checklistState={...this._checklistState,[e]:!this._checklistState[e]}}_setFeedback(t){this._feedback=t}async _complete(){this._loading=!0,this._error="",this._photos.clearError();try{let t={type:"maintenance_supporter/task/complete",entry_id:this.entryId,task_id:this.taskId};if(this._notes&&(t.notes=this._notes),this._cost){let e=parseFloat(this._cost);!isNaN(e)&&e>=0&&(t.cost=e)}if(this._duration){let e=parseInt(this._duration,10);!isNaN(e)&&e>=0&&(t.duration=e)}if(this.checklist.length>0&&(t.checklist_state=this._checklistState),this.adaptiveEnabled&&(t.feedback=this._feedback),this._photos.photos.length>0&&(t.photo_doc_ids=this._photos.ids),this.viaTagScan&&(t.via_tag_scan=!0),this._completedAt){if(new Date(this._completedAt).getTime()>Date.now()){this._error=a("completed_at_future_error",this.lang),this._loading=!1;return}t.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let e={};for(let i of this.readings){let s=(this._readingValues[i.id]??"").trim();if(s==="")continue;let r=parseFloat(s.replace(",","."));isNaN(r)||(e[i.id]=r)}Object.keys(e).length>0&&(t.reading_values=e)}else if(this._readingValue!==""){let e=parseFloat(this._readingValue);isNaN(e)||(t.reading_value=e)}if(this.restockDefault!==null&&this._restockQty!==""){let e=parseFloat(this._restockQty);!isNaN(e)&&e>=1&&(t.restock_quantity=e)}this.parts.length>0&&(t.used_parts=Object.values(this._usedParts).filter(e=>Number.isFinite(e.quantity)&&e.quantity>0).map(e=>e.entry_id?{part_id:e.part_id,quantity:e.quantity,entry_id:e.entry_id}:{part_id:e.part_id,quantity:e.quantity})),await this.hass.connection.sendMessagePromise(t),this._photos.markAttached(),this._open=!1,this.dispatchEvent(new CustomEvent("task-completed"))}catch(t){this._error=O(t,this.lang,a("save_error",this.lang))}finally{this._loading=!1}}_renderReadingField(t,e){let i=this._completedAt?new Date(this._completedAt).getTime():NaN,s=q(this.readingHistory,t.id,isNaN(i)?void 0:i),r=t.unit||this.readingUnit,f=(this._readingValues[t.id]??"").trim(),h=f===""?NaN:parseFloat(f.replace(",",".")),_=s!==void 0&&!isNaN(h)&&h<s.value,g=s!==void 0?T(s.value,e,{maximumFractionDigits:3}):"";return c`
<label class="field reading-field">
<span class="field-label">${t.name}${r?` (${r})`:""}</span>
<input type="text" inputmode="decimal" class="field-input"
placeholder=${s!==void 0?a("reading_last",e).replace("{value}",g):""}
.value=${this._readingValues[t.id]??""}
@input=${E=>{this._readingValues={...this._readingValues,[t.id]:E.target.value}}} />
${_?c`<span class="reading-warn">${a("reading_below_last",e).replace("{value}",g)}</span>`:p}
</label>`}get _missingRequired(){let t={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(e=>!t[e])}_req(t){return this.requiredFields.includes(t)?c`<span class="req-mark" aria-hidden="true">*</span>`:p}_partsCostSuggestion(){if(this.restockDefault!==null){let i=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(i)||i<=0?null:Math.round(this.restockUnitCost*i*100)/100}if(!this.parts.length)return null;let t=0,e=!1;for(let i of Object.values(this._usedParts)){let s=this.parts.find(r=>x({part_id:r.id,entry_id:r.entry_id})===x(i));s?.cost!=null&&(t+=s.cost*(i.quantity||1),e=!0)}return e?Math.round(t*100)/100:null}_renderCostSuggestion(t){if(this._cost.trim()!=="")return p;let e=this._partsCostSuggestion();if(e==null||e<=0)return p;let i=A(e,this.currencySymbol,t);return c`<button
type="button"
class="cost-suggestion"
@click=${()=>this._cost=String(Math.round(e*100)/100)}
>${a("cost_from_parts",t).replace("{amount}",i)}</button>`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){let t=new Date,e=i=>String(i).padStart(2,"0");this._completedAt=`${t.getFullYear()}-${e(t.getMonth()+1)}-${e(t.getDate())}T${e(t.getHours())}:${e(t.getMinutes())}:00`}render(){if(!this._open)return c``;let t=this.lang||this.hass?.language||"en",e=this._error||this._photos.errorText(t);return c`
<ha-dialog open @closed=${this._close}>
<div class="dialog-title">${a("complete_title",t)}${this.taskName}</div>
${this.phaseLabel?c`<div class="phase-line">${a("phase_current",t)}: ${this.phaseLabel}</div>`:p}
${this.requireTagScan&&!this.viaTagScan?c`<div class="scan-required-note">${a("require_tag_scan_hint",t)}</div>`:p}
<div class="content">
${e?c`<div class="error">${e}</div>`:p}
${this.checklist.length>0?c`
<div class="checklist-section">
<label class="checklist-label">${a("checklist",t)}</label>
${this.checklist.map((i,s)=>c`
<label class="checklist-item" @click=${()=>this._toggleCheck(s)}>
<input type="checkbox" .checked=${!!this._checklistState[String(s)]} />
<span>${i}</span>
</label>
`)}
</div>
`:p}
${this.readings.length>0?c`<div class="readings-block">
<span class="field-label">${a("readings_section",t)}</span>
${this.readings.map(i=>this._renderReadingField(i,t))}
</div>`:this.taskType==="reading"?c`
<label class="field">
<span class="field-label">${a("reading_value_label",t)}${this.readingUnit?` (${this.readingUnit})`:""}</span>
<input type="number" step="any" class="field-input"
.value=${this._readingValue}
@input=${i=>this._readingValue=i.target.value} />
</label>`:p}
${this.parts.length?c`<div class="used-parts">
<span class="field-label">${a("complete_parts_used",t)}</span>
${this.parts.map(i=>{let s=x({part_id:i.id,entry_id:i.entry_id}),r=this._usedParts[s],f=r!==void 0,h=i.entry_id?{part_id:i.id,quantity:1,entry_id:i.entry_id}:{part_id:i.id,quantity:1};return c`<div class="used-part-row">
<label class="used-part-check">
<input type="checkbox" .checked=${f}
@change=${_=>{let g={...this._usedParts};_.target.checked?g[s]=g[s]||h:delete g[s],this._usedParts=g}} />
<span
>${i.name}${i.owner_name?c`<span class="used-part-owner"> (${i.owner_name})</span>`:p}${i.stock!==null&&i.stock!==void 0?` (${i.stock}${i.unit?" "+i.unit:""})`:""}</span
>
</label>
${f?c`<input class="used-part-qty" type="number" min="0.01" max="999" step="0.01"
.value=${String(r.quantity)}
@input=${_=>{let g=parseFloat(_.target.value);this._usedParts={...this._usedParts,[s]:{...h,quantity:Number.isFinite(g)&&g>=.01?g:1}}}} />`:p}
</div>`})}
</div>`:this.consumesInfo.length?c`<div class="consumes-hint">
${this.consumesInfo.map(i=>c`<div>${i}</div>`)}
</div>`:p}
${this.restockDefault!==null?c`
<label class="field">
<span class="field-label">${a("restock_quantity_label",t)}</span>
<input type="number" step="0.01" min="0.01" class="field-input"
.value=${this._restockQty}
@input=${i=>this._restockQty=i.target.value} />
</label>`:p}
<!-- 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">${a("notes_optional",t)}${this._req("notes")}</span>
<input type="text" class="field-input"
.value=${this._notes}
@input=${i=>this._notes=i.target.value} />
</label>
<label class="field">
<span class="field-label">${a("cost_optional",t)}${this._req("cost")}</span>
<input type="number" step="0.01" min="0" class="field-input"
.value=${this._cost}
@input=${i=>this._cost=i.target.value} />
${this._renderCostSuggestion(t)}
</label>
<label class="field">
<span class="field-label">${a("duration_minutes",t)}${this._req("duration")}</span>
<input type="number" step="0.01" min="0" class="field-input"
.value=${this._duration}
@input=${i=>this._duration=i.target.value} />
</label>
<div class="field">
<span class="field-label">${a("completed_at_optional",t)}</span>
${this._completedAt?c`<ms-date-field
kind="datetime"
clearable
.hass=${this.hass}
.lang=${t}
.value=${this._completedAt}
@value-changed=${i=>this._completedAt=i.detail.value}
></ms-date-field>`:c`<button type="button" class="backdate-pick" @click=${this._pickCompletedAt}>
<ha-icon icon="mdi:calendar-clock"></ha-icon>${a("completed_at_pick",t)}
</button>`}
</div>
<div class="field">
<span class="field-label">${a("completion_photos_optional",t)}${this._req("photo")}</span>
${this._photos.photos.length>0?c`<div class="photo-strip">
${this._photos.photos.map(i=>c`
<div class="photo-preview">
<img src=${i.preview} alt="" />
<button type="button" class="photo-remove" @click=${()=>this._photos.remove(i.id)}
title="${a("remove",t)}">✕</button>
</div>`)}
</div>`:p}
${this._photos.full?c`<div class="photo-limit">${a("photos_limit",t).replace("{max}",String(this._photos.max))}</div>`:c`<ms-photo-picker .lang=${t} .busy=${this._photos.uploading} .remaining=${this._photos.remaining}
@files-picked=${i=>this._photos.addFiles(i.detail.files)}
></ms-photo-picker>`}
</div>
${this.adaptiveEnabled?c`
<div class="feedback-section">
<label class="feedback-label">${a("was_maintenance_needed",t)}</label>
<div class="feedback-buttons">
<button
class="feedback-btn ${this._feedback==="needed"?"selected":""}"
@click=${()=>this._setFeedback("needed")}
>${a("feedback_needed",t)}</button>
<button
class="feedback-btn ${this._feedback==="not_needed"?"selected":""}"
@click=${()=>this._setFeedback("not_needed")}
>${a("feedback_not_needed",t)}</button>
<button
class="feedback-btn ${this._feedback==="not_sure"?"selected":""}"
@click=${()=>this._setFeedback("not_sure")}
>${a("feedback_not_sure",t)}</button>
</div>
</div>
`:p}
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._close}>
${a("cancel",t)}
</ha-button>
<ha-button
@click=${this._complete}
.disabled=${this._loading||this._missingRequired.length>0}
title=${this._missingRequired.length?this._missingRequired.map(i=>a("err_required",t).replace("{field}",a(L[i]??i,t))).join(" \xB7 "):""}
>
${this._loading?a("completing",t):a("complete",t)}
</ha-button>
</div>
</ha-dialog>
`}};d.styles=[P,z,y`
.req-mark {
color: var(--error-color, #f44336);
margin-left: 2px;
font-weight: 600;
}
/* #104: one-click cost suggestion from parts — quiet link-style chip. */
.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);
}
`],o([l({attribute:!1})],d.prototype,"hass",2),o([l()],d.prototype,"entryId",2),o([l()],d.prototype,"taskId",2),o([l()],d.prototype,"taskName",2),o([l()],d.prototype,"lang",2),o([l({type:Array})],d.prototype,"checklist",2),o([l({type:Boolean})],d.prototype,"adaptiveEnabled",2),o([l()],d.prototype,"taskType",2),o([l()],d.prototype,"readingUnit",2),o([l({attribute:!1})],d.prototype,"readings",2),o([l({attribute:!1})],d.prototype,"readingHistory",2),o([l({attribute:!1})],d.prototype,"restockDefault",2),o([l({attribute:!1})],d.prototype,"restockUnitCost",2),o([l()],d.prototype,"currencySymbol",2),o([l({attribute:!1})],d.prototype,"parts",2),o([l({attribute:!1})],d.prototype,"consumesParts",2),o([l({type:Array})],d.prototype,"consumesInfo",2),o([l({type:Array})],d.prototype,"requiredFields",2),o([l()],d.prototype,"phaseLabel",2),o([l({type:Boolean})],d.prototype,"requireTagScan",2),o([l({type:Boolean})],d.prototype,"viaTagScan",2),o([u()],d.prototype,"_open",2),o([u()],d.prototype,"_notes",2),o([u()],d.prototype,"_cost",2),o([u()],d.prototype,"_duration",2),o([u()],d.prototype,"_loading",2),o([u()],d.prototype,"_error",2),o([u()],d.prototype,"_checklistState",2),o([u()],d.prototype,"_feedback",2),o([u()],d.prototype,"_readingValue",2),o([u()],d.prototype,"_readingValues",2),o([u()],d.prototype,"_restockQty",2),o([u()],d.prototype,"_completedAt",2),o([u()],d.prototype,"_usedParts",2),o([l({attribute:!1})],d.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",d);export{I as a,R as b,N as c,$ as d,V as e,j as f,z as g,w as h,d as i};
@@ -1,2 +0,0 @@
/*! maintenance_supporter frontend 2.96.0 */
import{b as j}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4OFQFCKD.js";import{e as x,f as A,l as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-BYGTDXRD.js";var q=500,E=new Set(["completed","skipped","reset","missed"]);function N(r,e){let n=r.reading_values||[];return n.length?n.filter(o=>typeof o.value=="number").map(o=>({id:o.id,name:o.name||"",value:o.value,unit:o.unit||""})):typeof r.reading_value=="number"?[{id:"",name:"",value:r.reading_value,unit:e||""}]:[]}function C(r){let e=[];for(let n of r){let o=[...n.history??[]].map(t=>({h:t,ts:new Date(t.timestamp).getTime()})).filter(t=>Number.isFinite(t.ts)).sort((t,a)=>t.ts-a.ts),s=new Map;for(let{h:t,ts:a}of o){let y=N(t,n.reading_unit).map(i=>{let d=s.get(i.id);return s.set(i.id,i.value),{name:i.name,value:i.value,unit:i.unit,delta:d==null?null:i.value-d}});if(!E.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:n.id,taskName:n.name,type:t.type,cost:x(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&&n.phases?.[t.phase_id]?.name||null,refNo:typeof t.ref_no=="number"?t.ref_no:null,taskRefNo:typeof n.ref_no=="number"?n.ref_no:null,readings:y,parts:(t.used_parts||[]).filter(i=>i&&(i.name||i.part_id)).map(i=>({name:i.name||i.part_id,quantity:typeof i.quantity=="number"?i.quantity:1})),photoIds:v(t),checklist:c&&c.length?{done:c.filter(Boolean).length,total:c.length}:null})}}return e.sort((n,o)=>o.ts-n.ts||n.taskName.localeCompare(o.taskName)),e}function H(r,e){let n=e.from?new Date(`${e.from}T00:00:00`).getTime():null,o=e.to?new Date(`${e.to}T00:00:00`).getTime()+864e5:null;return r.filter(s=>!(e.taskId&&s.taskId!==e.taskId||n!=null&&s.ts<n||o!=null&&s.ts>=o))}function S(r){let e=0,n=0;for(let o of r)o.type==="completed"&&(e++,o.cost!=null&&(n+=o.cost));return{completed:e,totalCost:n}}var p="__none__",I=36;function T(r){return r.area_id||p}function w(r,e,n){return r===p?n:e?.[r]?.name||r}function D(r,e){return r===p?"mdi:map-marker-off-outline":e?.[r]?.icon||"mdi:map-marker-outline"}function U(r,e,n){return r.filter(o=>(n||!o.object.archived)&&T(o.object)===e)}function B(r,e){let n=[];for(let o of r){let s=C(o.tasks.map(t=>({id:t.id,name:t.name,history:e(o.entry_id,t),phases:t.phases,ref_no:t.ref_no,reading_unit:t.reading_unit})));for(let t of s)n.push({...t,entryId:o.entry_id,objectName:o.object.name})}return n.sort((o,s)=>s.ts-o.ts||o.objectName.localeCompare(s.objectName)||o.taskName.localeCompare(s.taskName)),n}function z(r,e){let n=(e.taskQuery??"").trim();return H(r,{from:e.from,to:e.to}).filter(o=>(!e.entryId||o.entryId===e.entryId)&&(!n||j(o.taskName,n)))}function X(r){let{completed:e,totalCost:n}=S(r),o=0;for(let s of r)s.type==="completed"&&s.duration!=null&&(o+=s.duration);return{completions:e,totalCost:n,avgCost:e?n/e:null,totalDuration:o}}function G(r,e){let n=new Map;for(let t of e)n.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=n.get(t.entryId);a&&(a.completions++,t.cost!=null&&(a.cost+=t.cost))}let o=[...n.values()].reduce((t,a)=>t+a.cost,0),s=[...n.values()].map(t=>({...t,share:o>0?t.cost/o:0}));return s.sort((t,a)=>a.cost-t.cost||a.completions-t.completions||t.objectName.localeCompare(a.objectName)),s}function R(r){let[e,n]=r.split("-").map(Number);return[e,n-1]}function L(r,e){return`${r}-${String(e+1).padStart(2,"0")}`}function J(r,e,n=new Date){let o=r.filter(u=>u.type==="completed"),s=o.map(u=>A(new Date(u.ts))),t=A(n),a=s.reduce((u,m)=>m<u?m:u,t),y=s.reduce((u,m)=>m>u?m:u,t),[c,i]=R(e.from||a),[d,h]=R(e.to||y),l=d*12+h-(c*12+i)+1;if(l<=0)return{unit:"month",buckets:[]};let g=l>I?"year":"month",k=[],_=new Map;if(g==="month")for(let u=0;u<l;u++){let m=c+Math.floor((i+u)/12),b=(i+u)%12,f={key:L(m,b),year:m,month:b,cost:0,completions:0};k.push(f),_.set(f.key,f)}else for(let u=c;u<=d;u++){let m={key:String(u),year:u,month:null,cost:0,completions:0};k.push(m),_.set(m.key,m)}return o.forEach((u,m)=>{let b=s[m],f=_.get(g==="month"?b.slice(0,7):b.slice(0,4));f&&(f.completions++,u.cost!=null&&(f.cost+=u.cost))}),{unit:g,buckets:k}}function W(r=new Date){return{from:A(new Date(r.getFullYear(),r.getMonth()-11,1)),to:A(r)}}function Z(r){return{from:`${r}-01-01`,to:`${r}-12-31`}}function tt(r,e){let n=new Set([e]);for(let o of r)o.type==="completed"&&n.add(new Date(o.ts).getFullYear());return[...n].sort((o,s)=>s-o)}function et(r,e){let n=new Map;for(let s of r){if(!e.showArchived&&s.object.archived)continue;let t=T(s.object),a=n.get(t);a?a.push(s):n.set(t,[s])}let o=[];for(let[s,t]of n){let a=t.flatMap(l=>l.tasks.filter(g=>e.showArchived||!g.archived)),y=a.filterLine truncated
Loaded 100 of 331 files, more files were not shown because too many files have changed in this diff. Show more