158 files
This commit is contained in:
1 parent
c6db6ca558
commit
5388267a3e
158 files changed
+11840
-698
No files matched your search
@@ -133,6 +133,9 @@ SERVICE_COMPLETE_SCHEMA = vol.Schema(
|
||||
vol.Optional("duration"): vol.All(vol.Coerce(int), vol.Range(min=0, max=MAX_DURATION_MINUTES)),
|
||||
# Meter readings (v2.20, #83): recorded value for `reading` tasks.
|
||||
vol.Optional("reading_value"): vol.All(vol.Coerce(float), vol.Range(min=-1e12, max=1e12)),
|
||||
# #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,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -215,6 +218,10 @@ SERVICE_UPDATE_TASK_SCHEMA = vol.Schema(
|
||||
vol.Optional("notes"): vol.All(cv.string, vol.Length(max=MAX_TEXT_LENGTH)),
|
||||
vol.Optional("priority"): vol.In(TASK_PRIORITIES),
|
||||
vol.Optional("labels"): vol.All([vol.All(cv.string, vol.Length(max=MAX_LABEL_LENGTH))], vol.Length(max=MAX_LABELS)),
|
||||
# #128: (re)assign via automations — a person ENTITY resolved to the
|
||||
# linked HA user; the boolean clears the assignment instead.
|
||||
vol.Optional("responsible_user"): cv.entity_id,
|
||||
vol.Optional("clear_responsible_user"): cv.boolean,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -425,6 +432,25 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool:
|
||||
|
||||
async_register_document_views(hass)
|
||||
|
||||
def _resolve_person_user_id(person_entity_id: str) -> str:
|
||||
"""Resolve a person ENTITY to its linked HA user id (#128).
|
||||
|
||||
Person entities are the validated way to reference a user in a
|
||||
service form (HA has no user selector) — the picker rules out typos,
|
||||
and the entity's ``user_id`` attribute carries the account link.
|
||||
"""
|
||||
state = hass.states.get(person_entity_id)
|
||||
if state is None or not person_entity_id.startswith("person."):
|
||||
raise ServiceValidationError(
|
||||
f"{person_entity_id!r} is not a known person entity"
|
||||
)
|
||||
user_id = state.attributes.get("user_id")
|
||||
if not user_id:
|
||||
raise ServiceValidationError(
|
||||
f"Person {state.name!r} is not linked to a Home Assistant user account"
|
||||
)
|
||||
return str(user_id)
|
||||
|
||||
async def _handle_complete(call: ServiceCall) -> None:
|
||||
"""Handle the complete service call."""
|
||||
entity_id = call.data[ATTR_ENTITY_ID]
|
||||
@@ -442,12 +468,19 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool:
|
||||
translation_key="no_task_for_entity",
|
||||
translation_placeholders={"entity_id": entity_id},
|
||||
)
|
||||
# #128: explicit person beats the call context; the context covers the
|
||||
# common case for free (a dashboard tap propagates the tapping user).
|
||||
if call.data.get("completed_by"):
|
||||
completed_by: str | None = _resolve_person_user_id(call.data["completed_by"])
|
||||
else:
|
||||
completed_by = call.context.user_id if call.context else None
|
||||
await coordinator.complete_maintenance(
|
||||
task_id=task_id,
|
||||
notes=call.data.get("notes"),
|
||||
cost=call.data.get("cost"),
|
||||
duration=call.data.get("duration"),
|
||||
reading_value=call.data.get("reading_value"),
|
||||
completed_by=completed_by,
|
||||
)
|
||||
|
||||
async def _handle_reset(call: ServiceCall) -> None:
|
||||
@@ -599,6 +632,16 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool:
|
||||
"priority": call.data.get("priority"),
|
||||
"labels": call.data.get("labels"),
|
||||
}
|
||||
# #128: assignment via automations. Person entity -> HA user id; the
|
||||
# clear flag maps to "" (async_update_task_simple pops the key).
|
||||
if call.data.get("responsible_user") and call.data.get("clear_responsible_user"):
|
||||
raise ServiceValidationError(
|
||||
"Provide either responsible_user or clear_responsible_user, not both"
|
||||
)
|
||||
if call.data.get("responsible_user"):
|
||||
updates["responsible_user_id"] = _resolve_person_user_id(call.data["responsible_user"])
|
||||
elif call.data.get("clear_responsible_user"):
|
||||
updates["responsible_user_id"] = ""
|
||||
try:
|
||||
await async_update_task_simple(
|
||||
hass,
|
||||
|
||||
@@ -29,10 +29,9 @@ from .helpers.task_fields import INTERVAL_DAYS_RANGE
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
||||
# UI-only cap for the adaptive MINIMUM interval (one year). Deliberately not a
|
||||
# shared const: the adaptive min has no WS/schema twin to drift from — the
|
||||
# engine clamps recommendations to the per-task min/max pair itself.
|
||||
_ADAPTIVE_MIN_INTERVAL_CAP_DAYS = 365
|
||||
# Cap for the adaptive MINIMUM interval (one year). Shared with the
|
||||
# task/set_adaptive WS schema since the parity round — same field, two UIs.
|
||||
from .const import ADAPTIVE_MIN_INTERVAL_CAP_DAYS as _ADAPTIVE_MIN_INTERVAL_CAP_DAYS
|
||||
|
||||
|
||||
class AdaptiveMixin:
|
||||
|
||||
@@ -88,6 +88,46 @@ TRIGGER_ENTITY_DOMAINS = [
|
||||
]
|
||||
|
||||
|
||||
def _apply_recovery_flag(tc: dict[str, Any], user_input: dict[str, Any]) -> None:
|
||||
"""Write the #53 auto-complete-on-recovery flag from a form submission.
|
||||
|
||||
Editable since the dialog/flow parity round — before that the flow only
|
||||
carried a previously stored value. Absence in trigger_config means off.
|
||||
"""
|
||||
if user_input.get("auto_complete_on_recovery"):
|
||||
tc["auto_complete_on_recovery"] = True
|
||||
else:
|
||||
tc.pop("auto_complete_on_recovery", None)
|
||||
|
||||
|
||||
def _recovery_default(tc: dict[str, Any] | None) -> bool:
|
||||
return bool((tc or {}).get("auto_complete_on_recovery"))
|
||||
|
||||
|
||||
def _state_selector(entity_id: str | None, *, multiple: bool = False) -> Any:
|
||||
"""State field bound to the trigger entity (#129 follow-up).
|
||||
|
||||
Suggests the entity's known states instead of free text — typo'd states
|
||||
were a real failure mode. Falls back to a plain text field when no entity
|
||||
is available (defensive; the entity step always runs first).
|
||||
"""
|
||||
if entity_id:
|
||||
return selector.StateSelector(
|
||||
selector.StateSelectorConfig(entity_id=entity_id, multiple=multiple)
|
||||
)
|
||||
return selector.TextSelector(selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT))
|
||||
|
||||
|
||||
def _parse_states(raw: Any) -> list[str]:
|
||||
"""Normalize an on-states submission — list from the state selector,
|
||||
comma string from the legacy text fallback."""
|
||||
if isinstance(raw, list):
|
||||
return [s.strip().lower() for s in raw if isinstance(s, str) and s.strip()]
|
||||
if isinstance(raw, str):
|
||||
return [s.strip().lower() for s in raw.split(",") if s.strip()]
|
||||
return []
|
||||
|
||||
|
||||
class TriggerConfigMixin:
|
||||
"""Shared sensor trigger configuration logic for ConfigFlow and OptionsFlow.
|
||||
|
||||
@@ -381,6 +421,7 @@ class TriggerConfigMixin:
|
||||
if below is not None:
|
||||
tc[CONF_TRIGGER_BELOW] = below
|
||||
tc[CONF_TRIGGER_FOR_MINUTES] = user_input.get(CONF_TRIGGER_FOR_MINUTES, 0)
|
||||
_apply_recovery_flag(tc, user_input)
|
||||
|
||||
# Multi-entity: store entity_logic if multiple entities selected
|
||||
entity_ids = tc.get("entity_ids", [])
|
||||
@@ -419,6 +460,10 @@ class TriggerConfigMixin:
|
||||
vol.Optional(CONF_TRIGGER_FOR_MINUTES, default=0): selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(min=0, max=1440, step=1, mode=selector.NumberSelectorMode.BOX)
|
||||
),
|
||||
vol.Optional(
|
||||
"auto_complete_on_recovery",
|
||||
default=_recovery_default(self._current_task.get("trigger_config")),
|
||||
): selector.BooleanSelector(),
|
||||
}
|
||||
|
||||
# Add entity_logic selector when multiple entities are selected
|
||||
@@ -480,6 +525,13 @@ class TriggerConfigMixin:
|
||||
tc = self._current_task["trigger_config"]
|
||||
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)
|
||||
# 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.
|
||||
baseline = user_input.get("trigger_baseline_value")
|
||||
if baseline is not None and baseline >= 0:
|
||||
tc["trigger_baseline_value"] = baseline
|
||||
|
||||
# Multi-entity: store entity_logic if multiple entities selected
|
||||
entity_ids = tc.get("entity_ids", [])
|
||||
@@ -510,6 +562,12 @@ class TriggerConfigMixin:
|
||||
else:
|
||||
current_value = state.state
|
||||
|
||||
prev_tc = self._current_task.get("trigger_config") or {}
|
||||
baseline_key = (
|
||||
vol.Optional("trigger_baseline_value", default=prev_tc["trigger_baseline_value"])
|
||||
if "trigger_baseline_value" in prev_tc
|
||||
else vol.Optional("trigger_baseline_value")
|
||||
)
|
||||
schema_fields: dict[Any, Any] = {
|
||||
vol.Required(CONF_TRIGGER_TARGET_VALUE): selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(
|
||||
@@ -518,6 +576,17 @@ class TriggerConfigMixin:
|
||||
)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_DELTA_MODE, default=False): selector.BooleanSelector(),
|
||||
baseline_key: selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(
|
||||
min=0,
|
||||
mode=selector.NumberSelectorMode.BOX,
|
||||
step="any",
|
||||
)
|
||||
),
|
||||
vol.Optional(
|
||||
"auto_complete_on_recovery",
|
||||
default=_recovery_default(prev_tc),
|
||||
): selector.BooleanSelector(),
|
||||
}
|
||||
|
||||
# Add entity_logic selector when multiple entities are selected
|
||||
@@ -590,6 +659,7 @@ class TriggerConfigMixin:
|
||||
if to_state:
|
||||
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)
|
||||
|
||||
# Multi-entity: store entity_logic if multiple entities selected
|
||||
entity_ids = tc.get("entity_ids", [])
|
||||
@@ -608,12 +678,8 @@ class TriggerConfigMixin:
|
||||
return on_complete()
|
||||
|
||||
schema_fields: dict[Any, Any] = {
|
||||
vol.Optional(CONF_TRIGGER_FROM_STATE): selector.TextSelector(
|
||||
selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_TO_STATE): selector.TextSelector(
|
||||
selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_FROM_STATE): _state_selector(self._trigger_entity_id),
|
||||
vol.Optional(CONF_TRIGGER_TO_STATE): _state_selector(self._trigger_entity_id),
|
||||
vol.Required(CONF_TRIGGER_TARGET_CHANGES, default=1): selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(
|
||||
min=1,
|
||||
@@ -622,6 +688,10 @@ class TriggerConfigMixin:
|
||||
mode=selector.NumberSelectorMode.BOX,
|
||||
)
|
||||
),
|
||||
vol.Optional(
|
||||
"auto_complete_on_recovery",
|
||||
default=_recovery_default(self._current_task.get("trigger_config")),
|
||||
): selector.BooleanSelector(),
|
||||
}
|
||||
|
||||
# Add entity_logic selector when multiple entities are selected
|
||||
@@ -684,12 +754,12 @@ class TriggerConfigMixin:
|
||||
tc = self._current_task["trigger_config"]
|
||||
tc[CONF_TRIGGER_RUNTIME_HOURS] = user_input[CONF_TRIGGER_RUNTIME_HOURS]
|
||||
|
||||
# Parse comma-separated ON states
|
||||
raw_states = user_input.get(CONF_TRIGGER_ON_STATES, "")
|
||||
if raw_states and raw_states.strip():
|
||||
tc[CONF_TRIGGER_ON_STATES] = [s.strip().lower() for s in raw_states.split(",") if s.strip()]
|
||||
states = _parse_states(user_input.get(CONF_TRIGGER_ON_STATES))
|
||||
if states:
|
||||
tc[CONF_TRIGGER_ON_STATES] = states
|
||||
else:
|
||||
tc.pop(CONF_TRIGGER_ON_STATES, None)
|
||||
_apply_recovery_flag(tc, user_input)
|
||||
|
||||
# Multi-entity: store entity_logic if multiple entities selected
|
||||
entity_ids = tc.get("entity_ids", [])
|
||||
@@ -709,8 +779,9 @@ class TriggerConfigMixin:
|
||||
|
||||
# Pre-fill existing custom states for editing
|
||||
current_tc = self._current_task.get("trigger_config", {})
|
||||
existing_states = current_tc.get(CONF_TRIGGER_ON_STATES)
|
||||
default_states = ", ".join(existing_states) if existing_states else ""
|
||||
existing_states = current_tc.get(CONF_TRIGGER_ON_STATES) or []
|
||||
# The state selector takes/returns a LIST; the text fallback a comma string.
|
||||
default_states: Any = list(existing_states) if self._trigger_entity_id else ", ".join(existing_states)
|
||||
|
||||
schema_fields: dict[Any, Any] = {
|
||||
vol.Required(CONF_TRIGGER_RUNTIME_HOURS): selector.NumberSelector(
|
||||
@@ -722,11 +793,13 @@ class TriggerConfigMixin:
|
||||
unit_of_measurement="h",
|
||||
)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_ON_STATES, default=default_states): selector.TextSelector(
|
||||
selector.TextSelectorConfig(
|
||||
type=selector.TextSelectorType.TEXT,
|
||||
)
|
||||
vol.Optional(CONF_TRIGGER_ON_STATES, default=default_states): _state_selector(
|
||||
self._trigger_entity_id, multiple=True
|
||||
),
|
||||
vol.Optional(
|
||||
"auto_complete_on_recovery",
|
||||
default=_recovery_default(current_tc),
|
||||
): selector.BooleanSelector(),
|
||||
}
|
||||
|
||||
# Add entity_logic selector when multiple entities are selected
|
||||
@@ -791,15 +864,12 @@ class TriggerConfigMixin:
|
||||
return cancel
|
||||
|
||||
logic = user_input.get(CONF_COMPOUND_LOGIC, "AND").upper()
|
||||
# Carry over the panel-managed recovery flag (#53) across the
|
||||
# compound rebuild, mirroring the flat-trigger path above.
|
||||
prev_tc = self._current_task.get("trigger_config") or {}
|
||||
self._current_task["trigger_config"] = {
|
||||
"type": TriggerType.COMPOUND,
|
||||
CONF_COMPOUND_LOGIC: logic,
|
||||
CONF_COMPOUND_CONDITIONS: [],
|
||||
**({"auto_complete_on_recovery": True} if prev_tc.get("auto_complete_on_recovery") else {}),
|
||||
}
|
||||
_apply_recovery_flag(self._current_task["trigger_config"], user_input)
|
||||
if not hasattr(self, "_compound_conditions"):
|
||||
self._compound_conditions: list[dict[str, Any]] = []
|
||||
self._compound_conditions = []
|
||||
@@ -823,6 +893,10 @@ class TriggerConfigMixin:
|
||||
translation_key="compound_logic",
|
||||
)
|
||||
),
|
||||
vol.Optional(
|
||||
"auto_complete_on_recovery",
|
||||
default=_recovery_default(self._current_task.get("trigger_config")),
|
||||
): selector.BooleanSelector(),
|
||||
}
|
||||
return self.async_show_form(
|
||||
step_id=step_id,
|
||||
@@ -961,9 +1035,9 @@ class TriggerConfigMixin:
|
||||
cond["trigger_target_changes"] = user_input.get(CONF_TRIGGER_TARGET_CHANGES, 1)
|
||||
elif condition_type == TriggerType.RUNTIME:
|
||||
cond["trigger_runtime_hours"] = user_input[CONF_TRIGGER_RUNTIME_HOURS]
|
||||
raw_states = user_input.get(CONF_TRIGGER_ON_STATES, "")
|
||||
if raw_states and raw_states.strip():
|
||||
cond["trigger_on_states"] = [s.strip().lower() for s in raw_states.split(",") if s.strip()]
|
||||
states = _parse_states(user_input.get(CONF_TRIGGER_ON_STATES))
|
||||
if states:
|
||||
cond["trigger_on_states"] = states
|
||||
|
||||
entity_ids = cond.get("entity_ids", [])
|
||||
if len(entity_ids) > 1 and user_input.get(CONF_TRIGGER_ENTITY_LOGIC):
|
||||
@@ -1000,13 +1074,10 @@ class TriggerConfigMixin:
|
||||
vol.Optional(CONF_TRIGGER_DELTA_MODE, default=False): selector.BooleanSelector(),
|
||||
}
|
||||
elif condition_type == TriggerType.STATE_CHANGE:
|
||||
cond_entity = cond.get("entity_id")
|
||||
schema_fields = {
|
||||
vol.Optional(CONF_TRIGGER_FROM_STATE): selector.TextSelector(
|
||||
selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_TO_STATE): selector.TextSelector(
|
||||
selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_FROM_STATE): _state_selector(cond_entity),
|
||||
vol.Optional(CONF_TRIGGER_TO_STATE): _state_selector(cond_entity),
|
||||
vol.Required(CONF_TRIGGER_TARGET_CHANGES, default=1): selector.NumberSelector(
|
||||
selector.NumberSelectorConfig(
|
||||
min=1,
|
||||
@@ -1027,9 +1098,10 @@ class TriggerConfigMixin:
|
||||
unit_of_measurement="h",
|
||||
)
|
||||
),
|
||||
vol.Optional(CONF_TRIGGER_ON_STATES, default=""): selector.TextSelector(
|
||||
selector.TextSelectorConfig(type=selector.TextSelectorType.TEXT)
|
||||
),
|
||||
vol.Optional(
|
||||
CONF_TRIGGER_ON_STATES,
|
||||
default=[] if cond.get("entity_id") else "",
|
||||
): _state_selector(cond.get("entity_id"), multiple=True),
|
||||
}
|
||||
|
||||
entity_ids = cond.get("entity_ids", [])
|
||||
|
||||
@@ -403,6 +403,9 @@ CONF_ADAPTIVE_ENABLED = "adaptive_enabled"
|
||||
CONF_ADAPTIVE_EWA_ALPHA = "ewa_alpha"
|
||||
CONF_ADAPTIVE_MIN_INTERVAL = "min_interval_days"
|
||||
CONF_ADAPTIVE_MAX_INTERVAL = "max_interval_days"
|
||||
# Deliberate cap: a MINIMUM interval above a year defeats adaptive learning.
|
||||
# Shared by the options flow's adaptive step and the task/set_adaptive WS.
|
||||
ADAPTIVE_MIN_INTERVAL_CAP_DAYS = 365
|
||||
|
||||
# --- Config Keys: Seasonal Scheduling ---
|
||||
CONF_SEASONAL_ENABLED = "seasonal_enabled"
|
||||
|
||||
+4
-2
@@ -33,9 +33,11 @@ function completeDialog(el: HTMLElement): MaintenanceCompleteDialog | null {
|
||||
}
|
||||
|
||||
/** The dialogs are lazy code-split chunks — the open lands whenever the
|
||||
* whole lazy-UI group has loaded, so poll instead of guessing a delay. */
|
||||
* whole lazy-UI group has loaded, so poll instead of guessing a delay.
|
||||
* Generous window: under full-suite concurrency (70+ files) the 2 s the
|
||||
* poll originally allowed was load-dependent flaky. */
|
||||
async function waitForOpenCompleteDialog(el: HTMLElement): Promise<void> {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
for (let i = 0; i < 400; i++) {
|
||||
if (completeDialog(el)?.shadowRoot?.querySelector("ha-dialog")) return;
|
||||
await new Promise((r) => setTimeout(r, 20));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,11 @@ import type { AdaptiveConfig, HomeAssistant, MaintenanceTask, TaskPartLink, Trig
|
||||
import { formatDate, t, weekdayName } from "../styles";
|
||||
import { UserService } from "../user-service";
|
||||
import { partLinkKey } from "../helpers/shared-parts";
|
||||
import {
|
||||
ENVIRONMENTAL_PICKER_DEVICE_CLASSES,
|
||||
ENVIRONMENTAL_PICKER_DOMAINS,
|
||||
TRIGGER_PICKER_DOMAINS,
|
||||
} from "../helpers/trigger-domains";
|
||||
|
||||
import { describeWsError } from "../ws-errors";
|
||||
import { REQUIRED_COMPLETION_KEYS, REQUIRED_COMPLETION_LABELS } from "./required-completion-labels";
|
||||
@@ -25,6 +30,7 @@ const TRIGGER_TYPE_KEYS_WITH_COMPOUND = [...TRIGGER_TYPE_KEYS, "compound"];
|
||||
interface CompoundConditionDraft {
|
||||
entityIds: string; // comma-separated raw input
|
||||
type: string; // threshold | counter | state_change | runtime
|
||||
attribute: string; // "" = use the entity state
|
||||
above: string;
|
||||
below: string;
|
||||
forMinutes: string;
|
||||
@@ -42,7 +48,7 @@ interface CompoundConditionDraft {
|
||||
|
||||
function emptyCondition(): CompoundConditionDraft {
|
||||
return {
|
||||
entityIds: "", type: "threshold", above: "", below: "", forMinutes: "0",
|
||||
entityIds: "", type: "threshold", attribute: "", above: "", below: "", forMinutes: "0",
|
||||
targetValue: "", deltaMode: false, fromState: "", toState: "",
|
||||
targetChanges: "", runtimeHours: "", onStates: "", carry: {},
|
||||
};
|
||||
@@ -51,7 +57,7 @@ function emptyCondition(): CompoundConditionDraft {
|
||||
/** Keys the compound editor owns via its own form fields — everything else
|
||||
* travels through `carry` untouched. */
|
||||
const MANAGED_CONDITION_KEYS = new Set([
|
||||
"entity_id", "entity_ids", "type",
|
||||
"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",
|
||||
@@ -64,6 +70,7 @@ function conditionToDraft(c: TriggerConfig): CompoundConditionDraft {
|
||||
return {
|
||||
entityIds: ids.join(", "),
|
||||
type: c.type || "threshold",
|
||||
attribute: c.attribute || "",
|
||||
above: c.trigger_above?.toString() ?? "",
|
||||
below: c.trigger_below?.toString() ?? "",
|
||||
forMinutes: c.trigger_for_minutes?.toString() ?? "0",
|
||||
@@ -86,6 +93,7 @@ function draftToCondition(d: CompoundConditionDraft): TriggerConfig | null {
|
||||
const ids = d.entityIds.split(",").map((s) => s.trim()).filter(Boolean);
|
||||
if (ids.length === 0) return null;
|
||||
const c: TriggerConfig = { ...(d.carry || {}), entity_id: ids[0], entity_ids: ids, type: d.type };
|
||||
if (d.attribute) c.attribute = d.attribute;
|
||||
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;
|
||||
@@ -133,6 +141,11 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
parts: Array<{ id: string; name: string; unit?: string }>;
|
||||
}> = [];
|
||||
@state() private _open = false;
|
||||
// #129: flips the trigger entity pickers back to comma text fields when the
|
||||
// HA picker fails to lay out in this mount context (see _probeEntityPickers).
|
||||
@state() private _entityPickerFallback = false;
|
||||
private _pickerProbeTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
private _pickerProbeStrikes = 0;
|
||||
@state() private _loading = false;
|
||||
@state() private _error = "";
|
||||
@state() private _entryId = "";
|
||||
@@ -263,6 +276,22 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
@state() private _environmentalAttribute = "";
|
||||
private _environmentalInitial = ""; // for change detection on save
|
||||
private _environmentalAttributeInitial = "";
|
||||
// Adaptive tuning (parity with the options flow's adaptive step) — Store-
|
||||
// managed like the environmental binding, saved through task/set_adaptive.
|
||||
@state() private _adaptiveEnabled = false;
|
||||
@state() private _adaptiveAlpha = "0.3";
|
||||
@state() private _adaptiveMin = "7";
|
||||
@state() private _adaptiveMax = "365";
|
||||
@state() private _adaptiveSeasonal = true;
|
||||
@state() private _adaptivePrediction = true;
|
||||
private _adaptiveInitial = "";
|
||||
|
||||
private _adaptiveSnapshot(): string {
|
||||
return JSON.stringify([
|
||||
this._adaptiveEnabled, this._adaptiveAlpha, this._adaptiveMin,
|
||||
this._adaptiveMax, this._adaptiveSeasonal, this._adaptivePrediction,
|
||||
]);
|
||||
}
|
||||
private _userService: UserService | null = null;
|
||||
|
||||
private get _lang(): string {
|
||||
@@ -374,6 +403,13 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
this._environmentalAttribute = ac.environmental_attribute || "";
|
||||
this._environmentalInitial = this._environmentalEntity;
|
||||
this._environmentalAttributeInitial = this._environmentalAttribute;
|
||||
this._adaptiveEnabled = !!ac.enabled;
|
||||
this._adaptiveAlpha = (ac.ewa_alpha ?? 0.3).toString();
|
||||
this._adaptiveMin = (ac.min_interval_days ?? 7).toString();
|
||||
this._adaptiveMax = (ac.max_interval_days ?? 365).toString();
|
||||
this._adaptiveSeasonal = ac.seasonal_enabled !== false;
|
||||
this._adaptivePrediction = ac.sensor_prediction_enabled !== false;
|
||||
this._adaptiveInitial = this._adaptiveSnapshot();
|
||||
|
||||
if (task.trigger_config) {
|
||||
const tc = task.trigger_config;
|
||||
@@ -460,6 +496,13 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
this._environmentalAttribute = "";
|
||||
this._environmentalInitial = "";
|
||||
this._environmentalAttributeInitial = "";
|
||||
this._adaptiveEnabled = false;
|
||||
this._adaptiveAlpha = "0.3";
|
||||
this._adaptiveMin = "7";
|
||||
this._adaptiveMax = "365";
|
||||
this._adaptiveSeasonal = true;
|
||||
this._adaptivePrediction = true;
|
||||
this._adaptiveInitial = this._adaptiveSnapshot();
|
||||
// v1.3.0
|
||||
this._actionService = "";
|
||||
this._actionTargetEntity = "";
|
||||
@@ -802,6 +845,46 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
/** Per-entity attribute options — generic entity_id-keyed cache, fetched
|
||||
* lazily; serves the compound condition rows AND the environmental
|
||||
* attribute dropdown. (Parity round: the flow's compound path always had
|
||||
* an attribute step; the dialog only carried it without an editor.) */
|
||||
@state() private _conditionAttrOptions: Record<
|
||||
string,
|
||||
{ suggested: string[]; available: Array<{ name: string; numeric: boolean }> }
|
||||
> = {};
|
||||
private _conditionAttrPending = new Set<string>();
|
||||
|
||||
private _fetchConditionAttributes(entityId: string): void {
|
||||
if (!entityId || !this.hass) return;
|
||||
if (this._conditionAttrOptions[entityId] || this._conditionAttrPending.has(entityId)) return;
|
||||
this._conditionAttrPending.add(entityId);
|
||||
void this.hass.connection
|
||||
.sendMessagePromise({
|
||||
type: "maintenance_supporter/entity/attributes",
|
||||
entity_id: entityId,
|
||||
})
|
||||
.then((result) => {
|
||||
const r = result as {
|
||||
suggested_attributes: string[];
|
||||
available_attributes: Array<{ name: string; numeric: boolean }>;
|
||||
};
|
||||
this._conditionAttrOptions = {
|
||||
...this._conditionAttrOptions,
|
||||
[entityId]: {
|
||||
suggested: r.suggested_attributes || [],
|
||||
available: r.available_attributes || [],
|
||||
},
|
||||
};
|
||||
})
|
||||
.catch(() => {
|
||||
this._conditionAttrOptions = {
|
||||
...this._conditionAttrOptions,
|
||||
[entityId]: { suggested: [], available: [] },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private async _fetchEntityAttributes(entityId: string): Promise<void> {
|
||||
if (!entityId || !this.hass) {
|
||||
this._suggestedAttributes = [];
|
||||
@@ -894,6 +977,14 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
private async _save(): Promise<void> {
|
||||
if (this._loading) return; // synchronous re-entry guard (double-click)
|
||||
if (!this._name.trim()) return;
|
||||
if (this._adaptiveSnapshot() !== this._adaptiveInitial) {
|
||||
const minIv = parseInt(this._adaptiveMin, 10);
|
||||
const maxIv = parseInt(this._adaptiveMax, 10);
|
||||
if (!isNaN(minIv) && !isNaN(maxIv) && minIv > maxIv) {
|
||||
this._error = `${t("adaptive_min_interval", this._lang)} > ${t("adaptive_max_interval", this._lang)}`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._loading = true;
|
||||
this._error = "";
|
||||
try {
|
||||
@@ -1116,6 +1207,30 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
// Adaptive tuning is Store-managed like the environmental binding —
|
||||
// dedicated endpoint, only called when something actually changed.
|
||||
if (savedTaskId && this._adaptiveSnapshot() !== this._adaptiveInitial) {
|
||||
const alpha = parseFloat(this._adaptiveAlpha);
|
||||
const minIv = parseInt(this._adaptiveMin, 10);
|
||||
const maxIv = parseInt(this._adaptiveMax, 10);
|
||||
try {
|
||||
await this.hass.connection.sendMessagePromise({
|
||||
type: "maintenance_supporter/task/set_adaptive",
|
||||
entry_id: this._entryId,
|
||||
task_id: savedTaskId,
|
||||
enabled: this._adaptiveEnabled,
|
||||
...(alpha >= 0.1 && alpha <= 0.9 ? { ewa_alpha: alpha } : {}),
|
||||
...(!isNaN(minIv) && minIv >= 1 ? { min_interval_days: minIv } : {}),
|
||||
...(!isNaN(maxIv) && maxIv >= 1 ? { max_interval_days: maxIv } : {}),
|
||||
seasonal_enabled: this._adaptiveSeasonal,
|
||||
sensor_prediction_enabled: this._adaptivePrediction,
|
||||
});
|
||||
this._adaptiveInitial = this._adaptiveSnapshot();
|
||||
} catch {
|
||||
/* non-fatal — task itself saved */
|
||||
}
|
||||
}
|
||||
|
||||
this._open = false;
|
||||
this.dispatchEvent(new CustomEvent("task-saved"));
|
||||
} catch (e) {
|
||||
@@ -1127,6 +1242,11 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
|
||||
private _close(): void {
|
||||
this._open = false;
|
||||
if (this._pickerProbeTimer !== undefined) {
|
||||
clearTimeout(this._pickerProbeTimer);
|
||||
this._pickerProbeTimer = undefined;
|
||||
}
|
||||
this._pickerProbeStrikes = 0;
|
||||
}
|
||||
|
||||
private _renderTriggerFields() {
|
||||
@@ -1148,17 +1268,40 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
</select>
|
||||
</div>
|
||||
${isCompound ? this._renderCompoundEditor() : html`
|
||||
<ms-textfield
|
||||
label="${t("entity_id", L)} (${t("comma_separated", L)})"
|
||||
.value=${this._triggerEntityIds.length > 0 ? this._triggerEntityIds.join(", ") : this._triggerEntityId}
|
||||
@input=${(e: Event) => {
|
||||
const raw = (e.target as HTMLInputElement).value;
|
||||
const ids = raw.split(",").map((s: string) => s.trim()).filter(Boolean);
|
||||
${this._entityPickerFallback ? html`
|
||||
<ms-textfield
|
||||
label="${t("entity_id", L)} (${t("comma_separated", L)})"
|
||||
.value=${this._triggerEntityIds.length > 0 ? this._triggerEntityIds.join(", ") : this._triggerEntityId}
|
||||
@input=${(e: Event) => {
|
||||
const raw = (e.target as HTMLInputElement).value;
|
||||
const ids = raw.split(",").map((s: string) => s.trim()).filter(Boolean);
|
||||
this._triggerEntityId = ids[0] || "";
|
||||
this._triggerEntityIds = ids;
|
||||
if (ids[0]) this._fetchEntityAttributes(ids[0]);
|
||||
}}
|
||||
></ms-textfield>
|
||||
` : html`
|
||||
<ha-form
|
||||
class="entity-picker-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{
|
||||
name: "trigger_entities",
|
||||
selector: { entity: { multiple: true, domain: TRIGGER_PICKER_DOMAINS } },
|
||||
}]}
|
||||
.data=${{
|
||||
trigger_entities: this._triggerEntityIds.length > 0
|
||||
? this._triggerEntityIds
|
||||
: this._triggerEntityId ? [this._triggerEntityId] : [],
|
||||
}}
|
||||
.computeLabel=${() => t("entity_id", L)}
|
||||
@value-changed=${(e: CustomEvent) => {
|
||||
const ids = ((e.detail.value as { trigger_entities?: string[] }).trigger_entities || []).filter(Boolean);
|
||||
this._triggerEntityId = ids[0] || "";
|
||||
this._triggerEntityIds = ids;
|
||||
if (ids[0]) this._fetchEntityAttributes(ids[0]);
|
||||
else this._fetchEntityAttributes("");
|
||||
}}
|
||||
></ms-textfield>
|
||||
></ha-form>`}
|
||||
${this._triggerEntityIds.length > 1 ? html`
|
||||
<div class="select-row">
|
||||
<label>${t("entity_logic", L)}</label>
|
||||
@@ -1275,11 +1418,28 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
@click=${() => this._removeCondition(i)}
|
||||
>✕</button>
|
||||
</div>
|
||||
<ms-textfield
|
||||
label="${t("entity_id", L)} (${t("comma_separated", L)})"
|
||||
.value=${c.entityIds}
|
||||
@input=${(e: Event) => this._patchCondition(i, { entityIds: (e.target as HTMLInputElement).value })}
|
||||
></ms-textfield>
|
||||
${this._entityPickerFallback ? html`
|
||||
<ms-textfield
|
||||
label="${t("entity_id", L)} (${t("comma_separated", L)})"
|
||||
.value=${c.entityIds}
|
||||
@input=${(e: Event) => this._patchCondition(i, { entityIds: (e.target as HTMLInputElement).value })}
|
||||
></ms-textfield>
|
||||
` : html`
|
||||
<ha-form
|
||||
class="entity-picker-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{
|
||||
name: "condition_entities",
|
||||
selector: { entity: { multiple: true, domain: TRIGGER_PICKER_DOMAINS } },
|
||||
}]}
|
||||
.data=${{ condition_entities: c.entityIds.split(",").map((s) => s.trim()).filter(Boolean) }}
|
||||
.computeLabel=${() => t("entity_id", L)}
|
||||
@value-changed=${(e: CustomEvent) => {
|
||||
const ids = ((e.detail.value as { condition_entities?: string[] }).condition_entities || []).filter(Boolean);
|
||||
this._patchCondition(i, { entityIds: ids.join(", ") });
|
||||
}}
|
||||
></ha-form>`}
|
||||
${this._renderConditionAttribute(c, i)}
|
||||
<div class="select-row">
|
||||
<label>${t("trigger_type", L)}</label>
|
||||
<select
|
||||
@@ -1296,6 +1456,198 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
/** State field bound to an entity (#129 follow-up): HA's state selector
|
||||
* suggests the entity's known states instead of free text. Falls back to
|
||||
* the plain textfield without an entity or when the pickers are broken in
|
||||
* this context (same _entityPickerFallback flag). */
|
||||
private _renderStateField(args: {
|
||||
label: string;
|
||||
value: string;
|
||||
entityId: string;
|
||||
onInput: (v: string) => void;
|
||||
}) {
|
||||
if (this._entityPickerFallback || !args.entityId) {
|
||||
return html`
|
||||
<ms-textfield
|
||||
label=${args.label}
|
||||
.value=${args.value}
|
||||
@input=${(e: Event) => args.onInput((e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<ha-form
|
||||
class="state-picker-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{ name: "s", selector: { state: { entity_id: args.entityId } } }]}
|
||||
.data=${{ s: args.value }}
|
||||
.computeLabel=${() => args.label}
|
||||
@value-changed=${(e: CustomEvent) =>
|
||||
args.onInput(((e.detail.value as { s?: string }).s || "").trim())}
|
||||
></ha-form>
|
||||
`;
|
||||
}
|
||||
|
||||
/** Multi-state variant for runtime ON-states — keeps the internal
|
||||
* comma-string representation so the save path stays unchanged. */
|
||||
private _renderOnStatesField(args: { value: string; entityId: string; onInput: (v: string) => void }) {
|
||||
const L = this._lang;
|
||||
if (this._entityPickerFallback || !args.entityId) {
|
||||
return html`
|
||||
<ms-textfield
|
||||
label="${t("runtime_on_states", L)}"
|
||||
placeholder="on"
|
||||
.value=${args.value}
|
||||
@input=${(e: Event) => args.onInput((e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<ha-form
|
||||
class="state-picker-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{ name: "s", selector: { state: { entity_id: args.entityId, multiple: true } } }]}
|
||||
.data=${{ s: (args.value || "").split(",").map((x) => x.trim()).filter(Boolean) }}
|
||||
.computeLabel=${() => t("runtime_on_states", L)}
|
||||
@value-changed=${(e: CustomEvent) =>
|
||||
args.onInput((((e.detail.value as { s?: string[] }).s) || []).join(", "))}
|
||||
></ha-form>
|
||||
`;
|
||||
}
|
||||
|
||||
/** Adaptive-scheduling tuning (parity with the options flow's adaptive
|
||||
* step). Hidden for one-time/manual tasks — there is no recurrence to
|
||||
* adapt. Collapsed unless adaptive is already enabled. */
|
||||
private _renderAdaptiveSection(L: string) {
|
||||
if (this._scheduleType === "one_time" || this._scheduleType === "manual") return nothing;
|
||||
return html`
|
||||
<details class="adaptive-section" ?open=${this._adaptiveEnabled}>
|
||||
<summary>${t("adaptive_section_title", L)}</summary>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${this._adaptiveEnabled}
|
||||
@change=${(e: Event) => (this._adaptiveEnabled = (e.target as HTMLInputElement).checked)}
|
||||
/>
|
||||
${t("adaptive_enabled", L)}
|
||||
</label>
|
||||
${this._adaptiveEnabled ? html`
|
||||
<ms-textfield
|
||||
label="${t("adaptive_min_interval", L)}"
|
||||
type="number"
|
||||
min="1"
|
||||
.value=${this._adaptiveMin}
|
||||
@input=${(e: Event) => (this._adaptiveMin = (e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${t("adaptive_max_interval", L)}"
|
||||
type="number"
|
||||
min="1"
|
||||
.value=${this._adaptiveMax}
|
||||
@input=${(e: Event) => (this._adaptiveMax = (e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${t("adaptive_ewa_alpha", L)}"
|
||||
type="number"
|
||||
min="0.1"
|
||||
max="0.9"
|
||||
step="0.1"
|
||||
.value=${this._adaptiveAlpha}
|
||||
@input=${(e: Event) => (this._adaptiveAlpha = (e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${this._adaptiveSeasonal}
|
||||
@change=${(e: Event) => (this._adaptiveSeasonal = (e.target as HTMLInputElement).checked)}
|
||||
/>
|
||||
${t("adaptive_seasonal_enabled", L)}
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${this._adaptivePrediction}
|
||||
@change=${(e: Event) => (this._adaptivePrediction = (e.target as HTMLInputElement).checked)}
|
||||
/>
|
||||
${t("adaptive_prediction_enabled", L)}
|
||||
</label>
|
||||
` : nothing}
|
||||
</details>
|
||||
`;
|
||||
}
|
||||
|
||||
/** Environmental attribute — the same live-fetched dropdown the flat and
|
||||
* compound attribute fields use, keyed by the environmental entity. */
|
||||
private _renderEnvironmentalAttribute(L: string) {
|
||||
this._fetchConditionAttributes(this._environmentalEntity);
|
||||
const opts = this._conditionAttrOptions[this._environmentalEntity];
|
||||
if (opts && opts.available.length > 0) {
|
||||
return html`
|
||||
<div class="select-row">
|
||||
<label>${t("environmental_attribute_optional", L)}</label>
|
||||
<select
|
||||
.value=${this._environmentalAttribute}
|
||||
@change=${(e: Event) => (this._environmentalAttribute = (e.target as HTMLSelectElement).value)}
|
||||
>
|
||||
<option value="" ?selected=${!this._environmentalAttribute}>${t("use_entity_state", L)}</option>
|
||||
${opts.suggested.map(
|
||||
(attr) => html`<option value=${attr} ?selected=${attr === this._environmentalAttribute}>${attr} ★</option>`
|
||||
)}
|
||||
${opts.available
|
||||
.filter((a) => !opts.suggested.includes(a.name))
|
||||
.map(
|
||||
(a) => html`<option value=${a.name} ?selected=${a.name === this._environmentalAttribute}>${a.name}${a.numeric ? "" : " (non-numeric)"}</option>`
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<ms-textfield
|
||||
label="${t("environmental_attribute_optional", L)}"
|
||||
.value=${this._environmentalAttribute}
|
||||
@input=${(e: Event) => (this._environmentalAttribute = (e.target as HTMLInputElement).value.trim())}
|
||||
></ms-textfield>
|
||||
`;
|
||||
}
|
||||
|
||||
/** Attribute selector for one compound condition — the same live-fetched
|
||||
* dropdown the flat editor has, keyed by the condition's first entity. */
|
||||
private _renderConditionAttribute(c: CompoundConditionDraft, i: number) {
|
||||
const L = this._lang;
|
||||
const firstId = c.entityIds.split(",")[0]?.trim() || "";
|
||||
if (firstId) this._fetchConditionAttributes(firstId);
|
||||
const opts = firstId ? this._conditionAttrOptions[firstId] : undefined;
|
||||
if (opts && opts.available.length > 0) {
|
||||
return html`
|
||||
<div class="select-row">
|
||||
<label>${t("attribute_optional", L)}</label>
|
||||
<select
|
||||
.value=${c.attribute}
|
||||
@change=${(e: Event) => this._patchCondition(i, { attribute: (e.target as HTMLSelectElement).value })}
|
||||
>
|
||||
<option value="" ?selected=${!c.attribute}>${t("use_entity_state", L)}</option>
|
||||
${opts.suggested.map(
|
||||
(attr) => html`<option value=${attr} ?selected=${attr === c.attribute}>${attr} ★</option>`
|
||||
)}
|
||||
${opts.available
|
||||
.filter((a) => !opts.suggested.includes(a.name))
|
||||
.map(
|
||||
(a) => html`<option value=${a.name} ?selected=${a.name === c.attribute}>${a.name}${a.numeric ? "" : " (non-numeric)"}</option>`
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<ms-textfield
|
||||
label="${t("attribute_optional", L)}"
|
||||
.value=${c.attribute}
|
||||
@input=${(e: Event) => this._patchCondition(i, { attribute: (e.target as HTMLInputElement).value.trim() })}
|
||||
></ms-textfield>
|
||||
`;
|
||||
}
|
||||
|
||||
/** Type-specific inputs for a single compound condition (mirrors the flat
|
||||
* per-type fields, bound to the condition draft). */
|
||||
private _renderConditionTypeFields(c: CompoundConditionDraft, i: number) {
|
||||
@@ -1322,21 +1674,34 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
`;
|
||||
}
|
||||
if (c.type === "state_change") {
|
||||
const condEntity = c.entityIds.split(",")[0]?.trim() || "";
|
||||
return html`
|
||||
<ms-textfield label="${t("from_state_optional", L)}" .value=${c.fromState}
|
||||
@input=${(e: Event) => this._patchCondition(i, { fromState: (e.target as HTMLInputElement).value })}></ms-textfield>
|
||||
<ms-textfield label="${t("to_state_optional", L)}" .value=${c.toState}
|
||||
@input=${(e: Event) => this._patchCondition(i, { toState: (e.target as HTMLInputElement).value })}></ms-textfield>
|
||||
${this._renderStateField({
|
||||
label: t("from_state_optional", L),
|
||||
value: c.fromState,
|
||||
entityId: condEntity,
|
||||
onInput: (v) => this._patchCondition(i, { fromState: v }),
|
||||
})}
|
||||
${this._renderStateField({
|
||||
label: t("to_state_optional", L),
|
||||
value: c.toState,
|
||||
entityId: condEntity,
|
||||
onInput: (v) => this._patchCondition(i, { toState: v }),
|
||||
})}
|
||||
<ms-textfield label="${t("target_changes", L)}" type="number" .value=${c.targetChanges}
|
||||
@input=${(e: Event) => this._patchCondition(i, { targetChanges: (e.target as HTMLInputElement).value })}></ms-textfield>
|
||||
`;
|
||||
}
|
||||
if (c.type === "runtime") {
|
||||
const condEntity = c.entityIds.split(",")[0]?.trim() || "";
|
||||
return html`
|
||||
<ms-textfield label="${t("runtime_hours", L)}" type="number" .value=${c.runtimeHours}
|
||||
@input=${(e: Event) => this._patchCondition(i, { runtimeHours: (e.target as HTMLInputElement).value })}></ms-textfield>
|
||||
<ms-textfield label="${t("runtime_on_states", L)}" placeholder="on" .value=${c.onStates}
|
||||
@input=${(e: Event) => this._patchCondition(i, { onStates: (e.target as HTMLInputElement).value })}></ms-textfield>
|
||||
${this._renderOnStatesField({
|
||||
value: c.onStates,
|
||||
entityId: condEntity,
|
||||
onInput: (v) => this._patchCondition(i, { onStates: v }),
|
||||
})}
|
||||
`;
|
||||
}
|
||||
return nothing;
|
||||
@@ -1396,6 +1761,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
|
||||
protected updated(changed: Map<PropertyKey, unknown>): void {
|
||||
super.updated?.(changed);
|
||||
this._scheduleEntityPickerProbe();
|
||||
for (const key of changed.keys()) {
|
||||
if (MaintenanceTaskDialog._PREVIEW_RELEVANT.has(String(key))) {
|
||||
this._schedulePreviewRefresh();
|
||||
@@ -1404,6 +1770,62 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
/** #129 SAFETY NET (not the primary fix): HA's modern pickers resolve data
|
||||
* via Lit context — events that must bubble up to providers on the
|
||||
* <home-assistant> element. A dialog mounted outside that tree gets
|
||||
* pickers that upgrade to an EMPTY shadow root. The root cause is solved
|
||||
* by mounting dialogs inside <home-assistant>'s shadow root
|
||||
* (dialog-mount.ts); this probe remains as defense in depth for unknown
|
||||
* contexts: two consecutive zero-height measurements of the leaf pickers
|
||||
* inside a visible dialog flip the trigger fields back to the
|
||||
* comma-separated text inputs. */
|
||||
private _scheduleEntityPickerProbe(): void {
|
||||
if (
|
||||
this._entityPickerFallback
|
||||
|| this._pickerProbeTimer !== undefined
|
||||
|| !this._open
|
||||
|| this._scheduleType !== "sensor_based"
|
||||
) return;
|
||||
this._pickerProbeTimer = setTimeout(() => this._probeEntityPickers(), 1500);
|
||||
}
|
||||
|
||||
private _probeEntityPickers(): void {
|
||||
this._pickerProbeTimer = undefined;
|
||||
if (this._entityPickerFallback || !this._open) return;
|
||||
const form = this.shadowRoot?.querySelector<HTMLElement>("ha-form.entity-picker-form");
|
||||
const dialogVisible = (this.shadowRoot?.querySelector<HTMLElement>(".content")?.offsetHeight ?? 0) > 0;
|
||||
if (!form || !dialogVisible) {
|
||||
this._pickerProbeStrikes = 0;
|
||||
return;
|
||||
}
|
||||
// The broken-context signature is subtle: the form (and even a
|
||||
// ha-entities-picker wrapper) may keep its label height while the
|
||||
// ha-entity-picker LEAVES upgrade to empty shadow roots — so collect the
|
||||
// leaf pickers across ALL picker forms and require every one to lay out.
|
||||
const collectLeaves = (el: Element | null, out: HTMLElement[], depth = 0): void => {
|
||||
if (!el || depth > 10) return;
|
||||
if ((el.tagName?.toLowerCase() ?? "") === "ha-entity-picker") out.push(el as HTMLElement);
|
||||
for (const root of [el.shadowRoot, el]) {
|
||||
if (!root) continue;
|
||||
for (const child of Array.from(root.children ?? [])) collectLeaves(child, out, depth + 1);
|
||||
}
|
||||
};
|
||||
const forms = [...(this.shadowRoot?.querySelectorAll<HTMLElement>("ha-form.entity-picker-form") ?? [])];
|
||||
const leaves: HTMLElement[] = [];
|
||||
for (const f of forms) collectLeaves(f, leaves);
|
||||
const broken = leaves.length === 0 || leaves.some((leaf) => leaf.offsetHeight === 0);
|
||||
if (form.offsetHeight === 0 || broken) {
|
||||
this._pickerProbeStrikes += 1;
|
||||
if (this._pickerProbeStrikes >= 2) {
|
||||
this._entityPickerFallback = true;
|
||||
return;
|
||||
}
|
||||
this._pickerProbeTimer = setTimeout(() => this._probeEntityPickers(), 700);
|
||||
} else {
|
||||
this._pickerProbeStrikes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private _schedulePreviewRefresh(): void {
|
||||
if (this._previewTimer) clearTimeout(this._previewTimer);
|
||||
this._previewTimer = setTimeout(() => void this._fetchSchedulePreview(), 300);
|
||||
@@ -1773,17 +2195,19 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
}
|
||||
if (this._triggerType === "state_change") {
|
||||
return html`
|
||||
<ms-textfield
|
||||
label="${t("from_state_optional", L)}"
|
||||
.value=${this._triggerFromState}
|
||||
@input=${(e: Event) => (this._triggerFromState = (e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
${this._renderStateField({
|
||||
label: t("from_state_optional", L),
|
||||
value: this._triggerFromState,
|
||||
entityId: this._triggerEntityId,
|
||||
onInput: (v) => (this._triggerFromState = v),
|
||||
})}
|
||||
<div class="field-help">${t("state_value_help", L)}</div>
|
||||
<ms-textfield
|
||||
label="${t("to_state_optional", L)}"
|
||||
.value=${this._triggerToState}
|
||||
@input=${(e: Event) => (this._triggerToState = (e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
${this._renderStateField({
|
||||
label: t("to_state_optional", L),
|
||||
value: this._triggerToState,
|
||||
entityId: this._triggerEntityId,
|
||||
onInput: (v) => (this._triggerToState = v),
|
||||
})}
|
||||
<ms-textfield
|
||||
label="${t("target_changes", L)}"
|
||||
type="number"
|
||||
@@ -1803,12 +2227,11 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
.value=${this._triggerRuntimeHours}
|
||||
@input=${(e: Event) => (this._triggerRuntimeHours = (e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${t("runtime_on_states", L)}"
|
||||
placeholder="on"
|
||||
.value=${this._triggerOnStates}
|
||||
@input=${(e: Event) => (this._triggerOnStates = (e.target as HTMLInputElement).value)}
|
||||
></ms-textfield>
|
||||
${this._renderOnStatesField({
|
||||
value: this._triggerOnStates,
|
||||
entityId: this._triggerEntityId,
|
||||
onInput: (v) => (this._triggerOnStates = v),
|
||||
})}
|
||||
<div class="field-help">${t("runtime_on_states_help", L)}</div>
|
||||
`;
|
||||
}
|
||||
@@ -2064,20 +2487,34 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
` : nothing}
|
||||
${this._renderTriggerFields()}
|
||||
${this._scheduleType === "sensor_based" ? html`
|
||||
<ms-textfield
|
||||
label="${t("environmental_entity_optional", L)}"
|
||||
helper="${t("environmental_entity_helper", L)}"
|
||||
.value=${this._environmentalEntity}
|
||||
@input=${(e: Event) => (this._environmentalEntity = (e.target as HTMLInputElement).value.trim())}
|
||||
></ms-textfield>
|
||||
${this._environmentalEntity ? html`
|
||||
${this._entityPickerFallback ? html`
|
||||
<ms-textfield
|
||||
label="${t("environmental_attribute_optional", L)}"
|
||||
.value=${this._environmentalAttribute}
|
||||
@input=${(e: Event) => (this._environmentalAttribute = (e.target as HTMLInputElement).value.trim())}
|
||||
label="${t("environmental_entity_optional", L)}"
|
||||
helper="${t("environmental_entity_helper", L)}"
|
||||
.value=${this._environmentalEntity}
|
||||
@input=${(e: Event) => (this._environmentalEntity = (e.target as HTMLInputElement).value.trim())}
|
||||
></ms-textfield>
|
||||
` : nothing}
|
||||
` : html`
|
||||
<ha-form
|
||||
class="entity-picker-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{
|
||||
name: "environmental_entity",
|
||||
selector: { entity: {
|
||||
domain: ENVIRONMENTAL_PICKER_DOMAINS,
|
||||
device_class: ENVIRONMENTAL_PICKER_DEVICE_CLASSES,
|
||||
} },
|
||||
}]}
|
||||
.data=${{ environmental_entity: this._environmentalEntity }}
|
||||
.computeLabel=${() => t("environmental_entity_optional", L)}
|
||||
.computeHelper=${() => t("environmental_entity_helper", L)}
|
||||
@value-changed=${(e: CustomEvent) => {
|
||||
this._environmentalEntity = ((e.detail.value as { environmental_entity?: string }).environmental_entity || "").trim();
|
||||
}}
|
||||
></ha-form>`}
|
||||
${this._environmentalEntity ? this._renderEnvironmentalAttribute(L) : nothing}
|
||||
` : nothing}
|
||||
${this._renderAdaptiveSection(L)}
|
||||
<ms-textfield
|
||||
label="${t("notes_optional", L)}"
|
||||
.value=${this._notes}
|
||||
@@ -2157,17 +2594,35 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
font-weight: 500;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
/* v1.3.0: completion-action sections */
|
||||
.ca-section {
|
||||
/* #129: entity/state pickers in the trigger form (ha-form + selector) */
|
||||
.entity-picker-form,
|
||||
.state-picker-form {
|
||||
display: block;
|
||||
margin: 8px 0;
|
||||
}
|
||||
/* v1.3.0: completion-action sections (.adaptive-section shares the shell
|
||||
but keeps its own class — tests count .ca-section elements) */
|
||||
.ca-section,
|
||||
.adaptive-section {
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 6px;
|
||||
padding: 8px 12px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.ca-section > summary {
|
||||
.ca-section > summary,
|
||||
.adaptive-section > summary {
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
}
|
||||
.adaptive-section ms-textfield {
|
||||
width: 100%;
|
||||
margin-top: 8px;
|
||||
display: block;
|
||||
}
|
||||
.adaptive-section label {
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.ca-section ms-textfield,
|
||||
.ca-section ha-entity-picker,
|
||||
.ca-section ha-service-picker,
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
/** Standalone dialog mounting helper.
|
||||
*
|
||||
* Mounts the existing MaintenanceObjectDialog / MaintenanceTaskDialog onto
|
||||
* document.body so they can be opened from any Lovelace context — without
|
||||
* the user navigating to the panel first.
|
||||
* Mounts the existing MaintenanceObjectDialog / MaintenanceTaskDialog into
|
||||
* <home-assistant>'s shadow root — the same place HA's own dialogs live —
|
||||
* so they can be opened from any Lovelace context without the user
|
||||
* navigating to the panel first.
|
||||
*
|
||||
* The mount point matters (#129): HA's modern components (ha-entity-picker
|
||||
* and friends) resolve data through Lit context — `context-request` events
|
||||
* that bubble UP the DOM to providers on the <home-assistant> element. A
|
||||
* dialog on document.body is a SIBLING tree of <home-assistant>, the events
|
||||
* never reach the providers, and such components upgrade to an empty shadow
|
||||
* root. Mounting inside <home-assistant>'s shadow root keeps the provider
|
||||
* chain intact; document.body remains only as a last-resort fallback.
|
||||
*
|
||||
* Usage from a strategy or card click handler:
|
||||
*
|
||||
@@ -54,11 +63,21 @@ function getHass(): HomeAssistant | undefined {
|
||||
return root?.hass;
|
||||
}
|
||||
|
||||
/** Where dialogs live: <home-assistant>'s shadow root (context providers
|
||||
* reachable), falling back to document.body if HA's root ever goes away. */
|
||||
function dialogHost(): ShadowRoot | HTMLElement {
|
||||
return document.querySelector("home-assistant")?.shadowRoot ?? document.body;
|
||||
}
|
||||
|
||||
function getOrCreate<T extends HTMLElement>(tag: string): T {
|
||||
let el = document.body.querySelector<T>(tag);
|
||||
const host = dialogHost();
|
||||
let el = host.querySelector<T>(tag) ?? document.body.querySelector<T>(tag);
|
||||
if (!el) {
|
||||
el = document.createElement(tag) as T;
|
||||
document.body.appendChild(el);
|
||||
host.appendChild(el);
|
||||
} else if (el.parentNode !== host) {
|
||||
// Adopt a dialog mounted by an older bundle onto document.body.
|
||||
host.appendChild(el);
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Obnovit",
|
||||
"environmental_entity_optional": "Senzor prostředí (volitelný)",
|
||||
"environmental_entity_helper": "např. sensor.outdoor_temperature — upravuje interval podle podmínek prostředí",
|
||||
"adaptive_prediction_enabled": "Povolit predikce řízené senzory",
|
||||
"adaptive_seasonal_enabled": "Povolit sezónní povědomí",
|
||||
"adaptive_max_interval": "Maximální interval (dny)",
|
||||
"adaptive_min_interval": "Minimální interval (dny)",
|
||||
"adaptive_ewa_alpha": "Rychlost učení (alpha)",
|
||||
"adaptive_enabled": "Povolit adaptivní plánování",
|
||||
"adaptive_section_title": "Adaptivní plánování",
|
||||
"environmental_attribute_optional": "Atribut prostředí (volitelný)",
|
||||
"nfc_tag_id": "ID NFC tagu",
|
||||
"nfc_linked": "NFC tag propojen",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Opdater",
|
||||
"environmental_entity_optional": "Miljøsensor (valgfrit)",
|
||||
"environmental_entity_helper": "f.eks. sensor.outdoor_temperature — justerer intervallet baseret på miljøforhold",
|
||||
"adaptive_prediction_enabled": "Aktivér sensordrevne forudsigelser",
|
||||
"adaptive_seasonal_enabled": "Aktivér sæsonbevidsthed",
|
||||
"adaptive_max_interval": "Maksimumsinterval (dage)",
|
||||
"adaptive_min_interval": "Minimumsinterval (dage)",
|
||||
"adaptive_ewa_alpha": "Læringsrate (alfa)",
|
||||
"adaptive_enabled": "Aktivér adaptiv planlægning",
|
||||
"adaptive_section_title": "Adaptiv planlægning",
|
||||
"environmental_attribute_optional": "Miljøattribut (valgfrit)",
|
||||
"nfc_tag_id": "NFC-tag-ID",
|
||||
"nfc_linked": "NFC-tag tilknyttet",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Aktualisieren",
|
||||
"environmental_entity_optional": "Umgebungs-Sensor (optional)",
|
||||
"environmental_entity_helper": "z.B. sensor.aussentemperatur — passt das Intervall an Umgebungswerte an",
|
||||
"adaptive_prediction_enabled": "Sensorbasierte Vorhersagen aktivieren",
|
||||
"adaptive_seasonal_enabled": "Saisonale Anpassung aktivieren",
|
||||
"adaptive_max_interval": "Maximales Intervall (Tage)",
|
||||
"adaptive_min_interval": "Minimales Intervall (Tage)",
|
||||
"adaptive_ewa_alpha": "Lernrate (Alpha)",
|
||||
"adaptive_enabled": "Adaptive Planung aktivieren",
|
||||
"adaptive_section_title": "Adaptive Planung",
|
||||
"environmental_attribute_optional": "Umgebungs-Attribut (optional)",
|
||||
"nfc_tag_id": "NFC-Tag-ID",
|
||||
"nfc_linked": "NFC-Tag verknüpft",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Refresh",
|
||||
"environmental_entity_optional": "Environmental sensor (optional)",
|
||||
"environmental_entity_helper": "e.g. sensor.outdoor_temperature — 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",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Actualizar",
|
||||
"environmental_entity_optional": "Sensor ambiental (opcional)",
|
||||
"environmental_entity_helper": "p.ej. sensor.temperatura_exterior — ajusta el intervalo según las condiciones ambientales",
|
||||
"adaptive_prediction_enabled": "Activar predicciones de sensor",
|
||||
"adaptive_seasonal_enabled": "Activar conciencia estacional",
|
||||
"adaptive_max_interval": "Intervalo máximo (días)",
|
||||
"adaptive_min_interval": "Intervalo mínimo (días)",
|
||||
"adaptive_ewa_alpha": "Tasa de aprendizaje (alpha)",
|
||||
"adaptive_enabled": "Activar programación adaptativa",
|
||||
"adaptive_section_title": "Programación adaptativa",
|
||||
"environmental_attribute_optional": "Atributo ambiental (opcional)",
|
||||
"nfc_tag_id": "ID de etiqueta NFC",
|
||||
"nfc_linked": "Etiqueta NFC vinculada",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Päivitä",
|
||||
"environmental_entity_optional": "Ympäristöanturi (valinnainen)",
|
||||
"environmental_entity_helper": "esim. sensor.outdoor_temperature — säätää väliä ympäristöolosuhteiden mukaan",
|
||||
"adaptive_prediction_enabled": "Ota anturiperusteiset ennusteet käyttöön",
|
||||
"adaptive_seasonal_enabled": "Ota kausitietoisuus käyttöön",
|
||||
"adaptive_max_interval": "Enimmäisaikaväli (päivää)",
|
||||
"adaptive_min_interval": "Vähimmäisaikaväli (päivää)",
|
||||
"adaptive_ewa_alpha": "Oppimisnopeus (alfa)",
|
||||
"adaptive_enabled": "Ota mukautuva aikataulutus käyttöön",
|
||||
"adaptive_section_title": "Mukautuva aikataulutus",
|
||||
"environmental_attribute_optional": "Ympäristöattribuutti (valinnainen)",
|
||||
"nfc_tag_id": "NFC-tunnisteen tunnus",
|
||||
"nfc_linked": "NFC-tunniste linkitetty",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Actualiser",
|
||||
"environmental_entity_optional": "Capteur d'environnement (optionnel)",
|
||||
"environmental_entity_helper": "ex. sensor.temperature_exterieure — ajuste l'intervalle selon les conditions environnementales",
|
||||
"adaptive_prediction_enabled": "Activer les prédictions capteur",
|
||||
"adaptive_seasonal_enabled": "Activer la sensibilité saisonnière",
|
||||
"adaptive_max_interval": "Intervalle maximum (jours)",
|
||||
"adaptive_min_interval": "Intervalle minimum (jours)",
|
||||
"adaptive_ewa_alpha": "Taux d'apprentissage (alpha)",
|
||||
"adaptive_enabled": "Activer la planification adaptative",
|
||||
"adaptive_section_title": "Planification adaptative",
|
||||
"environmental_attribute_optional": "Attribut d'environnement (optionnel)",
|
||||
"nfc_tag_id": "ID tag NFC",
|
||||
"nfc_linked": "Tag NFC lié",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "रिफ़्रेश करें",
|
||||
"environmental_entity_optional": "पर्यावरण सेंसर (वैकल्पिक)",
|
||||
"environmental_entity_helper": "उदा. sensor.outdoor_temperature — पर्यावरणीय स्थितियों के आधार पर अंतराल समायोजित करता है",
|
||||
"adaptive_prediction_enabled": "सेंसर-संचालित पूर्वानुमान सक्षम करें",
|
||||
"adaptive_seasonal_enabled": "मौसमी जागरूकता सक्षम करें",
|
||||
"adaptive_max_interval": "अधिकतम अंतराल (दिन)",
|
||||
"adaptive_min_interval": "न्यूनतम अंतराल (दिन)",
|
||||
"adaptive_ewa_alpha": "अधिगम दर (अल्फा)",
|
||||
"adaptive_enabled": "अनुकूली अनुसूचन सक्षम करें",
|
||||
"adaptive_section_title": "अनुकूली अनुसूचन",
|
||||
"environmental_attribute_optional": "पर्यावरण विशेषता (वैकल्पिक)",
|
||||
"nfc_tag_id": "NFC टैग ID",
|
||||
"nfc_linked": "NFC टैग लिंक किया गया",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Frissítés",
|
||||
"environmental_entity_optional": "Környezeti érzékelő (opcionális)",
|
||||
"environmental_entity_helper": "pl. sensor.outdoor_temperature — a környezeti feltételek alapján igazítja az intervallumot",
|
||||
"adaptive_prediction_enabled": "Érzékelővezérelt előrejelzések engedélyezése",
|
||||
"adaptive_seasonal_enabled": "Szezonális igazodás engedélyezése",
|
||||
"adaptive_max_interval": "Maximális intervallum (nap)",
|
||||
"adaptive_min_interval": "Minimális intervallum (nap)",
|
||||
"adaptive_ewa_alpha": "Tanulási ráta (alfa)",
|
||||
"adaptive_enabled": "Adaptív ütemezés engedélyezése",
|
||||
"adaptive_section_title": "Adaptív ütemezés",
|
||||
"environmental_attribute_optional": "Környezeti attribútum (opcionális)",
|
||||
"nfc_tag_id": "NFC címke azonosító",
|
||||
"nfc_linked": "NFC címke hozzárendelve",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Aggiorna",
|
||||
"environmental_entity_optional": "Sensore ambientale (opzionale)",
|
||||
"environmental_entity_helper": "es. sensor.temperatura_esterna — regola l'intervallo in base alle condizioni ambientali",
|
||||
"adaptive_prediction_enabled": "Abilita previsioni sensore",
|
||||
"adaptive_seasonal_enabled": "Abilita consapevolezza stagionale",
|
||||
"adaptive_max_interval": "Intervallo massimo (giorni)",
|
||||
"adaptive_min_interval": "Intervallo minimo (giorni)",
|
||||
"adaptive_ewa_alpha": "Tasso di apprendimento (alpha)",
|
||||
"adaptive_enabled": "Abilita pianificazione adattiva",
|
||||
"adaptive_section_title": "Pianificazione adattiva",
|
||||
"environmental_attribute_optional": "Attributo ambientale (opzionale)",
|
||||
"nfc_tag_id": "ID tag NFC",
|
||||
"nfc_linked": "Tag NFC collegato",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "更新",
|
||||
"environmental_entity_optional": "環境センサー(任意)",
|
||||
"environmental_entity_helper": "例: sensor.outdoor_temperature — 環境条件に応じて間隔を調整します",
|
||||
"adaptive_prediction_enabled": "センサー駆動の予測を有効にする",
|
||||
"adaptive_seasonal_enabled": "季節認識を有効にする",
|
||||
"adaptive_max_interval": "最大間隔 (日)",
|
||||
"adaptive_min_interval": "最小間隔 (日)",
|
||||
"adaptive_ewa_alpha": "学習率 (アルファ)",
|
||||
"adaptive_enabled": "適応スケジューリングを有効にする",
|
||||
"adaptive_section_title": "適応スケジューリング",
|
||||
"environmental_attribute_optional": "環境属性(任意)",
|
||||
"nfc_tag_id": "NFCタグID",
|
||||
"nfc_linked": "NFCタグ連携済み",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "새로 고침",
|
||||
"environmental_entity_optional": "환경 센서 (선택)",
|
||||
"environmental_entity_helper": "예: sensor.outdoor_temperature — 환경 조건에 따라 주기를 조정합니다",
|
||||
"adaptive_prediction_enabled": "센서 기반 예측 사용",
|
||||
"adaptive_seasonal_enabled": "계절 인식 사용",
|
||||
"adaptive_max_interval": "최대 주기(일)",
|
||||
"adaptive_min_interval": "최소 주기(일)",
|
||||
"adaptive_ewa_alpha": "학습률(alpha)",
|
||||
"adaptive_enabled": "적응형 일정 사용",
|
||||
"adaptive_section_title": "적응형 일정",
|
||||
"environmental_attribute_optional": "환경 속성 (선택)",
|
||||
"nfc_tag_id": "NFC 태그 ID",
|
||||
"nfc_linked": "NFC 태그 연결됨",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Oppdater",
|
||||
"environmental_entity_optional": "Miljøsensor (valgfritt)",
|
||||
"environmental_entity_helper": "f.eks. sensor.outdoor_temperature — justerer intervallet basert på miljøforhold",
|
||||
"adaptive_prediction_enabled": "Aktiver sensordrevne prognoser",
|
||||
"adaptive_seasonal_enabled": "Aktiver sesongbevissthet",
|
||||
"adaptive_max_interval": "Største intervall (dager)",
|
||||
"adaptive_min_interval": "Minste intervall (dager)",
|
||||
"adaptive_ewa_alpha": "Læringsrate (alfa)",
|
||||
"adaptive_enabled": "Aktiver adaptiv planlegging",
|
||||
"adaptive_section_title": "Adaptiv planlegging",
|
||||
"environmental_attribute_optional": "Miljøattributt (valgfritt)",
|
||||
"nfc_tag_id": "NFC-brikke-ID",
|
||||
"nfc_linked": "NFC-brikke koblet",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Vernieuwen",
|
||||
"environmental_entity_optional": "Omgevingssensor (optioneel)",
|
||||
"environmental_entity_helper": "bv. sensor.buitentemperatuur — past het interval aan op basis van omgevingswaarden",
|
||||
"adaptive_prediction_enabled": "Sensorgestuurde voorspellingen inschakelen",
|
||||
"adaptive_seasonal_enabled": "Seizoensbewustzijn inschakelen",
|
||||
"adaptive_max_interval": "Maximaal interval (dagen)",
|
||||
"adaptive_min_interval": "Minimaal interval (dagen)",
|
||||
"adaptive_ewa_alpha": "Leersnelheid (alpha)",
|
||||
"adaptive_enabled": "Adaptieve planning inschakelen",
|
||||
"adaptive_section_title": "Adaptieve planning",
|
||||
"environmental_attribute_optional": "Omgevingsattribuut (optioneel)",
|
||||
"nfc_tag_id": "NFC-tag-ID",
|
||||
"nfc_linked": "NFC-tag gekoppeld",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Odśwież",
|
||||
"environmental_entity_optional": "Czujnik środowiskowy (opcjonalne)",
|
||||
"environmental_entity_helper": "np. sensor.outdoor_temperature — dostosowuje interwał na podstawie warunków środowiskowych",
|
||||
"adaptive_prediction_enabled": "Włącz predykcje sterowane czujnikami",
|
||||
"adaptive_seasonal_enabled": "Włącz świadomość sezonową",
|
||||
"adaptive_max_interval": "Maksymalny interwał (dni)",
|
||||
"adaptive_min_interval": "Minimalny interwał (dni)",
|
||||
"adaptive_ewa_alpha": "Tempo uczenia (alpha)",
|
||||
"adaptive_enabled": "Włącz adaptacyjne planowanie",
|
||||
"adaptive_section_title": "Adaptacyjne planowanie",
|
||||
"environmental_attribute_optional": "Atrybut środowiskowy (opcjonalne)",
|
||||
"nfc_tag_id": "ID tagu NFC",
|
||||
"nfc_linked": "Tag NFC powiązany",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Atualizar",
|
||||
"environmental_entity_optional": "Sensor ambiental (opcional)",
|
||||
"environmental_entity_helper": "ex.: sensor.outdoor_temperature — ajusta o intervalo com base nas condições ambientais",
|
||||
"adaptive_prediction_enabled": "Ativar previsões baseadas em sensor",
|
||||
"adaptive_seasonal_enabled": "Ativar sazonalidade",
|
||||
"adaptive_max_interval": "Intervalo máximo (dias)",
|
||||
"adaptive_min_interval": "Intervalo mínimo (dias)",
|
||||
"adaptive_ewa_alpha": "Taxa de aprendizado (alpha)",
|
||||
"adaptive_enabled": "Ativar agendamento adaptativo",
|
||||
"adaptive_section_title": "Agendamento adaptativo",
|
||||
"environmental_attribute_optional": "Atributo ambiental (opcional)",
|
||||
"nfc_tag_id": "ID da tag NFC",
|
||||
"nfc_linked": "Tag NFC vinculada",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Atualizar",
|
||||
"environmental_entity_optional": "Sensor ambiental (opcional)",
|
||||
"environmental_entity_helper": "ex. sensor.temperatura_exterior — ajusta o intervalo segundo as condições ambientais",
|
||||
"adaptive_prediction_enabled": "Ativar previsões baseadas em sensores",
|
||||
"adaptive_seasonal_enabled": "Ativar consciência sazonal",
|
||||
"adaptive_max_interval": "Intervalo máximo (dias)",
|
||||
"adaptive_min_interval": "Intervalo mínimo (dias)",
|
||||
"adaptive_ewa_alpha": "Taxa de aprendizagem (alfa)",
|
||||
"adaptive_enabled": "Ativar agendamento adaptativo",
|
||||
"adaptive_section_title": "Agendamento Adaptativo",
|
||||
"environmental_attribute_optional": "Atributo ambiental (opcional)",
|
||||
"nfc_tag_id": "ID da etiqueta NFC",
|
||||
"nfc_linked": "Etiqueta NFC associada",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Обновить",
|
||||
"environmental_entity_optional": "Датчик окружающей среды (опционально)",
|
||||
"environmental_entity_helper": "напр. sensor.outdoor_temperature — корректирует интервал в зависимости от условий",
|
||||
"adaptive_prediction_enabled": "Включить прогнозы на основе датчиков",
|
||||
"adaptive_seasonal_enabled": "Учитывать сезонность",
|
||||
"adaptive_max_interval": "Максимальный интервал (дни)",
|
||||
"adaptive_min_interval": "Минимальный интервал (дни)",
|
||||
"adaptive_ewa_alpha": "Скорость обучения (альфа)",
|
||||
"adaptive_enabled": "Включить адаптивное планирование",
|
||||
"adaptive_section_title": "Адаптивное планирование",
|
||||
"environmental_attribute_optional": "Атрибут среды (опционально)",
|
||||
"nfc_tag_id": "ID NFC-метки",
|
||||
"nfc_linked": "NFC-метка привязана",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Uppdatera",
|
||||
"environmental_entity_optional": "Miljösensor (valfritt)",
|
||||
"environmental_entity_helper": "t.ex. sensor.outdoor_temperature — justerar intervallet baserat på miljöförhållanden",
|
||||
"adaptive_prediction_enabled": "Aktivera sensorstyrda prediktioner",
|
||||
"adaptive_seasonal_enabled": "Aktivera säsongsmedvetenhet",
|
||||
"adaptive_max_interval": "Största intervall (dagar)",
|
||||
"adaptive_min_interval": "Minsta intervall (dagar)",
|
||||
"adaptive_ewa_alpha": "Inlärningshastighet (alpha)",
|
||||
"adaptive_enabled": "Aktivera adaptiv schemaläggning",
|
||||
"adaptive_section_title": "Adaptiv schemaläggning",
|
||||
"environmental_attribute_optional": "Miljöattribut (valfritt)",
|
||||
"nfc_tag_id": "NFC-tagg-ID",
|
||||
"nfc_linked": "NFC-tagg länkad",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Yenile",
|
||||
"environmental_entity_optional": "Çevresel sensör (isteğe bağlı)",
|
||||
"environmental_entity_helper": "örn. sensor.outdoor_temperature — aralığı çevresel koşullara göre ayarlar",
|
||||
"adaptive_prediction_enabled": "Sensör tabanlı tahminleri etkinleştir",
|
||||
"adaptive_seasonal_enabled": "Mevsimsel farkındalığı etkinleştir",
|
||||
"adaptive_max_interval": "Maksimum aralık (gün)",
|
||||
"adaptive_min_interval": "Minimum aralık (gün)",
|
||||
"adaptive_ewa_alpha": "Öğrenme hızı (alfa)",
|
||||
"adaptive_enabled": "Uyarlanabilir zamanlamayı etkinleştir",
|
||||
"adaptive_section_title": "Uyarlanabilir Zamanlama",
|
||||
"environmental_attribute_optional": "Çevresel öznitelik (isteğe bağlı)",
|
||||
"nfc_tag_id": "NFC Etiket Kimliği",
|
||||
"nfc_linked": "NFC etiketi bağlandı",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Оновити",
|
||||
"environmental_entity_optional": "Датчик навколишнього середовища (необов'язково)",
|
||||
"environmental_entity_helper": "напр. sensor.outdoor_temperature — коригує інтервал відповідно до умов навколишнього середовища",
|
||||
"adaptive_prediction_enabled": "Увімкнути прогнози за сенсорами",
|
||||
"adaptive_seasonal_enabled": "Увімкнути сезонну корекцію",
|
||||
"adaptive_max_interval": "Максимальний інтервал (дні)",
|
||||
"adaptive_min_interval": "Мінімальний інтервал (дні)",
|
||||
"adaptive_ewa_alpha": "Швидкість навчання (alpha)",
|
||||
"adaptive_enabled": "Увімкнути адаптивне планування",
|
||||
"adaptive_section_title": "Адаптивне планування",
|
||||
"environmental_attribute_optional": "Атрибут середовища (необов'язково)",
|
||||
"nfc_tag_id": "ID NFC-тега",
|
||||
"nfc_linked": "NFC-тег прив'язано",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "刷新",
|
||||
"environmental_entity_optional": "环境传感器 (可选)",
|
||||
"environmental_entity_helper": "例如:sensor.outdoor_temperature — 根据环境条件自动调整间隔",
|
||||
"adaptive_prediction_enabled": "启用基于传感器的预测",
|
||||
"adaptive_seasonal_enabled": "启用季节性感知",
|
||||
"adaptive_max_interval": "最大间隔 (天)",
|
||||
"adaptive_min_interval": "最小间隔 (天)",
|
||||
"adaptive_ewa_alpha": "学习率 (alpha)",
|
||||
"adaptive_enabled": "启用自适应计划",
|
||||
"adaptive_section_title": "自适应计划",
|
||||
"environmental_attribute_optional": "环境属性 (可选)",
|
||||
"nfc_tag_id": "NFC 标签 ID",
|
||||
"nfc_linked": "NFC 标签已链接",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Obnovit",
|
||||
"environmental_entity_optional": "Senzor prostředí (volitelný)",
|
||||
"environmental_entity_helper": "např. sensor.outdoor_temperature — upravuje interval podle podmínek prostředí",
|
||||
"adaptive_prediction_enabled": "Povolit predikce řízené senzory",
|
||||
"adaptive_seasonal_enabled": "Povolit sezónní povědomí",
|
||||
"adaptive_max_interval": "Maximální interval (dny)",
|
||||
"adaptive_min_interval": "Minimální interval (dny)",
|
||||
"adaptive_ewa_alpha": "Rychlost učení (alpha)",
|
||||
"adaptive_enabled": "Povolit adaptivní plánování",
|
||||
"adaptive_section_title": "Adaptivní plánování",
|
||||
"environmental_attribute_optional": "Atribut prostředí (volitelný)",
|
||||
"nfc_tag_id": "ID NFC tagu",
|
||||
"nfc_linked": "NFC tag propojen",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Opdater",
|
||||
"environmental_entity_optional": "Miljøsensor (valgfrit)",
|
||||
"environmental_entity_helper": "f.eks. sensor.outdoor_temperature — justerer intervallet baseret på miljøforhold",
|
||||
"adaptive_prediction_enabled": "Aktivér sensordrevne forudsigelser",
|
||||
"adaptive_seasonal_enabled": "Aktivér sæsonbevidsthed",
|
||||
"adaptive_max_interval": "Maksimumsinterval (dage)",
|
||||
"adaptive_min_interval": "Minimumsinterval (dage)",
|
||||
"adaptive_ewa_alpha": "Læringsrate (alfa)",
|
||||
"adaptive_enabled": "Aktivér adaptiv planlægning",
|
||||
"adaptive_section_title": "Adaptiv planlægning",
|
||||
"environmental_attribute_optional": "Miljøattribut (valgfrit)",
|
||||
"nfc_tag_id": "NFC-tag-ID",
|
||||
"nfc_linked": "NFC-tag tilknyttet",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Aktualisieren",
|
||||
"environmental_entity_optional": "Umgebungs-Sensor (optional)",
|
||||
"environmental_entity_helper": "z.B. sensor.aussentemperatur — passt das Intervall an Umgebungswerte an",
|
||||
"adaptive_prediction_enabled": "Sensorbasierte Vorhersagen aktivieren",
|
||||
"adaptive_seasonal_enabled": "Saisonale Anpassung aktivieren",
|
||||
"adaptive_max_interval": "Maximales Intervall (Tage)",
|
||||
"adaptive_min_interval": "Minimales Intervall (Tage)",
|
||||
"adaptive_ewa_alpha": "Lernrate (Alpha)",
|
||||
"adaptive_enabled": "Adaptive Planung aktivieren",
|
||||
"adaptive_section_title": "Adaptive Planung",
|
||||
"environmental_attribute_optional": "Umgebungs-Attribut (optional)",
|
||||
"nfc_tag_id": "NFC-Tag-ID",
|
||||
"nfc_linked": "NFC-Tag verknüpft",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Refresh",
|
||||
"environmental_entity_optional": "Environmental sensor (optional)",
|
||||
"environmental_entity_helper": "e.g. sensor.outdoor_temperature — 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",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Actualizar",
|
||||
"environmental_entity_optional": "Sensor ambiental (opcional)",
|
||||
"environmental_entity_helper": "p.ej. sensor.temperatura_exterior — ajusta el intervalo según las condiciones ambientales",
|
||||
"adaptive_prediction_enabled": "Activar predicciones de sensor",
|
||||
"adaptive_seasonal_enabled": "Activar conciencia estacional",
|
||||
"adaptive_max_interval": "Intervalo máximo (días)",
|
||||
"adaptive_min_interval": "Intervalo mínimo (días)",
|
||||
"adaptive_ewa_alpha": "Tasa de aprendizaje (alpha)",
|
||||
"adaptive_enabled": "Activar programación adaptativa",
|
||||
"adaptive_section_title": "Programación adaptativa",
|
||||
"environmental_attribute_optional": "Atributo ambiental (opcional)",
|
||||
"nfc_tag_id": "ID de etiqueta NFC",
|
||||
"nfc_linked": "Etiqueta NFC vinculada",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Päivitä",
|
||||
"environmental_entity_optional": "Ympäristöanturi (valinnainen)",
|
||||
"environmental_entity_helper": "esim. sensor.outdoor_temperature — säätää väliä ympäristöolosuhteiden mukaan",
|
||||
"adaptive_prediction_enabled": "Ota anturiperusteiset ennusteet käyttöön",
|
||||
"adaptive_seasonal_enabled": "Ota kausitietoisuus käyttöön",
|
||||
"adaptive_max_interval": "Enimmäisaikaväli (päivää)",
|
||||
"adaptive_min_interval": "Vähimmäisaikaväli (päivää)",
|
||||
"adaptive_ewa_alpha": "Oppimisnopeus (alfa)",
|
||||
"adaptive_enabled": "Ota mukautuva aikataulutus käyttöön",
|
||||
"adaptive_section_title": "Mukautuva aikataulutus",
|
||||
"environmental_attribute_optional": "Ympäristöattribuutti (valinnainen)",
|
||||
"nfc_tag_id": "NFC-tunnisteen tunnus",
|
||||
"nfc_linked": "NFC-tunniste linkitetty",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Actualiser",
|
||||
"environmental_entity_optional": "Capteur d'environnement (optionnel)",
|
||||
"environmental_entity_helper": "ex. sensor.temperature_exterieure — ajuste l'intervalle selon les conditions environnementales",
|
||||
"adaptive_prediction_enabled": "Activer les prédictions capteur",
|
||||
"adaptive_seasonal_enabled": "Activer la sensibilité saisonnière",
|
||||
"adaptive_max_interval": "Intervalle maximum (jours)",
|
||||
"adaptive_min_interval": "Intervalle minimum (jours)",
|
||||
"adaptive_ewa_alpha": "Taux d'apprentissage (alpha)",
|
||||
"adaptive_enabled": "Activer la planification adaptative",
|
||||
"adaptive_section_title": "Planification adaptative",
|
||||
"environmental_attribute_optional": "Attribut d'environnement (optionnel)",
|
||||
"nfc_tag_id": "ID tag NFC",
|
||||
"nfc_linked": "Tag NFC lié",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "रिफ़्रेश करें",
|
||||
"environmental_entity_optional": "पर्यावरण सेंसर (वैकल्पिक)",
|
||||
"environmental_entity_helper": "उदा. sensor.outdoor_temperature — पर्यावरणीय स्थितियों के आधार पर अंतराल समायोजित करता है",
|
||||
"adaptive_prediction_enabled": "सेंसर-संचालित पूर्वानुमान सक्षम करें",
|
||||
"adaptive_seasonal_enabled": "मौसमी जागरूकता सक्षम करें",
|
||||
"adaptive_max_interval": "अधिकतम अंतराल (दिन)",
|
||||
"adaptive_min_interval": "न्यूनतम अंतराल (दिन)",
|
||||
"adaptive_ewa_alpha": "अधिगम दर (अल्फा)",
|
||||
"adaptive_enabled": "अनुकूली अनुसूचन सक्षम करें",
|
||||
"adaptive_section_title": "अनुकूली अनुसूचन",
|
||||
"environmental_attribute_optional": "पर्यावरण विशेषता (वैकल्पिक)",
|
||||
"nfc_tag_id": "NFC टैग ID",
|
||||
"nfc_linked": "NFC टैग लिंक किया गया",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Frissítés",
|
||||
"environmental_entity_optional": "Környezeti érzékelő (opcionális)",
|
||||
"environmental_entity_helper": "pl. sensor.outdoor_temperature — a környezeti feltételek alapján igazítja az intervallumot",
|
||||
"adaptive_prediction_enabled": "Érzékelővezérelt előrejelzések engedélyezése",
|
||||
"adaptive_seasonal_enabled": "Szezonális igazodás engedélyezése",
|
||||
"adaptive_max_interval": "Maximális intervallum (nap)",
|
||||
"adaptive_min_interval": "Minimális intervallum (nap)",
|
||||
"adaptive_ewa_alpha": "Tanulási ráta (alfa)",
|
||||
"adaptive_enabled": "Adaptív ütemezés engedélyezése",
|
||||
"adaptive_section_title": "Adaptív ütemezés",
|
||||
"environmental_attribute_optional": "Környezeti attribútum (opcionális)",
|
||||
"nfc_tag_id": "NFC címke azonosító",
|
||||
"nfc_linked": "NFC címke hozzárendelve",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Aggiorna",
|
||||
"environmental_entity_optional": "Sensore ambientale (opzionale)",
|
||||
"environmental_entity_helper": "es. sensor.temperatura_esterna — regola l'intervallo in base alle condizioni ambientali",
|
||||
"adaptive_prediction_enabled": "Abilita previsioni sensore",
|
||||
"adaptive_seasonal_enabled": "Abilita consapevolezza stagionale",
|
||||
"adaptive_max_interval": "Intervallo massimo (giorni)",
|
||||
"adaptive_min_interval": "Intervallo minimo (giorni)",
|
||||
"adaptive_ewa_alpha": "Tasso di apprendimento (alpha)",
|
||||
"adaptive_enabled": "Abilita pianificazione adattiva",
|
||||
"adaptive_section_title": "Pianificazione adattiva",
|
||||
"environmental_attribute_optional": "Attributo ambientale (opzionale)",
|
||||
"nfc_tag_id": "ID tag NFC",
|
||||
"nfc_linked": "Tag NFC collegato",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "更新",
|
||||
"environmental_entity_optional": "環境センサー(任意)",
|
||||
"environmental_entity_helper": "例: sensor.outdoor_temperature — 環境条件に応じて間隔を調整します",
|
||||
"adaptive_prediction_enabled": "センサー駆動の予測を有効にする",
|
||||
"adaptive_seasonal_enabled": "季節認識を有効にする",
|
||||
"adaptive_max_interval": "最大間隔 (日)",
|
||||
"adaptive_min_interval": "最小間隔 (日)",
|
||||
"adaptive_ewa_alpha": "学習率 (アルファ)",
|
||||
"adaptive_enabled": "適応スケジューリングを有効にする",
|
||||
"adaptive_section_title": "適応スケジューリング",
|
||||
"environmental_attribute_optional": "環境属性(任意)",
|
||||
"nfc_tag_id": "NFCタグID",
|
||||
"nfc_linked": "NFCタグ連携済み",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "새로 고침",
|
||||
"environmental_entity_optional": "환경 센서 (선택)",
|
||||
"environmental_entity_helper": "예: sensor.outdoor_temperature — 환경 조건에 따라 주기를 조정합니다",
|
||||
"adaptive_prediction_enabled": "센서 기반 예측 사용",
|
||||
"adaptive_seasonal_enabled": "계절 인식 사용",
|
||||
"adaptive_max_interval": "최대 주기(일)",
|
||||
"adaptive_min_interval": "최소 주기(일)",
|
||||
"adaptive_ewa_alpha": "학습률(alpha)",
|
||||
"adaptive_enabled": "적응형 일정 사용",
|
||||
"adaptive_section_title": "적응형 일정",
|
||||
"environmental_attribute_optional": "환경 속성 (선택)",
|
||||
"nfc_tag_id": "NFC 태그 ID",
|
||||
"nfc_linked": "NFC 태그 연결됨",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Oppdater",
|
||||
"environmental_entity_optional": "Miljøsensor (valgfritt)",
|
||||
"environmental_entity_helper": "f.eks. sensor.outdoor_temperature — justerer intervallet basert på miljøforhold",
|
||||
"adaptive_prediction_enabled": "Aktiver sensordrevne prognoser",
|
||||
"adaptive_seasonal_enabled": "Aktiver sesongbevissthet",
|
||||
"adaptive_max_interval": "Største intervall (dager)",
|
||||
"adaptive_min_interval": "Minste intervall (dager)",
|
||||
"adaptive_ewa_alpha": "Læringsrate (alfa)",
|
||||
"adaptive_enabled": "Aktiver adaptiv planlegging",
|
||||
"adaptive_section_title": "Adaptiv planlegging",
|
||||
"environmental_attribute_optional": "Miljøattributt (valgfritt)",
|
||||
"nfc_tag_id": "NFC-brikke-ID",
|
||||
"nfc_linked": "NFC-brikke koblet",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Vernieuwen",
|
||||
"environmental_entity_optional": "Omgevingssensor (optioneel)",
|
||||
"environmental_entity_helper": "bv. sensor.buitentemperatuur — past het interval aan op basis van omgevingswaarden",
|
||||
"adaptive_prediction_enabled": "Sensorgestuurde voorspellingen inschakelen",
|
||||
"adaptive_seasonal_enabled": "Seizoensbewustzijn inschakelen",
|
||||
"adaptive_max_interval": "Maximaal interval (dagen)",
|
||||
"adaptive_min_interval": "Minimaal interval (dagen)",
|
||||
"adaptive_ewa_alpha": "Leersnelheid (alpha)",
|
||||
"adaptive_enabled": "Adaptieve planning inschakelen",
|
||||
"adaptive_section_title": "Adaptieve planning",
|
||||
"environmental_attribute_optional": "Omgevingsattribuut (optioneel)",
|
||||
"nfc_tag_id": "NFC-tag-ID",
|
||||
"nfc_linked": "NFC-tag gekoppeld",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Odśwież",
|
||||
"environmental_entity_optional": "Czujnik środowiskowy (opcjonalne)",
|
||||
"environmental_entity_helper": "np. sensor.outdoor_temperature — dostosowuje interwał na podstawie warunków środowiskowych",
|
||||
"adaptive_prediction_enabled": "Włącz predykcje sterowane czujnikami",
|
||||
"adaptive_seasonal_enabled": "Włącz świadomość sezonową",
|
||||
"adaptive_max_interval": "Maksymalny interwał (dni)",
|
||||
"adaptive_min_interval": "Minimalny interwał (dni)",
|
||||
"adaptive_ewa_alpha": "Tempo uczenia (alpha)",
|
||||
"adaptive_enabled": "Włącz adaptacyjne planowanie",
|
||||
"adaptive_section_title": "Adaptacyjne planowanie",
|
||||
"environmental_attribute_optional": "Atrybut środowiskowy (opcjonalne)",
|
||||
"nfc_tag_id": "ID tagu NFC",
|
||||
"nfc_linked": "Tag NFC powiązany",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Atualizar",
|
||||
"environmental_entity_optional": "Sensor ambiental (opcional)",
|
||||
"environmental_entity_helper": "ex.: sensor.outdoor_temperature — ajusta o intervalo com base nas condições ambientais",
|
||||
"adaptive_prediction_enabled": "Ativar previsões baseadas em sensor",
|
||||
"adaptive_seasonal_enabled": "Ativar sazonalidade",
|
||||
"adaptive_max_interval": "Intervalo máximo (dias)",
|
||||
"adaptive_min_interval": "Intervalo mínimo (dias)",
|
||||
"adaptive_ewa_alpha": "Taxa de aprendizado (alpha)",
|
||||
"adaptive_enabled": "Ativar agendamento adaptativo",
|
||||
"adaptive_section_title": "Agendamento adaptativo",
|
||||
"environmental_attribute_optional": "Atributo ambiental (opcional)",
|
||||
"nfc_tag_id": "ID da tag NFC",
|
||||
"nfc_linked": "Tag NFC vinculada",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Atualizar",
|
||||
"environmental_entity_optional": "Sensor ambiental (opcional)",
|
||||
"environmental_entity_helper": "ex. sensor.temperatura_exterior — ajusta o intervalo segundo as condições ambientais",
|
||||
"adaptive_prediction_enabled": "Ativar previsões baseadas em sensores",
|
||||
"adaptive_seasonal_enabled": "Ativar consciência sazonal",
|
||||
"adaptive_max_interval": "Intervalo máximo (dias)",
|
||||
"adaptive_min_interval": "Intervalo mínimo (dias)",
|
||||
"adaptive_ewa_alpha": "Taxa de aprendizagem (alfa)",
|
||||
"adaptive_enabled": "Ativar agendamento adaptativo",
|
||||
"adaptive_section_title": "Agendamento Adaptativo",
|
||||
"environmental_attribute_optional": "Atributo ambiental (opcional)",
|
||||
"nfc_tag_id": "ID da etiqueta NFC",
|
||||
"nfc_linked": "Etiqueta NFC associada",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Обновить",
|
||||
"environmental_entity_optional": "Датчик окружающей среды (опционально)",
|
||||
"environmental_entity_helper": "напр. sensor.outdoor_temperature — корректирует интервал в зависимости от условий",
|
||||
"adaptive_prediction_enabled": "Включить прогнозы на основе датчиков",
|
||||
"adaptive_seasonal_enabled": "Учитывать сезонность",
|
||||
"adaptive_max_interval": "Максимальный интервал (дни)",
|
||||
"adaptive_min_interval": "Минимальный интервал (дни)",
|
||||
"adaptive_ewa_alpha": "Скорость обучения (альфа)",
|
||||
"adaptive_enabled": "Включить адаптивное планирование",
|
||||
"adaptive_section_title": "Адаптивное планирование",
|
||||
"environmental_attribute_optional": "Атрибут среды (опционально)",
|
||||
"nfc_tag_id": "ID NFC-метки",
|
||||
"nfc_linked": "NFC-метка привязана",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Uppdatera",
|
||||
"environmental_entity_optional": "Miljösensor (valfritt)",
|
||||
"environmental_entity_helper": "t.ex. sensor.outdoor_temperature — justerar intervallet baserat på miljöförhållanden",
|
||||
"adaptive_prediction_enabled": "Aktivera sensorstyrda prediktioner",
|
||||
"adaptive_seasonal_enabled": "Aktivera säsongsmedvetenhet",
|
||||
"adaptive_max_interval": "Största intervall (dagar)",
|
||||
"adaptive_min_interval": "Minsta intervall (dagar)",
|
||||
"adaptive_ewa_alpha": "Inlärningshastighet (alpha)",
|
||||
"adaptive_enabled": "Aktivera adaptiv schemaläggning",
|
||||
"adaptive_section_title": "Adaptiv schemaläggning",
|
||||
"environmental_attribute_optional": "Miljöattribut (valfritt)",
|
||||
"nfc_tag_id": "NFC-tagg-ID",
|
||||
"nfc_linked": "NFC-tagg länkad",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "Yenile",
|
||||
"environmental_entity_optional": "Çevresel sensör (isteğe bağlı)",
|
||||
"environmental_entity_helper": "örn. sensor.outdoor_temperature — aralığı çevresel koşullara göre ayarlar",
|
||||
"adaptive_prediction_enabled": "Sensör tabanlı tahminleri etkinleştir",
|
||||
"adaptive_seasonal_enabled": "Mevsimsel farkındalığı etkinleştir",
|
||||
"adaptive_max_interval": "Maksimum aralık (gün)",
|
||||
"adaptive_min_interval": "Minimum aralık (gün)",
|
||||
"adaptive_ewa_alpha": "Öğrenme hızı (alfa)",
|
||||
"adaptive_enabled": "Uyarlanabilir zamanlamayı etkinleştir",
|
||||
"adaptive_section_title": "Uyarlanabilir Zamanlama",
|
||||
"environmental_attribute_optional": "Çevresel öznitelik (isteğe bağlı)",
|
||||
"nfc_tag_id": "NFC Etiket Kimliği",
|
||||
"nfc_linked": "NFC etiketi bağlandı",
|
||||
|
||||
@@ -205,6 +205,13 @@
|
||||
"nfc_tags_refresh": "Оновити",
|
||||
"environmental_entity_optional": "Датчик навколишнього середовища (необов'язково)",
|
||||
"environmental_entity_helper": "напр. sensor.outdoor_temperature — коригує інтервал відповідно до умов навколишнього середовища",
|
||||
"adaptive_prediction_enabled": "Увімкнути прогнози за сенсорами",
|
||||
"adaptive_seasonal_enabled": "Увімкнути сезонну корекцію",
|
||||
"adaptive_max_interval": "Максимальний інтервал (дні)",
|
||||
"adaptive_min_interval": "Мінімальний інтервал (дні)",
|
||||
"adaptive_ewa_alpha": "Швидкість навчання (alpha)",
|
||||
"adaptive_enabled": "Увімкнути адаптивне планування",
|
||||
"adaptive_section_title": "Адаптивне планування",
|
||||
"environmental_attribute_optional": "Атрибут середовища (необов'язково)",
|
||||
"nfc_tag_id": "ID NFC-тега",
|
||||
"nfc_linked": "NFC-тег прив'язано",
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
"nfc_tags_refresh": "刷新",
|
||||
"environmental_entity_optional": "环境传感器 (可选)",
|
||||
"environmental_entity_helper": "例如:sensor.outdoor_temperature — 根据环境条件自动调整间隔",
|
||||
"adaptive_prediction_enabled": "启用基于传感器的预测",
|
||||
"adaptive_seasonal_enabled": "启用季节性感知",
|
||||
"adaptive_max_interval": "最大间隔 (天)",
|
||||
"adaptive_min_interval": "最小间隔 (天)",
|
||||
"adaptive_ewa_alpha": "学习率 (alpha)",
|
||||
"adaptive_enabled": "启用自适应计划",
|
||||
"adaptive_section_title": "自适应计划",
|
||||
"environmental_attribute_optional": "环境属性 (可选)",
|
||||
"nfc_tag_id": "NFC 标签 ID",
|
||||
"nfc_linked": "NFC 标签已链接",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*! maintenance_supporter frontend 2.55.0 */
|
||||
var it=Object.defineProperty;var lt=Object.getOwnPropertyDescriptor;var x=(a,e,t,o)=>{for(var r=o>1?void 0:o?lt(e,t):e,n=a.length-1,s;n>=0;n--)(s=a[n])&&(r=(o?s(e,t,r):s(r))||r);return o&&r&&it(e,t,r),r};var ee=globalThis,te=ee.ShadowRoot&&(ee.ShadyCSS===void 0||ee.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,de=Symbol(),Se=new WeakMap,q=class{constructor(e,t,o){if(this._$cssResult$=!0,o!==de)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o,t=this.t;if(te&&e===void 0){let o=t!==void 0&&t.length===1;o&&(e=Se.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),o&&Se.set(t,e))}return e}toString(){return this.cssText}},$e=a=>new q(typeof a=="string"?a:a+"",void 0,de),k=(a,...e)=>{let t=a.length===1?a[0]:e.reduce((o,r,n)=>o+(s=>{if(s._$cssResult$===!0)return s.cssText;if(typeof s=="number")return s;throw Error("Value passed to 'css' function must be a 'css' function result: "+s+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(r)+a[n+1],a[0]);return new q(t,a,de)},Ae=(a,e)=>{if(te)a.adoptedStyleSheets=e.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of e){let o=document.createElement("style"),r=ee.litNonce;r!==void 0&&o.setAttribute("nonce",r),o.textContent=t.cssText,a.appendChild(o)}},pe=te?a=>a:a=>a instanceof CSSStyleSheet?(e=>{let t="";for(let o of e.cssRules)t+=o.cssText;return $e(t)})(a):a;var{is:ct,defineProperty:dt,getOwnPropertyDescriptor:pt,getOwnPropertyNames:ut,getOwnPropertySymbols:_t,getPrototypeOf:ht}=Object,oe=globalThis,je=oe.trustedTypes,gt=je?je.emptyScript:"",ft=oe.reactiveElementPolyfillSupport,F=(a,e)=>a,B={toAttribute(a,e){switch(e){case Boolean:a=a?gt:null;break;case Object:case Array:a=a==null?a:JSON.stringify(a)}return a},fromAttribute(a,e){let t=a;switch(e){case Boolean:t=a!==null;break;case Number:t=a===null?null:Number(a);break;case Object:case Array:try{t=JSON.parse(a)}catch{t=null}}return t}},re=(a,e)=>!ct(a,e),Ce={attribute:!0,type:String,converter:B,reflect:!1,useDefault:!1,hasChanged:re};Symbol.metadata??=Symbol("metadata"),oe.litPropertyMetadata??=new WeakMap;var S=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=Ce){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){let o=Symbol(),r=this.getPropertyDescriptor(e,o,t);r!==void 0&&dt(this.prototype,e,r)}}static getPropertyDescriptor(e,t,o){let{get:r,set:n}=pt(this.prototype,e)??{get(){return this[t]},set(s){this[t]=s}};return{get:r,set(s){let l=r?.call(this);n?.call(this,s),this.requestUpdate(e,l,o)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??Ce}static _$Ei(){if(this.hasOwnProperty(F("elementProperties")))return;let e=ht(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(F("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(F("properties"))){let t=this.properties,o=[...ut(t),..._t(t)];for(let r of o)this.createProperty(r,t[r])}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[o,r]of t)this.elementProperties.set(o,r)}this._$Eh=new Map;for(let[t,o]of this.elementProperties){let r=this._$Eu(t,o);r!==void 0&&this._$Eh.set(r,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let o=new Set(e.flat(1/0).reverse());for(let r of o)t.unshift(pe(r))}else e!==void 0&&t.push(pe(e));return t}static _$Eu(e,t){let o=t.attribute;return o===!1?void 0:typeof o=="string"?o:typeof e=="string"?e.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(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let o of t.keys())this.hasOwnProperty(o)&&(e.set(o,this[o]),delete this[o]);e.size>0&&(this._$Ep=e)}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return Ae(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,o){this._$AK(e,o)}_$ET(e,t){let o=this.constructor.elemenLine truncated
|
||||
\f\r]`,W=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,De=/-->/g,Ne=/>/g,C=RegExp(`>|${ue}(?:([^\\s"'>=/]+)(${ue}*=${ue}*(?:[^
|
||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),Re=/'/g,Pe=/"/g,Me=/^(?:script|style|textarea|title)$/i,ve=a=>(e,...t)=>({_$litType$:a,strings:e,values:t}),m=ve(1),It=ve(2),qt=ve(3),D=Symbol.for("lit-noChange"),g=Symbol.for("lit-nothing"),ze=new WeakMap,E=T.createTreeWalker(T,129);function Ue(a,e){if(!ye(a)||!a.hasOwnProperty("raw"))throw Error("invalid template strings array");return Te!==void 0?Te.createHTML(e):e}var yt=(a,e)=>{let t=a.length-1,o=[],r,n=e===2?"<svg>":e===3?"<math>":"",s=W;for(let l=0;l<t;l++){let d=a[l],p,u,c=-1,_=0;for(;_<d.length&&(s.lastIndex=_,u=s.exec(d),u!==null);)_=s.lastIndex,s===W?u[1]==="!--"?s=De:u[1]!==void 0?s=Ne:u[2]!==void 0?(Me.test(u[2])&&(r=RegExp("</"+u[2],"g")),s=C):u[3]!==void 0&&(s=C):s===C?u[0]===">"?(s=r??W,c=-1):u[1]===void 0?c=-2:(c=s.lastIndex-u[2].length,p=u[1],s=u[3]===void 0?C:u[3]==='"'?Pe:Re):s===Pe||s===Re?s=C:s===De||s===Ne?s=W:(s=C,r=void 0);let h=s===C&&a[l+1].startsWith("/>")?" ":"";n+=s===W?d+mt:c>=0?(o.push(p),d.slice(0,c)+Oe+d.slice(c)+A+h):d+A+(c===-2?l:h)}return[Ue(a,n+(a[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),o]},V=class a{constructor({strings:e,_$litType$:t},o){let r;this.parts=[];let n=0,s=0,l=e.length-1,d=this.parts,[p,u]=yt(e,t);if(this.el=a.createElement(p,o),E.currentNode=this.el.content,t===2||t===3){let c=this.el.content.firstChild;c.replaceWith(...c.childNodes)}for(;(r=E.nextNode())!==null&&d.length<l;){if(r.nodeType===1){if(r.hasAttributes())for(let c of r.getAttributeNames())if(c.endsWith(Oe)){let _=u[s++],h=r.getAttribute(c).split(A),b=/([.?@])?(.*)/.exec(_);d.push({type:1,index:n,name:b[2],strings:h,ctor:b[1]==="."?he:b[1]==="?"?ge:b[1]==="@"?fe:O}),r.removeAttribute(c)}else c.startsWith(A)&&(d.push({type:6,index:n}),r.removeAttribute(c));if(Me.test(r.tagName)){let c=r.textContent.split(A),_=c.length-1;if(_>0){r.textContent=ae?ae.emptyScript:"";for(let h=0;h<_;h++)r.append(c[h],Y()),E.nextNode(),d.push({type:2,index:++n});r.append(c[_],Y())}}}else if(r.nodeType===8)if(r.data===Le)d.push({type:2,index:n});else{let c=-1;for(;(c=r.data.indexOf(A,c+1))!==-1;)d.push({type:7,index:n}),c+=A.length-1}n++}}static createElement(e,t){let o=T.createElement("template");return o.innerHTML=e,o}};function z(a,e,t=a,o){if(e===D)return e;let r=o!==void 0?t._$Co?.[o]:t._$Cl,n=G(e)?void 0:e._$litDirective$;return r?.constructor!==n&&(r?._$AO?.(!1),n===void 0?r=void 0:(r=new n(a),r._$AT(a,t,o)),o!==void 0?(t._$Co??=[])[o]=r:t._$Cl=r),r!==void 0&&(e=z(a,r._$AS(a,e.values),r,o)),e}var _e=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:o}=this._$AD,r=(e?.creationScope??T).importNode(t,!0);E.currentNode=r;let n=E.nextNode(),s=0,l=0,d=o[0];for(;d!==void 0;){if(s===d.index){let p;d.type===2?p=new K(n,n.nextSibling,this,e):d.type===1?p=new d.ctor(n,d.name,d.strings,this,e):d.type===6&&(p=new me(n,this,e)),this._$AV.push(p),d=o[++l]}s!==d?.index&&(n=E.nextNode(),s++)}return E.currentNode=T,r}p(e){let t=0;for(let o of this._$AV)o!==void 0&&(o.strings!==void 0?(o._$AI(e,o,t),t+=o.strings.length-2):o._$AI(e[t])),t++}},K=class a{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,o,r){this.type=2,this._$AH=g,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=o,this.options=r,this._$Cv=r?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=z(this,e,t),G(e)?e===g||e==null||e===""?(this._$AH!==g&&this._$AR(),this._$AH=g):e!==this._$AH&&e!==D&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):bt(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==g&&G(this._$AH)?this._$AA.nextSibling.data=e:this.T(T.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:o}=e,r=typeof o=="number"?this._$AC(e):(o.el===void 0&&(o.el=V.createElement(Ue(o.h,o.h[0]),this.options)),o);if(this._$AH?._$AD===r)this._$AH.p(t);else{let n=new _e(r,this),s=n.u(this.options);n.p(t),this.T(s),this._$AH=n}}_$AC(e){let t=ze.get(e.strings);return t===void 0&&ze.set(e.strings,t=new V(e)),t}k(e){ye(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,o,r=0;for(let n of e)r===t.length?t.push(o=new a(this.O(Y()),this.O(Y()),this,this.options)):o=t[r],o._$AI(n),r++;r<t.length&&(this._$AR(o&&o._$AB.nextSibling,r),t.length=r)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let o=Ee(e).nextSibling;Ee(e).remove(),e=o}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},O=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,o,r,n){this.type=1,this._$AH=g,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=n,o.length>2||o[0]!==""||o[1]!==""?(this._$AH=Array(o.length-1).fill(new String),this.strings=Line truncated
|
||||
/*! maintenance_supporter frontend 2.56.0 */
|
||||
var it=Object.defineProperty;var lt=Object.getOwnPropertyDescriptor;var x=(a,e,t,o)=>{for(var r=o>1?void 0:o?lt(e,t):e,n=a.length-1,s;n>=0;n--)(s=a[n])&&(r=(o?s(e,t,r):s(r))||r);return o&&r&&it(e,t,r),r};var ee=globalThis,te=ee.ShadowRoot&&(ee.ShadyCSS===void 0||ee.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,de=Symbol(),Se=new WeakMap,q=class{constructor(e,t,o){if(this._$cssResult$=!0,o!==de)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o,t=this.t;if(te&&e===void 0){let o=t!==void 0&&t.length===1;o&&(e=Se.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),o&&Se.set(t,e))}return e}toString(){return this.cssText}},$e=a=>new q(typeof a=="string"?a:a+"",void 0,de),k=(a,...e)=>{let t=a.length===1?a[0]:e.reduce((o,r,n)=>o+(s=>{if(s._$cssResult$===!0)return s.cssText;if(typeof s=="number")return s;throw Error("Value passed to 'css' function must be a 'css' function result: "+s+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(r)+a[n+1],a[0]);return new q(t,a,de)},Ae=(a,e)=>{if(te)a.adoptedStyleSheets=e.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of e){let o=document.createElement("style"),r=ee.litNonce;r!==void 0&&o.setAttribute("nonce",r),o.textContent=t.cssText,a.appendChild(o)}},pe=te?a=>a:a=>a instanceof CSSStyleSheet?(e=>{let t="";for(let o of e.cssRules)t+=o.cssText;return $e(t)})(a):a;var{is:ct,defineProperty:dt,getOwnPropertyDescriptor:pt,getOwnPropertyNames:ut,getOwnPropertySymbols:_t,getPrototypeOf:ht}=Object,oe=globalThis,je=oe.trustedTypes,gt=je?je.emptyScript:"",ft=oe.reactiveElementPolyfillSupport,F=(a,e)=>a,B={toAttribute(a,e){switch(e){case Boolean:a=a?gt:null;break;case Object:case Array:a=a==null?a:JSON.stringify(a)}return a},fromAttribute(a,e){let t=a;switch(e){case Boolean:t=a!==null;break;case Number:t=a===null?null:Number(a);break;case Object:case Array:try{t=JSON.parse(a)}catch{t=null}}return t}},re=(a,e)=>!ct(a,e),Ee={attribute:!0,type:String,converter:B,reflect:!1,useDefault:!1,hasChanged:re};Symbol.metadata??=Symbol("metadata"),oe.litPropertyMetadata??=new WeakMap;var S=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=Ee){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){let o=Symbol(),r=this.getPropertyDescriptor(e,o,t);r!==void 0&&dt(this.prototype,e,r)}}static getPropertyDescriptor(e,t,o){let{get:r,set:n}=pt(this.prototype,e)??{get(){return this[t]},set(s){this[t]=s}};return{get:r,set(s){let l=r?.call(this);n?.call(this,s),this.requestUpdate(e,l,o)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??Ee}static _$Ei(){if(this.hasOwnProperty(F("elementProperties")))return;let e=ht(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(F("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(F("properties"))){let t=this.properties,o=[...ut(t),..._t(t)];for(let r of o)this.createProperty(r,t[r])}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[o,r]of t)this.elementProperties.set(o,r)}this._$Eh=new Map;for(let[t,o]of this.elementProperties){let r=this._$Eu(t,o);r!==void 0&&this._$Eh.set(r,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let o=new Set(e.flat(1/0).reverse());for(let r of o)t.unshift(pe(r))}else e!==void 0&&t.push(pe(e));return t}static _$Eu(e,t){let o=t.attribute;return o===!1?void 0:typeof o=="string"?o:typeof e=="string"?e.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(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let o of t.keys())this.hasOwnProperty(o)&&(e.set(o,this[o]),delete this[o]);e.size>0&&(this._$Ep=e)}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return Ae(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,o){this._$AK(e,o)}_$ET(e,t){let o=this.constructor.elemenLine truncated
|
||||
\f\r]`,W=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,De=/-->/g,Ne=/>/g,E=RegExp(`>|${ue}(?:([^\\s"'>=/]+)(${ue}*=${ue}*(?:[^
|
||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),Re=/'/g,Pe=/"/g,Me=/^(?:script|style|textarea|title)$/i,ve=a=>(e,...t)=>({_$litType$:a,strings:e,values:t}),m=ve(1),It=ve(2),qt=ve(3),D=Symbol.for("lit-noChange"),g=Symbol.for("lit-nothing"),ze=new WeakMap,C=T.createTreeWalker(T,129);function Ue(a,e){if(!ye(a)||!a.hasOwnProperty("raw"))throw Error("invalid template strings array");return Te!==void 0?Te.createHTML(e):e}var yt=(a,e)=>{let t=a.length-1,o=[],r,n=e===2?"<svg>":e===3?"<math>":"",s=W;for(let l=0;l<t;l++){let d=a[l],p,u,c=-1,_=0;for(;_<d.length&&(s.lastIndex=_,u=s.exec(d),u!==null);)_=s.lastIndex,s===W?u[1]==="!--"?s=De:u[1]!==void 0?s=Ne:u[2]!==void 0?(Me.test(u[2])&&(r=RegExp("</"+u[2],"g")),s=E):u[3]!==void 0&&(s=E):s===E?u[0]===">"?(s=r??W,c=-1):u[1]===void 0?c=-2:(c=s.lastIndex-u[2].length,p=u[1],s=u[3]===void 0?E:u[3]==='"'?Pe:Re):s===Pe||s===Re?s=E:s===De||s===Ne?s=W:(s=E,r=void 0);let h=s===E&&a[l+1].startsWith("/>")?" ":"";n+=s===W?d+mt:c>=0?(o.push(p),d.slice(0,c)+Oe+d.slice(c)+A+h):d+A+(c===-2?l:h)}return[Ue(a,n+(a[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),o]},V=class a{constructor({strings:e,_$litType$:t},o){let r;this.parts=[];let n=0,s=0,l=e.length-1,d=this.parts,[p,u]=yt(e,t);if(this.el=a.createElement(p,o),C.currentNode=this.el.content,t===2||t===3){let c=this.el.content.firstChild;c.replaceWith(...c.childNodes)}for(;(r=C.nextNode())!==null&&d.length<l;){if(r.nodeType===1){if(r.hasAttributes())for(let c of r.getAttributeNames())if(c.endsWith(Oe)){let _=u[s++],h=r.getAttribute(c).split(A),b=/([.?@])?(.*)/.exec(_);d.push({type:1,index:n,name:b[2],strings:h,ctor:b[1]==="."?he:b[1]==="?"?ge:b[1]==="@"?fe:O}),r.removeAttribute(c)}else c.startsWith(A)&&(d.push({type:6,index:n}),r.removeAttribute(c));if(Me.test(r.tagName)){let c=r.textContent.split(A),_=c.length-1;if(_>0){r.textContent=ae?ae.emptyScript:"";for(let h=0;h<_;h++)r.append(c[h],Y()),C.nextNode(),d.push({type:2,index:++n});r.append(c[_],Y())}}}else if(r.nodeType===8)if(r.data===Le)d.push({type:2,index:n});else{let c=-1;for(;(c=r.data.indexOf(A,c+1))!==-1;)d.push({type:7,index:n}),c+=A.length-1}n++}}static createElement(e,t){let o=T.createElement("template");return o.innerHTML=e,o}};function z(a,e,t=a,o){if(e===D)return e;let r=o!==void 0?t._$Co?.[o]:t._$Cl,n=G(e)?void 0:e._$litDirective$;return r?.constructor!==n&&(r?._$AO?.(!1),n===void 0?r=void 0:(r=new n(a),r._$AT(a,t,o)),o!==void 0?(t._$Co??=[])[o]=r:t._$Cl=r),r!==void 0&&(e=z(a,r._$AS(a,e.values),r,o)),e}var _e=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:o}=this._$AD,r=(e?.creationScope??T).importNode(t,!0);C.currentNode=r;let n=C.nextNode(),s=0,l=0,d=o[0];for(;d!==void 0;){if(s===d.index){let p;d.type===2?p=new K(n,n.nextSibling,this,e):d.type===1?p=new d.ctor(n,d.name,d.strings,this,e):d.type===6&&(p=new me(n,this,e)),this._$AV.push(p),d=o[++l]}s!==d?.index&&(n=C.nextNode(),s++)}return C.currentNode=T,r}p(e){let t=0;for(let o of this._$AV)o!==void 0&&(o.strings!==void 0?(o._$AI(e,o,t),t+=o.strings.length-2):o._$AI(e[t])),t++}},K=class a{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,o,r){this.type=2,this._$AH=g,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=o,this.options=r,this._$Cv=r?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=z(this,e,t),G(e)?e===g||e==null||e===""?(this._$AH!==g&&this._$AR(),this._$AH=g):e!==this._$AH&&e!==D&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):bt(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==g&&G(this._$AH)?this._$AA.nextSibling.data=e:this.T(T.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:o}=e,r=typeof o=="number"?this._$AC(e):(o.el===void 0&&(o.el=V.createElement(Ue(o.h,o.h[0]),this.options)),o);if(this._$AH?._$AD===r)this._$AH.p(t);else{let n=new _e(r,this),s=n.u(this.options);n.p(t),this.T(s),this._$AH=n}}_$AC(e){let t=ze.get(e.strings);return t===void 0&&ze.set(e.strings,t=new V(e)),t}k(e){ye(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,o,r=0;for(let n of e)r===t.length?t.push(o=new a(this.O(Y()),this.O(Y()),this,this.options)):o=t[r],o._$AI(n),r++;r<t.length&&(this._$AR(o&&o._$AB.nextSibling,r),t.length=r)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let o=Ce(e).nextSibling;Ce(e).remove(),e=o}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},O=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,o,r,n){this.type=1,this._$AH=g,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=n,o.length>2||o[0]!==""||o[1]!==""?(this._$AH=Array(o.length-1).fill(new String),this.strings=Line truncated
|
||||
.cal-controls {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
@@ -200,7 +200,7 @@ var it=Object.defineProperty;var lt=Object.getOwnPropertyDescriptor;var x=(a,e,t
|
||||
}
|
||||
`;var Ge={maintenance:"Maintenance",objects:"Objects",tasks:"Tasks",overdue:"Overdue",due_soon:"Due Soon",triggered:"Triggered",trigger_replaced:"Trigger replaced",ok:"OK",all:"All",new_object:"+ New Object",templates_from:"From template",templates_title:"Start from a template",templates_task_count:"{n} tasks",template_created:"Created from template",onboard_hint:"Add your first object to start tracking maintenance.",edit:"Edit",duplicate:"Duplicate",task_duplicated:"Task duplicated",object_duplicated:"Object duplicated",delete:"Delete",add_task:"+ Add Task",complete:"Complete",completed:"Completed",skip:"Skip",skipped:"Skipped",missed:"Missed",reset:"Reset",snooze:"Snooze",snoozed:"Snoozed",cancel:"Cancel",bulk_select:"Select",bulk_select_all:"Select all",bulk_n_selected:"{n} selected",bulk_completed:"{n} tasks completed",bulk_archived:"{n} tasks archived",completing:"Completing\u2026",interval:"Interval",warning:"Warning",last_performed:"Last performed",next_due:"Next due",days_until_due:"Days until due",avg_duration:"Avg duration",trigger:"Trigger",trigger_type:"Trigger type",threshold_above:"Upper limit",threshold_below:"Lower limit",threshold:"Threshold",counter:"Counter",state_change:"State change",runtime:"Runtime",runtime_hours:"Target runtime (hours)",target_value:"Target value",baseline:"Baseline",target_changes:"Target changes",for_minutes:"For (minutes)",time_based:"Time-based",sensor_based:"Sensor-based",manual:"Manual",one_time:"One-time",weekdays:"Weekdays",nth_weekday:"Nth weekday of month",day_of_month:"Day of month",recurrence_on_days:"Repeat on",recurrence_occurrence:"Occurrence",recurrence_weekday:"Weekday",recurrence_day:"Day of month (1\u201331)",recurrence_last_day:"Last day of the month",recurrence_business_day:"Business days only (roll back from weekend)",recurrence_offset:"Offset (days, \xB1)",recurrence_offset_help:"Shift the date by \xB1N days, e.g. -2 = two days before.",last_day_month:"Last day of month",last_business_day_month:"Last business day",ord_1:"1st",ord_2:"2nd",ord_3:"3rd",ord_4:"4th",ord_5:"5th",ord_last:"Last",day_word:"Day",interval_value:"Interval",interval_unit:"Unit",unit_days:"Days",unit_weeks:"Weeks",unit_months:"Months",unit_years:"Years",due_date:"Due date",cleaning:"Cleaning",inspection:"Inspection",replacement:"Replacement",calibration:"Calibration",service:"Service",reading:"Reading",custom:"Custom",history:"History",cost:"Cost",report_button:"Report",report_title:"Maintenance report",report_generated:"Generated",report_times_done:"Done",report_total_cost:"Total cost",report_every:"every {n} {unit}",report_notes:"Notes",report_col_type:"Type",report_col_status:"Status",report_col_schedule:"Schedule",duration:"Duration",both:"Both",trigger_val:"Trigger value",complete_title:"Complete: ",checklist:"Checklist",require_on_completion:"Require on completion",checklist_steps_optional:"Checklist steps (optional)",checklist_placeholder:`Clean filter
|
||||
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",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",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 confidence",budget_monthly:"Monthly budget",budget_yearly:"Yearly budget",groups:"Groups",new_group:"New group",edit_group:"Edit group",no_groups:"No groups yet",delete_group:"Delete group",delete_group_confirm:"Delete group '{name}'?",group_select_tasks:"Select tasks",group_name_required:"Name is required",description_optional:"Description (optional)",selected:"Sel
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)",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",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 confidence",budget_mo
Line truncated
|
||||
.field { display: flex; flex-direction: column; gap: 4px; }
|
||||
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
||||
.field-input {
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,5 @@
|
||||
/*! maintenance_supporter frontend 2.55.0 */
|
||||
import"/maintenance_supporter_panelfiles/panel-chunks/chunk-BDAGEP22.js";import{b as Ut,c as re}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4HD7ODUX.js";import{a as E}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-XYTY2SBA.js";import{a as se,b as ae,c as ne,d as oe,e as At}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-ZIQ7JY7R.js";import{a as le}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-6RMRSFSY.js";import{a as g,b as D,c as o,d as P,f as d,g as C,h as ee,i as T,j as m,k as St,l as Mt,m as ut,n as s,o as Et,p as q,q as Dt,r as Y,s as Ct,t as gt,v as xt,w as mt,x as ie,y as Lt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NHOMCQWL.js";function it(n){return!!n&&/^https?:\/\//i.test(n)}var He=["assignee_pool","required_completion_fields","checklist","labels","history"],Fe=["checklist_progress"],Be=["tasks","parts"],Ve=["manual_docs","battery_fleet_excluded"];function Wt(n,r,t=[]){for(let e of r)n[e]===void 0&&(n[e]=[]);for(let e of t)n[e]===void 0&&(n[e]={})}function Ne(n){let r=n;Wt(r,Be),r.object&&typeof r.object=="object"&&Wt(r.object,Ve);for(let t of r.tasks)Wt(t,He,Fe);return n}function $t(n){for(let r of n)Ne(r);return n}function Ue(n,r){if(r.objects)return r.objects;let t=r.delta||[],e=r.removed||[];if(!t.length&&!e.length)return null;let i=new Map(n.map(a=>[a.entry_id,a]));for(let a of t)i.set(a.entry_id,a);for(let a of e)i.delete(a);return[...i.values()]}function ce(n,r){return r.objects&&$t(r.objects),r.delta&&$t(r.delta),Ue(n,r)}var Rt="2.55.0";function de(n,r=Rt){return!n||!r||r==="dev"?!1:n!==r}var F={overviewTab:"msp-overview-tab",collapsedSections:"msp-collapsed-sections",chartRange:"msp-chart-range",chartHideOutliers:"msp-chart-hide-outliers",taskSort:"maintenance_supporter_sort",objectSort:"maintenance_supporter_object_sort",groupBy:"maintenance_supporter_groupby",objectView:"maintenance_supporter_object_view",objectsCache:"msp-objects-cache",gettingStartedDismissed:"msp-gs-dismissed"};var We=168*3600*1e3;function pe(){try{let n=localStorage.getItem(F.objectsCache);if(!n)return null;let r=JSON.parse(n);return r.v!==Rt||!Number.isFinite(r.at)||Date.now()-r.at>We||!Array.isArray(r.objects)||r.objects.length===0?null:{objects:r.objects,stats:r.stats??null}}catch{return null}}function qt(n,r){if(!(!Array.isArray(n)||n.length===0))try{let t={v:Rt,at:Date.now(),objects:n,stats:r};localStorage.setItem(F.objectsCache,JSON.stringify(t))}catch{}}var qe={days:1,weeks:7,months:30.4368,years:365.25};function Yt(n,r){return!n||n<=0?0:n*(qe[r||"days"]??1)}function Ot(n,r,t){let e=Yt(n,t);if(e<=0||r==null)return{pct:0,overflow:!1};let i=(e-r)/e*100;return{pct:Math.max(0,Math.min(100,i)),overflow:i>100}}function A(n){return String(n??"").replace(/[&<>"']/g,r=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[r])}function he(n,r,t,e,i,a){let l=[[t.manufacturer,n.manufacturer],[t.model,n.model],[t.serial,n.serial_number],[t.installed,n.installation_date?e(n.installation_date):null],[t.warranty,n.warranty_expiry?e(n.warranty_expiry):null]].filter(([,p])=>!!p),h=r.map(p=>{let u=t.scheduleLabel(p);return`<tr>
|
||||
/*! maintenance_supporter frontend 2.56.0 */
|
||||
import"/maintenance_supporter_panelfiles/panel-chunks/chunk-ZK3W7TF6.js";import{b as Ut,c as re}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-SD6IEJBA.js";import{a as E}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-LJXSDCLS.js";import{a as se,b as ae,c as ne,d as oe,e as At}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-DV4UHMJC.js";import{a as le}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-I7J3AORE.js";import{a as g,b as D,c as o,d as P,f as d,g as C,h as ee,i as T,j as m,k as St,l as Mt,m as ut,n as s,o as Et,p as q,q as Dt,r as Y,s as Ct,t as gt,v as xt,w as mt,x as ie,y as Lt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C5W5B43R.js";function it(n){return!!n&&/^https?:\/\//i.test(n)}var He=["assignee_pool","required_completion_fields","checklist","labels","history"],Fe=["checklist_progress"],Be=["tasks","parts"],Ve=["manual_docs","battery_fleet_excluded"];function Wt(n,r,t=[]){for(let e of r)n[e]===void 0&&(n[e]=[]);for(let e of t)n[e]===void 0&&(n[e]={})}function Ne(n){let r=n;Wt(r,Be),r.object&&typeof r.object=="object"&&Wt(r.object,Ve);for(let t of r.tasks)Wt(t,He,Fe);return n}function $t(n){for(let r of n)Ne(r);return n}function Ue(n,r){if(r.objects)return r.objects;let t=r.delta||[],e=r.removed||[];if(!t.length&&!e.length)return null;let i=new Map(n.map(a=>[a.entry_id,a]));for(let a of t)i.set(a.entry_id,a);for(let a of e)i.delete(a);return[...i.values()]}function ce(n,r){return r.objects&&$t(r.objects),r.delta&&$t(r.delta),Ue(n,r)}var Rt="2.56.0";function de(n,r=Rt){return!n||!r||r==="dev"?!1:n!==r}var F={overviewTab:"msp-overview-tab",collapsedSections:"msp-collapsed-sections",chartRange:"msp-chart-range",chartHideOutliers:"msp-chart-hide-outliers",taskSort:"maintenance_supporter_sort",objectSort:"maintenance_supporter_object_sort",groupBy:"maintenance_supporter_groupby",objectView:"maintenance_supporter_object_view",objectsCache:"msp-objects-cache",gettingStartedDismissed:"msp-gs-dismissed"};var We=168*3600*1e3;function pe(){try{let n=localStorage.getItem(F.objectsCache);if(!n)return null;let r=JSON.parse(n);return r.v!==Rt||!Number.isFinite(r.at)||Date.now()-r.at>We||!Array.isArray(r.objects)||r.objects.length===0?null:{objects:r.objects,stats:r.stats??null}}catch{return null}}function qt(n,r){if(!(!Array.isArray(n)||n.length===0))try{let t={v:Rt,at:Date.now(),objects:n,stats:r};localStorage.setItem(F.objectsCache,JSON.stringify(t))}catch{}}var qe={days:1,weeks:7,months:30.4368,years:365.25};function Yt(n,r){return!n||n<=0?0:n*(qe[r||"days"]??1)}function Ot(n,r,t){let e=Yt(n,t);if(e<=0||r==null)return{pct:0,overflow:!1};let i=(e-r)/e*100;return{pct:Math.max(0,Math.min(100,i)),overflow:i>100}}function A(n){return String(n??"").replace(/[&<>"']/g,r=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[r])}function he(n,r,t,e,i,a){let l=[[t.manufacturer,n.manufacturer],[t.model,n.model],[t.serial,n.serial_number],[t.installed,n.installation_date?e(n.installation_date):null],[t.warranty,n.warranty_expiry?e(n.warranty_expiry):null]].filter(([,p])=>!!p),h=r.map(p=>{let u=t.scheduleLabel(p);return`<tr>
|
||||
<td>${A(p.name)}</td>
|
||||
<td>${A(t.typeLabel(p.type))}</td>
|
||||
<td>${A(t.statusLabel(p.status))}</td>
|
||||
@@ -4556,7 +4556,7 @@ ${A(n.notes)}</div>`:""}
|
||||
.canWrite=${!r.isOperator}
|
||||
></maintenance-task-documents>
|
||||
</div>
|
||||
`}var jt=class extends C{createRenderRoot(){return this}render(){return!this.task||!this.ctx?d:o`${ze(this.task,this.ctx)}`}};g([T({attribute:!1})],jt.prototype,"task",2),g([T({attribute:!1})],jt.prototype,"ctx",2);customElements.get("maintenance-task-detail-view")||customElements.define("maintenance-task-detail-view",jt);function Ie(n){if(n.total<=0)return{start:0,end:0,padTop:0,padBottom:0};let r=n.overscan??12,t=Math.max(1,n.step??6),e=Math.max(1,n.rowHeight),i=Math.floor((n.scrollTop-n.listTop)/e),a=Math.ceil(n.viewportHeight/e)+1,l=Math.max(0,i-r);l=Math.floor(l/t)*t;let h=Math.min(n.total,Math.max(i,0)+a+r);return h=Math.min(n.total,Math.ceil(h/t)*t),l>=h&&(l=Math.min(l,Math.max(0,n.total-1)),h=Math.min(n.total,l+Math.max(a,1))),{start:l,end:h,padTop:l*e,padBottom:(n.total-h)*e}}var k=class extends C{constructor(){super(...arguments);this.narrow=!1;this.panel={};this._objects=[];this._stats=null;this._view="overview";this._selectedEntryId=null;this._selectedTaskId=null;this._filterStatus="";this._filterUser=null;this._filterLabel=null;this._savedViews=[];this._activeViewId="";this._unsub=null;this._chartRangeDays=(()=>{try{let t=parseInt(localStorage.getItem(F.chartRange)||"",10);return[7,30,90,365].includes(t)?t:30}catch{return 30}})();this._hideOutliers=(()=>{try{return localStorage.getItem(F.chartHideOutliers)==="1"}catch{return!1}})();this._historyFilter=null;this._budget=null;this._groups={};this._detailStatsData=new Map;this._miniStatsData=new Map;this._features={adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1};this._adminPanelUserIds=[];this._operatorWriteEnabled=!1;this._defaultWarningDays=7;this._actionLoading=!1;this._moreMenuOpen=!1;this._objMenuOpen=!1;this._toastMessage="";this._toastUndo=null;this._toastActionLabel="";this._filtersOpen=!1;this._newMenuOpen=!1;this._gsSetupsCount=0;this._gsAdoptCount=0;this._gsLoaded=!1;this._batteryFleetSetupAvailable=!1;this._staleBundle=!1;this._staleChecked=!1;this._toastTimer=null;this._dismissedSuggestions=new Set;this._overviewTab=(()=>{try{let t=localStorage.getItem(F.overviewTab);return t==="today"||t==="calendar"?t:"dashboard"}catch{return"dashboard"}})();this._activeTab="overview";this._costDurationToggle="both";this._historySearch="";this._sortMode="due_date";this._objectSortMode="alphabetical";this._groupByMode="none";this._objectViewMode="cards";this._objectsTableColumns=ae;this._showArchived=!1;this._bulkMode=!1;this._bulkSelected=new Set;this._virtStart=0;this._virtEnd=0;this._virtRowHeight=53;this._virtTotalRows=0;this._virtScrollAttached=!1;this._virtRaf=0;this._collapsedSections=(()=>{try{return new Set(JSON.parse(localStorage.getItem(F.collapsedSections)||"[]"))}catch{return new Set}})();this._paletteOpen=!1;this._paletteQuery="";this._paletteActive=0;this._templateGalleryOpen=!1;this._templates=[];this._templateCategories={};this._templateBusy=!1;this._statsService=null;this._userService=null;this._dataLoaded=!1;this._lastConnection=null;this._popstateHandler=t=>this._onPopState(t);this._lazyUi=null;this._onVirtualScroll=()=>{this._virtRaf||(this._virtRaf=requestAnimationFrame(()=>{this._virtRaf=0,this._updateVirtualWindow()}))};this._deepLinkHandled=!1;this._paletteKeydown=t=>{if(t.key==="/"&&!t.ctrlKey&&!t.metaKey&&!t.altKey&&!this._paletteOpen){let i=t.composedPath()[0];if(i instanceof HTMLElement&&(i.tagName==="INPUT"||i.tagName==="TEXTAREA"||i.tagName==="SELECT"||i.isContentEditable))return;t.preventDefault(),this._openPalette();return}if(!this._paletteOpen)return;let e=this._paletteResults;if(t.key==="Escape")t.preventDefault(),this._closePalette();else if(t.key==="ArrowDown")t.preventDefault(),this._paletteActive=Math.min(this._paletteActive+1,e.length-1);else if(t.key==="ArrowUp")t.preventDefault(),this._paletteActive=Math.max(this._paletteActive-1,0);else if(t.key==="Enter"){t.preventDefault();let i=e[this._paletteActive];i&&this._selectPaletteResult(i)}};this._onDialogEvent=async()=>{try{await this._loadData()}catch{}};this._onCalendarLlCustom=t=>{let e=t.detail;e?.type==="maintenance-supporter:open-task"&&e.entry_id&&e.task_id&&(t.stopPropagation(),this._showTask(e.entry_id,e.task_id))};this._fullHistory=null;this._onHistoryEntrySaved=async()=>{await this._loadData()}}get _lang(){return this.hass?.language||"en"}get _isOperator(){let t=this.hass?.user;return t?t.is_admin?!1:!(this._operatorWriteEnabled&&this._adminPanelUserIds.includes(t.id)):!0}_ensureLazyUi(){return this._lazyUi||(this._lazyUi=Promise.all([import("/maintenance_supporter_panelfiles/panel-chunks/object-dialog-YRX6AWLQ.js"),import("/maintenance_supporter_panelfiles/panel-chunks/task-dialog-FU3K4IJH.js"),import("/maintenance_supporter_panelfiles/panel-chunks/complete-dialog-DYCBJTZV.js"),import("/maintenance_supporter_panelfiles/panel-chunks/qr-dialog-ONGEWKLY.js"),import("/maintenance_supporter_panelfiles/panel-chunks/adopt-problem-sensors-dialog-2KGMOVVK.js"),import("/mainte
Line truncated
|
||||
`}var jt=class extends C{createRenderRoot(){return this}render(){return!this.task||!this.ctx?d:o`${ze(this.task,this.ctx)}`}};g([T({attribute:!1})],jt.prototype,"task",2),g([T({attribute:!1})],jt.prototype,"ctx",2);customElements.get("maintenance-task-detail-view")||customElements.define("maintenance-task-detail-view",jt);function Ie(n){if(n.total<=0)return{start:0,end:0,padTop:0,padBottom:0};let r=n.overscan??12,t=Math.max(1,n.step??6),e=Math.max(1,n.rowHeight),i=Math.floor((n.scrollTop-n.listTop)/e),a=Math.ceil(n.viewportHeight/e)+1,l=Math.max(0,i-r);l=Math.floor(l/t)*t;let h=Math.min(n.total,Math.max(i,0)+a+r);return h=Math.min(n.total,Math.ceil(h/t)*t),l>=h&&(l=Math.min(l,Math.max(0,n.total-1)),h=Math.min(n.total,l+Math.max(a,1))),{start:l,end:h,padTop:l*e,padBottom:(n.total-h)*e}}var k=class extends C{constructor(){super(...arguments);this.narrow=!1;this.panel={};this._objects=[];this._stats=null;this._view="overview";this._selectedEntryId=null;this._selectedTaskId=null;this._filterStatus="";this._filterUser=null;this._filterLabel=null;this._savedViews=[];this._activeViewId="";this._unsub=null;this._chartRangeDays=(()=>{try{let t=parseInt(localStorage.getItem(F.chartRange)||"",10);return[7,30,90,365].includes(t)?t:30}catch{return 30}})();this._hideOutliers=(()=>{try{return localStorage.getItem(F.chartHideOutliers)==="1"}catch{return!1}})();this._historyFilter=null;this._budget=null;this._groups={};this._detailStatsData=new Map;this._miniStatsData=new Map;this._features={adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1};this._adminPanelUserIds=[];this._operatorWriteEnabled=!1;this._defaultWarningDays=7;this._actionLoading=!1;this._moreMenuOpen=!1;this._objMenuOpen=!1;this._toastMessage="";this._toastUndo=null;this._toastActionLabel="";this._filtersOpen=!1;this._newMenuOpen=!1;this._gsSetupsCount=0;this._gsAdoptCount=0;this._gsLoaded=!1;this._batteryFleetSetupAvailable=!1;this._staleBundle=!1;this._staleChecked=!1;this._toastTimer=null;this._dismissedSuggestions=new Set;this._overviewTab=(()=>{try{let t=localStorage.getItem(F.overviewTab);return t==="today"||t==="calendar"?t:"dashboard"}catch{return"dashboard"}})();this._activeTab="overview";this._costDurationToggle="both";this._historySearch="";this._sortMode="due_date";this._objectSortMode="alphabetical";this._groupByMode="none";this._objectViewMode="cards";this._objectsTableColumns=ae;this._showArchived=!1;this._bulkMode=!1;this._bulkSelected=new Set;this._virtStart=0;this._virtEnd=0;this._virtRowHeight=53;this._virtTotalRows=0;this._virtScrollAttached=!1;this._virtRaf=0;this._collapsedSections=(()=>{try{return new Set(JSON.parse(localStorage.getItem(F.collapsedSections)||"[]"))}catch{return new Set}})();this._paletteOpen=!1;this._paletteQuery="";this._paletteActive=0;this._templateGalleryOpen=!1;this._templates=[];this._templateCategories={};this._templateBusy=!1;this._statsService=null;this._userService=null;this._dataLoaded=!1;this._lastConnection=null;this._popstateHandler=t=>this._onPopState(t);this._lazyUi=null;this._onVirtualScroll=()=>{this._virtRaf||(this._virtRaf=requestAnimationFrame(()=>{this._virtRaf=0,this._updateVirtualWindow()}))};this._deepLinkHandled=!1;this._paletteKeydown=t=>{if(t.key==="/"&&!t.ctrlKey&&!t.metaKey&&!t.altKey&&!this._paletteOpen){let i=t.composedPath()[0];if(i instanceof HTMLElement&&(i.tagName==="INPUT"||i.tagName==="TEXTAREA"||i.tagName==="SELECT"||i.isContentEditable))return;t.preventDefault(),this._openPalette();return}if(!this._paletteOpen)return;let e=this._paletteResults;if(t.key==="Escape")t.preventDefault(),this._closePalette();else if(t.key==="ArrowDown")t.preventDefault(),this._paletteActive=Math.min(this._paletteActive+1,e.length-1);else if(t.key==="ArrowUp")t.preventDefault(),this._paletteActive=Math.max(this._paletteActive-1,0);else if(t.key==="Enter"){t.preventDefault();let i=e[this._paletteActive];i&&this._selectPaletteResult(i)}};this._onDialogEvent=async()=>{try{await this._loadData()}catch{}};this._onCalendarLlCustom=t=>{let e=t.detail;e?.type==="maintenance-supporter:open-task"&&e.entry_id&&e.task_id&&(t.stopPropagation(),this._showTask(e.entry_id,e.task_id))};this._fullHistory=null;this._onHistoryEntrySaved=async()=>{await this._loadData()}}get _lang(){return this.hass?.language||"en"}get _isOperator(){let t=this.hass?.user;return t?t.is_admin?!1:!(this._operatorWriteEnabled&&this._adminPanelUserIds.includes(t.id)):!0}_ensureLazyUi(){return this._lazyUi||(this._lazyUi=Promise.all([import("/maintenance_supporter_panelfiles/panel-chunks/object-dialog-HNU4YSB4.js"),import("/maintenance_supporter_panelfiles/panel-chunks/task-dialog-FGXLL4GU.js"),import("/maintenance_supporter_panelfiles/panel-chunks/complete-dialog-AN3A2ME6.js"),import("/maintenance_supporter_panelfiles/panel-chunks/qr-dialog-QWUERDTM.js"),import("/maintenance_supporter_panelfiles/panel-chunks/adopt-problem-sensors-dialog-UBDFZUSU.js"),import("/mainte
Line truncated
|
||||
<div class="palette-backdrop" @click=${()=>this._closePalette()}>
|
||||
<div class="palette" @click=${i=>i.stopPropagation()}>
|
||||
<input
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.55.0 */
|
||||
var S="2.55.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.56.0 */
|
||||
var S="2.56.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.56.0 */
|
||||
import{a as d}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-LJXSDCLS.js";import{a as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-I7J3AORE.js";import{a,b as _,c as t,f as l,g as h,i as g,j as n,n as i,p as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C5W5B43R.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 this.hass?.language||"en"}updated(s){s.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,v(this._lang).then(()=>this.requestUpdate()))}async open(){this._open=!0,this._loading=!0,this._error="",this._sensors=[],this._selected=new Set,this._responsible="";try{this._userService?this._userService.updateHass(this.hass):this._userService=new u(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 m=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=${m}
|
||||
@change=${()=>this._toggle(e.entity_id)}
|
||||
/>
|
||||
<div class="row-main">
|
||||
<div class="row-top">
|
||||
<span class="row-name">${e.name}</span>
|
||||
<span class="chip ${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};
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.56.0 */
|
||||
var i=[{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"}],s=i.map(n=>n.key),l=["name","manufacturer","model","serial_number","installation_date","warranty_expiry","area_id","task_count","actions"];function c(n){if(!Array.isArray(n))return[...l];let o=new Set,e=[];for(let a of n)typeof a=="string"&&s.includes(a)&&!o.has(a)&&(o.add(a),e.push(a));return e.length?(e.includes("name")||e.unshift("name"),e):[...l]}function u(n,o,e){let a=new Blob([n],{type:e}),r=URL.createObjectURL(a),t=document.createElement("a");t.href=r,t.download=o,t.target="_blank",t.rel="noopener",t.style.display="none",document.body.appendChild(t),t.dispatchEvent(new MouseEvent("click")),document.body.removeChild(t),setTimeout(()=>URL.revokeObjectURL(r),6e4)}function y(n,o){let e=document.createElement("a");e.href=n,e.download=o,e.target="_blank",e.rel="noopener",e.style.display="none",document.body.appendChild(e),e.dispatchEvent(new MouseEvent("click")),document.body.removeChild(e)}export{i as a,l as b,c,u as d,y as e};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.56.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,2 @@
|
||||
/*! maintenance_supporter frontend 2.56.0 */
|
||||
import{n as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C5W5B43R.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_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,2 @@
|
||||
/*! maintenance_supporter frontend 2.56.0 */
|
||||
var o=["notes","cost","duration","photo","user"],t={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"};export{o as a,t as b};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.56.0 */
|
||||
import{n as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C5W5B43R.js";function _(e){return`${e.entry_id??""}\0${e.part_id}`}function l(e,r,s,c){let t=!!e.entry_id&&e.entry_id!==r,a=t?e.entry_id:r,o=s.find(p=>p.entry_id===a),n=(o?.parts||[]).find(p=>p.id===e.part_id)||null,d=t&&o?.object?.name||"",i=n?.name||u("shared_part_unknown",c);return{part:n,foreign:t,ownerName:d,label:d?`${i} (${d})`:i}}function f(e,r,s,c){let{part:t,label:a}=l(e,r,s,c),o=t&&t.stock!==null&&t.stock!==void 0?` (${t.stock}${t.unit?" "+t.unit:""})`:"",n=t?.storage_location?` \u2014 ${t.storage_location}`:"";return`${e.quantity}\xD7 ${a}${o}${n}`}function g(e,r,s,c){let a=(s.find(n=>n.entry_id===r)?.parts||[]).map(n=>({...n})),o=new Set(a.map(n=>_({part_id:n.id})));for(let n of e?.consumes_parts||[]){if(!n.entry_id||n.entry_id===r)continue;let d=_(n);if(o.has(d))continue;o.add(d);let{part:i,ownerName:p}=l(n,r,s,c);a.push({id:n.part_id,name:i?.name||u("shared_part_unknown",c),unit:i?.unit,stock:i?.stock??null,storage_location:i?.storage_location,entry_id:n.entry_id,owner_name:p})}return a}export{_ as a,f as b,g as c};
|
||||
@@ -0,0 +1,54 @@
|
||||
/*! maintenance_supporter frontend 2.56.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-C5W5B43R.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);
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
/*! maintenance_supporter frontend 2.56.0 */
|
||||
import{b as m}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NGMG4DEY.js";import{a as _}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-SD6IEJBA.js";import{a as g}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-LJXSDCLS.js";import{a as s,b,c as a,f as d,g as v,i as n,j as l,n as r,x as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C5W5B43R.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._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._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._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>
|
||||
<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(m[t]??t,e))).join(" \xB7 "):""}
|
||||
>
|
||||
${this._loading?r("completing",e):r("complete",e)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`}};i.styles=[k,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,"_usedParts",2),s([n({attribute:!1})],i.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",i);export{i as MaintenanceCompleteDialog};
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*! maintenance_supporter frontend 2.56.0 */
|
||||
import"/maintenance_supporter_panelfiles/panel-chunks/chunk-ZK3W7TF6.js";import{a as h}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-LJXSDCLS.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}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C5W5B43R.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 this.hass?.language??navigator.language.split("-")[0]??"en"}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=h(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 MaintenanceObjectDialog};
|
||||
@@ -0,0 +1,213 @@
|
||||
/*! maintenance_supporter frontend 2.56.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-C5W5B43R.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 MaintenanceQrDialog};
|
||||
+1141
File diff suppressed because it is too large.
Load diff
+146
@@ -0,0 +1,146 @@
|
||||
/*! maintenance_supporter frontend 2.56.0 */
|
||||
import{a as g}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-LJXSDCLS.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,p as f}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C5W5B43R.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 this.hass?.language||"en"}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,f(this._lang).then(()=>this.requestUpdate()))}async open(){this._open=!0,this._loading=!0,this._error="",this._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};
|
||||
+1132
File diff suppressed because it is too large.
Load diff
+125
@@ -0,0 +1,125 @@
|
||||
/*! maintenance_supporter frontend 2.56.0 */
|
||||
import{a as v}from"./chunk-XWMJNIQI.js";import{a as u,b as o,d as h,e as b,f as y,g as l,h as g,i as r,k as m,t as p}from"./chunk-TRW3CRLS.js";import{a as n}from"./chunk-UHANDS57.js";var x=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 this.hass?.language||"en"}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load(),m(this._lang).then(()=>this.requestUpdate()))}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/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),a=parseFloat(this._localYearly),i={};!isNaN(t)&&t>=0&&(i.budget_monthly=t),!isNaN(a)&&a>=0&&(i.budget_yearly=a),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,a=this._status;if(!a)return o`<ha-card><div class="loading">${r("loading",t)||"Loading\u2026"}</div></ha-card>`;let i=a.currency_symbol||g,_=a.alert_threshold_pct??x,f=[{label:r("budget_monthly",t)||"Monthly",spent:a.monthly_spent||0,budget:a.monthly_budget||0},{label:r("budget_yearly",t)||"Yearly",spent:a.yearly_spent||0,budget:a.yearly_budget||0}];return o`
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<span class="emoji">💰</span>
|
||||
<span>${this._config.title||r("settings_budget",t)||"Budget"}</span>
|
||||
</div>
|
||||
<span class="currency">${i}</span>
|
||||
</div>
|
||||
|
||||
${this._error?o`<div class="error">${this._error}</div>`:h}
|
||||
|
||||
${f.map(e=>{if(!(e.budget>0))return o`
|
||||
<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>=_?"warning":"ok";return o`
|
||||
<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?o`
|
||||
<div class="inputs-row">
|
||||
<div class="input-field">
|
||||
<label>${r("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>${r("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?r("save",t)||"Save":r("saved",t)||"Saved"}
|
||||
</button>
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${r("budget_advanced",t)||"Currency, alerts\u2026"}
|
||||
</button>
|
||||
</div>
|
||||
`:o`
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${r("budget_open_panel",t)||"Open in panel"}
|
||||
</button>
|
||||
`}
|
||||
</div>
|
||||
</ha-card>
|
||||
`}};s.styles=[v,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([l()],s.prototype,"_config",2),n([l()],s.prototype,"_status",2),n([l()],s.prototype,"_busy",2),n([l()],s.prototype,"_error",2),n([l()],s.prototype,"_localMonthly",2),n([l()],s.prototype,"_localYearly",2),n([l()],s.prototype,"_dirty",2);customElements.get("maintenance-budget-section-card")||customElements.define("maintenance-budget-section-card",s);window.customCards=window.customCards||[];window.customCards.push({type:"maintenance-budget-section-card",name:"Maintenance Supporter \u2014 Budget",description:"Inline monthly + yearly budget editor",preview:!1});export{s as MaintenanceBudgetSectionCard};
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.56.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.56.0 */
|
||||
import{a as r}from"./chunk-TRW3CRLS.js";var a=r`
|
||||
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{a};
|
||||
+2602
File diff suppressed because it is too large.
Load diff
+137
@@ -0,0 +1,137 @@
|
||||
/*! maintenance_supporter frontend 2.56.0 */
|
||||
import{a as m}from"./chunk-XWMJNIQI.js";import{a as u,b as s,d as l,e as h,f as g,g as o,i,k as _,t as p}from"./chunk-TRW3CRLS.js";import{a}from"./chunk-UHANDS57.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?.language||"en"}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(),_(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>`:l}
|
||||
|
||||
${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],v=d.task_refs?.length??0,b=this._editingId===n;return s`
|
||||
<div class="group-row">
|
||||
${b?s`
|
||||
<input class="edit-input" type="text"
|
||||
.value=${this._editingName}
|
||||
?disabled=${this._busy}
|
||||
@input=${c=>{this._editingName=c.target.value}}
|
||||
@keydown=${c=>this._onKeyDown(c,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">${v}</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>
|
||||
`:l}
|
||||
`}
|
||||
</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=[m,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);window.customCards=window.customCards||[];window.customCards.push({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.56.0 */
|
||||
import{a as m}from"./chunk-XWMJNIQI.js";import{a as h,b as n,d as c,e as _,f as v,g as r,i as e,k as f,t as l}from"./chunk-TRW3CRLS.js";import{a as i}from"./chunk-UHANDS57.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 this.hass?.language||"en"}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(),f(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,b=p?e("vacation_status_active",t)||"Active now":d?e("vacation_status_scheduled",t)||"Scheduled":e("vacation_status_inactive",t)||"Inactive",g=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 ${g}">${b}</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=[m,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);window.customCards=window.customCards||[];window.customCards.push({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.55.0 */
|
||||
import{c as y}from"./chunks/chunk-LPNFL3AF.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.56.0 */
|
||||
import{c as y}from"./chunks/chunk-UHANDS57.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-LPNFL3AF.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-UIZAZBZW.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-6U2VKRSH.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-SOUOTT4X.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-P5FL3UNR.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})}catch{m("/maintenance-suppor
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-GKIEFNUX.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-237GPVDV.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-HS2WQGRV.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-W7QTL5QF.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})}catch{m("/maintenance-suppor
Line truncated
|
||||
@@ -22,5 +22,5 @@
|
||||
"requirements": [
|
||||
"pypdf>=4.3.0"
|
||||
],
|
||||
"version": "2.55.0"
|
||||
"version": "2.56.0"
|
||||
}
|
||||
@@ -39,6 +39,12 @@ complete:
|
||||
number:
|
||||
mode: box
|
||||
step: any
|
||||
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.
|
||||
selector:
|
||||
entity:
|
||||
domain: person
|
||||
|
||||
reset:
|
||||
name: Reset Maintenance
|
||||
@@ -310,6 +316,17 @@ update_task:
|
||||
description: List of tags for filtering and reporting.
|
||||
selector:
|
||||
object:
|
||||
responsible_user:
|
||||
name: Responsible user
|
||||
description: Assign the task to this person (must be linked to a Home Assistant user).
|
||||
selector:
|
||||
entity:
|
||||
domain: person
|
||||
clear_responsible_user:
|
||||
name: Clear responsible user
|
||||
description: Remove the current assignment. Cannot be combined with "Responsible user".
|
||||
selector:
|
||||
boolean:
|
||||
|
||||
delete_task:
|
||||
name: Delete Task
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Trigger maintenance when value exceeds this threshold.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers",
|
||||
"trigger_baseline_value": "Start reading (optional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Trigger maintenance when this accumulated value is reached.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Only count transitions from this state. Leave empty for any.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Trigger maintenance after this many hours of accumulated runtime.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Choose how multiple conditions should be combined.",
|
||||
"data": {
|
||||
"compound_logic": "Logic",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = all conditions must trigger. OR = any condition triggers.",
|
||||
@@ -882,7 +888,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Trigger maintenance when value exceeds this threshold.",
|
||||
@@ -902,7 +909,9 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers",
|
||||
"trigger_baseline_value": "Start reading (optional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Trigger maintenance when this accumulated value is reached.",
|
||||
@@ -922,7 +931,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Only count transitions from this state. Leave empty for any.",
|
||||
@@ -942,7 +952,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Trigger maintenance after this many hours of accumulated runtime.",
|
||||
@@ -957,7 +968,8 @@
|
||||
"description": "Choose how multiple conditions should be combined.",
|
||||
"data": {
|
||||
"compound_logic": "Logic",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = all conditions must trigger. OR = any condition triggers."
|
||||
@@ -1440,6 +1452,10 @@
|
||||
"reading_value": {
|
||||
"name": "Reading value",
|
||||
"description": "Recorded value for reading-type tasks (meter reading, level check)."
|
||||
},
|
||||
"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."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1629,6 +1645,14 @@
|
||||
"labels": {
|
||||
"name": "Labels",
|
||||
"description": "List of tags for filtering and reporting."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Responsible user",
|
||||
"description": "Assign the task to this person (must be linked to a Home Assistant user)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Clear responsible user",
|
||||
"description": "Remove the current assignment. Cannot be combined with \"Responsible user\"."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět"
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Spustit údržbu, když hodnota překročí tento práh.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět"
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru",
|
||||
"trigger_baseline_value": "Počáteční hodnota (volitelné)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Spustit údržbu, když je dosaženo této kumulované hodnoty.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět"
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Počítat pouze přechody z tohoto stavu. Nechte prázdné pro libovolný.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět"
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Spustit údržbu po tolika hodinách kumulované doby běhu.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Vyberte, jak mají být kombinovány více podmínek.",
|
||||
"data": {
|
||||
"compound_logic": "Logika",
|
||||
"go_back": "Zpět"
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = všechny podmínky musí být splněny. OR = stačí jedna podmínka.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Vyberte, jak mají být kombinovány více podmínek.",
|
||||
"data": {
|
||||
"compound_logic": "Logika",
|
||||
"go_back": "Zpět"
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = všechny podmínky musí být splněny. OR = stačí jedna podmínka."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět"
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Spustit údržbu, když hodnota překročí tento práh.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět"
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru",
|
||||
"trigger_baseline_value": "Počáteční hodnota (volitelné)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Spustit údržbu, když je dosaženo této kumulované hodnoty.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět"
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Počítat pouze přechody z tohoto stavu. Nechte prázdné pro libovolný.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Bezpečnostní interval",
|
||||
"interval_unit": "Jednotka intervalu",
|
||||
"warning_days": "Dny upozornění před termínem",
|
||||
"go_back": "Zpět"
|
||||
"go_back": "Zpět",
|
||||
"auto_complete_on_recovery": "Automaticky dokončit při zotavení senzoru"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Spustit údržbu po tolika hodinách kumulované doby běhu.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Hodnota odečtu",
|
||||
"description": "Zaznamenaná hodnota pro odečtové úkoly (odečet měřiče, kontrola hladiny)."
|
||||
},
|
||||
"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."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Štítky",
|
||||
"description": "Seznam štítků pro filtrování a přehledy."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Odpovědný uživatel",
|
||||
"description": "Přiřadí úkol této osobě (musí být propojena s uživatelem Home Assistant)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Zrušit přiřazení",
|
||||
"description": "Zruší aktuální přiřazení. Nelze kombinovat s „Odpovědný uživatel“."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage"
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Udløs vedligeholdelse, når værdien overskrider denne tærskel.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage"
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig",
|
||||
"trigger_baseline_value": "Startværdi (valgfrit)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Udløs vedligeholdelse, når denne akkumulerede værdi er nået.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage"
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Tæl kun overgange fra denne tilstand. Lad feltet stå tomt for alle.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage"
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Udløs vedligeholdelse efter så mange timers akkumuleret driftstid.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Vælg hvordan flere betingelser skal kombineres.",
|
||||
"data": {
|
||||
"compound_logic": "Logik",
|
||||
"go_back": "Gå tilbage"
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "OG = alle betingelser skal udløses. ELLER = enhver betingelse udløser.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Vælg hvordan flere betingelser skal kombineres.",
|
||||
"data": {
|
||||
"compound_logic": "Logik",
|
||||
"go_back": "Gå tilbage"
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "OG = alle betingelser skal udløses. ELLER = enhver betingelse udløser."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage"
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Udløs vedligeholdelse, når værdien overskrider denne tærskel.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage"
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig",
|
||||
"trigger_baseline_value": "Startværdi (valgfrit)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Udløs vedligeholdelse, når denne akkumulerede værdi er nået.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage"
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Tæl kun overgange fra denne tilstand. Lad feltet stå tomt for alle.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Sikkerhedsinterval",
|
||||
"interval_unit": "Intervalenhed",
|
||||
"warning_days": "Advarsel i dage før forfald",
|
||||
"go_back": "Gå tilbage"
|
||||
"go_back": "Gå tilbage",
|
||||
"auto_complete_on_recovery": "Fuldfør automatisk når sensoren retter sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Udløs vedligeholdelse efter så mange timers akkumuleret driftstid.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Aflæst værdi",
|
||||
"description": "Registreret værdi for aflæsningsopgaver (måleraflæsning, niveaukontrol)."
|
||||
},
|
||||
"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."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Etiketter",
|
||||
"description": "Liste over etiketter til filtrering og rapportering."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Ansvarlig bruger",
|
||||
"description": "Tildeler opgaven til denne person (skal være knyttet til en Home Assistant-bruger)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Fjern ansvarlig",
|
||||
"description": "Fjerner den aktuelle tildeling. Kan ikke kombineres med \"Ansvarlig bruger\"."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Sicherheitsintervall",
|
||||
"interval_unit": "Intervalleinheit",
|
||||
"warning_days": "Warntage vor Fälligkeit",
|
||||
"go_back": "Zurück"
|
||||
"go_back": "Zurück",
|
||||
"auto_complete_on_recovery": "Bei Sensor-Erholung automatisch abschließen"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Wartung auslösen, wenn der Wert diesen Schwellwert überschreitet.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Sicherheitsintervall",
|
||||
"interval_unit": "Intervalleinheit",
|
||||
"warning_days": "Warntage vor Fälligkeit",
|
||||
"go_back": "Zurück"
|
||||
"go_back": "Zurück",
|
||||
"auto_complete_on_recovery": "Bei Sensor-Erholung automatisch abschließen",
|
||||
"trigger_baseline_value": "Startwert (optional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Wartung auslösen, wenn dieser akkumulierte Wert erreicht ist.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Sicherheitsintervall",
|
||||
"interval_unit": "Intervalleinheit",
|
||||
"warning_days": "Warntage vor Fälligkeit",
|
||||
"go_back": "Zurück"
|
||||
"go_back": "Zurück",
|
||||
"auto_complete_on_recovery": "Bei Sensor-Erholung automatisch abschließen"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Nur Übergänge von diesem Zustand zählen. Leer lassen für alle.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Sicherheitsintervall",
|
||||
"interval_unit": "Intervalleinheit",
|
||||
"warning_days": "Warntage vor Fälligkeit",
|
||||
"go_back": "Zurück"
|
||||
"go_back": "Zurück",
|
||||
"auto_complete_on_recovery": "Bei Sensor-Erholung automatisch abschließen"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Wartung auslösen nach dieser Anzahl akkumulierter Betriebsstunden.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Wählen Sie, wie mehrere Bedingungen kombiniert werden sollen.",
|
||||
"data": {
|
||||
"compound_logic": "Logik",
|
||||
"go_back": "Zurück"
|
||||
"go_back": "Zurück",
|
||||
"auto_complete_on_recovery": "Bei Sensor-Erholung automatisch abschließen"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "UND = alle Bedingungen müssen auslösen. ODER = eine Bedingung genügt.",
|
||||
@@ -906,7 +912,8 @@
|
||||
"interval_days": "Sicherheitsintervall",
|
||||
"interval_unit": "Intervalleinheit",
|
||||
"warning_days": "Warntage vor Fälligkeit",
|
||||
"go_back": "Zurück"
|
||||
"go_back": "Zurück",
|
||||
"auto_complete_on_recovery": "Bei Sensor-Erholung automatisch abschließen"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Wartung auslösen, wenn der Wert diesen Schwellenwert überschreitet.",
|
||||
@@ -926,7 +933,9 @@
|
||||
"interval_days": "Sicherheitsintervall",
|
||||
"interval_unit": "Intervalleinheit",
|
||||
"warning_days": "Warntage vor Fälligkeit",
|
||||
"go_back": "Zurück"
|
||||
"go_back": "Zurück",
|
||||
"auto_complete_on_recovery": "Bei Sensor-Erholung automatisch abschließen",
|
||||
"trigger_baseline_value": "Startwert (optional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Wartung auslösen, wenn dieser kumulierte Wert erreicht ist.",
|
||||
@@ -946,7 +955,8 @@
|
||||
"interval_days": "Sicherheitsintervall",
|
||||
"interval_unit": "Intervalleinheit",
|
||||
"warning_days": "Warntage vor Fälligkeit",
|
||||
"go_back": "Zurück"
|
||||
"go_back": "Zurück",
|
||||
"auto_complete_on_recovery": "Bei Sensor-Erholung automatisch abschließen"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Nur Übergänge von diesem Zustand zählen. Leer lassen für alle.",
|
||||
@@ -966,7 +976,8 @@
|
||||
"interval_days": "Sicherheitsintervall",
|
||||
"interval_unit": "Intervalleinheit",
|
||||
"warning_days": "Warntage vor Fälligkeit",
|
||||
"go_back": "Zurück"
|
||||
"go_back": "Zurück",
|
||||
"auto_complete_on_recovery": "Bei Sensor-Erholung automatisch abschließen"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Wartung auslösen nach dieser Anzahl von Stunden kumulierter Laufzeit.",
|
||||
@@ -981,7 +992,8 @@
|
||||
"description": "Wählen Sie, wie mehrere Bedingungen kombiniert werden sollen.",
|
||||
"data": {
|
||||
"compound_logic": "Logik",
|
||||
"go_back": "Zurück"
|
||||
"go_back": "Zurück",
|
||||
"auto_complete_on_recovery": "Bei Sensor-Erholung automatisch abschließen"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "UND = alle Bedingungen müssen auslösen. ODER = eine Bedingung genügt."
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Ablesewert",
|
||||
"description": "Erfasster Wert für Ablese-Aufgaben (Zählerstand, Füllstandskontrolle)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Erledigt von",
|
||||
"description": "Person, die die Wartung durchgeführt hat (muss mit einem Home-Assistant-Benutzer verknüpft sein). Ohne Angabe wird der auslösende Benutzer erfasst."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Labels",
|
||||
"description": "Liste von Tags für Filterung und Auswertung."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Verantwortlicher Benutzer",
|
||||
"description": "Weist die Aufgabe dieser Person zu (muss mit einem Home-Assistant-Benutzer verknüpft sein)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Zuweisung entfernen",
|
||||
"description": "Entfernt die aktuelle Zuweisung. Nicht mit „Verantwortlicher Benutzer“ kombinierbar."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Trigger maintenance when value exceeds this threshold.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers",
|
||||
"trigger_baseline_value": "Start reading (optional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Trigger maintenance when this accumulated value is reached.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Only count transitions from this state. Leave empty for any.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Trigger maintenance after this many hours of accumulated runtime.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Choose how multiple conditions should be combined.",
|
||||
"data": {
|
||||
"compound_logic": "Logic",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = all conditions must trigger. OR = any condition triggers.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Choose how multiple conditions should be combined.",
|
||||
"data": {
|
||||
"compound_logic": "Logic",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = all conditions must trigger. OR = any condition triggers."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Trigger maintenance when value exceeds this threshold.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers",
|
||||
"trigger_baseline_value": "Start reading (optional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Trigger maintenance when this accumulated value is reached.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Only count transitions from this state. Leave empty for any.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Safety interval",
|
||||
"interval_unit": "Interval unit",
|
||||
"warning_days": "Warning days before due",
|
||||
"go_back": "Go back"
|
||||
"go_back": "Go back",
|
||||
"auto_complete_on_recovery": "Auto-complete when the sensor recovers"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Trigger maintenance after this many hours of accumulated runtime.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Reading value",
|
||||
"description": "Recorded value for reading-type tasks (meter reading, level check)."
|
||||
},
|
||||
"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."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Labels",
|
||||
"description": "List of tags for filtering and reporting."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Responsible user",
|
||||
"description": "Assign the task to this person (must be linked to a Home Assistant user)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Clear responsible user",
|
||||
"description": "Remove the current assignment. Cannot be combined with \"Responsible user\"."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Intervalo de seguridad",
|
||||
"interval_unit": "Unidad de intervalo",
|
||||
"warning_days": "Días de aviso antes del vencimiento",
|
||||
"go_back": "Volver"
|
||||
"go_back": "Volver",
|
||||
"auto_complete_on_recovery": "Completar automáticamente cuando el sensor se recupere"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Activar mantenimiento cuando el valor supere este umbral.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Intervalo de seguridad",
|
||||
"interval_unit": "Unidad de intervalo",
|
||||
"warning_days": "Días de aviso antes del vencimiento",
|
||||
"go_back": "Volver"
|
||||
"go_back": "Volver",
|
||||
"auto_complete_on_recovery": "Completar automáticamente cuando el sensor se recupere",
|
||||
"trigger_baseline_value": "Valor inicial (opcional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Activar mantenimiento cuando se alcance este valor acumulado.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Intervalo de seguridad",
|
||||
"interval_unit": "Unidad de intervalo",
|
||||
"warning_days": "Días de aviso antes del vencimiento",
|
||||
"go_back": "Volver"
|
||||
"go_back": "Volver",
|
||||
"auto_complete_on_recovery": "Completar automáticamente cuando el sensor se recupere"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Contar solo transiciones desde este estado. Dejar vacío para todos.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Intervalo de seguridad",
|
||||
"interval_unit": "Unidad de intervalo",
|
||||
"warning_days": "Días de aviso antes del vencimiento",
|
||||
"go_back": "Volver"
|
||||
"go_back": "Volver",
|
||||
"auto_complete_on_recovery": "Completar automáticamente cuando el sensor se recupere"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Activar mantenimiento después de este número de horas de funcionamiento acumulado.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Elija cómo se deben combinar múltiples condiciones.",
|
||||
"data": {
|
||||
"compound_logic": "Lógica",
|
||||
"go_back": "Volver"
|
||||
"go_back": "Volver",
|
||||
"auto_complete_on_recovery": "Completar automáticamente cuando el sensor se recupere"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "Y = todas las condiciones deben activarse. O = cualquier condición activa.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Elija cómo se deben combinar múltiples condiciones.",
|
||||
"data": {
|
||||
"compound_logic": "Lógica",
|
||||
"go_back": "Volver"
|
||||
"go_back": "Volver",
|
||||
"auto_complete_on_recovery": "Completar automáticamente cuando el sensor se recupere"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "Y = todas las condiciones deben activarse. O = cualquier condición activa."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Intervalo de seguridad",
|
||||
"interval_unit": "Unidad de intervalo",
|
||||
"warning_days": "Días de aviso antes del vencimiento",
|
||||
"go_back": "Volver"
|
||||
"go_back": "Volver",
|
||||
"auto_complete_on_recovery": "Completar automáticamente cuando el sensor se recupere"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Activar mantenimiento cuando el valor exceda este umbral.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Intervalo de seguridad",
|
||||
"interval_unit": "Unidad de intervalo",
|
||||
"warning_days": "Días de aviso antes del vencimiento",
|
||||
"go_back": "Volver"
|
||||
"go_back": "Volver",
|
||||
"auto_complete_on_recovery": "Completar automáticamente cuando el sensor se recupere",
|
||||
"trigger_baseline_value": "Valor inicial (opcional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Activar mantenimiento cuando se alcance este valor acumulado.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Intervalo de seguridad",
|
||||
"interval_unit": "Unidad de intervalo",
|
||||
"warning_days": "Días de aviso antes del vencimiento",
|
||||
"go_back": "Volver"
|
||||
"go_back": "Volver",
|
||||
"auto_complete_on_recovery": "Completar automáticamente cuando el sensor se recupere"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Solo contar transiciones desde este estado. Dejar vacío para cualquiera.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Intervalo de seguridad",
|
||||
"interval_unit": "Unidad de intervalo",
|
||||
"warning_days": "Días de aviso antes del vencimiento",
|
||||
"go_back": "Volver"
|
||||
"go_back": "Volver",
|
||||
"auto_complete_on_recovery": "Completar automáticamente cuando el sensor se recupere"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Activar mantenimiento después de estas horas de tiempo de ejecución acumulado.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Valor de lectura",
|
||||
"description": "Valor registrado para tareas de lectura (lectura de contador, control de nivel)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Completado por",
|
||||
"description": "Persona que realizó el mantenimiento (debe estar vinculada a un usuario de Home Assistant). Si se omite, se registra el usuario que activó la llamada."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Etiquetas",
|
||||
"description": "Lista de etiquetas para filtrado e informes."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Usuario responsable",
|
||||
"description": "Asigna la tarea a esta persona (debe estar vinculada a un usuario de Home Assistant)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Quitar responsable",
|
||||
"description": "Elimina la asignación actual. No se puede combinar con «Usuario responsable»."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Turva-aikaväli",
|
||||
"interval_unit": "Aikavälin yksikkö",
|
||||
"warning_days": "Varoituspäivät ennen eräpäivää",
|
||||
"go_back": "Palaa takaisin"
|
||||
"go_back": "Palaa takaisin",
|
||||
"auto_complete_on_recovery": "Suorita automaattisesti, kun anturi palautuu"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Laukaise huolto, kun arvo ylittää tämän kynnysarvon.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Turva-aikaväli",
|
||||
"interval_unit": "Aikavälin yksikkö",
|
||||
"warning_days": "Varoituspäivät ennen eräpäivää",
|
||||
"go_back": "Palaa takaisin"
|
||||
"go_back": "Palaa takaisin",
|
||||
"auto_complete_on_recovery": "Suorita automaattisesti, kun anturi palautuu",
|
||||
"trigger_baseline_value": "Aloitusarvo (valinnainen)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Laukaise huolto, kun tämä kertynyt arvo saavutetaan.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Turva-aikaväli",
|
||||
"interval_unit": "Aikavälin yksikkö",
|
||||
"warning_days": "Varoituspäivät ennen eräpäivää",
|
||||
"go_back": "Palaa takaisin"
|
||||
"go_back": "Palaa takaisin",
|
||||
"auto_complete_on_recovery": "Suorita automaattisesti, kun anturi palautuu"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Laske vain siirtymät tästä tilasta. Jätä tyhjäksi, jos mikä tahansa käy.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Turva-aikaväli",
|
||||
"interval_unit": "Aikavälin yksikkö",
|
||||
"warning_days": "Varoituspäivät ennen eräpäivää",
|
||||
"go_back": "Palaa takaisin"
|
||||
"go_back": "Palaa takaisin",
|
||||
"auto_complete_on_recovery": "Suorita automaattisesti, kun anturi palautuu"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Laukaise huolto tämän kertyneen käyntiaikatuntimäärän jälkeen.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Valitse, miten useat ehdot yhdistetään.",
|
||||
"data": {
|
||||
"compound_logic": "Logiikka",
|
||||
"go_back": "Palaa takaisin"
|
||||
"go_back": "Palaa takaisin",
|
||||
"auto_complete_on_recovery": "Suorita automaattisesti, kun anturi palautuu"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "JA = kaikkien ehtojen on lauettava. TAI = mikä tahansa ehto laukaisee.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Valitse, miten useat ehdot yhdistetään.",
|
||||
"data": {
|
||||
"compound_logic": "Logiikka",
|
||||
"go_back": "Palaa takaisin"
|
||||
"go_back": "Palaa takaisin",
|
||||
"auto_complete_on_recovery": "Suorita automaattisesti, kun anturi palautuu"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "JA = kaikkien ehtojen on lauettava. TAI = mikä tahansa ehto laukaisee."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Turva-aikaväli",
|
||||
"interval_unit": "Aikavälin yksikkö",
|
||||
"warning_days": "Varoituspäivät ennen eräpäivää",
|
||||
"go_back": "Palaa takaisin"
|
||||
"go_back": "Palaa takaisin",
|
||||
"auto_complete_on_recovery": "Suorita automaattisesti, kun anturi palautuu"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Laukaise huolto, kun arvo ylittää tämän kynnysarvon.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Turva-aikaväli",
|
||||
"interval_unit": "Aikavälin yksikkö",
|
||||
"warning_days": "Varoituspäivät ennen eräpäivää",
|
||||
"go_back": "Palaa takaisin"
|
||||
"go_back": "Palaa takaisin",
|
||||
"auto_complete_on_recovery": "Suorita automaattisesti, kun anturi palautuu",
|
||||
"trigger_baseline_value": "Aloitusarvo (valinnainen)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Laukaise huolto, kun tämä kertynyt arvo saavutetaan.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Turva-aikaväli",
|
||||
"interval_unit": "Aikavälin yksikkö",
|
||||
"warning_days": "Varoituspäivät ennen eräpäivää",
|
||||
"go_back": "Palaa takaisin"
|
||||
"go_back": "Palaa takaisin",
|
||||
"auto_complete_on_recovery": "Suorita automaattisesti, kun anturi palautuu"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Laske vain siirtymät tästä tilasta. Jätä tyhjäksi, jos mikä tahansa käy.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Turva-aikaväli",
|
||||
"interval_unit": "Aikavälin yksikkö",
|
||||
"warning_days": "Varoituspäivät ennen eräpäivää",
|
||||
"go_back": "Palaa takaisin"
|
||||
"go_back": "Palaa takaisin",
|
||||
"auto_complete_on_recovery": "Suorita automaattisesti, kun anturi palautuu"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Laukaise huolto tämän kertyneen käyntiaikatuntimäärän jälkeen.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Lukema",
|
||||
"description": "Kirjattu arvo lukematehtäville (mittarilukema, tason tarkistus)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Suorittaja",
|
||||
"description": "Huollon suorittanut henkilö (on oltava liitetty Home Assistant -käyttäjään). Jos jätetään pois, kirjataan kutsun käynnistänyt käyttäjä."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Tunnisteet",
|
||||
"description": "Luettelo tunnisteista suodatusta ja raportointia varten."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Vastuukäyttäjä",
|
||||
"description": "Määrittää tehtävän tälle henkilölle (on oltava liitetty Home Assistant -käyttäjään)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Poista vastuuhenkilö",
|
||||
"description": "Poistaa nykyisen määrityksen. Ei voi yhdistää kohtaan \"Vastuukäyttäjä\"."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Intervalle de sécurité",
|
||||
"interval_unit": "Unité d'intervalle",
|
||||
"warning_days": "Jours d'avertissement avant échéance",
|
||||
"go_back": "Retour"
|
||||
"go_back": "Retour",
|
||||
"auto_complete_on_recovery": "Terminer automatiquement quand le capteur se rétablit"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Déclencher la maintenance lorsque la valeur dépasse ce seuil.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Intervalle de sécurité",
|
||||
"interval_unit": "Unité d'intervalle",
|
||||
"warning_days": "Jours d'avertissement avant échéance",
|
||||
"go_back": "Retour"
|
||||
"go_back": "Retour",
|
||||
"auto_complete_on_recovery": "Terminer automatiquement quand le capteur se rétablit",
|
||||
"trigger_baseline_value": "Valeur de départ (facultatif)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Déclencher la maintenance lorsque cette valeur accumulée est atteinte.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Intervalle de sécurité",
|
||||
"interval_unit": "Unité d'intervalle",
|
||||
"warning_days": "Jours d'avertissement avant échéance",
|
||||
"go_back": "Retour"
|
||||
"go_back": "Retour",
|
||||
"auto_complete_on_recovery": "Terminer automatiquement quand le capteur se rétablit"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Compter uniquement les transitions depuis cet état. Laissez vide pour tous.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Intervalle de sécurité",
|
||||
"interval_unit": "Unité d'intervalle",
|
||||
"warning_days": "Jours d'avertissement avant échéance",
|
||||
"go_back": "Retour"
|
||||
"go_back": "Retour",
|
||||
"auto_complete_on_recovery": "Terminer automatiquement quand le capteur se rétablit"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Déclencher la maintenance après ce nombre d'heures de fonctionnement cumulé.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Choisissez comment combiner les conditions multiples.",
|
||||
"data": {
|
||||
"compound_logic": "Logique",
|
||||
"go_back": "Retour"
|
||||
"go_back": "Retour",
|
||||
"auto_complete_on_recovery": "Terminer automatiquement quand le capteur se rétablit"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "ET = toutes les conditions doivent se déclencher. OU = n'importe quelle condition déclenche.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Choisissez comment combiner les conditions multiples.",
|
||||
"data": {
|
||||
"compound_logic": "Logique",
|
||||
"go_back": "Retour"
|
||||
"go_back": "Retour",
|
||||
"auto_complete_on_recovery": "Terminer automatiquement quand le capteur se rétablit"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "ET = toutes les conditions doivent se déclencher. OU = n'importe quelle condition déclenche."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Intervalle de sécurité",
|
||||
"interval_unit": "Unité d'intervalle",
|
||||
"warning_days": "Jours d'avertissement avant échéance",
|
||||
"go_back": "Retour"
|
||||
"go_back": "Retour",
|
||||
"auto_complete_on_recovery": "Terminer automatiquement quand le capteur se rétablit"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Déclencher la maintenance lorsque la valeur dépasse ce seuil.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Intervalle de sécurité",
|
||||
"interval_unit": "Unité d'intervalle",
|
||||
"warning_days": "Jours d'avertissement avant échéance",
|
||||
"go_back": "Retour"
|
||||
"go_back": "Retour",
|
||||
"auto_complete_on_recovery": "Terminer automatiquement quand le capteur se rétablit",
|
||||
"trigger_baseline_value": "Valeur de départ (facultatif)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Déclencher la maintenance lorsque cette valeur accumulée est atteinte.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Intervalle de sécurité",
|
||||
"interval_unit": "Unité d'intervalle",
|
||||
"warning_days": "Jours d'avertissement avant échéance",
|
||||
"go_back": "Retour"
|
||||
"go_back": "Retour",
|
||||
"auto_complete_on_recovery": "Terminer automatiquement quand le capteur se rétablit"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Ne compter que les transitions depuis cet état. Laisser vide pour tous.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Intervalle de sécurité",
|
||||
"interval_unit": "Unité d'intervalle",
|
||||
"warning_days": "Jours d'avertissement avant échéance",
|
||||
"go_back": "Retour"
|
||||
"go_back": "Retour",
|
||||
"auto_complete_on_recovery": "Terminer automatiquement quand le capteur se rétablit"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Déclencher la maintenance après ce nombre d'heures de temps de fonctionnement cumulé.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Valeur relevée",
|
||||
"description": "Valeur enregistrée pour les tâches de relevé (relevé de compteur, contrôle de niveau)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Effectué par",
|
||||
"description": "Personne ayant effectué la maintenance (doit être liée à un utilisateur Home Assistant). Si omis, l'utilisateur à l'origine de l'appel est enregistré."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Étiquettes",
|
||||
"description": "Liste d'étiquettes pour le filtrage et les rapports."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Utilisateur responsable",
|
||||
"description": "Attribue la tâche à cette personne (doit être liée à un utilisateur Home Assistant)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Retirer le responsable",
|
||||
"description": "Supprime l'attribution actuelle. Non combinable avec « Utilisateur responsable »."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "सुरक्षा अंतराल",
|
||||
"interval_unit": "अंतराल इकाई",
|
||||
"warning_days": "देय होने से पहले चेतावनी दिन",
|
||||
"go_back": "वापस जाएँ"
|
||||
"go_back": "वापस जाएँ",
|
||||
"auto_complete_on_recovery": "सेंसर ठीक होने पर स्वतः पूर्ण करें"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "मान इस थ्रेशोल्ड से अधिक होने पर रखरखाव ट्रिगर करें।",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "सुरक्षा अंतराल",
|
||||
"interval_unit": "अंतराल इकाई",
|
||||
"warning_days": "देय होने से पहले चेतावनी दिन",
|
||||
"go_back": "वापस जाएँ"
|
||||
"go_back": "वापस जाएँ",
|
||||
"auto_complete_on_recovery": "सेंसर ठीक होने पर स्वतः पूर्ण करें",
|
||||
"trigger_baseline_value": "प्रारंभिक मान (वैकल्पिक)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "यह संचित मान पहुँचने पर रखरखाव ट्रिगर करें।",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "सुरक्षा अंतराल",
|
||||
"interval_unit": "अंतराल इकाई",
|
||||
"warning_days": "देय होने से पहले चेतावनी दिन",
|
||||
"go_back": "वापस जाएँ"
|
||||
"go_back": "वापस जाएँ",
|
||||
"auto_complete_on_recovery": "सेंसर ठीक होने पर स्वतः पूर्ण करें"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "केवल इस स्थिति से संक्रमण गिनें। किसी भी के लिए खाली छोड़ें।",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "सुरक्षा अंतराल",
|
||||
"interval_unit": "अंतराल इकाई",
|
||||
"warning_days": "देय होने से पहले चेतावनी दिन",
|
||||
"go_back": "वापस जाएँ"
|
||||
"go_back": "वापस जाएँ",
|
||||
"auto_complete_on_recovery": "सेंसर ठीक होने पर स्वतः पूर्ण करें"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "इतने घंटे के संचित रनटाइम के बाद रखरखाव ट्रिगर करें।",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "चुनें कि कई शर्तों को कैसे संयोजित किया जाना चाहिए।",
|
||||
"data": {
|
||||
"compound_logic": "तर्क",
|
||||
"go_back": "वापस जाएँ"
|
||||
"go_back": "वापस जाएँ",
|
||||
"auto_complete_on_recovery": "सेंसर ठीक होने पर स्वतः पूर्ण करें"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = सभी शर्तों का ट्रिगर होना आवश्यक है। OR = कोई भी शर्त ट्रिगर करती है।",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "चुनें कि कई शर्तों को कैसे संयोजित किया जाना चाहिए।",
|
||||
"data": {
|
||||
"compound_logic": "तर्क",
|
||||
"go_back": "वापस जाएँ"
|
||||
"go_back": "वापस जाएँ",
|
||||
"auto_complete_on_recovery": "सेंसर ठीक होने पर स्वतः पूर्ण करें"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = सभी शर्तों का ट्रिगर होना आवश्यक है। OR = कोई भी शर्त ट्रिगर करती है।"
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "सुरक्षा अंतराल",
|
||||
"interval_unit": "अंतराल इकाई",
|
||||
"warning_days": "देय होने से पहले चेतावनी दिन",
|
||||
"go_back": "वापस जाएँ"
|
||||
"go_back": "वापस जाएँ",
|
||||
"auto_complete_on_recovery": "सेंसर ठीक होने पर स्वतः पूर्ण करें"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "मान इस थ्रेशोल्ड से अधिक होने पर रखरखाव ट्रिगर करें।",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "सुरक्षा अंतराल",
|
||||
"interval_unit": "अंतराल इकाई",
|
||||
"warning_days": "देय होने से पहले चेतावनी दिन",
|
||||
"go_back": "वापस जाएँ"
|
||||
"go_back": "वापस जाएँ",
|
||||
"auto_complete_on_recovery": "सेंसर ठीक होने पर स्वतः पूर्ण करें",
|
||||
"trigger_baseline_value": "प्रारंभिक मान (वैकल्पिक)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "यह संचित मान पहुँचने पर रखरखाव ट्रिगर करें।",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "सुरक्षा अंतराल",
|
||||
"interval_unit": "अंतराल इकाई",
|
||||
"warning_days": "देय होने से पहले चेतावनी दिन",
|
||||
"go_back": "वापस जाएँ"
|
||||
"go_back": "वापस जाएँ",
|
||||
"auto_complete_on_recovery": "सेंसर ठीक होने पर स्वतः पूर्ण करें"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "केवल इस स्थिति से संक्रमण गिनें। किसी भी के लिए खाली छोड़ें।",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "सुरक्षा अंतराल",
|
||||
"interval_unit": "अंतराल इकाई",
|
||||
"warning_days": "देय होने से पहले चेतावनी दिन",
|
||||
"go_back": "वापस जाएँ"
|
||||
"go_back": "वापस जाएँ",
|
||||
"auto_complete_on_recovery": "सेंसर ठीक होने पर स्वतः पूर्ण करें"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "इतने घंटे के संचित रनटाइम के बाद रखरखाव ट्रिगर करें।",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "रीडिंग मान",
|
||||
"description": "रीडिंग कार्यों के लिए दर्ज मान (मीटर रीडिंग, स्तर जांच)।"
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "द्वारा पूर्ण",
|
||||
"description": "रखरखाव करने वाला व्यक्ति (Home Assistant उपयोगकर्ता से जुड़ा होना चाहिए)। छोड़ने पर कॉल करने वाला उपयोगकर्ता दर्ज होता है।"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "लेबल",
|
||||
"description": "फ़िल्टरिंग और रिपोर्टिंग के लिए टैग की सूची।"
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "जिम्मेदार उपयोगकर्ता",
|
||||
"description": "कार्य इस व्यक्ति को सौंपें (Home Assistant उपयोगकर्ता से जुड़ा होना चाहिए)।"
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "ज़िम्मेदार हटाएँ",
|
||||
"description": "वर्तमान असाइनमेंट हटाता है। \"ज़िम्मेदार उपयोगकर्ता\" के साथ संयोजित नहीं किया जा सकता।"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Biztonsági intervallum",
|
||||
"interval_unit": "Intervallum egysége",
|
||||
"warning_days": "Figyelmeztetési napok az esedékesség előtt",
|
||||
"go_back": "Vissza"
|
||||
"go_back": "Vissza",
|
||||
"auto_complete_on_recovery": "Automatikus elvégzés, ha az érzékelő helyreáll"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "A karbantartás kiváltása, ha az érték túllépi ezt a küszöböt.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Biztonsági intervallum",
|
||||
"interval_unit": "Intervallum egysége",
|
||||
"warning_days": "Figyelmeztetési napok az esedékesség előtt",
|
||||
"go_back": "Vissza"
|
||||
"go_back": "Vissza",
|
||||
"auto_complete_on_recovery": "Automatikus elvégzés, ha az érzékelő helyreáll",
|
||||
"trigger_baseline_value": "Kezdő leolvasás (opcionális)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "A karbantartás kiváltása, amikor ez a felhalmozott érték elérésre kerül.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Biztonsági intervallum",
|
||||
"interval_unit": "Intervallum egysége",
|
||||
"warning_days": "Figyelmeztetési napok az esedékesség előtt",
|
||||
"go_back": "Vissza"
|
||||
"go_back": "Vissza",
|
||||
"auto_complete_on_recovery": "Automatikus elvégzés, ha az érzékelő helyreáll"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Csak az ebből az állapotból induló átmenetek számítanak. Hagyja üresen, ha bármelyik.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Biztonsági intervallum",
|
||||
"interval_unit": "Intervallum egysége",
|
||||
"warning_days": "Figyelmeztetési napok az esedékesség előtt",
|
||||
"go_back": "Vissza"
|
||||
"go_back": "Vissza",
|
||||
"auto_complete_on_recovery": "Automatikus elvégzés, ha az érzékelő helyreáll"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "A karbantartás kiváltása ennyi óra összesített üzemidő után.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Válassza ki, hogyan legyenek a feltételek kombinálva.",
|
||||
"data": {
|
||||
"compound_logic": "Logika",
|
||||
"go_back": "Vissza"
|
||||
"go_back": "Vissza",
|
||||
"auto_complete_on_recovery": "Automatikus elvégzés, ha az érzékelő helyreáll"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "ÉS = minden feltételnek teljesülnie kell. VAGY = bármely feltétel kivált.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Válassza ki, hogyan legyenek a feltételek kombinálva.",
|
||||
"data": {
|
||||
"compound_logic": "Logika",
|
||||
"go_back": "Vissza"
|
||||
"go_back": "Vissza",
|
||||
"auto_complete_on_recovery": "Automatikus elvégzés, ha az érzékelő helyreáll"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "ÉS = minden feltételnek teljesülnie kell. VAGY = bármely feltétel kivált."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Biztonsági intervallum",
|
||||
"interval_unit": "Intervallum egysége",
|
||||
"warning_days": "Figyelmeztetési napok az esedékesség előtt",
|
||||
"go_back": "Vissza"
|
||||
"go_back": "Vissza",
|
||||
"auto_complete_on_recovery": "Automatikus elvégzés, ha az érzékelő helyreáll"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "A karbantartás kiváltása, ha az érték túllépi ezt a küszöböt.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Biztonsági intervallum",
|
||||
"interval_unit": "Intervallum egysége",
|
||||
"warning_days": "Figyelmeztetési napok az esedékesség előtt",
|
||||
"go_back": "Vissza"
|
||||
"go_back": "Vissza",
|
||||
"auto_complete_on_recovery": "Automatikus elvégzés, ha az érzékelő helyreáll",
|
||||
"trigger_baseline_value": "Kezdő leolvasás (opcionális)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "A karbantartás kiváltása, amikor ez a felhalmozott érték elérésre kerül.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Biztonsági intervallum",
|
||||
"interval_unit": "Intervallum egysége",
|
||||
"warning_days": "Figyelmeztetési napok az esedékesség előtt",
|
||||
"go_back": "Vissza"
|
||||
"go_back": "Vissza",
|
||||
"auto_complete_on_recovery": "Automatikus elvégzés, ha az érzékelő helyreáll"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Csak az ebből az állapotból induló átmenetek számítanak. Hagyja üresen, ha bármelyik.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Biztonsági intervallum",
|
||||
"interval_unit": "Intervallum egysége",
|
||||
"warning_days": "Figyelmeztetési napok az esedékesség előtt",
|
||||
"go_back": "Vissza"
|
||||
"go_back": "Vissza",
|
||||
"auto_complete_on_recovery": "Automatikus elvégzés, ha az érzékelő helyreáll"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "A karbantartás kiváltása ennyi óra összesített üzemidő után.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Leolvasott érték",
|
||||
"description": "A leolvasás típusú feladatokhoz rögzített érték (mérőállás, szintellenőrzés)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Elvégezte",
|
||||
"description": "A karbantartást elvégző személy (Home Assistant-felhasználóhoz kell kapcsolódnia). Ha üres, a hívást indító felhasználó kerül rögzítésre."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Címkék",
|
||||
"description": "Címkék listája szűréshez és jelentésekhez."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Felelős felhasználó",
|
||||
"description": "A feladatot ehhez a személyhez rendeli (Home Assistant-felhasználóhoz kell kapcsolódnia)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Felelős törlése",
|
||||
"description": "Eltávolítja a jelenlegi hozzárendelést. Nem kombinálható a „Felelős felhasználó” mezővel."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Intervallo di sicurezza",
|
||||
"interval_unit": "Unità di intervallo",
|
||||
"warning_days": "Giorni di avviso prima della scadenza",
|
||||
"go_back": "Indietro"
|
||||
"go_back": "Indietro",
|
||||
"auto_complete_on_recovery": "Completa automaticamente quando il sensore si ripristina"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Attiva la manutenzione quando il valore supera questa soglia.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Intervallo di sicurezza",
|
||||
"interval_unit": "Unità di intervallo",
|
||||
"warning_days": "Giorni di avviso prima della scadenza",
|
||||
"go_back": "Indietro"
|
||||
"go_back": "Indietro",
|
||||
"auto_complete_on_recovery": "Completa automaticamente quando il sensore si ripristina",
|
||||
"trigger_baseline_value": "Valore iniziale (facoltativo)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Attiva la manutenzione quando questo valore accumulato viene raggiunto.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Intervallo di sicurezza",
|
||||
"interval_unit": "Unità di intervallo",
|
||||
"warning_days": "Giorni di avviso prima della scadenza",
|
||||
"go_back": "Indietro"
|
||||
"go_back": "Indietro",
|
||||
"auto_complete_on_recovery": "Completa automaticamente quando il sensore si ripristina"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Conta solo le transizioni da questo stato. Lasciare vuoto per tutti.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Intervallo di sicurezza",
|
||||
"interval_unit": "Unità di intervallo",
|
||||
"warning_days": "Giorni di avviso prima della scadenza",
|
||||
"go_back": "Indietro"
|
||||
"go_back": "Indietro",
|
||||
"auto_complete_on_recovery": "Completa automaticamente quando il sensore si ripristina"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Attiva la manutenzione dopo questo numero di ore di funzionamento cumulato.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Scegli come combinare più condizioni.",
|
||||
"data": {
|
||||
"compound_logic": "Logica",
|
||||
"go_back": "Indietro"
|
||||
"go_back": "Indietro",
|
||||
"auto_complete_on_recovery": "Completa automaticamente quando il sensore si ripristina"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "E = tutte le condizioni devono attivarsi. O = qualsiasi condizione attiva.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Scegli come combinare più condizioni.",
|
||||
"data": {
|
||||
"compound_logic": "Logica",
|
||||
"go_back": "Indietro"
|
||||
"go_back": "Indietro",
|
||||
"auto_complete_on_recovery": "Completa automaticamente quando il sensore si ripristina"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "E = tutte le condizioni devono attivarsi. O = qualsiasi condizione attiva."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Intervallo di sicurezza",
|
||||
"interval_unit": "Unità di intervallo",
|
||||
"warning_days": "Giorni di avviso prima della scadenza",
|
||||
"go_back": "Indietro"
|
||||
"go_back": "Indietro",
|
||||
"auto_complete_on_recovery": "Completa automaticamente quando il sensore si ripristina"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Attivare la manutenzione quando il valore supera questa soglia.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Intervallo di sicurezza",
|
||||
"interval_unit": "Unità di intervallo",
|
||||
"warning_days": "Giorni di avviso prima della scadenza",
|
||||
"go_back": "Indietro"
|
||||
"go_back": "Indietro",
|
||||
"auto_complete_on_recovery": "Completa automaticamente quando il sensore si ripristina",
|
||||
"trigger_baseline_value": "Valore iniziale (facoltativo)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Attivare la manutenzione quando questo valore accumulato viene raggiunto.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Intervallo di sicurezza",
|
||||
"interval_unit": "Unità di intervallo",
|
||||
"warning_days": "Giorni di avviso prima della scadenza",
|
||||
"go_back": "Indietro"
|
||||
"go_back": "Indietro",
|
||||
"auto_complete_on_recovery": "Completa automaticamente quando il sensore si ripristina"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Contare solo le transizioni da questo stato. Lasciare vuoto per qualsiasi.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Intervallo di sicurezza",
|
||||
"interval_unit": "Unità di intervallo",
|
||||
"warning_days": "Giorni di avviso prima della scadenza",
|
||||
"go_back": "Indietro"
|
||||
"go_back": "Indietro",
|
||||
"auto_complete_on_recovery": "Completa automaticamente quando il sensore si ripristina"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Attivare la manutenzione dopo questo numero di ore di tempo di esecuzione accumulato.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Valore letto",
|
||||
"description": "Valore registrato per attività di lettura (lettura contatore, controllo livello)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Completato da",
|
||||
"description": "Persona che ha eseguito la manutenzione (deve essere collegata a un utente Home Assistant). Se omesso, viene registrato l'utente che ha attivato la chiamata."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Etichette",
|
||||
"description": "Elenco di tag per filtri e report."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Utente responsabile",
|
||||
"description": "Assegna l'attività a questa persona (deve essere collegata a un utente Home Assistant)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Rimuovi responsabile",
|
||||
"description": "Rimuove l'assegnazione attuale. Non combinabile con «Utente responsabile»."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "安全間隔",
|
||||
"interval_unit": "間隔の単位",
|
||||
"warning_days": "期限前の警告日数",
|
||||
"go_back": "戻る"
|
||||
"go_back": "戻る",
|
||||
"auto_complete_on_recovery": "センサー回復時に自動完了"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "値がこのしきい値を超えたときにメンテナンスをトリガーします。",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "安全間隔",
|
||||
"interval_unit": "間隔の単位",
|
||||
"warning_days": "期限前の警告日数",
|
||||
"go_back": "戻る"
|
||||
"go_back": "戻る",
|
||||
"auto_complete_on_recovery": "センサー回復時に自動完了",
|
||||
"trigger_baseline_value": "開始値(任意)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "この累積値に達したときにメンテナンスをトリガーします。",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "安全間隔",
|
||||
"interval_unit": "間隔の単位",
|
||||
"warning_days": "期限前の警告日数",
|
||||
"go_back": "戻る"
|
||||
"go_back": "戻る",
|
||||
"auto_complete_on_recovery": "センサー回復時に自動完了"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "この状態からの遷移のみをカウントします。任意の状態の場合は空欄にします。",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "安全間隔",
|
||||
"interval_unit": "間隔の単位",
|
||||
"warning_days": "期限前の警告日数",
|
||||
"go_back": "戻る"
|
||||
"go_back": "戻る",
|
||||
"auto_complete_on_recovery": "センサー回復時に自動完了"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "累積稼働時間がこの時間数に達したらメンテナンスをトリガーします。",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "複数の条件をどのように組み合わせるかを選択してください。",
|
||||
"data": {
|
||||
"compound_logic": "論理",
|
||||
"go_back": "戻る"
|
||||
"go_back": "戻る",
|
||||
"auto_complete_on_recovery": "センサー回復時に自動完了"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = すべての条件がトリガーされる必要があります。OR = いずれかの条件でトリガーされます。",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "複数の条件をどのように組み合わせるかを選択してください。",
|
||||
"data": {
|
||||
"compound_logic": "論理",
|
||||
"go_back": "戻る"
|
||||
"go_back": "戻る",
|
||||
"auto_complete_on_recovery": "センサー回復時に自動完了"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = すべての条件がトリガーされる必要があります。OR = いずれかの条件でトリガーされます。"
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "安全間隔",
|
||||
"interval_unit": "間隔の単位",
|
||||
"warning_days": "期限前の警告日数",
|
||||
"go_back": "戻る"
|
||||
"go_back": "戻る",
|
||||
"auto_complete_on_recovery": "センサー回復時に自動完了"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "値がこのしきい値を超えたときにメンテナンスをトリガーします。",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "安全間隔",
|
||||
"interval_unit": "間隔の単位",
|
||||
"warning_days": "期限前の警告日数",
|
||||
"go_back": "戻る"
|
||||
"go_back": "戻る",
|
||||
"auto_complete_on_recovery": "センサー回復時に自動完了",
|
||||
"trigger_baseline_value": "開始値(任意)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "この累積値に達したときにメンテナンスをトリガーします。",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "安全間隔",
|
||||
"interval_unit": "間隔の単位",
|
||||
"warning_days": "期限前の警告日数",
|
||||
"go_back": "戻る"
|
||||
"go_back": "戻る",
|
||||
"auto_complete_on_recovery": "センサー回復時に自動完了"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "この状態からの遷移のみをカウントします。任意の状態の場合は空欄にします。",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "安全間隔",
|
||||
"interval_unit": "間隔の単位",
|
||||
"warning_days": "期限前の警告日数",
|
||||
"go_back": "戻る"
|
||||
"go_back": "戻る",
|
||||
"auto_complete_on_recovery": "センサー回復時に自動完了"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "累積稼働時間がこの時間数に達したらメンテナンスをトリガーします。",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "検針値",
|
||||
"description": "検針タスクで記録する値(メーター読み取り、レベル確認)。"
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "実施者",
|
||||
"description": "メンテナンスを実施した人(Home Assistant ユーザーに関連付けられている必要があります)。省略時は呼び出したユーザーが記録されます。"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "ラベル",
|
||||
"description": "フィルタリングとレポート用のタグのリスト。"
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "担当ユーザー",
|
||||
"description": "このタスクをこの人に割り当てます(Home Assistant ユーザーに関連付けられている必要があります)。"
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "担当者をクリア",
|
||||
"description": "現在の割り当てを解除します。「担当ユーザー」と同時には指定できません。"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "안전 주기",
|
||||
"interval_unit": "주기 단위",
|
||||
"warning_days": "기한 전 경고 일수",
|
||||
"go_back": "뒤로 가기"
|
||||
"go_back": "뒤로 가기",
|
||||
"auto_complete_on_recovery": "센서가 정상으로 돌아오면 자동 완료"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "값이 이 임계값을 초과하면 유지보수를 트리거합니다.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "안전 주기",
|
||||
"interval_unit": "주기 단위",
|
||||
"warning_days": "기한 전 경고 일수",
|
||||
"go_back": "뒤로 가기"
|
||||
"go_back": "뒤로 가기",
|
||||
"auto_complete_on_recovery": "센서가 정상으로 돌아오면 자동 완료",
|
||||
"trigger_baseline_value": "시작 값 (선택)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "이 누적 값에 도달하면 유지보수를 트리거합니다.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "안전 주기",
|
||||
"interval_unit": "주기 단위",
|
||||
"warning_days": "기한 전 경고 일수",
|
||||
"go_back": "뒤로 가기"
|
||||
"go_back": "뒤로 가기",
|
||||
"auto_complete_on_recovery": "센서가 정상으로 돌아오면 자동 완료"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "이 상태에서의 전환만 셉니다. 비워 두면 모든 상태가 포함됩니다.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "안전 주기",
|
||||
"interval_unit": "주기 단위",
|
||||
"warning_days": "기한 전 경고 일수",
|
||||
"go_back": "뒤로 가기"
|
||||
"go_back": "뒤로 가기",
|
||||
"auto_complete_on_recovery": "센서가 정상으로 돌아오면 자동 완료"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "누적 가동 시간이 이 시간에 도달하면 유지보수를 트리거합니다.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "여러 조건을 결합하는 방식을 선택하세요.",
|
||||
"data": {
|
||||
"compound_logic": "논리",
|
||||
"go_back": "뒤로 가기"
|
||||
"go_back": "뒤로 가기",
|
||||
"auto_complete_on_recovery": "센서가 정상으로 돌아오면 자동 완료"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = 모든 조건이 트리거되어야 합니다. OR = 어느 한 조건만 트리거되면 됩니다.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "여러 조건을 결합하는 방식을 선택하세요.",
|
||||
"data": {
|
||||
"compound_logic": "논리",
|
||||
"go_back": "뒤로 가기"
|
||||
"go_back": "뒤로 가기",
|
||||
"auto_complete_on_recovery": "센서가 정상으로 돌아오면 자동 완료"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = 모든 조건이 트리거되어야 합니다. OR = 어느 한 조건만 트리거되면 됩니다."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "안전 주기",
|
||||
"interval_unit": "주기 단위",
|
||||
"warning_days": "기한 전 경고 일수",
|
||||
"go_back": "뒤로 가기"
|
||||
"go_back": "뒤로 가기",
|
||||
"auto_complete_on_recovery": "센서가 정상으로 돌아오면 자동 완료"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "값이 이 임계값을 초과하면 유지보수를 트리거합니다.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "안전 주기",
|
||||
"interval_unit": "주기 단위",
|
||||
"warning_days": "기한 전 경고 일수",
|
||||
"go_back": "뒤로 가기"
|
||||
"go_back": "뒤로 가기",
|
||||
"auto_complete_on_recovery": "센서가 정상으로 돌아오면 자동 완료",
|
||||
"trigger_baseline_value": "시작 값 (선택)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "이 누적 값에 도달하면 유지보수를 트리거합니다.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "안전 주기",
|
||||
"interval_unit": "주기 단위",
|
||||
"warning_days": "기한 전 경고 일수",
|
||||
"go_back": "뒤로 가기"
|
||||
"go_back": "뒤로 가기",
|
||||
"auto_complete_on_recovery": "센서가 정상으로 돌아오면 자동 완료"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "이 상태에서의 전환만 셉니다. 비워 두면 모든 상태가 포함됩니다.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "안전 주기",
|
||||
"interval_unit": "주기 단위",
|
||||
"warning_days": "기한 전 경고 일수",
|
||||
"go_back": "뒤로 가기"
|
||||
"go_back": "뒤로 가기",
|
||||
"auto_complete_on_recovery": "센서가 정상으로 돌아오면 자동 완료"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "누적 가동 시간이 이 시간에 도달하면 유지보수를 트리거합니다.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "측정값",
|
||||
"description": "측정형 작업에 기록할 값입니다(계량기 값, 수위 확인 등)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "완료자",
|
||||
"description": "정비를 수행한 사람(Home Assistant 사용자와 연결되어 있어야 함). 생략하면 호출을 실행한 사용자가 기록됩니다."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "라벨",
|
||||
"description": "필터링과 보고에 사용할 태그 목록입니다."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "담당 사용자",
|
||||
"description": "이 사람에게 작업을 할당합니다(Home Assistant 사용자와 연결되어 있어야 함)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "담당자 지우기",
|
||||
"description": "현재 할당을 제거합니다. \"담당 사용자\"와 함께 사용할 수 없습니다."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Sikkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Varseldager før forfall",
|
||||
"go_back": "Gå tilbake"
|
||||
"go_back": "Gå tilbake",
|
||||
"auto_complete_on_recovery": "Fullfør automatisk når sensoren normaliseres"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Utløs vedlikehold når verdien overskrider denne terskelen.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Sikkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Varseldager før forfall",
|
||||
"go_back": "Gå tilbake"
|
||||
"go_back": "Gå tilbake",
|
||||
"auto_complete_on_recovery": "Fullfør automatisk når sensoren normaliseres",
|
||||
"trigger_baseline_value": "Startverdi (valgfritt)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Utløs vedlikehold når denne akkumulerte verdien nås.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Sikkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Varseldager før forfall",
|
||||
"go_back": "Gå tilbake"
|
||||
"go_back": "Gå tilbake",
|
||||
"auto_complete_on_recovery": "Fullfør automatisk når sensoren normaliseres"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Tell bare overganger fra denne tilstanden. La feltet stå tomt for hvilken som helst.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Sikkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Varseldager før forfall",
|
||||
"go_back": "Gå tilbake"
|
||||
"go_back": "Gå tilbake",
|
||||
"auto_complete_on_recovery": "Fullfør automatisk når sensoren normaliseres"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Utløs vedlikehold etter så mange timer akkumulert driftstid.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Velg hvordan flere betingelser skal kombineres.",
|
||||
"data": {
|
||||
"compound_logic": "Logikk",
|
||||
"go_back": "Gå tilbake"
|
||||
"go_back": "Gå tilbake",
|
||||
"auto_complete_on_recovery": "Fullfør automatisk når sensoren normaliseres"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "OG = alle betingelser må utløses. ELLER = en hvilken som helst betingelse utløser.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Velg hvordan flere betingelser skal kombineres.",
|
||||
"data": {
|
||||
"compound_logic": "Logikk",
|
||||
"go_back": "Gå tilbake"
|
||||
"go_back": "Gå tilbake",
|
||||
"auto_complete_on_recovery": "Fullfør automatisk når sensoren normaliseres"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "OG = alle betingelser må utløses. ELLER = en hvilken som helst betingelse utløser."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Sikkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Varseldager før forfall",
|
||||
"go_back": "Gå tilbake"
|
||||
"go_back": "Gå tilbake",
|
||||
"auto_complete_on_recovery": "Fullfør automatisk når sensoren normaliseres"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Utløs vedlikehold når verdien overskrider denne terskelen.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Sikkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Varseldager før forfall",
|
||||
"go_back": "Gå tilbake"
|
||||
"go_back": "Gå tilbake",
|
||||
"auto_complete_on_recovery": "Fullfør automatisk når sensoren normaliseres",
|
||||
"trigger_baseline_value": "Startverdi (valgfritt)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Utløs vedlikehold når denne akkumulerte verdien nås.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Sikkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Varseldager før forfall",
|
||||
"go_back": "Gå tilbake"
|
||||
"go_back": "Gå tilbake",
|
||||
"auto_complete_on_recovery": "Fullfør automatisk når sensoren normaliseres"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Tell bare overganger fra denne tilstanden. La feltet stå tomt for hvilken som helst.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Sikkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Varseldager før forfall",
|
||||
"go_back": "Gå tilbake"
|
||||
"go_back": "Gå tilbake",
|
||||
"auto_complete_on_recovery": "Fullfør automatisk når sensoren normaliseres"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Utløs vedlikehold etter så mange timer akkumulert driftstid.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Avlest verdi",
|
||||
"description": "Registrert verdi for avlesningsoppgaver (måleravlesning, nivåkontroll)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Utført av",
|
||||
"description": "Person som utførte vedlikeholdet (må være knyttet til en Home Assistant-bruker). Hvis utelatt registreres brukeren som utløste kallet."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Etiketter",
|
||||
"description": "Liste over etiketter for filtrering og rapportering."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Ansvarlig bruker",
|
||||
"description": "Tildeler oppgaven til denne personen (må være knyttet til en Home Assistant-bruker)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Fjern ansvarlig",
|
||||
"description": "Fjerner gjeldende tildeling. Kan ikke kombineres med \"Ansvarlig bruker\"."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Veiligheidsinterval",
|
||||
"interval_unit": "Intervaleenheid",
|
||||
"warning_days": "Waarschuwingsdagen voor deadline",
|
||||
"go_back": "Terug"
|
||||
"go_back": "Terug",
|
||||
"auto_complete_on_recovery": "Automatisch voltooien wanneer de sensor herstelt"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Onderhoud activeren wanneer de waarde deze drempel overschrijdt.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Veiligheidsinterval",
|
||||
"interval_unit": "Intervaleenheid",
|
||||
"warning_days": "Waarschuwingsdagen voor deadline",
|
||||
"go_back": "Terug"
|
||||
"go_back": "Terug",
|
||||
"auto_complete_on_recovery": "Automatisch voltooien wanneer de sensor herstelt",
|
||||
"trigger_baseline_value": "Startwaarde (optioneel)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Onderhoud activeren wanneer deze opgetelde waarde bereikt is.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Veiligheidsinterval",
|
||||
"interval_unit": "Intervaleenheid",
|
||||
"warning_days": "Waarschuwingsdagen voor deadline",
|
||||
"go_back": "Terug"
|
||||
"go_back": "Terug",
|
||||
"auto_complete_on_recovery": "Automatisch voltooien wanneer de sensor herstelt"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Alleen overgangen vanaf deze status tellen. Laat leeg voor elke status.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Veiligheidsinterval",
|
||||
"interval_unit": "Intervaleenheid",
|
||||
"warning_days": "Waarschuwingsdagen voor deadline",
|
||||
"go_back": "Terug"
|
||||
"go_back": "Terug",
|
||||
"auto_complete_on_recovery": "Automatisch voltooien wanneer de sensor herstelt"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Onderhoud activeren na dit aantal uren totale looptijd.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Kies hoe meerdere voorwaarden gecombineerd moeten worden.",
|
||||
"data": {
|
||||
"compound_logic": "Logica",
|
||||
"go_back": "Terug"
|
||||
"go_back": "Terug",
|
||||
"auto_complete_on_recovery": "Automatisch voltooien wanneer de sensor herstelt"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "EN = alle voorwaarden moeten activeren. OF = elke voorwaarde activeert.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Kies hoe meerdere voorwaarden gecombineerd moeten worden.",
|
||||
"data": {
|
||||
"compound_logic": "Logica",
|
||||
"go_back": "Terug"
|
||||
"go_back": "Terug",
|
||||
"auto_complete_on_recovery": "Automatisch voltooien wanneer de sensor herstelt"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "EN = alle voorwaarden moeten activeren. OF = elke voorwaarde activeert."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Veiligheidsinterval",
|
||||
"interval_unit": "Intervaleenheid",
|
||||
"warning_days": "Waarschuwingsdagen voor deadline",
|
||||
"go_back": "Terug"
|
||||
"go_back": "Terug",
|
||||
"auto_complete_on_recovery": "Automatisch voltooien wanneer de sensor herstelt"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Onderhoud activeren wanneer de waarde deze drempel overschrijdt.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Veiligheidsinterval",
|
||||
"interval_unit": "Intervaleenheid",
|
||||
"warning_days": "Waarschuwingsdagen voor deadline",
|
||||
"go_back": "Terug"
|
||||
"go_back": "Terug",
|
||||
"auto_complete_on_recovery": "Automatisch voltooien wanneer de sensor herstelt",
|
||||
"trigger_baseline_value": "Startwaarde (optioneel)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Onderhoud activeren wanneer deze gecumuleerde waarde is bereikt.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Veiligheidsinterval",
|
||||
"interval_unit": "Intervaleenheid",
|
||||
"warning_days": "Waarschuwingsdagen voor deadline",
|
||||
"go_back": "Terug"
|
||||
"go_back": "Terug",
|
||||
"auto_complete_on_recovery": "Automatisch voltooien wanneer de sensor herstelt"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Alleen overgangen vanaf deze status tellen. Laat leeg voor alle.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Veiligheidsinterval",
|
||||
"interval_unit": "Intervaleenheid",
|
||||
"warning_days": "Waarschuwingsdagen voor deadline",
|
||||
"go_back": "Terug"
|
||||
"go_back": "Terug",
|
||||
"auto_complete_on_recovery": "Automatisch voltooien wanneer de sensor herstelt"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Onderhoud activeren na dit aantal uren gecumuleerde looptijd.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Meterstand",
|
||||
"description": "Vastgelegde waarde voor aflees-taken (meterstand, niveaucontrole)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Voltooid door",
|
||||
"description": "Persoon die het onderhoud heeft uitgevoerd (moet gekoppeld zijn aan een Home Assistant-gebruiker). Indien weggelaten wordt de aanroepende gebruiker vastgelegd."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Labels",
|
||||
"description": "Lijst met labels voor filteren en rapportage."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Verantwoordelijke gebruiker",
|
||||
"description": "Wijst de taak toe aan deze persoon (moet gekoppeld zijn aan een Home Assistant-gebruiker)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Toewijzing verwijderen",
|
||||
"description": "Verwijdert de huidige toewijzing. Niet te combineren met 'Verantwoordelijke gebruiker'."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Interwał bezpieczeństwa",
|
||||
"interval_unit": "Jednostka interwału",
|
||||
"warning_days": "Dni ostrzeżenia przed terminem",
|
||||
"go_back": "Wróć"
|
||||
"go_back": "Wróć",
|
||||
"auto_complete_on_recovery": "Zakończ automatycznie, gdy czujnik wróci do normy"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Wyzwalaj konserwację, gdy wartość przekroczy ten próg.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Interwał bezpieczeństwa",
|
||||
"interval_unit": "Jednostka interwału",
|
||||
"warning_days": "Dni ostrzeżenia przed terminem",
|
||||
"go_back": "Wróć"
|
||||
"go_back": "Wróć",
|
||||
"auto_complete_on_recovery": "Zakończ automatycznie, gdy czujnik wróci do normy",
|
||||
"trigger_baseline_value": "Wartość początkowa (opcjonalnie)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Wyzwalaj konserwację, gdy ta skumulowana wartość zostanie osiągnięta.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Interwał bezpieczeństwa",
|
||||
"interval_unit": "Jednostka interwału",
|
||||
"warning_days": "Dni ostrzeżenia przed terminem",
|
||||
"go_back": "Wróć"
|
||||
"go_back": "Wróć",
|
||||
"auto_complete_on_recovery": "Zakończ automatycznie, gdy czujnik wróci do normy"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Zliczaj tylko przejścia z tego stanu. Pozostaw puste dla dowolnego.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Interwał bezpieczeństwa",
|
||||
"interval_unit": "Jednostka interwału",
|
||||
"warning_days": "Dni ostrzeżenia przed terminem",
|
||||
"go_back": "Wróć"
|
||||
"go_back": "Wróć",
|
||||
"auto_complete_on_recovery": "Zakończ automatycznie, gdy czujnik wróci do normy"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Wyzwalaj konserwację po tylu godzinach skumulowanego czasu pracy.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Wybierz, w jaki sposób wiele warunków ma być łączonych.",
|
||||
"data": {
|
||||
"compound_logic": "Logika",
|
||||
"go_back": "Wróć"
|
||||
"go_back": "Wróć",
|
||||
"auto_complete_on_recovery": "Zakończ automatycznie, gdy czujnik wróci do normy"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "ORAZ = wszystkie warunki muszą zostać spełnione. LUB = wystarczy jeden warunek.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Wybierz, w jaki sposób wiele warunków ma być łączonych.",
|
||||
"data": {
|
||||
"compound_logic": "Logika",
|
||||
"go_back": "Wróć"
|
||||
"go_back": "Wróć",
|
||||
"auto_complete_on_recovery": "Zakończ automatycznie, gdy czujnik wróci do normy"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "ORAZ = wszystkie warunki muszą zostać spełnione. LUB = wystarczy jeden warunek."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Interwał bezpieczeństwa",
|
||||
"interval_unit": "Jednostka interwału",
|
||||
"warning_days": "Dni ostrzeżenia przed terminem",
|
||||
"go_back": "Wróć"
|
||||
"go_back": "Wróć",
|
||||
"auto_complete_on_recovery": "Zakończ automatycznie, gdy czujnik wróci do normy"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Wyzwalaj konserwację, gdy wartość przekroczy ten próg.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Interwał bezpieczeństwa",
|
||||
"interval_unit": "Jednostka interwału",
|
||||
"warning_days": "Dni ostrzeżenia przed terminem",
|
||||
"go_back": "Wróć"
|
||||
"go_back": "Wróć",
|
||||
"auto_complete_on_recovery": "Zakończ automatycznie, gdy czujnik wróci do normy",
|
||||
"trigger_baseline_value": "Wartość początkowa (opcjonalnie)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Wyzwalaj konserwację, gdy ta skumulowana wartość zostanie osiągnięta.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Interwał bezpieczeństwa",
|
||||
"interval_unit": "Jednostka interwału",
|
||||
"warning_days": "Dni ostrzeżenia przed terminem",
|
||||
"go_back": "Wróć"
|
||||
"go_back": "Wróć",
|
||||
"auto_complete_on_recovery": "Zakończ automatycznie, gdy czujnik wróci do normy"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Zliczaj tylko przejścia z tego stanu. Pozostaw puste dla dowolnego.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Interwał bezpieczeństwa",
|
||||
"interval_unit": "Jednostka interwału",
|
||||
"warning_days": "Dni ostrzeżenia przed terminem",
|
||||
"go_back": "Wróć"
|
||||
"go_back": "Wróć",
|
||||
"auto_complete_on_recovery": "Zakończ automatycznie, gdy czujnik wróci do normy"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Wyzwalaj konserwację po tylu godzinach skumulowanego czasu pracy.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Wartość odczytu",
|
||||
"description": "Zarejestrowana wartość dla zadań odczytu (odczyt licznika, kontrola poziomu)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Wykonane przez",
|
||||
"description": "Osoba, która wykonała konserwację (musi być powiązana z użytkownikiem Home Assistant). W razie pominięcia zapisywany jest użytkownik wywołujący."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Etykiety",
|
||||
"description": "Lista tagów do filtrowania i raportowania."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Użytkownik odpowiedzialny",
|
||||
"description": "Przypisuje zadanie tej osobie (musi być powiązana z użytkownikiem Home Assistant)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Usuń przypisanie",
|
||||
"description": "Usuwa bieżące przypisanie. Nie można łączyć z „Odpowiedzialny użytkownik”."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade do intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor se recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Aciona a manutenção quando o valor ultrapassa este limite.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade do intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor se recuperar",
|
||||
"trigger_baseline_value": "Leitura inicial (opcional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Aciona a manutenção quando este valor acumulado é atingido.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade do intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor se recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Conta apenas transições a partir deste estado. Deixe vazio para qualquer um.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade do intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor se recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Aciona a manutenção após este número de horas de operação acumulada.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Escolha como as múltiplas condições devem ser combinadas.",
|
||||
"data": {
|
||||
"compound_logic": "Lógica",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor se recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "E = todas as condições devem acionar. OU = qualquer condição aciona.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Escolha como as múltiplas condições devem ser combinadas.",
|
||||
"data": {
|
||||
"compound_logic": "Lógica",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor se recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "E = todas as condições devem acionar. OU = qualquer condição aciona."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade do intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor se recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Aciona a manutenção quando o valor ultrapassa este limite.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade do intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor se recuperar",
|
||||
"trigger_baseline_value": "Leitura inicial (opcional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Aciona a manutenção quando este valor acumulado é atingido.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade do intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor se recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Conta apenas transições a partir deste estado. Deixe vazio para qualquer um.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade do intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor se recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Aciona a manutenção após este número de horas de operação acumulada.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Valor da leitura",
|
||||
"description": "Valor registrado para tarefas do tipo leitura (leitura de medidor, verificação de nível)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Concluído por",
|
||||
"description": "Pessoa que realizou a manutenção (deve estar vinculada a um usuário do Home Assistant). Se omitido, o usuário que acionou a chamada é registrado."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Etiquetas",
|
||||
"description": "Lista de tags para filtragem e relatórios."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Usuário responsável",
|
||||
"description": "Atribui a tarefa a esta pessoa (deve estar vinculada a um usuário do Home Assistant)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Remover responsável",
|
||||
"description": "Remove a atribuição atual. Não pode ser combinado com \"Usuário responsável\"."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade de intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Acionar manutenção quando o valor exceder este limiar.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade de intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor recuperar",
|
||||
"trigger_baseline_value": "Valor inicial (opcional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Acionar manutenção quando este valor acumulado for atingido.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade de intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Contar apenas transições a partir deste estado. Deixe vazio para qualquer um.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade de intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Acionar manutenção após estas horas de tempo de execução acumulado.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Escolha como múltiplas condições devem ser combinadas.",
|
||||
"data": {
|
||||
"compound_logic": "Lógica",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = todas as condições devem ser acionadas. OR = qualquer condição aciona.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Escolha como múltiplas condições devem ser combinadas.",
|
||||
"data": {
|
||||
"compound_logic": "Lógica",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = todas as condições devem ser acionadas. OR = qualquer condição aciona."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade de intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Acionar manutenção quando o valor exceder este limiar.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade de intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor recuperar",
|
||||
"trigger_baseline_value": "Valor inicial (opcional)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Acionar manutenção quando este valor acumulado for atingido.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade de intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Contar apenas transições a partir deste estado. Deixe vazio para qualquer um.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Intervalo de segurança",
|
||||
"interval_unit": "Unidade de intervalo",
|
||||
"warning_days": "Dias de aviso antes do vencimento",
|
||||
"go_back": "Voltar"
|
||||
"go_back": "Voltar",
|
||||
"auto_complete_on_recovery": "Concluir automaticamente quando o sensor recuperar"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Acionar manutenção após estas horas de tempo de execução acumulado.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Valor de leitura",
|
||||
"description": "Valor registado para tarefas de leitura (leitura de contador, verificação de nível)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Concluído por",
|
||||
"description": "Pessoa que realizou a manutenção (tem de estar associada a um utilizador do Home Assistant). Se omitido, é registado o utilizador que acionou a chamada."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Etiquetas",
|
||||
"description": "Lista de etiquetas para filtragem e relatórios."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Utilizador responsável",
|
||||
"description": "Atribui a tarefa a esta pessoa (tem de estar associada a um utilizador do Home Assistant)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Remover responsável",
|
||||
"description": "Remove a atribuição atual. Não pode ser combinado com «Utilizador responsável»."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Защитный интервал",
|
||||
"interval_unit": "Единица интервала",
|
||||
"warning_days": "Дней предупреждения до срока",
|
||||
"go_back": "Назад"
|
||||
"go_back": "Назад",
|
||||
"auto_complete_on_recovery": "Автозавершение при восстановлении датчика"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Запускать обслуживание, когда значение превышает этот порог.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Защитный интервал",
|
||||
"interval_unit": "Единица интервала",
|
||||
"warning_days": "Дней предупреждения до срока",
|
||||
"go_back": "Назад"
|
||||
"go_back": "Назад",
|
||||
"auto_complete_on_recovery": "Автозавершение при восстановлении датчика",
|
||||
"trigger_baseline_value": "Начальное значение (необязательно)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Запускать обслуживание при достижении этого накопленного значения.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Защитный интервал",
|
||||
"interval_unit": "Единица интервала",
|
||||
"warning_days": "Дней предупреждения до срока",
|
||||
"go_back": "Назад"
|
||||
"go_back": "Назад",
|
||||
"auto_complete_on_recovery": "Автозавершение при восстановлении датчика"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Учитывать только переходы из этого состояния. Оставьте пустым для любого.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Защитный интервал",
|
||||
"interval_unit": "Единица интервала",
|
||||
"warning_days": "Дней предупреждения до срока",
|
||||
"go_back": "Назад"
|
||||
"go_back": "Назад",
|
||||
"auto_complete_on_recovery": "Автозавершение при восстановлении датчика"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Запускать обслуживание после этого количества часов накопленного времени работы.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Выберите, как должны комбинироваться несколько условий.",
|
||||
"data": {
|
||||
"compound_logic": "Логика",
|
||||
"go_back": "Назад"
|
||||
"go_back": "Назад",
|
||||
"auto_complete_on_recovery": "Автозавершение при восстановлении датчика"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "И = все условия должны сработать. ИЛИ = любое условие срабатывает.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Выберите, как должны комбинироваться несколько условий.",
|
||||
"data": {
|
||||
"compound_logic": "Логика",
|
||||
"go_back": "Назад"
|
||||
"go_back": "Назад",
|
||||
"auto_complete_on_recovery": "Автозавершение при восстановлении датчика"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "И = все условия должны сработать. ИЛИ = любое условие срабатывает."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Защитный интервал",
|
||||
"interval_unit": "Единица интервала",
|
||||
"warning_days": "Дней предупреждения до срока",
|
||||
"go_back": "Назад"
|
||||
"go_back": "Назад",
|
||||
"auto_complete_on_recovery": "Автозавершение при восстановлении датчика"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Запускать обслуживание, когда значение превышает этот порог.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Защитный интервал",
|
||||
"interval_unit": "Единица интервала",
|
||||
"warning_days": "Дней предупреждения до срока",
|
||||
"go_back": "Назад"
|
||||
"go_back": "Назад",
|
||||
"auto_complete_on_recovery": "Автозавершение при восстановлении датчика",
|
||||
"trigger_baseline_value": "Начальное значение (необязательно)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Запускать обслуживание при достижении этого накопленного значения.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Защитный интервал",
|
||||
"interval_unit": "Единица интервала",
|
||||
"warning_days": "Дней предупреждения до срока",
|
||||
"go_back": "Назад"
|
||||
"go_back": "Назад",
|
||||
"auto_complete_on_recovery": "Автозавершение при восстановлении датчика"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Учитывать только переходы из этого состояния. Оставьте пустым для любого.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Защитный интервал",
|
||||
"interval_unit": "Единица интервала",
|
||||
"warning_days": "Дней предупреждения до срока",
|
||||
"go_back": "Назад"
|
||||
"go_back": "Назад",
|
||||
"auto_complete_on_recovery": "Автозавершение при восстановлении датчика"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Запускать обслуживание после этого количества часов накопленного времени работы.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Показание",
|
||||
"description": "Записанное значение для задач снятия показаний (показание счётчика, проверка уровня)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Кем выполнено",
|
||||
"description": "Человек, выполнивший обслуживание (должен быть связан с пользователем Home Assistant). Если не указано, записывается пользователь, вызвавший службу."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Метки",
|
||||
"description": "Список меток для фильтрации и отчётов."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Ответственный пользователь",
|
||||
"description": "Назначает задачу этому человеку (должен быть связан с пользователем Home Assistant)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Снять назначение",
|
||||
"description": "Снимает текущее назначение. Нельзя сочетать с «Ответственный пользователь»."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Säkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Dagar för varning före förfall",
|
||||
"go_back": "Tillbaka"
|
||||
"go_back": "Tillbaka",
|
||||
"auto_complete_on_recovery": "Slutför automatiskt när sensorn återhämtar sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Utlös underhåll när värdet överskrider denna tröskel.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Säkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Dagar för varning före förfall",
|
||||
"go_back": "Tillbaka"
|
||||
"go_back": "Tillbaka",
|
||||
"auto_complete_on_recovery": "Slutför automatiskt när sensorn återhämtar sig",
|
||||
"trigger_baseline_value": "Startvärde (valfritt)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Utlös underhåll när detta ackumulerade värde nås.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Säkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Dagar för varning före förfall",
|
||||
"go_back": "Tillbaka"
|
||||
"go_back": "Tillbaka",
|
||||
"auto_complete_on_recovery": "Slutför automatiskt när sensorn återhämtar sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Räkna endast övergångar från detta tillstånd. Lämna tomt för alla.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Säkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Dagar för varning före förfall",
|
||||
"go_back": "Tillbaka"
|
||||
"go_back": "Tillbaka",
|
||||
"auto_complete_on_recovery": "Slutför automatiskt när sensorn återhämtar sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Utlös underhåll efter så här många timmar ackumulerad körtid.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Välj hur flera villkor ska kombineras.",
|
||||
"data": {
|
||||
"compound_logic": "Logik",
|
||||
"go_back": "Tillbaka"
|
||||
"go_back": "Tillbaka",
|
||||
"auto_complete_on_recovery": "Slutför automatiskt när sensorn återhämtar sig"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = alla villkor måste utlösa. OR = vilket som helst villkor utlöser.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Välj hur flera villkor ska kombineras.",
|
||||
"data": {
|
||||
"compound_logic": "Logik",
|
||||
"go_back": "Tillbaka"
|
||||
"go_back": "Tillbaka",
|
||||
"auto_complete_on_recovery": "Slutför automatiskt när sensorn återhämtar sig"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "AND = alla villkor måste utlösa. OR = vilket som helst villkor utlöser."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Säkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Dagar för varning före förfall",
|
||||
"go_back": "Tillbaka"
|
||||
"go_back": "Tillbaka",
|
||||
"auto_complete_on_recovery": "Slutför automatiskt när sensorn återhämtar sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Utlös underhåll när värdet överskrider denna tröskel.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Säkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Dagar för varning före förfall",
|
||||
"go_back": "Tillbaka"
|
||||
"go_back": "Tillbaka",
|
||||
"auto_complete_on_recovery": "Slutför automatiskt när sensorn återhämtar sig",
|
||||
"trigger_baseline_value": "Startvärde (valfritt)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Utlös underhåll när detta ackumulerade värde nås.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Säkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Dagar för varning före förfall",
|
||||
"go_back": "Tillbaka"
|
||||
"go_back": "Tillbaka",
|
||||
"auto_complete_on_recovery": "Slutför automatiskt när sensorn återhämtar sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Räkna endast övergångar från detta tillstånd. Lämna tomt för alla.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Säkerhetsintervall",
|
||||
"interval_unit": "Intervallenhet",
|
||||
"warning_days": "Dagar för varning före förfall",
|
||||
"go_back": "Tillbaka"
|
||||
"go_back": "Tillbaka",
|
||||
"auto_complete_on_recovery": "Slutför automatiskt när sensorn återhämtar sig"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Utlös underhåll efter så här många timmar ackumulerad körtid.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Avläst värde",
|
||||
"description": "Registrerat värde för avläsningsuppgifter (mätaravläsning, nivåkontroll)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Slutförd av",
|
||||
"description": "Person som utförde underhållet (måste vara kopplad till en Home Assistant-användare). Om utelämnad registreras användaren som utlöste anropet."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Etiketter",
|
||||
"description": "Lista med etiketter för filtrering och rapportering."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Ansvarig användare",
|
||||
"description": "Tilldelar uppgiften till denna person (måste vara kopplad till en Home Assistant-användare)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Ta bort ansvarig",
|
||||
"description": "Tar bort den aktuella tilldelningen. Kan inte kombineras med \"Ansvarig användare\"."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -230,7 +230,8 @@
|
||||
"interval_days": "Güvenlik aralığı",
|
||||
"interval_unit": "Aralık birimi",
|
||||
"warning_days": "Vadeden önce uyarı günleri",
|
||||
"go_back": "Geri dön"
|
||||
"go_back": "Geri dön",
|
||||
"auto_complete_on_recovery": "Sensör düzelince otomatik tamamla"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Değer bu eşiği aştığında bakımı tetikle.",
|
||||
@@ -251,7 +252,9 @@
|
||||
"interval_days": "Güvenlik aralığı",
|
||||
"interval_unit": "Aralık birimi",
|
||||
"warning_days": "Vadeden önce uyarı günleri",
|
||||
"go_back": "Geri dön"
|
||||
"go_back": "Geri dön",
|
||||
"auto_complete_on_recovery": "Sensör düzelince otomatik tamamla",
|
||||
"trigger_baseline_value": "Başlangıç okuması (isteğe bağlı)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Bu birikmiş değere ulaşıldığında bakımı tetikle.",
|
||||
@@ -272,7 +275,8 @@
|
||||
"interval_days": "Güvenlik aralığı",
|
||||
"interval_unit": "Aralık birimi",
|
||||
"warning_days": "Vadeden önce uyarı günleri",
|
||||
"go_back": "Geri dön"
|
||||
"go_back": "Geri dön",
|
||||
"auto_complete_on_recovery": "Sensör düzelince otomatik tamamla"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Yalnızca bu durumdan yapılan geçişleri say. Herhangi biri için boş bırakın.",
|
||||
@@ -293,7 +297,8 @@
|
||||
"interval_days": "Güvenlik aralığı",
|
||||
"interval_unit": "Aralık birimi",
|
||||
"warning_days": "Vadeden önce uyarı günleri",
|
||||
"go_back": "Geri dön"
|
||||
"go_back": "Geri dön",
|
||||
"auto_complete_on_recovery": "Sensör düzelince otomatik tamamla"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Bu kadar saat birikmiş çalışma süresinden sonra bakımı tetikle.",
|
||||
@@ -309,7 +314,8 @@
|
||||
"description": "Birden çok koşulun nasıl birleştirileceğini seçin.",
|
||||
"data": {
|
||||
"compound_logic": "Mantık",
|
||||
"go_back": "Geri dön"
|
||||
"go_back": "Geri dön",
|
||||
"auto_complete_on_recovery": "Sensör düzelince otomatik tamamla"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "VE = tüm koşullar tetiklenmelidir. VEYA = herhangi bir koşul tetikler.",
|
||||
@@ -720,7 +726,8 @@
|
||||
"description": "Birden çok koşulun nasıl birleştirileceğini seçin.",
|
||||
"data": {
|
||||
"compound_logic": "Mantık",
|
||||
"go_back": "Geri dön"
|
||||
"go_back": "Geri dön",
|
||||
"auto_complete_on_recovery": "Sensör düzelince otomatik tamamla"
|
||||
},
|
||||
"data_description": {
|
||||
"compound_logic": "VE = tüm koşullar tetiklenmelidir. VEYA = herhangi bir koşul tetikler."
|
||||
@@ -999,7 +1006,8 @@
|
||||
"interval_days": "Güvenlik aralığı",
|
||||
"interval_unit": "Aralık birimi",
|
||||
"warning_days": "Vadeden önce uyarı günleri",
|
||||
"go_back": "Geri dön"
|
||||
"go_back": "Geri dön",
|
||||
"auto_complete_on_recovery": "Sensör düzelince otomatik tamamla"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_above": "Değer bu eşiği aştığında bakımı tetikle.",
|
||||
@@ -1019,7 +1027,9 @@
|
||||
"interval_days": "Güvenlik aralığı",
|
||||
"interval_unit": "Aralık birimi",
|
||||
"warning_days": "Vadeden önce uyarı günleri",
|
||||
"go_back": "Geri dön"
|
||||
"go_back": "Geri dön",
|
||||
"auto_complete_on_recovery": "Sensör düzelince otomatik tamamla",
|
||||
"trigger_baseline_value": "Başlangıç okuması (isteğe bağlı)"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_target_value": "Bu birikmiş değere ulaşıldığında bakımı tetikle.",
|
||||
@@ -1039,7 +1049,8 @@
|
||||
"interval_days": "Güvenlik aralığı",
|
||||
"interval_unit": "Aralık birimi",
|
||||
"warning_days": "Vadeden önce uyarı günleri",
|
||||
"go_back": "Geri dön"
|
||||
"go_back": "Geri dön",
|
||||
"auto_complete_on_recovery": "Sensör düzelince otomatik tamamla"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_from_state": "Yalnızca bu durumdan yapılan geçişleri say. Herhangi biri için boş bırakın.",
|
||||
@@ -1059,7 +1070,8 @@
|
||||
"interval_days": "Güvenlik aralığı",
|
||||
"interval_unit": "Aralık birimi",
|
||||
"warning_days": "Vadeden önce uyarı günleri",
|
||||
"go_back": "Geri dön"
|
||||
"go_back": "Geri dön",
|
||||
"auto_complete_on_recovery": "Sensör düzelince otomatik tamamla"
|
||||
},
|
||||
"data_description": {
|
||||
"trigger_runtime_hours": "Bu kadar saat birikmiş çalışma süresinden sonra bakımı tetikle.",
|
||||
@@ -1500,6 +1512,10 @@
|
||||
"reading_value": {
|
||||
"name": "Okuma değeri",
|
||||
"description": "Okuma türü görevler için kaydedilen değer (sayaç okuması, seviye kontrolü)."
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "Tamamlayan",
|
||||
"description": "Bakımı yapan kişi (bir Home Assistant kullanıcısına bağlı olmalıdır). Belirtilmezse çağrıyı tetikleyen kullanıcı kaydedilir."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1689,6 +1705,14 @@
|
||||
"labels": {
|
||||
"name": "Etiketler",
|
||||
"description": "Filtreleme ve raporlama için etiket listesi."
|
||||
},
|
||||
"responsible_user": {
|
||||
"name": "Sorumlu kullanıcı",
|
||||
"description": "Görevi bu kişiye atar (bir Home Assistant kullanıcısına bağlı olmalıdır)."
|
||||
},
|
||||
"clear_responsible_user": {
|
||||
"name": "Sorumluyu Kaldır",
|
||||
"description": "Mevcut atamayı kaldırır. \"Sorumlu kullanıcı\" ile birlikte kullanılamaz."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Loaded 100 of 158 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user