187 files

This commit is contained in:
Home Assistant Version Control committed 2026-09-03 17:54:35 +00:00
1 parent 16c9b4d7f4
commit d6413e19b5
187 files changed
+15542 -2765

No files matched your search

@@ -122,7 +122,7 @@
"err_invalid_value": "{field}: neplatná hodnota",
"feat_schedule_time": "Plánování podle denní doby",
"feat_schedule_time_desc": "Úkoly se stanou po termínu v určenou denní dobu místo o půlnoci.",
"schedule_time_optional": "Termín v čase (volitelné, HH:MM)",
"schedule_time_optional": "Termín v čase (volitelné)",
"schedule_time_help": "Prázdné = půlnoc (výchozí). Časové pásmo HA.",
"at_time": "v",
"notes_optional": "Poznámky (volitelné)",
@@ -130,6 +130,7 @@
"cost_optional": "Náklady (volitelné)",
"duration_minutes": "Doba trvání v minutách (volitelné)",
"completed_at_optional": "Dokončeno dne (volitelné, prázdné = nyní)",
"completed_at_pick": "Nastavit datum a čas",
"completed_at_future_error": "Datum dokončení nesmí být v budoucnosti.",
"days": "dní",
"day": "den",
@@ -287,6 +288,7 @@
"seasonal_override_invalid": "Neplatná hodnota",
"seasonal_override_range": "Faktor musí být mezi 0.1 a 5.0",
"clear_all": "Vymazat vše",
"clear": "Vymazat",
"seasonal_chart_title": "Sezónní faktory",
"seasonal_learned": "Naučené",
"seasonal_manual": "Manuální",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Senzor nyní ukazuje {value}.",
"trigger_hint_above": "Úkol se spustí, jakmile hodnota překročí {target}.",
"trigger_hint_below": "Spustí se, jakmile hodnota klesne pod {target}.",
"trigger_hint_overlap": "Tyto meze se překrývají: každé měření spustí úkol a ten se nikdy nemůže zotavit. Jedno z polí nechte prázdné.",
"trigger_hint_counter_delta": "Počítá od aktuální hodnoty ({value}): splatné při {due} (+{target}); počítadlo se po každém dokončení restartuje.",
"trigger_hint_counter_delta_edit": "Počítá spotřebu od posledního dokončení: splatné po +{target}; počítadlo se po každém dokončení restartuje.",
"trigger_hint_counter_abs": "Úkol bude splatný, jakmile senzor dosáhne {target}.",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: ugyldig værdi",
"feat_schedule_time": "Planlægning efter tidspunkt på dagen",
"feat_schedule_time_desc": "Opgaver bliver forfaldne på et bestemt tidspunkt på dagen i stedet for midnat.",
"schedule_time_optional": "Forfalder kl. (valgfrit, TT:MM)",
"schedule_time_optional": "Forfalder kl. (valgfrit)",
"schedule_time_help": "Tom = midnat (standard). HA-tidszone.",
"at_time": "kl.",
"notes_optional": "Noter (valgfrit)",
@@ -132,6 +132,7 @@
"cost_optional": "Omkostning (valgfrit)",
"duration_minutes": "Varighed i minutter (valgfrit)",
"completed_at_optional": "Udført den (valgfrit, tomt = nu)",
"completed_at_pick": "Vælg dato og tidspunkt",
"completed_at_future_error": "Udførelsesdatoen må ikke ligge i fremtiden.",
"days": "dage",
"day": "dag",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "Ugyldig værdi",
"seasonal_override_range": "Faktor skal være mellem 0.1 og 5.0",
"clear_all": "Ryd alle",
"clear": "Ryd",
"seasonal_chart_title": "Sæsonfaktorer",
"seasonal_learned": "Lært",
"seasonal_manual": "Manuel",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Sensoren viser {value} lige nu.",
"trigger_hint_above": "Opgaven udløses, når værdien stiger over {target}.",
"trigger_hint_below": "Den udløses, når værdien falder under {target}.",
"trigger_hint_overlap": "Disse grænser overlapper: hver måling udløser opgaven, og den kan aldrig komme sig. Lad et af felterne stå tomt.",
"trigger_hint_counter_delta": "Tæller fra den aktuelle aflæsning ({value}): forfalder ved {due} (+{target}); tælleren starter forfra efter hver fuldførelse.",
"trigger_hint_counter_delta_edit": "Tæller forbruget siden sidste fuldførelse: forfalder efter +{target}; tælleren starter forfra efter hver fuldførelse.",
"trigger_hint_counter_abs": "Opgaven forfalder, når sensoren når {target}.",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: ungültiger Wert",
"feat_schedule_time": "Uhrzeit-Scheduling",
"feat_schedule_time_desc": "Tasks werden zu einer festen Uhrzeit fällig statt um Mitternacht.",
"schedule_time_optional": "Fällig um (optional, HH:MM)",
"schedule_time_optional": "Fällig um (optional)",
"schedule_time_help": "Leer = Mitternacht (Default). HA-Zeitzone.",
"at_time": "um",
"notes_optional": "Notizen (optional)",
@@ -132,6 +132,7 @@
"cost_optional": "Kosten (optional)",
"duration_minutes": "Dauer in Minuten (optional)",
"completed_at_optional": "Erledigt am (optional, leer = jetzt)",
"completed_at_pick": "Datum & Uhrzeit wählen",
"completed_at_future_error": "Das Erledigungsdatum darf nicht in der Zukunft liegen.",
"days": "Tage",
"day": "Tag",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "Ungültiger Wert",
"seasonal_override_range": "Faktor muss zwischen 0.1 und 5.0 liegen",
"clear_all": "Alle zurücksetzen",
"clear": "Leeren",
"seasonal_chart_title": "Saisonale Faktoren",
"seasonal_learned": "Gelernt",
"seasonal_manual": "Manuell",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Der Sensor zeigt aktuell {value}.",
"trigger_hint_above": "Die Aufgabe wird ausgelöst, sobald der Wert über {target} steigt.",
"trigger_hint_below": "Sie wird ausgelöst, sobald der Wert unter {target} fällt.",
"trigger_hint_overlap": "Diese Grenzen überschneiden sich: Jeder Messwert löst die Aufgabe aus, und sie kann sich nie erholen. Lass eines der Felder leer.",
"trigger_hint_counter_delta": "Zählt ab dem aktuellen Stand ({value}): fällig bei {due} (+{target}); der Zähler startet nach jedem Abschluss neu.",
"trigger_hint_counter_delta_edit": "Zählt den Verbrauch seit dem letzten Abschluss: fällig nach +{target}; der Zähler startet nach jedem Abschluss neu.",
"trigger_hint_counter_abs": "Die Aufgabe wird fällig, sobald der Sensor {target} erreicht.",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: invalid value",
"feat_schedule_time": "Time-of-day scheduling",
"feat_schedule_time_desc": "Tasks become overdue at a specific time of day instead of midnight.",
"schedule_time_optional": "Due at time (optional, HH:MM)",
"schedule_time_optional": "Due at time (optional)",
"schedule_time_help": "Empty = midnight (default). HA timezone.",
"at_time": "at",
"notes_optional": "Notes (optional)",
@@ -132,6 +132,7 @@
"cost_optional": "Cost (optional)",
"duration_minutes": "Duration in minutes (optional)",
"completed_at_optional": "Completed at (optional, empty = now)",
"completed_at_pick": "Set date & time",
"completed_at_future_error": "The completion date cannot be in the future.",
"days": "days",
"day": "day",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "Invalid value",
"seasonal_override_range": "Factor must be between 0.1 and 5.0",
"clear_all": "Clear all",
"clear": "Clear",
"seasonal_chart_title": "Seasonal Factors",
"seasonal_learned": "Learned",
"seasonal_manual": "Manual",
@@ -802,6 +804,7 @@
"trigger_hint_now": "The sensor reads {value} right now.",
"trigger_hint_above": "The task triggers once it rises above {target}.",
"trigger_hint_below": "It triggers once it falls below {target}.",
"trigger_hint_overlap": "These limits overlap: every reading triggers the task and it can never recover. Leave one of them empty.",
"trigger_hint_counter_delta": "Counts from the current reading ({value}): due at {due} (+{target}), and the count restarts after each completion.",
"trigger_hint_counter_delta_edit": "Counts usage since the last completion: due after +{target}; the count restarts after each completion.",
"trigger_hint_counter_abs": "The task becomes due once the sensor reaches {target}.",
@@ -122,7 +122,7 @@
"err_invalid_value": "{field}: valor inválido",
"feat_schedule_time": "Programación por hora",
"feat_schedule_time_desc": "Las tareas vencen a una hora específica en lugar de medianoche.",
"schedule_time_optional": "Vence a las (opcional, HH:MM)",
"schedule_time_optional": "Vence a las (opcional)",
"schedule_time_help": "Vacío = medianoche (predeterminado). Zona horaria HA.",
"at_time": "a las",
"notes_optional": "Notas (opcional)",
@@ -130,6 +130,7 @@
"cost_optional": "Coste (opcional)",
"duration_minutes": "Duración en minutos (opcional)",
"completed_at_optional": "Completado el (opcional, vacío = ahora)",
"completed_at_pick": "Elegir fecha y hora",
"completed_at_future_error": "La fecha de finalización no puede estar en el futuro.",
"days": "días",
"day": "día",
@@ -287,6 +288,7 @@
"seasonal_override_invalid": "Valor no válido",
"seasonal_override_range": "El factor debe estar entre 0.1 y 5.0",
"clear_all": "Borrar todo",
"clear": "Borrar",
"seasonal_chart_title": "Factores estacionales",
"seasonal_learned": "Aprendido",
"seasonal_manual": "Manual",
@@ -802,6 +804,7 @@
"trigger_hint_now": "El sensor marca {value} ahora mismo.",
"trigger_hint_above": "La tarea se activa cuando supere {target}.",
"trigger_hint_below": "Se activa cuando baje de {target}.",
"trigger_hint_overlap": "Estos límites se solapan: cada lectura activa la tarea y nunca puede recuperarse. Deja uno de los dos vacío.",
"trigger_hint_counter_delta": "Cuenta desde la lectura actual ({value}): vence en {due} (+{target}); el contador se reinicia tras cada finalización.",
"trigger_hint_counter_delta_edit": "Cuenta el uso desde la última finalización: vence tras +{target}; el contador se reinicia tras cada finalización.",
"trigger_hint_counter_abs": "La tarea vence cuando el sensor alcance {target}.",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: virheellinen arvo",
"feat_schedule_time": "Kellonajan ajoitus",
"feat_schedule_time_desc": "Tehtävät erääntyvät tiettyyn kellonaikaan keskiyön sijaan.",
"schedule_time_optional": "Erääntyy klo (valinnainen, HH:MM)",
"schedule_time_optional": "Erääntyy klo (valinnainen)",
"schedule_time_help": "Tyhjä = keskiyö (oletus). HA:n aikavyöhyke.",
"at_time": "klo",
"notes_optional": "Muistiinpanot (valinnainen)",
@@ -132,6 +132,7 @@
"cost_optional": "Kustannus (valinnainen)",
"duration_minutes": "Kesto minuutteina (valinnainen)",
"completed_at_optional": "Suoritettu (valinnainen, tyhjä = nyt)",
"completed_at_pick": "Aseta päivä ja aika",
"completed_at_future_error": "Suorituspäivä ei voi olla tulevaisuudessa.",
"days": "päivää",
"day": "päivä",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "Virheellinen arvo",
"seasonal_override_range": "Kertoimen on oltava välillä 0,1–5,0",
"clear_all": "Tyhjennä kaikki",
"clear": "Tyhjennä",
"seasonal_chart_title": "Kausikertoimet",
"seasonal_learned": "Opittu",
"seasonal_manual": "Manuaalinen",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Anturi näyttää nyt {value}.",
"trigger_hint_above": "Tehtävä laukeaa, kun arvo ylittää {target}.",
"trigger_hint_below": "Se laukeaa, kun arvo alittaa {target}.",
"trigger_hint_overlap": "Nämä rajat menevät päällekkäin: jokainen lukema laukaisee tehtävän eikä se voi koskaan palautua. Jätä toinen kentistä tyhjäksi.",
"trigger_hint_counter_delta": "Laskee nykyisestä lukemasta ({value}): erääntyy kohdassa {due} (+{target}); laskuri alkaa alusta jokaisen suorituksen jälkeen.",
"trigger_hint_counter_delta_edit": "Laskee käytön viime suorituksesta: erääntyy +{target} jälkeen; laskuri alkaa alusta jokaisen suorituksen jälkeen.",
"trigger_hint_counter_abs": "Tehtävä erääntyy, kun anturi saavuttaa {target}.",
@@ -122,7 +122,7 @@
"err_invalid_value": "{field} : valeur invalide",
"feat_schedule_time": "Planification à l'heure",
"feat_schedule_time_desc": "Les tâches arrivent à échéance à une heure précise plutôt qu'à minuit.",
"schedule_time_optional": "Échéance à l'heure (optionnel, HH:MM)",
"schedule_time_optional": "Échéance à l'heure (optionnel)",
"schedule_time_help": "Vide = minuit (défaut). Fuseau horaire HA.",
"at_time": "à",
"notes_optional": "Notes (optionnel)",
@@ -130,6 +130,7 @@
"cost_optional": "Coût (optionnel)",
"duration_minutes": "Durée en minutes (optionnel)",
"completed_at_optional": "Effectué le (optionnel, vide = maintenant)",
"completed_at_pick": "Choisir la date et l'heure",
"completed_at_future_error": "La date d'achèvement ne peut pas être dans le futur.",
"days": "jours",
"day": "jour",
@@ -287,6 +288,7 @@
"seasonal_override_invalid": "Valeur invalide",
"seasonal_override_range": "Le facteur doit être entre 0.1 et 5.0",
"clear_all": "Tout effacer",
"clear": "Effacer",
"seasonal_chart_title": "Facteurs saisonniers",
"seasonal_learned": "Appris",
"seasonal_manual": "Manuel",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Le capteur indique {value} en ce moment.",
"trigger_hint_above": "La tâche se déclenche dès que la valeur dépasse {target}.",
"trigger_hint_below": "Elle se déclenche dès que la valeur passe sous {target}.",
"trigger_hint_overlap": "Ces limites se chevauchent : chaque relevé déclenche la tâche et elle ne peut jamais se rétablir. Laissez l'une des deux vide.",
"trigger_hint_counter_delta": "Compte à partir de la valeur actuelle ({value}) : échéance à {due} (+{target}) ; le compteur repart après chaque exécution.",
"trigger_hint_counter_delta_edit": "Compte l'usage depuis la dernière exécution : échéance après +{target} ; le compteur repart après chaque exécution.",
"trigger_hint_counter_abs": "La tâche devient due dès que le capteur atteint {target}.",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: अमान्य मान",
"feat_schedule_time": "दिन का समय निर्धारण",
"feat_schedule_time_desc": "कार्य मध्यरात्रि के बजाय दिन के एक विशिष्ट समय पर अतिदेय हो जाते हैं।",
"schedule_time_optional": "इस समय देय (वैकल्पिक, HH:MM)",
"schedule_time_optional": "इस समय देय (वैकल्पिक)",
"schedule_time_help": "खाली = मध्यरात्रि (डिफ़ॉल्ट)। HA समय क्षेत्र।",
"at_time": "बजे",
"notes_optional": "टिप्पणियाँ (वैकल्पिक)",
@@ -132,6 +132,7 @@
"cost_optional": "लागत (वैकल्पिक)",
"duration_minutes": "मिनटों में अवधि (वैकल्पिक)",
"completed_at_optional": "पूर्ण होने का समय (वैकल्पिक, खाली = अभी)",
"completed_at_pick": "तारीख और समय चुनें",
"completed_at_future_error": "पूर्णता की तारीख भविष्य में नहीं हो सकती।",
"days": "दिन",
"day": "दिन",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "अमान्य मान",
"seasonal_override_range": "कारक 0.1 और 5.0 के बीच होना चाहिए",
"clear_all": "सभी साफ़ करें",
"clear": "साफ़ करें",
"seasonal_chart_title": "मौसमी कारक",
"seasonal_learned": "सीखा गया",
"seasonal_manual": "मैनुअल",
@@ -802,6 +804,7 @@
"trigger_hint_now": "सेंसर अभी {value} दिखा रहा है।",
"trigger_hint_above": "मान {target} से ऊपर जाते ही कार्य ट्रिगर होगा।",
"trigger_hint_below": "मान {target} से नीचे आते ही यह ट्रिगर होगा।",
"trigger_hint_overlap": "ये सीमाएँ एक-दूसरे को ओवरलैप करती हैं: हर रीडिंग कार्य को ट्रिगर करेगी और वह कभी सामान्य नहीं हो पाएगा। दोनों में से एक खाली छोड़ें।",
"trigger_hint_counter_delta": "वर्तमान रीडिंग ({value}) से गिनती: {due} पर देय (+{target}); हर पूर्णता के बाद गिनती फिर से शुरू होती है।",
"trigger_hint_counter_delta_edit": "पिछली पूर्णता से उपयोग गिनता है: +{target} के बाद देय; हर पूर्णता के बाद गिनती फिर से शुरू होती है।",
"trigger_hint_counter_abs": "सेंसर {target} तक पहुँचते ही कार्य देय होगा।",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: érvénytelen érték",
"feat_schedule_time": "Napszakhoz kötött ütemezés",
"feat_schedule_time_desc": "A feladatok nem éjfélkor, hanem egy megadott napszakban válnak lejárttá.",
"schedule_time_optional": "Esedékesség időpontja (opcionális, ÓÓ:PP)",
"schedule_time_optional": "Esedékesség időpontja (opcionális)",
"schedule_time_help": "Üres = éjfél (alapértelmezés). HA időzóna.",
"at_time": "ekkor:",
"notes_optional": "Megjegyzések (opcionális)",
@@ -132,6 +132,7 @@
"cost_optional": "Költség (opcionális)",
"duration_minutes": "Időtartam percben (opcionális)",
"completed_at_optional": "Elvégezve ekkor (opcionális, üres = most)",
"completed_at_pick": "Dátum és idő megadása",
"completed_at_future_error": "Az elvégzés dátuma nem lehet a jövőben.",
"days": "nap",
"day": "nap",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "Érvénytelen érték",
"seasonal_override_range": "A tényezőnek 0,1 és 5,0 között kell lennie",
"clear_all": "Összes törlése",
"clear": "Törlés",
"seasonal_chart_title": "Szezonális tényezők",
"seasonal_learned": "Tanult",
"seasonal_manual": "Kézi",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Az érzékelő jelenlegi értéke: {value}.",
"trigger_hint_above": "A feladat akkor aktiválódik, amikor az érték {target} fölé emelkedik.",
"trigger_hint_below": "Akkor aktiválódik, amikor az érték {target} alá csökken.",
"trigger_hint_overlap": "Ezek a határok átfedik egymást: minden mérés kiváltja a feladatot, és az soha nem állhat helyre. Hagyja üresen az egyik mezőt.",
"trigger_hint_counter_delta": "A jelenlegi értéktől ({value}) számol: esedékes {due} értéknél (+{target}), és a számlálás minden elvégzés után újraindul.",
"trigger_hint_counter_delta_edit": "A legutóbbi elvégzés óta számolja a használatot: esedékes +{target} után; a számlálás minden elvégzés után újraindul.",
"trigger_hint_counter_abs": "A feladat akkor válik esedékessé, amikor az érzékelő eléri a(z) {target} értéket.",
@@ -122,7 +122,7 @@
"err_invalid_value": "{field}: valore non valido",
"feat_schedule_time": "Pianificazione oraria",
"feat_schedule_time_desc": "Le attività scadono a un'ora specifica anziché a mezzanotte.",
"schedule_time_optional": "Scadenza all'ora (opzionale, HH:MM)",
"schedule_time_optional": "Scadenza all'ora (opzionale)",
"schedule_time_help": "Vuoto = mezzanotte (default). Fuso orario HA.",
"at_time": "alle",
"notes_optional": "Note (opzionale)",
@@ -130,6 +130,7 @@
"cost_optional": "Costo (opzionale)",
"duration_minutes": "Durata in minuti (opzionale)",
"completed_at_optional": "Completato il (opzionale, vuoto = adesso)",
"completed_at_pick": "Imposta data e ora",
"completed_at_future_error": "La data di completamento non può essere nel futuro.",
"days": "giorni",
"day": "giorno",
@@ -287,6 +288,7 @@
"seasonal_override_invalid": "Valore non valido",
"seasonal_override_range": "Il fattore deve essere tra 0.1 e 5.0",
"clear_all": "Cancella tutto",
"clear": "Cancella",
"seasonal_chart_title": "Fattori stagionali",
"seasonal_learned": "Appreso",
"seasonal_manual": "Manuale",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Il sensore indica {value} in questo momento.",
"trigger_hint_above": "L'attività scatta quando supera {target}.",
"trigger_hint_below": "Scatta quando scende sotto {target}.",
"trigger_hint_overlap": "Questi limiti si sovrappongono: ogni lettura attiva l'attività e non può mai rientrare. Lascia vuoto uno dei due campi.",
"trigger_hint_counter_delta": "Conta dalla lettura attuale ({value}): scade a {due} (+{target}); il conteggio riparte dopo ogni completamento.",
"trigger_hint_counter_delta_edit": "Conta l'uso dall'ultimo completamento: scade dopo +{target}; il conteggio riparte dopo ogni completamento.",
"trigger_hint_counter_abs": "L'attività scade quando il sensore raggiunge {target}.",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: 無効な値です",
"feat_schedule_time": "時刻指定スケジュール",
"feat_schedule_time_desc": "タスクが深夜0時ではなく指定した時刻に期限超過となります。",
"schedule_time_optional": "期限の時刻(任意、HH:MM)",
"schedule_time_optional": "期限の時刻(任意)",
"schedule_time_help": "空欄=深夜0時(既定)。HAのタイムゾーン。",
"at_time": "時刻",
"notes_optional": "メモ(任意)",
@@ -132,6 +132,7 @@
"cost_optional": "費用(任意)",
"duration_minutes": "所要時間(分、任意)",
"completed_at_optional": "完了日時(任意・空欄 = 現在)",
"completed_at_pick": "日時を設定",
"completed_at_future_error": "完了日時に未来は指定できません。",
"days": "日",
"day": "日",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "無効な値です",
"seasonal_override_range": "係数は0.1〜5.0の範囲で指定してください",
"clear_all": "すべてクリア",
"clear": "クリア",
"seasonal_chart_title": "季節係数",
"seasonal_learned": "学習値",
"seasonal_manual": "手動",
@@ -802,6 +804,7 @@
"trigger_hint_now": "センサーは現在 {value} を示しています。",
"trigger_hint_above": "値が {target} を上回るとタスクが発動します。",
"trigger_hint_below": "値が {target} を下回ると発動します。",
"trigger_hint_overlap": "これらの制限は重なっています。すべての読み取り値でタスクがトリガーされ、復帰できなくなります。どちらか一方を空欄にしてください。",
"trigger_hint_counter_delta": "現在の読み値({value})から数えます: {due}(+{target})で期限になり、完了のたびにカウントはやり直しになります。",
"trigger_hint_counter_delta_edit": "前回の完了からの使用量を数えます: +{target} で期限になり、完了のたびにカウントはやり直しになります。",
"trigger_hint_counter_abs": "センサーが {target} に達するとタスクが期限になります。",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: 유효하지 않은 값입니다",
"feat_schedule_time": "시각 지정 일정",
"feat_schedule_time_desc": "작업이 자정이 아닌 지정한 시각에 기한 초과로 전환됩니다.",
"schedule_time_optional": "기한 시각 (선택, HH:MM)",
"schedule_time_optional": "기한 시각 (선택)",
"schedule_time_help": "비워두면 자정(기본값)입니다. HA 시간대 기준.",
"at_time": "시각",
"notes_optional": "메모 (선택)",
@@ -132,6 +132,7 @@
"cost_optional": "비용 (선택)",
"duration_minutes": "소요 시간(분, 선택)",
"completed_at_optional": "완료 시각 (선택, 비우면 지금)",
"completed_at_pick": "날짜 및 시간 설정",
"completed_at_future_error": "완료 날짜는 미래일 수 없습니다.",
"days": "일",
"day": "일",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "유효하지 않은 값",
"seasonal_override_range": "계수는 0.1에서 5.0 사이여야 합니다",
"clear_all": "모두 지우기",
"clear": "지우기",
"seasonal_chart_title": "계절 계수",
"seasonal_learned": "학습됨",
"seasonal_manual": "수동",
@@ -802,6 +804,7 @@
"trigger_hint_now": "센서의 현재 값은 {value}입니다.",
"trigger_hint_above": "{target}을(를) 초과하면 작업이 트리거됩니다.",
"trigger_hint_below": "{target} 미만으로 떨어지면 트리거됩니다.",
"trigger_hint_overlap": "이 한계값들이 겹칩니다. 모든 측정값이 작업을 트리거하여 복구되지 않습니다. 둘 중 하나를 비워 두세요.",
"trigger_hint_counter_delta": "현재 값({value})부터 계수합니다: {due} 도달 시 기한 (+{target}), 완료할 때마다 계수가 다시 시작됩니다.",
"trigger_hint_counter_delta_edit": "마지막 완료 이후 사용량을 계수합니다: +{target} 후 기한이 되며, 완료할 때마다 계수가 다시 시작됩니다.",
"trigger_hint_counter_abs": "센서가 {target}에 도달하면 작업 기한이 됩니다.",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: ugyldig verdi",
"feat_schedule_time": "Planlegging med klokkeslett",
"feat_schedule_time_desc": "Oppgaver forfaller på et bestemt klokkeslett i stedet for ved midnatt.",
"schedule_time_optional": "Forfaller kl. (valgfritt, TT:MM)",
"schedule_time_optional": "Forfaller kl. (valgfritt)",
"schedule_time_help": "Tom = midnatt (standard). HA-tidssone.",
"at_time": "kl.",
"notes_optional": "Notater (valgfritt)",
@@ -132,6 +132,7 @@
"cost_optional": "Kostnad (valgfritt)",
"duration_minutes": "Varighet i minutter (valgfritt)",
"completed_at_optional": "Utført den (valgfritt, tomt = nå)",
"completed_at_pick": "Velg dato og klokkeslett",
"completed_at_future_error": "Fullføringsdatoen kan ikke ligge i fremtiden.",
"days": "dager",
"day": "dag",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "Ugyldig verdi",
"seasonal_override_range": "Faktor må være mellom 0,1 og 5,0",
"clear_all": "Fjern alle",
"clear": "Tøm",
"seasonal_chart_title": "Sesongfaktorer",
"seasonal_learned": "Lært",
"seasonal_manual": "Manuell",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Sensoren viser {value} akkurat nå.",
"trigger_hint_above": "Oppgaven utløses når verdien stiger over {target}.",
"trigger_hint_below": "Den utløses når verdien faller under {target}.",
"trigger_hint_overlap": "Disse grensene overlapper: hver måling utløser oppgaven, og den kan aldri gjenopprettes. La ett av feltene stå tomt.",
"trigger_hint_counter_delta": "Teller fra gjeldende avlesning ({value}): forfaller ved {due} (+{target}); telleren starter på nytt etter hver fullføring.",
"trigger_hint_counter_delta_edit": "Teller forbruket siden forrige fullføring: forfaller etter +{target}; telleren starter på nytt etter hver fullføring.",
"trigger_hint_counter_abs": "Oppgaven forfaller når sensoren når {target}.",
@@ -122,7 +122,7 @@
"err_invalid_value": "{field}: ongeldige waarde",
"feat_schedule_time": "Tijd-van-dag-planning",
"feat_schedule_time_desc": "Taken vervallen op een specifieke tijd in plaats van middernacht.",
"schedule_time_optional": "Vervaldagstijd (optioneel, HH:MM)",
"schedule_time_optional": "Vervaldagstijd (optioneel)",
"schedule_time_help": "Leeg = middernacht (standaard). HA-tijdzone.",
"at_time": "om",
"notes_optional": "Notities (optioneel)",
@@ -130,6 +130,7 @@
"cost_optional": "Kosten (optioneel)",
"duration_minutes": "Duur in minuten (optioneel)",
"completed_at_optional": "Voltooid op (optioneel, leeg = nu)",
"completed_at_pick": "Datum & tijd kiezen",
"completed_at_future_error": "De voltooiingsdatum mag niet in de toekomst liggen.",
"days": "dagen",
"day": "dag",
@@ -287,6 +288,7 @@
"seasonal_override_invalid": "Ongeldige waarde",
"seasonal_override_range": "Factor moet tussen 0.1 en 5.0 liggen",
"clear_all": "Alles wissen",
"clear": "Wissen",
"seasonal_chart_title": "Seizoensfactoren",
"seasonal_learned": "Geleerd",
"seasonal_manual": "Handmatig",
@@ -802,6 +804,7 @@
"trigger_hint_now": "De sensor staat nu op {value}.",
"trigger_hint_above": "De taak wordt geactiveerd zodra de waarde boven {target} komt.",
"trigger_hint_below": "Hij wordt geactiveerd zodra de waarde onder {target} zakt.",
"trigger_hint_overlap": "Deze grenzen overlappen: elke meting activeert de taak en deze kan nooit herstellen. Laat een van beide leeg.",
"trigger_hint_counter_delta": "Telt vanaf de huidige stand ({value}): vervalt bij {due} (+{target}); de teller herstart na elke afronding.",
"trigger_hint_counter_delta_edit": "Telt het gebruik sinds de laatste afronding: vervalt na +{target}; de teller herstart na elke afronding.",
"trigger_hint_counter_abs": "De taak vervalt zodra de sensor {target} bereikt.",
@@ -122,7 +122,7 @@
"err_invalid_value": "{field}: nieprawidłowa wartość",
"feat_schedule_time": "Harmonogram według pory dnia",
"feat_schedule_time_desc": "Zadania stają się zaległe o określonej porze dnia zamiast o północy.",
"schedule_time_optional": "Termin o godzinie (opcjonalne, HH:MM)",
"schedule_time_optional": "Termin o godzinie (opcjonalne)",
"schedule_time_help": "Puste = północ (domyślnie). Strefa czasowa HA.",
"at_time": "o",
"notes_optional": "Notatki (opcjonalne)",
@@ -130,6 +130,7 @@
"cost_optional": "Koszt (opcjonalne)",
"duration_minutes": "Czas trwania w minutach (opcjonalne)",
"completed_at_optional": "Wykonano dnia (opcjonalne, puste = teraz)",
"completed_at_pick": "Ustaw datę i godzinę",
"completed_at_future_error": "Data wykonania nie może być w przyszłości.",
"days": "dni",
"day": "dzień",
@@ -287,6 +288,7 @@
"seasonal_override_invalid": "Nieprawidłowa wartość",
"seasonal_override_range": "Czynnik musi być między 0.1 a 5.0",
"clear_all": "Wyczyść wszystko",
"clear": "Wyczyść",
"seasonal_chart_title": "Czynniki sezonowe",
"seasonal_learned": "Wyuczone",
"seasonal_manual": "Ręczne",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Czujnik wskazuje teraz {value}.",
"trigger_hint_above": "Zadanie uruchomi się, gdy wartość przekroczy {target}.",
"trigger_hint_below": "Uruchomi się, gdy wartość spadnie poniżej {target}.",
"trigger_hint_overlap": "Te granice nakładają się: każdy odczyt wyzwala zadanie i nigdy nie może ono wrócić do normy. Pozostaw jedno z pól puste.",
"trigger_hint_counter_delta": "Liczy od bieżącego odczytu ({value}): termin przy {due} (+{target}); licznik startuje od nowa po każdym ukończeniu.",
"trigger_hint_counter_delta_edit": "Liczy zużycie od ostatniego ukończenia: termin po +{target}; licznik startuje od nowa po każdym ukończeniu.",
"trigger_hint_counter_abs": "Zadanie staje się wymagalne, gdy czujnik osiągnie {target}.",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: valor inválido",
"feat_schedule_time": "Agendamento por horário",
"feat_schedule_time_desc": "As tarefas ficam atrasadas em um horário específico do dia, em vez de à meia-noite.",
"schedule_time_optional": "Vence às (opcional, HH:MM)",
"schedule_time_optional": "Vence às (opcional)",
"schedule_time_help": "Vazio = meia-noite (padrão). Fuso horário do HA.",
"at_time": "às",
"notes_optional": "Observações (opcional)",
@@ -132,6 +132,7 @@
"cost_optional": "Custo (opcional)",
"duration_minutes": "Duração em minutos (opcional)",
"completed_at_optional": "Concluído em (opcional, vazio = agora)",
"completed_at_pick": "Definir data e hora",
"completed_at_future_error": "A data de conclusão não pode estar no futuro.",
"days": "dias",
"day": "dia",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "Valor inválido",
"seasonal_override_range": "O fator deve estar entre 0,1 e 5,0",
"clear_all": "Limpar tudo",
"clear": "Limpar",
"seasonal_chart_title": "Fatores sazonais",
"seasonal_learned": "Aprendido",
"seasonal_manual": "Manual",
@@ -802,6 +804,7 @@
"trigger_hint_now": "O sensor lê {value} neste momento.",
"trigger_hint_above": "A tarefa é acionada quando o valor sobe acima de {target}.",
"trigger_hint_below": "É acionada quando o valor cai abaixo de {target}.",
"trigger_hint_overlap": "Esses limites se sobrepõem: toda leitura aciona a tarefa e ela nunca consegue se recuperar. Deixe um dos campos vazio.",
"trigger_hint_counter_delta": "Conta a partir da leitura atual ({value}): vence em {due} (+{target}), e a contagem recomeça após cada conclusão.",
"trigger_hint_counter_delta_edit": "Conta o uso desde a última conclusão: vence após +{target}; a contagem recomeça após cada conclusão.",
"trigger_hint_counter_abs": "A tarefa vence quando o sensor atinge {target}.",
@@ -122,7 +122,7 @@
"err_invalid_value": "{field}: valor inválido",
"feat_schedule_time": "Agendamento por hora",
"feat_schedule_time_desc": "Tarefas vencem em um horário específico em vez de meia-noite.",
"schedule_time_optional": "Vence às (opcional, HH:MM)",
"schedule_time_optional": "Vence às (opcional)",
"schedule_time_help": "Vazio = meia-noite (padrão). Fuso horário HA.",
"at_time": "às",
"notes_optional": "Notas (opcional)",
@@ -130,6 +130,7 @@
"cost_optional": "Custo (opcional)",
"duration_minutes": "Duração em minutos (opcional)",
"completed_at_optional": "Concluído em (opcional, vazio = agora)",
"completed_at_pick": "Definir data e hora",
"completed_at_future_error": "A data de conclusão não pode estar no futuro.",
"days": "dias",
"day": "dia",
@@ -287,6 +288,7 @@
"seasonal_override_invalid": "Valor inválido",
"seasonal_override_range": "O fator deve estar entre 0.1 e 5.0",
"clear_all": "Limpar tudo",
"clear": "Limpar",
"seasonal_chart_title": "Fatores sazonais",
"seasonal_learned": "Aprendido",
"seasonal_manual": "Manual",
@@ -802,6 +804,7 @@
"trigger_hint_now": "O sensor marca {value} neste momento.",
"trigger_hint_above": "A tarefa dispara quando ultrapassar {target}.",
"trigger_hint_below": "Dispara quando descer abaixo de {target}.",
"trigger_hint_overlap": "Estes limites sobrepõem-se: cada leitura aciona a tarefa e esta nunca consegue recuperar. Deixe um dos campos vazio.",
"trigger_hint_counter_delta": "Conta a partir da leitura atual ({value}): vence em {due} (+{target}); a contagem recomeça após cada conclusão.",
"trigger_hint_counter_delta_edit": "Conta o uso desde a última conclusão: vence após +{target}; a contagem recomeça após cada conclusão.",
"trigger_hint_counter_abs": "A tarefa vence quando o sensor atingir {target}.",
@@ -122,7 +122,7 @@
"err_invalid_value": "{field}: неверное значение",
"feat_schedule_time": "Планирование по времени дня",
"feat_schedule_time_desc": "Задачи становятся просроченными в определённое время дня, а не в полночь.",
"schedule_time_optional": "Срок (необязательно, HH:MM)",
"schedule_time_optional": "Срок (необязательно)",
"schedule_time_help": "Пусто = полночь (по умолчанию). Часовой пояс HA.",
"at_time": "в",
"notes_optional": "Примечания (опционально)",
@@ -130,6 +130,7 @@
"cost_optional": "Стоимость (опционально)",
"duration_minutes": "Длительность в минутах (опционально)",
"completed_at_optional": "Выполнено (необязательно, пусто = сейчас)",
"completed_at_pick": "Указать дату и время",
"completed_at_future_error": "Дата выполнения не может быть в будущем.",
"days": "дней",
"day": "день",
@@ -287,6 +288,7 @@
"seasonal_override_invalid": "Недопустимое значение",
"seasonal_override_range": "Коэффициент должен быть от 0.1 до 5.0",
"clear_all": "Очистить все",
"clear": "Очистить",
"seasonal_chart_title": "Сезонные факторы",
"seasonal_learned": "Изученные",
"seasonal_manual": "Ручные",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Сейчас датчик показывает {value}.",
"trigger_hint_above": "Задача сработает, когда значение поднимется выше {target}.",
"trigger_hint_below": "Она сработает, когда значение опустится ниже {target}.",
"trigger_hint_overlap": "Эти пределы перекрываются: каждое показание запускает задачу, и она никогда не сможет восстановиться. Оставьте одно из полей пустым.",
"trigger_hint_counter_delta": "Отсчёт от текущего показания ({value}): срок при {due} (+{target}); счётчик начинается заново после каждого выполнения.",
"trigger_hint_counter_delta_edit": "Считает расход с последнего выполнения: срок после +{target}; счётчик начинается заново после каждого выполнения.",
"trigger_hint_counter_abs": "Задача наступит, когда датчик достигнет {target}.",
@@ -122,7 +122,7 @@
"err_invalid_value": "{field}: ogiltigt värde",
"feat_schedule_time": "Schemaläggning per tid på dygnet",
"feat_schedule_time_desc": "Uppgifter blir försenade vid en specifik tid på dygnet istället för midnatt.",
"schedule_time_optional": "Förfaller kl. (valfritt, HH:MM)",
"schedule_time_optional": "Förfaller kl. (valfritt)",
"schedule_time_help": "Tomt = midnatt (standard). HA-tidszon.",
"at_time": "kl.",
"notes_optional": "Anteckningar (valfritt)",
@@ -130,6 +130,7 @@
"cost_optional": "Kostnad (valfritt)",
"duration_minutes": "Varaktighet i minuter (valfritt)",
"completed_at_optional": "Utförd den (valfritt, tomt = nu)",
"completed_at_pick": "Ange datum och tid",
"completed_at_future_error": "Slutförandedatumet får inte ligga i framtiden.",
"days": "dagar",
"day": "dag",
@@ -287,6 +288,7 @@
"seasonal_override_invalid": "Ogiltigt värde",
"seasonal_override_range": "Faktor måste vara mellan 0.1 och 5.0",
"clear_all": "Rensa alla",
"clear": "Rensa",
"seasonal_chart_title": "Säsongsfaktorer",
"seasonal_learned": "Lärt",
"seasonal_manual": "Manuell",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Sensorn visar {value} just nu.",
"trigger_hint_above": "Uppgiften utlöses när värdet stiger över {target}.",
"trigger_hint_below": "Den utlöses när värdet faller under {target}.",
"trigger_hint_overlap": "Dessa gränser överlappar: varje mätvärde utlöser uppgiften och den kan aldrig återhämta sig. Lämna ett av fälten tomt.",
"trigger_hint_counter_delta": "Räknar från den aktuella avläsningen ({value}): förfaller vid {due} (+{target}); räknaren börjar om efter varje slutförande.",
"trigger_hint_counter_delta_edit": "Räknar förbrukningen sedan senaste slutförandet: förfaller efter +{target}; räknaren börjar om efter varje slutförande.",
"trigger_hint_counter_abs": "Uppgiften förfaller när sensorn når {target}.",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: geçersiz değer",
"feat_schedule_time": "Gün içi saat zamanlaması",
"feat_schedule_time_desc": "Görevler gece yarısı yerine günün belirli bir saatinde gecikmiş olur.",
"schedule_time_optional": "Vade saati (isteğe bağlı, SS:DD)",
"schedule_time_optional": "Vade saati (isteğe bağlı)",
"schedule_time_help": "Boş = gece yarısı (varsayılan). HA saat dilimi.",
"at_time": "saat",
"notes_optional": "Notlar (isteğe bağlı)",
@@ -132,6 +132,7 @@
"cost_optional": "Maliyet (isteğe bağlı)",
"duration_minutes": "Dakika cinsinden süre (isteğe bağlı)",
"completed_at_optional": "Tamamlanma zamanı (isteğe bağlı, boş = şimdi)",
"completed_at_pick": "Tarih ve saat seç",
"completed_at_future_error": "Tamamlanma tarihi gelecekte olamaz.",
"days": "gün",
"day": "gün",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "Geçersiz değer",
"seasonal_override_range": "Faktör 0.1 ile 5.0 arasında olmalıdır",
"clear_all": "Tümünü temizle",
"clear": "Temizle",
"seasonal_chart_title": "Mevsimsel Faktörler",
"seasonal_learned": "Öğrenilmiş",
"seasonal_manual": "Manuel",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Sensör şu anda {value} değerini okuyor.",
"trigger_hint_above": "Görev, değer {target} üzerine çıktığında tetiklenir.",
"trigger_hint_below": "Değer {target} altına düştüğünde tetiklenir.",
"trigger_hint_overlap": "Bu sınırlar çakışıyor: her okuma görevi tetikler ve görev asla normale dönemez. Alanlardan birini boş bırakın.",
"trigger_hint_counter_delta": "Mevcut okumadan ({value}) itibaren sayar: {due} değerinde vadesi gelir (+{target}) ve sayım her tamamlamadan sonra yeniden başlar.",
"trigger_hint_counter_delta_edit": "Son tamamlamadan bu yana kullanımı sayar: +{target} sonrasında vadesi gelir; sayım her tamamlamadan sonra yeniden başlar.",
"trigger_hint_counter_abs": "Sensör {target} değerine ulaştığında görevin vadesi gelir.",
@@ -122,7 +122,7 @@
"err_invalid_value": "{field}: невірне значення",
"feat_schedule_time": "Планування за часом доби",
"feat_schedule_time_desc": "Задачі стають простроченими у певний час доби, а не опівночі.",
"schedule_time_optional": "Час прострочення (необов'язково, HH:MM)",
"schedule_time_optional": "Час прострочення (необов'язково)",
"schedule_time_help": "Порожньо = опівночі (за замовчуванням). Часовий пояс HA.",
"at_time": "о",
"notes_optional": "Примітки (необов'язково)",
@@ -130,6 +130,7 @@
"cost_optional": "Вартість (необов'язково)",
"duration_minutes": "Тривалість у хвилинах (необов'язково)",
"completed_at_optional": "Виконано (необов'язково, порожньо = зараз)",
"completed_at_pick": "Вказати дату й час",
"completed_at_future_error": "Дата виконання не може бути в майбутньому.",
"days": "днів",
"day": "день",
@@ -287,6 +288,7 @@
"seasonal_override_invalid": "Недійсне значення",
"seasonal_override_range": "Коефіцієнт має бути між 0.1 та 5.0",
"clear_all": "Очистити все",
"clear": "Очистити",
"seasonal_chart_title": "Сезонні коефіцієнти",
"seasonal_learned": "Навчена",
"seasonal_manual": "Ручна",
@@ -802,6 +804,7 @@
"trigger_hint_now": "Зараз датчик показує {value}.",
"trigger_hint_above": "Завдання спрацює, коли значення підніметься вище {target}.",
"trigger_hint_below": "Воно спрацює, коли значення опуститься нижче {target}.",
"trigger_hint_overlap": "Ці межі перекриваються: кожне показання запускає завдання, і воно ніколи не зможе відновитися. Залиште одне з полів порожнім.",
"trigger_hint_counter_delta": "Відлік від поточного показника ({value}): термін при {due} (+{target}); лічильник починається заново після кожного виконання.",
"trigger_hint_counter_delta_edit": "Рахує використання з останнього виконання: термін після +{target}; лічильник починається заново після кожного виконання.",
"trigger_hint_counter_abs": "Завдання настане, коли датчик досягне {target}.",
@@ -124,7 +124,7 @@
"err_invalid_value": "{field}: 无效数值",
"feat_schedule_time": "具体时间调度",
"feat_schedule_time_desc": "任务将在特定时间点变为逾期,而非默认的午夜。",
"schedule_time_optional": "到期时间 (可选, HH:MM)",
"schedule_time_optional": "到期时间 (可选)",
"schedule_time_help": "留空 = 午夜 (默认)。基于 HA 时区。",
"at_time": "于",
"notes_optional": "备注 (可选)",
@@ -132,6 +132,7 @@
"cost_optional": "成本 (可选)",
"duration_minutes": "耗时 (分钟, 可选)",
"completed_at_optional": "完成时间(可选,留空 = 现在)",
"completed_at_pick": "设置日期和时间",
"completed_at_future_error": "完成日期不能是未来时间。",
"days": "天",
"day": "天",
@@ -289,6 +290,7 @@
"seasonal_override_invalid": "无效数值",
"seasonal_override_range": "系数必须介于 0.1 到 5.0 之间",
"clear_all": "全部清除",
"clear": "清除",
"seasonal_chart_title": "季节性因素",
"seasonal_learned": "自动学习",
"seasonal_manual": "手动设置",
@@ -802,6 +804,7 @@
"trigger_hint_now": "传感器当前读数为 {value}。",
"trigger_hint_above": "当数值升到 {target} 以上时任务触发。",
"trigger_hint_below": "当数值降到 {target} 以下时任务触发。",
"trigger_hint_overlap": "这两个界限相互重叠:每个读数都会触发任务,任务将永远无法恢复。请将其中一项留空。",
"trigger_hint_counter_delta": "从当前读数({value})开始计数:到 {due}(+{target})时到期;每次完成后重新计数。",
"trigger_hint_counter_delta_edit": "从上次完成开始计算用量:+{target} 后到期;每次完成后重新计数。",
"trigger_hint_counter_abs": "当传感器达到 {target} 时任务到期。",
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.71.0 */
var S="2.71.0";var l="maintenance-supporter",T=`ll-strategy-dashboard-${l}`,D="hui-maintenance-supporter-strategy-editor",C=`/maintenance_supporter_strategy/maintenance-dashboard-strategy.js?v=${S}`,m=null;function v(){return m||(m=import(C)),m}async function I(){let r=await v();if(!r.MaintenanceDashboardStrategy)throw new Error("[maintenance-supporter] strategy bundle loaded but did not export MaintenanceDashboardStrategy");return r.MaintenanceDashboardStrategy}var p=class extends HTMLElement{static getCreateSuggestions(c){return{title:"Maintenance Supporter",icon:"mdi:wrench-clock"}}static async getConfigElement(){return await v(),document.createElement(D)}static async generate(c,f){return(await I()).generate(c,f)}};function M(){try{customElements.define(T,p)}catch{}}M();var w=window;w.customStrategies=w.customStrategies||[];w.customStrategies.some(r=>r.type===l&&r.strategyType==="dashboard")||w.customStrategies.push({type:l,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#dashboard-strategy"});(()=>{let r=window;if(r.__msStrategyHealActive)return;r.__msStrategyHealActive=!0;let c=/^\/(auth|config|developer-tools|profile|hassio|history|logbook|map|media-browser|energy|todo|calendar)\b/,f=/Timeout waiting for strategy element ll-strategy-(dashboard-)?maintenance-supporter/i,g=`custom:${l}`;function R(a){let t=[document.documentElement],n=0;for(;t.length&&n<9e3;){let o=t.pop();if(n++,!o)continue;let e=o;if(e.nodeType===1&&e.tagName&&e.tagName.toLowerCase()===a)return e;e.shadowRoot&&t.push(e.shadowRoot);let i=o.children;if(i)for(let d of Array.from(i))t.push(d)}return null}function k(a){let t=a?.views;if(!Array.isArray(t)||!t.length)return null;let n=window.location.pathname.split("/").filter(Boolean).pop()||"",o=t.find(i=>i?.path===n);if(o)return o;let e=Number(n);return Number.isInteger(e)&&t[e]?t[e]:t[0]}function b(){try{let t=R("ha-panel-lovelace")?.lovelace;if(!t)return!1;let n=o=>o?.type;for(let o of[t.config,t.rawConfig]){if(!o)continue;if(n(o.strategy)===g)return!0;let e=k(o);if(e&&n(e.strategy)===g)return!0}return!1}catch{return!1}}function A(){let a=!1,t=0,n=!1,o=!1,e=[document.documentElement],i=0;for(;e.length&&i<9e3;){let d=e.pop();if(i++,!d)continue;let u=d;if(u.nodeType===1&&u.tagName){let s=u.tagName.toLowerCase();(s==="hui-view"||s==="hui-sections-view")&&(a=!0),(s==="ha-card"||s==="hui-card")&&t++,s==="hui-empty-state-card"&&(o=!0),s==="hui-error-card"&&f.test(u.textContent||"")&&(n=!0)}u.shadowRoot&&e.push(u.shadowRoot);let E=d.children;if(E)for(let s of Array.from(E))e.push(s)}return n?!0:o?!1:a&&t<3&&b()}let N="/maintenance_supporter_strategy_shim.js",y=0,_=0;function L(){let a=Date.now();a-_<5e3||y>=3||(_=a,y+=1,import(`${N}?heal=${a}`).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 h(){if(c.test(window.location.pathname))return;let a=0,t=Date.now(),n=window.setInterval(()=>{a++;try{if(Date.now()-t<6e3)return;if(c.test(window.location.pathname)){window.clearInterval(n);return}A()?L():window.clearInterval(n),a>=30&&window.clearInterval(n)}catch{window.clearInterval(n)}},500)}try{document.readyState==="loading"?window.addEventListener("DOMContentLoaded",h):h(),window.addEventListener("location-changed",()=>{c.test(window.location.pathname)||h()})}catch{}})();
/*! maintenance_supporter frontend 2.74.0 */
var v="2.74.0";var f="maintenance-supporter",A=`ll-strategy-dashboard-${f}`,L="hui-maintenance-supporter-strategy-editor",D=["maintenance-supporter-section","maintenance-supporter-vacation","maintenance-supporter-budget","maintenance-supporter-groups"],I=`/maintenance_supporter_strategy/maintenance-dashboard-strategy.js?v=${v}`,w=null;function h(){return w||(w=import(I)),w}async function M(){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 B(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 O(e){return class extends HTMLElement{static async generate(i,l){return(await B(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(L)}static async generate(s,i){return(await M()).generate(s,i)}};function P(){try{customElements.define(A,y)}catch{}for(let e of D)try{customElements.define(`ll-strategy-section-${e}`,O(e))}catch{}}P();var g=window;g.customStrategies=g.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#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#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)g.customStrategies.some(s=>s.type===e.type&&s.strategyType===e.strategyType)||g.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 C(){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 m(){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()?C():window.clearInterval(a),r>=30&&window.clearInterval(a)}catch{window.clearInterval(a)}},500)}try{document.readyState==="loading"?window.addEventListener("DOMContentLoaded",m):m(),wLine truncated
@@ -0,0 +1,250 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a as f}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-S2VAROHZ.js";import{a as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NYOACMQR.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-Y2JXJRDF.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};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.74.0 */
import{b as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-EOLJHFO4.js";async function l(e,n,t=300){return(await e.connection.sendMessagePromise({type:"auth/sign_path",path:n,expires:t})).path}async function r(e,n,t=300){return l(e,`/api/maintenance_supporter/document/${n}`,t)}async function y(e,n,t=""){let a=window.open("about:blank","_blank");try{let o=await r(e,n);a&&(a.location.href=new URL(o+t,window.location.origin).href)}catch(o){throw a&&a.close(),o}}async function p(e,n,t){i(await r(e,n,30),t)}function d(e){let n=URL.createObjectURL(new Blob([e],{type:"text/html"}));window.open(n,"_blank"),setTimeout(()=>URL.revokeObjectURL(n),6e4)}var c=[{key:"name",labelKey:"name",required:!0},{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=c.map(e=>e.key),s=["name","manufacturer","model","serial_number","installation_date","warranty_expiry","area_id","task_count","actions"];function g(e){if(!Array.isArray(e))return[...s];let n=new Set,t=[];for(let a of e)typeof a=="string"&&u.includes(a)&&!n.has(a)&&(n.add(a),t.push(a));return t.length?(t.includes("name")||t.unshift("name"),t):[...s]}export{l as a,r as b,y as c,p as d,d as e,c as f,s as g,g as h};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.74.0 */
function c(o,t,e){let l=new Blob([o],{type:e}),d=URL.createObjectURL(l),n=document.createElement("a");n.href=d,n.download=t,n.target="_blank",n.rel="noopener",n.style.display="none",document.body.appendChild(n),n.dispatchEvent(new MouseEvent("click")),document.body.removeChild(n),setTimeout(()=>URL.revokeObjectURL(d),6e4)}function r(o,t){let e=document.createElement("a");e.href=o,e.download=t,e.target="_blank",e.rel="noopener",e.style.display="none",document.body.appendChild(e),e.dispatchEvent(new MouseEvent("click")),document.body.removeChild(e)}export{c as a,r as b};
@@ -0,0 +1,341 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a as _,e as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YP2KCO26.js";import{a as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NYOACMQR.js";import{K as m,a as s,b,c as o,f as d,h as v,l as n,m as l,q as r,x as g}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-Y2JXJRDF.js";var i=class extends v{constructor(){super(...arguments);this.entryId="";this.taskId="";this.taskName="";this.lang="en";this.checklist=[];this.adaptiveEnabled=!1;this.taskType="";this.readingUnit="";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._photoDocId="";this._photoPreview="";this._photoUploading=!1;this._readingValue="";this._restockQty="";this._completedAt="";this._usedParts={};this.checklistPrefill={}}open(e={}){this._open||(this._open=!0,this.viaTagScan=!!e.viaTagScan,this._notes="",this._cost="",this._duration="",this._error="",this._checklistState=Object.fromEntries(this.checklist.map((t,a)=>[String(a),!!this.checklistPrefill[t]]).filter(([,t])=>t)),this._feedback="needed",this._photoDocId="",this._photoPreview="",this._photoUploading=!1,this._readingValue="",this._restockQty=this.restockDefault!==null?String(this.restockDefault):"",this._completedAt="",this._usedParts=Object.fromEntries(this.consumesParts.map(t=>[_(t),{...t}])))}_toggleCheck(e){let t=String(e);this._checklistState={...this._checklistState,[t]:!this._checklistState[t]}}_setFeedback(e){this._feedback=e}async _onPhotoInput(e){let t=e.target,a=t.files?.[0];if(t.value="",!!a){this._photoUploading=!0,this._error="";try{let c=new FormData;c.append("entry_id",this.entryId),c.append("tags","photo"),c.append("file",a,a.name);let p=await fetch("/api/maintenance_supporter/document/upload",{method:"POST",headers:{Authorization:`Bearer ${this.hass.auth?.data?.access_token??""}`},body:c});if(!p.ok){this._error=p.status===413?r("doc_too_large",this.lang):r("doc_upload_failed",this.lang);return}let u=await p.json();u.id&&(this._photoDocId=u.id,this._photoPreview=URL.createObjectURL(a))}catch{this._error=r("doc_upload_failed",this.lang)}finally{this._photoUploading=!1}}}_removePhoto(){this._photoPreview&&URL.revokeObjectURL(this._photoPreview),this._photoDocId="",this._photoPreview=""}async _complete(){this._loading=!0,this._error="";try{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 t=parseFloat(this._cost);!isNaN(t)&&t>=0&&(e.cost=t)}if(this._duration){let t=parseInt(this._duration,10);!isNaN(t)&&t>=0&&(e.duration=t)}if(this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photoDocId&&(e.photo_doc_id=this._photoDocId),this.viaTagScan&&(e.via_tag_scan=!0),this._completedAt){if(new Date(this._completedAt).getTime()>Date.now()){this._error=r("completed_at_future_error",this.lang),this._loading=!1;return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this._readingValue!==""){let t=parseFloat(this._readingValue);isNaN(t)||(e.reading_value=t)}if(this.restockDefault!==null&&this._restockQty!==""){let t=parseFloat(this._restockQty);!isNaN(t)&&t>=1&&(e.restock_quantity=t)}this.parts.length>0&&(e.used_parts=Object.values(this._usedParts).filter(t=>Number.isFinite(t.quantity)&&t.quantity>0).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})),await this.hass.connection.sendMessagePromise(e),this._open=!1,this.dispatchEvent(new CustomEvent("task-completed"))}catch(e){this._error=k(e,this.lang,r("save_error",this.lang))}finally{this._loading=!1}}get _missingRequired(){let e={notes:this._notes.trim()!=="",cost:this._cost.trim()!=="",duration:this._duration.trim()!=="",photo:this._photoDocId!=="",user:!!this.hass?.user};return this.requiredFields.filter(t=>!e[t])}_req(e){return this.requiredFields.includes(e)?o`<span class="req-mark" aria-hidden="true">*</span>`:d}_partsCostSuggestion(){if(this.restockDefault!==null){let a=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(a)||a<=0?null:Math.round(this.restockUnitCost*a*100)/100}if(!this.parts.length)return null;let e=0,t=!1;for(let a of Object.values(this._usedParts)){let c=this.parts.find(p=>_({part_id:p.id,entry_id:p.entry_id})===_(a));c?.cost!=null&&(e+=c.cost*(a.quantity||1),t=!0)}return t?Math.round(e*100)/100:null}_renderCostSuggestion(e){if(this._cost.trim()!=="")return d;let t=this._partsCostSuggestion();if(t==null||t<=0)return d;let a=g(t,this.currencySymbol,e);return o`<button
type="button"
class="cost-suggestion"
@click=${()=>this._cost=String(Math.round(t*100)/100)}
>${r("cost_from_parts",e).replace("{amount}",a)}</button>`}_close(){this._open=!1}_pickCompletedAt(){let e=new Date,t=a=>String(a).padStart(2,"0");this._completedAt=`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}:00`}render(){if(!this._open)return o``;let e=this.lang||this.hass?.language||"en";return o`
<ha-dialog open @closed=${this._close}>
<div class="dialog-title">${r("complete_title",e)}${this.taskName}</div>
${this.phaseLabel?o`<div class="phase-line">${r("phase_current",e)}: ${this.phaseLabel}</div>`:d}
${this.requireTagScan&&!this.viaTagScan?o`<div class="scan-required-note">${r("require_tag_scan_hint",e)}</div>`:d}
<div class="content">
${this._error?o`<div class="error">${this._error}</div>`:d}
${this.checklist.length>0?o`
<div class="checklist-section">
<label class="checklist-label">${r("checklist",e)}</label>
${this.checklist.map((t,a)=>o`
<label class="checklist-item" @click=${()=>this._toggleCheck(a)}>
<input type="checkbox" .checked=${!!this._checklistState[String(a)]} />
<span>${t}</span>
</label>
`)}
</div>
`:d}
${this.taskType==="reading"?o`
<label class="field">
<span class="field-label">${r("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>`:d}
${this.parts.length?o`<div class="used-parts">
<span class="field-label">${r("complete_parts_used",e)}</span>
${this.parts.map(t=>{let a=_({part_id:t.id,entry_id:t.entry_id}),c=this._usedParts[a],p=c!==void 0,u=t.entry_id?{part_id:t.id,quantity:1,entry_id:t.entry_id}:{part_id:t.id,quantity:1};return o`<div class="used-part-row">
<label class="used-part-check">
<input type="checkbox" .checked=${p}
@change=${f=>{let h={...this._usedParts};f.target.checked?h[a]=h[a]||u:delete h[a],this._usedParts=h}} />
<span
>${t.name}${t.owner_name?o`<span class="used-part-owner"> (${t.owner_name})</span>`:d}${t.stock!==null&&t.stock!==void 0?` (${t.stock}${t.unit?" "+t.unit:""})`:""}</span
>
</label>
${p?o`<input class="used-part-qty" type="number" min="0.01" max="999" step="0.01"
.value=${String(c.quantity)}
@input=${f=>{let h=parseFloat(f.target.value);this._usedParts={...this._usedParts,[a]:{...u,quantity:Number.isFinite(h)&&h>=.01?h:1}}}} />`:d}
</div>`})}
</div>`:this.consumesInfo.length?o`<div class="consumes-hint">
${this.consumesInfo.map(t=>o`<div>${t}</div>`)}
</div>`:d}
${this.restockDefault!==null?o`
<label class="field">
<span class="field-label">${r("restock_quantity_label",e)}</span>
<input type="number" step="0.01" min="0.01" class="field-input"
.value=${this._restockQty}
@input=${t=>this._restockQty=t.target.value} />
</label>`:d}
<!-- 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">${r("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">${r("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">${r("duration_minutes",e)}${this._req("duration")}</span>
<input type="number" step="0.01" min="0" class="field-input"
.value=${this._duration}
@input=${t=>this._duration=t.target.value} />
</label>
<div class="field">
<span class="field-label">${r("completed_at_optional",e)}</span>
${this._completedAt?o`<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>`:o`<button type="button" class="backdate-pick" @click=${this._pickCompletedAt}>
<ha-icon icon="mdi:calendar-clock"></ha-icon>${r("completed_at_pick",e)}
</button>`}
</div>
<div class="field">
<span class="field-label">${r("completion_photo_optional",e)}${this._req("photo")}</span>
${this._photoPreview?o`
<div class="photo-preview">
<img src=${this._photoPreview} alt="" />
<button type="button" class="photo-remove" @click=${this._removePhoto}
title="${r("remove",e)}">✕</button>
</div>`:o`
<label class="photo-pick">
<ha-icon icon="mdi:camera"></ha-icon>
<span>${this._photoUploading?r("uploading",e):r("add_photo",e)}</span>
<input type="file" accept="image/*" capture="environment"
?disabled=${this._photoUploading}
@change=${this._onPhotoInput} />
</label>`}
</div>
${this.adaptiveEnabled?o`
<div class="feedback-section">
<label class="feedback-label">${r("was_maintenance_needed",e)}</label>
<div class="feedback-buttons">
<button
class="feedback-btn ${this._feedback==="needed"?"selected":""}"
@click=${()=>this._setFeedback("needed")}
>${r("feedback_needed",e)}</button>
<button
class="feedback-btn ${this._feedback==="not_needed"?"selected":""}"
@click=${()=>this._setFeedback("not_needed")}
>${r("feedback_not_needed",e)}</button>
<button
class="feedback-btn ${this._feedback==="not_sure"?"selected":""}"
@click=${()=>this._setFeedback("not_sure")}
>${r("feedback_not_sure",e)}</button>
</div>
</div>
`:d}
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._close}>
${r("cancel",e)}
</ha-button>
<ha-button
@click=${this._complete}
.disabled=${this._loading||this._missingRequired.length>0}
title=${this._missingRequired.length?this._missingRequired.map(t=>r("err_required",e).replace("{field}",r(y[t]??t,e))).join(" \xB7 "):""}
>
${this._loading?r("completing",e):r("complete",e)}
</ha-button>
</div>
</ha-dialog>
`}};i.styles=[m,b`
.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 */
.photo-pick {
display: inline-flex;
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); }
/* #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); }
.photo-pick input[type="file"] { display: none; }
.photo-preview {
position: relative;
width: fit-content;
}
.photo-preview img {
max-width: 160px;
max-height: 160px;
border-radius: 8px;
display: block;
}
.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);
}
`],s([n({attribute:!1})],i.prototype,"hass",2),s([n()],i.prototype,"entryId",2),s([n()],i.prototype,"taskId",2),s([n()],i.prototype,"taskName",2),s([n()],i.prototype,"lang",2),s([n({type:Array})],i.prototype,"checklist",2),s([n({type:Boolean})],i.prototype,"adaptiveEnabled",2),s([n()],i.prototype,"taskType",2),s([n()],i.prototype,"readingUnit",2),s([n({attribute:!1})],i.prototype,"restockDefault",2),s([n({attribute:!1})],i.prototype,"restockUnitCost",2),s([n()],i.prototype,"currencySymbol",2),s([n({attribute:!1})],i.prototype,"parts",2),s([n({attribute:!1})],i.prototype,"consumesParts",2),s([n({type:Array})],i.prototype,"consumesInfo",2),s([n({type:Array})],i.prototype,"requiredFields",2),s([n()],i.prototype,"phaseLabel",2),s([n({type:Boolean})],i.prototype,"requireTagScan",2),s([n({type:Boolean})],i.prototype,"viaTagScan",2),s([l()],i.prototype,"_open",2),s([l()],i.prototype,"_notes",2),s([l()],i.prototype,"_cost",2),s([l()],i.prototype,"_duration",2),s([l()],i.prototype,"_loading",2),s([l()],i.prototype,"_error",2),s([l()],i.prototype,"_checklistState",2),s([l()],i.prototype,"_feedback",2),s([l()],i.prototype,"_photoDocId",2),s([l()],i.prototype,"_photoPreview",2),s([l()],i.prototype,"_photoUploading",2),s([l()],i.prototype,"_readingValue",2),s([l()],i.prototype,"_restockQty",2),s([l()],i.prototype,"_completedAt",2),s([l()],i.prototype,"_usedParts",2),s([n({attribute:!1})],i.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",i);export{i as a};
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,153 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NYOACMQR.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-Y2JXJRDF.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};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.74.0 */
import{q as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-Y2JXJRDF.js";var s={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",group_name:"name",group_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 c(e,o){let r=s[e];if(!r)return e;let t=a(r,o);return t&&t!==r?t:e}function d(e){let r=e.match(/data\['([^']+)'\]/)?.[1],t;return(t=e.match(/length of value must be at most (\d+)/))?{field:r,rule:"too_long",param:t[1]}:(t=e.match(/length of value must be at least (\d+)/))?{field:r,rule:"too_short",param:t[1]}:(t=e.match(/value must be at most (\S+)/))?{field:r,rule:"value_too_high",param:t[1]}:(t=e.match(/value must be at least (\S+)/))?{field:r,rule:"value_too_low",param:t[1]}:/required key not provided/.test(e)?{field:r,rule:"required"}:(t=e.match(/expected (\w+)/))?{field:r,rule:"wrong_type",param:t[1]}:/value must be one of/.test(e)?{field:r,rule:"invalid_choice"}:/not a valid value/.test(e)?{field:r,rule:"invalid_value"}:{field:r,rule:"unknown"}}function g(e,o,r){if(r=r??a("action_error",o),typeof e=="string")return e;if(typeof e!="object"||e===null)return r;let t=e,_=t.message||t.error?.message||"";if(!_)return r;let i=d(_),l=i.field?c(i.field,o):"",n=u=>a(u,o).replace("{field}",l).replace("{n}",i.param??"");switch(i.rule){case"too_long":return n("err_too_long");case"too_short":return n("err_too_short");case"value_too_high":return n("err_value_too_high");case"value_too_low":return n("err_value_too_low");case"required":return n("err_required");case"wrong_type":return n("err_wrong_type").replace("{type}",i.param??"");case"invalid_choice":return n("err_invalid_choice");case"invalid_value":return n("err_invalid_value");default:return _||r}}export{g as a};
@@ -0,0 +1,79 @@
/*! maintenance_supporter frontend 2.74.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-Y2JXJRDF.js";var e=class extends n{constructor(){super(...arguments);this.label="";this.value="";this.placeholder="";this.type="text";this.required=!1;this.disabled=!1;this.multiline=!1;this.rows=3}_onInput(s){let a=s.target.value;this.value=a,this.dispatchEvent(new CustomEvent("input",{bubbles:!0,composed:!0,detail:{value:a}}))}render(){return i`
<label class="field">
${this.label?i`<span class="label">${this.label}${this.required?i`<span class="req">*</span>`:o}</span>`:o}
${this.multiline?i`
<textarea
.value=${this.value??""}
rows=${this.rows}
?required=${this.required}
?disabled=${this.disabled}
placeholder=${this.placeholder}
@input=${this._onInput}
@change=${this._onInput}
></textarea>`:i`
<input
.value=${this.value??""}
.type=${this.type}
?required=${this.required}
?disabled=${this.disabled}
placeholder=${this.placeholder}
step=${this.step??o}
min=${this.min??o}
max=${this.max??o}
pattern=${this.pattern??o}
@input=${this._onInput}
@change=${this._onInput}
/>`}
${this.helper?i`<span class="helper">${this.helper}</span>`:o}
</label>
`}};e.styles=l`
:host { display: block; }
.field {
display: flex;
flex-direction: column;
gap: 4px;
}
.label {
font-size: 12px;
color: var(--secondary-text-color, #888);
font-weight: 500;
}
.req { color: var(--error-color, #f44336); margin-left: 2px; }
input {
padding: 8px 10px;
font-size: 14px;
background: var(--secondary-background-color, rgba(0,0,0,0.06));
color: var(--primary-text-color);
border: 1px solid var(--divider-color, rgba(255,255,255,0.12));
border-radius: 6px;
font-family: inherit;
width: 100%;
box-sizing: border-box;
outline: none;
}
input:focus {
border-color: var(--primary-color);
}
input:disabled { opacity: 0.5; cursor: not-allowed; }
textarea {
padding: 8px 10px;
font-size: 14px;
background: var(--secondary-background-color, rgba(0,0,0,0.06));
color: var(--primary-text-color);
border: 1px solid var(--divider-color, rgba(255,255,255,0.12));
border-radius: 6px;
font-family: inherit;
width: 100%;
box-sizing: border-box;
outline: none;
resize: vertical;
}
textarea:focus { border-color: var(--primary-color); }
textarea:disabled { opacity: 0.5; cursor: not-allowed; }
.helper {
font-size: 11px;
color: var(--secondary-text-color);
font-style: italic;
}
`,r([t()],e.prototype,"label",2),r([t()],e.prototype,"value",2),r([t()],e.prototype,"placeholder",2),r([t()],e.prototype,"type",2),r([t({type:Boolean})],e.prototype,"required",2),r([t({type:Boolean})],e.prototype,"disabled",2),r([t()],e.prototype,"step",2),r([t()],e.prototype,"min",2),r([t()],e.prototype,"max",2),r([t()],e.prototype,"pattern",2),r([t()],e.prototype,"helper",2),r([t({type:Boolean})],e.prototype,"multiline",2),r([t({type:Number})],e.prototype,"rows",2);customElements.get("ms-textfield")||customElements.define("ms-textfield",e);
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.74.0 */
var r=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 e=Date.now();if(!s&&this.usersCache&&e-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=e,this.usersCache}catch(t){return console.error("Failed to fetch users:",t),this.usersCache||[]}}async assignUser(s,e,t){await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/assign_user",entry_id:s,task_id:e,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}getUser(s){return!s||!this.usersCache?null:this.usersCache.find(e=>e.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{r as a};
@@ -0,0 +1,825 @@
/*! maintenance_supporter frontend 2.74.0 */
import{b as ct,c as dt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-YP2KCO26.js";import{a as L}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NYOACMQR.js";import{A as at,C as it,H as G,I as rt,J as ot,L as lt,a as m,b as H,c as o,d as j,f as u,h as O,l as R,m as g,n as B,q as i,s as E,t as tt,u as et,v as nt,w as x,y as st,z}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-Y2JXJRDF.js";var A=class extends O{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null;this._partOptions=null;this._partQty={};this._partQtyOriginal=""}get _lang(){return E(this.hass)}openEdit(t){this._draft={...t},this._originalSnapshot={...t},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._loadPartOptions()}async _loadPartOptions(){let t=this._draft;if(t)try{let n=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"}),a=[];for(let l of n.parts||[]){let d=l.entry_id===t.entry_id,p=l.consumers.some(c=>c.entry_id===t.entry_id&&c.task_id===t.task_id);!d&&!p||a.push({part_id:l.part_id,name:l.name,entry_id:l.entry_id,foreign:!d,object_name:l.object_name})}for(let l of t.used_parts||[]){let d=l.entry_id||t.entry_id;a.some(p=>p.part_id===l.part_id&&p.entry_id===d)||a.push({part_id:l.part_id,name:l.name||l.part_id,entry_id:d,foreign:d!==t.entry_id,object_name:null})}let r={};for(let l of t.used_parts||[])r[`${l.entry_id||t.entry_id}:${l.part_id}`]=l.quantity??1;this._partOptions=a,this._partQty=r,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}_set(t,n){this._draft&&(this._draft={...this._draft,[t]:n})}async _save(){if(!(!this._draft||!this._originalSnapshot)){this._saving=!0,this._error="";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(a=>(this._partQty[`${a.entry_id}:${a.part_id}`]||0)>0).map(a=>({part_id:a.part_id,quantity:this._partQty[`${a.entry_id}:${a.part_id}`],...a.foreign?{entry_id:a.entry_id}:{}}))),Object.keys(t).filter(a=>!["type","entry_id","task_id","original_timestamp"].includes(a)).length===0){this.close();return}await this.hass.connection.sendMessagePromise(t),this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:this._draft.entry_id,task_id:this._draft.task_id,new_timestamp:this._draft.timestamp},bubbles:!0,composed:!0})),this.close()}catch(t){this._error=L(t,this._lang)}finally{this._saving=!1}}}render(){if(!this._open||!this._draft)return u;let t=this._lang,n=this._draft;return o`
<div class="backdrop" @click=${this.close}></div>
<div class="dialog" role="dialog" aria-modal="true">
<h2>${i("history_edit_title",t)||"Edit history entry"}</h2>
<div class="entry-type">
<ha-icon icon="mdi:tag-outline"></ha-icon>
<span>${i(n.type,t)||n.type}</span>
</div>
<ms-date-field
kind="datetime"
required
.hass=${this.hass}
.lang=${t}
.label=${i("history_edit_timestamp",t)||"Timestamp"}
.value=${n.timestamp.slice(0,19)}
@value-changed=${a=>{let r=a.detail.value;r&&this._set("timestamp",r)}}
></ms-date-field>
<label>
<span>${i("notes_label",t)}</span>
<textarea
rows="3"
@input=${a=>{let r=a.target.value;this._set("notes",r||null)}}
.value=${n.notes??""}></textarea>
</label>
<div class="row">
<label>
<span>${i("cost",t)||"Cost"}</span>
<input type="number" min="0" step="0.01"
.value=${n.cost!=null?String(n.cost):""}
@input=${a=>{let r=a.target.value;this._set("cost",r?Number(r):null)}} />
</label>
<label>
<span>${i("duration",t)||"Duration (min)"}</span>
<input type="number" min="0"
.value=${n.duration!=null?String(n.duration):""}
@input=${a=>{let r=a.target.value;this._set("duration",r?Number(r):null)}} />
</label>
</div>
${this._partOptions&&this._partOptions.length>0?o`
<div class="parts-block">
<span class="parts-title">${i("complete_parts_used",t)}</span>
${this._partOptions.map(a=>{let r=`${a.entry_id}:${a.part_id}`,l=this._partQty[r]||0;return o`
<label class="part-row-edit">
<input type="checkbox" .checked=${l>0}
@change=${d=>{let p=d.target.checked;this._partQty={...this._partQty,[r]:p?1:0}}} />
<span class="part-label">${a.name}${a.foreign&&a.object_name?` (${a.object_name})`:""}</span>
${l>0?o`
<input class="part-qty" type="number" min="0.01" max="999" step="0.01"
.value=${String(l)}
@input=${d=>{let p=parseFloat(d.target.value);!isNaN(p)&&p>0&&(this._partQty={...this._partQty,[r]:p})}} />
`:u}
</label>
`})}
</div>
`:u}
${this._error?o`<div class="error">${this._error}</div>`:u}
<div class="actions">
<button class="cancel" @click=${this.close} ?disabled=${this._saving}>
${i("cancel",t)||"Cancel"}
</button>
<button class="save" @click=${this._save} ?disabled=${this._saving}>
${this._saving?i("saving",t)||"Saving\u2026":i("save",t)||"Save"}
</button>
</div>
</div>
`}};A.styles=H`
: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;
}
.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; }
`,m([R({attribute:!1})],A.prototype,"hass",2),m([g()],A.prototype,"_open",2),m([g()],A.prototype,"_saving",2),m([g()],A.prototype,"_error",2),m([g()],A.prototype,"_draft",2),m([g()],A.prototype,"_partOptions",2),m([g()],A.prototype,"_partQty",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",A);var Pt={days:1,weeks:7,months:30.4368,years:365.25};function Y(e,s){return!e||e<=0?0:e*(Pt[s||"days"]??1)}function ne(e,s,t){let n=Y(e,t);if(n<=0||s==null)return{pct:0,overflow:!1};let a=(n-s)/n*100;return{pct:Math.max(0,Math.min(100,a)),overflow:a>100}}var pt=5;function q(e){let s=e.getFullYear(),t=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0");return`${s}-${t}-${n}`}function Ct(e,s){let t=[];for(let n=0;n<s;n++){let a=new Date(e);a.setDate(a.getDate()+n),a.setHours(0,0,0,0),t.push(q(a))}return t}function U(e,s){let[t,n,a]=e.split("-").map(Number),r=new Date(t,n-1,a);return r.setDate(r.getDate()+s),q(r)}function It(e){if(!e||e.length===0)return null;let s=e.map(t=>t.cost).filter(t=>typeof t=="number");return s.length===0?null:s.reduce((t,n)=>t+n,0)/s.length}function Et(e){let{windowStart:s,windowEnd:t,task:n,entryId:a,objectName:r}=e,l=[],d=(_,v)=>({date:_,entry_id:a,task_id:n.id,task_name:n.name,object_name:r,status:v&&(n.status==="overdue"||n.status==="triggered")?"ok":n.status,days_until_due:v?null:n.days_until_due??null,projected:v,schedule_type:n.schedule_type,interval_days:n.interval_days??null,interval_unit:n.interval_unit??null,responsible_user_id:n.responsible_user_id??null,avg_cost:It(n.history),adaptive_enabled:!!n.adaptive_config?.enabled,prediction_confidence:n.threshold_prediction_confidence??null}),p=Math.max(1,Math.round(Y(n.interval_days,n.interval_unit)));if(n.status==="overdue"||n.status==="triggered"){if(l.push(d(s,!1)),n.schedule_type==="time_based"&&n.interval_days&&n.interval_days>0){let _=U(s,p),v=1;for(;_<=t&&v<pt;)l.push(d(_,!0)),v++,_=U(_,p)}return l}let c=n.next_due;if(typeof c!="string"||!c)return l;let h=c.slice(0,10);if(h>=s&&h<=t)l.push(d(h,!1));else if(h>t)return l;if(n.schedule_type==="time_based"&&n.interval_days&&n.interval_days>0){let _=U(h,p),v=l.length;for(;_<=t&&v<pt;)_>=s&&(l.push(d(_,!0)),v++),_=U(_,p)}return l}var ut={overdue:0,triggered:1,due_soon:2,ok:3};function ie(e,s,t,n=null){let a=Ct(s,t),r=a[0],l=a[a.length-1],d=[];for(let c of e){let h=c.object?.name||"",_=c.entry_id,v=c.tasks||[];for(let f of v){if(n&&f.responsible_user_id!==n||f.enabled===!1)continue;let $=Et({windowStart:r,windowEnd:l,task:f,entryId:_,objectName:h});d.push(...$)}}let p=new Map;for(let c of a)p.set(c,[]);for(let c of d){let h=p.get(c.date);h&&h.push(c)}for(let[,c]of p)c.sort((h,_)=>{let v=ut[h.status]??99,f=ut[_.status]??99;if(v!==f)return v-f;if(h.projected!==_.projected)return h.projected?1:-1;let $=h.object_name.localeCompare(_.object_name);return $!==0?$:h.task_name.localeCompare(_.task_name)});return a.map(c=>({date:c,events:p.get(c)??[]}))}var St={completed:"ok",reset:"ok",skipped:"due_soon",missed:"overdue",triggered:"triggered",trigger_replaced:"triggered",trigger_removed:"ok"};function Ht(e,s){let t=[];for(let n=s-1;n>=0;n--){let a=new Date(e);a.setDate(a.getDate()-n),a.setHours(0,0,0,0),t.push(q(a))}return t}function re(e,s,t,n=null){let a=Ht(s,t),r=a[0],l=a[a.length-1],d=new Map;for(let c of a)d.set(c,[]);for(let c of e){let h=c.object?.name||"",_=c.entry_id,v=c.tasks||[];for(let f of v){if(n&&f.responsible_user_id!==n)continue;let $=f.history||[];for(let b of $){if(typeof b?.timestamp!="string")continue;let T=b.timestamp.slice(0,10);if(T<r||T>l)continue;let S=d.get(T);if(!S)continue;let P=b.type??"completed";S.push({date:T,entry_id:_,task_id:f.id,task_name:f.name,object_name:h,status:St[P]??"ok",days_until_due:null,projected:!1,schedule_type:f.schedule_type,interval_days:f.interval_days??null,responsible_user_id:f.responsible_user_id??null,avg_cost:typeof b.cost=="number"?b.cost:null,adaptive_enabled:!!f.adaptive_config?.enabled,prediction_confidence:null,history_timestamp:b.timestamp,history_type:P,history_cost:typeof b.cost=="number"?b.cost:null,history_notes:typeof b.notes=="string"?b.notes:null,history_duration:typeof b.duration=="number"?b.duration:null})}}}let p={completed:0,reset:1,skipped:2,triggered:3,trigger_replaced:4};for(let[,c]of d)c.sort((h,_)=>{let v=p[h.history_type??""]??99,f=p[_.history_type??""]??99;if(v!==f)return v-f;let $=h.object_name.localeCompare(_.object_name);return $!==0?$:h.task_name.localeCompare(_.task_name)});return a.map(c=>({date:c,events:d.get(c)??[]}))}function jt(e,s){if(s<=0)return 0;let t=typeof e=="number"&&Number.isFinite(e)?Math.trunc(e):0;return t<0?0:t%s}function Ot(e){return!!(e?.phases&&e.phase_sequence&&e.phase_sequence.length>0)}function Z(e){if(!e||!Ot(e))return null;let s=e.phase_sequence,t=jt(e.phase_cursor,s.length),n=s[t],a=e.phases?.[n];return a?{id:n,name:a.name,index:t,count:s.length,notes:a.notes,checklist:a.checklist!==void 0?a.che Line truncated
<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>
${i("weibull_reliability_curve",s)}
${Rt(n,s)}
</div>
${zt(n,a,r,l,s)}
${qt(t,s)}
${t?.confidence_interval_low!=null?Nt(t,e,s):u}
</div>
`}function Rt(e,s){let t,n,a;return e<.8?(t="early_failures",n="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z",a="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",a="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",a="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",a="beta_highly_predictable"),o`
<span class="beta-badge ${t}">
<ha-svg-icon path="${n}"></ha-svg-icon>
${i(a,s)} (\u03B2=${x(e,s,2)})
</span>
`}function zt(e,s,t,n,a){let f=Math.max(t,n,s,1)*1.3,$=50,b=[];for(let w=0;w<=$;w++){let D=w/$*f,Lt=1-Math.exp(-Math.pow(D/s,e)),Mt=32+D/f*260,Tt=136-Lt*128;b.push([Mt,Tt])}let T=b.map(([w,D])=>`${y(w)},${y(D)}`).join(" "),S="M32,136 "+b.map(([w,D])=>`L${y(w)},${y(D)}`).join(" ")+` L${y(b[$][0])},136 Z`,P=32+t/f*260,W=1-Math.exp(-Math.pow(t/s,e)),F=136-W*128,At=x((1-W)*100,a,0),X=32+n/f*260,Dt=[0,.25,.5,.75,1];return o`
<div class="weibull-chart">
<svg viewBox="0 0 ${300} ${160}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${i("chart_weibull",a)}">
${Dt.map(w=>{let D=136-w*128;return j`
<line x1="${32}" y1="${y(D)}" x2="${292}" y2="${y(D)}"
stroke="var(--divider-color)" stroke-width="0.5" stroke-dasharray="${w===.5?"4,3":u}" />
<text x="${28}" y="${y(D+3)}" fill="var(--secondary-text-color)"
font-size="8" text-anchor="end">${x(w*100,a,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(f/2)}</text>
<text x="${292}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">${Math.round(f)}</text>
<path d="${S}" fill="var(--primary-color, #03a9f4)" opacity="0.08" />
<polyline points="${T}" fill="none"
stroke="var(--primary-color, #03a9f4)" stroke-width="2" />
${t>0?j`
<line x1="${y(P)}" y1="${8}" x2="${y(P)}" y2="${y(136)}"
stroke="var(--primary-color, #03a9f4)" stroke-width="1.5" stroke-dasharray="4,3" />
<circle cx="${y(P)}" cy="${y(F)}" r="3"
fill="var(--primary-color, #03a9f4)" />
<text x="${y(P+4)}" y="${y(F-6)}" fill="var(--primary-color, #03a9f4)"
font-size="9" font-weight="600">R=${At}%</text>
`:u}
${n>0&&n!==t?j`
<line x1="${y(X)}" y1="${8}" x2="${y(X)}" y2="${y(136)}"
stroke="var(--success-color, #4caf50)" stroke-width="1.5" stroke-dasharray="4,3" />
`:u}
<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> ${i("weibull_failure_probability",a)}</span>
${t>0?o`<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color, #03a9f4); opacity:0.5"></span> ${i("current_interval_marker",a)}</span>`:u}
${n>0&&n!==t?o`<span class="legend-item"><span class="legend-swatch" style="background:var(--success-color, #4caf50)"></span> ${i("recommended_marker",a)}</span>`:u}
</div>
`}function qt(e,s){return o`
<div class="weibull-info-row">
<div class="weibull-info-item">
<span>${i("characteristic_life",s)}</span>
<span class="weibull-info-value">${Math.round(e.weibull_eta)} ${i("days",s)}</span>
</div>
${e.weibull_r_squared!=null?o`
<div class="weibull-info-item">
<span>${i("weibull_r_squared",s)}</span>
<span class="weibull-info-value">${x(e.weibull_r_squared,s,3)}</span>
</div>
`:u}
</div>
`}function Nt(e,s,t){let n=e.confidence_interval_low,a=e.confidence_interval_high,r=s.suggested_interval??s.interval_days??0,l=s.interval_days??0,d=Math.max(0,n-5),c=a+5-d,h=(n-d)/c*100,_=(a-n)/c*100,v=(r-d)/c*100,f=l>0?(l-d)/c*100:-1;return o`
<div class="confidence-range">
<div class="confidence-range-title">
${i("confidence_interval",t)}: ${r} ${i("days",t)} (${n}\u2013${a})
</div>
<div class="confidence-bar">
<div class="confidence-fill" style="left:${y(h)}%;width:${y(_)}%"></div>
${f>=0?o`<div class="confidence-marker current" style="left:${y(f)}%"></div>`:u}
<div class="confidence-marker recommended" style="left:${y(v)}%"></div>
</div>
<div class="confidence-labels">
<span class="confidence-text low">${i("confidence_conservative",t)} (${n}${i("days",t).charAt(0)})</span>
<span class="confidence-text high">${i("confidence_aggressive",t)} (${a}${i("days",t).charAt(0)})</span>
</div>
</div>
`}function ft(e,s,t){let n=e.degradation_trend!=null&&e.degradation_trend!=="insufficient_data",a=e.days_until_threshold!=null,r=e.environmental_factor!=null&&e.environmental_factor!==1;if(!n&&!a&&!r)return u;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>
${i("sensor_prediction_urgency",s).replace("{days}",String(Math.round(e.days_until_threshold||0)))}
</div>
`:u}
<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>
${i("sensor_prediction",s)}
</div>
<div class="prediction-grid">
${n?o`
<div class="prediction-item">
<ha-svg-icon path="${l}"></ha-svg-icon>
<span class="prediction-label">${i("degradation_trend",s)}</span>
<span class="prediction-value ${e.degradation_trend}">${i("trend_"+e.degradation_trend,s)}</span>
${e.degradation_rate!=null?o`<span class="prediction-rate">${e.degradation_rate>0?"+":""}${x(e.degradation_rate,s,Math.abs(e.degradation_rate)>=10?0:1)} ${e.trigger_entity_info?.unit_of_measurement||""}/${i("day_short",s)}</span>`:u}
</div>
`:u}
${a?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">${i("days_until_threshold",s)}</span>
<span class="prediction-value prediction-days${e.days_until_threshold===0?" exceeded":e.sensor_prediction_urgency?" urgent":""}">${e.days_until_threshold===0?i("threshold_exceeded",s):"~"+Math.round(e.days_until_threshold)+" "+i("days",s)}</span>
${e.threshold_prediction_date?o`<span class="prediction-date">${z(e.threshold_prediction_date,s)}</span>`:u}
${e.threshold_prediction_confidence?o`<span class="confidence-dot ${e.threshold_prediction_confidence}"></span>`:u}
${(e.prediction_cycles??0)>0?o`<span class="prediction-cycles">${i("prediction_cycles",s)}: ${e.prediction_cycles}</span>`:u}
</div>
`:u}
${r&&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">${i("environmental_adjustment",s)}</span>
<span class="prediction-value">${x(e.environmental_factor,s,2)}x</span>
${e.environmental_entity?o`<span class="prediction-entity entity-link" @click=${d=>ot(d,e.environmental_entity)}>${e.environmental_entity}</span>`:u}
</div>
`:u}
</div>
</div>
`}function yt(e,s,t,n){let a=Math.max(e||1,s);return o`
<div class="interval-comparison">
<div class="interval-bar">
<div class="interval-label">
${i("current",n)}: ${e??"\u2014"} ${e!=null?i("days",n):""}
</div>
<div class="interval-visual current"
style="width: ${e!=null?Math.min(e/a*100,100):0}%"></div>
</div>
<div class="interval-bar">
<div class="interval-label">
${i("recommended",n)}: ${s} ${i("days",n)}
<span class="confidence-badge ${t}">${i(`confidence_${t}`,n)}</span>
</div>
<div class="interval-visual suggested"
style="width: ${Math.min(s/a*100,100)}%"></div>
</div>
</div>
`}var gt=["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 vt(e,s,t){if(!t.seasonal||!e.seasonal_factor||e.seasonal_factor===1)return u;let n=gt.map(d=>i(d,s)),a=new Date().getMonth(),r=e.seasonal_factors||e.interval_analysis?.seasonal_factors||null,l=r&&r.length===12?r:n.map((d,p)=>{let c=e.seasonal_factor||1,h=Math.sin((p-6)*Math.PI/6)*.3;return Math.max(.7,Math.min(1.3,c+h))});return o`
<div class="seasonal-card-compact">
<h4>${i("seasonal_awareness",s)}</h4>
<div class="seasonal-mini-chart">
${l.map((d,p)=>{let c=d*40,h=d<.9?"low":d>1.1?"high":"normal";return o`
<div class="seasonal-bar ${h} ${p===a?"current":""}"
style="height: ${c}px"
title="${n[p]}: ${x(d,s,2)}x">
</div>
`})}
</div>
<div class="seasonal-legend">
<span class="legend-item"><span class="dot low"></span> ${i("shorter",s)||"K\xFCrzer"}</span>
<span class="legend-item"><span class="dot normal"></span> ${i("normal",s)||"Normal"}</span>
<span class="legend-item"><span class="dot high"></span> ${i("longer",s)||"L\xE4nger"}</span>
</div>
</div>
`}function bt(e,s){return Vt(e,s)}function Vt(e,s){let t=e.seasonal_factors??e.interval_analysis?.seasonal_factors;if(!t||t.length!==12)return u;let n=e.interval_analysis?.seasonal_reason,a=new Date().getMonth(),r=300,l=100,d=8,c=l-d-4,h=Math.max(...t,1.5),_=r/12,v=_*.65,f=d+c-1/h*c;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>
${i("seasonal_chart_title",s)}
${n?o`<span class="source-tag">${n==="learned"?i("seasonal_learned",s):i("seasonal_manual",s)}</span>`:u}
</div>
<svg viewBox="0 0 ${r} ${l}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${i("chart_seasonal",s)}">
<line x1="0" y1="${y(f)}" x2="${r}" y2="${y(f)}"
stroke="var(--divider-color)" stroke-width="1" stroke-dasharray="4,3" />
${t.map(($,b)=>{let T=$/h*c,S=b*_+(_-v)/2,P=d+c-T,W=b===a,F=$<1?"var(--success-color, #4caf50)":$>1?"var(--warning-color, #ff9800)":"var(--secondary-text-color)";return j`
<rect x="${y(S)}" y="${y(P)}"
width="${y(v)}" height="${y(T)}"
fill="${F}" opacity="${W?1:.5}" rx="2" />
`})}
</svg>
<div class="seasonal-labels">
${gt.map(($,b)=>o`<span class="seasonal-label ${b===a?"active-month":""}">${i($,s)}</span>`)}
</div>
</div>
`}var k=class extends O{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._taskId=null;this._task=null;this._objectName="";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 E(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=q(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=t?.budget?.currency_symbol||"",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(a=>a.id===this._taskId);this._task=n??null}catch(t){this._error=L(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=L(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-P3P7TFC2.js").then(async({openCompleteDialog:t})=>{let n=this._task,a=[];try{a=(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0})).objects||[]}catch{}t(ht({entryId:this._entryId,taskId:this._taskId,taskName:n.name,task:n,objects:a,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-P3P7TFC2.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-P3P7TFC2.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=i("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=i("suggestion_applied",this._lang)||"Applied",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_interval",entry_id:this._entryId, Line truncated
<div class="recommendation-card">
<h4>${i("suggested_interval",n)}</h4>
${yt(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>
${i("apply_suggestion",n)}
</button>
<button class="btn"
@click=${this._reanalyzeInterval} ?disabled=${this._busy}>
<ha-icon icon="mdi:refresh"></ha-icon>
${i("reanalyze",n)}
</button>
</div>
</div>
`}_renderAdaptive(t){let n=this._lang,a=this._features.adaptive&&t.suggested_interval&&t.suggested_interval!==t.interval_days,r=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!a&&!r&&!l&&!d?o`<div class="adaptive-empty">
${i("adaptive_no_data",n)||"Not enough completion history yet for adaptive analysis."}
</div>`:o`
<div class="adaptive-stack">
${this._toast?o`<div class="toast">${this._toast}</div>`:u}
${a?this._renderRecommendation(t):u}
${r?ft(t,n,this._features):u}
${l?mt(t,n):u}
${d?o`
${vt(t,n,this._features)}
${t.seasonal_factors?.length===12||t.interval_analysis?.seasonal_factors?.length===12?bt(t,n):u}
`:u}
</div>
`}_renderDetails(t){let n=this._lang,a=t.history||[],r=a.filter(p=>p.type==="completed"),l=r.reduce((p,c)=>p+(typeof c.cost=="number"?c.cost:0),0),d=(()=>{let p=r.map(c=>typeof c.duration=="number"?c.duration:null).filter(c=>c!=null);return p.length?Math.round(p.reduce((c,h)=>c+h,0)/p.length):null})();return o`
<div class="details">
<div class="stats-grid">
<div class="stat">
<span class="stat-label">${i("times_performed",n)||"Performed"}</span>
<span class="stat-value">${r.length}</span>
</div>
<div class="stat">
<span class="stat-label">${i("total_cost",n)||"Total cost"}</span>
<span class="stat-value">${x(l,n,2)}</span>
</div>
<div class="stat">
<span class="stat-label">${i("avg_duration",n)||"Avg duration"}</span>
<span class="stat-value">${d!=null?`${d}m`:"\u2014"}</span>
</div>
</div>
<div class="history-header">
<strong>${i("history",n)||"History"}</strong>
<span class="history-count">${a.length}</span>
</div>
${a.length===0?o`<div class="history-empty">${i("history_empty",n)||"No history yet."}</div>`:o`
<div class="history-list">
${[...a].reverse().slice(0,20).map(p=>{let c=["completed","reset","skipped"].includes(p.type);return o`
<div class="history-entry">
<div class="history-line">
<span class="history-type type-${p.type}">${i(p.type,n)}</span>
<span class="history-date">${at(p.timestamp,n)}</span>
${c?o`<button class="history-edit"
title="${i("history_edit_button",n)||"Edit"}"
@click=${()=>this._onEditHistoryEntry(p)}>
<ha-icon icon="mdi:pencil"></ha-icon>
</button>`:u}
</div>
${p.notes?o`<div class="history-notes">${p.notes}</div>`:u}
${p.cost!=null||p.duration!=null?o`<div class="history-meta">
${p.cost!=null?o`<span>💰 ${x(p.cost,n,2)}</span>`:u}
${p.duration!=null?o`<span>⏱️ ${p.duration}m</span>`:u}
</div>`:u}
</div>
`})}
${a.length>20?o`<div class="history-more">… +${a.length-20} ${i("older_entries",n)||"older"}</div>`:u}
</div>
`}
</div>
`}render(){if(!this._open)return u;let t=this._lang,n=this._task,a=this.hass?.user?.is_admin??!0;return o`
<div class="backdrop" @click=${this.close}></div>
<div class="dialog" role="dialog" aria-modal="true">
${n?o`
<div class="header">
<div class="title">
<span class="status-dot" style="background: ${B[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-P3P7TFC2.js").then(({openObjectQuickActions:r})=>{r(this._entryId),this.close()})}}>${this._objectName}</button>
</div>
<div class="quick-info">
${n.next_due?o`<span><strong>${i("next_due",t)||"Next due"}:</strong> ${z(n.next_due,t)}</span>`:u}
${n.last_performed?o`<span><strong>${i("last_performed",t)||"Last"}:</strong> ${z(n.last_performed,t)}</span>`:u}
${n.schedule?.kind&&!["manual","one_time"].includes(n.schedule.kind)||n.interval_days!=null?o`<span><strong>${i("interval",t)||"Interval"}:</strong> ${rt(n,t)}</span>`:u}
${N(n)?o`<span><strong>${i("phase_current",t)}:</strong> ${N(n)}</span>`:u}
</div>
</div>
${this._error?o`<div class="error">${this._error}</div>`:u}
${this._showSkip?o`
<div class="inline-form">
<label>${i("skip_reason",t)||"Skip reason (optional)"}</label>
<input type="text" .value=${this._skipReason}
@input=${r=>{this._skipReason=r.target.value}} />
<div class="inline-actions">
<button class="btn cancel" @click=${()=>{this._showSkip=!1}} ?disabled=${this._busy}>
${i("cancel",t)||"Cancel"}
</button>
<button class="btn primary" @click=${this._onSkipConfirm} ?disabled=${this._busy}>
${i("skip",t)||"Skip"}
</button>
</div>
</div>
`:this._showReset?o`
<div class="inline-form">
<label>${i("reset_to_date",t)||"Reset last_performed to"}</label>
<ms-date-field
kind="date"
.hass=${this.hass}
.lang=${t}
.value=${this._resetDate}
@value-changed=${r=>{this._resetDate=r.detail.value}}
></ms-date-field>
<div class="inline-actions">
<button class="btn cancel" @click=${()=>{this._showReset=!1}} ?disabled=${this._busy}>
${i("cancel",t)||"Cancel"}
</button>
<button class="btn primary" @click=${this._onResetConfirm} ?disabled=${this._busy}>
${i("reset",t)||"Reset"}
</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>
${i("complete",t)||"Complete"}
</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>
${i("skip",t)||"Skip"}
</ha-button>
`:u}
<ha-button appearance="outlined" variant="neutral" @click=${()=>{this._showReset=!0}} .disabled=${this._busy}>
<ha-icon slot="start" icon="mdi:restart"></ha-icon>
${i("reset",t)||"Reset"}
</ha-button>
</div>
${a?o`
<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>
${i("edit",t)||"Edit"}
</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>
${i("qr_code",t)||"QR"}
</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?i("unarchive",t)||"Unarchive":i("archive",t)||"Archive"}
</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>
${i("delete",t)||"Delete"}
</ha-button>
</div>
`:u}
<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?i("hide_details",t)||"Hide details":i("show_details",t)||"Show history + stats"}
</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?i("hide_stats",t)||"Hide stats":i("show_stats",t)||"Show stats + graphs"}
</button>`:u}
</div>
${this._showDetails?this._renderDetails(n):u}
${this._showAdaptive?this._renderAdaptive(n):u}
<div class="footer">
<button class="link" @click=${this._onOpenInPanel}>
<ha-icon icon="mdi:open-in-new"></ha-icon>
${i("open_in_panel",t)||"Open in Maintenance panel"}
</button>
</div>
`}
`:o`<div class="loading">${i("loading",t)||"Loading\u2026"}</div>`}
</div>
`}};k.styles=[lt,H`
: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; }
.history-list { display: flex; flex-direction: column; gap: 8px; max-height: 280px; overflow: auto; }
.history-entry {
padding: 6px 8px; border-radius: 6px;
background: var(--secondary-background-color, rgba(255,255,255,0.03));
font-size: 13px;
}
.history-line {
display: flex; align-items: center; gap: 8px;
justify-content: space-between;
}
.history-type {
font-weight: 600; font-size: 11px;
padding: 2px 6px; border-radius: 4px;
text-transform: uppercase; letter-spacing: 0.5px;
}
.type-completed { background: rgba(46,125,50,0.2); color: #66bb6a; }
.type-skipped { background: rgba(158,158,158,0.2); color: var(--secondary-text-color); }
.type-reset { background: rgba(33,150,243,0.2); color: #64b5f6; }
.type-triggered { background: rgba(255,87,34,0.2); color: #ff8a65; }
.history-date { font-size: 11px; color: var(--secondary-text-color); flex: 1; text-align: right; }
.history-edit {
background: transparent; border: none; cursor: pointer;
padding: 4px; border-radius: 4px;
color: var(--secondary-text-color);
}
.history-edit:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); color: var(--primary-color); }
.history-edit ha-icon { --mdc-icon-size: 14px; }
.history-notes { margin-top: 4px; color: var(--primary-text-color); }
.history-meta { display: flex; gap: 12px; margin-top: 4px; color: var(--secondary-text-color); 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; }
`],m([R({attribute:!1})],k.prototype,"hass",2),m([g()],k.prototype,"_open",2),m([g()],k.prototype,"_entryId",2),m([g()],k.prototype,"_taskId",2),m([g()],k.prototype,"_task",2),m([g()],k.prototype,"_objectName",2),m([g()],k.prototype,"_busy",2),m([g()],k.prototype,"_error",2),m([g()],k.prototype,"_showSkip",2),m([g()],k.prototype,"_showReset",2),m([g()],k.prototype,"_showDetails",2),m([g()],k.prototype,"_showAdaptive",2),m([g()],k.prototype,"_skipReason",2),m([g()],k.prototype,"_resetDate",2),m([g()],k.prototype,"_features",2),m([g()],k.prototype,"_toast",2);customElements.get("maintenance-task-quick-actions-dialog")||customElements.define("maintenance-task-quick-actions-dialog",k);function xt(e){return!!e&&/^https?:\/\//i.test(e)}function kt(e){return e?customElements.get("ha-markdown")?o`<ha-markdown class="notes-md" .content=${e} breaks></ha-markdown>`:o`${e}`:u}var M=class extends O{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._data=null;this._busy=!1;this._error=""}get _lang(){return E(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=L(t,this._lang)}}_onEditObject(){!this._entryId||!this._data||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-P3P7TFC2.js").then(({openEditObjectDialog:t})=>{t(this._entryId,this._data.object),this.close()})}_onAddTask(){this._entryId&&import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-P3P7TFC2.js").then(({openCreateTaskDialog:t})=>{t(this._entryId),this.close()})}async _onDelete(){if(!this._entryId||!this._data)return;let t=i("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=L(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=i("confirm_archive_object",this._lang)||"Archive this object and its tasks?";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=L(n,this._lang)}finally{this._busy=!1}}_onTaskClick(t){this._entryId&&import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-P3P7TFC2.js").then(({openTaskQuickActions:n})=>{n(this._entryId,t)})}render(){if(!this._open)return u;let t=this._lang,n=this._data,a=n?.object,r=n?.tasks||[],l=this.hass?.user?.is_admin??!0;return o`
<div class="backdrop" @click=${this.close}></div>
<div class="dialog" role="dialog" aria-modal="true">
${n&&a?o`
<div class="header">
<div class="title">${a.name}</div>
${this._renderMetaRow(a)}
</div>
${this._error?o`<div class="error">${this._error}</div>`:u}
<div class="tasks-section">
<div class="section-header">
<strong>${i("tasks",t)||"Tasks"}</strong>
<span class="count">${r.length}</span>
</div>
${r.length===0?o`<div class="empty">${i("no_tasks",t)||"No tasks yet."}</div>`:o`
<div class="task-list">
${r.map(d=>o`
<div class="task-row" @click=${()=>this._onTaskClick(d.id)}>
<span class="status-dot" style="background: ${B[d.status]||"#ccc"}"></span>
<span class="task-name">${d.name}</span>
<span class="task-status">${i(d.status||"ok",t)}</span>
</div>
`)}
</div>
`}
</div>
${a.notes?o`
<div class="notes-section">
<strong>${i("object_notes_label",t)}</strong>
<div class="notes-body">${kt(a.notes)}</div>
</div>
`:u}
${l?o`
<div class="actions">
<button class="btn primary" @click=${this._onAddTask} ?disabled=${this._busy}>
<ha-icon icon="mdi:plus"></ha-icon>
${i("add_task",t)||"Add task"}
</button>
<button class="btn" @click=${this._onEditObject} ?disabled=${this._busy}>
<ha-icon icon="mdi:pencil"></ha-icon>
${i("edit",t)||"Edit"}
</button>
<button class="btn" @click=${this._onArchiveObject} ?disabled=${this._busy}>
<ha-icon icon="${a.archived?"mdi:archive-arrow-up-outline":"mdi:archive-outline"}"></ha-icon>
${a.archived?i("unarchive_object",t)||"Unarchive object":i("archive_object",t)||"Archive object"}
</button>
<button class="btn danger" @click=${this._onDelete} ?disabled=${this._busy}>
<ha-icon icon="mdi:delete"></ha-icon>
${i("delete",t)||"Delete"}
</button>
</div>
`:u}
`:o`<div class="loading">${i("loading",t)||"Loading\u2026"}</div>`}
</div>
`}_renderMetaRow(t){let n=this._lang,a=[];return t.area_id&&a.push([i("area",n),t.area_id]),t.manufacturer&&a.push([i("manufacturer",n),t.manufacturer]),t.model&&a.push([i("model",n),t.model]),t.serial_number&&a.push([i("serial_number_label",n),t.serial_number]),t.installation_date&&a.push([i("installed",n),t.installation_date]),t.warranty_expiry&&a.push([i("warranty",n),t.warranty_expiry]),t.documentation_url&&a.push([i("documentation_url_label",n),t.documentation_url]),a.length===0?u:o`
<div class="meta">
${a.map(([r,l])=>o`
<div class="meta-item">
<span class="meta-label">${r}</span>
<span class="meta-value">${xt(l)?o`<a href="${l}" target="_blank" rel="noopener noreferrer">${l}</a>`:l}</span>
</div>
`)}
</div>
`}};M.styles=H`
: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; }
`,m([R({attribute:!1})],M.prototype,"hass",2),m([g()],M.prototype,"_open",2),m([g()],M.prototype,"_entryId",2),m([g()],M.prototype,"_data",2),m([g()],M.prototype,"_busy",2),m([g()],M.prototype,"_error",2);customElements.get("maintenance-object-quick-actions-dialog")||customElements.define("maintenance-object-quick-actions-dialog",M);var $t="maintenance-object-dialog",wt="maintenance-task-dialog",Wt="maintenance-history-edit-dialog",Ft="maintenance-complete-dialog",Bt="maintenance-qr-dialog",Ut="maintenance-task-quick-actions-dialog",Kt="maintenance-object-quick-actions-dialog";function K(){return document.querySelector("home-assistant")?.hass}function Gt(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function C(e){let s=Gt(),t=s.querySelector(e)??document.body.querySelector(e);return t?t.parentNode!==s&&s.appendChild(t):(t=document.createElement(e),s.appendChild(t)),t}function I(e){let s=K();if(!s)return!1;e.hass=s;let t=E(s);return tt(t)||et(t).then(()=>{e.requestUpdate?.()}),nt(s.locale,s.config?.country),!0}var Q={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"};function fn(e){return J(e).then(s=>s.rowActionStyle)}function yn(){V=null}var V=null;function J(e){return V||(V=e.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(s=>({features:s.features??Q.features,defaultWarningDays:s.general?.default_warning_days??7,rowActionStyle:s.general?.row_action_style??Q.rowActionStyle})).catch(()=>Q),V)}function gn(){let e=C($t);return I(e)?(e.openCreate(),!0):!1}function vn(e,s){let t=C($t);return I(t)?(t.openEdit(e,s),!0):!1}function bn(e="",s){let t=C(wt);if(!I(t))return!1;let n=K();return n?((async()=>{let a=await J(n),r=t;r.checklistsEnabled=a.features.checklists,r.scheduleTimeEnabled=a.features.schedule_time,r.completionActionsEnabled=a.features.completion_actions,r.defaultWarningDays=a.defaultWarningDays,r.openCreate(e,s)})(),!0):!1}function xn(e,s){let t=C(wt);if(!I(t))return!1;let n=K();return n?((async()=>{try{let[a,r]=await Promise.all([n.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:e}),J(n)]),l=(a.tasks||[]).find(p=>p.id===s);if(!l){console.warn(`openEditTaskDialog: task ${s} not found in entry ${e}`);return}let d=t;d.checklistsEnabled=r.features.checklists,d.scheduleTimeEnabled=r.features.schedule_time,d.completionActionsEnabled=r.features.completion_actions,d.defaultWarningDays=r.defaultWarningDays,await d.openEdit(e,l)}catch(a){console.warn("openEditTaskDialog: failed to load task/features",a)}})(),!0):!1}function kn(e){let s=C(Wt);return I(s)?(s.openEdit(e),!0):!1}function $n(e){let s=C(Ft);return I(s)?(_t(s,e,K()?.language||"en"),!0):!1}function wn(e){let s=C(Bt);return I(s)?(s.openForTask(e.entry_id,e.task_id,e.object_name,e.task_name),!0):!1}function An(e,s){let t=C(Ut);return I(t)?(t.openFor(e,s),!0):!1}function Dn(e){let s=C(Kt);return I(s)?(s.openFor(e),!0):!1}export{xt as a,ne as b,kt as c,jt as d,Ot as e,Z as f,ht as g,_t as h,y as i,he as j,_e as k,me as l,fe as m,ye as n,ge as o,ve as p,q,ie as r,re as s,mt as t,ft as u,yt as v,vt as w,bt as x,fn as y,yn as z,gn as A,vn as B,bn as C,xn as D,kn as E,$n as F,wn as G,An as H,Dn as I};
@@ -0,0 +1,213 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a as x}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-EOLJHFO4.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-Y2JXJRDF.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};
@@ -0,0 +1,64 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a as r,b as d,c as a,f as l,h as p,l as s,q as c}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-Y2JXJRDF.js";function h(o,e){if(e)switch(o){case"date":return e.split("T")[0];case"time":return e.length===5?`${e}:00`:e;case"datetime":{let[i,n="00:00:00"]=e.split("T");return`${i} ${n.length===5?`${n}:00`:n}`}}}function u(o,e){if(typeof e!="string"||!e)return"";switch(o){case"date":return e.slice(0,10);case"time":return e.slice(0,5);case"datetime":{let[i,n="00:00:00"]=e.split(" ");return`${i}T${n.length===5?`${n}:00`:n}`}}}var t=class extends p{constructor(){super(...arguments);this.kind="date";this.label="";this.value="";this.clearable=!1;this.disabled=!1;this.required=!1;this.lang="en"}_selector(){switch(this.kind){case"date":return{date:{}};case"time":return{time:{no_second:!0}};case"datetime":return{datetime:{}}}}_onSelectorChange(i){i.stopPropagation(),this._emit(u(this.kind,i.detail?.value))}_clear(){this._emit("")}_emit(i){i!==this.value&&(this.value=i,this.dispatchEvent(new CustomEvent("value-changed",{bubbles:!0,composed:!0,detail:{value:i}})))}render(){return a`
<div class="field">
${this.label?a`<span class="label">${this.label}${this.required?a`<span class="req">*</span>`:l}</span>`:l}
<div class="row">
<ha-selector
.hass=${this.hass}
.selector=${this._selector()}
.value=${h(this.kind,this.value)}
.required=${this.required}
.disabled=${this.disabled}
@value-changed=${this._onSelectorChange}
></ha-selector>
${this.clearable&&this.value&&!this.disabled?a`<button type="button" class="clear" title=${c("clear",this.lang)} aria-label=${c("clear",this.lang)} @click=${this._clear}>
<ha-icon icon="mdi:close"></ha-icon>
</button>`:l}
</div>
${this.helper?a`<span class="helper">${this.helper}</span>`:l}
</div>
`}};t.styles=d`
: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 {
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 { background: rgba(var(--rgb-primary-text-color, 0, 0, 0), 0.08); }
.clear:focus-visible { outline: 2px solid var(--primary-color); }
.helper {
font-size: 11px;
color: var(--secondary-text-color);
font-style: italic;
}
`,r([s({attribute:!1})],t.prototype,"hass",2),r([s()],t.prototype,"kind",2),r([s()],t.prototype,"label",2),r([s()],t.prototype,"value",2),r([s()],t.prototype,"helper",2),r([s({type:Boolean})],t.prototype,"clearable",2),r([s({type:Boolean})],t.prototype,"disabled",2),r([s({type:Boolean})],t.prototype,"required",2),r([s()],t.prototype,"lang",2);customElements.get("ms-date-field")||customElements.define("ms-date-field",t);
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.74.0 */
import{q as _}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-Y2JXJRDF.js";function u(e){return`${e.entry_id??""}\0${e.part_id}`}function l(e,r,s,c){let n=!!e.entry_id&&e.entry_id!==r,o=n?e.entry_id:r,a=s.find(p=>p.entry_id===o),t=(a?.parts||[]).find(p=>p.id===e.part_id)||null,d=n&&a?.object?.name||"",i=t?.name||_("shared_part_unknown",c);return{part:t,foreign:n,ownerName:d,label:d?`${i} (${d})`:i}}function P(e,r,s,c){let{part:n,label:o}=l(e,r,s,c),a=n&&n.stock!==null&&n.stock!==void 0?` (${n.stock}${n.unit?" "+n.unit:""})`:"",t=n?.storage_location?` \u2014 ${n.storage_location}`:"";return`${e.quantity}\xD7 ${o}${a}${t}`}function g(e,r,s,c){let o=(s.find(t=>t.entry_id===r)?.parts||[]).map(t=>({...t})),a=new Set(o.map(t=>u({part_id:t.id})));for(let t of e?.consumes_parts||[]){if(!t.entry_id||t.entry_id===r)continue;let d=u(t);if(a.has(d))continue;a.add(d);let{part:i,ownerName:p}=l(t,r,s,c);o.push({id:t.part_id,name:i?.name||_("shared_part_unknown",c),unit:i?.unit,stock:i?.stock??null,storage_location:i?.storage_location,entry_id:t.entry_id,owner_name:p})}return o}var f=["notes","cost","duration","photo","user"],m={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"};export{u as a,P as b,g as c,f as d,m as e};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-EUJZWPBG.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-YP2KCO26.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-VLQ4FCHW.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-NYOACMQR.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-Y2JXJRDF.js";export{a as MaintenanceCompleteDialog};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.74.0 */
import{A as c,B as d,C as e,D as f,E as g,F as h,G as i,H as j,I as k,y as a,z as b}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-T4NXNE6P.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-MESNEW3F.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-GV4G354Y.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-OFC6OKGF.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-EUJZWPBG.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-YP2KCO26.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-VLQ4FCHW.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-UJ7FC2Z7.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-EOLJHFO4.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-S2VAROHZ.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-NYOACMQR.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-Y2JXJRDF.js";export{b as __resetSettingsCacheForTests,a as getRowActionStyle,h as openCompleteDialog,c as openCreateObjectDialog,e as openCreateTaskDialog,d as openEditObjectDialog,f as openEditTaskDialog,g as openHistoryEditDialog,k as openObjectQuickActions,i as openQrDialog,j as openTaskQuickActions};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-MESNEW3F.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-OFC6OKGF.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-VLQ4FCHW.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-NYOACMQR.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-Y2JXJRDF.js";export{a as MaintenanceObjectDialog};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-UJ7FC2Z7.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-EOLJHFO4.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-Y2JXJRDF.js";export{a as MaintenanceQrDialog};
@@ -0,0 +1,146 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a as g}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NYOACMQR.js";import{a as l,b as m,c as i,f as h,h as v,l as u,m as d,q as p,s as f,u as x}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-Y2JXJRDF.js";var a=class extends v{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._adopting=!1;this._error="";this._setups=[];this._selected=new Set;this._baselines=new Map;this._targets=new Map;this._objects=[];this._localeReady=!1;this._toggle=t=>{let e=new Set(this._selected);e.has(t)?e.delete(t):e.add(t),this._selected=e};this._adopt=async()=>{if(!(this._selected.size===0||this._adopting)){this._adopting=!0,this._error="";try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/integration_setups/adopt",selections:[...this._selected].map(e=>{let r={device_id:e},c=this._targets.get(e);c&&(r.entry_id=c);let s=this._setups.find(n=>n.device_id===e);for(let n of s?.tasks??[]){let o=this._baselines.get(`${e} ${n.task_name}`),_=o?parseFloat(o):NaN;!isNaN(_)&&_>=0&&((r.baselines??={})[n.task_name]=_)}return r})});this.dispatchEvent(new CustomEvent("integration-setups-adopted",{bubbles:!0,composed:!0,detail:t})),this._open=!1}catch(t){this._error=g(t,this._lang)}finally{this._adopting=!1}}}}get _lang(){return f(this.hass)}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,x(this._lang).then(()=>this.requestUpdate()))}async open(){this._open=!0,this._loading=!0,this._error="",this._setups=[],this._selected=new Set;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/integration_setups/discover"});this._setups=t.setups||[],this._selected=new Set(this._setups.map(e=>e.device_id)),this._baselines=new Map,this._targets=new Map;try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"});this._objects=(e.objects||[]).map(r=>({entry_id:r.entry_id,name:r.object?.name||r.entry_id})).sort((r,c)=>r.name.localeCompare(c.name))}catch{this._objects=[]}}catch(t){this._error=g(t,this._lang)}finally{this._loading=!1}}_close(){this._open=!1}render(){if(!this._open)return i``;let t=this._lang;return i`
<div class="overlay" @click=${this._close}>
<div class="card" @click=${e=>e.stopPropagation()}>
<div class="title">${p("setups_title",t)}</div>
<div class="hint">${p("setups_hint",t)}</div>
${this._error?i`<div class="error">${this._error}</div>`:h}
${this._loading?i`<div class="loading">…</div>`:this._setups.length===0?i`<div class="empty">${p("setups_none",t)}</div>`:i`
<div class="list">
${this._setups.map(e=>{let r=this._selected.has(e.device_id),c=[e.integration_name,e.area_name].filter(Boolean).join(" \xB7 ");return i`
<label class="row">
<input
type="checkbox"
.checked=${r}
@change=${()=>this._toggle(e.device_id)}
/>
<div class="row-main">
<div class="row-top">
<span class="row-name">${e.device_name}</span>
</div>
<div class="row-sub">${c}</div>
<div class="row-target" @click=${s=>s.preventDefault()}>
→
${r&&this._objects.length>0?i`
<select
class="target-select"
@change=${s=>{let n=new Map(this._targets),o=s.target.value;o?n.set(e.device_id,o):n.delete(e.device_id),this._targets=n}}
>
<option value="" ?selected=${!this._targets.get(e.device_id)}>
${e.suggested_entry_id?e.suggested_object_name:p("setups_target_new",t).replace("{name}",e.suggested_object_name)}
</option>
${this._objects.filter(s=>s.entry_id!==e.suggested_entry_id).map(s=>i`<option
value=${s.entry_id}
?selected=${this._targets.get(e.device_id)===s.entry_id}
>
${s.name}
</option>`)}
</select>
`:i`${e.suggested_object_name}${e.suggested_entry_id?h:i` <span class="new-tag">${p("adopt_problem_new_object",t)}</span>`}`}
</div>
<div class="row-tasks">
${e.tasks.map(s=>i`<span class="chip" title=${s.entity_ids.join(", ")}>
<ha-icon icon="mdi:link-variant"></ha-icon>${s.task_name_localized||s.task_name}
</span>`)}
</div>
${r?e.tasks.filter(s=>s.direction==="usage_delta").map(s=>{let n=`${e.device_id} ${s.task_name}`;return i`
<div class="baseline-field" @click=${o=>o.preventDefault()}>
<span class="baseline-label"
>${s.task_name_localized||s.task_name} —
${p("setups_baseline_hint",t)}</span
>
<input
type="number"
step="any"
min="0"
.value=${this._baselines.get(n)??""}
@click=${o=>o.preventDefault()}
@input=${o=>{let _=new Map(this._baselines);_.set(n,o.target.value),this._baselines=_}}
/>
</div>
`}):h}
</div>
</label>
`})}
</div>
`}
<div class="actions">
<ha-button appearance="plain" @click=${this._close}>
${p("cancel",t)}
</ha-button>
<ha-button
@click=${this._adopt}
.disabled=${this._selected.size===0||this._adopting}
>
${p("setups_adopt",t)}
</ha-button>
</div>
</div>
</div>
`}};a.styles=m`
.overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.card {
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
border-radius: 12px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 12px;
min-width: min(360px, calc(100vw - 24px));
max-width: 560px;
width: 90vw;
max-height: 80vh;
overflow: hidden;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}
.title { font-size: 18px; font-weight: 500; }
.hint { color: var(--secondary-text-color); font-size: 13px; }
.error { color: var(--error-color, #f44336); font-size: 13px; }
.loading, .empty { color: var(--secondary-text-color); font-size: 14px; padding: 12px 0; }
.list { display: flex; flex-direction: column; gap: 6px; overflow-y: auto; max-height: 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: 3px; min-width: 0; flex: 1; }
.row-name { font-weight: 500; font-size: 13px; }
.row-sub, .row-target { color: var(--secondary-text-color); font-size: 12px; }
.new-tag { font-style: italic; }
.row-tasks { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; }
.chip {
display: inline-flex; align-items: center; gap: 4px;
font-size: 11px; padding: 2px 8px; border-radius: 10px;
background: var(--secondary-background-color, rgba(0, 0, 0, 0.06));
color: var(--primary-text-color); white-space: nowrap;
}
.chip ha-icon { --mdc-icon-size: 12px; color: var(--primary-color); }
.target-select {
font-size: 12px; padding: 2px 4px; max-width: 100%;
border: 1px solid var(--divider-color); border-radius: 4px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
}
.baseline-field {
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
margin-top: 4px; font-size: 12px; color: var(--secondary-text-color);
}
.baseline-field input {
width: 110px; padding: 3px 6px; font-size: 12px;
border: 1px solid var(--divider-color); border-radius: 4px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
}
.actions { display: flex; justify-content: flex-end; gap: 8px; padding-top: 8px; }
`,l([u({attribute:!1})],a.prototype,"hass",2),l([d()],a.prototype,"_open",2),l([d()],a.prototype,"_loading",2),l([d()],a.prototype,"_adopting",2),l([d()],a.prototype,"_error",2),l([d()],a.prototype,"_setups",2),l([d()],a.prototype,"_selected",2),l([d()],a.prototype,"_baselines",2),l([d()],a.prototype,"_targets",2),l([d()],a.prototype,"_objects",2);customElements.get("maintenance-suggested-setups-dialog")||customElements.define("maintenance-suggested-setups-dialog",a);export{a as MaintenanceSuggestedSetupsDialog};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GV4G354Y.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-OFC6OKGF.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-YP2KCO26.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-VLQ4FCHW.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-S2VAROHZ.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-NYOACMQR.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-Y2JXJRDF.js";export{a as MaintenanceTaskDialog};
@@ -0,0 +1,125 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a as x,b as $}from"./chunk-2PETYFO2.js";import{a as h,b as n,d as b,e as y,f as m,g as o,h as _,i as a,j as g,k as v,o as f,p,z as c}from"./chunk-VJ2K4NTW.js";import{a as l}from"./chunk-3YPUSKYO.js";var E=80,s=class extends y{constructor(){super(...arguments);this._config={type:""};this._status=null;this._busy=!1;this._error="";this._localMonthly="";this._localYearly="";this._dirty=!1;this._loaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return v(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),g(this,t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load())}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/budget_status"});this._status=t,this._localMonthly=t.monthly_budget?String(t.monthly_budget):"",this._localYearly=t.yearly_budget?String(t.yearly_budget):"",this._dirty=!1}catch(t){this._error=c(t,this._lang)}}async _save(){if(this._isAdmin){this._busy=!0,this._error="";try{let t=this._localMonthly.trim()===""?0:parseFloat(this._localMonthly),r=this._localYearly.trim()===""?0:parseFloat(this._localYearly),i={};!isNaN(t)&&t>=0&&(i.budget_monthly=t),!isNaN(r)&&r>=0&&(i.budget_yearly=r),await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/global/update",settings:i}),await this._load()}catch(t){this._error=c(t,this._lang)}finally{this._busy=!1}}}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_budget"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,r=this._status;if(!r)return n`<ha-card><div class="loading">${a("loading",t)||"Loading\u2026"}</div></ha-card>`;let i=r.currency_symbol||_,k=r.alert_threshold_pct??E,w=[{label:a("budget_monthly",t)||"Monthly",spent:r.monthly_spent||0,budget:r.monthly_budget||0},{label:a("budget_yearly",t)||"Yearly",spent:r.yearly_spent||0,budget:r.yearly_budget||0}];return n`
<ha-card>
<div class="card-content">
<div class="header">
<div class="title">
<span class="emoji">💰</span>
<span>${this._config.title||a("settings_budget",t)||"Budget"}</span>
</div>
<span class="currency">${i}</span>
</div>
${this._error?n`<div class="error">${this._error}</div>`:b}
${w.map(e=>{if(!(e.budget>0))return n`
<div class="track spent-only">
<div class="track-label-row">
<label>${e.label}</label>
<span class="track-numbers ok">${p(e.spent,i,t,0)}</span>
</div>
</div>
`;let d=Math.min(100,Math.max(0,e.spent/e.budget*100)),u=d>=100?"danger":d>=k?"warning":"ok";return n`
<div class="track">
<div class="track-label-row">
<label>${e.label}</label>
<span class="track-numbers ${u}">
${f(e.spent,t,0)} / ${p(e.budget,i,t,0)}
</span>
</div>
<div class="bar"><div class="bar-fill ${u}" style="width:${d}%"></div></div>
</div>
`})}
${this._isAdmin?n`
<div class="inputs-row">
<div class="input-field">
<label>${a("budget_monthly_set",t)||"Set monthly"}</label>
<div class="input-wrap">
<input type="number" min="0" step="1"
.value=${this._localMonthly}
?disabled=${this._busy}
@input=${e=>{this._localMonthly=e.target.value,this._dirty=!0}} />
<span class="input-suffix">${i}</span>
</div>
</div>
<div class="input-field">
<label>${a("budget_yearly_set",t)||"Set yearly"}</label>
<div class="input-wrap">
<input type="number" min="0" step="1"
.value=${this._localYearly}
?disabled=${this._busy}
@input=${e=>{this._localYearly=e.target.value,this._dirty=!0}} />
<span class="input-suffix">${i}</span>
</div>
</div>
</div>
<div class="actions">
<button class="btn ${this._dirty?"primary":"muted"}"
@click=${this._save}
?disabled=${this._busy||!this._dirty}>
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
${this._dirty?a("save",t)||"Save":a("saved",t)||"Saved"}
</button>
<button class="btn link" @click=${this._onDeepLink}>
${a("budget_advanced",t)||"Currency, alerts\u2026"}
</button>
</div>
`:n`
<button class="btn link" @click=${this._onDeepLink}>
${a("budget_open_panel",t)||"Open in panel"}
</button>
`}
</div>
</ha-card>
`}};s.styles=[$,h`
.currency {
font-size: 14px; font-weight: 600;
color: var(--secondary-text-color);
background: var(--secondary-background-color);
padding: 2px 10px; border-radius: 999px;
}
.track { display: flex; flex-direction: column; gap: 4px; }
.track-label-row {
display: flex; align-items: center; justify-content: space-between;
}
.track-label-row label {
font-size: 12px; color: var(--secondary-text-color);
text-transform: uppercase; letter-spacing: 0.5px;
}
.track-numbers { font-size: 13px; font-weight: 600; }
.track-numbers.ok { color: var(--primary-text-color); }
.track-numbers.warning { color: #ff9800; }
.track-numbers.danger { color: var(--error-color, #f44336); }
.bar {
height: 6px; background: var(--secondary-background-color);
border-radius: 3px; overflow: hidden;
}
.bar-fill { height: 100%; transition: width 0.3s; border-radius: 3px; }
.bar-fill.ok { background: var(--primary-color); }
.bar-fill.warning { background: #ff9800; }
.bar-fill.danger { background: var(--error-color, #f44336); }
.inputs-row {
display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
padding-top: 4px; border-top: 1px solid var(--divider-color);
}
.input-field { display: flex; flex-direction: column; gap: 4px; }
.input-field label {
font-size: 11px; color: var(--secondary-text-color);
text-transform: uppercase; letter-spacing: 0.3px;
}
.input-wrap { position: relative; display: flex; align-items: center; }
.input-wrap input {
flex: 1; padding: 6px 32px 6px 8px; font-size: 13px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color); border-radius: 6px;
font-family: inherit;
}
.input-suffix {
position: absolute; right: 8px;
color: var(--secondary-text-color); font-size: 13px;
pointer-events: none;
}
.actions { display: flex; gap: 8px; align-items: center; }
`],l([m({attribute:!1})],s.prototype,"hass",2),l([o()],s.prototype,"_config",2),l([o()],s.prototype,"_status",2),l([o()],s.prototype,"_busy",2),l([o()],s.prototype,"_error",2),l([o()],s.prototype,"_localMonthly",2),l([o()],s.prototype,"_localYearly",2),l([o()],s.prototype,"_dirty",2);customElements.get("maintenance-budget-section-card")||customElements.define("maintenance-budget-section-card",s);x({type:"maintenance-budget-section-card",name:"Maintenance Supporter \u2014 Budget",description:"Inline monthly + yearly budget editor",preview:!1});export{s as MaintenanceBudgetSectionCard};
@@ -0,0 +1,60 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a as t}from"./chunk-VJ2K4NTW.js";function e(o){let r=window;r.customCards=r.customCards||[],r.customCards.some(a=>a.type===o.type)||r.customCards.push(o)}var d=t`
ha-card { overflow: hidden; }
.card-content {
padding: 16px;
display: flex; flex-direction: column;
gap: 12px;
}
.header {
display: flex; align-items: center; justify-content: space-between;
gap: 12px;
}
.title {
display: flex; align-items: center; gap: 8px;
font-size: 16px; font-weight: 500;
}
.emoji { font-size: 20px; }
/* Button family — primary action / muted-saved-state / link / icon-with-text */
.btn {
padding: 6px 12px; font-size: 13px;
border-radius: 6px; cursor: pointer;
border: 1px solid var(--divider-color);
background: var(--secondary-background-color, transparent);
color: var(--primary-text-color);
font-weight: 500;
display: inline-flex; align-items: center; gap: 4px;
}
.btn:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.btn.primary {
background: var(--primary-color);
color: var(--text-primary-color, white);
border-color: var(--primary-color);
}
.btn.primary[disabled] { opacity: 0.6; }
.btn.muted {
background: transparent;
color: var(--secondary-text-color);
border-style: dashed;
}
.btn.muted[disabled] { opacity: 1; cursor: default; }
.btn.muted ha-icon, .btn.primary ha-icon { --mdc-icon-size: 14px; }
.btn.link {
background: transparent; border: none; padding: 6px 4px;
color: var(--primary-color); margin-left: auto;
}
.btn.link:hover { background: transparent; text-decoration: underline; }
/* Error + loading states */
.error {
padding: 8px; border-radius: 6px;
background: rgba(211, 47, 47, 0.1);
color: var(--error-color, #d32f2f); font-size: 13px;
}
.loading {
padding: 24px; text-align: center;
color: var(--secondary-text-color);
}
`;export{e as a,d as b};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.74.0 */
var s=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var t=(a,r,c,o)=>{for(var e=o>1?void 0:o?l(r,c):r,i=a.length-1,d;i>=0;i--)(d=a[i])&&(e=(o?d(r,c,e):d(e))||e);return o&&e&&s(r,c,e),e};var m={ok:"var(--success-color, #4caf50)",due_soon:"var(--warning-color, #ff9800)",overdue:"var(--error-color, #f44336)",triggered:"var(--deep-orange-color, #ff5722)",archived:"var(--disabled-color, #9e9e9e)",paused:"var(--info-color, #2196f3)"},v={ok:"mdi:check-circle",due_soon:"mdi:alert-circle",overdue:"mdi:alert-octagon",triggered:"mdi:bell-alert",archived:"mdi:archive-outline",paused:"mdi:pause-circle-outline",completed:"mdi:check-circle",skipped:"mdi:skip-next",missed:"mdi:calendar-remove",reset:"mdi:refresh"};export{t as a,m as b,v as c};
@@ -0,0 +1,64 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a as d,b as a,d as l,e as p,f as s,i as c}from"./chunk-VJ2K4NTW.js";import{a as r}from"./chunk-3YPUSKYO.js";function h(o,e){if(e)switch(o){case"date":return e.split("T")[0];case"time":return e.length===5?`${e}:00`:e;case"datetime":{let[i,n="00:00:00"]=e.split("T");return`${i} ${n.length===5?`${n}:00`:n}`}}}function u(o,e){if(typeof e!="string"||!e)return"";switch(o){case"date":return e.slice(0,10);case"time":return e.slice(0,5);case"datetime":{let[i,n="00:00:00"]=e.split(" ");return`${i}T${n.length===5?`${n}:00`:n}`}}}var t=class extends p{constructor(){super(...arguments);this.kind="date";this.label="";this.value="";this.clearable=!1;this.disabled=!1;this.required=!1;this.lang="en"}_selector(){switch(this.kind){case"date":return{date:{}};case"time":return{time:{no_second:!0}};case"datetime":return{datetime:{}}}}_onSelectorChange(i){i.stopPropagation(),this._emit(u(this.kind,i.detail?.value))}_clear(){this._emit("")}_emit(i){i!==this.value&&(this.value=i,this.dispatchEvent(new CustomEvent("value-changed",{bubbles:!0,composed:!0,detail:{value:i}})))}render(){return a`
<div class="field">
${this.label?a`<span class="label">${this.label}${this.required?a`<span class="req">*</span>`:l}</span>`:l}
<div class="row">
<ha-selector
.hass=${this.hass}
.selector=${this._selector()}
.value=${h(this.kind,this.value)}
.required=${this.required}
.disabled=${this.disabled}
@value-changed=${this._onSelectorChange}
></ha-selector>
${this.clearable&&this.value&&!this.disabled?a`<button type="button" class="clear" title=${c("clear",this.lang)} aria-label=${c("clear",this.lang)} @click=${this._clear}>
<ha-icon icon="mdi:close"></ha-icon>
</button>`:l}
</div>
${this.helper?a`<span class="helper">${this.helper}</span>`:l}
</div>
`}};t.styles=d`
: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 {
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 { background: rgba(var(--rgb-primary-text-color, 0, 0, 0), 0.08); }
.clear:focus-visible { outline: 2px solid var(--primary-color); }
.helper {
font-size: 11px;
color: var(--secondary-text-color);
font-style: italic;
}
`,r([s({attribute:!1})],t.prototype,"hass",2),r([s()],t.prototype,"kind",2),r([s()],t.prototype,"label",2),r([s()],t.prototype,"value",2),r([s()],t.prototype,"helper",2),r([s({type:Boolean})],t.prototype,"clearable",2),r([s({type:Boolean})],t.prototype,"disabled",2),r([s({type:Boolean})],t.prototype,"required",2),r([s()],t.prototype,"lang",2);customElements.get("ms-date-field")||customElements.define("ms-date-field",t);
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,137 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a as v,b}from"./chunk-2PETYFO2.js";import{a as u,b as s,d as c,e as h,f as g,g as o,i,k as _,m,z as p}from"./chunk-VJ2K4NTW.js";import{a}from"./chunk-3YPUSKYO.js";var e=class extends h{constructor(){super(...arguments);this._config={type:""};this._groups={};this._loaded=!1;this._busy=!1;this._error="";this._newName="";this._editingId=null;this._editingName="";this._hasInitiallyLoaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return _(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._hasInitiallyLoaded&&(this._hasInitiallyLoaded=!0,this._load(),m(this._lang).then(()=>this.requestUpdate()))}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/groups"});this._groups=t.groups||{},this._loaded=!0}catch(t){this._error=p(t,this._lang)}}async _addGroup(){if(!this._isAdmin)return;let t=this._newName.trim();if(t){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/create",name:t}),this._newName="",await this._load()}catch(r){this._error=p(r,this._lang)}finally{this._busy=!1}}}_startEdit(t){this._editingId=t,this._editingName=this._groups[t]?.name||""}async _saveEdit(){if(!this._isAdmin||!this._editingId)return;let t=this._editingName.trim();if(t){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/update",group_id:this._editingId,name:t}),this._editingId=null,this._editingName="",await this._load()}catch(r){this._error=p(r,this._lang)}finally{this._busy=!1}}}async _deleteGroup(t,r){if(!this._isAdmin)return;let n=(i("group_delete_confirm",this._lang)||'Delete group "{name}"?').replace("{name}",r);if(window.confirm(n)){this._busy=!0;try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/delete",group_id:t}),await this._load()}catch(d){this._error=p(d,this._lang)}finally{this._busy=!1}}}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_groups"),window.dispatchEvent(new CustomEvent("location-changed"))}_onKeyDown(t,r){t.key==="Enter"?(t.preventDefault(),r()):t.key==="Escape"&&(t.preventDefault(),this._editingId=null,this._editingName="")}render(){let t=this._lang;if(!this._loaded)return s`<ha-card><div class="loading">${i("loading",t)||"Loading\u2026"}</div></ha-card>`;let r=Object.keys(this._groups);return s`
<ha-card>
<div class="card-content">
<div class="header">
<div class="title">
<span class="emoji">🏷️</span>
<span>${this._config.title||i("groups",t)||"Groups"}</span>
<span class="count">${r.length}</span>
</div>
</div>
${this._error?s`<div class="error">${this._error}</div>`:c}
${r.length===0?s`<div class="empty">${i("groups_empty",t)||"No groups yet."}</div>`:s`
<div class="group-list">
${r.map(n=>{let d=this._groups[n],y=d.task_refs?.length??0,f=this._editingId===n;return s`
<div class="group-row">
${f?s`
<input class="edit-input" type="text"
.value=${this._editingName}
?disabled=${this._busy}
@input=${l=>{this._editingName=l.target.value}}
@keydown=${l=>this._onKeyDown(l,this._saveEdit.bind(this))} />
<button class="btn small primary"
@click=${this._saveEdit}
?disabled=${this._busy||!this._editingName.trim()}>
${i("save",t)||"Save"}
</button>
<button class="btn small"
@click=${()=>{this._editingId=null}}>
${i("cancel",t)||"Cancel"}
</button>
`:s`
<span class="group-name">${d.name||"Unnamed"}</span>
<span class="task-count">${y}</span>
${this._isAdmin?s`
<button class="icon-btn"
title="${i("edit",t)||"Edit"}"
@click=${()=>this._startEdit(n)}
?disabled=${this._busy}>
<ha-icon icon="mdi:pencil"></ha-icon>
</button>
<button class="icon-btn danger"
title="${i("delete",t)||"Delete"}"
@click=${()=>this._deleteGroup(n,d.name||"Unnamed")}
?disabled=${this._busy}>
<ha-icon icon="mdi:delete"></ha-icon>
</button>
`:c}
`}
</div>
`})}
</div>
`}
${this._isAdmin?s`
<div class="add-row">
<input type="text"
placeholder="${i("group_new_placeholder",t)||"Add group\u2026"}"
.value=${this._newName}
?disabled=${this._busy}
@input=${n=>{this._newName=n.target.value}}
@keydown=${n=>this._onKeyDown(n,this._addGroup.bind(this))} />
<button class="btn primary"
@click=${this._addGroup}
?disabled=${this._busy||!this._newName.trim()}>
<ha-icon icon="mdi:plus"></ha-icon>
${i("add",t)||"Add"}
</button>
</div>
<button class="btn link" @click=${this._onDeepLink}>
${i("groups_manage_tasks",t)||"Manage task assignments\u2026"}
</button>
`:s`
<button class="btn link" @click=${this._onDeepLink}>
${i("groups_open_panel",t)||"Open in panel"}
</button>
`}
</div>
</ha-card>
`}};e.styles=[b,u`
.count {
font-size: 12px; color: var(--secondary-text-color);
background: var(--secondary-background-color);
padding: 2px 8px; border-radius: 999px;
}
.empty {
padding: 16px; text-align: center;
color: var(--secondary-text-color); font-style: italic;
}
.group-list { display: flex; flex-direction: column; gap: 4px; }
.group-row {
display: flex; align-items: center; gap: 8px;
padding: 6px 8px; border-radius: 6px;
background: var(--secondary-background-color, rgba(255,255,255,0.03));
}
.group-name { flex: 1; font-size: 14px; }
.task-count {
font-size: 11px; color: var(--secondary-text-color);
background: var(--card-background-color, rgba(0,0,0,0.2));
padding: 1px 8px; border-radius: 999px;
font-weight: 500;
}
.edit-input {
flex: 1; padding: 4px 8px; font-size: 14px;
background: var(--card-background-color, #1c1c1c);
color: var(--primary-text-color);
border: 1px solid var(--primary-color); border-radius: 4px;
font-family: inherit;
}
.icon-btn {
background: transparent; border: none; cursor: pointer;
color: var(--secondary-text-color); padding: 4px;
border-radius: 4px;
}
.icon-btn:hover {
background: var(--state-icon-color, rgba(255,255,255,0.06));
color: var(--primary-text-color);
}
.icon-btn.danger:hover { color: var(--error-color); }
.icon-btn ha-icon { --mdc-icon-size: 18px; }
.add-row {
display: flex; gap: 6px;
padding-top: 8px; border-top: 1px solid var(--divider-color);
}
.add-row input {
flex: 1; padding: 6px 8px; font-size: 13px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color); border-radius: 6px;
font-family: inherit;
}
/* Card-specific overrides on the shared .btn */
.btn.small { padding: 4px 8px; font-size: 12px; }
.btn ha-icon { --mdc-icon-size: 16px; }
`],a([g({attribute:!1})],e.prototype,"hass",2),a([o()],e.prototype,"_config",2),a([o()],e.prototype,"_groups",2),a([o()],e.prototype,"_loaded",2),a([o()],e.prototype,"_busy",2),a([o()],e.prototype,"_error",2),a([o()],e.prototype,"_newName",2),a([o()],e.prototype,"_editingId",2),a([o()],e.prototype,"_editingName",2);customElements.get("maintenance-groups-section-card")||customElements.define("maintenance-groups-section-card",e);v({type:"maintenance-groups-section-card",name:"Maintenance Supporter \u2014 Groups",description:"Inline group CRUD",preview:!1});export{e as MaintenanceGroupsSectionCard};
@@ -0,0 +1,134 @@
/*! maintenance_supporter frontend 2.74.0 */
import{a as b,b as g}from"./chunk-2PETYFO2.js";import"./chunk-KWP6LLK2.js";import{a as h,b as n,d as c,e as _,f as v,g as r,i as e,k as f,m,z as o}from"./chunk-VJ2K4NTW.js";import{a as i}from"./chunk-3YPUSKYO.js";var a=class extends _{constructor(){super(...arguments);this._config={type:""};this._state=null;this._busy=!1;this._error="";this._localStart="";this._localEnd="";this._localBuffer=7;this._dirty=!1;this._loaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return f(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load(),m(this._lang).then(()=>this.requestUpdate()))}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/state"});this._state=t,this._localStart=t.start||"",this._localEnd=t.end||"",this._localBuffer=t.buffer_days??7,this._dirty=!1}catch(t){this._error=o(t,this._lang)}}async _toggleEnabled(t){this._busy=!0,this._error="";try{let s=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/update",enabled:t});this._state=s}catch(s){this._error=o(s,this._lang)}finally{this._busy=!1}}async _save(){if(this._isAdmin){this._busy=!0,this._error="";try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/update",start:this._localStart||null,end:this._localEnd||null,buffer_days:this._localBuffer});this._state=t,this._dirty=!1}catch(t){this._error=o(t,this._lang)}finally{this._busy=!1}}}async _endNow(){if(this._isAdmin&&window.confirm(e("vacation_end_now_confirm",this._lang)||"End vacation immediately?")){this._busy=!0;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/end_now"});this._state=t,this._localStart=t.start||"",this._localEnd=t.end||""}catch(t){this._error=o(t,this._lang)}finally{this._busy=!1}}}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_vacation"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,s=this._state;if(!s)return n`<ha-card><div class="loading">${e("loading",t)||"Loading\u2026"}</div></ha-card>`;let p=s.is_active===!0,d=s.enabled===!0,u=s.exempt_task_ids?.length??0,y=p?e("vacation_status_active",t)||"Active now":d?e("vacation_status_scheduled",t)||"Scheduled":e("vacation_status_inactive",t)||"Inactive",$=p?"active":d?"scheduled":"inactive";return n`
<ha-card>
<div class="card-content">
<div class="header">
<div class="title">
<span class="emoji">🏖️</span>
<span>${this._config.title||e("vacation_mode",t)||"Vacation mode"}</span>
</div>
<span class="status-pill ${$}">${y}</span>
</div>
${this._error?n`<div class="error">${this._error}</div>`:c}
${this._isAdmin?n`
<div class="row toggle-row">
<label>${e("enable",t)||"Enable"}</label>
<ha-switch
.checked=${d}
.disabled=${this._busy}
@change=${l=>this._toggleEnabled(l.target.checked)}
></ha-switch>
</div>
<div class="dates-row">
<div class="date-field">
<label>${e("vacation_start",t)||"Start"}</label>
<ms-date-field
kind="date"
clearable
.hass=${this.hass}
.lang=${t}
.value=${this._localStart}
.disabled=${this._busy}
@value-changed=${l=>{this._localStart=l.detail.value,this._dirty=!0}}
></ms-date-field>
</div>
<div class="date-field">
<label>${e("vacation_end",t)||"End"}</label>
<ms-date-field
kind="date"
clearable
.hass=${this.hass}
.lang=${t}
.value=${this._localEnd}
.disabled=${this._busy}
@value-changed=${l=>{this._localEnd=l.detail.value,this._dirty=!0}}
></ms-date-field>
</div>
<div class="date-field buffer">
<label>${e("vacation_buffer",t)||"Buffer days"}</label>
<input type="number" min="0" max="14"
.value=${String(this._localBuffer)}
?disabled=${this._busy}
@input=${l=>{this._localBuffer=parseInt(l.target.value,10)||0,this._dirty=!0}} />
</div>
</div>
<div class="actions">
<button class="btn ${this._dirty?"primary":"muted"}"
@click=${this._save}
?disabled=${this._busy||!this._dirty}>
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
${this._dirty?e("save",t)||"Save":e("saved",t)||"Saved"}
</button>
${p?n`<button class="btn"
@click=${this._endNow}
?disabled=${this._busy}>
${e("vacation_end_now",t)||"End now"}
</button>`:c}
${u>0?n`<button class="btn link"
@click=${this._onDeepLink}>
${u} ${e("vacation_exempt_count",t)||"exempt"}…
</button>`:n`<button class="btn link"
@click=${this._onDeepLink}>
${e("vacation_advanced",t)||"Advanced\u2026"}
</button>`}
</div>
`:n`
<div class="readonly">
${d&&s.start&&s.end?n`<div>${s.start} → ${s.end}</div>`:c}
<button class="btn link" @click=${this._onDeepLink}>
${e("vacation_open_panel",t)||"Open in panel"}
</button>
</div>
`}
</div>
</ha-card>
`}};a.styles=[g,h`
.status-pill {
font-size: 11px; font-weight: 600;
padding: 3px 8px; border-radius: 999px;
text-transform: uppercase; letter-spacing: 0.5px;
}
.status-pill.active {
background: rgba(76, 175, 80, 0.15);
color: #4caf50;
}
.status-pill.scheduled {
background: rgba(255, 152, 0, 0.15);
color: #ff9800;
}
.status-pill.inactive {
background: rgba(158, 158, 158, 0.15);
color: var(--secondary-text-color);
}
.row.toggle-row {
display: flex; align-items: center; justify-content: space-between;
}
.row.toggle-row label {
font-size: 14px; color: var(--primary-text-color);
}
.dates-row {
display: grid; grid-template-columns: 1fr 1fr 100px; gap: 10px;
}
.date-field.buffer label { white-space: nowrap; }
.date-field { display: flex; flex-direction: column; gap: 4px; }
.date-field label {
font-size: 11px; color: var(--secondary-text-color);
text-transform: uppercase; letter-spacing: 0.3px;
}
.date-field input {
padding: 6px 8px; font-size: 13px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color); border-radius: 6px;
font-family: inherit;
}
.date-field input:disabled { opacity: 0.5; cursor: not-allowed; }
.actions {
display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.readonly { display: flex; flex-direction: column; gap: 8px; }
`],i([v({attribute:!1})],a.prototype,"hass",2),i([r()],a.prototype,"_config",2),i([r()],a.prototype,"_state",2),i([r()],a.prototype,"_busy",2),i([r()],a.prototype,"_error",2),i([r()],a.prototype,"_localStart",2),i([r()],a.prototype,"_localEnd",2),i([r()],a.prototype,"_localBuffer",2),i([r()],a.prototype,"_dirty",2);customElements.get("maintenance-vacation-section-card")||customElements.define("maintenance-vacation-section-card",a);b({type:"maintenance-vacation-section-card",name:"Maintenance Supporter \u2014 Vacation",description:"Inline vacation mode toggle + dates",preview:!1});export{a as MaintenanceVacationSectionCard};
@@ -1,5 +1,5 @@
/*! maintenance_supporter frontend 2.71.0 */
import{c as y}from"./chunks/chunk-DEN57ILL.js";var L="maintenance-supporter",G=`ll-strategy-dashboard-${L}`,x="hui-maintenance-supporter-strategy-editor",V="NOT_RUNNING",H=[{status:"overdue",title:"Overdue",icon:y.overdue,path:"overdue"},{status:"triggered",title:"Triggered",icon:y.triggered,path:"triggered"},{status:"due_soon",title:"Due Soon",icon:y.due_soon,path:"due-soon"},{status:"ok",title:"OK",icon:y.ok,path:"ok"}],E=[{title:"Overdue",icon:"mdi:alert-circle",path:"overdue",filter:{filter_due_max_days:-1},matches:n=>n<=-1},{title:"Today",icon:"mdi:calendar-today",path:"today",filter:{filter_due_min_days:0,filter_due_max_days:0},matches:n=>n===0},{title:"This Week",icon:"mdi:calendar-week",path:"this-week",filter:{filter_due_min_days:1,filter_due_max_days:7},matches:n=>n>=1&&n<=7},{title:"This Month",icon:"mdi:calendar-month",path:"this-month",filter:{filter_due_min_days:8,filter_due_max_days:30},matches:n=>n>=8&&n<=30},{title:"Later",icon:"mdi:calendar-clock",path:"later",filter:{filter_due_min_days:31},matches:n=>n>=31}];function l(n){return{type:"grid",cards:[n]}}var N={condition:"view_columns",min:2};function _(n,i,e){let s=i[n];if(s)return`{{ states('${s}') }}`;let t=e[n];return t==null?"\u2014":String(t)}function B(n={},i={}){return{type:"markdown",text_only:!0,content:[`\u{1F534} **${_("overdue",n,i)}** overdue`,`\u26A1 **${_("triggered",n,i)}** triggered`,`\u{1F7E1} **${_("due_soon",n,i)}** due soon`,`\u{1F7E2} **${_("ok",n,i)}** ok`].join(" \xB7 ")}}function $(){return{title:"Maintenance",type:"panel",cards:[{type:"empty-state",icon:"mdi:wrench-clock",icon_color:"primary",content_only:!0,title:"No maintenance objects yet",content:"Open the Maintenance panel to add your first object \u2014 pool pump, HVAC filter, vehicle, anything that needs scheduled care.",buttons:[{icon:"mdi:wrench",text:"Open Maintenance panel",appearance:"filled",variant:"brand",tap_action:{action:"navigate",navigation_path:"/maintenance-supporter"}},{icon:"mdi:plus",text:"Add object",appearance:"outlined",variant:"brand",tap_action:{action:"fire-dom-event",ll_custom:{type:"maintenance-supporter:add-object"}}}]}]}}function U(n={},i={}){let e=B(n,i);return{title:"Overview",icon:"mdi:wrench-clock",path:"overview",type:"sections",header:{layout:"responsive",card:e},sidebar:{sections:[{type:"grid",cards:[{type:"heading",heading:"Status",heading_style:"title"},e]}],visibility:[N],content_label:"Tasks",sidebar_label:"Status"},sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:["overdue","triggered","due_soon"]})]}}function W(n,i){let e=new Map;for(let a of n){let r=a.object.area_id||null;e.has(r)||e.set(r,[]),e.get(r).push(a)}let s=Array.from(e.keys()).filter(a=>a!==null);s.sort((a,r)=>{let d=i[a]?.name||a,c=i[r]?.name||r;return d.localeCompare(c)});let t=[];for(let a of s){let r=e.get(a);if(r.length===0)continue;let d=i[a];t.push({title:d?.name||a,icon:d?.icon||"mdi:floor-plan",path:`area-${a}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:r.map(c=>c.object.name)})]})}let o=e.get(null);return o&&o.length>0&&t.push({title:"Unassigned",icon:"mdi:help-circle-outline",path:"unassigned",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:o.map(a=>a.object.name)})]}),t}function Y(n){let i=new Set;for(let s of n)for(let t of s.tasks||[])t.status&&i.add(t.status);let e=[];for(let s of H)i.has(s.status)&&e.push({title:s.title,icon:s.icon,path:s.path,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:[s.status]})]});return e}function F(n,i,e){let s=new Map;for(let r of n){let d=r.object.area_id,c=d&&i[d]?.floor_id||null;s.has(c)||s.set(c,[]),s.get(c).push(r)}let t=Array.from(s.keys()).filter(r=>r!==null);t.sort((r,d)=>{let c=e[r],g=e[d],u=c?.level??0,p=g?.level??0;return u!==p?u-p:(c?.name||r).localeCompare(g?.name||d)});let o=[];for(let r of t){let d=s.get(r);if(d.length===0)continue;let c=e[r];o.push({title:c?.name||r,icon:c?.icon||"mdi:home-floor-1",path:`floor-${r}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:d.map(g=>g.object.name)})]})}let a=s.get(null);return a&&a.length>0&&o.push({title:"Other",icon:"mdi:help-circle-outline",path:"other",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:a.map(r=>r.object.name)})]}),o}function K(n){return[{title:"Week",icon:"mdi:calendar-week",path:"cal-7",window_days:7},{title:"Fortnight",icon:"mdi:calendar-week-begin",path:"cal-14",window_days:14},{title:"Month",icon:"mdi:calendar-month",path:"cal-30",window_days:30},{title:"Year",icon:"mdi:calendar-clock",path:"cal-365",window_days:365}].map(e=>({title:e.title,icon:e.icon,path:e.path,type:"panel",cards:[{type:"custom:maintenance-supporter-calendar-card",window_days:e.window_days,show_window_chips:!1,show_user_filter:!0}]}))}function q(n){let i=new Set;for(let sLine truncated
/*! maintenance_supporter frontend 2.74.0 */
import{c as y}from"./chunks/chunk-3YPUSKYO.js";var x="maintenance-supporter",G=`ll-strategy-dashboard-${x}`,I="hui-maintenance-supporter-strategy-editor",V="NOT_RUNNING",H=[{status:"overdue",title:"Overdue",icon:y.overdue,path:"overdue"},{status:"triggered",title:"Triggered",icon:y.triggered,path:"triggered"},{status:"due_soon",title:"Due Soon",icon:y.due_soon,path:"due-soon"},{status:"ok",title:"OK",icon:y.ok,path:"ok"}],T=[{title:"Overdue",icon:"mdi:alert-circle",path:"overdue",filter:{filter_due_max_days:-1},matches:n=>n<=-1},{title:"Today",icon:"mdi:calendar-today",path:"today",filter:{filter_due_min_days:0,filter_due_max_days:0},matches:n=>n===0},{title:"This Week",icon:"mdi:calendar-week",path:"this-week",filter:{filter_due_min_days:1,filter_due_max_days:7},matches:n=>n>=1&&n<=7},{title:"This Month",icon:"mdi:calendar-month",path:"this-month",filter:{filter_due_min_days:8,filter_due_max_days:30},matches:n=>n>=8&&n<=30},{title:"Later",icon:"mdi:calendar-clock",path:"later",filter:{filter_due_min_days:31},matches:n=>n>=31}];function l(n){return{type:"grid",cards:[n]}}var N={condition:"view_columns",min:2};function _(n,i,e){let s=i[n];if(s)return`{{ states('${s}') }}`;let t=e[n];return t==null?"\u2014":String(t)}function B(n={},i={}){return{type:"markdown",text_only:!0,content:[`\u{1F534} **${_("overdue",n,i)}** overdue`,`\u26A1 **${_("triggered",n,i)}** triggered`,`\u{1F7E1} **${_("due_soon",n,i)}** due soon`,`\u{1F7E2} **${_("ok",n,i)}** ok`].join(" \xB7 ")}}function $(){return{title:"Maintenance",type:"panel",cards:[{type:"empty-state",icon:"mdi:wrench-clock",icon_color:"primary",content_only:!0,title:"No maintenance objects yet",content:"Open the Maintenance panel to add your first object \u2014 pool pump, HVAC filter, vehicle, anything that needs scheduled care.",buttons:[{icon:"mdi:wrench",text:"Open Maintenance panel",appearance:"filled",variant:"brand",tap_action:{action:"navigate",navigation_path:"/maintenance-supporter"}},{icon:"mdi:plus",text:"Add object",appearance:"outlined",variant:"brand",tap_action:{action:"fire-dom-event",ll_custom:{type:"maintenance-supporter:add-object"}}}]}]}}function U(n={},i={}){let e=B(n,i);return{title:"Overview",icon:"mdi:wrench-clock",path:"overview",type:"sections",header:{layout:"responsive",card:e},sidebar:{sections:[{type:"grid",cards:[{type:"heading",heading:"Status",heading_style:"title"},e]}],visibility:[N],content_label:"Tasks",sidebar_label:"Status"},sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:["overdue","triggered","due_soon"]})]}}function W(n,i){let e=new Map;for(let a of n){let r=a.object.area_id||null;e.has(r)||e.set(r,[]),e.get(r).push(a)}let s=Array.from(e.keys()).filter(a=>a!==null);s.sort((a,r)=>{let d=i[a]?.name||a,c=i[r]?.name||r;return d.localeCompare(c)});let t=[];for(let a of s){let r=e.get(a);if(r.length===0)continue;let d=i[a];t.push({title:d?.name||a,icon:d?.icon||"mdi:floor-plan",path:`area-${a}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:r.map(c=>c.object.name)})]})}let o=e.get(null);return o&&o.length>0&&t.push({title:"Unassigned",icon:"mdi:help-circle-outline",path:"unassigned",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:o.map(a=>a.object.name)})]}),t}function Y(n){let i=new Set;for(let s of n)for(let t of s.tasks||[])t.status&&i.add(t.status);let e=[];for(let s of H)i.has(s.status)&&e.push({title:s.title,icon:s.icon,path:s.path,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:[s.status]})]});return e}function F(n,i,e){let s=new Map;for(let r of n){let d=r.object.area_id,c=d&&i[d]?.floor_id||null;s.has(c)||s.set(c,[]),s.get(c).push(r)}let t=Array.from(s.keys()).filter(r=>r!==null);t.sort((r,d)=>{let c=e[r],g=e[d],u=c?.level??0,p=g?.level??0;return u!==p?u-p:(c?.name||r).localeCompare(g?.name||d)});let o=[];for(let r of t){let d=s.get(r);if(d.length===0)continue;let c=e[r];o.push({title:c?.name||r,icon:c?.icon||"mdi:home-floor-1",path:`floor-${r}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:d.map(g=>g.object.name)})]})}let a=s.get(null);return a&&a.length>0&&o.push({title:"Other",icon:"mdi:help-circle-outline",path:"other",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:a.map(r=>r.object.name)})]}),o}function K(n){return[{title:"Week",icon:"mdi:calendar-week",path:"cal-7",window_days:7},{title:"Fortnight",icon:"mdi:calendar-week-begin",path:"cal-14",window_days:14},{title:"Month",icon:"mdi:calendar-month",path:"cal-30",window_days:30},{title:"Year",icon:"mdi:calendar-clock",path:"cal-365",window_days:365}].map(e=>({title:e.title,icon:e.icon,path:e.path,type:"panel",cards:[{type:"custom:maintenance-supporter-calendar-card",window_days:e.window_days,show_window_chips:!1,show_user_filter:!0}]}))}function q(n){let i=new Set;for(let sLine truncated
<style>
:host, .editor { display: block; padding: 16px 0; }
label { display: block; font-weight: 500; margin-bottom: 8px; }
@@ -22,4 +22,4 @@ import{c as y}from"./chunks/chunk-DEN57ILL.js";var L="maintenance-supporter",G=`
The "Overview" view is always first. Empty groups are skipped.
</div>
</div>
`;let t=this.querySelector("#group-by");t?.addEventListener("change",()=>{let o={...this._config,group_by:t.value};this._config=o,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:o},bubbles:!0,composed:!0}))})}},I="maintenance-supporter-section",Q=`ll-strategy-section-${I}`,v=class extends HTMLElement{static async generate(i,e){let s={type:"custom:maintenance-supporter-card",show_header:!1};i?.filter_status?.length&&(s.filter_status=i.filter_status),i?.max_items&&(s.max_items=i.max_items),i?.filter_due_min_days!==void 0&&(s.filter_due_min_days=i.filter_due_min_days),i?.filter_due_max_days!==void 0&&(s.filter_due_max_days=i.filter_due_max_days);let t=i?.filter_objects;if(i?.area_id&&!t)try{t=((await e.connection.sendMessagePromise({type:"maintenance_supporter/objects"})).objects||[]).filter(r=>r.object.area_id===i.area_id).map(r=>r.object.name)}catch{}t&&t.length>0&&(s.filter_objects=t);let o=[];return i?.title&&o.push({type:"heading",heading:i.title,heading_style:"title"}),o.push(s),{type:"grid",cards:o}}},D="2.3.6",X="[maintenance-supporter]";function M(n,i){try{return customElements.get(n)?"skipped":(customElements.define(n,i),"ok")}catch(e){return`ERROR: ${String(e)}`}}var P={editor:M(x,w),section:M(Q,v)};console.log(`${X} strategy bundle v${D} loaded \u2014 registrations:`,P,"\u2014 run maintenanceSupporterDiagnose() in console for full state");window.maintenanceSupporterDiagnose=async()=>{let n=G,i=[];try{let e=document.querySelector("home-assistant");e?.hass&&(i=(await e.hass.connection.sendMessagePromise({type:"lovelace/resources"})).resources||[])}catch(e){i=[{url:`<error: ${String(e)}>`}]}return{version:D,el_registered:!!customElements.get(n),el_class_excerpt:customElements.get(n)?.toString().slice(0,100)||null,customStrategies_dashboard:window.customStrategies?.filter(e=>e.strategyType==="dashboard").map(e=>e.type)||[],scriptTagsInPage:Array.from(document.querySelectorAll("script[type=module]")).map(e=>e.src).filter(e=>/maint|strateg/i.test(e)),lovelaceResources_matching:i.filter(e=>/maint|strateg/i.test(e.url||"")).map(e=>e.url),registrations:P}};var k=class extends HTMLElement{static async generate(i,e){return await import("./chunks/vacation-section-card-Z4PS42I4.js"),{type:"grid",cards:[{type:"custom:maintenance-vacation-section-card",title:i?.title}]}}},C=class extends HTMLElement{static async generate(i,e){return await import("./chunks/budget-section-card-CEY3GOFL.js"),{type:"grid",cards:[{type:"custom:maintenance-budget-section-card",title:i?.title}]}}},S=class extends HTMLElement{static async generate(i,e){return await import("./chunks/groups-section-card-QQQDDGNO.js"),{type:"grid",cards:[{type:"custom:maintenance-groups-section-card",title:i?.title}]}}},j="ll-strategy-section-maintenance-supporter-vacation",R="ll-strategy-section-maintenance-supporter-budget",A="ll-strategy-section-maintenance-supporter-groups";customElements.get(j)||customElements.define(j,k);customElements.get(R)||customElements.define(R,C);customElements.get(A)||customElements.define(A,S);var h=null;function J(){return h||(h=import("./chunks/dialog-mount-3UTDIR2B.js").catch(n=>{throw h=null,n})),h}var O="_msSupporterLlCustomBound";function m(n){history.pushState(null,"",n),window.dispatchEvent(new CustomEvent("location-changed"))}function Z(){let n=window;n[O]||(n[O]=!0,document.addEventListener("ll-custom",i=>{let e=i.detail;if(!e||typeof e!="object")return;let s=e.ll_custom,t=s&&typeof s=="object"?s:e;if(!t||typeof t.type!="string"||!t.type.startsWith("maintenance-supporter:"))return;let o=t.type.slice(22);if(o==="deep-link"&&typeof t.path=="string"){m(t.path);return}(async()=>{let a;try{a=await J()}catch{m("/maintenance-supporter");return}if(o==="add-object"){if(a.openCreateObjectDialog())return;m("/maintenance-supporter?ms_action=add_object");return}if(o==="open-task"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"){if(a.openTaskQuickActions(t.entry_id,t.task_id)||a.openEditTaskDialog(t.entry_id,t.task_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}&task_id=${encodeURIComponent(t.task_id)}`);return}if(o==="open-object"&&typeof t.entry_id=="string"){if(a.openObjectQuickActions(t.entry_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}`);return}if(o==="edit-history"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"&&typeof t.original_timestamp=="string"){let d=document.querySelector("home-assistant")?.hass;if(!d)return;try{let u=(await d.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:t.entry_id})).tasks?.find(p=>p.id===t.task_id)?.history?.find(p=>p.timestamp===t.original_timestamp);if(!u)return;a.openHistoryEditDialog({entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.original_timestamp,type:u.type||"completed",timestamp:u.timestamp||t.original_timestamp,notes:u.notes??null,cost:u.cost??null,duration:u.duration??null,completed_by:u.completed_by??null,used_parts:u.used_parts??null} Line truncated
`;let t=this.querySelector("#group-by");t?.addEventListener("change",()=>{let o={...this._config,group_by:t.value};this._config=o,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:o},bubbles:!0,composed:!0}))})}},E="maintenance-supporter-section",Q=`ll-strategy-section-${E}`,b=class extends HTMLElement{static async generate(i,e){let s={type:"custom:maintenance-supporter-card",show_header:!1};i?.filter_status?.length&&(s.filter_status=i.filter_status),i?.max_items&&(s.max_items=i.max_items),i?.filter_due_min_days!==void 0&&(s.filter_due_min_days=i.filter_due_min_days),i?.filter_due_max_days!==void 0&&(s.filter_due_max_days=i.filter_due_max_days);let t=i?.filter_objects;if(i?.area_id&&!t)try{t=((await e.connection.sendMessagePromise({type:"maintenance_supporter/objects"})).objects||[]).filter(r=>r.object.area_id===i.area_id).map(r=>r.object.name)}catch{}t&&t.length>0&&(s.filter_objects=t);let o=[];return i?.title&&o.push({type:"heading",heading:i.title,heading_style:"title"}),o.push(s),{type:"grid",cards:o}}},D="2.3.6",X="[maintenance-supporter]";function R(n,i){try{return customElements.get(n)?"skipped":(customElements.define(n,i),"ok")}catch(e){return`ERROR: ${String(e)}`}}var P={editor:R(I,k),section:R(Q,b)};console.log(`${X} strategy bundle v${D} loaded \u2014 registrations:`,P,"\u2014 run maintenanceSupporterDiagnose() in console for full state");window.maintenanceSupporterDiagnose=async()=>{let n=G,i=[];try{let e=document.querySelector("home-assistant");e?.hass&&(i=(await e.hass.connection.sendMessagePromise({type:"lovelace/resources"})).resources||[])}catch(e){i=[{url:`<error: ${String(e)}>`}]}return{version:D,el_registered:!!customElements.get(n),el_class_excerpt:customElements.get(n)?.toString().slice(0,100)||null,customStrategies_dashboard:window.customStrategies?.filter(e=>e.strategyType==="dashboard").map(e=>e.type)||[],scriptTagsInPage:Array.from(document.querySelectorAll("script[type=module]")).map(e=>e.src).filter(e=>/maint|strateg/i.test(e)),lovelaceResources_matching:i.filter(e=>/maint|strateg/i.test(e.url||"")).map(e=>e.url),registrations:P}};var w=class extends HTMLElement{static async generate(i,e){return await import("./chunks/vacation-section-card-EWJTZM6N.js"),{type:"grid",cards:[{type:"custom:maintenance-vacation-section-card",title:i?.title}]}}},v=class extends HTMLElement{static async generate(i,e){return await import("./chunks/budget-section-card-LN7A7YQB.js"),{type:"grid",cards:[{type:"custom:maintenance-budget-section-card",title:i?.title}]}}},C=class extends HTMLElement{static async generate(i,e){return await import("./chunks/groups-section-card-F3GLQTRW.js"),{type:"grid",cards:[{type:"custom:maintenance-groups-section-card",title:i?.title}]}}},j="ll-strategy-section-maintenance-supporter-vacation",A="ll-strategy-section-maintenance-supporter-budget",O="ll-strategy-section-maintenance-supporter-groups";customElements.get(j)||customElements.define(j,w);customElements.get(A)||customElements.define(A,v);customElements.get(O)||customElements.define(O,C);var te={[E]:b,"maintenance-supporter-vacation":w,"maintenance-supporter-budget":v,"maintenance-supporter-groups":C},h=null;function J(){return h||(h=import("./chunks/dialog-mount-BLDNA6JI.js").catch(n=>{throw h=null,n})),h}var L="_msSupporterLlCustomBound";function m(n){history.pushState(null,"",n),window.dispatchEvent(new CustomEvent("location-changed"))}function Z(){let n=window;n[L]||(n[L]=!0,document.addEventListener("ll-custom",i=>{let e=i.detail;if(!e||typeof e!="object")return;let s=e.ll_custom,t=s&&typeof s=="object"?s:e;if(!t||typeof t.type!="string"||!t.type.startsWith("maintenance-supporter:"))return;let o=t.type.slice(22);if(o==="deep-link"&&typeof t.path=="string"){m(t.path);return}(async()=>{let a;try{a=await J()}catch{m("/maintenance-supporter");return}if(o==="add-object"){if(a.openCreateObjectDialog())return;m("/maintenance-supporter?ms_action=add_object");return}if(o==="open-task"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"){if(a.openTaskQuickActions(t.entry_id,t.task_id)||a.openEditTaskDialog(t.entry_id,t.task_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}&task_id=${encodeURIComponent(t.task_id)}`);return}if(o==="open-object"&&typeof t.entry_id=="string"){if(a.openObjectQuickActions(t.entry_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}`);return}if(o==="edit-history"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"&&typeof t.original_timestamp=="string"){let d=document.querySelector("home-assistant")?.hass;if(!d)return;try{let u=(await d.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:t.entry_id})).tasks?.find(p=>p.id===t.task_id)?.history?.find(p=>p.timestamp===t.original_timestamp);if(!u)return;a.openHistoryEditDialog({entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.original_timestamp,type:u.type||"completed",timestamp:u.timestamp||t.original_timestamp,notes:u.notes??n Line truncated