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
@@ -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();