291 files
This commit is contained in:
1 parent
c4e0178d8a
commit
280501d2e8
291 files changed
+32540
-3280
No files matched your search
+1
-1
@@ -1 +1 @@
|
||||
{"pid": 71, "version": 1, "ha_version": "2026.10.1", "start_ts": 1791844372.9210048}
|
||||
{"pid": 73, "version": 1, "ha_version": "2026.10.1", "start_ts": 1792001005.2570755}
|
||||
+37
-37
@@ -81,117 +81,117 @@
|
||||
},
|
||||
{
|
||||
"id": "88b90f2b1d6b45f0b44bee786ee1a525",
|
||||
"url": "/taskmate/taskmate-attr-resolver.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-attr-resolver.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "0796c92931dd458e81dc9c2677248274",
|
||||
"url": "/taskmate/taskmate-localize.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-localize.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "d2e281920ac7409583eafff1f1db69bd",
|
||||
"url": "/taskmate/taskmate-design.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-design.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "9eae9632f0734480be5edd784b030673",
|
||||
"url": "/taskmate/taskmate-badges-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-badges-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "5df49cd8a4eb420497b5df22cb31362c",
|
||||
"url": "/taskmate/taskmate-child-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-child-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "b44c87d0d74f468cb96c5eabc340f9ee",
|
||||
"url": "/taskmate/taskmate-rewards-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-rewards-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "787a96f9c30548708165a48457c99feb",
|
||||
"url": "/taskmate/taskmate-approvals-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-approvals-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "84031597de424ad68e7c2bc66d06b72e",
|
||||
"url": "/taskmate/taskmate-points-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-points-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "02613225844746b699bfbfac9642eca2",
|
||||
"url": "/taskmate/taskmate-reorder-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-reorder-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "7a06a07e17ba4b31b712bc91b77360b4",
|
||||
"url": "/taskmate/taskmate-overview-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-overview-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "08b42b53b33b4fa88db932455cf8d5aa",
|
||||
"url": "/taskmate/taskmate-activity-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-activity-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "15907eff51784acdba88ff694b574509",
|
||||
"url": "/taskmate/taskmate-streak-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-streak-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "1bd6bb5c0a6d4f0d916e3d82cb7fac39",
|
||||
"url": "/taskmate/taskmate-weekly-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-weekly-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "289ce5943f5a4972a593697db4c96ece",
|
||||
"url": "/taskmate/taskmate-graph-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-graph-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "d2904acee4c74a398dcc7b996c23e7e7",
|
||||
"url": "/taskmate/taskmate-reward-progress-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-reward-progress-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "46d378736fd54a26be253f2dfb27202e",
|
||||
"url": "/taskmate/taskmate-leaderboard-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-leaderboard-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "db11ae36457842fa826c7991e1d9c6f4",
|
||||
"url": "/taskmate/taskmate-parent-dashboard-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-parent-dashboard-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "ce85f301b59a412e9abfe5ffd51cb9a2",
|
||||
"url": "/taskmate/taskmate-penalties-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-penalties-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "1959e1629de2422daa8adaf87069c288",
|
||||
"url": "/taskmate/taskmate-bonuses-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-bonuses-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "2548524b269c4959bc7e0e967df943af",
|
||||
"url": "/taskmate/taskmate-points-display-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-points-display-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "36ada49368db4187a283fbbbef45454f",
|
||||
"url": "/taskmate/taskmate-calendar-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-calendar-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "67c32687acd2497b90030ef141f4b6db",
|
||||
"url": "/taskmate/taskmate-photo-gallery-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-photo-gallery-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "6f0c8348a91f4b74a9b846ab3f62621f",
|
||||
"url": "/taskmate/taskmate-family-goal-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-family-goal-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
@@ -276,7 +276,7 @@
|
||||
},
|
||||
{
|
||||
"id": "73dbd2de03de4530b451a55bfe6c46cf",
|
||||
"url": "/taskmate/taskmate-routine-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-routine-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
@@ -291,7 +291,7 @@
|
||||
},
|
||||
{
|
||||
"id": "1a4939ce1d2b47f89502176d3c5ac6e7",
|
||||
"url": "/taskmate/taskmate-sounds.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-sounds.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
@@ -306,32 +306,32 @@
|
||||
},
|
||||
{
|
||||
"id": "2cc757922cd142b69ce8844afc0e8410",
|
||||
"url": "/taskmate/taskmate-wishlist-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-wishlist-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "107319877a72413fbbea40b7f8adb06c",
|
||||
"url": "/taskmate/taskmate-kiosk-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-kiosk-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "5a2899c29e9046c78f060580ba113d9f",
|
||||
"url": "/taskmate/taskmate-bounty-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-bounty-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "a1aae7e334ba4c2d8dd3849178f780f6",
|
||||
"url": "/taskmate/taskmate-auction-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-auction-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "464b73198b7d4fe480c09bbf386a4e5d",
|
||||
"url": "/taskmate/taskmate-recap-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-recap-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "35f1f324116d4b589f3087065519360b",
|
||||
"url": "/taskmate/taskmate-chore-board-card.js?v=6.2.0",
|
||||
"url": "/taskmate/taskmate-chore-board-card.js?v=6.3.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
@@ -339,11 +339,6 @@
|
||||
"url": "/hacsfiles/Filament-Card/filament-card.js?hacstag=1290882685050",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "147a07760eec4fe69bd509064f81e3cd",
|
||||
"url": "/album_slideshow_static/album-slideshow-card.js?v=1.14.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "f9c46ac0dce64ee3bca668586145e4f0",
|
||||
"url": "/hacsfiles/lovelace-state-switch/state-switch.js?hacstag=158756598196",
|
||||
@@ -355,7 +350,12 @@
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "0d5a102183b74a2f9edb5b90dd664dcb",
|
||||
"id": "a1a494805ac84a78a6dba82b528ba900",
|
||||
"url": "/album_slideshow_static/album-slideshow-card.js?v=1.15.0",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
"id": "ec621063df614ae38f26b7c0c97d16fd",
|
||||
"url": "/climate_scheduler/static/climate-scheduler-card.js?v=1.15.1",
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -481,7 +481,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
return
|
||||
cam = data.get("camera")
|
||||
if cam:
|
||||
await cam.async_force_next()
|
||||
await cam.async_force_next(_displayed_frame_id(call))
|
||||
|
||||
async def _previous_slide(call) -> None:
|
||||
entry_id = call.data.get(ATTR_ENTRY_ID)
|
||||
@@ -492,7 +492,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
return
|
||||
cam = data.get("camera")
|
||||
if cam:
|
||||
await cam.async_force_prev()
|
||||
await cam.async_force_prev(_displayed_frame_id(call))
|
||||
|
||||
async def _refresh_album(call) -> None:
|
||||
entry_id = call.data.get(ATTR_ENTRY_ID)
|
||||
@@ -529,6 +529,12 @@ async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> Non
|
||||
await hass.config_entries.async_reload(entry.entry_id)
|
||||
|
||||
|
||||
def _displayed_frame_id(call) -> int | None:
|
||||
"""Optional frame a card is showing, so navigation starts from it."""
|
||||
frame_id = call.data.get("frame_id")
|
||||
return frame_id if type(frame_id) is int and frame_id >= 0 else None
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
if unload_ok:
|
||||
|
||||
@@ -2,8 +2,9 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections import OrderedDict, deque
|
||||
from dataclasses import dataclass, replace
|
||||
from dataclasses import dataclass, field, replace
|
||||
from datetime import datetime, timezone
|
||||
import itertools
|
||||
import logging
|
||||
import math
|
||||
import random
|
||||
@@ -64,6 +65,31 @@ _MAX_RENDER_ATTEMPTS = 10
|
||||
# a small percentage rounds down to zero.
|
||||
_PAIR_GAP_FLOOR = 2
|
||||
|
||||
# Recent frame IDs remembered so navigation can start from a card's displayed slide.
|
||||
_FRAME_ID_MEMORY = 64
|
||||
|
||||
# Store settings that change how slides look or which photos play. Changing any
|
||||
# of them discards rendered slides; other settings (interval, pause, buffer
|
||||
# size, cache size) keep the navigation history.
|
||||
_RENDER_SETTINGS = (
|
||||
"fill_mode",
|
||||
"portrait_mode",
|
||||
"order_mode",
|
||||
"shuffle_age_bias",
|
||||
"aspect_ratio",
|
||||
"pair_divider_px",
|
||||
"pair_divider_color",
|
||||
"pair_min_gap_percent",
|
||||
"max_resolution",
|
||||
"date_filter",
|
||||
"custom_lookback_days",
|
||||
"missing_date_mode",
|
||||
"face_debug",
|
||||
"hidden_revision",
|
||||
)
|
||||
|
||||
_next_frame_serial = itertools.count(1).__next__
|
||||
|
||||
|
||||
def _pair_exclusion_radius(n: int, min_gap_percent: float) -> int:
|
||||
"""Items to exclude on each side of the current index for pairing.
|
||||
@@ -100,6 +126,7 @@ class _RenderedFrame:
|
||||
data: bytes
|
||||
cursor: _NavigationCursor
|
||||
meta: dict
|
||||
serial: int = field(default_factory=_next_frame_serial, compare=False)
|
||||
|
||||
|
||||
def _ts_to_iso(ts_ms: int | None) -> str | None:
|
||||
@@ -125,6 +152,18 @@ def _camera_metadata_attributes(item: MediaItem | None) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _caption_frame(item: MediaItem | None) -> dict[str, Any]:
|
||||
"""Caption metadata for one photo of a slide."""
|
||||
return {
|
||||
"captured_at": _ts_to_iso(getattr(item, "captured_at", None)),
|
||||
"location": getattr(item, "location", None),
|
||||
"latitude": getattr(item, "latitude", None),
|
||||
"longitude": getattr(item, "longitude", None),
|
||||
"description": getattr(item, "description", None),
|
||||
**_camera_metadata_attributes(item),
|
||||
}
|
||||
|
||||
|
||||
def _item_faces(item: MediaItem | None) -> tuple[ip.FaceBox, ...] | None:
|
||||
"""Return the validated face boxes stored on a media item.
|
||||
|
||||
@@ -225,9 +264,6 @@ class AlbumSlideshowCamera(Camera):
|
||||
)
|
||||
self._recent_urls: list[str] = []
|
||||
self._last_is_portrait: bool | None = None
|
||||
# When the current frame is a paired image, this is [taken_a, taken_b]
|
||||
# ISO strings (top/left first); None for single frames.
|
||||
self._last_captured_at_pair: list[str | None] | None = None
|
||||
# Full per-half caption metadata for a paired frame: a list of two
|
||||
# dicts (top/left first) each carrying captured_at / location /
|
||||
# latitude / longitude. None for single frames. Lets the Lovelace
|
||||
@@ -247,6 +283,8 @@ class AlbumSlideshowCamera(Camera):
|
||||
# has an unambiguous "new frame ready" signal even when other
|
||||
# attributes happen not to change between slides.
|
||||
self._frame_id: int = 0
|
||||
# Recent frame IDs mapped to frame serials, oldest first.
|
||||
self._frame_serials: dict[int, int] = {}
|
||||
|
||||
self._interrupt_event: asyncio.Event = asyncio.Event()
|
||||
self._slide_deadline: float | None = None
|
||||
@@ -276,18 +314,31 @@ class AlbumSlideshowCamera(Camera):
|
||||
self._last_nav_error: str | None = None
|
||||
self._consecutive_failures: int = 0
|
||||
self._render_task: asyncio.Task | None = None
|
||||
self._render_settings = self._current_render_settings()
|
||||
|
||||
def _on_coordinator_update() -> None:
|
||||
previous_items = self._effective_cache[1] if self._effective_cache else None
|
||||
self._effective_cache = None
|
||||
self._invalidate_timeline()
|
||||
if self._keep_timeline(previous_items):
|
||||
self.async_write_ha_state()
|
||||
else:
|
||||
self._invalidate_timeline()
|
||||
|
||||
coordinator.async_add_listener(_on_coordinator_update)
|
||||
|
||||
def _on_store_change() -> None:
|
||||
self._download_cache.resize(self.store.image_cache_mb * 1024 * 1024)
|
||||
self._effective_cache = None
|
||||
self._slide_deadline = None
|
||||
self._invalidate_timeline()
|
||||
settings = self._current_render_settings()
|
||||
if settings != self._render_settings:
|
||||
self._render_settings = settings
|
||||
self._effective_cache = None
|
||||
self._invalidate_timeline()
|
||||
return
|
||||
# Interval, pause and buffer changes keep the rendered slides.
|
||||
self._schedule_preload()
|
||||
self._interrupt_event.set()
|
||||
self.async_write_ha_state()
|
||||
|
||||
store.add_listener(_on_store_change)
|
||||
|
||||
@@ -344,7 +395,11 @@ class AlbumSlideshowCamera(Camera):
|
||||
items: list[MediaItem] = self._effective_items()
|
||||
cur = items[self._index] if items and 0 <= self._index < len(items) else None
|
||||
captured_at = _ts_to_iso(getattr(cur, "captured_at", None))
|
||||
captured_at_pair = self._last_captured_at_pair
|
||||
caption_frames = self._caption_frames(cur)
|
||||
captured_at_pair = (
|
||||
[frame["captured_at"] for frame in caption_frames]
|
||||
if self._last_pair_frames else None
|
||||
)
|
||||
return {
|
||||
"entry_id": self.entry.entry_id,
|
||||
"displayed_photo_ids": (
|
||||
@@ -389,7 +444,7 @@ class AlbumSlideshowCamera(Camera):
|
||||
# so the card can overlay an accurate date/location on each half.
|
||||
# ``pair_orientation`` tells the card how the two halves are laid
|
||||
# out: ``horizontal`` (left/right) or ``vertical`` (top/bottom).
|
||||
"caption_frames": self._caption_frames(cur, captured_at),
|
||||
"caption_frames": caption_frames,
|
||||
"pair_orientation": self._last_pair_orientation,
|
||||
"slide_interval": int(self.store.slide_interval),
|
||||
"fill_mode": self.store.fill_mode,
|
||||
@@ -422,7 +477,7 @@ class AlbumSlideshowCamera(Camera):
|
||||
"pagination_debug": data.get("pagination_debug"),
|
||||
}
|
||||
|
||||
def _caption_frames(self, cur, captured_at: str | None) -> list[dict]:
|
||||
def _caption_frames(self, cur) -> list[dict]:
|
||||
"""Per-image caption metadata for the current slide.
|
||||
|
||||
Returns a list with one dict for a normal slide, or two (top/left
|
||||
@@ -430,18 +485,21 @@ class AlbumSlideshowCamera(Camera):
|
||||
string or ``None``), ``location`` (human label or ``None``), and
|
||||
``latitude`` / ``longitude``. The card reads this to overlay an
|
||||
accurate caption on each image, including each half of a pair.
|
||||
Paired captions are read from the live items so metadata found after
|
||||
the slide was rendered still shows.
|
||||
"""
|
||||
if self._last_pair_frames:
|
||||
if not self._last_pair_frames:
|
||||
return [_caption_frame(cur)]
|
||||
photo_ids = self._current_frame.meta.get("photo_ids", []) if self._current_frame else []
|
||||
if len(photo_ids) != len(self._last_pair_frames):
|
||||
return self._last_pair_frames
|
||||
live = {
|
||||
item.photo_id: item for item in self._effective_items()
|
||||
if item.photo_id and item.photo_id in photo_ids
|
||||
}
|
||||
return [
|
||||
{
|
||||
"captured_at": captured_at,
|
||||
"location": getattr(cur, "location", None),
|
||||
"latitude": getattr(cur, "latitude", None),
|
||||
"longitude": getattr(cur, "longitude", None),
|
||||
"description": getattr(cur, "description", None),
|
||||
**_camera_metadata_attributes(cur),
|
||||
}
|
||||
_caption_frame(live[photo_id]) if photo_id in live else frame
|
||||
for photo_id, frame in zip(photo_ids, self._last_pair_frames)
|
||||
]
|
||||
|
||||
@property
|
||||
@@ -496,15 +554,19 @@ class AlbumSlideshowCamera(Camera):
|
||||
self._effective_cache = (hash(cache_key), ordered)
|
||||
return ordered
|
||||
|
||||
async def async_force_next(self) -> None:
|
||||
"""Display the next buffered slide immediately."""
|
||||
await self._async_navigate(1)
|
||||
async def async_force_next(self, frame_id: int | None = None) -> None:
|
||||
"""Display the next buffered slide immediately.
|
||||
|
||||
async def async_force_prev(self) -> None:
|
||||
``frame_id`` is the frame a card is showing; when it is still retained,
|
||||
the step starts from that slide rather than the camera's latest one.
|
||||
"""
|
||||
await self._async_navigate(1, frame_id)
|
||||
|
||||
async def async_force_prev(self, frame_id: int | None = None) -> None:
|
||||
"""Display the previous retained slide immediately."""
|
||||
await self._async_navigate(-1)
|
||||
await self._async_navigate(-1, frame_id)
|
||||
|
||||
async def _async_navigate(self, direction: int) -> None:
|
||||
async def _async_navigate(self, direction: int, frame_id: int | None = None) -> None:
|
||||
"""Serialise a manual navigation request and execute it directly."""
|
||||
direction_name = "next" if direction > 0 else "previous"
|
||||
self._navigation_pending += 1
|
||||
@@ -522,11 +584,15 @@ class AlbumSlideshowCamera(Camera):
|
||||
self._last_nav_started_at = _utc_now_iso()
|
||||
if self._timeline_dirty:
|
||||
await self._rebuild_current_frame()
|
||||
rewound = self._rewind_to_displayed(frame_id)
|
||||
changed = (
|
||||
await self._show_next_frame()
|
||||
if direction > 0
|
||||
else await self._show_previous_frame()
|
||||
)
|
||||
if not changed and rewound:
|
||||
# Nothing older than the displayed slide: stay on it.
|
||||
self._apply_frame(self._current_frame)
|
||||
if changed:
|
||||
self._last_nav_committed_at = _utc_now_iso()
|
||||
self._last_nav_outcome = "displayed"
|
||||
@@ -678,6 +744,7 @@ class AlbumSlideshowCamera(Camera):
|
||||
"captured_at_pair": None,
|
||||
"pair_frames": None,
|
||||
"pair_orientation": None,
|
||||
"faces": faces[half:half + 1] if (faces := frame.meta.get("faces")) else None,
|
||||
}
|
||||
self._timeline_dirty = False
|
||||
self._apply_frame(_RenderedFrame(encoded, cursor, meta))
|
||||
@@ -693,7 +760,6 @@ class AlbumSlideshowCamera(Camera):
|
||||
self._framebuffer = None
|
||||
self.store.last_frame = None
|
||||
self._last_is_portrait = None
|
||||
self._last_captured_at_pair = None
|
||||
self._last_pair_frames = None
|
||||
self._last_pair_orientation = None
|
||||
|
||||
@@ -809,6 +875,8 @@ class AlbumSlideshowCamera(Camera):
|
||||
composed, meta = await renderer._compose_for_index(items)
|
||||
meta = dict(meta or {})
|
||||
meta.setdefault("photo_ids", [getattr(items[renderer._index], "photo_id", None)])
|
||||
# Faces used for the crop, so later face data can be detected.
|
||||
meta.setdefault("faces", (_item_faces(items[renderer._index]),))
|
||||
cursor = self._capture_cursor(renderer)
|
||||
if composed is None:
|
||||
raise RuntimeError("Image composition returned no frame")
|
||||
@@ -845,10 +913,12 @@ class AlbumSlideshowCamera(Camera):
|
||||
|
||||
meta = frame.meta
|
||||
self._last_is_portrait = meta.get("is_portrait")
|
||||
self._last_captured_at_pair = meta.get("captured_at_pair")
|
||||
self._last_pair_frames = meta.get("pair_frames")
|
||||
self._last_pair_orientation = meta.get("pair_orientation")
|
||||
self._frame_id += 1
|
||||
self._frame_serials[self._frame_id] = frame.serial
|
||||
while len(self._frame_serials) > _FRAME_ID_MEMORY:
|
||||
del self._frame_serials[next(iter(self._frame_serials))]
|
||||
|
||||
_LOGGER.debug(
|
||||
"Album Slideshow %s: displayed buffered frame_id=%d index=%d "
|
||||
@@ -886,6 +956,84 @@ class AlbumSlideshowCamera(Camera):
|
||||
self._interrupt_event.set()
|
||||
self.async_write_ha_state()
|
||||
|
||||
def _current_render_settings(self) -> tuple:
|
||||
return tuple(getattr(self.store, name) for name in _RENDER_SETTINGS)
|
||||
|
||||
def _keep_timeline(self, previous_items: list[MediaItem] | None) -> bool:
|
||||
"""Keep rendered slides that are still valid after a coordinator update.
|
||||
|
||||
Metadata-only updates (dates, places, captions) keep every slide. If the
|
||||
playlist itself changed, slides already shown are kept and re-anchored
|
||||
to their new positions, and upcoming slides are rendered again. Returns
|
||||
False when the timeline has to be rebuilt instead.
|
||||
"""
|
||||
current = self._current_frame
|
||||
if current is None or self._timeline_dirty or self._navigation_lock.locked():
|
||||
return False
|
||||
items = self._effective_items()
|
||||
found = {item.photo_id: (index, item) for index, item in enumerate(items) if item.photo_id}
|
||||
|
||||
def faces_changed(frame: _RenderedFrame) -> bool:
|
||||
recorded = frame.meta.get("faces")
|
||||
photo_ids = frame.meta.get("photo_ids") or []
|
||||
return (
|
||||
recorded is not None
|
||||
and all(photo_id in found for photo_id in photo_ids)
|
||||
and recorded != tuple(_item_faces(found[photo_id][1]) for photo_id in photo_ids)
|
||||
)
|
||||
|
||||
if previous_items is not None and [
|
||||
item.photo_id or item.url for item in previous_items
|
||||
] == [item.photo_id or item.url for item in items]:
|
||||
return not any(
|
||||
faces_changed(frame)
|
||||
for frame in (*self._previous_frames, current, *self._next_frames)
|
||||
)
|
||||
|
||||
def remap(frame: _RenderedFrame) -> _RenderedFrame | None:
|
||||
photo_ids = frame.meta.get("photo_ids") or []
|
||||
if not photo_ids or any(photo_id not in found for photo_id in photo_ids) or faces_changed(frame):
|
||||
return None
|
||||
return replace(frame, cursor=replace(frame.cursor, index=found[photo_ids[0]][0]))
|
||||
|
||||
current = remap(current)
|
||||
if current is None:
|
||||
return False
|
||||
previous = [frame for frame in map(remap, self._previous_frames) if frame is not None]
|
||||
self._timeline_generation += 1
|
||||
self._cancel_preload()
|
||||
self._previous_frames.clear()
|
||||
self._previous_frames.extend(previous)
|
||||
self._next_frames.clear()
|
||||
self._current_frame = current
|
||||
self._index = current.cursor.index
|
||||
self._schedule_preload()
|
||||
return True
|
||||
|
||||
def _rewind_to_displayed(self, frame_id: int | None) -> bool:
|
||||
"""Make the retained slide a card is still showing the current one.
|
||||
|
||||
A card holds its photo while its controls are open, so the camera may
|
||||
already be further ahead. Navigation then starts from what is on screen.
|
||||
"""
|
||||
serial = self._frame_serials.get(frame_id) if frame_id is not None else None
|
||||
current = self._current_frame
|
||||
if serial is None or current is None or current.serial == serial:
|
||||
return False
|
||||
timeline = [*self._previous_frames, current, *self._next_frames]
|
||||
position = next(
|
||||
(index for index, frame in enumerate(timeline) if frame.serial == serial),
|
||||
None,
|
||||
)
|
||||
if position is None:
|
||||
return False
|
||||
self._previous_frames.clear()
|
||||
self._previous_frames.extend(timeline[:position])
|
||||
self._next_frames.clear()
|
||||
self._next_frames.extend(timeline[position + 1:])
|
||||
self._current_frame = timeline[position]
|
||||
return True
|
||||
|
||||
def _schedule_preload(self) -> None:
|
||||
"""Start the single per-camera worker that fills future frames."""
|
||||
self._trim_timeline()
|
||||
@@ -1255,24 +1403,7 @@ class AlbumSlideshowCamera(Camera):
|
||||
is_portrait_canvas, divider, divider_fill, transparent_divider,
|
||||
self._crop_hints(cur), self._crop_hints(other_item),
|
||||
)
|
||||
pair_frames = [
|
||||
{
|
||||
"captured_at": _ts_to_iso(getattr(cur, "captured_at", None)),
|
||||
"location": getattr(cur, "location", None),
|
||||
"latitude": getattr(cur, "latitude", None),
|
||||
"longitude": getattr(cur, "longitude", None),
|
||||
"description": getattr(cur, "description", None),
|
||||
**_camera_metadata_attributes(cur),
|
||||
},
|
||||
{
|
||||
"captured_at": _ts_to_iso(getattr(other_item, "captured_at", None)),
|
||||
"location": getattr(other_item, "location", None),
|
||||
"latitude": getattr(other_item, "latitude", None),
|
||||
"longitude": getattr(other_item, "longitude", None),
|
||||
"description": getattr(other_item, "description", None),
|
||||
**_camera_metadata_attributes(other_item),
|
||||
},
|
||||
]
|
||||
pair_frames = [_caption_frame(cur), _caption_frame(other_item)]
|
||||
pair_meta = [f["captured_at"] for f in pair_frames]
|
||||
else:
|
||||
composed = await self._async_image_job(
|
||||
@@ -1285,6 +1416,10 @@ class AlbumSlideshowCamera(Camera):
|
||||
[getattr(cur, "photo_id", None), getattr(other_item, "photo_id", None)]
|
||||
if pair_frames else [getattr(cur, "photo_id", None)]
|
||||
),
|
||||
"faces": (
|
||||
(_item_faces(cur), _item_faces(other_item))
|
||||
if pair_frames else (_item_faces(cur),)
|
||||
),
|
||||
"is_portrait": cur_is_portrait,
|
||||
"captured_at_pair": pair_meta,
|
||||
"pair_frames": pair_frames,
|
||||
|
||||
@@ -29,6 +29,8 @@ from .const import (
|
||||
CONF_MEDIA_CONTENT_ID,
|
||||
CONF_RECURSIVE,
|
||||
CONF_REVERSE_GEOCODE,
|
||||
CONF_HIDE_HOME_COUNTRY,
|
||||
DEFAULT_HIDE_HOME_COUNTRY,
|
||||
CONF_IMMICH_URL,
|
||||
CONF_IMMICH_API_KEY,
|
||||
CONF_IMMICH_SELECTION_TYPE,
|
||||
@@ -1509,6 +1511,7 @@ class GoogleOptionsFlow(config_entries.OptionsFlow):
|
||||
CONF_GOOGLE_METADATA: DEFAULT_GOOGLE_METADATA,
|
||||
CONF_GOOGLE_LOCATION: DEFAULT_GOOGLE_LOCATION,
|
||||
CONF_REVERSE_GEOCODE: DEFAULT_GOOGLE_REVERSE_GEOCODE,
|
||||
CONF_HIDE_HOME_COUNTRY: DEFAULT_HIDE_HOME_COUNTRY,
|
||||
}
|
||||
if user_input is not None:
|
||||
options = {
|
||||
@@ -1531,9 +1534,9 @@ class GoogleOptionsFlow(config_entries.OptionsFlow):
|
||||
class LocalFolderOptionsFlow(config_entries.OptionsFlow):
|
||||
"""Options for local-folder entries.
|
||||
|
||||
Currently exposes a single toggle: ``reverse_geocode``. Users with
|
||||
Exposes the ``reverse_geocode`` toggle and ``hide_home_country``. Users with
|
||||
privacy concerns about handing EXIF GPS coordinates to an external
|
||||
OSM endpoint can turn this off; the GPS coordinates remain available
|
||||
OSM endpoint can turn geocoding off; the GPS coordinates remain available
|
||||
as ``latitude``/``longitude`` attributes regardless.
|
||||
|
||||
``self.config_entry`` is provided by ``OptionsFlow`` as a managed
|
||||
@@ -1550,11 +1553,17 @@ class LocalFolderOptionsFlow(config_entries.OptionsFlow):
|
||||
current = self.config_entry.options.get(
|
||||
CONF_REVERSE_GEOCODE, DEFAULT_REVERSE_GEOCODE
|
||||
)
|
||||
hide_home = self.config_entry.options.get(
|
||||
CONF_HIDE_HOME_COUNTRY, DEFAULT_HIDE_HOME_COUNTRY
|
||||
)
|
||||
schema = vol.Schema(
|
||||
{
|
||||
vol.Required(
|
||||
CONF_REVERSE_GEOCODE, default=bool(current)
|
||||
): bool,
|
||||
vol.Required(
|
||||
CONF_HIDE_HOME_COUNTRY, default=bool(hide_home)
|
||||
): bool,
|
||||
}
|
||||
)
|
||||
return self.async_show_form(step_id="init", data_schema=schema)
|
||||
@@ -1684,6 +1693,10 @@ class ImmichOptionsFlow(config_entries.OptionsFlow):
|
||||
CONF_REVERSE_GEOCODE,
|
||||
entry.options.get(CONF_REVERSE_GEOCODE, DEFAULT_REVERSE_GEOCODE),
|
||||
),
|
||||
CONF_HIDE_HOME_COUNTRY: user_input.get(
|
||||
CONF_HIDE_HOME_COUNTRY,
|
||||
entry.options.get(CONF_HIDE_HOME_COUNTRY, DEFAULT_HIDE_HOME_COUNTRY),
|
||||
),
|
||||
}
|
||||
self.hass.config_entries.async_update_entry(
|
||||
entry, data=new_data, title=fields[CONF_ALBUM_NAME], options=options
|
||||
@@ -1705,6 +1718,9 @@ class ImmichOptionsFlow(config_entries.OptionsFlow):
|
||||
vol.Required(CONF_REVERSE_GEOCODE, default=bool(entry.options.get(
|
||||
CONF_REVERSE_GEOCODE, DEFAULT_REVERSE_GEOCODE,
|
||||
))): bool,
|
||||
vol.Required(CONF_HIDE_HOME_COUNTRY, default=bool(entry.options.get(
|
||||
CONF_HIDE_HOME_COUNTRY, DEFAULT_HIDE_HOME_COUNTRY,
|
||||
))): bool,
|
||||
})
|
||||
return self.async_show_form(
|
||||
step_id="immich_select",
|
||||
|
||||
@@ -65,6 +65,10 @@ DEFAULT_IMMICH_IMAGE_SIZE = IMMICH_IMAGE_PREVIEW
|
||||
# integration's options dialog.
|
||||
CONF_REVERSE_GEOCODE = "reverse_geocode"
|
||||
DEFAULT_REVERSE_GEOCODE = True
|
||||
# Leave the country out of OpenStreetMap place names when it matches Home
|
||||
# Assistant's configured country.
|
||||
CONF_HIDE_HOME_COUNTRY = "hide_home_country"
|
||||
DEFAULT_HIDE_HOME_COUNTRY = False
|
||||
|
||||
PROVIDER_GOOGLE_SHARED = "google_shared"
|
||||
PROVIDER_LOCAL_FOLDER = "local_folder"
|
||||
|
||||
@@ -34,6 +34,8 @@ from .const import (
|
||||
CONF_MEDIA_CONTENT_ID,
|
||||
CONF_RECURSIVE,
|
||||
CONF_REVERSE_GEOCODE,
|
||||
CONF_HIDE_HOME_COUNTRY,
|
||||
DEFAULT_HIDE_HOME_COUNTRY,
|
||||
CONF_IMMICH_URL,
|
||||
CONF_IMMICH_API_KEY,
|
||||
CONF_IMMICH_SELECTION_TYPE,
|
||||
@@ -157,6 +159,9 @@ class MediaItem:
|
||||
face_scanned: bool = False
|
||||
camera_metadata: dict[str, Any] | None = None
|
||||
google_location_scanned: bool = False
|
||||
# True when ``location`` came from our OpenStreetMap lookup rather than
|
||||
# the provider, so it can be re-formatted from the place cache.
|
||||
location_geocoded: bool = False
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.photo_id is None:
|
||||
@@ -483,6 +488,22 @@ _HEIF_EXIF_RE = re.compile(rb"Exif\x00\x00(?:MM\x00\x2a|II\x2a\x00)")
|
||||
_NOMINATIM_ENDPOINT = "https://nominatim.openstreetmap.org/reverse"
|
||||
_NOMINATIM_MIN_INTERVAL_S = 1.1
|
||||
_NOMINATIM_TIMEOUT_S = 20
|
||||
# Next free request time, shared so several albums together stay within the limit.
|
||||
_nominatim_next_slot = 0.0
|
||||
|
||||
# Nominatim address parts used for place labels, most specific first.
|
||||
_LOCALITY_KEYS = (
|
||||
"city", "town", "village", "hamlet", "city_district", "suburb", "municipality",
|
||||
)
|
||||
_REGION_KEYS = ("state", "province", "region")
|
||||
_ADDRESS_KEYS = (*_LOCALITY_KEYS, *_REGION_KEYS, "country", "country_code")
|
||||
_PLACE_KEYS = (*_ADDRESS_KEYS, "display_name")
|
||||
# Administrative prefixes some areas carry in OpenStreetMap, longest first.
|
||||
_NAME_PREFIXES = (
|
||||
"regional municipality of ", "rural municipality of ", "municipal district of ",
|
||||
"municipality of ", "township of ", "district of ", "borough of ",
|
||||
"village of ", "town of ", "city of ",
|
||||
)
|
||||
|
||||
# How many EXIF reads to perform between cache flushes. Bigger batches
|
||||
# mean fewer Store writes but more rework if HA is killed mid-scan.
|
||||
@@ -882,41 +903,68 @@ def _jpeg_exif_segment(data: bytes) -> bytes | None:
|
||||
raise ValueError("JPEG header ends before image data")
|
||||
|
||||
|
||||
def _format_nominatim_location(payload: dict[str, Any]) -> str | None:
|
||||
"""Turn a Nominatim reverse-geocode response into a short label.
|
||||
def _place_name(value: Any) -> str | None:
|
||||
"""A town or city name without prefixes like "City of"; parishes don't count."""
|
||||
if not isinstance(value, str) or not value.strip():
|
||||
return None
|
||||
name = value.strip()
|
||||
folded = name.casefold()
|
||||
if folded.endswith(" parish") or folded.startswith("parish of "):
|
||||
return None
|
||||
for prefix in _NAME_PREFIXES:
|
||||
if folded.startswith(prefix) and len(name) > len(prefix):
|
||||
return name[len(prefix):].strip()
|
||||
return name
|
||||
|
||||
Prefers ``city`` > ``town`` > ``village`` > ``municipality`` >
|
||||
``county`` for the locality portion, plus ``country`` when present.
|
||||
Falls back to Nominatim's pre-formatted ``display_name`` (truncated
|
||||
to the first two comma-separated parts) when no recognisable
|
||||
locality fields are present.
|
||||
|
||||
def _nominatim_place(payload: Any) -> dict[str, str] | None:
|
||||
"""Keep the parts of a Nominatim reverse-geocode response that labels use.
|
||||
|
||||
Caching these instead of a finished label lets label options change
|
||||
without new lookups.
|
||||
"""
|
||||
if not isinstance(payload, dict):
|
||||
return None
|
||||
address = payload.get("address") if isinstance(payload.get("address"), dict) else {}
|
||||
locality = None
|
||||
for key in ("city", "town", "village", "hamlet", "municipality", "county", "state"):
|
||||
val = address.get(key)
|
||||
if isinstance(val, str) and val.strip():
|
||||
locality = val.strip()
|
||||
break
|
||||
country = address.get("country") if isinstance(address.get("country"), str) else None
|
||||
|
||||
if locality and country:
|
||||
return f"{locality}, {country}"
|
||||
if locality:
|
||||
return locality
|
||||
if isinstance(country, str) and country.strip():
|
||||
return country.strip()
|
||||
|
||||
place = {
|
||||
key: value.strip()
|
||||
for key in _ADDRESS_KEYS
|
||||
if isinstance(value := address.get(key), str) and value.strip()
|
||||
}
|
||||
display = payload.get("display_name")
|
||||
if isinstance(display, str) and display.strip():
|
||||
parts = [p.strip() for p in display.split(",") if p.strip()]
|
||||
if len(parts) >= 2:
|
||||
return ", ".join(parts[:2])
|
||||
if parts:
|
||||
return parts[0]
|
||||
return None
|
||||
if not place and isinstance(display, str) and display.strip():
|
||||
place["display_name"] = display.strip()
|
||||
return place or None
|
||||
|
||||
|
||||
def _format_place(place: dict[str, str], home_country: str | None = None) -> str | None:
|
||||
"""Short label such as ``"Lisbon, Portugal"`` from cached address parts.
|
||||
|
||||
Uses the town or city, else the province/state, then the country, which
|
||||
is left out when its code matches ``home_country``.
|
||||
"""
|
||||
area = next(
|
||||
(name for key in _LOCALITY_KEYS if (name := _place_name(place.get(key)))), None
|
||||
) or next((place[key] for key in _REGION_KEYS if place.get(key)), None)
|
||||
country = place.get("country")
|
||||
if home_country and place.get("country_code", "").upper() == home_country.upper():
|
||||
country = None
|
||||
parts = [part for part in (area, country) if part]
|
||||
if len(parts) == 2 and parts[0].casefold() == parts[1].casefold():
|
||||
parts.pop()
|
||||
if parts:
|
||||
return ", ".join(parts)
|
||||
shown = [part.strip() for part in place.get("display_name", "").split(",") if part.strip()]
|
||||
return ", ".join(shown[:2]) or None
|
||||
|
||||
|
||||
async def _wait_for_nominatim_slot() -> None:
|
||||
global _nominatim_next_slot
|
||||
now = asyncio.get_running_loop().time()
|
||||
slot = max(now, _nominatim_next_slot)
|
||||
_nominatim_next_slot = slot + _NOMINATIM_MIN_INTERVAL_S
|
||||
if slot > now:
|
||||
await asyncio.sleep(slot - now)
|
||||
|
||||
|
||||
async def _nominatim_lookup(
|
||||
@@ -924,18 +972,21 @@ async def _nominatim_lookup(
|
||||
lat: float,
|
||||
lon: float,
|
||||
user_agent: str,
|
||||
) -> str | None:
|
||||
) -> dict[str, str] | None:
|
||||
"""Reverse-geocode a coordinate pair via Nominatim.
|
||||
|
||||
Returns a human-readable label or ``None`` if the lookup failed or
|
||||
the response had no useful address. Never raises - geocoding is
|
||||
best-effort and a failure must never stop the slideshow.
|
||||
Returns the cached address parts (see :func:`_nominatim_place`) or
|
||||
``None`` if the lookup failed or the response had no useful address.
|
||||
Never raises - geocoding is best-effort and a failure must never stop
|
||||
the slideshow.
|
||||
"""
|
||||
params = {
|
||||
"format": "jsonv2",
|
||||
"lat": f"{lat:.5f}",
|
||||
"lon": f"{lon:.5f}",
|
||||
"zoom": "10", # Roughly city-level - we don't need street precision.
|
||||
# Neighbourhood level: coarser levels can return an administrative
|
||||
# area such as a parish instead of the town.
|
||||
"zoom": "14",
|
||||
"addressdetails": "1",
|
||||
}
|
||||
headers = {
|
||||
@@ -969,7 +1020,7 @@ async def _nominatim_lookup(
|
||||
_LOGGER.debug("Nominatim lookup failed (%s, %s): %s", lat, lon, err)
|
||||
return None
|
||||
|
||||
return _format_nominatim_location(payload)
|
||||
return _nominatim_place(payload)
|
||||
|
||||
|
||||
def _read_manifest_version(integration_dir: Path) -> str:
|
||||
@@ -1061,6 +1112,7 @@ def _merge_prior_enrichment(
|
||||
item.longitude = prev.longitude
|
||||
if prev.location and not item.location:
|
||||
item.location = prev.location
|
||||
item.location_geocoded = prev.location_geocoded
|
||||
if prev.description and not item.description:
|
||||
item.description = prev.description
|
||||
if prev.faces is not None and item.faces is None:
|
||||
@@ -1126,15 +1178,19 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
self._items_cache_loaded: bool = False
|
||||
|
||||
# Reverse-geocode cache. Coordinates rounded to ~100 m via
|
||||
# ``_geocode_cache_key``; mapping value -> label string. Shared
|
||||
# across all items in the album, persisted independently of the
|
||||
# items cache so changes to one don't invalidate the other.
|
||||
# ``_geocode_cache_key``; mapping value -> Nominatim address parts
|
||||
# (see ``_nominatim_place``). Shared across all items in the album,
|
||||
# persisted independently of the items cache so changes to one don't
|
||||
# invalidate the other.
|
||||
self._geocode_cache_store: Store = Store(
|
||||
hass,
|
||||
self._GEOCODE_CACHE_VERSION,
|
||||
f"{DOMAIN}.{entry.entry_id}.geocode",
|
||||
)
|
||||
self._geocode_cache: dict[str, str] = {}
|
||||
self._geocode_cache: dict[str, dict[str, str]] = {}
|
||||
# Finished labels from the older label-only cache, kept until each
|
||||
# coordinate has been looked up again.
|
||||
self._geocode_legacy: dict[str, str] = {}
|
||||
self._geocode_cache_loaded: bool = False
|
||||
# Per-coordinator User-Agent so OSM operators can track us if we
|
||||
# ever misbehave. Resolved lazily because __init__ is sync.
|
||||
@@ -1224,16 +1280,28 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
item.latitude = previous.latitude
|
||||
item.longitude = previous.longitude
|
||||
item.location = previous.location
|
||||
item.location_geocoded = previous.location_geocoded
|
||||
item.google_location_scanned = True
|
||||
self._apply_google_location_privacy(items)
|
||||
await self._relabel_from_place_cache(items)
|
||||
self._schedule_enrichment(data)
|
||||
elif self.provider in ENRICHING_PROVIDERS and items:
|
||||
# Carry forward EXIF/geocode metadata for items we've already
|
||||
# scanned this session; new items get filled in by the
|
||||
# background worker below.
|
||||
prior_items = (self.data or {}).get("items") if isinstance(self.data, dict) else None
|
||||
# scanned, this session or (after a restart) in the items cache
|
||||
# on disk; new items get filled in by the background worker
|
||||
# below. Session items come last so they win over the cache.
|
||||
prior_items = list((self.data or {}).get("items") or []) if isinstance(self.data, dict) else []
|
||||
if not self._items_cache_loaded:
|
||||
cached = await self._load_cached_items()
|
||||
prior_items = (cached or {}).get("items", []) + prior_items
|
||||
self._items_cache_loaded = True
|
||||
if prior_items:
|
||||
_merge_prior_enrichment(items, prior_items)
|
||||
_LOGGER.debug(
|
||||
"Album cache: %d of %d items already have their details",
|
||||
sum(1 for it in items if not self._needs_enrichment(it)), len(items),
|
||||
)
|
||||
await self._relabel_from_place_cache(items)
|
||||
self._schedule_enrichment(data)
|
||||
|
||||
if items:
|
||||
@@ -1294,9 +1362,71 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
item.latitude = None
|
||||
item.longitude = None
|
||||
item.location = None
|
||||
item.location_geocoded = False
|
||||
item.google_location_scanned = False
|
||||
elif not self.google_reverse_geocode_enabled:
|
||||
item.location = None
|
||||
item.location_geocoded = False
|
||||
|
||||
@property
|
||||
def reverse_geocode_enabled(self) -> bool:
|
||||
if getattr(self, "provider", None) == PROVIDER_GOOGLE_SHARED:
|
||||
return self.google_reverse_geocode_enabled
|
||||
options = getattr(getattr(self, "entry", None), "options", None) or {}
|
||||
return bool(options.get(CONF_REVERSE_GEOCODE, DEFAULT_REVERSE_GEOCODE))
|
||||
|
||||
@property
|
||||
def _hidden_home_country(self) -> str | None:
|
||||
"""Country code to leave out of place labels, if the user asked for that."""
|
||||
options = getattr(getattr(self, "entry", None), "options", None) or {}
|
||||
if not options.get(CONF_HIDE_HOME_COUNTRY, DEFAULT_HIDE_HOME_COUNTRY):
|
||||
return None
|
||||
return getattr(getattr(self.hass, "config", None), "country", None) or None
|
||||
|
||||
def _needs_geocode_lookup(self, item: MediaItem) -> bool:
|
||||
"""True for items with GPS whose place isn't cached yet."""
|
||||
if item.latitude is None or item.longitude is None:
|
||||
return False
|
||||
if item.location and not item.location_geocoded:
|
||||
return False # The provider's own label.
|
||||
return _geocode_cache_key(item.latitude, item.longitude) not in self._geocode_cache
|
||||
|
||||
def _label_items_from_geocode_cache(self, items: list[MediaItem]) -> int:
|
||||
"""Set OpenStreetMap labels from cached places; return how many changed.
|
||||
|
||||
Labels from the older label-only cache are adopted as ours, so they
|
||||
stay visible until a new lookup replaces them.
|
||||
"""
|
||||
home = self._hidden_home_country
|
||||
changed = 0
|
||||
for item in items:
|
||||
if item.latitude is None or item.longitude is None:
|
||||
continue
|
||||
key = _geocode_cache_key(item.latitude, item.longitude)
|
||||
legacy = self._geocode_legacy.get(key)
|
||||
if item.location and not item.location_geocoded:
|
||||
if item.location != legacy:
|
||||
continue
|
||||
item.location_geocoded = True
|
||||
place = self._geocode_cache.get(key)
|
||||
if place is None:
|
||||
if legacy and not item.location:
|
||||
item.location, item.location_geocoded = legacy, True
|
||||
changed += 1
|
||||
continue
|
||||
label = _format_place(place, home)
|
||||
if label != item.location or not item.location_geocoded:
|
||||
item.location, item.location_geocoded = label, True
|
||||
changed += 1
|
||||
return changed
|
||||
|
||||
async def _relabel_from_place_cache(self, items: list[MediaItem]) -> None:
|
||||
"""Apply current label options to known places without new lookups."""
|
||||
if self.reverse_geocode_enabled and any(
|
||||
it.latitude is not None and it.longitude is not None for it in items
|
||||
):
|
||||
await self._ensure_geocode_cache_loaded()
|
||||
self._label_items_from_geocode_cache(items)
|
||||
|
||||
def _needs_enrichment(self, item: MediaItem) -> bool:
|
||||
if self.provider == PROVIDER_GOOGLE_SHARED:
|
||||
@@ -1313,11 +1443,8 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
unscanned = [it for it in items if self._needs_enrichment(it)]
|
||||
# Providers that decrypt/return GPS inline (Ente) have nothing to scan
|
||||
# but still need the coordinates turned into a place label.
|
||||
needs_geocode = (
|
||||
self.provider != PROVIDER_GOOGLE_SHARED or self.google_reverse_geocode_enabled
|
||||
) and any(
|
||||
it.latitude is not None and it.longitude is not None and not it.location
|
||||
for it in items
|
||||
needs_geocode = self.reverse_geocode_enabled and any(
|
||||
self._needs_geocode_lookup(it) for it in items
|
||||
)
|
||||
if not unscanned and not needs_geocode:
|
||||
# Even with nothing to do, mark the phase as ``done`` so the
|
||||
@@ -1330,7 +1457,12 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
"geocode_total": 0,
|
||||
"geocode_done": 0,
|
||||
}
|
||||
_LOGGER.debug("Album enrichment: all %d items have their details", len(items))
|
||||
return
|
||||
_LOGGER.debug(
|
||||
"Album enrichment: starting background pass for %d of %d items%s",
|
||||
len(unscanned), len(items), " plus place names" if needs_geocode else "",
|
||||
)
|
||||
self._enrich_progress = {
|
||||
"phase": "exif",
|
||||
"exif_total": len(items),
|
||||
@@ -1351,14 +1483,17 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
_LOGGER.debug("Album cache: failed to load (%s)", err)
|
||||
return None
|
||||
if not isinstance(payload, dict):
|
||||
_LOGGER.debug("Album cache: nothing saved yet")
|
||||
return None
|
||||
|
||||
cached_source = payload.get("immich_source")
|
||||
if cached_source is not None and cached_source != getattr(self, "_immich_cache_source", None):
|
||||
_LOGGER.debug("Album cache: ignoring saved items, the Immich source changed")
|
||||
return None
|
||||
|
||||
raw_items = payload.get("items")
|
||||
if not isinstance(raw_items, list):
|
||||
_LOGGER.debug("Album cache: ignoring saved data without an item list")
|
||||
return None
|
||||
|
||||
items: list[MediaItem] = []
|
||||
@@ -1390,10 +1525,15 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
if key in CAMERA_METADATA_FIELDS
|
||||
} if isinstance(raw.get("camera_metadata"), dict) else None,
|
||||
google_location_scanned=bool(raw.get("google_location_scanned", False)),
|
||||
location_geocoded=bool(raw.get("location_geocoded", False)),
|
||||
))
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
_LOGGER.debug(
|
||||
"Album cache: loaded %d saved items (%d skipped as unreadable)",
|
||||
len(items), len(raw_items) - len(items),
|
||||
)
|
||||
self._apply_google_location_privacy(items)
|
||||
return {
|
||||
"title": payload.get("title"),
|
||||
@@ -1429,6 +1569,7 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
"face_scanned": it.face_scanned,
|
||||
"camera_metadata": it.camera_metadata,
|
||||
"google_location_scanned": it.google_location_scanned,
|
||||
"location_geocoded": it.location_geocoded,
|
||||
}
|
||||
for it in items
|
||||
],
|
||||
@@ -1439,6 +1580,8 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
await self._items_cache_store.async_save(payload)
|
||||
except Exception as err: # pragma: no cover - storage layer
|
||||
_LOGGER.debug("Album cache: failed to save (%s)", err)
|
||||
else:
|
||||
_LOGGER.debug("Album cache: saved %d items", len(items))
|
||||
|
||||
async def _update_local_folder(self) -> dict[str, Any]:
|
||||
if not self.local_path:
|
||||
@@ -2496,6 +2639,7 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
item.longitude = info["longitude"]
|
||||
if "location" in info:
|
||||
item.location = info["location"]
|
||||
item.location_geocoded = False
|
||||
if "description" in info:
|
||||
item.description = info["description"]
|
||||
item.exif_scanned = True
|
||||
@@ -2577,6 +2721,7 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
else:
|
||||
item.latitude = item.longitude = None
|
||||
item.location = None
|
||||
item.location_geocoded = False
|
||||
item.google_location_scanned = True
|
||||
else:
|
||||
if keys is None:
|
||||
@@ -2650,6 +2795,7 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
item.longitude = meta["longitude"]
|
||||
if "location" in meta:
|
||||
item.location = meta["location"]
|
||||
item.location_geocoded = False
|
||||
item.exif_scanned = True
|
||||
|
||||
async def _enrich_items_background(self, data: dict[str, Any]) -> None:
|
||||
@@ -2786,74 +2932,57 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
self._enrich_progress["phase"] = "done"
|
||||
|
||||
async def _geocode_items_background(self, data: dict[str, Any]) -> None:
|
||||
"""Reverse-geocode items with EXIF GPS but no location label yet.
|
||||
"""Label items with GPS from the place cache, looking up new places.
|
||||
|
||||
Honours the ``reverse_geocode`` option (default on) so privacy-
|
||||
conscious users can disable the Nominatim calls without losing
|
||||
the GPS coordinates themselves. Successful labels are written
|
||||
back into the items in-place and persisted via the items cache.
|
||||
the GPS coordinates themselves. Labels are written back into the
|
||||
items in-place and persisted via the items cache.
|
||||
"""
|
||||
if getattr(self, "provider", None) == PROVIDER_GOOGLE_SHARED and not self.google_reverse_geocode_enabled:
|
||||
return
|
||||
if not bool(
|
||||
self.entry.options.get(CONF_REVERSE_GEOCODE, DEFAULT_REVERSE_GEOCODE)
|
||||
if hasattr(self.entry, "options") and self.entry.options is not None
|
||||
else DEFAULT_REVERSE_GEOCODE
|
||||
):
|
||||
if not self.reverse_geocode_enabled:
|
||||
_LOGGER.debug("Reverse geocode disabled via options; skipping")
|
||||
return
|
||||
|
||||
items: list[MediaItem] = data.get("items") or []
|
||||
candidates: list[MediaItem] = [
|
||||
it
|
||||
for it in items
|
||||
if it.latitude is not None
|
||||
and it.longitude is not None
|
||||
and not it.location
|
||||
]
|
||||
if not candidates:
|
||||
if not any(it.latitude is not None and it.longitude is not None for it in items):
|
||||
return
|
||||
|
||||
await self._ensure_geocode_cache_loaded()
|
||||
if self._label_items_from_geocode_cache(items):
|
||||
self.async_set_updated_data(data)
|
||||
|
||||
pending: dict[str, list[MediaItem]] = {}
|
||||
for item in items:
|
||||
if self._needs_geocode_lookup(item):
|
||||
key = _geocode_cache_key(item.latitude, item.longitude)
|
||||
pending.setdefault(key, []).append(item)
|
||||
if not pending:
|
||||
return
|
||||
|
||||
self._enrich_progress["phase"] = "geocoding"
|
||||
self._enrich_progress["geocode_total"] = len(candidates)
|
||||
self._enrich_progress["geocode_total"] = sum(len(group) for group in pending.values())
|
||||
self._enrich_progress["geocode_done"] = 0
|
||||
|
||||
session = async_get_clientsession(self.hass)
|
||||
user_agent = await self._async_user_agent()
|
||||
|
||||
# Last network call wall-time; used to throttle Nominatim to the
|
||||
# 1 req/sec policy without sleeping for cached lookups.
|
||||
last_call: float = 0.0
|
||||
loop = asyncio.get_event_loop()
|
||||
home = self._hidden_home_country
|
||||
unsaved = 0
|
||||
|
||||
try:
|
||||
for item in candidates:
|
||||
key = _geocode_cache_key(item.latitude, item.longitude)
|
||||
cached_label = self._geocode_cache.get(key)
|
||||
if cached_label:
|
||||
item.location = cached_label
|
||||
self._enrich_progress["geocode_done"] += 1
|
||||
continue
|
||||
|
||||
# Respect the 1 req/sec Nominatim usage policy.
|
||||
elapsed = loop.time() - last_call
|
||||
if elapsed < _NOMINATIM_MIN_INTERVAL_S:
|
||||
await asyncio.sleep(_NOMINATIM_MIN_INTERVAL_S - elapsed)
|
||||
|
||||
label = await _nominatim_lookup(
|
||||
session, item.latitude, item.longitude, user_agent
|
||||
for key, group in pending.items():
|
||||
await _wait_for_nominatim_slot()
|
||||
place = await _nominatim_lookup(
|
||||
session, group[0].latitude, group[0].longitude, user_agent
|
||||
)
|
||||
last_call = loop.time()
|
||||
|
||||
if label:
|
||||
self._geocode_cache[key] = label
|
||||
item.location = label
|
||||
if place:
|
||||
self._geocode_cache[key] = place
|
||||
label = _format_place(place, home)
|
||||
for item in group:
|
||||
item.location, item.location_geocoded = label, True
|
||||
unsaved += 1
|
||||
|
||||
self._enrich_progress["geocode_done"] += 1
|
||||
self._enrich_progress["geocode_done"] += len(group)
|
||||
|
||||
if unsaved >= _GEOCODE_BATCH_SAVE:
|
||||
unsaved = 0
|
||||
@@ -2883,18 +3012,28 @@ class AlbumCoordinator(DataUpdateCoordinator):
|
||||
if isinstance(payload, dict):
|
||||
entries = payload.get("entries")
|
||||
if isinstance(entries, dict):
|
||||
self._geocode_cache = {
|
||||
str(k): str(v)
|
||||
for k, v in entries.items()
|
||||
if isinstance(v, str) and v
|
||||
}
|
||||
for key, value in entries.items():
|
||||
if isinstance(value, dict):
|
||||
place = {
|
||||
k: v for k, v in value.items()
|
||||
if k in _PLACE_KEYS and isinstance(v, str) and v
|
||||
}
|
||||
if place:
|
||||
self._geocode_cache[str(key)] = place
|
||||
elif isinstance(value, str) and value:
|
||||
self._geocode_legacy[str(key)] = value
|
||||
self._geocode_cache_loaded = True
|
||||
|
||||
async def _save_geocode_cache(self) -> None:
|
||||
# Old labels stay until their coordinate is looked up again, so an
|
||||
# unfinished upgrade still has them after a restart.
|
||||
entries: dict[str, Any] = {
|
||||
key: label for key, label in self._geocode_legacy.items()
|
||||
if key not in self._geocode_cache
|
||||
}
|
||||
entries.update(self._geocode_cache)
|
||||
try:
|
||||
await self._geocode_cache_store.async_save(
|
||||
{"entries": self._geocode_cache}
|
||||
)
|
||||
await self._geocode_cache_store.async_save({"entries": entries})
|
||||
except Exception as err: # pragma: no cover - storage layer
|
||||
_LOGGER.debug("Geocode cache: failed to save (%s)", err)
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"iot_class": "cloud_polling",
|
||||
"issue_tracker": "https://github.com/eyalgal/album_slideshow/issues",
|
||||
"requirements": ["PyNaCl>=1.5.0"],
|
||||
"version": "1.14.0"
|
||||
"version": "1.15.0"
|
||||
}
|
||||
@@ -99,6 +99,13 @@ next_slide:
|
||||
required: true
|
||||
selector:
|
||||
text:
|
||||
frame_id:
|
||||
name: Displayed frame ID
|
||||
description: Optional frame_id of the slide on screen. When it is still in the navigation buffer, the step starts from that slide.
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
mode: box
|
||||
|
||||
previous_slide:
|
||||
name: Previous slide
|
||||
@@ -110,6 +117,13 @@ previous_slide:
|
||||
required: true
|
||||
selector:
|
||||
text:
|
||||
frame_id:
|
||||
name: Displayed frame ID
|
||||
description: Optional frame_id of the slide on screen. When it is still in the navigation buffer, the step starts from that slide.
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
mode: box
|
||||
|
||||
refresh_album:
|
||||
name: Refresh album
|
||||
|
||||
@@ -203,14 +203,16 @@
|
||||
"data": {
|
||||
"google_metadata": "Fetch photo metadata (experimental)",
|
||||
"google_location": "Read original photo GPS (opt-in)",
|
||||
"reverse_geocode": "Look up GPS place names via OpenStreetMap (opt-in)"
|
||||
"reverse_geocode": "Look up GPS place names via OpenStreetMap (opt-in)",
|
||||
"hide_home_country": "Hide the country for places in your home country"
|
||||
}
|
||||
},
|
||||
"init": {
|
||||
"title": "Location & privacy options",
|
||||
"description": "Reverse geocoding sends your photos' EXIF GPS coordinates to the public OpenStreetMap Nominatim service to look up a human-readable place name. Coordinates are rounded to ~100 m before lookup and cached on disk. Turn this off to keep coordinates entirely local; the latitude and longitude attributes still work either way.",
|
||||
"data": {
|
||||
"reverse_geocode": "Reverse-geocode EXIF GPS coordinates via OpenStreetMap"
|
||||
"reverse_geocode": "Reverse-geocode EXIF GPS coordinates via OpenStreetMap",
|
||||
"hide_home_country": "Hide the country for places in your home country"
|
||||
}
|
||||
},
|
||||
"immich_select": {
|
||||
@@ -223,7 +225,8 @@
|
||||
"favorites": "Include favorites",
|
||||
"immich_filter": "Extra search filter (JSON, optional)",
|
||||
"immich_image_size": "Image quality",
|
||||
"reverse_geocode": "Look up EXIF GPS locations via OpenStreetMap"
|
||||
"reverse_geocode": "Look up EXIF GPS locations via OpenStreetMap",
|
||||
"hide_home_country": "Hide the country for places in your home country"
|
||||
}
|
||||
},
|
||||
"connection": {
|
||||
|
||||
@@ -203,14 +203,16 @@
|
||||
"data": {
|
||||
"google_metadata": "Fetch photo metadata (experimental)",
|
||||
"google_location": "Read original photo GPS (opt-in)",
|
||||
"reverse_geocode": "Look up GPS place names via OpenStreetMap (opt-in)"
|
||||
"reverse_geocode": "Look up GPS place names via OpenStreetMap (opt-in)",
|
||||
"hide_home_country": "Hide the country for places in your home country"
|
||||
}
|
||||
},
|
||||
"init": {
|
||||
"title": "Location & privacy options",
|
||||
"description": "Reverse geocoding sends your photos' EXIF GPS coordinates to the public OpenStreetMap Nominatim service to look up a human-readable place name. Coordinates are rounded to ~100 m before lookup and cached on disk. Turn this off to keep coordinates entirely local; the latitude and longitude attributes still work either way.",
|
||||
"data": {
|
||||
"reverse_geocode": "Reverse-geocode EXIF GPS coordinates via OpenStreetMap"
|
||||
"reverse_geocode": "Reverse-geocode EXIF GPS coordinates via OpenStreetMap",
|
||||
"hide_home_country": "Hide the country for places in your home country"
|
||||
}
|
||||
},
|
||||
"immich_select": {
|
||||
@@ -223,7 +225,8 @@
|
||||
"favorites": "Include favorites",
|
||||
"immich_filter": "Extra search filter (JSON, optional)",
|
||||
"immich_image_size": "Image quality",
|
||||
"reverse_geocode": "Look up EXIF GPS locations via OpenStreetMap"
|
||||
"reverse_geocode": "Look up EXIF GPS locations via OpenStreetMap",
|
||||
"hide_home_country": "Hide the country for places in your home country"
|
||||
}
|
||||
},
|
||||
"connection": {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
* tap_action: none # none | more-info
|
||||
*/
|
||||
|
||||
const VERSION = "1.14.0";
|
||||
const VERSION = "1.15.0";
|
||||
|
||||
const ANIMATED_TRANSITIONS = [
|
||||
"fade",
|
||||
@@ -87,6 +87,49 @@ const CAPTION_WEIGHT_MAP = {
|
||||
semibold: 600,
|
||||
bold: 700,
|
||||
};
|
||||
const WEATHER_DISPLAYS = ["condition_temperature", "icon_temperature", "temperature"];
|
||||
const WEATHER_ICON_STYLES = ["yr", "meteocons", "home_assistant"];
|
||||
// Icon files in www/weather (MIT, see the LICENSE there) per HA weather condition. Yr has
|
||||
// no wind or warning symbol, so those come from Meteocons.
|
||||
const WEATHER_ICON_SETS = {
|
||||
yr: {
|
||||
"clear-night": "yr/clearsky_night",
|
||||
cloudy: "yr/cloudy",
|
||||
exceptional: "meteocons/code-red",
|
||||
fog: "yr/fog",
|
||||
hail: "yr/heavysleet",
|
||||
lightning: "yr/lightrainandthunder",
|
||||
"lightning-rainy": "yr/rainandthunder",
|
||||
partlycloudy: "yr/partlycloudy_day",
|
||||
"partlycloudy-night": "yr/partlycloudy_night",
|
||||
pouring: "yr/heavyrain",
|
||||
rainy: "yr/rain",
|
||||
snowy: "yr/snow",
|
||||
"snowy-rainy": "yr/sleet",
|
||||
sunny: "yr/clearsky_day",
|
||||
windy: "meteocons/wind",
|
||||
"windy-variant": "meteocons/wind",
|
||||
},
|
||||
meteocons: {
|
||||
"clear-night": "meteocons/clear-night",
|
||||
cloudy: "meteocons/cloudy",
|
||||
exceptional: "meteocons/code-red",
|
||||
fog: "meteocons/fog",
|
||||
hail: "meteocons/hail",
|
||||
lightning: "meteocons/thunderstorms",
|
||||
"lightning-rainy": "meteocons/thunderstorms-rain",
|
||||
partlycloudy: "meteocons/partly-cloudy-day",
|
||||
"partlycloudy-night": "meteocons/partly-cloudy-night",
|
||||
pouring: "meteocons/extreme-rain",
|
||||
rainy: "meteocons/rain",
|
||||
snowy: "meteocons/snow",
|
||||
"snowy-rainy": "meteocons/sleet",
|
||||
sunny: "meteocons/clear-day",
|
||||
windy: "meteocons/wind",
|
||||
"windy-variant": "meteocons/wind",
|
||||
},
|
||||
};
|
||||
const WEATHER_ICON_PATH = "/album_slideshow_static/weather";
|
||||
const DATE_FORMAT_PRESETS = {
|
||||
full: { year: "numeric", month: "long", day: "numeric" },
|
||||
long: { year: "numeric", month: "long", day: "numeric" },
|
||||
@@ -216,8 +259,10 @@ class PhotoControls {
|
||||
async _navigate(service) {
|
||||
if (this._busy || !this._state.entryId) return false;
|
||||
const entryId = this._state.entryId;
|
||||
// Step from the slide on screen, which may be held behind the camera.
|
||||
const data = Number.isInteger(this._state.frameId) ? { frame_id: this._state.frameId } : {};
|
||||
this._onNavigate?.("start", entryId);
|
||||
const success = await this._run(service, {}, entryId);
|
||||
const success = await this._run(service, data, entryId);
|
||||
this._onNavigate?.(success ? "complete" : "failed", entryId);
|
||||
return success;
|
||||
}
|
||||
@@ -684,6 +729,8 @@ function createAlbumSlideshowCardClass(Base) {
|
||||
time_seconds: raw.time_seconds === true,
|
||||
weather_entity: typeof raw.weather_entity === "string" && /^(weather|sensor)\.[a-z0-9_]+$/.test(raw.weather_entity.trim())
|
||||
? raw.weather_entity.trim() : null,
|
||||
weather_display: WEATHER_DISPLAYS.includes(raw.weather_display) ? raw.weather_display : "condition_temperature",
|
||||
weather_icons: WEATHER_ICON_STYLES.includes(raw.weather_icons) ? raw.weather_icons : "yr",
|
||||
color,
|
||||
font_size: fontSize,
|
||||
font_weight: fontWeight,
|
||||
@@ -727,7 +774,9 @@ function createAlbumSlideshowCardClass(Base) {
|
||||
if (!this._rendered) return;
|
||||
this._maybeSwap();
|
||||
if (this._captionData && this._captionConfigs().some((cap) => cap.show.includes("weather") && cap.weather_entity &&
|
||||
(previous?.states?.[cap.weather_entity] !== hass.states?.[cap.weather_entity] || previous?.locale !== hass.locale))) {
|
||||
(previous?.states?.[cap.weather_entity] !== hass.states?.[cap.weather_entity] || previous?.locale !== hass.locale ||
|
||||
(cap.weather_display === "icon_temperature" &&
|
||||
previous?.states?.["sun.sun"]?.state !== hass.states?.["sun.sun"]?.state)))) {
|
||||
this._renderCaptions(this._captionData, false);
|
||||
}
|
||||
}
|
||||
@@ -868,6 +917,20 @@ function createAlbumSlideshowCardClass(Base) {
|
||||
0 1px 2px rgba(0, 0, 0, 0.9),
|
||||
0 1px 6px rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
.cap-icon { display: inline-block; width: 1.8em; height: 1.8em; margin: 0 0.12em 0 -0.1em; vertical-align: middle; }
|
||||
.cap-icon svg { display: block; width: 100%; height: 100%; }
|
||||
.cap-shadow .cap-icon { filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6)); }
|
||||
.cap-icon .sun { fill: var(--weather-icon-sun-color, #fdd93c); }
|
||||
.cap-icon .moon { fill: var(--weather-icon-moon-color, #fcf497); }
|
||||
.cap-icon .cloud-back { fill: var(--weather-icon-cloud-back-color, #d4d4d4); }
|
||||
.cap-icon .cloud-front { fill: var(--weather-icon-cloud-front-color, #f9f9f9); }
|
||||
.cap-icon .rain { fill: var(--weather-icon-rain-color, #30b3ff); }
|
||||
.cap-icon .snow {
|
||||
fill: var(--weather-icon-snow-color, #f9f9f9);
|
||||
stroke: var(--weather-icon-snow-stroke-color, #d4d4d4);
|
||||
stroke-width: 1;
|
||||
paint-order: stroke;
|
||||
}
|
||||
${this._transitionStyles()}
|
||||
</style>
|
||||
<ha-card part="card">
|
||||
@@ -1112,6 +1175,7 @@ function createAlbumSlideshowCardClass(Base) {
|
||||
this._photoControls?.update({
|
||||
entryId: attrs.entry_id,
|
||||
photoIds: this._displayedPhotoIds,
|
||||
frameId: this._displayedFrameId,
|
||||
orientation: this._photoOrientation,
|
||||
hiddenCount: attrs.hidden_photo_count,
|
||||
canUndo: attrs.undo_hide_available,
|
||||
@@ -1427,12 +1491,27 @@ function createAlbumSlideshowCardClass(Base) {
|
||||
? this._hass.formatEntityState(entity)
|
||||
: isWeather ? humanizeOption(entity.state.replace("partlycloudy", "partly cloudy"))
|
||||
: [entity.state, attributes.unit_of_measurement].filter(Boolean).join(" ");
|
||||
if (!isWeather || typeof attributes.temperature !== "number" || !Number.isFinite(attributes.temperature)) return state;
|
||||
const temperature = this._hass.formatEntityAttributeValue
|
||||
? this._hass.formatEntityAttributeValue(entity, "temperature")
|
||||
: [new Intl.NumberFormat(this._locale(), { maximumFractionDigits: 1 }).format(attributes.temperature),
|
||||
attributes.temperature_unit || this._hass.config?.unit_system?.temperature].filter(Boolean).join(" ");
|
||||
return `${state}, ${temperature}`;
|
||||
if (!isWeather) return state;
|
||||
let temperature = "";
|
||||
if (typeof attributes.temperature === "number" && Number.isFinite(attributes.temperature)) {
|
||||
temperature = this._hass.formatEntityAttributeValue
|
||||
? this._hass.formatEntityAttributeValue(entity, "temperature")
|
||||
: [new Intl.NumberFormat(this._locale(), { maximumFractionDigits: 1 }).format(attributes.temperature),
|
||||
attributes.temperature_unit || this._hass.config?.unit_system?.temperature].filter(Boolean).join(" ");
|
||||
}
|
||||
if (cap.weather_display === "temperature") return temperature;
|
||||
if (cap.weather_display === "icon_temperature") {
|
||||
const night = entity.state === "partlycloudy" && this._hass.states["sun.sun"]?.state === "below_horizon";
|
||||
if (cap.weather_icons === "home_assistant") {
|
||||
const svg = homeAssistantWeatherSvg(entity.state, night);
|
||||
if (svg) return { svg, label: state, text: temperature };
|
||||
} else {
|
||||
const icons = WEATHER_ICON_SETS[cap.weather_icons] || WEATHER_ICON_SETS.yr;
|
||||
const icon = icons[night ? "partlycloudy-night" : entity.state];
|
||||
if (icon) return { icon, label: state, text: temperature };
|
||||
}
|
||||
}
|
||||
return temperature ? `${state}, ${temperature}` : state;
|
||||
}
|
||||
|
||||
/** Build one positioned caption block. ``orientation`` is ``null`` for a
|
||||
@@ -1497,7 +1576,19 @@ function createAlbumSlideshowCardClass(Base) {
|
||||
for (const line of lines) {
|
||||
const el = document.createElement("div");
|
||||
el.className = "cap-line";
|
||||
el.textContent = line;
|
||||
if (typeof line === "string") {
|
||||
el.textContent = line;
|
||||
} else {
|
||||
const icon = document.createElement(line.svg ? "span" : "img");
|
||||
icon.className = "cap-icon";
|
||||
if (line.svg) {
|
||||
icon.innerHTML = line.svg;
|
||||
} else {
|
||||
icon.alt = line.label;
|
||||
icon.src = `${WEATHER_ICON_PATH}/${line.icon}.svg?v=${VERSION}`;
|
||||
}
|
||||
el.append(icon, line.text);
|
||||
}
|
||||
box.appendChild(el);
|
||||
}
|
||||
region._captionStack.appendChild(box);
|
||||
@@ -1739,6 +1830,18 @@ const CAPTION_WEIGHT_OPTIONS = [
|
||||
{ value: "bold", label: "Bold" },
|
||||
];
|
||||
|
||||
const WEATHER_DISPLAY_OPTIONS = [
|
||||
{ value: "condition_temperature", label: "Condition and temperature" },
|
||||
{ value: "icon_temperature", label: "Icon and temperature" },
|
||||
{ value: "temperature", label: "Temperature only" },
|
||||
];
|
||||
|
||||
const WEATHER_ICON_OPTIONS = [
|
||||
{ value: "yr", label: "Yr" },
|
||||
{ value: "meteocons", label: "Meteocons" },
|
||||
{ value: "home_assistant", label: "Home Assistant" },
|
||||
];
|
||||
|
||||
const CAPTION_DATE_FORMAT_OPTIONS = [
|
||||
{ value: "medium", label: "Medium (Aug 16, 2014)" },
|
||||
{ value: "full", label: "Full (August 16, 2014)" },
|
||||
@@ -1772,6 +1875,8 @@ const CAPTION_DEFAULTS = {
|
||||
date_format: "medium",
|
||||
time_format: "auto",
|
||||
time_seconds: false,
|
||||
weather_display: "condition_temperature",
|
||||
weather_icons: "yr",
|
||||
color: "#ffffff",
|
||||
font_size: "14px",
|
||||
font_weight: "medium",
|
||||
@@ -2197,6 +2302,8 @@ function createAlbumSlideshowCardEditorClass(Base) {
|
||||
caption_time_format: c.time_format || CAPTION_DEFAULTS.time_format,
|
||||
caption_time_seconds: c.time_seconds === true,
|
||||
caption_weather_entity: c.weather_entity || "",
|
||||
caption_weather_display: c.weather_display || CAPTION_DEFAULTS.weather_display,
|
||||
caption_weather_icons: c.weather_icons || CAPTION_DEFAULTS.weather_icons,
|
||||
caption_color: c.color || CAPTION_DEFAULTS.color,
|
||||
caption_font_size: c.font_size || CAPTION_DEFAULTS.font_size,
|
||||
caption_font_weight: c.font_weight || CAPTION_DEFAULTS.font_weight,
|
||||
@@ -2221,6 +2328,16 @@ function createAlbumSlideshowCardEditorClass(Base) {
|
||||
if (data.caption_show.includes("weather")) {
|
||||
schema.push({ name: "caption_weather_entity", required: true,
|
||||
selector: { entity: { filter: [{ domain: ["weather", "sensor"] }] } } });
|
||||
if (data.caption_weather_entity.startsWith("weather.")) {
|
||||
schema.push({ name: "caption_weather_display", selector: { select: {
|
||||
mode: "dropdown", options: WEATHER_DISPLAY_OPTIONS,
|
||||
} } });
|
||||
if (data.caption_weather_display === "icon_temperature") {
|
||||
schema.push({ name: "caption_weather_icons", selector: { select: {
|
||||
mode: "dropdown", options: WEATHER_ICON_OPTIONS,
|
||||
} } });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.caption_show.includes("date")) {
|
||||
schema.push({ name: "caption_date_format", selector: { select: {
|
||||
@@ -2305,7 +2422,7 @@ function createAlbumSlideshowCardEditorClass(Base) {
|
||||
if (!Array.isArray(show)) show = typeof show === "string" ? show.split(/[,\s]+/) : [];
|
||||
const caption = { show: [...new Set(show.filter((field) => CAPTION_FIELDS.includes(field)))] };
|
||||
if (data.caption_enabled === false) caption.enabled = false;
|
||||
for (const field of ["position", "date_format", "time_format", "color", "font_size", "font_weight"]) {
|
||||
for (const field of ["position", "date_format", "time_format", "weather_display", "weather_icons", "color", "font_size", "font_weight"]) {
|
||||
const value = String(data[`caption_${field}`] || CAPTION_DEFAULTS[field]).trim();
|
||||
if (value && value !== CAPTION_DEFAULTS[field]) caption[field] = value;
|
||||
}
|
||||
@@ -2561,6 +2678,8 @@ function createAlbumSlideshowCardEditorClass(Base) {
|
||||
caption_time_format: "Time format",
|
||||
caption_time_seconds: "Show seconds",
|
||||
caption_weather_entity: "Weather source",
|
||||
caption_weather_display: "Weather display",
|
||||
caption_weather_icons: "Weather icons",
|
||||
caption_color: "Text color",
|
||||
caption_font_size: "Font size",
|
||||
caption_font_weight: "Font weight",
|
||||
@@ -2883,6 +3002,58 @@ function createAlbumSlideshowCardEditorClass(Base) {
|
||||
};
|
||||
}
|
||||
|
||||
// Home Assistant's own weather icon shapes, adapted from the frontend's src/data/weather.ts
|
||||
// (Apache-2.0, see www/weather/LICENSE). Colors follow the --weather-icon-* theme variables.
|
||||
const HA_WEATHER_PATHS = {
|
||||
sun: "m 14.39303,8.4033507 c 0,3.3114723 -2.684145,5.9956173 -5.9956169,5.9956173 -3.3114716,0 -5.9956168,-2.684145 -5.9956168,-5.9956173 0,-3.311471 2.6841452,-5.995617 5.9956168,-5.995617 3.3114719,0 5.9956169,2.684146 5.9956169,5.995617",
|
||||
moon: "m 13.502891,11.382935 c -1.011285,1.859223 -2.976664,3.121381 -5.2405751,3.121381 -3.289929,0 -5.953329,-2.663833 -5.953329,-5.9537625 0,-2.263911 1.261724,-4.228856 3.120948,-5.240575 -0.452782,0.842738 -0.712753,1.806363 -0.712753,2.832381 0,3.289928 2.663833,5.9533275 5.9533291,5.9533275 1.026017,0 1.989641,-0.259969 2.83238,-0.712752",
|
||||
partly: "m14.981 4.2112c0 1.9244-1.56 3.4844-3.484 3.4844-1.9244 0-3.4844-1.56-3.4844-3.4844s1.56-3.484 3.4844-3.484c1.924 0 3.484 1.5596 3.484 3.484",
|
||||
cloudBack: "m3.8863 5.035c-0.54892 0.16898-1.04 0.46637-1.4372 0.8636-0.63077 0.63041-1.0206 1.4933-1.0206 2.455 0 1.9251 1.5589 3.4682 3.4837 3.4682h6.9688c1.9251 0 3.484-1.5981 3.484-3.5232 0-1.9251-1.5589-3.5232-3.484-3.5232h-1.0834c-0.25294-1.6916-1.6986-2.9083-3.4463-2.9083-1.7995 0-3.2805 1.4153-3.465 3.1679",
|
||||
cloudFront: "m4.1996 7.6995c-0.33902 0.10407-0.64276 0.28787-0.88794 0.5334-0.39017 0.38982-0.63147 0.92322-0.63147 1.5176 0 1.1896 0.96414 2.1431 2.1537 2.1431h4.3071c1.1896 0 2.153-0.98742 2.153-2.1777 0-1.1896-0.96344-2.1777-2.153-2.1777h-0.66992c-0.15593-1.0449-1.0499-1.7974-2.1297-1.7974-1.112 0-2.0274 0.87524-2.1417 1.9586",
|
||||
rain: [
|
||||
"m5.2852 14.734c-0.22401 0.24765-0.57115 0.2988-0.77505 0.11395-0.20391-0.1845-0.18732-0.53481 0.036689-0.78281 0.14817-0.16298 0.59126-0.32914 0.87559-0.42369 0.12453-0.04092 0.22684 0.05186 0.19791 0.17956-0.065617 0.2921-0.18732 0.74965-0.33514 0.91299",
|
||||
"m11.257 14.163c-0.22437 0.24765-0.57115 0.2988-0.77505 0.11395-0.2039-0.1845-0.18768-0.53481 0.03669-0.78281 0.14817-0.16298 0.59126-0.32914 0.8756-0.42369 0.12453-0.04092 0.22684 0.05186 0.19791 0.17956-0.06562 0.2921-0.18732 0.74965-0.33514 0.91299",
|
||||
"m8.432 15.878c-0.15452 0.17039-0.3937 0.20567-0.53446 0.07867-0.14041-0.12735-0.12876-0.36865 0.025753-0.53975 0.10195-0.11218 0.40711-0.22684 0.60325-0.29175 0.085725-0.02858 0.15628 0.03563 0.13652 0.12382-0.045508 0.20108-0.12912 0.51647-0.23107 0.629",
|
||||
"m7.9991 14.118c-0.19226 0.21237-0.49001 0.25612-0.66499 0.09737-0.17462-0.15804-0.16051-0.45861 0.03175-0.67098 0.12665-0.14005 0.50729-0.28293 0.75071-0.36336 0.10689-0.03563 0.19473 0.0441 0.17004 0.15346-0.056092 0.25082-0.16051 0.64347-0.28751 0.78352",
|
||||
],
|
||||
pouring: [
|
||||
"m10.648 16.448c-0.19226 0.21449-0.49001 0.25894-0.66499 0.09878-0.17498-0.16016-0.16087-0.4639 0.03175-0.67874 0.12665-0.14146 0.50694-0.2854 0.75071-0.36724 0.10689-0.03563 0.19473 0.0448 0.17004 0.15558-0.05645 0.25365-0.16051 0.65017-0.28751 0.79163",
|
||||
"m5.9383 16.658c-0.22437 0.25012-0.5715 0.30162-0.77505 0.11501-0.20391-0.18627-0.18768-0.54046 0.036689-0.79093 0.14817-0.1651 0.59126-0.33267 0.87559-0.42827 0.12418-0.04127 0.22648 0.05221 0.19791 0.18168-0.065617 0.29528-0.18732 0.75741-0.33514 0.92251",
|
||||
],
|
||||
wind: [
|
||||
"m 13.59616,15.30968 c 0,0 -0.09137,-0.0071 -0.250472,-0.0187 -0.158045,-0.01235 -0.381353,-0.02893 -0.64382,-0.05715 -0.262466,-0.02716 -0.564444,-0.06385 -0.877358,-0.124531 -0.156986,-0.03034 -0.315383,-0.06844 -0.473781,-0.111478 -0.157691,-0.04551 -0.313266,-0.09842 -0.463902,-0.161219 l -0.267406,-0.0949 c -0.09984,-0.02646 -0.205669,-0.04904 -0.305153,-0.06738 -0.193322,-0.02716 -0.3838218,-0.03316 -0.5640912,-0.02011 -0.3626556,0.02611 -0.6847417,0.119239 -0.94615,0.226483 -0.2617611,0.108656 -0.4642556,0.230364 -0.600075,0.324203 -0.1358195,0.09419 -0.2049639,0.160514 -0.2049639,0.160514 0,0 0.089958,-0.01623 0.24765,-0.04445 0.1559278,-0.02575 0.3764139,-0.06174 0.6367639,-0.08714 0.2596444,-0.02646 0.5591527,-0.0441 0.8678333,-0.02328 0.076905,0.0035 0.1538111,0.01658 0.2321278,0.02293 0.077611,0.01058 0.1534581,0.02893 0.2314221,0.04022 0.07267,0.01834 0.1397,0.03986 0.213078,0.05644 l 0.238125,0.08925 c 0.09207,0.03281 0.183444,0.07055 0.275872,0.09878 0.09243,0.0261 0.185208,0.05327 0.277636,0.07161 0.184856,0.0388 0.367947,0.06174 0.543983,0.0702 0.353131,0.01905 0.678745,-0.01341 0.951442,-0.06456 0.27305,-0.05292 0.494595,-0.123119 0.646642,-0.181681 0.152047,-0.05785 0.234597,-0.104069 0.234597,-0.104069",
|
||||
"m 4.7519154,13.905801 c 0,0 0.091369,-0.0032 0.2511778,-0.0092 0.1580444,-0.0064 0.3820583,-0.01446 0.6455833,-0.03281 0.2631722,-0.01729 0.5662083,-0.04269 0.8812389,-0.09137 0.1576916,-0.02434 0.3175,-0.05609 0.4776611,-0.09384 0.1591027,-0.03951 0.3167944,-0.08643 0.4699,-0.14358 l 0.2702277,-0.08467 c 0.1008945,-0.02222 0.2074334,-0.04127 0.3072695,-0.05574 0.1943805,-0.01976 0.3848805,-0.0187 0.5651499,0.0014 0.3608917,0.03951 0.67945,0.144639 0.936625,0.261761 0.2575278,0.118534 0.4554364,0.247297 0.5873754,0.346781 0.132291,0.09913 0.198966,0.168275 0.198966,0.168275 0,0 -0.08925,-0.01976 -0.245886,-0.05397 C 9.9423347,14.087088 9.7232597,14.042988 9.4639681,14.00736 9.2057347,13.97173 8.9072848,13.94245 8.5978986,13.95162 c -0.077258,7.06e-4 -0.1541638,0.01058 -0.2328333,0.01411 -0.077964,0.0078 -0.1545166,0.02328 -0.2331861,0.03175 -0.073025,0.01588 -0.1404055,0.03422 -0.2141361,0.04798 l -0.2420055,0.08008 c -0.093486,0.02963 -0.1859139,0.06421 -0.2794,0.0889 C 7.3028516,14.23666 7.2093653,14.2603 7.116232,14.27512 6.9303181,14.30722 6.7465209,14.3231 6.5697792,14.32486 6.2166487,14.33046 5.8924459,14.28605 5.6218654,14.224318 5.3505793,14.161565 5.1318571,14.082895 4.9822793,14.01869 4.8327015,13.95519 4.7519154,13.905801 4.7519154,13.905801",
|
||||
],
|
||||
snow: [
|
||||
"m 8.4319893,15.348341 c 0,0.257881 -0.209197,0.467079 -0.467078,0.467079 -0.258586,0 -0.46743,-0.209198 -0.46743,-0.467079 0,-0.258233 0.208844,-0.467431 0.46743,-0.467431 0.257881,0 0.467078,0.209198 0.467078,0.467431",
|
||||
"m 11.263878,14.358553 c 0,0.364067 -0.295275,0.659694 -0.659695,0.659694 -0.364419,0 -0.6596937,-0.295627 -0.6596937,-0.659694 0,-0.364419 0.2952747,-0.659694 0.6596937,-0.659694 0.36442,0 0.659695,0.295275 0.659695,0.659694",
|
||||
"m 5.3252173,13.69847 c 0,0.364419 -0.295275,0.660047 -0.659695,0.660047 -0.364067,0 -0.659694,-0.295628 -0.659694,-0.660047 0,-0.364067 0.295627,-0.659694 0.659694,-0.659694 0.36442,0 0.659695,0.295627 0.659695,0.659694",
|
||||
],
|
||||
lightning: "m 9.9252695,10.935875 -1.6483986,2.341014 1.1170184,0.05929 -1.2169864,2.02141 3.0450261,-2.616159 H 9.8864918 L 10.97937,11.294651 10.700323,10.79794 h -0.508706 l -0.2663475,0.137936",
|
||||
};
|
||||
const HA_CLOUDY_STATES = new Set([
|
||||
"partlycloudy", "cloudy", "fog", "windy", "windy-variant", "hail", "rainy", "snowy",
|
||||
"snowy-rainy", "pouring", "lightning", "lightning-rainy",
|
||||
]);
|
||||
const HA_RAIN_STATES = new Set(["hail", "rainy", "pouring", "lightning-rainy"]);
|
||||
|
||||
function homeAssistantWeatherSvg(state, night) {
|
||||
const p = HA_WEATHER_PATHS;
|
||||
const paths = [];
|
||||
if (state === "sunny") paths.push(["sun", p.sun]);
|
||||
if (state === "clear-night") paths.push(["moon", p.moon]);
|
||||
if (state === "partlycloudy") paths.push([night ? "moon" : "sun", p.partly]);
|
||||
if (HA_CLOUDY_STATES.has(state)) paths.push(["cloud-back", p.cloudBack], ["cloud-front", p.cloudFront]);
|
||||
if (HA_RAIN_STATES.has(state)) paths.push(...p.rain.map((d) => ["rain", d]));
|
||||
if (state === "pouring") paths.push(...p.pouring.map((d) => ["rain", d]));
|
||||
if (state === "windy" || state === "windy-variant") paths.push(...p.wind.map((d) => ["cloud-back", d]));
|
||||
if (state === "snowy" || state === "snowy-rainy") paths.push(...p.snow.map((d) => ["snow", d]));
|
||||
if (state === "lightning" || state === "lightning-rainy") paths.push(["sun", p.lightning]);
|
||||
if (!paths.length) return null;
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 17">${
|
||||
paths.map(([cls, d]) => `<path class="${cls}" d="${d}"/>`).join("")}</svg>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register both elements so they survive the
|
||||
* ``@webcomponents/scoped-custom-element-registry`` polyfill that
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
Apache License
|
||||
==============
|
||||
|
||||
_Version 2.0, January 2004_
|
||||
_<<http://www.apache.org/licenses/>>_
|
||||
|
||||
### Terms and Conditions for use, reproduction, and distribution
|
||||
|
||||
#### 1. Definitions
|
||||
|
||||
“License” shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
“Licensor” shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
“Legal Entity” shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, “control” means **(i)** the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or **(iii)** beneficial ownership of such entity.
|
||||
|
||||
“You” (or “Your”) shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
“Source” form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
“Object” form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
“Work” shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
“Derivative Works” shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
“Contribution” shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
“submitted” means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as “Not a Contribution.”
|
||||
|
||||
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
#### 2. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
#### 3. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
#### 4. Redistribution
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
* **(b)** You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
#### 5. Submission of Contributions
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
#### 6. Trademarks
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
#### 7. Disclaimer of Warranty
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
#### 8. Limitation of Liability
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
#### 9. Accepting Warranty or Additional Liability
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
_END OF TERMS AND CONDITIONS_
|
||||
|
||||
### APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets `[]` replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same “printed page” as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1274,7 +1274,7 @@ def _mask_secrets_content(content: str) -> str:
|
||||
return "\n".join(f'{key}: "[MASKED]"' for key in parsed)
|
||||
except YAMLError:
|
||||
return "# secrets.yaml could not be parsed — content withheld to avoid leaking secrets"
|
||||
except Exception:
|
||||
except Exception: # noqa: BLE001
|
||||
return "# secrets.yaml could not be masked — content withheld to avoid leaking secrets"
|
||||
|
||||
|
||||
@@ -1572,7 +1572,7 @@ async def _run_config_check(hass: HomeAssistant, rel_path: str) -> dict[str, Any
|
||||
"""
|
||||
try:
|
||||
errors = await async_check_ha_config_file(hass)
|
||||
except Exception as check_err:
|
||||
except Exception as check_err: # noqa: BLE001
|
||||
_LOGGER.warning(
|
||||
"Config check unavailable after editing %s: %s", rel_path, check_err
|
||||
)
|
||||
@@ -2149,7 +2149,7 @@ async def _resolve_post_action(
|
||||
"post_action": "reload_performed",
|
||||
"reload_service": "frontend.reload_themes",
|
||||
}
|
||||
except Exception as reload_err:
|
||||
except Exception as reload_err: # noqa: BLE001
|
||||
post_info = {
|
||||
"post_action": "reload_available",
|
||||
"reload_service": "frontend.reload_themes",
|
||||
@@ -3170,7 +3170,7 @@ def _build_get_caller_token_handler(
|
||||
# an absent one deserve the same answer.
|
||||
raise ValueError("the manifest carries no version")
|
||||
version = str(integration.version)
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001
|
||||
_LOGGER.warning(
|
||||
"Could not read ha_mcp_tools manifest version for "
|
||||
"get_caller_token response: %s",
|
||||
@@ -3463,7 +3463,7 @@ async def _async_setup_tools_entry(hass: HomeAssistant, entry: ConfigEntry) -> b
|
||||
moved, failed = await hass.async_add_executor_job(
|
||||
_migrate_legacy_backup_dir, config_dir
|
||||
)
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
# Defensive: a migration failure must not block setup_entry, since
|
||||
# the integration's normal value (file ops, edit_yaml_config) is
|
||||
# unaffected by whether old backups got relocated.
|
||||
@@ -3506,7 +3506,7 @@ async def _async_setup_tools_entry(hass: HomeAssistant, entry: ConfigEntry) -> b
|
||||
title="HA MCP Tools — credential exposure (GHSA-g39v-cvjh-8fpf)",
|
||||
notification_id="ha_mcp_tools_ghsa_g39v_cvjh_8fpf",
|
||||
)
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
# Defensive: log line above is the source of truth; the
|
||||
# notification is best-effort UX and must not block setup.
|
||||
_LOGGER.warning(
|
||||
@@ -3516,115 +3516,60 @@ async def _async_setup_tools_entry(hass: HomeAssistant, entry: ConfigEntry) -> b
|
||||
err,
|
||||
)
|
||||
|
||||
handle_list_files = _build_list_files_handler(hass)
|
||||
handle_read_file = _build_read_file_handler(hass)
|
||||
handle_write_file = _build_write_file_handler(hass)
|
||||
handle_delete_file = _build_delete_file_handler(hass)
|
||||
handle_edit_yaml_config = _build_edit_yaml_config_handler(hass)
|
||||
handle_get_caller_token = _build_get_caller_token_handler(hass)
|
||||
handle_get_allowed_paths = _build_get_allowed_paths_handler(hass)
|
||||
handle_set_allowed_paths = _build_set_allowed_paths_handler(hass)
|
||||
handle_get_extra_yaml_keys = _build_get_extra_yaml_keys_handler(hass)
|
||||
handle_set_extra_yaml_keys = _build_set_extra_yaml_keys_handler(hass)
|
||||
handle_list_legacy_backups = _build_list_legacy_backups_handler(hass)
|
||||
handle_read_legacy_backup = _build_read_legacy_backup_handler(hass)
|
||||
|
||||
# Register all services with response support
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_EDIT_YAML_CONFIG,
|
||||
handle_edit_yaml_config,
|
||||
schema=SERVICE_EDIT_YAML_CONFIG_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_LIST_FILES,
|
||||
handle_list_files,
|
||||
schema=SERVICE_LIST_FILES_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_READ_FILE,
|
||||
handle_read_file,
|
||||
schema=SERVICE_READ_FILE_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_WRITE_FILE,
|
||||
handle_write_file,
|
||||
schema=SERVICE_WRITE_FILE_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_DELETE_FILE,
|
||||
handle_delete_file,
|
||||
schema=SERVICE_DELETE_FILE_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_GET_CALLER_TOKEN,
|
||||
handle_get_caller_token,
|
||||
schema=SERVICE_GET_CALLER_TOKEN_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_GET_ALLOWED_PATHS,
|
||||
handle_get_allowed_paths,
|
||||
schema=SERVICE_GET_ALLOWED_PATHS_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_SET_ALLOWED_PATHS,
|
||||
handle_set_allowed_paths,
|
||||
schema=SERVICE_SET_ALLOWED_PATHS_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_GET_EXTRA_YAML_KEYS,
|
||||
handle_get_extra_yaml_keys,
|
||||
schema=SERVICE_GET_EXTRA_YAML_KEYS_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_SET_EXTRA_YAML_KEYS,
|
||||
handle_set_extra_yaml_keys,
|
||||
schema=SERVICE_SET_EXTRA_YAML_KEYS_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_LIST_LEGACY_BACKUPS,
|
||||
handle_list_legacy_backups,
|
||||
schema=SERVICE_LIST_LEGACY_BACKUPS_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_READ_LEGACY_BACKUP,
|
||||
handle_read_legacy_backup,
|
||||
schema=SERVICE_READ_LEGACY_BACKUP_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
for service, schema, build_handler in (
|
||||
(
|
||||
SERVICE_EDIT_YAML_CONFIG,
|
||||
SERVICE_EDIT_YAML_CONFIG_SCHEMA,
|
||||
_build_edit_yaml_config_handler,
|
||||
),
|
||||
(SERVICE_LIST_FILES, SERVICE_LIST_FILES_SCHEMA, _build_list_files_handler),
|
||||
(SERVICE_READ_FILE, SERVICE_READ_FILE_SCHEMA, _build_read_file_handler),
|
||||
(SERVICE_WRITE_FILE, SERVICE_WRITE_FILE_SCHEMA, _build_write_file_handler),
|
||||
(SERVICE_DELETE_FILE, SERVICE_DELETE_FILE_SCHEMA, _build_delete_file_handler),
|
||||
(
|
||||
SERVICE_GET_CALLER_TOKEN,
|
||||
SERVICE_GET_CALLER_TOKEN_SCHEMA,
|
||||
_build_get_caller_token_handler,
|
||||
),
|
||||
(
|
||||
SERVICE_GET_ALLOWED_PATHS,
|
||||
SERVICE_GET_ALLOWED_PATHS_SCHEMA,
|
||||
_build_get_allowed_paths_handler,
|
||||
),
|
||||
(
|
||||
SERVICE_SET_ALLOWED_PATHS,
|
||||
SERVICE_SET_ALLOWED_PATHS_SCHEMA,
|
||||
_build_set_allowed_paths_handler,
|
||||
),
|
||||
(
|
||||
SERVICE_GET_EXTRA_YAML_KEYS,
|
||||
SERVICE_GET_EXTRA_YAML_KEYS_SCHEMA,
|
||||
_build_get_extra_yaml_keys_handler,
|
||||
),
|
||||
(
|
||||
SERVICE_SET_EXTRA_YAML_KEYS,
|
||||
SERVICE_SET_EXTRA_YAML_KEYS_SCHEMA,
|
||||
_build_set_extra_yaml_keys_handler,
|
||||
),
|
||||
(
|
||||
SERVICE_LIST_LEGACY_BACKUPS,
|
||||
SERVICE_LIST_LEGACY_BACKUPS_SCHEMA,
|
||||
_build_list_legacy_backups_handler,
|
||||
),
|
||||
(
|
||||
SERVICE_READ_LEGACY_BACKUP,
|
||||
SERVICE_READ_LEGACY_BACKUP_SCHEMA,
|
||||
_build_read_legacy_backup_handler,
|
||||
),
|
||||
):
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
service,
|
||||
build_handler(hass),
|
||||
schema=schema,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
# Register the in-process ha_mcp_tools/* WebSocket commands (info + search)
|
||||
# the server calls behind a capability gate. Idempotent, and independent of
|
||||
@@ -3660,7 +3605,7 @@ async def _async_setup_tools_entry(hass: HomeAssistant, entry: ConfigEntry) -> b
|
||||
# and ``str()`` would put the literal "None" on the device.
|
||||
raise ValueError("the manifest carries no version")
|
||||
component_version = str(integration.version)
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
_LOGGER.debug(
|
||||
"Could not read the component version for the tools device, using "
|
||||
"the compiled-in %s: %s",
|
||||
|
||||
@@ -183,7 +183,7 @@ def _fill(common: dict[str, str], key: str, /, **values: str) -> str:
|
||||
"""
|
||||
try:
|
||||
return common[key].format(**values)
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
# Names both causes: a catalog string this caller cannot fill, or a
|
||||
# caller passing values the template never declared. The second is our
|
||||
# bug and crashes on the English constant below, so the log line has to
|
||||
@@ -243,14 +243,14 @@ async def _fetch_common_translations(
|
||||
) -> dict[str, str]:
|
||||
"""core ``async_get_translations(hass, language, "common")``; test seam.
|
||||
|
||||
Mirrors the seam in ``websocket_api`` so the lookup can be replaced in
|
||||
Mirrors the seam in ``websocket_api.services`` so the lookup can be replaced in
|
||||
tests without reaching into Home Assistant's translation machinery.
|
||||
"""
|
||||
from homeassistant.helpers.translation import async_get_translations
|
||||
|
||||
result = await async_get_translations(hass, language, "common", {DOMAIN})
|
||||
# Any Mapping, not just dict: core returns a plain dict today, but the
|
||||
# mirrored seam in ``websocket_api`` accepts a Mapping, and narrowing it
|
||||
# mirrored seam in ``websocket_api.services`` accepts a Mapping, and narrowing it
|
||||
# here would silently discard a whole catalog on a core-internal change.
|
||||
if isinstance(result, Mapping):
|
||||
return dict(result)
|
||||
@@ -297,7 +297,7 @@ async def _common_strings(hass: HomeAssistant | None) -> tuple[dict[str, str], s
|
||||
# broad ``except`` also covers an ImportError from the function-local
|
||||
# core import — a permanent defect nobody would ever notice at debug.
|
||||
# ``exc_info`` because the traceback is the only way to tell the two
|
||||
# apart. Same level the ``websocket_api`` seam this mirrors uses.
|
||||
# apart. Same level the ``websocket_api.services`` seam this mirrors uses.
|
||||
_LOGGER.warning(
|
||||
"Could not load the %s options-form translations, falling back to "
|
||||
"English: %s",
|
||||
@@ -848,7 +848,7 @@ class HaMcpServerOptionsFlow(OptionsFlow):
|
||||
"shows the unknown-version wording",
|
||||
DOMAIN,
|
||||
)
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
_LOGGER.warning(
|
||||
"Could not read the component version for the options hint, "
|
||||
"showing the unknown-version wording: %s",
|
||||
@@ -864,7 +864,7 @@ class HaMcpServerOptionsFlow(OptionsFlow):
|
||||
else _installed_server_version()
|
||||
)
|
||||
server_version = raw_version or common["version_not_installed"]
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
_LOGGER.warning(
|
||||
"Could not read the server version for the options hint, showing "
|
||||
"the not-installed wording: %s",
|
||||
@@ -905,7 +905,7 @@ class HaMcpServerOptionsFlow(OptionsFlow):
|
||||
loaded = any(
|
||||
entry.state is ConfigEntryState.LOADED for entry in tools_entries
|
||||
)
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
# Warning, like the two version reads above: this drops the whole
|
||||
# tools-module paragraph from the form, which is a larger visible
|
||||
# loss than either of those fallbacks.
|
||||
@@ -953,7 +953,7 @@ class HaMcpServerOptionsFlow(OptionsFlow):
|
||||
if urls:
|
||||
listed = "\n".join(f"- {u}" for u in urls)
|
||||
return f"{common['connect_urls_label']}\n{listed}"
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
# The hint is auxiliary display data: a resolution bug must not
|
||||
# take down the whole options form, but the degradation should
|
||||
# be visible by default - hence warning, not debug.
|
||||
|
||||
@@ -24,8 +24,8 @@ DOMAIN = "ha_mcp_tools"
|
||||
# together so a manifest bump that forgets this constant (or vice-versa) fails
|
||||
# in CI. The
|
||||
# capability negotiation — not this version — gates each WS command (see
|
||||
# ``websocket_api.CAPABILITIES``).
|
||||
COMPONENT_VERSION = "2.2.1"
|
||||
# ``websocket_api.constants.CAPABILITIES``).
|
||||
COMPONENT_VERSION = "2.2.2"
|
||||
|
||||
# Config-entry discriminator (``entry.data[CONF_ENTRY_TYPE]``). A missing value
|
||||
# means "tools" so the pre-existing services entry keeps working across the
|
||||
@@ -351,9 +351,9 @@ PYPI_JSON_URL = "https://pypi.org/pypi/{dist}/json"
|
||||
# server update until HACS delivers the component (issues #1783/#1785).
|
||||
# Tag-timing caveat: stable ``vX.Y.Z`` tags exist before the PyPI publish
|
||||
# (semantic-release pushes the tag first), but a dev ``vX.Y.Z.devN`` tag is
|
||||
# only created when its draft GitHub release is published — AFTER the binary
|
||||
# builds, minutes after PyPI already has the version. During that dev window
|
||||
# this URL 404s and the gate deliberately fails open (the registry's
|
||||
# created by publish-dev.yml's pre-release job, which runs in parallel with
|
||||
# the PyPI publish, so it can briefly trail PyPI. During that dev window this
|
||||
# URL 404s and the gate deliberately fails open (the registry's
|
||||
# skip-on-failure is the backstop on that channel).
|
||||
COMPONENT_MANIFEST_AT_TAG_URL = (
|
||||
"https://raw.githubusercontent.com/homeassistant-ai/ha-mcp/"
|
||||
@@ -598,3 +598,8 @@ ISSUE_LEGACY_HACS_SOURCE = "legacy_hacs_source"
|
||||
# nor unbind an HTTP view without a full Home Assistant restart, so both
|
||||
# transitions need one; see oauth_legacy.bind_legacy_views.
|
||||
ISSUE_LEGACY_OAUTH_RESTART = "legacy_oauth_restart"
|
||||
|
||||
# How long the in-process server's listener keeps an idle keep-alive connection
|
||||
# (uvicorn's default). The webhook relay drops its pooled connections sooner, or
|
||||
# a request sent as the listener closes one fails with a reset (mcp_webhook).
|
||||
SERVER_KEEPALIVE_SECONDS = 5
|
||||
@@ -49,7 +49,6 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.requirements import (
|
||||
RequirementsNotFound,
|
||||
async_process_requirements,
|
||||
pip_kwargs,
|
||||
)
|
||||
from homeassistant.util.package import is_virtual_env
|
||||
from packaging.requirements import InvalidRequirement, Requirement
|
||||
@@ -83,6 +82,7 @@ from .const import (
|
||||
OPT_SERVER_PORT,
|
||||
OPT_SERVER_URL,
|
||||
SERVER_CONFIG_SUBDIR,
|
||||
SERVER_KEEPALIVE_SECONDS,
|
||||
SERVER_TOKEN_CLIENT_NAME,
|
||||
SERVER_USER_NAME,
|
||||
dist_for_channel,
|
||||
@@ -96,6 +96,7 @@ from .dependency_diagnostics import (
|
||||
requirement_forces_conflict,
|
||||
root_import_failure,
|
||||
)
|
||||
from .pip_compat import pip_kwargs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable
|
||||
@@ -282,7 +283,7 @@ def _install_log_filters_if_available() -> None:
|
||||
return
|
||||
try:
|
||||
install_sdk_log_filters()
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
_LOGGER.warning(
|
||||
"Could not install MCP SDK log-noise filters; continuing without them: %s",
|
||||
err,
|
||||
@@ -1643,7 +1644,7 @@ class EmbeddedServerManager:
|
||||
_IMPORTING_WORKERS.discard(threading.current_thread())
|
||||
_teardown_worker_loop(loop)
|
||||
|
||||
async def _serve(self, access_token: str, stop_event: asyncio.Event) -> None:
|
||||
async def _serve(self, access_token: str, stop_event: asyncio.Event) -> None: # noqa: PLR0915
|
||||
"""Build the ha-mcp server and run it until a stop is signaled.
|
||||
|
||||
Mirrors the CLI HTTP runner in ``ha_mcp.__main__`` without importing it
|
||||
@@ -1798,17 +1799,16 @@ class EmbeddedServerManager:
|
||||
lifespan="on",
|
||||
# HTTP-ONLY listener, so no WebSocket protocol is loaded. uvicorn
|
||||
# resolves its ``ws`` class EAGERLY in Config.load(), and
|
||||
# "websockets-sansio" imports the SHARED websockets package —
|
||||
# the unowned, tearable copy ha-mcp vendors its own copy to stay
|
||||
# clear of (#2135/#2146). With that setting a torn shared install
|
||||
# crashed this server at listener startup no matter what the
|
||||
# client imports. "none" resolves to None and imports nothing;
|
||||
# the MCP app serves Streamable HTTP and registers no WebSocket
|
||||
# route. Pinned by tests/src/unit/test_vendored_websockets.py.
|
||||
# "websockets-sansio" imports the SHARED websockets package — the
|
||||
# unowned, tearable copy ha-mcp vendors its own to stay clear of
|
||||
# (#2135/#2146); a torn shared install crashed this server at
|
||||
# startup. "none" imports nothing; the MCP app serves Streamable
|
||||
# HTTP only. Pinned by tests/src/unit/test_vendored_websockets.py.
|
||||
ws="none",
|
||||
# Leave Home Assistant's logging untouched — do not let uvicorn
|
||||
# reconfigure the root logger from this thread.
|
||||
log_config=None,
|
||||
timeout_keep_alive=SERVER_KEEPALIVE_SECONDS,
|
||||
)
|
||||
uv_server = uvicorn.Server(config)
|
||||
|
||||
@@ -1986,7 +1986,7 @@ async def _shutdown_server_resources(server: Any) -> None:
|
||||
await stop_websocket_listener()
|
||||
except ImportError:
|
||||
_LOGGER.debug("WebSocket listener module not available")
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
_LOGGER.warning("WebSocket listener cleanup failed: %s", err)
|
||||
|
||||
try:
|
||||
@@ -1995,12 +1995,12 @@ async def _shutdown_server_resources(server: Any) -> None:
|
||||
await websocket_manager.disconnect()
|
||||
except ImportError:
|
||||
_LOGGER.debug("WebSocket manager module not available")
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
_LOGGER.warning("WebSocket manager cleanup failed: %s", err)
|
||||
|
||||
try:
|
||||
await server.close()
|
||||
except Exception as err:
|
||||
except Exception as err: # noqa: BLE001
|
||||
_LOGGER.warning("Server cleanup failed: %s", err)
|
||||
|
||||
|
||||
|
||||
@@ -776,9 +776,9 @@ async def _async_fetch_shipped_component_version(
|
||||
"""Return the component version shipped at server release ``vX.Y.Z``.
|
||||
|
||||
Reads the component manifest as committed at the release's git tag (raw
|
||||
GitHub URL). Stable tags exist before the PyPI publish; a dev tag only
|
||||
appears after its binary builds finish, so a fresh dev version can 404
|
||||
here for some minutes — see COMPONENT_MANIFEST_AT_TAG_URL. Returns None
|
||||
GitHub URL). Stable tags exist before the PyPI publish; a dev tag is
|
||||
created in parallel with the PyPI publish, so a fresh dev version can
|
||||
briefly 404 here — see COMPONENT_MANIFEST_AT_TAG_URL. Returns None
|
||||
on any failure; the caller treats that as "nothing to hold on"
|
||||
(fail-open).
|
||||
"""
|
||||
|
||||
@@ -13,7 +13,8 @@ registered; default is tool-search only):
|
||||
|
||||
* **tool search** — the agent gets a tiny catalog: the server's pinned tools
|
||||
mirrored directly, plus two meta-tools synthesized here: ``ha_search_tools``
|
||||
(find tools by task) and ``ha_call_tool`` (execute a discovered tool). This
|
||||
(find tools by task, then fetch one's full schema by name; see
|
||||
:mod:`llm_api_search`) and ``ha_call_tool`` (execute a discovered tool). This
|
||||
keeps per-turn context small — the shape context-limited models need.
|
||||
* **full** — every exposed tool is mirrored directly into the agent's tool
|
||||
list, one schema each.
|
||||
@@ -53,7 +54,7 @@ import logging
|
||||
import math
|
||||
import sys
|
||||
from collections import Counter
|
||||
from collections.abc import AsyncIterator, Callable, Iterable
|
||||
from collections.abc import AsyncIterator, Callable
|
||||
from contextlib import AsyncExitStack, asynccontextmanager
|
||||
from dataclasses import dataclass, field
|
||||
from functools import cache
|
||||
@@ -73,6 +74,11 @@ from .const import (
|
||||
EXPOSURE_TOOL_SEARCH,
|
||||
OPT_LLM_API_EXPOSURE,
|
||||
)
|
||||
from .llm_api_search import CALL_TOOL_NAME as _CALL_TOOL_NAME
|
||||
from .llm_api_search import SEARCH_TOOL_NAME as _SEARCH_TOOL_NAME
|
||||
from .llm_api_search import HaMcpSearchTool
|
||||
from .llm_tool_exposure import META_PARAMS_KEY, _tool_meta_namespace, partition_tools
|
||||
from .llm_tool_metadata import declare_metadata, tool_hints, tool_result, tool_title
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import httpx
|
||||
@@ -93,45 +99,6 @@ _LIST_TOOLS_TIMEOUT_SECONDS = 10.0
|
||||
# for the duration, so err generous rather than kill a legitimate slow tool.
|
||||
_CALL_TOOL_TIMEOUT_SECONDS = 300.0
|
||||
|
||||
# The server-side stamp this module filters on (mirrors
|
||||
# src/ha_mcp/llm_exposure.py — keep the names in sync).
|
||||
_META_NAMESPACE = "ha_mcp"
|
||||
_META_EXPOSED_KEY = "llm_api_exposed"
|
||||
_META_PINNED_KEY = "pinned"
|
||||
|
||||
# Fallback exposure policy for servers that predate the stamp: hide the
|
||||
# operational-hazard names and the known beta/developer tools. Imperfect by
|
||||
# construction (a newer beta tool on an old server can't be known here) but
|
||||
# strictly safer than exposing everything, and logged once per instance
|
||||
# build. The real policy lives server-side.
|
||||
_FALLBACK_DENY_PREFIXES = ("ha_dev_",)
|
||||
_FALLBACK_DENY_TOOLS = frozenset(
|
||||
{
|
||||
"ha_restart",
|
||||
"ha_reload_core",
|
||||
"ha_manage_backup",
|
||||
# Beta-tagged tools as of the stamp's introduction (server-side the
|
||||
# gate is tag-based and future-proof; this list is only the legacy
|
||||
# fallback).
|
||||
"ha_config_set_yaml",
|
||||
"ha_manage_custom_tool",
|
||||
"ha_get_dashboard_screenshot",
|
||||
"ha_install_mcp_tools",
|
||||
"ha_list_files",
|
||||
"ha_read_file",
|
||||
"ha_write_file",
|
||||
"ha_delete_file",
|
||||
}
|
||||
)
|
||||
|
||||
# Names of the meta-tools synthesized for the tool-search mode. ha_search_tools
|
||||
# deliberately matches the server's own tool-search terminology; if the server
|
||||
# itself runs ENABLE_TOOL_SEARCH its identically-named tool is excluded from
|
||||
# mirroring/search results to avoid duplicates.
|
||||
_SEARCH_TOOL_NAME = "ha_search_tools"
|
||||
_CALL_TOOL_NAME = "ha_call_tool"
|
||||
_SEARCH_RESULT_LIMIT = 8
|
||||
|
||||
|
||||
@cache
|
||||
def _schema_converter() -> Callable[[Any], Any]:
|
||||
@@ -377,10 +344,14 @@ _TOOL_SEARCH_PROMPT = (
|
||||
"This assistant uses search-based tool discovery: most tools are NOT "
|
||||
"listed directly.\n"
|
||||
f"1. Call {_SEARCH_TOOL_NAME}(query=...) to find tools for the task; "
|
||||
"results include each tool's name, description, and input schema.\n"
|
||||
f"2. Execute a discovered tool with {_CALL_TOOL_NAME}(name=..., "
|
||||
"arguments={...}) — discovered tools are NOT directly callable here.\n"
|
||||
"3. The few tools listed directly can be called as usual.\n"
|
||||
"results are compact: each tool's name, one-line description, and params.\n"
|
||||
f"2. Call {_SEARCH_TOOL_NAME}(tools=[...]) for the full description and "
|
||||
"input schema of the tool you will call — required before calling: the "
|
||||
"compact hit omits usage guidance, nested fields, defaults, and parameter "
|
||||
"descriptions.\n"
|
||||
f"3. Execute it with {_CALL_TOOL_NAME}(name=..., arguments={{...}}) — "
|
||||
"discovered tools are NOT directly callable here.\n"
|
||||
"4. The few tools listed directly can be called as usual.\n"
|
||||
"Search once per task, not per call — tool names stay valid all "
|
||||
"conversation."
|
||||
)
|
||||
@@ -598,50 +569,6 @@ async def _mcp_session(
|
||||
yield session, init_result
|
||||
|
||||
|
||||
def _tool_meta_namespace(tool: Any) -> dict[str, Any] | None:
|
||||
"""Return the tool's ``_meta.ha_mcp`` namespace, or None when absent."""
|
||||
meta = getattr(tool, "meta", None)
|
||||
if not isinstance(meta, dict):
|
||||
return None
|
||||
namespace = meta.get(_META_NAMESPACE)
|
||||
return namespace if isinstance(namespace, dict) else None
|
||||
|
||||
|
||||
def _fallback_exposed(name: str) -> bool:
|
||||
"""Legacy exposure policy for servers that predate the meta stamp."""
|
||||
if name.startswith(_FALLBACK_DENY_PREFIXES):
|
||||
return False
|
||||
return name not in _FALLBACK_DENY_TOOLS
|
||||
|
||||
|
||||
def _partition_tools(tools: Iterable[Any]) -> tuple[list[Any], set[str], bool]:
|
||||
"""Split a raw tools/list into (exposed tools, pinned names, stamped).
|
||||
|
||||
``stamped`` is False when NO tool carried the server's exposure stamp —
|
||||
an older server package — in which case the conservative component-side
|
||||
fallback policy was applied instead.
|
||||
"""
|
||||
stamped = False
|
||||
exposed: list[Any] = []
|
||||
pinned: set[str] = set()
|
||||
for tool in tools:
|
||||
namespace = _tool_meta_namespace(tool)
|
||||
if namespace is not None and _META_EXPOSED_KEY in namespace:
|
||||
stamped = True
|
||||
if namespace.get(_META_PINNED_KEY):
|
||||
pinned.add(tool.name)
|
||||
if namespace.get(_META_EXPOSED_KEY):
|
||||
exposed.append(tool)
|
||||
elif _fallback_exposed(tool.name):
|
||||
exposed.append(tool)
|
||||
if not stamped:
|
||||
# The fallback path already filtered; recompute pinned as empty (an
|
||||
# unstamped server gives no pinned signal — the tool-search mode then
|
||||
# simply mirrors nothing directly).
|
||||
pinned = set()
|
||||
return exposed, pinned, stamped
|
||||
|
||||
|
||||
class HaMcpTool(llm.Tool):
|
||||
"""One ha-mcp tool, called over loopback MCP."""
|
||||
|
||||
@@ -651,23 +578,28 @@ class HaMcpTool(llm.Tool):
|
||||
description: str | None,
|
||||
parameters: vol.Schema,
|
||||
server_url: str,
|
||||
*,
|
||||
title: str | None = None,
|
||||
hints: dict[str, Any] | None = None,
|
||||
) -> None:
|
||||
"""Store the converted schema and the loopback endpoint."""
|
||||
"""Store the converted schema, the server's metadata and the endpoint."""
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.parameters = parameters
|
||||
self._server_url = server_url
|
||||
declare_metadata(self, title=title, hints=hints)
|
||||
|
||||
async def async_call(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
tool_input: llm.ToolInput,
|
||||
llm_context: llm.LLMContext,
|
||||
) -> JsonObjectType:
|
||||
) -> Any:
|
||||
"""Call the tool on the in-process server and return its result."""
|
||||
return await _forward_tool_call(
|
||||
dumped = await _forward_tool_call(
|
||||
hass, self._server_url, self.name, tool_input.tool_args
|
||||
)
|
||||
return tool_result(dumped, error=dumped.get("isError") is True)
|
||||
|
||||
|
||||
async def _forward_tool_call(
|
||||
@@ -715,68 +647,6 @@ def _tool_input_schema(tool: Any) -> Any:
|
||||
return schema
|
||||
|
||||
|
||||
def _search_score(query_words: list[str], name: str, description: str) -> int:
|
||||
"""Score a tool against the query (simple word overlap + substring)."""
|
||||
haystack = f"{name} {description}".lower()
|
||||
name_lower = name.lower()
|
||||
score = 0
|
||||
for word in query_words:
|
||||
if word in name_lower:
|
||||
score += 3
|
||||
elif word in haystack:
|
||||
score += 1
|
||||
return score
|
||||
|
||||
|
||||
class HaMcpSearchTool(llm.Tool):
|
||||
"""Meta-tool: find ha-mcp tools relevant to a task (tool-search mode).
|
||||
|
||||
Searches only the EXPOSED catalog snapshot taken at instance build, so a
|
||||
hidden tool can never appear in results.
|
||||
"""
|
||||
|
||||
name = _SEARCH_TOOL_NAME
|
||||
description = (
|
||||
"Search the Home Assistant MCP toolset for tools relevant to a task. "
|
||||
"Returns each match's name, description, and input schema. Execute "
|
||||
f"matches with {_CALL_TOOL_NAME}."
|
||||
)
|
||||
parameters = vol.Schema({vol.Required("query"): str})
|
||||
|
||||
def __init__(self, catalog: list[dict[str, Any]]) -> None:
|
||||
"""Hold the exposed-catalog snapshot (name/description/schema dicts)."""
|
||||
self._catalog = catalog
|
||||
|
||||
async def async_call(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
tool_input: llm.ToolInput,
|
||||
llm_context: llm.LLMContext,
|
||||
) -> JsonObjectType:
|
||||
"""Return the top-scoring exposed tools for the query."""
|
||||
query_words = [
|
||||
w for w in str(tool_input.tool_args.get("query", "")).lower().split() if w
|
||||
]
|
||||
scored = sorted(
|
||||
(
|
||||
(_search_score(query_words, t["name"], t["description"]), t)
|
||||
for t in self._catalog
|
||||
),
|
||||
key=lambda pair: pair[0],
|
||||
reverse=True,
|
||||
)
|
||||
results = [t for score, t in scored[:_SEARCH_RESULT_LIMIT] if score > 0]
|
||||
if not results:
|
||||
return {
|
||||
"results": [],
|
||||
"message": (
|
||||
"No matching tools. Try different task words (e.g. "
|
||||
"'automation', 'light', 'history', 'dashboard')."
|
||||
),
|
||||
}
|
||||
return {"results": results}
|
||||
|
||||
|
||||
class HaMcpCallTool(llm.Tool):
|
||||
"""Meta-tool: execute a tool discovered via search (tool-search mode).
|
||||
|
||||
@@ -803,6 +673,8 @@ class HaMcpCallTool(llm.Tool):
|
||||
"""Hold the loopback endpoint and the exposed-name allowlist."""
|
||||
self._server_url = server_url
|
||||
self._exposed_names = exposed_names
|
||||
# Dispatches any exposed tool, so no hints: Core's least-safe defaults.
|
||||
declare_metadata(self, title="Call HA-MCP Tool", hints=None)
|
||||
|
||||
async def async_call(
|
||||
self,
|
||||
@@ -814,11 +686,17 @@ class HaMcpCallTool(llm.Tool):
|
||||
name = str(tool_input.tool_args.get("name", ""))
|
||||
arguments = tool_input.tool_args.get("arguments") or {}
|
||||
if name not in self._exposed_names:
|
||||
return {
|
||||
"error": f"Unknown tool '{name}'.",
|
||||
"suggestion": (f"Use {_SEARCH_TOOL_NAME} to discover available tools."),
|
||||
}
|
||||
return await _forward_tool_call(hass, self._server_url, name, arguments)
|
||||
return tool_result(
|
||||
{
|
||||
"error": f"Unknown tool '{name}'.",
|
||||
"suggestion": (
|
||||
f"Use {_SEARCH_TOOL_NAME} to discover available tools."
|
||||
),
|
||||
},
|
||||
error=True,
|
||||
)
|
||||
dumped = await _forward_tool_call(hass, self._server_url, name, arguments)
|
||||
return tool_result(dumped, error=dumped.get("isError") is True)
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
@@ -858,7 +736,7 @@ class HaMcpLlmApi(llm.API):
|
||||
f"Could not reach the in-process HA-MCP server: {err}"
|
||||
) from err
|
||||
|
||||
exposed, pinned, stamped = _partition_tools(list_result.tools)
|
||||
exposed, pinned, stamped = partition_tools(list_result.tools)
|
||||
# Never mirror or search a server-side tool that shares a synthesized
|
||||
# meta-tool's name (the server's own tool-search mode registers an
|
||||
# ha_search_tools) — one name, one behavior.
|
||||
@@ -902,6 +780,17 @@ class HaMcpLlmApi(llm.API):
|
||||
)
|
||||
return None
|
||||
|
||||
def _mirror(self, tool: Any, parameters: vol.Schema) -> HaMcpTool:
|
||||
"""Mirror one server tool with its title and safety hints."""
|
||||
return HaMcpTool(
|
||||
tool.name,
|
||||
tool.description,
|
||||
parameters,
|
||||
self.server_url,
|
||||
title=tool_title(tool),
|
||||
hints=tool_hints(tool),
|
||||
)
|
||||
|
||||
def _build_full_tools(self, exposed: list[Any]) -> list[llm.Tool]:
|
||||
"""Mirror every exposed tool directly (full-catalog mode)."""
|
||||
tools: list[llm.Tool] = []
|
||||
@@ -910,9 +799,7 @@ class HaMcpLlmApi(llm.API):
|
||||
parameters = self._convert_parameters(tool, schema)
|
||||
if parameters is None:
|
||||
continue
|
||||
tools.append(
|
||||
HaMcpTool(tool.name, tool.description, parameters, self.server_url)
|
||||
)
|
||||
tools.append(self._mirror(tool, parameters))
|
||||
return tools
|
||||
|
||||
def _build_tool_search_tools(
|
||||
@@ -921,6 +808,7 @@ class HaMcpLlmApi(llm.API):
|
||||
"""Build the compact catalog: mirrored pinned tools + meta-tools."""
|
||||
tools: list[llm.Tool] = []
|
||||
exposed_names: set[str] = set()
|
||||
mirrored: set[str] = set()
|
||||
catalog: list[dict[str, Any]] = []
|
||||
for tool in exposed:
|
||||
exposed_names.add(tool.name)
|
||||
@@ -935,22 +823,26 @@ class HaMcpLlmApi(llm.API):
|
||||
# converter that wrote back would corrupt the catalog entry, so
|
||||
# re-check this before pointing the component at a third one.
|
||||
schema = _normalise_schema(_tool_input_schema(tool), tool.name)
|
||||
catalog.append(
|
||||
{
|
||||
"name": tool.name,
|
||||
"description": tool.description or "",
|
||||
"input_schema": schema,
|
||||
}
|
||||
)
|
||||
entry = {
|
||||
"name": tool.name,
|
||||
"description": tool.description or "",
|
||||
"input_schema": schema,
|
||||
}
|
||||
# The server renders the compact params line (#2633); a server
|
||||
# that predates the stamp leaves the hit without one.
|
||||
params = (_tool_meta_namespace(tool) or {}).get(META_PARAMS_KEY)
|
||||
if isinstance(params, str):
|
||||
entry["params"] = params
|
||||
catalog.append(entry)
|
||||
if tool.name in pinned:
|
||||
parameters = self._convert_parameters(tool, schema)
|
||||
if parameters is not None:
|
||||
tools.append(
|
||||
HaMcpTool(
|
||||
tool.name, tool.description, parameters, self.server_url
|
||||
)
|
||||
)
|
||||
tools.append(HaMcpSearchTool(catalog))
|
||||
tools.append(self._mirror(tool, parameters))
|
||||
mirrored.add(tool.name)
|
||||
# Only a tool actually mirrored is in the agent's list; a pinned one
|
||||
# whose schema failed to convert stays a full search entry, reachable
|
||||
# through ha_call_tool.
|
||||
tools.append(HaMcpSearchTool(catalog, mirrored))
|
||||
tools.append(HaMcpCallTool(self.server_url, exposed_names))
|
||||
return tools
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
"after_dependencies": [
|
||||
"backup",
|
||||
"cloud",
|
||||
"energy",
|
||||
"frontend",
|
||||
"http",
|
||||
"lovelace",
|
||||
"network"
|
||||
"network",
|
||||
"recorder"
|
||||
],
|
||||
"codeowners": [
|
||||
"@homeassistant-ai"
|
||||
@@ -24,5 +26,5 @@
|
||||
"ruamel.yaml>=0.18.0",
|
||||
"voluptuous-openapi>=0.4.1"
|
||||
],
|
||||
"version": "2.2.1"
|
||||
"version": "2.2.2"
|
||||
}
|
||||
@@ -47,7 +47,9 @@ from aiohttp import web
|
||||
from homeassistant.components.http import HomeAssistantView
|
||||
from homeassistant.components.webhook import async_register, async_unregister
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.util.aiohttp import MockRequest
|
||||
|
||||
from .cloudhook import OAUTH_UNAVAILABLE, buffered_response
|
||||
from .const import (
|
||||
DATA_WEBHOOK,
|
||||
DATA_WEBHOOK_ID,
|
||||
@@ -124,6 +126,13 @@ _ALLOWED_CONTENT_TYPES = ("application/json", "text/event-stream", "text/plain")
|
||||
# long-lived streams fails a new request in 30 s instead of hanging it forever.
|
||||
_CLIENT_TIMEOUT = aiohttp.ClientTimeout(connect=30, sock_connect=10, sock_read=300)
|
||||
|
||||
|
||||
# The in-process server closes an idle keep-alive connection after 5 s
|
||||
# (``const.SERVER_KEEPALIVE_SECONDS``); aiohttp pools one for 15 s. A
|
||||
# request sent as the server closes a pooled connection fails with a connection
|
||||
# reset (502), so idle relay connections are dropped first.
|
||||
_RELAY_KEEPALIVE_SECONDS = 3
|
||||
|
||||
# Anonymous CIMD lookups get a separate, deliberately small connection pool.
|
||||
# The relay session may hold long-lived SSE connections; public metadata fetches
|
||||
# must never consume that authenticated forwarding capacity.
|
||||
@@ -154,7 +163,9 @@ def _build_base_url(request: web.Request) -> str:
|
||||
hardening.
|
||||
"""
|
||||
host = request.headers.get("X-Forwarded-Host") or request.headers.get("Host", "")
|
||||
scheme = request.headers.get("X-Forwarded-Proto", request.scheme)
|
||||
scheme = request.headers.get(
|
||||
"X-Forwarded-Proto", getattr(request, "scheme", "https")
|
||||
)
|
||||
return f"{scheme}://{host}"
|
||||
|
||||
|
||||
@@ -429,8 +440,7 @@ class _AuthorizationServerMetadataView(HomeAssistantView):
|
||||
|
||||
|
||||
class _WellKnownProtectedResourceView(HomeAssistantView):
|
||||
"""RFC 9728 §3.1 path-scoped Protected Resource Metadata — the ONLY
|
||||
protected-resource document this integration serves.
|
||||
"""RFC 9728 §3.1 metadata for the webhook and its read-only alias.
|
||||
|
||||
Served at the well-known location derived from the webhook resource URL
|
||||
(``/.well-known/oauth-protected-resource/api/webhook/<id>``), which is also
|
||||
@@ -460,15 +470,17 @@ class _WellKnownProtectedResourceView(HomeAssistantView):
|
||||
def __init__(self, hass: HomeAssistant) -> None:
|
||||
"""Bind the view to the HA instance; liveness is resolved per request."""
|
||||
self._hass = hass
|
||||
self.extra_urls = [f"{self.url}/readonly"]
|
||||
|
||||
async def get(self, request: web.Request, webhook_id: str) -> web.Response:
|
||||
"""Serve the document only for the CURRENT entry's webhook id."""
|
||||
active_id = _active_webhook_id(self._hass)
|
||||
if active_id is None or webhook_id != active_id:
|
||||
return _json_not_found()
|
||||
return web.json_response(
|
||||
_protected_resource_document(active_id, _build_base_url(request))
|
||||
)
|
||||
document = _protected_resource_document(active_id, _build_base_url(request))
|
||||
if request.path == f"{self.url.format(webhook_id=webhook_id)}/readonly":
|
||||
document["resource"] += "/readonly"
|
||||
return web.json_response(document)
|
||||
|
||||
|
||||
class _WellKnownAuthorizationServerMetadataView(_AuthorizationServerMetadataView):
|
||||
@@ -542,13 +554,20 @@ def _register_metadata_views(hass: HomeAssistant) -> None:
|
||||
hass.data[_OAUTH_VIEWS_REGISTERED_KEY] = True
|
||||
|
||||
|
||||
def _build_unauthorized_response(request: web.Request, webhook_id: str) -> web.Response:
|
||||
def _build_unauthorized_response(
|
||||
request: web.Request, cfg: dict[str, Any]
|
||||
) -> web.Response:
|
||||
"""Build the 401 + ``WWW-Authenticate`` challenge MCP clients use to discover.
|
||||
|
||||
Per RFC 9728 §5.1 / MCP 2026-07-28 Authorization Server Discovery, the
|
||||
``resource_metadata`` parameter points to the protected-resource metadata
|
||||
URL where the client finds the authorization server.
|
||||
URL where the client finds the authorization server. Home Assistant Cloud
|
||||
relays only ``Content-Type`` back from a cloudhook, so the challenge can
|
||||
never reach that client and sign-in cannot start: say so instead (#2696).
|
||||
"""
|
||||
webhook_id = cfg["webhook_id"]
|
||||
if isinstance(request, MockRequest):
|
||||
return web.Response(status=400, text=OAUTH_UNAVAILABLE)
|
||||
base = _build_base_url(request)
|
||||
# RFC 9728 §3.1 path-scoped location. The pointer names the id, but this
|
||||
# 401 is only produced on a request TO /api/webhook/<id>, so the caller
|
||||
@@ -557,6 +576,8 @@ def _build_unauthorized_response(request: web.Request, webhook_id: str) -> web.R
|
||||
metadata_url = (
|
||||
f"{base}/.well-known/oauth-protected-resource/api/webhook/{webhook_id}"
|
||||
)
|
||||
if getattr(request, "path", "") == f"/api/webhook/{webhook_id}/readonly":
|
||||
metadata_url += "/readonly"
|
||||
return web.Response(
|
||||
status=401,
|
||||
text="Unauthorized",
|
||||
@@ -589,10 +610,10 @@ async def _check_webhook_auth(
|
||||
if resource_server is not None and not await resource_server.validate_request(
|
||||
request
|
||||
):
|
||||
return _build_unauthorized_response(request, cfg["webhook_id"])
|
||||
return _build_unauthorized_response(request, cfg)
|
||||
oauth_provider: LegacyOAuthProvider | None = cfg.get("oauth_provider")
|
||||
if oauth_provider is not None and not oauth_provider.validate_bearer(request):
|
||||
return _build_unauthorized_response(request, cfg["webhook_id"])
|
||||
return _build_unauthorized_response(request, cfg)
|
||||
return None
|
||||
|
||||
|
||||
@@ -618,7 +639,10 @@ async def _async_handle_webhook(
|
||||
)
|
||||
session: aiohttp.ClientSession = cfg["session"]
|
||||
|
||||
body = await request.read()
|
||||
# A cloudhook (#2696) arrives as ``MockRequest``: no ``read()``, no transport,
|
||||
# and the relay returns only ``response.body`` — so buffer, never stream.
|
||||
cloudhook = isinstance(request, MockRequest)
|
||||
body = await (request.content.read() if cloudhook else request.read())
|
||||
|
||||
forward_headers = {
|
||||
key: value
|
||||
@@ -643,7 +667,7 @@ async def _async_handle_webhook(
|
||||
if mcp_session:
|
||||
resp_headers["Mcp-Session-Id"] = mcp_session
|
||||
|
||||
if "text/event-stream" in content_type:
|
||||
if "text/event-stream" in content_type and not cloudhook:
|
||||
# SSE streaming: prevent HA's compression middleware from
|
||||
# buffering/breaking the stream (supervisor#6470).
|
||||
resp_headers["Content-Type"] = "text/event-stream"
|
||||
@@ -677,10 +701,7 @@ async def _async_handle_webhook(
|
||||
if not any(ct in content_type for ct in _ALLOWED_CONTENT_TYPES):
|
||||
content_type = "application/json"
|
||||
resp_headers["Content-Type"] = content_type
|
||||
resp_body = await upstream_resp.read()
|
||||
return web.Response(
|
||||
status=upstream_resp.status, body=resp_body, headers=resp_headers
|
||||
)
|
||||
return await buffered_response(cloudhook, upstream_resp, resp_headers)
|
||||
except aiohttp.ClientError as err:
|
||||
_LOGGER.error("MCP webhook: upstream request failed: %s", err)
|
||||
return web.Response(status=502, text="MCP server unavailable")
|
||||
@@ -844,7 +865,10 @@ async def async_register_webhook(
|
||||
# Runs before the session opens so a raise here cannot leak it.
|
||||
_unregister_webhook(hass, webhook_id)
|
||||
target_url = f"http://127.0.0.1:{port}{secret_path}"
|
||||
session = aiohttp.ClientSession(timeout=_CLIENT_TIMEOUT)
|
||||
session = aiohttp.ClientSession(
|
||||
timeout=_CLIENT_TIMEOUT,
|
||||
connector=aiohttp.TCPConnector(keepalive_timeout=_RELAY_KEEPALIVE_SECONDS),
|
||||
)
|
||||
cimd_session: aiohttp.ClientSession | None = None
|
||||
if register_endpoint and auth_mode == WEBHOOK_AUTH_HA:
|
||||
try:
|
||||
|
||||
@@ -480,6 +480,13 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool:
|
||||
"""
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
|
||||
# Which version this run imported: an update HACS installs later changes
|
||||
# the files (and HA's integration cache) but not the code in memory, and
|
||||
# the panel asks for a restart until they agree again.
|
||||
from .helpers.update_state import async_remember_running_version
|
||||
|
||||
await async_remember_running_version(hass)
|
||||
|
||||
# The Lovelace card / calendar card / strategy modules FIRST (#184): HA
|
||||
# builds the list of extra module scripts into index.html at the moment a
|
||||
# page is served, and the frontend does not load modules registered later
|
||||
@@ -974,6 +981,10 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool:
|
||||
return
|
||||
|
||||
nm = hass.data.get(DOMAIN, {}).get(NOTIFICATION_MANAGER_KEY)
|
||||
# Whose phones carry the reminder: read BEFORE completing, which
|
||||
# hands a rotation on to the next person.
|
||||
task_cfg = (config_entry.data.get(CONF_TASKS) or {}).get(task_id) or {} if config_entry is not None else {}
|
||||
reminded_user_ids = task_user_ids(task_cfg)
|
||||
|
||||
try:
|
||||
if action_type == "complete":
|
||||
@@ -1017,9 +1028,7 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool:
|
||||
|
||||
# Action succeeded — dismiss notification and clear NM rate-limit state
|
||||
if nm is not None:
|
||||
cfg_entry = hass.config_entries.async_get_entry(entry_id)
|
||||
task_cfg = ((cfg_entry.data.get(CONF_TASKS) or {}).get(task_id) or {}) if cfg_entry is not None else {}
|
||||
await nm.async_dismiss_task_notification(task_id, user_ids=task_user_ids(task_cfg))
|
||||
await nm.async_dismiss_task_notification(task_id, user_ids=reminded_user_ids)
|
||||
nm.clear_task_state(entry_id, task_id)
|
||||
|
||||
unsub_notification = hass.bus.async_listen("mobile_app_notification_action", _handle_notification_action)
|
||||
|
||||
@@ -973,7 +973,9 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
bundling_enabled = global_option(self.hass, CONF_NOTIFICATION_BUNDLING_ENABLED)
|
||||
bundle_threshold = int(global_option(self.hass, CONF_NOTIFICATION_BUNDLE_THRESHOLD))
|
||||
|
||||
if bundling_enabled and len(notifiable) >= bundle_threshold:
|
||||
# No household target: a bundle would reach nobody, so the tasks go
|
||||
# out one by one to their people's phones (D#110).
|
||||
if bundling_enabled and nm.can_bundle and len(notifiable) >= bundle_threshold:
|
||||
await nm.async_send_bundled(
|
||||
entry_id=self.entry.entry_id,
|
||||
object_name=obj_name,
|
||||
|
||||
+89
-56
@@ -11,6 +11,12 @@
|
||||
* under another name starts unticked with that task's name; a summary says
|
||||
* per object how many tasks it has before and after. Typing another object
|
||||
* asks the server again (problem_sensors/preview).
|
||||
*
|
||||
* #211 (54 problem sensors of 18 devices, on a phone): the summary grew a
|
||||
* line per object and squeezed the list, the only part that could shrink,
|
||||
* to nothing. The dialog now sits in the shared modal frame: the title and
|
||||
* the buttons stay, everything between them scrolls as one, and the summary
|
||||
* folds to its totals once it names more than three objects.
|
||||
*/
|
||||
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
@@ -18,6 +24,7 @@ import { property, state } from "lit/decorators.js";
|
||||
|
||||
import { t, ensureLocale, langOf } from "../styles";
|
||||
import { runWs } from "../helpers/ws-run";
|
||||
import { focusModalShell, modalShellStyles, renderModalShell } from "../helpers/modal-shell";
|
||||
import { TRIGGER_FOR_MINUTES_RANGE } from "../helpers/setting-ranges";
|
||||
import { UserService } from "../user-service";
|
||||
import type { HAUser, HomeAssistant } from "../types";
|
||||
@@ -52,6 +59,16 @@ interface AdoptResponse {
|
||||
errors?: string[];
|
||||
}
|
||||
|
||||
/** One object of the summary: the tasks it gains (entry null = a new object). */
|
||||
interface SummaryGroup {
|
||||
name: string;
|
||||
entry: string | null;
|
||||
adding: number;
|
||||
}
|
||||
|
||||
/** Up to this many objects the summary opens with its lines shown. */
|
||||
const SUMMARY_LINES_OPEN = 3;
|
||||
|
||||
export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@@ -74,6 +91,9 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
// #136: minutes the problem must persist before the created task triggers
|
||||
// (one field applied to every selection). "0" = react to the first flicker.
|
||||
@state() private _forMinutes = "0";
|
||||
/** #211: the summary's lines shown; decided when the list arrives (folded
|
||||
* beyond three objects), then the user's. */
|
||||
@state() private _summaryOpen = true;
|
||||
|
||||
private _localeReady = false;
|
||||
private _userService: UserService | null = null;
|
||||
@@ -87,6 +107,7 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
this._localeReady = true;
|
||||
ensureLocale(this._lang).then(() => this.requestUpdate());
|
||||
}
|
||||
if (changed.has("_open") && this._open) focusModalShell(this.shadowRoot);
|
||||
}
|
||||
|
||||
public async open(): Promise<void> {
|
||||
@@ -125,6 +146,7 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
// What the target probably already watches starts unticked.
|
||||
this._selected = new Set(this._sensors.filter((s) => !s.covered_by).map((s) => s.entity_id));
|
||||
this._users = users;
|
||||
this._summaryOpen = this._summaryGroups().length <= SUMMARY_LINES_OPEN;
|
||||
}
|
||||
|
||||
/** The default object: the one linked to the device, else the one the
|
||||
@@ -169,9 +191,9 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
if (resp?.covered) this._covered = { ...this._covered, ...resp.covered };
|
||||
}
|
||||
|
||||
/** Per target object: tasks before → after (only ticked rows count). */
|
||||
private _summary(L: string) {
|
||||
const groups = new Map<string, { name: string; entry: string | null; adding: number }>();
|
||||
/** The objects the ticked rows go to, each with the tasks it gains. */
|
||||
private _summaryGroups(): SummaryGroup[] {
|
||||
const groups = new Map<string, SummaryGroup>();
|
||||
for (const s of this._sensors) {
|
||||
if (!this._selected.has(s.entity_id)) continue;
|
||||
const entry = this._existingEntryFor(s);
|
||||
@@ -181,11 +203,30 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
g.adding += 1;
|
||||
groups.set(key, g);
|
||||
}
|
||||
if (groups.size === 0) return nothing;
|
||||
return [...groups.values()];
|
||||
}
|
||||
|
||||
/** Per target object: tasks before → after (only ticked rows count), under
|
||||
* a line with the totals that stays when the lines are folded (#211). */
|
||||
private _summary(L: string) {
|
||||
const groups = this._summaryGroups();
|
||||
if (groups.length === 0) return nothing;
|
||||
const created = groups.filter((g) => !g.entry).length;
|
||||
const totals = t(created ? "adopt_summary_totals_new" : "adopt_summary_totals", L)
|
||||
.replace("{tasks}", String(groups.reduce((n, g) => n + g.adding, 0)))
|
||||
.replace("{objects}", String(groups.length))
|
||||
.replace("{new}", String(created));
|
||||
return html`
|
||||
<div class="summary">
|
||||
<div class="summary-title">${t("adopt_summary_title", L)}</div>
|
||||
${[...groups.values()].map((g) => {
|
||||
<details
|
||||
class="summary"
|
||||
.open=${this._summaryOpen}
|
||||
@toggle=${(e: Event) => { this._summaryOpen = (e.target as HTMLDetailsElement).open; }}
|
||||
>
|
||||
<summary>
|
||||
<span class="summary-title">${t("adopt_summary_title", L)}</span>
|
||||
<span class="summary-totals">${totals}</span>
|
||||
</summary>
|
||||
${groups.map((g) => {
|
||||
if (!g.entry) {
|
||||
return html`<div class="summary-line new">
|
||||
${t("setups_new_object_count", L).replace("{name}", g.name).replace("{count}", String(g.adding))}
|
||||
@@ -199,7 +240,7 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
.replace("{after}", String(before + g.adding))}
|
||||
</div>`;
|
||||
})}
|
||||
</div>
|
||||
</details>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -269,13 +310,12 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
const allSelected =
|
||||
this._sensors.length > 0 && this._selected.size === this._sensors.length;
|
||||
|
||||
return html`
|
||||
<div class="overlay" @click=${this._close}>
|
||||
<div class="card" @click=${(e: Event) => e.stopPropagation()}>
|
||||
<div class="title">${t("adopt_problem_title", L)}</div>
|
||||
<div class="hint">${t("adopt_problem_hint", L)}</div>
|
||||
${this._error ? html`<div class="error">${this._error}</div>` : nothing}
|
||||
return renderModalShell(() => this._close(), html`
|
||||
<div class="title">${t("adopt_problem_title", L)}</div>
|
||||
${this._error ? html`<div class="error">${this._error}</div>` : nothing}
|
||||
|
||||
<div class="dialog-scroll">
|
||||
<div class="hint">${t("adopt_problem_hint", L)}</div>
|
||||
${this._loading
|
||||
? html`<div class="loading">…</div>`
|
||||
: this._sensors.length === 0
|
||||
@@ -392,47 +432,28 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
</label>
|
||||
`
|
||||
: nothing}
|
||||
|
||||
<div class="actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${t("cancel", L)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._adopt}
|
||||
.disabled=${this._selected.size === 0 || this._adopting}
|
||||
>
|
||||
${t("adopt_problem_adopt", L)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
<div class="actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${t("cancel", L)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._adopt}
|
||||
.disabled=${this._selected.size === 0 || this._adopting}
|
||||
>
|
||||
${t("adopt_problem_adopt", L)}
|
||||
</ha-button>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
.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);
|
||||
static styles = [modalShellStyles, css`
|
||||
:host {
|
||||
--ms-modal-max-width: 560px;
|
||||
--ms-modal-max-height: 90dvh;
|
||||
--ms-modal-gap: 12px;
|
||||
--ms-modal-z: 1000;
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
@@ -452,6 +473,9 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
font-size: 14px;
|
||||
padding: 12px 0;
|
||||
}
|
||||
/* Stays at the top of the scrolling middle: the count while ticking.
|
||||
top: -1px + 1px more padding: on a 3x screen a fractional offset let a
|
||||
line of the text scrolled under it show above it. */
|
||||
.select-all {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -459,6 +483,11 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
cursor: pointer;
|
||||
position: sticky;
|
||||
top: -1px;
|
||||
z-index: 1;
|
||||
padding: 5px 0 4px;
|
||||
background: var(--card-background-color, var(--ha-card-background, #1c1c1c));
|
||||
}
|
||||
.select-all input {
|
||||
cursor: pointer;
|
||||
@@ -467,8 +496,6 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
overflow-y: auto;
|
||||
max-height: 50vh;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
@@ -536,9 +563,15 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
border-top: 1px dashed var(--divider-color);
|
||||
padding-top: 6px;
|
||||
}
|
||||
.summary > summary {
|
||||
cursor: pointer;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.summary-title {
|
||||
font-weight: 500;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.summary-totals {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.summary-line {
|
||||
color: var(--primary-color);
|
||||
@@ -594,7 +627,7 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
gap: 8px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
`;
|
||||
`];
|
||||
}
|
||||
|
||||
if (!customElements.get("maintenance-adopt-problem-sensors-dialog")) {
|
||||
|
||||
+54
-76
@@ -7,6 +7,9 @@
|
||||
*
|
||||
* Uses a native <input> for the name — <ha-textfield> is not registered in the
|
||||
* custom-panel context, so it renders without its field (the documented trap).
|
||||
*
|
||||
* In the shared modal frame (#211): the list of views scrolls, the name
|
||||
* field and the Close button stay.
|
||||
*/
|
||||
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
@@ -14,6 +17,7 @@ import { property, state } from "lit/decorators.js";
|
||||
|
||||
import { t, ensureLocale, langOf } from "../styles";
|
||||
import { runWs } from "../helpers/ws-run";
|
||||
import { focusModalShell, modalShellStyles, renderModalShell } from "../helpers/modal-shell";
|
||||
import type { HomeAssistant, SavedView, SavedViewFilters } from "../types";
|
||||
|
||||
interface ViewsResponse {
|
||||
@@ -41,6 +45,7 @@ export class MaintenanceSavedViewsDialog extends LitElement {
|
||||
this._localeReady = true;
|
||||
ensureLocale(this._lang).then(() => this.requestUpdate());
|
||||
}
|
||||
if (changed.has("_open") && this._open) focusModalShell(this.shadowRoot);
|
||||
}
|
||||
|
||||
public async open(currentFilters: SavedViewFilters, views: SavedView[]): Promise<void> {
|
||||
@@ -90,81 +95,58 @@ export class MaintenanceSavedViewsDialog extends LitElement {
|
||||
render() {
|
||||
if (!this._open) return html``;
|
||||
const L = this._lang;
|
||||
return html`
|
||||
<div class="overlay" @click=${this._close}>
|
||||
<div class="card" @click=${(e: Event) => e.stopPropagation()}>
|
||||
<div class="title">${t("views_dialog_title", L)}</div>
|
||||
<div class="hint">${t("views_dialog_hint", L)}</div>
|
||||
${this._error ? html`<div class="error">${this._error}</div>` : nothing}
|
||||
return renderModalShell(() => this._close(), html`
|
||||
<div class="title">${t("views_dialog_title", L)}</div>
|
||||
<div class="hint">${t("views_dialog_hint", L)}</div>
|
||||
${this._error ? html`<div class="error">${this._error}</div>` : nothing}
|
||||
|
||||
<div class="save-row">
|
||||
<input
|
||||
class="name-input"
|
||||
type="text"
|
||||
.value=${this._name}
|
||||
placeholder=${t("views_name_placeholder", L)}
|
||||
maxlength="60"
|
||||
@input=${(e: Event) => (this._name = (e.target as HTMLInputElement).value)}
|
||||
@keydown=${(e: KeyboardEvent) => {
|
||||
if (e.key === "Enter") this._save();
|
||||
}}
|
||||
/>
|
||||
<ha-button @click=${this._save} .disabled=${!this._name.trim() || this._busy}>
|
||||
${t("views_save_current", L)}
|
||||
</ha-button>
|
||||
</div>
|
||||
|
||||
${this._views.length === 0
|
||||
? html`<div class="empty">${t("views_none_yet", L)}</div>`
|
||||
: html`
|
||||
<div class="list">
|
||||
${this._views.map(
|
||||
(v) => html`
|
||||
<div class="row">
|
||||
<span class="row-name">${v.name}</span>
|
||||
<ha-icon-button
|
||||
.path=${"M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z"}
|
||||
.label=${t("delete", L)}
|
||||
@click=${() => this._delete(v.id)}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
|
||||
<div class="actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>${t("close", L)}</ha-button>
|
||||
</div>
|
||||
<div class="save-row">
|
||||
<input
|
||||
class="name-input"
|
||||
type="text"
|
||||
.value=${this._name}
|
||||
placeholder=${t("views_name_placeholder", L)}
|
||||
maxlength="60"
|
||||
@input=${(e: Event) => (this._name = (e.target as HTMLInputElement).value)}
|
||||
@keydown=${(e: KeyboardEvent) => {
|
||||
if (e.key === "Enter") this._save();
|
||||
}}
|
||||
/>
|
||||
<ha-button @click=${this._save} .disabled=${!this._name.trim() || this._busy}>
|
||||
${t("views_save_current", L)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
${this._views.length === 0
|
||||
? html`<div class="empty">${t("views_none_yet", L)}</div>`
|
||||
: html`
|
||||
<div class="list dialog-scroll">
|
||||
${this._views.map(
|
||||
(v) => html`
|
||||
<div class="row">
|
||||
<span class="row-name">${v.name}</span>
|
||||
<ha-icon-button
|
||||
.path=${"M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z"}
|
||||
.label=${t("delete", L)}
|
||||
@click=${() => this._delete(v.id)}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
|
||||
<div class="actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>${t("close", L)}</ha-button>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
.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: 480px;
|
||||
width: 90vw;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
|
||||
static styles = [modalShellStyles, css`
|
||||
:host {
|
||||
--ms-modal-max-height: 90dvh;
|
||||
--ms-modal-gap: 12px;
|
||||
--ms-modal-z: 1000;
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
@@ -198,11 +180,7 @@ export class MaintenanceSavedViewsDialog extends LitElement {
|
||||
padding: 8px 0;
|
||||
}
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
overflow-y: auto;
|
||||
max-height: 50vh;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
@@ -227,7 +205,7 @@ export class MaintenanceSavedViewsDialog extends LitElement {
|
||||
gap: 8px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
`;
|
||||
`];
|
||||
}
|
||||
|
||||
if (!customElements.get("maintenance-saved-views-dialog")) {
|
||||
|
||||
+28
-44
@@ -19,6 +19,9 @@
|
||||
* reset button completing it will press; tasks adopted before (or wired by
|
||||
* hand) are offered the same in their own section, with a before/after line
|
||||
* (integration_setups/reset_offers + wire_resets).
|
||||
*
|
||||
* #211: in the shared modal frame like the adopt dialog: the title and the
|
||||
* buttons stay, the offers and the devices scroll as one.
|
||||
*/
|
||||
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
@@ -26,6 +29,7 @@ import { property, state } from "lit/decorators.js";
|
||||
|
||||
import { t, ensureLocale, langOf } from "../styles";
|
||||
import { runWs } from "../helpers/ws-run";
|
||||
import { focusModalShell, modalShellStyles, renderModalShell } from "../helpers/modal-shell";
|
||||
import type { HomeAssistant } from "../types";
|
||||
|
||||
interface SetupTask {
|
||||
@@ -112,6 +116,7 @@ export class MaintenanceSuggestedSetupsDialog extends LitElement {
|
||||
this._localeReady = true;
|
||||
ensureLocale(this._lang).then(() => this.requestUpdate());
|
||||
}
|
||||
if (changed.has("_open") && this._open) focusModalShell(this.shadowRoot);
|
||||
}
|
||||
|
||||
/** Ticked by default: everything the target does not probably have yet. */
|
||||
@@ -336,13 +341,12 @@ export class MaintenanceSuggestedSetupsDialog extends LitElement {
|
||||
if (!this._open) return html``;
|
||||
const L = this._lang;
|
||||
|
||||
return html`
|
||||
<div class="overlay" @click=${this._close}>
|
||||
<div class="card" @click=${(e: Event) => e.stopPropagation()}>
|
||||
<div class="title">${t("setups_title", L)}</div>
|
||||
<div class="hint">${t("setups_hint", L)}</div>
|
||||
${this._error ? html`<div class="error">${this._error}</div>` : nothing}
|
||||
return renderModalShell(() => this._close(), html`
|
||||
<div class="title">${t("setups_title", L)}</div>
|
||||
${this._error ? html`<div class="error">${this._error}</div>` : nothing}
|
||||
|
||||
<div class="dialog-scroll">
|
||||
<div class="hint">${t("setups_hint", L)}</div>
|
||||
${this._renderOffers(L)}
|
||||
${this._loading
|
||||
? html`<div class="loading">…</div>`
|
||||
@@ -428,50 +432,31 @@ export class MaintenanceSuggestedSetupsDialog extends LitElement {
|
||||
})}
|
||||
</div>
|
||||
`}
|
||||
|
||||
<div class="actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${t("cancel", L)}
|
||||
</ha-button>
|
||||
<ha-button @click=${this._adopt} .disabled=${!this._anythingTicked || this._adopting}>
|
||||
${t("setups_adopt", L)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
<div class="actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${t("cancel", L)}
|
||||
</ha-button>
|
||||
<ha-button @click=${this._adopt} .disabled=${!this._anythingTicked || this._adopting}>
|
||||
${t("setups_adopt", L)}
|
||||
</ha-button>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
.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);
|
||||
static styles = [modalShellStyles, css`
|
||||
:host {
|
||||
--ms-modal-max-width: 560px;
|
||||
--ms-modal-max-height: 90dvh;
|
||||
--ms-modal-gap: 12px;
|
||||
--ms-modal-z: 1000;
|
||||
}
|
||||
.title { font-size: 18px; font-weight: 500; }
|
||||
.hint { color: var(--secondary-text-color); font-size: 13px; }
|
||||
.error { color: var(--error-color, #f44336); font-size: 13px; }
|
||||
.loading, .empty { color: var(--secondary-text-color); font-size: 14px; padding: 12px 0; }
|
||||
.list { display: flex; flex-direction: column; gap: 6px; overflow-y: auto; max-height: 55vh; }
|
||||
.list { display: flex; flex-direction: column; gap: 6px; }
|
||||
.row {
|
||||
display: flex; align-items: flex-start; gap: 10px; padding: 8px;
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
@@ -497,7 +482,6 @@ export class MaintenanceSuggestedSetupsDialog extends LitElement {
|
||||
.offers {
|
||||
display: flex; flex-direction: column; gap: 6px; padding: 8px;
|
||||
border: 1px solid var(--primary-color); border-radius: 6px;
|
||||
overflow-y: auto; max-height: 40vh; flex-shrink: 0;
|
||||
}
|
||||
.offers-title { font-weight: 500; font-size: 14px; }
|
||||
.offer { display: flex; align-items: flex-start; gap: 6px; font-size: 13px; cursor: pointer; }
|
||||
@@ -520,7 +504,7 @@ export class MaintenanceSuggestedSetupsDialog extends LitElement {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.actions { display: flex; justify-content: flex-end; gap: 8px; padding-top: 8px; }
|
||||
`;
|
||||
`];
|
||||
}
|
||||
|
||||
if (!customElements.get("maintenance-suggested-setups-dialog")) {
|
||||
|
||||
@@ -3072,6 +3072,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
<option value="completion" ?selected=${this._intervalAnchor === "completion"}>${t("anchor_completion", L)}</option>
|
||||
<option value="planned" ?selected=${this._intervalAnchor === "planned"}>${t("anchor_planned", L)}</option>
|
||||
</select>
|
||||
<div class="field-help anchor-help">${t("interval_anchor_hint", L)}</div>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Ukotvení intervalu",
|
||||
"anchor_completion": "Od data dokončení",
|
||||
"anchor_planned": "Od plánovaného data (bez posunu)",
|
||||
"interval_anchor_hint": "Od data dokončení: další termín se počítá ode dne, kdy je úkol označen jako hotový, takže dřívější nebo pozdější splnění posune plán. Od plánovaného data: plán si ponechá své termíny, například když je faktura zaplacena týdny před splatností.",
|
||||
"edit_object": "Upravit objekt",
|
||||
"name": "Název",
|
||||
"manufacturer_optional": "Výrobce (volitelné)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Dejte několika senzorům stejný název objektu a stanou se jedním objektem; zadejte název existujícího objektu a přidají se tam.",
|
||||
"adopt_summary_title": "Co převzetí změní",
|
||||
"adopt_summary_existing": "„{name}“: úkoly {before} → {after}",
|
||||
"adopt_summary_totals": "Úkoly: {tasks} · objekty: {objects}",
|
||||
"adopt_summary_totals_new": "Úkoly: {tasks} · objekty: {objects} (z toho nové: {new})",
|
||||
"adopt_problem_adopt": "Převzít vybrané",
|
||||
"adopt_problem_done": "Převzato {tasks} senzorů problémů",
|
||||
"adopt_problem_done_one": "Převzat 1 senzor problémů",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Flotila baterií nastavena — jeden úkol sleduje všechny.",
|
||||
"update_banner": "Na serveru je novější verze Maintenance Supporter — načtěte znovu pro aktualizaci panelu.",
|
||||
"update_reload": "Načíst znovu",
|
||||
"restart_pending_banner": "Maintenance Supporter byl aktualizován na verzi {version}. Restartujte Home Assistant, aby se aktualizace dokončila.",
|
||||
"restart_pending_error": "Nepodařilo se: Maintenance Supporter byl aktualizován na verzi {version}, ale Home Assistant od té doby nebyl restartován. Restartujte Home Assistant a zkuste to znovu.",
|
||||
"row_actions_banner": "Dokončit a Přeskočit jsou v řádcích úkolů nyní tlačítka. Dáváte přednost starým ikonám?",
|
||||
"row_actions_keep": "Ponechat tlačítka",
|
||||
"row_actions_back": "Zpět na ikony",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Intervalanker",
|
||||
"anchor_completion": "Fra fuldførelsesdato",
|
||||
"anchor_planned": "Fra planlagt dato (ingen drift)",
|
||||
"interval_anchor_hint": "Fra fuldførelsesdato: næste forfaldsdato regnes fra den dag, opgaven markeres som udført, så tidlig eller sen udførelse flytter planen. Fra planlagt dato: planen beholder sine datoer, for eksempel når en regning betales uger før forfald.",
|
||||
"edit_object": "Rediger objekt",
|
||||
"name": "Navn",
|
||||
"manufacturer_optional": "Producent (valgfrit)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Giv flere sensorer samme objektnavn, så bliver de ét objekt; skriv et eksisterende objekts navn for at tilføje dem der.",
|
||||
"adopt_summary_title": "Hvad overtagelsen ændrer",
|
||||
"adopt_summary_existing": "\"{name}\": opgaver {before} → {after}",
|
||||
"adopt_summary_totals": "Opgaver: {tasks} · objekter: {objects}",
|
||||
"adopt_summary_totals_new": "Opgaver: {tasks} · objekter: {objects} (heraf nye: {new})",
|
||||
"adopt_problem_adopt": "Adopter valgte",
|
||||
"adopt_problem_done": "Adopterede {tasks} problemsensor(er)",
|
||||
"adopt_problem_done_one": "Adopterede 1 problemsensor",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Batteriflåde opsat — én opgave følger alle batterier.",
|
||||
"update_banner": "En nyere version af Maintenance Supporter er på serveren — genindlæs for at opdatere panelet.",
|
||||
"update_reload": "Genindlæs",
|
||||
"restart_pending_banner": "Maintenance Supporter er blevet opdateret til {version}. Genstart Home Assistant for at fuldføre opdateringen.",
|
||||
"restart_pending_error": "Det lykkedes ikke: Maintenance Supporter er blevet opdateret til {version}, men Home Assistant er ikke blevet genstartet siden. Genstart Home Assistant, og prøv igen.",
|
||||
"row_actions_banner": "Fuldfør og Spring over er nu knapper i opgaverækkerne. Foretrækker du de gamle ikoner?",
|
||||
"row_actions_keep": "Behold knapper",
|
||||
"row_actions_back": "Tilbage til ikoner",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Intervall-Anker",
|
||||
"anchor_completion": "Ab Erledigung",
|
||||
"anchor_planned": "Ab geplantem Datum (kein Drift)",
|
||||
"interval_anchor_hint": "Ab Erledigung: Die nächste Fälligkeit zählt ab dem Tag, an dem die Aufgabe erledigt wird; früher oder später erledigt verschiebt also den Plan. Ab geplantem Datum: Der Plan behält seine Termine, zum Beispiel wenn eine Rechnung Wochen vor der Fälligkeit bezahlt wird.",
|
||||
"edit_object": "Objekt bearbeiten",
|
||||
"name": "Name",
|
||||
"manufacturer_optional": "Hersteller (optional)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Gib mehreren Sensoren denselben Objektnamen, dann werden sie ein Objekt; der Name eines vorhandenen Objekts ordnet sie dort zu.",
|
||||
"adopt_summary_title": "Was die Übernahme ändert",
|
||||
"adopt_summary_existing": "„{name}“: Aufgaben {before} → {after}",
|
||||
"adopt_summary_totals": "Aufgaben: {tasks} · Objekte: {objects}",
|
||||
"adopt_summary_totals_new": "Aufgaben: {tasks} · Objekte: {objects} (davon neu: {new})",
|
||||
"adopt_problem_adopt": "Auswahl übernehmen",
|
||||
"adopt_problem_done": "{tasks} Problem-Sensor(en) übernommen",
|
||||
"adopt_problem_done_one": "1 Problem-Sensor übernommen",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Batterie-Flotte eingerichtet — ein Task überwacht alle Batterien.",
|
||||
"update_banner": "Auf dem Server läuft eine neuere Version von Maintenance Supporter — neu laden, um das Panel zu aktualisieren.",
|
||||
"update_reload": "Neu laden",
|
||||
"restart_pending_banner": "Maintenance Supporter wurde auf {version} aktualisiert. Starte Home Assistant neu, um das Update abzuschließen.",
|
||||
"restart_pending_error": "Das hat nicht geklappt: Maintenance Supporter wurde auf {version} aktualisiert, Home Assistant aber seitdem nicht neu gestartet. Starte Home Assistant neu und versuche es dann noch einmal.",
|
||||
"row_actions_banner": "Erledigt und Überspringen sind in den Aufgabenzeilen jetzt Buttons. Lieber die alten Symbole?",
|
||||
"row_actions_keep": "Buttons behalten",
|
||||
"row_actions_back": "Zurück zu Symbolen",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Interval anchor",
|
||||
"anchor_completion": "From completion date",
|
||||
"anchor_planned": "From planned date (no drift)",
|
||||
"interval_anchor_hint": "From completion date: the next due date counts from the day the task is marked done, so doing it early or late moves the schedule. From planned date: the schedule keeps its dates, for example when a bill is paid weeks before it is due.",
|
||||
"edit_object": "Edit Object",
|
||||
"name": "Name",
|
||||
"manufacturer_optional": "Manufacturer (optional)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Give several sensors the same object name and they become one object; type an existing object's name to add them there.",
|
||||
"adopt_summary_title": "What adopting changes",
|
||||
"adopt_summary_existing": "\"{name}\": tasks {before} → {after}",
|
||||
"adopt_summary_totals": "Tasks: {tasks} · objects: {objects}",
|
||||
"adopt_summary_totals_new": "Tasks: {tasks} · objects: {objects} ({new} new)",
|
||||
"adopt_problem_adopt": "Adopt selected",
|
||||
"adopt_problem_done": "Adopted {tasks} problem sensor(s)",
|
||||
"adopt_problem_done_one": "Adopted 1 problem sensor",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Battery fleet set up — one task tracks all your batteries.",
|
||||
"update_banner": "A newer version of Maintenance Supporter is on the server — reload to update the panel.",
|
||||
"update_reload": "Reload",
|
||||
"restart_pending_banner": "Maintenance Supporter was updated to {version}. Restart Home Assistant to finish the update.",
|
||||
"restart_pending_error": "That did not work: Maintenance Supporter was updated to {version}, but Home Assistant has not been restarted since. Restart Home Assistant, then try again.",
|
||||
"row_actions_banner": "Complete and Skip in task rows are now buttons. Prefer the old icons?",
|
||||
"row_actions_keep": "Keep buttons",
|
||||
"row_actions_back": "Back to icons",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Anclaje del intervalo",
|
||||
"anchor_completion": "Desde la fecha de finalización",
|
||||
"anchor_planned": "Desde la fecha planificada (sin desviación)",
|
||||
"interval_anchor_hint": "Desde la fecha de finalización: el próximo vencimiento se cuenta desde el día en que se marca la tarea como hecha, así que hacerla antes o después mueve el calendario. Desde la fecha planificada: el calendario mantiene sus fechas, por ejemplo cuando una factura se paga semanas antes de su vencimiento.",
|
||||
"edit_object": "Editar objeto",
|
||||
"name": "Nombre",
|
||||
"manufacturer_optional": "Fabricante (opcional)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Da a varios sensores el mismo nombre de objeto y se convierten en un solo objeto; escribe el nombre de un objeto existente para añadirlos allí.",
|
||||
"adopt_summary_title": "Qué cambia al adoptar",
|
||||
"adopt_summary_existing": "«{name}»: tareas {before} → {after}",
|
||||
"adopt_summary_totals": "Tareas: {tasks} · objetos: {objects}",
|
||||
"adopt_summary_totals_new": "Tareas: {tasks} · objetos: {objects} (nuevos: {new})",
|
||||
"adopt_problem_adopt": "Adoptar seleccionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adoptado(s)",
|
||||
"adopt_problem_done_one": "1 sensor de problema adoptado",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Flota de baterías configurada — una tarea controla todas.",
|
||||
"update_banner": "Hay una versión más reciente de Maintenance Supporter en el servidor — recarga para actualizar el panel.",
|
||||
"update_reload": "Recargar",
|
||||
"restart_pending_banner": "Maintenance Supporter se actualizó a la versión {version}. Reinicia Home Assistant para completar la actualización.",
|
||||
"restart_pending_error": "No ha funcionado: Maintenance Supporter se actualizó a la versión {version}, pero Home Assistant no se ha reiniciado desde entonces. Reinicia Home Assistant y vuelve a intentarlo.",
|
||||
"row_actions_banner": "Completar y Omitir ahora son botones en las filas de tareas. ¿Prefieres los iconos antiguos?",
|
||||
"row_actions_keep": "Mantener botones",
|
||||
"row_actions_back": "Volver a los iconos",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Välin ankkuri",
|
||||
"anchor_completion": "Suorituspäivästä",
|
||||
"anchor_planned": "Suunnitellusta päivästä (ei poikkeamaa)",
|
||||
"interval_anchor_hint": "Suorituspäivästä: seuraava eräpäivä lasketaan päivästä, jolloin tehtävä merkitään tehdyksi, joten aikainen tai myöhäinen suoritus siirtää aikataulua. Suunnitellusta päivästä: aikataulu pitää päivänsä, esimerkiksi kun lasku maksetaan viikkoja ennen eräpäivää.",
|
||||
"edit_object": "Muokkaa kohdetta",
|
||||
"name": "Nimi",
|
||||
"manufacturer_optional": "Valmistaja (valinnainen)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Anna useille antureille sama kohteen nimi, niin niistä tulee yksi kohde; kirjoita olemassa olevan kohteen nimi lisätäksesi ne sinne.",
|
||||
"adopt_summary_title": "Mitä käyttöönotto muuttaa",
|
||||
"adopt_summary_existing": "\"{name}\": tehtävät {before} → {after}",
|
||||
"adopt_summary_totals": "Tehtäviä: {tasks} · kohteita: {objects}",
|
||||
"adopt_summary_totals_new": "Tehtäviä: {tasks} · kohteita: {objects} (uusia: {new})",
|
||||
"adopt_problem_adopt": "Ota valitut käyttöön",
|
||||
"adopt_problem_done": "Otettiin käyttöön {tasks} ongelma-anturia",
|
||||
"adopt_problem_done_one": "Otettiin käyttöön 1 ongelma-anturi",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Paristokanta määritetty — yksi tehtävä seuraa kaikkia.",
|
||||
"update_banner": "Palvelimella on uudempi Maintenance Supporter -versio — lataa uudelleen päivittääksesi paneelin.",
|
||||
"update_reload": "Lataa uudelleen",
|
||||
"restart_pending_banner": "Maintenance Supporter on päivitetty versioon {version}. Käynnistä Home Assistant uudelleen viimeistelläksesi päivityksen.",
|
||||
"restart_pending_error": "Se ei onnistunut: Maintenance Supporter on päivitetty versioon {version}, mutta Home Assistantia ei ole sen jälkeen käynnistetty uudelleen. Käynnistä Home Assistant uudelleen ja yritä sitten uudelleen.",
|
||||
"row_actions_banner": "Valmis ja Ohita ovat tehtäväriveillä nyt painikkeita. Haluatko mieluummin vanhat kuvakkeet?",
|
||||
"row_actions_keep": "Pidä painikkeet",
|
||||
"row_actions_back": "Takaisin kuvakkeisiin",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Ancrage de l'intervalle",
|
||||
"anchor_completion": "Depuis la date de réalisation",
|
||||
"anchor_planned": "Depuis la date prévue (sans dérive)",
|
||||
"interval_anchor_hint": "Depuis la date de réalisation : la prochaine échéance compte à partir du jour où la tâche est marquée comme faite, donc la faire en avance ou en retard décale le planning. Depuis la date prévue : le planning garde ses dates, par exemple quand une facture est payée des semaines avant son échéance.",
|
||||
"edit_object": "Modifier l'objet",
|
||||
"name": "Nom",
|
||||
"manufacturer_optional": "Fabricant (optionnel)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Donnez le même nom d'objet à plusieurs capteurs et ils forment un seul objet ; saisissez le nom d'un objet existant pour les y ajouter.",
|
||||
"adopt_summary_title": "Ce que l'adoption modifie",
|
||||
"adopt_summary_existing": "« {name} » : tâches {before} → {after}",
|
||||
"adopt_summary_totals": "Tâches : {tasks} · objets : {objects}",
|
||||
"adopt_summary_totals_new": "Tâches : {tasks} · objets : {objects} (dont nouveaux : {new})",
|
||||
"adopt_problem_adopt": "Adopter la sélection",
|
||||
"adopt_problem_done": "{tasks} capteur(s) de problème adopté(s)",
|
||||
"adopt_problem_done_one": "1 capteur de problème adopté",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Parc de piles configuré — une tâche suit toutes vos piles.",
|
||||
"update_banner": "Une version plus récente de Maintenance Supporter est sur le serveur — rechargez pour mettre à jour le panneau.",
|
||||
"update_reload": "Recharger",
|
||||
"restart_pending_banner": "Maintenance Supporter a été mis à jour vers la version {version}. Redémarrez Home Assistant pour terminer la mise à jour.",
|
||||
"restart_pending_error": "Cela n'a pas fonctionné : Maintenance Supporter a été mis à jour vers la version {version}, mais Home Assistant n'a pas été redémarré depuis. Redémarrez Home Assistant, puis réessayez.",
|
||||
"row_actions_banner": "Terminer et Ignorer sont désormais des boutons dans les lignes de tâches. Vous préférez les anciennes icônes ?",
|
||||
"row_actions_keep": "Garder les boutons",
|
||||
"row_actions_back": "Revenir aux icônes",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "अंतराल आधार",
|
||||
"anchor_completion": "पूर्ण तिथि से",
|
||||
"anchor_planned": "नियोजित तिथि से (कोई विचलन नहीं)",
|
||||
"interval_anchor_hint": "पूर्ण तिथि से: अगली देय तिथि उस दिन से गिनी जाती है जिस दिन कार्य पूरा चिह्नित किया जाता है, इसलिए पहले या देर से करने पर समय-सारणी खिसक जाती है। नियोजित तिथि से: समय-सारणी अपनी तिथियाँ बनाए रखती है, उदाहरण के लिए जब कोई बिल देय तिथि से हफ़्तों पहले चुकाया जाता है।",
|
||||
"edit_object": "वस्तु संपादित करें",
|
||||
"name": "नाम",
|
||||
"manufacturer_optional": "निर्माता (वैकल्पिक)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "कई सेंसरों को एक ही ऑब्जेक्ट नाम दें तो वे एक ऑब्जेक्ट बन जाते हैं; मौजूदा ऑब्जेक्ट का नाम लिखें तो वे वहीं जुड़ जाते हैं।",
|
||||
"adopt_summary_title": "अपनाने से क्या बदलेगा",
|
||||
"adopt_summary_existing": "\"{name}\": कार्य {before} → {after}",
|
||||
"adopt_summary_totals": "कार्य: {tasks} · ऑब्जेक्ट: {objects}",
|
||||
"adopt_summary_totals_new": "कार्य: {tasks} · ऑब्जेक्ट: {objects} (नए: {new})",
|
||||
"adopt_problem_adopt": "चयनित अपनाएँ",
|
||||
"adopt_problem_done": "{tasks} समस्या सेंसर अपनाए गए",
|
||||
"adopt_problem_done_one": "1 समस्या सेंसर अपनाया गया",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "बैटरी फ्लीट सेट — एक कार्य सभी बैटरियों को ट्रैक करता है।",
|
||||
"update_banner": "सर्वर पर Maintenance Supporter का नया संस्करण है — पैनल अपडेट करने के लिए पुनः लोड करें।",
|
||||
"update_reload": "पुनः लोड करें",
|
||||
"restart_pending_banner": "Maintenance Supporter को {version} संस्करण में अपडेट किया गया है। अपडेट पूरा करने के लिए Home Assistant को पुनः आरंभ करें।",
|
||||
"restart_pending_error": "यह नहीं हो सका: Maintenance Supporter को {version} संस्करण में अपडेट किया गया है, लेकिन उसके बाद से Home Assistant को पुनः आरंभ नहीं किया गया है। Home Assistant को पुनः आरंभ करें, फिर दोबारा प्रयास करें।",
|
||||
"row_actions_banner": "कार्य पंक्तियों में पूर्ण और छोड़ें अब बटन हैं। पुराने आइकन पसंद हैं?",
|
||||
"row_actions_keep": "बटन रखें",
|
||||
"row_actions_back": "आइकन पर वापस जाएँ",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Intervallum horgonya",
|
||||
"anchor_completion": "Az elvégzés dátumától",
|
||||
"anchor_planned": "A tervezett dátumtól (nincs csúszás)",
|
||||
"interval_anchor_hint": "Az elvégzés dátumától: a következő határidő attól a naptól számít, amikor a feladatot elvégzettnek jelölik, így a korábbi vagy későbbi elvégzés eltolja az ütemezést. A tervezett dátumtól: az ütemezés megtartja a dátumait, például ha egy számlát hetekkel a határidő előtt fizetnek be.",
|
||||
"edit_object": "Objektum szerkesztése",
|
||||
"name": "Név",
|
||||
"manufacturer_optional": "Gyártó (opcionális)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Adja több érzékelőnek ugyanazt az objektumnevet, és egy objektummá válnak; meglévő objektum nevét beírva oda kerülnek.",
|
||||
"adopt_summary_title": "Mit változtat az átvétel",
|
||||
"adopt_summary_existing": "„{name}”: feladatok {before} → {after}",
|
||||
"adopt_summary_totals": "Feladatok: {tasks} · objektumok: {objects}",
|
||||
"adopt_summary_totals_new": "Feladatok: {tasks} · objektumok: {objects} (ebből új: {new})",
|
||||
"adopt_problem_adopt": "Kijelöltek átvétele",
|
||||
"adopt_problem_done": "{tasks} problémaérzékelő átvéve",
|
||||
"adopt_problem_done_one": "1 problémaérzékelő átvéve",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Elemflotta beállítva — egyetlen feladat követi az összes elemet.",
|
||||
"update_banner": "A Maintenance Supporter újabb verziója érhető el a szerveren — töltse újra az oldalt a panel frissítéséhez.",
|
||||
"update_reload": "Újratöltés",
|
||||
"restart_pending_banner": "A Maintenance Supporter frissült a(z) {version} verzióra. Indítsa újra a Home Assistantot a frissítés befejezéséhez.",
|
||||
"restart_pending_error": "Ez nem sikerült: a Maintenance Supporter frissült a(z) {version} verzióra, de a Home Assistant azóta nem indult újra. Indítsa újra a Home Assistantot, majd próbálja újra.",
|
||||
"row_actions_banner": "A Kész és a Kihagyás a feladatsorokban mostantól gombok. Inkább a régi ikonokat szeretné?",
|
||||
"row_actions_keep": "Gombok megtartása",
|
||||
"row_actions_back": "Vissza az ikonokhoz",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Ancoraggio intervallo",
|
||||
"anchor_completion": "Dalla data di completamento",
|
||||
"anchor_planned": "Dalla data pianificata (nessuna deriva)",
|
||||
"interval_anchor_hint": "Dalla data di completamento: la prossima scadenza si conta dal giorno in cui l'attività viene segnata come fatta, quindi farla prima o dopo sposta la pianificazione. Dalla data pianificata: la pianificazione mantiene le sue date, per esempio quando una bolletta viene pagata settimane prima della scadenza.",
|
||||
"edit_object": "Modifica oggetto",
|
||||
"name": "Nome",
|
||||
"manufacturer_optional": "Produttore (opzionale)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Assegna lo stesso nome oggetto a più sensori e diventano un unico oggetto; digita il nome di un oggetto esistente per aggiungerli lì.",
|
||||
"adopt_summary_title": "Cosa cambia l'adozione",
|
||||
"adopt_summary_existing": "«{name}»: attività {before} → {after}",
|
||||
"adopt_summary_totals": "Attività: {tasks} · oggetti: {objects}",
|
||||
"adopt_summary_totals_new": "Attività: {tasks} · oggetti: {objects} (di cui nuovi: {new})",
|
||||
"adopt_problem_adopt": "Adotta selezionati",
|
||||
"adopt_problem_done": "{tasks} sensore/i di problema adottato/i",
|
||||
"adopt_problem_done_one": "1 sensore di problema adottato",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Parco batterie configurato — un'attività monitora tutte.",
|
||||
"update_banner": "Sul server è presente una versione più recente di Maintenance Supporter — ricarica per aggiornare il pannello.",
|
||||
"update_reload": "Ricarica",
|
||||
"restart_pending_banner": "Maintenance Supporter è stato aggiornato alla versione {version}. Riavvia Home Assistant per completare l'aggiornamento.",
|
||||
"restart_pending_error": "Non è andato a buon fine: Maintenance Supporter è stato aggiornato alla versione {version}, ma da allora Home Assistant non è stato riavviato. Riavvia Home Assistant e riprova.",
|
||||
"row_actions_banner": "Completa e Salta nelle righe delle attività ora sono pulsanti. Preferisci le vecchie icone?",
|
||||
"row_actions_keep": "Mantieni i pulsanti",
|
||||
"row_actions_back": "Torna alle icone",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "間隔の起点",
|
||||
"anchor_completion": "完了日から",
|
||||
"anchor_planned": "予定日から(ずれなし)",
|
||||
"interval_anchor_hint": "完了日から: 次の期限はタスクを完了にした日から数えるため、早く・遅く完了すると予定がずれます。予定日から: 予定は元の日付を保ちます。たとえば請求書を期限の数週間前に支払った場合です。",
|
||||
"edit_object": "対象を編集",
|
||||
"name": "名前",
|
||||
"manufacturer_optional": "メーカー(任意)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "複数のセンサーに同じオブジェクト名を付けると1つのオブジェクトになります。既存のオブジェクト名を入力すればそこに追加されます。",
|
||||
"adopt_summary_title": "取り込みで変わること",
|
||||
"adopt_summary_existing": "「{name}」: タスク {before} → {after}",
|
||||
"adopt_summary_totals": "タスク: {tasks} · オブジェクト: {objects}",
|
||||
"adopt_summary_totals_new": "タスク: {tasks} · オブジェクト: {objects}(うち新規: {new})",
|
||||
"adopt_problem_adopt": "選択を取り込む",
|
||||
"adopt_problem_done": "{tasks} 件の問題センサーを取り込みました",
|
||||
"adopt_problem_done_one": "1 件の問題センサーを取り込みました",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "電池フリートを設定 — 1つのタスクで全電池を管理。",
|
||||
"update_banner": "サーバーに新しいバージョンの Maintenance Supporter があります — 再読み込みしてパネルを更新してください。",
|
||||
"update_reload": "再読み込み",
|
||||
"restart_pending_banner": "Maintenance Supporter はバージョン {version} に更新されました。更新を完了するには Home Assistant を再起動してください。",
|
||||
"restart_pending_error": "実行できませんでした: Maintenance Supporter はバージョン {version} に更新されましたが、その後 Home Assistant が再起動されていません。Home Assistant を再起動してから、もう一度お試しください。",
|
||||
"row_actions_banner": "タスク行の「完了」と「スキップ」がボタンになりました。以前のアイコンに戻しますか?",
|
||||
"row_actions_keep": "ボタンのままにする",
|
||||
"row_actions_back": "アイコンに戻す",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "주기 기준",
|
||||
"anchor_completion": "완료일 기준",
|
||||
"anchor_planned": "예정일 기준 (밀림 없음)",
|
||||
"interval_anchor_hint": "완료일 기준: 다음 예정일은 작업을 완료로 표시한 날부터 계산되므로, 일찍 또는 늦게 완료하면 일정이 바뀝니다. 예정일 기준: 일정이 원래 날짜를 유지합니다. 예를 들어 청구서를 기한보다 몇 주 일찍 납부한 경우입니다.",
|
||||
"edit_object": "객체 편집",
|
||||
"name": "이름",
|
||||
"manufacturer_optional": "제조사 (선택)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "여러 센서에 같은 개체 이름을 주면 하나의 개체가 됩니다. 기존 개체 이름을 입력하면 거기에 추가됩니다.",
|
||||
"adopt_summary_title": "가져오기로 바뀌는 점",
|
||||
"adopt_summary_existing": "\"{name}\": 작업 {before} → {after}",
|
||||
"adopt_summary_totals": "작업: {tasks} · 객체: {objects}",
|
||||
"adopt_summary_totals_new": "작업: {tasks} · 객체: {objects} (새 객체: {new})",
|
||||
"adopt_problem_adopt": "선택 항목 가져오기",
|
||||
"adopt_problem_done": "문제 센서 {tasks}개를 가져왔습니다",
|
||||
"adopt_problem_done_one": "문제 센서 1개를 가져왔습니다",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "배터리 플릿이 설정되었습니다 — 하나의 작업이 모든 배터리를 추적합니다.",
|
||||
"update_banner": "서버에 Maintenance Supporter의 새 버전이 있습니다 — 패널을 업데이트하려면 새로 고침하세요.",
|
||||
"update_reload": "새로 고침",
|
||||
"restart_pending_banner": "Maintenance Supporter가 {version} 버전으로 업데이트되었습니다. 업데이트를 완료하려면 Home Assistant를 다시 시작하세요.",
|
||||
"restart_pending_error": "실패했습니다: Maintenance Supporter가 {version} 버전으로 업데이트되었지만 그 이후 Home Assistant가 다시 시작되지 않았습니다. Home Assistant를 다시 시작한 후 다시 시도하세요.",
|
||||
"row_actions_banner": "작업 행의 완료와 건너뛰기가 이제 버튼으로 표시됩니다. 이전 아이콘이 더 좋으신가요?",
|
||||
"row_actions_keep": "버튼 유지",
|
||||
"row_actions_back": "아이콘으로 되돌리기",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Intervallforankring",
|
||||
"anchor_completion": "Fra fullføringsdato",
|
||||
"anchor_planned": "Fra planlagt dato (ingen avdrift)",
|
||||
"interval_anchor_hint": "Fra fullføringsdato: neste forfallsdato regnes fra dagen oppgaven markeres som utført, så tidlig eller sen utførelse flytter planen. Fra planlagt dato: planen beholder datoene sine, for eksempel når en regning betales uker før forfall.",
|
||||
"edit_object": "Rediger objekt",
|
||||
"name": "Navn",
|
||||
"manufacturer_optional": "Produsent (valgfritt)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Gi flere sensorer samme objektnavn, så blir de ett objekt; skriv navnet på et eksisterende objekt for å legge dem der.",
|
||||
"adopt_summary_title": "Hva overtakelsen endrer",
|
||||
"adopt_summary_existing": "«{name}»: oppgaver {before} → {after}",
|
||||
"adopt_summary_totals": "Oppgaver: {tasks} · objekter: {objects}",
|
||||
"adopt_summary_totals_new": "Oppgaver: {tasks} · objekter: {objects} (herav nye: {new})",
|
||||
"adopt_problem_adopt": "Ta i bruk valgte",
|
||||
"adopt_problem_done": "Tok i bruk {tasks} problemsensor(er)",
|
||||
"adopt_problem_done_one": "Tok i bruk 1 problemsensor",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Batteriflåte satt opp — én oppgave følger alle batteriene.",
|
||||
"update_banner": "En nyere versjon av Maintenance Supporter er på serveren — last inn på nytt for å oppdatere panelet.",
|
||||
"update_reload": "Last inn på nytt",
|
||||
"restart_pending_banner": "Maintenance Supporter er oppdatert til {version}. Start Home Assistant på nytt for å fullføre oppdateringen.",
|
||||
"restart_pending_error": "Det fungerte ikke: Maintenance Supporter er oppdatert til {version}, men Home Assistant er ikke startet på nytt siden. Start Home Assistant på nytt, og prøv igjen.",
|
||||
"row_actions_banner": "Fullfør og Hopp over er nå knapper i oppgaveradene. Foretrekker du de gamle ikonene?",
|
||||
"row_actions_keep": "Behold knapper",
|
||||
"row_actions_back": "Tilbake til ikoner",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Interval-anker",
|
||||
"anchor_completion": "Vanaf voltooiing",
|
||||
"anchor_planned": "Vanaf geplande datum (geen drift)",
|
||||
"interval_anchor_hint": "Vanaf voltooiing: de volgende vervaldatum telt vanaf de dag waarop de taak als gedaan wordt gemarkeerd, dus eerder of later uitvoeren verschuift de planning. Vanaf geplande datum: de planning houdt haar data, bijvoorbeeld wanneer een rekening weken voor de vervaldatum wordt betaald.",
|
||||
"edit_object": "Object bewerken",
|
||||
"name": "Naam",
|
||||
"manufacturer_optional": "Fabrikant (optioneel)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Geef meerdere sensoren dezelfde objectnaam en ze worden één object; typ de naam van een bestaand object om ze daar toe te voegen.",
|
||||
"adopt_summary_title": "Wat overnemen verandert",
|
||||
"adopt_summary_existing": "\"{name}\": taken {before} → {after}",
|
||||
"adopt_summary_totals": "Taken: {tasks} · objecten: {objects}",
|
||||
"adopt_summary_totals_new": "Taken: {tasks} · objecten: {objects} (waarvan nieuw: {new})",
|
||||
"adopt_problem_adopt": "Selectie overnemen",
|
||||
"adopt_problem_done": "{tasks} probleemsensor(en) overgenomen",
|
||||
"adopt_problem_done_one": "1 probleemsensor overgenomen",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Batterijvloot ingesteld — één taak volgt al je batterijen.",
|
||||
"update_banner": "Er staat een nieuwere versie van Maintenance Supporter op de server — herlaad om het paneel bij te werken.",
|
||||
"update_reload": "Herladen",
|
||||
"restart_pending_banner": "Maintenance Supporter is bijgewerkt naar {version}. Start Home Assistant opnieuw op om de update te voltooien.",
|
||||
"restart_pending_error": "Dat is niet gelukt: Maintenance Supporter is bijgewerkt naar {version}, maar Home Assistant is sindsdien niet opnieuw opgestart. Start Home Assistant opnieuw op en probeer het dan nog eens.",
|
||||
"row_actions_banner": "Voltooien en Overslaan zijn in taakrijen nu knoppen. Liever de oude pictogrammen?",
|
||||
"row_actions_keep": "Knoppen houden",
|
||||
"row_actions_back": "Terug naar pictogrammen",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Punkt zaczepienia interwału",
|
||||
"anchor_completion": "Od daty wykonania",
|
||||
"anchor_planned": "Od daty planowanej (bez przesunięć)",
|
||||
"interval_anchor_hint": "Od daty wykonania: następny termin liczy się od dnia oznaczenia zadania jako wykonanego, więc wcześniejsze lub późniejsze wykonanie przesuwa harmonogram. Od daty planowanej: harmonogram zachowuje swoje daty, na przykład gdy rachunek zostaje opłacony kilka tygodni przed terminem.",
|
||||
"edit_object": "Edytuj obiekt",
|
||||
"name": "Nazwa",
|
||||
"manufacturer_optional": "Producent (opcjonalne)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Nadaj kilku czujnikom tę samą nazwę obiektu, a staną się jednym obiektem; wpisz nazwę istniejącego obiektu, aby je tam dodać.",
|
||||
"adopt_summary_title": "Co zmieni przejęcie",
|
||||
"adopt_summary_existing": "„{name}”: zadania {before} → {after}",
|
||||
"adopt_summary_totals": "Zadania: {tasks} · obiekty: {objects}",
|
||||
"adopt_summary_totals_new": "Zadania: {tasks} · obiekty: {objects} (w tym nowe: {new})",
|
||||
"adopt_problem_adopt": "Przejmij zaznaczone",
|
||||
"adopt_problem_done": "Przejęto {tasks} czujnik(ów) problemów",
|
||||
"adopt_problem_done_one": "Przejęto 1 czujnik problemów",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Flota baterii skonfigurowana — jedno zadanie śledzi wszystkie.",
|
||||
"update_banner": "Na serwerze jest nowsza wersja Maintenance Supporter — załaduj ponownie, aby zaktualizować panel.",
|
||||
"update_reload": "Załaduj ponownie",
|
||||
"restart_pending_banner": "Maintenance Supporter został zaktualizowany do wersji {version}. Uruchom ponownie Home Assistant, aby dokończyć aktualizację.",
|
||||
"restart_pending_error": "Nie udało się: Maintenance Supporter został zaktualizowany do wersji {version}, ale od tego czasu Home Assistant nie został uruchomiony ponownie. Uruchom ponownie Home Assistant i spróbuj jeszcze raz.",
|
||||
"row_actions_banner": "Ukończ i Pomiń w wierszach zadań są teraz przyciskami. Wolisz stare ikony?",
|
||||
"row_actions_keep": "Zachowaj przyciski",
|
||||
"row_actions_back": "Wróć do ikon",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Âncora do intervalo",
|
||||
"anchor_completion": "A partir da data de conclusão",
|
||||
"anchor_planned": "A partir da data planejada (sem deriva)",
|
||||
"interval_anchor_hint": "A partir da data de conclusão: o próximo vencimento conta a partir do dia em que a tarefa é marcada como feita, então fazê-la antes ou depois desloca o cronograma. A partir da data planejada: o cronograma mantém suas datas, por exemplo quando uma conta é paga semanas antes do vencimento.",
|
||||
"edit_object": "Editar objeto",
|
||||
"name": "Nome",
|
||||
"manufacturer_optional": "Fabricante (opcional)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Dê a vários sensores o mesmo nome de objeto e eles viram um único objeto; digite o nome de um objeto existente para adicioná-los lá.",
|
||||
"adopt_summary_title": "O que a adoção muda",
|
||||
"adopt_summary_existing": "\"{name}\": tarefas {before} → {after}",
|
||||
"adopt_summary_totals": "Tarefas: {tasks} · objetos: {objects}",
|
||||
"adopt_summary_totals_new": "Tarefas: {tasks} · objetos: {objects} (novos: {new})",
|
||||
"adopt_problem_adopt": "Adotar selecionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adotado(s)",
|
||||
"adopt_problem_done_one": "1 sensor de problema adotado",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Frota de baterias configurada — uma única tarefa acompanha todas as suas baterias.",
|
||||
"update_banner": "Há uma versão mais nova do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
||||
"update_reload": "Recarregar",
|
||||
"restart_pending_banner": "O Maintenance Supporter foi atualizado para a versão {version}. Reinicie o Home Assistant para finalizar a atualização.",
|
||||
"restart_pending_error": "Não deu certo: o Maintenance Supporter foi atualizado para a versão {version}, mas o Home Assistant ainda não foi reiniciado. Reinicie o Home Assistant e tente de novo.",
|
||||
"row_actions_banner": "Concluir e Pular agora são botões nas linhas de tarefas. Prefere os ícones antigos?",
|
||||
"row_actions_keep": "Manter botões",
|
||||
"row_actions_back": "Voltar aos ícones",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Âncora do intervalo",
|
||||
"anchor_completion": "A partir da data de conclusão",
|
||||
"anchor_planned": "A partir da data planeada (sem desvio)",
|
||||
"interval_anchor_hint": "A partir da data de conclusão: o próximo vencimento conta a partir do dia em que a tarefa é marcada como feita, por isso fazê-la antes ou depois desloca o calendário. A partir da data planeada: o calendário mantém as suas datas, por exemplo quando uma fatura é paga semanas antes do vencimento.",
|
||||
"edit_object": "Editar objeto",
|
||||
"name": "Nome",
|
||||
"manufacturer_optional": "Fabricante (opcional)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Dê a vários sensores o mesmo nome de objeto e tornam-se um só objeto; escreva o nome de um objeto existente para os juntar lá.",
|
||||
"adopt_summary_title": "O que a adoção altera",
|
||||
"adopt_summary_existing": "«{name}»: tarefas {before} → {after}",
|
||||
"adopt_summary_totals": "Tarefas: {tasks} · objetos: {objects}",
|
||||
"adopt_summary_totals_new": "Tarefas: {tasks} · objetos: {objects} (novos: {new})",
|
||||
"adopt_problem_adopt": "Adotar selecionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adotado(s)",
|
||||
"adopt_problem_done_one": "1 sensor de problema adotado",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Frota de baterias configurada — uma tarefa acompanha todas.",
|
||||
"update_banner": "Há uma versão mais recente do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
||||
"update_reload": "Recarregar",
|
||||
"restart_pending_banner": "O Maintenance Supporter foi atualizado para a versão {version}. Reinicie o Home Assistant para concluir a atualização.",
|
||||
"restart_pending_error": "Não foi possível: o Maintenance Supporter foi atualizado para a versão {version}, mas o Home Assistant ainda não foi reiniciado. Reinicie o Home Assistant e tente novamente.",
|
||||
"row_actions_banner": "Concluir e Ignorar são agora botões nas linhas de tarefas. Prefere os ícones antigos?",
|
||||
"row_actions_keep": "Manter botões",
|
||||
"row_actions_back": "Voltar aos ícones",
|
||||
|
||||
@@ -249,6 +249,7 @@
|
||||
"interval_anchor": "Якорь интервала",
|
||||
"anchor_completion": "От даты выполнения",
|
||||
"anchor_planned": "От плановой даты (без смещения)",
|
||||
"interval_anchor_hint": "От даты выполнения: следующий срок отсчитывается от дня, когда задача отмечена выполненной, поэтому раннее или позднее выполнение сдвигает график. От плановой даты: график сохраняет свои даты, например когда счёт оплачен за несколько недель до срока.",
|
||||
"edit_object": "Изменить объект",
|
||||
"name": "Имя",
|
||||
"manufacturer_optional": "Производитель (опционально)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Дайте нескольким датчикам одно имя объекта — они станут одним объектом; введите имя существующего объекта, чтобы добавить их туда.",
|
||||
"adopt_summary_title": "Что изменит добавление",
|
||||
"adopt_summary_existing": "«{name}»: задачи {before} → {after}",
|
||||
"adopt_summary_totals": "Задачи: {tasks} · объекты: {objects}",
|
||||
"adopt_summary_totals_new": "Задачи: {tasks} · объекты: {objects} (из них новых: {new})",
|
||||
"adopt_problem_adopt": "Принять выбранные",
|
||||
"adopt_problem_done": "Принято сенсоров проблем: {tasks}",
|
||||
"adopt_problem_done_one": "Принят 1 сенсор проблем",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Парк батарей настроен — одна задача следит за всеми.",
|
||||
"update_banner": "На сервере более новая версия Maintenance Supporter — перезагрузите, чтобы обновить панель.",
|
||||
"update_reload": "Перезагрузить",
|
||||
"restart_pending_banner": "Maintenance Supporter обновлён до версии {version}. Перезапустите Home Assistant, чтобы завершить обновление.",
|
||||
"restart_pending_error": "Не получилось: Maintenance Supporter обновлён до версии {version}, но Home Assistant с тех пор не перезапускался. Перезапустите Home Assistant и попробуйте ещё раз.",
|
||||
"row_actions_banner": "«Выполнено» и «Пропустить» в строках задач теперь кнопки. Предпочитаете старые значки?",
|
||||
"row_actions_keep": "Оставить кнопки",
|
||||
"row_actions_back": "Вернуть значки",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Intervallankare",
|
||||
"anchor_completion": "Från slutförandedatum",
|
||||
"anchor_planned": "Från planerat datum (ingen drift)",
|
||||
"interval_anchor_hint": "Från slutförandedatum: nästa förfallodatum räknas från dagen då uppgiften markeras som utförd, så att göra den tidigt eller sent flyttar schemat. Från planerat datum: schemat behåller sina datum, till exempel när en räkning betalas veckor före förfallodagen.",
|
||||
"edit_object": "Redigera objekt",
|
||||
"name": "Namn",
|
||||
"manufacturer_optional": "Tillverkare (valfritt)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Ge flera sensorer samma objektnamn så blir de ett objekt; skriv ett befintligt objekts namn för att lägga dem där.",
|
||||
"adopt_summary_title": "Vad övertagandet ändrar",
|
||||
"adopt_summary_existing": "”{name}”: uppgifter {before} → {after}",
|
||||
"adopt_summary_totals": "Uppgifter: {tasks} · objekt: {objects}",
|
||||
"adopt_summary_totals_new": "Uppgifter: {tasks} · objekt: {objects} (varav nya: {new})",
|
||||
"adopt_problem_adopt": "Anta valda",
|
||||
"adopt_problem_done": "Antog {tasks} problemsensor(er)",
|
||||
"adopt_problem_done_one": "Antog 1 problemsensor",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Batteriflotta konfigurerad — en uppgift följer alla batterier.",
|
||||
"update_banner": "En nyare version av Maintenance Supporter finns på servern — ladda om för att uppdatera panelen.",
|
||||
"update_reload": "Ladda om",
|
||||
"restart_pending_banner": "Maintenance Supporter har uppdaterats till {version}. Starta om Home Assistant för att slutföra uppdateringen.",
|
||||
"restart_pending_error": "Det fungerade inte: Maintenance Supporter har uppdaterats till {version}, men Home Assistant har inte startats om sedan dess. Starta om Home Assistant och försök igen.",
|
||||
"row_actions_banner": "Slutför och Hoppa över är nu knappar i uppgiftsraderna. Föredrar du de gamla ikonerna?",
|
||||
"row_actions_keep": "Behåll knappar",
|
||||
"row_actions_back": "Tillbaka till ikoner",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Aralık referansı",
|
||||
"anchor_completion": "Tamamlama tarihinden",
|
||||
"anchor_planned": "Planlanan tarihten (kayma olmaz)",
|
||||
"interval_anchor_hint": "Tamamlama tarihinden: sonraki vade, görevin yapıldı olarak işaretlendiği günden itibaren sayılır; bu yüzden erken veya geç yapmak planı kaydırır. Planlanan tarihten: plan tarihlerini korur; örneğin bir fatura vadesinden haftalar önce ödendiğinde.",
|
||||
"edit_object": "Nesneyi Düzenle",
|
||||
"name": "Ad",
|
||||
"manufacturer_optional": "Üretici (isteğe bağlı)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Birden çok sensöre aynı nesne adını verin, tek nesne olurlar; mevcut bir nesnenin adını yazarsanız oraya eklenirler.",
|
||||
"adopt_summary_title": "Devralmanın değiştirecekleri",
|
||||
"adopt_summary_existing": "\"{name}\": görevler {before} → {after}",
|
||||
"adopt_summary_totals": "Görevler: {tasks} · nesneler: {objects}",
|
||||
"adopt_summary_totals_new": "Görevler: {tasks} · nesneler: {objects} (yeni: {new})",
|
||||
"adopt_problem_adopt": "Seçilenleri devral",
|
||||
"adopt_problem_done": "{tasks} sorun sensörü devralındı",
|
||||
"adopt_problem_done_one": "1 sorun sensörü devralındı",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Pil filosu kuruldu — tek bir görev tüm pillerinizi takip ediyor.",
|
||||
"update_banner": "Sunucuda Maintenance Supporter'ın daha yeni bir sürümü var — paneli güncellemek için sayfayı yeniden yükleyin.",
|
||||
"update_reload": "Yeniden yükle",
|
||||
"restart_pending_banner": "Maintenance Supporter {version} sürümüne güncellendi. Güncellemeyi tamamlamak için Home Assistant'ı yeniden başlatın.",
|
||||
"restart_pending_error": "Bu işlem başarısız oldu: Maintenance Supporter {version} sürümüne güncellendi, ancak Home Assistant o zamandan beri yeniden başlatılmadı. Home Assistant'ı yeniden başlatın ve tekrar deneyin.",
|
||||
"row_actions_banner": "Görev satırlarındaki Tamamla ve Atla artık düğme. Eski simgeleri mi tercih edersiniz?",
|
||||
"row_actions_keep": "Düğmeleri koru",
|
||||
"row_actions_back": "Simgelere geri dön",
|
||||
|
||||
@@ -249,6 +249,7 @@
|
||||
"interval_anchor": "Прив'язка інтервалу",
|
||||
"anchor_completion": "Від дати виконання",
|
||||
"anchor_planned": "Від запланованої дати (без зміщення)",
|
||||
"interval_anchor_hint": "Від дати виконання: наступний термін відраховується від дня, коли завдання позначено виконаним, тож раннє чи пізнє виконання зсуває графік. Від запланованої дати: графік зберігає свої дати, наприклад коли рахунок сплачено за кілька тижнів до терміну.",
|
||||
"edit_object": "Редагувати об'єкт",
|
||||
"name": "Назва",
|
||||
"manufacturer_optional": "Виробник (необов'язково)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Дайте кільком сенсорам однакову назву об'єкта — вони стануть одним об'єктом; введіть назву наявного об'єкта, щоб додати їх туди.",
|
||||
"adopt_summary_title": "Що змінить додавання",
|
||||
"adopt_summary_existing": "«{name}»: завдання {before} → {after}",
|
||||
"adopt_summary_totals": "Завдання: {tasks} · об'єкти: {objects}",
|
||||
"adopt_summary_totals_new": "Завдання: {tasks} · об'єкти: {objects} (з них нових: {new})",
|
||||
"adopt_problem_adopt": "Прийняти вибрані",
|
||||
"adopt_problem_done": "Прийнято сенсорів проблем: {tasks}",
|
||||
"adopt_problem_done_one": "Прийнято 1 сенсор проблем",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Парк батарей налаштовано — одне завдання стежить за всіма.",
|
||||
"update_banner": "На сервері новіша версія Maintenance Supporter — перезавантажте, щоб оновити панель.",
|
||||
"update_reload": "Перезавантажити",
|
||||
"restart_pending_banner": "Maintenance Supporter оновлено до версії {version}. Перезапустіть Home Assistant, щоб завершити оновлення.",
|
||||
"restart_pending_error": "Не вдалося: Maintenance Supporter оновлено до версії {version}, але Home Assistant відтоді не перезапускався. Перезапустіть Home Assistant і спробуйте ще раз.",
|
||||
"row_actions_banner": "«Виконано» та «Пропустити» в рядках завдань тепер кнопки. Бажаєте старі значки?",
|
||||
"row_actions_keep": "Залишити кнопки",
|
||||
"row_actions_back": "Повернути значки",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "计划锚点",
|
||||
"anchor_completion": "从完成日期起算",
|
||||
"anchor_planned": "从计划日期起算 (无偏差)",
|
||||
"interval_anchor_hint": "从完成日期起算:下一个到期日从任务标记为完成的那天开始计算,因此提前或推迟完成都会移动计划。从计划日期起算:计划保持原定日期,例如账单在到期前几周就已支付时。",
|
||||
"edit_object": "编辑维护项",
|
||||
"name": "名称",
|
||||
"manufacturer_optional": "制造商 (可选)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "给多个传感器相同的对象名称,它们就会合并为一个对象;输入已有对象的名称即可加入该对象。",
|
||||
"adopt_summary_title": "采用后会发生的变化",
|
||||
"adopt_summary_existing": "“{name}”:任务 {before} → {after}",
|
||||
"adopt_summary_totals": "任务:{tasks} · 对象:{objects}",
|
||||
"adopt_summary_totals_new": "任务:{tasks} · 对象:{objects}(其中新建:{new})",
|
||||
"adopt_problem_adopt": "采用所选",
|
||||
"adopt_problem_done": "已采用 {tasks} 个问题传感器",
|
||||
"adopt_problem_done_one": "已采用 1 个问题传感器",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "电池群已设置 — 一个任务跟踪所有电池。",
|
||||
"update_banner": "服务器上有更新版本的 Maintenance Supporter——请重新加载以更新面板。",
|
||||
"update_reload": "重新加载",
|
||||
"restart_pending_banner": "Maintenance Supporter 已更新到 {version} 版本。请重启 Home Assistant 以完成更新。",
|
||||
"restart_pending_error": "操作失败:Maintenance Supporter 已更新到 {version} 版本,但 Home Assistant 此后尚未重启。请重启 Home Assistant 后重试。",
|
||||
"row_actions_banner": "任务行中的“完成”和“跳过”现在是按钮。更喜欢旧的图标?",
|
||||
"row_actions_keep": "保留按钮",
|
||||
"row_actions_back": "改回图标",
|
||||
|
||||
@@ -5,7 +5,7 @@ import { isSafeLink } from "./helpers/url";
|
||||
import { queryTokens, scoreFields } from "./helpers/search-match";
|
||||
import { objectRef, parseRef, renderRefChip, taskRef, type HasRef } from "./helpers/reference";
|
||||
import { applySubscriptionEvent, type SubscriptionEvent } from "./helpers/subscription-merge";
|
||||
import { isStaleBundle } from "./helpers/bundle-version";
|
||||
import { isStaleBundle, pendingRestartVersion, type ServerVersion } from "./helpers/bundle-version";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { syncLocaleFromHass, sharedStyles, STATUS_COLORS, currencySymbolOf, t, ensureLocale, isLocaleLoaded, formatDate, formatDueDays, formatInterval, formatRecurrence, setProfilePrefs, langOf, formatCost, formatQty, syncCurrencyDecimals} from "./styles";
|
||||
import { OVERVIEW_TABS, type OverviewTab } from "./helpers/overview-tabs";
|
||||
@@ -313,7 +313,11 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
// and the fleet isn't set up yet.
|
||||
@state() private _batteryFleetSetupAvailable = false;
|
||||
@state() private _staleBundle = false;
|
||||
/** The version an update installed while Home Assistant still runs the
|
||||
* old code (helpers/update_state.py); null when both agree. */
|
||||
@state() private _restartPendingVersion: string | null = null;
|
||||
private _staleChecked = false;
|
||||
private _onReconnect = (): void => this._checkServerVersion();
|
||||
private _toastTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
private _dismissedSuggestions = new Set<string>();
|
||||
|
||||
@@ -408,7 +412,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
private _statsService: StatisticsService | null = null;
|
||||
private _userService: UserService | null = null;
|
||||
private _dataLoaded = false;
|
||||
private _lastConnection: unknown = null;
|
||||
private _lastConnection: HomeAssistant["connection"] | null = null;
|
||||
|
||||
private get _lang(): string {
|
||||
return langOf(this.hass);
|
||||
@@ -553,7 +557,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
}
|
||||
this._dataLoaded = false;
|
||||
this._initialLoadDone = false;
|
||||
this._lastConnection = null;
|
||||
this._watchConnection(null);
|
||||
this._deepLinkHandled = false;
|
||||
// `_presetsApplied` intentionally survives (see its declaration).
|
||||
// Pending timers must not fire into a detached element (bug audit
|
||||
@@ -582,13 +586,13 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
if (changedProps.has("hass") && this.hass) {
|
||||
if (!this._dataLoaded) {
|
||||
this._dataLoaded = true;
|
||||
this._lastConnection = this.hass.connection;
|
||||
this._watchConnection(this.hass.connection);
|
||||
// Seed initial history state so back button returns to overview
|
||||
history.replaceState({ msp_view: "overview", msp_entry: null, msp_task: null }, "");
|
||||
this._loadData();
|
||||
this._subscribe();
|
||||
} else if (this.hass.connection !== this._lastConnection) {
|
||||
this._lastConnection = this.hass.connection;
|
||||
this._watchConnection(this.hass.connection);
|
||||
if (this._unsub) {
|
||||
try { this._unsub(); } catch { /* ignore */ }
|
||||
this._unsub = null;
|
||||
@@ -743,6 +747,31 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
/** Follow `conn`'s reconnects for the version check (and stop following
|
||||
* the previous connection). */
|
||||
private _watchConnection(conn: HomeAssistant["connection"] | null): void {
|
||||
this._lastConnection?.removeEventListener?.("ready", this._onReconnect);
|
||||
this._lastConnection = conn;
|
||||
conn?.addEventListener?.("ready", this._onReconnect);
|
||||
}
|
||||
|
||||
/** Stale-bundle handshake (roadmap guard 2): compare the version esbuild
|
||||
* stamped into this bundle with the backend's — a mismatch means the
|
||||
* browser/service worker is still serving an OLD cached frontend, and no
|
||||
* amount of HA restarts fixes that. Unless an update waits for its
|
||||
* restart: then that explains any difference, and only the restart helps. */
|
||||
private _checkServerVersion(): void {
|
||||
this.hass.connection
|
||||
.sendMessagePromise<ServerVersion>({ type: "maintenance_supporter/version" })
|
||||
.then((v) => {
|
||||
this._restartPendingVersion = pendingRestartVersion(v);
|
||||
this._staleBundle = !this._restartPendingVersion && isStaleBundle(v?.version);
|
||||
})
|
||||
.catch(() => {
|
||||
/* backend too old to answer — no banner */
|
||||
});
|
||||
}
|
||||
|
||||
private async _loadData(): Promise<void> {
|
||||
const [objResult, statsResult, budgetResult, groupsResult, settingsResult, viewsResult] = await Promise.all([
|
||||
this.hass.connection.sendMessagePromise({ type: "maintenance_supporter/objects", compact: true }).catch(() => null),
|
||||
@@ -780,20 +809,11 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
.catch(() => {
|
||||
this._batteryFleetSetupAvailable = false;
|
||||
});
|
||||
// Stale-bundle handshake (roadmap guard 2): compare the version esbuild
|
||||
// stamped into this bundle with the backend's — a mismatch means the
|
||||
// browser/service worker is still serving an OLD cached frontend, and no
|
||||
// amount of HA restarts fixes that. Checked once per panel lifetime.
|
||||
// Checked once per panel lifetime, and again after every reconnect (a
|
||||
// Home Assistant restart ends the "restart pending" state).
|
||||
if (!this._staleChecked) {
|
||||
this._staleChecked = true;
|
||||
this.hass.connection
|
||||
.sendMessagePromise<{ version: string }>({ type: "maintenance_supporter/version" })
|
||||
.then((v) => {
|
||||
this._staleBundle = isStaleBundle(v?.version);
|
||||
})
|
||||
.catch(() => {
|
||||
/* backend too old to answer — no banner */
|
||||
});
|
||||
this._checkServerVersion();
|
||||
}
|
||||
if (statsResult) this._stats = statsResult as StatisticsResponse;
|
||||
if (budgetResult) { this._budget = budgetResult as BudgetStatus; syncCurrencyDecimals(this._budget); }
|
||||
@@ -1272,6 +1292,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
labels: task.labels ?? [],
|
||||
area_id: obj.object.area_id ?? null,
|
||||
responsible_user_id: task.responsible_user_id ?? null,
|
||||
assignee_pool: task.assignee_pool ?? null,
|
||||
group_names: groupNames,
|
||||
});
|
||||
}
|
||||
@@ -1281,8 +1302,11 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
const byDue = (a: TaskRow, b: TaskRow) => byStatus(a, b) || byDays(a, b);
|
||||
const areaName = (r: TaskRow) =>
|
||||
r.area_id ? this.hass?.areas?.[r.area_id]?.name || "" : "";
|
||||
const userName = (r: TaskRow) =>
|
||||
r.responsible_user_id ? this._userService?.getUserName(r.responsible_user_id) || "" : "";
|
||||
// Whom the task is meant for, as the person filter reads it (D#110):
|
||||
// the responsible person, else everyone it is shared with.
|
||||
const userNames = (r: TaskRow) =>
|
||||
taskUserIds(r).map((id) => this._userService?.getUserName(id) || "").filter(Boolean);
|
||||
const userName = (r: TaskRow) => userNames(r).sort((a, b) => a.localeCompare(b)).join(", ");
|
||||
const groupName = (r: TaskRow) => r.group_names[0] || "";
|
||||
const sorts: Record<SortMode, (a: TaskRow, b: TaskRow) => number> = {
|
||||
due_date: byDue,
|
||||
@@ -3172,6 +3196,14 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
render() {
|
||||
return html`
|
||||
<div class="panel">
|
||||
${this._restartPendingVersion
|
||||
? html`
|
||||
<div class="update-banner restart-pending-banner" role="status">
|
||||
<ha-icon icon="mdi:restart"></ha-icon>
|
||||
<span>${t("restart_pending_banner", this._lang).replace("{version}", this._restartPendingVersion)}</span>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
${this._staleBundle
|
||||
? html`
|
||||
<div class="update-banner" role="status">
|
||||
@@ -3906,8 +3938,10 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
const a = row.area_id ? this.hass?.areas?.[row.area_id]?.name : null;
|
||||
keys = [a || noneLabel];
|
||||
} else if (this._groupByMode === "user") {
|
||||
const u = row.responsible_user_id ? this._userService?.getUserName(row.responsible_user_id) : null;
|
||||
keys = [u || noneLabel];
|
||||
// A shared task with nobody responsible is listed under each of its
|
||||
// people, as the person filter lists it (D#110).
|
||||
const names = taskUserIds(row).map((id) => this._userService?.getUserName(id)).filter((n): n is string => !!n);
|
||||
keys = names.length > 0 ? [...new Set(names)] : [noneLabel];
|
||||
} else if (this._groupByMode === "group") {
|
||||
keys = row.group_names.length > 0 ? row.group_names : [noneLabel];
|
||||
} else if (this._groupByMode === "object") {
|
||||
|
||||
@@ -633,6 +633,8 @@ export interface TaskRow {
|
||||
labels: string[];
|
||||
area_id: string | null;
|
||||
responsible_user_id: string | null;
|
||||
/** "Shared with": with nobody responsible, the task is meant for each (D#110). */
|
||||
assignee_pool?: string[] | null;
|
||||
group_names: string[];
|
||||
/** #189: titles of the calendar events behind next_due (calendar kind). */
|
||||
next_event_titles: string[];
|
||||
@@ -660,6 +662,10 @@ export interface HomeAssistant {
|
||||
subscribeMsg: Record<string, unknown>,
|
||||
options?: Record<string, unknown>
|
||||
): Promise<() => void>;
|
||||
/** "ready" fires after a reconnect (a Home Assistant restart). Optional:
|
||||
* test stubs leave it out. */
|
||||
addEventListener?(event: "ready", callback: () => void): void;
|
||||
removeEventListener?(event: "ready", callback: () => void): void;
|
||||
};
|
||||
callService(
|
||||
domain: string,
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Ukotvení intervalu",
|
||||
"anchor_completion": "Od data dokončení",
|
||||
"anchor_planned": "Od plánovaného data (bez posunu)",
|
||||
"interval_anchor_hint": "Od data dokončení: další termín se počítá ode dne, kdy je úkol označen jako hotový, takže dřívější nebo pozdější splnění posune plán. Od plánovaného data: plán si ponechá své termíny, například když je faktura zaplacena týdny před splatností.",
|
||||
"edit_object": "Upravit objekt",
|
||||
"name": "Název",
|
||||
"manufacturer_optional": "Výrobce (volitelné)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Dejte několika senzorům stejný název objektu a stanou se jedním objektem; zadejte název existujícího objektu a přidají se tam.",
|
||||
"adopt_summary_title": "Co převzetí změní",
|
||||
"adopt_summary_existing": "„{name}“: úkoly {before} → {after}",
|
||||
"adopt_summary_totals": "Úkoly: {tasks} · objekty: {objects}",
|
||||
"adopt_summary_totals_new": "Úkoly: {tasks} · objekty: {objects} (z toho nové: {new})",
|
||||
"adopt_problem_adopt": "Převzít vybrané",
|
||||
"adopt_problem_done": "Převzato {tasks} senzorů problémů",
|
||||
"adopt_problem_done_one": "Převzat 1 senzor problémů",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Flotila baterií nastavena — jeden úkol sleduje všechny.",
|
||||
"update_banner": "Na serveru je novější verze Maintenance Supporter — načtěte znovu pro aktualizaci panelu.",
|
||||
"update_reload": "Načíst znovu",
|
||||
"restart_pending_banner": "Maintenance Supporter byl aktualizován na verzi {version}. Restartujte Home Assistant, aby se aktualizace dokončila.",
|
||||
"restart_pending_error": "Nepodařilo se: Maintenance Supporter byl aktualizován na verzi {version}, ale Home Assistant od té doby nebyl restartován. Restartujte Home Assistant a zkuste to znovu.",
|
||||
"row_actions_banner": "Dokončit a Přeskočit jsou v řádcích úkolů nyní tlačítka. Dáváte přednost starým ikonám?",
|
||||
"row_actions_keep": "Ponechat tlačítka",
|
||||
"row_actions_back": "Zpět na ikony",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Intervalanker",
|
||||
"anchor_completion": "Fra fuldførelsesdato",
|
||||
"anchor_planned": "Fra planlagt dato (ingen drift)",
|
||||
"interval_anchor_hint": "Fra fuldførelsesdato: næste forfaldsdato regnes fra den dag, opgaven markeres som udført, så tidlig eller sen udførelse flytter planen. Fra planlagt dato: planen beholder sine datoer, for eksempel når en regning betales uger før forfald.",
|
||||
"edit_object": "Rediger objekt",
|
||||
"name": "Navn",
|
||||
"manufacturer_optional": "Producent (valgfrit)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Giv flere sensorer samme objektnavn, så bliver de ét objekt; skriv et eksisterende objekts navn for at tilføje dem der.",
|
||||
"adopt_summary_title": "Hvad overtagelsen ændrer",
|
||||
"adopt_summary_existing": "\"{name}\": opgaver {before} → {after}",
|
||||
"adopt_summary_totals": "Opgaver: {tasks} · objekter: {objects}",
|
||||
"adopt_summary_totals_new": "Opgaver: {tasks} · objekter: {objects} (heraf nye: {new})",
|
||||
"adopt_problem_adopt": "Adopter valgte",
|
||||
"adopt_problem_done": "Adopterede {tasks} problemsensor(er)",
|
||||
"adopt_problem_done_one": "Adopterede 1 problemsensor",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Batteriflåde opsat — én opgave følger alle batterier.",
|
||||
"update_banner": "En nyere version af Maintenance Supporter er på serveren — genindlæs for at opdatere panelet.",
|
||||
"update_reload": "Genindlæs",
|
||||
"restart_pending_banner": "Maintenance Supporter er blevet opdateret til {version}. Genstart Home Assistant for at fuldføre opdateringen.",
|
||||
"restart_pending_error": "Det lykkedes ikke: Maintenance Supporter er blevet opdateret til {version}, men Home Assistant er ikke blevet genstartet siden. Genstart Home Assistant, og prøv igen.",
|
||||
"row_actions_banner": "Fuldfør og Spring over er nu knapper i opgaverækkerne. Foretrækker du de gamle ikoner?",
|
||||
"row_actions_keep": "Behold knapper",
|
||||
"row_actions_back": "Tilbage til ikoner",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Intervall-Anker",
|
||||
"anchor_completion": "Ab Erledigung",
|
||||
"anchor_planned": "Ab geplantem Datum (kein Drift)",
|
||||
"interval_anchor_hint": "Ab Erledigung: Die nächste Fälligkeit zählt ab dem Tag, an dem die Aufgabe erledigt wird; früher oder später erledigt verschiebt also den Plan. Ab geplantem Datum: Der Plan behält seine Termine, zum Beispiel wenn eine Rechnung Wochen vor der Fälligkeit bezahlt wird.",
|
||||
"edit_object": "Objekt bearbeiten",
|
||||
"name": "Name",
|
||||
"manufacturer_optional": "Hersteller (optional)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Gib mehreren Sensoren denselben Objektnamen, dann werden sie ein Objekt; der Name eines vorhandenen Objekts ordnet sie dort zu.",
|
||||
"adopt_summary_title": "Was die Übernahme ändert",
|
||||
"adopt_summary_existing": "„{name}“: Aufgaben {before} → {after}",
|
||||
"adopt_summary_totals": "Aufgaben: {tasks} · Objekte: {objects}",
|
||||
"adopt_summary_totals_new": "Aufgaben: {tasks} · Objekte: {objects} (davon neu: {new})",
|
||||
"adopt_problem_adopt": "Auswahl übernehmen",
|
||||
"adopt_problem_done": "{tasks} Problem-Sensor(en) übernommen",
|
||||
"adopt_problem_done_one": "1 Problem-Sensor übernommen",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Batterie-Flotte eingerichtet — ein Task überwacht alle Batterien.",
|
||||
"update_banner": "Auf dem Server läuft eine neuere Version von Maintenance Supporter — neu laden, um das Panel zu aktualisieren.",
|
||||
"update_reload": "Neu laden",
|
||||
"restart_pending_banner": "Maintenance Supporter wurde auf {version} aktualisiert. Starte Home Assistant neu, um das Update abzuschließen.",
|
||||
"restart_pending_error": "Das hat nicht geklappt: Maintenance Supporter wurde auf {version} aktualisiert, Home Assistant aber seitdem nicht neu gestartet. Starte Home Assistant neu und versuche es dann noch einmal.",
|
||||
"row_actions_banner": "Erledigt und Überspringen sind in den Aufgabenzeilen jetzt Buttons. Lieber die alten Symbole?",
|
||||
"row_actions_keep": "Buttons behalten",
|
||||
"row_actions_back": "Zurück zu Symbolen",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Interval anchor",
|
||||
"anchor_completion": "From completion date",
|
||||
"anchor_planned": "From planned date (no drift)",
|
||||
"interval_anchor_hint": "From completion date: the next due date counts from the day the task is marked done, so doing it early or late moves the schedule. From planned date: the schedule keeps its dates, for example when a bill is paid weeks before it is due.",
|
||||
"edit_object": "Edit Object",
|
||||
"name": "Name",
|
||||
"manufacturer_optional": "Manufacturer (optional)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Give several sensors the same object name and they become one object; type an existing object's name to add them there.",
|
||||
"adopt_summary_title": "What adopting changes",
|
||||
"adopt_summary_existing": "\"{name}\": tasks {before} → {after}",
|
||||
"adopt_summary_totals": "Tasks: {tasks} · objects: {objects}",
|
||||
"adopt_summary_totals_new": "Tasks: {tasks} · objects: {objects} ({new} new)",
|
||||
"adopt_problem_adopt": "Adopt selected",
|
||||
"adopt_problem_done": "Adopted {tasks} problem sensor(s)",
|
||||
"adopt_problem_done_one": "Adopted 1 problem sensor",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Battery fleet set up — one task tracks all your batteries.",
|
||||
"update_banner": "A newer version of Maintenance Supporter is on the server — reload to update the panel.",
|
||||
"update_reload": "Reload",
|
||||
"restart_pending_banner": "Maintenance Supporter was updated to {version}. Restart Home Assistant to finish the update.",
|
||||
"restart_pending_error": "That did not work: Maintenance Supporter was updated to {version}, but Home Assistant has not been restarted since. Restart Home Assistant, then try again.",
|
||||
"row_actions_banner": "Complete and Skip in task rows are now buttons. Prefer the old icons?",
|
||||
"row_actions_keep": "Keep buttons",
|
||||
"row_actions_back": "Back to icons",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Anclaje del intervalo",
|
||||
"anchor_completion": "Desde la fecha de finalización",
|
||||
"anchor_planned": "Desde la fecha planificada (sin desviación)",
|
||||
"interval_anchor_hint": "Desde la fecha de finalización: el próximo vencimiento se cuenta desde el día en que se marca la tarea como hecha, así que hacerla antes o después mueve el calendario. Desde la fecha planificada: el calendario mantiene sus fechas, por ejemplo cuando una factura se paga semanas antes de su vencimiento.",
|
||||
"edit_object": "Editar objeto",
|
||||
"name": "Nombre",
|
||||
"manufacturer_optional": "Fabricante (opcional)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Da a varios sensores el mismo nombre de objeto y se convierten en un solo objeto; escribe el nombre de un objeto existente para añadirlos allí.",
|
||||
"adopt_summary_title": "Qué cambia al adoptar",
|
||||
"adopt_summary_existing": "«{name}»: tareas {before} → {after}",
|
||||
"adopt_summary_totals": "Tareas: {tasks} · objetos: {objects}",
|
||||
"adopt_summary_totals_new": "Tareas: {tasks} · objetos: {objects} (nuevos: {new})",
|
||||
"adopt_problem_adopt": "Adoptar seleccionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adoptado(s)",
|
||||
"adopt_problem_done_one": "1 sensor de problema adoptado",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Flota de baterías configurada — una tarea controla todas.",
|
||||
"update_banner": "Hay una versión más reciente de Maintenance Supporter en el servidor — recarga para actualizar el panel.",
|
||||
"update_reload": "Recargar",
|
||||
"restart_pending_banner": "Maintenance Supporter se actualizó a la versión {version}. Reinicia Home Assistant para completar la actualización.",
|
||||
"restart_pending_error": "No ha funcionado: Maintenance Supporter se actualizó a la versión {version}, pero Home Assistant no se ha reiniciado desde entonces. Reinicia Home Assistant y vuelve a intentarlo.",
|
||||
"row_actions_banner": "Completar y Omitir ahora son botones en las filas de tareas. ¿Prefieres los iconos antiguos?",
|
||||
"row_actions_keep": "Mantener botones",
|
||||
"row_actions_back": "Volver a los iconos",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Välin ankkuri",
|
||||
"anchor_completion": "Suorituspäivästä",
|
||||
"anchor_planned": "Suunnitellusta päivästä (ei poikkeamaa)",
|
||||
"interval_anchor_hint": "Suorituspäivästä: seuraava eräpäivä lasketaan päivästä, jolloin tehtävä merkitään tehdyksi, joten aikainen tai myöhäinen suoritus siirtää aikataulua. Suunnitellusta päivästä: aikataulu pitää päivänsä, esimerkiksi kun lasku maksetaan viikkoja ennen eräpäivää.",
|
||||
"edit_object": "Muokkaa kohdetta",
|
||||
"name": "Nimi",
|
||||
"manufacturer_optional": "Valmistaja (valinnainen)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Anna useille antureille sama kohteen nimi, niin niistä tulee yksi kohde; kirjoita olemassa olevan kohteen nimi lisätäksesi ne sinne.",
|
||||
"adopt_summary_title": "Mitä käyttöönotto muuttaa",
|
||||
"adopt_summary_existing": "\"{name}\": tehtävät {before} → {after}",
|
||||
"adopt_summary_totals": "Tehtäviä: {tasks} · kohteita: {objects}",
|
||||
"adopt_summary_totals_new": "Tehtäviä: {tasks} · kohteita: {objects} (uusia: {new})",
|
||||
"adopt_problem_adopt": "Ota valitut käyttöön",
|
||||
"adopt_problem_done": "Otettiin käyttöön {tasks} ongelma-anturia",
|
||||
"adopt_problem_done_one": "Otettiin käyttöön 1 ongelma-anturi",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Paristokanta määritetty — yksi tehtävä seuraa kaikkia.",
|
||||
"update_banner": "Palvelimella on uudempi Maintenance Supporter -versio — lataa uudelleen päivittääksesi paneelin.",
|
||||
"update_reload": "Lataa uudelleen",
|
||||
"restart_pending_banner": "Maintenance Supporter on päivitetty versioon {version}. Käynnistä Home Assistant uudelleen viimeistelläksesi päivityksen.",
|
||||
"restart_pending_error": "Se ei onnistunut: Maintenance Supporter on päivitetty versioon {version}, mutta Home Assistantia ei ole sen jälkeen käynnistetty uudelleen. Käynnistä Home Assistant uudelleen ja yritä sitten uudelleen.",
|
||||
"row_actions_banner": "Valmis ja Ohita ovat tehtäväriveillä nyt painikkeita. Haluatko mieluummin vanhat kuvakkeet?",
|
||||
"row_actions_keep": "Pidä painikkeet",
|
||||
"row_actions_back": "Takaisin kuvakkeisiin",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Ancrage de l'intervalle",
|
||||
"anchor_completion": "Depuis la date de réalisation",
|
||||
"anchor_planned": "Depuis la date prévue (sans dérive)",
|
||||
"interval_anchor_hint": "Depuis la date de réalisation : la prochaine échéance compte à partir du jour où la tâche est marquée comme faite, donc la faire en avance ou en retard décale le planning. Depuis la date prévue : le planning garde ses dates, par exemple quand une facture est payée des semaines avant son échéance.",
|
||||
"edit_object": "Modifier l'objet",
|
||||
"name": "Nom",
|
||||
"manufacturer_optional": "Fabricant (optionnel)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Donnez le même nom d'objet à plusieurs capteurs et ils forment un seul objet ; saisissez le nom d'un objet existant pour les y ajouter.",
|
||||
"adopt_summary_title": "Ce que l'adoption modifie",
|
||||
"adopt_summary_existing": "« {name} » : tâches {before} → {after}",
|
||||
"adopt_summary_totals": "Tâches : {tasks} · objets : {objects}",
|
||||
"adopt_summary_totals_new": "Tâches : {tasks} · objets : {objects} (dont nouveaux : {new})",
|
||||
"adopt_problem_adopt": "Adopter la sélection",
|
||||
"adopt_problem_done": "{tasks} capteur(s) de problème adopté(s)",
|
||||
"adopt_problem_done_one": "1 capteur de problème adopté",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Parc de piles configuré — une tâche suit toutes vos piles.",
|
||||
"update_banner": "Une version plus récente de Maintenance Supporter est sur le serveur — rechargez pour mettre à jour le panneau.",
|
||||
"update_reload": "Recharger",
|
||||
"restart_pending_banner": "Maintenance Supporter a été mis à jour vers la version {version}. Redémarrez Home Assistant pour terminer la mise à jour.",
|
||||
"restart_pending_error": "Cela n'a pas fonctionné : Maintenance Supporter a été mis à jour vers la version {version}, mais Home Assistant n'a pas été redémarré depuis. Redémarrez Home Assistant, puis réessayez.",
|
||||
"row_actions_banner": "Terminer et Ignorer sont désormais des boutons dans les lignes de tâches. Vous préférez les anciennes icônes ?",
|
||||
"row_actions_keep": "Garder les boutons",
|
||||
"row_actions_back": "Revenir aux icônes",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "अंतराल आधार",
|
||||
"anchor_completion": "पूर्ण तिथि से",
|
||||
"anchor_planned": "नियोजित तिथि से (कोई विचलन नहीं)",
|
||||
"interval_anchor_hint": "पूर्ण तिथि से: अगली देय तिथि उस दिन से गिनी जाती है जिस दिन कार्य पूरा चिह्नित किया जाता है, इसलिए पहले या देर से करने पर समय-सारणी खिसक जाती है। नियोजित तिथि से: समय-सारणी अपनी तिथियाँ बनाए रखती है, उदाहरण के लिए जब कोई बिल देय तिथि से हफ़्तों पहले चुकाया जाता है।",
|
||||
"edit_object": "वस्तु संपादित करें",
|
||||
"name": "नाम",
|
||||
"manufacturer_optional": "निर्माता (वैकल्पिक)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "कई सेंसरों को एक ही ऑब्जेक्ट नाम दें तो वे एक ऑब्जेक्ट बन जाते हैं; मौजूदा ऑब्जेक्ट का नाम लिखें तो वे वहीं जुड़ जाते हैं।",
|
||||
"adopt_summary_title": "अपनाने से क्या बदलेगा",
|
||||
"adopt_summary_existing": "\"{name}\": कार्य {before} → {after}",
|
||||
"adopt_summary_totals": "कार्य: {tasks} · ऑब्जेक्ट: {objects}",
|
||||
"adopt_summary_totals_new": "कार्य: {tasks} · ऑब्जेक्ट: {objects} (नए: {new})",
|
||||
"adopt_problem_adopt": "चयनित अपनाएँ",
|
||||
"adopt_problem_done": "{tasks} समस्या सेंसर अपनाए गए",
|
||||
"adopt_problem_done_one": "1 समस्या सेंसर अपनाया गया",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "बैटरी फ्लीट सेट — एक कार्य सभी बैटरियों को ट्रैक करता है।",
|
||||
"update_banner": "सर्वर पर Maintenance Supporter का नया संस्करण है — पैनल अपडेट करने के लिए पुनः लोड करें।",
|
||||
"update_reload": "पुनः लोड करें",
|
||||
"restart_pending_banner": "Maintenance Supporter को {version} संस्करण में अपडेट किया गया है। अपडेट पूरा करने के लिए Home Assistant को पुनः आरंभ करें।",
|
||||
"restart_pending_error": "यह नहीं हो सका: Maintenance Supporter को {version} संस्करण में अपडेट किया गया है, लेकिन उसके बाद से Home Assistant को पुनः आरंभ नहीं किया गया है। Home Assistant को पुनः आरंभ करें, फिर दोबारा प्रयास करें।",
|
||||
"row_actions_banner": "कार्य पंक्तियों में पूर्ण और छोड़ें अब बटन हैं। पुराने आइकन पसंद हैं?",
|
||||
"row_actions_keep": "बटन रखें",
|
||||
"row_actions_back": "आइकन पर वापस जाएँ",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Intervallum horgonya",
|
||||
"anchor_completion": "Az elvégzés dátumától",
|
||||
"anchor_planned": "A tervezett dátumtól (nincs csúszás)",
|
||||
"interval_anchor_hint": "Az elvégzés dátumától: a következő határidő attól a naptól számít, amikor a feladatot elvégzettnek jelölik, így a korábbi vagy későbbi elvégzés eltolja az ütemezést. A tervezett dátumtól: az ütemezés megtartja a dátumait, például ha egy számlát hetekkel a határidő előtt fizetnek be.",
|
||||
"edit_object": "Objektum szerkesztése",
|
||||
"name": "Név",
|
||||
"manufacturer_optional": "Gyártó (opcionális)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Adja több érzékelőnek ugyanazt az objektumnevet, és egy objektummá válnak; meglévő objektum nevét beírva oda kerülnek.",
|
||||
"adopt_summary_title": "Mit változtat az átvétel",
|
||||
"adopt_summary_existing": "„{name}”: feladatok {before} → {after}",
|
||||
"adopt_summary_totals": "Feladatok: {tasks} · objektumok: {objects}",
|
||||
"adopt_summary_totals_new": "Feladatok: {tasks} · objektumok: {objects} (ebből új: {new})",
|
||||
"adopt_problem_adopt": "Kijelöltek átvétele",
|
||||
"adopt_problem_done": "{tasks} problémaérzékelő átvéve",
|
||||
"adopt_problem_done_one": "1 problémaérzékelő átvéve",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Elemflotta beállítva — egyetlen feladat követi az összes elemet.",
|
||||
"update_banner": "A Maintenance Supporter újabb verziója érhető el a szerveren — töltse újra az oldalt a panel frissítéséhez.",
|
||||
"update_reload": "Újratöltés",
|
||||
"restart_pending_banner": "A Maintenance Supporter frissült a(z) {version} verzióra. Indítsa újra a Home Assistantot a frissítés befejezéséhez.",
|
||||
"restart_pending_error": "Ez nem sikerült: a Maintenance Supporter frissült a(z) {version} verzióra, de a Home Assistant azóta nem indult újra. Indítsa újra a Home Assistantot, majd próbálja újra.",
|
||||
"row_actions_banner": "A Kész és a Kihagyás a feladatsorokban mostantól gombok. Inkább a régi ikonokat szeretné?",
|
||||
"row_actions_keep": "Gombok megtartása",
|
||||
"row_actions_back": "Vissza az ikonokhoz",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Ancoraggio intervallo",
|
||||
"anchor_completion": "Dalla data di completamento",
|
||||
"anchor_planned": "Dalla data pianificata (nessuna deriva)",
|
||||
"interval_anchor_hint": "Dalla data di completamento: la prossima scadenza si conta dal giorno in cui l'attività viene segnata come fatta, quindi farla prima o dopo sposta la pianificazione. Dalla data pianificata: la pianificazione mantiene le sue date, per esempio quando una bolletta viene pagata settimane prima della scadenza.",
|
||||
"edit_object": "Modifica oggetto",
|
||||
"name": "Nome",
|
||||
"manufacturer_optional": "Produttore (opzionale)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Assegna lo stesso nome oggetto a più sensori e diventano un unico oggetto; digita il nome di un oggetto esistente per aggiungerli lì.",
|
||||
"adopt_summary_title": "Cosa cambia l'adozione",
|
||||
"adopt_summary_existing": "«{name}»: attività {before} → {after}",
|
||||
"adopt_summary_totals": "Attività: {tasks} · oggetti: {objects}",
|
||||
"adopt_summary_totals_new": "Attività: {tasks} · oggetti: {objects} (di cui nuovi: {new})",
|
||||
"adopt_problem_adopt": "Adotta selezionati",
|
||||
"adopt_problem_done": "{tasks} sensore/i di problema adottato/i",
|
||||
"adopt_problem_done_one": "1 sensore di problema adottato",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Parco batterie configurato — un'attività monitora tutte.",
|
||||
"update_banner": "Sul server è presente una versione più recente di Maintenance Supporter — ricarica per aggiornare il pannello.",
|
||||
"update_reload": "Ricarica",
|
||||
"restart_pending_banner": "Maintenance Supporter è stato aggiornato alla versione {version}. Riavvia Home Assistant per completare l'aggiornamento.",
|
||||
"restart_pending_error": "Non è andato a buon fine: Maintenance Supporter è stato aggiornato alla versione {version}, ma da allora Home Assistant non è stato riavviato. Riavvia Home Assistant e riprova.",
|
||||
"row_actions_banner": "Completa e Salta nelle righe delle attività ora sono pulsanti. Preferisci le vecchie icone?",
|
||||
"row_actions_keep": "Mantieni i pulsanti",
|
||||
"row_actions_back": "Torna alle icone",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "間隔の起点",
|
||||
"anchor_completion": "完了日から",
|
||||
"anchor_planned": "予定日から(ずれなし)",
|
||||
"interval_anchor_hint": "完了日から: 次の期限はタスクを完了にした日から数えるため、早く・遅く完了すると予定がずれます。予定日から: 予定は元の日付を保ちます。たとえば請求書を期限の数週間前に支払った場合です。",
|
||||
"edit_object": "対象を編集",
|
||||
"name": "名前",
|
||||
"manufacturer_optional": "メーカー(任意)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "複数のセンサーに同じオブジェクト名を付けると1つのオブジェクトになります。既存のオブジェクト名を入力すればそこに追加されます。",
|
||||
"adopt_summary_title": "取り込みで変わること",
|
||||
"adopt_summary_existing": "「{name}」: タスク {before} → {after}",
|
||||
"adopt_summary_totals": "タスク: {tasks} · オブジェクト: {objects}",
|
||||
"adopt_summary_totals_new": "タスク: {tasks} · オブジェクト: {objects}(うち新規: {new})",
|
||||
"adopt_problem_adopt": "選択を取り込む",
|
||||
"adopt_problem_done": "{tasks} 件の問題センサーを取り込みました",
|
||||
"adopt_problem_done_one": "1 件の問題センサーを取り込みました",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "電池フリートを設定 — 1つのタスクで全電池を管理。",
|
||||
"update_banner": "サーバーに新しいバージョンの Maintenance Supporter があります — 再読み込みしてパネルを更新してください。",
|
||||
"update_reload": "再読み込み",
|
||||
"restart_pending_banner": "Maintenance Supporter はバージョン {version} に更新されました。更新を完了するには Home Assistant を再起動してください。",
|
||||
"restart_pending_error": "実行できませんでした: Maintenance Supporter はバージョン {version} に更新されましたが、その後 Home Assistant が再起動されていません。Home Assistant を再起動してから、もう一度お試しください。",
|
||||
"row_actions_banner": "タスク行の「完了」と「スキップ」がボタンになりました。以前のアイコンに戻しますか?",
|
||||
"row_actions_keep": "ボタンのままにする",
|
||||
"row_actions_back": "アイコンに戻す",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "주기 기준",
|
||||
"anchor_completion": "완료일 기준",
|
||||
"anchor_planned": "예정일 기준 (밀림 없음)",
|
||||
"interval_anchor_hint": "완료일 기준: 다음 예정일은 작업을 완료로 표시한 날부터 계산되므로, 일찍 또는 늦게 완료하면 일정이 바뀝니다. 예정일 기준: 일정이 원래 날짜를 유지합니다. 예를 들어 청구서를 기한보다 몇 주 일찍 납부한 경우입니다.",
|
||||
"edit_object": "객체 편집",
|
||||
"name": "이름",
|
||||
"manufacturer_optional": "제조사 (선택)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "여러 센서에 같은 개체 이름을 주면 하나의 개체가 됩니다. 기존 개체 이름을 입력하면 거기에 추가됩니다.",
|
||||
"adopt_summary_title": "가져오기로 바뀌는 점",
|
||||
"adopt_summary_existing": "\"{name}\": 작업 {before} → {after}",
|
||||
"adopt_summary_totals": "작업: {tasks} · 객체: {objects}",
|
||||
"adopt_summary_totals_new": "작업: {tasks} · 객체: {objects} (새 객체: {new})",
|
||||
"adopt_problem_adopt": "선택 항목 가져오기",
|
||||
"adopt_problem_done": "문제 센서 {tasks}개를 가져왔습니다",
|
||||
"adopt_problem_done_one": "문제 센서 1개를 가져왔습니다",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "배터리 플릿이 설정되었습니다 — 하나의 작업이 모든 배터리를 추적합니다.",
|
||||
"update_banner": "서버에 Maintenance Supporter의 새 버전이 있습니다 — 패널을 업데이트하려면 새로 고침하세요.",
|
||||
"update_reload": "새로 고침",
|
||||
"restart_pending_banner": "Maintenance Supporter가 {version} 버전으로 업데이트되었습니다. 업데이트를 완료하려면 Home Assistant를 다시 시작하세요.",
|
||||
"restart_pending_error": "실패했습니다: Maintenance Supporter가 {version} 버전으로 업데이트되었지만 그 이후 Home Assistant가 다시 시작되지 않았습니다. Home Assistant를 다시 시작한 후 다시 시도하세요.",
|
||||
"row_actions_banner": "작업 행의 완료와 건너뛰기가 이제 버튼으로 표시됩니다. 이전 아이콘이 더 좋으신가요?",
|
||||
"row_actions_keep": "버튼 유지",
|
||||
"row_actions_back": "아이콘으로 되돌리기",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Intervallforankring",
|
||||
"anchor_completion": "Fra fullføringsdato",
|
||||
"anchor_planned": "Fra planlagt dato (ingen avdrift)",
|
||||
"interval_anchor_hint": "Fra fullføringsdato: neste forfallsdato regnes fra dagen oppgaven markeres som utført, så tidlig eller sen utførelse flytter planen. Fra planlagt dato: planen beholder datoene sine, for eksempel når en regning betales uker før forfall.",
|
||||
"edit_object": "Rediger objekt",
|
||||
"name": "Navn",
|
||||
"manufacturer_optional": "Produsent (valgfritt)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Gi flere sensorer samme objektnavn, så blir de ett objekt; skriv navnet på et eksisterende objekt for å legge dem der.",
|
||||
"adopt_summary_title": "Hva overtakelsen endrer",
|
||||
"adopt_summary_existing": "«{name}»: oppgaver {before} → {after}",
|
||||
"adopt_summary_totals": "Oppgaver: {tasks} · objekter: {objects}",
|
||||
"adopt_summary_totals_new": "Oppgaver: {tasks} · objekter: {objects} (herav nye: {new})",
|
||||
"adopt_problem_adopt": "Ta i bruk valgte",
|
||||
"adopt_problem_done": "Tok i bruk {tasks} problemsensor(er)",
|
||||
"adopt_problem_done_one": "Tok i bruk 1 problemsensor",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Batteriflåte satt opp — én oppgave følger alle batteriene.",
|
||||
"update_banner": "En nyere versjon av Maintenance Supporter er på serveren — last inn på nytt for å oppdatere panelet.",
|
||||
"update_reload": "Last inn på nytt",
|
||||
"restart_pending_banner": "Maintenance Supporter er oppdatert til {version}. Start Home Assistant på nytt for å fullføre oppdateringen.",
|
||||
"restart_pending_error": "Det fungerte ikke: Maintenance Supporter er oppdatert til {version}, men Home Assistant er ikke startet på nytt siden. Start Home Assistant på nytt, og prøv igjen.",
|
||||
"row_actions_banner": "Fullfør og Hopp over er nå knapper i oppgaveradene. Foretrekker du de gamle ikonene?",
|
||||
"row_actions_keep": "Behold knapper",
|
||||
"row_actions_back": "Tilbake til ikoner",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Interval-anker",
|
||||
"anchor_completion": "Vanaf voltooiing",
|
||||
"anchor_planned": "Vanaf geplande datum (geen drift)",
|
||||
"interval_anchor_hint": "Vanaf voltooiing: de volgende vervaldatum telt vanaf de dag waarop de taak als gedaan wordt gemarkeerd, dus eerder of later uitvoeren verschuift de planning. Vanaf geplande datum: de planning houdt haar data, bijvoorbeeld wanneer een rekening weken voor de vervaldatum wordt betaald.",
|
||||
"edit_object": "Object bewerken",
|
||||
"name": "Naam",
|
||||
"manufacturer_optional": "Fabrikant (optioneel)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Geef meerdere sensoren dezelfde objectnaam en ze worden één object; typ de naam van een bestaand object om ze daar toe te voegen.",
|
||||
"adopt_summary_title": "Wat overnemen verandert",
|
||||
"adopt_summary_existing": "\"{name}\": taken {before} → {after}",
|
||||
"adopt_summary_totals": "Taken: {tasks} · objecten: {objects}",
|
||||
"adopt_summary_totals_new": "Taken: {tasks} · objecten: {objects} (waarvan nieuw: {new})",
|
||||
"adopt_problem_adopt": "Selectie overnemen",
|
||||
"adopt_problem_done": "{tasks} probleemsensor(en) overgenomen",
|
||||
"adopt_problem_done_one": "1 probleemsensor overgenomen",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Batterijvloot ingesteld — één taak volgt al je batterijen.",
|
||||
"update_banner": "Er staat een nieuwere versie van Maintenance Supporter op de server — herlaad om het paneel bij te werken.",
|
||||
"update_reload": "Herladen",
|
||||
"restart_pending_banner": "Maintenance Supporter is bijgewerkt naar {version}. Start Home Assistant opnieuw op om de update te voltooien.",
|
||||
"restart_pending_error": "Dat is niet gelukt: Maintenance Supporter is bijgewerkt naar {version}, maar Home Assistant is sindsdien niet opnieuw opgestart. Start Home Assistant opnieuw op en probeer het dan nog eens.",
|
||||
"row_actions_banner": "Voltooien en Overslaan zijn in taakrijen nu knoppen. Liever de oude pictogrammen?",
|
||||
"row_actions_keep": "Knoppen houden",
|
||||
"row_actions_back": "Terug naar pictogrammen",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Punkt zaczepienia interwału",
|
||||
"anchor_completion": "Od daty wykonania",
|
||||
"anchor_planned": "Od daty planowanej (bez przesunięć)",
|
||||
"interval_anchor_hint": "Od daty wykonania: następny termin liczy się od dnia oznaczenia zadania jako wykonanego, więc wcześniejsze lub późniejsze wykonanie przesuwa harmonogram. Od daty planowanej: harmonogram zachowuje swoje daty, na przykład gdy rachunek zostaje opłacony kilka tygodni przed terminem.",
|
||||
"edit_object": "Edytuj obiekt",
|
||||
"name": "Nazwa",
|
||||
"manufacturer_optional": "Producent (opcjonalne)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Nadaj kilku czujnikom tę samą nazwę obiektu, a staną się jednym obiektem; wpisz nazwę istniejącego obiektu, aby je tam dodać.",
|
||||
"adopt_summary_title": "Co zmieni przejęcie",
|
||||
"adopt_summary_existing": "„{name}”: zadania {before} → {after}",
|
||||
"adopt_summary_totals": "Zadania: {tasks} · obiekty: {objects}",
|
||||
"adopt_summary_totals_new": "Zadania: {tasks} · obiekty: {objects} (w tym nowe: {new})",
|
||||
"adopt_problem_adopt": "Przejmij zaznaczone",
|
||||
"adopt_problem_done": "Przejęto {tasks} czujnik(ów) problemów",
|
||||
"adopt_problem_done_one": "Przejęto 1 czujnik problemów",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Flota baterii skonfigurowana — jedno zadanie śledzi wszystkie.",
|
||||
"update_banner": "Na serwerze jest nowsza wersja Maintenance Supporter — załaduj ponownie, aby zaktualizować panel.",
|
||||
"update_reload": "Załaduj ponownie",
|
||||
"restart_pending_banner": "Maintenance Supporter został zaktualizowany do wersji {version}. Uruchom ponownie Home Assistant, aby dokończyć aktualizację.",
|
||||
"restart_pending_error": "Nie udało się: Maintenance Supporter został zaktualizowany do wersji {version}, ale od tego czasu Home Assistant nie został uruchomiony ponownie. Uruchom ponownie Home Assistant i spróbuj jeszcze raz.",
|
||||
"row_actions_banner": "Ukończ i Pomiń w wierszach zadań są teraz przyciskami. Wolisz stare ikony?",
|
||||
"row_actions_keep": "Zachowaj przyciski",
|
||||
"row_actions_back": "Wróć do ikon",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Âncora do intervalo",
|
||||
"anchor_completion": "A partir da data de conclusão",
|
||||
"anchor_planned": "A partir da data planejada (sem deriva)",
|
||||
"interval_anchor_hint": "A partir da data de conclusão: o próximo vencimento conta a partir do dia em que a tarefa é marcada como feita, então fazê-la antes ou depois desloca o cronograma. A partir da data planejada: o cronograma mantém suas datas, por exemplo quando uma conta é paga semanas antes do vencimento.",
|
||||
"edit_object": "Editar objeto",
|
||||
"name": "Nome",
|
||||
"manufacturer_optional": "Fabricante (opcional)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Dê a vários sensores o mesmo nome de objeto e eles viram um único objeto; digite o nome de um objeto existente para adicioná-los lá.",
|
||||
"adopt_summary_title": "O que a adoção muda",
|
||||
"adopt_summary_existing": "\"{name}\": tarefas {before} → {after}",
|
||||
"adopt_summary_totals": "Tarefas: {tasks} · objetos: {objects}",
|
||||
"adopt_summary_totals_new": "Tarefas: {tasks} · objetos: {objects} (novos: {new})",
|
||||
"adopt_problem_adopt": "Adotar selecionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adotado(s)",
|
||||
"adopt_problem_done_one": "1 sensor de problema adotado",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Frota de baterias configurada — uma única tarefa acompanha todas as suas baterias.",
|
||||
"update_banner": "Há uma versão mais nova do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
||||
"update_reload": "Recarregar",
|
||||
"restart_pending_banner": "O Maintenance Supporter foi atualizado para a versão {version}. Reinicie o Home Assistant para finalizar a atualização.",
|
||||
"restart_pending_error": "Não deu certo: o Maintenance Supporter foi atualizado para a versão {version}, mas o Home Assistant ainda não foi reiniciado. Reinicie o Home Assistant e tente de novo.",
|
||||
"row_actions_banner": "Concluir e Pular agora são botões nas linhas de tarefas. Prefere os ícones antigos?",
|
||||
"row_actions_keep": "Manter botões",
|
||||
"row_actions_back": "Voltar aos ícones",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Âncora do intervalo",
|
||||
"anchor_completion": "A partir da data de conclusão",
|
||||
"anchor_planned": "A partir da data planeada (sem desvio)",
|
||||
"interval_anchor_hint": "A partir da data de conclusão: o próximo vencimento conta a partir do dia em que a tarefa é marcada como feita, por isso fazê-la antes ou depois desloca o calendário. A partir da data planeada: o calendário mantém as suas datas, por exemplo quando uma fatura é paga semanas antes do vencimento.",
|
||||
"edit_object": "Editar objeto",
|
||||
"name": "Nome",
|
||||
"manufacturer_optional": "Fabricante (opcional)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Dê a vários sensores o mesmo nome de objeto e tornam-se um só objeto; escreva o nome de um objeto existente para os juntar lá.",
|
||||
"adopt_summary_title": "O que a adoção altera",
|
||||
"adopt_summary_existing": "«{name}»: tarefas {before} → {after}",
|
||||
"adopt_summary_totals": "Tarefas: {tasks} · objetos: {objects}",
|
||||
"adopt_summary_totals_new": "Tarefas: {tasks} · objetos: {objects} (novos: {new})",
|
||||
"adopt_problem_adopt": "Adotar selecionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adotado(s)",
|
||||
"adopt_problem_done_one": "1 sensor de problema adotado",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Frota de baterias configurada — uma tarefa acompanha todas.",
|
||||
"update_banner": "Há uma versão mais recente do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
||||
"update_reload": "Recarregar",
|
||||
"restart_pending_banner": "O Maintenance Supporter foi atualizado para a versão {version}. Reinicie o Home Assistant para concluir a atualização.",
|
||||
"restart_pending_error": "Não foi possível: o Maintenance Supporter foi atualizado para a versão {version}, mas o Home Assistant ainda não foi reiniciado. Reinicie o Home Assistant e tente novamente.",
|
||||
"row_actions_banner": "Concluir e Ignorar são agora botões nas linhas de tarefas. Prefere os ícones antigos?",
|
||||
"row_actions_keep": "Manter botões",
|
||||
"row_actions_back": "Voltar aos ícones",
|
||||
|
||||
@@ -249,6 +249,7 @@
|
||||
"interval_anchor": "Якорь интервала",
|
||||
"anchor_completion": "От даты выполнения",
|
||||
"anchor_planned": "От плановой даты (без смещения)",
|
||||
"interval_anchor_hint": "От даты выполнения: следующий срок отсчитывается от дня, когда задача отмечена выполненной, поэтому раннее или позднее выполнение сдвигает график. От плановой даты: график сохраняет свои даты, например когда счёт оплачен за несколько недель до срока.",
|
||||
"edit_object": "Изменить объект",
|
||||
"name": "Имя",
|
||||
"manufacturer_optional": "Производитель (опционально)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Дайте нескольким датчикам одно имя объекта — они станут одним объектом; введите имя существующего объекта, чтобы добавить их туда.",
|
||||
"adopt_summary_title": "Что изменит добавление",
|
||||
"adopt_summary_existing": "«{name}»: задачи {before} → {after}",
|
||||
"adopt_summary_totals": "Задачи: {tasks} · объекты: {objects}",
|
||||
"adopt_summary_totals_new": "Задачи: {tasks} · объекты: {objects} (из них новых: {new})",
|
||||
"adopt_problem_adopt": "Принять выбранные",
|
||||
"adopt_problem_done": "Принято сенсоров проблем: {tasks}",
|
||||
"adopt_problem_done_one": "Принят 1 сенсор проблем",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Парк батарей настроен — одна задача следит за всеми.",
|
||||
"update_banner": "На сервере более новая версия Maintenance Supporter — перезагрузите, чтобы обновить панель.",
|
||||
"update_reload": "Перезагрузить",
|
||||
"restart_pending_banner": "Maintenance Supporter обновлён до версии {version}. Перезапустите Home Assistant, чтобы завершить обновление.",
|
||||
"restart_pending_error": "Не получилось: Maintenance Supporter обновлён до версии {version}, но Home Assistant с тех пор не перезапускался. Перезапустите Home Assistant и попробуйте ещё раз.",
|
||||
"row_actions_banner": "«Выполнено» и «Пропустить» в строках задач теперь кнопки. Предпочитаете старые значки?",
|
||||
"row_actions_keep": "Оставить кнопки",
|
||||
"row_actions_back": "Вернуть значки",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"interval_anchor": "Intervallankare",
|
||||
"anchor_completion": "Från slutförandedatum",
|
||||
"anchor_planned": "Från planerat datum (ingen drift)",
|
||||
"interval_anchor_hint": "Från slutförandedatum: nästa förfallodatum räknas från dagen då uppgiften markeras som utförd, så att göra den tidigt eller sent flyttar schemat. Från planerat datum: schemat behåller sina datum, till exempel när en räkning betalas veckor före förfallodagen.",
|
||||
"edit_object": "Redigera objekt",
|
||||
"name": "Namn",
|
||||
"manufacturer_optional": "Tillverkare (valfritt)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Ge flera sensorer samma objektnamn så blir de ett objekt; skriv ett befintligt objekts namn för att lägga dem där.",
|
||||
"adopt_summary_title": "Vad övertagandet ändrar",
|
||||
"adopt_summary_existing": "”{name}”: uppgifter {before} → {after}",
|
||||
"adopt_summary_totals": "Uppgifter: {tasks} · objekt: {objects}",
|
||||
"adopt_summary_totals_new": "Uppgifter: {tasks} · objekt: {objects} (varav nya: {new})",
|
||||
"adopt_problem_adopt": "Anta valda",
|
||||
"adopt_problem_done": "Antog {tasks} problemsensor(er)",
|
||||
"adopt_problem_done_one": "Antog 1 problemsensor",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Batteriflotta konfigurerad — en uppgift följer alla batterier.",
|
||||
"update_banner": "En nyare version av Maintenance Supporter finns på servern — ladda om för att uppdatera panelen.",
|
||||
"update_reload": "Ladda om",
|
||||
"restart_pending_banner": "Maintenance Supporter har uppdaterats till {version}. Starta om Home Assistant för att slutföra uppdateringen.",
|
||||
"restart_pending_error": "Det fungerade inte: Maintenance Supporter har uppdaterats till {version}, men Home Assistant har inte startats om sedan dess. Starta om Home Assistant och försök igen.",
|
||||
"row_actions_banner": "Slutför och Hoppa över är nu knappar i uppgiftsraderna. Föredrar du de gamla ikonerna?",
|
||||
"row_actions_keep": "Behåll knappar",
|
||||
"row_actions_back": "Tillbaka till ikoner",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "Aralık referansı",
|
||||
"anchor_completion": "Tamamlama tarihinden",
|
||||
"anchor_planned": "Planlanan tarihten (kayma olmaz)",
|
||||
"interval_anchor_hint": "Tamamlama tarihinden: sonraki vade, görevin yapıldı olarak işaretlendiği günden itibaren sayılır; bu yüzden erken veya geç yapmak planı kaydırır. Planlanan tarihten: plan tarihlerini korur; örneğin bir fatura vadesinden haftalar önce ödendiğinde.",
|
||||
"edit_object": "Nesneyi Düzenle",
|
||||
"name": "Ad",
|
||||
"manufacturer_optional": "Üretici (isteğe bağlı)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Birden çok sensöre aynı nesne adını verin, tek nesne olurlar; mevcut bir nesnenin adını yazarsanız oraya eklenirler.",
|
||||
"adopt_summary_title": "Devralmanın değiştirecekleri",
|
||||
"adopt_summary_existing": "\"{name}\": görevler {before} → {after}",
|
||||
"adopt_summary_totals": "Görevler: {tasks} · nesneler: {objects}",
|
||||
"adopt_summary_totals_new": "Görevler: {tasks} · nesneler: {objects} (yeni: {new})",
|
||||
"adopt_problem_adopt": "Seçilenleri devral",
|
||||
"adopt_problem_done": "{tasks} sorun sensörü devralındı",
|
||||
"adopt_problem_done_one": "1 sorun sensörü devralındı",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Pil filosu kuruldu — tek bir görev tüm pillerinizi takip ediyor.",
|
||||
"update_banner": "Sunucuda Maintenance Supporter'ın daha yeni bir sürümü var — paneli güncellemek için sayfayı yeniden yükleyin.",
|
||||
"update_reload": "Yeniden yükle",
|
||||
"restart_pending_banner": "Maintenance Supporter {version} sürümüne güncellendi. Güncellemeyi tamamlamak için Home Assistant'ı yeniden başlatın.",
|
||||
"restart_pending_error": "Bu işlem başarısız oldu: Maintenance Supporter {version} sürümüne güncellendi, ancak Home Assistant o zamandan beri yeniden başlatılmadı. Home Assistant'ı yeniden başlatın ve tekrar deneyin.",
|
||||
"row_actions_banner": "Görev satırlarındaki Tamamla ve Atla artık düğme. Eski simgeleri mi tercih edersiniz?",
|
||||
"row_actions_keep": "Düğmeleri koru",
|
||||
"row_actions_back": "Simgelere geri dön",
|
||||
|
||||
@@ -249,6 +249,7 @@
|
||||
"interval_anchor": "Прив'язка інтервалу",
|
||||
"anchor_completion": "Від дати виконання",
|
||||
"anchor_planned": "Від запланованої дати (без зміщення)",
|
||||
"interval_anchor_hint": "Від дати виконання: наступний термін відраховується від дня, коли завдання позначено виконаним, тож раннє чи пізнє виконання зсуває графік. Від запланованої дати: графік зберігає свої дати, наприклад коли рахунок сплачено за кілька тижнів до терміну.",
|
||||
"edit_object": "Редагувати об'єкт",
|
||||
"name": "Назва",
|
||||
"manufacturer_optional": "Виробник (необов'язково)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "Дайте кільком сенсорам однакову назву об'єкта — вони стануть одним об'єктом; введіть назву наявного об'єкта, щоб додати їх туди.",
|
||||
"adopt_summary_title": "Що змінить додавання",
|
||||
"adopt_summary_existing": "«{name}»: завдання {before} → {after}",
|
||||
"adopt_summary_totals": "Завдання: {tasks} · об'єкти: {objects}",
|
||||
"adopt_summary_totals_new": "Завдання: {tasks} · об'єкти: {objects} (з них нових: {new})",
|
||||
"adopt_problem_adopt": "Прийняти вибрані",
|
||||
"adopt_problem_done": "Прийнято сенсорів проблем: {tasks}",
|
||||
"adopt_problem_done_one": "Прийнято 1 сенсор проблем",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "Парк батарей налаштовано — одне завдання стежить за всіма.",
|
||||
"update_banner": "На сервері новіша версія Maintenance Supporter — перезавантажте, щоб оновити панель.",
|
||||
"update_reload": "Перезавантажити",
|
||||
"restart_pending_banner": "Maintenance Supporter оновлено до версії {version}. Перезапустіть Home Assistant, щоб завершити оновлення.",
|
||||
"restart_pending_error": "Не вдалося: Maintenance Supporter оновлено до версії {version}, але Home Assistant відтоді не перезапускався. Перезапустіть Home Assistant і спробуйте ще раз.",
|
||||
"row_actions_banner": "«Виконано» та «Пропустити» в рядках завдань тепер кнопки. Бажаєте старі значки?",
|
||||
"row_actions_keep": "Залишити кнопки",
|
||||
"row_actions_back": "Повернути значки",
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
"interval_anchor": "计划锚点",
|
||||
"anchor_completion": "从完成日期起算",
|
||||
"anchor_planned": "从计划日期起算 (无偏差)",
|
||||
"interval_anchor_hint": "从完成日期起算:下一个到期日从任务标记为完成的那天开始计算,因此提前或推迟完成都会移动计划。从计划日期起算:计划保持原定日期,例如账单在到期前几周就已支付时。",
|
||||
"edit_object": "编辑维护项",
|
||||
"name": "名称",
|
||||
"manufacturer_optional": "制造商 (可选)",
|
||||
@@ -1121,6 +1122,8 @@
|
||||
"adopt_object_hint": "给多个传感器相同的对象名称,它们就会合并为一个对象;输入已有对象的名称即可加入该对象。",
|
||||
"adopt_summary_title": "采用后会发生的变化",
|
||||
"adopt_summary_existing": "“{name}”:任务 {before} → {after}",
|
||||
"adopt_summary_totals": "任务:{tasks} · 对象:{objects}",
|
||||
"adopt_summary_totals_new": "任务:{tasks} · 对象:{objects}(其中新建:{new})",
|
||||
"adopt_problem_adopt": "采用所选",
|
||||
"adopt_problem_done": "已采用 {tasks} 个问题传感器",
|
||||
"adopt_problem_done_one": "已采用 1 个问题传感器",
|
||||
@@ -1282,6 +1285,8 @@
|
||||
"battery_fleet_setup_done": "电池群已设置 — 一个任务跟踪所有电池。",
|
||||
"update_banner": "服务器上有更新版本的 Maintenance Supporter——请重新加载以更新面板。",
|
||||
"update_reload": "重新加载",
|
||||
"restart_pending_banner": "Maintenance Supporter 已更新到 {version} 版本。请重启 Home Assistant 以完成更新。",
|
||||
"restart_pending_error": "操作失败:Maintenance Supporter 已更新到 {version} 版本,但 Home Assistant 此后尚未重启。请重启 Home Assistant 后重试。",
|
||||
"row_actions_banner": "任务行中的“完成”和“跳过”现在是按钮。更喜欢旧的图标?",
|
||||
"row_actions_keep": "保留按钮",
|
||||
"row_actions_back": "改回图标",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*! maintenance_supporter frontend 2.102.0 */
|
||||
var Hr=Object.defineProperty;var Ba=Object.getOwnPropertyDescriptor;var y=(s,r,e)=>()=>{if(e)throw e[0];try{return s&&(r=s(s=0)),r}catch(t){throw e=[t],t}};var Wa=(s,r)=>{for(var e in r)Hr(s,e,{get:r[e],enumerable:!0})};var c=(s,r,e,t)=>{for(var i=t>1?void 0:t?Ba(r,e):r,n=s.length-1,o;n>=0;n--)(o=s[n])&&(i=(t?o(r,e,i):o(i))||i);return t&&i&&Hr(r,e,i),i};var Nt,Ht,Ci,qr,pt,Or,E,Dr,Ii,Ri=y(()=>{Nt=globalThis,Ht=Nt.ShadowRoot&&(Nt.ShadyCSS===void 0||Nt.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Ci=Symbol(),qr=new WeakMap,pt=class{constructor(r,e,t){if(this._$cssResult$=!0,t!==Ci)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=r,this.t=e}get styleSheet(){let r=this.o,e=this.t;if(Ht&&r===void 0){let t=e!==void 0&&e.length===1;t&&(r=qr.get(e)),r===void 0&&((this.o=r=new CSSStyleSheet).replaceSync(this.cssText),t&&qr.set(e,r))}return r}toString(){return this.cssText}},Or=s=>new pt(typeof s=="string"?s:s+"",void 0,Ci),E=(s,...r)=>{let e=s.length===1?s[0]:r.reduce((t,i,n)=>t+(o=>{if(o._$cssResult$===!0)return o.cssText;if(typeof o=="number")return o;throw Error("Value passed to 'css' function must be a 'css' function result: "+o+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+s[n+1],s[0]);return new pt(e,s,Ci)},Dr=(s,r)=>{if(Ht)s.adoptedStyleSheets=r.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of r){let t=document.createElement("style"),i=Nt.litNonce;i!==void 0&&t.setAttribute("nonce",i),t.textContent=e.cssText,s.appendChild(t)}},Ii=Ht?s=>s:s=>s instanceof CSSStyleSheet?(r=>{let e="";for(let t of r.cssRules)e+=t.cssText;return Or(e)})(s):s});var Va,Ga,Ka,Ya,Qa,Za,qt,jr,Ja,Xa,ut,ht,Ot,Mr,ce,_t=y(()=>{Ri();Ri();({is:Va,defineProperty:Ga,getOwnPropertyDescriptor:Ka,getOwnPropertyNames:Ya,getOwnPropertySymbols:Qa,getPrototypeOf:Za}=Object),qt=globalThis,jr=qt.trustedTypes,Ja=jr?jr.emptyScript:"",Xa=qt.reactiveElementPolyfillSupport,ut=(s,r)=>s,ht={toAttribute(s,r){switch(r){case Boolean:s=s?Ja:null;break;case Object:case Array:s=s==null?s:JSON.stringify(s)}return s},fromAttribute(s,r){let e=s;switch(r){case Boolean:e=s!==null;break;case Number:e=s===null?null:Number(s);break;case Object:case Array:try{e=JSON.parse(s)}catch{e=null}}return e}},Ot=(s,r)=>!Va(s,r),Mr={attribute:!0,type:String,converter:ht,reflect:!1,useDefault:!1,hasChanged:Ot};Symbol.metadata??=Symbol("metadata"),qt.litPropertyMetadata??=new WeakMap;ce=class extends HTMLElement{static addInitializer(r){this._$Ei(),(this.l??=[]).push(r)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(r,e=Mr){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(r)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(r,e),!e.noAccessor){let t=Symbol(),i=this.getPropertyDescriptor(r,t,e);i!==void 0&&Ga(this.prototype,r,i)}}static getPropertyDescriptor(r,e,t){let{get:i,set:n}=Ka(this.prototype,r)??{get(){return this[e]},set(o){this[e]=o}};return{get:i,set(o){let d=i?.call(this);n?.call(this,o),this.requestUpdate(r,d,t)},configurable:!0,enumerable:!0}}static getPropertyOptions(r){return this.elementProperties.get(r)??Mr}static _$Ei(){if(this.hasOwnProperty(ut("elementProperties")))return;let r=Za(this);r.finalize(),r.l!==void 0&&(this.l=[...r.l]),this.elementProperties=new Map(r.elementProperties)}static finalize(){if(this.hasOwnProperty(ut("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(ut("properties"))){let e=this.properties,t=[...Ya(e),...Qa(e)];for(let i of t)this.createProperty(i,e[i])}let r=this[Symbol.metadata];if(r!==null){let e=litPropertyMetadata.get(r);if(e!==void 0)for(let[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(let[e,t]of this.elementProperties){let i=this._$Eu(e,t);i!==void 0&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(r){let e=[];if(Array.isArray(r)){let t=new Set(r.flat(1/0).reverse());for(let i of t)e.unshift(Ii(i))}else r!==void 0&&e.push(Ii(r));return e}static _$Eu(r,e){let t=e.attribute;return t===!1?void 0:typeof t=="string"?t:typeof r=="string"?r.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(r=>this.enableUpdating=r),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(r=>r(this))}addController(r){(this._$EO??=new Set).add(r),this.renderRoot!==void 0&&this.isConnected&&r.hostConnected?.()}removeController(r){this._$EO?.delete(r)}_$E_(){let r=new Map,e=this.constructor.elementProperties;for(let t of e.keys())this.hasOwnProperty(t)&&(r.set(t,this[t]),delete this[t]);r.size>0&&(this._$Ep=r)}createRenderRoot(){let r=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return Dr(r,this.constructor.elementStyles),r}connectedCallback(){this.renderRoot??=tLine truncated
|
||||
\f\r]`,mt=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Ur=/-->/g,Br=/>/g,Te=RegExp(`>|${Pi}(?:([^\\s"'>=/]+)(${Pi}*=${Pi}*(?:[^
|
||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),Wr=/'/g,Vr=/"/g,Yr=/^(?:script|style|textarea|title)$/i,Oi=s=>(r,...e)=>({_$litType$:s,strings:r,values:e}),l=Oi(1),Ve=Oi(2),sc=Oi(3),Ie=Symbol.for("lit-noChange"),u=Symbol.for("lit-nothing"),Gr=new WeakMap,Ae=Ce.createTreeWalker(Ce,129);Zr=(s,r)=>{let e=s.length-1,t=[],i,n=r===2?"<svg>":r===3?"<math>":"",o=mt;for(let d=0;d<e;d++){let p=s[d],_,m,f=-1,x=0;for(;x<p.length&&(o.lastIndex=x,m=o.exec(p),m!==null);)x=o.lastIndex,o===mt?m[1]==="!--"?o=Ur:m[1]!==void 0?o=Br:m[2]!==void 0?(Yr.test(m[2])&&(i=RegExp("</"+m[2],"g")),o=Te):m[3]!==void 0&&(o=Te):o===Te?m[0]===">"?(o=i??mt,f=-1):m[1]===void 0?f=-2:(f=o.lastIndex-m[2].length,_=m[1],o=m[3]===void 0?Te:m[3]==='"'?Vr:Wr):o===Vr||o===Wr?o=Te:o===Ur||o===Br?o=mt:(o=Te,i=void 0);let w=o===Te&&s[d+1].startsWith("/>")?" ":"";n+=o===mt?p+eo:f>=0?(t.push(_),p.slice(0,f)+Ni+p.slice(f)+de+w):p+de+(f===-2?d:w)}return[Qr(s,n+(s[e]||"<?>")+(r===2?"</svg>":r===3?"</math>":"")),t]},vt=class s{constructor({strings:r,_$litType$:e},t){let i;this.parts=[];let n=0,o=0,d=r.length-1,p=this.parts,[_,m]=Zr(r,e);if(this.el=s.createElement(_,t),Ae.currentNode=this.el.content,e===2||e===3){let f=this.el.content.firstChild;f.replaceWith(...f.childNodes)}for(;(i=Ae.nextNode())!==null&&p.length<d;){if(i.nodeType===1){if(i.hasAttributes())for(let f of i.getAttributeNames())if(f.endsWith(Ni)){let x=m[o++],w=i.getAttribute(f).split(de),k=/([.?@])?(.*)/.exec(x);p.push({type:1,index:n,name:k[2],strings:w,ctor:k[1]==="."?Mt:k[1]==="?"?zt:k[1]==="@"?Ft:Pe}),i.removeAttribute(f)}else f.startsWith(de)&&(p.push({type:6,index:n}),i.removeAttribute(f));if(Yr.test(i.tagName)){let f=i.textContent.split(de),x=f.length-1;if(x>0){i.textContent=Dt?Dt.emptyScript:"";for(let w=0;w<x;w++)i.append(f[w],gt()),Ae.nextNode(),p.push({type:2,index:++n});i.append(f[x],gt())}}}else if(i.nodeType===8)if(i.data===Hi)p.push({type:2,index:n});else{let f=-1;for(;(f=i.data.indexOf(de,f+1))!==-1;)p.push({type:7,index:n}),f+=de.length-1}n++}}static createElement(r,e){let t=Ce.createElement("template");return t.innerHTML=r,t}};jt=class{constructor(r,e){this._$AV=[],this._$AN=void 0,this._$AD=r,this._$AM=e}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(r){let{el:{content:e},parts:t}=this._$AD,i=(r?.creationScope??Ce).importNode(e,!0);Ae.currentNode=i;let n=Ae.nextNode(),o=0,d=0,p=t[0];for(;p!==void 0;){if(o===p.index){let _;p.type===2?_=new We(n,n.nextSibling,this,r):p.type===1?_=new p.ctor(n,p.name,p.strings,this,r):p.type===6&&(_=new Ut(n,this,r)),this._$AV.push(_),p=t[++d]}o!==p?.index&&(n=Ae.nextNode(),o++)}return Ae.currentNode=Ce,i}p(r){let e=0;for(let t of this._$AV)t!==void 0&&(t.strings!==void 0?(t._$AI(r,t,e),e+=t.strings.length-2):t._$AI(r[e])),e++}},We=class s{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(r,e,t,i){this.type=2,this._$AH=u,this._$AN=void 0,this._$AA=r,this._$AB=e,this._$AM=t,this.options=i,this._$Cv=i?.isConnected??!0}get parentNode(){let r=this._$AA.parentNode,e=this._$AM;return e!==void 0&&r?.nodeType===11&&(r=e.parentNode),r}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(r,e=this){r=Re(this,r,e),ft(r)?r===u||r==null||r===""?(this._$AH!==u&&this._$AR(),this._$AH=u):r!==this._$AH&&r!==Ie&&this._(r):r._$litType$!==void 0?this.$(r):r.nodeType!==void 0?this.T(r):Kr(r)?this.k(r):this._(r)}O(r){return this._$AA.parentNode.insertBefore(r,this._$AB)}T(r){this._$AH!==r&&(this._$AR(),this._$AH=this.O(r))}_(r){this._$AH!==u&&ft(this._$AH)?this._$AA.nextSibling.data=r:this.T(Ce.createTextNode(r)),this._$AH=r}$(r){let{values:e,_$litType$:t}=r,i=typeof t=="number"?this._$AC(r):(t.el===void 0&&(t.el=vt.createElement(Qr(t.h,t.h[0]),this.options)),t);if(this._$AH?._$AD===i)this._$AH.p(e);else{let n=new jt(i,this),o=n.u(this.options);n.p(e),this.T(o),this._$AH=n}}_$AC(r){let e=Gr.get(r.strings);return e===void 0&&Gr.set(r.strings,e=new vt(r)),e}k(r){qi(this._$AH)||(this._$AH=[],this._$AR());let e=this._$AH,t,i=0;for(let n of r)i===e.length?e.push(t=new s(this.O(gt()),this.O(gt()),this,this.options)):t=e[i],t._$AI(n),i++;i<e.length&&(this._$AR(t&&t._$AB.nextSibling,i),e.length=i)}_$AR(r=this._$AA.nextSibling,e){for(this._$AP?.(!1,!0,e);r!==this._$AB;){let t=zr(r).nextSibling;zr(r).remove(),r=t}}setConnected(r){this._$AM===void 0&&(this._$Cv=r,this._$AP?.(r))}},Pe=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(r,e,t,i,n){this.type=1,this._$AH=u,this._$AN=void 0,this.element=r,this.name=e,this._$AM=i,this.options=n,t.length>2||t[0]!==""||t[1]!==""?(this._$AH=Array(t.length-1).fill(new String),this.strings=t):this._$AH=u}_$AI(r,e=this,t,i){let n=this.strings,o=!1;if(n===void 0)r=Re(this,r,e,0),o=!ft(r)||r!==this._$AH&&r!==Ie,o&&(this._$AH=r);else{let d=r,p,_;for(r=n[0],p=0;p<n.length-1;p++)_=Re(this,d[t+p],e,p),_===Ie&&(_=this._$AH[p]),o||=!ft(_)||_!==this._$AH[p],_===u?r=u:r!==u&&(r+=(_??"")+n[p+1]),this._$AH[p]=_}o&&!i&&this.j(r)}j(r){r===u?this.element.removeAttribute(this.naLine truncated
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
var qr=Object.defineProperty;var Wa=Object.getOwnPropertyDescriptor;var y=(s,r,e)=>()=>{if(e)throw e[0];try{return s&&(r=s(s=0)),r}catch(t){throw e=[t],t}};var Va=(s,r)=>{for(var e in r)qr(s,e,{get:r[e],enumerable:!0})};var c=(s,r,e,t)=>{for(var i=t>1?void 0:t?Wa(r,e):r,n=s.length-1,o;n>=0;n--)(o=s[n])&&(i=(t?o(r,e,i):o(i))||i);return t&&i&&qr(r,e,i),i};var Nt,Ht,Ci,Or,pt,Dr,E,jr,Ii,Ri=y(()=>{Nt=globalThis,Ht=Nt.ShadowRoot&&(Nt.ShadyCSS===void 0||Nt.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Ci=Symbol(),Or=new WeakMap,pt=class{constructor(r,e,t){if(this._$cssResult$=!0,t!==Ci)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=r,this.t=e}get styleSheet(){let r=this.o,e=this.t;if(Ht&&r===void 0){let t=e!==void 0&&e.length===1;t&&(r=Or.get(e)),r===void 0&&((this.o=r=new CSSStyleSheet).replaceSync(this.cssText),t&&Or.set(e,r))}return r}toString(){return this.cssText}},Dr=s=>new pt(typeof s=="string"?s:s+"",void 0,Ci),E=(s,...r)=>{let e=s.length===1?s[0]:r.reduce((t,i,n)=>t+(o=>{if(o._$cssResult$===!0)return o.cssText;if(typeof o=="number")return o;throw Error("Value passed to 'css' function must be a 'css' function result: "+o+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+s[n+1],s[0]);return new pt(e,s,Ci)},jr=(s,r)=>{if(Ht)s.adoptedStyleSheets=r.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of r){let t=document.createElement("style"),i=Nt.litNonce;i!==void 0&&t.setAttribute("nonce",i),t.textContent=e.cssText,s.appendChild(t)}},Ii=Ht?s=>s:s=>s instanceof CSSStyleSheet?(r=>{let e="";for(let t of r.cssRules)e+=t.cssText;return Dr(e)})(s):s});var Ga,Ka,Ya,Qa,Za,Ja,qt,Mr,Xa,eo,ut,ht,Ot,zr,ce,_t=y(()=>{Ri();Ri();({is:Ga,defineProperty:Ka,getOwnPropertyDescriptor:Ya,getOwnPropertyNames:Qa,getOwnPropertySymbols:Za,getPrototypeOf:Ja}=Object),qt=globalThis,Mr=qt.trustedTypes,Xa=Mr?Mr.emptyScript:"",eo=qt.reactiveElementPolyfillSupport,ut=(s,r)=>s,ht={toAttribute(s,r){switch(r){case Boolean:s=s?Xa:null;break;case Object:case Array:s=s==null?s:JSON.stringify(s)}return s},fromAttribute(s,r){let e=s;switch(r){case Boolean:e=s!==null;break;case Number:e=s===null?null:Number(s);break;case Object:case Array:try{e=JSON.parse(s)}catch{e=null}}return e}},Ot=(s,r)=>!Ga(s,r),zr={attribute:!0,type:String,converter:ht,reflect:!1,useDefault:!1,hasChanged:Ot};Symbol.metadata??=Symbol("metadata"),qt.litPropertyMetadata??=new WeakMap;ce=class extends HTMLElement{static addInitializer(r){this._$Ei(),(this.l??=[]).push(r)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(r,e=zr){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(r)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(r,e),!e.noAccessor){let t=Symbol(),i=this.getPropertyDescriptor(r,t,e);i!==void 0&&Ka(this.prototype,r,i)}}static getPropertyDescriptor(r,e,t){let{get:i,set:n}=Ya(this.prototype,r)??{get(){return this[e]},set(o){this[e]=o}};return{get:i,set(o){let d=i?.call(this);n?.call(this,o),this.requestUpdate(r,d,t)},configurable:!0,enumerable:!0}}static getPropertyOptions(r){return this.elementProperties.get(r)??zr}static _$Ei(){if(this.hasOwnProperty(ut("elementProperties")))return;let r=Ja(this);r.finalize(),r.l!==void 0&&(this.l=[...r.l]),this.elementProperties=new Map(r.elementProperties)}static finalize(){if(this.hasOwnProperty(ut("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(ut("properties"))){let e=this.properties,t=[...Qa(e),...Za(e)];for(let i of t)this.createProperty(i,e[i])}let r=this[Symbol.metadata];if(r!==null){let e=litPropertyMetadata.get(r);if(e!==void 0)for(let[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(let[e,t]of this.elementProperties){let i=this._$Eu(e,t);i!==void 0&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(r){let e=[];if(Array.isArray(r)){let t=new Set(r.flat(1/0).reverse());for(let i of t)e.unshift(Ii(i))}else r!==void 0&&e.push(Ii(r));return e}static _$Eu(r,e){let t=e.attribute;return t===!1?void 0:typeof t=="string"?t:typeof r=="string"?r.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(r=>this.enableUpdating=r),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(r=>r(this))}addController(r){(this._$EO??=new Set).add(r),this.renderRoot!==void 0&&this.isConnected&&r.hostConnected?.()}removeController(r){this._$EO?.delete(r)}_$E_(){let r=new Map,e=this.constructor.elementProperties;for(let t of e.keys())this.hasOwnProperty(t)&&(r.set(t,this[t]),delete this[t]);r.size>0&&(this._$Ep=r)}createRenderRoot(){let r=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return jr(r,this.constructor.elementStyles),r}connectedCallback(){this.renderRoot??=tLine truncated
|
||||
\f\r]`,mt=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Br=/-->/g,Wr=/>/g,Te=RegExp(`>|${Pi}(?:([^\\s"'>=/]+)(${Pi}*=${Pi}*(?:[^
|
||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),Vr=/'/g,Gr=/"/g,Qr=/^(?:script|style|textarea|title)$/i,Oi=s=>(r,...e)=>({_$litType$:s,strings:r,values:e}),l=Oi(1),Ve=Oi(2),oc=Oi(3),Ie=Symbol.for("lit-noChange"),u=Symbol.for("lit-nothing"),Kr=new WeakMap,Ae=Ce.createTreeWalker(Ce,129);Jr=(s,r)=>{let e=s.length-1,t=[],i,n=r===2?"<svg>":r===3?"<math>":"",o=mt;for(let d=0;d<e;d++){let p=s[d],_,m,f=-1,x=0;for(;x<p.length&&(o.lastIndex=x,m=o.exec(p),m!==null);)x=o.lastIndex,o===mt?m[1]==="!--"?o=Br:m[1]!==void 0?o=Wr:m[2]!==void 0?(Qr.test(m[2])&&(i=RegExp("</"+m[2],"g")),o=Te):m[3]!==void 0&&(o=Te):o===Te?m[0]===">"?(o=i??mt,f=-1):m[1]===void 0?f=-2:(f=o.lastIndex-m[2].length,_=m[1],o=m[3]===void 0?Te:m[3]==='"'?Gr:Vr):o===Gr||o===Vr?o=Te:o===Br||o===Wr?o=mt:(o=Te,i=void 0);let w=o===Te&&s[d+1].startsWith("/>")?" ":"";n+=o===mt?p+to:f>=0?(t.push(_),p.slice(0,f)+Ni+p.slice(f)+de+w):p+de+(f===-2?d:w)}return[Zr(s,n+(s[e]||"<?>")+(r===2?"</svg>":r===3?"</math>":"")),t]},vt=class s{constructor({strings:r,_$litType$:e},t){let i;this.parts=[];let n=0,o=0,d=r.length-1,p=this.parts,[_,m]=Jr(r,e);if(this.el=s.createElement(_,t),Ae.currentNode=this.el.content,e===2||e===3){let f=this.el.content.firstChild;f.replaceWith(...f.childNodes)}for(;(i=Ae.nextNode())!==null&&p.length<d;){if(i.nodeType===1){if(i.hasAttributes())for(let f of i.getAttributeNames())if(f.endsWith(Ni)){let x=m[o++],w=i.getAttribute(f).split(de),k=/([.?@])?(.*)/.exec(x);p.push({type:1,index:n,name:k[2],strings:w,ctor:k[1]==="."?Mt:k[1]==="?"?zt:k[1]==="@"?Ft:Pe}),i.removeAttribute(f)}else f.startsWith(de)&&(p.push({type:6,index:n}),i.removeAttribute(f));if(Qr.test(i.tagName)){let f=i.textContent.split(de),x=f.length-1;if(x>0){i.textContent=Dt?Dt.emptyScript:"";for(let w=0;w<x;w++)i.append(f[w],gt()),Ae.nextNode(),p.push({type:2,index:++n});i.append(f[x],gt())}}}else if(i.nodeType===8)if(i.data===Hi)p.push({type:2,index:n});else{let f=-1;for(;(f=i.data.indexOf(de,f+1))!==-1;)p.push({type:7,index:n}),f+=de.length-1}n++}}static createElement(r,e){let t=Ce.createElement("template");return t.innerHTML=r,t}};jt=class{constructor(r,e){this._$AV=[],this._$AN=void 0,this._$AD=r,this._$AM=e}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(r){let{el:{content:e},parts:t}=this._$AD,i=(r?.creationScope??Ce).importNode(e,!0);Ae.currentNode=i;let n=Ae.nextNode(),o=0,d=0,p=t[0];for(;p!==void 0;){if(o===p.index){let _;p.type===2?_=new We(n,n.nextSibling,this,r):p.type===1?_=new p.ctor(n,p.name,p.strings,this,r):p.type===6&&(_=new Ut(n,this,r)),this._$AV.push(_),p=t[++d]}o!==p?.index&&(n=Ae.nextNode(),o++)}return Ae.currentNode=Ce,i}p(r){let e=0;for(let t of this._$AV)t!==void 0&&(t.strings!==void 0?(t._$AI(r,t,e),e+=t.strings.length-2):t._$AI(r[e])),e++}},We=class s{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(r,e,t,i){this.type=2,this._$AH=u,this._$AN=void 0,this._$AA=r,this._$AB=e,this._$AM=t,this.options=i,this._$Cv=i?.isConnected??!0}get parentNode(){let r=this._$AA.parentNode,e=this._$AM;return e!==void 0&&r?.nodeType===11&&(r=e.parentNode),r}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(r,e=this){r=Re(this,r,e),ft(r)?r===u||r==null||r===""?(this._$AH!==u&&this._$AR(),this._$AH=u):r!==this._$AH&&r!==Ie&&this._(r):r._$litType$!==void 0?this.$(r):r.nodeType!==void 0?this.T(r):Yr(r)?this.k(r):this._(r)}O(r){return this._$AA.parentNode.insertBefore(r,this._$AB)}T(r){this._$AH!==r&&(this._$AR(),this._$AH=this.O(r))}_(r){this._$AH!==u&&ft(this._$AH)?this._$AA.nextSibling.data=r:this.T(Ce.createTextNode(r)),this._$AH=r}$(r){let{values:e,_$litType$:t}=r,i=typeof t=="number"?this._$AC(r):(t.el===void 0&&(t.el=vt.createElement(Zr(t.h,t.h[0]),this.options)),t);if(this._$AH?._$AD===i)this._$AH.p(e);else{let n=new jt(i,this),o=n.u(this.options);n.p(e),this.T(o),this._$AH=n}}_$AC(r){let e=Kr.get(r.strings);return e===void 0&&Kr.set(r.strings,e=new vt(r)),e}k(r){qi(this._$AH)||(this._$AH=[],this._$AR());let e=this._$AH,t,i=0;for(let n of r)i===e.length?e.push(t=new s(this.O(gt()),this.O(gt()),this,this.options)):t=e[i],t._$AI(n),i++;i<e.length&&(this._$AR(t&&t._$AB.nextSibling,i),e.length=i)}_$AR(r=this._$AA.nextSibling,e){for(this._$AP?.(!1,!0,e);r!==this._$AB;){let t=Fr(r).nextSibling;Fr(r).remove(),r=t}}setConnected(r){this._$AM===void 0&&(this._$Cv=r,this._$AP?.(r))}},Pe=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(r,e,t,i,n){this.type=1,this._$AH=u,this._$AN=void 0,this.element=r,this.name=e,this._$AM=i,this.options=n,t.length>2||t[0]!==""||t[1]!==""?(this._$AH=Array(t.length-1).fill(new String),this.strings=t):this._$AH=u}_$AI(r,e=this,t,i){let n=this.strings,o=!1;if(n===void 0)r=Re(this,r,e,0),o=!ft(r)||r!==this._$AH&&r!==Ie,o&&(this._$AH=r);else{let d=r,p,_;for(r=n[0],p=0;p<n.length-1;p++)_=Re(this,d[t+p],e,p),_===Ie&&(_=this._$AH[p]),o||=!ft(_)||_!==this._$AH[p],_===u?r=u:r!==u&&(r+=(_??"")+n[p+1]),this._$AH[p]=_}o&&!i&&this.j(r)}j(r){r===u?this.element.removeAttribute(this.naLine truncated
|
||||
Replace seal
|
||||
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",ws_err_not_found:"Not found \u2014 it may have been deleted meanwhile",ws_err_invalid_input:"Invalid input",ws_err_invalid_date:"Invalid date",ws_err_invalid_format:"Invalid format",ws_err_invalid_url:"Invalid link",ws_err_invalid_mirror_todo:"Invalid to-do list",ws_err_not_configured:"Not set up yet",ws_err_not_loaded:"Not loaded yet \u2014 try again in a moment",ws_err_limit_reached:"Limit reached",ws_err_too_many:"Too many entries",ws_err_too_large:"Too large",ws_err_not_archived:"Not archived",ws_err_invalid_target:"Invalid target",ws_err_create_failed:"Could not be created",ws_err_archived:"Archived \u2014 restore it first",ws_err_already_archived:"Already archived",ws_err_unavailable:"Currently unavailable",ws_err_unauthorized:"Not permitted for your user",ws_err_too_many_views:"Too many saved views",ws_err_storage_unavailable:"Storage is not available",ws_err_replace_failed:"Replacement failed",ws_err_not_paused:"Not paused",ws_err_not_available:"Nothing available",ws_err_no_url:"No link given",ws_err_no_phases:"This task has no phases",ws_err_invalid_view:"Invalid view",ws_err_invalid_user:"Unknown user",ws_err_invalid_range:"Invalid range",ws_err_invalid_parent:"Invalid parent object",ws_err_invalid_device:"Unknown device",ws_err_empty_csv:"The CSV file is empty",ws_err_empty:"Nothing to import",ws_err_duplicate_failed:"Could not duplicate",ws_err_already_paused:"Already paused",ws_err_invalid_cursor:"Invalid phase position",ws_err_invalid_entity_slug:"Invalid entity name",ws_err_invalid_trigger_config:"Invalid trigger configuration",ws_err_no_defaults:"No quick-complete defaults set",ws_err_self_link_device:"An object cannot be linked to itself",ws_err_too_early:"Too early \u2014 this task can only be completed closer to its due date",ws_err_invalid_search_template:"The search link must be an http(s) URL containing {q}",ws_err_invalid_icon:"The notification icon must be an mdi: name, e.g. mdi:air-filter",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_toggle:"Due at a specific time",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",notes_markdown_hint:"Markdown is supported \u2014 **bold**, lists, [links](\u2026)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",completed_at_optional:"Completed at (optional, empty = now)",completed_at_pick:"Set date & time",completed_at_future_error:"The completion date cannot be in the future.",ha_time_zone_hint:"Time in Home Assistant's time zone ({zone})",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",task_mirror_todo:"Mirror into to-do lists",task_mirror_todo_hint:"The task appears in these lists while it is due; checking it off there completes it here.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",all_priorities:"All priorities",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",object_replaces:"Replaces",object_replaced_by:"Replaced by",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",all_parts:"All parts",all_areas:"All areas",areas_filter:"Filter areas\u2026",areas_filter_none:"No area matches the filter.",area_cost_year:"Cost {year}",area_object_count:"{n} o
Line truncated
|
||||
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",ws_err_not_found:"Not found \u2014 it may have been deleted meanwhile",ws_err_invalid_input:"Invalid input",ws_err_invalid_date:"Invalid date",ws_err_invalid_format:"Invalid format",ws_err_invalid_url:"Invalid link",ws_err_invalid_mirror_todo:"Invalid to-do list",ws_err_not_configured:"Not set up yet",ws_err_not_loaded:"Not loaded yet \u2014 try again in a moment",ws_err_limit_reached:"Limit reached",ws_err_too_many:"Too many entries",ws_err_too_large:"Too large",ws_err_not_archived:"Not archived",ws_err_invalid_target:"Invalid target",ws_err_create_failed:"Could not be created",ws_err_archived:"Archived \u2014 restore it first",ws_err_already_archived:"Already archived",ws_err_unavailable:"Currently unavailable",ws_err_unauthorized:"Not permitted for your user",ws_err_too_many_views:"Too many saved views",ws_err_storage_unavailable:"Storage is not available",ws_err_replace_failed:"Replacement failed",ws_err_not_paused:"Not paused",ws_err_not_available:"Nothing available",ws_err_no_url:"No link given",ws_err_no_phases:"This task has no phases",ws_err_invalid_view:"Invalid view",ws_err_invalid_user:"Unknown user",ws_err_invalid_range:"Invalid range",ws_err_invalid_parent:"Invalid parent object",ws_err_invalid_device:"Unknown device",ws_err_empty_csv:"The CSV file is empty",ws_err_empty:"Nothing to import",ws_err_duplicate_failed:"Could not duplicate",ws_err_already_paused:"Already paused",ws_err_invalid_cursor:"Invalid phase position",ws_err_invalid_entity_slug:"Invalid entity name",ws_err_invalid_trigger_config:"Invalid trigger configuration",ws_err_no_defaults:"No quick-complete defaults set",ws_err_self_link_device:"An object cannot be linked to itself",ws_err_too_early:"Too early \u2014 this task can only be completed closer to its due date",ws_err_invalid_search_template:"The search link must be an http(s) URL containing {q}",ws_err_invalid_icon:"The notification icon must be an mdi: name, e.g. mdi:air-filter",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_toggle:"Due at a specific time",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",notes_markdown_hint:"Markdown is supported \u2014 **bold**, lists, [links](\u2026)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",completed_at_optional:"Completed at (optional, empty = now)",completed_at_pick:"Set date & time",completed_at_future_error:"The completion date cannot be in the future.",ha_time_zone_hint:"Time in Home Assistant's time zone ({zone})",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",task_mirror_todo:"Mirror into to-do lists",task_mirror_todo_hint:"The task appears in these lists while it is due; checking it off there completes it here.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",all_priorities:"All priorities",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",interval_anchor_hint:"From completion date: the next due date counts from the day the task is marked done, so doing it early or late moves the schedule. From planned date: the schedule keeps its dates, for example when a bill is paid weeks before it is due.",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",object_replaces:"Replaces",object_replaced_by:"Replaced by",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Obj
Line truncated
|
||||
.field { display: flex; flex-direction: column; gap: 4px; }
|
||||
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
||||
.field-input {
|
||||
@@ -14,7 +14,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
font-family: inherit; width: 100%; box-sizing: border-box;
|
||||
}
|
||||
.field-input:focus { outline: none; border-color: var(--primary-color); }
|
||||
`,So=E`
|
||||
`,To=E`
|
||||
.person-chip { display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; vertical-align: middle; }
|
||||
.person-avatar {
|
||||
width: 22px; height: 22px; border-radius: 50%; flex: none;
|
||||
@@ -24,7 +24,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.person-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
||||
`,To=E`
|
||||
`,Ao=E`
|
||||
.ref-chip {
|
||||
display: inline-block; font-size: 11.5px; font-weight: 500; line-height: 1; padding: 3px 6px;
|
||||
border-radius: 6px; border: 1px solid var(--divider-color); color: var(--secondary-text-color);
|
||||
@@ -34,8 +34,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
/* #189: "· Residual waste, Paper" after a calendar-driven task's name. */
|
||||
.event-titles { color: var(--secondary-text-color); font-weight: 400; }
|
||||
`,ni=E`
|
||||
${So}
|
||||
${To}
|
||||
${Ao}
|
||||
:host {
|
||||
--maint-ok-color: var(--success-color, #4caf50);
|
||||
--maint-due-soon-color: var(--warning-color, #ff9800);
|
||||
@@ -1290,7 +1290,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.stat-item .stat-label { font-size: 11px; white-space: normal; text-align: center; line-height: 1.2; hyphens: auto; overflow-wrap: anywhere; }
|
||||
.stat-value { font-size: 20px; }
|
||||
}
|
||||
`});function ai(s){if(!s)return[];let r=[],e=s.photo_doc_id;typeof e=="string"&&r.push(e);let t=s.photo_doc_ids;Array.isArray(t)&&r.push(...t);let i=[];for(let n of r){if(typeof n!="string")continue;let o=n.trim();if(!(!o||i.includes(o))&&(i.push(o),i.length>=10))break}return i}var oi=y(()=>{"use strict"});function Gs(){let s=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:r=>r.map(()=>Math.floor(Math.random()*256))}).getRandomValues(s),Array.from(s,r=>r.toString(16).padStart(2,"0")).join("")}function xe(s){let r=s?.reading_values;if(!Array.isArray(r))return[];let e=[],t=new Set;for(let i of r){if(!i||typeof i!="object")continue;let n=i;typeof n.id!="string"||!n.id||t.has(n.id)||typeof n.value!="number"||!Number.isFinite(n.value)||(t.add(n.id),e.push({id:n.id,name:typeof n.name=="string"?n.name:n.id,unit:typeof n.unit=="string"?n.unit:null,value:n.value}))}return e}function Ks(s){return s.filter(r=>r.type==="completed"&&(r.reading_value!=null||xe(r).length>0)).sort((r,e)=>r.timestamp.localeCompare(e.timestamp))}function Ys(s){return Ks(s??[]).map(r=>({timestamp:r.timestamp,values:xe(r)})).filter(r=>r.values.length>0)}function Qs(s,r,e){let t;for(let i of s){if(e!==void 0){let o=Q(i.timestamp);if(!isNaN(o)&&o>=e)break}let n=i.values.find(o=>o.id===r);n&&(t=n)}return t}function Zs(s,r,e){let t=xe(r).find(n=>n.id===e);if(!t)return null;let i=null;for(let n of Ks(s)){if(n.timestamp>=r.timestamp)break;let o=xe(n).find(d=>d.id===e);o&&(i=o.value)}return i==null?null:t.value-i}function Js(s){let r=new Set,e=new Set;for(let t of s){let i=(t.name||"").trim().toLowerCase();i&&(r.has(i)?e.add(t.id):r.add(i))}return e}function Xs(s){let r=[],e=new Set,t=new Set;for(let i of s){let n=(i.name||"").trim();if(!(!n||e.has(i.id)||t.has(n.toLowerCase()))&&(e.add(i.id),t.add(n.toLowerCase()),r.push({id:i.id,name:n,unit:(i.unit||"").trim()||null}),r.length>=er))break}return r}var er,je=y(()=>{"use strict";Z();er=20});function tr(s,r,e,t){let i=e,n=p=>typeof p=="string"?p:null,o=p=>typeof p=="number"?p:null,d=n(i.timestamp)??"";return{entry_id:s,task_id:r,original_timestamp:d,type:n(i.type)||"completed",timestamp:d,notes:n(i.notes),cost:o(i.cost),duration:o(i.duration),completed_by:n(i.completed_by),used_parts:Array.isArray(i.used_parts)?i.used_parts:null,photo_doc_ids:ai(i),reading_value:o(i.reading_value),reading_values:xe(i),readings:t?.readings??[],task_type:t?.type??null,reading_unit:t?.reading_unit??null}}async function en(s,r,e,t){let n=(await s.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:r})).tasks?.find(d=>d.id===e);if(!n)return null;let o=n.history?.find(d=>d.timestamp===t);return o||(o=(await s.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:r,task_id:e})).history?.find(p=>p.timestamp===t)),o?tr(r,e,o,n):null}var ir=y(()=>{"use strict";oi();je()});function we(s,r=Me){return s?s.is_admin?!0:r.operatorWriteEnabled&&r.operatorIds.includes(s.id):!1}var Me,wt=y(()=>{"use strict";Me={operatorWriteEnabled:!1,operatorIds:[]}});var tn,rn,sn,kt,$t,Et,rr,ke,Xe,St=y(()=>{"use strict";tn={default_warning_days:[0,365],default_consumable_threshold:[1,90],battery_low_percent:[1,90],battery_recovered_percent:[20,100],archive_oneoff_days:[0,3650],delete_archived_oneoff_days:[0,3650],notify_due_soon_interval_hours:[0,720],notify_overdue_interval_hours:[0,720],notify_triggered_interval_hours:[0,720],max_notifications_per_day:[0,1e3],notification_bundle_threshold:[2,20],snooze_duration_hours:[1,168],warranty_reminder_days:[1,365],budget_alert_threshold:[10,100],currency_decimals:[0,3]},rn=[0,1440],sn=[1,1e4],kt=[0,365],$t=15,Et=[.1,.9],rr=[0,365],ke=[.01,1e4],Xe=[.01,1e5]});function Co(s){let[r,e]=tn.default_warning_days,t=s?.general?.default_warning_days,i=s?.general?.row_action_style;return{features:{...li.features,...s?.features??{}},defaultWarningDays:typeof t=="number"&&Number.isFinite(t)&&t>=r&&t<=e?t:li.defaultWarningDays,rowActionStyle:Ao.includes(i??"")?i:li.rowActionStyle,access:{operatorWriteEnabled:s?.operator_write_enabled===!0,operatorIds:Array.isArray(s?.admin_panel_user_ids)?s.admin_panel_user_ids.filter(n=>typeof n=="string"):[]},budget:s?.budget??null,rowActionNoticePending:s?.general?.row_action_notice_pending===!0,refsInLists:s?.general?.ref_numbers_in_lists===!0,objectsTableColumns:Array.isArray(s?.objects_table_columns)?s.objects_table_columns:void 0,partsCostMode:ds(s?.budget?.parts_cost_mode)}}function nn(){let s=window;return s.__msSettingsCache??={promise:null}}function se(s){let r=nn();if(r.promise)return r.promise;let e=s.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(t=>Co(t)).catch(()=>(r.promise===e&&(r.promise=null),li));return r.promise=e,e}function an(){nn().promise=null}var Ao,li,Tt=y(()=>{"use strict";wt();St();Gt();Ao=["buttons_compact","buttons","icons"];li={features:{adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1,places:!1},def
Line truncated
|
||||
`});function ai(s){if(!s)return[];let r=[],e=s.photo_doc_id;typeof e=="string"&&r.push(e);let t=s.photo_doc_ids;Array.isArray(t)&&r.push(...t);let i=[];for(let n of r){if(typeof n!="string")continue;let o=n.trim();if(!(!o||i.includes(o))&&(i.push(o),i.length>=10))break}return i}var oi=y(()=>{"use strict"});function Ks(){let s=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:r=>r.map(()=>Math.floor(Math.random()*256))}).getRandomValues(s),Array.from(s,r=>r.toString(16).padStart(2,"0")).join("")}function xe(s){let r=s?.reading_values;if(!Array.isArray(r))return[];let e=[],t=new Set;for(let i of r){if(!i||typeof i!="object")continue;let n=i;typeof n.id!="string"||!n.id||t.has(n.id)||typeof n.value!="number"||!Number.isFinite(n.value)||(t.add(n.id),e.push({id:n.id,name:typeof n.name=="string"?n.name:n.id,unit:typeof n.unit=="string"?n.unit:null,value:n.value}))}return e}function Ys(s){return s.filter(r=>r.type==="completed"&&(r.reading_value!=null||xe(r).length>0)).sort((r,e)=>r.timestamp.localeCompare(e.timestamp))}function Qs(s){return Ys(s??[]).map(r=>({timestamp:r.timestamp,values:xe(r)})).filter(r=>r.values.length>0)}function Zs(s,r,e){let t;for(let i of s){if(e!==void 0){let o=Q(i.timestamp);if(!isNaN(o)&&o>=e)break}let n=i.values.find(o=>o.id===r);n&&(t=n)}return t}function Js(s,r,e){let t=xe(r).find(n=>n.id===e);if(!t)return null;let i=null;for(let n of Ys(s)){if(n.timestamp>=r.timestamp)break;let o=xe(n).find(d=>d.id===e);o&&(i=o.value)}return i==null?null:t.value-i}function Xs(s){let r=new Set,e=new Set;for(let t of s){let i=(t.name||"").trim().toLowerCase();i&&(r.has(i)?e.add(t.id):r.add(i))}return e}function en(s){let r=[],e=new Set,t=new Set;for(let i of s){let n=(i.name||"").trim();if(!(!n||e.has(i.id)||t.has(n.toLowerCase()))&&(e.add(i.id),t.add(n.toLowerCase()),r.push({id:i.id,name:n,unit:(i.unit||"").trim()||null}),r.length>=tr))break}return r}var tr,je=y(()=>{"use strict";Z();tr=20});function ir(s,r,e,t){let i=e,n=p=>typeof p=="string"?p:null,o=p=>typeof p=="number"?p:null,d=n(i.timestamp)??"";return{entry_id:s,task_id:r,original_timestamp:d,type:n(i.type)||"completed",timestamp:d,notes:n(i.notes),cost:o(i.cost),duration:o(i.duration),completed_by:n(i.completed_by),used_parts:Array.isArray(i.used_parts)?i.used_parts:null,photo_doc_ids:ai(i),reading_value:o(i.reading_value),reading_values:xe(i),readings:t?.readings??[],task_type:t?.type??null,reading_unit:t?.reading_unit??null}}async function tn(s,r,e,t){let n=(await s.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:r})).tasks?.find(d=>d.id===e);if(!n)return null;let o=n.history?.find(d=>d.timestamp===t);return o||(o=(await s.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:r,task_id:e})).history?.find(p=>p.timestamp===t)),o?ir(r,e,o,n):null}var rr=y(()=>{"use strict";oi();je()});function we(s,r=Me){return s?s.is_admin?!0:r.operatorWriteEnabled&&r.operatorIds.includes(s.id):!1}var Me,wt=y(()=>{"use strict";Me={operatorWriteEnabled:!1,operatorIds:[]}});var rn,sn,nn,kt,$t,Et,sr,ke,Xe,St=y(()=>{"use strict";rn={default_warning_days:[0,365],default_consumable_threshold:[1,90],battery_low_percent:[1,90],battery_recovered_percent:[20,100],archive_oneoff_days:[0,3650],delete_archived_oneoff_days:[0,3650],notify_due_soon_interval_hours:[0,720],notify_overdue_interval_hours:[0,720],notify_triggered_interval_hours:[0,720],max_notifications_per_day:[0,1e3],notification_bundle_threshold:[2,20],snooze_duration_hours:[1,168],warranty_reminder_days:[1,365],budget_alert_threshold:[10,100],currency_decimals:[0,3]},sn=[0,1440],nn=[1,1e4],kt=[0,365],$t=15,Et=[.1,.9],sr=[0,365],ke=[.01,1e4],Xe=[.01,1e5]});function Io(s){let[r,e]=rn.default_warning_days,t=s?.general?.default_warning_days,i=s?.general?.row_action_style;return{features:{...li.features,...s?.features??{}},defaultWarningDays:typeof t=="number"&&Number.isFinite(t)&&t>=r&&t<=e?t:li.defaultWarningDays,rowActionStyle:Co.includes(i??"")?i:li.rowActionStyle,access:{operatorWriteEnabled:s?.operator_write_enabled===!0,operatorIds:Array.isArray(s?.admin_panel_user_ids)?s.admin_panel_user_ids.filter(n=>typeof n=="string"):[]},budget:s?.budget??null,rowActionNoticePending:s?.general?.row_action_notice_pending===!0,refsInLists:s?.general?.ref_numbers_in_lists===!0,objectsTableColumns:Array.isArray(s?.objects_table_columns)?s.objects_table_columns:void 0,partsCostMode:ps(s?.budget?.parts_cost_mode)}}function an(){let s=window;return s.__msSettingsCache??={promise:null}}function se(s){let r=an();if(r.promise)return r.promise;let e=s.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(t=>Io(t)).catch(()=>(r.promise===e&&(r.promise=null),li));return r.promise=e,e}function on(){an().promise=null}var Co,li,Tt=y(()=>{"use strict";wt();St();Gt();Co=["buttons_compact","buttons","icons"];li={features:{adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1,places:!1},def
Line truncated
|
||||
<label class="field">
|
||||
${this.label?l`<span class="label">${this.label}${this.required?l`<span class="req">*</span>`:u}</span>`:u}
|
||||
${this.multiline?l`
|
||||
@@ -1367,7 +1367,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
color: var(--secondary-text-color);
|
||||
font-style: italic;
|
||||
}
|
||||
`,c([v()],j.prototype,"label",2),c([v()],j.prototype,"value",2),c([v()],j.prototype,"placeholder",2),c([v()],j.prototype,"type",2),c([v({type:Boolean})],j.prototype,"required",2),c([v({type:Boolean})],j.prototype,"disabled",2),c([v()],j.prototype,"step",2),c([v()],j.prototype,"min",2),c([v()],j.prototype,"max",2),c([v()],j.prototype,"pattern",2),c([v()],j.prototype,"helper",2),c([v({type:Boolean})],j.prototype,"multiline",2),c([v({type:Number})],j.prototype,"rows",2);customElements.get("ms-textfield")||customElements.define("ms-textfield",j)});function qo(s){let e=O("2001-02-03",s).match(/\d+/g)||[],t=d=>e.findIndex(p=>Number(p)===d),i=t(2001),n=t(2),o=t(3);return i===0?"YMD":n>=0&&o>=0&&n<o?"MDY":"DMY"}function et(s,r,e){if(s<1e3||s>9999||r<1||r>12||e<1||e>31)return null;let t=new Date(s,r-1,e);return t.getFullYear()!==s||t.getMonth()!==r-1||t.getDate()!==e?null:`${s}-${String(r).padStart(2,"0")}-${String(e).padStart(2,"0")}`}function dn(s,r){let e=s.trim(),t;if(t=e.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/))return et(+t[1],+t[2],+t[3]);if(t=e.match(/^(\d{4})$/))return et(+t[1],1,1);if(t=e.match(/^(\d{1,2})[./](\d{4})$/))return et(+t[2],+t[1],1);if(t=e.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/))return et(+t[3],+t[2],+t[1]);if(t=e.match(/^(\d{1,2})[/-](\d{1,2})[/-](\d{4})$/)){let i=+t[1],n=+t[2],o=+t[3];return qo(r)==="MDY"?et(o,i,n):et(o,n,i)}return null}var pn=y(()=>{"use strict";T()});function Oo(s,r){if(r)switch(s){case"date":return r.split("T")[0];case"time":return r.length===5?`${r}:00`:r;case"datetime":{let[e,t="00:00:00"]=r.split("T");return`${e} ${t.length===5?`${t}:00`:t}`}}}function Do(s,r){if(typeof r!="string"||!r)return"";switch(s){case"date":return r.slice(0,10);case"time":return r.slice(0,5);case"datetime":{let[e,t="00:00:00"]=r.split(" ");return`${e}T${t.length===5?`${t}:00`:t}`}}}var U,tt=y(()=>{"use strict";I();F();T();pn();U=class extends S{constructor(){super(...arguments);this.kind="date";this.label="";this.value="";this.clearable=!1;this.disabled=!1;this.required=!1;this.lang="en";this._typing=!1;this._typed="";this._typedInvalid=!1}_startTyping(){this._typed=this.value,this._typedInvalid=!1,this._typing=!0,this.updateComplete.then(()=>this.shadowRoot?.querySelector("input.typed")?.focus())}_commitTyped(){if(!this._typed.trim()){this._typing=!1;return}let e=dn(this._typed,this.lang);if(!e){this._typedInvalid=!0;return}this._typing=!1,this._typedInvalid=!1,this._emit(e)}_onTypedKey(e){e.key==="Enter"?(e.preventDefault(),this._commitTyped()):e.key==="Escape"&&(e.preventDefault(),this._typing=!1,this._typedInvalid=!1)}_selector(){switch(this.kind){case"date":return{date:{}};case"time":return{time:{no_second:!0}};case"datetime":return{datetime:{}}}}_onSelectorChange(e){e.stopPropagation(),this._emit(Do(this.kind,e.detail?.value))}_clear(){this._emit("")}_emit(e){e!==this.value&&(this.value=e,this.dispatchEvent(new CustomEvent("value-changed",{bubbles:!0,composed:!0,detail:{value:e}})))}render(){return l`
|
||||
`,c([v()],j.prototype,"label",2),c([v()],j.prototype,"value",2),c([v()],j.prototype,"placeholder",2),c([v()],j.prototype,"type",2),c([v({type:Boolean})],j.prototype,"required",2),c([v({type:Boolean})],j.prototype,"disabled",2),c([v()],j.prototype,"step",2),c([v()],j.prototype,"min",2),c([v()],j.prototype,"max",2),c([v()],j.prototype,"pattern",2),c([v()],j.prototype,"helper",2),c([v({type:Boolean})],j.prototype,"multiline",2),c([v({type:Number})],j.prototype,"rows",2);customElements.get("ms-textfield")||customElements.define("ms-textfield",j)});function jo(s){let e=O("2001-02-03",s).match(/\d+/g)||[],t=d=>e.findIndex(p=>Number(p)===d),i=t(2001),n=t(2),o=t(3);return i===0?"YMD":n>=0&&o>=0&&n<o?"MDY":"DMY"}function et(s,r,e){if(s<1e3||s>9999||r<1||r>12||e<1||e>31)return null;let t=new Date(s,r-1,e);return t.getFullYear()!==s||t.getMonth()!==r-1||t.getDate()!==e?null:`${s}-${String(r).padStart(2,"0")}-${String(e).padStart(2,"0")}`}function pn(s,r){let e=s.trim(),t;if(t=e.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/))return et(+t[1],+t[2],+t[3]);if(t=e.match(/^(\d{4})$/))return et(+t[1],1,1);if(t=e.match(/^(\d{1,2})[./](\d{4})$/))return et(+t[2],+t[1],1);if(t=e.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/))return et(+t[3],+t[2],+t[1]);if(t=e.match(/^(\d{1,2})[/-](\d{1,2})[/-](\d{4})$/)){let i=+t[1],n=+t[2],o=+t[3];return jo(r)==="MDY"?et(o,i,n):et(o,n,i)}return null}var un=y(()=>{"use strict";T()});function Mo(s,r){if(r)switch(s){case"date":return r.split("T")[0];case"time":return r.length===5?`${r}:00`:r;case"datetime":{let[e,t="00:00:00"]=r.split("T");return`${e} ${t.length===5?`${t}:00`:t}`}}}function zo(s,r){if(typeof r!="string"||!r)return"";switch(s){case"date":return r.slice(0,10);case"time":return r.slice(0,5);case"datetime":{let[e,t="00:00:00"]=r.split(" ");return`${e}T${t.length===5?`${t}:00`:t}`}}}var U,tt=y(()=>{"use strict";I();F();T();un();U=class extends S{constructor(){super(...arguments);this.kind="date";this.label="";this.value="";this.clearable=!1;this.disabled=!1;this.required=!1;this.lang="en";this._typing=!1;this._typed="";this._typedInvalid=!1}_startTyping(){this._typed=this.value,this._typedInvalid=!1,this._typing=!0,this.updateComplete.then(()=>this.shadowRoot?.querySelector("input.typed")?.focus())}_commitTyped(){if(!this._typed.trim()){this._typing=!1;return}let e=pn(this._typed,this.lang);if(!e){this._typedInvalid=!0;return}this._typing=!1,this._typedInvalid=!1,this._emit(e)}_onTypedKey(e){e.key==="Enter"?(e.preventDefault(),this._commitTyped()):e.key==="Escape"&&(e.preventDefault(),this._typing=!1,this._typedInvalid=!1)}_selector(){switch(this.kind){case"date":return{date:{}};case"time":return{time:{no_second:!0}};case"datetime":return{datetime:{}}}}_onSelectorChange(e){e.stopPropagation(),this._emit(zo(this.kind,e.detail?.value))}_clear(){this._emit("")}_emit(e){e!==this.value&&(this.value=e,this.dispatchEvent(new CustomEvent("value-changed",{bubbles:!0,composed:!0,detail:{value:e}})))}render(){return l`
|
||||
<div class="field">
|
||||
${this.label?l`<span class="label">${this.label}${this.required?l`<span class="req">*</span>`:u}</span>`:u}
|
||||
<div class="row">
|
||||
@@ -1380,7 +1380,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
@blur=${this._commitTyped} />`:l`<ha-selector
|
||||
.hass=${this.hass}
|
||||
.selector=${this._selector()}
|
||||
.value=${Oo(this.kind,this.value)}
|
||||
.value=${Mo(this.kind,this.value)}
|
||||
.required=${this.required}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._onSelectorChange}
|
||||
@@ -1453,7 +1453,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
}
|
||||
input.typed[aria-invalid="true"] { border-color: var(--error-color, #f44336); }
|
||||
input.typed:focus { outline: 2px solid var(--primary-color); outline-offset: -1px; }
|
||||
`,c([v({attribute:!1})],U.prototype,"hass",2),c([v()],U.prototype,"kind",2),c([v()],U.prototype,"label",2),c([v()],U.prototype,"value",2),c([v()],U.prototype,"helper",2),c([v({type:Boolean})],U.prototype,"clearable",2),c([v({type:Boolean})],U.prototype,"disabled",2),c([v({type:Boolean})],U.prototype,"required",2),c([v()],U.prototype,"lang",2),c([h()],U.prototype,"_typing",2),c([h()],U.prototype,"_typed",2),c([h()],U.prototype,"_typedInvalid",2);customElements.get("ms-date-field")||customElements.define("ms-date-field",U)});var R,un=y(()=>{"use strict";I();F();T();ze();sr();tt();R=class extends S{constructor(){super(...arguments);this.objects=[];this.placesEnabled=!1;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._place="";this._remindOnSite=!1;this._entryId=null;this._replacing=!1;this._oldDeviceId="";this._replaceDevice="keep"}get _lang(){return N(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._place="",this._remindOnSite=!1,this._replacing=!1,this._error="",this._open=!0}openReplace(e,t){this._entryId=e,this._replacing=!0,this._name=t.name||"",this._oldDeviceId=t.ha_device_id||"",this._haDeviceId="",this._replaceDevice="keep",this._error="",this._open=!0}openEdit(e,t){this._entryId=e,this._name=t.name||"",this._manufacturer=t.manufacturer||"",this._model=t.model||"",this._serialNumber=t.serial_number||"",this._areaId=t.area_id||"",this._installationDate=t.installation_date||"",this._warrantyExpiry=t.warranty_expiry||"",this._documentationUrl=t.documentation_url||"",this._notes=t.notes||"",this._haDeviceId=t.ha_device_id||"",this._parentEntryId=t.parent_entry_id||"",this._place=t.place||"",this._remindOnSite=!!t.remind_on_site,this._replacing=!1,this._error="",this._open=!0}async _replace(){if(this._loading||!this._entryId)return;let e={type:"maintenance_supporter/object/replace",entry_id:this._entryId,name:this._name.trim()||null};this._oldDeviceId?(this._replaceDevice==="other"&&(e.ha_device_id=this._haDeviceId),this._replaceDevice==="none"&&(e.ha_device_id=null)):this._haDeviceId&&(e.ha_device_id=this._haDeviceId);let t=await D(this,e,{busy:i=>{this._loading=i},fallbackKey:"save_error",onError:i=>{this._error=i}});t!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("object-replaced",{detail:{entry_id:t?.entry_id,device_swap:t?.device_swap}})))}_deviceName(e){let i=this.hass?.devices?.[e];return i?.name_by_user||i?.name||e}_deviceSelector(e){return l`<ha-form
|
||||
`,c([v({attribute:!1})],U.prototype,"hass",2),c([v()],U.prototype,"kind",2),c([v()],U.prototype,"label",2),c([v()],U.prototype,"value",2),c([v()],U.prototype,"helper",2),c([v({type:Boolean})],U.prototype,"clearable",2),c([v({type:Boolean})],U.prototype,"disabled",2),c([v({type:Boolean})],U.prototype,"required",2),c([v()],U.prototype,"lang",2),c([h()],U.prototype,"_typing",2),c([h()],U.prototype,"_typed",2),c([h()],U.prototype,"_typedInvalid",2);customElements.get("ms-date-field")||customElements.define("ms-date-field",U)});var R,hn=y(()=>{"use strict";I();F();T();ze();nr();tt();R=class extends S{constructor(){super(...arguments);this.objects=[];this.placesEnabled=!1;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._place="";this._remindOnSite=!1;this._entryId=null;this._replacing=!1;this._oldDeviceId="";this._replaceDevice="keep"}get _lang(){return N(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._place="",this._remindOnSite=!1,this._replacing=!1,this._error="",this._open=!0}openReplace(e,t){this._entryId=e,this._replacing=!0,this._name=t.name||"",this._oldDeviceId=t.ha_device_id||"",this._haDeviceId="",this._replaceDevice="keep",this._error="",this._open=!0}openEdit(e,t){this._entryId=e,this._name=t.name||"",this._manufacturer=t.manufacturer||"",this._model=t.model||"",this._serialNumber=t.serial_number||"",this._areaId=t.area_id||"",this._installationDate=t.installation_date||"",this._warrantyExpiry=t.warranty_expiry||"",this._documentationUrl=t.documentation_url||"",this._notes=t.notes||"",this._haDeviceId=t.ha_device_id||"",this._parentEntryId=t.parent_entry_id||"",this._place=t.place||"",this._remindOnSite=!!t.remind_on_site,this._replacing=!1,this._error="",this._open=!0}async _replace(){if(this._loading||!this._entryId)return;let e={type:"maintenance_supporter/object/replace",entry_id:this._entryId,name:this._name.trim()||null};this._oldDeviceId?(this._replaceDevice==="other"&&(e.ha_device_id=this._haDeviceId),this._replaceDevice==="none"&&(e.ha_device_id=null)):this._haDeviceId&&(e.ha_device_id=this._haDeviceId);let t=await D(this,e,{busy:i=>{this._loading=i},fallbackKey:"save_error",onError:i=>{this._error=i}});t!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("object-replaced",{detail:{entry_id:t?.entry_id,device_swap:t?.device_swap}})))}_deviceName(e){let i=this.hass?.devices?.[e];return i?.name_by_user||i?.name||e}_deviceSelector(e){return l`<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${{device:this._haDeviceId||void 0}}
|
||||
.schema=${[{name:"device",selector:{device:{}}}]}
|
||||
@@ -1707,7 +1707,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.radio-row input {
|
||||
margin: 0;
|
||||
}
|
||||
`,c([v({attribute:!1})],R.prototype,"hass",2),c([v({attribute:!1})],R.prototype,"objects",2),c([v({type:Boolean})],R.prototype,"placesEnabled",2),c([h()],R.prototype,"_open",2),c([h()],R.prototype,"_loading",2),c([h()],R.prototype,"_error",2),c([h()],R.prototype,"_name",2),c([h()],R.prototype,"_manufacturer",2),c([h()],R.prototype,"_model",2),c([h()],R.prototype,"_serialNumber",2),c([h()],R.prototype,"_areaId",2),c([h()],R.prototype,"_installationDate",2),c([h()],R.prototype,"_warrantyExpiry",2),c([h()],R.prototype,"_documentationUrl",2),c([h()],R.prototype,"_notes",2),c([h()],R.prototype,"_haDeviceId",2),c([h()],R.prototype,"_parentEntryId",2),c([h()],R.prototype,"_place",2),c([h()],R.prototype,"_remindOnSite",2),c([h()],R.prototype,"_entryId",2),c([h()],R.prototype,"_replacing",2),c([h()],R.prototype,"_oldDeviceId",2),c([h()],R.prototype,"_replaceDevice",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",R)});function jo(s){let r=(s||"").split(/\s+/).filter(Boolean);return r.length===0?"?":r.length===1?r[0][0].toUpperCase():(r[0][0]+r[r.length-1][0]).toUpperCase()}function Mo(s){let r=0;for(let e of s)r=r*31+e.charCodeAt(0)>>>0;return hn[r%hn.length]}function _n(s){return s?{id:s.id,name:s.name,initials:s.initials||jo(s.name),color:s.color||Mo(s.id)}:null}var hn,mn=y(()=>{"use strict";I();hn=["#c62828","#ad1457","#6a1b9a","#4527a0","#283593","#1565c0","#00838f","#2e7d32","#558b2f","#ef6c00","#6d4c41","#546e7a"]});var ci,gn=y(()=>{"use strict";mn();ci=class{constructor(r){this.usersCache=null;this.cacheTimestamp=0;this.CACHE_TTL_MS=6e4;this.hass=r}updateHass(r){this.hass=r}async getUsers(r=!1){let e=Date.now();if(!r&&this.usersCache&&e-this.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(r,e,t){await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/assign_user",entry_id:r,task_id:e,user_id:t})}async getTasksByUser(r){return(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/tasks/by_user",user_id:r})).tasks}getUserName(r){return!r||!this.usersCache?null:this.usersCache.find(t=>t.id===r)?.name||null}getPerson(r){return _n(this.getUser(r))}getUser(r){return!r||!this.usersCache?null:this.usersCache.find(e=>e.id===r)||null}getCurrentUserId(){return this.hass.user?.id||null}isCurrentUser(r){return r?r===this.getCurrentUserId():!1}clearCache(){this.usersCache=null,this.cacheTimestamp=0}}});function ae(s){return`${s.entry_id??""}\0${s.part_id}`}function fn(s,r,e,t){let i=!!s.entry_id&&s.entry_id!==r,n=i?s.entry_id:r,o=e.find(m=>m.entry_id===n),d=(o?.parts||[]).find(m=>m.id===s.part_id)||null,p=i&&o?.object?.name||"",_=d?.name||a("shared_part_unknown",t);return{part:d,foreign:i,ownerName:p,label:p?`${_} (${p})`:_}}function vn(s,r,e,t){let{part:i,label:n}=fn(s,r,e,t),o=i&&i.stock!==null&&i.stock!==void 0?` (${Ze(i.stock,i.unit,t)})`:"",d=i?.storage_location?` \u2014 ${i.storage_location}`:"";return`${C(s.quantity,t)}\xD7 ${n}${o}${d}`}function yn(s,r,e,t){let n=(e.find(d=>d.entry_id===r)?.parts||[]).map(d=>({...d})),o=new Set(n.map(d=>ae({part_id:d.id})));for(let d of s?.consumes_parts||[]){if(!d.entry_id||d.entry_id===r)continue;let p=ae(d);if(o.has(p))continue;o.add(p);let{part:_,ownerName:m}=fn(d,r,e,t);n.push({id:d.part_id,name:_?.name||a("shared_part_unknown",t),unit:_?.unit,stock:_?.stock??null,storage_location:_?.storage_location,entry_id:d.entry_id,owner_name:m})}return n}var di=y(()=>{"use strict";T()});var nr,bn,xn,wn=y(()=>{"use strict";nr=["sensor","binary_sensor","number","input_number","input_boolean","switch","climate","vacuum","cover","fan","light","water_heater","humidifier","media_player","weather","air_quality","valve","lawn_mower","lock","plant"],bn=["sensor"],xn=["temperature","humidity","pressure"]});function it(s){let r=(s??"").trim();if(r==="")return null;let e=Number(r.replace(",","."));return!Number.isFinite(e)||e<0?null:Math.round(e)}var pi=y(()=>{"use strict"});var ar,At,or=y(()=>{"use strict";ar=["notes","cost","duration","photo","user"],At={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"}});var zo,Fo,lr,kn=y(()=>{"use strict";zo={cleaning:"mdi:broom",inspection:"mdi:magnify",replacement:"mdi:swap-horizontal",calibration:"mdi:tune",service:"mdi:wrench",reading:"mdi:counter",custom:"mdi:wrench-clock"},Fo="mdi:wrench-clock",lr=s=>s&&zo[s]||Fo});function ui(s){return s?Array.isArray(s.entity_ids)&&s.entity_ids.length>0?[...s.entity_ids]:s.entity_id?[s.entity_id]:[]:[]}function $n(s){if(!(!s||s.type==="compound"))return ui(s)[0]}var En=y(()=>{"use strict"});var $e,hi=y(()=>{"use strict";I();F();T();$e=class extends S{constructor(){super(...arguments);this.value="";this.lang="en";th
Line truncated
|
||||
`,c([v({attribute:!1})],R.prototype,"hass",2),c([v({attribute:!1})],R.prototype,"objects",2),c([v({type:Boolean})],R.prototype,"placesEnabled",2),c([h()],R.prototype,"_open",2),c([h()],R.prototype,"_loading",2),c([h()],R.prototype,"_error",2),c([h()],R.prototype,"_name",2),c([h()],R.prototype,"_manufacturer",2),c([h()],R.prototype,"_model",2),c([h()],R.prototype,"_serialNumber",2),c([h()],R.prototype,"_areaId",2),c([h()],R.prototype,"_installationDate",2),c([h()],R.prototype,"_warrantyExpiry",2),c([h()],R.prototype,"_documentationUrl",2),c([h()],R.prototype,"_notes",2),c([h()],R.prototype,"_haDeviceId",2),c([h()],R.prototype,"_parentEntryId",2),c([h()],R.prototype,"_place",2),c([h()],R.prototype,"_remindOnSite",2),c([h()],R.prototype,"_entryId",2),c([h()],R.prototype,"_replacing",2),c([h()],R.prototype,"_oldDeviceId",2),c([h()],R.prototype,"_replaceDevice",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",R)});function Fo(s){let r=(s||"").split(/\s+/).filter(Boolean);return r.length===0?"?":r.length===1?r[0][0].toUpperCase():(r[0][0]+r[r.length-1][0]).toUpperCase()}function Uo(s){let r=0;for(let e of s)r=r*31+e.charCodeAt(0)>>>0;return _n[r%_n.length]}function mn(s){return s?{id:s.id,name:s.name,initials:s.initials||Fo(s.name),color:s.color||Uo(s.id)}:null}var _n,gn=y(()=>{"use strict";I();_n=["#c62828","#ad1457","#6a1b9a","#4527a0","#283593","#1565c0","#00838f","#2e7d32","#558b2f","#ef6c00","#6d4c41","#546e7a"]});var ci,fn=y(()=>{"use strict";gn();ci=class{constructor(r){this.usersCache=null;this.cacheTimestamp=0;this.CACHE_TTL_MS=6e4;this.hass=r}updateHass(r){this.hass=r}async getUsers(r=!1){let e=Date.now();if(!r&&this.usersCache&&e-this.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(r,e,t){await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/assign_user",entry_id:r,task_id:e,user_id:t})}async getTasksByUser(r){return(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/tasks/by_user",user_id:r})).tasks}getUserName(r){return!r||!this.usersCache?null:this.usersCache.find(t=>t.id===r)?.name||null}getPerson(r){return mn(this.getUser(r))}getUser(r){return!r||!this.usersCache?null:this.usersCache.find(e=>e.id===r)||null}getCurrentUserId(){return this.hass.user?.id||null}isCurrentUser(r){return r?r===this.getCurrentUserId():!1}clearCache(){this.usersCache=null,this.cacheTimestamp=0}}});function ae(s){return`${s.entry_id??""}\0${s.part_id}`}function vn(s,r,e,t){let i=!!s.entry_id&&s.entry_id!==r,n=i?s.entry_id:r,o=e.find(m=>m.entry_id===n),d=(o?.parts||[]).find(m=>m.id===s.part_id)||null,p=i&&o?.object?.name||"",_=d?.name||a("shared_part_unknown",t);return{part:d,foreign:i,ownerName:p,label:p?`${_} (${p})`:_}}function yn(s,r,e,t){let{part:i,label:n}=vn(s,r,e,t),o=i&&i.stock!==null&&i.stock!==void 0?` (${Ze(i.stock,i.unit,t)})`:"",d=i?.storage_location?` \u2014 ${i.storage_location}`:"";return`${C(s.quantity,t)}\xD7 ${n}${o}${d}`}function bn(s,r,e,t){let n=(e.find(d=>d.entry_id===r)?.parts||[]).map(d=>({...d})),o=new Set(n.map(d=>ae({part_id:d.id})));for(let d of s?.consumes_parts||[]){if(!d.entry_id||d.entry_id===r)continue;let p=ae(d);if(o.has(p))continue;o.add(p);let{part:_,ownerName:m}=vn(d,r,e,t);n.push({id:d.part_id,name:_?.name||a("shared_part_unknown",t),unit:_?.unit,stock:_?.stock??null,storage_location:_?.storage_location,entry_id:d.entry_id,owner_name:m})}return n}var di=y(()=>{"use strict";T()});var ar,xn,wn,kn=y(()=>{"use strict";ar=["sensor","binary_sensor","number","input_number","input_boolean","switch","climate","vacuum","cover","fan","light","water_heater","humidifier","media_player","weather","air_quality","valve","lawn_mower","lock","plant"],xn=["sensor"],wn=["temperature","humidity","pressure"]});function it(s){let r=(s??"").trim();if(r==="")return null;let e=Number(r.replace(",","."));return!Number.isFinite(e)||e<0?null:Math.round(e)}var pi=y(()=>{"use strict"});var or,At,lr=y(()=>{"use strict";or=["notes","cost","duration","photo","user"],At={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"}});var Bo,Wo,cr,$n=y(()=>{"use strict";Bo={cleaning:"mdi:broom",inspection:"mdi:magnify",replacement:"mdi:swap-horizontal",calibration:"mdi:tune",service:"mdi:wrench",reading:"mdi:counter",custom:"mdi:wrench-clock"},Wo="mdi:wrench-clock",cr=s=>s&&Bo[s]||Wo});function ui(s){return s?Array.isArray(s.entity_ids)&&s.entity_ids.length>0?[...s.entity_ids]:s.entity_id?[s.entity_id]:[]:[]}function En(s){if(!(!s||s.type==="compound"))return ui(s)[0]}var Sn=y(()=>{"use strict"});var $e,hi=y(()=>{"use strict";I();F();T();$e=class extends S{constructor(){super(...arguments);this.value="";this.lang="en";th
Line truncated
|
||||
<div class="wrap">
|
||||
<div class="sign" role="group">
|
||||
<button type="button" class="kind cost ${this._credit?"":"on"}" aria-pressed=${String(!this._credit)}
|
||||
@@ -1742,9 +1742,9 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.kind.credit.on { background: var(--success-color, #43a047); }
|
||||
.amount { flex: 1; min-width: 0; }
|
||||
.hint { margin-top: 4px; font-size: 12px; color: var(--secondary-text-color); }
|
||||
`],c([v()],$e.prototype,"value",2),c([v()],$e.prototype,"lang",2),c([h()],$e.prototype,"_credit",2),c([h()],$e.prototype,"_amount",2);customElements.get("ms-cost-input")||customElements.define("ms-cost-input",$e)});function An(){return{entityIds:"",type:"threshold",attribute:"",above:"",below:"",equals:"",notEquals:"",forMinutes:"0",targetValue:"",deltaMode:!1,fromState:"",toState:"",targetChanges:"",runtimeHours:"",onStates:"",daysBefore:"0",carry:{}}}function In(s){return{type:s.type||"threshold",attribute:s.attribute||"",above:s.trigger_above?.toString()??"",below:s.trigger_below?.toString()??"",equals:s.trigger_equals?.toString()??"",notEquals:s.trigger_not_equals?.toString()??"",forMinutes:s.trigger_for_minutes?.toString()??"0",targetValue:s.trigger_target_value?.toString()??"",deltaMode:s.trigger_delta_mode||!1,fromState:s.trigger_from_state||"",toState:s.trigger_to_state||"",targetChanges:s.trigger_target_changes?.toString()??"",runtimeHours:s.trigger_runtime_hours?.toString()??"",onStates:(s.trigger_on_states||[]).join(", "),daysBefore:s.trigger_days_before?.toString()??"0"}}function Rn(s,r){r.attribute&&(s.attribute=r.attribute);let e=parseInt(r.forMinutes,10);if(r.type==="threshold"){let t=parseFloat(r.above);isNaN(t)||(s.trigger_above=t);let i=parseFloat(r.below);isNaN(i)||(s.trigger_below=i);let n=parseFloat(r.equals);isNaN(n)||(s.trigger_equals=n);let o=parseFloat(r.notEquals);isNaN(o)||(s.trigger_not_equals=o),isNaN(e)||(s.trigger_for_minutes=e)}else if(r.type==="counter"){let t=parseFloat(r.targetValue);isNaN(t)||(s.trigger_target_value=t),s.trigger_delta_mode=r.deltaMode}else if(r.type==="state_change"){r.fromState&&(s.trigger_from_state=r.fromState),r.toState&&(s.trigger_to_state=r.toState);let t=parseInt(r.targetChanges,10);isNaN(t)||(s.trigger_target_changes=t),isNaN(e)||(s.trigger_for_minutes=e)}else if(r.type==="runtime"){let t=parseFloat(r.runtimeHours);isNaN(t)||(s.trigger_runtime_hours=t);let i=(r.onStates||"").split(",").map(n=>n.trim()).filter(Boolean);i.length>0&&(s.trigger_on_states=i)}else if(r.type==="due_date"){let t=parseInt(r.daysBefore,10);s.trigger_days_before=isNaN(t)?0:t}}function Ko(s){return{entityIds:ui(s).join(", "),...In(s),carry:Object.fromEntries(Object.entries(s).filter(([e])=>!Go.has(e)&&!e.startsWith("_")))}}function Yo(s){let r=s.entityIds.split(",").map(t=>t.trim()).filter(Boolean);if(r.length===0)return null;let e={...s.carry||{},entity_id:r[0],entity_ids:r,type:s.type};return Rn(e,s),e}function Qo(s){return Array.from({length:7},(r,e)=>Qe(e,s,"short"))}function Zo(s){return Array.from({length:12},(r,e)=>Xi(e,s,"short"))}var Uo,Bo,Wo,_i,Sn,Cn,Tn,Vo,pe,Fe,Go,g,cr,Pn=y(()=>{"use strict";I();F();T();gn();di();je();wn();ze();St();pi();or();sr();kn();En();tt();hi();Uo=["cleaning","inspection","replacement","calibration","service","reading","custom"],Bo=["low","normal","high"],Wo=["time_based","weekdays","nth_weekday","day_of_month","calendar","sensor_based","one_time","manual"],_i=["weekdays","nth_weekday","day_of_month","calendar"],Sn=["time_based","one_time",..._i],Cn=["threshold","counter","state_change","runtime","due_date"],Tn=(s,r)=>a(s==="due_date"?"trigger_type_due_date":s,r),Vo=[...Cn,"compound"],pe={alpha:"0.3",min:"7",max:"365"},Fe=ke;Go=new Set(["entity_id","entity_ids","type","attribute","trigger_above","trigger_below","trigger_equals","trigger_not_equals","trigger_for_minutes","trigger_target_value","trigger_delta_mode","trigger_from_state","trigger_to_state","trigger_target_changes","trigger_runtime_hours","trigger_on_states","trigger_days_before"]);g=class g extends S{constructor(){super(...arguments);this.checklistsEnabled=!1;this.scheduleTimeEnabled=!1;this.completionActionsEnabled=!1;this.adaptiveFeature=!1;this.seasonalFeature=!1;this.environmentalFeature=!1;this.defaultWarningDays=7;this.parts=[];this._foreignOwners=[];this._open=!1;this._entityPickerFallback=!1;this._pickerProbeStrikes=0;this._loading=!1;this._error="";this._warning="";this._entryId="";this._taskId=null;this._isFleetTask=!1;this._objectChoices=[];this._name="";this._type="custom";this._scheduleType="time_based";this._intervalDays="30";this._intervalUnit="days";this._dueDate="";this._warningDays="7";this._earliestCompletionDays="";this._intervalAnchor="completion";this._weekdays=[];this._nth="1";this._nthWeekday="5";this._domDay="1";this._domLastDay=!1;this._domBusiness=!1;this._calOffset="0";this._calendarEntity="";this._seasonMonths=[];this._endsMode="never";this._endsCount="";this._endsUntil="";this._schedulePreview=[];this._schedulePreviewEnded=!1;this._previewSeq=0;this._notes="";this._documentationUrl="";this._customIcon="";this._notifyIcon="";this._priority="normal";this._labels="";this._mirrorTodoEntities=[];this._enabled=!0;this._triggerEntityId="";this._triggerEntityIds=[];this._triggerEntityLogic="any";this._triggerAttribute="";this._triggerType="threshold";this._triggerAbove="";this._triggerBelow="";this._triggerEquals="";this._triggerNotEquals="";this._trigg
Line truncated
|
||||
`],c([v()],$e.prototype,"value",2),c([v()],$e.prototype,"lang",2),c([h()],$e.prototype,"_credit",2),c([h()],$e.prototype,"_amount",2);customElements.get("ms-cost-input")||customElements.define("ms-cost-input",$e)});function Cn(){return{entityIds:"",type:"threshold",attribute:"",above:"",below:"",equals:"",notEquals:"",forMinutes:"0",targetValue:"",deltaMode:!1,fromState:"",toState:"",targetChanges:"",runtimeHours:"",onStates:"",daysBefore:"0",carry:{}}}function Rn(s){return{type:s.type||"threshold",attribute:s.attribute||"",above:s.trigger_above?.toString()??"",below:s.trigger_below?.toString()??"",equals:s.trigger_equals?.toString()??"",notEquals:s.trigger_not_equals?.toString()??"",forMinutes:s.trigger_for_minutes?.toString()??"0",targetValue:s.trigger_target_value?.toString()??"",deltaMode:s.trigger_delta_mode||!1,fromState:s.trigger_from_state||"",toState:s.trigger_to_state||"",targetChanges:s.trigger_target_changes?.toString()??"",runtimeHours:s.trigger_runtime_hours?.toString()??"",onStates:(s.trigger_on_states||[]).join(", "),daysBefore:s.trigger_days_before?.toString()??"0"}}function Pn(s,r){r.attribute&&(s.attribute=r.attribute);let e=parseInt(r.forMinutes,10);if(r.type==="threshold"){let t=parseFloat(r.above);isNaN(t)||(s.trigger_above=t);let i=parseFloat(r.below);isNaN(i)||(s.trigger_below=i);let n=parseFloat(r.equals);isNaN(n)||(s.trigger_equals=n);let o=parseFloat(r.notEquals);isNaN(o)||(s.trigger_not_equals=o),isNaN(e)||(s.trigger_for_minutes=e)}else if(r.type==="counter"){let t=parseFloat(r.targetValue);isNaN(t)||(s.trigger_target_value=t),s.trigger_delta_mode=r.deltaMode}else if(r.type==="state_change"){r.fromState&&(s.trigger_from_state=r.fromState),r.toState&&(s.trigger_to_state=r.toState);let t=parseInt(r.targetChanges,10);isNaN(t)||(s.trigger_target_changes=t),isNaN(e)||(s.trigger_for_minutes=e)}else if(r.type==="runtime"){let t=parseFloat(r.runtimeHours);isNaN(t)||(s.trigger_runtime_hours=t);let i=(r.onStates||"").split(",").map(n=>n.trim()).filter(Boolean);i.length>0&&(s.trigger_on_states=i)}else if(r.type==="due_date"){let t=parseInt(r.daysBefore,10);s.trigger_days_before=isNaN(t)?0:t}}function Zo(s){return{entityIds:ui(s).join(", "),...Rn(s),carry:Object.fromEntries(Object.entries(s).filter(([e])=>!Qo.has(e)&&!e.startsWith("_")))}}function Jo(s){let r=s.entityIds.split(",").map(t=>t.trim()).filter(Boolean);if(r.length===0)return null;let e={...s.carry||{},entity_id:r[0],entity_ids:r,type:s.type};return Pn(e,s),e}function Xo(s){return Array.from({length:7},(r,e)=>Qe(e,s,"short"))}function el(s){return Array.from({length:12},(r,e)=>er(e,s,"short"))}var Vo,Go,Ko,_i,Tn,In,An,Yo,pe,Fe,Qo,g,dr,Ln=y(()=>{"use strict";I();F();T();fn();di();je();kn();ze();St();pi();lr();nr();$n();Sn();tt();hi();Vo=["cleaning","inspection","replacement","calibration","service","reading","custom"],Go=["low","normal","high"],Ko=["time_based","weekdays","nth_weekday","day_of_month","calendar","sensor_based","one_time","manual"],_i=["weekdays","nth_weekday","day_of_month","calendar"],Tn=["time_based","one_time",..._i],In=["threshold","counter","state_change","runtime","due_date"],An=(s,r)=>a(s==="due_date"?"trigger_type_due_date":s,r),Yo=[...In,"compound"],pe={alpha:"0.3",min:"7",max:"365"},Fe=ke;Qo=new Set(["entity_id","entity_ids","type","attribute","trigger_above","trigger_below","trigger_equals","trigger_not_equals","trigger_for_minutes","trigger_target_value","trigger_delta_mode","trigger_from_state","trigger_to_state","trigger_target_changes","trigger_runtime_hours","trigger_on_states","trigger_days_before"]);g=class g extends S{constructor(){super(...arguments);this.checklistsEnabled=!1;this.scheduleTimeEnabled=!1;this.completionActionsEnabled=!1;this.adaptiveFeature=!1;this.seasonalFeature=!1;this.environmentalFeature=!1;this.defaultWarningDays=7;this.parts=[];this._foreignOwners=[];this._open=!1;this._entityPickerFallback=!1;this._pickerProbeStrikes=0;this._loading=!1;this._error="";this._warning="";this._entryId="";this._taskId=null;this._isFleetTask=!1;this._objectChoices=[];this._name="";this._type="custom";this._scheduleType="time_based";this._intervalDays="30";this._intervalUnit="days";this._dueDate="";this._warningDays="7";this._earliestCompletionDays="";this._intervalAnchor="completion";this._weekdays=[];this._nth="1";this._nthWeekday="5";this._domDay="1";this._domLastDay=!1;this._domBusiness=!1;this._calOffset="0";this._calendarEntity="";this._seasonMonths=[];this._endsMode="never";this._endsCount="";this._endsUntil="";this._schedulePreview=[];this._schedulePreviewEnded=!1;this._previewSeq=0;this._notes="";this._documentationUrl="";this._customIcon="";this._notifyIcon="";this._priority="normal";this._labels="";this._mirrorTodoEntities=[];this._enabled=!0;this._triggerEntityId="";this._triggerEntityIds=[];this._triggerEntityLogic="any";this._triggerAttribute="";this._triggerType="threshold";this._triggerAbove="";this._triggerBelow="";this._triggerEquals="";this._triggerNotEquals="";this._trigg
Line truncated
|
||||
`),this._phaseDefs=Object.entries(t.phases||{}).map(([_,m])=>{let{name:f,checklist:x,consumes_parts:w,required_completion_fields:k,...H}=m,L=m.consumes_parts||[],M=L.findIndex(W=>!W.entry_id),B=M>=0?L[M]:void 0;return{id:_,name:m.name||_,checklistText:(m.checklist||[]).join(`
|
||||
`),partId:B?.part_id||"",partQty:B?.quantity!=null?String(B.quantity):"",reqOverride:m.required_completion_fields!==void 0,reqFields:[...m.required_completion_fields||[]],extraParts:L.filter((W,b)=>b!==M).map(W=>({...W})),carry:H}}),this._phaseSeq=[...t.phase_sequence||[]],this._requiredCompletion=[...t.required_completion_fields||[]],this._scheduleTime=t.schedule_time||"",this._scheduleTimeOn=!!t.schedule_time;let o=t.on_complete_action;if(o&&o.service){this._actionService=o.service;let _=o.target?.entity_id;this._actionTargetEntity=Array.isArray(_)?_[0]||"":_||"",this._actionTargetStored=o.target&&typeof o.target=="object"?JSON.parse(JSON.stringify(o.target)):null,this._actionTargetInitial=this._actionTargetEntity,this._actionData=o.data&&typeof o.data=="object"?{...o.data}:{},this._actionDataJsonFallback="",this._actionSkipAuto=o.skip_auto===!0,this._actionPresent=!0}else this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1;let d=t.quick_complete_defaults;this._qcNotes=d?.notes||"",this._qcCost=d?.cost!=null?String(d.cost):"",this._qcDuration=d?.duration!=null?String(d.duration):"",this._qcFeedback=d?.feedback||"";let p=t.adaptive_config||{};if(this._environmentalEntity=p.environmental_entity||"",this._environmentalAttribute=p.environmental_attribute||"",this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute,this._adaptiveEnabled=!!p.enabled,this._adaptiveAlpha=p.ewa_alpha?.toString()??pe.alpha,this._adaptiveMin=p.min_interval_days?.toString()??pe.min,this._adaptiveMax=p.max_interval_days?.toString()??pe.max,this._adaptiveSeasonal=p.seasonal_enabled!==!1,this._adaptivePrediction=p.sensor_prediction_enabled!==!1,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=this._adaptiveEnabled,t.trigger_config){let _=t.trigger_config;this._triggerEntityId=$n(_)||"",this._triggerEntityIds=ui(_),this._triggerEntityLogic=_.entity_logic||"any",this._setTypeFields(In(_)),this._triggerCombinator=_.trigger_combinator==="all"?"all":"any",this._triggerBaselineValue=_.trigger_baseline_value?.toString()||"",this._liveBaselineValue=t.trigger_baseline_value??null,this._autoCompleteOnRecovery=_.auto_complete_on_recovery||!1,this._triggerRuntimeMaxSession=_.trigger_runtime_max_session_seconds?.toString()||"",_.type==="compound"?(this._compoundLogic=_.compound_logic==="OR"?"OR":"AND",this._compoundConditions=(_.conditions||[]).map(Ko)):(this._compoundLogic="AND",this._compoundConditions=[])}else this._resetTriggerFields();this._triggerEntityId&&this._fetchEntityAttributes(this._triggerEntityId),await Promise.all([this._loadUsers(),this._loadTags(),this._loadParts(),this._loadForeignPools()]),this._open=!0}_resetFields(){this._name="",this._type="custom",this._scheduleType="time_based",this._intervalDays="30",this._intervalUnit="days",this._dueDate="",this._warningDays=String(this.defaultWarningDays),this._earliestCompletionDays="",this._intervalAnchor="completion",this._weekdays=[],this._nth="1",this._nthWeekday="5",this._domDay="1",this._domLastDay=!1,this._domBusiness=!1,this._calOffset="0",this._seasonMonths=[],this._endsMode="never",this._endsCount="",this._endsUntil="",this._notes="",this._documentationUrl="",this._customIcon="",this._notifyIcon="",this._priority="normal",this._labels="",this._mirrorTodoEntities=[],this._enabled=!0,this._lastPerformed="",this._nfcTagId="",this._requireTagScan=!1,this._allowSkip=!0,this._readingUnit="",this._readings=[],this._consumesParts={},this._consumesQtyText={},this._responsibleUserId=null,this._assigneePool=[],this._rotationStrategy="",this._checklistText="",this._phaseDefs=[],this._phaseSeq=[],this._requiredCompletion=[],this._scheduleTime="",this._scheduleTimeOn=!1,this._environmentalEntity="",this._environmentalAttribute="",this._environmentalInitial="",this._environmentalAttributeInitial="",this._adaptiveEnabled=!1,this._adaptiveAlpha=pe.alpha,this._adaptiveMin=pe.min,this._adaptiveMax=pe.max,this._adaptiveSeasonal=!0,this._adaptivePrediction=!0,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=!1,this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1,this._actionTesting=!1,this._actionTestResult="",this._qcNotes="",this._qcCost="",this._qcDuration="",this._qcFeedback="",this._resetTriggerFields()}_typeFields(){return{type:this._triggerType,attribute:this._triggerAttribute,above:this._triggerAbove,below:this._triggerBelow,equals:this._triggerEquals,notEquals:this._triggerNotEquals,forMinutes:this._triggerForMinutes,targetValue:this._triggerTargetValue,deltaMode:this._triggerDeltaMode,fromState:this._triggerFromState,toState:this._triggerToState,targetChanges:this._triggerTa
Line truncated
|
||||
`),partId:B?.part_id||"",partQty:B?.quantity!=null?String(B.quantity):"",reqOverride:m.required_completion_fields!==void 0,reqFields:[...m.required_completion_fields||[]],extraParts:L.filter((W,b)=>b!==M).map(W=>({...W})),carry:H}}),this._phaseSeq=[...t.phase_sequence||[]],this._requiredCompletion=[...t.required_completion_fields||[]],this._scheduleTime=t.schedule_time||"",this._scheduleTimeOn=!!t.schedule_time;let o=t.on_complete_action;if(o&&o.service){this._actionService=o.service;let _=o.target?.entity_id;this._actionTargetEntity=Array.isArray(_)?_[0]||"":_||"",this._actionTargetStored=o.target&&typeof o.target=="object"?JSON.parse(JSON.stringify(o.target)):null,this._actionTargetInitial=this._actionTargetEntity,this._actionData=o.data&&typeof o.data=="object"?{...o.data}:{},this._actionDataJsonFallback="",this._actionSkipAuto=o.skip_auto===!0,this._actionPresent=!0}else this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1;let d=t.quick_complete_defaults;this._qcNotes=d?.notes||"",this._qcCost=d?.cost!=null?String(d.cost):"",this._qcDuration=d?.duration!=null?String(d.duration):"",this._qcFeedback=d?.feedback||"";let p=t.adaptive_config||{};if(this._environmentalEntity=p.environmental_entity||"",this._environmentalAttribute=p.environmental_attribute||"",this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute,this._adaptiveEnabled=!!p.enabled,this._adaptiveAlpha=p.ewa_alpha?.toString()??pe.alpha,this._adaptiveMin=p.min_interval_days?.toString()??pe.min,this._adaptiveMax=p.max_interval_days?.toString()??pe.max,this._adaptiveSeasonal=p.seasonal_enabled!==!1,this._adaptivePrediction=p.sensor_prediction_enabled!==!1,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=this._adaptiveEnabled,t.trigger_config){let _=t.trigger_config;this._triggerEntityId=En(_)||"",this._triggerEntityIds=ui(_),this._triggerEntityLogic=_.entity_logic||"any",this._setTypeFields(Rn(_)),this._triggerCombinator=_.trigger_combinator==="all"?"all":"any",this._triggerBaselineValue=_.trigger_baseline_value?.toString()||"",this._liveBaselineValue=t.trigger_baseline_value??null,this._autoCompleteOnRecovery=_.auto_complete_on_recovery||!1,this._triggerRuntimeMaxSession=_.trigger_runtime_max_session_seconds?.toString()||"",_.type==="compound"?(this._compoundLogic=_.compound_logic==="OR"?"OR":"AND",this._compoundConditions=(_.conditions||[]).map(Zo)):(this._compoundLogic="AND",this._compoundConditions=[])}else this._resetTriggerFields();this._triggerEntityId&&this._fetchEntityAttributes(this._triggerEntityId),await Promise.all([this._loadUsers(),this._loadTags(),this._loadParts(),this._loadForeignPools()]),this._open=!0}_resetFields(){this._name="",this._type="custom",this._scheduleType="time_based",this._intervalDays="30",this._intervalUnit="days",this._dueDate="",this._warningDays=String(this.defaultWarningDays),this._earliestCompletionDays="",this._intervalAnchor="completion",this._weekdays=[],this._nth="1",this._nthWeekday="5",this._domDay="1",this._domLastDay=!1,this._domBusiness=!1,this._calOffset="0",this._seasonMonths=[],this._endsMode="never",this._endsCount="",this._endsUntil="",this._notes="",this._documentationUrl="",this._customIcon="",this._notifyIcon="",this._priority="normal",this._labels="",this._mirrorTodoEntities=[],this._enabled=!0,this._lastPerformed="",this._nfcTagId="",this._requireTagScan=!1,this._allowSkip=!0,this._readingUnit="",this._readings=[],this._consumesParts={},this._consumesQtyText={},this._responsibleUserId=null,this._assigneePool=[],this._rotationStrategy="",this._checklistText="",this._phaseDefs=[],this._phaseSeq=[],this._requiredCompletion=[],this._scheduleTime="",this._scheduleTimeOn=!1,this._environmentalEntity="",this._environmentalAttribute="",this._environmentalInitial="",this._environmentalAttributeInitial="",this._adaptiveEnabled=!1,this._adaptiveAlpha=pe.alpha,this._adaptiveMin=pe.min,this._adaptiveMax=pe.max,this._adaptiveSeasonal=!0,this._adaptivePrediction=!0,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=!1,this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1,this._actionTesting=!1,this._actionTestResult="",this._qcNotes="",this._qcCost="",this._qcDuration="",this._qcFeedback="",this._resetTriggerFields()}_typeFields(){return{type:this._triggerType,attribute:this._triggerAttribute,above:this._triggerAbove,below:this._triggerBelow,equals:this._triggerEquals,notEquals:this._triggerNotEquals,forMinutes:this._triggerForMinutes,targetValue:this._triggerTargetValue,deltaMode:this._triggerDeltaMode,fromState:this._triggerFromState,toState:this._triggerToState,targetChanges:this._triggerTa
Line truncated
|
||||
<details class="ca-section">
|
||||
<summary>${a("on_complete_action_title",e)}</summary>
|
||||
<p class="field-help">${a("on_complete_action_desc",e)}</p>
|
||||
@@ -1846,7 +1846,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
@input=${d=>{let p=d.target.value;this._consumesQtyText={...this._consumesQtyText,[i]:p};let _=parseFloat(p.replace(",","."));Number.isFinite(_)&&_>=Fe[0]&&(this._consumesParts={...this._consumesParts,[i]:{...o,quantity:_}})}}
|
||||
/>`:u}
|
||||
</div>
|
||||
`}_applyConsumesQtyText(){let e={...this._consumesParts};for(let t of Object.keys(e)){let i=this._consumesQtyText[t];if(i===void 0)continue;let n=parseFloat(i.replace(",","."));if(!Number.isFinite(n)||n<Fe[0]||n>Fe[1]){let o=d=>C(d,this._lang,{maximumFractionDigits:2});return this._error=a("settings_value_out_of_range",this._lang).replace("{min}",o(Fe[0])).replace("{max}",o(Fe[1])),!1}e[t]={...e[t],quantity:n}}return this._consumesParts=e,!0}_toggleRequired(e,t){let i=new Set(this._requiredCompletion);t?i.add(e):i.delete(e),this._requiredCompletion=[...i]}_patchReading(e,t){this._readings=this._readings.map(i=>i.id===e?{...i,...t}:i)}_renderReadingsEditor(e){let t=Js(this._readings);return l`
|
||||
`}_applyConsumesQtyText(){let e={...this._consumesParts};for(let t of Object.keys(e)){let i=this._consumesQtyText[t];if(i===void 0)continue;let n=parseFloat(i.replace(",","."));if(!Number.isFinite(n)||n<Fe[0]||n>Fe[1]){let o=d=>C(d,this._lang,{maximumFractionDigits:2});return this._error=a("settings_value_out_of_range",this._lang).replace("{min}",o(Fe[0])).replace("{max}",o(Fe[1])),!1}e[t]={...e[t],quantity:n}}return this._consumesParts=e,!0}_toggleRequired(e,t){let i=new Set(this._requiredCompletion);t?i.add(e):i.delete(e),this._requiredCompletion=[...i]}_patchReading(e,t){this._readings=this._readings.map(i=>i.id===e?{...i,...t}:i)}_renderReadingsEditor(e){let t=Xs(this._readings);return l`
|
||||
<div class="readings-editor">
|
||||
<div class="field-label">${a("readings_section",e)}</div>
|
||||
<div class="field-help">${a("readings_hint",e)}</div>
|
||||
@@ -1870,9 +1870,9 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
</ha-icon-button>
|
||||
</div>
|
||||
`)}
|
||||
${this._readings.length<er?l`
|
||||
${this._readings.length<tr?l`
|
||||
<ha-button appearance="plain" class="reading-add"
|
||||
@click=${()=>this._readings=[...this._readings,{id:Gs(),name:"",unit:this._readings.length?this._readings[this._readings.length-1].unit:this._readingUnit}]}>
|
||||
@click=${()=>this._readings=[...this._readings,{id:Ks(),name:"",unit:this._readings.length?this._readings[this._readings.length-1].unit:this._readingUnit}]}>
|
||||
<ha-icon icon="mdi:plus"></ha-icon> ${a("reading_add",e)}
|
||||
</ha-button>`:u}
|
||||
</div>
|
||||
@@ -1927,7 +1927,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
</label>
|
||||
${i.reqOverride?l`
|
||||
<div class="required-completion phase-req-fields">
|
||||
${ar.map(n=>l`
|
||||
${or.map(n=>l`
|
||||
<label class="req-option">
|
||||
<input
|
||||
type="checkbox"
|
||||
@@ -1963,8 +1963,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
</select>
|
||||
</div>
|
||||
`:u}
|
||||
`}async _save(){if(!this._loading&&this._name.trim()){if(this._adaptiveSnapshot()!==this._adaptiveInitial){let e=parseInt(this._adaptiveMin,10),t=parseInt(this._adaptiveMax,10);if(!isNaN(e)&&!isNaN(t)&&e>t){this._error=`${a("adaptive_min_interval",this._lang)} > ${a("adaptive_max_interval",this._lang)}`;return}}if(this._triggerType==="threshold"&&this._thresholdLimitsOverlap()){this._error=a("trigger_hint_overlap",this._lang);return}if(this._scheduleType==="calendar"&&!this._calendarEntity.trim().startsWith("calendar.")){this._error=a("calendar_entity_required",this._lang);return}if(this._applyConsumesQtyText()){this._loading=!0,this._error="";try{let e=await D(this,()=>this.hass.connection.sendMessagePromise(this._savePayload()),{fallbackKey:"save_error",onError:o=>{this._error=o}});if(e===void 0)return;let t=this._taskId||e?.task_id,i=this._environmentalEntity!==this._environmentalInitial||this._environmentalAttribute!==this._environmentalAttributeInitial;this._warning="";let n=o=>{this._warning=a("subsave_warning",this._lang).replace("{detail}",o)};if(t&&this._scheduleType==="sensor_based"&&i&&await D(this,{type:"maintenance_supporter/task/set_environmental_entity",entry_id:this._entryId,task_id:t,environmental_entity:this._environmentalEntity||null,environmental_attribute:this._environmentalAttribute||null},{onError:n})!==void 0&&(this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute),t&&this._adaptiveSnapshot()!==this._adaptiveInitial){let o=parseFloat(this._adaptiveAlpha),d=parseInt(this._adaptiveMin,10),p=parseInt(this._adaptiveMax,10);await D(this,{type:"maintenance_supporter/task/set_adaptive",entry_id:this._entryId,task_id:t,enabled:this._adaptiveEnabled,...o>=Et[0]&&o<=Et[1]?{ewa_alpha:o}:{},...!isNaN(d)&&d>=1?{min_interval_days:d}:{},...!isNaN(p)&&p>=1?{max_interval_days:p}:{},seasonal_enabled:this._adaptiveSeasonal,sensor_prediction_enabled:this._adaptivePrediction},{onError:n})!==void 0&&(this._adaptiveInitial=this._adaptiveSnapshot())}this._warning?t&&(this._taskId=t):this._open=!1,this.dispatchEvent(new CustomEvent("task-saved"))}finally{this._loading=!1}}}}_savePayload(){let e={type:this._taskId?"maintenance_supporter/task/update":"maintenance_supporter/task/create",entry_id:this._entryId,name:this._name,task_type:this._type,schedule_type:this._scheduleType,warning_days:Number.isNaN(parseInt(this._warningDays,10))?this.defaultWarningDays:Math.max(0,parseInt(this._warningDays,10))},t=this._earliestCompletionDays.trim();e.earliest_completion_days=t===""?null:Math.max(0,parseInt(t,10)||0),this._taskId&&(e.task_id=this._taskId),this._scheduleType==="one_time"?(e.due_date=this._dueDate||null,e.interval_days=null):_i.includes(this._scheduleType)?(e.schedule={...this._buildSchedule(),...this._recurrenceExtras()},e.interval_days=null,this._taskId&&(e.due_date=null)):(this._taskId&&(e.due_date=null),this._scheduleType!=="manual"&&this._intervalDays?(e.interval_days=parseInt(this._intervalDays,10),e.interval_unit=this._intervalUnit,e.interval_anchor=this._intervalAnchor,this._scheduleType==="time_based"&&(e.schedule={kind:"interval",...this._recurrenceExtras()})):this._taskId&&(e.interval_days=null,e.interval_anchor="completion")),e.notes=this._notes||null,e.documentation_url=this._documentationUrl||null,e.custom_icon=this._customIcon||null,e.notify_icon=this._notifyIcon.trim()||null,e.priority=this._priority,e.labels=this._labels.split(",").map(i=>i.trim()).filter(Boolean),e.mirror_todo_entities=this._mirrorTodoEntities.filter(Boolean),e.enabled=this._enabled,(!this._taskId||this._lastPerformed!==this._loadedLastPerformed)&&(e.last_performed=this._lastPerformed||null),e.nfc_tag_id=this._nfcTagId||null,e.require_tag_scan=this._requireTagScan,e.allow_skip=this._allowSkip,e.notify_enabled=this._notifyEnabled,e.reading_unit=this._readingUnit.trim()||null,e.readings=Xs(this._readings);{let i={};for(let o of this._phaseDefs){if(!o.name.trim())continue;let d={...o.carry,name:o.name.trim()},p=o.checklistText.split(`
|
||||
`).map(m=>m.trim()).filter(Boolean);p.length&&(d.checklist=p);let _=[];if(o.partId){let m=parseFloat(o.partQty);_.push({part_id:o.partId,quantity:Number.isFinite(m)&&m>0?m:1})}for(let m of o.extraParts)_.push(m.entry_id?{part_id:m.part_id,quantity:m.quantity,entry_id:m.entry_id}:{part_id:m.part_id,quantity:m.quantity});_.length&&(d.consumes_parts=_),o.reqOverride&&(d.required_completion_fields=[...o.reqFields]),i[o.id]=d}let n=this._phaseSeq.filter(o=>o in i);e.phases=Object.keys(i).length&&n.length?i:null,e.phase_sequence=e.phases?n:null}if((this.parts.length||this._foreignOwners.length)&&(e.consumes_parts=Object.values(this._consumesParts).map(i=>i.entry_id?{part_id:i.part_id,quantity:i.quantity,entry_id:i.entry_id}:{part_id:i.part_id,quantity:i.quantity})),(!this._taskId||this._responsibleUserId!==this._loadedResponsibleUserId)&&(e.responsible_user_id=this._responsibleUserId),e.assignee_pool=this._assigneePool,e.required_completion_fields=this._requiredCompletion,e.rotation_strategy=this._assigneePool.length>=2&&this._rotationStrategy?this._rotationStrategy:null,this._scheduleType==="sensor_based"&&this._triggerType==="compound"){let i=this._compoundConditions.map(Yo).filter(n=>n!==null);if(i.length>0){let n={type:"compound",compound_logic:this._compoundLogic,conditions:i};this._autoCompleteOnRecovery&&(n.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(n.trigger_combinator="all"),e.trigger_config=n}else this._taskId&&(e.trigger_config=null)}else if(this._scheduleType==="sensor_based"&&this._triggerEntityId){let i=this._triggerEntityIds.length>0?this._triggerEntityIds:[this._triggerEntityId],n={entity_id:i[0],entity_ids:i,type:this._triggerType};if(Rn(n,this._typeFields()),this._autoCompleteOnRecovery&&(n.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(n.trigger_combinator="all"),i.length>1&&(n.entity_logic=this._triggerEntityLogic),this._triggerType==="counter"&&this._triggerDeltaMode&&this._triggerBaselineValue){let o=parseFloat(this._triggerBaselineValue);!isNaN(o)&&o>=0&&(n.trigger_baseline_value=o)}else if(this._triggerType==="runtime"&&this._triggerRuntimeMaxSession){let o=parseInt(this._triggerRuntimeMaxSession,10);!isNaN(o)&&o>0&&(n.trigger_runtime_max_session_seconds=o)}e.trigger_config=n}else this._taskId&&(e.trigger_config=null);if(this.scheduleTimeEnabled&&Sn.includes(this._scheduleType)){let i=this._scheduleTimeOn?this._scheduleTime.trim():"";e.schedule_time=/^([01]\d|2[0-3]):[0-5]\d$/.test(i)?i:null}if(this.checklistsEnabled){let i=this._checklistText.split(`
|
||||
`}async _save(){if(!this._loading&&this._name.trim()){if(this._adaptiveSnapshot()!==this._adaptiveInitial){let e=parseInt(this._adaptiveMin,10),t=parseInt(this._adaptiveMax,10);if(!isNaN(e)&&!isNaN(t)&&e>t){this._error=`${a("adaptive_min_interval",this._lang)} > ${a("adaptive_max_interval",this._lang)}`;return}}if(this._triggerType==="threshold"&&this._thresholdLimitsOverlap()){this._error=a("trigger_hint_overlap",this._lang);return}if(this._scheduleType==="calendar"&&!this._calendarEntity.trim().startsWith("calendar.")){this._error=a("calendar_entity_required",this._lang);return}if(this._applyConsumesQtyText()){this._loading=!0,this._error="";try{let e=await D(this,()=>this.hass.connection.sendMessagePromise(this._savePayload()),{fallbackKey:"save_error",onError:o=>{this._error=o}});if(e===void 0)return;let t=this._taskId||e?.task_id,i=this._environmentalEntity!==this._environmentalInitial||this._environmentalAttribute!==this._environmentalAttributeInitial;this._warning="";let n=o=>{this._warning=a("subsave_warning",this._lang).replace("{detail}",o)};if(t&&this._scheduleType==="sensor_based"&&i&&await D(this,{type:"maintenance_supporter/task/set_environmental_entity",entry_id:this._entryId,task_id:t,environmental_entity:this._environmentalEntity||null,environmental_attribute:this._environmentalAttribute||null},{onError:n})!==void 0&&(this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute),t&&this._adaptiveSnapshot()!==this._adaptiveInitial){let o=parseFloat(this._adaptiveAlpha),d=parseInt(this._adaptiveMin,10),p=parseInt(this._adaptiveMax,10);await D(this,{type:"maintenance_supporter/task/set_adaptive",entry_id:this._entryId,task_id:t,enabled:this._adaptiveEnabled,...o>=Et[0]&&o<=Et[1]?{ewa_alpha:o}:{},...!isNaN(d)&&d>=1?{min_interval_days:d}:{},...!isNaN(p)&&p>=1?{max_interval_days:p}:{},seasonal_enabled:this._adaptiveSeasonal,sensor_prediction_enabled:this._adaptivePrediction},{onError:n})!==void 0&&(this._adaptiveInitial=this._adaptiveSnapshot())}this._warning?t&&(this._taskId=t):this._open=!1,this.dispatchEvent(new CustomEvent("task-saved"))}finally{this._loading=!1}}}}_savePayload(){let e={type:this._taskId?"maintenance_supporter/task/update":"maintenance_supporter/task/create",entry_id:this._entryId,name:this._name,task_type:this._type,schedule_type:this._scheduleType,warning_days:Number.isNaN(parseInt(this._warningDays,10))?this.defaultWarningDays:Math.max(0,parseInt(this._warningDays,10))},t=this._earliestCompletionDays.trim();e.earliest_completion_days=t===""?null:Math.max(0,parseInt(t,10)||0),this._taskId&&(e.task_id=this._taskId),this._scheduleType==="one_time"?(e.due_date=this._dueDate||null,e.interval_days=null):_i.includes(this._scheduleType)?(e.schedule={...this._buildSchedule(),...this._recurrenceExtras()},e.interval_days=null,this._taskId&&(e.due_date=null)):(this._taskId&&(e.due_date=null),this._scheduleType!=="manual"&&this._intervalDays?(e.interval_days=parseInt(this._intervalDays,10),e.interval_unit=this._intervalUnit,e.interval_anchor=this._intervalAnchor,this._scheduleType==="time_based"&&(e.schedule={kind:"interval",...this._recurrenceExtras()})):this._taskId&&(e.interval_days=null,e.interval_anchor="completion")),e.notes=this._notes||null,e.documentation_url=this._documentationUrl||null,e.custom_icon=this._customIcon||null,e.notify_icon=this._notifyIcon.trim()||null,e.priority=this._priority,e.labels=this._labels.split(",").map(i=>i.trim()).filter(Boolean),e.mirror_todo_entities=this._mirrorTodoEntities.filter(Boolean),e.enabled=this._enabled,(!this._taskId||this._lastPerformed!==this._loadedLastPerformed)&&(e.last_performed=this._lastPerformed||null),e.nfc_tag_id=this._nfcTagId||null,e.require_tag_scan=this._requireTagScan,e.allow_skip=this._allowSkip,e.notify_enabled=this._notifyEnabled,e.reading_unit=this._readingUnit.trim()||null,e.readings=en(this._readings);{let i={};for(let o of this._phaseDefs){if(!o.name.trim())continue;let d={...o.carry,name:o.name.trim()},p=o.checklistText.split(`
|
||||
`).map(m=>m.trim()).filter(Boolean);p.length&&(d.checklist=p);let _=[];if(o.partId){let m=parseFloat(o.partQty);_.push({part_id:o.partId,quantity:Number.isFinite(m)&&m>0?m:1})}for(let m of o.extraParts)_.push(m.entry_id?{part_id:m.part_id,quantity:m.quantity,entry_id:m.entry_id}:{part_id:m.part_id,quantity:m.quantity});_.length&&(d.consumes_parts=_),o.reqOverride&&(d.required_completion_fields=[...o.reqFields]),i[o.id]=d}let n=this._phaseSeq.filter(o=>o in i);e.phases=Object.keys(i).length&&n.length?i:null,e.phase_sequence=e.phases?n:null}if((this.parts.length||this._foreignOwners.length)&&(e.consumes_parts=Object.values(this._consumesParts).map(i=>i.entry_id?{part_id:i.part_id,quantity:i.quantity,entry_id:i.entry_id}:{part_id:i.part_id,quantity:i.quantity})),(!this._taskId||this._responsibleUserId!==this._loadedResponsibleUserId)&&(e.responsible_user_id=this._responsibleUserId),e.assignee_pool=this._assigneePool,e.required_completion_fields=this._requiredCompletion,e.rotation_strategy=this._assigneePool.length>=2&&this._rotationStrategy?this._rotationStrategy:null,this._scheduleType==="sensor_based"&&this._triggerType==="compound"){let i=this._compoundConditions.map(Jo).filter(n=>n!==null);if(i.length>0){let n={type:"compound",compound_logic:this._compoundLogic,conditions:i};this._autoCompleteOnRecovery&&(n.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(n.trigger_combinator="all"),e.trigger_config=n}else this._taskId&&(e.trigger_config=null)}else if(this._scheduleType==="sensor_based"&&this._triggerEntityId){let i=this._triggerEntityIds.length>0?this._triggerEntityIds:[this._triggerEntityId],n={entity_id:i[0],entity_ids:i,type:this._triggerType};if(Pn(n,this._typeFields()),this._autoCompleteOnRecovery&&(n.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(n.trigger_combinator="all"),i.length>1&&(n.entity_logic=this._triggerEntityLogic),this._triggerType==="counter"&&this._triggerDeltaMode&&this._triggerBaselineValue){let o=parseFloat(this._triggerBaselineValue);!isNaN(o)&&o>=0&&(n.trigger_baseline_value=o)}else if(this._triggerType==="runtime"&&this._triggerRuntimeMaxSession){let o=parseInt(this._triggerRuntimeMaxSession,10);!isNaN(o)&&o>0&&(n.trigger_runtime_max_session_seconds=o)}e.trigger_config=n}else this._taskId&&(e.trigger_config=null);if(this.scheduleTimeEnabled&&Tn.includes(this._scheduleType)){let i=this._scheduleTimeOn?this._scheduleTime.trim():"";e.schedule_time=/^([01]\d|2[0-3]):[0-5]\d$/.test(i)?i:null}if(this.checklistsEnabled){let i=this._checklistText.split(`
|
||||
`).map(n=>n.trim()).filter(Boolean).slice(0,100);e.checklist=i.length?i:null}if(this.completionActionsEnabled||this._actionPresent){let i=this._actionService.trim();if(i&&/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(i)){let n={service:i},o=this._actionTargetEntity.trim();this._actionTargetStored&&o===this._actionTargetInitial?n.target=JSON.parse(JSON.stringify(this._actionTargetStored)):o&&(n.target={entity_id:o});let d=this._buildActionData();Object.keys(d).length>0&&(n.data=d),this._actionSkipAuto&&(n.skip_auto=!0),e.on_complete_action=n}else e.on_complete_action=null}if(this.completionActionsEnabled){let i={};this._qcNotes.trim()&&(i.notes=this._qcNotes.trim());let n=parseFloat(this._qcCost);isNaN(n)||(i.cost=n);let o=it(this._qcDuration);o!==null&&(i.duration=o),this._qcFeedback&&(i.feedback=this._qcFeedback),e.quick_complete_defaults=Object.keys(i).length?i:null}return e}_close(){this._open=!1,this._warning="",this._pickerProbeTimer!==void 0&&(clearTimeout(this._pickerProbeTimer),this._pickerProbeTimer=void 0),this._pickerProbeStrikes=0}_renderTriggerFields(){if(this._scheduleType!=="sensor_based")return u;let e=this._lang,t=this._triggerType==="compound";return l`
|
||||
<h3>${a("trigger_configuration",e)}</h3>
|
||||
<div class="select-row">
|
||||
@@ -1973,7 +1973,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._triggerType}
|
||||
@change=${i=>this._triggerType=i.target.value}
|
||||
>
|
||||
${Vo.map(i=>l`<option value=${i} ?selected=${i===this._triggerType}>${Tn(i,e)}</option>`)}
|
||||
${Yo.map(i=>l`<option value=${i} ?selected=${i===this._triggerType}>${An(i,e)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
${t?this._renderCompoundEditor():l`
|
||||
@@ -1987,7 +1987,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ha-form
|
||||
class="entity-picker-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{name:"trigger_entities",selector:{entity:{multiple:!0,domain:nr}}}]}
|
||||
.schema=${[{name:"trigger_entities",selector:{entity:{multiple:!0,domain:ar}}}]}
|
||||
.data=${{trigger_entities:this._triggerEntityIds.length>0?this._triggerEntityIds:this._triggerEntityId?[this._triggerEntityId]:[]}}
|
||||
.computeLabel=${()=>a("entity_id",e)}
|
||||
@value-changed=${i=>{let n=(i.detail.value.trigger_entities||[]).filter(Boolean);this._triggerEntityId=n[0]||"",this._triggerEntityIds=n,n[0]?this._fetchEntityAttributes(n[0]):this._fetchEntityAttributes("")}}
|
||||
@@ -2035,7 +2035,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
</select>
|
||||
</div>
|
||||
`:u}
|
||||
`}_patchCondition(e,t){this._compoundConditions=this._compoundConditions.map((i,n)=>n===e?{...i,...t}:i)}_addCondition(){this._compoundConditions=[...this._compoundConditions,An()]}_removeCondition(e){this._compoundConditions=this._compoundConditions.filter((t,i)=>i!==e)}_renderCompoundEditor(){let e=this._lang;return l`
|
||||
`}_patchCondition(e,t){this._compoundConditions=this._compoundConditions.map((i,n)=>n===e?{...i,...t}:i)}_addCondition(){this._compoundConditions=[...this._compoundConditions,Cn()]}_removeCondition(e){this._compoundConditions=this._compoundConditions.filter((t,i)=>i!==e)}_renderCompoundEditor(){let e=this._lang;return l`
|
||||
<div class="select-row">
|
||||
<label>${a("compound_logic",e)}</label>
|
||||
<select
|
||||
@@ -2072,7 +2072,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ha-form
|
||||
class="entity-picker-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{name:"condition_entities",selector:{entity:{multiple:!0,domain:nr}}}]}
|
||||
.schema=${[{name:"condition_entities",selector:{entity:{multiple:!0,domain:ar}}}]}
|
||||
.data=${{condition_entities:e.entityIds.split(",").map(o=>o.trim()).filter(Boolean)}}
|
||||
.computeLabel=${()=>a("entity_id",i)}
|
||||
@value-changed=${o=>{let d=(o.detail.value.condition_entities||[]).filter(Boolean);this._patchCondition(t,{entityIds:d.join(", ")})}}
|
||||
@@ -2084,7 +2084,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${e.type}
|
||||
@change=${o=>this._patchCondition(t,{type:o.target.value})}
|
||||
>
|
||||
${Cn.map(o=>l`<option value=${o} ?selected=${o===e.type}>${Tn(o,i)}</option>`)}
|
||||
${In.map(o=>l`<option value=${o} ?selected=${o===e.type}>${An(o,i)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
${this._renderConditionTypeFields(e,t)}
|
||||
@@ -2239,7 +2239,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
${a("schedule_preview_title",e)}: ${i}${this._schedulePreviewEnded?l` <span class="field-help">${a("schedule_preview_ends",e)}</span>`:u}
|
||||
${n}
|
||||
</div>
|
||||
`}_buildSchedule(){let e=i=>{let n=parseInt(this._calOffset,10)||0;return n&&(i.offset=Math.max(-$t,Math.min(n,$t))),i};if(this._scheduleType==="weekdays")return e({kind:"weekdays",weekdays:[...this._weekdays].sort((i,n)=>i-n)});if(this._scheduleType==="nth_weekday")return e({kind:"nth_weekday",nth:parseInt(this._nth,10),weekday:parseInt(this._nthWeekday,10)});if(this._scheduleType==="calendar")return e({kind:"calendar",entity_id:this._calendarEntity.trim()});let t={kind:"day_of_month",day:this._domLastDay?-1:parseInt(this._domDay,10)||1};return this._domBusiness&&(t.business=!0),e(t)}_recurrenceExtras(){let e={};if(this._seasonMonths.length&&(e.season_months=[...this._seasonMonths].sort((t,i)=>t-i)),this._endsMode==="count"){let t=parseInt(this._endsCount,10);t>=1&&(e.ends={count:t})}else this._endsMode==="until"&&this._endsUntil&&(e.ends={until:this._endsUntil});return e}_toggleSeasonMonth(e){this._seasonMonths=this._seasonMonths.includes(e)?this._seasonMonths.filter(t=>t!==e):[...this._seasonMonths,e]}_renderRecurrenceExtras(){let e=this._lang;if(!(this._scheduleType==="time_based"||_i.includes(this._scheduleType)))return u;let i=Zo(e);return l`
|
||||
`}_buildSchedule(){let e=i=>{let n=parseInt(this._calOffset,10)||0;return n&&(i.offset=Math.max(-$t,Math.min(n,$t))),i};if(this._scheduleType==="weekdays")return e({kind:"weekdays",weekdays:[...this._weekdays].sort((i,n)=>i-n)});if(this._scheduleType==="nth_weekday")return e({kind:"nth_weekday",nth:parseInt(this._nth,10),weekday:parseInt(this._nthWeekday,10)});if(this._scheduleType==="calendar")return e({kind:"calendar",entity_id:this._calendarEntity.trim()});let t={kind:"day_of_month",day:this._domLastDay?-1:parseInt(this._domDay,10)||1};return this._domBusiness&&(t.business=!0),e(t)}_recurrenceExtras(){let e={};if(this._seasonMonths.length&&(e.season_months=[...this._seasonMonths].sort((t,i)=>t-i)),this._endsMode==="count"){let t=parseInt(this._endsCount,10);t>=1&&(e.ends={count:t})}else this._endsMode==="until"&&this._endsUntil&&(e.ends={until:this._endsUntil});return e}_toggleSeasonMonth(e){this._seasonMonths=this._seasonMonths.includes(e)?this._seasonMonths.filter(t=>t!==e):[...this._seasonMonths,e]}_renderRecurrenceExtras(){let e=this._lang;if(!(this._scheduleType==="time_based"||_i.includes(this._scheduleType)))return u;let i=el(e);return l`
|
||||
<label class="field-label">${a("season_window_label",e)}</label>
|
||||
<div class="field-help">${a("season_window_hint",e)}</div>
|
||||
<div class="weekday-chips season-chips">
|
||||
@@ -2276,7 +2276,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._endsUntil}
|
||||
@value-changed=${n=>this._endsUntil=n.detail.value}
|
||||
></ms-date-field>`:u}
|
||||
`}_renderCalendarFields(){let e=this._lang,t=Qo(e);if(this._scheduleType==="weekdays")return l`
|
||||
`}_renderCalendarFields(){let e=this._lang,t=Xo(e);if(this._scheduleType==="weekdays")return l`
|
||||
<label class="field-label">${a("recurrence_on_days",e)}</label>
|
||||
<div class="weekday-chips">
|
||||
${t.map((i,n)=>l`
|
||||
@@ -2419,7 +2419,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ms-textfield
|
||||
label="${a("target_changes",e)}"
|
||||
type="number"
|
||||
min=${sn[0]}
|
||||
min=${nn[0]}
|
||||
.value=${this._triggerTargetChanges}
|
||||
@input=${t=>this._triggerTargetChanges=t.target.value}
|
||||
></ms-textfield>
|
||||
@@ -2428,7 +2428,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ms-textfield
|
||||
label="${a("for_at_least_minutes",e)}"
|
||||
type="number"
|
||||
min=${rn[0]}
|
||||
min=${sn[0]}
|
||||
.value=${this._triggerForMinutes}
|
||||
@input=${t=>this._triggerForMinutes=t.target.value}
|
||||
></ms-textfield>
|
||||
@@ -2491,7 +2491,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._type}
|
||||
@change=${i=>this._type=i.target.value}
|
||||
>
|
||||
${Uo.map(i=>l`<option value=${i} ?selected=${i===this._type}>${a(i,e)}</option>`)}
|
||||
${Vo.map(i=>l`<option value=${i} ?selected=${i===this._type}>${a(i,e)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
${this._type==="reading"?l`
|
||||
@@ -2526,7 +2526,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._priority}
|
||||
@change=${i=>this._priority=i.target.value}
|
||||
>
|
||||
${Bo.map(i=>l`<option value=${i} ?selected=${i===this._priority}>${a("priority_"+i,e)}</option>`)}
|
||||
${Go.map(i=>l`<option value=${i} ?selected=${i===this._priority}>${a("priority_"+i,e)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
@@ -2564,7 +2564,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._scheduleType}
|
||||
@change=${i=>this._scheduleType=i.target.value}
|
||||
>
|
||||
${Wo.map(i=>l`<option value=${i} ?selected=${i===this._scheduleType}>${a(i,e)}</option>`)}
|
||||
${Ko.map(i=>l`<option value=${i} ?selected=${i===this._scheduleType}>${a(i,e)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
${this._scheduleType==="time_based"?l`
|
||||
@@ -2584,6 +2584,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<option value="completion" ?selected=${this._intervalAnchor==="completion"}>${a("anchor_completion",e)}</option>
|
||||
<option value="planned" ?selected=${this._intervalAnchor==="planned"}>${a("anchor_planned",e)}</option>
|
||||
</select>
|
||||
<div class="field-help anchor-help">${a("interval_anchor_hint",e)}</div>
|
||||
</div>
|
||||
`:u}
|
||||
${this._renderCalendarFields()}
|
||||
@@ -2597,7 +2598,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
@value-changed=${i=>this._dueDate=i.detail.value}
|
||||
></ms-date-field>
|
||||
`:u}
|
||||
${this.scheduleTimeEnabled&&Sn.includes(this._scheduleType)?l`
|
||||
${this.scheduleTimeEnabled&&Tn.includes(this._scheduleType)?l`
|
||||
<label class="checkbox-row schedule-time-toggle">
|
||||
<input type="checkbox" .checked=${this._scheduleTimeOn}
|
||||
@change=${i=>this._scheduleTimeOn=i.target.checked} />
|
||||
@@ -2619,8 +2620,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ms-textfield
|
||||
label="${a("warning_days",e)}"
|
||||
type="number"
|
||||
min=${rr[0]}
|
||||
max=${rr[1]}
|
||||
min=${sr[0]}
|
||||
max=${sr[1]}
|
||||
.value=${this._warningDays}
|
||||
@input=${i=>this._warningDays=i.target.value}
|
||||
></ms-textfield>
|
||||
@@ -2646,7 +2647,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
${this._renderPhasesEditor(e)}
|
||||
<h3>${a("require_on_completion",e)}</h3>
|
||||
<div class="required-completion">
|
||||
${ar.map(i=>l`
|
||||
${or.map(i=>l`
|
||||
<label class="req-option">
|
||||
<input
|
||||
type="checkbox"
|
||||
@@ -2715,7 +2716,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ha-form
|
||||
class="entity-picker-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{name:"environmental_entity",selector:{entity:{domain:bn,device_class:xn}}}]}
|
||||
.schema=${[{name:"environmental_entity",selector:{entity:{domain:xn,device_class:wn}}}]}
|
||||
.data=${{environmental_entity:this._environmentalEntity}}
|
||||
.computeLabel=${()=>a("environmental_entity_optional",e)}
|
||||
.computeHelper=${()=>a("environmental_entity_helper",e)}
|
||||
@@ -2751,8 +2752,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
@value-changed=${i=>this._notifyIcon=i.detail.value||""}
|
||||
></ha-icon-picker>
|
||||
<div class="field-help notify-icon-help">
|
||||
<ha-icon icon=${this._notifyIcon.trim()||lr(this._type)}></ha-icon>
|
||||
${a("notify_icon_hint",e).replace("{default}",lr(this._type))}
|
||||
<ha-icon icon=${this._notifyIcon.trim()||cr(this._type)}></ha-icon>
|
||||
${a("notify_icon_hint",e).replace("{default}",cr(this._type))}
|
||||
</div>
|
||||
${this._availableTags.length>0?l`
|
||||
<div class="select-row">
|
||||
@@ -3230,8 +3231,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
`,c([v({attribute:!1})],g.prototype,"hass",2),c([v({type:Boolean,attribute:"checklists-enabled"})],g.prototype,"checklistsEnabled",2),c([v({type:Boolean,attribute:"schedule-time-enabled"})],g.prototype,"scheduleTimeEnabled",2),c([v({type:Boolean,attribute:"completion-actions-enabled"})],g.prototype,"completionActionsEnabled",2),c([v({type:Boolean,attribute:"adaptive-feature"})],g.prototype,"adaptiveFeature",2),c([v({type:Boolean,attribute:"seasonal-feature"})],g.prototype,"seasonalFeature",2),c([v({type:Boolean,attribute:"environmental-feature"})],g.prototype,"environmentalFeature",2),c([v({type:Number,attribute:"default-warning-days"})],g.prototype,"defaultWarningDays",2),c([h()],g.prototype,"parts",2),c([h()],g.prototype,"_foreignOwners",2),c([h()],g.prototype,"_open",2),c([h()],g.prototype,"_entityPickerFallback",2),c([h()],g.prototype,"_loading",2),c([h()],g.prototype,"_error",2),c([h()],g.prototype,"_warning",2),c([h()],g.prototype,"_entryId",2),c([h()],g.prototype,"_taskId",2),c([h()],g.prototype,"_isFleetTask",2),c([h()],g.prototype,"_objectChoices",2),c([h()],g.prototype,"_name",2),c([h()],g.prototype,"_type",2),c([h()],g.prototype,"_scheduleType",2),c([h()],g.prototype,"_intervalDays",2),c([h()],g.prototype,"_intervalUnit",2),c([h()],g.prototype,"_dueDate",2),c([h()],g.prototype,"_warningDays",2),c([h()],g.prototype,"_earliestCompletionDays",2),c([h()],g.prototype,"_intervalAnchor",2),c([h()],g.prototype,"_weekdays",2),c([h()],g.prototype,"_nth",2),c([h()],g.prototype,"_nthWeekday",2),c([h()],g.prototype,"_domDay",2),c([h()],g.prototype,"_domLastDay",2),c([h()],g.prototype,"_domBusiness",2),c([h()],g.prototype,"_calOffset",2),c([h()],g.prototype,"_calendarEntity",2),c([h()],g.prototype,"_seasonMonths",2),c([h()],g.prototype,"_endsMode",2),c([h()],g.prototype,"_endsCount",2),c([h()],g.prototype,"_endsUntil",2),c([h()],g.prototype,"_schedulePreview",2),c([h()],g.prototype,"_schedulePreviewEnded",2),c([h()],g.prototype,"_notes",2),c([h()],g.prototype,"_documentationUrl",2),c([h()],g.prototype,"_customIcon",2),c([h()],g.prototype,"_notifyIcon",2),c([h()],g.prototype,"_priority",2),c([h()],g.prototype,"_labels",2),c([h()],g.prototype,"_mirrorTodoEntities",2),c([h()],g.prototype,"_enabled",2),c([h()],g.prototype,"_triggerEntityId",2),c([h()],g.prototype,"_triggerEntityIds",2),c([h()],g.prototype,"_triggerEntityLogic",2),c([h()],g.prototype,"_triggerAttribute",2),c([h()],g.prototype,"_triggerType",2),c([h()],g.prototype,"_triggerAbove",2),c([h()],g.prototype,"_triggerBelow",2),c([h()],g.prototype,"_triggerEquals",2),c([h()],g.prototype,"_triggerNotEquals",2),c([h()],g.prototype,"_triggerForMinutes",2),c([h()],g.prototype,"_triggerCombinator",2),c([h()],g.prototype,"_triggerTargetValue",2),c([h()],g.prototype,"_triggerDeltaMode",2),c([h()],g.prototype,"_triggerBaselineValue",2),c([h()],g.prototype,"_liveBaselineValue",2),c([h()],g.prototype,"_autoCompleteOnRecovery",2),c([h()],g.prototype,"_triggerFromState",2),c([h()],g.prototype,"_triggerToState",2),c([h()],g.prototype,"_triggerTargetChanges",2),c([h()],g.prototype,"_triggerRuntimeHours",2),c([h()],g.prototype,"_triggerDaysBefore",2),c([h()],g.prototype,"_triggerRuntimeMaxSession",2),c([h()],g.prototype,"_triggerOnStates",2),c([h()],g.prototype,"_compoundLogic",2),c([h()],g.prototype,"_compoundConditions",2),c([h()],g.prototype,"_suggestedAttributes",2),c([h()],g.prototype,"_availableAttributes",2),c([h()],g.prototype,"_entityDomain",2),c([h()],g.prototype,"_lastPerformed",2),c([h()],g.prototype,"_nfcTagId",2),c([h()],g.prototype,"_requireTagScan",2),c([h()],g.prototype,"_allowSkip",2),c([h()],g.prototype,"_notifyEnabled",2),c([h()],g.prototype,"_readingUnit",2),c([h()],g.prototype,"_readings",2),c([h()],g.prototype,"_consumesParts",2),c([h()],g.prototype,"_consumesQtyText",2),c([h()],g.prototype,"_partsLoadFailed",2),c([h()],g.prototype,"_availableTags",2),c([h()],g.prototype,"_responsibleUserId",2),c([h()],g.prototype,"_assigneePool",2),c([h()],g.prototype,"_rotationStrategy",2),c([h()],g.prototype,"_availableUsers",2),c([h()],g.prototype,"_checklistText",2),c([h()],g.prototype,"_phaseDefs",2),c([h()],g.prototype,"_phaseSeq",2),c([h()],g.prototype,"_requiredCompletion",2),c([h()],g.prototype,"_scheduleTime",2),c([h()],g.prototype,"_scheduleTimeOn",2),c([h()],g.prototype,"_actionService",2),c([h()],g.prototype,"_actionTargetEntity",2),c([h()],g.prototype,"_actionSkipAuto",2),c([h()],g.prototype,"_actionPresent",2),c([h()],g.prototype,"_actionData",2),c([h()],g.prototype,"_actionDataJsonFallback",2),c([h()],g.prototype,"_actionTesting",2),c([h()],g.prototype,"_actionTestResult",2),c([h()],g.prototype,"_actionTestError",2),c([h()],g.prototype,"_qcNotes",2),c([h()],g.prototype,"_qcCost",2),c([h()],g.prototype,"_qcDuration",2),c([h()],g.prototype,"_qcFeedback",2),c([h()],g.prototype,"_environmentalEntity",2),c([h()],g.prototype,"_environmentalAttribute",2),c([h()],g.prototype,"_adaptiveEnabled",2),c([h()],g.prototype,"_adaptiveAlpha",2),c([h()],g.prototy
Line truncated
|
||||
`),t=!1;try{navigator.clipboard?.writeText&&(await navigator.clipboard.writeText(e),t=!0)}catch{}if(!t){let i=this.shadowRoot?.querySelector(".details textarea");if(i){i.focus(),i.select();try{t=document.execCommand("copy")}catch{t=!1}}}this._copied=t}async _shoot(){let e=this._video;if(!(!e||this._busy||this._switching)){this._busy=!0;try{let t=e.videoWidth||640,i=e.videoHeight||480,n=Math.min(1,il/Math.max(t,i)),o=document.createElement("canvas");o.width=Math.round(t*n),o.height=Math.round(i*n);let d=o.getContext("2d");if(!d)throw new Error("no_canvas");d.drawImage(e,0,0,o.width,o.height);let p=await new Promise(f=>o.toBlob(f,"image/jpeg",rl));if(!p)throw new Error("no_blob");let _=new Date().toISOString().replace(/[-:]/g,"").slice(0,15),m=new File([p],`photo-${_}.jpg`,{type:"image/jpeg"});this.close(),this.dispatchEvent(new CustomEvent("photo-captured",{detail:{file:m},bubbles:!0,composed:!0}))}catch(t){this._unavailable(t instanceof Error?t.message:String(t))}finally{this._busy=!1}}}render(){if(!this._open)return u;let e=this.lang,t=this._busy||this._switching;return l`
|
||||
`,c([v({attribute:!1})],g.prototype,"hass",2),c([v({type:Boolean,attribute:"checklists-enabled"})],g.prototype,"checklistsEnabled",2),c([v({type:Boolean,attribute:"schedule-time-enabled"})],g.prototype,"scheduleTimeEnabled",2),c([v({type:Boolean,attribute:"completion-actions-enabled"})],g.prototype,"completionActionsEnabled",2),c([v({type:Boolean,attribute:"adaptive-feature"})],g.prototype,"adaptiveFeature",2),c([v({type:Boolean,attribute:"seasonal-feature"})],g.prototype,"seasonalFeature",2),c([v({type:Boolean,attribute:"environmental-feature"})],g.prototype,"environmentalFeature",2),c([v({type:Number,attribute:"default-warning-days"})],g.prototype,"defaultWarningDays",2),c([h()],g.prototype,"parts",2),c([h()],g.prototype,"_foreignOwners",2),c([h()],g.prototype,"_open",2),c([h()],g.prototype,"_entityPickerFallback",2),c([h()],g.prototype,"_loading",2),c([h()],g.prototype,"_error",2),c([h()],g.prototype,"_warning",2),c([h()],g.prototype,"_entryId",2),c([h()],g.prototype,"_taskId",2),c([h()],g.prototype,"_isFleetTask",2),c([h()],g.prototype,"_objectChoices",2),c([h()],g.prototype,"_name",2),c([h()],g.prototype,"_type",2),c([h()],g.prototype,"_scheduleType",2),c([h()],g.prototype,"_intervalDays",2),c([h()],g.prototype,"_intervalUnit",2),c([h()],g.prototype,"_dueDate",2),c([h()],g.prototype,"_warningDays",2),c([h()],g.prototype,"_earliestCompletionDays",2),c([h()],g.prototype,"_intervalAnchor",2),c([h()],g.prototype,"_weekdays",2),c([h()],g.prototype,"_nth",2),c([h()],g.prototype,"_nthWeekday",2),c([h()],g.prototype,"_domDay",2),c([h()],g.prototype,"_domLastDay",2),c([h()],g.prototype,"_domBusiness",2),c([h()],g.prototype,"_calOffset",2),c([h()],g.prototype,"_calendarEntity",2),c([h()],g.prototype,"_seasonMonths",2),c([h()],g.prototype,"_endsMode",2),c([h()],g.prototype,"_endsCount",2),c([h()],g.prototype,"_endsUntil",2),c([h()],g.prototype,"_schedulePreview",2),c([h()],g.prototype,"_schedulePreviewEnded",2),c([h()],g.prototype,"_notes",2),c([h()],g.prototype,"_documentationUrl",2),c([h()],g.prototype,"_customIcon",2),c([h()],g.prototype,"_notifyIcon",2),c([h()],g.prototype,"_priority",2),c([h()],g.prototype,"_labels",2),c([h()],g.prototype,"_mirrorTodoEntities",2),c([h()],g.prototype,"_enabled",2),c([h()],g.prototype,"_triggerEntityId",2),c([h()],g.prototype,"_triggerEntityIds",2),c([h()],g.prototype,"_triggerEntityLogic",2),c([h()],g.prototype,"_triggerAttribute",2),c([h()],g.prototype,"_triggerType",2),c([h()],g.prototype,"_triggerAbove",2),c([h()],g.prototype,"_triggerBelow",2),c([h()],g.prototype,"_triggerEquals",2),c([h()],g.prototype,"_triggerNotEquals",2),c([h()],g.prototype,"_triggerForMinutes",2),c([h()],g.prototype,"_triggerCombinator",2),c([h()],g.prototype,"_triggerTargetValue",2),c([h()],g.prototype,"_triggerDeltaMode",2),c([h()],g.prototype,"_triggerBaselineValue",2),c([h()],g.prototype,"_liveBaselineValue",2),c([h()],g.prototype,"_autoCompleteOnRecovery",2),c([h()],g.prototype,"_triggerFromState",2),c([h()],g.prototype,"_triggerToState",2),c([h()],g.prototype,"_triggerTargetChanges",2),c([h()],g.prototype,"_triggerRuntimeHours",2),c([h()],g.prototype,"_triggerDaysBefore",2),c([h()],g.prototype,"_triggerRuntimeMaxSession",2),c([h()],g.prototype,"_triggerOnStates",2),c([h()],g.prototype,"_compoundLogic",2),c([h()],g.prototype,"_compoundConditions",2),c([h()],g.prototype,"_suggestedAttributes",2),c([h()],g.prototype,"_availableAttributes",2),c([h()],g.prototype,"_entityDomain",2),c([h()],g.prototype,"_lastPerformed",2),c([h()],g.prototype,"_nfcTagId",2),c([h()],g.prototype,"_requireTagScan",2),c([h()],g.prototype,"_allowSkip",2),c([h()],g.prototype,"_notifyEnabled",2),c([h()],g.prototype,"_readingUnit",2),c([h()],g.prototype,"_readings",2),c([h()],g.prototype,"_consumesParts",2),c([h()],g.prototype,"_consumesQtyText",2),c([h()],g.prototype,"_partsLoadFailed",2),c([h()],g.prototype,"_availableTags",2),c([h()],g.prototype,"_responsibleUserId",2),c([h()],g.prototype,"_assigneePool",2),c([h()],g.prototype,"_rotationStrategy",2),c([h()],g.prototype,"_availableUsers",2),c([h()],g.prototype,"_checklistText",2),c([h()],g.prototype,"_phaseDefs",2),c([h()],g.prototype,"_phaseSeq",2),c([h()],g.prototype,"_requiredCompletion",2),c([h()],g.prototype,"_scheduleTime",2),c([h()],g.prototype,"_scheduleTimeOn",2),c([h()],g.prototype,"_actionService",2),c([h()],g.prototype,"_actionTargetEntity",2),c([h()],g.prototype,"_actionSkipAuto",2),c([h()],g.prototype,"_actionPresent",2),c([h()],g.prototype,"_actionData",2),c([h()],g.prototype,"_actionDataJsonFallback",2),c([h()],g.prototype,"_actionTesting",2),c([h()],g.prototype,"_actionTestResult",2),c([h()],g.prototype,"_actionTestError",2),c([h()],g.prototype,"_qcNotes",2),c([h()],g.prototype,"_qcCost",2),c([h()],g.prototype,"_qcDuration",2),c([h()],g.prototype,"_qcFeedback",2),c([h()],g.prototype,"_environmentalEntity",2),c([h()],g.prototype,"_environmentalAttribute",2),c([h()],g.prototype,"_adaptiveEnabled",2),c([h()],g.prototype,"_adaptiveAlpha",2),c([h()],g.prototy
Line truncated
|
||||
`),t=!1;try{navigator.clipboard?.writeText&&(await navigator.clipboard.writeText(e),t=!0)}catch{}if(!t){let i=this.shadowRoot?.querySelector(".details textarea");if(i){i.focus(),i.select();try{t=document.execCommand("copy")}catch{t=!1}}}this._copied=t}async _shoot(){let e=this._video;if(!(!e||this._busy||this._switching)){this._busy=!0;try{let t=e.videoWidth||640,i=e.videoHeight||480,n=Math.min(1,nl/Math.max(t,i)),o=document.createElement("canvas");o.width=Math.round(t*n),o.height=Math.round(i*n);let d=o.getContext("2d");if(!d)throw new Error("no_canvas");d.drawImage(e,0,0,o.width,o.height);let p=await new Promise(f=>o.toBlob(f,"image/jpeg",al));if(!p)throw new Error("no_blob");let _=new Date().toISOString().replace(/[-:]/g,"").slice(0,15),m=new File([p],`photo-${_}.jpg`,{type:"image/jpeg"});this.close(),this.dispatchEvent(new CustomEvent("photo-captured",{detail:{file:m},bubbles:!0,composed:!0}))}catch(t){this._unavailable(t instanceof Error?t.message:String(t))}finally{this._busy=!1}}}render(){if(!this._open)return u;let e=this.lang,t=this._busy||this._switching;return l`
|
||||
<div class="overlay" role="dialog" aria-modal="true" aria-label=${a("doc_camera",e)}>
|
||||
<video autoplay playsinline muted></video>
|
||||
${this._switching?l`<div class="switching" role="status">${a("camera_switching",e)}</div>`:u}
|
||||
@@ -3296,7 +3297,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.shoot { background: var(--primary-color, #03a9f4); color: #fff; border: none; font-weight: 600; }
|
||||
.shoot[disabled] { opacity: 0.6; cursor: default; }
|
||||
.shoot ha-icon { --mdc-icon-size: 22px; }
|
||||
`,c([v({type:String})],X.prototype,"lang",2),c([h()],X.prototype,"_open",2),c([h()],X.prototype,"_busy",2),c([h()],X.prototype,"_switching",2),c([h()],X.prototype,"_devices",2),c([h()],X.prototype,"_deviceIndex",2),c([h()],X.prototype,"_switchFailed",2),c([h()],X.prototype,"_copied",2);customElements.get("ms-camera-capture")||customElements.define("ms-camera-capture",X)});var gi,ee,Ct=y(()=>{"use strict";I();F();T();ur();_r();_r();gi=E`
|
||||
`,c([v({type:String})],X.prototype,"lang",2),c([h()],X.prototype,"_open",2),c([h()],X.prototype,"_busy",2),c([h()],X.prototype,"_switching",2),c([h()],X.prototype,"_devices",2),c([h()],X.prototype,"_deviceIndex",2),c([h()],X.prototype,"_switchFailed",2),c([h()],X.prototype,"_copied",2);customElements.get("ms-camera-capture")||customElements.define("ms-camera-capture",X)});var gi,ee,Ct=y(()=>{"use strict";I();F();T();hr();mr();mr();gi=E`
|
||||
ms-photo-picker { display: contents; }
|
||||
.photo-pickers {
|
||||
display: flex;
|
||||
@@ -3325,7 +3326,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
color: var(--secondary-text-color);
|
||||
margin-top: 4px;
|
||||
}
|
||||
`,ee=class extends S{constructor(){super(...arguments);this.lang="en";this.disabled=!1;this.busy=!1;this.accept="image/*";this.showCamera=!0;this.showGallery=!0;this.compact=!1;this.remaining=1/0;this._singlePick=mi();this._inAppCamera=Bn()}createRenderRoot(){return this}get _locked(){return this.disabled||this.busy}_emit(e){e.length!==0&&this.dispatchEvent(new CustomEvent("files-picked",{detail:{files:e},bubbles:!0,composed:!0}))}_onInput(e){let t=e.target,i=Array.from(t.files??[]);t.value="",this._emit(i)}_onCameraClick(e){!this._inAppCamera||this._locked||(e.preventDefault(),this.querySelector("ms-camera-capture")?.open())}_onCameraUnavailable(){this._inAppCamera=!1,this.querySelector(".photo-pick-camera input")?.click()}_onKeydown(e){e.key!=="Enter"&&e.key!==" "||(e.preventDefault(),!this._locked&&e.currentTarget.click())}render(){if(this.remaining<=0||!this.showCamera&&!this.showGallery)return u;let e=this.lang,t=this._locked?"disabled":"",i=this.busy?a("uploading",e):a("doc_camera",e),n=a(this._singlePick?"choose_photo":"choose_photos",e);return l`
|
||||
`,ee=class extends S{constructor(){super(...arguments);this.lang="en";this.disabled=!1;this.busy=!1;this.accept="image/*";this.showCamera=!0;this.showGallery=!0;this.compact=!1;this.remaining=1/0;this._singlePick=mi();this._inAppCamera=Wn()}createRenderRoot(){return this}get _locked(){return this.disabled||this.busy}_emit(e){e.length!==0&&this.dispatchEvent(new CustomEvent("files-picked",{detail:{files:e},bubbles:!0,composed:!0}))}_onInput(e){let t=e.target,i=Array.from(t.files??[]);t.value="",this._emit(i)}_onCameraClick(e){!this._inAppCamera||this._locked||(e.preventDefault(),this.querySelector("ms-camera-capture")?.open())}_onCameraUnavailable(){this._inAppCamera=!1,this.querySelector(".photo-pick-camera input")?.click()}_onKeydown(e){e.key!=="Enter"&&e.key!==" "||(e.preventDefault(),!this._locked&&e.currentTarget.click())}render(){if(this.remaining<=0||!this.showCamera&&!this.showGallery)return u;let e=this.lang,t=this._locked?"disabled":"",i=this.busy?a("uploading",e):a("doc_camera",e),n=a(this._singlePick?"choose_photo":"choose_photos",e);return l`
|
||||
<div class="photo-pickers">
|
||||
${this.showCamera?l`<label class="photo-pick photo-pick-camera ${t}" role="button" tabindex="0"
|
||||
aria-label=${i} title=${this.compact?i:u}
|
||||
@@ -3348,7 +3349,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
${this.showCamera&&this._inAppCamera?l`<ms-camera-capture .lang=${e}
|
||||
@photo-captured=${o=>this._emit([o.detail.file])}
|
||||
@capture-unavailable=${this._onCameraUnavailable}></ms-camera-capture>`:u}
|
||||
`}};c([v({type:String})],ee.prototype,"lang",2),c([v({type:Boolean})],ee.prototype,"disabled",2),c([v({type:Boolean})],ee.prototype,"busy",2),c([v({type:String})],ee.prototype,"accept",2),c([v({type:Boolean})],ee.prototype,"showCamera",2),c([v({type:Boolean})],ee.prototype,"showGallery",2),c([v({type:Boolean})],ee.prototype,"compact",2),c([v({type:Number})],ee.prototype,"remaining",2),c([h()],ee.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",ee)});var st,$,Vn=y(()=>{"use strict";I();F();je();T();ze();Z();St();di();Gt();or();pr();pi();tt();hi();Ct();Ct();st=ke,$=class extends S{constructor(){super(...arguments);this.entryId="";this.taskId="";this.taskName="";this.lang="en";this.checklist=[];this.adaptiveEnabled=!1;this.taskType="";this.readingUnit="";this.readings=[];this.readingHistory=[];this.restockDefault=null;this.restockUnitCost=null;this.restockPackage="";this.currencySymbol="";this.partsCostMode="purchase";this.parts=[];this.consumesParts=[];this.consumesInfo=[];this.requiredFields=[];this.phaseLabel="";this.requireTagScan=!1;this.viaTagScan=!1;this._open=!1;this._notes="";this._cost="";this._duration="";this._loading=!1;this._error="";this._checklistState={};this._feedback="needed";this._photos=new rt(this,{entryId:()=>this.entryId,hass:()=>this.hass});this._readingValue="";this._readingValues={};this._restockQty="";this._completedAt="";this._usedParts={};this._usedQtyText={};this.checklistPrefill={}}open(e={}){this._open||(this._open=!0,this.viaTagScan=!!e.viaTagScan,this._notes="",this._cost="",this._duration="",this._error="",this._checklistState=Object.fromEntries(this.checklist.map((t,i)=>[String(i),!!this.checklistPrefill[t]]).filter(([,t])=>t)),this._feedback="needed",this._photos.reset(),this._readingValue="",this._readingValues={},this._restockQty=this.restockDefault!==null?String(this.restockDefault):"",this._completedAt="",this._usedParts=Object.fromEntries(this.consumesParts.map(t=>[ae(t),{...t}])),this._usedQtyText={})}_rangeError(e,t){let i=this.lang;return a("settings_value_out_of_range",i).replace("{min}",C(e,i,{maximumFractionDigits:2})).replace("{max}",C(t,i,{maximumFractionDigits:2}))}_toggleCheck(e){let t=String(e);this._checklistState={...this._checklistState,[t]:!this._checklistState[t]}}_setFeedback(e){this._feedback=e}async _complete(){if(this._loading||this._photos.uploading)return;this._error="",this._photos.clearError();let e={type:"maintenance_supporter/task/complete",entry_id:this.entryId,task_id:this.taskId},t=this._notes.trim();if(t&&(e.notes=t),this._cost){let d=parseFloat(this._cost);isNaN(d)||(e.cost=d)}let i=it(this._duration);if(i!==null&&(e.duration=i),this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photos.photos.length>0&&(e.photo_doc_ids=this._photos.ids),this.viaTagScan&&(e.via_tag_scan=!0),this._completedAt){if(Q(this._completedAt)>Date.now()){this._error=a("completed_at_future_error",this.lang);return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let d={};for(let p of this.readings){let _=(this._readingValues[p.id]??"").trim();if(_==="")continue;let m=parseFloat(_.replace(",","."));isNaN(m)||(d[p.id]=m)}Object.keys(d).length>0&&(e.reading_values=d)}else if(this._readingValue!==""){let d=parseFloat(this._readingValue);isNaN(d)||(e.reading_value=d)}if(this.restockDefault!==null&&this._restockQty.trim()!==""){let d=parseFloat(this._restockQty.replace(",","."));if(!Number.isFinite(d)||d<Xe[0]||d>Xe[1]){this._error=this._rangeError(...Xe);return}e.restock_quantity=d}if(this.parts.length>0){let d=[];for(let[p,_]of Object.entries(this._usedParts)){let m=this._usedQtyText[p],f=m===void 0?_.quantity:parseFloat(m.replace(",","."));if(!Number.isFinite(f)||f<st[0]||f>st[1]){this._error=this._rangeError(...st);return}d.push({..._,quantity:f})}e.used_parts=d.map(p=>p.entry_id?{part_id:p.part_id,quantity:p.quantity,entry_id:p.entry_id}:{part_id:p.part_id,quantity:p.quantity})}let n=await D(this,e,{busy:d=>{this._loading=d},lang:this.lang,fallbackKey:"save_error",onError:d=>{this._error=d}});if(n===void 0)return;this._photos.markAttached(),this._open=!1;let o={entryId:this.entryId,taskId:this.taskId,taskName:this.taskName,undo:n?.undo===!0};this.dispatchEvent(new CustomEvent("task-completed",{detail:o}))}_renderReadingField(e,t){let i=this._completedAt?Q(this._completedAt):NaN,n=Qs(this.readingHistory,e.id,isNaN(i)?void 0:i),o=e.unit||this.readingUnit,d=(this._readingValues[e.id]??"").trim(),p=d===""?NaN:parseFloat(d.replace(",",".")),_=n!==void 0&&!isNaN(p)&&p<n.value,m=n!==void 0?C(n.value,t,{maximumFractionDigits:3}):"";return l`
|
||||
`}};c([v({type:String})],ee.prototype,"lang",2),c([v({type:Boolean})],ee.prototype,"disabled",2),c([v({type:Boolean})],ee.prototype,"busy",2),c([v({type:String})],ee.prototype,"accept",2),c([v({type:Boolean})],ee.prototype,"showCamera",2),c([v({type:Boolean})],ee.prototype,"showGallery",2),c([v({type:Boolean})],ee.prototype,"compact",2),c([v({type:Number})],ee.prototype,"remaining",2),c([h()],ee.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",ee)});var st,$,Gn=y(()=>{"use strict";I();F();je();T();ze();Z();St();di();Gt();lr();ur();pi();tt();hi();Ct();Ct();st=ke,$=class extends S{constructor(){super(...arguments);this.entryId="";this.taskId="";this.taskName="";this.lang="en";this.checklist=[];this.adaptiveEnabled=!1;this.taskType="";this.readingUnit="";this.readings=[];this.readingHistory=[];this.restockDefault=null;this.restockUnitCost=null;this.restockPackage="";this.currencySymbol="";this.partsCostMode="purchase";this.parts=[];this.consumesParts=[];this.consumesInfo=[];this.requiredFields=[];this.phaseLabel="";this.requireTagScan=!1;this.viaTagScan=!1;this._open=!1;this._notes="";this._cost="";this._duration="";this._loading=!1;this._error="";this._checklistState={};this._feedback="needed";this._photos=new rt(this,{entryId:()=>this.entryId,hass:()=>this.hass});this._readingValue="";this._readingValues={};this._restockQty="";this._completedAt="";this._usedParts={};this._usedQtyText={};this.checklistPrefill={}}open(e={}){this._open||(this._open=!0,this.viaTagScan=!!e.viaTagScan,this._notes="",this._cost="",this._duration="",this._error="",this._checklistState=Object.fromEntries(this.checklist.map((t,i)=>[String(i),!!this.checklistPrefill[t]]).filter(([,t])=>t)),this._feedback="needed",this._photos.reset(),this._readingValue="",this._readingValues={},this._restockQty=this.restockDefault!==null?String(this.restockDefault):"",this._completedAt="",this._usedParts=Object.fromEntries(this.consumesParts.map(t=>[ae(t),{...t}])),this._usedQtyText={})}_rangeError(e,t){let i=this.lang;return a("settings_value_out_of_range",i).replace("{min}",C(e,i,{maximumFractionDigits:2})).replace("{max}",C(t,i,{maximumFractionDigits:2}))}_toggleCheck(e){let t=String(e);this._checklistState={...this._checklistState,[t]:!this._checklistState[t]}}_setFeedback(e){this._feedback=e}async _complete(){if(this._loading||this._photos.uploading)return;this._error="",this._photos.clearError();let e={type:"maintenance_supporter/task/complete",entry_id:this.entryId,task_id:this.taskId},t=this._notes.trim();if(t&&(e.notes=t),this._cost){let d=parseFloat(this._cost);isNaN(d)||(e.cost=d)}let i=it(this._duration);if(i!==null&&(e.duration=i),this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photos.photos.length>0&&(e.photo_doc_ids=this._photos.ids),this.viaTagScan&&(e.via_tag_scan=!0),this._completedAt){if(Q(this._completedAt)>Date.now()){this._error=a("completed_at_future_error",this.lang);return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let d={};for(let p of this.readings){let _=(this._readingValues[p.id]??"").trim();if(_==="")continue;let m=parseFloat(_.replace(",","."));isNaN(m)||(d[p.id]=m)}Object.keys(d).length>0&&(e.reading_values=d)}else if(this._readingValue!==""){let d=parseFloat(this._readingValue);isNaN(d)||(e.reading_value=d)}if(this.restockDefault!==null&&this._restockQty.trim()!==""){let d=parseFloat(this._restockQty.replace(",","."));if(!Number.isFinite(d)||d<Xe[0]||d>Xe[1]){this._error=this._rangeError(...Xe);return}e.restock_quantity=d}if(this.parts.length>0){let d=[];for(let[p,_]of Object.entries(this._usedParts)){let m=this._usedQtyText[p],f=m===void 0?_.quantity:parseFloat(m.replace(",","."));if(!Number.isFinite(f)||f<st[0]||f>st[1]){this._error=this._rangeError(...st);return}d.push({..._,quantity:f})}e.used_parts=d.map(p=>p.entry_id?{part_id:p.part_id,quantity:p.quantity,entry_id:p.entry_id}:{part_id:p.part_id,quantity:p.quantity})}let n=await D(this,e,{busy:d=>{this._loading=d},lang:this.lang,fallbackKey:"save_error",onError:d=>{this._error=d}});if(n===void 0)return;this._photos.markAttached(),this._open=!1;let o={entryId:this.entryId,taskId:this.taskId,taskName:this.taskName,undo:n?.undo===!0};this.dispatchEvent(new CustomEvent("task-completed",{detail:o}))}_renderReadingField(e,t){let i=this._completedAt?Q(this._completedAt):NaN,n=Zs(this.readingHistory,e.id,isNaN(i)?void 0:i),o=e.unit||this.readingUnit,d=(this._readingValues[e.id]??"").trim(),p=d===""?NaN:parseFloat(d.replace(",",".")),_=n!==void 0&&!isNaN(p)&&p<n.value,m=n!==void 0?C(n.value,t,{maximumFractionDigits:3}):"";return l`
|
||||
<label class="field reading-field">
|
||||
<span class="field-label">${e.name}${o?` (${o})`:""}</span>
|
||||
<input type="text" inputmode="decimal" class="field-input"
|
||||
@@ -3356,11 +3357,11 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._readingValues[e.id]??""}
|
||||
@input=${f=>{this._readingValues={...this._readingValues,[e.id]:f.target.value}}} />
|
||||
${_?l`<span class="reading-warn">${a("reading_below_last",t).replace("{value}",m)}</span>`:u}
|
||||
</label>`}get _missingRequired(){let e={notes:this._notes.trim()!=="",cost:this._cost.trim()!=="",duration:this._duration.trim()!=="",photo:this._photos.photos.length>0,user:!!this.hass?.user};return this.requiredFields.filter(t=>!e[t])}_demands(e){return this.requiredFields.includes(e)}_req(e){return this._demands(e)?l`<span class="req-mark" aria-hidden="true">*</span>`:u}_purchaseSuggestion(){if(this.restockDefault===null)return null;let e=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(e)||e<=0?null:Math.round(this.restockUnitCost*e*100)/100}_partsValue(){if(this.restockDefault!==null||!this.parts.length)return null;let e=0,t=!1;for(let i of Object.values(this._usedParts)){let n=this.parts.find(d=>ae({part_id:d.id,entry_id:d.entry_id})===ae(i)),o=ps(n);o!==null&&(e+=o*(i.quantity||1),t=!0)}return t?Math.round(e*100)/100:null}_renderCostSuggestion(e){let t=this._purchaseSuggestion();if(this.restockDefault!==null){let d=this.partsCostMode==="use"?l`<div class="cost-note">${a("cost_purchase_use_hint",e)}</div>`:u;if(this._cost.trim()!==""||t==null||t<=0)return d;let p=J(t,this.currencySymbol,e);return l`<button
|
||||
</label>`}get _missingRequired(){let e={notes:this._notes.trim()!=="",cost:this._cost.trim()!=="",duration:this._duration.trim()!=="",photo:this._photos.photos.length>0,user:!!this.hass?.user};return this.requiredFields.filter(t=>!e[t])}_demands(e){return this.requiredFields.includes(e)}_req(e){return this._demands(e)?l`<span class="req-mark" aria-hidden="true">*</span>`:u}_purchaseSuggestion(){if(this.restockDefault===null)return null;let e=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(e)||e<=0?null:Math.round(this.restockUnitCost*e*100)/100}_partsValue(){if(this.restockDefault!==null||!this.parts.length)return null;let e=0,t=!1;for(let i of Object.values(this._usedParts)){let n=this.parts.find(d=>ae({part_id:d.id,entry_id:d.entry_id})===ae(i)),o=us(n);o!==null&&(e+=o*(i.quantity||1),t=!0)}return t?Math.round(e*100)/100:null}_renderCostSuggestion(e){let t=this._purchaseSuggestion();if(this.restockDefault!==null){let d=this.partsCostMode==="use"?l`<div class="cost-note">${a("cost_purchase_use_hint",e)}</div>`:u;if(this._cost.trim()!==""||t==null||t<=0)return d;let p=J(t,this.currencySymbol,e);return l`<button
|
||||
type="button"
|
||||
class="cost-suggestion"
|
||||
@click=${()=>this._cost=String(Math.round(t*100)/100)}
|
||||
>${a("cost_from_parts",e).replace("{amount}",p)}</button>${d}`}let i=this._partsValue();if(i==null||i<=0)return u;let n=J(i,this.currencySymbol,e),o=this.partsCostMode==="use"?"cost_parts_booked":"cost_parts_info";return l`<div class="cost-note">${a(o,e).replace("{amount}",n)}</div>`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=`${ys()}:00`}render(){if(!this._open)return l``;let e=this.lang||this.hass?.language||"en",t=this._error||this._photos.errorText(e);return l`
|
||||
>${a("cost_from_parts",e).replace("{amount}",p)}</button>${d}`}let i=this._partsValue();if(i==null||i<=0)return u;let n=J(i,this.currencySymbol,e),o=this.partsCostMode==="use"?"cost_parts_booked":"cost_parts_info";return l`<div class="cost-note">${a(o,e).replace("{amount}",n)}</div>`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=`${bs()}:00`}render(){if(!this._open)return l``;let e=this.lang||this.hass?.language||"en",t=this._error||this._photos.errorText(e);return l`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${a("complete_title",e)}${this.taskName}</div>
|
||||
${this.phaseLabel?l`<div class="phase-line">${a("phase_current",e)}: ${this.phaseLabel}</div>`:u}
|
||||
@@ -3716,13 +3717,13 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
color: var(--text-primary-color, #fff);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
`],c([v({attribute:!1})],$.prototype,"hass",2),c([v()],$.prototype,"entryId",2),c([v()],$.prototype,"taskId",2),c([v()],$.prototype,"taskName",2),c([v()],$.prototype,"lang",2),c([v({type:Array})],$.prototype,"checklist",2),c([v({type:Boolean})],$.prototype,"adaptiveEnabled",2),c([v()],$.prototype,"taskType",2),c([v()],$.prototype,"readingUnit",2),c([v({attribute:!1})],$.prototype,"readings",2),c([v({attribute:!1})],$.prototype,"readingHistory",2),c([v({attribute:!1})],$.prototype,"restockDefault",2),c([v({attribute:!1})],$.prototype,"restockUnitCost",2),c([v({attribute:!1})],$.prototype,"restockPackage",2),c([v()],$.prototype,"currencySymbol",2),c([v({attribute:!1})],$.prototype,"partsCostMode",2),c([v({attribute:!1})],$.prototype,"parts",2),c([v({attribute:!1})],$.prototype,"consumesParts",2),c([v({type:Array})],$.prototype,"consumesInfo",2),c([v({type:Array})],$.prototype,"requiredFields",2),c([v()],$.prototype,"phaseLabel",2),c([v({type:Boolean})],$.prototype,"requireTagScan",2),c([v({type:Boolean})],$.prototype,"viaTagScan",2),c([h()],$.prototype,"_open",2),c([h()],$.prototype,"_notes",2),c([h()],$.prototype,"_cost",2),c([h()],$.prototype,"_duration",2),c([h()],$.prototype,"_loading",2),c([h()],$.prototype,"_error",2),c([h()],$.prototype,"_checklistState",2),c([h()],$.prototype,"_feedback",2),c([h()],$.prototype,"_readingValue",2),c([h()],$.prototype,"_readingValues",2),c([h()],$.prototype,"_restockQty",2),c([h()],$.prototype,"_completedAt",2),c([h()],$.prototype,"_usedParts",2),c([h()],$.prototype,"_usedQtyText",2),c([v({attribute:!1})],$.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",$)});function ol(s,r){s.key!=="Escape"||s.defaultPrevented||s.composedPath().some(e=>e instanceof Element&&e.localName==="ms-camera-capture")||(s.preventDefault(),s.stopPropagation(),r())}function at(s,r){return l`
|
||||
`],c([v({attribute:!1})],$.prototype,"hass",2),c([v()],$.prototype,"entryId",2),c([v()],$.prototype,"taskId",2),c([v()],$.prototype,"taskName",2),c([v()],$.prototype,"lang",2),c([v({type:Array})],$.prototype,"checklist",2),c([v({type:Boolean})],$.prototype,"adaptiveEnabled",2),c([v()],$.prototype,"taskType",2),c([v()],$.prototype,"readingUnit",2),c([v({attribute:!1})],$.prototype,"readings",2),c([v({attribute:!1})],$.prototype,"readingHistory",2),c([v({attribute:!1})],$.prototype,"restockDefault",2),c([v({attribute:!1})],$.prototype,"restockUnitCost",2),c([v({attribute:!1})],$.prototype,"restockPackage",2),c([v()],$.prototype,"currencySymbol",2),c([v({attribute:!1})],$.prototype,"partsCostMode",2),c([v({attribute:!1})],$.prototype,"parts",2),c([v({attribute:!1})],$.prototype,"consumesParts",2),c([v({type:Array})],$.prototype,"consumesInfo",2),c([v({type:Array})],$.prototype,"requiredFields",2),c([v()],$.prototype,"phaseLabel",2),c([v({type:Boolean})],$.prototype,"requireTagScan",2),c([v({type:Boolean})],$.prototype,"viaTagScan",2),c([h()],$.prototype,"_open",2),c([h()],$.prototype,"_notes",2),c([h()],$.prototype,"_cost",2),c([h()],$.prototype,"_duration",2),c([h()],$.prototype,"_loading",2),c([h()],$.prototype,"_error",2),c([h()],$.prototype,"_checklistState",2),c([h()],$.prototype,"_feedback",2),c([h()],$.prototype,"_readingValue",2),c([h()],$.prototype,"_readingValues",2),c([h()],$.prototype,"_restockQty",2),c([h()],$.prototype,"_completedAt",2),c([h()],$.prototype,"_usedParts",2),c([h()],$.prototype,"_usedQtyText",2),c([v({attribute:!1})],$.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",$)});function dl(s,r){s.key!=="Escape"||s.defaultPrevented||s.composedPath().some(e=>e instanceof Element&&e.localName==="ms-camera-capture")||(s.preventDefault(),s.stopPropagation(),r())}function at(s,r){return l`
|
||||
<div class="backdrop" @click=${s}></div>
|
||||
<div class="dialog" role="dialog" aria-modal="true" tabindex="-1"
|
||||
@keydown=${e=>ol(e,s)}>${r}</div>
|
||||
@keydown=${e=>dl(e,s)}>${r}</div>
|
||||
`}function ot(s){s?.querySelector(".dialog")?.focus({preventScroll:!0})}var nt,fi=y(()=>{"use strict";I();nt=E`
|
||||
.backdrop {
|
||||
position: fixed; inset: 0; z-index: 100;
|
||||
position: fixed; inset: 0; z-index: var(--ms-modal-z, 100);
|
||||
background: rgba(0,0,0,0.5);
|
||||
}
|
||||
.dialog {
|
||||
@@ -3736,11 +3737,18 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
|
||||
padding: 20px;
|
||||
display: flex; flex-direction: column; gap: var(--ms-modal-gap, 14px);
|
||||
z-index: 101;
|
||||
z-index: calc(var(--ms-modal-z, 100) + 1);
|
||||
}
|
||||
/* Focused programmatically on open (so Escape works at once) — no ring. */
|
||||
.dialog:focus { outline: none; }
|
||||
`});var V,Gn=y(()=>{"use strict";I();F();T();V=class extends S{constructor(){super(...arguments);this._open=!1;this._title="";this._message="";this._confirmText="";this._danger=!1;this._inputLabel="";this._inputType="";this._options=null;this._inputValue="";this._resolve=null;this._promptResolve=null}confirm(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel="",this._inputType="",this._options=null,this._inputValue="",this._open=!0,new Promise(t=>{this._resolve=t,this._promptResolve=null})}prompt(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel=e.inputLabel||"",this._inputType=e.inputType||"text",this._options=e.options&&e.options.length?e.options:null,this._inputValue=e.inputValue||"",this._open=!0,new Promise(t=>{this._promptResolve=t,this._resolve=null})}_cancel(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!1,value:""}),this._promptResolve=null),this._resolve?.(!1),this._resolve=null}_confirmAction(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!0,value:this._inputValue}),this._promptResolve=null),this._resolve?.(!0),this._resolve=null}render(){if(!this._open)return u;let e=N(this.hass);return l`
|
||||
/* The one part that shrinks and scrolls (min-height: 0); the header and the
|
||||
buttons around it keep their content's height. */
|
||||
.dialog-scroll {
|
||||
flex: 1 1 auto; min-height: 0;
|
||||
overflow-y: auto; overscroll-behavior: contain;
|
||||
display: flex; flex-direction: column; gap: var(--ms-modal-gap, 14px);
|
||||
}
|
||||
`});var V,Kn=y(()=>{"use strict";I();F();T();V=class extends S{constructor(){super(...arguments);this._open=!1;this._title="";this._message="";this._confirmText="";this._danger=!1;this._inputLabel="";this._inputType="";this._options=null;this._inputValue="";this._resolve=null;this._promptResolve=null}confirm(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel="",this._inputType="",this._options=null,this._inputValue="",this._open=!0,new Promise(t=>{this._resolve=t,this._promptResolve=null})}prompt(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel=e.inputLabel||"",this._inputType=e.inputType||"text",this._options=e.options&&e.options.length?e.options:null,this._inputValue=e.inputValue||"",this._open=!0,new Promise(t=>{this._promptResolve=t,this._resolve=null})}_cancel(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!1,value:""}),this._promptResolve=null),this._resolve?.(!1),this._resolve=null}_confirmAction(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!0,value:this._inputValue}),this._promptResolve=null),this._resolve?.(!0),this._resolve=null}render(){if(!this._open)return u;let e=N(this.hass);return l`
|
||||
<ha-dialog open @closed=${this._cancel}>
|
||||
<div class="dialog-title">${this._title}</div>
|
||||
<div class="content">
|
||||
@@ -3804,7 +3812,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
ha-button.danger {
|
||||
--mdc-theme-primary: var(--error-color, #f44336);
|
||||
}
|
||||
`],c([v({attribute:!1})],V.prototype,"hass",2),c([h()],V.prototype,"_open",2),c([h()],V.prototype,"_title",2),c([h()],V.prototype,"_message",2),c([h()],V.prototype,"_confirmText",2),c([h()],V.prototype,"_danger",2),c([h()],V.prototype,"_inputLabel",2),c([h()],V.prototype,"_inputType",2),c([h()],V.prototype,"_options",2),c([h()],V.prototype,"_inputValue",2);customElements.get("maintenance-confirm-dialog")||customElements.define("maintenance-confirm-dialog",V)});function ll(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function Ue(s,r){let e=ll(),t=e.querySelector(`${Kn}[${Yn}]`);return t||(t=document.createElement(Kn),t.setAttribute(Yn,""),e.appendChild(t)),t.hass=s,t.confirm(r)}var Kn,Yn,vi=y(()=>{"use strict";Gn();Kn="maintenance-confirm-dialog",Yn="data-ms-lovelace-confirm"});function Qn(s,r,e){let t=new Blob([s],{type:e}),i=URL.createObjectURL(t),n=document.createElement("a");n.href=i,n.download=r,n.target="_blank",n.rel="noopener",n.style.display="none",document.body.appendChild(n),n.dispatchEvent(new MouseEvent("click")),document.body.removeChild(n),setTimeout(()=>URL.revokeObjectURL(i),6e4)}var mr=y(()=>{"use strict"});async function cl(s,r,e=300){return(await s.connection.sendMessagePromise({type:"auth/sign_path",path:r,expires:e})).path}async function Zn(s,r,e=300){return cl(s,`/api/maintenance_supporter/document/${r}`,e)}var Jn=y(()=>{"use strict";mr()});var Ee,gr=y(()=>{"use strict";I();F();Jn();Ee=class extends S{constructor(){super(...arguments);this.docId="";this._url="";this._failed=!1;this._signedFor=""}updated(){this.hass&&this.docId&&this._signedFor!==this.docId&&(this._signedFor=this.docId,this._url="",this._failed=!1,this._sign())}async _sign(){try{this._url=await Zn(this.hass,this.docId)}catch{this._failed=!0}}render(){return this._failed||!this.docId?u:this._url?l`
|
||||
`],c([v({attribute:!1})],V.prototype,"hass",2),c([h()],V.prototype,"_open",2),c([h()],V.prototype,"_title",2),c([h()],V.prototype,"_message",2),c([h()],V.prototype,"_confirmText",2),c([h()],V.prototype,"_danger",2),c([h()],V.prototype,"_inputLabel",2),c([h()],V.prototype,"_inputType",2),c([h()],V.prototype,"_options",2),c([h()],V.prototype,"_inputValue",2);customElements.get("maintenance-confirm-dialog")||customElements.define("maintenance-confirm-dialog",V)});function pl(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function Ue(s,r){let e=pl(),t=e.querySelector(`${Yn}[${Qn}]`);return t||(t=document.createElement(Yn),t.setAttribute(Qn,""),e.appendChild(t)),t.hass=s,t.confirm(r)}var Yn,Qn,vi=y(()=>{"use strict";Kn();Yn="maintenance-confirm-dialog",Qn="data-ms-lovelace-confirm"});function Zn(s,r,e){let t=new Blob([s],{type:e}),i=URL.createObjectURL(t),n=document.createElement("a");n.href=i,n.download=r,n.target="_blank",n.rel="noopener",n.style.display="none",document.body.appendChild(n),n.dispatchEvent(new MouseEvent("click")),document.body.removeChild(n),setTimeout(()=>URL.revokeObjectURL(i),6e4)}var gr=y(()=>{"use strict"});async function ul(s,r,e=300){return(await s.connection.sendMessagePromise({type:"auth/sign_path",path:r,expires:e})).path}async function Jn(s,r,e=300){return ul(s,`/api/maintenance_supporter/document/${r}`,e)}var Xn=y(()=>{"use strict";gr()});var Ee,fr=y(()=>{"use strict";I();F();Xn();Ee=class extends S{constructor(){super(...arguments);this.docId="";this._url="";this._failed=!1;this._signedFor=""}updated(){this.hass&&this.docId&&this._signedFor!==this.docId&&(this._signedFor=this.docId,this._url="",this._failed=!1,this._sign())}async _sign(){try{this._url=await Jn(this.hass,this.docId)}catch{this._failed=!0}}render(){return this._failed||!this.docId?u:this._url?l`
|
||||
<a href=${this._url} target="_blank" rel="noopener" class="wrap">
|
||||
<img src=${this._url} alt="" loading="lazy"
|
||||
@error=${()=>this._failed=!0} />
|
||||
@@ -3828,7 +3836,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||
margin-top: 4px;
|
||||
}
|
||||
`,c([v({attribute:!1})],Ee.prototype,"hass",2),c([v()],Ee.prototype,"docId",2),c([h()],Ee.prototype,"_url",2),c([h()],Ee.prototype,"_failed",2);customElements.get("maintenance-history-photo")||customElements.define("maintenance-history-photo",Ee)});var K,Xn=y(()=>{"use strict";I();F();T();ze();Z();St();fi();pr();pi();vi();tt();hi();gr();Ct();Ct();K=class extends S{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null;this._partOptions=null;this._partQty={};this._partQtyOriginal="";this._openGen=0;this._photos=new rt(this,{entryId:()=>this._draft?.entry_id??"",hass:()=>this.hass});this._photosOriginal="";this._readingRows=[];this._readingText={};this._readingsOriginal=""}get _lang(){return N(this.hass)}openEdit(e){this._openGen++,this._draft={...e},this._originalSnapshot={...e},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._photos.reset(e.photo_doc_ids??[]),this._photosOriginal=JSON.stringify(this._photos.ids),this._seedReadings(e),this._loadPartOptions()}_seedReadings(e){let t=[],i=new Set;for(let o of e.readings??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));for(let o of e.reading_values??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));this._readingRows=t;let n={};for(let o of e.reading_values??[])n[o.id]=String(o.value);this._readingText=n,this._readingsOriginal=JSON.stringify(this._readingNumbers())}_readingNumbers(){let e={};for(let t of this._readingRows){let i=(this._readingText[t.id]??"").trim();if(i==="")continue;let n=parseFloat(i.replace(",","."));isNaN(n)||(e[t.id]=n)}return e}async _loadPartOptions(){let e=this._draft;if(!e)return;let t=this._openGen;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"});if(t!==this._openGen)return;let n=[];for(let d of i.parts||[]){let p=d.entry_id===e.entry_id,_=d.consumers.some(m=>m.entry_id===e.entry_id&&m.task_id===e.task_id);!p&&!_||n.push({part_id:d.part_id,name:d.name,entry_id:d.entry_id,foreign:!p,object_name:d.object_name})}for(let d of e.used_parts||[]){let p=d.entry_id||e.entry_id;n.some(_=>_.part_id===d.part_id&&_.entry_id===p)||n.push({part_id:d.part_id,name:d.name||d.part_id,entry_id:p,foreign:p!==e.entry_id,object_name:null})}let o={};for(let d of e.used_parts||[])o[`${d.entry_id||e.entry_id}:${d.part_id}`]=d.quantity??1;this._partOptions=n,this._partQty=o,this._partQtyOriginal=this._partSelectionKey()}catch{if(t!==this._openGen)return;this._partOptions=[]}}_partSelectionKey(){return JSON.stringify(Object.entries(this._partQty).filter(([,e])=>e>0).sort(([e],[t])=>e.localeCompare(t)))}close(){this._openGen++,this._open=!1,this._error="",this._draft=null,this._originalSnapshot=null,this._photos.discardOrphans()}_set(e,t){this._draft&&(this._draft={...this._draft,[e]:t})}async _delete(){if(!this._draft||!this._originalSnapshot)return;let e=this._lang,i=(this._originalSnapshot.used_parts||[]).filter(p=>p.quantity>0).map(p=>`${C(p.quantity,e)}\xD7 ${p.name||p.part_id}`).join(", ");if(!await Ue(this.hass,{title:a("history_delete_entry",e),message:i?`${a("history_delete_confirm_entry",e)} ${a("history_delete_returns_parts",e).replace("{parts}",i)}`:a("history_delete_confirm_entry",e),confirmText:a("delete",e),danger:!0})||!this._draft||!this._originalSnapshot)return;let o=this._draft;this._error="",await this._runWs({type:"maintenance_supporter/task/history/delete",entry_id:o.entry_id,task_id:o.task_id,timestamp:this._originalSnapshot.original_timestamp})!==void 0&&(this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:o.entry_id,task_id:o.task_id,deleted:!0},bubbles:!0,composed:!0})),this.close())}_runWs(e){return D(this,e,{busy:t=>{this._saving=t},onError:t=>{this._error=t}})}async _save(){if(!this._draft||!this._originalSnapshot||this._saving||this._photos.uploading)return;this._error="",this._photos.clearError();let e=this._draft,t=this._originalSnapshot,i={type:"maintenance_supporter/task/history/update",entry_id:e.entry_id,task_id:e.task_id,original_timestamp:t.original_timestamp};if(e.timestamp!==t.timestamp&&(i.timestamp=e.timestamp),e.notes!==t.notes&&(i.notes=e.notes),e.cost!==t.cost&&(i.cost=e.cost),e.duration!==t.duration&&(i.duration=e.duration),e.completed_by!==t.completed_by&&(i.completed_by=e.completed_by),this._partOptions!==null&&this._partSelectionKey()!==this._partQtyOriginal&&(i.used_parts=(this._partOptions||[]).filter(o=>(this._partQty[`${o.entry_id}:${o.part_id}`]||0)>0).map(o=>({part_id:o.part_id,quantity:this._partQty[`${o.entry_id}:${o.part_id}`],...o.foreign?{entry_id:o.entry_id}:{}}))),e.reading_value!==t.reading_value&&(i.reading_value=e.reading_value??null),this._readingRows.length>0&&JSON.stringify(this._readingNumbers())!==this._readingsOriginal){let o=this._readingNumbers(),d={};for(let p of this._readingRows)d[p.id]=o[p.id]??null;i.reading_values=d}if(JSON.stringify(
Line truncated
|
||||
`,c([v({attribute:!1})],Ee.prototype,"hass",2),c([v()],Ee.prototype,"docId",2),c([h()],Ee.prototype,"_url",2),c([h()],Ee.prototype,"_failed",2);customElements.get("maintenance-history-photo")||customElements.define("maintenance-history-photo",Ee)});var K,ea=y(()=>{"use strict";I();F();T();ze();Z();St();fi();ur();pi();vi();tt();hi();fr();Ct();Ct();K=class extends S{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null;this._partOptions=null;this._partQty={};this._partQtyOriginal="";this._openGen=0;this._photos=new rt(this,{entryId:()=>this._draft?.entry_id??"",hass:()=>this.hass});this._photosOriginal="";this._readingRows=[];this._readingText={};this._readingsOriginal=""}get _lang(){return N(this.hass)}openEdit(e){this._openGen++,this._draft={...e},this._originalSnapshot={...e},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._photos.reset(e.photo_doc_ids??[]),this._photosOriginal=JSON.stringify(this._photos.ids),this._seedReadings(e),this._loadPartOptions()}_seedReadings(e){let t=[],i=new Set;for(let o of e.readings??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));for(let o of e.reading_values??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));this._readingRows=t;let n={};for(let o of e.reading_values??[])n[o.id]=String(o.value);this._readingText=n,this._readingsOriginal=JSON.stringify(this._readingNumbers())}_readingNumbers(){let e={};for(let t of this._readingRows){let i=(this._readingText[t.id]??"").trim();if(i==="")continue;let n=parseFloat(i.replace(",","."));isNaN(n)||(e[t.id]=n)}return e}async _loadPartOptions(){let e=this._draft;if(!e)return;let t=this._openGen;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"});if(t!==this._openGen)return;let n=[];for(let d of i.parts||[]){let p=d.entry_id===e.entry_id,_=d.consumers.some(m=>m.entry_id===e.entry_id&&m.task_id===e.task_id);!p&&!_||n.push({part_id:d.part_id,name:d.name,entry_id:d.entry_id,foreign:!p,object_name:d.object_name})}for(let d of e.used_parts||[]){let p=d.entry_id||e.entry_id;n.some(_=>_.part_id===d.part_id&&_.entry_id===p)||n.push({part_id:d.part_id,name:d.name||d.part_id,entry_id:p,foreign:p!==e.entry_id,object_name:null})}let o={};for(let d of e.used_parts||[])o[`${d.entry_id||e.entry_id}:${d.part_id}`]=d.quantity??1;this._partOptions=n,this._partQty=o,this._partQtyOriginal=this._partSelectionKey()}catch{if(t!==this._openGen)return;this._partOptions=[]}}_partSelectionKey(){return JSON.stringify(Object.entries(this._partQty).filter(([,e])=>e>0).sort(([e],[t])=>e.localeCompare(t)))}close(){this._openGen++,this._open=!1,this._error="",this._draft=null,this._originalSnapshot=null,this._photos.discardOrphans()}_set(e,t){this._draft&&(this._draft={...this._draft,[e]:t})}async _delete(){if(!this._draft||!this._originalSnapshot)return;let e=this._lang,i=(this._originalSnapshot.used_parts||[]).filter(p=>p.quantity>0).map(p=>`${C(p.quantity,e)}\xD7 ${p.name||p.part_id}`).join(", ");if(!await Ue(this.hass,{title:a("history_delete_entry",e),message:i?`${a("history_delete_confirm_entry",e)} ${a("history_delete_returns_parts",e).replace("{parts}",i)}`:a("history_delete_confirm_entry",e),confirmText:a("delete",e),danger:!0})||!this._draft||!this._originalSnapshot)return;let o=this._draft;this._error="",await this._runWs({type:"maintenance_supporter/task/history/delete",entry_id:o.entry_id,task_id:o.task_id,timestamp:this._originalSnapshot.original_timestamp})!==void 0&&(this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:o.entry_id,task_id:o.task_id,deleted:!0},bubbles:!0,composed:!0})),this.close())}_runWs(e){return D(this,e,{busy:t=>{this._saving=t},onError:t=>{this._error=t}})}async _save(){if(!this._draft||!this._originalSnapshot||this._saving||this._photos.uploading)return;this._error="",this._photos.clearError();let e=this._draft,t=this._originalSnapshot,i={type:"maintenance_supporter/task/history/update",entry_id:e.entry_id,task_id:e.task_id,original_timestamp:t.original_timestamp};if(e.timestamp!==t.timestamp&&(i.timestamp=e.timestamp),e.notes!==t.notes&&(i.notes=e.notes),e.cost!==t.cost&&(i.cost=e.cost),e.duration!==t.duration&&(i.duration=e.duration),e.completed_by!==t.completed_by&&(i.completed_by=e.completed_by),this._partOptions!==null&&this._partSelectionKey()!==this._partQtyOriginal&&(i.used_parts=(this._partOptions||[]).filter(o=>(this._partQty[`${o.entry_id}:${o.part_id}`]||0)>0).map(o=>({part_id:o.part_id,quantity:this._partQty[`${o.entry_id}:${o.part_id}`],...o.foreign?{entry_id:o.entry_id}:{}}))),e.reading_value!==t.reading_value&&(i.reading_value=e.reading_value??null),this._readingRows.length>0&&JSON.stringify(this._readingNumbers())!==this._readingsOriginal){let o=this._readingNumbers(),d={};for(let p of this._readingRows)d[p.id]=o[p.id]??null;i.reading_values=d}if(JSON.stringify(
Line truncated
|
||||
<h2>${a("history_edit_title",e)}</h2>
|
||||
<div class="entry-type">
|
||||
<ha-icon icon="mdi:tag-outline"></ha-icon>
|
||||
@@ -3841,7 +3849,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.lang=${e}
|
||||
.label=${a("history_edit_timestamp",e)}
|
||||
.helper=${ri(e)}
|
||||
.value=${xs(t.timestamp)}
|
||||
.value=${ws(t.timestamp)}
|
||||
@value-changed=${n=>{let o=n.detail.value;o&&this._set("timestamp",o)}}
|
||||
></ms-date-field>
|
||||
<label>
|
||||
@@ -4018,7 +4026,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
}
|
||||
/* the camera / gallery pickers come from photoPickerStyles (ms-photo-picker) */
|
||||
.photos-hint { font-size: 12px; color: var(--secondary-text-color); }
|
||||
`],c([v({attribute:!1})],K.prototype,"hass",2),c([h()],K.prototype,"_open",2),c([h()],K.prototype,"_saving",2),c([h()],K.prototype,"_error",2),c([h()],K.prototype,"_draft",2),c([h()],K.prototype,"_partOptions",2),c([h()],K.prototype,"_partQty",2),c([h()],K.prototype,"_readingRows",2),c([h()],K.prototype,"_readingText",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",K)});function Be(s){return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function fr(s){return!s.startsWith("data:image/svg+xml,")&&!s.startsWith("data:image/png;base64,")?"":Be(s)}function dl(s){return s.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var Y,ea=y(()=>{"use strict";I();F();T();mr();Y=class extends S{constructor(){super(...arguments);this.lang="";this._open=!1;this._loading=!1;this._error="";this._viewResult=null;this._completeResult=null;this._quickResult=null;this._urlMode="companion";this._entryId="";this._taskId=null;this._objectName="";this._taskName="";this._generateSeq=0}get _dialogLang(){return this.lang||N(this.hass)}openForObject(e,t){this._entryId=e,this._taskId=null,this._objectName=t,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}openForTask(e,t,i,n){this._entryId=e,this._taskId=t,this._objectName=i,this._taskName=n,this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}async _generate(){let e=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null;try{let t={type:"maintenance_supporter/qr/generate",entry_id:this._entryId,url_mode:this._urlMode};this._taskId&&(t.task_id=this._taskId);let i=[this.hass.connection.sendMessagePromise({...t,action:"view"})];this._taskId&&(i.push(this.hass.connection.sendMessagePromise({...t,action:"complete"})),await this._hasQuickCompleteDefaults()&&i.push(this.hass.connection.sendMessagePromise({...t,action:"quick_complete"})));let n=await Promise.all(i);if(e!==this._generateSeq)return;this._viewResult=n[0],n.length>1&&(this._completeResult=n[1]),n.length>2&&(this._quickResult=n[2])}catch(t){if(e!==this._generateSeq)return;let i=t?.code,n=t?.message;this._error=i==="no_url"||typeof n=="string"&&n.includes("No Home Assistant URL")?a("qr_error_no_url",this._dialogLang):a("qr_error",this._dialogLang)}finally{e===this._generateSeq&&(this._loading=!1)}}async _hasQuickCompleteDefaults(){try{let t=((await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId})).tasks||[]).find(i=>i.id===this._taskId);return!!t?.quick_complete_defaults&&Object.keys(t.quick_complete_defaults).length>0}catch{return!1}}_setUrlMode(e){this._urlMode!==e&&(this._urlMode=e,this._generate())}_print(){if(!this._viewResult)return;let e=this._viewResult,t=e.label.task_name?`${e.label.object_name} \u2014 ${e.label.task_name}`:e.label.object_name,i=[e.label.manufacturer,e.label.model].filter(Boolean).join(" "),n=window.open("","_blank","width=600,height=500");if(!n)return;let o=this._dialogLang,d=Be(t),p=Be(i),_=!!this._completeResult,m=!!this._quickResult,f=Be(a("qr_action_view",o)),x=Be(a("qr_action_complete",o)),w=Be(a("qr_action_quick_complete",o));n.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
||||
`],c([v({attribute:!1})],K.prototype,"hass",2),c([h()],K.prototype,"_open",2),c([h()],K.prototype,"_saving",2),c([h()],K.prototype,"_error",2),c([h()],K.prototype,"_draft",2),c([h()],K.prototype,"_partOptions",2),c([h()],K.prototype,"_partQty",2),c([h()],K.prototype,"_readingRows",2),c([h()],K.prototype,"_readingText",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",K)});function Be(s){return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function vr(s){return!s.startsWith("data:image/svg+xml,")&&!s.startsWith("data:image/png;base64,")?"":Be(s)}function hl(s){return s.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var Y,ta=y(()=>{"use strict";I();F();T();gr();Y=class extends S{constructor(){super(...arguments);this.lang="";this._open=!1;this._loading=!1;this._error="";this._viewResult=null;this._completeResult=null;this._quickResult=null;this._urlMode="companion";this._entryId="";this._taskId=null;this._objectName="";this._taskName="";this._generateSeq=0}get _dialogLang(){return this.lang||N(this.hass)}openForObject(e,t){this._entryId=e,this._taskId=null,this._objectName=t,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}openForTask(e,t,i,n){this._entryId=e,this._taskId=t,this._objectName=i,this._taskName=n,this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}async _generate(){let e=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null;try{let t={type:"maintenance_supporter/qr/generate",entry_id:this._entryId,url_mode:this._urlMode};this._taskId&&(t.task_id=this._taskId);let i=[this.hass.connection.sendMessagePromise({...t,action:"view"})];this._taskId&&(i.push(this.hass.connection.sendMessagePromise({...t,action:"complete"})),await this._hasQuickCompleteDefaults()&&i.push(this.hass.connection.sendMessagePromise({...t,action:"quick_complete"})));let n=await Promise.all(i);if(e!==this._generateSeq)return;this._viewResult=n[0],n.length>1&&(this._completeResult=n[1]),n.length>2&&(this._quickResult=n[2])}catch(t){if(e!==this._generateSeq)return;let i=t?.code,n=t?.message;this._error=i==="no_url"||typeof n=="string"&&n.includes("No Home Assistant URL")?a("qr_error_no_url",this._dialogLang):a("qr_error",this._dialogLang)}finally{e===this._generateSeq&&(this._loading=!1)}}async _hasQuickCompleteDefaults(){try{let t=((await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId})).tasks||[]).find(i=>i.id===this._taskId);return!!t?.quick_complete_defaults&&Object.keys(t.quick_complete_defaults).length>0}catch{return!1}}_setUrlMode(e){this._urlMode!==e&&(this._urlMode=e,this._generate())}_print(){if(!this._viewResult)return;let e=this._viewResult,t=e.label.task_name?`${e.label.object_name} \u2014 ${e.label.task_name}`:e.label.object_name,i=[e.label.manufacturer,e.label.model].filter(Boolean).join(" "),n=window.open("","_blank","width=600,height=500");if(!n)return;let o=this._dialogLang,d=Be(t),p=Be(i),_=!!this._completeResult,m=!!this._quickResult,f=Be(a("qr_action_view",o)),x=Be(a("qr_action_complete",o)),w=Be(a("qr_action_quick_complete",o));n.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
||||
<meta name="color-scheme" content="light">
|
||||
<title>${d}</title>
|
||||
<style>
|
||||
@@ -4040,21 +4048,21 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
${p?`<div class="sub">${p}</div>`:""}
|
||||
<div class="qr-row">
|
||||
<div class="qr-col">
|
||||
<img src="${fr(this._viewResult.svg_data_uri)}" alt="QR Info" />
|
||||
<img src="${vr(this._viewResult.svg_data_uri)}" alt="QR Info" />
|
||||
<div class="qr-label">${f}</div>
|
||||
</div>
|
||||
${_?`<div class="qr-col">
|
||||
<img src="${fr(this._completeResult.svg_data_uri)}" alt="QR Complete" />
|
||||
<img src="${vr(this._completeResult.svg_data_uri)}" alt="QR Complete" />
|
||||
<div class="qr-label">${x}</div>
|
||||
</div>`:""}
|
||||
${m?`<div class="qr-col">
|
||||
<img src="${fr(this._quickResult.svg_data_uri)}" alt="QR Quick-complete" />
|
||||
<img src="${vr(this._quickResult.svg_data_uri)}" alt="QR Quick-complete" />
|
||||
<div class="qr-label">${w}</div>
|
||||
</div>`:""}
|
||||
</div>
|
||||
<div class="url">${Be(this._viewResult.url)}</div>
|
||||
<script>setTimeout(()=>window.print(),300)<\/script>
|
||||
</body></html>`),n.document.close()}_downloadSvg(e,t){let i=decodeURIComponent(e.svg_data_uri.replace("data:image/svg+xml,","")),n=this._taskName?`${this._objectName}-${this._taskName}`:this._objectName;Qn(i,`qr-${dl(n)}-${t}.svg`,"image/svg+xml")}_close(){this._open=!1,this._viewResult=null,this._completeResult=null,this._quickResult=null,this._error="",this._loading=!1}render(){if(!this._open)return l``;let e=this._dialogLang,t=this._taskName?`${a("qr_code",e)}: ${this._objectName} \u2014 ${this._taskName}`:`${a("qr_code",e)}: ${this._objectName}`,i=!!this._viewResult;return l`
|
||||
</body></html>`),n.document.close()}_downloadSvg(e,t){let i=decodeURIComponent(e.svg_data_uri.replace("data:image/svg+xml,","")),n=this._taskName?`${this._objectName}-${this._taskName}`:this._objectName;Zn(i,`qr-${hl(n)}-${t}.svg`,"image/svg+xml")}_close(){this._open=!1,this._viewResult=null,this._completeResult=null,this._quickResult=null,this._error="",this._loading=!1}render(){if(!this._open)return l``;let e=this._dialogLang,t=this._taskName?`${a("qr_code",e)}: ${this._objectName} \u2014 ${this._taskName}`:`${a("qr_code",e)}: ${this._objectName}`,i=!!this._viewResult;return l`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${t}</div>
|
||||
<div class="content">
|
||||
@@ -4250,14 +4258,14 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
color: var(--text-primary-color, #fff);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
`,c([v({attribute:!1})],Y.prototype,"hass",2),c([v()],Y.prototype,"lang",2),c([h()],Y.prototype,"_open",2),c([h()],Y.prototype,"_loading",2),c([h()],Y.prototype,"_error",2),c([h()],Y.prototype,"_viewResult",2),c([h()],Y.prototype,"_completeResult",2),c([h()],Y.prototype,"_quickResult",2),c([h()],Y.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",Y)});function ta(s,r,e=new Date){let t=s?.hours,i=Q(s?.snoozed_until);if(typeof t!="number"||!Number.isFinite(i))return a("snoozed",r);let n=fe(),d=ve(i,n)===ve(e,n)?ti(new Date(i),r):ii(s.snoozed_until,r);return(t===1?a("snoozed_for_one",r):a("snoozed_for",r).replace("{hours}",C(t,r))).replace("{until}",d)}var ia=y(()=>{"use strict";T();Z()});function pl(s,r){if(r<=0)return 0;let e=typeof s=="number"&&Number.isFinite(s)?Math.trunc(s):0;return e<0?0:e%r}function ul(s){return!!(s?.phases&&s.phase_sequence&&s.phase_sequence.length>0)}function vr(s){if(!s||!ul(s))return null;let r=s.phase_sequence,e=pl(s.phase_cursor,r.length),t=r[e],i=s.phases?.[t];return i?{id:t,name:i.name,index:e,count:r.length,notes:i.notes,checklist:i.checklist!==void 0?i.checklist:s.checklist??[],consumesParts:i.consumes_parts!==void 0?i.consumes_parts:s.consumes_parts??[],requiredFields:i.required_completion_fields!==void 0?i.required_completion_fields:s.required_completion_fields??[]}:null}function It(s){let r=vr(s);return r?`${r.index+1}/${r.count} \xB7 ${r.name}`:""}var yr=y(()=>{"use strict"});function hl(s,r){return typeof s=="number"&&Number.isFinite(s)&&s>=.01?s:r}function ra(s){let r=s.task??null,e=r?vr(r):null,t=e?e.consumesParts:r?.consumes_parts||[],i=!!r?.part_ref,n=s.objects.find(m=>m.entry_id===s.entryId)?.parts||[],o=i?n.find(m=>m.id===r.part_ref.part_id):void 0,d=s.features?s.features.checklists:s.checklistsEnabled??!0,p=s.features?s.features.checklists?s.checklist??r?.checklist??[]:[]:s.checklist??[],_=s.features?s.features.adaptive&&(s.adaptiveEnabled??!!r?.adaptive_config?.enabled):!!s.adaptiveEnabled;return{entry_id:s.entryId,task_id:s.taskId,task_name:s.taskName,checklist:e?d?e.checklist:[]:p,adaptive_enabled:_,required_completion_fields:e?e.requiredFields:r?.required_completion_fields||[],task_type:r?.type||"",reading_unit:r?.reading_unit||"",readings:r?.readings||[],reading_history:Ys(r?.history),parts:i?[]:yn({consumes_parts:t},s.entryId,s.objects,s.lang),consumes_parts:i?[]:t,phase_label:e?It(r):"",require_tag_scan:!!r?.require_tag_scan,restock_default:i?hl(o?.restock_quantity,1):null,restock_unit_cost:i?o?.cost??null:null,restock_package:i&&o?.package_size?Ze(o.package_size,o.unit,s.lang):"",currency_symbol:De({currency_symbol:s.currencySymbol}),consumes_info:t.map(m=>vn(m,s.entryId,s.objects,s.lang)),checklist_prefill:r?.checklist_progress||{},via_tag_scan:!!s.viaTagScan,parts_cost_mode:s.partsCostMode??"purchase"}}function sa(s,r,e){s.entryId=r.entry_id,s.taskId=r.task_id,s.taskName=r.task_name,s.lang=e,s.checklist=r.checklist??[],s.adaptiveEnabled=!!r.adaptive_enabled,s.requiredFields=r.required_completion_fields??[],s.taskType=r.task_type??"",s.readingUnit=r.reading_unit??"",s.readings=r.readings??[],s.readingHistory=r.reading_history??[],s.parts=r.parts??[],s.consumesParts=r.consumes_parts??[],s.phaseLabel=r.phase_label??"",s.requireTagScan=!!r.require_tag_scan,s.restockDefault=r.restock_default??null,s.restockUnitCost=r.restock_unit_cost??null,s.restockPackage=r.restock_package??"",s.currencySymbol=De(r),s.consumesInfo=r.consumes_info??[],s.checklistPrefill=r.checklist_prefill??{},s.viaTagScan=!!r.via_tag_scan,s.partsCostMode=r.parts_cost_mode??"purchase",s.open({viaTagScan:!!r.via_tag_scan})}var br=y(()=>{"use strict";je();di();yr();T()});var kh,na,aa=y(()=>{Ge();({I:kh}=Jr),na=s=>s.strings===void 0});var oa,xr,yi,bi=y(()=>{oa={ATTRIBUTE:1,CHILD:2,PROPERTY:3,BOOLEAN_ATTRIBUTE:4,EVENT:5,ELEMENT:6},xr=s=>(...r)=>({_$litDirective$:s,values:r}),yi=class{constructor(r){}get _$AU(){return this._$AM._$AU}_$AT(r,e,t){this._$Ct=r,this._$AM=e,this._$Ci=t}_$AS(r,e){return this.update(r,e)}update(r,e){return this.render(...e)}}});function _l(s){this._$AN!==void 0?(xi(this),this._$AM=s,la(this)):this._$AM=s}function ml(s,r=!1,e=0){let t=this._$AH,i=this._$AN;if(i!==void 0&&i.size!==0)if(r)if(Array.isArray(t))for(let n=e;n<t.length;n++)Rt(t[n],!1),xi(t[n]);else t!=null&&(Rt(t,!1),xi(t));else Rt(this,s)}var Rt,xi,la,gl,wi,ca=y(()=>{aa();bi();bi();Rt=(s,r)=>{let e=s._$AN;if(e===void 0)return!1;for(let t of e)t._$AO?.(r,!1),Rt(t,r);return!0},xi=s=>{let r,e;do{if((r=s._$AM)===void 0)break;e=r._$AN,e.delete(s),s=r}while(e?.size===0)},la=s=>{for(let r;r=s._$AM;s=r){let e=r._$AN;if(e===void 0)r._$AN=e=new Set;else if(e.has(s))break;e.add(s),gl(r)}};gl=s=>{s.type==oa.CHILD&&(s._$AP??=ml,s._$AQ??=_l)},wi=class extends yi{constructor(){super(...arguments),this._$AN=void 0}_$AT(r,e,t){super._$AT(r,e,t),la(this),this.isConnected=r._$AU}_$AO(r,e=!0){r!==this.isConnected&&(this.isConnected=r,r?this.reconnected?.():this.di
Line truncated
|
||||
`,c([v({attribute:!1})],Y.prototype,"hass",2),c([v()],Y.prototype,"lang",2),c([h()],Y.prototype,"_open",2),c([h()],Y.prototype,"_loading",2),c([h()],Y.prototype,"_error",2),c([h()],Y.prototype,"_viewResult",2),c([h()],Y.prototype,"_completeResult",2),c([h()],Y.prototype,"_quickResult",2),c([h()],Y.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",Y)});function ia(s,r,e=new Date){let t=s?.hours,i=Q(s?.snoozed_until);if(typeof t!="number"||!Number.isFinite(i))return a("snoozed",r);let n=fe(),d=ve(i,n)===ve(e,n)?ti(new Date(i),r):ii(s.snoozed_until,r);return(t===1?a("snoozed_for_one",r):a("snoozed_for",r).replace("{hours}",C(t,r))).replace("{until}",d)}var ra=y(()=>{"use strict";T();Z()});function _l(s,r){if(r<=0)return 0;let e=typeof s=="number"&&Number.isFinite(s)?Math.trunc(s):0;return e<0?0:e%r}function ml(s){return!!(s?.phases&&s.phase_sequence&&s.phase_sequence.length>0)}function yr(s){if(!s||!ml(s))return null;let r=s.phase_sequence,e=_l(s.phase_cursor,r.length),t=r[e],i=s.phases?.[t];return i?{id:t,name:i.name,index:e,count:r.length,notes:i.notes,checklist:i.checklist!==void 0?i.checklist:s.checklist??[],consumesParts:i.consumes_parts!==void 0?i.consumes_parts:s.consumes_parts??[],requiredFields:i.required_completion_fields!==void 0?i.required_completion_fields:s.required_completion_fields??[]}:null}function It(s){let r=yr(s);return r?`${r.index+1}/${r.count} \xB7 ${r.name}`:""}var br=y(()=>{"use strict"});function gl(s,r){return typeof s=="number"&&Number.isFinite(s)&&s>=.01?s:r}function sa(s){let r=s.task??null,e=r?yr(r):null,t=e?e.consumesParts:r?.consumes_parts||[],i=!!r?.part_ref,n=s.objects.find(m=>m.entry_id===s.entryId)?.parts||[],o=i?n.find(m=>m.id===r.part_ref.part_id):void 0,d=s.features?s.features.checklists:s.checklistsEnabled??!0,p=s.features?s.features.checklists?s.checklist??r?.checklist??[]:[]:s.checklist??[],_=s.features?s.features.adaptive&&(s.adaptiveEnabled??!!r?.adaptive_config?.enabled):!!s.adaptiveEnabled;return{entry_id:s.entryId,task_id:s.taskId,task_name:s.taskName,checklist:e?d?e.checklist:[]:p,adaptive_enabled:_,required_completion_fields:e?e.requiredFields:r?.required_completion_fields||[],task_type:r?.type||"",reading_unit:r?.reading_unit||"",readings:r?.readings||[],reading_history:Qs(r?.history),parts:i?[]:bn({consumes_parts:t},s.entryId,s.objects,s.lang),consumes_parts:i?[]:t,phase_label:e?It(r):"",require_tag_scan:!!r?.require_tag_scan,restock_default:i?gl(o?.restock_quantity,1):null,restock_unit_cost:i?o?.cost??null:null,restock_package:i&&o?.package_size?Ze(o.package_size,o.unit,s.lang):"",currency_symbol:De({currency_symbol:s.currencySymbol}),consumes_info:t.map(m=>yn(m,s.entryId,s.objects,s.lang)),checklist_prefill:r?.checklist_progress||{},via_tag_scan:!!s.viaTagScan,parts_cost_mode:s.partsCostMode??"purchase"}}function na(s,r,e){s.entryId=r.entry_id,s.taskId=r.task_id,s.taskName=r.task_name,s.lang=e,s.checklist=r.checklist??[],s.adaptiveEnabled=!!r.adaptive_enabled,s.requiredFields=r.required_completion_fields??[],s.taskType=r.task_type??"",s.readingUnit=r.reading_unit??"",s.readings=r.readings??[],s.readingHistory=r.reading_history??[],s.parts=r.parts??[],s.consumesParts=r.consumes_parts??[],s.phaseLabel=r.phase_label??"",s.requireTagScan=!!r.require_tag_scan,s.restockDefault=r.restock_default??null,s.restockUnitCost=r.restock_unit_cost??null,s.restockPackage=r.restock_package??"",s.currencySymbol=De(r),s.consumesInfo=r.consumes_info??[],s.checklistPrefill=r.checklist_prefill??{},s.viaTagScan=!!r.via_tag_scan,s.partsCostMode=r.parts_cost_mode??"purchase",s.open({viaTagScan:!!r.via_tag_scan})}var xr=y(()=>{"use strict";je();di();br();T()});var Th,aa,oa=y(()=>{Ge();({I:Th}=Xr),aa=s=>s.strings===void 0});var la,wr,yi,bi=y(()=>{la={ATTRIBUTE:1,CHILD:2,PROPERTY:3,BOOLEAN_ATTRIBUTE:4,EVENT:5,ELEMENT:6},wr=s=>(...r)=>({_$litDirective$:s,values:r}),yi=class{constructor(r){}get _$AU(){return this._$AM._$AU}_$AT(r,e,t){this._$Ct=r,this._$AM=e,this._$Ci=t}_$AS(r,e){return this.update(r,e)}update(r,e){return this.render(...e)}}});function fl(s){this._$AN!==void 0?(xi(this),this._$AM=s,ca(this)):this._$AM=s}function vl(s,r=!1,e=0){let t=this._$AH,i=this._$AN;if(i!==void 0&&i.size!==0)if(r)if(Array.isArray(t))for(let n=e;n<t.length;n++)Rt(t[n],!1),xi(t[n]);else t!=null&&(Rt(t,!1),xi(t));else Rt(this,s)}var Rt,xi,ca,yl,wi,da=y(()=>{oa();bi();bi();Rt=(s,r)=>{let e=s._$AN;if(e===void 0)return!1;for(let t of e)t._$AO?.(r,!1),Rt(t,r);return!0},xi=s=>{let r,e;do{if((r=s._$AM)===void 0)break;e=r._$AN,e.delete(s),s=r}while(e?.size===0)},ca=s=>{for(let r;r=s._$AM;s=r){let e=r._$AN;if(e===void 0)r._$AN=e=new Set;else if(e.has(s))break;e.add(s),yl(r)}};yl=s=>{s.type==la.CHILD&&(s._$AP??=vl,s._$AQ??=fl)},wi=class extends yi{constructor(){super(...arguments),this._$AN=void 0}_$AT(r,e,t){super._$AT(r,e,t),ca(this),this.isConnected=r._$AU}_$AO(r,e=!0){r!==this.isConnected&&(this.isConnected=r,r?this.reconnected?.():this.di
Line truncated
|
||||
class="notes-md"
|
||||
.content=${r}
|
||||
breaks
|
||||
${da(t=>xl(t,e))}
|
||||
></ha-markdown>`}return l`${s}`}function bl(s){let r=[],e=n=>{let o=$r(n);return!o||vl.has(o)||!ki(n)?null:(r.push(kr(n)),`${Tr}${r.length-1}`)},t=n=>n.replace(new RegExp(`(!?)(\\[[^\\]\\n]*\\]\\(\\s*)<(${$i}[^>\\n]*)>`,"g"),(o,d,p,_)=>{let m=d?null:e(_);return m?`${p}${m}`:o}).replace(new RegExp(`(!?)(\\[[^\\]\\n]*\\]\\(\\s*)(${$i}[^\\s)]*)`,"g"),(o,d,p,_)=>{let m=d?null:e(_);return m?`${p}${m}`:o}).replace(new RegExp(`(^|[^(])<(${$i}[^\\s<>]*)>`,"gm"),(o,d,p)=>{let _=e(p);return _?`${d}[${p.replace(/([\\[\]])/g,"\\$1")}](${_})`:o}).replace(new RegExp(`^( {0,3}\\[[^\\]\\n]+\\]:[ \\t]*)<?(${$i}[^\\s>]*)>?`,"gm"),(o,d,p)=>{let _=e(p);return _?`${d}${_}`:o});return{content:s.split(yl).map((n,o)=>o%2?n:t(n)).join(""),links:r}}function Sr(s,r){for(let e of s.querySelectorAll(`a[href^="${Tr}"]`)){let t=r[Number(e.getAttribute("href").slice(Tr.length))];t&&e.setAttribute("href",t)}}function xl(s,r){if(!s)return;let e=_a.get(s);if(!e&&r.length===0)return;if(e){e.links=r,s.shadowRoot&&Sr(s.shadowRoot,r);return}let t={links:r};_a.set(s,t),(async()=>{await s.updateComplete;let i=s.shadowRoot;i&&(new MutationObserver(()=>Sr(i,t.links)).observe(i,{childList:!0,subtree:!0}),Sr(i,t.links))})()}var Tr,vl,yl,$i,_a,Ar=y(()=>{"use strict";I();ua();Er();Tr="https://app-link.invalid/",vl=new Set(["http","https","mailto","tel","ftp"]),yl=/(```[\s\S]*?```|~~~[\s\S]*?~~~|`[^`\n]*`)/,$i="[a-zA-Z][a-zA-Z0-9+.-]+:";_a=new WeakMap});function wl(s){return s&&ma(s.ref_no)?String(s.ref_no):null}function ga(s,r){let e=wl(s);return e&&r&&ma(r.ref_no)?`${e}.${r.ref_no}`:null}function fa(s,r){return s?l`<span class="ref-chip" title=${r??""}>#${s}</span>`:u}var ma,Cr=y(()=>{"use strict";I();ma=s=>typeof s=="number"&&Number.isInteger(s)&&s>0});var va=y(()=>{"use strict"});function ya(s,r){if(!s)return"";let e=kl[s.trim()];if(e)return a(e,r);for(let[t,i,n]of $l){let o=s.trim().match(t);if(o){let d=n(o,r);return a(i,r).replace(/\{(\w+)\}/g,(p,_)=>d[_]??p)}}return s}var kl,$l,ba=y(()=>{"use strict";T();kl={"Completed from dashboard button":"hist_note_button","Completed from the To-do list":"hist_note_todo","Completed by voice":"hist_note_voice","Completed from the notification":"hist_note_notification","Completed via NFC tag":"hist_note_nfc","Completed from the shopping list":"hist_note_shopping_list","Completed from a mirrored to-do list":"hist_note_todo_mirror","Skipped from notification":"hist_note_skipped_notification","Skipped from dashboard button":"hist_note_skipped_button","Sensor trigger activated":"hist_note_sensor_triggered","Initial value set during task creation":"hist_note_initial"},$l=[[/^Auto-completed: sensor recovered \((.+)\)$/,"hist_note_auto_recovered",s=>({value:s[1]})],[/^Reset to (\d{4}-\d{2}-\d{2})$/,"hist_note_reset",(s,r)=>({date:O(s[1],r)})],[/^Trigger entity replaced: (.+) → (.+)$/,"hist_note_trigger_replaced",s=>({old:s[1],new:s[2]})],[/^Sensor trigger removed \(entity was: (.+)\)\. Schedule converted to (\w+)\.$/,"hist_note_trigger_removed",(s,r)=>({entity:s[1],schedule:a(s[2],r)})],[/^Entity (.+) removed from compound trigger; (\d+) conditions remain\.$/,"hist_note_compound_removed",s=>({entity:s[1],count:s[2]})]]});function xa(s){let r=e=>{let t=Q(e.timestamp);return Number.isNaN(t)?-1/0:t};return(s??[]).map((e,t)=>({entry:e,index:t,at:r(e)})).sort((e,t)=>t.at-e.at||t.index-e.index).map(e=>e.entry)}function Sl(s,r){return s.taskRef&&r.ref_no?`${s.taskRef}-${r.ref_no}`:null}function Tl(s,r){let e=ai(r);return e.length>0?l`<div class="history-photos">
|
||||
${pa(t=>$l(t,e))}
|
||||
></ha-markdown>`}return l`${s}`}function kl(s){let r=[],e=n=>{let o=Er(n);return!o||xl.has(o)||!ki(n)?null:(r.push($r(n)),`${Ar}${r.length-1}`)},t=n=>n.replace(new RegExp(`(!?)(\\[[^\\]\\n]*\\]\\(\\s*)<(${$i}[^>\\n]*)>`,"g"),(o,d,p,_)=>{let m=d?null:e(_);return m?`${p}${m}`:o}).replace(new RegExp(`(!?)(\\[[^\\]\\n]*\\]\\(\\s*)(${$i}[^\\s)]*)`,"g"),(o,d,p,_)=>{let m=d?null:e(_);return m?`${p}${m}`:o}).replace(new RegExp(`(^|[^(])<(${$i}[^\\s<>]*)>`,"gm"),(o,d,p)=>{let _=e(p);return _?`${d}[${p.replace(/([\\[\]])/g,"\\$1")}](${_})`:o}).replace(new RegExp(`^( {0,3}\\[[^\\]\\n]+\\]:[ \\t]*)<?(${$i}[^\\s>]*)>?`,"gm"),(o,d,p)=>{let _=e(p);return _?`${d}${_}`:o});return{content:s.split(wl).map((n,o)=>o%2?n:t(n)).join(""),links:r}}function Tr(s,r){for(let e of s.querySelectorAll(`a[href^="${Ar}"]`)){let t=r[Number(e.getAttribute("href").slice(Ar.length))];t&&e.setAttribute("href",t)}}function $l(s,r){if(!s)return;let e=ma.get(s);if(!e&&r.length===0)return;if(e){e.links=r,s.shadowRoot&&Tr(s.shadowRoot,r);return}let t={links:r};ma.set(s,t),(async()=>{await s.updateComplete;let i=s.shadowRoot;i&&(new MutationObserver(()=>Tr(i,t.links)).observe(i,{childList:!0,subtree:!0}),Tr(i,t.links))})()}var Ar,xl,wl,$i,ma,Cr=y(()=>{"use strict";I();ha();Sr();Ar="https://app-link.invalid/",xl=new Set(["http","https","mailto","tel","ftp"]),wl=/(```[\s\S]*?```|~~~[\s\S]*?~~~|`[^`\n]*`)/,$i="[a-zA-Z][a-zA-Z0-9+.-]+:";ma=new WeakMap});function El(s){return s&&ga(s.ref_no)?String(s.ref_no):null}function fa(s,r){let e=El(s);return e&&r&&ga(r.ref_no)?`${e}.${r.ref_no}`:null}function va(s,r){return s?l`<span class="ref-chip" title=${r??""}>#${s}</span>`:u}var ga,Ir=y(()=>{"use strict";I();ga=s=>typeof s=="number"&&Number.isInteger(s)&&s>0});var ya=y(()=>{"use strict"});function ba(s,r){if(!s)return"";let e=Sl[s.trim()];if(e)return a(e,r);for(let[t,i,n]of Tl){let o=s.trim().match(t);if(o){let d=n(o,r);return a(i,r).replace(/\{(\w+)\}/g,(p,_)=>d[_]??p)}}return s}var Sl,Tl,xa=y(()=>{"use strict";T();Sl={"Completed from dashboard button":"hist_note_button","Completed from the To-do list":"hist_note_todo","Completed by voice":"hist_note_voice","Completed from the notification":"hist_note_notification","Completed via NFC tag":"hist_note_nfc","Completed from the shopping list":"hist_note_shopping_list","Completed from a mirrored to-do list":"hist_note_todo_mirror","Skipped from notification":"hist_note_skipped_notification","Skipped from dashboard button":"hist_note_skipped_button","Sensor trigger activated":"hist_note_sensor_triggered","Initial value set during task creation":"hist_note_initial"},Tl=[[/^Auto-completed: sensor recovered \((.+)\)$/,"hist_note_auto_recovered",s=>({value:s[1]})],[/^Reset to (\d{4}-\d{2}-\d{2})$/,"hist_note_reset",(s,r)=>({date:O(s[1],r)})],[/^Trigger entity replaced: (.+) → (.+)$/,"hist_note_trigger_replaced",s=>({old:s[1],new:s[2]})],[/^Sensor trigger removed \(entity was: (.+)\)\. Schedule converted to (\w+)\.$/,"hist_note_trigger_removed",(s,r)=>({entity:s[1],schedule:a(s[2],r)})],[/^Entity (.+) removed from compound trigger; (\d+) conditions remain\.$/,"hist_note_compound_removed",s=>({entity:s[1],count:s[2]})]]});function wa(s){let r=e=>{let t=Q(e.timestamp);return Number.isNaN(t)?-1/0:t};return(s??[]).map((e,t)=>({entry:e,index:t,at:r(e)})).sort((e,t)=>t.at-e.at||t.index-e.index).map(e=>e.entry)}function Cl(s,r){return s.taskRef&&r.ref_no?`${s.taskRef}-${r.ref_no}`:null}function Il(s,r){let e=ai(r);return e.length>0?l`<div class="history-photos">
|
||||
${e.map(t=>l`<maintenance-history-photo .hass=${s} .docId=${t}></maintenance-history-photo>`)}
|
||||
</div>`:u}function Al(s,r){let e=r.lang,t=o=>C(o,e,{maximumFractionDigits:3}),i=o=>o==null?"":` (${o>=0?"+":""}${t(o)})`,n=xe(s);return n.length>0?l`<div class="history-readings">
|
||||
</div>`:u}function Rl(s,r){let e=r.lang,t=o=>C(o,e,{maximumFractionDigits:3}),i=o=>o==null?"":` (${o>=0?"+":""}${t(o)})`,n=xe(s);return n.length>0?l`<div class="history-readings">
|
||||
${n.map(o=>l`<span class="history-reading">
|
||||
<span class="history-reading-name">${o.name}</span>
|
||||
<span class="history-reading-value">${t(o.value)}${o.unit?` ${o.unit}`:""}${i(r.readingSlotDelta?.(s,o.id))}</span>
|
||||
@@ -4265,7 +4273,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
</div>`:s.reading_value!=null?l`<div class="history-readings"><span class="history-reading">
|
||||
<span class="history-reading-name">${a("reading_label",e)}</span>
|
||||
<span class="history-reading-value">${t(s.reading_value)}${r.readingUnit?` ${r.readingUnit}`:""}${i(r.readingDelta?.(s))}</span>
|
||||
</span></div>`:u}function wa(s,r,e={}){let t=r.lang,{compact:i=!1,showRef:n=!0,showBadges:o=!0,showEdit:d=!0}=e,p=r.openEdit,_=d&&!!p&&El.includes(s.type),m=typeof s.parts_cost=="number"?s.parts_cost:null,f=s.cost_basis==="use",x=f&&!!s.purchase;return l`
|
||||
</span></div>`:u}function ka(s,r,e={}){let t=r.lang,{compact:i=!1,showRef:n=!0,showBadges:o=!0,showEdit:d=!0}=e,p=r.openEdit,_=d&&!!p&&Al.includes(s.type),m=typeof s.parts_cost=="number"?s.parts_cost:null,f=s.cost_basis==="use",x=f&&!!s.purchase;return l`
|
||||
<div class="history-entry${i?" compact":""}">
|
||||
${i?u:l`<div class="history-icon ${s.type}">
|
||||
<ha-icon .icon=${yt[s.type]||"mdi:circle"}></ha-icon>
|
||||
@@ -4273,7 +4281,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
<div class="history-content">
|
||||
<div class="history-row">
|
||||
<strong>${a(s.type,t)}</strong>
|
||||
${n?fa(Sl(r,s),a("ref_number",t)):u}
|
||||
${n?va(Cl(r,s),a("ref_number",t)):u}
|
||||
${o&&s.phase_id?l`<span class="history-phase-badge">${r.phaseNames?.[s.phase_id]||s.phase_id}</span>`:u}
|
||||
${o&&s.auto?l`<span class="history-auto-badge">${a("history_auto",t)}</span>`:u}
|
||||
${_?l`<button class="history-edit-btn"
|
||||
@@ -4283,9 +4291,9 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
</button>`:u}
|
||||
</div>
|
||||
<div class="history-date">${ii(s.timestamp,t)}</div>
|
||||
${s.notes?l`<div class="history-notes">${ya(s.notes,t)}</div>`:u}
|
||||
${Tl(r.hass,s)}
|
||||
${Al(s,r)}
|
||||
${s.notes?l`<div class="history-notes">${ba(s.notes,t)}</div>`:u}
|
||||
${Il(r.hass,s)}
|
||||
${Rl(s,r)}
|
||||
${s.cost!=null||s.duration!=null||s.trigger_value!=null||m!=null?l`<div class="history-details">
|
||||
${s.cost!=null?x?l`<span>${a("history_purchase_stock",t).replace("{amount}",J(s.cost,r.currencySymbol,t))}</span>`:s.cost<0?l`<span class="history-credit">${a("cost_kind_credit",t)}: ${J(-s.cost,r.currencySymbol,t)}</span>`:l`<span>${a("cost",t)}: ${J(s.cost,r.currencySymbol,t)}</span>`:u}
|
||||
${m!=null?l`<span title=${a(f?"history_parts_counted_hint":"history_parts_info_hint",t)}>${a(f?"history_parts_counted":"history_parts_info",t).replace("{amount}",J(m,r.currencySymbol,t))}</span>`:u}
|
||||
@@ -4294,23 +4302,23 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
</div>`:u}
|
||||
</div>
|
||||
</div>
|
||||
`}var El,ka=y(()=>{"use strict";I();T();gr();oi();Cr();je();va();ba();Z();El=["completed","reset","skipped"]});function Pt(s){return s.archived?"archived":s.is_done?"done":s.status||"ok"}function Ir(s,r){return a(s==="done"?"completed":s,r)}function Si(s){let r=Pt(s);return r==="done"?Cl:Mi[r]||"var(--disabled-color, #9e9e9e)"}function Il(s){return yt[s==="done"?"completed":s]||"mdi:circle-medium"}function $a(s,r,e="pill"){let t=Pt(s),i=Ir(t,r);return e==="chip"?l`<span class="status-chip ${t}">${i}</span>`:l`<span class="status-badge ${t}" role="img" title="${i}" aria-label="${i}"><ha-icon icon="${Il(t)}"></ha-icon><span class="status-label">${i}</span></span>`}var Cl,Rr=y(()=>{"use strict";I();T();Kt();Cl="var(--maint-done-color, #78909c)"});var Ti,Ea=y(()=>{"use strict";Ti=class{constructor(){this._handle=null}schedule(r,e=4e3){this.clear(),this._handle=setTimeout(()=>{this._handle=null,r()},e)}clear(){this._handle!==null&&(clearTimeout(this._handle),this._handle=null)}get pending(){return this._handle!==null}}});function A(s){return s.toFixed(1)}var Pr=y(()=>{"use strict";T();Z()});function Sa(s,r){let e=s.interval_analysis,t=e?.weibull_beta,i=e?.weibull_eta;if(t==null||i==null||i<=0)return u;let n=s.interval_days??0,o=s.suggested_interval??n;return l`
|
||||
`}var Al,$a=y(()=>{"use strict";I();T();fr();oi();Ir();je();ya();xa();Z();Al=["completed","reset","skipped"]});function Pt(s){return s.archived?"archived":s.is_done?"done":s.status||"ok"}function Rr(s,r){return a(s==="done"?"completed":s,r)}function Si(s){let r=Pt(s);return r==="done"?Pl:Mi[r]||"var(--disabled-color, #9e9e9e)"}function Ll(s){return yt[s==="done"?"completed":s]||"mdi:circle-medium"}function Ea(s,r,e="pill"){let t=Pt(s),i=Rr(t,r);return e==="chip"?l`<span class="status-chip ${t}">${i}</span>`:l`<span class="status-badge ${t}" role="img" title="${i}" aria-label="${i}"><ha-icon icon="${Ll(t)}"></ha-icon><span class="status-label">${i}</span></span>`}var Pl,Pr=y(()=>{"use strict";I();T();Kt();Pl="var(--maint-done-color, #78909c)"});var Ti,Sa=y(()=>{"use strict";Ti=class{constructor(){this._handle=null}schedule(r,e=4e3){this.clear(),this._handle=setTimeout(()=>{this._handle=null,r()},e)}clear(){this._handle!==null&&(clearTimeout(this._handle),this._handle=null)}get pending(){return this._handle!==null}}});function A(s){return s.toFixed(1)}var Lr=y(()=>{"use strict";T();Z()});function Ta(s,r){let e=s.interval_analysis,t=e?.weibull_beta,i=e?.weibull_eta;if(t==null||i==null||i<=0)return u;let n=s.interval_days??0,o=s.suggested_interval??n;return l`
|
||||
<div class="weibull-section">
|
||||
<div class="weibull-title">
|
||||
<ha-svg-icon aria-hidden="true" path="M3,14L3.5,14.07L8.07,9.5C7.89,8.85 8.06,8.11 8.59,7.59C9.37,6.8 10.63,6.8 11.41,7.59C11.94,8.11 12.11,8.85 11.93,9.5L14.5,12.07L15,12C15.18,12 15.35,12 15.5,12.07L19.07,8.5C19,8.35 19,8.18 19,8A2,2 0 0,1 21,6A2,2 0 0,1 23,8A2,2 0 0,1 21,10C20.82,10 20.65,10 20.5,9.93L16.93,13.5C17,13.65 17,13.82 17,14A2,2 0 0,1 15,16A2,2 0 0,1 13,14L13.07,13.5L10.5,10.93C10.18,11 9.82,11 9.5,10.93L4.93,15.5L5,16A2,2 0 0,1 3,18A2,2 0 0,1 1,16A2,2 0 0,1 3,14Z"></ha-svg-icon>
|
||||
${a("weibull_reliability_curve",r)}
|
||||
${Rl(t,r)}
|
||||
${Nl(t,r)}
|
||||
</div>
|
||||
${Pl(t,i,n,o,r)}
|
||||
${Ll(e,r)}
|
||||
${e?.confidence_interval_low!=null?Nl(e,s,r):u}
|
||||
${Hl(t,i,n,o,r)}
|
||||
${ql(e,r)}
|
||||
${e?.confidence_interval_low!=null?Ol(e,s,r):u}
|
||||
</div>
|
||||
`}function Rl(s,r){let e,t,i;return s<.8?(e="early_failures",t="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z",i="beta_early_failures"):s<=1.2?(e="random_failures",t="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",i="beta_random_failures"):s<=3.5?(e="wear_out",t="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",i="beta_wear_out"):(e="highly_predictable",t="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",i="beta_highly_predictable"),l`
|
||||
`}function Nl(s,r){let e,t,i;return s<.8?(e="early_failures",t="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z",i="beta_early_failures"):s<=1.2?(e="random_failures",t="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",i="beta_random_failures"):s<=3.5?(e="wear_out",t="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",i="beta_wear_out"):(e="highly_predictable",t="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",i="beta_highly_predictable"),l`
|
||||
<span class="beta-badge ${e}">
|
||||
<ha-svg-icon path="${t}"></ha-svg-icon>
|
||||
${a(i,r)} (\u03B2=${C(s,r,2)})
|
||||
</span>
|
||||
`}function Pl(s,r,e,t,i){let w=Math.max(e,t,r,1)*1.3,k=50,H=[];for(let q=0;q<=k;q++){let z=q/k*w,ct=1-Math.exp(-Math.pow(z/r,s)),dt=32+z/w*260,Ai=136-ct*128;H.push([dt,Ai])}let L=H.map(([q,z])=>`${A(q)},${A(z)}`).join(" "),M="M32,136 "+H.map(([q,z])=>`L${A(q)},${A(z)}`).join(" ")+` L${A(H[k][0])},136 Z`,B=32+e/w*260,W=1-Math.exp(-Math.pow(e/r,s)),b=136-W*128,le=C((1-W)*100,i,0),Se=32+t/w*260,me=[0,.25,.5,.75,1];return l`
|
||||
`}function Hl(s,r,e,t,i){let w=Math.max(e,t,r,1)*1.3,k=50,H=[];for(let q=0;q<=k;q++){let z=q/k*w,ct=1-Math.exp(-Math.pow(z/r,s)),dt=32+z/w*260,Ai=136-ct*128;H.push([dt,Ai])}let L=H.map(([q,z])=>`${A(q)},${A(z)}`).join(" "),M="M32,136 "+H.map(([q,z])=>`L${A(q)},${A(z)}`).join(" ")+` L${A(H[k][0])},136 Z`,B=32+e/w*260,W=1-Math.exp(-Math.pow(e/r,s)),b=136-W*128,le=C((1-W)*100,i,0),Se=32+t/w*260,me=[0,.25,.5,.75,1];return l`
|
||||
<div class="weibull-chart">
|
||||
<svg viewBox="0 0 ${300} ${160}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${a("chart_weibull",i)}">
|
||||
${me.map(q=>{let z=136-q*128;return Ve`
|
||||
@@ -4353,7 +4361,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
${e>0?l`<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color, #03a9f4); opacity:0.5"></span> ${a("current_interval_marker",i)}</span>`:u}
|
||||
${t>0&&t!==e?l`<span class="legend-item"><span class="legend-swatch" style="background:var(--success-color, #4caf50)"></span> ${a("recommended_marker",i)}</span>`:u}
|
||||
</div>
|
||||
`}function Ll(s,r){return l`
|
||||
`}function ql(s,r){return l`
|
||||
<div class="weibull-info-row">
|
||||
<div class="weibull-info-item">
|
||||
<span>${a("characteristic_life",r)}</span>
|
||||
@@ -4366,7 +4374,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
</div>
|
||||
`:u}
|
||||
</div>
|
||||
`}function Nl(s,r,e){let t=s.confidence_interval_low,i=s.confidence_interval_high,n=r.suggested_interval??r.interval_days??0,o=r.interval_days??0,d=Math.max(0,t-5),_=i+5-d,m=(t-d)/_*100,f=(i-t)/_*100,x=(n-d)/_*100,w=o>0?(o-d)/_*100:-1;return l`
|
||||
`}function Ol(s,r,e){let t=s.confidence_interval_low,i=s.confidence_interval_high,n=r.suggested_interval??r.interval_days??0,o=r.interval_days??0,d=Math.max(0,t-5),_=i+5-d,m=(t-d)/_*100,f=(i-t)/_*100,x=(n-d)/_*100,w=o>0?(o-d)/_*100:-1;return l`
|
||||
<div class="confidence-range">
|
||||
<div class="confidence-range-title">
|
||||
${a("confidence_interval",e)}: ${n} ${a("days",e)} (${t}\u2013${i})
|
||||
@@ -4381,7 +4389,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
<span class="confidence-text high">${a("confidence_aggressive",e)} (${i}${a("days",e).charAt(0)})</span>
|
||||
</div>
|
||||
</div>
|
||||
`}var Ta=y(()=>{"use strict";I();T();Pr()});function Aa(s,r,e){let t=s.degradation_trend!=null&&s.degradation_trend!=="insufficient_data",i=s.days_until_threshold!=null,n=s.environmental_factor!=null&&s.environmental_factor!==1;if(!t&&!i&&!n)return u;let o=s.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":s.degradation_trend==="falling"?"M16,18L18.29,15.71L13.41,10.83L9.41,14.83L2,7.41L3.41,6L9.41,12L13.41,8L19.71,14.29L22,12V18H16Z":"M22,12L18,8V11H3V13H18V16L22,12Z";return l`
|
||||
`}var Aa=y(()=>{"use strict";I();T();Lr()});function Ca(s,r,e){let t=s.degradation_trend!=null&&s.degradation_trend!=="insufficient_data",i=s.days_until_threshold!=null,n=s.environmental_factor!=null&&s.environmental_factor!==1;if(!t&&!i&&!n)return u;let o=s.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":s.degradation_trend==="falling"?"M16,18L18.29,15.71L13.41,10.83L9.41,14.83L2,7.41L3.41,6L9.41,12L13.41,8L19.71,14.29L22,12V18H16Z":"M22,12L18,8V11H3V13H18V16L22,12Z";return l`
|
||||
<div class="prediction-section">
|
||||
${s.sensor_prediction_urgency?l`
|
||||
<div class="prediction-urgency-banner">
|
||||
@@ -4417,12 +4425,12 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
<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">${a("environmental_adjustment",r)}</span>
|
||||
<span class="prediction-value">${C(s.environmental_factor,r,2)}x</span>
|
||||
${s.environmental_entity?l`<span class="prediction-entity entity-link" @click=${d=>Bs(d,s.environmental_entity)}>${s.environmental_entity}</span>`:u}
|
||||
${s.environmental_entity?l`<span class="prediction-entity entity-link" @click=${d=>Ws(d,s.environmental_entity)}>${s.environmental_entity}</span>`:u}
|
||||
</div>
|
||||
`:u}
|
||||
</div>
|
||||
</div>
|
||||
`}var Ca=y(()=>{"use strict";I();T()});function Ia(s,r,e,t){let i=Math.max(s||1,r);return l`
|
||||
`}var Ia=y(()=>{"use strict";I();T()});function Ra(s,r,e,t){let i=Math.max(s||1,r);return l`
|
||||
<div class="interval-comparison">
|
||||
<div class="interval-bar">
|
||||
<div class="interval-label">
|
||||
@@ -4440,7 +4448,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
style="width: ${Math.min(r/i*100,100)}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
`}var Ra=y(()=>{"use strict";I();T()});function La(){return Number(ye().slice(5,7))-1}function Na(s,r,e){if(!e.seasonal||!s.seasonal_factor||s.seasonal_factor===1)return u;let t=Pa.map(d=>a(d,r)),i=La(),n=s.seasonal_factors||s.interval_analysis?.seasonal_factors||null,o=n&&n.length===12?n:t.map((d,p)=>{let _=s.seasonal_factor||1,m=Math.sin((p-6)*Math.PI/6)*.3;return Math.max(.7,Math.min(1.3,_+m))});return l`
|
||||
`}var Pa=y(()=>{"use strict";I();T()});function Na(){return Number(ye().slice(5,7))-1}function Ha(s,r,e){if(!e.seasonal||!s.seasonal_factor||s.seasonal_factor===1)return u;let t=La.map(d=>a(d,r)),i=Na(),n=s.seasonal_factors||s.interval_analysis?.seasonal_factors||null,o=n&&n.length===12?n:t.map((d,p)=>{let _=s.seasonal_factor||1,m=Math.sin((p-6)*Math.PI/6)*.3;return Math.max(.7,Math.min(1.3,_+m))});return l`
|
||||
<div class="seasonal-card-compact">
|
||||
<h4>${a("seasonal_awareness",r)}</h4>
|
||||
<div class="seasonal-mini-chart">
|
||||
@@ -4457,7 +4465,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
<span class="legend-item"><span class="dot high"></span> ${a("longer",r)}</span>
|
||||
</div>
|
||||
</div>
|
||||
`}function Ha(s,r){return Hl(s,r)}function Hl(s,r){let e=s.seasonal_factors??s.interval_analysis?.seasonal_factors;if(!e||e.length!==12)return u;let t=s.interval_analysis?.seasonal_reason,i=La(),n=300,o=100,d=8,_=o-d-4,m=Math.max(...e,1.5),f=n/12,x=f*.65,w=d+_-1/m*_;return l`
|
||||
`}function qa(s,r){return Dl(s,r)}function Dl(s,r){let e=s.seasonal_factors??s.interval_analysis?.seasonal_factors;if(!e||e.length!==12)return u;let t=s.interval_analysis?.seasonal_reason,i=Na(),n=300,o=100,d=8,_=o-d-4,m=Math.max(...e,1.5),f=n/12,x=f*.65,w=d+_-1/m*_;return l`
|
||||
<div class="seasonal-chart">
|
||||
<div class="seasonal-chart-title">
|
||||
<ha-svg-icon aria-hidden="true" path="M17.75 4.09L15.22 6.03L16.13 9.09L13.5 7.28L10.87 9.09L11.78 6.03L9.25 4.09L12.44 4L13.5 1L14.56 4L17.75 4.09M21.25 11L19.61 12.25L20.2 14.23L18.5 13.06L16.8 14.23L17.39 12.25L15.75 11L17.81 10.95L18.5 9L19.19 10.95L21.25 11M18.97 15.95C19.8 15.87 20.69 17.05 20.16 17.8C19.84 18.25 19.5 18.67 19.08 19.07C15.17 23 8.84 23 4.94 19.07C1.03 15.17 1.03 8.83 4.94 4.93C5.34 4.53 5.76 4.17 6.21 3.85C6.96 3.32 8.14 4.21 8.06 5.04C7.79 7.9 8.75 10.87 10.95 13.06C13.14 15.26 16.1 16.22 18.97 15.95Z"></ha-svg-icon>
|
||||
@@ -4474,13 +4482,13 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
`})}
|
||||
</svg>
|
||||
<div class="seasonal-labels">
|
||||
${Pa.map((k,H)=>l`<span class="seasonal-label ${H===i?"active-month":""}">${a(k,r)}</span>`)}
|
||||
${La.map((k,H)=>l`<span class="seasonal-label ${H===i?"active-month":""}">${a(k,r)}</span>`)}
|
||||
</div>
|
||||
</div>
|
||||
`}var Pa,qa=y(()=>{"use strict";I();T();Pr();Z();Pa=["month_jan","month_feb","month_mar","month_apr","month_may","month_jun","month_jul","month_aug","month_sep","month_oct","month_nov","month_dec"]});var P,Oa=y(()=>{"use strict";I();F();T();ze();ia();fi();Z();br();yr();Ar();ir();je();Cr();ka();Rr();Tt();wt();vi();Ea();Ta();Ca();Ra();tt();qa();P=class extends S{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._taskId=null;this._task=null;this._objectName="";this._taskRef=null;this._busy=!1;this._error="";this._showSkip=!1;this._showReset=!1;this._showPostpone=!1;this._showDetails=!1;this._showAdaptive=!1;this._skipReason="";this._resetDate="";this._postponeDate="";this._features={adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1,places:!1};this._toast="";this._toastTimer=new Ti;this._access=Me;this._currencySymbol="";this._partsCostMode="purchase";this._loadSeq=0}get _lang(){return N(this.hass)}async openFor(e,t){(e!==this._entryId||t!==this._taskId)&&(this._task=null),this._entryId=e,this._taskId=t,this._error="",this._showSkip=!1,this._showReset=!1,this._showPostpone=!1,this._showAdaptive=!1,this._skipReason="",this._postponeDate="",this._resetDate=ye(),this._open=!0,await Promise.all([this._loadTask(),this._loadFeatures()])}async _loadFeatures(){let e=await se(this.hass);this._features={...this._features,...e.features},this._access=e.access,this._currencySymbol=De(e.budget??void 0),ei(e.budget??void 0),this._partsCostMode=e.partsCostMode}close(){this._loadSeq++,this._open=!1,this._task=null,this._error="",this._toastTimer.clear(),this._toast=""}_showToast(e,t){this._toast=e,this._toastTimer.schedule(()=>{this._toast=""},t)}async _loadTask(){let e=this._entryId,t=this._taskId;if(!e||!t)return;let i=++this._loadSeq,n="",o=await D(this,{type:"maintenance_supporter/object",entry_id:e},{onError:p=>{n=p}});if(i!==this._loadSeq)return;if(o===void 0){this._error=n;return}this._objectName=o?.object?.name||"";let d=(o?.tasks||[]).find(p=>p.id===t);this._task=d??null,this._taskRef=ga(o?.object,d),d||(this._error=a("ws_err_not_found",this._lang))}_runWs(e){return this._error="",D(this,e,{busy:t=>{this._busy=t},onError:t=>{this._error=t}})}_notifyChanged(e){this.dispatchEvent(new CustomEvent("task-action-fired",{detail:{entry_id:this._entryId,task_id:this._taskId,action:e},bubbles:!0,composed:!0}))}_onComplete(){!this._entryId||!this._taskId||!this._task||Promise.resolve().then(()=>(oe(),ue)).then(async({openCompleteDialog:e})=>{let t=this._task,i=[];try{i=(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0})).objects||[]}catch{}e(ra({entryId:this._entryId,taskId:this._taskId,taskName:t.name,task:t,objects:i,lang:this._lang,features:this._features,currencySymbol:this._currencySymbol,partsCostMode:this._partsCostMode}))&&(this._notifyChanged("complete"),this.close())})}async _onSkipConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/skip",entry_id:this._entryId,task_id:this._taskId,reason:this._skipReason.trim()||null})!==void 0&&(this._notifyChanged("skip"),this.close())}async _onResetConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/reset",entry_id:this._entryId,task_id:this._taskId,date:this._resetDate||void 0})!==void 0&&(this._notifyChanged("reset"),this.close())}async _onPostponeConfirm(){if(!this._entryId||!this._taskId||!this._postponeDate)return;await this._runWs({type:"maintenance_supporter/task/postpone",entry_id:this._entryId,task_id:this._taskId,until:this._postponeDate})!==void 0&&(this._notifyChanged("postpone"),this.close())}async _onSnooze(){if(!this._entryId||!this._taskId)return;let e=await this._runWs({type:"maintenance_supporter/task/snooze",entry_id:this._entryId,task_id:this._taskId});e!==void 0&&(this._notifyChanged("snooze"),this.dispatchEvent(new CustomEvent("hass-notification",{detail:{message:ta(e,this._lang)},bubbles:!0,composed:!0})),this.close())}_onEdit(){!this._entryId||!this._taskId||Promise.resolve().then(()=>(oe(),ue)).then(({openEditTaskDialog:e})=>{e(this._entryId,this._taskId),this.close()})}_onQr(){!this._entryId||!this._taskId||!this._task||Promise.resolve().then(()=>(oe(),ue)).then(({openQrDialog:e})=>{e({entry_id:this._entryId,task_id:this._taskId,task_name:this._task.name,object_name:this._objectName}),this.close()})}async _onDelete(){if(!this._entryId||!this._taskId||!await Ue(this.hass,{title:a("delete",this._lang),message:a("delete_task_confirm",this._lang),confirmText:a("delete",this._lang),danger:!0}))return;await this._runWs({type:"maintenance_supporter/task/delete",entry_id:this._entryId,task_id:this._taskId})!==void 0&&(this._notifyChanged("delete"),this.close())}async _onArchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/archive",entry_id:this._entryId,task_id:this._taskId})!==void 0&&
Line truncated
|
||||
`}var La,Oa=y(()=>{"use strict";I();T();Lr();Z();La=["month_jan","month_feb","month_mar","month_apr","month_may","month_jun","month_jul","month_aug","month_sep","month_oct","month_nov","month_dec"]});var P,Da=y(()=>{"use strict";I();F();T();ze();ra();fi();Z();xr();br();Cr();rr();je();Ir();$a();Pr();Tt();wt();vi();Sa();Aa();Ia();Pa();tt();Oa();P=class extends S{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._taskId=null;this._task=null;this._objectName="";this._taskRef=null;this._busy=!1;this._error="";this._showSkip=!1;this._showReset=!1;this._showPostpone=!1;this._showDetails=!1;this._showAdaptive=!1;this._skipReason="";this._resetDate="";this._postponeDate="";this._features={adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1,places:!1};this._toast="";this._toastTimer=new Ti;this._access=Me;this._currencySymbol="";this._partsCostMode="purchase";this._loadSeq=0}get _lang(){return N(this.hass)}async openFor(e,t){(e!==this._entryId||t!==this._taskId)&&(this._task=null),this._entryId=e,this._taskId=t,this._error="",this._showSkip=!1,this._showReset=!1,this._showPostpone=!1,this._showAdaptive=!1,this._skipReason="",this._postponeDate="",this._resetDate=ye(),this._open=!0,await Promise.all([this._loadTask(),this._loadFeatures()])}async _loadFeatures(){let e=await se(this.hass);this._features={...this._features,...e.features},this._access=e.access,this._currencySymbol=De(e.budget??void 0),ei(e.budget??void 0),this._partsCostMode=e.partsCostMode}close(){this._loadSeq++,this._open=!1,this._task=null,this._error="",this._toastTimer.clear(),this._toast=""}_showToast(e,t){this._toast=e,this._toastTimer.schedule(()=>{this._toast=""},t)}async _loadTask(){let e=this._entryId,t=this._taskId;if(!e||!t)return;let i=++this._loadSeq,n="",o=await D(this,{type:"maintenance_supporter/object",entry_id:e},{onError:p=>{n=p}});if(i!==this._loadSeq)return;if(o===void 0){this._error=n;return}this._objectName=o?.object?.name||"";let d=(o?.tasks||[]).find(p=>p.id===t);this._task=d??null,this._taskRef=fa(o?.object,d),d||(this._error=a("ws_err_not_found",this._lang))}_runWs(e){return this._error="",D(this,e,{busy:t=>{this._busy=t},onError:t=>{this._error=t}})}_notifyChanged(e){this.dispatchEvent(new CustomEvent("task-action-fired",{detail:{entry_id:this._entryId,task_id:this._taskId,action:e},bubbles:!0,composed:!0}))}_onComplete(){!this._entryId||!this._taskId||!this._task||Promise.resolve().then(()=>(oe(),ue)).then(async({openCompleteDialog:e})=>{let t=this._task,i=[];try{i=(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0})).objects||[]}catch{}e(sa({entryId:this._entryId,taskId:this._taskId,taskName:t.name,task:t,objects:i,lang:this._lang,features:this._features,currencySymbol:this._currencySymbol,partsCostMode:this._partsCostMode}))&&(this._notifyChanged("complete"),this.close())})}async _onSkipConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/skip",entry_id:this._entryId,task_id:this._taskId,reason:this._skipReason.trim()||null})!==void 0&&(this._notifyChanged("skip"),this.close())}async _onResetConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/reset",entry_id:this._entryId,task_id:this._taskId,date:this._resetDate||void 0})!==void 0&&(this._notifyChanged("reset"),this.close())}async _onPostponeConfirm(){if(!this._entryId||!this._taskId||!this._postponeDate)return;await this._runWs({type:"maintenance_supporter/task/postpone",entry_id:this._entryId,task_id:this._taskId,until:this._postponeDate})!==void 0&&(this._notifyChanged("postpone"),this.close())}async _onSnooze(){if(!this._entryId||!this._taskId)return;let e=await this._runWs({type:"maintenance_supporter/task/snooze",entry_id:this._entryId,task_id:this._taskId});e!==void 0&&(this._notifyChanged("snooze"),this.dispatchEvent(new CustomEvent("hass-notification",{detail:{message:ia(e,this._lang)},bubbles:!0,composed:!0})),this.close())}_onEdit(){!this._entryId||!this._taskId||Promise.resolve().then(()=>(oe(),ue)).then(({openEditTaskDialog:e})=>{e(this._entryId,this._taskId),this.close()})}_onQr(){!this._entryId||!this._taskId||!this._task||Promise.resolve().then(()=>(oe(),ue)).then(({openQrDialog:e})=>{e({entry_id:this._entryId,task_id:this._taskId,task_name:this._task.name,object_name:this._objectName}),this.close()})}async _onDelete(){if(!this._entryId||!this._taskId||!await Ue(this.hass,{title:a("delete",this._lang),message:a("delete_task_confirm",this._lang),confirmText:a("delete",this._lang),danger:!0}))return;await this._runWs({type:"maintenance_supporter/task/delete",entry_id:this._entryId,task_id:this._taskId})!==void 0&&(this._notifyChanged("delete"),this.close())}async _onArchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/archive",entry_id:this._entryId,task_id:this._taskId})!==void 0&&
Line truncated
|
||||
<div class="recommendation-card">
|
||||
<h4>${a("suggested_interval",t)}</h4>
|
||||
${Ia(e.interval_days,e.suggested_interval,e.interval_confidence||"medium",t)}
|
||||
${Ra(e.interval_days,e.suggested_interval,e.interval_confidence||"medium",t)}
|
||||
<div class="recommendation-actions">
|
||||
${we(this.hass?.user,this._access)?l`<button class="btn primary qa-apply-suggestion"
|
||||
@click=${this._applySuggestion} ?disabled=${this._busy}>
|
||||
@@ -4500,14 +4508,14 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
<div class="adaptive-stack">
|
||||
${this._toast?l`<div class="toast">${this._toast}</div>`:u}
|
||||
${i?this._renderRecommendation(e):u}
|
||||
${n?Aa(e,t,this._features):u}
|
||||
${o?Sa(e,t):u}
|
||||
${n?Ca(e,t,this._features):u}
|
||||
${o?Ta(e,t):u}
|
||||
${d?l`
|
||||
${Na(e,t,this._features)}
|
||||
${e.seasonal_factors?.length===12||e.interval_analysis?.seasonal_factors?.length===12?Ha(e,t):u}
|
||||
${Ha(e,t,this._features)}
|
||||
${e.seasonal_factors?.length===12||e.interval_analysis?.seasonal_factors?.length===12?qa(e,t):u}
|
||||
`:u}
|
||||
</div>
|
||||
`}_renderDetails(e){let t=this._lang,i=e.history||[],n=e.history_count??i.length,o=xa(i).slice(0,20);return l`
|
||||
`}_renderDetails(e){let t=this._lang,i=e.history||[],n=e.history_count??i.length,o=wa(i).slice(0,20);return l`
|
||||
<div class="details">
|
||||
<div class="stats-grid">
|
||||
<div class="stat">
|
||||
@@ -4529,7 +4537,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
</div>
|
||||
${i.length===0?l`<div class="history-empty">${a("history_empty",t)}</div>`:l`
|
||||
<div class="history-list">
|
||||
${o.map(d=>wa(d,{lang:t,hass:this.hass,currencySymbol:this._currencySymbol,openEdit:we(this.hass?.user,this._access)?p=>this._onEditHistoryEntry(p):void 0,readingUnit:e.reading_unit,readingSlotDelta:(p,_)=>Zs(i,p,_),taskRef:this._taskRef},{compact:!0}))}
|
||||
${o.map(d=>ka(d,{lang:t,hass:this.hass,currencySymbol:this._currencySymbol,openEdit:we(this.hass?.user,this._access)?p=>this._onEditHistoryEntry(p):void 0,readingUnit:e.reading_unit,readingSlotDelta:(p,_)=>Js(i,p,_),taskRef:this._taskRef},{compact:!0}))}
|
||||
${n>o.length?l`<div class="history-more">… +${n-o.length} ${a("older_entries",t)}</div>`:u}
|
||||
</div>
|
||||
`}
|
||||
@@ -4540,7 +4548,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
<div class="title">
|
||||
<span class="status-dot" style="background: ${Si(t)}"></span>
|
||||
<span class="task-name">${t.name}</span>
|
||||
${$a(t,e)}
|
||||
${Ea(t,e)}
|
||||
</div>
|
||||
<div class="object">
|
||||
<button class="link-inline" @click=${()=>{this._entryId&&Promise.resolve().then(()=>(oe(),ue)).then(({openObjectQuickActions:o})=>{o(this._entryId),this.close()})}}>${this._objectName}</button>
|
||||
@@ -4548,7 +4556,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
<div class="quick-info">
|
||||
${t.next_due?l`<span><strong>${a("next_due",e)}:</strong> ${O(t.next_due,e)}</span>`:u}
|
||||
${t.last_performed?l`<span><strong>${a("last_performed",e)}:</strong> ${O(t.last_performed,e)}</span>`:u}
|
||||
${t.schedule?.kind&&!["manual","one_time"].includes(t.schedule.kind)||t.interval_days!=null?l`<span><strong>${a("interval",e)}:</strong> ${Us(t,e)}</span>`:u}
|
||||
${t.schedule?.kind&&!["manual","one_time"].includes(t.schedule.kind)||t.interval_days!=null?l`<span><strong>${a("interval",e)}:</strong> ${Bs(t,e)}</span>`:u}
|
||||
${It(t)?l`<span><strong>${a("phase_current",e)}:</strong> ${It(t)}</span>`:u}
|
||||
</div>
|
||||
${t.notes?l`<div class="notes-body">${Ei(t.notes)}</div>`:u}
|
||||
@@ -4836,7 +4844,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
.weibull-section, .seasonal-card-compact { max-width: 100%; }
|
||||
.weibull-chart svg { max-width: 100%; height: auto; }
|
||||
.details-toggle { gap: 12px; flex-wrap: wrap; }
|
||||
`],c([v({attribute:!1})],P.prototype,"hass",2),c([h()],P.prototype,"_open",2),c([h()],P.prototype,"_entryId",2),c([h()],P.prototype,"_taskId",2),c([h()],P.prototype,"_task",2),c([h()],P.prototype,"_objectName",2),c([h()],P.prototype,"_taskRef",2),c([h()],P.prototype,"_busy",2),c([h()],P.prototype,"_error",2),c([h()],P.prototype,"_showSkip",2),c([h()],P.prototype,"_showReset",2),c([h()],P.prototype,"_showPostpone",2),c([h()],P.prototype,"_showDetails",2),c([h()],P.prototype,"_showAdaptive",2),c([h()],P.prototype,"_skipReason",2),c([h()],P.prototype,"_resetDate",2),c([h()],P.prototype,"_postponeDate",2),c([h()],P.prototype,"_features",2),c([h()],P.prototype,"_toast",2),c([h()],P.prototype,"_access",2),c([h()],P.prototype,"_partsCostMode",2);customElements.get("maintenance-task-quick-actions-dialog")||customElements.define("maintenance-task-quick-actions-dialog",P)});var ne,Da=y(()=>{"use strict";I();Er();Ar();F();T();ze();Rr();Tt();wt();vi();fi();ne=class extends S{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._data=null;this._busy=!1;this._error="";this._access=Me}get _lang(){return N(this.hass)}async openFor(e){this._entryId=e,this._error="",this._open=!0,await Promise.all([this._load(),se(this.hass).then(t=>{this._access=t.access})])}close(){this._open=!1,this._data=null,this._error=""}async _load(){if(!this._entryId)return;let e=await D(this,{type:"maintenance_supporter/object",entry_id:this._entryId},{onError:t=>{this._error=t}});e!==void 0&&(this._data=e)}_runWs(e){return this._error="",D(this,e,{busy:t=>{this._busy=t},onError:t=>{this._error=t}})}_onEditObject(){!this._entryId||!this._data||Promise.resolve().then(()=>(oe(),ue)).then(({openEditObjectDialog:e})=>{e(this._entryId,this._data.object),this.close()})}_onAddTask(){this._entryId&&Promise.resolve().then(()=>(oe(),ue)).then(({openCreateTaskDialog:e})=>{e(this._entryId),this.close()})}async _onDelete(){if(!this._entryId||!this._data||!await Ue(this.hass,{title:a("delete",this._lang),message:a("delete_object_confirm",this._lang),confirmText:a("delete",this._lang),danger:!0}))return;let t=this._entryId;await this._runWs({type:"maintenance_supporter/object/delete",entry_id:t})!==void 0&&(this.dispatchEvent(new CustomEvent("object-deleted",{detail:{entry_id:t},bubbles:!0,composed:!0})),this.close())}async _onArchiveObject(){if(!this._entryId||!this._data)return;let e=!!this._data.object.archived;if(!e&&!await Ue(this.hass,{title:a("archive_object",this._lang),message:a("confirm_archive_object",this._lang),confirmText:a("archive_object",this._lang)}))return;let t=this._entryId;await this._runWs({type:e?"maintenance_supporter/object/unarchive":"maintenance_supporter/object/archive",entry_id:t})!==void 0&&(this.dispatchEvent(new CustomEvent("object-changed",{detail:{entry_id:t},bubbles:!0,composed:!0})),this.close())}_onTaskClick(e){this._entryId&&Promise.resolve().then(()=>(oe(),ue)).then(({openTaskQuickActions:t})=>{t(this._entryId,e)})}render(){if(!this._open)return u;let e=this._lang,t=this._data,i=t?.object,n=t?.tasks||[],o=we(this.hass?.user,this._access);return at(()=>this.close(),l`
|
||||
`],c([v({attribute:!1})],P.prototype,"hass",2),c([h()],P.prototype,"_open",2),c([h()],P.prototype,"_entryId",2),c([h()],P.prototype,"_taskId",2),c([h()],P.prototype,"_task",2),c([h()],P.prototype,"_objectName",2),c([h()],P.prototype,"_taskRef",2),c([h()],P.prototype,"_busy",2),c([h()],P.prototype,"_error",2),c([h()],P.prototype,"_showSkip",2),c([h()],P.prototype,"_showReset",2),c([h()],P.prototype,"_showPostpone",2),c([h()],P.prototype,"_showDetails",2),c([h()],P.prototype,"_showAdaptive",2),c([h()],P.prototype,"_skipReason",2),c([h()],P.prototype,"_resetDate",2),c([h()],P.prototype,"_postponeDate",2),c([h()],P.prototype,"_features",2),c([h()],P.prototype,"_toast",2),c([h()],P.prototype,"_access",2),c([h()],P.prototype,"_partsCostMode",2);customElements.get("maintenance-task-quick-actions-dialog")||customElements.define("maintenance-task-quick-actions-dialog",P)});var ne,ja=y(()=>{"use strict";I();Sr();Cr();F();T();ze();Pr();Tt();wt();vi();fi();ne=class extends S{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._data=null;this._busy=!1;this._error="";this._access=Me}get _lang(){return N(this.hass)}async openFor(e){this._entryId=e,this._error="",this._open=!0,await Promise.all([this._load(),se(this.hass).then(t=>{this._access=t.access})])}close(){this._open=!1,this._data=null,this._error=""}async _load(){if(!this._entryId)return;let e=await D(this,{type:"maintenance_supporter/object",entry_id:this._entryId},{onError:t=>{this._error=t}});e!==void 0&&(this._data=e)}_runWs(e){return this._error="",D(this,e,{busy:t=>{this._busy=t},onError:t=>{this._error=t}})}_onEditObject(){!this._entryId||!this._data||Promise.resolve().then(()=>(oe(),ue)).then(({openEditObjectDialog:e})=>{e(this._entryId,this._data.object),this.close()})}_onAddTask(){this._entryId&&Promise.resolve().then(()=>(oe(),ue)).then(({openCreateTaskDialog:e})=>{e(this._entryId),this.close()})}async _onDelete(){if(!this._entryId||!this._data||!await Ue(this.hass,{title:a("delete",this._lang),message:a("delete_object_confirm",this._lang),confirmText:a("delete",this._lang),danger:!0}))return;let t=this._entryId;await this._runWs({type:"maintenance_supporter/object/delete",entry_id:t})!==void 0&&(this.dispatchEvent(new CustomEvent("object-deleted",{detail:{entry_id:t},bubbles:!0,composed:!0})),this.close())}async _onArchiveObject(){if(!this._entryId||!this._data)return;let e=!!this._data.object.archived;if(!e&&!await Ue(this.hass,{title:a("archive_object",this._lang),message:a("confirm_archive_object",this._lang),confirmText:a("archive_object",this._lang)}))return;let t=this._entryId;await this._runWs({type:e?"maintenance_supporter/object/unarchive":"maintenance_supporter/object/archive",entry_id:t})!==void 0&&(this.dispatchEvent(new CustomEvent("object-changed",{detail:{entry_id:t},bubbles:!0,composed:!0})),this.close())}_onTaskClick(e){this._entryId&&Promise.resolve().then(()=>(oe(),ue)).then(({openTaskQuickActions:t})=>{t(this._entryId,e)})}render(){if(!this._open)return u;let e=this._lang,t=this._data,i=t?.object,n=t?.tasks||[],o=we(this.hass?.user,this._access);return at(()=>this.close(),l`
|
||||
${t&&i?l`
|
||||
<div class="header">
|
||||
<div class="title">${i.name}</div>
|
||||
@@ -4856,7 +4864,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
<div class="task-row" @click=${()=>this._onTaskClick(d.id)}>
|
||||
<span class="status-dot" style="background: ${Si(d)}"></span>
|
||||
<span class="task-name">${d.name}</span>
|
||||
<span class="task-status ${Pt(d)}">${Ir(Pt(d),e)}</span>
|
||||
<span class="task-status ${Pt(d)}">${Rr(Pt(d),e)}</span>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
@@ -4896,7 +4904,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
${i.map(([n,o,d])=>l`
|
||||
<div class="meta-item">
|
||||
<span class="meta-label">${n}</span>
|
||||
<span class="meta-value">${d||ha(o)?l`<a href="${o}" target="_blank" rel="noopener noreferrer">${o}</a>`:o}</span>
|
||||
<span class="meta-value">${d||_a(o)?l`<a href="${o}" target="_blank" rel="noopener noreferrer">${o}</a>`:o}</span>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
@@ -4945,7 +4953,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
.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; }
|
||||
`],c([v({attribute:!1})],ne.prototype,"hass",2),c([h()],ne.prototype,"_open",2),c([h()],ne.prototype,"_entryId",2),c([h()],ne.prototype,"_data",2),c([h()],ne.prototype,"_busy",2),c([h()],ne.prototype,"_error",2),c([h()],ne.prototype,"_access",2);customElements.get("maintenance-object-quick-actions-dialog")||customElements.define("maintenance-object-quick-actions-dialog",ne)});var ue={};Wa(ue,{__resetSettingsCacheForTests:()=>Ul,getRowActionStyle:()=>Fl,openCompleteDialog:()=>Kl,openCreateObjectDialog:()=>Bl,openCreateTaskDialog:()=>Vl,openEditObjectDialog:()=>Wl,openEditTaskDialog:()=>Gl,openHistoryEditDialog:()=>Lr,openObjectQuickActions:()=>Ql,openQrDialog:()=>Yl,openTaskQuickActions:()=>Nr});function Lt(){return document.querySelector("home-assistant")?.hass}function zl(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function he(s){let r=zl(),e=r.querySelector(s)??document.body.querySelector(s);return e?e.parentNode!==r&&r.appendChild(e):(e=document.createElement(s),r.appendChild(e)),e}function _e(s){let r=Lt();if(!r)return!1;s.hass=r;let e=N(r);return He(e)||qe(e).then(()=>{s.requestUpdate?.()}),Ji(r.locale,r.config?.country,r.config?.time_zone),!0}function Fl(s){return se(s).then(r=>r.rowActionStyle)}function Ul(){an()}function Bl(){let s=he(ja);return _e(s)?(s.openCreate(),za(s),!0):!1}async function za(s){let r=Lt();r&&(s.placesEnabled=(await se(r)).features.places)}function Wl(s,r){let e=he(ja);return _e(e)?(e.openEdit(s,r),za(e),!0):!1}function Vl(s="",r){let e=he(Ma);if(!_e(e))return!1;let t=Lt();return t?((async()=>{let i=await se(t),n=e;Fa(n,i),n.openCreate(s,r)})(),!0):!1}function Fa(s,r){s.checklistsEnabled=r.features.checklists,s.scheduleTimeEnabled=r.features.schedule_time,s.completionActionsEnabled=r.features.completion_actions,s.adaptiveFeature=r.features.adaptive,s.seasonalFeature=r.features.seasonal,s.environmentalFeature=r.features.environmental,s.defaultWarningDays=r.defaultWarningDays}function Gl(s,r){let e=he(Ma);if(!_e(e))return!1;let t=Lt();return t?((async()=>{try{let[i,n]=await Promise.all([t.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:s}),se(t)]),o=(i.tasks||[]).find(p=>p.id===r);if(!o){console.warn(`openEditTaskDialog: task ${r} not found in entry ${s}`);return}let d=e;Fa(d,n),await d.openEdit(s,o)}catch(i){console.warn("openEditTaskDialog: failed to load task/features",i)}})(),!0):!1}function Lr(s){let r=he(ql);return _e(r)?(r.openEdit(s),!0):!1}function Kl(s){let r=he(Ol);return _e(r)?(sa(r,s,N(Lt())),!0):!1}function Yl(s){let r=he(Dl);return _e(r)?(r.openForTask(s.entry_id,s.task_id,s.object_name,s.task_name),!0):!1}function Nr(s,r){let e=he(jl);return _e(e)?(e.openFor(s,r),!0):!1}function Ql(s){let r=he(Ml);return _e(r)?(r.openFor(s),!0):!1}var ja,Ma,ql,Ol,Dl,jl,Ml,oe=y(()=>{"use strict";un();Pn();Vn();Xn();ea();Oa();Da();T();br();Tt();ja="maintenance-object-dialog",Ma="maintenance-task-dialog",ql="maintenance-history-edit-dialog",Ol="maintenance-complete-dialog",Dl="maintenance-qr-dialog",jl="maintenance-task-quick-actions-dialog",Ml="maintenance-object-quick-actions-dialog"});I();F();Gt();var no={days:1,weeks:7,months:30.4368,years:365.25};function us(s,r){return!s||s<=0?0:s*(no[r||"days"]??1)}Kt();function oo(s){return s.responsible_user_id?[s.responsible_user_id]:[...new Set((s.assignee_pool||[]).filter(r=>typeof r=="string"&&r))]}function Fi(s,r){return!!r&&oo(s).includes(r)}Z();var ws=5;function _o(s,r){let e=[];for(let t=0;t<r;t++)e.push(Le(s,t));return e}function mo(s){if(!s||s.length===0)return null;let r=s.map(e=>Vt(e)).filter(e=>e!==null&&e>=0);return r.length===0?null:r.reduce((e,t)=>e+t,0)/r.length}function go(s){let{windowStart:r,windowEnd:e,task:t,entryId:i,objectName:n}=s,o=[],d=(f,x)=>({date:f,entry_id:i,task_id:t.id,task_name:t.name,object_name:n,status:x&&(t.status==="overdue"||t.status==="triggered")?"ok":t.status,days_until_due:x?null:t.days_until_due??null,projected:x,schedule_type:t.schedule_type,interval_days:t.interval_days??null,interval_unit:t.interval_unit??null,responsible_user_id:t.responsible_user_id??null,avg_cost:mo(t.history),adaptive_enabled:!!t.adaptive_config?.enabled,prediction_confidence:t.threshold_prediction_confidence??null}),p=Math.max(1,Math.round(us(t.interval_days,t.interval_unit)));if(t.status==="overdue"||t.status==="triggered"){if(o.push(d(r,!1)),t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let f=Le(r,p),x=1;for(;f<=e&&x<ws;)o.push(d(f,!0)),x++,f=Le(f,p)}return o}let _=t.next_due;if(typeof _!="string"||!_)return o;let m=_.slice(0,10);if(!/^\d{4}-\d{2}-\d{2}$/.test(m))return o;if(m>=r&&m<=e)o.push(d(m,!1));else if(m>e)return o;if(t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let f=Le(m,p),x=o.length;for(;f<=e&&x<ws;)f>=r&&(o.push(d(f,!0)),x++),f=Le(f,p)}return o}function ks(s,r,e,t=null){let i=_o(r,e),n=i[0],o=i[i.length-1],d=[];for(let _ of s){let m=_.object?.name||"",f=_.entry_id,x=_.tasks||[];for(let w of x){if(t&&!F
Line truncated
|
||||
`],c([v({attribute:!1})],ne.prototype,"hass",2),c([h()],ne.prototype,"_open",2),c([h()],ne.prototype,"_entryId",2),c([h()],ne.prototype,"_data",2),c([h()],ne.prototype,"_busy",2),c([h()],ne.prototype,"_error",2),c([h()],ne.prototype,"_access",2);customElements.get("maintenance-object-quick-actions-dialog")||customElements.define("maintenance-object-quick-actions-dialog",ne)});var ue={};Va(ue,{__resetSettingsCacheForTests:()=>Vl,getRowActionStyle:()=>Wl,openCompleteDialog:()=>Zl,openCreateObjectDialog:()=>Gl,openCreateTaskDialog:()=>Yl,openEditObjectDialog:()=>Kl,openEditTaskDialog:()=>Ql,openHistoryEditDialog:()=>Nr,openObjectQuickActions:()=>Xl,openQrDialog:()=>Jl,openTaskQuickActions:()=>Hr});function Lt(){return document.querySelector("home-assistant")?.hass}function Bl(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function he(s){let r=Bl(),e=r.querySelector(s)??document.body.querySelector(s);return e?e.parentNode!==r&&r.appendChild(e):(e=document.createElement(s),r.appendChild(e)),e}function _e(s){let r=Lt();if(!r)return!1;s.hass=r;let e=N(r);return He(e)||qe(e).then(()=>{s.requestUpdate?.()}),Xi(r.locale,r.config?.country,r.config?.time_zone),!0}function Wl(s){return se(s).then(r=>r.rowActionStyle)}function Vl(){on()}function Gl(){let s=he(Ma);return _e(s)?(s.openCreate(),Fa(s),!0):!1}async function Fa(s){let r=Lt();r&&(s.placesEnabled=(await se(r)).features.places)}function Kl(s,r){let e=he(Ma);return _e(e)?(e.openEdit(s,r),Fa(e),!0):!1}function Yl(s="",r){let e=he(za);if(!_e(e))return!1;let t=Lt();return t?((async()=>{let i=await se(t),n=e;Ua(n,i),n.openCreate(s,r)})(),!0):!1}function Ua(s,r){s.checklistsEnabled=r.features.checklists,s.scheduleTimeEnabled=r.features.schedule_time,s.completionActionsEnabled=r.features.completion_actions,s.adaptiveFeature=r.features.adaptive,s.seasonalFeature=r.features.seasonal,s.environmentalFeature=r.features.environmental,s.defaultWarningDays=r.defaultWarningDays}function Ql(s,r){let e=he(za);if(!_e(e))return!1;let t=Lt();return t?((async()=>{try{let[i,n]=await Promise.all([t.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:s}),se(t)]),o=(i.tasks||[]).find(p=>p.id===r);if(!o){console.warn(`openEditTaskDialog: task ${r} not found in entry ${s}`);return}let d=e;Ua(d,n),await d.openEdit(s,o)}catch(i){console.warn("openEditTaskDialog: failed to load task/features",i)}})(),!0):!1}function Nr(s){let r=he(jl);return _e(r)?(r.openEdit(s),!0):!1}function Zl(s){let r=he(Ml);return _e(r)?(na(r,s,N(Lt())),!0):!1}function Jl(s){let r=he(zl);return _e(r)?(r.openForTask(s.entry_id,s.task_id,s.object_name,s.task_name),!0):!1}function Hr(s,r){let e=he(Fl);return _e(e)?(e.openFor(s,r),!0):!1}function Xl(s){let r=he(Ul);return _e(r)?(r.openFor(s),!0):!1}var Ma,za,jl,Ml,zl,Fl,Ul,oe=y(()=>{"use strict";hn();Ln();Gn();ea();ta();Da();ja();T();xr();Tt();Ma="maintenance-object-dialog",za="maintenance-task-dialog",jl="maintenance-history-edit-dialog",Ml="maintenance-complete-dialog",zl="maintenance-qr-dialog",Fl="maintenance-task-quick-actions-dialog",Ul="maintenance-object-quick-actions-dialog"});I();F();Gt();var ao={days:1,weeks:7,months:30.4368,years:365.25};function hs(s,r){return!s||s<=0?0:s*(ao[r||"days"]??1)}Kt();function lo(s){return s.responsible_user_id?[s.responsible_user_id]:[...new Set((s.assignee_pool||[]).filter(r=>typeof r=="string"&&r))]}function Fi(s,r){return!!r&&lo(s).includes(r)}Z();var ks=5;function mo(s,r){let e=[];for(let t=0;t<r;t++)e.push(Le(s,t));return e}function go(s){if(!s||s.length===0)return null;let r=s.map(e=>Vt(e)).filter(e=>e!==null&&e>=0);return r.length===0?null:r.reduce((e,t)=>e+t,0)/r.length}function fo(s){let{windowStart:r,windowEnd:e,task:t,entryId:i,objectName:n}=s,o=[],d=(f,x)=>({date:f,entry_id:i,task_id:t.id,task_name:t.name,object_name:n,status:x&&(t.status==="overdue"||t.status==="triggered")?"ok":t.status,days_until_due:x?null:t.days_until_due??null,projected:x,schedule_type:t.schedule_type,interval_days:t.interval_days??null,interval_unit:t.interval_unit??null,responsible_user_id:t.responsible_user_id??null,avg_cost:go(t.history),adaptive_enabled:!!t.adaptive_config?.enabled,prediction_confidence:t.threshold_prediction_confidence??null}),p=Math.max(1,Math.round(hs(t.interval_days,t.interval_unit)));if(t.status==="overdue"||t.status==="triggered"){if(o.push(d(r,!1)),t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let f=Le(r,p),x=1;for(;f<=e&&x<ks;)o.push(d(f,!0)),x++,f=Le(f,p)}return o}let _=t.next_due;if(typeof _!="string"||!_)return o;let m=_.slice(0,10);if(!/^\d{4}-\d{2}-\d{2}$/.test(m))return o;if(m>=r&&m<=e)o.push(d(m,!1));else if(m>e)return o;if(t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0){let f=Le(m,p),x=o.length;for(;f<=e&&x<ks;)f>=r&&(o.push(d(f,!0)),x++),f=Le(f,p)}return o}function $s(s,r,e,t=null){let i=mo(r,e),n=i[0],o=i[i.length-1],d=[];for(let _ of s){let m=_.object?.name||"",f=_.entry_id,x=_.tasks||[];for(let w of x){if(t&&!F
Line truncated
|
||||
.cal-controls {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
@@ -5142,16 +5150,16 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
.cal-pill-day { font-size: 17px; }
|
||||
.cal-user-filter { margin-left: 0; width: 100%; }
|
||||
}
|
||||
`;T();function Ws(s){let r=window;r.customCards=r.customCards||[],r.customCards.some(e=>e.type===s.type)||r.customCards.push(s)}function Vs(s,r,e=t=>import(t)){let t=window,i;try{let m=new URL(r);i=m.origin+m.pathname}catch{return}let n=`__msCardHeal:${s[0]}:${i}`;if(t[n])return;t[n]=!0;let o=0,d=0,p=!1,_=()=>{if(o+=1,s.some(f=>!customElements.get(f))&&d<3&&!p){d+=1,p=!0;try{let f=new URL(r);f.searchParams.set("heal",`${Date.now()}`),e(f.href).catch(()=>{}).finally(()=>{p=!1})}catch{return}}o<20&&window.setTimeout(_,o<8?500:2e3)};window.setTimeout(_,250)}ir();wt();Tt();oe();var G=class extends S{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"};this._objects=[];this._stats=null;this._windowDays=30;this._pastDays=0;this._userFilter="";this._objectFilter="";this._configuredObjects=[];this._unsub=null;this._pastHistory={};this._pastHistorySig="";this._pastSeq=0;this._dataLoaded=!1;this._lastConnection=null;this._onHistorySaved=e=>{let t=e.detail;!t?.entry_id||!t.task_id||!(Jt(t.entry_id,t.task_id)in this._pastHistory)||(this._pastHistorySig="",this._loadPastHistories())}}static getConfigElement(){return document.createElement("maintenance-supporter-calendar-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-calendar-card",window_days:30,show_window_chips:!0,show_user_filter:!0}}setConfig(e){if(this._config={...e},this._windowDays=e.window_days&&[7,14,30,365].includes(e.window_days)?e.window_days:30,this._pastDays=e.past_days&&[30,90].includes(e.past_days)?e.past_days:0,this._userFilter=typeof e.user_filter=="string"?e.user_filter:"",typeof e.object_filter=="string")this._objectFilter=e.object_filter,this._configuredObjects=[];else if(Array.isArray(e.object_filter)){let t=e.object_filter.filter(i=>typeof i=="string"&&i!=="");this._objectFilter=t.length===1?t[0]:"",this._configuredObjects=t.length>1?t:[]}else this._objectFilter="",this._configuredObjects=[]}getCardSize(){return 6}get _lang(){return N(this.hass)}connectedCallback(){super.connectedCallback(),window.addEventListener("history-entry-saved",this._onHistorySaved)}disconnectedCallback(){if(super.disconnectedCallback(),window.removeEventListener("history-entry-saved",this._onHistorySaved),this._unsub){try{this._unsub()}catch{}this._unsub=null}this._dataLoaded=!1,this._lastConnection=null}updated(e){if(super.updated(e),Hs(this,e),this.hass&&this._pastDays>0&&(e.has("_objects")||e.has("_pastDays"))&&this._loadPastHistories(),e.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){try{let[e,t]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=e.objects,this._stats=t,ei(this._stats.budget)}catch{}}async _loadPastHistories(){let e=$s(this._objects,ye(),this._pastDays||30),t=e.map(o=>o.sig).join("|");if(t===this._pastHistorySig)return;this._pastHistorySig=t;let i=++this._pastSeq,n=await Promise.all(e.map(async o=>{try{let d=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:o.entryId,task_id:o.taskId});return[o.key,d.history??[]]}catch{return null}}));i===this._pastSeq&&(this._pastHistory=Object.fromEntries(n.filter(o=>o!==null)))}async _subscribe(){try{let e=await this.hass.connection.subscribeMessage(t=>{let i=t;this._objects=i.objects},{type:"maintenance_supporter/subscribe"});if(!this.isConnected){e();return}this._unsub=e}catch{}}_onEventClick(e){if(e.history_timestamp){this._openHistoryEntry(e);return}this._openTask(e)}_openTask(e){Nr(e.entry_id,e.task_id)||this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:open-task",entry_id:e.entry_id,task_id:e.task_id},bubbles:!0,composed:!0}))}async _openHistoryEntry(e){try{let t=await se(this.hass);if(!we(this.hass?.user,t.access)){this._openTask(e);return}}catch{}try{let t=await en(this.hass,e.entry_id,e.task_id,e.history_timestamp);if(!t||Lr(t))return}catch{}this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:edit-history",entry_id:e.entry_id,task_id:e.task_id,original_timestamp:e.history_timestamp},bubbles:!0,composed:!0}))}render(){if(!this.hass)return u;let e=this._lang,t=this._config.show_window_chips!==!1,i=this._config.show_user_filter!==!1,n=this._config.title,o=null;this._userFilter&&(o=this._userFilter==="current_user"?this.hass?.user?.id??null:this._userFilter);let d=b=>{let le=b.toLowerCase();return this._objects.find(me=>me.entry_id===b||me.object.name.toLowerCase()===le)?.entry_id??null},p=new Set(this._configuredObjects.map(d).filter(b=>b!==null)),_=p.size?this._objects.filter(b
Line truncated
|
||||
`;T();function Vs(s){let r=window;r.customCards=r.customCards||[],r.customCards.some(e=>e.type===s.type)||r.customCards.push(s)}function Gs(s,r,e=t=>import(t)){let t=window,i;try{let m=new URL(r);i=m.origin+m.pathname}catch{return}let n=`__msCardHeal:${s[0]}:${i}`;if(t[n])return;t[n]=!0;let o=0,d=0,p=!1,_=()=>{if(o+=1,s.some(f=>!customElements.get(f))&&d<3&&!p){d+=1,p=!0;try{let f=new URL(r);f.searchParams.set("heal",`${Date.now()}`),e(f.href).catch(()=>{}).finally(()=>{p=!1})}catch{return}}o<20&&window.setTimeout(_,o<8?500:2e3)};window.setTimeout(_,250)}rr();wt();Tt();oe();var G=class extends S{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"};this._objects=[];this._stats=null;this._windowDays=30;this._pastDays=0;this._userFilter="";this._objectFilter="";this._configuredObjects=[];this._unsub=null;this._pastHistory={};this._pastHistorySig="";this._pastSeq=0;this._dataLoaded=!1;this._lastConnection=null;this._onHistorySaved=e=>{let t=e.detail;!t?.entry_id||!t.task_id||!(Jt(t.entry_id,t.task_id)in this._pastHistory)||(this._pastHistorySig="",this._loadPastHistories())}}static getConfigElement(){return document.createElement("maintenance-supporter-calendar-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-calendar-card",window_days:30,show_window_chips:!0,show_user_filter:!0}}setConfig(e){if(this._config={...e},this._windowDays=e.window_days&&[7,14,30,365].includes(e.window_days)?e.window_days:30,this._pastDays=e.past_days&&[30,90].includes(e.past_days)?e.past_days:0,this._userFilter=typeof e.user_filter=="string"?e.user_filter:"",typeof e.object_filter=="string")this._objectFilter=e.object_filter,this._configuredObjects=[];else if(Array.isArray(e.object_filter)){let t=e.object_filter.filter(i=>typeof i=="string"&&i!=="");this._objectFilter=t.length===1?t[0]:"",this._configuredObjects=t.length>1?t:[]}else this._objectFilter="",this._configuredObjects=[]}getCardSize(){return 6}get _lang(){return N(this.hass)}connectedCallback(){super.connectedCallback(),window.addEventListener("history-entry-saved",this._onHistorySaved)}disconnectedCallback(){if(super.disconnectedCallback(),window.removeEventListener("history-entry-saved",this._onHistorySaved),this._unsub){try{this._unsub()}catch{}this._unsub=null}this._dataLoaded=!1,this._lastConnection=null}updated(e){if(super.updated(e),qs(this,e),this.hass&&this._pastDays>0&&(e.has("_objects")||e.has("_pastDays"))&&this._loadPastHistories(),e.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){try{let[e,t]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=e.objects,this._stats=t,ei(this._stats.budget)}catch{}}async _loadPastHistories(){let e=Es(this._objects,ye(),this._pastDays||30),t=e.map(o=>o.sig).join("|");if(t===this._pastHistorySig)return;this._pastHistorySig=t;let i=++this._pastSeq,n=await Promise.all(e.map(async o=>{try{let d=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:o.entryId,task_id:o.taskId});return[o.key,d.history??[]]}catch{return null}}));i===this._pastSeq&&(this._pastHistory=Object.fromEntries(n.filter(o=>o!==null)))}async _subscribe(){try{let e=await this.hass.connection.subscribeMessage(t=>{let i=t;this._objects=i.objects},{type:"maintenance_supporter/subscribe"});if(!this.isConnected){e();return}this._unsub=e}catch{}}_onEventClick(e){if(e.history_timestamp){this._openHistoryEntry(e);return}this._openTask(e)}_openTask(e){Hr(e.entry_id,e.task_id)||this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:open-task",entry_id:e.entry_id,task_id:e.task_id},bubbles:!0,composed:!0}))}async _openHistoryEntry(e){try{let t=await se(this.hass);if(!we(this.hass?.user,t.access)){this._openTask(e);return}}catch{}try{let t=await tn(this.hass,e.entry_id,e.task_id,e.history_timestamp);if(!t||Nr(t))return}catch{}this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:edit-history",entry_id:e.entry_id,task_id:e.task_id,original_timestamp:e.history_timestamp},bubbles:!0,composed:!0}))}render(){if(!this.hass)return u;let e=this._lang,t=this._config.show_window_chips!==!1,i=this._config.show_user_filter!==!1,n=this._config.title,o=null;this._userFilter&&(o=this._userFilter==="current_user"?this.hass?.user?.id??null:this._userFilter);let d=b=>{let le=b.toLowerCase();return this._objects.find(me=>me.entry_id===b||me.object.name.toLowerCase()===le)?.entry_id??null},p=new Set(this._configuredObjects.map(d).filter(b=>b!==null)),_=p.size?this._objects.filter(b
Line truncated
|
||||
title="${a("cal_source_sensor",e)}" icon="mdi:trending-up"></ha-icon>`:l`<ha-icon class="cal-event-icon cal-source-time"
|
||||
title="${b.adaptive_enabled?a("cal_source_time_adaptive",e):a("cal_source_time",e)}"
|
||||
icon="${b.adaptive_enabled?"mdi:clock-time-four-outline":"mdi:clock-outline"}"></ha-icon>`,dt=z&&b.prediction_confidence&&b.status!=="triggered"&&!b.projected?l`<span class="cal-event-prediction cal-conf-${b.prediction_confidence}">
|
||||
${a("cal_predicted",e)} · ${a(`cal_confidence_${b.prediction_confidence}`,e)}
|
||||
</span>`:u,Ai=De(this._stats?.budget),Ua=b.history_type?a(b.history_type,e):a(b.status,e);return l`
|
||||
</span>`:u,Ai=De(this._stats?.budget),Ba=b.history_type?a(b.history_type,e):a(b.status,e);return l`
|
||||
<div class="cal-event ${Se}"
|
||||
@click=${()=>this._onEventClick(b)}>
|
||||
${ct}
|
||||
<span class="cal-status-pill ${le}">${Ua}</span>
|
||||
<span class="cal-status-pill ${le}">${Ba}</span>
|
||||
<div class="cal-event-body">
|
||||
<div class="cal-event-title">${b.object_name} · ${b.task_name}${me}</div>
|
||||
${dt}
|
||||
@@ -5159,7 +5167,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
</div>
|
||||
${b.avg_cost!=null&&b.avg_cost!==0?l`<span class="cal-event-cost">${J(b.avg_cost,Ai,e)}</span>`:u}
|
||||
</div>
|
||||
`},W=b=>{let[le,Se,me]=b.date.split("-").map(Number),q=new Date(le,Se-1,me),z=b.date===w,ct=zs(q,e,"short"),dt=Fs(q,e,"long");return l`
|
||||
`},W=b=>{let[le,Se,me]=b.date.split("-").map(Number),q=new Date(le,Se-1,me),z=b.date===w,ct=Fs(q,e,"short"),dt=Us(q,e,"long");return l`
|
||||
<div class="cal-day-row">
|
||||
<div class="cal-day-pill ${z?"cal-today":""}">
|
||||
<span class="cal-pill-weekday">${ct}</span>
|
||||
@@ -5218,10 +5226,10 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
${M.length===0&&L?l`<div class="cal-empty">${a("cal_no_events",e)}</div>`:M.map(W)}
|
||||
</div>
|
||||
</ha-card>
|
||||
`}};G.styles=[ni,Ts,E`
|
||||
`}};G.styles=[ni,As,E`
|
||||
:host { display: block; }
|
||||
ha-card { padding: 0; overflow: hidden; }
|
||||
`],c([v({attribute:!1})],G.prototype,"hass",2),c([h()],G.prototype,"_config",2),c([h()],G.prototype,"_objects",2),c([h()],G.prototype,"_stats",2),c([h()],G.prototype,"_windowDays",2),c([h()],G.prototype,"_pastDays",2),c([h()],G.prototype,"_userFilter",2),c([h()],G.prototype,"_objectFilter",2),c([h()],G.prototype,"_unsub",2),c([h()],G.prototype,"_pastHistory",2);var Zl=[{value:7,key:"cal_editor_window_week"},{value:14,key:"cal_editor_window_fortnight"},{value:30,key:"cal_editor_window_month"},{value:365,key:"cal_editor_window_year"}],Jl=[{value:30,key:"cal_editor_window_past_30"},{value:90,key:"cal_editor_window_past_90"}],lt=class extends S{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"}}get _lang(){return N(this.hass)}setConfig(e){this._config={...e}}updated(){let e=this._lang;e&&!He(e)&&qe(e).then(()=>this.requestUpdate())}_valueChanged(e,t){let i={...this._config,[e]:t};e==="show_window_chips"&&t===!0&&delete i.show_window_chips,e==="show_user_filter"&&t===!0&&delete i.show_user_filter,e==="show_object_filter"&&t===!0&&delete i.show_object_filter,e==="title"&&(!t||typeof t=="string"&&t.trim()==="")&&delete i.title,e==="user_filter"&&t===""&&delete i.user_filter,this._emit(i)}_windowChanged(e){let t={...this._config};e.startsWith("past-")?(t.past_days=Number(e.slice(5)),delete t.window_days):(t.window_days=Number(e),delete t.past_days),this._emit(t)}_emit(e){this._config=e,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:e},bubbles:!0,composed:!0}))}render(){let e=this._lang,t=this._config.past_days?`past-${this._config.past_days}`:`${this._config.window_days??30}`,i=this._config.show_window_chips!==!1,n=this._config.show_user_filter!==!1,o=this._config.user_filter??"",d=this._config.title??"";return l`
|
||||
`],c([v({attribute:!1})],G.prototype,"hass",2),c([h()],G.prototype,"_config",2),c([h()],G.prototype,"_objects",2),c([h()],G.prototype,"_stats",2),c([h()],G.prototype,"_windowDays",2),c([h()],G.prototype,"_pastDays",2),c([h()],G.prototype,"_userFilter",2),c([h()],G.prototype,"_objectFilter",2),c([h()],G.prototype,"_unsub",2),c([h()],G.prototype,"_pastHistory",2);var ec=[{value:7,key:"cal_editor_window_week"},{value:14,key:"cal_editor_window_fortnight"},{value:30,key:"cal_editor_window_month"},{value:365,key:"cal_editor_window_year"}],tc=[{value:30,key:"cal_editor_window_past_30"},{value:90,key:"cal_editor_window_past_90"}],lt=class extends S{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"}}get _lang(){return N(this.hass)}setConfig(e){this._config={...e}}updated(){let e=this._lang;e&&!He(e)&&qe(e).then(()=>this.requestUpdate())}_valueChanged(e,t){let i={...this._config,[e]:t};e==="show_window_chips"&&t===!0&&delete i.show_window_chips,e==="show_user_filter"&&t===!0&&delete i.show_user_filter,e==="show_object_filter"&&t===!0&&delete i.show_object_filter,e==="title"&&(!t||typeof t=="string"&&t.trim()==="")&&delete i.title,e==="user_filter"&&t===""&&delete i.user_filter,this._emit(i)}_windowChanged(e){let t={...this._config};e.startsWith("past-")?(t.past_days=Number(e.slice(5)),delete t.window_days):(t.window_days=Number(e),delete t.past_days),this._emit(t)}_emit(e){this._config=e,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:e},bubbles:!0,composed:!0}))}render(){let e=this._lang,t=this._config.past_days?`past-${this._config.past_days}`:`${this._config.window_days??30}`,i=this._config.show_window_chips!==!1,n=this._config.show_user_filter!==!1,o=this._config.user_filter??"",d=this._config.title??"";return l`
|
||||
<div class="editor">
|
||||
<div class="row">
|
||||
<label for="title">${a("card_title",e)}</label>
|
||||
@@ -5238,8 +5246,8 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
id="window"
|
||||
@change=${p=>this._windowChanged(p.target.value)}
|
||||
>
|
||||
${Zl.map(p=>l`<option value="${p.value}" ?selected=${`${p.value}`===t}>${a(p.key,e)}</option>`)}
|
||||
${Jl.map(p=>l`<option value="past-${p.value}" ?selected=${`past-${p.value}`===t}>${a(p.key,e)}</option>`)}
|
||||
${ec.map(p=>l`<option value="${p.value}" ?selected=${`${p.value}`===t}>${a(p.key,e)}</option>`)}
|
||||
${tc.map(p=>l`<option value="past-${p.value}" ?selected=${`past-${p.value}`===t}>${a(p.key,e)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
<div class="row toggle">
|
||||
@@ -5308,7 +5316,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color, #666);
|
||||
}
|
||||
`,c([v({attribute:!1})],lt.prototype,"hass",2),c([h()],lt.prototype,"_config",2);customElements.get("maintenance-supporter-calendar-card")||customElements.define("maintenance-supporter-calendar-card",G);customElements.get("maintenance-supporter-calendar-card-editor")||customElements.define("maintenance-supporter-calendar-card-editor",lt);Vs(["maintenance-supporter-calendar-card"],import.meta.url);Ws({type:"maintenance-supporter-calendar-card",name:"Maintenance Supporter \u2014 Calendar",description:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",preview:!0});export{G as MaintenanceCalendarCard};
|
||||
`,c([v({attribute:!1})],lt.prototype,"hass",2),c([h()],lt.prototype,"_config",2);customElements.get("maintenance-supporter-calendar-card")||customElements.define("maintenance-supporter-calendar-card",G);customElements.get("maintenance-supporter-calendar-card-editor")||customElements.define("maintenance-supporter-calendar-card-editor",lt);Gs(["maintenance-supporter-calendar-card"],import.meta.url);Vs({type:"maintenance-supporter-calendar-card",name:"Maintenance Supporter \u2014 Calendar",description:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",preview:!0});export{G as MaintenanceCalendarCard};
|
||||
/*! Bundled license information:
|
||||
|
||||
@lit/reactive-element/css-tag.js:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*! maintenance_supporter frontend 2.102.0 */
|
||||
var er=Object.defineProperty;var ao=Object.getOwnPropertyDescriptor;var y=(r,s,e)=>()=>{if(e)throw e[0];try{return r&&(s=r(r=0)),s}catch(t){throw e=[t],t}};var oo=(r,s)=>{for(var e in s)er(r,e,{get:s[e],enumerable:!0})};var c=(r,s,e,t)=>{for(var i=t>1?void 0:t?ao(s,e):s,a=r.length-1,o;a>=0;a--)(o=r[a])&&(i=(t?o(s,e,i):o(i))||i);return t&&i&&er(s,e,i),i};var Ut,Bt,ji,tr,_t,ir,$,sr,Di,qi=y(()=>{Ut=globalThis,Bt=Ut.ShadowRoot&&(Ut.ShadyCSS===void 0||Ut.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,ji=Symbol(),tr=new WeakMap,_t=class{constructor(s,e,t){if(this._$cssResult$=!0,t!==ji)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=s,this.t=e}get styleSheet(){let s=this.o,e=this.t;if(Bt&&s===void 0){let t=e!==void 0&&e.length===1;t&&(s=tr.get(e)),s===void 0&&((this.o=s=new CSSStyleSheet).replaceSync(this.cssText),t&&tr.set(e,s))}return s}toString(){return this.cssText}},ir=r=>new _t(typeof r=="string"?r:r+"",void 0,ji),$=(r,...s)=>{let e=r.length===1?r[0]:s.reduce((t,i,a)=>t+(o=>{if(o._$cssResult$===!0)return o.cssText;if(typeof o=="number")return o;throw Error("Value passed to 'css' function must be a 'css' function result: "+o+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+r[a+1],r[0]);return new _t(e,r,ji)},sr=(r,s)=>{if(Bt)r.adoptedStyleSheets=s.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of s){let t=document.createElement("style"),i=Ut.litNonce;i!==void 0&&t.setAttribute("nonce",i),t.textContent=e.cssText,r.appendChild(t)}},Di=Bt?r=>r:r=>r instanceof CSSStyleSheet?(s=>{let e="";for(let t of s.cssRules)e+=t.cssText;return ir(e)})(r):r});var lo,co,po,uo,ho,_o,Wt,rr,mo,go,mt,gt,Vt,nr,de,ft=y(()=>{qi();qi();({is:lo,defineProperty:co,getOwnPropertyDescriptor:po,getOwnPropertyNames:uo,getOwnPropertySymbols:ho,getPrototypeOf:_o}=Object),Wt=globalThis,rr=Wt.trustedTypes,mo=rr?rr.emptyScript:"",go=Wt.reactiveElementPolyfillSupport,mt=(r,s)=>r,gt={toAttribute(r,s){switch(s){case Boolean:r=r?mo:null;break;case Object:case Array:r=r==null?r:JSON.stringify(r)}return r},fromAttribute(r,s){let e=r;switch(s){case Boolean:e=r!==null;break;case Number:e=r===null?null:Number(r);break;case Object:case Array:try{e=JSON.parse(r)}catch{e=null}}return e}},Vt=(r,s)=>!lo(r,s),nr={attribute:!0,type:String,converter:gt,reflect:!1,useDefault:!1,hasChanged:Vt};Symbol.metadata??=Symbol("metadata"),Wt.litPropertyMetadata??=new WeakMap;de=class extends HTMLElement{static addInitializer(s){this._$Ei(),(this.l??=[]).push(s)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(s,e=nr){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(s)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(s,e),!e.noAccessor){let t=Symbol(),i=this.getPropertyDescriptor(s,t,e);i!==void 0&&co(this.prototype,s,i)}}static getPropertyDescriptor(s,e,t){let{get:i,set:a}=po(this.prototype,s)??{get(){return this[e]},set(o){this[e]=o}};return{get:i,set(o){let d=i?.call(this);a?.call(this,o),this.requestUpdate(s,d,t)},configurable:!0,enumerable:!0}}static getPropertyOptions(s){return this.elementProperties.get(s)??nr}static _$Ei(){if(this.hasOwnProperty(mt("elementProperties")))return;let s=_o(this);s.finalize(),s.l!==void 0&&(this.l=[...s.l]),this.elementProperties=new Map(s.elementProperties)}static finalize(){if(this.hasOwnProperty(mt("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(mt("properties"))){let e=this.properties,t=[...uo(e),...ho(e)];for(let i of t)this.createProperty(i,e[i])}let s=this[Symbol.metadata];if(s!==null){let e=litPropertyMetadata.get(s);if(e!==void 0)for(let[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(let[e,t]of this.elementProperties){let i=this._$Eu(e,t);i!==void 0&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(s){let e=[];if(Array.isArray(s)){let t=new Set(s.flat(1/0).reverse());for(let i of t)e.unshift(Di(i))}else s!==void 0&&e.push(Di(s));return e}static _$Eu(s,e){let t=e.attribute;return t===!1?void 0:typeof t=="string"?t:typeof s=="string"?s.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(s=>this.enableUpdating=s),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(s=>s(this))}addController(s){(this._$EO??=new Set).add(s),this.renderRoot!==void 0&&this.isConnected&&s.hostConnected?.()}removeController(s){this._$EO?.delete(s)}_$E_(){let s=new Map,e=this.constructor.elementProperties;for(let t of e.keys())this.hasOwnProperty(t)&&(s.set(t,this[t]),delete this[t]);s.size>0&&(this._$Ep=s)}createRenderRoot(){let s=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return sr(s,this.constructor.elementStyles),s}connectedCallback(){this.renderRoot??=tLine truncated
|
||||
\f\r]`,vt=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,lr=/-->/g,cr=/>/g,Re=RegExp(`>|${Mi}(?:([^\\s"'>=/]+)(${Mi}*=${Mi}*(?:[^
|
||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),dr=/'/g,pr=/"/g,_r=/^(?:script|style|textarea|title)$/i,Wi=r=>(s,...e)=>({_$litType$:r,strings:s,values:e}),l=Wi(1),We=Wi(2),kc=Wi(3),Le=Symbol.for("lit-noChange"),p=Symbol.for("lit-nothing"),ur=new WeakMap,Ie=Pe.createTreeWalker(Pe,129);gr=(r,s)=>{let e=r.length-1,t=[],i,a=s===2?"<svg>":s===3?"<math>":"",o=vt;for(let d=0;d<e;d++){let h=r[d],_,m,b=-1,k=0;for(;k<h.length&&(o.lastIndex=k,m=o.exec(h),m!==null);)k=o.lastIndex,o===vt?m[1]==="!--"?o=lr:m[1]!==void 0?o=cr:m[2]!==void 0?(_r.test(m[2])&&(i=RegExp("</"+m[2],"g")),o=Re):m[3]!==void 0&&(o=Re):o===Re?m[0]===">"?(o=i??vt,b=-1):m[1]===void 0?b=-2:(b=o.lastIndex-m[2].length,_=m[1],o=m[3]===void 0?Re:m[3]==='"'?pr:dr):o===pr||o===dr?o=Re:o===lr||o===cr?o=vt:(o=Re,i=void 0);let w=o===Re&&r[d+1].startsWith("/>")?" ":"";a+=o===vt?h+fo:b>=0?(t.push(_),h.slice(0,b)+Fi+h.slice(b)+pe+w):h+pe+(b===-2?d:w)}return[mr(r,a+(r[e]||"<?>")+(s===2?"</svg>":s===3?"</math>":"")),t]},xt=class r{constructor({strings:s,_$litType$:e},t){let i;this.parts=[];let a=0,o=0,d=s.length-1,h=this.parts,[_,m]=gr(s,e);if(this.el=r.createElement(_,t),Ie.currentNode=this.el.content,e===2||e===3){let b=this.el.content.firstChild;b.replaceWith(...b.childNodes)}for(;(i=Ie.nextNode())!==null&&h.length<d;){if(i.nodeType===1){if(i.hasAttributes())for(let b of i.getAttributeNames())if(b.endsWith(Fi)){let k=m[o++],w=i.getAttribute(b).split(pe),v=/([.?@])?(.*)/.exec(k);h.push({type:1,index:a,name:v[2],strings:w,ctor:v[1]==="."?Yt:v[1]==="?"?Qt:v[1]==="@"?Zt:Oe}),i.removeAttribute(b)}else b.startsWith(pe)&&(h.push({type:6,index:a}),i.removeAttribute(b));if(_r.test(i.tagName)){let b=i.textContent.split(pe),k=b.length-1;if(k>0){i.textContent=Gt?Gt.emptyScript:"";for(let w=0;w<k;w++)i.append(b[w],bt()),Ie.nextNode(),h.push({type:2,index:++a});i.append(b[k],bt())}}}else if(i.nodeType===8)if(i.data===Ui)h.push({type:2,index:a});else{let b=-1;for(;(b=i.data.indexOf(pe,b+1))!==-1;)h.push({type:7,index:a}),b+=pe.length-1}a++}}static createElement(s,e){let t=Pe.createElement("template");return t.innerHTML=s,t}};Kt=class{constructor(s,e){this._$AV=[],this._$AN=void 0,this._$AD=s,this._$AM=e}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(s){let{el:{content:e},parts:t}=this._$AD,i=(s?.creationScope??Pe).importNode(e,!0);Ie.currentNode=i;let a=Ie.nextNode(),o=0,d=0,h=t[0];for(;h!==void 0;){if(o===h.index){let _;h.type===2?_=new Be(a,a.nextSibling,this,s):h.type===1?_=new h.ctor(a,h.name,h.strings,this,s):h.type===6&&(_=new Jt(a,this,s)),this._$AV.push(_),h=t[++d]}o!==h?.index&&(a=Ie.nextNode(),o++)}return Ie.currentNode=Pe,i}p(s){let e=0;for(let t of this._$AV)t!==void 0&&(t.strings!==void 0?(t._$AI(s,t,e),e+=t.strings.length-2):t._$AI(s[e])),e++}},Be=class r{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(s,e,t,i){this.type=2,this._$AH=p,this._$AN=void 0,this._$AA=s,this._$AB=e,this._$AM=t,this.options=i,this._$Cv=i?.isConnected??!0}get parentNode(){let s=this._$AA.parentNode,e=this._$AM;return e!==void 0&&s?.nodeType===11&&(s=e.parentNode),s}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(s,e=this){s=Ne(this,s,e),yt(s)?s===p||s==null||s===""?(this._$AH!==p&&this._$AR(),this._$AH=p):s!==this._$AH&&s!==Le&&this._(s):s._$litType$!==void 0?this.$(s):s.nodeType!==void 0?this.T(s):hr(s)?this.k(s):this._(s)}O(s){return this._$AA.parentNode.insertBefore(s,this._$AB)}T(s){this._$AH!==s&&(this._$AR(),this._$AH=this.O(s))}_(s){this._$AH!==p&&yt(this._$AH)?this._$AA.nextSibling.data=s:this.T(Pe.createTextNode(s)),this._$AH=s}$(s){let{values:e,_$litType$:t}=s,i=typeof t=="number"?this._$AC(s):(t.el===void 0&&(t.el=xt.createElement(mr(t.h,t.h[0]),this.options)),t);if(this._$AH?._$AD===i)this._$AH.p(e);else{let a=new Kt(i,this),o=a.u(this.options);a.p(e),this.T(o),this._$AH=a}}_$AC(s){let e=ur.get(s.strings);return e===void 0&&ur.set(s.strings,e=new xt(s)),e}k(s){Bi(this._$AH)||(this._$AH=[],this._$AR());let e=this._$AH,t,i=0;for(let a of s)i===e.length?e.push(t=new r(this.O(bt()),this.O(bt()),this,this.options)):t=e[i],t._$AI(a),i++;i<e.length&&(this._$AR(t&&t._$AB.nextSibling,i),e.length=i)}_$AR(s=this._$AA.nextSibling,e){for(this._$AP?.(!1,!0,e);s!==this._$AB;){let t=ar(s).nextSibling;ar(s).remove(),s=t}}setConnected(s){this._$AM===void 0&&(this._$Cv=s,this._$AP?.(s))}},Oe=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(s,e,t,i,a){this.type=1,this._$AH=p,this._$AN=void 0,this.element=s,this.name=e,this._$AM=i,this.options=a,t.length>2||t[0]!==""||t[1]!==""?(this._$AH=Array(t.length-1).fill(new String),this.strings=t):this._$AH=p}_$AI(s,e=this,t,i){let a=this.strings,o=!1;if(a===void 0)s=Ne(this,s,e,0),o=!yt(s)||s!==this._$AH&&s!==Le,o&&(this._$AH=s);else{let d=s,h,_;for(s=a[0],h=0;h<a.length-1;h++)_=Ne(this,d[t+h],e,h),_===Le&&(_=this._$AH[h]),o||=!yt(_)||_!==this._$AH[h],_===p?s=p:s!==p&&(s+=(_??"")+a[h+1]),this._$AH[h]=_}o&&!i&&this.j(s)}j(s){s===p?this.element.removeAttribute(this.naLine truncated
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
var tr=Object.defineProperty;var oo=Object.getOwnPropertyDescriptor;var y=(r,s,e)=>()=>{if(e)throw e[0];try{return r&&(s=r(r=0)),s}catch(t){throw e=[t],t}};var lo=(r,s)=>{for(var e in s)tr(r,e,{get:s[e],enumerable:!0})};var c=(r,s,e,t)=>{for(var i=t>1?void 0:t?oo(s,e):s,a=r.length-1,o;a>=0;a--)(o=r[a])&&(i=(t?o(s,e,i):o(i))||i);return t&&i&&tr(s,e,i),i};var Ut,Bt,ji,ir,_t,sr,$,rr,Di,qi=y(()=>{Ut=globalThis,Bt=Ut.ShadowRoot&&(Ut.ShadyCSS===void 0||Ut.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,ji=Symbol(),ir=new WeakMap,_t=class{constructor(s,e,t){if(this._$cssResult$=!0,t!==ji)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=s,this.t=e}get styleSheet(){let s=this.o,e=this.t;if(Bt&&s===void 0){let t=e!==void 0&&e.length===1;t&&(s=ir.get(e)),s===void 0&&((this.o=s=new CSSStyleSheet).replaceSync(this.cssText),t&&ir.set(e,s))}return s}toString(){return this.cssText}},sr=r=>new _t(typeof r=="string"?r:r+"",void 0,ji),$=(r,...s)=>{let e=r.length===1?r[0]:s.reduce((t,i,a)=>t+(o=>{if(o._$cssResult$===!0)return o.cssText;if(typeof o=="number")return o;throw Error("Value passed to 'css' function must be a 'css' function result: "+o+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+r[a+1],r[0]);return new _t(e,r,ji)},rr=(r,s)=>{if(Bt)r.adoptedStyleSheets=s.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of s){let t=document.createElement("style"),i=Ut.litNonce;i!==void 0&&t.setAttribute("nonce",i),t.textContent=e.cssText,r.appendChild(t)}},Di=Bt?r=>r:r=>r instanceof CSSStyleSheet?(s=>{let e="";for(let t of s.cssRules)e+=t.cssText;return sr(e)})(r):r});var co,po,uo,ho,_o,mo,Wt,nr,go,fo,mt,gt,Vt,ar,de,ft=y(()=>{qi();qi();({is:co,defineProperty:po,getOwnPropertyDescriptor:uo,getOwnPropertyNames:ho,getOwnPropertySymbols:_o,getPrototypeOf:mo}=Object),Wt=globalThis,nr=Wt.trustedTypes,go=nr?nr.emptyScript:"",fo=Wt.reactiveElementPolyfillSupport,mt=(r,s)=>r,gt={toAttribute(r,s){switch(s){case Boolean:r=r?go:null;break;case Object:case Array:r=r==null?r:JSON.stringify(r)}return r},fromAttribute(r,s){let e=r;switch(s){case Boolean:e=r!==null;break;case Number:e=r===null?null:Number(r);break;case Object:case Array:try{e=JSON.parse(r)}catch{e=null}}return e}},Vt=(r,s)=>!co(r,s),ar={attribute:!0,type:String,converter:gt,reflect:!1,useDefault:!1,hasChanged:Vt};Symbol.metadata??=Symbol("metadata"),Wt.litPropertyMetadata??=new WeakMap;de=class extends HTMLElement{static addInitializer(s){this._$Ei(),(this.l??=[]).push(s)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(s,e=ar){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(s)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(s,e),!e.noAccessor){let t=Symbol(),i=this.getPropertyDescriptor(s,t,e);i!==void 0&&po(this.prototype,s,i)}}static getPropertyDescriptor(s,e,t){let{get:i,set:a}=uo(this.prototype,s)??{get(){return this[e]},set(o){this[e]=o}};return{get:i,set(o){let d=i?.call(this);a?.call(this,o),this.requestUpdate(s,d,t)},configurable:!0,enumerable:!0}}static getPropertyOptions(s){return this.elementProperties.get(s)??ar}static _$Ei(){if(this.hasOwnProperty(mt("elementProperties")))return;let s=mo(this);s.finalize(),s.l!==void 0&&(this.l=[...s.l]),this.elementProperties=new Map(s.elementProperties)}static finalize(){if(this.hasOwnProperty(mt("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(mt("properties"))){let e=this.properties,t=[...ho(e),..._o(e)];for(let i of t)this.createProperty(i,e[i])}let s=this[Symbol.metadata];if(s!==null){let e=litPropertyMetadata.get(s);if(e!==void 0)for(let[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(let[e,t]of this.elementProperties){let i=this._$Eu(e,t);i!==void 0&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(s){let e=[];if(Array.isArray(s)){let t=new Set(s.flat(1/0).reverse());for(let i of t)e.unshift(Di(i))}else s!==void 0&&e.push(Di(s));return e}static _$Eu(s,e){let t=e.attribute;return t===!1?void 0:typeof t=="string"?t:typeof s=="string"?s.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(s=>this.enableUpdating=s),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(s=>s(this))}addController(s){(this._$EO??=new Set).add(s),this.renderRoot!==void 0&&this.isConnected&&s.hostConnected?.()}removeController(s){this._$EO?.delete(s)}_$E_(){let s=new Map,e=this.constructor.elementProperties;for(let t of e.keys())this.hasOwnProperty(t)&&(s.set(t,this[t]),delete this[t]);s.size>0&&(this._$Ep=s)}createRenderRoot(){let s=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return rr(s,this.constructor.elementStyles),s}connectedCallback(){this.renderRoot??=tLine truncated
|
||||
\f\r]`,vt=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,cr=/-->/g,dr=/>/g,Re=RegExp(`>|${Mi}(?:([^\\s"'>=/]+)(${Mi}*=${Mi}*(?:[^
|
||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),pr=/'/g,ur=/"/g,mr=/^(?:script|style|textarea|title)$/i,Wi=r=>(s,...e)=>({_$litType$:r,strings:s,values:e}),l=Wi(1),We=Wi(2),Sc=Wi(3),Le=Symbol.for("lit-noChange"),p=Symbol.for("lit-nothing"),hr=new WeakMap,Ie=Pe.createTreeWalker(Pe,129);fr=(r,s)=>{let e=r.length-1,t=[],i,a=s===2?"<svg>":s===3?"<math>":"",o=vt;for(let d=0;d<e;d++){let h=r[d],_,m,b=-1,k=0;for(;k<h.length&&(o.lastIndex=k,m=o.exec(h),m!==null);)k=o.lastIndex,o===vt?m[1]==="!--"?o=cr:m[1]!==void 0?o=dr:m[2]!==void 0?(mr.test(m[2])&&(i=RegExp("</"+m[2],"g")),o=Re):m[3]!==void 0&&(o=Re):o===Re?m[0]===">"?(o=i??vt,b=-1):m[1]===void 0?b=-2:(b=o.lastIndex-m[2].length,_=m[1],o=m[3]===void 0?Re:m[3]==='"'?ur:pr):o===ur||o===pr?o=Re:o===cr||o===dr?o=vt:(o=Re,i=void 0);let w=o===Re&&r[d+1].startsWith("/>")?" ":"";a+=o===vt?h+vo:b>=0?(t.push(_),h.slice(0,b)+Fi+h.slice(b)+pe+w):h+pe+(b===-2?d:w)}return[gr(r,a+(r[e]||"<?>")+(s===2?"</svg>":s===3?"</math>":"")),t]},xt=class r{constructor({strings:s,_$litType$:e},t){let i;this.parts=[];let a=0,o=0,d=s.length-1,h=this.parts,[_,m]=fr(s,e);if(this.el=r.createElement(_,t),Ie.currentNode=this.el.content,e===2||e===3){let b=this.el.content.firstChild;b.replaceWith(...b.childNodes)}for(;(i=Ie.nextNode())!==null&&h.length<d;){if(i.nodeType===1){if(i.hasAttributes())for(let b of i.getAttributeNames())if(b.endsWith(Fi)){let k=m[o++],w=i.getAttribute(b).split(pe),v=/([.?@])?(.*)/.exec(k);h.push({type:1,index:a,name:v[2],strings:w,ctor:v[1]==="."?Yt:v[1]==="?"?Qt:v[1]==="@"?Zt:Oe}),i.removeAttribute(b)}else b.startsWith(pe)&&(h.push({type:6,index:a}),i.removeAttribute(b));if(mr.test(i.tagName)){let b=i.textContent.split(pe),k=b.length-1;if(k>0){i.textContent=Gt?Gt.emptyScript:"";for(let w=0;w<k;w++)i.append(b[w],bt()),Ie.nextNode(),h.push({type:2,index:++a});i.append(b[k],bt())}}}else if(i.nodeType===8)if(i.data===Ui)h.push({type:2,index:a});else{let b=-1;for(;(b=i.data.indexOf(pe,b+1))!==-1;)h.push({type:7,index:a}),b+=pe.length-1}a++}}static createElement(s,e){let t=Pe.createElement("template");return t.innerHTML=s,t}};Kt=class{constructor(s,e){this._$AV=[],this._$AN=void 0,this._$AD=s,this._$AM=e}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(s){let{el:{content:e},parts:t}=this._$AD,i=(s?.creationScope??Pe).importNode(e,!0);Ie.currentNode=i;let a=Ie.nextNode(),o=0,d=0,h=t[0];for(;h!==void 0;){if(o===h.index){let _;h.type===2?_=new Be(a,a.nextSibling,this,s):h.type===1?_=new h.ctor(a,h.name,h.strings,this,s):h.type===6&&(_=new Jt(a,this,s)),this._$AV.push(_),h=t[++d]}o!==h?.index&&(a=Ie.nextNode(),o++)}return Ie.currentNode=Pe,i}p(s){let e=0;for(let t of this._$AV)t!==void 0&&(t.strings!==void 0?(t._$AI(s,t,e),e+=t.strings.length-2):t._$AI(s[e])),e++}},Be=class r{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(s,e,t,i){this.type=2,this._$AH=p,this._$AN=void 0,this._$AA=s,this._$AB=e,this._$AM=t,this.options=i,this._$Cv=i?.isConnected??!0}get parentNode(){let s=this._$AA.parentNode,e=this._$AM;return e!==void 0&&s?.nodeType===11&&(s=e.parentNode),s}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(s,e=this){s=Ne(this,s,e),yt(s)?s===p||s==null||s===""?(this._$AH!==p&&this._$AR(),this._$AH=p):s!==this._$AH&&s!==Le&&this._(s):s._$litType$!==void 0?this.$(s):s.nodeType!==void 0?this.T(s):_r(s)?this.k(s):this._(s)}O(s){return this._$AA.parentNode.insertBefore(s,this._$AB)}T(s){this._$AH!==s&&(this._$AR(),this._$AH=this.O(s))}_(s){this._$AH!==p&&yt(this._$AH)?this._$AA.nextSibling.data=s:this.T(Pe.createTextNode(s)),this._$AH=s}$(s){let{values:e,_$litType$:t}=s,i=typeof t=="number"?this._$AC(s):(t.el===void 0&&(t.el=xt.createElement(gr(t.h,t.h[0]),this.options)),t);if(this._$AH?._$AD===i)this._$AH.p(e);else{let a=new Kt(i,this),o=a.u(this.options);a.p(e),this.T(o),this._$AH=a}}_$AC(s){let e=hr.get(s.strings);return e===void 0&&hr.set(s.strings,e=new xt(s)),e}k(s){Bi(this._$AH)||(this._$AH=[],this._$AR());let e=this._$AH,t,i=0;for(let a of s)i===e.length?e.push(t=new r(this.O(bt()),this.O(bt()),this,this.options)):t=e[i],t._$AI(a),i++;i<e.length&&(this._$AR(t&&t._$AB.nextSibling,i),e.length=i)}_$AR(s=this._$AA.nextSibling,e){for(this._$AP?.(!1,!0,e);s!==this._$AB;){let t=or(s).nextSibling;or(s).remove(),s=t}}setConnected(s){this._$AM===void 0&&(this._$Cv=s,this._$AP?.(s))}},Oe=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(s,e,t,i,a){this.type=1,this._$AH=p,this._$AN=void 0,this.element=s,this.name=e,this._$AM=i,this.options=a,t.length>2||t[0]!==""||t[1]!==""?(this._$AH=Array(t.length-1).fill(new String),this.strings=t):this._$AH=p}_$AI(s,e=this,t,i){let a=this.strings,o=!1;if(a===void 0)s=Ne(this,s,e,0),o=!yt(s)||s!==this._$AH&&s!==Le,o&&(this._$AH=s);else{let d=s,h,_;for(s=a[0],h=0;h<a.length-1;h++)_=Ne(this,d[t+h],e,h),_===Le&&(_=this._$AH[h]),o||=!yt(_)||_!==this._$AH[h],_===p?s=p:s!==p&&(s+=(_??"")+a[h+1]),this._$AH[h]=_}o&&!i&&this.j(s)}j(s){s===p?this.element.removeAttribute(this.naLine truncated
|
||||
Replace seal
|
||||
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",ws_err_not_found:"Not found \u2014 it may have been deleted meanwhile",ws_err_invalid_input:"Invalid input",ws_err_invalid_date:"Invalid date",ws_err_invalid_format:"Invalid format",ws_err_invalid_url:"Invalid link",ws_err_invalid_mirror_todo:"Invalid to-do list",ws_err_not_configured:"Not set up yet",ws_err_not_loaded:"Not loaded yet \u2014 try again in a moment",ws_err_limit_reached:"Limit reached",ws_err_too_many:"Too many entries",ws_err_too_large:"Too large",ws_err_not_archived:"Not archived",ws_err_invalid_target:"Invalid target",ws_err_create_failed:"Could not be created",ws_err_archived:"Archived \u2014 restore it first",ws_err_already_archived:"Already archived",ws_err_unavailable:"Currently unavailable",ws_err_unauthorized:"Not permitted for your user",ws_err_too_many_views:"Too many saved views",ws_err_storage_unavailable:"Storage is not available",ws_err_replace_failed:"Replacement failed",ws_err_not_paused:"Not paused",ws_err_not_available:"Nothing available",ws_err_no_url:"No link given",ws_err_no_phases:"This task has no phases",ws_err_invalid_view:"Invalid view",ws_err_invalid_user:"Unknown user",ws_err_invalid_range:"Invalid range",ws_err_invalid_parent:"Invalid parent object",ws_err_invalid_device:"Unknown device",ws_err_empty_csv:"The CSV file is empty",ws_err_empty:"Nothing to import",ws_err_duplicate_failed:"Could not duplicate",ws_err_already_paused:"Already paused",ws_err_invalid_cursor:"Invalid phase position",ws_err_invalid_entity_slug:"Invalid entity name",ws_err_invalid_trigger_config:"Invalid trigger configuration",ws_err_no_defaults:"No quick-complete defaults set",ws_err_self_link_device:"An object cannot be linked to itself",ws_err_too_early:"Too early \u2014 this task can only be completed closer to its due date",ws_err_invalid_search_template:"The search link must be an http(s) URL containing {q}",ws_err_invalid_icon:"The notification icon must be an mdi: name, e.g. mdi:air-filter",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_toggle:"Due at a specific time",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",notes_markdown_hint:"Markdown is supported \u2014 **bold**, lists, [links](\u2026)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",completed_at_optional:"Completed at (optional, empty = now)",completed_at_pick:"Set date & time",completed_at_future_error:"The completion date cannot be in the future.",ha_time_zone_hint:"Time in Home Assistant's time zone ({zone})",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",task_mirror_todo:"Mirror into to-do lists",task_mirror_todo_hint:"The task appears in these lists while it is due; checking it off there completes it here.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",all_priorities:"All priorities",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",object_replaces:"Replaces",object_replaced_by:"Replaced by",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",all_parts:"All parts",all_areas:"All areas",areas_filter:"Filter areas\u2026",areas_filter_none:"No area matches the filter.",area_cost_year:"Cost {year}",area_object_count:"{n} o
Line truncated
|
||||
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",ws_err_not_found:"Not found \u2014 it may have been deleted meanwhile",ws_err_invalid_input:"Invalid input",ws_err_invalid_date:"Invalid date",ws_err_invalid_format:"Invalid format",ws_err_invalid_url:"Invalid link",ws_err_invalid_mirror_todo:"Invalid to-do list",ws_err_not_configured:"Not set up yet",ws_err_not_loaded:"Not loaded yet \u2014 try again in a moment",ws_err_limit_reached:"Limit reached",ws_err_too_many:"Too many entries",ws_err_too_large:"Too large",ws_err_not_archived:"Not archived",ws_err_invalid_target:"Invalid target",ws_err_create_failed:"Could not be created",ws_err_archived:"Archived \u2014 restore it first",ws_err_already_archived:"Already archived",ws_err_unavailable:"Currently unavailable",ws_err_unauthorized:"Not permitted for your user",ws_err_too_many_views:"Too many saved views",ws_err_storage_unavailable:"Storage is not available",ws_err_replace_failed:"Replacement failed",ws_err_not_paused:"Not paused",ws_err_not_available:"Nothing available",ws_err_no_url:"No link given",ws_err_no_phases:"This task has no phases",ws_err_invalid_view:"Invalid view",ws_err_invalid_user:"Unknown user",ws_err_invalid_range:"Invalid range",ws_err_invalid_parent:"Invalid parent object",ws_err_invalid_device:"Unknown device",ws_err_empty_csv:"The CSV file is empty",ws_err_empty:"Nothing to import",ws_err_duplicate_failed:"Could not duplicate",ws_err_already_paused:"Already paused",ws_err_invalid_cursor:"Invalid phase position",ws_err_invalid_entity_slug:"Invalid entity name",ws_err_invalid_trigger_config:"Invalid trigger configuration",ws_err_no_defaults:"No quick-complete defaults set",ws_err_self_link_device:"An object cannot be linked to itself",ws_err_too_early:"Too early \u2014 this task can only be completed closer to its due date",ws_err_invalid_search_template:"The search link must be an http(s) URL containing {q}",ws_err_invalid_icon:"The notification icon must be an mdi: name, e.g. mdi:air-filter",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_toggle:"Due at a specific time",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",notes_markdown_hint:"Markdown is supported \u2014 **bold**, lists, [links](\u2026)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",completed_at_optional:"Completed at (optional, empty = now)",completed_at_pick:"Set date & time",completed_at_future_error:"The completion date cannot be in the future.",ha_time_zone_hint:"Time in Home Assistant's time zone ({zone})",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",task_mirror_todo:"Mirror into to-do lists",task_mirror_todo_hint:"The task appears in these lists while it is due; checking it off there completes it here.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",all_priorities:"All priorities",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",interval_anchor_hint:"From completion date: the next due date counts from the day the task is marked done, so doing it early or late moves the schedule. From planned date: the schedule keeps its dates, for example when a bill is paid weeks before it is due.",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",object_replaces:"Replaces",object_replaced_by:"Replaced by",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Obj
Line truncated
|
||||
.field { display: flex; flex-direction: column; gap: 4px; }
|
||||
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
||||
.field-input {
|
||||
@@ -14,7 +14,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
font-family: inherit; width: 100%; box-sizing: border-box;
|
||||
}
|
||||
.field-input:focus { outline: none; border-color: var(--primary-color); }
|
||||
`,zo=$`
|
||||
`,Fo=$`
|
||||
.person-chip { display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; vertical-align: middle; }
|
||||
.person-avatar {
|
||||
width: 22px; height: 22px; border-radius: 50%; flex: none;
|
||||
@@ -24,7 +24,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.person-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
||||
`,Fo=$`
|
||||
`,Uo=$`
|
||||
.ref-chip {
|
||||
display: inline-block; font-size: 11.5px; font-weight: 500; line-height: 1; padding: 3px 6px;
|
||||
border-radius: 6px; border: 1px solid var(--divider-color); color: var(--secondary-text-color);
|
||||
@@ -34,8 +34,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
/* #189: "· Residual waste, Paper" after a calendar-driven task's name. */
|
||||
.event-titles { color: var(--secondary-text-color); font-weight: 400; }
|
||||
`,ci=$`
|
||||
${zo}
|
||||
${Fo}
|
||||
${Uo}
|
||||
:host {
|
||||
--maint-ok-color: var(--success-color, #4caf50);
|
||||
--maint-due-soon-color: var(--warning-color, #ff9800);
|
||||
@@ -1290,7 +1290,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.stat-item .stat-label { font-size: 11px; white-space: normal; text-align: center; line-height: 1.2; hyphens: auto; overflow-wrap: anywhere; }
|
||||
.stat-value { font-size: 20px; }
|
||||
}
|
||||
`});function an(r,s,e){let t=new Blob([r],{type:e}),i=URL.createObjectURL(t),a=document.createElement("a");a.href=i,a.download=s,a.target="_blank",a.rel="noopener",a.style.display="none",document.body.appendChild(a),a.dispatchEvent(new MouseEvent("click")),document.body.removeChild(a),setTimeout(()=>URL.revokeObjectURL(i),6e4)}var cs=y(()=>{"use strict"});async function Uo(r,s,e=300){return(await r.connection.sendMessagePromise({type:"auth/sign_path",path:s,expires:e})).path}async function ds(r,s,e=300){return Uo(r,`/api/maintenance_supporter/document/${s}`,e)}async function on(r,s,e=""){let t=window.open("about:blank","_blank");try{let i=await ds(r,s);t&&(t.location.href=new URL(i+e,window.location.origin).href)}catch(i){throw t&&t.close(),i}}var ps=y(()=>{"use strict";cs()});function us(r){return r.replace(/[\t\n\r]/g,"").replace(/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g,"")}function hs(r){let s=/^([a-z][a-z0-9+.-]+):/i.exec(us(r||""));return s?s[1].toLowerCase():null}function Ze(r){let s=hs(r);return s!==null&&!Bo.has(s)}function cn(r){return!!r&&/^https?:\/\//i.test(r)}var Bo,di=y(()=>{"use strict";Bo=new Set(["about","blob","data","file","filesystem","javascript","livescript","ms-appinstaller","ms-cxh","ms-cxh-full","ms-msdt","ms-officecmd","search","search-ms","view-source","vbscript"])});function Go(r){let s=(r||"").split(/\s+/).filter(Boolean);return s.length===0?"?":s.length===1?s[0][0].toUpperCase():(s[0][0]+s[s.length-1][0]).toUpperCase()}function Ko(r){let s=0;for(let e of r)s=s*31+e.charCodeAt(0)>>>0;return un[s%un.length]}function ui(r){return r?{id:r.id,name:r.name,initials:r.initials||Go(r.name),color:r.color||Ko(r.id)}:null}function ms(r){return r?l`<span class="person-avatar" style="--person-color: ${r.color}" title=${r.name}>${r.initials}</span>`:p}var un,gs=y(()=>{"use strict";R();un=["#c62828","#ad1457","#6a1b9a","#4527a0","#283593","#1565c0","#00838f","#2e7d32","#558b2f","#ef6c00","#6d4c41","#546e7a"]});var Xe,fs=y(()=>{"use strict";gs();Xe=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}getPerson(s){return ui(this.getUser(s))}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}}});function Yo(r,s){if(s<=0)return 0;let e=typeof r=="number"&&Number.isFinite(r)?Math.trunc(r):0;return e<0?0:e%s}function Qo(r){return!!(r?.phases&&r.phase_sequence&&r.phase_sequence.length>0)}function vs(r){if(!r||!Qo(r))return null;let s=r.phase_sequence,e=Yo(r.phase_cursor,s.length),t=s[e],i=r.phases?.[t];return i?{id:t,name:i.name,index:e,count:s.length,notes:i.notes,checklist:i.checklist!==void 0?i.checklist:r.checklist??[],consumesParts:i.consumes_parts!==void 0?i.consumes_parts:r.consumes_parts??[],requiredFields:i.required_completion_fields!==void 0?i.required_completion_fields:r.required_completion_fields??[]}:null}function ke(r){let s=vs(r);return s?`${s.index+1}/${s.count} \xB7 ${s.name}`:""}var hi=y(()=>{"use strict"});function _n(){let r=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:s=>s.map(()=>Math.floor(Math.random()*256))}).getRandomValues(r),Array.from(r,s=>s.toString(16).padStart(2,"0")).join("")}function $e(r){let s=r?.reading_values;if(!Array.isArray(s))return[];let e=[],t=new Set;for(let i of s){if(!i||typeof i!="object")continue;let a=i;typeof a.id!="string"||!a.id||t.has(a.id)||typeof a.value!="number"||!Number.isFinite(a.value)||(t.add(a.id),e.push({id:a.id,name:typeof a.name=="string"?a.name:a.id,unit:typeof a.unit=="string"?a.unit:null,value:a.value}))}return e}function mn(r){return r.filter(s=>s.type==="completed"&&(s.reading_value!=null||$e(s).length>0)).sort((s,e)=>s.timestamp.localeCompare(e.timestamp))}function gn(r){return mn(r??[]).map(s=>({timestamp:s.timestamp,values:$e(s)})).filter(s=>s.values.length>0)}function fn(r,s,e){let t;for(let i of r){if(e!==void 0){let o=K(i.timestamp);if(!isNaN(o)&&o>=e)break}let a=i.values.find(o=>o.id===s);a&&(t=a)}return t}function vn(r,s,e){let t=$e(s).find(a=>a.id===e);if(!t)return null;let i=null;for(let a of mn(r)){if(aLine truncated
|
||||
`});function on(r,s,e){let t=new Blob([r],{type:e}),i=URL.createObjectURL(t),a=document.createElement("a");a.href=i,a.download=s,a.target="_blank",a.rel="noopener",a.style.display="none",document.body.appendChild(a),a.dispatchEvent(new MouseEvent("click")),document.body.removeChild(a),setTimeout(()=>URL.revokeObjectURL(i),6e4)}var ds=y(()=>{"use strict"});async function Bo(r,s,e=300){return(await r.connection.sendMessagePromise({type:"auth/sign_path",path:s,expires:e})).path}async function ps(r,s,e=300){return Bo(r,`/api/maintenance_supporter/document/${s}`,e)}async function ln(r,s,e=""){let t=window.open("about:blank","_blank");try{let i=await ps(r,s);t&&(t.location.href=new URL(i+e,window.location.origin).href)}catch(i){throw t&&t.close(),i}}var us=y(()=>{"use strict";ds()});function hs(r){return r.replace(/[\t\n\r]/g,"").replace(/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g,"")}function _s(r){let s=/^([a-z][a-z0-9+.-]+):/i.exec(hs(r||""));return s?s[1].toLowerCase():null}function Ze(r){let s=_s(r);return s!==null&&!Wo.has(s)}function dn(r){return!!r&&/^https?:\/\//i.test(r)}var Wo,di=y(()=>{"use strict";Wo=new Set(["about","blob","data","file","filesystem","javascript","livescript","ms-appinstaller","ms-cxh","ms-cxh-full","ms-msdt","ms-officecmd","search","search-ms","view-source","vbscript"])});function Ko(r){let s=(r||"").split(/\s+/).filter(Boolean);return s.length===0?"?":s.length===1?s[0][0].toUpperCase():(s[0][0]+s[s.length-1][0]).toUpperCase()}function Yo(r){let s=0;for(let e of r)s=s*31+e.charCodeAt(0)>>>0;return hn[s%hn.length]}function ui(r){return r?{id:r.id,name:r.name,initials:r.initials||Ko(r.name),color:r.color||Yo(r.id)}:null}function gs(r){return r?l`<span class="person-avatar" style="--person-color: ${r.color}" title=${r.name}>${r.initials}</span>`:p}var hn,fs=y(()=>{"use strict";R();hn=["#c62828","#ad1457","#6a1b9a","#4527a0","#283593","#1565c0","#00838f","#2e7d32","#558b2f","#ef6c00","#6d4c41","#546e7a"]});var Xe,vs=y(()=>{"use strict";fs();Xe=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}getPerson(s){return ui(this.getUser(s))}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}}});function Qo(r,s){if(s<=0)return 0;let e=typeof r=="number"&&Number.isFinite(r)?Math.trunc(r):0;return e<0?0:e%s}function Zo(r){return!!(r?.phases&&r.phase_sequence&&r.phase_sequence.length>0)}function bs(r){if(!r||!Zo(r))return null;let s=r.phase_sequence,e=Qo(r.phase_cursor,s.length),t=s[e],i=r.phases?.[t];return i?{id:t,name:i.name,index:e,count:s.length,notes:i.notes,checklist:i.checklist!==void 0?i.checklist:r.checklist??[],consumesParts:i.consumes_parts!==void 0?i.consumes_parts:r.consumes_parts??[],requiredFields:i.required_completion_fields!==void 0?i.required_completion_fields:r.required_completion_fields??[]}:null}function ke(r){let s=bs(r);return s?`${s.index+1}/${s.count} \xB7 ${s.name}`:""}var hi=y(()=>{"use strict"});function mn(){let r=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:s=>s.map(()=>Math.floor(Math.random()*256))}).getRandomValues(r),Array.from(r,s=>s.toString(16).padStart(2,"0")).join("")}function $e(r){let s=r?.reading_values;if(!Array.isArray(s))return[];let e=[],t=new Set;for(let i of s){if(!i||typeof i!="object")continue;let a=i;typeof a.id!="string"||!a.id||t.has(a.id)||typeof a.value!="number"||!Number.isFinite(a.value)||(t.add(a.id),e.push({id:a.id,name:typeof a.name=="string"?a.name:a.id,unit:typeof a.unit=="string"?a.unit:null,value:a.value}))}return e}function gn(r){return r.filter(s=>s.type==="completed"&&(s.reading_value!=null||$e(s).length>0)).sort((s,e)=>s.timestamp.localeCompare(e.timestamp))}function fn(r){return gn(r??[]).map(s=>({timestamp:s.timestamp,values:$e(s)})).filter(s=>s.values.length>0)}function vn(r,s,e){let t;for(let i of r){if(e!==void 0){let o=K(i.timestamp);if(!isNaN(o)&&o>=e)break}let a=i.values.find(o=>o.id===s);a&&(t=a)}return t}function bn(r,s,e){let t=$e(s).find(a=>a.id===e);if(!t)return null;let i=null;for(let a of gn(r)){if(aLine truncated
|
||||
<div class="field">
|
||||
${this.label?l`<span class="label">${this.label}${this.required?l`<span class="req">*</span>`:p}</span>`:p}
|
||||
<div class="row">
|
||||
@@ -1303,7 +1303,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
@blur=${this._commitTyped} />`:l`<ha-selector
|
||||
.hass=${this.hass}
|
||||
.selector=${this._selector()}
|
||||
.value=${pl(this.kind,this.value)}
|
||||
.value=${_l(this.kind,this.value)}
|
||||
.required=${this.required}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._onSelectorChange}
|
||||
@@ -1411,8 +1411,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.kind.credit.on { background: var(--success-color, #43a047); }
|
||||
.amount { flex: 1; min-width: 0; }
|
||||
.hint { margin-top: 4px; font-size: 12px; color: var(--secondary-text-color); }
|
||||
`],c([f()],Te.prototype,"value",2),c([f()],Te.prototype,"lang",2),c([u()],Te.prototype,"_credit",2),c([u()],Te.prototype,"_amount",2);customElements.get("ms-cost-input")||customElements.define("ms-cost-input",Te)});function wi(){if(window.externalApp!==void 0)return!0;let s=typeof navigator<"u"&&navigator.userAgent||"";return/Home Assistant\//.test(s)&&/Android/.test(s)}var Ss=y(()=>{"use strict"});function jt(r){try{return localStorage.getItem(r)}catch{return null}}function Dt(r,s){try{localStorage.setItem(r,s)}catch{}}var Ae,Ts=y(()=>{"use strict";Ae={objectSections:"msp-object-sections",printOptions:"msp-print-options",batteryRosterOpen:"msp-bf-roster-open",docSort:"msp-doc-sort",cameraLabel:"msp-camera-label",overviewTab:"msp-overview-tab",collapsedSections:"msp-collapsed-sections",chartRange:"msp-chart-range",chartHideOutliers:"msp-chart-hide-outliers",taskSort:"maintenance_supporter_sort",objectSort:"maintenance_supporter_object_sort",groupBy:"maintenance_supporter_groupby",objectView:"maintenance_supporter_object_view",objectsCache:"msp-objects-cache",gettingStartedDismissed:"msp-gs-dismissed",batteryRosterSort:"ms_bf_roster_sort",areaSort:"msp-area-sort"}});function Wn(){if(!wi())return!1;let r=typeof navigator<"u"?navigator.mediaDevices:void 0;return!!r&&typeof r.getUserMedia=="function"}function Fn(r){let s=/camera2?\s*(\d+)/i.exec(r);return s?Number(s[1]):Number.MAX_SAFE_INTEGER}function Un(r,s){if(s){let t=r.find(i=>i.label===s);if(t)return t}return r.filter(t=>t.label&&Vn.test(t.label)).sort((t,i)=>Fn(t.label)-Fn(i.label))[0]??null}var hl,_l,ml,gl,Mn,Vn,zn,Bn,fl,Y,As=y(()=>{"use strict";R();j();C();Ss();Ts();hl=1920,_l=.88,ml={retryMs:500,windowMs:5e3},gl=new Set(["NotReadableError","AbortError","TrackStartError"]),Mn=80,Vn=/back|rear|environment|rück|hinten/i,zn=/front|user|selfie|vorne/i;Bn=r=>r?.name||"Error",fl=r=>r?.message||"",Y=class extends E{constructor(){super(...arguments);this.lang="en";this._open=!1;this._busy=!1;this._switching=!1;this._devices=[];this._deviceIndex=-1;this._switchFailed=!1;this._copied=!1;this.timing={...ml};this._facing="environment";this._stream=null;this._opening=!1;this._gen=0;this._refused=new Set;this._log=[];this._t0=0;this._lastError=""}async open(){if(this._open||this._opening)return;this._opening=!0;let e=++this._gen;try{await this._acquireAndShow(e)}finally{this._opening=!1}}_live(e){return e===this._gen&&this.isConnected}async _acquireAndShow(e){let t=typeof navigator<"u"?navigator.mediaDevices:void 0;if(!t||typeof t.getUserMedia!="function"){this._unavailable("no_media_devices");return}this._log=[],this._t0=Date.now(),this._lastError="",this._refused.clear(),this._switchFailed=!1,this._copied=!1,this._note(navigator.userAgent);let i=jt(Ae.cameraLabel),a=await this._enumerate(t);if(!this._live(e))return;let o=Un(a,i),d="refused";if(o&&(d=await this._openPatiently(t,e,this._byDevice(o))),d==="cancelled")return;if(d!=="ok"){if(d=await this._openPatiently(t,e,{video:{facingMode:{ideal:"environment"}},what:"facing environment"}),d==="cancelled")return;if(d!=="ok"){this._unavailable(this._lastError||"camera_unavailable");return}if(a=await this._enumerate(t),!this._live(e)){this._stopStream();return}}if(this._devices=a,this._deviceIndex=this._indexOfCurrent(),this._facing=this._currentFacing(),this._open=!0,await this.updateComplete,!this._live(e)){this._stopStream(),this._open=!1;return}await this._attach();let h=o?null:Un(a,i),_=this._deviceIndex>=0?a[this._deviceIndex]:void 0;if(!h||h.deviceId===_?.deviceId)return;let m=await this._replace(t,e,[this._byDevice(h)],this._restoreCandidates(_));if(m!=="cancelled"){if(m==="lost"){this._unavailable("camera_lost");return}this._settle(m)}}async _openPatiently(e,t,i){let a=Date.now();for(;;){let o;try{o=await e.getUserMedia({video:i.video,audio:!1})}catch(d){let h=Bn(d),_=fl(d);if(this._lastError=h,this._note(`${i.what} \u2192 ${h}${_&&_!==h?`: ${_}`:""}`),!this._live(t))return"cancelled";if(!gl.has(h))return"refused";if(Date.now()-a+this.timing.retryMs>this.timing.windowMs)return"busy";if(await new Promise(m=>setTimeout(m,this.timing.retryMs)),!this._live(t))return"cancelled";continue}if(!this._live(t)){for(let d of o.getTracks())d.stop();return"cancelled"}return this._stream=o,this._note(`${i.what} \u2192 ok (${this._describeTrack()})`),"ok"}}async _replace(e,t,i,a){this._switching=!0,this._stopStream();try{for(let o of i){let d=await this._openPatiently(e,t,o);if(d==="ok")return o;if(d==="cancelled")return d;if(d==="busy"){o.deviceId&&this._refused.add(o.deviceId);break}}for(let o of a){let d=await this._openPatiently(e,t,o);if(d==="ok")return"restored";if(d==="cancelled")return d}return"lost"}finally{this._switching=!1}}_settle(e){if(e==="restored"){this._switchFailed=!0;let i=this._indexOfCurrent();return i>=0&&(this._deviceIndex=i),this._attach(),!1}this._switchFailed=!1;let t=e.deviceId?this._devices.findIndex(i=>i.deviceId===e.deviceId):-1;return this._deviceIndex=t>=0?t:this._indexOfCurrent(),this._
Line truncated
|
||||
`),t=!1;try{navigator.clipboard?.writeText&&(await navigator.clipboard.writeText(e),t=!0)}catch{}if(!t){let i=this.shadowRoot?.querySelector(".details textarea");if(i){i.focus(),i.select();try{t=document.execCommand("copy")}catch{t=!1}}}this._copied=t}async _shoot(){let e=this._video;if(!(!e||this._busy||this._switching)){this._busy=!0;try{let t=e.videoWidth||640,i=e.videoHeight||480,a=Math.min(1,hl/Math.max(t,i)),o=document.createElement("canvas");o.width=Math.round(t*a),o.height=Math.round(i*a);let d=o.getContext("2d");if(!d)throw new Error("no_canvas");d.drawImage(e,0,0,o.width,o.height);let h=await new Promise(b=>o.toBlob(b,"image/jpeg",_l));if(!h)throw new Error("no_blob");let _=new Date().toISOString().replace(/[-:]/g,"").slice(0,15),m=new File([h],`photo-${_}.jpg`,{type:"image/jpeg"});this.close(),this.dispatchEvent(new CustomEvent("photo-captured",{detail:{file:m},bubbles:!0,composed:!0}))}catch(t){this._unavailable(t instanceof Error?t.message:String(t))}finally{this._busy=!1}}}render(){if(!this._open)return p;let e=this.lang,t=this._busy||this._switching;return l`
|
||||
`],c([f()],Te.prototype,"value",2),c([f()],Te.prototype,"lang",2),c([u()],Te.prototype,"_credit",2),c([u()],Te.prototype,"_amount",2);customElements.get("ms-cost-input")||customElements.define("ms-cost-input",Te)});function wi(){if(window.externalApp!==void 0)return!0;let s=typeof navigator<"u"&&navigator.userAgent||"";return/Home Assistant\//.test(s)&&/Android/.test(s)}var Ts=y(()=>{"use strict"});function jt(r){try{return localStorage.getItem(r)}catch{return null}}function Dt(r,s){try{localStorage.setItem(r,s)}catch{}}var Ae,As=y(()=>{"use strict";Ae={objectSections:"msp-object-sections",printOptions:"msp-print-options",batteryRosterOpen:"msp-bf-roster-open",docSort:"msp-doc-sort",cameraLabel:"msp-camera-label",overviewTab:"msp-overview-tab",collapsedSections:"msp-collapsed-sections",chartRange:"msp-chart-range",chartHideOutliers:"msp-chart-hide-outliers",taskSort:"maintenance_supporter_sort",objectSort:"maintenance_supporter_object_sort",groupBy:"maintenance_supporter_groupby",objectView:"maintenance_supporter_object_view",objectsCache:"msp-objects-cache",gettingStartedDismissed:"msp-gs-dismissed",batteryRosterSort:"ms_bf_roster_sort",areaSort:"msp-area-sort"}});function Vn(){if(!wi())return!1;let r=typeof navigator<"u"?navigator.mediaDevices:void 0;return!!r&&typeof r.getUserMedia=="function"}function Un(r){let s=/camera2?\s*(\d+)/i.exec(r);return s?Number(s[1]):Number.MAX_SAFE_INTEGER}function Bn(r,s){if(s){let t=r.find(i=>i.label===s);if(t)return t}return r.filter(t=>t.label&&Gn.test(t.label)).sort((t,i)=>Un(t.label)-Un(i.label))[0]??null}var gl,fl,vl,bl,zn,Gn,Fn,Wn,yl,Y,Cs=y(()=>{"use strict";R();j();C();Ts();As();gl=1920,fl=.88,vl={retryMs:500,windowMs:5e3},bl=new Set(["NotReadableError","AbortError","TrackStartError"]),zn=80,Gn=/back|rear|environment|rück|hinten/i,Fn=/front|user|selfie|vorne/i;Wn=r=>r?.name||"Error",yl=r=>r?.message||"",Y=class extends E{constructor(){super(...arguments);this.lang="en";this._open=!1;this._busy=!1;this._switching=!1;this._devices=[];this._deviceIndex=-1;this._switchFailed=!1;this._copied=!1;this.timing={...vl};this._facing="environment";this._stream=null;this._opening=!1;this._gen=0;this._refused=new Set;this._log=[];this._t0=0;this._lastError=""}async open(){if(this._open||this._opening)return;this._opening=!0;let e=++this._gen;try{await this._acquireAndShow(e)}finally{this._opening=!1}}_live(e){return e===this._gen&&this.isConnected}async _acquireAndShow(e){let t=typeof navigator<"u"?navigator.mediaDevices:void 0;if(!t||typeof t.getUserMedia!="function"){this._unavailable("no_media_devices");return}this._log=[],this._t0=Date.now(),this._lastError="",this._refused.clear(),this._switchFailed=!1,this._copied=!1,this._note(navigator.userAgent);let i=jt(Ae.cameraLabel),a=await this._enumerate(t);if(!this._live(e))return;let o=Bn(a,i),d="refused";if(o&&(d=await this._openPatiently(t,e,this._byDevice(o))),d==="cancelled")return;if(d!=="ok"){if(d=await this._openPatiently(t,e,{video:{facingMode:{ideal:"environment"}},what:"facing environment"}),d==="cancelled")return;if(d!=="ok"){this._unavailable(this._lastError||"camera_unavailable");return}if(a=await this._enumerate(t),!this._live(e)){this._stopStream();return}}if(this._devices=a,this._deviceIndex=this._indexOfCurrent(),this._facing=this._currentFacing(),this._open=!0,await this.updateComplete,!this._live(e)){this._stopStream(),this._open=!1;return}await this._attach();let h=o?null:Bn(a,i),_=this._deviceIndex>=0?a[this._deviceIndex]:void 0;if(!h||h.deviceId===_?.deviceId)return;let m=await this._replace(t,e,[this._byDevice(h)],this._restoreCandidates(_));if(m!=="cancelled"){if(m==="lost"){this._unavailable("camera_lost");return}this._settle(m)}}async _openPatiently(e,t,i){let a=Date.now();for(;;){let o;try{o=await e.getUserMedia({video:i.video,audio:!1})}catch(d){let h=Wn(d),_=yl(d);if(this._lastError=h,this._note(`${i.what} \u2192 ${h}${_&&_!==h?`: ${_}`:""}`),!this._live(t))return"cancelled";if(!bl.has(h))return"refused";if(Date.now()-a+this.timing.retryMs>this.timing.windowMs)return"busy";if(await new Promise(m=>setTimeout(m,this.timing.retryMs)),!this._live(t))return"cancelled";continue}if(!this._live(t)){for(let d of o.getTracks())d.stop();return"cancelled"}return this._stream=o,this._note(`${i.what} \u2192 ok (${this._describeTrack()})`),"ok"}}async _replace(e,t,i,a){this._switching=!0,this._stopStream();try{for(let o of i){let d=await this._openPatiently(e,t,o);if(d==="ok")return o;if(d==="cancelled")return d;if(d==="busy"){o.deviceId&&this._refused.add(o.deviceId);break}}for(let o of a){let d=await this._openPatiently(e,t,o);if(d==="ok")return"restored";if(d==="cancelled")return d}return"lost"}finally{this._switching=!1}}_settle(e){if(e==="restored"){this._switchFailed=!0;let i=this._indexOfCurrent();return i>=0&&(this._deviceIndex=i),this._attach(),!1}this._switchFailed=!1;let t=e.deviceId?this._devices.findIndex(i=>i.deviceId===e.deviceId):-1;return this._deviceIndex=t>=0?t:this._indexOfCurrent(),this._
Line truncated
|
||||
`),t=!1;try{navigator.clipboard?.writeText&&(await navigator.clipboard.writeText(e),t=!0)}catch{}if(!t){let i=this.shadowRoot?.querySelector(".details textarea");if(i){i.focus(),i.select();try{t=document.execCommand("copy")}catch{t=!1}}}this._copied=t}async _shoot(){let e=this._video;if(!(!e||this._busy||this._switching)){this._busy=!0;try{let t=e.videoWidth||640,i=e.videoHeight||480,a=Math.min(1,gl/Math.max(t,i)),o=document.createElement("canvas");o.width=Math.round(t*a),o.height=Math.round(i*a);let d=o.getContext("2d");if(!d)throw new Error("no_canvas");d.drawImage(e,0,0,o.width,o.height);let h=await new Promise(b=>o.toBlob(b,"image/jpeg",fl));if(!h)throw new Error("no_blob");let _=new Date().toISOString().replace(/[-:]/g,"").slice(0,15),m=new File([h],`photo-${_}.jpg`,{type:"image/jpeg"});this.close(),this.dispatchEvent(new CustomEvent("photo-captured",{detail:{file:m},bubbles:!0,composed:!0}))}catch(t){this._unavailable(t instanceof Error?t.message:String(t))}finally{this._busy=!1}}}render(){if(!this._open)return p;let e=this.lang,t=this._busy||this._switching;return l`
|
||||
<div class="overlay" role="dialog" aria-modal="true" aria-label=${n("doc_camera",e)}>
|
||||
<video autoplay playsinline muted></video>
|
||||
${this._switching?l`<div class="switching" role="status">${n("camera_switching",e)}</div>`:p}
|
||||
@@ -1477,7 +1477,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.shoot { background: var(--primary-color, #03a9f4); color: #fff; border: none; font-weight: 600; }
|
||||
.shoot[disabled] { opacity: 0.6; cursor: default; }
|
||||
.shoot ha-icon { --mdc-icon-size: 22px; }
|
||||
`,c([f({type:String})],Y.prototype,"lang",2),c([u()],Y.prototype,"_open",2),c([u()],Y.prototype,"_busy",2),c([u()],Y.prototype,"_switching",2),c([u()],Y.prototype,"_devices",2),c([u()],Y.prototype,"_deviceIndex",2),c([u()],Y.prototype,"_switchFailed",2),c([u()],Y.prototype,"_copied",2);customElements.get("ms-camera-capture")||customElements.define("ms-camera-capture",Y)});var ki,Q,qt=y(()=>{"use strict";R();j();C();Ss();As();As();ki=$`
|
||||
`,c([f({type:String})],Y.prototype,"lang",2),c([u()],Y.prototype,"_open",2),c([u()],Y.prototype,"_busy",2),c([u()],Y.prototype,"_switching",2),c([u()],Y.prototype,"_devices",2),c([u()],Y.prototype,"_deviceIndex",2),c([u()],Y.prototype,"_switchFailed",2),c([u()],Y.prototype,"_copied",2);customElements.get("ms-camera-capture")||customElements.define("ms-camera-capture",Y)});var ki,Q,qt=y(()=>{"use strict";R();j();C();Ts();Cs();Cs();ki=$`
|
||||
ms-photo-picker { display: contents; }
|
||||
.photo-pickers {
|
||||
display: flex;
|
||||
@@ -1506,7 +1506,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
color: var(--secondary-text-color);
|
||||
margin-top: 4px;
|
||||
}
|
||||
`,Q=class extends E{constructor(){super(...arguments);this.lang="en";this.disabled=!1;this.busy=!1;this.accept="image/*";this.showCamera=!0;this.showGallery=!0;this.compact=!1;this.remaining=1/0;this._singlePick=wi();this._inAppCamera=Wn()}createRenderRoot(){return this}get _locked(){return this.disabled||this.busy}_emit(e){e.length!==0&&this.dispatchEvent(new CustomEvent("files-picked",{detail:{files:e},bubbles:!0,composed:!0}))}_onInput(e){let t=e.target,i=Array.from(t.files??[]);t.value="",this._emit(i)}_onCameraClick(e){!this._inAppCamera||this._locked||(e.preventDefault(),this.querySelector("ms-camera-capture")?.open())}_onCameraUnavailable(){this._inAppCamera=!1,this.querySelector(".photo-pick-camera input")?.click()}_onKeydown(e){e.key!=="Enter"&&e.key!==" "||(e.preventDefault(),!this._locked&&e.currentTarget.click())}render(){if(this.remaining<=0||!this.showCamera&&!this.showGallery)return p;let e=this.lang,t=this._locked?"disabled":"",i=this.busy?n("uploading",e):n("doc_camera",e),a=n(this._singlePick?"choose_photo":"choose_photos",e);return l`
|
||||
`,Q=class extends E{constructor(){super(...arguments);this.lang="en";this.disabled=!1;this.busy=!1;this.accept="image/*";this.showCamera=!0;this.showGallery=!0;this.compact=!1;this.remaining=1/0;this._singlePick=wi();this._inAppCamera=Vn()}createRenderRoot(){return this}get _locked(){return this.disabled||this.busy}_emit(e){e.length!==0&&this.dispatchEvent(new CustomEvent("files-picked",{detail:{files:e},bubbles:!0,composed:!0}))}_onInput(e){let t=e.target,i=Array.from(t.files??[]);t.value="",this._emit(i)}_onCameraClick(e){!this._inAppCamera||this._locked||(e.preventDefault(),this.querySelector("ms-camera-capture")?.open())}_onCameraUnavailable(){this._inAppCamera=!1,this.querySelector(".photo-pick-camera input")?.click()}_onKeydown(e){e.key!=="Enter"&&e.key!==" "||(e.preventDefault(),!this._locked&&e.currentTarget.click())}render(){if(this.remaining<=0||!this.showCamera&&!this.showGallery)return p;let e=this.lang,t=this._locked?"disabled":"",i=this.busy?n("uploading",e):n("doc_camera",e),a=n(this._singlePick?"choose_photo":"choose_photos",e);return l`
|
||||
<div class="photo-pickers">
|
||||
${this.showCamera?l`<label class="photo-pick photo-pick-camera ${t}" role="button" tabindex="0"
|
||||
aria-label=${i} title=${this.compact?i:p}
|
||||
@@ -1529,7 +1529,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
${this.showCamera&&this._inAppCamera?l`<ms-camera-capture .lang=${e}
|
||||
@photo-captured=${o=>this._emit([o.detail.file])}
|
||||
@capture-unavailable=${this._onCameraUnavailable}></ms-camera-capture>`:p}
|
||||
`}};c([f({type:String})],Q.prototype,"lang",2),c([f({type:Boolean})],Q.prototype,"disabled",2),c([f({type:Boolean})],Q.prototype,"busy",2),c([f({type:String})],Q.prototype,"accept",2),c([f({type:Boolean})],Q.prototype,"showCamera",2),c([f({type:Boolean})],Q.prototype,"showGallery",2),c([f({type:Boolean})],Q.prototype,"compact",2),c([f({type:Number})],Q.prototype,"remaining",2),c([u()],Q.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",Q)});var lt,S,Cs=y(()=>{"use strict";R();j();De();C();Se();ee();Ot();_i();xs();ks();Es();yi();ot();xi();qt();qt();lt=Ee,S=class extends E{constructor(){super(...arguments);this.entryId="";this.taskId="";this.taskName="";this.lang="en";this.checklist=[];this.adaptiveEnabled=!1;this.taskType="";this.readingUnit="";this.readings=[];this.readingHistory=[];this.restockDefault=null;this.restockUnitCost=null;this.restockPackage="";this.currencySymbol="";this.partsCostMode="purchase";this.parts=[];this.consumesParts=[];this.consumesInfo=[];this.requiredFields=[];this.phaseLabel="";this.requireTagScan=!1;this.viaTagScan=!1;this._open=!1;this._notes="";this._cost="";this._duration="";this._loading=!1;this._error="";this._checklistState={};this._feedback="needed";this._photos=new rt(this,{entryId:()=>this.entryId,hass:()=>this.hass});this._readingValue="";this._readingValues={};this._restockQty="";this._completedAt="";this._usedParts={};this._usedQtyText={};this.checklistPrefill={}}open(e={}){this._open||(this._open=!0,this.viaTagScan=!!e.viaTagScan,this._notes="",this._cost="",this._duration="",this._error="",this._checklistState=Object.fromEntries(this.checklist.map((t,i)=>[String(i),!!this.checklistPrefill[t]]).filter(([,t])=>t)),this._feedback="needed",this._photos.reset(),this._readingValue="",this._readingValues={},this._restockQty=this.restockDefault!==null?String(this.restockDefault):"",this._completedAt="",this._usedParts=Object.fromEntries(this.consumesParts.map(t=>[ne(t),{...t}])),this._usedQtyText={})}_rangeError(e,t){let i=this.lang;return n("settings_value_out_of_range",i).replace("{min}",I(e,i,{maximumFractionDigits:2})).replace("{max}",I(t,i,{maximumFractionDigits:2}))}_toggleCheck(e){let t=String(e);this._checklistState={...this._checklistState,[t]:!this._checklistState[t]}}_setFeedback(e){this._feedback=e}async _complete(){if(this._loading||this._photos.uploading)return;this._error="",this._photos.clearError();let e={type:"maintenance_supporter/task/complete",entry_id:this.entryId,task_id:this.taskId},t=this._notes.trim();if(t&&(e.notes=t),this._cost){let d=parseFloat(this._cost);isNaN(d)||(e.cost=d)}let i=nt(this._duration);if(i!==null&&(e.duration=i),this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photos.photos.length>0&&(e.photo_doc_ids=this._photos.ids),this.viaTagScan&&(e.via_tag_scan=!0),this._completedAt){if(K(this._completedAt)>Date.now()){this._error=n("completed_at_future_error",this.lang);return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let d={};for(let h of this.readings){let _=(this._readingValues[h.id]??"").trim();if(_==="")continue;let m=parseFloat(_.replace(",","."));isNaN(m)||(d[h.id]=m)}Object.keys(d).length>0&&(e.reading_values=d)}else if(this._readingValue!==""){let d=parseFloat(this._readingValue);isNaN(d)||(e.reading_value=d)}if(this.restockDefault!==null&&this._restockQty.trim()!==""){let d=parseFloat(this._restockQty.replace(",","."));if(!Number.isFinite(d)||d<tt[0]||d>tt[1]){this._error=this._rangeError(...tt);return}e.restock_quantity=d}if(this.parts.length>0){let d=[];for(let[h,_]of Object.entries(this._usedParts)){let m=this._usedQtyText[h],b=m===void 0?_.quantity:parseFloat(m.replace(",","."));if(!Number.isFinite(b)||b<lt[0]||b>lt[1]){this._error=this._rangeError(...lt);return}d.push({..._,quantity:b})}e.used_parts=d.map(h=>h.entry_id?{part_id:h.part_id,quantity:h.quantity,entry_id:h.entry_id}:{part_id:h.part_id,quantity:h.quantity})}let a=await D(this,e,{busy:d=>{this._loading=d},lang:this.lang,fallbackKey:"save_error",onError:d=>{this._error=d}});if(a===void 0)return;this._photos.markAttached(),this._open=!1;let o={entryId:this.entryId,taskId:this.taskId,taskName:this.taskName,undo:a?.undo===!0};this.dispatchEvent(new CustomEvent("task-completed",{detail:o}))}_renderReadingField(e,t){let i=this._completedAt?K(this._completedAt):NaN,a=fn(this.readingHistory,e.id,isNaN(i)?void 0:i),o=e.unit||this.readingUnit,d=(this._readingValues[e.id]??"").trim(),h=d===""?NaN:parseFloat(d.replace(",",".")),_=a!==void 0&&!isNaN(h)&&h<a.value,m=a!==void 0?I(a.value,t,{maximumFractionDigits:3}):"";return l`
|
||||
`}};c([f({type:String})],Q.prototype,"lang",2),c([f({type:Boolean})],Q.prototype,"disabled",2),c([f({type:Boolean})],Q.prototype,"busy",2),c([f({type:String})],Q.prototype,"accept",2),c([f({type:Boolean})],Q.prototype,"showCamera",2),c([f({type:Boolean})],Q.prototype,"showGallery",2),c([f({type:Boolean})],Q.prototype,"compact",2),c([f({type:Number})],Q.prototype,"remaining",2),c([u()],Q.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",Q)});var lt,S,Rs=y(()=>{"use strict";R();j();De();C();Se();ee();Ot();_i();ws();$s();Ss();yi();ot();xi();qt();qt();lt=Ee,S=class extends E{constructor(){super(...arguments);this.entryId="";this.taskId="";this.taskName="";this.lang="en";this.checklist=[];this.adaptiveEnabled=!1;this.taskType="";this.readingUnit="";this.readings=[];this.readingHistory=[];this.restockDefault=null;this.restockUnitCost=null;this.restockPackage="";this.currencySymbol="";this.partsCostMode="purchase";this.parts=[];this.consumesParts=[];this.consumesInfo=[];this.requiredFields=[];this.phaseLabel="";this.requireTagScan=!1;this.viaTagScan=!1;this._open=!1;this._notes="";this._cost="";this._duration="";this._loading=!1;this._error="";this._checklistState={};this._feedback="needed";this._photos=new rt(this,{entryId:()=>this.entryId,hass:()=>this.hass});this._readingValue="";this._readingValues={};this._restockQty="";this._completedAt="";this._usedParts={};this._usedQtyText={};this.checklistPrefill={}}open(e={}){this._open||(this._open=!0,this.viaTagScan=!!e.viaTagScan,this._notes="",this._cost="",this._duration="",this._error="",this._checklistState=Object.fromEntries(this.checklist.map((t,i)=>[String(i),!!this.checklistPrefill[t]]).filter(([,t])=>t)),this._feedback="needed",this._photos.reset(),this._readingValue="",this._readingValues={},this._restockQty=this.restockDefault!==null?String(this.restockDefault):"",this._completedAt="",this._usedParts=Object.fromEntries(this.consumesParts.map(t=>[ne(t),{...t}])),this._usedQtyText={})}_rangeError(e,t){let i=this.lang;return n("settings_value_out_of_range",i).replace("{min}",I(e,i,{maximumFractionDigits:2})).replace("{max}",I(t,i,{maximumFractionDigits:2}))}_toggleCheck(e){let t=String(e);this._checklistState={...this._checklistState,[t]:!this._checklistState[t]}}_setFeedback(e){this._feedback=e}async _complete(){if(this._loading||this._photos.uploading)return;this._error="",this._photos.clearError();let e={type:"maintenance_supporter/task/complete",entry_id:this.entryId,task_id:this.taskId},t=this._notes.trim();if(t&&(e.notes=t),this._cost){let d=parseFloat(this._cost);isNaN(d)||(e.cost=d)}let i=nt(this._duration);if(i!==null&&(e.duration=i),this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photos.photos.length>0&&(e.photo_doc_ids=this._photos.ids),this.viaTagScan&&(e.via_tag_scan=!0),this._completedAt){if(K(this._completedAt)>Date.now()){this._error=n("completed_at_future_error",this.lang);return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let d={};for(let h of this.readings){let _=(this._readingValues[h.id]??"").trim();if(_==="")continue;let m=parseFloat(_.replace(",","."));isNaN(m)||(d[h.id]=m)}Object.keys(d).length>0&&(e.reading_values=d)}else if(this._readingValue!==""){let d=parseFloat(this._readingValue);isNaN(d)||(e.reading_value=d)}if(this.restockDefault!==null&&this._restockQty.trim()!==""){let d=parseFloat(this._restockQty.replace(",","."));if(!Number.isFinite(d)||d<tt[0]||d>tt[1]){this._error=this._rangeError(...tt);return}e.restock_quantity=d}if(this.parts.length>0){let d=[];for(let[h,_]of Object.entries(this._usedParts)){let m=this._usedQtyText[h],b=m===void 0?_.quantity:parseFloat(m.replace(",","."));if(!Number.isFinite(b)||b<lt[0]||b>lt[1]){this._error=this._rangeError(...lt);return}d.push({..._,quantity:b})}e.used_parts=d.map(h=>h.entry_id?{part_id:h.part_id,quantity:h.quantity,entry_id:h.entry_id}:{part_id:h.part_id,quantity:h.quantity})}let a=await D(this,e,{busy:d=>{this._loading=d},lang:this.lang,fallbackKey:"save_error",onError:d=>{this._error=d}});if(a===void 0)return;this._photos.markAttached(),this._open=!1;let o={entryId:this.entryId,taskId:this.taskId,taskName:this.taskName,undo:a?.undo===!0};this.dispatchEvent(new CustomEvent("task-completed",{detail:o}))}_renderReadingField(e,t){let i=this._completedAt?K(this._completedAt):NaN,a=vn(this.readingHistory,e.id,isNaN(i)?void 0:i),o=e.unit||this.readingUnit,d=(this._readingValues[e.id]??"").trim(),h=d===""?NaN:parseFloat(d.replace(",",".")),_=a!==void 0&&!isNaN(h)&&h<a.value,m=a!==void 0?I(a.value,t,{maximumFractionDigits:3}):"";return l`
|
||||
<label class="field reading-field">
|
||||
<span class="field-label">${e.name}${o?` (${o})`:""}</span>
|
||||
<input type="text" inputmode="decimal" class="field-input"
|
||||
@@ -1537,11 +1537,11 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._readingValues[e.id]??""}
|
||||
@input=${b=>{this._readingValues={...this._readingValues,[e.id]:b.target.value}}} />
|
||||
${_?l`<span class="reading-warn">${n("reading_below_last",t).replace("{value}",m)}</span>`:p}
|
||||
</label>`}get _missingRequired(){let e={notes:this._notes.trim()!=="",cost:this._cost.trim()!=="",duration:this._duration.trim()!=="",photo:this._photos.photos.length>0,user:!!this.hass?.user};return this.requiredFields.filter(t=>!e[t])}_demands(e){return this.requiredFields.includes(e)}_req(e){return this._demands(e)?l`<span class="req-mark" aria-hidden="true">*</span>`:p}_purchaseSuggestion(){if(this.restockDefault===null)return null;let e=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(e)||e<=0?null:Math.round(this.restockUnitCost*e*100)/100}_partsValue(){if(this.restockDefault!==null||!this.parts.length)return null;let e=0,t=!1;for(let i of Object.values(this._usedParts)){let a=this.parts.find(d=>ne({part_id:d.id,entry_id:d.entry_id})===ne(i)),o=Cn(a);o!==null&&(e+=o*(i.quantity||1),t=!0)}return t?Math.round(e*100)/100:null}_renderCostSuggestion(e){let t=this._purchaseSuggestion();if(this.restockDefault!==null){let d=this.partsCostMode==="use"?l`<div class="cost-note">${n("cost_purchase_use_hint",e)}</div>`:p;if(this._cost.trim()!==""||t==null||t<=0)return d;let h=re(t,this.currencySymbol,e);return l`<button
|
||||
</label>`}get _missingRequired(){let e={notes:this._notes.trim()!=="",cost:this._cost.trim()!=="",duration:this._duration.trim()!=="",photo:this._photos.photos.length>0,user:!!this.hass?.user};return this.requiredFields.filter(t=>!e[t])}_demands(e){return this.requiredFields.includes(e)}_req(e){return this._demands(e)?l`<span class="req-mark" aria-hidden="true">*</span>`:p}_purchaseSuggestion(){if(this.restockDefault===null)return null;let e=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(e)||e<=0?null:Math.round(this.restockUnitCost*e*100)/100}_partsValue(){if(this.restockDefault!==null||!this.parts.length)return null;let e=0,t=!1;for(let i of Object.values(this._usedParts)){let a=this.parts.find(d=>ne({part_id:d.id,entry_id:d.entry_id})===ne(i)),o=Rn(a);o!==null&&(e+=o*(i.quantity||1),t=!0)}return t?Math.round(e*100)/100:null}_renderCostSuggestion(e){let t=this._purchaseSuggestion();if(this.restockDefault!==null){let d=this.partsCostMode==="use"?l`<div class="cost-note">${n("cost_purchase_use_hint",e)}</div>`:p;if(this._cost.trim()!==""||t==null||t<=0)return d;let h=re(t,this.currencySymbol,e);return l`<button
|
||||
type="button"
|
||||
class="cost-suggestion"
|
||||
@click=${()=>this._cost=String(Math.round(t*100)/100)}
|
||||
>${n("cost_from_parts",e).replace("{amount}",h)}</button>${d}`}let i=this._partsValue();if(i==null||i<=0)return p;let a=re(i,this.currencySymbol,e),o=this.partsCostMode==="use"?"cost_parts_booked":"cost_parts_info";return l`<div class="cost-note">${n(o,e).replace("{amount}",a)}</div>`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=`${Br()}:00`}render(){if(!this._open)return l``;let e=this.lang||this.hass?.language||"en",t=this._error||this._photos.errorText(e);return l`
|
||||
>${n("cost_from_parts",e).replace("{amount}",h)}</button>${d}`}let i=this._partsValue();if(i==null||i<=0)return p;let a=re(i,this.currencySymbol,e),o=this.partsCostMode==="use"?"cost_parts_booked":"cost_parts_info";return l`<div class="cost-note">${n(o,e).replace("{amount}",a)}</div>`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=`${Wr()}:00`}render(){if(!this._open)return l``;let e=this.lang||this.hass?.language||"en",t=this._error||this._photos.errorText(e);return l`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${n("complete_title",e)}${this.taskName}</div>
|
||||
${this.phaseLabel?l`<div class="phase-line">${n("phase_current",e)}: ${this.phaseLabel}</div>`:p}
|
||||
@@ -1897,7 +1897,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
color: var(--text-primary-color, #fff);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
`],c([f({attribute:!1})],S.prototype,"hass",2),c([f()],S.prototype,"entryId",2),c([f()],S.prototype,"taskId",2),c([f()],S.prototype,"taskName",2),c([f()],S.prototype,"lang",2),c([f({type:Array})],S.prototype,"checklist",2),c([f({type:Boolean})],S.prototype,"adaptiveEnabled",2),c([f()],S.prototype,"taskType",2),c([f()],S.prototype,"readingUnit",2),c([f({attribute:!1})],S.prototype,"readings",2),c([f({attribute:!1})],S.prototype,"readingHistory",2),c([f({attribute:!1})],S.prototype,"restockDefault",2),c([f({attribute:!1})],S.prototype,"restockUnitCost",2),c([f({attribute:!1})],S.prototype,"restockPackage",2),c([f()],S.prototype,"currencySymbol",2),c([f({attribute:!1})],S.prototype,"partsCostMode",2),c([f({attribute:!1})],S.prototype,"parts",2),c([f({attribute:!1})],S.prototype,"consumesParts",2),c([f({type:Array})],S.prototype,"consumesInfo",2),c([f({type:Array})],S.prototype,"requiredFields",2),c([f()],S.prototype,"phaseLabel",2),c([f({type:Boolean})],S.prototype,"requireTagScan",2),c([f({type:Boolean})],S.prototype,"viaTagScan",2),c([u()],S.prototype,"_open",2),c([u()],S.prototype,"_notes",2),c([u()],S.prototype,"_cost",2),c([u()],S.prototype,"_duration",2),c([u()],S.prototype,"_loading",2),c([u()],S.prototype,"_error",2),c([u()],S.prototype,"_checklistState",2),c([u()],S.prototype,"_feedback",2),c([u()],S.prototype,"_readingValue",2),c([u()],S.prototype,"_readingValues",2),c([u()],S.prototype,"_restockQty",2),c([u()],S.prototype,"_completedAt",2),c([u()],S.prototype,"_usedParts",2),c([u()],S.prototype,"_usedQtyText",2),c([f({attribute:!1})],S.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",S)});function A(r){return r.toFixed(1)}var $i=y(()=>{"use strict";C();ee()});var q,Is=y(()=>{"use strict";R();j();q=class extends E{constructor(){super(...arguments);this.label="";this.value="";this.placeholder="";this.type="text";this.required=!1;this.disabled=!1;this.multiline=!1;this.rows=3}_onInput(e){let t=e.target.value;this.value=t,this.dispatchEvent(new CustomEvent("input",{bubbles:!0,composed:!0,detail:{value:t}}))}render(){return l`
|
||||
`],c([f({attribute:!1})],S.prototype,"hass",2),c([f()],S.prototype,"entryId",2),c([f()],S.prototype,"taskId",2),c([f()],S.prototype,"taskName",2),c([f()],S.prototype,"lang",2),c([f({type:Array})],S.prototype,"checklist",2),c([f({type:Boolean})],S.prototype,"adaptiveEnabled",2),c([f()],S.prototype,"taskType",2),c([f()],S.prototype,"readingUnit",2),c([f({attribute:!1})],S.prototype,"readings",2),c([f({attribute:!1})],S.prototype,"readingHistory",2),c([f({attribute:!1})],S.prototype,"restockDefault",2),c([f({attribute:!1})],S.prototype,"restockUnitCost",2),c([f({attribute:!1})],S.prototype,"restockPackage",2),c([f()],S.prototype,"currencySymbol",2),c([f({attribute:!1})],S.prototype,"partsCostMode",2),c([f({attribute:!1})],S.prototype,"parts",2),c([f({attribute:!1})],S.prototype,"consumesParts",2),c([f({type:Array})],S.prototype,"consumesInfo",2),c([f({type:Array})],S.prototype,"requiredFields",2),c([f()],S.prototype,"phaseLabel",2),c([f({type:Boolean})],S.prototype,"requireTagScan",2),c([f({type:Boolean})],S.prototype,"viaTagScan",2),c([u()],S.prototype,"_open",2),c([u()],S.prototype,"_notes",2),c([u()],S.prototype,"_cost",2),c([u()],S.prototype,"_duration",2),c([u()],S.prototype,"_loading",2),c([u()],S.prototype,"_error",2),c([u()],S.prototype,"_checklistState",2),c([u()],S.prototype,"_feedback",2),c([u()],S.prototype,"_readingValue",2),c([u()],S.prototype,"_readingValues",2),c([u()],S.prototype,"_restockQty",2),c([u()],S.prototype,"_completedAt",2),c([u()],S.prototype,"_usedParts",2),c([u()],S.prototype,"_usedQtyText",2),c([f({attribute:!1})],S.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",S)});function A(r){return r.toFixed(1)}var $i=y(()=>{"use strict";C();ee()});var q,Ps=y(()=>{"use strict";R();j();q=class extends E{constructor(){super(...arguments);this.label="";this.value="";this.placeholder="";this.type="text";this.required=!1;this.disabled=!1;this.multiline=!1;this.rows=3}_onInput(e){let t=e.target.value;this.value=t,this.dispatchEvent(new CustomEvent("input",{bubbles:!0,composed:!0,detail:{value:t}}))}render(){return l`
|
||||
<label class="field">
|
||||
${this.label?l`<span class="label">${this.label}${this.required?l`<span class="req">*</span>`:p}</span>`:p}
|
||||
${this.multiline?l`
|
||||
@@ -1974,7 +1974,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
color: var(--secondary-text-color);
|
||||
font-style: italic;
|
||||
}
|
||||
`,c([f()],q.prototype,"label",2),c([f()],q.prototype,"value",2),c([f()],q.prototype,"placeholder",2),c([f()],q.prototype,"type",2),c([f({type:Boolean})],q.prototype,"required",2),c([f({type:Boolean})],q.prototype,"disabled",2),c([f()],q.prototype,"step",2),c([f()],q.prototype,"min",2),c([f()],q.prototype,"max",2),c([f()],q.prototype,"pattern",2),c([f()],q.prototype,"helper",2),c([f({type:Boolean})],q.prototype,"multiline",2),c([f({type:Number})],q.prototype,"rows",2);customElements.get("ms-textfield")||customElements.define("ms-textfield",q)});var L,Kn=y(()=>{"use strict";R();j();C();Se();Is();ot();L=class extends E{constructor(){super(...arguments);this.objects=[];this.placesEnabled=!1;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._place="";this._remindOnSite=!1;this._entryId=null;this._replacing=!1;this._oldDeviceId="";this._replaceDevice="keep"}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._place="",this._remindOnSite=!1,this._replacing=!1,this._error="",this._open=!0}openReplace(e,t){this._entryId=e,this._replacing=!0,this._name=t.name||"",this._oldDeviceId=t.ha_device_id||"",this._haDeviceId="",this._replaceDevice="keep",this._error="",this._open=!0}openEdit(e,t){this._entryId=e,this._name=t.name||"",this._manufacturer=t.manufacturer||"",this._model=t.model||"",this._serialNumber=t.serial_number||"",this._areaId=t.area_id||"",this._installationDate=t.installation_date||"",this._warrantyExpiry=t.warranty_expiry||"",this._documentationUrl=t.documentation_url||"",this._notes=t.notes||"",this._haDeviceId=t.ha_device_id||"",this._parentEntryId=t.parent_entry_id||"",this._place=t.place||"",this._remindOnSite=!!t.remind_on_site,this._replacing=!1,this._error="",this._open=!0}async _replace(){if(this._loading||!this._entryId)return;let e={type:"maintenance_supporter/object/replace",entry_id:this._entryId,name:this._name.trim()||null};this._oldDeviceId?(this._replaceDevice==="other"&&(e.ha_device_id=this._haDeviceId),this._replaceDevice==="none"&&(e.ha_device_id=null)):this._haDeviceId&&(e.ha_device_id=this._haDeviceId);let t=await D(this,e,{busy:i=>{this._loading=i},fallbackKey:"save_error",onError:i=>{this._error=i}});t!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("object-replaced",{detail:{entry_id:t?.entry_id,device_swap:t?.device_swap}})))}_deviceName(e){let i=this.hass?.devices?.[e];return i?.name_by_user||i?.name||e}_deviceSelector(e){return l`<ha-form
|
||||
`,c([f()],q.prototype,"label",2),c([f()],q.prototype,"value",2),c([f()],q.prototype,"placeholder",2),c([f()],q.prototype,"type",2),c([f({type:Boolean})],q.prototype,"required",2),c([f({type:Boolean})],q.prototype,"disabled",2),c([f()],q.prototype,"step",2),c([f()],q.prototype,"min",2),c([f()],q.prototype,"max",2),c([f()],q.prototype,"pattern",2),c([f()],q.prototype,"helper",2),c([f({type:Boolean})],q.prototype,"multiline",2),c([f({type:Number})],q.prototype,"rows",2);customElements.get("ms-textfield")||customElements.define("ms-textfield",q)});var L,Yn=y(()=>{"use strict";R();j();C();Se();Ps();ot();L=class extends E{constructor(){super(...arguments);this.objects=[];this.placesEnabled=!1;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._place="";this._remindOnSite=!1;this._entryId=null;this._replacing=!1;this._oldDeviceId="";this._replaceDevice="keep"}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._place="",this._remindOnSite=!1,this._replacing=!1,this._error="",this._open=!0}openReplace(e,t){this._entryId=e,this._replacing=!0,this._name=t.name||"",this._oldDeviceId=t.ha_device_id||"",this._haDeviceId="",this._replaceDevice="keep",this._error="",this._open=!0}openEdit(e,t){this._entryId=e,this._name=t.name||"",this._manufacturer=t.manufacturer||"",this._model=t.model||"",this._serialNumber=t.serial_number||"",this._areaId=t.area_id||"",this._installationDate=t.installation_date||"",this._warrantyExpiry=t.warranty_expiry||"",this._documentationUrl=t.documentation_url||"",this._notes=t.notes||"",this._haDeviceId=t.ha_device_id||"",this._parentEntryId=t.parent_entry_id||"",this._place=t.place||"",this._remindOnSite=!!t.remind_on_site,this._replacing=!1,this._error="",this._open=!0}async _replace(){if(this._loading||!this._entryId)return;let e={type:"maintenance_supporter/object/replace",entry_id:this._entryId,name:this._name.trim()||null};this._oldDeviceId?(this._replaceDevice==="other"&&(e.ha_device_id=this._haDeviceId),this._replaceDevice==="none"&&(e.ha_device_id=null)):this._haDeviceId&&(e.ha_device_id=this._haDeviceId);let t=await D(this,e,{busy:i=>{this._loading=i},fallbackKey:"save_error",onError:i=>{this._error=i}});t!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("object-replaced",{detail:{entry_id:t?.entry_id,device_swap:t?.device_swap}})))}_deviceName(e){let i=this.hass?.devices?.[e];return i?.name_by_user||i?.name||e}_deviceSelector(e){return l`<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${{device:this._haDeviceId||void 0}}
|
||||
.schema=${[{name:"device",selector:{device:{}}}]}
|
||||
@@ -2228,9 +2228,9 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.radio-row input {
|
||||
margin: 0;
|
||||
}
|
||||
`,c([f({attribute:!1})],L.prototype,"hass",2),c([f({attribute:!1})],L.prototype,"objects",2),c([f({type:Boolean})],L.prototype,"placesEnabled",2),c([u()],L.prototype,"_open",2),c([u()],L.prototype,"_loading",2),c([u()],L.prototype,"_error",2),c([u()],L.prototype,"_name",2),c([u()],L.prototype,"_manufacturer",2),c([u()],L.prototype,"_model",2),c([u()],L.prototype,"_serialNumber",2),c([u()],L.prototype,"_areaId",2),c([u()],L.prototype,"_installationDate",2),c([u()],L.prototype,"_warrantyExpiry",2),c([u()],L.prototype,"_documentationUrl",2),c([u()],L.prototype,"_notes",2),c([u()],L.prototype,"_haDeviceId",2),c([u()],L.prototype,"_parentEntryId",2),c([u()],L.prototype,"_place",2),c([u()],L.prototype,"_remindOnSite",2),c([u()],L.prototype,"_entryId",2),c([u()],L.prototype,"_replacing",2),c([u()],L.prototype,"_oldDeviceId",2),c([u()],L.prototype,"_replaceDevice",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",L)});var Ps,Yn,Qn,Zn=y(()=>{"use strict";Ps=["sensor","binary_sensor","number","input_number","input_boolean","switch","climate","vacuum","cover","fan","light","water_heater","humidifier","media_player","weather","air_quality","valve","lawn_mower","lock","plant"],Yn=["sensor"],Qn=["temperature","humidity","pressure"]});var bl,yl,Ls,Jn=y(()=>{"use strict";bl={cleaning:"mdi:broom",inspection:"mdi:magnify",replacement:"mdi:swap-horizontal",calibration:"mdi:tune",service:"mdi:wrench",reading:"mdi:counter",custom:"mdi:wrench-clock"},yl="mdi:wrench-clock",Ls=r=>r&&bl[r]||yl});function Ei(r){return r?Array.isArray(r.entity_ids)&&r.entity_ids.length>0?[...r.entity_ids]:r.entity_id?[r.entity_id]:[]:[]}function Xn(r){if(!(!r||r.type==="compound"))return Ei(r)[0]}var ea=y(()=>{"use strict"});function sa(){return{entityIds:"",type:"threshold",attribute:"",above:"",below:"",equals:"",notEquals:"",forMinutes:"0",targetValue:"",deltaMode:!1,fromState:"",toState:"",targetChanges:"",runtimeHours:"",onStates:"",daysBefore:"0",carry:{}}}function na(r){return{type:r.type||"threshold",attribute:r.attribute||"",above:r.trigger_above?.toString()??"",below:r.trigger_below?.toString()??"",equals:r.trigger_equals?.toString()??"",notEquals:r.trigger_not_equals?.toString()??"",forMinutes:r.trigger_for_minutes?.toString()??"0",targetValue:r.trigger_target_value?.toString()??"",deltaMode:r.trigger_delta_mode||!1,fromState:r.trigger_from_state||"",toState:r.trigger_to_state||"",targetChanges:r.trigger_target_changes?.toString()??"",runtimeHours:r.trigger_runtime_hours?.toString()??"",onStates:(r.trigger_on_states||[]).join(", "),daysBefore:r.trigger_days_before?.toString()??"0"}}function aa(r,s){s.attribute&&(r.attribute=s.attribute);let e=parseInt(s.forMinutes,10);if(s.type==="threshold"){let t=parseFloat(s.above);isNaN(t)||(r.trigger_above=t);let i=parseFloat(s.below);isNaN(i)||(r.trigger_below=i);let a=parseFloat(s.equals);isNaN(a)||(r.trigger_equals=a);let o=parseFloat(s.notEquals);isNaN(o)||(r.trigger_not_equals=o),isNaN(e)||(r.trigger_for_minutes=e)}else if(s.type==="counter"){let t=parseFloat(s.targetValue);isNaN(t)||(r.trigger_target_value=t),r.trigger_delta_mode=s.deltaMode}else if(s.type==="state_change"){s.fromState&&(r.trigger_from_state=s.fromState),s.toState&&(r.trigger_to_state=s.toState);let t=parseInt(s.targetChanges,10);isNaN(t)||(r.trigger_target_changes=t),isNaN(e)||(r.trigger_for_minutes=e)}else if(s.type==="runtime"){let t=parseFloat(s.runtimeHours);isNaN(t)||(r.trigger_runtime_hours=t);let i=(s.onStates||"").split(",").map(a=>a.trim()).filter(Boolean);i.length>0&&(r.trigger_on_states=i)}else if(s.type==="due_date"){let t=parseInt(s.daysBefore,10);r.trigger_days_before=isNaN(t)?0:t}}function Sl(r){return{entityIds:Ei(r).join(", "),...na(r),carry:Object.fromEntries(Object.entries(r).filter(([e])=>!El.has(e)&&!e.startsWith("_")))}}function Tl(r){let s=r.entityIds.split(",").map(t=>t.trim()).filter(Boolean);if(s.length===0)return null;let e={...r.carry||{},entity_id:s[0],entity_ids:s,type:r.type};return aa(e,r),e}function Al(r){return Array.from({length:7},(s,e)=>It(e,r,"short"))}function Cl(r){return Array.from({length:12},(s,e)=>sn(e,r,"short"))}var xl,wl,kl,Si,ta,ra,ia,$l,_e,qe,El,g,Ns,oa=y(()=>{"use strict";R();j();C();fs();_i();De();Zn();Se();Ot();yi();ks();Is();Jn();ea();ot();xi();xl=["cleaning","inspection","replacement","calibration","service","reading","custom"],wl=["low","normal","high"],kl=["time_based","weekdays","nth_weekday","day_of_month","calendar","sensor_based","one_time","manual"],Si=["weekdays","nth_weekday","day_of_month","calendar"],ta=["time_based","one_time",...Si],ra=["threshold","counter","state_change","runtime","due_date"],ia=(r,s)=>n(r==="due_date"?"trigger_type_due_date":r,s),$l=[...ra,"compound"],_e={alpha:"0.3",min:"7",max:"365"},qe=Ee;El=new Set(["entity_id","entity_ids","type","attribute","trigger_above","trigger_below","trigger_equals","trigger_not_equals","trigger_for_minutes","trigger_target_value","trigger_delta_mode","trigger
Line truncated
|
||||
`,c([f({attribute:!1})],L.prototype,"hass",2),c([f({attribute:!1})],L.prototype,"objects",2),c([f({type:Boolean})],L.prototype,"placesEnabled",2),c([u()],L.prototype,"_open",2),c([u()],L.prototype,"_loading",2),c([u()],L.prototype,"_error",2),c([u()],L.prototype,"_name",2),c([u()],L.prototype,"_manufacturer",2),c([u()],L.prototype,"_model",2),c([u()],L.prototype,"_serialNumber",2),c([u()],L.prototype,"_areaId",2),c([u()],L.prototype,"_installationDate",2),c([u()],L.prototype,"_warrantyExpiry",2),c([u()],L.prototype,"_documentationUrl",2),c([u()],L.prototype,"_notes",2),c([u()],L.prototype,"_haDeviceId",2),c([u()],L.prototype,"_parentEntryId",2),c([u()],L.prototype,"_place",2),c([u()],L.prototype,"_remindOnSite",2),c([u()],L.prototype,"_entryId",2),c([u()],L.prototype,"_replacing",2),c([u()],L.prototype,"_oldDeviceId",2),c([u()],L.prototype,"_replaceDevice",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",L)});var Ls,Qn,Zn,Jn=y(()=>{"use strict";Ls=["sensor","binary_sensor","number","input_number","input_boolean","switch","climate","vacuum","cover","fan","light","water_heater","humidifier","media_player","weather","air_quality","valve","lawn_mower","lock","plant"],Qn=["sensor"],Zn=["temperature","humidity","pressure"]});var wl,kl,Ns,Xn=y(()=>{"use strict";wl={cleaning:"mdi:broom",inspection:"mdi:magnify",replacement:"mdi:swap-horizontal",calibration:"mdi:tune",service:"mdi:wrench",reading:"mdi:counter",custom:"mdi:wrench-clock"},kl="mdi:wrench-clock",Ns=r=>r&&wl[r]||kl});function Ei(r){return r?Array.isArray(r.entity_ids)&&r.entity_ids.length>0?[...r.entity_ids]:r.entity_id?[r.entity_id]:[]:[]}function ea(r){if(!(!r||r.type==="compound"))return Ei(r)[0]}var ta=y(()=>{"use strict"});function ra(){return{entityIds:"",type:"threshold",attribute:"",above:"",below:"",equals:"",notEquals:"",forMinutes:"0",targetValue:"",deltaMode:!1,fromState:"",toState:"",targetChanges:"",runtimeHours:"",onStates:"",daysBefore:"0",carry:{}}}function aa(r){return{type:r.type||"threshold",attribute:r.attribute||"",above:r.trigger_above?.toString()??"",below:r.trigger_below?.toString()??"",equals:r.trigger_equals?.toString()??"",notEquals:r.trigger_not_equals?.toString()??"",forMinutes:r.trigger_for_minutes?.toString()??"0",targetValue:r.trigger_target_value?.toString()??"",deltaMode:r.trigger_delta_mode||!1,fromState:r.trigger_from_state||"",toState:r.trigger_to_state||"",targetChanges:r.trigger_target_changes?.toString()??"",runtimeHours:r.trigger_runtime_hours?.toString()??"",onStates:(r.trigger_on_states||[]).join(", "),daysBefore:r.trigger_days_before?.toString()??"0"}}function oa(r,s){s.attribute&&(r.attribute=s.attribute);let e=parseInt(s.forMinutes,10);if(s.type==="threshold"){let t=parseFloat(s.above);isNaN(t)||(r.trigger_above=t);let i=parseFloat(s.below);isNaN(i)||(r.trigger_below=i);let a=parseFloat(s.equals);isNaN(a)||(r.trigger_equals=a);let o=parseFloat(s.notEquals);isNaN(o)||(r.trigger_not_equals=o),isNaN(e)||(r.trigger_for_minutes=e)}else if(s.type==="counter"){let t=parseFloat(s.targetValue);isNaN(t)||(r.trigger_target_value=t),r.trigger_delta_mode=s.deltaMode}else if(s.type==="state_change"){s.fromState&&(r.trigger_from_state=s.fromState),s.toState&&(r.trigger_to_state=s.toState);let t=parseInt(s.targetChanges,10);isNaN(t)||(r.trigger_target_changes=t),isNaN(e)||(r.trigger_for_minutes=e)}else if(s.type==="runtime"){let t=parseFloat(s.runtimeHours);isNaN(t)||(r.trigger_runtime_hours=t);let i=(s.onStates||"").split(",").map(a=>a.trim()).filter(Boolean);i.length>0&&(r.trigger_on_states=i)}else if(s.type==="due_date"){let t=parseInt(s.daysBefore,10);r.trigger_days_before=isNaN(t)?0:t}}function Cl(r){return{entityIds:Ei(r).join(", "),...aa(r),carry:Object.fromEntries(Object.entries(r).filter(([e])=>!Al.has(e)&&!e.startsWith("_")))}}function Rl(r){let s=r.entityIds.split(",").map(t=>t.trim()).filter(Boolean);if(s.length===0)return null;let e={...r.carry||{},entity_id:s[0],entity_ids:s,type:r.type};return oa(e,r),e}function Il(r){return Array.from({length:7},(s,e)=>It(e,r,"short"))}function Pl(r){return Array.from({length:12},(s,e)=>rn(e,r,"short"))}var $l,El,Sl,Si,ia,na,sa,Tl,_e,qe,Al,g,Os,la=y(()=>{"use strict";R();j();C();vs();_i();De();Jn();Se();Ot();yi();$s();Ps();Xn();ta();ot();xi();$l=["cleaning","inspection","replacement","calibration","service","reading","custom"],El=["low","normal","high"],Sl=["time_based","weekdays","nth_weekday","day_of_month","calendar","sensor_based","one_time","manual"],Si=["weekdays","nth_weekday","day_of_month","calendar"],ia=["time_based","one_time",...Si],na=["threshold","counter","state_change","runtime","due_date"],sa=(r,s)=>n(r==="due_date"?"trigger_type_due_date":r,s),Tl=[...na,"compound"],_e={alpha:"0.3",min:"7",max:"365"},qe=Ee;Al=new Set(["entity_id","entity_ids","type","attribute","trigger_above","trigger_below","trigger_equals","trigger_not_equals","trigger_for_minutes","trigger_target_value","trigger_delta_mode","trigger
Line truncated
|
||||
`),this._phaseDefs=Object.entries(t.phases||{}).map(([_,m])=>{let{name:b,checklist:k,consumes_parts:w,required_completion_fields:v,...x}=m,T=m.consumes_parts||[],O=T.findIndex(ce=>!ce.entry_id),G=O>=0?T[O]:void 0;return{id:_,name:m.name||_,checklistText:(m.checklist||[]).join(`
|
||||
`),partId:G?.part_id||"",partQty:G?.quantity!=null?String(G.quantity):"",reqOverride:m.required_completion_fields!==void 0,reqFields:[...m.required_completion_fields||[]],extraParts:T.filter((ce,Ue)=>Ue!==O).map(ce=>({...ce})),carry:x}}),this._phaseSeq=[...t.phase_sequence||[]],this._requiredCompletion=[...t.required_completion_fields||[]],this._scheduleTime=t.schedule_time||"",this._scheduleTimeOn=!!t.schedule_time;let o=t.on_complete_action;if(o&&o.service){this._actionService=o.service;let _=o.target?.entity_id;this._actionTargetEntity=Array.isArray(_)?_[0]||"":_||"",this._actionTargetStored=o.target&&typeof o.target=="object"?JSON.parse(JSON.stringify(o.target)):null,this._actionTargetInitial=this._actionTargetEntity,this._actionData=o.data&&typeof o.data=="object"?{...o.data}:{},this._actionDataJsonFallback="",this._actionSkipAuto=o.skip_auto===!0,this._actionPresent=!0}else this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1;let d=t.quick_complete_defaults;this._qcNotes=d?.notes||"",this._qcCost=d?.cost!=null?String(d.cost):"",this._qcDuration=d?.duration!=null?String(d.duration):"",this._qcFeedback=d?.feedback||"";let h=t.adaptive_config||{};if(this._environmentalEntity=h.environmental_entity||"",this._environmentalAttribute=h.environmental_attribute||"",this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute,this._adaptiveEnabled=!!h.enabled,this._adaptiveAlpha=h.ewa_alpha?.toString()??_e.alpha,this._adaptiveMin=h.min_interval_days?.toString()??_e.min,this._adaptiveMax=h.max_interval_days?.toString()??_e.max,this._adaptiveSeasonal=h.seasonal_enabled!==!1,this._adaptivePrediction=h.sensor_prediction_enabled!==!1,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=this._adaptiveEnabled,t.trigger_config){let _=t.trigger_config;this._triggerEntityId=Xn(_)||"",this._triggerEntityIds=Ei(_),this._triggerEntityLogic=_.entity_logic||"any",this._setTypeFields(na(_)),this._triggerCombinator=_.trigger_combinator==="all"?"all":"any",this._triggerBaselineValue=_.trigger_baseline_value?.toString()||"",this._liveBaselineValue=t.trigger_baseline_value??null,this._autoCompleteOnRecovery=_.auto_complete_on_recovery||!1,this._triggerRuntimeMaxSession=_.trigger_runtime_max_session_seconds?.toString()||"",_.type==="compound"?(this._compoundLogic=_.compound_logic==="OR"?"OR":"AND",this._compoundConditions=(_.conditions||[]).map(Sl)):(this._compoundLogic="AND",this._compoundConditions=[])}else this._resetTriggerFields();this._triggerEntityId&&this._fetchEntityAttributes(this._triggerEntityId),await Promise.all([this._loadUsers(),this._loadTags(),this._loadParts(),this._loadForeignPools()]),this._open=!0}_resetFields(){this._name="",this._type="custom",this._scheduleType="time_based",this._intervalDays="30",this._intervalUnit="days",this._dueDate="",this._warningDays=String(this.defaultWarningDays),this._earliestCompletionDays="",this._intervalAnchor="completion",this._weekdays=[],this._nth="1",this._nthWeekday="5",this._domDay="1",this._domLastDay=!1,this._domBusiness=!1,this._calOffset="0",this._seasonMonths=[],this._endsMode="never",this._endsCount="",this._endsUntil="",this._notes="",this._documentationUrl="",this._customIcon="",this._notifyIcon="",this._priority="normal",this._labels="",this._mirrorTodoEntities=[],this._enabled=!0,this._lastPerformed="",this._nfcTagId="",this._requireTagScan=!1,this._allowSkip=!0,this._readingUnit="",this._readings=[],this._consumesParts={},this._consumesQtyText={},this._responsibleUserId=null,this._assigneePool=[],this._rotationStrategy="",this._checklistText="",this._phaseDefs=[],this._phaseSeq=[],this._requiredCompletion=[],this._scheduleTime="",this._scheduleTimeOn=!1,this._environmentalEntity="",this._environmentalAttribute="",this._environmentalInitial="",this._environmentalAttributeInitial="",this._adaptiveEnabled=!1,this._adaptiveAlpha=_e.alpha,this._adaptiveMin=_e.min,this._adaptiveMax=_e.max,this._adaptiveSeasonal=!0,this._adaptivePrediction=!0,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=!1,this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1,this._actionTesting=!1,this._actionTestResult="",this._qcNotes="",this._qcCost="",this._qcDuration="",this._qcFeedback="",this._resetTriggerFields()}_typeFields(){return{type:this._triggerType,attribute:this._triggerAttribute,above:this._triggerAbove,below:this._triggerBelow,equals:this._triggerEquals,notEquals:this._triggerNotEquals,forMinutes:this._triggerForMinutes,targetValue:this._triggerTargetValue,deltaMode:this._triggerDeltaMode,fromState:this._triggerFromState,toState:this._triggerToState,targetChanges:this._trig
Line truncated
|
||||
`),partId:G?.part_id||"",partQty:G?.quantity!=null?String(G.quantity):"",reqOverride:m.required_completion_fields!==void 0,reqFields:[...m.required_completion_fields||[]],extraParts:T.filter((ce,Ue)=>Ue!==O).map(ce=>({...ce})),carry:x}}),this._phaseSeq=[...t.phase_sequence||[]],this._requiredCompletion=[...t.required_completion_fields||[]],this._scheduleTime=t.schedule_time||"",this._scheduleTimeOn=!!t.schedule_time;let o=t.on_complete_action;if(o&&o.service){this._actionService=o.service;let _=o.target?.entity_id;this._actionTargetEntity=Array.isArray(_)?_[0]||"":_||"",this._actionTargetStored=o.target&&typeof o.target=="object"?JSON.parse(JSON.stringify(o.target)):null,this._actionTargetInitial=this._actionTargetEntity,this._actionData=o.data&&typeof o.data=="object"?{...o.data}:{},this._actionDataJsonFallback="",this._actionSkipAuto=o.skip_auto===!0,this._actionPresent=!0}else this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1;let d=t.quick_complete_defaults;this._qcNotes=d?.notes||"",this._qcCost=d?.cost!=null?String(d.cost):"",this._qcDuration=d?.duration!=null?String(d.duration):"",this._qcFeedback=d?.feedback||"";let h=t.adaptive_config||{};if(this._environmentalEntity=h.environmental_entity||"",this._environmentalAttribute=h.environmental_attribute||"",this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute,this._adaptiveEnabled=!!h.enabled,this._adaptiveAlpha=h.ewa_alpha?.toString()??_e.alpha,this._adaptiveMin=h.min_interval_days?.toString()??_e.min,this._adaptiveMax=h.max_interval_days?.toString()??_e.max,this._adaptiveSeasonal=h.seasonal_enabled!==!1,this._adaptivePrediction=h.sensor_prediction_enabled!==!1,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=this._adaptiveEnabled,t.trigger_config){let _=t.trigger_config;this._triggerEntityId=ea(_)||"",this._triggerEntityIds=Ei(_),this._triggerEntityLogic=_.entity_logic||"any",this._setTypeFields(aa(_)),this._triggerCombinator=_.trigger_combinator==="all"?"all":"any",this._triggerBaselineValue=_.trigger_baseline_value?.toString()||"",this._liveBaselineValue=t.trigger_baseline_value??null,this._autoCompleteOnRecovery=_.auto_complete_on_recovery||!1,this._triggerRuntimeMaxSession=_.trigger_runtime_max_session_seconds?.toString()||"",_.type==="compound"?(this._compoundLogic=_.compound_logic==="OR"?"OR":"AND",this._compoundConditions=(_.conditions||[]).map(Cl)):(this._compoundLogic="AND",this._compoundConditions=[])}else this._resetTriggerFields();this._triggerEntityId&&this._fetchEntityAttributes(this._triggerEntityId),await Promise.all([this._loadUsers(),this._loadTags(),this._loadParts(),this._loadForeignPools()]),this._open=!0}_resetFields(){this._name="",this._type="custom",this._scheduleType="time_based",this._intervalDays="30",this._intervalUnit="days",this._dueDate="",this._warningDays=String(this.defaultWarningDays),this._earliestCompletionDays="",this._intervalAnchor="completion",this._weekdays=[],this._nth="1",this._nthWeekday="5",this._domDay="1",this._domLastDay=!1,this._domBusiness=!1,this._calOffset="0",this._seasonMonths=[],this._endsMode="never",this._endsCount="",this._endsUntil="",this._notes="",this._documentationUrl="",this._customIcon="",this._notifyIcon="",this._priority="normal",this._labels="",this._mirrorTodoEntities=[],this._enabled=!0,this._lastPerformed="",this._nfcTagId="",this._requireTagScan=!1,this._allowSkip=!0,this._readingUnit="",this._readings=[],this._consumesParts={},this._consumesQtyText={},this._responsibleUserId=null,this._assigneePool=[],this._rotationStrategy="",this._checklistText="",this._phaseDefs=[],this._phaseSeq=[],this._requiredCompletion=[],this._scheduleTime="",this._scheduleTimeOn=!1,this._environmentalEntity="",this._environmentalAttribute="",this._environmentalInitial="",this._environmentalAttributeInitial="",this._adaptiveEnabled=!1,this._adaptiveAlpha=_e.alpha,this._adaptiveMin=_e.min,this._adaptiveMax=_e.max,this._adaptiveSeasonal=!0,this._adaptivePrediction=!0,this._adaptiveInitial=this._adaptiveSnapshot(),this._adaptiveWasEnabled=!1,this._actionService="",this._actionTargetEntity="",this._actionTargetStored=null,this._actionTargetInitial="",this._actionData={},this._actionDataJsonFallback="",this._actionSkipAuto=!1,this._actionPresent=!1,this._actionTesting=!1,this._actionTestResult="",this._qcNotes="",this._qcCost="",this._qcDuration="",this._qcFeedback="",this._resetTriggerFields()}_typeFields(){return{type:this._triggerType,attribute:this._triggerAttribute,above:this._triggerAbove,below:this._triggerBelow,equals:this._triggerEquals,notEquals:this._triggerNotEquals,forMinutes:this._triggerForMinutes,targetValue:this._triggerTargetValue,deltaMode:this._triggerDeltaMode,fromState:this._triggerFromState,toState:this._triggerToState,targetChanges:this._trig
Line truncated
|
||||
<details class="ca-section">
|
||||
<summary>${n("on_complete_action_title",e)}</summary>
|
||||
<p class="field-help">${n("on_complete_action_desc",e)}</p>
|
||||
@@ -2332,7 +2332,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
@input=${d=>{let h=d.target.value;this._consumesQtyText={...this._consumesQtyText,[i]:h};let _=parseFloat(h.replace(",","."));Number.isFinite(_)&&_>=qe[0]&&(this._consumesParts={...this._consumesParts,[i]:{...o,quantity:_}})}}
|
||||
/>`:p}
|
||||
</div>
|
||||
`}_applyConsumesQtyText(){let e={...this._consumesParts};for(let t of Object.keys(e)){let i=this._consumesQtyText[t];if(i===void 0)continue;let a=parseFloat(i.replace(",","."));if(!Number.isFinite(a)||a<qe[0]||a>qe[1]){let o=d=>I(d,this._lang,{maximumFractionDigits:2});return this._error=n("settings_value_out_of_range",this._lang).replace("{min}",o(qe[0])).replace("{max}",o(qe[1])),!1}e[t]={...e[t],quantity:a}}return this._consumesParts=e,!0}_toggleRequired(e,t){let i=new Set(this._requiredCompletion);t?i.add(e):i.delete(e),this._requiredCompletion=[...i]}_patchReading(e,t){this._readings=this._readings.map(i=>i.id===e?{...i,...t}:i)}_renderReadingsEditor(e){let t=bn(this._readings);return l`
|
||||
`}_applyConsumesQtyText(){let e={...this._consumesParts};for(let t of Object.keys(e)){let i=this._consumesQtyText[t];if(i===void 0)continue;let a=parseFloat(i.replace(",","."));if(!Number.isFinite(a)||a<qe[0]||a>qe[1]){let o=d=>I(d,this._lang,{maximumFractionDigits:2});return this._error=n("settings_value_out_of_range",this._lang).replace("{min}",o(qe[0])).replace("{max}",o(qe[1])),!1}e[t]={...e[t],quantity:a}}return this._consumesParts=e,!0}_toggleRequired(e,t){let i=new Set(this._requiredCompletion);t?i.add(e):i.delete(e),this._requiredCompletion=[...i]}_patchReading(e,t){this._readings=this._readings.map(i=>i.id===e?{...i,...t}:i)}_renderReadingsEditor(e){let t=yn(this._readings);return l`
|
||||
<div class="readings-editor">
|
||||
<div class="field-label">${n("readings_section",e)}</div>
|
||||
<div class="field-help">${n("readings_hint",e)}</div>
|
||||
@@ -2356,9 +2356,9 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
</ha-icon-button>
|
||||
</div>
|
||||
`)}
|
||||
${this._readings.length<bs?l`
|
||||
${this._readings.length<ys?l`
|
||||
<ha-button appearance="plain" class="reading-add"
|
||||
@click=${()=>this._readings=[...this._readings,{id:_n(),name:"",unit:this._readings.length?this._readings[this._readings.length-1].unit:this._readingUnit}]}>
|
||||
@click=${()=>this._readings=[...this._readings,{id:mn(),name:"",unit:this._readings.length?this._readings[this._readings.length-1].unit:this._readingUnit}]}>
|
||||
<ha-icon icon="mdi:plus"></ha-icon> ${n("reading_add",e)}
|
||||
</ha-button>`:p}
|
||||
</div>
|
||||
@@ -2413,7 +2413,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
</label>
|
||||
${i.reqOverride?l`
|
||||
<div class="required-completion phase-req-fields">
|
||||
${ws.map(a=>l`
|
||||
${ks.map(a=>l`
|
||||
<label class="req-option">
|
||||
<input
|
||||
type="checkbox"
|
||||
@@ -2449,8 +2449,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
</select>
|
||||
</div>
|
||||
`:p}
|
||||
`}async _save(){if(!this._loading&&this._name.trim()){if(this._adaptiveSnapshot()!==this._adaptiveInitial){let e=parseInt(this._adaptiveMin,10),t=parseInt(this._adaptiveMax,10);if(!isNaN(e)&&!isNaN(t)&&e>t){this._error=`${n("adaptive_min_interval",this._lang)} > ${n("adaptive_max_interval",this._lang)}`;return}}if(this._triggerType==="threshold"&&this._thresholdLimitsOverlap()){this._error=n("trigger_hint_overlap",this._lang);return}if(this._scheduleType==="calendar"&&!this._calendarEntity.trim().startsWith("calendar.")){this._error=n("calendar_entity_required",this._lang);return}if(this._applyConsumesQtyText()){this._loading=!0,this._error="";try{let e=await D(this,()=>this.hass.connection.sendMessagePromise(this._savePayload()),{fallbackKey:"save_error",onError:o=>{this._error=o}});if(e===void 0)return;let t=this._taskId||e?.task_id,i=this._environmentalEntity!==this._environmentalInitial||this._environmentalAttribute!==this._environmentalAttributeInitial;this._warning="";let a=o=>{this._warning=n("subsave_warning",this._lang).replace("{detail}",o)};if(t&&this._scheduleType==="sensor_based"&&i&&await D(this,{type:"maintenance_supporter/task/set_environmental_entity",entry_id:this._entryId,task_id:t,environmental_entity:this._environmentalEntity||null,environmental_attribute:this._environmentalAttribute||null},{onError:a})!==void 0&&(this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute),t&&this._adaptiveSnapshot()!==this._adaptiveInitial){let o=parseFloat(this._adaptiveAlpha),d=parseInt(this._adaptiveMin,10),h=parseInt(this._adaptiveMax,10);await D(this,{type:"maintenance_supporter/task/set_adaptive",entry_id:this._entryId,task_id:t,enabled:this._adaptiveEnabled,...o>=Nt[0]&&o<=Nt[1]?{ewa_alpha:o}:{},...!isNaN(d)&&d>=1?{min_interval_days:d}:{},...!isNaN(h)&&h>=1?{max_interval_days:h}:{},seasonal_enabled:this._adaptiveSeasonal,sensor_prediction_enabled:this._adaptivePrediction},{onError:a})!==void 0&&(this._adaptiveInitial=this._adaptiveSnapshot())}this._warning?t&&(this._taskId=t):this._open=!1,this.dispatchEvent(new CustomEvent("task-saved"))}finally{this._loading=!1}}}}_savePayload(){let e={type:this._taskId?"maintenance_supporter/task/update":"maintenance_supporter/task/create",entry_id:this._entryId,name:this._name,task_type:this._type,schedule_type:this._scheduleType,warning_days:Number.isNaN(parseInt(this._warningDays,10))?this.defaultWarningDays:Math.max(0,parseInt(this._warningDays,10))},t=this._earliestCompletionDays.trim();e.earliest_completion_days=t===""?null:Math.max(0,parseInt(t,10)||0),this._taskId&&(e.task_id=this._taskId),this._scheduleType==="one_time"?(e.due_date=this._dueDate||null,e.interval_days=null):Si.includes(this._scheduleType)?(e.schedule={...this._buildSchedule(),...this._recurrenceExtras()},e.interval_days=null,this._taskId&&(e.due_date=null)):(this._taskId&&(e.due_date=null),this._scheduleType!=="manual"&&this._intervalDays?(e.interval_days=parseInt(this._intervalDays,10),e.interval_unit=this._intervalUnit,e.interval_anchor=this._intervalAnchor,this._scheduleType==="time_based"&&(e.schedule={kind:"interval",...this._recurrenceExtras()})):this._taskId&&(e.interval_days=null,e.interval_anchor="completion")),e.notes=this._notes||null,e.documentation_url=this._documentationUrl||null,e.custom_icon=this._customIcon||null,e.notify_icon=this._notifyIcon.trim()||null,e.priority=this._priority,e.labels=this._labels.split(",").map(i=>i.trim()).filter(Boolean),e.mirror_todo_entities=this._mirrorTodoEntities.filter(Boolean),e.enabled=this._enabled,(!this._taskId||this._lastPerformed!==this._loadedLastPerformed)&&(e.last_performed=this._lastPerformed||null),e.nfc_tag_id=this._nfcTagId||null,e.require_tag_scan=this._requireTagScan,e.allow_skip=this._allowSkip,e.notify_enabled=this._notifyEnabled,e.reading_unit=this._readingUnit.trim()||null,e.readings=yn(this._readings);{let i={};for(let o of this._phaseDefs){if(!o.name.trim())continue;let d={...o.carry,name:o.name.trim()},h=o.checklistText.split(`
|
||||
`).map(m=>m.trim()).filter(Boolean);h.length&&(d.checklist=h);let _=[];if(o.partId){let m=parseFloat(o.partQty);_.push({part_id:o.partId,quantity:Number.isFinite(m)&&m>0?m:1})}for(let m of o.extraParts)_.push(m.entry_id?{part_id:m.part_id,quantity:m.quantity,entry_id:m.entry_id}:{part_id:m.part_id,quantity:m.quantity});_.length&&(d.consumes_parts=_),o.reqOverride&&(d.required_completion_fields=[...o.reqFields]),i[o.id]=d}let a=this._phaseSeq.filter(o=>o in i);e.phases=Object.keys(i).length&&a.length?i:null,e.phase_sequence=e.phases?a:null}if((this.parts.length||this._foreignOwners.length)&&(e.consumes_parts=Object.values(this._consumesParts).map(i=>i.entry_id?{part_id:i.part_id,quantity:i.quantity,entry_id:i.entry_id}:{part_id:i.part_id,quantity:i.quantity})),(!this._taskId||this._responsibleUserId!==this._loadedResponsibleUserId)&&(e.responsible_user_id=this._responsibleUserId),e.assignee_pool=this._assigneePool,e.required_completion_fields=this._requiredCompletion,e.rotation_strategy=this._assigneePool.length>=2&&this._rotationStrategy?this._rotationStrategy:null,this._scheduleType==="sensor_based"&&this._triggerType==="compound"){let i=this._compoundConditions.map(Tl).filter(a=>a!==null);if(i.length>0){let a={type:"compound",compound_logic:this._compoundLogic,conditions:i};this._autoCompleteOnRecovery&&(a.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(a.trigger_combinator="all"),e.trigger_config=a}else this._taskId&&(e.trigger_config=null)}else if(this._scheduleType==="sensor_based"&&this._triggerEntityId){let i=this._triggerEntityIds.length>0?this._triggerEntityIds:[this._triggerEntityId],a={entity_id:i[0],entity_ids:i,type:this._triggerType};if(aa(a,this._typeFields()),this._autoCompleteOnRecovery&&(a.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(a.trigger_combinator="all"),i.length>1&&(a.entity_logic=this._triggerEntityLogic),this._triggerType==="counter"&&this._triggerDeltaMode&&this._triggerBaselineValue){let o=parseFloat(this._triggerBaselineValue);!isNaN(o)&&o>=0&&(a.trigger_baseline_value=o)}else if(this._triggerType==="runtime"&&this._triggerRuntimeMaxSession){let o=parseInt(this._triggerRuntimeMaxSession,10);!isNaN(o)&&o>0&&(a.trigger_runtime_max_session_seconds=o)}e.trigger_config=a}else this._taskId&&(e.trigger_config=null);if(this.scheduleTimeEnabled&&ta.includes(this._scheduleType)){let i=this._scheduleTimeOn?this._scheduleTime.trim():"";e.schedule_time=/^([01]\d|2[0-3]):[0-5]\d$/.test(i)?i:null}if(this.checklistsEnabled){let i=this._checklistText.split(`
|
||||
`}async _save(){if(!this._loading&&this._name.trim()){if(this._adaptiveSnapshot()!==this._adaptiveInitial){let e=parseInt(this._adaptiveMin,10),t=parseInt(this._adaptiveMax,10);if(!isNaN(e)&&!isNaN(t)&&e>t){this._error=`${n("adaptive_min_interval",this._lang)} > ${n("adaptive_max_interval",this._lang)}`;return}}if(this._triggerType==="threshold"&&this._thresholdLimitsOverlap()){this._error=n("trigger_hint_overlap",this._lang);return}if(this._scheduleType==="calendar"&&!this._calendarEntity.trim().startsWith("calendar.")){this._error=n("calendar_entity_required",this._lang);return}if(this._applyConsumesQtyText()){this._loading=!0,this._error="";try{let e=await D(this,()=>this.hass.connection.sendMessagePromise(this._savePayload()),{fallbackKey:"save_error",onError:o=>{this._error=o}});if(e===void 0)return;let t=this._taskId||e?.task_id,i=this._environmentalEntity!==this._environmentalInitial||this._environmentalAttribute!==this._environmentalAttributeInitial;this._warning="";let a=o=>{this._warning=n("subsave_warning",this._lang).replace("{detail}",o)};if(t&&this._scheduleType==="sensor_based"&&i&&await D(this,{type:"maintenance_supporter/task/set_environmental_entity",entry_id:this._entryId,task_id:t,environmental_entity:this._environmentalEntity||null,environmental_attribute:this._environmentalAttribute||null},{onError:a})!==void 0&&(this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute),t&&this._adaptiveSnapshot()!==this._adaptiveInitial){let o=parseFloat(this._adaptiveAlpha),d=parseInt(this._adaptiveMin,10),h=parseInt(this._adaptiveMax,10);await D(this,{type:"maintenance_supporter/task/set_adaptive",entry_id:this._entryId,task_id:t,enabled:this._adaptiveEnabled,...o>=Nt[0]&&o<=Nt[1]?{ewa_alpha:o}:{},...!isNaN(d)&&d>=1?{min_interval_days:d}:{},...!isNaN(h)&&h>=1?{max_interval_days:h}:{},seasonal_enabled:this._adaptiveSeasonal,sensor_prediction_enabled:this._adaptivePrediction},{onError:a})!==void 0&&(this._adaptiveInitial=this._adaptiveSnapshot())}this._warning?t&&(this._taskId=t):this._open=!1,this.dispatchEvent(new CustomEvent("task-saved"))}finally{this._loading=!1}}}}_savePayload(){let e={type:this._taskId?"maintenance_supporter/task/update":"maintenance_supporter/task/create",entry_id:this._entryId,name:this._name,task_type:this._type,schedule_type:this._scheduleType,warning_days:Number.isNaN(parseInt(this._warningDays,10))?this.defaultWarningDays:Math.max(0,parseInt(this._warningDays,10))},t=this._earliestCompletionDays.trim();e.earliest_completion_days=t===""?null:Math.max(0,parseInt(t,10)||0),this._taskId&&(e.task_id=this._taskId),this._scheduleType==="one_time"?(e.due_date=this._dueDate||null,e.interval_days=null):Si.includes(this._scheduleType)?(e.schedule={...this._buildSchedule(),...this._recurrenceExtras()},e.interval_days=null,this._taskId&&(e.due_date=null)):(this._taskId&&(e.due_date=null),this._scheduleType!=="manual"&&this._intervalDays?(e.interval_days=parseInt(this._intervalDays,10),e.interval_unit=this._intervalUnit,e.interval_anchor=this._intervalAnchor,this._scheduleType==="time_based"&&(e.schedule={kind:"interval",...this._recurrenceExtras()})):this._taskId&&(e.interval_days=null,e.interval_anchor="completion")),e.notes=this._notes||null,e.documentation_url=this._documentationUrl||null,e.custom_icon=this._customIcon||null,e.notify_icon=this._notifyIcon.trim()||null,e.priority=this._priority,e.labels=this._labels.split(",").map(i=>i.trim()).filter(Boolean),e.mirror_todo_entities=this._mirrorTodoEntities.filter(Boolean),e.enabled=this._enabled,(!this._taskId||this._lastPerformed!==this._loadedLastPerformed)&&(e.last_performed=this._lastPerformed||null),e.nfc_tag_id=this._nfcTagId||null,e.require_tag_scan=this._requireTagScan,e.allow_skip=this._allowSkip,e.notify_enabled=this._notifyEnabled,e.reading_unit=this._readingUnit.trim()||null,e.readings=xn(this._readings);{let i={};for(let o of this._phaseDefs){if(!o.name.trim())continue;let d={...o.carry,name:o.name.trim()},h=o.checklistText.split(`
|
||||
`).map(m=>m.trim()).filter(Boolean);h.length&&(d.checklist=h);let _=[];if(o.partId){let m=parseFloat(o.partQty);_.push({part_id:o.partId,quantity:Number.isFinite(m)&&m>0?m:1})}for(let m of o.extraParts)_.push(m.entry_id?{part_id:m.part_id,quantity:m.quantity,entry_id:m.entry_id}:{part_id:m.part_id,quantity:m.quantity});_.length&&(d.consumes_parts=_),o.reqOverride&&(d.required_completion_fields=[...o.reqFields]),i[o.id]=d}let a=this._phaseSeq.filter(o=>o in i);e.phases=Object.keys(i).length&&a.length?i:null,e.phase_sequence=e.phases?a:null}if((this.parts.length||this._foreignOwners.length)&&(e.consumes_parts=Object.values(this._consumesParts).map(i=>i.entry_id?{part_id:i.part_id,quantity:i.quantity,entry_id:i.entry_id}:{part_id:i.part_id,quantity:i.quantity})),(!this._taskId||this._responsibleUserId!==this._loadedResponsibleUserId)&&(e.responsible_user_id=this._responsibleUserId),e.assignee_pool=this._assigneePool,e.required_completion_fields=this._requiredCompletion,e.rotation_strategy=this._assigneePool.length>=2&&this._rotationStrategy?this._rotationStrategy:null,this._scheduleType==="sensor_based"&&this._triggerType==="compound"){let i=this._compoundConditions.map(Rl).filter(a=>a!==null);if(i.length>0){let a={type:"compound",compound_logic:this._compoundLogic,conditions:i};this._autoCompleteOnRecovery&&(a.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(a.trigger_combinator="all"),e.trigger_config=a}else this._taskId&&(e.trigger_config=null)}else if(this._scheduleType==="sensor_based"&&this._triggerEntityId){let i=this._triggerEntityIds.length>0?this._triggerEntityIds:[this._triggerEntityId],a={entity_id:i[0],entity_ids:i,type:this._triggerType};if(oa(a,this._typeFields()),this._autoCompleteOnRecovery&&(a.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(a.trigger_combinator="all"),i.length>1&&(a.entity_logic=this._triggerEntityLogic),this._triggerType==="counter"&&this._triggerDeltaMode&&this._triggerBaselineValue){let o=parseFloat(this._triggerBaselineValue);!isNaN(o)&&o>=0&&(a.trigger_baseline_value=o)}else if(this._triggerType==="runtime"&&this._triggerRuntimeMaxSession){let o=parseInt(this._triggerRuntimeMaxSession,10);!isNaN(o)&&o>0&&(a.trigger_runtime_max_session_seconds=o)}e.trigger_config=a}else this._taskId&&(e.trigger_config=null);if(this.scheduleTimeEnabled&&ia.includes(this._scheduleType)){let i=this._scheduleTimeOn?this._scheduleTime.trim():"";e.schedule_time=/^([01]\d|2[0-3]):[0-5]\d$/.test(i)?i:null}if(this.checklistsEnabled){let i=this._checklistText.split(`
|
||||
`).map(a=>a.trim()).filter(Boolean).slice(0,100);e.checklist=i.length?i:null}if(this.completionActionsEnabled||this._actionPresent){let i=this._actionService.trim();if(i&&/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(i)){let a={service:i},o=this._actionTargetEntity.trim();this._actionTargetStored&&o===this._actionTargetInitial?a.target=JSON.parse(JSON.stringify(this._actionTargetStored)):o&&(a.target={entity_id:o});let d=this._buildActionData();Object.keys(d).length>0&&(a.data=d),this._actionSkipAuto&&(a.skip_auto=!0),e.on_complete_action=a}else e.on_complete_action=null}if(this.completionActionsEnabled){let i={};this._qcNotes.trim()&&(i.notes=this._qcNotes.trim());let a=parseFloat(this._qcCost);isNaN(a)||(i.cost=a);let o=nt(this._qcDuration);o!==null&&(i.duration=o),this._qcFeedback&&(i.feedback=this._qcFeedback),e.quick_complete_defaults=Object.keys(i).length?i:null}return e}_close(){this._open=!1,this._warning="",this._pickerProbeTimer!==void 0&&(clearTimeout(this._pickerProbeTimer),this._pickerProbeTimer=void 0),this._pickerProbeStrikes=0}_renderTriggerFields(){if(this._scheduleType!=="sensor_based")return p;let e=this._lang,t=this._triggerType==="compound";return l`
|
||||
<h3>${n("trigger_configuration",e)}</h3>
|
||||
<div class="select-row">
|
||||
@@ -2459,7 +2459,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._triggerType}
|
||||
@change=${i=>this._triggerType=i.target.value}
|
||||
>
|
||||
${$l.map(i=>l`<option value=${i} ?selected=${i===this._triggerType}>${ia(i,e)}</option>`)}
|
||||
${Tl.map(i=>l`<option value=${i} ?selected=${i===this._triggerType}>${sa(i,e)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
${t?this._renderCompoundEditor():l`
|
||||
@@ -2473,7 +2473,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ha-form
|
||||
class="entity-picker-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{name:"trigger_entities",selector:{entity:{multiple:!0,domain:Ps}}}]}
|
||||
.schema=${[{name:"trigger_entities",selector:{entity:{multiple:!0,domain:Ls}}}]}
|
||||
.data=${{trigger_entities:this._triggerEntityIds.length>0?this._triggerEntityIds:this._triggerEntityId?[this._triggerEntityId]:[]}}
|
||||
.computeLabel=${()=>n("entity_id",e)}
|
||||
@value-changed=${i=>{let a=(i.detail.value.trigger_entities||[]).filter(Boolean);this._triggerEntityId=a[0]||"",this._triggerEntityIds=a,a[0]?this._fetchEntityAttributes(a[0]):this._fetchEntityAttributes("")}}
|
||||
@@ -2521,7 +2521,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
</select>
|
||||
</div>
|
||||
`:p}
|
||||
`}_patchCondition(e,t){this._compoundConditions=this._compoundConditions.map((i,a)=>a===e?{...i,...t}:i)}_addCondition(){this._compoundConditions=[...this._compoundConditions,sa()]}_removeCondition(e){this._compoundConditions=this._compoundConditions.filter((t,i)=>i!==e)}_renderCompoundEditor(){let e=this._lang;return l`
|
||||
`}_patchCondition(e,t){this._compoundConditions=this._compoundConditions.map((i,a)=>a===e?{...i,...t}:i)}_addCondition(){this._compoundConditions=[...this._compoundConditions,ra()]}_removeCondition(e){this._compoundConditions=this._compoundConditions.filter((t,i)=>i!==e)}_renderCompoundEditor(){let e=this._lang;return l`
|
||||
<div class="select-row">
|
||||
<label>${n("compound_logic",e)}</label>
|
||||
<select
|
||||
@@ -2558,7 +2558,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ha-form
|
||||
class="entity-picker-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{name:"condition_entities",selector:{entity:{multiple:!0,domain:Ps}}}]}
|
||||
.schema=${[{name:"condition_entities",selector:{entity:{multiple:!0,domain:Ls}}}]}
|
||||
.data=${{condition_entities:e.entityIds.split(",").map(o=>o.trim()).filter(Boolean)}}
|
||||
.computeLabel=${()=>n("entity_id",i)}
|
||||
@value-changed=${o=>{let d=(o.detail.value.condition_entities||[]).filter(Boolean);this._patchCondition(t,{entityIds:d.join(", ")})}}
|
||||
@@ -2570,7 +2570,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${e.type}
|
||||
@change=${o=>this._patchCondition(t,{type:o.target.value})}
|
||||
>
|
||||
${ra.map(o=>l`<option value=${o} ?selected=${o===e.type}>${ia(o,i)}</option>`)}
|
||||
${na.map(o=>l`<option value=${o} ?selected=${o===e.type}>${sa(o,i)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
${this._renderConditionTypeFields(e,t)}
|
||||
@@ -2725,7 +2725,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
${n("schedule_preview_title",e)}: ${i}${this._schedulePreviewEnded?l` <span class="field-help">${n("schedule_preview_ends",e)}</span>`:p}
|
||||
${a}
|
||||
</div>
|
||||
`}_buildSchedule(){let e=i=>{let a=parseInt(this._calOffset,10)||0;return a&&(i.offset=Math.max(-Lt,Math.min(a,Lt))),i};if(this._scheduleType==="weekdays")return e({kind:"weekdays",weekdays:[...this._weekdays].sort((i,a)=>i-a)});if(this._scheduleType==="nth_weekday")return e({kind:"nth_weekday",nth:parseInt(this._nth,10),weekday:parseInt(this._nthWeekday,10)});if(this._scheduleType==="calendar")return e({kind:"calendar",entity_id:this._calendarEntity.trim()});let t={kind:"day_of_month",day:this._domLastDay?-1:parseInt(this._domDay,10)||1};return this._domBusiness&&(t.business=!0),e(t)}_recurrenceExtras(){let e={};if(this._seasonMonths.length&&(e.season_months=[...this._seasonMonths].sort((t,i)=>t-i)),this._endsMode==="count"){let t=parseInt(this._endsCount,10);t>=1&&(e.ends={count:t})}else this._endsMode==="until"&&this._endsUntil&&(e.ends={until:this._endsUntil});return e}_toggleSeasonMonth(e){this._seasonMonths=this._seasonMonths.includes(e)?this._seasonMonths.filter(t=>t!==e):[...this._seasonMonths,e]}_renderRecurrenceExtras(){let e=this._lang;if(!(this._scheduleType==="time_based"||Si.includes(this._scheduleType)))return p;let i=Cl(e);return l`
|
||||
`}_buildSchedule(){let e=i=>{let a=parseInt(this._calOffset,10)||0;return a&&(i.offset=Math.max(-Lt,Math.min(a,Lt))),i};if(this._scheduleType==="weekdays")return e({kind:"weekdays",weekdays:[...this._weekdays].sort((i,a)=>i-a)});if(this._scheduleType==="nth_weekday")return e({kind:"nth_weekday",nth:parseInt(this._nth,10),weekday:parseInt(this._nthWeekday,10)});if(this._scheduleType==="calendar")return e({kind:"calendar",entity_id:this._calendarEntity.trim()});let t={kind:"day_of_month",day:this._domLastDay?-1:parseInt(this._domDay,10)||1};return this._domBusiness&&(t.business=!0),e(t)}_recurrenceExtras(){let e={};if(this._seasonMonths.length&&(e.season_months=[...this._seasonMonths].sort((t,i)=>t-i)),this._endsMode==="count"){let t=parseInt(this._endsCount,10);t>=1&&(e.ends={count:t})}else this._endsMode==="until"&&this._endsUntil&&(e.ends={until:this._endsUntil});return e}_toggleSeasonMonth(e){this._seasonMonths=this._seasonMonths.includes(e)?this._seasonMonths.filter(t=>t!==e):[...this._seasonMonths,e]}_renderRecurrenceExtras(){let e=this._lang;if(!(this._scheduleType==="time_based"||Si.includes(this._scheduleType)))return p;let i=Pl(e);return l`
|
||||
<label class="field-label">${n("season_window_label",e)}</label>
|
||||
<div class="field-help">${n("season_window_hint",e)}</div>
|
||||
<div class="weekday-chips season-chips">
|
||||
@@ -2762,7 +2762,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._endsUntil}
|
||||
@value-changed=${a=>this._endsUntil=a.detail.value}
|
||||
></ms-date-field>`:p}
|
||||
`}_renderCalendarFields(){let e=this._lang,t=Al(e);if(this._scheduleType==="weekdays")return l`
|
||||
`}_renderCalendarFields(){let e=this._lang,t=Il(e);if(this._scheduleType==="weekdays")return l`
|
||||
<label class="field-label">${n("recurrence_on_days",e)}</label>
|
||||
<div class="weekday-chips">
|
||||
${t.map((i,a)=>l`
|
||||
@@ -2905,7 +2905,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ms-textfield
|
||||
label="${n("target_changes",e)}"
|
||||
type="number"
|
||||
min=${Sn[0]}
|
||||
min=${Tn[0]}
|
||||
.value=${this._triggerTargetChanges}
|
||||
@input=${t=>this._triggerTargetChanges=t.target.value}
|
||||
></ms-textfield>
|
||||
@@ -2914,7 +2914,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ms-textfield
|
||||
label="${n("for_at_least_minutes",e)}"
|
||||
type="number"
|
||||
min=${En[0]}
|
||||
min=${Sn[0]}
|
||||
.value=${this._triggerForMinutes}
|
||||
@input=${t=>this._triggerForMinutes=t.target.value}
|
||||
></ms-textfield>
|
||||
@@ -2977,7 +2977,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._type}
|
||||
@change=${i=>this._type=i.target.value}
|
||||
>
|
||||
${xl.map(i=>l`<option value=${i} ?selected=${i===this._type}>${n(i,e)}</option>`)}
|
||||
${$l.map(i=>l`<option value=${i} ?selected=${i===this._type}>${n(i,e)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
${this._type==="reading"?l`
|
||||
@@ -3012,7 +3012,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._priority}
|
||||
@change=${i=>this._priority=i.target.value}
|
||||
>
|
||||
${wl.map(i=>l`<option value=${i} ?selected=${i===this._priority}>${n("priority_"+i,e)}</option>`)}
|
||||
${El.map(i=>l`<option value=${i} ?selected=${i===this._priority}>${n("priority_"+i,e)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
@@ -3050,7 +3050,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._scheduleType}
|
||||
@change=${i=>this._scheduleType=i.target.value}
|
||||
>
|
||||
${kl.map(i=>l`<option value=${i} ?selected=${i===this._scheduleType}>${n(i,e)}</option>`)}
|
||||
${Sl.map(i=>l`<option value=${i} ?selected=${i===this._scheduleType}>${n(i,e)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
${this._scheduleType==="time_based"?l`
|
||||
@@ -3070,6 +3070,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<option value="completion" ?selected=${this._intervalAnchor==="completion"}>${n("anchor_completion",e)}</option>
|
||||
<option value="planned" ?selected=${this._intervalAnchor==="planned"}>${n("anchor_planned",e)}</option>
|
||||
</select>
|
||||
<div class="field-help anchor-help">${n("interval_anchor_hint",e)}</div>
|
||||
</div>
|
||||
`:p}
|
||||
${this._renderCalendarFields()}
|
||||
@@ -3083,7 +3084,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
@value-changed=${i=>this._dueDate=i.detail.value}
|
||||
></ms-date-field>
|
||||
`:p}
|
||||
${this.scheduleTimeEnabled&&ta.includes(this._scheduleType)?l`
|
||||
${this.scheduleTimeEnabled&&ia.includes(this._scheduleType)?l`
|
||||
<label class="checkbox-row schedule-time-toggle">
|
||||
<input type="checkbox" .checked=${this._scheduleTimeOn}
|
||||
@change=${i=>this._scheduleTimeOn=i.target.checked} />
|
||||
@@ -3105,8 +3106,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ms-textfield
|
||||
label="${n("warning_days",e)}"
|
||||
type="number"
|
||||
min=${ys[0]}
|
||||
max=${ys[1]}
|
||||
min=${xs[0]}
|
||||
max=${xs[1]}
|
||||
.value=${this._warningDays}
|
||||
@input=${i=>this._warningDays=i.target.value}
|
||||
></ms-textfield>
|
||||
@@ -3132,7 +3133,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
${this._renderPhasesEditor(e)}
|
||||
<h3>${n("require_on_completion",e)}</h3>
|
||||
<div class="required-completion">
|
||||
${ws.map(i=>l`
|
||||
${ks.map(i=>l`
|
||||
<label class="req-option">
|
||||
<input
|
||||
type="checkbox"
|
||||
@@ -3201,7 +3202,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
<ha-form
|
||||
class="entity-picker-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{name:"environmental_entity",selector:{entity:{domain:Yn,device_class:Qn}}}]}
|
||||
.schema=${[{name:"environmental_entity",selector:{entity:{domain:Qn,device_class:Zn}}}]}
|
||||
.data=${{environmental_entity:this._environmentalEntity}}
|
||||
.computeLabel=${()=>n("environmental_entity_optional",e)}
|
||||
.computeHelper=${()=>n("environmental_entity_helper",e)}
|
||||
@@ -3237,8 +3238,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
@value-changed=${i=>this._notifyIcon=i.detail.value||""}
|
||||
></ha-icon-picker>
|
||||
<div class="field-help notify-icon-help">
|
||||
<ha-icon icon=${this._notifyIcon.trim()||Ls(this._type)}></ha-icon>
|
||||
${n("notify_icon_hint",e).replace("{default}",Ls(this._type))}
|
||||
<ha-icon icon=${this._notifyIcon.trim()||Ns(this._type)}></ha-icon>
|
||||
${n("notify_icon_hint",e).replace("{default}",Ns(this._type))}
|
||||
</div>
|
||||
${this._availableTags.length>0?l`
|
||||
<div class="select-row">
|
||||
@@ -3716,13 +3717,13 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
`,c([f({attribute:!1})],g.prototype,"hass",2),c([f({type:Boolean,attribute:"checklists-enabled"})],g.prototype,"checklistsEnabled",2),c([f({type:Boolean,attribute:"schedule-time-enabled"})],g.prototype,"scheduleTimeEnabled",2),c([f({type:Boolean,attribute:"completion-actions-enabled"})],g.prototype,"completionActionsEnabled",2),c([f({type:Boolean,attribute:"adaptive-feature"})],g.prototype,"adaptiveFeature",2),c([f({type:Boolean,attribute:"seasonal-feature"})],g.prototype,"seasonalFeature",2),c([f({type:Boolean,attribute:"environmental-feature"})],g.prototype,"environmentalFeature",2),c([f({type:Number,attribute:"default-warning-days"})],g.prototype,"defaultWarningDays",2),c([u()],g.prototype,"parts",2),c([u()],g.prototype,"_foreignOwners",2),c([u()],g.prototype,"_open",2),c([u()],g.prototype,"_entityPickerFallback",2),c([u()],g.prototype,"_loading",2),c([u()],g.prototype,"_error",2),c([u()],g.prototype,"_warning",2),c([u()],g.prototype,"_entryId",2),c([u()],g.prototype,"_taskId",2),c([u()],g.prototype,"_isFleetTask",2),c([u()],g.prototype,"_objectChoices",2),c([u()],g.prototype,"_name",2),c([u()],g.prototype,"_type",2),c([u()],g.prototype,"_scheduleType",2),c([u()],g.prototype,"_intervalDays",2),c([u()],g.prototype,"_intervalUnit",2),c([u()],g.prototype,"_dueDate",2),c([u()],g.prototype,"_warningDays",2),c([u()],g.prototype,"_earliestCompletionDays",2),c([u()],g.prototype,"_intervalAnchor",2),c([u()],g.prototype,"_weekdays",2),c([u()],g.prototype,"_nth",2),c([u()],g.prototype,"_nthWeekday",2),c([u()],g.prototype,"_domDay",2),c([u()],g.prototype,"_domLastDay",2),c([u()],g.prototype,"_domBusiness",2),c([u()],g.prototype,"_calOffset",2),c([u()],g.prototype,"_calendarEntity",2),c([u()],g.prototype,"_seasonMonths",2),c([u()],g.prototype,"_endsMode",2),c([u()],g.prototype,"_endsCount",2),c([u()],g.prototype,"_endsUntil",2),c([u()],g.prototype,"_schedulePreview",2),c([u()],g.prototype,"_schedulePreviewEnded",2),c([u()],g.prototype,"_notes",2),c([u()],g.prototype,"_documentationUrl",2),c([u()],g.prototype,"_customIcon",2),c([u()],g.prototype,"_notifyIcon",2),c([u()],g.prototype,"_priority",2),c([u()],g.prototype,"_labels",2),c([u()],g.prototype,"_mirrorTodoEntities",2),c([u()],g.prototype,"_enabled",2),c([u()],g.prototype,"_triggerEntityId",2),c([u()],g.prototype,"_triggerEntityIds",2),c([u()],g.prototype,"_triggerEntityLogic",2),c([u()],g.prototype,"_triggerAttribute",2),c([u()],g.prototype,"_triggerType",2),c([u()],g.prototype,"_triggerAbove",2),c([u()],g.prototype,"_triggerBelow",2),c([u()],g.prototype,"_triggerEquals",2),c([u()],g.prototype,"_triggerNotEquals",2),c([u()],g.prototype,"_triggerForMinutes",2),c([u()],g.prototype,"_triggerCombinator",2),c([u()],g.prototype,"_triggerTargetValue",2),c([u()],g.prototype,"_triggerDeltaMode",2),c([u()],g.prototype,"_triggerBaselineValue",2),c([u()],g.prototype,"_liveBaselineValue",2),c([u()],g.prototype,"_autoCompleteOnRecovery",2),c([u()],g.prototype,"_triggerFromState",2),c([u()],g.prototype,"_triggerToState",2),c([u()],g.prototype,"_triggerTargetChanges",2),c([u()],g.prototype,"_triggerRuntimeHours",2),c([u()],g.prototype,"_triggerDaysBefore",2),c([u()],g.prototype,"_triggerRuntimeMaxSession",2),c([u()],g.prototype,"_triggerOnStates",2),c([u()],g.prototype,"_compoundLogic",2),c([u()],g.prototype,"_compoundConditions",2),c([u()],g.prototype,"_suggestedAttributes",2),c([u()],g.prototype,"_availableAttributes",2),c([u()],g.prototype,"_entityDomain",2),c([u()],g.prototype,"_lastPerformed",2),c([u()],g.prototype,"_nfcTagId",2),c([u()],g.prototype,"_requireTagScan",2),c([u()],g.prototype,"_allowSkip",2),c([u()],g.prototype,"_notifyEnabled",2),c([u()],g.prototype,"_readingUnit",2),c([u()],g.prototype,"_readings",2),c([u()],g.prototype,"_consumesParts",2),c([u()],g.prototype,"_consumesQtyText",2),c([u()],g.prototype,"_partsLoadFailed",2),c([u()],g.prototype,"_availableTags",2),c([u()],g.prototype,"_responsibleUserId",2),c([u()],g.prototype,"_assigneePool",2),c([u()],g.prototype,"_rotationStrategy",2),c([u()],g.prototype,"_availableUsers",2),c([u()],g.prototype,"_checklistText",2),c([u()],g.prototype,"_phaseDefs",2),c([u()],g.prototype,"_phaseSeq",2),c([u()],g.prototype,"_requiredCompletion",2),c([u()],g.prototype,"_scheduleTime",2),c([u()],g.prototype,"_scheduleTimeOn",2),c([u()],g.prototype,"_actionService",2),c([u()],g.prototype,"_actionTargetEntity",2),c([u()],g.prototype,"_actionSkipAuto",2),c([u()],g.prototype,"_actionPresent",2),c([u()],g.prototype,"_actionData",2),c([u()],g.prototype,"_actionDataJsonFallback",2),c([u()],g.prototype,"_actionTesting",2),c([u()],g.prototype,"_actionTestResult",2),c([u()],g.prototype,"_actionTestError",2),c([u()],g.prototype,"_qcNotes",2),c([u()],g.prototype,"_qcCost",2),c([u()],g.prototype,"_qcDuration",2),c([u()],g.prototype,"_qcFeedback",2),c([u()],g.prototype,"_environmentalEntity",2),c([u()],g.prototype,"_environmentalAttribute",2),c([u()],g.prototype,"_adaptiveEnabled",2),c([u()],g.prototype,"_adaptiveAlpha",2),c([u()],g.prototy
Line truncated
|
||||
`,c([f({attribute:!1})],g.prototype,"hass",2),c([f({type:Boolean,attribute:"checklists-enabled"})],g.prototype,"checklistsEnabled",2),c([f({type:Boolean,attribute:"schedule-time-enabled"})],g.prototype,"scheduleTimeEnabled",2),c([f({type:Boolean,attribute:"completion-actions-enabled"})],g.prototype,"completionActionsEnabled",2),c([f({type:Boolean,attribute:"adaptive-feature"})],g.prototype,"adaptiveFeature",2),c([f({type:Boolean,attribute:"seasonal-feature"})],g.prototype,"seasonalFeature",2),c([f({type:Boolean,attribute:"environmental-feature"})],g.prototype,"environmentalFeature",2),c([f({type:Number,attribute:"default-warning-days"})],g.prototype,"defaultWarningDays",2),c([u()],g.prototype,"parts",2),c([u()],g.prototype,"_foreignOwners",2),c([u()],g.prototype,"_open",2),c([u()],g.prototype,"_entityPickerFallback",2),c([u()],g.prototype,"_loading",2),c([u()],g.prototype,"_error",2),c([u()],g.prototype,"_warning",2),c([u()],g.prototype,"_entryId",2),c([u()],g.prototype,"_taskId",2),c([u()],g.prototype,"_isFleetTask",2),c([u()],g.prototype,"_objectChoices",2),c([u()],g.prototype,"_name",2),c([u()],g.prototype,"_type",2),c([u()],g.prototype,"_scheduleType",2),c([u()],g.prototype,"_intervalDays",2),c([u()],g.prototype,"_intervalUnit",2),c([u()],g.prototype,"_dueDate",2),c([u()],g.prototype,"_warningDays",2),c([u()],g.prototype,"_earliestCompletionDays",2),c([u()],g.prototype,"_intervalAnchor",2),c([u()],g.prototype,"_weekdays",2),c([u()],g.prototype,"_nth",2),c([u()],g.prototype,"_nthWeekday",2),c([u()],g.prototype,"_domDay",2),c([u()],g.prototype,"_domLastDay",2),c([u()],g.prototype,"_domBusiness",2),c([u()],g.prototype,"_calOffset",2),c([u()],g.prototype,"_calendarEntity",2),c([u()],g.prototype,"_seasonMonths",2),c([u()],g.prototype,"_endsMode",2),c([u()],g.prototype,"_endsCount",2),c([u()],g.prototype,"_endsUntil",2),c([u()],g.prototype,"_schedulePreview",2),c([u()],g.prototype,"_schedulePreviewEnded",2),c([u()],g.prototype,"_notes",2),c([u()],g.prototype,"_documentationUrl",2),c([u()],g.prototype,"_customIcon",2),c([u()],g.prototype,"_notifyIcon",2),c([u()],g.prototype,"_priority",2),c([u()],g.prototype,"_labels",2),c([u()],g.prototype,"_mirrorTodoEntities",2),c([u()],g.prototype,"_enabled",2),c([u()],g.prototype,"_triggerEntityId",2),c([u()],g.prototype,"_triggerEntityIds",2),c([u()],g.prototype,"_triggerEntityLogic",2),c([u()],g.prototype,"_triggerAttribute",2),c([u()],g.prototype,"_triggerType",2),c([u()],g.prototype,"_triggerAbove",2),c([u()],g.prototype,"_triggerBelow",2),c([u()],g.prototype,"_triggerEquals",2),c([u()],g.prototype,"_triggerNotEquals",2),c([u()],g.prototype,"_triggerForMinutes",2),c([u()],g.prototype,"_triggerCombinator",2),c([u()],g.prototype,"_triggerTargetValue",2),c([u()],g.prototype,"_triggerDeltaMode",2),c([u()],g.prototype,"_triggerBaselineValue",2),c([u()],g.prototype,"_liveBaselineValue",2),c([u()],g.prototype,"_autoCompleteOnRecovery",2),c([u()],g.prototype,"_triggerFromState",2),c([u()],g.prototype,"_triggerToState",2),c([u()],g.prototype,"_triggerTargetChanges",2),c([u()],g.prototype,"_triggerRuntimeHours",2),c([u()],g.prototype,"_triggerDaysBefore",2),c([u()],g.prototype,"_triggerRuntimeMaxSession",2),c([u()],g.prototype,"_triggerOnStates",2),c([u()],g.prototype,"_compoundLogic",2),c([u()],g.prototype,"_compoundConditions",2),c([u()],g.prototype,"_suggestedAttributes",2),c([u()],g.prototype,"_availableAttributes",2),c([u()],g.prototype,"_entityDomain",2),c([u()],g.prototype,"_lastPerformed",2),c([u()],g.prototype,"_nfcTagId",2),c([u()],g.prototype,"_requireTagScan",2),c([u()],g.prototype,"_allowSkip",2),c([u()],g.prototype,"_notifyEnabled",2),c([u()],g.prototype,"_readingUnit",2),c([u()],g.prototype,"_readings",2),c([u()],g.prototype,"_consumesParts",2),c([u()],g.prototype,"_consumesQtyText",2),c([u()],g.prototype,"_partsLoadFailed",2),c([u()],g.prototype,"_availableTags",2),c([u()],g.prototype,"_responsibleUserId",2),c([u()],g.prototype,"_assigneePool",2),c([u()],g.prototype,"_rotationStrategy",2),c([u()],g.prototype,"_availableUsers",2),c([u()],g.prototype,"_checklistText",2),c([u()],g.prototype,"_phaseDefs",2),c([u()],g.prototype,"_phaseSeq",2),c([u()],g.prototype,"_requiredCompletion",2),c([u()],g.prototype,"_scheduleTime",2),c([u()],g.prototype,"_scheduleTimeOn",2),c([u()],g.prototype,"_actionService",2),c([u()],g.prototype,"_actionTargetEntity",2),c([u()],g.prototype,"_actionSkipAuto",2),c([u()],g.prototype,"_actionPresent",2),c([u()],g.prototype,"_actionData",2),c([u()],g.prototype,"_actionDataJsonFallback",2),c([u()],g.prototype,"_actionTesting",2),c([u()],g.prototype,"_actionTestResult",2),c([u()],g.prototype,"_actionTestError",2),c([u()],g.prototype,"_qcNotes",2),c([u()],g.prototype,"_qcCost",2),c([u()],g.prototype,"_qcDuration",2),c([u()],g.prototype,"_qcFeedback",2),c([u()],g.prototype,"_environmentalEntity",2),c([u()],g.prototype,"_environmentalAttribute",2),c([u()],g.prototype,"_adaptiveEnabled",2),c([u()],g.prototype,"_adaptiveAlpha",2),c([u()],g.prototy
Line truncated
|
||||
<div class="backdrop" @click=${r}></div>
|
||||
<div class="dialog" role="dialog" aria-modal="true" tabindex="-1"
|
||||
@keydown=${e=>Rl(e,r)}>${s}</div>
|
||||
@keydown=${e=>Ll(e,r)}>${s}</div>
|
||||
`}function ut(r){r?.querySelector(".dialog")?.focus({preventScroll:!0})}var dt,Ti=y(()=>{"use strict";R();dt=$`
|
||||
.backdrop {
|
||||
position: fixed; inset: 0; z-index: 100;
|
||||
position: fixed; inset: 0; z-index: var(--ms-modal-z, 100);
|
||||
background: rgba(0,0,0,0.5);
|
||||
}
|
||||
.dialog {
|
||||
@@ -3736,11 +3737,18 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
|
||||
padding: 20px;
|
||||
display: flex; flex-direction: column; gap: var(--ms-modal-gap, 14px);
|
||||
z-index: 101;
|
||||
z-index: calc(var(--ms-modal-z, 100) + 1);
|
||||
}
|
||||
/* Focused programmatically on open (so Escape works at once) — no ring. */
|
||||
.dialog:focus { outline: none; }
|
||||
`});var U,la=y(()=>{"use strict";R();j();C();U=class extends E{constructor(){super(...arguments);this._open=!1;this._title="";this._message="";this._confirmText="";this._danger=!1;this._inputLabel="";this._inputType="";this._options=null;this._inputValue="";this._resolve=null;this._promptResolve=null}confirm(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel="",this._inputType="",this._options=null,this._inputValue="",this._open=!0,new Promise(t=>{this._resolve=t,this._promptResolve=null})}prompt(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel=e.inputLabel||"",this._inputType=e.inputType||"text",this._options=e.options&&e.options.length?e.options:null,this._inputValue=e.inputValue||"",this._open=!0,new Promise(t=>{this._promptResolve=t,this._resolve=null})}_cancel(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!1,value:""}),this._promptResolve=null),this._resolve?.(!1),this._resolve=null}_confirmAction(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!0,value:this._inputValue}),this._promptResolve=null),this._resolve?.(!0),this._resolve=null}render(){if(!this._open)return p;let e=P(this.hass);return l`
|
||||
/* The one part that shrinks and scrolls (min-height: 0); the header and the
|
||||
buttons around it keep their content's height. */
|
||||
.dialog-scroll {
|
||||
flex: 1 1 auto; min-height: 0;
|
||||
overflow-y: auto; overscroll-behavior: contain;
|
||||
display: flex; flex-direction: column; gap: var(--ms-modal-gap, 14px);
|
||||
}
|
||||
`});var U,ca=y(()=>{"use strict";R();j();C();U=class extends E{constructor(){super(...arguments);this._open=!1;this._title="";this._message="";this._confirmText="";this._danger=!1;this._inputLabel="";this._inputType="";this._options=null;this._inputValue="";this._resolve=null;this._promptResolve=null}confirm(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel="",this._inputType="",this._options=null,this._inputValue="",this._open=!0,new Promise(t=>{this._resolve=t,this._promptResolve=null})}prompt(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel=e.inputLabel||"",this._inputType=e.inputType||"text",this._options=e.options&&e.options.length?e.options:null,this._inputValue=e.inputValue||"",this._open=!0,new Promise(t=>{this._promptResolve=t,this._resolve=null})}_cancel(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!1,value:""}),this._promptResolve=null),this._resolve?.(!1),this._resolve=null}_confirmAction(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!0,value:this._inputValue}),this._promptResolve=null),this._resolve?.(!0),this._resolve=null}render(){if(!this._open)return p;let e=P(this.hass);return l`
|
||||
<ha-dialog open @closed=${this._cancel}>
|
||||
<div class="dialog-title">${this._title}</div>
|
||||
<div class="content">
|
||||
@@ -3804,7 +3812,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
ha-button.danger {
|
||||
--mdc-theme-primary: var(--error-color, #f44336);
|
||||
}
|
||||
`],c([f({attribute:!1})],U.prototype,"hass",2),c([u()],U.prototype,"_open",2),c([u()],U.prototype,"_title",2),c([u()],U.prototype,"_message",2),c([u()],U.prototype,"_confirmText",2),c([u()],U.prototype,"_danger",2),c([u()],U.prototype,"_inputLabel",2),c([u()],U.prototype,"_inputType",2),c([u()],U.prototype,"_options",2),c([u()],U.prototype,"_inputValue",2);customElements.get("maintenance-confirm-dialog")||customElements.define("maintenance-confirm-dialog",U)});function Il(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function Me(r,s){let e=Il(),t=e.querySelector(`${ca}[${da}]`);return t||(t=document.createElement(ca),t.setAttribute(da,""),e.appendChild(t)),t.hass=r,t.confirm(s)}var ca,da,Ai=y(()=>{"use strict";la();ca="maintenance-confirm-dialog",da="data-ms-lovelace-confirm"});var Ce,Os=y(()=>{"use strict";R();j();ps();Ce=class extends E{constructor(){super(...arguments);this.docId="";this._url="";this._failed=!1;this._signedFor=""}updated(){this.hass&&this.docId&&this._signedFor!==this.docId&&(this._signedFor=this.docId,this._url="",this._failed=!1,this._sign())}async _sign(){try{this._url=await ds(this.hass,this.docId)}catch{this._failed=!0}}render(){return this._failed||!this.docId?p:this._url?l`
|
||||
`],c([f({attribute:!1})],U.prototype,"hass",2),c([u()],U.prototype,"_open",2),c([u()],U.prototype,"_title",2),c([u()],U.prototype,"_message",2),c([u()],U.prototype,"_confirmText",2),c([u()],U.prototype,"_danger",2),c([u()],U.prototype,"_inputLabel",2),c([u()],U.prototype,"_inputType",2),c([u()],U.prototype,"_options",2),c([u()],U.prototype,"_inputValue",2);customElements.get("maintenance-confirm-dialog")||customElements.define("maintenance-confirm-dialog",U)});function Nl(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function Me(r,s){let e=Nl(),t=e.querySelector(`${da}[${pa}]`);return t||(t=document.createElement(da),t.setAttribute(pa,""),e.appendChild(t)),t.hass=r,t.confirm(s)}var da,pa,Ai=y(()=>{"use strict";ca();da="maintenance-confirm-dialog",pa="data-ms-lovelace-confirm"});var Ce,Hs=y(()=>{"use strict";R();j();us();Ce=class extends E{constructor(){super(...arguments);this.docId="";this._url="";this._failed=!1;this._signedFor=""}updated(){this.hass&&this.docId&&this._signedFor!==this.docId&&(this._signedFor=this.docId,this._url="",this._failed=!1,this._sign())}async _sign(){try{this._url=await ps(this.hass,this.docId)}catch{this._failed=!0}}render(){return this._failed||!this.docId?p:this._url?l`
|
||||
<a href=${this._url} target="_blank" rel="noopener" class="wrap">
|
||||
<img src=${this._url} alt="" loading="lazy"
|
||||
@error=${()=>this._failed=!0} />
|
||||
@@ -3828,7 +3836,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||
margin-top: 4px;
|
||||
}
|
||||
`,c([f({attribute:!1})],Ce.prototype,"hass",2),c([f()],Ce.prototype,"docId",2),c([u()],Ce.prototype,"_url",2),c([u()],Ce.prototype,"_failed",2);customElements.get("maintenance-history-photo")||customElements.define("maintenance-history-photo",Ce)});var W,pa=y(()=>{"use strict";R();j();C();Se();ee();Ot();Ti();Es();yi();Ai();ot();xi();Os();qt();qt();W=class extends E{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null;this._partOptions=null;this._partQty={};this._partQtyOriginal="";this._openGen=0;this._photos=new rt(this,{entryId:()=>this._draft?.entry_id??"",hass:()=>this.hass});this._photosOriginal="";this._readingRows=[];this._readingText={};this._readingsOriginal=""}get _lang(){return P(this.hass)}openEdit(e){this._openGen++,this._draft={...e},this._originalSnapshot={...e},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._photos.reset(e.photo_doc_ids??[]),this._photosOriginal=JSON.stringify(this._photos.ids),this._seedReadings(e),this._loadPartOptions()}_seedReadings(e){let t=[],i=new Set;for(let o of e.readings??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));for(let o of e.reading_values??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));this._readingRows=t;let a={};for(let o of e.reading_values??[])a[o.id]=String(o.value);this._readingText=a,this._readingsOriginal=JSON.stringify(this._readingNumbers())}_readingNumbers(){let e={};for(let t of this._readingRows){let i=(this._readingText[t.id]??"").trim();if(i==="")continue;let a=parseFloat(i.replace(",","."));isNaN(a)||(e[t.id]=a)}return e}async _loadPartOptions(){let e=this._draft;if(!e)return;let t=this._openGen;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"});if(t!==this._openGen)return;let a=[];for(let d of i.parts||[]){let h=d.entry_id===e.entry_id,_=d.consumers.some(m=>m.entry_id===e.entry_id&&m.task_id===e.task_id);!h&&!_||a.push({part_id:d.part_id,name:d.name,entry_id:d.entry_id,foreign:!h,object_name:d.object_name})}for(let d of e.used_parts||[]){let h=d.entry_id||e.entry_id;a.some(_=>_.part_id===d.part_id&&_.entry_id===h)||a.push({part_id:d.part_id,name:d.name||d.part_id,entry_id:h,foreign:h!==e.entry_id,object_name:null})}let o={};for(let d of e.used_parts||[])o[`${d.entry_id||e.entry_id}:${d.part_id}`]=d.quantity??1;this._partOptions=a,this._partQty=o,this._partQtyOriginal=this._partSelectionKey()}catch{if(t!==this._openGen)return;this._partOptions=[]}}_partSelectionKey(){return JSON.stringify(Object.entries(this._partQty).filter(([,e])=>e>0).sort(([e],[t])=>e.localeCompare(t)))}close(){this._openGen++,this._open=!1,this._error="",this._draft=null,this._originalSnapshot=null,this._photos.discardOrphans()}_set(e,t){this._draft&&(this._draft={...this._draft,[e]:t})}async _delete(){if(!this._draft||!this._originalSnapshot)return;let e=this._lang,i=(this._originalSnapshot.used_parts||[]).filter(h=>h.quantity>0).map(h=>`${I(h.quantity,e)}\xD7 ${h.name||h.part_id}`).join(", ");if(!await Me(this.hass,{title:n("history_delete_entry",e),message:i?`${n("history_delete_confirm_entry",e)} ${n("history_delete_returns_parts",e).replace("{parts}",i)}`:n("history_delete_confirm_entry",e),confirmText:n("delete",e),danger:!0})||!this._draft||!this._originalSnapshot)return;let o=this._draft;this._error="",await this._runWs({type:"maintenance_supporter/task/history/delete",entry_id:o.entry_id,task_id:o.task_id,timestamp:this._originalSnapshot.original_timestamp})!==void 0&&(this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:o.entry_id,task_id:o.task_id,deleted:!0},bubbles:!0,composed:!0})),this.close())}_runWs(e){return D(this,e,{busy:t=>{this._saving=t},onError:t=>{this._error=t}})}async _save(){if(!this._draft||!this._originalSnapshot||this._saving||this._photos.uploading)return;this._error="",this._photos.clearError();let e=this._draft,t=this._originalSnapshot,i={type:"maintenance_supporter/task/history/update",entry_id:e.entry_id,task_id:e.task_id,original_timestamp:t.original_timestamp};if(e.timestamp!==t.timestamp&&(i.timestamp=e.timestamp),e.notes!==t.notes&&(i.notes=e.notes),e.cost!==t.cost&&(i.cost=e.cost),e.duration!==t.duration&&(i.duration=e.duration),e.completed_by!==t.completed_by&&(i.completed_by=e.completed_by),this._partOptions!==null&&this._partSelectionKey()!==this._partQtyOriginal&&(i.used_parts=(this._partOptions||[]).filter(o=>(this._partQty[`${o.entry_id}:${o.part_id}`]||0)>0).map(o=>({part_id:o.part_id,quantity:this._partQty[`${o.entry_id}:${o.part_id}`],...o.foreign?{entry_id:o.entry_id}:{}}))),e.reading_value!==t.reading_value&&(i.reading_value=e.reading_value??null),this._readingRows.length>0&&JSON.stringify(this._readingNumbers())!==this._readingsOriginal){let o=this._readingNumbers(),d={};for(let h of this._readingRows)d[h.id]=o[h.id]??null;i.reading_values=d}if(JSON.stringify
Line truncated
|
||||
`,c([f({attribute:!1})],Ce.prototype,"hass",2),c([f()],Ce.prototype,"docId",2),c([u()],Ce.prototype,"_url",2),c([u()],Ce.prototype,"_failed",2);customElements.get("maintenance-history-photo")||customElements.define("maintenance-history-photo",Ce)});var W,ua=y(()=>{"use strict";R();j();C();Se();ee();Ot();Ti();Ss();yi();Ai();ot();xi();Hs();qt();qt();W=class extends E{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null;this._partOptions=null;this._partQty={};this._partQtyOriginal="";this._openGen=0;this._photos=new rt(this,{entryId:()=>this._draft?.entry_id??"",hass:()=>this.hass});this._photosOriginal="";this._readingRows=[];this._readingText={};this._readingsOriginal=""}get _lang(){return P(this.hass)}openEdit(e){this._openGen++,this._draft={...e},this._originalSnapshot={...e},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._photos.reset(e.photo_doc_ids??[]),this._photosOriginal=JSON.stringify(this._photos.ids),this._seedReadings(e),this._loadPartOptions()}_seedReadings(e){let t=[],i=new Set;for(let o of e.readings??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));for(let o of e.reading_values??[])i.has(o.id)||(i.add(o.id),t.push({id:o.id,name:o.name,unit:o.unit??null}));this._readingRows=t;let a={};for(let o of e.reading_values??[])a[o.id]=String(o.value);this._readingText=a,this._readingsOriginal=JSON.stringify(this._readingNumbers())}_readingNumbers(){let e={};for(let t of this._readingRows){let i=(this._readingText[t.id]??"").trim();if(i==="")continue;let a=parseFloat(i.replace(",","."));isNaN(a)||(e[t.id]=a)}return e}async _loadPartOptions(){let e=this._draft;if(!e)return;let t=this._openGen;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"});if(t!==this._openGen)return;let a=[];for(let d of i.parts||[]){let h=d.entry_id===e.entry_id,_=d.consumers.some(m=>m.entry_id===e.entry_id&&m.task_id===e.task_id);!h&&!_||a.push({part_id:d.part_id,name:d.name,entry_id:d.entry_id,foreign:!h,object_name:d.object_name})}for(let d of e.used_parts||[]){let h=d.entry_id||e.entry_id;a.some(_=>_.part_id===d.part_id&&_.entry_id===h)||a.push({part_id:d.part_id,name:d.name||d.part_id,entry_id:h,foreign:h!==e.entry_id,object_name:null})}let o={};for(let d of e.used_parts||[])o[`${d.entry_id||e.entry_id}:${d.part_id}`]=d.quantity??1;this._partOptions=a,this._partQty=o,this._partQtyOriginal=this._partSelectionKey()}catch{if(t!==this._openGen)return;this._partOptions=[]}}_partSelectionKey(){return JSON.stringify(Object.entries(this._partQty).filter(([,e])=>e>0).sort(([e],[t])=>e.localeCompare(t)))}close(){this._openGen++,this._open=!1,this._error="",this._draft=null,this._originalSnapshot=null,this._photos.discardOrphans()}_set(e,t){this._draft&&(this._draft={...this._draft,[e]:t})}async _delete(){if(!this._draft||!this._originalSnapshot)return;let e=this._lang,i=(this._originalSnapshot.used_parts||[]).filter(h=>h.quantity>0).map(h=>`${I(h.quantity,e)}\xD7 ${h.name||h.part_id}`).join(", ");if(!await Me(this.hass,{title:n("history_delete_entry",e),message:i?`${n("history_delete_confirm_entry",e)} ${n("history_delete_returns_parts",e).replace("{parts}",i)}`:n("history_delete_confirm_entry",e),confirmText:n("delete",e),danger:!0})||!this._draft||!this._originalSnapshot)return;let o=this._draft;this._error="",await this._runWs({type:"maintenance_supporter/task/history/delete",entry_id:o.entry_id,task_id:o.task_id,timestamp:this._originalSnapshot.original_timestamp})!==void 0&&(this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:o.entry_id,task_id:o.task_id,deleted:!0},bubbles:!0,composed:!0})),this.close())}_runWs(e){return D(this,e,{busy:t=>{this._saving=t},onError:t=>{this._error=t}})}async _save(){if(!this._draft||!this._originalSnapshot||this._saving||this._photos.uploading)return;this._error="",this._photos.clearError();let e=this._draft,t=this._originalSnapshot,i={type:"maintenance_supporter/task/history/update",entry_id:e.entry_id,task_id:e.task_id,original_timestamp:t.original_timestamp};if(e.timestamp!==t.timestamp&&(i.timestamp=e.timestamp),e.notes!==t.notes&&(i.notes=e.notes),e.cost!==t.cost&&(i.cost=e.cost),e.duration!==t.duration&&(i.duration=e.duration),e.completed_by!==t.completed_by&&(i.completed_by=e.completed_by),this._partOptions!==null&&this._partSelectionKey()!==this._partQtyOriginal&&(i.used_parts=(this._partOptions||[]).filter(o=>(this._partQty[`${o.entry_id}:${o.part_id}`]||0)>0).map(o=>({part_id:o.part_id,quantity:this._partQty[`${o.entry_id}:${o.part_id}`],...o.foreign?{entry_id:o.entry_id}:{}}))),e.reading_value!==t.reading_value&&(i.reading_value=e.reading_value??null),this._readingRows.length>0&&JSON.stringify(this._readingNumbers())!==this._readingsOriginal){let o=this._readingNumbers(),d={};for(let h of this._readingRows)d[h.id]=o[h.id]??null;i.reading_values=d}if(JSON.stringify
Line truncated
|
||||
<h2>${n("history_edit_title",e)}</h2>
|
||||
<div class="entry-type">
|
||||
<ha-icon icon="mdi:tag-outline"></ha-icon>
|
||||
@@ -3841,7 +3849,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.lang=${e}
|
||||
.label=${n("history_edit_timestamp",e)}
|
||||
.helper=${oi(e)}
|
||||
.value=${Gr(t.timestamp)}
|
||||
.value=${Kr(t.timestamp)}
|
||||
@value-changed=${a=>{let o=a.detail.value;o&&this._set("timestamp",o)}}
|
||||
></ms-date-field>
|
||||
<label>
|
||||
@@ -4018,7 +4026,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
}
|
||||
/* the camera / gallery pickers come from photoPickerStyles (ms-photo-picker) */
|
||||
.photos-hint { font-size: 12px; color: var(--secondary-text-color); }
|
||||
`],c([f({attribute:!1})],W.prototype,"hass",2),c([u()],W.prototype,"_open",2),c([u()],W.prototype,"_saving",2),c([u()],W.prototype,"_error",2),c([u()],W.prototype,"_draft",2),c([u()],W.prototype,"_partOptions",2),c([u()],W.prototype,"_partQty",2),c([u()],W.prototype,"_readingRows",2),c([u()],W.prototype,"_readingText",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",W)});function ze(r){return r.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function Hs(r){return!r.startsWith("data:image/svg+xml,")&&!r.startsWith("data:image/png;base64,")?"":ze(r)}function Pl(r){return r.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var V,ua=y(()=>{"use strict";R();j();C();cs();V=class extends E{constructor(){super(...arguments);this.lang="";this._open=!1;this._loading=!1;this._error="";this._viewResult=null;this._completeResult=null;this._quickResult=null;this._urlMode="companion";this._entryId="";this._taskId=null;this._objectName="";this._taskName="";this._generateSeq=0}get _dialogLang(){return this.lang||P(this.hass)}openForObject(e,t){this._entryId=e,this._taskId=null,this._objectName=t,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}openForTask(e,t,i,a){this._entryId=e,this._taskId=t,this._objectName=i,this._taskName=a,this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}async _generate(){let e=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null;try{let t={type:"maintenance_supporter/qr/generate",entry_id:this._entryId,url_mode:this._urlMode};this._taskId&&(t.task_id=this._taskId);let i=[this.hass.connection.sendMessagePromise({...t,action:"view"})];this._taskId&&(i.push(this.hass.connection.sendMessagePromise({...t,action:"complete"})),await this._hasQuickCompleteDefaults()&&i.push(this.hass.connection.sendMessagePromise({...t,action:"quick_complete"})));let a=await Promise.all(i);if(e!==this._generateSeq)return;this._viewResult=a[0],a.length>1&&(this._completeResult=a[1]),a.length>2&&(this._quickResult=a[2])}catch(t){if(e!==this._generateSeq)return;let i=t?.code,a=t?.message;this._error=i==="no_url"||typeof a=="string"&&a.includes("No Home Assistant URL")?n("qr_error_no_url",this._dialogLang):n("qr_error",this._dialogLang)}finally{e===this._generateSeq&&(this._loading=!1)}}async _hasQuickCompleteDefaults(){try{let t=((await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId})).tasks||[]).find(i=>i.id===this._taskId);return!!t?.quick_complete_defaults&&Object.keys(t.quick_complete_defaults).length>0}catch{return!1}}_setUrlMode(e){this._urlMode!==e&&(this._urlMode=e,this._generate())}_print(){if(!this._viewResult)return;let e=this._viewResult,t=e.label.task_name?`${e.label.object_name} \u2014 ${e.label.task_name}`:e.label.object_name,i=[e.label.manufacturer,e.label.model].filter(Boolean).join(" "),a=window.open("","_blank","width=600,height=500");if(!a)return;let o=this._dialogLang,d=ze(t),h=ze(i),_=!!this._completeResult,m=!!this._quickResult,b=ze(n("qr_action_view",o)),k=ze(n("qr_action_complete",o)),w=ze(n("qr_action_quick_complete",o));a.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
||||
`],c([f({attribute:!1})],W.prototype,"hass",2),c([u()],W.prototype,"_open",2),c([u()],W.prototype,"_saving",2),c([u()],W.prototype,"_error",2),c([u()],W.prototype,"_draft",2),c([u()],W.prototype,"_partOptions",2),c([u()],W.prototype,"_partQty",2),c([u()],W.prototype,"_readingRows",2),c([u()],W.prototype,"_readingText",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",W)});function ze(r){return r.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function js(r){return!r.startsWith("data:image/svg+xml,")&&!r.startsWith("data:image/png;base64,")?"":ze(r)}function Ol(r){return r.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var V,ha=y(()=>{"use strict";R();j();C();ds();V=class extends E{constructor(){super(...arguments);this.lang="";this._open=!1;this._loading=!1;this._error="";this._viewResult=null;this._completeResult=null;this._quickResult=null;this._urlMode="companion";this._entryId="";this._taskId=null;this._objectName="";this._taskName="";this._generateSeq=0}get _dialogLang(){return this.lang||P(this.hass)}openForObject(e,t){this._entryId=e,this._taskId=null,this._objectName=t,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}openForTask(e,t,i,a){this._entryId=e,this._taskId=t,this._objectName=i,this._taskName=a,this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null,this._open=!0,this._generate()}async _generate(){let e=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=null,this._quickResult=null;try{let t={type:"maintenance_supporter/qr/generate",entry_id:this._entryId,url_mode:this._urlMode};this._taskId&&(t.task_id=this._taskId);let i=[this.hass.connection.sendMessagePromise({...t,action:"view"})];this._taskId&&(i.push(this.hass.connection.sendMessagePromise({...t,action:"complete"})),await this._hasQuickCompleteDefaults()&&i.push(this.hass.connection.sendMessagePromise({...t,action:"quick_complete"})));let a=await Promise.all(i);if(e!==this._generateSeq)return;this._viewResult=a[0],a.length>1&&(this._completeResult=a[1]),a.length>2&&(this._quickResult=a[2])}catch(t){if(e!==this._generateSeq)return;let i=t?.code,a=t?.message;this._error=i==="no_url"||typeof a=="string"&&a.includes("No Home Assistant URL")?n("qr_error_no_url",this._dialogLang):n("qr_error",this._dialogLang)}finally{e===this._generateSeq&&(this._loading=!1)}}async _hasQuickCompleteDefaults(){try{let t=((await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId})).tasks||[]).find(i=>i.id===this._taskId);return!!t?.quick_complete_defaults&&Object.keys(t.quick_complete_defaults).length>0}catch{return!1}}_setUrlMode(e){this._urlMode!==e&&(this._urlMode=e,this._generate())}_print(){if(!this._viewResult)return;let e=this._viewResult,t=e.label.task_name?`${e.label.object_name} \u2014 ${e.label.task_name}`:e.label.object_name,i=[e.label.manufacturer,e.label.model].filter(Boolean).join(" "),a=window.open("","_blank","width=600,height=500");if(!a)return;let o=this._dialogLang,d=ze(t),h=ze(i),_=!!this._completeResult,m=!!this._quickResult,b=ze(n("qr_action_view",o)),k=ze(n("qr_action_complete",o)),w=ze(n("qr_action_quick_complete",o));a.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
||||
<meta name="color-scheme" content="light">
|
||||
<title>${d}</title>
|
||||
<style>
|
||||
@@ -4040,21 +4048,21 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
${h?`<div class="sub">${h}</div>`:""}
|
||||
<div class="qr-row">
|
||||
<div class="qr-col">
|
||||
<img src="${Hs(this._viewResult.svg_data_uri)}" alt="QR Info" />
|
||||
<img src="${js(this._viewResult.svg_data_uri)}" alt="QR Info" />
|
||||
<div class="qr-label">${b}</div>
|
||||
</div>
|
||||
${_?`<div class="qr-col">
|
||||
<img src="${Hs(this._completeResult.svg_data_uri)}" alt="QR Complete" />
|
||||
<img src="${js(this._completeResult.svg_data_uri)}" alt="QR Complete" />
|
||||
<div class="qr-label">${k}</div>
|
||||
</div>`:""}
|
||||
${m?`<div class="qr-col">
|
||||
<img src="${Hs(this._quickResult.svg_data_uri)}" alt="QR Quick-complete" />
|
||||
<img src="${js(this._quickResult.svg_data_uri)}" alt="QR Quick-complete" />
|
||||
<div class="qr-label">${w}</div>
|
||||
</div>`:""}
|
||||
</div>
|
||||
<div class="url">${ze(this._viewResult.url)}</div>
|
||||
<script>setTimeout(()=>window.print(),300)<\/script>
|
||||
</body></html>`),a.document.close()}_downloadSvg(e,t){let i=decodeURIComponent(e.svg_data_uri.replace("data:image/svg+xml,","")),a=this._taskName?`${this._objectName}-${this._taskName}`:this._objectName;an(i,`qr-${Pl(a)}-${t}.svg`,"image/svg+xml")}_close(){this._open=!1,this._viewResult=null,this._completeResult=null,this._quickResult=null,this._error="",this._loading=!1}render(){if(!this._open)return l``;let e=this._dialogLang,t=this._taskName?`${n("qr_code",e)}: ${this._objectName} \u2014 ${this._taskName}`:`${n("qr_code",e)}: ${this._objectName}`,i=!!this._viewResult;return l`
|
||||
</body></html>`),a.document.close()}_downloadSvg(e,t){let i=decodeURIComponent(e.svg_data_uri.replace("data:image/svg+xml,","")),a=this._taskName?`${this._objectName}-${this._taskName}`:this._objectName;on(i,`qr-${Ol(a)}-${t}.svg`,"image/svg+xml")}_close(){this._open=!1,this._viewResult=null,this._completeResult=null,this._quickResult=null,this._error="",this._loading=!1}render(){if(!this._open)return l``;let e=this._dialogLang,t=this._taskName?`${n("qr_code",e)}: ${this._objectName} \u2014 ${this._taskName}`:`${n("qr_code",e)}: ${this._objectName}`,i=!!this._viewResult;return l`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${t}</div>
|
||||
<div class="content">
|
||||
@@ -4250,14 +4258,14 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
color: var(--text-primary-color, #fff);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
`,c([f({attribute:!1})],V.prototype,"hass",2),c([f()],V.prototype,"lang",2),c([u()],V.prototype,"_open",2),c([u()],V.prototype,"_loading",2),c([u()],V.prototype,"_error",2),c([u()],V.prototype,"_viewResult",2),c([u()],V.prototype,"_completeResult",2),c([u()],V.prototype,"_quickResult",2),c([u()],V.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",V)});function ha(r,s,e=new Date){let t=r?.hours,i=K(r?.snoozed_until);if(typeof t!="number"||!Number.isFinite(i))return n("snoozed",s);let a=ye(),d=xe(i,a)===xe(e,a)?ni(new Date(i),s):ai(r.snoozed_until,s);return(t===1?n("snoozed_for_one",s):n("snoozed_for",s).replace("{hours}",I(t,s))).replace("{until}",d)}var _a=y(()=>{"use strict";C();ee()});var __,ma,ga=y(()=>{Ve();({I:__}=fr),ma=r=>r.strings===void 0});var fa,js,Ci,Ri=y(()=>{fa={ATTRIBUTE:1,CHILD:2,PROPERTY:3,BOOLEAN_ATTRIBUTE:4,EVENT:5,ELEMENT:6},js=r=>(...s)=>({_$litDirective$:r,values:s}),Ci=class{constructor(s){}get _$AU(){return this._$AM._$AU}_$AT(s,e,t){this._$Ct=s,this._$AM=e,this._$Ci=t}_$AS(s,e){return this.update(s,e)}update(s,e){return this.render(...e)}}});function Ll(r){this._$AN!==void 0?(Ii(this),this._$AM=r,va(this)):this._$AM=r}function Nl(r,s=!1,e=0){let t=this._$AH,i=this._$AN;if(i!==void 0&&i.size!==0)if(s)if(Array.isArray(t))for(let a=e;a<t.length;a++)Mt(t[a],!1),Ii(t[a]);else t!=null&&(Mt(t,!1),Ii(t));else Mt(this,r)}var Mt,Ii,va,Ol,Pi,ba=y(()=>{ga();Ri();Ri();Mt=(r,s)=>{let e=r._$AN;if(e===void 0)return!1;for(let t of e)t._$AO?.(s,!1),Mt(t,s);return!0},Ii=r=>{let s,e;do{if((s=r._$AM)===void 0)break;e=s._$AN,e.delete(r),r=s}while(e?.size===0)},va=r=>{for(let s;s=r._$AM;r=s){let e=s._$AN;if(e===void 0)s._$AN=e=new Set;else if(e.has(r))break;e.add(r),Ol(s)}};Ol=r=>{r.type==fa.CHILD&&(r._$AP??=Nl,r._$AQ??=Ll)},Pi=class extends Ci{constructor(){super(...arguments),this._$AN=void 0}_$AT(s,e,t){super._$AT(s,e,t),va(this),this.isConnected=s._$AU}_$AO(s,e=!0){s!==this.isConnected&&(this.isConnected=s,s?this.reconnected?.():this.disconnected?.()),e&&(Mt(this,s),Ii(this))}setValue(s){if(ma(this._$Ct))this._$Ct._$AI(s,this);else{let e=[...this._$Ct._$AH];e[this._$Ci]=s,this._$Ct._$AI(e,this,0)}}disconnected(){}reconnected(){}}});var Ds,ya,xa=y(()=>{Ve();ba();Ri();Ds=new WeakMap,ya=js(class extends Pi{render(r){return p}update(r,[s]){let e=s!==this.G;return e&&this.G!==void 0&&this.rt(void 0),(e||this.lt!==this.ct)&&(this.G=s,this.ht=r.options?.host,this.rt(this.ct=r.element)),p}rt(r){if(this.isConnected||(r=void 0),typeof this.G=="function"){let s=this.ht??globalThis,e=Ds.get(s);e===void 0&&(e=new WeakMap,Ds.set(s,e)),e.get(this.G)!==void 0&&this.G.call(this.ht,void 0),e.set(this.G,r),r!==void 0&&this.G.call(this.ht,r)}else this.G.value=r}get lt(){return typeof this.G=="function"?Ds.get(this.ht??globalThis)?.get(this.G):this.G?.value}disconnected(){this.lt===this.ct&&this.rt(void 0)}reconnected(){this.rt(this.ct)}})});var wa=y(()=>{xa()});function Ni(r){if(!r)return p;if(customElements.get("ha-markdown")){let{content:s,links:e}=Dl(r);return l`<ha-markdown
|
||||
`,c([f({attribute:!1})],V.prototype,"hass",2),c([f()],V.prototype,"lang",2),c([u()],V.prototype,"_open",2),c([u()],V.prototype,"_loading",2),c([u()],V.prototype,"_error",2),c([u()],V.prototype,"_viewResult",2),c([u()],V.prototype,"_completeResult",2),c([u()],V.prototype,"_quickResult",2),c([u()],V.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",V)});function _a(r,s,e=new Date){let t=r?.hours,i=K(r?.snoozed_until);if(typeof t!="number"||!Number.isFinite(i))return n("snoozed",s);let a=ye(),d=xe(i,a)===xe(e,a)?ni(new Date(i),s):ai(r.snoozed_until,s);return(t===1?n("snoozed_for_one",s):n("snoozed_for",s).replace("{hours}",I(t,s))).replace("{until}",d)}var ma=y(()=>{"use strict";C();ee()});var v_,ga,fa=y(()=>{Ve();({I:v_}=vr),ga=r=>r.strings===void 0});var va,Ds,Ci,Ri=y(()=>{va={ATTRIBUTE:1,CHILD:2,PROPERTY:3,BOOLEAN_ATTRIBUTE:4,EVENT:5,ELEMENT:6},Ds=r=>(...s)=>({_$litDirective$:r,values:s}),Ci=class{constructor(s){}get _$AU(){return this._$AM._$AU}_$AT(s,e,t){this._$Ct=s,this._$AM=e,this._$Ci=t}_$AS(s,e){return this.update(s,e)}update(s,e){return this.render(...e)}}});function Hl(r){this._$AN!==void 0?(Ii(this),this._$AM=r,ba(this)):this._$AM=r}function jl(r,s=!1,e=0){let t=this._$AH,i=this._$AN;if(i!==void 0&&i.size!==0)if(s)if(Array.isArray(t))for(let a=e;a<t.length;a++)Mt(t[a],!1),Ii(t[a]);else t!=null&&(Mt(t,!1),Ii(t));else Mt(this,r)}var Mt,Ii,ba,Dl,Pi,ya=y(()=>{fa();Ri();Ri();Mt=(r,s)=>{let e=r._$AN;if(e===void 0)return!1;for(let t of e)t._$AO?.(s,!1),Mt(t,s);return!0},Ii=r=>{let s,e;do{if((s=r._$AM)===void 0)break;e=s._$AN,e.delete(r),r=s}while(e?.size===0)},ba=r=>{for(let s;s=r._$AM;r=s){let e=s._$AN;if(e===void 0)s._$AN=e=new Set;else if(e.has(r))break;e.add(r),Dl(s)}};Dl=r=>{r.type==va.CHILD&&(r._$AP??=jl,r._$AQ??=Hl)},Pi=class extends Ci{constructor(){super(...arguments),this._$AN=void 0}_$AT(s,e,t){super._$AT(s,e,t),ba(this),this.isConnected=s._$AU}_$AO(s,e=!0){s!==this.isConnected&&(this.isConnected=s,s?this.reconnected?.():this.disconnected?.()),e&&(Mt(this,s),Ii(this))}setValue(s){if(ga(this._$Ct))this._$Ct._$AI(s,this);else{let e=[...this._$Ct._$AH];e[this._$Ci]=s,this._$Ct._$AI(e,this,0)}}disconnected(){}reconnected(){}}});var qs,xa,wa=y(()=>{Ve();ya();Ri();qs=new WeakMap,xa=Ds(class extends Pi{render(r){return p}update(r,[s]){let e=s!==this.G;return e&&this.G!==void 0&&this.rt(void 0),(e||this.lt!==this.ct)&&(this.G=s,this.ht=r.options?.host,this.rt(this.ct=r.element)),p}rt(r){if(this.isConnected||(r=void 0),typeof this.G=="function"){let s=this.ht??globalThis,e=qs.get(s);e===void 0&&(e=new WeakMap,qs.set(s,e)),e.get(this.G)!==void 0&&this.G.call(this.ht,void 0),e.set(this.G,r),r!==void 0&&this.G.call(this.ht,r)}else this.G.value=r}get lt(){return typeof this.G=="function"?qs.get(this.ht??globalThis)?.get(this.G):this.G?.value}disconnected(){this.lt===this.ct&&this.rt(void 0)}reconnected(){this.rt(this.ct)}})});var ka=y(()=>{wa()});function Ni(r){if(!r)return p;if(customElements.get("ha-markdown")){let{content:s,links:e}=zl(r);return l`<ha-markdown
|
||||
class="notes-md"
|
||||
.content=${s}
|
||||
breaks
|
||||
${ya(t=>ql(t,e))}
|
||||
></ha-markdown>`}return l`${r}`}function Dl(r){let s=[],e=a=>{let o=hs(a);return!o||Hl.has(o)||!Ze(a)?null:(s.push(us(a)),`${Ms}${s.length-1}`)},t=a=>a.replace(new RegExp(`(!?)(\\[[^\\]\\n]*\\]\\(\\s*)<(${Li}[^>\\n]*)>`,"g"),(o,d,h,_)=>{let m=d?null:e(_);return m?`${h}${m}`:o}).replace(new RegExp(`(!?)(\\[[^\\]\\n]*\\]\\(\\s*)(${Li}[^\\s)]*)`,"g"),(o,d,h,_)=>{let m=d?null:e(_);return m?`${h}${m}`:o}).replace(new RegExp(`(^|[^(])<(${Li}[^\\s<>]*)>`,"gm"),(o,d,h)=>{let _=e(h);return _?`${d}[${h.replace(/([\\[\]])/g,"\\$1")}](${_})`:o}).replace(new RegExp(`^( {0,3}\\[[^\\]\\n]+\\]:[ \\t]*)<?(${Li}[^\\s>]*)>?`,"gm"),(o,d,h)=>{let _=e(h);return _?`${d}${_}`:o});return{content:r.split(jl).map((a,o)=>o%2?a:t(a)).join(""),links:s}}function qs(r,s){for(let e of r.querySelectorAll(`a[href^="${Ms}"]`)){let t=s[Number(e.getAttribute("href").slice(Ms.length))];t&&e.setAttribute("href",t)}}function ql(r,s){if(!r)return;let e=ka.get(r);if(!e&&s.length===0)return;if(e){e.links=s,r.shadowRoot&&qs(r.shadowRoot,s);return}let t={links:s};ka.set(r,t),(async()=>{await r.updateComplete;let i=r.shadowRoot;i&&(new MutationObserver(()=>qs(i,t.links)).observe(i,{childList:!0,subtree:!0}),qs(i,t.links))})()}var Ms,Hl,jl,Li,ka,zs=y(()=>{"use strict";R();wa();di();Ms="https://app-link.invalid/",Hl=new Set(["http","https","mailto","tel","ftp"]),jl=/(```[\s\S]*?```|~~~[\s\S]*?~~~|`[^`\n]*`)/,Li="[a-zA-Z][a-zA-Z0-9+.-]+:";ka=new WeakMap});function $a(r,s,e,t){let i=e,a=h=>typeof h=="string"?h:null,o=h=>typeof h=="number"?h:null,d=a(i.timestamp)??"";return{entry_id:r,task_id:s,original_timestamp:d,type:a(i.type)||"completed",timestamp:d,notes:a(i.notes),cost:o(i.cost),duration:o(i.duration),completed_by:a(i.completed_by),used_parts:Array.isArray(i.used_parts)?i.used_parts:null,photo_doc_ids:vi(i),reading_value:o(i.reading_value),reading_values:$e(i),readings:t?.readings??[],task_type:t?.type??null,reading_unit:t?.reading_unit??null}}var Ea=y(()=>{"use strict";bi();De()});function Ml(r){return r&&Sa(r.ref_no)?String(r.ref_no):null}function Ta(r,s){let e=Ml(r);return e&&s&&Sa(s.ref_no)?`${e}.${s.ref_no}`:null}function Aa(r,s){return r?l`<span class="ref-chip" title=${s??""}>#${r}</span>`:p}var Sa,Fs=y(()=>{"use strict";R();Sa=r=>typeof r=="number"&&Number.isInteger(r)&&r>0});var Ca=y(()=>{"use strict"});function Ra(r,s){if(!r)return"";let e=zl[r.trim()];if(e)return n(e,s);for(let[t,i,a]of Fl){let o=r.trim().match(t);if(o){let d=a(o,s);return n(i,s).replace(/\{(\w+)\}/g,(h,_)=>d[_]??h)}}return r}var zl,Fl,Ia=y(()=>{"use strict";C();zl={"Completed from dashboard button":"hist_note_button","Completed from the To-do list":"hist_note_todo","Completed by voice":"hist_note_voice","Completed from the notification":"hist_note_notification","Completed via NFC tag":"hist_note_nfc","Completed from the shopping list":"hist_note_shopping_list","Completed from a mirrored to-do list":"hist_note_todo_mirror","Skipped from notification":"hist_note_skipped_notification","Skipped from dashboard button":"hist_note_skipped_button","Sensor trigger activated":"hist_note_sensor_triggered","Initial value set during task creation":"hist_note_initial"},Fl=[[/^Auto-completed: sensor recovered \((.+)\)$/,"hist_note_auto_recovered",r=>({value:r[1]})],[/^Reset to (\d{4}-\d{2}-\d{2})$/,"hist_note_reset",(r,s)=>({date:H(r[1],s)})],[/^Trigger entity replaced: (.+) → (.+)$/,"hist_note_trigger_replaced",r=>({old:r[1],new:r[2]})],[/^Sensor trigger removed \(entity was: (.+)\)\. Schedule converted to (\w+)\.$/,"hist_note_trigger_removed",(r,s)=>({entity:r[1],schedule:n(r[2],s)})],[/^Entity (.+) removed from compound trigger; (\d+) conditions remain\.$/,"hist_note_compound_removed",r=>({entity:r[1],count:r[2]})]]});function Pa(r){let s=e=>{let t=K(e.timestamp);return Number.isNaN(t)?-1/0:t};return(r??[]).map((e,t)=>({entry:e,index:t,at:s(e)})).sort((e,t)=>t.at-e.at||t.index-e.index).map(e=>e.entry)}function Bl(r,s){return r.taskRef&&s.ref_no?`${r.taskRef}-${s.ref_no}`:null}function Wl(r,s){let e=vi(s);return e.length>0?l`<div class="history-photos">
|
||||
${xa(t=>Fl(t,e))}
|
||||
></ha-markdown>`}return l`${r}`}function zl(r){let s=[],e=a=>{let o=_s(a);return!o||ql.has(o)||!Ze(a)?null:(s.push(hs(a)),`${zs}${s.length-1}`)},t=a=>a.replace(new RegExp(`(!?)(\\[[^\\]\\n]*\\]\\(\\s*)<(${Li}[^>\\n]*)>`,"g"),(o,d,h,_)=>{let m=d?null:e(_);return m?`${h}${m}`:o}).replace(new RegExp(`(!?)(\\[[^\\]\\n]*\\]\\(\\s*)(${Li}[^\\s)]*)`,"g"),(o,d,h,_)=>{let m=d?null:e(_);return m?`${h}${m}`:o}).replace(new RegExp(`(^|[^(])<(${Li}[^\\s<>]*)>`,"gm"),(o,d,h)=>{let _=e(h);return _?`${d}[${h.replace(/([\\[\]])/g,"\\$1")}](${_})`:o}).replace(new RegExp(`^( {0,3}\\[[^\\]\\n]+\\]:[ \\t]*)<?(${Li}[^\\s>]*)>?`,"gm"),(o,d,h)=>{let _=e(h);return _?`${d}${_}`:o});return{content:r.split(Ml).map((a,o)=>o%2?a:t(a)).join(""),links:s}}function Ms(r,s){for(let e of r.querySelectorAll(`a[href^="${zs}"]`)){let t=s[Number(e.getAttribute("href").slice(zs.length))];t&&e.setAttribute("href",t)}}function Fl(r,s){if(!r)return;let e=$a.get(r);if(!e&&s.length===0)return;if(e){e.links=s,r.shadowRoot&&Ms(r.shadowRoot,s);return}let t={links:s};$a.set(r,t),(async()=>{await r.updateComplete;let i=r.shadowRoot;i&&(new MutationObserver(()=>Ms(i,t.links)).observe(i,{childList:!0,subtree:!0}),Ms(i,t.links))})()}var zs,ql,Ml,Li,$a,Fs=y(()=>{"use strict";R();ka();di();zs="https://app-link.invalid/",ql=new Set(["http","https","mailto","tel","ftp"]),Ml=/(```[\s\S]*?```|~~~[\s\S]*?~~~|`[^`\n]*`)/,Li="[a-zA-Z][a-zA-Z0-9+.-]+:";$a=new WeakMap});function Ea(r,s,e,t){let i=e,a=h=>typeof h=="string"?h:null,o=h=>typeof h=="number"?h:null,d=a(i.timestamp)??"";return{entry_id:r,task_id:s,original_timestamp:d,type:a(i.type)||"completed",timestamp:d,notes:a(i.notes),cost:o(i.cost),duration:o(i.duration),completed_by:a(i.completed_by),used_parts:Array.isArray(i.used_parts)?i.used_parts:null,photo_doc_ids:vi(i),reading_value:o(i.reading_value),reading_values:$e(i),readings:t?.readings??[],task_type:t?.type??null,reading_unit:t?.reading_unit??null}}var Sa=y(()=>{"use strict";bi();De()});function Ul(r){return r&&Ta(r.ref_no)?String(r.ref_no):null}function Aa(r,s){let e=Ul(r);return e&&s&&Ta(s.ref_no)?`${e}.${s.ref_no}`:null}function Ca(r,s){return r?l`<span class="ref-chip" title=${s??""}>#${r}</span>`:p}var Ta,Us=y(()=>{"use strict";R();Ta=r=>typeof r=="number"&&Number.isInteger(r)&&r>0});var Ra=y(()=>{"use strict"});function Ia(r,s){if(!r)return"";let e=Bl[r.trim()];if(e)return n(e,s);for(let[t,i,a]of Wl){let o=r.trim().match(t);if(o){let d=a(o,s);return n(i,s).replace(/\{(\w+)\}/g,(h,_)=>d[_]??h)}}return r}var Bl,Wl,Pa=y(()=>{"use strict";C();Bl={"Completed from dashboard button":"hist_note_button","Completed from the To-do list":"hist_note_todo","Completed by voice":"hist_note_voice","Completed from the notification":"hist_note_notification","Completed via NFC tag":"hist_note_nfc","Completed from the shopping list":"hist_note_shopping_list","Completed from a mirrored to-do list":"hist_note_todo_mirror","Skipped from notification":"hist_note_skipped_notification","Skipped from dashboard button":"hist_note_skipped_button","Sensor trigger activated":"hist_note_sensor_triggered","Initial value set during task creation":"hist_note_initial"},Wl=[[/^Auto-completed: sensor recovered \((.+)\)$/,"hist_note_auto_recovered",r=>({value:r[1]})],[/^Reset to (\d{4}-\d{2}-\d{2})$/,"hist_note_reset",(r,s)=>({date:H(r[1],s)})],[/^Trigger entity replaced: (.+) → (.+)$/,"hist_note_trigger_replaced",r=>({old:r[1],new:r[2]})],[/^Sensor trigger removed \(entity was: (.+)\)\. Schedule converted to (\w+)\.$/,"hist_note_trigger_removed",(r,s)=>({entity:r[1],schedule:n(r[2],s)})],[/^Entity (.+) removed from compound trigger; (\d+) conditions remain\.$/,"hist_note_compound_removed",r=>({entity:r[1],count:r[2]})]]});function La(r){let s=e=>{let t=K(e.timestamp);return Number.isNaN(t)?-1/0:t};return(r??[]).map((e,t)=>({entry:e,index:t,at:s(e)})).sort((e,t)=>t.at-e.at||t.index-e.index).map(e=>e.entry)}function Gl(r,s){return r.taskRef&&s.ref_no?`${r.taskRef}-${s.ref_no}`:null}function Kl(r,s){let e=vi(s);return e.length>0?l`<div class="history-photos">
|
||||
${e.map(t=>l`<maintenance-history-photo .hass=${r} .docId=${t}></maintenance-history-photo>`)}
|
||||
</div>`:p}function Vl(r,s){let e=s.lang,t=o=>I(o,e,{maximumFractionDigits:3}),i=o=>o==null?"":` (${o>=0?"+":""}${t(o)})`,a=$e(r);return a.length>0?l`<div class="history-readings">
|
||||
</div>`:p}function Yl(r,s){let e=s.lang,t=o=>I(o,e,{maximumFractionDigits:3}),i=o=>o==null?"":` (${o>=0?"+":""}${t(o)})`,a=$e(r);return a.length>0?l`<div class="history-readings">
|
||||
${a.map(o=>l`<span class="history-reading">
|
||||
<span class="history-reading-name">${o.name}</span>
|
||||
<span class="history-reading-value">${t(o.value)}${o.unit?` ${o.unit}`:""}${i(s.readingSlotDelta?.(r,o.id))}</span>
|
||||
@@ -4265,7 +4273,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
</div>`:r.reading_value!=null?l`<div class="history-readings"><span class="history-reading">
|
||||
<span class="history-reading-name">${n("reading_label",e)}</span>
|
||||
<span class="history-reading-value">${t(r.reading_value)}${s.readingUnit?` ${s.readingUnit}`:""}${i(s.readingDelta?.(r))}</span>
|
||||
</span></div>`:p}function La(r,s,e={}){let t=s.lang,{compact:i=!1,showRef:a=!0,showBadges:o=!0,showEdit:d=!0}=e,h=s.openEdit,_=d&&!!h&&Ul.includes(r.type),m=typeof r.parts_cost=="number"?r.parts_cost:null,b=r.cost_basis==="use",k=b&&!!r.purchase;return l`
|
||||
</span></div>`:p}function Na(r,s,e={}){let t=s.lang,{compact:i=!1,showRef:a=!0,showBadges:o=!0,showEdit:d=!0}=e,h=s.openEdit,_=d&&!!h&&Vl.includes(r.type),m=typeof r.parts_cost=="number"?r.parts_cost:null,b=r.cost_basis==="use",k=b&&!!r.purchase;return l`
|
||||
<div class="history-entry${i?" compact":""}">
|
||||
${i?p:l`<div class="history-icon ${r.type}">
|
||||
<ha-icon .icon=${$t[r.type]||"mdi:circle"}></ha-icon>
|
||||
@@ -4273,7 +4281,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
<div class="history-content">
|
||||
<div class="history-row">
|
||||
<strong>${n(r.type,t)}</strong>
|
||||
${a?Aa(Bl(s,r),n("ref_number",t)):p}
|
||||
${a?Ca(Gl(s,r),n("ref_number",t)):p}
|
||||
${o&&r.phase_id?l`<span class="history-phase-badge">${s.phaseNames?.[r.phase_id]||r.phase_id}</span>`:p}
|
||||
${o&&r.auto?l`<span class="history-auto-badge">${n("history_auto",t)}</span>`:p}
|
||||
${_?l`<button class="history-edit-btn"
|
||||
@@ -4283,9 +4291,9 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
</button>`:p}
|
||||
</div>
|
||||
<div class="history-date">${ai(r.timestamp,t)}</div>
|
||||
${r.notes?l`<div class="history-notes">${Ra(r.notes,t)}</div>`:p}
|
||||
${Wl(s.hass,r)}
|
||||
${Vl(r,s)}
|
||||
${r.notes?l`<div class="history-notes">${Ia(r.notes,t)}</div>`:p}
|
||||
${Kl(s.hass,r)}
|
||||
${Yl(r,s)}
|
||||
${r.cost!=null||r.duration!=null||r.trigger_value!=null||m!=null?l`<div class="history-details">
|
||||
${r.cost!=null?k?l`<span>${n("history_purchase_stock",t).replace("{amount}",re(r.cost,s.currencySymbol,t))}</span>`:r.cost<0?l`<span class="history-credit">${n("cost_kind_credit",t)}: ${re(-r.cost,s.currencySymbol,t)}</span>`:l`<span>${n("cost",t)}: ${re(r.cost,s.currencySymbol,t)}</span>`:p}
|
||||
${m!=null?l`<span title=${n(b?"history_parts_counted_hint":"history_parts_info_hint",t)}>${n(b?"history_parts_counted":"history_parts_info",t).replace("{amount}",re(m,s.currencySymbol,t))}</span>`:p}
|
||||
@@ -4294,26 +4302,26 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
</div>`:p}
|
||||
</div>
|
||||
</div>
|
||||
`}var Ul,Na=y(()=>{"use strict";R();C();Os();bi();Fs();De();Ca();Ia();ee();Ul=["completed","reset","skipped"]});function zt(r){return r.archived?"archived":r.is_done?"done":r.status||"ok"}function Us(r,s){return n(r==="done"?"completed":r,s)}function Oi(r){let s=zt(r);return s==="done"?Gl:kt[s]||"var(--disabled-color, #9e9e9e)"}function Kl(r){return $t[r==="done"?"completed":r]||"mdi:circle-medium"}function Oa(r,s,e="pill"){let t=zt(r),i=Us(t,s);return e==="chip"?l`<span class="status-chip ${t}">${i}</span>`:l`<span class="status-badge ${t}" role="img" title="${i}" aria-label="${i}"><ha-icon icon="${Kl(t)}"></ha-icon><span class="status-label">${i}</span></span>`}var Gl,Bs=y(()=>{"use strict";R();C();Et();Gl="var(--maint-done-color, #78909c)"});var Hi,Ha=y(()=>{"use strict";Hi=class{constructor(){this._handle=null}schedule(s,e=4e3){this.clear(),this._handle=setTimeout(()=>{this._handle=null,s()},e)}clear(){this._handle!==null&&(clearTimeout(this._handle),this._handle=null)}get pending(){return this._handle!==null}}});function ja(r,s){let e=r.interval_analysis,t=e?.weibull_beta,i=e?.weibull_eta;if(t==null||i==null||i<=0)return p;let a=r.interval_days??0,o=r.suggested_interval??a;return l`
|
||||
`}var Vl,Oa=y(()=>{"use strict";R();C();Hs();bi();Us();De();Ra();Pa();ee();Vl=["completed","reset","skipped"]});function zt(r){return r.archived?"archived":r.is_done?"done":r.status||"ok"}function Bs(r,s){return n(r==="done"?"completed":r,s)}function Oi(r){let s=zt(r);return s==="done"?Ql:kt[s]||"var(--disabled-color, #9e9e9e)"}function Zl(r){return $t[r==="done"?"completed":r]||"mdi:circle-medium"}function Ha(r,s,e="pill"){let t=zt(r),i=Bs(t,s);return e==="chip"?l`<span class="status-chip ${t}">${i}</span>`:l`<span class="status-badge ${t}" role="img" title="${i}" aria-label="${i}"><ha-icon icon="${Zl(t)}"></ha-icon><span class="status-label">${i}</span></span>`}var Ql,Ws=y(()=>{"use strict";R();C();Et();Ql="var(--maint-done-color, #78909c)"});var Hi,ja=y(()=>{"use strict";Hi=class{constructor(){this._handle=null}schedule(s,e=4e3){this.clear(),this._handle=setTimeout(()=>{this._handle=null,s()},e)}clear(){this._handle!==null&&(clearTimeout(this._handle),this._handle=null)}get pending(){return this._handle!==null}}});function Da(r,s){let e=r.interval_analysis,t=e?.weibull_beta,i=e?.weibull_eta;if(t==null||i==null||i<=0)return p;let a=r.interval_days??0,o=r.suggested_interval??a;return l`
|
||||
<div class="weibull-section">
|
||||
<div class="weibull-title">
|
||||
<ha-svg-icon aria-hidden="true" path="M3,14L3.5,14.07L8.07,9.5C7.89,8.85 8.06,8.11 8.59,7.59C9.37,6.8 10.63,6.8 11.41,7.59C11.94,8.11 12.11,8.85 11.93,9.5L14.5,12.07L15,12C15.18,12 15.35,12 15.5,12.07L19.07,8.5C19,8.35 19,8.18 19,8A2,2 0 0,1 21,6A2,2 0 0,1 23,8A2,2 0 0,1 21,10C20.82,10 20.65,10 20.5,9.93L16.93,13.5C17,13.65 17,13.82 17,14A2,2 0 0,1 15,16A2,2 0 0,1 13,14L13.07,13.5L10.5,10.93C10.18,11 9.82,11 9.5,10.93L4.93,15.5L5,16A2,2 0 0,1 3,18A2,2 0 0,1 1,16A2,2 0 0,1 3,14Z"></ha-svg-icon>
|
||||
${n("weibull_reliability_curve",s)}
|
||||
${Yl(t,s)}
|
||||
${Jl(t,s)}
|
||||
</div>
|
||||
${Ql(t,i,a,o,s)}
|
||||
${Zl(e,s)}
|
||||
${e?.confidence_interval_low!=null?Jl(e,r,s):p}
|
||||
${Xl(t,i,a,o,s)}
|
||||
${ec(e,s)}
|
||||
${e?.confidence_interval_low!=null?tc(e,r,s):p}
|
||||
</div>
|
||||
`}function Yl(r,s){let e,t,i;return r<.8?(e="early_failures",t="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z",i="beta_early_failures"):r<=1.2?(e="random_failures",t="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",i="beta_random_failures"):r<=3.5?(e="wear_out",t="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",i="beta_wear_out"):(e="highly_predictable",t="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",i="beta_highly_predictable"),l`
|
||||
`}function Jl(r,s){let e,t,i;return r<.8?(e="early_failures",t="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z",i="beta_early_failures"):r<=1.2?(e="random_failures",t="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",i="beta_random_failures"):r<=3.5?(e="wear_out",t="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",i="beta_wear_out"):(e="highly_predictable",t="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",i="beta_highly_predictable"),l`
|
||||
<span class="beta-badge ${e}">
|
||||
<ha-svg-icon path="${t}"></ha-svg-icon>
|
||||
${n(i,s)} (\u03B2=${I(r,s,2)})
|
||||
</span>
|
||||
`}function Ql(r,s,e,t,i){let w=Math.max(e,t,s,1)*1.3,v=50,x=[];for(let Z=0;Z<=v;Z++){let se=Z/v*w,so=1-Math.exp(-Math.pow(se/s,r)),ro=32+se/w*260,no=136-so*128;x.push([ro,no])}let T=x.map(([Z,se])=>`${A(Z)},${A(se)}`).join(" "),O="M32,136 "+x.map(([Z,se])=>`L${A(Z)},${A(se)}`).join(" ")+` L${A(x[v][0])},136 Z`,G=32+e/w*260,ce=1-Math.exp(-Math.pow(e/s,r)),Ue=136-ce*128,to=I((1-ce)*100,i,0),Xs=32+t/w*260,io=[0,.25,.5,.75,1];return l`
|
||||
`}function Xl(r,s,e,t,i){let w=Math.max(e,t,s,1)*1.3,v=50,x=[];for(let Z=0;Z<=v;Z++){let se=Z/v*w,ro=1-Math.exp(-Math.pow(se/s,r)),no=32+se/w*260,ao=136-ro*128;x.push([no,ao])}let T=x.map(([Z,se])=>`${A(Z)},${A(se)}`).join(" "),O="M32,136 "+x.map(([Z,se])=>`L${A(Z)},${A(se)}`).join(" ")+` L${A(x[v][0])},136 Z`,G=32+e/w*260,ce=1-Math.exp(-Math.pow(e/s,r)),Ue=136-ce*128,io=I((1-ce)*100,i,0),er=32+t/w*260,so=[0,.25,.5,.75,1];return l`
|
||||
<div class="weibull-chart">
|
||||
<svg viewBox="0 0 ${300} ${160}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${n("chart_weibull",i)}">
|
||||
${io.map(Z=>{let se=136-Z*128;return We`
|
||||
${so.map(Z=>{let se=136-Z*128;return We`
|
||||
<line x1="${32}" y1="${A(se)}" x2="${292}" y2="${A(se)}"
|
||||
stroke="var(--divider-color)" stroke-width="0.5" stroke-dasharray="${Z===.5?"4,3":p}" />
|
||||
<text x="${28}" y="${A(se+3)}" fill="var(--secondary-text-color)"
|
||||
@@ -4334,11 +4342,11 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
<circle cx="${A(G)}" cy="${A(Ue)}" r="3"
|
||||
fill="var(--primary-color, #03a9f4)" />
|
||||
<text x="${A(G+4)}" y="${A(Ue-6)}" fill="var(--primary-color, #03a9f4)"
|
||||
font-size="9" font-weight="600">R=${to}%</text>
|
||||
font-size="9" font-weight="600">R=${io}%</text>
|
||||
`:p}
|
||||
|
||||
${t>0&&t!==e?We`
|
||||
<line x1="${A(Xs)}" y1="${8}" x2="${A(Xs)}" y2="${A(136)}"
|
||||
<line x1="${A(er)}" y1="${8}" x2="${A(er)}" y2="${A(136)}"
|
||||
stroke="var(--success-color, #4caf50)" stroke-width="1.5" stroke-dasharray="4,3" />
|
||||
`:p}
|
||||
|
||||
@@ -4353,7 +4361,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
${e>0?l`<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color, #03a9f4); opacity:0.5"></span> ${n("current_interval_marker",i)}</span>`:p}
|
||||
${t>0&&t!==e?l`<span class="legend-item"><span class="legend-swatch" style="background:var(--success-color, #4caf50)"></span> ${n("recommended_marker",i)}</span>`:p}
|
||||
</div>
|
||||
`}function Zl(r,s){return l`
|
||||
`}function ec(r,s){return l`
|
||||
<div class="weibull-info-row">
|
||||
<div class="weibull-info-item">
|
||||
<span>${n("characteristic_life",s)}</span>
|
||||
@@ -4366,7 +4374,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
</div>
|
||||
`:p}
|
||||
</div>
|
||||
`}function Jl(r,s,e){let t=r.confidence_interval_low,i=r.confidence_interval_high,a=s.suggested_interval??s.interval_days??0,o=s.interval_days??0,d=Math.max(0,t-5),_=i+5-d,m=(t-d)/_*100,b=(i-t)/_*100,k=(a-d)/_*100,w=o>0?(o-d)/_*100:-1;return l`
|
||||
`}function tc(r,s,e){let t=r.confidence_interval_low,i=r.confidence_interval_high,a=s.suggested_interval??s.interval_days??0,o=s.interval_days??0,d=Math.max(0,t-5),_=i+5-d,m=(t-d)/_*100,b=(i-t)/_*100,k=(a-d)/_*100,w=o>0?(o-d)/_*100:-1;return l`
|
||||
<div class="confidence-range">
|
||||
<div class="confidence-range-title">
|
||||
${n("confidence_interval",e)}: ${a} ${n("days",e)} (${t}\u2013${i})
|
||||
@@ -4381,7 +4389,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
<span class="confidence-text high">${n("confidence_aggressive",e)} (${i}${n("days",e).charAt(0)})</span>
|
||||
</div>
|
||||
</div>
|
||||
`}var Da=y(()=>{"use strict";R();C();$i()});function qa(r,s,e){let t=r.degradation_trend!=null&&r.degradation_trend!=="insufficient_data",i=r.days_until_threshold!=null,a=r.environmental_factor!=null&&r.environmental_factor!==1;if(!t&&!i&&!a)return p;let o=r.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":r.degradation_trend==="falling"?"M16,18L18.29,15.71L13.41,10.83L9.41,14.83L2,7.41L3.41,6L9.41,12L13.41,8L19.71,14.29L22,12V18H16Z":"M22,12L18,8V11H3V13H18V16L22,12Z";return l`
|
||||
`}var qa=y(()=>{"use strict";R();C();$i()});function Ma(r,s,e){let t=r.degradation_trend!=null&&r.degradation_trend!=="insufficient_data",i=r.days_until_threshold!=null,a=r.environmental_factor!=null&&r.environmental_factor!==1;if(!t&&!i&&!a)return p;let o=r.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":r.degradation_trend==="falling"?"M16,18L18.29,15.71L13.41,10.83L9.41,14.83L2,7.41L3.41,6L9.41,12L13.41,8L19.71,14.29L22,12V18H16Z":"M22,12L18,8V11H3V13H18V16L22,12Z";return l`
|
||||
<div class="prediction-section">
|
||||
${r.sensor_prediction_urgency?l`
|
||||
<div class="prediction-urgency-banner">
|
||||
@@ -4417,12 +4425,12 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
<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">${n("environmental_adjustment",s)}</span>
|
||||
<span class="prediction-value">${I(r.environmental_factor,s,2)}x</span>
|
||||
${r.environmental_entity?l`<span class="prediction-entity entity-link" @click=${d=>nn(d,r.environmental_entity)}>${r.environmental_entity}</span>`:p}
|
||||
${r.environmental_entity?l`<span class="prediction-entity entity-link" @click=${d=>an(d,r.environmental_entity)}>${r.environmental_entity}</span>`:p}
|
||||
</div>
|
||||
`:p}
|
||||
</div>
|
||||
</div>
|
||||
`}var Ma=y(()=>{"use strict";R();C()});function za(r,s,e,t){let i=Math.max(r||1,s);return l`
|
||||
`}var za=y(()=>{"use strict";R();C()});function Fa(r,s,e,t){let i=Math.max(r||1,s);return l`
|
||||
<div class="interval-comparison">
|
||||
<div class="interval-bar">
|
||||
<div class="interval-label">
|
||||
@@ -4440,7 +4448,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
style="width: ${Math.min(s/i*100,100)}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
`}var Fa=y(()=>{"use strict";R();C()});function Ba(){return Number(we().slice(5,7))-1}function Wa(r,s,e){if(!e.seasonal||!r.seasonal_factor||r.seasonal_factor===1)return p;let t=Ua.map(d=>n(d,s)),i=Ba(),a=r.seasonal_factors||r.interval_analysis?.seasonal_factors||null,o=a&&a.length===12?a:t.map((d,h)=>{let _=r.seasonal_factor||1,m=Math.sin((h-6)*Math.PI/6)*.3;return Math.max(.7,Math.min(1.3,_+m))});return l`
|
||||
`}var Ua=y(()=>{"use strict";R();C()});function Wa(){return Number(we().slice(5,7))-1}function Va(r,s,e){if(!e.seasonal||!r.seasonal_factor||r.seasonal_factor===1)return p;let t=Ba.map(d=>n(d,s)),i=Wa(),a=r.seasonal_factors||r.interval_analysis?.seasonal_factors||null,o=a&&a.length===12?a:t.map((d,h)=>{let _=r.seasonal_factor||1,m=Math.sin((h-6)*Math.PI/6)*.3;return Math.max(.7,Math.min(1.3,_+m))});return l`
|
||||
<div class="seasonal-card-compact">
|
||||
<h4>${n("seasonal_awareness",s)}</h4>
|
||||
<div class="seasonal-mini-chart">
|
||||
@@ -4457,7 +4465,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
<span class="legend-item"><span class="dot high"></span> ${n("longer",s)}</span>
|
||||
</div>
|
||||
</div>
|
||||
`}function Va(r,s){return Xl(r,s)}function Xl(r,s){let e=r.seasonal_factors??r.interval_analysis?.seasonal_factors;if(!e||e.length!==12)return p;let t=r.interval_analysis?.seasonal_reason,i=Ba(),a=300,o=100,d=8,_=o-d-4,m=Math.max(...e,1.5),b=a/12,k=b*.65,w=d+_-1/m*_;return l`
|
||||
`}function Ga(r,s){return ic(r,s)}function ic(r,s){let e=r.seasonal_factors??r.interval_analysis?.seasonal_factors;if(!e||e.length!==12)return p;let t=r.interval_analysis?.seasonal_reason,i=Wa(),a=300,o=100,d=8,_=o-d-4,m=Math.max(...e,1.5),b=a/12,k=b*.65,w=d+_-1/m*_;return l`
|
||||
<div class="seasonal-chart">
|
||||
<div class="seasonal-chart-title">
|
||||
<ha-svg-icon aria-hidden="true" path="M17.75 4.09L15.22 6.03L16.13 9.09L13.5 7.28L10.87 9.09L11.78 6.03L9.25 4.09L12.44 4L13.5 1L14.56 4L17.75 4.09M21.25 11L19.61 12.25L20.2 14.23L18.5 13.06L16.8 14.23L17.39 12.25L15.75 11L17.81 10.95L18.5 9L19.19 10.95L21.25 11M18.97 15.95C19.8 15.87 20.69 17.05 20.16 17.8C19.84 18.25 19.5 18.67 19.08 19.07C15.17 23 8.84 23 4.94 19.07C1.03 15.17 1.03 8.83 4.94 4.93C5.34 4.53 5.76 4.17 6.21 3.85C6.96 3.32 8.14 4.21 8.06 5.04C7.79 7.9 8.75 10.87 10.95 13.06C13.14 15.26 16.1 16.22 18.97 15.95Z"></ha-svg-icon>
|
||||
@@ -4474,13 +4482,13 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
`})}
|
||||
</svg>
|
||||
<div class="seasonal-labels">
|
||||
${Ua.map((v,x)=>l`<span class="seasonal-label ${x===i?"active-month":""}">${n(v,s)}</span>`)}
|
||||
${Ba.map((v,x)=>l`<span class="seasonal-label ${x===i?"active-month":""}">${n(v,s)}</span>`)}
|
||||
</div>
|
||||
</div>
|
||||
`}var Ua,Ga=y(()=>{"use strict";R();C();$i();ee();Ua=["month_jan","month_feb","month_mar","month_apr","month_may","month_jun","month_jul","month_aug","month_sep","month_oct","month_nov","month_dec"]});var N,Ka=y(()=>{"use strict";R();j();C();Se();_a();Ti();ee();fi();hi();zs();Ea();De();Fs();Na();Bs();st();et();Ai();Ha();Da();Ma();Fa();ot();Ga();N=class extends E{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._taskId=null;this._task=null;this._objectName="";this._taskRef=null;this._busy=!1;this._error="";this._showSkip=!1;this._showReset=!1;this._showPostpone=!1;this._showDetails=!1;this._showAdaptive=!1;this._skipReason="";this._resetDate="";this._postponeDate="";this._features={adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1,places:!1};this._toast="";this._toastTimer=new Hi;this._access=he;this._currencySymbol="";this._partsCostMode="purchase";this._loadSeq=0}get _lang(){return P(this.hass)}async openFor(e,t){(e!==this._entryId||t!==this._taskId)&&(this._task=null),this._entryId=e,this._taskId=t,this._error="",this._showSkip=!1,this._showReset=!1,this._showPostpone=!1,this._showAdaptive=!1,this._skipReason="",this._postponeDate="",this._resetDate=we(),this._open=!0,await Promise.all([this._loadTask(),this._loadFeatures()])}async _loadFeatures(){let e=await B(this.hass);this._features={...this._features,...e.features},this._access=e.access,this._currencySymbol=je(e.budget??void 0),ri(e.budget??void 0),this._partsCostMode=e.partsCostMode}close(){this._loadSeq++,this._open=!1,this._task=null,this._error="",this._toastTimer.clear(),this._toast=""}_showToast(e,t){this._toast=e,this._toastTimer.schedule(()=>{this._toast=""},t)}async _loadTask(){let e=this._entryId,t=this._taskId;if(!e||!t)return;let i=++this._loadSeq,a="",o=await D(this,{type:"maintenance_supporter/object",entry_id:e},{onError:h=>{a=h}});if(i!==this._loadSeq)return;if(o===void 0){this._error=a;return}this._objectName=o?.object?.name||"";let d=(o?.tasks||[]).find(h=>h.id===t);this._task=d??null,this._taskRef=Ta(o?.object,d),d||(this._error=n("ws_err_not_found",this._lang))}_runWs(e){return this._error="",D(this,e,{busy:t=>{this._busy=t},onError:t=>{this._error=t}})}_notifyChanged(e){this.dispatchEvent(new CustomEvent("task-action-fired",{detail:{entry_id:this._entryId,task_id:this._taskId,action:e},bubbles:!0,composed:!0}))}_onComplete(){!this._entryId||!this._taskId||!this._task||Promise.resolve().then(()=>(le(),me)).then(async({openCompleteDialog:e})=>{let t=this._task,i=[];try{i=(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0})).objects||[]}catch{}e(mi({entryId:this._entryId,taskId:this._taskId,taskName:t.name,task:t,objects:i,lang:this._lang,features:this._features,currencySymbol:this._currencySymbol,partsCostMode:this._partsCostMode}))&&(this._notifyChanged("complete"),this.close())})}async _onSkipConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/skip",entry_id:this._entryId,task_id:this._taskId,reason:this._skipReason.trim()||null})!==void 0&&(this._notifyChanged("skip"),this.close())}async _onResetConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/reset",entry_id:this._entryId,task_id:this._taskId,date:this._resetDate||void 0})!==void 0&&(this._notifyChanged("reset"),this.close())}async _onPostponeConfirm(){if(!this._entryId||!this._taskId||!this._postponeDate)return;await this._runWs({type:"maintenance_supporter/task/postpone",entry_id:this._entryId,task_id:this._taskId,until:this._postponeDate})!==void 0&&(this._notifyChanged("postpone"),this.close())}async _onSnooze(){if(!this._entryId||!this._taskId)return;let e=await this._runWs({type:"maintenance_supporter/task/snooze",entry_id:this._entryId,task_id:this._taskId});e!==void 0&&(this._notifyChanged("snooze"),this.dispatchEvent(new CustomEvent("hass-notification",{detail:{message:ha(e,this._lang)},bubbles:!0,composed:!0})),this.close())}_onEdit(){!this._entryId||!this._taskId||Promise.resolve().then(()=>(le(),me)).then(({openEditTaskDialog:e})=>{e(this._entryId,this._taskId),this.close()})}_onQr(){!this._entryId||!this._taskId||!this._task||Promise.resolve().then(()=>(le(),me)).then(({openQrDialog:e})=>{e({entry_id:this._entryId,task_id:this._taskId,task_name:this._task.name,object_name:this._objectName}),this.close()})}async _onDelete(){if(!this._entryId||!this._taskId||!await Me(this.hass,{title:n("delete",this._lang),message:n("delete_task_confirm",this._lang),confirmText:n("delete",this._lang),danger:!0}))return;await this._runWs({type:"maintenance_supporter/task/delete",entry_id:this._entryId,task_id:this._taskId})!==void 0&&(this._notifyChanged("delete"),this.close())}async _onArchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/archive",entry_id:this._entryId,task_id:this._taskId})!==void 0&
Line truncated
|
||||
`}var Ba,Ka=y(()=>{"use strict";R();C();$i();ee();Ba=["month_jan","month_feb","month_mar","month_apr","month_may","month_jun","month_jul","month_aug","month_sep","month_oct","month_nov","month_dec"]});var N,Ya=y(()=>{"use strict";R();j();C();Se();ma();Ti();ee();fi();hi();Fs();Sa();De();Us();Oa();Ws();st();et();Ai();ja();qa();za();Ua();ot();Ka();N=class extends E{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._taskId=null;this._task=null;this._objectName="";this._taskRef=null;this._busy=!1;this._error="";this._showSkip=!1;this._showReset=!1;this._showPostpone=!1;this._showDetails=!1;this._showAdaptive=!1;this._skipReason="";this._resetDate="";this._postponeDate="";this._features={adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1,places:!1};this._toast="";this._toastTimer=new Hi;this._access=he;this._currencySymbol="";this._partsCostMode="purchase";this._loadSeq=0}get _lang(){return P(this.hass)}async openFor(e,t){(e!==this._entryId||t!==this._taskId)&&(this._task=null),this._entryId=e,this._taskId=t,this._error="",this._showSkip=!1,this._showReset=!1,this._showPostpone=!1,this._showAdaptive=!1,this._skipReason="",this._postponeDate="",this._resetDate=we(),this._open=!0,await Promise.all([this._loadTask(),this._loadFeatures()])}async _loadFeatures(){let e=await B(this.hass);this._features={...this._features,...e.features},this._access=e.access,this._currencySymbol=je(e.budget??void 0),ri(e.budget??void 0),this._partsCostMode=e.partsCostMode}close(){this._loadSeq++,this._open=!1,this._task=null,this._error="",this._toastTimer.clear(),this._toast=""}_showToast(e,t){this._toast=e,this._toastTimer.schedule(()=>{this._toast=""},t)}async _loadTask(){let e=this._entryId,t=this._taskId;if(!e||!t)return;let i=++this._loadSeq,a="",o=await D(this,{type:"maintenance_supporter/object",entry_id:e},{onError:h=>{a=h}});if(i!==this._loadSeq)return;if(o===void 0){this._error=a;return}this._objectName=o?.object?.name||"";let d=(o?.tasks||[]).find(h=>h.id===t);this._task=d??null,this._taskRef=Aa(o?.object,d),d||(this._error=n("ws_err_not_found",this._lang))}_runWs(e){return this._error="",D(this,e,{busy:t=>{this._busy=t},onError:t=>{this._error=t}})}_notifyChanged(e){this.dispatchEvent(new CustomEvent("task-action-fired",{detail:{entry_id:this._entryId,task_id:this._taskId,action:e},bubbles:!0,composed:!0}))}_onComplete(){!this._entryId||!this._taskId||!this._task||Promise.resolve().then(()=>(le(),me)).then(async({openCompleteDialog:e})=>{let t=this._task,i=[];try{i=(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0})).objects||[]}catch{}e(mi({entryId:this._entryId,taskId:this._taskId,taskName:t.name,task:t,objects:i,lang:this._lang,features:this._features,currencySymbol:this._currencySymbol,partsCostMode:this._partsCostMode}))&&(this._notifyChanged("complete"),this.close())})}async _onSkipConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/skip",entry_id:this._entryId,task_id:this._taskId,reason:this._skipReason.trim()||null})!==void 0&&(this._notifyChanged("skip"),this.close())}async _onResetConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/reset",entry_id:this._entryId,task_id:this._taskId,date:this._resetDate||void 0})!==void 0&&(this._notifyChanged("reset"),this.close())}async _onPostponeConfirm(){if(!this._entryId||!this._taskId||!this._postponeDate)return;await this._runWs({type:"maintenance_supporter/task/postpone",entry_id:this._entryId,task_id:this._taskId,until:this._postponeDate})!==void 0&&(this._notifyChanged("postpone"),this.close())}async _onSnooze(){if(!this._entryId||!this._taskId)return;let e=await this._runWs({type:"maintenance_supporter/task/snooze",entry_id:this._entryId,task_id:this._taskId});e!==void 0&&(this._notifyChanged("snooze"),this.dispatchEvent(new CustomEvent("hass-notification",{detail:{message:_a(e,this._lang)},bubbles:!0,composed:!0})),this.close())}_onEdit(){!this._entryId||!this._taskId||Promise.resolve().then(()=>(le(),me)).then(({openEditTaskDialog:e})=>{e(this._entryId,this._taskId),this.close()})}_onQr(){!this._entryId||!this._taskId||!this._task||Promise.resolve().then(()=>(le(),me)).then(({openQrDialog:e})=>{e({entry_id:this._entryId,task_id:this._taskId,task_name:this._task.name,object_name:this._objectName}),this.close()})}async _onDelete(){if(!this._entryId||!this._taskId||!await Me(this.hass,{title:n("delete",this._lang),message:n("delete_task_confirm",this._lang),confirmText:n("delete",this._lang),danger:!0}))return;await this._runWs({type:"maintenance_supporter/task/delete",entry_id:this._entryId,task_id:this._taskId})!==void 0&&(this._notifyChanged("delete"),this.close())}async _onArchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/archive",entry_id:this._entryId,task_id:this._taskId})!==void 0&
Line truncated
|
||||
<div class="recommendation-card">
|
||||
<h4>${n("suggested_interval",t)}</h4>
|
||||
${za(e.interval_days,e.suggested_interval,e.interval_confidence||"medium",t)}
|
||||
${Fa(e.interval_days,e.suggested_interval,e.interval_confidence||"medium",t)}
|
||||
<div class="recommendation-actions">
|
||||
${ae(this.hass?.user,this._access)?l`<button class="btn primary qa-apply-suggestion"
|
||||
@click=${this._applySuggestion} ?disabled=${this._busy}>
|
||||
@@ -4500,14 +4508,14 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
<div class="adaptive-stack">
|
||||
${this._toast?l`<div class="toast">${this._toast}</div>`:p}
|
||||
${i?this._renderRecommendation(e):p}
|
||||
${a?qa(e,t,this._features):p}
|
||||
${o?ja(e,t):p}
|
||||
${a?Ma(e,t,this._features):p}
|
||||
${o?Da(e,t):p}
|
||||
${d?l`
|
||||
${Wa(e,t,this._features)}
|
||||
${e.seasonal_factors?.length===12||e.interval_analysis?.seasonal_factors?.length===12?Va(e,t):p}
|
||||
${Va(e,t,this._features)}
|
||||
${e.seasonal_factors?.length===12||e.interval_analysis?.seasonal_factors?.length===12?Ga(e,t):p}
|
||||
`:p}
|
||||
</div>
|
||||
`}_renderDetails(e){let t=this._lang,i=e.history||[],a=e.history_count??i.length,o=Pa(i).slice(0,20);return l`
|
||||
`}_renderDetails(e){let t=this._lang,i=e.history||[],a=e.history_count??i.length,o=La(i).slice(0,20);return l`
|
||||
<div class="details">
|
||||
<div class="stats-grid">
|
||||
<div class="stat">
|
||||
@@ -4529,7 +4537,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
</div>
|
||||
${i.length===0?l`<div class="history-empty">${n("history_empty",t)}</div>`:l`
|
||||
<div class="history-list">
|
||||
${o.map(d=>La(d,{lang:t,hass:this.hass,currencySymbol:this._currencySymbol,openEdit:ae(this.hass?.user,this._access)?h=>this._onEditHistoryEntry(h):void 0,readingUnit:e.reading_unit,readingSlotDelta:(h,_)=>vn(i,h,_),taskRef:this._taskRef},{compact:!0}))}
|
||||
${o.map(d=>Na(d,{lang:t,hass:this.hass,currencySymbol:this._currencySymbol,openEdit:ae(this.hass?.user,this._access)?h=>this._onEditHistoryEntry(h):void 0,readingUnit:e.reading_unit,readingSlotDelta:(h,_)=>bn(i,h,_),taskRef:this._taskRef},{compact:!0}))}
|
||||
${a>o.length?l`<div class="history-more">… +${a-o.length} ${n("older_entries",t)}</div>`:p}
|
||||
</div>
|
||||
`}
|
||||
@@ -4540,7 +4548,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
<div class="title">
|
||||
<span class="status-dot" style="background: ${Oi(t)}"></span>
|
||||
<span class="task-name">${t.name}</span>
|
||||
${Oa(t,e)}
|
||||
${Ha(t,e)}
|
||||
</div>
|
||||
<div class="object">
|
||||
<button class="link-inline" @click=${()=>{this._entryId&&Promise.resolve().then(()=>(le(),me)).then(({openObjectQuickActions:o})=>{o(this._entryId),this.close()})}}>${this._objectName}</button>
|
||||
@@ -4548,7 +4556,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
<div class="quick-info">
|
||||
${t.next_due?l`<span><strong>${n("next_due",e)}:</strong> ${H(t.next_due,e)}</span>`:p}
|
||||
${t.last_performed?l`<span><strong>${n("last_performed",e)}:</strong> ${H(t.last_performed,e)}</span>`:p}
|
||||
${t.schedule?.kind&&!["manual","one_time"].includes(t.schedule.kind)||t.interval_days!=null?l`<span><strong>${n("interval",e)}:</strong> ${rn(t,e)}</span>`:p}
|
||||
${t.schedule?.kind&&!["manual","one_time"].includes(t.schedule.kind)||t.interval_days!=null?l`<span><strong>${n("interval",e)}:</strong> ${nn(t,e)}</span>`:p}
|
||||
${ke(t)?l`<span><strong>${n("phase_current",e)}:</strong> ${ke(t)}</span>`:p}
|
||||
</div>
|
||||
${t.notes?l`<div class="notes-body">${Ni(t.notes)}</div>`:p}
|
||||
@@ -4836,7 +4844,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
.weibull-section, .seasonal-card-compact { max-width: 100%; }
|
||||
.weibull-chart svg { max-width: 100%; height: auto; }
|
||||
.details-toggle { gap: 12px; flex-wrap: wrap; }
|
||||
`],c([f({attribute:!1})],N.prototype,"hass",2),c([u()],N.prototype,"_open",2),c([u()],N.prototype,"_entryId",2),c([u()],N.prototype,"_taskId",2),c([u()],N.prototype,"_task",2),c([u()],N.prototype,"_objectName",2),c([u()],N.prototype,"_taskRef",2),c([u()],N.prototype,"_busy",2),c([u()],N.prototype,"_error",2),c([u()],N.prototype,"_showSkip",2),c([u()],N.prototype,"_showReset",2),c([u()],N.prototype,"_showPostpone",2),c([u()],N.prototype,"_showDetails",2),c([u()],N.prototype,"_showAdaptive",2),c([u()],N.prototype,"_skipReason",2),c([u()],N.prototype,"_resetDate",2),c([u()],N.prototype,"_postponeDate",2),c([u()],N.prototype,"_features",2),c([u()],N.prototype,"_toast",2),c([u()],N.prototype,"_access",2),c([u()],N.prototype,"_partsCostMode",2);customElements.get("maintenance-task-quick-actions-dialog")||customElements.define("maintenance-task-quick-actions-dialog",N)});var ie,Ya=y(()=>{"use strict";R();di();zs();j();C();Se();Bs();st();et();Ai();Ti();ie=class extends E{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._data=null;this._busy=!1;this._error="";this._access=he}get _lang(){return P(this.hass)}async openFor(e){this._entryId=e,this._error="",this._open=!0,await Promise.all([this._load(),B(this.hass).then(t=>{this._access=t.access})])}close(){this._open=!1,this._data=null,this._error=""}async _load(){if(!this._entryId)return;let e=await D(this,{type:"maintenance_supporter/object",entry_id:this._entryId},{onError:t=>{this._error=t}});e!==void 0&&(this._data=e)}_runWs(e){return this._error="",D(this,e,{busy:t=>{this._busy=t},onError:t=>{this._error=t}})}_onEditObject(){!this._entryId||!this._data||Promise.resolve().then(()=>(le(),me)).then(({openEditObjectDialog:e})=>{e(this._entryId,this._data.object),this.close()})}_onAddTask(){this._entryId&&Promise.resolve().then(()=>(le(),me)).then(({openCreateTaskDialog:e})=>{e(this._entryId),this.close()})}async _onDelete(){if(!this._entryId||!this._data||!await Me(this.hass,{title:n("delete",this._lang),message:n("delete_object_confirm",this._lang),confirmText:n("delete",this._lang),danger:!0}))return;let t=this._entryId;await this._runWs({type:"maintenance_supporter/object/delete",entry_id:t})!==void 0&&(this.dispatchEvent(new CustomEvent("object-deleted",{detail:{entry_id:t},bubbles:!0,composed:!0})),this.close())}async _onArchiveObject(){if(!this._entryId||!this._data)return;let e=!!this._data.object.archived;if(!e&&!await Me(this.hass,{title:n("archive_object",this._lang),message:n("confirm_archive_object",this._lang),confirmText:n("archive_object",this._lang)}))return;let t=this._entryId;await this._runWs({type:e?"maintenance_supporter/object/unarchive":"maintenance_supporter/object/archive",entry_id:t})!==void 0&&(this.dispatchEvent(new CustomEvent("object-changed",{detail:{entry_id:t},bubbles:!0,composed:!0})),this.close())}_onTaskClick(e){this._entryId&&Promise.resolve().then(()=>(le(),me)).then(({openTaskQuickActions:t})=>{t(this._entryId,e)})}render(){if(!this._open)return p;let e=this._lang,t=this._data,i=t?.object,a=t?.tasks||[],o=ae(this.hass?.user,this._access);return pt(()=>this.close(),l`
|
||||
`],c([f({attribute:!1})],N.prototype,"hass",2),c([u()],N.prototype,"_open",2),c([u()],N.prototype,"_entryId",2),c([u()],N.prototype,"_taskId",2),c([u()],N.prototype,"_task",2),c([u()],N.prototype,"_objectName",2),c([u()],N.prototype,"_taskRef",2),c([u()],N.prototype,"_busy",2),c([u()],N.prototype,"_error",2),c([u()],N.prototype,"_showSkip",2),c([u()],N.prototype,"_showReset",2),c([u()],N.prototype,"_showPostpone",2),c([u()],N.prototype,"_showDetails",2),c([u()],N.prototype,"_showAdaptive",2),c([u()],N.prototype,"_skipReason",2),c([u()],N.prototype,"_resetDate",2),c([u()],N.prototype,"_postponeDate",2),c([u()],N.prototype,"_features",2),c([u()],N.prototype,"_toast",2),c([u()],N.prototype,"_access",2),c([u()],N.prototype,"_partsCostMode",2);customElements.get("maintenance-task-quick-actions-dialog")||customElements.define("maintenance-task-quick-actions-dialog",N)});var ie,Qa=y(()=>{"use strict";R();di();Fs();j();C();Se();Ws();st();et();Ai();Ti();ie=class extends E{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._data=null;this._busy=!1;this._error="";this._access=he}get _lang(){return P(this.hass)}async openFor(e){this._entryId=e,this._error="",this._open=!0,await Promise.all([this._load(),B(this.hass).then(t=>{this._access=t.access})])}close(){this._open=!1,this._data=null,this._error=""}async _load(){if(!this._entryId)return;let e=await D(this,{type:"maintenance_supporter/object",entry_id:this._entryId},{onError:t=>{this._error=t}});e!==void 0&&(this._data=e)}_runWs(e){return this._error="",D(this,e,{busy:t=>{this._busy=t},onError:t=>{this._error=t}})}_onEditObject(){!this._entryId||!this._data||Promise.resolve().then(()=>(le(),me)).then(({openEditObjectDialog:e})=>{e(this._entryId,this._data.object),this.close()})}_onAddTask(){this._entryId&&Promise.resolve().then(()=>(le(),me)).then(({openCreateTaskDialog:e})=>{e(this._entryId),this.close()})}async _onDelete(){if(!this._entryId||!this._data||!await Me(this.hass,{title:n("delete",this._lang),message:n("delete_object_confirm",this._lang),confirmText:n("delete",this._lang),danger:!0}))return;let t=this._entryId;await this._runWs({type:"maintenance_supporter/object/delete",entry_id:t})!==void 0&&(this.dispatchEvent(new CustomEvent("object-deleted",{detail:{entry_id:t},bubbles:!0,composed:!0})),this.close())}async _onArchiveObject(){if(!this._entryId||!this._data)return;let e=!!this._data.object.archived;if(!e&&!await Me(this.hass,{title:n("archive_object",this._lang),message:n("confirm_archive_object",this._lang),confirmText:n("archive_object",this._lang)}))return;let t=this._entryId;await this._runWs({type:e?"maintenance_supporter/object/unarchive":"maintenance_supporter/object/archive",entry_id:t})!==void 0&&(this.dispatchEvent(new CustomEvent("object-changed",{detail:{entry_id:t},bubbles:!0,composed:!0})),this.close())}_onTaskClick(e){this._entryId&&Promise.resolve().then(()=>(le(),me)).then(({openTaskQuickActions:t})=>{t(this._entryId,e)})}render(){if(!this._open)return p;let e=this._lang,t=this._data,i=t?.object,a=t?.tasks||[],o=ae(this.hass?.user,this._access);return pt(()=>this.close(),l`
|
||||
${t&&i?l`
|
||||
<div class="header">
|
||||
<div class="title">${i.name}</div>
|
||||
@@ -4856,7 +4864,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
<div class="task-row" @click=${()=>this._onTaskClick(d.id)}>
|
||||
<span class="status-dot" style="background: ${Oi(d)}"></span>
|
||||
<span class="task-name">${d.name}</span>
|
||||
<span class="task-status ${zt(d)}">${Us(zt(d),e)}</span>
|
||||
<span class="task-status ${zt(d)}">${Bs(zt(d),e)}</span>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
@@ -4896,7 +4904,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
${i.map(([a,o,d])=>l`
|
||||
<div class="meta-item">
|
||||
<span class="meta-label">${a}</span>
|
||||
<span class="meta-value">${d||cn(o)?l`<a href="${o}" target="_blank" rel="noopener noreferrer">${o}</a>`:o}</span>
|
||||
<span class="meta-value">${d||dn(o)?l`<a href="${o}" target="_blank" rel="noopener noreferrer">${o}</a>`:o}</span>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
@@ -4945,7 +4953,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
.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; }
|
||||
`],c([f({attribute:!1})],ie.prototype,"hass",2),c([u()],ie.prototype,"_open",2),c([u()],ie.prototype,"_entryId",2),c([u()],ie.prototype,"_data",2),c([u()],ie.prototype,"_busy",2),c([u()],ie.prototype,"_error",2),c([u()],ie.prototype,"_access",2);customElements.get("maintenance-object-quick-actions-dialog")||customElements.define("maintenance-object-quick-actions-dialog",ie)});var me={};oo(me,{__resetSettingsCacheForTests:()=>oc,getRowActionStyle:()=>ac,openCompleteDialog:()=>pc,openCreateObjectDialog:()=>Ws,openCreateTaskDialog:()=>Vs,openEditObjectDialog:()=>lc,openEditTaskDialog:()=>cc,openHistoryEditDialog:()=>dc,openObjectQuickActions:()=>hc,openQrDialog:()=>uc,openTaskQuickActions:()=>Gs});function Ft(){return document.querySelector("home-assistant")?.hass}function nc(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function ge(r){let s=nc(),e=s.querySelector(r)??document.body.querySelector(r);return e?e.parentNode!==s&&s.appendChild(e):(e=document.createElement(r),s.appendChild(e)),e}function fe(r){let s=Ft();if(!s)return!1;r.hass=s;let e=P(s);return Tt(e)||ue(e).then(()=>{r.requestUpdate?.()}),os(s.locale,s.config?.country,s.config?.time_zone),!0}function ac(r){return B(r).then(s=>s.rowActionStyle)}function oc(){In()}function Ws(){let r=ge(Qa);return fe(r)?(r.openCreate(),Ja(r),!0):!1}async function Ja(r){let s=Ft();s&&(r.placesEnabled=(await B(s)).features.places)}function lc(r,s){let e=ge(Qa);return fe(e)?(e.openEdit(r,s),Ja(e),!0):!1}function Vs(r="",s){let e=ge(Za);if(!fe(e))return!1;let t=Ft();return t?((async()=>{let i=await B(t),a=e;Xa(a,i),a.openCreate(r,s)})(),!0):!1}function Xa(r,s){r.checklistsEnabled=s.features.checklists,r.scheduleTimeEnabled=s.features.schedule_time,r.completionActionsEnabled=s.features.completion_actions,r.adaptiveFeature=s.features.adaptive,r.seasonalFeature=s.features.seasonal,r.environmentalFeature=s.features.environmental,r.defaultWarningDays=s.defaultWarningDays}function cc(r,s){let e=ge(Za);if(!fe(e))return!1;let t=Ft();return t?((async()=>{try{let[i,a]=await Promise.all([t.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:r}),B(t)]),o=(i.tasks||[]).find(h=>h.id===s);if(!o){console.warn(`openEditTaskDialog: task ${s} not found in entry ${r}`);return}let d=e;Xa(d,a),await d.openEdit(r,o)}catch(i){console.warn("openEditTaskDialog: failed to load task/features",i)}})(),!0):!1}function dc(r){let s=ge(ec);return fe(s)?(s.openEdit(r),!0):!1}function pc(r){let s=ge(tc);return fe(s)?(gi(s,r,P(Ft())),!0):!1}function uc(r){let s=ge(ic);return fe(s)?(s.openForTask(r.entry_id,r.task_id,r.object_name,r.task_name),!0):!1}function Gs(r,s){let e=ge(sc);return fe(e)?(e.openFor(r,s),!0):!1}function hc(r){let s=ge(rc);return fe(s)?(s.openFor(r),!0):!1}var Qa,Za,ec,tc,ic,sc,rc,le=y(()=>{"use strict";Kn();oa();Cs();pa();ua();Ka();Ya();C();fi();st();Qa="maintenance-object-dialog",Za="maintenance-task-dialog",ec="maintenance-history-edit-dialog",tc="maintenance-complete-dialog",ic="maintenance-qr-dialog",sc="maintenance-task-quick-actions-dialog",rc="maintenance-object-quick-actions-dialog"});R();var yo=["assignee_pool","required_completion_fields","checklist","labels","mirror_todo_entities","next_event_titles","history","readings"],xo=["checklist_progress"],wo=["tasks","parts"],ko=["manual_docs","battery_fleet_excluded"];function Gi(r,s,e=[]){for(let t of s)r[t]===void 0&&(r[t]=[]);for(let t of e)r[t]===void 0&&(r[t]={})}function $o(r){let s=r;Gi(s,wo),s.object&&typeof s.object=="object"&&Gi(s.object,ko);for(let e of s.tasks)Gi(e,yo,xo);return r}function wt(r){for(let s of r)$o(s);return r}function Eo(r,s){if(s.objects)return s.objects;let e=s.delta||[],t=s.removed||[];if(!e.length&&!t.length)return null;let i=new Map(r.map(a=>[a.entry_id,a]));for(let a of e)i.set(a.entry_id,a);for(let a of t)i.delete(a);return[...i.values()]}function xr(r,s){return s.objects&&wt(s.objects),s.delta&&wt(s.delta),Eo(r,s)}function So(r){return r.responsible_user_id?[r.responsible_user_id]:[...new Set((r.assignee_pool||[]).filter(s=>typeof s=="string"&&s))]}function wr(r,s){return!!s&&So(r).includes(s)}j();C();ps();function ln(r){return(r.tags||[]).includes("photo")}di();function dn(){return window.customCards??[]}function Je(r){let s=window;s.customCards=s.customCards||[],s.customCards.some(e=>e.type===r.type)||s.customCards.push(r)}function pn(r,s,e=t=>import(t)){let t=window,i;try{let m=new URL(s);i=m.origin+m.pathname}catch{return}let a=`__msCardHeal:${r[0]}:${i}`;if(t[a])return;t[a]=!0;let o=0,d=0,h=!1,_=()=>{if(o+=1,r.some(b=>!customElements.get(b))&&d<3&&!h){d+=1,h=!0;try{let b=new URL(s);b.searchParams.set("heal",`${Date.now()}`),e(b.href).catch(()=>{}).finally(()=>{h=!1})}catch{return}}o<20&&window.setTimeout(_,o<8?500:2e3)};window.setTimeout(_,250)}At();var Wo={"maintenance-supporter-card":[null,"picker_desc_card"],"maintenance-supporter-calendar-card":["picker_name_calendar","picker_desc_calendar"],"maintenance-supporter-panel-card":["pic
Line truncated
|
||||
`],c([f({attribute:!1})],ie.prototype,"hass",2),c([u()],ie.prototype,"_open",2),c([u()],ie.prototype,"_entryId",2),c([u()],ie.prototype,"_data",2),c([u()],ie.prototype,"_busy",2),c([u()],ie.prototype,"_error",2),c([u()],ie.prototype,"_access",2);customElements.get("maintenance-object-quick-actions-dialog")||customElements.define("maintenance-object-quick-actions-dialog",ie)});var me={};lo(me,{__resetSettingsCacheForTests:()=>dc,getRowActionStyle:()=>cc,openCompleteDialog:()=>_c,openCreateObjectDialog:()=>Vs,openCreateTaskDialog:()=>Gs,openEditObjectDialog:()=>pc,openEditTaskDialog:()=>uc,openHistoryEditDialog:()=>hc,openObjectQuickActions:()=>gc,openQrDialog:()=>mc,openTaskQuickActions:()=>Ks});function Ft(){return document.querySelector("home-assistant")?.hass}function lc(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function ge(r){let s=lc(),e=s.querySelector(r)??document.body.querySelector(r);return e?e.parentNode!==s&&s.appendChild(e):(e=document.createElement(r),s.appendChild(e)),e}function fe(r){let s=Ft();if(!s)return!1;r.hass=s;let e=P(s);return Tt(e)||ue(e).then(()=>{r.requestUpdate?.()}),ls(s.locale,s.config?.country,s.config?.time_zone),!0}function cc(r){return B(r).then(s=>s.rowActionStyle)}function dc(){Pn()}function Vs(){let r=ge(Za);return fe(r)?(r.openCreate(),Xa(r),!0):!1}async function Xa(r){let s=Ft();s&&(r.placesEnabled=(await B(s)).features.places)}function pc(r,s){let e=ge(Za);return fe(e)?(e.openEdit(r,s),Xa(e),!0):!1}function Gs(r="",s){let e=ge(Ja);if(!fe(e))return!1;let t=Ft();return t?((async()=>{let i=await B(t),a=e;eo(a,i),a.openCreate(r,s)})(),!0):!1}function eo(r,s){r.checklistsEnabled=s.features.checklists,r.scheduleTimeEnabled=s.features.schedule_time,r.completionActionsEnabled=s.features.completion_actions,r.adaptiveFeature=s.features.adaptive,r.seasonalFeature=s.features.seasonal,r.environmentalFeature=s.features.environmental,r.defaultWarningDays=s.defaultWarningDays}function uc(r,s){let e=ge(Ja);if(!fe(e))return!1;let t=Ft();return t?((async()=>{try{let[i,a]=await Promise.all([t.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:r}),B(t)]),o=(i.tasks||[]).find(h=>h.id===s);if(!o){console.warn(`openEditTaskDialog: task ${s} not found in entry ${r}`);return}let d=e;eo(d,a),await d.openEdit(r,o)}catch(i){console.warn("openEditTaskDialog: failed to load task/features",i)}})(),!0):!1}function hc(r){let s=ge(sc);return fe(s)?(s.openEdit(r),!0):!1}function _c(r){let s=ge(rc);return fe(s)?(gi(s,r,P(Ft())),!0):!1}function mc(r){let s=ge(nc);return fe(s)?(s.openForTask(r.entry_id,r.task_id,r.object_name,r.task_name),!0):!1}function Ks(r,s){let e=ge(ac);return fe(e)?(e.openFor(r,s),!0):!1}function gc(r){let s=ge(oc);return fe(s)?(s.openFor(r),!0):!1}var Za,Ja,sc,rc,nc,ac,oc,le=y(()=>{"use strict";Yn();la();Rs();ua();ha();Ya();Qa();C();fi();st();Za="maintenance-object-dialog",Ja="maintenance-task-dialog",sc="maintenance-history-edit-dialog",rc="maintenance-complete-dialog",nc="maintenance-qr-dialog",ac="maintenance-task-quick-actions-dialog",oc="maintenance-object-quick-actions-dialog"});R();var xo=["assignee_pool","required_completion_fields","checklist","labels","mirror_todo_entities","next_event_titles","history","readings"],wo=["checklist_progress"],ko=["tasks","parts"],$o=["manual_docs","battery_fleet_excluded"];function Gi(r,s,e=[]){for(let t of s)r[t]===void 0&&(r[t]=[]);for(let t of e)r[t]===void 0&&(r[t]={})}function Eo(r){let s=r;Gi(s,ko),s.object&&typeof s.object=="object"&&Gi(s.object,$o);for(let e of s.tasks)Gi(e,xo,wo);return r}function wt(r){for(let s of r)Eo(s);return r}function So(r,s){if(s.objects)return s.objects;let e=s.delta||[],t=s.removed||[];if(!e.length&&!t.length)return null;let i=new Map(r.map(a=>[a.entry_id,a]));for(let a of e)i.set(a.entry_id,a);for(let a of t)i.delete(a);return[...i.values()]}function wr(r,s){return s.objects&&wt(s.objects),s.delta&&wt(s.delta),So(r,s)}function To(r){return r.responsible_user_id?[r.responsible_user_id]:[...new Set((r.assignee_pool||[]).filter(s=>typeof s=="string"&&s))]}function kr(r,s){return!!s&&To(r).includes(s)}j();C();us();function cn(r){return(r.tags||[]).includes("photo")}di();function pn(){return window.customCards??[]}function Je(r){let s=window;s.customCards=s.customCards||[],s.customCards.some(e=>e.type===r.type)||s.customCards.push(r)}function un(r,s,e=t=>import(t)){let t=window,i;try{let m=new URL(s);i=m.origin+m.pathname}catch{return}let a=`__msCardHeal:${r[0]}:${i}`;if(t[a])return;t[a]=!0;let o=0,d=0,h=!1,_=()=>{if(o+=1,r.some(b=>!customElements.get(b))&&d<3&&!h){d+=1,h=!0;try{let b=new URL(s);b.searchParams.set("heal",`${Date.now()}`),e(b.href).catch(()=>{}).finally(()=>{h=!1})}catch{return}}o<20&&window.setTimeout(_,o<8?500:2e3)};window.setTimeout(_,250)}At();var Vo={"maintenance-supporter-card":[null,"picker_desc_card"],"maintenance-supporter-calendar-card":["picker_name_calendar","picker_desc_calendar"],"maintenance-supporter-panel-card":["pic
Line truncated
|
||||
<div class="editor">
|
||||
<ha-textfield
|
||||
label="${n("card_title",e)}"
|
||||
@@ -5204,7 +5212,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
font-size: 14px;
|
||||
max-width: 320px;
|
||||
}
|
||||
`,c([f({attribute:!1})],oe.prototype,"hass",2),c([u()],oe.prototype,"_config",2),c([u()],oe.prototype,"_objects",2),c([u()],oe.prototype,"_loadingObjects",2),c([u()],oe.prototype,"_loadError",2),c([u()],oe.prototype,"_views",2);customElements.get("maintenance-supporter-card-editor")||customElements.define("maintenance-supporter-card-editor",oe);Cs();C();async function vl(r,s,e,t){try{let i=await r.connection.sendMessagePromise({type:"maintenance_supporter/task/undo",entry_id:s,task_id:e});return{ok:!0,message:n(i?.action_ran?"undo_done_action_ran":"undo_done",t)}}catch(i){let a=i?.code;return a==="changed_since"?{ok:!1,message:n("undo_changed",t)}:a==="nothing_to_undo"?{ok:!1,message:n("undo_nothing",t)}:{ok:!1,message:n("action_error",t)}}}function Gn(r,s,e,t,i){let a=(o,d)=>r.dispatchEvent(new CustomEvent("hass-notification",{detail:d?{message:o,action:d,duration:1e4}:{message:o},bubbles:!0,composed:!0}));a(n("task_completed_named",t).replace("{task}",e.taskName),{text:n("undo",t),action:()=>{vl(s,e.entryId,e.taskId,t).then(o=>{a(o.message),o.ok&&i()})}})}R();j();R();j();C();Ts();Se();et();st();ee();$i();var z=class z extends E{constructor(){super(...arguments);this.flat=!1;this._ov=null;this._loading=!1;this._marking=!1;this._error="";this._history=null;this._rosterSort=z._storedSort();this._typeFilter=null;this._recorded=[];this._access=he;this._historyRequested=!1;this._localeReady=!1;this._markAll=async()=>{await this._mark(void 0)};this._repair=async()=>{await this._act({type:"maintenance_supporter/battery_fleet/setup",language:this._lang})};this._loadHistory=async e=>{let t=e.target.open;if(Dt(Ae.batteryRosterOpen,t?"1":"0"),!(!t||this._historyRequested)){this._historyRequested=!0;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/overview_history"});this._history=i.series}catch{this._history=null}}}}get _lang(){return P(this.hass)}get _canWrite(){return ae(this.hass?.user,this._access)}connectedCallback(){super.connectedCallback(),this.hass&&this._load()}updated(e){si(this,e),e.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,ue(this._lang).then(()=>this.requestUpdate()),B(this.hass).then(t=>{this._access=t.access}),this._ov===null&&!this._loading&&this._load())}async _load(){this._error="";let e=await D(this,{type:"maintenance_supporter/battery_fleet/overview"},{busy:t=>{this._loading=t},onError:t=>{this._error=t}});e!==void 0&&(this._ov=e)}async _act(e,t){this._marking||(this._error="",await D(this,e,{busy:i=>{this._marking=i},reload:async()=>{t?.(),await this._load()},onError:i=>{this._error=i}}))}async _mark(e){await this._act({type:"maintenance_supporter/battery_fleet/mark_replaced",...e?{entity_ids:e}:{}})}async _setExcluded(e,t){await this._act({type:"maintenance_supporter/battery_fleet/set_excluded",entity_id:e,excluded:t})}async _addBattery(e){let t=e.detail?.value;t&&await this._act({type:"maintenance_supporter/battery_fleet/set_included",entity_id:t,included:!0})}async _setTrackSelf(e){await this._setFleetOption("set_track_self_charging",e.target.checked)}async _setDueWithoutSensor(e){await this._setFleetOption("set_due_without_sensor",e.target.checked)}async _setFleetOption(e,t){await this._act({type:`maintenance_supporter/battery_fleet/${e}`,enabled:t})}_rosterOpen(){return jt(Ae.batteryRosterOpen)!=="0"}_predictedTitle(e,t){if(e.forecast_overdue)return n("battery_fleet_forecast_overdue",t);let i=this._predictedDate(e.days_until??0);if(e.predicted_source==="trend")return n("battery_fleet_predicted_trend",t).replace("{date}",i).replace("{confidence}",n("cal_confidence_"+(e.prediction_confidence||"medium"),t));if(e.lifetime_months!=null&&e.lifetime_source){let a=n("lifetime_source_"+e.lifetime_source,t).replace("{n}",String(e.lifetime_samples??0));return n("battery_fleet_predicted_typical",t).replace("{date}",i).replace("{months}",String(e.lifetime_months)).replace("{type}",e.battery_type).replace("{source}",a)}return n("battery_fleet_predicted_on",t).replace("{date}",i)}_sparkline(e){let t=this._history?.[e.entity_id];if(!t||t.points.length<2)return p;let i=110,a=24,o=2,d=t.points[0][0],h=t.points[t.points.length-1][0],_=Date.now()/1e3,m=e.status!=="low"&&e.predicted_source==="trend"&&e.days_until!=null?_+e.days_until*86400:null,b=Math.max(h,m??h),k=O=>b===d?o:o+(O-d)/(b-d)*(i-2*o),w=O=>o+(1-Math.min(100,Math.max(0,O))/100)*(a-2*o),v=t.points.map(([O,G])=>`${A(k(O))},${A(w(G))}`).join(" "),x=t.points[t.points.length-1][1],T=A(w(t.threshold));return l`<svg
|
||||
`,c([f({attribute:!1})],oe.prototype,"hass",2),c([u()],oe.prototype,"_config",2),c([u()],oe.prototype,"_objects",2),c([u()],oe.prototype,"_loadingObjects",2),c([u()],oe.prototype,"_loadError",2),c([u()],oe.prototype,"_views",2);customElements.get("maintenance-supporter-card-editor")||customElements.define("maintenance-supporter-card-editor",oe);Rs();C();async function xl(r,s,e,t){try{let i=await r.connection.sendMessagePromise({type:"maintenance_supporter/task/undo",entry_id:s,task_id:e});return{ok:!0,message:n(i?.action_ran?"undo_done_action_ran":"undo_done",t)}}catch(i){let a=i?.code;return a==="changed_since"?{ok:!1,message:n("undo_changed",t)}:a==="nothing_to_undo"?{ok:!1,message:n("undo_nothing",t)}:{ok:!1,message:n("action_error",t)}}}function Kn(r,s,e,t,i){let a=(o,d)=>r.dispatchEvent(new CustomEvent("hass-notification",{detail:d?{message:o,action:d,duration:1e4}:{message:o},bubbles:!0,composed:!0}));a(n("task_completed_named",t).replace("{task}",e.taskName),{text:n("undo",t),action:()=>{xl(s,e.entryId,e.taskId,t).then(o=>{a(o.message),o.ok&&i()})}})}R();j();R();j();C();As();Se();et();st();ee();$i();var z=class z extends E{constructor(){super(...arguments);this.flat=!1;this._ov=null;this._loading=!1;this._marking=!1;this._error="";this._history=null;this._rosterSort=z._storedSort();this._typeFilter=null;this._recorded=[];this._access=he;this._historyRequested=!1;this._localeReady=!1;this._markAll=async()=>{await this._mark(void 0)};this._repair=async()=>{await this._act({type:"maintenance_supporter/battery_fleet/setup",language:this._lang})};this._loadHistory=async e=>{let t=e.target.open;if(Dt(Ae.batteryRosterOpen,t?"1":"0"),!(!t||this._historyRequested)){this._historyRequested=!0;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/overview_history"});this._history=i.series}catch{this._history=null}}}}get _lang(){return P(this.hass)}get _canWrite(){return ae(this.hass?.user,this._access)}connectedCallback(){super.connectedCallback(),this.hass&&this._load()}updated(e){si(this,e),e.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,ue(this._lang).then(()=>this.requestUpdate()),B(this.hass).then(t=>{this._access=t.access}),this._ov===null&&!this._loading&&this._load())}async _load(){this._error="";let e=await D(this,{type:"maintenance_supporter/battery_fleet/overview"},{busy:t=>{this._loading=t},onError:t=>{this._error=t}});e!==void 0&&(this._ov=e)}async _act(e,t){this._marking||(this._error="",await D(this,e,{busy:i=>{this._marking=i},reload:async()=>{t?.(),await this._load()},onError:i=>{this._error=i}}))}async _mark(e){await this._act({type:"maintenance_supporter/battery_fleet/mark_replaced",...e?{entity_ids:e}:{}})}async _setExcluded(e,t){await this._act({type:"maintenance_supporter/battery_fleet/set_excluded",entity_id:e,excluded:t})}async _addBattery(e){let t=e.detail?.value;t&&await this._act({type:"maintenance_supporter/battery_fleet/set_included",entity_id:t,included:!0})}async _setTrackSelf(e){await this._setFleetOption("set_track_self_charging",e.target.checked)}async _setDueWithoutSensor(e){await this._setFleetOption("set_due_without_sensor",e.target.checked)}async _setFleetOption(e,t){await this._act({type:`maintenance_supporter/battery_fleet/${e}`,enabled:t})}_rosterOpen(){return jt(Ae.batteryRosterOpen)!=="0"}_predictedTitle(e,t){if(e.forecast_overdue)return n("battery_fleet_forecast_overdue",t);let i=this._predictedDate(e.days_until??0);if(e.predicted_source==="trend")return n("battery_fleet_predicted_trend",t).replace("{date}",i).replace("{confidence}",n("cal_confidence_"+(e.prediction_confidence||"medium"),t));if(e.lifetime_months!=null&&e.lifetime_source){let a=n("lifetime_source_"+e.lifetime_source,t).replace("{n}",String(e.lifetime_samples??0));return n("battery_fleet_predicted_typical",t).replace("{date}",i).replace("{months}",String(e.lifetime_months)).replace("{type}",e.battery_type).replace("{source}",a)}return n("battery_fleet_predicted_on",t).replace("{date}",i)}_sparkline(e){let t=this._history?.[e.entity_id];if(!t||t.points.length<2)return p;let i=110,a=24,o=2,d=t.points[0][0],h=t.points[t.points.length-1][0],_=Date.now()/1e3,m=e.status!=="low"&&e.predicted_source==="trend"&&e.days_until!=null?_+e.days_until*86400:null,b=Math.max(h,m??h),k=O=>b===d?o:o+(O-d)/(b-d)*(i-2*o),w=O=>o+(1-Math.min(100,Math.max(0,O))/100)*(a-2*o),v=t.points.map(([O,G])=>`${A(k(O))},${A(w(G))}`).join(" "),x=t.points[t.points.length-1][1],T=A(w(t.threshold));return l`<svg
|
||||
class="bf-spark"
|
||||
viewBox="0 0 ${i} ${a}"
|
||||
role="img"
|
||||
@@ -5220,7 +5228,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
x2=${A(k(m))}
|
||||
y2=${T}
|
||||
></line>`:p}
|
||||
</svg>`}static _storedSort(){return jt(Ae.batteryRosterSort)==="name"?"name":"urgency"}_setSort(e){this._rosterSort=e,Dt(Ae.batteryRosterSort,e)}_sortedRoster(e){let t=this._typeFilter===null?e:e.filter(a=>a.battery_type===this._typeFilter);if(this._rosterSort==="name")return t;let i=a=>a.status==="low"?-1e3+(a.level??101)/101:a.days_until??1/0;return[...t].sort((a,o)=>i(a)-i(o)||a.device_name.localeCompare(o.device_name))}_predictedDate(e){return H(Yr(we(),e),this._lang)}_fmtDate(e){return Number.isFinite(e)?H(new Date(e).toISOString(),this._lang):"\u2014"}_shoppingLine(e){return Object.entries(e).map(([t,i])=>l`<button
|
||||
</svg>`}static _storedSort(){return jt(Ae.batteryRosterSort)==="name"?"name":"urgency"}_setSort(e){this._rosterSort=e,Dt(Ae.batteryRosterSort,e)}_sortedRoster(e){let t=this._typeFilter===null?e:e.filter(a=>a.battery_type===this._typeFilter);if(this._rosterSort==="name")return t;let i=a=>a.status==="low"?-1e3+(a.level??101)/101:a.days_until??1/0;return[...t].sort((a,o)=>i(a)-i(o)||a.device_name.localeCompare(o.device_name))}_predictedDate(e){return H(Qr(we(),e),this._lang)}_fmtDate(e){return Number.isFinite(e)?H(new Date(e).toISOString(),this._lang):"\u2014"}_shoppingLine(e){return Object.entries(e).map(([t,i])=>l`<button
|
||||
class="bf-type-chip ${this._typeFilter===t?"bf-type-chip-active":""}"
|
||||
title=${n("battery_fleet_filter_type",this._lang)}
|
||||
@click=${()=>this._toggleTypeFilter(t)}
|
||||
@@ -5917,7 +5925,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
accent-color: var(--primary-color);
|
||||
margin: 0;
|
||||
}
|
||||
`,c([f({attribute:!1})],z.prototype,"hass",2),c([f({type:Boolean})],z.prototype,"flat",2),c([u()],z.prototype,"_ov",2),c([u()],z.prototype,"_loading",2),c([u()],z.prototype,"_marking",2),c([u()],z.prototype,"_error",2),c([u()],z.prototype,"_history",2),c([u()],z.prototype,"_rosterSort",2),c([u()],z.prototype,"_typeFilter",2),c([u()],z.prototype,"_recorded",2),c([u()],z.prototype,"_access",2);var Rs=z;customElements.get("maintenance-battery-fleet-section")||customElements.define("maintenance-battery-fleet-section",Rs);var ct=class extends E{constructor(){super(...arguments);this._config={type:"custom:maintenance-battery-fleet-card"}}static getStubConfig(){return{type:"custom:maintenance-battery-fleet-card"}}setConfig(e){this._config=e}getCardSize(){return 6}render(){return this.hass?l`
|
||||
`,c([f({attribute:!1})],z.prototype,"hass",2),c([f({type:Boolean})],z.prototype,"flat",2),c([u()],z.prototype,"_ov",2),c([u()],z.prototype,"_loading",2),c([u()],z.prototype,"_marking",2),c([u()],z.prototype,"_error",2),c([u()],z.prototype,"_history",2),c([u()],z.prototype,"_rosterSort",2),c([u()],z.prototype,"_typeFilter",2),c([u()],z.prototype,"_recorded",2),c([u()],z.prototype,"_access",2);var Is=z;customElements.get("maintenance-battery-fleet-section")||customElements.define("maintenance-battery-fleet-section",Is);var ct=class extends E{constructor(){super(...arguments);this._config={type:"custom:maintenance-battery-fleet-card"}}static getStubConfig(){return{type:"custom:maintenance-battery-fleet-card"}}setConfig(e){this._config=e}getCardSize(){return 6}render(){return this.hass?l`
|
||||
<ha-card .header=${this._config.title||void 0}>
|
||||
<div class="content">
|
||||
<maintenance-battery-fleet-section flat .hass=${this.hass}></maintenance-battery-fleet-section>
|
||||
@@ -5930,17 +5938,17 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
.content {
|
||||
padding: 12px 16px 14px;
|
||||
}
|
||||
`,c([f({attribute:!1})],ct.prototype,"hass",2),c([u()],ct.prototype,"_config",2);customElements.get("maintenance-battery-fleet-card")||customElements.define("maintenance-battery-fleet-card",ct);Je({type:"maintenance-battery-fleet-card",name:"Battery Fleet",description:"All tracked batteries: what is low now, what runs out soon, and what to buy.",preview:!1});le();R();j();var Ks=["today","dashboard","calendar","settings"];C();var ht="maintenance-supporter-panel-card",Ys="maintenance-supporter-panel",Zs="maintenance-supporter",Qs=870,_c=320,mc=480;function gc(r){let e=r?.panels?.[Zs]?.config?._panel_custom?.module_url;return typeof e=="string"&&e.startsWith("/")?e:null}function fc(r){if(r==null||r===""||r==="fill")return null;if(typeof r=="number")return r>0?`${Math.round(r)}px`:null;let s=String(r).trim();return/^\d+(\.\d+)?$/.test(s)?`${s}px`:s||null}var Js=class extends HTMLElement{constructor(){super();this._config={type:`custom:${ht}`};this._panel=null;this._loading=null;this._observer=null;this._lastWidth=-1;this._preview=!1;this._onResize=()=>this._layout(!0);let e=this.attachShadow({mode:"open"}),t=document.createElement("style");t.textContent=`
|
||||
`,c([f({attribute:!1})],ct.prototype,"hass",2),c([u()],ct.prototype,"_config",2);customElements.get("maintenance-battery-fleet-card")||customElements.define("maintenance-battery-fleet-card",ct);Je({type:"maintenance-battery-fleet-card",name:"Battery Fleet",description:"All tracked batteries: what is low now, what runs out soon, and what to buy.",preview:!1});le();R();j();var Ys=["today","dashboard","calendar","settings"];C();var ht="maintenance-supporter-panel-card",Qs="maintenance-supporter-panel",Js="maintenance-supporter",Zs=870,fc=320,vc=480;function bc(r){let e=r?.panels?.[Js]?.config?._panel_custom?.module_url;return typeof e=="string"&&e.startsWith("/")?e:null}function yc(r){if(r==null||r===""||r==="fill")return null;if(typeof r=="number")return r>0?`${Math.round(r)}px`:null;let s=String(r).trim();return/^\d+(\.\d+)?$/.test(s)?`${s}px`:s||null}var Xs=class extends HTMLElement{constructor(){super();this._config={type:`custom:${ht}`};this._panel=null;this._loading=null;this._observer=null;this._lastWidth=-1;this._preview=!1;this._onResize=()=>this._layout(!0);let e=this.attachShadow({mode:"open"}),t=document.createElement("style");t.textContent=`
|
||||
:host { display: block; box-sizing: border-box; overflow: hidden; border-radius: var(--ha-card-border-radius, 12px); }
|
||||
.status { padding: 16px; color: var(--secondary-text-color); font-size: 14px; }
|
||||
${Ys} { display: block; height: 100%; }
|
||||
`,e.appendChild(t),this._status=document.createElement("div"),this._status.className="status",this._status.hidden=!0,e.appendChild(this._status)}static getConfigElement(){return document.createElement("maintenance-supporter-panel-card-editor")}static getStubConfig(){return{type:`custom:${ht}`}}set preview(e){this._preview=!!e,this._layout(!0)}get preview(){return this._preview}_inEditorPreview(){if(this._preview)return!0;let e=this;for(let t=0;e&&t<40;t++){let i=e;if(i.tagName==="HUI-CARD-PREVIEW"||i.tagName==="HUI-DIALOG-EDIT-CARD")return!0;e=i.parentElement??i.getRootNode().host??null}return!1}setConfig(e){this._config={...e},this._panel&&(this._panel.presets=this._presets()),this._layout(!0)}getCardSize(){return 12}getGridOptions(){return{columns:"full",rows:"auto"}}set hass(e){this._hass=e,this._panel?this._panel.hass=e:this._mount()}get hass(){return this._hass}connectedCallback(){typeof ResizeObserver<"u"&&!this._observer&&(this._observer=new ResizeObserver(()=>this._layout(!1)),this._observer.observe(this)),window.addEventListener("resize",this._onResize),this._layout(!0),this._hass&&this._mount()}disconnectedCallback(){this._observer?.disconnect(),this._observer=null,window.removeEventListener("resize",this._onResize)}_presets(){let e={};return Ks.includes(this._config.tab??"")&&(e.tab=this._config.tab),typeof this._config.view=="string"&&this._config.view.trim()&&(e.view=this._config.view.trim()),e}_setStatus(e){this._status.textContent=e,this._status.hidden=!1}async _mount(){if(this._panel||this._loading||!this._hass||!this.isConnected)return;let e=P(this._hass);if(!customElements.get(Ys)){let i=gc(this._hass);if(!i){this._setStatus(n("panel_card_not_registered",e));return}this._loading=import(i).then(()=>{},()=>{throw this._setStatus(n("panel_card_load_failed",e)),new Error("panel bundle failed to load")});try{await this._loading}catch{return}finally{this._loading=null}if(this._panel||!this._hass||!this.isConnected)return}let t=document.createElement(Ys);t.embedded=!0,t.panel=this._hass.panels?.[Zs]??{url_path:Zs},t.presets=this._presets(),t.narrow=this._narrow(),t.hass=this._hass,this._status.hidden=!0,this.shadowRoot.appendChild(t),this._panel=t,this._layout(!0)}_narrow(){let e=this.getBoundingClientRect().width;return e>0?e<Qs:window.innerWidth<Qs}_layout(e){let t=this.getBoundingClientRect(),i=Math.round(t.width)!==this._lastWidth;if(!e&&!i)return;this._lastWidth=Math.round(t.width),this._panel&&t.width>0&&(this._panel.narrow=t.width<Qs);let a=fc(this._config.height);if(a){this.style.height=a;return}if(!this.isConnected)return;if(this._inEditorPreview()){this.style.height=`${mc}px`;return}let o=Math.max(0,this._unscrolledTop(t)),d=Math.max(_c,Math.floor(window.innerHeight-o));this.style.height=`${d}px`}_unscrolledTop(e){let t=e.top+window.scrollY,i=this.ownerDocument,a=this.parentElement??this.getRootNode().host??null;for(let o=0;a&&o<100;o++){let d=a;d!==i.documentElement&&d!==i.body&&typeof d.scrollTop=="number"&&d.scrollTop>0&&(t+=d.scrollTop),a=d.parentElement??d.getRootNode().host??null}return t}},Fe=class extends E{constructor(){super(...arguments);this._config={type:`custom:${ht}`};this._views=[];this._viewsLoaded=!1}setConfig(e){this._config={...e}}updated(e){super.updated(e),e.has("hass")&&this.hass&&!this._viewsLoaded&&(this._viewsLoaded=!0,this._loadViews())}async _loadViews(){try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/views/list"});this._views=e?.views||[]}catch{this._views=[]}}_set(e,t){let i={...this._config};t===""||t===void 0?delete i[e]:i[e]=t,this._config=i,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:i},bubbles:!0,composed:!0}))}render(){let e=P(this.hass),t=i=>n(i==="today"?"tab_today":i==="calendar"?"tab_calendar":i,e);return l`
|
||||
${Qs} { display: block; height: 100%; }
|
||||
`,e.appendChild(t),this._status=document.createElement("div"),this._status.className="status",this._status.hidden=!0,e.appendChild(this._status)}static getConfigElement(){return document.createElement("maintenance-supporter-panel-card-editor")}static getStubConfig(){return{type:`custom:${ht}`}}set preview(e){this._preview=!!e,this._layout(!0)}get preview(){return this._preview}_inEditorPreview(){if(this._preview)return!0;let e=this;for(let t=0;e&&t<40;t++){let i=e;if(i.tagName==="HUI-CARD-PREVIEW"||i.tagName==="HUI-DIALOG-EDIT-CARD")return!0;e=i.parentElement??i.getRootNode().host??null}return!1}setConfig(e){this._config={...e},this._panel&&(this._panel.presets=this._presets()),this._layout(!0)}getCardSize(){return 12}getGridOptions(){return{columns:"full",rows:"auto"}}set hass(e){this._hass=e,this._panel?this._panel.hass=e:this._mount()}get hass(){return this._hass}connectedCallback(){typeof ResizeObserver<"u"&&!this._observer&&(this._observer=new ResizeObserver(()=>this._layout(!1)),this._observer.observe(this)),window.addEventListener("resize",this._onResize),this._layout(!0),this._hass&&this._mount()}disconnectedCallback(){this._observer?.disconnect(),this._observer=null,window.removeEventListener("resize",this._onResize)}_presets(){let e={};return Ys.includes(this._config.tab??"")&&(e.tab=this._config.tab),typeof this._config.view=="string"&&this._config.view.trim()&&(e.view=this._config.view.trim()),e}_setStatus(e){this._status.textContent=e,this._status.hidden=!1}async _mount(){if(this._panel||this._loading||!this._hass||!this.isConnected)return;let e=P(this._hass);if(!customElements.get(Qs)){let i=bc(this._hass);if(!i){this._setStatus(n("panel_card_not_registered",e));return}this._loading=import(i).then(()=>{},()=>{throw this._setStatus(n("panel_card_load_failed",e)),new Error("panel bundle failed to load")});try{await this._loading}catch{return}finally{this._loading=null}if(this._panel||!this._hass||!this.isConnected)return}let t=document.createElement(Qs);t.embedded=!0,t.panel=this._hass.panels?.[Js]??{url_path:Js},t.presets=this._presets(),t.narrow=this._narrow(),t.hass=this._hass,this._status.hidden=!0,this.shadowRoot.appendChild(t),this._panel=t,this._layout(!0)}_narrow(){let e=this.getBoundingClientRect().width;return e>0?e<Zs:window.innerWidth<Zs}_layout(e){let t=this.getBoundingClientRect(),i=Math.round(t.width)!==this._lastWidth;if(!e&&!i)return;this._lastWidth=Math.round(t.width),this._panel&&t.width>0&&(this._panel.narrow=t.width<Zs);let a=yc(this._config.height);if(a){this.style.height=a;return}if(!this.isConnected)return;if(this._inEditorPreview()){this.style.height=`${vc}px`;return}let o=Math.max(0,this._unscrolledTop(t)),d=Math.max(fc,Math.floor(window.innerHeight-o));this.style.height=`${d}px`}_unscrolledTop(e){let t=e.top+window.scrollY,i=this.ownerDocument,a=this.parentElement??this.getRootNode().host??null;for(let o=0;a&&o<100;o++){let d=a;d!==i.documentElement&&d!==i.body&&typeof d.scrollTop=="number"&&d.scrollTop>0&&(t+=d.scrollTop),a=d.parentElement??d.getRootNode().host??null}return t}},Fe=class extends E{constructor(){super(...arguments);this._config={type:`custom:${ht}`};this._views=[];this._viewsLoaded=!1}setConfig(e){this._config={...e}}updated(e){super.updated(e),e.has("hass")&&this.hass&&!this._viewsLoaded&&(this._viewsLoaded=!0,this._loadViews())}async _loadViews(){try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/views/list"});this._views=e?.views||[]}catch{this._views=[]}}_set(e,t){let i={...this._config};t===""||t===void 0?delete i[e]:i[e]=t,this._config=i,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:i},bubbles:!0,composed:!0}))}render(){let e=P(this.hass),t=i=>n(i==="today"?"tab_today":i==="calendar"?"tab_calendar":i,e);return l`
|
||||
<div class="editor">
|
||||
<div class="field">
|
||||
<div class="field-label">${n("panel_card_tab",e)}</div>
|
||||
<select class="tab-select" .value=${this._config.tab||""} @change=${i=>this._set("tab",i.target.value)}>
|
||||
<option value="" ?selected=${!this._config.tab}>${n("panel_card_tab_default",e)}</option>
|
||||
${Ks.map(i=>l`<option value=${i} ?selected=${this._config.tab===i}>${t(i)}</option>`)}
|
||||
${Ys.map(i=>l`<option value=${i} ?selected=${this._config.tab===i}>${t(i)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
${this._views.length>0?l`<div class="field">
|
||||
@@ -5965,8 +5973,8 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
.field-label { font-size: 13px; color: var(--secondary-text-color); font-weight: 500; }
|
||||
.field-help { font-size: 12px; color: var(--secondary-text-color); }
|
||||
select { padding: 8px; border-radius: 4px; border: 1px solid var(--divider-color); background: var(--card-background-color); color: var(--primary-text-color); font-size: 14px; max-width: 320px; }
|
||||
`,c([f({attribute:!1})],Fe.prototype,"hass",2),c([u()],Fe.prototype,"_config",2),c([u()],Fe.prototype,"_views",2);customElements.get(ht)||customElements.define(ht,Js);customElements.get("maintenance-supporter-panel-card-editor")||customElements.define("maintenance-supporter-panel-card-editor",Fe);Je({type:ht,name:"Maintenance Supporter \u2014 Panel",description:"The complete Maintenance Supporter panel as a card \u2014 for a panel view / dashboard subview without the sidebar entry.",preview:!1});pi();var eo=2,F=class extends E{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-card"};this._globalRowStyle="buttons_compact";this._settings=it;this._firstLoadDone=!1;this._objects=[];this._stats=null;this._unsub=null;this._viewFilters=null;this._userNames={};this._userPersons={};this._userService=null;this._userNamesLoaded=!1;this._taskDocs={};this._docsLoadedFor=new Set;this._dataLoaded=!1;this._lastConnection=null;this._onCompleted=async e=>{await this._loadData();let t=e.detail;t?.undo&&Gn(this,this.hass,t,this._lang,()=>{this._loadData()})}}get _lang(){return P(this.hass)}static getConfigElement(){return document.createElement("maintenance-supporter-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-card",show_header:!0,show_actions:!0,filter_status:[...Yi],max_items:10}}setConfig(e){let t=e.view_id!==this._config.view_id;this._config=e,t&&this._dataLoaded&&this.hass&&this._loadViewFilters()}getCardSize(){return 3}connectedCallback(){super.connectedCallback()}disconnectedCallback(){super.disconnectedCallback(),this._unsub&&(this._unsub(),this._unsub=null),this._dataLoaded=!1,this._lastConnection=null}updated(e){if(super.updated(e),si(this,e),this.hass&&!this._userNamesLoaded&&this._config.show_assignee!==!1&&this._objects.some(t=>t.tasks.some(i=>i.responsible_user_id))&&this._loadUserNames(),this.hass&&this._config.show_documents!==!1)for(let t of this._objects)this._docsLoadedFor.has(t.entry_id)||t.tasks.some(i=>(i.document_count??0)>0)&&this._loadDocuments(t.entry_id);if(e.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){B(this.hass).then(t=>{this._settings=t,this._globalRowStyle=t.rowActionStyle}).catch(()=>{});let e=this._loadViewFilters();try{let[t,i]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);await e,this._objects=wt(t.objects),this._stats=i,ri(this._stats.budget)}catch{}await e,this._firstLoadDone=!0}_lastDone(e,t){let i=tn(e.last_performed,t);return i?l`<span class="last-done" title="${n("last_performed",t)}: ${H(e.last_performed,t)}">${i}</span>`:"\u2014"}_assigneeName(e){if(this._config.show_assignee===!1)return"";let t=e.responsible_user_id;return t&&this._userNames[t]||""}async _loadUserNames(){this._userNamesLoaded=!0,this._userService?this._userService.updateHass(this.hass):this._userService=new Xe(this.hass);try{let e=await this._userService.getUsers();this._userPersons=Object.fromEntries(e.map(t=>[t.id,ui(t)])),this._userNames=Object.fromEntries(e.map(t=>[t.id,t.name]))}catch{}}async _loadDocuments(e){this._docsLoadedFor.add(e);try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/list",entry_id:e}),i={};for(let a of t.documents||[])if(!ln(a))for(let o of a.task_ids||[])(i[o]||=[]).push({id:a.id,title:a.title,kind:a.kind,url:a.url});this._taskDocs={...this._taskDocs,[e]:i}}catch{}}_docsFor(e,t){if(this._config.show_documents===!1)return[];let a=[...this._taskDocs[e]?.[t.id]||[]];return t.documentation_url&&a.push({id:`url:${t.id}`,title:n("documentation_label",this._lang),kind:"weblink",url:t.documentation_url}),a}_renderDocChips(e,t){let i=this._docsFor(e,t);if(!i.length)return p;let a=i.slice(eo);return l`<div class="doc-chips">
|
||||
${i.slice(0,eo).map(o=>l`
|
||||
`,c([f({attribute:!1})],Fe.prototype,"hass",2),c([u()],Fe.prototype,"_config",2),c([u()],Fe.prototype,"_views",2);customElements.get(ht)||customElements.define(ht,Xs);customElements.get("maintenance-supporter-panel-card-editor")||customElements.define("maintenance-supporter-panel-card-editor",Fe);Je({type:ht,name:"Maintenance Supporter \u2014 Panel",description:"The complete Maintenance Supporter panel as a card \u2014 for a panel view / dashboard subview without the sidebar entry.",preview:!1});pi();var to=2,F=class extends E{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-card"};this._globalRowStyle="buttons_compact";this._settings=it;this._firstLoadDone=!1;this._objects=[];this._stats=null;this._unsub=null;this._viewFilters=null;this._userNames={};this._userPersons={};this._userService=null;this._userNamesLoaded=!1;this._taskDocs={};this._docsLoadedFor=new Set;this._dataLoaded=!1;this._lastConnection=null;this._onCompleted=async e=>{await this._loadData();let t=e.detail;t?.undo&&Kn(this,this.hass,t,this._lang,()=>{this._loadData()})}}get _lang(){return P(this.hass)}static getConfigElement(){return document.createElement("maintenance-supporter-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-card",show_header:!0,show_actions:!0,filter_status:[...Yi],max_items:10}}setConfig(e){let t=e.view_id!==this._config.view_id;this._config=e,t&&this._dataLoaded&&this.hass&&this._loadViewFilters()}getCardSize(){return 3}connectedCallback(){super.connectedCallback()}disconnectedCallback(){super.disconnectedCallback(),this._unsub&&(this._unsub(),this._unsub=null),this._dataLoaded=!1,this._lastConnection=null}updated(e){if(super.updated(e),si(this,e),this.hass&&!this._userNamesLoaded&&this._config.show_assignee!==!1&&this._objects.some(t=>t.tasks.some(i=>i.responsible_user_id))&&this._loadUserNames(),this.hass&&this._config.show_documents!==!1)for(let t of this._objects)this._docsLoadedFor.has(t.entry_id)||t.tasks.some(i=>(i.document_count??0)>0)&&this._loadDocuments(t.entry_id);if(e.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){B(this.hass).then(t=>{this._settings=t,this._globalRowStyle=t.rowActionStyle}).catch(()=>{});let e=this._loadViewFilters();try{let[t,i]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);await e,this._objects=wt(t.objects),this._stats=i,ri(this._stats.budget)}catch{}await e,this._firstLoadDone=!0}_lastDone(e,t){let i=sn(e.last_performed,t);return i?l`<span class="last-done" title="${n("last_performed",t)}: ${H(e.last_performed,t)}">${i}</span>`:"\u2014"}_assigneeName(e){if(this._config.show_assignee===!1)return"";let t=e.responsible_user_id;return t&&this._userNames[t]||""}async _loadUserNames(){this._userNamesLoaded=!0,this._userService?this._userService.updateHass(this.hass):this._userService=new Xe(this.hass);try{let e=await this._userService.getUsers();this._userPersons=Object.fromEntries(e.map(t=>[t.id,ui(t)])),this._userNames=Object.fromEntries(e.map(t=>[t.id,t.name]))}catch{}}async _loadDocuments(e){this._docsLoadedFor.add(e);try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/list",entry_id:e}),i={};for(let a of t.documents||[])if(!cn(a))for(let o of a.task_ids||[])(i[o]||=[]).push({id:a.id,title:a.title,kind:a.kind,url:a.url});this._taskDocs={...this._taskDocs,[e]:i}}catch{}}_docsFor(e,t){if(this._config.show_documents===!1)return[];let a=[...this._taskDocs[e]?.[t.id]||[]];return t.documentation_url&&a.push({id:`url:${t.id}`,title:n("documentation_label",this._lang),kind:"weblink",url:t.documentation_url}),a}_renderDocChips(e,t){let i=this._docsFor(e,t);if(!i.length)return p;let a=i.slice(to);return l`<div class="doc-chips">
|
||||
${i.slice(0,to).map(o=>l`
|
||||
<button
|
||||
type="button"
|
||||
class="doc-chip"
|
||||
@@ -5979,7 +5987,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
`)}
|
||||
${a.length?l`<span class="doc-chip doc-more" title="${a.map(o=>o.title).join(`
|
||||
`)}">+${a.length}</span>`:p}
|
||||
</div>`}async _openDoc(e){if(e.kind==="weblink"&&e.url){Ze(e.url)&&window.open(e.url,"_blank","noopener");return}try{await on(this.hass,e.id)}catch{}}async _loadViewFilters(){if(!this._config.view_id){this._viewFilters=null;return}try{let t=((await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/views/list"})).views||[]).find(i=>i.id===this._config.view_id);this._viewFilters=t?t.filters:null}catch{this._viewFilters=null}}async _subscribe(){try{let e=await this.hass.connection.subscribeMessage(t=>{let i=xr(this._objects,t);i!==null&&(this._objects=i)},{type:"maintenance_supporter/subscribe",deltas:!0,compact:!0});if(!this.isConnected){e();return}this._unsub=e}catch{}}get _selectedTasks(){let e=[],{filter_status:t,filter_objects:i,entity_ids:a,filter_due_min_days:o,filter_due_max_days:d,filter_labels:h,filter_priority:_,filter_areas:m}=this._config,b=a?.length?new Set(a):null,k=o!==void 0||d!==void 0,w=this._viewFilters,v=w?.user_id==="current_user"?this.hass.user?.id??null:w?.user_id??null;for(let x of this._objects)if(!(i?.length&&!i.includes(x.object.name))){if(m?.length){let T=x.object.area_id;if(!T||!m.includes(T))continue}for(let T of x.tasks)if(!T.is_done&&!(T.archived||x.object.archived)&&!(t?.length&&!t.includes(T.status))&&!(h?.length&&!(T.labels||[]).some(O=>h.includes(O)))&&!(_?.length&&!_.includes(T.priority||"normal"))&&!(b&&!(T.sensor_entity_id&&b.has(T.sensor_entity_id)||T.binary_sensor_entity_id&&b.has(T.binary_sensor_entity_id)))){if(k){let O=T.days_until_due;if(O==null||o!==void 0&&O<o||d!==void 0&&O>d)continue}w&&(w.status&&T.status!==w.status||w.label&&!(T.labels||[]).includes(w.label)||w.priority&&(T.priority||"normal")!==w.priority||v&&!wr(T,v))||e.push({entry_id:x.entry_id,object_name:x.object.name,task:T})}}return e.sort((x,T)=>{let O=Qi(x.task.status)-Qi(T.task.status);return O!==0?O:(x.task.days_until_due??1/0)-(T.task.days_until_due??1/0)}),e}_openComplete(e,t){let i=this.shadowRoot.querySelector("maintenance-complete-dialog");gi(i,mi({entryId:e,taskId:t.id,taskName:t.name,task:t,objects:this._objects,lang:this._lang,features:this._settings.features,currencySymbol:je(this._stats?.budget),partsCostMode:this._settings.partsCostMode}),this._lang)}_headerCounts(e){let t={overdue:0,due_soon:0,triggered:0};for(let{task:i}of e)Lr(i.status)&&(t[i.status]+=1);return t}_openTaskDetail(e,t){Gs(e,t)}render(){let e=this._lang,t=this._config.title||n("maintenance",e),i=this._config.show_header!==!1,a=(this._config.action_style??(this._globalRowStyle==="icons"?"icons":"buttons"))==="buttons",o=this._config.show_actions!==!1,d=o&&ae(this.hass?.user,this._settings.access),h=this._config.compact||!1,_=this._selectedTasks,{max_items:m}=this._config,b=m&&m>0?_.slice(0,m):_,k=this._objects.length||this._stats?this._headerCounts(_):null;return l`
|
||||
</div>`}async _openDoc(e){if(e.kind==="weblink"&&e.url){Ze(e.url)&&window.open(e.url,"_blank","noopener");return}try{await ln(this.hass,e.id)}catch{}}async _loadViewFilters(){if(!this._config.view_id){this._viewFilters=null;return}try{let t=((await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/views/list"})).views||[]).find(i=>i.id===this._config.view_id);this._viewFilters=t?t.filters:null}catch{this._viewFilters=null}}async _subscribe(){try{let e=await this.hass.connection.subscribeMessage(t=>{let i=wr(this._objects,t);i!==null&&(this._objects=i)},{type:"maintenance_supporter/subscribe",deltas:!0,compact:!0});if(!this.isConnected){e();return}this._unsub=e}catch{}}get _selectedTasks(){let e=[],{filter_status:t,filter_objects:i,entity_ids:a,filter_due_min_days:o,filter_due_max_days:d,filter_labels:h,filter_priority:_,filter_areas:m}=this._config,b=a?.length?new Set(a):null,k=o!==void 0||d!==void 0,w=this._viewFilters,v=w?.user_id==="current_user"?this.hass.user?.id??null:w?.user_id??null;for(let x of this._objects)if(!(i?.length&&!i.includes(x.object.name))){if(m?.length){let T=x.object.area_id;if(!T||!m.includes(T))continue}for(let T of x.tasks)if(!T.is_done&&!(T.archived||x.object.archived)&&!(t?.length&&!t.includes(T.status))&&!(h?.length&&!(T.labels||[]).some(O=>h.includes(O)))&&!(_?.length&&!_.includes(T.priority||"normal"))&&!(b&&!(T.sensor_entity_id&&b.has(T.sensor_entity_id)||T.binary_sensor_entity_id&&b.has(T.binary_sensor_entity_id)))){if(k){let O=T.days_until_due;if(O==null||o!==void 0&&O<o||d!==void 0&&O>d)continue}w&&(w.status&&T.status!==w.status||w.label&&!(T.labels||[]).includes(w.label)||w.priority&&(T.priority||"normal")!==w.priority||v&&!kr(T,v))||e.push({entry_id:x.entry_id,object_name:x.object.name,task:T})}}return e.sort((x,T)=>{let O=Qi(x.task.status)-Qi(T.task.status);return O!==0?O:(x.task.days_until_due??1/0)-(T.task.days_until_due??1/0)}),e}_openComplete(e,t){let i=this.shadowRoot.querySelector("maintenance-complete-dialog");gi(i,mi({entryId:e,taskId:t.id,taskName:t.name,task:t,objects:this._objects,lang:this._lang,features:this._settings.features,currencySymbol:je(this._stats?.budget),partsCostMode:this._settings.partsCostMode}),this._lang)}_headerCounts(e){let t={overdue:0,due_soon:0,triggered:0};for(let{task:i}of e)Nr(i.status)&&(t[i.status]+=1);return t}_openTaskDetail(e,t){Ks(e,t)}render(){let e=this._lang,t=this._config.title||n("maintenance",e),i=this._config.show_header!==!1,a=(this._config.action_style??(this._globalRowStyle==="icons"?"icons":"buttons"))==="buttons",o=this._config.show_actions!==!1,d=o&&ae(this.hass?.user,this._settings.access),h=this._config.compact||!1,_=this._selectedTasks,{max_items:m}=this._config,b=m&&m>0?_.slice(0,m):_,k=this._objects.length||this._stats?this._headerCounts(_):null;return l`
|
||||
<ha-card>
|
||||
<div class="card-header">
|
||||
<h1>${t}</h1>
|
||||
@@ -5995,14 +6003,14 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
<ha-icon-button
|
||||
class="hdr-add"
|
||||
title="${n("new_object",e)}"
|
||||
@click=${()=>Ws()}
|
||||
@click=${()=>Vs()}
|
||||
>
|
||||
<ha-icon icon="mdi:plus-box"></ha-icon>
|
||||
</ha-icon-button>
|
||||
<ha-icon-button
|
||||
class="hdr-add"
|
||||
title="${n("add_task",e)}"
|
||||
@click=${()=>Vs("",this._objects)}
|
||||
@click=${()=>Gs("",this._objects)}
|
||||
>
|
||||
<ha-icon icon="mdi:playlist-plus"></ha-icon>
|
||||
</ha-icon-button>
|
||||
@@ -6025,7 +6033,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
<div class="status-dot" style="background: ${kt[x.status]||"#ccc"}"></div>
|
||||
<div class="task-info">
|
||||
<div class="task-name">
|
||||
${x.name}${hn(x.next_event_titles)}
|
||||
${x.name}${_n(x.next_event_titles)}
|
||||
${x.due_override?l`<ha-icon
|
||||
class="postponed-icon"
|
||||
icon="mdi:calendar-clock"
|
||||
@@ -6033,16 +6041,16 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
></ha-icon>`:p}
|
||||
</div>
|
||||
${h?this._assigneeName(x)?l`<div class="task-meta compact-assignee" title="${this._assigneeName(x)}">
|
||||
${ms(this._userPersons[x.responsible_user_id])}${this._assigneeName(x)}
|
||||
${gs(this._userPersons[x.responsible_user_id])}${this._assigneeName(x)}
|
||||
</div>`:p:l`<div class="task-meta">
|
||||
${v} · ${n(x.type,e)}${ke(x)?l` · ${ke(x)}`:p}${this._assigneeName(x)?l` · <span class="assignee"
|
||||
>${ms(this._userPersons[x.responsible_user_id])}${this._assigneeName(x)}</span
|
||||
>${gs(this._userPersons[x.responsible_user_id])}${this._assigneeName(x)}</span
|
||||
>`:p}
|
||||
</div>`}
|
||||
</div>
|
||||
${this._renderDocChips(w,x)}
|
||||
<div class="task-due">
|
||||
${x.days_until_due!==null&&x.days_until_due!==void 0?x.days_until_due<0?l`<span class="overdue-text">${ls(x.days_until_due,e)}</span>`:ls(x.days_until_due,e):x.trigger_active?"\u26A1":this._lastDone(x,e)}
|
||||
${x.days_until_due!==null&&x.days_until_due!==void 0?x.days_until_due<0?l`<span class="overdue-text">${cs(x.days_until_due,e)}</span>`:cs(x.days_until_due,e):x.trigger_active?"\u26A1":this._lastDone(x,e)}
|
||||
</div>
|
||||
${o&&a?l`
|
||||
<ha-button
|
||||
@@ -6240,7 +6248,7 @@ ${h?`<div class="sub">${h}</div>`:""}
|
||||
/* DESIGN PROTOTYPE (#145): action_style: buttons — HA-native labelled button. */
|
||||
.complete-btn-text { --ha-button-font-size: 13px; flex: none; white-space: nowrap; }
|
||||
.complete-btn-text ha-icon { --mdc-icon-size: 18px; }
|
||||
`],c([f({attribute:!1})],F.prototype,"hass",2),c([u()],F.prototype,"_config",2),c([u()],F.prototype,"_globalRowStyle",2),c([u()],F.prototype,"_settings",2),c([u()],F.prototype,"_firstLoadDone",2),c([u()],F.prototype,"_objects",2),c([u()],F.prototype,"_stats",2),c([u()],F.prototype,"_unsub",2),c([u()],F.prototype,"_viewFilters",2),c([u()],F.prototype,"_userNames",2),c([u()],F.prototype,"_taskDocs",2);customElements.get("maintenance-supporter-card")||customElements.define("maintenance-supporter-card",F);Je({type:"maintenance-supporter-card",name:"Maintenance Supporter",description:"Overview of your maintenance tasks with quick actions.",preview:!0});pi();pn(["maintenance-supporter-card","maintenance-battery-fleet-card","maintenance-supporter-panel-card"],import.meta.url);export{F as MaintenanceSupporterCard};
|
||||
`],c([f({attribute:!1})],F.prototype,"hass",2),c([u()],F.prototype,"_config",2),c([u()],F.prototype,"_globalRowStyle",2),c([u()],F.prototype,"_settings",2),c([u()],F.prototype,"_firstLoadDone",2),c([u()],F.prototype,"_objects",2),c([u()],F.prototype,"_stats",2),c([u()],F.prototype,"_unsub",2),c([u()],F.prototype,"_viewFilters",2),c([u()],F.prototype,"_userNames",2),c([u()],F.prototype,"_taskDocs",2);customElements.get("maintenance-supporter-card")||customElements.define("maintenance-supporter-card",F);Je({type:"maintenance-supporter-card",name:"Maintenance Supporter",description:"Overview of your maintenance tasks with quick actions.",preview:!0});pi();un(["maintenance-supporter-card","maintenance-battery-fleet-card","maintenance-supporter-panel-card"],import.meta.url);export{F as MaintenanceSupporterCard};
|
||||
/*! Bundled license information:
|
||||
|
||||
@lit/reactive-element/css-tag.js:
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,2 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.102.0 */
|
||||
var v="2.102.0";var f="maintenance-supporter",L=`ll-strategy-dashboard-${f}`,C="hui-maintenance-supporter-strategy-editor",M=["maintenance-supporter-section","maintenance-supporter-vacation","maintenance-supporter-budget","maintenance-supporter-groups"],D=`/maintenance_supporter_strategy/maintenance-dashboard-strategy.js?v=${v}`,w=null;function h(){return w||(w=import(D)),w}async function I(){let e=await h();if(!e.MaintenanceDashboardStrategy)throw new Error("[maintenance-supporter] strategy bundle loaded but did not export MaintenanceDashboardStrategy");return e.MaintenanceDashboardStrategy}async function P(e){let i=(await h()).SECTION_STRATEGIES?.[e];if(!i)throw new Error(`[maintenance-supporter] strategy bundle loaded but has no section strategy "${e}"`);return i}function B(e){return class extends HTMLElement{static async generate(i,l){return(await P(e)).generate(i,l)}}}var y=class extends HTMLElement{static getCreateSuggestions(s){return{title:"Maintenance Supporter",icon:"mdi:wrench-clock"}}static async getConfigElement(){return await h(),document.createElement(C)}static async generate(s,i){return(await I()).generate(s,i)}};function O(){try{customElements.define(L,y)}catch{}for(let e of M)try{customElements.define(`ll-strategy-section-${e}`,B(e))}catch{}}O();var m=window;m.customStrategies=m.customStrategies||[];var U=[{type:f,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentationURL:"https://github.com/iluebbe/maintenance_supporter/blob/master/docs/EXAMPLES.md#dashboard-strategy"},{type:"maintenance-supporter-section",strategyType:"section",name:"Maintenance Supporter \u2014 Section",description:"Embed maintenance tasks (filterable by area, status, due date) as a section in any dashboard view.",documentationURL:"https://github.com/iluebbe/maintenance_supporter/blob/master/docs/EXAMPLES.md#section-strategy"},{type:"maintenance-supporter-vacation",strategyType:"section",name:"Maintenance Supporter \u2014 Vacation Status",description:"Compact vacation-mode status banner. Tap to open settings in the panel."},{type:"maintenance-supporter-budget",strategyType:"section",name:"Maintenance Supporter \u2014 Budget Status",description:"Monthly + yearly maintenance budget overview. Tap for details."},{type:"maintenance-supporter-groups",strategyType:"section",name:"Maintenance Supporter \u2014 Groups",description:"List of configured task groups with member counts."}];for(let e of U)m.customStrategies.some(s=>s.type===e.type&&s.strategyType===e.strategyType)||m.customStrategies.push(e);(()=>{let e=window;if(e.__msStrategyHealActive)return;e.__msStrategyHealActive=!0;let s=/^\/(auth|config|developer-tools|profile|hassio|history|logbook|map|media-browser|energy|todo|calendar)\b/,i=/Timeout waiting for strategy element ll-strategy-(dashboard-)?maintenance-supporter/i,l=`custom:${f}`;function S(r){let t=[document.documentElement],a=0;for(;t.length&&a<9e3;){let o=t.pop();if(a++,!o)continue;let n=o;if(n.nodeType===1&&n.tagName&&n.tagName.toLowerCase()===r)return n;n.shadowRoot&&t.push(n.shadowRoot);let u=o.children;if(u)for(let p of Array.from(u))t.push(p)}return null}function R(r){let t=r?.views;if(!Array.isArray(t)||!t.length)return null;let a=window.location.pathname.split("/").filter(Boolean).pop()||"",o=t.find(u=>u?.path===a);if(o)return o;let n=Number(a);return Number.isInteger(n)&&t[n]?t[n]:t[0]}function k(){try{let t=S("ha-panel-lovelace")?.lovelace;if(!t)return!1;let a=o=>o?.type;for(let o of[t.config,t.rawConfig]){if(!o)continue;if(a(o.strategy)===l)return!0;let n=R(o);if(n&&a(n.strategy)===l)return!0}return!1}catch{return!1}}function T(){let r=!1,t=0,a=!1,o=!1,n=[document.documentElement],u=0;for(;n.length&&u<9e3;){let p=n.pop();if(u++,!p)continue;let d=p;if(d.nodeType===1&&d.tagName){let c=d.tagName.toLowerCase();(c==="hui-view"||c==="hui-sections-view")&&(r=!0),(c==="ha-card"||c==="hui-card")&&t++,c==="hui-empty-state-card"&&(o=!0),c==="hui-error-card"&&i.test(d.textContent||"")&&(a=!0)}d.shadowRoot&&n.push(d.shadowRoot);let _=p.children;if(_)for(let c of Array.from(_))n.push(c)}return a?!0:o?!1:r&&t<3&&k()}let N="/maintenance_supporter_strategy_shim.js",E=0,b=0;function A(){let r=Date.now();r-b<5e3||E>=3||(b=r,E+=1,import(`${N}?heal=${r}`).catch(()=>{}).finally(()=>{let t=window.location.pathname+window.location.search;history.pushState(null,"","/lovelace"),window.dispatchEvent(new CustomEvent("location-changed")),window.setTimeout(()=>{history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed"))},200)}))}function g(){if(s.test(window.location.pathname))return;let r=0,t=Date.now(),a=window.setInterval(()=>{r++;try{if(Date.now()-t<6e3)return;if(s.test(window.location.pathname)){window.clearInterval(a);return}T()?A():window.clearInterval(a),r>=30&&window.clearInterval(a)}catch{window.clearInterval(a)}},500)}try{document.readyState==="lLine truncated
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
var v="2.103.0";var y="maintenance-supporter",L=`ll-strategy-dashboard-${y}`,C="hui-maintenance-supporter-strategy-editor",M=["maintenance-supporter-section","maintenance-supporter-vacation","maintenance-supporter-budget","maintenance-supporter-groups"],D=`/maintenance_supporter_strategy/maintenance-dashboard-strategy.js?v=${v}`,w=null;function h(){return w||(w=import(D)),w}async function I(){let t=await h();if(!t.MaintenanceDashboardStrategy)throw new Error("[maintenance-supporter] strategy bundle loaded but did not export MaintenanceDashboardStrategy");return t.MaintenanceDashboardStrategy}async function P(t){let i=(await h()).SECTION_STRATEGIES?.[t];if(!i)throw new Error(`[maintenance-supporter] strategy bundle loaded but has no section strategy "${t}"`);return i}function B(t){return class extends HTMLElement{static async generate(i,d){return(await P(t)).generate(i,d)}}}var f=class extends HTMLElement{static getCreateSuggestions(s){return{title:"Maintenance Supporter",icon:"mdi:wrench-clock"}}static async getConfigElement(){return await h(),document.createElement(C)}static async generate(s,i){return(await I()).generate(s,i)}};function O(){try{customElements.define(L,f)}catch{}for(let t of M)try{customElements.define(`ll-strategy-section-${t}`,B(t))}catch{}}O();var g=window;g.customStrategies=g.customStrategies||[];var U=[{type:y,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentationURL:"https://github.com/iluebbe/maintenance_supporter/blob/master/docs/EXAMPLES.md#dashboard-strategy"},{type:"maintenance-supporter-section",strategyType:"section",name:"Maintenance Supporter \u2014 Section",description:"Embed maintenance tasks (filterable by area, status, due date) as a section in any dashboard view.",documentationURL:"https://github.com/iluebbe/maintenance_supporter/blob/master/docs/EXAMPLES.md#section-strategy"},{type:"maintenance-supporter-vacation",strategyType:"section",name:"Maintenance Supporter \u2014 Vacation Status",description:"Compact vacation-mode status banner. Tap to open settings in the panel."},{type:"maintenance-supporter-budget",strategyType:"section",name:"Maintenance Supporter \u2014 Budget Status",description:"Monthly + yearly maintenance budget overview. Tap for details."},{type:"maintenance-supporter-groups",strategyType:"section",name:"Maintenance Supporter \u2014 Groups",description:"List of configured task groups with member counts."}];for(let t of U)g.customStrategies.some(s=>s.type===t.type&&s.strategyType===t.strategyType)||g.customStrategies.push(t);(()=>{let t=window;if(t.__msStrategyHealActive)return;t.__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,d=`custom:${y}`;function S(r){let e=[document.documentElement],o=0;for(;e.length&&o<9e3;){let a=e.pop();if(o++,!a)continue;let n=a;if(n.nodeType===1&&n.tagName&&n.tagName.toLowerCase()===r)return n;n.shadowRoot&&e.push(n.shadowRoot);let u=a.children;if(u)for(let p of Array.from(u))e.push(p)}return null}function R(r){let e=r?.views;if(!Array.isArray(e)||!e.length)return null;let o=window.location.pathname.split("/").filter(Boolean).pop()||"",a=e.find(u=>u?.path===o);if(a)return a;let n=Number(o);return Number.isInteger(n)&&e[n]?e[n]:e[0]}function k(){try{let e=S("ha-panel-lovelace")?.lovelace;if(!e)return!1;let o=a=>a?.type;for(let a of[e.config,e.rawConfig]){if(!a)continue;if(o(a.strategy)===d)return!0;let n=R(a);if(n&&o(n.strategy)===d)return!0}return!1}catch{return!1}}function T(){let r=!1,e=0,o=!1,a=!1,n=[document.documentElement],u=0;for(;n.length&&u<9e3;){let p=n.pop();if(u++,!p)continue;let l=p;if(l.nodeType===1&&l.tagName){let c=l.tagName.toLowerCase();(c==="hui-view"||c==="hui-sections-view")&&(r=!0),(c==="ha-card"||c==="hui-card")&&e++,c==="hui-empty-state-card"&&(a=!0),c==="hui-error-card"&&i.test(l.textContent||"")&&(o=!0)}l.shadowRoot&&n.push(l.shadowRoot);let _=p.children;if(_)for(let c of Array.from(_))n.push(c)}return o?!0:a?!1:r&&e<3&&k()}let N="/maintenance_supporter_strategy_shim.js",E=0,b=0;function A(){let r=Date.now();r-b<5e3||E>=3||(b=r,E+=1,import(`${N}?heal=${r}`).catch(()=>{}).finally(()=>{let e=window.location.pathname+window.location.search;history.pushState(null,"","/lovelace"),window.dispatchEvent(new CustomEvent("location-changed")),window.setTimeout(()=>{history.pushState(null,"",e),window.dispatchEvent(new CustomEvent("location-changed"))},200)}))}function m(){if(s.test(window.location.pathname))return;let r=0,e=Date.now(),o=window.setInterval(()=>{r++;try{if(Date.now()-e<6e3)return;if(s.test(window.location.pathname)){window.clearInterval(o);return}T()?A():window.clearInterval(o),r>=30&&window.clearInterval(o)}catch{window.clearInterval(o)}},500)}try{document.readyState==="lLine truncated
|
||||
+300
@@ -0,0 +1,300 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{e as b}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DPJSGXJS.js";import{d as h}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-2BQZ33DM.js";import{a as x,b as w,c as $}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-QVOLUT24.js";import{a as m}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-3LDXEWBF.js";import{I as y,a as l,b as u,c as n,f as p,h as g,m as v,n as d,t as i,v as f}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";var j=3,o=class extends g{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._adopting=!1;this._error="";this._sensors=[];this._selected=new Set;this._objectNames={};this._objects=[];this._covered={};this._users=[];this._responsible="";this._forMinutes="0";this._summaryOpen=!0;this._localeReady=!1;this._userService=null;this._toggle=e=>{let s=new Set(this._selected);s.has(e)?s.delete(e):s.add(e),this._selected=s};this._toggleAll=()=>{this._selected.size===this._sensors.length?this._selected=new Set:this._selected=new Set(this._sensors.map(e=>e.entity_id))};this._adopt=async()=>{if(this._selected.size===0||this._adopting)return;this._error="";let e=this._sensors.filter(t=>this._selected.has(t.entity_id)).map(t=>({entity_id:t.entity_id,name:t.name,entry_id:this._existingEntryFor(t)??void 0,object_name:this._effectiveName(t),device_id:t.device_id??void 0,part_id:t.suggested_part_id??void 0,responsible_user_id:this._responsible||void 0,for_minutes:parseInt(this._forMinutes,10)>0?parseInt(this._forMinutes,10):void 0})),s=await m(this,{type:"maintenance_supporter/problem_sensors/adopt",selections:e},{busy:t=>{this._adopting=t},onError:t=>{this._error=t}});s!==void 0&&(this.dispatchEvent(new CustomEvent("problem-sensors-adopted",{bubbles:!0,composed:!0,detail:s})),this._open=!1)}}get _lang(){return y(this.hass)}updated(e){e.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,f(this._lang).then(()=>this.requestUpdate())),e.has("_open")&&this._open&&$(this.shadowRoot)}async open(){this._open=!0,this._loading=!0,this._error="",this._sensors=[],this._selected=new Set,this._objectNames={},this._responsible="",this._forMinutes="0",this._userService?this._userService.updateHass(this.hass):this._userService=new b(this.hass);let[e,s,t]=await Promise.all([m(this,{type:"maintenance_supporter/problem_sensors/discover"},{onError:r=>{this._error=r}}),this._userService.getUsers().catch(()=>[]),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}).catch(()=>({objects:[]}))]);this._loading=!1,e!==void 0&&(this._objects=(t?.objects||[]).filter(r=>!r.object.archived_at).map(r=>({entry_id:r.entry_id,name:r.object.name,tasks:(r.tasks||[]).length})),this._sensors=e?.sensors||[],this._covered=Object.fromEntries(this._sensors.map(r=>[r.entity_id,r.covered_by??null])),this._selected=new Set(this._sensors.filter(r=>!r.covered_by).map(r=>r.entity_id)),this._users=s,this._summaryOpen=this._summaryGroups().length<=j)}_defaultName(e){return e.suggested_entry_id?e.suggested_object_name:e.candidate?.name??e.suggested_object_name}_effectiveName(e){return(this._objectNames[e.entity_id]??"").trim()||this._defaultName(e)}_existingEntryFor(e){let s=this._effectiveName(e),t=e.suggested_entry_id||e.target_entry_id||null;if(s===this._defaultName(e)&&t)return t;let r=this._objects.find(a=>a.name.trim().toLowerCase()===s.toLowerCase());return r?r.entry_id:null}_schedulePreview(){clearTimeout(this._previewTimer),this._previewTimer=setTimeout(()=>{this._preview()},350)}async _preview(){let e=this._sensors.map(t=>({entity_id:t.entity_id,name:t.name,entry_id:this._existingEntryFor(t)})),s=await m(this,{type:"maintenance_supporter/problem_sensors/preview",selections:e},{onError:()=>{}});s?.covered&&(this._covered={...this._covered,...s.covered})}_summaryGroups(){let e=new Map;for(let s of this._sensors){if(!this._selected.has(s.entity_id))continue;let t=this._existingEntryFor(s),r=this._effectiveName(s),a=t??`new:${r.toLowerCase()}`,c=e.get(a)??{name:r,entry:t,adding:0};c.adding+=1,e.set(a,c)}return[...e.values()]}_summary(e){let s=this._summaryGroups();if(s.length===0)return p;let t=s.filter(a=>!a.entry).length,r=i(t?"adopt_summary_totals_new":"adopt_summary_totals",e).replace("{tasks}",String(s.reduce((a,c)=>a+c.adding,0))).replace("{objects}",String(s.length)).replace("{new}",String(t));return n`
|
||||
<details
|
||||
class="summary"
|
||||
.open=${this._summaryOpen}
|
||||
@toggle=${a=>{this._summaryOpen=a.target.open}}
|
||||
>
|
||||
<summary>
|
||||
<span class="summary-title">${i("adopt_summary_title",e)}</span>
|
||||
<span class="summary-totals">${r}</span>
|
||||
</summary>
|
||||
${s.map(a=>{if(!a.entry)return n`<div class="summary-line new">
|
||||
${i("setups_new_object_count",e).replace("{name}",a.name).replace("{count}",String(a.adding))}
|
||||
</div>`;let c=this._objects.find(_=>_.entry_id===a.entry)?.tasks??0;return n`<div class="summary-line">
|
||||
${i("adopt_summary_existing",e).replace("{name}",a.name).replace("{before}",String(c)).replace("{after}",String(c+a.adding))}
|
||||
</div>`})}
|
||||
</details>
|
||||
`}_close(){clearTimeout(this._previewTimer),this._open=!1}_targetLabel(e,s){if(e.candidate&&this._existingEntryFor(e)===e.candidate.entry_id){let t=e.candidate.reasons.map(r=>i(`setups_reason_${r}`,s)).join(", ");return i("setups_target_match",s).replace("{name}",e.candidate.name).replace("{reasons}",t)}return this._effectiveName(e)}render(){if(!this._open)return n``;let e=this._lang,s=this._sensors.length>0&&this._selected.size===this._sensors.length;return w(()=>this._close(),n`
|
||||
<div class="title">${i("adopt_problem_title",e)}</div>
|
||||
${this._error?n`<div class="error">${this._error}</div>`:p}
|
||||
|
||||
<div class="dialog-scroll">
|
||||
<div class="hint">${i("adopt_problem_hint",e)}</div>
|
||||
${this._loading?n`<div class="loading">…</div>`:this._sensors.length===0?n`<div class="empty">${i("adopt_problem_none",e)}</div>`:n`
|
||||
<label class="select-all">
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${s}
|
||||
@change=${this._toggleAll}
|
||||
/>
|
||||
<span>${i("selected",e)}: ${this._selected.size} / ${this._sensors.length}</span>
|
||||
</label>
|
||||
<div class="row-sub adopt-object-hint">${i("adopt_object_hint",e)}</div>
|
||||
<datalist id="adopt-object-names">
|
||||
${this._objects.map(t=>n`<option value=${t.name}></option>`)}
|
||||
</datalist>
|
||||
<div class="list">
|
||||
${this._sensors.map(t=>{let r=this._selected.has(t.entity_id),a=t.state==="on",c=[t.device_name,t.area_name].filter(Boolean).join(" \xB7 ");return n`
|
||||
<label class="row">
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${r}
|
||||
@change=${()=>this._toggle(t.entity_id)}
|
||||
/>
|
||||
<div class="row-main">
|
||||
<div class="row-top">
|
||||
<span class="row-name">${t.name}</span>
|
||||
<span class="chip ${a?"chip-active":"chip-ok"}">
|
||||
${a?i("adopt_problem_active",e):i("adopt_problem_ok",e)}
|
||||
</span>
|
||||
</div>
|
||||
${c?n`<div class="row-sub">${c}</div>`:p}
|
||||
${r?n`<div class="row-object" @click=${_=>_.stopPropagation()}>
|
||||
<input
|
||||
class="adopt-object"
|
||||
list="adopt-object-names"
|
||||
aria-label=${i("object",e)}
|
||||
placeholder=${this._defaultName(t)}
|
||||
.value=${this._objectNames[t.entity_id]??this._defaultName(t)}
|
||||
@input=${_=>{this._objectNames={...this._objectNames,[t.entity_id]:_.target.value},this._schedulePreview()}}
|
||||
/>
|
||||
</div>`:p}
|
||||
<div class="row-target">
|
||||
→ ${this._targetLabel(t,e)}${this._existingEntryFor(t)?p:n` <span class="new-tag">${i("adopt_problem_new_object",e)}</span>`}
|
||||
</div>
|
||||
${this._covered[t.entity_id]?n`<div class="maybe">
|
||||
${i("setups_maybe_covered",e).replace("{name}",this._covered[t.entity_id].name)}
|
||||
</div>`:p}
|
||||
${t.suggested_part_name?n`<div class="row-part">
|
||||
<ha-icon icon="mdi:package-variant-closed"></ha-icon>
|
||||
${i("adopt_problem_part",e).replace("{name}",t.suggested_part_name)}
|
||||
</div>`:p}
|
||||
</div>
|
||||
</label>
|
||||
`})}
|
||||
</div>
|
||||
`}
|
||||
|
||||
${!this._loading&&this._sensors.length>0?this._summary(e):p}
|
||||
|
||||
${!this._loading&&this._sensors.length>0?n`
|
||||
<label class="responsible">
|
||||
<span>${i("for_at_least_minutes",e)}</span>
|
||||
<input
|
||||
class="for-input"
|
||||
type="number"
|
||||
min=${h[0]}
|
||||
max=${h[1]}
|
||||
.value=${this._forMinutes}
|
||||
@input=${t=>this._forMinutes=t.target.value}
|
||||
/>
|
||||
</label>
|
||||
<div class="for-hint">${i("adopt_for_minutes_hint",e)}</div>
|
||||
`:p}
|
||||
|
||||
${!this._loading&&this._sensors.length>0&&this._users.length>0?n`
|
||||
<label class="responsible">
|
||||
<span>${i("adopt_problem_responsible",e)}</span>
|
||||
<select
|
||||
.value=${this._responsible}
|
||||
@change=${t=>{this._responsible=t.target.value}}
|
||||
>
|
||||
<option value="" ?selected=${!this._responsible}>${i("no_user_assigned",e)}</option>
|
||||
${this._users.map(t=>n`<option value=${t.id} ?selected=${t.id===this._responsible}>${t.name}</option>`)}
|
||||
</select>
|
||||
</label>
|
||||
`:p}
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${i("cancel",e)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._adopt}
|
||||
.disabled=${this._selected.size===0||this._adopting}
|
||||
>
|
||||
${i("adopt_problem_adopt",e)}
|
||||
</ha-button>
|
||||
</div>
|
||||
`)}};o.styles=[x,u`
|
||||
:host {
|
||||
--ms-modal-max-width: 560px;
|
||||
--ms-modal-max-height: 90dvh;
|
||||
--ms-modal-gap: 12px;
|
||||
--ms-modal-z: 1000;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
/* Stays at the top of the scrolling middle: the count while ticking.
|
||||
top: -1px + 1px more padding: on a 3x screen a fractional offset let a
|
||||
line of the text scrolled under it show above it. */
|
||||
.select-all {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
cursor: pointer;
|
||||
position: sticky;
|
||||
top: -1px;
|
||||
z-index: 1;
|
||||
padding: 5px 0 4px;
|
||||
background: var(--card-background-color, var(--ha-card-background, #1c1c1c));
|
||||
}
|
||||
.select-all input {
|
||||
cursor: pointer;
|
||||
}
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.row input {
|
||||
margin-top: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.row-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
.row-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.row-name {
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
}
|
||||
.row-sub {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
}
|
||||
.row-object { margin-top: 6px; }
|
||||
.row-object input {
|
||||
width: 100%; box-sizing: border-box; padding: 6px 8px; font: inherit;
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
background: var(--card-background-color); color: var(--primary-text-color);
|
||||
}
|
||||
.adopt-object-hint { margin: 0 0 8px; }
|
||||
.row-target {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
}
|
||||
.row-part {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.row-part ha-icon {
|
||||
--mdc-icon-size: 14px;
|
||||
}
|
||||
.new-tag {
|
||||
font-style: italic;
|
||||
}
|
||||
.maybe {
|
||||
font-size: 11px;
|
||||
color: var(--warning-color, #ff9800);
|
||||
}
|
||||
.summary {
|
||||
font-size: 12px;
|
||||
border-top: 1px dashed var(--divider-color);
|
||||
padding-top: 6px;
|
||||
}
|
||||
.summary > summary {
|
||||
cursor: pointer;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.summary-title {
|
||||
font-weight: 500;
|
||||
}
|
||||
.summary-totals {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.summary-line {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.chip {
|
||||
font-size: 11px;
|
||||
padding: 1px 8px;
|
||||
border-radius: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.chip-active {
|
||||
background: var(--error-color, #f44336);
|
||||
color: #fff;
|
||||
}
|
||||
.chip-ok {
|
||||
background: var(--divider-color);
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.responsible {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.for-input {
|
||||
width: 70px;
|
||||
background: var(--card-background-color);
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 4px;
|
||||
padding: 4px 6px;
|
||||
}
|
||||
.for-hint {
|
||||
font-size: 11px;
|
||||
color: var(--secondary-text-color);
|
||||
margin: -4px 0 2px;
|
||||
}
|
||||
.responsible select {
|
||||
flex: 1;
|
||||
min-width: 140px;
|
||||
padding: 4px 6px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--divider-color);
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
font-size: 13px;
|
||||
}
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
`],l([v({attribute:!1})],o.prototype,"hass",2),l([d()],o.prototype,"_open",2),l([d()],o.prototype,"_loading",2),l([d()],o.prototype,"_adopting",2),l([d()],o.prototype,"_error",2),l([d()],o.prototype,"_sensors",2),l([d()],o.prototype,"_selected",2),l([d()],o.prototype,"_objectNames",2),l([d()],o.prototype,"_objects",2),l([d()],o.prototype,"_covered",2),l([d()],o.prototype,"_users",2),l([d()],o.prototype,"_responsible",2),l([d()],o.prototype,"_forMinutes",2),l([d()],o.prototype,"_summaryOpen",2);customElements.get("maintenance-adopt-problem-sensors-dialog")||customElements.define("maintenance-adopt-problem-sensors-dialog",o);export{o as MaintenanceAdoptProblemSensorsDialog};
|
||||
@@ -0,0 +1,279 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{a as X}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-H44SM3WA.js";import{a as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-274MLN75.js";import{f as E,g as M,h as z,i as Q,j as U,k as Y,l as q,m as G,n as R,o as A,p as W}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-FH35SLMS.js";import{a as B}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-KZ3OKTLK.js";import{e as P,f as K}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DR2AFVDA.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-EOMYEBQ4.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-MMIPM7EE.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-R77C34J4.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-IRRUA3DS.js";import{C as S,I as F,L as g,M as v,P as N,Q as I,V as w,X as T,a as $,c as p,f as y,h as H,m as k,n as j,o as C,r as D,t as a,v as L,z as O}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";function J(b,i,t,s){let l=b.entries.filter(e=>e.type==="completed").sort((e,n)=>e.ts-n.ts),d=`${b.from?t.date(b.from):"\u2026"} \u2013 ${b.to?t.date(b.to):"\u2026"}`,r=b.totals,h=[[i.completions,t.number(r.completions)],[i.totalCost,t.cost(r.totalCost)],[i.avgCost,r.avgCost!=null?t.cost(r.avgCost):i.none],[i.totalTime,r.totalDuration?t.duration(r.totalDuration):i.none]].map(([e,n])=>`<div class="kpi"><div class="k">${o(e)}</div><div class="v">${o(n)}</div></div>`).join(""),u=b.byObject.map(e=>`<tr>
|
||||
<td>${o(e.objectName)}</td>
|
||||
<td class="num">${o(t.number(e.completions))}</td>
|
||||
<td class="num">${o(t.cost(e.cost))}</td>
|
||||
<td class="num">${o(t.share(e.share))}</td>
|
||||
</tr>`).join(""),f=b.buckets.buckets.reduce((e,n)=>Math.max(e,n.cost),0),c=b.buckets.buckets.map(e=>{let n=f>0?Math.round(e.cost/f*100):0;return`<tr>
|
||||
<td class="nowrap">${o(t.bucket(e))}</td>
|
||||
<td class="num">${o(t.number(e.completions))}</td>
|
||||
<td class="bar-cell">${n>0?`<span class="bar" style="width:${n}%"></span>`:""}</td>
|
||||
<td class="num">${o(t.cost(e.cost))}</td>
|
||||
</tr>`}).join(""),m=l.map(e=>{let n=[e.notes,e.completedBy?`${i.completedBy}: ${e.completedBy}`:null].filter(Boolean).join(" \xB7 "),x=e.phaseName?`${e.taskName} \xB7 ${e.phaseName}`:e.taskName;return`<tr>
|
||||
<td class="nowrap">${o(t.date(e.timestamp))}</td>
|
||||
<td>${o(e.objectName)}</td>
|
||||
<td>${o(x)}</td>
|
||||
<td class="num">${e.cost!=null?o(t.cost(e.cost)):o(i.none)}</td>
|
||||
<td class="num">${e.duration!=null?o(t.duration(e.duration)):o(i.none)}</td>
|
||||
<td class="notes">${o(n)||o(i.none)}</td>
|
||||
</tr>`}).join(`
|
||||
`);return`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="color-scheme" content="light">
|
||||
<title>${o(i.title)} \u2014 ${o(b.areaName)}</title>
|
||||
<style>
|
||||
/* Printable sheet: it opens as a blob in whatever viewer the OS supplies
|
||||
(Companion = WebView, dark phones paint a dark default canvas), so the
|
||||
document states its own light scheme and paints its background. */
|
||||
:root { color-scheme: light; }
|
||||
* { box-sizing: border-box; }
|
||||
body { font: 13px/1.5 -apple-system, Segoe UI, Roboto, sans-serif; color: #1a1a1a; background: #fff; margin: 32px; }
|
||||
h1 { font-size: 22px; margin: 0 0 2px; }
|
||||
h2 { font-size: 15px; margin: 24px 0 8px; }
|
||||
.sub { color: #666; margin: 0 0 16px; }
|
||||
.kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin: 0 0 8px; }
|
||||
.kpi { border: 1px solid #ddd; border-radius: 6px; padding: 8px 10px; }
|
||||
.kpi .k { color: #777; font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; }
|
||||
.kpi .v { font-size: 16px; font-weight: 600; }
|
||||
table { border-collapse: collapse; width: 100%; }
|
||||
th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: #666; border-bottom: 2px solid #ccc; padding: 6px 8px; }
|
||||
td { border-bottom: 1px solid #e5e5e5; padding: 6px 8px; vertical-align: top; }
|
||||
td.num, th.num { text-align: right; white-space: nowrap; }
|
||||
td.nowrap { white-space: nowrap; }
|
||||
td.notes { color: #444; white-space: pre-wrap; }
|
||||
td.bar-cell { width: 40%; vertical-align: middle; }
|
||||
.bar { display: block; height: 10px; background: #9aa7b8; border-radius: 0 3px 3px 0;
|
||||
-webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
||||
tfoot td { border-bottom: none; border-top: 2px solid #ccc; font-weight: 600; }
|
||||
tr { break-inside: avoid; }
|
||||
.cap-note { margin-top: 14px; color: #888; font-size: 11px; }
|
||||
@media print { body { margin: 12mm; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>${o(i.title)} \u2014 ${o(b.areaName)}</h1>
|
||||
<p class="sub">${o(i.period)}: ${o(d)} \xB7 ${o(i.generated)} ${o(t.date(s))}</p>
|
||||
<div class="kpis">${h}</div>
|
||||
|
||||
<h2>${o(i.costPerObject)}</h2>
|
||||
<table>
|
||||
<thead><tr>
|
||||
<th>${o(i.colObject)}</th><th class="num">${o(i.completions)}</th>
|
||||
<th class="num">${o(i.colCost)}</th><th class="num">${o(i.share)}</th>
|
||||
</tr></thead>
|
||||
<tbody>${u||`<tr><td colspan="4">${o(i.none)}</td></tr>`}</tbody>
|
||||
<tfoot><tr>
|
||||
<td>${o(i.totalCost)}</td><td class="num">${o(t.number(r.completions))}</td>
|
||||
<td class="num">${o(t.cost(r.totalCost))}</td><td></td>
|
||||
</tr></tfoot>
|
||||
</table>
|
||||
|
||||
<h2>${o(i.costPerBucket)}</h2>
|
||||
<table>
|
||||
<thead><tr>
|
||||
<th>${o(i.period)}</th><th class="num">${o(i.completions)}</th>
|
||||
<th></th><th class="num">${o(i.colCost)}</th>
|
||||
</tr></thead>
|
||||
<tbody>${c||`<tr><td colspan="4">${o(i.none)}</td></tr>`}</tbody>
|
||||
</table>
|
||||
|
||||
<h2>${o(i.historyHeading)} (${o(t.number(l.length))})</h2>
|
||||
<table>
|
||||
<thead><tr>
|
||||
<th>${o(i.colDate)}</th><th>${o(i.colObject)}</th><th>${o(i.colTask)}</th>
|
||||
<th class="num">${o(i.colCost)}</th><th class="num">${o(i.colDuration)}</th><th>${o(i.colNotes)}</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
${m||`<tr><td colspan="6">${o(i.none)}</td></tr>`}
|
||||
</tbody>
|
||||
<tfoot><tr>
|
||||
<td colspan="3">${o(i.totalCost)}</td>
|
||||
<td class="num">${o(t.cost(r.totalCost))}</td>
|
||||
<td class="num">${r.totalDuration?o(t.duration(r.totalDuration)):""}</td><td></td>
|
||||
</tr></tfoot>
|
||||
</table>
|
||||
${b.capped?`<p class="cap-note">${o(i.capNote)}</p>`:""}
|
||||
</body>
|
||||
</html>`}var Z=25,V=5,tt={completed:C.ok,missed:C.overdue,reset:C.paused,skipped:"var(--secondary-text-color)"},_=class extends H{constructor(){super(...arguments);this.areaKey="";this.objects=[];this.showArchived=!1;this.currencySymbol="";this.userName=()=>null;this._from="";this._to="";this._entryFilter="";this._taskQuery="";this._expanded=!1;this._printing=!1;this._histories=new X(this);this._localeReady=!1;this._filtersFor=null;this._memo=null}createRenderRoot(){return this}get _lang(){return F(this.hass)}willUpdate(t){if(super.willUpdate(t),t.has("areaKey")&&this._filtersFor!==this.areaKey){this._filtersFor=this.areaKey;let s=R();this._from=s.from,this._to=s.to,this._entryFilter="",this._taskQuery="",this._expanded=!1}if(t.has("objects")||t.has("areaKey")||t.has("showArchived")||t.has("hass")&&t.get("hass")===void 0){let s=this._areaObjects().flatMap(l=>l.tasks.map(d=>({entryId:l.entry_id,task:d})));this._histories.sync(this.hass,s)}}updated(t){super.updated(t),!this._localeReady&&this.hass&&(this._localeReady=!0,L(this._lang).then(()=>this.requestUpdate()))}_areaObjects(){return z(this.objects,this.areaKey,this.showArchived).sort((t,s)=>t.object.name.localeCompare(s.object.name))}_entries(t){let s=[this.objects,this.areaKey,this.showArchived,this._histories.version];if(this._memo&&this._memo.deps.every((d,r)=>d===s[r]))return this._memo.entries;let l=Q(t,(d,r)=>this._histories.historyOf(d,r));return this._memo={deps:s,entries:l},l}_figures(){let t=this._areaObjects(),s=this._entries(t),l={from:this._from||null,to:this._to||null},d=U(s,{...l,entryId:this._entryFilter||null,taskQuery:this._taskQuery}),r=this._entryFilter?t.filter(h=>h.entry_id===this._entryFilter):t;return{objects:t,entries:s,filtered:d,totals:Y(d),buckets:G(d,l),byObject:q(d,r)}}_setRange(t){this._from=t.from,this._to=t.to,this._expanded=!1}_openObject(t){this.dispatchEvent(new CustomEvent("open-object",{detail:{entryId:t},bubbles:!0,composed:!0}))}_openTask(t,s){this.dispatchEvent(new CustomEvent("open-task",{detail:{entryId:t,taskId:s},bubbles:!0,composed:!0}))}_bucketLabel(t,s){return t.month==null?String(t.year):`${T(t.month,this._lang,s)} ${t.year}`}_countText(t,s,l){let d=this._lang;return l===1?a(s,d):a(t,d).replace("{n}",g(l,d))}async _print(){if(this._printing)return;let t=K();this._printing=!0;try{await this._histories.settled()}finally{this._printing=!1}let s=this._lang,l=this.currencySymbol,{filtered:d,totals:r,buckets:h,byObject:u}=this._figures(),f={title:a("area_report_title",s),generated:a("report_generated",s),period:a("area_report_period",s),completions:a("area_kpi_completions",s),totalCost:a("total_cost",s),avgCost:a("avg_cost",s),totalTime:a("area_kpi_total_time",s),costPerObject:a("area_cost_per_object",s),costPerBucket:h.unit==="month"?a("area_cost_per_month",s):a("area_cost_per_year",s),share:a("area_cost_share",s),historyHeading:a("area_history_section",s),colDate:a("date",s),colObject:a("object",s),colTask:a("task_name",s),colCost:a("cost",s),colDuration:a("duration",s),colNotes:a("notes_label",s),completedBy:a("completed_by",s),capNote:a("object_history_cap_note",s),none:"\u2014"},c=d.filter(n=>n.type==="completed"),m=d.map(n=>({...n,completedBy:n.completedBy?this.userName(n.completedBy):null,notes:n.notes?B(n.notes,s):null})),e=J({areaName:E(this.areaKey,this.hass?.areas,a("no_area",s)),from:this._from||S(c[c.length-1]?.timestamp)||null,to:this._to||O(),totals:r,byObject:u,buckets:h,entries:m,capped:this._histories.capped},f,{date:n=>N(n,s),cost:n=>v(n,l,s),duration:n=>w(n,s),bucket:n=>this._bucketLabel(n,"long"),share:n=>`${g(n*100,s,0)} %`,number:n=>g(n,s)},new Date().toISOString());P(e,t)}_renderRangeChips(t){let s=this._lang,l=O(),d=R(l),r=u=>this._from===u.from&&this._to===u.to,h=W(t,Number(l.slice(0,4))).slice(0,V);return p`
|
||||
<div class="filter-chips area-range-chips">
|
||||
<button class="filter-chip ${r(d)?"active":""}" @click=${()=>this._setRange(R())}>
|
||||
${a("area_range_12m",s)}
|
||||
</button>
|
||||
${h.map(u=>p`
|
||||
<button class="filter-chip ${r(A(u))?"active":""}" @click=${()=>this._setRange(A(u))}>${u}</button>
|
||||
`)}
|
||||
<button class="filter-chip ${!this._from&&!this._to?"active":""}" @click=${()=>this._setRange({from:"",to:""})}>
|
||||
${a("area_range_all",s)}
|
||||
</button>
|
||||
</div>
|
||||
`}_renderChart(t){let s=this._lang,l=this.currencySymbol,d=t.reduce((c,m)=>Math.max(c,m.cost),0),r=t.reduce((c,m)=>Math.min(c,m.cost),0);if(d<=0&&r>=0)return p`<p class="area-empty">${a("area_no_costs",s)}</p>`;let h=c=>Math.round(c/(d-r)*1e3)/10,u=Math.max(1,Math.ceil(t.length/12)),f=t.map((c,m)=>({b:c,i:m})).filter(({i:c})=>c%u===0);return p`
|
||||
<div class="area-chart">
|
||||
<div class="area-chart-max">${v(d,l,s)}</div>
|
||||
<div class="area-chart-bars">
|
||||
${r<0?p`<div class="area-chart-zero" style="bottom: ${h(-r)}%"></div>`:y}
|
||||
${t.map(c=>{let m=`${this._bucketLabel(c,"long")}: ${v(c.cost,l,s)} \xB7 ${a("area_kpi_completions",s)}: ${g(c.completions,s)}`,e=c.cost<0?h(c.cost-r):h(-r);return p`<div class="area-bar" title=${m} aria-label=${m}>
|
||||
${c.cost!==0?p`<div class="area-bar-fill ${c.cost<0?"credit":""}" style="height: ${h(Math.abs(c.cost))}%${e?`; bottom: ${e}%`:""}"></div>`:y}
|
||||
</div>`})}
|
||||
</div>
|
||||
${r<0?p`<div class="area-chart-min">${v(r,l,s)}</div>`:y}
|
||||
<div class="area-chart-axis ${u>1?"grouped":""}">
|
||||
${f.map(({b:c,i:m})=>p`<span class="area-bar-label" style="flex-grow: ${Math.min(u,t.length-m)}">${c.month==null?String(c.year):p`${T(c.month,s,"short")}${c.month===0||m===0?p`<br />${c.year}`:y}`}</span>`)}
|
||||
</div>
|
||||
</div>
|
||||
`}render(){if(!this.hass||!this.areaKey)return y;let t=this._lang,s=this.currencySymbol,{objects:l,entries:d,filtered:r,totals:h,buckets:u,byObject:f}=this._figures(),c=l.reduce((e,n)=>e+n.tasks.filter(x=>this.showArchived||!x.archived).length,0),m=this._expanded?r:r.slice(0,Z);return p`
|
||||
<div class="detail-section area-view">
|
||||
<div class="detail-header">
|
||||
<h2 class="area-title">
|
||||
<ha-icon .icon=${M(this.areaKey,this.hass.areas)}></ha-icon>
|
||||
${E(this.areaKey,this.hass.areas,a("no_area",t))}
|
||||
</h2>
|
||||
<div class="action-buttons">
|
||||
<ha-button appearance="plain" class="area-print" .disabled=${this._printing} @click=${()=>this._print()}>
|
||||
<ha-icon icon="mdi:printer-outline"></ha-icon>
|
||||
${this._printing?a("loading",t):a("area_report_print",t)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="meta">
|
||||
${this._countText("area_object_count","area_object_count_one",l.length)} ·
|
||||
${this._countText("templates_task_count","templates_task_count_one",c)}
|
||||
${this._histories.loading?p` · <span class="area-loading">${a("loading",t)}</span>`:y}
|
||||
</p>
|
||||
|
||||
${this._renderRangeChips(d)}
|
||||
<div class="filter-bar area-filters">
|
||||
<ms-date-field
|
||||
kind="date"
|
||||
clearable
|
||||
.hass=${this.hass}
|
||||
.lang=${t}
|
||||
.label=${a("date_from",t)}
|
||||
.value=${this._from}
|
||||
@value-changed=${e=>{this._from=e.detail.value}}
|
||||
></ms-date-field>
|
||||
<ms-date-field
|
||||
kind="date"
|
||||
clearable
|
||||
.hass=${this.hass}
|
||||
.lang=${t}
|
||||
.label=${a("date_to",t)}
|
||||
.value=${this._to}
|
||||
@value-changed=${e=>{this._to=e.detail.value}}
|
||||
></ms-date-field>
|
||||
<label class="filter-field">
|
||||
<span class="filter-label">${a("object",t)}</span>
|
||||
<select class="area-object-filter" .value=${this._entryFilter}
|
||||
@change=${e=>{this._entryFilter=e.target.value}}>
|
||||
<option value="" ?selected=${!this._entryFilter}>${a("all_objects",t)}</option>
|
||||
${l.map(e=>p`<option value=${e.entry_id} ?selected=${e.entry_id===this._entryFilter}>${e.object.name}</option>`)}
|
||||
</select>
|
||||
</label>
|
||||
<input
|
||||
type="search"
|
||||
class="search-input area-task-filter"
|
||||
aria-label=${a("area_task_filter",t)}
|
||||
placeholder=${a("area_task_filter",t)}
|
||||
.value=${this._taskQuery}
|
||||
@input=${e=>{this._taskQuery=e.target.value}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="kpi-bar area-kpis">
|
||||
<div class="kpi-card">
|
||||
<div class="kpi-label">${a("area_kpi_completions",t)}</div>
|
||||
<div class="kpi-value-large area-kpi-completions">${g(h.completions,t)}</div>
|
||||
</div>
|
||||
<div class="kpi-card">
|
||||
<div class="kpi-label">${a("total_cost",t)}</div>
|
||||
<div class="kpi-value-large area-kpi-cost">${v(h.totalCost,s,t)}</div>
|
||||
</div>
|
||||
<div class="kpi-card">
|
||||
<div class="kpi-label">${a("avg_cost",t)}</div>
|
||||
<div class="kpi-value-large">${h.avgCost!=null?v(h.avgCost,s,t):"\u2014"}</div>
|
||||
</div>
|
||||
<div class="kpi-card">
|
||||
<div class="kpi-label">${a("area_kpi_total_time",t)}</div>
|
||||
<div class="kpi-value-large">${h.totalDuration?w(h.totalDuration,t):"\u2014"}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>${u.unit==="month"?a("area_cost_per_month",t):a("area_cost_per_year",t)}</h3>
|
||||
${this._renderChart(u.buckets)}
|
||||
|
||||
<h3>${a("area_cost_per_object",t)}</h3>
|
||||
<div class="objects-table-wrap">
|
||||
<table class="objects-table area-object-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>${a("object",t)}</th>
|
||||
<th class="num">${a("area_kpi_completions",t)}</th>
|
||||
<th class="num">${a("cost",t)}</th>
|
||||
<th class="num">${a("area_cost_share",t)}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${f.map(e=>p`
|
||||
<tr class="objects-table-row" @click=${()=>this._openObject(e.entryId)}>
|
||||
<td><span class="objects-table-name">${e.objectName}</span></td>
|
||||
<td class="num">${g(e.completions,t)}</td>
|
||||
<td class="num">${v(e.cost,s,t)}</td>
|
||||
<td class="num">
|
||||
<span class="area-share"><span class="area-share-fill" style="width: ${Math.round(e.share*100)}%"></span></span>
|
||||
${g(e.share*100,t,0)} %
|
||||
</td>
|
||||
</tr>
|
||||
`)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>
|
||||
${a("area_history_section",t)}
|
||||
<span class="area-count">${g(r.length,t)}</span>
|
||||
</h3>
|
||||
${r.length===0?p`<p class="area-empty">${a("object_history_empty",t)}</p>`:p`
|
||||
<div class="objects-table-wrap">
|
||||
<table class="objects-table area-history-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>${a("date",t)}</th>
|
||||
<th></th>
|
||||
<th>${a("object",t)}</th>
|
||||
<th>${a("task_name",t)}</th>
|
||||
<th class="num">${a("cost",t)}</th>
|
||||
<th class="num">${a("duration",t)}</th>
|
||||
<th>${a("notes_label",t)}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${m.map(e=>{let n=e.notes?B(e.notes,t):"";return p`
|
||||
<tr class="objects-table-row area-history-row" @click=${()=>this._openTask(e.entryId,e.taskId)}>
|
||||
<td title=${I(e.timestamp,t)}>${N(e.timestamp,t)}</td>
|
||||
<td>
|
||||
<span class="area-entry-type" style="color: ${tt[e.type]??"inherit"}">
|
||||
<ha-icon .icon=${D[e.type]||"mdi:circle"}></ha-icon>${a(e.type,t)}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="area-object-link" @click=${x=>{x.stopPropagation(),this._openObject(e.entryId)}}>
|
||||
${e.objectName}
|
||||
</button>
|
||||
</td>
|
||||
<td><button class="area-task-link">${e.taskName}${e.phaseName?` \xB7 ${e.phaseName}`:""}</button></td>
|
||||
<td class="num">${e.cost!=null?v(e.cost,s,t):"\u2014"}</td>
|
||||
<td class="num">${e.duration!=null?w(e.duration,t):"\u2014"}</td>
|
||||
<td class="oc-notes" title=${n}>${n||"\u2014"}</td>
|
||||
</tr>
|
||||
`})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
${r.length>m.length?p`<ha-button appearance="plain" class="area-more" @click=${()=>{this._expanded=!0}}>
|
||||
${a("show_all",t)} (${g(r.length,t)})
|
||||
</ha-button>`:y}
|
||||
`}
|
||||
${this._histories.capped?p`<p class="area-cap-note">${a("object_history_cap_note",t)}</p>`:y}
|
||||
</div>
|
||||
`}};$([k({attribute:!1})],_.prototype,"hass",2),$([k()],_.prototype,"areaKey",2),$([k({attribute:!1})],_.prototype,"objects",2),$([k({type:Boolean})],_.prototype,"showArchived",2),$([k()],_.prototype,"currencySymbol",2),$([k({attribute:!1})],_.prototype,"userName",2),$([j()],_.prototype,"_from",2),$([j()],_.prototype,"_to",2),$([j()],_.prototype,"_entryFilter",2),$([j()],_.prototype,"_taskQuery",2),$([j()],_.prototype,"_expanded",2),$([j()],_.prototype,"_printing",2);customElements.get("maintenance-area-view")||customElements.define("maintenance-area-view",_);export{_ as MaintenanceAreaView};
|
||||
@@ -0,0 +1,54 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{a as O}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-H44SM3WA.js";import{q as j,r as E,s as L,t as R,u as C}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-FH35SLMS.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-EOMYEBQ4.js";import{a as _,b as S,c as A}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-VZUMUVFP.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-MMIPM7EE.js";import{I as g,L as k,M as v,P as w,a as l,c as a,f as m,h as y,m as p,n as b,t as r,v as $,z as f}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";var q=[{key:"name",label:"area",num:!1},{key:"objects",label:"objects",num:!0},{key:"tasks",label:"tasks",num:!0},{key:"overdue",label:"overdue",num:!0},{key:"due_soon",label:"due_soon",num:!0},{key:"cost_year",label:"area_cost_year",num:!0},{key:"cost_total",label:"total_cost",num:!0},{key:"last",label:"last_performed",num:!1}],i=class extends y{constructor(){super(...arguments);this.objects=[];this.showArchived=!1;this.currencySymbol="";this._query="";this._sort=E(S(_.areaSort));this._histories=new O(this);this._localeReady=!1;this._memo=null}createRenderRoot(){return this}get _lang(){return g(this.hass)}willUpdate(t){if(super.willUpdate(t),t.has("objects")||t.has("showArchived")||t.has("hass")&&t.get("hass")===void 0){let o=this.objects.filter(s=>this.showArchived||!s.object.archived).flatMap(s=>s.tasks.map(n=>({entryId:s.entry_id,task:n})));this._histories.sync(this.hass,o)}}updated(t){super.updated(t),!this._localeReady&&this.hass&&(this._localeReady=!0,$(this._lang).then(()=>this.requestUpdate()))}_rows(t){let o=this._lang,s=[this.objects,this.showArchived,this._histories.version,this.hass?.areas,o,t];if(this._memo&&this._memo.deps.every((c,h)=>c===s[h]))return this._memo.rows;let n=j(this.objects,{showArchived:this.showArchived,areas:this.hass?.areas,noAreaLabel:r("no_area",o),year:t,historyOf:(c,h)=>this._histories.historyOf(c,h)});return this._memo={deps:s,rows:n},n}_setSort(t){this._sort=L(this._sort,t),A(_.areaSort,`${this._sort.key}:${this._sort.dir}`)}_open(t){this.dispatchEvent(new CustomEvent("open-area",{detail:{areaKey:t},bubbles:!0,composed:!0}))}_toggleArchived(){this.dispatchEvent(new CustomEvent("archived-toggle",{bubbles:!0,composed:!0}))}_headerLabel(t,o,s){return t==="area_cost_year"?r("area_cost_year",s).replace("{year}",String(o)):r(t,s)}render(){if(!this.hass)return m;let t=this._lang,o=Number(f().slice(0,4)),s=this.currencySymbol,n=this._rows(o),c=R(C(n,this._query),this._sort),h=this.objects.filter(e=>e.object.archived).length,d=e=>k(e,t);return a`
|
||||
<div class="filter-bar area-filter-bar">
|
||||
<input
|
||||
type="search"
|
||||
class="search-input"
|
||||
aria-label=${r("areas_filter",t)}
|
||||
placeholder=${r("areas_filter",t)}
|
||||
.value=${this._query}
|
||||
@input=${e=>{this._query=e.target.value}}
|
||||
/>
|
||||
${this._histories.loading?a`<span class="area-loading">${r("loading",t)}</span>`:m}
|
||||
${h>0?a`<ha-button class="archived-toggle ${this.showArchived?"active":""}" @click=${()=>this._toggleArchived()}>
|
||||
<ha-icon icon="mdi:archive-outline"></ha-icon>
|
||||
${this.showArchived?r("hide_archived",t):`${r("show_archived",t)} (${h})`}
|
||||
</ha-button>`:m}
|
||||
</div>
|
||||
${n.length===0?a`<div class="empty-state">${r("no_objects",t)}</div>`:c.length===0?a`<div class="empty-state">${r("areas_filter_none",t)}</div>`:a`
|
||||
<div class="objects-table-wrap">
|
||||
<table class="objects-table areas-table">
|
||||
<thead>
|
||||
<tr>
|
||||
${q.map(e=>{let u=this._sort.key===e.key;return a`<th class=${e.num?"num":""}
|
||||
aria-sort=${u?this._sort.dir==="asc"?"ascending":"descending":"none"}>
|
||||
<button class="area-sort ${u?"active":""}" title=${r("sort_label",t)} @click=${()=>this._setSort(e.key)}>
|
||||
${this._headerLabel(e.label,o,t)}
|
||||
${u?a`<ha-icon icon=${this._sort.dir==="asc"?"mdi:arrow-up":"mdi:arrow-down"}></ha-icon>`:m}
|
||||
</button>
|
||||
</th>`})}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${c.map(e=>a`
|
||||
<tr class="objects-table-row" tabindex="0"
|
||||
@click=${()=>this._open(e.key)}
|
||||
@keydown=${u=>{u.key==="Enter"&&this._open(e.key)}}>
|
||||
<td>
|
||||
<ha-icon class="area-row-icon" .icon=${e.icon}></ha-icon>
|
||||
<span class="objects-table-name">${e.name}</span>
|
||||
</td>
|
||||
<td class="num">${d(e.objects)}</td>
|
||||
<td class="num">${d(e.tasks)}</td>
|
||||
<td class="num">${e.overdue?a`<span class="area-count overdue">${d(e.overdue)}</span>`:d(0)}</td>
|
||||
<td class="num">${e.dueSoon?a`<span class="area-count due-soon">${d(e.dueSoon)}</span>`:d(0)}</td>
|
||||
<td class="num">${v(e.costYear,s,t)}</td>
|
||||
<td class="num">${v(e.costTotal,s,t)}</td>
|
||||
<td>${e.lastCompletion?w(e.lastCompletion,t):"\u2014"}</td>
|
||||
</tr>
|
||||
`)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`}
|
||||
`}};l([p({attribute:!1})],i.prototype,"hass",2),l([p({attribute:!1})],i.prototype,"objects",2),l([p({type:Boolean})],i.prototype,"showArchived",2),l([p()],i.prototype,"currencySymbol",2),l([b()],i.prototype,"_query",2),l([b()],i.prototype,"_sort",2);customElements.get("maintenance-areas-view")||customElements.define("maintenance-areas-view",i);export{i as MaintenanceAreasView};
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import"/maintenance_supporter_panelfiles/panel-chunks/chunk-5TWB2KD3.js";import{I as u,a as n,b as _,c as o,f as p,h as c,m as g,n as a,t as s}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";var d=["round_robin","least_completed","random"],v=["low","normal","high"],m=365,i=class extends c{constructor(){super(...arguments);this._open=!1;this._mode="assign";this._count=0;this._users=[];this._present=[];this._assignKind="one";this._person="";this._pool=new Set;this._rotation=d[0];this._addText="";this._remove=new Set;this._setWarning=!1;this._warning=7;this._setPriority=!1;this._priority="normal";this._setMute=!1;this._mute=!1;this._resolve=null}get _lang(){return u(this.hass)}open(t,e,r){return this._resolve?.(null),this._mode=t,this._count=e.length,this._users=[...r].sort((l,h)=>l.name.localeCompare(h.name)),this._present=[...new Set(e.flatMap(l=>l.labels||[]))].sort((l,h)=>l.localeCompare(h)),this._assignKind="one",this._person="",this._pool=new Set,this._rotation=d[0],this._addText="",this._remove=new Set,this._setWarning=!1,this._warning=7,this._setPriority=!1,this._priority="normal",this._setMute=!1,this._mute=!1,this._open=!0,new Promise(l=>{this._resolve=l})}_finish(t){this._open=!1;let e=this._resolve;this._resolve=null,e?.(t)}changes(){if(this._mode==="assign"){if(this._assignKind==="one")return{responsible_user_id:this._person||null,assignee_pool:null,rotation_strategy:null};let e=this._users.map(r=>r.id).filter(r=>this._pool.has(r));return e.length<2?null:{assignee_pool:e,rotation_strategy:this._rotation,responsible_user_id:null}}if(this._mode==="labels"){let e=[...new Set(this._addText.split(",").map(l=>l.trim()).filter(Boolean))],r=[...this._remove];return e.length||r.length?{labels_add:e,labels_remove:r}:null}let t={};return this._setWarning&&(t.warning_days=this._warning),this._setPriority&&(t.priority=this._priority),this._setMute&&(t.notify_enabled=!this._mute),Object.keys(t).length?t:null}_toggle(t,e){let r=new Set(t);return r.has(e)?r.delete(e):r.add(e),r}_renderAssign(t){return o`
|
||||
<div class="hint">${s("bulk_assign_hint",t)}</div>
|
||||
<label class="choice">
|
||||
<input type="radio" name="kind" .checked=${this._assignKind==="one"} @change=${()=>this._assignKind="one"} />
|
||||
${s("bulk_assign_one",t)}
|
||||
</label>
|
||||
${this._assignKind==="one"?o`<select class="person" .value=${this._person} @change=${e=>this._person=e.target.value}>
|
||||
<option value="" ?selected=${!this._person}>${s("unassigned",t)}</option>
|
||||
${this._users.map(e=>o`<option value=${e.id} ?selected=${this._person===e.id}>${e.name}</option>`)}
|
||||
</select>`:p}
|
||||
<label class="choice">
|
||||
<input type="radio" name="kind" .checked=${this._assignKind==="rotate"} @change=${()=>this._assignKind="rotate"} />
|
||||
${s("bulk_assign_rotate",t)}
|
||||
</label>
|
||||
${this._assignKind==="rotate"?o`<div class="pool">
|
||||
${this._users.map(e=>o`<label class="row">
|
||||
<input type="checkbox" .checked=${this._pool.has(e.id)} @change=${()=>this._pool=this._toggle(this._pool,e.id)} />
|
||||
${e.name}
|
||||
</label>`)}
|
||||
</div>
|
||||
<label class="field">
|
||||
<span>${s("rotation_strategy",t)}</span>
|
||||
<select class="rotation" .value=${this._rotation} @change=${e=>this._rotation=e.target.value}>
|
||||
${d.map(e=>o`<option value=${e} ?selected=${this._rotation===e}>${s(`rotation_${e}`,t)}</option>`)}
|
||||
</select>
|
||||
</label>
|
||||
${this._pool.size<2?o`<div class="hint">${s("bulk_rotation_min_two",t)}</div>`:p}`:p}
|
||||
`}_renderLabels(t){return o`
|
||||
<ms-textfield
|
||||
class="labels-add"
|
||||
label=${s("bulk_labels_add",t)}
|
||||
.helper=${s("labels_help",t)}
|
||||
.value=${this._addText}
|
||||
@input=${e=>this._addText=e.target.value}
|
||||
></ms-textfield>
|
||||
${this._present.length?o`<div class="section-title">${s("bulk_labels_remove",t)}</div>
|
||||
<div class="pool">
|
||||
${this._present.map(e=>o`<label class="row">
|
||||
<input type="checkbox" .checked=${this._remove.has(e)} @change=${()=>this._remove=this._toggle(this._remove,e)} />
|
||||
${e}
|
||||
</label>`)}
|
||||
</div>`:p}
|
||||
`}_renderEdit(t){return o`
|
||||
<div class="hint">${s("bulk_edit_hint",t)}</div>
|
||||
<div class="row edit-row">
|
||||
<input type="checkbox" class="set-warning" .checked=${this._setWarning} @change=${e=>this._setWarning=e.target.checked} />
|
||||
<span class="grow">${s("warning_days",t)}</span>
|
||||
<input type="number" class="warning" min="0" max=${m} .value=${String(this._warning)} ?disabled=${!this._setWarning}
|
||||
@change=${e=>{let r=parseInt(e.target.value,10);this._warning=Number.isInteger(r)?Math.min(Math.max(r,0),m):this._warning}} />
|
||||
</div>
|
||||
<div class="row edit-row">
|
||||
<input type="checkbox" class="set-priority" .checked=${this._setPriority} @change=${e=>this._setPriority=e.target.checked} />
|
||||
<span class="grow">${s("priority",t)}</span>
|
||||
<select class="priority" .value=${this._priority} ?disabled=${!this._setPriority} @change=${e=>this._priority=e.target.value}>
|
||||
${v.map(e=>o`<option value=${e} ?selected=${this._priority===e}>${s(`priority_${e}`,t)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
<div class="row edit-row">
|
||||
<input type="checkbox" class="set-mute" .checked=${this._setMute} @change=${e=>this._setMute=e.target.checked} />
|
||||
<span class="grow">${s("bulk_no_notifications",t)}</span>
|
||||
<input type="checkbox" class="mute" .checked=${this._mute} ?disabled=${!this._setMute} @change=${e=>this._mute=e.target.checked} />
|
||||
</div>
|
||||
`}render(){if(!this._open)return o``;let t=this._lang,e=this._mode==="assign"?s("bulk_assign",t):this._mode==="labels"?s("labels",t):s("edit",t),r=this.changes()!==null;return o`
|
||||
<ha-dialog open @closed=${()=>this._finish(null)}>
|
||||
<div class="dialog-title">${e}</div>
|
||||
<div class="content">
|
||||
<div class="count">${s("bulk_n_selected",t).replace("{n}",String(this._count))}</div>
|
||||
${this._mode==="assign"?this._renderAssign(t):this._mode==="labels"?this._renderLabels(t):this._renderEdit(t)}
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
<ha-button appearance="plain" @click=${()=>this._finish(null)}>${s("cancel",t)}</ha-button>
|
||||
<ha-button class="apply" .disabled=${!r} @click=${()=>this._finish(this.changes())}>${s("save",t)}</ha-button>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`}};i.styles=_`
|
||||
.dialog-title { font-size: 18px; font-weight: 500; padding-bottom: 12px; }
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
min-width: min(360px, calc(100vw - 24px));
|
||||
max-width: 520px;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.content { min-width: 0; max-width: none; max-height: none; }
|
||||
}
|
||||
.count, .hint { color: var(--secondary-text-color); font-size: 13px; }
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
padding-bottom: 4px;
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
}
|
||||
.choice, .row { display: flex; align-items: center; gap: 8px; font-size: 14px; cursor: pointer; }
|
||||
.pool { display: flex; flex-direction: column; gap: 4px; padding-left: 26px; }
|
||||
.field { display: flex; align-items: center; gap: 8px; justify-content: space-between; font-size: 14px; }
|
||||
.grow { flex: 1; min-width: 0; }
|
||||
select, input[type="number"] {
|
||||
font: inherit;
|
||||
padding: 4px 6px;
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 4px;
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
max-width: 100%;
|
||||
}
|
||||
input[type="number"] { width: 72px; }
|
||||
select.person { margin-left: 26px; }
|
||||
.dialog-actions { display: flex; justify-content: flex-end; gap: 8px; padding-top: 16px; }
|
||||
`,n([g({attribute:!1})],i.prototype,"hass",2),n([a()],i.prototype,"_open",2),n([a()],i.prototype,"_mode",2),n([a()],i.prototype,"_count",2),n([a()],i.prototype,"_users",2),n([a()],i.prototype,"_present",2),n([a()],i.prototype,"_assignKind",2),n([a()],i.prototype,"_person",2),n([a()],i.prototype,"_pool",2),n([a()],i.prototype,"_rotation",2),n([a()],i.prototype,"_addText",2),n([a()],i.prototype,"_remove",2),n([a()],i.prototype,"_setWarning",2),n([a()],i.prototype,"_warning",2),n([a()],i.prototype,"_setPriority",2),n([a()],i.prototype,"_priority",2),n([a()],i.prototype,"_setMute",2),n([a()],i.prototype,"_mute",2);customElements.get("maintenance-bulk-edit-dialog")||customElements.define("maintenance-bulk-edit-dialog",i);export{i as MaintenanceBulkEditDialog};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
function r(t){return String(t??"").replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}export{r as a};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
var n={default_warning_days:[0,365],default_consumable_threshold:[1,90],battery_low_percent:[1,90],battery_recovered_percent:[20,100],archive_oneoff_days:[0,3650],delete_archived_oneoff_days:[0,3650],notify_due_soon_interval_hours:[0,720],notify_overdue_interval_hours:[0,720],notify_triggered_interval_hours:[0,720],max_notifications_per_day:[0,1e3],notification_bundle_threshold:[2,20],snooze_duration_hours:[1,168],warranty_reminder_days:[1,365],budget_alert_threshold:[10,100],currency_decimals:[0,3]};function o(e){let r=n[e];if(!r)throw new Error(`not an int-ranged setting: ${e}`);return r}var t=[0,14],_=[0,1440],u=[1,1e4],a=[0,365],d=15,s=[.1,.9],b=[0,365],A=[.01,1e4],E=[.01,1e5],i=[.1,5];export{n as a,o as b,t as c,_ as d,u as e,a as f,d as g,s as h,b as i,A as j,E as k,i as l};
|
||||
@@ -0,0 +1,488 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{d as M,e as R}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-XDU67K3J.js";import{a as L,b as z,c as O}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-VZUMUVFP.js";import{c as U}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-MMIPM7EE.js";import{a as I,h as H,l as V,n as B}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GMGHSBQJ.js";import{j as Q,k as w}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-2BQZ33DM.js";import{a as j}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-3LDXEWBF.js";import{A as P,B as A,L as E,M as q,N as F,R as N,a,b as x,ba as C,c as l,f,h as k,m as h,n as _,t as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";var T=class{constructor(p,e){this.host=p;this.opts=e;this.photos=[];this.uploadedIds=[];this.uploading=!1;this.errorKey="";this._session=0;this._uploadEntry=new Map;this.max=e.max??10,p.addController(this)}hostConnected(){}get ids(){return this.photos.map(p=>p.id)}get remaining(){return Math.max(this.max-this.photos.length,0)}get full(){return this.remaining===0}errorText(p){return this.errorKey?o(this.errorKey,p).replace("{max}",String(this.max)):""}clearError(){this.errorKey=""}reset(p=[]){this._endSession(),this._revokeAll(),this.photos=p.map(e=>({id:e,preview:""})),this.uploadedIds=[],this._uploadEntry.clear(),this.errorKey="",this.host.requestUpdate()}async addFiles(p){if(p.length===0)return;let e=this._session,i=this.opts.hass(),t=this.opts.entryId(),r=p.slice(0,this.remaining);this.uploading=!0,this.errorKey="",this.host.requestUpdate();try{for(let n of r){let s=await M(i,t,n);if(e!==this._session){R(i,t,[s]);return}this.uploadedIds=[...this.uploadedIds,s],this._uploadEntry.set(s,t),this.photos=[...this.photos,{id:s,preview:URL.createObjectURL(n)}],this.host.requestUpdate()}p.length>r.length&&(this.errorKey="photos_limit")}catch(n){if(e!==this._session)return;this.errorKey=n instanceof Error&&n.message==="doc_too_large"?"doc_too_large":"doc_upload_failed"}finally{e===this._session&&(this.uploading=!1,this.host.requestUpdate())}}remove(p){let e=this.photos.find(i=>i.id===p);e?.preview&&URL.revokeObjectURL(e.preview),this.photos=this.photos.filter(i=>i.id!==p),this.uploadedIds.includes(p)&&(this.uploadedIds=this.uploadedIds.filter(i=>i!==p),this._discard([p])),this.host.requestUpdate()}discardOrphans(){if(this._endSession(),this.uploadedIds.length===0)return;let p=this.uploadedIds;this.uploadedIds=[],this._discard(p)}markAttached(){this._endSession(),this.uploadedIds=[],this._uploadEntry.clear()}_endSession(){this._session++,this.uploading=!1}_discard(p){let e=new Map;for(let t of p){let r=this._uploadEntry.get(t)??this.opts.entryId();this._uploadEntry.delete(t),e.set(r,[...e.get(r)??[],t])}let i=this.opts.hass();for(let[t,r]of e)R(i,t,r)}_revokeAll(){for(let p of this.photos)p.preview&&URL.revokeObjectURL(p.preview)}};function S(){if(window.externalApp!==void 0)return!0;let p=typeof navigator<"u"&&navigator.userAgent||"";return/Home Assistant\//.test(p)&&/Android/.test(p)}function W(){if(!S())return!1;let g=typeof navigator<"u"?navigator.mediaDevices:void 0;return!!g&&typeof g.getUserMedia=="function"}var te=1920,ie=.88,se={retryMs:500,windowMs:5e3},re=new Set(["NotReadableError","AbortError","TrackStartError"]),K=80,J=/back|rear|environment|rück|hinten/i,G=/front|user|selfie|vorne/i;function Y(g){let p=/camera2?\s*(\d+)/i.exec(g);return p?Number(p[1]):Number.MAX_SAFE_INTEGER}function D(g,p){if(p){let i=g.find(t=>t.label===p);if(i)return i}return g.filter(i=>i.label&&J.test(i.label)).sort((i,t)=>Y(i.label)-Y(t.label))[0]??null}var X=g=>g?.name||"Error",ae=g=>g?.message||"",b=class extends k{constructor(){super(...arguments);this.lang="en";this._open=!1;this._busy=!1;this._switching=!1;this._devices=[];this._deviceIndex=-1;this._switchFailed=!1;this._copied=!1;this.timing={...se};this._facing="environment";this._stream=null;this._opening=!1;this._gen=0;this._refused=new Set;this._log=[];this._t0=0;this._lastError=""}async open(){if(this._open||this._opening)return;this._opening=!0;let e=++this._gen;try{await this._acquireAndShow(e)}finally{this._opening=!1}}_live(e){return e===this._gen&&this.isConnected}async _acquireAndShow(e){let i=typeof navigator<"u"?navigator.mediaDevices:void 0;if(!i||typeof i.getUserMedia!="function"){this._unavailable("no_media_devices");return}this._log=[],this._t0=Date.now(),this._lastError="",this._refused.clear(),this._switchFailed=!1,this._copied=!1,this._note(navigator.userAgent);let t=z(L.cameraLabel),r=await this._enumerate(i);if(!this._live(e))return;let n=D(r,t),s="refused";if(n&&(s=await this._openPatiently(i,e,this._byDevice(n))),s==="cancelled")return;if(s!=="ok"){if(s=await this._openPatiently(i,e,{video:{facingMode:{ideal:"environment"}},what:"facing environment"}),s==="cancelled")return;if(s!=="ok"){this._unavailable(this._lastError||"camera_unavailable");return}if(r=await this._enumerate(i),!this._live(e)){this._stopStream();return}}if(thiLine truncated
|
||||
`),i=!1;try{navigator.clipboard?.writeText&&(await navigator.clipboard.writeText(e),i=!0)}catch{}if(!i){let t=this.shadowRoot?.querySelector(".details textarea");if(t){t.focus(),t.select();try{i=document.execCommand("copy")}catch{i=!1}}}this._copied=i}async _shoot(){let e=this._video;if(!(!e||this._busy||this._switching)){this._busy=!0;try{let i=e.videoWidth||640,t=e.videoHeight||480,r=Math.min(1,te/Math.max(i,t)),n=document.createElement("canvas");n.width=Math.round(i*r),n.height=Math.round(t*r);let s=n.getContext("2d");if(!s)throw new Error("no_canvas");s.drawImage(e,0,0,n.width,n.height);let d=await new Promise(v=>n.toBlob(v,"image/jpeg",ie));if(!d)throw new Error("no_blob");let m=new Date().toISOString().replace(/[-:]/g,"").slice(0,15),u=new File([d],`photo-${m}.jpg`,{type:"image/jpeg"});this.close(),this.dispatchEvent(new CustomEvent("photo-captured",{detail:{file:u},bubbles:!0,composed:!0}))}catch(i){this._unavailable(i instanceof Error?i.message:String(i))}finally{this._busy=!1}}}render(){if(!this._open)return f;let e=this.lang,i=this._busy||this._switching;return l`
|
||||
<div class="overlay" role="dialog" aria-modal="true" aria-label=${o("doc_camera",e)}>
|
||||
<video autoplay playsinline muted></video>
|
||||
${this._switching?l`<div class="switching" role="status">${o("camera_switching",e)}</div>`:f}
|
||||
${this._switchFailed?l`<div class="switch-note" role="status">
|
||||
<div>${o("camera_not_answered",e)}</div>
|
||||
<details class="details">
|
||||
<summary>${o("camera_diagnostics",e)}</summary>
|
||||
<textarea readonly rows="6" .value=${this._log.join(`
|
||||
`)}></textarea>
|
||||
<button type="button" class="copy" @click=${this._copyLog}>${o(this._copied?"camera_copied":"camera_copy",e)}</button>
|
||||
</details>
|
||||
</div>`:f}
|
||||
<div class="bar">
|
||||
<button type="button" class="cancel" @click=${this.close}>${o("cancel",e)}</button>
|
||||
${this._devices.length>1?l`<button type="button" class="switch" ?disabled=${i} title=${o("camera_switch_lens",e)} aria-label=${o("camera_switch_lens",e)} @click=${this._switchCamera}>
|
||||
<ha-icon icon="mdi:camera-flip-outline"></ha-icon>
|
||||
<span class="switch-pos">${this._deviceIndex>=0?`${this._deviceIndex+1}/${this._devices.length}`:`?/${this._devices.length}`}</span>
|
||||
</button>`:f}
|
||||
<button type="button" class="shoot" ?disabled=${i} @click=${this._shoot}>
|
||||
<ha-icon icon="mdi:camera"></ha-icon><span>${o("camera_capture_shoot",e)}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`}};b.styles=x`
|
||||
:host { display: contents; }
|
||||
.overlay {
|
||||
position: fixed; inset: 0; z-index: 10000;
|
||||
background: #000; color: #fff;
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
video { flex: 1; min-height: 0; width: 100%; object-fit: contain; background: #000; }
|
||||
.bar {
|
||||
display: flex; justify-content: space-between; align-items: center; gap: 16px;
|
||||
padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
button {
|
||||
font: inherit; border-radius: 24px; padding: 10px 18px; cursor: pointer;
|
||||
display: inline-flex; align-items: center; gap: 8px;
|
||||
}
|
||||
.cancel { background: transparent; color: #fff; border: 1px solid rgba(255, 255, 255, 0.6); }
|
||||
.switch { background: transparent; color: #fff; border: 1px solid rgba(255, 255, 255, 0.6); padding: 10px 12px; }
|
||||
.switch[disabled] { opacity: 0.5; cursor: default; }
|
||||
.switch ha-icon { --mdc-icon-size: 22px; }
|
||||
.switch-pos { font-size: 12px; opacity: 0.85; }
|
||||
.switching {
|
||||
position: absolute; top: 45%; left: 50%; transform: translate(-50%, -50%);
|
||||
padding: 8px 16px; border-radius: 16px; background: rgba(0, 0, 0, 0.6); font-size: 14px;
|
||||
}
|
||||
.switch-note {
|
||||
position: absolute; left: 12px; right: 12px; bottom: 84px; max-height: 60%; overflow: auto;
|
||||
text-align: center; color: #fff; font-size: 13px; text-shadow: 0 1px 2px #000;
|
||||
}
|
||||
.details { margin-top: 6px; text-align: start; text-shadow: none; }
|
||||
.details summary { cursor: pointer; text-align: center; opacity: 0.85; }
|
||||
.details textarea {
|
||||
display: block; box-sizing: border-box; width: 100%; margin: 6px 0;
|
||||
font: 11px/1.35 monospace; color: #fff; background: rgba(255, 255, 255, 0.12);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3); border-radius: 6px; padding: 6px; resize: vertical;
|
||||
}
|
||||
.copy { background: transparent; color: #fff; border: 1px solid rgba(255, 255, 255, 0.6); padding: 6px 14px; font-size: 13px; }
|
||||
.shoot { background: var(--primary-color, #03a9f4); color: #fff; border: none; font-weight: 600; }
|
||||
.shoot[disabled] { opacity: 0.6; cursor: default; }
|
||||
.shoot ha-icon { --mdc-icon-size: 22px; }
|
||||
`,a([h({type:String})],b.prototype,"lang",2),a([_()],b.prototype,"_open",2),a([_()],b.prototype,"_busy",2),a([_()],b.prototype,"_switching",2),a([_()],b.prototype,"_devices",2),a([_()],b.prototype,"_deviceIndex",2),a([_()],b.prototype,"_switchFailed",2),a([_()],b.prototype,"_copied",2);customElements.get("ms-camera-capture")||customElements.define("ms-camera-capture",b);var Z=x`
|
||||
ms-photo-picker { display: contents; }
|
||||
.photo-pickers {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
.photo-pick {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
border: 1px dashed var(--divider-color);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
width: fit-content;
|
||||
}
|
||||
.photo-pick:hover { border-color: var(--primary-color); }
|
||||
.photo-pick:focus-visible { outline: 2px solid var(--primary-color); outline-offset: 2px; }
|
||||
.photo-pick.disabled { opacity: 0.6; cursor: default; }
|
||||
.photo-pick input[type="file"] { display: none; }
|
||||
.photo-android-hint {
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
margin-top: 4px;
|
||||
}
|
||||
`,y=class extends k{constructor(){super(...arguments);this.lang="en";this.disabled=!1;this.busy=!1;this.accept="image/*";this.showCamera=!0;this.showGallery=!0;this.compact=!1;this.remaining=1/0;this._singlePick=S();this._inAppCamera=W()}createRenderRoot(){return this}get _locked(){return this.disabled||this.busy}_emit(e){e.length!==0&&this.dispatchEvent(new CustomEvent("files-picked",{detail:{files:e},bubbles:!0,composed:!0}))}_onInput(e){let i=e.target,t=Array.from(i.files??[]);i.value="",this._emit(t)}_onCameraClick(e){!this._inAppCamera||this._locked||(e.preventDefault(),this.querySelector("ms-camera-capture")?.open())}_onCameraUnavailable(){this._inAppCamera=!1,this.querySelector(".photo-pick-camera input")?.click()}_onKeydown(e){e.key!=="Enter"&&e.key!==" "||(e.preventDefault(),!this._locked&&e.currentTarget.click())}render(){if(this.remaining<=0||!this.showCamera&&!this.showGallery)return f;let e=this.lang,i=this._locked?"disabled":"",t=this.busy?o("uploading",e):o("doc_camera",e),r=o(this._singlePick?"choose_photo":"choose_photos",e);return l`
|
||||
<div class="photo-pickers">
|
||||
${this.showCamera?l`<label class="photo-pick photo-pick-camera ${i}" role="button" tabindex="0"
|
||||
aria-label=${t} title=${this.compact?t:f}
|
||||
@click=${this._onCameraClick} @keydown=${this._onKeydown}>
|
||||
<ha-icon icon="mdi:camera"></ha-icon>
|
||||
${this.compact?f:l`<span>${t}</span>`}
|
||||
<input type="file" accept=${this.accept} capture="environment"
|
||||
?disabled=${this._locked} @change=${this._onInput} />
|
||||
</label>`:f}
|
||||
${this.showGallery?l`<label class="photo-pick photo-pick-gallery ${i}" role="button" tabindex="0"
|
||||
aria-label=${r} title=${this.compact?r:f}
|
||||
@keydown=${this._onKeydown}>
|
||||
<ha-icon icon="mdi:image-multiple"></ha-icon>
|
||||
${this.compact?f:l`<span>${r}</span>`}
|
||||
<input type="file" accept=${this.accept} ?multiple=${!this._singlePick}
|
||||
?disabled=${this._locked} @change=${this._onInput} />
|
||||
</label>`:f}
|
||||
</div>
|
||||
${this.showGallery&&this._singlePick?l`<div class="photo-android-hint">${o("photos_android_hint",e)}</div>`:f}
|
||||
${this.showCamera&&this._inAppCamera?l`<ms-camera-capture .lang=${e}
|
||||
@photo-captured=${n=>this._emit([n.detail.file])}
|
||||
@capture-unavailable=${this._onCameraUnavailable}></ms-camera-capture>`:f}
|
||||
`}};a([h({type:String})],y.prototype,"lang",2),a([h({type:Boolean})],y.prototype,"disabled",2),a([h({type:Boolean})],y.prototype,"busy",2),a([h({type:String})],y.prototype,"accept",2),a([h({type:Boolean})],y.prototype,"showCamera",2),a([h({type:Boolean})],y.prototype,"showGallery",2),a([h({type:Boolean})],y.prototype,"compact",2),a([h({type:Number})],y.prototype,"remaining",2),a([_()],y.prototype,"_inAppCamera",2);customElements.get("ms-photo-picker")||customElements.define("ms-photo-picker",y);var $=Q,c=class extends k{constructor(){super(...arguments);this.entryId="";this.taskId="";this.taskName="";this.lang="en";this.checklist=[];this.adaptiveEnabled=!1;this.taskType="";this.readingUnit="";this.readings=[];this.readingHistory=[];this.restockDefault=null;this.restockUnitCost=null;this.restockPackage="";this.currencySymbol="";this.partsCostMode="purchase";this.parts=[];this.consumesParts=[];this.consumesInfo=[];this.requiredFields=[];this.phaseLabel="";this.requireTagScan=!1;this.viaTagScan=!1;this._open=!1;this._notes="";this._cost="";this._duration="";this._loading=!1;this._error="";this._checklistState={};this._feedback="needed";this._photos=new T(this,{entryId:()=>this.entryId,hass:()=>this.hass});this._readingValue="";this._readingValues={};this._restockQty="";this._completedAt="";this._usedParts={};this._usedQtyText={};this.checklistPrefill={}}open(e={}){this._open||(this._open=!0,this.viaTagScan=!!e.viaTagScan,this._notes="",this._cost="",this._duration="",this._error="",this._checklistState=Object.fromEntries(this.checklist.map((i,t)=>[String(t),!!this.checklistPrefill[i]]).filter(([,i])=>i)),this._feedback="needed",this._photos.reset(),this._readingValue="",this._readingValues={},this._restockQty=this.restockDefault!==null?String(this.restockDefault):"",this._completedAt="",this._usedParts=Object.fromEntries(this.consumesParts.map(i=>[I(i),{...i}])),this._usedQtyText={})}_rangeError(e,i){let t=this.lang;return o("settings_value_out_of_range",t).replace("{min}",E(e,t,{maximumFractionDigits:2})).replace("{max}",E(i,t,{maximumFractionDigits:2}))}_toggleCheck(e){let i=String(e);this._checklistState={...this._checklistState,[i]:!this._checklistState[i]}}_setFeedback(e){this._feedback=e}async _complete(){if(this._loading||this._photos.uploading)return;this._error="",this._photos.clearError();let e={type:"maintenance_supporter/task/complete",entry_id:this.entryId,task_id:this.taskId},i=this._notes.trim();if(i&&(e.notes=i),this._cost){let s=parseFloat(this._cost);isNaN(s)||(e.cost=s)}let t=V(this._duration);if(t!==null&&(e.duration=t),this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photos.photos.length>0&&(e.photo_doc_ids=this._photos.ids),this.viaTagScan&&(e.via_tag_scan=!0),this._completedAt){if(A(this._completedAt)>Date.now()){this._error=o("completed_at_future_error",this.lang);return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this.readings.length>0){let s={};for(let d of this.readings){let m=(this._readingValues[d.id]??"").trim();if(m==="")continue;let u=parseFloat(m.replace(",","."));isNaN(u)||(s[d.id]=u)}Object.keys(s).length>0&&(e.reading_values=s)}else if(this._readingValue!==""){let s=parseFloat(this._readingValue);isNaN(s)||(e.reading_value=s)}if(this.restockDefault!==null&&this._restockQty.trim()!==""){let s=parseFloat(this._restockQty.replace(",","."));if(!Number.isFinite(s)||s<w[0]||s>w[1]){this._error=this._rangeError(...w);return}e.restock_quantity=s}if(this.parts.length>0){let s=[];for(let[d,m]of Object.entries(this._usedParts)){let u=this._usedQtyText[d],v=u===void 0?m.quantity:parseFloat(u.replace(",","."));if(!Number.isFinite(v)||v<$[0]||v>$[1]){this._error=this._rangeError(...$);return}s.push({...m,quantity:v})}e.used_parts=s.map(d=>d.entry_id?{part_id:d.part_id,quantity:d.quantity,entry_id:d.entry_id}:{part_id:d.part_id,quantity:d.quantity})}let r=await j(this,e,{busy:s=>{this._loading=s},lang:this.lang,fallbackKey:"save_error",onError:s=>{this._error=s}});if(r===void 0)return;this._photos.markAttached(),this._open=!1;let n={entryId:this.entryId,taskId:this.taskId,taskName:this.taskName,undo:r?.undo===!0};this.dispatchEvent(new CustomEvent("task-completed",{detail:n}))}_renderReadingField(e,i){let t=this._completedAt?A(this._completedAt):NaN,r=H(this.readingHistory,e.id,isNaN(t)?void 0:t),n=e.unit||this.readingUnit,s=(this._readingValues[e.id]??"").trim(),d=s===""?NaN:parseFloat(s.replace(",",".")),m=r!==void 0&&!isNaN(d)&&d<r.value,u=r!==void 0?E(r.value,i,{maximumFractionDigits:3}):"";return l`
|
||||
<label class="field reading-field">
|
||||
<span class="field-label">${e.name}${n?` (${n})`:""}</span>
|
||||
<input type="text" inputmode="decimal" class="field-input"
|
||||
placeholder=${r!==void 0?o("reading_last",i).replace("{value}",u):""}
|
||||
.value=${this._readingValues[e.id]??""}
|
||||
@input=${v=>{this._readingValues={...this._readingValues,[e.id]:v.target.value}}} />
|
||||
${m?l`<span class="reading-warn">${o("reading_below_last",i).replace("{value}",u)}</span>`:f}
|
||||
</label>`}get _missingRequired(){let e={notes:this._notes.trim()!=="",cost:this._cost.trim()!=="",duration:this._duration.trim()!=="",photo:this._photos.photos.length>0,user:!!this.hass?.user};return this.requiredFields.filter(i=>!e[i])}_demands(e){return this.requiredFields.includes(e)}_req(e){return this._demands(e)?l`<span class="req-mark" aria-hidden="true">*</span>`:f}_purchaseSuggestion(){if(this.restockDefault===null)return null;let e=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(e)||e<=0?null:Math.round(this.restockUnitCost*e*100)/100}_partsValue(){if(this.restockDefault!==null||!this.parts.length)return null;let e=0,i=!1;for(let t of Object.values(this._usedParts)){let r=this.parts.find(s=>I({part_id:s.id,entry_id:s.entry_id})===I(t)),n=U(r);n!==null&&(e+=n*(t.quantity||1),i=!0)}return i?Math.round(e*100)/100:null}_renderCostSuggestion(e){let i=this._purchaseSuggestion();if(this.restockDefault!==null){let s=this.partsCostMode==="use"?l`<div class="cost-note">${o("cost_purchase_use_hint",e)}</div>`:f;if(this._cost.trim()!==""||i==null||i<=0)return s;let d=q(i,this.currencySymbol,e);return l`<button
|
||||
type="button"
|
||||
class="cost-suggestion"
|
||||
@click=${()=>this._cost=String(Math.round(i*100)/100)}
|
||||
>${o("cost_from_parts",e).replace("{amount}",d)}</button>${s}`}let t=this._partsValue();if(t==null||t<=0)return f;let r=q(t,this.currencySymbol,e),n=this.partsCostMode==="use"?"cost_parts_booked":"cost_parts_info";return l`<div class="cost-note">${o(n,e).replace("{amount}",r)}</div>`}_close(){this._open=!1,this._photos.discardOrphans()}_pickCompletedAt(){this._completedAt=`${P()}:00`}render(){if(!this._open)return l``;let e=this.lang||this.hass?.language||"en",i=this._error||this._photos.errorText(e);return l`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${o("complete_title",e)}${this.taskName}</div>
|
||||
${this.phaseLabel?l`<div class="phase-line">${o("phase_current",e)}: ${this.phaseLabel}</div>`:f}
|
||||
${this.requireTagScan&&!this.viaTagScan?l`<div class="scan-required-note">${o("require_tag_scan_hint",e)}</div>`:f}
|
||||
<div class="content">
|
||||
${i?l`<div class="error">${i}</div>`:f}
|
||||
${this.checklist.length>0?l`
|
||||
<div class="checklist-section">
|
||||
<label class="checklist-label">${o("checklist",e)}</label>
|
||||
${this.checklist.map((t,r)=>l`
|
||||
<label class="checklist-item" @click=${()=>this._toggleCheck(r)}>
|
||||
<input type="checkbox" .checked=${!!this._checklistState[String(r)]} />
|
||||
<span>${t}</span>
|
||||
</label>
|
||||
`)}
|
||||
</div>
|
||||
`:f}
|
||||
${this.readings.length>0?l`<div class="readings-block">
|
||||
<span class="field-label">${o("readings_section",e)}</span>
|
||||
${this.readings.map(t=>this._renderReadingField(t,e))}
|
||||
</div>`:this.taskType==="reading"?l`
|
||||
<label class="field">
|
||||
<span class="field-label">${o("reading_value_label",e)}${this.readingUnit?` (${this.readingUnit})`:""}</span>
|
||||
<input type="number" step="any" class="field-input"
|
||||
.value=${this._readingValue}
|
||||
@input=${t=>this._readingValue=t.target.value} />
|
||||
</label>`:f}
|
||||
${this.parts.length?l`<div class="used-parts">
|
||||
<span class="field-label">${o("complete_parts_used",e)}</span>
|
||||
${this.parts.map(t=>{let r=I({part_id:t.id,entry_id:t.entry_id}),n=this._usedParts[r],s=n!==void 0,d=t.entry_id?{part_id:t.id,quantity:1,entry_id:t.entry_id}:{part_id:t.id,quantity:1};return l`<div class="used-part-row">
|
||||
<label class="used-part-check">
|
||||
<input type="checkbox" .checked=${s}
|
||||
@change=${m=>{let u={...this._usedParts};if(m.target.checked)u[r]=u[r]||d;else{delete u[r];let v={...this._usedQtyText};delete v[r],this._usedQtyText=v}this._usedParts=u}} />
|
||||
<span
|
||||
>${t.name}${t.owner_name?l`<span class="used-part-owner"> (${t.owner_name})</span>`:f}${t.stock!==null&&t.stock!==void 0?` (${F(t.stock,t.unit,e)})`:""}</span
|
||||
>
|
||||
</label>
|
||||
${s?l`<input class="used-part-qty" type="number" min=${$[0]} max=${$[1]} step="0.01"
|
||||
.value=${this._usedQtyText[r]??String(n.quantity)}
|
||||
@input=${m=>{let u=m.target.value;this._usedQtyText={...this._usedQtyText,[r]:u};let v=parseFloat(u.replace(",","."));Number.isFinite(v)&&v>=$[0]&&(this._usedParts={...this._usedParts,[r]:{...d,quantity:v}})}} />`:f}
|
||||
</div>`})}
|
||||
</div>`:this.consumesInfo.length?l`<div class="consumes-hint">
|
||||
${this.consumesInfo.map(t=>l`<div>${t}</div>`)}
|
||||
</div>`:f}
|
||||
${this.restockDefault!==null?l`
|
||||
<label class="field">
|
||||
<span class="field-label">${o("restock_quantity_label",e)}${this.restockPackage?` (\xD7 ${this.restockPackage})`:""}</span>
|
||||
<input type="number" step="0.01" min=${w[0]} max=${w[1]} class="field-input"
|
||||
.value=${this._restockQty}
|
||||
@input=${t=>this._restockQty=t.target.value} />
|
||||
</label>`:f}
|
||||
<!-- Native <input>s rather than <ha-textfield>: when this dialog
|
||||
is opened from a Lovelace card via dialog-mount, ha-textfield
|
||||
isn't yet registered (HA loads it lazily when its own panels
|
||||
need it) so the elements render with zero height and the user
|
||||
only sees the title + Cancel/Complete buttons — the original
|
||||
bug report. Native inputs always render. -->
|
||||
<label class="field">
|
||||
<span class="field-label">${this._demands("notes")?o("notes_label",e):o("notes_optional",e)}${this._req("notes")}</span>
|
||||
<!-- Several lines (#202): what was done, one line each. The
|
||||
history and the printouts keep the line breaks; they show
|
||||
notes as plain text, so no Markdown hint here. -->
|
||||
<textarea class="field-input notes-input" rows="3"
|
||||
.value=${this._notes}
|
||||
@input=${t=>this._notes=t.target.value}></textarea>
|
||||
</label>
|
||||
<div class="field">
|
||||
<span class="field-label">${this._demands("cost")?o("cost",e):o("cost_optional",e)}${this._req("cost")}</span>
|
||||
<ms-cost-input .lang=${e} .value=${this._cost}
|
||||
@value-changed=${t=>this._cost=t.detail.value}></ms-cost-input>
|
||||
${this._renderCostSuggestion(e)}
|
||||
</div>
|
||||
<label class="field">
|
||||
<span class="field-label">${this._demands("duration")?o("quick_complete_defaults_duration",e):o("duration_minutes",e)}${this._req("duration")}</span>
|
||||
<input type="number" step="1" min="0" inputmode="numeric" class="field-input"
|
||||
.value=${this._duration}
|
||||
@input=${t=>this._duration=t.target.value} />
|
||||
</label>
|
||||
<div class="field">
|
||||
<span class="field-label">${o("completed_at_optional",e)}</span>
|
||||
${this._completedAt?l`<ms-date-field
|
||||
kind="datetime"
|
||||
clearable
|
||||
.hass=${this.hass}
|
||||
.lang=${e}
|
||||
.value=${this._completedAt}
|
||||
.helper=${N(e)}
|
||||
@value-changed=${t=>this._completedAt=t.detail.value}
|
||||
></ms-date-field>`:l`<button type="button" class="backdate-pick" @click=${this._pickCompletedAt}>
|
||||
<ha-icon icon="mdi:calendar-clock"></ha-icon>${o("completed_at_pick",e)}
|
||||
</button>`}
|
||||
</div>
|
||||
<div class="field">
|
||||
<span class="field-label">${this._demands("photo")?o("completion_photos",e):o("completion_photos_optional",e)}${this._req("photo")}</span>
|
||||
${this._photos.photos.length>0?l`<div class="photo-strip">
|
||||
${this._photos.photos.map(t=>l`
|
||||
<div class="photo-preview">
|
||||
<img src=${t.preview} alt="" />
|
||||
<button type="button" class="photo-remove" @click=${()=>this._photos.remove(t.id)}
|
||||
title="${o("remove",e)}">✕</button>
|
||||
</div>`)}
|
||||
</div>`:f}
|
||||
${this._photos.full?l`<div class="photo-limit">${o("photos_limit",e).replace("{max}",String(this._photos.max))}</div>`:l`<ms-photo-picker .lang=${e} .busy=${this._photos.uploading} .remaining=${this._photos.remaining}
|
||||
@files-picked=${t=>this._photos.addFiles(t.detail.files)}
|
||||
></ms-photo-picker>`}
|
||||
</div>
|
||||
${this.adaptiveEnabled?l`
|
||||
<div class="feedback-section">
|
||||
<label class="feedback-label">${o("was_maintenance_needed",e)}</label>
|
||||
<div class="feedback-buttons">
|
||||
<button
|
||||
class="feedback-btn ${this._feedback==="needed"?"selected":""}"
|
||||
@click=${()=>this._setFeedback("needed")}
|
||||
>${o("feedback_needed",e)}</button>
|
||||
<button
|
||||
class="feedback-btn ${this._feedback==="not_needed"?"selected":""}"
|
||||
@click=${()=>this._setFeedback("not_needed")}
|
||||
>${o("feedback_not_needed",e)}</button>
|
||||
<button
|
||||
class="feedback-btn ${this._feedback==="not_sure"?"selected":""}"
|
||||
@click=${()=>this._setFeedback("not_sure")}
|
||||
>${o("feedback_not_sure",e)}</button>
|
||||
</div>
|
||||
</div>
|
||||
`:f}
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${o("cancel",e)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._complete}
|
||||
.disabled=${this._loading||this._photos.uploading||this._missingRequired.length>0}
|
||||
title=${this._photos.uploading?o("uploading",e):this._missingRequired.length?this._missingRequired.map(t=>o("err_required",e).replace("{field}",o(B[t]??t,e))).join(" \xB7 "):""}
|
||||
>
|
||||
${this._loading?o("completing",e):o("complete",e)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`}};c.styles=[C,Z,x`
|
||||
.req-mark {
|
||||
color: var(--error-color, #f44336);
|
||||
margin-left: 2px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.notes-input { resize: vertical; line-height: 1.4; }
|
||||
/* #104: one-click cost suggestion from parts — quiet link-style chip. */
|
||||
.cost-note {
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
margin-top: 4px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.cost-suggestion {
|
||||
align-self: flex-start;
|
||||
margin-top: 4px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--primary-color);
|
||||
font-size: 12.5px;
|
||||
cursor: pointer;
|
||||
text-decoration: underline dotted;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
.dialog-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
.scan-required-note {
|
||||
margin: -4px 0 12px;
|
||||
padding: 8px 10px;
|
||||
border-radius: 6px;
|
||||
background: rgba(255, 152, 0, 0.12);
|
||||
color: var(--primary-text-color);
|
||||
font-size: 13px;
|
||||
}
|
||||
.phase-line {
|
||||
margin-top: -8px;
|
||||
padding-bottom: 12px;
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
min-width: 300px;
|
||||
}
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
.consumes-hint {
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
border-left: 3px solid var(--primary-color);
|
||||
padding: 4px 8px;
|
||||
margin: 4px 0 8px;
|
||||
}
|
||||
/* #99: editable per-completion parts selection */
|
||||
.used-parts { margin: 4px 0 8px; display: flex; flex-direction: column; gap: 4px; }
|
||||
.used-part-row { display: flex; align-items: center; gap: 8px; }
|
||||
.used-part-check {
|
||||
display: flex; align-items: center; gap: 6px; flex: 1;
|
||||
font-size: 13px; cursor: pointer;
|
||||
}
|
||||
.used-part-check input { cursor: pointer; }
|
||||
/* #111: whose stock this row draws on. Muted but never omitted — an
|
||||
unlabelled foreign pool is indistinguishable from an own part. */
|
||||
.used-part-owner { color: var(--secondary-text-color); }
|
||||
.used-part-qty {
|
||||
width: 76px; padding: 4px 6px; border-radius: 4px; font: inherit; font-size: 13px;
|
||||
border: 1px solid var(--divider-color);
|
||||
background: var(--card-background-color);
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.error {
|
||||
color: var(--error-color, #f44336);
|
||||
font-size: 13px;
|
||||
}
|
||||
/* .field/.field-label/.field-input come from nativeFieldStyles */
|
||||
/* #161 phase 2: the per-slot reading fields */
|
||||
.readings-block { display: flex; flex-direction: column; gap: 8px; }
|
||||
.readings-block > .field-label { margin-bottom: -4px; }
|
||||
.reading-warn {
|
||||
font-size: 12px;
|
||||
color: var(--warning-color, #ff9800);
|
||||
}
|
||||
/* .photo-pick / .photo-pickers / .photo-android-hint come from photoPickerStyles */
|
||||
/* #163: the backdate moment starts EMPTY (= now); the button seeds the
|
||||
HA date+time picker with the current minute instead of the picker's
|
||||
own 00:00 default, so a backdated completion never lands at midnight
|
||||
by accident. */
|
||||
.backdate-pick {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
border: 1px dashed var(--divider-color);
|
||||
border-radius: 8px;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
width: fit-content;
|
||||
--mdc-icon-size: 18px;
|
||||
}
|
||||
.backdate-pick:hover { border-color: var(--primary-color); }
|
||||
/* #161: several photos per completion — tiles wrap into a strip,
|
||||
the two pickers (camera / gallery) sit underneath while there is
|
||||
room left under the cap. */
|
||||
.photo-strip {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin: 8px 0; /* room for the remove badges above the tiles */
|
||||
}
|
||||
.photo-limit {
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.photo-preview {
|
||||
position: relative;
|
||||
width: fit-content;
|
||||
}
|
||||
/* Uniform tiles: a tiny or portrait shot must not collapse the strip. */
|
||||
.photo-preview img {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
display: block;
|
||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||
}
|
||||
.photo-remove {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
background: var(--error-color, #db4437);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
.checklist-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.checklist-label {
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.checklist-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
padding: 4px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
.checklist-item input[type="checkbox"] {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.feedback-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 8px 0;
|
||||
border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
.feedback-label {
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.feedback-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.feedback-btn {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 8px;
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.feedback-btn:hover {
|
||||
background: var(--secondary-background-color, #f5f5f5);
|
||||
}
|
||||
.feedback-btn.selected {
|
||||
background: var(--primary-color);
|
||||
color: var(--text-primary-color, #fff);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
`],a([h({attribute:!1})],c.prototype,"hass",2),a([h()],c.prototype,"entryId",2),a([h()],c.prototype,"taskId",2),a([h()],c.prototype,"taskName",2),a([h()],c.prototype,"lang",2),a([h({type:Array})],c.prototype,"checklist",2),a([h({type:Boolean})],c.prototype,"adaptiveEnabled",2),a([h()],c.prototype,"taskType",2),a([h()],c.prototype,"readingUnit",2),a([h({attribute:!1})],c.prototype,"readings",2),a([h({attribute:!1})],c.prototype,"readingHistory",2),a([h({attribute:!1})],c.prototype,"restockDefault",2),a([h({attribute:!1})],c.prototype,"restockUnitCost",2),a([h({attribute:!1})],c.prototype,"restockPackage",2),a([h()],c.prototype,"currencySymbol",2),a([h({attribute:!1})],c.prototype,"partsCostMode",2),a([h({attribute:!1})],c.prototype,"parts",2),a([h({attribute:!1})],c.prototype,"consumesParts",2),a([h({type:Array})],c.prototype,"consumesInfo",2),a([h({type:Array})],c.prototype,"requiredFields",2),a([h()],c.prototype,"phaseLabel",2),a([h({type:Boolean})],c.prototype,"requireTagScan",2),a([h({type:Boolean})],c.prototype,"viaTagScan",2),a([_()],c.prototype,"_open",2),a([_()],c.prototype,"_notes",2),a([_()],c.prototype,"_cost",2),a([_()],c.prototype,"_duration",2),a([_()],c.prototype,"_loading",2),a([_()],c.prototype,"_error",2),a([_()],c.prototype,"_checklistState",2),a([_()],c.prototype,"_feedback",2),a([_()],c.prototype,"_readingValue",2),a([_()],c.prototype,"_readingValues",2),a([_()],c.prototype,"_restockQty",2),a([_()],c.prototype,"_completedAt",2),a([_()],c.prototype,"_usedParts",2),a([_()],c.prototype,"_usedQtyText",2),a([h({attribute:!1})],c.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",c);export{S as a,Z as b,T as c,c as d};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{I as f,k as g,s as p,t as a,w as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";var h={already_archived:"ws_err_already_archived",already_paused:"ws_err_already_paused",archived:"ws_err_archived",changed_since:"undo_changed",create_failed:"ws_err_create_failed",duplicate_failed:"ws_err_duplicate_failed",empty:"ws_err_empty",empty_csv:"ws_err_empty_csv",invalid_cursor:"ws_err_invalid_cursor",invalid_date:"ws_err_invalid_date",invalid_device:"ws_err_invalid_device",invalid_entity_slug:"ws_err_invalid_entity_slug",invalid_format:"ws_err_invalid_format",invalid_input:"ws_err_invalid_input",invalid_mirror_todo:"ws_err_invalid_mirror_todo",invalid_parent:"ws_err_invalid_parent",invalid_icon:"ws_err_invalid_icon",invalid_range:"ws_err_invalid_range",invalid_search_template:"ws_err_invalid_search_template",invalid_target:"ws_err_invalid_target",invalid_trigger_config:"ws_err_invalid_trigger_config",invalid_url:"ws_err_invalid_url",invalid_user:"ws_err_invalid_user",invalid_view:"ws_err_invalid_view",limit_reached:"ws_err_limit_reached",no_defaults:"ws_err_no_defaults",no_phases:"ws_err_no_phases",no_url:"ws_err_no_url",not_archived:"ws_err_not_archived",not_available:"ws_err_not_available",not_configured:"ws_err_not_configured",not_found:"ws_err_not_found",not_loaded:"ws_err_not_loaded",not_paused:"ws_err_not_paused",nothing_to_undo:"undo_nothing",replace_failed:"ws_err_replace_failed",self_link_device:"ws_err_self_link_device",storage_unavailable:"ws_err_storage_unavailable",too_early:"ws_err_too_early",too_large:"ws_err_too_large",too_many:"ws_err_too_many",too_many_views:"ws_err_too_many_views",unauthorized:"ws_err_unauthorized",unavailable:"ws_err_unavailable"},y={entry_id:"object",name:"name",task_type:"maintenance_type",schedule_type:"schedule_type",interval_days:"interval_days",interval_anchor:"interval_anchor",warning_days:"warning_days",last_performed:"last_performed_optional",notes:"notes_optional",documentation_url:"documentation_url_optional",custom_icon:"custom_icon_optional",nfc_tag_id:"nfc_tag_id_optional",responsible_user_id:"responsible_user",entity_slug:"entity_slug",entity_id:"entity_id",area_id:"area_id_optional",manufacturer:"manufacturer_optional",model:"model_optional",serial_number:"serial_number_optional",installation_date:"installation_date_optional",warranty_expiry:"warranty_expiry_optional",checklist:"checklist_steps_optional",reason:"reason",feedback:"feedback",cost:"cost",duration:"duration",description:"description_optional",environmental_entity:"environmental_entity_optional",environmental_attribute:"environmental_attribute_optional",trigger_above:"trigger_above",trigger_below:"trigger_below",trigger_equals:"trigger_equals",trigger_not_equals:"trigger_not_equals",trigger_for_minutes:"trigger_for_minutes"};function b(n){let t=n.replace(/_ids?$/,"").split("_").filter(Boolean);if(t.length===0)return n;let e=t.join(" ");return e.charAt(0).toUpperCase()+e.slice(1)}function k(n,t){let e=y[n];if(e){let r=a(e,t);if(r&&r!==e)return r}return b(n)}function E(n){let t=[...n.matchAll(/\['([^']+)'\]/g)].map(i=>i[1]),e=t.length?t[t.length-1]:void 0,r;return(r=n.match(/length of value must be at most (\d+)/))?{field:e,rule:"too_long",param:r[1]}:(r=n.match(/length of value must be at least (\d+)/))?{field:e,rule:"too_short",param:r[1]}:(r=n.match(/value must be at most (\S+)/))?{field:e,rule:"value_too_high",param:r[1]}:(r=n.match(/value must be at least (\S+)/))?{field:e,rule:"value_too_low",param:r[1]}:/required key not provided/.test(n)?{field:e,rule:"required"}:(r=n.match(/expected (\w+)/))?{field:e,rule:"wrong_type",param:r[1]}:/value must be one of/.test(n)?{field:e,rule:"invalid_choice"}:/not a valid value/.test(n)?{field:e,rule:"invalid_value"}:{field:e,rule:"unknown"}}var m=n=>n.toLowerCase().split(/[^a-z0-9]+/).filter(t=>t.length>1);function R(n,t){let e=new Set(m(t));return m(n).every(r=>e.has(r))}function c(n,t,e){if(e=e??a("action_error",t),typeof n=="string")return n;if(typeof n!="object"||n===null)return e;let r=n,i=r.message||r.error?.message||"",o=r.code||r.error?.code||"",l=o?h[o]:void 0,d=v(r.translation_domain??r.error?.translation_domain,r.translation_key??r.error?.translation_key,r.translation_placeholders??r.error?.translation_placeholders);if(d)return d;if(!i&&!l)return e;let _=E(i),w=_.field?k(_.field,t):"",s=u=>a(u,t).replace("{field}",w).replace("{n}",_.param??"");switch(_.rule){case"too_long":return s("err_too_long");case"too_short":return s("err_too_short");case"value_too_high":return s("err_value_too_high");case"value_too_low":return s("err_value_too_low");case"required":return s("err_required");case"wrong_type":return s("err_wrong_type").replace("{type}",_.param??"");case"invalid_choice":return s("err_invalid_choice");case"invalid_value":return s("err_invalid_value");default:if(l){let u=a(l,t);return p(t)==="en"&&i&&!R(i,o)?`${u} (${i})`:u}return i||e}}async function W(n,t,e={}){e.busy?.(!0);try{let r=typeof t=="function"?await t():awaLine truncated
|
||||
@@ -0,0 +1,256 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{a as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-3LDXEWBF.js";import{I as v,a as r,b as _,c as l,f as o,h,m as c,n,t as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";var s=class extends h{constructor(){super(...arguments);this.objects=[];this.placesEnabled=!1;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._place="";this._remindOnSite=!1;this._entryId=null;this._replacing=!1;this._oldDeviceId="";this._replaceDevice="keep"}get _lang(){return v(this.hass)}openCreate(){this._entryId=null,this._name="",this._manufacturer="",this._model="",this._serialNumber="",this._areaId="",this._installationDate="",this._warrantyExpiry="",this._documentationUrl="",this._notes="",this._haDeviceId="",this._parentEntryId="",this._place="",this._remindOnSite=!1,this._replacing=!1,this._error="",this._open=!0}openReplace(e,a){this._entryId=e,this._replacing=!0,this._name=a.name||"",this._oldDeviceId=a.ha_device_id||"",this._haDeviceId="",this._replaceDevice="keep",this._error="",this._open=!0}openEdit(e,a){this._entryId=e,this._name=a.name||"",this._manufacturer=a.manufacturer||"",this._model=a.model||"",this._serialNumber=a.serial_number||"",this._areaId=a.area_id||"",this._installationDate=a.installation_date||"",this._warrantyExpiry=a.warranty_expiry||"",this._documentationUrl=a.documentation_url||"",this._notes=a.notes||"",this._haDeviceId=a.ha_device_id||"",this._parentEntryId=a.parent_entry_id||"",this._place=a.place||"",this._remindOnSite=!!a.remind_on_site,this._replacing=!1,this._error="",this._open=!0}async _replace(){if(this._loading||!this._entryId)return;let e={type:"maintenance_supporter/object/replace",entry_id:this._entryId,name:this._name.trim()||null};this._oldDeviceId?(this._replaceDevice==="other"&&(e.ha_device_id=this._haDeviceId),this._replaceDevice==="none"&&(e.ha_device_id=null)):this._haDeviceId&&(e.ha_device_id=this._haDeviceId);let a=await p(this,e,{busy:t=>{this._loading=t},fallbackKey:"save_error",onError:t=>{this._error=t}});a!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("object-replaced",{detail:{entry_id:a?.entry_id,device_swap:a?.device_swap}})))}_deviceName(e){let t=this.hass?.devices?.[e];return t?.name_by_user||t?.name||e}_deviceSelector(e){return l`<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${{device:this._haDeviceId||void 0}}
|
||||
.schema=${[{name:"device",selector:{device:{}}}]}
|
||||
.computeLabel=${()=>e}
|
||||
@value-changed=${a=>this._haDeviceId=a.detail.value?.device||""}
|
||||
></ha-form>`}_renderReplace(){let e=this._lang,a=(d,u)=>l`<label class="radio-row">
|
||||
<input
|
||||
type="radio"
|
||||
name="replace-device"
|
||||
.checked=${this._replaceDevice===d}
|
||||
@change=${()=>{this._replaceDevice=d}}
|
||||
/>
|
||||
<span>${u}</span>
|
||||
</label>`,t=this._replaceDevice==="other"&&!this._haDeviceId;return l`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${i("replace_object",e)}</div>
|
||||
<div class="content">
|
||||
${this._error?l`<div class="error">${this._error}</div>`:o}
|
||||
<div class="hint">${i("replace_object_prompt",e)}</div>
|
||||
<ms-textfield
|
||||
label="${i("replace_name_label",e)}"
|
||||
.value=${this._name}
|
||||
@input=${d=>this._name=d.target.value}
|
||||
></ms-textfield>
|
||||
${this._oldDeviceId?l`<div class="radio-group" role="radiogroup" aria-label=${i("replace_device_heading",e)}>
|
||||
<div class="textarea-label">${i("replace_device_heading",e)}</div>
|
||||
${a("keep",i("replace_device_keep",e).replace("{device}",this._deviceName(this._oldDeviceId)))}
|
||||
${this._replaceDevice==="keep"?l`<div class="hint">${i("replace_device_keep_hint",e)}</div>`:o}
|
||||
${a("other",i("replace_device_other",e))}
|
||||
${this._replaceDevice==="other"?l`${this._deviceSelector(i("replace_device_pick",e))}
|
||||
<div class="hint">${i("replace_device_other_hint",e)}</div>`:o}
|
||||
${a("none",i("replace_device_none",e))}
|
||||
</div>`:this._deviceSelector(i("link_device_optional",e))}
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${i("cancel",e)}
|
||||
</ha-button>
|
||||
<ha-button @click=${this._replace} .disabled=${this._loading||t}>
|
||||
${this._loading?i("saving",e):i("replace_object",e)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`}_renderPlace(e){let a=!!this._place&&!this.hass?.states?.[this._place];return l`
|
||||
<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${{place:this._place||void 0}}
|
||||
.schema=${[{name:"place",selector:{entity:{domain:"zone"}}}]}
|
||||
.computeLabel=${()=>i("place_optional",e)}
|
||||
@value-changed=${t=>{this._place=t.detail.value?.place||"",this._place||(this._remindOnSite=!1)}}
|
||||
></ha-form>
|
||||
${a?l`<div class="place-missing">${i("place_missing",e)}</div>`:o}
|
||||
<label class="place-on-site ${this._place?"":"disabled"}">
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${this._remindOnSite}
|
||||
?disabled=${!this._place}
|
||||
@change=${t=>this._remindOnSite=t.target.checked}
|
||||
/>
|
||||
<span>${i("remind_on_site",e)}</span>
|
||||
</label>
|
||||
${this._place?l`<div class="place-hint">${i("remind_on_site_hint",e)}</div>`:o}
|
||||
`}async _save(){if(this._loading||!this._name.trim())return;this._error="";let e={name:this._name,manufacturer:this._manufacturer||null,model:this._model||null,serial_number:this._serialNumber||null,area_id:this._areaId||null,installation_date:this._installationDate||null,warranty_expiry:this._warrantyExpiry||null,documentation_url:this._documentationUrl.trim()||null,notes:this._notes.trim()||null,ha_device_id:this._haDeviceId||null,parent_entry_id:this._parentEntryId||null,...this.placesEnabled?{place:this._place||null,remind_on_site:!!this._place&&this._remindOnSite}:{}},a=await p(this,this._entryId?{type:"maintenance_supporter/object/update",entry_id:this._entryId,...e}:{type:"maintenance_supporter/object/create",...e},{busy:t=>{this._loading=t},fallbackKey:"save_error",onError:t=>{this._error=t}});a!==void 0&&(this._open=!1,this.dispatchEvent(new CustomEvent("object-saved",{detail:{device_swap:a?.device_swap}})))}_parentChoices(){return(this.objects||[]).filter(e=>e.entry_id!==this._entryId)}_close(){this._open=!1}render(){if(!this._open)return l``;if(this._replacing)return this._renderReplace();let e=this._lang,a=this._entryId?i("edit_object",e):i("new_object",e);return l`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${a}</div>
|
||||
<div class="content">
|
||||
${this._error?l`<div class="error">${this._error}</div>`:o}
|
||||
<ms-textfield
|
||||
label="${i("name",e)}"
|
||||
required
|
||||
.value=${this._name}
|
||||
@input=${t=>this._name=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("manufacturer_optional",e)}"
|
||||
.value=${this._manufacturer}
|
||||
@input=${t=>this._manufacturer=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("model_optional",e)}"
|
||||
.value=${this._model}
|
||||
@input=${t=>this._model=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("serial_number_optional",e)}"
|
||||
.value=${this._serialNumber}
|
||||
@input=${t=>this._serialNumber=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("documentation_url_optional",e)}"
|
||||
type="url"
|
||||
.value=${this._documentationUrl}
|
||||
@input=${t=>this._documentationUrl=t.target.value}
|
||||
></ms-textfield>
|
||||
<ha-area-picker
|
||||
.hass=${this.hass}
|
||||
label="${i("area_id_optional",e)}"
|
||||
.value=${this._areaId}
|
||||
@value-changed=${t=>this._areaId=t.detail.value||""}
|
||||
></ha-area-picker>
|
||||
${this.placesEnabled?this._renderPlace(e):o}
|
||||
<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>
|
||||
`}};s.styles=_`
|
||||
.place-on-site {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 14px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.place-on-site.disabled {
|
||||
color: var(--disabled-text-color, var(--secondary-text-color));
|
||||
}
|
||||
.place-hint,
|
||||
.place-missing {
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
margin-top: -4px;
|
||||
}
|
||||
.place-missing {
|
||||
color: var(--warning-color, #c77700);
|
||||
}
|
||||
.dialog-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
min-width: 300px;
|
||||
}
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
ms-textfield {
|
||||
display: block;
|
||||
}
|
||||
.textarea-field {
|
||||
display: flex; flex-direction: column; gap: 4px;
|
||||
}
|
||||
.textarea-label {
|
||||
font-size: 12px; color: var(--secondary-text-color, #888); font-weight: 500;
|
||||
}
|
||||
.textarea-field textarea {
|
||||
padding: 8px 10px; font-size: 14px; font-family: inherit;
|
||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
resize: vertical;
|
||||
}
|
||||
.textarea-field textarea:focus {
|
||||
outline: none; border-color: var(--primary-color);
|
||||
}
|
||||
.md-hint {
|
||||
font-size: 11px; color: var(--secondary-text-color); font-style: italic;
|
||||
}
|
||||
.parent-select {
|
||||
padding: 8px 10px; font-size: 14px; font-family: inherit;
|
||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
}
|
||||
.error {
|
||||
color: var(--error-color, #f44336);
|
||||
font-size: 13px;
|
||||
}
|
||||
.hint {
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
line-height: 1.4;
|
||||
}
|
||||
.radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.radio-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.radio-row input {
|
||||
margin: 0;
|
||||
}
|
||||
`,r([c({attribute:!1})],s.prototype,"hass",2),r([c({attribute:!1})],s.prototype,"objects",2),r([c({type:Boolean})],s.prototype,"placesEnabled",2),r([n()],s.prototype,"_open",2),r([n()],s.prototype,"_loading",2),r([n()],s.prototype,"_error",2),r([n()],s.prototype,"_name",2),r([n()],s.prototype,"_manufacturer",2),r([n()],s.prototype,"_model",2),r([n()],s.prototype,"_serialNumber",2),r([n()],s.prototype,"_areaId",2),r([n()],s.prototype,"_installationDate",2),r([n()],s.prototype,"_warrantyExpiry",2),r([n()],s.prototype,"_documentationUrl",2),r([n()],s.prototype,"_notes",2),r([n()],s.prototype,"_haDeviceId",2),r([n()],s.prototype,"_parentEntryId",2),r([n()],s.prototype,"_place",2),r([n()],s.prototype,"_remindOnSite",2),r([n()],s.prototype,"_entryId",2),r([n()],s.prototype,"_replacing",2),r([n()],s.prototype,"_oldDeviceId",2),r([n()],s.prototype,"_replaceDevice",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",s);export{s as a};
|
||||
@@ -0,0 +1,79 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{a as r,b as l,c as i,f as o,h as n,m as t}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.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.103.0 */
|
||||
import{c as r,f as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";var a=["#c62828","#ad1457","#6a1b9a","#4527a0","#283593","#1565c0","#00838f","#2e7d32","#558b2f","#ef6c00","#6d4c41","#546e7a"];function u(e){let s=(e||"").split(/\s+/).filter(Boolean);return s.length===0?"?":s.length===1?s[0][0].toUpperCase():(s[0][0]+s[s.length-1][0]).toUpperCase()}function c(e){let s=0;for(let n of e)s=s*31+n.charCodeAt(0)>>>0;return a[s%a.length]}function o(e){return e?{id:e.id,name:e.name,initials:e.initials||u(e.name),color:e.color||c(e.id)}:null}function h(e){return e?r`<span class="person-avatar" style="--person-color: ${e.color}" title=${e.name}>${e.initials}</span>`:i}function m(e,s=""){return e?r`<span class="person-chip ${s}" title=${e.name}>${h(e)}<span class="person-name">${e.name}</span></span>`:i}var l=class{constructor(s){this.usersCache=null;this.cacheTimestamp=0;this.CACHE_TTL_MS=6e4;this.hass=s}updateHass(s){this.hass=s}async getUsers(s=!1){let n=Date.now();if(!s&&this.usersCache&&n-this.cacheTimestamp<this.CACHE_TTL_MS)return this.usersCache;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/users/list"});return this.usersCache=t.users,this.cacheTimestamp=n,this.usersCache}catch(t){return console.error("Failed to fetch users:",t),this.usersCache||[]}}async assignUser(s,n,t){await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/assign_user",entry_id:s,task_id:n,user_id:t})}async getTasksByUser(s){return(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/tasks/by_user",user_id:s})).tasks}getUserName(s){return!s||!this.usersCache?null:this.usersCache.find(t=>t.id===s)?.name||null}getPerson(s){return o(this.getUser(s))}getUser(s){return!s||!this.usersCache?null:this.usersCache.find(n=>n.id===s)||null}getCurrentUserId(){return this.hass.user?.id||null}isCurrentUser(s){return s?s===this.getCurrentUserId():!1}clearCache(){this.usersCache=null,this.cacheTimestamp=0}};export{a,o as b,h as c,m as d,l as e};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{b as s}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-IRRUA3DS.js";async function a(o,n,t=300){return(await o.connection.sendMessagePromise({type:"auth/sign_path",path:n,expires:t})).path}async function r(o,n,t=300){return a(o,`/api/maintenance_supporter/document/${n}`,t)}async function p(o,n,t=""){let e=window.open("about:blank","_blank");try{let i=await r(o,n);e&&(e.location.href=new URL(i+t,window.location.origin).href)}catch(i){throw e&&e.close(),i}}async function l(o,n,t){s(await r(o,n,30),t)}function m(o,n=null){let t=URL.createObjectURL(new Blob([o],{type:"text/html"}));n&&!n.closed?n.location.href=t:window.open(t,"_blank"),setTimeout(()=>URL.revokeObjectURL(t),6e4)}function u(){return window.open("about:blank","_blank")}export{a,r as b,p as c,l as d,m as e,u as f};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
var E={\u00DF:"s","\u1E9E":"s",\u00E6:"a",\u0153:"o",\u00F8:"o",\u0111:"d",\u00F0:"d",\u00FE:"t",\u0142:"l",\u0131:"i"},d=10,R=7,g=4,h=2,S=5,x=3,_=/[a-z0-9]+/g;function u(r){let e="";for(let t of r.toLowerCase()){if(t.charCodeAt(0)<128&&t.length===1){e+=t;continue}let n=E[t];if(n){e+=n;continue}let o=t.normalize("NFKD")[0]||t;e+=o.charCodeAt(0)<128?o:t}return e}function m(r){return u(r).match(_)||[]}function C(r){return u(r).replace(/[^a-z0-9]+/g,"")}function b(r){return r.replace(/ue/g,"u").replace(/oe/g,"o").replace(/ae/g,"a").replace(/ss/g,"s")}function F(r){let e=[];for(let t of m(r)){let n=[t],o=b(t);o&&o!==t&&n.push(o),e.push(n)}return e}function p(r,e){if(r===e)return!0;let t=r.length,n=e.length;if(Math.abs(t-n)>1)return!1;if(t===n){let l=[];for(let i=0;i<t;i++)r[i]!==e[i]&&l.push(i);if(l.length===1)return!0;if(l.length===2&&l[1]===l[0]+1){let i=l[0];return r[i]===e[i+1]&&r[i+1]===e[i]}return!1}let[o,s]=t>n?[r,e]:[e,r],c=0,f=0,a=!1;for(;c<o.length&&f<s.length;)if(o[c]===s[f])c++,f++;else{if(a)return!1;a=!0,c++}return!0}function N(r,e){let t=0;for(let n of r)if(n){if(e===n)return d;if(e.startsWith(n)){t=Math.max(t,R);continue}if(n.length>=x&&e.includes(n)){t=Math.max(t,g);continue}n.length>=S&&t<h&&(p(n,e)||e.length>n.length&&p(n,e.slice(0,n.length)))&&(t=h)}return t}function I(r,e){let t=0;for(let n of m(e))if(t=Math.max(t,N(r,n)),t===d)return t;if(t<g){let n=C(e);for(let o of r)if(o.length>=x&&n.includes(o))return g}return t}function O(r,e){if(!r)return!1;let t=F(e);if(!t.length){let n=u(e.trim());return n.length>0&&u(r).includes(n)}return M(t,[{text:r,weight:1}])>0}function M(r,e){if(!r.length)return 0;let t=e.filter(o=>o.text),n=0;for(let o of r){let s=0;for(let c of t){let f=I(o,c.text)*c.weight;f>s&&(s=f)}if(s===0)return 0;n+=s}return n}export{F as a,O as b,M as c};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{b as x}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-EOMYEBQ4.js";import{a as H,e as S}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-MMIPM7EE.js";import{B as k,C as A,z as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";var V=500,B=new Set(["completed","skipped","reset","missed"]);function M(r,e){let o=r.reading_values||[];return o.length?o.filter(n=>typeof n.value=="number").map(n=>({id:n.id,name:n.name||"",value:n.value,unit:n.unit||""})):typeof r.reading_value=="number"?[{id:"",name:"",value:r.reading_value,unit:e||""}]:[]}function O(r){let e=[];for(let o of r){let n=[...o.history??[]].map(t=>({h:t,ts:k(t.timestamp)})).filter(t=>Number.isFinite(t.ts)).sort((t,a)=>t.ts-a.ts),s=new Map;for(let{h:t,ts:a}of n){let y=M(t,o.reading_unit).map(u=>{let f=s.get(u.id);return s.set(u.id,u.value),{name:u.name,value:u.value,unit:u.unit,delta:f==null?null:u.value-f}});if(!B.has(t.type))continue;let c=t.checklist_state&&typeof t.checklist_state=="object"?Object.values(t.checklist_state):null;e.push({ts:a,timestamp:t.timestamp,taskId:o.id,taskName:o.name,type:t.type,cost:S(t),partsCost:typeof t.parts_cost=="number"?t.parts_cost:null,partsCounted:t.cost_basis==="use",purchaseCost:t.cost_basis==="use"&&t.purchase&&typeof t.cost=="number"?t.cost:null,duration:typeof t.duration=="number"?t.duration:null,notes:t.notes??null,completedBy:t.completed_by??null,phaseName:t.phase_id&&o.phases?.[t.phase_id]?.name||null,refNo:typeof t.ref_no=="number"?t.ref_no:null,taskRefNo:typeof o.ref_no=="number"?o.ref_no:null,readings:y,parts:(t.used_parts||[]).filter(u=>u&&(u.name||u.part_id)).map(u=>({name:u.name||u.part_id,quantity:typeof u.quantity=="number"?u.quantity:1})),photoIds:H(t),checklist:c&&c.length?{done:c.filter(Boolean).length,total:c.length}:null})}}return e.sort((o,n)=>n.ts-o.ts||o.taskName.localeCompare(n.taskName)),e}function R(r,e){return r.filter(o=>{if(e.taskId&&o.taskId!==e.taskId)return!1;if(!e.from&&!e.to)return!0;let n=A(o.timestamp);return!(!n||e.from&&n<e.from||e.to&&n>e.to)})}function E(r){let e=0,o=0;for(let n of r)n.type==="completed"&&(e++,n.cost!=null&&(o+=n.cost));return{completed:e,totalCost:o}}var d="__none__",L=36;function T(r){return r.area_id||d}function K(r,e,o){return r===d?o:e?.[r]?.name||r}function Y(r,e){return r===d?"mdi:map-marker-off-outline":e?.[r]?.icon||"mdi:map-marker-outline"}function J(r,e,o){return r.filter(n=>(o||!n.object.archived)&&T(n.object)===e)}function D(r,e){let o=[];for(let n of r){let s=O(n.tasks.map(t=>({id:t.id,name:t.name,history:e(n.entry_id,t),phases:t.phases,ref_no:t.ref_no,reading_unit:t.reading_unit})));for(let t of s)o.push({...t,entryId:n.entry_id,objectName:n.object.name})}return o.sort((n,s)=>s.ts-n.ts||n.objectName.localeCompare(s.objectName)||n.taskName.localeCompare(s.taskName)),o}function W(r,e){let o=(e.taskQuery??"").trim();return R(r,{from:e.from,to:e.to}).filter(n=>(!e.entryId||n.entryId===e.entryId)&&(!o||x(n.taskName,o)))}function Z(r){let{completed:e,totalCost:o}=E(r),n=0,s=0,t=0;for(let a of r)a.type==="completed"&&(a.duration!=null&&(n+=a.duration),!((a.cost??0)<0)&&(s++,t+=a.cost??0));return{completions:e,totalCost:o,avgCost:s?t/s:null,totalDuration:n}}function tt(r,e){let o=new Map;for(let t of e)o.set(t.entry_id,{entryId:t.entry_id,objectName:t.object.name,completions:0,cost:0,share:0});for(let t of r){if(t.type!=="completed")continue;let a=o.get(t.entryId);a&&(a.completions++,t.cost!=null&&(a.cost+=t.cost))}let n=[...o.values()].reduce((t,a)=>t+Math.max(a.cost,0),0),s=[...o.values()].map(t=>({...t,share:n>0?Math.max(t.cost,0)/n:0}));return s.sort((t,a)=>a.cost-t.cost||a.completions-t.completions||t.objectName.localeCompare(a.objectName)),s}function C(r){let[e,o]=r.split("-").map(Number);return[e,o-1]}function I(r,e){return`${r}-${String(e+1).padStart(2,"0")}`}function et(r,e,o=v()){let n=r.filter(i=>i.type==="completed"),s=n.map(i=>A(i.timestamp)),t=s.filter(i=>i!==null),a=t.reduce((i,m)=>m<i?m:i,o),y=t.reduce((i,m)=>m>i?m:i,o),[c,u]=C(e.from||a),[f,h]=C(e.to||y),l=f*12+h-(c*12+u)+1;if(l<=0)return{unit:"month",buckets:[]};let g=l>L?"year":"month",_=[],j=new Map;if(g==="month")for(let i=0;i<l;i++){let m=c+Math.floor((u+i)/12),b=(u+i)%12,p={key:I(m,b),year:m,month:b,cost:0,completions:0};_.push(p),j.set(p.key,p)}else for(let i=c;i<=f;i++){let m={key:String(i),year:i,month:null,cost:0,completions:0};_.push(m),j.set(m.key,m)}return n.forEach((i,m)=>{let b=s[m];if(!b)return;let p=j.get(g==="month"?b.slice(0,7):b.slice(0,4));p&&(p.completions++,i.cost!=null&&(p.cost+=i.cost))}),{unit:g,buckets:_}}function rt(r=v()){let[e,o]=C(r),n=e*12+o-11;return{from:`${I(Math.floor(n/12),n%12)}-01`,to:r}}function nt(r){return{from:`${r}-01-01`,to:`${r}-12-31`}}function w(r){let e=A(r.timestamp);return e?Number(e.slice(0,4)):null}function ot(r,e){let o=new Set([e]);for(let n of r){let s=n.type==="completed"?w(n):null;s!==null&&o.add(s)}return[...o].sort((n,s)=>s-n)}function st(r,e){let o=new Map;for(let s of r){if(!Line truncated
|
||||
@@ -0,0 +1,37 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{B as k,L as R,N as x,a as m,b as h,ba as w,c as g,f as v,h as b,m as y,n as _,t as l}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";function E(i){return`${i.entry_id??""}\0${i.part_id}`}function S(i,t,e,o){let n=!!i.entry_id&&i.entry_id!==t,r=n?i.entry_id:t,s=e.find(p=>p.entry_id===r),a=(s?.parts||[]).find(p=>p.id===i.part_id)||null,c=n&&s?.object?.name||"",u=a?.name||l("shared_part_unknown",o);return{part:a,foreign:n,ownerName:c,label:c?`${u} (${c})`:u}}function N(i,t,e,o){let{part:n,label:r}=S(i,t,e,o),s=n&&n.stock!==null&&n.stock!==void 0?` (${x(n.stock,n.unit,o)})`:"",a=n?.storage_location?` \u2014 ${n.storage_location}`:"";return`${R(i.quantity,o)}\xD7 ${r}${s}${a}`}function V(i,t,e,o){let r=(e.find(a=>a.entry_id===t)?.parts||[]).map(a=>({...a})),s=new Set(r.map(a=>E({part_id:a.id})));for(let a of i?.consumes_parts||[]){if(!a.entry_id||a.entry_id===t)continue;let c=E(a);if(s.has(c))continue;s.add(c);let{part:u,ownerName:p}=S(a,t,e,o);r.push({id:a.part_id,name:u?.name||l("shared_part_unknown",o),unit:u?.unit,stock:u?.stock??null,storage_location:u?.storage_location,entry_id:a.entry_id,owner_name:p})}return r}var L=20;function T(){let i=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:t=>t.map(()=>Math.floor(Math.random()*256))}).getRandomValues(i),Array.from(i,t=>t.toString(16).padStart(2,"0")).join("")}function f(i){let t=i?.reading_values;if(!Array.isArray(t))return[];let e=[],o=new Set;for(let n of t){if(!n||typeof n!="object")continue;let r=n;typeof r.id!="string"||!r.id||o.has(r.id)||typeof r.value!="number"||!Number.isFinite(r.value)||(o.add(r.id),e.push({id:r.id,name:typeof r.name=="string"?r.name:r.id,unit:typeof r.unit=="string"?r.unit:null,value:r.value}))}return e}function P(i){return i.filter(t=>t.type==="completed"&&(t.reading_value!=null||f(t).length>0)).sort((t,e)=>t.timestamp.localeCompare(e.timestamp))}function M(i){return P(i??[]).map(t=>({timestamp:t.timestamp,values:f(t)})).filter(t=>t.values.length>0)}function A(i,t,e){let o;for(let n of i){if(e!==void 0){let s=k(n.timestamp);if(!isNaN(s)&&s>=e)break}let r=n.values.find(s=>s.id===t);r&&(o=r)}return o}function C(i,t,e){let o=f(t).find(r=>r.id===e);if(!o)return null;let n=null;for(let r of P(i)){if(r.timestamp>=t.timestamp)break;let s=f(r).find(a=>a.id===e);s&&(n=s.value)}return n==null?null:o.value-n}function D(i){let t=new Set,e=new Set;for(let o of i){let n=(o.name||"").trim().toLowerCase();n&&(t.has(n)?e.add(o.id):t.add(n))}return e}function F(i){let t=[],e=new Set,o=new Set;for(let n of i){let r=(n.name||"").trim();if(!(!r||e.has(n.id)||o.has(r.toLowerCase()))&&(e.add(n.id),o.add(r.toLowerCase()),t.push({id:n.id,name:r,unit:(n.unit||"").trim()||null}),t.length>=L))break}return t}function j(i){let t=(i??"").trim();if(t==="")return null;let e=Number(t.replace(",","."));return!Number.isFinite(e)||e<0?null:Math.round(e)}var B=["notes","cost","duration","photo","user"],I={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"};var d=class extends b{constructor(){super(...arguments);this.value="";this.lang="en";this._credit=!1;this._amount=""}willUpdate(e){if(!e.has("value"))return;let o=(this.value??"").trim();if(o===this._signed())return;let n=parseFloat(o);if(o===""||Number.isNaN(n)){this._amount="",this._credit=!1;return}this._credit=n<0,this._amount=String(Math.abs(n))}_signed(){let e=this._amount.trim();return e===""?"":this._credit?`-${e}`:e}_emit(){this.value=this._signed(),this.dispatchEvent(new CustomEvent("value-changed",{detail:{value:this.value},bubbles:!0,composed:!0}))}_setCredit(e){this._credit!==e&&(this._credit=e,this._emit())}_onInput(e){let o=e.target.value;o.startsWith("-")&&(this._credit=!0),this._amount=o.replace(/^-+/,""),this._emit()}render(){let e=this.lang;return g`
|
||||
<div class="wrap">
|
||||
<div class="sign" role="group">
|
||||
<button type="button" class="kind cost ${this._credit?"":"on"}" aria-pressed=${String(!this._credit)}
|
||||
@click=${()=>this._setCredit(!1)}>${l("cost",e)}</button>
|
||||
<button type="button" class="kind credit ${this._credit?"on":""}" aria-pressed=${String(this._credit)}
|
||||
@click=${()=>this._setCredit(!0)}>${l("cost_kind_credit",e)}</button>
|
||||
</div>
|
||||
<input type="number" step="0.01" min="0" inputmode="decimal" class="field-input amount"
|
||||
.value=${this._amount} @input=${this._onInput} />
|
||||
</div>
|
||||
${this._credit?g`<div class="hint">${l("cost_credit_hint",e)}</div>`:v}
|
||||
`}};d.styles=[w,h`
|
||||
:host { display: block; }
|
||||
.wrap { display: flex; gap: 8px; align-items: stretch; }
|
||||
.sign {
|
||||
display: inline-flex;
|
||||
flex: none;
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.kind {
|
||||
font: inherit;
|
||||
font-size: 13px;
|
||||
padding: 0 10px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--secondary-text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
.kind.on { background: var(--primary-color); color: var(--text-primary-color, #fff); }
|
||||
.kind.credit.on { background: var(--success-color, #43a047); }
|
||||
.amount { flex: 1; min-width: 0; }
|
||||
.hint { margin-top: 4px; font-size: 12px; color: var(--secondary-text-color); }
|
||||
`],m([y()],d.prototype,"value",2),m([y()],d.prototype,"lang",2),m([_()],d.prototype,"_credit",2),m([_()],d.prototype,"_amount",2);customElements.get("ms-cost-input")||customElements.define("ms-cost-input",d);export{E as a,N as b,V as c,L as d,T as e,f,M as g,A as h,C as i,D as j,F as k,j as l,B as m,I as n};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{t as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";var _=[{key:"name",labelKey:"name",required:!0},{key:"ref_no",labelKey:"ref_number"},{key:"manufacturer",labelKey:"manufacturer"},{key:"model",labelKey:"model"},{key:"serial_number",labelKey:"serial_number_label"},{key:"installation_date",labelKey:"installed"},{key:"warranty_expiry",labelKey:"warranty"},{key:"area_id",labelKey:"area"},{key:"documentation_url",labelKey:"documentation_url_label"},{key:"notes",labelKey:"object_notes_label"},{key:"task_count",labelKey:"tasks"},{key:"actions",labelKey:"actions"}],u=_.map(e=>e.key),i=["name","manufacturer","model","serial_number","installation_date","warranty_expiry","area_id","task_count","actions"];function g(e){if(!Array.isArray(e))return[...i];let n=new Set,r=[];for(let t of e)typeof t=="string"&&u.includes(t)&&!n.has(t)&&(n.add(t),r.push(t));return r.length?(r.includes("name")||r.unshift("name"),r):[...i]}function f(e,n){return a(`home_dwelling_${e==="house"||e==="apartment"?e:"unknown"}`,n)}function m(e,n){if(!e)return"";try{return new Intl.DisplayNames([n],{type:"region"}).of(e)||e}catch{return e}}var l={floors:"home_reason_floors",basement_floor:"home_reason_basement",area_basement:"home_reason_basement",area_garden:"home_reason_garden",area_shed:"home_reason_shed",area_driveway:"home_reason_driveway",area_garage:"home_reason_garage",entity_garage:"home_reason_garage",area_attic:"home_reason_attic",entity_lawn_mower:"home_reason_lawn_mower",entity_gate:"home_reason_gate",area_balcony:"home_reason_balcony",small_home:"home_reason_small_home"},c={ups:"home_reason_ups"};function d(e,n){let r=[];for(let t of e){let o=l[t];if(!o)continue;let s=a(o,n);r.includes(s)||r.push(s)}return r.join(", ")}function b(e,n,r){if(e==="starter")return a("home_reason_starter",n);if(e==="country")return a("home_reason_country",n).replace("{country}",m(r,n));if(e.startsWith("feature_")){let t=e.slice(8),o=l[`area_${t}`]??c[t];return a("home_reason_feature",n).replace("{feature}",o?a(o,n):e)}return a(`home_trait_${e}`,n)}export{_ as a,i as b,g as c,f as d,m as e,d as f,b as g};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{a as y}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-FH35SLMS.js";var l=6;async function g(e,i,n){let r=new Array(e.length),a=0,t=async()=>{for(;a<e.length;){let s=a++;r[s]=await n(e[s],s)}},o=Math.min(Math.max(1,i),e.length);return await Promise.all(Array.from({length:o},t)),r}function u(e){let i=e.history?.length??0;return typeof e.history_count!="number"||e.history_count>i}function d(e){return JSON.stringify([e.history_count??null,e.history??[]])}function h(e,i){return`${e}:${i}`}var c=class{constructor(i){this._host=i;this._cache=new Map;this._inFlight=new Map;this._running=0;this._pending=Promise.resolve();this.version=0;i.addController(this)}hostConnected(){}get loading(){return this._running>0}get capped(){for(let i of this._cache.values())if(i.entries.length>=y)return!0;return!1}historyOf(i,n){return this._cache.get(h(i,n.id))?.entries??n.history??[]}sync(i,n){if(!i?.connection)return this._pending;let r=n.filter(t=>u(t.task)).map(t=>({...t,key:h(t.entryId,t.task.id),sig:d(t.task)})).filter(t=>this._cache.get(t.key)?.sig!==t.sig&&this._inFlight.get(t.key)!==t.sig);if(!r.length)return this._pending;for(let t of r)this._inFlight.set(t.key,t.sig);this._running++,this._host.requestUpdate();let a=g(r,l,async t=>{let o;try{let s=await i.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:t.entryId,task_id:t.task.id});o=Array.isArray(s?.history)?s.history:t.task.history??[]}catch{o=t.task.history??[]}this._inFlight.get(t.key)===t.sig&&(this._inFlight.delete(t.key),this._cache.set(t.key,{sig:t.sig,entries:o}))}).then(()=>{this._running--,this.version++,this._host.requestUpdate()});return this._pending=Promise.all([this._pending,a]).then(()=>{}),this._pending}settled(){return this._pending}};export{c as a};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.103.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,2 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{P as n,t as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";var l={"Completed from dashboard button":"hist_note_button","Completed from the To-do list":"hist_note_todo","Completed by voice":"hist_note_voice","Completed from the notification":"hist_note_notification","Completed via NFC tag":"hist_note_nfc","Completed from the shopping list":"hist_note_shopping_list","Completed from a mirrored to-do list":"hist_note_todo_mirror","Skipped from notification":"hist_note_skipped_notification","Skipped from dashboard button":"hist_note_skipped_button","Sensor trigger activated":"hist_note_sensor_triggered","Initial value set during task creation":"hist_note_initial"},m=[[/^Auto-completed: sensor recovered \((.+)\)$/,"hist_note_auto_recovered",t=>({value:t[1]})],[/^Reset to (\d{4}-\d{2}-\d{2})$/,"hist_note_reset",(t,e)=>({date:n(t[1],e)})],[/^Trigger entity replaced: (.+) → (.+)$/,"hist_note_trigger_replaced",t=>({old:t[1],new:t[2]})],[/^Sensor trigger removed \(entity was: (.+)\)\. Schedule converted to (\w+)\.$/,"hist_note_trigger_removed",(t,e)=>({entity:t[1],schedule:o(t[2],e)})],[/^Entity (.+) removed from compound trigger; (\d+) conditions remain\.$/,"hist_note_compound_removed",t=>({entity:t[1],count:t[2]})]];function h(t,e){if(!t)return"";let i=l[t.trim()];if(i)return o(i,e);for(let[s,d,_]of m){let r=t.trim().match(s);if(r){let c=_(r,e);return o(d,e).replace(/\{(\w+)\}/g,(a,g)=>c[g]??a)}}return t}export{h as a};
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
function c(n){return n==="use"?"use":"purchase"}var s=n=>typeof n=="number"&&Number.isFinite(n)?n:null;function a(n){let t=s(n?.cost);if(t===null)return null;let o=s(n?.package_size);return o&&o>0?t/o:t}function p(n,t){let o=s(t)&&t>0?t:s(n.restock_quantity)||1,e=s(n.package_size);return Math.round(o*(e&&e>0?e:1)*100)/100}function l(n){let t=s(n.cost);if(n.cost_basis!=="use")return t;let o=s(n.parts_cost),e=n.purchase?null:t;return e===null&&o===null?null:(e??0)+(o??0)}function _(n){if(!n)return[];let t=[],o=n.photo_doc_id;typeof o=="string"&&t.push(o);let e=n.photo_doc_ids;Array.isArray(e)&&t.push(...e);let r=[];for(let u of t){if(typeof u!="string")continue;let i=u.trim();if(!(!i||r.includes(i))&&(r.push(i),r.length>=10))break}return r}export{_ as a,c as b,a as c,p as d,l as e};
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,33 @@
|
||||
/*! maintenance_supporter frontend 2.103.0 */
|
||||
import{b as r,c as t}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-OWNF6K2Z.js";var d=r`
|
||||
.backdrop {
|
||||
position: fixed; inset: 0; z-index: var(--ms-modal-z, 100);
|
||||
background: rgba(0,0,0,0.5);
|
||||
}
|
||||
.dialog {
|
||||
position: fixed; left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 95vw; max-width: var(--ms-modal-max-width, 480px);
|
||||
max-height: var(--ms-modal-max-height, 92vh); overflow: auto;
|
||||
background: var(--card-background-color, var(--ha-card-background, #1c1c1c));
|
||||
color: var(--primary-text-color);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
|
||||
padding: 20px;
|
||||
display: flex; flex-direction: column; gap: var(--ms-modal-gap, 14px);
|
||||
z-index: calc(var(--ms-modal-z, 100) + 1);
|
||||
}
|
||||
/* Focused programmatically on open (so Escape works at once) — no ring. */
|
||||
.dialog:focus { outline: none; }
|
||||
/* The one part that shrinks and scrolls (min-height: 0); the header and the
|
||||
buttons around it keep their content's height. */
|
||||
.dialog-scroll {
|
||||
flex: 1 1 auto; min-height: 0;
|
||||
overflow-y: auto; overscroll-behavior: contain;
|
||||
display: flex; flex-direction: column; gap: var(--ms-modal-gap, 14px);
|
||||
}
|
||||
`;function l(o,a){o.key!=="Escape"||o.defaultPrevented||o.composedPath().some(e=>e instanceof Element&&e.localName==="ms-camera-capture")||(o.preventDefault(),o.stopPropagation(),a())}function i(o,a){return t`
|
||||
<div class="backdrop" @click=${o}></div>
|
||||
<div class="dialog" role="dialog" aria-modal="true" tabindex="-1"
|
||||
@keydown=${e=>l(e,o)}>${a}</div>
|
||||
`}function c(o){o?.querySelector(".dialog")?.focus({preventScroll:!0})}export{d as a,i as b,c};
|
||||
Loaded 100 of 291 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user