257 files

This commit is contained in:
Home Assistant Version Control committed 2026-10-02 16:06:24 +00:00
1 parent 7c55603942
commit c29f5cc088
258 files changed
+24621 -3136

No files matched your search

@@ -40,6 +40,7 @@ import {
import { calendarStyles } from "./calendar-styles";
import { syncLocaleFromHass, sharedStyles, currencySymbolOf, t, ensureLocale, isLocaleLoaded, setProfilePrefs, formatDueDays, formatInterval, formatWeekday, formatMonth, langOf, formatCost, syncCurrencyDecimals} from "./styles";
import { registerCustomCard } from "./helpers/register-card";
import { healCardRegistry } from "./helpers/registry-heal";
import { loadHistoryEntryDraft } from "./helpers/history-draft";
import { canWrite } from "./helpers/permissions";
import { fetchSettingsOnce } from "./helpers/settings-cache";
@@ -107,15 +108,17 @@ export class MaintenanceCalendarCard extends LitElement {
setConfig(config: CalendarCardConfig): void {
this._config = { ...config };
if (config.past_days && [30, 90].includes(config.past_days)) {
this._pastDays = config.past_days as PastDays;
} else if (config.window_days && [7, 14, 30, 365].includes(config.window_days)) {
this._windowDays = config.window_days as WindowDays;
this._pastDays = 0;
}
if (typeof config.user_filter === "string") {
this._userFilter = config.user_filter;
}
// The config decides the window every time it changes: removing
// past_days in the editor left the card in its past view (audit
// 2026-09-29).
this._windowDays = config.window_days && [7, 14, 30, 365].includes(config.window_days)
? (config.window_days as WindowDays)
: 30;
this._pastDays = config.past_days && [30, 90].includes(config.past_days) ? (config.past_days as PastDays) : 0;
// Like the window above: the config decides the filters every time — the
// editor DELETES user_filter when it goes back to "All users", and a
// card kept its old filter (bug audit 2026-09-29).
this._userFilter = typeof config.user_filter === "string" ? config.user_filter : "";
if (typeof config.object_filter === "string") {
this._objectFilter = config.object_filter;
this._configuredObjects = [];
@@ -127,6 +130,9 @@ export class MaintenanceCalendarCard extends LitElement {
// card's filter_objects that #83 asked for.
this._objectFilter = values.length === 1 ? values[0] : "";
this._configuredObjects = values.length > 1 ? values : [];
} else {
this._objectFilter = "";
this._configuredObjects = [];
}
}
@@ -466,7 +472,7 @@ export class MaintenanceCalendarCard extends LitElement {
return html`
<ha-card .header=${title}>
${showChips || showUserFilter
${showChips || showUserFilter || showObjectFilter
? html`
<div class="cal-controls">
${showChips
@@ -557,6 +563,12 @@ const WINDOW_DAY_KEYS: Array<{ value: WindowDays; key: string }> = [
{ value: 30, key: "cal_editor_window_month" },
{ value: 365, key: "cal_editor_window_year" },
];
/** past_days had no editor control and silently beat the window picked
* here (audit 2026-09-29) — the past windows share the one dropdown. */
const PAST_DAY_KEYS: Array<{ value: PastDays; key: string }> = [
{ value: 30, key: "cal_editor_window_past_30" },
{ value: 90, key: "cal_editor_window_past_90" },
];
class MaintenanceCalendarCardEditor extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -597,6 +609,24 @@ class MaintenanceCalendarCardEditor extends LitElement {
if (key === "user_filter" && value === "") {
delete (newConfig as unknown as Record<string, unknown>).user_filter;
}
this._emit(newConfig);
}
/** One dropdown, two keys: "past-N" writes past_days, a number writes
* window_days — each drops the other, since past_days wins in the card. */
private _windowChanged(value: string): void {
const next = { ...this._config } as unknown as Record<string, unknown>;
if (value.startsWith("past-")) {
next.past_days = Number(value.slice(5));
delete next.window_days;
} else {
next.window_days = Number(value);
delete next.past_days;
}
this._emit(next as unknown as CalendarCardConfig);
}
private _emit(newConfig: CalendarCardConfig): void {
this._config = newConfig;
this.dispatchEvent(
new CustomEvent("config-changed", {
@@ -609,7 +639,7 @@ class MaintenanceCalendarCardEditor extends LitElement {
render() {
const L = this._lang;
const currentWindow = this._config.window_days ?? 30;
const currentWindow = this._config.past_days ? `past-${this._config.past_days}` : `${this._config.window_days ?? 30}`;
const showChips = this._config.show_window_chips !== false;
const showUserFilter = this._config.show_user_filter !== false;
const userFilter = this._config.user_filter ?? "";
@@ -630,15 +660,15 @@ class MaintenanceCalendarCardEditor extends LitElement {
<label for="window">${t("cal_editor_window", L)}</label>
<select
id="window"
@change=${(e: Event) =>
this._valueChanged(
"window_days",
Number((e.target as HTMLSelectElement).value) as WindowDays,
)}
@change=${(e: Event) => this._windowChanged((e.target as HTMLSelectElement).value)}
>
${WINDOW_DAY_KEYS.map(
(o) =>
html`<option value="${o.value}" ?selected=${o.value === currentWindow}>${t(o.key, L)}</option>`,
html`<option value="${o.value}" ?selected=${`${o.value}` === currentWindow}>${t(o.key, L)}</option>`,
)}
${PAST_DAY_KEYS.map(
(o) =>
html`<option value="past-${o.value}" ?selected=${`past-${o.value}` === currentWindow}>${t(o.key, L)}</option>`,
)}
</select>
</div>
@@ -747,6 +777,9 @@ if (!customElements.get("maintenance-supporter-calendar-card-editor")) {
// The type MUST match the registered element tag exactly (custom:X → tag X),
// or the picker entry resolves to a non-existent element and the strategy's
// calendar mode throws a config error.
// HA's boot-time registry swap can strand these definitions (audit 2026-09-29).
healCardRegistry(["maintenance-supporter-calendar-card"], import.meta.url);
registerCustomCard({
type: "maintenance-supporter-calendar-card",
name: "Maintenance Supporter — Calendar",