456 files
This commit is contained in:
@@ -26,6 +26,7 @@ import { effectivePhase } from "./helpers/phases";
|
||||
import { renderEventTitles } from "./helpers/event-titles";
|
||||
import { recommendationReason, type HomeProfile, type TemplateRecommendation } from "./helpers/home-profile";
|
||||
import { buildCompleteDialogArgs, fillAndOpenCompleteDialog } from "./helpers/complete-dialog-args";
|
||||
import { areaDisplayName, areaKeyOf } from "./helpers/area-history";
|
||||
import { panelStyles } from "./panel-styles";
|
||||
|
||||
// Global search (#171): what the panel needs to know about a hit — enough
|
||||
@@ -130,7 +131,8 @@ import { readingSlotDelta } from "./helpers/reading-slots";
|
||||
import { bulkResultMessage, runWs, runWsEach } from "./helpers/ws-run";
|
||||
import { STATUS_ORDER, statusRank } from "./status-constants";
|
||||
|
||||
type View = "overview" | "object" | "task" | "all_objects" | "all_parts";
|
||||
// #191: all_areas = the areas page, area = one area's history and costs.
|
||||
type View = "overview" | "object" | "task" | "all_objects" | "all_parts" | "all_areas" | "area";
|
||||
|
||||
/** One row of the instance-wide parts overview (#130) — the WS response of
|
||||
* `parts/overview`: the stored part fields plus owner, live stock and the
|
||||
@@ -221,6 +223,8 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
@state() private _allParts: PartsOverviewRow[] | null = null;
|
||||
@state() private _selectedEntryId: string | null = null;
|
||||
@state() private _selectedTaskId: string | null = null;
|
||||
/** #191: the area on the `area` view (HA area id or area-history NO_AREA). */
|
||||
@state() private _selectedAreaId: string | null = null;
|
||||
@state() private _filterStatus = "";
|
||||
@state() private _filterUser: string | null = null;
|
||||
@state() private _filterLabel: string | null = null;
|
||||
@@ -272,6 +276,9 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
@state() private _moreMenuOpen = false;
|
||||
@state() private _objMenuOpen = false;
|
||||
@state() private _toastMessage = "";
|
||||
/** error = red (a refusal, a failure); info = neutral like HA's own
|
||||
* toasts — a success used to show in the error red too (2.95). */
|
||||
@state() private _toastKind: "error" | "info" = "error";
|
||||
@state() private _toastUndo: (() => void) | null = null;
|
||||
@state() private _toastActionLabel = "";
|
||||
// Narrow-viewport disclosure (UX 2026-07): filters and create-actions are
|
||||
@@ -284,6 +291,10 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
@state() private _gsSetupsCount = 0;
|
||||
@state() private _gsAdoptCount = 0;
|
||||
private _gsLoaded = false;
|
||||
// 2.95: tasks whose completion could also reset the integration's counter
|
||||
// — offered to every install (the fix for tasks adopted before), once.
|
||||
private _resetOffersLoaded = false;
|
||||
@state() private _resetOffersCount = 0;
|
||||
// Battery Fleet: offer one-click setup only when Battery Notes is present
|
||||
// and the fleet isn't set up yet.
|
||||
@state() private _batteryFleetSetupAvailable = false;
|
||||
@@ -837,7 +848,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
// state-less entry would restore nothing and leave the task page up.
|
||||
const state = history.state as { msp_view?: View } | null;
|
||||
if (!state?.msp_view) {
|
||||
history.replaceState({ msp_view: this._view, msp_entry: this._selectedEntryId, msp_task: this._selectedTaskId }, "");
|
||||
history.replaceState({ msp_view: this._view, msp_entry: this._selectedEntryId, msp_task: this._selectedTaskId, msp_area: this._selectedAreaId }, "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -964,6 +975,17 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
// #191: `?area=<area_id>` opens that area's page (a dashboard button per
|
||||
// room); an area no object sits in lands on the areas list instead.
|
||||
const areaParam = params.get("area");
|
||||
if (areaParam && !params.get("entry_id")) {
|
||||
this._deepLinkHandled = true;
|
||||
cleanMsActionUrl();
|
||||
if (this._objects.some((o) => areaKeyOf(o.object) === areaParam)) this._showArea(areaParam);
|
||||
else this._showAllAreas();
|
||||
return;
|
||||
}
|
||||
|
||||
const entryId = params.get("entry_id");
|
||||
if (!entryId) return;
|
||||
this._deepLinkHandled = true;
|
||||
@@ -1212,6 +1234,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
trigger_current_delta: task.trigger_current_delta ?? null,
|
||||
trigger_config: task.trigger_config ?? null,
|
||||
trigger_entity_info: task.trigger_entity_info ?? null,
|
||||
battery_fleet_task: task.battery_fleet_task === true,
|
||||
times_performed: task.times_performed,
|
||||
total_cost: task.total_cost,
|
||||
interval_days: task.interval_days ?? null,
|
||||
@@ -1293,15 +1316,15 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
/** Push a browser history entry so the back button navigates within the
|
||||
* panel. An in-app deep link arrives on the entry HA's navigate() just
|
||||
* pushed — that one is taken over instead (see _onLocationChanged). */
|
||||
private _pushPanelState(view: View, entryId?: string | null, taskId?: string | null): void {
|
||||
const state = { msp_view: view, msp_entry: entryId || null, msp_task: taskId || null };
|
||||
private _pushPanelState(view: View, entryId?: string | null, taskId?: string | null, areaId?: string | null): void {
|
||||
const state = { msp_view: view, msp_entry: entryId || null, msp_task: taskId || null, msp_area: areaId || null };
|
||||
if (this._deepLinkInPlace) history.replaceState(state, "");
|
||||
else history.pushState(state, "");
|
||||
}
|
||||
|
||||
/** Handle browser back/forward button. */
|
||||
private _onPopState(e: PopStateEvent): void {
|
||||
const s = e.state as { msp_view?: View; msp_entry?: string; msp_task?: string } | null;
|
||||
const s = e.state as { msp_view?: View; msp_entry?: string; msp_task?: string; msp_area?: string } | null;
|
||||
if (!s?.msp_view) {
|
||||
// No panel state → we're leaving the panel, let HA handle it
|
||||
return;
|
||||
@@ -1310,6 +1333,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
this._view = s.msp_view;
|
||||
this._selectedEntryId = s.msp_entry || null;
|
||||
this._selectedTaskId = s.msp_task || null;
|
||||
this._selectedAreaId = s.msp_area || null;
|
||||
this._moreMenuOpen = false;
|
||||
this._objectSectionOverride = null;
|
||||
if (s.msp_view === "all_parts") void this._loadAllParts();
|
||||
@@ -1362,6 +1386,35 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
// #191: the areas page (sibling of All objects / All parts) and one area.
|
||||
private _showAllAreas(): void {
|
||||
this._pushPanelState("all_areas");
|
||||
this._view = "all_areas";
|
||||
this._selectedEntryId = null;
|
||||
this._selectedTaskId = null;
|
||||
this._scrollContentToTop();
|
||||
}
|
||||
|
||||
private _showArea(areaId: string): void {
|
||||
this._pushPanelState("area", null, null, areaId);
|
||||
this._view = "area";
|
||||
this._selectedAreaId = areaId;
|
||||
this._selectedEntryId = null;
|
||||
this._selectedTaskId = null;
|
||||
this._scrollContentToTop();
|
||||
}
|
||||
|
||||
/** The two area components are a code-split chunk, fetched the first time
|
||||
* either view renders (every route in — chip, Back, `?area=` — renders).
|
||||
* Until then the element is an unknown tag; Lit keeps the properties it
|
||||
* was given and the upgrade picks them up. */
|
||||
private _areaUi: Promise<unknown> | null = null;
|
||||
private _ensureAreaUi(): void {
|
||||
// A failed chunk fetch (connection blip) is retried on the next render.
|
||||
this._areaUi ??= Promise.all([import("./components/areas-view"), import("./components/area-view")])
|
||||
.catch(() => { this._areaUi = null; });
|
||||
}
|
||||
|
||||
/** v2.1.0 (Discussion #49 — @byoung79): tap a KPI value to auto-filter
|
||||
* the task list. Empty string clears the filter (used by "Tasks" KPI). */
|
||||
private _filterByStatus(status: string): void {
|
||||
@@ -1568,8 +1621,16 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
|
||||
// --- Toast ---
|
||||
|
||||
private _showToast(msg: string): void {
|
||||
/** A count sentence with its own singular for exactly one ("1 devices"
|
||||
* read in every language, 2.95). Both keys literal, so the locale
|
||||
* hygiene scan sees them. */
|
||||
private _countText(key: string, oneKey: string, placeholder: string, n: number, L: string = this._lang): string {
|
||||
return n === 1 ? t(oneKey, L) : t(key, L).replace(`{${placeholder}}`, String(n));
|
||||
}
|
||||
|
||||
private _showToast(msg: string, kind: "error" | "info" = "error"): void {
|
||||
if (this._toastTimer) clearTimeout(this._toastTimer);
|
||||
this._toastKind = kind;
|
||||
this._toastUndo = null;
|
||||
this._toastActionLabel = "";
|
||||
this._toastMessage = msg;
|
||||
@@ -1587,6 +1648,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
|
||||
private _showUndoToast(msg: string, undo: () => void): void {
|
||||
if (this._toastTimer) clearTimeout(this._toastTimer);
|
||||
this._toastKind = "info";
|
||||
this._toastActionLabel = "";
|
||||
this._toastMessage = msg;
|
||||
this._toastUndo = undo;
|
||||
@@ -1886,7 +1948,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
const tasks = e.detail?.tasks_created ?? 0;
|
||||
const created = (e.detail?.created ?? []) as Array<{ entry_id: string; task_id: string; name: string }>;
|
||||
await this._loadData();
|
||||
const msg = t("adopt_problem_done", this._lang).replace("{tasks}", String(tasks));
|
||||
const msg = this._countText("adopt_problem_done", "adopt_problem_done_one", "tasks", tasks);
|
||||
if (created.length > 0) {
|
||||
// Adopted tasks are fully configurable from day one (responsible user,
|
||||
// priority, documents) — surface that with a direct path to the first.
|
||||
@@ -1900,7 +1962,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._showToast(msg);
|
||||
this._showToast(msg, "info");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1925,7 +1987,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
if (obj && tk) {
|
||||
this._showTask(obj.entry_id, tk.id);
|
||||
}
|
||||
this._showToast(t("battery_fleet_setup_done", this._lang));
|
||||
this._showToast(t("battery_fleet_setup_done", this._lang), "info");
|
||||
}
|
||||
|
||||
private _openSuggestedSetups(): void {
|
||||
@@ -1933,9 +1995,18 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
.then((d) => d?.open());
|
||||
}
|
||||
|
||||
private _onResetsWired(e: CustomEvent): void {
|
||||
const count = e.detail?.wired ?? 0;
|
||||
this._showToast(this._countText("reset_offers_done", "reset_offers_done_one", "count", count), "info");
|
||||
this._resetOffersLoaded = false;
|
||||
this._resetOffersCount = 0;
|
||||
this._maybeLoadResetOffers();
|
||||
this._loadData();
|
||||
}
|
||||
|
||||
private _onSetupsAdopted(e: CustomEvent): void {
|
||||
const tasks = e.detail?.tasks_created ?? 0;
|
||||
this._showToast(t("setups_done", this._lang).replace("{tasks}", String(tasks)));
|
||||
this._showToast(this._countText("setups_done", "setups_done_one", "tasks", tasks), "info");
|
||||
this._loadData();
|
||||
}
|
||||
|
||||
@@ -1971,7 +2042,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
await this._loadData();
|
||||
},
|
||||
successToast: t("template_created", this._lang),
|
||||
onSuccess: (m) => this._showToast(m),
|
||||
onSuccess: (m) => this._showToast(m, "info"),
|
||||
onError: (m) => this._showToast(m),
|
||||
},
|
||||
);
|
||||
@@ -2109,7 +2180,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
await this._loadData();
|
||||
const msg = bulkResultMessage(doneMsg(done.length), failed, this._lang);
|
||||
if (undo && done.length > 0) this._showUndoToast(msg, () => undo(done));
|
||||
else this._showToast(msg);
|
||||
else this._showToast(msg, failed.length > 0 ? "error" : "info");
|
||||
}
|
||||
|
||||
/** One WS message per selected task row. */
|
||||
@@ -2284,7 +2355,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
busy: (b) => { this._actionLoading = b; },
|
||||
reload: () => this._loadData(),
|
||||
successToast: opts?.successToast,
|
||||
onSuccess: (m) => this._showToast(m),
|
||||
onSuccess: (m) => this._showToast(m, "info"),
|
||||
onError: (m) => this._showToast(m),
|
||||
});
|
||||
return res === undefined ? null : ((res ?? {}) as T);
|
||||
@@ -2546,9 +2617,10 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
this._showToast(
|
||||
`${t("reanalyze_result", this._lang)}: ${res.recommended_interval} ${t("days", this._lang)} ` +
|
||||
`(${t(`confidence_${res.confidence}`, this._lang)}, ${res.data_points} ${t("data_points", this._lang)})`,
|
||||
"info",
|
||||
);
|
||||
} else {
|
||||
this._showToast(t("reanalyze_insufficient_data", this._lang));
|
||||
this._showToast(t("reanalyze_insufficient_data", this._lang), "info");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2653,7 +2725,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
}
|
||||
return;
|
||||
}
|
||||
this._showToast(t("quick_complete_success", this._lang));
|
||||
this._showToast(t("quick_complete_success", this._lang), "info");
|
||||
// Silent success: the list must reflect the completion right away — the
|
||||
// subscription delta may lag or be coalesced.
|
||||
try { await this._loadData(); } catch { /* subscription will sync */ }
|
||||
@@ -2906,6 +2978,10 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
? this._renderAllObjects()
|
||||
: this._view === "all_parts"
|
||||
? this._renderAllParts()
|
||||
: this._view === "all_areas"
|
||||
? this._renderAllAreas()
|
||||
: this._view === "area"
|
||||
? this._renderArea()
|
||||
: this._view === "object"
|
||||
? this._renderObjectDetail()
|
||||
: this._renderTaskDetail()}
|
||||
@@ -2955,12 +3031,13 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
<maintenance-suggested-setups-dialog
|
||||
.hass=${this.hass}
|
||||
@integration-setups-adopted=${(e: CustomEvent) => this._onSetupsAdopted(e)}
|
||||
@reset-counters-wired=${(e: CustomEvent) => this._onResetsWired(e)}
|
||||
></maintenance-suggested-setups-dialog>
|
||||
<maintenance-saved-views-dialog
|
||||
.hass=${this.hass}
|
||||
@saved-views-changed=${(e: CustomEvent<{ views: SavedView[] }>) => this._onSavedViewsChanged(e)}
|
||||
></maintenance-saved-views-dialog>
|
||||
${this._toastMessage ? html`<div class="toast">
|
||||
${this._toastMessage ? html`<div class="toast ${this._toastKind}" role=${this._toastKind === "error" ? "alert" : "status"}>
|
||||
<span>${this._toastMessage}</span>
|
||||
${this._toastUndo ? html`<button class="toast-undo" @click=${() => this._runToastUndo()}>${this._toastActionLabel || t("undo", this._lang)}</button>` : nothing}
|
||||
</div>` : nothing}
|
||||
@@ -3000,6 +3077,10 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
const task = this._getTask(this._selectedEntryId, this._selectedTaskId);
|
||||
crumbs.push({ label: task?.name || "Task" });
|
||||
}
|
||||
if (this._view === "area" && this._selectedAreaId) {
|
||||
crumbs.push({ label: t("all_areas", this._lang), action: () => this._showAllAreas() });
|
||||
crumbs.push({ label: areaDisplayName(this._selectedAreaId, this.hass?.areas, t("no_area", this._lang)) });
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="header">
|
||||
@@ -3009,6 +3090,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
.path=${"M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z"}
|
||||
@click=${() => {
|
||||
if (this._view === "task") this._showObject(this._selectedEntryId!);
|
||||
else if (this._view === "area") this._showAllAreas();
|
||||
else this._showOverview();
|
||||
}}
|
||||
></ha-icon-button>`
|
||||
@@ -3726,6 +3808,9 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
<button class="sibling-view-chip" @click=${() => this._showAllParts()}>
|
||||
<ha-icon icon="mdi:package-variant-closed"></ha-icon> ${t("all_parts", L)}
|
||||
</button>
|
||||
<button class="sibling-view-chip" data-view="all_areas" @click=${() => this._showAllAreas()}>
|
||||
<ha-icon icon="mdi:floor-plan"></ha-icon> ${t("all_areas", L)}
|
||||
</button>
|
||||
</div>
|
||||
<div class="filter-bar">
|
||||
<label class="filter-field">
|
||||
@@ -3837,6 +3922,9 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
<button class="sibling-view-chip" @click=${() => this._showAllObjects()}>
|
||||
<ha-icon icon="mdi:devices"></ha-icon> ${t("all_objects", L)}
|
||||
</button>
|
||||
<button class="sibling-view-chip" data-view="all_areas" @click=${() => this._showAllAreas()}>
|
||||
<ha-icon icon="mdi:floor-plan"></ha-icon> ${t("all_areas", L)}
|
||||
</button>
|
||||
</div>
|
||||
<div class="filter-bar">
|
||||
<ha-button appearance="plain" @click=${() => this._exportPartsCsv()}>
|
||||
@@ -3895,6 +3983,59 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
// ── #191: areas ──────────────────────────────────────────────────────────
|
||||
|
||||
private _renderAllAreas() {
|
||||
const L = this._lang;
|
||||
this._ensureAreaUi();
|
||||
return html`
|
||||
<div class="breadcrumb">
|
||||
<ha-icon-button @click=${() => this._showAllObjects()}>
|
||||
<ha-icon icon="mdi:arrow-left"></ha-icon>
|
||||
</ha-icon-button>
|
||||
<span>${t("all_areas", L)}</span>
|
||||
<button class="sibling-view-chip" @click=${() => this._showAllObjects()}>
|
||||
<ha-icon icon="mdi:devices"></ha-icon> ${t("all_objects", L)}
|
||||
</button>
|
||||
<button class="sibling-view-chip" @click=${() => this._showAllParts()}>
|
||||
<ha-icon icon="mdi:package-variant-closed"></ha-icon> ${t("all_parts", L)}
|
||||
</button>
|
||||
</div>
|
||||
<maintenance-areas-view
|
||||
.hass=${this.hass}
|
||||
.objects=${this._objects}
|
||||
.showArchived=${this._showArchived}
|
||||
.currencySymbol=${this._currencySymbol}
|
||||
@open-area=${(e: CustomEvent<{ areaKey: string }>) => this._showArea(e.detail.areaKey)}
|
||||
@archived-toggle=${() => { this._showArchived = !this._showArchived; }}
|
||||
></maintenance-areas-view>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderArea() {
|
||||
if (!this._selectedAreaId) return nothing;
|
||||
const L = this._lang;
|
||||
this._ensureAreaUi();
|
||||
return html`
|
||||
<div class="breadcrumb">
|
||||
<ha-icon-button @click=${() => this._showAllAreas()}>
|
||||
<ha-icon icon="mdi:arrow-left"></ha-icon>
|
||||
</ha-icon-button>
|
||||
<span>${t("all_areas", L)}</span>
|
||||
</div>
|
||||
<maintenance-area-view
|
||||
.hass=${this.hass}
|
||||
.areaKey=${this._selectedAreaId}
|
||||
.objects=${this._objects}
|
||||
.showArchived=${this._showArchived}
|
||||
.currencySymbol=${this._currencySymbol}
|
||||
.userName=${(id: string) => this._userService?.getUserName(id) ?? null}
|
||||
@open-object=${(e: CustomEvent<{ entryId: string }>) => this._showObject(e.detail.entryId)}
|
||||
@open-task=${(e: CustomEvent<{ entryId: string; taskId: string }>) => this._showTask(e.detail.entryId, e.detail.taskId)}
|
||||
></maintenance-area-view>
|
||||
`;
|
||||
}
|
||||
|
||||
/** Client-side CSV of the loaded overview rows (the objects table's CSV is
|
||||
* server-built; the parts rows are already fully materialized here). */
|
||||
private _exportPartsCsv(): void {
|
||||
@@ -4362,6 +4503,11 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
? html`<p class="meta">${[o.manufacturer, o.model].filter(Boolean).join(" ")}</p>`
|
||||
: nothing}
|
||||
${o.serial_number ? html`<p class="meta">${t("serial_number_label", L)}: ${o.serial_number}</p>` : nothing}
|
||||
${o.area_id
|
||||
? html`<p class="meta">${t("area", L)}:
|
||||
<a href="#" class="object-area-link" @click=${(e: Event) => { e.preventDefault(); this._showArea(o.area_id!); }}
|
||||
>${areaDisplayName(o.area_id, this.hass?.areas, t("no_area", L))}</a></p>`
|
||||
: nothing}
|
||||
${isSafeHttpUrl(o.documentation_url)
|
||||
? html`<p class="meta">${t("documentation_url_label", L)}:
|
||||
<a href=${o.documentation_url} target="_blank" rel="noopener noreferrer">${o.documentation_url}</a>
|
||||
@@ -4598,7 +4744,17 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
|
||||
/** Discovery counts for the chips — fetched ONCE per panel life and ONLY
|
||||
* while the install is young, so mature installs pay nothing. */
|
||||
private _maybeLoadResetOffers(): void {
|
||||
if (this._resetOffersLoaded) return;
|
||||
this._resetOffersLoaded = true;
|
||||
this.hass.connection
|
||||
.sendMessagePromise<{ offers: unknown[] }>({ type: "maintenance_supporter/integration_setups/reset_offers" })
|
||||
.then((r) => { this._resetOffersCount = (r.offers || []).length; })
|
||||
.catch(() => { this._resetOffersCount = 0; });
|
||||
}
|
||||
|
||||
private _maybeLoadGettingStarted(): void {
|
||||
this._maybeLoadResetOffers();
|
||||
if (this._gsLoaded || !this._isYoungInstall()) return;
|
||||
this._gsLoaded = true;
|
||||
this.hass.connection
|
||||
@@ -4618,17 +4774,24 @@ export class MaintenanceSupporterPanel extends LitElement {
|
||||
if (young && this._gsSetupsCount > 0 && !dismissed.has("setups")) {
|
||||
chips.push({
|
||||
id: "setups", icon: "mdi:auto-fix",
|
||||
text: t("gs_setups_chip", L).replace("{n}", String(this._gsSetupsCount)),
|
||||
text: this._countText("gs_setups_chip", "gs_setups_chip_one", "n", this._gsSetupsCount, L),
|
||||
run: () => this._openSuggestedSetups(),
|
||||
});
|
||||
}
|
||||
if (young && this._gsAdoptCount > 0 && !dismissed.has("adopt")) {
|
||||
chips.push({
|
||||
id: "adopt", icon: "mdi:alert-circle-check-outline",
|
||||
text: t("gs_adopt_chip", L).replace("{n}", String(this._gsAdoptCount)),
|
||||
text: this._countText("gs_adopt_chip", "gs_adopt_chip_one", "n", this._gsAdoptCount, L),
|
||||
run: () => this._openAdoptProblemSensors(),
|
||||
});
|
||||
}
|
||||
if (this._resetOffersCount > 0 && !dismissed.has("resets")) {
|
||||
chips.push({
|
||||
id: "resets", icon: "mdi:counter",
|
||||
text: this._countText("gs_reset_chip", "gs_reset_chip_one", "n", this._resetOffersCount, L),
|
||||
run: () => this._openSuggestedSetups(),
|
||||
});
|
||||
}
|
||||
if (this._batteryFleetSetupAvailable && !dismissed.has("fleet")) {
|
||||
chips.push({
|
||||
id: "fleet", icon: "mdi:battery-sync",
|
||||
|
||||
Reference in New Issue
Block a user