148 files
This commit is contained in:
@@ -206,7 +206,7 @@
|
||||
},
|
||||
{
|
||||
"id": "d3c3e144a91247ce8ac524814737d7f8",
|
||||
"url": "/hacsfiles/lovelace-wallpanel/wallpanel.js?hacstag=3095064164670",
|
||||
"url": "/hacsfiles/lovelace-wallpanel/wallpanel.js?hacstag=3095064164671",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
@@ -261,7 +261,7 @@
|
||||
},
|
||||
{
|
||||
"id": "6c3f7d87683d4473b5dc8fe8177535f6",
|
||||
"url": "/hacsfiles/simple-thermostat/simple-thermostat.js?hacstag=1230152807440",
|
||||
"url": "/hacsfiles/simple-thermostat/simple-thermostat.js?hacstag=1230152807450",
|
||||
"type": "module"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# Brand assets
|
||||
|
||||
Home Assistant serves these. Since **2026.3** a custom integration ships its own brand images in a `brand/` folder inside the integration, and HA exposes them at `/api/brands/integration/cafe/`, taking priority over the brands CDN. The central [home-assistant/brands](https://github.com/home-assistant/brands) repository no longer accepts custom integrations, so there is nothing to submit anywhere — the files here are the whole story. See the [Brands Proxy API announcement](https://developers.home-assistant.io/blog/2026/02/24/brands-proxy-api/).
|
||||
|
||||
On Home Assistant older than 2026.3 the integration shows the generic puzzle-piece icon. Nothing breaks.
|
||||
|
||||
| File | Size | Used for |
|
||||
| --- | --- | --- |
|
||||
| `icon.png` | 256×256 | The integration tile, the device page, the "add integration" list |
|
||||
| `icon@2x.png` | 512×512 | The same, on a retina display |
|
||||
| `logo.png` | ≤256 tall | The wordmark, shown in the config flow header |
|
||||
| `logo@2x.png` | ≤512 tall | The same, on a retina display |
|
||||
| `dark_logo.png` / `dark_logo@2x.png` | as above | The logo on a dark theme |
|
||||
|
||||
The icon's tile is self-contained — a roast-brown squircle with the bean on it — so it reads the same on light and dark themes and there is no `dark_icon.png` to keep in sync. The logo is a bare glyph and a wordmark with no background of their own, which is exactly why the dark variant exists.
|
||||
|
||||
The wordmark is drawn by the generator rather than set in a typeface, so there are no glyph outlines in here that someone else owns and no font to install before regenerating.
|
||||
|
||||
## Regenerating
|
||||
|
||||
Every SVG in here is generated, not hand-edited. Change `tools/make_icon.py` and re-run it; it writes all three, renders the PNGs beside them, and copies the icon to `packages/frontend/public/icon.svg`, which is the panel's favicon.
|
||||
|
||||
```sh
|
||||
python3 tools/make_icon.py
|
||||
```
|
||||
|
||||
Needs `rsvg-convert` (`brew install librsvg`). Use it rather than Chromium or Inkscape — librsvg is what Home Assistant's own tooling uses, and the three disagree about filters.
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"domain": "cafe",
|
||||
"name": "C.A.F.E.",
|
||||
"version": "0.9.0",
|
||||
"version": "0.10.0",
|
||||
"codeowners": [],
|
||||
"config_flow": true,
|
||||
"dependencies": ["frontend", "http"],
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -494,6 +494,14 @@ async def _async_setup_shared(hass: HomeAssistant) -> bool:
|
||||
await reference_numbers.async_load()
|
||||
hass.data[DOMAIN][REFERENCE_NUMBERS_KEY] = reference_numbers
|
||||
|
||||
# Calendar-entity schedules (#187): the pure schedule engine reads a
|
||||
# calendar's event dates through this provider; the coordinators keep
|
||||
# the shared cache behind it warm. Removed again on the last unload.
|
||||
from .helpers.calendar_source import calendar_occurrence_provider
|
||||
from .helpers.schedule import set_calendar_occurrence_provider
|
||||
|
||||
set_calendar_occurrence_provider(calendar_occurrence_provider(hass))
|
||||
|
||||
|
||||
# Authenticated upload + serve endpoints for document blobs (the blobs live
|
||||
# under /config, so they must never be exposed via an unauthenticated path).
|
||||
@@ -2047,6 +2055,9 @@ async def async_unload_entry(hass: HomeAssistant, entry: MaintenanceSupporterCon
|
||||
text_index.cancel()
|
||||
for unsub in hass.data.get(DOMAIN, {}).get(EVENT_UNSUBS_KEY, []):
|
||||
unsub()
|
||||
from .helpers.schedule import set_calendar_occurrence_provider
|
||||
|
||||
set_calendar_occurrence_provider(None)
|
||||
hass.data.pop(DOMAIN, None)
|
||||
|
||||
return unload_ok
|
||||
|
||||
@@ -498,6 +498,11 @@ def _recurrence_text(task: MaintenanceTask, lang: str) -> str:
|
||||
"""
|
||||
raw = task.schedule_raw if isinstance(task.schedule_raw, dict) else None
|
||||
kind = raw.get("kind") if raw else None
|
||||
if raw is not None and kind == "calendar":
|
||||
# #187: driven by another calendar entity — name it (no hass here for
|
||||
# the friendly name; the entity_id is what the user configured).
|
||||
eid = raw.get("entity_id")
|
||||
return eid if isinstance(eid, str) else ""
|
||||
if raw is not None and kind in ("weekdays", "nth_weekday", "day_of_month"):
|
||||
loc = lang or "en"
|
||||
try:
|
||||
|
||||
@@ -19,6 +19,7 @@ from .const import (
|
||||
from .helpers.dates import INTERVAL_UNITS
|
||||
from .helpers.entity_analyzer import EntityAnalyzer
|
||||
from .helpers.schedule import (
|
||||
KIND_CALENDAR,
|
||||
KIND_DAY_OF_MONTH,
|
||||
KIND_NTH_WEEKDAY,
|
||||
KIND_WEEKDAYS,
|
||||
@@ -28,10 +29,11 @@ from .helpers.threshold_calculator import ThresholdCalculator, ThresholdSuggesti
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# Calendar recurrence kinds offered in the config + options flows (Phase 4).
|
||||
# Hardcoded English labels for the weekday/occurrence sub-options keep the
|
||||
# config-flow i18n surface small; the kind names are translated via strings.json.
|
||||
CALENDAR_KIND_VALUES = (KIND_WEEKDAYS, KIND_NTH_WEEKDAY, KIND_DAY_OF_MONTH)
|
||||
# Calendar recurrence kinds offered in the config + options flows (Phase 4;
|
||||
# the calendar-entity kind since #187). Hardcoded English labels for the
|
||||
# weekday/occurrence sub-options keep the config-flow i18n surface small; the
|
||||
# kind names are translated via strings.json.
|
||||
CALENDAR_KIND_VALUES = (KIND_WEEKDAYS, KIND_NTH_WEEKDAY, KIND_DAY_OF_MONTH, KIND_CALENDAR)
|
||||
# #168: every kind that produces a due DATE takes a time of day — the
|
||||
# interval, the three calendar kinds and a one-off. Sensor-based and
|
||||
# manual tasks have no due date to refine. Mirrors SCHEDULE_TIME_KINDS in
|
||||
@@ -92,6 +94,12 @@ def calendar_schema(kind: str, current: dict[str, Any] | None = None) -> vol.Sch
|
||||
# "business" rolls a weekend date back to Friday.
|
||||
fields[vol.Optional("last_day", default=cur.get("last_day", False))] = selector.BooleanSelector()
|
||||
fields[vol.Optional("business", default=cur.get("business", False))] = selector.BooleanSelector()
|
||||
elif kind == KIND_CALENDAR:
|
||||
# #187: the HA calendar whose events are the occurrences. No default
|
||||
# when the task has none yet — an empty string would fail the entity
|
||||
# selector's own validation on submit.
|
||||
entity_key = vol.Required("entity_id", default=cur["entity_id"]) if cur.get("entity_id") else vol.Required("entity_id")
|
||||
fields[entity_key] = selector.EntitySelector(selector.EntitySelectorConfig(domain="calendar"))
|
||||
# (#83) ±N-day shift of the computed occurrence, on every calendar kind
|
||||
# ("two days before the last working day" = last_day + business + offset -2).
|
||||
fields[vol.Optional("offset", default=cur.get("offset", 0))] = selector.NumberSelector(
|
||||
@@ -127,6 +135,11 @@ def schedule_from_calendar_input(kind: str, user_input: dict[str, Any]) -> dict[
|
||||
if user_input.get("business"):
|
||||
schedule["business"] = True
|
||||
return _with_offset(schedule)
|
||||
if kind == KIND_CALENDAR:
|
||||
entity_id = user_input.get("entity_id")
|
||||
if not isinstance(entity_id, str) or not entity_id.startswith("calendar."):
|
||||
return None
|
||||
return _with_offset({"kind": KIND_CALENDAR, "entity_id": entity_id})
|
||||
return None
|
||||
|
||||
|
||||
@@ -142,6 +155,7 @@ def calendar_current(task: dict[str, Any]) -> dict[str, Any]:
|
||||
"last_day": s.day == -1,
|
||||
"business": s.business,
|
||||
"offset": s.offset_days,
|
||||
"entity_id": s.entity_id,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ from .const import (
|
||||
CONF_TASK_NAME,
|
||||
CONF_TASK_NFC_TAG,
|
||||
CONF_TASK_NOTES,
|
||||
CONF_TASK_NOTIFY_ICON,
|
||||
CONF_TASK_PRIORITY,
|
||||
CONF_TASK_READING_UNIT,
|
||||
CONF_TASK_ROTATION_STRATEGY,
|
||||
@@ -164,6 +165,15 @@ class TaskCrudMixin:
|
||||
if dup_warn:
|
||||
errors[CONF_TASK_NFC_TAG] = "nfc_tag_duplicate"
|
||||
|
||||
# #185: per-task notification icon — "" clears the override, a
|
||||
# malformed value is refused (same rule as the WS write paths).
|
||||
notify_icon_val = (user_input.get(CONF_TASK_NOTIFY_ICON) or "").strip()
|
||||
if notify_icon_val:
|
||||
from .helpers.notify_icons import is_valid_icon
|
||||
|
||||
if not is_valid_icon(notify_icon_val):
|
||||
errors[CONF_TASK_NOTIFY_ICON] = "invalid_notify_icon"
|
||||
|
||||
if not errors:
|
||||
new_data = dict(self.config_entry.data)
|
||||
new_tasks = dict(new_data.get(CONF_TASKS, {}))
|
||||
@@ -260,6 +270,10 @@ class TaskCrudMixin:
|
||||
updated_task[CONF_TASK_ICON] = icon_val
|
||||
else:
|
||||
updated_task.pop(CONF_TASK_ICON, None)
|
||||
if notify_icon_val:
|
||||
updated_task[CONF_TASK_NOTIFY_ICON] = notify_icon_val
|
||||
else:
|
||||
updated_task.pop(CONF_TASK_NOTIFY_ICON, None)
|
||||
if nfc_val:
|
||||
updated_task[CONF_TASK_NFC_TAG] = nfc_val
|
||||
else:
|
||||
@@ -329,6 +343,12 @@ class TaskCrudMixin:
|
||||
if task.get(CONF_TASK_ICON)
|
||||
else vol.Optional(CONF_TASK_ICON)
|
||||
)
|
||||
# #185: push-notification icon override (empty = the type's default).
|
||||
notify_icon_key = (
|
||||
vol.Optional(CONF_TASK_NOTIFY_ICON, default=task.get(CONF_TASK_NOTIFY_ICON))
|
||||
if task.get(CONF_TASK_NOTIFY_ICON)
|
||||
else vol.Optional(CONF_TASK_NOTIFY_ICON)
|
||||
)
|
||||
nfc_tag_key = (
|
||||
vol.Optional(CONF_TASK_NFC_TAG, default=task.get(CONF_TASK_NFC_TAG))
|
||||
if task.get(CONF_TASK_NFC_TAG)
|
||||
@@ -500,6 +520,7 @@ class TaskCrudMixin:
|
||||
else dict[Any, Any]()
|
||||
),
|
||||
icon_key: selector.IconSelector(),
|
||||
notify_icon_key: selector.IconSelector(),
|
||||
vol.Optional(CONF_TASK_PRIORITY, default=task.get(CONF_TASK_PRIORITY, "normal")): selector.SelectSelector(
|
||||
selector.SelectSelectorConfig(
|
||||
options=list(TASK_PRIORITIES),
|
||||
|
||||
@@ -468,6 +468,10 @@ CONF_TASK_ENDS_UNTIL = "ends_until"
|
||||
CONF_TASK_NOTES = "notes"
|
||||
CONF_TASK_DOCUMENTATION_URL = "documentation_url"
|
||||
CONF_TASK_ICON = "custom_icon"
|
||||
# #185: per-task override of the push-notification icon (``mdi:…``); absent =
|
||||
# the maintenance type's default (helpers/notify_icons.py).
|
||||
CONF_TASK_NOTIFY_ICON = "notify_icon"
|
||||
MAX_NOTIFY_ICON_LENGTH = 64
|
||||
CONF_TASK_NFC_TAG = "nfc_tag_id"
|
||||
# v2.20 (#83): display unit for `reading`-type tasks ("kWh", "m³", ...).
|
||||
CONF_TASK_READING_UNIT = "reading_unit"
|
||||
|
||||
@@ -124,6 +124,9 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
|
||||
# Trigger completion cooldown tracking
|
||||
self._recently_completed: dict[str, float] = {} # task_id -> monotonic timestamp
|
||||
# #187: set by async_refresh_now so the next refresh refetches this
|
||||
# object's calendar entities regardless of the cache age.
|
||||
self._calendar_refresh_forced = False
|
||||
# Which of those cooldowns came from a COMPLETION (not a skip/reset):
|
||||
# only those require the sensor to recover before a re-activation
|
||||
# counts as a new edge (bug audit 2026-09-12).
|
||||
@@ -174,6 +177,31 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
obj_data.get("name"),
|
||||
)
|
||||
|
||||
async def _async_prefetch_calendar_occurrences(self) -> None:
|
||||
"""#187: warm the shared calendar-entity event cache BEFORE statuses.
|
||||
|
||||
A ``calendar``-kind task's next due is the first event after its last
|
||||
completion, and the schedule engine reads those dates synchronously
|
||||
through the provider installed at shared setup. Every object's tasks
|
||||
are collected (the cache is process-wide), stale entries refetched;
|
||||
this object's own calendars are refetched unconditionally after a
|
||||
user action (``async_refresh_now``), so a completion on pickup day
|
||||
shows the next pickup right away.
|
||||
"""
|
||||
from .helpers.calendar_source import (
|
||||
all_calendar_entity_ids,
|
||||
async_refresh_calendar_occurrences,
|
||||
calendar_entity_ids,
|
||||
)
|
||||
|
||||
forced = self._calendar_refresh_forced
|
||||
self._calendar_refresh_forced = False
|
||||
entity_ids = all_calendar_entity_ids(self.hass)
|
||||
if not entity_ids:
|
||||
return
|
||||
own = calendar_entity_ids(self.entry.data.get(CONF_TASKS, {})) if forced else frozenset()
|
||||
await async_refresh_calendar_occurrences(self.hass, entity_ids, force=own)
|
||||
|
||||
def _assign_task_refs(self) -> None:
|
||||
"""#170: number tasks that have none yet (every creation path ends in
|
||||
a refresh, so this is the one place), and completions recorded before
|
||||
@@ -205,6 +233,7 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
# paused_until, then continue this refresh un-paused.
|
||||
await self._async_maybe_auto_resume()
|
||||
self._assign_task_refs()
|
||||
await self._async_prefetch_calendar_occurrences()
|
||||
|
||||
obj = self.maintenance_object
|
||||
tasks = self.tasks
|
||||
@@ -1603,6 +1632,7 @@ class MaintenanceCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
The recompute covers one object's tasks, so doing it per user action is
|
||||
cheap; the debounced path stays exactly as it was for triggers.
|
||||
"""
|
||||
self._calendar_refresh_forced = True
|
||||
await self.async_refresh()
|
||||
|
||||
async def _persist_and_signal_task_change(
|
||||
|
||||
@@ -102,6 +102,8 @@ def _build_export_object(
|
||||
"allow_skip": tdata.get("allow_skip"),
|
||||
# #173: per-task notification mute.
|
||||
"notify_enabled": tdata.get("notify_enabled"),
|
||||
# #185: per-task notification icon override.
|
||||
"notify_icon": tdata.get("notify_icon"),
|
||||
"responsible_user_id": tdata.get("responsible_user_id"),
|
||||
"entity_slug": tdata.get("entity_slug"),
|
||||
"adaptive_config": tdata.get("adaptive_config"),
|
||||
|
||||
+59
-4
@@ -48,6 +48,11 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
@state() private _error = "";
|
||||
@state() private _sensors: ProblemSensor[] = [];
|
||||
@state() private _selected: Set<string> = new Set();
|
||||
/** #188: the object each selected sensor goes to — typed per row; the same
|
||||
* name on several rows makes them ONE object, an existing object's name
|
||||
* adds them to it. */
|
||||
@state() private _objectNames: Record<string, string> = {};
|
||||
@state() private _objects: Array<{ entry_id: string; name: string }> = [];
|
||||
@state() private _users: HAUser[] = [];
|
||||
@state() private _responsible = "";
|
||||
// #136: minutes the problem must persist before the created task triggers
|
||||
@@ -74,18 +79,28 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
this._error = "";
|
||||
this._sensors = [];
|
||||
this._selected = new Set();
|
||||
this._objectNames = {};
|
||||
this._responsible = "";
|
||||
this._forMinutes = "0";
|
||||
try {
|
||||
if (!this._userService) this._userService = new UserService(this.hass);
|
||||
else this._userService.updateHass(this.hass);
|
||||
const [resp, users] = await Promise.all([
|
||||
const [resp, users, objs] = await Promise.all([
|
||||
this.hass.connection.sendMessagePromise<DiscoverResponse>({
|
||||
type: "maintenance_supporter/problem_sensors/discover",
|
||||
}),
|
||||
// Best-effort: adoption works fine without the user list.
|
||||
this._userService.getUsers().catch(() => [] as HAUser[]),
|
||||
// Best-effort too: the existing objects feed the name suggestions.
|
||||
this.hass.connection
|
||||
.sendMessagePromise<{ objects: Array<{ entry_id: string; object: { name: string; archived_at?: string | null } }> }>({
|
||||
type: "maintenance_supporter/objects",
|
||||
})
|
||||
.catch(() => ({ objects: [] })),
|
||||
]);
|
||||
this._objects = (objs.objects || [])
|
||||
.filter((o) => !o.object.archived_at)
|
||||
.map((o) => ({ entry_id: o.entry_id, name: o.object.name }));
|
||||
this._sensors = resp.sensors || [];
|
||||
this._selected = new Set(this._sensors.map((s) => s.entity_id));
|
||||
this._users = users;
|
||||
@@ -96,6 +111,21 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
/** The object name a row will be adopted into (typed, else the suggestion). */
|
||||
private _effectiveName(s: ProblemSensor): string {
|
||||
const typed = (this._objectNames[s.entity_id] ?? "").trim();
|
||||
return typed || s.suggested_object_name;
|
||||
}
|
||||
|
||||
/** An existing object the row lands in: the suggestion's entry when the
|
||||
* name is untouched, else an existing object with exactly that name. */
|
||||
private _existingEntryFor(s: ProblemSensor): string | null {
|
||||
const name = this._effectiveName(s);
|
||||
if (name === s.suggested_object_name && s.suggested_entry_id) return s.suggested_entry_id;
|
||||
const hit = this._objects.find((o) => o.name.trim().toLowerCase() === name.toLowerCase());
|
||||
return hit ? hit.entry_id : null;
|
||||
}
|
||||
|
||||
private _close(): void {
|
||||
this._open = false;
|
||||
}
|
||||
@@ -125,8 +155,8 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
.map((s) => ({
|
||||
entity_id: s.entity_id,
|
||||
name: s.name,
|
||||
entry_id: s.suggested_entry_id ?? undefined,
|
||||
object_name: s.suggested_object_name,
|
||||
entry_id: this._existingEntryFor(s) ?? undefined,
|
||||
object_name: this._effectiveName(s),
|
||||
device_id: s.device_id ?? undefined,
|
||||
part_id: s.suggested_part_id ?? undefined,
|
||||
responsible_user_id: this._responsible || undefined,
|
||||
@@ -177,6 +207,10 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
/>
|
||||
<span>${t("selected", L)}: ${this._selected.size} / ${this._sensors.length}</span>
|
||||
</label>
|
||||
<div class="row-sub adopt-object-hint">${t("adopt_object_hint", L)}</div>
|
||||
<datalist id="adopt-object-names">
|
||||
${this._objects.map((o) => html`<option value=${o.name}></option>`)}
|
||||
</datalist>
|
||||
<div class="list">
|
||||
${this._sensors.map((s) => {
|
||||
const checked = this._selected.has(s.entity_id);
|
||||
@@ -201,8 +235,22 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
</span>
|
||||
</div>
|
||||
${sub ? html`<div class="row-sub">${sub}</div>` : nothing}
|
||||
${checked
|
||||
? html`<div class="row-object" @click=${(e: Event) => e.stopPropagation()}>
|
||||
<input
|
||||
class="adopt-object"
|
||||
list="adopt-object-names"
|
||||
aria-label=${t("object", L)}
|
||||
placeholder=${s.suggested_object_name}
|
||||
.value=${this._objectNames[s.entity_id] ?? s.suggested_object_name}
|
||||
@input=${(e: Event) => {
|
||||
this._objectNames = { ...this._objectNames, [s.entity_id]: (e.target as HTMLInputElement).value };
|
||||
}}
|
||||
/>
|
||||
</div>`
|
||||
: nothing}
|
||||
<div class="row-target">
|
||||
→ ${s.suggested_object_name}${s.suggested_entry_id
|
||||
→ ${this._effectiveName(s)}${this._existingEntryFor(s)
|
||||
? nothing
|
||||
: html` <span class="new-tag">${t("adopt_problem_new_object", L)}</span>`}
|
||||
</div>
|
||||
@@ -365,6 +413,13 @@ export class MaintenanceAdoptProblemSensorsDialog extends LitElement {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
}
|
||||
.row-object { margin-top: 6px; }
|
||||
.row-object input {
|
||||
width: 100%; box-sizing: border-box; padding: 6px 8px; font: inherit;
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
background: var(--card-background-color); color: var(--primary-text-color);
|
||||
}
|
||||
.adopt-object-hint { margin: 0 0 8px; }
|
||||
.row-target {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
|
||||
@@ -18,12 +18,16 @@ import { runWs } from "../helpers/ws-run";
|
||||
import type { TriggerType } from "../types";
|
||||
import { REQUIRED_COMPLETION_KEYS, REQUIRED_COMPLETION_LABELS } from "./required-completion-labels";
|
||||
import "./ms-textfield";
|
||||
import { defaultNotifyIcon } from "../helpers/notify-icons";
|
||||
import "./ms-date-field";
|
||||
|
||||
const MAINTENANCE_TYPE_KEYS = ["cleaning", "inspection", "replacement", "calibration", "service", "reading", "custom"];
|
||||
const PRIORITY_KEYS = ["low", "normal", "high"];
|
||||
const SCHEDULE_TYPE_KEYS = ["time_based", "weekdays", "nth_weekday", "day_of_month", "sensor_based", "one_time", "manual"];
|
||||
const CALENDAR_KINDS = ["weekdays", "nth_weekday", "day_of_month"];
|
||||
const SCHEDULE_TYPE_KEYS = ["time_based", "weekdays", "nth_weekday", "day_of_month", "calendar", "sensor_based", "one_time", "manual"];
|
||||
// The nested calendar kinds — the three date patterns plus, since #187, a HA
|
||||
// calendar entity (one occurrence per event). Mirrors _CALENDAR_KINDS in
|
||||
// helpers/schedule.py (tripwire: tests/test_cross_layer_vocab.py).
|
||||
const CALENDAR_KINDS = ["weekdays", "nth_weekday", "day_of_month", "calendar"];
|
||||
// #168: kinds that produce a due DATE and therefore take a time of day
|
||||
// (mirrors SCHEDULE_TIME_KINDS in config_flow_helpers.py).
|
||||
const SCHEDULE_TIME_KINDS = ["time_based", "one_time", ...CALENDAR_KINDS];
|
||||
@@ -194,6 +198,8 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
@state() private _domLastDay = false;
|
||||
@state() private _domBusiness = false;
|
||||
@state() private _calOffset = "0";
|
||||
// #187: the HA calendar entity whose events are the occurrences ("calendar" kind).
|
||||
@state() private _calendarEntity = "";
|
||||
// Recurrence extras (apply to interval + calendar kinds): a seasonal active
|
||||
// window and a finite-series end condition.
|
||||
@state() private _seasonMonths: number[] = [];
|
||||
@@ -209,6 +215,8 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
@state() private _notes = "";
|
||||
@state() private _documentationUrl = "";
|
||||
@state() private _customIcon = "";
|
||||
/** #185: mdi icon for this task's push notifications ("" = type default). */
|
||||
@state() private _notifyIcon = "";
|
||||
@state() private _priority = "normal";
|
||||
@state() private _labels = "";
|
||||
/** D#183: external todo.* lists the task is mirrored into while due. */
|
||||
@@ -402,6 +410,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
this._domDay = sched?.kind === "day_of_month" && (sched.day ?? 1) >= 1 ? String(sched.day ?? 1) : "1";
|
||||
this._domLastDay = sched?.kind === "day_of_month" && sched.day === -1;
|
||||
this._domBusiness = sched?.kind === "day_of_month" && sched.business === true;
|
||||
this._calendarEntity = sched?.kind === "calendar" ? (sched.entity_id || "") : "";
|
||||
this._calOffset = sched?.offset ? String(sched.offset) : "0";
|
||||
// Recurrence extras — read from the nested schedule wherever it lives.
|
||||
this._seasonMonths = Array.isArray(sched?.season_months) ? [...sched!.season_months] : [];
|
||||
@@ -420,6 +429,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
this._notes = task.notes || "";
|
||||
this._documentationUrl = task.documentation_url || "";
|
||||
this._customIcon = task.custom_icon || "";
|
||||
this._notifyIcon = task.notify_icon || "";
|
||||
this._priority = task.priority || "normal";
|
||||
this._labels = (task.labels || []).join(", ");
|
||||
this._mirrorTodoEntities = [...(task.mirror_todo_entities || [])];
|
||||
@@ -577,6 +587,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
this._notes = "";
|
||||
this._documentationUrl = "";
|
||||
this._customIcon = "";
|
||||
this._notifyIcon = "";
|
||||
this._priority = "normal";
|
||||
this._labels = "";
|
||||
this._mirrorTodoEntities = [];
|
||||
@@ -1266,6 +1277,11 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
this._error = t("trigger_hint_overlap", this._lang);
|
||||
return;
|
||||
}
|
||||
if (this._scheduleType === "calendar" && !this._calendarEntity.trim().startsWith("calendar.")) {
|
||||
// #187: the backend would store entity_id null (a task without dates).
|
||||
this._error = t("calendar_entity_required", this._lang);
|
||||
return;
|
||||
}
|
||||
this._loading = true;
|
||||
this._error = "";
|
||||
try {
|
||||
@@ -1326,6 +1342,8 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
data.notes = this._notes || null;
|
||||
data.documentation_url = this._documentationUrl || null;
|
||||
data.custom_icon = this._customIcon || null;
|
||||
// #185: null clears the override (the update path pops the key).
|
||||
data.notify_icon = this._notifyIcon.trim() || null;
|
||||
data.priority = this._priority;
|
||||
data.labels = this._labels
|
||||
.split(",")
|
||||
@@ -2071,6 +2089,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
if (this._scheduleType === "one_time") {
|
||||
return this._dueDate ? { kind: "one_time", due_date: this._dueDate } : null;
|
||||
}
|
||||
if (this._scheduleType === "calendar" && !this._calendarEntity.trim()) return null;
|
||||
if (CALENDAR_KINDS.includes(this._scheduleType)) {
|
||||
return { ...this._buildSchedule(), ...this._recurrenceExtras() };
|
||||
}
|
||||
@@ -2088,7 +2107,7 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
private static readonly _PREVIEW_RELEVANT = new Set([
|
||||
"_open", "_scheduleType", "_intervalDays", "_intervalUnit", "_intervalAnchor",
|
||||
"_dueDate", "_weekdays", "_nth", "_nthWeekday", "_domDay", "_domLastDay",
|
||||
"_domBusiness", "_calOffset", "_seasonMonths", "_endsMode", "_endsCount",
|
||||
"_domBusiness", "_calOffset", "_calendarEntity", "_seasonMonths", "_endsMode", "_endsCount",
|
||||
"_endsUntil", "_lastPerformed",
|
||||
]);
|
||||
|
||||
@@ -2231,6 +2250,10 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
weekday: parseInt(this._nthWeekday, 10),
|
||||
});
|
||||
}
|
||||
if (this._scheduleType === "calendar") {
|
||||
// #187: once per event of the picked HA calendar entity.
|
||||
return withOffset({ kind: "calendar", entity_id: this._calendarEntity.trim() });
|
||||
}
|
||||
// (#83) "last day" wins over the day number; business rolls weekends back.
|
||||
const schedule: Record<string, unknown> = {
|
||||
kind: "day_of_month",
|
||||
@@ -2345,6 +2368,33 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
</div>
|
||||
${this._renderCalOffsetField()}`;
|
||||
}
|
||||
if (this._scheduleType === "calendar") {
|
||||
// #187: pick the HA calendar. Same <ha-form> entity-selector idiom as the
|
||||
// trigger pickers (never <ha-entity-picker> directly — see the
|
||||
// dialog-no-lazy-load-elements tripwire), with the text fallback the
|
||||
// picker probe flips to in a broken context.
|
||||
return html`
|
||||
${this._entityPickerFallback ? html`
|
||||
<ms-textfield
|
||||
label="${t("calendar_entity_label", L)}"
|
||||
helper="${t("calendar_entity_hint", L)}"
|
||||
.value=${this._calendarEntity}
|
||||
@input=${(e: Event) => (this._calendarEntity = (e.target as HTMLInputElement).value.trim())}
|
||||
></ms-textfield>
|
||||
` : html`
|
||||
<ha-form
|
||||
class="entity-picker-form calendar-entity-form"
|
||||
.hass=${this.hass}
|
||||
.schema=${[{ name: "calendar_entity", selector: { entity: { domain: "calendar" } } }]}
|
||||
.data=${{ calendar_entity: this._calendarEntity }}
|
||||
.computeLabel=${() => t("calendar_entity_label", L)}
|
||||
.computeHelper=${() => t("calendar_entity_hint", L)}
|
||||
@value-changed=${(e: CustomEvent) => {
|
||||
this._calendarEntity = ((e.detail.value as { calendar_entity?: string }).calendar_entity || "").trim();
|
||||
}}
|
||||
></ha-form>`}
|
||||
${this._renderCalOffsetField()}`;
|
||||
}
|
||||
if (this._scheduleType === "day_of_month") {
|
||||
return html`
|
||||
${this._domLastDay ? nothing : html`
|
||||
@@ -2962,6 +3012,18 @@ export class MaintenanceTaskDialog extends LitElement {
|
||||
@value-changed=${(e: CustomEvent) =>
|
||||
(this._customIcon = (e.detail.value as string) || "")}
|
||||
></ha-icon-picker>
|
||||
<ha-icon-picker
|
||||
class="notify-icon-picker"
|
||||
.hass=${this.hass}
|
||||
label="${t("notify_icon", L)}"
|
||||
.value=${this._notifyIcon}
|
||||
@value-changed=${(e: CustomEvent) =>
|
||||
(this._notifyIcon = (e.detail.value as string) || "")}
|
||||
></ha-icon-picker>
|
||||
<div class="field-help notify-icon-help">
|
||||
<ha-icon icon=${this._notifyIcon.trim() || defaultNotifyIcon(this._type)}></ha-icon>
|
||||
${t("notify_icon_hint", L).replace("{default}", defaultNotifyIcon(this._type))}
|
||||
</div>
|
||||
${this._availableTags.length > 0
|
||||
? html`
|
||||
<div class="select-row">
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Úkol přesunut",
|
||||
"move_task_target": "Cílový objekt",
|
||||
"move_task_message": "Vyberte objekt, ke kterému má tento úkol patřit. Historie, odečty a stav spouštěče se přesunou s ním; dostane nové referenční číslo a jeho entity se vytvoří znovu pod novým objektem. Propojené dokumenty zůstanou u aktuálního objektu.",
|
||||
"bulk_move_message": "Vyberte objekt, ke kterému mají vybrané úkoly patřit. Úkoly, které tam už jsou, se přeskočí; historie, odečty a stav spouštěče se přesunou s nimi.",
|
||||
"bulk_moved": "Přesunuto úkolů: {n}",
|
||||
"more_actions": "Další akce",
|
||||
"move_task_title": "Přesunout úkol",
|
||||
"move_task": "Přesunout do jiného objektu…",
|
||||
"object_duplicated": "Objekt duplikován",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} vybráno",
|
||||
"bulk_completed": "Dokončeno {n} úkolů",
|
||||
"bulk_archived": "Archivováno {n} úkolů",
|
||||
"bulk_delete_objects_confirm": "Smazat {n} objektů včetně všech jejich úkolů? Archivace místo toho zachová historii.",
|
||||
"bulk_objects_deleted": "Smazáno objektů: {n}",
|
||||
"bulk_objects_archived": "Archivováno objektů: {n}",
|
||||
"completing": "Dokončování…",
|
||||
"interval": "Interval",
|
||||
"warning": "Upozornění",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Dny v týdnu",
|
||||
"nth_weekday": "N-tý den v týdnu v měsíci",
|
||||
"day_of_month": "Den v měsíci",
|
||||
"calendar": "Entita kalendáře",
|
||||
"calendar_entity_label": "Kalendář",
|
||||
"calendar_entity_hint": "Splatné jednou za každou událost tohoto kalendáře, v den začátku události — další událost po posledním dokončení.",
|
||||
"calendar_entity_required": "Vyberte entitu kalendáře.",
|
||||
"recurrence_on_days": "Opakovat v",
|
||||
"recurrence_occurrence": "Výskyt",
|
||||
"recurrence_weekday": "Den v týdnu",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Objekt nelze propojit sám se sebou",
|
||||
"ws_err_too_early": "Příliš brzy — tento úkol lze dokončit až blíže k termínu",
|
||||
"ws_err_invalid_search_template": "Odkaz pro vyhledávání musí být URL http(s) obsahující {q}",
|
||||
"ws_err_invalid_icon": "Ikona oznámení musí být název mdi:, např. mdi:air-filter",
|
||||
"feat_schedule_time": "Plánování podle denní doby",
|
||||
"feat_schedule_time_desc": "Úkoly se stanou po termínu v určenou denní dobu místo o půlnoci.",
|
||||
"schedule_time_toggle": "Termín v určitou hodinu",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Sloupce tabulky objektů",
|
||||
"objects_table_columns_hint": "Vyberte, které sloupce se zobrazí v tabulkovém zobrazení objektů.",
|
||||
"custom_icon_optional": "Ikona (volitelná, např. mdi:wrench)",
|
||||
"notify_icon": "Ikona oznámení",
|
||||
"notify_icon_hint": "Zobrazuje aplikace Companion na Androidu. Prázdné = ikona typu údržby tohoto úkolu ({default}).",
|
||||
"task_enabled": "Úkol povolen",
|
||||
"skip_reason_prompt": "Přeskočit tento úkol?",
|
||||
"reason_optional": "Důvod (volitelný)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Vyfotit",
|
||||
"camera_capture_shoot": "Vyfotit",
|
||||
"camera_switch_lens": "Přepnout kameru",
|
||||
"camera_switch_failed": "Žádná jiná kamera neodpověděla – tento telefon uvolňuje jen jednu. Pro druhý objektiv použijte výběr souboru.",
|
||||
"doc_drop_hint": "Přetáhněte soubory sem",
|
||||
"doc_task_none": "Žádné dokumenty spojené s tímto úkolem.",
|
||||
"doc_link_existing": "Připojit dokument…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktivní",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nový)",
|
||||
"adopt_object_hint": "Dejte několika senzorům stejný název objektu a stanou se jedním objektem; zadejte název existujícího objektu a přidají se tam.",
|
||||
"adopt_problem_adopt": "Převzít vybrané",
|
||||
"adopt_problem_done": "Převzato {tasks} senzorů problémů",
|
||||
"views_label": "Zobrazení",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Opgave flyttet",
|
||||
"move_task_target": "Målobjekt",
|
||||
"move_task_message": "Vælg det objekt, opgaven skal høre til. Historik, aflæsninger og triggerstatus flytter med; den får et nyt referencenummer, og dens entiteter oprettes igen under det nye objekt. Tilknyttede dokumenter bliver hos det nuværende objekt.",
|
||||
"bulk_move_message": "Vælg det objekt, de markerede opgaver skal høre til. Opgaver, der allerede er der, springes over; historik, aflæsninger og triggerstatus flytter med.",
|
||||
"bulk_moved": "{n} opgaver flyttet",
|
||||
"more_actions": "Flere handlinger",
|
||||
"move_task_title": "Flyt opgave",
|
||||
"move_task": "Flyt til et andet objekt…",
|
||||
"object_duplicated": "Objekt duplikeret",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} valgt",
|
||||
"bulk_completed": "{n} opgaver fuldført",
|
||||
"bulk_archived": "{n} opgaver arkiveret",
|
||||
"bulk_delete_objects_confirm": "Slet {n} objekter og alle deres opgaver? Arkivering bevarer i stedet historikken.",
|
||||
"bulk_objects_deleted": "{n} objekter slettet",
|
||||
"bulk_objects_archived": "{n} objekter arkiveret",
|
||||
"completing": "Fuldfører…",
|
||||
"interval": "Interval",
|
||||
"warning": "Advarsel",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Ugedage",
|
||||
"nth_weekday": "N'te ugedag i måneden",
|
||||
"day_of_month": "Dag i måneden",
|
||||
"calendar": "Kalenderentitet",
|
||||
"calendar_entity_label": "Kalender",
|
||||
"calendar_entity_hint": "Forfalder én gang pr. begivenhed i denne kalender, på begivenhedens startdato — den næste begivenhed efter seneste udførelse.",
|
||||
"calendar_entity_required": "Vælg en kalenderentitet.",
|
||||
"recurrence_on_days": "Gentag på",
|
||||
"recurrence_occurrence": "Forekomst",
|
||||
"recurrence_weekday": "Ugedag",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Et objekt kan ikke knyttes til sig selv",
|
||||
"ws_err_too_early": "For tidligt — opgaven kan først fuldføres tættere på forfaldsdatoen",
|
||||
"ws_err_invalid_search_template": "Søgelinket skal være en http(s)-URL, der indeholder {q}",
|
||||
"ws_err_invalid_icon": "Notifikationsikonet skal være et mdi:-navn, f.eks. mdi:air-filter",
|
||||
"feat_schedule_time": "Planlægning efter tidspunkt på dagen",
|
||||
"feat_schedule_time_desc": "Opgaver bliver forfaldne på et bestemt tidspunkt på dagen i stedet for midnat.",
|
||||
"schedule_time_toggle": "Forfalder på et bestemt tidspunkt",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Kolonner i objekttabel",
|
||||
"objects_table_columns_hint": "Vælg, hvilke kolonner der vises i objekttabelvisningen.",
|
||||
"custom_icon_optional": "Ikon (valgfrit, f.eks. mdi:wrench)",
|
||||
"notify_icon": "Notifikationsikon",
|
||||
"notify_icon_hint": "Vises af Companion-appen på Android. Tom = ikonet for opgavens vedligeholdelsestype ({default}).",
|
||||
"task_enabled": "Opgave aktiveret",
|
||||
"skip_reason_prompt": "Spring denne opgave over?",
|
||||
"reason_optional": "Årsag (valgfrit)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Tag billede",
|
||||
"camera_capture_shoot": "Tag billede",
|
||||
"camera_switch_lens": "Skift kamera",
|
||||
"camera_switch_failed": "Intet andet kamera svarede — denne telefon frigiver kun ét. Brug filvælgeren til det andet objektiv.",
|
||||
"doc_drop_hint": "Slip filer her",
|
||||
"doc_task_none": "Ingen dokumenter knyttet til denne opgave.",
|
||||
"doc_link_existing": "Knyt et dokument…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktiv",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(ny)",
|
||||
"adopt_object_hint": "Giv flere sensorer samme objektnavn, så bliver de ét objekt; skriv et eksisterende objekts navn for at tilføje dem der.",
|
||||
"adopt_problem_adopt": "Adopter valgte",
|
||||
"adopt_problem_done": "Adopterede {tasks} problemsensor(er)",
|
||||
"views_label": "Visninger",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Aufgabe verschoben",
|
||||
"move_task_target": "Zielobjekt",
|
||||
"move_task_message": "Wähle das Objekt, zu dem diese Aufgabe gehören soll. Historie, Zählerstände und Trigger-Zustand wandern mit; sie bekommt eine neue Referenznummer und ihre Entitäten werden unter dem neuen Objekt neu angelegt. Verknüpfte Dokumente bleiben beim aktuellen Objekt.",
|
||||
"bulk_move_message": "Wähle das Objekt, zu dem die markierten Aufgaben gehören sollen. Aufgaben, die schon dort sind, werden übersprungen; Historie, Messwerte und Trigger-Zustand wandern mit.",
|
||||
"bulk_moved": "{n} Aufgaben verschoben",
|
||||
"more_actions": "Weitere Aktionen",
|
||||
"move_task_title": "Aufgabe verschieben",
|
||||
"move_task": "In anderes Objekt verschieben…",
|
||||
"object_duplicated": "Objekt dupliziert",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} ausgewählt",
|
||||
"bulk_completed": "{n} Aufgaben erledigt",
|
||||
"bulk_archived": "{n} Aufgaben archiviert",
|
||||
"bulk_delete_objects_confirm": "{n} Objekte mit allen ihren Aufgaben löschen? Archivieren behält stattdessen die Historie.",
|
||||
"bulk_objects_deleted": "{n} Objekte gelöscht",
|
||||
"bulk_objects_archived": "{n} Objekte archiviert",
|
||||
"completing": "Wird erledigt…",
|
||||
"interval": "Intervall",
|
||||
"warning": "Vorwarnung",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Wochentage",
|
||||
"nth_weekday": "N-ter Wochentag im Monat",
|
||||
"day_of_month": "Tag im Monat",
|
||||
"calendar": "Kalender-Entität",
|
||||
"calendar_entity_label": "Kalender",
|
||||
"calendar_entity_hint": "Einmal pro Termin dieses Kalenders fällig, am Starttag des Termins — der nächste Termin nach der letzten Erledigung.",
|
||||
"calendar_entity_required": "Bitte eine Kalender-Entität auswählen.",
|
||||
"recurrence_on_days": "Wiederholen an",
|
||||
"recurrence_occurrence": "Vorkommen",
|
||||
"recurrence_weekday": "Wochentag",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Ein Objekt kann nicht mit sich selbst verknüpft werden",
|
||||
"ws_err_too_early": "Zu früh — diese Aufgabe kann erst näher am Fälligkeitsdatum erledigt werden",
|
||||
"ws_err_invalid_search_template": "Der Suchlink muss eine http(s)-URL mit {q} sein",
|
||||
"ws_err_invalid_icon": "Das Benachrichtigungs-Icon muss ein mdi:-Name sein, z. B. mdi:air-filter",
|
||||
"feat_schedule_time": "Uhrzeit-Scheduling",
|
||||
"feat_schedule_time_desc": "Tasks werden zu einer festen Uhrzeit fällig statt um Mitternacht.",
|
||||
"schedule_time_toggle": "Zu einer bestimmten Uhrzeit fällig",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Spalten der Objekt-Tabelle",
|
||||
"objects_table_columns_hint": "Wähle die Spalten für die Tabellenansicht der Objektübersicht.",
|
||||
"custom_icon_optional": "Icon (optional, z.B. mdi:wrench)",
|
||||
"notify_icon": "Benachrichtigungs-Icon",
|
||||
"notify_icon_hint": "Zeigt die Companion-App auf Android. Leer = das Icon der Wartungsart dieser Aufgabe ({default}).",
|
||||
"task_enabled": "Aufgabe aktiviert",
|
||||
"skip_reason_prompt": "Aufgabe überspringen?",
|
||||
"reason_optional": "Grund (optional)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Foto aufnehmen",
|
||||
"camera_capture_shoot": "Aufnehmen",
|
||||
"camera_switch_lens": "Kamera wechseln",
|
||||
"camera_switch_failed": "Keine andere Kamera hat geantwortet – dieses Telefon gibt nur eine frei. Für das andere Objektiv die Dateiauswahl nutzen.",
|
||||
"doc_drop_hint": "Dateien hier ablegen",
|
||||
"doc_task_none": "Keine Dokumente mit dieser Aufgabe verknüpft.",
|
||||
"doc_link_existing": "Dokument verknüpfen…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktiv",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(neu)",
|
||||
"adopt_object_hint": "Gib mehreren Sensoren denselben Objektnamen, dann werden sie ein Objekt; der Name eines vorhandenen Objekts ordnet sie dort zu.",
|
||||
"adopt_problem_adopt": "Auswahl übernehmen",
|
||||
"adopt_problem_done": "{tasks} Problem-Sensor(en) übernommen",
|
||||
"views_label": "Ansichten",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Task moved",
|
||||
"move_task_target": "Target object",
|
||||
"move_task_message": "Choose the object this task should belong to. Its history, readings and trigger state move with it; it gets a new reference number and its entities are recreated under the new object. Linked documents stay with the current object.",
|
||||
"bulk_move_message": "Choose the object the selected tasks should belong to. Tasks that already live there are skipped; history, readings and trigger state move along.",
|
||||
"bulk_moved": "{n} tasks moved",
|
||||
"more_actions": "More actions",
|
||||
"move_task_title": "Move task",
|
||||
"move_task": "Move to another object…",
|
||||
"object_duplicated": "Object duplicated",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} selected",
|
||||
"bulk_completed": "{n} tasks completed",
|
||||
"bulk_archived": "{n} tasks archived",
|
||||
"bulk_delete_objects_confirm": "Delete {n} objects and all their tasks? Archiving keeps their history instead.",
|
||||
"bulk_objects_deleted": "{n} objects deleted",
|
||||
"bulk_objects_archived": "{n} objects archived",
|
||||
"completing": "Completing…",
|
||||
"interval": "Interval",
|
||||
"warning": "Warning",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Weekdays",
|
||||
"nth_weekday": "Nth weekday of month",
|
||||
"day_of_month": "Day of month",
|
||||
"calendar": "Calendar entity",
|
||||
"calendar_entity_label": "Calendar",
|
||||
"calendar_entity_hint": "Due once per event of this calendar, on the event's start date — the next event after the last completion.",
|
||||
"calendar_entity_required": "Choose a calendar entity.",
|
||||
"recurrence_on_days": "Repeat on",
|
||||
"recurrence_occurrence": "Occurrence",
|
||||
"recurrence_weekday": "Weekday",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "An object cannot be linked to itself",
|
||||
"ws_err_too_early": "Too early — this task can only be completed closer to its due date",
|
||||
"ws_err_invalid_search_template": "The search link must be an http(s) URL containing {q}",
|
||||
"ws_err_invalid_icon": "The notification icon must be an mdi: name, e.g. mdi:air-filter",
|
||||
"feat_schedule_time": "Time-of-day scheduling",
|
||||
"feat_schedule_time_desc": "Tasks become overdue at a specific time of day instead of midnight.",
|
||||
"schedule_time_toggle": "Due at a specific time",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Objects table columns",
|
||||
"objects_table_columns_hint": "Choose which columns appear in the objects table view.",
|
||||
"custom_icon_optional": "Icon (optional, e.g. mdi:wrench)",
|
||||
"notify_icon": "Notification icon",
|
||||
"notify_icon_hint": "Shown by the Companion app on Android. Empty = the icon of this task's maintenance type ({default}).",
|
||||
"task_enabled": "Task enabled",
|
||||
"skip_reason_prompt": "Skip this task?",
|
||||
"reason_optional": "Reason (optional)",
|
||||
@@ -784,6 +797,7 @@
|
||||
"doc_camera": "Take photo",
|
||||
"camera_capture_shoot": "Capture",
|
||||
"camera_switch_lens": "Switch camera",
|
||||
"camera_switch_failed": "No other camera answered — this phone hands out only one. Use the file picker for the other lens.",
|
||||
"doc_drop_hint": "Drop files here",
|
||||
"doc_task_none": "No documents linked to this task.",
|
||||
"doc_link_existing": "Link a document…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "active",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(new)",
|
||||
"adopt_object_hint": "Give several sensors the same object name and they become one object; type an existing object's name to add them there.",
|
||||
"adopt_problem_adopt": "Adopt selected",
|
||||
"adopt_problem_done": "Adopted {tasks} problem sensor(s)",
|
||||
"views_label": "Views",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Tarea movida",
|
||||
"move_task_target": "Objeto de destino",
|
||||
"move_task_message": "Elige el objeto al que debe pertenecer esta tarea. Su historial, lecturas y estado del disparador se mueven con ella; recibe un nuevo número de referencia y sus entidades se recrean bajo el nuevo objeto. Los documentos vinculados se quedan con el objeto actual.",
|
||||
"bulk_move_message": "Elige el objeto al que deben pertenecer las tareas seleccionadas. Las que ya están allí se omiten; el historial, las lecturas y el estado del disparador se mueven con ellas.",
|
||||
"bulk_moved": "{n} tareas movidas",
|
||||
"more_actions": "Más acciones",
|
||||
"move_task_title": "Mover tarea",
|
||||
"move_task": "Mover a otro objeto…",
|
||||
"object_duplicated": "Objeto duplicado",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} seleccionados",
|
||||
"bulk_completed": "{n} tareas completadas",
|
||||
"bulk_archived": "{n} tareas archivadas",
|
||||
"bulk_delete_objects_confirm": "¿Eliminar {n} objetos y todas sus tareas? Archivar conserva su historial.",
|
||||
"bulk_objects_deleted": "{n} objetos eliminados",
|
||||
"bulk_objects_archived": "{n} objetos archivados",
|
||||
"completing": "Completando…",
|
||||
"interval": "Intervalo",
|
||||
"warning": "Aviso",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Días de la semana",
|
||||
"nth_weekday": "N-ésimo día de la semana del mes",
|
||||
"day_of_month": "Día del mes",
|
||||
"calendar": "Entidad de calendario",
|
||||
"calendar_entity_label": "Calendario",
|
||||
"calendar_entity_hint": "Vence una vez por evento de este calendario, en la fecha de inicio del evento — el siguiente evento tras la última finalización.",
|
||||
"calendar_entity_required": "Elige una entidad de calendario.",
|
||||
"recurrence_on_days": "Repetir los",
|
||||
"recurrence_occurrence": "Aparición",
|
||||
"recurrence_weekday": "Día de la semana",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Un objeto no puede vincularse a sí mismo",
|
||||
"ws_err_too_early": "Demasiado pronto — esta tarea solo puede completarse más cerca de su vencimiento",
|
||||
"ws_err_invalid_search_template": "El enlace de búsqueda debe ser una URL http(s) que contenga {q}",
|
||||
"ws_err_invalid_icon": "El icono de la notificación debe ser un nombre mdi:, p. ej. mdi:air-filter",
|
||||
"feat_schedule_time": "Programación por hora",
|
||||
"feat_schedule_time_desc": "Las tareas vencen a una hora específica en lugar de medianoche.",
|
||||
"schedule_time_toggle": "Vence a una hora concreta",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Columnas de la tabla de objetos",
|
||||
"objects_table_columns_hint": "Elige qué columnas aparecen en la vista de tabla de objetos.",
|
||||
"custom_icon_optional": "Icono (opcional, ej. mdi:wrench)",
|
||||
"notify_icon": "Icono de la notificación",
|
||||
"notify_icon_hint": "Lo muestra la app Companion en Android. Vacío = el icono del tipo de mantenimiento de esta tarea ({default}).",
|
||||
"task_enabled": "Tarea habilitada",
|
||||
"skip_reason_prompt": "¿Omitir esta tarea?",
|
||||
"reason_optional": "Motivo (opcional)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Tomar foto",
|
||||
"camera_capture_shoot": "Capturar",
|
||||
"camera_switch_lens": "Cambiar de cámara",
|
||||
"camera_switch_failed": "Ninguna otra cámara respondió: este teléfono solo expone una. Usa el selector de archivos para el otro objetivo.",
|
||||
"doc_drop_hint": "Suelta los archivos aquí",
|
||||
"doc_task_none": "Ningún documento vinculado a esta tarea.",
|
||||
"doc_link_existing": "Vincular un documento…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "activo",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nuevo)",
|
||||
"adopt_object_hint": "Da a varios sensores el mismo nombre de objeto y se convierten en un solo objeto; escribe el nombre de un objeto existente para añadirlos allí.",
|
||||
"adopt_problem_adopt": "Adoptar seleccionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adoptado(s)",
|
||||
"views_label": "Vistas",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Tehtävä siirretty",
|
||||
"move_task_target": "Kohde",
|
||||
"move_task_message": "Valitse kohde, johon tämän tehtävän tulee kuulua. Historia, lukemat ja liipaisimen tila siirtyvät mukana; tehtävä saa uuden viitenumeron ja sen entiteetit luodaan uudelleen uuden kohteen alle. Linkitetyt asiakirjat jäävät nykyiseen kohteeseen.",
|
||||
"bulk_move_message": "Valitse kohde, johon valittujen tehtävien tulee kuulua. Siellä jo olevat tehtävät ohitetaan; historia, lukemat ja liipaisimen tila siirtyvät mukana.",
|
||||
"bulk_moved": "{n} tehtävää siirretty",
|
||||
"more_actions": "Lisää toimintoja",
|
||||
"move_task_title": "Siirrä tehtävä",
|
||||
"move_task": "Siirrä toiseen kohteeseen…",
|
||||
"object_duplicated": "Kohde monistettu",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} valittu",
|
||||
"bulk_completed": "{n} tehtävää valmiina",
|
||||
"bulk_archived": "{n} tehtävää arkistoitu",
|
||||
"bulk_delete_objects_confirm": "Poistetaanko {n} kohdetta kaikkine tehtävineen? Arkistointi säilyttää historian.",
|
||||
"bulk_objects_deleted": "{n} kohdetta poistettu",
|
||||
"bulk_objects_archived": "{n} kohdetta arkistoitu",
|
||||
"completing": "Suoritetaan…",
|
||||
"interval": "Väli",
|
||||
"warning": "Varoitus",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Viikonpäivät",
|
||||
"nth_weekday": "Kuukauden n:s viikonpäivä",
|
||||
"day_of_month": "Kuukauden päivä",
|
||||
"calendar": "Kalenterientiteetti",
|
||||
"calendar_entity_label": "Kalenteri",
|
||||
"calendar_entity_hint": "Erääntyy kerran tämän kalenterin jokaista tapahtumaa kohti, tapahtuman alkupäivänä — seuraava tapahtuma viimeisimmän suorituksen jälkeen.",
|
||||
"calendar_entity_required": "Valitse kalenterientiteetti.",
|
||||
"recurrence_on_days": "Toista päivinä",
|
||||
"recurrence_occurrence": "Esiintymä",
|
||||
"recurrence_weekday": "Viikonpäivä",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Objektia ei voi linkittää itseensä",
|
||||
"ws_err_too_early": "Liian aikaista — tehtävän voi merkitä tehdyksi vasta lähempänä eräpäivää",
|
||||
"ws_err_invalid_search_template": "Hakulinkin on oltava http(s)-URL, joka sisältää {q}",
|
||||
"ws_err_invalid_icon": "Ilmoituksen kuvakkeen on oltava mdi:-nimi, esim. mdi:air-filter",
|
||||
"feat_schedule_time": "Kellonajan ajoitus",
|
||||
"feat_schedule_time_desc": "Tehtävät erääntyvät tiettyyn kellonaikaan keskiyön sijaan.",
|
||||
"schedule_time_toggle": "Erääntyy tiettyyn kellonaikaan",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Kohdetaulukon sarakkeet",
|
||||
"objects_table_columns_hint": "Valitse, mitkä sarakkeet näkyvät kohdetaulukkonäkymässä.",
|
||||
"custom_icon_optional": "Kuvake (valinnainen, esim. mdi:wrench)",
|
||||
"notify_icon": "Ilmoituksen kuvake",
|
||||
"notify_icon_hint": "Näytetään Companion-sovelluksessa Androidilla. Tyhjä = tämän tehtävän huoltotyypin kuvake ({default}).",
|
||||
"task_enabled": "Tehtävä käytössä",
|
||||
"skip_reason_prompt": "Ohitetaanko tämä tehtävä?",
|
||||
"reason_optional": "Syy (valinnainen)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Ota kuva",
|
||||
"camera_capture_shoot": "Ota kuva",
|
||||
"camera_switch_lens": "Vaihda kameraa",
|
||||
"camera_switch_failed": "Muu kamera ei vastannut – tämä puhelin antaa käyttöön vain yhden. Käytä toiselle objektiiville tiedostovalitsinta.",
|
||||
"doc_drop_hint": "Pudota tiedostot tähän",
|
||||
"doc_task_none": "Tähän tehtävään ei ole liitetty asiakirjoja.",
|
||||
"doc_link_existing": "Liitä asiakirja…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktiivinen",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(uusi)",
|
||||
"adopt_object_hint": "Anna useille antureille sama kohteen nimi, niin niistä tulee yksi kohde; kirjoita olemassa olevan kohteen nimi lisätäksesi ne sinne.",
|
||||
"adopt_problem_adopt": "Ota valitut käyttöön",
|
||||
"adopt_problem_done": "Otettiin käyttöön {tasks} ongelma-anturia",
|
||||
"views_label": "Näkymät",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Tâche déplacée",
|
||||
"move_task_target": "Objet cible",
|
||||
"move_task_message": "Choisissez l'objet auquel cette tâche doit appartenir. Son historique, ses relevés et l'état de son déclencheur la suivent ; elle reçoit un nouveau numéro de référence et ses entités sont recréées sous le nouvel objet. Les documents liés restent avec l'objet actuel.",
|
||||
"bulk_move_message": "Choisissez l'objet auquel les tâches sélectionnées doivent appartenir. Les tâches déjà présentes sont ignorées ; historique, relevés et état du déclencheur suivent.",
|
||||
"bulk_moved": "{n} tâches déplacées",
|
||||
"more_actions": "Autres actions",
|
||||
"move_task_title": "Déplacer la tâche",
|
||||
"move_task": "Déplacer vers un autre objet…",
|
||||
"object_duplicated": "Objet dupliqué",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} sélectionné(s)",
|
||||
"bulk_completed": "{n} tâches terminées",
|
||||
"bulk_archived": "{n} tâches archivées",
|
||||
"bulk_delete_objects_confirm": "Supprimer {n} objets et toutes leurs tâches ? L'archivage conserve leur historique.",
|
||||
"bulk_objects_deleted": "{n} objets supprimés",
|
||||
"bulk_objects_archived": "{n} objets archivés",
|
||||
"completing": "En cours…",
|
||||
"interval": "Intervalle",
|
||||
"warning": "Avertissement",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Jours de semaine",
|
||||
"nth_weekday": "N-ième jour de la semaine du mois",
|
||||
"day_of_month": "Jour du mois",
|
||||
"calendar": "Entité calendrier",
|
||||
"calendar_entity_label": "Calendrier",
|
||||
"calendar_entity_hint": "À faire une fois par événement de ce calendrier, à la date de début de l'événement — le prochain événement après la dernière réalisation.",
|
||||
"calendar_entity_required": "Choisissez une entité calendrier.",
|
||||
"recurrence_on_days": "Répéter le",
|
||||
"recurrence_occurrence": "Occurrence",
|
||||
"recurrence_weekday": "Jour de semaine",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Un objet ne peut pas être lié à lui-même",
|
||||
"ws_err_too_early": "Trop tôt — cette tâche ne peut être terminée que plus près de son échéance",
|
||||
"ws_err_invalid_search_template": "Le lien de recherche doit être une URL http(s) contenant {q}",
|
||||
"ws_err_invalid_icon": "L'icône de notification doit être un nom mdi:, p. ex. mdi:air-filter",
|
||||
"feat_schedule_time": "Planification à l'heure",
|
||||
"feat_schedule_time_desc": "Les tâches arrivent à échéance à une heure précise plutôt qu'à minuit.",
|
||||
"schedule_time_toggle": "Échéance à une heure précise",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Colonnes du tableau d'objets",
|
||||
"objects_table_columns_hint": "Choisissez les colonnes affichées dans la vue tableau des objets.",
|
||||
"custom_icon_optional": "Icône (optionnel, ex. mdi:wrench)",
|
||||
"notify_icon": "Icône de notification",
|
||||
"notify_icon_hint": "Affichée par l'application Companion sur Android. Vide = l'icône du type d'entretien de cette tâche ({default}).",
|
||||
"task_enabled": "Tâche activée",
|
||||
"skip_reason_prompt": "Ignorer cette tâche ?",
|
||||
"reason_optional": "Raison (optionnel)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Prendre une photo",
|
||||
"camera_capture_shoot": "Prendre la photo",
|
||||
"camera_switch_lens": "Changer de caméra",
|
||||
"camera_switch_failed": "Aucune autre caméra n'a répondu — ce téléphone n'en expose qu'une. Utilisez le sélecteur de fichiers pour l'autre objectif.",
|
||||
"doc_drop_hint": "Déposez les fichiers ici",
|
||||
"doc_task_none": "Aucun document lié à cette tâche.",
|
||||
"doc_link_existing": "Lier un document…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "actif",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nouveau)",
|
||||
"adopt_object_hint": "Donnez le même nom d'objet à plusieurs capteurs et ils forment un seul objet ; saisissez le nom d'un objet existant pour les y ajouter.",
|
||||
"adopt_problem_adopt": "Adopter la sélection",
|
||||
"adopt_problem_done": "{tasks} capteur(s) de problème adopté(s)",
|
||||
"views_label": "Vues",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "कार्य ले जाया गया",
|
||||
"move_task_target": "लक्ष्य ऑब्जेक्ट",
|
||||
"move_task_message": "वह ऑब्जेक्ट चुनें जिससे यह कार्य जुड़ा होना चाहिए। इतिहास, रीडिंग और ट्रिगर स्थिति साथ जाएँगे; इसे नया संदर्भ नंबर मिलेगा और इसकी एंटिटी नए ऑब्जेक्ट के अंतर्गत फिर से बनेंगी। जुड़े दस्तावेज़ वर्तमान ऑब्जेक्ट के पास रहेंगे।",
|
||||
"bulk_move_message": "वह ऑब्जेक्ट चुनें जिससे चयनित कार्य जुड़ने चाहिए। जो पहले से वहाँ हैं उन्हें छोड़ दिया जाता है; इतिहास, रीडिंग और ट्रिगर स्थिति साथ में जाते हैं।",
|
||||
"bulk_moved": "{n} कार्य स्थानांतरित किए गए",
|
||||
"more_actions": "और कार्रवाइयाँ",
|
||||
"move_task_title": "कार्य ले जाएँ",
|
||||
"move_task": "दूसरे ऑब्जेक्ट में ले जाएँ…",
|
||||
"object_duplicated": "ऑब्जेक्ट डुप्लिकेट किया गया",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} चयनित",
|
||||
"bulk_completed": "{n} कार्य पूर्ण",
|
||||
"bulk_archived": "{n} कार्य संग्रहित",
|
||||
"bulk_delete_objects_confirm": "{n} ऑब्जेक्ट और उनके सभी कार्य हटाएँ? संग्रहित करने से उनका इतिहास बना रहता है।",
|
||||
"bulk_objects_deleted": "{n} ऑब्जेक्ट हटाए गए",
|
||||
"bulk_objects_archived": "{n} ऑब्जेक्ट संग्रहित किए गए",
|
||||
"completing": "पूर्ण किया जा रहा है…",
|
||||
"interval": "अंतराल",
|
||||
"warning": "चेतावनी",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "सप्ताह के दिन",
|
||||
"nth_weekday": "महीने का N-वाँ सप्ताह-दिन",
|
||||
"day_of_month": "महीने का दिन",
|
||||
"calendar": "कैलेंडर एंटिटी",
|
||||
"calendar_entity_label": "कैलेंडर",
|
||||
"calendar_entity_hint": "इस कैलेंडर की हर घटना पर एक बार, घटना की शुरुआत की तारीख को देय — पिछली बार पूरा करने के बाद की अगली घटना।",
|
||||
"calendar_entity_required": "एक कैलेंडर एंटिटी चुनें।",
|
||||
"recurrence_on_days": "दोहराएँ",
|
||||
"recurrence_occurrence": "घटना",
|
||||
"recurrence_weekday": "सप्ताह-दिन",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "कोई ऑब्जेक्ट स्वयं से लिंक नहीं हो सकता",
|
||||
"ws_err_too_early": "बहुत जल्दी — यह कार्य केवल नियत तारीख के करीब ही पूरा किया जा सकता है",
|
||||
"ws_err_invalid_search_template": "खोज लिंक {q} वाला http(s) URL होना चाहिए",
|
||||
"ws_err_invalid_icon": "सूचना आइकन एक mdi: नाम होना चाहिए, जैसे mdi:air-filter",
|
||||
"feat_schedule_time": "दिन का समय निर्धारण",
|
||||
"feat_schedule_time_desc": "कार्य मध्यरात्रि के बजाय दिन के एक विशिष्ट समय पर अतिदेय हो जाते हैं।",
|
||||
"schedule_time_toggle": "किसी निश्चित समय पर देय",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "वस्तु तालिका कॉलम",
|
||||
"objects_table_columns_hint": "चुनें कि वस्तु तालिका दृश्य में कौन से कॉलम दिखाई दें।",
|
||||
"custom_icon_optional": "आइकन (वैकल्पिक, उदा. mdi:wrench)",
|
||||
"notify_icon": "सूचना आइकन",
|
||||
"notify_icon_hint": "Android पर Companion ऐप में दिखता है। खाली = इस कार्य के रखरखाव प्रकार का आइकन ({default})।",
|
||||
"task_enabled": "कार्य सक्षम",
|
||||
"skip_reason_prompt": "इस कार्य को छोड़ें?",
|
||||
"reason_optional": "कारण (वैकल्पिक)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "फ़ोटो लें",
|
||||
"camera_capture_shoot": "कैप्चर करें",
|
||||
"camera_switch_lens": "कैमरा बदलें",
|
||||
"camera_switch_failed": "किसी अन्य कैमरे ने जवाब नहीं दिया — यह फ़ोन केवल एक ही देता है। दूसरे लेंस के लिए फ़ाइल चयनकर्ता का उपयोग करें।",
|
||||
"doc_drop_hint": "फ़ाइलें यहाँ छोड़ें",
|
||||
"doc_task_none": "इस कार्य से कोई दस्तावेज़ संबद्ध नहीं है।",
|
||||
"doc_link_existing": "दस्तावेज़ जोड़ें…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "सक्रिय",
|
||||
"adopt_problem_ok": "ठीक",
|
||||
"adopt_problem_new_object": "(नया)",
|
||||
"adopt_object_hint": "कई सेंसरों को एक ही ऑब्जेक्ट नाम दें तो वे एक ऑब्जेक्ट बन जाते हैं; मौजूदा ऑब्जेक्ट का नाम लिखें तो वे वहीं जुड़ जाते हैं।",
|
||||
"adopt_problem_adopt": "चयनित अपनाएँ",
|
||||
"adopt_problem_done": "{tasks} समस्या सेंसर अपनाए गए",
|
||||
"views_label": "व्यू",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Feladat áthelyezve",
|
||||
"move_task_target": "Célobjektum",
|
||||
"move_task_message": "Válaszd ki, melyik objektumhoz tartozzon ez a feladat. Az előzmények, a mérőállások és a trigger állapota vele költöznek; új hivatkozási számot kap, és az entitásai az új objektum alatt jönnek létre újra. A csatolt dokumentumok a jelenlegi objektumnál maradnak.",
|
||||
"bulk_move_message": "Válassza ki az objektumot, amelyhez a kijelölt feladatok tartozzanak. Az ott lévőket kihagyja; az előzmények, mérések és a kioldó állapota velük költöznek.",
|
||||
"bulk_moved": "{n} feladat áthelyezve",
|
||||
"more_actions": "További műveletek",
|
||||
"move_task_title": "Feladat áthelyezése",
|
||||
"move_task": "Áthelyezés másik objektumba…",
|
||||
"object_duplicated": "Objektum duplikálva",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} kijelölve",
|
||||
"bulk_completed": "{n} feladat elvégezve",
|
||||
"bulk_archived": "{n} feladat archiválva",
|
||||
"bulk_delete_objects_confirm": "Törli a(z) {n} objektumot az összes feladatával együtt? Az archiválás ehelyett megőrzi az előzményeket.",
|
||||
"bulk_objects_deleted": "{n} objektum törölve",
|
||||
"bulk_objects_archived": "{n} objektum archiválva",
|
||||
"completing": "Elvégzés…",
|
||||
"interval": "Intervallum",
|
||||
"warning": "Figyelmeztetés",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Hét napjai",
|
||||
"nth_weekday": "A hónap n. hétnapja",
|
||||
"day_of_month": "A hónap napja",
|
||||
"calendar": "Naptárentitás",
|
||||
"calendar_entity_label": "Naptár",
|
||||
"calendar_entity_hint": "A naptár minden eseményénél egyszer esedékes, az esemény kezdőnapján — az utolsó elvégzés utáni következő esemény.",
|
||||
"calendar_entity_required": "Válasszon egy naptárentitást.",
|
||||
"recurrence_on_days": "Ismétlés ezeken a napokon",
|
||||
"recurrence_occurrence": "Előfordulás",
|
||||
"recurrence_weekday": "Hét napja",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Egy objektum nem kapcsolható önmagához",
|
||||
"ws_err_too_early": "Túl korai — ez a feladat csak a határidőhöz közelebb fejezhető be",
|
||||
"ws_err_invalid_search_template": "A keresőhivatkozásnak {q}-t tartalmazó http(s) URL-nek kell lennie",
|
||||
"ws_err_invalid_icon": "Az értesítés ikonjának mdi: névnek kell lennie, pl. mdi:air-filter",
|
||||
"feat_schedule_time": "Napszakhoz kötött ütemezés",
|
||||
"feat_schedule_time_desc": "A feladatok nem éjfélkor, hanem egy megadott napszakban válnak lejárttá.",
|
||||
"schedule_time_toggle": "Adott időpontban esedékes",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Objektumtáblázat oszlopai",
|
||||
"objects_table_columns_hint": "Válassza ki, mely oszlopok jelenjenek meg az objektumok táblázatnézetében.",
|
||||
"custom_icon_optional": "Ikon (opcionális, pl. mdi:wrench)",
|
||||
"notify_icon": "Értesítés ikonja",
|
||||
"notify_icon_hint": "Az androidos Companion alkalmazás mutatja. Üres = a feladat karbantartási típusának ikonja ({default}).",
|
||||
"task_enabled": "Feladat engedélyezve",
|
||||
"skip_reason_prompt": "Kihagyja ezt a feladatot?",
|
||||
"reason_optional": "Indoklás (opcionális)",
|
||||
@@ -784,6 +797,7 @@
|
||||
"doc_camera": "Fotó készítése",
|
||||
"camera_capture_shoot": "Felvétel",
|
||||
"camera_switch_lens": "Kamera váltása",
|
||||
"camera_switch_failed": "Nem válaszolt másik kamera – ez a telefon csak egyet ad ki. A másik objektívhez használja a fájlválasztót.",
|
||||
"doc_drop_hint": "Húzza ide a fájlokat",
|
||||
"doc_task_none": "Ehhez a feladathoz nincs dokumentum csatolva.",
|
||||
"doc_link_existing": "Dokumentum hozzárendelése…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktív",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(új)",
|
||||
"adopt_object_hint": "Adja több érzékelőnek ugyanazt az objektumnevet, és egy objektummá válnak; meglévő objektum nevét beírva oda kerülnek.",
|
||||
"adopt_problem_adopt": "Kijelöltek átvétele",
|
||||
"adopt_problem_done": "{tasks} problémaérzékelő átvéve",
|
||||
"views_label": "Nézetek",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Attività spostata",
|
||||
"move_task_target": "Oggetto di destinazione",
|
||||
"move_task_message": "Scegli l'oggetto a cui deve appartenere questa attività. Storico, letture e stato del trigger si spostano con lei; riceve un nuovo numero di riferimento e le sue entità vengono ricreate sotto il nuovo oggetto. I documenti collegati restano con l'oggetto attuale.",
|
||||
"bulk_move_message": "Scegli l'oggetto a cui devono appartenere le attività selezionate. Quelle già presenti vengono saltate; cronologia, letture e stato del trigger si spostano insieme.",
|
||||
"bulk_moved": "{n} attività spostate",
|
||||
"more_actions": "Altre azioni",
|
||||
"move_task_title": "Sposta attività",
|
||||
"move_task": "Sposta in un altro oggetto…",
|
||||
"object_duplicated": "Oggetto duplicato",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} selezionati",
|
||||
"bulk_completed": "{n} attività completate",
|
||||
"bulk_archived": "{n} attività archiviate",
|
||||
"bulk_delete_objects_confirm": "Eliminare {n} oggetti con tutte le loro attività? L'archiviazione conserva invece la cronologia.",
|
||||
"bulk_objects_deleted": "{n} oggetti eliminati",
|
||||
"bulk_objects_archived": "{n} oggetti archiviati",
|
||||
"completing": "Completamento…",
|
||||
"interval": "Intervallo",
|
||||
"warning": "Avviso",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Giorni della settimana",
|
||||
"nth_weekday": "N-esimo giorno della settimana del mese",
|
||||
"day_of_month": "Giorno del mese",
|
||||
"calendar": "Entità calendario",
|
||||
"calendar_entity_label": "Calendario",
|
||||
"calendar_entity_hint": "Da fare una volta per ogni evento di questo calendario, nella data di inizio dell'evento — il prossimo evento dopo l'ultimo completamento.",
|
||||
"calendar_entity_required": "Scegli un'entità calendario.",
|
||||
"recurrence_on_days": "Ripeti il",
|
||||
"recurrence_occurrence": "Occorrenza",
|
||||
"recurrence_weekday": "Giorno della settimana",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Un oggetto non può essere collegato a sé stesso",
|
||||
"ws_err_too_early": "Troppo presto — questa attività può essere completata solo più vicino alla scadenza",
|
||||
"ws_err_invalid_search_template": "Il link di ricerca deve essere un URL http(s) contenente {q}",
|
||||
"ws_err_invalid_icon": "L'icona della notifica deve essere un nome mdi:, ad es. mdi:air-filter",
|
||||
"feat_schedule_time": "Pianificazione oraria",
|
||||
"feat_schedule_time_desc": "Le attività scadono a un'ora specifica anziché a mezzanotte.",
|
||||
"schedule_time_toggle": "Scadenza a un orario preciso",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Colonne tabella oggetti",
|
||||
"objects_table_columns_hint": "Scegli quali colonne mostrare nella vista tabella degli oggetti.",
|
||||
"custom_icon_optional": "Icona (opzionale, es. mdi:wrench)",
|
||||
"notify_icon": "Icona della notifica",
|
||||
"notify_icon_hint": "Mostrata dall'app Companion su Android. Vuoto = l'icona del tipo di manutenzione di questa attività ({default}).",
|
||||
"task_enabled": "Attività abilitata",
|
||||
"skip_reason_prompt": "Saltare questa attività?",
|
||||
"reason_optional": "Motivo (opzionale)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Scatta foto",
|
||||
"camera_capture_shoot": "Scatta",
|
||||
"camera_switch_lens": "Cambia fotocamera",
|
||||
"camera_switch_failed": "Nessun'altra fotocamera ha risposto: questo telefono ne espone una sola. Per l'altro obiettivo usa la selezione file.",
|
||||
"doc_drop_hint": "Trascina qui i file",
|
||||
"doc_task_none": "Nessun documento collegato a questa attività.",
|
||||
"doc_link_existing": "Collega un documento…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "attivo",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nuovo)",
|
||||
"adopt_object_hint": "Assegna lo stesso nome oggetto a più sensori e diventano un unico oggetto; digita il nome di un oggetto esistente per aggiungerli lì.",
|
||||
"adopt_problem_adopt": "Adotta selezionati",
|
||||
"adopt_problem_done": "{tasks} sensore/i di problema adottato/i",
|
||||
"views_label": "Viste",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "タスクを移動しました",
|
||||
"move_task_target": "移動先オブジェクト",
|
||||
"move_task_message": "このタスクを所属させるオブジェクトを選んでください。履歴・検針値・トリガー状態は一緒に移動し、新しい参照番号が付き、エンティティは新しいオブジェクトの下で作り直されます。関連付けた文書は現在のオブジェクトに残ります。",
|
||||
"bulk_move_message": "選択したタスクの所属先オブジェクトを選んでください。すでにそこにあるタスクはスキップされ、履歴・計測値・トリガー状態は一緒に移動します。",
|
||||
"bulk_moved": "{n} 件のタスクを移動しました",
|
||||
"more_actions": "その他の操作",
|
||||
"move_task_title": "タスクを移動",
|
||||
"move_task": "別のオブジェクトへ移動…",
|
||||
"object_duplicated": "オブジェクトを複製しました",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} 件選択",
|
||||
"bulk_completed": "{n} 件のタスクを完了",
|
||||
"bulk_archived": "{n} 件のタスクをアーカイブ",
|
||||
"bulk_delete_objects_confirm": "{n} 件のオブジェクトとそのすべてのタスクを削除しますか?アーカイブなら履歴が残ります。",
|
||||
"bulk_objects_deleted": "{n} 件のオブジェクトを削除しました",
|
||||
"bulk_objects_archived": "{n} 件のオブジェクトをアーカイブしました",
|
||||
"completing": "完了処理中…",
|
||||
"interval": "間隔",
|
||||
"warning": "警告",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "曜日",
|
||||
"nth_weekday": "毎月第N曜日",
|
||||
"day_of_month": "毎月の日",
|
||||
"calendar": "カレンダーエンティティ",
|
||||
"calendar_entity_label": "カレンダー",
|
||||
"calendar_entity_hint": "このカレンダーの予定ごとに1回、予定の開始日に期限を迎えます — 前回完了後の次の予定です。",
|
||||
"calendar_entity_required": "カレンダーエンティティを選択してください。",
|
||||
"recurrence_on_days": "繰り返す曜日",
|
||||
"recurrence_occurrence": "出現週",
|
||||
"recurrence_weekday": "曜日",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "オブジェクトを自分自身にリンクすることはできません",
|
||||
"ws_err_too_early": "早すぎます — このタスクは期日が近づいてからのみ完了できます",
|
||||
"ws_err_invalid_search_template": "検索リンクは {q} を含む http(s) URL である必要があります",
|
||||
"ws_err_invalid_icon": "通知アイコンは mdi: 名である必要があります(例: mdi:air-filter)",
|
||||
"feat_schedule_time": "時刻指定スケジュール",
|
||||
"feat_schedule_time_desc": "タスクが深夜0時ではなく指定した時刻に期限超過となります。",
|
||||
"schedule_time_toggle": "特定の時刻に期限",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "対象テーブルの列",
|
||||
"objects_table_columns_hint": "対象のテーブル表示に表示する列を選択します。",
|
||||
"custom_icon_optional": "アイコン(任意、例: mdi:wrench)",
|
||||
"notify_icon": "通知アイコン",
|
||||
"notify_icon_hint": "Android の Companion アプリに表示されます。空欄 = このタスクのメンテナンス種別のアイコン({default})。",
|
||||
"task_enabled": "タスク有効",
|
||||
"skip_reason_prompt": "このタスクをスキップしますか?",
|
||||
"reason_optional": "理由(任意)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "写真を撮る",
|
||||
"camera_capture_shoot": "撮影",
|
||||
"camera_switch_lens": "カメラを切り替え",
|
||||
"camera_switch_failed": "他のカメラが応答しませんでした。この端末は1台しか公開していません。別のレンズにはファイル選択を使ってください。",
|
||||
"doc_drop_hint": "ここにファイルをドロップ",
|
||||
"doc_task_none": "このタスクに紐付いたドキュメントはありません。",
|
||||
"doc_link_existing": "ドキュメントを紐付け…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "発生中",
|
||||
"adopt_problem_ok": "正常",
|
||||
"adopt_problem_new_object": "(新規)",
|
||||
"adopt_object_hint": "複数のセンサーに同じオブジェクト名を付けると1つのオブジェクトになります。既存のオブジェクト名を入力すればそこに追加されます。",
|
||||
"adopt_problem_adopt": "選択を取り込む",
|
||||
"adopt_problem_done": "{tasks} 件の問題センサーを取り込みました",
|
||||
"views_label": "ビュー",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "작업을 이동했습니다",
|
||||
"move_task_target": "대상 개체",
|
||||
"move_task_message": "이 작업이 속할 개체를 선택하세요. 이력, 검침값, 트리거 상태가 함께 이동하며 새 참조 번호를 받고 엔티티는 새 개체 아래에 다시 생성됩니다. 연결된 문서는 현재 개체에 남습니다.",
|
||||
"bulk_move_message": "선택한 작업이 속할 개체를 고르세요. 이미 그곳에 있는 작업은 건너뛰며 기록, 측정값, 트리거 상태가 함께 이동합니다.",
|
||||
"bulk_moved": "작업 {n}개 이동됨",
|
||||
"more_actions": "추가 작업",
|
||||
"move_task_title": "작업 이동",
|
||||
"move_task": "다른 개체로 이동…",
|
||||
"object_duplicated": "객체가 복제되었습니다",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n}개 선택됨",
|
||||
"bulk_completed": "작업 {n}개 완료됨",
|
||||
"bulk_archived": "작업 {n}개 보관됨",
|
||||
"bulk_delete_objects_confirm": "개체 {n}개와 모든 작업을 삭제할까요? 보관하면 기록이 유지됩니다.",
|
||||
"bulk_objects_deleted": "개체 {n}개 삭제됨",
|
||||
"bulk_objects_archived": "개체 {n}개 보관됨",
|
||||
"completing": "완료 처리 중…",
|
||||
"interval": "주기",
|
||||
"warning": "경고",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "요일",
|
||||
"nth_weekday": "매월 N번째 요일",
|
||||
"day_of_month": "매월 특정 일",
|
||||
"calendar": "캘린더 엔티티",
|
||||
"calendar_entity_label": "캘린더",
|
||||
"calendar_entity_hint": "이 캘린더의 이벤트마다 한 번, 이벤트 시작일에 기한이 됩니다 — 마지막 완료 이후의 다음 이벤트입니다.",
|
||||
"calendar_entity_required": "캘린더 엔티티를 선택하세요.",
|
||||
"recurrence_on_days": "반복 요일",
|
||||
"recurrence_occurrence": "회차",
|
||||
"recurrence_weekday": "요일",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "객체는 자기 자신에게 연결할 수 없음",
|
||||
"ws_err_too_early": "너무 이름 — 이 작업은 기한에 가까워져야 완료할 수 있습니다",
|
||||
"ws_err_invalid_search_template": "검색 링크는 {q}를 포함한 http(s) URL이어야 합니다",
|
||||
"ws_err_invalid_icon": "알림 아이콘은 mdi: 이름이어야 합니다(예: mdi:air-filter)",
|
||||
"feat_schedule_time": "시각 지정 일정",
|
||||
"feat_schedule_time_desc": "작업이 자정이 아닌 지정한 시각에 기한 초과로 전환됩니다.",
|
||||
"schedule_time_toggle": "특정 시각에 기한",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "객체 표 열",
|
||||
"objects_table_columns_hint": "객체 표 보기에 표시할 열을 선택하세요.",
|
||||
"custom_icon_optional": "아이콘 (선택, 예: mdi:wrench)",
|
||||
"notify_icon": "알림 아이콘",
|
||||
"notify_icon_hint": "Android의 Companion 앱에 표시됩니다. 비워 두면 이 작업의 유지보수 유형 아이콘({default})을 사용합니다.",
|
||||
"task_enabled": "작업 활성화",
|
||||
"skip_reason_prompt": "이 작업을 건너뛸까요?",
|
||||
"reason_optional": "사유 (선택)",
|
||||
@@ -784,6 +797,7 @@
|
||||
"doc_camera": "사진 촬영",
|
||||
"camera_capture_shoot": "촬영",
|
||||
"camera_switch_lens": "카메라 전환",
|
||||
"camera_switch_failed": "다른 카메라가 응답하지 않았습니다. 이 휴대폰은 하나만 제공합니다. 다른 렌즈는 파일 선택기를 사용하세요.",
|
||||
"doc_drop_hint": "파일을 여기에 놓으세요",
|
||||
"doc_task_none": "이 작업에 연결된 문서가 없습니다.",
|
||||
"doc_link_existing": "문서 연결…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "활성",
|
||||
"adopt_problem_ok": "정상",
|
||||
"adopt_problem_new_object": "(신규)",
|
||||
"adopt_object_hint": "여러 센서에 같은 개체 이름을 주면 하나의 개체가 됩니다. 기존 개체 이름을 입력하면 거기에 추가됩니다.",
|
||||
"adopt_problem_adopt": "선택 항목 가져오기",
|
||||
"adopt_problem_done": "문제 센서 {tasks}개를 가져왔습니다",
|
||||
"views_label": "보기",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Oppgave flyttet",
|
||||
"move_task_target": "Målobjekt",
|
||||
"move_task_message": "Velg objektet denne oppgaven skal tilhøre. Historikk, avlesninger og utløserstatus følger med; den får et nytt referansenummer, og entitetene opprettes på nytt under det nye objektet. Tilknyttede dokumenter blir hos det nåværende objektet.",
|
||||
"bulk_move_message": "Velg objektet de merkede oppgavene skal tilhøre. Oppgaver som allerede er der hoppes over; historikk, avlesninger og utløserstatus flytter med.",
|
||||
"bulk_moved": "{n} oppgaver flyttet",
|
||||
"more_actions": "Flere handlinger",
|
||||
"move_task_title": "Flytt oppgave",
|
||||
"move_task": "Flytt til et annet objekt…",
|
||||
"object_duplicated": "Objekt duplisert",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} valgt",
|
||||
"bulk_completed": "{n} oppgaver fullført",
|
||||
"bulk_archived": "{n} oppgaver arkivert",
|
||||
"bulk_delete_objects_confirm": "Slette {n} objekter og alle oppgavene deres? Arkivering beholder historikken i stedet.",
|
||||
"bulk_objects_deleted": "{n} objekter slettet",
|
||||
"bulk_objects_archived": "{n} objekter arkivert",
|
||||
"completing": "Fullfører…",
|
||||
"interval": "Intervall",
|
||||
"warning": "Advarsel",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Ukedager",
|
||||
"nth_weekday": "N-te ukedag i måneden",
|
||||
"day_of_month": "Dag i måneden",
|
||||
"calendar": "Kalenderentitet",
|
||||
"calendar_entity_label": "Kalender",
|
||||
"calendar_entity_hint": "Forfaller én gang per hendelse i denne kalenderen, på hendelsens startdato — neste hendelse etter siste utførelse.",
|
||||
"calendar_entity_required": "Velg en kalenderentitet.",
|
||||
"recurrence_on_days": "Gjenta på",
|
||||
"recurrence_occurrence": "Forekomst",
|
||||
"recurrence_weekday": "Ukedag",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Et objekt kan ikke kobles til seg selv",
|
||||
"ws_err_too_early": "For tidlig — oppgaven kan først fullføres nærmere forfallsdatoen",
|
||||
"ws_err_invalid_search_template": "Søkelenken må være en http(s)-URL som inneholder {q}",
|
||||
"ws_err_invalid_icon": "Varselikonet må være et mdi:-navn, f.eks. mdi:air-filter",
|
||||
"feat_schedule_time": "Planlegging med klokkeslett",
|
||||
"feat_schedule_time_desc": "Oppgaver forfaller på et bestemt klokkeslett i stedet for ved midnatt.",
|
||||
"schedule_time_toggle": "Forfaller på et bestemt klokkeslett",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Kolonner i objekttabell",
|
||||
"objects_table_columns_hint": "Velg hvilke kolonner som vises i tabellvisningen for objekter.",
|
||||
"custom_icon_optional": "Ikon (valgfritt, f.eks. mdi:wrench)",
|
||||
"notify_icon": "Varselikon",
|
||||
"notify_icon_hint": "Vises av Companion-appen på Android. Tom = ikonet for oppgavens vedlikeholdstype ({default}).",
|
||||
"task_enabled": "Oppgave aktivert",
|
||||
"skip_reason_prompt": "Hoppe over denne oppgaven?",
|
||||
"reason_optional": "Årsak (valgfritt)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Ta bilde",
|
||||
"camera_capture_shoot": "Ta bilde",
|
||||
"camera_switch_lens": "Bytt kamera",
|
||||
"camera_switch_failed": "Ingen andre kameraer svarte – denne telefonen gir bare fra seg ett. Bruk filvelgeren for det andre objektivet.",
|
||||
"doc_drop_hint": "Slipp filer her",
|
||||
"doc_task_none": "Ingen dokumenter knyttet til denne oppgaven.",
|
||||
"doc_link_existing": "Knytt et dokument…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktiv",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(ny)",
|
||||
"adopt_object_hint": "Gi flere sensorer samme objektnavn, så blir de ett objekt; skriv navnet på et eksisterende objekt for å legge dem der.",
|
||||
"adopt_problem_adopt": "Ta i bruk valgte",
|
||||
"adopt_problem_done": "Tok i bruk {tasks} problemsensor(er)",
|
||||
"views_label": "Visninger",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Taak verplaatst",
|
||||
"move_task_target": "Doelobject",
|
||||
"move_task_message": "Kies het object waar deze taak bij hoort. Geschiedenis, meterstanden en triggerstatus verhuizen mee; de taak krijgt een nieuw referentienummer en haar entiteiten worden onder het nieuwe object opnieuw aangemaakt. Gekoppelde documenten blijven bij het huidige object.",
|
||||
"bulk_move_message": "Kies het object waartoe de geselecteerde taken moeten behoren. Taken die daar al staan worden overgeslagen; geschiedenis, meetwaarden en triggerstatus verhuizen mee.",
|
||||
"bulk_moved": "{n} taken verplaatst",
|
||||
"more_actions": "Meer acties",
|
||||
"move_task_title": "Taak verplaatsen",
|
||||
"move_task": "Naar ander object verplaatsen…",
|
||||
"object_duplicated": "Object gedupliceerd",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} geselecteerd",
|
||||
"bulk_completed": "{n} taken voltooid",
|
||||
"bulk_archived": "{n} taken gearchiveerd",
|
||||
"bulk_delete_objects_confirm": "{n} objecten met al hun taken verwijderen? Archiveren bewaart in plaats daarvan de geschiedenis.",
|
||||
"bulk_objects_deleted": "{n} objecten verwijderd",
|
||||
"bulk_objects_archived": "{n} objecten gearchiveerd",
|
||||
"completing": "Wordt voltooid…",
|
||||
"interval": "Interval",
|
||||
"warning": "Waarschuwing",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Weekdagen",
|
||||
"nth_weekday": "Zoveelste weekdag van de maand",
|
||||
"day_of_month": "Dag van de maand",
|
||||
"calendar": "Kalender-entiteit",
|
||||
"calendar_entity_label": "Kalender",
|
||||
"calendar_entity_hint": "Eén keer per gebeurtenis van deze kalender, op de startdatum van de gebeurtenis — de volgende gebeurtenis na de laatste afronding.",
|
||||
"calendar_entity_required": "Kies een kalender-entiteit.",
|
||||
"recurrence_on_days": "Herhalen op",
|
||||
"recurrence_occurrence": "Voorkomen",
|
||||
"recurrence_weekday": "Weekdag",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Een object kan niet aan zichzelf worden gekoppeld",
|
||||
"ws_err_too_early": "Te vroeg — deze taak kan pas dichter bij de vervaldatum worden afgerond",
|
||||
"ws_err_invalid_search_template": "De zoeklink moet een http(s)-URL met {q} zijn",
|
||||
"ws_err_invalid_icon": "Het meldingspictogram moet een mdi:-naam zijn, bijv. mdi:air-filter",
|
||||
"feat_schedule_time": "Tijd-van-dag-planning",
|
||||
"feat_schedule_time_desc": "Taken vervallen op een specifieke tijd in plaats van middernacht.",
|
||||
"schedule_time_toggle": "Vervalt op een vast tijdstip",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Kolommen objecttabel",
|
||||
"objects_table_columns_hint": "Kies welke kolommen in de tabelweergave van objecten verschijnen.",
|
||||
"custom_icon_optional": "Icoon (optioneel, bijv. mdi:wrench)",
|
||||
"notify_icon": "Meldingspictogram",
|
||||
"notify_icon_hint": "Getoond door de Companion-app op Android. Leeg = het pictogram van het onderhoudstype van deze taak ({default}).",
|
||||
"task_enabled": "Taak ingeschakeld",
|
||||
"skip_reason_prompt": "Deze taak overslaan?",
|
||||
"reason_optional": "Reden (optioneel)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Foto maken",
|
||||
"camera_capture_shoot": "Vastleggen",
|
||||
"camera_switch_lens": "Camera wisselen",
|
||||
"camera_switch_failed": "Geen andere camera reageerde — deze telefoon geeft er maar één vrij. Gebruik de bestandskiezer voor de andere lens.",
|
||||
"doc_drop_hint": "Sleep bestanden hierheen",
|
||||
"doc_task_none": "Geen documenten aan deze taak gekoppeld.",
|
||||
"doc_link_existing": "Document koppelen…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "actief",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nieuw)",
|
||||
"adopt_object_hint": "Geef meerdere sensoren dezelfde objectnaam en ze worden één object; typ de naam van een bestaand object om ze daar toe te voegen.",
|
||||
"adopt_problem_adopt": "Selectie overnemen",
|
||||
"adopt_problem_done": "{tasks} probleemsensor(en) overgenomen",
|
||||
"views_label": "Weergaven",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Zadanie przeniesione",
|
||||
"move_task_target": "Obiekt docelowy",
|
||||
"move_task_message": "Wybierz obiekt, do którego ma należeć to zadanie. Historia, odczyty i stan wyzwalacza przenoszą się razem z nim; dostaje nowy numer referencyjny, a jego encje są tworzone na nowo pod nowym obiektem. Powiązane dokumenty zostają przy obecnym obiekcie.",
|
||||
"bulk_move_message": "Wybierz obiekt, do którego mają należeć zaznaczone zadania. Te, które już tam są, zostaną pominięte; historia, odczyty i stan wyzwalacza przenoszą się razem.",
|
||||
"bulk_moved": "Przeniesiono zadań: {n}",
|
||||
"more_actions": "Więcej działań",
|
||||
"move_task_title": "Przenieś zadanie",
|
||||
"move_task": "Przenieś do innego obiektu…",
|
||||
"object_duplicated": "Obiekt zduplikowany",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "Zaznaczono {n}",
|
||||
"bulk_completed": "Ukończono {n} zadań",
|
||||
"bulk_archived": "Zarchiwizowano {n} zadań",
|
||||
"bulk_delete_objects_confirm": "Usunąć {n} obiektów wraz ze wszystkimi zadaniami? Archiwizacja zachowa ich historię.",
|
||||
"bulk_objects_deleted": "Usunięto obiektów: {n}",
|
||||
"bulk_objects_archived": "Zarchiwizowano obiektów: {n}",
|
||||
"completing": "Wykonywanie…",
|
||||
"interval": "Interwał",
|
||||
"warning": "Ostrzeżenie",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Dni tygodnia",
|
||||
"nth_weekday": "N-ty dzień tygodnia w miesiącu",
|
||||
"day_of_month": "Dzień miesiąca",
|
||||
"calendar": "Encja kalendarza",
|
||||
"calendar_entity_label": "Kalendarz",
|
||||
"calendar_entity_hint": "Termin przypada raz na każde wydarzenie z tego kalendarza, w dniu rozpoczęcia wydarzenia — następne wydarzenie po ostatnim wykonaniu.",
|
||||
"calendar_entity_required": "Wybierz encję kalendarza.",
|
||||
"recurrence_on_days": "Powtarzaj w",
|
||||
"recurrence_occurrence": "Wystąpienie",
|
||||
"recurrence_weekday": "Dzień tygodnia",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Obiekt nie może być powiązany sam ze sobą",
|
||||
"ws_err_too_early": "Za wcześnie — to zadanie można ukończyć dopiero bliżej terminu",
|
||||
"ws_err_invalid_search_template": "Link wyszukiwania musi być adresem URL http(s) zawierającym {q}",
|
||||
"ws_err_invalid_icon": "Ikona powiadomienia musi być nazwą mdi:, np. mdi:air-filter",
|
||||
"feat_schedule_time": "Harmonogram według pory dnia",
|
||||
"feat_schedule_time_desc": "Zadania stają się zaległe o określonej porze dnia zamiast o północy.",
|
||||
"schedule_time_toggle": "Termin o określonej godzinie",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Kolumny tabeli obiektów",
|
||||
"objects_table_columns_hint": "Wybierz, które kolumny mają być widoczne w widoku tabeli obiektów.",
|
||||
"custom_icon_optional": "Ikona (opcjonalna, np. mdi:wrench)",
|
||||
"notify_icon": "Ikona powiadomienia",
|
||||
"notify_icon_hint": "Wyświetlana przez aplikację Companion na Androidzie. Puste = ikona typu konserwacji tego zadania ({default}).",
|
||||
"task_enabled": "Zadanie włączone",
|
||||
"skip_reason_prompt": "Pominąć to zadanie?",
|
||||
"reason_optional": "Powód (opcjonalny)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Zrób zdjęcie",
|
||||
"camera_capture_shoot": "Zrób zdjęcie",
|
||||
"camera_switch_lens": "Przełącz kamerę",
|
||||
"camera_switch_failed": "Żadna inna kamera nie odpowiedziała — ten telefon udostępnia tylko jedną. Dla drugiego obiektywu użyj wyboru pliku.",
|
||||
"doc_drop_hint": "Upuść pliki tutaj",
|
||||
"doc_task_none": "Brak dokumentów powiązanych z tym zadaniem.",
|
||||
"doc_link_existing": "Powiąż dokument…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktywny",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nowy)",
|
||||
"adopt_object_hint": "Nadaj kilku czujnikom tę samą nazwę obiektu, a staną się jednym obiektem; wpisz nazwę istniejącego obiektu, aby je tam dodać.",
|
||||
"adopt_problem_adopt": "Przejmij zaznaczone",
|
||||
"adopt_problem_done": "Przejęto {tasks} czujnik(ów) problemów",
|
||||
"views_label": "Widoki",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Tarefa movida",
|
||||
"move_task_target": "Objeto de destino",
|
||||
"move_task_message": "Escolha o objeto ao qual esta tarefa deve pertencer. Histórico, leituras e estado do gatilho vão junto; ela recebe um novo número de referência e suas entidades são recriadas no novo objeto. Documentos vinculados permanecem no objeto atual.",
|
||||
"bulk_move_message": "Escolha o objeto ao qual as tarefas selecionadas devem pertencer. As que já estão lá são ignoradas; histórico, leituras e estado do gatilho vão junto.",
|
||||
"bulk_moved": "{n} tarefas movidas",
|
||||
"more_actions": "Mais ações",
|
||||
"move_task_title": "Mover tarefa",
|
||||
"move_task": "Mover para outro objeto…",
|
||||
"object_duplicated": "Objeto duplicado",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} selecionadas",
|
||||
"bulk_completed": "{n} tarefas concluídas",
|
||||
"bulk_archived": "{n} tarefas arquivadas",
|
||||
"bulk_delete_objects_confirm": "Excluir {n} objetos e todas as suas tarefas? Arquivar mantém o histórico.",
|
||||
"bulk_objects_deleted": "{n} objetos excluídos",
|
||||
"bulk_objects_archived": "{n} objetos arquivados",
|
||||
"completing": "Concluindo…",
|
||||
"interval": "Intervalo",
|
||||
"warning": "Aviso",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Dias da semana",
|
||||
"nth_weekday": "Enésimo dia da semana do mês",
|
||||
"day_of_month": "Dia do mês",
|
||||
"calendar": "Entidade de calendário",
|
||||
"calendar_entity_label": "Calendário",
|
||||
"calendar_entity_hint": "Vence uma vez por evento deste calendário, na data de início do evento — o próximo evento após a última conclusão.",
|
||||
"calendar_entity_required": "Escolha uma entidade de calendário.",
|
||||
"recurrence_on_days": "Repetir em",
|
||||
"recurrence_occurrence": "Ocorrência",
|
||||
"recurrence_weekday": "Dia da semana",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Um objeto não pode ser vinculado a si mesmo",
|
||||
"ws_err_too_early": "Cedo demais — esta tarefa só pode ser concluída mais perto do vencimento",
|
||||
"ws_err_invalid_search_template": "O link de busca deve ser uma URL http(s) contendo {q}",
|
||||
"ws_err_invalid_icon": "O ícone da notificação deve ser um nome mdi:, por ex. mdi:air-filter",
|
||||
"feat_schedule_time": "Agendamento por horário",
|
||||
"feat_schedule_time_desc": "As tarefas ficam atrasadas em um horário específico do dia, em vez de à meia-noite.",
|
||||
"schedule_time_toggle": "Vence em um horário específico",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Colunas da tabela de objetos",
|
||||
"objects_table_columns_hint": "Escolha quais colunas aparecem na visualização em tabela dos objetos.",
|
||||
"custom_icon_optional": "Ícone (opcional, ex.: mdi:wrench)",
|
||||
"notify_icon": "Ícone da notificação",
|
||||
"notify_icon_hint": "Exibido pelo app Companion no Android. Vazio = o ícone do tipo de manutenção desta tarefa ({default}).",
|
||||
"task_enabled": "Tarefa ativada",
|
||||
"skip_reason_prompt": "Pular esta tarefa?",
|
||||
"reason_optional": "Motivo (opcional)",
|
||||
@@ -784,6 +797,7 @@
|
||||
"doc_camera": "Tirar foto",
|
||||
"camera_capture_shoot": "Capturar",
|
||||
"camera_switch_lens": "Trocar de câmera",
|
||||
"camera_switch_failed": "Nenhuma outra câmera respondeu — este celular libera só uma. Use o seletor de arquivos para a outra lente.",
|
||||
"doc_drop_hint": "Solte os arquivos aqui",
|
||||
"doc_task_none": "Nenhum documento vinculado a esta tarefa.",
|
||||
"doc_link_existing": "Vincular um documento…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "ativo",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(novo)",
|
||||
"adopt_object_hint": "Dê a vários sensores o mesmo nome de objeto e eles viram um único objeto; digite o nome de um objeto existente para adicioná-los lá.",
|
||||
"adopt_problem_adopt": "Adotar selecionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adotado(s)",
|
||||
"views_label": "Visualizações",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Tarefa movida",
|
||||
"move_task_target": "Objeto de destino",
|
||||
"move_task_message": "Escolha o objeto a que esta tarefa deve pertencer. O histórico, as leituras e o estado do gatilho vão com ela; recebe um novo número de referência e as suas entidades são recriadas no novo objeto. Os documentos ligados ficam no objeto atual.",
|
||||
"bulk_move_message": "Escolha o objeto a que as tarefas selecionadas devem pertencer. As que já lá estão são ignoradas; histórico, leituras e estado do gatilho acompanham.",
|
||||
"bulk_moved": "{n} tarefas movidas",
|
||||
"more_actions": "Mais ações",
|
||||
"move_task_title": "Mover tarefa",
|
||||
"move_task": "Mover para outro objeto…",
|
||||
"object_duplicated": "Objeto duplicado",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} selecionados",
|
||||
"bulk_completed": "{n} tarefas concluídas",
|
||||
"bulk_archived": "{n} tarefas arquivadas",
|
||||
"bulk_delete_objects_confirm": "Eliminar {n} objetos e todas as suas tarefas? Arquivar mantém o histórico.",
|
||||
"bulk_objects_deleted": "{n} objetos eliminados",
|
||||
"bulk_objects_archived": "{n} objetos arquivados",
|
||||
"completing": "A concluir…",
|
||||
"interval": "Intervalo",
|
||||
"warning": "Aviso",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Dias da semana",
|
||||
"nth_weekday": "N-ésimo dia da semana do mês",
|
||||
"day_of_month": "Dia do mês",
|
||||
"calendar": "Entidade de calendário",
|
||||
"calendar_entity_label": "Calendário",
|
||||
"calendar_entity_hint": "Vence uma vez por evento deste calendário, na data de início do evento — o próximo evento após a última conclusão.",
|
||||
"calendar_entity_required": "Escolha uma entidade de calendário.",
|
||||
"recurrence_on_days": "Repetir em",
|
||||
"recurrence_occurrence": "Ocorrência",
|
||||
"recurrence_weekday": "Dia da semana",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Um objeto não pode ser ligado a si próprio",
|
||||
"ws_err_too_early": "Demasiado cedo — esta tarefa só pode ser concluída mais perto do prazo",
|
||||
"ws_err_invalid_search_template": "A ligação de pesquisa tem de ser um URL http(s) com {q}",
|
||||
"ws_err_invalid_icon": "O ícone da notificação tem de ser um nome mdi:, p. ex. mdi:air-filter",
|
||||
"feat_schedule_time": "Agendamento por hora",
|
||||
"feat_schedule_time_desc": "Tarefas vencem em um horário específico em vez de meia-noite.",
|
||||
"schedule_time_toggle": "Vence a uma hora específica",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Colunas da tabela de objetos",
|
||||
"objects_table_columns_hint": "Escolha que colunas aparecem na vista de tabela de objetos.",
|
||||
"custom_icon_optional": "Ícone (opcional, ex. mdi:wrench)",
|
||||
"notify_icon": "Ícone da notificação",
|
||||
"notify_icon_hint": "Mostrado pela app Companion no Android. Vazio = o ícone do tipo de manutenção desta tarefa ({default}).",
|
||||
"task_enabled": "Tarefa ativada",
|
||||
"skip_reason_prompt": "Saltar esta tarefa?",
|
||||
"reason_optional": "Motivo (opcional)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Tirar foto",
|
||||
"camera_capture_shoot": "Capturar",
|
||||
"camera_switch_lens": "Mudar de câmara",
|
||||
"camera_switch_failed": "Nenhuma outra câmara respondeu — este telemóvel só disponibiliza uma. Use o seletor de ficheiros para a outra objetiva.",
|
||||
"doc_drop_hint": "Solte os ficheiros aqui",
|
||||
"doc_task_none": "Nenhum documento associado a esta tarefa.",
|
||||
"doc_link_existing": "Associar um documento…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "ativo",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(novo)",
|
||||
"adopt_object_hint": "Dê a vários sensores o mesmo nome de objeto e tornam-se um só objeto; escreva o nome de um objeto existente para os juntar lá.",
|
||||
"adopt_problem_adopt": "Adotar selecionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adotado(s)",
|
||||
"views_label": "Vistas",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Задача перемещена",
|
||||
"move_task_target": "Целевой объект",
|
||||
"move_task_message": "Выберите объект, к которому должна относиться эта задача. История, показания и состояние триггера переедут вместе с ней; она получит новый номер, а её сущности будут созданы заново под новым объектом. Привязанные документы остаются у текущего объекта.",
|
||||
"bulk_move_message": "Выберите объект, к которому должны относиться выбранные задачи. Уже находящиеся там пропускаются; история, показания и состояние триггера переносятся.",
|
||||
"bulk_moved": "Перемещено задач: {n}",
|
||||
"more_actions": "Другие действия",
|
||||
"move_task_title": "Переместить задачу",
|
||||
"move_task": "Переместить в другой объект…",
|
||||
"object_duplicated": "Объект продублирован",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "Выбрано: {n}",
|
||||
"bulk_completed": "Выполнено задач: {n}",
|
||||
"bulk_archived": "Архивировано задач: {n}",
|
||||
"bulk_delete_objects_confirm": "Удалить {n} объектов со всеми их задачами? Архивация вместо этого сохранит историю.",
|
||||
"bulk_objects_deleted": "Удалено объектов: {n}",
|
||||
"bulk_objects_archived": "Архивировано объектов: {n}",
|
||||
"completing": "Выполнение…",
|
||||
"interval": "Интервал",
|
||||
"warning": "Предупреждение",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Дни недели",
|
||||
"nth_weekday": "N-й день недели месяца",
|
||||
"day_of_month": "День месяца",
|
||||
"calendar": "Сущность календаря",
|
||||
"calendar_entity_label": "Календарь",
|
||||
"calendar_entity_hint": "Срок наступает один раз на каждое событие этого календаря, в дату начала события — следующее событие после последнего выполнения.",
|
||||
"calendar_entity_required": "Выберите сущность календаря.",
|
||||
"recurrence_on_days": "Повторять в",
|
||||
"recurrence_occurrence": "Вхождение",
|
||||
"recurrence_weekday": "День недели",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Объект нельзя связать с самим собой",
|
||||
"ws_err_too_early": "Слишком рано — эту задачу можно завершить только ближе к сроку",
|
||||
"ws_err_invalid_search_template": "Ссылка для поиска должна быть URL http(s) с {q}",
|
||||
"ws_err_invalid_icon": "Значок уведомления должен быть именем mdi:, например mdi:air-filter",
|
||||
"feat_schedule_time": "Планирование по времени дня",
|
||||
"feat_schedule_time_desc": "Задачи становятся просроченными в определённое время дня, а не в полночь.",
|
||||
"schedule_time_toggle": "Срок в определённое время",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Столбцы таблицы объектов",
|
||||
"objects_table_columns_hint": "Выберите, какие столбцы показывать в табличном виде объектов.",
|
||||
"custom_icon_optional": "Иконка (опционально, например mdi:wrench)",
|
||||
"notify_icon": "Значок уведомления",
|
||||
"notify_icon_hint": "Показывается приложением Companion на Android. Пусто = значок типа обслуживания этой задачи ({default}).",
|
||||
"task_enabled": "Задача включена",
|
||||
"skip_reason_prompt": "Пропустить эту задачу?",
|
||||
"reason_optional": "Причина (опционально)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Сделать фото",
|
||||
"camera_capture_shoot": "Снять",
|
||||
"camera_switch_lens": "Сменить камеру",
|
||||
"camera_switch_failed": "Другая камера не ответила — этот телефон отдаёт только одну. Для другого объектива используйте выбор файла.",
|
||||
"doc_drop_hint": "Перетащите файлы сюда",
|
||||
"doc_task_none": "Нет документов, связанных с этой задачей.",
|
||||
"doc_link_existing": "Связать документ…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "активна",
|
||||
"adopt_problem_ok": "норма",
|
||||
"adopt_problem_new_object": "(новый)",
|
||||
"adopt_object_hint": "Дайте нескольким датчикам одно имя объекта — они станут одним объектом; введите имя существующего объекта, чтобы добавить их туда.",
|
||||
"adopt_problem_adopt": "Принять выбранные",
|
||||
"adopt_problem_done": "Принято сенсоров проблем: {tasks}",
|
||||
"views_label": "Представления",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Uppgift flyttad",
|
||||
"move_task_target": "Målobjekt",
|
||||
"move_task_message": "Välj vilket objekt uppgiften ska tillhöra. Historik, avläsningar och utlösarstatus följer med; den får ett nytt referensnummer och dess entiteter skapas om under det nya objektet. Länkade dokument stannar hos det nuvarande objektet.",
|
||||
"bulk_move_message": "Välj det objekt som de markerade uppgifterna ska tillhöra. Uppgifter som redan finns där hoppas över; historik, avläsningar och utlösarstatus följer med.",
|
||||
"bulk_moved": "{n} uppgifter flyttade",
|
||||
"more_actions": "Fler åtgärder",
|
||||
"move_task_title": "Flytta uppgift",
|
||||
"move_task": "Flytta till ett annat objekt…",
|
||||
"object_duplicated": "Objekt duplicerat",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} valda",
|
||||
"bulk_completed": "{n} uppgifter slutförda",
|
||||
"bulk_archived": "{n} uppgifter arkiverade",
|
||||
"bulk_delete_objects_confirm": "Ta bort {n} objekt och alla deras uppgifter? Arkivering behåller historiken i stället.",
|
||||
"bulk_objects_deleted": "{n} objekt borttagna",
|
||||
"bulk_objects_archived": "{n} objekt arkiverade",
|
||||
"completing": "Slutför…",
|
||||
"interval": "Intervall",
|
||||
"warning": "Varning",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Veckodagar",
|
||||
"nth_weekday": "N:te veckodag i månaden",
|
||||
"day_of_month": "Dag i månaden",
|
||||
"calendar": "Kalenderentitet",
|
||||
"calendar_entity_label": "Kalender",
|
||||
"calendar_entity_hint": "Förfaller en gång per händelse i den här kalendern, på händelsens startdatum — nästa händelse efter det senaste utförandet.",
|
||||
"calendar_entity_required": "Välj en kalenderentitet.",
|
||||
"recurrence_on_days": "Upprepa på",
|
||||
"recurrence_occurrence": "Förekomst",
|
||||
"recurrence_weekday": "Veckodag",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Ett objekt kan inte länkas till sig självt",
|
||||
"ws_err_too_early": "För tidigt — uppgiften kan bara slutföras närmare förfallodatumet",
|
||||
"ws_err_invalid_search_template": "Söklänken måste vara en http(s)-URL som innehåller {q}",
|
||||
"ws_err_invalid_icon": "Aviseringsikonen måste vara ett mdi:-namn, t.ex. mdi:air-filter",
|
||||
"feat_schedule_time": "Schemaläggning per tid på dygnet",
|
||||
"feat_schedule_time_desc": "Uppgifter blir försenade vid en specifik tid på dygnet istället för midnatt.",
|
||||
"schedule_time_toggle": "Förfaller vid en viss tid",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Kolumner i objekttabell",
|
||||
"objects_table_columns_hint": "Välj vilka kolumner som visas i objekttabellvyn.",
|
||||
"custom_icon_optional": "Ikon (valfritt, t.ex. mdi:wrench)",
|
||||
"notify_icon": "Aviseringsikon",
|
||||
"notify_icon_hint": "Visas av Companion-appen på Android. Tomt = ikonen för uppgiftens underhållstyp ({default}).",
|
||||
"task_enabled": "Uppgift aktiverad",
|
||||
"skip_reason_prompt": "Hoppa över denna uppgift?",
|
||||
"reason_optional": "Anledning (valfritt)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Ta foto",
|
||||
"camera_capture_shoot": "Ta bild",
|
||||
"camera_switch_lens": "Byt kamera",
|
||||
"camera_switch_failed": "Ingen annan kamera svarade – den här telefonen lämnar bara ut en. Använd filväljaren för det andra objektivet.",
|
||||
"doc_drop_hint": "Släpp filer här",
|
||||
"doc_task_none": "Inga dokument kopplade till denna uppgift.",
|
||||
"doc_link_existing": "Koppla ett dokument…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktiv",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(ny)",
|
||||
"adopt_object_hint": "Ge flera sensorer samma objektnamn så blir de ett objekt; skriv ett befintligt objekts namn för att lägga dem där.",
|
||||
"adopt_problem_adopt": "Anta valda",
|
||||
"adopt_problem_done": "Antog {tasks} problemsensor(er)",
|
||||
"views_label": "Vyer",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Görev taşındı",
|
||||
"move_task_target": "Hedef nesne",
|
||||
"move_task_message": "Bu görevin ait olacağı nesneyi seçin. Geçmiş, okumalar ve tetikleyici durumu birlikte taşınır; yeni bir referans numarası alır ve varlıkları yeni nesne altında yeniden oluşturulur. Bağlı belgeler mevcut nesnede kalır.",
|
||||
"bulk_move_message": "Seçili görevlerin ait olacağı nesneyi seçin. Zaten orada olanlar atlanır; geçmiş, okumalar ve tetikleyici durumu birlikte taşınır.",
|
||||
"bulk_moved": "{n} görev taşındı",
|
||||
"more_actions": "Diğer işlemler",
|
||||
"move_task_title": "Görevi taşı",
|
||||
"move_task": "Başka bir nesneye taşı…",
|
||||
"object_duplicated": "Nesne çoğaltıldı",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} seçildi",
|
||||
"bulk_completed": "{n} görev tamamlandı",
|
||||
"bulk_archived": "{n} görev arşivlendi",
|
||||
"bulk_delete_objects_confirm": "{n} nesne ve tüm görevleri silinsin mi? Arşivlemek geçmişi korur.",
|
||||
"bulk_objects_deleted": "{n} nesne silindi",
|
||||
"bulk_objects_archived": "{n} nesne arşivlendi",
|
||||
"completing": "Tamamlanıyor…",
|
||||
"interval": "Aralık",
|
||||
"warning": "Uyarı",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Haftanın günleri",
|
||||
"nth_weekday": "Ayın n. hafta günü",
|
||||
"day_of_month": "Ayın günü",
|
||||
"calendar": "Takvim varlığı",
|
||||
"calendar_entity_label": "Takvim",
|
||||
"calendar_entity_hint": "Bu takvimin her etkinliği için bir kez, etkinliğin başlangıç tarihinde vadesi gelir — son tamamlamadan sonraki bir sonraki etkinlik.",
|
||||
"calendar_entity_required": "Bir takvim varlığı seçin.",
|
||||
"recurrence_on_days": "Tekrar günleri",
|
||||
"recurrence_occurrence": "Kaçıncı",
|
||||
"recurrence_weekday": "Haftanın günü",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Bir nesne kendisine bağlanamaz",
|
||||
"ws_err_too_early": "Çok erken — bu görev ancak son tarihine yaklaşınca tamamlanabilir",
|
||||
"ws_err_invalid_search_template": "Arama bağlantısı {q} içeren bir http(s) URL olmalıdır",
|
||||
"ws_err_invalid_icon": "Bildirim simgesi bir mdi: adı olmalıdır, örn. mdi:air-filter",
|
||||
"feat_schedule_time": "Gün içi saat zamanlaması",
|
||||
"feat_schedule_time_desc": "Görevler gece yarısı yerine günün belirli bir saatinde gecikmiş olur.",
|
||||
"schedule_time_toggle": "Belirli bir saatte vadesi dolar",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Nesne tablosu sütunları",
|
||||
"objects_table_columns_hint": "Nesne tablosu görünümünde hangi sütunların görüneceğini seçin.",
|
||||
"custom_icon_optional": "Simge (isteğe bağlı, örn. mdi:wrench)",
|
||||
"notify_icon": "Bildirim simgesi",
|
||||
"notify_icon_hint": "Android'de Companion uygulamasında gösterilir. Boş = bu görevin bakım türünün simgesi ({default}).",
|
||||
"task_enabled": "Görev etkin",
|
||||
"skip_reason_prompt": "Bu görev atlansın mı?",
|
||||
"reason_optional": "Neden (isteğe bağlı)",
|
||||
@@ -784,6 +797,7 @@
|
||||
"doc_camera": "Fotoğraf çek",
|
||||
"camera_capture_shoot": "Çek",
|
||||
"camera_switch_lens": "Kamerayı değiştir",
|
||||
"camera_switch_failed": "Başka bir kamera yanıt vermedi — bu telefon yalnızca birini açıyor. Diğer lens için dosya seçiciyi kullanın.",
|
||||
"doc_drop_hint": "Dosyaları buraya bırakın",
|
||||
"doc_task_none": "Bu göreve bağlı belge yok.",
|
||||
"doc_link_existing": "Belge bağla…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "etkin",
|
||||
"adopt_problem_ok": "tamam",
|
||||
"adopt_problem_new_object": "(yeni)",
|
||||
"adopt_object_hint": "Birden çok sensöre aynı nesne adını verin, tek nesne olurlar; mevcut bir nesnenin adını yazarsanız oraya eklenirler.",
|
||||
"adopt_problem_adopt": "Seçilenleri devral",
|
||||
"adopt_problem_done": "{tasks} sorun sensörü devralındı",
|
||||
"views_label": "Görünümler",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Завдання переміщено",
|
||||
"move_task_target": "Цільовий об'єкт",
|
||||
"move_task_message": "Виберіть об'єкт, до якого має належати це завдання. Історія, показники та стан тригера переїдуть разом із ним; воно отримає новий номер, а його сутності буде створено заново під новим об'єктом. Прив'язані документи залишаться в поточному об'єкті.",
|
||||
"bulk_move_message": "Виберіть об'єкт, до якого мають належати вибрані завдання. Ті, що вже там, пропускаються; історія, показники та стан тригера переносяться.",
|
||||
"bulk_moved": "Переміщено завдань: {n}",
|
||||
"more_actions": "Інші дії",
|
||||
"move_task_title": "Перемістити завдання",
|
||||
"move_task": "Перемістити до іншого об'єкта…",
|
||||
"object_duplicated": "Об'єкт продубльовано",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "Вибрано: {n}",
|
||||
"bulk_completed": "Виконано завдань: {n}",
|
||||
"bulk_archived": "Архівовано завдань: {n}",
|
||||
"bulk_delete_objects_confirm": "Видалити {n} об'єктів з усіма їхніми завданнями? Архівування натомість збереже історію.",
|
||||
"bulk_objects_deleted": "Видалено об'єктів: {n}",
|
||||
"bulk_objects_archived": "Архівовано об'єктів: {n}",
|
||||
"completing": "Виконується…",
|
||||
"interval": "Інтервал",
|
||||
"warning": "Попередження",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Дні тижня",
|
||||
"nth_weekday": "N-й день тижня в місяці",
|
||||
"day_of_month": "День місяця",
|
||||
"calendar": "Сутність календаря",
|
||||
"calendar_entity_label": "Календар",
|
||||
"calendar_entity_hint": "Термін настає один раз на кожну подію цього календаря, у дату початку події — наступна подія після останнього виконання.",
|
||||
"calendar_entity_required": "Виберіть сутність календаря.",
|
||||
"recurrence_on_days": "Повторювати у",
|
||||
"recurrence_occurrence": "Входження",
|
||||
"recurrence_weekday": "День тижня",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Об'єкт не можна пов'язати із самим собою",
|
||||
"ws_err_too_early": "Зарано — це завдання можна завершити лише ближче до терміну",
|
||||
"ws_err_invalid_search_template": "Посилання для пошуку має бути URL http(s) із {q}",
|
||||
"ws_err_invalid_icon": "Значок сповіщення має бути іменем mdi:, наприклад mdi:air-filter",
|
||||
"feat_schedule_time": "Планування за часом доби",
|
||||
"feat_schedule_time_desc": "Задачі стають простроченими у певний час доби, а не опівночі.",
|
||||
"schedule_time_toggle": "Термін у визначений час",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Стовпці таблиці об'єктів",
|
||||
"objects_table_columns_hint": "Виберіть, які стовпці показувати в табличному вигляді об'єктів.",
|
||||
"custom_icon_optional": "Іконка (необов'язково, наприклад mdi:wrench)",
|
||||
"notify_icon": "Значок сповіщення",
|
||||
"notify_icon_hint": "Показується застосунком Companion на Android. Порожньо = значок типу обслуговування цього завдання ({default}).",
|
||||
"task_enabled": "Завдання увімкнено",
|
||||
"skip_reason_prompt": "Пропустити це завдання?",
|
||||
"reason_optional": "Причина (необов'язково)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Зробити фото",
|
||||
"camera_capture_shoot": "Зняти",
|
||||
"camera_switch_lens": "Змінити камеру",
|
||||
"camera_switch_failed": "Інша камера не відповіла — цей телефон надає лише одну. Для іншого об'єктива скористайтеся вибором файлу.",
|
||||
"doc_drop_hint": "Перетягніть файли сюди",
|
||||
"doc_task_none": "Немає документів, пов'язаних із цим завданням.",
|
||||
"doc_link_existing": "Пов'язати документ…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "активна",
|
||||
"adopt_problem_ok": "норма",
|
||||
"adopt_problem_new_object": "(новий)",
|
||||
"adopt_object_hint": "Дайте кільком сенсорам однакову назву об'єкта — вони стануть одним об'єктом; введіть назву наявного об'єкта, щоб додати їх туди.",
|
||||
"adopt_problem_adopt": "Прийняти вибрані",
|
||||
"adopt_problem_done": "Прийнято сенсорів проблем: {tasks}",
|
||||
"views_label": "Подання",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "任务已移动",
|
||||
"move_task_target": "目标对象",
|
||||
"move_task_message": "选择此任务应归属的对象。历史记录、读数和触发器状态会一并迁移;任务将获得新的编号,其实体会在新对象下重新创建。关联的文档仍留在当前对象。",
|
||||
"bulk_move_message": "选择所选任务应归属的对象。已在该对象下的任务将被跳过;历史记录、读数和触发状态会一并迁移。",
|
||||
"bulk_moved": "已移动 {n} 个任务",
|
||||
"more_actions": "更多操作",
|
||||
"move_task_title": "移动任务",
|
||||
"move_task": "移动到其他对象…",
|
||||
"object_duplicated": "对象已复制",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "已选 {n} 项",
|
||||
"bulk_completed": "已完成 {n} 个任务",
|
||||
"bulk_archived": "已归档 {n} 个任务",
|
||||
"bulk_delete_objects_confirm": "删除 {n} 个对象及其全部任务?归档则会保留其历史记录。",
|
||||
"bulk_objects_deleted": "已删除 {n} 个对象",
|
||||
"bulk_objects_archived": "已归档 {n} 个对象",
|
||||
"completing": "正在完成…",
|
||||
"interval": "间隔",
|
||||
"warning": "预警",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "工作日",
|
||||
"nth_weekday": "每月第 N 个工作日",
|
||||
"day_of_month": "每月某天",
|
||||
"calendar": "日历实体",
|
||||
"calendar_entity_label": "日历",
|
||||
"calendar_entity_hint": "此日历的每个事件到期一次,以事件开始日期为准——即上次完成后的下一个事件。",
|
||||
"calendar_entity_required": "请选择一个日历实体。",
|
||||
"recurrence_on_days": "重复日期",
|
||||
"recurrence_occurrence": "发生次数",
|
||||
"recurrence_weekday": "星期",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "对象不能链接到自身",
|
||||
"ws_err_too_early": "为时过早 — 此任务只能在临近到期日时完成",
|
||||
"ws_err_invalid_search_template": "搜索链接必须是包含 {q} 的 http(s) 网址",
|
||||
"ws_err_invalid_icon": "通知图标必须是 mdi: 名称,例如 mdi:air-filter",
|
||||
"feat_schedule_time": "具体时间调度",
|
||||
"feat_schedule_time_desc": "任务将在特定时间点变为逾期,而非默认的午夜。",
|
||||
"schedule_time_toggle": "在特定时间到期",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "对象表格列",
|
||||
"objects_table_columns_hint": "选择对象表格视图中显示的列。",
|
||||
"custom_icon_optional": "图标 (可选,例如 mdi:wrench)",
|
||||
"notify_icon": "通知图标",
|
||||
"notify_icon_hint": "由 Android 上的 Companion 应用显示。留空 = 此任务维护类型的图标({default})。",
|
||||
"task_enabled": "任务已启用",
|
||||
"skip_reason_prompt": "跳过此任务?",
|
||||
"reason_optional": "原因 (可选)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "拍照",
|
||||
"camera_capture_shoot": "拍摄",
|
||||
"camera_switch_lens": "切换摄像头",
|
||||
"camera_switch_failed": "没有其他摄像头响应——这部手机只开放一个。另一个镜头请使用文件选择器。",
|
||||
"doc_drop_hint": "将文件拖放到此处",
|
||||
"doc_task_none": "没有与此任务关联的文档。",
|
||||
"doc_link_existing": "关联文档…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "存在",
|
||||
"adopt_problem_ok": "正常",
|
||||
"adopt_problem_new_object": "(新建)",
|
||||
"adopt_object_hint": "给多个传感器相同的对象名称,它们就会合并为一个对象;输入已有对象的名称即可加入该对象。",
|
||||
"adopt_problem_adopt": "采用所选",
|
||||
"adopt_problem_done": "已采用 {tasks} 个问题传感器",
|
||||
"views_label": "视图",
|
||||
|
||||
@@ -307,6 +307,11 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
// complete/archive). Keys are `${entry_id}:${task_id}`.
|
||||
@state() private _bulkMode = false;
|
||||
@state() private _bulkSelected = new Set<string>();
|
||||
/** #188: multi-select in the All-objects view (delete / archive many at once). */
|
||||
@state() private _objBulkMode = false;
|
||||
@state() private _objBulkSelected = new Set<string>();
|
||||
/** #188: the task selection bar's overflow menu (Move to another object…). */
|
||||
@state() private _bulkMenuOpen = false;
|
||||
// Virtualized dashboard task table (large installs): only rows in the
|
||||
// scroll window are in the DOM; spacers keep the scrollbar honest. The
|
||||
// window is recomputed from `.content` scroll/resize (rAF-throttled).
|
||||
@@ -1308,6 +1313,8 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
private _showAllObjects(): void {
|
||||
this._pushPanelState("all_objects");
|
||||
this._view = "all_objects";
|
||||
this._objBulkMode = false;
|
||||
this._objBulkSelected = new Set();
|
||||
this._selectedEntryId = null;
|
||||
this._selectedTaskId = null;
|
||||
this._scrollContentToTop();
|
||||
@@ -2003,6 +2010,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
|
||||
private _toggleBulkMode(): void {
|
||||
this._bulkMode = !this._bulkMode;
|
||||
this._bulkMenuOpen = false;
|
||||
if (!this._bulkMode) this._bulkSelected = new Set();
|
||||
}
|
||||
|
||||
@@ -2045,6 +2053,122 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
else this._showToast(doneMsg(ok));
|
||||
}
|
||||
|
||||
/** #188: move every selected task to one object (the single-task move's
|
||||
* prompt, then task/move per row; rows already there are skipped). */
|
||||
private async _bulkMove(rows: TaskRow[]): Promise<void> {
|
||||
const targets = this._objects
|
||||
.filter((o) => !o.object.archived_at)
|
||||
.sort((a, b) => (a.object.name || "").localeCompare(b.object.name || ""));
|
||||
if (!targets.length || this._bulkSelected.size === 0) return;
|
||||
const dlg = this.shadowRoot!.querySelector<MaintenanceConfirmDialog>("maintenance-confirm-dialog");
|
||||
const result = await dlg?.prompt({
|
||||
title: t("move_task_title", this._lang),
|
||||
message: t("bulk_move_message", this._lang),
|
||||
confirmText: t("move_task_title", this._lang),
|
||||
inputLabel: t("move_task_target", this._lang),
|
||||
inputValue: targets[0].entry_id,
|
||||
options: targets.map((o) => ({ value: o.entry_id, label: o.object.name || o.entry_id })),
|
||||
});
|
||||
if (!result?.confirmed || !result.value) return;
|
||||
const target = result.value;
|
||||
await this._runBulk(
|
||||
rows.filter((r) => r.entry_id !== target),
|
||||
(row) => ({ type: "maintenance_supporter/task/move", entry_id: row.entry_id, task_id: row.task_id, target_entry_id: target }),
|
||||
(n) => t("bulk_moved", this._lang).replace("{n}", String(n)),
|
||||
);
|
||||
}
|
||||
|
||||
// ── #188: bulk select in the All-objects view ──────────────────────────
|
||||
private _toggleObjBulkMode(): void {
|
||||
this._objBulkMode = !this._objBulkMode;
|
||||
if (!this._objBulkMode) this._objBulkSelected = new Set();
|
||||
}
|
||||
|
||||
private _toggleObjBulk(entryId: string): void {
|
||||
const next = new Set(this._objBulkSelected);
|
||||
if (next.has(entryId)) next.delete(entryId);
|
||||
else next.add(entryId);
|
||||
this._objBulkSelected = next;
|
||||
}
|
||||
|
||||
private _objBulkSelectAll(objs: MaintenanceObjectResponse[]): void {
|
||||
const ids = objs.map((o) => o.entry_id);
|
||||
const all = ids.length > 0 && ids.every((id) => this._objBulkSelected.has(id));
|
||||
this._objBulkSelected = all ? new Set() : new Set(ids);
|
||||
}
|
||||
|
||||
/** One WS call per selected object, sequentially (config entries are
|
||||
* removed one at a time on the backend); the successful count is reported. */
|
||||
private async _runObjBulk(type: string, doneMsg: (n: number) => string, undo?: (ids: string[]) => Promise<void>): Promise<void> {
|
||||
const ids = [...this._objBulkSelected];
|
||||
if (ids.length === 0) return;
|
||||
this._actionLoading = true;
|
||||
const done: string[] = [];
|
||||
for (const id of ids) {
|
||||
try {
|
||||
await this.hass.connection.sendMessagePromise({ type, entry_id: id });
|
||||
done.push(id);
|
||||
} catch { /* keep going; report the successful count */ }
|
||||
}
|
||||
this._actionLoading = false;
|
||||
this._objBulkSelected = new Set();
|
||||
this._objBulkMode = false;
|
||||
await this._loadData();
|
||||
if (undo && done.length > 0) this._showUndoToast(doneMsg(done.length), () => { void undo(done); });
|
||||
else this._showToast(doneMsg(done.length));
|
||||
}
|
||||
|
||||
private async _objBulkDelete(): Promise<void> {
|
||||
const n = this._objBulkSelected.size;
|
||||
if (n === 0) return;
|
||||
const dlg = this.shadowRoot!.querySelector<MaintenanceConfirmDialog>("maintenance-confirm-dialog");
|
||||
const ok = await dlg?.confirm({
|
||||
title: t("delete", this._lang),
|
||||
message: t("bulk_delete_objects_confirm", this._lang).replace("{n}", String(n)),
|
||||
confirmText: t("delete", this._lang),
|
||||
danger: true,
|
||||
});
|
||||
if (!ok) return;
|
||||
await this._runObjBulk("maintenance_supporter/object/delete", (k) => t("bulk_objects_deleted", this._lang).replace("{n}", String(k)));
|
||||
}
|
||||
|
||||
private _objBulkArchive(): void {
|
||||
void this._runObjBulk(
|
||||
"maintenance_supporter/object/archive",
|
||||
(k) => t("bulk_objects_archived", this._lang).replace("{n}", String(k)),
|
||||
async (ids) => {
|
||||
for (const id of ids) {
|
||||
try {
|
||||
await this.hass.connection.sendMessagePromise({ type: "maintenance_supporter/object/unarchive", entry_id: id });
|
||||
} catch { /* best effort */ }
|
||||
}
|
||||
await this._loadData();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private _renderObjBulkBar(objs: MaintenanceObjectResponse[], L: string) {
|
||||
const n = this._objBulkSelected.size;
|
||||
const allSelected = objs.length > 0 && objs.every((o) => this._objBulkSelected.has(o.entry_id));
|
||||
return html`
|
||||
<div class="bulk-bar obj-bulk-bar">
|
||||
<label class="bulk-selectall">
|
||||
<input type="checkbox" .checked=${allSelected} @change=${() => this._objBulkSelectAll(objs)} />
|
||||
${t("bulk_select_all", L)}
|
||||
</label>
|
||||
<span class="bulk-count">${t("bulk_n_selected", L).replace("{n}", String(n))}</span>
|
||||
<span class="bulk-actions">
|
||||
<ha-button appearance="plain" class="obj-bulk-archive" .disabled=${n === 0 || this._actionLoading} @click=${() => this._objBulkArchive()}>
|
||||
<ha-icon icon="mdi:archive-outline"></ha-icon> ${t("archive", L)}
|
||||
</ha-button>
|
||||
<ha-button appearance="filled" variant="danger" class="obj-bulk-delete" .disabled=${n === 0 || this._actionLoading} @click=${() => this._objBulkDelete()}>
|
||||
<ha-icon icon="mdi:delete-outline"></ha-icon> ${t("delete", L)}
|
||||
</ha-button>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _bulkComplete(rows: TaskRow[]): void {
|
||||
void this._runBulk(
|
||||
rows,
|
||||
@@ -3311,6 +3435,17 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
@click=${() => this._bulkArchive(rows)}>
|
||||
<ha-icon icon="mdi:archive-outline"></ha-icon> ${t("archive", L)}
|
||||
</ha-button>
|
||||
<span class="bulk-more-wrapper">
|
||||
<ha-button appearance="plain" class="bulk-more" title=${t("more_actions", L)} aria-label=${t("more_actions", L)} .disabled=${n === 0 || this._actionLoading}
|
||||
@click=${(e: Event) => { e.stopPropagation(); this._bulkMenuOpen = !this._bulkMenuOpen; }}>
|
||||
<ha-icon icon="mdi:dots-vertical"></ha-icon>
|
||||
</ha-button>
|
||||
${this._bulkMenuOpen ? html`
|
||||
<div class="popup-menu" @click=${(e: Event) => e.stopPropagation()}>
|
||||
<div class="popup-menu-item bulk-move" @click=${() => { this._bulkMenuOpen = false; void this._bulkMove(rows); }}>${t("move_task", L)}</div>
|
||||
</div>
|
||||
` : nothing}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
@@ -3454,7 +3589,13 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
const renderObject = (obj: MaintenanceObjectResponse) => {
|
||||
const overdue = obj.tasks.some(t => t.status === "overdue" || t.status === "triggered");
|
||||
return html`
|
||||
<div class="object-card${overdue ? ' object-card-overdue' : ''}" @click=${() => this._showObject(obj.entry_id)}>
|
||||
<div class="object-card${overdue ? ' object-card-overdue' : ''}${this._objBulkMode ? ' selectable' : ''}${this._objBulkMode && this._objBulkSelected.has(obj.entry_id) ? ' bulk-selected' : ''}"
|
||||
@click=${() => (this._objBulkMode ? this._toggleObjBulk(obj.entry_id) : this._showObject(obj.entry_id))}>
|
||||
${this._objBulkMode
|
||||
? html`<label class="obj-bulk-check bulk-check" @click=${(e: Event) => e.stopPropagation()}>
|
||||
<input type="checkbox" .checked=${this._objBulkSelected.has(obj.entry_id)} @change=${() => this._toggleObjBulk(obj.entry_id)} />
|
||||
</label>`
|
||||
: nothing}
|
||||
${overdue ? html`<span class="overdue-dot" title="${t("has_overdue", L)}"></span>` : nothing}
|
||||
<div class="object-card-header">
|
||||
<span class="object-card-name">${this._objRef(obj.object)}${obj.object.name}</span>
|
||||
@@ -3544,6 +3685,12 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
<ha-button appearance="plain" @click=${() => this._exportObjectsCsv()}>
|
||||
<ha-icon icon="mdi:file-delimited-outline"></ha-icon> ${t("settings_export_csv", L)}
|
||||
</ha-button>
|
||||
${!isOperator ? html`
|
||||
<ha-button appearance="plain" class="bulk-toggle obj-bulk-toggle ${this._objBulkMode ? "active" : ""}" @click=${() => this._toggleObjBulkMode()}>
|
||||
<ha-icon icon="mdi:checkbox-multiple-marked-outline"></ha-icon>
|
||||
${this._objBulkMode ? t("cancel", L) : t("bulk_select", L)}
|
||||
</ha-button>
|
||||
` : nothing}
|
||||
${archivedObjCount > 0 ? html`
|
||||
<ha-button
|
||||
class="archived-toggle ${this._showArchived ? "active" : ""}"
|
||||
@@ -3554,6 +3701,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
</ha-button>
|
||||
` : nothing}
|
||||
</div>
|
||||
${this._objBulkMode ? this._renderObjBulkBar(sorted, L) : nothing}
|
||||
${tableMode
|
||||
? this._renderObjectsTable(sorted)
|
||||
: this._groupByMode === "area"
|
||||
@@ -3696,6 +3844,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
<table class="objects-table">
|
||||
<thead>
|
||||
<tr>
|
||||
${this._objBulkMode ? html`<th class="oc-bulk"></th>` : nothing}
|
||||
${cols.map((key) => {
|
||||
const def = OBJECT_COLUMNS.find((c) => c.key === key);
|
||||
// The actions column header stays blank (icon-only cells).
|
||||
@@ -3706,7 +3855,12 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
</thead>
|
||||
<tbody>
|
||||
${objs.map((obj) => html`
|
||||
<tr class="objects-table-row" @click=${() => this._showObject(obj.entry_id)}>
|
||||
<tr class="objects-table-row${this._objBulkMode && this._objBulkSelected.has(obj.entry_id) ? ' bulk-selected' : ''}"
|
||||
@click=${() => (this._objBulkMode ? this._toggleObjBulk(obj.entry_id) : this._showObject(obj.entry_id))}>
|
||||
${this._objBulkMode
|
||||
? html`<td class="oc-bulk"><input type="checkbox" .checked=${this._objBulkSelected.has(obj.entry_id)}
|
||||
@click=${(e: Event) => e.stopPropagation()} @change=${() => this._toggleObjBulk(obj.entry_id)} /></td>`
|
||||
: nothing}
|
||||
${cols.map((key) => this._renderObjectCell(key, obj, L))}
|
||||
</tr>
|
||||
`)}
|
||||
|
||||
@@ -360,6 +360,7 @@ export const panelStyles = css`
|
||||
.bulk-selectall { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; font-size: 13px; }
|
||||
.bulk-count { color: var(--secondary-text-color); font-size: 13px; }
|
||||
.bulk-actions { margin-left: auto; display: inline-flex; gap: 8px; }
|
||||
.bulk-more-wrapper { position: relative; display: inline-flex; }
|
||||
.bulk-toggle.active { --mdc-theme-primary: var(--primary-color); }
|
||||
|
||||
/* Collapsible analysis sections on the task-detail overview tab. The header
|
||||
|
||||
@@ -435,12 +435,14 @@ interface RecurrenceLike {
|
||||
schedule?: {
|
||||
kind?: string; every?: number | null; unit?: string;
|
||||
weekdays?: number[]; nth?: number; weekday?: number; day?: number;
|
||||
business?: boolean; offset?: number;
|
||||
business?: boolean; offset?: number; entity_id?: string | null;
|
||||
} | null;
|
||||
interval_days?: number | null;
|
||||
interval_unit?: string | null;
|
||||
due_date?: string | null;
|
||||
schedule_type?: string;
|
||||
/** (#187) calendar kind: friendly name of the driving calendar entity. */
|
||||
schedule_entity_name?: string | null;
|
||||
}
|
||||
|
||||
/** A task's recurrence as a localized human label, for ANY schedule kind.
|
||||
@@ -474,6 +476,10 @@ export function formatRecurrence(task: RecurrenceLike, lang?: string): string {
|
||||
: `${t("day_word", lang)} ${s.day}`;
|
||||
return base + off;
|
||||
}
|
||||
case "calendar":
|
||||
// (#187) "Calendar: Bio waste" — the summary carries the friendly name;
|
||||
// fall back to the entity_id when the calendar is not loaded.
|
||||
return `${t("calendar_entity_label", lang)}: ${task.schedule_entity_name || s.entity_id || "—"}${off}`;
|
||||
case "one_time":
|
||||
return task.due_date ? formatDate(task.due_date, lang) : t("one_time", lang);
|
||||
case "manual":
|
||||
@@ -653,6 +659,16 @@ export const sharedStyles = css`
|
||||
|
||||
/* Overdue indicator dot on object cards (#35) */
|
||||
.object-card { position: relative; }
|
||||
/* #188: bulk select in the All-objects view */
|
||||
.object-card.bulk-selected, .objects-table-row.bulk-selected {
|
||||
outline: 2px solid var(--primary-color); outline-offset: -2px;
|
||||
background: color-mix(in srgb, var(--primary-color) 10%, transparent);
|
||||
}
|
||||
.object-card.selectable { padding-left: 44px; }
|
||||
.obj-bulk-check { position: absolute; top: 12px; left: 12px; z-index: 1; }
|
||||
.obj-bulk-check input, .oc-bulk input { width: 17px; height: 17px; cursor: pointer; accent-color: var(--primary-color); }
|
||||
.oc-bulk { width: 28px; }
|
||||
.obj-bulk-bar { margin: 0 0 12px; }
|
||||
.object-card-overdue { border-left: 3px solid var(--error-color); }
|
||||
.overdue-dot {
|
||||
position: absolute;
|
||||
|
||||
@@ -10,8 +10,9 @@ export type MaintenanceStatus = "ok" | "due_soon" | "overdue" | "triggered" | "a
|
||||
export type HistoryEntryType = "completed" | "skipped" | "missed" | "reset" | "triggered" | "trigger_removed" | "trigger_replaced";
|
||||
/** const.MaintenanceTypeEnum */
|
||||
export type MaintenanceType = "cleaning" | "inspection" | "replacement" | "calibration" | "service" | "reading" | "custom";
|
||||
/** The nested calendar recurrence kinds (schedule-model v2). */
|
||||
export type CalendarKind = "weekdays" | "nth_weekday" | "day_of_month";
|
||||
/** The nested calendar recurrence kinds (schedule-model v2); `calendar` (#187)
|
||||
* = one occurrence per event of a HA calendar entity. */
|
||||
export type CalendarKind = "weekdays" | "nth_weekday" | "day_of_month" | "calendar";
|
||||
/** const.ScheduleType plus the calendar kinds the dialog exposes as schedule types. */
|
||||
export type ScheduleType = "time_based" | "sensor_based" | "one_time" | "manual" | CalendarKind;
|
||||
/** TaskSchedule.kind — the flat kinds plus the calendar kinds. */
|
||||
@@ -211,6 +212,8 @@ export interface TaskSchedule {
|
||||
months?: number[];
|
||||
/** (#83) day_of_month only: roll a weekend date back to Friday. */
|
||||
business?: boolean;
|
||||
/** (#187) calendar kind only: the `calendar.*` entity whose events are the occurrences. */
|
||||
entity_id?: string | null;
|
||||
/** (#83) shift the computed occurrence by ±N days (clamped ±15). */
|
||||
offset?: number;
|
||||
/** Seasonal active window — months (1..12) the task may be due in. */
|
||||
@@ -230,12 +233,16 @@ export interface MaintenanceTask {
|
||||
allow_skip?: boolean;
|
||||
/** #173: false = this task sends no reminders (dashboard/entities unaffected). */
|
||||
notify_enabled?: boolean;
|
||||
/** #185: mdi icon for this task's push notifications; null/absent = the type's default. */
|
||||
notify_icon?: string | null;
|
||||
schedule_type: ScheduleType;
|
||||
interval_days?: number | null;
|
||||
interval_unit?: IntervalUnit;
|
||||
due_date?: string | null; // one-time task due date (ISO)
|
||||
interval_anchor?: "completion" | "planned";
|
||||
schedule?: TaskSchedule; // nested recurrence (calendar kinds read this)
|
||||
/** (#187) calendar kind: the picked calendar's friendly name (summary-only). */
|
||||
schedule_entity_name?: string | null;
|
||||
schedule_time?: string | null; // "HH:MM" or null/undefined = midnight
|
||||
warning_days: number;
|
||||
last_performed?: string | null;
|
||||
@@ -576,6 +583,8 @@ export interface TaskRow {
|
||||
allow_skip: boolean;
|
||||
/** #173: false = no reminders for this task. */
|
||||
notify_enabled: boolean;
|
||||
/** #185: per-task notification icon override; null/absent = the type's default. */
|
||||
notify_icon?: string | null;
|
||||
nfc_tag_id: string | null;
|
||||
priority: string;
|
||||
labels: string[];
|
||||
|
||||
@@ -35,6 +35,7 @@ export const WS_ERROR_CODE_KEYS: Record<string, string> = {
|
||||
invalid_input: "ws_err_invalid_input",
|
||||
invalid_mirror_todo: "ws_err_invalid_mirror_todo",
|
||||
invalid_parent: "ws_err_invalid_parent",
|
||||
invalid_icon: "ws_err_invalid_icon",
|
||||
invalid_range: "ws_err_invalid_range",
|
||||
invalid_search_template: "ws_err_invalid_search_template",
|
||||
invalid_target: "ws_err_invalid_target",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Úkol přesunut",
|
||||
"move_task_target": "Cílový objekt",
|
||||
"move_task_message": "Vyberte objekt, ke kterému má tento úkol patřit. Historie, odečty a stav spouštěče se přesunou s ním; dostane nové referenční číslo a jeho entity se vytvoří znovu pod novým objektem. Propojené dokumenty zůstanou u aktuálního objektu.",
|
||||
"bulk_move_message": "Vyberte objekt, ke kterému mají vybrané úkoly patřit. Úkoly, které tam už jsou, se přeskočí; historie, odečty a stav spouštěče se přesunou s nimi.",
|
||||
"bulk_moved": "Přesunuto úkolů: {n}",
|
||||
"more_actions": "Další akce",
|
||||
"move_task_title": "Přesunout úkol",
|
||||
"move_task": "Přesunout do jiného objektu…",
|
||||
"object_duplicated": "Objekt duplikován",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} vybráno",
|
||||
"bulk_completed": "Dokončeno {n} úkolů",
|
||||
"bulk_archived": "Archivováno {n} úkolů",
|
||||
"bulk_delete_objects_confirm": "Smazat {n} objektů včetně všech jejich úkolů? Archivace místo toho zachová historii.",
|
||||
"bulk_objects_deleted": "Smazáno objektů: {n}",
|
||||
"bulk_objects_archived": "Archivováno objektů: {n}",
|
||||
"completing": "Dokončování…",
|
||||
"interval": "Interval",
|
||||
"warning": "Upozornění",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Dny v týdnu",
|
||||
"nth_weekday": "N-tý den v týdnu v měsíci",
|
||||
"day_of_month": "Den v měsíci",
|
||||
"calendar": "Entita kalendáře",
|
||||
"calendar_entity_label": "Kalendář",
|
||||
"calendar_entity_hint": "Splatné jednou za každou událost tohoto kalendáře, v den začátku události — další událost po posledním dokončení.",
|
||||
"calendar_entity_required": "Vyberte entitu kalendáře.",
|
||||
"recurrence_on_days": "Opakovat v",
|
||||
"recurrence_occurrence": "Výskyt",
|
||||
"recurrence_weekday": "Den v týdnu",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Objekt nelze propojit sám se sebou",
|
||||
"ws_err_too_early": "Příliš brzy — tento úkol lze dokončit až blíže k termínu",
|
||||
"ws_err_invalid_search_template": "Odkaz pro vyhledávání musí být URL http(s) obsahující {q}",
|
||||
"ws_err_invalid_icon": "Ikona oznámení musí být název mdi:, např. mdi:air-filter",
|
||||
"feat_schedule_time": "Plánování podle denní doby",
|
||||
"feat_schedule_time_desc": "Úkoly se stanou po termínu v určenou denní dobu místo o půlnoci.",
|
||||
"schedule_time_toggle": "Termín v určitou hodinu",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Sloupce tabulky objektů",
|
||||
"objects_table_columns_hint": "Vyberte, které sloupce se zobrazí v tabulkovém zobrazení objektů.",
|
||||
"custom_icon_optional": "Ikona (volitelná, např. mdi:wrench)",
|
||||
"notify_icon": "Ikona oznámení",
|
||||
"notify_icon_hint": "Zobrazuje aplikace Companion na Androidu. Prázdné = ikona typu údržby tohoto úkolu ({default}).",
|
||||
"task_enabled": "Úkol povolen",
|
||||
"skip_reason_prompt": "Přeskočit tento úkol?",
|
||||
"reason_optional": "Důvod (volitelný)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Vyfotit",
|
||||
"camera_capture_shoot": "Vyfotit",
|
||||
"camera_switch_lens": "Přepnout kameru",
|
||||
"camera_switch_failed": "Žádná jiná kamera neodpověděla – tento telefon uvolňuje jen jednu. Pro druhý objektiv použijte výběr souboru.",
|
||||
"doc_drop_hint": "Přetáhněte soubory sem",
|
||||
"doc_task_none": "Žádné dokumenty spojené s tímto úkolem.",
|
||||
"doc_link_existing": "Připojit dokument…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktivní",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nový)",
|
||||
"adopt_object_hint": "Dejte několika senzorům stejný název objektu a stanou se jedním objektem; zadejte název existujícího objektu a přidají se tam.",
|
||||
"adopt_problem_adopt": "Převzít vybrané",
|
||||
"adopt_problem_done": "Převzato {tasks} senzorů problémů",
|
||||
"views_label": "Zobrazení",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Opgave flyttet",
|
||||
"move_task_target": "Målobjekt",
|
||||
"move_task_message": "Vælg det objekt, opgaven skal høre til. Historik, aflæsninger og triggerstatus flytter med; den får et nyt referencenummer, og dens entiteter oprettes igen under det nye objekt. Tilknyttede dokumenter bliver hos det nuværende objekt.",
|
||||
"bulk_move_message": "Vælg det objekt, de markerede opgaver skal høre til. Opgaver, der allerede er der, springes over; historik, aflæsninger og triggerstatus flytter med.",
|
||||
"bulk_moved": "{n} opgaver flyttet",
|
||||
"more_actions": "Flere handlinger",
|
||||
"move_task_title": "Flyt opgave",
|
||||
"move_task": "Flyt til et andet objekt…",
|
||||
"object_duplicated": "Objekt duplikeret",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} valgt",
|
||||
"bulk_completed": "{n} opgaver fuldført",
|
||||
"bulk_archived": "{n} opgaver arkiveret",
|
||||
"bulk_delete_objects_confirm": "Slet {n} objekter og alle deres opgaver? Arkivering bevarer i stedet historikken.",
|
||||
"bulk_objects_deleted": "{n} objekter slettet",
|
||||
"bulk_objects_archived": "{n} objekter arkiveret",
|
||||
"completing": "Fuldfører…",
|
||||
"interval": "Interval",
|
||||
"warning": "Advarsel",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Ugedage",
|
||||
"nth_weekday": "N'te ugedag i måneden",
|
||||
"day_of_month": "Dag i måneden",
|
||||
"calendar": "Kalenderentitet",
|
||||
"calendar_entity_label": "Kalender",
|
||||
"calendar_entity_hint": "Forfalder én gang pr. begivenhed i denne kalender, på begivenhedens startdato — den næste begivenhed efter seneste udførelse.",
|
||||
"calendar_entity_required": "Vælg en kalenderentitet.",
|
||||
"recurrence_on_days": "Gentag på",
|
||||
"recurrence_occurrence": "Forekomst",
|
||||
"recurrence_weekday": "Ugedag",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Et objekt kan ikke knyttes til sig selv",
|
||||
"ws_err_too_early": "For tidligt — opgaven kan først fuldføres tættere på forfaldsdatoen",
|
||||
"ws_err_invalid_search_template": "Søgelinket skal være en http(s)-URL, der indeholder {q}",
|
||||
"ws_err_invalid_icon": "Notifikationsikonet skal være et mdi:-navn, f.eks. mdi:air-filter",
|
||||
"feat_schedule_time": "Planlægning efter tidspunkt på dagen",
|
||||
"feat_schedule_time_desc": "Opgaver bliver forfaldne på et bestemt tidspunkt på dagen i stedet for midnat.",
|
||||
"schedule_time_toggle": "Forfalder på et bestemt tidspunkt",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Kolonner i objekttabel",
|
||||
"objects_table_columns_hint": "Vælg, hvilke kolonner der vises i objekttabelvisningen.",
|
||||
"custom_icon_optional": "Ikon (valgfrit, f.eks. mdi:wrench)",
|
||||
"notify_icon": "Notifikationsikon",
|
||||
"notify_icon_hint": "Vises af Companion-appen på Android. Tom = ikonet for opgavens vedligeholdelsestype ({default}).",
|
||||
"task_enabled": "Opgave aktiveret",
|
||||
"skip_reason_prompt": "Spring denne opgave over?",
|
||||
"reason_optional": "Årsag (valgfrit)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Tag billede",
|
||||
"camera_capture_shoot": "Tag billede",
|
||||
"camera_switch_lens": "Skift kamera",
|
||||
"camera_switch_failed": "Intet andet kamera svarede — denne telefon frigiver kun ét. Brug filvælgeren til det andet objektiv.",
|
||||
"doc_drop_hint": "Slip filer her",
|
||||
"doc_task_none": "Ingen dokumenter knyttet til denne opgave.",
|
||||
"doc_link_existing": "Knyt et dokument…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktiv",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(ny)",
|
||||
"adopt_object_hint": "Giv flere sensorer samme objektnavn, så bliver de ét objekt; skriv et eksisterende objekts navn for at tilføje dem der.",
|
||||
"adopt_problem_adopt": "Adopter valgte",
|
||||
"adopt_problem_done": "Adopterede {tasks} problemsensor(er)",
|
||||
"views_label": "Visninger",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Aufgabe verschoben",
|
||||
"move_task_target": "Zielobjekt",
|
||||
"move_task_message": "Wähle das Objekt, zu dem diese Aufgabe gehören soll. Historie, Zählerstände und Trigger-Zustand wandern mit; sie bekommt eine neue Referenznummer und ihre Entitäten werden unter dem neuen Objekt neu angelegt. Verknüpfte Dokumente bleiben beim aktuellen Objekt.",
|
||||
"bulk_move_message": "Wähle das Objekt, zu dem die markierten Aufgaben gehören sollen. Aufgaben, die schon dort sind, werden übersprungen; Historie, Messwerte und Trigger-Zustand wandern mit.",
|
||||
"bulk_moved": "{n} Aufgaben verschoben",
|
||||
"more_actions": "Weitere Aktionen",
|
||||
"move_task_title": "Aufgabe verschieben",
|
||||
"move_task": "In anderes Objekt verschieben…",
|
||||
"object_duplicated": "Objekt dupliziert",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} ausgewählt",
|
||||
"bulk_completed": "{n} Aufgaben erledigt",
|
||||
"bulk_archived": "{n} Aufgaben archiviert",
|
||||
"bulk_delete_objects_confirm": "{n} Objekte mit allen ihren Aufgaben löschen? Archivieren behält stattdessen die Historie.",
|
||||
"bulk_objects_deleted": "{n} Objekte gelöscht",
|
||||
"bulk_objects_archived": "{n} Objekte archiviert",
|
||||
"completing": "Wird erledigt…",
|
||||
"interval": "Intervall",
|
||||
"warning": "Vorwarnung",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Wochentage",
|
||||
"nth_weekday": "N-ter Wochentag im Monat",
|
||||
"day_of_month": "Tag im Monat",
|
||||
"calendar": "Kalender-Entität",
|
||||
"calendar_entity_label": "Kalender",
|
||||
"calendar_entity_hint": "Einmal pro Termin dieses Kalenders fällig, am Starttag des Termins — der nächste Termin nach der letzten Erledigung.",
|
||||
"calendar_entity_required": "Bitte eine Kalender-Entität auswählen.",
|
||||
"recurrence_on_days": "Wiederholen an",
|
||||
"recurrence_occurrence": "Vorkommen",
|
||||
"recurrence_weekday": "Wochentag",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Ein Objekt kann nicht mit sich selbst verknüpft werden",
|
||||
"ws_err_too_early": "Zu früh — diese Aufgabe kann erst näher am Fälligkeitsdatum erledigt werden",
|
||||
"ws_err_invalid_search_template": "Der Suchlink muss eine http(s)-URL mit {q} sein",
|
||||
"ws_err_invalid_icon": "Das Benachrichtigungs-Icon muss ein mdi:-Name sein, z. B. mdi:air-filter",
|
||||
"feat_schedule_time": "Uhrzeit-Scheduling",
|
||||
"feat_schedule_time_desc": "Tasks werden zu einer festen Uhrzeit fällig statt um Mitternacht.",
|
||||
"schedule_time_toggle": "Zu einer bestimmten Uhrzeit fällig",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Spalten der Objekt-Tabelle",
|
||||
"objects_table_columns_hint": "Wähle die Spalten für die Tabellenansicht der Objektübersicht.",
|
||||
"custom_icon_optional": "Icon (optional, z.B. mdi:wrench)",
|
||||
"notify_icon": "Benachrichtigungs-Icon",
|
||||
"notify_icon_hint": "Zeigt die Companion-App auf Android. Leer = das Icon der Wartungsart dieser Aufgabe ({default}).",
|
||||
"task_enabled": "Aufgabe aktiviert",
|
||||
"skip_reason_prompt": "Aufgabe überspringen?",
|
||||
"reason_optional": "Grund (optional)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Foto aufnehmen",
|
||||
"camera_capture_shoot": "Aufnehmen",
|
||||
"camera_switch_lens": "Kamera wechseln",
|
||||
"camera_switch_failed": "Keine andere Kamera hat geantwortet – dieses Telefon gibt nur eine frei. Für das andere Objektiv die Dateiauswahl nutzen.",
|
||||
"doc_drop_hint": "Dateien hier ablegen",
|
||||
"doc_task_none": "Keine Dokumente mit dieser Aufgabe verknüpft.",
|
||||
"doc_link_existing": "Dokument verknüpfen…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktiv",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(neu)",
|
||||
"adopt_object_hint": "Gib mehreren Sensoren denselben Objektnamen, dann werden sie ein Objekt; der Name eines vorhandenen Objekts ordnet sie dort zu.",
|
||||
"adopt_problem_adopt": "Auswahl übernehmen",
|
||||
"adopt_problem_done": "{tasks} Problem-Sensor(en) übernommen",
|
||||
"views_label": "Ansichten",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Task moved",
|
||||
"move_task_target": "Target object",
|
||||
"move_task_message": "Choose the object this task should belong to. Its history, readings and trigger state move with it; it gets a new reference number and its entities are recreated under the new object. Linked documents stay with the current object.",
|
||||
"bulk_move_message": "Choose the object the selected tasks should belong to. Tasks that already live there are skipped; history, readings and trigger state move along.",
|
||||
"bulk_moved": "{n} tasks moved",
|
||||
"more_actions": "More actions",
|
||||
"move_task_title": "Move task",
|
||||
"move_task": "Move to another object…",
|
||||
"object_duplicated": "Object duplicated",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} selected",
|
||||
"bulk_completed": "{n} tasks completed",
|
||||
"bulk_archived": "{n} tasks archived",
|
||||
"bulk_delete_objects_confirm": "Delete {n} objects and all their tasks? Archiving keeps their history instead.",
|
||||
"bulk_objects_deleted": "{n} objects deleted",
|
||||
"bulk_objects_archived": "{n} objects archived",
|
||||
"completing": "Completing…",
|
||||
"interval": "Interval",
|
||||
"warning": "Warning",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Weekdays",
|
||||
"nth_weekday": "Nth weekday of month",
|
||||
"day_of_month": "Day of month",
|
||||
"calendar": "Calendar entity",
|
||||
"calendar_entity_label": "Calendar",
|
||||
"calendar_entity_hint": "Due once per event of this calendar, on the event's start date — the next event after the last completion.",
|
||||
"calendar_entity_required": "Choose a calendar entity.",
|
||||
"recurrence_on_days": "Repeat on",
|
||||
"recurrence_occurrence": "Occurrence",
|
||||
"recurrence_weekday": "Weekday",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "An object cannot be linked to itself",
|
||||
"ws_err_too_early": "Too early — this task can only be completed closer to its due date",
|
||||
"ws_err_invalid_search_template": "The search link must be an http(s) URL containing {q}",
|
||||
"ws_err_invalid_icon": "The notification icon must be an mdi: name, e.g. mdi:air-filter",
|
||||
"feat_schedule_time": "Time-of-day scheduling",
|
||||
"feat_schedule_time_desc": "Tasks become overdue at a specific time of day instead of midnight.",
|
||||
"schedule_time_toggle": "Due at a specific time",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Objects table columns",
|
||||
"objects_table_columns_hint": "Choose which columns appear in the objects table view.",
|
||||
"custom_icon_optional": "Icon (optional, e.g. mdi:wrench)",
|
||||
"notify_icon": "Notification icon",
|
||||
"notify_icon_hint": "Shown by the Companion app on Android. Empty = the icon of this task's maintenance type ({default}).",
|
||||
"task_enabled": "Task enabled",
|
||||
"skip_reason_prompt": "Skip this task?",
|
||||
"reason_optional": "Reason (optional)",
|
||||
@@ -784,6 +797,7 @@
|
||||
"doc_camera": "Take photo",
|
||||
"camera_capture_shoot": "Capture",
|
||||
"camera_switch_lens": "Switch camera",
|
||||
"camera_switch_failed": "No other camera answered — this phone hands out only one. Use the file picker for the other lens.",
|
||||
"doc_drop_hint": "Drop files here",
|
||||
"doc_task_none": "No documents linked to this task.",
|
||||
"doc_link_existing": "Link a document…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "active",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(new)",
|
||||
"adopt_object_hint": "Give several sensors the same object name and they become one object; type an existing object's name to add them there.",
|
||||
"adopt_problem_adopt": "Adopt selected",
|
||||
"adopt_problem_done": "Adopted {tasks} problem sensor(s)",
|
||||
"views_label": "Views",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Tarea movida",
|
||||
"move_task_target": "Objeto de destino",
|
||||
"move_task_message": "Elige el objeto al que debe pertenecer esta tarea. Su historial, lecturas y estado del disparador se mueven con ella; recibe un nuevo número de referencia y sus entidades se recrean bajo el nuevo objeto. Los documentos vinculados se quedan con el objeto actual.",
|
||||
"bulk_move_message": "Elige el objeto al que deben pertenecer las tareas seleccionadas. Las que ya están allí se omiten; el historial, las lecturas y el estado del disparador se mueven con ellas.",
|
||||
"bulk_moved": "{n} tareas movidas",
|
||||
"more_actions": "Más acciones",
|
||||
"move_task_title": "Mover tarea",
|
||||
"move_task": "Mover a otro objeto…",
|
||||
"object_duplicated": "Objeto duplicado",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} seleccionados",
|
||||
"bulk_completed": "{n} tareas completadas",
|
||||
"bulk_archived": "{n} tareas archivadas",
|
||||
"bulk_delete_objects_confirm": "¿Eliminar {n} objetos y todas sus tareas? Archivar conserva su historial.",
|
||||
"bulk_objects_deleted": "{n} objetos eliminados",
|
||||
"bulk_objects_archived": "{n} objetos archivados",
|
||||
"completing": "Completando…",
|
||||
"interval": "Intervalo",
|
||||
"warning": "Aviso",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Días de la semana",
|
||||
"nth_weekday": "N-ésimo día de la semana del mes",
|
||||
"day_of_month": "Día del mes",
|
||||
"calendar": "Entidad de calendario",
|
||||
"calendar_entity_label": "Calendario",
|
||||
"calendar_entity_hint": "Vence una vez por evento de este calendario, en la fecha de inicio del evento — el siguiente evento tras la última finalización.",
|
||||
"calendar_entity_required": "Elige una entidad de calendario.",
|
||||
"recurrence_on_days": "Repetir los",
|
||||
"recurrence_occurrence": "Aparición",
|
||||
"recurrence_weekday": "Día de la semana",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Un objeto no puede vincularse a sí mismo",
|
||||
"ws_err_too_early": "Demasiado pronto — esta tarea solo puede completarse más cerca de su vencimiento",
|
||||
"ws_err_invalid_search_template": "El enlace de búsqueda debe ser una URL http(s) que contenga {q}",
|
||||
"ws_err_invalid_icon": "El icono de la notificación debe ser un nombre mdi:, p. ej. mdi:air-filter",
|
||||
"feat_schedule_time": "Programación por hora",
|
||||
"feat_schedule_time_desc": "Las tareas vencen a una hora específica en lugar de medianoche.",
|
||||
"schedule_time_toggle": "Vence a una hora concreta",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Columnas de la tabla de objetos",
|
||||
"objects_table_columns_hint": "Elige qué columnas aparecen en la vista de tabla de objetos.",
|
||||
"custom_icon_optional": "Icono (opcional, ej. mdi:wrench)",
|
||||
"notify_icon": "Icono de la notificación",
|
||||
"notify_icon_hint": "Lo muestra la app Companion en Android. Vacío = el icono del tipo de mantenimiento de esta tarea ({default}).",
|
||||
"task_enabled": "Tarea habilitada",
|
||||
"skip_reason_prompt": "¿Omitir esta tarea?",
|
||||
"reason_optional": "Motivo (opcional)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Tomar foto",
|
||||
"camera_capture_shoot": "Capturar",
|
||||
"camera_switch_lens": "Cambiar de cámara",
|
||||
"camera_switch_failed": "Ninguna otra cámara respondió: este teléfono solo expone una. Usa el selector de archivos para el otro objetivo.",
|
||||
"doc_drop_hint": "Suelta los archivos aquí",
|
||||
"doc_task_none": "Ningún documento vinculado a esta tarea.",
|
||||
"doc_link_existing": "Vincular un documento…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "activo",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nuevo)",
|
||||
"adopt_object_hint": "Da a varios sensores el mismo nombre de objeto y se convierten en un solo objeto; escribe el nombre de un objeto existente para añadirlos allí.",
|
||||
"adopt_problem_adopt": "Adoptar seleccionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adoptado(s)",
|
||||
"views_label": "Vistas",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Tehtävä siirretty",
|
||||
"move_task_target": "Kohde",
|
||||
"move_task_message": "Valitse kohde, johon tämän tehtävän tulee kuulua. Historia, lukemat ja liipaisimen tila siirtyvät mukana; tehtävä saa uuden viitenumeron ja sen entiteetit luodaan uudelleen uuden kohteen alle. Linkitetyt asiakirjat jäävät nykyiseen kohteeseen.",
|
||||
"bulk_move_message": "Valitse kohde, johon valittujen tehtävien tulee kuulua. Siellä jo olevat tehtävät ohitetaan; historia, lukemat ja liipaisimen tila siirtyvät mukana.",
|
||||
"bulk_moved": "{n} tehtävää siirretty",
|
||||
"more_actions": "Lisää toimintoja",
|
||||
"move_task_title": "Siirrä tehtävä",
|
||||
"move_task": "Siirrä toiseen kohteeseen…",
|
||||
"object_duplicated": "Kohde monistettu",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} valittu",
|
||||
"bulk_completed": "{n} tehtävää valmiina",
|
||||
"bulk_archived": "{n} tehtävää arkistoitu",
|
||||
"bulk_delete_objects_confirm": "Poistetaanko {n} kohdetta kaikkine tehtävineen? Arkistointi säilyttää historian.",
|
||||
"bulk_objects_deleted": "{n} kohdetta poistettu",
|
||||
"bulk_objects_archived": "{n} kohdetta arkistoitu",
|
||||
"completing": "Suoritetaan…",
|
||||
"interval": "Väli",
|
||||
"warning": "Varoitus",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Viikonpäivät",
|
||||
"nth_weekday": "Kuukauden n:s viikonpäivä",
|
||||
"day_of_month": "Kuukauden päivä",
|
||||
"calendar": "Kalenterientiteetti",
|
||||
"calendar_entity_label": "Kalenteri",
|
||||
"calendar_entity_hint": "Erääntyy kerran tämän kalenterin jokaista tapahtumaa kohti, tapahtuman alkupäivänä — seuraava tapahtuma viimeisimmän suorituksen jälkeen.",
|
||||
"calendar_entity_required": "Valitse kalenterientiteetti.",
|
||||
"recurrence_on_days": "Toista päivinä",
|
||||
"recurrence_occurrence": "Esiintymä",
|
||||
"recurrence_weekday": "Viikonpäivä",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Objektia ei voi linkittää itseensä",
|
||||
"ws_err_too_early": "Liian aikaista — tehtävän voi merkitä tehdyksi vasta lähempänä eräpäivää",
|
||||
"ws_err_invalid_search_template": "Hakulinkin on oltava http(s)-URL, joka sisältää {q}",
|
||||
"ws_err_invalid_icon": "Ilmoituksen kuvakkeen on oltava mdi:-nimi, esim. mdi:air-filter",
|
||||
"feat_schedule_time": "Kellonajan ajoitus",
|
||||
"feat_schedule_time_desc": "Tehtävät erääntyvät tiettyyn kellonaikaan keskiyön sijaan.",
|
||||
"schedule_time_toggle": "Erääntyy tiettyyn kellonaikaan",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Kohdetaulukon sarakkeet",
|
||||
"objects_table_columns_hint": "Valitse, mitkä sarakkeet näkyvät kohdetaulukkonäkymässä.",
|
||||
"custom_icon_optional": "Kuvake (valinnainen, esim. mdi:wrench)",
|
||||
"notify_icon": "Ilmoituksen kuvake",
|
||||
"notify_icon_hint": "Näytetään Companion-sovelluksessa Androidilla. Tyhjä = tämän tehtävän huoltotyypin kuvake ({default}).",
|
||||
"task_enabled": "Tehtävä käytössä",
|
||||
"skip_reason_prompt": "Ohitetaanko tämä tehtävä?",
|
||||
"reason_optional": "Syy (valinnainen)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Ota kuva",
|
||||
"camera_capture_shoot": "Ota kuva",
|
||||
"camera_switch_lens": "Vaihda kameraa",
|
||||
"camera_switch_failed": "Muu kamera ei vastannut – tämä puhelin antaa käyttöön vain yhden. Käytä toiselle objektiiville tiedostovalitsinta.",
|
||||
"doc_drop_hint": "Pudota tiedostot tähän",
|
||||
"doc_task_none": "Tähän tehtävään ei ole liitetty asiakirjoja.",
|
||||
"doc_link_existing": "Liitä asiakirja…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktiivinen",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(uusi)",
|
||||
"adopt_object_hint": "Anna useille antureille sama kohteen nimi, niin niistä tulee yksi kohde; kirjoita olemassa olevan kohteen nimi lisätäksesi ne sinne.",
|
||||
"adopt_problem_adopt": "Ota valitut käyttöön",
|
||||
"adopt_problem_done": "Otettiin käyttöön {tasks} ongelma-anturia",
|
||||
"views_label": "Näkymät",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Tâche déplacée",
|
||||
"move_task_target": "Objet cible",
|
||||
"move_task_message": "Choisissez l'objet auquel cette tâche doit appartenir. Son historique, ses relevés et l'état de son déclencheur la suivent ; elle reçoit un nouveau numéro de référence et ses entités sont recréées sous le nouvel objet. Les documents liés restent avec l'objet actuel.",
|
||||
"bulk_move_message": "Choisissez l'objet auquel les tâches sélectionnées doivent appartenir. Les tâches déjà présentes sont ignorées ; historique, relevés et état du déclencheur suivent.",
|
||||
"bulk_moved": "{n} tâches déplacées",
|
||||
"more_actions": "Autres actions",
|
||||
"move_task_title": "Déplacer la tâche",
|
||||
"move_task": "Déplacer vers un autre objet…",
|
||||
"object_duplicated": "Objet dupliqué",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} sélectionné(s)",
|
||||
"bulk_completed": "{n} tâches terminées",
|
||||
"bulk_archived": "{n} tâches archivées",
|
||||
"bulk_delete_objects_confirm": "Supprimer {n} objets et toutes leurs tâches ? L'archivage conserve leur historique.",
|
||||
"bulk_objects_deleted": "{n} objets supprimés",
|
||||
"bulk_objects_archived": "{n} objets archivés",
|
||||
"completing": "En cours…",
|
||||
"interval": "Intervalle",
|
||||
"warning": "Avertissement",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Jours de semaine",
|
||||
"nth_weekday": "N-ième jour de la semaine du mois",
|
||||
"day_of_month": "Jour du mois",
|
||||
"calendar": "Entité calendrier",
|
||||
"calendar_entity_label": "Calendrier",
|
||||
"calendar_entity_hint": "À faire une fois par événement de ce calendrier, à la date de début de l'événement — le prochain événement après la dernière réalisation.",
|
||||
"calendar_entity_required": "Choisissez une entité calendrier.",
|
||||
"recurrence_on_days": "Répéter le",
|
||||
"recurrence_occurrence": "Occurrence",
|
||||
"recurrence_weekday": "Jour de semaine",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Un objet ne peut pas être lié à lui-même",
|
||||
"ws_err_too_early": "Trop tôt — cette tâche ne peut être terminée que plus près de son échéance",
|
||||
"ws_err_invalid_search_template": "Le lien de recherche doit être une URL http(s) contenant {q}",
|
||||
"ws_err_invalid_icon": "L'icône de notification doit être un nom mdi:, p. ex. mdi:air-filter",
|
||||
"feat_schedule_time": "Planification à l'heure",
|
||||
"feat_schedule_time_desc": "Les tâches arrivent à échéance à une heure précise plutôt qu'à minuit.",
|
||||
"schedule_time_toggle": "Échéance à une heure précise",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Colonnes du tableau d'objets",
|
||||
"objects_table_columns_hint": "Choisissez les colonnes affichées dans la vue tableau des objets.",
|
||||
"custom_icon_optional": "Icône (optionnel, ex. mdi:wrench)",
|
||||
"notify_icon": "Icône de notification",
|
||||
"notify_icon_hint": "Affichée par l'application Companion sur Android. Vide = l'icône du type d'entretien de cette tâche ({default}).",
|
||||
"task_enabled": "Tâche activée",
|
||||
"skip_reason_prompt": "Ignorer cette tâche ?",
|
||||
"reason_optional": "Raison (optionnel)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Prendre une photo",
|
||||
"camera_capture_shoot": "Prendre la photo",
|
||||
"camera_switch_lens": "Changer de caméra",
|
||||
"camera_switch_failed": "Aucune autre caméra n'a répondu — ce téléphone n'en expose qu'une. Utilisez le sélecteur de fichiers pour l'autre objectif.",
|
||||
"doc_drop_hint": "Déposez les fichiers ici",
|
||||
"doc_task_none": "Aucun document lié à cette tâche.",
|
||||
"doc_link_existing": "Lier un document…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "actif",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nouveau)",
|
||||
"adopt_object_hint": "Donnez le même nom d'objet à plusieurs capteurs et ils forment un seul objet ; saisissez le nom d'un objet existant pour les y ajouter.",
|
||||
"adopt_problem_adopt": "Adopter la sélection",
|
||||
"adopt_problem_done": "{tasks} capteur(s) de problème adopté(s)",
|
||||
"views_label": "Vues",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "कार्य ले जाया गया",
|
||||
"move_task_target": "लक्ष्य ऑब्जेक्ट",
|
||||
"move_task_message": "वह ऑब्जेक्ट चुनें जिससे यह कार्य जुड़ा होना चाहिए। इतिहास, रीडिंग और ट्रिगर स्थिति साथ जाएँगे; इसे नया संदर्भ नंबर मिलेगा और इसकी एंटिटी नए ऑब्जेक्ट के अंतर्गत फिर से बनेंगी। जुड़े दस्तावेज़ वर्तमान ऑब्जेक्ट के पास रहेंगे।",
|
||||
"bulk_move_message": "वह ऑब्जेक्ट चुनें जिससे चयनित कार्य जुड़ने चाहिए। जो पहले से वहाँ हैं उन्हें छोड़ दिया जाता है; इतिहास, रीडिंग और ट्रिगर स्थिति साथ में जाते हैं।",
|
||||
"bulk_moved": "{n} कार्य स्थानांतरित किए गए",
|
||||
"more_actions": "और कार्रवाइयाँ",
|
||||
"move_task_title": "कार्य ले जाएँ",
|
||||
"move_task": "दूसरे ऑब्जेक्ट में ले जाएँ…",
|
||||
"object_duplicated": "ऑब्जेक्ट डुप्लिकेट किया गया",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} चयनित",
|
||||
"bulk_completed": "{n} कार्य पूर्ण",
|
||||
"bulk_archived": "{n} कार्य संग्रहित",
|
||||
"bulk_delete_objects_confirm": "{n} ऑब्जेक्ट और उनके सभी कार्य हटाएँ? संग्रहित करने से उनका इतिहास बना रहता है।",
|
||||
"bulk_objects_deleted": "{n} ऑब्जेक्ट हटाए गए",
|
||||
"bulk_objects_archived": "{n} ऑब्जेक्ट संग्रहित किए गए",
|
||||
"completing": "पूर्ण किया जा रहा है…",
|
||||
"interval": "अंतराल",
|
||||
"warning": "चेतावनी",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "सप्ताह के दिन",
|
||||
"nth_weekday": "महीने का N-वाँ सप्ताह-दिन",
|
||||
"day_of_month": "महीने का दिन",
|
||||
"calendar": "कैलेंडर एंटिटी",
|
||||
"calendar_entity_label": "कैलेंडर",
|
||||
"calendar_entity_hint": "इस कैलेंडर की हर घटना पर एक बार, घटना की शुरुआत की तारीख को देय — पिछली बार पूरा करने के बाद की अगली घटना।",
|
||||
"calendar_entity_required": "एक कैलेंडर एंटिटी चुनें।",
|
||||
"recurrence_on_days": "दोहराएँ",
|
||||
"recurrence_occurrence": "घटना",
|
||||
"recurrence_weekday": "सप्ताह-दिन",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "कोई ऑब्जेक्ट स्वयं से लिंक नहीं हो सकता",
|
||||
"ws_err_too_early": "बहुत जल्दी — यह कार्य केवल नियत तारीख के करीब ही पूरा किया जा सकता है",
|
||||
"ws_err_invalid_search_template": "खोज लिंक {q} वाला http(s) URL होना चाहिए",
|
||||
"ws_err_invalid_icon": "सूचना आइकन एक mdi: नाम होना चाहिए, जैसे mdi:air-filter",
|
||||
"feat_schedule_time": "दिन का समय निर्धारण",
|
||||
"feat_schedule_time_desc": "कार्य मध्यरात्रि के बजाय दिन के एक विशिष्ट समय पर अतिदेय हो जाते हैं।",
|
||||
"schedule_time_toggle": "किसी निश्चित समय पर देय",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "वस्तु तालिका कॉलम",
|
||||
"objects_table_columns_hint": "चुनें कि वस्तु तालिका दृश्य में कौन से कॉलम दिखाई दें।",
|
||||
"custom_icon_optional": "आइकन (वैकल्पिक, उदा. mdi:wrench)",
|
||||
"notify_icon": "सूचना आइकन",
|
||||
"notify_icon_hint": "Android पर Companion ऐप में दिखता है। खाली = इस कार्य के रखरखाव प्रकार का आइकन ({default})।",
|
||||
"task_enabled": "कार्य सक्षम",
|
||||
"skip_reason_prompt": "इस कार्य को छोड़ें?",
|
||||
"reason_optional": "कारण (वैकल्पिक)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "फ़ोटो लें",
|
||||
"camera_capture_shoot": "कैप्चर करें",
|
||||
"camera_switch_lens": "कैमरा बदलें",
|
||||
"camera_switch_failed": "किसी अन्य कैमरे ने जवाब नहीं दिया — यह फ़ोन केवल एक ही देता है। दूसरे लेंस के लिए फ़ाइल चयनकर्ता का उपयोग करें।",
|
||||
"doc_drop_hint": "फ़ाइलें यहाँ छोड़ें",
|
||||
"doc_task_none": "इस कार्य से कोई दस्तावेज़ संबद्ध नहीं है।",
|
||||
"doc_link_existing": "दस्तावेज़ जोड़ें…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "सक्रिय",
|
||||
"adopt_problem_ok": "ठीक",
|
||||
"adopt_problem_new_object": "(नया)",
|
||||
"adopt_object_hint": "कई सेंसरों को एक ही ऑब्जेक्ट नाम दें तो वे एक ऑब्जेक्ट बन जाते हैं; मौजूदा ऑब्जेक्ट का नाम लिखें तो वे वहीं जुड़ जाते हैं।",
|
||||
"adopt_problem_adopt": "चयनित अपनाएँ",
|
||||
"adopt_problem_done": "{tasks} समस्या सेंसर अपनाए गए",
|
||||
"views_label": "व्यू",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Feladat áthelyezve",
|
||||
"move_task_target": "Célobjektum",
|
||||
"move_task_message": "Válaszd ki, melyik objektumhoz tartozzon ez a feladat. Az előzmények, a mérőállások és a trigger állapota vele költöznek; új hivatkozási számot kap, és az entitásai az új objektum alatt jönnek létre újra. A csatolt dokumentumok a jelenlegi objektumnál maradnak.",
|
||||
"bulk_move_message": "Válassza ki az objektumot, amelyhez a kijelölt feladatok tartozzanak. Az ott lévőket kihagyja; az előzmények, mérések és a kioldó állapota velük költöznek.",
|
||||
"bulk_moved": "{n} feladat áthelyezve",
|
||||
"more_actions": "További műveletek",
|
||||
"move_task_title": "Feladat áthelyezése",
|
||||
"move_task": "Áthelyezés másik objektumba…",
|
||||
"object_duplicated": "Objektum duplikálva",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} kijelölve",
|
||||
"bulk_completed": "{n} feladat elvégezve",
|
||||
"bulk_archived": "{n} feladat archiválva",
|
||||
"bulk_delete_objects_confirm": "Törli a(z) {n} objektumot az összes feladatával együtt? Az archiválás ehelyett megőrzi az előzményeket.",
|
||||
"bulk_objects_deleted": "{n} objektum törölve",
|
||||
"bulk_objects_archived": "{n} objektum archiválva",
|
||||
"completing": "Elvégzés…",
|
||||
"interval": "Intervallum",
|
||||
"warning": "Figyelmeztetés",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Hét napjai",
|
||||
"nth_weekday": "A hónap n. hétnapja",
|
||||
"day_of_month": "A hónap napja",
|
||||
"calendar": "Naptárentitás",
|
||||
"calendar_entity_label": "Naptár",
|
||||
"calendar_entity_hint": "A naptár minden eseményénél egyszer esedékes, az esemény kezdőnapján — az utolsó elvégzés utáni következő esemény.",
|
||||
"calendar_entity_required": "Válasszon egy naptárentitást.",
|
||||
"recurrence_on_days": "Ismétlés ezeken a napokon",
|
||||
"recurrence_occurrence": "Előfordulás",
|
||||
"recurrence_weekday": "Hét napja",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Egy objektum nem kapcsolható önmagához",
|
||||
"ws_err_too_early": "Túl korai — ez a feladat csak a határidőhöz közelebb fejezhető be",
|
||||
"ws_err_invalid_search_template": "A keresőhivatkozásnak {q}-t tartalmazó http(s) URL-nek kell lennie",
|
||||
"ws_err_invalid_icon": "Az értesítés ikonjának mdi: névnek kell lennie, pl. mdi:air-filter",
|
||||
"feat_schedule_time": "Napszakhoz kötött ütemezés",
|
||||
"feat_schedule_time_desc": "A feladatok nem éjfélkor, hanem egy megadott napszakban válnak lejárttá.",
|
||||
"schedule_time_toggle": "Adott időpontban esedékes",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Objektumtáblázat oszlopai",
|
||||
"objects_table_columns_hint": "Válassza ki, mely oszlopok jelenjenek meg az objektumok táblázatnézetében.",
|
||||
"custom_icon_optional": "Ikon (opcionális, pl. mdi:wrench)",
|
||||
"notify_icon": "Értesítés ikonja",
|
||||
"notify_icon_hint": "Az androidos Companion alkalmazás mutatja. Üres = a feladat karbantartási típusának ikonja ({default}).",
|
||||
"task_enabled": "Feladat engedélyezve",
|
||||
"skip_reason_prompt": "Kihagyja ezt a feladatot?",
|
||||
"reason_optional": "Indoklás (opcionális)",
|
||||
@@ -784,6 +797,7 @@
|
||||
"doc_camera": "Fotó készítése",
|
||||
"camera_capture_shoot": "Felvétel",
|
||||
"camera_switch_lens": "Kamera váltása",
|
||||
"camera_switch_failed": "Nem válaszolt másik kamera – ez a telefon csak egyet ad ki. A másik objektívhez használja a fájlválasztót.",
|
||||
"doc_drop_hint": "Húzza ide a fájlokat",
|
||||
"doc_task_none": "Ehhez a feladathoz nincs dokumentum csatolva.",
|
||||
"doc_link_existing": "Dokumentum hozzárendelése…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktív",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(új)",
|
||||
"adopt_object_hint": "Adja több érzékelőnek ugyanazt az objektumnevet, és egy objektummá válnak; meglévő objektum nevét beírva oda kerülnek.",
|
||||
"adopt_problem_adopt": "Kijelöltek átvétele",
|
||||
"adopt_problem_done": "{tasks} problémaérzékelő átvéve",
|
||||
"views_label": "Nézetek",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Attività spostata",
|
||||
"move_task_target": "Oggetto di destinazione",
|
||||
"move_task_message": "Scegli l'oggetto a cui deve appartenere questa attività. Storico, letture e stato del trigger si spostano con lei; riceve un nuovo numero di riferimento e le sue entità vengono ricreate sotto il nuovo oggetto. I documenti collegati restano con l'oggetto attuale.",
|
||||
"bulk_move_message": "Scegli l'oggetto a cui devono appartenere le attività selezionate. Quelle già presenti vengono saltate; cronologia, letture e stato del trigger si spostano insieme.",
|
||||
"bulk_moved": "{n} attività spostate",
|
||||
"more_actions": "Altre azioni",
|
||||
"move_task_title": "Sposta attività",
|
||||
"move_task": "Sposta in un altro oggetto…",
|
||||
"object_duplicated": "Oggetto duplicato",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} selezionati",
|
||||
"bulk_completed": "{n} attività completate",
|
||||
"bulk_archived": "{n} attività archiviate",
|
||||
"bulk_delete_objects_confirm": "Eliminare {n} oggetti con tutte le loro attività? L'archiviazione conserva invece la cronologia.",
|
||||
"bulk_objects_deleted": "{n} oggetti eliminati",
|
||||
"bulk_objects_archived": "{n} oggetti archiviati",
|
||||
"completing": "Completamento…",
|
||||
"interval": "Intervallo",
|
||||
"warning": "Avviso",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Giorni della settimana",
|
||||
"nth_weekday": "N-esimo giorno della settimana del mese",
|
||||
"day_of_month": "Giorno del mese",
|
||||
"calendar": "Entità calendario",
|
||||
"calendar_entity_label": "Calendario",
|
||||
"calendar_entity_hint": "Da fare una volta per ogni evento di questo calendario, nella data di inizio dell'evento — il prossimo evento dopo l'ultimo completamento.",
|
||||
"calendar_entity_required": "Scegli un'entità calendario.",
|
||||
"recurrence_on_days": "Ripeti il",
|
||||
"recurrence_occurrence": "Occorrenza",
|
||||
"recurrence_weekday": "Giorno della settimana",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Un oggetto non può essere collegato a sé stesso",
|
||||
"ws_err_too_early": "Troppo presto — questa attività può essere completata solo più vicino alla scadenza",
|
||||
"ws_err_invalid_search_template": "Il link di ricerca deve essere un URL http(s) contenente {q}",
|
||||
"ws_err_invalid_icon": "L'icona della notifica deve essere un nome mdi:, ad es. mdi:air-filter",
|
||||
"feat_schedule_time": "Pianificazione oraria",
|
||||
"feat_schedule_time_desc": "Le attività scadono a un'ora specifica anziché a mezzanotte.",
|
||||
"schedule_time_toggle": "Scadenza a un orario preciso",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Colonne tabella oggetti",
|
||||
"objects_table_columns_hint": "Scegli quali colonne mostrare nella vista tabella degli oggetti.",
|
||||
"custom_icon_optional": "Icona (opzionale, es. mdi:wrench)",
|
||||
"notify_icon": "Icona della notifica",
|
||||
"notify_icon_hint": "Mostrata dall'app Companion su Android. Vuoto = l'icona del tipo di manutenzione di questa attività ({default}).",
|
||||
"task_enabled": "Attività abilitata",
|
||||
"skip_reason_prompt": "Saltare questa attività?",
|
||||
"reason_optional": "Motivo (opzionale)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Scatta foto",
|
||||
"camera_capture_shoot": "Scatta",
|
||||
"camera_switch_lens": "Cambia fotocamera",
|
||||
"camera_switch_failed": "Nessun'altra fotocamera ha risposto: questo telefono ne espone una sola. Per l'altro obiettivo usa la selezione file.",
|
||||
"doc_drop_hint": "Trascina qui i file",
|
||||
"doc_task_none": "Nessun documento collegato a questa attività.",
|
||||
"doc_link_existing": "Collega un documento…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "attivo",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nuovo)",
|
||||
"adopt_object_hint": "Assegna lo stesso nome oggetto a più sensori e diventano un unico oggetto; digita il nome di un oggetto esistente per aggiungerli lì.",
|
||||
"adopt_problem_adopt": "Adotta selezionati",
|
||||
"adopt_problem_done": "{tasks} sensore/i di problema adottato/i",
|
||||
"views_label": "Viste",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "タスクを移動しました",
|
||||
"move_task_target": "移動先オブジェクト",
|
||||
"move_task_message": "このタスクを所属させるオブジェクトを選んでください。履歴・検針値・トリガー状態は一緒に移動し、新しい参照番号が付き、エンティティは新しいオブジェクトの下で作り直されます。関連付けた文書は現在のオブジェクトに残ります。",
|
||||
"bulk_move_message": "選択したタスクの所属先オブジェクトを選んでください。すでにそこにあるタスクはスキップされ、履歴・計測値・トリガー状態は一緒に移動します。",
|
||||
"bulk_moved": "{n} 件のタスクを移動しました",
|
||||
"more_actions": "その他の操作",
|
||||
"move_task_title": "タスクを移動",
|
||||
"move_task": "別のオブジェクトへ移動…",
|
||||
"object_duplicated": "オブジェクトを複製しました",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} 件選択",
|
||||
"bulk_completed": "{n} 件のタスクを完了",
|
||||
"bulk_archived": "{n} 件のタスクをアーカイブ",
|
||||
"bulk_delete_objects_confirm": "{n} 件のオブジェクトとそのすべてのタスクを削除しますか?アーカイブなら履歴が残ります。",
|
||||
"bulk_objects_deleted": "{n} 件のオブジェクトを削除しました",
|
||||
"bulk_objects_archived": "{n} 件のオブジェクトをアーカイブしました",
|
||||
"completing": "完了処理中…",
|
||||
"interval": "間隔",
|
||||
"warning": "警告",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "曜日",
|
||||
"nth_weekday": "毎月第N曜日",
|
||||
"day_of_month": "毎月の日",
|
||||
"calendar": "カレンダーエンティティ",
|
||||
"calendar_entity_label": "カレンダー",
|
||||
"calendar_entity_hint": "このカレンダーの予定ごとに1回、予定の開始日に期限を迎えます — 前回完了後の次の予定です。",
|
||||
"calendar_entity_required": "カレンダーエンティティを選択してください。",
|
||||
"recurrence_on_days": "繰り返す曜日",
|
||||
"recurrence_occurrence": "出現週",
|
||||
"recurrence_weekday": "曜日",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "オブジェクトを自分自身にリンクすることはできません",
|
||||
"ws_err_too_early": "早すぎます — このタスクは期日が近づいてからのみ完了できます",
|
||||
"ws_err_invalid_search_template": "検索リンクは {q} を含む http(s) URL である必要があります",
|
||||
"ws_err_invalid_icon": "通知アイコンは mdi: 名である必要があります(例: mdi:air-filter)",
|
||||
"feat_schedule_time": "時刻指定スケジュール",
|
||||
"feat_schedule_time_desc": "タスクが深夜0時ではなく指定した時刻に期限超過となります。",
|
||||
"schedule_time_toggle": "特定の時刻に期限",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "対象テーブルの列",
|
||||
"objects_table_columns_hint": "対象のテーブル表示に表示する列を選択します。",
|
||||
"custom_icon_optional": "アイコン(任意、例: mdi:wrench)",
|
||||
"notify_icon": "通知アイコン",
|
||||
"notify_icon_hint": "Android の Companion アプリに表示されます。空欄 = このタスクのメンテナンス種別のアイコン({default})。",
|
||||
"task_enabled": "タスク有効",
|
||||
"skip_reason_prompt": "このタスクをスキップしますか?",
|
||||
"reason_optional": "理由(任意)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "写真を撮る",
|
||||
"camera_capture_shoot": "撮影",
|
||||
"camera_switch_lens": "カメラを切り替え",
|
||||
"camera_switch_failed": "他のカメラが応答しませんでした。この端末は1台しか公開していません。別のレンズにはファイル選択を使ってください。",
|
||||
"doc_drop_hint": "ここにファイルをドロップ",
|
||||
"doc_task_none": "このタスクに紐付いたドキュメントはありません。",
|
||||
"doc_link_existing": "ドキュメントを紐付け…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "発生中",
|
||||
"adopt_problem_ok": "正常",
|
||||
"adopt_problem_new_object": "(新規)",
|
||||
"adopt_object_hint": "複数のセンサーに同じオブジェクト名を付けると1つのオブジェクトになります。既存のオブジェクト名を入力すればそこに追加されます。",
|
||||
"adopt_problem_adopt": "選択を取り込む",
|
||||
"adopt_problem_done": "{tasks} 件の問題センサーを取り込みました",
|
||||
"views_label": "ビュー",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "작업을 이동했습니다",
|
||||
"move_task_target": "대상 개체",
|
||||
"move_task_message": "이 작업이 속할 개체를 선택하세요. 이력, 검침값, 트리거 상태가 함께 이동하며 새 참조 번호를 받고 엔티티는 새 개체 아래에 다시 생성됩니다. 연결된 문서는 현재 개체에 남습니다.",
|
||||
"bulk_move_message": "선택한 작업이 속할 개체를 고르세요. 이미 그곳에 있는 작업은 건너뛰며 기록, 측정값, 트리거 상태가 함께 이동합니다.",
|
||||
"bulk_moved": "작업 {n}개 이동됨",
|
||||
"more_actions": "추가 작업",
|
||||
"move_task_title": "작업 이동",
|
||||
"move_task": "다른 개체로 이동…",
|
||||
"object_duplicated": "객체가 복제되었습니다",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n}개 선택됨",
|
||||
"bulk_completed": "작업 {n}개 완료됨",
|
||||
"bulk_archived": "작업 {n}개 보관됨",
|
||||
"bulk_delete_objects_confirm": "개체 {n}개와 모든 작업을 삭제할까요? 보관하면 기록이 유지됩니다.",
|
||||
"bulk_objects_deleted": "개체 {n}개 삭제됨",
|
||||
"bulk_objects_archived": "개체 {n}개 보관됨",
|
||||
"completing": "완료 처리 중…",
|
||||
"interval": "주기",
|
||||
"warning": "경고",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "요일",
|
||||
"nth_weekday": "매월 N번째 요일",
|
||||
"day_of_month": "매월 특정 일",
|
||||
"calendar": "캘린더 엔티티",
|
||||
"calendar_entity_label": "캘린더",
|
||||
"calendar_entity_hint": "이 캘린더의 이벤트마다 한 번, 이벤트 시작일에 기한이 됩니다 — 마지막 완료 이후의 다음 이벤트입니다.",
|
||||
"calendar_entity_required": "캘린더 엔티티를 선택하세요.",
|
||||
"recurrence_on_days": "반복 요일",
|
||||
"recurrence_occurrence": "회차",
|
||||
"recurrence_weekday": "요일",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "객체는 자기 자신에게 연결할 수 없음",
|
||||
"ws_err_too_early": "너무 이름 — 이 작업은 기한에 가까워져야 완료할 수 있습니다",
|
||||
"ws_err_invalid_search_template": "검색 링크는 {q}를 포함한 http(s) URL이어야 합니다",
|
||||
"ws_err_invalid_icon": "알림 아이콘은 mdi: 이름이어야 합니다(예: mdi:air-filter)",
|
||||
"feat_schedule_time": "시각 지정 일정",
|
||||
"feat_schedule_time_desc": "작업이 자정이 아닌 지정한 시각에 기한 초과로 전환됩니다.",
|
||||
"schedule_time_toggle": "특정 시각에 기한",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "객체 표 열",
|
||||
"objects_table_columns_hint": "객체 표 보기에 표시할 열을 선택하세요.",
|
||||
"custom_icon_optional": "아이콘 (선택, 예: mdi:wrench)",
|
||||
"notify_icon": "알림 아이콘",
|
||||
"notify_icon_hint": "Android의 Companion 앱에 표시됩니다. 비워 두면 이 작업의 유지보수 유형 아이콘({default})을 사용합니다.",
|
||||
"task_enabled": "작업 활성화",
|
||||
"skip_reason_prompt": "이 작업을 건너뛸까요?",
|
||||
"reason_optional": "사유 (선택)",
|
||||
@@ -784,6 +797,7 @@
|
||||
"doc_camera": "사진 촬영",
|
||||
"camera_capture_shoot": "촬영",
|
||||
"camera_switch_lens": "카메라 전환",
|
||||
"camera_switch_failed": "다른 카메라가 응답하지 않았습니다. 이 휴대폰은 하나만 제공합니다. 다른 렌즈는 파일 선택기를 사용하세요.",
|
||||
"doc_drop_hint": "파일을 여기에 놓으세요",
|
||||
"doc_task_none": "이 작업에 연결된 문서가 없습니다.",
|
||||
"doc_link_existing": "문서 연결…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "활성",
|
||||
"adopt_problem_ok": "정상",
|
||||
"adopt_problem_new_object": "(신규)",
|
||||
"adopt_object_hint": "여러 센서에 같은 개체 이름을 주면 하나의 개체가 됩니다. 기존 개체 이름을 입력하면 거기에 추가됩니다.",
|
||||
"adopt_problem_adopt": "선택 항목 가져오기",
|
||||
"adopt_problem_done": "문제 센서 {tasks}개를 가져왔습니다",
|
||||
"views_label": "보기",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Oppgave flyttet",
|
||||
"move_task_target": "Målobjekt",
|
||||
"move_task_message": "Velg objektet denne oppgaven skal tilhøre. Historikk, avlesninger og utløserstatus følger med; den får et nytt referansenummer, og entitetene opprettes på nytt under det nye objektet. Tilknyttede dokumenter blir hos det nåværende objektet.",
|
||||
"bulk_move_message": "Velg objektet de merkede oppgavene skal tilhøre. Oppgaver som allerede er der hoppes over; historikk, avlesninger og utløserstatus flytter med.",
|
||||
"bulk_moved": "{n} oppgaver flyttet",
|
||||
"more_actions": "Flere handlinger",
|
||||
"move_task_title": "Flytt oppgave",
|
||||
"move_task": "Flytt til et annet objekt…",
|
||||
"object_duplicated": "Objekt duplisert",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} valgt",
|
||||
"bulk_completed": "{n} oppgaver fullført",
|
||||
"bulk_archived": "{n} oppgaver arkivert",
|
||||
"bulk_delete_objects_confirm": "Slette {n} objekter og alle oppgavene deres? Arkivering beholder historikken i stedet.",
|
||||
"bulk_objects_deleted": "{n} objekter slettet",
|
||||
"bulk_objects_archived": "{n} objekter arkivert",
|
||||
"completing": "Fullfører…",
|
||||
"interval": "Intervall",
|
||||
"warning": "Advarsel",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Ukedager",
|
||||
"nth_weekday": "N-te ukedag i måneden",
|
||||
"day_of_month": "Dag i måneden",
|
||||
"calendar": "Kalenderentitet",
|
||||
"calendar_entity_label": "Kalender",
|
||||
"calendar_entity_hint": "Forfaller én gang per hendelse i denne kalenderen, på hendelsens startdato — neste hendelse etter siste utførelse.",
|
||||
"calendar_entity_required": "Velg en kalenderentitet.",
|
||||
"recurrence_on_days": "Gjenta på",
|
||||
"recurrence_occurrence": "Forekomst",
|
||||
"recurrence_weekday": "Ukedag",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Et objekt kan ikke kobles til seg selv",
|
||||
"ws_err_too_early": "For tidlig — oppgaven kan først fullføres nærmere forfallsdatoen",
|
||||
"ws_err_invalid_search_template": "Søkelenken må være en http(s)-URL som inneholder {q}",
|
||||
"ws_err_invalid_icon": "Varselikonet må være et mdi:-navn, f.eks. mdi:air-filter",
|
||||
"feat_schedule_time": "Planlegging med klokkeslett",
|
||||
"feat_schedule_time_desc": "Oppgaver forfaller på et bestemt klokkeslett i stedet for ved midnatt.",
|
||||
"schedule_time_toggle": "Forfaller på et bestemt klokkeslett",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Kolonner i objekttabell",
|
||||
"objects_table_columns_hint": "Velg hvilke kolonner som vises i tabellvisningen for objekter.",
|
||||
"custom_icon_optional": "Ikon (valgfritt, f.eks. mdi:wrench)",
|
||||
"notify_icon": "Varselikon",
|
||||
"notify_icon_hint": "Vises av Companion-appen på Android. Tom = ikonet for oppgavens vedlikeholdstype ({default}).",
|
||||
"task_enabled": "Oppgave aktivert",
|
||||
"skip_reason_prompt": "Hoppe over denne oppgaven?",
|
||||
"reason_optional": "Årsak (valgfritt)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Ta bilde",
|
||||
"camera_capture_shoot": "Ta bilde",
|
||||
"camera_switch_lens": "Bytt kamera",
|
||||
"camera_switch_failed": "Ingen andre kameraer svarte – denne telefonen gir bare fra seg ett. Bruk filvelgeren for det andre objektivet.",
|
||||
"doc_drop_hint": "Slipp filer her",
|
||||
"doc_task_none": "Ingen dokumenter knyttet til denne oppgaven.",
|
||||
"doc_link_existing": "Knytt et dokument…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktiv",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(ny)",
|
||||
"adopt_object_hint": "Gi flere sensorer samme objektnavn, så blir de ett objekt; skriv navnet på et eksisterende objekt for å legge dem der.",
|
||||
"adopt_problem_adopt": "Ta i bruk valgte",
|
||||
"adopt_problem_done": "Tok i bruk {tasks} problemsensor(er)",
|
||||
"views_label": "Visninger",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Taak verplaatst",
|
||||
"move_task_target": "Doelobject",
|
||||
"move_task_message": "Kies het object waar deze taak bij hoort. Geschiedenis, meterstanden en triggerstatus verhuizen mee; de taak krijgt een nieuw referentienummer en haar entiteiten worden onder het nieuwe object opnieuw aangemaakt. Gekoppelde documenten blijven bij het huidige object.",
|
||||
"bulk_move_message": "Kies het object waartoe de geselecteerde taken moeten behoren. Taken die daar al staan worden overgeslagen; geschiedenis, meetwaarden en triggerstatus verhuizen mee.",
|
||||
"bulk_moved": "{n} taken verplaatst",
|
||||
"more_actions": "Meer acties",
|
||||
"move_task_title": "Taak verplaatsen",
|
||||
"move_task": "Naar ander object verplaatsen…",
|
||||
"object_duplicated": "Object gedupliceerd",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} geselecteerd",
|
||||
"bulk_completed": "{n} taken voltooid",
|
||||
"bulk_archived": "{n} taken gearchiveerd",
|
||||
"bulk_delete_objects_confirm": "{n} objecten met al hun taken verwijderen? Archiveren bewaart in plaats daarvan de geschiedenis.",
|
||||
"bulk_objects_deleted": "{n} objecten verwijderd",
|
||||
"bulk_objects_archived": "{n} objecten gearchiveerd",
|
||||
"completing": "Wordt voltooid…",
|
||||
"interval": "Interval",
|
||||
"warning": "Waarschuwing",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Weekdagen",
|
||||
"nth_weekday": "Zoveelste weekdag van de maand",
|
||||
"day_of_month": "Dag van de maand",
|
||||
"calendar": "Kalender-entiteit",
|
||||
"calendar_entity_label": "Kalender",
|
||||
"calendar_entity_hint": "Eén keer per gebeurtenis van deze kalender, op de startdatum van de gebeurtenis — de volgende gebeurtenis na de laatste afronding.",
|
||||
"calendar_entity_required": "Kies een kalender-entiteit.",
|
||||
"recurrence_on_days": "Herhalen op",
|
||||
"recurrence_occurrence": "Voorkomen",
|
||||
"recurrence_weekday": "Weekdag",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Een object kan niet aan zichzelf worden gekoppeld",
|
||||
"ws_err_too_early": "Te vroeg — deze taak kan pas dichter bij de vervaldatum worden afgerond",
|
||||
"ws_err_invalid_search_template": "De zoeklink moet een http(s)-URL met {q} zijn",
|
||||
"ws_err_invalid_icon": "Het meldingspictogram moet een mdi:-naam zijn, bijv. mdi:air-filter",
|
||||
"feat_schedule_time": "Tijd-van-dag-planning",
|
||||
"feat_schedule_time_desc": "Taken vervallen op een specifieke tijd in plaats van middernacht.",
|
||||
"schedule_time_toggle": "Vervalt op een vast tijdstip",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Kolommen objecttabel",
|
||||
"objects_table_columns_hint": "Kies welke kolommen in de tabelweergave van objecten verschijnen.",
|
||||
"custom_icon_optional": "Icoon (optioneel, bijv. mdi:wrench)",
|
||||
"notify_icon": "Meldingspictogram",
|
||||
"notify_icon_hint": "Getoond door de Companion-app op Android. Leeg = het pictogram van het onderhoudstype van deze taak ({default}).",
|
||||
"task_enabled": "Taak ingeschakeld",
|
||||
"skip_reason_prompt": "Deze taak overslaan?",
|
||||
"reason_optional": "Reden (optioneel)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Foto maken",
|
||||
"camera_capture_shoot": "Vastleggen",
|
||||
"camera_switch_lens": "Camera wisselen",
|
||||
"camera_switch_failed": "Geen andere camera reageerde — deze telefoon geeft er maar één vrij. Gebruik de bestandskiezer voor de andere lens.",
|
||||
"doc_drop_hint": "Sleep bestanden hierheen",
|
||||
"doc_task_none": "Geen documenten aan deze taak gekoppeld.",
|
||||
"doc_link_existing": "Document koppelen…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "actief",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nieuw)",
|
||||
"adopt_object_hint": "Geef meerdere sensoren dezelfde objectnaam en ze worden één object; typ de naam van een bestaand object om ze daar toe te voegen.",
|
||||
"adopt_problem_adopt": "Selectie overnemen",
|
||||
"adopt_problem_done": "{tasks} probleemsensor(en) overgenomen",
|
||||
"views_label": "Weergaven",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Zadanie przeniesione",
|
||||
"move_task_target": "Obiekt docelowy",
|
||||
"move_task_message": "Wybierz obiekt, do którego ma należeć to zadanie. Historia, odczyty i stan wyzwalacza przenoszą się razem z nim; dostaje nowy numer referencyjny, a jego encje są tworzone na nowo pod nowym obiektem. Powiązane dokumenty zostają przy obecnym obiekcie.",
|
||||
"bulk_move_message": "Wybierz obiekt, do którego mają należeć zaznaczone zadania. Te, które już tam są, zostaną pominięte; historia, odczyty i stan wyzwalacza przenoszą się razem.",
|
||||
"bulk_moved": "Przeniesiono zadań: {n}",
|
||||
"more_actions": "Więcej działań",
|
||||
"move_task_title": "Przenieś zadanie",
|
||||
"move_task": "Przenieś do innego obiektu…",
|
||||
"object_duplicated": "Obiekt zduplikowany",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "Zaznaczono {n}",
|
||||
"bulk_completed": "Ukończono {n} zadań",
|
||||
"bulk_archived": "Zarchiwizowano {n} zadań",
|
||||
"bulk_delete_objects_confirm": "Usunąć {n} obiektów wraz ze wszystkimi zadaniami? Archiwizacja zachowa ich historię.",
|
||||
"bulk_objects_deleted": "Usunięto obiektów: {n}",
|
||||
"bulk_objects_archived": "Zarchiwizowano obiektów: {n}",
|
||||
"completing": "Wykonywanie…",
|
||||
"interval": "Interwał",
|
||||
"warning": "Ostrzeżenie",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Dni tygodnia",
|
||||
"nth_weekday": "N-ty dzień tygodnia w miesiącu",
|
||||
"day_of_month": "Dzień miesiąca",
|
||||
"calendar": "Encja kalendarza",
|
||||
"calendar_entity_label": "Kalendarz",
|
||||
"calendar_entity_hint": "Termin przypada raz na każde wydarzenie z tego kalendarza, w dniu rozpoczęcia wydarzenia — następne wydarzenie po ostatnim wykonaniu.",
|
||||
"calendar_entity_required": "Wybierz encję kalendarza.",
|
||||
"recurrence_on_days": "Powtarzaj w",
|
||||
"recurrence_occurrence": "Wystąpienie",
|
||||
"recurrence_weekday": "Dzień tygodnia",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Obiekt nie może być powiązany sam ze sobą",
|
||||
"ws_err_too_early": "Za wcześnie — to zadanie można ukończyć dopiero bliżej terminu",
|
||||
"ws_err_invalid_search_template": "Link wyszukiwania musi być adresem URL http(s) zawierającym {q}",
|
||||
"ws_err_invalid_icon": "Ikona powiadomienia musi być nazwą mdi:, np. mdi:air-filter",
|
||||
"feat_schedule_time": "Harmonogram według pory dnia",
|
||||
"feat_schedule_time_desc": "Zadania stają się zaległe o określonej porze dnia zamiast o północy.",
|
||||
"schedule_time_toggle": "Termin o określonej godzinie",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Kolumny tabeli obiektów",
|
||||
"objects_table_columns_hint": "Wybierz, które kolumny mają być widoczne w widoku tabeli obiektów.",
|
||||
"custom_icon_optional": "Ikona (opcjonalna, np. mdi:wrench)",
|
||||
"notify_icon": "Ikona powiadomienia",
|
||||
"notify_icon_hint": "Wyświetlana przez aplikację Companion na Androidzie. Puste = ikona typu konserwacji tego zadania ({default}).",
|
||||
"task_enabled": "Zadanie włączone",
|
||||
"skip_reason_prompt": "Pominąć to zadanie?",
|
||||
"reason_optional": "Powód (opcjonalny)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Zrób zdjęcie",
|
||||
"camera_capture_shoot": "Zrób zdjęcie",
|
||||
"camera_switch_lens": "Przełącz kamerę",
|
||||
"camera_switch_failed": "Żadna inna kamera nie odpowiedziała — ten telefon udostępnia tylko jedną. Dla drugiego obiektywu użyj wyboru pliku.",
|
||||
"doc_drop_hint": "Upuść pliki tutaj",
|
||||
"doc_task_none": "Brak dokumentów powiązanych z tym zadaniem.",
|
||||
"doc_link_existing": "Powiąż dokument…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktywny",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(nowy)",
|
||||
"adopt_object_hint": "Nadaj kilku czujnikom tę samą nazwę obiektu, a staną się jednym obiektem; wpisz nazwę istniejącego obiektu, aby je tam dodać.",
|
||||
"adopt_problem_adopt": "Przejmij zaznaczone",
|
||||
"adopt_problem_done": "Przejęto {tasks} czujnik(ów) problemów",
|
||||
"views_label": "Widoki",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Tarefa movida",
|
||||
"move_task_target": "Objeto de destino",
|
||||
"move_task_message": "Escolha o objeto ao qual esta tarefa deve pertencer. Histórico, leituras e estado do gatilho vão junto; ela recebe um novo número de referência e suas entidades são recriadas no novo objeto. Documentos vinculados permanecem no objeto atual.",
|
||||
"bulk_move_message": "Escolha o objeto ao qual as tarefas selecionadas devem pertencer. As que já estão lá são ignoradas; histórico, leituras e estado do gatilho vão junto.",
|
||||
"bulk_moved": "{n} tarefas movidas",
|
||||
"more_actions": "Mais ações",
|
||||
"move_task_title": "Mover tarefa",
|
||||
"move_task": "Mover para outro objeto…",
|
||||
"object_duplicated": "Objeto duplicado",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} selecionadas",
|
||||
"bulk_completed": "{n} tarefas concluídas",
|
||||
"bulk_archived": "{n} tarefas arquivadas",
|
||||
"bulk_delete_objects_confirm": "Excluir {n} objetos e todas as suas tarefas? Arquivar mantém o histórico.",
|
||||
"bulk_objects_deleted": "{n} objetos excluídos",
|
||||
"bulk_objects_archived": "{n} objetos arquivados",
|
||||
"completing": "Concluindo…",
|
||||
"interval": "Intervalo",
|
||||
"warning": "Aviso",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Dias da semana",
|
||||
"nth_weekday": "Enésimo dia da semana do mês",
|
||||
"day_of_month": "Dia do mês",
|
||||
"calendar": "Entidade de calendário",
|
||||
"calendar_entity_label": "Calendário",
|
||||
"calendar_entity_hint": "Vence uma vez por evento deste calendário, na data de início do evento — o próximo evento após a última conclusão.",
|
||||
"calendar_entity_required": "Escolha uma entidade de calendário.",
|
||||
"recurrence_on_days": "Repetir em",
|
||||
"recurrence_occurrence": "Ocorrência",
|
||||
"recurrence_weekday": "Dia da semana",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Um objeto não pode ser vinculado a si mesmo",
|
||||
"ws_err_too_early": "Cedo demais — esta tarefa só pode ser concluída mais perto do vencimento",
|
||||
"ws_err_invalid_search_template": "O link de busca deve ser uma URL http(s) contendo {q}",
|
||||
"ws_err_invalid_icon": "O ícone da notificação deve ser um nome mdi:, por ex. mdi:air-filter",
|
||||
"feat_schedule_time": "Agendamento por horário",
|
||||
"feat_schedule_time_desc": "As tarefas ficam atrasadas em um horário específico do dia, em vez de à meia-noite.",
|
||||
"schedule_time_toggle": "Vence em um horário específico",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Colunas da tabela de objetos",
|
||||
"objects_table_columns_hint": "Escolha quais colunas aparecem na visualização em tabela dos objetos.",
|
||||
"custom_icon_optional": "Ícone (opcional, ex.: mdi:wrench)",
|
||||
"notify_icon": "Ícone da notificação",
|
||||
"notify_icon_hint": "Exibido pelo app Companion no Android. Vazio = o ícone do tipo de manutenção desta tarefa ({default}).",
|
||||
"task_enabled": "Tarefa ativada",
|
||||
"skip_reason_prompt": "Pular esta tarefa?",
|
||||
"reason_optional": "Motivo (opcional)",
|
||||
@@ -784,6 +797,7 @@
|
||||
"doc_camera": "Tirar foto",
|
||||
"camera_capture_shoot": "Capturar",
|
||||
"camera_switch_lens": "Trocar de câmera",
|
||||
"camera_switch_failed": "Nenhuma outra câmera respondeu — este celular libera só uma. Use o seletor de arquivos para a outra lente.",
|
||||
"doc_drop_hint": "Solte os arquivos aqui",
|
||||
"doc_task_none": "Nenhum documento vinculado a esta tarefa.",
|
||||
"doc_link_existing": "Vincular um documento…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "ativo",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(novo)",
|
||||
"adopt_object_hint": "Dê a vários sensores o mesmo nome de objeto e eles viram um único objeto; digite o nome de um objeto existente para adicioná-los lá.",
|
||||
"adopt_problem_adopt": "Adotar selecionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adotado(s)",
|
||||
"views_label": "Visualizações",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Tarefa movida",
|
||||
"move_task_target": "Objeto de destino",
|
||||
"move_task_message": "Escolha o objeto a que esta tarefa deve pertencer. O histórico, as leituras e o estado do gatilho vão com ela; recebe um novo número de referência e as suas entidades são recriadas no novo objeto. Os documentos ligados ficam no objeto atual.",
|
||||
"bulk_move_message": "Escolha o objeto a que as tarefas selecionadas devem pertencer. As que já lá estão são ignoradas; histórico, leituras e estado do gatilho acompanham.",
|
||||
"bulk_moved": "{n} tarefas movidas",
|
||||
"more_actions": "Mais ações",
|
||||
"move_task_title": "Mover tarefa",
|
||||
"move_task": "Mover para outro objeto…",
|
||||
"object_duplicated": "Objeto duplicado",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} selecionados",
|
||||
"bulk_completed": "{n} tarefas concluídas",
|
||||
"bulk_archived": "{n} tarefas arquivadas",
|
||||
"bulk_delete_objects_confirm": "Eliminar {n} objetos e todas as suas tarefas? Arquivar mantém o histórico.",
|
||||
"bulk_objects_deleted": "{n} objetos eliminados",
|
||||
"bulk_objects_archived": "{n} objetos arquivados",
|
||||
"completing": "A concluir…",
|
||||
"interval": "Intervalo",
|
||||
"warning": "Aviso",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Dias da semana",
|
||||
"nth_weekday": "N-ésimo dia da semana do mês",
|
||||
"day_of_month": "Dia do mês",
|
||||
"calendar": "Entidade de calendário",
|
||||
"calendar_entity_label": "Calendário",
|
||||
"calendar_entity_hint": "Vence uma vez por evento deste calendário, na data de início do evento — o próximo evento após a última conclusão.",
|
||||
"calendar_entity_required": "Escolha uma entidade de calendário.",
|
||||
"recurrence_on_days": "Repetir em",
|
||||
"recurrence_occurrence": "Ocorrência",
|
||||
"recurrence_weekday": "Dia da semana",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Um objeto não pode ser ligado a si próprio",
|
||||
"ws_err_too_early": "Demasiado cedo — esta tarefa só pode ser concluída mais perto do prazo",
|
||||
"ws_err_invalid_search_template": "A ligação de pesquisa tem de ser um URL http(s) com {q}",
|
||||
"ws_err_invalid_icon": "O ícone da notificação tem de ser um nome mdi:, p. ex. mdi:air-filter",
|
||||
"feat_schedule_time": "Agendamento por hora",
|
||||
"feat_schedule_time_desc": "Tarefas vencem em um horário específico em vez de meia-noite.",
|
||||
"schedule_time_toggle": "Vence a uma hora específica",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Colunas da tabela de objetos",
|
||||
"objects_table_columns_hint": "Escolha que colunas aparecem na vista de tabela de objetos.",
|
||||
"custom_icon_optional": "Ícone (opcional, ex. mdi:wrench)",
|
||||
"notify_icon": "Ícone da notificação",
|
||||
"notify_icon_hint": "Mostrado pela app Companion no Android. Vazio = o ícone do tipo de manutenção desta tarefa ({default}).",
|
||||
"task_enabled": "Tarefa ativada",
|
||||
"skip_reason_prompt": "Saltar esta tarefa?",
|
||||
"reason_optional": "Motivo (opcional)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Tirar foto",
|
||||
"camera_capture_shoot": "Capturar",
|
||||
"camera_switch_lens": "Mudar de câmara",
|
||||
"camera_switch_failed": "Nenhuma outra câmara respondeu — este telemóvel só disponibiliza uma. Use o seletor de ficheiros para a outra objetiva.",
|
||||
"doc_drop_hint": "Solte os ficheiros aqui",
|
||||
"doc_task_none": "Nenhum documento associado a esta tarefa.",
|
||||
"doc_link_existing": "Associar um documento…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "ativo",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(novo)",
|
||||
"adopt_object_hint": "Dê a vários sensores o mesmo nome de objeto e tornam-se um só objeto; escreva o nome de um objeto existente para os juntar lá.",
|
||||
"adopt_problem_adopt": "Adotar selecionados",
|
||||
"adopt_problem_done": "{tasks} sensor(es) de problema adotado(s)",
|
||||
"views_label": "Vistas",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Задача перемещена",
|
||||
"move_task_target": "Целевой объект",
|
||||
"move_task_message": "Выберите объект, к которому должна относиться эта задача. История, показания и состояние триггера переедут вместе с ней; она получит новый номер, а её сущности будут созданы заново под новым объектом. Привязанные документы остаются у текущего объекта.",
|
||||
"bulk_move_message": "Выберите объект, к которому должны относиться выбранные задачи. Уже находящиеся там пропускаются; история, показания и состояние триггера переносятся.",
|
||||
"bulk_moved": "Перемещено задач: {n}",
|
||||
"more_actions": "Другие действия",
|
||||
"move_task_title": "Переместить задачу",
|
||||
"move_task": "Переместить в другой объект…",
|
||||
"object_duplicated": "Объект продублирован",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "Выбрано: {n}",
|
||||
"bulk_completed": "Выполнено задач: {n}",
|
||||
"bulk_archived": "Архивировано задач: {n}",
|
||||
"bulk_delete_objects_confirm": "Удалить {n} объектов со всеми их задачами? Архивация вместо этого сохранит историю.",
|
||||
"bulk_objects_deleted": "Удалено объектов: {n}",
|
||||
"bulk_objects_archived": "Архивировано объектов: {n}",
|
||||
"completing": "Выполнение…",
|
||||
"interval": "Интервал",
|
||||
"warning": "Предупреждение",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Дни недели",
|
||||
"nth_weekday": "N-й день недели месяца",
|
||||
"day_of_month": "День месяца",
|
||||
"calendar": "Сущность календаря",
|
||||
"calendar_entity_label": "Календарь",
|
||||
"calendar_entity_hint": "Срок наступает один раз на каждое событие этого календаря, в дату начала события — следующее событие после последнего выполнения.",
|
||||
"calendar_entity_required": "Выберите сущность календаря.",
|
||||
"recurrence_on_days": "Повторять в",
|
||||
"recurrence_occurrence": "Вхождение",
|
||||
"recurrence_weekday": "День недели",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Объект нельзя связать с самим собой",
|
||||
"ws_err_too_early": "Слишком рано — эту задачу можно завершить только ближе к сроку",
|
||||
"ws_err_invalid_search_template": "Ссылка для поиска должна быть URL http(s) с {q}",
|
||||
"ws_err_invalid_icon": "Значок уведомления должен быть именем mdi:, например mdi:air-filter",
|
||||
"feat_schedule_time": "Планирование по времени дня",
|
||||
"feat_schedule_time_desc": "Задачи становятся просроченными в определённое время дня, а не в полночь.",
|
||||
"schedule_time_toggle": "Срок в определённое время",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Столбцы таблицы объектов",
|
||||
"objects_table_columns_hint": "Выберите, какие столбцы показывать в табличном виде объектов.",
|
||||
"custom_icon_optional": "Иконка (опционально, например mdi:wrench)",
|
||||
"notify_icon": "Значок уведомления",
|
||||
"notify_icon_hint": "Показывается приложением Companion на Android. Пусто = значок типа обслуживания этой задачи ({default}).",
|
||||
"task_enabled": "Задача включена",
|
||||
"skip_reason_prompt": "Пропустить эту задачу?",
|
||||
"reason_optional": "Причина (опционально)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Сделать фото",
|
||||
"camera_capture_shoot": "Снять",
|
||||
"camera_switch_lens": "Сменить камеру",
|
||||
"camera_switch_failed": "Другая камера не ответила — этот телефон отдаёт только одну. Для другого объектива используйте выбор файла.",
|
||||
"doc_drop_hint": "Перетащите файлы сюда",
|
||||
"doc_task_none": "Нет документов, связанных с этой задачей.",
|
||||
"doc_link_existing": "Связать документ…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "активна",
|
||||
"adopt_problem_ok": "норма",
|
||||
"adopt_problem_new_object": "(новый)",
|
||||
"adopt_object_hint": "Дайте нескольким датчикам одно имя объекта — они станут одним объектом; введите имя существующего объекта, чтобы добавить их туда.",
|
||||
"adopt_problem_adopt": "Принять выбранные",
|
||||
"adopt_problem_done": "Принято сенсоров проблем: {tasks}",
|
||||
"views_label": "Представления",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Uppgift flyttad",
|
||||
"move_task_target": "Målobjekt",
|
||||
"move_task_message": "Välj vilket objekt uppgiften ska tillhöra. Historik, avläsningar och utlösarstatus följer med; den får ett nytt referensnummer och dess entiteter skapas om under det nya objektet. Länkade dokument stannar hos det nuvarande objektet.",
|
||||
"bulk_move_message": "Välj det objekt som de markerade uppgifterna ska tillhöra. Uppgifter som redan finns där hoppas över; historik, avläsningar och utlösarstatus följer med.",
|
||||
"bulk_moved": "{n} uppgifter flyttade",
|
||||
"more_actions": "Fler åtgärder",
|
||||
"move_task_title": "Flytta uppgift",
|
||||
"move_task": "Flytta till ett annat objekt…",
|
||||
"object_duplicated": "Objekt duplicerat",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "{n} valda",
|
||||
"bulk_completed": "{n} uppgifter slutförda",
|
||||
"bulk_archived": "{n} uppgifter arkiverade",
|
||||
"bulk_delete_objects_confirm": "Ta bort {n} objekt och alla deras uppgifter? Arkivering behåller historiken i stället.",
|
||||
"bulk_objects_deleted": "{n} objekt borttagna",
|
||||
"bulk_objects_archived": "{n} objekt arkiverade",
|
||||
"completing": "Slutför…",
|
||||
"interval": "Intervall",
|
||||
"warning": "Varning",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Veckodagar",
|
||||
"nth_weekday": "N:te veckodag i månaden",
|
||||
"day_of_month": "Dag i månaden",
|
||||
"calendar": "Kalenderentitet",
|
||||
"calendar_entity_label": "Kalender",
|
||||
"calendar_entity_hint": "Förfaller en gång per händelse i den här kalendern, på händelsens startdatum — nästa händelse efter det senaste utförandet.",
|
||||
"calendar_entity_required": "Välj en kalenderentitet.",
|
||||
"recurrence_on_days": "Upprepa på",
|
||||
"recurrence_occurrence": "Förekomst",
|
||||
"recurrence_weekday": "Veckodag",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Ett objekt kan inte länkas till sig självt",
|
||||
"ws_err_too_early": "För tidigt — uppgiften kan bara slutföras närmare förfallodatumet",
|
||||
"ws_err_invalid_search_template": "Söklänken måste vara en http(s)-URL som innehåller {q}",
|
||||
"ws_err_invalid_icon": "Aviseringsikonen måste vara ett mdi:-namn, t.ex. mdi:air-filter",
|
||||
"feat_schedule_time": "Schemaläggning per tid på dygnet",
|
||||
"feat_schedule_time_desc": "Uppgifter blir försenade vid en specifik tid på dygnet istället för midnatt.",
|
||||
"schedule_time_toggle": "Förfaller vid en viss tid",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Kolumner i objekttabell",
|
||||
"objects_table_columns_hint": "Välj vilka kolumner som visas i objekttabellvyn.",
|
||||
"custom_icon_optional": "Ikon (valfritt, t.ex. mdi:wrench)",
|
||||
"notify_icon": "Aviseringsikon",
|
||||
"notify_icon_hint": "Visas av Companion-appen på Android. Tomt = ikonen för uppgiftens underhållstyp ({default}).",
|
||||
"task_enabled": "Uppgift aktiverad",
|
||||
"skip_reason_prompt": "Hoppa över denna uppgift?",
|
||||
"reason_optional": "Anledning (valfritt)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Ta foto",
|
||||
"camera_capture_shoot": "Ta bild",
|
||||
"camera_switch_lens": "Byt kamera",
|
||||
"camera_switch_failed": "Ingen annan kamera svarade – den här telefonen lämnar bara ut en. Använd filväljaren för det andra objektivet.",
|
||||
"doc_drop_hint": "Släpp filer här",
|
||||
"doc_task_none": "Inga dokument kopplade till denna uppgift.",
|
||||
"doc_link_existing": "Koppla ett dokument…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "aktiv",
|
||||
"adopt_problem_ok": "ok",
|
||||
"adopt_problem_new_object": "(ny)",
|
||||
"adopt_object_hint": "Ge flera sensorer samma objektnamn så blir de ett objekt; skriv ett befintligt objekts namn för att lägga dem där.",
|
||||
"adopt_problem_adopt": "Anta valda",
|
||||
"adopt_problem_done": "Antog {tasks} problemsensor(er)",
|
||||
"views_label": "Vyer",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "Görev taşındı",
|
||||
"move_task_target": "Hedef nesne",
|
||||
"move_task_message": "Bu görevin ait olacağı nesneyi seçin. Geçmiş, okumalar ve tetikleyici durumu birlikte taşınır; yeni bir referans numarası alır ve varlıkları yeni nesne altında yeniden oluşturulur. Bağlı belgeler mevcut nesnede kalır.",
|
||||
"bulk_move_message": "Seçili görevlerin ait olacağı nesneyi seçin. Zaten orada olanlar atlanır; geçmiş, okumalar ve tetikleyici durumu birlikte taşınır.",
|
||||
"bulk_moved": "{n} görev taşındı",
|
||||
"more_actions": "Diğer işlemler",
|
||||
"move_task_title": "Görevi taşı",
|
||||
"move_task": "Başka bir nesneye taşı…",
|
||||
"object_duplicated": "Nesne çoğaltıldı",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "{n} seçildi",
|
||||
"bulk_completed": "{n} görev tamamlandı",
|
||||
"bulk_archived": "{n} görev arşivlendi",
|
||||
"bulk_delete_objects_confirm": "{n} nesne ve tüm görevleri silinsin mi? Arşivlemek geçmişi korur.",
|
||||
"bulk_objects_deleted": "{n} nesne silindi",
|
||||
"bulk_objects_archived": "{n} nesne arşivlendi",
|
||||
"completing": "Tamamlanıyor…",
|
||||
"interval": "Aralık",
|
||||
"warning": "Uyarı",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "Haftanın günleri",
|
||||
"nth_weekday": "Ayın n. hafta günü",
|
||||
"day_of_month": "Ayın günü",
|
||||
"calendar": "Takvim varlığı",
|
||||
"calendar_entity_label": "Takvim",
|
||||
"calendar_entity_hint": "Bu takvimin her etkinliği için bir kez, etkinliğin başlangıç tarihinde vadesi gelir — son tamamlamadan sonraki bir sonraki etkinlik.",
|
||||
"calendar_entity_required": "Bir takvim varlığı seçin.",
|
||||
"recurrence_on_days": "Tekrar günleri",
|
||||
"recurrence_occurrence": "Kaçıncı",
|
||||
"recurrence_weekday": "Haftanın günü",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "Bir nesne kendisine bağlanamaz",
|
||||
"ws_err_too_early": "Çok erken — bu görev ancak son tarihine yaklaşınca tamamlanabilir",
|
||||
"ws_err_invalid_search_template": "Arama bağlantısı {q} içeren bir http(s) URL olmalıdır",
|
||||
"ws_err_invalid_icon": "Bildirim simgesi bir mdi: adı olmalıdır, örn. mdi:air-filter",
|
||||
"feat_schedule_time": "Gün içi saat zamanlaması",
|
||||
"feat_schedule_time_desc": "Görevler gece yarısı yerine günün belirli bir saatinde gecikmiş olur.",
|
||||
"schedule_time_toggle": "Belirli bir saatte vadesi dolar",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "Nesne tablosu sütunları",
|
||||
"objects_table_columns_hint": "Nesne tablosu görünümünde hangi sütunların görüneceğini seçin.",
|
||||
"custom_icon_optional": "Simge (isteğe bağlı, örn. mdi:wrench)",
|
||||
"notify_icon": "Bildirim simgesi",
|
||||
"notify_icon_hint": "Android'de Companion uygulamasında gösterilir. Boş = bu görevin bakım türünün simgesi ({default}).",
|
||||
"task_enabled": "Görev etkin",
|
||||
"skip_reason_prompt": "Bu görev atlansın mı?",
|
||||
"reason_optional": "Neden (isteğe bağlı)",
|
||||
@@ -784,6 +797,7 @@
|
||||
"doc_camera": "Fotoğraf çek",
|
||||
"camera_capture_shoot": "Çek",
|
||||
"camera_switch_lens": "Kamerayı değiştir",
|
||||
"camera_switch_failed": "Başka bir kamera yanıt vermedi — bu telefon yalnızca birini açıyor. Diğer lens için dosya seçiciyi kullanın.",
|
||||
"doc_drop_hint": "Dosyaları buraya bırakın",
|
||||
"doc_task_none": "Bu göreve bağlı belge yok.",
|
||||
"doc_link_existing": "Belge bağla…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "etkin",
|
||||
"adopt_problem_ok": "tamam",
|
||||
"adopt_problem_new_object": "(yeni)",
|
||||
"adopt_object_hint": "Birden çok sensöre aynı nesne adını verin, tek nesne olurlar; mevcut bir nesnenin adını yazarsanız oraya eklenirler.",
|
||||
"adopt_problem_adopt": "Seçilenleri devral",
|
||||
"adopt_problem_done": "{tasks} sorun sensörü devralındı",
|
||||
"views_label": "Görünümler",
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
"task_moved": "Завдання переміщено",
|
||||
"move_task_target": "Цільовий об'єкт",
|
||||
"move_task_message": "Виберіть об'єкт, до якого має належати це завдання. Історія, показники та стан тригера переїдуть разом із ним; воно отримає новий номер, а його сутності буде створено заново під новим об'єктом. Прив'язані документи залишаться в поточному об'єкті.",
|
||||
"bulk_move_message": "Виберіть об'єкт, до якого мають належати вибрані завдання. Ті, що вже там, пропускаються; історія, показники та стан тригера переносяться.",
|
||||
"bulk_moved": "Переміщено завдань: {n}",
|
||||
"more_actions": "Інші дії",
|
||||
"move_task_title": "Перемістити завдання",
|
||||
"move_task": "Перемістити до іншого об'єкта…",
|
||||
"object_duplicated": "Об'єкт продубльовано",
|
||||
@@ -38,6 +41,9 @@
|
||||
"bulk_n_selected": "Вибрано: {n}",
|
||||
"bulk_completed": "Виконано завдань: {n}",
|
||||
"bulk_archived": "Архівовано завдань: {n}",
|
||||
"bulk_delete_objects_confirm": "Видалити {n} об'єктів з усіма їхніми завданнями? Архівування натомість збереже історію.",
|
||||
"bulk_objects_deleted": "Видалено об'єктів: {n}",
|
||||
"bulk_objects_archived": "Архівовано об'єктів: {n}",
|
||||
"completing": "Виконується…",
|
||||
"interval": "Інтервал",
|
||||
"warning": "Попередження",
|
||||
@@ -64,6 +70,10 @@
|
||||
"weekdays": "Дні тижня",
|
||||
"nth_weekday": "N-й день тижня в місяці",
|
||||
"day_of_month": "День місяця",
|
||||
"calendar": "Сутність календаря",
|
||||
"calendar_entity_label": "Календар",
|
||||
"calendar_entity_hint": "Термін настає один раз на кожну подію цього календаря, у дату початку події — наступна подія після останнього виконання.",
|
||||
"calendar_entity_required": "Виберіть сутність календаря.",
|
||||
"recurrence_on_days": "Повторювати у",
|
||||
"recurrence_occurrence": "Входження",
|
||||
"recurrence_weekday": "День тижня",
|
||||
@@ -165,6 +175,7 @@
|
||||
"ws_err_self_link_device": "Об'єкт не можна пов'язати із самим собою",
|
||||
"ws_err_too_early": "Зарано — це завдання можна завершити лише ближче до терміну",
|
||||
"ws_err_invalid_search_template": "Посилання для пошуку має бути URL http(s) із {q}",
|
||||
"ws_err_invalid_icon": "Значок сповіщення має бути іменем mdi:, наприклад mdi:air-filter",
|
||||
"feat_schedule_time": "Планування за часом доби",
|
||||
"feat_schedule_time_desc": "Задачі стають простроченими у певний час доби, а не опівночі.",
|
||||
"schedule_time_toggle": "Термін у визначений час",
|
||||
@@ -454,6 +465,8 @@
|
||||
"objects_table_columns_label": "Стовпці таблиці об'єктів",
|
||||
"objects_table_columns_hint": "Виберіть, які стовпці показувати в табличному вигляді об'єктів.",
|
||||
"custom_icon_optional": "Іконка (необов'язково, наприклад mdi:wrench)",
|
||||
"notify_icon": "Значок сповіщення",
|
||||
"notify_icon_hint": "Показується застосунком Companion на Android. Порожньо = значок типу обслуговування цього завдання ({default}).",
|
||||
"task_enabled": "Завдання увімкнено",
|
||||
"skip_reason_prompt": "Пропустити це завдання?",
|
||||
"reason_optional": "Причина (необов'язково)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "Зробити фото",
|
||||
"camera_capture_shoot": "Зняти",
|
||||
"camera_switch_lens": "Змінити камеру",
|
||||
"camera_switch_failed": "Інша камера не відповіла — цей телефон надає лише одну. Для іншого об'єктива скористайтеся вибором файлу.",
|
||||
"doc_drop_hint": "Перетягніть файли сюди",
|
||||
"doc_task_none": "Немає документів, пов'язаних із цим завданням.",
|
||||
"doc_link_existing": "Пов'язати документ…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "активна",
|
||||
"adopt_problem_ok": "норма",
|
||||
"adopt_problem_new_object": "(новий)",
|
||||
"adopt_object_hint": "Дайте кільком сенсорам однакову назву об'єкта — вони стануть одним об'єктом; введіть назву наявного об'єкта, щоб додати їх туди.",
|
||||
"adopt_problem_adopt": "Прийняти вибрані",
|
||||
"adopt_problem_done": "Прийнято сенсорів проблем: {tasks}",
|
||||
"views_label": "Подання",
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
"task_moved": "任务已移动",
|
||||
"move_task_target": "目标对象",
|
||||
"move_task_message": "选择此任务应归属的对象。历史记录、读数和触发器状态会一并迁移;任务将获得新的编号,其实体会在新对象下重新创建。关联的文档仍留在当前对象。",
|
||||
"bulk_move_message": "选择所选任务应归属的对象。已在该对象下的任务将被跳过;历史记录、读数和触发状态会一并迁移。",
|
||||
"bulk_moved": "已移动 {n} 个任务",
|
||||
"more_actions": "更多操作",
|
||||
"move_task_title": "移动任务",
|
||||
"move_task": "移动到其他对象…",
|
||||
"object_duplicated": "对象已复制",
|
||||
@@ -40,6 +43,9 @@
|
||||
"bulk_n_selected": "已选 {n} 项",
|
||||
"bulk_completed": "已完成 {n} 个任务",
|
||||
"bulk_archived": "已归档 {n} 个任务",
|
||||
"bulk_delete_objects_confirm": "删除 {n} 个对象及其全部任务?归档则会保留其历史记录。",
|
||||
"bulk_objects_deleted": "已删除 {n} 个对象",
|
||||
"bulk_objects_archived": "已归档 {n} 个对象",
|
||||
"completing": "正在完成…",
|
||||
"interval": "间隔",
|
||||
"warning": "预警",
|
||||
@@ -66,6 +72,10 @@
|
||||
"weekdays": "工作日",
|
||||
"nth_weekday": "每月第 N 个工作日",
|
||||
"day_of_month": "每月某天",
|
||||
"calendar": "日历实体",
|
||||
"calendar_entity_label": "日历",
|
||||
"calendar_entity_hint": "此日历的每个事件到期一次,以事件开始日期为准——即上次完成后的下一个事件。",
|
||||
"calendar_entity_required": "请选择一个日历实体。",
|
||||
"recurrence_on_days": "重复日期",
|
||||
"recurrence_occurrence": "发生次数",
|
||||
"recurrence_weekday": "星期",
|
||||
@@ -167,6 +177,7 @@
|
||||
"ws_err_self_link_device": "对象不能链接到自身",
|
||||
"ws_err_too_early": "为时过早 — 此任务只能在临近到期日时完成",
|
||||
"ws_err_invalid_search_template": "搜索链接必须是包含 {q} 的 http(s) 网址",
|
||||
"ws_err_invalid_icon": "通知图标必须是 mdi: 名称,例如 mdi:air-filter",
|
||||
"feat_schedule_time": "具体时间调度",
|
||||
"feat_schedule_time_desc": "任务将在特定时间点变为逾期,而非默认的午夜。",
|
||||
"schedule_time_toggle": "在特定时间到期",
|
||||
@@ -456,6 +467,8 @@
|
||||
"objects_table_columns_label": "对象表格列",
|
||||
"objects_table_columns_hint": "选择对象表格视图中显示的列。",
|
||||
"custom_icon_optional": "图标 (可选,例如 mdi:wrench)",
|
||||
"notify_icon": "通知图标",
|
||||
"notify_icon_hint": "由 Android 上的 Companion 应用显示。留空 = 此任务维护类型的图标({default})。",
|
||||
"task_enabled": "任务已启用",
|
||||
"skip_reason_prompt": "跳过此任务?",
|
||||
"reason_optional": "原因 (可选)",
|
||||
@@ -778,6 +791,7 @@
|
||||
"doc_camera": "拍照",
|
||||
"camera_capture_shoot": "拍摄",
|
||||
"camera_switch_lens": "切换摄像头",
|
||||
"camera_switch_failed": "没有其他摄像头响应——这部手机只开放一个。另一个镜头请使用文件选择器。",
|
||||
"doc_drop_hint": "将文件拖放到此处",
|
||||
"doc_task_none": "没有与此任务关联的文档。",
|
||||
"doc_link_existing": "关联文档…",
|
||||
@@ -886,6 +900,7 @@
|
||||
"adopt_problem_active": "存在",
|
||||
"adopt_problem_ok": "正常",
|
||||
"adopt_problem_new_object": "(新建)",
|
||||
"adopt_object_hint": "给多个传感器相同的对象名称,它们就会合并为一个对象;输入已有对象的名称即可加入该对象。",
|
||||
"adopt_problem_adopt": "采用所选",
|
||||
"adopt_problem_done": "已采用 {tasks} 个问题传感器",
|
||||
"views_label": "视图",
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+271
@@ -0,0 +1,271 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{e as f}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-73EHFI76.js";import{a as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WQXORDNI.js";import{a,b as g,c as i,f as c,h as u,l as v,m as n,q as s,s as m,u as b}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";var r=class extends u{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._adopting=!1;this._error="";this._sensors=[];this._selected=new Set;this._objectNames={};this._objects=[];this._users=[];this._responsible="";this._forMinutes="0";this._localeReady=!1;this._userService=null;this._toggle=e=>{let o=new Set(this._selected);o.has(e)?o.delete(e):o.add(e),this._selected=o};this._toggleAll=()=>{this._selected.size===this._sensors.length?this._selected=new Set:this._selected=new Set(this._sensors.map(e=>e.entity_id))};this._adopt=async()=>{if(!(this._selected.size===0||this._adopting)){this._adopting=!0,this._error="";try{let e=this._sensors.filter(t=>this._selected.has(t.entity_id)).map(t=>({entity_id:t.entity_id,name:t.name,entry_id:this._existingEntryFor(t)??void 0,object_name:this._effectiveName(t),device_id:t.device_id??void 0,part_id:t.suggested_part_id??void 0,responsible_user_id:this._responsible||void 0,for_minutes:parseInt(this._forMinutes,10)>0?parseInt(this._forMinutes,10):void 0})),o=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/problem_sensors/adopt",selections:e});this.dispatchEvent(new CustomEvent("problem-sensors-adopted",{bubbles:!0,composed:!0,detail:o})),this._open=!1}catch(e){this._error=p(e,this._lang)}finally{this._adopting=!1}}}}get _lang(){return m(this.hass)}updated(e){e.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,b(this._lang).then(()=>this.requestUpdate()))}async open(){this._open=!0,this._loading=!0,this._error="",this._sensors=[],this._selected=new Set,this._objectNames={},this._responsible="",this._forMinutes="0";try{this._userService?this._userService.updateHass(this.hass):this._userService=new f(this.hass);let[e,o,t]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/problem_sensors/discover"}),this._userService.getUsers().catch(()=>[]),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}).catch(()=>({objects:[]}))]);this._objects=(t.objects||[]).filter(l=>!l.object.archived_at).map(l=>({entry_id:l.entry_id,name:l.object.name})),this._sensors=e.sensors||[],this._selected=new Set(this._sensors.map(l=>l.entity_id)),this._users=o}catch(e){this._error=p(e,this._lang)}finally{this._loading=!1}}_effectiveName(e){return(this._objectNames[e.entity_id]??"").trim()||e.suggested_object_name}_existingEntryFor(e){let o=this._effectiveName(e);if(o===e.suggested_object_name&&e.suggested_entry_id)return e.suggested_entry_id;let t=this._objects.find(l=>l.name.trim().toLowerCase()===o.toLowerCase());return t?t.entry_id:null}_close(){this._open=!1}render(){if(!this._open)return i``;let e=this._lang,o=this._sensors.length>0&&this._selected.size===this._sensors.length;return i`
|
||||
<div class="overlay" @click=${this._close}>
|
||||
<div class="card" @click=${t=>t.stopPropagation()}>
|
||||
<div class="title">${s("adopt_problem_title",e)}</div>
|
||||
<div class="hint">${s("adopt_problem_hint",e)}</div>
|
||||
${this._error?i`<div class="error">${this._error}</div>`:c}
|
||||
|
||||
${this._loading?i`<div class="loading">…</div>`:this._sensors.length===0?i`<div class="empty">${s("adopt_problem_none",e)}</div>`:i`
|
||||
<label class="select-all">
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${o}
|
||||
@change=${this._toggleAll}
|
||||
/>
|
||||
<span>${s("selected",e)}: ${this._selected.size} / ${this._sensors.length}</span>
|
||||
</label>
|
||||
<div class="row-sub adopt-object-hint">${s("adopt_object_hint",e)}</div>
|
||||
<datalist id="adopt-object-names">
|
||||
${this._objects.map(t=>i`<option value=${t.name}></option>`)}
|
||||
</datalist>
|
||||
<div class="list">
|
||||
${this._sensors.map(t=>{let l=this._selected.has(t.entity_id),_=t.state==="on",h=[t.device_name,t.area_name].filter(Boolean).join(" \xB7 ");return i`
|
||||
<label class="row">
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${l}
|
||||
@change=${()=>this._toggle(t.entity_id)}
|
||||
/>
|
||||
<div class="row-main">
|
||||
<div class="row-top">
|
||||
<span class="row-name">${t.name}</span>
|
||||
<span class="chip ${_?"chip-active":"chip-ok"}">
|
||||
${_?s("adopt_problem_active",e):s("adopt_problem_ok",e)}
|
||||
</span>
|
||||
</div>
|
||||
${h?i`<div class="row-sub">${h}</div>`:c}
|
||||
${l?i`<div class="row-object" @click=${d=>d.stopPropagation()}>
|
||||
<input
|
||||
class="adopt-object"
|
||||
list="adopt-object-names"
|
||||
aria-label=${s("object",e)}
|
||||
placeholder=${t.suggested_object_name}
|
||||
.value=${this._objectNames[t.entity_id]??t.suggested_object_name}
|
||||
@input=${d=>{this._objectNames={...this._objectNames,[t.entity_id]:d.target.value}}}
|
||||
/>
|
||||
</div>`:c}
|
||||
<div class="row-target">
|
||||
→ ${this._effectiveName(t)}${this._existingEntryFor(t)?c:i` <span class="new-tag">${s("adopt_problem_new_object",e)}</span>`}
|
||||
</div>
|
||||
${t.suggested_part_name?i`<div class="row-part">
|
||||
<ha-icon icon="mdi:package-variant-closed"></ha-icon>
|
||||
${s("adopt_problem_part",e).replace("{name}",t.suggested_part_name)}
|
||||
</div>`:c}
|
||||
</div>
|
||||
</label>
|
||||
`})}
|
||||
</div>
|
||||
`}
|
||||
|
||||
${!this._loading&&this._sensors.length>0?i`
|
||||
<label class="responsible">
|
||||
<span>${s("for_at_least_minutes",e)}</span>
|
||||
<input
|
||||
class="for-input"
|
||||
type="number"
|
||||
min="0"
|
||||
max="1440"
|
||||
.value=${this._forMinutes}
|
||||
@input=${t=>this._forMinutes=t.target.value}
|
||||
/>
|
||||
</label>
|
||||
<div class="for-hint">${s("adopt_for_minutes_hint",e)}</div>
|
||||
`:c}
|
||||
|
||||
${!this._loading&&this._sensors.length>0&&this._users.length>0?i`
|
||||
<label class="responsible">
|
||||
<span>${s("adopt_problem_responsible",e)}</span>
|
||||
<select
|
||||
.value=${this._responsible}
|
||||
@change=${t=>{this._responsible=t.target.value}}
|
||||
>
|
||||
<option value="" ?selected=${!this._responsible}>${s("no_user_assigned",e)}</option>
|
||||
${this._users.map(t=>i`<option value=${t.id} ?selected=${t.id===this._responsible}>${t.name}</option>`)}
|
||||
</select>
|
||||
</label>
|
||||
`:c}
|
||||
|
||||
<div class="actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${s("cancel",e)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._adopt}
|
||||
.disabled=${this._selected.size===0||this._adopting}
|
||||
>
|
||||
${s("adopt_problem_adopt",e)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`}};r.styles=g`
|
||||
.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
min-width: min(360px, calc(100vw - 24px));
|
||||
max-width: 560px;
|
||||
width: 90vw;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.hint {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 13px;
|
||||
}
|
||||
.error {
|
||||
color: var(--error-color, #f44336);
|
||||
font-size: 13px;
|
||||
}
|
||||
.loading,
|
||||
.empty {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 14px;
|
||||
padding: 12px 0;
|
||||
}
|
||||
.select-all {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
.select-all input {
|
||||
cursor: pointer;
|
||||
}
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
overflow-y: auto;
|
||||
max-height: 50vh;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.row input {
|
||||
margin-top: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.row-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
.row-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.row-name {
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
}
|
||||
.row-sub {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
}
|
||||
.row-object { margin-top: 6px; }
|
||||
.row-object input {
|
||||
width: 100%; box-sizing: border-box; padding: 6px 8px; font: inherit;
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
background: var(--card-background-color); color: var(--primary-text-color);
|
||||
}
|
||||
.adopt-object-hint { margin: 0 0 8px; }
|
||||
.row-target {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
}
|
||||
.row-part {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.row-part ha-icon {
|
||||
--mdc-icon-size: 14px;
|
||||
}
|
||||
.new-tag {
|
||||
font-style: italic;
|
||||
}
|
||||
.chip {
|
||||
font-size: 11px;
|
||||
padding: 1px 8px;
|
||||
border-radius: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.chip-active {
|
||||
background: var(--error-color, #f44336);
|
||||
color: #fff;
|
||||
}
|
||||
.chip-ok {
|
||||
background: var(--divider-color);
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.responsible {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.for-input {
|
||||
width: 70px;
|
||||
background: var(--card-background-color);
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 4px;
|
||||
padding: 4px 6px;
|
||||
}
|
||||
.for-hint {
|
||||
font-size: 11px;
|
||||
color: var(--secondary-text-color);
|
||||
margin: -4px 0 2px;
|
||||
}
|
||||
.responsible select {
|
||||
flex: 1;
|
||||
min-width: 140px;
|
||||
padding: 4px 6px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--divider-color);
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
font-size: 13px;
|
||||
}
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
`,a([v({attribute:!1})],r.prototype,"hass",2),a([n()],r.prototype,"_open",2),a([n()],r.prototype,"_loading",2),a([n()],r.prototype,"_adopting",2),a([n()],r.prototype,"_error",2),a([n()],r.prototype,"_sensors",2),a([n()],r.prototype,"_selected",2),a([n()],r.prototype,"_objectNames",2),a([n()],r.prototype,"_objects",2),a([n()],r.prototype,"_users",2),a([n()],r.prototype,"_responsible",2),a([n()],r.prototype,"_forMinutes",2);customElements.get("maintenance-adopt-problem-sensors-dialog")||customElements.define("maintenance-adopt-problem-sensors-dialog",r);export{r as MaintenanceAdoptProblemSensorsDialog};
|
||||
@@ -0,0 +1,153 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WQXORDNI.js";import{a as r,b as _,c as l,f as o,h,l as d,m as s,q as i,s as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";var a=class extends h{constructor(){super(...arguments);this.objects=[];this._open=!1;this._loading=!1;this._error="";this._name="";this._manufacturer="";this._model="";this._serialNumber="";this._areaId="";this._installationDate="";this._warrantyExpiry="";this._documentationUrl="";this._notes="";this._haDeviceId="";this._parentEntryId="";this._entryId=null}get _lang(){return p(this.hass)}openCreate(){this._entryId=null,this._name="",this._manufacturer="",this._model="",this._serialNumber="",this._areaId="",this._installationDate="",this._warrantyExpiry="",this._documentationUrl="",this._notes="",this._haDeviceId="",this._parentEntryId="",this._error="",this._open=!0}openEdit(e,n){this._entryId=e,this._name=n.name||"",this._manufacturer=n.manufacturer||"",this._model=n.model||"",this._serialNumber=n.serial_number||"",this._areaId=n.area_id||"",this._installationDate=n.installation_date||"",this._warrantyExpiry=n.warranty_expiry||"",this._documentationUrl=n.documentation_url||"",this._notes=n.notes||"",this._haDeviceId=n.ha_device_id||"",this._parentEntryId=n.parent_entry_id||"",this._error="",this._open=!0}async _save(){if(!this._loading&&this._name.trim()){this._loading=!0,this._error="";try{this._entryId?await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/update",entry_id:this._entryId,name:this._name,manufacturer:this._manufacturer||null,model:this._model||null,serial_number:this._serialNumber||null,area_id:this._areaId||null,installation_date:this._installationDate||null,warranty_expiry:this._warrantyExpiry||null,documentation_url:this._documentationUrl.trim()||null,notes:this._notes.trim()||null,ha_device_id:this._haDeviceId||null,parent_entry_id:this._parentEntryId||null}):await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/create",name:this._name,manufacturer:this._manufacturer||null,model:this._model||null,serial_number:this._serialNumber||null,area_id:this._areaId||null,installation_date:this._installationDate||null,warranty_expiry:this._warrantyExpiry||null,documentation_url:this._documentationUrl.trim()||null,notes:this._notes.trim()||null,ha_device_id:this._haDeviceId||null,parent_entry_id:this._parentEntryId||null}),this._open=!1,this.dispatchEvent(new CustomEvent("object-saved"))}catch(e){this._error=u(e,this._lang,i("save_error",this._lang))}finally{this._loading=!1}}}_parentChoices(){return(this.objects||[]).filter(e=>e.entry_id!==this._entryId)}_close(){this._open=!1}render(){if(!this._open)return l``;let e=this._lang,n=this._entryId?i("edit_object",e):i("new_object",e);return l`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${n}</div>
|
||||
<div class="content">
|
||||
${this._error?l`<div class="error">${this._error}</div>`:o}
|
||||
<ms-textfield
|
||||
label="${i("name",e)}"
|
||||
required
|
||||
.value=${this._name}
|
||||
@input=${t=>this._name=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("manufacturer_optional",e)}"
|
||||
.value=${this._manufacturer}
|
||||
@input=${t=>this._manufacturer=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("model_optional",e)}"
|
||||
.value=${this._model}
|
||||
@input=${t=>this._model=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("serial_number_optional",e)}"
|
||||
.value=${this._serialNumber}
|
||||
@input=${t=>this._serialNumber=t.target.value}
|
||||
></ms-textfield>
|
||||
<ms-textfield
|
||||
label="${i("documentation_url_optional",e)}"
|
||||
type="url"
|
||||
.value=${this._documentationUrl}
|
||||
@input=${t=>this._documentationUrl=t.target.value}
|
||||
></ms-textfield>
|
||||
<ha-area-picker
|
||||
.hass=${this.hass}
|
||||
label="${i("area_id_optional",e)}"
|
||||
.value=${this._areaId}
|
||||
@value-changed=${t=>this._areaId=t.detail.value||""}
|
||||
></ha-area-picker>
|
||||
<ms-date-field
|
||||
kind="date"
|
||||
clearable
|
||||
.hass=${this.hass}
|
||||
.lang=${e}
|
||||
label="${i("installation_date_optional",e)}"
|
||||
.value=${this._installationDate}
|
||||
@value-changed=${t=>this._installationDate=t.detail.value}
|
||||
></ms-date-field>
|
||||
<ms-date-field
|
||||
kind="date"
|
||||
clearable
|
||||
.hass=${this.hass}
|
||||
.lang=${e}
|
||||
label="${i("warranty_expiry_optional",e)}"
|
||||
.value=${this._warrantyExpiry}
|
||||
@value-changed=${t=>this._warrantyExpiry=t.detail.value}
|
||||
></ms-date-field>
|
||||
<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${{device:this._haDeviceId||void 0}}
|
||||
.schema=${[{name:"device",selector:{device:{}}}]}
|
||||
.computeLabel=${()=>i("link_device_optional",e)}
|
||||
@value-changed=${t=>this._haDeviceId=t.detail.value?.device||""}
|
||||
></ha-form>
|
||||
${this._parentChoices().length?l`<label class="textarea-field">
|
||||
<span class="textarea-label">${i("parent_object_optional",e)}</span>
|
||||
<select
|
||||
class="parent-select"
|
||||
.value=${this._parentEntryId}
|
||||
@change=${t=>this._parentEntryId=t.target.value}
|
||||
>
|
||||
<option value="" ?selected=${!this._parentEntryId}>
|
||||
${i("parent_none",e)}
|
||||
</option>
|
||||
${this._parentChoices().map(t=>l`<option
|
||||
value=${t.entry_id}
|
||||
?selected=${this._parentEntryId===t.entry_id}
|
||||
>${t.object.name}</option>`)}
|
||||
</select>
|
||||
</label>`:o}
|
||||
<label class="textarea-field">
|
||||
<span class="textarea-label">${i("object_notes_optional",e)}</span>
|
||||
<textarea
|
||||
rows="3"
|
||||
.value=${this._notes}
|
||||
@input=${t=>this._notes=t.target.value}
|
||||
></textarea>
|
||||
<span class="md-hint">${i("notes_markdown_hint",e)}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${i("cancel",this._lang)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._save}
|
||||
.disabled=${this._loading||!this._name.trim()}
|
||||
>
|
||||
${this._loading?i("saving",this._lang):i("save",this._lang)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`}};a.styles=_`
|
||||
.dialog-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
min-width: 300px;
|
||||
}
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
ms-textfield {
|
||||
display: block;
|
||||
}
|
||||
.textarea-field {
|
||||
display: flex; flex-direction: column; gap: 4px;
|
||||
}
|
||||
.textarea-label {
|
||||
font-size: 12px; color: var(--secondary-text-color, #888); font-weight: 500;
|
||||
}
|
||||
.textarea-field textarea {
|
||||
padding: 8px 10px; font-size: 14px; font-family: inherit;
|
||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
resize: vertical;
|
||||
}
|
||||
.textarea-field textarea:focus {
|
||||
outline: none; border-color: var(--primary-color);
|
||||
}
|
||||
.md-hint {
|
||||
font-size: 11px; color: var(--secondary-text-color); font-style: italic;
|
||||
}
|
||||
.parent-select {
|
||||
padding: 8px 10px; font-size: 14px; font-family: inherit;
|
||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
}
|
||||
.error {
|
||||
color: var(--error-color, #f44336);
|
||||
font-size: 13px;
|
||||
}
|
||||
`,r([d({attribute:!1})],a.prototype,"hass",2),r([d({attribute:!1})],a.prototype,"objects",2),r([s()],a.prototype,"_open",2),r([s()],a.prototype,"_loading",2),r([s()],a.prototype,"_error",2),r([s()],a.prototype,"_name",2),r([s()],a.prototype,"_manufacturer",2),r([s()],a.prototype,"_model",2),r([s()],a.prototype,"_serialNumber",2),r([s()],a.prototype,"_areaId",2),r([s()],a.prototype,"_installationDate",2),r([s()],a.prototype,"_warrantyExpiry",2),r([s()],a.prototype,"_documentationUrl",2),r([s()],a.prototype,"_notes",2),r([s()],a.prototype,"_haDeviceId",2),r([s()],a.prototype,"_parentEntryId",2),r([s()],a.prototype,"_entryId",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",a);export{a};
|
||||
@@ -0,0 +1,88 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{A as m,a,b as y,c as s,f as l,h as g,l as o,m as f,q as d}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";function $(n){let t=m("2001-02-03",n).match(/\d+/g)||[],e=v=>t.findIndex(_=>Number(_)===v),h=e(2001),c=e(2),u=e(3);return h===0?"YMD":c>=0&&u>=0&&c<u?"MDY":"DMY"}function p(n,i,t){if(n<1e3||n>9999||i<1||i>12||t<1||t>31)return null;let e=new Date(n,i-1,t);return e.getFullYear()!==n||e.getMonth()!==i-1||e.getDate()!==t?null:`${n}-${String(i).padStart(2,"0")}-${String(t).padStart(2,"0")}`}function b(n,i){let t=n.trim(),e;if(e=t.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/))return p(+e[1],+e[2],+e[3]);if(e=t.match(/^(\d{4})$/))return p(+e[1],1,1);if(e=t.match(/^(\d{1,2})[./](\d{4})$/))return p(+e[2],+e[1],1);if(e=t.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/))return p(+e[3],+e[2],+e[1]);if(e=t.match(/^(\d{1,2})[/-](\d{1,2})[/-](\d{4})$/)){let h=+e[1],c=+e[2],u=+e[3];return $(i)==="MDY"?p(u,h,c):p(u,c,h)}return null}function x(n,i){if(i)switch(n){case"date":return i.split("T")[0];case"time":return i.length===5?`${i}:00`:i;case"datetime":{let[t,e="00:00:00"]=i.split("T");return`${t} ${e.length===5?`${e}:00`:e}`}}}function k(n,i){if(typeof i!="string"||!i)return"";switch(n){case"date":return i.slice(0,10);case"time":return i.slice(0,5);case"datetime":{let[t,e="00:00:00"]=i.split(" ");return`${t}T${e.length===5?`${e}:00`:e}`}}}var r=class extends g{constructor(){super(...arguments);this.kind="date";this.label="";this.value="";this.clearable=!1;this.disabled=!1;this.required=!1;this.lang="en";this._typing=!1;this._typed="";this._typedInvalid=!1}_startTyping(){this._typed=this.value,this._typedInvalid=!1,this._typing=!0,this.updateComplete.then(()=>this.shadowRoot?.querySelector("input.typed")?.focus())}_commitTyped(){if(!this._typed.trim()){this._typing=!1;return}let t=b(this._typed,this.lang);if(!t){this._typedInvalid=!0;return}this._typing=!1,this._typedInvalid=!1,this._emit(t)}_onTypedKey(t){t.key==="Enter"?(t.preventDefault(),this._commitTyped()):t.key==="Escape"&&(t.preventDefault(),this._typing=!1,this._typedInvalid=!1)}_selector(){switch(this.kind){case"date":return{date:{}};case"time":return{time:{no_second:!0}};case"datetime":return{datetime:{}}}}_onSelectorChange(t){t.stopPropagation(),this._emit(k(this.kind,t.detail?.value))}_clear(){this._emit("")}_emit(t){t!==this.value&&(this.value=t,this.dispatchEvent(new CustomEvent("value-changed",{bubbles:!0,composed:!0,detail:{value:t}})))}render(){return s`
|
||||
<div class="field">
|
||||
${this.label?s`<span class="label">${this.label}${this.required?s`<span class="req">*</span>`:l}</span>`:l}
|
||||
<div class="row">
|
||||
${this._typing?s`<input class="typed" type="text" inputmode="numeric" autocomplete="off"
|
||||
.value=${this._typed}
|
||||
placeholder=${m("1978-03-15",this.lang)}
|
||||
aria-invalid=${this._typedInvalid?"true":"false"}
|
||||
@input=${t=>{this._typed=t.target.value,this._typedInvalid=!1}}
|
||||
@keydown=${this._onTypedKey}
|
||||
@blur=${this._commitTyped} />`:s`<ha-selector
|
||||
.hass=${this.hass}
|
||||
.selector=${this._selector()}
|
||||
.value=${x(this.kind,this.value)}
|
||||
.required=${this.required}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._onSelectorChange}
|
||||
></ha-selector>`}
|
||||
${this.kind==="date"&&!this.disabled&&!this._typing?s`<button type="button" class="type-toggle" title=${d("date_type_toggle",this.lang)} aria-label=${d("date_type_toggle",this.lang)} @click=${this._startTyping}>
|
||||
<ha-icon icon="mdi:keyboard-outline"></ha-icon>
|
||||
</button>`:l}
|
||||
${this.clearable&&this.value&&!this.disabled&&!this._typing?s`<button type="button" class="clear" title=${d("clear",this.lang)} aria-label=${d("clear",this.lang)} @click=${this._clear}>
|
||||
<ha-icon icon="mdi:close"></ha-icon>
|
||||
</button>`:l}
|
||||
</div>
|
||||
${this._typedInvalid?s`<span class="helper invalid">${d("date_type_invalid",this.lang)}</span>`:this.helper?s`<span class="helper">${this.helper}</span>`:l}
|
||||
</div>
|
||||
`}};r.styles=y`
|
||||
:host { display: block; }
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.label {
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color, #888);
|
||||
font-weight: 500;
|
||||
}
|
||||
.req { color: var(--error-color, #f44336); margin-left: 2px; }
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
ha-selector {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.clear, .type-toggle {
|
||||
flex: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
color: var(--secondary-text-color);
|
||||
cursor: pointer;
|
||||
--mdc-icon-size: 20px;
|
||||
}
|
||||
.clear:hover, .type-toggle:hover { background: rgba(var(--rgb-primary-text-color, 0, 0, 0), 0.08); }
|
||||
.clear:focus-visible, .type-toggle:focus-visible { outline: 2px solid var(--primary-color); }
|
||||
.helper {
|
||||
font-size: 11px;
|
||||
color: var(--secondary-text-color);
|
||||
font-style: italic;
|
||||
}
|
||||
.helper.invalid { color: var(--error-color, #f44336); font-style: normal; }
|
||||
input.typed {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
padding: 0 12px;
|
||||
border: 1px solid var(--divider-color, #ccc);
|
||||
border-radius: 4px;
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
font: inherit;
|
||||
}
|
||||
input.typed[aria-invalid="true"] { border-color: var(--error-color, #f44336); }
|
||||
input.typed:focus { outline: 2px solid var(--primary-color); outline-offset: -1px; }
|
||||
`,a([o({attribute:!1})],r.prototype,"hass",2),a([o()],r.prototype,"kind",2),a([o()],r.prototype,"label",2),a([o()],r.prototype,"value",2),a([o()],r.prototype,"helper",2),a([o({type:Boolean})],r.prototype,"clearable",2),a([o({type:Boolean})],r.prototype,"disabled",2),a([o({type:Boolean})],r.prototype,"required",2),a([o()],r.prototype,"lang",2),a([f()],r.prototype,"_typing",2),a([f()],r.prototype,"_typed",2),a([f()],r.prototype,"_typedInvalid",2);customElements.get("ms-date-field")||customElements.define("ms-date-field",r);
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{q as p}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";function f(r){return`${r.entry_id??""}\0${r.part_id}`}function g(r,n,i,o){let t=!!r.entry_id&&r.entry_id!==n,e=t?r.entry_id:n,s=i.find(l=>l.entry_id===e),a=(s?.parts||[]).find(l=>l.id===r.part_id)||null,u=t&&s?.object?.name||"",d=a?.name||p("shared_part_unknown",o);return{part:a,foreign:t,ownerName:u,label:u?`${d} (${u})`:d}}function _(r,n,i,o){let{part:t,label:e}=g(r,n,i,o),s=t&&t.stock!==null&&t.stock!==void 0?` (${t.stock}${t.unit?" "+t.unit:""})`:"",a=t?.storage_location?` \u2014 ${t.storage_location}`:"";return`${r.quantity}\xD7 ${e}${s}${a}`}function R(r,n,i,o){let e=(i.find(a=>a.entry_id===n)?.parts||[]).map(a=>({...a})),s=new Set(e.map(a=>f({part_id:a.id})));for(let a of r?.consumes_parts||[]){if(!a.entry_id||a.entry_id===n)continue;let u=f(a);if(s.has(u))continue;s.add(u);let{part:d,ownerName:l}=g(a,n,i,o);e.push({id:a.part_id,name:d?.name||p("shared_part_unknown",o),unit:d?.unit,stock:d?.stock??null,storage_location:d?.storage_location,entry_id:a.entry_id,owner_name:l})}return e}function w(){let r=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:n=>n.map(()=>Math.floor(Math.random()*256))}).getRandomValues(r),Array.from(r,n=>n.toString(16).padStart(2,"0")).join("")}function c(r){let n=r?.reading_values;if(!Array.isArray(n))return[];let i=[],o=new Set;for(let t of n){if(!t||typeof t!="object")continue;let e=t;typeof e.id!="string"||!e.id||o.has(e.id)||typeof e.value!="number"||!Number.isFinite(e.value)||(o.add(e.id),i.push({id:e.id,name:typeof e.name=="string"?e.name:e.id,unit:typeof e.unit=="string"?e.unit:null,value:e.value}))}return i}function y(r){return r.filter(n=>n.type==="completed"&&(n.reading_value!=null||c(n).length>0)).sort((n,i)=>n.timestamp.localeCompare(i.timestamp))}function S(r){return y(r??[]).map(n=>({timestamp:n.timestamp,values:c(n)})).filter(n=>n.values.length>0)}function P(r,n,i){let o;for(let t of r){if(i!==void 0){let s=new Date(t.timestamp).getTime();if(!isNaN(s)&&s>=i)break}let e=t.values.find(s=>s.id===n);e&&(o=e)}return o}function b(r,n,i){let o=c(n).find(e=>e.id===i);if(!o)return null;let t=null;for(let e of y(r)){if(e.timestamp>=n.timestamp)break;let s=c(e).find(a=>a.id===i);s&&(t=s.value)}return t==null?null:o.value-t}function E(r){let n=new Set,i=new Set;for(let o of r){let t=(o.name||"").trim().toLowerCase();t&&(n.has(t)?i.add(o.id):n.add(t))}return i}function v(r){let n=[],i=new Set,o=new Set;for(let t of r){let e=(t.name||"").trim();if(!(!e||i.has(t.id)||o.has(e.toLowerCase()))&&(i.add(t.id),o.add(e.toLowerCase()),n.push({id:t.id,name:e,unit:(t.unit||"").trim()||null}),n.length>=20))break}return n}var x=["notes","cost","duration","photo","user"],h={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"};export{f as a,_ as b,R as c,w as d,c as e,S as f,P as g,b as h,E as i,v as j,x as k,h as l};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{c as r,f as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";var a=["#c62828","#ad1457","#6a1b9a","#4527a0","#283593","#1565c0","#00838f","#2e7d32","#558b2f","#ef6c00","#6d4c41","#546e7a"];function u(e){let s=(e||"").split(/\s+/).filter(Boolean);return s.length===0?"?":s.length===1?s[0][0].toUpperCase():(s[0][0]+s[s.length-1][0]).toUpperCase()}function c(e){let s=0;for(let n of e)s=s*31+n.charCodeAt(0)>>>0;return a[s%a.length]}function o(e){return e?{id:e.id,name:e.name,initials:e.initials||u(e.name),color:e.color||c(e.id)}:null}function h(e){return e?r`<span class="person-avatar" style="--person-color: ${e.color}" title=${e.name}>${e.initials}</span>`:i}function m(e,s=""){return e?r`<span class="person-chip ${s}" title=${e.name}>${h(e)}<span class="person-name">${e.name}</span></span>`:i}var l=class{constructor(s){this.usersCache=null;this.cacheTimestamp=0;this.CACHE_TTL_MS=6e4;this.hass=s}updateHass(s){this.hass=s}async getUsers(s=!1){let n=Date.now();if(!s&&this.usersCache&&n-this.cacheTimestamp<this.CACHE_TTL_MS)return this.usersCache;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/users/list"});return this.usersCache=t.users,this.cacheTimestamp=n,this.usersCache}catch(t){return console.error("Failed to fetch users:",t),this.usersCache||[]}}async assignUser(s,n,t){await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/assign_user",entry_id:s,task_id:n,user_id:t})}async getTasksByUser(s){return(await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/tasks/by_user",user_id:s})).tasks}getUserName(s){return!s||!this.usersCache?null:this.usersCache.find(t=>t.id===s)?.name||null}getPerson(s){return o(this.getUser(s))}getUser(s){return!s||!this.usersCache?null:this.usersCache.find(n=>n.id===s)||null}getCurrentUserId(){return this.hass.user?.id||null}isCurrentUser(s){return s?s===this.getCurrentUserId():!1}clearCache(){this.usersCache=null,this.cacheTimestamp=0}};export{a,o as b,h as c,m as d,l as e};
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,79 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a as r,b as l,c as i,f as o,h as n,l as t}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";var e=class extends n{constructor(){super(...arguments);this.label="";this.value="";this.placeholder="";this.type="text";this.required=!1;this.disabled=!1;this.multiline=!1;this.rows=3}_onInput(s){let a=s.target.value;this.value=a,this.dispatchEvent(new CustomEvent("input",{bubbles:!0,composed:!0,detail:{value:a}}))}render(){return i`
|
||||
<label class="field">
|
||||
${this.label?i`<span class="label">${this.label}${this.required?i`<span class="req">*</span>`:o}</span>`:o}
|
||||
${this.multiline?i`
|
||||
<textarea
|
||||
.value=${this.value??""}
|
||||
rows=${this.rows}
|
||||
?required=${this.required}
|
||||
?disabled=${this.disabled}
|
||||
placeholder=${this.placeholder}
|
||||
@input=${this._onInput}
|
||||
@change=${this._onInput}
|
||||
></textarea>`:i`
|
||||
<input
|
||||
.value=${this.value??""}
|
||||
.type=${this.type}
|
||||
?required=${this.required}
|
||||
?disabled=${this.disabled}
|
||||
placeholder=${this.placeholder}
|
||||
step=${this.step??o}
|
||||
min=${this.min??o}
|
||||
max=${this.max??o}
|
||||
pattern=${this.pattern??o}
|
||||
@input=${this._onInput}
|
||||
@change=${this._onInput}
|
||||
/>`}
|
||||
${this.helper?i`<span class="helper">${this.helper}</span>`:o}
|
||||
</label>
|
||||
`}};e.styles=l`
|
||||
:host { display: block; }
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.label {
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color, #888);
|
||||
font-weight: 500;
|
||||
}
|
||||
.req { color: var(--error-color, #f44336); margin-left: 2px; }
|
||||
input {
|
||||
padding: 8px 10px;
|
||||
font-size: 14px;
|
||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color, rgba(255,255,255,0.12));
|
||||
border-radius: 6px;
|
||||
font-family: inherit;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
}
|
||||
input:focus {
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
input:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
textarea {
|
||||
padding: 8px 10px;
|
||||
font-size: 14px;
|
||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color, rgba(255,255,255,0.12));
|
||||
border-radius: 6px;
|
||||
font-family: inherit;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
resize: vertical;
|
||||
}
|
||||
textarea:focus { border-color: var(--primary-color); }
|
||||
textarea:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.helper {
|
||||
font-size: 11px;
|
||||
color: var(--secondary-text-color);
|
||||
font-style: italic;
|
||||
}
|
||||
`,r([t()],e.prototype,"label",2),r([t()],e.prototype,"value",2),r([t()],e.prototype,"placeholder",2),r([t()],e.prototype,"type",2),r([t({type:Boolean})],e.prototype,"required",2),r([t({type:Boolean})],e.prototype,"disabled",2),r([t()],e.prototype,"step",2),r([t()],e.prototype,"min",2),r([t()],e.prototype,"max",2),r([t()],e.prototype,"pattern",2),r([t()],e.prototype,"helper",2),r([t({type:Boolean})],e.prototype,"multiline",2),r([t({type:Number})],e.prototype,"rows",2);customElements.get("ms-textfield")||customElements.define("ms-textfield",e);
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
var l=[{key:"name",labelKey:"name",required:!0},{key:"ref_no",labelKey:"ref_number"},{key:"manufacturer",labelKey:"manufacturer"},{key:"model",labelKey:"model"},{key:"serial_number",labelKey:"serial_number_label"},{key:"installation_date",labelKey:"installed"},{key:"warranty_expiry",labelKey:"warranty"},{key:"area_id",labelKey:"area"},{key:"documentation_url",labelKey:"documentation_url_label"},{key:"notes",labelKey:"object_notes_label"},{key:"task_count",labelKey:"tasks"},{key:"actions",labelKey:"actions"}],i=l.map(a=>a.key),r=["name","manufacturer","model","serial_number","installation_date","warranty_expiry","area_id","task_count","actions"];function o(a){if(!Array.isArray(a))return[...r];let t=new Set,e=[];for(let n of a)typeof n=="string"&&i.includes(n)&&!t.has(n)&&(t.add(n),e.push(n));return e.length?(e.includes("name")||e.unshift("name"),e):[...r]}export{l as a,r as b,o as c};
|
||||
@@ -0,0 +1,213 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a as x}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-XB4BHMUS.js";import{a,b as v,c as n,f as p,h as b,l as h,m as c,q as t}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";function d(l){return l.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function f(l){return!l.startsWith("data:image/svg+xml,")&&!l.startsWith("data:image/png;base64,")?"":d(l)}function q(l){return l.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var o=class extends b{constructor(){super(...arguments);this.lang="en";this._open=!1;this._loading=!1;this._error="";this._viewResult=null;this._completeResult=null;this._urlMode="companion";this._entryId="";this._taskId=null;this._objectName="";this._taskName="";this._generateSeq=0}openForObject(e,i){this._entryId=e,this._taskId=null,this._objectName=i,this._taskName="",this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._open=!0,this._generate()}openForTask(e,i,r,s){this._entryId=e,this._taskId=i,this._objectName=r,this._taskName=s,this._urlMode="companion",this._error="",this._viewResult=null,this._completeResult=null,this._open=!0,this._generate()}async _generate(){let e=++this._generateSeq;this._loading=!0,this._error="",this._viewResult=null,this._completeResult=null;try{let i={type:"maintenance_supporter/qr/generate",entry_id:this._entryId,url_mode:this._urlMode};this._taskId&&(i.task_id=this._taskId);let r=[this.hass.connection.sendMessagePromise({...i,action:"view"})];this._taskId&&r.push(this.hass.connection.sendMessagePromise({...i,action:"complete"}));let s=await Promise.all(r);if(e!==this._generateSeq)return;this._viewResult=s[0],s.length>1&&(this._completeResult=s[1])}catch(i){if(e!==this._generateSeq)return;let r=i?.code,s=i?.message;this._error=r==="no_url"||typeof s=="string"&&s.includes("No Home Assistant URL")?t("qr_error_no_url",this.lang):t("qr_error",this.lang)}finally{e===this._generateSeq&&(this._loading=!1)}}_setUrlMode(e){this._urlMode!==e&&(this._urlMode=e,this._generate())}_print(){if(!this._viewResult)return;let e=this._viewResult,i=e.label.task_name?`${e.label.object_name} \u2014 ${e.label.task_name}`:e.label.object_name,r=[e.label.manufacturer,e.label.model].filter(Boolean).join(" "),s=window.open("","_blank","width=600,height=500");if(!s)return;let g=this.lang||"en",u=d(i),m=d(r),_=!!this._completeResult,w=d(t("qr_action_view",g)),$=d(t("qr_action_complete",g));s.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
||||
<meta name="color-scheme" content="light">
|
||||
<title>${u}</title>
|
||||
<style>
|
||||
/* Printable sheet \u2014 must not inherit the phone's dark theme. The QR images
|
||||
carry their own white quiet zone and stay scannable either way, but the
|
||||
labels below are explicit dark greys and would vanish on a WebView's dark
|
||||
canvas. Same reasoning as helpers/report.ts. */
|
||||
:root{color-scheme:light}
|
||||
body{font-family:sans-serif;text-align:center;padding:20px;background:#fff;color:#1a1a1a}
|
||||
h2{margin:0 0 4px}
|
||||
.sub{color:#666;font-size:14px;margin-bottom:16px}
|
||||
.qr-row{display:flex;justify-content:center;gap:24px;margin:12px 0}
|
||||
.qr-col{display:flex;flex-direction:column;align-items:center;gap:6px}
|
||||
.qr-col img{width:${_?"200px":"280px"}}
|
||||
.qr-label{font-size:13px;font-weight:500;color:#333}
|
||||
.url{font-size:10px;color:#999;word-break:break-all;margin-top:8px;max-width:480px}
|
||||
</style></head><body>
|
||||
<h2>${u}</h2>
|
||||
${m?`<div class="sub">${m}</div>`:""}
|
||||
<div class="qr-row">
|
||||
<div class="qr-col">
|
||||
<img src="${f(this._viewResult.svg_data_uri)}" alt="QR Info" />
|
||||
<div class="qr-label">${w}</div>
|
||||
</div>
|
||||
${_?`<div class="qr-col">
|
||||
<img src="${f(this._completeResult.svg_data_uri)}" alt="QR Complete" />
|
||||
<div class="qr-label">${$}</div>
|
||||
</div>`:""}
|
||||
</div>
|
||||
<div class="url">${d(this._viewResult.url)}</div>
|
||||
<script>setTimeout(()=>window.print(),300)<\/script>
|
||||
</body></html>`),s.document.close()}_downloadSvg(e,i){let r=decodeURIComponent(e.svg_data_uri.replace("data:image/svg+xml,","")),s=this._taskName?`${this._objectName}-${this._taskName}`:this._objectName;x(r,`qr-${q(s)}-${i}.svg`,"image/svg+xml")}_close(){this._open=!1,this._viewResult=null,this._completeResult=null,this._error="",this._loading=!1}render(){if(!this._open)return n``;let e=this.lang||this.hass?.language||"en",i=this._taskName?`${t("qr_code",e)}: ${this._objectName} \u2014 ${this._taskName}`:`${t("qr_code",e)}: ${this._objectName}`,r=!!this._viewResult;return n`
|
||||
<ha-dialog open @closed=${this._close}>
|
||||
<div class="dialog-title">${i}</div>
|
||||
<div class="content">
|
||||
${this._loading?n`<div class="loading">${t("qr_generating",e)}</div>`:this._error?n`<div class="error">${this._error}</div>`:r?n`
|
||||
<div class="qr-pair">
|
||||
<div class="qr-item">
|
||||
<img
|
||||
class="qr-image ${this._completeResult?"small":""}"
|
||||
src="${this._viewResult.svg_data_uri}"
|
||||
alt="QR Info"
|
||||
/>
|
||||
<div class="qr-item-label">${t("qr_action_view",e)}</div>
|
||||
<button class="dl-btn"
|
||||
@click=${()=>this._downloadSvg(this._viewResult,"info")}>
|
||||
<ha-icon icon="mdi:download"></ha-icon>
|
||||
${t("qr_download",e)}
|
||||
</button>
|
||||
</div>
|
||||
${this._completeResult?n`
|
||||
<div class="qr-item">
|
||||
<img
|
||||
class="qr-image small"
|
||||
src="${this._completeResult.svg_data_uri}"
|
||||
alt="QR Complete"
|
||||
/>
|
||||
<div class="qr-item-label">${t("qr_action_complete",e)}</div>
|
||||
<button class="dl-btn"
|
||||
@click=${()=>this._downloadSvg(this._completeResult,"complete")}>
|
||||
<ha-icon icon="mdi:download"></ha-icon>
|
||||
${t("qr_download",e)}
|
||||
</button>
|
||||
</div>
|
||||
`:p}
|
||||
</div>
|
||||
<div class="url-display">${this._viewResult.url}</div>
|
||||
`:p}
|
||||
<div class="action-row">
|
||||
<label>${t("qr_url_mode",e)}</label>
|
||||
<div class="action-toggle">
|
||||
<button class="toggle-btn ${this._urlMode==="companion"?"active":""}"
|
||||
@click=${()=>this._setUrlMode("companion")}>${t("qr_mode_companion",e)}</button>
|
||||
<button class="toggle-btn ${this._urlMode==="local"?"active":""}"
|
||||
@click=${()=>this._setUrlMode("local")}>${t("qr_mode_local",e)}</button>
|
||||
<button class="toggle-btn ${this._urlMode==="server"?"active":""}"
|
||||
@click=${()=>this._setUrlMode("server")}>${t("qr_mode_server",e)}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${t("cancel",e)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._print}
|
||||
.disabled=${!r}
|
||||
>
|
||||
${t("qr_print",e)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`}};o.styles=v`
|
||||
.dialog-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
min-width: 300px;
|
||||
}
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
.qr-pair {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
.qr-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.qr-image {
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
.qr-image.small {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
}
|
||||
.qr-item-label {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--secondary-text-color);
|
||||
text-align: center;
|
||||
}
|
||||
.dl-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
background: none;
|
||||
border: 1px solid var(--divider-color, #e0e0e0);
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
color: var(--primary-text-color);
|
||||
padding: 6px 14px;
|
||||
border-radius: 18px;
|
||||
transition: background 0.2s, border-color 0.2s;
|
||||
}
|
||||
.dl-btn:hover {
|
||||
background: var(--secondary-background-color, #f5f5f5);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
.dl-btn ha-icon {
|
||||
--mdc-icon-size: 18px;
|
||||
}
|
||||
.url-display {
|
||||
font-size: 11px;
|
||||
color: var(--secondary-text-color);
|
||||
word-break: break-all;
|
||||
text-align: center;
|
||||
max-width: 400px;
|
||||
}
|
||||
.loading {
|
||||
padding: 40px 0;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.error {
|
||||
padding: 20px 0;
|
||||
color: var(--error-color, #f44336);
|
||||
}
|
||||
.action-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
.action-row label {
|
||||
font-size: 13px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.action-toggle {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
background: var(--divider-color, #e0e0e0);
|
||||
border-radius: 6px;
|
||||
padding: 3px;
|
||||
}
|
||||
.toggle-btn {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--primary-text-color);
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
transition: all 0.2s;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.toggle-btn:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.toggle-btn.active {
|
||||
background: var(--primary-color);
|
||||
color: var(--text-primary-color, #fff);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
`,a([h({attribute:!1})],o.prototype,"hass",2),a([h()],o.prototype,"lang",2),a([c()],o.prototype,"_open",2),a([c()],o.prototype,"_loading",2),a([c()],o.prototype,"_error",2),a([c()],o.prototype,"_viewResult",2),a([c()],o.prototype,"_completeResult",2),a([c()],o.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",o);export{o as a};
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WQXORDNI.js";import{q as s,s as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";async function f(e,a,n={}){n.busy?.(!0);try{return await e.hass.connection.sendMessagePromise(a)}catch(t){let r=o(e.hass);n.onError?.(i(t,r,n.fallbackKey?s(n.fallbackKey,r):void 0));return}finally{n.busy?.(!1)}}export{f as a};
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{q as o}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";var v={already_archived:"ws_err_already_archived",already_paused:"ws_err_already_paused",archived:"ws_err_archived",create_failed:"ws_err_create_failed",duplicate_failed:"ws_err_duplicate_failed",empty:"ws_err_empty",empty_csv:"ws_err_empty_csv",invalid_cursor:"ws_err_invalid_cursor",invalid_date:"ws_err_invalid_date",invalid_device:"ws_err_invalid_device",invalid_entity_slug:"ws_err_invalid_entity_slug",invalid_format:"ws_err_invalid_format",invalid_input:"ws_err_invalid_input",invalid_mirror_todo:"ws_err_invalid_mirror_todo",invalid_parent:"ws_err_invalid_parent",invalid_icon:"ws_err_invalid_icon",invalid_range:"ws_err_invalid_range",invalid_search_template:"ws_err_invalid_search_template",invalid_target:"ws_err_invalid_target",invalid_trigger_config:"ws_err_invalid_trigger_config",invalid_url:"ws_err_invalid_url",invalid_user:"ws_err_invalid_user",invalid_view:"ws_err_invalid_view",limit_reached:"ws_err_limit_reached",no_defaults:"ws_err_no_defaults",no_phases:"ws_err_no_phases",no_url:"ws_err_no_url",not_archived:"ws_err_not_archived",not_available:"ws_err_not_available",not_configured:"ws_err_not_configured",not_found:"ws_err_not_found",not_loaded:"ws_err_not_loaded",not_paused:"ws_err_not_paused",replace_failed:"ws_err_replace_failed",self_link_device:"ws_err_self_link_device",storage_unavailable:"ws_err_storage_unavailable",too_early:"ws_err_too_early",too_large:"ws_err_too_large",too_many:"ws_err_too_many",too_many_views:"ws_err_too_many_views",unauthorized:"ws_err_unauthorized",unavailable:"ws_err_unavailable"},p={entry_id:"object",name:"name",task_type:"maintenance_type",schedule_type:"schedule_type",interval_days:"interval_days",interval_anchor:"interval_anchor",warning_days:"warning_days",last_performed:"last_performed_optional",notes:"notes_optional",documentation_url:"documentation_url_optional",custom_icon:"custom_icon_optional",nfc_tag_id:"nfc_tag_id_optional",responsible_user_id:"responsible_user",entity_slug:"entity_slug",entity_id:"entity_id",area_id:"area_id_optional",manufacturer:"manufacturer_optional",model:"model_optional",serial_number:"serial_number_optional",installation_date:"installation_date_optional",warranty_expiry:"warranty_expiry_optional",checklist:"checklist_steps_optional",reason:"reason",feedback:"feedback",cost:"cost",duration:"duration",description:"description_optional",environmental_entity:"environmental_entity_optional",environmental_attribute:"environmental_attribute_optional",trigger_above:"trigger_above",trigger_below:"trigger_below",trigger_equals:"trigger_equals",trigger_not_equals:"trigger_not_equals",trigger_for_minutes:"trigger_for_minutes"};function g(e){let _=e.replace(/_ids?$/,"").split("_").filter(Boolean);if(_.length===0)return e;let r=_.join(" ");return r.charAt(0).toUpperCase()+r.slice(1)}function w(e,_){let r=p[e];if(r){let t=o(r,_);if(t&&t!==r)return t}return g(e)}function f(e){let _=[...e.matchAll(/\['([^']+)'\]/g)].map(i=>i[1]),r=_.length?_[_.length-1]:void 0,t;return(t=e.match(/length of value must be at most (\d+)/))?{field:r,rule:"too_long",param:t[1]}:(t=e.match(/length of value must be at least (\d+)/))?{field:r,rule:"too_short",param:t[1]}:(t=e.match(/value must be at most (\S+)/))?{field:r,rule:"value_too_high",param:t[1]}:(t=e.match(/value must be at least (\S+)/))?{field:r,rule:"value_too_low",param:t[1]}:/required key not provided/.test(e)?{field:r,rule:"required"}:(t=e.match(/expected (\w+)/))?{field:r,rule:"wrong_type",param:t[1]}:/value must be one of/.test(e)?{field:r,rule:"invalid_choice"}:/not a valid value/.test(e)?{field:r,rule:"invalid_value"}:{field:r,rule:"unknown"}}var u=e=>e.toLowerCase().split(/[^a-z0-9]+/).filter(_=>_.length>1);function m(e,_){let r=new Set(u(_));return u(e).every(t=>r.has(t))}function y(e,_,r){if(r=r??o("action_error",_),typeof e=="string")return e;if(typeof e!="object"||e===null)return r;let t=e,i=t.message||t.error?.message||"",s=t.code||t.error?.code||"",d=s?v[s]:void 0;if(!i&&!d)return r;let a=f(i),c=a.field?w(a.field,_):"",n=l=>o(l,_).replace("{field}",c).replace("{n}",a.param??"");switch(a.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}",a.param??"");case"invalid_choice":return n("err_invalid_choice");case"invalid_value":return n("err_invalid_value");default:if(d){let l=o(d,_);return i&&!m(i,s)?`${l} (${i})`:l}return i||r}}export{y as a};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
function c(o,t,e){let l=new Blob([o],{type:e}),d=URL.createObjectURL(l),n=document.createElement("a");n.href=d,n.download=t,n.target="_blank",n.rel="noopener",n.style.display="none",document.body.appendChild(n),n.dispatchEvent(new MouseEvent("click")),document.body.removeChild(n),setTimeout(()=>URL.revokeObjectURL(d),6e4)}function r(o,t){let e=document.createElement("a");e.href=o,e.download=t,e.target="_blank",e.rel="noopener",e.style.display="none",document.body.appendChild(e),e.dispatchEvent(new MouseEvent("click")),document.body.removeChild(e)}export{c as a,r as b};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{i as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-PDDZINC4.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-5XRT3AM7.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-2PKU3QXM.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-WQXORDNI.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";export{a as MaintenanceCompleteDialog};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{F as a,G as b,H as c,I as d,J as e,K as f,L as g,M as h,N as i,O as j,P as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-ZMV2VB57.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-C7OGYVZI.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-2IGVBRZV.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-ZJPHP3YU.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-QOKIQTSS.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-EH52ZZY4.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-PDDZINC4.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-5XRT3AM7.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-2PKU3QXM.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-FLCA3VKG.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-XB4BHMUS.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-73EHFI76.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-WQXORDNI.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";export{b as __resetSettingsCacheForTests,a as getRowActionStyle,h as openCompleteDialog,c as openCreateObjectDialog,e as openCreateTaskDialog,d as openEditObjectDialog,f as openEditTaskDialog,g as openHistoryEditDialog,k as openObjectQuickActions,i as openQrDialog,j as openTaskQuickActions};
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-2IGVBRZV.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-EH52ZZY4.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-2PKU3QXM.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-WQXORDNI.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";export{a as MaintenanceObjectDialog};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-FLCA3VKG.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-XB4BHMUS.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";export{a as MaintenanceQrDialog};
|
||||
+1371
File diff suppressed because one or more lines are too long
+146
@@ -0,0 +1,146 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a as g}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WQXORDNI.js";import{a as l,b as m,c as i,f as h,h as v,l as u,m as d,q as p,s as f,u as x}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";var a=class extends v{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._adopting=!1;this._error="";this._setups=[];this._selected=new Set;this._baselines=new Map;this._targets=new Map;this._objects=[];this._localeReady=!1;this._toggle=t=>{let e=new Set(this._selected);e.has(t)?e.delete(t):e.add(t),this._selected=e};this._adopt=async()=>{if(!(this._selected.size===0||this._adopting)){this._adopting=!0,this._error="";try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/integration_setups/adopt",selections:[...this._selected].map(e=>{let r={device_id:e},c=this._targets.get(e);c&&(r.entry_id=c);let s=this._setups.find(n=>n.device_id===e);for(let n of s?.tasks??[]){let o=this._baselines.get(`${e} ${n.task_name}`),_=o?parseFloat(o):NaN;!isNaN(_)&&_>=0&&((r.baselines??={})[n.task_name]=_)}return r})});this.dispatchEvent(new CustomEvent("integration-setups-adopted",{bubbles:!0,composed:!0,detail:t})),this._open=!1}catch(t){this._error=g(t,this._lang)}finally{this._adopting=!1}}}}get _lang(){return f(this.hass)}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,x(this._lang).then(()=>this.requestUpdate()))}async open(){this._open=!0,this._loading=!0,this._error="",this._setups=[],this._selected=new Set;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/integration_setups/discover"});this._setups=t.setups||[],this._selected=new Set(this._setups.map(e=>e.device_id)),this._baselines=new Map,this._targets=new Map;try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"});this._objects=(e.objects||[]).map(r=>({entry_id:r.entry_id,name:r.object?.name||r.entry_id})).sort((r,c)=>r.name.localeCompare(c.name))}catch{this._objects=[]}}catch(t){this._error=g(t,this._lang)}finally{this._loading=!1}}_close(){this._open=!1}render(){if(!this._open)return i``;let t=this._lang;return i`
|
||||
<div class="overlay" @click=${this._close}>
|
||||
<div class="card" @click=${e=>e.stopPropagation()}>
|
||||
<div class="title">${p("setups_title",t)}</div>
|
||||
<div class="hint">${p("setups_hint",t)}</div>
|
||||
${this._error?i`<div class="error">${this._error}</div>`:h}
|
||||
|
||||
${this._loading?i`<div class="loading">…</div>`:this._setups.length===0?i`<div class="empty">${p("setups_none",t)}</div>`:i`
|
||||
<div class="list">
|
||||
${this._setups.map(e=>{let r=this._selected.has(e.device_id),c=[e.integration_name,e.area_name].filter(Boolean).join(" \xB7 ");return i`
|
||||
<label class="row">
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${r}
|
||||
@change=${()=>this._toggle(e.device_id)}
|
||||
/>
|
||||
<div class="row-main">
|
||||
<div class="row-top">
|
||||
<span class="row-name">${e.device_name}</span>
|
||||
</div>
|
||||
<div class="row-sub">${c}</div>
|
||||
<div class="row-target" @click=${s=>s.preventDefault()}>
|
||||
→
|
||||
${r&&this._objects.length>0?i`
|
||||
<select
|
||||
class="target-select"
|
||||
@change=${s=>{let n=new Map(this._targets),o=s.target.value;o?n.set(e.device_id,o):n.delete(e.device_id),this._targets=n}}
|
||||
>
|
||||
<option value="" ?selected=${!this._targets.get(e.device_id)}>
|
||||
${e.suggested_entry_id?e.suggested_object_name:p("setups_target_new",t).replace("{name}",e.suggested_object_name)}
|
||||
</option>
|
||||
${this._objects.filter(s=>s.entry_id!==e.suggested_entry_id).map(s=>i`<option
|
||||
value=${s.entry_id}
|
||||
?selected=${this._targets.get(e.device_id)===s.entry_id}
|
||||
>
|
||||
${s.name}
|
||||
</option>`)}
|
||||
</select>
|
||||
`:i`${e.suggested_object_name}${e.suggested_entry_id?h:i` <span class="new-tag">${p("adopt_problem_new_object",t)}</span>`}`}
|
||||
</div>
|
||||
<div class="row-tasks">
|
||||
${e.tasks.map(s=>i`<span class="chip" title=${s.entity_ids.join(", ")}>
|
||||
<ha-icon icon="mdi:link-variant"></ha-icon>${s.task_name_localized||s.task_name}
|
||||
</span>`)}
|
||||
</div>
|
||||
${r?e.tasks.filter(s=>s.direction==="usage_delta").map(s=>{let n=`${e.device_id} ${s.task_name}`;return i`
|
||||
<div class="baseline-field" @click=${o=>o.preventDefault()}>
|
||||
<span class="baseline-label"
|
||||
>${s.task_name_localized||s.task_name} —
|
||||
${p("setups_baseline_hint",t)}</span
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
step="any"
|
||||
min="0"
|
||||
.value=${this._baselines.get(n)??""}
|
||||
@click=${o=>o.preventDefault()}
|
||||
@input=${o=>{let _=new Map(this._baselines);_.set(n,o.target.value),this._baselines=_}}
|
||||
/>
|
||||
</div>
|
||||
`}):h}
|
||||
</div>
|
||||
</label>
|
||||
`})}
|
||||
</div>
|
||||
`}
|
||||
|
||||
<div class="actions">
|
||||
<ha-button appearance="plain" @click=${this._close}>
|
||||
${p("cancel",t)}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._adopt}
|
||||
.disabled=${this._selected.size===0||this._adopting}
|
||||
>
|
||||
${p("setups_adopt",t)}
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`}};a.styles=m`
|
||||
.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
min-width: min(360px, calc(100vw - 24px));
|
||||
max-width: 560px;
|
||||
width: 90vw;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.title { font-size: 18px; font-weight: 500; }
|
||||
.hint { color: var(--secondary-text-color); font-size: 13px; }
|
||||
.error { color: var(--error-color, #f44336); font-size: 13px; }
|
||||
.loading, .empty { color: var(--secondary-text-color); font-size: 14px; padding: 12px 0; }
|
||||
.list { display: flex; flex-direction: column; gap: 6px; overflow-y: auto; max-height: 50vh; }
|
||||
.row {
|
||||
display: flex; align-items: flex-start; gap: 10px; padding: 8px;
|
||||
border: 1px solid var(--divider-color); border-radius: 6px; cursor: pointer;
|
||||
}
|
||||
.row input { margin-top: 2px; cursor: pointer; }
|
||||
.row-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
|
||||
.row-name { font-weight: 500; font-size: 13px; }
|
||||
.row-sub, .row-target { color: var(--secondary-text-color); font-size: 12px; }
|
||||
.new-tag { font-style: italic; }
|
||||
.row-tasks { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; }
|
||||
.chip {
|
||||
display: inline-flex; align-items: center; gap: 4px;
|
||||
font-size: 11px; padding: 2px 8px; border-radius: 10px;
|
||||
background: var(--secondary-background-color, rgba(0, 0, 0, 0.06));
|
||||
color: var(--primary-text-color); white-space: nowrap;
|
||||
}
|
||||
.chip ha-icon { --mdc-icon-size: 12px; color: var(--primary-color); }
|
||||
.target-select {
|
||||
font-size: 12px; padding: 2px 4px; max-width: 100%;
|
||||
border: 1px solid var(--divider-color); border-radius: 4px;
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.baseline-field {
|
||||
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
|
||||
margin-top: 4px; font-size: 12px; color: var(--secondary-text-color);
|
||||
}
|
||||
.baseline-field input {
|
||||
width: 110px; padding: 3px 6px; font-size: 12px;
|
||||
border: 1px solid var(--divider-color); border-radius: 4px;
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.actions { display: flex; justify-content: flex-end; gap: 8px; padding-top: 8px; }
|
||||
`,l([u({attribute:!1})],a.prototype,"hass",2),l([d()],a.prototype,"_open",2),l([d()],a.prototype,"_loading",2),l([d()],a.prototype,"_adopting",2),l([d()],a.prototype,"_error",2),l([d()],a.prototype,"_setups",2),l([d()],a.prototype,"_selected",2),l([d()],a.prototype,"_baselines",2),l([d()],a.prototype,"_targets",2),l([d()],a.prototype,"_objects",2);customElements.get("maintenance-suggested-setups-dialog")||customElements.define("maintenance-suggested-setups-dialog",a);export{a as MaintenanceSuggestedSetupsDialog};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-ZJPHP3YU.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-QOKIQTSS.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-EH52ZZY4.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-5XRT3AM7.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-2PKU3QXM.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-73EHFI76.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-WQXORDNI.js";import"/maintenance_supporter_panelfiles/panel-chunks/chunk-RAW6RFRE.js";export{a as MaintenanceTaskDialog};
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a as x,b as $}from"./chunk-MSGNUEIB.js";import{B as p,a as h,b as l,d as b,e as y,f as m,g as o,h as g,i as a,j as v,k as _,n as f,q as d}from"./chunk-UI7IMFM7.js";import{a as n}from"./chunk-BR3YZILG.js";var E=80,e=class extends y{constructor(){super(...arguments);this._config={type:""};this._status=null;this._busy=!1;this._error="";this._localMonthly="";this._localYearly="";this._dirty=!1;this._loaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return _(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),v(this,t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load())}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/budget_status"});this._status=t,f(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=this._localMonthly.trim()===""?0:parseFloat(this._localMonthly),r=this._localYearly.trim()===""?0:parseFloat(this._localYearly),i={};!isNaN(t)&&t>=0&&(i.budget_monthly=t),!isNaN(r)&&r>=0&&(i.budget_yearly=r),await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/global/update",settings:i}),await this._load()}catch(t){this._error=p(t,this._lang)}finally{this._busy=!1}}}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_budget"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,r=this._status;if(!r)return l`<ha-card><div class="loading">${a("loading",t)}</div></ha-card>`;let i=g(r),k=r.alert_threshold_pct??E,w=[{label:a("budget_monthly",t),spent:r.monthly_spent||0,budget:r.monthly_budget||0},{label:a("budget_yearly",t),spent:r.yearly_spent||0,budget:r.yearly_budget||0}];return l`
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<span class="emoji">💰</span>
|
||||
<span>${this._config.title||a("settings_budget",t)}</span>
|
||||
</div>
|
||||
<span class="currency">${i}</span>
|
||||
</div>
|
||||
|
||||
${this._error?l`<div class="error">${this._error}</div>`:b}
|
||||
|
||||
${w.map(s=>{if(!(s.budget>0))return l`
|
||||
<div class="track spent-only">
|
||||
<div class="track-label-row">
|
||||
<label>${s.label}</label>
|
||||
<span class="track-numbers ok">${d(s.spent,i,t)}</span>
|
||||
</div>
|
||||
</div>
|
||||
`;let c=Math.min(100,Math.max(0,s.spent/s.budget*100)),u=c>=100?"danger":c>=k?"warning":"ok";return l`
|
||||
<div class="track">
|
||||
<div class="track-label-row">
|
||||
<label>${s.label}</label>
|
||||
<span class="track-numbers ${u}">
|
||||
${d(s.spent,void 0,t)} / ${d(s.budget,i,t)}
|
||||
</span>
|
||||
</div>
|
||||
<div class="bar"><div class="bar-fill ${u}" style="width:${c}%"></div></div>
|
||||
</div>
|
||||
`})}
|
||||
|
||||
${this._isAdmin?l`
|
||||
<div class="inputs-row">
|
||||
<div class="input-field">
|
||||
<label>${a("budget_monthly_set",t)}</label>
|
||||
<div class="input-wrap">
|
||||
<input type="number" min="0" step="1"
|
||||
.value=${this._localMonthly}
|
||||
?disabled=${this._busy}
|
||||
@input=${s=>{this._localMonthly=s.target.value,this._dirty=!0}} />
|
||||
<span class="input-suffix">${i}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-field">
|
||||
<label>${a("budget_yearly_set",t)}</label>
|
||||
<div class="input-wrap">
|
||||
<input type="number" min="0" step="1"
|
||||
.value=${this._localYearly}
|
||||
?disabled=${this._busy}
|
||||
@input=${s=>{this._localYearly=s.target.value,this._dirty=!0}} />
|
||||
<span class="input-suffix">${i}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn ${this._dirty?"primary":"muted"}"
|
||||
@click=${this._save}
|
||||
?disabled=${this._busy||!this._dirty}>
|
||||
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
|
||||
${this._dirty?a("save",t):a("saved",t)}
|
||||
</button>
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${a("budget_advanced",t)}
|
||||
</button>
|
||||
</div>
|
||||
`:l`
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${a("budget_open_panel",t)}
|
||||
</button>
|
||||
`}
|
||||
</div>
|
||||
</ha-card>
|
||||
`}};e.styles=[$,h`
|
||||
.currency {
|
||||
font-size: 14px; font-weight: 600;
|
||||
color: var(--secondary-text-color);
|
||||
background: var(--secondary-background-color);
|
||||
padding: 2px 10px; border-radius: 999px;
|
||||
}
|
||||
.track { display: flex; flex-direction: column; gap: 4px; }
|
||||
.track-label-row {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
}
|
||||
.track-label-row label {
|
||||
font-size: 12px; color: var(--secondary-text-color);
|
||||
text-transform: uppercase; letter-spacing: 0.5px;
|
||||
}
|
||||
.track-numbers { font-size: 13px; font-weight: 600; }
|
||||
.track-numbers.ok { color: var(--primary-text-color); }
|
||||
.track-numbers.warning { color: #ff9800; }
|
||||
.track-numbers.danger { color: var(--error-color, #f44336); }
|
||||
.bar {
|
||||
height: 6px; background: var(--secondary-background-color);
|
||||
border-radius: 3px; overflow: hidden;
|
||||
}
|
||||
.bar-fill { height: 100%; transition: width 0.3s; border-radius: 3px; }
|
||||
.bar-fill.ok { background: var(--primary-color); }
|
||||
.bar-fill.warning { background: #ff9800; }
|
||||
.bar-fill.danger { background: var(--error-color, #f44336); }
|
||||
.inputs-row {
|
||||
display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
|
||||
padding-top: 4px; border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
.input-field { display: flex; flex-direction: column; gap: 4px; }
|
||||
.input-field label {
|
||||
font-size: 11px; color: var(--secondary-text-color);
|
||||
text-transform: uppercase; letter-spacing: 0.3px;
|
||||
}
|
||||
.input-wrap { position: relative; display: flex; align-items: center; }
|
||||
.input-wrap input {
|
||||
flex: 1; padding: 6px 32px 6px 8px; font-size: 13px;
|
||||
background: var(--secondary-background-color, #2c2c2c);
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
font-family: inherit;
|
||||
}
|
||||
.input-suffix {
|
||||
position: absolute; right: 8px;
|
||||
color: var(--secondary-text-color); font-size: 13px;
|
||||
pointer-events: none;
|
||||
}
|
||||
.actions { display: flex; gap: 8px; align-items: center; }
|
||||
`],n([m({attribute:!1})],e.prototype,"hass",2),n([o()],e.prototype,"_config",2),n([o()],e.prototype,"_status",2),n([o()],e.prototype,"_busy",2),n([o()],e.prototype,"_error",2),n([o()],e.prototype,"_localMonthly",2),n([o()],e.prototype,"_localYearly",2),n([o()],e.prototype,"_dirty",2);customElements.get("maintenance-budget-section-card")||customElements.define("maintenance-budget-section-card",e);x({type:"maintenance-budget-section-card",name:"Maintenance Supporter \u2014 Budget",description:"Inline monthly + yearly budget editor",preview:!1});export{e as MaintenanceBudgetSectionCard};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.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.90.0 */
|
||||
import{a as t}from"./chunk-UI7IMFM7.js";function e(o){let r=window;r.customCards=r.customCards||[],r.customCards.some(a=>a.type===o.type)||r.customCards.push(o)}var d=t`
|
||||
ha-card { overflow: hidden; }
|
||||
.card-content {
|
||||
padding: 16px;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
.header {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
.title {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
font-size: 16px; font-weight: 500;
|
||||
}
|
||||
.emoji { font-size: 20px; }
|
||||
|
||||
/* Button family — primary action / muted-saved-state / link / icon-with-text */
|
||||
.btn {
|
||||
padding: 6px 12px; font-size: 13px;
|
||||
border-radius: 6px; cursor: pointer;
|
||||
border: 1px solid var(--divider-color);
|
||||
background: var(--secondary-background-color, transparent);
|
||||
color: var(--primary-text-color);
|
||||
font-weight: 500;
|
||||
display: inline-flex; align-items: center; gap: 4px;
|
||||
}
|
||||
.btn:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
|
||||
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
|
||||
.btn.primary {
|
||||
background: var(--primary-color);
|
||||
color: var(--text-primary-color, white);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
.btn.primary[disabled] { opacity: 0.6; }
|
||||
.btn.muted {
|
||||
background: transparent;
|
||||
color: var(--secondary-text-color);
|
||||
border-style: dashed;
|
||||
}
|
||||
.btn.muted[disabled] { opacity: 1; cursor: default; }
|
||||
.btn.muted ha-icon, .btn.primary ha-icon { --mdc-icon-size: 14px; }
|
||||
.btn.link {
|
||||
background: transparent; border: none; padding: 6px 4px;
|
||||
color: var(--primary-color); margin-left: auto;
|
||||
}
|
||||
.btn.link:hover { background: transparent; text-decoration: underline; }
|
||||
|
||||
/* Error + loading states */
|
||||
.error {
|
||||
padding: 8px; border-radius: 6px;
|
||||
background: rgba(211, 47, 47, 0.1);
|
||||
color: var(--error-color, #d32f2f); font-size: 13px;
|
||||
}
|
||||
.loading {
|
||||
padding: 24px; text-align: center;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
`;export{e as a,d as b};
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
function l(r){if(!r)return[];let n=[],i=r.photo_doc_id;typeof i=="string"&&n.push(i);let o=r.photo_doc_ids;Array.isArray(o)&&n.push(...o);let t=[];for(let e of n){if(typeof e!="string")continue;let s=e.trim();if(!(!s||t.includes(s))&&(t.push(s),t.length>=10))break}return t}function f(){let r=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:n=>n.map(()=>Math.floor(Math.random()*256))}).getRandomValues(r),Array.from(r,n=>n.toString(16).padStart(2,"0")).join("")}function u(r){let n=r?.reading_values;if(!Array.isArray(n))return[];let i=[],o=new Set;for(let t of n){if(!t||typeof t!="object")continue;let e=t;typeof e.id!="string"||!e.id||o.has(e.id)||typeof e.value!="number"||!Number.isFinite(e.value)||(o.add(e.id),i.push({id:e.id,name:typeof e.name=="string"?e.name:e.id,unit:typeof e.unit=="string"?e.unit:null,value:e.value}))}return i}function c(r){return r.filter(n=>n.type==="completed"&&(n.reading_value!=null||u(n).length>0)).sort((n,i)=>n.timestamp.localeCompare(i.timestamp))}function p(r){return c(r??[]).map(n=>({timestamp:n.timestamp,values:u(n)})).filter(n=>n.values.length>0)}function m(r,n,i){let o;for(let t of r){if(i!==void 0){let s=new Date(t.timestamp).getTime();if(!isNaN(s)&&s>=i)break}let e=t.values.find(s=>s.id===n);e&&(o=e)}return o}function _(r,n,i){let o=u(n).find(e=>e.id===i);if(!o)return null;let t=null;for(let e of c(r)){if(e.timestamp>=n.timestamp)break;let s=u(e).find(a=>a.id===i);s&&(t=s.value)}return t==null?null:o.value-t}function R(r){let n=new Set,i=new Set;for(let o of r){let t=(o.name||"").trim().toLowerCase();t&&(n.has(t)?i.add(o.id):n.add(t))}return i}function h(r){let n=[],i=new Set,o=new Set;for(let t of r){let e=(t.name||"").trim();if(!(!e||i.has(t.id)||o.has(e.toLowerCase()))&&(i.add(t.id),o.add(e.toLowerCase()),n.push({id:t.id,name:e,unit:(t.unit||"").trim()||null}),n.length>=20))break}return n}function g(r,n,i,o){let t=i,e=d=>typeof d=="string"?d:null,s=d=>typeof d=="number"?d:null,a=e(t.timestamp)??"";return{entry_id:r,task_id:n,original_timestamp:a,type:e(t.type)||"completed",timestamp:a,notes:e(t.notes),cost:s(t.cost),duration:s(t.duration),completed_by:e(t.completed_by),used_parts:Array.isArray(t.used_parts)?t.used_parts:null,photo_doc_ids:l(t),reading_value:s(t.reading_value),reading_values:u(t),readings:o?.readings??[],task_type:o?.type??null,reading_unit:o?.reading_unit??null}}async function E(r,n,i,o){let e=(await r.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:n})).tasks?.find(a=>a.id===i),s=e?.history?.find(a=>a.timestamp===o);return!e||!s?null:g(n,i,s,e)}export{l as a,f as b,u as c,p as d,m as e,_ as f,R as g,h,g as i,E as j};
|
||||
@@ -0,0 +1,88 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a as y,b as s,d as l,e as g,f as o,g as f,i as d,r as m}from"./chunk-UI7IMFM7.js";import{a}from"./chunk-BR3YZILG.js";function $(n){let t=m("2001-02-03",n).match(/\d+/g)||[],e=v=>t.findIndex(_=>Number(_)===v),h=e(2001),c=e(2),u=e(3);return h===0?"YMD":c>=0&&u>=0&&c<u?"MDY":"DMY"}function p(n,i,t){if(n<1e3||n>9999||i<1||i>12||t<1||t>31)return null;let e=new Date(n,i-1,t);return e.getFullYear()!==n||e.getMonth()!==i-1||e.getDate()!==t?null:`${n}-${String(i).padStart(2,"0")}-${String(t).padStart(2,"0")}`}function b(n,i){let t=n.trim(),e;if(e=t.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/))return p(+e[1],+e[2],+e[3]);if(e=t.match(/^(\d{4})$/))return p(+e[1],1,1);if(e=t.match(/^(\d{1,2})[./](\d{4})$/))return p(+e[2],+e[1],1);if(e=t.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/))return p(+e[3],+e[2],+e[1]);if(e=t.match(/^(\d{1,2})[/-](\d{1,2})[/-](\d{4})$/)){let h=+e[1],c=+e[2],u=+e[3];return $(i)==="MDY"?p(u,h,c):p(u,c,h)}return null}function x(n,i){if(i)switch(n){case"date":return i.split("T")[0];case"time":return i.length===5?`${i}:00`:i;case"datetime":{let[t,e="00:00:00"]=i.split("T");return`${t} ${e.length===5?`${e}:00`:e}`}}}function k(n,i){if(typeof i!="string"||!i)return"";switch(n){case"date":return i.slice(0,10);case"time":return i.slice(0,5);case"datetime":{let[t,e="00:00:00"]=i.split(" ");return`${t}T${e.length===5?`${e}:00`:e}`}}}var r=class extends g{constructor(){super(...arguments);this.kind="date";this.label="";this.value="";this.clearable=!1;this.disabled=!1;this.required=!1;this.lang="en";this._typing=!1;this._typed="";this._typedInvalid=!1}_startTyping(){this._typed=this.value,this._typedInvalid=!1,this._typing=!0,this.updateComplete.then(()=>this.shadowRoot?.querySelector("input.typed")?.focus())}_commitTyped(){if(!this._typed.trim()){this._typing=!1;return}let t=b(this._typed,this.lang);if(!t){this._typedInvalid=!0;return}this._typing=!1,this._typedInvalid=!1,this._emit(t)}_onTypedKey(t){t.key==="Enter"?(t.preventDefault(),this._commitTyped()):t.key==="Escape"&&(t.preventDefault(),this._typing=!1,this._typedInvalid=!1)}_selector(){switch(this.kind){case"date":return{date:{}};case"time":return{time:{no_second:!0}};case"datetime":return{datetime:{}}}}_onSelectorChange(t){t.stopPropagation(),this._emit(k(this.kind,t.detail?.value))}_clear(){this._emit("")}_emit(t){t!==this.value&&(this.value=t,this.dispatchEvent(new CustomEvent("value-changed",{bubbles:!0,composed:!0,detail:{value:t}})))}render(){return s`
|
||||
<div class="field">
|
||||
${this.label?s`<span class="label">${this.label}${this.required?s`<span class="req">*</span>`:l}</span>`:l}
|
||||
<div class="row">
|
||||
${this._typing?s`<input class="typed" type="text" inputmode="numeric" autocomplete="off"
|
||||
.value=${this._typed}
|
||||
placeholder=${m("1978-03-15",this.lang)}
|
||||
aria-invalid=${this._typedInvalid?"true":"false"}
|
||||
@input=${t=>{this._typed=t.target.value,this._typedInvalid=!1}}
|
||||
@keydown=${this._onTypedKey}
|
||||
@blur=${this._commitTyped} />`:s`<ha-selector
|
||||
.hass=${this.hass}
|
||||
.selector=${this._selector()}
|
||||
.value=${x(this.kind,this.value)}
|
||||
.required=${this.required}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._onSelectorChange}
|
||||
></ha-selector>`}
|
||||
${this.kind==="date"&&!this.disabled&&!this._typing?s`<button type="button" class="type-toggle" title=${d("date_type_toggle",this.lang)} aria-label=${d("date_type_toggle",this.lang)} @click=${this._startTyping}>
|
||||
<ha-icon icon="mdi:keyboard-outline"></ha-icon>
|
||||
</button>`:l}
|
||||
${this.clearable&&this.value&&!this.disabled&&!this._typing?s`<button type="button" class="clear" title=${d("clear",this.lang)} aria-label=${d("clear",this.lang)} @click=${this._clear}>
|
||||
<ha-icon icon="mdi:close"></ha-icon>
|
||||
</button>`:l}
|
||||
</div>
|
||||
${this._typedInvalid?s`<span class="helper invalid">${d("date_type_invalid",this.lang)}</span>`:this.helper?s`<span class="helper">${this.helper}</span>`:l}
|
||||
</div>
|
||||
`}};r.styles=y`
|
||||
:host { display: block; }
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.label {
|
||||
font-size: 12px;
|
||||
color: var(--secondary-text-color, #888);
|
||||
font-weight: 500;
|
||||
}
|
||||
.req { color: var(--error-color, #f44336); margin-left: 2px; }
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
ha-selector {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.clear, .type-toggle {
|
||||
flex: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
color: var(--secondary-text-color);
|
||||
cursor: pointer;
|
||||
--mdc-icon-size: 20px;
|
||||
}
|
||||
.clear:hover, .type-toggle:hover { background: rgba(var(--rgb-primary-text-color, 0, 0, 0), 0.08); }
|
||||
.clear:focus-visible, .type-toggle:focus-visible { outline: 2px solid var(--primary-color); }
|
||||
.helper {
|
||||
font-size: 11px;
|
||||
color: var(--secondary-text-color);
|
||||
font-style: italic;
|
||||
}
|
||||
.helper.invalid { color: var(--error-color, #f44336); font-style: normal; }
|
||||
input.typed {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
padding: 0 12px;
|
||||
border: 1px solid var(--divider-color, #ccc);
|
||||
border-radius: 4px;
|
||||
background: var(--card-background-color, #fff);
|
||||
color: var(--primary-text-color);
|
||||
font: inherit;
|
||||
}
|
||||
input.typed[aria-invalid="true"] { border-color: var(--error-color, #f44336); }
|
||||
input.typed:focus { outline: 2px solid var(--primary-color); outline-offset: -1px; }
|
||||
`,a([o({attribute:!1})],r.prototype,"hass",2),a([o()],r.prototype,"kind",2),a([o()],r.prototype,"label",2),a([o()],r.prototype,"value",2),a([o()],r.prototype,"helper",2),a([o({type:Boolean})],r.prototype,"clearable",2),a([o({type:Boolean})],r.prototype,"disabled",2),a([o({type:Boolean})],r.prototype,"required",2),a([o()],r.prototype,"lang",2),a([f()],r.prototype,"_typing",2),a([f()],r.prototype,"_typed",2),a([f()],r.prototype,"_typedInvalid",2);customElements.get("ms-date-field")||customElements.define("ms-date-field",r);
|
||||
File diff suppressed because one or more lines are too long
+3265
File diff suppressed because one or more lines are too long
+137
@@ -0,0 +1,137 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a as v,b}from"./chunk-MSGNUEIB.js";import{B as p,a as u,b as s,d as c,e as h,f as g,g as o,i,k as _,m}from"./chunk-UI7IMFM7.js";import{a}from"./chunk-BR3YZILG.js";var e=class extends h{constructor(){super(...arguments);this._config={type:""};this._groups={};this._loaded=!1;this._busy=!1;this._error="";this._newName="";this._editingId=null;this._editingName="";this._hasInitiallyLoaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return _(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._hasInitiallyLoaded&&(this._hasInitiallyLoaded=!0,this._load(),m(this._lang).then(()=>this.requestUpdate()))}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/groups"});this._groups=t.groups||{},this._loaded=!0}catch(t){this._error=p(t,this._lang)}}async _addGroup(){if(!this._isAdmin)return;let t=this._newName.trim();if(t){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/create",name:t}),this._newName="",await this._load()}catch(r){this._error=p(r,this._lang)}finally{this._busy=!1}}}_startEdit(t){this._editingId=t,this._editingName=this._groups[t]?.name||""}async _saveEdit(){if(!this._isAdmin||!this._editingId)return;let t=this._editingName.trim();if(t){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/update",group_id:this._editingId,name:t}),this._editingId=null,this._editingName="",await this._load()}catch(r){this._error=p(r,this._lang)}finally{this._busy=!1}}}async _deleteGroup(t,r){if(!this._isAdmin)return;let n=i("group_delete_confirm",this._lang).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)}</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)}</span>
|
||||
<span class="count">${r.length}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${this._error?s`<div class="error">${this._error}</div>`:c}
|
||||
|
||||
${r.length===0?s`<div class="empty">${i("groups_empty",t)}</div>`:s`
|
||||
<div class="group-list">
|
||||
${r.map(n=>{let d=this._groups[n],y=d.task_refs?.length??0,f=this._editingId===n;return s`
|
||||
<div class="group-row">
|
||||
${f?s`
|
||||
<input class="edit-input" type="text"
|
||||
.value=${this._editingName}
|
||||
?disabled=${this._busy}
|
||||
@input=${l=>{this._editingName=l.target.value}}
|
||||
@keydown=${l=>this._onKeyDown(l,this._saveEdit.bind(this))} />
|
||||
<button class="btn small primary"
|
||||
@click=${this._saveEdit}
|
||||
?disabled=${this._busy||!this._editingName.trim()}>
|
||||
${i("save",t)}
|
||||
</button>
|
||||
<button class="btn small"
|
||||
@click=${()=>{this._editingId=null}}>
|
||||
${i("cancel",t)}
|
||||
</button>
|
||||
`:s`
|
||||
<span class="group-name">${d.name||"Unnamed"}</span>
|
||||
<span class="task-count">${y}</span>
|
||||
${this._isAdmin?s`
|
||||
<button class="icon-btn"
|
||||
title="${i("edit",t)}"
|
||||
@click=${()=>this._startEdit(n)}
|
||||
?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:pencil"></ha-icon>
|
||||
</button>
|
||||
<button class="icon-btn danger"
|
||||
title="${i("delete",t)}"
|
||||
@click=${()=>this._deleteGroup(n,d.name||"Unnamed")}
|
||||
?disabled=${this._busy}>
|
||||
<ha-icon icon="mdi:delete"></ha-icon>
|
||||
</button>
|
||||
`:c}
|
||||
`}
|
||||
</div>
|
||||
`})}
|
||||
</div>
|
||||
`}
|
||||
|
||||
${this._isAdmin?s`
|
||||
<div class="add-row">
|
||||
<input type="text"
|
||||
placeholder="${i("group_new_placeholder",t)}"
|
||||
.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)}
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${i("groups_manage_tasks",t)}
|
||||
</button>
|
||||
`:s`
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${i("groups_open_panel",t)}
|
||||
</button>
|
||||
`}
|
||||
</div>
|
||||
</ha-card>
|
||||
`}};e.styles=[b,u`
|
||||
.count {
|
||||
font-size: 12px; color: var(--secondary-text-color);
|
||||
background: var(--secondary-background-color);
|
||||
padding: 2px 8px; border-radius: 999px;
|
||||
}
|
||||
.empty {
|
||||
padding: 16px; text-align: center;
|
||||
color: var(--secondary-text-color); font-style: italic;
|
||||
}
|
||||
.group-list { display: flex; flex-direction: column; gap: 4px; }
|
||||
.group-row {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 6px 8px; border-radius: 6px;
|
||||
background: var(--secondary-background-color, rgba(255,255,255,0.03));
|
||||
}
|
||||
.group-name { flex: 1; font-size: 14px; }
|
||||
.task-count {
|
||||
font-size: 11px; color: var(--secondary-text-color);
|
||||
background: var(--card-background-color, rgba(0,0,0,0.2));
|
||||
padding: 1px 8px; border-radius: 999px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.edit-input {
|
||||
flex: 1; padding: 4px 8px; font-size: 14px;
|
||||
background: var(--card-background-color, #1c1c1c);
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--primary-color); border-radius: 4px;
|
||||
font-family: inherit;
|
||||
}
|
||||
.icon-btn {
|
||||
background: transparent; border: none; cursor: pointer;
|
||||
color: var(--secondary-text-color); padding: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.icon-btn:hover {
|
||||
background: var(--state-icon-color, rgba(255,255,255,0.06));
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.icon-btn.danger:hover { color: var(--error-color); }
|
||||
.icon-btn ha-icon { --mdc-icon-size: 18px; }
|
||||
.add-row {
|
||||
display: flex; gap: 6px;
|
||||
padding-top: 8px; border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
.add-row input {
|
||||
flex: 1; padding: 6px 8px; font-size: 13px;
|
||||
background: var(--secondary-background-color, #2c2c2c);
|
||||
color: var(--primary-text-color);
|
||||
border: 1px solid var(--divider-color); border-radius: 6px;
|
||||
font-family: inherit;
|
||||
}
|
||||
/* Card-specific overrides on the shared .btn */
|
||||
.btn.small { padding: 4px 8px; font-size: 12px; }
|
||||
.btn ha-icon { --mdc-icon-size: 16px; }
|
||||
`],a([g({attribute:!1})],e.prototype,"hass",2),a([o()],e.prototype,"_config",2),a([o()],e.prototype,"_groups",2),a([o()],e.prototype,"_loaded",2),a([o()],e.prototype,"_busy",2),a([o()],e.prototype,"_error",2),a([o()],e.prototype,"_newName",2),a([o()],e.prototype,"_editingId",2),a([o()],e.prototype,"_editingName",2);customElements.get("maintenance-groups-section-card")||customElements.define("maintenance-groups-section-card",e);v({type:"maintenance-groups-section-card",name:"Maintenance Supporter \u2014 Groups",description:"Inline group CRUD",preview:!1});export{e as MaintenanceGroupsSectionCard};
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*! maintenance_supporter frontend 2.90.0 */
|
||||
import{a as g,b as y}from"./chunk-MSGNUEIB.js";import"./chunk-R3EVJQWN.js";import{B as o,a as h,b as r,d as c,e as _,f as v,g as n,i as e,j as f,k as m,m as b}from"./chunk-UI7IMFM7.js";import{a as i}from"./chunk-BR3YZILG.js";var s=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 m(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),f(this,t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load(),b(this._lang).then(()=>this.requestUpdate()))}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/state"});this._state=t,this._localStart=t.start||"",this._localEnd=t.end||"",this._localBuffer=t.buffer_days??7,this._dirty=!1}catch(t){this._error=o(t,this._lang)}}async _toggleEnabled(t){this._busy=!0,this._error="";try{let a=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/update",enabled:t});this._state=a}catch(a){this._error=o(a,this._lang)}finally{this._busy=!1}}async _save(){if(this._isAdmin){this._busy=!0,this._error="";try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/update",start:this._localStart||null,end:this._localEnd||null,buffer_days:this._localBuffer});this._state=t,this._dirty=!1}catch(t){this._error=o(t,this._lang)}finally{this._busy=!1}}}async _endNow(){if(this._isAdmin&&window.confirm(e("vacation_end_now_confirm",this._lang))){this._busy=!0;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/end_now"});this._state=t,this._localStart=t.start||"",this._localEnd=t.end||""}catch(t){this._error=o(t,this._lang)}finally{this._busy=!1}}}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_vacation"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,a=this._state;if(!a)return r`<ha-card><div class="loading">${e("loading",t)}</div></ha-card>`;let p=a.is_active===!0,d=a.enabled===!0,u=a.exempt_task_ids?.length??0,$=p?e("vacation_status_active",t):d?e("vacation_status_scheduled",t):e("vacation_status_inactive",t),x=p?"active":d?"scheduled":"inactive";return r`
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<span class="emoji">🏖️</span>
|
||||
<span>${this._config.title||e("vacation_mode",t)}</span>
|
||||
</div>
|
||||
<span class="status-pill ${x}">${$}</span>
|
||||
</div>
|
||||
|
||||
${this._error?r`<div class="error">${this._error}</div>`:c}
|
||||
|
||||
${this._isAdmin?r`
|
||||
<div class="row toggle-row">
|
||||
<label>${e("enable",t)}</label>
|
||||
<ha-switch
|
||||
.checked=${d}
|
||||
.disabled=${this._busy}
|
||||
@change=${l=>this._toggleEnabled(l.target.checked)}
|
||||
></ha-switch>
|
||||
</div>
|
||||
|
||||
<div class="dates-row">
|
||||
<div class="date-field">
|
||||
<label>${e("vacation_start",t)}</label>
|
||||
<ms-date-field
|
||||
kind="date"
|
||||
clearable
|
||||
.hass=${this.hass}
|
||||
.lang=${t}
|
||||
.value=${this._localStart}
|
||||
.disabled=${this._busy}
|
||||
@value-changed=${l=>{this._localStart=l.detail.value,this._dirty=!0}}
|
||||
></ms-date-field>
|
||||
</div>
|
||||
<div class="date-field">
|
||||
<label>${e("vacation_end",t)}</label>
|
||||
<ms-date-field
|
||||
kind="date"
|
||||
clearable
|
||||
.hass=${this.hass}
|
||||
.lang=${t}
|
||||
.value=${this._localEnd}
|
||||
.disabled=${this._busy}
|
||||
@value-changed=${l=>{this._localEnd=l.detail.value,this._dirty=!0}}
|
||||
></ms-date-field>
|
||||
</div>
|
||||
<div class="date-field buffer">
|
||||
<label>${e("vacation_buffer",t)}</label>
|
||||
<input type="number" min="0" max="14"
|
||||
.value=${String(this._localBuffer)}
|
||||
?disabled=${this._busy}
|
||||
@input=${l=>{this._localBuffer=parseInt(l.target.value,10)||0,this._dirty=!0}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button class="btn ${this._dirty?"primary":"muted"}"
|
||||
@click=${this._save}
|
||||
?disabled=${this._busy||!this._dirty}>
|
||||
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
|
||||
${this._dirty?e("save",t):e("saved",t)}
|
||||
</button>
|
||||
${p?r`<button class="btn"
|
||||
@click=${this._endNow}
|
||||
?disabled=${this._busy}>
|
||||
${e("vacation_end_now",t)}
|
||||
</button>`:c}
|
||||
${u>0?r`<button class="btn link"
|
||||
@click=${this._onDeepLink}>
|
||||
${u} ${e("vacation_exempt_count",t)}…
|
||||
</button>`:r`<button class="btn link"
|
||||
@click=${this._onDeepLink}>
|
||||
${e("vacation_advanced",t)}
|
||||
</button>`}
|
||||
</div>
|
||||
`:r`
|
||||
<div class="readonly">
|
||||
${d&&a.start&&a.end?r`<div>${a.start} → ${a.end}</div>`:c}
|
||||
<button class="btn link" @click=${this._onDeepLink}>
|
||||
${e("vacation_open_panel",t)}
|
||||
</button>
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
</ha-card>
|
||||
`}};s.styles=[y,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})],s.prototype,"hass",2),i([n()],s.prototype,"_config",2),i([n()],s.prototype,"_state",2),i([n()],s.prototype,"_busy",2),i([n()],s.prototype,"_error",2),i([n()],s.prototype,"_localStart",2),i([n()],s.prototype,"_localEnd",2),i([n()],s.prototype,"_localBuffer",2),i([n()],s.prototype,"_dirty",2);customElements.get("maintenance-vacation-section-card")||customElements.define("maintenance-vacation-section-card",s);g({type:"maintenance-vacation-section-card",name:"Maintenance Supporter \u2014 Vacation",description:"Inline vacation mode toggle + dates",preview:!1});export{s as MaintenanceVacationSectionCard};
|
||||
+3
-3
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user