185 files
This commit is contained in:
1 parent
5f9330abd7
commit
a718af6423
185 files changed
+16868
-3088
No files matched your search
@@ -138,6 +138,9 @@ SERVICE_COMPLETE_SCHEMA = vol.Schema(
|
||||
# #128: who did it — a person ENTITY (validated picker, no free text);
|
||||
# resolved to the linked HA user id. Omitted -> the calling user.
|
||||
vol.Optional("completed_by"): cv.entity_id,
|
||||
# #133: when the maintenance was actually performed (backfill a past
|
||||
# completion). Future values are rejected by the coordinator.
|
||||
vol.Optional("completed_at"): cv.datetime,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -474,6 +477,7 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool:
|
||||
duration=call.data.get("duration"),
|
||||
reading_value=call.data.get("reading_value"),
|
||||
completed_by=completed_by,
|
||||
completed_at=call.data.get("completed_at"),
|
||||
)
|
||||
|
||||
async def _handle_reset(call: ServiceCall) -> None:
|
||||
|
||||
@@ -59,6 +59,10 @@ class TriggerStepsMixin(TriggerConfigMixin):
|
||||
parts.append(f"above: {cond['trigger_above']}")
|
||||
if cond.get("trigger_below") is not None:
|
||||
parts.append(f"below: {cond['trigger_below']}")
|
||||
if cond.get("trigger_equals") is not None:
|
||||
parts.append(f"= {cond['trigger_equals']}")
|
||||
if cond.get("trigger_not_equals") is not None:
|
||||
parts.append(f"≠ {cond['trigger_not_equals']}")
|
||||
if cond.get("trigger_for_minutes"):
|
||||
parts.append(f"for: {cond['trigger_for_minutes']}min")
|
||||
elif ctype == TriggerType.COUNTER:
|
||||
@@ -97,6 +101,10 @@ class TriggerStepsMixin(TriggerConfigMixin):
|
||||
config_parts.append(f"above: {tc['trigger_above']}")
|
||||
if tc.get("trigger_below") is not None:
|
||||
config_parts.append(f"below: {tc['trigger_below']}")
|
||||
if tc.get("trigger_equals") is not None:
|
||||
config_parts.append(f"= {tc['trigger_equals']}")
|
||||
if tc.get("trigger_not_equals") is not None:
|
||||
config_parts.append(f"≠ {tc['trigger_not_equals']}")
|
||||
if tc.get("trigger_for_minutes"):
|
||||
config_parts.append(f"for: {tc['trigger_for_minutes']}min")
|
||||
elif trigger_type == TriggerType.COUNTER:
|
||||
|
||||
@@ -44,11 +44,14 @@ from .const import (
|
||||
CONF_TRIGGER_ABOVE,
|
||||
CONF_TRIGGER_ATTRIBUTE,
|
||||
CONF_TRIGGER_BELOW,
|
||||
CONF_TRIGGER_COMBINATOR,
|
||||
CONF_TRIGGER_DELTA_MODE,
|
||||
CONF_TRIGGER_ENTITY,
|
||||
CONF_TRIGGER_ENTITY_LOGIC,
|
||||
CONF_TRIGGER_EQUALS,
|
||||
CONF_TRIGGER_FOR_MINUTES,
|
||||
CONF_TRIGGER_FROM_STATE,
|
||||
CONF_TRIGGER_NOT_EQUALS,
|
||||
CONF_TRIGGER_ON_STATES,
|
||||
CONF_TRIGGER_RUNTIME_HOURS,
|
||||
CONF_TRIGGER_TARGET_CHANGES,
|
||||
@@ -133,7 +136,7 @@ def _entity_logic_field(entity_ids: list[Any]) -> dict[Any, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _interval_warning_fields(hass: HomeAssistant) -> dict[Any, Any]:
|
||||
def _interval_warning_fields(hass: HomeAssistant, tc: dict[str, Any] | None = None) -> dict[Any, Any]:
|
||||
"""The safety-interval + warning-days tail shared by all four type steps."""
|
||||
return {
|
||||
vol.Optional(CONF_TASK_INTERVAL_DAYS): selector.NumberSelector(
|
||||
@@ -145,6 +148,19 @@ def _interval_warning_fields(hass: HomeAssistant) -> dict[Any, Any]:
|
||||
)
|
||||
),
|
||||
vol.Optional(CONF_TASK_INTERVAL_UNIT, default="days"): interval_unit_selector(),
|
||||
vol.Optional(
|
||||
CONF_TRIGGER_COMBINATOR,
|
||||
default=(tc or {}).get(CONF_TRIGGER_COMBINATOR, DEFAULT_ENTITY_LOGIC),
|
||||
): selector.SelectSelector(
|
||||
selector.SelectSelectorConfig(
|
||||
options=[
|
||||
selector.SelectOptionDict(value="any", label="Trigger or interval (whichever first)"),
|
||||
selector.SelectOptionDict(value="all", label="Trigger and interval (both required)"),
|
||||
],
|
||||
mode=selector.SelectSelectorMode.DROPDOWN,
|
||||
translation_key="trigger_combinator",
|
||||
)
|
||||
),
|
||||
vol.Optional(
|
||||
CONF_TASK_WARNING_DAYS,
|
||||
default=get_default_warning_days(hass),
|
||||
@@ -156,6 +172,14 @@ def _interval_warning_fields(hass: HomeAssistant) -> dict[Any, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _apply_combinator(tc: dict[str, Any], user_input: dict[str, Any]) -> None:
|
||||
"""Store the trigger∧interval combinator; absence means the default "any"."""
|
||||
if user_input.get(CONF_TRIGGER_COMBINATOR) == "all":
|
||||
tc[CONF_TRIGGER_COMBINATOR] = "all"
|
||||
else:
|
||||
tc.pop(CONF_TRIGGER_COMBINATOR, None)
|
||||
|
||||
|
||||
def _state_selector(entity_id: str | None, *, multiple: bool = False) -> Any:
|
||||
"""State field bound to the trigger entity (#129 follow-up).
|
||||
|
||||
@@ -463,8 +487,10 @@ class TriggerConfigMixin:
|
||||
|
||||
above = user_input.get(CONF_TRIGGER_ABOVE)
|
||||
below = user_input.get(CONF_TRIGGER_BELOW)
|
||||
equals = user_input.get(CONF_TRIGGER_EQUALS)
|
||||
not_equals = user_input.get(CONF_TRIGGER_NOT_EQUALS)
|
||||
|
||||
if above is None and below is None:
|
||||
if above is None and below is None and equals is None and not_equals is None:
|
||||
errors["base"] = "invalid_threshold"
|
||||
else:
|
||||
tc = self._current_task["trigger_config"]
|
||||
@@ -472,8 +498,13 @@ class TriggerConfigMixin:
|
||||
tc[CONF_TRIGGER_ABOVE] = above
|
||||
if below is not None:
|
||||
tc[CONF_TRIGGER_BELOW] = below
|
||||
if equals is not None:
|
||||
tc[CONF_TRIGGER_EQUALS] = equals
|
||||
if not_equals is not None:
|
||||
tc[CONF_TRIGGER_NOT_EQUALS] = not_equals
|
||||
tc[CONF_TRIGGER_FOR_MINUTES] = user_input.get(CONF_TRIGGER_FOR_MINUTES, 0)
|
||||
_apply_recovery_flag(tc, user_input)
|
||||
_apply_combinator(tc, user_input)
|
||||
|
||||
# Multi-entity: store entity_logic if multiple entities selected
|
||||
entity_ids = tc.get("entity_ids", [])
|
||||
@@ -509,13 +540,25 @@ class TriggerConfigMixin:
|
||||
step="any",
|
||||
)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_EQUALS): selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(
|
||||
mode=selector.NumberSelectorMode.BOX,
|
||||
step="any",
|
||||
)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_NOT_EQUALS): selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(
|
||||
mode=selector.NumberSelectorMode.BOX,
|
||||
step="any",
|
||||
)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_FOR_MINUTES, default=0): selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(min=0, max=1440, step=1, mode=selector.NumberSelectorMode.BOX)
|
||||
),
|
||||
**_recovery_field(self._current_task.get("trigger_config")),
|
||||
}
|
||||
schema_fields.update(_entity_logic_field(self._current_task.get("trigger_config", {}).get("entity_ids", [])))
|
||||
schema_fields.update(_interval_warning_fields(self.hass))
|
||||
schema_fields.update(_interval_warning_fields(self.hass, self._current_task.get("trigger_config")))
|
||||
|
||||
return self.async_show_form(
|
||||
step_id=step_id,
|
||||
@@ -541,6 +584,7 @@ class TriggerConfigMixin:
|
||||
tc[CONF_TRIGGER_TARGET_VALUE] = user_input[CONF_TRIGGER_TARGET_VALUE]
|
||||
tc[CONF_TRIGGER_DELTA_MODE] = user_input.get(CONF_TRIGGER_DELTA_MODE, False)
|
||||
_apply_recovery_flag(tc, user_input)
|
||||
_apply_combinator(tc, user_input)
|
||||
# Counting start value (#102/#103): editable here since the parity
|
||||
# round — an omitted field keeps the value the attribute step
|
||||
# carried over; the backend clears stale Store state on change.
|
||||
@@ -601,7 +645,7 @@ class TriggerConfigMixin:
|
||||
**_recovery_field(prev_tc),
|
||||
}
|
||||
schema_fields.update(_entity_logic_field(self._current_task.get("trigger_config", {}).get("entity_ids", [])))
|
||||
schema_fields.update(_interval_warning_fields(self.hass))
|
||||
schema_fields.update(_interval_warning_fields(self.hass, self._current_task.get("trigger_config")))
|
||||
|
||||
return self.async_show_form(
|
||||
step_id=step_id,
|
||||
@@ -638,6 +682,7 @@ class TriggerConfigMixin:
|
||||
tc[CONF_TRIGGER_TO_STATE] = to_state
|
||||
tc[CONF_TRIGGER_TARGET_CHANGES] = user_input.get(CONF_TRIGGER_TARGET_CHANGES, 1)
|
||||
_apply_recovery_flag(tc, user_input)
|
||||
_apply_combinator(tc, user_input)
|
||||
|
||||
# Multi-entity: store entity_logic if multiple entities selected
|
||||
entity_ids = tc.get("entity_ids", [])
|
||||
@@ -669,7 +714,7 @@ class TriggerConfigMixin:
|
||||
**_recovery_field(self._current_task.get("trigger_config")),
|
||||
}
|
||||
schema_fields.update(_entity_logic_field(self._current_task.get("trigger_config", {}).get("entity_ids", [])))
|
||||
schema_fields.update(_interval_warning_fields(self.hass))
|
||||
schema_fields.update(_interval_warning_fields(self.hass, self._current_task.get("trigger_config")))
|
||||
|
||||
return self.async_show_form(
|
||||
step_id=step_id,
|
||||
@@ -701,6 +746,7 @@ class TriggerConfigMixin:
|
||||
else:
|
||||
tc.pop(CONF_TRIGGER_ON_STATES, None)
|
||||
_apply_recovery_flag(tc, user_input)
|
||||
_apply_combinator(tc, user_input)
|
||||
|
||||
# Multi-entity: store entity_logic if multiple entities selected
|
||||
entity_ids = tc.get("entity_ids", [])
|
||||
@@ -740,7 +786,7 @@ class TriggerConfigMixin:
|
||||
**_recovery_field(current_tc),
|
||||
}
|
||||
schema_fields.update(_entity_logic_field(self._current_task.get("trigger_config", {}).get("entity_ids", [])))
|
||||
schema_fields.update(_interval_warning_fields(self.hass))
|
||||
schema_fields.update(_interval_warning_fields(self.hass, self._current_task.get("trigger_config")))
|
||||
|
||||
return self.async_show_form(
|
||||
step_id=step_id,
|
||||
@@ -920,6 +966,12 @@ class TriggerConfigMixin:
|
||||
cond["trigger_above"] = above
|
||||
if below is not None:
|
||||
cond["trigger_below"] = below
|
||||
equals = user_input.get(CONF_TRIGGER_EQUALS)
|
||||
if equals is not None:
|
||||
cond["trigger_equals"] = equals
|
||||
not_equals = user_input.get(CONF_TRIGGER_NOT_EQUALS)
|
||||
if not_equals is not None:
|
||||
cond["trigger_not_equals"] = not_equals
|
||||
for_min = user_input.get(CONF_TRIGGER_FOR_MINUTES)
|
||||
if for_min:
|
||||
cond["trigger_for_minutes"] = for_min
|
||||
@@ -957,6 +1009,12 @@ class TriggerConfigMixin:
|
||||
vol.Optional(CONF_TRIGGER_BELOW): selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(mode=selector.NumberSelectorMode.BOX)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_EQUALS): selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(mode=selector.NumberSelectorMode.BOX)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_NOT_EQUALS): selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(mode=selector.NumberSelectorMode.BOX)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_FOR_MINUTES, default=0): selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(
|
||||
min=0,
|
||||
|
||||
@@ -401,7 +401,14 @@ DEFAULT_ENTITY_LOGIC = "any"
|
||||
CONF_TRIGGER_ATTRIBUTE = "trigger_attribute"
|
||||
CONF_TRIGGER_ABOVE = "trigger_above"
|
||||
CONF_TRIGGER_BELOW = "trigger_below"
|
||||
CONF_TRIGGER_EQUALS = "trigger_equals"
|
||||
CONF_TRIGGER_NOT_EQUALS = "trigger_not_equals"
|
||||
CONF_TRIGGER_FOR_MINUTES = "trigger_for_minutes"
|
||||
# How the trigger combines with the safety interval on the same task:
|
||||
# "any" (default) — whichever fires first makes the task due;
|
||||
# "all" — the task only becomes due once the trigger fired AND the interval
|
||||
# elapsed (the interval acts as a minimum age, not a deadline).
|
||||
CONF_TRIGGER_COMBINATOR = "trigger_combinator"
|
||||
CONF_TRIGGER_TARGET_VALUE = "trigger_target_value"
|
||||
CONF_TRIGGER_DELTA_MODE = "trigger_delta_mode"
|
||||
CONF_TRIGGER_BASELINE_VALUE = "trigger_baseline_value"
|
||||
@@ -622,6 +629,22 @@ class HistoryEntryType(StrEnum):
|
||||
TRIGGER_REPLACED = "trigger_replaced"
|
||||
|
||||
|
||||
# Entry types that reset the maintenance cycle — the ``last_performed`` anchor
|
||||
# is always the LATEST such entry (by timestamp). Shared by the history-edit
|
||||
# reconciliation and the backdated-completion path (#133) so the two can't
|
||||
# drift on what counts as a cycle anchor. MISSED is included because
|
||||
# ``skip(as_missed=True)`` moves ``last_performed`` exactly like a skip —
|
||||
# the edit path historically omitted it (latent reconciliation gap).
|
||||
LIFECYCLE_HISTORY_TYPES = frozenset(
|
||||
{
|
||||
HistoryEntryType.COMPLETED,
|
||||
HistoryEntryType.RESET,
|
||||
HistoryEntryType.SKIPPED,
|
||||
HistoryEntryType.MISSED,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class MaintenanceFeedback(StrEnum):
|
||||
"""Feedback from user about whether maintenance was needed."""
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import time
|
||||
from datetime import date, timedelta
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
@@ -907,6 +907,7 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
used_parts: list[dict[str, Any]] | None = None,
|
||||
auto: bool = False,
|
||||
unattended: bool = False,
|
||||
completed_at: datetime | None = None,
|
||||
) -> None:
|
||||
"""Mark a task as completed and persist.
|
||||
|
||||
@@ -915,12 +916,28 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
voice command. Those paths attach a canned provenance note
|
||||
("Completed via NFC tag"), which must NOT be mistaken for the note a
|
||||
task demands: the point of a required note is that somebody wrote it.
|
||||
|
||||
``completed_at`` (#133) records the completion at a past moment
|
||||
(dialog date field / service parameter). Validated HERE — the one
|
||||
point the WS command and the HA service both funnel through. See
|
||||
:meth:`MaintenanceTask.complete` for the latest-vs-backfill split.
|
||||
"""
|
||||
merged = self._get_merged_tasks_data()
|
||||
if task_id not in merged:
|
||||
_LOGGER.error("Task %s not found in entry %s", task_id, self.entry.title)
|
||||
return
|
||||
|
||||
if completed_at is not None:
|
||||
# Naive input (datetime-local field, service YAML) means local time.
|
||||
if completed_at.tzinfo is None:
|
||||
completed_at = completed_at.replace(tzinfo=dt_util.DEFAULT_TIME_ZONE)
|
||||
if completed_at > dt_util.now():
|
||||
raise ServiceValidationError(
|
||||
"The completion date cannot be in the future",
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="completed_at_in_future",
|
||||
)
|
||||
|
||||
# Required completion details. Checked HERE — the one point every
|
||||
# surface funnels through — so a task demanding a note cannot be
|
||||
# closed out from a button, the to-do list, an NFC tag, a
|
||||
@@ -972,29 +989,38 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
# because the task is already completed. Deliberately a SEPARATE map
|
||||
# from _recently_completed: that one is also stamped by skip/reset,
|
||||
# and a complete right after a date-correction reset must go through.
|
||||
last_manual = self._recent_manual_completions.get(task_id)
|
||||
if last_manual is not None and time.monotonic() - last_manual < MANUAL_COMPLETION_DEDUP_SECONDS:
|
||||
_LOGGER.info(
|
||||
"Ignoring duplicate completion of %s within %.0fs (double-tap from a second device?)",
|
||||
task_id,
|
||||
time.monotonic() - last_manual,
|
||||
)
|
||||
return
|
||||
# Stamp the guard NOW, before any await (the photo-link below yields the
|
||||
# loop). Stamping only at the end let two photo-carrying completions in
|
||||
# the same tick both pass the check and interleave → double rotation /
|
||||
# part-consume / history entry.
|
||||
self._recent_manual_completions[task_id] = time.monotonic()
|
||||
# An explicit completed_at is a deliberate backfill, not a double-tap
|
||||
# — it neither checks nor stamps the guard (a stamped guard would
|
||||
# swallow a normal completion made right after backfilling, and a
|
||||
# normal completion's stamp must not swallow the backfill).
|
||||
if completed_at is None:
|
||||
last_manual = self._recent_manual_completions.get(task_id)
|
||||
if last_manual is not None and time.monotonic() - last_manual < MANUAL_COMPLETION_DEDUP_SECONDS:
|
||||
_LOGGER.info(
|
||||
"Ignoring duplicate completion of %s within %.0fs (double-tap from a second device?)",
|
||||
task_id,
|
||||
time.monotonic() - last_manual,
|
||||
)
|
||||
return
|
||||
# Stamp the guard NOW, before any await (the photo-link below yields the
|
||||
# loop). Stamping only at the end let two photo-carrying completions in
|
||||
# the same tick both pass the check and interleave → double rotation /
|
||||
# part-consume / history entry.
|
||||
self._recent_manual_completions[task_id] = time.monotonic()
|
||||
|
||||
task = MaintenanceTask.from_dict(merged[task_id])
|
||||
pre_rotation_responsible = task.responsible_user_id
|
||||
effective_ts = completed_at if completed_at is not None else dt_util.now()
|
||||
|
||||
# Compute actual interval before updating last_performed
|
||||
# Compute actual interval before updating last_performed. Anchored on
|
||||
# the EFFECTIVE moment: "did it three days ago" must feed the real
|
||||
# elapsed interval into adaptive learning, and a pure backfill yields
|
||||
# a negative interval the learning guard below already rejects.
|
||||
actual_interval: int | None = None
|
||||
if task.last_performed:
|
||||
try:
|
||||
last = date.fromisoformat(task.last_performed)
|
||||
actual_interval = (dt_util.now().date() - last).days
|
||||
actual_interval = (effective_ts.date() - last).days
|
||||
except (ValueError, TypeError):
|
||||
actual_interval = None
|
||||
|
||||
@@ -1029,7 +1055,7 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
if isinstance(link, dict) and link.get("part_id")
|
||||
]
|
||||
|
||||
task.complete(
|
||||
is_latest = task.complete(
|
||||
notes=notes,
|
||||
cost=cost,
|
||||
duration=duration,
|
||||
@@ -1040,10 +1066,13 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
reading_value=reading_value,
|
||||
used_parts=enriched_used,
|
||||
auto=auto,
|
||||
completed_at=completed_at,
|
||||
)
|
||||
# #73: a completed cycle retires its in-cycle checklist ticks — the
|
||||
# snapshot that matters is in the history entry above.
|
||||
self._store.clear_checklist_progress(task_id)
|
||||
# snapshot that matters is in the history entry above. A pure backfill
|
||||
# closed no current cycle, so the live ticks stay.
|
||||
if is_latest:
|
||||
self._store.clear_checklist_progress(task_id)
|
||||
|
||||
# Link the completion photo to this task so it also surfaces under the
|
||||
# object's documents and is deref'd correctly on cleanup. Best-effort:
|
||||
@@ -1051,8 +1080,11 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
if photo_doc_id:
|
||||
await self._link_completion_photo(photo_doc_id, task_id)
|
||||
|
||||
# Update adaptive scheduling if enabled
|
||||
if task.adaptive_config and task.adaptive_config.get("enabled"):
|
||||
# Update adaptive scheduling if enabled. Gated on is_latest: a pure
|
||||
# backfill is not a fresh service interval (its negative
|
||||
# actual_interval would be rejected below anyway — the gate makes the
|
||||
# intent explicit and keeps the seasonal stamps off stale months).
|
||||
if is_latest and task.adaptive_config and task.adaptive_config.get("enabled"):
|
||||
if actual_interval is not None and actual_interval > 0:
|
||||
from .helpers.interval_analyzer import IntervalAnalyzer
|
||||
|
||||
@@ -1060,11 +1092,12 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
# Store the base interval for blending reference
|
||||
if "base_interval" not in task.adaptive_config:
|
||||
task.adaptive_config["base_interval"] = task.interval_days or DEFAULT_INTERVAL_DAYS
|
||||
# Inject hemisphere, current month/date for seasonal awareness
|
||||
# Inject hemisphere + month/date of the EFFECTIVE completion
|
||||
# moment for seasonal awareness (a completion logged today but
|
||||
# performed in March belongs to March).
|
||||
task.adaptive_config["hemisphere"] = "south" if (self.hass.config.latitude or 0) < 0 else "north"
|
||||
now = dt_util.now()
|
||||
task.adaptive_config["_current_month"] = now.month
|
||||
task.adaptive_config["_current_date"] = now.date().isoformat()
|
||||
task.adaptive_config["_current_month"] = effective_ts.month
|
||||
task.adaptive_config["_current_date"] = effective_ts.date().isoformat()
|
||||
updated_config = analyzer.update_on_completion(task.adaptive_config, actual_interval, feedback)
|
||||
task.adaptive_config = updated_config
|
||||
|
||||
@@ -1118,6 +1151,14 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
duration=duration,
|
||||
feedback=feedback,
|
||||
completed_by=completed_by,
|
||||
# #133: the history entry's own timestamp — identical to what
|
||||
# the history records, so automations can attribute backdated
|
||||
# completions to the right period instead of time_fired.
|
||||
completed_at=effective_ts.isoformat(),
|
||||
# True when this completion was OLDER than the latest one (a
|
||||
# pure history backfill): the action listener skips
|
||||
# on_complete_action for those, and automations can filter.
|
||||
backfill=not is_latest,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ from homeassistant.util import dt as dt_util
|
||||
if TYPE_CHECKING:
|
||||
from ...sensor import MaintenanceSensor
|
||||
|
||||
from ...helpers.trigger_fallback import threshold_exceeds
|
||||
from .base_trigger import BaseTrigger
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -24,6 +25,7 @@ class ThresholdTrigger(BaseTrigger):
|
||||
Supports:
|
||||
- Above threshold (value > above)
|
||||
- Below threshold (value < below)
|
||||
- Equals / not-equals a discrete level (value = / ≠ equals)
|
||||
- Duration requirement (value must exceed for X minutes)
|
||||
"""
|
||||
|
||||
@@ -38,6 +40,8 @@ class ThresholdTrigger(BaseTrigger):
|
||||
|
||||
self._above: float | None = trigger_config.get("trigger_above")
|
||||
self._below: float | None = trigger_config.get("trigger_below")
|
||||
self._equals: float | None = trigger_config.get("trigger_equals")
|
||||
self._not_equals: float | None = trigger_config.get("trigger_not_equals")
|
||||
self._for_minutes: int = trigger_config.get("trigger_for_minutes", 0)
|
||||
|
||||
self._threshold_exceeded = False
|
||||
@@ -63,11 +67,13 @@ class ThresholdTrigger(BaseTrigger):
|
||||
|
||||
def _value_exceeds_threshold(self, value: float) -> bool:
|
||||
"""Check if the value exceeds configured thresholds."""
|
||||
if self._above is not None and value > self._above:
|
||||
return True
|
||||
if self._below is not None and value < self._below:
|
||||
return True
|
||||
return False
|
||||
return threshold_exceeds(
|
||||
value,
|
||||
above=self._above,
|
||||
below=self._below,
|
||||
equals=self._equals,
|
||||
not_equals=self._not_equals,
|
||||
)
|
||||
|
||||
def evaluate(self, value: float) -> bool:
|
||||
"""Evaluate threshold condition."""
|
||||
|
||||
+35
@@ -101,6 +101,41 @@ describe("complete-dialog", () => {
|
||||
expect("feedback" in msg).to.be.false;
|
||||
expect("checklist_state" in msg).to.be.false;
|
||||
expect("photo_doc_id" in msg).to.be.false;
|
||||
expect("completed_at" in msg).to.be.false;
|
||||
});
|
||||
|
||||
it("sends completed_at with seconds re-added when a backdate is picked (#133)", async () => {
|
||||
const { el, sent } = await mount();
|
||||
const dt = el.shadowRoot!.querySelector<HTMLInputElement>('input[type="datetime-local"]')!;
|
||||
expect(dt, "backdate field rendered").to.exist;
|
||||
dt.value = "2026-01-10T14:30";
|
||||
dt.dispatchEvent(new Event("change"));
|
||||
await el.updateComplete;
|
||||
|
||||
clickComplete(el);
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
const msg = sent.find((m) => m.type === "maintenance_supporter/task/complete")!;
|
||||
expect(msg).to.exist;
|
||||
expect(msg.completed_at).to.equal("2026-01-10T14:30:00");
|
||||
});
|
||||
|
||||
it("rejects a future completed_at client-side without a WS roundtrip (#133)", async () => {
|
||||
const { el, sent } = await mount();
|
||||
const future = new Date(Date.now() + 48 * 3600 * 1000);
|
||||
const pad = (n: number) => String(n).padStart(2, "0");
|
||||
const v = `${future.getFullYear()}-${pad(future.getMonth() + 1)}-${pad(future.getDate())}T12:00`;
|
||||
const dt = el.shadowRoot!.querySelector<HTMLInputElement>('input[type="datetime-local"]')!;
|
||||
dt.value = v;
|
||||
dt.dispatchEvent(new Event("change"));
|
||||
await el.updateComplete;
|
||||
|
||||
clickComplete(el);
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(sent.find((m) => m.type === "maintenance_supporter/task/complete")).to.equal(undefined);
|
||||
await el.updateComplete;
|
||||
expect(el.shadowRoot!.textContent).to.include("future");
|
||||
});
|
||||
|
||||
it("attaches an uploaded photo as photo_doc_id", async () => {
|
||||
|
||||
+55
@@ -63,6 +63,31 @@ describe("task-dialog trigger_config roundtrip closure (#103 class)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("threshold: =/≠ limits and the all-combinator survive", async () => {
|
||||
const tc = await saveRoundtrip({
|
||||
type: "threshold",
|
||||
entity_id: "sensor.a",
|
||||
trigger_equals: 3,
|
||||
trigger_not_equals: 1,
|
||||
trigger_combinator: "all",
|
||||
});
|
||||
expect(tc).to.deep.include({
|
||||
type: "threshold",
|
||||
trigger_equals: 3,
|
||||
trigger_not_equals: 1,
|
||||
trigger_combinator: "all",
|
||||
});
|
||||
});
|
||||
|
||||
it("combinator defaults to any and is then omitted from the payload", async () => {
|
||||
const tc = await saveRoundtrip({
|
||||
type: "threshold",
|
||||
entity_id: "sensor.a",
|
||||
trigger_above: 80,
|
||||
});
|
||||
expect(tc.trigger_combinator, "any must not be persisted").to.equal(undefined);
|
||||
});
|
||||
|
||||
it("threshold stored with ONLY plural entity_ids survives an edit (#106)", async () => {
|
||||
// The Battery Fleet task's trigger has no singular entity_id; the save
|
||||
// path gates on _triggerEntityId, so before the hydration fallback an
|
||||
@@ -179,4 +204,34 @@ describe("task-dialog trigger_config roundtrip closure (#103 class)", () => {
|
||||
entity_logic: "any",
|
||||
});
|
||||
});
|
||||
|
||||
it("compound: condition =/≠ limits and task-level combinator survive", async () => {
|
||||
const tc = await saveRoundtrip({
|
||||
type: "compound",
|
||||
compound_logic: "AND",
|
||||
trigger_combinator: "all",
|
||||
conditions: [
|
||||
{
|
||||
type: "threshold",
|
||||
entity_id: "sensor.a",
|
||||
entity_ids: ["sensor.a"],
|
||||
trigger_equals: 3,
|
||||
trigger_not_equals: 1,
|
||||
},
|
||||
{
|
||||
type: "threshold",
|
||||
entity_id: "sensor.b",
|
||||
entity_ids: ["sensor.b"],
|
||||
trigger_above: 80,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(tc.trigger_combinator).to.equal("all");
|
||||
const conds = tc.conditions as Array<Record<string, unknown>>;
|
||||
expect(conds[0]).to.deep.include({
|
||||
type: "threshold",
|
||||
trigger_equals: 3,
|
||||
trigger_not_equals: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -53,6 +53,8 @@ export class MaintenanceCompleteDialog extends LitElement {
|
||||
@state() private _photoUploading = false;
|
||||
@state() private _readingValue = "";
|
||||
@state() private _restockQty = "";
|
||||
/** #133: optional backdated completion moment (datetime-local value; "" = now). */
|
||||
@state() private _completedAt = "";
|
||||
/** Keyed by `partLinkKey` — the (entry_id, part_id) pair — because two
|
||||
* objects can carry the same part id, so part_id alone would merge pools. */
|
||||
@state() private _usedParts: Record<string, TaskPartLink> = {};
|
||||
@@ -81,6 +83,7 @@ export class MaintenanceCompleteDialog extends LitElement {
|
||||
this._photoUploading = false;
|
||||
this._readingValue = "";
|
||||
this._restockQty = this.restockDefault !== null ? String(this.restockDefault) : "";
|
||||
this._completedAt = "";
|
||||
// #99: prefill "parts used" with the task's fixed links — the user can
|
||||
// untick or adjust before completing. The whole link is kept, entry_id
|
||||
// included, so a shared pool survives the edit (#111).
|
||||
@@ -167,6 +170,18 @@ export class MaintenanceCompleteDialog extends LitElement {
|
||||
if (this._photoDocId) {
|
||||
data.photo_doc_id = this._photoDocId;
|
||||
}
|
||||
if (this._completedAt) {
|
||||
// Client-side guard mirrors the backend rule — a picked future moment
|
||||
// fails fast with a localized message instead of a WS roundtrip.
|
||||
if (new Date(this._completedAt).getTime() > Date.now()) {
|
||||
this._error = t("completed_at_future_error", this.lang);
|
||||
this._loading = false;
|
||||
return;
|
||||
}
|
||||
// Re-add seconds if the datetime-local input drops them (same
|
||||
// normalisation as the history-edit dialog).
|
||||
data.completed_at = this._completedAt.length === 16 ? `${this._completedAt}:00` : this._completedAt;
|
||||
}
|
||||
if (this._readingValue !== "") {
|
||||
const rv = parseFloat(this._readingValue);
|
||||
if (!isNaN(rv)) data.reading_value = rv;
|
||||
@@ -371,6 +386,13 @@ export class MaintenanceCompleteDialog extends LitElement {
|
||||
.value=${this._duration}
|
||||
@input=${(e: Event) => (this._duration = (e.target as HTMLInputElement).value)} />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span class="field-label">${t("completed_at_optional", L)}</span>
|
||||
<input type="datetime-local" class="field-input"
|
||||
max=${new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString().slice(0, 16)}
|
||||
.value=${this._completedAt}
|
||||
@change=${(e: Event) => (this._completedAt = (e.target as HTMLInputElement).value)} />
|
||||
</label>
|
||||
<div class="field">
|
||||
<span class="field-label">${t("completion_photo_optional", L)}${this._req("photo")}</span>
|
||||
${this._photoPreview
|
||||
|
||||
@@ -35,6 +35,8 @@ interface CompoundConditionDraft {
|
||||
attribute: string; // "" = use the entity state
|
||||
above: string;
|
||||
below: string;
|
||||
equals: string;
|
||||
notEquals: string;
|
||||
forMinutes: string;
|
||||
targetValue: string;
|
||||
deltaMode: boolean;
|
||||
@@ -50,7 +52,8 @@ interface CompoundConditionDraft {
|
||||
|
||||
function emptyCondition(): CompoundConditionDraft {
|
||||
return {
|
||||
entityIds: "", type: "threshold", attribute: "", above: "", below: "", forMinutes: "0",
|
||||
entityIds: "", type: "threshold", attribute: "", above: "", below: "",
|
||||
equals: "", notEquals: "", forMinutes: "0",
|
||||
targetValue: "", deltaMode: false, fromState: "", toState: "",
|
||||
targetChanges: "", runtimeHours: "", onStates: "", carry: {},
|
||||
};
|
||||
@@ -60,7 +63,7 @@ function emptyCondition(): CompoundConditionDraft {
|
||||
* travels through `carry` untouched. */
|
||||
const MANAGED_CONDITION_KEYS = new Set([
|
||||
"entity_id", "entity_ids", "type", "attribute",
|
||||
"trigger_above", "trigger_below", "trigger_for_minutes",
|
||||
"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",
|
||||
@@ -75,6 +78,8 @@ function conditionToDraft(c: TriggerConfig): CompoundConditionDraft {
|
||||
attribute: c.attribute || "",
|
||||
above: c.trigger_above?.toString() ?? "",
|
||||
below: c.trigger_below?.toString() ?? "",
|
||||
equals: c.trigger_equals?.toString() ?? "",
|
||||
notEquals: c.trigger_not_equals?.toString() ?? "",
|
||||
forMinutes: c.trigger_for_minutes?.toString() ?? "0",
|
||||
targetValue: c.trigger_target_value?.toString() ?? "",
|
||||
deltaMode: c.trigger_delta_mode || false,
|
||||
@@ -99,6 +104,8 @@ function draftToCondition(d: CompoundConditionDraft): TriggerConfig | null {
|
||||
if (d.type === "threshold") {
|
||||
const a = parseFloat(d.above); if (!isNaN(a)) c.trigger_above = a;
|
||||
const b = parseFloat(d.below); if (!isNaN(b)) c.trigger_below = b;
|
||||
const eq = parseFloat(d.equals); if (!isNaN(eq)) c.trigger_equals = eq;
|
||||
const ne = parseFloat(d.notEquals); if (!isNaN(ne)) c.trigger_not_equals = ne;
|
||||
const f = parseInt(d.forMinutes, 10); if (!isNaN(f)) c.trigger_for_minutes = f;
|
||||
} else if (d.type === "counter") {
|
||||
const v = parseFloat(d.targetValue); if (!isNaN(v)) c.trigger_target_value = v;
|
||||
@@ -202,7 +209,11 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
@state() private _triggerType = "threshold";
|
||||
@state() private _triggerAbove = "";
|
||||
@state() private _triggerBelow = "";
|
||||
@state() private _triggerEquals = "";
|
||||
@state() private _triggerNotEquals = "";
|
||||
@state() private _triggerForMinutes = "0";
|
||||
/** Trigger vs. safety interval: "any" = whichever first (default), "all" = both required. */
|
||||
@state() private _triggerCombinator: "any" | "all" = "any";
|
||||
@state() private _triggerTargetValue = "";
|
||||
@state() private _triggerDeltaMode = false;
|
||||
@state() private _triggerBaselineValue = "";
|
||||
@@ -426,7 +437,10 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
this._triggerType = tc.type || "threshold";
|
||||
this._triggerAbove = tc.trigger_above?.toString() || "";
|
||||
this._triggerBelow = tc.trigger_below?.toString() || "";
|
||||
this._triggerEquals = tc.trigger_equals?.toString() || "";
|
||||
this._triggerNotEquals = tc.trigger_not_equals?.toString() || "";
|
||||
this._triggerForMinutes = tc.trigger_for_minutes?.toString() || "0";
|
||||
this._triggerCombinator = tc.trigger_combinator === "all" ? "all" : "any";
|
||||
this._triggerTargetValue = tc.trigger_target_value?.toString() || "";
|
||||
this._triggerDeltaMode = tc.trigger_delta_mode || false;
|
||||
this._triggerBaselineValue = tc.trigger_baseline_value?.toString() || "";
|
||||
@@ -530,7 +544,10 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
this._triggerType = "threshold";
|
||||
this._triggerAbove = "";
|
||||
this._triggerBelow = "";
|
||||
this._triggerEquals = "";
|
||||
this._triggerNotEquals = "";
|
||||
this._triggerForMinutes = "0";
|
||||
this._triggerCombinator = "any";
|
||||
this._triggerTargetValue = "";
|
||||
this._triggerDeltaMode = false;
|
||||
this._triggerBaselineValue = "";
|
||||
@@ -1089,6 +1106,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
conditions,
|
||||
};
|
||||
if (this._autoCompleteOnRecovery) triggerConfig.auto_complete_on_recovery = true;
|
||||
if (this._triggerCombinator === "all") triggerConfig.trigger_combinator = "all";
|
||||
data.trigger_config = triggerConfig;
|
||||
} else if (this._taskId) {
|
||||
data.trigger_config = null;
|
||||
@@ -1104,6 +1122,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
};
|
||||
if (this._triggerAttribute) triggerConfig.attribute = this._triggerAttribute;
|
||||
if (this._autoCompleteOnRecovery) triggerConfig.auto_complete_on_recovery = true;
|
||||
if (this._triggerCombinator === "all") triggerConfig.trigger_combinator = "all";
|
||||
|
||||
// Multi-entity: store entity_logic for all trigger types
|
||||
if (entityIds.length > 1) {
|
||||
@@ -1113,6 +1132,8 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
if (this._triggerType === "threshold") {
|
||||
if (this._triggerAbove) { const v = parseFloat(this._triggerAbove); if (!isNaN(v)) triggerConfig.trigger_above = v; }
|
||||
if (this._triggerBelow) { const v = parseFloat(this._triggerBelow); if (!isNaN(v)) triggerConfig.trigger_below = v; }
|
||||
if (this._triggerEquals) { const v = parseFloat(this._triggerEquals); if (!isNaN(v)) triggerConfig.trigger_equals = v; }
|
||||
if (this._triggerNotEquals) { const v = parseFloat(this._triggerNotEquals); if (!isNaN(v)) triggerConfig.trigger_not_equals = v; }
|
||||
if (this._triggerForMinutes) { const v = parseInt(this._triggerForMinutes, 10); if (!isNaN(v)) triggerConfig.trigger_for_minutes = v; }
|
||||
} else if (this._triggerType === "counter") {
|
||||
if (this._triggerTargetValue) { const v = parseFloat(this._triggerTargetValue); if (!isNaN(v)) triggerConfig.trigger_target_value = v; }
|
||||
@@ -1342,6 +1363,19 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
@input=${(e: Event) => (this._intervalDays = (e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
${this._intervalDays ? this._renderUnitSelect() : nothing}
|
||||
${this._intervalDays
|
||||
? html`
|
||||
<div class="select-row">
|
||||
<label>${t("trigger_combinator", L)}</label>
|
||||
<select
|
||||
@change=${(e: Event) => (this._triggerCombinator = (e.target as HTMLSelectElement).value as "any" | "all")}
|
||||
>
|
||||
<option value="any" ?selected=${this._triggerCombinator === "any"}>${t("trigger_combinator_any", L)}</option>
|
||||
<option value="all" ?selected=${this._triggerCombinator === "all"}>${t("trigger_combinator_all", L)}</option>
|
||||
</select>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1636,6 +1670,10 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
@input=${(e: Event) => this._patchCondition(i, { above: (e.target as HTMLInputElement).value })}></ms-textfield>
|
||||
<ms-textfield label="${t("trigger_below", L)}" type="number" .value=${c.below}
|
||||
@input=${(e: Event) => this._patchCondition(i, { below: (e.target as HTMLInputElement).value })}></ms-textfield>
|
||||
<ms-textfield label="${t("trigger_equals", L)}" type="number" .value=${c.equals}
|
||||
@input=${(e: Event) => this._patchCondition(i, { equals: (e.target as HTMLInputElement).value })}></ms-textfield>
|
||||
<ms-textfield label="${t("trigger_not_equals", L)}" type="number" .value=${c.notEquals}
|
||||
@input=${(e: Event) => this._patchCondition(i, { notEquals: (e.target as HTMLInputElement).value })}></ms-textfield>
|
||||
<ms-textfield label="${t("for_minutes", L)}" type="number" .value=${c.forMinutes}
|
||||
@input=${(e: Event) => this._patchCondition(i, { forMinutes: (e.target as HTMLInputElement).value })}></ms-textfield>
|
||||
`;
|
||||
@@ -2122,6 +2160,20 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
.value=${this._triggerBelow}
|
||||
@input=${(e: Event) => (this._triggerBelow = (e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${t("trigger_equals", L)}"
|
||||
type="number"
|
||||
step="any"
|
||||
.value=${this._triggerEquals}
|
||||
@input=${(e: Event) => (this._triggerEquals = (e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${t("trigger_not_equals", L)}"
|
||||
type="number"
|
||||
step="any"
|
||||
.value=${this._triggerNotEquals}
|
||||
@input=${(e: Event) => (this._triggerNotEquals = (e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${t("for_at_least_minutes", L)}"
|
||||
type="number"
|
||||
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Poznámky (volitelné)",
|
||||
"cost_optional": "Náklady (volitelné)",
|
||||
"duration_minutes": "Doba trvání v minutách (volitelné)",
|
||||
"completed_at_optional": "Dokončeno dne (volitelné, prázdné = nyní)",
|
||||
"completed_at_future_error": "Datum dokončení nesmí být v budoucnosti.",
|
||||
"days": "dní",
|
||||
"day": "den",
|
||||
"today": "Dnes",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Použít stav entity (bez atributu)",
|
||||
"trigger_above": "Spustit nad",
|
||||
"trigger_below": "Spustit pod",
|
||||
"trigger_equals": "Spustit při rovnosti (=)",
|
||||
"trigger_not_equals": "Spustit při odlišnosti od (≠)",
|
||||
"for_at_least_minutes": "Po dobu alespoň (minut)",
|
||||
"safety_interval_days": "Bezpečnostní interval (dny, volitelný)",
|
||||
"safety_interval": "Bezpečnostní interval (volitelný)",
|
||||
"trigger_combinator": "Kombinovat spouštěč a interval",
|
||||
"trigger_combinator_any": "Spouštěč nebo interval (co dřív)",
|
||||
"trigger_combinator_all": "Spouštěč a interval (obojí vyžadováno)",
|
||||
"delta_mode": "Režim delta",
|
||||
"from_state_optional": "Ze stavu (volitelné)",
|
||||
"to_state_optional": "Do stavu (volitelné)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Začínáme — tyto tipy zmizí, jak vaše nastavení poroste",
|
||||
"gs_setups_chip": "Navrhovaná nastavení: nalezeno {n} zařízení s předpřipravenými spouštěči",
|
||||
"gs_adopt_chip": "{n} problémových senzorů se může stát údržbovými úkoly",
|
||||
"gs_fleet_chip": "Jedno kliknutí nastaví flotilu baterií"
|
||||
"gs_fleet_chip": "Jedno kliknutí nastaví flotilu baterií",
|
||||
"cal_editor_window": "Výchozí okno",
|
||||
"cal_editor_window_week": "Týden (7 dní)",
|
||||
"cal_editor_window_fortnight": "Dva týdny (14 dní)",
|
||||
"cal_editor_window_month": "Měsíc (30 dní, výchozí)",
|
||||
"cal_editor_window_year": "Rok (365 dní, prázdné dny skryty)",
|
||||
"cal_editor_show_chips": "Zobrazit přepínače okna v kartě",
|
||||
"cal_editor_chips_hint": "Skryjte přepínače, pokud je karta ve strategickém pohledu, který už slouží jako výběr okna.",
|
||||
"cal_editor_show_user_filter": "Zobrazit filtr uživatele",
|
||||
"cal_editor_default_user": "Výchozí filtr uživatele",
|
||||
"cal_editor_my_tasks": "Moje úkoly (aktuální uživatel)",
|
||||
"cal_editor_show_object_filter": "Zobrazit filtr objektu",
|
||||
"cal_editor_object_hint": "Předvyberte objekt přes YAML: object_filter: \"<název>\" — nebo seznam názvů pro omezení karty na více objektů."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Noter (valgfrit)",
|
||||
"cost_optional": "Omkostning (valgfrit)",
|
||||
"duration_minutes": "Varighed i minutter (valgfrit)",
|
||||
"completed_at_optional": "Udført den (valgfrit, tomt = nu)",
|
||||
"completed_at_future_error": "Udførelsesdatoen må ikke ligge i fremtiden.",
|
||||
"days": "dage",
|
||||
"day": "dag",
|
||||
"today": "I dag",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Brug enhedstilstand (ingen attribut)",
|
||||
"trigger_above": "Udløs over",
|
||||
"trigger_below": "Udløs under",
|
||||
"trigger_equals": "Udløs ved lig med (=)",
|
||||
"trigger_not_equals": "Udløs ved forskellig fra (≠)",
|
||||
"for_at_least_minutes": "I mindst (minutter)",
|
||||
"safety_interval_days": "Sikkerhedsinterval (dage, valgfrit)",
|
||||
"safety_interval": "Sikkerhedsinterval (valgfrit)",
|
||||
"trigger_combinator": "Kombinér trigger og interval",
|
||||
"trigger_combinator_any": "Trigger eller interval (først opfyldt)",
|
||||
"trigger_combinator_all": "Trigger og interval (begge kræves)",
|
||||
"delta_mode": "Delta-tilstand",
|
||||
"from_state_optional": "Fra tilstand (valgfrit)",
|
||||
"to_state_optional": "Til tilstand (valgfrit)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Kom godt i gang — disse tips forsvinder, efterhånden som opsætningen vokser",
|
||||
"gs_setups_chip": "Foreslåede opsætninger fandt {n} enheder med forudindstillede udløsere",
|
||||
"gs_adopt_chip": "{n} problemsensorer kan blive vedligeholdelsesopgaver",
|
||||
"gs_fleet_chip": "Ét klik opsætter batteriflåden"
|
||||
"gs_fleet_chip": "Ét klik opsætter batteriflåden",
|
||||
"cal_editor_window": "Standardvindue",
|
||||
"cal_editor_window_week": "Uge (7 dage)",
|
||||
"cal_editor_window_fortnight": "To uger (14 dage)",
|
||||
"cal_editor_window_month": "Måned (30 dage, standard)",
|
||||
"cal_editor_window_year": "År (365 dage, tomme dage skjult)",
|
||||
"cal_editor_show_chips": "Vis vinduechips i kortet",
|
||||
"cal_editor_chips_hint": "Skjul chips, når kortet er indlejret i en strategivisning, der allerede fungerer som vinduesvælger.",
|
||||
"cal_editor_show_user_filter": "Vis brugerfilter",
|
||||
"cal_editor_default_user": "Standard brugerfilter",
|
||||
"cal_editor_my_tasks": "Mine opgaver (aktuel bruger)",
|
||||
"cal_editor_show_object_filter": "Vis objektfilter",
|
||||
"cal_editor_object_hint": "Forvælg et objekt via YAML: object_filter: \"<navn>\" — eller en liste af navne for at begrænse kortet til flere objekter."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Notizen (optional)",
|
||||
"cost_optional": "Kosten (optional)",
|
||||
"duration_minutes": "Dauer in Minuten (optional)",
|
||||
"completed_at_optional": "Erledigt am (optional, leer = jetzt)",
|
||||
"completed_at_future_error": "Das Erledigungsdatum darf nicht in der Zukunft liegen.",
|
||||
"days": "Tage",
|
||||
"day": "Tag",
|
||||
"today": "Heute",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Entitäts-Zustand verwenden (kein Attribut)",
|
||||
"trigger_above": "Auslösen wenn über",
|
||||
"trigger_below": "Auslösen wenn unter",
|
||||
"trigger_equals": "Auslösen bei genau (=)",
|
||||
"trigger_not_equals": "Auslösen bei abweichend von (≠)",
|
||||
"for_at_least_minutes": "Für mindestens (Minuten)",
|
||||
"safety_interval_days": "Sicherheitsintervall (Tage, optional)",
|
||||
"safety_interval": "Sicherheitsintervall (optional)",
|
||||
"trigger_combinator": "Trigger und Intervall kombinieren",
|
||||
"trigger_combinator_any": "Trigger oder Intervall (zuerst erfüllt)",
|
||||
"trigger_combinator_all": "Trigger und Intervall (beides erforderlich)",
|
||||
"delta_mode": "Delta-Modus",
|
||||
"from_state_optional": "Von Zustand (optional)",
|
||||
"to_state_optional": "Zu Zustand (optional)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Erste Schritte — diese Hinweise verschwinden, wenn dein Setup wächst",
|
||||
"gs_setups_chip": "Vorgeschlagene Setups: {n} Geräte mit vorverdrahteten Auslösern gefunden",
|
||||
"gs_adopt_chip": "{n} Problem-Sensoren können zu Wartungsaufgaben werden",
|
||||
"gs_fleet_chip": "Ein Klick richtet die Batterieflotte ein"
|
||||
"gs_fleet_chip": "Ein Klick richtet die Batterieflotte ein",
|
||||
"cal_editor_window": "Standard-Zeitfenster",
|
||||
"cal_editor_window_week": "Woche (7 Tage)",
|
||||
"cal_editor_window_fortnight": "Zwei Wochen (14 Tage)",
|
||||
"cal_editor_window_month": "Monat (30 Tage, Standard)",
|
||||
"cal_editor_window_year": "Jahr (365 Tage, leere Tage ausgeblendet)",
|
||||
"cal_editor_show_chips": "Zeitfenster-Chips in der Karte anzeigen",
|
||||
"cal_editor_chips_hint": "Chips ausblenden, wenn die Karte in einer Strategie-Ansicht steckt, die bereits als Zeitfenster-Auswahl dient.",
|
||||
"cal_editor_show_user_filter": "Benutzerfilter-Dropdown anzeigen",
|
||||
"cal_editor_default_user": "Standard-Benutzerfilter",
|
||||
"cal_editor_my_tasks": "Meine Aufgaben (aktueller Benutzer)",
|
||||
"cal_editor_show_object_filter": "Objektfilter-Dropdown anzeigen",
|
||||
"cal_editor_object_hint": "Ein Objekt per YAML vorauswählen: object_filter: \"<Objektname>\" — oder eine Namensliste, um die Karte auf mehrere Objekte zu beschränken."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Notes (optional)",
|
||||
"cost_optional": "Cost (optional)",
|
||||
"duration_minutes": "Duration in minutes (optional)",
|
||||
"completed_at_optional": "Completed at (optional, empty = now)",
|
||||
"completed_at_future_error": "The completion date cannot be in the future.",
|
||||
"days": "days",
|
||||
"day": "day",
|
||||
"today": "Today",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Use entity state (no attribute)",
|
||||
"trigger_above": "Trigger above",
|
||||
"trigger_below": "Trigger below",
|
||||
"trigger_equals": "Trigger when equal to (=)",
|
||||
"trigger_not_equals": "Trigger when different from (≠)",
|
||||
"for_at_least_minutes": "For at least (minutes)",
|
||||
"safety_interval_days": "Safety interval (days, optional)",
|
||||
"safety_interval": "Safety interval (optional)",
|
||||
"trigger_combinator": "Combine trigger and interval",
|
||||
"trigger_combinator_any": "Trigger or interval (whichever first)",
|
||||
"trigger_combinator_all": "Trigger and interval (both required)",
|
||||
"delta_mode": "Delta mode",
|
||||
"from_state_optional": "From state (optional)",
|
||||
"to_state_optional": "To state (optional)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Getting started — these hints retire as your setup grows",
|
||||
"gs_setups_chip": "Suggested setups found {n} devices with pre-wired triggers",
|
||||
"gs_adopt_chip": "{n} problem sensors can become maintenance tasks",
|
||||
"gs_fleet_chip": "One click sets up the battery fleet"
|
||||
"gs_fleet_chip": "One click sets up the battery fleet",
|
||||
"cal_editor_window": "Default window",
|
||||
"cal_editor_window_week": "Week (7 days)",
|
||||
"cal_editor_window_fortnight": "Fortnight (14 days)",
|
||||
"cal_editor_window_month": "Month (30 days, default)",
|
||||
"cal_editor_window_year": "Year (365 days, empty days collapsed)",
|
||||
"cal_editor_show_chips": "Show window chips inside the card",
|
||||
"cal_editor_chips_hint": "Hide the chips when the card is embedded in a strategy view that already serves as the window selector.",
|
||||
"cal_editor_show_user_filter": "Show user filter dropdown",
|
||||
"cal_editor_default_user": "Default user filter",
|
||||
"cal_editor_my_tasks": "My tasks (current user)",
|
||||
"cal_editor_show_object_filter": "Show object filter dropdown",
|
||||
"cal_editor_object_hint": "Pre-select one object via YAML: object_filter: \"<object name>\" — or a list of names to restrict the card to several objects."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Notas (opcional)",
|
||||
"cost_optional": "Coste (opcional)",
|
||||
"duration_minutes": "Duración en minutos (opcional)",
|
||||
"completed_at_optional": "Completado el (opcional, vacío = ahora)",
|
||||
"completed_at_future_error": "La fecha de finalización no puede estar en el futuro.",
|
||||
"days": "días",
|
||||
"day": "día",
|
||||
"today": "Hoy",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Usar estado de la entidad (sin atributo)",
|
||||
"trigger_above": "Activar por encima de",
|
||||
"trigger_below": "Activar por debajo de",
|
||||
"trigger_equals": "Activar cuando sea igual a (=)",
|
||||
"trigger_not_equals": "Activar cuando sea distinto de (≠)",
|
||||
"for_at_least_minutes": "Durante al menos (minutos)",
|
||||
"safety_interval_days": "Intervalo de seguridad (días, opcional)",
|
||||
"safety_interval": "Intervalo de seguridad (opcional)",
|
||||
"trigger_combinator": "Combinar disparador e intervalo",
|
||||
"trigger_combinator_any": "Disparador o intervalo (el primero)",
|
||||
"trigger_combinator_all": "Disparador e intervalo (ambos requeridos)",
|
||||
"delta_mode": "Modo delta",
|
||||
"from_state_optional": "Desde estado (opcional)",
|
||||
"to_state_optional": "Hasta estado (opcional)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Primeros pasos: estas sugerencias desaparecen a medida que crece tu configuración",
|
||||
"gs_setups_chip": "Configuraciones sugeridas: {n} dispositivos con disparadores preconfigurados",
|
||||
"gs_adopt_chip": "{n} sensores de problemas pueden convertirse en tareas de mantenimiento",
|
||||
"gs_fleet_chip": "Un clic configura la flota de baterías"
|
||||
"gs_fleet_chip": "Un clic configura la flota de baterías",
|
||||
"cal_editor_window": "Ventana predeterminada",
|
||||
"cal_editor_window_week": "Semana (7 días)",
|
||||
"cal_editor_window_fortnight": "Quincena (14 días)",
|
||||
"cal_editor_window_month": "Mes (30 días, predeterminado)",
|
||||
"cal_editor_window_year": "Año (365 días, días vacíos ocultos)",
|
||||
"cal_editor_show_chips": "Mostrar chips de ventana en la tarjeta",
|
||||
"cal_editor_chips_hint": "Oculta los chips cuando la tarjeta está en una vista de estrategia que ya sirve como selector de ventana.",
|
||||
"cal_editor_show_user_filter": "Mostrar filtro de usuario",
|
||||
"cal_editor_default_user": "Filtro de usuario predeterminado",
|
||||
"cal_editor_my_tasks": "Mis tareas (usuario actual)",
|
||||
"cal_editor_show_object_filter": "Mostrar filtro de objeto",
|
||||
"cal_editor_object_hint": "Preselecciona un objeto por YAML: object_filter: \"<nombre>\" — o una lista de nombres para limitar la tarjeta a varios objetos."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Muistiinpanot (valinnainen)",
|
||||
"cost_optional": "Kustannus (valinnainen)",
|
||||
"duration_minutes": "Kesto minuutteina (valinnainen)",
|
||||
"completed_at_optional": "Suoritettu (valinnainen, tyhjä = nyt)",
|
||||
"completed_at_future_error": "Suorituspäivä ei voi olla tulevaisuudessa.",
|
||||
"days": "päivää",
|
||||
"day": "päivä",
|
||||
"today": "Tänään",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Käytä entiteetin tilaa (ei attribuuttia)",
|
||||
"trigger_above": "Laukaise yli",
|
||||
"trigger_below": "Laukaise alle",
|
||||
"trigger_equals": "Laukaise kun yhtä suuri kuin (=)",
|
||||
"trigger_not_equals": "Laukaise kun eri kuin (≠)",
|
||||
"for_at_least_minutes": "Vähintään (minuuttia)",
|
||||
"safety_interval_days": "Turvaväli (päivää, valinnainen)",
|
||||
"safety_interval": "Turvaväli (valinnainen)",
|
||||
"trigger_combinator": "Yhdistä laukaisin ja väli",
|
||||
"trigger_combinator_any": "Laukaisin tai väli (ensin täyttyvä)",
|
||||
"trigger_combinator_all": "Laukaisin ja väli (molemmat vaaditaan)",
|
||||
"delta_mode": "Delta-tila",
|
||||
"from_state_optional": "Lähtötilasta (valinnainen)",
|
||||
"to_state_optional": "Kohdetilaan (valinnainen)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Aloitus — nämä vihjeet poistuvat asennuksen kasvaessa",
|
||||
"gs_setups_chip": "Ehdotetut asetukset löysivät {n} laitetta valmiilla laukaisimilla",
|
||||
"gs_adopt_chip": "{n} ongelma-anturia voi muuttua huoltotehtäviksi",
|
||||
"gs_fleet_chip": "Yksi napsautus määrittää akkukannan"
|
||||
"gs_fleet_chip": "Yksi napsautus määrittää akkukannan",
|
||||
"cal_editor_window": "Oletusikkuna",
|
||||
"cal_editor_window_week": "Viikko (7 päivää)",
|
||||
"cal_editor_window_fortnight": "Kaksi viikkoa (14 päivää)",
|
||||
"cal_editor_window_month": "Kuukausi (30 päivää, oletus)",
|
||||
"cal_editor_window_year": "Vuosi (365 päivää, tyhjät päivät piilotettu)",
|
||||
"cal_editor_show_chips": "Näytä ikkunavalinnat kortissa",
|
||||
"cal_editor_chips_hint": "Piilota valinnat, kun kortti on strategianäkymässä, joka jo toimii ikkunan valitsimena.",
|
||||
"cal_editor_show_user_filter": "Näytä käyttäjäsuodatin",
|
||||
"cal_editor_default_user": "Oletuskäyttäjäsuodatin",
|
||||
"cal_editor_my_tasks": "Omat tehtävät (nykyinen käyttäjä)",
|
||||
"cal_editor_show_object_filter": "Näytä kohdesuodatin",
|
||||
"cal_editor_object_hint": "Esivalitse kohde YAML:lla: object_filter: \"<nimi>\" — tai nimilista rajataksesi kortin useisiin kohteisiin."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Notes (optionnel)",
|
||||
"cost_optional": "Coût (optionnel)",
|
||||
"duration_minutes": "Durée en minutes (optionnel)",
|
||||
"completed_at_optional": "Effectué le (optionnel, vide = maintenant)",
|
||||
"completed_at_future_error": "La date d'achèvement ne peut pas être dans le futur.",
|
||||
"days": "jours",
|
||||
"day": "jour",
|
||||
"today": "Aujourd'hui",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Utiliser l'état de l'entité (pas d'attribut)",
|
||||
"trigger_above": "Déclencher au-dessus de",
|
||||
"trigger_below": "Déclencher en dessous de",
|
||||
"trigger_equals": "Déclencher si égal à (=)",
|
||||
"trigger_not_equals": "Déclencher si différent de (≠)",
|
||||
"for_at_least_minutes": "Pendant au moins (minutes)",
|
||||
"safety_interval_days": "Intervalle de sécurité (jours, optionnel)",
|
||||
"safety_interval": "Intervalle de sécurité (optionnel)",
|
||||
"trigger_combinator": "Combiner déclencheur et intervalle",
|
||||
"trigger_combinator_any": "Déclencheur ou intervalle (premier atteint)",
|
||||
"trigger_combinator_all": "Déclencheur et intervalle (les deux requis)",
|
||||
"delta_mode": "Mode delta",
|
||||
"from_state_optional": "État source (optionnel)",
|
||||
"to_state_optional": "État cible (optionnel)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Premiers pas — ces conseils disparaissent à mesure que votre configuration grandit",
|
||||
"gs_setups_chip": "Configurations suggérées : {n} appareils avec déclencheurs pré-câblés trouvés",
|
||||
"gs_adopt_chip": "{n} capteurs de problème peuvent devenir des tâches de maintenance",
|
||||
"gs_fleet_chip": "Un clic configure le parc de piles"
|
||||
"gs_fleet_chip": "Un clic configure le parc de piles",
|
||||
"cal_editor_window": "Fenêtre par défaut",
|
||||
"cal_editor_window_week": "Semaine (7 jours)",
|
||||
"cal_editor_window_fortnight": "Quinzaine (14 jours)",
|
||||
"cal_editor_window_month": "Mois (30 jours, défaut)",
|
||||
"cal_editor_window_year": "Année (365 jours, jours vides masqués)",
|
||||
"cal_editor_show_chips": "Afficher les puces de fenêtre dans la carte",
|
||||
"cal_editor_chips_hint": "Masquez les puces lorsque la carte est intégrée dans une vue stratégie qui sert déjà de sélecteur de fenêtre.",
|
||||
"cal_editor_show_user_filter": "Afficher le filtre utilisateur",
|
||||
"cal_editor_default_user": "Filtre utilisateur par défaut",
|
||||
"cal_editor_my_tasks": "Mes tâches (utilisateur actuel)",
|
||||
"cal_editor_show_object_filter": "Afficher le filtre d'objet",
|
||||
"cal_editor_object_hint": "Présélectionnez un objet via YAML : object_filter : \"<nom>\" — ou une liste de noms pour limiter la carte à plusieurs objets."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "टिप्पणियाँ (वैकल्पिक)",
|
||||
"cost_optional": "लागत (वैकल्पिक)",
|
||||
"duration_minutes": "मिनटों में अवधि (वैकल्पिक)",
|
||||
"completed_at_optional": "पूर्ण होने का समय (वैकल्पिक, खाली = अभी)",
|
||||
"completed_at_future_error": "पूर्णता की तारीख भविष्य में नहीं हो सकती।",
|
||||
"days": "दिन",
|
||||
"day": "दिन",
|
||||
"today": "आज",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "एंटिटी स्थिति का उपयोग करें (कोई विशेषता नहीं)",
|
||||
"trigger_above": "इससे ऊपर ट्रिगर करें",
|
||||
"trigger_below": "इससे नीचे ट्रिगर करें",
|
||||
"trigger_equals": "बराबर होने पर ट्रिगर करें (=)",
|
||||
"trigger_not_equals": "भिन्न होने पर ट्रिगर करें (≠)",
|
||||
"for_at_least_minutes": "कम से कम (मिनट)",
|
||||
"safety_interval_days": "सुरक्षा अंतराल (दिन, वैकल्पिक)",
|
||||
"safety_interval": "सुरक्षा अंतराल (वैकल्पिक)",
|
||||
"trigger_combinator": "ट्रिगर और अंतराल संयोजित करें",
|
||||
"trigger_combinator_any": "ट्रिगर या अंतराल (जो पहले हो)",
|
||||
"trigger_combinator_all": "ट्रिगर और अंतराल (दोनों आवश्यक)",
|
||||
"delta_mode": "डेल्टा मोड",
|
||||
"from_state_optional": "किस स्थिति से (वैकल्पिक)",
|
||||
"to_state_optional": "किस स्थिति तक (वैकल्पिक)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "शुरुआत — सेटअप बढ़ने पर ये संकेत हट जाते हैं",
|
||||
"gs_setups_chip": "सुझाए गए सेटअप: पूर्व-निर्धारित ट्रिगर वाले {n} उपकरण मिले",
|
||||
"gs_adopt_chip": "{n} समस्या सेंसर रखरखाव कार्य बन सकते हैं",
|
||||
"gs_fleet_chip": "एक क्लिक में बैटरी बेड़ा सेट करें"
|
||||
"gs_fleet_chip": "एक क्लिक में बैटरी बेड़ा सेट करें",
|
||||
"cal_editor_window": "डिफ़ॉल्ट विंडो",
|
||||
"cal_editor_window_week": "सप्ताह (7 दिन)",
|
||||
"cal_editor_window_fortnight": "पखवाड़ा (14 दिन)",
|
||||
"cal_editor_window_month": "महीना (30 दिन, डिफ़ॉल्ट)",
|
||||
"cal_editor_window_year": "वर्ष (365 दिन, खाली दिन छिपे)",
|
||||
"cal_editor_show_chips": "कार्ड में विंडो चिप्स दिखाएँ",
|
||||
"cal_editor_chips_hint": "जब कार्ड ऐसी स्ट्रैटेजी व्यू में हो जो पहले से विंडो चयनक है, तो चिप्स छिपाएँ।",
|
||||
"cal_editor_show_user_filter": "उपयोगकर्ता फ़िल्टर दिखाएँ",
|
||||
"cal_editor_default_user": "डिफ़ॉल्ट उपयोगकर्ता फ़िल्टर",
|
||||
"cal_editor_my_tasks": "मेरे कार्य (वर्तमान उपयोगकर्ता)",
|
||||
"cal_editor_show_object_filter": "ऑब्जेक्ट फ़िल्टर दिखाएँ",
|
||||
"cal_editor_object_hint": "YAML से एक ऑब्जेक्ट पहले से चुनें: object_filter: \"<नाम>\" — या कार्ड को कई ऑब्जेक्ट तक सीमित करने हेतु नामों की सूची।"
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Megjegyzések (opcionális)",
|
||||
"cost_optional": "Költség (opcionális)",
|
||||
"duration_minutes": "Időtartam percben (opcionális)",
|
||||
"completed_at_optional": "Elvégezve ekkor (opcionális, üres = most)",
|
||||
"completed_at_future_error": "Az elvégzés dátuma nem lehet a jövőben.",
|
||||
"days": "nap",
|
||||
"day": "nap",
|
||||
"today": "Ma",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Entitás állapotának használata (attribútum nélkül)",
|
||||
"trigger_above": "Kiváltás e fölött",
|
||||
"trigger_below": "Kiváltás ez alatt",
|
||||
"trigger_equals": "Aktiválás ha egyenlő (=)",
|
||||
"trigger_not_equals": "Aktiválás ha eltér ettől (≠)",
|
||||
"for_at_least_minutes": "Legalább ennyi ideig (perc)",
|
||||
"safety_interval_days": "Biztonsági intervallum (nap, opcionális)",
|
||||
"safety_interval": "Biztonsági intervallum (opcionális)",
|
||||
"trigger_combinator": "Trigger és időköz kombinálása",
|
||||
"trigger_combinator_any": "Trigger vagy időköz (amelyik előbb)",
|
||||
"trigger_combinator_all": "Trigger és időköz (mindkettő szükséges)",
|
||||
"delta_mode": "Delta mód",
|
||||
"from_state_optional": "Kezdő állapot (opcionális)",
|
||||
"to_state_optional": "Célállapot (opcionális)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Első lépések — a tippek eltűnnek, ahogy a beállítás bővül",
|
||||
"gs_setups_chip": "Javasolt beállítások: {n} eszköz előre bekötött triggerekkel",
|
||||
"gs_adopt_chip": "{n} problémaérzékelő karbantartási feladattá válhat",
|
||||
"gs_fleet_chip": "Egy kattintás beállítja az elemflottát"
|
||||
"gs_fleet_chip": "Egy kattintás beállítja az elemflottát",
|
||||
"cal_editor_window": "Alapértelmezett időablak",
|
||||
"cal_editor_window_week": "Hét (7 nap)",
|
||||
"cal_editor_window_fortnight": "Két hét (14 nap)",
|
||||
"cal_editor_window_month": "Hónap (30 nap, alapértelmezett)",
|
||||
"cal_editor_window_year": "Év (365 nap, üres napok elrejtve)",
|
||||
"cal_editor_show_chips": "Időablak-választók megjelenítése a kártyán",
|
||||
"cal_editor_chips_hint": "Rejtsd el a választókat, ha a kártya olyan stratégianézetben van, amely már időablak-választóként szolgál.",
|
||||
"cal_editor_show_user_filter": "Felhasználószűrő megjelenítése",
|
||||
"cal_editor_default_user": "Alapértelmezett felhasználószűrő",
|
||||
"cal_editor_my_tasks": "Saját feladatok (aktuális felhasználó)",
|
||||
"cal_editor_show_object_filter": "Objektumszűrő megjelenítése",
|
||||
"cal_editor_object_hint": "Előválasztás YAML-lel: object_filter: \"<név>\" — vagy névlista, hogy a kártya több objektumra korlátozódjon."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Note (opzionale)",
|
||||
"cost_optional": "Costo (opzionale)",
|
||||
"duration_minutes": "Durata in minuti (opzionale)",
|
||||
"completed_at_optional": "Completato il (opzionale, vuoto = adesso)",
|
||||
"completed_at_future_error": "La data di completamento non può essere nel futuro.",
|
||||
"days": "giorni",
|
||||
"day": "giorno",
|
||||
"today": "Oggi",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Usa stato dell'entità (nessun attributo)",
|
||||
"trigger_above": "Attivare sopra",
|
||||
"trigger_below": "Attivare sotto",
|
||||
"trigger_equals": "Attiva quando uguale a (=)",
|
||||
"trigger_not_equals": "Attiva quando diverso da (≠)",
|
||||
"for_at_least_minutes": "Per almeno (minuti)",
|
||||
"safety_interval_days": "Intervallo di sicurezza (giorni, opzionale)",
|
||||
"safety_interval": "Intervallo di sicurezza (opzionale)",
|
||||
"trigger_combinator": "Combina trigger e intervallo",
|
||||
"trigger_combinator_any": "Trigger o intervallo (il primo)",
|
||||
"trigger_combinator_all": "Trigger e intervallo (entrambi richiesti)",
|
||||
"delta_mode": "Modalità delta",
|
||||
"from_state_optional": "Dallo stato (opzionale)",
|
||||
"to_state_optional": "Allo stato (opzionale)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Primi passi — questi suggerimenti scompaiono man mano che la configurazione cresce",
|
||||
"gs_setups_chip": "Configurazioni suggerite: trovati {n} dispositivi con trigger preconfigurati",
|
||||
"gs_adopt_chip": "{n} sensori di problemi possono diventare attività di manutenzione",
|
||||
"gs_fleet_chip": "Un clic configura la flotta di batterie"
|
||||
"gs_fleet_chip": "Un clic configura la flotta di batterie",
|
||||
"cal_editor_window": "Finestra predefinita",
|
||||
"cal_editor_window_week": "Settimana (7 giorni)",
|
||||
"cal_editor_window_fortnight": "Due settimane (14 giorni)",
|
||||
"cal_editor_window_month": "Mese (30 giorni, predefinito)",
|
||||
"cal_editor_window_year": "Anno (365 giorni, giorni vuoti nascosti)",
|
||||
"cal_editor_show_chips": "Mostra i chip della finestra nella scheda",
|
||||
"cal_editor_chips_hint": "Nascondi i chip quando la scheda è in una vista strategia che funge già da selettore di finestra.",
|
||||
"cal_editor_show_user_filter": "Mostra il filtro utente",
|
||||
"cal_editor_default_user": "Filtro utente predefinito",
|
||||
"cal_editor_my_tasks": "Le mie attività (utente attuale)",
|
||||
"cal_editor_show_object_filter": "Mostra il filtro oggetto",
|
||||
"cal_editor_object_hint": "Preseleziona un oggetto via YAML: object_filter: \"<nome>\" — o un elenco di nomi per limitare la scheda a più oggetti."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "メモ(任意)",
|
||||
"cost_optional": "費用(任意)",
|
||||
"duration_minutes": "所要時間(分、任意)",
|
||||
"completed_at_optional": "完了日時(任意・空欄 = 現在)",
|
||||
"completed_at_future_error": "完了日時に未来は指定できません。",
|
||||
"days": "日",
|
||||
"day": "日",
|
||||
"today": "今日",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "エンティティの状態を使用(属性なし)",
|
||||
"trigger_above": "この値を超えたらトリガー",
|
||||
"trigger_below": "この値を下回ったらトリガー",
|
||||
"trigger_equals": "値が一致したらトリガー(=)",
|
||||
"trigger_not_equals": "値が異なればトリガー(≠)",
|
||||
"for_at_least_minutes": "最低継続時間(分)",
|
||||
"safety_interval_days": "安全間隔(日、任意)",
|
||||
"safety_interval": "安全間隔(任意)",
|
||||
"trigger_combinator": "トリガーと間隔の組み合わせ",
|
||||
"trigger_combinator_any": "トリガーまたは間隔(先に満たした方)",
|
||||
"trigger_combinator_all": "トリガーと間隔(両方必須)",
|
||||
"delta_mode": "差分モード",
|
||||
"from_state_optional": "変化前の状態(任意)",
|
||||
"to_state_optional": "変化後の状態(任意)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "はじめに — セットアップが進むとこれらのヒントは消えます",
|
||||
"gs_setups_chip": "推奨セットアップ:トリガー設定済みのデバイスを{n}台検出",
|
||||
"gs_adopt_chip": "{n}個の問題センサーをメンテナンスタスクにできます",
|
||||
"gs_fleet_chip": "ワンクリックで電池フリートを設定"
|
||||
"gs_fleet_chip": "ワンクリックで電池フリートを設定",
|
||||
"cal_editor_window": "既定の期間",
|
||||
"cal_editor_window_week": "1週間(7日)",
|
||||
"cal_editor_window_fortnight": "2週間(14日)",
|
||||
"cal_editor_window_month": "1か月(30日・既定)",
|
||||
"cal_editor_window_year": "1年(365日・空の日は省略)",
|
||||
"cal_editor_show_chips": "カード内に期間チップを表示",
|
||||
"cal_editor_chips_hint": "ストラテジービューが期間選択を担う場合はチップを非表示にします。",
|
||||
"cal_editor_show_user_filter": "ユーザーフィルターを表示",
|
||||
"cal_editor_default_user": "既定のユーザーフィルター",
|
||||
"cal_editor_my_tasks": "自分のタスク(現在のユーザー)",
|
||||
"cal_editor_show_object_filter": "オブジェクトフィルターを表示",
|
||||
"cal_editor_object_hint": "YAML でオブジェクトを事前選択:object_filter: \"<名前>\" — 複数指定はカードを複数オブジェクトに限定します。"
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "메모 (선택)",
|
||||
"cost_optional": "비용 (선택)",
|
||||
"duration_minutes": "소요 시간(분, 선택)",
|
||||
"completed_at_optional": "완료 시각 (선택, 비우면 지금)",
|
||||
"completed_at_future_error": "완료 날짜는 미래일 수 없습니다.",
|
||||
"days": "일",
|
||||
"day": "일",
|
||||
"today": "오늘",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "엔티티 상태 사용 (속성 없음)",
|
||||
"trigger_above": "초과 시 트리거",
|
||||
"trigger_below": "미만 시 트리거",
|
||||
"trigger_equals": "값이 같으면 트리거 (=)",
|
||||
"trigger_not_equals": "값이 다르면 트리거 (≠)",
|
||||
"for_at_least_minutes": "최소 지속 시간 (분)",
|
||||
"safety_interval_days": "안전 주기 (일, 선택)",
|
||||
"safety_interval": "안전 주기 (선택)",
|
||||
"trigger_combinator": "트리거와 간격 결합",
|
||||
"trigger_combinator_any": "트리거 또는 간격 (먼저 충족)",
|
||||
"trigger_combinator_all": "트리거와 간격 (둘 다 필요)",
|
||||
"delta_mode": "델타 모드",
|
||||
"from_state_optional": "변경 전 상태 (선택)",
|
||||
"to_state_optional": "변경 후 상태 (선택)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "시작하기 — 설정이 늘어나면 이 힌트는 사라집니다",
|
||||
"gs_setups_chip": "추천 설정: 트리거가 준비된 기기 {n}대 발견",
|
||||
"gs_adopt_chip": "문제 센서 {n}개를 유지보수 작업으로 만들 수 있습니다",
|
||||
"gs_fleet_chip": "클릭 한 번으로 배터리 플릿 설정"
|
||||
"gs_fleet_chip": "클릭 한 번으로 배터리 플릿 설정",
|
||||
"cal_editor_window": "기본 기간",
|
||||
"cal_editor_window_week": "1주 (7일)",
|
||||
"cal_editor_window_fortnight": "2주 (14일)",
|
||||
"cal_editor_window_month": "1개월 (30일, 기본)",
|
||||
"cal_editor_window_year": "1년 (365일, 빈 날은 접힘)",
|
||||
"cal_editor_show_chips": "카드 안에 기간 칩 표시",
|
||||
"cal_editor_chips_hint": "전략 뷰가 이미 기간 선택기 역할을 하면 칩을 숨기세요.",
|
||||
"cal_editor_show_user_filter": "사용자 필터 표시",
|
||||
"cal_editor_default_user": "기본 사용자 필터",
|
||||
"cal_editor_my_tasks": "내 작업 (현재 사용자)",
|
||||
"cal_editor_show_object_filter": "객체 필터 표시",
|
||||
"cal_editor_object_hint": "YAML로 객체를 미리 선택: object_filter: \"<이름>\" — 이름 목록으로 카드를 여러 객체로 제한할 수 있습니다."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Notater (valgfritt)",
|
||||
"cost_optional": "Kostnad (valgfritt)",
|
||||
"duration_minutes": "Varighet i minutter (valgfritt)",
|
||||
"completed_at_optional": "Utført den (valgfritt, tomt = nå)",
|
||||
"completed_at_future_error": "Fullføringsdatoen kan ikke ligge i fremtiden.",
|
||||
"days": "dager",
|
||||
"day": "dag",
|
||||
"today": "I dag",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Bruk entitetstilstand (ingen attributt)",
|
||||
"trigger_above": "Utløs over",
|
||||
"trigger_below": "Utløs under",
|
||||
"trigger_equals": "Utløs ved lik (=)",
|
||||
"trigger_not_equals": "Utløs ved forskjellig fra (≠)",
|
||||
"for_at_least_minutes": "I minst (minutter)",
|
||||
"safety_interval_days": "Sikkerhetsintervall (dager, valgfritt)",
|
||||
"safety_interval": "Sikkerhetsintervall (valgfritt)",
|
||||
"trigger_combinator": "Kombiner utløser og intervall",
|
||||
"trigger_combinator_any": "Utløser eller intervall (først oppfylt)",
|
||||
"trigger_combinator_all": "Utløser og intervall (begge kreves)",
|
||||
"delta_mode": "Deltamodus",
|
||||
"from_state_optional": "Fra tilstand (valgfritt)",
|
||||
"to_state_optional": "Til tilstand (valgfritt)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Kom i gang — tipsene forsvinner etter hvert som oppsettet vokser",
|
||||
"gs_setups_chip": "Foreslåtte oppsett fant {n} enheter med ferdigkoblede utløsere",
|
||||
"gs_adopt_chip": "{n} problemsensorer kan bli vedlikeholdsoppgaver",
|
||||
"gs_fleet_chip": "Ett klikk setter opp batteriflåten"
|
||||
"gs_fleet_chip": "Ett klikk setter opp batteriflåten",
|
||||
"cal_editor_window": "Standardvindu",
|
||||
"cal_editor_window_week": "Uke (7 dager)",
|
||||
"cal_editor_window_fortnight": "To uker (14 dager)",
|
||||
"cal_editor_window_month": "Måned (30 dager, standard)",
|
||||
"cal_editor_window_year": "År (365 dager, tomme dager skjult)",
|
||||
"cal_editor_show_chips": "Vis vindus-chips i kortet",
|
||||
"cal_editor_chips_hint": "Skjul chipsene når kortet er innebygd i en strategivisning som allerede fungerer som vindusvelger.",
|
||||
"cal_editor_show_user_filter": "Vis brukerfilter",
|
||||
"cal_editor_default_user": "Standard brukerfilter",
|
||||
"cal_editor_my_tasks": "Mine oppgaver (gjeldende bruker)",
|
||||
"cal_editor_show_object_filter": "Vis objektfilter",
|
||||
"cal_editor_object_hint": "Forhåndsvelg et objekt via YAML: object_filter: \"<navn>\" — eller en liste med navn for å begrense kortet til flere objekter."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Notities (optioneel)",
|
||||
"cost_optional": "Kosten (optioneel)",
|
||||
"duration_minutes": "Duur in minuten (optioneel)",
|
||||
"completed_at_optional": "Voltooid op (optioneel, leeg = nu)",
|
||||
"completed_at_future_error": "De voltooiingsdatum mag niet in de toekomst liggen.",
|
||||
"days": "dagen",
|
||||
"day": "dag",
|
||||
"today": "Vandaag",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Entiteitsstatus gebruiken (geen attribuut)",
|
||||
"trigger_above": "Activeren als boven",
|
||||
"trigger_below": "Activeren als onder",
|
||||
"trigger_equals": "Activeren bij gelijk aan (=)",
|
||||
"trigger_not_equals": "Activeren bij afwijkend van (≠)",
|
||||
"for_at_least_minutes": "Voor minstens (minuten)",
|
||||
"safety_interval_days": "Veiligheidsinterval (dagen, optioneel)",
|
||||
"safety_interval": "Veiligheidsinterval (optioneel)",
|
||||
"trigger_combinator": "Trigger en interval combineren",
|
||||
"trigger_combinator_any": "Trigger of interval (eerst vervuld)",
|
||||
"trigger_combinator_all": "Trigger en interval (beide vereist)",
|
||||
"delta_mode": "Deltamodus",
|
||||
"from_state_optional": "Van status (optioneel)",
|
||||
"to_state_optional": "Naar status (optioneel)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Aan de slag — deze tips verdwijnen naarmate je installatie groeit",
|
||||
"gs_setups_chip": "Voorgestelde setups: {n} apparaten met vooraf ingestelde triggers gevonden",
|
||||
"gs_adopt_chip": "{n} probleemsensoren kunnen onderhoudstaken worden",
|
||||
"gs_fleet_chip": "Eén klik stelt het batterijpark in"
|
||||
"gs_fleet_chip": "Eén klik stelt het batterijpark in",
|
||||
"cal_editor_window": "Standaardvenster",
|
||||
"cal_editor_window_week": "Week (7 dagen)",
|
||||
"cal_editor_window_fortnight": "Twee weken (14 dagen)",
|
||||
"cal_editor_window_month": "Maand (30 dagen, standaard)",
|
||||
"cal_editor_window_year": "Jaar (365 dagen, lege dagen verborgen)",
|
||||
"cal_editor_show_chips": "Vensterchips in de kaart tonen",
|
||||
"cal_editor_chips_hint": "Verberg de chips wanneer de kaart in een strategieweergave staat die al als vensterkeuze dient.",
|
||||
"cal_editor_show_user_filter": "Gebruikersfilter tonen",
|
||||
"cal_editor_default_user": "Standaard gebruikersfilter",
|
||||
"cal_editor_my_tasks": "Mijn taken (huidige gebruiker)",
|
||||
"cal_editor_show_object_filter": "Objectfilter tonen",
|
||||
"cal_editor_object_hint": "Selecteer een object vooraf via YAML: object_filter: \"<naam>\" — of een lijst met namen om de kaart tot meerdere objecten te beperken."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Notatki (opcjonalne)",
|
||||
"cost_optional": "Koszt (opcjonalne)",
|
||||
"duration_minutes": "Czas trwania w minutach (opcjonalne)",
|
||||
"completed_at_optional": "Wykonano dnia (opcjonalne, puste = teraz)",
|
||||
"completed_at_future_error": "Data wykonania nie może być w przyszłości.",
|
||||
"days": "dni",
|
||||
"day": "dzień",
|
||||
"today": "Dzisiaj",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Użyj stanu encji (bez atrybutu)",
|
||||
"trigger_above": "Wyzwól powyżej",
|
||||
"trigger_below": "Wyzwól poniżej",
|
||||
"trigger_equals": "Wyzwól przy równym (=)",
|
||||
"trigger_not_equals": "Wyzwól przy różnym od (≠)",
|
||||
"for_at_least_minutes": "Przez co najmniej (minuty)",
|
||||
"safety_interval_days": "Interwał bezpieczeństwa (dni, opcjonalny)",
|
||||
"safety_interval": "Interwał bezpieczeństwa (opcjonalny)",
|
||||
"trigger_combinator": "Połącz wyzwalacz i interwał",
|
||||
"trigger_combinator_any": "Wyzwalacz lub interwał (co pierwsze)",
|
||||
"trigger_combinator_all": "Wyzwalacz i interwał (oba wymagane)",
|
||||
"delta_mode": "Tryb delta",
|
||||
"from_state_optional": "Ze stanu (opcjonalne)",
|
||||
"to_state_optional": "Do stanu (opcjonalne)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Pierwsze kroki — te wskazówki znikają wraz z rozwojem konfiguracji",
|
||||
"gs_setups_chip": "Sugerowane konfiguracje: znaleziono {n} urządzeń z gotowymi wyzwalaczami",
|
||||
"gs_adopt_chip": "{n} czujników problemów może stać się zadaniami konserwacji",
|
||||
"gs_fleet_chip": "Jedno kliknięcie konfiguruje flotę baterii"
|
||||
"gs_fleet_chip": "Jedno kliknięcie konfiguruje flotę baterii",
|
||||
"cal_editor_window": "Okno domyślne",
|
||||
"cal_editor_window_week": "Tydzień (7 dni)",
|
||||
"cal_editor_window_fortnight": "Dwa tygodnie (14 dni)",
|
||||
"cal_editor_window_month": "Miesiąc (30 dni, domyślnie)",
|
||||
"cal_editor_window_year": "Rok (365 dni, puste dni ukryte)",
|
||||
"cal_editor_show_chips": "Pokaż przełączniki okna na karcie",
|
||||
"cal_editor_chips_hint": "Ukryj przełączniki, gdy karta jest osadzona w widoku strategii, który już pełni rolę wyboru okna.",
|
||||
"cal_editor_show_user_filter": "Pokaż filtr użytkownika",
|
||||
"cal_editor_default_user": "Domyślny filtr użytkownika",
|
||||
"cal_editor_my_tasks": "Moje zadania (bieżący użytkownik)",
|
||||
"cal_editor_show_object_filter": "Pokaż filtr obiektu",
|
||||
"cal_editor_object_hint": "Wybierz obiekt w YAML: object_filter: \"<nazwa>\" — lub listę nazw, aby ograniczyć kartę do kilku obiektów."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Observações (opcional)",
|
||||
"cost_optional": "Custo (opcional)",
|
||||
"duration_minutes": "Duração em minutos (opcional)",
|
||||
"completed_at_optional": "Concluído em (opcional, vazio = agora)",
|
||||
"completed_at_future_error": "A data de conclusão não pode estar no futuro.",
|
||||
"days": "dias",
|
||||
"day": "dia",
|
||||
"today": "Hoje",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Usar o estado da entidade (sem atributo)",
|
||||
"trigger_above": "Acionar acima de",
|
||||
"trigger_below": "Acionar abaixo de",
|
||||
"trigger_equals": "Acionar quando igual a (=)",
|
||||
"trigger_not_equals": "Acionar quando diferente de (≠)",
|
||||
"for_at_least_minutes": "Por pelo menos (minutos)",
|
||||
"safety_interval_days": "Intervalo de segurança (dias, opcional)",
|
||||
"safety_interval": "Intervalo de segurança (opcional)",
|
||||
"trigger_combinator": "Combinar gatilho e intervalo",
|
||||
"trigger_combinator_any": "Gatilho ou intervalo (o primeiro)",
|
||||
"trigger_combinator_all": "Gatilho e intervalo (ambos exigidos)",
|
||||
"delta_mode": "Modo delta",
|
||||
"from_state_optional": "Do estado (opcional)",
|
||||
"to_state_optional": "Para o estado (opcional)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Primeiros passos — estas dicas somem conforme a configuração cresce",
|
||||
"gs_setups_chip": "Configurações sugeridas: {n} dispositivos com gatilhos pré-configurados",
|
||||
"gs_adopt_chip": "{n} sensores de problema podem virar tarefas de manutenção",
|
||||
"gs_fleet_chip": "Um clique configura a frota de pilhas"
|
||||
"gs_fleet_chip": "Um clique configura a frota de pilhas",
|
||||
"cal_editor_window": "Janela padrão",
|
||||
"cal_editor_window_week": "Semana (7 dias)",
|
||||
"cal_editor_window_fortnight": "Quinzena (14 dias)",
|
||||
"cal_editor_window_month": "Mês (30 dias, padrão)",
|
||||
"cal_editor_window_year": "Ano (365 dias, dias vazios ocultos)",
|
||||
"cal_editor_show_chips": "Mostrar chips de janela no cartão",
|
||||
"cal_editor_chips_hint": "Oculte os chips quando o cartão estiver em uma visão de estratégia que já serve como seletor de janela.",
|
||||
"cal_editor_show_user_filter": "Mostrar filtro de usuário",
|
||||
"cal_editor_default_user": "Filtro de usuário padrão",
|
||||
"cal_editor_my_tasks": "Minhas tarefas (usuário atual)",
|
||||
"cal_editor_show_object_filter": "Mostrar filtro de objeto",
|
||||
"cal_editor_object_hint": "Pré-selecione um objeto via YAML: object_filter: \"<nome>\" — ou uma lista de nomes para limitar o cartão a vários objetos."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Notas (opcional)",
|
||||
"cost_optional": "Custo (opcional)",
|
||||
"duration_minutes": "Duração em minutos (opcional)",
|
||||
"completed_at_optional": "Concluído em (opcional, vazio = agora)",
|
||||
"completed_at_future_error": "A data de conclusão não pode estar no futuro.",
|
||||
"days": "dias",
|
||||
"day": "dia",
|
||||
"today": "Hoje",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Usar estado da entidade (sem atributo)",
|
||||
"trigger_above": "Acionar acima de",
|
||||
"trigger_below": "Acionar abaixo de",
|
||||
"trigger_equals": "Acionar quando igual a (=)",
|
||||
"trigger_not_equals": "Acionar quando diferente de (≠)",
|
||||
"for_at_least_minutes": "Durante pelo menos (minutos)",
|
||||
"safety_interval_days": "Intervalo de segurança (dias, opcional)",
|
||||
"safety_interval": "Intervalo de segurança (opcional)",
|
||||
"trigger_combinator": "Combinar acionador e intervalo",
|
||||
"trigger_combinator_any": "Acionador ou intervalo (o primeiro)",
|
||||
"trigger_combinator_all": "Acionador e intervalo (ambos exigidos)",
|
||||
"delta_mode": "Modo delta",
|
||||
"from_state_optional": "Do estado (opcional)",
|
||||
"to_state_optional": "Para o estado (opcional)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Primeiros passos — estas dicas desaparecem à medida que a configuração cresce",
|
||||
"gs_setups_chip": "Configurações sugeridas: {n} dispositivos com gatilhos pré-configurados",
|
||||
"gs_adopt_chip": "{n} sensores de problema podem tornar-se tarefas de manutenção",
|
||||
"gs_fleet_chip": "Um clique configura a frota de pilhas"
|
||||
"gs_fleet_chip": "Um clique configura a frota de pilhas",
|
||||
"cal_editor_window": "Janela predefinida",
|
||||
"cal_editor_window_week": "Semana (7 dias)",
|
||||
"cal_editor_window_fortnight": "Quinzena (14 dias)",
|
||||
"cal_editor_window_month": "Mês (30 dias, predefinido)",
|
||||
"cal_editor_window_year": "Ano (365 dias, dias vazios ocultos)",
|
||||
"cal_editor_show_chips": "Mostrar chips de janela no cartão",
|
||||
"cal_editor_chips_hint": "Oculte os chips quando o cartão está numa vista de estratégia que já serve de seletor de janela.",
|
||||
"cal_editor_show_user_filter": "Mostrar filtro de utilizador",
|
||||
"cal_editor_default_user": "Filtro de utilizador predefinido",
|
||||
"cal_editor_my_tasks": "As minhas tarefas (utilizador atual)",
|
||||
"cal_editor_show_object_filter": "Mostrar filtro de objeto",
|
||||
"cal_editor_object_hint": "Pré-selecione um objeto via YAML: object_filter: \"<nome>\" — ou uma lista de nomes para limitar o cartão a vários objetos."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Примечания (опционально)",
|
||||
"cost_optional": "Стоимость (опционально)",
|
||||
"duration_minutes": "Длительность в минутах (опционально)",
|
||||
"completed_at_optional": "Выполнено (необязательно, пусто = сейчас)",
|
||||
"completed_at_future_error": "Дата выполнения не может быть в будущем.",
|
||||
"days": "дней",
|
||||
"day": "день",
|
||||
"today": "Сегодня",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Использовать состояние сущности (без атрибута)",
|
||||
"trigger_above": "Срабатывать выше",
|
||||
"trigger_below": "Срабатывать ниже",
|
||||
"trigger_equals": "Срабатывать при равенстве (=)",
|
||||
"trigger_not_equals": "Срабатывать при отличии от (≠)",
|
||||
"for_at_least_minutes": "Не менее (минут)",
|
||||
"safety_interval_days": "Интервал безопасности (дни, опционально)",
|
||||
"safety_interval": "Интервал безопасности (опционально)",
|
||||
"trigger_combinator": "Совместить триггер и интервал",
|
||||
"trigger_combinator_any": "Триггер или интервал (что раньше)",
|
||||
"trigger_combinator_all": "Триггер и интервал (оба условия)",
|
||||
"delta_mode": "Режим дельты",
|
||||
"from_state_optional": "Из состояния (опционально)",
|
||||
"to_state_optional": "В состояние (опционально)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Первые шаги — эти подсказки исчезнут по мере роста настройки",
|
||||
"gs_setups_chip": "Рекомендуемые настройки: найдено {n} устройств с готовыми триггерами",
|
||||
"gs_adopt_chip": "{n} датчиков проблем могут стать задачами обслуживания",
|
||||
"gs_fleet_chip": "Один клик настроит парк батарей"
|
||||
"gs_fleet_chip": "Один клик настроит парк батарей",
|
||||
"cal_editor_window": "Окно по умолчанию",
|
||||
"cal_editor_window_week": "Неделя (7 дней)",
|
||||
"cal_editor_window_fortnight": "Две недели (14 дней)",
|
||||
"cal_editor_window_month": "Месяц (30 дней, по умолчанию)",
|
||||
"cal_editor_window_year": "Год (365 дней, пустые дни скрыты)",
|
||||
"cal_editor_show_chips": "Показывать чипы окна в карточке",
|
||||
"cal_editor_chips_hint": "Скройте чипы, если карточка встроена в стратегию, которая уже служит выбором окна.",
|
||||
"cal_editor_show_user_filter": "Показывать фильтр пользователя",
|
||||
"cal_editor_default_user": "Фильтр пользователя по умолчанию",
|
||||
"cal_editor_my_tasks": "Мои задачи (текущий пользователь)",
|
||||
"cal_editor_show_object_filter": "Показывать фильтр объекта",
|
||||
"cal_editor_object_hint": "Предварительный выбор объекта через YAML: object_filter: \"<имя>\" — или список имён, чтобы ограничить карточку несколькими объектами."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Anteckningar (valfritt)",
|
||||
"cost_optional": "Kostnad (valfritt)",
|
||||
"duration_minutes": "Varaktighet i minuter (valfritt)",
|
||||
"completed_at_optional": "Utförd den (valfritt, tomt = nu)",
|
||||
"completed_at_future_error": "Slutförandedatumet får inte ligga i framtiden.",
|
||||
"days": "dagar",
|
||||
"day": "dag",
|
||||
"today": "Idag",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Använd entitetstillstånd (inget attribut)",
|
||||
"trigger_above": "Utlös över",
|
||||
"trigger_below": "Utlös under",
|
||||
"trigger_equals": "Utlös vid lika med (=)",
|
||||
"trigger_not_equals": "Utlös vid skilt från (≠)",
|
||||
"for_at_least_minutes": "Under minst (minuter)",
|
||||
"safety_interval_days": "Säkerhetsintervall (dagar, valfritt)",
|
||||
"safety_interval": "Säkerhetsintervall (valfritt)",
|
||||
"trigger_combinator": "Kombinera utlösare och intervall",
|
||||
"trigger_combinator_any": "Utlösare eller intervall (först uppfylld)",
|
||||
"trigger_combinator_all": "Utlösare och intervall (båda krävs)",
|
||||
"delta_mode": "Delta-läge",
|
||||
"from_state_optional": "Från tillstånd (valfritt)",
|
||||
"to_state_optional": "Till tillstånd (valfritt)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Kom igång — tipsen försvinner när din installation växer",
|
||||
"gs_setups_chip": "Föreslagna uppsättningar hittade {n} enheter med förkopplade utlösare",
|
||||
"gs_adopt_chip": "{n} problemsensorer kan bli underhållsuppgifter",
|
||||
"gs_fleet_chip": "Ett klick konfigurerar batteriflottan"
|
||||
"gs_fleet_chip": "Ett klick konfigurerar batteriflottan",
|
||||
"cal_editor_window": "Standardfönster",
|
||||
"cal_editor_window_week": "Vecka (7 dagar)",
|
||||
"cal_editor_window_fortnight": "Två veckor (14 dagar)",
|
||||
"cal_editor_window_month": "Månad (30 dagar, standard)",
|
||||
"cal_editor_window_year": "År (365 dagar, tomma dagar dolda)",
|
||||
"cal_editor_show_chips": "Visa fönsterchips i kortet",
|
||||
"cal_editor_chips_hint": "Dölj chipsen när kortet är inbäddat i en strategivy som redan fungerar som fönsterväljare.",
|
||||
"cal_editor_show_user_filter": "Visa användarfilter",
|
||||
"cal_editor_default_user": "Standardanvändarfilter",
|
||||
"cal_editor_my_tasks": "Mina uppgifter (aktuell användare)",
|
||||
"cal_editor_show_object_filter": "Visa objektfilter",
|
||||
"cal_editor_object_hint": "Förvälj ett objekt via YAML: object_filter: \"<namn>\" — eller en lista med namn för att begränsa kortet till flera objekt."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Notlar (isteğe bağlı)",
|
||||
"cost_optional": "Maliyet (isteğe bağlı)",
|
||||
"duration_minutes": "Dakika cinsinden süre (isteğe bağlı)",
|
||||
"completed_at_optional": "Tamamlanma zamanı (isteğe bağlı, boş = şimdi)",
|
||||
"completed_at_future_error": "Tamamlanma tarihi gelecekte olamaz.",
|
||||
"days": "gün",
|
||||
"day": "gün",
|
||||
"today": "Bugün",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Varlık durumunu kullan (öznitelik yok)",
|
||||
"trigger_above": "Üstünde tetikle",
|
||||
"trigger_below": "Altında tetikle",
|
||||
"trigger_equals": "Şuna eşitse tetikle (=)",
|
||||
"trigger_not_equals": "Şundan farklıysa tetikle (≠)",
|
||||
"for_at_least_minutes": "En az (dakika)",
|
||||
"safety_interval_days": "Güvenlik aralığı (gün, isteğe bağlı)",
|
||||
"safety_interval": "Güvenlik aralığı (isteğe bağlı)",
|
||||
"trigger_combinator": "Tetikleyici ve aralığı birleştir",
|
||||
"trigger_combinator_any": "Tetikleyici veya aralık (ilk gerçekleşen)",
|
||||
"trigger_combinator_all": "Tetikleyici ve aralık (her ikisi gerekli)",
|
||||
"delta_mode": "Fark modu",
|
||||
"from_state_optional": "Başlangıç durumu (isteğe bağlı)",
|
||||
"to_state_optional": "Hedef durum (isteğe bağlı)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Başlarken — kurulumunuz büyüdükçe bu ipuçları kaybolur",
|
||||
"gs_setups_chip": "Önerilen kurulumlar {n} cihaz buldu (hazır tetikleyicilerle)",
|
||||
"gs_adopt_chip": "{n} sorun sensörü bakım görevine dönüşebilir",
|
||||
"gs_fleet_chip": "Tek tıkla pil filosunu kurun"
|
||||
"gs_fleet_chip": "Tek tıkla pil filosunu kurun",
|
||||
"cal_editor_window": "Varsayılan pencere",
|
||||
"cal_editor_window_week": "Hafta (7 gün)",
|
||||
"cal_editor_window_fortnight": "İki hafta (14 gün)",
|
||||
"cal_editor_window_month": "Ay (30 gün, varsayılan)",
|
||||
"cal_editor_window_year": "Yıl (365 gün, boş günler gizli)",
|
||||
"cal_editor_show_chips": "Pencere seçeneklerini kartta göster",
|
||||
"cal_editor_chips_hint": "Kart, zaten pencere seçici görevi gören bir strateji görünümüne gömülüyse seçenekleri gizleyin.",
|
||||
"cal_editor_show_user_filter": "Kullanıcı filtresini göster",
|
||||
"cal_editor_default_user": "Varsayılan kullanıcı filtresi",
|
||||
"cal_editor_my_tasks": "Görevlerim (geçerli kullanıcı)",
|
||||
"cal_editor_show_object_filter": "Nesne filtresini göster",
|
||||
"cal_editor_object_hint": "YAML ile bir nesne önceden seçin: object_filter: \"<ad>\" — veya kartı birden çok nesneyle sınırlamak için ad listesi."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Примітки (необов'язково)",
|
||||
"cost_optional": "Вартість (необов'язково)",
|
||||
"duration_minutes": "Тривалість у хвилинах (необов'язково)",
|
||||
"completed_at_optional": "Виконано (необов'язково, порожньо = зараз)",
|
||||
"completed_at_future_error": "Дата виконання не може бути в майбутньому.",
|
||||
"days": "днів",
|
||||
"day": "день",
|
||||
"today": "Сьогодні",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Використовувати стан об'єкта (без атрибута)",
|
||||
"trigger_above": "Спрацювати, коли вище",
|
||||
"trigger_below": "Спрацювати, коли нижче",
|
||||
"trigger_equals": "Спрацьовувати при рівності (=)",
|
||||
"trigger_not_equals": "Спрацьовувати при відмінності від (≠)",
|
||||
"for_at_least_minutes": "Протягом не менше (хвилин)",
|
||||
"safety_interval_days": "Страховий інтервал (дні, необов'язково)",
|
||||
"safety_interval": "Страховий інтервал (необов'язково)",
|
||||
"trigger_combinator": "Поєднати тригер та інтервал",
|
||||
"trigger_combinator_any": "Тригер або інтервал (що раніше)",
|
||||
"trigger_combinator_all": "Тригер та інтервал (обидва потрібні)",
|
||||
"delta_mode": "Режим дельти",
|
||||
"from_state_optional": "З стану (необов'язково)",
|
||||
"to_state_optional": "До стану (необов'язково)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Перші кроки — ці підказки зникнуть у міру зростання налаштування",
|
||||
"gs_setups_chip": "Рекомендовані налаштування: знайдено {n} пристроїв із готовими тригерами",
|
||||
"gs_adopt_chip": "{n} датчиків проблем можуть стати завданнями обслуговування",
|
||||
"gs_fleet_chip": "Один клік налаштує парк батарей"
|
||||
"gs_fleet_chip": "Один клік налаштує парк батарей",
|
||||
"cal_editor_window": "Вікно за замовчуванням",
|
||||
"cal_editor_window_week": "Тиждень (7 днів)",
|
||||
"cal_editor_window_fortnight": "Два тижні (14 днів)",
|
||||
"cal_editor_window_month": "Місяць (30 днів, типово)",
|
||||
"cal_editor_window_year": "Рік (365 днів, порожні дні приховано)",
|
||||
"cal_editor_show_chips": "Показувати чипи вікна в картці",
|
||||
"cal_editor_chips_hint": "Приховайте чипи, якщо картка вбудована в стратегію, що вже слугує вибором вікна.",
|
||||
"cal_editor_show_user_filter": "Показувати фільтр користувача",
|
||||
"cal_editor_default_user": "Типовий фільтр користувача",
|
||||
"cal_editor_my_tasks": "Мої завдання (поточний користувач)",
|
||||
"cal_editor_show_object_filter": "Показувати фільтр об'єкта",
|
||||
"cal_editor_object_hint": "Попередній вибір об'єкта через YAML: object_filter: \"<назва>\" — або список назв, щоб обмежити картку кількома об'єктами."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "备注 (可选)",
|
||||
"cost_optional": "成本 (可选)",
|
||||
"duration_minutes": "耗时 (分钟, 可选)",
|
||||
"completed_at_optional": "完成时间(可选,留空 = 现在)",
|
||||
"completed_at_future_error": "完成日期不能是未来时间。",
|
||||
"days": "天",
|
||||
"day": "天",
|
||||
"today": "今天",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "使用实体状态 (不使用属性)",
|
||||
"trigger_above": "高于此值触发",
|
||||
"trigger_below": "低于此值触发",
|
||||
"trigger_equals": "等于时触发(=)",
|
||||
"trigger_not_equals": "不等于时触发(≠)",
|
||||
"for_at_least_minutes": "持续至少 (分钟)",
|
||||
"safety_interval_days": "安全间隔 (天, 可选)",
|
||||
"safety_interval": "安全间隔 (可选)",
|
||||
"trigger_combinator": "组合触发器与间隔",
|
||||
"trigger_combinator_any": "触发器或间隔(先到者)",
|
||||
"trigger_combinator_all": "触发器与间隔(两者皆需)",
|
||||
"delta_mode": "增量模式",
|
||||
"from_state_optional": "起始状态 (可选)",
|
||||
"to_state_optional": "目标状态 (可选)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "入门提示——随着配置的完善,这些提示会自动消失",
|
||||
"gs_setups_chip": "推荐配置发现 {n} 台设备(含预设触发器)",
|
||||
"gs_adopt_chip": "{n} 个问题传感器可转换为维护任务",
|
||||
"gs_fleet_chip": "一键设置电池车队"
|
||||
"gs_fleet_chip": "一键设置电池车队",
|
||||
"cal_editor_window": "默认时间窗",
|
||||
"cal_editor_window_week": "一周(7天)",
|
||||
"cal_editor_window_fortnight": "两周(14天)",
|
||||
"cal_editor_window_month": "一个月(30天,默认)",
|
||||
"cal_editor_window_year": "一年(365天,空白日折叠)",
|
||||
"cal_editor_show_chips": "在卡片内显示时间窗标签",
|
||||
"cal_editor_chips_hint": "当卡片嵌入已充当时间窗选择器的策略视图时,请隐藏标签。",
|
||||
"cal_editor_show_user_filter": "显示用户筛选",
|
||||
"cal_editor_default_user": "默认用户筛选",
|
||||
"cal_editor_my_tasks": "我的任务(当前用户)",
|
||||
"cal_editor_show_object_filter": "显示对象筛选",
|
||||
"cal_editor_object_hint": "通过 YAML 预选对象:object_filter: \"<对象名>\" — 或名称列表,将卡片限定为多个对象。"
|
||||
}
|
||||
@@ -5,11 +5,12 @@
|
||||
* (clock vs trending-up), prediction-confidence pill, projected recurrences
|
||||
* at 55% opacity, today-pill highlight, empty-day collapsing in the year view.
|
||||
*
|
||||
* Click on an event fires an ``ll-custom`` event with payload
|
||||
* ``{type: "maintenance-supporter:open-task", entry_id, task_id}``. The
|
||||
* dashboard-strategy bundle's document-level handler picks that up and
|
||||
* either opens the task dialog in-place (preferred) or deep-links into the
|
||||
* panel as a fallback.
|
||||
* Click on an event opens the task quick-actions dialog (future events) or
|
||||
* the history-edit dialog (past events) DIRECTLY via the shared dialog-mount
|
||||
* — so clicks work on any dashboard, with or without the strategy bundle.
|
||||
* When the dialog helper cannot mount, an ``ll-custom`` event
|
||||
* (``{type: "maintenance-supporter:open-task", entry_id, task_id}``) is
|
||||
* dispatched as the fallback for the strategy bundle's document listener.
|
||||
*
|
||||
* Card config:
|
||||
*
|
||||
@@ -36,6 +37,7 @@ import {
|
||||
import { calendarStyles } from "./calendar-styles";
|
||||
import { sharedStyles, DEFAULT_CURRENCY_SYMBOL, t, ensureLocale, isLocaleLoaded, setDateTimePrefs, formatDueDays, langOf } from "./styles";
|
||||
import { registerCustomCard } from "./helpers/register-card";
|
||||
import { openHistoryEditDialog, openTaskQuickActions } from "./dialog-mount";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
MaintenanceObjectResponse,
|
||||
@@ -200,23 +202,17 @@ export class MaintenanceCalendarCard extends LitElement {
|
||||
|
||||
private _onEventClick(ev: CalendarEvent): void {
|
||||
// Past events carry a history_timestamp — those open the history-edit
|
||||
// dialog instead of the task editor. Future / next_due events open
|
||||
// the task editor as usual.
|
||||
// dialog instead of the task editor. Future / next_due events open the
|
||||
// task quick-actions. Dialogs open DIRECTLY via the shared dialog-mount
|
||||
// (same fix the task card got): the ll-custom event this used to
|
||||
// dispatch is only handled by the strategy bundle's document listener,
|
||||
// so on a plain dashboard the clicks silently did nothing. ll-custom
|
||||
// stays as the fallback when the dialog helper cannot mount.
|
||||
if (ev.history_timestamp) {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("ll-custom", {
|
||||
detail: {
|
||||
type: "maintenance-supporter:edit-history",
|
||||
entry_id: ev.entry_id,
|
||||
task_id: ev.task_id,
|
||||
original_timestamp: ev.history_timestamp,
|
||||
},
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
void this._openHistoryEntry(ev);
|
||||
return;
|
||||
}
|
||||
if (openTaskQuickActions(ev.entry_id, ev.task_id)) return;
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("ll-custom", {
|
||||
detail: {
|
||||
@@ -230,6 +226,48 @@ export class MaintenanceCalendarCard extends LitElement {
|
||||
);
|
||||
}
|
||||
|
||||
/** Fetch the recorded entry and open the history-edit dialog directly
|
||||
* (mirrors the strategy shim's ll-custom "edit-history" path). */
|
||||
private async _openHistoryEntry(ev: CalendarEvent): Promise<void> {
|
||||
try {
|
||||
const resp = await this.hass.connection.sendMessagePromise<{
|
||||
tasks?: Array<{ id: string; history?: Array<Record<string, unknown>> }>;
|
||||
}>({ type: "maintenance_supporter/object", entry_id: ev.entry_id });
|
||||
const entry = resp.tasks
|
||||
?.find((tk) => tk.id === ev.task_id)
|
||||
?.history?.find((h) => h.timestamp === ev.history_timestamp);
|
||||
if (!entry) return;
|
||||
const opened = openHistoryEditDialog({
|
||||
entry_id: ev.entry_id,
|
||||
task_id: ev.task_id,
|
||||
original_timestamp: ev.history_timestamp!,
|
||||
type: (entry.type as string) || "completed",
|
||||
timestamp: (entry.timestamp as string) || ev.history_timestamp!,
|
||||
notes: (entry.notes as string | null) ?? null,
|
||||
cost: (entry.cost as number | null) ?? null,
|
||||
duration: (entry.duration as number | null) ?? null,
|
||||
completed_by: (entry.completed_by as string | null) ?? null,
|
||||
used_parts:
|
||||
(entry.used_parts as Array<{ part_id: string; name?: string; quantity: number; entry_id?: string }> | null) ?? null,
|
||||
});
|
||||
if (opened) return;
|
||||
} catch {
|
||||
/* fall through to the ll-custom fallback below */
|
||||
}
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("ll-custom", {
|
||||
detail: {
|
||||
type: "maintenance-supporter:edit-history",
|
||||
entry_id: ev.entry_id,
|
||||
task_id: ev.task_id,
|
||||
original_timestamp: ev.history_timestamp,
|
||||
},
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.hass) return nothing;
|
||||
|
||||
@@ -456,11 +494,11 @@ export class MaintenanceCalendarCard extends LitElement {
|
||||
// and user-filter on/off. Same pattern as MaintenanceSupporterCardEditor —
|
||||
// LitElement with setConfig + dispatched config-changed.
|
||||
|
||||
const WINDOW_DAY_OPTIONS: Array<{ value: WindowDays; label: string }> = [
|
||||
{ value: 7, label: "Week (7 days)" },
|
||||
{ value: 14, label: "Fortnight (14 days)" },
|
||||
{ value: 30, label: "Month (30 days, default)" },
|
||||
{ value: 365, label: "Year (365 days, empty days collapsed)" },
|
||||
const WINDOW_DAY_KEYS: Array<{ value: WindowDays; key: string }> = [
|
||||
{ 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" },
|
||||
];
|
||||
|
||||
class MaintenanceCalendarCardEditor extends LitElement {
|
||||
@@ -469,10 +507,21 @@ class MaintenanceCalendarCardEditor extends LitElement {
|
||||
type: "custom:maintenance-supporter-calendar-card",
|
||||
};
|
||||
|
||||
private get _lang(): string {
|
||||
return langOf(this.hass);
|
||||
}
|
||||
|
||||
setConfig(config: CalendarCardConfig): void {
|
||||
this._config = { ...config };
|
||||
}
|
||||
|
||||
/** The editor renders before the locale JSON is fetched — re-render once
|
||||
* it lands so the labels localize (same pattern as the card itself). */
|
||||
updated(): void {
|
||||
const lang = this._lang;
|
||||
if (lang && !isLocaleLoaded(lang)) void ensureLocale(lang).then(() => this.requestUpdate());
|
||||
}
|
||||
|
||||
private _valueChanged(key: keyof CalendarCardConfig, value: unknown): void {
|
||||
const newConfig = { ...this._config, [key]: value } as CalendarCardConfig;
|
||||
// Drop default-equivalent values so saved YAML stays minimal
|
||||
@@ -502,6 +551,7 @@ class MaintenanceCalendarCardEditor extends LitElement {
|
||||
}
|
||||
|
||||
render() {
|
||||
const L = this._lang;
|
||||
const currentWindow = this._config.window_days ?? 30;
|
||||
const showChips = this._config.show_window_chips !== false;
|
||||
const showUserFilter = this._config.show_user_filter !== false;
|
||||
@@ -510,7 +560,7 @@ class MaintenanceCalendarCardEditor extends LitElement {
|
||||
return html`
|
||||
<div class="editor">
|
||||
<div class="row">
|
||||
<label for="title">Title (optional)</label>
|
||||
<label for="title">${t("card_title", L)}</label>
|
||||
<input
|
||||
id="title"
|
||||
type="text"
|
||||
@@ -520,7 +570,7 @@ class MaintenanceCalendarCardEditor extends LitElement {
|
||||
/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label for="window">Default window</label>
|
||||
<label for="window">${t("cal_editor_window", L)}</label>
|
||||
<select
|
||||
id="window"
|
||||
@change=${(e: Event) =>
|
||||
@@ -529,14 +579,14 @@ class MaintenanceCalendarCardEditor extends LitElement {
|
||||
Number((e.target as HTMLSelectElement).value) as WindowDays,
|
||||
)}
|
||||
>
|
||||
${WINDOW_DAY_OPTIONS.map(
|
||||
${WINDOW_DAY_KEYS.map(
|
||||
(o) =>
|
||||
html`<option value="${o.value}" ?selected=${o.value === currentWindow}>${o.label}</option>`,
|
||||
html`<option value="${o.value}" ?selected=${o.value === currentWindow}>${t(o.key, L)}</option>`,
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<div class="row toggle">
|
||||
<label for="chips">Show window chips inside the card</label>
|
||||
<label for="chips">${t("cal_editor_show_chips", L)}</label>
|
||||
<input
|
||||
id="chips"
|
||||
type="checkbox"
|
||||
@@ -548,12 +598,9 @@ class MaintenanceCalendarCardEditor extends LitElement {
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div class="hint">
|
||||
Hide the chips when the card is embedded in a strategy view that
|
||||
already serves as the window selector.
|
||||
</div>
|
||||
<div class="hint">${t("cal_editor_chips_hint", L)}</div>
|
||||
<div class="row toggle">
|
||||
<label for="userf">Show user filter dropdown</label>
|
||||
<label for="userf">${t("cal_editor_show_user_filter", L)}</label>
|
||||
<input
|
||||
id="userf"
|
||||
type="checkbox"
|
||||
@@ -566,7 +613,7 @@ class MaintenanceCalendarCardEditor extends LitElement {
|
||||
/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label for="userv">Default user filter</label>
|
||||
<label for="userv">${t("cal_editor_default_user", L)}</label>
|
||||
<select
|
||||
id="userv"
|
||||
@change=${(e: Event) =>
|
||||
@@ -575,14 +622,14 @@ class MaintenanceCalendarCardEditor extends LitElement {
|
||||
(e.target as HTMLSelectElement).value,
|
||||
)}
|
||||
>
|
||||
<option value="" ?selected=${userFilter === ""}>All users</option>
|
||||
<option value="" ?selected=${userFilter === ""}>${t("all_users", L)}</option>
|
||||
<option value="current_user" ?selected=${userFilter === "current_user"}>
|
||||
My tasks (current user)
|
||||
${t("cal_editor_my_tasks", L)}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row toggle">
|
||||
<label for="objf">Show object filter dropdown</label>
|
||||
<label for="objf">${t("cal_editor_show_object_filter", L)}</label>
|
||||
<input
|
||||
id="objf"
|
||||
type="checkbox"
|
||||
@@ -594,10 +641,7 @@ class MaintenanceCalendarCardEditor extends LitElement {
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div class="hint">
|
||||
Pre-select one object via YAML: object_filter: "<object name>" — or a
|
||||
list of names to restrict the card to several objects.
|
||||
</div>
|
||||
<div class="hint">${t("cal_editor_object_hint", L)}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,12 @@ export function renderTriggerProgress(row: TaskRow | MaintenanceTask) {
|
||||
const range = high - below || 1;
|
||||
pct = Math.min(100, Math.max(0, ((high - val) / range) * 100));
|
||||
label = `${val.toFixed(1)} / ${below} ${unit}`;
|
||||
} else if (tc.trigger_equals != null || tc.trigger_not_equals != null) {
|
||||
// Discrete = / ≠ levels have no meaningful gradient — binary bar,
|
||||
// same treatment as compound.
|
||||
const target = tc.trigger_equals != null ? `= ${tc.trigger_equals}` : `≠ ${tc.trigger_not_equals}`;
|
||||
label = `${val.toFixed(1)} (${target}${unit ? ` ${unit}` : ""})`;
|
||||
pct = row.trigger_active ? 100 : 0;
|
||||
} else {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,8 @@ export function renderTriggerSection(task: MaintenanceTask, ctx: SparklineContex
|
||||
${triggerType === "threshold" ? html`
|
||||
${tc.trigger_above != null ? html`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${t("threshold_above", L)}: ${tc.trigger_above} ${unit}</span>` : nothing}
|
||||
${tc.trigger_below != null ? html`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${t("threshold_below", L)}: ${tc.trigger_below} ${unit}</span>` : nothing}
|
||||
${tc.trigger_equals != null ? html`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> = ${tc.trigger_equals} ${unit}</span>` : nothing}
|
||||
${tc.trigger_not_equals != null ? html`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ≠ ${tc.trigger_not_equals} ${unit}</span>` : nothing}
|
||||
${tc.trigger_for_minutes ? html`<span class="trigger-limit-item"><span class="dot range" aria-hidden="true"></span> ${t("for_minutes", L)}: ${tc.trigger_for_minutes}</span>` : nothing}
|
||||
` : nothing}
|
||||
${triggerType === "state_change" ? html`
|
||||
|
||||
@@ -56,6 +56,10 @@ export interface TriggerConfig {
|
||||
type?: string; // "threshold" | "counter" | "state_change" | "runtime"
|
||||
trigger_above?: number | null;
|
||||
trigger_below?: number | null;
|
||||
trigger_equals?: number | null;
|
||||
trigger_not_equals?: number | null;
|
||||
/** "any" (default) = trigger or safety interval, whichever first; "all" = both required. */
|
||||
trigger_combinator?: string;
|
||||
trigger_for_minutes?: number;
|
||||
trigger_target_value?: number;
|
||||
trigger_delta_mode?: boolean;
|
||||
|
||||
@@ -48,6 +48,8 @@ const FIELD_LABEL_KEYS: Record<string, string> = {
|
||||
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",
|
||||
};
|
||||
|
||||
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Poznámky (volitelné)",
|
||||
"cost_optional": "Náklady (volitelné)",
|
||||
"duration_minutes": "Doba trvání v minutách (volitelné)",
|
||||
"completed_at_optional": "Dokončeno dne (volitelné, prázdné = nyní)",
|
||||
"completed_at_future_error": "Datum dokončení nesmí být v budoucnosti.",
|
||||
"days": "dní",
|
||||
"day": "den",
|
||||
"today": "Dnes",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Použít stav entity (bez atributu)",
|
||||
"trigger_above": "Spustit nad",
|
||||
"trigger_below": "Spustit pod",
|
||||
"trigger_equals": "Spustit při rovnosti (=)",
|
||||
"trigger_not_equals": "Spustit při odlišnosti od (≠)",
|
||||
"for_at_least_minutes": "Po dobu alespoň (minut)",
|
||||
"safety_interval_days": "Bezpečnostní interval (dny, volitelný)",
|
||||
"safety_interval": "Bezpečnostní interval (volitelný)",
|
||||
"trigger_combinator": "Kombinovat spouštěč a interval",
|
||||
"trigger_combinator_any": "Spouštěč nebo interval (co dřív)",
|
||||
"trigger_combinator_all": "Spouštěč a interval (obojí vyžadováno)",
|
||||
"delta_mode": "Režim delta",
|
||||
"from_state_optional": "Ze stavu (volitelné)",
|
||||
"to_state_optional": "Do stavu (volitelné)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Začínáme — tyto tipy zmizí, jak vaše nastavení poroste",
|
||||
"gs_setups_chip": "Navrhovaná nastavení: nalezeno {n} zařízení s předpřipravenými spouštěči",
|
||||
"gs_adopt_chip": "{n} problémových senzorů se může stát údržbovými úkoly",
|
||||
"gs_fleet_chip": "Jedno kliknutí nastaví flotilu baterií"
|
||||
"gs_fleet_chip": "Jedno kliknutí nastaví flotilu baterií",
|
||||
"cal_editor_window": "Výchozí okno",
|
||||
"cal_editor_window_week": "Týden (7 dní)",
|
||||
"cal_editor_window_fortnight": "Dva týdny (14 dní)",
|
||||
"cal_editor_window_month": "Měsíc (30 dní, výchozí)",
|
||||
"cal_editor_window_year": "Rok (365 dní, prázdné dny skryty)",
|
||||
"cal_editor_show_chips": "Zobrazit přepínače okna v kartě",
|
||||
"cal_editor_chips_hint": "Skryjte přepínače, pokud je karta ve strategickém pohledu, který už slouží jako výběr okna.",
|
||||
"cal_editor_show_user_filter": "Zobrazit filtr uživatele",
|
||||
"cal_editor_default_user": "Výchozí filtr uživatele",
|
||||
"cal_editor_my_tasks": "Moje úkoly (aktuální uživatel)",
|
||||
"cal_editor_show_object_filter": "Zobrazit filtr objektu",
|
||||
"cal_editor_object_hint": "Předvyberte objekt přes YAML: object_filter: \"<název>\" — nebo seznam názvů pro omezení karty na více objektů."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Noter (valgfrit)",
|
||||
"cost_optional": "Omkostning (valgfrit)",
|
||||
"duration_minutes": "Varighed i minutter (valgfrit)",
|
||||
"completed_at_optional": "Udført den (valgfrit, tomt = nu)",
|
||||
"completed_at_future_error": "Udførelsesdatoen må ikke ligge i fremtiden.",
|
||||
"days": "dage",
|
||||
"day": "dag",
|
||||
"today": "I dag",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Brug enhedstilstand (ingen attribut)",
|
||||
"trigger_above": "Udløs over",
|
||||
"trigger_below": "Udløs under",
|
||||
"trigger_equals": "Udløs ved lig med (=)",
|
||||
"trigger_not_equals": "Udløs ved forskellig fra (≠)",
|
||||
"for_at_least_minutes": "I mindst (minutter)",
|
||||
"safety_interval_days": "Sikkerhedsinterval (dage, valgfrit)",
|
||||
"safety_interval": "Sikkerhedsinterval (valgfrit)",
|
||||
"trigger_combinator": "Kombinér trigger og interval",
|
||||
"trigger_combinator_any": "Trigger eller interval (først opfyldt)",
|
||||
"trigger_combinator_all": "Trigger og interval (begge kræves)",
|
||||
"delta_mode": "Delta-tilstand",
|
||||
"from_state_optional": "Fra tilstand (valgfrit)",
|
||||
"to_state_optional": "Til tilstand (valgfrit)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Kom godt i gang — disse tips forsvinder, efterhånden som opsætningen vokser",
|
||||
"gs_setups_chip": "Foreslåede opsætninger fandt {n} enheder med forudindstillede udløsere",
|
||||
"gs_adopt_chip": "{n} problemsensorer kan blive vedligeholdelsesopgaver",
|
||||
"gs_fleet_chip": "Ét klik opsætter batteriflåden"
|
||||
"gs_fleet_chip": "Ét klik opsætter batteriflåden",
|
||||
"cal_editor_window": "Standardvindue",
|
||||
"cal_editor_window_week": "Uge (7 dage)",
|
||||
"cal_editor_window_fortnight": "To uger (14 dage)",
|
||||
"cal_editor_window_month": "Måned (30 dage, standard)",
|
||||
"cal_editor_window_year": "År (365 dage, tomme dage skjult)",
|
||||
"cal_editor_show_chips": "Vis vinduechips i kortet",
|
||||
"cal_editor_chips_hint": "Skjul chips, når kortet er indlejret i en strategivisning, der allerede fungerer som vinduesvælger.",
|
||||
"cal_editor_show_user_filter": "Vis brugerfilter",
|
||||
"cal_editor_default_user": "Standard brugerfilter",
|
||||
"cal_editor_my_tasks": "Mine opgaver (aktuel bruger)",
|
||||
"cal_editor_show_object_filter": "Vis objektfilter",
|
||||
"cal_editor_object_hint": "Forvælg et objekt via YAML: object_filter: \"<navn>\" — eller en liste af navne for at begrænse kortet til flere objekter."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Notizen (optional)",
|
||||
"cost_optional": "Kosten (optional)",
|
||||
"duration_minutes": "Dauer in Minuten (optional)",
|
||||
"completed_at_optional": "Erledigt am (optional, leer = jetzt)",
|
||||
"completed_at_future_error": "Das Erledigungsdatum darf nicht in der Zukunft liegen.",
|
||||
"days": "Tage",
|
||||
"day": "Tag",
|
||||
"today": "Heute",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Entitäts-Zustand verwenden (kein Attribut)",
|
||||
"trigger_above": "Auslösen wenn über",
|
||||
"trigger_below": "Auslösen wenn unter",
|
||||
"trigger_equals": "Auslösen bei genau (=)",
|
||||
"trigger_not_equals": "Auslösen bei abweichend von (≠)",
|
||||
"for_at_least_minutes": "Für mindestens (Minuten)",
|
||||
"safety_interval_days": "Sicherheitsintervall (Tage, optional)",
|
||||
"safety_interval": "Sicherheitsintervall (optional)",
|
||||
"trigger_combinator": "Trigger und Intervall kombinieren",
|
||||
"trigger_combinator_any": "Trigger oder Intervall (zuerst erfüllt)",
|
||||
"trigger_combinator_all": "Trigger und Intervall (beides erforderlich)",
|
||||
"delta_mode": "Delta-Modus",
|
||||
"from_state_optional": "Von Zustand (optional)",
|
||||
"to_state_optional": "Zu Zustand (optional)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Erste Schritte — diese Hinweise verschwinden, wenn dein Setup wächst",
|
||||
"gs_setups_chip": "Vorgeschlagene Setups: {n} Geräte mit vorverdrahteten Auslösern gefunden",
|
||||
"gs_adopt_chip": "{n} Problem-Sensoren können zu Wartungsaufgaben werden",
|
||||
"gs_fleet_chip": "Ein Klick richtet die Batterieflotte ein"
|
||||
"gs_fleet_chip": "Ein Klick richtet die Batterieflotte ein",
|
||||
"cal_editor_window": "Standard-Zeitfenster",
|
||||
"cal_editor_window_week": "Woche (7 Tage)",
|
||||
"cal_editor_window_fortnight": "Zwei Wochen (14 Tage)",
|
||||
"cal_editor_window_month": "Monat (30 Tage, Standard)",
|
||||
"cal_editor_window_year": "Jahr (365 Tage, leere Tage ausgeblendet)",
|
||||
"cal_editor_show_chips": "Zeitfenster-Chips in der Karte anzeigen",
|
||||
"cal_editor_chips_hint": "Chips ausblenden, wenn die Karte in einer Strategie-Ansicht steckt, die bereits als Zeitfenster-Auswahl dient.",
|
||||
"cal_editor_show_user_filter": "Benutzerfilter-Dropdown anzeigen",
|
||||
"cal_editor_default_user": "Standard-Benutzerfilter",
|
||||
"cal_editor_my_tasks": "Meine Aufgaben (aktueller Benutzer)",
|
||||
"cal_editor_show_object_filter": "Objektfilter-Dropdown anzeigen",
|
||||
"cal_editor_object_hint": "Ein Objekt per YAML vorauswählen: object_filter: \"<Objektname>\" — oder eine Namensliste, um die Karte auf mehrere Objekte zu beschränken."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Notes (optional)",
|
||||
"cost_optional": "Cost (optional)",
|
||||
"duration_minutes": "Duration in minutes (optional)",
|
||||
"completed_at_optional": "Completed at (optional, empty = now)",
|
||||
"completed_at_future_error": "The completion date cannot be in the future.",
|
||||
"days": "days",
|
||||
"day": "day",
|
||||
"today": "Today",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Use entity state (no attribute)",
|
||||
"trigger_above": "Trigger above",
|
||||
"trigger_below": "Trigger below",
|
||||
"trigger_equals": "Trigger when equal to (=)",
|
||||
"trigger_not_equals": "Trigger when different from (≠)",
|
||||
"for_at_least_minutes": "For at least (minutes)",
|
||||
"safety_interval_days": "Safety interval (days, optional)",
|
||||
"safety_interval": "Safety interval (optional)",
|
||||
"trigger_combinator": "Combine trigger and interval",
|
||||
"trigger_combinator_any": "Trigger or interval (whichever first)",
|
||||
"trigger_combinator_all": "Trigger and interval (both required)",
|
||||
"delta_mode": "Delta mode",
|
||||
"from_state_optional": "From state (optional)",
|
||||
"to_state_optional": "To state (optional)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Getting started — these hints retire as your setup grows",
|
||||
"gs_setups_chip": "Suggested setups found {n} devices with pre-wired triggers",
|
||||
"gs_adopt_chip": "{n} problem sensors can become maintenance tasks",
|
||||
"gs_fleet_chip": "One click sets up the battery fleet"
|
||||
"gs_fleet_chip": "One click sets up the battery fleet",
|
||||
"cal_editor_window": "Default window",
|
||||
"cal_editor_window_week": "Week (7 days)",
|
||||
"cal_editor_window_fortnight": "Fortnight (14 days)",
|
||||
"cal_editor_window_month": "Month (30 days, default)",
|
||||
"cal_editor_window_year": "Year (365 days, empty days collapsed)",
|
||||
"cal_editor_show_chips": "Show window chips inside the card",
|
||||
"cal_editor_chips_hint": "Hide the chips when the card is embedded in a strategy view that already serves as the window selector.",
|
||||
"cal_editor_show_user_filter": "Show user filter dropdown",
|
||||
"cal_editor_default_user": "Default user filter",
|
||||
"cal_editor_my_tasks": "My tasks (current user)",
|
||||
"cal_editor_show_object_filter": "Show object filter dropdown",
|
||||
"cal_editor_object_hint": "Pre-select one object via YAML: object_filter: \"<object name>\" — or a list of names to restrict the card to several objects."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Notas (opcional)",
|
||||
"cost_optional": "Coste (opcional)",
|
||||
"duration_minutes": "Duración en minutos (opcional)",
|
||||
"completed_at_optional": "Completado el (opcional, vacío = ahora)",
|
||||
"completed_at_future_error": "La fecha de finalización no puede estar en el futuro.",
|
||||
"days": "días",
|
||||
"day": "día",
|
||||
"today": "Hoy",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Usar estado de la entidad (sin atributo)",
|
||||
"trigger_above": "Activar por encima de",
|
||||
"trigger_below": "Activar por debajo de",
|
||||
"trigger_equals": "Activar cuando sea igual a (=)",
|
||||
"trigger_not_equals": "Activar cuando sea distinto de (≠)",
|
||||
"for_at_least_minutes": "Durante al menos (minutos)",
|
||||
"safety_interval_days": "Intervalo de seguridad (días, opcional)",
|
||||
"safety_interval": "Intervalo de seguridad (opcional)",
|
||||
"trigger_combinator": "Combinar disparador e intervalo",
|
||||
"trigger_combinator_any": "Disparador o intervalo (el primero)",
|
||||
"trigger_combinator_all": "Disparador e intervalo (ambos requeridos)",
|
||||
"delta_mode": "Modo delta",
|
||||
"from_state_optional": "Desde estado (opcional)",
|
||||
"to_state_optional": "Hasta estado (opcional)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Primeros pasos: estas sugerencias desaparecen a medida que crece tu configuración",
|
||||
"gs_setups_chip": "Configuraciones sugeridas: {n} dispositivos con disparadores preconfigurados",
|
||||
"gs_adopt_chip": "{n} sensores de problemas pueden convertirse en tareas de mantenimiento",
|
||||
"gs_fleet_chip": "Un clic configura la flota de baterías"
|
||||
"gs_fleet_chip": "Un clic configura la flota de baterías",
|
||||
"cal_editor_window": "Ventana predeterminada",
|
||||
"cal_editor_window_week": "Semana (7 días)",
|
||||
"cal_editor_window_fortnight": "Quincena (14 días)",
|
||||
"cal_editor_window_month": "Mes (30 días, predeterminado)",
|
||||
"cal_editor_window_year": "Año (365 días, días vacíos ocultos)",
|
||||
"cal_editor_show_chips": "Mostrar chips de ventana en la tarjeta",
|
||||
"cal_editor_chips_hint": "Oculta los chips cuando la tarjeta está en una vista de estrategia que ya sirve como selector de ventana.",
|
||||
"cal_editor_show_user_filter": "Mostrar filtro de usuario",
|
||||
"cal_editor_default_user": "Filtro de usuario predeterminado",
|
||||
"cal_editor_my_tasks": "Mis tareas (usuario actual)",
|
||||
"cal_editor_show_object_filter": "Mostrar filtro de objeto",
|
||||
"cal_editor_object_hint": "Preselecciona un objeto por YAML: object_filter: \"<nombre>\" — o una lista de nombres para limitar la tarjeta a varios objetos."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Muistiinpanot (valinnainen)",
|
||||
"cost_optional": "Kustannus (valinnainen)",
|
||||
"duration_minutes": "Kesto minuutteina (valinnainen)",
|
||||
"completed_at_optional": "Suoritettu (valinnainen, tyhjä = nyt)",
|
||||
"completed_at_future_error": "Suorituspäivä ei voi olla tulevaisuudessa.",
|
||||
"days": "päivää",
|
||||
"day": "päivä",
|
||||
"today": "Tänään",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Käytä entiteetin tilaa (ei attribuuttia)",
|
||||
"trigger_above": "Laukaise yli",
|
||||
"trigger_below": "Laukaise alle",
|
||||
"trigger_equals": "Laukaise kun yhtä suuri kuin (=)",
|
||||
"trigger_not_equals": "Laukaise kun eri kuin (≠)",
|
||||
"for_at_least_minutes": "Vähintään (minuuttia)",
|
||||
"safety_interval_days": "Turvaväli (päivää, valinnainen)",
|
||||
"safety_interval": "Turvaväli (valinnainen)",
|
||||
"trigger_combinator": "Yhdistä laukaisin ja väli",
|
||||
"trigger_combinator_any": "Laukaisin tai väli (ensin täyttyvä)",
|
||||
"trigger_combinator_all": "Laukaisin ja väli (molemmat vaaditaan)",
|
||||
"delta_mode": "Delta-tila",
|
||||
"from_state_optional": "Lähtötilasta (valinnainen)",
|
||||
"to_state_optional": "Kohdetilaan (valinnainen)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Aloitus — nämä vihjeet poistuvat asennuksen kasvaessa",
|
||||
"gs_setups_chip": "Ehdotetut asetukset löysivät {n} laitetta valmiilla laukaisimilla",
|
||||
"gs_adopt_chip": "{n} ongelma-anturia voi muuttua huoltotehtäviksi",
|
||||
"gs_fleet_chip": "Yksi napsautus määrittää akkukannan"
|
||||
"gs_fleet_chip": "Yksi napsautus määrittää akkukannan",
|
||||
"cal_editor_window": "Oletusikkuna",
|
||||
"cal_editor_window_week": "Viikko (7 päivää)",
|
||||
"cal_editor_window_fortnight": "Kaksi viikkoa (14 päivää)",
|
||||
"cal_editor_window_month": "Kuukausi (30 päivää, oletus)",
|
||||
"cal_editor_window_year": "Vuosi (365 päivää, tyhjät päivät piilotettu)",
|
||||
"cal_editor_show_chips": "Näytä ikkunavalinnat kortissa",
|
||||
"cal_editor_chips_hint": "Piilota valinnat, kun kortti on strategianäkymässä, joka jo toimii ikkunan valitsimena.",
|
||||
"cal_editor_show_user_filter": "Näytä käyttäjäsuodatin",
|
||||
"cal_editor_default_user": "Oletuskäyttäjäsuodatin",
|
||||
"cal_editor_my_tasks": "Omat tehtävät (nykyinen käyttäjä)",
|
||||
"cal_editor_show_object_filter": "Näytä kohdesuodatin",
|
||||
"cal_editor_object_hint": "Esivalitse kohde YAML:lla: object_filter: \"<nimi>\" — tai nimilista rajataksesi kortin useisiin kohteisiin."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Notes (optionnel)",
|
||||
"cost_optional": "Coût (optionnel)",
|
||||
"duration_minutes": "Durée en minutes (optionnel)",
|
||||
"completed_at_optional": "Effectué le (optionnel, vide = maintenant)",
|
||||
"completed_at_future_error": "La date d'achèvement ne peut pas être dans le futur.",
|
||||
"days": "jours",
|
||||
"day": "jour",
|
||||
"today": "Aujourd'hui",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Utiliser l'état de l'entité (pas d'attribut)",
|
||||
"trigger_above": "Déclencher au-dessus de",
|
||||
"trigger_below": "Déclencher en dessous de",
|
||||
"trigger_equals": "Déclencher si égal à (=)",
|
||||
"trigger_not_equals": "Déclencher si différent de (≠)",
|
||||
"for_at_least_minutes": "Pendant au moins (minutes)",
|
||||
"safety_interval_days": "Intervalle de sécurité (jours, optionnel)",
|
||||
"safety_interval": "Intervalle de sécurité (optionnel)",
|
||||
"trigger_combinator": "Combiner déclencheur et intervalle",
|
||||
"trigger_combinator_any": "Déclencheur ou intervalle (premier atteint)",
|
||||
"trigger_combinator_all": "Déclencheur et intervalle (les deux requis)",
|
||||
"delta_mode": "Mode delta",
|
||||
"from_state_optional": "État source (optionnel)",
|
||||
"to_state_optional": "État cible (optionnel)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Premiers pas — ces conseils disparaissent à mesure que votre configuration grandit",
|
||||
"gs_setups_chip": "Configurations suggérées : {n} appareils avec déclencheurs pré-câblés trouvés",
|
||||
"gs_adopt_chip": "{n} capteurs de problème peuvent devenir des tâches de maintenance",
|
||||
"gs_fleet_chip": "Un clic configure le parc de piles"
|
||||
"gs_fleet_chip": "Un clic configure le parc de piles",
|
||||
"cal_editor_window": "Fenêtre par défaut",
|
||||
"cal_editor_window_week": "Semaine (7 jours)",
|
||||
"cal_editor_window_fortnight": "Quinzaine (14 jours)",
|
||||
"cal_editor_window_month": "Mois (30 jours, défaut)",
|
||||
"cal_editor_window_year": "Année (365 jours, jours vides masqués)",
|
||||
"cal_editor_show_chips": "Afficher les puces de fenêtre dans la carte",
|
||||
"cal_editor_chips_hint": "Masquez les puces lorsque la carte est intégrée dans une vue stratégie qui sert déjà de sélecteur de fenêtre.",
|
||||
"cal_editor_show_user_filter": "Afficher le filtre utilisateur",
|
||||
"cal_editor_default_user": "Filtre utilisateur par défaut",
|
||||
"cal_editor_my_tasks": "Mes tâches (utilisateur actuel)",
|
||||
"cal_editor_show_object_filter": "Afficher le filtre d'objet",
|
||||
"cal_editor_object_hint": "Présélectionnez un objet via YAML : object_filter : \"<nom>\" — ou une liste de noms pour limiter la carte à plusieurs objets."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "टिप्पणियाँ (वैकल्पिक)",
|
||||
"cost_optional": "लागत (वैकल्पिक)",
|
||||
"duration_minutes": "मिनटों में अवधि (वैकल्पिक)",
|
||||
"completed_at_optional": "पूर्ण होने का समय (वैकल्पिक, खाली = अभी)",
|
||||
"completed_at_future_error": "पूर्णता की तारीख भविष्य में नहीं हो सकती।",
|
||||
"days": "दिन",
|
||||
"day": "दिन",
|
||||
"today": "आज",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "एंटिटी स्थिति का उपयोग करें (कोई विशेषता नहीं)",
|
||||
"trigger_above": "इससे ऊपर ट्रिगर करें",
|
||||
"trigger_below": "इससे नीचे ट्रिगर करें",
|
||||
"trigger_equals": "बराबर होने पर ट्रिगर करें (=)",
|
||||
"trigger_not_equals": "भिन्न होने पर ट्रिगर करें (≠)",
|
||||
"for_at_least_minutes": "कम से कम (मिनट)",
|
||||
"safety_interval_days": "सुरक्षा अंतराल (दिन, वैकल्पिक)",
|
||||
"safety_interval": "सुरक्षा अंतराल (वैकल्पिक)",
|
||||
"trigger_combinator": "ट्रिगर और अंतराल संयोजित करें",
|
||||
"trigger_combinator_any": "ट्रिगर या अंतराल (जो पहले हो)",
|
||||
"trigger_combinator_all": "ट्रिगर और अंतराल (दोनों आवश्यक)",
|
||||
"delta_mode": "डेल्टा मोड",
|
||||
"from_state_optional": "किस स्थिति से (वैकल्पिक)",
|
||||
"to_state_optional": "किस स्थिति तक (वैकल्पिक)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "शुरुआत — सेटअप बढ़ने पर ये संकेत हट जाते हैं",
|
||||
"gs_setups_chip": "सुझाए गए सेटअप: पूर्व-निर्धारित ट्रिगर वाले {n} उपकरण मिले",
|
||||
"gs_adopt_chip": "{n} समस्या सेंसर रखरखाव कार्य बन सकते हैं",
|
||||
"gs_fleet_chip": "एक क्लिक में बैटरी बेड़ा सेट करें"
|
||||
"gs_fleet_chip": "एक क्लिक में बैटरी बेड़ा सेट करें",
|
||||
"cal_editor_window": "डिफ़ॉल्ट विंडो",
|
||||
"cal_editor_window_week": "सप्ताह (7 दिन)",
|
||||
"cal_editor_window_fortnight": "पखवाड़ा (14 दिन)",
|
||||
"cal_editor_window_month": "महीना (30 दिन, डिफ़ॉल्ट)",
|
||||
"cal_editor_window_year": "वर्ष (365 दिन, खाली दिन छिपे)",
|
||||
"cal_editor_show_chips": "कार्ड में विंडो चिप्स दिखाएँ",
|
||||
"cal_editor_chips_hint": "जब कार्ड ऐसी स्ट्रैटेजी व्यू में हो जो पहले से विंडो चयनक है, तो चिप्स छिपाएँ।",
|
||||
"cal_editor_show_user_filter": "उपयोगकर्ता फ़िल्टर दिखाएँ",
|
||||
"cal_editor_default_user": "डिफ़ॉल्ट उपयोगकर्ता फ़िल्टर",
|
||||
"cal_editor_my_tasks": "मेरे कार्य (वर्तमान उपयोगकर्ता)",
|
||||
"cal_editor_show_object_filter": "ऑब्जेक्ट फ़िल्टर दिखाएँ",
|
||||
"cal_editor_object_hint": "YAML से एक ऑब्जेक्ट पहले से चुनें: object_filter: \"<नाम>\" — या कार्ड को कई ऑब्जेक्ट तक सीमित करने हेतु नामों की सूची।"
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Megjegyzések (opcionális)",
|
||||
"cost_optional": "Költség (opcionális)",
|
||||
"duration_minutes": "Időtartam percben (opcionális)",
|
||||
"completed_at_optional": "Elvégezve ekkor (opcionális, üres = most)",
|
||||
"completed_at_future_error": "Az elvégzés dátuma nem lehet a jövőben.",
|
||||
"days": "nap",
|
||||
"day": "nap",
|
||||
"today": "Ma",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Entitás állapotának használata (attribútum nélkül)",
|
||||
"trigger_above": "Kiváltás e fölött",
|
||||
"trigger_below": "Kiváltás ez alatt",
|
||||
"trigger_equals": "Aktiválás ha egyenlő (=)",
|
||||
"trigger_not_equals": "Aktiválás ha eltér ettől (≠)",
|
||||
"for_at_least_minutes": "Legalább ennyi ideig (perc)",
|
||||
"safety_interval_days": "Biztonsági intervallum (nap, opcionális)",
|
||||
"safety_interval": "Biztonsági intervallum (opcionális)",
|
||||
"trigger_combinator": "Trigger és időköz kombinálása",
|
||||
"trigger_combinator_any": "Trigger vagy időköz (amelyik előbb)",
|
||||
"trigger_combinator_all": "Trigger és időköz (mindkettő szükséges)",
|
||||
"delta_mode": "Delta mód",
|
||||
"from_state_optional": "Kezdő állapot (opcionális)",
|
||||
"to_state_optional": "Célállapot (opcionális)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Első lépések — a tippek eltűnnek, ahogy a beállítás bővül",
|
||||
"gs_setups_chip": "Javasolt beállítások: {n} eszköz előre bekötött triggerekkel",
|
||||
"gs_adopt_chip": "{n} problémaérzékelő karbantartási feladattá válhat",
|
||||
"gs_fleet_chip": "Egy kattintás beállítja az elemflottát"
|
||||
"gs_fleet_chip": "Egy kattintás beállítja az elemflottát",
|
||||
"cal_editor_window": "Alapértelmezett időablak",
|
||||
"cal_editor_window_week": "Hét (7 nap)",
|
||||
"cal_editor_window_fortnight": "Két hét (14 nap)",
|
||||
"cal_editor_window_month": "Hónap (30 nap, alapértelmezett)",
|
||||
"cal_editor_window_year": "Év (365 nap, üres napok elrejtve)",
|
||||
"cal_editor_show_chips": "Időablak-választók megjelenítése a kártyán",
|
||||
"cal_editor_chips_hint": "Rejtsd el a választókat, ha a kártya olyan stratégianézetben van, amely már időablak-választóként szolgál.",
|
||||
"cal_editor_show_user_filter": "Felhasználószűrő megjelenítése",
|
||||
"cal_editor_default_user": "Alapértelmezett felhasználószűrő",
|
||||
"cal_editor_my_tasks": "Saját feladatok (aktuális felhasználó)",
|
||||
"cal_editor_show_object_filter": "Objektumszűrő megjelenítése",
|
||||
"cal_editor_object_hint": "Előválasztás YAML-lel: object_filter: \"<név>\" — vagy névlista, hogy a kártya több objektumra korlátozódjon."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Note (opzionale)",
|
||||
"cost_optional": "Costo (opzionale)",
|
||||
"duration_minutes": "Durata in minuti (opzionale)",
|
||||
"completed_at_optional": "Completato il (opzionale, vuoto = adesso)",
|
||||
"completed_at_future_error": "La data di completamento non può essere nel futuro.",
|
||||
"days": "giorni",
|
||||
"day": "giorno",
|
||||
"today": "Oggi",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Usa stato dell'entità (nessun attributo)",
|
||||
"trigger_above": "Attivare sopra",
|
||||
"trigger_below": "Attivare sotto",
|
||||
"trigger_equals": "Attiva quando uguale a (=)",
|
||||
"trigger_not_equals": "Attiva quando diverso da (≠)",
|
||||
"for_at_least_minutes": "Per almeno (minuti)",
|
||||
"safety_interval_days": "Intervallo di sicurezza (giorni, opzionale)",
|
||||
"safety_interval": "Intervallo di sicurezza (opzionale)",
|
||||
"trigger_combinator": "Combina trigger e intervallo",
|
||||
"trigger_combinator_any": "Trigger o intervallo (il primo)",
|
||||
"trigger_combinator_all": "Trigger e intervallo (entrambi richiesti)",
|
||||
"delta_mode": "Modalità delta",
|
||||
"from_state_optional": "Dallo stato (opzionale)",
|
||||
"to_state_optional": "Allo stato (opzionale)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Primi passi — questi suggerimenti scompaiono man mano che la configurazione cresce",
|
||||
"gs_setups_chip": "Configurazioni suggerite: trovati {n} dispositivi con trigger preconfigurati",
|
||||
"gs_adopt_chip": "{n} sensori di problemi possono diventare attività di manutenzione",
|
||||
"gs_fleet_chip": "Un clic configura la flotta di batterie"
|
||||
"gs_fleet_chip": "Un clic configura la flotta di batterie",
|
||||
"cal_editor_window": "Finestra predefinita",
|
||||
"cal_editor_window_week": "Settimana (7 giorni)",
|
||||
"cal_editor_window_fortnight": "Due settimane (14 giorni)",
|
||||
"cal_editor_window_month": "Mese (30 giorni, predefinito)",
|
||||
"cal_editor_window_year": "Anno (365 giorni, giorni vuoti nascosti)",
|
||||
"cal_editor_show_chips": "Mostra i chip della finestra nella scheda",
|
||||
"cal_editor_chips_hint": "Nascondi i chip quando la scheda è in una vista strategia che funge già da selettore di finestra.",
|
||||
"cal_editor_show_user_filter": "Mostra il filtro utente",
|
||||
"cal_editor_default_user": "Filtro utente predefinito",
|
||||
"cal_editor_my_tasks": "Le mie attività (utente attuale)",
|
||||
"cal_editor_show_object_filter": "Mostra il filtro oggetto",
|
||||
"cal_editor_object_hint": "Preseleziona un oggetto via YAML: object_filter: \"<nome>\" — o un elenco di nomi per limitare la scheda a più oggetti."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "メモ(任意)",
|
||||
"cost_optional": "費用(任意)",
|
||||
"duration_minutes": "所要時間(分、任意)",
|
||||
"completed_at_optional": "完了日時(任意・空欄 = 現在)",
|
||||
"completed_at_future_error": "完了日時に未来は指定できません。",
|
||||
"days": "日",
|
||||
"day": "日",
|
||||
"today": "今日",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "エンティティの状態を使用(属性なし)",
|
||||
"trigger_above": "この値を超えたらトリガー",
|
||||
"trigger_below": "この値を下回ったらトリガー",
|
||||
"trigger_equals": "値が一致したらトリガー(=)",
|
||||
"trigger_not_equals": "値が異なればトリガー(≠)",
|
||||
"for_at_least_minutes": "最低継続時間(分)",
|
||||
"safety_interval_days": "安全間隔(日、任意)",
|
||||
"safety_interval": "安全間隔(任意)",
|
||||
"trigger_combinator": "トリガーと間隔の組み合わせ",
|
||||
"trigger_combinator_any": "トリガーまたは間隔(先に満たした方)",
|
||||
"trigger_combinator_all": "トリガーと間隔(両方必須)",
|
||||
"delta_mode": "差分モード",
|
||||
"from_state_optional": "変化前の状態(任意)",
|
||||
"to_state_optional": "変化後の状態(任意)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "はじめに — セットアップが進むとこれらのヒントは消えます",
|
||||
"gs_setups_chip": "推奨セットアップ:トリガー設定済みのデバイスを{n}台検出",
|
||||
"gs_adopt_chip": "{n}個の問題センサーをメンテナンスタスクにできます",
|
||||
"gs_fleet_chip": "ワンクリックで電池フリートを設定"
|
||||
"gs_fleet_chip": "ワンクリックで電池フリートを設定",
|
||||
"cal_editor_window": "既定の期間",
|
||||
"cal_editor_window_week": "1週間(7日)",
|
||||
"cal_editor_window_fortnight": "2週間(14日)",
|
||||
"cal_editor_window_month": "1か月(30日・既定)",
|
||||
"cal_editor_window_year": "1年(365日・空の日は省略)",
|
||||
"cal_editor_show_chips": "カード内に期間チップを表示",
|
||||
"cal_editor_chips_hint": "ストラテジービューが期間選択を担う場合はチップを非表示にします。",
|
||||
"cal_editor_show_user_filter": "ユーザーフィルターを表示",
|
||||
"cal_editor_default_user": "既定のユーザーフィルター",
|
||||
"cal_editor_my_tasks": "自分のタスク(現在のユーザー)",
|
||||
"cal_editor_show_object_filter": "オブジェクトフィルターを表示",
|
||||
"cal_editor_object_hint": "YAML でオブジェクトを事前選択:object_filter: \"<名前>\" — 複数指定はカードを複数オブジェクトに限定します。"
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "메모 (선택)",
|
||||
"cost_optional": "비용 (선택)",
|
||||
"duration_minutes": "소요 시간(분, 선택)",
|
||||
"completed_at_optional": "완료 시각 (선택, 비우면 지금)",
|
||||
"completed_at_future_error": "완료 날짜는 미래일 수 없습니다.",
|
||||
"days": "일",
|
||||
"day": "일",
|
||||
"today": "오늘",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "엔티티 상태 사용 (속성 없음)",
|
||||
"trigger_above": "초과 시 트리거",
|
||||
"trigger_below": "미만 시 트리거",
|
||||
"trigger_equals": "값이 같으면 트리거 (=)",
|
||||
"trigger_not_equals": "값이 다르면 트리거 (≠)",
|
||||
"for_at_least_minutes": "최소 지속 시간 (분)",
|
||||
"safety_interval_days": "안전 주기 (일, 선택)",
|
||||
"safety_interval": "안전 주기 (선택)",
|
||||
"trigger_combinator": "트리거와 간격 결합",
|
||||
"trigger_combinator_any": "트리거 또는 간격 (먼저 충족)",
|
||||
"trigger_combinator_all": "트리거와 간격 (둘 다 필요)",
|
||||
"delta_mode": "델타 모드",
|
||||
"from_state_optional": "변경 전 상태 (선택)",
|
||||
"to_state_optional": "변경 후 상태 (선택)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "시작하기 — 설정이 늘어나면 이 힌트는 사라집니다",
|
||||
"gs_setups_chip": "추천 설정: 트리거가 준비된 기기 {n}대 발견",
|
||||
"gs_adopt_chip": "문제 센서 {n}개를 유지보수 작업으로 만들 수 있습니다",
|
||||
"gs_fleet_chip": "클릭 한 번으로 배터리 플릿 설정"
|
||||
"gs_fleet_chip": "클릭 한 번으로 배터리 플릿 설정",
|
||||
"cal_editor_window": "기본 기간",
|
||||
"cal_editor_window_week": "1주 (7일)",
|
||||
"cal_editor_window_fortnight": "2주 (14일)",
|
||||
"cal_editor_window_month": "1개월 (30일, 기본)",
|
||||
"cal_editor_window_year": "1년 (365일, 빈 날은 접힘)",
|
||||
"cal_editor_show_chips": "카드 안에 기간 칩 표시",
|
||||
"cal_editor_chips_hint": "전략 뷰가 이미 기간 선택기 역할을 하면 칩을 숨기세요.",
|
||||
"cal_editor_show_user_filter": "사용자 필터 표시",
|
||||
"cal_editor_default_user": "기본 사용자 필터",
|
||||
"cal_editor_my_tasks": "내 작업 (현재 사용자)",
|
||||
"cal_editor_show_object_filter": "객체 필터 표시",
|
||||
"cal_editor_object_hint": "YAML로 객체를 미리 선택: object_filter: \"<이름>\" — 이름 목록으로 카드를 여러 객체로 제한할 수 있습니다."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Notater (valgfritt)",
|
||||
"cost_optional": "Kostnad (valgfritt)",
|
||||
"duration_minutes": "Varighet i minutter (valgfritt)",
|
||||
"completed_at_optional": "Utført den (valgfritt, tomt = nå)",
|
||||
"completed_at_future_error": "Fullføringsdatoen kan ikke ligge i fremtiden.",
|
||||
"days": "dager",
|
||||
"day": "dag",
|
||||
"today": "I dag",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Bruk entitetstilstand (ingen attributt)",
|
||||
"trigger_above": "Utløs over",
|
||||
"trigger_below": "Utløs under",
|
||||
"trigger_equals": "Utløs ved lik (=)",
|
||||
"trigger_not_equals": "Utløs ved forskjellig fra (≠)",
|
||||
"for_at_least_minutes": "I minst (minutter)",
|
||||
"safety_interval_days": "Sikkerhetsintervall (dager, valgfritt)",
|
||||
"safety_interval": "Sikkerhetsintervall (valgfritt)",
|
||||
"trigger_combinator": "Kombiner utløser og intervall",
|
||||
"trigger_combinator_any": "Utløser eller intervall (først oppfylt)",
|
||||
"trigger_combinator_all": "Utløser og intervall (begge kreves)",
|
||||
"delta_mode": "Deltamodus",
|
||||
"from_state_optional": "Fra tilstand (valgfritt)",
|
||||
"to_state_optional": "Til tilstand (valgfritt)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Kom i gang — tipsene forsvinner etter hvert som oppsettet vokser",
|
||||
"gs_setups_chip": "Foreslåtte oppsett fant {n} enheter med ferdigkoblede utløsere",
|
||||
"gs_adopt_chip": "{n} problemsensorer kan bli vedlikeholdsoppgaver",
|
||||
"gs_fleet_chip": "Ett klikk setter opp batteriflåten"
|
||||
"gs_fleet_chip": "Ett klikk setter opp batteriflåten",
|
||||
"cal_editor_window": "Standardvindu",
|
||||
"cal_editor_window_week": "Uke (7 dager)",
|
||||
"cal_editor_window_fortnight": "To uker (14 dager)",
|
||||
"cal_editor_window_month": "Måned (30 dager, standard)",
|
||||
"cal_editor_window_year": "År (365 dager, tomme dager skjult)",
|
||||
"cal_editor_show_chips": "Vis vindus-chips i kortet",
|
||||
"cal_editor_chips_hint": "Skjul chipsene når kortet er innebygd i en strategivisning som allerede fungerer som vindusvelger.",
|
||||
"cal_editor_show_user_filter": "Vis brukerfilter",
|
||||
"cal_editor_default_user": "Standard brukerfilter",
|
||||
"cal_editor_my_tasks": "Mine oppgaver (gjeldende bruker)",
|
||||
"cal_editor_show_object_filter": "Vis objektfilter",
|
||||
"cal_editor_object_hint": "Forhåndsvelg et objekt via YAML: object_filter: \"<navn>\" — eller en liste med navn for å begrense kortet til flere objekter."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Notities (optioneel)",
|
||||
"cost_optional": "Kosten (optioneel)",
|
||||
"duration_minutes": "Duur in minuten (optioneel)",
|
||||
"completed_at_optional": "Voltooid op (optioneel, leeg = nu)",
|
||||
"completed_at_future_error": "De voltooiingsdatum mag niet in de toekomst liggen.",
|
||||
"days": "dagen",
|
||||
"day": "dag",
|
||||
"today": "Vandaag",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Entiteitsstatus gebruiken (geen attribuut)",
|
||||
"trigger_above": "Activeren als boven",
|
||||
"trigger_below": "Activeren als onder",
|
||||
"trigger_equals": "Activeren bij gelijk aan (=)",
|
||||
"trigger_not_equals": "Activeren bij afwijkend van (≠)",
|
||||
"for_at_least_minutes": "Voor minstens (minuten)",
|
||||
"safety_interval_days": "Veiligheidsinterval (dagen, optioneel)",
|
||||
"safety_interval": "Veiligheidsinterval (optioneel)",
|
||||
"trigger_combinator": "Trigger en interval combineren",
|
||||
"trigger_combinator_any": "Trigger of interval (eerst vervuld)",
|
||||
"trigger_combinator_all": "Trigger en interval (beide vereist)",
|
||||
"delta_mode": "Deltamodus",
|
||||
"from_state_optional": "Van status (optioneel)",
|
||||
"to_state_optional": "Naar status (optioneel)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Aan de slag — deze tips verdwijnen naarmate je installatie groeit",
|
||||
"gs_setups_chip": "Voorgestelde setups: {n} apparaten met vooraf ingestelde triggers gevonden",
|
||||
"gs_adopt_chip": "{n} probleemsensoren kunnen onderhoudstaken worden",
|
||||
"gs_fleet_chip": "Eén klik stelt het batterijpark in"
|
||||
"gs_fleet_chip": "Eén klik stelt het batterijpark in",
|
||||
"cal_editor_window": "Standaardvenster",
|
||||
"cal_editor_window_week": "Week (7 dagen)",
|
||||
"cal_editor_window_fortnight": "Twee weken (14 dagen)",
|
||||
"cal_editor_window_month": "Maand (30 dagen, standaard)",
|
||||
"cal_editor_window_year": "Jaar (365 dagen, lege dagen verborgen)",
|
||||
"cal_editor_show_chips": "Vensterchips in de kaart tonen",
|
||||
"cal_editor_chips_hint": "Verberg de chips wanneer de kaart in een strategieweergave staat die al als vensterkeuze dient.",
|
||||
"cal_editor_show_user_filter": "Gebruikersfilter tonen",
|
||||
"cal_editor_default_user": "Standaard gebruikersfilter",
|
||||
"cal_editor_my_tasks": "Mijn taken (huidige gebruiker)",
|
||||
"cal_editor_show_object_filter": "Objectfilter tonen",
|
||||
"cal_editor_object_hint": "Selecteer een object vooraf via YAML: object_filter: \"<naam>\" — of een lijst met namen om de kaart tot meerdere objecten te beperken."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Notatki (opcjonalne)",
|
||||
"cost_optional": "Koszt (opcjonalne)",
|
||||
"duration_minutes": "Czas trwania w minutach (opcjonalne)",
|
||||
"completed_at_optional": "Wykonano dnia (opcjonalne, puste = teraz)",
|
||||
"completed_at_future_error": "Data wykonania nie może być w przyszłości.",
|
||||
"days": "dni",
|
||||
"day": "dzień",
|
||||
"today": "Dzisiaj",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Użyj stanu encji (bez atrybutu)",
|
||||
"trigger_above": "Wyzwól powyżej",
|
||||
"trigger_below": "Wyzwól poniżej",
|
||||
"trigger_equals": "Wyzwól przy równym (=)",
|
||||
"trigger_not_equals": "Wyzwól przy różnym od (≠)",
|
||||
"for_at_least_minutes": "Przez co najmniej (minuty)",
|
||||
"safety_interval_days": "Interwał bezpieczeństwa (dni, opcjonalny)",
|
||||
"safety_interval": "Interwał bezpieczeństwa (opcjonalny)",
|
||||
"trigger_combinator": "Połącz wyzwalacz i interwał",
|
||||
"trigger_combinator_any": "Wyzwalacz lub interwał (co pierwsze)",
|
||||
"trigger_combinator_all": "Wyzwalacz i interwał (oba wymagane)",
|
||||
"delta_mode": "Tryb delta",
|
||||
"from_state_optional": "Ze stanu (opcjonalne)",
|
||||
"to_state_optional": "Do stanu (opcjonalne)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Pierwsze kroki — te wskazówki znikają wraz z rozwojem konfiguracji",
|
||||
"gs_setups_chip": "Sugerowane konfiguracje: znaleziono {n} urządzeń z gotowymi wyzwalaczami",
|
||||
"gs_adopt_chip": "{n} czujników problemów może stać się zadaniami konserwacji",
|
||||
"gs_fleet_chip": "Jedno kliknięcie konfiguruje flotę baterii"
|
||||
"gs_fleet_chip": "Jedno kliknięcie konfiguruje flotę baterii",
|
||||
"cal_editor_window": "Okno domyślne",
|
||||
"cal_editor_window_week": "Tydzień (7 dni)",
|
||||
"cal_editor_window_fortnight": "Dwa tygodnie (14 dni)",
|
||||
"cal_editor_window_month": "Miesiąc (30 dni, domyślnie)",
|
||||
"cal_editor_window_year": "Rok (365 dni, puste dni ukryte)",
|
||||
"cal_editor_show_chips": "Pokaż przełączniki okna na karcie",
|
||||
"cal_editor_chips_hint": "Ukryj przełączniki, gdy karta jest osadzona w widoku strategii, który już pełni rolę wyboru okna.",
|
||||
"cal_editor_show_user_filter": "Pokaż filtr użytkownika",
|
||||
"cal_editor_default_user": "Domyślny filtr użytkownika",
|
||||
"cal_editor_my_tasks": "Moje zadania (bieżący użytkownik)",
|
||||
"cal_editor_show_object_filter": "Pokaż filtr obiektu",
|
||||
"cal_editor_object_hint": "Wybierz obiekt w YAML: object_filter: \"<nazwa>\" — lub listę nazw, aby ograniczyć kartę do kilku obiektów."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Observações (opcional)",
|
||||
"cost_optional": "Custo (opcional)",
|
||||
"duration_minutes": "Duração em minutos (opcional)",
|
||||
"completed_at_optional": "Concluído em (opcional, vazio = agora)",
|
||||
"completed_at_future_error": "A data de conclusão não pode estar no futuro.",
|
||||
"days": "dias",
|
||||
"day": "dia",
|
||||
"today": "Hoje",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Usar o estado da entidade (sem atributo)",
|
||||
"trigger_above": "Acionar acima de",
|
||||
"trigger_below": "Acionar abaixo de",
|
||||
"trigger_equals": "Acionar quando igual a (=)",
|
||||
"trigger_not_equals": "Acionar quando diferente de (≠)",
|
||||
"for_at_least_minutes": "Por pelo menos (minutos)",
|
||||
"safety_interval_days": "Intervalo de segurança (dias, opcional)",
|
||||
"safety_interval": "Intervalo de segurança (opcional)",
|
||||
"trigger_combinator": "Combinar gatilho e intervalo",
|
||||
"trigger_combinator_any": "Gatilho ou intervalo (o primeiro)",
|
||||
"trigger_combinator_all": "Gatilho e intervalo (ambos exigidos)",
|
||||
"delta_mode": "Modo delta",
|
||||
"from_state_optional": "Do estado (opcional)",
|
||||
"to_state_optional": "Para o estado (opcional)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Primeiros passos — estas dicas somem conforme a configuração cresce",
|
||||
"gs_setups_chip": "Configurações sugeridas: {n} dispositivos com gatilhos pré-configurados",
|
||||
"gs_adopt_chip": "{n} sensores de problema podem virar tarefas de manutenção",
|
||||
"gs_fleet_chip": "Um clique configura a frota de pilhas"
|
||||
"gs_fleet_chip": "Um clique configura a frota de pilhas",
|
||||
"cal_editor_window": "Janela padrão",
|
||||
"cal_editor_window_week": "Semana (7 dias)",
|
||||
"cal_editor_window_fortnight": "Quinzena (14 dias)",
|
||||
"cal_editor_window_month": "Mês (30 dias, padrão)",
|
||||
"cal_editor_window_year": "Ano (365 dias, dias vazios ocultos)",
|
||||
"cal_editor_show_chips": "Mostrar chips de janela no cartão",
|
||||
"cal_editor_chips_hint": "Oculte os chips quando o cartão estiver em uma visão de estratégia que já serve como seletor de janela.",
|
||||
"cal_editor_show_user_filter": "Mostrar filtro de usuário",
|
||||
"cal_editor_default_user": "Filtro de usuário padrão",
|
||||
"cal_editor_my_tasks": "Minhas tarefas (usuário atual)",
|
||||
"cal_editor_show_object_filter": "Mostrar filtro de objeto",
|
||||
"cal_editor_object_hint": "Pré-selecione um objeto via YAML: object_filter: \"<nome>\" — ou uma lista de nomes para limitar o cartão a vários objetos."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Notas (opcional)",
|
||||
"cost_optional": "Custo (opcional)",
|
||||
"duration_minutes": "Duração em minutos (opcional)",
|
||||
"completed_at_optional": "Concluído em (opcional, vazio = agora)",
|
||||
"completed_at_future_error": "A data de conclusão não pode estar no futuro.",
|
||||
"days": "dias",
|
||||
"day": "dia",
|
||||
"today": "Hoje",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Usar estado da entidade (sem atributo)",
|
||||
"trigger_above": "Acionar acima de",
|
||||
"trigger_below": "Acionar abaixo de",
|
||||
"trigger_equals": "Acionar quando igual a (=)",
|
||||
"trigger_not_equals": "Acionar quando diferente de (≠)",
|
||||
"for_at_least_minutes": "Durante pelo menos (minutos)",
|
||||
"safety_interval_days": "Intervalo de segurança (dias, opcional)",
|
||||
"safety_interval": "Intervalo de segurança (opcional)",
|
||||
"trigger_combinator": "Combinar acionador e intervalo",
|
||||
"trigger_combinator_any": "Acionador ou intervalo (o primeiro)",
|
||||
"trigger_combinator_all": "Acionador e intervalo (ambos exigidos)",
|
||||
"delta_mode": "Modo delta",
|
||||
"from_state_optional": "Do estado (opcional)",
|
||||
"to_state_optional": "Para o estado (opcional)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Primeiros passos — estas dicas desaparecem à medida que a configuração cresce",
|
||||
"gs_setups_chip": "Configurações sugeridas: {n} dispositivos com gatilhos pré-configurados",
|
||||
"gs_adopt_chip": "{n} sensores de problema podem tornar-se tarefas de manutenção",
|
||||
"gs_fleet_chip": "Um clique configura a frota de pilhas"
|
||||
"gs_fleet_chip": "Um clique configura a frota de pilhas",
|
||||
"cal_editor_window": "Janela predefinida",
|
||||
"cal_editor_window_week": "Semana (7 dias)",
|
||||
"cal_editor_window_fortnight": "Quinzena (14 dias)",
|
||||
"cal_editor_window_month": "Mês (30 dias, predefinido)",
|
||||
"cal_editor_window_year": "Ano (365 dias, dias vazios ocultos)",
|
||||
"cal_editor_show_chips": "Mostrar chips de janela no cartão",
|
||||
"cal_editor_chips_hint": "Oculte os chips quando o cartão está numa vista de estratégia que já serve de seletor de janela.",
|
||||
"cal_editor_show_user_filter": "Mostrar filtro de utilizador",
|
||||
"cal_editor_default_user": "Filtro de utilizador predefinido",
|
||||
"cal_editor_my_tasks": "As minhas tarefas (utilizador atual)",
|
||||
"cal_editor_show_object_filter": "Mostrar filtro de objeto",
|
||||
"cal_editor_object_hint": "Pré-selecione um objeto via YAML: object_filter: \"<nome>\" — ou uma lista de nomes para limitar o cartão a vários objetos."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Примечания (опционально)",
|
||||
"cost_optional": "Стоимость (опционально)",
|
||||
"duration_minutes": "Длительность в минутах (опционально)",
|
||||
"completed_at_optional": "Выполнено (необязательно, пусто = сейчас)",
|
||||
"completed_at_future_error": "Дата выполнения не может быть в будущем.",
|
||||
"days": "дней",
|
||||
"day": "день",
|
||||
"today": "Сегодня",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Использовать состояние сущности (без атрибута)",
|
||||
"trigger_above": "Срабатывать выше",
|
||||
"trigger_below": "Срабатывать ниже",
|
||||
"trigger_equals": "Срабатывать при равенстве (=)",
|
||||
"trigger_not_equals": "Срабатывать при отличии от (≠)",
|
||||
"for_at_least_minutes": "Не менее (минут)",
|
||||
"safety_interval_days": "Интервал безопасности (дни, опционально)",
|
||||
"safety_interval": "Интервал безопасности (опционально)",
|
||||
"trigger_combinator": "Совместить триггер и интервал",
|
||||
"trigger_combinator_any": "Триггер или интервал (что раньше)",
|
||||
"trigger_combinator_all": "Триггер и интервал (оба условия)",
|
||||
"delta_mode": "Режим дельты",
|
||||
"from_state_optional": "Из состояния (опционально)",
|
||||
"to_state_optional": "В состояние (опционально)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Первые шаги — эти подсказки исчезнут по мере роста настройки",
|
||||
"gs_setups_chip": "Рекомендуемые настройки: найдено {n} устройств с готовыми триггерами",
|
||||
"gs_adopt_chip": "{n} датчиков проблем могут стать задачами обслуживания",
|
||||
"gs_fleet_chip": "Один клик настроит парк батарей"
|
||||
"gs_fleet_chip": "Один клик настроит парк батарей",
|
||||
"cal_editor_window": "Окно по умолчанию",
|
||||
"cal_editor_window_week": "Неделя (7 дней)",
|
||||
"cal_editor_window_fortnight": "Две недели (14 дней)",
|
||||
"cal_editor_window_month": "Месяц (30 дней, по умолчанию)",
|
||||
"cal_editor_window_year": "Год (365 дней, пустые дни скрыты)",
|
||||
"cal_editor_show_chips": "Показывать чипы окна в карточке",
|
||||
"cal_editor_chips_hint": "Скройте чипы, если карточка встроена в стратегию, которая уже служит выбором окна.",
|
||||
"cal_editor_show_user_filter": "Показывать фильтр пользователя",
|
||||
"cal_editor_default_user": "Фильтр пользователя по умолчанию",
|
||||
"cal_editor_my_tasks": "Мои задачи (текущий пользователь)",
|
||||
"cal_editor_show_object_filter": "Показывать фильтр объекта",
|
||||
"cal_editor_object_hint": "Предварительный выбор объекта через YAML: object_filter: \"<имя>\" — или список имён, чтобы ограничить карточку несколькими объектами."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Anteckningar (valfritt)",
|
||||
"cost_optional": "Kostnad (valfritt)",
|
||||
"duration_minutes": "Varaktighet i minuter (valfritt)",
|
||||
"completed_at_optional": "Utförd den (valfritt, tomt = nu)",
|
||||
"completed_at_future_error": "Slutförandedatumet får inte ligga i framtiden.",
|
||||
"days": "dagar",
|
||||
"day": "dag",
|
||||
"today": "Idag",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Använd entitetstillstånd (inget attribut)",
|
||||
"trigger_above": "Utlös över",
|
||||
"trigger_below": "Utlös under",
|
||||
"trigger_equals": "Utlös vid lika med (=)",
|
||||
"trigger_not_equals": "Utlös vid skilt från (≠)",
|
||||
"for_at_least_minutes": "Under minst (minuter)",
|
||||
"safety_interval_days": "Säkerhetsintervall (dagar, valfritt)",
|
||||
"safety_interval": "Säkerhetsintervall (valfritt)",
|
||||
"trigger_combinator": "Kombinera utlösare och intervall",
|
||||
"trigger_combinator_any": "Utlösare eller intervall (först uppfylld)",
|
||||
"trigger_combinator_all": "Utlösare och intervall (båda krävs)",
|
||||
"delta_mode": "Delta-läge",
|
||||
"from_state_optional": "Från tillstånd (valfritt)",
|
||||
"to_state_optional": "Till tillstånd (valfritt)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Kom igång — tipsen försvinner när din installation växer",
|
||||
"gs_setups_chip": "Föreslagna uppsättningar hittade {n} enheter med förkopplade utlösare",
|
||||
"gs_adopt_chip": "{n} problemsensorer kan bli underhållsuppgifter",
|
||||
"gs_fleet_chip": "Ett klick konfigurerar batteriflottan"
|
||||
"gs_fleet_chip": "Ett klick konfigurerar batteriflottan",
|
||||
"cal_editor_window": "Standardfönster",
|
||||
"cal_editor_window_week": "Vecka (7 dagar)",
|
||||
"cal_editor_window_fortnight": "Två veckor (14 dagar)",
|
||||
"cal_editor_window_month": "Månad (30 dagar, standard)",
|
||||
"cal_editor_window_year": "År (365 dagar, tomma dagar dolda)",
|
||||
"cal_editor_show_chips": "Visa fönsterchips i kortet",
|
||||
"cal_editor_chips_hint": "Dölj chipsen när kortet är inbäddat i en strategivy som redan fungerar som fönsterväljare.",
|
||||
"cal_editor_show_user_filter": "Visa användarfilter",
|
||||
"cal_editor_default_user": "Standardanvändarfilter",
|
||||
"cal_editor_my_tasks": "Mina uppgifter (aktuell användare)",
|
||||
"cal_editor_show_object_filter": "Visa objektfilter",
|
||||
"cal_editor_object_hint": "Förvälj ett objekt via YAML: object_filter: \"<namn>\" — eller en lista med namn för att begränsa kortet till flera objekt."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "Notlar (isteğe bağlı)",
|
||||
"cost_optional": "Maliyet (isteğe bağlı)",
|
||||
"duration_minutes": "Dakika cinsinden süre (isteğe bağlı)",
|
||||
"completed_at_optional": "Tamamlanma zamanı (isteğe bağlı, boş = şimdi)",
|
||||
"completed_at_future_error": "Tamamlanma tarihi gelecekte olamaz.",
|
||||
"days": "gün",
|
||||
"day": "gün",
|
||||
"today": "Bugün",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "Varlık durumunu kullan (öznitelik yok)",
|
||||
"trigger_above": "Üstünde tetikle",
|
||||
"trigger_below": "Altında tetikle",
|
||||
"trigger_equals": "Şuna eşitse tetikle (=)",
|
||||
"trigger_not_equals": "Şundan farklıysa tetikle (≠)",
|
||||
"for_at_least_minutes": "En az (dakika)",
|
||||
"safety_interval_days": "Güvenlik aralığı (gün, isteğe bağlı)",
|
||||
"safety_interval": "Güvenlik aralığı (isteğe bağlı)",
|
||||
"trigger_combinator": "Tetikleyici ve aralığı birleştir",
|
||||
"trigger_combinator_any": "Tetikleyici veya aralık (ilk gerçekleşen)",
|
||||
"trigger_combinator_all": "Tetikleyici ve aralık (her ikisi gerekli)",
|
||||
"delta_mode": "Fark modu",
|
||||
"from_state_optional": "Başlangıç durumu (isteğe bağlı)",
|
||||
"to_state_optional": "Hedef durum (isteğe bağlı)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Başlarken — kurulumunuz büyüdükçe bu ipuçları kaybolur",
|
||||
"gs_setups_chip": "Önerilen kurulumlar {n} cihaz buldu (hazır tetikleyicilerle)",
|
||||
"gs_adopt_chip": "{n} sorun sensörü bakım görevine dönüşebilir",
|
||||
"gs_fleet_chip": "Tek tıkla pil filosunu kurun"
|
||||
"gs_fleet_chip": "Tek tıkla pil filosunu kurun",
|
||||
"cal_editor_window": "Varsayılan pencere",
|
||||
"cal_editor_window_week": "Hafta (7 gün)",
|
||||
"cal_editor_window_fortnight": "İki hafta (14 gün)",
|
||||
"cal_editor_window_month": "Ay (30 gün, varsayılan)",
|
||||
"cal_editor_window_year": "Yıl (365 gün, boş günler gizli)",
|
||||
"cal_editor_show_chips": "Pencere seçeneklerini kartta göster",
|
||||
"cal_editor_chips_hint": "Kart, zaten pencere seçici görevi gören bir strateji görünümüne gömülüyse seçenekleri gizleyin.",
|
||||
"cal_editor_show_user_filter": "Kullanıcı filtresini göster",
|
||||
"cal_editor_default_user": "Varsayılan kullanıcı filtresi",
|
||||
"cal_editor_my_tasks": "Görevlerim (geçerli kullanıcı)",
|
||||
"cal_editor_show_object_filter": "Nesne filtresini göster",
|
||||
"cal_editor_object_hint": "YAML ile bir nesne önceden seçin: object_filter: \"<ad>\" — veya kartı birden çok nesneyle sınırlamak için ad listesi."
|
||||
}
|
||||
@@ -128,6 +128,8 @@
|
||||
"notes_optional": "Примітки (необов'язково)",
|
||||
"cost_optional": "Вартість (необов'язково)",
|
||||
"duration_minutes": "Тривалість у хвилинах (необов'язково)",
|
||||
"completed_at_optional": "Виконано (необов'язково, порожньо = зараз)",
|
||||
"completed_at_future_error": "Дата виконання не може бути в майбутньому.",
|
||||
"days": "днів",
|
||||
"day": "день",
|
||||
"today": "Сьогодні",
|
||||
@@ -192,9 +194,14 @@
|
||||
"use_entity_state": "Використовувати стан об'єкта (без атрибута)",
|
||||
"trigger_above": "Спрацювати, коли вище",
|
||||
"trigger_below": "Спрацювати, коли нижче",
|
||||
"trigger_equals": "Спрацьовувати при рівності (=)",
|
||||
"trigger_not_equals": "Спрацьовувати при відмінності від (≠)",
|
||||
"for_at_least_minutes": "Протягом не менше (хвилин)",
|
||||
"safety_interval_days": "Страховий інтервал (дні, необов'язково)",
|
||||
"safety_interval": "Страховий інтервал (необов'язково)",
|
||||
"trigger_combinator": "Поєднати тригер та інтервал",
|
||||
"trigger_combinator_any": "Тригер або інтервал (що раніше)",
|
||||
"trigger_combinator_all": "Тригер та інтервал (обидва потрібні)",
|
||||
"delta_mode": "Режим дельти",
|
||||
"from_state_optional": "З стану (необов'язково)",
|
||||
"to_state_optional": "До стану (необов'язково)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "Перші кроки — ці підказки зникнуть у міру зростання налаштування",
|
||||
"gs_setups_chip": "Рекомендовані налаштування: знайдено {n} пристроїв із готовими тригерами",
|
||||
"gs_adopt_chip": "{n} датчиків проблем можуть стати завданнями обслуговування",
|
||||
"gs_fleet_chip": "Один клік налаштує парк батарей"
|
||||
"gs_fleet_chip": "Один клік налаштує парк батарей",
|
||||
"cal_editor_window": "Вікно за замовчуванням",
|
||||
"cal_editor_window_week": "Тиждень (7 днів)",
|
||||
"cal_editor_window_fortnight": "Два тижні (14 днів)",
|
||||
"cal_editor_window_month": "Місяць (30 днів, типово)",
|
||||
"cal_editor_window_year": "Рік (365 днів, порожні дні приховано)",
|
||||
"cal_editor_show_chips": "Показувати чипи вікна в картці",
|
||||
"cal_editor_chips_hint": "Приховайте чипи, якщо картка вбудована в стратегію, що вже слугує вибором вікна.",
|
||||
"cal_editor_show_user_filter": "Показувати фільтр користувача",
|
||||
"cal_editor_default_user": "Типовий фільтр користувача",
|
||||
"cal_editor_my_tasks": "Мої завдання (поточний користувач)",
|
||||
"cal_editor_show_object_filter": "Показувати фільтр об'єкта",
|
||||
"cal_editor_object_hint": "Попередній вибір об'єкта через YAML: object_filter: \"<назва>\" — або список назв, щоб обмежити картку кількома об'єктами."
|
||||
}
|
||||
@@ -129,6 +129,8 @@
|
||||
"notes_optional": "备注 (可选)",
|
||||
"cost_optional": "成本 (可选)",
|
||||
"duration_minutes": "耗时 (分钟, 可选)",
|
||||
"completed_at_optional": "完成时间(可选,留空 = 现在)",
|
||||
"completed_at_future_error": "完成日期不能是未来时间。",
|
||||
"days": "天",
|
||||
"day": "天",
|
||||
"today": "今天",
|
||||
@@ -193,9 +195,14 @@
|
||||
"use_entity_state": "使用实体状态 (不使用属性)",
|
||||
"trigger_above": "高于此值触发",
|
||||
"trigger_below": "低于此值触发",
|
||||
"trigger_equals": "等于时触发(=)",
|
||||
"trigger_not_equals": "不等于时触发(≠)",
|
||||
"for_at_least_minutes": "持续至少 (分钟)",
|
||||
"safety_interval_days": "安全间隔 (天, 可选)",
|
||||
"safety_interval": "安全间隔 (可选)",
|
||||
"trigger_combinator": "组合触发器与间隔",
|
||||
"trigger_combinator_any": "触发器或间隔(先到者)",
|
||||
"trigger_combinator_all": "触发器与间隔(两者皆需)",
|
||||
"delta_mode": "增量模式",
|
||||
"from_state_optional": "起始状态 (可选)",
|
||||
"to_state_optional": "目标状态 (可选)",
|
||||
@@ -850,5 +857,17 @@
|
||||
"gs_label": "入门提示——随着配置的完善,这些提示会自动消失",
|
||||
"gs_setups_chip": "推荐配置发现 {n} 台设备(含预设触发器)",
|
||||
"gs_adopt_chip": "{n} 个问题传感器可转换为维护任务",
|
||||
"gs_fleet_chip": "一键设置电池车队"
|
||||
"gs_fleet_chip": "一键设置电池车队",
|
||||
"cal_editor_window": "默认时间窗",
|
||||
"cal_editor_window_week": "一周(7天)",
|
||||
"cal_editor_window_fortnight": "两周(14天)",
|
||||
"cal_editor_window_month": "一个月(30天,默认)",
|
||||
"cal_editor_window_year": "一年(365天,空白日折叠)",
|
||||
"cal_editor_show_chips": "在卡片内显示时间窗标签",
|
||||
"cal_editor_chips_hint": "当卡片嵌入已充当时间窗选择器的策略视图时,请隐藏标签。",
|
||||
"cal_editor_show_user_filter": "显示用户筛选",
|
||||
"cal_editor_default_user": "默认用户筛选",
|
||||
"cal_editor_my_tasks": "我的任务(当前用户)",
|
||||
"cal_editor_show_object_filter": "显示对象筛选",
|
||||
"cal_editor_object_hint": "通过 YAML 预选对象:object_filter: \"<对象名>\" — 或名称列表,将卡片限定为多个对象。"
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,9 +1,9 @@
|
||||
/*! maintenance_supporter frontend 2.58.0 */
|
||||
var bt=Object.defineProperty;var zi=Object.getOwnPropertyDescriptor;var $=(a,s,e)=>()=>{if(e)throw e[0];try{return a&&(s=a(a=0)),s}catch(t){throw e=[t],t}};var Fi=(a,s)=>{for(var e in s)bt(a,e,{get:s[e],enumerable:!0})};var d=(a,s,e,t)=>{for(var i=t>1?void 0:t?zi(s,e):s,n=a.length-1,l;n>=0;n--)(l=a[n])&&(i=(t?l(s,e,i):l(i))||i);return t&&i&&bt(s,e,i),i};var Te,Ce,Be,yt,_e,xt,E,$t,We,Ke=$(()=>{Te=globalThis,Ce=Te.ShadowRoot&&(Te.ShadyCSS===void 0||Te.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Be=Symbol(),yt=new WeakMap,_e=class{constructor(s,e,t){if(this._$cssResult$=!0,t!==Be)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(Ce&&s===void 0){let t=e!==void 0&&e.length===1;t&&(s=yt.get(e)),s===void 0&&((this.o=s=new CSSStyleSheet).replaceSync(this.cssText),t&&yt.set(e,s))}return s}toString(){return this.cssText}},xt=a=>new _e(typeof a=="string"?a:a+"",void 0,Be),E=(a,...s)=>{let e=a.length===1?a[0]:s.reduce((t,i,n)=>t+(l=>{if(l._$cssResult$===!0)return l.cssText;if(typeof l=="number")return l;throw Error("Value passed to 'css' function must be a 'css' function result: "+l+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+a[n+1],a[0]);return new _e(e,a,Be)},$t=(a,s)=>{if(Ce)a.adoptedStyleSheets=s.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of s){let t=document.createElement("style"),i=Te.litNonce;i!==void 0&&t.setAttribute("nonce",i),t.textContent=e.cssText,a.appendChild(t)}},We=Ce?a=>a:a=>a instanceof CSSStyleSheet?(s=>{let e="";for(let t of s.cssRules)e+=t.cssText;return xt(e)})(a):a});var Di,Ui,Vi,Bi,Wi,Ki,Ie,wt,Gi,Yi,ue,ge,Le,kt,K,me=$(()=>{Ke();Ke();({is:Di,defineProperty:Ui,getOwnPropertyDescriptor:Vi,getOwnPropertyNames:Bi,getOwnPropertySymbols:Wi,getPrototypeOf:Ki}=Object),Ie=globalThis,wt=Ie.trustedTypes,Gi=wt?wt.emptyScript:"",Yi=Ie.reactiveElementPolyfillSupport,ue=(a,s)=>a,ge={toAttribute(a,s){switch(s){case Boolean:a=a?Gi:null;break;case Object:case Array:a=a==null?a:JSON.stringify(a)}return a},fromAttribute(a,s){let e=a;switch(s){case Boolean:e=a!==null;break;case Number:e=a===null?null:Number(a);break;case Object:case Array:try{e=JSON.parse(a)}catch{e=null}}return e}},Le=(a,s)=>!Di(a,s),kt={attribute:!0,type:String,converter:ge,reflect:!1,useDefault:!1,hasChanged:Le};Symbol.metadata??=Symbol("metadata"),Ie.litPropertyMetadata??=new WeakMap;K=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=kt){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&&Ui(this.prototype,s,i)}}static getPropertyDescriptor(s,e,t){let{get:i,set:n}=Vi(this.prototype,s)??{get(){return this[e]},set(l){this[e]=l}};return{get:i,set(l){let c=i?.call(this);n?.call(this,l),this.requestUpdate(s,c,t)},configurable:!0,enumerable:!0}}static getPropertyOptions(s){return this.elementProperties.get(s)??kt}static _$Ei(){if(this.hasOwnProperty(ue("elementProperties")))return;let s=Ki(this);s.finalize(),s.l!==void 0&&(this.l=[...s.l]),this.elementProperties=new Map(s.elementProperties)}static finalize(){if(this.hasOwnProperty(ue("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(ue("properties"))){let e=this.properties,t=[...Bi(e),...Wi(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(We(i))}else s!==void 0&&e.push(We(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 $t(s,this.constructor.elementStyles),s}connectedCallback(){this.renderRoot??=thiLine truncated
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
var bt=Object.defineProperty;var zi=Object.getOwnPropertyDescriptor;var w=(a,s,e)=>()=>{if(e)throw e[0];try{return a&&(s=a(a=0)),s}catch(t){throw e=[t],t}};var Fi=(a,s)=>{for(var e in s)bt(a,e,{get:s[e],enumerable:!0})};var d=(a,s,e,t)=>{for(var i=t>1?void 0:t?zi(s,e):s,n=a.length-1,l;n>=0;n--)(l=a[n])&&(i=(t?l(s,e,i):l(i))||i);return t&&i&&bt(s,e,i),i};var Te,Ce,Be,yt,_e,xt,E,wt,We,Ke=w(()=>{Te=globalThis,Ce=Te.ShadowRoot&&(Te.ShadyCSS===void 0||Te.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Be=Symbol(),yt=new WeakMap,_e=class{constructor(s,e,t){if(this._$cssResult$=!0,t!==Be)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(Ce&&s===void 0){let t=e!==void 0&&e.length===1;t&&(s=yt.get(e)),s===void 0&&((this.o=s=new CSSStyleSheet).replaceSync(this.cssText),t&&yt.set(e,s))}return s}toString(){return this.cssText}},xt=a=>new _e(typeof a=="string"?a:a+"",void 0,Be),E=(a,...s)=>{let e=a.length===1?a[0]:s.reduce((t,i,n)=>t+(l=>{if(l._$cssResult$===!0)return l.cssText;if(typeof l=="number")return l;throw Error("Value passed to 'css' function must be a 'css' function result: "+l+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+a[n+1],a[0]);return new _e(e,a,Be)},wt=(a,s)=>{if(Ce)a.adoptedStyleSheets=s.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of s){let t=document.createElement("style"),i=Te.litNonce;i!==void 0&&t.setAttribute("nonce",i),t.textContent=e.cssText,a.appendChild(t)}},We=Ce?a=>a:a=>a instanceof CSSStyleSheet?(s=>{let e="";for(let t of s.cssRules)e+=t.cssText;return xt(e)})(a):a});var Di,Ui,Vi,Bi,Wi,Ki,Ie,$t,Gi,Yi,ue,ge,Le,kt,K,me=w(()=>{Ke();Ke();({is:Di,defineProperty:Ui,getOwnPropertyDescriptor:Vi,getOwnPropertyNames:Bi,getOwnPropertySymbols:Wi,getPrototypeOf:Ki}=Object),Ie=globalThis,$t=Ie.trustedTypes,Gi=$t?$t.emptyScript:"",Yi=Ie.reactiveElementPolyfillSupport,ue=(a,s)=>a,ge={toAttribute(a,s){switch(s){case Boolean:a=a?Gi:null;break;case Object:case Array:a=a==null?a:JSON.stringify(a)}return a},fromAttribute(a,s){let e=a;switch(s){case Boolean:e=a!==null;break;case Number:e=a===null?null:Number(a);break;case Object:case Array:try{e=JSON.parse(a)}catch{e=null}}return e}},Le=(a,s)=>!Di(a,s),kt={attribute:!0,type:String,converter:ge,reflect:!1,useDefault:!1,hasChanged:Le};Symbol.metadata??=Symbol("metadata"),Ie.litPropertyMetadata??=new WeakMap;K=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=kt){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&&Ui(this.prototype,s,i)}}static getPropertyDescriptor(s,e,t){let{get:i,set:n}=Vi(this.prototype,s)??{get(){return this[e]},set(l){this[e]=l}};return{get:i,set(l){let c=i?.call(this);n?.call(this,l),this.requestUpdate(s,c,t)},configurable:!0,enumerable:!0}}static getPropertyOptions(s){return this.elementProperties.get(s)??kt}static _$Ei(){if(this.hasOwnProperty(ue("elementProperties")))return;let s=Ki(this);s.finalize(),s.l!==void 0&&(this.l=[...s.l]),this.elementProperties=new Map(s.elementProperties)}static finalize(){if(this.hasOwnProperty(ue("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(ue("properties"))){let e=this.properties,t=[...Bi(e),...Wi(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(We(i))}else s!==void 0&&e.push(We(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 wt(s,this.constructor.elementStyles),s}connectedCallback(){this.renderRoot??=thiLine truncated
|
||||
\f\r]`,fe=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,At=/-->/g,Tt=/>/g,ee=RegExp(`>|${Ge}(?:([^\\s"'>=/]+)(${Ge}*=${Ge}*(?:[^
|
||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),Ct=/'/g,It=/"/g,jt=/^(?:script|style|textarea|title)$/i,it=a=>(s,...e)=>({_$litType$:a,strings:s,values:e}),o=it(1),de=it(2),er=it(3),se=Symbol.for("lit-noChange"),_=Symbol.for("lit-nothing"),Lt=new WeakMap,te=ie.createTreeWalker(ie,129);Zi=(a,s)=>{let e=a.length-1,t=[],i,n=s===2?"<svg>":s===3?"<math>":"",l=fe;for(let c=0;c<e;c++){let p=a[c],u,v,f=-1,y=0;for(;y<p.length&&(l.lastIndex=y,v=l.exec(p),v!==null);)y=l.lastIndex,l===fe?v[1]==="!--"?l=At:v[1]!==void 0?l=Tt:v[2]!==void 0?(jt.test(v[2])&&(i=RegExp("</"+v[2],"g")),l=ee):v[3]!==void 0&&(l=ee):l===ee?v[0]===">"?(l=i??fe,f=-1):v[1]===void 0?f=-2:(f=l.lastIndex-v[2].length,u=v[1],l=v[3]===void 0?ee:v[3]==='"'?It:Ct):l===It||l===Ct?l=ee:l===At||l===Tt?l=fe:(l=ee,i=void 0);let g=l===ee&&a[c+1].startsWith("/>")?" ":"";n+=l===fe?p+Qi:f>=0?(t.push(u),p.slice(0,f)+Pt+p.slice(f)+X+g):p+X+(f===-2?c:g)}return[Nt(a,n+(a[e]||"<?>")+(s===2?"</svg>":s===3?"</math>":"")),t]},ye=class a{constructor({strings:s,_$litType$:e},t){let i;this.parts=[];let n=0,l=0,c=s.length-1,p=this.parts,[u,v]=Zi(s,e);if(this.el=a.createElement(u,t),te.currentNode=this.el.content,e===2||e===3){let f=this.el.content.firstChild;f.replaceWith(...f.childNodes)}for(;(i=te.nextNode())!==null&&p.length<c;){if(i.nodeType===1){if(i.hasAttributes())for(let f of i.getAttributeNames())if(f.endsWith(Pt)){let y=v[l++],g=i.getAttribute(f).split(X),x=/([.?@])?(.*)/.exec(y);p.push({type:1,index:n,name:x[2],strings:g,ctor:x[1]==="."?Qe:x[1]==="?"?Je:x[1]==="@"?Ze:le}),i.removeAttribute(f)}else f.startsWith(X)&&(p.push({type:6,index:n}),i.removeAttribute(f));if(jt.test(i.tagName)){let f=i.textContent.split(X),y=f.length-1;if(y>0){i.textContent=Pe?Pe.emptyScript:"";for(let g=0;g<y;g++)i.append(f[g],ve()),te.nextNode(),p.push({type:2,index:++n});i.append(f[y],ve())}}}else if(i.nodeType===8)if(i.data===Rt)p.push({type:2,index:n});else{let f=-1;for(;(f=i.data.indexOf(X,f+1))!==-1;)p.push({type:7,index:n}),f+=X.length-1}n++}}static createElement(s,e){let t=ie.createElement("template");return t.innerHTML=s,t}};Ye=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??ie).importNode(e,!0);te.currentNode=i;let n=te.nextNode(),l=0,c=0,p=t[0];for(;p!==void 0;){if(l===p.index){let u;p.type===2?u=new xe(n,n.nextSibling,this,s):p.type===1?u=new p.ctor(n,p.name,p.strings,this,s):p.type===6&&(u=new Xe(n,this,s)),this._$AV.push(u),p=t[++c]}l!==p?.index&&(n=te.nextNode(),l++)}return te.currentNode=ie,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++}},xe=class a{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(s,e,t,i){this.type=2,this._$AH=_,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=oe(this,s,e),be(s)?s===_||s==null||s===""?(this._$AH!==_&&this._$AR(),this._$AH=_):s!==this._$AH&&s!==se&&this._(s):s._$litType$!==void 0?this.$(s):s.nodeType!==void 0?this.T(s):Ji(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!==_&&be(this._$AH)?this._$AA.nextSibling.data=s:this.T(ie.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=ye.createElement(Nt(t.h,t.h[0]),this.options)),t);if(this._$AH?._$AD===i)this._$AH.p(e);else{let n=new Ye(i,this),l=n.u(this.options);n.p(e),this.T(l),this._$AH=n}}_$AC(s){let e=Lt.get(s.strings);return e===void 0&&Lt.set(s.strings,e=new ye(s)),e}k(s){tt(this._$AH)||(this._$AH=[],this._$AR());let e=this._$AH,t,i=0;for(let n of s)i===e.length?e.push(t=new a(this.O(ve()),this.O(ve()),this,this.options)):t=e[i],t._$AI(n),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=Et(s).nextSibling;Et(s).remove(),s=t}}setConnected(s){this._$AM===void 0&&(this._$Cv=s,this._$AP?.(s))}},le=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(s,e,t,i,n){this.type=1,this._$AH=_,this._$AN=void 0,this.element=s,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=_}_$AI(s,e=this,t,i){let n=this.strings,l=!1;if(n===void 0)s=oe(this,s,e,0),l=!be(s)||s!==this._$AH&&s!==se,l&&(this._$AH=s);else{let c=s,p,u;for(s=n[0],p=0;p<n.length-1;p++)u=oe(this,c[t+p],e,p),u===se&&(u=this._$AH[p]),l||=!be(u)||u!==this._$AH[p],u===_?s=_:s!==_&&(s+=(u??"")+n[p+1]),this._$AH[p]=u}l&&!i&&this.j(s)}j(s){s===_?this.element.removeAttribute(this.name):thiLine truncated
|
||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),Ct=/'/g,It=/"/g,jt=/^(?:script|style|textarea|title)$/i,it=a=>(s,...e)=>({_$litType$:a,strings:s,values:e}),o=it(1),de=it(2),er=it(3),se=Symbol.for("lit-noChange"),_=Symbol.for("lit-nothing"),Lt=new WeakMap,te=ie.createTreeWalker(ie,129);Zi=(a,s)=>{let e=a.length-1,t=[],i,n=s===2?"<svg>":s===3?"<math>":"",l=fe;for(let c=0;c<e;c++){let p=a[c],u,v,f=-1,y=0;for(;y<p.length&&(l.lastIndex=y,v=l.exec(p),v!==null);)y=l.lastIndex,l===fe?v[1]==="!--"?l=At:v[1]!==void 0?l=Tt:v[2]!==void 0?(jt.test(v[2])&&(i=RegExp("</"+v[2],"g")),l=ee):v[3]!==void 0&&(l=ee):l===ee?v[0]===">"?(l=i??fe,f=-1):v[1]===void 0?f=-2:(f=l.lastIndex-v[2].length,u=v[1],l=v[3]===void 0?ee:v[3]==='"'?It:Ct):l===It||l===Ct?l=ee:l===At||l===Tt?l=fe:(l=ee,i=void 0);let g=l===ee&&a[c+1].startsWith("/>")?" ":"";n+=l===fe?p+Qi:f>=0?(t.push(u),p.slice(0,f)+Pt+p.slice(f)+X+g):p+X+(f===-2?c:g)}return[Nt(a,n+(a[e]||"<?>")+(s===2?"</svg>":s===3?"</math>":"")),t]},ye=class a{constructor({strings:s,_$litType$:e},t){let i;this.parts=[];let n=0,l=0,c=s.length-1,p=this.parts,[u,v]=Zi(s,e);if(this.el=a.createElement(u,t),te.currentNode=this.el.content,e===2||e===3){let f=this.el.content.firstChild;f.replaceWith(...f.childNodes)}for(;(i=te.nextNode())!==null&&p.length<c;){if(i.nodeType===1){if(i.hasAttributes())for(let f of i.getAttributeNames())if(f.endsWith(Pt)){let y=v[l++],g=i.getAttribute(f).split(X),x=/([.?@])?(.*)/.exec(y);p.push({type:1,index:n,name:x[2],strings:g,ctor:x[1]==="."?Qe:x[1]==="?"?Je:x[1]==="@"?Ze:le}),i.removeAttribute(f)}else f.startsWith(X)&&(p.push({type:6,index:n}),i.removeAttribute(f));if(jt.test(i.tagName)){let f=i.textContent.split(X),y=f.length-1;if(y>0){i.textContent=Pe?Pe.emptyScript:"";for(let g=0;g<y;g++)i.append(f[g],ve()),te.nextNode(),p.push({type:2,index:++n});i.append(f[y],ve())}}}else if(i.nodeType===8)if(i.data===Rt)p.push({type:2,index:n});else{let f=-1;for(;(f=i.data.indexOf(X,f+1))!==-1;)p.push({type:7,index:n}),f+=X.length-1}n++}}static createElement(s,e){let t=ie.createElement("template");return t.innerHTML=s,t}};Ye=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??ie).importNode(e,!0);te.currentNode=i;let n=te.nextNode(),l=0,c=0,p=t[0];for(;p!==void 0;){if(l===p.index){let u;p.type===2?u=new xe(n,n.nextSibling,this,s):p.type===1?u=new p.ctor(n,p.name,p.strings,this,s):p.type===6&&(u=new Xe(n,this,s)),this._$AV.push(u),p=t[++c]}l!==p?.index&&(n=te.nextNode(),l++)}return te.currentNode=ie,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++}},xe=class a{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(s,e,t,i){this.type=2,this._$AH=_,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=oe(this,s,e),be(s)?s===_||s==null||s===""?(this._$AH!==_&&this._$AR(),this._$AH=_):s!==this._$AH&&s!==se&&this._(s):s._$litType$!==void 0?this.$(s):s.nodeType!==void 0?this.T(s):Ji(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!==_&&be(this._$AH)?this._$AA.nextSibling.data=s:this.T(ie.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=ye.createElement(Nt(t.h,t.h[0]),this.options)),t);if(this._$AH?._$AD===i)this._$AH.p(e);else{let n=new Ye(i,this),l=n.u(this.options);n.p(e),this.T(l),this._$AH=n}}_$AC(s){let e=Lt.get(s.strings);return e===void 0&&Lt.set(s.strings,e=new ye(s)),e}k(s){tt(this._$AH)||(this._$AH=[],this._$AR());let e=this._$AH,t,i=0;for(let n of s)i===e.length?e.push(t=new a(this.O(ve()),this.O(ve()),this,this.options)):t=e[i],t._$AI(n),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=Et(s).nextSibling;Et(s).remove(),s=t}}setConnected(s){this._$AM===void 0&&(this._$Cv=s,this._$AP?.(s))}},le=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(s,e,t,i,n){this.type=1,this._$AH=_,this._$AN=void 0,this.element=s,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=_}_$AI(s,e=this,t,i){let n=this.strings,l=!1;if(n===void 0)s=oe(this,s,e,0),l=!be(s)||s!==this._$AH&&s!==se,l&&(this._$AH=s);else{let c=s,p,u;for(s=n[0],p=0;p<n.length-1;p++)u=oe(this,c[t+p],e,p),u===se&&(u=this._$AH[p]),l||=!be(u)||u!==this._$AH[p],u===_?s=_:s!==_&&(s+=(u??"")+n[p+1]),this._$AH[p]=u}l&&!i&&this.j(s)}j(s){s===_?this.element.removeAttribute(this.name):thiLine 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",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_optional:"Due at time (optional, HH:MM)",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",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",confirm_delete_object:"Delete this object and all its tasks?",confirm_delete_task:"Delete this task?",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.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",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",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",tasks_lower:"tasks",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",for_at_least_minutes:"For at least (minutes)",safety_interval_days:"Safety interval (days, optional)",safety_interval:"Safety interval (optional)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",adaptive_prediction_enabled:"Enable sensor-driven predictions",adaptive_seasonal_enabled:"Enable seasonal awareness",adaptive_max_interval:"Maximum interval (days)",adaptive_min_interval:"Minimum interval (days)",adaptive_ewa_alpha:"Learning rate (alpha)",adaptive_enabled:"Enable adaptive scheduling",adaptive_section_title:"Adaptive Scheduling",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:"Calendar",cal_no_events:"No maintenance",cal_window_7:"7 days",cal_window_14:"14 days",cal_window_30:"30 days",cal_window_365:"1 year",cal_every_n_days:"every {n} days",cal_source_time:"Time-based",cal_source_time_adaptive:"Time-based (adaptive)",cal_source_sensor:"Sensor-based",cal_predicted:"predicted",cal_confidence_high:"high confidence",cal_confidence_medium:"medium confidence",cal_confidence_low:"low
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",feat_schedule_time:"Time-of-day scheduling",feat_schedule_time_desc:"Tasks become overdue at a specific time of day instead of midnight.",schedule_time_optional:"Due at time (optional, HH:MM)",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",completed_at_optional:"Completed at (optional, empty = now)",completed_at_future_error:"The completion date cannot be in the future.",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",confirm_delete_object:"Delete this object and all its tasks?",confirm_delete_task:"Delete this task?",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.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",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",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",tasks_lower:"tasks",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",trigger_equals:"Trigger when equal to (=)",trigger_not_equals:"Trigger when different from (\u2260)",for_at_least_minutes:"For at least (minutes)",safety_interval_days:"Safety interval (days, optional)",safety_interval:"Safety interval (optional)",trigger_combinator:"Combine trigger and interval",trigger_combinator_any:"Trigger or interval (whichever first)",trigger_combinator_all:"Trigger and interval (both required)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",adaptive_prediction_enabled:"Enable sensor-driven predictions",adaptive_seasonal_enabled:"Enable seasonal awareness",adaptive_max_interval:"Maximum interval (days)",adaptive_min_interval:"Minimum interval (days)",adaptive_ewa_alpha:"Learning rate (alpha)",adaptive_enabled:"Enable adaptive scheduling",adaptive_section_title:"Adaptive Scheduling",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:
Line truncated
|
||||
.field { display: flex; flex-direction: column; gap: 4px; }
|
||||
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
||||
.field-input {
|
||||
@@ -1157,7 +1157,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; }
|
||||
.stat-value { font-size: 20px; }
|
||||
}
|
||||
`});var pe,lt=$(()=>{"use strict";pe=class{constructor(s){this.usersCache=null;this.cacheTimestamp=0;this.CACHE_TTL_MS=6e4;this.hass=s}updateHass(s){this.hass=s}async getUsers(s=!1){let e=Date.now();if(!s&&this.usersCache&&e-this.cacheTimestamp<this.CACHE_TTL_MS)return this.usersCache;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/users/list"});return this.usersCache=t.users,this.cacheTimestamp=e,this.usersCache}catch(t){return console.error("Failed to fetch users:",t),this.usersCache||[]}}async assignUser(s,e,t){await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/assign_user",entry_id:s,task_id:e,user_id:t})}async getTasksByUser(s){return(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/tasks/by_user",user_id:s})).tasks}getUserName(s){return!s||!this.usersCache?null:this.usersCache.find(t=>t.id===s)?.name||null}getUser(s){return!s||!this.usersCache?null:this.usersCache.find(e=>e.id===s)||null}getCurrentUserId(){return this.hass.user?.id||null}isCurrentUser(s){return s?s===this.getCurrentUserId():!1}clearCache(){this.usersCache=null,this.cacheTimestamp=0}}});function U(a){return`${a.entry_id??""}\0${a.part_id}`}function ms(a,s,e,t){let i=!!a.entry_id&&a.entry_id!==s,n=i?a.entry_id:s,l=e.find(v=>v.entry_id===n),c=(l?.parts||[]).find(v=>v.id===a.part_id)||null,p=i&&l?.object?.name||"",u=c?.name||r("shared_part_unknown",t);return{part:c,foreign:i,ownerName:p,label:p?`${u} (${p})`:u}}function ni(a,s,e,t){let n=(e.find(c=>c.entry_id===s)?.parts||[]).map(c=>({...c})),l=new Set(n.map(c=>U({part_id:c.id})));for(let c of a?.consumes_parts||[]){if(!c.entry_id||c.entry_id===s)continue;let p=U(c);if(l.has(p))continue;l.add(p);let{part:u,ownerName:v}=ms(c,s,e,t);n.push({id:c.part_id,name:u?.name||r("shared_part_unknown",t),unit:u?.unit,stock:u?.stock??null,storage_location:u?.storage_location,entry_id:c.entry_id,owner_name:v})}return n}var Fe=$(()=>{"use strict";I()});function bs(a,s){let e=vs[a];if(!e)return a;let t=r(e,s);return t&&t!==e?t:a}function ys(a){let e=a.match(/data\['([^']+)'\]/)?.[1],t;return(t=a.match(/length of value must be at most (\d+)/))?{field:e,rule:"too_long",param:t[1]}:(t=a.match(/length of value must be at least (\d+)/))?{field:e,rule:"too_short",param:t[1]}:(t=a.match(/value must be at most (\S+)/))?{field:e,rule:"value_too_high",param:t[1]}:(t=a.match(/value must be at least (\S+)/))?{field:e,rule:"value_too_low",param:t[1]}:/required key not provided/.test(a)?{field:e,rule:"required"}:(t=a.match(/expected (\w+)/))?{field:e,rule:"wrong_type",param:t[1]}:/value must be one of/.test(a)?{field:e,rule:"invalid_choice"}:/not a valid value/.test(a)?{field:e,rule:"invalid_value"}:{field:e,rule:"unknown"}}function P(a,s,e){if(e=e??r("action_error",s),typeof a=="string")return a;if(typeof a!="object"||a===null)return e;let t=a,i=t.message||t.error?.message||"";if(!i)return e;let n=ys(i),l=n.field?bs(n.field,s):"",c=p=>r(p,s).replace("{field}",l).replace("{n}",n.param??"");switch(n.rule){case"too_long":return c("err_too_long");case"too_short":return c("err_too_short");case"value_too_high":return c("err_value_too_high");case"value_too_low":return c("err_value_too_low");case"required":return c("err_required");case"wrong_type":return c("err_wrong_type").replace("{type}",n.param??"");case"invalid_choice":return c("err_invalid_choice");case"invalid_value":return c("err_invalid_value");default:return i||e}}var vs,ne=$(()=>{"use strict";I();vs={name:"name",task_type:"maintenance_type",schedule_type:"schedule_type",interval_days:"interval_days",interval_anchor:"interval_anchor",warning_days:"warning_days",last_performed:"last_performed_optional",notes:"notes_optional",documentation_url:"documentation_url_optional",custom_icon:"custom_icon_optional",nfc_tag_id:"nfc_tag_id_optional",responsible_user_id:"responsible_user",entity_slug:"entity_slug",entity_id:"entity_id",area_id:"area_id_optional",manufacturer:"manufacturer_optional",model:"model_optional",serial_number:"serial_number_optional",installation_date:"installation_date_optional",warranty_expiry:"warranty_expiry_optional",checklist:"checklist_steps_optional",reason:"reason",feedback:"feedback",cost:"cost",duration:"duration",description:"description_optional",group_name:"name",group_description:"description_optional",environmental_entity:"environmental_entity_optional",environmental_attribute:"environmental_attribute_optional",trigger_above:"trigger_above",trigger_below:"trigger_below",trigger_for_minutes:"trigger_for_minutes"}});var oi,De,dt=$(()=>{"use strict";oi=["notes","cost","duration","photo","user"],De={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"}});var w,ct=$(()=>{"use strict";L();z();I();ne();Fe();dt();w=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.restockDef
Line truncated
|
||||
`});var pe,lt=w(()=>{"use strict";pe=class{constructor(s){this.usersCache=null;this.cacheTimestamp=0;this.CACHE_TTL_MS=6e4;this.hass=s}updateHass(s){this.hass=s}async getUsers(s=!1){let e=Date.now();if(!s&&this.usersCache&&e-this.cacheTimestamp<this.CACHE_TTL_MS)return this.usersCache;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/users/list"});return this.usersCache=t.users,this.cacheTimestamp=e,this.usersCache}catch(t){return console.error("Failed to fetch users:",t),this.usersCache||[]}}async assignUser(s,e,t){await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/assign_user",entry_id:s,task_id:e,user_id:t})}async getTasksByUser(s){return(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/tasks/by_user",user_id:s})).tasks}getUserName(s){return!s||!this.usersCache?null:this.usersCache.find(t=>t.id===s)?.name||null}getUser(s){return!s||!this.usersCache?null:this.usersCache.find(e=>e.id===s)||null}getCurrentUserId(){return this.hass.user?.id||null}isCurrentUser(s){return s?s===this.getCurrentUserId():!1}clearCache(){this.usersCache=null,this.cacheTimestamp=0}}});function U(a){return`${a.entry_id??""}\0${a.part_id}`}function ms(a,s,e,t){let i=!!a.entry_id&&a.entry_id!==s,n=i?a.entry_id:s,l=e.find(v=>v.entry_id===n),c=(l?.parts||[]).find(v=>v.id===a.part_id)||null,p=i&&l?.object?.name||"",u=c?.name||r("shared_part_unknown",t);return{part:c,foreign:i,ownerName:p,label:p?`${u} (${p})`:u}}function ni(a,s,e,t){let n=(e.find(c=>c.entry_id===s)?.parts||[]).map(c=>({...c})),l=new Set(n.map(c=>U({part_id:c.id})));for(let c of a?.consumes_parts||[]){if(!c.entry_id||c.entry_id===s)continue;let p=U(c);if(l.has(p))continue;l.add(p);let{part:u,ownerName:v}=ms(c,s,e,t);n.push({id:c.part_id,name:u?.name||r("shared_part_unknown",t),unit:u?.unit,stock:u?.stock??null,storage_location:u?.storage_location,entry_id:c.entry_id,owner_name:v})}return n}var Fe=w(()=>{"use strict";I()});function bs(a,s){let e=vs[a];if(!e)return a;let t=r(e,s);return t&&t!==e?t:a}function ys(a){let e=a.match(/data\['([^']+)'\]/)?.[1],t;return(t=a.match(/length of value must be at most (\d+)/))?{field:e,rule:"too_long",param:t[1]}:(t=a.match(/length of value must be at least (\d+)/))?{field:e,rule:"too_short",param:t[1]}:(t=a.match(/value must be at most (\S+)/))?{field:e,rule:"value_too_high",param:t[1]}:(t=a.match(/value must be at least (\S+)/))?{field:e,rule:"value_too_low",param:t[1]}:/required key not provided/.test(a)?{field:e,rule:"required"}:(t=a.match(/expected (\w+)/))?{field:e,rule:"wrong_type",param:t[1]}:/value must be one of/.test(a)?{field:e,rule:"invalid_choice"}:/not a valid value/.test(a)?{field:e,rule:"invalid_value"}:{field:e,rule:"unknown"}}function P(a,s,e){if(e=e??r("action_error",s),typeof a=="string")return a;if(typeof a!="object"||a===null)return e;let t=a,i=t.message||t.error?.message||"";if(!i)return e;let n=ys(i),l=n.field?bs(n.field,s):"",c=p=>r(p,s).replace("{field}",l).replace("{n}",n.param??"");switch(n.rule){case"too_long":return c("err_too_long");case"too_short":return c("err_too_short");case"value_too_high":return c("err_value_too_high");case"value_too_low":return c("err_value_too_low");case"required":return c("err_required");case"wrong_type":return c("err_wrong_type").replace("{type}",n.param??"");case"invalid_choice":return c("err_invalid_choice");case"invalid_value":return c("err_invalid_value");default:return i||e}}var vs,ne=w(()=>{"use strict";I();vs={name:"name",task_type:"maintenance_type",schedule_type:"schedule_type",interval_days:"interval_days",interval_anchor:"interval_anchor",warning_days:"warning_days",last_performed:"last_performed_optional",notes:"notes_optional",documentation_url:"documentation_url_optional",custom_icon:"custom_icon_optional",nfc_tag_id:"nfc_tag_id_optional",responsible_user_id:"responsible_user",entity_slug:"entity_slug",entity_id:"entity_id",area_id:"area_id_optional",manufacturer:"manufacturer_optional",model:"model_optional",serial_number:"serial_number_optional",installation_date:"installation_date_optional",warranty_expiry:"warranty_expiry_optional",checklist:"checklist_steps_optional",reason:"reason",feedback:"feedback",cost:"cost",duration:"duration",description:"description_optional",group_name:"name",group_description:"description_optional",environmental_entity:"environmental_entity_optional",environmental_attribute:"environmental_attribute_optional",trigger_above:"trigger_above",trigger_below:"trigger_below",trigger_equals:"trigger_equals",trigger_not_equals:"trigger_not_equals",trigger_for_minutes:"trigger_for_minutes"}});var oi,De,dt=w(()=>{"use strict";oi=["notes","cost","duration","photo","user"],De={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"}});var $,ct=w(()=>{"use strict";L();z();I();ne();Fe();dt();$=class extends k{constructor(){super(...arguments);this.entryId="";this.taskId="";this.taskName="";this.lang="en";this.checklist=[];this
Line truncated
|
||||
type="button"
|
||||
class="cost-suggestion"
|
||||
@click=${()=>this._cost=t.toFixed(2)}
|
||||
@@ -1233,6 +1233,13 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._duration}
|
||||
@input=${t=>this._duration=t.target.value} />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span class="field-label">${r("completed_at_optional",e)}</span>
|
||||
<input type="datetime-local" class="field-input"
|
||||
max=${new Date(Date.now()-new Date().getTimezoneOffset()*6e4).toISOString().slice(0,16)}
|
||||
.value=${this._completedAt}
|
||||
@change=${t=>this._completedAt=t.target.value} />
|
||||
</label>
|
||||
<div class="field">
|
||||
<span class="field-label">${r("completion_photo_optional",e)}${this._req("photo")}</span>
|
||||
${this._photoPreview?o`
|
||||
@@ -1282,7 +1289,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`}};w.styles=[si,E`
|
||||
`}};$.styles=[si,E`
|
||||
.req-mark {
|
||||
color: var(--error-color, #f44336);
|
||||
margin-left: 2px;
|
||||
@@ -1447,7 +1454,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);
|
||||
}
|
||||
`],d([b({attribute:!1})],w.prototype,"hass",2),d([b()],w.prototype,"entryId",2),d([b()],w.prototype,"taskId",2),d([b()],w.prototype,"taskName",2),d([b()],w.prototype,"lang",2),d([b({type:Array})],w.prototype,"checklist",2),d([b({type:Boolean})],w.prototype,"adaptiveEnabled",2),d([b()],w.prototype,"taskType",2),d([b()],w.prototype,"readingUnit",2),d([b({attribute:!1})],w.prototype,"restockDefault",2),d([b({attribute:!1})],w.prototype,"restockUnitCost",2),d([b()],w.prototype,"currencySymbol",2),d([b({attribute:!1})],w.prototype,"parts",2),d([b({attribute:!1})],w.prototype,"consumesParts",2),d([b({type:Array})],w.prototype,"consumesInfo",2),d([b({type:Array})],w.prototype,"requiredFields",2),d([h()],w.prototype,"_open",2),d([h()],w.prototype,"_notes",2),d([h()],w.prototype,"_cost",2),d([h()],w.prototype,"_duration",2),d([h()],w.prototype,"_loading",2),d([h()],w.prototype,"_error",2),d([h()],w.prototype,"_checklistState",2),d([h()],w.prototype,"_feedback",2),d([h()],w.prototype,"_photoDocId",2),d([h()],w.prototype,"_photoPreview",2),d([h()],w.prototype,"_photoUploading",2),d([h()],w.prototype,"_readingValue",2),d([h()],w.prototype,"_restockQty",2),d([h()],w.prototype,"_usedParts",2),d([b({attribute:!1})],w.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",w)});var R,pt=$(()=>{"use strict";L();z();R=class extends k{constructor(){super(...arguments);this.label="";this.value="";this.placeholder="";this.type="text";this.required=!1;this.disabled=!1}_onInput(e){let t=e.target.value;this.value=t,this.dispatchEvent(new CustomEvent("input",{bubbles:!0,composed:!0,detail:{value:t}}))}render(){return o`
|
||||
`],d([b({attribute:!1})],$.prototype,"hass",2),d([b()],$.prototype,"entryId",2),d([b()],$.prototype,"taskId",2),d([b()],$.prototype,"taskName",2),d([b()],$.prototype,"lang",2),d([b({type:Array})],$.prototype,"checklist",2),d([b({type:Boolean})],$.prototype,"adaptiveEnabled",2),d([b()],$.prototype,"taskType",2),d([b()],$.prototype,"readingUnit",2),d([b({attribute:!1})],$.prototype,"restockDefault",2),d([b({attribute:!1})],$.prototype,"restockUnitCost",2),d([b()],$.prototype,"currencySymbol",2),d([b({attribute:!1})],$.prototype,"parts",2),d([b({attribute:!1})],$.prototype,"consumesParts",2),d([b({type:Array})],$.prototype,"consumesInfo",2),d([b({type:Array})],$.prototype,"requiredFields",2),d([h()],$.prototype,"_open",2),d([h()],$.prototype,"_notes",2),d([h()],$.prototype,"_cost",2),d([h()],$.prototype,"_duration",2),d([h()],$.prototype,"_loading",2),d([h()],$.prototype,"_error",2),d([h()],$.prototype,"_checklistState",2),d([h()],$.prototype,"_feedback",2),d([h()],$.prototype,"_photoDocId",2),d([h()],$.prototype,"_photoPreview",2),d([h()],$.prototype,"_photoUploading",2),d([h()],$.prototype,"_readingValue",2),d([h()],$.prototype,"_restockQty",2),d([h()],$.prototype,"_completedAt",2),d([h()],$.prototype,"_usedParts",2),d([b({attribute:!1})],$.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",$)});var R,pt=w(()=>{"use strict";L();z();R=class extends k{constructor(){super(...arguments);this.label="";this.value="";this.placeholder="";this.type="text";this.required=!1;this.disabled=!1}_onInput(e){let t=e.target.value;this.value=t,this.dispatchEvent(new CustomEvent("input",{bubbles:!0,composed:!0,detail:{value:t}}))}render(){return o`
|
||||
<label class="field">
|
||||
${this.label?o`<span class="label">${this.label}${this.required?o`<span class="req">*</span>`:_}</span>`:_}
|
||||
<input
|
||||
@@ -1499,7 +1506,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
color: var(--secondary-text-color);
|
||||
font-style: italic;
|
||||
}
|
||||
`,d([b()],R.prototype,"label",2),d([b()],R.prototype,"value",2),d([b()],R.prototype,"placeholder",2),d([b()],R.prototype,"type",2),d([b({type:Boolean})],R.prototype,"required",2),d([b({type:Boolean})],R.prototype,"disabled",2),d([b()],R.prototype,"step",2),d([b()],R.prototype,"min",2),d([b()],R.prototype,"max",2),d([b()],R.prototype,"pattern",2),d([b()],R.prototype,"helper",2);customElements.get("ms-textfield")||customElements.define("ms-textfield",R)});var A,li=$(()=>{"use strict";L();z();I();ne();pt();A=class extends k{constructor(){super(...arguments);this.objects=[];this._open=!1;this._loading=!1;this._error="";this._name="";this._manufacturer="";this._model="";this._serialNumber="";this._areaId="";this._installationDate="";this._warrantyExpiry="";this._documentationUrl="";this._notes="";this._haDeviceId="";this._parentEntryId="";this._entryId=null}get _lang(){return 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._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._error="",this._open=!0}async _save(){if(!this._loading&&this._name.trim()){this._loading=!0,this._error="";try{this._entryId?await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/update",entry_id:this._entryId,name:this._name,manufacturer:this._manufacturer||null,model:this._model||null,serial_number:this._serialNumber||null,area_id:this._areaId||null,installation_date:this._installationDate||null,warranty_expiry:this._warrantyExpiry||null,documentation_url:this._documentationUrl.trim()||null,notes:this._notes.trim()||null,ha_device_id:this._haDeviceId||null,parent_entry_id:this._parentEntryId||null}):await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/create",name:this._name,manufacturer:this._manufacturer||null,model:this._model||null,serial_number:this._serialNumber||null,area_id:this._areaId||null,installation_date:this._installationDate||null,warranty_expiry:this._warrantyExpiry||null,documentation_url:this._documentationUrl.trim()||null,notes:this._notes.trim()||null,ha_device_id:this._haDeviceId||null,parent_entry_id:this._parentEntryId||null}),this._open=!1,this.dispatchEvent(new CustomEvent("object-saved"))}catch(e){this._error=P(e,this._lang,r("save_error",this._lang))}finally{this._loading=!1}}}_parentChoices(){return(this.objects||[]).filter(e=>e.entry_id!==this._entryId)}_close(){this._open=!1}render(){if(!this._open)return o``;let e=this._lang,t=this._entryId?r("edit_object",e):r("new_object",e);return o`
|
||||
`,d([b()],R.prototype,"label",2),d([b()],R.prototype,"value",2),d([b()],R.prototype,"placeholder",2),d([b()],R.prototype,"type",2),d([b({type:Boolean})],R.prototype,"required",2),d([b({type:Boolean})],R.prototype,"disabled",2),d([b()],R.prototype,"step",2),d([b()],R.prototype,"min",2),d([b()],R.prototype,"max",2),d([b()],R.prototype,"pattern",2),d([b()],R.prototype,"helper",2);customElements.get("ms-textfield")||customElements.define("ms-textfield",R)});var A,li=w(()=>{"use strict";L();z();I();ne();pt();A=class extends k{constructor(){super(...arguments);this.objects=[];this._open=!1;this._loading=!1;this._error="";this._name="";this._manufacturer="";this._model="";this._serialNumber="";this._areaId="";this._installationDate="";this._warrantyExpiry="";this._documentationUrl="";this._notes="";this._haDeviceId="";this._parentEntryId="";this._entryId=null}get _lang(){return 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._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._error="",this._open=!0}async _save(){if(!this._loading&&this._name.trim()){this._loading=!0,this._error="";try{this._entryId?await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/update",entry_id:this._entryId,name:this._name,manufacturer:this._manufacturer||null,model:this._model||null,serial_number:this._serialNumber||null,area_id:this._areaId||null,installation_date:this._installationDate||null,warranty_expiry:this._warrantyExpiry||null,documentation_url:this._documentationUrl.trim()||null,notes:this._notes.trim()||null,ha_device_id:this._haDeviceId||null,parent_entry_id:this._parentEntryId||null}):await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/create",name:this._name,manufacturer:this._manufacturer||null,model:this._model||null,serial_number:this._serialNumber||null,area_id:this._areaId||null,installation_date:this._installationDate||null,warranty_expiry:this._warrantyExpiry||null,documentation_url:this._documentationUrl.trim()||null,notes:this._notes.trim()||null,ha_device_id:this._haDeviceId||null,parent_entry_id:this._parentEntryId||null}),this._open=!1,this.dispatchEvent(new CustomEvent("object-saved"))}catch(e){this._error=P(e,this._lang,r("save_error",this._lang))}finally{this._loading=!1}}}_parentChoices(){return(this.objects||[]).filter(e=>e.entry_id!==this._entryId)}_close(){this._open=!1}render(){if(!this._open)return o``;let e=this._lang,t=this._entryId?r("edit_object",e):r("new_object",e);return o`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${t}</div>
|
||||
<div class="content">
|
||||
@@ -1640,8 +1647,8 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
color: var(--error-color, #f44336);
|
||||
font-size: 13px;
|
||||
}
|
||||
`,d([b({attribute:!1})],A.prototype,"hass",2),d([b({attribute:!1})],A.prototype,"objects",2),d([h()],A.prototype,"_open",2),d([h()],A.prototype,"_loading",2),d([h()],A.prototype,"_error",2),d([h()],A.prototype,"_name",2),d([h()],A.prototype,"_manufacturer",2),d([h()],A.prototype,"_model",2),d([h()],A.prototype,"_serialNumber",2),d([h()],A.prototype,"_areaId",2),d([h()],A.prototype,"_installationDate",2),d([h()],A.prototype,"_warrantyExpiry",2),d([h()],A.prototype,"_documentationUrl",2),d([h()],A.prototype,"_notes",2),d([h()],A.prototype,"_haDeviceId",2),d([h()],A.prototype,"_parentEntryId",2),d([h()],A.prototype,"_entryId",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",A)});var ht,di,ci,pi=$(()=>{"use strict";ht=["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"],di=["sensor"],ci=["temperature","humidity","pressure"]});function Es(){return{entityIds:"",type:"threshold",attribute:"",above:"",below:"",forMinutes:"0",targetValue:"",deltaMode:!1,fromState:"",toState:"",targetChanges:"",runtimeHours:"",onStates:"",carry:{}}}function As(a){return{entityIds:(a.entity_ids||(a.entity_id?[a.entity_id]:[])).join(", "),type:a.type||"threshold",attribute:a.attribute||"",above:a.trigger_above?.toString()??"",below:a.trigger_below?.toString()??"",forMinutes:a.trigger_for_minutes?.toString()??"0",targetValue:a.trigger_target_value?.toString()??"",deltaMode:a.trigger_delta_mode||!1,fromState:a.trigger_from_state||"",toState:a.trigger_to_state||"",targetChanges:a.trigger_target_changes?.toString()??"",runtimeHours:a.trigger_runtime_hours?.toString()??"",onStates:(a.trigger_on_states||[]).join(", "),carry:Object.fromEntries(Object.entries(a).filter(([e])=>!Ss.has(e)&&!e.startsWith("_")))}}function Ts(a){let s=a.entityIds.split(",").map(t=>t.trim()).filter(Boolean);if(s.length===0)return null;let e={...a.carry||{},entity_id:s[0],entity_ids:s,type:a.type};if(a.attribute&&(e.attribute=a.attribute),a.type==="threshold"){let t=parseFloat(a.above);isNaN(t)||(e.trigger_above=t);let i=parseFloat(a.below);isNaN(i)||(e.trigger_below=i);let n=parseInt(a.forMinutes,10);isNaN(n)||(e.trigger_for_minutes=n)}else if(a.type==="counter"){let t=parseFloat(a.targetValue);isNaN(t)||(e.trigger_target_value=t),e.trigger_delta_mode=a.deltaMode}else if(a.type==="state_change"){a.fromState&&(e.trigger_from_state=a.fromState),a.toState&&(e.trigger_to_state=a.toState);let t=parseInt(a.targetChanges,10);isNaN(t)||(e.trigger_target_changes=t)}else if(a.type==="runtime"){let t=parseFloat(a.runtimeHours);isNaN(t)||(e.trigger_runtime_hours=t);let i=(a.onStates||"").split(",").map(n=>n.trim()).filter(Boolean);i.length>0&&(e.trigger_on_states=i)}return e}function Cs(a){return Array.from({length:7},(s,e)=>Ee(e,a,"short"))}function Is(a){let s=new Intl.DateTimeFormat(a||"en",{month:"short"});return Array.from({length:12},(e,t)=>s.format(new Date(2021,t,1)))}var xs,$s,ws,_t,hi,ks,Y,Ss,m,ut,_i=$(()=>{"use strict";L();z();I();lt();Fe();pi();ne();dt();pt();xs=["cleaning","inspection","replacement","calibration","service","reading","custom"],$s=["low","normal","high"],ws=["time_based","weekdays","nth_weekday","day_of_month","sensor_based","one_time","manual"],_t=["weekdays","nth_weekday","day_of_month"],hi=["threshold","counter","state_change","runtime"],ks=[...hi,"compound"],Y={alpha:"0.3",min:"7",max:"365"};Ss=new Set(["entity_id","entity_ids","type","attribute","trigger_above","trigger_below","trigger_for_minutes","trigger_target_value","trigger_delta_mode","trigger_from_state","trigger_to_state","trigger_target_changes","trigger_runtime_hours","trigger_on_states"]);m=class m extends k{constructor(){super(...arguments);this.checklistsEnabled=!1;this.scheduleTimeEnabled=!1;this.completionActionsEnabled=!1;this.defaultWarningDays=7;this.parts=[];this._foreignOwners=[];this._open=!1;this._entityPickerFallback=!1;this._pickerProbeStrikes=0;this._loading=!1;this._error="";this._entryId="";this._taskId=null;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._seasonMonths=[];this._endsMode="never";this._endsCount="";this._endsUntil="";this._schedulePreview=[];this._schedulePreviewEnded=!1;this._previewSeq=0;this._notes="";this._documentationUrl="";this._customIcon="";this._priority="normal";this._labels="";this._enabled=!0;this._triggerEntityId="";this._triggerEntityIds=[];this._triggerEntityLogic="any";this._triggerAttribute="";this._triggerType="threshold";this._triggerAbove="";this._triggerBelow="";this._triggerForMinutes="0";this.
Line truncated
|
||||
`),this._requiredCompletion=[...t.required_completion_fields||[]],this._scheduleTime=t.schedule_time||"";let l=t.on_complete_action;if(l&&l.service){this._actionService=l.service;let u=l.target?.entity_id;this._actionTargetEntity=Array.isArray(u)?u[0]||"":u||"",this._actionData=l.data&&typeof l.data=="object"?{...l.data}:{},this._actionDataJsonFallback=""}else this._actionService="",this._actionTargetEntity="",this._actionData={},this._actionDataJsonFallback="";let c=t.quick_complete_defaults;this._qcNotes=c?.notes||"",this._qcCost=c?.cost!=null?String(c.cost):"",this._qcDuration=c?.duration!=null?String(c.duration):"",this._qcFeedback=c?.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()??Y.alpha,this._adaptiveMin=p.min_interval_days?.toString()??Y.min,this._adaptiveMax=p.max_interval_days?.toString()??Y.max,this._adaptiveSeasonal=p.seasonal_enabled!==!1,this._adaptivePrediction=p.sensor_prediction_enabled!==!1,this._adaptiveInitial=this._adaptiveSnapshot(),t.trigger_config){let u=t.trigger_config;this._triggerEntityId=u.entity_id||u.entity_ids&&u.entity_ids[0]||"",this._triggerEntityIds=u.entity_ids||(u.entity_id?[u.entity_id]:[]),this._triggerEntityLogic=u.entity_logic||"any",this._triggerAttribute=u.attribute||"",this._triggerType=u.type||"threshold",this._triggerAbove=u.trigger_above?.toString()||"",this._triggerBelow=u.trigger_below?.toString()||"",this._triggerForMinutes=u.trigger_for_minutes?.toString()||"0",this._triggerTargetValue=u.trigger_target_value?.toString()||"",this._triggerDeltaMode=u.trigger_delta_mode||!1,this._triggerBaselineValue=u.trigger_baseline_value?.toString()||"",this._liveBaselineValue=t.trigger_baseline_value??null,this._autoCompleteOnRecovery=u.auto_complete_on_recovery||!1,this._triggerFromState=u.trigger_from_state||"",this._triggerToState=u.trigger_to_state||"",this._triggerTargetChanges=u.trigger_target_changes?.toString()||"",this._triggerRuntimeHours=u.trigger_runtime_hours?.toString()||"",this._triggerOnStates=(u.trigger_on_states||[]).join(", "),u.type==="compound"?(this._compoundLogic=u.compound_logic==="OR"?"OR":"AND",this._compoundConditions=(u.conditions||[]).map(As)):(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._priority="normal",this._labels="",this._enabled=!0,this._lastPerformed="",this._nfcTagId="",this._readingUnit="",this._consumesParts={},this._responsibleUserId=null,this._assigneePool=[],this._rotationStrategy="",this._checklistText="",this._requiredCompletion=[],this._scheduleTime="",this._environmentalEntity="",this._environmentalAttribute="",this._environmentalInitial="",this._environmentalAttributeInitial="",this._adaptiveEnabled=!1,this._adaptiveAlpha=Y.alpha,this._adaptiveMin=Y.min,this._adaptiveMax=Y.max,this._adaptiveSeasonal=!0,this._adaptivePrediction=!0,this._adaptiveInitial=this._adaptiveSnapshot(),this._actionService="",this._actionTargetEntity="",this._actionData={},this._actionDataJsonFallback="",this._actionTesting=!1,this._actionTestResult="",this._qcNotes="",this._qcCost="",this._qcDuration="",this._qcFeedback="",this._resetTriggerFields()}_resetTriggerFields(){this._triggerEntityId="",this._triggerEntityIds=[],this._triggerEntityLogic="any",this._triggerAttribute="",this._suggestedAttributes=[],this._availableAttributes=[],this._entityDomain="",this._triggerType="threshold",this._triggerAbove="",this._triggerBelow="",this._triggerForMinutes="0",this._triggerTargetValue="",this._triggerDeltaMode=!1,this._triggerBaselineValue="",this._liveBaselineValue=null,this._autoCompleteOnRecovery=!1,this._triggerFromState="",this._triggerToState="",this._triggerTargetChanges="",this._triggerRuntimeHours="",this._triggerOnStates="",this._compoundLogic="AND",this._compoundConditions=[]}async _loadUsers(){this._userService||(this._userService=new pe(this.hass));try{this._availableUsers=await this._userService.getUsers()}catch(e){console.error("Failed to load users:",e),this._availableUsers=[]}}_t
Line truncated
|
||||
`,d([b({attribute:!1})],A.prototype,"hass",2),d([b({attribute:!1})],A.prototype,"objects",2),d([h()],A.prototype,"_open",2),d([h()],A.prototype,"_loading",2),d([h()],A.prototype,"_error",2),d([h()],A.prototype,"_name",2),d([h()],A.prototype,"_manufacturer",2),d([h()],A.prototype,"_model",2),d([h()],A.prototype,"_serialNumber",2),d([h()],A.prototype,"_areaId",2),d([h()],A.prototype,"_installationDate",2),d([h()],A.prototype,"_warrantyExpiry",2),d([h()],A.prototype,"_documentationUrl",2),d([h()],A.prototype,"_notes",2),d([h()],A.prototype,"_haDeviceId",2),d([h()],A.prototype,"_parentEntryId",2),d([h()],A.prototype,"_entryId",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",A)});var ht,di,ci,pi=w(()=>{"use strict";ht=["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"],di=["sensor"],ci=["temperature","humidity","pressure"]});function Es(){return{entityIds:"",type:"threshold",attribute:"",above:"",below:"",equals:"",notEquals:"",forMinutes:"0",targetValue:"",deltaMode:!1,fromState:"",toState:"",targetChanges:"",runtimeHours:"",onStates:"",carry:{}}}function As(a){return{entityIds:(a.entity_ids||(a.entity_id?[a.entity_id]:[])).join(", "),type:a.type||"threshold",attribute:a.attribute||"",above:a.trigger_above?.toString()??"",below:a.trigger_below?.toString()??"",equals:a.trigger_equals?.toString()??"",notEquals:a.trigger_not_equals?.toString()??"",forMinutes:a.trigger_for_minutes?.toString()??"0",targetValue:a.trigger_target_value?.toString()??"",deltaMode:a.trigger_delta_mode||!1,fromState:a.trigger_from_state||"",toState:a.trigger_to_state||"",targetChanges:a.trigger_target_changes?.toString()??"",runtimeHours:a.trigger_runtime_hours?.toString()??"",onStates:(a.trigger_on_states||[]).join(", "),carry:Object.fromEntries(Object.entries(a).filter(([e])=>!Ss.has(e)&&!e.startsWith("_")))}}function Ts(a){let s=a.entityIds.split(",").map(t=>t.trim()).filter(Boolean);if(s.length===0)return null;let e={...a.carry||{},entity_id:s[0],entity_ids:s,type:a.type};if(a.attribute&&(e.attribute=a.attribute),a.type==="threshold"){let t=parseFloat(a.above);isNaN(t)||(e.trigger_above=t);let i=parseFloat(a.below);isNaN(i)||(e.trigger_below=i);let n=parseFloat(a.equals);isNaN(n)||(e.trigger_equals=n);let l=parseFloat(a.notEquals);isNaN(l)||(e.trigger_not_equals=l);let c=parseInt(a.forMinutes,10);isNaN(c)||(e.trigger_for_minutes=c)}else if(a.type==="counter"){let t=parseFloat(a.targetValue);isNaN(t)||(e.trigger_target_value=t),e.trigger_delta_mode=a.deltaMode}else if(a.type==="state_change"){a.fromState&&(e.trigger_from_state=a.fromState),a.toState&&(e.trigger_to_state=a.toState);let t=parseInt(a.targetChanges,10);isNaN(t)||(e.trigger_target_changes=t)}else if(a.type==="runtime"){let t=parseFloat(a.runtimeHours);isNaN(t)||(e.trigger_runtime_hours=t);let i=(a.onStates||"").split(",").map(n=>n.trim()).filter(Boolean);i.length>0&&(e.trigger_on_states=i)}return e}function Cs(a){return Array.from({length:7},(s,e)=>Ee(e,a,"short"))}function Is(a){let s=new Intl.DateTimeFormat(a||"en",{month:"short"});return Array.from({length:12},(e,t)=>s.format(new Date(2021,t,1)))}var xs,ws,$s,_t,hi,ks,Y,Ss,m,ut,_i=w(()=>{"use strict";L();z();I();lt();Fe();pi();ne();dt();pt();xs=["cleaning","inspection","replacement","calibration","service","reading","custom"],ws=["low","normal","high"],$s=["time_based","weekdays","nth_weekday","day_of_month","sensor_based","one_time","manual"],_t=["weekdays","nth_weekday","day_of_month"],hi=["threshold","counter","state_change","runtime"],ks=[...hi,"compound"],Y={alpha:"0.3",min:"7",max:"365"};Ss=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"]);m=class m extends k{constructor(){super(...arguments);this.checklistsEnabled=!1;this.scheduleTimeEnabled=!1;this.completionActionsEnabled=!1;this.defaultWarningDays=7;this.parts=[];this._foreignOwners=[];this._open=!1;this._entityPickerFallback=!1;this._pickerProbeStrikes=0;this._loading=!1;this._error="";this._entryId="";this._taskId=null;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._seasonMonths=[];this._endsMode="never";this._endsCount="";this._endsUntil="";this._schedulePreview=[];this._schedulePreviewEnded=!1;this._previewSeq=0;this._notes="";this._documentationUrl="";this._customIcon="";t
Line truncated
|
||||
`),this._requiredCompletion=[...t.required_completion_fields||[]],this._scheduleTime=t.schedule_time||"";let l=t.on_complete_action;if(l&&l.service){this._actionService=l.service;let u=l.target?.entity_id;this._actionTargetEntity=Array.isArray(u)?u[0]||"":u||"",this._actionData=l.data&&typeof l.data=="object"?{...l.data}:{},this._actionDataJsonFallback=""}else this._actionService="",this._actionTargetEntity="",this._actionData={},this._actionDataJsonFallback="";let c=t.quick_complete_defaults;this._qcNotes=c?.notes||"",this._qcCost=c?.cost!=null?String(c.cost):"",this._qcDuration=c?.duration!=null?String(c.duration):"",this._qcFeedback=c?.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()??Y.alpha,this._adaptiveMin=p.min_interval_days?.toString()??Y.min,this._adaptiveMax=p.max_interval_days?.toString()??Y.max,this._adaptiveSeasonal=p.seasonal_enabled!==!1,this._adaptivePrediction=p.sensor_prediction_enabled!==!1,this._adaptiveInitial=this._adaptiveSnapshot(),t.trigger_config){let u=t.trigger_config;this._triggerEntityId=u.entity_id||u.entity_ids&&u.entity_ids[0]||"",this._triggerEntityIds=u.entity_ids||(u.entity_id?[u.entity_id]:[]),this._triggerEntityLogic=u.entity_logic||"any",this._triggerAttribute=u.attribute||"",this._triggerType=u.type||"threshold",this._triggerAbove=u.trigger_above?.toString()||"",this._triggerBelow=u.trigger_below?.toString()||"",this._triggerEquals=u.trigger_equals?.toString()||"",this._triggerNotEquals=u.trigger_not_equals?.toString()||"",this._triggerForMinutes=u.trigger_for_minutes?.toString()||"0",this._triggerCombinator=u.trigger_combinator==="all"?"all":"any",this._triggerTargetValue=u.trigger_target_value?.toString()||"",this._triggerDeltaMode=u.trigger_delta_mode||!1,this._triggerBaselineValue=u.trigger_baseline_value?.toString()||"",this._liveBaselineValue=t.trigger_baseline_value??null,this._autoCompleteOnRecovery=u.auto_complete_on_recovery||!1,this._triggerFromState=u.trigger_from_state||"",this._triggerToState=u.trigger_to_state||"",this._triggerTargetChanges=u.trigger_target_changes?.toString()||"",this._triggerRuntimeHours=u.trigger_runtime_hours?.toString()||"",this._triggerOnStates=(u.trigger_on_states||[]).join(", "),u.type==="compound"?(this._compoundLogic=u.compound_logic==="OR"?"OR":"AND",this._compoundConditions=(u.conditions||[]).map(As)):(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._priority="normal",this._labels="",this._enabled=!0,this._lastPerformed="",this._nfcTagId="",this._readingUnit="",this._consumesParts={},this._responsibleUserId=null,this._assigneePool=[],this._rotationStrategy="",this._checklistText="",this._requiredCompletion=[],this._scheduleTime="",this._environmentalEntity="",this._environmentalAttribute="",this._environmentalInitial="",this._environmentalAttributeInitial="",this._adaptiveEnabled=!1,this._adaptiveAlpha=Y.alpha,this._adaptiveMin=Y.min,this._adaptiveMax=Y.max,this._adaptiveSeasonal=!0,this._adaptivePrediction=!0,this._adaptiveInitial=this._adaptiveSnapshot(),this._actionService="",this._actionTargetEntity="",this._actionData={},this._actionDataJsonFallback="",this._actionTesting=!1,this._actionTestResult="",this._qcNotes="",this._qcCost="",this._qcDuration="",this._qcFeedback="",this._resetTriggerFields()}_resetTriggerFields(){this._triggerEntityId="",this._triggerEntityIds=[],this._triggerEntityLogic="any",this._triggerAttribute="",this._suggestedAttributes=[],this._availableAttributes=[],this._entityDomain="",this._triggerType="threshold",this._triggerAbove="",this._triggerBelow="",this._triggerEquals="",this._triggerNotEquals="",this._triggerForMinutes="0",this._triggerCombinator="any",this._triggerTargetValue="",this._triggerDeltaMode=!1,this._triggerBaselineValue="",this._liveBaselineValue=null,this._autoCompleteOnRecovery=!1,this._triggerFromState="",this._triggerToState="",this._triggerTargetChanges="",this._triggerRuntimeHours="",this._triggerOnStates="",this._comp
Line truncated
|
||||
<details class="ca-section">
|
||||
<summary>${r("on_complete_action_title",e)}</summary>
|
||||
<p class="field-help">${r("on_complete_action_desc",e)}</p>
|
||||
@@ -1737,7 +1744,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
@input=${c=>{let p=parseFloat(c.target.value);this._consumesParts={...this._consumesParts,[i]:{...l,quantity:Number.isFinite(p)&&p>=.01?p:1}}}}
|
||||
/>`:_}
|
||||
</div>
|
||||
`}_toggleRequired(e,t){let i=new Set(this._requiredCompletion);t?i.add(e):i.delete(e),this._requiredCompletion=[...i]}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=`${r("adaptive_min_interval",this._lang)} > ${r("adaptive_max_interval",this._lang)}`;return}}this._loading=!0,this._error="";try{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();if(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):_t.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.priority=this._priority,e.labels=this._labels.split(",").map(c=>c.trim()).filter(Boolean),e.enabled=this._enabled,e.last_performed=this._lastPerformed||null,e.nfc_tag_id=this._nfcTagId||null,e.reading_unit=this._readingUnit.trim()||null,(this.parts.length||this._foreignOwners.length)&&(e.consumes_parts=Object.values(this._consumesParts).map(c=>c.entry_id?{part_id:c.part_id,quantity:c.quantity,entry_id:c.entry_id}:{part_id:c.part_id,quantity:c.quantity})),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 c=this._compoundConditions.map(Ts).filter(p=>p!==null);if(c.length>0){let p={type:"compound",compound_logic:this._compoundLogic,conditions:c};this._autoCompleteOnRecovery&&(p.auto_complete_on_recovery=!0),e.trigger_config=p}else this._taskId&&(e.trigger_config=null)}else if(this._scheduleType==="sensor_based"&&this._triggerEntityId){let c=this._triggerEntityIds.length>0?this._triggerEntityIds:[this._triggerEntityId],p={entity_id:c[0],entity_ids:c,type:this._triggerType};if(this._triggerAttribute&&(p.attribute=this._triggerAttribute),this._autoCompleteOnRecovery&&(p.auto_complete_on_recovery=!0),c.length>1&&(p.entity_logic=this._triggerEntityLogic),this._triggerType==="threshold"){if(this._triggerAbove){let u=parseFloat(this._triggerAbove);isNaN(u)||(p.trigger_above=u)}if(this._triggerBelow){let u=parseFloat(this._triggerBelow);isNaN(u)||(p.trigger_below=u)}if(this._triggerForMinutes){let u=parseInt(this._triggerForMinutes,10);isNaN(u)||(p.trigger_for_minutes=u)}}else if(this._triggerType==="counter"){if(this._triggerTargetValue){let u=parseFloat(this._triggerTargetValue);isNaN(u)||(p.trigger_target_value=u)}if(p.trigger_delta_mode=this._triggerDeltaMode,this._triggerDeltaMode&&this._triggerBaselineValue){let u=parseFloat(this._triggerBaselineValue);!isNaN(u)&&u>=0&&(p.trigger_baseline_value=u)}}else if(this._triggerType==="state_change"){if(this._triggerFromState&&(p.trigger_from_state=this._triggerFromState),this._triggerToState&&(p.trigger_to_state=this._triggerToState),this._triggerTargetChanges){let u=parseInt(this._triggerTargetChanges,10);isNaN(u)||(p.trigger_target_changes=u)}}else if(this._triggerType==="runtime"){if(this._triggerRuntimeHours){let v=parseFloat(this._triggerRuntimeHours);isNaN(v)||(p.trigger_runtime_hours=v)}let u=this._triggerOnStates.split(",").map(v=>v.trim()).filter(Boolean);u.length>0&&(p.trigger_on_states=u)}e.trigger_config=p}else this._taskId&&(e.trigger_config=null);if(this.scheduleTimeEnabled&&this._scheduleType==="time_based"){let c=this._scheduleTime.trim();e.schedule_time=/^([01]\d|2[0-3]):[0-5]\d$/.test(c)?c:null}if(this.checklistsEnabled){let c=this._checklistText.split(`
|
||||
`}_toggleRequired(e,t){let i=new Set(this._requiredCompletion);t?i.add(e):i.delete(e),this._requiredCompletion=[...i]}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=`${r("adaptive_min_interval",this._lang)} > ${r("adaptive_max_interval",this._lang)}`;return}}this._loading=!0,this._error="";try{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();if(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):_t.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.priority=this._priority,e.labels=this._labels.split(",").map(c=>c.trim()).filter(Boolean),e.enabled=this._enabled,e.last_performed=this._lastPerformed||null,e.nfc_tag_id=this._nfcTagId||null,e.reading_unit=this._readingUnit.trim()||null,(this.parts.length||this._foreignOwners.length)&&(e.consumes_parts=Object.values(this._consumesParts).map(c=>c.entry_id?{part_id:c.part_id,quantity:c.quantity,entry_id:c.entry_id}:{part_id:c.part_id,quantity:c.quantity})),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 c=this._compoundConditions.map(Ts).filter(p=>p!==null);if(c.length>0){let p={type:"compound",compound_logic:this._compoundLogic,conditions:c};this._autoCompleteOnRecovery&&(p.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(p.trigger_combinator="all"),e.trigger_config=p}else this._taskId&&(e.trigger_config=null)}else if(this._scheduleType==="sensor_based"&&this._triggerEntityId){let c=this._triggerEntityIds.length>0?this._triggerEntityIds:[this._triggerEntityId],p={entity_id:c[0],entity_ids:c,type:this._triggerType};if(this._triggerAttribute&&(p.attribute=this._triggerAttribute),this._autoCompleteOnRecovery&&(p.auto_complete_on_recovery=!0),this._triggerCombinator==="all"&&(p.trigger_combinator="all"),c.length>1&&(p.entity_logic=this._triggerEntityLogic),this._triggerType==="threshold"){if(this._triggerAbove){let u=parseFloat(this._triggerAbove);isNaN(u)||(p.trigger_above=u)}if(this._triggerBelow){let u=parseFloat(this._triggerBelow);isNaN(u)||(p.trigger_below=u)}if(this._triggerEquals){let u=parseFloat(this._triggerEquals);isNaN(u)||(p.trigger_equals=u)}if(this._triggerNotEquals){let u=parseFloat(this._triggerNotEquals);isNaN(u)||(p.trigger_not_equals=u)}if(this._triggerForMinutes){let u=parseInt(this._triggerForMinutes,10);isNaN(u)||(p.trigger_for_minutes=u)}}else if(this._triggerType==="counter"){if(this._triggerTargetValue){let u=parseFloat(this._triggerTargetValue);isNaN(u)||(p.trigger_target_value=u)}if(p.trigger_delta_mode=this._triggerDeltaMode,this._triggerDeltaMode&&this._triggerBaselineValue){let u=parseFloat(this._triggerBaselineValue);!isNaN(u)&&u>=0&&(p.trigger_baseline_value=u)}}else if(this._triggerType==="state_change"){if(this._triggerFromState&&(p.trigger_from_state=this._triggerFromState),this._triggerToState&&(p.trigger_to_state=this._triggerToState),this._triggerTargetChanges){let u=parseInt(this._triggerTargetChanges,10);isNaN(u)||(p.trigger_target_changes=u)}}else if(this._triggerType==="runtime"){if(this._triggerRuntimeHours){let v=parseFloat(this._triggerRuntimeHours);isNaN(v)||(p.trigger_runtime_hours=v)}let u=this._triggerOnStates.split(",").map(v=>v.trim()).filter(Boolean);u.length>0&&(p.trigger_on_states=u)}e.trigger_config=p}else this._taskId&&(e.trigger_config=null);if(this.scheduleTimeEnabled&&this._scheduleType==="time_based"){let c=this._scheduleTime.trim();e.schedule_time=/^([01]\d|2[0-3]):[0-5]\d$/.test(c)?c:null}if(this.checklistsEnabled){let c=this._checklistText.split(`
|
||||
`).map(p=>p.trim()).filter(Boolean).slice(0,100);e.checklist=c.length?c:null}if(this.completionActionsEnabled){let c=this._actionService.trim();if(c&&/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(c)){let f={service:c},y=this._actionTargetEntity.trim();y&&(f.target={entity_id:y});let g=this._buildActionData();Object.keys(g).length>0&&(f.data=g),e.on_complete_action=f}else e.on_complete_action=null;let p={};this._qcNotes.trim()&&(p.notes=this._qcNotes.trim());let u=parseFloat(this._qcCost);!isNaN(u)&&u>=0&&(p.cost=u);let v=parseInt(this._qcDuration,10);!isNaN(v)&&v>=0&&(p.duration=v),this._qcFeedback&&(p.feedback=this._qcFeedback),e.quick_complete_defaults=Object.keys(p).length?p:null}let i=await this.hass.connection.sendMessagePromise(e),n=this._taskId||i?.task_id,l=this._environmentalEntity!==this._environmentalInitial||this._environmentalAttribute!==this._environmentalAttributeInitial;if(n&&this._scheduleType==="sensor_based"&&l)try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/set_environmental_entity",entry_id:this._entryId,task_id:n,environmental_entity:this._environmentalEntity||null,environmental_attribute:this._environmentalAttribute||null}),this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute}catch{}if(n&&this._adaptiveSnapshot()!==this._adaptiveInitial){let c=parseFloat(this._adaptiveAlpha),p=parseInt(this._adaptiveMin,10),u=parseInt(this._adaptiveMax,10);try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/set_adaptive",entry_id:this._entryId,task_id:n,enabled:this._adaptiveEnabled,...c>=.1&&c<=.9?{ewa_alpha:c}:{},...!isNaN(p)&&p>=1?{min_interval_days:p}:{},...!isNaN(u)&&u>=1?{max_interval_days:u}:{},seasonal_enabled:this._adaptiveSeasonal,sensor_prediction_enabled:this._adaptivePrediction}),this._adaptiveInitial=this._adaptiveSnapshot()}catch{}}this._open=!1,this.dispatchEvent(new CustomEvent("task-saved"))}catch(e){this._error=P(e,this._lang,r("save_error",this._lang))}finally{this._loading=!1}}}_close(){this._open=!1,this._pickerProbeTimer!==void 0&&(clearTimeout(this._pickerProbeTimer),this._pickerProbeTimer=void 0),this._pickerProbeStrikes=0}_renderTriggerFields(){if(this._scheduleType!=="sensor_based")return _;let e=this._lang,t=this._triggerType==="compound";return o`
|
||||
<h3>${r("trigger_configuration",e)}</h3>
|
||||
<div class="select-row">
|
||||
@@ -1797,6 +1804,17 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
@input=${i=>this._intervalDays=i.target.value}
|
||||
></ms-textfield>
|
||||
${this._intervalDays?this._renderUnitSelect():_}
|
||||
${this._intervalDays?o`
|
||||
<div class="select-row">
|
||||
<label>${r("trigger_combinator",e)}</label>
|
||||
<select
|
||||
@change=${i=>this._triggerCombinator=i.target.value}
|
||||
>
|
||||
<option value="any" ?selected=${this._triggerCombinator==="any"}>${r("trigger_combinator_any",e)}</option>
|
||||
<option value="all" ?selected=${this._triggerCombinator==="all"}>${r("trigger_combinator_all",e)}</option>
|
||||
</select>
|
||||
</div>
|
||||
`:_}
|
||||
`}_patchCondition(e,t){this._compoundConditions=this._compoundConditions.map((i,n)=>n===e?{...i,...t}:i)}_addCondition(){this._compoundConditions=[...this._compoundConditions,Es()]}_removeCondition(e){this._compoundConditions=this._compoundConditions.filter((t,i)=>i!==e)}_renderCompoundEditor(){let e=this._lang;return o`
|
||||
<div class="select-row">
|
||||
<label>${r("compound_logic",e)}</label>
|
||||
@@ -1958,6 +1976,10 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
@input=${n=>this._patchCondition(t,{above:n.target.value})}></ms-textfield>
|
||||
<ms-textfield label="${r("trigger_below",i)}" type="number" .value=${e.below}
|
||||
@input=${n=>this._patchCondition(t,{below:n.target.value})}></ms-textfield>
|
||||
<ms-textfield label="${r("trigger_equals",i)}" type="number" .value=${e.equals}
|
||||
@input=${n=>this._patchCondition(t,{equals:n.target.value})}></ms-textfield>
|
||||
<ms-textfield label="${r("trigger_not_equals",i)}" type="number" .value=${e.notEquals}
|
||||
@input=${n=>this._patchCondition(t,{notEquals:n.target.value})}></ms-textfield>
|
||||
<ms-textfield label="${r("for_minutes",i)}" type="number" .value=${e.forMinutes}
|
||||
@input=${n=>this._patchCondition(t,{forMinutes:n.target.value})}></ms-textfield>
|
||||
`;if(e.type==="counter")return o`
|
||||
@@ -2093,6 +2115,20 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.value=${this._triggerBelow}
|
||||
@input=${t=>this._triggerBelow=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${r("trigger_equals",e)}"
|
||||
type="number"
|
||||
step="any"
|
||||
.value=${this._triggerEquals}
|
||||
@input=${t=>this._triggerEquals=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${r("trigger_not_equals",e)}"
|
||||
type="number"
|
||||
step="any"
|
||||
.value=${this._triggerNotEquals}
|
||||
@input=${t=>this._triggerNotEquals=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${r("for_at_least_minutes",e)}"
|
||||
type="number"
|
||||
@@ -2214,7 +2250,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}
|
||||
>
|
||||
${$s.map(i=>o`<option value=${i} ?selected=${i===this._priority}>${r("priority_"+i,e)}</option>`)}
|
||||
${ws.map(i=>o`<option value=${i} ?selected=${i===this._priority}>${r("priority_"+i,e)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
@@ -2233,7 +2269,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}
|
||||
>
|
||||
${ws.map(i=>o`<option value=${i} ?selected=${i===this._scheduleType}>${r(i,e)}</option>`)}
|
||||
${$s.map(i=>o`<option value=${i} ?selected=${i===this._scheduleType}>${r(i,e)}</option>`)}
|
||||
</select>
|
||||
</div>
|
||||
${this._scheduleType==="time_based"?o`
|
||||
@@ -2734,7 +2770,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
`,d([b({attribute:!1})],m.prototype,"hass",2),d([b({type:Boolean,attribute:"checklists-enabled"})],m.prototype,"checklistsEnabled",2),d([b({type:Boolean,attribute:"schedule-time-enabled"})],m.prototype,"scheduleTimeEnabled",2),d([b({type:Boolean,attribute:"completion-actions-enabled"})],m.prototype,"completionActionsEnabled",2),d([b({type:Number,attribute:"default-warning-days"})],m.prototype,"defaultWarningDays",2),d([h()],m.prototype,"parts",2),d([h()],m.prototype,"_foreignOwners",2),d([h()],m.prototype,"_open",2),d([h()],m.prototype,"_entityPickerFallback",2),d([h()],m.prototype,"_loading",2),d([h()],m.prototype,"_error",2),d([h()],m.prototype,"_entryId",2),d([h()],m.prototype,"_taskId",2),d([h()],m.prototype,"_objectChoices",2),d([h()],m.prototype,"_name",2),d([h()],m.prototype,"_type",2),d([h()],m.prototype,"_scheduleType",2),d([h()],m.prototype,"_intervalDays",2),d([h()],m.prototype,"_intervalUnit",2),d([h()],m.prototype,"_dueDate",2),d([h()],m.prototype,"_warningDays",2),d([h()],m.prototype,"_earliestCompletionDays",2),d([h()],m.prototype,"_intervalAnchor",2),d([h()],m.prototype,"_weekdays",2),d([h()],m.prototype,"_nth",2),d([h()],m.prototype,"_nthWeekday",2),d([h()],m.prototype,"_domDay",2),d([h()],m.prototype,"_domLastDay",2),d([h()],m.prototype,"_domBusiness",2),d([h()],m.prototype,"_calOffset",2),d([h()],m.prototype,"_seasonMonths",2),d([h()],m.prototype,"_endsMode",2),d([h()],m.prototype,"_endsCount",2),d([h()],m.prototype,"_endsUntil",2),d([h()],m.prototype,"_schedulePreview",2),d([h()],m.prototype,"_schedulePreviewEnded",2),d([h()],m.prototype,"_notes",2),d([h()],m.prototype,"_documentationUrl",2),d([h()],m.prototype,"_customIcon",2),d([h()],m.prototype,"_priority",2),d([h()],m.prototype,"_labels",2),d([h()],m.prototype,"_enabled",2),d([h()],m.prototype,"_triggerEntityId",2),d([h()],m.prototype,"_triggerEntityIds",2),d([h()],m.prototype,"_triggerEntityLogic",2),d([h()],m.prototype,"_triggerAttribute",2),d([h()],m.prototype,"_triggerType",2),d([h()],m.prototype,"_triggerAbove",2),d([h()],m.prototype,"_triggerBelow",2),d([h()],m.prototype,"_triggerForMinutes",2),d([h()],m.prototype,"_triggerTargetValue",2),d([h()],m.prototype,"_triggerDeltaMode",2),d([h()],m.prototype,"_triggerBaselineValue",2),d([h()],m.prototype,"_liveBaselineValue",2),d([h()],m.prototype,"_autoCompleteOnRecovery",2),d([h()],m.prototype,"_triggerFromState",2),d([h()],m.prototype,"_triggerToState",2),d([h()],m.prototype,"_triggerTargetChanges",2),d([h()],m.prototype,"_triggerRuntimeHours",2),d([h()],m.prototype,"_triggerOnStates",2),d([h()],m.prototype,"_compoundLogic",2),d([h()],m.prototype,"_compoundConditions",2),d([h()],m.prototype,"_suggestedAttributes",2),d([h()],m.prototype,"_availableAttributes",2),d([h()],m.prototype,"_entityDomain",2),d([h()],m.prototype,"_lastPerformed",2),d([h()],m.prototype,"_nfcTagId",2),d([h()],m.prototype,"_readingUnit",2),d([h()],m.prototype,"_consumesParts",2),d([h()],m.prototype,"_partsLoadFailed",2),d([h()],m.prototype,"_availableTags",2),d([h()],m.prototype,"_responsibleUserId",2),d([h()],m.prototype,"_assigneePool",2),d([h()],m.prototype,"_rotationStrategy",2),d([h()],m.prototype,"_availableUsers",2),d([h()],m.prototype,"_checklistText",2),d([h()],m.prototype,"_requiredCompletion",2),d([h()],m.prototype,"_scheduleTime",2),d([h()],m.prototype,"_actionService",2),d([h()],m.prototype,"_actionTargetEntity",2),d([h()],m.prototype,"_actionData",2),d([h()],m.prototype,"_actionDataJsonFallback",2),d([h()],m.prototype,"_actionTesting",2),d([h()],m.prototype,"_actionTestResult",2),d([h()],m.prototype,"_actionTestError",2),d([h()],m.prototype,"_qcNotes",2),d([h()],m.prototype,"_qcCost",2),d([h()],m.prototype,"_qcDuration",2),d([h()],m.prototype,"_qcFeedback",2),d([h()],m.prototype,"_environmentalEntity",2),d([h()],m.prototype,"_environmentalAttribute",2),d([h()],m.prototype,"_adaptiveEnabled",2),d([h()],m.prototype,"_adaptiveAlpha",2),d([h()],m.prototype,"_adaptiveMin",2),d([h()],m.prototype,"_adaptiveMax",2),d([h()],m.prototype,"_adaptiveSeasonal",2),d([h()],m.prototype,"_adaptivePrediction",2),d([h()],m.prototype,"_conditionAttrOptions",2);ut=m;customElements.get("maintenance-task-dialog")||customElements.define("maintenance-task-dialog",ut)});var F,ui=$(()=>{"use strict";L();z();I();ne();F=class extends k{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null;this._partOptions=null;this._partQty={};this._partQtyOriginal=""}get _lang(){return N(this.hass)}openEdit(e){this._draft={...e},this._originalSnapshot={...e},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._loadPartOptions()}async _loadPartOptions(){let e=this._draft;if(e)try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"}),i=[];for(let l of t.parts||[]){let c=l.entry_id===e.entry_id,p=l.consumers.some(u=>u.entry_id===e.entry_id&&u.task_id===e.task_id);!c&&!p||i.push({part
Line truncated
|
||||
`,d([b({attribute:!1})],m.prototype,"hass",2),d([b({type:Boolean,attribute:"checklists-enabled"})],m.prototype,"checklistsEnabled",2),d([b({type:Boolean,attribute:"schedule-time-enabled"})],m.prototype,"scheduleTimeEnabled",2),d([b({type:Boolean,attribute:"completion-actions-enabled"})],m.prototype,"completionActionsEnabled",2),d([b({type:Number,attribute:"default-warning-days"})],m.prototype,"defaultWarningDays",2),d([h()],m.prototype,"parts",2),d([h()],m.prototype,"_foreignOwners",2),d([h()],m.prototype,"_open",2),d([h()],m.prototype,"_entityPickerFallback",2),d([h()],m.prototype,"_loading",2),d([h()],m.prototype,"_error",2),d([h()],m.prototype,"_entryId",2),d([h()],m.prototype,"_taskId",2),d([h()],m.prototype,"_objectChoices",2),d([h()],m.prototype,"_name",2),d([h()],m.prototype,"_type",2),d([h()],m.prototype,"_scheduleType",2),d([h()],m.prototype,"_intervalDays",2),d([h()],m.prototype,"_intervalUnit",2),d([h()],m.prototype,"_dueDate",2),d([h()],m.prototype,"_warningDays",2),d([h()],m.prototype,"_earliestCompletionDays",2),d([h()],m.prototype,"_intervalAnchor",2),d([h()],m.prototype,"_weekdays",2),d([h()],m.prototype,"_nth",2),d([h()],m.prototype,"_nthWeekday",2),d([h()],m.prototype,"_domDay",2),d([h()],m.prototype,"_domLastDay",2),d([h()],m.prototype,"_domBusiness",2),d([h()],m.prototype,"_calOffset",2),d([h()],m.prototype,"_seasonMonths",2),d([h()],m.prototype,"_endsMode",2),d([h()],m.prototype,"_endsCount",2),d([h()],m.prototype,"_endsUntil",2),d([h()],m.prototype,"_schedulePreview",2),d([h()],m.prototype,"_schedulePreviewEnded",2),d([h()],m.prototype,"_notes",2),d([h()],m.prototype,"_documentationUrl",2),d([h()],m.prototype,"_customIcon",2),d([h()],m.prototype,"_priority",2),d([h()],m.prototype,"_labels",2),d([h()],m.prototype,"_enabled",2),d([h()],m.prototype,"_triggerEntityId",2),d([h()],m.prototype,"_triggerEntityIds",2),d([h()],m.prototype,"_triggerEntityLogic",2),d([h()],m.prototype,"_triggerAttribute",2),d([h()],m.prototype,"_triggerType",2),d([h()],m.prototype,"_triggerAbove",2),d([h()],m.prototype,"_triggerBelow",2),d([h()],m.prototype,"_triggerEquals",2),d([h()],m.prototype,"_triggerNotEquals",2),d([h()],m.prototype,"_triggerForMinutes",2),d([h()],m.prototype,"_triggerCombinator",2),d([h()],m.prototype,"_triggerTargetValue",2),d([h()],m.prototype,"_triggerDeltaMode",2),d([h()],m.prototype,"_triggerBaselineValue",2),d([h()],m.prototype,"_liveBaselineValue",2),d([h()],m.prototype,"_autoCompleteOnRecovery",2),d([h()],m.prototype,"_triggerFromState",2),d([h()],m.prototype,"_triggerToState",2),d([h()],m.prototype,"_triggerTargetChanges",2),d([h()],m.prototype,"_triggerRuntimeHours",2),d([h()],m.prototype,"_triggerOnStates",2),d([h()],m.prototype,"_compoundLogic",2),d([h()],m.prototype,"_compoundConditions",2),d([h()],m.prototype,"_suggestedAttributes",2),d([h()],m.prototype,"_availableAttributes",2),d([h()],m.prototype,"_entityDomain",2),d([h()],m.prototype,"_lastPerformed",2),d([h()],m.prototype,"_nfcTagId",2),d([h()],m.prototype,"_readingUnit",2),d([h()],m.prototype,"_consumesParts",2),d([h()],m.prototype,"_partsLoadFailed",2),d([h()],m.prototype,"_availableTags",2),d([h()],m.prototype,"_responsibleUserId",2),d([h()],m.prototype,"_assigneePool",2),d([h()],m.prototype,"_rotationStrategy",2),d([h()],m.prototype,"_availableUsers",2),d([h()],m.prototype,"_checklistText",2),d([h()],m.prototype,"_requiredCompletion",2),d([h()],m.prototype,"_scheduleTime",2),d([h()],m.prototype,"_actionService",2),d([h()],m.prototype,"_actionTargetEntity",2),d([h()],m.prototype,"_actionData",2),d([h()],m.prototype,"_actionDataJsonFallback",2),d([h()],m.prototype,"_actionTesting",2),d([h()],m.prototype,"_actionTestResult",2),d([h()],m.prototype,"_actionTestError",2),d([h()],m.prototype,"_qcNotes",2),d([h()],m.prototype,"_qcCost",2),d([h()],m.prototype,"_qcDuration",2),d([h()],m.prototype,"_qcFeedback",2),d([h()],m.prototype,"_environmentalEntity",2),d([h()],m.prototype,"_environmentalAttribute",2),d([h()],m.prototype,"_adaptiveEnabled",2),d([h()],m.prototype,"_adaptiveAlpha",2),d([h()],m.prototype,"_adaptiveMin",2),d([h()],m.prototype,"_adaptiveMax",2),d([h()],m.prototype,"_adaptiveSeasonal",2),d([h()],m.prototype,"_adaptivePrediction",2),d([h()],m.prototype,"_conditionAttrOptions",2);ut=m;customElements.get("maintenance-task-dialog")||customElements.define("maintenance-task-dialog",ut)});var F,ui=w(()=>{"use strict";L();z();I();ne();F=class extends k{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null;this._partOptions=null;this._partQty={};this._partQtyOriginal=""}get _lang(){return N(this.hass)}openEdit(e){this._draft={...e},this._originalSnapshot={...e},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._loadPartOptions()}async _loadPartOptions(){let e=this._draft;if(e)try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"}),i=[];for(let l of t.part
Line truncated
|
||||
<div class="backdrop" @click=${this.close}></div>
|
||||
<div class="dialog" role="dialog" aria-modal="true">
|
||||
<h2>${r("history_edit_title",e)||"Edit history entry"}</h2>
|
||||
@@ -2872,7 +2908,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
||||
.part-row-edit input[type="checkbox"] { width: auto; }
|
||||
.part-label { flex: 1; color: var(--primary-text-color); }
|
||||
.part-qty { width: 76px; }
|
||||
`,d([b({attribute:!1})],F.prototype,"hass",2),d([h()],F.prototype,"_open",2),d([h()],F.prototype,"_saving",2),d([h()],F.prototype,"_error",2),d([h()],F.prototype,"_draft",2),d([h()],F.prototype,"_partOptions",2),d([h()],F.prototype,"_partQty",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",F)});function he(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function gi(a){return!a.startsWith("data:image/svg+xml,")&&!a.startsWith("data:image/png;base64,")?"":he(a)}function Ls(a){return a.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var O,mi=$(()=>{"use strict";L();z();I();O=class extends k{constructor(){super(...arguments);this.lang="en";this._open=!1;this._loading=!1;this._error="";this._viewResult=null;this._completeResult=null;this._urlMode="companion";this._entryId="";this._taskId=null;this._objectName="";this._taskName="";this._generateSeq=0}openForObject(e,t){this._entryId=e,this._taskId=null,this._objectName=t,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=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._open=!0,this._generate()}async _generate(){let e=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=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"}));let n=await Promise.all(i);if(e!==this._generateSeq)return;this._viewResult=n[0],n.length>1&&(this._completeResult=n[1])}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")?r("qr_error_no_url",this.lang):r("qr_error",this.lang)}finally{e===this._generateSeq&&(this._loading=!1)}}_setUrlMode(e){this._urlMode!==e&&(this._urlMode=e,this._generate())}_print(){if(!this._viewResult)return;let e=this._viewResult,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 l=this.lang||"en",c=he(t),p=he(i),u=!!this._completeResult,v=he(r("qr_action_view",l)),f=he(r("qr_action_complete",l));n.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
||||
`,d([b({attribute:!1})],F.prototype,"hass",2),d([h()],F.prototype,"_open",2),d([h()],F.prototype,"_saving",2),d([h()],F.prototype,"_error",2),d([h()],F.prototype,"_draft",2),d([h()],F.prototype,"_partOptions",2),d([h()],F.prototype,"_partQty",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",F)});function he(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function gi(a){return!a.startsWith("data:image/svg+xml,")&&!a.startsWith("data:image/png;base64,")?"":he(a)}function Ls(a){return a.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var q,mi=w(()=>{"use strict";L();z();I();q=class extends k{constructor(){super(...arguments);this.lang="en";this._open=!1;this._loading=!1;this._error="";this._viewResult=null;this._completeResult=null;this._urlMode="companion";this._entryId="";this._taskId=null;this._objectName="";this._taskName="";this._generateSeq=0}openForObject(e,t){this._entryId=e,this._taskId=null,this._objectName=t,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=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._open=!0,this._generate()}async _generate(){let e=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=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"}));let n=await Promise.all(i);if(e!==this._generateSeq)return;this._viewResult=n[0],n.length>1&&(this._completeResult=n[1])}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")?r("qr_error_no_url",this.lang):r("qr_error",this.lang)}finally{e===this._generateSeq&&(this._loading=!1)}}_setUrlMode(e){this._urlMode!==e&&(this._urlMode=e,this._generate())}_print(){if(!this._viewResult)return;let e=this._viewResult,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 l=this.lang||"en",c=he(t),p=he(i),u=!!this._completeResult,v=he(r("qr_action_view",l)),f=he(r("qr_action_complete",l));n.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
||||
<meta name="color-scheme" content="light">
|
||||
<title>${c}</title>
|
||||
<style>
|
||||
@@ -2965,7 +3001,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`}};O.styles=E`
|
||||
`}};q.styles=E`
|
||||
.dialog-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
@@ -3083,7 +3119,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
color: var(--text-primary-color, #fff);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
`,d([b({attribute:!1})],O.prototype,"hass",2),d([b()],O.prototype,"lang",2),d([h()],O.prototype,"_open",2),d([h()],O.prototype,"_loading",2),d([h()],O.prototype,"_error",2),d([h()],O.prototype,"_viewResult",2),d([h()],O.prototype,"_completeResult",2),d([h()],O.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",O)});function fi(a,s){let e=a.interval_analysis,t=e?.weibull_beta,i=e?.weibull_eta;if(t==null||i==null||i<=0)return _;let n=a.interval_days??0,l=a.suggested_interval??n;return o`
|
||||
`,d([b({attribute:!1})],q.prototype,"hass",2),d([b()],q.prototype,"lang",2),d([h()],q.prototype,"_open",2),d([h()],q.prototype,"_loading",2),d([h()],q.prototype,"_error",2),d([h()],q.prototype,"_viewResult",2),d([h()],q.prototype,"_completeResult",2),d([h()],q.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",q)});function fi(a,s){let e=a.interval_analysis,t=e?.weibull_beta,i=e?.weibull_eta;if(t==null||i==null||i<=0)return _;let n=a.interval_days??0,l=a.suggested_interval??n;return o`
|
||||
<div class="weibull-section">
|
||||
<div class="weibull-title">
|
||||
<ha-svg-icon aria-hidden="true" path="M3,14L3.5,14.07L8.07,9.5C7.89,8.85 8.06,8.11 8.59,7.59C9.37,6.8 10.63,6.8 11.41,7.59C11.94,8.11 12.11,8.85 11.93,9.5L14.5,12.07L15,12C15.18,12 15.35,12 15.5,12.07L19.07,8.5C19,8.35 19,8.18 19,8A2,2 0 0,1 21,6A2,2 0 0,1 23,8A2,2 0 0,1 21,10C20.82,10 20.65,10 20.5,9.93L16.93,13.5C17,13.65 17,13.82 17,14A2,2 0 0,1 15,16A2,2 0 0,1 13,14L13.07,13.5L10.5,10.93C10.18,11 9.82,11 9.5,10.93L4.93,15.5L5,16A2,2 0 0,1 3,18A2,2 0 0,1 1,16A2,2 0 0,1 3,14Z"></ha-svg-icon>
|
||||
@@ -3099,14 +3135,14 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
<ha-svg-icon path="${t}"></ha-svg-icon>
|
||||
${r(i,s)} (\u03B2=${a.toFixed(2)})
|
||||
</span>
|
||||
`}function Rs(a,s,e,t,i){let g=Math.max(e,t,s,1)*1.3,x=50,H=[];for(let q=0;q<=x;q++){let D=q/x*g,Oi=1-Math.exp(-Math.pow(D/s,a)),Mi=32+D/g*260,qi=136-Oi*128;H.push([Mi,qi])}let j=H.map(([q,D])=>`${q.toFixed(1)},${D.toFixed(1)}`).join(" "),S="M32,136 "+H.map(([q,D])=>`L${q.toFixed(1)},${D.toFixed(1)}`).join(" ")+` L${H[x][0].toFixed(1)},136 Z`,C=32+e/g*260,Se=1-Math.exp(-Math.pow(e/s,a)),Ae=136-Se*128,Ni=((1-Se)*100).toFixed(0),vt=32+t/g*260,Hi=[0,.25,.5,.75,1];return o`
|
||||
`}function Rs(a,s,e,t,i){let g=Math.max(e,t,s,1)*1.3,x=50,H=[];for(let M=0;M<=x;M++){let D=M/x*g,qi=1-Math.exp(-Math.pow(D/s,a)),Oi=32+D/g*260,Mi=136-qi*128;H.push([Oi,Mi])}let j=H.map(([M,D])=>`${M.toFixed(1)},${D.toFixed(1)}`).join(" "),S="M32,136 "+H.map(([M,D])=>`L${M.toFixed(1)},${D.toFixed(1)}`).join(" ")+` L${H[x][0].toFixed(1)},136 Z`,C=32+e/g*260,Se=1-Math.exp(-Math.pow(e/s,a)),Ae=136-Se*128,Ni=((1-Se)*100).toFixed(0),vt=32+t/g*260,Hi=[0,.25,.5,.75,1];return o`
|
||||
<div class="weibull-chart">
|
||||
<svg viewBox="0 0 ${300} ${160}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${r("chart_weibull",i)}">
|
||||
${Hi.map(q=>{let D=136-q*128;return de`
|
||||
${Hi.map(M=>{let D=136-M*128;return de`
|
||||
<line x1="${32}" y1="${D.toFixed(1)}" x2="${292}" y2="${D.toFixed(1)}"
|
||||
stroke="var(--divider-color)" stroke-width="0.5" stroke-dasharray="${q===.5?"4,3":_}" />
|
||||
stroke="var(--divider-color)" stroke-width="0.5" stroke-dasharray="${M===.5?"4,3":_}" />
|
||||
<text x="${28}" y="${(D+3).toFixed(1)}" fill="var(--secondary-text-color)"
|
||||
font-size="8" text-anchor="end">${(q*100).toFixed(0)}%</text>
|
||||
font-size="8" text-anchor="end">${(M*100).toFixed(0)}%</text>
|
||||
`})}
|
||||
|
||||
<text x="${32}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">0</text>
|
||||
@@ -3170,7 +3206,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
<span class="confidence-text high">${r("confidence_aggressive",e)} (${i}${r("days",e).charAt(0)})</span>
|
||||
</div>
|
||||
</div>
|
||||
`}var vi=$(()=>{"use strict";L();I()});function bi(a,s,e){let t=a.degradation_trend!=null&&a.degradation_trend!=="insufficient_data",i=a.days_until_threshold!=null,n=a.environmental_factor!=null&&a.environmental_factor!==1;if(!t&&!i&&!n)return _;let l=a.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":a.degradation_trend==="falling"?"M16,18L18.29,15.71L13.41,10.83L9.41,14.83L2,7.41L3.41,6L9.41,12L13.41,8L19.71,14.29L22,12V18H16Z":"M22,12L18,8V11H3V13H18V16L22,12Z";return o`
|
||||
`}var vi=w(()=>{"use strict";L();I()});function bi(a,s,e){let t=a.degradation_trend!=null&&a.degradation_trend!=="insufficient_data",i=a.days_until_threshold!=null,n=a.environmental_factor!=null&&a.environmental_factor!==1;if(!t&&!i&&!n)return _;let l=a.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":a.degradation_trend==="falling"?"M16,18L18.29,15.71L13.41,10.83L9.41,14.83L2,7.41L3.41,6L9.41,12L13.41,8L19.71,14.29L22,12V18H16Z":"M22,12L18,8V11H3V13H18V16L22,12Z";return o`
|
||||
<div class="prediction-section">
|
||||
${a.sensor_prediction_urgency?o`
|
||||
<div class="prediction-urgency-banner">
|
||||
@@ -3210,7 +3246,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
`:_}
|
||||
</div>
|
||||
</div>
|
||||
`}var yi=$(()=>{"use strict";L();I()});function xi(a,s,e,t){let i=Math.max(a||1,s);return o`
|
||||
`}var yi=w(()=>{"use strict";L();I()});function xi(a,s,e,t){let i=Math.max(a||1,s);return o`
|
||||
<div class="interval-comparison">
|
||||
<div class="interval-bar">
|
||||
<div class="interval-label">
|
||||
@@ -3228,7 +3264,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
style="width: ${Math.min(s/i*100,100)}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
`}var $i=$(()=>{"use strict";L();I()});function ki(a,s,e){if(!e.seasonal||!a.seasonal_factor||a.seasonal_factor===1)return _;let t=wi.map(c=>r(c,s)),i=new Date().getMonth(),n=a.seasonal_factors||a.interval_analysis?.seasonal_factors||null,l=n&&n.length===12?n:t.map((c,p)=>{let u=a.seasonal_factor||1,v=Math.sin((p-6)*Math.PI/6)*.3;return Math.max(.7,Math.min(1.3,u+v))});return o`
|
||||
`}var wi=w(()=>{"use strict";L();I()});function ki(a,s,e){if(!e.seasonal||!a.seasonal_factor||a.seasonal_factor===1)return _;let t=$i.map(c=>r(c,s)),i=new Date().getMonth(),n=a.seasonal_factors||a.interval_analysis?.seasonal_factors||null,l=n&&n.length===12?n:t.map((c,p)=>{let u=a.seasonal_factor||1,v=Math.sin((p-6)*Math.PI/6)*.3;return Math.max(.7,Math.min(1.3,u+v))});return o`
|
||||
<div class="seasonal-card-compact">
|
||||
<h4>${r("seasonal_awareness",s)}</h4>
|
||||
<div class="seasonal-mini-chart">
|
||||
@@ -3262,10 +3298,10 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
`})}
|
||||
</svg>
|
||||
<div class="seasonal-labels">
|
||||
${wi.map((x,H)=>o`<span class="seasonal-label ${H===i?"active-month":""}">${r(x,s)}</span>`)}
|
||||
${$i.map((x,H)=>o`<span class="seasonal-label ${H===i?"active-month":""}">${r(x,s)}</span>`)}
|
||||
</div>
|
||||
</div>
|
||||
`}var wi,Si=$(()=>{"use strict";L();I();wi=["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 T,Ai=$(()=>{"use strict";L();z();I();ne();vi();yi();$i();Si();T=class extends k{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._taskId=null;this._task=null;this._objectName="";this._busy=!1;this._error="";this._showSkip=!1;this._showReset=!1;this._showDetails=!1;this._showAdaptive=!1;this._skipReason="";this._resetDate="";this._features={adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1};this._toast="";this._featuresLoaded=!1}get _lang(){return N(this.hass)}async openFor(e,t){this._entryId=e,this._taskId=t,this._error="",this._showSkip=!1,this._showReset=!1,this._showAdaptive=!1,this._skipReason="",this._resetDate=new Date().toISOString().slice(0,10),this._open=!0,await Promise.all([this._loadTask(),this._loadFeatures()])}async _loadFeatures(){if(!this._featuresLoaded)try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/settings"});e?.features&&(this._features={...this._features,...e.features}),this._featuresLoaded=!0}catch{}}close(){this._open=!1,this._task=null,this._error=""}async _loadTask(){if(!(!this._entryId||!this._taskId))try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId});this._objectName=e.object?.name||"";let t=(e.tasks||[]).find(i=>i.id===this._taskId);this._task=t??null}catch(e){this._error=P(e,this._lang)}}async _runWs(e){this._busy=!0,this._error="";try{return await this.hass.connection.sendMessagePromise(e),this._busy=!1,!0}catch(t){return this._error=P(t,this._lang),this._busy=!1,!1}}_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(()=>(B(),Q)).then(({openCompleteDialog:e})=>{e({entry_id:this._entryId,task_id:this._taskId,task_name:this._task.name,checklist:this._task.checklist||[],adaptive_enabled:!!this._task.adaptive_config?.enabled})&&(this._notifyChanged("complete"),this.close())})}async _onSkipConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/skip",entry_id:this._entryId,task_id:this._taskId,reason:this._skipReason.trim()||null})&&(this._notifyChanged("skip"),this.close())}async _onResetConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/reset",entry_id:this._entryId,task_id:this._taskId,date:this._resetDate||void 0})&&(this._notifyChanged("reset"),this.close())}_onEdit(){!this._entryId||!this._taskId||Promise.resolve().then(()=>(B(),Q)).then(({openEditTaskDialog:e})=>{e(this._entryId,this._taskId),this.close()})}_onQr(){!this._entryId||!this._taskId||!this._task||Promise.resolve().then(()=>(B(),Q)).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)return;let e=r("delete_task_confirm",this._lang)||`Delete "${this._task?.name}"?`;if(!window.confirm(e))return;await this._runWs({type:"maintenance_supporter/task/delete",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("delete"),this.close())}async _onArchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/archive",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("archive"),this.close())}async _onUnarchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/unarchive",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("unarchive"),this.close())}_onOpenInPanel(){if(!this._entryId||!this._taskId)return;let e=`/maintenance-supporter?entry_id=${encodeURIComponent(this._entryId)}&task_id=${encodeURIComponent(this._taskId)}`;history.pushState(null,"",e),window.dispatchEvent(new CustomEvent("location-changed")),this.close()}async _applySuggestion(){if(!this._entryId||!this._taskId||!this._task?.suggested_interval)return;await this._runWs({type:"maintenance_supporter/task/apply_suggestion",entry_id:this._entryId,task_id:this._taskId,interval:this._task.suggested_interval})&&(this._toast=r("suggestion_applied",this._lang)||"Applied",this._notifyChanged("apply_suggestion"),await this._loadTask(),setTimeout(()=>{this._toast=""},2500))}async _reanalyzeInterval(){if(!(!this._entryId||!this._taskId)){this._busy=!0,this._error="";try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/analyze_interval",entry_id:this._entryId,task_id:this._taskId});this._toast=e.recommended_interval?`${r("reanalyze_result",this._lang)||"Recomputed"}: ${He(e.recommended_inLine truncated
|
||||
`}var $i,Si=w(()=>{"use strict";L();I();$i=["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 T,Ai=w(()=>{"use strict";L();z();I();ne();vi();yi();wi();Si();T=class extends k{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._taskId=null;this._task=null;this._objectName="";this._busy=!1;this._error="";this._showSkip=!1;this._showReset=!1;this._showDetails=!1;this._showAdaptive=!1;this._skipReason="";this._resetDate="";this._features={adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1};this._toast="";this._featuresLoaded=!1}get _lang(){return N(this.hass)}async openFor(e,t){this._entryId=e,this._taskId=t,this._error="",this._showSkip=!1,this._showReset=!1,this._showAdaptive=!1,this._skipReason="",this._resetDate=new Date().toISOString().slice(0,10),this._open=!0,await Promise.all([this._loadTask(),this._loadFeatures()])}async _loadFeatures(){if(!this._featuresLoaded)try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/settings"});e?.features&&(this._features={...this._features,...e.features}),this._featuresLoaded=!0}catch{}}close(){this._open=!1,this._task=null,this._error=""}async _loadTask(){if(!(!this._entryId||!this._taskId))try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId});this._objectName=e.object?.name||"";let t=(e.tasks||[]).find(i=>i.id===this._taskId);this._task=t??null}catch(e){this._error=P(e,this._lang)}}async _runWs(e){this._busy=!0,this._error="";try{return await this.hass.connection.sendMessagePromise(e),this._busy=!1,!0}catch(t){return this._error=P(t,this._lang),this._busy=!1,!1}}_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(()=>(B(),Q)).then(({openCompleteDialog:e})=>{e({entry_id:this._entryId,task_id:this._taskId,task_name:this._task.name,checklist:this._task.checklist||[],adaptive_enabled:!!this._task.adaptive_config?.enabled})&&(this._notifyChanged("complete"),this.close())})}async _onSkipConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/skip",entry_id:this._entryId,task_id:this._taskId,reason:this._skipReason.trim()||null})&&(this._notifyChanged("skip"),this.close())}async _onResetConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/reset",entry_id:this._entryId,task_id:this._taskId,date:this._resetDate||void 0})&&(this._notifyChanged("reset"),this.close())}_onEdit(){!this._entryId||!this._taskId||Promise.resolve().then(()=>(B(),Q)).then(({openEditTaskDialog:e})=>{e(this._entryId,this._taskId),this.close()})}_onQr(){!this._entryId||!this._taskId||!this._task||Promise.resolve().then(()=>(B(),Q)).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)return;let e=r("delete_task_confirm",this._lang)||`Delete "${this._task?.name}"?`;if(!window.confirm(e))return;await this._runWs({type:"maintenance_supporter/task/delete",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("delete"),this.close())}async _onArchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/archive",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("archive"),this.close())}async _onUnarchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/unarchive",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("unarchive"),this.close())}_onOpenInPanel(){if(!this._entryId||!this._taskId)return;let e=`/maintenance-supporter?entry_id=${encodeURIComponent(this._entryId)}&task_id=${encodeURIComponent(this._taskId)}`;history.pushState(null,"",e),window.dispatchEvent(new CustomEvent("location-changed")),this.close()}async _applySuggestion(){if(!this._entryId||!this._taskId||!this._task?.suggested_interval)return;await this._runWs({type:"maintenance_supporter/task/apply_suggestion",entry_id:this._entryId,task_id:this._taskId,interval:this._task.suggested_interval})&&(this._toast=r("suggestion_applied",this._lang)||"Applied",this._notifyChanged("apply_suggestion"),await this._loadTask(),setTimeout(()=>{this._toast=""},2500))}async _reanalyzeInterval(){if(!(!this._entryId||!this._taskId)){this._busy=!0,this._error="";try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/analyze_interval",entry_id:this._entryId,task_id:this._taskId});this._toast=e.recommended_interval?`${r("reanalyze_result",this._lang)||"Recomputed"}: ${He(e.recommended_inLine truncated
|
||||
<div class="recommendation-card">
|
||||
<h4>${r("suggested_interval",t)}</h4>
|
||||
${xi(e.interval_days,e.suggested_interval,e.interval_confidence||"medium",t)}
|
||||
@@ -3626,7 +3662,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; }
|
||||
`],d([b({attribute:!1})],T.prototype,"hass",2),d([h()],T.prototype,"_open",2),d([h()],T.prototype,"_entryId",2),d([h()],T.prototype,"_taskId",2),d([h()],T.prototype,"_task",2),d([h()],T.prototype,"_objectName",2),d([h()],T.prototype,"_busy",2),d([h()],T.prototype,"_error",2),d([h()],T.prototype,"_showSkip",2),d([h()],T.prototype,"_showReset",2),d([h()],T.prototype,"_showDetails",2),d([h()],T.prototype,"_showAdaptive",2),d([h()],T.prototype,"_skipReason",2),d([h()],T.prototype,"_resetDate",2),d([h()],T.prototype,"_features",2),d([h()],T.prototype,"_toast",2);customElements.get("maintenance-task-quick-actions-dialog")||customElements.define("maintenance-task-quick-actions-dialog",T)});function Ti(a){return!!a&&/^https?:\/\//i.test(a)}var Ci=$(()=>{"use strict"});var W,Ii=$(()=>{"use strict";L();Ci();z();I();ne();W=class extends k{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._data=null;this._busy=!1;this._error=""}get _lang(){return N(this.hass)}async openFor(e){this._entryId=e,this._error="",this._open=!0,await this._load()}close(){this._open=!1,this._data=null,this._error=""}async _load(){if(this._entryId)try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId});this._data=e}catch(e){this._error=P(e,this._lang)}}_onEditObject(){!this._entryId||!this._data||Promise.resolve().then(()=>(B(),Q)).then(({openEditObjectDialog:e})=>{e(this._entryId,this._data.object),this.close()})}_onAddTask(){this._entryId&&Promise.resolve().then(()=>(B(),Q)).then(({openCreateTaskDialog:e})=>{e(),this.close()})}async _onDelete(){if(!this._entryId||!this._data)return;let e=r("delete_object_confirm",this._lang)||`Delete "${this._data.object.name}" and all its tasks?`;if(window.confirm(e)){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/delete",entry_id:this._entryId}),this.dispatchEvent(new CustomEvent("object-deleted",{detail:{entry_id:this._entryId},bubbles:!0,composed:!0})),this.close()}catch(t){this._error=P(t,this._lang)}finally{this._busy=!1}}}async _onArchiveObject(){if(!this._entryId||!this._data)return;let e=!!this._data.object.archived;if(!e){let t=r("confirm_archive_object",this._lang)||"Archive this object and its tasks?";if(!window.confirm(t))return}this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:e?"maintenance_supporter/object/unarchive":"maintenance_supporter/object/archive",entry_id:this._entryId}),this.dispatchEvent(new CustomEvent("object-changed",{detail:{entry_id:this._entryId},bubbles:!0,composed:!0})),this.close()}catch(t){this._error=P(t,this._lang)}finally{this._busy=!1}}_onTaskClick(e){this._entryId&&Promise.resolve().then(()=>(B(),Q)).then(({openTaskQuickActions:t})=>{t(this._entryId,e)})}render(){if(!this._open)return _;let e=this._lang,t=this._data,i=t?.object,n=t?.tasks||[],l=this.hass?.user?.is_admin??!0;return o`
|
||||
`],d([b({attribute:!1})],T.prototype,"hass",2),d([h()],T.prototype,"_open",2),d([h()],T.prototype,"_entryId",2),d([h()],T.prototype,"_taskId",2),d([h()],T.prototype,"_task",2),d([h()],T.prototype,"_objectName",2),d([h()],T.prototype,"_busy",2),d([h()],T.prototype,"_error",2),d([h()],T.prototype,"_showSkip",2),d([h()],T.prototype,"_showReset",2),d([h()],T.prototype,"_showDetails",2),d([h()],T.prototype,"_showAdaptive",2),d([h()],T.prototype,"_skipReason",2),d([h()],T.prototype,"_resetDate",2),d([h()],T.prototype,"_features",2),d([h()],T.prototype,"_toast",2);customElements.get("maintenance-task-quick-actions-dialog")||customElements.define("maintenance-task-quick-actions-dialog",T)});function Ti(a){return!!a&&/^https?:\/\//i.test(a)}var Ci=w(()=>{"use strict"});var W,Ii=w(()=>{"use strict";L();Ci();z();I();ne();W=class extends k{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._data=null;this._busy=!1;this._error=""}get _lang(){return N(this.hass)}async openFor(e){this._entryId=e,this._error="",this._open=!0,await this._load()}close(){this._open=!1,this._data=null,this._error=""}async _load(){if(this._entryId)try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId});this._data=e}catch(e){this._error=P(e,this._lang)}}_onEditObject(){!this._entryId||!this._data||Promise.resolve().then(()=>(B(),Q)).then(({openEditObjectDialog:e})=>{e(this._entryId,this._data.object),this.close()})}_onAddTask(){this._entryId&&Promise.resolve().then(()=>(B(),Q)).then(({openCreateTaskDialog:e})=>{e(),this.close()})}async _onDelete(){if(!this._entryId||!this._data)return;let e=r("delete_object_confirm",this._lang)||`Delete "${this._data.object.name}" and all its tasks?`;if(window.confirm(e)){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/delete",entry_id:this._entryId}),this.dispatchEvent(new CustomEvent("object-deleted",{detail:{entry_id:this._entryId},bubbles:!0,composed:!0})),this.close()}catch(t){this._error=P(t,this._lang)}finally{this._busy=!1}}}async _onArchiveObject(){if(!this._entryId||!this._data)return;let e=!!this._data.object.archived;if(!e){let t=r("confirm_archive_object",this._lang)||"Archive this object and its tasks?";if(!window.confirm(t))return}this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:e?"maintenance_supporter/object/unarchive":"maintenance_supporter/object/archive",entry_id:this._entryId}),this.dispatchEvent(new CustomEvent("object-changed",{detail:{entry_id:this._entryId},bubbles:!0,composed:!0})),this.close()}catch(t){this._error=P(t,this._lang)}finally{this._busy=!1}}_onTaskClick(e){this._entryId&&Promise.resolve().then(()=>(B(),Q)).then(({openTaskQuickActions:t})=>{t(this._entryId,e)})}render(){if(!this._open)return _;let e=this._lang,t=this._data,i=t?.object,n=t?.tasks||[],l=this.hass?.user?.is_admin??!0;return o`
|
||||
<div class="backdrop" @click=${this.close}></div>
|
||||
<div class="dialog" role="dialog" aria-modal="true">
|
||||
${t&&i?o`
|
||||
@@ -3752,7 +3788,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; }
|
||||
`,d([b({attribute:!1})],W.prototype,"hass",2),d([h()],W.prototype,"_open",2),d([h()],W.prototype,"_entryId",2),d([h()],W.prototype,"_data",2),d([h()],W.prototype,"_busy",2),d([h()],W.prototype,"_error",2);customElements.get("maintenance-object-quick-actions-dialog")||customElements.define("maintenance-object-quick-actions-dialog",W)});var Q={};Fi(Q,{openCompleteDialog:()=>Ws,openCreateObjectDialog:()=>gt,openCreateTaskDialog:()=>mt,openEditObjectDialog:()=>Us,openEditTaskDialog:()=>Vs,openHistoryEditDialog:()=>Bs,openObjectQuickActions:()=>Gs,openQrDialog:()=>Ks,openTaskQuickActions:()=>ft});function Ve(){return document.querySelector("home-assistant")?.hass}function Ds(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function J(a){let s=Ds(),e=s.querySelector(a)??document.body.querySelector(a);return e?e.parentNode!==s&&s.appendChild(e):(e=document.createElement(a),s.appendChild(e)),e}function Z(a){let s=Ve();if(!s)return!1;a.hass=s;let e=s.language||"en";return Me(e)||qe(e).then(()=>{a.requestUpdate?.()}),!0}function ji(a){return Ue||(Ue=a.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(s=>({features:s.features??Li.features,defaultWarningDays:s.general?.default_warning_days??7})).catch(()=>Li),Ue)}function gt(){let a=J(Pi);return Z(a)?(a.openCreate(),!0):!1}function Us(a,s){let e=J(Pi);return Z(e)?(e.openEdit(a,s),!0):!1}function mt(){let a=J(Ri);if(!Z(a))return!1;let s=Ve();return s?((async()=>{let e=await ji(s),t=a;t.checklistsEnabled=e.features.checklists,t.scheduleTimeEnabled=e.features.schedule_time,t.completionActionsEnabled=e.features.completion_actions,t.defaultWarningDays=e.defaultWarningDays,t.openCreate()})(),!0):!1}function Vs(a,s){let e=J(Ri);if(!Z(e))return!1;let t=Ve();return t?((async()=>{try{let[i,n]=await Promise.all([t.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:a}),ji(t)]),l=(i.tasks||[]).find(p=>p.id===s);if(!l){console.warn(`openEditTaskDialog: task ${s} not found in entry ${a}`);return}let c=e;c.checklistsEnabled=n.features.checklists,c.scheduleTimeEnabled=n.features.schedule_time,c.completionActionsEnabled=n.features.completion_actions,c.defaultWarningDays=n.defaultWarningDays,await c.openEdit(a,l)}catch(i){console.warn("openEditTaskDialog: failed to load task/features",i)}})(),!0):!1}function Bs(a){let s=J(Os);return Z(s)?(s.openEdit(a),!0):!1}function Ws(a){let s=J(Ms);return Z(s)?(s.entryId=a.entry_id,s.taskId=a.task_id,s.taskName=a.task_name,s.checklist=a.checklist??[],s.adaptiveEnabled=!!a.adaptive_enabled,s.requiredFields=a.required_completion_fields??[],s.lang=Ve()?.language||"en",s.open(),!0):!1}function Ks(a){let s=J(qs);return Z(s)?(s.openForTask(a.entry_id,a.task_id,a.object_name,a.task_name),!0):!1}function ft(a,s){let e=J(zs);return Z(e)?(e.openFor(a,s),!0):!1}function Gs(a){let s=J(Fs);return Z(s)?(s.openFor(a),!0):!1}var Pi,Ri,Os,Ms,qs,zs,Fs,Li,Ue,B=$(()=>{"use strict";li();_i();ct();ui();mi();Ai();Ii();I();Pi="maintenance-object-dialog",Ri="maintenance-task-dialog",Os="maintenance-history-edit-dialog",Ms="maintenance-complete-dialog",qs="maintenance-qr-dialog",zs="maintenance-task-quick-actions-dialog",Fs="maintenance-object-quick-actions-dialog";Li={features:{adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1},defaultWarningDays:7},Ue=null});L();var ts=["assignee_pool","required_completion_fields","checklist","labels","history"],is=["checklist_progress"],ss=["tasks","parts"],rs=["manual_docs","battery_fleet_excluded"];function rt(a,s,e=[]){for(let t of s)a[t]===void 0&&(a[t]=[]);for(let t of e)a[t]===void 0&&(a[t]={})}function as(a){let s=a;rt(s,ss),s.object&&typeof s.object=="object"&&rt(s.object,rs);for(let e of s.tasks)rt(e,ts,is);return a}function $e(a){for(let s of a)as(s);return a}function ns(a,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(a.map(n=>[n.entry_id,n]));for(let n of e)i.set(n.entry_id,n);for(let n of t)i.delete(n);return[...i.values()]}function qt(a,s){return s.objects&&$e(s.objects),s.delta&&$e(s.delta),ns(a,s)}z();I();async function us(a,s,e=300){return(await a.connection.sendMessagePromise({type:"auth/sign_path",path:s,expires:e})).path}async function gs(a,s,e=300){return us(a,`/api/maintenance_supporter/document/${s}`,e)}async function ri(a,s,e=""){let t=window.open("about:blank","_blank");try{let i=await gs(a,s);t&&(t.location.href=new URL(i+e,window.location.origin).href)}catch(i){throw t&&t.close(),i}}function ai(a){let s=window;s.customCards=s.customCards||[],s.customCards.some(e=>e.type===a.type)||s.customCards.push(a)}lt();Fe();L();z();I();var fs=["overdue","triggered","due_soon","ok"],V=class extends k{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-card"};this._objects=[];this._loadingObjects=!0;this._loadError=!1;this._views=[];this._objectsLoaded=!1;this._onEntiti
Line truncated
|
||||
`,d([b({attribute:!1})],W.prototype,"hass",2),d([h()],W.prototype,"_open",2),d([h()],W.prototype,"_entryId",2),d([h()],W.prototype,"_data",2),d([h()],W.prototype,"_busy",2),d([h()],W.prototype,"_error",2);customElements.get("maintenance-object-quick-actions-dialog")||customElements.define("maintenance-object-quick-actions-dialog",W)});var Q={};Fi(Q,{openCompleteDialog:()=>Ws,openCreateObjectDialog:()=>gt,openCreateTaskDialog:()=>mt,openEditObjectDialog:()=>Us,openEditTaskDialog:()=>Vs,openHistoryEditDialog:()=>Bs,openObjectQuickActions:()=>Gs,openQrDialog:()=>Ks,openTaskQuickActions:()=>ft});function Ve(){return document.querySelector("home-assistant")?.hass}function Ds(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function J(a){let s=Ds(),e=s.querySelector(a)??document.body.querySelector(a);return e?e.parentNode!==s&&s.appendChild(e):(e=document.createElement(a),s.appendChild(e)),e}function Z(a){let s=Ve();if(!s)return!1;a.hass=s;let e=s.language||"en";return Oe(e)||Me(e).then(()=>{a.requestUpdate?.()}),!0}function ji(a){return Ue||(Ue=a.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(s=>({features:s.features??Li.features,defaultWarningDays:s.general?.default_warning_days??7})).catch(()=>Li),Ue)}function gt(){let a=J(Pi);return Z(a)?(a.openCreate(),!0):!1}function Us(a,s){let e=J(Pi);return Z(e)?(e.openEdit(a,s),!0):!1}function mt(){let a=J(Ri);if(!Z(a))return!1;let s=Ve();return s?((async()=>{let e=await ji(s),t=a;t.checklistsEnabled=e.features.checklists,t.scheduleTimeEnabled=e.features.schedule_time,t.completionActionsEnabled=e.features.completion_actions,t.defaultWarningDays=e.defaultWarningDays,t.openCreate()})(),!0):!1}function Vs(a,s){let e=J(Ri);if(!Z(e))return!1;let t=Ve();return t?((async()=>{try{let[i,n]=await Promise.all([t.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:a}),ji(t)]),l=(i.tasks||[]).find(p=>p.id===s);if(!l){console.warn(`openEditTaskDialog: task ${s} not found in entry ${a}`);return}let c=e;c.checklistsEnabled=n.features.checklists,c.scheduleTimeEnabled=n.features.schedule_time,c.completionActionsEnabled=n.features.completion_actions,c.defaultWarningDays=n.defaultWarningDays,await c.openEdit(a,l)}catch(i){console.warn("openEditTaskDialog: failed to load task/features",i)}})(),!0):!1}function Bs(a){let s=J(qs);return Z(s)?(s.openEdit(a),!0):!1}function Ws(a){let s=J(Os);return Z(s)?(s.entryId=a.entry_id,s.taskId=a.task_id,s.taskName=a.task_name,s.checklist=a.checklist??[],s.adaptiveEnabled=!!a.adaptive_enabled,s.requiredFields=a.required_completion_fields??[],s.lang=Ve()?.language||"en",s.open(),!0):!1}function Ks(a){let s=J(Ms);return Z(s)?(s.openForTask(a.entry_id,a.task_id,a.object_name,a.task_name),!0):!1}function ft(a,s){let e=J(zs);return Z(e)?(e.openFor(a,s),!0):!1}function Gs(a){let s=J(Fs);return Z(s)?(s.openFor(a),!0):!1}var Pi,Ri,qs,Os,Ms,zs,Fs,Li,Ue,B=w(()=>{"use strict";li();_i();ct();ui();mi();Ai();Ii();I();Pi="maintenance-object-dialog",Ri="maintenance-task-dialog",qs="maintenance-history-edit-dialog",Os="maintenance-complete-dialog",Ms="maintenance-qr-dialog",zs="maintenance-task-quick-actions-dialog",Fs="maintenance-object-quick-actions-dialog";Li={features:{adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1},defaultWarningDays:7},Ue=null});L();var ts=["assignee_pool","required_completion_fields","checklist","labels","history"],is=["checklist_progress"],ss=["tasks","parts"],rs=["manual_docs","battery_fleet_excluded"];function rt(a,s,e=[]){for(let t of s)a[t]===void 0&&(a[t]=[]);for(let t of e)a[t]===void 0&&(a[t]={})}function as(a){let s=a;rt(s,ss),s.object&&typeof s.object=="object"&&rt(s.object,rs);for(let e of s.tasks)rt(e,ts,is);return a}function we(a){for(let s of a)as(s);return a}function ns(a,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(a.map(n=>[n.entry_id,n]));for(let n of e)i.set(n.entry_id,n);for(let n of t)i.delete(n);return[...i.values()]}function Mt(a,s){return s.objects&&we(s.objects),s.delta&&we(s.delta),ns(a,s)}z();I();async function us(a,s,e=300){return(await a.connection.sendMessagePromise({type:"auth/sign_path",path:s,expires:e})).path}async function gs(a,s,e=300){return us(a,`/api/maintenance_supporter/document/${s}`,e)}async function ri(a,s,e=""){let t=window.open("about:blank","_blank");try{let i=await gs(a,s);t&&(t.location.href=new URL(i+e,window.location.origin).href)}catch(i){throw t&&t.close(),i}}function ai(a){let s=window;s.customCards=s.customCards||[],s.customCards.some(e=>e.type===a.type)||s.customCards.push(a)}lt();Fe();L();z();I();var fs=["overdue","triggered","due_soon","ok"],V=class extends k{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-card"};this._objects=[];this._loadingObjects=!0;this._loadError=!1;this._views=[];this._objectsLoaded=!1;this._onEntiti
Line truncated
|
||||
<div class="editor">
|
||||
<ha-textfield
|
||||
label="${r("card_title",e)}"
|
||||
@@ -3985,7 +4021,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
font-size: 14px;
|
||||
max-width: 320px;
|
||||
}
|
||||
`,d([b({attribute:!1})],V.prototype,"hass",2),d([h()],V.prototype,"_config",2),d([h()],V.prototype,"_objects",2),d([h()],V.prototype,"_loadingObjects",2),d([h()],V.prototype,"_loadError",2),d([h()],V.prototype,"_views",2);customElements.get("maintenance-supporter-card-editor")||customElements.define("maintenance-supporter-card-editor",V);ct();B();var M=class extends k{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-card"};this._objects=[];this._stats=null;this._unsub=null;this._viewFilters=null;this._userNames={};this._userService=null;this._userNamesLoaded=!1;this._taskDocs={};this._docsLoadedFor=new Set;this._dataLoaded=!1;this._lastConnection=null;this._onCompleted=async()=>{await this._loadData()}}get _lang(){return N(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:["overdue","triggered","due_soon"],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){super.updated(e),e.has("hass")&&Zt(this.hass?.locale);let t=this.hass?.language;if(t&&!Me(t)&&qe(t).then(()=>this.requestUpdate()),this.hass&&!this._userNamesLoaded&&this._config.show_assignee!==!1&&this._objects.some(i=>i.tasks.some(n=>n.responsible_user_id))&&this._loadUserNames(),this.hass&&this._config.show_documents!==!1)for(let i of this._objects)this._docsLoadedFor.has(i.entry_id)||i.tasks.some(n=>(n.document_count??0)>0)&&this._loadDocuments(i.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(){try{let[e,t]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=$e(e.objects),this._stats=t}catch{}await this._loadViewFilters()}_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 pe(this.hass);try{let e=await this._userService.getUsers();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 n of t.documents||[])for(let l of n.task_ids||[])(i[l]||=[]).push({id:n.id,title:n.title,kind:n.kind,url:n.url});this._taskDocs={...this._taskDocs,[e]:i}}catch{}}_docsFor(e,t){if(this._config.show_documents===!1)return[];let n=[...this._taskDocs[e]?.[t.id]||[]];return t.documentation_url&&n.push({id:`url:${t.id}`,title:r("documentation_label",this._lang),kind:"weblink",url:t.documentation_url}),n}async _openDoc(e){if(e.kind==="weblink"&&e.url){window.open(e.url,"_blank","noopener");return}try{await ri(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=qt(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 _flatTasks(){let e=[],{filter_status:t,filter_objects:i,entity_ids:n,filter_due_min_days:l,filter_due_max_days:c,filter_labels:p,filter_areas:u,max_items:v}=this._config,f=n?.length?new Set(n):null,y=l!==void 0||c!==void 0,g=this._viewFilters,x=g?.user_id==="current_user"?this.hass.user?.id??null:g?.user_id??null;for(let j of this._objects)if(!(i?.length&&!i.includes(j.object.name))){if(u?.length){let S=j.object.area_id;if(!S||!u.includes(S))continue}for(let S of j.tasks)if(!S.is_done&&!(S.archived||j.object.archived)&&!(t?.length&&!t.includes(S.status))&&!(p?.length&&!(S.labels||[]).some(C=>p.includes(C)))&&!(f&&!(S.sensor_entity_id&&f.has(S.sensor_entity_id)||S.binary_sensor_entity_id&&f.has(S.binary_sensor_entity_id)))){if(y){let C=S.days_until_due;if(C==null||l!==void 0&&C<l||c!==void 0&&C>c)continue}g&&(g.status&&S.status!==g.status||g.label&&!(S.labels
Line truncated
|
||||
`,d([b({attribute:!1})],V.prototype,"hass",2),d([h()],V.prototype,"_config",2),d([h()],V.prototype,"_objects",2),d([h()],V.prototype,"_loadingObjects",2),d([h()],V.prototype,"_loadError",2),d([h()],V.prototype,"_views",2);customElements.get("maintenance-supporter-card-editor")||customElements.define("maintenance-supporter-card-editor",V);ct();B();var O=class extends k{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-card"};this._objects=[];this._stats=null;this._unsub=null;this._viewFilters=null;this._userNames={};this._userService=null;this._userNamesLoaded=!1;this._taskDocs={};this._docsLoadedFor=new Set;this._dataLoaded=!1;this._lastConnection=null;this._onCompleted=async()=>{await this._loadData()}}get _lang(){return N(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:["overdue","triggered","due_soon"],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){super.updated(e),e.has("hass")&&Zt(this.hass?.locale);let t=this.hass?.language;if(t&&!Oe(t)&&Me(t).then(()=>this.requestUpdate()),this.hass&&!this._userNamesLoaded&&this._config.show_assignee!==!1&&this._objects.some(i=>i.tasks.some(n=>n.responsible_user_id))&&this._loadUserNames(),this.hass&&this._config.show_documents!==!1)for(let i of this._objects)this._docsLoadedFor.has(i.entry_id)||i.tasks.some(n=>(n.document_count??0)>0)&&this._loadDocuments(i.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(){try{let[e,t]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects",compact:!0}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=we(e.objects),this._stats=t}catch{}await this._loadViewFilters()}_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 pe(this.hass);try{let e=await this._userService.getUsers();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 n of t.documents||[])for(let l of n.task_ids||[])(i[l]||=[]).push({id:n.id,title:n.title,kind:n.kind,url:n.url});this._taskDocs={...this._taskDocs,[e]:i}}catch{}}_docsFor(e,t){if(this._config.show_documents===!1)return[];let n=[...this._taskDocs[e]?.[t.id]||[]];return t.documentation_url&&n.push({id:`url:${t.id}`,title:r("documentation_label",this._lang),kind:"weblink",url:t.documentation_url}),n}async _openDoc(e){if(e.kind==="weblink"&&e.url){window.open(e.url,"_blank","noopener");return}try{await ri(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=Mt(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 _flatTasks(){let e=[],{filter_status:t,filter_objects:i,entity_ids:n,filter_due_min_days:l,filter_due_max_days:c,filter_labels:p,filter_areas:u,max_items:v}=this._config,f=n?.length?new Set(n):null,y=l!==void 0||c!==void 0,g=this._viewFilters,x=g?.user_id==="current_user"?this.hass.user?.id??null:g?.user_id??null;for(let j of this._objects)if(!(i?.length&&!i.includes(j.object.name))){if(u?.length){let S=j.object.area_id;if(!S||!u.includes(S))continue}for(let S of j.tasks)if(!S.is_done&&!(S.archived||j.object.archived)&&!(t?.length&&!t.includes(S.status))&&!(p?.length&&!(S.labels||[]).some(C=>p.includes(C)))&&!(f&&!(S.sensor_entity_id&&f.has(S.sensor_entity_id)||S.binary_sensor_entity_id&&f.has(S.binary_sensor_entity_id)))){if(y){let C=S.days_until_due;if(C==null||l!==void 0&&C<l||c!==void 0&&C>c)continue}g&&(g.status&&S.status!==g.status||g.label&&!(S.labels
Line truncated
|
||||
<ha-card>
|
||||
<div class="card-header">
|
||||
<h1>${t}</h1>
|
||||
@@ -4080,7 +4116,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
.hass=${this.hass}
|
||||
@task-completed=${this._onCompleted}
|
||||
></maintenance-complete-dialog>
|
||||
`}};M.styles=[ze,E`
|
||||
`}};O.styles=[ze,E`
|
||||
ha-card { overflow: hidden; }
|
||||
|
||||
.card-header {
|
||||
@@ -4212,7 +4248,7 @@ ${p?`<div class="sub">${p}</div>`:""}
|
||||
--mdc-icon-size: 18px;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
`],d([b({attribute:!1})],M.prototype,"hass",2),d([h()],M.prototype,"_config",2),d([h()],M.prototype,"_objects",2),d([h()],M.prototype,"_stats",2),d([h()],M.prototype,"_unsub",2),d([h()],M.prototype,"_viewFilters",2),d([h()],M.prototype,"_userNames",2),d([h()],M.prototype,"_taskDocs",2);customElements.get("maintenance-supporter-card")||customElements.define("maintenance-supporter-card",M);ai({type:"maintenance-supporter-card",name:"Maintenance Supporter",description:"Overview of your maintenance tasks with quick actions.",preview:!0});export{M as MaintenanceSupporterCard};
|
||||
`],d([b({attribute:!1})],O.prototype,"hass",2),d([h()],O.prototype,"_config",2),d([h()],O.prototype,"_objects",2),d([h()],O.prototype,"_stats",2),d([h()],O.prototype,"_unsub",2),d([h()],O.prototype,"_viewFilters",2),d([h()],O.prototype,"_userNames",2),d([h()],O.prototype,"_taskDocs",2);customElements.get("maintenance-supporter-card")||customElements.define("maintenance-supporter-card",O);ai({type:"maintenance-supporter-card",name:"Maintenance Supporter",description:"Overview of your maintenance tasks with quick actions.",preview:!0});export{O 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.58.0 */
|
||||
var S="2.58.0";var l="maintenance-supporter",T=`ll-strategy-dashboard-${l}`,D="hui-maintenance-supporter-strategy-editor",C=`/maintenance_supporter_strategy/maintenance-dashboard-strategy.js?v=${S}`,m=null;function v(){return m||(m=import(C)),m}async function I(){let r=await v();if(!r.MaintenanceDashboardStrategy)throw new Error("[maintenance-supporter] strategy bundle loaded but did not export MaintenanceDashboardStrategy");return r.MaintenanceDashboardStrategy}var p=class extends HTMLElement{static getCreateSuggestions(c){return{title:"Maintenance Supporter",icon:"mdi:wrench-clock"}}static async getConfigElement(){return await v(),document.createElement(D)}static async generate(c,f){return(await I()).generate(c,f)}};function M(){try{customElements.define(T,p)}catch{}}M();var w=window;w.customStrategies=w.customStrategies||[];w.customStrategies.some(r=>r.type===l&&r.strategyType==="dashboard")||w.customStrategies.push({type:l,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentationURL:"https://github.com/iluebbe/maintenance_supporter#dashboard-strategy"});(()=>{let r=window;if(r.__msStrategyHealActive)return;r.__msStrategyHealActive=!0;let c=/^\/(auth|config|developer-tools|profile|hassio|history|logbook|map|media-browser|energy|todo|calendar)\b/,f=/Timeout waiting for strategy element ll-strategy-(dashboard-)?maintenance-supporter/i,g=`custom:${l}`;function R(a){let t=[document.documentElement],n=0;for(;t.length&&n<9e3;){let o=t.pop();if(n++,!o)continue;let e=o;if(e.nodeType===1&&e.tagName&&e.tagName.toLowerCase()===a)return e;e.shadowRoot&&t.push(e.shadowRoot);let i=o.children;if(i)for(let d of Array.from(i))t.push(d)}return null}function k(a){let t=a?.views;if(!Array.isArray(t)||!t.length)return null;let n=window.location.pathname.split("/").filter(Boolean).pop()||"",o=t.find(i=>i?.path===n);if(o)return o;let e=Number(n);return Number.isInteger(e)&&t[e]?t[e]:t[0]}function b(){try{let t=R("ha-panel-lovelace")?.lovelace;if(!t)return!1;let n=o=>o?.type;for(let o of[t.config,t.rawConfig]){if(!o)continue;if(n(o.strategy)===g)return!0;let e=k(o);if(e&&n(e.strategy)===g)return!0}return!1}catch{return!1}}function A(){let a=!1,t=0,n=!1,o=!1,e=[document.documentElement],i=0;for(;e.length&&i<9e3;){let d=e.pop();if(i++,!d)continue;let u=d;if(u.nodeType===1&&u.tagName){let s=u.tagName.toLowerCase();(s==="hui-view"||s==="hui-sections-view")&&(a=!0),(s==="ha-card"||s==="hui-card")&&t++,s==="hui-empty-state-card"&&(o=!0),s==="hui-error-card"&&f.test(u.textContent||"")&&(n=!0)}u.shadowRoot&&e.push(u.shadowRoot);let E=d.children;if(E)for(let s of Array.from(E))e.push(s)}return n?!0:o?!1:a&&t<3&&b()}let N="/maintenance_supporter_strategy_shim.js",y=0,_=0;function L(){let a=Date.now();a-_<5e3||y>=3||(_=a,y+=1,import(`${N}?heal=${a}`).catch(()=>{}).finally(()=>{let t=window.location.pathname+window.location.search;history.pushState(null,"","/lovelace"),window.dispatchEvent(new CustomEvent("location-changed")),window.setTimeout(()=>{history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed"))},200)}))}function h(){if(c.test(window.location.pathname))return;let a=0,t=Date.now(),n=window.setInterval(()=>{a++;try{if(Date.now()-t<6e3)return;if(c.test(window.location.pathname)){window.clearInterval(n);return}A()?L():window.clearInterval(n),a>=30&&window.clearInterval(n)}catch{window.clearInterval(n)}},500)}try{document.readyState==="loading"?window.addEventListener("DOMContentLoaded",h):h(),window.addEventListener("location-changed",()=>{c.test(window.location.pathname)||h()})}catch{}})();
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
var S="2.59.0";var l="maintenance-supporter",T=`ll-strategy-dashboard-${l}`,D="hui-maintenance-supporter-strategy-editor",C=`/maintenance_supporter_strategy/maintenance-dashboard-strategy.js?v=${S}`,m=null;function v(){return m||(m=import(C)),m}async function I(){let r=await v();if(!r.MaintenanceDashboardStrategy)throw new Error("[maintenance-supporter] strategy bundle loaded but did not export MaintenanceDashboardStrategy");return r.MaintenanceDashboardStrategy}var p=class extends HTMLElement{static getCreateSuggestions(c){return{title:"Maintenance Supporter",icon:"mdi:wrench-clock"}}static async getConfigElement(){return await v(),document.createElement(D)}static async generate(c,f){return(await I()).generate(c,f)}};function M(){try{customElements.define(T,p)}catch{}}M();var w=window;w.customStrategies=w.customStrategies||[];w.customStrategies.some(r=>r.type===l&&r.strategyType==="dashboard")||w.customStrategies.push({type:l,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentationURL:"https://github.com/iluebbe/maintenance_supporter#dashboard-strategy"});(()=>{let r=window;if(r.__msStrategyHealActive)return;r.__msStrategyHealActive=!0;let c=/^\/(auth|config|developer-tools|profile|hassio|history|logbook|map|media-browser|energy|todo|calendar)\b/,f=/Timeout waiting for strategy element ll-strategy-(dashboard-)?maintenance-supporter/i,g=`custom:${l}`;function R(a){let t=[document.documentElement],n=0;for(;t.length&&n<9e3;){let o=t.pop();if(n++,!o)continue;let e=o;if(e.nodeType===1&&e.tagName&&e.tagName.toLowerCase()===a)return e;e.shadowRoot&&t.push(e.shadowRoot);let i=o.children;if(i)for(let d of Array.from(i))t.push(d)}return null}function k(a){let t=a?.views;if(!Array.isArray(t)||!t.length)return null;let n=window.location.pathname.split("/").filter(Boolean).pop()||"",o=t.find(i=>i?.path===n);if(o)return o;let e=Number(n);return Number.isInteger(e)&&t[e]?t[e]:t[0]}function b(){try{let t=R("ha-panel-lovelace")?.lovelace;if(!t)return!1;let n=o=>o?.type;for(let o of[t.config,t.rawConfig]){if(!o)continue;if(n(o.strategy)===g)return!0;let e=k(o);if(e&&n(e.strategy)===g)return!0}return!1}catch{return!1}}function A(){let a=!1,t=0,n=!1,o=!1,e=[document.documentElement],i=0;for(;e.length&&i<9e3;){let d=e.pop();if(i++,!d)continue;let u=d;if(u.nodeType===1&&u.tagName){let s=u.tagName.toLowerCase();(s==="hui-view"||s==="hui-sections-view")&&(a=!0),(s==="ha-card"||s==="hui-card")&&t++,s==="hui-empty-state-card"&&(o=!0),s==="hui-error-card"&&f.test(u.textContent||"")&&(n=!0)}u.shadowRoot&&e.push(u.shadowRoot);let E=d.children;if(E)for(let s of Array.from(E))e.push(s)}return n?!0:o?!1:a&&t<3&&b()}let N="/maintenance_supporter_strategy_shim.js",y=0,_=0;function L(){let a=Date.now();a-_<5e3||y>=3||(_=a,y+=1,import(`${N}?heal=${a}`).catch(()=>{}).finally(()=>{let t=window.location.pathname+window.location.search;history.pushState(null,"","/lovelace"),window.dispatchEvent(new CustomEvent("location-changed")),window.setTimeout(()=>{history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed"))},200)}))}function h(){if(c.test(window.location.pathname))return;let a=0,t=Date.now(),n=window.setInterval(()=>{a++;try{if(Date.now()-t<6e3)return;if(c.test(window.location.pathname)){window.clearInterval(n);return}A()?L():window.clearInterval(n),a>=30&&window.clearInterval(n)}catch{window.clearInterval(n)}},500)}try{document.readyState==="loading"?window.addEventListener("DOMContentLoaded",h):h(),window.addEventListener("location-changed",()=>{c.test(window.location.pathname)||h()})}catch{}})();
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a as m}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DZAYWHWN.js";import{a as d}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-7ZFDRUH2.js";import{a,b as _,c as t,f as l,g as h,i as g,j as n,n as i,o as v,q as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";var r=class extends h{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._adopting=!1;this._error="";this._sensors=[];this._selected=new Set;this._users=[];this._responsible="";this._localeReady=!1;this._userService=null;this._toggle=s=>{let o=new Set(this._selected);o.has(s)?o.delete(s):o.add(s),this._selected=o};this._toggleAll=()=>{this._selected.size===this._sensors.length?this._selected=new Set:this._selected=new Set(this._sensors.map(s=>s.entity_id))};this._adopt=async()=>{if(!(this._selected.size===0||this._adopting)){this._adopting=!0,this._error="";try{let s=this._sensors.filter(e=>this._selected.has(e.entity_id)).map(e=>({entity_id:e.entity_id,name:e.name,entry_id:e.suggested_entry_id??void 0,object_name:e.suggested_object_name,device_id:e.device_id??void 0,part_id:e.suggested_part_id??void 0,responsible_user_id:this._responsible||void 0})),o=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/problem_sensors/adopt",selections:s});this.dispatchEvent(new CustomEvent("problem-sensors-adopted",{bubbles:!0,composed:!0,detail:o})),this._open=!1}catch(s){this._error=d(s,this._lang)}finally{this._adopting=!1}}}}get _lang(){return v(this.hass)}updated(s){s.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,u(this._lang).then(()=>this.requestUpdate()))}async open(){this._open=!0,this._loading=!0,this._error="",this._sensors=[],this._selected=new Set,this._responsible="";try{this._userService?this._userService.updateHass(this.hass):this._userService=new m(this.hass);let[s,o]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/problem_sensors/discover"}),this._userService.getUsers().catch(()=>[])]);this._sensors=s.sensors||[],this._selected=new Set(this._sensors.map(e=>e.entity_id)),this._users=o}catch(s){this._error=d(s,this._lang)}finally{this._loading=!1}}_close(){this._open=!1}render(){if(!this._open)return t``;let s=this._lang,o=this._sensors.length>0&&this._selected.size===this._sensors.length;return t`
|
||||
<div class="overlay" @click=${this._close}>
|
||||
<div class="card" @click=${e=>e.stopPropagation()}>
|
||||
<div class="title">${i("adopt_problem_title",s)}</div>
|
||||
<div class="hint">${i("adopt_problem_hint",s)}</div>
|
||||
${this._error?t`<div class="error">${this._error}</div>`:l}
|
||||
|
||||
${this._loading?t`<div class="loading">…</div>`:this._sensors.length===0?t`<div class="empty">${i("adopt_problem_none",s)}</div>`:t`
|
||||
<label class="select-all">
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${o}
|
||||
@change=${this._toggleAll}
|
||||
/>
|
||||
<span>${i("selected",s)}: ${this._selected.size} / ${this._sensors.length}</span>
|
||||
</label>
|
||||
<div class="list">
|
||||
${this._sensors.map(e=>{let f=this._selected.has(e.entity_id),p=e.state==="on",c=[e.device_name,e.area_name].filter(Boolean).join(" \xB7 ");return t`
|
||||
<label class="row">
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${f}
|
||||
@change=${()=>this._toggle(e.entity_id)}
|
||||
/>
|
||||
<div class="row-main">
|
||||
<div class="row-top">
|
||||
<span class="row-name">${e.name}</span>
|
||||
<span class="chip ${p?"chip-active":"chip-ok"}">
|
||||
${p?i("adopt_problem_active",s):i("adopt_problem_ok",s)}
|
||||
</span>
|
||||
</div>
|
||||
${c?t`<div class="row-sub">${c}</div>`:l}
|
||||
<div class="row-target">
|
||||
→ ${e.suggested_object_name}${e.suggested_entry_id?l:t` <span class="new-tag">${i("adopt_problem_new_object",s)}</span>`}
|
||||
</div>
|
||||
${e.suggested_part_name?t`<div class="row-part">
|
||||
<ha-icon icon="mdi:package-variant-closed"></ha-icon>
|
||||
${i("adopt_problem_part",s).replace("{name}",e.suggested_part_name)}
|
||||
</div>`:l}
|
||||
</div>
|
||||
</label>
|
||||
`})}
|
||||
</div>
|
||||
`}
|
||||
|
||||
${!this._loading&&this._sensors.length>0&&this._users.length>0?t`
|
||||
<label class="responsible">
|
||||
<span>${i("adopt_problem_responsible",s)}</span>
|
||||
<select
|
||||
.value=${this._responsible}
|
||||
@change=${e=>{this._responsible=e.target.value}}
|
||||
>
|
||||
<option value="" ?selected=${!this._responsible}>${i("no_user_assigned",s)}</option>
|
||||
${this._users.map(e=>t`<option value=${e.id} ?selected=${e.id===this._responsible}>${e.name}</option>`)}
|
||||
</select>
|
||||
</label>
|
||||
`:l}
|
||||
|
||||
<div class="actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${i("cancel",s)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._adopt}
|
||||
.disabled=${this._selected.size===0||this._adopting}
|
||||
>
|
||||
${i("adopt_problem_adopt",s)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`}};r.styles=_`
|
||||
.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
min-width: min(360px, calc(100vw - 24px));
|
||||
max-width: 560px;
|
||||
width: 90vw;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.hint {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 13px;
|
||||
}
|
||||
.error {
|
||||
color: var(--error-color, #f44336);
|
||||
font-size: 13px;
|
||||
}
|
||||
.loading,
|
||||
.empty {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 14px;
|
||||
padding: 12px 0;
|
||||
}
|
||||
.select-all {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
.select-all input {
|
||||
cursor: pointer;
|
||||
}
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
overflow-y: auto;
|
||||
max-height: 50vh;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.row input {
|
||||
margin-top: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.row-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
.row-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.row-name {
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
}
|
||||
.row-sub {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
}
|
||||
.row-target {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
}
|
||||
.row-part {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.row-part ha-icon {
|
||||
--mdc-icon-size: 14px;
|
||||
}
|
||||
.new-tag {
|
||||
font-style: italic;
|
||||
}
|
||||
.chip {
|
||||
font-size: 11px;
|
||||
padding: 1px 8px;
|
||||
border-radius: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.chip-active {
|
||||
background: var(--error-color, #f44336);
|
||||
color: #fff;
|
||||
}
|
||||
.chip-ok {
|
||||
background: var(--divider-color);
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.responsible {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.responsible select {
|
||||
flex: 1;
|
||||
min-width: 140px;
|
||||
padding: 4px 6px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--divider-color);
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
font-size: 13px;
|
||||
}
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
`,a([g({attribute:!1})],r.prototype,"hass",2),a([n()],r.prototype,"_open",2),a([n()],r.prototype,"_loading",2),a([n()],r.prototype,"_adopting",2),a([n()],r.prototype,"_error",2),a([n()],r.prototype,"_sensors",2),a([n()],r.prototype,"_selected",2),a([n()],r.prototype,"_users",2),a([n()],r.prototype,"_responsible",2);customElements.get("maintenance-adopt-problem-sensors-dialog")||customElements.define("maintenance-adopt-problem-sensors-dialog",r);export{r as MaintenanceAdoptProblemSensorsDialog};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{n as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";var s={name:"name",task_type:"maintenance_type",schedule_type:"schedule_type",interval_days:"interval_days",interval_anchor:"interval_anchor",warning_days:"warning_days",last_performed:"last_performed_optional",notes:"notes_optional",documentation_url:"documentation_url_optional",custom_icon:"custom_icon_optional",nfc_tag_id:"nfc_tag_id_optional",responsible_user_id:"responsible_user",entity_slug:"entity_slug",entity_id:"entity_id",area_id:"area_id_optional",manufacturer:"manufacturer_optional",model:"model_optional",serial_number:"serial_number_optional",installation_date:"installation_date_optional",warranty_expiry:"warranty_expiry_optional",checklist:"checklist_steps_optional",reason:"reason",feedback:"feedback",cost:"cost",duration:"duration",description:"description_optional",group_name:"name",group_description:"description_optional",environmental_entity:"environmental_entity_optional",environmental_attribute:"environmental_attribute_optional",trigger_above:"trigger_above",trigger_below:"trigger_below",trigger_equals:"trigger_equals",trigger_not_equals:"trigger_not_equals",trigger_for_minutes:"trigger_for_minutes"};function c(r,o){let e=s[r];if(!e)return r;let t=a(e,o);return t&&t!==e?t:r}function d(r){let e=r.match(/data\['([^']+)'\]/)?.[1],t;return(t=r.match(/length of value must be at most (\d+)/))?{field:e,rule:"too_long",param:t[1]}:(t=r.match(/length of value must be at least (\d+)/))?{field:e,rule:"too_short",param:t[1]}:(t=r.match(/value must be at most (\S+)/))?{field:e,rule:"value_too_high",param:t[1]}:(t=r.match(/value must be at least (\S+)/))?{field:e,rule:"value_too_low",param:t[1]}:/required key not provided/.test(r)?{field:e,rule:"required"}:(t=r.match(/expected (\w+)/))?{field:e,rule:"wrong_type",param:t[1]}:/value must be one of/.test(r)?{field:e,rule:"invalid_choice"}:/not a valid value/.test(r)?{field:e,rule:"invalid_value"}:{field:e,rule:"unknown"}}function g(r,o,e){if(e=e??a("action_error",o),typeof r=="string")return r;if(typeof r!="object"||r===null)return e;let t=r,_=t.message||t.error?.message||"";if(!_)return e;let i=d(_),l=i.field?c(i.field,o):"",n=u=>a(u,o).replace("{field}",l).replace("{n}",i.param??"");switch(i.rule){case"too_long":return n("err_too_long");case"too_short":return n("err_too_short");case"value_too_high":return n("err_value_too_high");case"value_too_low":return n("err_value_too_low");case"required":return n("err_required");case"wrong_type":return n("err_wrong_type").replace("{type}",i.param??"");case"invalid_choice":return n("err_invalid_choice");case"invalid_value":return n("err_invalid_value");default:return _||e}}export{g as a};
|
||||
@@ -0,0 +1,299 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a as _,e as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-FMV3K4OT.js";import{a as g}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-7ZFDRUH2.js";import{a as s,b,c as a,f as d,g as v,i as n,j as l,n as r,z as m}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";var i=class extends v{constructor(){super(...arguments);this.entryId="";this.taskId="";this.taskName="";this.lang="en";this.checklist=[];this.adaptiveEnabled=!1;this.taskType="";this.readingUnit="";this.restockDefault=null;this.restockUnitCost=null;this.currencySymbol="";this.parts=[];this.consumesParts=[];this.consumesInfo=[];this.requiredFields=[];this._open=!1;this._notes="";this._cost="";this._duration="";this._loading=!1;this._error="";this._checklistState={};this._feedback="needed";this._photoDocId="";this._photoPreview="";this._photoUploading=!1;this._readingValue="";this._restockQty="";this._completedAt="";this._usedParts={};this.checklistPrefill={}}open(){this._open||(this._open=!0,this._notes="",this._cost="",this._duration="",this._error="",this._checklistState=Object.fromEntries(this.checklist.map((e,t)=>[String(t),!!this.checklistPrefill[e]]).filter(([,e])=>e)),this._feedback="needed",this._photoDocId="",this._photoPreview="",this._photoUploading=!1,this._readingValue="",this._restockQty=this.restockDefault!==null?String(this.restockDefault):"",this._completedAt="",this._usedParts=Object.fromEntries(this.consumesParts.map(e=>[_(e),{...e}])))}_toggleCheck(e){let t=String(e);this._checklistState={...this._checklistState,[t]:!this._checklistState[t]}}_setFeedback(e){this._feedback=e}async _onPhotoInput(e){let t=e.target,o=t.files?.[0];if(t.value="",!!o){this._photoUploading=!0,this._error="";try{let c=new FormData;c.append("entry_id",this.entryId),c.append("tags","photo"),c.append("file",o,o.name);let p=await fetch("/api/maintenance_supporter/document/upload",{method:"POST",headers:{Authorization:`Bearer ${this.hass.auth?.data?.access_token??""}`},body:c});if(!p.ok){this._error=p.status===413?r("doc_too_large",this.lang):r("doc_upload_failed",this.lang);return}let u=await p.json();u.id&&(this._photoDocId=u.id,this._photoPreview=URL.createObjectURL(o))}catch{this._error=r("doc_upload_failed",this.lang)}finally{this._photoUploading=!1}}}_removePhoto(){this._photoPreview&&URL.revokeObjectURL(this._photoPreview),this._photoDocId="",this._photoPreview=""}async _complete(){this._loading=!0,this._error="";try{let e={type:"maintenance_supporter/task/complete",entry_id:this.entryId,task_id:this.taskId};if(this._notes&&(e.notes=this._notes),this._cost){let t=parseFloat(this._cost);!isNaN(t)&&t>=0&&(e.cost=t)}if(this._duration){let t=parseInt(this._duration,10);!isNaN(t)&&t>=0&&(e.duration=t)}if(this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photoDocId&&(e.photo_doc_id=this._photoDocId),this._completedAt){if(new Date(this._completedAt).getTime()>Date.now()){this._error=r("completed_at_future_error",this.lang),this._loading=!1;return}e.completed_at=this._completedAt.length===16?`${this._completedAt}:00`:this._completedAt}if(this._readingValue!==""){let t=parseFloat(this._readingValue);isNaN(t)||(e.reading_value=t)}if(this.restockDefault!==null&&this._restockQty!==""){let t=parseFloat(this._restockQty);!isNaN(t)&&t>=1&&(e.restock_quantity=t)}this.parts.length>0&&(e.used_parts=Object.values(this._usedParts).filter(t=>Number.isFinite(t.quantity)&&t.quantity>0).map(t=>t.entry_id?{part_id:t.part_id,quantity:t.quantity,entry_id:t.entry_id}:{part_id:t.part_id,quantity:t.quantity})),await this.hass.connection.sendMessagePromise(e),this._open=!1,this.dispatchEvent(new CustomEvent("task-completed"))}catch(e){this._error=g(e,this.lang,r("save_error",this.lang))}finally{this._loading=!1}}get _missingRequired(){let e={notes:this._notes.trim()!=="",cost:this._cost.trim()!=="",duration:this._duration.trim()!=="",photo:this._photoDocId!=="",user:!!this.hass?.user};return this.requiredFields.filter(t=>!e[t])}_req(e){return this.requiredFields.includes(e)?a`<span class="req-mark" aria-hidden="true">*</span>`:d}_partsCostSuggestion(){if(this.restockDefault!==null){let o=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(o)||o<=0?null:Math.round(this.restockUnitCost*o*100)/100}if(!this.parts.length)return null;let e=0,t=!1;for(let o of Object.values(this._usedParts)){let c=this.parts.find(p=>_({part_id:p.id,entry_id:p.entry_id})===_(o));c?.cost!=null&&(e+=c.cost*(o.quantity||1),t=!0)}return t?Math.round(e*100)/100:null}_renderCostSuggestion(e){if(this._cost.trim()!=="")return d;let t=this._partsCostSuggestion();if(t==null||t<=0)return d;let o=`${t.toFixed(2)}${this.currencySymbol?` ${this.currencySymbol}`:""}`;return a`<button
|
||||
type="button"
|
||||
class="cost-suggestion"
|
||||
@click=${()=>this._cost=t.toFixed(2)}
|
||||
>${r("cost_from_parts",e).replace("{amount}",o)}</button>`}_close(){this._open=!1}render(){if(!this._open)return a``;let e=this.lang||this.hass?.language||"en";return a`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${r("complete_title",e)}${this.taskName}</div>
|
||||
<div class="content">
|
||||
${this._error?a`<div class="error">${this._error}</div>`:d}
|
||||
${this.checklist.length>0?a`
|
||||
<div class="checklist-section">
|
||||
<label class="checklist-label">${r("checklist",e)}</label>
|
||||
${this.checklist.map((t,o)=>a`
|
||||
<label class="checklist-item" @click=${()=>this._toggleCheck(o)}>
|
||||
<input type="checkbox" .checked=${!!this._checklistState[String(o)]} />
|
||||
<span>${t}</span>
|
||||
</label>
|
||||
`)}
|
||||
</div>
|
||||
`:d}
|
||||
${this.taskType==="reading"?a`
|
||||
<label class="field">
|
||||
<span class="field-label">${r("reading_value_label",e)}${this.readingUnit?` (${this.readingUnit})`:""}</span>
|
||||
<input type="number" step="any" class="field-input"
|
||||
.value=${this._readingValue}
|
||||
@input=${t=>this._readingValue=t.target.value} />
|
||||
</label>`:d}
|
||||
${this.parts.length?a`<div class="used-parts">
|
||||
<span class="field-label">${r("complete_parts_used",e)}</span>
|
||||
${this.parts.map(t=>{let o=_({part_id:t.id,entry_id:t.entry_id}),c=this._usedParts[o],p=c!==void 0,u=t.entry_id?{part_id:t.id,quantity:1,entry_id:t.entry_id}:{part_id:t.id,quantity:1};return a`<div class="used-part-row">
|
||||
<label class="used-part-check">
|
||||
<input type="checkbox" .checked=${p}
|
||||
@change=${f=>{let h={...this._usedParts};f.target.checked?h[o]=h[o]||u:delete h[o],this._usedParts=h}} />
|
||||
<span
|
||||
>${t.name}${t.owner_name?a`<span class="used-part-owner"> (${t.owner_name})</span>`:d}${t.stock!==null&&t.stock!==void 0?` (${t.stock}${t.unit?" "+t.unit:""})`:""}</span
|
||||
>
|
||||
</label>
|
||||
${p?a`<input class="used-part-qty" type="number" min="0.01" max="999" step="0.01"
|
||||
.value=${String(c.quantity)}
|
||||
@input=${f=>{let h=parseFloat(f.target.value);this._usedParts={...this._usedParts,[o]:{...u,quantity:Number.isFinite(h)&&h>=.01?h:1}}}} />`:d}
|
||||
</div>`})}
|
||||
</div>`:this.consumesInfo.length?a`<div class="consumes-hint">
|
||||
${this.consumesInfo.map(t=>a`<div>${t}</div>`)}
|
||||
</div>`:d}
|
||||
${this.restockDefault!==null?a`
|
||||
<label class="field">
|
||||
<span class="field-label">${r("restock_quantity_label",e)}</span>
|
||||
<input type="number" step="0.01" min="0.01" class="field-input"
|
||||
.value=${this._restockQty}
|
||||
@input=${t=>this._restockQty=t.target.value} />
|
||||
</label>`:d}
|
||||
<!-- Native <input>s rather than <ha-textfield>: when this dialog
|
||||
is opened from a Lovelace card via dialog-mount, ha-textfield
|
||||
isn't yet registered (HA loads it lazily when its own panels
|
||||
need it) so the elements render with zero height and the user
|
||||
only sees the title + Cancel/Complete buttons — the original
|
||||
bug report. Native inputs always render. -->
|
||||
<label class="field">
|
||||
<span class="field-label">${r("notes_optional",e)}${this._req("notes")}</span>
|
||||
<input type="text" class="field-input"
|
||||
.value=${this._notes}
|
||||
@input=${t=>this._notes=t.target.value} />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span class="field-label">${r("cost_optional",e)}${this._req("cost")}</span>
|
||||
<input type="number" step="0.01" min="0" class="field-input"
|
||||
.value=${this._cost}
|
||||
@input=${t=>this._cost=t.target.value} />
|
||||
${this._renderCostSuggestion(e)}
|
||||
</label>
|
||||
<label class="field">
|
||||
<span class="field-label">${r("duration_minutes",e)}${this._req("duration")}</span>
|
||||
<input type="number" step="0.01" min="0" class="field-input"
|
||||
.value=${this._duration}
|
||||
@input=${t=>this._duration=t.target.value} />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span class="field-label">${r("completed_at_optional",e)}</span>
|
||||
<input type="datetime-local" class="field-input"
|
||||
max=${new Date(Date.now()-new Date().getTimezoneOffset()*6e4).toISOString().slice(0,16)}
|
||||
.value=${this._completedAt}
|
||||
@change=${t=>this._completedAt=t.target.value} />
|
||||
</label>
|
||||
<div class="field">
|
||||
<span class="field-label">${r("completion_photo_optional",e)}${this._req("photo")}</span>
|
||||
${this._photoPreview?a`
|
||||
<div class="photo-preview">
|
||||
<img src=${this._photoPreview} alt="" />
|
||||
<button type="button" class="photo-remove" @click=${this._removePhoto}
|
||||
title="${r("remove",e)}">✕</button>
|
||||
</div>`:a`
|
||||
<label class="photo-pick">
|
||||
<ha-icon icon="mdi:camera"></ha-icon>
|
||||
<span>${this._photoUploading?r("uploading",e):r("add_photo",e)}</span>
|
||||
<input type="file" accept="image/*" capture="environment"
|
||||
?disabled=${this._photoUploading}
|
||||
@change=${this._onPhotoInput} />
|
||||
</label>`}
|
||||
</div>
|
||||
${this.adaptiveEnabled?a`
|
||||
<div class="feedback-section">
|
||||
<label class="feedback-label">${r("was_maintenance_needed",e)}</label>
|
||||
<div class="feedback-buttons">
|
||||
<button
|
||||
class="feedback-btn ${this._feedback==="needed"?"selected":""}"
|
||||
@click=${()=>this._setFeedback("needed")}
|
||||
>${r("feedback_needed",e)}</button>
|
||||
<button
|
||||
class="feedback-btn ${this._feedback==="not_needed"?"selected":""}"
|
||||
@click=${()=>this._setFeedback("not_needed")}
|
||||
>${r("feedback_not_needed",e)}</button>
|
||||
<button
|
||||
class="feedback-btn ${this._feedback==="not_sure"?"selected":""}"
|
||||
@click=${()=>this._setFeedback("not_sure")}
|
||||
>${r("feedback_not_sure",e)}</button>
|
||||
</div>
|
||||
</div>
|
||||
`:d}
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${r("cancel",e)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._complete}
|
||||
.disabled=${this._loading||this._missingRequired.length>0}
|
||||
title=${this._missingRequired.length?this._missingRequired.map(t=>r("err_required",e).replace("{field}",r(k[t]??t,e))).join(" \xB7 "):""}
|
||||
>
|
||||
${this._loading?r("completing",e):r("complete",e)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`}};i.styles=[m,b`
|
||||
.req-mark {
|
||||
color: var(--error-color, #f44336);
|
||||
margin-left: 2px;
|
||||
font-weight: 600;
|
||||
}
|
||||
/* #104: one-click cost suggestion from parts — quiet link-style chip. */
|
||||
.cost-suggestion {
|
||||
align-self: flex-start;
|
||||
margin-top: 4px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--primary-color);
|
||||
font-size: 12.5px;
|
||||
cursor: pointer;
|
||||
text-decoration: underline dotted;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
.dialog-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
min-width: 300px;
|
||||
}
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
.consumes-hint {
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
border-left: 3px solid var(--primary-color);
|
||||
padding: 4px 8px;
|
||||
margin: 4px 0 8px;
|
||||
}
|
||||
/* #99: editable per-completion parts selection */
|
||||
.used-parts { margin: 4px 0 8px; display: flex; flex-direction: column; gap: 4px; }
|
||||
.used-part-row { display: flex; align-items: center; gap: 8px; }
|
||||
.used-part-check {
|
||||
display: flex; align-items: center; gap: 6px; flex: 1;
|
||||
font-size: 13px; cursor: pointer;
|
||||
}
|
||||
.used-part-check input { cursor: pointer; }
|
||||
/* #111: whose stock this row draws on. Muted but never omitted — an
|
||||
unlabelled foreign pool is indistinguishable from an own part. */
|
||||
.used-part-owner { color: var(--secondary-text-color); }
|
||||
.used-part-qty {
|
||||
width: 76px; padding: 4px 6px; border-radius: 4px; font: inherit; font-size: 13px;
|
||||
border: 1px solid var(--divider-color);
|
||||
background: var(--card-background-color);
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.error {
|
||||
color: var(--error-color, #f44336);
|
||||
font-size: 13px;
|
||||
}
|
||||
/* .field/.field-label/.field-input come from nativeFieldStyles */
|
||||
.photo-pick {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
border: 1px dashed var(--divider-color);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
width: fit-content;
|
||||
}
|
||||
.photo-pick:hover { border-color: var(--primary-color); }
|
||||
.photo-pick input[type="file"] { display: none; }
|
||||
.photo-preview {
|
||||
position: relative;
|
||||
width: fit-content;
|
||||
}
|
||||
.photo-preview img {
|
||||
max-width: 160px;
|
||||
max-height: 160px;
|
||||
border-radius: 8px;
|
||||
display: block;
|
||||
}
|
||||
.photo-remove {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
background: var(--error-color, #db4437);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
.checklist-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.checklist-label {
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.checklist-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
padding: 4px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
.checklist-item input[type="checkbox"] {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.feedback-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 8px 0;
|
||||
border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
.feedback-label {
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.feedback-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.feedback-btn {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 8px;
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.feedback-btn:hover {
|
||||
background: var(--secondary-background-color, #f5f5f5);
|
||||
}
|
||||
.feedback-btn.selected {
|
||||
background: var(--primary-color);
|
||||
color: var(--text-primary-color, #fff);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
`],s([n({attribute:!1})],i.prototype,"hass",2),s([n()],i.prototype,"entryId",2),s([n()],i.prototype,"taskId",2),s([n()],i.prototype,"taskName",2),s([n()],i.prototype,"lang",2),s([n({type:Array})],i.prototype,"checklist",2),s([n({type:Boolean})],i.prototype,"adaptiveEnabled",2),s([n()],i.prototype,"taskType",2),s([n()],i.prototype,"readingUnit",2),s([n({attribute:!1})],i.prototype,"restockDefault",2),s([n({attribute:!1})],i.prototype,"restockUnitCost",2),s([n()],i.prototype,"currencySymbol",2),s([n({attribute:!1})],i.prototype,"parts",2),s([n({attribute:!1})],i.prototype,"consumesParts",2),s([n({type:Array})],i.prototype,"consumesInfo",2),s([n({type:Array})],i.prototype,"requiredFields",2),s([l()],i.prototype,"_open",2),s([l()],i.prototype,"_notes",2),s([l()],i.prototype,"_cost",2),s([l()],i.prototype,"_duration",2),s([l()],i.prototype,"_loading",2),s([l()],i.prototype,"_error",2),s([l()],i.prototype,"_checklistState",2),s([l()],i.prototype,"_feedback",2),s([l()],i.prototype,"_photoDocId",2),s([l()],i.prototype,"_photoPreview",2),s([l()],i.prototype,"_photoUploading",2),s([l()],i.prototype,"_readingValue",2),s([l()],i.prototype,"_restockQty",2),s([l()],i.prototype,"_completedAt",2),s([l()],i.prototype,"_usedParts",2),s([n({attribute:!1})],i.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",i);export{i as a};
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
var r=class{constructor(s){this.usersCache=null;this.cacheTimestamp=0;this.CACHE_TTL_MS=6e4;this.hass=s}updateHass(s){this.hass=s}async getUsers(s=!1){let e=Date.now();if(!s&&this.usersCache&&e-this.cacheTimestamp<this.CACHE_TTL_MS)return this.usersCache;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/users/list"});return this.usersCache=t.users,this.cacheTimestamp=e,this.usersCache}catch(t){return console.error("Failed to fetch users:",t),this.usersCache||[]}}async assignUser(s,e,t){await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/assign_user",entry_id:s,task_id:e,user_id:t})}async getTasksByUser(s){return(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/tasks/by_user",user_id:s})).tasks}getUserName(s){return!s||!this.usersCache?null:this.usersCache.find(t=>t.id===s)?.name||null}getUser(s){return!s||!this.usersCache?null:this.usersCache.find(e=>e.id===s)||null}getCurrentUserId(){return this.hass.user?.id||null}isCurrentUser(s){return s?s===this.getCurrentUserId():!1}clearCache(){this.usersCache=null,this.cacheTimestamp=0}};export{r as a};
|
||||
@@ -0,0 +1,213 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a,b as v,c as n,f as g,g as b,i as m,j as c,n as t}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";function p(l){return l.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function x(l){return!l.startsWith("data:image/svg+xml,")&&!l.startsWith("data:image/png;base64,")?"":p(l)}function $(l){return l.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var r=class extends b{constructor(){super(...arguments);this.lang="en";this._open=!1;this._loading=!1;this._error="";this._viewResult=null;this._completeResult=null;this._urlMode="companion";this._entryId="";this._taskId=null;this._objectName="";this._taskName="";this._generateSeq=0}openForObject(e,i){this._entryId=e,this._taskId=null,this._objectName=i,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._open=!0,this._generate()}openForTask(e,i,o,s){this._entryId=e,this._taskId=i,this._objectName=o,this._taskName=s,this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._open=!0,this._generate()}async _generate(){let e=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=null;try{let i={type:"maintenance_supporter/qr/generate",entry_id:this._entryId,url_mode:this._urlMode};this._taskId&&(i.task_id=this._taskId);let o=[this.hass.connection.sendMessagePromise({...i,action:"view"})];this._taskId&&o.push(this.hass.connection.sendMessagePromise({...i,action:"complete"}));let s=await Promise.all(o);if(e!==this._generateSeq)return;this._viewResult=s[0],s.length>1&&(this._completeResult=s[1])}catch(i){if(e!==this._generateSeq)return;let o=i?.code,s=i?.message;this._error=o==="no_url"||typeof s=="string"&&s.includes("No Home Assistant URL")?t("qr_error_no_url",this.lang):t("qr_error",this.lang)}finally{e===this._generateSeq&&(this._loading=!1)}}_setUrlMode(e){this._urlMode!==e&&(this._urlMode=e,this._generate())}_print(){if(!this._viewResult)return;let e=this._viewResult,i=e.label.task_name?`${e.label.object_name} \u2014 ${e.label.task_name}`:e.label.object_name,o=[e.label.manufacturer,e.label.model].filter(Boolean).join(" "),s=window.open("","_blank","width=600,height=500");if(!s)return;let h=this.lang||"en",d=p(i),u=p(o),_=!!this._completeResult,f=p(t("qr_action_view",h)),w=p(t("qr_action_complete",h));s.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
||||
<meta name="color-scheme" content="light">
|
||||
<title>${d}</title>
|
||||
<style>
|
||||
/* Printable sheet \u2014 must not inherit the phone's dark theme. The QR images
|
||||
carry their own white quiet zone and stay scannable either way, but the
|
||||
labels below are explicit dark greys and would vanish on a WebView's dark
|
||||
canvas. Same reasoning as helpers/report.ts. */
|
||||
:root{color-scheme:light}
|
||||
body{font-family:sans-serif;text-align:center;padding:20px;background:#fff;color:#1a1a1a}
|
||||
h2{margin:0 0 4px}
|
||||
.sub{color:#666;font-size:14px;margin-bottom:16px}
|
||||
.qr-row{display:flex;justify-content:center;gap:24px;margin:12px 0}
|
||||
.qr-col{display:flex;flex-direction:column;align-items:center;gap:6px}
|
||||
.qr-col img{width:${_?"200px":"280px"}}
|
||||
.qr-label{font-size:13px;font-weight:500;color:#333}
|
||||
.url{font-size:10px;color:#999;word-break:break-all;margin-top:8px;max-width:480px}
|
||||
</style></head><body>
|
||||
<h2>${d}</h2>
|
||||
${u?`<div class="sub">${u}</div>`:""}
|
||||
<div class="qr-row">
|
||||
<div class="qr-col">
|
||||
<img src="${x(this._viewResult.svg_data_uri)}" alt="QR Info" />
|
||||
<div class="qr-label">${f}</div>
|
||||
</div>
|
||||
${_?`<div class="qr-col">
|
||||
<img src="${x(this._completeResult.svg_data_uri)}" alt="QR Complete" />
|
||||
<div class="qr-label">${w}</div>
|
||||
</div>`:""}
|
||||
</div>
|
||||
<div class="url">${p(this._viewResult.url)}</div>
|
||||
<script>setTimeout(()=>window.print(),300)<\/script>
|
||||
</body></html>`),s.document.close()}_downloadSvg(e,i){let o=decodeURIComponent(e.svg_data_uri.replace("data:image/svg+xml,","")),s=new Blob([o],{type:"image/svg+xml"}),h=URL.createObjectURL(s),d=document.createElement("a");d.href=h;let u=this._taskName?`${this._objectName}-${this._taskName}`:this._objectName;d.download=`qr-${$(u)}-${i}.svg`,d.click(),URL.revokeObjectURL(h)}_close(){this._open=!1,this._viewResult=null,this._completeResult=null,this._error="",this._loading=!1}render(){if(!this._open)return n``;let e=this.lang||this.hass?.language||"en",i=this._taskName?`${t("qr_code",e)}: ${this._objectName} \u2014 ${this._taskName}`:`${t("qr_code",e)}: ${this._objectName}`,o=!!this._viewResult;return n`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${i}</div>
|
||||
<div class="content">
|
||||
${this._loading?n`<div class="loading">${t("qr_generating",e)}</div>`:this._error?n`<div class="error">${this._error}</div>`:o?n`
|
||||
<div class="qr-pair">
|
||||
<div class="qr-item">
|
||||
<img
|
||||
class="qr-image ${this._completeResult?"small":""}"
|
||||
src="${this._viewResult.svg_data_uri}"
|
||||
alt="QR Info"
|
||||
/>
|
||||
<div class="qr-item-label">${t("qr_action_view",e)}</div>
|
||||
<button class="dl-btn"
|
||||
@click=${()=>this._downloadSvg(this._viewResult,"info")}>
|
||||
<ha-icon icon="mdi:download"></ha-icon>
|
||||
${t("qr_download",e)}
|
||||
</button>
|
||||
</div>
|
||||
${this._completeResult?n`
|
||||
<div class="qr-item">
|
||||
<img
|
||||
class="qr-image small"
|
||||
src="${this._completeResult.svg_data_uri}"
|
||||
alt="QR Complete"
|
||||
/>
|
||||
<div class="qr-item-label">${t("qr_action_complete",e)}</div>
|
||||
<button class="dl-btn"
|
||||
@click=${()=>this._downloadSvg(this._completeResult,"complete")}>
|
||||
<ha-icon icon="mdi:download"></ha-icon>
|
||||
${t("qr_download",e)}
|
||||
</button>
|
||||
</div>
|
||||
`:g}
|
||||
</div>
|
||||
<div class="url-display">${this._viewResult.url}</div>
|
||||
`:g}
|
||||
<div class="action-row">
|
||||
<label>${t("qr_url_mode",e)}</label>
|
||||
<div class="action-toggle">
|
||||
<button class="toggle-btn ${this._urlMode==="companion"?"active":""}"
|
||||
@click=${()=>this._setUrlMode("companion")}>${t("qr_mode_companion",e)}</button>
|
||||
<button class="toggle-btn ${this._urlMode==="local"?"active":""}"
|
||||
@click=${()=>this._setUrlMode("local")}>${t("qr_mode_local",e)}</button>
|
||||
<button class="toggle-btn ${this._urlMode==="server"?"active":""}"
|
||||
@click=${()=>this._setUrlMode("server")}>${t("qr_mode_server",e)}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${t("cancel",e)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._print}
|
||||
.disabled=${!o}
|
||||
>
|
||||
${t("qr_print",e)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`}};r.styles=v`
|
||||
.dialog-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
min-width: 300px;
|
||||
}
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
.qr-pair {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
.qr-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.qr-image {
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
.qr-image.small {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
}
|
||||
.qr-item-label {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--secondary-text-color);
|
||||
text-align: center;
|
||||
}
|
||||
.dl-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
background: none;
|
||||
border: 1px solid var(--divider-color, #e0e0e0);
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
color: var(--primary-text-color);
|
||||
padding: 6px 14px;
|
||||
border-radius: 18px;
|
||||
transition: background 0.2s, border-color 0.2s;
|
||||
}
|
||||
.dl-btn:hover {
|
||||
background: var(--secondary-background-color, #f5f5f5);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
.dl-btn ha-icon {
|
||||
--mdc-icon-size: 18px;
|
||||
}
|
||||
.url-display {
|
||||
font-size: 11px;
|
||||
color: var(--secondary-text-color);
|
||||
word-break: break-all;
|
||||
text-align: center;
|
||||
max-width: 400px;
|
||||
}
|
||||
.loading {
|
||||
padding: 40px 0;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.error {
|
||||
padding: 20px 0;
|
||||
color: var(--error-color, #f44336);
|
||||
}
|
||||
.action-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
.action-row label {
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.action-toggle {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
background: var(--divider-color, #e0e0e0);
|
||||
border-radius: 6px;
|
||||
padding: 3px;
|
||||
}
|
||||
.toggle-btn {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--primary-text-color);
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
transition: all 0.2s;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.toggle-btn:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.toggle-btn.active {
|
||||
background: var(--primary-color);
|
||||
color: var(--text-primary-color, #fff);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
`,a([m({attribute:!1})],r.prototype,"hass",2),a([m()],r.prototype,"lang",2),a([c()],r.prototype,"_open",2),a([c()],r.prototype,"_loading",2),a([c()],r.prototype,"_error",2),a([c()],r.prototype,"_viewResult",2),a([c()],r.prototype,"_completeResult",2),a([c()],r.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",r);export{r as a};
|
||||
@@ -0,0 +1,54 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a as t,b as a,c as i,f as l,g as p,i as r}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";var e=class extends p{constructor(){super(...arguments);this.label="";this.value="";this.placeholder="";this.type="text";this.required=!1;this.disabled=!1}_onInput(n){let o=n.target.value;this.value=o,this.dispatchEvent(new CustomEvent("input",{bubbles:!0,composed:!0,detail:{value:o}}))}render(){return i`
|
||||
<label class="field">
|
||||
${this.label?i`<span class="label">${this.label}${this.required?i`<span class="req">*</span>`:l}</span>`:l}
|
||||
<input
|
||||
.value=${this.value??""}
|
||||
.type=${this.type}
|
||||
?required=${this.required}
|
||||
?disabled=${this.disabled}
|
||||
placeholder=${this.placeholder}
|
||||
step=${this.step??l}
|
||||
min=${this.min??l}
|
||||
max=${this.max??l}
|
||||
pattern=${this.pattern??l}
|
||||
@input=${this._onInput}
|
||||
@change=${this._onInput}
|
||||
/>
|
||||
${this.helper?i`<span class="helper">${this.helper}</span>`:l}
|
||||
</label>
|
||||
`}};e.styles=a`
|
||||
: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; }
|
||||
.helper {
|
||||
font-size: 11px;
|
||||
color: var(--secondary-text-color);
|
||||
font-style: italic;
|
||||
}
|
||||
`,t([r()],e.prototype,"label",2),t([r()],e.prototype,"value",2),t([r()],e.prototype,"placeholder",2),t([r()],e.prototype,"type",2),t([r({type:Boolean})],e.prototype,"required",2),t([r({type:Boolean})],e.prototype,"disabled",2),t([r()],e.prototype,"step",2),t([r()],e.prototype,"min",2),t([r()],e.prototype,"max",2),t([r()],e.prototype,"pattern",2),t([r()],e.prototype,"helper",2);customElements.get("ms-textfield")||customElements.define("ms-textfield",e);
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{n as _}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";function u(e){return`${e.entry_id??""}\0${e.part_id}`}function l(e,r,s,c){let n=!!e.entry_id&&e.entry_id!==r,o=n?e.entry_id:r,a=s.find(p=>p.entry_id===o),t=(a?.parts||[]).find(p=>p.id===e.part_id)||null,d=n&&a?.object?.name||"",i=t?.name||_("shared_part_unknown",c);return{part:t,foreign:n,ownerName:d,label:d?`${i} (${d})`:i}}function P(e,r,s,c){let{part:n,label:o}=l(e,r,s,c),a=n&&n.stock!==null&&n.stock!==void 0?` (${n.stock}${n.unit?" "+n.unit:""})`:"",t=n?.storage_location?` \u2014 ${n.storage_location}`:"";return`${e.quantity}\xD7 ${o}${a}${t}`}function g(e,r,s,c){let o=(s.find(t=>t.entry_id===r)?.parts||[]).map(t=>({...t})),a=new Set(o.map(t=>u({part_id:t.id})));for(let t of e?.consumes_parts||[]){if(!t.entry_id||t.entry_id===r)continue;let d=u(t);if(a.has(d))continue;a.add(d);let{part:i,ownerName:p}=l(t,r,s,c);o.push({id:t.part_id,name:i?.name||_("shared_part_unknown",c),unit:i?.unit,stock:i?.stock??null,storage_location:i?.storage_location,entry_id:t.entry_id,owner_name:p})}return o}var f=["notes","cost","duration","photo","user"],m={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"};export{u as a,P as b,g as c,f as d,m as e};
|
||||
@@ -0,0 +1,143 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-7ZFDRUH2.js";import{a as r,b as _,c as l,f as o,g as p,i as d,j as s,n as i,o as h}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";var e=class extends p{constructor(){super(...arguments);this.objects=[];this._open=!1;this._loading=!1;this._error="";this._name="";this._manufacturer="";this._model="";this._serialNumber="";this._areaId="";this._installationDate="";this._warrantyExpiry="";this._documentationUrl="";this._notes="";this._haDeviceId="";this._parentEntryId="";this._entryId=null}get _lang(){return h(this.hass)}openCreate(){this._entryId=null,this._name="",this._manufacturer="",this._model="",this._serialNumber="",this._areaId="",this._installationDate="",this._warrantyExpiry="",this._documentationUrl="",this._notes="",this._haDeviceId="",this._parentEntryId="",this._error="",this._open=!0}openEdit(a,n){this._entryId=a,this._name=n.name||"",this._manufacturer=n.manufacturer||"",this._model=n.model||"",this._serialNumber=n.serial_number||"",this._areaId=n.area_id||"",this._installationDate=n.installation_date||"",this._warrantyExpiry=n.warranty_expiry||"",this._documentationUrl=n.documentation_url||"",this._notes=n.notes||"",this._haDeviceId=n.ha_device_id||"",this._parentEntryId=n.parent_entry_id||"",this._error="",this._open=!0}async _save(){if(!this._loading&&this._name.trim()){this._loading=!0,this._error="";try{this._entryId?await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/update",entry_id:this._entryId,name:this._name,manufacturer:this._manufacturer||null,model:this._model||null,serial_number:this._serialNumber||null,area_id:this._areaId||null,installation_date:this._installationDate||null,warranty_expiry:this._warrantyExpiry||null,documentation_url:this._documentationUrl.trim()||null,notes:this._notes.trim()||null,ha_device_id:this._haDeviceId||null,parent_entry_id:this._parentEntryId||null}):await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/create",name:this._name,manufacturer:this._manufacturer||null,model:this._model||null,serial_number:this._serialNumber||null,area_id:this._areaId||null,installation_date:this._installationDate||null,warranty_expiry:this._warrantyExpiry||null,documentation_url:this._documentationUrl.trim()||null,notes:this._notes.trim()||null,ha_device_id:this._haDeviceId||null,parent_entry_id:this._parentEntryId||null}),this._open=!1,this.dispatchEvent(new CustomEvent("object-saved"))}catch(a){this._error=u(a,this._lang,i("save_error",this._lang))}finally{this._loading=!1}}}_parentChoices(){return(this.objects||[]).filter(a=>a.entry_id!==this._entryId)}_close(){this._open=!1}render(){if(!this._open)return l``;let a=this._lang,n=this._entryId?i("edit_object",a):i("new_object",a);return l`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${n}</div>
|
||||
<div class="content">
|
||||
${this._error?l`<div class="error">${this._error}</div>`:o}
|
||||
<ms-textfield
|
||||
label="${i("name",a)}"
|
||||
required
|
||||
.value=${this._name}
|
||||
@input=${t=>this._name=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("manufacturer_optional",a)}"
|
||||
.value=${this._manufacturer}
|
||||
@input=${t=>this._manufacturer=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("model_optional",a)}"
|
||||
.value=${this._model}
|
||||
@input=${t=>this._model=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("serial_number_optional",a)}"
|
||||
.value=${this._serialNumber}
|
||||
@input=${t=>this._serialNumber=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("documentation_url_optional",a)}"
|
||||
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",a)}"
|
||||
.value=${this._areaId}
|
||||
@value-changed=${t=>this._areaId=t.detail.value||""}
|
||||
></ha-area-picker>
|
||||
<ms-textfield
|
||||
label="${i("installation_date_optional",a)}"
|
||||
type="date"
|
||||
.value=${this._installationDate}
|
||||
@input=${t=>this._installationDate=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("warranty_expiry_optional",a)}"
|
||||
type="date"
|
||||
.value=${this._warrantyExpiry}
|
||||
@input=${t=>this._warrantyExpiry=t.target.value}
|
||||
></ms-textfield>
|
||||
<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${{device:this._haDeviceId||void 0}}
|
||||
.schema=${[{name:"device",selector:{device:{}}}]}
|
||||
.computeLabel=${()=>i("link_device_optional",a)}
|
||||
@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",a)}</span>
|
||||
<select
|
||||
class="parent-select"
|
||||
.value=${this._parentEntryId}
|
||||
@change=${t=>this._parentEntryId=t.target.value}
|
||||
>
|
||||
<option value="" ?selected=${!this._parentEntryId}>
|
||||
${i("parent_none",a)}
|
||||
</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",a)}</span>
|
||||
<textarea
|
||||
rows="3"
|
||||
.value=${this._notes}
|
||||
@input=${t=>this._notes=t.target.value}
|
||||
></textarea>
|
||||
</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>
|
||||
`}};e.styles=_`
|
||||
.dialog-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
min-width: 300px;
|
||||
}
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
ms-textfield {
|
||||
display: block;
|
||||
}
|
||||
.textarea-field {
|
||||
display: flex; flex-direction: column; gap: 4px;
|
||||
}
|
||||
.textarea-label {
|
||||
font-size: 12px; color: var(--secondary-text-color, #888); font-weight: 500;
|
||||
}
|
||||
.textarea-field textarea {
|
||||
padding: 8px 10px; font-size: 14px; font-family: inherit;
|
||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
resize: vertical;
|
||||
}
|
||||
.textarea-field textarea:focus {
|
||||
outline: none; border-color: var(--primary-color);
|
||||
}
|
||||
.parent-select {
|
||||
padding: 8px 10px; font-size: 14px; font-family: inherit;
|
||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
}
|
||||
.error {
|
||||
color: var(--error-color, #f44336);
|
||||
font-size: 13px;
|
||||
}
|
||||
`,r([d({attribute:!1})],e.prototype,"hass",2),r([d({attribute:!1})],e.prototype,"objects",2),r([s()],e.prototype,"_open",2),r([s()],e.prototype,"_loading",2),r([s()],e.prototype,"_error",2),r([s()],e.prototype,"_name",2),r([s()],e.prototype,"_manufacturer",2),r([s()],e.prototype,"_model",2),r([s()],e.prototype,"_serialNumber",2),r([s()],e.prototype,"_areaId",2),r([s()],e.prototype,"_installationDate",2),r([s()],e.prototype,"_warrantyExpiry",2),r([s()],e.prototype,"_documentationUrl",2),r([s()],e.prototype,"_notes",2),r([s()],e.prototype,"_haDeviceId",2),r([s()],e.prototype,"_parentEntryId",2),r([s()],e.prototype,"_entryId",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",e);export{e as a};
|
||||
@@ -0,0 +1,809 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a as x}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-7ZFDRUH2.js";import{A as Y,a as h,b as H,c as r,d as T,f as l,g as E,i as D,j as _,k as z,n as i,o as P,p as N,q as G,s as S,t as B,v as K,x as U,y as Z}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";var g=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=""}get _lang(){return P(this.hass)}openEdit(t){this._draft={...t},this._originalSnapshot={...t},this._error="",this._open=!0,this._partOptions=null,this._partQty={},this._partQtyOriginal="",this._loadPartOptions()}async _loadPartOptions(){let t=this._draft;if(t)try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/parts/overview"}),s=[];for(let d of e.parts||[]){let c=d.entry_id===t.entry_id,p=d.consumers.some(u=>u.entry_id===t.entry_id&&u.task_id===t.task_id);!c&&!p||s.push({part_id:d.part_id,name:d.name,entry_id:d.entry_id,foreign:!c,object_name:d.object_name})}for(let d of t.used_parts||[]){let c=d.entry_id||t.entry_id;s.some(p=>p.part_id===d.part_id&&p.entry_id===c)||s.push({part_id:d.part_id,name:d.name||d.part_id,entry_id:c,foreign:c!==t.entry_id,object_name:null})}let o={};for(let d of t.used_parts||[])o[`${d.entry_id||t.entry_id}:${d.part_id}`]=d.quantity??1;this._partOptions=s,this._partQty=o,this._partQtyOriginal=this._partSelectionKey()}catch{this._partOptions=[]}}_partSelectionKey(){return JSON.stringify(Object.entries(this._partQty).filter(([,t])=>t>0).sort(([t],[e])=>t.localeCompare(e)))}close(){this._open=!1,this._error="",this._draft=null,this._originalSnapshot=null}_set(t,e){this._draft&&(this._draft={...this._draft,[t]:e})}async _save(){if(!(!this._draft||!this._originalSnapshot)){this._saving=!0,this._error="";try{let t={type:"maintenance_supporter/task/history/update",entry_id:this._draft.entry_id,task_id:this._draft.task_id,original_timestamp:this._originalSnapshot.original_timestamp};if(this._draft.timestamp!==this._originalSnapshot.timestamp&&(t.timestamp=this._draft.timestamp),this._draft.notes!==this._originalSnapshot.notes&&(t.notes=this._draft.notes),this._draft.cost!==this._originalSnapshot.cost&&(t.cost=this._draft.cost),this._draft.duration!==this._originalSnapshot.duration&&(t.duration=this._draft.duration),this._draft.completed_by!==this._originalSnapshot.completed_by&&(t.completed_by=this._draft.completed_by),this._partOptions!==null&&this._partSelectionKey()!==this._partQtyOriginal&&(t.used_parts=(this._partOptions||[]).filter(s=>(this._partQty[`${s.entry_id}:${s.part_id}`]||0)>0).map(s=>({part_id:s.part_id,quantity:this._partQty[`${s.entry_id}:${s.part_id}`],...s.foreign?{entry_id:s.entry_id}:{}}))),Object.keys(t).filter(s=>!["type","entry_id","task_id","original_timestamp"].includes(s)).length===0){this.close();return}await this.hass.connection.sendMessagePromise(t),this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:this._draft.entry_id,task_id:this._draft.task_id,new_timestamp:this._draft.timestamp},bubbles:!0,composed:!0})),this.close()}catch(t){this._error=x(t,this._lang)}finally{this._saving=!1}}}render(){if(!this._open||!this._draft)return l;let t=this._lang,e=this._draft;return r`
|
||||
<div class="backdrop" @click=${this.close}></div>
|
||||
<div class="dialog" role="dialog" aria-modal="true">
|
||||
<h2>${i("history_edit_title",t)||"Edit history entry"}</h2>
|
||||
<div class="entry-type">
|
||||
<ha-icon icon="mdi:tag-outline"></ha-icon>
|
||||
<span>${i(e.type,t)||e.type}</span>
|
||||
</div>
|
||||
<label>
|
||||
<span>${i("history_edit_timestamp",t)||"Timestamp"}</span>
|
||||
<input type="datetime-local"
|
||||
.value=${e.timestamp.length>=16?e.timestamp.slice(0,16):e.timestamp}
|
||||
@change=${s=>{let o=s.target.value;this._set("timestamp",o.length===16?`${o}:00`:o)}} />
|
||||
</label>
|
||||
<label>
|
||||
<span>${i("notes_label",t)}</span>
|
||||
<textarea
|
||||
rows="3"
|
||||
@input=${s=>{let o=s.target.value;this._set("notes",o||null)}}
|
||||
.value=${e.notes??""}></textarea>
|
||||
</label>
|
||||
<div class="row">
|
||||
<label>
|
||||
<span>${i("cost",t)||"Cost"}</span>
|
||||
<input type="number" min="0" step="0.01"
|
||||
.value=${e.cost!=null?String(e.cost):""}
|
||||
@input=${s=>{let o=s.target.value;this._set("cost",o?Number(o):null)}} />
|
||||
</label>
|
||||
<label>
|
||||
<span>${i("duration",t)||"Duration (min)"}</span>
|
||||
<input type="number" min="0"
|
||||
.value=${e.duration!=null?String(e.duration):""}
|
||||
@input=${s=>{let o=s.target.value;this._set("duration",o?Number(o):null)}} />
|
||||
</label>
|
||||
</div>
|
||||
${this._partOptions&&this._partOptions.length>0?r`
|
||||
<div class="parts-block">
|
||||
<span class="parts-title">${i("complete_parts_used",t)}</span>
|
||||
${this._partOptions.map(s=>{let o=`${s.entry_id}:${s.part_id}`,d=this._partQty[o]||0;return r`
|
||||
<label class="part-row-edit">
|
||||
<input type="checkbox" .checked=${d>0}
|
||||
@change=${c=>{let p=c.target.checked;this._partQty={...this._partQty,[o]:p?1:0}}} />
|
||||
<span class="part-label">${s.name}${s.foreign&&s.object_name?` (${s.object_name})`:""}</span>
|
||||
${d>0?r`
|
||||
<input class="part-qty" type="number" min="0.01" max="999" step="0.01"
|
||||
.value=${String(d)}
|
||||
@input=${c=>{let p=parseFloat(c.target.value);!isNaN(p)&&p>0&&(this._partQty={...this._partQty,[o]:p})}} />
|
||||
`:l}
|
||||
</label>
|
||||
`})}
|
||||
</div>
|
||||
`:l}
|
||||
${this._error?r`<div class="error">${this._error}</div>`:l}
|
||||
<div class="actions">
|
||||
<button class="cancel" @click=${this.close} ?disabled=${this._saving}>
|
||||
${i("cancel",t)||"Cancel"}
|
||||
</button>
|
||||
<button class="save" @click=${this._save} ?disabled=${this._saving}>
|
||||
${this._saving?i("saving",t)||"Saving\u2026":i("save",t)||"Save"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`}};g.styles=H`
|
||||
:host { display: contents; }
|
||||
.backdrop {
|
||||
position: fixed; inset: 0;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 100;
|
||||
}
|
||||
.dialog {
|
||||
position: fixed; left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 95vw; max-width: 480px;
|
||||
background: var(--card-background-color, var(--ha-card-background, #1c1c1c));
|
||||
color: var(--primary-text-color);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
|
||||
padding: 20px;
|
||||
display: flex; flex-direction: column; gap: 12px;
|
||||
z-index: 101;
|
||||
max-height: 90vh; overflow: auto;
|
||||
}
|
||||
h2 { margin: 0; font-size: 18px; }
|
||||
.entry-type {
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
color: var(--secondary-text-color); font-size: 13px;
|
||||
}
|
||||
label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
|
||||
label span { color: var(--secondary-text-color); }
|
||||
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
||||
input, textarea {
|
||||
padding: 8px; font-size: 14px;
|
||||
background: var(--secondary-background-color, #2c2c2c);
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color, #444);
|
||||
border-radius: 6px;
|
||||
width: 100%; box-sizing: border-box;
|
||||
font-family: inherit;
|
||||
}
|
||||
.actions {
|
||||
display: flex; gap: 8px; justify-content: flex-end;
|
||||
margin-top: 8px;
|
||||
}
|
||||
button {
|
||||
padding: 8px 16px; font-size: 14px;
|
||||
border-radius: 6px; cursor: pointer;
|
||||
border: none; font-weight: 500;
|
||||
}
|
||||
button.cancel {
|
||||
background: transparent;
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
}
|
||||
button.save {
|
||||
background: var(--primary-color);
|
||||
color: var(--text-primary-color, white);
|
||||
}
|
||||
button[disabled] { opacity: 0.5; cursor: wait; }
|
||||
.error {
|
||||
color: var(--error-color, #d32f2f);
|
||||
font-size: 13px; padding: 8px;
|
||||
background: rgba(211,47,47,0.1);
|
||||
border-radius: 6px;
|
||||
}
|
||||
/* #130: parts on the entry */
|
||||
.parts-block {
|
||||
display: flex; flex-direction: column; gap: 6px;
|
||||
border: 1px solid var(--divider-color, #444);
|
||||
border-radius: 6px; padding: 8px;
|
||||
}
|
||||
.parts-title { color: var(--secondary-text-color); font-size: 13px; }
|
||||
.part-row-edit {
|
||||
display: flex; flex-direction: row; align-items: center; gap: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.part-row-edit input[type="checkbox"] { width: auto; }
|
||||
.part-label { flex: 1; color: var(--primary-text-color); }
|
||||
.part-qty { width: 76px; }
|
||||
`,h([D({attribute:!1})],g.prototype,"hass",2),h([_()],g.prototype,"_open",2),h([_()],g.prototype,"_saving",2),h([_()],g.prototype,"_error",2),h([_()],g.prototype,"_draft",2),h([_()],g.prototype,"_partOptions",2),h([_()],g.prototype,"_partQty",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",g);function Q(a,n){let t=a.interval_analysis,e=t?.weibull_beta,s=t?.weibull_eta;if(e==null||s==null||s<=0)return l;let o=a.interval_days??0,d=a.suggested_interval??o;return r`
|
||||
<div class="weibull-section">
|
||||
<div class="weibull-title">
|
||||
<ha-svg-icon aria-hidden="true" path="M3,14L3.5,14.07L8.07,9.5C7.89,8.85 8.06,8.11 8.59,7.59C9.37,6.8 10.63,6.8 11.41,7.59C11.94,8.11 12.11,8.85 11.93,9.5L14.5,12.07L15,12C15.18,12 15.35,12 15.5,12.07L19.07,8.5C19,8.35 19,8.18 19,8A2,2 0 0,1 21,6A2,2 0 0,1 23,8A2,2 0 0,1 21,10C20.82,10 20.65,10 20.5,9.93L16.93,13.5C17,13.65 17,13.82 17,14A2,2 0 0,1 15,16A2,2 0 0,1 13,14L13.07,13.5L10.5,10.93C10.18,11 9.82,11 9.5,10.93L4.93,15.5L5,16A2,2 0 0,1 3,18A2,2 0 0,1 1,16A2,2 0 0,1 3,14Z"></ha-svg-icon>
|
||||
${i("weibull_reliability_curve",n)}
|
||||
${ut(e,n)}
|
||||
</div>
|
||||
${_t(e,s,o,d,n)}
|
||||
${mt(t,n)}
|
||||
${t?.confidence_interval_low!=null?vt(t,a,n):l}
|
||||
</div>
|
||||
`}function ut(a,n){let t,e,s;return a<.8?(t="early_failures",e="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z",s="beta_early_failures"):a<=1.2?(t="random_failures",e="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,17H11V15H13V17M13,13H11V7H13V13Z",s="beta_random_failures"):a<=3.5?(t="wear_out",e="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4M12,6A6,6 0 0,1 18,12H12V6Z",s="beta_wear_out"):(t="highly_predictable",e="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M11,16.5L18,9.5L16.59,8.09L11,13.67L7.91,10.59L6.5,12L11,16.5Z",s="beta_highly_predictable"),r`
|
||||
<span class="beta-badge ${t}">
|
||||
<ha-svg-icon path="${e}"></ha-svg-icon>
|
||||
${i(s,n)} (\u03B2=${a.toFixed(2)})
|
||||
</span>
|
||||
`}function _t(a,n,t,e,s){let v=Math.max(t,e,n,1)*1.3,k=50,w=[];for(let y=0;y<=k;y++){let b=y/k*v,ct=1-Math.exp(-Math.pow(b/n,a)),pt=32+b/v*260,ht=136-ct*128;w.push([pt,ht])}let j=w.map(([y,b])=>`${y.toFixed(1)},${b.toFixed(1)}`).join(" "),W="M32,136 "+w.map(([y,b])=>`L${y.toFixed(1)},${b.toFixed(1)}`).join(" ")+` L${w[k][0].toFixed(1)},136 Z`,I=32+t/v*260,F=1-Math.exp(-Math.pow(t/n,a)),O=136-F*128,lt=((1-F)*100).toFixed(0),q=32+e/v*260,dt=[0,.25,.5,.75,1];return r`
|
||||
<div class="weibull-chart">
|
||||
<svg viewBox="0 0 ${300} ${160}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${i("chart_weibull",s)}">
|
||||
${dt.map(y=>{let b=136-y*128;return T`
|
||||
<line x1="${32}" y1="${b.toFixed(1)}" x2="${292}" y2="${b.toFixed(1)}"
|
||||
stroke="var(--divider-color)" stroke-width="0.5" stroke-dasharray="${y===.5?"4,3":l}" />
|
||||
<text x="${28}" y="${(b+3).toFixed(1)}" fill="var(--secondary-text-color)"
|
||||
font-size="8" text-anchor="end">${(y*100).toFixed(0)}%</text>
|
||||
`})}
|
||||
|
||||
<text x="${32}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">0</text>
|
||||
<text x="${324/2}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">${Math.round(v/2)}</text>
|
||||
<text x="${292}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">${Math.round(v)}</text>
|
||||
|
||||
<path d="${W}" fill="var(--primary-color, #03a9f4)" opacity="0.08" />
|
||||
<polyline points="${j}" fill="none"
|
||||
stroke="var(--primary-color, #03a9f4)" stroke-width="2" />
|
||||
|
||||
${t>0?T`
|
||||
<line x1="${I.toFixed(1)}" y1="${8}" x2="${I.toFixed(1)}" y2="${136 .toFixed(1)}"
|
||||
stroke="var(--primary-color, #03a9f4)" stroke-width="1.5" stroke-dasharray="4,3" />
|
||||
<circle cx="${I.toFixed(1)}" cy="${O.toFixed(1)}" r="3"
|
||||
fill="var(--primary-color, #03a9f4)" />
|
||||
<text x="${(I+4).toFixed(1)}" y="${(O-6).toFixed(1)}" fill="var(--primary-color, #03a9f4)"
|
||||
font-size="9" font-weight="600">R=${lt}%</text>
|
||||
`:l}
|
||||
|
||||
${e>0&&e!==t?T`
|
||||
<line x1="${q.toFixed(1)}" y1="${8}" x2="${q.toFixed(1)}" y2="${136 .toFixed(1)}"
|
||||
stroke="var(--success-color, #4caf50)" stroke-width="1.5" stroke-dasharray="4,3" />
|
||||
`:l}
|
||||
|
||||
<line x1="${32}" y1="${8}" x2="${32}" y2="${136}"
|
||||
stroke="var(--secondary-text-color)" stroke-width="1" />
|
||||
<line x1="${32}" y1="${136}" x2="${292}" y2="${136}"
|
||||
stroke="var(--secondary-text-color)" stroke-width="1" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="chart-legend">
|
||||
<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color, #03a9f4)"></span> ${i("weibull_failure_probability",s)}</span>
|
||||
${t>0?r`<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color, #03a9f4); opacity:0.5"></span> ${i("current_interval_marker",s)}</span>`:l}
|
||||
${e>0&&e!==t?r`<span class="legend-item"><span class="legend-swatch" style="background:var(--success-color, #4caf50)"></span> ${i("recommended_marker",s)}</span>`:l}
|
||||
</div>
|
||||
`}function mt(a,n){return r`
|
||||
<div class="weibull-info-row">
|
||||
<div class="weibull-info-item">
|
||||
<span>${i("characteristic_life",n)}</span>
|
||||
<span class="weibull-info-value">${Math.round(a.weibull_eta)} ${i("days",n)}</span>
|
||||
</div>
|
||||
${a.weibull_r_squared!=null?r`
|
||||
<div class="weibull-info-item">
|
||||
<span>${i("weibull_r_squared",n)}</span>
|
||||
<span class="weibull-info-value">${a.weibull_r_squared.toFixed(3)}</span>
|
||||
</div>
|
||||
`:l}
|
||||
</div>
|
||||
`}function vt(a,n,t){let e=a.confidence_interval_low,s=a.confidence_interval_high,o=n.suggested_interval??n.interval_days??0,d=n.interval_days??0,c=Math.max(0,e-5),u=s+5-c,f=(e-c)/u*100,M=(s-e)/u*100,C=(o-c)/u*100,v=d>0?(d-c)/u*100:-1;return r`
|
||||
<div class="confidence-range">
|
||||
<div class="confidence-range-title">
|
||||
${i("confidence_interval",t)}: ${o} ${i("days",t)} (${e}\u2013${s})
|
||||
</div>
|
||||
<div class="confidence-bar">
|
||||
<div class="confidence-fill" style="left:${f.toFixed(1)}%;width:${M.toFixed(1)}%"></div>
|
||||
${v>=0?r`<div class="confidence-marker current" style="left:${v.toFixed(1)}%"></div>`:l}
|
||||
<div class="confidence-marker recommended" style="left:${C.toFixed(1)}%"></div>
|
||||
</div>
|
||||
<div class="confidence-labels">
|
||||
<span class="confidence-text low">${i("confidence_conservative",t)} (${e}${i("days",t).charAt(0)})</span>
|
||||
<span class="confidence-text high">${i("confidence_aggressive",t)} (${s}${i("days",t).charAt(0)})</span>
|
||||
</div>
|
||||
</div>
|
||||
`}function J(a,n,t){let e=a.degradation_trend!=null&&a.degradation_trend!=="insufficient_data",s=a.days_until_threshold!=null,o=a.environmental_factor!=null&&a.environmental_factor!==1;if(!e&&!s&&!o)return l;let d=a.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":a.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 r`
|
||||
<div class="prediction-section">
|
||||
${a.sensor_prediction_urgency?r`
|
||||
<div class="prediction-urgency-banner">
|
||||
<ha-svg-icon path="M1,21H23L12,2L1,21M12,18A1,1 0 0,1 11,17A1,1 0 0,1 12,16A1,1 0 0,1 13,17A1,1 0 0,1 12,18M13,15H11V10H13V15Z"></ha-svg-icon>
|
||||
${i("sensor_prediction_urgency",n).replace("{days}",String(Math.round(a.days_until_threshold||0)))}
|
||||
</div>
|
||||
`:l}
|
||||
<div class="prediction-title">
|
||||
<ha-svg-icon path="M2,2V4H7V2H2M22,2V4H13V2H22M7,7V9H2V7H7M22,7V9H13V7H22M7,12V14H2V12H7M22,12V14H13V12H22M7,17V19H2V17H7M22,17V19H13V17H22M9,2V19L12,22L15,19V2H9M11,4H13V17.17L12,18.17L11,17.17V4Z"></ha-svg-icon>
|
||||
${i("sensor_prediction",n)}
|
||||
</div>
|
||||
<div class="prediction-grid">
|
||||
${e?r`
|
||||
<div class="prediction-item">
|
||||
<ha-svg-icon path="${d}"></ha-svg-icon>
|
||||
<span class="prediction-label">${i("degradation_trend",n)}</span>
|
||||
<span class="prediction-value ${a.degradation_trend}">${i("trend_"+a.degradation_trend,n)}</span>
|
||||
${a.degradation_rate!=null?r`<span class="prediction-rate">${a.degradation_rate>0?"+":""}${Math.abs(a.degradation_rate)>=10?Math.round(a.degradation_rate).toLocaleString():a.degradation_rate.toFixed(1)} ${a.trigger_entity_info?.unit_of_measurement||""}/${i("day_short",n)}</span>`:l}
|
||||
</div>
|
||||
`:l}
|
||||
${s?r`
|
||||
<div class="prediction-item">
|
||||
<ha-svg-icon path="M12,20A7,7 0 0,1 5,13A7,7 0 0,1 12,6A7,7 0 0,1 19,13A7,7 0 0,1 12,20M12,4A9,9 0 0,0 3,13A9,9 0 0,0 12,22A9,9 0 0,0 21,13A9,9 0 0,0 12,4M12.5,8H11V14L15.75,16.85L16.5,15.62L12.5,13.25V8M7.88,3.39L6.6,1.86L2,5.71L3.29,7.24L7.88,3.39M22,5.72L17.4,1.86L16.11,3.39L20.71,7.25L22,5.72Z"></ha-svg-icon>
|
||||
<span class="prediction-label">${i("days_until_threshold",n)}</span>
|
||||
<span class="prediction-value prediction-days${a.days_until_threshold===0?" exceeded":a.sensor_prediction_urgency?" urgent":""}">${a.days_until_threshold===0?i("threshold_exceeded",n):"~"+Math.round(a.days_until_threshold)+" "+i("days",n)}</span>
|
||||
${a.threshold_prediction_date?r`<span class="prediction-date">${S(a.threshold_prediction_date,n)}</span>`:l}
|
||||
${a.threshold_prediction_confidence?r`<span class="confidence-dot ${a.threshold_prediction_confidence}"></span>`:l}
|
||||
</div>
|
||||
`:l}
|
||||
${o&&t.environmental?r`
|
||||
<div class="prediction-item">
|
||||
<ha-svg-icon path="M15,13V5A3,3 0 0,0 12,2A3,3 0 0,0 9,5V13A5,5 0 0,0 7,17A5,5 0 0,0 12,22A5,5 0 0,0 17,17A5,5 0 0,0 15,13M12,4A1,1 0 0,1 13,5V8H11V5A1,1 0 0,1 12,4Z"></ha-svg-icon>
|
||||
<span class="prediction-label">${i("environmental_adjustment",n)}</span>
|
||||
<span class="prediction-value">${a.environmental_factor.toFixed(2)}x</span>
|
||||
${a.environmental_entity?r`<span class="prediction-entity entity-link" @click=${c=>Z(c,a.environmental_entity)}>${a.environmental_entity}</span>`:l}
|
||||
</div>
|
||||
`:l}
|
||||
</div>
|
||||
</div>
|
||||
`}function X(a,n,t,e){let s=Math.max(a||1,n);return r`
|
||||
<div class="interval-comparison">
|
||||
<div class="interval-bar">
|
||||
<div class="interval-label">
|
||||
${i("current",e)}: ${a??"\u2014"} ${a!=null?i("days",e):""}
|
||||
</div>
|
||||
<div class="interval-visual current"
|
||||
style="width: ${a!=null?Math.min(a/s*100,100):0}%"></div>
|
||||
</div>
|
||||
<div class="interval-bar">
|
||||
<div class="interval-label">
|
||||
${i("recommended",e)}: ${n} ${i("days",e)}
|
||||
<span class="confidence-badge ${t}">${i(`confidence_${t}`,e)}</span>
|
||||
</div>
|
||||
<div class="interval-visual suggested"
|
||||
style="width: ${Math.min(n/s*100,100)}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
`}var tt=["month_jan","month_feb","month_mar","month_apr","month_may","month_jun","month_jul","month_aug","month_sep","month_oct","month_nov","month_dec"];function et(a,n,t){if(!t.seasonal||!a.seasonal_factor||a.seasonal_factor===1)return l;let e=tt.map(c=>i(c,n)),s=new Date().getMonth(),o=a.seasonal_factors||a.interval_analysis?.seasonal_factors||null,d=o&&o.length===12?o:e.map((c,p)=>{let u=a.seasonal_factor||1,f=Math.sin((p-6)*Math.PI/6)*.3;return Math.max(.7,Math.min(1.3,u+f))});return r`
|
||||
<div class="seasonal-card-compact">
|
||||
<h4>${i("seasonal_awareness",n)}</h4>
|
||||
<div class="seasonal-mini-chart">
|
||||
${d.map((c,p)=>{let u=c*40,f=c<.9?"low":c>1.1?"high":"normal";return r`
|
||||
<div class="seasonal-bar ${f} ${p===s?"current":""}"
|
||||
style="height: ${u}px"
|
||||
title="${e[p]}: ${c.toFixed(2)}x">
|
||||
</div>
|
||||
`})}
|
||||
</div>
|
||||
<div class="seasonal-legend">
|
||||
<span class="legend-item"><span class="dot low"></span> ${i("shorter",n)||"K\xFCrzer"}</span>
|
||||
<span class="legend-item"><span class="dot normal"></span> ${i("normal",n)||"Normal"}</span>
|
||||
<span class="legend-item"><span class="dot high"></span> ${i("longer",n)||"L\xE4nger"}</span>
|
||||
</div>
|
||||
</div>
|
||||
`}function it(a,n){return ft(a,n)}function ft(a,n){let t=a.seasonal_factors??a.interval_analysis?.seasonal_factors;if(!t||t.length!==12)return l;let e=a.interval_analysis?.seasonal_reason,s=new Date().getMonth(),o=300,d=100,c=8,u=d-c-4,f=Math.max(...t,1.5),M=o/12,C=M*.65,v=c+u-1/f*u;return r`
|
||||
<div class="seasonal-chart">
|
||||
<div class="seasonal-chart-title">
|
||||
<ha-svg-icon aria-hidden="true" path="M17.75 4.09L15.22 6.03L16.13 9.09L13.5 7.28L10.87 9.09L11.78 6.03L9.25 4.09L12.44 4L13.5 1L14.56 4L17.75 4.09M21.25 11L19.61 12.25L20.2 14.23L18.5 13.06L16.8 14.23L17.39 12.25L15.75 11L17.81 10.95L18.5 9L19.19 10.95L21.25 11M18.97 15.95C19.8 15.87 20.69 17.05 20.16 17.8C19.84 18.25 19.5 18.67 19.08 19.07C15.17 23 8.84 23 4.94 19.07C1.03 15.17 1.03 8.83 4.94 4.93C5.34 4.53 5.76 4.17 6.21 3.85C6.96 3.32 8.14 4.21 8.06 5.04C7.79 7.9 8.75 10.87 10.95 13.06C13.14 15.26 16.1 16.22 18.97 15.95Z"></ha-svg-icon>
|
||||
${i("seasonal_chart_title",n)}
|
||||
${e?r`<span class="source-tag">${e==="learned"?i("seasonal_learned",n):i("seasonal_manual",n)}</span>`:l}
|
||||
</div>
|
||||
<svg viewBox="0 0 ${o} ${d}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${i("chart_seasonal",n)}">
|
||||
<line x1="0" y1="${v.toFixed(1)}" x2="${o}" y2="${v.toFixed(1)}"
|
||||
stroke="var(--divider-color)" stroke-width="1" stroke-dasharray="4,3" />
|
||||
${t.map((k,w)=>{let j=k/f*u,W=w*M+(M-C)/2,I=c+u-j,F=w===s,O=k<1?"var(--success-color, #4caf50)":k>1?"var(--warning-color, #ff9800)":"var(--secondary-text-color)";return T`
|
||||
<rect x="${W.toFixed(1)}" y="${I.toFixed(1)}"
|
||||
width="${C.toFixed(1)}" height="${j.toFixed(1)}"
|
||||
fill="${O}" opacity="${F?1:.5}" rx="2" />
|
||||
`})}
|
||||
</svg>
|
||||
<div class="seasonal-labels">
|
||||
${tt.map((k,w)=>r`<span class="seasonal-label ${w===s?"active-month":""}">${i(k,n)}</span>`)}
|
||||
</div>
|
||||
</div>
|
||||
`}var m=class extends E{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._taskId=null;this._task=null;this._objectName="";this._busy=!1;this._error="";this._showSkip=!1;this._showReset=!1;this._showDetails=!1;this._showAdaptive=!1;this._skipReason="";this._resetDate="";this._features={adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1};this._toast="";this._featuresLoaded=!1}get _lang(){return P(this.hass)}async openFor(t,e){this._entryId=t,this._taskId=e,this._error="",this._showSkip=!1,this._showReset=!1,this._showAdaptive=!1,this._skipReason="",this._resetDate=new Date().toISOString().slice(0,10),this._open=!0,await Promise.all([this._loadTask(),this._loadFeatures()])}async _loadFeatures(){if(!this._featuresLoaded)try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/settings"});t?.features&&(this._features={...this._features,...t.features}),this._featuresLoaded=!0}catch{}}close(){this._open=!1,this._task=null,this._error=""}async _loadTask(){if(!(!this._entryId||!this._taskId))try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId});this._objectName=t.object?.name||"";let e=(t.tasks||[]).find(s=>s.id===this._taskId);this._task=e??null}catch(t){this._error=x(t,this._lang)}}async _runWs(t){this._busy=!0,this._error="";try{return await this.hass.connection.sendMessagePromise(t),this._busy=!1,!0}catch(e){return this._error=x(e,this._lang),this._busy=!1,!1}}_notifyChanged(t){this.dispatchEvent(new CustomEvent("task-action-fired",{detail:{entry_id:this._entryId,task_id:this._taskId,action:t},bubbles:!0,composed:!0}))}_onComplete(){!this._entryId||!this._taskId||!this._task||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-ZLYYN2LL.js").then(({openCompleteDialog:t})=>{t({entry_id:this._entryId,task_id:this._taskId,task_name:this._task.name,checklist:this._task.checklist||[],adaptive_enabled:!!this._task.adaptive_config?.enabled})&&(this._notifyChanged("complete"),this.close())})}async _onSkipConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/skip",entry_id:this._entryId,task_id:this._taskId,reason:this._skipReason.trim()||null})&&(this._notifyChanged("skip"),this.close())}async _onResetConfirm(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/reset",entry_id:this._entryId,task_id:this._taskId,date:this._resetDate||void 0})&&(this._notifyChanged("reset"),this.close())}_onEdit(){!this._entryId||!this._taskId||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-ZLYYN2LL.js").then(({openEditTaskDialog:t})=>{t(this._entryId,this._taskId),this.close()})}_onQr(){!this._entryId||!this._taskId||!this._task||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-ZLYYN2LL.js").then(({openQrDialog:t})=>{t({entry_id:this._entryId,task_id:this._taskId,task_name:this._task.name,object_name:this._objectName}),this.close()})}async _onDelete(){if(!this._entryId||!this._taskId)return;let t=i("delete_task_confirm",this._lang)||`Delete "${this._task?.name}"?`;if(!window.confirm(t))return;await this._runWs({type:"maintenance_supporter/task/delete",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("delete"),this.close())}async _onArchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/archive",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("archive"),this.close())}async _onUnarchive(){if(!this._entryId||!this._taskId)return;await this._runWs({type:"maintenance_supporter/task/unarchive",entry_id:this._entryId,task_id:this._taskId})&&(this._notifyChanged("unarchive"),this.close())}_onOpenInPanel(){if(!this._entryId||!this._taskId)return;let t=`/maintenance-supporter?entry_id=${encodeURIComponent(this._entryId)}&task_id=${encodeURIComponent(this._taskId)}`;history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed")),this.close()}async _applySuggestion(){if(!this._entryId||!this._taskId||!this._task?.suggested_interval)return;await this._runWs({type:"maintenance_supporter/task/apply_suggestion",entry_id:this._entryId,task_id:this._taskId,interval:this._task.suggested_interval})&&(this._toast=i("suggestion_applied",this._lang)||"Applied",this._notifyChanged("apply_suggestion"),await this._loadTask(),setTimeout(()=>{this._toast=""},2500))}async _reanalyzeInterval(){if(!(!this._entryId||!this._taskId)){this._busy=!0,this._error="";try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/analyze_interval",entry_id:this._entryId,task_id:this._taskId});this._toast=t.recommended_interval?`${i("reanalyze_result",this._lang)||"Recomputed"}: ${K(t.recommended_interval,"days",this._lang)} (${t.data_points} pts)`:i("reanalyze_insufficient_data",this._lang)||"Not enough data",
Line truncated
|
||||
<div class="recommendation-card">
|
||||
<h4>${i("suggested_interval",e)}</h4>
|
||||
${X(t.interval_days,t.suggested_interval,t.interval_confidence||"medium",e)}
|
||||
<div class="recommendation-actions">
|
||||
<button class="btn primary"
|
||||
@click=${this._applySuggestion} ?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:check"></ha-icon>
|
||||
${i("apply_suggestion",e)}
|
||||
</button>
|
||||
<button class="btn"
|
||||
@click=${this._reanalyzeInterval} ?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:refresh"></ha-icon>
|
||||
${i("reanalyze",e)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`}_renderAdaptive(t){let e=this._lang,s=this._features.adaptive&&t.suggested_interval&&t.suggested_interval!==t.interval_days,o=t.degradation_trend!=null&&t.degradation_trend!=="insufficient_data"||t.days_until_threshold!=null||t.environmental_factor!=null&&t.environmental_factor!==1,d=this._features.adaptive&&t.interval_analysis?.weibull_beta!=null&&t.interval_analysis?.weibull_eta!=null,c=this._features.seasonal&&t.seasonal_factor&&t.seasonal_factor!==1;return!s&&!o&&!d&&!c?r`<div class="adaptive-empty">
|
||||
${i("adaptive_no_data",e)||"Not enough completion history yet for adaptive analysis."}
|
||||
</div>`:r`
|
||||
<div class="adaptive-stack">
|
||||
${this._toast?r`<div class="toast">${this._toast}</div>`:l}
|
||||
${s?this._renderRecommendation(t):l}
|
||||
${o?J(t,e,this._features):l}
|
||||
${d?Q(t,e):l}
|
||||
${c?r`
|
||||
${et(t,e,this._features)}
|
||||
${t.seasonal_factors?.length===12||t.interval_analysis?.seasonal_factors?.length===12?it(t,e):l}
|
||||
`:l}
|
||||
</div>
|
||||
`}_renderDetails(t){let e=this._lang,s=t.history||[],o=s.filter(p=>p.type==="completed"),d=o.reduce((p,u)=>p+(typeof u.cost=="number"?u.cost:0),0),c=(()=>{let p=o.map(u=>typeof u.duration=="number"?u.duration:null).filter(u=>u!=null);return p.length?Math.round(p.reduce((u,f)=>u+f,0)/p.length):null})();return r`
|
||||
<div class="details">
|
||||
<div class="stats-grid">
|
||||
<div class="stat">
|
||||
<span class="stat-label">${i("times_performed",e)||"Performed"}</span>
|
||||
<span class="stat-value">${o.length}</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">${i("total_cost",e)||"Total cost"}</span>
|
||||
<span class="stat-value">${d.toFixed(2)}</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">${i("avg_duration",e)||"Avg duration"}</span>
|
||||
<span class="stat-value">${c!=null?`${c}m`:"\u2014"}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="history-header">
|
||||
<strong>${i("history",e)||"History"}</strong>
|
||||
<span class="history-count">${s.length}</span>
|
||||
</div>
|
||||
${s.length===0?r`<div class="history-empty">${i("history_empty",e)||"No history yet."}</div>`:r`
|
||||
<div class="history-list">
|
||||
${[...s].reverse().slice(0,20).map(p=>{let u=["completed","reset","skipped"].includes(p.type);return r`
|
||||
<div class="history-entry">
|
||||
<div class="history-line">
|
||||
<span class="history-type type-${p.type}">${i(p.type,e)}</span>
|
||||
<span class="history-date">${B(p.timestamp,e)}</span>
|
||||
${u?r`<button class="history-edit"
|
||||
title="${i("history_edit_button",e)||"Edit"}"
|
||||
@click=${()=>this._onEditHistoryEntry(p)}>
|
||||
<ha-icon icon="mdi:pencil"></ha-icon>
|
||||
</button>`:l}
|
||||
</div>
|
||||
${p.notes?r`<div class="history-notes">${p.notes}</div>`:l}
|
||||
${p.cost!=null||p.duration!=null?r`<div class="history-meta">
|
||||
${p.cost!=null?r`<span>💰 ${p.cost.toFixed(2)}</span>`:l}
|
||||
${p.duration!=null?r`<span>⏱️ ${p.duration}m</span>`:l}
|
||||
</div>`:l}
|
||||
</div>
|
||||
`})}
|
||||
${s.length>20?r`<div class="history-more">… +${s.length-20} ${i("older_entries",e)||"older"}</div>`:l}
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
`}render(){if(!this._open)return l;let t=this._lang,e=this._task,s=this.hass?.user?.is_admin??!0;return r`
|
||||
<div class="backdrop" @click=${this.close}></div>
|
||||
<div class="dialog" role="dialog" aria-modal="true">
|
||||
${e?r`
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<span class="status-dot" style="background: ${z[e.status]||"#ccc"}"></span>
|
||||
<span class="task-name">${e.name}</span>
|
||||
</div>
|
||||
<div class="object">
|
||||
<button class="link-inline" @click=${()=>{this._entryId&&import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-ZLYYN2LL.js").then(({openObjectQuickActions:o})=>{o(this._entryId),this.close()})}}>${this._objectName}</button>
|
||||
</div>
|
||||
<div class="quick-info">
|
||||
${e.next_due?r`<span><strong>${i("next_due",t)||"Next due"}:</strong> ${S(e.next_due,t)}</span>`:l}
|
||||
${e.last_performed?r`<span><strong>${i("last_performed",t)||"Last"}:</strong> ${S(e.last_performed,t)}</span>`:l}
|
||||
${e.schedule?.kind&&!["manual","one_time"].includes(e.schedule.kind)||e.interval_days!=null?r`<span><strong>${i("interval",t)||"Interval"}:</strong> ${U(e,t)}</span>`:l}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${this._error?r`<div class="error">${this._error}</div>`:l}
|
||||
|
||||
${this._showSkip?r`
|
||||
<div class="inline-form">
|
||||
<label>${i("skip_reason",t)||"Skip reason (optional)"}</label>
|
||||
<input type="text" .value=${this._skipReason}
|
||||
@input=${o=>{this._skipReason=o.target.value}} />
|
||||
<div class="inline-actions">
|
||||
<button class="btn cancel" @click=${()=>{this._showSkip=!1}} ?disabled=${this._busy}>
|
||||
${i("cancel",t)||"Cancel"}
|
||||
</button>
|
||||
<button class="btn primary" @click=${this._onSkipConfirm} ?disabled=${this._busy}>
|
||||
${i("skip",t)||"Skip"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`:this._showReset?r`
|
||||
<div class="inline-form">
|
||||
<label>${i("reset_to_date",t)||"Reset last_performed to"}</label>
|
||||
<input type="date" .value=${this._resetDate}
|
||||
@input=${o=>{this._resetDate=o.target.value}} />
|
||||
<div class="inline-actions">
|
||||
<button class="btn cancel" @click=${()=>{this._showReset=!1}} ?disabled=${this._busy}>
|
||||
${i("cancel",t)||"Cancel"}
|
||||
</button>
|
||||
<button class="btn primary" @click=${this._onResetConfirm} ?disabled=${this._busy}>
|
||||
${i("reset",t)||"Reset"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`:r`
|
||||
<div class="actions primary-row">
|
||||
<button class="btn primary" @click=${this._onComplete} ?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:check"></ha-icon>
|
||||
${i("complete",t)||"Complete"}
|
||||
</button>
|
||||
<button class="btn" @click=${()=>{this._showSkip=!0}} ?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:skip-next"></ha-icon>
|
||||
${i("skip",t)||"Skip"}
|
||||
</button>
|
||||
<button class="btn" @click=${()=>{this._showReset=!0}} ?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:restart"></ha-icon>
|
||||
${i("reset",t)||"Reset"}
|
||||
</button>
|
||||
</div>
|
||||
${s?r`
|
||||
<div class="actions secondary-row">
|
||||
<button class="btn ghost" @click=${this._onEdit} ?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:pencil"></ha-icon>
|
||||
${i("edit",t)||"Edit"}
|
||||
</button>
|
||||
<button class="btn ghost" @click=${this._onQr} ?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:qrcode"></ha-icon>
|
||||
${i("qr_code",t)||"QR"}
|
||||
</button>
|
||||
<button class="btn ghost"
|
||||
@click=${e.archived?this._onUnarchive:this._onArchive}
|
||||
?disabled=${this._busy}>
|
||||
<ha-icon icon="${e.archived?"mdi:archive-arrow-up-outline":"mdi:archive-outline"}"></ha-icon>
|
||||
${e.archived?i("unarchive",t)||"Unarchive":i("archive",t)||"Archive"}
|
||||
</button>
|
||||
<button class="btn ghost danger" @click=${this._onDelete} ?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:delete"></ha-icon>
|
||||
${i("delete",t)||"Delete"}
|
||||
</button>
|
||||
</div>
|
||||
`:l}
|
||||
<div class="details-toggle">
|
||||
<button class="link" @click=${()=>{this._showDetails=!this._showDetails}}>
|
||||
<ha-icon icon="${this._showDetails?"mdi:chevron-up":"mdi:chevron-down"}"></ha-icon>
|
||||
${this._showDetails?i("hide_details",t)||"Hide details":i("show_details",t)||"Show history + stats"}
|
||||
</button>
|
||||
${this._features.adaptive||this._features.seasonal||this._features.environmental?r`<button class="link" @click=${()=>{this._showAdaptive=!this._showAdaptive}}>
|
||||
<ha-icon icon="${this._showAdaptive?"mdi:chart-line":"mdi:chart-line-variant"}"></ha-icon>
|
||||
${this._showAdaptive?i("hide_stats",t)||"Hide stats":i("show_stats",t)||"Show stats + graphs"}
|
||||
</button>`:l}
|
||||
</div>
|
||||
${this._showDetails?this._renderDetails(e):l}
|
||||
${this._showAdaptive?this._renderAdaptive(e):l}
|
||||
<div class="footer">
|
||||
<button class="link" @click=${this._onOpenInPanel}>
|
||||
<ha-icon icon="mdi:open-in-new"></ha-icon>
|
||||
${i("open_in_panel",t)||"Open in Maintenance panel"}
|
||||
</button>
|
||||
</div>
|
||||
`}
|
||||
`:r`<div class="loading">${i("loading",t)||"Loading\u2026"}</div>`}
|
||||
</div>
|
||||
`}};m.styles=[Y,H`
|
||||
:host { display: contents; }
|
||||
.backdrop {
|
||||
position: fixed; inset: 0; z-index: 100;
|
||||
background: rgba(0,0,0,0.5);
|
||||
}
|
||||
.dialog {
|
||||
position: fixed; left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 95vw; max-width: 460px;
|
||||
max-height: 92vh; overflow: auto;
|
||||
background: var(--card-background-color, var(--ha-card-background, #1c1c1c));
|
||||
color: var(--primary-text-color);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
|
||||
padding: 20px;
|
||||
display: flex; flex-direction: column; gap: 14px;
|
||||
z-index: 101;
|
||||
}
|
||||
.header { display: flex; flex-direction: column; gap: 6px; }
|
||||
.title { display: flex; align-items: center; gap: 10px; }
|
||||
.status-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
|
||||
.task-name { font-size: 18px; font-weight: 600; }
|
||||
.object { font-size: 13px; color: var(--secondary-text-color); }
|
||||
.link-inline {
|
||||
background: transparent; border: none; padding: 0; cursor: pointer;
|
||||
color: var(--primary-color); font-size: inherit; font-family: inherit;
|
||||
}
|
||||
.link-inline:hover { text-decoration: underline; }
|
||||
.quick-info {
|
||||
display: flex; flex-wrap: wrap; gap: 12px;
|
||||
font-size: 12px; color: var(--secondary-text-color);
|
||||
padding-top: 4px; border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
.quick-info strong { color: var(--primary-text-color); font-weight: 500; }
|
||||
.actions { display: flex; gap: 8px; }
|
||||
.actions.primary-row { gap: 6px; }
|
||||
.actions.primary-row .btn { flex: 1; }
|
||||
/* Edit + QR are admin-tools — left-align as a group; Delete is destructive
|
||||
so it gets pushed to the far right with margin-left:auto for visual
|
||||
separation. Earlier this row was flex-end which left a strange empty
|
||||
gap on the left (user feedback). */
|
||||
.actions.secondary-row {
|
||||
padding-top: 8px; border-top: 1px solid var(--divider-color);
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.actions.secondary-row .btn.danger {
|
||||
margin-left: auto;
|
||||
}
|
||||
.btn {
|
||||
padding: 8px 12px; font-size: 14px;
|
||||
border-radius: 6px; cursor: pointer;
|
||||
border: 1px solid var(--divider-color);
|
||||
background: var(--secondary-background-color, transparent);
|
||||
color: var(--primary-text-color);
|
||||
font-weight: 500;
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
transition: background 0.12s;
|
||||
}
|
||||
.btn:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
|
||||
.btn[disabled] { opacity: 0.5; cursor: wait; }
|
||||
.btn.primary {
|
||||
background: var(--primary-color);
|
||||
color: var(--text-primary-color, white);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
.btn.cancel { background: transparent; }
|
||||
.btn.ghost { padding: 6px 10px; font-size: 13px; }
|
||||
.btn.danger { color: var(--error-color); }
|
||||
.btn ha-icon { --mdc-icon-size: 18px; }
|
||||
.inline-form { display: flex; flex-direction: column; gap: 8px; }
|
||||
.inline-form label { font-size: 13px; color: var(--secondary-text-color); }
|
||||
.inline-form input {
|
||||
padding: 8px; font-size: 14px;
|
||||
background: var(--secondary-background-color, #2c2c2c);
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color, #444);
|
||||
border-radius: 6px;
|
||||
}
|
||||
.inline-actions { display: flex; gap: 8px; justify-content: flex-end; }
|
||||
.footer { display: flex; justify-content: center; padding-top: 4px; }
|
||||
.link {
|
||||
background: transparent; border: none; cursor: pointer;
|
||||
color: var(--primary-color); font-size: 13px;
|
||||
display: inline-flex; align-items: center; gap: 4px;
|
||||
}
|
||||
.link:hover { text-decoration: underline; }
|
||||
.link ha-icon { --mdc-icon-size: 14px; }
|
||||
.loading { padding: 24px; text-align: center; color: var(--secondary-text-color); }
|
||||
.error {
|
||||
padding: 8px; border-radius: 6px;
|
||||
background: rgba(211,47,47,0.1);
|
||||
color: var(--error-color, #d32f2f); font-size: 13px;
|
||||
}
|
||||
|
||||
/* Details (expandable Show details section) */
|
||||
.details-toggle { display: flex; justify-content: center; margin-top: 4px; }
|
||||
.details {
|
||||
display: flex; flex-direction: column; gap: 12px;
|
||||
border-top: 1px solid var(--divider-color);
|
||||
padding-top: 12px;
|
||||
}
|
||||
.stats-grid {
|
||||
display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px;
|
||||
}
|
||||
.stat {
|
||||
display: flex; flex-direction: column; gap: 2px;
|
||||
background: var(--secondary-background-color, rgba(255,255,255,0.04));
|
||||
padding: 8px; border-radius: 6px;
|
||||
align-items: center;
|
||||
}
|
||||
.stat-label { font-size: 11px; color: var(--secondary-text-color); text-transform: uppercase; letter-spacing: 0.5px; }
|
||||
.stat-value { font-size: 16px; font-weight: 600; }
|
||||
.history-header {
|
||||
display: flex; align-items: baseline; gap: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.history-count {
|
||||
font-size: 12px; color: var(--secondary-text-color);
|
||||
background: var(--secondary-background-color); padding: 2px 8px; border-radius: 999px;
|
||||
}
|
||||
.history-empty { color: var(--secondary-text-color); font-style: italic; font-size: 13px; }
|
||||
.history-list { display: flex; flex-direction: column; gap: 8px; max-height: 280px; overflow: auto; }
|
||||
.history-entry {
|
||||
padding: 6px 8px; border-radius: 6px;
|
||||
background: var(--secondary-background-color, rgba(255,255,255,0.03));
|
||||
font-size: 13px;
|
||||
}
|
||||
.history-line {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.history-type {
|
||||
font-weight: 600; font-size: 11px;
|
||||
padding: 2px 6px; border-radius: 4px;
|
||||
text-transform: uppercase; letter-spacing: 0.5px;
|
||||
}
|
||||
.type-completed { background: rgba(46,125,50,0.2); color: #66bb6a; }
|
||||
.type-skipped { background: rgba(158,158,158,0.2); color: var(--secondary-text-color); }
|
||||
.type-reset { background: rgba(33,150,243,0.2); color: #64b5f6; }
|
||||
.type-triggered { background: rgba(255,87,34,0.2); color: #ff8a65; }
|
||||
.history-date { font-size: 11px; color: var(--secondary-text-color); flex: 1; text-align: right; }
|
||||
.history-edit {
|
||||
background: transparent; border: none; cursor: pointer;
|
||||
padding: 4px; border-radius: 4px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.history-edit:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); color: var(--primary-color); }
|
||||
.history-edit ha-icon { --mdc-icon-size: 14px; }
|
||||
.history-notes { margin-top: 4px; color: var(--primary-text-color); }
|
||||
.history-meta { display: flex; gap: 12px; margin-top: 4px; color: var(--secondary-text-color); font-size: 11px; }
|
||||
.history-more { padding: 8px; text-align: center; font-size: 12px; color: var(--secondary-text-color); font-style: italic; }
|
||||
|
||||
/* Adaptive section — wraps the panel renderers (which assume sharedStyles
|
||||
are present) and adds dialog-specific layout. */
|
||||
.adaptive-stack {
|
||||
display: flex; flex-direction: column; gap: 12px;
|
||||
border-top: 1px solid var(--divider-color);
|
||||
padding-top: 12px;
|
||||
}
|
||||
.adaptive-empty {
|
||||
padding: 16px; text-align: center;
|
||||
color: var(--secondary-text-color);
|
||||
font-style: italic; font-size: 13px;
|
||||
border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
.toast {
|
||||
padding: 8px 12px; border-radius: 6px;
|
||||
background: rgba(76, 175, 80, 0.15);
|
||||
color: #4caf50; font-size: 13px; font-weight: 500;
|
||||
}
|
||||
/* The panel's recommendation-card uses ha-button. We use plain <button>
|
||||
in this dialog's button styles. Re-style the action row to match. */
|
||||
.recommendation-actions {
|
||||
display: flex; gap: 8px; margin-top: 8px;
|
||||
}
|
||||
/* Constrain SVG charts so they fit the dialog width even on mobile. */
|
||||
.weibull-section, .seasonal-card-compact { max-width: 100%; }
|
||||
.weibull-chart svg { max-width: 100%; height: auto; }
|
||||
.details-toggle { gap: 12px; flex-wrap: wrap; }
|
||||
`],h([D({attribute:!1})],m.prototype,"hass",2),h([_()],m.prototype,"_open",2),h([_()],m.prototype,"_entryId",2),h([_()],m.prototype,"_taskId",2),h([_()],m.prototype,"_task",2),h([_()],m.prototype,"_objectName",2),h([_()],m.prototype,"_busy",2),h([_()],m.prototype,"_error",2),h([_()],m.prototype,"_showSkip",2),h([_()],m.prototype,"_showReset",2),h([_()],m.prototype,"_showDetails",2),h([_()],m.prototype,"_showAdaptive",2),h([_()],m.prototype,"_skipReason",2),h([_()],m.prototype,"_resetDate",2),h([_()],m.prototype,"_features",2),h([_()],m.prototype,"_toast",2);customElements.get("maintenance-task-quick-actions-dialog")||customElements.define("maintenance-task-quick-actions-dialog",m);function at(a){return!!a&&/^https?:\/\//i.test(a)}var $=class extends E{constructor(){super(...arguments);this._open=!1;this._entryId=null;this._data=null;this._busy=!1;this._error=""}get _lang(){return P(this.hass)}async openFor(t){this._entryId=t,this._error="",this._open=!0,await this._load()}close(){this._open=!1,this._data=null,this._error=""}async _load(){if(this._entryId)try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId});this._data=t}catch(t){this._error=x(t,this._lang)}}_onEditObject(){!this._entryId||!this._data||import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-ZLYYN2LL.js").then(({openEditObjectDialog:t})=>{t(this._entryId,this._data.object),this.close()})}_onAddTask(){this._entryId&&import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-ZLYYN2LL.js").then(({openCreateTaskDialog:t})=>{t(),this.close()})}async _onDelete(){if(!this._entryId||!this._data)return;let t=i("delete_object_confirm",this._lang)||`Delete "${this._data.object.name}" and all its tasks?`;if(window.confirm(t)){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/delete",entry_id:this._entryId}),this.dispatchEvent(new CustomEvent("object-deleted",{detail:{entry_id:this._entryId},bubbles:!0,composed:!0})),this.close()}catch(e){this._error=x(e,this._lang)}finally{this._busy=!1}}}async _onArchiveObject(){if(!this._entryId||!this._data)return;let t=!!this._data.object.archived;if(!t){let e=i("confirm_archive_object",this._lang)||"Archive this object and its tasks?";if(!window.confirm(e))return}this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:t?"maintenance_supporter/object/unarchive":"maintenance_supporter/object/archive",entry_id:this._entryId}),this.dispatchEvent(new CustomEvent("object-changed",{detail:{entry_id:this._entryId},bubbles:!0,composed:!0})),this.close()}catch(e){this._error=x(e,this._lang)}finally{this._busy=!1}}_onTaskClick(t){this._entryId&&import("/maintenance_supporter_panelfiles/panel-chunks/dialog-mount-ZLYYN2LL.js").then(({openTaskQuickActions:e})=>{e(this._entryId,t)})}render(){if(!this._open)return l;let t=this._lang,e=this._data,s=e?.object,o=e?.tasks||[],d=this.hass?.user?.is_admin??!0;return r`
|
||||
<div class="backdrop" @click=${this.close}></div>
|
||||
<div class="dialog" role="dialog" aria-modal="true">
|
||||
${e&&s?r`
|
||||
<div class="header">
|
||||
<div class="title">${s.name}</div>
|
||||
${this._renderMetaRow(s)}
|
||||
</div>
|
||||
|
||||
${this._error?r`<div class="error">${this._error}</div>`:l}
|
||||
|
||||
<div class="tasks-section">
|
||||
<div class="section-header">
|
||||
<strong>${i("tasks",t)||"Tasks"}</strong>
|
||||
<span class="count">${o.length}</span>
|
||||
</div>
|
||||
${o.length===0?r`<div class="empty">${i("no_tasks",t)||"No tasks yet."}</div>`:r`
|
||||
<div class="task-list">
|
||||
${o.map(c=>r`
|
||||
<div class="task-row" @click=${()=>this._onTaskClick(c.id)}>
|
||||
<span class="status-dot" style="background: ${z[c.status]||"#ccc"}"></span>
|
||||
<span class="task-name">${c.name}</span>
|
||||
<span class="task-status">${i(c.status||"ok",t)}</span>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
|
||||
${s.notes?r`
|
||||
<div class="notes-section">
|
||||
<strong>${i("object_notes_label",t)}</strong>
|
||||
<div class="notes-body">${s.notes}</div>
|
||||
</div>
|
||||
`:l}
|
||||
|
||||
${d?r`
|
||||
<div class="actions">
|
||||
<button class="btn primary" @click=${this._onAddTask} ?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:plus"></ha-icon>
|
||||
${i("add_task",t)||"Add task"}
|
||||
</button>
|
||||
<button class="btn" @click=${this._onEditObject} ?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:pencil"></ha-icon>
|
||||
${i("edit",t)||"Edit"}
|
||||
</button>
|
||||
<button class="btn" @click=${this._onArchiveObject} ?disabled=${this._busy}>
|
||||
<ha-icon icon="${s.archived?"mdi:archive-arrow-up-outline":"mdi:archive-outline"}"></ha-icon>
|
||||
${s.archived?i("unarchive_object",t)||"Unarchive object":i("archive_object",t)||"Archive object"}
|
||||
</button>
|
||||
<button class="btn danger" @click=${this._onDelete} ?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:delete"></ha-icon>
|
||||
${i("delete",t)||"Delete"}
|
||||
</button>
|
||||
</div>
|
||||
`:l}
|
||||
`:r`<div class="loading">${i("loading",t)||"Loading\u2026"}</div>`}
|
||||
</div>
|
||||
`}_renderMetaRow(t){let e=this._lang,s=[];return t.area_id&&s.push([i("area",e),t.area_id]),t.manufacturer&&s.push([i("manufacturer",e),t.manufacturer]),t.model&&s.push([i("model",e),t.model]),t.serial_number&&s.push([i("serial_number_label",e),t.serial_number]),t.installation_date&&s.push([i("installed",e),t.installation_date]),t.warranty_expiry&&s.push([i("warranty",e),t.warranty_expiry]),t.documentation_url&&s.push([i("documentation_url_label",e),t.documentation_url]),s.length===0?l:r`
|
||||
<div class="meta">
|
||||
${s.map(([o,d])=>r`
|
||||
<div class="meta-item">
|
||||
<span class="meta-label">${o}</span>
|
||||
<span class="meta-value">${at(d)?r`<a href="${d}" target="_blank" rel="noopener noreferrer">${d}</a>`:d}</span>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
`}};$.styles=H`
|
||||
:host { display: contents; }
|
||||
.backdrop {
|
||||
position: fixed; inset: 0; z-index: 100; background: rgba(0,0,0,0.5);
|
||||
}
|
||||
.dialog {
|
||||
position: fixed; left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 95vw; max-width: 480px;
|
||||
max-height: 92vh; overflow: auto;
|
||||
background: var(--card-background-color, var(--ha-card-background, #1c1c1c));
|
||||
color: var(--primary-text-color);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
|
||||
padding: 20px; z-index: 101;
|
||||
display: flex; flex-direction: column; gap: 14px;
|
||||
}
|
||||
.header { display: flex; flex-direction: column; gap: 6px; }
|
||||
.title { font-size: 20px; font-weight: 600; }
|
||||
.meta { display: flex; flex-direction: column; gap: 4px; padding-top: 4px; border-top: 1px solid var(--divider-color); }
|
||||
.meta-item { display: flex; gap: 8px; font-size: 12px; }
|
||||
.meta-label { color: var(--secondary-text-color); min-width: 100px; }
|
||||
.meta-value { color: var(--primary-text-color); flex: 1; word-break: break-word; }
|
||||
.meta-value a { color: var(--primary-color); }
|
||||
.tasks-section, .notes-section { display: flex; flex-direction: column; gap: 6px; }
|
||||
.section-header { display: flex; align-items: baseline; gap: 8px; }
|
||||
.count {
|
||||
font-size: 11px; color: var(--secondary-text-color);
|
||||
background: var(--secondary-background-color); padding: 2px 8px; border-radius: 999px;
|
||||
}
|
||||
.empty { color: var(--secondary-text-color); font-style: italic; font-size: 13px; padding: 8px 0; }
|
||||
.task-list { display: flex; flex-direction: column; gap: 4px; max-height: 200px; overflow: auto; }
|
||||
.task-row {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 8px; border-radius: 6px; cursor: pointer;
|
||||
background: var(--secondary-background-color, rgba(255,255,255,0.03));
|
||||
transition: background 0.12s;
|
||||
}
|
||||
.task-row:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
|
||||
.status-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
|
||||
.task-name { flex: 1; font-size: 14px; }
|
||||
.task-status { font-size: 11px; color: var(--secondary-text-color); text-transform: uppercase; }
|
||||
.notes-body { white-space: pre-wrap; font-size: 13px; padding: 8px; background: var(--secondary-background-color); border-radius: 6px; }
|
||||
.actions { display: flex; gap: 8px; padding-top: 8px; border-top: 1px solid var(--divider-color); }
|
||||
.actions .btn { flex: 1; }
|
||||
.btn {
|
||||
padding: 8px; font-size: 13px; border-radius: 6px; cursor: pointer;
|
||||
border: 1px solid var(--divider-color);
|
||||
background: var(--secondary-background-color, transparent);
|
||||
color: var(--primary-text-color); font-weight: 500;
|
||||
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
|
||||
}
|
||||
.btn:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
|
||||
.btn[disabled] { opacity: 0.5; cursor: wait; }
|
||||
.btn.primary { background: var(--primary-color); color: var(--text-primary-color, white); border-color: var(--primary-color); }
|
||||
.btn.danger { color: var(--error-color); }
|
||||
.btn ha-icon { --mdc-icon-size: 16px; }
|
||||
.loading { padding: 24px; text-align: center; color: var(--secondary-text-color); }
|
||||
.error { padding: 8px; border-radius: 6px; background: rgba(211,47,47,0.1); color: var(--error-color); font-size: 13px; }
|
||||
`,h([D({attribute:!1})],$.prototype,"hass",2),h([_()],$.prototype,"_open",2),h([_()],$.prototype,"_entryId",2),h([_()],$.prototype,"_data",2),h([_()],$.prototype,"_busy",2),h([_()],$.prototype,"_error",2);customElements.get("maintenance-object-quick-actions-dialog")||customElements.define("maintenance-object-quick-actions-dialog",$);var nt="maintenance-object-dialog",rt="maintenance-task-dialog",yt="maintenance-history-edit-dialog",gt="maintenance-complete-dialog",bt="maintenance-qr-dialog",xt="maintenance-task-quick-actions-dialog",$t="maintenance-object-quick-actions-dialog";function V(){return document.querySelector("home-assistant")?.hass}function kt(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function A(a){let n=kt(),t=n.querySelector(a)??document.body.querySelector(a);return t?t.parentNode!==n&&n.appendChild(t):(t=document.createElement(a),n.appendChild(t)),t}function L(a){let n=V();if(!n)return!1;a.hass=n;let t=n.language||"en";return N(t)||G(t).then(()=>{a.requestUpdate?.()}),!0}var st={features:{adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1},defaultWarningDays:7},R=null;function ot(a){return R||(R=a.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(n=>({features:n.features??st.features,defaultWarningDays:n.general?.default_warning_days??7})).catch(()=>st),R)}function _e(){let a=A(nt);return L(a)?(a.openCreate(),!0):!1}function me(a,n){let t=A(nt);return L(t)?(t.openEdit(a,n),!0):!1}function ve(){let a=A(rt);if(!L(a))return!1;let n=V();return n?((async()=>{let t=await ot(n),e=a;e.checklistsEnabled=t.features.checklists,e.scheduleTimeEnabled=t.features.schedule_time,e.completionActionsEnabled=t.features.completion_actions,e.defaultWarningDays=t.defaultWarningDays,e.openCreate()})(),!0):!1}function fe(a,n){let t=A(rt);if(!L(t))return!1;let e=V();return e?((async()=>{try{let[s,o]=await Promise.all([e.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:a}),ot(e)]),d=(s.tasks||[]).find(p=>p.id===n);if(!d){console.warn(`openEditTaskDialog: task ${n} not found in entry ${a}`);return}let c=t;c.checklistsEnabled=o.features.checklists,c.scheduleTimeEnabled=o.features.schedule_time,c.completionActionsEnabled=o.features.completion_actions,c.defaultWarningDays=o.defaultWarningDays,await c.openEdit(a,d)}catch(s){console.warn("openEditTaskDialog: failed to load task/features",s)}})(),!0):!1}function ye(a){let n=A(yt);return L(n)?(n.openEdit(a),!0):!1}function ge(a){let n=A(gt);return L(n)?(n.entryId=a.entry_id,n.taskId=a.task_id,n.taskName=a.task_name,n.checklist=a.checklist??[],n.adaptiveEnabled=!!a.adaptive_enabled,n.requiredFields=a.required_completion_fields??[],n.lang=V()?.language||"en",n.open(),!0):!1}function be(a){let n=A(bt);return L(n)?(n.openForTask(a.entry_id,a.task_id,a.object_name,a.task_name),!0):!1}function xe(a,n){let t=A(xt);return L(t)?(t.openFor(a,n),!0):!1}function $e(a){let n=A($t);return L(n)?(n.openFor(a),!0):!1}export{at as a,Q as b,J as c,X as d,et as e,it as f,_e as g,me as h,ve as i,fe as j,ye as k,ge as l,be as m,xe as n,$e as o};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
function m(n,t,e){let o=new Blob([n],{type:e}),r=URL.createObjectURL(o),a=document.createElement("a");a.href=r,a.download=t,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(r),6e4)}function i(n,t){let e=document.createElement("a");e.href=n,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)}async function c(n,t,e=300){return(await n.connection.sendMessagePromise({type:"auth/sign_path",path:t,expires:e})).path}async function s(n,t,e=300){return c(n,`/api/maintenance_supporter/document/${t}`,e)}async function b(n,t,e=""){let o=window.open("about:blank","_blank");try{let r=await s(n,t);o&&(o.location.href=new URL(r+e,window.location.origin).href)}catch(r){throw o&&o.close(),r}}async function g(n,t,e){i(await s(n,t,30),e)}var d=[{key:"name",labelKey:"name",required:!0},{key:"manufacturer",labelKey:"manufacturer"},{key:"model",labelKey:"model"},{key:"serial_number",labelKey:"serial_number_label"},{key:"installation_date",labelKey:"installed"},{key:"warranty_expiry",labelKey:"warranty"},{key:"area_id",labelKey:"area"},{key:"documentation_url",labelKey:"documentation_url_label"},{key:"notes",labelKey:"object_notes_label"},{key:"task_count",labelKey:"tasks"},{key:"actions",labelKey:"actions"}],u=d.map(n=>n.key),l=["name","manufacturer","model","serial_number","installation_date","warranty_expiry","area_id","task_count","actions"];function _(n){if(!Array.isArray(n))return[...l];let t=new Set,e=[];for(let o of n)typeof o=="string"&&u.includes(o)&&!t.has(o)&&(t.add(o),e.push(o));return e.length?(e.includes("name")||e.unshift("name"),e):[...l]}export{m as a,i as b,c,s as d,b as e,g as f,d as g,l as h,_ as i};
|
||||
File diff suppressed because it is too large.
Load diff
+2
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-CWIVA4GR.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-FMV3K4OT.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-7ZFDRUH2.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";export{a as MaintenanceCompleteDialog};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{g as a,h as b,i as c,j as d,k as e,l as f,m as g,n as h,o as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NJUM55WH.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-GF2CJ2A7.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-WP2TGE7S.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-FBSXXMGM.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-CWIVA4GR.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-FMV3K4OT.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-EIEW3O3I.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-DZAYWHWN.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-7ZFDRUH2.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";export{f as openCompleteDialog,a as openCreateObjectDialog,c as openCreateTaskDialog,b as openEditObjectDialog,d as openEditTaskDialog,e as openHistoryEditDialog,i as openObjectQuickActions,g as openQrDialog,h as openTaskQuickActions};
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-GF2CJ2A7.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-FBSXXMGM.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-7ZFDRUH2.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";export{a as MaintenanceObjectDialog};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-EIEW3O3I.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";export{a as MaintenanceQrDialog};
|
||||
+1142
File diff suppressed because it is too large.
Load diff
+146
@@ -0,0 +1,146 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a as g}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-7ZFDRUH2.js";import{a as l,b as m,c as i,f as h,g as v,i as u,j as d,n as p,o as f,q as x}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";var a=class extends v{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._adopting=!1;this._error="";this._setups=[];this._selected=new Set;this._baselines=new Map;this._targets=new Map;this._objects=[];this._localeReady=!1;this._toggle=t=>{let e=new Set(this._selected);e.has(t)?e.delete(t):e.add(t),this._selected=e};this._adopt=async()=>{if(!(this._selected.size===0||this._adopting)){this._adopting=!0,this._error="";try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/integration_setups/adopt",selections:[...this._selected].map(e=>{let r={device_id:e},c=this._targets.get(e);c&&(r.entry_id=c);let s=this._setups.find(n=>n.device_id===e);for(let n of s?.tasks??[]){let o=this._baselines.get(`${e} ${n.task_name}`),_=o?parseFloat(o):NaN;!isNaN(_)&&_>=0&&((r.baselines??={})[n.task_name]=_)}return r})});this.dispatchEvent(new CustomEvent("integration-setups-adopted",{bubbles:!0,composed:!0,detail:t})),this._open=!1}catch(t){this._error=g(t,this._lang)}finally{this._adopting=!1}}}}get _lang(){return f(this.hass)}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,x(this._lang).then(()=>this.requestUpdate()))}async open(){this._open=!0,this._loading=!0,this._error="",this._setups=[],this._selected=new Set;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/integration_setups/discover"});this._setups=t.setups||[],this._selected=new Set(this._setups.map(e=>e.device_id)),this._baselines=new Map,this._targets=new Map;try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"});this._objects=(e.objects||[]).map(r=>({entry_id:r.entry_id,name:r.object?.name||r.entry_id})).sort((r,c)=>r.name.localeCompare(c.name))}catch{this._objects=[]}}catch(t){this._error=g(t,this._lang)}finally{this._loading=!1}}_close(){this._open=!1}render(){if(!this._open)return i``;let t=this._lang;return i`
|
||||
<div class="overlay" @click=${this._close}>
|
||||
<div class="card" @click=${e=>e.stopPropagation()}>
|
||||
<div class="title">${p("setups_title",t)}</div>
|
||||
<div class="hint">${p("setups_hint",t)}</div>
|
||||
${this._error?i`<div class="error">${this._error}</div>`:h}
|
||||
|
||||
${this._loading?i`<div class="loading">…</div>`:this._setups.length===0?i`<div class="empty">${p("setups_none",t)}</div>`:i`
|
||||
<div class="list">
|
||||
${this._setups.map(e=>{let r=this._selected.has(e.device_id),c=[e.integration_name,e.area_name].filter(Boolean).join(" \xB7 ");return i`
|
||||
<label class="row">
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${r}
|
||||
@change=${()=>this._toggle(e.device_id)}
|
||||
/>
|
||||
<div class="row-main">
|
||||
<div class="row-top">
|
||||
<span class="row-name">${e.device_name}</span>
|
||||
</div>
|
||||
<div class="row-sub">${c}</div>
|
||||
<div class="row-target" @click=${s=>s.preventDefault()}>
|
||||
→
|
||||
${r&&this._objects.length>0?i`
|
||||
<select
|
||||
class="target-select"
|
||||
@change=${s=>{let n=new Map(this._targets),o=s.target.value;o?n.set(e.device_id,o):n.delete(e.device_id),this._targets=n}}
|
||||
>
|
||||
<option value="" ?selected=${!this._targets.get(e.device_id)}>
|
||||
${e.suggested_entry_id?e.suggested_object_name:p("setups_target_new",t).replace("{name}",e.suggested_object_name)}
|
||||
</option>
|
||||
${this._objects.filter(s=>s.entry_id!==e.suggested_entry_id).map(s=>i`<option
|
||||
value=${s.entry_id}
|
||||
?selected=${this._targets.get(e.device_id)===s.entry_id}
|
||||
>
|
||||
${s.name}
|
||||
</option>`)}
|
||||
</select>
|
||||
`:i`${e.suggested_object_name}${e.suggested_entry_id?h:i` <span class="new-tag">${p("adopt_problem_new_object",t)}</span>`}`}
|
||||
</div>
|
||||
<div class="row-tasks">
|
||||
${e.tasks.map(s=>i`<span class="chip" title=${s.entity_ids.join(", ")}>
|
||||
<ha-icon icon="mdi:link-variant"></ha-icon>${s.task_name_localized||s.task_name}
|
||||
</span>`)}
|
||||
</div>
|
||||
${r?e.tasks.filter(s=>s.direction==="usage_delta").map(s=>{let n=`${e.device_id} ${s.task_name}`;return i`
|
||||
<div class="baseline-field" @click=${o=>o.preventDefault()}>
|
||||
<span class="baseline-label"
|
||||
>${s.task_name_localized||s.task_name} —
|
||||
${p("setups_baseline_hint",t)}</span
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
step="any"
|
||||
min="0"
|
||||
.value=${this._baselines.get(n)??""}
|
||||
@click=${o=>o.preventDefault()}
|
||||
@input=${o=>{let _=new Map(this._baselines);_.set(n,o.target.value),this._baselines=_}}
|
||||
/>
|
||||
</div>
|
||||
`}):h}
|
||||
</div>
|
||||
</label>
|
||||
`})}
|
||||
</div>
|
||||
`}
|
||||
|
||||
<div class="actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${p("cancel",t)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._adopt}
|
||||
.disabled=${this._selected.size===0||this._adopting}
|
||||
>
|
||||
${p("setups_adopt",t)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`}};a.styles=m`
|
||||
.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
min-width: min(360px, calc(100vw - 24px));
|
||||
max-width: 560px;
|
||||
width: 90vw;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.title { font-size: 18px; font-weight: 500; }
|
||||
.hint { color: var(--secondary-text-color); font-size: 13px; }
|
||||
.error { color: var(--error-color, #f44336); font-size: 13px; }
|
||||
.loading, .empty { color: var(--secondary-text-color); font-size: 14px; padding: 12px 0; }
|
||||
.list { display: flex; flex-direction: column; gap: 6px; overflow-y: auto; max-height: 50vh; }
|
||||
.row {
|
||||
display: flex; align-items: flex-start; gap: 10px; padding: 8px;
|
||||
border: 1px solid var(--divider-color); border-radius: 6px; cursor: pointer;
|
||||
}
|
||||
.row input { margin-top: 2px; cursor: pointer; }
|
||||
.row-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
|
||||
.row-name { font-weight: 500; font-size: 13px; }
|
||||
.row-sub, .row-target { color: var(--secondary-text-color); font-size: 12px; }
|
||||
.new-tag { font-style: italic; }
|
||||
.row-tasks { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; }
|
||||
.chip {
|
||||
display: inline-flex; align-items: center; gap: 4px;
|
||||
font-size: 11px; padding: 2px 8px; border-radius: 10px;
|
||||
background: var(--secondary-background-color, rgba(0, 0, 0, 0.06));
|
||||
color: var(--primary-text-color); white-space: nowrap;
|
||||
}
|
||||
.chip ha-icon { --mdc-icon-size: 12px; color: var(--primary-color); }
|
||||
.target-select {
|
||||
font-size: 12px; padding: 2px 4px; max-width: 100%;
|
||||
border: 1px solid var(--divider-color); border-radius: 4px;
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.baseline-field {
|
||||
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
|
||||
margin-top: 4px; font-size: 12px; color: var(--secondary-text-color);
|
||||
}
|
||||
.baseline-field input {
|
||||
width: 110px; padding: 3px 6px; font-size: 12px;
|
||||
border: 1px solid var(--divider-color); border-radius: 4px;
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.actions { display: flex; justify-content: flex-end; gap: 8px; padding-top: 8px; }
|
||||
`,l([u({attribute:!1})],a.prototype,"hass",2),l([d()],a.prototype,"_open",2),l([d()],a.prototype,"_loading",2),l([d()],a.prototype,"_adopting",2),l([d()],a.prototype,"_error",2),l([d()],a.prototype,"_setups",2),l([d()],a.prototype,"_selected",2),l([d()],a.prototype,"_baselines",2),l([d()],a.prototype,"_targets",2),l([d()],a.prototype,"_objects",2);customElements.get("maintenance-suggested-setups-dialog")||customElements.define("maintenance-suggested-setups-dialog",a);export{a as MaintenanceSuggestedSetupsDialog};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WP2TGE7S.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-FBSXXMGM.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-FMV3K4OT.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-DZAYWHWN.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-7ZFDRUH2.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-DD2OCRNH.js";export{a as MaintenanceTaskDialog};
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a as m,b as f}from"./chunk-KBMB3TAQ.js";import{a as u,b as l,d as h,e as b,f as y,g as o,h as g,i as a,j as v,l as _,u as p}from"./chunk-QC7DYHKY.js";import{a as n}from"./chunk-DSAXFRSJ.js";var k=80,s=class extends b{constructor(){super(...arguments);this._config={type:""};this._status=null;this._busy=!1;this._error="";this._localMonthly="";this._localYearly="";this._dirty=!1;this._loaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return v(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load(),_(this._lang).then(()=>this.requestUpdate()))}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/budget_status"});this._status=t,this._localMonthly=t.monthly_budget?String(t.monthly_budget):"",this._localYearly=t.yearly_budget?String(t.yearly_budget):"",this._dirty=!1}catch(t){this._error=p(t,this._lang)}}async _save(){if(this._isAdmin){this._busy=!0,this._error="";try{let t=parseFloat(this._localMonthly),r=parseFloat(this._localYearly),i={};!isNaN(t)&&t>=0&&(i.budget_monthly=t),!isNaN(r)&&r>=0&&(i.budget_yearly=r),await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/global/update",settings:i}),await this._load()}catch(t){this._error=p(t,this._lang)}finally{this._busy=!1}}}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_budget"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,r=this._status;if(!r)return l`<ha-card><div class="loading">${a("loading",t)||"Loading\u2026"}</div></ha-card>`;let i=r.currency_symbol||g,x=r.alert_threshold_pct??k,$=[{label:a("budget_monthly",t)||"Monthly",spent:r.monthly_spent||0,budget:r.monthly_budget||0},{label:a("budget_yearly",t)||"Yearly",spent:r.yearly_spent||0,budget:r.yearly_budget||0}];return l`
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<span class="emoji">💰</span>
|
||||
<span>${this._config.title||a("settings_budget",t)||"Budget"}</span>
|
||||
</div>
|
||||
<span class="currency">${i}</span>
|
||||
</div>
|
||||
|
||||
${this._error?l`<div class="error">${this._error}</div>`:h}
|
||||
|
||||
${$.map(e=>{if(!(e.budget>0))return l`
|
||||
<div class="track spent-only">
|
||||
<div class="track-label-row">
|
||||
<label>${e.label}</label>
|
||||
<span class="track-numbers ok">${e.spent.toFixed(0)} ${i}</span>
|
||||
</div>
|
||||
</div>
|
||||
`;let d=Math.min(100,Math.max(0,e.spent/e.budget*100)),c=d>=100?"danger":d>=x?"warning":"ok";return l`
|
||||
<div class="track">
|
||||
<div class="track-label-row">
|
||||
<label>${e.label}</label>
|
||||
<span class="track-numbers ${c}">
|
||||
${e.spent.toFixed(0)} / ${e.budget.toFixed(0)} ${i}
|
||||
</span>
|
||||
</div>
|
||||
<div class="bar"><div class="bar-fill ${c}" style="width:${d}%"></div></div>
|
||||
</div>
|
||||
`})}
|
||||
|
||||
${this._isAdmin?l`
|
||||
<div class="inputs-row">
|
||||
<div class="input-field">
|
||||
<label>${a("budget_monthly_set",t)||"Set monthly"}</label>
|
||||
<div class="input-wrap">
|
||||
<input type="number" min="0" step="1"
|
||||
.value=${this._localMonthly}
|
||||
?disabled=${this._busy}
|
||||
@input=${e=>{this._localMonthly=e.target.value,this._dirty=!0}} />
|
||||
<span class="input-suffix">${i}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-field">
|
||||
<label>${a("budget_yearly_set",t)||"Set yearly"}</label>
|
||||
<div class="input-wrap">
|
||||
<input type="number" min="0" step="1"
|
||||
.value=${this._localYearly}
|
||||
?disabled=${this._busy}
|
||||
@input=${e=>{this._localYearly=e.target.value,this._dirty=!0}} />
|
||||
<span class="input-suffix">${i}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn ${this._dirty?"primary":"muted"}"
|
||||
@click=${this._save}
|
||||
?disabled=${this._busy||!this._dirty}>
|
||||
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
|
||||
${this._dirty?a("save",t)||"Save":a("saved",t)||"Saved"}
|
||||
</button>
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${a("budget_advanced",t)||"Currency, alerts\u2026"}
|
||||
</button>
|
||||
</div>
|
||||
`:l`
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${a("budget_open_panel",t)||"Open in panel"}
|
||||
</button>
|
||||
`}
|
||||
</div>
|
||||
</ha-card>
|
||||
`}};s.styles=[f,u`
|
||||
.currency {
|
||||
font-size: 14px; font-weight: 600;
|
||||
color: var(--secondary-text-color);
|
||||
background: var(--secondary-background-color);
|
||||
padding: 2px 10px; border-radius: 999px;
|
||||
}
|
||||
.track { display: flex; flex-direction: column; gap: 4px; }
|
||||
.track-label-row {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
}
|
||||
.track-label-row label {
|
||||
font-size: 12px; color: var(--secondary-text-color);
|
||||
text-transform: uppercase; letter-spacing: 0.5px;
|
||||
}
|
||||
.track-numbers { font-size: 13px; font-weight: 600; }
|
||||
.track-numbers.ok { color: var(--primary-text-color); }
|
||||
.track-numbers.warning { color: #ff9800; }
|
||||
.track-numbers.danger { color: var(--error-color, #f44336); }
|
||||
.bar {
|
||||
height: 6px; background: var(--secondary-background-color);
|
||||
border-radius: 3px; overflow: hidden;
|
||||
}
|
||||
.bar-fill { height: 100%; transition: width 0.3s; border-radius: 3px; }
|
||||
.bar-fill.ok { background: var(--primary-color); }
|
||||
.bar-fill.warning { background: #ff9800; }
|
||||
.bar-fill.danger { background: var(--error-color, #f44336); }
|
||||
.inputs-row {
|
||||
display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
|
||||
padding-top: 4px; border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
.input-field { display: flex; flex-direction: column; gap: 4px; }
|
||||
.input-field label {
|
||||
font-size: 11px; color: var(--secondary-text-color);
|
||||
text-transform: uppercase; letter-spacing: 0.3px;
|
||||
}
|
||||
.input-wrap { position: relative; display: flex; align-items: center; }
|
||||
.input-wrap input {
|
||||
flex: 1; padding: 6px 32px 6px 8px; font-size: 13px;
|
||||
background: var(--secondary-background-color, #2c2c2c);
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
font-family: inherit;
|
||||
}
|
||||
.input-suffix {
|
||||
position: absolute; right: 8px;
|
||||
color: var(--secondary-text-color); font-size: 13px;
|
||||
pointer-events: none;
|
||||
}
|
||||
.actions { display: flex; gap: 8px; align-items: center; }
|
||||
`],n([y({attribute:!1})],s.prototype,"hass",2),n([o()],s.prototype,"_config",2),n([o()],s.prototype,"_status",2),n([o()],s.prototype,"_busy",2),n([o()],s.prototype,"_error",2),n([o()],s.prototype,"_localMonthly",2),n([o()],s.prototype,"_localYearly",2),n([o()],s.prototype,"_dirty",2);customElements.get("maintenance-budget-section-card")||customElements.define("maintenance-budget-section-card",s);m({type:"maintenance-budget-section-card",name:"Maintenance Supporter \u2014 Budget",description:"Inline monthly + yearly budget editor",preview:!1});export{s as MaintenanceBudgetSectionCard};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
var s=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var t=(a,r,c,o)=>{for(var e=o>1?void 0:o?l(r,c):r,i=a.length-1,d;i>=0;i--)(d=a[i])&&(e=(o?d(r,c,e):d(e))||e);return o&&e&&s(r,c,e),e};var m={ok:"var(--success-color, #4caf50)",due_soon:"var(--warning-color, #ff9800)",overdue:"var(--error-color, #f44336)",triggered:"var(--deep-orange-color, #ff5722)",archived:"var(--disabled-color, #9e9e9e)",paused:"var(--info-color, #2196f3)"},v={ok:"mdi:check-circle",due_soon:"mdi:alert-circle",overdue:"mdi:alert-octagon",triggered:"mdi:bell-alert",archived:"mdi:archive-outline",paused:"mdi:pause-circle-outline",completed:"mdi:check-circle",skipped:"mdi:skip-next",missed:"mdi:calendar-remove",reset:"mdi:refresh"};export{t as a,m as b,v as c};
|
||||
@@ -0,0 +1,60 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a as t}from"./chunk-QC7DYHKY.js";function e(o){let r=window;r.customCards=r.customCards||[],r.customCards.some(a=>a.type===o.type)||r.customCards.push(o)}var d=t`
|
||||
ha-card { overflow: hidden; }
|
||||
.card-content {
|
||||
padding: 16px;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
.header {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
.title {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
font-size: 16px; font-weight: 500;
|
||||
}
|
||||
.emoji { font-size: 20px; }
|
||||
|
||||
/* Button family — primary action / muted-saved-state / link / icon-with-text */
|
||||
.btn {
|
||||
padding: 6px 12px; font-size: 13px;
|
||||
border-radius: 6px; cursor: pointer;
|
||||
border: 1px solid var(--divider-color);
|
||||
background: var(--secondary-background-color, transparent);
|
||||
color: var(--primary-text-color);
|
||||
font-weight: 500;
|
||||
display: inline-flex; align-items: center; gap: 4px;
|
||||
}
|
||||
.btn:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
|
||||
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
|
||||
.btn.primary {
|
||||
background: var(--primary-color);
|
||||
color: var(--text-primary-color, white);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
.btn.primary[disabled] { opacity: 0.6; }
|
||||
.btn.muted {
|
||||
background: transparent;
|
||||
color: var(--secondary-text-color);
|
||||
border-style: dashed;
|
||||
}
|
||||
.btn.muted[disabled] { opacity: 1; cursor: default; }
|
||||
.btn.muted ha-icon, .btn.primary ha-icon { --mdc-icon-size: 14px; }
|
||||
.btn.link {
|
||||
background: transparent; border: none; padding: 6px 4px;
|
||||
color: var(--primary-color); margin-left: auto;
|
||||
}
|
||||
.btn.link:hover { background: transparent; text-decoration: underline; }
|
||||
|
||||
/* Error + loading states */
|
||||
.error {
|
||||
padding: 8px; border-radius: 6px;
|
||||
background: rgba(211, 47, 47, 0.1);
|
||||
color: var(--error-color, #d32f2f); font-size: 13px;
|
||||
}
|
||||
.loading {
|
||||
padding: 24px; text-align: center;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
`;export{e as a,d as b};
|
||||
File diff suppressed because it is too large.
Load diff
+2633
File diff suppressed because it is too large.
Load diff
+137
@@ -0,0 +1,137 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a as v,b}from"./chunk-KBMB3TAQ.js";import{a as u,b as s,d as c,e as h,f as g,g as o,i,j as _,l as m,u as p}from"./chunk-QC7DYHKY.js";import{a}from"./chunk-DSAXFRSJ.js";var e=class extends h{constructor(){super(...arguments);this._config={type:""};this._groups={};this._loaded=!1;this._busy=!1;this._error="";this._newName="";this._editingId=null;this._editingName="";this._hasInitiallyLoaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return _(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._hasInitiallyLoaded&&(this._hasInitiallyLoaded=!0,this._load(),m(this._lang).then(()=>this.requestUpdate()))}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/groups"});this._groups=t.groups||{},this._loaded=!0}catch(t){this._error=p(t,this._lang)}}async _addGroup(){if(!this._isAdmin)return;let t=this._newName.trim();if(t){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/create",name:t}),this._newName="",await this._load()}catch(r){this._error=p(r,this._lang)}finally{this._busy=!1}}}_startEdit(t){this._editingId=t,this._editingName=this._groups[t]?.name||""}async _saveEdit(){if(!this._isAdmin||!this._editingId)return;let t=this._editingName.trim();if(t){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/update",group_id:this._editingId,name:t}),this._editingId=null,this._editingName="",await this._load()}catch(r){this._error=p(r,this._lang)}finally{this._busy=!1}}}async _deleteGroup(t,r){if(!this._isAdmin)return;let n=(i("group_delete_confirm",this._lang)||'Delete group "{name}"?').replace("{name}",r);if(window.confirm(n)){this._busy=!0;try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/delete",group_id:t}),await this._load()}catch(d){this._error=p(d,this._lang)}finally{this._busy=!1}}}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_groups"),window.dispatchEvent(new CustomEvent("location-changed"))}_onKeyDown(t,r){t.key==="Enter"?(t.preventDefault(),r()):t.key==="Escape"&&(t.preventDefault(),this._editingId=null,this._editingName="")}render(){let t=this._lang;if(!this._loaded)return s`<ha-card><div class="loading">${i("loading",t)||"Loading\u2026"}</div></ha-card>`;let r=Object.keys(this._groups);return s`
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<span class="emoji">🏷️</span>
|
||||
<span>${this._config.title||i("groups",t)||"Groups"}</span>
|
||||
<span class="count">${r.length}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${this._error?s`<div class="error">${this._error}</div>`:c}
|
||||
|
||||
${r.length===0?s`<div class="empty">${i("groups_empty",t)||"No groups yet."}</div>`:s`
|
||||
<div class="group-list">
|
||||
${r.map(n=>{let d=this._groups[n],y=d.task_refs?.length??0,f=this._editingId===n;return s`
|
||||
<div class="group-row">
|
||||
${f?s`
|
||||
<input class="edit-input" type="text"
|
||||
.value=${this._editingName}
|
||||
?disabled=${this._busy}
|
||||
@input=${l=>{this._editingName=l.target.value}}
|
||||
@keydown=${l=>this._onKeyDown(l,this._saveEdit.bind(this))} />
|
||||
<button class="btn small primary"
|
||||
@click=${this._saveEdit}
|
||||
?disabled=${this._busy||!this._editingName.trim()}>
|
||||
${i("save",t)||"Save"}
|
||||
</button>
|
||||
<button class="btn small"
|
||||
@click=${()=>{this._editingId=null}}>
|
||||
${i("cancel",t)||"Cancel"}
|
||||
</button>
|
||||
`:s`
|
||||
<span class="group-name">${d.name||"Unnamed"}</span>
|
||||
<span class="task-count">${y}</span>
|
||||
${this._isAdmin?s`
|
||||
<button class="icon-btn"
|
||||
title="${i("edit",t)||"Edit"}"
|
||||
@click=${()=>this._startEdit(n)}
|
||||
?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:pencil"></ha-icon>
|
||||
</button>
|
||||
<button class="icon-btn danger"
|
||||
title="${i("delete",t)||"Delete"}"
|
||||
@click=${()=>this._deleteGroup(n,d.name||"Unnamed")}
|
||||
?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:delete"></ha-icon>
|
||||
</button>
|
||||
`:c}
|
||||
`}
|
||||
</div>
|
||||
`})}
|
||||
</div>
|
||||
`}
|
||||
|
||||
${this._isAdmin?s`
|
||||
<div class="add-row">
|
||||
<input type="text"
|
||||
placeholder="${i("group_new_placeholder",t)||"Add group\u2026"}"
|
||||
.value=${this._newName}
|
||||
?disabled=${this._busy}
|
||||
@input=${n=>{this._newName=n.target.value}}
|
||||
@keydown=${n=>this._onKeyDown(n,this._addGroup.bind(this))} />
|
||||
<button class="btn primary"
|
||||
@click=${this._addGroup}
|
||||
?disabled=${this._busy||!this._newName.trim()}>
|
||||
<ha-icon icon="mdi:plus"></ha-icon>
|
||||
${i("add",t)||"Add"}
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${i("groups_manage_tasks",t)||"Manage task assignments\u2026"}
|
||||
</button>
|
||||
`:s`
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${i("groups_open_panel",t)||"Open in panel"}
|
||||
</button>
|
||||
`}
|
||||
</div>
|
||||
</ha-card>
|
||||
`}};e.styles=[b,u`
|
||||
.count {
|
||||
font-size: 12px; color: var(--secondary-text-color);
|
||||
background: var(--secondary-background-color);
|
||||
padding: 2px 8px; border-radius: 999px;
|
||||
}
|
||||
.empty {
|
||||
padding: 16px; text-align: center;
|
||||
color: var(--secondary-text-color); font-style: italic;
|
||||
}
|
||||
.group-list { display: flex; flex-direction: column; gap: 4px; }
|
||||
.group-row {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 6px 8px; border-radius: 6px;
|
||||
background: var(--secondary-background-color, rgba(255,255,255,0.03));
|
||||
}
|
||||
.group-name { flex: 1; font-size: 14px; }
|
||||
.task-count {
|
||||
font-size: 11px; color: var(--secondary-text-color);
|
||||
background: var(--card-background-color, rgba(0,0,0,0.2));
|
||||
padding: 1px 8px; border-radius: 999px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.edit-input {
|
||||
flex: 1; padding: 4px 8px; font-size: 14px;
|
||||
background: var(--card-background-color, #1c1c1c);
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--primary-color); border-radius: 4px;
|
||||
font-family: inherit;
|
||||
}
|
||||
.icon-btn {
|
||||
background: transparent; border: none; cursor: pointer;
|
||||
color: var(--secondary-text-color); padding: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.icon-btn:hover {
|
||||
background: var(--state-icon-color, rgba(255,255,255,0.06));
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.icon-btn.danger:hover { color: var(--error-color); }
|
||||
.icon-btn ha-icon { --mdc-icon-size: 18px; }
|
||||
.add-row {
|
||||
display: flex; gap: 6px;
|
||||
padding-top: 8px; border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
.add-row input {
|
||||
flex: 1; padding: 6px 8px; font-size: 13px;
|
||||
background: var(--secondary-background-color, #2c2c2c);
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
font-family: inherit;
|
||||
}
|
||||
/* Card-specific overrides on the shared .btn */
|
||||
.btn.small { padding: 4px 8px; font-size: 12px; }
|
||||
.btn ha-icon { --mdc-icon-size: 16px; }
|
||||
`],a([g({attribute:!1})],e.prototype,"hass",2),a([o()],e.prototype,"_config",2),a([o()],e.prototype,"_groups",2),a([o()],e.prototype,"_loaded",2),a([o()],e.prototype,"_busy",2),a([o()],e.prototype,"_error",2),a([o()],e.prototype,"_newName",2),a([o()],e.prototype,"_editingId",2),a([o()],e.prototype,"_editingName",2);customElements.get("maintenance-groups-section-card")||customElements.define("maintenance-groups-section-card",e);v({type:"maintenance-groups-section-card",name:"Maintenance Supporter \u2014 Groups",description:"Inline group CRUD",preview:!1});export{e as MaintenanceGroupsSectionCard};
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{a as m,b as g}from"./chunk-KBMB3TAQ.js";import{a as h,b as n,d as c,e as _,f as v,g as r,i as e,j as f,l as b,u as l}from"./chunk-QC7DYHKY.js";import{a as i}from"./chunk-DSAXFRSJ.js";var a=class extends _{constructor(){super(...arguments);this._config={type:""};this._state=null;this._busy=!1;this._error="";this._localStart="";this._localEnd="";this._localBuffer=7;this._dirty=!1;this._loaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return f(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load(),b(this._lang).then(()=>this.requestUpdate()))}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/state"});this._state=t,this._localStart=t.start||"",this._localEnd=t.end||"",this._localBuffer=t.buffer_days??7,this._dirty=!1}catch(t){this._error=l(t,this._lang)}}async _toggleEnabled(t){this._busy=!0,this._error="";try{let s=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/update",enabled:t});this._state=s}catch(s){this._error=l(s,this._lang)}finally{this._busy=!1}}async _save(){if(this._isAdmin){this._busy=!0,this._error="";try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/update",start:this._localStart||null,end:this._localEnd||null,buffer_days:this._localBuffer});this._state=t,this._dirty=!1}catch(t){this._error=l(t,this._lang)}finally{this._busy=!1}}}async _endNow(){if(this._isAdmin&&window.confirm(e("vacation_end_now_confirm",this._lang)||"End vacation immediately?")){this._busy=!0;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/end_now"});this._state=t,this._localStart=t.start||"",this._localEnd=t.end||""}catch(t){this._error=l(t,this._lang)}finally{this._busy=!1}}}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_vacation"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,s=this._state;if(!s)return n`<ha-card><div class="loading">${e("loading",t)||"Loading\u2026"}</div></ha-card>`;let p=s.is_active===!0,d=s.enabled===!0,u=s.exempt_task_ids?.length??0,y=p?e("vacation_status_active",t)||"Active now":d?e("vacation_status_scheduled",t)||"Scheduled":e("vacation_status_inactive",t)||"Inactive",$=p?"active":d?"scheduled":"inactive";return n`
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<span class="emoji">🏖️</span>
|
||||
<span>${this._config.title||e("vacation_mode",t)||"Vacation mode"}</span>
|
||||
</div>
|
||||
<span class="status-pill ${$}">${y}</span>
|
||||
</div>
|
||||
|
||||
${this._error?n`<div class="error">${this._error}</div>`:c}
|
||||
|
||||
${this._isAdmin?n`
|
||||
<div class="row toggle-row">
|
||||
<label>${e("enable",t)||"Enable"}</label>
|
||||
<ha-switch
|
||||
.checked=${d}
|
||||
.disabled=${this._busy}
|
||||
@change=${o=>this._toggleEnabled(o.target.checked)}
|
||||
></ha-switch>
|
||||
</div>
|
||||
|
||||
<div class="dates-row">
|
||||
<div class="date-field">
|
||||
<label>${e("vacation_start",t)||"Start"}</label>
|
||||
<input type="date" .value=${this._localStart}
|
||||
?disabled=${this._busy}
|
||||
@input=${o=>{this._localStart=o.target.value,this._dirty=!0}} />
|
||||
</div>
|
||||
<div class="date-field">
|
||||
<label>${e("vacation_end",t)||"End"}</label>
|
||||
<input type="date" .value=${this._localEnd}
|
||||
?disabled=${this._busy}
|
||||
@input=${o=>{this._localEnd=o.target.value,this._dirty=!0}} />
|
||||
</div>
|
||||
<div class="date-field buffer">
|
||||
<label>${e("vacation_buffer",t)||"Buffer days"}</label>
|
||||
<input type="number" min="0" max="14"
|
||||
.value=${String(this._localBuffer)}
|
||||
?disabled=${this._busy}
|
||||
@input=${o=>{this._localBuffer=parseInt(o.target.value,10)||0,this._dirty=!0}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button class="btn ${this._dirty?"primary":"muted"}"
|
||||
@click=${this._save}
|
||||
?disabled=${this._busy||!this._dirty}>
|
||||
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
|
||||
${this._dirty?e("save",t)||"Save":e("saved",t)||"Saved"}
|
||||
</button>
|
||||
${p?n`<button class="btn"
|
||||
@click=${this._endNow}
|
||||
?disabled=${this._busy}>
|
||||
${e("vacation_end_now",t)||"End now"}
|
||||
</button>`:c}
|
||||
${u>0?n`<button class="btn link"
|
||||
@click=${this._onDeepLink}>
|
||||
${u} ${e("vacation_exempt_count",t)||"exempt"}…
|
||||
</button>`:n`<button class="btn link"
|
||||
@click=${this._onDeepLink}>
|
||||
${e("vacation_advanced",t)||"Advanced\u2026"}
|
||||
</button>`}
|
||||
</div>
|
||||
`:n`
|
||||
<div class="readonly">
|
||||
${d&&s.start&&s.end?n`<div>${s.start} → ${s.end}</div>`:c}
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${e("vacation_open_panel",t)||"Open in panel"}
|
||||
</button>
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
</ha-card>
|
||||
`}};a.styles=[g,h`
|
||||
.status-pill {
|
||||
font-size: 11px; font-weight: 600;
|
||||
padding: 3px 8px; border-radius: 999px;
|
||||
text-transform: uppercase; letter-spacing: 0.5px;
|
||||
}
|
||||
.status-pill.active {
|
||||
background: rgba(76, 175, 80, 0.15);
|
||||
color: #4caf50;
|
||||
}
|
||||
.status-pill.scheduled {
|
||||
background: rgba(255, 152, 0, 0.15);
|
||||
color: #ff9800;
|
||||
}
|
||||
.status-pill.inactive {
|
||||
background: rgba(158, 158, 158, 0.15);
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.row.toggle-row {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
}
|
||||
.row.toggle-row label {
|
||||
font-size: 14px; color: var(--primary-text-color);
|
||||
}
|
||||
.dates-row {
|
||||
display: grid; grid-template-columns: 1fr 1fr 100px; gap: 10px;
|
||||
}
|
||||
.date-field.buffer label { white-space: nowrap; }
|
||||
.date-field { display: flex; flex-direction: column; gap: 4px; }
|
||||
.date-field label {
|
||||
font-size: 11px; color: var(--secondary-text-color);
|
||||
text-transform: uppercase; letter-spacing: 0.3px;
|
||||
}
|
||||
.date-field input {
|
||||
padding: 6px 8px; font-size: 13px;
|
||||
background: var(--secondary-background-color, #2c2c2c);
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
font-family: inherit;
|
||||
}
|
||||
.date-field input:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.actions {
|
||||
display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
|
||||
}
|
||||
.readonly { display: flex; flex-direction: column; gap: 8px; }
|
||||
`],i([v({attribute:!1})],a.prototype,"hass",2),i([r()],a.prototype,"_config",2),i([r()],a.prototype,"_state",2),i([r()],a.prototype,"_busy",2),i([r()],a.prototype,"_error",2),i([r()],a.prototype,"_localStart",2),i([r()],a.prototype,"_localEnd",2),i([r()],a.prototype,"_localBuffer",2),i([r()],a.prototype,"_dirty",2);customElements.get("maintenance-vacation-section-card")||customElements.define("maintenance-vacation-section-card",a);m({type:"maintenance-vacation-section-card",name:"Maintenance Supporter \u2014 Vacation",description:"Inline vacation mode toggle + dates",preview:!1});export{a as MaintenanceVacationSectionCard};
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*! maintenance_supporter frontend 2.58.0 */
|
||||
import{c as y}from"./chunks/chunk-PAZTCVYX.js";var L="maintenance-supporter",G=`ll-strategy-dashboard-${L}`,x="hui-maintenance-supporter-strategy-editor",V="NOT_RUNNING",H=[{status:"overdue",title:"Overdue",icon:y.overdue,path:"overdue"},{status:"triggered",title:"Triggered",icon:y.triggered,path:"triggered"},{status:"due_soon",title:"Due Soon",icon:y.due_soon,path:"due-soon"},{status:"ok",title:"OK",icon:y.ok,path:"ok"}],E=[{title:"Overdue",icon:"mdi:alert-circle",path:"overdue",filter:{filter_due_max_days:-1},matches:n=>n<=-1},{title:"Today",icon:"mdi:calendar-today",path:"today",filter:{filter_due_min_days:0,filter_due_max_days:0},matches:n=>n===0},{title:"This Week",icon:"mdi:calendar-week",path:"this-week",filter:{filter_due_min_days:1,filter_due_max_days:7},matches:n=>n>=1&&n<=7},{title:"This Month",icon:"mdi:calendar-month",path:"this-month",filter:{filter_due_min_days:8,filter_due_max_days:30},matches:n=>n>=8&&n<=30},{title:"Later",icon:"mdi:calendar-clock",path:"later",filter:{filter_due_min_days:31},matches:n=>n>=31}];function l(n){return{type:"grid",cards:[n]}}var N={condition:"view_columns",min:2};function _(n,i,e){let s=i[n];if(s)return`{{ states('${s}') }}`;let t=e[n];return t==null?"\u2014":String(t)}function B(n={},i={}){return{type:"markdown",text_only:!0,content:[`\u{1F534} **${_("overdue",n,i)}** overdue`,`\u26A1 **${_("triggered",n,i)}** triggered`,`\u{1F7E1} **${_("due_soon",n,i)}** due soon`,`\u{1F7E2} **${_("ok",n,i)}** ok`].join(" \xB7 ")}}function $(){return{title:"Maintenance",type:"panel",cards:[{type:"empty-state",icon:"mdi:wrench-clock",icon_color:"primary",content_only:!0,title:"No maintenance objects yet",content:"Open the Maintenance panel to add your first object \u2014 pool pump, HVAC filter, vehicle, anything that needs scheduled care.",buttons:[{icon:"mdi:wrench",text:"Open Maintenance panel",appearance:"filled",variant:"brand",tap_action:{action:"navigate",navigation_path:"/maintenance-supporter"}},{icon:"mdi:plus",text:"Add object",appearance:"outlined",variant:"brand",tap_action:{action:"fire-dom-event",ll_custom:{type:"maintenance-supporter:add-object"}}}]}]}}function U(n={},i={}){let e=B(n,i);return{title:"Overview",icon:"mdi:wrench-clock",path:"overview",type:"sections",header:{layout:"responsive",card:e},sidebar:{sections:[{type:"grid",cards:[{type:"heading",heading:"Status",heading_style:"title"},e]}],visibility:[N],content_label:"Tasks",sidebar_label:"Status"},sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:["overdue","triggered","due_soon"]})]}}function W(n,i){let e=new Map;for(let a of n){let r=a.object.area_id||null;e.has(r)||e.set(r,[]),e.get(r).push(a)}let s=Array.from(e.keys()).filter(a=>a!==null);s.sort((a,r)=>{let d=i[a]?.name||a,c=i[r]?.name||r;return d.localeCompare(c)});let t=[];for(let a of s){let r=e.get(a);if(r.length===0)continue;let d=i[a];t.push({title:d?.name||a,icon:d?.icon||"mdi:floor-plan",path:`area-${a}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:r.map(c=>c.object.name)})]})}let o=e.get(null);return o&&o.length>0&&t.push({title:"Unassigned",icon:"mdi:help-circle-outline",path:"unassigned",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:o.map(a=>a.object.name)})]}),t}function Y(n){let i=new Set;for(let s of n)for(let t of s.tasks||[])t.status&&i.add(t.status);let e=[];for(let s of H)i.has(s.status)&&e.push({title:s.title,icon:s.icon,path:s.path,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:[s.status]})]});return e}function F(n,i,e){let s=new Map;for(let r of n){let d=r.object.area_id,c=d&&i[d]?.floor_id||null;s.has(c)||s.set(c,[]),s.get(c).push(r)}let t=Array.from(s.keys()).filter(r=>r!==null);t.sort((r,d)=>{let c=e[r],g=e[d],u=c?.level??0,p=g?.level??0;return u!==p?u-p:(c?.name||r).localeCompare(g?.name||d)});let o=[];for(let r of t){let d=s.get(r);if(d.length===0)continue;let c=e[r];o.push({title:c?.name||r,icon:c?.icon||"mdi:home-floor-1",path:`floor-${r}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:d.map(g=>g.object.name)})]})}let a=s.get(null);return a&&a.length>0&&o.push({title:"Other",icon:"mdi:help-circle-outline",path:"other",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:a.map(r=>r.object.name)})]}),o}function K(n){return[{title:"Week",icon:"mdi:calendar-week",path:"cal-7",window_days:7},{title:"Fortnight",icon:"mdi:calendar-week-begin",path:"cal-14",window_days:14},{title:"Month",icon:"mdi:calendar-month",path:"cal-30",window_days:30},{title:"Year",icon:"mdi:calendar-clock",path:"cal-365",window_days:365}].map(e=>({title:e.title,icon:e.icon,path:e.path,type:"panel",cards:[{type:"custom:maintenance-supporter-calendar-card",window_days:e.window_days,show_window_chips:!1,show_user_filter:!0}]}))}function q(n){let i=new Set;for(let sLine truncated
|
||||
/*! maintenance_supporter frontend 2.59.0 */
|
||||
import{c as y}from"./chunks/chunk-DSAXFRSJ.js";var L="maintenance-supporter",G=`ll-strategy-dashboard-${L}`,x="hui-maintenance-supporter-strategy-editor",V="NOT_RUNNING",H=[{status:"overdue",title:"Overdue",icon:y.overdue,path:"overdue"},{status:"triggered",title:"Triggered",icon:y.triggered,path:"triggered"},{status:"due_soon",title:"Due Soon",icon:y.due_soon,path:"due-soon"},{status:"ok",title:"OK",icon:y.ok,path:"ok"}],E=[{title:"Overdue",icon:"mdi:alert-circle",path:"overdue",filter:{filter_due_max_days:-1},matches:n=>n<=-1},{title:"Today",icon:"mdi:calendar-today",path:"today",filter:{filter_due_min_days:0,filter_due_max_days:0},matches:n=>n===0},{title:"This Week",icon:"mdi:calendar-week",path:"this-week",filter:{filter_due_min_days:1,filter_due_max_days:7},matches:n=>n>=1&&n<=7},{title:"This Month",icon:"mdi:calendar-month",path:"this-month",filter:{filter_due_min_days:8,filter_due_max_days:30},matches:n=>n>=8&&n<=30},{title:"Later",icon:"mdi:calendar-clock",path:"later",filter:{filter_due_min_days:31},matches:n=>n>=31}];function l(n){return{type:"grid",cards:[n]}}var N={condition:"view_columns",min:2};function _(n,i,e){let s=i[n];if(s)return`{{ states('${s}') }}`;let t=e[n];return t==null?"\u2014":String(t)}function B(n={},i={}){return{type:"markdown",text_only:!0,content:[`\u{1F534} **${_("overdue",n,i)}** overdue`,`\u26A1 **${_("triggered",n,i)}** triggered`,`\u{1F7E1} **${_("due_soon",n,i)}** due soon`,`\u{1F7E2} **${_("ok",n,i)}** ok`].join(" \xB7 ")}}function $(){return{title:"Maintenance",type:"panel",cards:[{type:"empty-state",icon:"mdi:wrench-clock",icon_color:"primary",content_only:!0,title:"No maintenance objects yet",content:"Open the Maintenance panel to add your first object \u2014 pool pump, HVAC filter, vehicle, anything that needs scheduled care.",buttons:[{icon:"mdi:wrench",text:"Open Maintenance panel",appearance:"filled",variant:"brand",tap_action:{action:"navigate",navigation_path:"/maintenance-supporter"}},{icon:"mdi:plus",text:"Add object",appearance:"outlined",variant:"brand",tap_action:{action:"fire-dom-event",ll_custom:{type:"maintenance-supporter:add-object"}}}]}]}}function U(n={},i={}){let e=B(n,i);return{title:"Overview",icon:"mdi:wrench-clock",path:"overview",type:"sections",header:{layout:"responsive",card:e},sidebar:{sections:[{type:"grid",cards:[{type:"heading",heading:"Status",heading_style:"title"},e]}],visibility:[N],content_label:"Tasks",sidebar_label:"Status"},sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:["overdue","triggered","due_soon"]})]}}function W(n,i){let e=new Map;for(let a of n){let r=a.object.area_id||null;e.has(r)||e.set(r,[]),e.get(r).push(a)}let s=Array.from(e.keys()).filter(a=>a!==null);s.sort((a,r)=>{let d=i[a]?.name||a,c=i[r]?.name||r;return d.localeCompare(c)});let t=[];for(let a of s){let r=e.get(a);if(r.length===0)continue;let d=i[a];t.push({title:d?.name||a,icon:d?.icon||"mdi:floor-plan",path:`area-${a}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:r.map(c=>c.object.name)})]})}let o=e.get(null);return o&&o.length>0&&t.push({title:"Unassigned",icon:"mdi:help-circle-outline",path:"unassigned",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:o.map(a=>a.object.name)})]}),t}function Y(n){let i=new Set;for(let s of n)for(let t of s.tasks||[])t.status&&i.add(t.status);let e=[];for(let s of H)i.has(s.status)&&e.push({title:s.title,icon:s.icon,path:s.path,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:[s.status]})]});return e}function F(n,i,e){let s=new Map;for(let r of n){let d=r.object.area_id,c=d&&i[d]?.floor_id||null;s.has(c)||s.set(c,[]),s.get(c).push(r)}let t=Array.from(s.keys()).filter(r=>r!==null);t.sort((r,d)=>{let c=e[r],g=e[d],u=c?.level??0,p=g?.level??0;return u!==p?u-p:(c?.name||r).localeCompare(g?.name||d)});let o=[];for(let r of t){let d=s.get(r);if(d.length===0)continue;let c=e[r];o.push({title:c?.name||r,icon:c?.icon||"mdi:home-floor-1",path:`floor-${r}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:d.map(g=>g.object.name)})]})}let a=s.get(null);return a&&a.length>0&&o.push({title:"Other",icon:"mdi:help-circle-outline",path:"other",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:a.map(r=>r.object.name)})]}),o}function K(n){return[{title:"Week",icon:"mdi:calendar-week",path:"cal-7",window_days:7},{title:"Fortnight",icon:"mdi:calendar-week-begin",path:"cal-14",window_days:14},{title:"Month",icon:"mdi:calendar-month",path:"cal-30",window_days:30},{title:"Year",icon:"mdi:calendar-clock",path:"cal-365",window_days:365}].map(e=>({title:e.title,icon:e.icon,path:e.path,type:"panel",cards:[{type:"custom:maintenance-supporter-calendar-card",window_days:e.window_days,show_window_chips:!1,show_user_filter:!0}]}))}function q(n){let i=new Set;for(let sLine truncated
|
||||
<style>
|
||||
:host, .editor { display: block; padding: 16px 0; }
|
||||
label { display: block; font-weight: 500; margin-bottom: 8px; }
|
||||
@@ -22,4 +22,4 @@ import{c as y}from"./chunks/chunk-PAZTCVYX.js";var L="maintenance-supporter",G=`
|
||||
The "Overview" view is always first. Empty groups are skipped.
|
||||
</div>
|
||||
</div>
|
||||
`;let t=this.querySelector("#group-by");t?.addEventListener("change",()=>{let o={...this._config,group_by:t.value};this._config=o,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:o},bubbles:!0,composed:!0}))})}},I="maintenance-supporter-section",Q=`ll-strategy-section-${I}`,v=class extends HTMLElement{static async generate(i,e){let s={type:"custom:maintenance-supporter-card",show_header:!1};i?.filter_status?.length&&(s.filter_status=i.filter_status),i?.max_items&&(s.max_items=i.max_items),i?.filter_due_min_days!==void 0&&(s.filter_due_min_days=i.filter_due_min_days),i?.filter_due_max_days!==void 0&&(s.filter_due_max_days=i.filter_due_max_days);let t=i?.filter_objects;if(i?.area_id&&!t)try{t=((await e.connection.sendMessagePromise({type:"maintenance_supporter/objects"})).objects||[]).filter(r=>r.object.area_id===i.area_id).map(r=>r.object.name)}catch{}t&&t.length>0&&(s.filter_objects=t);let o=[];return i?.title&&o.push({type:"heading",heading:i.title,heading_style:"title"}),o.push(s),{type:"grid",cards:o}}},D="2.3.6",X="[maintenance-supporter]";function M(n,i){try{return customElements.get(n)?"skipped":(customElements.define(n,i),"ok")}catch(e){return`ERROR: ${String(e)}`}}var P={editor:M(x,w),section:M(Q,v)};console.log(`${X} strategy bundle v${D} loaded \u2014 registrations:`,P,"\u2014 run maintenanceSupporterDiagnose() in console for full state");window.maintenanceSupporterDiagnose=async()=>{let n=G,i=[];try{let e=document.querySelector("home-assistant");e?.hass&&(i=(await e.hass.connection.sendMessagePromise({type:"lovelace/resources"})).resources||[])}catch(e){i=[{url:`<error: ${String(e)}>`}]}return{version:D,el_registered:!!customElements.get(n),el_class_excerpt:customElements.get(n)?.toString().slice(0,100)||null,customStrategies_dashboard:window.customStrategies?.filter(e=>e.strategyType==="dashboard").map(e=>e.type)||[],scriptTagsInPage:Array.from(document.querySelectorAll("script[type=module]")).map(e=>e.src).filter(e=>/maint|strateg/i.test(e)),lovelaceResources_matching:i.filter(e=>/maint|strateg/i.test(e.url||"")).map(e=>e.url),registrations:P}};var k=class extends HTMLElement{static async generate(i,e){return await import("./chunks/vacation-section-card-WAKWCXI4.js"),{type:"grid",cards:[{type:"custom:maintenance-vacation-section-card",title:i?.title}]}}},C=class extends HTMLElement{static async generate(i,e){return await import("./chunks/budget-section-card-XAPE5YLJ.js"),{type:"grid",cards:[{type:"custom:maintenance-budget-section-card",title:i?.title}]}}},S=class extends HTMLElement{static async generate(i,e){return await import("./chunks/groups-section-card-AYZTJKYB.js"),{type:"grid",cards:[{type:"custom:maintenance-groups-section-card",title:i?.title}]}}},j="ll-strategy-section-maintenance-supporter-vacation",R="ll-strategy-section-maintenance-supporter-budget",A="ll-strategy-section-maintenance-supporter-groups";customElements.get(j)||customElements.define(j,k);customElements.get(R)||customElements.define(R,C);customElements.get(A)||customElements.define(A,S);var h=null;function J(){return h||(h=import("./chunks/dialog-mount-UXMVFSWC.js").catch(n=>{throw h=null,n})),h}var O="_msSupporterLlCustomBound";function m(n){history.pushState(null,"",n),window.dispatchEvent(new CustomEvent("location-changed"))}function Z(){let n=window;n[O]||(n[O]=!0,document.addEventListener("ll-custom",i=>{let e=i.detail;if(!e||typeof e!="object")return;let s=e.ll_custom,t=s&&typeof s=="object"?s:e;if(!t||typeof t.type!="string"||!t.type.startsWith("maintenance-supporter:"))return;let o=t.type.slice(22);if(o==="deep-link"&&typeof t.path=="string"){m(t.path);return}(async()=>{let a;try{a=await J()}catch{m("/maintenance-supporter");return}if(o==="add-object"){if(a.openCreateObjectDialog())return;m("/maintenance-supporter?ms_action=add_object");return}if(o==="open-task"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"){if(a.openTaskQuickActions(t.entry_id,t.task_id)||a.openEditTaskDialog(t.entry_id,t.task_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}&task_id=${encodeURIComponent(t.task_id)}`);return}if(o==="open-object"&&typeof t.entry_id=="string"){if(a.openObjectQuickActions(t.entry_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}`);return}if(o==="edit-history"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"&&typeof t.original_timestamp=="string"){let d=document.querySelector("home-assistant")?.hass;if(!d)return;try{let u=(await d.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:t.entry_id})).tasks?.find(p=>p.id===t.task_id)?.history?.find(p=>p.timestamp===t.original_timestamp);if(!u)return;a.openHistoryEditDialog({entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.original_timestamp,type:u.type||"completed",timestamp:u.timestamp||t.original_timestamp,notes:u.notes??null,cost:u.cost??null,duration:u.duration??null,completed_by:u.completed_by??null,used_parts:u.used_parts??null}
Line truncated
|
||||
`;let t=this.querySelector("#group-by");t?.addEventListener("change",()=>{let o={...this._config,group_by:t.value};this._config=o,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:o},bubbles:!0,composed:!0}))})}},I="maintenance-supporter-section",Q=`ll-strategy-section-${I}`,v=class extends HTMLElement{static async generate(i,e){let s={type:"custom:maintenance-supporter-card",show_header:!1};i?.filter_status?.length&&(s.filter_status=i.filter_status),i?.max_items&&(s.max_items=i.max_items),i?.filter_due_min_days!==void 0&&(s.filter_due_min_days=i.filter_due_min_days),i?.filter_due_max_days!==void 0&&(s.filter_due_max_days=i.filter_due_max_days);let t=i?.filter_objects;if(i?.area_id&&!t)try{t=((await e.connection.sendMessagePromise({type:"maintenance_supporter/objects"})).objects||[]).filter(r=>r.object.area_id===i.area_id).map(r=>r.object.name)}catch{}t&&t.length>0&&(s.filter_objects=t);let o=[];return i?.title&&o.push({type:"heading",heading:i.title,heading_style:"title"}),o.push(s),{type:"grid",cards:o}}},D="2.3.6",X="[maintenance-supporter]";function M(n,i){try{return customElements.get(n)?"skipped":(customElements.define(n,i),"ok")}catch(e){return`ERROR: ${String(e)}`}}var P={editor:M(x,w),section:M(Q,v)};console.log(`${X} strategy bundle v${D} loaded \u2014 registrations:`,P,"\u2014 run maintenanceSupporterDiagnose() in console for full state");window.maintenanceSupporterDiagnose=async()=>{let n=G,i=[];try{let e=document.querySelector("home-assistant");e?.hass&&(i=(await e.hass.connection.sendMessagePromise({type:"lovelace/resources"})).resources||[])}catch(e){i=[{url:`<error: ${String(e)}>`}]}return{version:D,el_registered:!!customElements.get(n),el_class_excerpt:customElements.get(n)?.toString().slice(0,100)||null,customStrategies_dashboard:window.customStrategies?.filter(e=>e.strategyType==="dashboard").map(e=>e.type)||[],scriptTagsInPage:Array.from(document.querySelectorAll("script[type=module]")).map(e=>e.src).filter(e=>/maint|strateg/i.test(e)),lovelaceResources_matching:i.filter(e=>/maint|strateg/i.test(e.url||"")).map(e=>e.url),registrations:P}};var k=class extends HTMLElement{static async generate(i,e){return await import("./chunks/vacation-section-card-QWEHFNOM.js"),{type:"grid",cards:[{type:"custom:maintenance-vacation-section-card",title:i?.title}]}}},C=class extends HTMLElement{static async generate(i,e){return await import("./chunks/budget-section-card-LY6N7QAT.js"),{type:"grid",cards:[{type:"custom:maintenance-budget-section-card",title:i?.title}]}}},S=class extends HTMLElement{static async generate(i,e){return await import("./chunks/groups-section-card-LRRTTDOC.js"),{type:"grid",cards:[{type:"custom:maintenance-groups-section-card",title:i?.title}]}}},j="ll-strategy-section-maintenance-supporter-vacation",R="ll-strategy-section-maintenance-supporter-budget",A="ll-strategy-section-maintenance-supporter-groups";customElements.get(j)||customElements.define(j,k);customElements.get(R)||customElements.define(R,C);customElements.get(A)||customElements.define(A,S);var h=null;function J(){return h||(h=import("./chunks/dialog-mount-YLZ4K4RT.js").catch(n=>{throw h=null,n})),h}var O="_msSupporterLlCustomBound";function m(n){history.pushState(null,"",n),window.dispatchEvent(new CustomEvent("location-changed"))}function Z(){let n=window;n[O]||(n[O]=!0,document.addEventListener("ll-custom",i=>{let e=i.detail;if(!e||typeof e!="object")return;let s=e.ll_custom,t=s&&typeof s=="object"?s:e;if(!t||typeof t.type!="string"||!t.type.startsWith("maintenance-supporter:"))return;let o=t.type.slice(22);if(o==="deep-link"&&typeof t.path=="string"){m(t.path);return}(async()=>{let a;try{a=await J()}catch{m("/maintenance-supporter");return}if(o==="add-object"){if(a.openCreateObjectDialog())return;m("/maintenance-supporter?ms_action=add_object");return}if(o==="open-task"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"){if(a.openTaskQuickActions(t.entry_id,t.task_id)||a.openEditTaskDialog(t.entry_id,t.task_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}&task_id=${encodeURIComponent(t.task_id)}`);return}if(o==="open-object"&&typeof t.entry_id=="string"){if(a.openObjectQuickActions(t.entry_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}`);return}if(o==="edit-history"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"&&typeof t.original_timestamp=="string"){let d=document.querySelector("home-assistant")?.hass;if(!d)return;try{let u=(await d.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:t.entry_id})).tasks?.find(p=>p.id===t.task_id)?.history?.find(p=>p.timestamp===t.original_timestamp);if(!u)return;a.openHistoryEditDialog({entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.original_timestamp,type:u.type||"completed",timestamp:u.timestamp||t.original_timestamp,notes:u.notes??null,cost:u.cost??null,duration:u.duration??null,completed_by:u.completed_by??null,used_parts:u.used_parts??null}
Line truncated
|
||||
@@ -102,6 +102,11 @@ def register_action_listener(hass: HomeAssistant) -> Callable[[], None]:
|
||||
task_id = event.data.get("task_id")
|
||||
if not entry_id or not task_id:
|
||||
return
|
||||
# #133: a pure backfill records maintenance that happened long ago —
|
||||
# running the on_complete_action NOW (reset a device counter, toggle
|
||||
# a helper) would act on the live device for stale work.
|
||||
if event.data.get("backfill"):
|
||||
return
|
||||
action = _resolve_task_action(hass, entry_id, task_id)
|
||||
if action is None:
|
||||
return
|
||||
|
||||
@@ -35,13 +35,23 @@ def compute_status_from_task_dict(task: dict[str, Any]) -> str:
|
||||
# between refreshes.
|
||||
if task.get("_paused"):
|
||||
return MaintenanceStatus.PAUSED
|
||||
if task.get("_trigger_active", False):
|
||||
days = task.get("_days_until_due")
|
||||
|
||||
# "all" combinator: trigger AND elapsed safety interval must both be met
|
||||
# before the task actions (model twin: MaintenanceTask.status).
|
||||
all_mode = (task.get("trigger_config") or {}).get("trigger_combinator") == "all"
|
||||
time_met = days is None or days <= 0
|
||||
trigger_active = task.get("_trigger_active", False)
|
||||
|
||||
if trigger_active and (not all_mode or time_met):
|
||||
return MaintenanceStatus.TRIGGERED
|
||||
|
||||
days = task.get("_days_until_due")
|
||||
if days is None:
|
||||
return MaintenanceStatus.OK
|
||||
|
||||
if all_mode and not trigger_active:
|
||||
return MaintenanceStatus.OK
|
||||
|
||||
warning_days = task.get("warning_days", DEFAULT_WARNING_DAYS)
|
||||
if days < 0:
|
||||
return MaintenanceStatus.OVERDUE
|
||||
|
||||
@@ -14,6 +14,7 @@ every rule is individually testable.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, Any
|
||||
@@ -44,6 +45,30 @@ def _aggregate(per_entity: list[bool], entity_logic: str) -> bool:
|
||||
return all(per_entity) if entity_logic == "all" else any(per_entity)
|
||||
|
||||
|
||||
def threshold_exceeds(
|
||||
value: float,
|
||||
*,
|
||||
above: float | None,
|
||||
below: float | None,
|
||||
equals: float | None = None,
|
||||
not_equals: float | None = None,
|
||||
) -> bool:
|
||||
"""Whether *value* violates any configured threshold limit.
|
||||
|
||||
The single predicate shared by the event-driven ThresholdTrigger and the
|
||||
refresh-time fallback below — keep both surfaces on this one rule.
|
||||
Equality uses ``math.isclose`` so float round-trips (state strings, JSON)
|
||||
can't miss a discrete level like 3.0.
|
||||
"""
|
||||
if above is not None and value > above:
|
||||
return True
|
||||
if below is not None and value < below:
|
||||
return True
|
||||
if equals is not None and math.isclose(value, equals, rel_tol=1e-9, abs_tol=1e-9):
|
||||
return True
|
||||
return not_equals is not None and not math.isclose(value, not_equals, rel_tol=1e-9, abs_tol=1e-9)
|
||||
|
||||
|
||||
def _numeric_entity_value(get_state: StateGetter, entity_id: str, attribute: str | None) -> float | None:
|
||||
"""Read a numeric value from an entity state/attribute (None when unusable)."""
|
||||
state = get_state(entity_id)
|
||||
@@ -69,6 +94,8 @@ def evaluate_threshold(
|
||||
for_minutes = trigger_config.get("trigger_for_minutes", 0)
|
||||
above = trigger_config.get("trigger_above")
|
||||
below = trigger_config.get("trigger_below")
|
||||
equals = trigger_config.get("trigger_equals")
|
||||
not_equals = trigger_config.get("trigger_not_equals")
|
||||
|
||||
per_entity: list[bool] = []
|
||||
last_value: float | None = None
|
||||
@@ -78,8 +105,7 @@ def evaluate_threshold(
|
||||
per_entity.append(False)
|
||||
continue
|
||||
last_value = value
|
||||
exceeds = (above is not None and value > above) or (below is not None and value < below)
|
||||
per_entity.append(exceeds)
|
||||
per_entity.append(threshold_exceeds(value, above=above, below=below, equals=equals, not_equals=not_equals))
|
||||
|
||||
aggregated = _aggregate(per_entity, entity_logic) if per_entity else False
|
||||
|
||||
|
||||
@@ -22,5 +22,5 @@
|
||||
"requirements": [
|
||||
"pypdf>=4.3.0"
|
||||
],
|
||||
"version": "2.58.0"
|
||||
"version": "2.59.0"
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import date, time
|
||||
from datetime import date, datetime, time
|
||||
from typing import Any
|
||||
from uuid import uuid4
|
||||
|
||||
@@ -12,6 +12,7 @@ from homeassistant.util import dt as dt_util
|
||||
from ..const import (
|
||||
DEFAULT_MAX_HISTORY_ENTRIES,
|
||||
DEFAULT_WARNING_DAYS,
|
||||
LIFECYCLE_HISTORY_TYPES,
|
||||
HistoryEntryType,
|
||||
MaintenanceStatus,
|
||||
MaintenanceTypeEnum,
|
||||
@@ -192,15 +193,28 @@ class MaintenanceTask:
|
||||
if self.archived_at is not None:
|
||||
return MaintenanceStatus.ARCHIVED
|
||||
|
||||
days = self.days_until_due
|
||||
|
||||
# Trigger ∧/∨ safety interval: with the "all" combinator BOTH legs must
|
||||
# be met — the trigger must have fired AND the due date been reached
|
||||
# (the interval is a minimum age, not a deadline). Default "any" keeps
|
||||
# the historical whichever-first behaviour. Mirror any change in
|
||||
# helpers/status.compute_status_from_task_dict (the dict twin).
|
||||
all_mode = (self.trigger_config or {}).get("trigger_combinator") == "all"
|
||||
time_met = days is None or days <= 0
|
||||
|
||||
# Trigger takes precedence
|
||||
if self._trigger_active:
|
||||
if self._trigger_active and (not all_mode or time_met):
|
||||
return MaintenanceStatus.TRIGGERED
|
||||
|
||||
days = self.days_until_due
|
||||
if days is None:
|
||||
# Manual task or no schedule: always OK unless triggered
|
||||
return MaintenanceStatus.OK
|
||||
|
||||
if all_mode and not self._trigger_active:
|
||||
# The elapsed interval alone never actions an "all" task.
|
||||
return MaintenanceStatus.OK
|
||||
|
||||
if days < 0:
|
||||
return MaintenanceStatus.OVERDUE
|
||||
# Sub-day refinement: same-day past schedule_time also counts as overdue.
|
||||
@@ -300,24 +314,54 @@ class MaintenanceTask:
|
||||
reading_value: float | None = None,
|
||||
used_parts: list[dict[str, Any]] | None = None,
|
||||
auto: bool = False,
|
||||
) -> None:
|
||||
completed_at: datetime | None = None,
|
||||
) -> bool:
|
||||
"""Mark this task as completed.
|
||||
|
||||
``auto`` marks a completion nobody performed in the UI (a trigger
|
||||
recovering on its own): the history entry is flagged so surfaces can
|
||||
label it, and the rotation pointer stays put — advancing it would
|
||||
credit/skip a pool member for work nobody attributed."""
|
||||
# Save current next_due as anchor for planned mode before resetting
|
||||
if self.interval_anchor == "planned" and self.next_due is not None:
|
||||
self.last_planned_due = self.next_due.isoformat()
|
||||
credit/skip a pool member for work nobody attributed.
|
||||
|
||||
now = dt_util.now()
|
||||
self.last_performed = now.date().isoformat()
|
||||
self._trigger_active = False
|
||||
self._trigger_current_value = None
|
||||
# A postponed occurrence is consumed by completing it — the next cycle
|
||||
# returns to the normal cadence.
|
||||
self.due_override = None
|
||||
``completed_at`` (#133) records the completion at a past moment
|
||||
instead of now. When that moment is still the LATEST lifecycle entry
|
||||
("did it three days ago, logging it now") the cycle advances exactly
|
||||
like a normal completion. When it is OLDER than the latest lifecycle
|
||||
entry it is a pure backfill: only the history entry is written — the
|
||||
cycle anchor, trigger latch, postpone override, planned anchor and
|
||||
rotation pointer all stay put (moving them would throw the live cycle
|
||||
backwards). Mirrors the history-edit reconciliation's
|
||||
max-by-timestamp rule (websocket/tasks_history.py).
|
||||
|
||||
Returns True when the completion advanced the cycle (it was the
|
||||
latest lifecycle entry), False for a pure backfill.
|
||||
"""
|
||||
ts = completed_at if completed_at is not None else dt_util.now()
|
||||
ts_iso = ts.isoformat()
|
||||
# String comparison, deliberately — history timestamps mix TZ-aware
|
||||
# (live completions) and naive (hand-edited) values, and the edit
|
||||
# reconciliation already compares them as strings. last_performed
|
||||
# (date-only ISO) joins the anchors: an imported or history-trimmed
|
||||
# task has a cycle anchor but no lifecycle entries, and a backfill
|
||||
# must not drag that anchor backwards either. A full timestamp on the
|
||||
# same day sorts after the bare date, so a same-day completion still
|
||||
# counts as latest.
|
||||
anchors = [h.get("timestamp") or "" for h in self.history if h.get("type") in LIFECYCLE_HISTORY_TYPES]
|
||||
if self.last_performed:
|
||||
anchors.append(self.last_performed)
|
||||
is_latest = ts_iso >= max(anchors, default="")
|
||||
|
||||
if is_latest:
|
||||
# Save current next_due as anchor for planned mode before resetting
|
||||
if self.interval_anchor == "planned" and self.next_due is not None:
|
||||
self.last_planned_due = self.next_due.isoformat()
|
||||
|
||||
self.last_performed = ts.date().isoformat()
|
||||
self._trigger_active = False
|
||||
self._trigger_current_value = None
|
||||
# A postponed occurrence is consumed by completing it — the next
|
||||
# cycle returns to the normal cadence.
|
||||
self.due_override = None
|
||||
|
||||
self.add_history_entry(
|
||||
entry_type=HistoryEntryType.COMPLETED,
|
||||
@@ -331,14 +375,19 @@ class MaintenanceTask:
|
||||
reading_value=reading_value,
|
||||
used_parts=used_parts,
|
||||
auto=auto,
|
||||
timestamp=ts_iso,
|
||||
)
|
||||
|
||||
# Shared tasks: rotate the "currently responsible" pointer to the next
|
||||
# assignee for the coming cycle (after this completion is recorded, so
|
||||
# least_completed sees it). Auto-completions don't rotate — see above.
|
||||
if not auto:
|
||||
# Pure backfills don't either: the coming cycle's assignee was already
|
||||
# decided by the real latest completion.
|
||||
if not auto and is_latest:
|
||||
self.advance_rotation()
|
||||
|
||||
return is_latest
|
||||
|
||||
def advance_rotation(self) -> None:
|
||||
"""Advance ``responsible_user_id`` to the next pool member.
|
||||
|
||||
@@ -420,10 +469,15 @@ class MaintenanceTask:
|
||||
reading_value: float | None = None,
|
||||
used_parts: list[dict[str, Any]] | None = None,
|
||||
auto: bool = False,
|
||||
timestamp: str | None = None,
|
||||
) -> None:
|
||||
"""Add an entry to the maintenance history."""
|
||||
"""Add an entry to the maintenance history.
|
||||
|
||||
``timestamp`` overrides the default "now" (backdated completions,
|
||||
#133). Entries are APPENDED regardless of chronology — consumers that
|
||||
need order sort defensively, same as after a history-edit."""
|
||||
entry: dict[str, Any] = {
|
||||
"timestamp": dt_util.now().isoformat(),
|
||||
"timestamp": timestamp or dt_util.now().isoformat(),
|
||||
"type": entry_type,
|
||||
}
|
||||
if auto:
|
||||
|
||||
@@ -237,10 +237,14 @@ class MaintenanceSensor(MaintenanceEntity, SensorEntity):
|
||||
ttype = trigger_config.get("type")
|
||||
attrs["trigger_type"] = ttype
|
||||
attrs["trigger_active"] = task.get("_trigger_active", False)
|
||||
if trigger_config.get("trigger_combinator") == "all":
|
||||
attrs["trigger_combinator"] = "all"
|
||||
|
||||
if ttype == "threshold":
|
||||
attrs["trigger_above"] = trigger_config.get("trigger_above")
|
||||
attrs["trigger_below"] = trigger_config.get("trigger_below")
|
||||
attrs["trigger_equals"] = trigger_config.get("trigger_equals")
|
||||
attrs["trigger_not_equals"] = trigger_config.get("trigger_not_equals")
|
||||
attrs["trigger_for_minutes"] = trigger_config.get("trigger_for_minutes")
|
||||
elif ttype == "counter":
|
||||
attrs["trigger_target_value"] = trigger_config.get("trigger_target_value")
|
||||
@@ -391,6 +395,7 @@ class MaintenanceSensor(MaintenanceEntity, SensorEntity):
|
||||
|
||||
tasks = self.coordinator.data.get(CONF_TASKS, {})
|
||||
task = tasks.get(self._task_id, {})
|
||||
prev_active = task.get("_trigger_active", False)
|
||||
|
||||
# Track per-entity state
|
||||
if trigger_entity_id is not None:
|
||||
@@ -421,9 +426,12 @@ class MaintenanceSensor(MaintenanceEntity, SensorEntity):
|
||||
new_status = self._compute_live_status(task)
|
||||
task["_status"] = new_status
|
||||
|
||||
# Only write HA state when status actually changes to avoid
|
||||
# unnecessary recorder writes on every trigger value update.
|
||||
if new_status != old_status:
|
||||
# Only write HA state when the status — or the latched trigger flag —
|
||||
# actually changes, to avoid recorder writes on every value update.
|
||||
# With trigger_combinator="all" a latched trigger no longer implies a
|
||||
# status change (the interval leg may still be pending), but the
|
||||
# trigger_active attribute must repaint regardless.
|
||||
if new_status != old_status or task.get("_trigger_active", False) != prev_active:
|
||||
self.async_write_ha_state()
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -45,6 +45,11 @@ complete:
|
||||
selector:
|
||||
entity:
|
||||
domain: person
|
||||
completed_at:
|
||||
name: Completed at
|
||||
description: When the maintenance was actually performed — use it to backfill a past completion. Must not be in the future; when omitted, now is recorded.
|
||||
selector:
|
||||
datetime:
|
||||
|
||||
reset:
|
||||
name: Reset Maintenance
|
||||
|
||||
@@ -228,9 +228,12 @@
|
||||
"data": {
|
||||
"trigger_above": "Trigger when above",
|
||||
"trigger_below": "Trigger when below",
|
||||
"trigger_equals": "Trigger when equal to",
|
||||
"trigger_not_equals": "Trigger when different from",
|
||||
"trigger_for_minutes": "For at least (minutes)",
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"trigger_combinator": "Combine trigger and interval",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
@@ -238,9 +241,12 @@
|
||||
"data_description": {
|
||||
"trigger_above": "Trigger maintenance when value exceeds this threshold.",
|
||||
"trigger_below": "Trigger maintenance when value falls below this threshold.",
|
||||
"trigger_equals": "Trigger maintenance when the value equals this level.",
|
||||
"trigger_not_equals": "Trigger maintenance when the value differs from this level.",
|
||||
"trigger_for_minutes": "Value must exceed threshold for this many minutes before triggering.",
|
||||
"interval_days": "Optional time-based safety interval in addition to the sensor trigger.",
|
||||
"interval_unit": "Unit for the interval: days, weeks, months or years. Months and years follow the calendar.",
|
||||
"trigger_combinator": "Whichever first (default): trigger or elapsed interval makes the task due. Both required: the task only becomes due once the trigger fired and the interval elapsed.",
|
||||
"warning_days": "Number of days before due date to show a warning.",
|
||||
"go_back": "Return to trigger type selection without saving."
|
||||
}
|
||||
@@ -253,6 +259,7 @@
|
||||
"trigger_delta_mode": "Delta mode (count changes, not absolute)",
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"trigger_combinator": "Combine trigger and interval",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers",
|
||||
@@ -263,6 +270,7 @@
|
||||
"trigger_delta_mode": "If enabled, counts the difference from a baseline instead of the absolute value.",
|
||||
"interval_days": "Optional time-based safety interval in addition to the counter trigger.",
|
||||
"interval_unit": "Unit for the interval: days, weeks, months or years. Months and years follow the calendar.",
|
||||
"trigger_combinator": "Whichever first (default): trigger or elapsed interval makes the task due. Both required: the task only becomes due once the trigger fired and the interval elapsed.",
|
||||
"warning_days": "Number of days before due date to show a warning.",
|
||||
"go_back": "Return to trigger type selection without saving."
|
||||
}
|
||||
@@ -276,6 +284,7 @@
|
||||
"trigger_target_changes": "Number of changes to trigger",
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"trigger_combinator": "Combine trigger and interval",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
@@ -286,6 +295,7 @@
|
||||
"trigger_target_changes": "Number of matching state changes before triggering maintenance.",
|
||||
"interval_days": "Optional time-based safety interval in addition to the state change trigger.",
|
||||
"interval_unit": "Unit for the interval: days, weeks, months or years. Months and years follow the calendar.",
|
||||
"trigger_combinator": "Whichever first (default): trigger or elapsed interval makes the task due. Both required: the task only becomes due once the trigger fired and the interval elapsed.",
|
||||
"warning_days": "Number of days before due date to show a warning.",
|
||||
"go_back": "Return to trigger type selection without saving."
|
||||
}
|
||||
@@ -298,6 +308,7 @@
|
||||
"trigger_on_states": "Active states (comma-separated)",
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"trigger_combinator": "Combine trigger and interval",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
@@ -307,6 +318,7 @@
|
||||
"trigger_on_states": "Which sensor states count as 'active'. Leave empty for default: on, 1, true. Example: in_use, running",
|
||||
"interval_days": "Optional time-based safety interval in addition to the runtime trigger.",
|
||||
"interval_unit": "Unit for the interval: days, weeks, months or years. Months and years follow the calendar.",
|
||||
"trigger_combinator": "Whichever first (default): trigger or elapsed interval makes the task due. Both required: the task only becomes due once the trigger fired and the interval elapsed.",
|
||||
"warning_days": "Number of days before due date to show a warning.",
|
||||
"go_back": "Return to trigger type selection without saving."
|
||||
}
|
||||
@@ -353,12 +365,16 @@
|
||||
"data": {
|
||||
"trigger_above": "Trigger above",
|
||||
"trigger_below": "Trigger below",
|
||||
"trigger_equals": "Trigger when equal to",
|
||||
"trigger_not_equals": "Trigger when different from",
|
||||
"trigger_for_minutes": "Duration (minutes)",
|
||||
"go_back": "Go back"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Trigger when value exceeds this threshold.",
|
||||
"trigger_below": "Trigger when value drops below this threshold.",
|
||||
"trigger_equals": "Trigger maintenance when the value equals this level.",
|
||||
"trigger_not_equals": "Trigger maintenance when the value differs from this level.",
|
||||
"trigger_for_minutes": "Value must remain beyond threshold for this duration.",
|
||||
"go_back": "Return to condition type selection without saving."
|
||||
}
|
||||
@@ -886,9 +902,12 @@
|
||||
"data": {
|
||||
"trigger_above": "Trigger when above",
|
||||
"trigger_below": "Trigger when below",
|
||||
"trigger_equals": "Trigger when equal to",
|
||||
"trigger_not_equals": "Trigger when different from",
|
||||
"trigger_for_minutes": "For at least (minutes)",
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"trigger_combinator": "Combine trigger and interval",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
@@ -896,9 +915,12 @@
|
||||
"data_description": {
|
||||
"trigger_above": "Trigger maintenance when value exceeds this threshold.",
|
||||
"trigger_below": "Trigger maintenance when value falls below this threshold.",
|
||||
"trigger_equals": "Trigger maintenance when the value equals this level.",
|
||||
"trigger_not_equals": "Trigger maintenance when the value differs from this level.",
|
||||
"trigger_for_minutes": "Value must exceed threshold for this many minutes before triggering.",
|
||||
"interval_days": "Optional time-based safety interval in addition to the sensor trigger.",
|
||||
"interval_unit": "Unit for the interval: days, weeks, months or years. Months and years follow the calendar.",
|
||||
"trigger_combinator": "Whichever first (default): trigger or elapsed interval makes the task due. Both required: the task only becomes due once the trigger fired and the interval elapsed.",
|
||||
"warning_days": "Number of days before due date to show a warning."
|
||||
}
|
||||
},
|
||||
@@ -910,6 +932,7 @@
|
||||
"trigger_delta_mode": "Delta mode (count changes, not absolute)",
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"trigger_combinator": "Combine trigger and interval",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers",
|
||||
@@ -920,6 +943,7 @@
|
||||
"trigger_delta_mode": "If enabled, counts the difference from a baseline instead of the absolute value.",
|
||||
"interval_days": "Optional time-based safety interval in addition to the counter trigger.",
|
||||
"interval_unit": "Unit for the interval: days, weeks, months or years. Months and years follow the calendar.",
|
||||
"trigger_combinator": "Whichever first (default): trigger or elapsed interval makes the task due. Both required: the task only becomes due once the trigger fired and the interval elapsed.",
|
||||
"warning_days": "Number of days before due date to show a warning."
|
||||
}
|
||||
},
|
||||
@@ -932,6 +956,7 @@
|
||||
"trigger_target_changes": "Number of changes to trigger",
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"trigger_combinator": "Combine trigger and interval",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
@@ -942,6 +967,7 @@
|
||||
"trigger_target_changes": "Number of matching state changes before triggering maintenance.",
|
||||
"interval_days": "Optional time-based safety interval in addition to the state change trigger.",
|
||||
"interval_unit": "Unit for the interval: days, weeks, months or years. Months and years follow the calendar.",
|
||||
"trigger_combinator": "Whichever first (default): trigger or elapsed interval makes the task due. Both required: the task only becomes due once the trigger fired and the interval elapsed.",
|
||||
"warning_days": "Number of days before due date to show a warning."
|
||||
}
|
||||
},
|
||||
@@ -953,6 +979,7 @@
|
||||
"trigger_on_states": "Active states (comma-separated)",
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"trigger_combinator": "Combine trigger and interval",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
@@ -962,6 +989,7 @@
|
||||
"trigger_on_states": "Which sensor states count as 'active'. Leave empty for default: on, 1, true. Example: in_use, running",
|
||||
"interval_days": "Optional time-based safety interval in addition to the runtime trigger.",
|
||||
"interval_unit": "Unit for the interval: days, weeks, months or years. Months and years follow the calendar.",
|
||||
"trigger_combinator": "Whichever first (default): trigger or elapsed interval makes the task due. Both required: the task only becomes due once the trigger fired and the interval elapsed.",
|
||||
"warning_days": "Number of days before due date to show a warning."
|
||||
}
|
||||
},
|
||||
@@ -1004,12 +1032,16 @@
|
||||
"data": {
|
||||
"trigger_above": "Trigger above",
|
||||
"trigger_below": "Trigger below",
|
||||
"trigger_equals": "Trigger when equal to",
|
||||
"trigger_not_equals": "Trigger when different from",
|
||||
"trigger_for_minutes": "Duration (minutes)",
|
||||
"go_back": "Go back"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Trigger when value exceeds this threshold.",
|
||||
"trigger_below": "Trigger when value drops below this threshold.",
|
||||
"trigger_equals": "Trigger maintenance when the value equals this level.",
|
||||
"trigger_not_equals": "Trigger maintenance when the value differs from this level.",
|
||||
"trigger_for_minutes": "Value must remain beyond threshold for this duration."
|
||||
}
|
||||
},
|
||||
@@ -1458,6 +1490,10 @@
|
||||
"completed_by": {
|
||||
"name": "Completed by",
|
||||
"description": "Person who performed the maintenance (must be linked to a Home Assistant user). When omitted, the user triggering the call is recorded."
|
||||
},
|
||||
"completed_at": {
|
||||
"name": "Completed at",
|
||||
"description": "When the maintenance was actually performed — use it to backfill a past completion. Must not be in the future; when omitted, now is recorded."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1739,6 +1775,12 @@
|
||||
"all": "All entities must trigger"
|
||||
}
|
||||
},
|
||||
"trigger_combinator": {
|
||||
"options": {
|
||||
"any": "Trigger or interval (whichever first)",
|
||||
"all": "Trigger and interval (both required)"
|
||||
}
|
||||
},
|
||||
"notification_title_style": {
|
||||
"options": {
|
||||
"default": "Default (per-status title)",
|
||||
@@ -1925,6 +1967,9 @@
|
||||
},
|
||||
"completion_details_required": {
|
||||
"message": "“{task_name}” requires these details when you complete it: {fields}. Complete it from the Maintenance panel or card so you can fill them in."
|
||||
},
|
||||
"completed_at_in_future": {
|
||||
"message": "The completion date cannot be in the future."
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
|
||||
@@ -228,9 +228,12 @@
|
||||
"data": {
|
||||
"trigger_above": "Spustit nad",
|
||||
"trigger_below": "Spustit pod",
|
||||
"trigger_equals": "Spustit při rovnosti",
|
||||
"trigger_not_equals": "Spustit při odlišnosti od",
|
||||
"trigger_for_minutes": "Po dobu alespoň (minut)",
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"trigger_combinator": "Kombinovat spouštěč a interval",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
@@ -238,9 +241,12 @@
|
||||
"data_description": {
|
||||
"trigger_above": "Spustit údržbu, když hodnota překročí tento práh.",
|
||||
"trigger_below": "Spustit údržbu, když hodnota klesne pod tento práh.",
|
||||
"trigger_equals": "Spustit údržbu, když se hodnota rovná této úrovni.",
|
||||
"trigger_not_equals": "Spustit údržbu, když se hodnota liší od této úrovně.",
|
||||
"trigger_for_minutes": "Hodnota musí překračovat práh tolik minut před spuštěním.",
|
||||
"interval_days": "Volitelný bezpečnostní interval založený na čase, navíc ke spouštěči senzoru.",
|
||||
"interval_unit": "Jednotka intervalu: dny, týdny, měsíce nebo roky. Měsíce a roky se řídí kalendářem.",
|
||||
"trigger_combinator": "Co nastane dřív (výchozí): spouštěč nebo uplynulý interval učiní úkol splatným. Obojí vyžadováno: úkol je splatný, až když spouštěč vystřelil a interval uplynul.",
|
||||
"warning_days": "Počet dní před termínem pro zobrazení upozornění.",
|
||||
"go_back": "Návrat k výběru typu spouště bez uložení."
|
||||
}
|
||||
@@ -253,6 +259,7 @@
|
||||
"trigger_delta_mode": "Delta režim (počítej změny, ne absolutní hodnotu)",
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"trigger_combinator": "Kombinovat spouštěč a interval",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru",
|
||||
@@ -263,6 +270,7 @@
|
||||
"trigger_delta_mode": "Pokud je povoleno, počítá rozdíl od základní hodnoty místo absolutní hodnoty.",
|
||||
"interval_days": "Volitelný bezpečnostní interval založený na čase, navíc ke spouštěči čítače.",
|
||||
"interval_unit": "Jednotka intervalu: dny, týdny, měsíce nebo roky. Měsíce a roky se řídí kalendářem.",
|
||||
"trigger_combinator": "Co nastane dřív (výchozí): spouštěč nebo uplynulý interval učiní úkol splatným. Obojí vyžadováno: úkol je splatný, až když spouštěč vystřelil a interval uplynul.",
|
||||
"warning_days": "Počet dní před termínem pro zobrazení upozornění.",
|
||||
"go_back": "Návrat k výběru typu spouště bez uložení."
|
||||
}
|
||||
@@ -276,6 +284,7 @@
|
||||
"trigger_target_changes": "Počet změn pro spuštění",
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"trigger_combinator": "Kombinovat spouštěč a interval",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
@@ -286,6 +295,7 @@
|
||||
"trigger_target_changes": "Počet odpovídajících změn stavu před spuštěním údržby.",
|
||||
"interval_days": "Volitelný bezpečnostní interval založený na čase, navíc ke spouštěči změny stavu.",
|
||||
"interval_unit": "Jednotka intervalu: dny, týdny, měsíce nebo roky. Měsíce a roky se řídí kalendářem.",
|
||||
"trigger_combinator": "Co nastane dřív (výchozí): spouštěč nebo uplynulý interval učiní úkol splatným. Obojí vyžadováno: úkol je splatný, až když spouštěč vystřelil a interval uplynul.",
|
||||
"warning_days": "Počet dní před termínem pro zobrazení upozornění.",
|
||||
"go_back": "Návrat k výběru typu spouště bez uložení."
|
||||
}
|
||||
@@ -298,6 +308,7 @@
|
||||
"trigger_on_states": "Aktivní stavy (oddělené čárkou)",
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"trigger_combinator": "Kombinovat spouštěč a interval",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
@@ -307,6 +318,7 @@
|
||||
"trigger_on_states": "Které stavy senzoru se počítají jako „aktivní“. Nechte prázdné pro výchozí: on, 1, true. Příklad: in_use, running",
|
||||
"interval_days": "Volitelný bezpečnostní interval založený na čase, navíc ke spouštěči doby běhu.",
|
||||
"interval_unit": "Jednotka intervalu: dny, týdny, měsíce nebo roky. Měsíce a roky se řídí kalendářem.",
|
||||
"trigger_combinator": "Co nastane dřív (výchozí): spouštěč nebo uplynulý interval učiní úkol splatným. Obojí vyžadováno: úkol je splatný, až když spouštěč vystřelil a interval uplynul.",
|
||||
"warning_days": "Počet dní před termínem pro zobrazení upozornění.",
|
||||
"go_back": "Návrat k výběru typu spouště bez uložení."
|
||||
}
|
||||
@@ -353,12 +365,16 @@
|
||||
"data": {
|
||||
"trigger_above": "Spustit nad",
|
||||
"trigger_below": "Spustit pod",
|
||||
"trigger_equals": "Spustit při rovnosti",
|
||||
"trigger_not_equals": "Spustit při odlišnosti od",
|
||||
"trigger_for_minutes": "Doba trvání (minuty)",
|
||||
"go_back": "Zpět"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Spustit, když hodnota překročí tento práh.",
|
||||
"trigger_below": "Spustit, když hodnota klesne pod tento práh.",
|
||||
"trigger_equals": "Spustit údržbu, když se hodnota rovná této úrovni.",
|
||||
"trigger_not_equals": "Spustit údržbu, když se hodnota liší od této úrovně.",
|
||||
"trigger_for_minutes": "Hodnota musí zůstat mimo práh po tuto dobu.",
|
||||
"go_back": "Návrat k výběru typu podmínky bez uložení."
|
||||
}
|
||||
@@ -762,12 +778,16 @@
|
||||
"data": {
|
||||
"trigger_above": "Spustit nad",
|
||||
"trigger_below": "Spustit pod",
|
||||
"trigger_equals": "Spustit při rovnosti",
|
||||
"trigger_not_equals": "Spustit při odlišnosti od",
|
||||
"trigger_for_minutes": "Doba trvání (minuty)",
|
||||
"go_back": "Zpět"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Spustit, když hodnota překročí tento práh.",
|
||||
"trigger_below": "Spustit, když hodnota klesne pod tento práh.",
|
||||
"trigger_equals": "Spustit údržbu, když se hodnota rovná této úrovni.",
|
||||
"trigger_not_equals": "Spustit údržbu, když se hodnota liší od této úrovně.",
|
||||
"trigger_for_minutes": "Hodnota musí zůstat mimo práh po tuto dobu."
|
||||
}
|
||||
},
|
||||
@@ -1004,9 +1024,12 @@
|
||||
"data": {
|
||||
"trigger_above": "Spustit nad",
|
||||
"trigger_below": "Spustit pod",
|
||||
"trigger_equals": "Spustit při rovnosti",
|
||||
"trigger_not_equals": "Spustit při odlišnosti od",
|
||||
"trigger_for_minutes": "Po dobu alespoň (minut)",
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"trigger_combinator": "Kombinovat spouštěč a interval",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
@@ -1014,9 +1037,12 @@
|
||||
"data_description": {
|
||||
"trigger_above": "Spustit údržbu, když hodnota překročí tento práh.",
|
||||
"trigger_below": "Spustit údržbu, když hodnota klesne pod tento práh.",
|
||||
"trigger_equals": "Spustit údržbu, když se hodnota rovná této úrovni.",
|
||||
"trigger_not_equals": "Spustit údržbu, když se hodnota liší od této úrovně.",
|
||||
"trigger_for_minutes": "Hodnota musí překračovat práh tolik minut před spuštěním.",
|
||||
"interval_days": "Volitelný bezpečnostní interval založený na čase, navíc ke spouštěči senzoru.",
|
||||
"interval_unit": "Jednotka intervalu: dny, týdny, měsíce nebo roky. Měsíce a roky se řídí kalendářem.",
|
||||
"trigger_combinator": "Co nastane dřív (výchozí): spouštěč nebo uplynulý interval učiní úkol splatným. Obojí vyžadováno: úkol je splatný, až když spouštěč vystřelil a interval uplynul.",
|
||||
"warning_days": "Počet dní před termínem pro zobrazení upozornění."
|
||||
}
|
||||
},
|
||||
@@ -1028,6 +1054,7 @@
|
||||
"trigger_delta_mode": "Delta režim (počítej změny, ne absolutní hodnotu)",
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"trigger_combinator": "Kombinovat spouštěč a interval",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru",
|
||||
@@ -1038,6 +1065,7 @@
|
||||
"trigger_delta_mode": "Pokud je povoleno, počítá rozdíl od základní hodnoty místo absolutní hodnoty.",
|
||||
"interval_days": "Volitelný bezpečnostní interval založený na čase, navíc ke spouštěči čítače.",
|
||||
"interval_unit": "Jednotka intervalu: dny, týdny, měsíce nebo roky. Měsíce a roky se řídí kalendářem.",
|
||||
"trigger_combinator": "Co nastane dřív (výchozí): spouštěč nebo uplynulý interval učiní úkol splatným. Obojí vyžadováno: úkol je splatný, až když spouštěč vystřelil a interval uplynul.",
|
||||
"warning_days": "Počet dní před termínem pro zobrazení upozornění."
|
||||
}
|
||||
},
|
||||
@@ -1050,6 +1078,7 @@
|
||||
"trigger_target_changes": "Počet změn pro spuštění",
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"trigger_combinator": "Kombinovat spouštěč a interval",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
@@ -1060,6 +1089,7 @@
|
||||
"trigger_target_changes": "Počet odpovídajících změn stavu před spuštěním údržby.",
|
||||
"interval_days": "Volitelný bezpečnostní interval založený na čase, navíc ke spouštěči změny stavu.",
|
||||
"interval_unit": "Jednotka intervalu: dny, týdny, měsíce nebo roky. Měsíce a roky se řídí kalendářem.",
|
||||
"trigger_combinator": "Co nastane dřív (výchozí): spouštěč nebo uplynulý interval učiní úkol splatným. Obojí vyžadováno: úkol je splatný, až když spouštěč vystřelil a interval uplynul.",
|
||||
"warning_days": "Počet dní před termínem pro zobrazení upozornění."
|
||||
}
|
||||
},
|
||||
@@ -1071,6 +1101,7 @@
|
||||
"trigger_on_states": "Aktivní stavy (oddělené čárkou)",
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"trigger_combinator": "Kombinovat spouštěč a interval",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
@@ -1080,6 +1111,7 @@
|
||||
"trigger_on_states": "Které stavy senzoru se počítají jako „aktivní“. Nechte prázdné pro výchozí: on, 1, true. Příklad: in_use, running",
|
||||
"interval_days": "Volitelný bezpečnostní interval založený na čase, navíc ke spouštěči doby běhu.",
|
||||
"interval_unit": "Jednotka intervalu: dny, týdny, měsíce nebo roky. Měsíce a roky se řídí kalendářem.",
|
||||
"trigger_combinator": "Co nastane dřív (výchozí): spouštěč nebo uplynulý interval učiní úkol splatným. Obojí vyžadováno: úkol je splatný, až když spouštěč vystřelil a interval uplynul.",
|
||||
"warning_days": "Počet dní před termínem pro zobrazení upozornění."
|
||||
}
|
||||
},
|
||||
@@ -1482,6 +1514,12 @@
|
||||
"all": "Všechny entity musí spouštět"
|
||||
}
|
||||
},
|
||||
"trigger_combinator": {
|
||||
"options": {
|
||||
"any": "Spouštěč nebo interval (co dřív)",
|
||||
"all": "Spouštěč a interval (obojí vyžadováno)"
|
||||
}
|
||||
},
|
||||
"notification_title_style": {
|
||||
"options": {
|
||||
"default": "Výchozí (titulek podle stavu)",
|
||||
@@ -1518,6 +1556,10 @@
|
||||
"completed_by": {
|
||||
"name": "Dokončil(a)",
|
||||
"description": "Osoba, která údržbu provedla (musí být propojena s uživatelem Home Assistant). Pokud není uvedeno, zaznamená se volající uživatel."
|
||||
},
|
||||
"completed_at": {
|
||||
"name": "Dokončeno dne",
|
||||
"description": "Kdy byla údržba skutečně provedena — pro zpětné doplnění dřívějšího dokončení. Nesmí být v budoucnosti; při vynechání se zaznamená nyní."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1925,6 +1967,9 @@
|
||||
},
|
||||
"completion_details_required": {
|
||||
"message": "„{task_name}“ při dokončení vyžaduje tyto údaje: {fields}. Dokončete úlohu v panelu údržby nebo na kartě, abyste je mohli vyplnit."
|
||||
},
|
||||
"completed_at_in_future": {
|
||||
"message": "Datum dokončení nesmí být v budoucnosti."
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
|
||||
@@ -228,9 +228,12 @@
|
||||
"data": {
|
||||
"trigger_above": "Udløs når over",
|
||||
"trigger_below": "Udløs når under",
|
||||
"trigger_equals": "Udløs ved lig med",
|
||||
"trigger_not_equals": "Udløs ved forskellig fra",
|
||||
"trigger_for_minutes": "I mindst (minutter)",
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"trigger_combinator": "Kombinér trigger og interval",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
@@ -238,9 +241,12 @@
|
||||
"data_description": {
|
||||
"trigger_above": "Udløs vedligeholdelse, når værdien overskrider denne tærskel.",
|
||||
"trigger_below": "Udløs vedligeholdelse, når værdien falder under denne tærskel.",
|
||||
"trigger_equals": "Udløs vedligeholdelse, når værdien er lig med dette niveau.",
|
||||
"trigger_not_equals": "Udløs vedligeholdelse, når værdien afviger fra dette niveau.",
|
||||
"trigger_for_minutes": "Værdien skal overskride tærsklen i så mange minutter, før der udløses.",
|
||||
"interval_days": "Valgfrit tidsbaseret sikkerhedsinterval ud over sensorudløseren.",
|
||||
"interval_unit": "Enhed for intervallet: dage, uger, måneder eller år. Måneder og år følger kalenderen.",
|
||||
"trigger_combinator": "Først opfyldt (standard): trigger eller udløbet interval gør opgaven forfalden. Begge kræves: opgaven forfalder først, når triggeren er udløst og intervallet er udløbet.",
|
||||
"warning_days": "Antal dage før forfaldsdatoen, hvor der vises en advarsel.",
|
||||
"go_back": "Vend tilbage til valg af udløsertype uden at gemme."
|
||||
}
|
||||
@@ -253,6 +259,7 @@
|
||||
"trigger_delta_mode": "Delta-tilstand (tæl ændringer, ikke absolut)",
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"trigger_combinator": "Kombinér trigger og interval",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig",
|
||||
@@ -263,6 +270,7 @@
|
||||
"trigger_delta_mode": "Hvis aktiveret, tælles forskellen fra en baseline i stedet for den absolutte værdi.",
|
||||
"interval_days": "Valgfrit tidsbaseret sikkerhedsinterval ud over tællerudløseren.",
|
||||
"interval_unit": "Enhed for intervallet: dage, uger, måneder eller år. Måneder og år følger kalenderen.",
|
||||
"trigger_combinator": "Først opfyldt (standard): trigger eller udløbet interval gør opgaven forfalden. Begge kræves: opgaven forfalder først, når triggeren er udløst og intervallet er udløbet.",
|
||||
"warning_days": "Antal dage før forfaldsdatoen, hvor der vises en advarsel.",
|
||||
"go_back": "Vend tilbage til valg af udløsertype uden at gemme."
|
||||
}
|
||||
@@ -276,6 +284,7 @@
|
||||
"trigger_target_changes": "Antal ændringer for at udløse",
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"trigger_combinator": "Kombinér trigger og interval",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
@@ -286,6 +295,7 @@
|
||||
"trigger_target_changes": "Antal matchende tilstandsændringer, før vedligeholdelse udløses.",
|
||||
"interval_days": "Valgfrit tidsbaseret sikkerhedsinterval ud over udløseren for tilstandsændring.",
|
||||
"interval_unit": "Enhed for intervallet: dage, uger, måneder eller år. Måneder og år følger kalenderen.",
|
||||
"trigger_combinator": "Først opfyldt (standard): trigger eller udløbet interval gør opgaven forfalden. Begge kræves: opgaven forfalder først, når triggeren er udløst og intervallet er udløbet.",
|
||||
"warning_days": "Antal dage før forfaldsdatoen, hvor der vises en advarsel.",
|
||||
"go_back": "Vend tilbage til valg af udløsertype uden at gemme."
|
||||
}
|
||||
@@ -298,6 +308,7 @@
|
||||
"trigger_on_states": "Aktive tilstande (kommasepareret)",
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"trigger_combinator": "Kombinér trigger og interval",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
@@ -307,6 +318,7 @@
|
||||
"trigger_on_states": "Hvilke sensortilstande der tæller som 'aktive'. Lad feltet stå tomt for standard: on, 1, true. Eksempel: in_use, running",
|
||||
"interval_days": "Valgfrit tidsbaseret sikkerhedsinterval ud over driftstidsudløseren.",
|
||||
"interval_unit": "Enhed for intervallet: dage, uger, måneder eller år. Måneder og år følger kalenderen.",
|
||||
"trigger_combinator": "Først opfyldt (standard): trigger eller udløbet interval gør opgaven forfalden. Begge kræves: opgaven forfalder først, når triggeren er udløst og intervallet er udløbet.",
|
||||
"warning_days": "Antal dage før forfaldsdatoen, hvor der vises en advarsel.",
|
||||
"go_back": "Vend tilbage til valg af udløsertype uden at gemme."
|
||||
}
|
||||
@@ -353,12 +365,16 @@
|
||||
"data": {
|
||||
"trigger_above": "Udløs over",
|
||||
"trigger_below": "Udløs under",
|
||||
"trigger_equals": "Udløs ved lig med",
|
||||
"trigger_not_equals": "Udløs ved forskellig fra",
|
||||
"trigger_for_minutes": "Varighed (minutter)",
|
||||
"go_back": "Gå tilbage"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Udløs, når værdien overskrider denne tærskel.",
|
||||
"trigger_below": "Udløs, når værdien falder under denne tærskel.",
|
||||
"trigger_equals": "Udløs vedligeholdelse, når værdien er lig med dette niveau.",
|
||||
"trigger_not_equals": "Udløs vedligeholdelse, når værdien afviger fra dette niveau.",
|
||||
"trigger_for_minutes": "Værdien skal forblive ud over tærsklen i denne varighed.",
|
||||
"go_back": "Vend tilbage til valg af betingelsestype uden at gemme."
|
||||
}
|
||||
@@ -762,12 +778,16 @@
|
||||
"data": {
|
||||
"trigger_above": "Udløs over",
|
||||
"trigger_below": "Udløs under",
|
||||
"trigger_equals": "Udløs ved lig med",
|
||||
"trigger_not_equals": "Udløs ved forskellig fra",
|
||||
"trigger_for_minutes": "Varighed (minutter)",
|
||||
"go_back": "Gå tilbage"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Udløs, når værdien overskrider denne tærskel.",
|
||||
"trigger_below": "Udløs, når værdien falder under denne tærskel.",
|
||||
"trigger_equals": "Udløs vedligeholdelse, når værdien er lig med dette niveau.",
|
||||
"trigger_not_equals": "Udløs vedligeholdelse, når værdien afviger fra dette niveau.",
|
||||
"trigger_for_minutes": "Værdien skal forblive ud over tærsklen i denne varighed."
|
||||
}
|
||||
},
|
||||
@@ -1004,9 +1024,12 @@
|
||||
"data": {
|
||||
"trigger_above": "Udløs når over",
|
||||
"trigger_below": "Udløs når under",
|
||||
"trigger_equals": "Udløs ved lig med",
|
||||
"trigger_not_equals": "Udløs ved forskellig fra",
|
||||
"trigger_for_minutes": "I mindst (minutter)",
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"trigger_combinator": "Kombinér trigger og interval",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
@@ -1014,9 +1037,12 @@
|
||||
"data_description": {
|
||||
"trigger_above": "Udløs vedligeholdelse, når værdien overskrider denne tærskel.",
|
||||
"trigger_below": "Udløs vedligeholdelse, når værdien falder under denne tærskel.",
|
||||
"trigger_equals": "Udløs vedligeholdelse, når værdien er lig med dette niveau.",
|
||||
"trigger_not_equals": "Udløs vedligeholdelse, når værdien afviger fra dette niveau.",
|
||||
"trigger_for_minutes": "Værdien skal overskride tærsklen i så mange minutter, før der udløses.",
|
||||
"interval_days": "Valgfrit tidsbaseret sikkerhedsinterval ud over sensorudløseren.",
|
||||
"interval_unit": "Enhed for intervallet: dage, uger, måneder eller år. Måneder og år følger kalenderen.",
|
||||
"trigger_combinator": "Først opfyldt (standard): trigger eller udløbet interval gør opgaven forfalden. Begge kræves: opgaven forfalder først, når triggeren er udløst og intervallet er udløbet.",
|
||||
"warning_days": "Antal dage før forfaldsdatoen, hvor der vises en advarsel."
|
||||
}
|
||||
},
|
||||
@@ -1028,6 +1054,7 @@
|
||||
"trigger_delta_mode": "Delta-tilstand (tæl ændringer, ikke absolut)",
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"trigger_combinator": "Kombinér trigger og interval",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig",
|
||||
@@ -1038,6 +1065,7 @@
|
||||
"trigger_delta_mode": "Hvis aktiveret, tælles forskellen fra en baseline i stedet for den absolutte værdi.",
|
||||
"interval_days": "Valgfrit tidsbaseret sikkerhedsinterval ud over tællerudløseren.",
|
||||
"interval_unit": "Enhed for intervallet: dage, uger, måneder eller år. Måneder og år følger kalenderen.",
|
||||
"trigger_combinator": "Først opfyldt (standard): trigger eller udløbet interval gør opgaven forfalden. Begge kræves: opgaven forfalder først, når triggeren er udløst og intervallet er udløbet.",
|
||||
"warning_days": "Antal dage før forfaldsdatoen, hvor der vises en advarsel."
|
||||
}
|
||||
},
|
||||
@@ -1050,6 +1078,7 @@
|
||||
"trigger_target_changes": "Antal ændringer for at udløse",
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"trigger_combinator": "Kombinér trigger og interval",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
@@ -1060,6 +1089,7 @@
|
||||
"trigger_target_changes": "Antal matchende tilstandsændringer, før vedligeholdelse udløses.",
|
||||
"interval_days": "Valgfrit tidsbaseret sikkerhedsinterval ud over udløseren for tilstandsændring.",
|
||||
"interval_unit": "Enhed for intervallet: dage, uger, måneder eller år. Måneder og år følger kalenderen.",
|
||||
"trigger_combinator": "Først opfyldt (standard): trigger eller udløbet interval gør opgaven forfalden. Begge kræves: opgaven forfalder først, når triggeren er udløst og intervallet er udløbet.",
|
||||
"warning_days": "Antal dage før forfaldsdatoen, hvor der vises en advarsel."
|
||||
}
|
||||
},
|
||||
@@ -1071,6 +1101,7 @@
|
||||
"trigger_on_states": "Aktive tilstande (kommasepareret)",
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"trigger_combinator": "Kombinér trigger og interval",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
@@ -1080,6 +1111,7 @@
|
||||
"trigger_on_states": "Hvilke sensortilstande der tæller som 'aktive'. Lad feltet stå tomt for standard: on, 1, true. Eksempel: in_use, running",
|
||||
"interval_days": "Valgfrit tidsbaseret sikkerhedsinterval ud over driftstidsudløseren.",
|
||||
"interval_unit": "Enhed for intervallet: dage, uger, måneder eller år. Måneder og år følger kalenderen.",
|
||||
"trigger_combinator": "Først opfyldt (standard): trigger eller udløbet interval gør opgaven forfalden. Begge kræves: opgaven forfalder først, når triggeren er udløst og intervallet er udløbet.",
|
||||
"warning_days": "Antal dage før forfaldsdatoen, hvor der vises en advarsel."
|
||||
}
|
||||
},
|
||||
@@ -1482,6 +1514,12 @@
|
||||
"all": "Alle enheder skal udløses"
|
||||
}
|
||||
},
|
||||
"trigger_combinator": {
|
||||
"options": {
|
||||
"any": "Trigger eller interval (først opfyldt)",
|
||||
"all": "Trigger og interval (begge kræves)"
|
||||
}
|
||||
},
|
||||
"notification_title_style": {
|
||||
"options": {
|
||||
"default": "Standard (titel pr. status)",
|
||||
@@ -1518,6 +1556,10 @@
|
||||
"completed_by": {
|
||||
"name": "Udført af",
|
||||
"description": "Person der udførte vedligeholdelsen (skal være knyttet til en Home Assistant-bruger). Hvis udeladt registreres brugeren der udløste kaldet."
|
||||
},
|
||||
"completed_at": {
|
||||
"name": "Udført den",
|
||||
"description": "Hvornår vedligeholdelsen faktisk blev udført — til at efterregistrere en tidligere udførelse. Må ikke ligge i fremtiden; udelades den, registreres nu."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1925,6 +1967,9 @@
|
||||
},
|
||||
"completion_details_required": {
|
||||
"message": "”{task_name}” kræver disse oplysninger ved fuldførelse: {fields}. Fuldfør opgaven fra vedligeholdelsespanelet eller kortet for at udfylde dem."
|
||||
},
|
||||
"completed_at_in_future": {
|
||||
"message": "Udførelsesdatoen må ikke ligge i fremtiden."
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
|
||||
Loaded 100 of 185 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user