200 files

This commit is contained in:
Home Assistant Version Control
2026-09-11 12:11:18 +00:00
parent ff4156dc89
commit 8769f3b12b
201 changed files with 5190 additions and 24141 deletions
@@ -186,18 +186,25 @@ describe("task-detail renderer", () => {
toggleArchive: () => calls.push("archive"),
}));
const items = [...host.querySelectorAll(".popup-menu-item")];
// edit, qr, worksheet, duplicate, reset, postpone, snooze, archive, delete
expect(items.length).to.equal(9);
(items[5] as HTMLElement).click(); // postpone
(items[6] as HTMLElement).click(); // snooze
// edit, qr, worksheet, duplicate, move (#23), reset, postpone, snooze, archive, delete
expect(items.length).to.equal(10);
(items[6] as HTMLElement).click(); // postpone
(items[7] as HTMLElement).click(); // snooze
(items[2] as HTMLElement).click(); // work sheet (v2.21)
(items[7] as HTMLElement).click(); // archive (demoted from the header)
(items[8] as HTMLElement).click(); // delete (danger)
(items[8] as HTMLElement).click(); // archive (demoted from the header)
(items[9] as HTMLElement).click(); // delete (danger)
expect(calls).to.deep.equal([
"close", "postpone", "close", "snooze", "close", "worksheet", "close", "archive", "close", "delete",
]);
});
it("shows a bell-off badge for a muted task (#173), and none otherwise", () => {
const muted = mount(task({ notify_enabled: false }), ctx());
expect(muted.querySelector(".muted-badge")).to.exist;
const loud = mount(task(), ctx());
expect(loud.querySelector(".muted-badge")).to.not.exist;
});
it("shows a postponed badge when the task has a due_override, and none otherwise", () => {
const plain = mount(task(), ctx());
expect(plain.querySelector(".postponed-badge")).to.be.null;
@@ -16,6 +16,8 @@ export interface PromptOptions extends ConfirmOptions {
inputLabel?: string;
inputType?: string; // "text" | "date" etc.
inputValue?: string;
/** Render a <select> instead of a text input (task/move picks an object). */
options?: { value: string; label: string }[];
}
export interface PromptResult {
@@ -33,6 +35,7 @@ export class MaintenanceConfirmDialog extends LitElement {
@state() private _danger = false;
@state() private _inputLabel = "";
@state() private _inputType = "";
@state() private _options: { value: string; label: string }[] | null = null;
@state() private _inputValue = "";
private _resolve: ((value: boolean) => void) | null = null;
@@ -45,6 +48,7 @@ export class MaintenanceConfirmDialog extends LitElement {
this._danger = opts.danger || false;
this._inputLabel = "";
this._inputType = "";
this._options = null;
this._inputValue = "";
this._open = true;
return new Promise<boolean>((resolve) => {
@@ -60,6 +64,7 @@ export class MaintenanceConfirmDialog extends LitElement {
this._danger = opts.danger || false;
this._inputLabel = opts.inputLabel || "";
this._inputType = opts.inputType || "text";
this._options = opts.options && opts.options.length ? opts.options : null;
this._inputValue = opts.inputValue || "";
this._open = true;
return new Promise<PromptResult>((resolve) => {
@@ -104,10 +109,15 @@ export class MaintenanceConfirmDialog extends LitElement {
the pause/replace prompts; same fix as complete-dialog). -->
<label class="field">
<span class="field-label">${this._inputLabel}</span>
<input class="field-input"
type="${this._inputType || "text"}"
.value=${this._inputValue}
@input=${(e: Event) => (this._inputValue = (e.target as HTMLInputElement).value)} />
${this._options
? html`<select class="field-input field-select"
@change=${(e: Event) => (this._inputValue = (e.target as HTMLSelectElement).value)}>
${this._options.map((o) => html`<option value=${o.value} ?selected=${o.value === this._inputValue}>${o.label}</option>`)}
</select>`
: html`<input class="field-input"
type="${this._inputType || "text"}"
.value=${this._inputValue}
@input=${(e: Event) => (this._inputValue = (e.target as HTMLInputElement).value)} />`}
</label>
` : nothing}
</div>
@@ -982,7 +982,9 @@ export class MaintenanceSettingsView extends LitElement {
<div class="setting-hint">${t("settings_notify_event_only_hint", L)}</div>
<label class="setting-row setting-row-block">
<span class="setting-label">${t("settings_notify_extra_data", L)}</span>
<textarea class="import-area notify-extra" .value=${live(n.extra_data || "")} maxlength="2000" spellcheck="false"
<!-- No live(): the view re-renders on every hass update and live()
would snap the DOM back to the stored value mid-typing (#176). -->
<textarea class="import-area notify-extra" .value=${n.extra_data || ""} maxlength="2000" spellcheck="false"
placeholder=${'{"category": "maintenance", "critical": {{ priority == "high" }}, "navigate_to": "{{ url }}"}'}
@change=${(e: Event) => this._updateSetting("notify_extra_data", (e.target as HTMLTextAreaElement).value)}
></textarea>
@@ -251,6 +251,7 @@ export class MaintenanceTaskDialog extends LitElement {
@state() private _nfcTagId = "";
@state() private _requireTagScan = false;
@state() private _allowSkip = true;
@state() private _notifyEnabled = true;
// v2.20 (#83): unit for `reading`-type tasks ("kWh", "m³", ...)
@state() private _readingUnit = "";
// #161 phase 2: named reading slots — several values per completion.
@@ -412,6 +413,7 @@ export class MaintenanceTaskDialog extends LitElement {
this._nfcTagId = task.nfc_tag_id || "";
this._requireTagScan = !!task.require_tag_scan;
this._allowSkip = task.allow_skip !== false;
this._notifyEnabled = task.notify_enabled !== false;
this._readingUnit = task.reading_unit || "";
this._readings = (task.readings || []).map((s) => ({ ...s }));
// Whole link, entry_id included — hydrating only part_id would turn every
@@ -1318,6 +1320,7 @@ export class MaintenanceTaskDialog extends LitElement {
data.nfc_tag_id = this._nfcTagId || null;
data.require_tag_scan = this._requireTagScan;
data.allow_skip = this._allowSkip;
data.notify_enabled = this._notifyEnabled;
data.reading_unit = this._readingUnit.trim() || null;
// #161 phase 2: always sent — [] clears the slots (single-value task).
// Sent as hydrated even when the editor is hidden (type != reading), so
@@ -2953,6 +2956,15 @@ export class MaintenanceTaskDialog extends LitElement {
<span>${t("disallow_skip", L)}</span>
</label>
${!this._allowSkip ? html`<div class="field-help">${t("disallow_skip_help", L)}</div>` : nothing}
<label class="req-option">
<input
type="checkbox"
.checked=${!this._notifyEnabled}
@change=${(e: Event) => (this._notifyEnabled = !(e.target as HTMLInputElement).checked)}
/>
<span>${t("no_notifications", L)}</span>
</label>
${!this._notifyEnabled ? html`<div class="field-help">${t("no_notifications_help", L)}</div>` : nothing}
<label class="toggle-row">
<input
type="checkbox"
@@ -13,7 +13,7 @@
import { LitElement, html, css, nothing } from "lit";
import { property, state } from "lit/decorators.js";
import { t, ensureLocale, langOf } from "../styles";
import { t, ensureLocale, langOf, syncLocaleFromHass } from "../styles";
import { registerCustomCard } from "../helpers/register-card";
import { describeWsError } from "../ws-errors";
import { sectionCardSharedStyles } from "./section-card-shared-styles";
@@ -66,6 +66,8 @@ export class MaintenanceVacationSectionCard extends LitElement {
updated(changedProps: Map<string, unknown>): void {
super.updated(changedProps);
// #163 tripwire: the date field's typed-entry placeholder formats a date.
syncLocaleFromHass(this, changedProps);
if (changedProps.has("hass") && this.hass && !this._loaded) {
this._loaded = true;
void this._load();
@@ -16,6 +16,11 @@
"edit": "Upravit",
"duplicate": "Duplikovat",
"task_duplicated": "Úkol duplikován",
"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.",
"move_task_title": "Přesunout úkol",
"move_task": "Přesunout do jiného objektu…",
"object_duplicated": "Objekt duplikován",
"delete": "Smazat",
"add_task": "+ Přidat úkol",
@@ -289,6 +294,8 @@
"seasonal_override_range": "Faktor musí být mezi 0.1 a 5.0",
"clear_all": "Vymazat vše",
"clear": "Vymazat",
"date_type_toggle": "Zadat datum",
"date_type_invalid": "Neplatné datum — zkuste 1978-03-15, rok jako 1978 nebo svůj formát data",
"seasonal_chart_title": "Sezónní faktory",
"seasonal_learned": "Naučené",
"seasonal_manual": "Manuální",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Důkaz přítomnosti: „Hotovo“ je všude blokováno, dokud nenaskenujete NFC štítek nebo QR kód na zařízení. Automatizace mohou službě complete předat 'via_tag_scan'.",
"disallow_skip": "Nepovolit přeskočení",
"disallow_skip_help": "Akce Přeskočit zmizí ze všech ploch a server odmítne přeskočení i z automatizací a hlasu.",
"no_notifications": "Bez oznámení pro tento úkol",
"no_notifications_help": "Bez připomínek pro tento úkol — žádná oznámení o stavu, opakování, předstihové připomínky ani souhrny. Zůstává vidět na přehledu a ve svých entitách; týdenní přehled ho stále počítá.",
"require_tag_scan_hint": "Tento úkol lze dokončit pouze naskenováním jeho NFC štítku nebo QR kódu na zařízení — uložení zde bude odmítnuto."
}
@@ -18,6 +18,11 @@
"edit": "Rediger",
"duplicate": "Dupliker",
"task_duplicated": "Opgave duplikeret",
"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.",
"move_task_title": "Flyt opgave",
"move_task": "Flyt til et andet objekt…",
"object_duplicated": "Objekt duplikeret",
"delete": "Slet",
"add_task": "+ Tilføj opgave",
@@ -291,6 +296,8 @@
"seasonal_override_range": "Faktor skal være mellem 0.1 og 5.0",
"clear_all": "Ryd alle",
"clear": "Ryd",
"date_type_toggle": "Indtast datoen",
"date_type_invalid": "Ugyldig dato — prøv 1978-03-15, et år som 1978 eller dit eget datoformat",
"seasonal_chart_title": "Sæsonfaktorer",
"seasonal_learned": "Lært",
"seasonal_manual": "Manuel",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Tilstedeværelsesbevis: „Udført“ er blokeret overalt, indtil NFC-tagget eller QR-koden på selve tingen er scannet. Automatiseringer kan give 'via_tag_scan' til complete-tjenesten.",
"disallow_skip": "Tillad ikke at springe over",
"disallow_skip_help": "Handlingen Spring over forsvinder fra alle flader, og serveren afviser også spring fra automatiseringer og stemme.",
"no_notifications": "Ingen notifikationer for denne opgave",
"no_notifications_help": "Ingen påmindelser for denne opgave — ingen statusnotifikationer, gentagelser, forudpåmindelser eller bundter. Den vises stadig på dashboardet og i sine entiteter; ugeoversigten tæller den stadig med.",
"require_tag_scan_hint": "Denne opgave udføres kun ved at scanne dens NFC-tag eller QR-kode på selve tingen — at gemme her vil blive afvist."
}
@@ -18,6 +18,11 @@
"edit": "Bearbeiten",
"duplicate": "Duplizieren",
"task_duplicated": "Aufgabe dupliziert",
"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.",
"move_task_title": "Aufgabe verschieben",
"move_task": "In anderes Objekt verschieben…",
"object_duplicated": "Objekt dupliziert",
"delete": "Löschen",
"add_task": "+ Aufgabe",
@@ -291,6 +296,8 @@
"seasonal_override_range": "Faktor muss zwischen 0.1 und 5.0 liegen",
"clear_all": "Alle zurücksetzen",
"clear": "Leeren",
"date_type_toggle": "Datum eintippen",
"date_type_invalid": "Kein gültiges Datum — versuche 1978-03-15, ein Jahr wie 1978 oder dein Datumsformat",
"seasonal_chart_title": "Saisonale Faktoren",
"seasonal_learned": "Gelernt",
"seasonal_manual": "Manuell",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Anwesenheitsnachweis: „Erledigt“ ist überall blockiert, bis das NFC-Tag oder der QR-Code am Gerät gescannt wurde. Automationen können 'via_tag_scan' an den complete-Dienst übergeben.",
"disallow_skip": "Überspringen nicht erlauben",
"disallow_skip_help": "Die Aktion Überspringen verschwindet von allen Oberflächen; auch Automationen und Sprachbefehle werden abgewiesen.",
"no_notifications": "Keine Benachrichtigungen für diese Aufgabe",
"no_notifications_help": "Keine Erinnerungen für diese Aufgabe — keine Status-Benachrichtigungen, Wiederholungen, Vorlauf-Erinnerungen oder Bündel. Sie erscheint weiterhin im Dashboard und in ihren Entitäten; der Wochen-Digest zählt sie weiterhin mit.",
"require_tag_scan_hint": "Diese Aufgabe kann nur per Scan des NFC-Tags oder QR-Codes am Gerät erledigt werden — Speichern hier wird abgelehnt."
}
@@ -18,6 +18,11 @@
"edit": "Edit",
"duplicate": "Duplicate",
"task_duplicated": "Task duplicated",
"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.",
"move_task_title": "Move task",
"move_task": "Move to another object…",
"object_duplicated": "Object duplicated",
"delete": "Delete",
"add_task": "+ Add Task",
@@ -291,6 +296,8 @@
"seasonal_override_range": "Factor must be between 0.1 and 5.0",
"clear_all": "Clear all",
"clear": "Clear",
"date_type_toggle": "Type the date",
"date_type_invalid": "Not a valid date — try 1978-03-15, a year like 1978, or your own date format",
"seasonal_chart_title": "Seasonal Factors",
"seasonal_learned": "Learned",
"seasonal_manual": "Manual",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Proof of presence: Done is blocked on every surface until the NFC tag or QR code on the thing itself is scanned. Automations can pass 'via_tag_scan' to the complete service.",
"disallow_skip": "Don't allow skipping",
"disallow_skip_help": "The Skip action disappears from every surface, and the server refuses a skip from automations and voice too.",
"no_notifications": "No notifications for this task",
"no_notifications_help": "No reminders for this task — no status notifications, repeats, lead-time reminders or bundles. It still shows on the dashboard and in its entities; the weekly digest still counts it.",
"require_tag_scan_hint": "This task completes only by scanning its NFC tag or QR code on the thing itself — saving here will be refused."
}
@@ -16,6 +16,11 @@
"edit": "Editar",
"duplicate": "Duplicar",
"task_duplicated": "Tarea duplicada",
"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.",
"move_task_title": "Mover tarea",
"move_task": "Mover a otro objeto…",
"object_duplicated": "Objeto duplicado",
"delete": "Eliminar",
"add_task": "+ Tarea",
@@ -289,6 +294,8 @@
"seasonal_override_range": "El factor debe estar entre 0.1 y 5.0",
"clear_all": "Borrar todo",
"clear": "Borrar",
"date_type_toggle": "Escribir la fecha",
"date_type_invalid": "Fecha no válida — prueba 1978-03-15, un año como 1978 o tu formato de fecha",
"seasonal_chart_title": "Factores estacionales",
"seasonal_learned": "Aprendido",
"seasonal_manual": "Manual",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Prueba de presencia: «Hecho» queda bloqueado en todas partes hasta escanear la etiqueta NFC o el código QR del propio objeto. Las automatizaciones pueden pasar 'via_tag_scan' al servicio complete.",
"disallow_skip": "No permitir omitir",
"disallow_skip_help": "La acción Omitir desaparece de todas las superficies y el servidor también rechaza omisiones desde automatizaciones y voz.",
"no_notifications": "Sin notificaciones para esta tarea",
"no_notifications_help": "Sin recordatorios para esta tarea — ni notificaciones de estado, ni repeticiones, ni avisos anticipados, ni agrupaciones. Sigue apareciendo en el panel y en sus entidades; el resumen semanal la sigue contando.",
"require_tag_scan_hint": "Esta tarea solo se completa escaneando su etiqueta NFC o código QR en el propio objeto; guardar aquí será rechazado."
}
@@ -18,6 +18,11 @@
"edit": "Muokkaa",
"duplicate": "Monista",
"task_duplicated": "Tehtävä monistettu",
"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.",
"move_task_title": "Siirrä tehtävä",
"move_task": "Siirrä toiseen kohteeseen…",
"object_duplicated": "Kohde monistettu",
"delete": "Poista",
"add_task": "+ Lisää tehtävä",
@@ -291,6 +296,8 @@
"seasonal_override_range": "Kertoimen on oltava välillä 0,1–5,0",
"clear_all": "Tyhjennä kaikki",
"clear": "Tyhjennä",
"date_type_toggle": "Kirjoita päivämäärä",
"date_type_invalid": "Virheellinen päivämäärä — kokeile 1978-03-15, vuotta kuten 1978 tai omaa päivämäärämuotoasi",
"seasonal_chart_title": "Kausikertoimet",
"seasonal_learned": "Opittu",
"seasonal_manual": "Manuaalinen",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Läsnäolotodistus: ”Valmis” on estetty kaikkialla, kunnes laitteen NFC-tunniste tai QR-koodi on skannattu. Automaatiot voivat välittää 'via_tag_scan' complete-palvelulle.",
"disallow_skip": "Estä ohittaminen",
"disallow_skip_help": "Ohita-toiminto katoaa kaikista näkymistä, ja palvelin hylkää ohituksen myös automaatioista ja puheesta.",
"no_notifications": "Ei ilmoituksia tästä tehtävästä",
"no_notifications_help": "Ei muistutuksia tästä tehtävästä — ei tilailmoituksia, toistoja, ennakkomuistutuksia eikä niputuksia. Se näkyy yhä kojelaudalla ja entiteeteissään; viikkokooste laskee sen edelleen mukaan.",
"require_tag_scan_hint": "Tämä tehtävä valmistuu vain skannaamalla sen NFC-tunniste tai QR-koodi itse laitteesta — tallennus tässä estetään."
}
@@ -16,6 +16,11 @@
"edit": "Modifier",
"duplicate": "Dupliquer",
"task_duplicated": "Tâche dupliquée",
"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.",
"move_task_title": "Déplacer la tâche",
"move_task": "Déplacer vers un autre objet…",
"object_duplicated": "Objet dupliqué",
"delete": "Supprimer",
"add_task": "+ Tâche",
@@ -289,6 +294,8 @@
"seasonal_override_range": "Le facteur doit être entre 0.1 et 5.0",
"clear_all": "Tout effacer",
"clear": "Effacer",
"date_type_toggle": "Saisir la date",
"date_type_invalid": "Date invalide — essayez 1978-03-15, une année comme 1978 ou votre format de date",
"seasonal_chart_title": "Facteurs saisonniers",
"seasonal_learned": "Appris",
"seasonal_manual": "Manuel",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Preuve de présence : « Terminé » est bloqué partout tant que le tag NFC ou le QR code sur l'objet n'a pas été scanné. Les automatisations peuvent passer 'via_tag_scan' au service complete.",
"disallow_skip": "Ne pas autoriser à ignorer",
"disallow_skip_help": "L'action Ignorer disparaît de toutes les surfaces et le serveur refuse aussi un saut via les automatisations et la voix.",
"no_notifications": "Aucune notification pour cette tâche",
"no_notifications_help": "Aucun rappel pour cette tâche — ni notifications de statut, ni répétitions, ni rappels anticipés, ni regroupements. Elle reste visible sur le tableau de bord et dans ses entités ; le résumé hebdomadaire la compte toujours.",
"require_tag_scan_hint": "Cette tâche ne se termine qu'en scannant son tag NFC ou son QR code sur l'objet — l'enregistrement ici sera refusé."
}
@@ -18,6 +18,11 @@
"edit": "संपादित करें",
"duplicate": "डुप्लिकेट करें",
"task_duplicated": "कार्य डुप्लिकेट किया गया",
"task_moved": "कार्य ले जाया गया",
"move_task_target": "लक्ष्य ऑब्जेक्ट",
"move_task_message": "वह ऑब्जेक्ट चुनें जिससे यह कार्य जुड़ा होना चाहिए। इतिहास, रीडिंग और ट्रिगर स्थिति साथ जाएँगे; इसे नया संदर्भ नंबर मिलेगा और इसकी एंटिटी नए ऑब्जेक्ट के अंतर्गत फिर से बनेंगी। जुड़े दस्तावेज़ वर्तमान ऑब्जेक्ट के पास रहेंगे।",
"move_task_title": "कार्य ले जाएँ",
"move_task": "दूसरे ऑब्जेक्ट में ले जाएँ…",
"object_duplicated": "ऑब्जेक्ट डुप्लिकेट किया गया",
"delete": "हटाएँ",
"add_task": "+ कार्य जोड़ें",
@@ -291,6 +296,8 @@
"seasonal_override_range": "कारक 0.1 और 5.0 के बीच होना चाहिए",
"clear_all": "सभी साफ़ करें",
"clear": "साफ़ करें",
"date_type_toggle": "तारीख टाइप करें",
"date_type_invalid": "मान्य तारीख नहीं — 1978-03-15, 1978 जैसा वर्ष या अपना तारीख प्रारूप आज़माएँ",
"seasonal_chart_title": "मौसमी कारक",
"seasonal_learned": "सीखा गया",
"seasonal_manual": "मैनुअल",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "उपस्थिति प्रमाण: जब तक वस्तु पर लगा NFC टैग या QR कोड स्कैन न हो, हर जगह “पूर्ण” अवरुद्ध रहता है। ऑटोमेशन complete सेवा को 'via_tag_scan' दे सकते हैं।",
"disallow_skip": "छोड़ने की अनुमति न दें",
"disallow_skip_help": "छोड़ें क्रिया सभी सतहों से हट जाती है, और सर्वर ऑटोमेशन व वॉयस से छोड़ने को भी अस्वीकार करता है।",
"no_notifications": "इस कार्य के लिए कोई सूचना नहीं",
"no_notifications_help": "इस कार्य के लिए कोई रिमाइंडर नहीं — न स्थिति सूचनाएँ, न दोहराव, न अग्रिम रिमाइंडर, न बंडल। यह डैशबोर्ड और अपनी एंटिटी में दिखता रहेगा; साप्ताहिक सारांश इसे अब भी गिनेगा।",
"require_tag_scan_hint": "यह कार्य केवल वस्तु पर लगे NFC टैग या QR कोड को स्कैन करके ही पूर्ण होता है — यहाँ सहेजना अस्वीकार होगा।"
}
@@ -18,6 +18,11 @@
"edit": "Szerkesztés",
"duplicate": "Duplikálás",
"task_duplicated": "Feladat duplikálva",
"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.",
"move_task_title": "Feladat áthelyezése",
"move_task": "Áthelyezés másik objektumba…",
"object_duplicated": "Objektum duplikálva",
"delete": "Törlés",
"add_task": "+ Új feladat",
@@ -291,6 +296,8 @@
"seasonal_override_range": "A tényezőnek 0,1 és 5,0 között kell lennie",
"clear_all": "Összes törlése",
"clear": "Törlés",
"date_type_toggle": "Dátum beírása",
"date_type_invalid": "Érvénytelen dátum — próbáld 1978-03-15 formában, egy évszámmal (1978) vagy a saját dátumformátumoddal",
"seasonal_chart_title": "Szezonális tényezők",
"seasonal_learned": "Tanult",
"seasonal_manual": "Kézi",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Jelenlét-igazolás: a „Kész” mindenhol blokkolva van, amíg be nem olvasod az eszközön lévő NFC-címkét vagy QR-kódot. Az automatizálások 'via_tag_scan' értéket adhatnak át a complete szolgáltatásnak.",
"disallow_skip": "Kihagyás tiltása",
"disallow_skip_help": "A Kihagyás művelet minden felületről eltűnik, és a szerver az automatizálásokból és hangból érkező kihagyást is elutasítja.",
"no_notifications": "Nincs értesítés ehhez a feladathoz",
"no_notifications_help": "Nincs emlékeztető ehhez a feladathoz — sem állapotértesítés, sem ismétlés, sem előzetes emlékeztető, sem csoportos üzenet. Továbbra is látszik a műszerfalon és az entitásaiban; a heti összefoglaló továbbra is számolja.",
"require_tag_scan_hint": "Ez a feladat csak az eszközön lévő NFC-címke vagy QR-kód beolvasásával fejezhető be — az itteni mentés el lesz utasítva."
}
@@ -16,6 +16,11 @@
"edit": "Modifica",
"duplicate": "Duplica",
"task_duplicated": "Attività duplicata",
"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.",
"move_task_title": "Sposta attività",
"move_task": "Sposta in un altro oggetto…",
"object_duplicated": "Oggetto duplicato",
"delete": "Elimina",
"add_task": "+ Attività",
@@ -289,6 +294,8 @@
"seasonal_override_range": "Il fattore deve essere tra 0.1 e 5.0",
"clear_all": "Cancella tutto",
"clear": "Cancella",
"date_type_toggle": "Digita la data",
"date_type_invalid": "Data non valida — prova 1978-03-15, un anno come 1978 o il tuo formato di data",
"seasonal_chart_title": "Fattori stagionali",
"seasonal_learned": "Appreso",
"seasonal_manual": "Manuale",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Prova di presenza: «Fatto» è bloccato ovunque finché non viene scansionato il tag NFC o il codice QR sull'oggetto. Le automazioni possono passare 'via_tag_scan' al servizio complete.",
"disallow_skip": "Non consentire di saltare",
"disallow_skip_help": "L'azione Salta scompare da tutte le superfici e il server rifiuta anche i salti da automazioni e voce.",
"no_notifications": "Nessuna notifica per questa attività",
"no_notifications_help": "Nessun promemoria per questa attività — niente notifiche di stato, ripetizioni, promemoria anticipati o raggruppamenti. Resta visibile nella dashboard e nelle sue entità; il riepilogo settimanale la conta ancora.",
"require_tag_scan_hint": "Questa attività si completa solo scansionando il suo tag NFC o codice QR sull'oggetto — il salvataggio qui verrà rifiutato."
}
@@ -18,6 +18,11 @@
"edit": "編集",
"duplicate": "複製",
"task_duplicated": "タスクを複製しました",
"task_moved": "タスクを移動しました",
"move_task_target": "移動先オブジェクト",
"move_task_message": "このタスクを所属させるオブジェクトを選んでください。履歴・検針値・トリガー状態は一緒に移動し、新しい参照番号が付き、エンティティは新しいオブジェクトの下で作り直されます。関連付けた文書は現在のオブジェクトに残ります。",
"move_task_title": "タスクを移動",
"move_task": "別のオブジェクトへ移動…",
"object_duplicated": "オブジェクトを複製しました",
"delete": "削除",
"add_task": "+ タスク追加",
@@ -291,6 +296,8 @@
"seasonal_override_range": "係数は0.1〜5.0の範囲で指定してください",
"clear_all": "すべてクリア",
"clear": "クリア",
"date_type_toggle": "日付を入力",
"date_type_invalid": "日付として無効です — 1978-03-15、1978 のような年、または設定中の日付形式で入力してください",
"seasonal_chart_title": "季節係数",
"seasonal_learned": "学習値",
"seasonal_manual": "手動",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "在席証明:対象物のNFCタグまたはQRコードをスキャンするまで、どの画面でも「完了」はブロックされます。オートメーションはcompleteサービスに 'via_tag_scan' を渡せます。",
"disallow_skip": "スキップを許可しない",
"disallow_skip_help": "スキップ操作はすべての画面から消え、オートメーションや音声からのスキップもサーバーが拒否します。",
"no_notifications": "このタスクは通知しない",
"no_notifications_help": "このタスクのリマインダーを止めます。ステータス通知・繰り返し・事前リマインダー・まとめ通知は送られません。ダッシュボードやエンティティには引き続き表示され、週次ダイジェストにも数えられます。",
"require_tag_scan_hint": "このタスクは対象物のNFCタグまたはQRコードをスキャンしないと完了できません。ここでの保存は拒否されます。"
}
@@ -18,6 +18,11 @@
"edit": "편집",
"duplicate": "복제",
"task_duplicated": "작업이 복제되었습니다",
"task_moved": "작업을 이동했습니다",
"move_task_target": "대상 개체",
"move_task_message": "이 작업이 속할 개체를 선택하세요. 이력, 검침값, 트리거 상태가 함께 이동하며 새 참조 번호를 받고 엔티티는 새 개체 아래에 다시 생성됩니다. 연결된 문서는 현재 개체에 남습니다.",
"move_task_title": "작업 이동",
"move_task": "다른 개체로 이동…",
"object_duplicated": "객체가 복제되었습니다",
"delete": "삭제",
"add_task": "+ 작업 추가",
@@ -291,6 +296,8 @@
"seasonal_override_range": "계수는 0.1에서 5.0 사이여야 합니다",
"clear_all": "모두 지우기",
"clear": "지우기",
"date_type_toggle": "날짜 직접 입력",
"date_type_invalid": "올바른 날짜가 아닙니다 — 1978-03-15, 1978 같은 연도 또는 사용 중인 날짜 형식으로 입력하세요",
"seasonal_chart_title": "계절 계수",
"seasonal_learned": "학습됨",
"seasonal_manual": "수동",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "현장 확인: 기기의 NFC 태그나 QR 코드를 스캔할 때까지 모든 화면에서 '완료'가 차단됩니다. 자동화는 complete 서비스에 'via_tag_scan'을 전달할 수 있습니다.",
"disallow_skip": "건너뛰기 허용 안 함",
"disallow_skip_help": "건너뛰기 동작이 모든 화면에서 사라지며, 서버는 자동화와 음성의 건너뛰기도 거부합니다.",
"no_notifications": "이 작업은 알림 없음",
"no_notifications_help": "이 작업에는 리마인더가 없습니다. 상태 알림, 반복, 사전 알림, 묶음 알림이 모두 꺼집니다. 대시보드와 엔티티에는 계속 표시되며 주간 요약에는 계속 포함됩니다.",
"require_tag_scan_hint": "이 작업은 기기의 NFC 태그나 QR 코드를 스캔해야만 완료됩니다. 여기서 저장하면 거부됩니다."
}
@@ -18,6 +18,11 @@
"edit": "Rediger",
"duplicate": "Dupliser",
"task_duplicated": "Oppgave duplisert",
"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.",
"move_task_title": "Flytt oppgave",
"move_task": "Flytt til et annet objekt…",
"object_duplicated": "Objekt duplisert",
"delete": "Slett",
"add_task": "+ Legg til oppgave",
@@ -291,6 +296,8 @@
"seasonal_override_range": "Faktor må være mellom 0,1 og 5,0",
"clear_all": "Fjern alle",
"clear": "Tøm",
"date_type_toggle": "Skriv inn datoen",
"date_type_invalid": "Ugyldig dato — prøv 1978-03-15, et år som 1978 eller ditt eget datoformat",
"seasonal_chart_title": "Sesongfaktorer",
"seasonal_learned": "Lært",
"seasonal_manual": "Manuell",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Tilstedeværelsesbevis: «Fullført» er blokkert overalt til NFC-taggen eller QR-koden på selve tingen er skannet. Automatiseringer kan sende 'via_tag_scan' til complete-tjenesten.",
"disallow_skip": "Ikke tillat å hoppe over",
"disallow_skip_help": "Handlingen Hopp over forsvinner fra alle flater, og serveren avviser også hopp fra automatiseringer og tale.",
"no_notifications": "Ingen varsler for denne oppgaven",
"no_notifications_help": "Ingen påminnelser for denne oppgaven — ingen statusvarsler, gjentakelser, forhåndspåminnelser eller bunter. Den vises fortsatt på dashbordet og i entitetene sine; ukesoppsummeringen teller den fortsatt med.",
"require_tag_scan_hint": "Denne oppgaven fullføres bare ved å skanne NFC-taggen eller QR-koden på selve tingen — lagring her vil bli avvist."
}
@@ -16,6 +16,11 @@
"edit": "Bewerken",
"duplicate": "Dupliceren",
"task_duplicated": "Taak gedupliceerd",
"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.",
"move_task_title": "Taak verplaatsen",
"move_task": "Naar ander object verplaatsen…",
"object_duplicated": "Object gedupliceerd",
"delete": "Verwijderen",
"add_task": "+ Taak",
@@ -289,6 +294,8 @@
"seasonal_override_range": "Factor moet tussen 0.1 en 5.0 liggen",
"clear_all": "Alles wissen",
"clear": "Wissen",
"date_type_toggle": "Datum typen",
"date_type_invalid": "Geen geldige datum — probeer 1978-03-15, een jaar zoals 1978 of je eigen datumnotatie",
"seasonal_chart_title": "Seizoensfactoren",
"seasonal_learned": "Geleerd",
"seasonal_manual": "Handmatig",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Aanwezigheidsbewijs: „Klaar” is overal geblokkeerd totdat de NFC-tag of QR-code op het apparaat zelf is gescand. Automatiseringen kunnen 'via_tag_scan' aan de complete-service meegeven.",
"disallow_skip": "Overslaan niet toestaan",
"disallow_skip_help": "De actie Overslaan verdwijnt overal, en de server weigert ook een skip via automatiseringen en spraak.",
"no_notifications": "Geen notificaties voor deze taak",
"no_notifications_help": "Geen herinneringen voor deze taak — geen statusnotificaties, herhalingen, vooraankondigingen of bundels. Ze blijft zichtbaar op het dashboard en in haar entiteiten; het weekoverzicht telt haar nog mee.",
"require_tag_scan_hint": "Deze taak wordt alleen afgerond door de NFC-tag of QR-code op het apparaat te scannen — opslaan hier wordt geweigerd."
}
@@ -16,6 +16,11 @@
"edit": "Edytuj",
"duplicate": "Duplikuj",
"task_duplicated": "Zadanie zduplikowane",
"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.",
"move_task_title": "Przenieś zadanie",
"move_task": "Przenieś do innego obiektu…",
"object_duplicated": "Obiekt zduplikowany",
"delete": "Usuń",
"add_task": "+ Dodaj zadanie",
@@ -289,6 +294,8 @@
"seasonal_override_range": "Czynnik musi być między 0.1 a 5.0",
"clear_all": "Wyczyść wszystko",
"clear": "Wyczyść",
"date_type_toggle": "Wpisz datę",
"date_type_invalid": "Nieprawidłowa data — wpisz 1978-03-15, rok jak 1978 albo swój format daty",
"seasonal_chart_title": "Czynniki sezonowe",
"seasonal_learned": "Wyuczone",
"seasonal_manual": "Ręczne",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Dowód obecności: „Gotowe” jest wszędzie zablokowane, dopóki nie zeskanujesz tagu NFC lub kodu QR na urządzeniu. Automatyzacje mogą przekazać 'via_tag_scan' do usługi complete.",
"disallow_skip": "Nie zezwalaj na pomijanie",
"disallow_skip_help": "Akcja Pomiń znika ze wszystkich widoków, a serwer odrzuca pominięcie także z automatyzacji i głosu.",
"no_notifications": "Bez powiadomień dla tego zadania",
"no_notifications_help": "Bez przypomnień dla tego zadania — bez powiadomień o statusie, powtórzeń, wcześniejszych przypomnień i pakietów. Nadal widać je na pulpicie i w jego encjach; tygodniowe podsumowanie wciąż je liczy.",
"require_tag_scan_hint": "To zadanie można ukończyć tylko skanując jego tag NFC lub kod QR na urządzeniu — zapis tutaj zostanie odrzucony."
}
@@ -18,6 +18,11 @@
"edit": "Editar",
"duplicate": "Duplicar",
"task_duplicated": "Tarefa duplicada",
"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.",
"move_task_title": "Mover tarefa",
"move_task": "Mover para outro objeto…",
"object_duplicated": "Objeto duplicado",
"delete": "Excluir",
"add_task": "+ Adicionar tarefa",
@@ -291,6 +296,8 @@
"seasonal_override_range": "O fator deve estar entre 0,1 e 5,0",
"clear_all": "Limpar tudo",
"clear": "Limpar",
"date_type_toggle": "Digitar a data",
"date_type_invalid": "Data inválida — tente 1978-03-15, um ano como 1978 ou seu formato de data",
"seasonal_chart_title": "Fatores sazonais",
"seasonal_learned": "Aprendido",
"seasonal_manual": "Manual",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Prova de presença: “Concluído” fica bloqueado em toda parte até escanear a etiqueta NFC ou o código QR no próprio objeto. Automações podem passar 'via_tag_scan' ao serviço complete.",
"disallow_skip": "Não permitir pular",
"disallow_skip_help": "A ação Pular desaparece de todas as telas e o servidor também recusa pular via automações e voz.",
"no_notifications": "Sem notificações para esta tarefa",
"no_notifications_help": "Sem lembretes para esta tarefa — sem notificações de status, repetições, avisos antecipados ou agrupamentos. Ela continua aparecendo no painel e em suas entidades; o resumo semanal ainda a conta.",
"require_tag_scan_hint": "Esta tarefa só é concluída escaneando sua etiqueta NFC ou código QR no próprio objeto — salvar aqui será recusado."
}
@@ -16,6 +16,11 @@
"edit": "Editar",
"duplicate": "Duplicar",
"task_duplicated": "Tarefa duplicada",
"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.",
"move_task_title": "Mover tarefa",
"move_task": "Mover para outro objeto…",
"object_duplicated": "Objeto duplicado",
"delete": "Eliminar",
"add_task": "+ Tarefa",
@@ -289,6 +294,8 @@
"seasonal_override_range": "O fator deve estar entre 0.1 e 5.0",
"clear_all": "Limpar tudo",
"clear": "Limpar",
"date_type_toggle": "Escrever a data",
"date_type_invalid": "Data inválida — tente 1978-03-15, um ano como 1978 ou o seu formato de data",
"seasonal_chart_title": "Fatores sazonais",
"seasonal_learned": "Aprendido",
"seasonal_manual": "Manual",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Prova de presença: «Concluído» fica bloqueado em todo o lado até ler a etiqueta NFC ou o código QR no próprio objeto. As automações podem passar 'via_tag_scan' ao serviço complete.",
"disallow_skip": "Não permitir ignorar",
"disallow_skip_help": "A ação Ignorar desaparece de todas as superfícies e o servidor também recusa ignorar via automações e voz.",
"no_notifications": "Sem notificações para esta tarefa",
"no_notifications_help": "Sem lembretes para esta tarefa — sem notificações de estado, repetições, avisos antecipados ou agrupamentos. Continua a aparecer no painel e nas suas entidades; o resumo semanal continua a contá-la.",
"require_tag_scan_hint": "Esta tarefa só é concluída lendo a sua etiqueta NFC ou código QR no próprio objeto — guardar aqui será recusado."
}
@@ -16,6 +16,11 @@
"edit": "Изменить",
"duplicate": "Дублировать",
"task_duplicated": "Задача продублирована",
"task_moved": "Задача перемещена",
"move_task_target": "Целевой объект",
"move_task_message": "Выберите объект, к которому должна относиться эта задача. История, показания и состояние триггера переедут вместе с ней; она получит новый номер, а её сущности будут созданы заново под новым объектом. Привязанные документы остаются у текущего объекта.",
"move_task_title": "Переместить задачу",
"move_task": "Переместить в другой объект…",
"object_duplicated": "Объект продублирован",
"delete": "Удалить",
"add_task": "+ Добавить задачу",
@@ -289,6 +294,8 @@
"seasonal_override_range": "Коэффициент должен быть от 0.1 до 5.0",
"clear_all": "Очистить все",
"clear": "Очистить",
"date_type_toggle": "Ввести дату",
"date_type_invalid": "Некорректная дата — попробуйте 1978-03-15, год вроде 1978 или ваш формат даты",
"seasonal_chart_title": "Сезонные факторы",
"seasonal_learned": "Изученные",
"seasonal_manual": "Ручные",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Подтверждение присутствия: «Готово» заблокировано везде, пока не отсканирована NFC-метка или QR-код на самом устройстве. Автоматизации могут передавать 'via_tag_scan' в службу complete.",
"disallow_skip": "Запретить пропуск",
"disallow_skip_help": "Действие «Пропустить» исчезает со всех экранов, а сервер отклоняет пропуск из автоматизаций и голосовых команд.",
"no_notifications": "Без уведомлений для этой задачи",
"no_notifications_help": "Без напоминаний для этой задачи — ни уведомлений о статусе, ни повторов, ни заблаговременных напоминаний, ни объединённых сообщений. Она по-прежнему видна на панели и в своих сущностях; еженедельная сводка её учитывает.",
"require_tag_scan_hint": "Эта задача завершается только сканированием её NFC-метки или QR-кода на самом устройстве — сохранение здесь будет отклонено."
}
@@ -16,6 +16,11 @@
"edit": "Redigera",
"duplicate": "Duplicera",
"task_duplicated": "Uppgift duplicerad",
"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.",
"move_task_title": "Flytta uppgift",
"move_task": "Flytta till ett annat objekt…",
"object_duplicated": "Objekt duplicerat",
"delete": "Ta bort",
"add_task": "+ Lägg till uppgift",
@@ -289,6 +294,8 @@
"seasonal_override_range": "Faktor måste vara mellan 0.1 och 5.0",
"clear_all": "Rensa alla",
"clear": "Rensa",
"date_type_toggle": "Skriv datumet",
"date_type_invalid": "Ogiltigt datum — prova 1978-03-15, ett år som 1978 eller ditt eget datumformat",
"seasonal_chart_title": "Säsongsfaktorer",
"seasonal_learned": "Lärt",
"seasonal_manual": "Manuell",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Närvarobevis: ”Klar” är blockerad överallt tills NFC-taggen eller QR-koden på själva saken har skannats. Automationer kan skicka 'via_tag_scan' till complete-tjänsten.",
"disallow_skip": "Tillåt inte att hoppa över",
"disallow_skip_help": "Åtgärden Hoppa över försvinner från alla ytor och servern nekar även hopp från automationer och röst.",
"no_notifications": "Inga aviseringar för den här uppgiften",
"no_notifications_help": "Inga påminnelser för den här uppgiften — inga statusaviseringar, upprepningar, förhandspåminnelser eller buntar. Den syns fortfarande på instrumentpanelen och i sina entiteter; veckosammanfattningen räknar den fortfarande.",
"require_tag_scan_hint": "Den här uppgiften slutförs endast genom att skanna dess NFC-tagg eller QR-kod på själva saken — att spara här kommer att nekas."
}
@@ -18,6 +18,11 @@
"edit": "Düzenle",
"duplicate": "Çoğalt",
"task_duplicated": "Görev çoğaltıldı",
"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.",
"move_task_title": "Görevi taşı",
"move_task": "Başka bir nesneye taşı…",
"object_duplicated": "Nesne çoğaltıldı",
"delete": "Sil",
"add_task": "+ Görev Ekle",
@@ -291,6 +296,8 @@
"seasonal_override_range": "Faktör 0.1 ile 5.0 arasında olmalıdır",
"clear_all": "Tümünü temizle",
"clear": "Temizle",
"date_type_toggle": "Tarihi yazın",
"date_type_invalid": "Geçersiz tarih — 1978-03-15, 1978 gibi bir yıl ya da kendi tarih biçiminizi deneyin",
"seasonal_chart_title": "Mevsimsel Faktörler",
"seasonal_learned": "Öğrenilmiş",
"seasonal_manual": "Manuel",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Yerinde olma kanıtı: Cihazın üzerindeki NFC etiketi veya QR kodu taranana kadar 'Tamamlandı' her yerde engellenir. Otomasyonlar complete servisine 'via_tag_scan' iletebilir.",
"disallow_skip": "Atlamaya izin verme",
"disallow_skip_help": "Atla eylemi tüm yüzeylerden kaybolur; sunucu otomasyonlardan ve sesten gelen atlamayı da reddeder.",
"no_notifications": "Bu görev için bildirim yok",
"no_notifications_help": "Bu görev için hatırlatma yok — durum bildirimi, tekrar, önceden hatırlatma veya toplu bildirim gönderilmez. Panoda ve varlıklarında görünmeye devam eder; haftalık özet onu saymaya devam eder.",
"require_tag_scan_hint": "Bu görev yalnızca cihazın üzerindeki NFC etiketi veya QR kodu taranarak tamamlanır — buradan kaydetme reddedilecektir."
}
@@ -16,6 +16,11 @@
"edit": "Редагувати",
"duplicate": "Дублювати",
"task_duplicated": "Завдання продубльовано",
"task_moved": "Завдання переміщено",
"move_task_target": "Цільовий об'єкт",
"move_task_message": "Виберіть об'єкт, до якого має належати це завдання. Історія, показники та стан тригера переїдуть разом із ним; воно отримає новий номер, а його сутності буде створено заново під новим об'єктом. Прив'язані документи залишаться в поточному об'єкті.",
"move_task_title": "Перемістити завдання",
"move_task": "Перемістити до іншого об'єкта…",
"object_duplicated": "Об'єкт продубльовано",
"delete": "Видалити",
"add_task": "+ Додати завдання",
@@ -289,6 +294,8 @@
"seasonal_override_range": "Коефіцієнт має бути між 0.1 та 5.0",
"clear_all": "Очистити все",
"clear": "Очистити",
"date_type_toggle": "Ввести дату",
"date_type_invalid": "Некоректна дата — спробуйте 1978-03-15, рік на кшталт 1978 або ваш формат дати",
"seasonal_chart_title": "Сезонні коефіцієнти",
"seasonal_learned": "Навчена",
"seasonal_manual": "Ручна",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "Підтвердження присутності: «Готово» заблоковано всюди, доки не відскановано NFC-мітку або QR-код на самому пристрої. Автоматизації можуть передати 'via_tag_scan' службі complete.",
"disallow_skip": "Заборонити пропуск",
"disallow_skip_help": "Дія «Пропустити» зникає з усіх поверхонь, а сервер відхиляє пропуск з автоматизацій і голосу.",
"no_notifications": "Без сповіщень для цього завдання",
"no_notifications_help": "Без нагадувань для цього завдання — ні сповіщень про статус, ні повторів, ні завчасних нагадувань, ні об'єднаних повідомлень. Воно й далі видиме на панелі та у своїх сутностях; тижневий підсумок його враховує.",
"require_tag_scan_hint": "Це завдання завершується лише скануванням його NFC-мітки або QR-коду на самому пристрої — збереження тут буде відхилено."
}
@@ -18,6 +18,11 @@
"edit": "编辑",
"duplicate": "复制",
"task_duplicated": "任务已复制",
"task_moved": "任务已移动",
"move_task_target": "目标对象",
"move_task_message": "选择此任务应归属的对象。历史记录、读数和触发器状态会一并迁移;任务将获得新的编号,其实体会在新对象下重新创建。关联的文档仍留在当前对象。",
"move_task_title": "移动任务",
"move_task": "移动到其他对象…",
"object_duplicated": "对象已复制",
"delete": "删除",
"add_task": "+ 添加任务",
@@ -291,6 +296,8 @@
"seasonal_override_range": "系数必须介于 0.1 到 5.0 之间",
"clear_all": "全部清除",
"clear": "清除",
"date_type_toggle": "输入日期",
"date_type_invalid": "日期无效 — 请试试 1978-03-15、年份如 1978 或你的日期格式",
"seasonal_chart_title": "季节性因素",
"seasonal_learned": "自动学习",
"seasonal_manual": "手动设置",
@@ -995,5 +1002,7 @@
"require_tag_scan_help": "在场证明:在扫描设备上的 NFC 标签或二维码之前,所有界面的“完成”均被阻止。自动化可向 complete 服务传递 'via_tag_scan'。",
"disallow_skip": "不允许跳过",
"disallow_skip_help": "跳过操作将从所有界面消失,服务器也会拒绝来自自动化和语音的跳过。",
"no_notifications": "此任务不发送通知",
"no_notifications_help": "此任务不再提醒——没有状态通知、重复、提前提醒或合并通知。它仍显示在仪表板和其实体中;每周摘要仍会统计它。",
"require_tag_scan_hint": "此任务只能通过扫描设备上的 NFC 标签或二维码来完成——在此保存将被拒绝。"
}
@@ -1091,6 +1091,7 @@ export class MaintenanceSupporterPanel extends LitElement {
task_id: task.id,
object_name: obj.object.name,
allow_skip: task.allow_skip !== false,
notify_enabled: task.notify_enabled !== false,
task_name: task.name,
type: task.type,
schedule_type: task.schedule_type,
@@ -2048,6 +2049,32 @@ export class MaintenanceSupporterPanel extends LitElement {
if (res?.task_id) this._showTask(entryId, res.task_id);
}
// Forum #23: a task created on the wrong object — move it instead of
// re-creating it. Config, history, readings and trigger state travel with
// the task; it gets a new reference number and entities under the target.
private async _moveTask(entryId: string, taskId: string): Promise<void> {
this._moreMenuOpen = false;
const others = this._objects
.filter((o) => o.entry_id !== entryId && !o.object.archived_at)
.sort((a, b) => (a.object.name || "").localeCompare(b.object.name || ""));
if (!others.length) return;
const dlg = this.shadowRoot!.querySelector<MaintenanceConfirmDialog>("maintenance-confirm-dialog");
const result = await dlg?.prompt({
title: t("move_task_title", this._lang),
message: t("move_task_message", this._lang),
confirmText: t("move_task_title", this._lang),
inputLabel: t("move_task_target", this._lang),
inputValue: others[0].entry_id,
options: others.map((o) => ({ value: o.entry_id, label: o.object.name || o.entry_id })),
});
if (!result?.confirmed || !result.value) return;
const res = await this._runAction<{ task_id?: string; entry_id?: string }>(
{ type: "maintenance_supporter/task/move", entry_id: entryId, task_id: taskId, target_entry_id: result.value },
{ successToast: t("task_moved", this._lang) },
);
if (res?.entry_id && res.task_id) this._showTask(res.entry_id, res.task_id);
}
private async _toggleArchiveTask(entryId: string, taskId: string, archived: boolean): Promise<void> {
const res = await this._runAction({
type: archived
@@ -4353,6 +4380,7 @@ export class MaintenanceSupporterPanel extends LitElement {
toggleArchive: (archived) => this._toggleArchiveTask(entryId, taskId, archived),
openQr: (taskName) => this._openQrForTask(entryId, taskId, obj?.object.name || "", taskName),
duplicateTask: () => this._duplicateTask(entryId, taskId),
moveTask: () => this._moveTask(entryId, taskId),
promptReset: () => this._promptResetTask(entryId, taskId),
promptPostpone: () => this._promptPostponeTask(entryId, taskId),
snoozeTask: () => this._snoozeTask(entryId, taskId),
@@ -4480,9 +4480,9 @@
"license": "MIT"
},
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"version": "3.3.18",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
"integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
"dev": true,
"funding": [
{
@@ -78,6 +78,8 @@ export interface TaskDetailContext {
toggleArchive: (archived: boolean) => void;
openQr: (taskName: string) => void;
duplicateTask: () => void;
/** Forum #23: move the task to another object. */
moveTask: () => void;
promptReset: () => void;
promptPostpone: () => void;
snoozeTask: () => void;
@@ -133,6 +135,9 @@ function renderTaskHeader(task: MaintenanceTask, ctx: TaskDetailContext) {
<ha-icon icon="mdi:calendar-arrow-right"></ha-icon>${formatDate(task.due_override, L)}
</span>` : nothing}
${renderUserBadge(task, ctx.getUserName, ctx.getPerson)}
${task.notify_enabled === false
? html`<span class="nfc-badge muted-badge" title="${t("no_notifications", L)}"><ha-icon icon="mdi:bell-off-outline"></ha-icon></span>`
: nothing}
${task.nfc_tag_id
? html`<span class="nfc-badge" title="${t("nfc_tag_id", L)}: ${task.nfc_tag_id}"><ha-icon icon="mdi:nfc-variant"></ha-icon> NFC</span>`
: !isOperator ? html`<span class="nfc-badge unlinked" title="${t("nfc_link_hint", L)}"
@@ -157,6 +162,7 @@ function renderTaskHeader(task: MaintenanceTask, ctx: TaskDetailContext) {
<div class="popup-menu-item" @click=${() => { ctx.closeMoreMenu(); ctx.printWorksheet(); }}>${t("worksheet", L)}</div>
${!isOperator ? html`
<div class="popup-menu-item" @click=${() => ctx.duplicateTask()}>${t("duplicate", L)}</div>
<div class="popup-menu-item" @click=${() => ctx.moveTask()}>${t("move_task", L)}</div>
<div class="popup-menu-item" @click=${() => { ctx.closeMoreMenu(); ctx.promptReset(); }}>${t("reset", L)}</div>
<div class="popup-menu-item" @click=${() => { ctx.closeMoreMenu(); ctx.promptPostpone(); }}>${t("postpone", L)}…</div>
<div class="popup-menu-item" @click=${() => { ctx.closeMoreMenu(); ctx.snoozeTask(); }}>${t("snooze", L)}</div>
@@ -410,6 +410,14 @@ interface RecurrenceLike {
* day_of_month / one_time / manual. Used by the panel, card, and quick-actions. */
export function formatRecurrence(task: RecurrenceLike, lang?: string): string {
const s = task.schedule;
// A sensor-driven task is not "Manual": say so, and append the safety
// interval when one is set (the KPI card read "Manual" for the HVAC filter
// in the docs shot — reported as "schief").
if (task.schedule_type === "sensor_based") {
const base = t("sensor_based", lang);
const every = s && s.kind === "interval" && s.every ? s.every : task.interval_days;
return every ? `${base} · ${formatInterval(every, (s && s.kind === "interval" ? s.unit : task.interval_unit) || "days", lang)}` : base;
}
// (#83) ±N-day shift suffix shared by the calendar kinds.
const off = s?.offset ? ` ${s.offset > 0 ? "+" : "−"}${Math.abs(s.offset)}d` : "";
switch (s?.kind) {
@@ -204,6 +204,8 @@ export interface MaintenanceTask {
enabled: boolean;
/** #150: false = the skip lock — Skip hidden everywhere, server refuses. */
allow_skip?: boolean;
/** #173: false = this task sends no reminders (dashboard/entities unaffected). */
notify_enabled?: boolean;
schedule_type: string; // "time_based" | "sensor_based" | "one_time" | "manual" | calendar kind
interval_days?: number | null;
interval_unit?: string; // "days" | "weeks" | "months" | "years"
@@ -544,6 +546,8 @@ export interface TaskRow {
enabled: boolean;
/** #150: false = skip locked for this task. */
allow_skip: boolean;
/** #173: false = no reminders for this task. */
notify_enabled: boolean;
nfc_tag_id: string | null;
priority: string;
labels: string[];