117 files
This commit is contained in:
1 parent
c31830deeb
commit
ca54a47de7
119 files changed
+9719
-605
No files matched your search
+1
-1
@@ -1 +1 @@
|
|||||||
{"pid": 71, "version": 1, "ha_version": "2026.8.1", "start_ts": 1786185306.3297718}
|
{"pid": 71, "version": 1, "ha_version": "2026.8.1", "start_ts": 1786185437.2270892}
|
||||||
+26
-26
@@ -81,117 +81,117 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "88b90f2b1d6b45f0b44bee786ee1a525",
|
"id": "88b90f2b1d6b45f0b44bee786ee1a525",
|
||||||
"url": "/taskmate/taskmate-attr-resolver.js?v=5.0.3",
|
"url": "/taskmate/taskmate-attr-resolver.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "0796c92931dd458e81dc9c2677248274",
|
"id": "0796c92931dd458e81dc9c2677248274",
|
||||||
"url": "/taskmate/taskmate-localize.js?v=5.0.3",
|
"url": "/taskmate/taskmate-localize.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "d2e281920ac7409583eafff1f1db69bd",
|
"id": "d2e281920ac7409583eafff1f1db69bd",
|
||||||
"url": "/taskmate/taskmate-design.js?v=5.0.3",
|
"url": "/taskmate/taskmate-design.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "9eae9632f0734480be5edd784b030673",
|
"id": "9eae9632f0734480be5edd784b030673",
|
||||||
"url": "/taskmate/taskmate-badges-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-badges-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "5df49cd8a4eb420497b5df22cb31362c",
|
"id": "5df49cd8a4eb420497b5df22cb31362c",
|
||||||
"url": "/taskmate/taskmate-child-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-child-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "b44c87d0d74f468cb96c5eabc340f9ee",
|
"id": "b44c87d0d74f468cb96c5eabc340f9ee",
|
||||||
"url": "/taskmate/taskmate-rewards-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-rewards-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "787a96f9c30548708165a48457c99feb",
|
"id": "787a96f9c30548708165a48457c99feb",
|
||||||
"url": "/taskmate/taskmate-approvals-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-approvals-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "84031597de424ad68e7c2bc66d06b72e",
|
"id": "84031597de424ad68e7c2bc66d06b72e",
|
||||||
"url": "/taskmate/taskmate-points-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-points-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "02613225844746b699bfbfac9642eca2",
|
"id": "02613225844746b699bfbfac9642eca2",
|
||||||
"url": "/taskmate/taskmate-reorder-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-reorder-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "7a06a07e17ba4b31b712bc91b77360b4",
|
"id": "7a06a07e17ba4b31b712bc91b77360b4",
|
||||||
"url": "/taskmate/taskmate-overview-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-overview-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "08b42b53b33b4fa88db932455cf8d5aa",
|
"id": "08b42b53b33b4fa88db932455cf8d5aa",
|
||||||
"url": "/taskmate/taskmate-activity-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-activity-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "15907eff51784acdba88ff694b574509",
|
"id": "15907eff51784acdba88ff694b574509",
|
||||||
"url": "/taskmate/taskmate-streak-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-streak-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "1bd6bb5c0a6d4f0d916e3d82cb7fac39",
|
"id": "1bd6bb5c0a6d4f0d916e3d82cb7fac39",
|
||||||
"url": "/taskmate/taskmate-weekly-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-weekly-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "289ce5943f5a4972a593697db4c96ece",
|
"id": "289ce5943f5a4972a593697db4c96ece",
|
||||||
"url": "/taskmate/taskmate-graph-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-graph-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "d2904acee4c74a398dcc7b996c23e7e7",
|
"id": "d2904acee4c74a398dcc7b996c23e7e7",
|
||||||
"url": "/taskmate/taskmate-reward-progress-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-reward-progress-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "46d378736fd54a26be253f2dfb27202e",
|
"id": "46d378736fd54a26be253f2dfb27202e",
|
||||||
"url": "/taskmate/taskmate-leaderboard-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-leaderboard-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "db11ae36457842fa826c7991e1d9c6f4",
|
"id": "db11ae36457842fa826c7991e1d9c6f4",
|
||||||
"url": "/taskmate/taskmate-parent-dashboard-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-parent-dashboard-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "ce85f301b59a412e9abfe5ffd51cb9a2",
|
"id": "ce85f301b59a412e9abfe5ffd51cb9a2",
|
||||||
"url": "/taskmate/taskmate-penalties-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-penalties-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "1959e1629de2422daa8adaf87069c288",
|
"id": "1959e1629de2422daa8adaf87069c288",
|
||||||
"url": "/taskmate/taskmate-bonuses-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-bonuses-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "2548524b269c4959bc7e0e967df943af",
|
"id": "2548524b269c4959bc7e0e967df943af",
|
||||||
"url": "/taskmate/taskmate-points-display-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-points-display-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "36ada49368db4187a283fbbbef45454f",
|
"id": "36ada49368db4187a283fbbbef45454f",
|
||||||
"url": "/taskmate/taskmate-calendar-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-calendar-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "67c32687acd2497b90030ef141f4b6db",
|
"id": "67c32687acd2497b90030ef141f4b6db",
|
||||||
"url": "/taskmate/taskmate-photo-gallery-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-photo-gallery-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "6f0c8348a91f4b74a9b846ab3f62621f",
|
"id": "6f0c8348a91f4b74a9b846ab3f62621f",
|
||||||
"url": "/taskmate/taskmate-family-goal-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-family-goal-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -256,7 +256,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "8713ea9c008e4270bb28085eed5be959",
|
"id": "8713ea9c008e4270bb28085eed5be959",
|
||||||
"url": "/hacsfiles/Statistics-Graph-Chart-Card/statistics-graph-chart-card.js?hacstag=1034932856333",
|
"url": "/hacsfiles/Statistics-Graph-Chart-Card/statistics-graph-chart-card.js?hacstag=1034932856400",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -281,7 +281,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "73dbd2de03de4530b451a55bfe6c46cf",
|
"id": "73dbd2de03de4530b451a55bfe6c46cf",
|
||||||
"url": "/taskmate/taskmate-routine-card.js?v=5.0.3",
|
"url": "/taskmate/taskmate-routine-card.js?v=5.0.4",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -305,7 +305,7 @@
|
|||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "ac6b7985c72348d3bd9a3a495514e65a",
|
"id": "350bafe29e8f43749bf07fed623b0a8c",
|
||||||
"url": "/climate_scheduler/static/climate-scheduler-card.js?v=1.15.1",
|
"url": "/climate_scheduler/static/climate-scheduler-card.js?v=1.15.1",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-15
@@ -1,10 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Dashboard budget display: spent totals without a maximum (#104).
|
* Budget KPI tiles: spent totals without a maximum (#104, layout #125).
|
||||||
*
|
*
|
||||||
* With budget tracking enabled but no monthly/yearly maximum configured,
|
* With budget tracking enabled but no monthly/yearly maximum configured,
|
||||||
* the spent totals used to be invisible (a bar needs a denominator).
|
* the spent totals used to be invisible (a bar needs a denominator).
|
||||||
* Pins: spent-only lines render without a bar, a configured maximum still
|
* Since #125 the budgets render as KPI tiles in the stats strip; the #104
|
||||||
* renders the classic bar, and the mixed case shows one of each.
|
* semantics survive the move: a tile without a maximum shows the plain
|
||||||
|
* spent total and no bar, a configured maximum keeps its mini bar, and the
|
||||||
|
* mixed case shows one of each.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { expect } from "@open-wc/testing";
|
import { expect } from "@open-wc/testing";
|
||||||
@@ -25,27 +27,37 @@ function handlers(budget: Record<string, unknown>) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("dashboard budget: spent-only display (#104)", () => {
|
describe("budget KPI tiles: spent-only display (#104)", () => {
|
||||||
beforeEach(() => resetTaskSeq());
|
beforeEach(() => resetTaskSeq());
|
||||||
|
|
||||||
it("no maximum set: renders spent lines without bars", async () => {
|
it("no maximum set: tiles show spent totals without bars", async () => {
|
||||||
const { el } = await mountPanel([obj("e1", [task()])], handlers({
|
const { el } = await mountPanel([obj("e1", [task()])], handlers({
|
||||||
monthly_budget: 0, yearly_budget: 0, monthly_spent: 9, yearly_spent: 429.6,
|
monthly_budget: 0, yearly_budget: 0, monthly_spent: 9, yearly_spent: 429.6,
|
||||||
}));
|
}));
|
||||||
const items = sr(el).querySelectorAll(".budget-spent-only");
|
const tiles = sr(el).querySelectorAll(".budget-tile");
|
||||||
expect(items.length).to.equal(2);
|
expect(tiles.length).to.equal(2);
|
||||||
expect(items[0].textContent).to.contain("9.00 €");
|
expect(tiles[0].textContent).to.contain("9.00 €");
|
||||||
expect(items[1].textContent).to.contain("429.60 €");
|
expect(tiles[1].textContent).to.contain("429.60 €");
|
||||||
expect(sr(el).querySelectorAll(".budget-bar").length).to.equal(0);
|
expect(sr(el).querySelectorAll(".budget-tile-bar").length).to.equal(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("mixed: monthly maximum renders a bar, yearly stays spent-only", async () => {
|
it("mixed: monthly maximum renders a mini bar, yearly stays spent-only", async () => {
|
||||||
const { el } = await mountPanel([obj("e1", [task()])], handlers({
|
const { el } = await mountPanel([obj("e1", [task()])], handlers({
|
||||||
monthly_budget: 150, yearly_budget: 0, monthly_spent: 9, yearly_spent: 429.6,
|
monthly_budget: 150, yearly_budget: 0, monthly_spent: 9, yearly_spent: 429.6,
|
||||||
}));
|
}));
|
||||||
expect(sr(el).querySelectorAll(".budget-bar").length).to.equal(1);
|
const tiles = sr(el).querySelectorAll(".budget-tile");
|
||||||
const spentOnly = sr(el).querySelectorAll(".budget-spent-only");
|
expect(tiles.length).to.equal(2);
|
||||||
expect(spentOnly.length).to.equal(1);
|
expect(sr(el).querySelectorAll(".budget-tile-bar").length).to.equal(1);
|
||||||
expect(spentOnly[0].textContent).to.contain("429.60 €");
|
expect(tiles[0].textContent).to.contain("9.00 / 150 €");
|
||||||
|
expect(tiles[1].textContent).to.contain("429.60 €");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("tiles live INSIDE the stats strip (#125)", async () => {
|
||||||
|
const { el } = await mountPanel([obj("e1", [task()])], handlers({
|
||||||
|
monthly_budget: 150, yearly_budget: 1500, monthly_spent: 9, yearly_spent: 429.6,
|
||||||
|
}));
|
||||||
|
const strip = sr(el).querySelector(".stats-bar");
|
||||||
|
expect(strip, "stats strip rendered").to.exist;
|
||||||
|
expect(strip!.querySelectorAll(".budget-tile").length).to.equal(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -17,4 +17,5 @@ export const LS_KEYS = {
|
|||||||
groupBy: "maintenance_supporter_groupby",
|
groupBy: "maintenance_supporter_groupby",
|
||||||
objectView: "maintenance_supporter_object_view",
|
objectView: "maintenance_supporter_object_view",
|
||||||
objectsCache: "msp-objects-cache",
|
objectsCache: "msp-objects-cache",
|
||||||
|
gettingStartedDismissed: "msp-gs-dismissed",
|
||||||
} as const;
|
} as const;
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Na serveru je novější verze Maintenance Supporter — načtěte znovu pro aktualizaci panelu.",
|
"update_banner": "Na serveru je novější verze Maintenance Supporter — načtěte znovu pro aktualizaci panelu.",
|
||||||
"update_reload": "Načíst znovu",
|
"update_reload": "Načíst znovu",
|
||||||
"battery_fleet_forecast_overdue": "Předpovězené datum uplynulo — baterie stále hlásí dobrý stav. Pokud jste ji vyměnili, zaznamenejte výměnu; jinak byla předpověď mylná.",
|
"battery_fleet_forecast_overdue": "Předpovězené datum uplynulo — baterie stále hlásí dobrý stav. Pokud jste ji vyměnili, zaznamenejte výměnu; jinak byla předpověď mylná.",
|
||||||
"cost_from_parts": "Použít ≈ {amount} z dílů"
|
"cost_from_parts": "Použít ≈ {amount} z dílů",
|
||||||
|
"new_menu": "Nový",
|
||||||
|
"dismiss": "Skrýt",
|
||||||
|
"gs_label": "Začínáme — tyto tipy zmizí, jak vaše nastavení poroste",
|
||||||
|
"gs_setups_chip": "Navrhovaná nastavení: nalezeno {n} zařízení s předpřipravenými spouštěči",
|
||||||
|
"gs_adopt_chip": "{n} problémových senzorů se může stát údržbovými úkoly",
|
||||||
|
"gs_fleet_chip": "Jedno kliknutí nastaví flotilu baterií"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "En nyere version af Maintenance Supporter er på serveren — genindlæs for at opdatere panelet.",
|
"update_banner": "En nyere version af Maintenance Supporter er på serveren — genindlæs for at opdatere panelet.",
|
||||||
"update_reload": "Genindlæs",
|
"update_reload": "Genindlæs",
|
||||||
"battery_fleet_forecast_overdue": "Forudsagt dato er overskredet — batteriet melder stadig god tilstand. Hvis du har skiftet det, registrér udskiftningen; ellers ramte prognosen forbi.",
|
"battery_fleet_forecast_overdue": "Forudsagt dato er overskredet — batteriet melder stadig god tilstand. Hvis du har skiftet det, registrér udskiftningen; ellers ramte prognosen forbi.",
|
||||||
"cost_from_parts": "Brug ≈ {amount} fra dele"
|
"cost_from_parts": "Brug ≈ {amount} fra dele",
|
||||||
|
"new_menu": "Ny",
|
||||||
|
"dismiss": "Afvis",
|
||||||
|
"gs_label": "Kom godt i gang — disse tips forsvinder, efterhånden som opsætningen vokser",
|
||||||
|
"gs_setups_chip": "Foreslåede opsætninger fandt {n} enheder med forudindstillede udløsere",
|
||||||
|
"gs_adopt_chip": "{n} problemsensorer kan blive vedligeholdelsesopgaver",
|
||||||
|
"gs_fleet_chip": "Ét klik opsætter batteriflåden"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Auf dem Server läuft eine neuere Version von Maintenance Supporter — neu laden, um das Panel zu aktualisieren.",
|
"update_banner": "Auf dem Server läuft eine neuere Version von Maintenance Supporter — neu laden, um das Panel zu aktualisieren.",
|
||||||
"update_reload": "Neu laden",
|
"update_reload": "Neu laden",
|
||||||
"battery_fleet_forecast_overdue": "Prognosedatum überschritten — die Batterie meldet sich weiterhin gesund. Falls du sie gewechselt hast, trage den Wechsel nach; andernfalls lag die Prognose daneben.",
|
"battery_fleet_forecast_overdue": "Prognosedatum überschritten — die Batterie meldet sich weiterhin gesund. Falls du sie gewechselt hast, trage den Wechsel nach; andernfalls lag die Prognose daneben.",
|
||||||
"cost_from_parts": "≈ {amount} aus Teilen übernehmen"
|
"cost_from_parts": "≈ {amount} aus Teilen übernehmen",
|
||||||
|
"new_menu": "Neu",
|
||||||
|
"dismiss": "Ausblenden",
|
||||||
|
"gs_label": "Erste Schritte — diese Hinweise verschwinden, wenn dein Setup wächst",
|
||||||
|
"gs_setups_chip": "Vorgeschlagene Setups: {n} Geräte mit vorverdrahteten Auslösern gefunden",
|
||||||
|
"gs_adopt_chip": "{n} Problem-Sensoren können zu Wartungsaufgaben werden",
|
||||||
|
"gs_fleet_chip": "Ein Klick richtet die Batterieflotte ein"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "A newer version of Maintenance Supporter is on the server — reload to update the panel.",
|
"update_banner": "A newer version of Maintenance Supporter is on the server — reload to update the panel.",
|
||||||
"update_reload": "Reload",
|
"update_reload": "Reload",
|
||||||
"battery_fleet_forecast_overdue": "Predicted date passed — the battery still reports healthy. If you swapped it, record the replacement; otherwise the forecast was off.",
|
"battery_fleet_forecast_overdue": "Predicted date passed — the battery still reports healthy. If you swapped it, record the replacement; otherwise the forecast was off.",
|
||||||
"cost_from_parts": "Use ≈ {amount} from parts"
|
"cost_from_parts": "Use ≈ {amount} from parts",
|
||||||
|
"new_menu": "New",
|
||||||
|
"dismiss": "Dismiss",
|
||||||
|
"gs_label": "Getting started — these hints retire as your setup grows",
|
||||||
|
"gs_setups_chip": "Suggested setups found {n} devices with pre-wired triggers",
|
||||||
|
"gs_adopt_chip": "{n} problem sensors can become maintenance tasks",
|
||||||
|
"gs_fleet_chip": "One click sets up the battery fleet"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Hay una versión más reciente de Maintenance Supporter en el servidor — recarga para actualizar el panel.",
|
"update_banner": "Hay una versión más reciente de Maintenance Supporter en el servidor — recarga para actualizar el panel.",
|
||||||
"update_reload": "Recargar",
|
"update_reload": "Recargar",
|
||||||
"battery_fleet_forecast_overdue": "Fecha prevista superada: la batería sigue informando buen estado. Si la cambiaste, registra el reemplazo; si no, la previsión falló.",
|
"battery_fleet_forecast_overdue": "Fecha prevista superada: la batería sigue informando buen estado. Si la cambiaste, registra el reemplazo; si no, la previsión falló.",
|
||||||
"cost_from_parts": "Usar ≈ {amount} de las piezas"
|
"cost_from_parts": "Usar ≈ {amount} de las piezas",
|
||||||
|
"new_menu": "Nuevo",
|
||||||
|
"dismiss": "Descartar",
|
||||||
|
"gs_label": "Primeros pasos: estas sugerencias desaparecen a medida que crece tu configuración",
|
||||||
|
"gs_setups_chip": "Configuraciones sugeridas: {n} dispositivos con disparadores preconfigurados",
|
||||||
|
"gs_adopt_chip": "{n} sensores de problemas pueden convertirse en tareas de mantenimiento",
|
||||||
|
"gs_fleet_chip": "Un clic configura la flota de baterías"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Palvelimella on uudempi Maintenance Supporter -versio — lataa uudelleen päivittääksesi paneelin.",
|
"update_banner": "Palvelimella on uudempi Maintenance Supporter -versio — lataa uudelleen päivittääksesi paneelin.",
|
||||||
"update_reload": "Lataa uudelleen",
|
"update_reload": "Lataa uudelleen",
|
||||||
"battery_fleet_forecast_overdue": "Ennustettu päivä on ohitettu — akku ilmoittaa yhä hyvästä kunnosta. Jos vaihdoit sen, kirjaa vaihto; muuten ennuste oli pielessä.",
|
"battery_fleet_forecast_overdue": "Ennustettu päivä on ohitettu — akku ilmoittaa yhä hyvästä kunnosta. Jos vaihdoit sen, kirjaa vaihto; muuten ennuste oli pielessä.",
|
||||||
"cost_from_parts": "Käytä ≈ {amount} osista"
|
"cost_from_parts": "Käytä ≈ {amount} osista",
|
||||||
|
"new_menu": "Uusi",
|
||||||
|
"dismiss": "Hylkää",
|
||||||
|
"gs_label": "Aloitus — nämä vihjeet poistuvat asennuksen kasvaessa",
|
||||||
|
"gs_setups_chip": "Ehdotetut asetukset löysivät {n} laitetta valmiilla laukaisimilla",
|
||||||
|
"gs_adopt_chip": "{n} ongelma-anturia voi muuttua huoltotehtäviksi",
|
||||||
|
"gs_fleet_chip": "Yksi napsautus määrittää akkukannan"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Une version plus récente de Maintenance Supporter est sur le serveur — rechargez pour mettre à jour le panneau.",
|
"update_banner": "Une version plus récente de Maintenance Supporter est sur le serveur — rechargez pour mettre à jour le panneau.",
|
||||||
"update_reload": "Recharger",
|
"update_reload": "Recharger",
|
||||||
"battery_fleet_forecast_overdue": "Date prévue dépassée — la batterie se signale toujours en bon état. Si vous l'avez remplacée, enregistrez le remplacement ; sinon la prévision était erronée.",
|
"battery_fleet_forecast_overdue": "Date prévue dépassée — la batterie se signale toujours en bon état. Si vous l'avez remplacée, enregistrez le remplacement ; sinon la prévision était erronée.",
|
||||||
"cost_from_parts": "Reprendre ≈ {amount} des pièces"
|
"cost_from_parts": "Reprendre ≈ {amount} des pièces",
|
||||||
|
"new_menu": "Nouveau",
|
||||||
|
"dismiss": "Ignorer",
|
||||||
|
"gs_label": "Premiers pas — ces conseils disparaissent à mesure que votre configuration grandit",
|
||||||
|
"gs_setups_chip": "Configurations suggérées : {n} appareils avec déclencheurs pré-câblés trouvés",
|
||||||
|
"gs_adopt_chip": "{n} capteurs de problème peuvent devenir des tâches de maintenance",
|
||||||
|
"gs_fleet_chip": "Un clic configure le parc de piles"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "सर्वर पर Maintenance Supporter का नया संस्करण है — पैनल अपडेट करने के लिए पुनः लोड करें।",
|
"update_banner": "सर्वर पर Maintenance Supporter का नया संस्करण है — पैनल अपडेट करने के लिए पुनः लोड करें।",
|
||||||
"update_reload": "पुनः लोड करें",
|
"update_reload": "पुनः लोड करें",
|
||||||
"battery_fleet_forecast_overdue": "अनुमानित तिथि बीत गई — बैटरी अब भी अच्छी स्थिति बता रही है। यदि आपने इसे बदला है, तो बदलाव दर्ज करें; अन्यथा पूर्वानुमान गलत था।",
|
"battery_fleet_forecast_overdue": "अनुमानित तिथि बीत गई — बैटरी अब भी अच्छी स्थिति बता रही है। यदि आपने इसे बदला है, तो बदलाव दर्ज करें; अन्यथा पूर्वानुमान गलत था।",
|
||||||
"cost_from_parts": "पुर्ज़ों से ≈ {amount} लें"
|
"cost_from_parts": "पुर्ज़ों से ≈ {amount} लें",
|
||||||
|
"new_menu": "नया",
|
||||||
|
"dismiss": "हटाएँ",
|
||||||
|
"gs_label": "शुरुआत — सेटअप बढ़ने पर ये संकेत हट जाते हैं",
|
||||||
|
"gs_setups_chip": "सुझाए गए सेटअप: पूर्व-निर्धारित ट्रिगर वाले {n} उपकरण मिले",
|
||||||
|
"gs_adopt_chip": "{n} समस्या सेंसर रखरखाव कार्य बन सकते हैं",
|
||||||
|
"gs_fleet_chip": "एक क्लिक में बैटरी बेड़ा सेट करें"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "A Maintenance Supporter újabb verziója érhető el a szerveren — töltse újra az oldalt a panel frissítéséhez.",
|
"update_banner": "A Maintenance Supporter újabb verziója érhető el a szerveren — töltse újra az oldalt a panel frissítéséhez.",
|
||||||
"update_reload": "Újratöltés",
|
"update_reload": "Újratöltés",
|
||||||
"battery_fleet_forecast_overdue": "Az előrejelzett dátum elmúlt — az elem továbbra is jó állapotot jelez. Ha kicserélted, rögzítsd a cserét; különben az előrejelzés tévedett.",
|
"battery_fleet_forecast_overdue": "Az előrejelzett dátum elmúlt — az elem továbbra is jó állapotot jelez. Ha kicserélted, rögzítsd a cserét; különben az előrejelzés tévedett.",
|
||||||
"cost_from_parts": "≈ {amount} átvétele az alkatrészekből"
|
"cost_from_parts": "≈ {amount} átvétele az alkatrészekből",
|
||||||
|
"new_menu": "Új",
|
||||||
|
"dismiss": "Elrejtés",
|
||||||
|
"gs_label": "Első lépések — a tippek eltűnnek, ahogy a beállítás bővül",
|
||||||
|
"gs_setups_chip": "Javasolt beállítások: {n} eszköz előre bekötött triggerekkel",
|
||||||
|
"gs_adopt_chip": "{n} problémaérzékelő karbantartási feladattá válhat",
|
||||||
|
"gs_fleet_chip": "Egy kattintás beállítja az elemflottát"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Sul server è presente una versione più recente di Maintenance Supporter — ricarica per aggiornare il pannello.",
|
"update_banner": "Sul server è presente una versione più recente di Maintenance Supporter — ricarica per aggiornare il pannello.",
|
||||||
"update_reload": "Ricarica",
|
"update_reload": "Ricarica",
|
||||||
"battery_fleet_forecast_overdue": "Data prevista superata — la batteria risulta ancora in buono stato. Se l'hai sostituita, registra la sostituzione; altrimenti la previsione era errata.",
|
"battery_fleet_forecast_overdue": "Data prevista superata — la batteria risulta ancora in buono stato. Se l'hai sostituita, registra la sostituzione; altrimenti la previsione era errata.",
|
||||||
"cost_from_parts": "Usa ≈ {amount} dai ricambi"
|
"cost_from_parts": "Usa ≈ {amount} dai ricambi",
|
||||||
|
"new_menu": "Nuovo",
|
||||||
|
"dismiss": "Ignora",
|
||||||
|
"gs_label": "Primi passi — questi suggerimenti scompaiono man mano che la configurazione cresce",
|
||||||
|
"gs_setups_chip": "Configurazioni suggerite: trovati {n} dispositivi con trigger preconfigurati",
|
||||||
|
"gs_adopt_chip": "{n} sensori di problemi possono diventare attività di manutenzione",
|
||||||
|
"gs_fleet_chip": "Un clic configura la flotta di batterie"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "サーバーに新しいバージョンの Maintenance Supporter があります — 再読み込みしてパネルを更新してください。",
|
"update_banner": "サーバーに新しいバージョンの Maintenance Supporter があります — 再読み込みしてパネルを更新してください。",
|
||||||
"update_reload": "再読み込み",
|
"update_reload": "再読み込み",
|
||||||
"battery_fleet_forecast_overdue": "予測日を過ぎましたが、電池はまだ正常と報告しています。交換済みなら交換を記録してください。そうでなければ予測が外れています。",
|
"battery_fleet_forecast_overdue": "予測日を過ぎましたが、電池はまだ正常と報告しています。交換済みなら交換を記録してください。そうでなければ予測が外れています。",
|
||||||
"cost_from_parts": "部品から ≈ {amount} を適用"
|
"cost_from_parts": "部品から ≈ {amount} を適用",
|
||||||
|
"new_menu": "新規",
|
||||||
|
"dismiss": "閉じる",
|
||||||
|
"gs_label": "はじめに — セットアップが進むとこれらのヒントは消えます",
|
||||||
|
"gs_setups_chip": "推奨セットアップ:トリガー設定済みのデバイスを{n}台検出",
|
||||||
|
"gs_adopt_chip": "{n}個の問題センサーをメンテナンスタスクにできます",
|
||||||
|
"gs_fleet_chip": "ワンクリックで電池フリートを設定"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "서버에 Maintenance Supporter의 새 버전이 있습니다 — 패널을 업데이트하려면 새로 고침하세요.",
|
"update_banner": "서버에 Maintenance Supporter의 새 버전이 있습니다 — 패널을 업데이트하려면 새로 고침하세요.",
|
||||||
"update_reload": "새로 고침",
|
"update_reload": "새로 고침",
|
||||||
"battery_fleet_forecast_overdue": "예측 날짜가 지났지만 배터리는 여전히 정상으로 보고됩니다. 교체했다면 교체를 기록하세요. 아니라면 예측이 빗나간 것입니다.",
|
"battery_fleet_forecast_overdue": "예측 날짜가 지났지만 배터리는 여전히 정상으로 보고됩니다. 교체했다면 교체를 기록하세요. 아니라면 예측이 빗나간 것입니다.",
|
||||||
"cost_from_parts": "부품에서 ≈ {amount} 적용"
|
"cost_from_parts": "부품에서 ≈ {amount} 적용",
|
||||||
|
"new_menu": "새로 만들기",
|
||||||
|
"dismiss": "닫기",
|
||||||
|
"gs_label": "시작하기 — 설정이 늘어나면 이 힌트는 사라집니다",
|
||||||
|
"gs_setups_chip": "추천 설정: 트리거가 준비된 기기 {n}대 발견",
|
||||||
|
"gs_adopt_chip": "문제 센서 {n}개를 유지보수 작업으로 만들 수 있습니다",
|
||||||
|
"gs_fleet_chip": "클릭 한 번으로 배터리 플릿 설정"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "En nyere versjon av Maintenance Supporter er på serveren — last inn på nytt for å oppdatere panelet.",
|
"update_banner": "En nyere versjon av Maintenance Supporter er på serveren — last inn på nytt for å oppdatere panelet.",
|
||||||
"update_reload": "Last inn på nytt",
|
"update_reload": "Last inn på nytt",
|
||||||
"battery_fleet_forecast_overdue": "Forutsagt dato er passert — batteriet melder fortsatt god tilstand. Hvis du byttet det, registrer byttet; ellers bommet prognosen.",
|
"battery_fleet_forecast_overdue": "Forutsagt dato er passert — batteriet melder fortsatt god tilstand. Hvis du byttet det, registrer byttet; ellers bommet prognosen.",
|
||||||
"cost_from_parts": "Bruk ≈ {amount} fra deler"
|
"cost_from_parts": "Bruk ≈ {amount} fra deler",
|
||||||
|
"new_menu": "Ny",
|
||||||
|
"dismiss": "Avvis",
|
||||||
|
"gs_label": "Kom i gang — tipsene forsvinner etter hvert som oppsettet vokser",
|
||||||
|
"gs_setups_chip": "Foreslåtte oppsett fant {n} enheter med ferdigkoblede utløsere",
|
||||||
|
"gs_adopt_chip": "{n} problemsensorer kan bli vedlikeholdsoppgaver",
|
||||||
|
"gs_fleet_chip": "Ett klikk setter opp batteriflåten"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Er staat een nieuwere versie van Maintenance Supporter op de server — herlaad om het paneel bij te werken.",
|
"update_banner": "Er staat een nieuwere versie van Maintenance Supporter op de server — herlaad om het paneel bij te werken.",
|
||||||
"update_reload": "Herladen",
|
"update_reload": "Herladen",
|
||||||
"battery_fleet_forecast_overdue": "Voorspelde datum verstreken — de batterij meldt zich nog steeds gezond. Heb je hem vervangen, registreer dan de vervanging; anders zat de voorspelling ernaast.",
|
"battery_fleet_forecast_overdue": "Voorspelde datum verstreken — de batterij meldt zich nog steeds gezond. Heb je hem vervangen, registreer dan de vervanging; anders zat de voorspelling ernaast.",
|
||||||
"cost_from_parts": "≈ {amount} uit onderdelen overnemen"
|
"cost_from_parts": "≈ {amount} uit onderdelen overnemen",
|
||||||
|
"new_menu": "Nieuw",
|
||||||
|
"dismiss": "Verbergen",
|
||||||
|
"gs_label": "Aan de slag — deze tips verdwijnen naarmate je installatie groeit",
|
||||||
|
"gs_setups_chip": "Voorgestelde setups: {n} apparaten met vooraf ingestelde triggers gevonden",
|
||||||
|
"gs_adopt_chip": "{n} probleemsensoren kunnen onderhoudstaken worden",
|
||||||
|
"gs_fleet_chip": "Eén klik stelt het batterijpark in"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Na serwerze jest nowsza wersja Maintenance Supporter — załaduj ponownie, aby zaktualizować panel.",
|
"update_banner": "Na serwerze jest nowsza wersja Maintenance Supporter — załaduj ponownie, aby zaktualizować panel.",
|
||||||
"update_reload": "Załaduj ponownie",
|
"update_reload": "Załaduj ponownie",
|
||||||
"battery_fleet_forecast_overdue": "Przewidywana data minęła — bateria nadal zgłasza dobry stan. Jeśli ją wymieniono, zapisz wymianę; w przeciwnym razie prognoza była błędna.",
|
"battery_fleet_forecast_overdue": "Przewidywana data minęła — bateria nadal zgłasza dobry stan. Jeśli ją wymieniono, zapisz wymianę; w przeciwnym razie prognoza była błędna.",
|
||||||
"cost_from_parts": "Użyj ≈ {amount} z części"
|
"cost_from_parts": "Użyj ≈ {amount} z części",
|
||||||
|
"new_menu": "Nowy",
|
||||||
|
"dismiss": "Odrzuć",
|
||||||
|
"gs_label": "Pierwsze kroki — te wskazówki znikają wraz z rozwojem konfiguracji",
|
||||||
|
"gs_setups_chip": "Sugerowane konfiguracje: znaleziono {n} urządzeń z gotowymi wyzwalaczami",
|
||||||
|
"gs_adopt_chip": "{n} czujników problemów może stać się zadaniami konserwacji",
|
||||||
|
"gs_fleet_chip": "Jedno kliknięcie konfiguruje flotę baterii"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Há uma versão mais nova do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
"update_banner": "Há uma versão mais nova do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
||||||
"update_reload": "Recarregar",
|
"update_reload": "Recarregar",
|
||||||
"battery_fleet_forecast_overdue": "Data prevista ultrapassada — a bateria ainda reporta bom estado. Se você a trocou, registre a troca; caso contrário, a previsão errou.",
|
"battery_fleet_forecast_overdue": "Data prevista ultrapassada — a bateria ainda reporta bom estado. Se você a trocou, registre a troca; caso contrário, a previsão errou.",
|
||||||
"cost_from_parts": "Usar ≈ {amount} das peças"
|
"cost_from_parts": "Usar ≈ {amount} das peças",
|
||||||
|
"new_menu": "Novo",
|
||||||
|
"dismiss": "Dispensar",
|
||||||
|
"gs_label": "Primeiros passos — estas dicas somem conforme a configuração cresce",
|
||||||
|
"gs_setups_chip": "Configurações sugeridas: {n} dispositivos com gatilhos pré-configurados",
|
||||||
|
"gs_adopt_chip": "{n} sensores de problema podem virar tarefas de manutenção",
|
||||||
|
"gs_fleet_chip": "Um clique configura a frota de pilhas"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Há uma versão mais recente do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
"update_banner": "Há uma versão mais recente do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
||||||
"update_reload": "Recarregar",
|
"update_reload": "Recarregar",
|
||||||
"battery_fleet_forecast_overdue": "Data prevista ultrapassada — a bateria continua a reportar bom estado. Se a substituiu, registe a substituição; caso contrário, a previsão falhou.",
|
"battery_fleet_forecast_overdue": "Data prevista ultrapassada — a bateria continua a reportar bom estado. Se a substituiu, registe a substituição; caso contrário, a previsão falhou.",
|
||||||
"cost_from_parts": "Usar ≈ {amount} das peças"
|
"cost_from_parts": "Usar ≈ {amount} das peças",
|
||||||
|
"new_menu": "Novo",
|
||||||
|
"dismiss": "Dispensar",
|
||||||
|
"gs_label": "Primeiros passos — estas dicas desaparecem à medida que a configuração cresce",
|
||||||
|
"gs_setups_chip": "Configurações sugeridas: {n} dispositivos com gatilhos pré-configurados",
|
||||||
|
"gs_adopt_chip": "{n} sensores de problema podem tornar-se tarefas de manutenção",
|
||||||
|
"gs_fleet_chip": "Um clique configura a frota de pilhas"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "На сервере более новая версия Maintenance Supporter — перезагрузите, чтобы обновить панель.",
|
"update_banner": "На сервере более новая версия Maintenance Supporter — перезагрузите, чтобы обновить панель.",
|
||||||
"update_reload": "Перезагрузить",
|
"update_reload": "Перезагрузить",
|
||||||
"battery_fleet_forecast_overdue": "Прогнозируемая дата прошла — батарея по-прежнему сообщает о хорошем состоянии. Если вы её заменили, зафиксируйте замену; иначе прогноз оказался неверным.",
|
"battery_fleet_forecast_overdue": "Прогнозируемая дата прошла — батарея по-прежнему сообщает о хорошем состоянии. Если вы её заменили, зафиксируйте замену; иначе прогноз оказался неверным.",
|
||||||
"cost_from_parts": "Взять ≈ {amount} из запчастей"
|
"cost_from_parts": "Взять ≈ {amount} из запчастей",
|
||||||
|
"new_menu": "Создать",
|
||||||
|
"dismiss": "Скрыть",
|
||||||
|
"gs_label": "Первые шаги — эти подсказки исчезнут по мере роста настройки",
|
||||||
|
"gs_setups_chip": "Рекомендуемые настройки: найдено {n} устройств с готовыми триггерами",
|
||||||
|
"gs_adopt_chip": "{n} датчиков проблем могут стать задачами обслуживания",
|
||||||
|
"gs_fleet_chip": "Один клик настроит парк батарей"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "En nyare version av Maintenance Supporter finns på servern — ladda om för att uppdatera panelen.",
|
"update_banner": "En nyare version av Maintenance Supporter finns på servern — ladda om för att uppdatera panelen.",
|
||||||
"update_reload": "Ladda om",
|
"update_reload": "Ladda om",
|
||||||
"battery_fleet_forecast_overdue": "Förutsagt datum har passerat — batteriet rapporterar fortfarande god status. Om du bytte det, registrera bytet; annars slog prognosen fel.",
|
"battery_fleet_forecast_overdue": "Förutsagt datum har passerat — batteriet rapporterar fortfarande god status. Om du bytte det, registrera bytet; annars slog prognosen fel.",
|
||||||
"cost_from_parts": "Använd ≈ {amount} från delar"
|
"cost_from_parts": "Använd ≈ {amount} från delar",
|
||||||
|
"new_menu": "Ny",
|
||||||
|
"dismiss": "Avfärda",
|
||||||
|
"gs_label": "Kom igång — tipsen försvinner när din installation växer",
|
||||||
|
"gs_setups_chip": "Föreslagna uppsättningar hittade {n} enheter med förkopplade utlösare",
|
||||||
|
"gs_adopt_chip": "{n} problemsensorer kan bli underhållsuppgifter",
|
||||||
|
"gs_fleet_chip": "Ett klick konfigurerar batteriflottan"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Sunucuda Maintenance Supporter'ın daha yeni bir sürümü var — paneli güncellemek için sayfayı yeniden yükleyin.",
|
"update_banner": "Sunucuda Maintenance Supporter'ın daha yeni bir sürümü var — paneli güncellemek için sayfayı yeniden yükleyin.",
|
||||||
"update_reload": "Yeniden yükle",
|
"update_reload": "Yeniden yükle",
|
||||||
"battery_fleet_forecast_overdue": "Öngörülen tarih geçti — pil hâlâ sağlıklı görünüyor. Değiştirdiyseniz değişimi kaydedin; aksi halde tahmin yanılmış demektir.",
|
"battery_fleet_forecast_overdue": "Öngörülen tarih geçti — pil hâlâ sağlıklı görünüyor. Değiştirdiyseniz değişimi kaydedin; aksi halde tahmin yanılmış demektir.",
|
||||||
"cost_from_parts": "Parçalardan ≈ {amount} kullan"
|
"cost_from_parts": "Parçalardan ≈ {amount} kullan",
|
||||||
|
"new_menu": "Yeni",
|
||||||
|
"dismiss": "Kapat",
|
||||||
|
"gs_label": "Başlarken — kurulumunuz büyüdükçe bu ipuçları kaybolur",
|
||||||
|
"gs_setups_chip": "Önerilen kurulumlar {n} cihaz buldu (hazır tetikleyicilerle)",
|
||||||
|
"gs_adopt_chip": "{n} sorun sensörü bakım görevine dönüşebilir",
|
||||||
|
"gs_fleet_chip": "Tek tıkla pil filosunu kurun"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "На сервері новіша версія Maintenance Supporter — перезавантажте, щоб оновити панель.",
|
"update_banner": "На сервері новіша версія Maintenance Supporter — перезавантажте, щоб оновити панель.",
|
||||||
"update_reload": "Перезавантажити",
|
"update_reload": "Перезавантажити",
|
||||||
"battery_fleet_forecast_overdue": "Прогнозована дата минула — батарея й далі повідомляє про добрий стан. Якщо ви її замінили, зафіксуйте заміну; інакше прогноз не справдився.",
|
"battery_fleet_forecast_overdue": "Прогнозована дата минула — батарея й далі повідомляє про добрий стан. Якщо ви її замінили, зафіксуйте заміну; інакше прогноз не справдився.",
|
||||||
"cost_from_parts": "Узяти ≈ {amount} із запчастин"
|
"cost_from_parts": "Узяти ≈ {amount} із запчастин",
|
||||||
|
"new_menu": "Створити",
|
||||||
|
"dismiss": "Приховати",
|
||||||
|
"gs_label": "Перші кроки — ці підказки зникнуть у міру зростання налаштування",
|
||||||
|
"gs_setups_chip": "Рекомендовані налаштування: знайдено {n} пристроїв із готовими тригерами",
|
||||||
|
"gs_adopt_chip": "{n} датчиків проблем можуть стати завданнями обслуговування",
|
||||||
|
"gs_fleet_chip": "Один клік налаштує парк батарей"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "服务器上有更新版本的 Maintenance Supporter——请重新加载以更新面板。",
|
"update_banner": "服务器上有更新版本的 Maintenance Supporter——请重新加载以更新面板。",
|
||||||
"update_reload": "重新加载",
|
"update_reload": "重新加载",
|
||||||
"battery_fleet_forecast_overdue": "预测日期已过——电池仍报告状态良好。如果您已更换电池,请记录更换;否则说明预测有误。",
|
"battery_fleet_forecast_overdue": "预测日期已过——电池仍报告状态良好。如果您已更换电池,请记录更换;否则说明预测有误。",
|
||||||
"cost_from_parts": "采用配件合计 ≈ {amount}"
|
"cost_from_parts": "采用配件合计 ≈ {amount}",
|
||||||
|
"new_menu": "新建",
|
||||||
|
"dismiss": "忽略",
|
||||||
|
"gs_label": "入门提示——随着配置的完善,这些提示会自动消失",
|
||||||
|
"gs_setups_chip": "推荐配置发现 {n} 台设备(含预设触发器)",
|
||||||
|
"gs_adopt_chip": "{n} 个问题传感器可转换为维护任务",
|
||||||
|
"gs_fleet_chip": "一键设置电池车队"
|
||||||
}
|
}
|
||||||
@@ -141,7 +141,12 @@ export class MaintenanceSupporterPanel extends LitElement {
|
|||||||
// occasional-use — collapsed behind two toggle buttons so the task list
|
// occasional-use — collapsed behind two toggle buttons so the task list
|
||||||
// starts above the fold on phones. Desktop renders them inline as before.
|
// starts above the fold on phones. Desktop renders them inline as before.
|
||||||
@state() private _filtersOpen = false;
|
@state() private _filtersOpen = false;
|
||||||
@state() private _actionsMenuOpen = false;
|
// #125: the one "New" menu replacing the six action buttons, plus the
|
||||||
|
// getting-started chip discovery counts (fetched once, young installs only).
|
||||||
|
@state() private _newMenuOpen = false;
|
||||||
|
@state() private _gsSetupsCount = 0;
|
||||||
|
@state() private _gsAdoptCount = 0;
|
||||||
|
private _gsLoaded = false;
|
||||||
// Battery Fleet: offer one-click setup only when Battery Notes is present
|
// Battery Fleet: offer one-click setup only when Battery Notes is present
|
||||||
// and the fleet isn't set up yet.
|
// and the fleet isn't set up yet.
|
||||||
@state() private _batteryFleetSetupAvailable = false;
|
@state() private _batteryFleetSetupAvailable = false;
|
||||||
@@ -434,6 +439,10 @@ export class MaintenanceSupporterPanel extends LitElement {
|
|||||||
if (objResult) {
|
if (objResult) {
|
||||||
this._objects = hydrateObjects((objResult as { objects: MaintenanceObjectResponse[] }).objects);
|
this._objects = hydrateObjects((objResult as { objects: MaintenanceObjectResponse[] }).objects);
|
||||||
writeObjectsCache(this._objects, (statsResult as StatisticsResponse | null) ?? this._stats ?? null);
|
writeObjectsCache(this._objects, (statsResult as StatisticsResponse | null) ?? this._stats ?? null);
|
||||||
|
// #125: getting-started discovery runs AFTER the objects are known —
|
||||||
|
// judging youth on the pre-load empty list would bill every mature
|
||||||
|
// install for two discovery calls.
|
||||||
|
this._maybeLoadGettingStarted();
|
||||||
}
|
}
|
||||||
// A data refresh means the open task's history may have grown (complete,
|
// A data refresh means the open task's history may have grown (complete,
|
||||||
// history edit) — the truncated list payload can't tell, so refetch.
|
// history edit) — the truncated list payload can't tell, so refetch.
|
||||||
@@ -2137,6 +2146,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
|||||||
<span class="stat-value" style="color: #ff5722">${s.triggered}</span>
|
<span class="stat-value" style="color: #ff5722">${s.triggered}</span>
|
||||||
<span class="stat-label">${t("triggered", L)}</span>
|
<span class="stat-label">${t("triggered", L)}</span>
|
||||||
</div>
|
</div>
|
||||||
|
${this._features.budget ? this._renderBudgetTiles() : nothing}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
@@ -2296,7 +2306,6 @@ export class MaintenanceSupporterPanel extends LitElement {
|
|||||||
(this._activeViewId ? 1 : 0);
|
(this._activeViewId ? 1 : 0);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${this._features.budget ? this._renderBudgetBar() : nothing}
|
|
||||||
|
|
||||||
${this.narrow ? html`
|
${this.narrow ? html`
|
||||||
<div class="mobile-controls">
|
<div class="mobile-controls">
|
||||||
@@ -2307,15 +2316,7 @@ export class MaintenanceSupporterPanel extends LitElement {
|
|||||||
<ha-icon icon="mdi:filter-variant"></ha-icon>
|
<ha-icon icon="mdi:filter-variant"></ha-icon>
|
||||||
${t("filter_label", L)}${activeFilterCount > 0 ? ` (${activeFilterCount})` : ""}
|
${t("filter_label", L)}${activeFilterCount > 0 ? ` (${activeFilterCount})` : ""}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
${!isOperator ? html`
|
${!isOperator ? this._renderNewMenu(L) : nothing}
|
||||||
<ha-button
|
|
||||||
class="mobile-toggle ${this._actionsMenuOpen ? "active" : ""}"
|
|
||||||
@click=${() => { this._actionsMenuOpen = !this._actionsMenuOpen; }}
|
|
||||||
>
|
|
||||||
<ha-icon icon="mdi:plus"></ha-icon>
|
|
||||||
${t("add", L)}
|
|
||||||
</ha-button>
|
|
||||||
` : nothing}
|
|
||||||
</div>
|
</div>
|
||||||
` : nothing}
|
` : nothing}
|
||||||
|
|
||||||
@@ -2439,39 +2440,10 @@ export class MaintenanceSupporterPanel extends LitElement {
|
|||||||
${this._bulkMode ? t("cancel", L) : t("bulk_select", L)}
|
${this._bulkMode ? t("cancel", L) : t("bulk_select", L)}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
` : nothing}
|
` : nothing}
|
||||||
|
${!isOperator && !this.narrow ? this._renderNewMenu(L) : nothing}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${!isOperator ? html`
|
${!isOperator ? this._renderGettingStartedChips(L) : nothing}
|
||||||
<div
|
|
||||||
class="actions-bar ${this.narrow && !this._actionsMenuOpen ? "collapsed" : ""}"
|
|
||||||
@click=${() => { if (this.narrow) this._actionsMenuOpen = false; }}
|
|
||||||
>
|
|
||||||
<ha-button
|
|
||||||
@click=${() => this._ui<MaintenanceTaskDialog>("maintenance-task-dialog").then((d) => d?.openCreate("", this._objects))}
|
|
||||||
>
|
|
||||||
${t("new_task", L)}
|
|
||||||
</ha-button>
|
|
||||||
<ha-button
|
|
||||||
@click=${() => this._ui<MaintenanceObjectDialog>("maintenance-object-dialog").then((d) => d?.openCreate())}
|
|
||||||
>
|
|
||||||
${t("new_object", L)}
|
|
||||||
</ha-button>
|
|
||||||
<ha-button @click=${() => this._openTemplateGallery()}>
|
|
||||||
<ha-icon icon="mdi:view-grid-plus-outline"></ha-icon> ${t("templates_from", L)}
|
|
||||||
</ha-button>
|
|
||||||
<ha-button @click=${() => this._openAdoptProblemSensors()}>
|
|
||||||
<ha-icon icon="mdi:alert-circle-check-outline"></ha-icon> ${t("adopt_problem_button", L)}
|
|
||||||
</ha-button>
|
|
||||||
<ha-button @click=${() => this._openSuggestedSetups()}>
|
|
||||||
<ha-icon icon="mdi:auto-fix"></ha-icon> ${t("setups_button", L)}
|
|
||||||
</ha-button>
|
|
||||||
${this._batteryFleetSetupAvailable ? html`
|
|
||||||
<ha-button @click=${() => this._setupBatteryFleet()}>
|
|
||||||
<ha-icon icon="mdi:battery-sync"></ha-icon> ${t("battery_fleet_setup_button", L)}
|
|
||||||
</ha-button>
|
|
||||||
` : nothing}
|
|
||||||
</div>
|
|
||||||
` : nothing}
|
|
||||||
|
|
||||||
${rows.length === 0
|
${rows.length === 0
|
||||||
? html`
|
? html`
|
||||||
@@ -3016,50 +2988,40 @@ export class MaintenanceSupporterPanel extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderBudgetBar() {
|
/** Budget as KPI tiles in the stats strip (#125) — replaces the old
|
||||||
|
* full-width budget row. Same semantics as before, incl. #104: a budget
|
||||||
|
* WITHOUT a maximum still shows its plain spent total (no denominator,
|
||||||
|
* no bar), so "what did I spend" always has an answer. Being part of the
|
||||||
|
* strip, the tiles now show on every tab — budget is a global figure
|
||||||
|
* like the overdue count. */
|
||||||
|
private _renderBudgetTiles() {
|
||||||
const b = this._budget;
|
const b = this._budget;
|
||||||
if (!b) return nothing;
|
if (!b) return nothing;
|
||||||
const L = this._lang;
|
const L = this._lang;
|
||||||
const cs = b.currency_symbol || DEFAULT_CURRENCY_SYMBOL;
|
const cs = b.currency_symbol || DEFAULT_CURRENCY_SYMBOL;
|
||||||
const bars: { label: string; spent: number; budget: number }[] = [];
|
const tile = (label: string, spent: number, budget: number | null) => {
|
||||||
if (b.monthly_budget > 0) bars.push({ label: t("budget_monthly", L), spent: b.monthly_spent, budget: b.monthly_budget });
|
if (budget !== null) {
|
||||||
if (b.yearly_budget > 0) bars.push({ label: t("budget_yearly", L), spent: b.yearly_spent, budget: b.yearly_budget });
|
const pct = Math.min(100, Math.max(0, (spent / budget) * 100));
|
||||||
// #104: budget tracking enabled WITHOUT a maximum — the spent totals were
|
|
||||||
// invisible (a bar needs a denominator). Show plain spent lines instead,
|
|
||||||
// so "what did I spend" always has a dashboard answer.
|
|
||||||
const spentOnly: { label: string; spent: number }[] = [];
|
|
||||||
if (!(b.monthly_budget > 0)) spentOnly.push({ label: t("budget_monthly", L), spent: b.monthly_spent || 0 });
|
|
||||||
if (!(b.yearly_budget > 0)) spentOnly.push({ label: t("budget_yearly", L), spent: b.yearly_spent || 0 });
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div class="budget-bars">
|
|
||||||
${bars.map((bar) => {
|
|
||||||
const pct = Math.min(100, Math.max(0, (bar.spent / bar.budget) * 100));
|
|
||||||
const color = pct >= 100 ? "var(--error-color, #f44336)" : pct >= b.alert_threshold_pct ? "var(--warning-color, #ff9800)" : "var(--success-color, #4caf50)";
|
const color = pct >= 100 ? "var(--error-color, #f44336)" : pct >= b.alert_threshold_pct ? "var(--warning-color, #ff9800)" : "var(--success-color, #4caf50)";
|
||||||
return html`
|
return html`
|
||||||
<div class="budget-item">
|
<div class="stat-item budget-tile" title="${label}: ${spent.toFixed(2)} / ${budget.toFixed(2)} ${cs}">
|
||||||
<div class="budget-label">
|
<span class="stat-value budget-tile-value">${spent.toFixed(2)} / ${budget.toFixed(0)} ${cs}</span>
|
||||||
<span>${bar.label}</span>
|
<div class="budget-tile-bar"><div style="width:${pct}%; background:${color}"></div></div>
|
||||||
<span>${bar.spent.toFixed(2)} / ${bar.budget.toFixed(2)} ${cs}</span>
|
<span class="stat-label">${label}</span>
|
||||||
</div>
|
|
||||||
<div class="budget-bar">
|
|
||||||
<div class="budget-bar-fill" style="width:${pct}%; background:${color}"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
})}
|
}
|
||||||
${spentOnly.map(
|
return html`
|
||||||
(s) => html`
|
<div class="stat-item budget-tile" title="${label}: ${spent.toFixed(2)} ${cs}">
|
||||||
<div class="budget-item budget-spent-only">
|
<span class="stat-value budget-tile-value">${spent.toFixed(2)} ${cs}</span>
|
||||||
<div class="budget-label">
|
<span class="stat-label">${label}</span>
|
||||||
<span>${s.label}</span>
|
|
||||||
<span>${s.spent.toFixed(2)} ${cs}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
};
|
||||||
|
return html`
|
||||||
|
${tile(t("budget_monthly", L), b.monthly_spent || 0, b.monthly_budget > 0 ? b.monthly_budget : null)}
|
||||||
|
${tile(t("budget_yearly", L), b.yearly_spent || 0, b.yearly_budget > 0 ? b.yearly_budget : null)}
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderOverviewRow(row: TaskRow) {
|
private _renderOverviewRow(row: TaskRow) {
|
||||||
@@ -3314,6 +3276,150 @@ export class MaintenanceSupporterPanel extends LitElement {
|
|||||||
* Render compact task header with status chip and action buttons.
|
* Render compact task header with status chip and action buttons.
|
||||||
*/
|
*/
|
||||||
// Object-detail ⋮ menu — same click-away pattern as the task-detail menu.
|
// Object-detail ⋮ menu — same click-away pattern as the task-detail menu.
|
||||||
|
/** #125: the one "New ▾" menu replacing the six action buttons. Same
|
||||||
|
* popup pattern as the object/task menus; on narrow it lives in the
|
||||||
|
* mobile-controls row and replaced the old collapsed actions bar. */
|
||||||
|
private _renderNewMenu(L: string) {
|
||||||
|
return html`
|
||||||
|
<div class="new-menu-wrapper">
|
||||||
|
<ha-button appearance="filled" class="new-menu-button"
|
||||||
|
@click=${(e: Event) => { e.stopPropagation(); this._toggleNewMenu(); }}>
|
||||||
|
<ha-icon icon="mdi:plus"></ha-icon> ${t("new_menu", L)}
|
||||||
|
<ha-icon icon="mdi:menu-down"></ha-icon>
|
||||||
|
</ha-button>
|
||||||
|
${this._newMenuOpen ? html`
|
||||||
|
<div class="popup-menu new-menu-popup" @click=${(e: Event) => e.stopPropagation()}>
|
||||||
|
<div class="popup-menu-item" @click=${() => { this._closeNewMenu(); void this._ui<MaintenanceTaskDialog>("maintenance-task-dialog").then((d) => d?.openCreate("", this._objects)); }}>
|
||||||
|
<ha-icon icon="mdi:clipboard-plus-outline"></ha-icon> ${t("new_task", L)}
|
||||||
|
</div>
|
||||||
|
<div class="popup-menu-item" @click=${() => { this._closeNewMenu(); void this._ui<MaintenanceObjectDialog>("maintenance-object-dialog").then((d) => d?.openCreate()); }}>
|
||||||
|
<ha-icon icon="mdi:package-variant-closed-plus"></ha-icon> ${t("new_object", L).replace(/^\+\s*/, "")}
|
||||||
|
</div>
|
||||||
|
<div class="popup-menu-item" @click=${() => { this._closeNewMenu(); this._openTemplateGallery(); }}>
|
||||||
|
<ha-icon icon="mdi:view-grid-plus-outline"></ha-icon> ${t("templates_from", L)}
|
||||||
|
</div>
|
||||||
|
<div class="popup-menu-divider"></div>
|
||||||
|
<div class="popup-menu-item" @click=${() => { this._closeNewMenu(); this._openAdoptProblemSensors(); }}>
|
||||||
|
<ha-icon icon="mdi:alert-circle-check-outline"></ha-icon> ${t("adopt_problem_button", L)}
|
||||||
|
</div>
|
||||||
|
<div class="popup-menu-item" @click=${() => { this._closeNewMenu(); this._openSuggestedSetups(); }}>
|
||||||
|
<ha-icon icon="mdi:auto-fix"></ha-icon> ${t("setups_button", L)}
|
||||||
|
</div>
|
||||||
|
${this._batteryFleetSetupAvailable ? html`
|
||||||
|
<div class="popup-menu-item" @click=${() => { this._closeNewMenu(); this._setupBatteryFleet(); }}>
|
||||||
|
<ha-icon icon="mdi:battery-sync"></ha-icon> ${t("battery_fleet_setup_button", L)}
|
||||||
|
</div>
|
||||||
|
` : nothing}
|
||||||
|
</div>
|
||||||
|
` : nothing}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _toggleNewMenu(): void {
|
||||||
|
this._newMenuOpen = !this._newMenuOpen;
|
||||||
|
if (this._newMenuOpen) {
|
||||||
|
setTimeout(() => {
|
||||||
|
const handler = () => { this._newMenuOpen = false; document.removeEventListener("click", handler); };
|
||||||
|
document.addEventListener("click", handler);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _closeNewMenu(): void {
|
||||||
|
this._newMenuOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── #125: getting-started chips ──────────────────────────────────────────
|
||||||
|
// Dismissible onboarding hints while the instance is YOUNG (few objects/
|
||||||
|
// tasks — deliberately a maturity signal, not install age). The fleet chip
|
||||||
|
// is content-driven instead (available && not configured), mirroring the
|
||||||
|
// old inline button's own retirement rule. Nothing ever moves: the New
|
||||||
|
// menu is the stable home from day one; these are visibly temporary.
|
||||||
|
|
||||||
|
/** Young = the discovery hints still earn their place. Fleet objects don't
|
||||||
|
* count — a one-click fleet setup shouldn't age the install by itself. */
|
||||||
|
private _isYoungInstall(): boolean {
|
||||||
|
const objs = this._objects.filter((o) => !o.object?.battery_fleet);
|
||||||
|
const tasks = objs.reduce((n, o) => n + o.tasks.length, 0);
|
||||||
|
return objs.length < 3 && tasks < 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _gsDismissed(): Set<string> {
|
||||||
|
try {
|
||||||
|
return new Set(JSON.parse(localStorage.getItem(LS_KEYS.gettingStartedDismissed) || "[]"));
|
||||||
|
} catch {
|
||||||
|
return new Set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _dismissGettingStarted(id: string): void {
|
||||||
|
const next = this._gsDismissed();
|
||||||
|
next.add(id);
|
||||||
|
try { localStorage.setItem(LS_KEYS.gettingStartedDismissed, JSON.stringify([...next])); } catch { /* storage blocked */ }
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Discovery counts for the chips — fetched ONCE per panel life and ONLY
|
||||||
|
* while the install is young, so mature installs pay nothing. */
|
||||||
|
private _maybeLoadGettingStarted(): void {
|
||||||
|
if (this._gsLoaded || !this._isYoungInstall()) return;
|
||||||
|
this._gsLoaded = true;
|
||||||
|
this.hass.connection
|
||||||
|
.sendMessagePromise<{ setups: unknown[] }>({ type: "maintenance_supporter/integration_setups/discover" })
|
||||||
|
.then((r) => { this._gsSetupsCount = (r.setups || []).length; })
|
||||||
|
.catch(() => { this._gsSetupsCount = 0; });
|
||||||
|
this.hass.connection
|
||||||
|
.sendMessagePromise<{ sensors: unknown[] }>({ type: "maintenance_supporter/problem_sensors/discover" })
|
||||||
|
.then((r) => { this._gsAdoptCount = (r.sensors || []).length; })
|
||||||
|
.catch(() => { this._gsAdoptCount = 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderGettingStartedChips(L: string) {
|
||||||
|
const dismissed = this._gsDismissed();
|
||||||
|
const young = this._isYoungInstall();
|
||||||
|
const chips: { id: string; icon: string; text: string; run: () => void }[] = [];
|
||||||
|
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)),
|
||||||
|
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)),
|
||||||
|
run: () => this._openAdoptProblemSensors(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this._batteryFleetSetupAvailable && !dismissed.has("fleet")) {
|
||||||
|
chips.push({
|
||||||
|
id: "fleet", icon: "mdi:battery-sync",
|
||||||
|
text: t("gs_fleet_chip", L),
|
||||||
|
run: () => this._setupBatteryFleet(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (chips.length === 0) return nothing;
|
||||||
|
return html`
|
||||||
|
<div class="gs-chips-wrap">
|
||||||
|
<div class="gs-chips-label">${t("gs_label", L)}</div>
|
||||||
|
<div class="gs-chips">
|
||||||
|
${chips.map((c) => html`
|
||||||
|
<div class="gs-chip" @click=${() => c.run()}>
|
||||||
|
<ha-icon icon="${c.icon}"></ha-icon>
|
||||||
|
<span>${c.text}</span>
|
||||||
|
<span class="gs-chip-x" title="${t("dismiss", L)}"
|
||||||
|
@click=${(e: Event) => { e.stopPropagation(); this._dismissGettingStarted(c.id); }}>
|
||||||
|
<ha-icon icon="mdi:close"></ha-icon>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
private _toggleObjMenu(): void {
|
private _toggleObjMenu(): void {
|
||||||
this._objMenuOpen = !this._objMenuOpen;
|
this._objMenuOpen = !this._objMenuOpen;
|
||||||
if (this._objMenuOpen) {
|
if (this._objMenuOpen) {
|
||||||
|
|||||||
@@ -3838,9 +3838,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ip-address": {
|
"node_modules/ip-address": {
|
||||||
"version": "10.2.0",
|
"version": "10.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.4.0.tgz",
|
||||||
"integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
|
"integrity": "sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -55,10 +55,9 @@ export const panelStyles = css`
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Narrow-viewport disclosure (UX 2026-07): the collapsed classes are only
|
/* Narrow-viewport disclosure (UX 2026-07): the collapsed class is only
|
||||||
ever set when the host is narrow — desktop always renders inline. */
|
ever set when the host is narrow — desktop always renders inline. */
|
||||||
.filter-bar.collapsed,
|
.filter-bar.collapsed {
|
||||||
.actions-bar.collapsed {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,29 +67,64 @@ export const panelStyles = css`
|
|||||||
padding: 8px 0 0;
|
padding: 8px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-controls .mobile-toggle {
|
.mobile-controls .mobile-toggle,
|
||||||
|
.mobile-controls .new-menu-wrapper {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile-controls .new-menu-wrapper .new-menu-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.mobile-controls .mobile-toggle.active {
|
.mobile-controls .mobile-toggle.active {
|
||||||
--ha-button-background: var(--primary-color);
|
--ha-button-background: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions-bar {
|
/* #125: the one "New" menu that replaced the six-button actions bar. */
|
||||||
|
.new-menu-wrapper {
|
||||||
|
position: relative;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.new-menu-popup {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
min-width: 256px;
|
||||||
|
}
|
||||||
|
.new-menu-popup .popup-menu-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 10px;
|
||||||
padding: 4px 0 8px;
|
|
||||||
/* Left-aligned on purpose: flex-end mimicked the pre-v2.37 look (buttons
|
|
||||||
trailing the filter row), but on wide desktops it strands the primary
|
|
||||||
"new task" action at the far right of an otherwise empty row. */
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
}
|
||||||
|
.new-menu-popup .popup-menu-item ha-icon {
|
||||||
|
--mdc-icon-size: 18px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
:host([narrow]) .new-menu-popup { right: 0; left: auto; }
|
||||||
|
|
||||||
:host([narrow]) .actions-bar {
|
/* #125: getting-started chips — visibly temporary onboarding hints. */
|
||||||
flex-direction: column;
|
.gs-chips-wrap { margin: 2px 0 12px; }
|
||||||
align-items: stretch;
|
.gs-chips-label {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.6px;
|
||||||
|
margin-bottom: 7px;
|
||||||
}
|
}
|
||||||
|
.gs-chips { display: flex; gap: 10px; flex-wrap: wrap; }
|
||||||
|
.gs-chip {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 9px;
|
||||||
|
background: var(--secondary-background-color);
|
||||||
|
border: 1px dashed var(--divider-color);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 7px 8px 7px 13px;
|
||||||
|
font-size: 12.5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.gs-chip ha-icon { --mdc-icon-size: 16px; color: var(--primary-color); }
|
||||||
|
.gs-chip-x { display: inline-flex; padding: 0 3px; }
|
||||||
|
.gs-chip-x ha-icon { --mdc-icon-size: 14px; color: var(--secondary-text-color); }
|
||||||
|
|
||||||
.filter-field {
|
.filter-field {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -366,7 +366,10 @@ export const sharedStyles = css`
|
|||||||
label length. */
|
label length. */
|
||||||
.stats-bar {
|
.stats-bar {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(5, 1fr);
|
/* auto-fit instead of a fixed 5: with the budget feature on, two KPI
|
||||||
|
tiles join the strip (#125) — and on narrow screens the tiles wrap
|
||||||
|
instead of crushing. */
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
@@ -905,38 +908,25 @@ export const sharedStyles = css`
|
|||||||
50% { opacity: 0.7; }
|
50% { opacity: 0.7; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Budget bars */
|
/* Budget KPI tiles in the stats strip (#125) — replaced the full-width
|
||||||
.budget-bars {
|
budget-bars row. */
|
||||||
display: flex;
|
.stat-item.budget-tile .budget-tile-value {
|
||||||
gap: 16px;
|
font-size: 15px;
|
||||||
padding: 8px 16px;
|
padding-top: 5px;
|
||||||
flex-wrap: wrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
.budget-tile-bar {
|
||||||
.budget-item {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.budget-label {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.budget-bar {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 6px;
|
max-width: 130px;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
background: var(--divider-color);
|
background: var(--divider-color);
|
||||||
border-radius: 3px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
.budget-tile-bar > div {
|
||||||
.budget-bar-fill {
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 3px;
|
border-radius: 2px;
|
||||||
transition: width 0.3s;
|
transition: width 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1444,21 +1434,9 @@ export const sharedStyles = css`
|
|||||||
|
|
||||||
.weibull-info-row { flex-direction: column; gap: 8px; }
|
.weibull-info-row { flex-direction: column; gap: 8px; }
|
||||||
|
|
||||||
/* One compact line instead of two stacked rows — the bars are glanceable
|
/* Budget tiles on narrow screens (#125): slightly smaller value so the
|
||||||
info, not the page's main content (UX 2026-07). The label stacks above
|
"x / y €" pair fits the wrapped grid cell. */
|
||||||
the value: side-by-side, the yearly pair wrapped raggedly on 360px
|
.stat-item.budget-tile .budget-tile-value { font-size: 13px; }
|
||||||
screens; a uniform two-line stack reads as intended at every width. */
|
|
||||||
.budget-bars { gap: 12px; padding: 6px 8px; }
|
|
||||||
.budget-item { min-width: 0; }
|
|
||||||
.budget-label {
|
|
||||||
font-size: 11px;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 0;
|
|
||||||
}
|
|
||||||
.budget-label span { white-space: nowrap; }
|
|
||||||
.budget-bar { height: 4px; }
|
|
||||||
|
|
||||||
.group-card { min-width: 0; max-width: 100%; }
|
.group-card { min-width: 0; max-width: 100%; }
|
||||||
|
|
||||||
|
|||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Na serveru je novější verze Maintenance Supporter — načtěte znovu pro aktualizaci panelu.",
|
"update_banner": "Na serveru je novější verze Maintenance Supporter — načtěte znovu pro aktualizaci panelu.",
|
||||||
"update_reload": "Načíst znovu",
|
"update_reload": "Načíst znovu",
|
||||||
"battery_fleet_forecast_overdue": "Předpovězené datum uplynulo — baterie stále hlásí dobrý stav. Pokud jste ji vyměnili, zaznamenejte výměnu; jinak byla předpověď mylná.",
|
"battery_fleet_forecast_overdue": "Předpovězené datum uplynulo — baterie stále hlásí dobrý stav. Pokud jste ji vyměnili, zaznamenejte výměnu; jinak byla předpověď mylná.",
|
||||||
"cost_from_parts": "Použít ≈ {amount} z dílů"
|
"cost_from_parts": "Použít ≈ {amount} z dílů",
|
||||||
|
"new_menu": "Nový",
|
||||||
|
"dismiss": "Skrýt",
|
||||||
|
"gs_label": "Začínáme — tyto tipy zmizí, jak vaše nastavení poroste",
|
||||||
|
"gs_setups_chip": "Navrhovaná nastavení: nalezeno {n} zařízení s předpřipravenými spouštěči",
|
||||||
|
"gs_adopt_chip": "{n} problémových senzorů se může stát údržbovými úkoly",
|
||||||
|
"gs_fleet_chip": "Jedno kliknutí nastaví flotilu baterií"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "En nyere version af Maintenance Supporter er på serveren — genindlæs for at opdatere panelet.",
|
"update_banner": "En nyere version af Maintenance Supporter er på serveren — genindlæs for at opdatere panelet.",
|
||||||
"update_reload": "Genindlæs",
|
"update_reload": "Genindlæs",
|
||||||
"battery_fleet_forecast_overdue": "Forudsagt dato er overskredet — batteriet melder stadig god tilstand. Hvis du har skiftet det, registrér udskiftningen; ellers ramte prognosen forbi.",
|
"battery_fleet_forecast_overdue": "Forudsagt dato er overskredet — batteriet melder stadig god tilstand. Hvis du har skiftet det, registrér udskiftningen; ellers ramte prognosen forbi.",
|
||||||
"cost_from_parts": "Brug ≈ {amount} fra dele"
|
"cost_from_parts": "Brug ≈ {amount} fra dele",
|
||||||
|
"new_menu": "Ny",
|
||||||
|
"dismiss": "Afvis",
|
||||||
|
"gs_label": "Kom godt i gang — disse tips forsvinder, efterhånden som opsætningen vokser",
|
||||||
|
"gs_setups_chip": "Foreslåede opsætninger fandt {n} enheder med forudindstillede udløsere",
|
||||||
|
"gs_adopt_chip": "{n} problemsensorer kan blive vedligeholdelsesopgaver",
|
||||||
|
"gs_fleet_chip": "Ét klik opsætter batteriflåden"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Auf dem Server läuft eine neuere Version von Maintenance Supporter — neu laden, um das Panel zu aktualisieren.",
|
"update_banner": "Auf dem Server läuft eine neuere Version von Maintenance Supporter — neu laden, um das Panel zu aktualisieren.",
|
||||||
"update_reload": "Neu laden",
|
"update_reload": "Neu laden",
|
||||||
"battery_fleet_forecast_overdue": "Prognosedatum überschritten — die Batterie meldet sich weiterhin gesund. Falls du sie gewechselt hast, trage den Wechsel nach; andernfalls lag die Prognose daneben.",
|
"battery_fleet_forecast_overdue": "Prognosedatum überschritten — die Batterie meldet sich weiterhin gesund. Falls du sie gewechselt hast, trage den Wechsel nach; andernfalls lag die Prognose daneben.",
|
||||||
"cost_from_parts": "≈ {amount} aus Teilen übernehmen"
|
"cost_from_parts": "≈ {amount} aus Teilen übernehmen",
|
||||||
|
"new_menu": "Neu",
|
||||||
|
"dismiss": "Ausblenden",
|
||||||
|
"gs_label": "Erste Schritte — diese Hinweise verschwinden, wenn dein Setup wächst",
|
||||||
|
"gs_setups_chip": "Vorgeschlagene Setups: {n} Geräte mit vorverdrahteten Auslösern gefunden",
|
||||||
|
"gs_adopt_chip": "{n} Problem-Sensoren können zu Wartungsaufgaben werden",
|
||||||
|
"gs_fleet_chip": "Ein Klick richtet die Batterieflotte ein"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "A newer version of Maintenance Supporter is on the server — reload to update the panel.",
|
"update_banner": "A newer version of Maintenance Supporter is on the server — reload to update the panel.",
|
||||||
"update_reload": "Reload",
|
"update_reload": "Reload",
|
||||||
"battery_fleet_forecast_overdue": "Predicted date passed — the battery still reports healthy. If you swapped it, record the replacement; otherwise the forecast was off.",
|
"battery_fleet_forecast_overdue": "Predicted date passed — the battery still reports healthy. If you swapped it, record the replacement; otherwise the forecast was off.",
|
||||||
"cost_from_parts": "Use ≈ {amount} from parts"
|
"cost_from_parts": "Use ≈ {amount} from parts",
|
||||||
|
"new_menu": "New",
|
||||||
|
"dismiss": "Dismiss",
|
||||||
|
"gs_label": "Getting started — these hints retire as your setup grows",
|
||||||
|
"gs_setups_chip": "Suggested setups found {n} devices with pre-wired triggers",
|
||||||
|
"gs_adopt_chip": "{n} problem sensors can become maintenance tasks",
|
||||||
|
"gs_fleet_chip": "One click sets up the battery fleet"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Hay una versión más reciente de Maintenance Supporter en el servidor — recarga para actualizar el panel.",
|
"update_banner": "Hay una versión más reciente de Maintenance Supporter en el servidor — recarga para actualizar el panel.",
|
||||||
"update_reload": "Recargar",
|
"update_reload": "Recargar",
|
||||||
"battery_fleet_forecast_overdue": "Fecha prevista superada: la batería sigue informando buen estado. Si la cambiaste, registra el reemplazo; si no, la previsión falló.",
|
"battery_fleet_forecast_overdue": "Fecha prevista superada: la batería sigue informando buen estado. Si la cambiaste, registra el reemplazo; si no, la previsión falló.",
|
||||||
"cost_from_parts": "Usar ≈ {amount} de las piezas"
|
"cost_from_parts": "Usar ≈ {amount} de las piezas",
|
||||||
|
"new_menu": "Nuevo",
|
||||||
|
"dismiss": "Descartar",
|
||||||
|
"gs_label": "Primeros pasos: estas sugerencias desaparecen a medida que crece tu configuración",
|
||||||
|
"gs_setups_chip": "Configuraciones sugeridas: {n} dispositivos con disparadores preconfigurados",
|
||||||
|
"gs_adopt_chip": "{n} sensores de problemas pueden convertirse en tareas de mantenimiento",
|
||||||
|
"gs_fleet_chip": "Un clic configura la flota de baterías"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Palvelimella on uudempi Maintenance Supporter -versio — lataa uudelleen päivittääksesi paneelin.",
|
"update_banner": "Palvelimella on uudempi Maintenance Supporter -versio — lataa uudelleen päivittääksesi paneelin.",
|
||||||
"update_reload": "Lataa uudelleen",
|
"update_reload": "Lataa uudelleen",
|
||||||
"battery_fleet_forecast_overdue": "Ennustettu päivä on ohitettu — akku ilmoittaa yhä hyvästä kunnosta. Jos vaihdoit sen, kirjaa vaihto; muuten ennuste oli pielessä.",
|
"battery_fleet_forecast_overdue": "Ennustettu päivä on ohitettu — akku ilmoittaa yhä hyvästä kunnosta. Jos vaihdoit sen, kirjaa vaihto; muuten ennuste oli pielessä.",
|
||||||
"cost_from_parts": "Käytä ≈ {amount} osista"
|
"cost_from_parts": "Käytä ≈ {amount} osista",
|
||||||
|
"new_menu": "Uusi",
|
||||||
|
"dismiss": "Hylkää",
|
||||||
|
"gs_label": "Aloitus — nämä vihjeet poistuvat asennuksen kasvaessa",
|
||||||
|
"gs_setups_chip": "Ehdotetut asetukset löysivät {n} laitetta valmiilla laukaisimilla",
|
||||||
|
"gs_adopt_chip": "{n} ongelma-anturia voi muuttua huoltotehtäviksi",
|
||||||
|
"gs_fleet_chip": "Yksi napsautus määrittää akkukannan"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Une version plus récente de Maintenance Supporter est sur le serveur — rechargez pour mettre à jour le panneau.",
|
"update_banner": "Une version plus récente de Maintenance Supporter est sur le serveur — rechargez pour mettre à jour le panneau.",
|
||||||
"update_reload": "Recharger",
|
"update_reload": "Recharger",
|
||||||
"battery_fleet_forecast_overdue": "Date prévue dépassée — la batterie se signale toujours en bon état. Si vous l'avez remplacée, enregistrez le remplacement ; sinon la prévision était erronée.",
|
"battery_fleet_forecast_overdue": "Date prévue dépassée — la batterie se signale toujours en bon état. Si vous l'avez remplacée, enregistrez le remplacement ; sinon la prévision était erronée.",
|
||||||
"cost_from_parts": "Reprendre ≈ {amount} des pièces"
|
"cost_from_parts": "Reprendre ≈ {amount} des pièces",
|
||||||
|
"new_menu": "Nouveau",
|
||||||
|
"dismiss": "Ignorer",
|
||||||
|
"gs_label": "Premiers pas — ces conseils disparaissent à mesure que votre configuration grandit",
|
||||||
|
"gs_setups_chip": "Configurations suggérées : {n} appareils avec déclencheurs pré-câblés trouvés",
|
||||||
|
"gs_adopt_chip": "{n} capteurs de problème peuvent devenir des tâches de maintenance",
|
||||||
|
"gs_fleet_chip": "Un clic configure le parc de piles"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "सर्वर पर Maintenance Supporter का नया संस्करण है — पैनल अपडेट करने के लिए पुनः लोड करें।",
|
"update_banner": "सर्वर पर Maintenance Supporter का नया संस्करण है — पैनल अपडेट करने के लिए पुनः लोड करें।",
|
||||||
"update_reload": "पुनः लोड करें",
|
"update_reload": "पुनः लोड करें",
|
||||||
"battery_fleet_forecast_overdue": "अनुमानित तिथि बीत गई — बैटरी अब भी अच्छी स्थिति बता रही है। यदि आपने इसे बदला है, तो बदलाव दर्ज करें; अन्यथा पूर्वानुमान गलत था।",
|
"battery_fleet_forecast_overdue": "अनुमानित तिथि बीत गई — बैटरी अब भी अच्छी स्थिति बता रही है। यदि आपने इसे बदला है, तो बदलाव दर्ज करें; अन्यथा पूर्वानुमान गलत था।",
|
||||||
"cost_from_parts": "पुर्ज़ों से ≈ {amount} लें"
|
"cost_from_parts": "पुर्ज़ों से ≈ {amount} लें",
|
||||||
|
"new_menu": "नया",
|
||||||
|
"dismiss": "हटाएँ",
|
||||||
|
"gs_label": "शुरुआत — सेटअप बढ़ने पर ये संकेत हट जाते हैं",
|
||||||
|
"gs_setups_chip": "सुझाए गए सेटअप: पूर्व-निर्धारित ट्रिगर वाले {n} उपकरण मिले",
|
||||||
|
"gs_adopt_chip": "{n} समस्या सेंसर रखरखाव कार्य बन सकते हैं",
|
||||||
|
"gs_fleet_chip": "एक क्लिक में बैटरी बेड़ा सेट करें"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "A Maintenance Supporter újabb verziója érhető el a szerveren — töltse újra az oldalt a panel frissítéséhez.",
|
"update_banner": "A Maintenance Supporter újabb verziója érhető el a szerveren — töltse újra az oldalt a panel frissítéséhez.",
|
||||||
"update_reload": "Újratöltés",
|
"update_reload": "Újratöltés",
|
||||||
"battery_fleet_forecast_overdue": "Az előrejelzett dátum elmúlt — az elem továbbra is jó állapotot jelez. Ha kicserélted, rögzítsd a cserét; különben az előrejelzés tévedett.",
|
"battery_fleet_forecast_overdue": "Az előrejelzett dátum elmúlt — az elem továbbra is jó állapotot jelez. Ha kicserélted, rögzítsd a cserét; különben az előrejelzés tévedett.",
|
||||||
"cost_from_parts": "≈ {amount} átvétele az alkatrészekből"
|
"cost_from_parts": "≈ {amount} átvétele az alkatrészekből",
|
||||||
|
"new_menu": "Új",
|
||||||
|
"dismiss": "Elrejtés",
|
||||||
|
"gs_label": "Első lépések — a tippek eltűnnek, ahogy a beállítás bővül",
|
||||||
|
"gs_setups_chip": "Javasolt beállítások: {n} eszköz előre bekötött triggerekkel",
|
||||||
|
"gs_adopt_chip": "{n} problémaérzékelő karbantartási feladattá válhat",
|
||||||
|
"gs_fleet_chip": "Egy kattintás beállítja az elemflottát"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Sul server è presente una versione più recente di Maintenance Supporter — ricarica per aggiornare il pannello.",
|
"update_banner": "Sul server è presente una versione più recente di Maintenance Supporter — ricarica per aggiornare il pannello.",
|
||||||
"update_reload": "Ricarica",
|
"update_reload": "Ricarica",
|
||||||
"battery_fleet_forecast_overdue": "Data prevista superata — la batteria risulta ancora in buono stato. Se l'hai sostituita, registra la sostituzione; altrimenti la previsione era errata.",
|
"battery_fleet_forecast_overdue": "Data prevista superata — la batteria risulta ancora in buono stato. Se l'hai sostituita, registra la sostituzione; altrimenti la previsione era errata.",
|
||||||
"cost_from_parts": "Usa ≈ {amount} dai ricambi"
|
"cost_from_parts": "Usa ≈ {amount} dai ricambi",
|
||||||
|
"new_menu": "Nuovo",
|
||||||
|
"dismiss": "Ignora",
|
||||||
|
"gs_label": "Primi passi — questi suggerimenti scompaiono man mano che la configurazione cresce",
|
||||||
|
"gs_setups_chip": "Configurazioni suggerite: trovati {n} dispositivi con trigger preconfigurati",
|
||||||
|
"gs_adopt_chip": "{n} sensori di problemi possono diventare attività di manutenzione",
|
||||||
|
"gs_fleet_chip": "Un clic configura la flotta di batterie"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "サーバーに新しいバージョンの Maintenance Supporter があります — 再読み込みしてパネルを更新してください。",
|
"update_banner": "サーバーに新しいバージョンの Maintenance Supporter があります — 再読み込みしてパネルを更新してください。",
|
||||||
"update_reload": "再読み込み",
|
"update_reload": "再読み込み",
|
||||||
"battery_fleet_forecast_overdue": "予測日を過ぎましたが、電池はまだ正常と報告しています。交換済みなら交換を記録してください。そうでなければ予測が外れています。",
|
"battery_fleet_forecast_overdue": "予測日を過ぎましたが、電池はまだ正常と報告しています。交換済みなら交換を記録してください。そうでなければ予測が外れています。",
|
||||||
"cost_from_parts": "部品から ≈ {amount} を適用"
|
"cost_from_parts": "部品から ≈ {amount} を適用",
|
||||||
|
"new_menu": "新規",
|
||||||
|
"dismiss": "閉じる",
|
||||||
|
"gs_label": "はじめに — セットアップが進むとこれらのヒントは消えます",
|
||||||
|
"gs_setups_chip": "推奨セットアップ:トリガー設定済みのデバイスを{n}台検出",
|
||||||
|
"gs_adopt_chip": "{n}個の問題センサーをメンテナンスタスクにできます",
|
||||||
|
"gs_fleet_chip": "ワンクリックで電池フリートを設定"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "서버에 Maintenance Supporter의 새 버전이 있습니다 — 패널을 업데이트하려면 새로 고침하세요.",
|
"update_banner": "서버에 Maintenance Supporter의 새 버전이 있습니다 — 패널을 업데이트하려면 새로 고침하세요.",
|
||||||
"update_reload": "새로 고침",
|
"update_reload": "새로 고침",
|
||||||
"battery_fleet_forecast_overdue": "예측 날짜가 지났지만 배터리는 여전히 정상으로 보고됩니다. 교체했다면 교체를 기록하세요. 아니라면 예측이 빗나간 것입니다.",
|
"battery_fleet_forecast_overdue": "예측 날짜가 지났지만 배터리는 여전히 정상으로 보고됩니다. 교체했다면 교체를 기록하세요. 아니라면 예측이 빗나간 것입니다.",
|
||||||
"cost_from_parts": "부품에서 ≈ {amount} 적용"
|
"cost_from_parts": "부품에서 ≈ {amount} 적용",
|
||||||
|
"new_menu": "새로 만들기",
|
||||||
|
"dismiss": "닫기",
|
||||||
|
"gs_label": "시작하기 — 설정이 늘어나면 이 힌트는 사라집니다",
|
||||||
|
"gs_setups_chip": "추천 설정: 트리거가 준비된 기기 {n}대 발견",
|
||||||
|
"gs_adopt_chip": "문제 센서 {n}개를 유지보수 작업으로 만들 수 있습니다",
|
||||||
|
"gs_fleet_chip": "클릭 한 번으로 배터리 플릿 설정"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "En nyere versjon av Maintenance Supporter er på serveren — last inn på nytt for å oppdatere panelet.",
|
"update_banner": "En nyere versjon av Maintenance Supporter er på serveren — last inn på nytt for å oppdatere panelet.",
|
||||||
"update_reload": "Last inn på nytt",
|
"update_reload": "Last inn på nytt",
|
||||||
"battery_fleet_forecast_overdue": "Forutsagt dato er passert — batteriet melder fortsatt god tilstand. Hvis du byttet det, registrer byttet; ellers bommet prognosen.",
|
"battery_fleet_forecast_overdue": "Forutsagt dato er passert — batteriet melder fortsatt god tilstand. Hvis du byttet det, registrer byttet; ellers bommet prognosen.",
|
||||||
"cost_from_parts": "Bruk ≈ {amount} fra deler"
|
"cost_from_parts": "Bruk ≈ {amount} fra deler",
|
||||||
|
"new_menu": "Ny",
|
||||||
|
"dismiss": "Avvis",
|
||||||
|
"gs_label": "Kom i gang — tipsene forsvinner etter hvert som oppsettet vokser",
|
||||||
|
"gs_setups_chip": "Foreslåtte oppsett fant {n} enheter med ferdigkoblede utløsere",
|
||||||
|
"gs_adopt_chip": "{n} problemsensorer kan bli vedlikeholdsoppgaver",
|
||||||
|
"gs_fleet_chip": "Ett klikk setter opp batteriflåten"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Er staat een nieuwere versie van Maintenance Supporter op de server — herlaad om het paneel bij te werken.",
|
"update_banner": "Er staat een nieuwere versie van Maintenance Supporter op de server — herlaad om het paneel bij te werken.",
|
||||||
"update_reload": "Herladen",
|
"update_reload": "Herladen",
|
||||||
"battery_fleet_forecast_overdue": "Voorspelde datum verstreken — de batterij meldt zich nog steeds gezond. Heb je hem vervangen, registreer dan de vervanging; anders zat de voorspelling ernaast.",
|
"battery_fleet_forecast_overdue": "Voorspelde datum verstreken — de batterij meldt zich nog steeds gezond. Heb je hem vervangen, registreer dan de vervanging; anders zat de voorspelling ernaast.",
|
||||||
"cost_from_parts": "≈ {amount} uit onderdelen overnemen"
|
"cost_from_parts": "≈ {amount} uit onderdelen overnemen",
|
||||||
|
"new_menu": "Nieuw",
|
||||||
|
"dismiss": "Verbergen",
|
||||||
|
"gs_label": "Aan de slag — deze tips verdwijnen naarmate je installatie groeit",
|
||||||
|
"gs_setups_chip": "Voorgestelde setups: {n} apparaten met vooraf ingestelde triggers gevonden",
|
||||||
|
"gs_adopt_chip": "{n} probleemsensoren kunnen onderhoudstaken worden",
|
||||||
|
"gs_fleet_chip": "Eén klik stelt het batterijpark in"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Na serwerze jest nowsza wersja Maintenance Supporter — załaduj ponownie, aby zaktualizować panel.",
|
"update_banner": "Na serwerze jest nowsza wersja Maintenance Supporter — załaduj ponownie, aby zaktualizować panel.",
|
||||||
"update_reload": "Załaduj ponownie",
|
"update_reload": "Załaduj ponownie",
|
||||||
"battery_fleet_forecast_overdue": "Przewidywana data minęła — bateria nadal zgłasza dobry stan. Jeśli ją wymieniono, zapisz wymianę; w przeciwnym razie prognoza była błędna.",
|
"battery_fleet_forecast_overdue": "Przewidywana data minęła — bateria nadal zgłasza dobry stan. Jeśli ją wymieniono, zapisz wymianę; w przeciwnym razie prognoza była błędna.",
|
||||||
"cost_from_parts": "Użyj ≈ {amount} z części"
|
"cost_from_parts": "Użyj ≈ {amount} z części",
|
||||||
|
"new_menu": "Nowy",
|
||||||
|
"dismiss": "Odrzuć",
|
||||||
|
"gs_label": "Pierwsze kroki — te wskazówki znikają wraz z rozwojem konfiguracji",
|
||||||
|
"gs_setups_chip": "Sugerowane konfiguracje: znaleziono {n} urządzeń z gotowymi wyzwalaczami",
|
||||||
|
"gs_adopt_chip": "{n} czujników problemów może stać się zadaniami konserwacji",
|
||||||
|
"gs_fleet_chip": "Jedno kliknięcie konfiguruje flotę baterii"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Há uma versão mais nova do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
"update_banner": "Há uma versão mais nova do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
||||||
"update_reload": "Recarregar",
|
"update_reload": "Recarregar",
|
||||||
"battery_fleet_forecast_overdue": "Data prevista ultrapassada — a bateria ainda reporta bom estado. Se você a trocou, registre a troca; caso contrário, a previsão errou.",
|
"battery_fleet_forecast_overdue": "Data prevista ultrapassada — a bateria ainda reporta bom estado. Se você a trocou, registre a troca; caso contrário, a previsão errou.",
|
||||||
"cost_from_parts": "Usar ≈ {amount} das peças"
|
"cost_from_parts": "Usar ≈ {amount} das peças",
|
||||||
|
"new_menu": "Novo",
|
||||||
|
"dismiss": "Dispensar",
|
||||||
|
"gs_label": "Primeiros passos — estas dicas somem conforme a configuração cresce",
|
||||||
|
"gs_setups_chip": "Configurações sugeridas: {n} dispositivos com gatilhos pré-configurados",
|
||||||
|
"gs_adopt_chip": "{n} sensores de problema podem virar tarefas de manutenção",
|
||||||
|
"gs_fleet_chip": "Um clique configura a frota de pilhas"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Há uma versão mais recente do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
"update_banner": "Há uma versão mais recente do Maintenance Supporter no servidor — recarregue para atualizar o painel.",
|
||||||
"update_reload": "Recarregar",
|
"update_reload": "Recarregar",
|
||||||
"battery_fleet_forecast_overdue": "Data prevista ultrapassada — a bateria continua a reportar bom estado. Se a substituiu, registe a substituição; caso contrário, a previsão falhou.",
|
"battery_fleet_forecast_overdue": "Data prevista ultrapassada — a bateria continua a reportar bom estado. Se a substituiu, registe a substituição; caso contrário, a previsão falhou.",
|
||||||
"cost_from_parts": "Usar ≈ {amount} das peças"
|
"cost_from_parts": "Usar ≈ {amount} das peças",
|
||||||
|
"new_menu": "Novo",
|
||||||
|
"dismiss": "Dispensar",
|
||||||
|
"gs_label": "Primeiros passos — estas dicas desaparecem à medida que a configuração cresce",
|
||||||
|
"gs_setups_chip": "Configurações sugeridas: {n} dispositivos com gatilhos pré-configurados",
|
||||||
|
"gs_adopt_chip": "{n} sensores de problema podem tornar-se tarefas de manutenção",
|
||||||
|
"gs_fleet_chip": "Um clique configura a frota de pilhas"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "На сервере более новая версия Maintenance Supporter — перезагрузите, чтобы обновить панель.",
|
"update_banner": "На сервере более новая версия Maintenance Supporter — перезагрузите, чтобы обновить панель.",
|
||||||
"update_reload": "Перезагрузить",
|
"update_reload": "Перезагрузить",
|
||||||
"battery_fleet_forecast_overdue": "Прогнозируемая дата прошла — батарея по-прежнему сообщает о хорошем состоянии. Если вы её заменили, зафиксируйте замену; иначе прогноз оказался неверным.",
|
"battery_fleet_forecast_overdue": "Прогнозируемая дата прошла — батарея по-прежнему сообщает о хорошем состоянии. Если вы её заменили, зафиксируйте замену; иначе прогноз оказался неверным.",
|
||||||
"cost_from_parts": "Взять ≈ {amount} из запчастей"
|
"cost_from_parts": "Взять ≈ {amount} из запчастей",
|
||||||
|
"new_menu": "Создать",
|
||||||
|
"dismiss": "Скрыть",
|
||||||
|
"gs_label": "Первые шаги — эти подсказки исчезнут по мере роста настройки",
|
||||||
|
"gs_setups_chip": "Рекомендуемые настройки: найдено {n} устройств с готовыми триггерами",
|
||||||
|
"gs_adopt_chip": "{n} датчиков проблем могут стать задачами обслуживания",
|
||||||
|
"gs_fleet_chip": "Один клик настроит парк батарей"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "En nyare version av Maintenance Supporter finns på servern — ladda om för att uppdatera panelen.",
|
"update_banner": "En nyare version av Maintenance Supporter finns på servern — ladda om för att uppdatera panelen.",
|
||||||
"update_reload": "Ladda om",
|
"update_reload": "Ladda om",
|
||||||
"battery_fleet_forecast_overdue": "Förutsagt datum har passerat — batteriet rapporterar fortfarande god status. Om du bytte det, registrera bytet; annars slog prognosen fel.",
|
"battery_fleet_forecast_overdue": "Förutsagt datum har passerat — batteriet rapporterar fortfarande god status. Om du bytte det, registrera bytet; annars slog prognosen fel.",
|
||||||
"cost_from_parts": "Använd ≈ {amount} från delar"
|
"cost_from_parts": "Använd ≈ {amount} från delar",
|
||||||
|
"new_menu": "Ny",
|
||||||
|
"dismiss": "Avfärda",
|
||||||
|
"gs_label": "Kom igång — tipsen försvinner när din installation växer",
|
||||||
|
"gs_setups_chip": "Föreslagna uppsättningar hittade {n} enheter med förkopplade utlösare",
|
||||||
|
"gs_adopt_chip": "{n} problemsensorer kan bli underhållsuppgifter",
|
||||||
|
"gs_fleet_chip": "Ett klick konfigurerar batteriflottan"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "Sunucuda Maintenance Supporter'ın daha yeni bir sürümü var — paneli güncellemek için sayfayı yeniden yükleyin.",
|
"update_banner": "Sunucuda Maintenance Supporter'ın daha yeni bir sürümü var — paneli güncellemek için sayfayı yeniden yükleyin.",
|
||||||
"update_reload": "Yeniden yükle",
|
"update_reload": "Yeniden yükle",
|
||||||
"battery_fleet_forecast_overdue": "Öngörülen tarih geçti — pil hâlâ sağlıklı görünüyor. Değiştirdiyseniz değişimi kaydedin; aksi halde tahmin yanılmış demektir.",
|
"battery_fleet_forecast_overdue": "Öngörülen tarih geçti — pil hâlâ sağlıklı görünüyor. Değiştirdiyseniz değişimi kaydedin; aksi halde tahmin yanılmış demektir.",
|
||||||
"cost_from_parts": "Parçalardan ≈ {amount} kullan"
|
"cost_from_parts": "Parçalardan ≈ {amount} kullan",
|
||||||
|
"new_menu": "Yeni",
|
||||||
|
"dismiss": "Kapat",
|
||||||
|
"gs_label": "Başlarken — kurulumunuz büyüdükçe bu ipuçları kaybolur",
|
||||||
|
"gs_setups_chip": "Önerilen kurulumlar {n} cihaz buldu (hazır tetikleyicilerle)",
|
||||||
|
"gs_adopt_chip": "{n} sorun sensörü bakım görevine dönüşebilir",
|
||||||
|
"gs_fleet_chip": "Tek tıkla pil filosunu kurun"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "На сервері новіша версія Maintenance Supporter — перезавантажте, щоб оновити панель.",
|
"update_banner": "На сервері новіша версія Maintenance Supporter — перезавантажте, щоб оновити панель.",
|
||||||
"update_reload": "Перезавантажити",
|
"update_reload": "Перезавантажити",
|
||||||
"battery_fleet_forecast_overdue": "Прогнозована дата минула — батарея й далі повідомляє про добрий стан. Якщо ви її замінили, зафіксуйте заміну; інакше прогноз не справдився.",
|
"battery_fleet_forecast_overdue": "Прогнозована дата минула — батарея й далі повідомляє про добрий стан. Якщо ви її замінили, зафіксуйте заміну; інакше прогноз не справдився.",
|
||||||
"cost_from_parts": "Узяти ≈ {amount} із запчастин"
|
"cost_from_parts": "Узяти ≈ {amount} із запчастин",
|
||||||
|
"new_menu": "Створити",
|
||||||
|
"dismiss": "Приховати",
|
||||||
|
"gs_label": "Перші кроки — ці підказки зникнуть у міру зростання налаштування",
|
||||||
|
"gs_setups_chip": "Рекомендовані налаштування: знайдено {n} пристроїв із готовими тригерами",
|
||||||
|
"gs_adopt_chip": "{n} датчиків проблем можуть стати завданнями обслуговування",
|
||||||
|
"gs_fleet_chip": "Один клік налаштує парк батарей"
|
||||||
}
|
}
|
||||||
@@ -835,5 +835,11 @@
|
|||||||
"update_banner": "服务器上有更新版本的 Maintenance Supporter——请重新加载以更新面板。",
|
"update_banner": "服务器上有更新版本的 Maintenance Supporter——请重新加载以更新面板。",
|
||||||
"update_reload": "重新加载",
|
"update_reload": "重新加载",
|
||||||
"battery_fleet_forecast_overdue": "预测日期已过——电池仍报告状态良好。如果您已更换电池,请记录更换;否则说明预测有误。",
|
"battery_fleet_forecast_overdue": "预测日期已过——电池仍报告状态良好。如果您已更换电池,请记录更换;否则说明预测有误。",
|
||||||
"cost_from_parts": "采用配件合计 ≈ {amount}"
|
"cost_from_parts": "采用配件合计 ≈ {amount}",
|
||||||
|
"new_menu": "新建",
|
||||||
|
"dismiss": "忽略",
|
||||||
|
"gs_label": "入门提示——随着配置的完善,这些提示会自动消失",
|
||||||
|
"gs_setups_chip": "推荐配置发现 {n} 台设备(含预设触发器)",
|
||||||
|
"gs_adopt_chip": "{n} 个问题传感器可转换为维护任务",
|
||||||
|
"gs_fleet_chip": "一键设置电池车队"
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*! maintenance_supporter frontend 2.53.0 */
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
var it=Object.defineProperty;var lt=Object.getOwnPropertyDescriptor;var x=(a,e,t,o)=>{for(var r=o>1?void 0:o?lt(e,t):e,n=a.length-1,s;n>=0;n--)(s=a[n])&&(r=(o?s(e,t,r):s(r))||r);return o&&r&&it(e,t,r),r};var ee=globalThis,te=ee.ShadowRoot&&(ee.ShadyCSS===void 0||ee.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,de=Symbol(),Se=new WeakMap,I=class{constructor(e,t,o){if(this._$cssResult$=!0,o!==de)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o,t=this.t;if(te&&e===void 0){let o=t!==void 0&&t.length===1;o&&(e=Se.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),o&&Se.set(t,e))}return e}toString(){return this.cssText}},$e=a=>new I(typeof a=="string"?a:a+"",void 0,de),k=(a,...e)=>{let t=a.length===1?a[0]:e.reduce((o,r,n)=>o+(s=>{if(s._$cssResult$===!0)return s.cssText;if(typeof s=="number")return s;throw Error("Value passed to 'css' function must be a 'css' function result: "+s+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(r)+a[n+1],a[0]);return new I(t,a,de)},Ae=(a,e)=>{if(te)a.adoptedStyleSheets=e.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of e){let o=document.createElement("style"),r=ee.litNonce;r!==void 0&&o.setAttribute("nonce",r),o.textContent=t.cssText,a.appendChild(o)}},pe=te?a=>a:a=>a instanceof CSSStyleSheet?(e=>{let t="";for(let o of e.cssRules)t+=o.cssText;return $e(t)})(a):a;var{is:ct,defineProperty:dt,getOwnPropertyDescriptor:pt,getOwnPropertyNames:ut,getOwnPropertySymbols:_t,getPrototypeOf:ht}=Object,oe=globalThis,je=oe.trustedTypes,gt=je?je.emptyScript:"",ft=oe.reactiveElementPolyfillSupport,F=(a,e)=>a,B={toAttribute(a,e){switch(e){case Boolean:a=a?gt:null;break;case Object:case Array:a=a==null?a:JSON.stringify(a)}return a},fromAttribute(a,e){let t=a;switch(e){case Boolean:t=a!==null;break;case Number:t=a===null?null:Number(a);break;case Object:case Array:try{t=JSON.parse(a)}catch{t=null}}return t}},re=(a,e)=>!ct(a,e),Ce={attribute:!0,type:String,converter:B,reflect:!1,useDefault:!1,hasChanged:re};Symbol.metadata??=Symbol("metadata"),oe.litPropertyMetadata??=new WeakMap;var S=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=Ce){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){let o=Symbol(),r=this.getPropertyDescriptor(e,o,t);r!==void 0&&dt(this.prototype,e,r)}}static getPropertyDescriptor(e,t,o){let{get:r,set:n}=pt(this.prototype,e)??{get(){return this[t]},set(s){this[t]=s}};return{get:r,set(s){let l=r?.call(this);n?.call(this,s),this.requestUpdate(e,l,o)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??Ce}static _$Ei(){if(this.hasOwnProperty(F("elementProperties")))return;let e=ht(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(F("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(F("properties"))){let t=this.properties,o=[...ut(t),..._t(t)];for(let r of o)this.createProperty(r,t[r])}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[o,r]of t)this.elementProperties.set(o,r)}this._$Eh=new Map;for(let[t,o]of this.elementProperties){let r=this._$Eu(t,o);r!==void 0&&this._$Eh.set(r,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let o=new Set(e.flat(1/0).reverse());for(let r of o)t.unshift(pe(r))}else e!==void 0&&t.push(pe(e));return t}static _$Eu(e,t){let o=t.attribute;return o===!1?void 0:typeof o=="string"?o:typeof e=="string"?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let o of t.keys())this.hasOwnProperty(o)&&(e.set(o,this[o]),delete this[o]);e.size>0&&(this._$Ep=e)}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return Ae(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,o){this._$AK(e,o)}_$ET(e,t){let o=this.constructor.elemenLine truncated
|
var it=Object.defineProperty;var lt=Object.getOwnPropertyDescriptor;var w=(a,e,t,o)=>{for(var r=o>1?void 0:o?lt(e,t):e,n=a.length-1,s;n>=0;n--)(s=a[n])&&(r=(o?s(e,t,r):s(r))||r);return o&&r&&it(e,t,r),r};var ee=globalThis,te=ee.ShadowRoot&&(ee.ShadyCSS===void 0||ee.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,de=Symbol(),Se=new WeakMap,q=class{constructor(e,t,o){if(this._$cssResult$=!0,o!==de)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o,t=this.t;if(te&&e===void 0){let o=t!==void 0&&t.length===1;o&&(e=Se.get(t)),e===void 0&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),o&&Se.set(t,e))}return e}toString(){return this.cssText}},$e=a=>new q(typeof a=="string"?a:a+"",void 0,de),k=(a,...e)=>{let t=a.length===1?a[0]:e.reduce((o,r,n)=>o+(s=>{if(s._$cssResult$===!0)return s.cssText;if(typeof s=="number")return s;throw Error("Value passed to 'css' function must be a 'css' function result: "+s+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(r)+a[n+1],a[0]);return new q(t,a,de)},Ae=(a,e)=>{if(te)a.adoptedStyleSheets=e.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of e){let o=document.createElement("style"),r=ee.litNonce;r!==void 0&&o.setAttribute("nonce",r),o.textContent=t.cssText,a.appendChild(o)}},pe=te?a=>a:a=>a instanceof CSSStyleSheet?(e=>{let t="";for(let o of e.cssRules)t+=o.cssText;return $e(t)})(a):a;var{is:ct,defineProperty:dt,getOwnPropertyDescriptor:pt,getOwnPropertyNames:ut,getOwnPropertySymbols:_t,getPrototypeOf:ht}=Object,oe=globalThis,je=oe.trustedTypes,gt=je?je.emptyScript:"",ft=oe.reactiveElementPolyfillSupport,F=(a,e)=>a,B={toAttribute(a,e){switch(e){case Boolean:a=a?gt:null;break;case Object:case Array:a=a==null?a:JSON.stringify(a)}return a},fromAttribute(a,e){let t=a;switch(e){case Boolean:t=a!==null;break;case Number:t=a===null?null:Number(a);break;case Object:case Array:try{t=JSON.parse(a)}catch{t=null}}return t}},re=(a,e)=>!ct(a,e),Ce={attribute:!0,type:String,converter:B,reflect:!1,useDefault:!1,hasChanged:re};Symbol.metadata??=Symbol("metadata"),oe.litPropertyMetadata??=new WeakMap;var S=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=Ce){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){let o=Symbol(),r=this.getPropertyDescriptor(e,o,t);r!==void 0&&dt(this.prototype,e,r)}}static getPropertyDescriptor(e,t,o){let{get:r,set:n}=pt(this.prototype,e)??{get(){return this[t]},set(s){this[t]=s}};return{get:r,set(s){let l=r?.call(this);n?.call(this,s),this.requestUpdate(e,l,o)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??Ce}static _$Ei(){if(this.hasOwnProperty(F("elementProperties")))return;let e=ht(this);e.finalize(),e.l!==void 0&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(F("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(F("properties"))){let t=this.properties,o=[...ut(t),..._t(t)];for(let r of o)this.createProperty(r,t[r])}let e=this[Symbol.metadata];if(e!==null){let t=litPropertyMetadata.get(e);if(t!==void 0)for(let[o,r]of t)this.elementProperties.set(o,r)}this._$Eh=new Map;for(let[t,o]of this.elementProperties){let r=this._$Eu(t,o);r!==void 0&&this._$Eh.set(r,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){let t=[];if(Array.isArray(e)){let o=new Set(e.flat(1/0).reverse());for(let r of o)t.unshift(pe(r))}else e!==void 0&&t.push(pe(e));return t}static _$Eu(e,t){let o=t.attribute;return o===!1?void 0:typeof o=="string"?o:typeof e=="string"?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),this.renderRoot!==void 0&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){let e=new Map,t=this.constructor.elementProperties;for(let o of t.keys())this.hasOwnProperty(o)&&(e.set(o,this[o]),delete this[o]);e.size>0&&(this._$Ep=e)}createRenderRoot(){let e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return Ae(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,o){this._$AK(e,o)}_$ET(e,t){let o=this.constructor.elemenLine truncated
|
||||||
\f\r]`,W=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,De=/-->/g,Ne=/>/g,C=RegExp(`>|${ue}(?:([^\\s"'>=/]+)(${ue}*=${ue}*(?:[^
|
\f\r]`,W=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,De=/-->/g,Ne=/>/g,C=RegExp(`>|${ue}(?:([^\\s"'>=/]+)(${ue}*=${ue}*(?:[^
|
||||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),Re=/'/g,Pe=/"/g,Me=/^(?:script|style|textarea|title)$/i,ve=a=>(e,...t)=>({_$litType$:a,strings:e,values:t}),m=ve(1),qt=ve(2),It=ve(3),D=Symbol.for("lit-noChange"),g=Symbol.for("lit-nothing"),ze=new WeakMap,E=T.createTreeWalker(T,129);function Ue(a,e){if(!ye(a)||!a.hasOwnProperty("raw"))throw Error("invalid template strings array");return Te!==void 0?Te.createHTML(e):e}var yt=(a,e)=>{let t=a.length-1,o=[],r,n=e===2?"<svg>":e===3?"<math>":"",s=W;for(let l=0;l<t;l++){let d=a[l],p,u,c=-1,_=0;for(;_<d.length&&(s.lastIndex=_,u=s.exec(d),u!==null);)_=s.lastIndex,s===W?u[1]==="!--"?s=De:u[1]!==void 0?s=Ne:u[2]!==void 0?(Me.test(u[2])&&(r=RegExp("</"+u[2],"g")),s=C):u[3]!==void 0&&(s=C):s===C?u[0]===">"?(s=r??W,c=-1):u[1]===void 0?c=-2:(c=s.lastIndex-u[2].length,p=u[1],s=u[3]===void 0?C:u[3]==='"'?Pe:Re):s===Pe||s===Re?s=C:s===De||s===Ne?s=W:(s=C,r=void 0);let h=s===C&&a[l+1].startsWith("/>")?" ":"";n+=s===W?d+mt:c>=0?(o.push(p),d.slice(0,c)+Oe+d.slice(c)+A+h):d+A+(c===-2?l:h)}return[Ue(a,n+(a[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),o]},V=class a{constructor({strings:e,_$litType$:t},o){let r;this.parts=[];let n=0,s=0,l=e.length-1,d=this.parts,[p,u]=yt(e,t);if(this.el=a.createElement(p,o),E.currentNode=this.el.content,t===2||t===3){let c=this.el.content.firstChild;c.replaceWith(...c.childNodes)}for(;(r=E.nextNode())!==null&&d.length<l;){if(r.nodeType===1){if(r.hasAttributes())for(let c of r.getAttributeNames())if(c.endsWith(Oe)){let _=u[s++],h=r.getAttribute(c).split(A),b=/([.?@])?(.*)/.exec(_);d.push({type:1,index:n,name:b[2],strings:h,ctor:b[1]==="."?he:b[1]==="?"?ge:b[1]==="@"?fe:O}),r.removeAttribute(c)}else c.startsWith(A)&&(d.push({type:6,index:n}),r.removeAttribute(c));if(Me.test(r.tagName)){let c=r.textContent.split(A),_=c.length-1;if(_>0){r.textContent=ae?ae.emptyScript:"";for(let h=0;h<_;h++)r.append(c[h],Y()),E.nextNode(),d.push({type:2,index:++n});r.append(c[_],Y())}}}else if(r.nodeType===8)if(r.data===Le)d.push({type:2,index:n});else{let c=-1;for(;(c=r.data.indexOf(A,c+1))!==-1;)d.push({type:7,index:n}),c+=A.length-1}n++}}static createElement(e,t){let o=T.createElement("template");return o.innerHTML=e,o}};function z(a,e,t=a,o){if(e===D)return e;let r=o!==void 0?t._$Co?.[o]:t._$Cl,n=G(e)?void 0:e._$litDirective$;return r?.constructor!==n&&(r?._$AO?.(!1),n===void 0?r=void 0:(r=new n(a),r._$AT(a,t,o)),o!==void 0?(t._$Co??=[])[o]=r:t._$Cl=r),r!==void 0&&(e=z(a,r._$AS(a,e.values),r,o)),e}var _e=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:o}=this._$AD,r=(e?.creationScope??T).importNode(t,!0);E.currentNode=r;let n=E.nextNode(),s=0,l=0,d=o[0];for(;d!==void 0;){if(s===d.index){let p;d.type===2?p=new K(n,n.nextSibling,this,e):d.type===1?p=new d.ctor(n,d.name,d.strings,this,e):d.type===6&&(p=new me(n,this,e)),this._$AV.push(p),d=o[++l]}s!==d?.index&&(n=E.nextNode(),s++)}return E.currentNode=T,r}p(e){let t=0;for(let o of this._$AV)o!==void 0&&(o.strings!==void 0?(o._$AI(e,o,t),t+=o.strings.length-2):o._$AI(e[t])),t++}},K=class a{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,o,r){this.type=2,this._$AH=g,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=o,this.options=r,this._$Cv=r?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=z(this,e,t),G(e)?e===g||e==null||e===""?(this._$AH!==g&&this._$AR(),this._$AH=g):e!==this._$AH&&e!==D&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):bt(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==g&&G(this._$AH)?this._$AA.nextSibling.data=e:this.T(T.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:o}=e,r=typeof o=="number"?this._$AC(e):(o.el===void 0&&(o.el=V.createElement(Ue(o.h,o.h[0]),this.options)),o);if(this._$AH?._$AD===r)this._$AH.p(t);else{let n=new _e(r,this),s=n.u(this.options);n.p(t),this.T(s),this._$AH=n}}_$AC(e){let t=ze.get(e.strings);return t===void 0&&ze.set(e.strings,t=new V(e)),t}k(e){ye(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,o,r=0;for(let n of e)r===t.length?t.push(o=new a(this.O(Y()),this.O(Y()),this,this.options)):o=t[r],o._$AI(n),r++;r<t.length&&(this._$AR(o&&o._$AB.nextSibling,r),t.length=r)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let o=Ee(e).nextSibling;Ee(e).remove(),e=o}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},O=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,o,r,n){this.type=1,this._$AH=g,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=n,o.length>2||o[0]!==""||o[1]!==""?(this._$AH=Array(o.length-1).fill(new String),this.strings=Line truncated
|
\f\r"'\`<>=]|("|')|))|$)`,"g"),Re=/'/g,Pe=/"/g,Me=/^(?:script|style|textarea|title)$/i,ve=a=>(e,...t)=>({_$litType$:a,strings:e,values:t}),m=ve(1),It=ve(2),qt=ve(3),D=Symbol.for("lit-noChange"),g=Symbol.for("lit-nothing"),ze=new WeakMap,E=T.createTreeWalker(T,129);function Ue(a,e){if(!ye(a)||!a.hasOwnProperty("raw"))throw Error("invalid template strings array");return Te!==void 0?Te.createHTML(e):e}var yt=(a,e)=>{let t=a.length-1,o=[],r,n=e===2?"<svg>":e===3?"<math>":"",s=W;for(let l=0;l<t;l++){let d=a[l],p,u,c=-1,_=0;for(;_<d.length&&(s.lastIndex=_,u=s.exec(d),u!==null);)_=s.lastIndex,s===W?u[1]==="!--"?s=De:u[1]!==void 0?s=Ne:u[2]!==void 0?(Me.test(u[2])&&(r=RegExp("</"+u[2],"g")),s=C):u[3]!==void 0&&(s=C):s===C?u[0]===">"?(s=r??W,c=-1):u[1]===void 0?c=-2:(c=s.lastIndex-u[2].length,p=u[1],s=u[3]===void 0?C:u[3]==='"'?Pe:Re):s===Pe||s===Re?s=C:s===De||s===Ne?s=W:(s=C,r=void 0);let h=s===C&&a[l+1].startsWith("/>")?" ":"";n+=s===W?d+mt:c>=0?(o.push(p),d.slice(0,c)+Oe+d.slice(c)+A+h):d+A+(c===-2?l:h)}return[Ue(a,n+(a[t]||"<?>")+(e===2?"</svg>":e===3?"</math>":"")),o]},V=class a{constructor({strings:e,_$litType$:t},o){let r;this.parts=[];let n=0,s=0,l=e.length-1,d=this.parts,[p,u]=yt(e,t);if(this.el=a.createElement(p,o),E.currentNode=this.el.content,t===2||t===3){let c=this.el.content.firstChild;c.replaceWith(...c.childNodes)}for(;(r=E.nextNode())!==null&&d.length<l;){if(r.nodeType===1){if(r.hasAttributes())for(let c of r.getAttributeNames())if(c.endsWith(Oe)){let _=u[s++],h=r.getAttribute(c).split(A),b=/([.?@])?(.*)/.exec(_);d.push({type:1,index:n,name:b[2],strings:h,ctor:b[1]==="."?he:b[1]==="?"?ge:b[1]==="@"?fe:O}),r.removeAttribute(c)}else c.startsWith(A)&&(d.push({type:6,index:n}),r.removeAttribute(c));if(Me.test(r.tagName)){let c=r.textContent.split(A),_=c.length-1;if(_>0){r.textContent=ae?ae.emptyScript:"";for(let h=0;h<_;h++)r.append(c[h],Y()),E.nextNode(),d.push({type:2,index:++n});r.append(c[_],Y())}}}else if(r.nodeType===8)if(r.data===Le)d.push({type:2,index:n});else{let c=-1;for(;(c=r.data.indexOf(A,c+1))!==-1;)d.push({type:7,index:n}),c+=A.length-1}n++}}static createElement(e,t){let o=T.createElement("template");return o.innerHTML=e,o}};function z(a,e,t=a,o){if(e===D)return e;let r=o!==void 0?t._$Co?.[o]:t._$Cl,n=G(e)?void 0:e._$litDirective$;return r?.constructor!==n&&(r?._$AO?.(!1),n===void 0?r=void 0:(r=new n(a),r._$AT(a,t,o)),o!==void 0?(t._$Co??=[])[o]=r:t._$Cl=r),r!==void 0&&(e=z(a,r._$AS(a,e.values),r,o)),e}var _e=class{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){let{el:{content:t},parts:o}=this._$AD,r=(e?.creationScope??T).importNode(t,!0);E.currentNode=r;let n=E.nextNode(),s=0,l=0,d=o[0];for(;d!==void 0;){if(s===d.index){let p;d.type===2?p=new K(n,n.nextSibling,this,e):d.type===1?p=new d.ctor(n,d.name,d.strings,this,e):d.type===6&&(p=new me(n,this,e)),this._$AV.push(p),d=o[++l]}s!==d?.index&&(n=E.nextNode(),s++)}return E.currentNode=T,r}p(e){let t=0;for(let o of this._$AV)o!==void 0&&(o.strings!==void 0?(o._$AI(e,o,t),t+=o.strings.length-2):o._$AI(e[t])),t++}},K=class a{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,o,r){this.type=2,this._$AH=g,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=o,this.options=r,this._$Cv=r?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode,t=this._$AM;return t!==void 0&&e?.nodeType===11&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=z(this,e,t),G(e)?e===g||e==null||e===""?(this._$AH!==g&&this._$AR(),this._$AH=g):e!==this._$AH&&e!==D&&this._(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):bt(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==g&&G(this._$AH)?this._$AA.nextSibling.data=e:this.T(T.createTextNode(e)),this._$AH=e}$(e){let{values:t,_$litType$:o}=e,r=typeof o=="number"?this._$AC(e):(o.el===void 0&&(o.el=V.createElement(Ue(o.h,o.h[0]),this.options)),o);if(this._$AH?._$AD===r)this._$AH.p(t);else{let n=new _e(r,this),s=n.u(this.options);n.p(t),this.T(s),this._$AH=n}}_$AC(e){let t=ze.get(e.strings);return t===void 0&&ze.set(e.strings,t=new V(e)),t}k(e){ye(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,o,r=0;for(let n of e)r===t.length?t.push(o=new a(this.O(Y()),this.O(Y()),this,this.options)):o=t[r],o._$AI(n),r++;r<t.length&&(this._$AR(o&&o._$AB.nextSibling,r),t.length=r)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){let o=Ee(e).nextSibling;Ee(e).remove(),e=o}}setConnected(e){this._$AM===void 0&&(this._$Cv=e,this._$AP?.(e))}},O=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,o,r,n){this.type=1,this._$AH=g,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=n,o.length>2||o[0]!==""||o[1]!==""?(this._$AH=Array(o.length-1).fill(new String),this.strings=Line truncated
|
||||||
.cal-controls {
|
.cal-controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
@@ -200,7 +200,7 @@ var it=Object.defineProperty;var lt=Object.getOwnPropertyDescriptor;var x=(a,e,t
|
|||||||
}
|
}
|
||||||
`;var Ge={maintenance:"Maintenance",objects:"Objects",tasks:"Tasks",overdue:"Overdue",due_soon:"Due Soon",triggered:"Triggered",trigger_replaced:"Trigger replaced",ok:"OK",all:"All",new_object:"+ New Object",templates_from:"From template",templates_title:"Start from a template",templates_task_count:"{n} tasks",template_created:"Created from template",onboard_hint:"Add your first object to start tracking maintenance.",edit:"Edit",duplicate:"Duplicate",task_duplicated:"Task duplicated",object_duplicated:"Object duplicated",delete:"Delete",add_task:"+ Add Task",complete:"Complete",completed:"Completed",skip:"Skip",skipped:"Skipped",missed:"Missed",reset:"Reset",snooze:"Snooze",snoozed:"Snoozed",cancel:"Cancel",bulk_select:"Select",bulk_select_all:"Select all",bulk_n_selected:"{n} selected",bulk_completed:"{n} tasks completed",bulk_archived:"{n} tasks archived",completing:"Completing\u2026",interval:"Interval",warning:"Warning",last_performed:"Last performed",next_due:"Next due",days_until_due:"Days until due",avg_duration:"Avg duration",trigger:"Trigger",trigger_type:"Trigger type",threshold_above:"Upper limit",threshold_below:"Lower limit",threshold:"Threshold",counter:"Counter",state_change:"State change",runtime:"Runtime",runtime_hours:"Target runtime (hours)",target_value:"Target value",baseline:"Baseline",target_changes:"Target changes",for_minutes:"For (minutes)",time_based:"Time-based",sensor_based:"Sensor-based",manual:"Manual",one_time:"One-time",weekdays:"Weekdays",nth_weekday:"Nth weekday of month",day_of_month:"Day of month",recurrence_on_days:"Repeat on",recurrence_occurrence:"Occurrence",recurrence_weekday:"Weekday",recurrence_day:"Day of month (1\u201331)",recurrence_last_day:"Last day of the month",recurrence_business_day:"Business days only (roll back from weekend)",recurrence_offset:"Offset (days, \xB1)",recurrence_offset_help:"Shift the date by \xB1N days, e.g. -2 = two days before.",last_day_month:"Last day of month",last_business_day_month:"Last business day",ord_1:"1st",ord_2:"2nd",ord_3:"3rd",ord_4:"4th",ord_5:"5th",ord_last:"Last",day_word:"Day",interval_value:"Interval",interval_unit:"Unit",unit_days:"Days",unit_weeks:"Weeks",unit_months:"Months",unit_years:"Years",due_date:"Due date",cleaning:"Cleaning",inspection:"Inspection",replacement:"Replacement",calibration:"Calibration",service:"Service",reading:"Reading",custom:"Custom",history:"History",cost:"Cost",report_button:"Report",report_title:"Maintenance report",report_generated:"Generated",report_times_done:"Done",report_total_cost:"Total cost",report_every:"every {n} {unit}",report_notes:"Notes",report_col_type:"Type",report_col_status:"Status",report_col_schedule:"Schedule",duration:"Duration",both:"Both",trigger_val:"Trigger value",complete_title:"Complete: ",checklist:"Checklist",require_on_completion:"Require on completion",checklist_steps_optional:"Checklist steps (optional)",checklist_placeholder:`Clean filter
|
`;var Ge={maintenance:"Maintenance",objects:"Objects",tasks:"Tasks",overdue:"Overdue",due_soon:"Due Soon",triggered:"Triggered",trigger_replaced:"Trigger replaced",ok:"OK",all:"All",new_object:"+ New Object",templates_from:"From template",templates_title:"Start from a template",templates_task_count:"{n} tasks",template_created:"Created from template",onboard_hint:"Add your first object to start tracking maintenance.",edit:"Edit",duplicate:"Duplicate",task_duplicated:"Task duplicated",object_duplicated:"Object duplicated",delete:"Delete",add_task:"+ Add Task",complete:"Complete",completed:"Completed",skip:"Skip",skipped:"Skipped",missed:"Missed",reset:"Reset",snooze:"Snooze",snoozed:"Snoozed",cancel:"Cancel",bulk_select:"Select",bulk_select_all:"Select all",bulk_n_selected:"{n} selected",bulk_completed:"{n} tasks completed",bulk_archived:"{n} tasks archived",completing:"Completing\u2026",interval:"Interval",warning:"Warning",last_performed:"Last performed",next_due:"Next due",days_until_due:"Days until due",avg_duration:"Avg duration",trigger:"Trigger",trigger_type:"Trigger type",threshold_above:"Upper limit",threshold_below:"Lower limit",threshold:"Threshold",counter:"Counter",state_change:"State change",runtime:"Runtime",runtime_hours:"Target runtime (hours)",target_value:"Target value",baseline:"Baseline",target_changes:"Target changes",for_minutes:"For (minutes)",time_based:"Time-based",sensor_based:"Sensor-based",manual:"Manual",one_time:"One-time",weekdays:"Weekdays",nth_weekday:"Nth weekday of month",day_of_month:"Day of month",recurrence_on_days:"Repeat on",recurrence_occurrence:"Occurrence",recurrence_weekday:"Weekday",recurrence_day:"Day of month (1\u201331)",recurrence_last_day:"Last day of the month",recurrence_business_day:"Business days only (roll back from weekend)",recurrence_offset:"Offset (days, \xB1)",recurrence_offset_help:"Shift the date by \xB1N days, e.g. -2 = two days before.",last_day_month:"Last day of month",last_business_day_month:"Last business day",ord_1:"1st",ord_2:"2nd",ord_3:"3rd",ord_4:"4th",ord_5:"5th",ord_last:"Last",day_word:"Day",interval_value:"Interval",interval_unit:"Unit",unit_days:"Days",unit_weeks:"Weeks",unit_months:"Months",unit_years:"Years",due_date:"Due date",cleaning:"Cleaning",inspection:"Inspection",replacement:"Replacement",calibration:"Calibration",service:"Service",reading:"Reading",custom:"Custom",history:"History",cost:"Cost",report_button:"Report",report_title:"Maintenance report",report_generated:"Generated",report_times_done:"Done",report_total_cost:"Total cost",report_every:"every {n} {unit}",report_notes:"Notes",report_col_type:"Type",report_col_status:"Status",report_col_schedule:"Schedule",duration:"Duration",both:"Both",trigger_val:"Trigger value",complete_title:"Complete: ",checklist:"Checklist",require_on_completion:"Require on completion",checklist_steps_optional:"Checklist steps (optional)",checklist_placeholder:`Clean filter
|
||||||
Replace seal
|
Replace seal
|
||||||
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",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_optional:"Due at time (optional, HH:MM)",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",confirm_delete_object:"Delete this object and all its tasks?",confirm_delete_task:"Delete this task?",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",tasks_lower:"tasks",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",for_at_least_minutes:"For at least (minutes)",safety_interval_days:"Safety interval (days, optional)",safety_interval:"Safety interval (optional)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:"Calendar",cal_no_events:"No maintenance",cal_window_7:"7 days",cal_window_14:"14 days",cal_window_30:"30 days",cal_window_365:"1 year",cal_every_n_days:"every {n} days",cal_source_time:"Time-based",cal_source_time_adaptive:"Time-based (adaptive)",cal_source_sensor:"Sensor-based",cal_predicted:"predicted",cal_confidence_high:"high confidence",cal_confidence_medium:"medium confidence",cal_confidence_low:"low confidence",budget_monthly:"Monthly budget",budget_yearly:"Yearly budget",groups:"Groups",new_group:"New group",edit_group:"Edit group",no_groups:"No groups yet",delete_group:"Delete group",delete_group_confirm:"Delete group '{name}'?",group_select_tasks:"Select tasks",group_name_required:"Name is required",description_optional:"Description (optional)",selected:"Sel
Line truncated
|
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",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_optional:"Due at time (optional, HH:MM)",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",confirm_delete_object:"Delete this object and all its tasks?",confirm_delete_task:"Delete this task?",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",tasks_lower:"tasks",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",for_at_least_minutes:"For at least (minutes)",safety_interval_days:"Safety interval (days, optional)",safety_interval:"Safety interval (optional)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:"Calendar",cal_no_events:"No maintenance",cal_window_7:"7 days",cal_window_14:"14 days",cal_window_30:"30 days",cal_window_365:"1 year",cal_every_n_days:"every {n} days",cal_source_time:"Time-based",cal_source_time_adaptive:"Time-based (adaptive)",cal_source_sensor:"Sensor-based",cal_predicted:"predicted",cal_confidence_high:"high confidence",cal_confidence_medium:"medium confidence",cal_confidence_low:"low confidence",budget_monthly:"Monthly budget",budget_yearly:"Yearly budget",groups:"Groups",new_group:"New group",edit_group:"Edit group",no_groups:"No groups yet",delete_group:"Delete group",delete_group_confirm:"Delete group '{name}'?",group_select_tasks:"Select tasks",group_name_required:"Name is required",description_optional:"Description (optional)",selected:"Sel
Line truncated
|
||||||
.field { display: flex; flex-direction: column; gap: 4px; }
|
.field { display: flex; flex-direction: column; gap: 4px; }
|
||||||
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
||||||
.field-input {
|
.field-input {
|
||||||
@@ -262,7 +262,10 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
label length. */
|
label length. */
|
||||||
.stats-bar {
|
.stats-bar {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(5, 1fr);
|
/* auto-fit instead of a fixed 5: with the budget feature on, two KPI
|
||||||
|
tiles join the strip (#125) — and on narrow screens the tiles wrap
|
||||||
|
instead of crushing. */
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
@@ -801,38 +804,25 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
50% { opacity: 0.7; }
|
50% { opacity: 0.7; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Budget bars */
|
/* Budget KPI tiles in the stats strip (#125) — replaced the full-width
|
||||||
.budget-bars {
|
budget-bars row. */
|
||||||
display: flex;
|
.stat-item.budget-tile .budget-tile-value {
|
||||||
gap: 16px;
|
font-size: 15px;
|
||||||
padding: 8px 16px;
|
padding-top: 5px;
|
||||||
flex-wrap: wrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
.budget-tile-bar {
|
||||||
.budget-item {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.budget-label {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.budget-bar {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 6px;
|
max-width: 130px;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
background: var(--divider-color);
|
background: var(--divider-color);
|
||||||
border-radius: 3px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
.budget-tile-bar > div {
|
||||||
.budget-bar-fill {
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 3px;
|
border-radius: 2px;
|
||||||
transition: width 0.3s;
|
transition: width 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1340,21 +1330,9 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
|
|
||||||
.weibull-info-row { flex-direction: column; gap: 8px; }
|
.weibull-info-row { flex-direction: column; gap: 8px; }
|
||||||
|
|
||||||
/* One compact line instead of two stacked rows — the bars are glanceable
|
/* Budget tiles on narrow screens (#125): slightly smaller value so the
|
||||||
info, not the page's main content (UX 2026-07). The label stacks above
|
"x / y €" pair fits the wrapped grid cell. */
|
||||||
the value: side-by-side, the yearly pair wrapped raggedly on 360px
|
.stat-item.budget-tile .budget-tile-value { font-size: 13px; }
|
||||||
screens; a uniform two-line stack reads as intended at every width. */
|
|
||||||
.budget-bars { gap: 12px; padding: 6px 8px; }
|
|
||||||
.budget-item { min-width: 0; }
|
|
||||||
.budget-label {
|
|
||||||
font-size: 11px;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 0;
|
|
||||||
}
|
|
||||||
.budget-label span { white-space: nowrap; }
|
|
||||||
.budget-bar { height: 4px; }
|
|
||||||
|
|
||||||
.group-card { min-width: 0; max-width: 100%; }
|
.group-card { min-width: 0; max-width: 100%; }
|
||||||
|
|
||||||
@@ -1376,10 +1354,10 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
.stat-item .stat-label { font-size: 11px; white-space: normal; text-align: center; line-height: 1.2; }
|
.stat-item .stat-label { font-size: 11px; white-space: normal; text-align: center; line-height: 1.2; }
|
||||||
.stat-value { font-size: 20px; }
|
.stat-value { font-size: 20px; }
|
||||||
}
|
}
|
||||||
`;var v=class extends ${constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"};this._objects=[];this._stats=null;this._windowDays=30;this._pastDays=0;this._userFilter="";this._objectFilter="";this._configuredObjects=[];this._unsub=null;this._dataLoaded=!1;this._lastConnection=null}static getConfigElement(){return document.createElement("maintenance-supporter-calendar-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-calendar-card",window_days:30,show_window_chips:!0,show_user_filter:!0}}setConfig(t){if(this._config={...t},t.past_days&&[30,90].includes(t.past_days)?this._pastDays=t.past_days:t.window_days&&[7,14,30,365].includes(t.window_days)&&(this._windowDays=t.window_days,this._pastDays=0),typeof t.user_filter=="string"&&(this._userFilter=t.user_filter),typeof t.object_filter=="string")this._objectFilter=t.object_filter,this._configuredObjects=[];else if(Array.isArray(t.object_filter)){let o=t.object_filter.filter(r=>typeof r=="string"&&r!=="");this._objectFilter=o.length===1?o[0]:"",this._configuredObjects=o.length>1?o:[]}}getCardSize(){return 6}get _lang(){return this.hass?.language||"en"}disconnectedCallback(){if(super.disconnectedCallback(),this._unsub){try{this._unsub()}catch{}this._unsub=null}this._dataLoaded=!1,this._lastConnection=null}updated(t){super.updated(t),t.has("hass")&&Xe(this.hass?.locale);let o=this.hass?.language;if(o&&!Je(o)&&Ze(o).then(()=>this.requestUpdate()),t.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){try{let[t,o]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=t.objects,this._stats=o}catch{}}async _subscribe(){try{let t=await this.hass.connection.subscribeMessage(o=>{let r=o;this._objects=r.objects},{type:"maintenance_supporter/subscribe"});if(!this.isConnected){t();return}this._unsub=t}catch{}}_onEventClick(t){if(t.history_timestamp){this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:edit-history",entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.history_timestamp},bubbles:!0,composed:!0}));return}this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:open-task",entry_id:t.entry_id,task_id:t.task_id},bubbles:!0,composed:!0}))}render(){if(!this.hass)return g;let t=this._lang,o=this._config.show_window_chips!==!1,r=this._config.show_user_filter!==!1,n=this._config.title,s=null;this._userFilter&&(s=this._userFilter==="current_user"?this.hass?.user?.id??null:this._userFilter);let l=i=>{let j=i.toLowerCase();return this._objects.find(P=>P.entry_id===i||P.object.name.toLowerCase()===j)?.entry_id??null},d=new Set(this._configuredObjects.map(l).filter(i=>i!==null)),p=d.size?this._objects.filter(i=>d.has(i.entry_id)):this._objects,u=this._config.show_object_filter!==!1&&p.length>1,c=this._objectFilter?l(this._objectFilter):null,_=c&&p.some(i=>i.entry_id===c)?p.filter(i=>i.entry_id===c):p,h=new Date;h.setHours(0,0,0,0);let b=this._pastDays>0,y=b?We(_,h,this._pastDays,s):Be(_,h,this._windowDays,s),R=J(h),M=this._windowDays===365||b,U=M?y.filter(i=>i.events.length>0):y,rt=i=>{let j=`cal-status-${i.status}`,X=i.projected?"cal-event-projected":"",P=i.status==="overdue"&&i.days_until_due!=null?` (${et(i.days_until_due,t)})`:"",H=i.projected&&i.interval_days?m`<span class="cal-event-recur">${i.interval_unit&&i.interval_unit!=="days"?`${i.interval_days} ${f("unit_"+i.interval_unit,t)}`:f("cal_every_n_days",t).replace("{n}",String(i.interval_days))}</span>`:g,q=i.schedule_type==="sensor_based",le=q?m`<ha-icon class="cal-event-icon cal-source-sensor"
|
`;var v=class extends ${constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"};this._objects=[];this._stats=null;this._windowDays=30;this._pastDays=0;this._userFilter="";this._objectFilter="";this._configuredObjects=[];this._unsub=null;this._dataLoaded=!1;this._lastConnection=null}static getConfigElement(){return document.createElement("maintenance-supporter-calendar-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-calendar-card",window_days:30,show_window_chips:!0,show_user_filter:!0}}setConfig(t){if(this._config={...t},t.past_days&&[30,90].includes(t.past_days)?this._pastDays=t.past_days:t.window_days&&[7,14,30,365].includes(t.window_days)&&(this._windowDays=t.window_days,this._pastDays=0),typeof t.user_filter=="string"&&(this._userFilter=t.user_filter),typeof t.object_filter=="string")this._objectFilter=t.object_filter,this._configuredObjects=[];else if(Array.isArray(t.object_filter)){let o=t.object_filter.filter(r=>typeof r=="string"&&r!=="");this._objectFilter=o.length===1?o[0]:"",this._configuredObjects=o.length>1?o:[]}}getCardSize(){return 6}get _lang(){return this.hass?.language||"en"}disconnectedCallback(){if(super.disconnectedCallback(),this._unsub){try{this._unsub()}catch{}this._unsub=null}this._dataLoaded=!1,this._lastConnection=null}updated(t){super.updated(t),t.has("hass")&&Xe(this.hass?.locale);let o=this.hass?.language;if(o&&!Je(o)&&Ze(o).then(()=>this.requestUpdate()),t.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){try{let[t,o]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=t.objects,this._stats=o}catch{}}async _subscribe(){try{let t=await this.hass.connection.subscribeMessage(o=>{let r=o;this._objects=r.objects},{type:"maintenance_supporter/subscribe"});if(!this.isConnected){t();return}this._unsub=t}catch{}}_onEventClick(t){if(t.history_timestamp){this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:edit-history",entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.history_timestamp},bubbles:!0,composed:!0}));return}this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:open-task",entry_id:t.entry_id,task_id:t.task_id},bubbles:!0,composed:!0}))}render(){if(!this.hass)return g;let t=this._lang,o=this._config.show_window_chips!==!1,r=this._config.show_user_filter!==!1,n=this._config.title,s=null;this._userFilter&&(s=this._userFilter==="current_user"?this.hass?.user?.id??null:this._userFilter);let l=i=>{let j=i.toLowerCase();return this._objects.find(P=>P.entry_id===i||P.object.name.toLowerCase()===j)?.entry_id??null},d=new Set(this._configuredObjects.map(l).filter(i=>i!==null)),p=d.size?this._objects.filter(i=>d.has(i.entry_id)):this._objects,u=this._config.show_object_filter!==!1&&p.length>1,c=this._objectFilter?l(this._objectFilter):null,_=c&&p.some(i=>i.entry_id===c)?p.filter(i=>i.entry_id===c):p,h=new Date;h.setHours(0,0,0,0);let b=this._pastDays>0,y=b?We(_,h,this._pastDays,s):Be(_,h,this._windowDays,s),R=J(h),M=this._windowDays===365||b,U=M?y.filter(i=>i.events.length>0):y,rt=i=>{let j=`cal-status-${i.status}`,X=i.projected?"cal-event-projected":"",P=i.status==="overdue"&&i.days_until_due!=null?` (${et(i.days_until_due,t)})`:"",H=i.projected&&i.interval_days?m`<span class="cal-event-recur">${i.interval_unit&&i.interval_unit!=="days"?`${i.interval_days} ${f("unit_"+i.interval_unit,t)}`:f("cal_every_n_days",t).replace("{n}",String(i.interval_days))}</span>`:g,I=i.schedule_type==="sensor_based",le=I?m`<ha-icon class="cal-event-icon cal-source-sensor"
|
||||||
title="${f("cal_source_sensor",t)}" icon="mdi:trending-up"></ha-icon>`:m`<ha-icon class="cal-event-icon cal-source-time"
|
title="${f("cal_source_sensor",t)}" icon="mdi:trending-up"></ha-icon>`:m`<ha-icon class="cal-event-icon cal-source-time"
|
||||||
title="${i.adaptive_enabled?f("cal_source_time_adaptive",t):f("cal_source_time",t)}"
|
title="${i.adaptive_enabled?f("cal_source_time_adaptive",t):f("cal_source_time",t)}"
|
||||||
icon="${i.adaptive_enabled?"mdi:clock-time-four-outline":"mdi:clock-outline"}"></ha-icon>`,ce=q&&i.prediction_confidence&&i.status!=="triggered"&&!i.projected?m`<span class="cal-event-prediction cal-conf-${i.prediction_confidence}">
|
icon="${i.adaptive_enabled?"mdi:clock-time-four-outline":"mdi:clock-outline"}"></ha-icon>`,ce=I&&i.prediction_confidence&&i.status!=="triggered"&&!i.projected?m`<span class="cal-event-prediction cal-conf-${i.prediction_confidence}">
|
||||||
${f("cal_predicted",t)} · ${f(`cal_confidence_${i.prediction_confidence}`,t)}
|
${f("cal_predicted",t)} · ${f(`cal_confidence_${i.prediction_confidence}`,t)}
|
||||||
</span>`:g,nt=this._stats?.budget?.currency_symbol||Ke,st=i.history_type?f(i.history_type,t):f(i.status,t);return m`
|
</span>`:g,nt=this._stats?.budget?.currency_symbol||Ke,st=i.history_type?f(i.history_type,t):f(i.status,t);return m`
|
||||||
<div class="cal-event ${X}"
|
<div class="cal-event ${X}"
|
||||||
@@ -1393,16 +1371,16 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
</div>
|
</div>
|
||||||
${i.avg_cost!=null&&i.avg_cost>0?m`<span class="cal-event-cost">${i.avg_cost.toFixed(0)} ${nt}</span>`:g}
|
${i.avg_cost!=null&&i.avg_cost>0?m`<span class="cal-event-cost">${i.avg_cost.toFixed(0)} ${nt}</span>`:g}
|
||||||
</div>
|
</div>
|
||||||
`},at=i=>{let[j,X,P]=i.date.split("-").map(Number),H=new Date(j,X-1,P),q=i.date===R,le=H.toLocaleDateString(t,{weekday:"short"}),ce=H.toLocaleDateString(t,{month:"long"});return m`
|
`},at=i=>{let[j,X,P]=i.date.split("-").map(Number),H=new Date(j,X-1,P),I=i.date===R,le=H.toLocaleDateString(t,{weekday:"short"}),ce=H.toLocaleDateString(t,{month:"long"});return m`
|
||||||
<div class="cal-day-row">
|
<div class="cal-day-row">
|
||||||
<div class="cal-day-pill ${q?"cal-today":""}">
|
<div class="cal-day-pill ${I?"cal-today":""}">
|
||||||
<span class="cal-pill-weekday">${le}</span>
|
<span class="cal-pill-weekday">${le}</span>
|
||||||
<span class="cal-pill-day">${H.getDate()}</span>
|
<span class="cal-pill-day">${H.getDate()}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cal-day-content">
|
<div class="cal-day-content">
|
||||||
<div class="cal-day-header">
|
<div class="cal-day-header">
|
||||||
<span class="cal-day-month">${ce}</span>
|
<span class="cal-day-month">${ce}</span>
|
||||||
${q?m`<span class="cal-day-today-badge">${f("today",t)}</span>`:g}
|
${I?m`<span class="cal-day-today-badge">${f("today",t)}</span>`:g}
|
||||||
</div>
|
</div>
|
||||||
${i.events.length===0?m`<div class="cal-empty">${f("cal_no_events",t)}</div>`:i.events.map(rt)}
|
${i.events.length===0?m`<div class="cal-empty">${f("cal_no_events",t)}</div>`:i.events.map(rt)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1455,7 +1433,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
`}};v.styles=[tt,Ye,k`
|
`}};v.styles=[tt,Ye,k`
|
||||||
:host { display: block; }
|
:host { display: block; }
|
||||||
ha-card { padding: 0; overflow: hidden; }
|
ha-card { padding: 0; overflow: hidden; }
|
||||||
`],x([Q({attribute:!1})],v.prototype,"hass",2),x([w()],v.prototype,"_config",2),x([w()],v.prototype,"_objects",2),x([w()],v.prototype,"_stats",2),x([w()],v.prototype,"_windowDays",2),x([w()],v.prototype,"_pastDays",2),x([w()],v.prototype,"_userFilter",2),x([w()],v.prototype,"_objectFilter",2),x([w()],v.prototype,"_unsub",2);var Pt=[{value:7,label:"Week (7 days)"},{value:14,label:"Fortnight (14 days)"},{value:30,label:"Month (30 days, default)"},{value:365,label:"Year (365 days, empty days collapsed)"}],L=class extends ${constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"}}setConfig(t){this._config={...t}}_valueChanged(t,o){let r={...this._config,[t]:o};t==="show_window_chips"&&o===!0&&delete r.show_window_chips,t==="show_user_filter"&&o===!0&&delete r.show_user_filter,t==="show_object_filter"&&o===!0&&delete r.show_object_filter,t==="title"&&(!o||typeof o=="string"&&o.trim()==="")&&delete r.title,t==="user_filter"&&o===""&&delete r.user_filter,this._config=r,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:r},bubbles:!0,composed:!0}))}render(){let t=this._config.window_days??30,o=this._config.show_window_chips!==!1,r=this._config.show_user_filter!==!1,n=this._config.user_filter??"",s=this._config.title??"";return m`
|
`],w([Q({attribute:!1})],v.prototype,"hass",2),w([x()],v.prototype,"_config",2),w([x()],v.prototype,"_objects",2),w([x()],v.prototype,"_stats",2),w([x()],v.prototype,"_windowDays",2),w([x()],v.prototype,"_pastDays",2),w([x()],v.prototype,"_userFilter",2),w([x()],v.prototype,"_objectFilter",2),w([x()],v.prototype,"_unsub",2);var Pt=[{value:7,label:"Week (7 days)"},{value:14,label:"Fortnight (14 days)"},{value:30,label:"Month (30 days, default)"},{value:365,label:"Year (365 days, empty days collapsed)"}],L=class extends ${constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"}}setConfig(t){this._config={...t}}_valueChanged(t,o){let r={...this._config,[t]:o};t==="show_window_chips"&&o===!0&&delete r.show_window_chips,t==="show_user_filter"&&o===!0&&delete r.show_user_filter,t==="show_object_filter"&&o===!0&&delete r.show_object_filter,t==="title"&&(!o||typeof o=="string"&&o.trim()==="")&&delete r.title,t==="user_filter"&&o===""&&delete r.user_filter,this._config=r,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:r},bubbles:!0,composed:!0}))}render(){let t=this._config.window_days??30,o=this._config.show_window_chips!==!1,r=this._config.show_user_filter!==!1,n=this._config.user_filter??"",s=this._config.title??"";return m`
|
||||||
<div class="editor">
|
<div class="editor">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="title">Title (optional)</label>
|
<label for="title">Title (optional)</label>
|
||||||
@@ -1547,7 +1525,7 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--secondary-text-color, #666);
|
color: var(--secondary-text-color, #666);
|
||||||
}
|
}
|
||||||
`,x([Q({attribute:!1})],L.prototype,"hass",2),x([w()],L.prototype,"_config",2);customElements.get("maintenance-supporter-calendar-card")||customElements.define("maintenance-supporter-calendar-card",v);customElements.get("maintenance-supporter-calendar-card-editor")||customElements.define("maintenance-supporter-calendar-card-editor",L);var ie=window;ie.customCards=ie.customCards||[];var ot="maintenance-supporter-calendar-card",zt=ie.customCards.some(a=>a.type===ot);zt||ie.customCards.push({type:ot,name:"Maintenance Supporter \u2014 Calendar",description:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",preview:!0});export{v as MaintenanceCalendarCard};
|
`,w([Q({attribute:!1})],L.prototype,"hass",2),w([x()],L.prototype,"_config",2);customElements.get("maintenance-supporter-calendar-card")||customElements.define("maintenance-supporter-calendar-card",v);customElements.get("maintenance-supporter-calendar-card-editor")||customElements.define("maintenance-supporter-calendar-card-editor",L);var ie=window;ie.customCards=ie.customCards||[];var ot="maintenance-supporter-calendar-card",zt=ie.customCards.some(a=>a.type===ot);zt||ie.customCards.push({type:ot,name:"Maintenance Supporter \u2014 Calendar",description:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",preview:!0});export{v as MaintenanceCalendarCard};
|
||||||
/*! Bundled license information:
|
/*! Bundled license information:
|
||||||
|
|
||||||
@lit/reactive-element/css-tag.js:
|
@lit/reactive-element/css-tag.js:
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/*! maintenance_supporter frontend 2.53.0 */
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
var mt=Object.defineProperty;var Pi=Object.getOwnPropertyDescriptor;var w=(a,s,e)=>()=>{if(e)throw e[0];try{return a&&(s=a(a=0)),s}catch(t){throw e=[t],t}};var Ri=(a,s)=>{for(var e in s)mt(a,e,{get:s[e],enumerable:!0})};var l=(a,s,e,t)=>{for(var i=t>1?void 0:t?Pi(s,e):s,n=a.length-1,c;n>=0;n--)(c=a[n])&&(i=(t?c(s,e,i):c(i))||i);return t&&i&&mt(s,e,i),i};var Ee,Se,Ue,ft,pe,vt,E,bt,Ve,Be=w(()=>{Ee=globalThis,Se=Ee.ShadowRoot&&(Ee.ShadyCSS===void 0||Ee.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Ue=Symbol(),ft=new WeakMap,pe=class{constructor(s,e,t){if(this._$cssResult$=!0,t!==Ue)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=s,this.t=e}get styleSheet(){let s=this.o,e=this.t;if(Se&&s===void 0){let t=e!==void 0&&e.length===1;t&&(s=ft.get(e)),s===void 0&&((this.o=s=new CSSStyleSheet).replaceSync(this.cssText),t&&ft.set(e,s))}return s}toString(){return this.cssText}},vt=a=>new pe(typeof a=="string"?a:a+"",void 0,Ue),E=(a,...s)=>{let e=a.length===1?a[0]:s.reduce((t,i,n)=>t+(c=>{if(c._$cssResult$===!0)return c.cssText;if(typeof c=="number")return c;throw Error("Value passed to 'css' function must be a 'css' function result: "+c+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+a[n+1],a[0]);return new pe(e,a,Ue)},bt=(a,s)=>{if(Se)a.adoptedStyleSheets=s.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of s){let t=document.createElement("style"),i=Ee.litNonce;i!==void 0&&t.setAttribute("nonce",i),t.textContent=e.cssText,a.appendChild(t)}},Ve=Se?a=>a:a=>a instanceof CSSStyleSheet?(s=>{let e="";for(let t of s.cssRules)e+=t.cssText;return vt(e)})(a):a});var ji,Hi,Ni,qi,zi,Mi,Ae,yt,Oi,Di,he,ue,Te,xt,B,_e=w(()=>{Be();Be();({is:ji,defineProperty:Hi,getOwnPropertyDescriptor:Ni,getOwnPropertyNames:qi,getOwnPropertySymbols:zi,getPrototypeOf:Mi}=Object),Ae=globalThis,yt=Ae.trustedTypes,Oi=yt?yt.emptyScript:"",Di=Ae.reactiveElementPolyfillSupport,he=(a,s)=>a,ue={toAttribute(a,s){switch(s){case Boolean:a=a?Oi:null;break;case Object:case Array:a=a==null?a:JSON.stringify(a)}return a},fromAttribute(a,s){let e=a;switch(s){case Boolean:e=a!==null;break;case Number:e=a===null?null:Number(a);break;case Object:case Array:try{e=JSON.parse(a)}catch{e=null}}return e}},Te=(a,s)=>!ji(a,s),xt={attribute:!0,type:String,converter:ue,reflect:!1,useDefault:!1,hasChanged:Te};Symbol.metadata??=Symbol("metadata"),Ae.litPropertyMetadata??=new WeakMap;B=class extends HTMLElement{static addInitializer(s){this._$Ei(),(this.l??=[]).push(s)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(s,e=xt){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(s)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(s,e),!e.noAccessor){let t=Symbol(),i=this.getPropertyDescriptor(s,t,e);i!==void 0&&Hi(this.prototype,s,i)}}static getPropertyDescriptor(s,e,t){let{get:i,set:n}=Ni(this.prototype,s)??{get(){return this[e]},set(c){this[e]=c}};return{get:i,set(c){let d=i?.call(this);n?.call(this,c),this.requestUpdate(s,d,t)},configurable:!0,enumerable:!0}}static getPropertyOptions(s){return this.elementProperties.get(s)??xt}static _$Ei(){if(this.hasOwnProperty(he("elementProperties")))return;let s=Mi(this);s.finalize(),s.l!==void 0&&(this.l=[...s.l]),this.elementProperties=new Map(s.elementProperties)}static finalize(){if(this.hasOwnProperty(he("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(he("properties"))){let e=this.properties,t=[...qi(e),...zi(e)];for(let i of t)this.createProperty(i,e[i])}let s=this[Symbol.metadata];if(s!==null){let e=litPropertyMetadata.get(s);if(e!==void 0)for(let[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(let[e,t]of this.elementProperties){let i=this._$Eu(e,t);i!==void 0&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(s){let e=[];if(Array.isArray(s)){let t=new Set(s.flat(1/0).reverse());for(let i of t)e.unshift(Ve(i))}else s!==void 0&&e.push(Ve(s));return e}static _$Eu(s,e){let t=e.attribute;return t===!1?void 0:typeof t=="string"?t:typeof s=="string"?s.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(s=>this.enableUpdating=s),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(s=>s(this))}addController(s){(this._$EO??=new Set).add(s),this.renderRoot!==void 0&&this.isConnected&&s.hostConnected?.()}removeController(s){this._$EO?.delete(s)}_$E_(){let s=new Map,e=this.constructor.elementProperties;for(let t of e.keys())this.hasOwnProperty(t)&&(s.set(t,this[t]),delete this[t]);s.size>0&&(this._$Ep=s)}createRenderRoot(){let s=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return bt(s,this.constructor.elementStyles),s}connectedCallback(){this.renderRoot??=thiLine truncated
|
var mt=Object.defineProperty;var Pi=Object.getOwnPropertyDescriptor;var w=(a,s,e)=>()=>{if(e)throw e[0];try{return a&&(s=a(a=0)),s}catch(t){throw e=[t],t}};var Ri=(a,s)=>{for(var e in s)mt(a,e,{get:s[e],enumerable:!0})};var l=(a,s,e,t)=>{for(var i=t>1?void 0:t?Pi(s,e):s,n=a.length-1,c;n>=0;n--)(c=a[n])&&(i=(t?c(s,e,i):c(i))||i);return t&&i&&mt(s,e,i),i};var Ee,Se,Ue,ft,pe,vt,E,bt,Ve,Be=w(()=>{Ee=globalThis,Se=Ee.ShadowRoot&&(Ee.ShadyCSS===void 0||Ee.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Ue=Symbol(),ft=new WeakMap,pe=class{constructor(s,e,t){if(this._$cssResult$=!0,t!==Ue)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=s,this.t=e}get styleSheet(){let s=this.o,e=this.t;if(Se&&s===void 0){let t=e!==void 0&&e.length===1;t&&(s=ft.get(e)),s===void 0&&((this.o=s=new CSSStyleSheet).replaceSync(this.cssText),t&&ft.set(e,s))}return s}toString(){return this.cssText}},vt=a=>new pe(typeof a=="string"?a:a+"",void 0,Ue),E=(a,...s)=>{let e=a.length===1?a[0]:s.reduce((t,i,n)=>t+(c=>{if(c._$cssResult$===!0)return c.cssText;if(typeof c=="number")return c;throw Error("Value passed to 'css' function must be a 'css' function result: "+c+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+a[n+1],a[0]);return new pe(e,a,Ue)},bt=(a,s)=>{if(Se)a.adoptedStyleSheets=s.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of s){let t=document.createElement("style"),i=Ee.litNonce;i!==void 0&&t.setAttribute("nonce",i),t.textContent=e.cssText,a.appendChild(t)}},Ve=Se?a=>a:a=>a instanceof CSSStyleSheet?(s=>{let e="";for(let t of s.cssRules)e+=t.cssText;return vt(e)})(a):a});var ji,Hi,Ni,qi,zi,Mi,Ae,yt,Oi,Di,he,ue,Te,xt,B,_e=w(()=>{Be();Be();({is:ji,defineProperty:Hi,getOwnPropertyDescriptor:Ni,getOwnPropertyNames:qi,getOwnPropertySymbols:zi,getPrototypeOf:Mi}=Object),Ae=globalThis,yt=Ae.trustedTypes,Oi=yt?yt.emptyScript:"",Di=Ae.reactiveElementPolyfillSupport,he=(a,s)=>a,ue={toAttribute(a,s){switch(s){case Boolean:a=a?Oi:null;break;case Object:case Array:a=a==null?a:JSON.stringify(a)}return a},fromAttribute(a,s){let e=a;switch(s){case Boolean:e=a!==null;break;case Number:e=a===null?null:Number(a);break;case Object:case Array:try{e=JSON.parse(a)}catch{e=null}}return e}},Te=(a,s)=>!ji(a,s),xt={attribute:!0,type:String,converter:ue,reflect:!1,useDefault:!1,hasChanged:Te};Symbol.metadata??=Symbol("metadata"),Ae.litPropertyMetadata??=new WeakMap;B=class extends HTMLElement{static addInitializer(s){this._$Ei(),(this.l??=[]).push(s)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(s,e=xt){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(s)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(s,e),!e.noAccessor){let t=Symbol(),i=this.getPropertyDescriptor(s,t,e);i!==void 0&&Hi(this.prototype,s,i)}}static getPropertyDescriptor(s,e,t){let{get:i,set:n}=Ni(this.prototype,s)??{get(){return this[e]},set(c){this[e]=c}};return{get:i,set(c){let d=i?.call(this);n?.call(this,c),this.requestUpdate(s,d,t)},configurable:!0,enumerable:!0}}static getPropertyOptions(s){return this.elementProperties.get(s)??xt}static _$Ei(){if(this.hasOwnProperty(he("elementProperties")))return;let s=Mi(this);s.finalize(),s.l!==void 0&&(this.l=[...s.l]),this.elementProperties=new Map(s.elementProperties)}static finalize(){if(this.hasOwnProperty(he("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(he("properties"))){let e=this.properties,t=[...qi(e),...zi(e)];for(let i of t)this.createProperty(i,e[i])}let s=this[Symbol.metadata];if(s!==null){let e=litPropertyMetadata.get(s);if(e!==void 0)for(let[t,i]of e)this.elementProperties.set(t,i)}this._$Eh=new Map;for(let[e,t]of this.elementProperties){let i=this._$Eu(e,t);i!==void 0&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(s){let e=[];if(Array.isArray(s)){let t=new Set(s.flat(1/0).reverse());for(let i of t)e.unshift(Ve(i))}else s!==void 0&&e.push(Ve(s));return e}static _$Eu(s,e){let t=e.attribute;return t===!1?void 0:typeof t=="string"?t:typeof s=="string"?s.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(s=>this.enableUpdating=s),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(s=>s(this))}addController(s){(this._$EO??=new Set).add(s),this.renderRoot!==void 0&&this.isConnected&&s.hostConnected?.()}removeController(s){this._$EO?.delete(s)}_$E_(){let s=new Map,e=this.constructor.elementProperties;for(let t of e.keys())this.hasOwnProperty(t)&&(s.set(t,this[t]),delete this[t]);s.size>0&&(this._$Ep=s)}createRenderRoot(){let s=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return bt(s,this.constructor.elementStyles),s}connectedCallback(){this.renderRoot??=thiLine truncated
|
||||||
\f\r]`,ge=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,kt=/-->/g,Et=/>/g,Z=RegExp(`>|${We}(?:([^\\s"'>=/]+)(${We}*=${We}*(?:[^
|
\f\r]`,ge=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,kt=/-->/g,Et=/>/g,Z=RegExp(`>|${We}(?:([^\\s"'>=/]+)(${We}*=${We}*(?:[^
|
||||||
\f\r"'\`<>=]|("|')|))|$)`,"g"),St=/'/g,At=/"/g,It=/^(?:script|style|textarea|title)$/i,et=a=>(s,...e)=>({_$litType$:a,strings:s,values:e}),o=et(1),oe=et(2),Fs=et(3),te=Symbol.for("lit-noChange"),h=Symbol.for("lit-nothing"),Tt=new WeakMap,X=ee.createTreeWalker(ee,129);Vi=(a,s)=>{let e=a.length-1,t=[],i,n=s===2?"<svg>":s===3?"<math>":"",c=ge;for(let d=0;d<e;d++){let u=a[d],_,v,f=-1,y=0;for(;y<u.length&&(c.lastIndex=y,v=c.exec(u),v!==null);)y=c.lastIndex,c===ge?v[1]==="!--"?c=kt:v[1]!==void 0?c=Et:v[2]!==void 0?(It.test(v[2])&&(i=RegExp("</"+v[2],"g")),c=Z):v[3]!==void 0&&(c=Z):c===Z?v[0]===">"?(c=i??ge,f=-1):v[1]===void 0?f=-2:(f=c.lastIndex-v[2].length,_=v[1],c=v[3]===void 0?Z:v[3]==='"'?At:St):c===At||c===St?c=Z:c===kt||c===Et?c=ge:(c=Z,i=void 0);let g=c===Z&&a[d+1].startsWith("/>")?" ":"";n+=c===ge?u+Fi:f>=0?(t.push(_),u.slice(0,f)+Ct+u.slice(f)+Q+g):u+Q+(f===-2?d:g)}return[Pt(a,n+(a[e]||"<?>")+(s===2?"</svg>":s===3?"</math>":"")),t]},ve=class a{constructor({strings:s,_$litType$:e},t){let i;this.parts=[];let n=0,c=0,d=s.length-1,u=this.parts,[_,v]=Vi(s,e);if(this.el=a.createElement(_,t),X.currentNode=this.el.content,e===2||e===3){let f=this.el.content.firstChild;f.replaceWith(...f.childNodes)}for(;(i=X.nextNode())!==null&&u.length<d;){if(i.nodeType===1){if(i.hasAttributes())for(let f of i.getAttributeNames())if(f.endsWith(Ct)){let y=v[c++],g=i.getAttribute(f).split(Q),x=/([.?@])?(.*)/.exec(y);u.push({type:1,index:n,name:x[2],strings:g,ctor:x[1]==="."?Ge:x[1]==="?"?Ye:x[1]==="@"?Je:ne}),i.removeAttribute(f)}else f.startsWith(Q)&&(u.push({type:6,index:n}),i.removeAttribute(f));if(It.test(i.tagName)){let f=i.textContent.split(Q),y=f.length-1;if(y>0){i.textContent=Ce?Ce.emptyScript:"";for(let g=0;g<y;g++)i.append(f[g],me()),X.nextNode(),u.push({type:2,index:++n});i.append(f[y],me())}}}else if(i.nodeType===8)if(i.data===Lt)u.push({type:2,index:n});else{let f=-1;for(;(f=i.data.indexOf(Q,f+1))!==-1;)u.push({type:7,index:n}),f+=Q.length-1}n++}}static createElement(s,e){let t=ee.createElement("template");return t.innerHTML=s,t}};Ke=class{constructor(s,e){this._$AV=[],this._$AN=void 0,this._$AD=s,this._$AM=e}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(s){let{el:{content:e},parts:t}=this._$AD,i=(s?.creationScope??ee).importNode(e,!0);X.currentNode=i;let n=X.nextNode(),c=0,d=0,u=t[0];for(;u!==void 0;){if(c===u.index){let _;u.type===2?_=new be(n,n.nextSibling,this,s):u.type===1?_=new u.ctor(n,u.name,u.strings,this,s):u.type===6&&(_=new Qe(n,this,s)),this._$AV.push(_),u=t[++d]}c!==u?.index&&(n=X.nextNode(),c++)}return X.currentNode=ee,i}p(s){let e=0;for(let t of this._$AV)t!==void 0&&(t.strings!==void 0?(t._$AI(s,t,e),e+=t.strings.length-2):t._$AI(s[e])),e++}},be=class a{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(s,e,t,i){this.type=2,this._$AH=h,this._$AN=void 0,this._$AA=s,this._$AB=e,this._$AM=t,this.options=i,this._$Cv=i?.isConnected??!0}get parentNode(){let s=this._$AA.parentNode,e=this._$AM;return e!==void 0&&s?.nodeType===11&&(s=e.parentNode),s}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(s,e=this){s=ae(this,s,e),fe(s)?s===h||s==null||s===""?(this._$AH!==h&&this._$AR(),this._$AH=h):s!==this._$AH&&s!==te&&this._(s):s._$litType$!==void 0?this.$(s):s.nodeType!==void 0?this.T(s):Ui(s)?this.k(s):this._(s)}O(s){return this._$AA.parentNode.insertBefore(s,this._$AB)}T(s){this._$AH!==s&&(this._$AR(),this._$AH=this.O(s))}_(s){this._$AH!==h&&fe(this._$AH)?this._$AA.nextSibling.data=s:this.T(ee.createTextNode(s)),this._$AH=s}$(s){let{values:e,_$litType$:t}=s,i=typeof t=="number"?this._$AC(s):(t.el===void 0&&(t.el=ve.createElement(Pt(t.h,t.h[0]),this.options)),t);if(this._$AH?._$AD===i)this._$AH.p(e);else{let n=new Ke(i,this),c=n.u(this.options);n.p(e),this.T(c),this._$AH=n}}_$AC(s){let e=Tt.get(s.strings);return e===void 0&&Tt.set(s.strings,e=new ve(s)),e}k(s){Xe(this._$AH)||(this._$AH=[],this._$AR());let e=this._$AH,t,i=0;for(let n of s)i===e.length?e.push(t=new a(this.O(me()),this.O(me()),this,this.options)):t=e[i],t._$AI(n),i++;i<e.length&&(this._$AR(t&&t._$AB.nextSibling,i),e.length=i)}_$AR(s=this._$AA.nextSibling,e){for(this._$AP?.(!1,!0,e);s!==this._$AB;){let t=wt(s).nextSibling;wt(s).remove(),s=t}}setConnected(s){this._$AM===void 0&&(this._$Cv=s,this._$AP?.(s))}},ne=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(s,e,t,i,n){this.type=1,this._$AH=h,this._$AN=void 0,this.element=s,this.name=e,this._$AM=i,this.options=n,t.length>2||t[0]!==""||t[1]!==""?(this._$AH=Array(t.length-1).fill(new String),this.strings=t):this._$AH=h}_$AI(s,e=this,t,i){let n=this.strings,c=!1;if(n===void 0)s=ae(this,s,e,0),c=!fe(s)||s!==this._$AH&&s!==te,c&&(this._$AH=s);else{let d=s,u,_;for(s=n[0],u=0;u<n.length-1;u++)_=ae(this,d[t+u],e,u),_===te&&(_=this._$AH[u]),c||=!fe(_)||_!==this._$AH[u],_===h?s=h:s!==h&&(s+=(_??"")+n[u+1]),this._$AH[u]=_}c&&!i&&this.j(s)}j(s){s===h?this.element.removeAttribute(this.name):this.element.setAtLine truncated
|
\f\r"'\`<>=]|("|')|))|$)`,"g"),St=/'/g,At=/"/g,It=/^(?:script|style|textarea|title)$/i,et=a=>(s,...e)=>({_$litType$:a,strings:s,values:e}),o=et(1),oe=et(2),Fs=et(3),te=Symbol.for("lit-noChange"),h=Symbol.for("lit-nothing"),Tt=new WeakMap,X=ee.createTreeWalker(ee,129);Vi=(a,s)=>{let e=a.length-1,t=[],i,n=s===2?"<svg>":s===3?"<math>":"",c=ge;for(let d=0;d<e;d++){let u=a[d],_,v,f=-1,y=0;for(;y<u.length&&(c.lastIndex=y,v=c.exec(u),v!==null);)y=c.lastIndex,c===ge?v[1]==="!--"?c=kt:v[1]!==void 0?c=Et:v[2]!==void 0?(It.test(v[2])&&(i=RegExp("</"+v[2],"g")),c=Z):v[3]!==void 0&&(c=Z):c===Z?v[0]===">"?(c=i??ge,f=-1):v[1]===void 0?f=-2:(f=c.lastIndex-v[2].length,_=v[1],c=v[3]===void 0?Z:v[3]==='"'?At:St):c===At||c===St?c=Z:c===kt||c===Et?c=ge:(c=Z,i=void 0);let g=c===Z&&a[d+1].startsWith("/>")?" ":"";n+=c===ge?u+Fi:f>=0?(t.push(_),u.slice(0,f)+Ct+u.slice(f)+Q+g):u+Q+(f===-2?d:g)}return[Pt(a,n+(a[e]||"<?>")+(s===2?"</svg>":s===3?"</math>":"")),t]},ve=class a{constructor({strings:s,_$litType$:e},t){let i;this.parts=[];let n=0,c=0,d=s.length-1,u=this.parts,[_,v]=Vi(s,e);if(this.el=a.createElement(_,t),X.currentNode=this.el.content,e===2||e===3){let f=this.el.content.firstChild;f.replaceWith(...f.childNodes)}for(;(i=X.nextNode())!==null&&u.length<d;){if(i.nodeType===1){if(i.hasAttributes())for(let f of i.getAttributeNames())if(f.endsWith(Ct)){let y=v[c++],g=i.getAttribute(f).split(Q),x=/([.?@])?(.*)/.exec(y);u.push({type:1,index:n,name:x[2],strings:g,ctor:x[1]==="."?Ge:x[1]==="?"?Ye:x[1]==="@"?Je:ne}),i.removeAttribute(f)}else f.startsWith(Q)&&(u.push({type:6,index:n}),i.removeAttribute(f));if(It.test(i.tagName)){let f=i.textContent.split(Q),y=f.length-1;if(y>0){i.textContent=Ce?Ce.emptyScript:"";for(let g=0;g<y;g++)i.append(f[g],me()),X.nextNode(),u.push({type:2,index:++n});i.append(f[y],me())}}}else if(i.nodeType===8)if(i.data===Lt)u.push({type:2,index:n});else{let f=-1;for(;(f=i.data.indexOf(Q,f+1))!==-1;)u.push({type:7,index:n}),f+=Q.length-1}n++}}static createElement(s,e){let t=ee.createElement("template");return t.innerHTML=s,t}};Ke=class{constructor(s,e){this._$AV=[],this._$AN=void 0,this._$AD=s,this._$AM=e}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(s){let{el:{content:e},parts:t}=this._$AD,i=(s?.creationScope??ee).importNode(e,!0);X.currentNode=i;let n=X.nextNode(),c=0,d=0,u=t[0];for(;u!==void 0;){if(c===u.index){let _;u.type===2?_=new be(n,n.nextSibling,this,s):u.type===1?_=new u.ctor(n,u.name,u.strings,this,s):u.type===6&&(_=new Qe(n,this,s)),this._$AV.push(_),u=t[++d]}c!==u?.index&&(n=X.nextNode(),c++)}return X.currentNode=ee,i}p(s){let e=0;for(let t of this._$AV)t!==void 0&&(t.strings!==void 0?(t._$AI(s,t,e),e+=t.strings.length-2):t._$AI(s[e])),e++}},be=class a{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(s,e,t,i){this.type=2,this._$AH=h,this._$AN=void 0,this._$AA=s,this._$AB=e,this._$AM=t,this.options=i,this._$Cv=i?.isConnected??!0}get parentNode(){let s=this._$AA.parentNode,e=this._$AM;return e!==void 0&&s?.nodeType===11&&(s=e.parentNode),s}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(s,e=this){s=ae(this,s,e),fe(s)?s===h||s==null||s===""?(this._$AH!==h&&this._$AR(),this._$AH=h):s!==this._$AH&&s!==te&&this._(s):s._$litType$!==void 0?this.$(s):s.nodeType!==void 0?this.T(s):Ui(s)?this.k(s):this._(s)}O(s){return this._$AA.parentNode.insertBefore(s,this._$AB)}T(s){this._$AH!==s&&(this._$AR(),this._$AH=this.O(s))}_(s){this._$AH!==h&&fe(this._$AH)?this._$AA.nextSibling.data=s:this.T(ee.createTextNode(s)),this._$AH=s}$(s){let{values:e,_$litType$:t}=s,i=typeof t=="number"?this._$AC(s):(t.el===void 0&&(t.el=ve.createElement(Pt(t.h,t.h[0]),this.options)),t);if(this._$AH?._$AD===i)this._$AH.p(e);else{let n=new Ke(i,this),c=n.u(this.options);n.p(e),this.T(c),this._$AH=n}}_$AC(s){let e=Tt.get(s.strings);return e===void 0&&Tt.set(s.strings,e=new ve(s)),e}k(s){Xe(this._$AH)||(this._$AH=[],this._$AR());let e=this._$AH,t,i=0;for(let n of s)i===e.length?e.push(t=new a(this.O(me()),this.O(me()),this,this.options)):t=e[i],t._$AI(n),i++;i<e.length&&(this._$AR(t&&t._$AB.nextSibling,i),e.length=i)}_$AR(s=this._$AA.nextSibling,e){for(this._$AP?.(!1,!0,e);s!==this._$AB;){let t=wt(s).nextSibling;wt(s).remove(),s=t}}setConnected(s){this._$AM===void 0&&(this._$Cv=s,this._$AP?.(s))}},ne=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(s,e,t,i,n){this.type=1,this._$AH=h,this._$AN=void 0,this.element=s,this.name=e,this._$AM=i,this.options=n,t.length>2||t[0]!==""||t[1]!==""?(this._$AH=Array(t.length-1).fill(new String),this.strings=t):this._$AH=h}_$AI(s,e=this,t,i){let n=this.strings,c=!1;if(n===void 0)s=ae(this,s,e,0),c=!fe(s)||s!==this._$AH&&s!==te,c&&(this._$AH=s);else{let d=s,u,_;for(s=n[0],u=0;u<n.length-1;u++)_=ae(this,d[t+u],e,u),_===te&&(_=this._$AH[u]),c||=!fe(_)||_!==this._$AH[u],_===h?s=h:s!==h&&(s+=(_??"")+n[u+1]),this._$AH[u]=_}c&&!i&&this.j(s)}j(s){s===h?this.element.removeAttribute(this.name):this.element.setAtLine truncated
|
||||||
Replace seal
|
Replace seal
|
||||||
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",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_optional:"Due at time (optional, HH:MM)",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",confirm_delete_object:"Delete this object and all its tasks?",confirm_delete_task:"Delete this task?",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",tasks_lower:"tasks",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",for_at_least_minutes:"For at least (minutes)",safety_interval_days:"Safety interval (days, optional)",safety_interval:"Safety interval (optional)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:"Calendar",cal_no_events:"No maintenance",cal_window_7:"7 days",cal_window_14:"14 days",cal_window_30:"30 days",cal_window_365:"1 year",cal_every_n_days:"every {n} days",cal_source_time:"Time-based",cal_source_time_adaptive:"Time-based (adaptive)",cal_source_sensor:"Sensor-based",cal_predicted:"predicted",cal_confidence_high:"high confidence",cal_confidence_medium:"medium confidence",cal_confidence_low:"low confidence",budget_monthly:"Monthly budget",budget_yearly:"Yearly budget",groups:"Groups",new_group:"New group",edit_group:"Edit group",no_groups:"No groups yet",delete_group:"Delete group",delete_group_confirm:"Delete group '{name}'?",group_select_tasks:"Select tasks",group_name_required:"Name is required",description_optional:"Description (optional)",selected:"Sel
Line truncated
|
Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"{field}: too long (max {n} characters)",err_too_short:"{field}: too short (min {n} characters)",err_value_too_high:"{field}: too large (max {n})",err_value_too_low:"{field}: too small (min {n})",err_required:"{field}: required",err_wrong_type:"{field}: wrong type (expected: {type})",err_invalid_choice:"{field}: not an allowed value",err_invalid_value:"{field}: invalid value",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_optional:"Due at time (optional, HH:MM)",schedule_time_help:"Empty = midnight (default). HA timezone.",at_time:"at",notes_optional:"Notes (optional)",cost_optional:"Cost (optional)",duration_minutes:"Duration in minutes (optional)",days:"days",day:"day",today:"Today",d_overdue:"d overdue",no_tasks:"No maintenance tasks yet. Create an object to get started.",no_tasks_short:"No tasks",no_history:"No history entries yet.",show_all:"Show all",cost_duration_chart:"Cost & Duration",installed:"Installed",confirm_delete_object:"Delete this object and all its tasks?",confirm_delete_task:"Delete this task?",min:"Min",max:"Max",save:"Save",saving:"Saving\u2026",edit_task:"Edit Task",new_task:"New Maintenance Task",task_name:"Task name",maintenance_type:"Maintenance type",priority:"Priority",labels:"Labels",labels_placeholder:"e.g. safety, seasonal, tenant-visible",labels_help:"Comma-separated tags for filtering and reporting.",priority_low:"Low",priority_normal:"Normal",priority_high:"High",schedule_type:"Schedule type",interval_days:"Interval (days)",warning_days:"Warning days",earliest_completion_days:"Earliest completion (days before due)",earliest_completion_days_help:"Leave empty to allow completing any time. 0 = only on/after the due date.",last_performed_optional:"Last performed (optional)",interval_anchor:"Interval anchor",anchor_completion:"From completion date",anchor_planned:"From planned date (no drift)",edit_object:"Edit Object",name:"Name",manufacturer_optional:"Manufacturer (optional)",model_optional:"Model (optional)",serial_number_optional:"Serial number (optional)",serial_number_label:"S/N",documentation_url_label:"Manual",object_notes_label:"Notes",sort_due_date:"Due date",sort_object:"Object name",sort_type:"Type",sort_task_name:"Task name",all_objects:"All objects",tasks_lower:"tasks",no_tasks_yet:"No tasks yet",add_first_task:"Add first task",trigger_configuration:"Trigger Configuration",entity_id:"Entity ID",comma_separated:"comma-separated",entity_logic:"Entity logic",entity_logic_any:"Any entity triggers",entity_logic_all:"All entities must trigger",entities:"entities",attribute_optional:"Attribute (optional, blank = state)",use_entity_state:"Use entity state (no attribute)",trigger_above:"Trigger above",trigger_below:"Trigger below",for_at_least_minutes:"For at least (minutes)",safety_interval_days:"Safety interval (days, optional)",safety_interval:"Safety interval (optional)",delta_mode:"Delta mode",from_state_optional:"From state (optional)",to_state_optional:"To state (optional)",documentation_url_optional:"Documentation URL (optional)",object_notes_optional:"Notes (optional)",nfc_tag_id_optional:"NFC Tag ID (optional)",nfc_tags_empty_help:"No NFC tags registered in Home Assistant yet.",nfc_tags_open_settings:"Open Tags settings",nfc_tags_refresh:"Refresh",environmental_entity_optional:"Environmental sensor (optional)",environmental_entity_helper:"e.g. sensor.outdoor_temperature \u2014 adjusts the interval based on environmental conditions",environmental_attribute_optional:"Environmental attribute (optional)",nfc_tag_id:"NFC Tag ID",nfc_linked:"NFC tag linked",nfc_link_hint:"Click to link NFC tag",responsible_user:"Responsible User",shared_with:"Shared with (rotation)",shared_with_help:"Pick multiple people to share this task; the responsible person rotates on each completion.",rotation_strategy:"Rotation",rotation_none:"No rotation",rotation_round_robin:"Round-robin",rotation_least_completed:"Least completed",rotation_random:"Random",no_user_assigned:"(No user assigned)",all_users:"All Users",my_tasks:"My Tasks",tab_calendar:"Calendar",cal_no_events:"No maintenance",cal_window_7:"7 days",cal_window_14:"14 days",cal_window_30:"30 days",cal_window_365:"1 year",cal_every_n_days:"every {n} days",cal_source_time:"Time-based",cal_source_time_adaptive:"Time-based (adaptive)",cal_source_sensor:"Sensor-based",cal_predicted:"predicted",cal_confidence_high:"high confidence",cal_confidence_medium:"medium confidence",cal_confidence_low:"low confidence",budget_monthly:"Monthly budget",budget_yearly:"Yearly budget",groups:"Groups",new_group:"New group",edit_group:"Edit group",no_groups:"No groups yet",delete_group:"Delete group",delete_group_confirm:"Delete group '{name}'?",group_select_tasks:"Select tasks",group_name_required:"Name is required",description_optional:"Description (optional)",selected:"Sel
Line truncated
|
||||||
.field { display: flex; flex-direction: column; gap: 4px; }
|
.field { display: flex; flex-direction: column; gap: 4px; }
|
||||||
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
.field-label { font-size: 12px; color: var(--secondary-text-color); }
|
||||||
.field-input {
|
.field-input {
|
||||||
@@ -65,7 +65,10 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
label length. */
|
label length. */
|
||||||
.stats-bar {
|
.stats-bar {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(5, 1fr);
|
/* auto-fit instead of a fixed 5: with the budget feature on, two KPI
|
||||||
|
tiles join the strip (#125) — and on narrow screens the tiles wrap
|
||||||
|
instead of crushing. */
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
@@ -604,38 +607,25 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
50% { opacity: 0.7; }
|
50% { opacity: 0.7; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Budget bars */
|
/* Budget KPI tiles in the stats strip (#125) — replaced the full-width
|
||||||
.budget-bars {
|
budget-bars row. */
|
||||||
display: flex;
|
.stat-item.budget-tile .budget-tile-value {
|
||||||
gap: 16px;
|
font-size: 15px;
|
||||||
padding: 8px 16px;
|
padding-top: 5px;
|
||||||
flex-wrap: wrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
.budget-tile-bar {
|
||||||
.budget-item {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.budget-label {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.budget-bar {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 6px;
|
max-width: 130px;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
background: var(--divider-color);
|
background: var(--divider-color);
|
||||||
border-radius: 3px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
.budget-tile-bar > div {
|
||||||
.budget-bar-fill {
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 3px;
|
border-radius: 2px;
|
||||||
transition: width 0.3s;
|
transition: width 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1143,21 +1133,9 @@ Test pressure`,checklist_help:"One step per line. Max 100 items.",err_too_long:"
|
|||||||
|
|
||||||
.weibull-info-row { flex-direction: column; gap: 8px; }
|
.weibull-info-row { flex-direction: column; gap: 8px; }
|
||||||
|
|
||||||
/* One compact line instead of two stacked rows — the bars are glanceable
|
/* Budget tiles on narrow screens (#125): slightly smaller value so the
|
||||||
info, not the page's main content (UX 2026-07). The label stacks above
|
"x / y €" pair fits the wrapped grid cell. */
|
||||||
the value: side-by-side, the yearly pair wrapped raggedly on 360px
|
.stat-item.budget-tile .budget-tile-value { font-size: 13px; }
|
||||||
screens; a uniform two-line stack reads as intended at every width. */
|
|
||||||
.budget-bars { gap: 12px; padding: 6px 8px; }
|
|
||||||
.budget-item { min-width: 0; }
|
|
||||||
.budget-label {
|
|
||||||
font-size: 11px;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 0;
|
|
||||||
}
|
|
||||||
.budget-label span { white-space: nowrap; }
|
|
||||||
.budget-bar { height: 4px; }
|
|
||||||
|
|
||||||
.group-card { min-width: 0; max-width: 100%; }
|
.group-card { min-width: 0; max-width: 100%; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*! maintenance_supporter frontend 2.53.0 */
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
import"/maintenance_supporter_panelfiles/panel-chunks/chunk-6CM3ZIHM.js";import{b as Nt,c as oe}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-3FYWLAW5.js";import{a as E}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-MEKM6THN.js";import{a as se,b as ae,c as ne,d as re,e as Ct}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-JBZVB6GP.js";import{a as le}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-URNT5464.js";import{a as _,b as D,c as r,d as P,f as d,g as L,h as ee,i as T,j as m,k as jt,l as Mt,m as ut,n as s,o as St,p as q,q as Et,r as Y,s as Dt,t as _t,v as xt,w as mt,x as ie,y as Lt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-4MVSRJ3Y.js";function it(n){return!!n&&/^https?:\/\//i.test(n)}function ce(n,o){if(o.objects)return o.objects;let t=o.delta||[],e=o.removed||[];if(!t.length&&!e.length)return null;let i=new Map(n.map(a=>[a.entry_id,a]));for(let a of t)i.set(a.entry_id,a);for(let a of e)i.delete(a);return[...i.values()]}var At="2.53.0";function de(n,o=At){return!n||!o||o==="dev"?!1:n!==o}var F={overviewTab:"msp-overview-tab",collapsedSections:"msp-collapsed-sections",chartRange:"msp-chart-range",chartHideOutliers:"msp-chart-hide-outliers",taskSort:"maintenance_supporter_sort",objectSort:"maintenance_supporter_object_sort",groupBy:"maintenance_supporter_groupby",objectView:"maintenance_supporter_object_view",objectsCache:"msp-objects-cache"};var He=168*3600*1e3;function pe(){try{let n=localStorage.getItem(F.objectsCache);if(!n)return null;let o=JSON.parse(n);return o.v!==At||!Number.isFinite(o.at)||Date.now()-o.at>He||!Array.isArray(o.objects)||o.objects.length===0?null:{objects:o.objects,stats:o.stats??null}}catch{return null}}function Wt(n,o){if(!(!Array.isArray(n)||n.length===0))try{let t={v:At,at:Date.now(),objects:n,stats:o};localStorage.setItem(F.objectsCache,JSON.stringify(t))}catch{}}var Fe=["assignee_pool","required_completion_fields","checklist","labels","history"],Be=["checklist_progress"],Ve=["tasks","parts"],Ue=["manual_docs","battery_fleet_excluded"];function qt(n,o,t=[]){for(let e of o)n[e]===void 0&&(n[e]=[]);for(let e of t)n[e]===void 0&&(n[e]={})}function Ne(n){let o=n;qt(o,Ve),o.object&&typeof o.object=="object"&&qt(o.object,Ue);for(let t of o.tasks)qt(t,Fe,Be);return n}function Rt(n){for(let o of n)Ne(o);return n}var We={days:1,weeks:7,months:30.4368,years:365.25};function Yt(n,o){return!n||n<=0?0:n*(We[o||"days"]??1)}function Ot(n,o,t){let e=Yt(n,t);if(e<=0||o==null)return{pct:0,overflow:!1};let i=(e-o)/e*100;return{pct:Math.max(0,Math.min(100,i)),overflow:i>100}}function A(n){return String(n??"").replace(/[&<>"']/g,o=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[o])}function he(n,o,t,e,i,a){let l=[[t.manufacturer,n.manufacturer],[t.model,n.model],[t.serial,n.serial_number],[t.installed,n.installation_date?e(n.installation_date):null],[t.warranty,n.warranty_expiry?e(n.warranty_expiry):null]].filter(([,p])=>!!p),h=o.map(p=>{let u=t.scheduleLabel(p);return`<tr>
|
import"/maintenance_supporter_panelfiles/panel-chunks/chunk-AEF5ZY4E.js";import{b as Ut,c as oe}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-KH7UXWPC.js";import{a as E}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WZ6RLKNK.js";import{a as se,b as ae,c as ne,d as re,e as Ct}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-NSBT2PED.js";import{a as le}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A7WM72WE.js";import{a as g,b as D,c as r,d as P,f as d,g as L,h as ee,i as T,j as m,k as jt,l as St,m as ut,n as s,o as Mt,p as q,q as Et,r as Y,s as Dt,t as gt,v as xt,w as mt,x as ie,y as Lt}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C2ERU424.js";function it(n){return!!n&&/^https?:\/\//i.test(n)}function ce(n,o){if(o.objects)return o.objects;let t=o.delta||[],e=o.removed||[];if(!t.length&&!e.length)return null;let i=new Map(n.map(a=>[a.entry_id,a]));for(let a of t)i.set(a.entry_id,a);for(let a of e)i.delete(a);return[...i.values()]}var At="2.54.0";function de(n,o=At){return!n||!o||o==="dev"?!1:n!==o}var F={overviewTab:"msp-overview-tab",collapsedSections:"msp-collapsed-sections",chartRange:"msp-chart-range",chartHideOutliers:"msp-chart-hide-outliers",taskSort:"maintenance_supporter_sort",objectSort:"maintenance_supporter_object_sort",groupBy:"maintenance_supporter_groupby",objectView:"maintenance_supporter_object_view",objectsCache:"msp-objects-cache",gettingStartedDismissed:"msp-gs-dismissed"};var He=168*3600*1e3;function pe(){try{let n=localStorage.getItem(F.objectsCache);if(!n)return null;let o=JSON.parse(n);return o.v!==At||!Number.isFinite(o.at)||Date.now()-o.at>He||!Array.isArray(o.objects)||o.objects.length===0?null:{objects:o.objects,stats:o.stats??null}}catch{return null}}function Wt(n,o){if(!(!Array.isArray(n)||n.length===0))try{let t={v:At,at:Date.now(),objects:n,stats:o};localStorage.setItem(F.objectsCache,JSON.stringify(t))}catch{}}var Fe=["assignee_pool","required_completion_fields","checklist","labels","history"],Be=["checklist_progress"],Ve=["tasks","parts"],Ne=["manual_docs","battery_fleet_excluded"];function qt(n,o,t=[]){for(let e of o)n[e]===void 0&&(n[e]=[]);for(let e of t)n[e]===void 0&&(n[e]={})}function Ue(n){let o=n;qt(o,Ve),o.object&&typeof o.object=="object"&&qt(o.object,Ne);for(let t of o.tasks)qt(t,Fe,Be);return n}function Rt(n){for(let o of n)Ue(o);return n}var We={days:1,weeks:7,months:30.4368,years:365.25};function Yt(n,o){return!n||n<=0?0:n*(We[o||"days"]??1)}function Ot(n,o,t){let e=Yt(n,t);if(e<=0||o==null)return{pct:0,overflow:!1};let i=(e-o)/e*100;return{pct:Math.max(0,Math.min(100,i)),overflow:i>100}}function A(n){return String(n??"").replace(/[&<>"']/g,o=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[o])}function he(n,o,t,e,i,a){let l=[[t.manufacturer,n.manufacturer],[t.model,n.model],[t.serial,n.serial_number],[t.installed,n.installation_date?e(n.installation_date):null],[t.warranty,n.warranty_expiry?e(n.warranty_expiry):null]].filter(([,p])=>!!p),h=o.map(p=>{let u=t.scheduleLabel(p);return`<tr>
|
||||||
<td>${A(p.name)}</td>
|
<td>${A(p.name)}</td>
|
||||||
<td>${A(t.typeLabel(p.type))}</td>
|
<td>${A(t.typeLabel(p.type))}</td>
|
||||||
<td>${A(t.statusLabel(p.status))}</td>
|
<td>${A(t.statusLabel(p.status))}</td>
|
||||||
@@ -51,7 +51,7 @@ import"/maintenance_supporter_panelfiles/panel-chunks/chunk-6CM3ZIHM.js";import{
|
|||||||
</table>
|
</table>
|
||||||
${n.notes?`<div class="notes"><strong>${A(t.notes)}:</strong>
|
${n.notes?`<div class="notes"><strong>${A(t.notes)}:</strong>
|
||||||
${A(n.notes)}</div>`:""}
|
${A(n.notes)}</div>`:""}
|
||||||
</body></html>`}function Kt(n,o=new Date){if(!n)return{kind:"none",days:null,date:null};let t=new Date(`${n}T00:00:00`);if(isNaN(t.getTime()))return{kind:"none",days:null,date:null};let e=Date.UTC(o.getFullYear(),o.getMonth(),o.getDate()),i=Date.UTC(t.getFullYear(),t.getMonth(),t.getDate()),a=Math.round((i-e)/864e5);return a<0?{kind:"expired",days:a,date:n}:a<=60?{kind:"expiring",days:a,date:n}:{kind:"valid",days:a,date:n}}var z=n=>String(n??"").replace(/[&<>"']/g,o=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[o]);function ue(n,o,t,e,i,a,l,h,c,p=[]){let u=[[t.object,z(o)],[t.type,z(t.typeLabel(n.type))],[t.interval,z(i(n))],[t.nextDue,n.next_due?z(e(n.next_due)):"\u2014"],[t.lastDone,n.last_performed?z(e(n.last_performed)):z(t.never)]];n.priority&&n.priority!=="normal"&&u.push([t.priority,z(n.priority)]);let g=(n.checklist||[]).map(b=>`<li><span class="box"></span>${z(b)}</li>`).join(""),v=(b,x)=>b?`<figure class="qr"><img src="${b}" alt="" /><figcaption>${z(x)}</figcaption></figure>`:"";return`<!DOCTYPE html>
|
</body></html>`}function Kt(n,o=new Date){if(!n)return{kind:"none",days:null,date:null};let t=new Date(`${n}T00:00:00`);if(isNaN(t.getTime()))return{kind:"none",days:null,date:null};let e=Date.UTC(o.getFullYear(),o.getMonth(),o.getDate()),i=Date.UTC(t.getFullYear(),t.getMonth(),t.getDate()),a=Math.round((i-e)/864e5);return a<0?{kind:"expired",days:a,date:n}:a<=60?{kind:"expiring",days:a,date:n}:{kind:"valid",days:a,date:n}}var z=n=>String(n??"").replace(/[&<>"']/g,o=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[o]);function ue(n,o,t,e,i,a,l,h,c,p=[]){let u=[[t.object,z(o)],[t.type,z(t.typeLabel(n.type))],[t.interval,z(i(n))],[t.nextDue,n.next_due?z(e(n.next_due)):"\u2014"],[t.lastDone,n.last_performed?z(e(n.last_performed)):z(t.never)]];n.priority&&n.priority!=="normal"&&u.push([t.priority,z(n.priority)]);let _=(n.checklist||[]).map(b=>`<li><span class="box"></span>${z(b)}</li>`).join(""),v=(b,x)=>b?`<figure class="qr"><img src="${b}" alt="" /><figcaption>${z(x)}</figcaption></figure>`:"";return`<!DOCTYPE html>
|
||||||
<html><head><meta charset="utf-8"><meta name="color-scheme" content="light">
|
<html><head><meta charset="utf-8"><meta name="color-scheme" content="light">
|
||||||
<title>${z(n.name)} \u2014 ${z(t.title)}</title>
|
<title>${z(n.name)} \u2014 ${z(t.title)}</title>
|
||||||
<style>
|
<style>
|
||||||
@@ -103,7 +103,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<table class="meta">
|
<table class="meta">
|
||||||
${u.map(([b,x])=>`<tr><td>${z(b)}</td><td>${x}</td></tr>`).join("")}
|
${u.map(([b,x])=>`<tr><td>${z(b)}</td><td>${x}</td></tr>`).join("")}
|
||||||
</table>
|
</table>
|
||||||
${g?`<h2>${z(t.checklist)}</h2><ul class="check">${g}</ul>`:""}
|
${_?`<h2>${z(t.checklist)}</h2><ul class="check">${_}</ul>`:""}
|
||||||
${p.length?`<h2>${z(t.parts)}</h2><ul class="check">${p.map(b=>`<li><span class="box"></span>${z(b)}</li>`).join("")}</ul>`:""}
|
${p.length?`<h2>${z(t.parts)}</h2><ul class="check">${p.map(b=>`<li><span class="box"></span>${z(b)}</li>`).join("")}</ul>`:""}
|
||||||
${n.notes?`<h2>${z(t.notes)}</h2><div class="notes">${z(n.notes)}</div>`:""}
|
${n.notes?`<h2>${z(t.notes)}</h2><div class="notes">${z(n.notes)}</div>`:""}
|
||||||
${h?`<h2>${z(t.manualExcerpt)}</h2>
|
${h?`<h2>${z(t.manualExcerpt)}</h2>
|
||||||
@@ -131,7 +131,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
} catch (e) { console.warn("excerpt inline render failed", e); }
|
} catch (e) { console.warn("excerpt inline render failed", e); }
|
||||||
<\/script>`:""}`:""}
|
<\/script>`:""}`:""}
|
||||||
<footer>${z(o)} \xB7 ${z(n.name)} \xB7 ${z(t.printedOn)} ${z(c.slice(0,10))}</footer>
|
<footer>${z(o)} \xB7 ${z(n.name)} \xB7 ${z(t.printedOn)} ${z(c.slice(0,10))}</footer>
|
||||||
</body></html>`}var _e=D`
|
</body></html>`}var ge=D`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -184,10 +184,9 @@ ${A(n.notes)}</div>`:""}
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Narrow-viewport disclosure (UX 2026-07): the collapsed classes are only
|
/* Narrow-viewport disclosure (UX 2026-07): the collapsed class is only
|
||||||
ever set when the host is narrow — desktop always renders inline. */
|
ever set when the host is narrow — desktop always renders inline. */
|
||||||
.filter-bar.collapsed,
|
.filter-bar.collapsed {
|
||||||
.actions-bar.collapsed {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,29 +196,64 @@ ${A(n.notes)}</div>`:""}
|
|||||||
padding: 8px 0 0;
|
padding: 8px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-controls .mobile-toggle {
|
.mobile-controls .mobile-toggle,
|
||||||
|
.mobile-controls .new-menu-wrapper {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile-controls .new-menu-wrapper .new-menu-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.mobile-controls .mobile-toggle.active {
|
.mobile-controls .mobile-toggle.active {
|
||||||
--ha-button-background: var(--primary-color);
|
--ha-button-background: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions-bar {
|
/* #125: the one "New" menu that replaced the six-button actions bar. */
|
||||||
|
.new-menu-wrapper {
|
||||||
|
position: relative;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.new-menu-popup {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
min-width: 256px;
|
||||||
|
}
|
||||||
|
.new-menu-popup .popup-menu-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 10px;
|
||||||
padding: 4px 0 8px;
|
|
||||||
/* Left-aligned on purpose: flex-end mimicked the pre-v2.37 look (buttons
|
|
||||||
trailing the filter row), but on wide desktops it strands the primary
|
|
||||||
"new task" action at the far right of an otherwise empty row. */
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
}
|
||||||
|
.new-menu-popup .popup-menu-item ha-icon {
|
||||||
|
--mdc-icon-size: 18px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
:host([narrow]) .new-menu-popup { right: 0; left: auto; }
|
||||||
|
|
||||||
:host([narrow]) .actions-bar {
|
/* #125: getting-started chips — visibly temporary onboarding hints. */
|
||||||
flex-direction: column;
|
.gs-chips-wrap { margin: 2px 0 12px; }
|
||||||
align-items: stretch;
|
.gs-chips-label {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.6px;
|
||||||
|
margin-bottom: 7px;
|
||||||
}
|
}
|
||||||
|
.gs-chips { display: flex; gap: 10px; flex-wrap: wrap; }
|
||||||
|
.gs-chip {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 9px;
|
||||||
|
background: var(--secondary-background-color);
|
||||||
|
border: 1px dashed var(--divider-color);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 7px 8px 7px 13px;
|
||||||
|
font-size: 12.5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.gs-chip ha-icon { --mdc-icon-size: 16px; color: var(--primary-color); }
|
||||||
|
.gs-chip-x { display: inline-flex; padding: 0 3px; }
|
||||||
|
.gs-chip-x ha-icon { --mdc-icon-size: 14px; color: var(--secondary-text-color); }
|
||||||
|
|
||||||
.filter-field {
|
.filter-field {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1925,7 +1959,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
.icon-btn.danger { color: var(--error-color, #f44336); }
|
.icon-btn.danger { color: var(--error-color, #f44336); }
|
||||||
.icon-btn[disabled] { opacity: 0.4; pointer-events: none; }
|
.icon-btn[disabled] { opacity: 0.4; pointer-events: none; }
|
||||||
.icon-btn ha-icon { --mdc-icon-size: 20px; }
|
.icon-btn ha-icon { --mdc-icon-size: 20px; }
|
||||||
`,_([T({attribute:!1})],B.prototype,"hass",2),_([T({attribute:!1})],B.prototype,"entryId",2),_([T({type:Boolean})],B.prototype,"canWrite",2),_([m()],B.prototype,"_docs",2),_([m()],B.prototype,"_loaded",2),_([m()],B.prototype,"_busy",2),_([m()],B.prototype,"_error",2),_([m()],B.prototype,"_hint",2),_([m()],B.prototype,"_addingLink",2),_([m()],B.prototype,"_linkUrl",2),_([m()],B.prototype,"_linkTitle",2),_([m()],B.prototype,"_category",2),_([m()],B.prototype,"_thumbs",2),_([m()],B.prototype,"_lightboxUrl",2),_([m()],B.prototype,"_editingId",2),_([m()],B.prototype,"_editTitle",2),_([m()],B.prototype,"_editCategory",2),_([m()],B.prototype,"_dragOver",2);customElements.get("maintenance-documents-section")||customElements.define("maintenance-documents-section",B);var Ye=["manual","warranty","invoice","spare_parts","photo","other"],Ke={manual:"mdi:book-open-variant",warranty:"mdi:shield-check",invoice:"mdi:receipt-text-outline",spare_parts:"mdi:cog-outline",photo:"mdi:image-outline",other:"mdi:file-document-outline"},Q=class extends L{constructor(){super(...arguments);this.canWrite=!1;this._docs=[];this._loaded=!1;this._busy=!1;this._error="";this._attachId="";this._loadedKey="";this._localeReady=!1}get _lang(){return this.hass?.language||"en"}get _refId(){return this.partId||this.taskId||""}get _linkField(){return this.partId?"part_ids":"task_ids"}updated(t){super.updated(t),this.hass&&!this._localeReady&&(this._localeReady=!0,q(this._lang).then(()=>this.requestUpdate()));let e=`${this.entryId}|${this._refId}`;this.hass&&this.entryId&&this._refId&&this._loadedKey!==e&&(this._loadedKey=e,this._load())}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/list",entry_id:this.entryId});this._docs=t.documents||[],this._loaded=!0,this._error=""}catch(t){this._error=E(t,this._lang),this._loaded=!0}}_links(t){return t[this._linkField]||[]}_linked(){return this._docs.filter(t=>this._links(t).includes(this._refId))}_available(){return this._docs.filter(t=>!this._links(t).includes(this._refId))}async _setLinks(t,e){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/update",doc_id:t.id,[this._linkField]:e}),await this._load()}catch(i){this._error=E(i,this._lang)}finally{this._busy=!1}}_link(){let t=this._docs.find(e=>e.id===this._attachId);t&&(this._attachId="",this._setLinks(t,[...this._links(t),this._refId]))}_unlink(t){this._setLinks(t,this._links(t).filter(e=>e!==this._refId))}_isPdf(t){return t.mime==="application/pdf"||(t.filename||"").toLowerCase().endsWith(".pdf")}_pageFor(t){return this._isPdf(t)&&this.taskId?t.task_pages?.[this.taskId]:void 0}async _open(t){if(t.kind==="weblink"){window.open(t.url,"_blank","noopener");return}let e=this._pageFor(t),i=e?`#page=${e}`:"",a=window.open("about:blank","_blank");try{let l=await this.hass.connection.sendMessagePromise({type:"auth/sign_path",path:`/api/maintenance_supporter/document/${t.id}`,expires:300});a&&(a.location.href=new URL(l.path+i,window.location.origin).href)}catch(l){a&&a.close(),this._error=E(l,this._lang)}}async _setPage(t,e){if(this.taskId){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/update",doc_id:t.id,task_pages:{[this.taskId]:e}}),await this._load()}catch(i){this._error=E(i,this._lang)}finally{this._busy=!1}}}async _download(t){try{let e=await this.hass.connection.sendMessagePromise({type:"auth/sign_path",path:`/api/maintenance_supporter/document/${t.id}`,expires:30});Ct(e.path,t.filename||t.title||"document")}catch(e){this._error=E(e,this._lang)}}render(){if(!this._loaded||this._docs.length===0)return d;let t=this._lang,e=this._linked(),i=this._available();return r`
|
`,g([T({attribute:!1})],B.prototype,"hass",2),g([T({attribute:!1})],B.prototype,"entryId",2),g([T({type:Boolean})],B.prototype,"canWrite",2),g([m()],B.prototype,"_docs",2),g([m()],B.prototype,"_loaded",2),g([m()],B.prototype,"_busy",2),g([m()],B.prototype,"_error",2),g([m()],B.prototype,"_hint",2),g([m()],B.prototype,"_addingLink",2),g([m()],B.prototype,"_linkUrl",2),g([m()],B.prototype,"_linkTitle",2),g([m()],B.prototype,"_category",2),g([m()],B.prototype,"_thumbs",2),g([m()],B.prototype,"_lightboxUrl",2),g([m()],B.prototype,"_editingId",2),g([m()],B.prototype,"_editTitle",2),g([m()],B.prototype,"_editCategory",2),g([m()],B.prototype,"_dragOver",2);customElements.get("maintenance-documents-section")||customElements.define("maintenance-documents-section",B);var Ye=["manual","warranty","invoice","spare_parts","photo","other"],Ke={manual:"mdi:book-open-variant",warranty:"mdi:shield-check",invoice:"mdi:receipt-text-outline",spare_parts:"mdi:cog-outline",photo:"mdi:image-outline",other:"mdi:file-document-outline"},Q=class extends L{constructor(){super(...arguments);this.canWrite=!1;this._docs=[];this._loaded=!1;this._busy=!1;this._error="";this._attachId="";this._loadedKey="";this._localeReady=!1}get _lang(){return this.hass?.language||"en"}get _refId(){return this.partId||this.taskId||""}get _linkField(){return this.partId?"part_ids":"task_ids"}updated(t){super.updated(t),this.hass&&!this._localeReady&&(this._localeReady=!0,q(this._lang).then(()=>this.requestUpdate()));let e=`${this.entryId}|${this._refId}`;this.hass&&this.entryId&&this._refId&&this._loadedKey!==e&&(this._loadedKey=e,this._load())}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/list",entry_id:this.entryId});this._docs=t.documents||[],this._loaded=!0,this._error=""}catch(t){this._error=E(t,this._lang),this._loaded=!0}}_links(t){return t[this._linkField]||[]}_linked(){return this._docs.filter(t=>this._links(t).includes(this._refId))}_available(){return this._docs.filter(t=>!this._links(t).includes(this._refId))}async _setLinks(t,e){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/update",doc_id:t.id,[this._linkField]:e}),await this._load()}catch(i){this._error=E(i,this._lang)}finally{this._busy=!1}}_link(){let t=this._docs.find(e=>e.id===this._attachId);t&&(this._attachId="",this._setLinks(t,[...this._links(t),this._refId]))}_unlink(t){this._setLinks(t,this._links(t).filter(e=>e!==this._refId))}_isPdf(t){return t.mime==="application/pdf"||(t.filename||"").toLowerCase().endsWith(".pdf")}_pageFor(t){return this._isPdf(t)&&this.taskId?t.task_pages?.[this.taskId]:void 0}async _open(t){if(t.kind==="weblink"){window.open(t.url,"_blank","noopener");return}let e=this._pageFor(t),i=e?`#page=${e}`:"",a=window.open("about:blank","_blank");try{let l=await this.hass.connection.sendMessagePromise({type:"auth/sign_path",path:`/api/maintenance_supporter/document/${t.id}`,expires:300});a&&(a.location.href=new URL(l.path+i,window.location.origin).href)}catch(l){a&&a.close(),this._error=E(l,this._lang)}}async _setPage(t,e){if(this.taskId){this._busy=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/update",doc_id:t.id,task_pages:{[this.taskId]:e}}),await this._load()}catch(i){this._error=E(i,this._lang)}finally{this._busy=!1}}}async _download(t){try{let e=await this.hass.connection.sendMessagePromise({type:"auth/sign_path",path:`/api/maintenance_supporter/document/${t.id}`,expires:30});Ct(e.path,t.filename||t.title||"document")}catch(e){this._error=E(e,this._lang)}}render(){if(!this._loaded||this._docs.length===0)return d;let t=this._lang,e=this._linked(),i=this._available();return r`
|
||||||
<div class="task-docs">
|
<div class="task-docs">
|
||||||
<h3><ha-icon icon="mdi:paperclip"></ha-icon> ${s("documents",t)} (${e.length})</h3>
|
<h3><ha-icon icon="mdi:paperclip"></ha-icon> ${s("documents",t)} (${e.length})</h3>
|
||||||
${this._error?r`<div class="tdoc-error">${this._error}</div>`:d}
|
${this._error?r`<div class="tdoc-error">${this._error}</div>`:d}
|
||||||
@@ -2032,7 +2066,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
}
|
}
|
||||||
.tdoc-btn ha-icon { --mdc-icon-size: 18px; }
|
.tdoc-btn ha-icon { --mdc-icon-size: 18px; }
|
||||||
.tdoc-btn[disabled] { opacity: 0.5; pointer-events: none; }
|
.tdoc-btn[disabled] { opacity: 0.5; pointer-events: none; }
|
||||||
`,_([T({attribute:!1})],Q.prototype,"hass",2),_([T({attribute:!1})],Q.prototype,"entryId",2),_([T({attribute:!1})],Q.prototype,"taskId",2),_([T({attribute:!1})],Q.prototype,"partId",2),_([T({type:Boolean})],Q.prototype,"canWrite",2),_([m()],Q.prototype,"_docs",2),_([m()],Q.prototype,"_loaded",2),_([m()],Q.prototype,"_busy",2),_([m()],Q.prototype,"_error",2),_([m()],Q.prototype,"_attachId",2);customElements.get("maintenance-task-documents")||customElements.define("maintenance-task-documents",Q);var Ge={name:"",vendor:"",mpn:"",gtin:"",storage_location:"",product_url:"",unit:"",cost:"",stock:"",reorder_threshold:"",restock_quantity:"",auto_buy_task:!0,notes:""},K=class extends L{constructor(){super(...arguments);this.parts=[];this.canWrite=!1;this.currencySymbol="\u20AC";this._editing=null;this._busy=!1;this._error="";this._restockFor=null;this._restockQty="";this._restockInvalid=!1;this._docsFor=null}get _lang(){return this.hass?.locale?.language||this.hass?.language||"en"}connectedCallback(){super.connectedCallback(),q(this._lang).then(()=>this.requestUpdate())}_notifyChanged(){this.dispatchEvent(new CustomEvent("parts-changed",{bubbles:!0,composed:!0}))}async _send(t){this._busy=!0,this._error="";try{return await this.hass.connection.sendMessagePromise(t)}catch(e){return this._error=E(e,this._lang),null}finally{this._busy=!1}}_openAdd(){this._editing={...Ge}}_openEdit(t){this._editing={id:t.id,name:t.name,vendor:t.vendor||"",mpn:t.mpn||"",gtin:t.gtin||"",storage_location:t.storage_location||"",product_url:t.product_url||"",unit:t.unit||"",cost:t.cost!=null?String(t.cost):"",stock:t.stock!=null?String(t.stock):"",reorder_threshold:t.reorder_threshold!=null?String(t.reorder_threshold):"",restock_quantity:t.restock_quantity!=null?String(t.restock_quantity):"",auto_buy_task:!!t.auto_buy_task,notes:t.notes||""}}_formValue(t){let e=i=>i.trim()===""?null:Number(i);return{entry_id:this.entryId,name:t.name.trim(),vendor:t.vendor.trim()||null,mpn:t.mpn.trim()||null,gtin:t.gtin.trim()||null,storage_location:t.storage_location.trim()||null,product_url:t.product_url.trim()||null,unit:t.unit.trim()||null,cost:e(t.cost),stock:e(t.stock),reorder_threshold:e(t.reorder_threshold),restock_quantity:e(t.restock_quantity),auto_buy_task:t.auto_buy_task,notes:t.notes.trim()||null}}async _save(){let t=this._editing;if(!t||!t.name.trim())return;let e=this._formValue(t),i=t.id?"maintenance_supporter/part/update":"maintenance_supporter/part/create";await this._send(t.id?{type:i,part_id:t.id,...e}:{type:i,...e})!==null&&(this._editing=null,this._notifyChanged())}async _delete(t){if(!window.confirm(s("part_delete_confirm",this._lang).replace("{name}",t.name)))return;await this._send({type:"maintenance_supporter/part/delete",entry_id:this.entryId,part_id:t.id})!==null&&this._notifyChanged()}async _restock(t){let e=parseFloat(this._restockQty);if(!Number.isFinite(e)||e===0){this._restockInvalid=!0;return}this._restockInvalid=!1;let i=await this._send({type:"maintenance_supporter/part/restock",entry_id:this.entryId,part_id:t.id,delta:e});this._restockFor=null,i!==null&&(t.stock=i.stock,this.requestUpdate(),this._notifyChanged())}_identLine(t){return[t.vendor,t.mpn?`MPN: ${t.mpn}`:"",t.gtin?`GTIN: ${t.gtin}`:""].filter(Boolean).join(" \xB7 ")}_renderRow(t){let e=this._lang,i=t.stock!==null&&t.stock!==void 0,a=this._identLine(t),l=this._docsFor===t.id;return r`
|
`,g([T({attribute:!1})],Q.prototype,"hass",2),g([T({attribute:!1})],Q.prototype,"entryId",2),g([T({attribute:!1})],Q.prototype,"taskId",2),g([T({attribute:!1})],Q.prototype,"partId",2),g([T({type:Boolean})],Q.prototype,"canWrite",2),g([m()],Q.prototype,"_docs",2),g([m()],Q.prototype,"_loaded",2),g([m()],Q.prototype,"_busy",2),g([m()],Q.prototype,"_error",2),g([m()],Q.prototype,"_attachId",2);customElements.get("maintenance-task-documents")||customElements.define("maintenance-task-documents",Q);var Ge={name:"",vendor:"",mpn:"",gtin:"",storage_location:"",product_url:"",unit:"",cost:"",stock:"",reorder_threshold:"",restock_quantity:"",auto_buy_task:!0,notes:""},K=class extends L{constructor(){super(...arguments);this.parts=[];this.canWrite=!1;this.currencySymbol="\u20AC";this._editing=null;this._busy=!1;this._error="";this._restockFor=null;this._restockQty="";this._restockInvalid=!1;this._docsFor=null}get _lang(){return this.hass?.locale?.language||this.hass?.language||"en"}connectedCallback(){super.connectedCallback(),q(this._lang).then(()=>this.requestUpdate())}_notifyChanged(){this.dispatchEvent(new CustomEvent("parts-changed",{bubbles:!0,composed:!0}))}async _send(t){this._busy=!0,this._error="";try{return await this.hass.connection.sendMessagePromise(t)}catch(e){return this._error=E(e,this._lang),null}finally{this._busy=!1}}_openAdd(){this._editing={...Ge}}_openEdit(t){this._editing={id:t.id,name:t.name,vendor:t.vendor||"",mpn:t.mpn||"",gtin:t.gtin||"",storage_location:t.storage_location||"",product_url:t.product_url||"",unit:t.unit||"",cost:t.cost!=null?String(t.cost):"",stock:t.stock!=null?String(t.stock):"",reorder_threshold:t.reorder_threshold!=null?String(t.reorder_threshold):"",restock_quantity:t.restock_quantity!=null?String(t.restock_quantity):"",auto_buy_task:!!t.auto_buy_task,notes:t.notes||""}}_formValue(t){let e=i=>i.trim()===""?null:Number(i);return{entry_id:this.entryId,name:t.name.trim(),vendor:t.vendor.trim()||null,mpn:t.mpn.trim()||null,gtin:t.gtin.trim()||null,storage_location:t.storage_location.trim()||null,product_url:t.product_url.trim()||null,unit:t.unit.trim()||null,cost:e(t.cost),stock:e(t.stock),reorder_threshold:e(t.reorder_threshold),restock_quantity:e(t.restock_quantity),auto_buy_task:t.auto_buy_task,notes:t.notes.trim()||null}}async _save(){let t=this._editing;if(!t||!t.name.trim())return;let e=this._formValue(t),i=t.id?"maintenance_supporter/part/update":"maintenance_supporter/part/create";await this._send(t.id?{type:i,part_id:t.id,...e}:{type:i,...e})!==null&&(this._editing=null,this._notifyChanged())}async _delete(t){if(!window.confirm(s("part_delete_confirm",this._lang).replace("{name}",t.name)))return;await this._send({type:"maintenance_supporter/part/delete",entry_id:this.entryId,part_id:t.id})!==null&&this._notifyChanged()}async _restock(t){let e=parseFloat(this._restockQty);if(!Number.isFinite(e)||e===0){this._restockInvalid=!0;return}this._restockInvalid=!1;let i=await this._send({type:"maintenance_supporter/part/restock",entry_id:this.entryId,part_id:t.id,delta:e});this._restockFor=null,i!==null&&(t.stock=i.stock,this.requestUpdate(),this._notifyChanged())}_identLine(t){return[t.vendor,t.mpn?`MPN: ${t.mpn}`:"",t.gtin?`GTIN: ${t.gtin}`:""].filter(Boolean).join(" \xB7 ")}_renderRow(t){let e=this._lang,i=t.stock!==null&&t.stock!==void 0,a=this._identLine(t),l=this._docsFor===t.id;return r`
|
||||||
<div class="part-row ${t.is_low?"low":""}">
|
<div class="part-row ${t.is_low?"low":""}">
|
||||||
<ha-icon class="part-icon" icon=${t.is_low?"mdi:cart-arrow-down":"mdi:package-variant-closed"}></ha-icon>
|
<ha-icon class="part-icon" icon=${t.is_low?"mdi:cart-arrow-down":"mdi:package-variant-closed"}></ha-icon>
|
||||||
<div class="part-main">
|
<div class="part-main">
|
||||||
@@ -2277,21 +2311,21 @@ ${A(n.notes)}</div>`:""}
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
}
|
}
|
||||||
`,_([T({attribute:!1})],K.prototype,"hass",2),_([T({attribute:!1})],K.prototype,"entryId",2),_([T({attribute:!1})],K.prototype,"parts",2),_([T({type:Boolean})],K.prototype,"canWrite",2),_([T({attribute:!1})],K.prototype,"currencySymbol",2),_([m()],K.prototype,"_editing",2),_([m()],K.prototype,"_busy",2),_([m()],K.prototype,"_error",2),_([m()],K.prototype,"_restockFor",2),_([m()],K.prototype,"_restockQty",2),_([m()],K.prototype,"_restockInvalid",2),_([m()],K.prototype,"_docsFor",2);customElements.define("maintenance-parts-section",K);var G=class G extends L{constructor(){super(...arguments);this._ov=null;this._loading=!1;this._marking=!1;this._error="";this._history=null;this._rosterSort=G._storedSort();this._typeFilter=null;this._recorded=[];this._historyRequested=!1;this._localeReady=!1;this._markAll=async()=>{await this._mark(void 0)};this._repair=async()=>{if(!this._marking){this._marking=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/setup",language:this._lang}),await this._load()}catch(t){this._error=E(t,this._lang)}finally{this._marking=!1}}};this._loadHistory=async t=>{if(!(!t.target.open||this._historyRequested)){this._historyRequested=!0;try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/overview_history"});this._history=e.series}catch{this._history=null}}}}get _lang(){return this.hass?.language||"en"}connectedCallback(){super.connectedCallback(),this.hass&&this._load()}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,q(this._lang).then(()=>this.requestUpdate()),this._ov===null&&!this._loading&&this._load())}async _load(){this._loading=!0,this._error="";try{this._ov=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/overview"})}catch(t){this._error=E(t,this._lang)}finally{this._loading=!1}}async _mark(t){if(!this._marking){this._marking=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/mark_replaced",...t?{entity_ids:t}:{}}),await this._load()}catch(e){this._error=E(e,this._lang)}finally{this._marking=!1}}}async _setExcluded(t,e){if(!this._marking){this._marking=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/set_excluded",entity_id:t,excluded:e}),await this._load()}catch(i){this._error=E(i,this._lang)}finally{this._marking=!1}}}_sparkline(t){let e=this._history?.[t.entity_id];if(!e||e.points.length<2)return d;let i=110,a=24,l=2,h=e.points[0][0],c=e.points[e.points.length-1][0],p=Date.now()/1e3,u=t.status!=="low"&&t.predicted_source==="trend"&&t.days_until!=null?p+t.days_until*86400:null,g=Math.max(c,u??c),v=S=>g===h?l:l+(S-h)/(g-h)*(i-2*l),b=S=>l+(1-Math.min(100,Math.max(0,S))/100)*(a-2*l),x=e.points.map(([S,I])=>`${v(S).toFixed(1)},${b(I).toFixed(1)}`).join(" "),f=e.points[e.points.length-1][1],M=b(e.threshold).toFixed(1);return r`<svg
|
`,g([T({attribute:!1})],K.prototype,"hass",2),g([T({attribute:!1})],K.prototype,"entryId",2),g([T({attribute:!1})],K.prototype,"parts",2),g([T({type:Boolean})],K.prototype,"canWrite",2),g([T({attribute:!1})],K.prototype,"currencySymbol",2),g([m()],K.prototype,"_editing",2),g([m()],K.prototype,"_busy",2),g([m()],K.prototype,"_error",2),g([m()],K.prototype,"_restockFor",2),g([m()],K.prototype,"_restockQty",2),g([m()],K.prototype,"_restockInvalid",2),g([m()],K.prototype,"_docsFor",2);customElements.define("maintenance-parts-section",K);var G=class G extends L{constructor(){super(...arguments);this._ov=null;this._loading=!1;this._marking=!1;this._error="";this._history=null;this._rosterSort=G._storedSort();this._typeFilter=null;this._recorded=[];this._historyRequested=!1;this._localeReady=!1;this._markAll=async()=>{await this._mark(void 0)};this._repair=async()=>{if(!this._marking){this._marking=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/setup",language:this._lang}),await this._load()}catch(t){this._error=E(t,this._lang)}finally{this._marking=!1}}};this._loadHistory=async t=>{if(!(!t.target.open||this._historyRequested)){this._historyRequested=!0;try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/overview_history"});this._history=e.series}catch{this._history=null}}}}get _lang(){return this.hass?.language||"en"}connectedCallback(){super.connectedCallback(),this.hass&&this._load()}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,q(this._lang).then(()=>this.requestUpdate()),this._ov===null&&!this._loading&&this._load())}async _load(){this._loading=!0,this._error="";try{this._ov=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/overview"})}catch(t){this._error=E(t,this._lang)}finally{this._loading=!1}}async _mark(t){if(!this._marking){this._marking=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/mark_replaced",...t?{entity_ids:t}:{}}),await this._load()}catch(e){this._error=E(e,this._lang)}finally{this._marking=!1}}}async _setExcluded(t,e){if(!this._marking){this._marking=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/battery_fleet/set_excluded",entity_id:t,excluded:e}),await this._load()}catch(i){this._error=E(i,this._lang)}finally{this._marking=!1}}}_sparkline(t){let e=this._history?.[t.entity_id];if(!e||e.points.length<2)return d;let i=110,a=24,l=2,h=e.points[0][0],c=e.points[e.points.length-1][0],p=Date.now()/1e3,u=t.status!=="low"&&t.predicted_source==="trend"&&t.days_until!=null?p+t.days_until*86400:null,_=Math.max(c,u??c),v=M=>_===h?l:l+(M-h)/(_-h)*(i-2*l),b=M=>l+(1-Math.min(100,Math.max(0,M))/100)*(a-2*l),x=e.points.map(([M,I])=>`${v(M).toFixed(1)},${b(I).toFixed(1)}`).join(" "),f=e.points[e.points.length-1][1],S=b(e.threshold).toFixed(1);return r`<svg
|
||||||
class="bf-spark"
|
class="bf-spark"
|
||||||
viewBox="0 0 ${i} ${a}"
|
viewBox="0 0 ${i} ${a}"
|
||||||
role="img"
|
role="img"
|
||||||
aria-label=${s("battery_fleet_sparkline_hint",this._lang)}
|
aria-label=${s("battery_fleet_sparkline_hint",this._lang)}
|
||||||
>
|
>
|
||||||
<title>${s("battery_fleet_sparkline_hint",this._lang)}</title>
|
<title>${s("battery_fleet_sparkline_hint",this._lang)}</title>
|
||||||
<line class="bf-spark-th" x1="0" y1=${M} x2=${i} y2=${M}></line>
|
<line class="bf-spark-th" x1="0" y1=${S} x2=${i} y2=${S}></line>
|
||||||
<polyline class="bf-spark-line" points=${x}></polyline>
|
<polyline class="bf-spark-line" points=${x}></polyline>
|
||||||
${u!==null?r`<line
|
${u!==null?r`<line
|
||||||
class="bf-spark-proj"
|
class="bf-spark-proj"
|
||||||
x1=${v(c).toFixed(1)}
|
x1=${v(c).toFixed(1)}
|
||||||
y1=${b(f).toFixed(1)}
|
y1=${b(f).toFixed(1)}
|
||||||
x2=${v(u).toFixed(1)}
|
x2=${v(u).toFixed(1)}
|
||||||
y2=${M}
|
y2=${S}
|
||||||
></line>`:d}
|
></line>`:d}
|
||||||
</svg>`}static _storedSort(){try{return localStorage.getItem(G._SORT_KEY)==="name"?"name":"urgency"}catch{return"urgency"}}_setSort(t){this._rosterSort=t;try{localStorage.setItem(G._SORT_KEY,t)}catch{}}_sortedRoster(t){let e=this._typeFilter===null?t:t.filter(a=>a.battery_type===this._typeFilter);if(this._rosterSort==="name")return e;let i=a=>a.status==="low"?-1e3+(a.level??101)/101:a.days_until??1/0;return[...e].sort((a,l)=>i(a)-i(l)||a.device_name.localeCompare(l.device_name))}_predictedDate(t){return this._fmtDate(Date.now()+t*864e5)}_fmtDate(t){return new Intl.DateTimeFormat(this._lang,{day:"numeric",month:"numeric",year:"numeric"}).format(new Date(t))}_shoppingLine(t){return Object.entries(t).map(([e,i])=>r`<button
|
</svg>`}static _storedSort(){try{return localStorage.getItem(G._SORT_KEY)==="name"?"name":"urgency"}catch{return"urgency"}}_setSort(t){this._rosterSort=t;try{localStorage.setItem(G._SORT_KEY,t)}catch{}}_sortedRoster(t){let e=this._typeFilter===null?t:t.filter(a=>a.battery_type===this._typeFilter);if(this._rosterSort==="name")return e;let i=a=>a.status==="low"?-1e3+(a.level??101)/101:a.days_until??1/0;return[...e].sort((a,l)=>i(a)-i(l)||a.device_name.localeCompare(l.device_name))}_predictedDate(t){return this._fmtDate(Date.now()+t*864e5)}_fmtDate(t){return new Intl.DateTimeFormat(this._lang,{day:"numeric",month:"numeric",year:"numeric"}).format(new Date(t))}_shoppingLine(t){return Object.entries(t).map(([e,i])=>r`<button
|
||||||
class="bf-type-chip ${this._typeFilter===e?"bf-type-chip-active":""}"
|
class="bf-type-chip ${this._typeFilter===e?"bf-type-chip-active":""}"
|
||||||
@@ -2731,7 +2765,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 1px 4px 1px 10px;
|
padding: 1px 4px 1px 10px;
|
||||||
}
|
}
|
||||||
`,_([T({attribute:!1})],G.prototype,"hass",2),_([m()],G.prototype,"_ov",2),_([m()],G.prototype,"_loading",2),_([m()],G.prototype,"_marking",2),_([m()],G.prototype,"_error",2),_([m()],G.prototype,"_history",2),_([m()],G.prototype,"_rosterSort",2),_([m()],G.prototype,"_typeFilter",2),_([m()],G.prototype,"_recorded",2);var Gt=G;customElements.get("maintenance-battery-fleet-section")||customElements.define("maintenance-battery-fleet-section",Gt);var ge=5;function $t(n){let o=n.getFullYear(),t=String(n.getMonth()+1).padStart(2,"0"),e=String(n.getDate()).padStart(2,"0");return`${o}-${t}-${e}`}function Ze(n,o){let t=[];for(let e=0;e<o;e++){let i=new Date(n);i.setDate(i.getDate()+e),i.setHours(0,0,0,0),t.push($t(i))}return t}function It(n,o){let[t,e,i]=n.split("-").map(Number),a=new Date(t,e-1,i);return a.setDate(a.getDate()+o),$t(a)}function Qe(n){if(!n||n.length===0)return null;let o=n.map(t=>t.cost).filter(t=>typeof t=="number");return o.length===0?null:o.reduce((t,e)=>t+e,0)/o.length}function Xe(n){let{windowStart:o,windowEnd:t,task:e,entryId:i,objectName:a}=n,l=[],h=(g,v)=>({date:g,entry_id:i,task_id:e.id,task_name:e.name,object_name:a,status:v&&(e.status==="overdue"||e.status==="triggered")?"ok":e.status,days_until_due:v?null:e.days_until_due??null,projected:v,schedule_type:e.schedule_type,interval_days:e.interval_days??null,interval_unit:e.interval_unit??null,responsible_user_id:e.responsible_user_id??null,avg_cost:Qe(e.history),adaptive_enabled:!!e.adaptive_config?.enabled,prediction_confidence:e.threshold_prediction_confidence??null}),c=Math.max(1,Math.round(Yt(e.interval_days,e.interval_unit)));if(e.status==="overdue"||e.status==="triggered"){if(l.push(h(o,!1)),e.schedule_type==="time_based"&&e.interval_days&&e.interval_days>0){let g=It(o,c),v=1;for(;g<=t&&v<ge;)l.push(h(g,!0)),v++,g=It(g,c)}return l}let p=e.next_due;if(typeof p!="string"||!p)return l;let u=p.slice(0,10);if(u>=o&&u<=t)l.push(h(u,!1));else if(u>t)return l;if(e.schedule_type==="time_based"&&e.interval_days&&e.interval_days>0){let g=It(u,c),v=l.length;for(;g<=t&&v<ge;)g>=o&&(l.push(h(g,!0)),v++),g=It(g,c)}return l}var me={overdue:0,triggered:1,due_soon:2,ok:3};function ve(n,o,t,e=null){let i=Ze(o,t),a=i[0],l=i[i.length-1],h=[];for(let p of n){let u=p.object?.name||"",g=p.entry_id,v=p.tasks||[];for(let b of v){if(e&&b.responsible_user_id!==e||b.enabled===!1)continue;let x=Xe({windowStart:a,windowEnd:l,task:b,entryId:g,objectName:u});h.push(...x)}}let c=new Map;for(let p of i)c.set(p,[]);for(let p of h){let u=c.get(p.date);u&&u.push(p)}for(let[,p]of c)p.sort((u,g)=>{let v=me[u.status]??99,b=me[g.status]??99;if(v!==b)return v-b;if(u.projected!==g.projected)return u.projected?1:-1;let x=u.object_name.localeCompare(g.object_name);return x!==0?x:u.task_name.localeCompare(g.task_name)});return i.map(p=>({date:p,events:c.get(p)??[]}))}var Je={completed:"ok",reset:"ok",skipped:"due_soon",triggered:"triggered",trigger_replaced:"triggered",trigger_removed:"ok"};function ti(n,o){let t=[];for(let e=o-1;e>=0;e--){let i=new Date(n);i.setDate(i.getDate()-e),i.setHours(0,0,0,0),t.push($t(i))}return t}function be(n,o,t,e=null){let i=ti(o,t),a=i[0],l=i[i.length-1],h=new Map;for(let p of i)h.set(p,[]);for(let p of n){let u=p.object?.name||"",g=p.entry_id,v=p.tasks||[];for(let b of v){if(e&&b.responsible_user_id!==e)continue;let x=b.history||[];for(let f of x){if(typeof f?.timestamp!="string")continue;let M=f.timestamp.slice(0,10);if(M<a||M>l)continue;let S=h.get(M);if(!S)continue;let I=f.type??"completed";S.push({date:M,entry_id:g,task_id:b.id,task_name:b.name,object_name:u,status:Je[I]??"ok",days_until_due:null,projected:!1,schedule_type:b.schedule_type,interval_days:b.interval_days??null,responsible_user_id:b.responsible_user_id??null,avg_cost:typeof f.cost=="number"?f.cost:null,adaptive_enabled:!!b.adaptive_config?.enabled,prediction_confidence:null,history_timestamp:f.timestamp,history_type:I,history_cost:typeof f.cost=="number"?f.cost:null,history_notes:typeof f.notes=="string"?f.notes:null,history_duration:typeof f.duration=="number"?f.duration:null})}}}let c={completed:0,reset:1,skipped:2,triggered:3,trigger_replaced:4};for(let[,p]of h)p.sort((u,g)=>{let v=c[u.history_type??""]??99,b=c[g.history_type??""]??99;if(v!==b)return v-b;let x=u.object_name.localeCompare(g.object_name);return x!==0?x:u.task_name.localeCompare(g.task_name)});return i.map(p=>({date:p,events:h.get(p)??[]}))}var fe=D`
|
`,g([T({attribute:!1})],G.prototype,"hass",2),g([m()],G.prototype,"_ov",2),g([m()],G.prototype,"_loading",2),g([m()],G.prototype,"_marking",2),g([m()],G.prototype,"_error",2),g([m()],G.prototype,"_history",2),g([m()],G.prototype,"_rosterSort",2),g([m()],G.prototype,"_typeFilter",2),g([m()],G.prototype,"_recorded",2);var Gt=G;customElements.get("maintenance-battery-fleet-section")||customElements.define("maintenance-battery-fleet-section",Gt);var _e=5;function $t(n){let o=n.getFullYear(),t=String(n.getMonth()+1).padStart(2,"0"),e=String(n.getDate()).padStart(2,"0");return`${o}-${t}-${e}`}function Ze(n,o){let t=[];for(let e=0;e<o;e++){let i=new Date(n);i.setDate(i.getDate()+e),i.setHours(0,0,0,0),t.push($t(i))}return t}function It(n,o){let[t,e,i]=n.split("-").map(Number),a=new Date(t,e-1,i);return a.setDate(a.getDate()+o),$t(a)}function Qe(n){if(!n||n.length===0)return null;let o=n.map(t=>t.cost).filter(t=>typeof t=="number");return o.length===0?null:o.reduce((t,e)=>t+e,0)/o.length}function Xe(n){let{windowStart:o,windowEnd:t,task:e,entryId:i,objectName:a}=n,l=[],h=(_,v)=>({date:_,entry_id:i,task_id:e.id,task_name:e.name,object_name:a,status:v&&(e.status==="overdue"||e.status==="triggered")?"ok":e.status,days_until_due:v?null:e.days_until_due??null,projected:v,schedule_type:e.schedule_type,interval_days:e.interval_days??null,interval_unit:e.interval_unit??null,responsible_user_id:e.responsible_user_id??null,avg_cost:Qe(e.history),adaptive_enabled:!!e.adaptive_config?.enabled,prediction_confidence:e.threshold_prediction_confidence??null}),c=Math.max(1,Math.round(Yt(e.interval_days,e.interval_unit)));if(e.status==="overdue"||e.status==="triggered"){if(l.push(h(o,!1)),e.schedule_type==="time_based"&&e.interval_days&&e.interval_days>0){let _=It(o,c),v=1;for(;_<=t&&v<_e;)l.push(h(_,!0)),v++,_=It(_,c)}return l}let p=e.next_due;if(typeof p!="string"||!p)return l;let u=p.slice(0,10);if(u>=o&&u<=t)l.push(h(u,!1));else if(u>t)return l;if(e.schedule_type==="time_based"&&e.interval_days&&e.interval_days>0){let _=It(u,c),v=l.length;for(;_<=t&&v<_e;)_>=o&&(l.push(h(_,!0)),v++),_=It(_,c)}return l}var me={overdue:0,triggered:1,due_soon:2,ok:3};function ve(n,o,t,e=null){let i=Ze(o,t),a=i[0],l=i[i.length-1],h=[];for(let p of n){let u=p.object?.name||"",_=p.entry_id,v=p.tasks||[];for(let b of v){if(e&&b.responsible_user_id!==e||b.enabled===!1)continue;let x=Xe({windowStart:a,windowEnd:l,task:b,entryId:_,objectName:u});h.push(...x)}}let c=new Map;for(let p of i)c.set(p,[]);for(let p of h){let u=c.get(p.date);u&&u.push(p)}for(let[,p]of c)p.sort((u,_)=>{let v=me[u.status]??99,b=me[_.status]??99;if(v!==b)return v-b;if(u.projected!==_.projected)return u.projected?1:-1;let x=u.object_name.localeCompare(_.object_name);return x!==0?x:u.task_name.localeCompare(_.task_name)});return i.map(p=>({date:p,events:c.get(p)??[]}))}var Je={completed:"ok",reset:"ok",skipped:"due_soon",triggered:"triggered",trigger_replaced:"triggered",trigger_removed:"ok"};function ti(n,o){let t=[];for(let e=o-1;e>=0;e--){let i=new Date(n);i.setDate(i.getDate()-e),i.setHours(0,0,0,0),t.push($t(i))}return t}function be(n,o,t,e=null){let i=ti(o,t),a=i[0],l=i[i.length-1],h=new Map;for(let p of i)h.set(p,[]);for(let p of n){let u=p.object?.name||"",_=p.entry_id,v=p.tasks||[];for(let b of v){if(e&&b.responsible_user_id!==e)continue;let x=b.history||[];for(let f of x){if(typeof f?.timestamp!="string")continue;let S=f.timestamp.slice(0,10);if(S<a||S>l)continue;let M=h.get(S);if(!M)continue;let I=f.type??"completed";M.push({date:S,entry_id:_,task_id:b.id,task_name:b.name,object_name:u,status:Je[I]??"ok",days_until_due:null,projected:!1,schedule_type:b.schedule_type,interval_days:b.interval_days??null,responsible_user_id:b.responsible_user_id??null,avg_cost:typeof f.cost=="number"?f.cost:null,adaptive_enabled:!!b.adaptive_config?.enabled,prediction_confidence:null,history_timestamp:f.timestamp,history_type:I,history_cost:typeof f.cost=="number"?f.cost:null,history_notes:typeof f.notes=="string"?f.notes:null,history_duration:typeof f.duration=="number"?f.duration:null})}}}let c={completed:0,reset:1,skipped:2,triggered:3,trigger_replaced:4};for(let[,p]of h)p.sort((u,_)=>{let v=c[u.history_type??""]??99,b=c[_.history_type??""]??99;if(v!==b)return v-b;let x=u.object_name.localeCompare(_.object_name);return x!==0?x:u.task_name.localeCompare(_.task_name)});return i.map(p=>({date:p,events:h.get(p)??[]}))}var fe=D`
|
||||||
.cal-controls {
|
.cal-controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
@@ -2928,24 +2962,24 @@ ${A(n.notes)}</div>`:""}
|
|||||||
.cal-pill-day { font-size: 17px; }
|
.cal-pill-day { font-size: 17px; }
|
||||||
.cal-user-filter { margin-left: 0; width: 100%; }
|
.cal-user-filter { margin-left: 0; width: 100%; }
|
||||||
}
|
}
|
||||||
`;var X=class extends L{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"};this._objects=[];this._stats=null;this._windowDays=30;this._pastDays=0;this._userFilter="";this._objectFilter="";this._configuredObjects=[];this._unsub=null;this._dataLoaded=!1;this._lastConnection=null}static getConfigElement(){return document.createElement("maintenance-supporter-calendar-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-calendar-card",window_days:30,show_window_chips:!0,show_user_filter:!0}}setConfig(t){if(this._config={...t},t.past_days&&[30,90].includes(t.past_days)?this._pastDays=t.past_days:t.window_days&&[7,14,30,365].includes(t.window_days)&&(this._windowDays=t.window_days,this._pastDays=0),typeof t.user_filter=="string"&&(this._userFilter=t.user_filter),typeof t.object_filter=="string")this._objectFilter=t.object_filter,this._configuredObjects=[];else if(Array.isArray(t.object_filter)){let e=t.object_filter.filter(i=>typeof i=="string"&&i!=="");this._objectFilter=e.length===1?e[0]:"",this._configuredObjects=e.length>1?e:[]}}getCardSize(){return 6}get _lang(){return this.hass?.language||"en"}disconnectedCallback(){if(super.disconnectedCallback(),this._unsub){try{this._unsub()}catch{}this._unsub=null}this._dataLoaded=!1,this._lastConnection=null}updated(t){super.updated(t),t.has("hass")&&Et(this.hass?.locale);let e=this.hass?.language;if(e&&!St(e)&&q(e).then(()=>this.requestUpdate()),t.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){try{let[t,e]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=t.objects,this._stats=e}catch{}}async _subscribe(){try{let t=await this.hass.connection.subscribeMessage(e=>{let i=e;this._objects=i.objects},{type:"maintenance_supporter/subscribe"});if(!this.isConnected){t();return}this._unsub=t}catch{}}_onEventClick(t){if(t.history_timestamp){this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:edit-history",entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.history_timestamp},bubbles:!0,composed:!0}));return}this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:open-task",entry_id:t.entry_id,task_id:t.task_id},bubbles:!0,composed:!0}))}render(){if(!this.hass)return d;let t=this._lang,e=this._config.show_window_chips!==!1,i=this._config.show_user_filter!==!1,a=this._config.title,l=null;this._userFilter&&(l=this._userFilter==="current_user"?this.hass?.user?.id??null:this._userFilter);let h=y=>{let N=y.toLowerCase();return this._objects.find(H=>H.entry_id===y||H.object.name.toLowerCase()===N)?.entry_id??null},c=new Set(this._configuredObjects.map(h).filter(y=>y!==null)),p=c.size?this._objects.filter(y=>c.has(y.entry_id)):this._objects,u=this._config.show_object_filter!==!1&&p.length>1,g=this._objectFilter?h(this._objectFilter):null,v=g&&p.some(y=>y.entry_id===g)?p.filter(y=>y.entry_id===g):p,b=new Date;b.setHours(0,0,0,0);let x=this._pastDays>0,f=x?be(v,b,this._pastDays,l):ve(v,b,this._windowDays,l),M=$t(b),S=this._windowDays===365||x,I=S?f.filter(y=>y.events.length>0):f,R=y=>{let N=`cal-status-${y.status}`,W=y.projected?"cal-event-projected":"",H=y.status==="overdue"&&y.days_until_due!=null?` (${_t(y.days_until_due,t)})`:"",O=y.projected&&y.interval_days?r`<span class="cal-event-recur">${y.interval_unit&&y.interval_unit!=="days"?`${y.interval_days} ${s("unit_"+y.interval_unit,t)}`:s("cal_every_n_days",t).replace("{n}",String(y.interval_days))}</span>`:d,Z=y.schedule_type==="sensor_based",st=Z?r`<ha-icon class="cal-event-icon cal-source-sensor"
|
`;var X=class extends L{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"};this._objects=[];this._stats=null;this._windowDays=30;this._pastDays=0;this._userFilter="";this._objectFilter="";this._configuredObjects=[];this._unsub=null;this._dataLoaded=!1;this._lastConnection=null}static getConfigElement(){return document.createElement("maintenance-supporter-calendar-card-editor")}static getStubConfig(){return{type:"custom:maintenance-supporter-calendar-card",window_days:30,show_window_chips:!0,show_user_filter:!0}}setConfig(t){if(this._config={...t},t.past_days&&[30,90].includes(t.past_days)?this._pastDays=t.past_days:t.window_days&&[7,14,30,365].includes(t.window_days)&&(this._windowDays=t.window_days,this._pastDays=0),typeof t.user_filter=="string"&&(this._userFilter=t.user_filter),typeof t.object_filter=="string")this._objectFilter=t.object_filter,this._configuredObjects=[];else if(Array.isArray(t.object_filter)){let e=t.object_filter.filter(i=>typeof i=="string"&&i!=="");this._objectFilter=e.length===1?e[0]:"",this._configuredObjects=e.length>1?e:[]}}getCardSize(){return 6}get _lang(){return this.hass?.language||"en"}disconnectedCallback(){if(super.disconnectedCallback(),this._unsub){try{this._unsub()}catch{}this._unsub=null}this._dataLoaded=!1,this._lastConnection=null}updated(t){super.updated(t),t.has("hass")&&Et(this.hass?.locale);let e=this.hass?.language;if(e&&!Mt(e)&&q(e).then(()=>this.requestUpdate()),t.has("hass")&&this.hass){if(!this._dataLoaded)this._dataLoaded=!0,this._lastConnection=this.hass.connection,this._loadData(),this._subscribe();else if(this.hass.connection!==this._lastConnection){if(this._lastConnection=this.hass.connection,this._unsub){try{this._unsub()}catch{}this._unsub=null}this._subscribe(),this._loadData()}}}async _loadData(){try{let[t,e]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/statistics"})]);this._objects=t.objects,this._stats=e}catch{}}async _subscribe(){try{let t=await this.hass.connection.subscribeMessage(e=>{let i=e;this._objects=i.objects},{type:"maintenance_supporter/subscribe"});if(!this.isConnected){t();return}this._unsub=t}catch{}}_onEventClick(t){if(t.history_timestamp){this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:edit-history",entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.history_timestamp},bubbles:!0,composed:!0}));return}this.dispatchEvent(new CustomEvent("ll-custom",{detail:{type:"maintenance-supporter:open-task",entry_id:t.entry_id,task_id:t.task_id},bubbles:!0,composed:!0}))}render(){if(!this.hass)return d;let t=this._lang,e=this._config.show_window_chips!==!1,i=this._config.show_user_filter!==!1,a=this._config.title,l=null;this._userFilter&&(l=this._userFilter==="current_user"?this.hass?.user?.id??null:this._userFilter);let h=y=>{let U=y.toLowerCase();return this._objects.find(H=>H.entry_id===y||H.object.name.toLowerCase()===U)?.entry_id??null},c=new Set(this._configuredObjects.map(h).filter(y=>y!==null)),p=c.size?this._objects.filter(y=>c.has(y.entry_id)):this._objects,u=this._config.show_object_filter!==!1&&p.length>1,_=this._objectFilter?h(this._objectFilter):null,v=_&&p.some(y=>y.entry_id===_)?p.filter(y=>y.entry_id===_):p,b=new Date;b.setHours(0,0,0,0);let x=this._pastDays>0,f=x?be(v,b,this._pastDays,l):ve(v,b,this._windowDays,l),S=$t(b),M=this._windowDays===365||x,I=M?f.filter(y=>y.events.length>0):f,R=y=>{let U=`cal-status-${y.status}`,W=y.projected?"cal-event-projected":"",H=y.status==="overdue"&&y.days_until_due!=null?` (${gt(y.days_until_due,t)})`:"",O=y.projected&&y.interval_days?r`<span class="cal-event-recur">${y.interval_unit&&y.interval_unit!=="days"?`${y.interval_days} ${s("unit_"+y.interval_unit,t)}`:s("cal_every_n_days",t).replace("{n}",String(y.interval_days))}</span>`:d,Z=y.schedule_type==="sensor_based",st=Z?r`<ha-icon class="cal-event-icon cal-source-sensor"
|
||||||
title="${s("cal_source_sensor",t)}" icon="mdi:trending-up"></ha-icon>`:r`<ha-icon class="cal-event-icon cal-source-time"
|
title="${s("cal_source_sensor",t)}" icon="mdi:trending-up"></ha-icon>`:r`<ha-icon class="cal-event-icon cal-source-time"
|
||||||
title="${y.adaptive_enabled?s("cal_source_time_adaptive",t):s("cal_source_time",t)}"
|
title="${y.adaptive_enabled?s("cal_source_time_adaptive",t):s("cal_source_time",t)}"
|
||||||
icon="${y.adaptive_enabled?"mdi:clock-time-four-outline":"mdi:clock-outline"}"></ha-icon>`,rt=Z&&y.prediction_confidence&&y.status!=="triggered"&&!y.projected?r`<span class="cal-event-prediction cal-conf-${y.prediction_confidence}">
|
icon="${y.adaptive_enabled?"mdi:clock-time-four-outline":"mdi:clock-outline"}"></ha-icon>`,rt=Z&&y.prediction_confidence&&y.status!=="triggered"&&!y.projected?r`<span class="cal-event-prediction cal-conf-${y.prediction_confidence}">
|
||||||
${s("cal_predicted",t)} · ${s(`cal_confidence_${y.prediction_confidence}`,t)}
|
${s("cal_predicted",t)} · ${s(`cal_confidence_${y.prediction_confidence}`,t)}
|
||||||
</span>`:d,U=this._stats?.budget?.currency_symbol||ut,w=y.history_type?s(y.history_type,t):s(y.status,t);return r`
|
</span>`:d,N=this._stats?.budget?.currency_symbol||ut,w=y.history_type?s(y.history_type,t):s(y.status,t);return r`
|
||||||
<div class="cal-event ${W}"
|
<div class="cal-event ${W}"
|
||||||
@click=${()=>this._onEventClick(y)}>
|
@click=${()=>this._onEventClick(y)}>
|
||||||
${st}
|
${st}
|
||||||
<span class="cal-status-pill ${N}">${w}</span>
|
<span class="cal-status-pill ${U}">${w}</span>
|
||||||
<div class="cal-event-body">
|
<div class="cal-event-body">
|
||||||
<div class="cal-event-title">${y.object_name} · ${y.task_name}${H}</div>
|
<div class="cal-event-title">${y.object_name} · ${y.task_name}${H}</div>
|
||||||
${rt}
|
${rt}
|
||||||
${O}
|
${O}
|
||||||
</div>
|
</div>
|
||||||
${y.avg_cost!=null&&y.avg_cost>0?r`<span class="cal-event-cost">${y.avg_cost.toFixed(0)} ${U}</span>`:d}
|
${y.avg_cost!=null&&y.avg_cost>0?r`<span class="cal-event-cost">${y.avg_cost.toFixed(0)} ${N}</span>`:d}
|
||||||
</div>
|
</div>
|
||||||
`},j=y=>{let[N,W,H]=y.date.split("-").map(Number),O=new Date(N,W-1,H),Z=y.date===M,st=O.toLocaleDateString(t,{weekday:"short"}),rt=O.toLocaleDateString(t,{month:"long"});return r`
|
`},j=y=>{let[U,W,H]=y.date.split("-").map(Number),O=new Date(U,W-1,H),Z=y.date===S,st=O.toLocaleDateString(t,{weekday:"short"}),rt=O.toLocaleDateString(t,{month:"long"});return r`
|
||||||
<div class="cal-day-row">
|
<div class="cal-day-row">
|
||||||
<div class="cal-day-pill ${Z?"cal-today":""}">
|
<div class="cal-day-pill ${Z?"cal-today":""}">
|
||||||
<span class="cal-pill-weekday">${st}</span>
|
<span class="cal-pill-weekday">${st}</span>
|
||||||
@@ -2992,22 +3026,22 @@ ${A(n.notes)}</div>`:""}
|
|||||||
`:d}
|
`:d}
|
||||||
${u?r`
|
${u?r`
|
||||||
<select class="cal-user-filter"
|
<select class="cal-user-filter"
|
||||||
.value=${g??""}
|
.value=${_??""}
|
||||||
@change=${y=>{this._objectFilter=y.target.value}}>
|
@change=${y=>{this._objectFilter=y.target.value}}>
|
||||||
<option value="">${s("all_objects",t)}</option>
|
<option value="">${s("all_objects",t)}</option>
|
||||||
${[...p].sort((y,N)=>y.object.name.localeCompare(N.object.name)).map(y=>r`<option value=${y.entry_id} ?selected=${y.entry_id===g}>${y.object.name}</option>`)}
|
${[...p].sort((y,U)=>y.object.name.localeCompare(U.object.name)).map(y=>r`<option value=${y.entry_id} ?selected=${y.entry_id===_}>${y.object.name}</option>`)}
|
||||||
</select>
|
</select>
|
||||||
`:d}
|
`:d}
|
||||||
</div>
|
</div>
|
||||||
`:d}
|
`:d}
|
||||||
<div class="cal-rolling">
|
<div class="cal-rolling">
|
||||||
${I.length===0&&S?r`<div class="cal-empty">${s("cal_no_events",t)}</div>`:I.map(j)}
|
${I.length===0&&M?r`<div class="cal-empty">${s("cal_no_events",t)}</div>`:I.map(j)}
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`}};X.styles=[Lt,fe,D`
|
`}};X.styles=[Lt,fe,D`
|
||||||
:host { display: block; }
|
:host { display: block; }
|
||||||
ha-card { padding: 0; overflow: hidden; }
|
ha-card { padding: 0; overflow: hidden; }
|
||||||
`],_([T({attribute:!1})],X.prototype,"hass",2),_([m()],X.prototype,"_config",2),_([m()],X.prototype,"_objects",2),_([m()],X.prototype,"_stats",2),_([m()],X.prototype,"_windowDays",2),_([m()],X.prototype,"_pastDays",2),_([m()],X.prototype,"_userFilter",2),_([m()],X.prototype,"_objectFilter",2),_([m()],X.prototype,"_unsub",2);var ei=[{value:7,label:"Week (7 days)"},{value:14,label:"Fortnight (14 days)"},{value:30,label:"Month (30 days, default)"},{value:365,label:"Year (365 days, empty days collapsed)"}],bt=class extends L{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"}}setConfig(t){this._config={...t}}_valueChanged(t,e){let i={...this._config,[t]:e};t==="show_window_chips"&&e===!0&&delete i.show_window_chips,t==="show_user_filter"&&e===!0&&delete i.show_user_filter,t==="show_object_filter"&&e===!0&&delete i.show_object_filter,t==="title"&&(!e||typeof e=="string"&&e.trim()==="")&&delete i.title,t==="user_filter"&&e===""&&delete i.user_filter,this._config=i,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:i},bubbles:!0,composed:!0}))}render(){let t=this._config.window_days??30,e=this._config.show_window_chips!==!1,i=this._config.show_user_filter!==!1,a=this._config.user_filter??"",l=this._config.title??"";return r`
|
`],g([T({attribute:!1})],X.prototype,"hass",2),g([m()],X.prototype,"_config",2),g([m()],X.prototype,"_objects",2),g([m()],X.prototype,"_stats",2),g([m()],X.prototype,"_windowDays",2),g([m()],X.prototype,"_pastDays",2),g([m()],X.prototype,"_userFilter",2),g([m()],X.prototype,"_objectFilter",2),g([m()],X.prototype,"_unsub",2);var ei=[{value:7,label:"Week (7 days)"},{value:14,label:"Fortnight (14 days)"},{value:30,label:"Month (30 days, default)"},{value:365,label:"Year (365 days, empty days collapsed)"}],bt=class extends L{constructor(){super(...arguments);this._config={type:"custom:maintenance-supporter-calendar-card"}}setConfig(t){this._config={...t}}_valueChanged(t,e){let i={...this._config,[t]:e};t==="show_window_chips"&&e===!0&&delete i.show_window_chips,t==="show_user_filter"&&e===!0&&delete i.show_user_filter,t==="show_object_filter"&&e===!0&&delete i.show_object_filter,t==="title"&&(!e||typeof e=="string"&&e.trim()==="")&&delete i.title,t==="user_filter"&&e===""&&delete i.user_filter,this._config=i,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:i},bubbles:!0,composed:!0}))}render(){let t=this._config.window_days??30,e=this._config.show_window_chips!==!1,i=this._config.show_user_filter!==!1,a=this._config.user_filter??"",l=this._config.title??"";return r`
|
||||||
<div class="editor">
|
<div class="editor">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="title">Title (optional)</label>
|
<label for="title">Title (optional)</label>
|
||||||
@@ -3099,7 +3133,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--secondary-text-color, #666);
|
color: var(--secondary-text-color, #666);
|
||||||
}
|
}
|
||||||
`,_([T({attribute:!1})],bt.prototype,"hass",2),_([m()],bt.prototype,"_config",2);customElements.get("maintenance-supporter-calendar-card")||customElements.define("maintenance-supporter-calendar-card",X);customElements.get("maintenance-supporter-calendar-card-editor")||customElements.define("maintenance-supporter-calendar-card-editor",bt);var Ht=window;Ht.customCards=Ht.customCards||[];var ye="maintenance-supporter-calendar-card",ii=Ht.customCards.some(n=>n.type===ye);ii||Ht.customCards.push({type:ye,name:"Maintenance Supporter \u2014 Calendar",description:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",preview:!0});var dt=class extends L{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null}get _lang(){return this.hass?.language||"en"}openEdit(t){this._draft={...t},this._originalSnapshot={...t},this._error="",this._open=!0}close(){this._open=!1,this._error="",this._draft=null,this._originalSnapshot=null}_set(t,e){this._draft&&(this._draft={...this._draft,[t]:e})}async _save(){if(!(!this._draft||!this._originalSnapshot)){this._saving=!0,this._error="";try{let t={type:"maintenance_supporter/task/history/update",entry_id:this._draft.entry_id,task_id:this._draft.task_id,original_timestamp:this._originalSnapshot.original_timestamp};if(this._draft.timestamp!==this._originalSnapshot.timestamp&&(t.timestamp=this._draft.timestamp),this._draft.notes!==this._originalSnapshot.notes&&(t.notes=this._draft.notes),this._draft.cost!==this._originalSnapshot.cost&&(t.cost=this._draft.cost),this._draft.duration!==this._originalSnapshot.duration&&(t.duration=this._draft.duration),this._draft.completed_by!==this._originalSnapshot.completed_by&&(t.completed_by=this._draft.completed_by),Object.keys(t).filter(i=>!["type","entry_id","task_id","original_timestamp"].includes(i)).length===0){this.close();return}await this.hass.connection.sendMessagePromise(t),this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:this._draft.entry_id,task_id:this._draft.task_id,new_timestamp:this._draft.timestamp},bubbles:!0,composed:!0})),this.close()}catch(t){this._error=E(t,this._lang)}finally{this._saving=!1}}}render(){if(!this._open||!this._draft)return d;let t=this._lang,e=this._draft;return r`
|
`,g([T({attribute:!1})],bt.prototype,"hass",2),g([m()],bt.prototype,"_config",2);customElements.get("maintenance-supporter-calendar-card")||customElements.define("maintenance-supporter-calendar-card",X);customElements.get("maintenance-supporter-calendar-card-editor")||customElements.define("maintenance-supporter-calendar-card-editor",bt);var Ht=window;Ht.customCards=Ht.customCards||[];var ye="maintenance-supporter-calendar-card",ii=Ht.customCards.some(n=>n.type===ye);ii||Ht.customCards.push({type:ye,name:"Maintenance Supporter \u2014 Calendar",description:"Rolling calendar of maintenance tasks with 7/14/30/365 day windows, source icons, and prediction-confidence pills.",preview:!0});var dt=class extends L{constructor(){super(...arguments);this._open=!1;this._saving=!1;this._error="";this._draft=null;this._originalSnapshot=null}get _lang(){return this.hass?.language||"en"}openEdit(t){this._draft={...t},this._originalSnapshot={...t},this._error="",this._open=!0}close(){this._open=!1,this._error="",this._draft=null,this._originalSnapshot=null}_set(t,e){this._draft&&(this._draft={...this._draft,[t]:e})}async _save(){if(!(!this._draft||!this._originalSnapshot)){this._saving=!0,this._error="";try{let t={type:"maintenance_supporter/task/history/update",entry_id:this._draft.entry_id,task_id:this._draft.task_id,original_timestamp:this._originalSnapshot.original_timestamp};if(this._draft.timestamp!==this._originalSnapshot.timestamp&&(t.timestamp=this._draft.timestamp),this._draft.notes!==this._originalSnapshot.notes&&(t.notes=this._draft.notes),this._draft.cost!==this._originalSnapshot.cost&&(t.cost=this._draft.cost),this._draft.duration!==this._originalSnapshot.duration&&(t.duration=this._draft.duration),this._draft.completed_by!==this._originalSnapshot.completed_by&&(t.completed_by=this._draft.completed_by),Object.keys(t).filter(i=>!["type","entry_id","task_id","original_timestamp"].includes(i)).length===0){this.close();return}await this.hass.connection.sendMessagePromise(t),this.dispatchEvent(new CustomEvent("history-entry-saved",{detail:{entry_id:this._draft.entry_id,task_id:this._draft.task_id,new_timestamp:this._draft.timestamp},bubbles:!0,composed:!0})),this.close()}catch(t){this._error=E(t,this._lang)}finally{this._saving=!1}}}render(){if(!this._open||!this._draft)return d;let t=this._lang,e=this._draft;return r`
|
||||||
<div class="backdrop" @click=${this.close}></div>
|
<div class="backdrop" @click=${this.close}></div>
|
||||||
<div class="dialog" role="dialog" aria-modal="true">
|
<div class="dialog" role="dialog" aria-modal="true">
|
||||||
<h2>${s("history_edit_title",t)||"Edit history entry"}</h2>
|
<h2>${s("history_edit_title",t)||"Edit history entry"}</h2>
|
||||||
@@ -3206,7 +3240,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
background: rgba(211,47,47,0.1);
|
background: rgba(211,47,47,0.1);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
`,_([T({attribute:!1})],dt.prototype,"hass",2),_([m()],dt.prototype,"_open",2),_([m()],dt.prototype,"_saving",2),_([m()],dt.prototype,"_error",2),_([m()],dt.prototype,"_draft",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",dt);var J=class extends L{constructor(){super(...arguments);this._open=!1;this._title="";this._message="";this._confirmText="";this._danger=!1;this._inputLabel="";this._inputType="";this._inputValue="";this._resolve=null;this._promptResolve=null}confirm(t){return this._title=t.title,this._message=t.message,this._confirmText=t.confirmText||"OK",this._danger=t.danger||!1,this._inputLabel="",this._inputType="",this._inputValue="",this._open=!0,new Promise(e=>{this._resolve=e,this._promptResolve=null})}prompt(t){return this._title=t.title,this._message=t.message,this._confirmText=t.confirmText||"OK",this._danger=t.danger||!1,this._inputLabel=t.inputLabel||"",this._inputType=t.inputType||"text",this._inputValue=t.inputValue||"",this._open=!0,new Promise(e=>{this._promptResolve=e,this._resolve=null})}_cancel(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!1,value:""}),this._promptResolve=null),this._resolve?.(!1),this._resolve=null}_confirmAction(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!0,value:this._inputValue}),this._promptResolve=null),this._resolve?.(!0),this._resolve=null}render(){if(!this._open)return d;let t=this.hass?.language||"en";return r`
|
`,g([T({attribute:!1})],dt.prototype,"hass",2),g([m()],dt.prototype,"_open",2),g([m()],dt.prototype,"_saving",2),g([m()],dt.prototype,"_error",2),g([m()],dt.prototype,"_draft",2);customElements.get("maintenance-history-edit-dialog")||customElements.define("maintenance-history-edit-dialog",dt);var J=class extends L{constructor(){super(...arguments);this._open=!1;this._title="";this._message="";this._confirmText="";this._danger=!1;this._inputLabel="";this._inputType="";this._inputValue="";this._resolve=null;this._promptResolve=null}confirm(t){return this._title=t.title,this._message=t.message,this._confirmText=t.confirmText||"OK",this._danger=t.danger||!1,this._inputLabel="",this._inputType="",this._inputValue="",this._open=!0,new Promise(e=>{this._resolve=e,this._promptResolve=null})}prompt(t){return this._title=t.title,this._message=t.message,this._confirmText=t.confirmText||"OK",this._danger=t.danger||!1,this._inputLabel=t.inputLabel||"",this._inputType=t.inputType||"text",this._inputValue=t.inputValue||"",this._open=!0,new Promise(e=>{this._promptResolve=e,this._resolve=null})}_cancel(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!1,value:""}),this._promptResolve=null),this._resolve?.(!1),this._resolve=null}_confirmAction(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!0,value:this._inputValue}),this._promptResolve=null),this._resolve?.(!0),this._resolve=null}render(){if(!this._open)return d;let t=this.hass?.language||"en";return r`
|
||||||
<ha-dialog open @closed=${this._cancel}>
|
<ha-dialog open @closed=${this._cancel}>
|
||||||
<div class="dialog-title">${this._title}</div>
|
<div class="dialog-title">${this._title}</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -3267,7 +3301,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
ha-button.danger {
|
ha-button.danger {
|
||||||
--mdc-theme-primary: var(--error-color, #f44336);
|
--mdc-theme-primary: var(--error-color, #f44336);
|
||||||
}
|
}
|
||||||
`],_([T({attribute:!1})],J.prototype,"hass",2),_([m()],J.prototype,"_open",2),_([m()],J.prototype,"_title",2),_([m()],J.prototype,"_message",2),_([m()],J.prototype,"_confirmText",2),_([m()],J.prototype,"_danger",2),_([m()],J.prototype,"_inputLabel",2),_([m()],J.prototype,"_inputType",2),_([m()],J.prototype,"_inputValue",2);customElements.get("maintenance-confirm-dialog")||customElements.define("maintenance-confirm-dialog",J);var tt=class extends L{constructor(){super(...arguments);this.objects=[];this._summary=null;this._loaded=!1;this._busy=!1;this._error="";this._query="";this._results=[];this._expanded=!1;this._initiallyLoaded=!1;this._searchTimer=0}get _lang(){return this.hass?.language||"en"}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._initiallyLoaded&&(this._initiallyLoaded=!0,this._load(),q(this._lang).then(()=>this.requestUpdate()))}async _load(){this._busy=!0;try{this._summary=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/storage"}),this._error=""}catch(t){this._error=E(t,this._lang)}finally{this._loaded=!0,this._busy=!1}}_nameFor(t){return this.objects.find(i=>i.object?.id===t)?.object?.name||t.slice(0,8)}_entryFor(t){return this.objects.find(e=>e.object?.id===t)?.entry_id}_toggle(){this._expanded=!this._expanded}_openObject(t){this.dispatchEvent(new CustomEvent("open-object",{detail:{entry_id:t},bubbles:!0,composed:!0}))}_onSearch(t){this._query=t.target.value,clearTimeout(this._searchTimer),this._searchTimer=window.setTimeout(()=>{this._doSearch()},250)}async _doSearch(){let t=this._query.trim();if(!t){this._results=[];return}try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/search",query:t});this._results=e.results||[]}catch(e){this._error=E(e,this._lang),this._results=[]}}async _openResult(t){if(t.kind==="weblink"){window.open(t.url,"_blank","noopener");return}let e=window.open("about:blank","_blank");try{let i=await this.hass.connection.sendMessagePromise({type:"auth/sign_path",path:`/api/maintenance_supporter/document/${t.id}`,expires:300});e&&(e.location.href=new URL(i.path,window.location.origin).href)}catch(i){e&&e.close(),this._error=E(i,this._lang)}}_renderResult(t,e){return r`
|
`],g([T({attribute:!1})],J.prototype,"hass",2),g([m()],J.prototype,"_open",2),g([m()],J.prototype,"_title",2),g([m()],J.prototype,"_message",2),g([m()],J.prototype,"_confirmText",2),g([m()],J.prototype,"_danger",2),g([m()],J.prototype,"_inputLabel",2),g([m()],J.prototype,"_inputType",2),g([m()],J.prototype,"_inputValue",2);customElements.get("maintenance-confirm-dialog")||customElements.define("maintenance-confirm-dialog",J);var tt=class extends L{constructor(){super(...arguments);this.objects=[];this._summary=null;this._loaded=!1;this._busy=!1;this._error="";this._query="";this._results=[];this._expanded=!1;this._initiallyLoaded=!1;this._searchTimer=0}get _lang(){return this.hass?.language||"en"}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._initiallyLoaded&&(this._initiallyLoaded=!0,this._load(),q(this._lang).then(()=>this.requestUpdate()))}async _load(){this._busy=!0;try{this._summary=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/storage"}),this._error=""}catch(t){this._error=E(t,this._lang)}finally{this._loaded=!0,this._busy=!1}}_nameFor(t){return this.objects.find(i=>i.object?.id===t)?.object?.name||t.slice(0,8)}_entryFor(t){return this.objects.find(e=>e.object?.id===t)?.entry_id}_toggle(){this._expanded=!this._expanded}_openObject(t){this.dispatchEvent(new CustomEvent("open-object",{detail:{entry_id:t},bubbles:!0,composed:!0}))}_onSearch(t){this._query=t.target.value,clearTimeout(this._searchTimer),this._searchTimer=window.setTimeout(()=>{this._doSearch()},250)}async _doSearch(){let t=this._query.trim();if(!t){this._results=[];return}try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/documents/search",query:t});this._results=e.results||[]}catch(e){this._error=E(e,this._lang),this._results=[]}}async _openResult(t){if(t.kind==="weblink"){window.open(t.url,"_blank","noopener");return}let e=window.open("about:blank","_blank");try{let i=await this.hass.connection.sendMessagePromise({type:"auth/sign_path",path:`/api/maintenance_supporter/document/${t.id}`,expires:300});e&&(e.location.href=new URL(i.path,window.location.origin).href)}catch(i){e&&e.close(),this._error=E(i,this._lang)}}_renderResult(t,e){return r`
|
||||||
<div class="obj-row result-row" title=${s("doc_open",e)} @click=${()=>this._openResult(t)}>
|
<div class="obj-row result-row" title=${s("doc_open",e)} @click=${()=>this._openResult(t)}>
|
||||||
<ha-icon icon=${t.kind==="weblink"?"mdi:link-variant":"mdi:file-document-outline"}></ha-icon>
|
<ha-icon icon=${t.kind==="weblink"?"mdi:link-variant":"mdi:file-document-outline"}></ha-icon>
|
||||||
<div class="result-info">
|
<div class="result-info">
|
||||||
@@ -3425,7 +3459,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
.icon-btn:hover { background: var(--secondary-background-color, rgba(0,0,0,0.06)); }
|
.icon-btn:hover { background: var(--secondary-background-color, rgba(0,0,0,0.06)); }
|
||||||
.icon-btn[disabled] { opacity: 0.4; pointer-events: none; }
|
.icon-btn[disabled] { opacity: 0.4; pointer-events: none; }
|
||||||
.error { color: var(--error-color, #f44336); font-size: 13px; margin-top: 6px; }
|
.error { color: var(--error-color, #f44336); font-size: 13px; margin-top: 6px; }
|
||||||
`,_([T({attribute:!1})],tt.prototype,"hass",2),_([T({attribute:!1})],tt.prototype,"objects",2),_([m()],tt.prototype,"_summary",2),_([m()],tt.prototype,"_loaded",2),_([m()],tt.prototype,"_busy",2),_([m()],tt.prototype,"_error",2),_([m()],tt.prototype,"_query",2),_([m()],tt.prototype,"_results",2),_([m()],tt.prototype,"_expanded",2);customElements.get("maintenance-storage-section-card")||customElements.define("maintenance-storage-section-card",tt);var si=["month_jan","month_feb","month_mar","month_apr","month_may","month_jun","month_jul","month_aug","month_sep","month_oct","month_nov","month_dec"],at=class extends L{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._error="";this._entryId="";this._taskId="";this._values=new Array(12).fill("");this._save=async()=>{let t=this._buildOverrides();if(t!==null){this._loading=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/seasonal_overrides",entry_id:this._entryId,task_id:this._taskId,overrides:t}),this._open=!1,this.dispatchEvent(new CustomEvent("overrides-saved"))}catch(e){this._error=E(e,this._lang,s("save_error",this._lang))}finally{this._loading=!1}}};this._clearAll=async()=>{this._loading=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/seasonal_overrides",entry_id:this._entryId,task_id:this._taskId,overrides:{}}),this._values=new Array(12).fill(""),this._open=!1,this.dispatchEvent(new CustomEvent("overrides-saved"))}catch(t){this._error=E(t,this._lang,s("save_error",this._lang))}finally{this._loading=!1}}}get _lang(){return this.hass?.language??navigator.language.split("-")[0]??"en"}open(t,e,i){if(this._entryId=t,this._taskId=e,this._values=new Array(12).fill(""),i)for(let[a,l]of Object.entries(i)){let h=parseInt(a,10);h>=1&&h<=12&&typeof l=="number"&&(this._values[h-1]=l.toString())}this._error="",this._open=!0}_close(){this._open=!1}_buildOverrides(){let t={};for(let e=0;e<12;e++){let i=this._values[e].trim();if(!i)continue;let a=parseFloat(i);if(Number.isNaN(a))return this._error=`${s("month_"+["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"][e],this._lang)}: ${s("seasonal_override_invalid",this._lang)}`,null;if(a<.1||a>5)return this._error=s("seasonal_override_range",this._lang),null;t[e+1]=a}return t}render(){if(!this._open)return r``;let t=this._lang;return r`
|
`,g([T({attribute:!1})],tt.prototype,"hass",2),g([T({attribute:!1})],tt.prototype,"objects",2),g([m()],tt.prototype,"_summary",2),g([m()],tt.prototype,"_loaded",2),g([m()],tt.prototype,"_busy",2),g([m()],tt.prototype,"_error",2),g([m()],tt.prototype,"_query",2),g([m()],tt.prototype,"_results",2),g([m()],tt.prototype,"_expanded",2);customElements.get("maintenance-storage-section-card")||customElements.define("maintenance-storage-section-card",tt);var si=["month_jan","month_feb","month_mar","month_apr","month_may","month_jun","month_jul","month_aug","month_sep","month_oct","month_nov","month_dec"],at=class extends L{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._error="";this._entryId="";this._taskId="";this._values=new Array(12).fill("");this._save=async()=>{let t=this._buildOverrides();if(t!==null){this._loading=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/seasonal_overrides",entry_id:this._entryId,task_id:this._taskId,overrides:t}),this._open=!1,this.dispatchEvent(new CustomEvent("overrides-saved"))}catch(e){this._error=E(e,this._lang,s("save_error",this._lang))}finally{this._loading=!1}}};this._clearAll=async()=>{this._loading=!0,this._error="";try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/seasonal_overrides",entry_id:this._entryId,task_id:this._taskId,overrides:{}}),this._values=new Array(12).fill(""),this._open=!1,this.dispatchEvent(new CustomEvent("overrides-saved"))}catch(t){this._error=E(t,this._lang,s("save_error",this._lang))}finally{this._loading=!1}}}get _lang(){return this.hass?.language??navigator.language.split("-")[0]??"en"}open(t,e,i){if(this._entryId=t,this._taskId=e,this._values=new Array(12).fill(""),i)for(let[a,l]of Object.entries(i)){let h=parseInt(a,10);h>=1&&h<=12&&typeof l=="number"&&(this._values[h-1]=l.toString())}this._error="",this._open=!0}_close(){this._open=!1}_buildOverrides(){let t={};for(let e=0;e<12;e++){let i=this._values[e].trim();if(!i)continue;let a=parseFloat(i);if(Number.isNaN(a))return this._error=`${s("month_"+["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"][e],this._lang)}: ${s("seasonal_override_invalid",this._lang)}`,null;if(a<.1||a>5)return this._error=s("seasonal_override_range",this._lang),null;t[e+1]=a}return t}render(){if(!this._open)return r``;let t=this._lang;return r`
|
||||||
<ha-dialog open @closed=${this._close} heading="${s("seasonal_overrides_title",t)}">
|
<ha-dialog open @closed=${this._close} heading="${s("seasonal_overrides_title",t)}">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p class="hint">${s("seasonal_overrides_hint",t)}</p>
|
<p class="hint">${s("seasonal_overrides_hint",t)}</p>
|
||||||
@@ -3500,7 +3534,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
}
|
}
|
||||||
.spacer { flex: 1; }
|
.spacer { flex: 1; }
|
||||||
`,_([T({attribute:!1})],at.prototype,"hass",2),_([m()],at.prototype,"_open",2),_([m()],at.prototype,"_loading",2),_([m()],at.prototype,"_error",2),_([m()],at.prototype,"_entryId",2),_([m()],at.prototype,"_taskId",2),_([m()],at.prototype,"_values",2);customElements.get("maintenance-seasonal-overrides-dialog")||customElements.define("maintenance-seasonal-overrides-dialog",at);var et=class extends L{constructor(){super(...arguments);this.objects=[];this._open=!1;this._loading=!1;this._error="";this._groupId=null;this._name="";this._description="";this._selected=new Set;this._toggleTask=(t,e)=>{let i=`${t}:${e}`,a=new Set(this._selected);a.has(i)?a.delete(i):a.add(i),this._selected=a};this._save=async()=>{let t=this._name.trim();if(!t){this._error=s("group_name_required",this._lang);return}this._loading=!0,this._error="";try{let e=this._buildTaskRefs();this._groupId?await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/update",group_id:this._groupId,name:t,description:this._description,task_refs:e}):await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/create",name:t,description:this._description,task_refs:e}),this._open=!1,this.dispatchEvent(new CustomEvent("group-saved"))}catch(e){this._error=E(e,this._lang,s("save_error",this._lang))}finally{this._loading=!1}}}get _lang(){return this.hass?.language??navigator.language.split("-")[0]??"en"}openCreate(){this._reset(),this._open=!0}openEdit(t,e){this._reset(),this._groupId=t,this._name=e.name,this._description=e.description||"",this._selected=new Set(e.task_refs.map(i=>`${i.entry_id}:${i.task_id}`)),this._open=!0}_reset(){this._groupId=null,this._name="",this._description="",this._selected=new Set,this._error=""}_close(){this._open=!1}_buildTaskRefs(){return[...this._selected].map(t=>{let[e,i]=t.split(":",2);return{entry_id:e,task_id:i}})}render(){if(!this._open)return r``;let t=this._lang,e=this._groupId?s("edit_group",t):s("new_group",t);return r`
|
`,g([T({attribute:!1})],at.prototype,"hass",2),g([m()],at.prototype,"_open",2),g([m()],at.prototype,"_loading",2),g([m()],at.prototype,"_error",2),g([m()],at.prototype,"_entryId",2),g([m()],at.prototype,"_taskId",2),g([m()],at.prototype,"_values",2);customElements.get("maintenance-seasonal-overrides-dialog")||customElements.define("maintenance-seasonal-overrides-dialog",at);var et=class extends L{constructor(){super(...arguments);this.objects=[];this._open=!1;this._loading=!1;this._error="";this._groupId=null;this._name="";this._description="";this._selected=new Set;this._toggleTask=(t,e)=>{let i=`${t}:${e}`,a=new Set(this._selected);a.has(i)?a.delete(i):a.add(i),this._selected=a};this._save=async()=>{let t=this._name.trim();if(!t){this._error=s("group_name_required",this._lang);return}this._loading=!0,this._error="";try{let e=this._buildTaskRefs();this._groupId?await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/update",group_id:this._groupId,name:t,description:this._description,task_refs:e}):await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/create",name:t,description:this._description,task_refs:e}),this._open=!1,this.dispatchEvent(new CustomEvent("group-saved"))}catch(e){this._error=E(e,this._lang,s("save_error",this._lang))}finally{this._loading=!1}}}get _lang(){return this.hass?.language??navigator.language.split("-")[0]??"en"}openCreate(){this._reset(),this._open=!0}openEdit(t,e){this._reset(),this._groupId=t,this._name=e.name,this._description=e.description||"",this._selected=new Set(e.task_refs.map(i=>`${i.entry_id}:${i.task_id}`)),this._open=!0}_reset(){this._groupId=null,this._name="",this._description="",this._selected=new Set,this._error=""}_close(){this._open=!1}_buildTaskRefs(){return[...this._selected].map(t=>{let[e,i]=t.split(":",2);return{entry_id:e,task_id:i}})}render(){if(!this._open)return r``;let t=this._lang,e=this._groupId?s("edit_group",t):s("new_group",t);return r`
|
||||||
<ha-dialog open @closed=${this._close} heading="${e}">
|
<ha-dialog open @closed=${this._close} heading="${e}">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
${this._error?r`<div class="error">${this._error}</div>`:d}
|
${this._error?r`<div class="error">${this._error}</div>`:d}
|
||||||
@@ -3611,7 +3645,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
}
|
}
|
||||||
`,_([T({attribute:!1})],et.prototype,"hass",2),_([T({attribute:!1})],et.prototype,"objects",2),_([m()],et.prototype,"_open",2),_([m()],et.prototype,"_loading",2),_([m()],et.prototype,"_error",2),_([m()],et.prototype,"_groupId",2),_([m()],et.prototype,"_name",2),_([m()],et.prototype,"_description",2),_([m()],et.prototype,"_selected",2);customElements.get("maintenance-group-dialog")||customElements.define("maintenance-group-dialog",et);var lt=class extends L{constructor(){super(...arguments);this._open=!1;this._busy=!1;this._error="";this._name="";this._views=[];this._filters=null;this._localeReady=!1;this._save=async()=>{let t=this._name.trim();if(!(!t||this._busy||!this._filters)){this._busy=!0,this._error="";try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/views/save",name:t,filters:this._filters});this._name="",this._emitChanged(e.views||[])}catch(e){this._error=E(e,this._lang)}finally{this._busy=!1}}};this._delete=async t=>{if(!this._busy){this._busy=!0,this._error="";try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/views/delete",view_id:t});this._emitChanged(e.views||[])}catch(e){this._error=E(e,this._lang)}finally{this._busy=!1}}}}get _lang(){return this.hass?.language||"en"}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,q(this._lang).then(()=>this.requestUpdate()))}async open(t,e){this._open=!0,this._error="",this._name="",this._filters=t,this._views=e}_close(){this._open=!1}_emitChanged(t){this._views=t,this.dispatchEvent(new CustomEvent("saved-views-changed",{bubbles:!0,composed:!0,detail:{views:t}}))}render(){if(!this._open)return r``;let t=this._lang;return r`
|
`,g([T({attribute:!1})],et.prototype,"hass",2),g([T({attribute:!1})],et.prototype,"objects",2),g([m()],et.prototype,"_open",2),g([m()],et.prototype,"_loading",2),g([m()],et.prototype,"_error",2),g([m()],et.prototype,"_groupId",2),g([m()],et.prototype,"_name",2),g([m()],et.prototype,"_description",2),g([m()],et.prototype,"_selected",2);customElements.get("maintenance-group-dialog")||customElements.define("maintenance-group-dialog",et);var lt=class extends L{constructor(){super(...arguments);this._open=!1;this._busy=!1;this._error="";this._name="";this._views=[];this._filters=null;this._localeReady=!1;this._save=async()=>{let t=this._name.trim();if(!(!t||this._busy||!this._filters)){this._busy=!0,this._error="";try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/views/save",name:t,filters:this._filters});this._name="",this._emitChanged(e.views||[])}catch(e){this._error=E(e,this._lang)}finally{this._busy=!1}}};this._delete=async t=>{if(!this._busy){this._busy=!0,this._error="";try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/views/delete",view_id:t});this._emitChanged(e.views||[])}catch(e){this._error=E(e,this._lang)}finally{this._busy=!1}}}}get _lang(){return this.hass?.language||"en"}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,q(this._lang).then(()=>this.requestUpdate()))}async open(t,e){this._open=!0,this._error="",this._name="",this._filters=t,this._views=e}_close(){this._open=!1}_emitChanged(t){this._views=t,this.dispatchEvent(new CustomEvent("saved-views-changed",{bubbles:!0,composed:!0,detail:{views:t}}))}render(){if(!this._open)return r``;let t=this._lang;return r`
|
||||||
<div class="overlay" @click=${this._close}>
|
<div class="overlay" @click=${this._close}>
|
||||||
<div class="card" @click=${e=>e.stopPropagation()}>
|
<div class="card" @click=${e=>e.stopPropagation()}>
|
||||||
<div class="title">${s("views_dialog_title",t)}</div>
|
<div class="title">${s("views_dialog_title",t)}</div>
|
||||||
@@ -3739,14 +3773,14 @@ ${A(n.notes)}</div>`:""}
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
}
|
}
|
||||||
`,_([T({attribute:!1})],lt.prototype,"hass",2),_([m()],lt.prototype,"_open",2),_([m()],lt.prototype,"_busy",2),_([m()],lt.prototype,"_error",2),_([m()],lt.prototype,"_name",2),_([m()],lt.prototype,"_views",2);customElements.get("maintenance-saved-views-dialog")||customElements.define("maintenance-saved-views-dialog",lt);var ai=60,ni=20,xe=30;function Zt(n){let o=n.trigger_config??null;if(!o)return d;let t=o.type||"threshold",e=n.trigger_entity_info?.unit_of_measurement??"",i=0,a="";if(t==="threshold"){let c=n.trigger_current_value??null;if(c==null)return d;let p=o.trigger_above,u=o.trigger_below;if(p!=null){let g=u??0,v=p-g||1;i=Math.min(100,Math.max(0,(c-g)/v*100)),a=`${c.toFixed(1)} / ${p} ${e}`}else if(u!=null){let v=n.trigger_entity_info?.max??(u*2||100),b=v-u||1;i=Math.min(100,Math.max(0,(v-c)/b*100)),a=`${c.toFixed(1)} / ${u} ${e}`}else return d}else if(t==="counter"){let c=o.trigger_target_value||1,p;if(o.trigger_delta_mode?(p=n.trigger_current_delta??null,p==null&&n.trigger_baseline_value!=null&&n.trigger_current_value!=null&&(p=n.trigger_current_value-n.trigger_baseline_value)):p=n.trigger_current_value??null,p==null)return d;i=Math.min(100,Math.max(0,p/c*100)),a=`${p.toFixed(1)} / ${c} ${e}`}else if(t==="state_change"){let c=o.trigger_target_changes||1,p=n.trigger_current_value??null;if(p==null)return d;i=Math.min(100,Math.max(0,p/c*100)),a=`${Math.round(p)} / ${c}`}else if(t==="runtime"){let c=o.trigger_runtime_hours||100,p=n.trigger_current_value??null;if(p==null)return d;i=Math.min(100,Math.max(0,p/c*100)),a=`${p.toFixed(1)}h / ${c}h`}else if(t==="compound"){let c=o.compound_logic||o.operator||"AND",p=o.conditions?.length||0;a=`${c} (${p})`,i=n.trigger_active?100:0}else return d;let l=i>=100,h=i>90?"var(--error-color, #f44336)":i>70?"var(--warning-color, #ff9800)":"var(--primary-color)";return r`
|
`,g([T({attribute:!1})],lt.prototype,"hass",2),g([m()],lt.prototype,"_open",2),g([m()],lt.prototype,"_busy",2),g([m()],lt.prototype,"_error",2),g([m()],lt.prototype,"_name",2),g([m()],lt.prototype,"_views",2);customElements.get("maintenance-saved-views-dialog")||customElements.define("maintenance-saved-views-dialog",lt);var ai=60,ni=20,xe=30;function Zt(n){let o=n.trigger_config??null;if(!o)return d;let t=o.type||"threshold",e=n.trigger_entity_info?.unit_of_measurement??"",i=0,a="";if(t==="threshold"){let c=n.trigger_current_value??null;if(c==null)return d;let p=o.trigger_above,u=o.trigger_below;if(p!=null){let _=u??0,v=p-_||1;i=Math.min(100,Math.max(0,(c-_)/v*100)),a=`${c.toFixed(1)} / ${p} ${e}`}else if(u!=null){let v=n.trigger_entity_info?.max??(u*2||100),b=v-u||1;i=Math.min(100,Math.max(0,(v-c)/b*100)),a=`${c.toFixed(1)} / ${u} ${e}`}else return d}else if(t==="counter"){let c=o.trigger_target_value||1,p;if(o.trigger_delta_mode?(p=n.trigger_current_delta??null,p==null&&n.trigger_baseline_value!=null&&n.trigger_current_value!=null&&(p=n.trigger_current_value-n.trigger_baseline_value)):p=n.trigger_current_value??null,p==null)return d;i=Math.min(100,Math.max(0,p/c*100)),a=`${p.toFixed(1)} / ${c} ${e}`}else if(t==="state_change"){let c=o.trigger_target_changes||1,p=n.trigger_current_value??null;if(p==null)return d;i=Math.min(100,Math.max(0,p/c*100)),a=`${Math.round(p)} / ${c}`}else if(t==="runtime"){let c=o.trigger_runtime_hours||100,p=n.trigger_current_value??null;if(p==null)return d;i=Math.min(100,Math.max(0,p/c*100)),a=`${p.toFixed(1)}h / ${c}h`}else if(t==="compound"){let c=o.compound_logic||o.operator||"AND",p=o.conditions?.length||0;a=`${c} (${p})`,i=n.trigger_active?100:0}else return d;let l=i>=100,h=i>90?"var(--error-color, #f44336)":i>70?"var(--warning-color, #ff9800)":"var(--primary-color)";return r`
|
||||||
<div class="trigger-progress">
|
<div class="trigger-progress">
|
||||||
<div class="trigger-progress-bar">
|
<div class="trigger-progress-bar">
|
||||||
<div class="trigger-progress-fill${l?" overflow":""}" style="width:${i}%;background:${h}"></div>
|
<div class="trigger-progress-fill${l?" overflow":""}" style="width:${i}%;background:${h}"></div>
|
||||||
</div>
|
</div>
|
||||||
<span class="trigger-progress-label">${a}</span>
|
<span class="trigger-progress-label">${a}</span>
|
||||||
</div>
|
</div>
|
||||||
`}function Qt(n,o,t){if(!n.trigger_config?.entity_id)return d;let e=n.trigger_config.entity_id,i=o.get(e)||[],a=[];if(i.length>=2)a=i.map(j=>({ts:j.ts,val:j.val}));else{if(!n.history)return d;for(let j of n.history)j.trigger_value!=null&&a.push({ts:new Date(j.timestamp).getTime(),val:j.trigger_value})}if(n.trigger_current_value!=null&&a.push({ts:Date.now(),val:n.trigger_current_value}),a.length<2)return d;a.sort((j,y)=>j.ts-y.ts);let l=ai,h=ni,c=a.map(j=>j.val),p=Math.min(...c),u=Math.max(...c),g=u-p||1;p-=g*.1,u+=g*.1;let v=a[0].ts,x=a[a.length-1].ts-v||1,f=j=>(j-v)/x*l,M=j=>2+(1-(j-p)/(u-p))*(h-4),S=a;if(S.length>xe){let j=Math.ceil(S.length/xe);S=S.filter((y,N)=>N%j===0||N===S.length-1)}let I=S.map(j=>`${f(j.ts).toFixed(1)},${M(j.val).toFixed(1)}`).join(" "),R=n.trigger_active?"var(--error-color, #f44336)":"var(--primary-color)";return r`
|
`}function Qt(n,o,t){if(!n.trigger_config?.entity_id)return d;let e=n.trigger_config.entity_id,i=o.get(e)||[],a=[];if(i.length>=2)a=i.map(j=>({ts:j.ts,val:j.val}));else{if(!n.history)return d;for(let j of n.history)j.trigger_value!=null&&a.push({ts:new Date(j.timestamp).getTime(),val:j.trigger_value})}if(n.trigger_current_value!=null&&a.push({ts:Date.now(),val:n.trigger_current_value}),a.length<2)return d;a.sort((j,y)=>j.ts-y.ts);let l=ai,h=ni,c=a.map(j=>j.val),p=Math.min(...c),u=Math.max(...c),_=u-p||1;p-=_*.1,u+=_*.1;let v=a[0].ts,x=a[a.length-1].ts-v||1,f=j=>(j-v)/x*l,S=j=>2+(1-(j-p)/(u-p))*(h-4),M=a;if(M.length>xe){let j=Math.ceil(M.length/xe);M=M.filter((y,U)=>U%j===0||U===M.length-1)}let I=M.map(j=>`${f(j.ts).toFixed(1)},${S(j.val).toFixed(1)}`).join(" "),R=n.trigger_active?"var(--error-color, #f44336)":"var(--primary-color)";return r`
|
||||||
<svg class="mini-sparkline" viewBox="0 0 ${l} ${h}" preserveAspectRatio="none" role="img" aria-label="${s("chart_mini_sparkline",t)}">
|
<svg class="mini-sparkline" viewBox="0 0 ${l} ${h}" preserveAspectRatio="none" role="img" aria-label="${s("chart_mini_sparkline",t)}">
|
||||||
<polyline points="${I}" fill="none" stroke="${R}" stroke-width="1.5" stroke-linejoin="round" />
|
<polyline points="${I}" fill="none" stroke="${R}" stroke-width="1.5" stroke-linejoin="round" />
|
||||||
</svg>
|
</svg>
|
||||||
@@ -3759,7 +3793,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<div class="days-progress-bar" role="progressbar" aria-valuenow="${Math.round(e)}" aria-valuemin="0" aria-valuemax="100" aria-label="${s("days_progress",t)}">
|
<div class="days-progress-bar" role="progressbar" aria-valuenow="${Math.round(e)}" aria-valuemin="0" aria-valuemax="100" aria-label="${s("days_progress",t)}">
|
||||||
<div class="days-progress-fill${i?" overflow":""}" style="width:${e}%;background:${a}"></div>
|
<div class="days-progress-fill${i?" overflow":""}" style="width:${e}%;background:${a}"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="days-progress-text">${_t(n.days_until_due,t)}</div>
|
<div class="days-progress-text">${gt(n.days_until_due,t)}</div>
|
||||||
</div>
|
</div>
|
||||||
`}function wt(n,o,t=4){if(!isFinite(n)||!isFinite(o))return{ticks:[],niceMin:0,niceMax:1};if(n===o){let p=Math.abs(n)*.1||1;n-=p,o+=p}let e=o-n,i=Math.pow(10,Math.floor(Math.log10(e/Math.max(1,t)))),a=i;for(let p of[1,2,5,10])if(a=i*p,e/a<=t+.5)break;let l=Math.floor(n/a)*a,h=Math.ceil(o/a)*a,c=[];for(let p=l;p<=h+a*1e-6;p+=a)c.push(Math.abs(p)<a*1e-9?0:p);return{ticks:c,niceMin:l,niceMax:h}}function ct(n){let o=Math.abs(n);return o>=1e6?ft((n/1e6).toFixed(o>=1e7?0:1))+"M":o>=1e4?ft((n/1e3).toFixed(0))+"k":o>=1e3?ft((n/1e3).toFixed(1))+"k":o>=100?n.toFixed(0):o>=10||o>=1?ft(n.toFixed(1)):o===0?"0":ft(n.toFixed(2))}function ft(n){return n.replace(/\.0+$/,"").replace(/(\.\d*[1-9])0+$/,"$1")}function vt(n,o,t){let e=n.toLocaleString(t,{maximumFractionDigits:Math.abs(n)>=100?0:1});return o?`${e} ${o}`:e}function yt(n,o,t){let e=new Date(n),i=t?{month:"short",day:"numeric",year:"2-digit"}:{month:"short",day:"numeric"};return e.toLocaleDateString(o,i)}function Xt(n,o){return new Date(n).toLocaleDateString(o,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}function Ft(n,o){return new Date(n).getFullYear()!==new Date(o).getFullYear()}function Bt(n,o,t){if(t<2||o<=n)return[n,o];let e=[];for(let i=0;i<t;i++)e.push(n+(o-n)*i/(t-1));return e}var Vt=210,nt=46,pt=14,ht=12,we=14,ri=20+we,oi=[{days:7,key:"chart_range_7d"},{days:30,key:"chart_range_30d"},{days:90,key:"chart_range_90d"},{days:365,key:"chart_range_1y"}],V=class extends L{constructor(){super(...arguments);this.points=[];this.events=[];this.unit="";this.lang="en";this.thresholdAbove=null;this.thresholdBelow=null;this.targetValue=null;this.forceZero=!1;this.projection=null;this.rangeDays=30;this.showRange=!0;this.busy=!1;this.hideOutliers=!1;this.showOutlierToggle=!0;this._width=0;this._hover=null;this._ro=null}connectedCallback(){super.connectedCallback(),this._ro=new ResizeObserver(t=>{let e=Math.floor(t[0]?.contentRect?.width||0);e&&Math.abs(e-this._width)>2&&(this._width=e)}),this._ro.observe(this)}disconnectedCallback(){super.disconnectedCallback(),this._ro?.disconnect(),this._ro=null}_emitRange(t){t!==this.rangeDays&&this.dispatchEvent(new CustomEvent("range-change",{detail:{days:t},bubbles:!0,composed:!0}))}_toggleOutliers(){this.dispatchEvent(new CustomEvent("outlier-toggle",{detail:{hide:!this.hideOutliers},bubbles:!0,composed:!0}))}render(){let t=this._width||320,e=[...this.points].sort((a,l)=>a.ts-l.ts),i=this.lang;return r`
|
`}function wt(n,o,t=4){if(!isFinite(n)||!isFinite(o))return{ticks:[],niceMin:0,niceMax:1};if(n===o){let p=Math.abs(n)*.1||1;n-=p,o+=p}let e=o-n,i=Math.pow(10,Math.floor(Math.log10(e/Math.max(1,t)))),a=i;for(let p of[1,2,5,10])if(a=i*p,e/a<=t+.5)break;let l=Math.floor(n/a)*a,h=Math.ceil(o/a)*a,c=[];for(let p=l;p<=h+a*1e-6;p+=a)c.push(Math.abs(p)<a*1e-9?0:p);return{ticks:c,niceMin:l,niceMax:h}}function ct(n){let o=Math.abs(n);return o>=1e6?ft((n/1e6).toFixed(o>=1e7?0:1))+"M":o>=1e4?ft((n/1e3).toFixed(0))+"k":o>=1e3?ft((n/1e3).toFixed(1))+"k":o>=100?n.toFixed(0):o>=10||o>=1?ft(n.toFixed(1)):o===0?"0":ft(n.toFixed(2))}function ft(n){return n.replace(/\.0+$/,"").replace(/(\.\d*[1-9])0+$/,"$1")}function vt(n,o,t){let e=n.toLocaleString(t,{maximumFractionDigits:Math.abs(n)>=100?0:1});return o?`${e} ${o}`:e}function yt(n,o,t){let e=new Date(n),i=t?{month:"short",day:"numeric",year:"2-digit"}:{month:"short",day:"numeric"};return e.toLocaleDateString(o,i)}function Xt(n,o){return new Date(n).toLocaleDateString(o,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}function Ft(n,o){return new Date(n).getFullYear()!==new Date(o).getFullYear()}function Bt(n,o,t){if(t<2||o<=n)return[n,o];let e=[];for(let i=0;i<t;i++)e.push(n+(o-n)*i/(t-1));return e}var Vt=210,nt=46,pt=14,ht=12,we=14,ri=20+we,oi=[{days:7,key:"chart_range_7d"},{days:30,key:"chart_range_30d"},{days:90,key:"chart_range_90d"},{days:365,key:"chart_range_1y"}],V=class extends L{constructor(){super(...arguments);this.points=[];this.events=[];this.unit="";this.lang="en";this.thresholdAbove=null;this.thresholdBelow=null;this.targetValue=null;this.forceZero=!1;this.projection=null;this.rangeDays=30;this.showRange=!0;this.busy=!1;this.hideOutliers=!1;this.showOutlierToggle=!0;this._width=0;this._hover=null;this._ro=null}connectedCallback(){super.connectedCallback(),this._ro=new ResizeObserver(t=>{let e=Math.floor(t[0]?.contentRect?.width||0);e&&Math.abs(e-this._width)>2&&(this._width=e)}),this._ro.observe(this)}disconnectedCallback(){super.disconnectedCallback(),this._ro?.disconnect(),this._ro=null}_emitRange(t){t!==this.rangeDays&&this.dispatchEvent(new CustomEvent("range-change",{detail:{days:t},bubbles:!0,composed:!0}))}_toggleOutliers(){this.dispatchEvent(new CustomEvent("outlier-toggle",{detail:{hide:!this.hideOutliers},bubbles:!0,composed:!0}))}render(){let t=this._width||320,e=[...this.points].sort((a,l)=>a.ts-l.ts),i=this.lang;return r`
|
||||||
<div class="chart-wrap">
|
<div class="chart-wrap">
|
||||||
@@ -3780,7 +3814,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<ha-icon icon="mdi:chart-line"></ha-icon> ${s("loading_chart",i)}
|
<ha-icon icon="mdi:chart-line"></ha-icon> ${s("loading_chart",i)}
|
||||||
</div>`:this._renderSvg(t,e)}
|
</div>`:this._renderSvg(t,e)}
|
||||||
</div>
|
</div>
|
||||||
`}_renderSvg(t,e){let i=this.lang,a=t-nt-pt,l=Vt-ri,h=l-ht,c=1/0,p=-1/0;for(let w of e)c=Math.min(c,w.min??w.val),p=Math.max(p,w.max??w.val);this.thresholdAbove!=null&&(c=Math.min(c,this.thresholdAbove),p=Math.max(p,this.thresholdAbove)),this.thresholdBelow!=null&&(c=Math.min(c,this.thresholdBelow),p=Math.max(p,this.thresholdBelow)),this.targetValue!=null&&(c=Math.min(c,this.targetValue),p=Math.max(p,this.targetValue)),this.forceZero&&(c=Math.min(c,0));let u=(p-c||1)*.06,g=this.forceZero&&c>=0?0:c-u,{ticks:v,niceMin:b,niceMax:x}=wt(g,p+u,4);this.forceZero&&c>=0&&b<0&&(b=0,v=v.filter(w=>w>=0));let f=e[0].ts,M=e[e.length-1].ts,S=M-f||1,I=Ft(f,M),R=w=>nt+(w-f)/S*a,j=w=>ht+(1-(w-b)/(x-b||1))*h,y=e.map(w=>`${R(w.ts).toFixed(1)},${j(w.val).toFixed(1)}`).join(" "),N=`M${R(e[0].ts).toFixed(1)},${l} `+e.map(w=>`L${R(w.ts).toFixed(1)},${j(w.val).toFixed(1)}`).join(" ")+` L${R(e[e.length-1].ts).toFixed(1)},${l} Z`,W="",H=e.filter(w=>w.min!=null&&w.max!=null);if(H.length>=2){let w=H.map(C=>`${R(C.ts).toFixed(1)},${j(C.max).toFixed(1)}`),$=[...H].reverse().map(C=>`${R(C.ts).toFixed(1)},${j(C.min).toFixed(1)}`);W=`M${w[0]} `+w.slice(1).map(C=>`L${C}`).join(" ")+` L${$.join(" L")} Z`}let O=[];if(this.thresholdBelow!=null){let w=j(this.thresholdBelow);O.push({y:w,h:Math.max(0,l-w),lineY:w,label:`\u25BC ${ct(this.thresholdBelow)}`,labelY:Math.min(l-4,w+13)})}if(this.thresholdAbove!=null){let w=j(this.thresholdAbove);O.push({y:ht,h:Math.max(0,w-ht),lineY:w,label:`\u25B2 ${ct(this.thresholdAbove)}`,labelY:Math.max(ht+11,w-5)})}let Z=e[e.length-1],st=(this.events||[]).filter(w=>w.ts>=f&&w.ts<=M),rt=Bt(f,M,Math.max(2,Math.min(5,Math.floor(a/110)+1))),U=this._hover;return r`
|
`}_renderSvg(t,e){let i=this.lang,a=t-nt-pt,l=Vt-ri,h=l-ht,c=1/0,p=-1/0;for(let w of e)c=Math.min(c,w.min??w.val),p=Math.max(p,w.max??w.val);this.thresholdAbove!=null&&(c=Math.min(c,this.thresholdAbove),p=Math.max(p,this.thresholdAbove)),this.thresholdBelow!=null&&(c=Math.min(c,this.thresholdBelow),p=Math.max(p,this.thresholdBelow)),this.targetValue!=null&&(c=Math.min(c,this.targetValue),p=Math.max(p,this.targetValue)),this.forceZero&&(c=Math.min(c,0));let u=(p-c||1)*.06,_=this.forceZero&&c>=0?0:c-u,{ticks:v,niceMin:b,niceMax:x}=wt(_,p+u,4);this.forceZero&&c>=0&&b<0&&(b=0,v=v.filter(w=>w>=0));let f=e[0].ts,S=e[e.length-1].ts,M=S-f||1,I=Ft(f,S),R=w=>nt+(w-f)/M*a,j=w=>ht+(1-(w-b)/(x-b||1))*h,y=e.map(w=>`${R(w.ts).toFixed(1)},${j(w.val).toFixed(1)}`).join(" "),U=`M${R(e[0].ts).toFixed(1)},${l} `+e.map(w=>`L${R(w.ts).toFixed(1)},${j(w.val).toFixed(1)}`).join(" ")+` L${R(e[e.length-1].ts).toFixed(1)},${l} Z`,W="",H=e.filter(w=>w.min!=null&&w.max!=null);if(H.length>=2){let w=H.map(C=>`${R(C.ts).toFixed(1)},${j(C.max).toFixed(1)}`),$=[...H].reverse().map(C=>`${R(C.ts).toFixed(1)},${j(C.min).toFixed(1)}`);W=`M${w[0]} `+w.slice(1).map(C=>`L${C}`).join(" ")+` L${$.join(" L")} Z`}let O=[];if(this.thresholdBelow!=null){let w=j(this.thresholdBelow);O.push({y:w,h:Math.max(0,l-w),lineY:w,label:`\u25BC ${ct(this.thresholdBelow)}`,labelY:Math.min(l-4,w+13)})}if(this.thresholdAbove!=null){let w=j(this.thresholdAbove);O.push({y:ht,h:Math.max(0,w-ht),lineY:w,label:`\u25B2 ${ct(this.thresholdAbove)}`,labelY:Math.max(ht+11,w-5)})}let Z=e[e.length-1],st=(this.events||[]).filter(w=>w.ts>=f&&w.ts<=S),rt=Bt(f,S,Math.max(2,Math.min(5,Math.floor(a/110)+1))),N=this._hover;return r`
|
||||||
<div class="svg-holder">
|
<div class="svg-holder">
|
||||||
<svg
|
<svg
|
||||||
class="chart-svg"
|
class="chart-svg"
|
||||||
@@ -3813,7 +3847,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
fill="url(#dangerHatch)" />`)}
|
fill="url(#dangerHatch)" />`)}
|
||||||
|
|
||||||
${W?P`<path d="${W}" fill="var(--primary-color)" opacity="0.08" clip-path="url(#plot)" />`:d}
|
${W?P`<path d="${W}" fill="var(--primary-color)" opacity="0.08" clip-path="url(#plot)" />`:d}
|
||||||
<path d="${N}" fill="var(--primary-color)" opacity="0.10" clip-path="url(#plot)" />
|
<path d="${U}" fill="var(--primary-color)" opacity="0.10" clip-path="url(#plot)" />
|
||||||
<polyline points="${y}" fill="none" stroke="var(--primary-color)" stroke-width="2"
|
<polyline points="${y}" fill="none" stroke="var(--primary-color)" stroke-width="2"
|
||||||
stroke-linejoin="round" stroke-linecap="round" clip-path="url(#plot)" />
|
stroke-linejoin="round" stroke-linecap="round" clip-path="url(#plot)" />
|
||||||
${O.length?P`<polyline points="${y}" fill="none" stroke="var(--error-color, #f44336)" stroke-width="2"
|
${O.length?P`<polyline points="${y}" fill="none" stroke="var(--error-color, #f44336)" stroke-width="2"
|
||||||
@@ -3832,7 +3866,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
x2="${Math.min(R(this.projection[1].ts),t-pt).toFixed(1)}" y2="${j(Math.max(b,Math.min(x,this.projection[1].val))).toFixed(1)}"
|
x2="${Math.min(R(this.projection[1].ts),t-pt).toFixed(1)}" y2="${j(Math.max(b,Math.min(x,this.projection[1].val))).toFixed(1)}"
|
||||||
stroke="var(--warning-color, #ff9800)" stroke-width="1.5" stroke-dasharray="4,3" opacity="0.8" />`:d}
|
stroke="var(--warning-color, #ff9800)" stroke-width="1.5" stroke-dasharray="4,3" opacity="0.8" />`:d}
|
||||||
|
|
||||||
${rt.map((w,$)=>{let C=R(w),Ut=$===0?"start":$===rt.length-1?"end":"middle";return P`<text x="${C.toFixed(1)}" y="${Vt-5}" text-anchor="${Ut}" class="tick-label">${yt(w,i,I)}</text>`})}
|
${rt.map((w,$)=>{let C=R(w),Nt=$===0?"start":$===rt.length-1?"end":"middle";return P`<text x="${C.toFixed(1)}" y="${Vt-5}" text-anchor="${Nt}" class="tick-label">${yt(w,i,I)}</text>`})}
|
||||||
|
|
||||||
<line x1="${nt}" y1="${l}" x2="${t-pt}" y2="${l}" stroke="var(--divider-color)" stroke-width="1" />
|
<line x1="${nt}" y1="${l}" x2="${t-pt}" y2="${l}" stroke="var(--divider-color)" stroke-width="1" />
|
||||||
|
|
||||||
@@ -3842,25 +3876,25 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<title>${Xt(w.ts,i)}</title>
|
<title>${Xt(w.ts,i)}</title>
|
||||||
</rect>`})}
|
</rect>`})}
|
||||||
|
|
||||||
${U?P`
|
${N?P`
|
||||||
<line x1="${U.x.toFixed(1)}" y1="${ht}" x2="${U.x.toFixed(1)}" y2="${l}"
|
<line x1="${N.x.toFixed(1)}" y1="${ht}" x2="${N.x.toFixed(1)}" y2="${l}"
|
||||||
stroke="var(--secondary-text-color)" stroke-width="1" stroke-dasharray="3,3" opacity="0.7" />
|
stroke="var(--secondary-text-color)" stroke-width="1" stroke-dasharray="3,3" opacity="0.7" />
|
||||||
<circle cx="${U.x.toFixed(1)}" cy="${U.y.toFixed(1)}" r="4.5" fill="var(--primary-color)"
|
<circle cx="${N.x.toFixed(1)}" cy="${N.y.toFixed(1)}" r="4.5" fill="var(--primary-color)"
|
||||||
stroke="var(--card-background-color, #fff)" stroke-width="2" />`:P`<circle cx="${R(Z.ts).toFixed(1)}" cy="${j(Z.val).toFixed(1)}" r="4" fill="var(--primary-color)"
|
stroke="var(--card-background-color, #fff)" stroke-width="2" />`:P`<circle cx="${R(Z.ts).toFixed(1)}" cy="${j(Z.val).toFixed(1)}" r="4" fill="var(--primary-color)"
|
||||||
stroke="var(--card-background-color, #fff)" stroke-width="1.5" />`}
|
stroke="var(--card-background-color, #fff)" stroke-width="1.5" />`}
|
||||||
</svg>
|
</svg>
|
||||||
${U?r`<div
|
${N?r`<div
|
||||||
class="hover-chip"
|
class="hover-chip"
|
||||||
style="left:${Math.min(Math.max(U.x,70),t-70)}px"
|
style="left:${Math.min(Math.max(N.x,70),t-70)}px"
|
||||||
>
|
>
|
||||||
<div class="hover-date">${Xt(U.p.ts,i)}</div>
|
<div class="hover-date">${Xt(N.p.ts,i)}</div>
|
||||||
<div class="hover-val">
|
<div class="hover-val">
|
||||||
${vt(U.p.val,this.unit,i)}
|
${vt(N.p.val,this.unit,i)}
|
||||||
${U.p.min!=null&&U.p.max!=null?r`<span class="hover-range">(${ct(U.p.min)}–${ct(U.p.max)})</span>`:d}
|
${N.p.min!=null&&N.p.max!=null?r`<span class="hover-range">(${ct(N.p.min)}–${ct(N.p.max)})</span>`:d}
|
||||||
</div>
|
</div>
|
||||||
</div>`:d}
|
</div>`:d}
|
||||||
</div>
|
</div>
|
||||||
`}_onPointer(t,e,i,a,l){let c=t.currentTarget.getBoundingClientRect(),p=(t.clientX-c.left)/c.width*l;if(p<nt-8||p>l-pt+8){this._hover=null;return}let u=e[0],g=1/0;for(let v of e){let b=Math.abs(i(v.ts)-p);b<g&&(g=b,u=v)}this._hover={x:i(u.ts),y:a(u.val),p:u}}};V.styles=D`
|
`}_onPointer(t,e,i,a,l){let c=t.currentTarget.getBoundingClientRect(),p=(t.clientX-c.left)/c.width*l;if(p<nt-8||p>l-pt+8){this._hover=null;return}let u=e[0],_=1/0;for(let v of e){let b=Math.abs(i(v.ts)-p);b<_&&(_=b,u=v)}this._hover={x:i(u.ts),y:a(u.val),p:u}}};V.styles=D`
|
||||||
:host { display: block; width: 100%; }
|
:host { display: block; width: 100%; }
|
||||||
.chart-wrap { position: relative; }
|
.chart-wrap { position: relative; }
|
||||||
.range-chips { display: flex; gap: 4px; justify-content: flex-end; margin-bottom: 2px; }
|
.range-chips { display: flex; gap: 4px; justify-content: flex-end; margin-bottom: 2px; }
|
||||||
@@ -3895,7 +3929,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
.hover-date { font-size: 10.5px; color: var(--secondary-text-color); }
|
.hover-date { font-size: 10.5px; color: var(--secondary-text-color); }
|
||||||
.hover-val { font-size: 12.5px; font-weight: 600; color: var(--primary-text-color); }
|
.hover-val { font-size: 12.5px; font-weight: 600; color: var(--primary-text-color); }
|
||||||
.hover-range { font-weight: 400; color: var(--secondary-text-color); font-size: 11px; }
|
.hover-range { font-weight: 400; color: var(--secondary-text-color); font-size: 11px; }
|
||||||
`,_([T({attribute:!1})],V.prototype,"points",2),_([T({attribute:!1})],V.prototype,"events",2),_([T()],V.prototype,"unit",2),_([T()],V.prototype,"lang",2),_([T({attribute:!1})],V.prototype,"thresholdAbove",2),_([T({attribute:!1})],V.prototype,"thresholdBelow",2),_([T({attribute:!1})],V.prototype,"targetValue",2),_([T({type:Boolean})],V.prototype,"forceZero",2),_([T({attribute:!1})],V.prototype,"projection",2),_([T({attribute:!1})],V.prototype,"rangeDays",2),_([T({type:Boolean})],V.prototype,"showRange",2),_([T({type:Boolean})],V.prototype,"busy",2),_([T({type:Boolean})],V.prototype,"hideOutliers",2),_([T({type:Boolean})],V.prototype,"showOutlierToggle",2),_([m()],V.prototype,"_width",2),_([m()],V.prototype,"_hover",2);customElements.get("maintenance-trigger-chart")||customElements.define("maintenance-trigger-chart",V);function li(n){if(n.length<4)return n;let o=n.map(p=>p.val).sort((p,u)=>p-u),t=p=>{let u=(o.length-1)*p,g=Math.floor(u),v=Math.ceil(u);return o[g]+(o[v]-o[g])*(u-g)},e=t(.25),i=t(.75),a=i-e;if(a===0)return n;let l=e-1.5*a,h=i+1.5*a,c=n.filter(p=>p.val>=l&&p.val<=h);return c.length>=2?c:n}function ke(n,o){let t=n.trigger_config;if(!t)return d;let e=o.lang,i=n.trigger_entity_info,a=n.trigger_entity_infos,l=i?.friendly_name||t.entity_id||"\u2014",h=t.entity_id||"",c=t.entity_ids||(h?[h]:[]),p=i?.unit_of_measurement||"",u=n.trigger_current_value,g=t.type||"threshold",v=c.length>1,b=ci(n,p,o);return r`
|
`,g([T({attribute:!1})],V.prototype,"points",2),g([T({attribute:!1})],V.prototype,"events",2),g([T()],V.prototype,"unit",2),g([T()],V.prototype,"lang",2),g([T({attribute:!1})],V.prototype,"thresholdAbove",2),g([T({attribute:!1})],V.prototype,"thresholdBelow",2),g([T({attribute:!1})],V.prototype,"targetValue",2),g([T({type:Boolean})],V.prototype,"forceZero",2),g([T({attribute:!1})],V.prototype,"projection",2),g([T({attribute:!1})],V.prototype,"rangeDays",2),g([T({type:Boolean})],V.prototype,"showRange",2),g([T({type:Boolean})],V.prototype,"busy",2),g([T({type:Boolean})],V.prototype,"hideOutliers",2),g([T({type:Boolean})],V.prototype,"showOutlierToggle",2),g([m()],V.prototype,"_width",2),g([m()],V.prototype,"_hover",2);customElements.get("maintenance-trigger-chart")||customElements.define("maintenance-trigger-chart",V);function li(n){if(n.length<4)return n;let o=n.map(p=>p.val).sort((p,u)=>p-u),t=p=>{let u=(o.length-1)*p,_=Math.floor(u),v=Math.ceil(u);return o[_]+(o[v]-o[_])*(u-_)},e=t(.25),i=t(.75),a=i-e;if(a===0)return n;let l=e-1.5*a,h=i+1.5*a,c=n.filter(p=>p.val>=l&&p.val<=h);return c.length>=2?c:n}function ke(n,o){let t=n.trigger_config;if(!t)return d;let e=o.lang,i=n.trigger_entity_info,a=n.trigger_entity_infos,l=i?.friendly_name||t.entity_id||"\u2014",h=t.entity_id||"",c=t.entity_ids||(h?[h]:[]),p=i?.unit_of_measurement||"",u=n.trigger_current_value,_=t.type||"threshold",v=c.length>1,b=ci(n,p,o);return r`
|
||||||
<h3>${s("trigger",e)}</h3>
|
<h3>${s("trigger",e)}</h3>
|
||||||
<div class="trigger-card">
|
<div class="trigger-card">
|
||||||
<div class="trigger-header">
|
<div class="trigger-header">
|
||||||
@@ -3903,7 +3937,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<div>
|
<div>
|
||||||
${v?r`
|
${v?r`
|
||||||
<div class="trigger-entity-name">${c.length} ${s("entities",e)} (${t.entity_logic||"any"})</div>
|
<div class="trigger-entity-name">${c.length} ${s("entities",e)} (${t.entity_logic||"any"})</div>
|
||||||
<div class="trigger-entity-id">${c.map((x,f)=>r`${f>0?", ":""}<span class="entity-link" @click=${M=>mt(M,x)}>${x}</span>`)}${t.attribute?` \u2192 ${t.attribute}`:""}</div>
|
<div class="trigger-entity-id">${c.map((x,f)=>r`${f>0?", ":""}<span class="entity-link" @click=${S=>mt(S,x)}>${x}</span>`)}${t.attribute?` \u2192 ${t.attribute}`:""}</div>
|
||||||
`:r`
|
`:r`
|
||||||
<div class="trigger-entity-name">${l}</div>
|
<div class="trigger-entity-name">${l}</div>
|
||||||
<div class="trigger-entity-id">${h?r`<span class="entity-link" @click=${x=>mt(x,h)}>${h}</span>`:""}${t.attribute?` \u2192 ${t.attribute}`:""}</div>
|
<div class="trigger-entity-id">${h?r`<span class="entity-link" @click=${x=>mt(x,h)}>${h}</span>`:""}${t.attribute?` \u2192 ${t.attribute}`:""}</div>
|
||||||
@@ -3922,21 +3956,21 @@ ${A(n.notes)}</div>`:""}
|
|||||||
`:d}
|
`:d}
|
||||||
|
|
||||||
<div class="trigger-limits">
|
<div class="trigger-limits">
|
||||||
${g==="threshold"?r`
|
${_==="threshold"?r`
|
||||||
${t.trigger_above!=null?r`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${s("threshold_above",e)}: ${t.trigger_above} ${p}</span>`:d}
|
${t.trigger_above!=null?r`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${s("threshold_above",e)}: ${t.trigger_above} ${p}</span>`:d}
|
||||||
${t.trigger_below!=null?r`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${s("threshold_below",e)}: ${t.trigger_below} ${p}</span>`:d}
|
${t.trigger_below!=null?r`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${s("threshold_below",e)}: ${t.trigger_below} ${p}</span>`:d}
|
||||||
${t.trigger_for_minutes?r`<span class="trigger-limit-item"><span class="dot range" aria-hidden="true"></span> ${s("for_minutes",e)}: ${t.trigger_for_minutes}</span>`:d}
|
${t.trigger_for_minutes?r`<span class="trigger-limit-item"><span class="dot range" aria-hidden="true"></span> ${s("for_minutes",e)}: ${t.trigger_for_minutes}</span>`:d}
|
||||||
`:d}
|
`:d}
|
||||||
${g==="state_change"?r`
|
${_==="state_change"?r`
|
||||||
${t.trigger_target_changes!=null?r`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${s("target_changes",e)}: ${t.trigger_target_changes}</span>`:d}
|
${t.trigger_target_changes!=null?r`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${s("target_changes",e)}: ${t.trigger_target_changes}</span>`:d}
|
||||||
`:d}
|
`:d}
|
||||||
${g==="runtime"?r`
|
${_==="runtime"?r`
|
||||||
${t.trigger_runtime_hours!=null?r`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${s("runtime_hours",e)}: ${t.trigger_runtime_hours}h</span>`:d}
|
${t.trigger_runtime_hours!=null?r`<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${s("runtime_hours",e)}: ${t.trigger_runtime_hours}h</span>`:d}
|
||||||
`:d}
|
`:d}
|
||||||
${g==="compound"?r`
|
${_==="compound"?r`
|
||||||
<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${s("compound_logic",e)}: ${t.compound_logic||t.operator||"AND"}</span>
|
<span class="trigger-limit-item"><span class="dot warn" aria-hidden="true"></span> ${s("compound_logic",e)}: ${t.compound_logic||t.operator||"AND"}</span>
|
||||||
${(t.conditions||[]).map((x,f)=>r`
|
${(t.conditions||[]).map((x,f)=>r`
|
||||||
<span class="trigger-limit-item"><span class="dot range" aria-hidden="true"></span> ${f+1}. ${s(x.type||"unknown",e)}: ${x.entity_id?r`<span class="entity-link" @click=${M=>mt(M,x.entity_id)}>${x.entity_id}</span>`:""}</span>
|
<span class="trigger-limit-item"><span class="dot range" aria-hidden="true"></span> ${f+1}. ${s(x.type||"unknown",e)}: ${x.entity_id?r`<span class="entity-link" @click=${S=>mt(S,x.entity_id)}>${x.entity_id}</span>`:""}</span>
|
||||||
`)}
|
`)}
|
||||||
`:d}
|
`:d}
|
||||||
</div>
|
</div>
|
||||||
@@ -3964,7 +3998,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
${s("chart_since_service",o)}${n.meter!=null?r` · ${s("current",o)}: ${vt(n.meter,n.unit,o)}`:d}
|
${s("chart_since_service",o)}${n.meter!=null?r` · ${s("current",o)}: ${vt(n.meter,n.unit,o)}`:d}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`}function je(n,o){let t=n.trigger_config;if(!t)return[];let e=t.type||"threshold",i=t.entity_id||"",a=e==="runtime"?[]:o.detailStatsData.get(i)||[],l=o.isCounterEntity(t),h=[];if(a.length>=2)for(let c of a){let p={ts:c.ts,val:c.val};!l&&c.min!=null&&c.max!=null&&(p.min=c.min,p.max=c.max),h.push(p)}else for(let c of n.history)c.trigger_value!=null&&h.push({ts:new Date(c.timestamp).getTime(),val:c.trigger_value});return n.trigger_current_value!=null&&h.push({ts:Date.now(),val:n.trigger_current_value}),h.sort((c,p)=>c.ts-p.ts),h}function pi(n,o,t){let e=n.trigger_config;if(!e)return d;let i=e.type||"threshold",a=e.entity_id||"",l=je(n,t);i==="runtime"&&e.trigger_runtime_hours&&n.trigger_current_value!=null&&(l=[{ts:Jt(n)??l[0]?.ts??Date.now()-864e5,val:0},{ts:Date.now(),val:Math.max(0,n.trigger_current_value)}]),t.hideOutliers&&(l=li(l));let h=l.length<2&&!!a&&t.hasStatsService&&!t.detailStatsData.has(a);if(l.length<2&&!h)return d;let c=!!a&&t.detailStatsData.has(a)&&(t.detailStatsData.get(a)?.length??0)<2,p=Date.now()-t.rangeDays*864e5,u=l.filter(f=>f.ts>=p);u.length>=2&&(l=u);let g=null,v=!1;if(i==="counter"&&e.trigger_target_value!=null&&l.length){let f=Te(n,l);if(f){if(f.ts!=null){let M=l.filter(S=>S.ts>=f.ts);M.length>=2&&(l=M)}l=l.map(M=>({...M,val:Math.max(0,M.val-f.value)}))}g=e.trigger_target_value,v=!0}else i==="state_change"&&e.trigger_target_changes?(g=e.trigger_target_changes,v=!0):i==="runtime"&&e.trigger_runtime_hours&&(g=e.trigger_runtime_hours,v=!0);let b=null;if(g==null&&n.degradation_rate!=null&&(n.degradation_trend!=="stable"||n.days_until_threshold!=null)&&n.degradation_trend!=="insufficient_data"&&l.length>=2){let f=l[l.length-1];b=[f,{ts:f.ts+30*864e5,val:f.val+n.degradation_rate*30}]}let x=n.history.filter(f=>["completed","skipped","reset"].includes(f.type)).map(f=>({ts:new Date(f.timestamp).getTime(),type:f.type}));return r`
|
`}function je(n,o){let t=n.trigger_config;if(!t)return[];let e=t.type||"threshold",i=t.entity_id||"",a=e==="runtime"?[]:o.detailStatsData.get(i)||[],l=o.isCounterEntity(t),h=[];if(a.length>=2)for(let c of a){let p={ts:c.ts,val:c.val};!l&&c.min!=null&&c.max!=null&&(p.min=c.min,p.max=c.max),h.push(p)}else for(let c of n.history)c.trigger_value!=null&&h.push({ts:new Date(c.timestamp).getTime(),val:c.trigger_value});return n.trigger_current_value!=null&&h.push({ts:Date.now(),val:n.trigger_current_value}),h.sort((c,p)=>c.ts-p.ts),h}function pi(n,o,t){let e=n.trigger_config;if(!e)return d;let i=e.type||"threshold",a=e.entity_id||"",l=je(n,t);i==="runtime"&&e.trigger_runtime_hours&&n.trigger_current_value!=null&&(l=[{ts:Jt(n)??l[0]?.ts??Date.now()-864e5,val:0},{ts:Date.now(),val:Math.max(0,n.trigger_current_value)}]),t.hideOutliers&&(l=li(l));let h=l.length<2&&!!a&&t.hasStatsService&&!t.detailStatsData.has(a);if(l.length<2&&!h)return d;let c=!!a&&t.detailStatsData.has(a)&&(t.detailStatsData.get(a)?.length??0)<2,p=Date.now()-t.rangeDays*864e5,u=l.filter(f=>f.ts>=p);u.length>=2&&(l=u);let _=null,v=!1;if(i==="counter"&&e.trigger_target_value!=null&&l.length){let f=Te(n,l);if(f){if(f.ts!=null){let S=l.filter(M=>M.ts>=f.ts);S.length>=2&&(l=S)}l=l.map(S=>({...S,val:Math.max(0,S.val-f.value)}))}_=e.trigger_target_value,v=!0}else i==="state_change"&&e.trigger_target_changes?(_=e.trigger_target_changes,v=!0):i==="runtime"&&e.trigger_runtime_hours&&(_=e.trigger_runtime_hours,v=!0);let b=null;if(_==null&&n.degradation_rate!=null&&(n.degradation_trend!=="stable"||n.days_until_threshold!=null)&&n.degradation_trend!=="insufficient_data"&&l.length>=2){let f=l[l.length-1];b=[f,{ts:f.ts+30*864e5,val:f.val+n.degradation_rate*30}]}let x=n.history.filter(f=>["completed","skipped","reset"].includes(f.type)).map(f=>({ts:new Date(f.timestamp).getTime(),type:f.type}));return r`
|
||||||
<maintenance-trigger-chart
|
<maintenance-trigger-chart
|
||||||
.points=${h?[]:l}
|
.points=${h?[]:l}
|
||||||
.events=${x}
|
.events=${x}
|
||||||
@@ -3972,7 +4006,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
.lang=${t.lang}
|
.lang=${t.lang}
|
||||||
.thresholdAbove=${i==="threshold"?e.trigger_above??null:null}
|
.thresholdAbove=${i==="threshold"?e.trigger_above??null:null}
|
||||||
.thresholdBelow=${i==="threshold"?e.trigger_below??null:null}
|
.thresholdBelow=${i==="threshold"?e.trigger_below??null:null}
|
||||||
.targetValue=${g}
|
.targetValue=${_}
|
||||||
.forceZero=${v}
|
.forceZero=${v}
|
||||||
.projection=${b}
|
.projection=${b}
|
||||||
.rangeDays=${t.rangeDays}
|
.rangeDays=${t.rangeDays}
|
||||||
@@ -3985,7 +4019,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<ha-icon icon="mdi:information-outline"></ha-icon>
|
<ha-icon icon="mdi:information-outline"></ha-icon>
|
||||||
${s("chart_no_stats",t.lang)}
|
${s("chart_no_stats",t.lang)}
|
||||||
</div>`:d}
|
</div>`:d}
|
||||||
`}function Me(n,o,t){let e=n.degradation_trend!=null&&n.degradation_trend!=="insufficient_data",i=n.days_until_threshold!=null,a=n.environmental_factor!=null&&n.environmental_factor!==1;if(!e&&!i&&!a)return d;let l=n.degradation_trend==="rising"?"M16,6L18.29,8.29L13.41,13.17L9.41,9.17L2,16.59L3.41,18L9.41,12L13.41,16L19.71,9.71L22,12V6H16Z":n.degradation_trend==="falling"?"M16,18L18.29,15.71L13.41,10.83L9.41,14.83L2,7.41L3.41,6L9.41,12L13.41,8L19.71,14.29L22,12V18H16Z":"M22,12L18,8V11H3V13H18V16L22,12Z";return r`
|
`}function Se(n,o,t){let e=n.degradation_trend!=null&&n.degradation_trend!=="insufficient_data",i=n.days_until_threshold!=null,a=n.environmental_factor!=null&&n.environmental_factor!==1;if(!e&&!i&&!a)return d;let l=n.degradation_trend==="rising"?"M16,6L18.29,8.29L13.41,13.17L9.41,9.17L2,16.59L3.41,18L9.41,12L13.41,16L19.71,9.71L22,12V6H16Z":n.degradation_trend==="falling"?"M16,18L18.29,15.71L13.41,10.83L9.41,14.83L2,7.41L3.41,6L9.41,12L13.41,8L19.71,14.29L22,12V18H16Z":"M22,12L18,8V11H3V13H18V16L22,12Z";return r`
|
||||||
<div class="prediction-section">
|
<div class="prediction-section">
|
||||||
${n.sensor_prediction_urgency?r`
|
${n.sensor_prediction_urgency?r`
|
||||||
<div class="prediction-urgency-banner">
|
<div class="prediction-urgency-banner">
|
||||||
@@ -4025,7 +4059,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
`:d}
|
`:d}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`}function Se(n,o){let t=n.interval_analysis,e=t?.weibull_beta,i=t?.weibull_eta;if(e==null||i==null||i<=0)return d;let a=n.interval_days??0,l=n.suggested_interval??a;return r`
|
`}function Me(n,o){let t=n.interval_analysis,e=t?.weibull_beta,i=t?.weibull_eta;if(e==null||i==null||i<=0)return d;let a=n.interval_days??0,l=n.suggested_interval??a;return r`
|
||||||
<div class="weibull-section">
|
<div class="weibull-section">
|
||||||
<div class="weibull-title">
|
<div class="weibull-title">
|
||||||
<ha-svg-icon aria-hidden="true" path="M3,14L3.5,14.07L8.07,9.5C7.89,8.85 8.06,8.11 8.59,7.59C9.37,6.8 10.63,6.8 11.41,7.59C11.94,8.11 12.11,8.85 11.93,9.5L14.5,12.07L15,12C15.18,12 15.35,12 15.5,12.07L19.07,8.5C19,8.35 19,8.18 19,8A2,2 0 0,1 21,6A2,2 0 0,1 23,8A2,2 0 0,1 21,10C20.82,10 20.65,10 20.5,9.93L16.93,13.5C17,13.65 17,13.82 17,14A2,2 0 0,1 15,16A2,2 0 0,1 13,14L13.07,13.5L10.5,10.93C10.18,11 9.82,11 9.5,10.93L4.93,15.5L5,16A2,2 0 0,1 3,18A2,2 0 0,1 1,16A2,2 0 0,1 3,14Z"></ha-svg-icon>
|
<ha-svg-icon aria-hidden="true" path="M3,14L3.5,14.07L8.07,9.5C7.89,8.85 8.06,8.11 8.59,7.59C9.37,6.8 10.63,6.8 11.41,7.59C11.94,8.11 12.11,8.85 11.93,9.5L14.5,12.07L15,12C15.18,12 15.35,12 15.5,12.07L19.07,8.5C19,8.35 19,8.18 19,8A2,2 0 0,1 21,6A2,2 0 0,1 23,8A2,2 0 0,1 21,10C20.82,10 20.65,10 20.5,9.93L16.93,13.5C17,13.65 17,13.82 17,14A2,2 0 0,1 15,16A2,2 0 0,1 13,14L13.07,13.5L10.5,10.93C10.18,11 9.82,11 9.5,10.93L4.93,15.5L5,16A2,2 0 0,1 3,18A2,2 0 0,1 1,16A2,2 0 0,1 3,14Z"></ha-svg-icon>
|
||||||
@@ -4033,15 +4067,15 @@ ${A(n.notes)}</div>`:""}
|
|||||||
${hi(e,o)}
|
${hi(e,o)}
|
||||||
</div>
|
</div>
|
||||||
${ui(e,i,a,l,o)}
|
${ui(e,i,a,l,o)}
|
||||||
${_i(t,o)}
|
${gi(t,o)}
|
||||||
${t?.confidence_interval_low!=null?gi(t,n,o):d}
|
${t?.confidence_interval_low!=null?_i(t,n,o):d}
|
||||||
</div>
|
</div>
|
||||||
`}function hi(n,o){let t,e,i;return n<.8?(t="early_failures",e="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z",i="beta_early_failures"):n<=1.2?(t="random_failures",e="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,17H11V15H13V17M13,13H11V7H13V13Z",i="beta_random_failures"):n<=3.5?(t="wear_out",e="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4M12,6A6,6 0 0,1 18,12H12V6Z",i="beta_wear_out"):(t="highly_predictable",e="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M11,16.5L18,9.5L16.59,8.09L11,13.67L7.91,10.59L6.5,12L11,16.5Z",i="beta_highly_predictable"),r`
|
`}function hi(n,o){let t,e,i;return n<.8?(t="early_failures",e="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z",i="beta_early_failures"):n<=1.2?(t="random_failures",e="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,17H11V15H13V17M13,13H11V7H13V13Z",i="beta_random_failures"):n<=3.5?(t="wear_out",e="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4M12,6A6,6 0 0,1 18,12H12V6Z",i="beta_wear_out"):(t="highly_predictable",e="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M11,16.5L18,9.5L16.59,8.09L11,13.67L7.91,10.59L6.5,12L11,16.5Z",i="beta_highly_predictable"),r`
|
||||||
<span class="beta-badge ${t}">
|
<span class="beta-badge ${t}">
|
||||||
<ha-svg-icon path="${e}"></ha-svg-icon>
|
<ha-svg-icon path="${e}"></ha-svg-icon>
|
||||||
${s(i,o)} (\u03B2=${n.toFixed(2)})
|
${s(i,o)} (\u03B2=${n.toFixed(2)})
|
||||||
</span>
|
</span>
|
||||||
`}function ui(n,o,t,e,i){let b=Math.max(t,e,o,1)*1.3,x=50,f=[];for(let H=0;H<=x;H++){let O=H/x*b,Z=1-Math.exp(-Math.pow(O/o,n)),st=32+O/b*260,rt=136-Z*128;f.push([st,rt])}let M=f.map(([H,O])=>`${H.toFixed(1)},${O.toFixed(1)}`).join(" "),S="M32,136 "+f.map(([H,O])=>`L${H.toFixed(1)},${O.toFixed(1)}`).join(" ")+` L${f[x][0].toFixed(1)},136 Z`,I=32+t/b*260,R=1-Math.exp(-Math.pow(t/o,n)),j=136-R*128,y=((1-R)*100).toFixed(0),N=32+e/b*260,W=[0,.25,.5,.75,1];return r`
|
`}function ui(n,o,t,e,i){let b=Math.max(t,e,o,1)*1.3,x=50,f=[];for(let H=0;H<=x;H++){let O=H/x*b,Z=1-Math.exp(-Math.pow(O/o,n)),st=32+O/b*260,rt=136-Z*128;f.push([st,rt])}let S=f.map(([H,O])=>`${H.toFixed(1)},${O.toFixed(1)}`).join(" "),M="M32,136 "+f.map(([H,O])=>`L${H.toFixed(1)},${O.toFixed(1)}`).join(" ")+` L${f[x][0].toFixed(1)},136 Z`,I=32+t/b*260,R=1-Math.exp(-Math.pow(t/o,n)),j=136-R*128,y=((1-R)*100).toFixed(0),U=32+e/b*260,W=[0,.25,.5,.75,1];return r`
|
||||||
<div class="weibull-chart">
|
<div class="weibull-chart">
|
||||||
<svg viewBox="0 0 ${300} ${160}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${s("chart_weibull",i)}">
|
<svg viewBox="0 0 ${300} ${160}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${s("chart_weibull",i)}">
|
||||||
${W.map(H=>{let O=136-H*128;return P`
|
${W.map(H=>{let O=136-H*128;return P`
|
||||||
@@ -4055,8 +4089,8 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<text x="${324/2}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">${Math.round(b/2)}</text>
|
<text x="${324/2}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">${Math.round(b/2)}</text>
|
||||||
<text x="${292}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">${Math.round(b)}</text>
|
<text x="${292}" y="${156}" fill="var(--secondary-text-color)" font-size="8" text-anchor="middle">${Math.round(b)}</text>
|
||||||
|
|
||||||
<path d="${S}" fill="var(--primary-color, #03a9f4)" opacity="0.08" />
|
<path d="${M}" fill="var(--primary-color, #03a9f4)" opacity="0.08" />
|
||||||
<polyline points="${M}" fill="none"
|
<polyline points="${S}" fill="none"
|
||||||
stroke="var(--primary-color, #03a9f4)" stroke-width="2" />
|
stroke="var(--primary-color, #03a9f4)" stroke-width="2" />
|
||||||
|
|
||||||
${t>0?P`
|
${t>0?P`
|
||||||
@@ -4069,7 +4103,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
`:d}
|
`:d}
|
||||||
|
|
||||||
${e>0&&e!==t?P`
|
${e>0&&e!==t?P`
|
||||||
<line x1="${N.toFixed(1)}" y1="${8}" x2="${N.toFixed(1)}" y2="${136 .toFixed(1)}"
|
<line x1="${U.toFixed(1)}" y1="${8}" x2="${U.toFixed(1)}" y2="${136 .toFixed(1)}"
|
||||||
stroke="var(--success-color, #4caf50)" stroke-width="1.5" stroke-dasharray="4,3" />
|
stroke="var(--success-color, #4caf50)" stroke-width="1.5" stroke-dasharray="4,3" />
|
||||||
`:d}
|
`:d}
|
||||||
|
|
||||||
@@ -4084,7 +4118,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
${t>0?r`<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color, #03a9f4); opacity:0.5"></span> ${s("current_interval_marker",i)}</span>`:d}
|
${t>0?r`<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color, #03a9f4); opacity:0.5"></span> ${s("current_interval_marker",i)}</span>`:d}
|
||||||
${e>0&&e!==t?r`<span class="legend-item"><span class="legend-swatch" style="background:var(--success-color, #4caf50)"></span> ${s("recommended_marker",i)}</span>`:d}
|
${e>0&&e!==t?r`<span class="legend-item"><span class="legend-swatch" style="background:var(--success-color, #4caf50)"></span> ${s("recommended_marker",i)}</span>`:d}
|
||||||
</div>
|
</div>
|
||||||
`}function _i(n,o){return r`
|
`}function gi(n,o){return r`
|
||||||
<div class="weibull-info-row">
|
<div class="weibull-info-row">
|
||||||
<div class="weibull-info-item">
|
<div class="weibull-info-item">
|
||||||
<span>${s("characteristic_life",o)}</span>
|
<span>${s("characteristic_life",o)}</span>
|
||||||
@@ -4097,13 +4131,13 @@ ${A(n.notes)}</div>`:""}
|
|||||||
</div>
|
</div>
|
||||||
`:d}
|
`:d}
|
||||||
</div>
|
</div>
|
||||||
`}function gi(n,o,t){let e=n.confidence_interval_low,i=n.confidence_interval_high,a=o.suggested_interval??o.interval_days??0,l=o.interval_days??0,h=Math.max(0,e-5),p=i+5-h,u=(e-h)/p*100,g=(i-e)/p*100,v=(a-h)/p*100,b=l>0?(l-h)/p*100:-1;return r`
|
`}function _i(n,o,t){let e=n.confidence_interval_low,i=n.confidence_interval_high,a=o.suggested_interval??o.interval_days??0,l=o.interval_days??0,h=Math.max(0,e-5),p=i+5-h,u=(e-h)/p*100,_=(i-e)/p*100,v=(a-h)/p*100,b=l>0?(l-h)/p*100:-1;return r`
|
||||||
<div class="confidence-range">
|
<div class="confidence-range">
|
||||||
<div class="confidence-range-title">
|
<div class="confidence-range-title">
|
||||||
${s("confidence_interval",t)}: ${a} ${s("days",t)} (${e}\u2013${i})
|
${s("confidence_interval",t)}: ${a} ${s("days",t)} (${e}\u2013${i})
|
||||||
</div>
|
</div>
|
||||||
<div class="confidence-bar">
|
<div class="confidence-bar">
|
||||||
<div class="confidence-fill" style="left:${u.toFixed(1)}%;width:${g.toFixed(1)}%"></div>
|
<div class="confidence-fill" style="left:${u.toFixed(1)}%;width:${_.toFixed(1)}%"></div>
|
||||||
${b>=0?r`<div class="confidence-marker current" style="left:${b.toFixed(1)}%"></div>`:d}
|
${b>=0?r`<div class="confidence-marker current" style="left:${b.toFixed(1)}%"></div>`:d}
|
||||||
<div class="confidence-marker recommended" style="left:${v.toFixed(1)}%"></div>
|
<div class="confidence-marker recommended" style="left:${v.toFixed(1)}%"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -4147,7 +4181,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<span class="legend-item"><span class="dot high"></span> ${s("longer",o)||"L\xE4nger"}</span>
|
<span class="legend-item"><span class="dot high"></span> ${s("longer",o)||"L\xE4nger"}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`}function Ce(n,o){return mi(n,o)}function mi(n,o){let t=n.seasonal_factors??n.interval_analysis?.seasonal_factors;if(!t||t.length!==12)return d;let e=n.interval_analysis?.seasonal_reason,i=new Date().getMonth(),a=300,l=100,h=8,p=l-h-4,u=Math.max(...t,1.5),g=a/12,v=g*.65,b=h+p-1/u*p;return r`
|
`}function Ce(n,o){return mi(n,o)}function mi(n,o){let t=n.seasonal_factors??n.interval_analysis?.seasonal_factors;if(!t||t.length!==12)return d;let e=n.interval_analysis?.seasonal_reason,i=new Date().getMonth(),a=300,l=100,h=8,p=l-h-4,u=Math.max(...t,1.5),_=a/12,v=_*.65,b=h+p-1/u*p;return r`
|
||||||
<div class="seasonal-chart">
|
<div class="seasonal-chart">
|
||||||
<div class="seasonal-chart-title">
|
<div class="seasonal-chart-title">
|
||||||
<ha-svg-icon aria-hidden="true" path="M17.75 4.09L15.22 6.03L16.13 9.09L13.5 7.28L10.87 9.09L11.78 6.03L9.25 4.09L12.44 4L13.5 1L14.56 4L17.75 4.09M21.25 11L19.61 12.25L20.2 14.23L18.5 13.06L16.8 14.23L17.39 12.25L15.75 11L17.81 10.95L18.5 9L19.19 10.95L21.25 11M18.97 15.95C19.8 15.87 20.69 17.05 20.16 17.8C19.84 18.25 19.5 18.67 19.08 19.07C15.17 23 8.84 23 4.94 19.07C1.03 15.17 1.03 8.83 4.94 4.93C5.34 4.53 5.76 4.17 6.21 3.85C6.96 3.32 8.14 4.21 8.06 5.04C7.79 7.9 8.75 10.87 10.95 13.06C13.14 15.26 16.1 16.22 18.97 15.95Z"></ha-svg-icon>
|
<ha-svg-icon aria-hidden="true" path="M17.75 4.09L15.22 6.03L16.13 9.09L13.5 7.28L10.87 9.09L11.78 6.03L9.25 4.09L12.44 4L13.5 1L14.56 4L17.75 4.09M21.25 11L19.61 12.25L20.2 14.23L18.5 13.06L16.8 14.23L17.39 12.25L15.75 11L17.81 10.95L18.5 9L19.19 10.95L21.25 11M18.97 15.95C19.8 15.87 20.69 17.05 20.16 17.8C19.84 18.25 19.5 18.67 19.08 19.07C15.17 23 8.84 23 4.94 19.07C1.03 15.17 1.03 8.83 4.94 4.93C5.34 4.53 5.76 4.17 6.21 3.85C6.96 3.32 8.14 4.21 8.06 5.04C7.79 7.9 8.75 10.87 10.95 13.06C13.14 15.26 16.1 16.22 18.97 15.95Z"></ha-svg-icon>
|
||||||
@@ -4157,9 +4191,9 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<svg viewBox="0 0 ${a} ${l}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${s("chart_seasonal",o)}">
|
<svg viewBox="0 0 ${a} ${l}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${s("chart_seasonal",o)}">
|
||||||
<line x1="0" y1="${b.toFixed(1)}" x2="${a}" y2="${b.toFixed(1)}"
|
<line x1="0" y1="${b.toFixed(1)}" x2="${a}" y2="${b.toFixed(1)}"
|
||||||
stroke="var(--divider-color)" stroke-width="1" stroke-dasharray="4,3" />
|
stroke="var(--divider-color)" stroke-width="1" stroke-dasharray="4,3" />
|
||||||
${t.map((x,f)=>{let M=x/u*p,S=f*g+(g-v)/2,I=h+p-M,R=f===i,j=x<1?"var(--success-color, #4caf50)":x>1?"var(--warning-color, #ff9800)":"var(--secondary-text-color)";return P`
|
${t.map((x,f)=>{let S=x/u*p,M=f*_+(_-v)/2,I=h+p-S,R=f===i,j=x<1?"var(--success-color, #4caf50)":x>1?"var(--warning-color, #ff9800)":"var(--secondary-text-color)";return P`
|
||||||
<rect x="${S.toFixed(1)}" y="${I.toFixed(1)}"
|
<rect x="${M.toFixed(1)}" y="${I.toFixed(1)}"
|
||||||
width="${v.toFixed(1)}" height="${M.toFixed(1)}"
|
width="${v.toFixed(1)}" height="${S.toFixed(1)}"
|
||||||
fill="${j}" opacity="${R?1:.5}" rx="2" />
|
fill="${j}" opacity="${R?1:.5}" rx="2" />
|
||||||
`})}
|
`})}
|
||||||
</svg>
|
</svg>
|
||||||
@@ -4191,16 +4225,16 @@ ${A(n.notes)}</div>`:""}
|
|||||||
</div>
|
</div>
|
||||||
${fi(n,o,t)}
|
${fi(n,o,t)}
|
||||||
</div>
|
</div>
|
||||||
`}function fi(n,o,t){let e=n.history.filter($=>$.type==="completed"&&($.cost!=null||$.duration!=null)).map($=>({ts:new Date($.timestamp).getTime(),cost:$.cost??0,duration:$.duration??0})).sort(($,C)=>$.ts-C.ts);if(e.length<2)return d;let i=e.some($=>$.cost>0),a=e.some($=>$.duration>0);if(!i&&!a)return d;let l=t!=="duration"&&i,h=t!=="cost"&&a,c=l||!h&&i,p=h||!l&&a,u=640,g=vi,v=c?44:12,b=p?44:12,x=u-v-b,f=g-bi,M=f-kt,S=e[0].ts,I=e[e.length-1].ts,R=(I-S||864e5)*.05,j=S-R,y=I+R,N=Ft(S,I),W=$=>v+($-j)/(y-j)*x,H=wt(0,Math.max(...e.map($=>$.cost))||1,3),O=wt(0,Math.max(...e.map($=>$.duration))||1,3),Z=$=>kt+(1-$/(H.niceMax||1))*M,st=$=>kt+(1-$/(O.niceMax||1))*M,rt=e.length>1?Math.min(...e.slice(1).map(($,C)=>W($.ts)-W(e[C].ts))):x,U=Math.max(6,Math.min(22,rt*.55)),w=Bt(S,I,Math.max(2,Math.min(4,e.length)));return r`
|
`}function fi(n,o,t){let e=n.history.filter($=>$.type==="completed"&&($.cost!=null||$.duration!=null)).map($=>({ts:new Date($.timestamp).getTime(),cost:$.cost??0,duration:$.duration??0})).sort(($,C)=>$.ts-C.ts);if(e.length<2)return d;let i=e.some($=>$.cost>0),a=e.some($=>$.duration>0);if(!i&&!a)return d;let l=t!=="duration"&&i,h=t!=="cost"&&a,c=l||!h&&i,p=h||!l&&a,u=640,_=vi,v=c?44:12,b=p?44:12,x=u-v-b,f=_-bi,S=f-kt,M=e[0].ts,I=e[e.length-1].ts,R=(I-M||864e5)*.05,j=M-R,y=I+R,U=Ft(M,I),W=$=>v+($-j)/(y-j)*x,H=wt(0,Math.max(...e.map($=>$.cost))||1,3),O=wt(0,Math.max(...e.map($=>$.duration))||1,3),Z=$=>kt+(1-$/(H.niceMax||1))*S,st=$=>kt+(1-$/(O.niceMax||1))*S,rt=e.length>1?Math.min(...e.slice(1).map(($,C)=>W($.ts)-W(e[C].ts))):x,N=Math.max(6,Math.min(22,rt*.55)),w=Bt(M,I,Math.max(2,Math.min(4,e.length)));return r`
|
||||||
<div class="sparkline-container">
|
<div class="sparkline-container">
|
||||||
<svg class="history-chart" viewBox="0 0 ${u} ${g}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${s("chart_history",o)}">
|
<svg class="history-chart" viewBox="0 0 ${u} ${_}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${s("chart_history",o)}">
|
||||||
${c?H.ticks.map($=>{let C=Z($);return C<kt-1||C>f+1?d:P`
|
${c?H.ticks.map($=>{let C=Z($);return C<kt-1||C>f+1?d:P`
|
||||||
<line x1="${v}" y1="${C.toFixed(1)}" x2="${u-b}" y2="${C.toFixed(1)}" stroke="var(--divider-color)" stroke-width="1" opacity="0.55" />
|
<line x1="${v}" y1="${C.toFixed(1)}" x2="${u-b}" y2="${C.toFixed(1)}" stroke="var(--divider-color)" stroke-width="1" opacity="0.55" />
|
||||||
<text x="${v-6}" y="${(C+3.5).toFixed(1)}" text-anchor="end" fill="var(--primary-color)" font-size="10.5">${ct($)}€</text>`}):d}
|
<text x="${v-6}" y="${(C+3.5).toFixed(1)}" text-anchor="end" fill="var(--primary-color)" font-size="10.5">${ct($)}€</text>`}):d}
|
||||||
${p?O.ticks.map($=>{let C=st($);return C<kt-1||C>f+1?d:P`<text x="${u-b+6}" y="${(C+3.5).toFixed(1)}" text-anchor="start" fill="var(--accent-color, #ff9800)" font-size="10.5">${ct($)}m</text>`}):d}
|
${p?O.ticks.map($=>{let C=st($);return C<kt-1||C>f+1?d:P`<text x="${u-b+6}" y="${(C+3.5).toFixed(1)}" text-anchor="start" fill="var(--accent-color, #ff9800)" font-size="10.5">${ct($)}m</text>`}):d}
|
||||||
|
|
||||||
${c?e.filter($=>$.cost>0).map($=>P`
|
${c?e.filter($=>$.cost>0).map($=>P`
|
||||||
<rect x="${(W($.ts)-U/2).toFixed(1)}" y="${Z($.cost).toFixed(1)}" width="${U.toFixed(1)}" height="${(f-Z($.cost)).toFixed(1)}"
|
<rect x="${(W($.ts)-N/2).toFixed(1)}" y="${Z($.cost).toFixed(1)}" width="${N.toFixed(1)}" height="${(f-Z($.cost)).toFixed(1)}"
|
||||||
fill="var(--primary-color)" opacity="0.6" rx="2">
|
fill="var(--primary-color)" opacity="0.6" rx="2">
|
||||||
<title>${yt($.ts,o,!0)}: ${$.cost.toLocaleString(o)}€${$.duration?` \xB7 ${$.duration}m`:""}</title>
|
<title>${yt($.ts,o,!0)}: ${$.cost.toLocaleString(o)}€${$.duration?` \xB7 ${$.duration}m`:""}</title>
|
||||||
</rect>
|
</rect>
|
||||||
@@ -4216,18 +4250,18 @@ ${A(n.notes)}</div>`:""}
|
|||||||
`:d}
|
`:d}
|
||||||
|
|
||||||
<line x1="${v}" y1="${f}" x2="${u-b}" y2="${f}" stroke="var(--divider-color)" stroke-width="1" />
|
<line x1="${v}" y1="${f}" x2="${u-b}" y2="${f}" stroke="var(--divider-color)" stroke-width="1" />
|
||||||
${w.map(($,C)=>{let Ut=C===0?"start":C===w.length-1?"end":"middle";return P`<text x="${W($).toFixed(1)}" y="${g-6}" text-anchor="${Ut}" fill="var(--secondary-text-color)" font-size="10">${yt($,o,N)}</text>`})}
|
${w.map(($,C)=>{let Nt=C===0?"start":C===w.length-1?"end":"middle";return P`<text x="${W($).toFixed(1)}" y="${_-6}" text-anchor="${Nt}" fill="var(--secondary-text-color)" font-size="10">${yt($,o,U)}</text>`})}
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="chart-legend">
|
<div class="chart-legend">
|
||||||
${c?r`<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color);opacity:0.6"></span>${s("cost",o)}</span>`:d}
|
${c?r`<span class="legend-item"><span class="legend-swatch" style="background:var(--primary-color);opacity:0.6"></span>${s("cost",o)}</span>`:d}
|
||||||
${p?r`<span class="legend-item"><span class="legend-swatch" style="background:var(--accent-color, #ff9800)"></span>${s("duration",o)}</span>`:d}
|
${p?r`<span class="legend-item"><span class="legend-swatch" style="background:var(--accent-color, #ff9800)"></span>${s("duration",o)}</span>`:d}
|
||||||
</div>
|
</div>
|
||||||
`}var gt=class extends L{constructor(){super(...arguments);this.docId="";this._url="";this._failed=!1;this._signedFor=""}updated(){this.hass&&this.docId&&this._signedFor!==this.docId&&(this._signedFor=this.docId,this._url="",this._failed=!1,this._sign())}async _sign(){try{let t=await this.hass.connection.sendMessagePromise({type:"auth/sign_path",path:`/api/maintenance_supporter/document/${this.docId}`,expires:300});this._url=t.path}catch{this._failed=!0}}render(){return this._failed||!this.docId?d:this._url?r`
|
`}var _t=class extends L{constructor(){super(...arguments);this.docId="";this._url="";this._failed=!1;this._signedFor=""}updated(){this.hass&&this.docId&&this._signedFor!==this.docId&&(this._signedFor=this.docId,this._url="",this._failed=!1,this._sign())}async _sign(){try{let t=await this.hass.connection.sendMessagePromise({type:"auth/sign_path",path:`/api/maintenance_supporter/document/${this.docId}`,expires:300});this._url=t.path}catch{this._failed=!0}}render(){return this._failed||!this.docId?d:this._url?r`
|
||||||
<a href=${this._url} target="_blank" rel="noopener" class="wrap">
|
<a href=${this._url} target="_blank" rel="noopener" class="wrap">
|
||||||
<img src=${this._url} alt="" loading="lazy"
|
<img src=${this._url} alt="" loading="lazy"
|
||||||
@error=${()=>this._failed=!0} />
|
@error=${()=>this._failed=!0} />
|
||||||
</a>`:r`<div class="ph"></div>`}};gt.styles=D`
|
</a>`:r`<div class="ph"></div>`}};_t.styles=D`
|
||||||
.wrap { display: inline-block; margin-top: 4px; }
|
.wrap { display: inline-block; margin-top: 4px; }
|
||||||
img {
|
img {
|
||||||
max-width: 96px;
|
max-width: 96px;
|
||||||
@@ -4243,7 +4277,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
background: var(--secondary-background-color, rgba(0,0,0,0.06));
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
`,_([T({attribute:!1})],gt.prototype,"hass",2),_([T()],gt.prototype,"docId",2),_([m()],gt.prototype,"_url",2),_([m()],gt.prototype,"_failed",2);customElements.get("maintenance-history-photo")||customElements.define("maintenance-history-photo",gt);var yi=["completed","skipped","missed","reset","triggered"];function Re(n,o){let t=o.lang;return r`
|
`,g([T({attribute:!1})],_t.prototype,"hass",2),g([T()],_t.prototype,"docId",2),g([m()],_t.prototype,"_url",2),g([m()],_t.prototype,"_failed",2);customElements.get("maintenance-history-photo")||customElements.define("maintenance-history-photo",_t);var yi=["completed","skipped","missed","reset","triggered"];function Re(n,o){let t=o.lang;return r`
|
||||||
<div class="history-filters-new">
|
<div class="history-filters-new">
|
||||||
<div class="filter-chips">
|
<div class="filter-chips">
|
||||||
${yi.map(e=>{let i=n.history.filter(a=>a.type===e).length;return i===0?d:r`
|
${yi.map(e=>{let i=n.history.filter(a=>a.type===e).length;return i===0?d:r`
|
||||||
@@ -4265,7 +4299,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
`}function xi(n,o){let t=o.lang,e=["completed","reset","skipped"].includes(n.type);return r`
|
`}function xi(n,o){let t=o.lang,e=["completed","reset","skipped"].includes(n.type);return r`
|
||||||
<div class="history-entry">
|
<div class="history-entry">
|
||||||
<div class="history-icon ${n.type}">
|
<div class="history-icon ${n.type}">
|
||||||
<ha-icon .icon=${Mt[n.type]||"mdi:circle"}></ha-icon>
|
<ha-icon .icon=${St[n.type]||"mdi:circle"}></ha-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="history-content">
|
<div class="history-content">
|
||||||
<div class="history-row">
|
<div class="history-row">
|
||||||
@@ -4437,7 +4471,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<div class="kpi-value">${n.average_duration?n.average_duration.toFixed(0):"\u2014"} min</div>
|
<div class="kpi-value">${n.average_duration?n.average_duration.toFixed(0):"\u2014"} min</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`}function Mi(n,o){let t=o.lang;if(!o.features.adaptive||!n.suggested_interval||n.suggested_interval===n.interval_days)return d;if(o.suggestionDismissed)return d;let e=n.suggested_interval;return r`
|
`}function Si(n,o){let t=o.lang;if(!o.features.adaptive||!n.suggested_interval||n.suggested_interval===n.interval_days)return d;if(o.suggestionDismissed)return d;let e=n.suggested_interval;return r`
|
||||||
<div class="recommendation-card">
|
<div class="recommendation-card">
|
||||||
<h4>${s("suggested_interval",t)}</h4>
|
<h4>${s("suggested_interval",t)}</h4>
|
||||||
${Ee(n.interval_days,e,n.interval_confidence||"medium",t)}
|
${Ee(n.interval_days,e,n.interval_confidence||"medium",t)}
|
||||||
@@ -4456,7 +4490,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
</ha-button>
|
</ha-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`}function Si(n,o){let t=o.lang,e=n.history.slice(-3).reverse();if(e.length===0)return d;let i=a=>{switch(a){case"completed":return"\u2713";case"triggered":return"\u2297";case"skipped":return"\u21B7";case"reset":return"\u21BA";default:return"\xB7"}};return r`
|
`}function Mi(n,o){let t=o.lang,e=n.history.slice(-3).reverse();if(e.length===0)return d;let i=a=>{switch(a){case"completed":return"\u2713";case"triggered":return"\u2297";case"skipped":return"\u21B7";case"reset":return"\u21BA";default:return"\xB7"}};return r`
|
||||||
<div class="recent-activities">
|
<div class="recent-activities">
|
||||||
<h3>${s("recent_activities",t)}</h3>
|
<h3>${s("recent_activities",t)}</h3>
|
||||||
${e.map(a=>r`
|
${e.map(a=>r`
|
||||||
@@ -4480,12 +4514,12 @@ ${A(n.notes)}</div>`:""}
|
|||||||
${n.battery_fleet_task?d:r`
|
${n.battery_fleet_task?d:r`
|
||||||
${$e(n,o.lang)}
|
${$e(n,o.lang)}
|
||||||
${ke(n,o.sparkline)}
|
${ke(n,o.sparkline)}
|
||||||
${Me(n,t,o.features)}
|
${Se(n,t,o.features)}
|
||||||
`}
|
`}
|
||||||
<div class="two-column-layout ${a?"":"single-column"}">
|
<div class="two-column-layout ${a?"":"single-column"}">
|
||||||
${a?r`
|
${a?r`
|
||||||
<div class="left-column">
|
<div class="left-column">
|
||||||
${Mi(n,o)}
|
${Si(n,o)}
|
||||||
${Le(n,t,o.features)}
|
${Le(n,t,o.features)}
|
||||||
</div>
|
</div>
|
||||||
`:d}
|
`:d}
|
||||||
@@ -4493,7 +4527,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
${Ae(n,t,o.costDurationToggle,c=>o.setCostDurationToggle(c))}
|
${Ae(n,t,o.costDurationToggle,c=>o.setCostDurationToggle(c))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${l?Pe("weibull","weibull_reliability_curve",Se(n,t),o):d}
|
${l?Pe("weibull","weibull_reliability_curve",Me(n,t),o):d}
|
||||||
${h?Pe("seasonal","seasonal_chart_title",r`
|
${h?Pe("seasonal","seasonal_chart_title",r`
|
||||||
${Ce(n,t)}
|
${Ce(n,t)}
|
||||||
<div class="seasonal-actions">
|
<div class="seasonal-actions">
|
||||||
@@ -4503,7 +4537,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
</div>
|
</div>
|
||||||
`,o):d}
|
`,o):d}
|
||||||
${ki(n,o)}
|
${ki(n,o)}
|
||||||
${Si(n,o)}
|
${Mi(n,o)}
|
||||||
</div>
|
</div>
|
||||||
`}function Di(n,o){return r`
|
`}function Di(n,o){return r`
|
||||||
<div class="tab-content history-tab">
|
<div class="tab-content history-tab">
|
||||||
@@ -4522,7 +4556,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
.canWrite=${!o.isOperator}
|
.canWrite=${!o.isOperator}
|
||||||
></maintenance-task-documents>
|
></maintenance-task-documents>
|
||||||
</div>
|
</div>
|
||||||
`}var Tt=class extends L{createRenderRoot(){return this}render(){return!this.task||!this.ctx?d:r`${ze(this.task,this.ctx)}`}};_([T({attribute:!1})],Tt.prototype,"task",2),_([T({attribute:!1})],Tt.prototype,"ctx",2);customElements.get("maintenance-task-detail-view")||customElements.define("maintenance-task-detail-view",Tt);function Ie(n){if(n.total<=0)return{start:0,end:0,padTop:0,padBottom:0};let o=n.overscan??12,t=Math.max(1,n.step??6),e=Math.max(1,n.rowHeight),i=Math.floor((n.scrollTop-n.listTop)/e),a=Math.ceil(n.viewportHeight/e)+1,l=Math.max(0,i-o);l=Math.floor(l/t)*t;let h=Math.min(n.total,Math.max(i,0)+a+o);return h=Math.min(n.total,Math.ceil(h/t)*t),l>=h&&(l=Math.min(l,Math.max(0,n.total-1)),h=Math.min(n.total,l+Math.max(a,1))),{start:l,end:h,padTop:l*e,padBottom:(n.total-h)*e}}var k=class extends L{constructor(){super(...arguments);this.narrow=!1;this.panel={};this._objects=[];this._stats=null;this._view="overview";this._selectedEntryId=null;this._selectedTaskId=null;this._filterStatus="";this._filterUser=null;this._filterLabel=null;this._savedViews=[];this._activeViewId="";this._unsub=null;this._chartRangeDays=(()=>{try{let t=parseInt(localStorage.getItem(F.chartRange)||"",10);return[7,30,90,365].includes(t)?t:30}catch{return 30}})();this._hideOutliers=(()=>{try{return localStorage.getItem(F.chartHideOutliers)==="1"}catch{return!1}})();this._historyFilter=null;this._budget=null;this._groups={};this._detailStatsData=new Map;this._miniStatsData=new Map;this._features={adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1};this._adminPanelUserIds=[];this._operatorWriteEnabled=!1;this._defaultWarningDays=7;this._actionLoading=!1;this._moreMenuOpen=!1;this._objMenuOpen=!1;this._toastMessage="";this._toastUndo=null;this._toastActionLabel="";this._filtersOpen=!1;this._actionsMenuOpen=!1;this._batteryFleetSetupAvailable=!1;this._staleBundle=!1;this._staleChecked=!1;this._toastTimer=null;this._dismissedSuggestions=new Set;this._overviewTab=(()=>{try{let t=localStorage.getItem(F.overviewTab);return t==="today"||t==="calendar"?t:"dashboard"}catch{return"dashboard"}})();this._activeTab="overview";this._costDurationToggle="both";this._historySearch="";this._sortMode="due_date";this._objectSortMode="alphabetical";this._groupByMode="none";this._objectViewMode="cards";this._objectsTableColumns=ae;this._showArchived=!1;this._bulkMode=!1;this._bulkSelected=new Set;this._virtStart=0;this._virtEnd=0;this._virtRowHeight=53;this._virtTotalRows=0;this._virtScrollAttached=!1;this._virtRaf=0;this._collapsedSections=(()=>{try{return new Set(JSON.parse(localStorage.getItem(F.collapsedSections)||"[]"))}catch{return new Set}})();this._paletteOpen=!1;this._paletteQuery="";this._paletteActive=0;this._templateGalleryOpen=!1;this._templates=[];this._templateCategories={};this._templateBusy=!1;this._statsService=null;this._userService=null;this._dataLoaded=!1;this._lastConnection=null;this._popstateHandler=t=>this._onPopState(t);this._lazyUi=null;this._onVirtualScroll=()=>{this._virtRaf||(this._virtRaf=requestAnimationFrame(()=>{this._virtRaf=0,this._updateVirtualWindow()}))};this._deepLinkHandled=!1;this._paletteKeydown=t=>{if(t.key==="/"&&!t.ctrlKey&&!t.metaKey&&!t.altKey&&!this._paletteOpen){let i=t.composedPath()[0];if(i instanceof HTMLElement&&(i.tagName==="INPUT"||i.tagName==="TEXTAREA"||i.tagName==="SELECT"||i.isContentEditable))return;t.preventDefault(),this._openPalette();return}if(!this._paletteOpen)return;let e=this._paletteResults;if(t.key==="Escape")t.preventDefault(),this._closePalette();else if(t.key==="ArrowDown")t.preventDefault(),this._paletteActive=Math.min(this._paletteActive+1,e.length-1);else if(t.key==="ArrowUp")t.preventDefault(),this._paletteActive=Math.max(this._paletteActive-1,0);else if(t.key==="Enter"){t.preventDefault();let i=e[this._paletteActive];i&&this._selectPaletteResult(i)}};this._onDialogEvent=async()=>{try{await this._loadData()}catch{}};this._onCalendarLlCustom=t=>{let e=t.detail;e?.type==="maintenance-supporter:open-task"&&e.entry_id&&e.task_id&&(t.stopPropagation(),this._showTask(e.entry_id,e.task_id))};this._fullHistory=null;this._onHistoryEntrySaved=async()=>{await this._loadData()}}get _lang(){return this.hass?.language||"en"}get _isOperator(){let t=this.hass?.user;return t?t.is_admin?!1:!(this._operatorWriteEnabled&&this._adminPanelUserIds.includes(t.id)):!0}_ensureLazyUi(){return this._lazyUi||(this._lazyUi=Promise.all([import("/maintenance_supporter_panelfiles/panel-chunks/object-dialog-IU7V7TDN.js"),import("/maintenance_supporter_panelfiles/panel-chunks/task-dialog-5VUS7JEH.js"),import("/maintenance_supporter_panelfiles/panel-chunks/complete-dialog-KGRPNNX2.js"),import("/maintenance_supporter_panelfiles/panel-chunks/qr-dialog-U2M7KFS3.js"),import("/maintenance_supporter_panelfiles/panel-chunks/adopt-problem-sensors-dialog-EEQGF7EF.js"),import("/maintenance_supporter_panelfiles/panel-chunks/suggested-setups-
Line truncated
|
`}var Tt=class extends L{createRenderRoot(){return this}render(){return!this.task||!this.ctx?d:r`${ze(this.task,this.ctx)}`}};g([T({attribute:!1})],Tt.prototype,"task",2),g([T({attribute:!1})],Tt.prototype,"ctx",2);customElements.get("maintenance-task-detail-view")||customElements.define("maintenance-task-detail-view",Tt);function Ie(n){if(n.total<=0)return{start:0,end:0,padTop:0,padBottom:0};let o=n.overscan??12,t=Math.max(1,n.step??6),e=Math.max(1,n.rowHeight),i=Math.floor((n.scrollTop-n.listTop)/e),a=Math.ceil(n.viewportHeight/e)+1,l=Math.max(0,i-o);l=Math.floor(l/t)*t;let h=Math.min(n.total,Math.max(i,0)+a+o);return h=Math.min(n.total,Math.ceil(h/t)*t),l>=h&&(l=Math.min(l,Math.max(0,n.total-1)),h=Math.min(n.total,l+Math.max(a,1))),{start:l,end:h,padTop:l*e,padBottom:(n.total-h)*e}}var k=class extends L{constructor(){super(...arguments);this.narrow=!1;this.panel={};this._objects=[];this._stats=null;this._view="overview";this._selectedEntryId=null;this._selectedTaskId=null;this._filterStatus="";this._filterUser=null;this._filterLabel=null;this._savedViews=[];this._activeViewId="";this._unsub=null;this._chartRangeDays=(()=>{try{let t=parseInt(localStorage.getItem(F.chartRange)||"",10);return[7,30,90,365].includes(t)?t:30}catch{return 30}})();this._hideOutliers=(()=>{try{return localStorage.getItem(F.chartHideOutliers)==="1"}catch{return!1}})();this._historyFilter=null;this._budget=null;this._groups={};this._detailStatsData=new Map;this._miniStatsData=new Map;this._features={adaptive:!1,predictions:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1};this._adminPanelUserIds=[];this._operatorWriteEnabled=!1;this._defaultWarningDays=7;this._actionLoading=!1;this._moreMenuOpen=!1;this._objMenuOpen=!1;this._toastMessage="";this._toastUndo=null;this._toastActionLabel="";this._filtersOpen=!1;this._newMenuOpen=!1;this._gsSetupsCount=0;this._gsAdoptCount=0;this._gsLoaded=!1;this._batteryFleetSetupAvailable=!1;this._staleBundle=!1;this._staleChecked=!1;this._toastTimer=null;this._dismissedSuggestions=new Set;this._overviewTab=(()=>{try{let t=localStorage.getItem(F.overviewTab);return t==="today"||t==="calendar"?t:"dashboard"}catch{return"dashboard"}})();this._activeTab="overview";this._costDurationToggle="both";this._historySearch="";this._sortMode="due_date";this._objectSortMode="alphabetical";this._groupByMode="none";this._objectViewMode="cards";this._objectsTableColumns=ae;this._showArchived=!1;this._bulkMode=!1;this._bulkSelected=new Set;this._virtStart=0;this._virtEnd=0;this._virtRowHeight=53;this._virtTotalRows=0;this._virtScrollAttached=!1;this._virtRaf=0;this._collapsedSections=(()=>{try{return new Set(JSON.parse(localStorage.getItem(F.collapsedSections)||"[]"))}catch{return new Set}})();this._paletteOpen=!1;this._paletteQuery="";this._paletteActive=0;this._templateGalleryOpen=!1;this._templates=[];this._templateCategories={};this._templateBusy=!1;this._statsService=null;this._userService=null;this._dataLoaded=!1;this._lastConnection=null;this._popstateHandler=t=>this._onPopState(t);this._lazyUi=null;this._onVirtualScroll=()=>{this._virtRaf||(this._virtRaf=requestAnimationFrame(()=>{this._virtRaf=0,this._updateVirtualWindow()}))};this._deepLinkHandled=!1;this._paletteKeydown=t=>{if(t.key==="/"&&!t.ctrlKey&&!t.metaKey&&!t.altKey&&!this._paletteOpen){let i=t.composedPath()[0];if(i instanceof HTMLElement&&(i.tagName==="INPUT"||i.tagName==="TEXTAREA"||i.tagName==="SELECT"||i.isContentEditable))return;t.preventDefault(),this._openPalette();return}if(!this._paletteOpen)return;let e=this._paletteResults;if(t.key==="Escape")t.preventDefault(),this._closePalette();else if(t.key==="ArrowDown")t.preventDefault(),this._paletteActive=Math.min(this._paletteActive+1,e.length-1);else if(t.key==="ArrowUp")t.preventDefault(),this._paletteActive=Math.max(this._paletteActive-1,0);else if(t.key==="Enter"){t.preventDefault();let i=e[this._paletteActive];i&&this._selectPaletteResult(i)}};this._onDialogEvent=async()=>{try{await this._loadData()}catch{}};this._onCalendarLlCustom=t=>{let e=t.detail;e?.type==="maintenance-supporter:open-task"&&e.entry_id&&e.task_id&&(t.stopPropagation(),this._showTask(e.entry_id,e.task_id))};this._fullHistory=null;this._onHistoryEntrySaved=async()=>{await this._loadData()}}get _lang(){return this.hass?.language||"en"}get _isOperator(){let t=this.hass?.user;return t?t.is_admin?!1:!(this._operatorWriteEnabled&&this._adminPanelUserIds.includes(t.id)):!0}_ensureLazyUi(){return this._lazyUi||(this._lazyUi=Promise.all([import("/maintenance_supporter_panelfiles/panel-chunks/object-dialog-MJEKQGZX.js"),import("/maintenance_supporter_panelfiles/panel-chunks/task-dialog-5FAYDEJA.js"),import("/maintenance_supporter_panelfiles/panel-chunks/complete-dialog-IWH3ZTRB.js"),import("/maintenance_supporter_panelfiles/panel-chunks/qr-dialog-7BZLBCBJ.js"),import("/maintenance_supporter_panelfiles/panel-chunks/adopt-problem-sensors-dialog-NKSR5P67.js"),import("/mainte
Line truncated
|
||||||
<div class="palette-backdrop" @click=${()=>this._closePalette()}>
|
<div class="palette-backdrop" @click=${()=>this._closePalette()}>
|
||||||
<div class="palette" @click=${i=>i.stopPropagation()}>
|
<div class="palette" @click=${i=>i.stopPropagation()}>
|
||||||
<input
|
<input
|
||||||
@@ -4575,7 +4609,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`}_bulkKey(t){return`${t.entry_id}:${t.task_id}`}_toggleBulkMode(){this._bulkMode=!this._bulkMode,this._bulkMode||(this._bulkSelected=new Set)}_toggleBulkRow(t){let e=this._bulkKey(t),i=new Set(this._bulkSelected);i.has(e)?i.delete(e):i.add(e),this._bulkSelected=i}_bulkSelectAll(t){let e=t.map(a=>this._bulkKey(a)),i=e.every(a=>this._bulkSelected.has(a));this._bulkSelected=i?new Set:new Set(e)}async _runBulk(t,e,i,a){let l=t.filter(c=>this._bulkSelected.has(this._bulkKey(c)));if(l.length===0)return;this._actionLoading=!0;let h=0;for(let c of l)try{await this.hass.connection.sendMessagePromise(e(c)),h++}catch{}this._actionLoading=!1,this._bulkSelected=new Set,this._bulkMode=!1,await this._loadData(),a&&h>0?this._showUndoToast(i(h),a):this._showToast(i(h))}_bulkComplete(t){this._runBulk(t,e=>({type:"maintenance_supporter/task/complete",entry_id:e.entry_id,task_id:e.task_id}),e=>s("bulk_completed",this._lang).replace("{n}",String(e)))}_bulkArchive(t){let e=t.filter(i=>this._bulkSelected.has(this._bulkKey(i))).map(i=>({entry_id:i.entry_id,task_id:i.task_id}));this._runBulk(t,i=>({type:"maintenance_supporter/task/archive",entry_id:i.entry_id,task_id:i.task_id}),i=>s("bulk_archived",this._lang).replace("{n}",String(i)),async()=>{for(let i of e)try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/unarchive",entry_id:i.entry_id,task_id:i.task_id})}catch{}await this._loadData()})}async _deleteObject(t){if(await this.shadowRoot.querySelector("maintenance-confirm-dialog")?.confirm({title:s("delete",this._lang),message:s("confirm_delete_object",this._lang),confirmText:s("delete",this._lang),danger:!0}))try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/delete",entry_id:t}),this._showOverview(),await this._loadData()}catch{this._showToast(s("action_error",this._lang))}}_printObjectReport(t){let e=this._getObject(t);if(!e)return;let i=this._lang,a={title:s("report_title",i),generated:s("report_generated",i),manufacturer:s("manufacturer",i),model:s("model",i),serial:s("serial_number_label",i),installed:s("installed",i),warranty:s("warranty",i),area:s("area",i),notes:s("report_notes",i),tasksHeading:s("tasks",i),colTask:s("task_name",i),colType:s("report_col_type",i),colStatus:s("report_col_status",i),colSchedule:s("report_col_schedule",i),colLastDone:s("last_performed",i),colNextDue:s("next_due",i),colCost:s("cost",i),colTimes:s("report_times_done",i),totalCost:s("report_total_cost",i),scheduleLabel:c=>xt(c,i),none:"\u2014",statusLabel:c=>s(c,i),typeLabel:c=>s(c,i)},l=he(e.object,e.tasks,a,c=>c?Y(c,i):"",this._budget?.currency_symbol||ut,new Date().toISOString()),h=URL.createObjectURL(new Blob([l],{type:"text/html"}));window.open(h,"_blank"),setTimeout(()=>URL.revokeObjectURL(h),6e4)}async _duplicateObject(t){this._actionLoading=!0;try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/duplicate",entry_id:t});await this._loadData(),this._showToast(s("object_duplicated",this._lang)),e?.entry_id&&this._showObject(e.entry_id)}catch{this._showToast(s("action_error",this._lang))}finally{this._actionLoading=!1}}async _deleteTask(t,e){if(await this.shadowRoot.querySelector("maintenance-confirm-dialog")?.confirm({title:s("delete",this._lang),message:s("confirm_delete_task",this._lang),confirmText:s("delete",this._lang),danger:!0}))try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/delete",entry_id:t,task_id:e}),this._showObject(t),await this._loadData()}catch{this._showToast(s("action_error",this._lang))}}async _duplicateTask(t,e){this._moreMenuOpen=!1,this._actionLoading=!0;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/duplicate",entry_id:t,task_id:e});await this._loadData(),this._showToast(s("task_duplicated",this._lang)),i?.task_id&&this._showTask(t,i.task_id)}catch{this._showToast(s("action_error",this._lang))}finally{this._actionLoading=!1}}async _toggleArchiveTask(t,e,i){this._actionLoading=!0;try{await this.hass.connection.sendMessagePromise({type:i?"maintenance_supporter/task/unarchive":"maintenance_supporter/task/archive",entry_id:t,task_id:e}),await this._loadData(),i||this._showUndoToast(s("task_archived",this._lang),()=>this._toggleArchiveTask(t,e,!0))}catch{this._showToast(s("action_error",this._lang))}finally{this._actionLoading=!1}}async _toggleArchiveObject(t,e){try{await this.hass.connection.sendMessagePromise({type:e?"maintenance_supporter/object/unarchive":"maintenance_supporter/object/archive",entry_id:t}),await this._loadData(),e||this._showUndoToast(s("object_archived",this._lang),()=>this._toggleArchiveObject(t,!0))}catch{this._showToast(s("action_error",this._lang))}}async _togglePauseObject(t,e){if(!e){let a=await this.shadowRoot.querySelector("maintenance-confirm-dialog")?.prompt({title:s("pause_object",this._lang),message:s("pause_until_prompt",this._lang),confirmText:s("pause_object",this._lang),inputLabel:s("pause_until_
Line truncated
|
`}_bulkKey(t){return`${t.entry_id}:${t.task_id}`}_toggleBulkMode(){this._bulkMode=!this._bulkMode,this._bulkMode||(this._bulkSelected=new Set)}_toggleBulkRow(t){let e=this._bulkKey(t),i=new Set(this._bulkSelected);i.has(e)?i.delete(e):i.add(e),this._bulkSelected=i}_bulkSelectAll(t){let e=t.map(a=>this._bulkKey(a)),i=e.every(a=>this._bulkSelected.has(a));this._bulkSelected=i?new Set:new Set(e)}async _runBulk(t,e,i,a){let l=t.filter(c=>this._bulkSelected.has(this._bulkKey(c)));if(l.length===0)return;this._actionLoading=!0;let h=0;for(let c of l)try{await this.hass.connection.sendMessagePromise(e(c)),h++}catch{}this._actionLoading=!1,this._bulkSelected=new Set,this._bulkMode=!1,await this._loadData(),a&&h>0?this._showUndoToast(i(h),a):this._showToast(i(h))}_bulkComplete(t){this._runBulk(t,e=>({type:"maintenance_supporter/task/complete",entry_id:e.entry_id,task_id:e.task_id}),e=>s("bulk_completed",this._lang).replace("{n}",String(e)))}_bulkArchive(t){let e=t.filter(i=>this._bulkSelected.has(this._bulkKey(i))).map(i=>({entry_id:i.entry_id,task_id:i.task_id}));this._runBulk(t,i=>({type:"maintenance_supporter/task/archive",entry_id:i.entry_id,task_id:i.task_id}),i=>s("bulk_archived",this._lang).replace("{n}",String(i)),async()=>{for(let i of e)try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/unarchive",entry_id:i.entry_id,task_id:i.task_id})}catch{}await this._loadData()})}async _deleteObject(t){if(await this.shadowRoot.querySelector("maintenance-confirm-dialog")?.confirm({title:s("delete",this._lang),message:s("confirm_delete_object",this._lang),confirmText:s("delete",this._lang),danger:!0}))try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/delete",entry_id:t}),this._showOverview(),await this._loadData()}catch{this._showToast(s("action_error",this._lang))}}_printObjectReport(t){let e=this._getObject(t);if(!e)return;let i=this._lang,a={title:s("report_title",i),generated:s("report_generated",i),manufacturer:s("manufacturer",i),model:s("model",i),serial:s("serial_number_label",i),installed:s("installed",i),warranty:s("warranty",i),area:s("area",i),notes:s("report_notes",i),tasksHeading:s("tasks",i),colTask:s("task_name",i),colType:s("report_col_type",i),colStatus:s("report_col_status",i),colSchedule:s("report_col_schedule",i),colLastDone:s("last_performed",i),colNextDue:s("next_due",i),colCost:s("cost",i),colTimes:s("report_times_done",i),totalCost:s("report_total_cost",i),scheduleLabel:c=>xt(c,i),none:"\u2014",statusLabel:c=>s(c,i),typeLabel:c=>s(c,i)},l=he(e.object,e.tasks,a,c=>c?Y(c,i):"",this._budget?.currency_symbol||ut,new Date().toISOString()),h=URL.createObjectURL(new Blob([l],{type:"text/html"}));window.open(h,"_blank"),setTimeout(()=>URL.revokeObjectURL(h),6e4)}async _duplicateObject(t){this._actionLoading=!0;try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object/duplicate",entry_id:t});await this._loadData(),this._showToast(s("object_duplicated",this._lang)),e?.entry_id&&this._showObject(e.entry_id)}catch{this._showToast(s("action_error",this._lang))}finally{this._actionLoading=!1}}async _deleteTask(t,e){if(await this.shadowRoot.querySelector("maintenance-confirm-dialog")?.confirm({title:s("delete",this._lang),message:s("confirm_delete_task",this._lang),confirmText:s("delete",this._lang),danger:!0}))try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/delete",entry_id:t,task_id:e}),this._showObject(t),await this._loadData()}catch{this._showToast(s("action_error",this._lang))}}async _duplicateTask(t,e){this._moreMenuOpen=!1,this._actionLoading=!0;try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/duplicate",entry_id:t,task_id:e});await this._loadData(),this._showToast(s("task_duplicated",this._lang)),i?.task_id&&this._showTask(t,i.task_id)}catch{this._showToast(s("action_error",this._lang))}finally{this._actionLoading=!1}}async _toggleArchiveTask(t,e,i){this._actionLoading=!0;try{await this.hass.connection.sendMessagePromise({type:i?"maintenance_supporter/task/unarchive":"maintenance_supporter/task/archive",entry_id:t,task_id:e}),await this._loadData(),i||this._showUndoToast(s("task_archived",this._lang),()=>this._toggleArchiveTask(t,e,!0))}catch{this._showToast(s("action_error",this._lang))}finally{this._actionLoading=!1}}async _toggleArchiveObject(t,e){try{await this.hass.connection.sendMessagePromise({type:e?"maintenance_supporter/object/unarchive":"maintenance_supporter/object/archive",entry_id:t}),await this._loadData(),e||this._showUndoToast(s("object_archived",this._lang),()=>this._toggleArchiveObject(t,!0))}catch{this._showToast(s("action_error",this._lang))}}async _togglePauseObject(t,e){if(!e){let a=await this.shadowRoot.querySelector("maintenance-confirm-dialog")?.prompt({title:s("pause_object",this._lang),message:s("pause_until_prompt",this._lang),confirmText:s("pause_object",this._lang),inputLabel:s("pause_until_
Line truncated
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
${this._staleBundle?r`
|
${this._staleBundle?r`
|
||||||
<div class="update-banner" role="status">
|
<div class="update-banner" role="status">
|
||||||
@@ -4693,6 +4727,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<span class="stat-value" style="color: #ff5722">${i.triggered}</span>
|
<span class="stat-value" style="color: #ff5722">${i.triggered}</span>
|
||||||
<span class="stat-label">${s("triggered",t)}</span>
|
<span class="stat-label">${s("triggered",t)}</span>
|
||||||
</div>
|
</div>
|
||||||
|
${this._features.budget?this._renderBudgetTiles():d}
|
||||||
</div>
|
</div>
|
||||||
`:d}
|
`:d}
|
||||||
<div class="tab-bar">
|
<div class="tab-bar">
|
||||||
@@ -4727,7 +4762,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
.budget=${this._budget}
|
.budget=${this._budget}
|
||||||
@settings-changed=${this._onSettingsChanged}
|
@settings-changed=${this._onSettingsChanged}
|
||||||
></maintenance-settings-view>`}
|
></maintenance-settings-view>`}
|
||||||
`}_statusBadge(t,e,i){let a=this._lang,l=t?"archived":e?"done":i,h=t?"archived":e?"completed":i,c=t?s("archived",a):e?s("completed",a):s(i,a);return r`<span class="status-badge ${l}"><ha-icon icon="${Mt[h]||"mdi:circle-medium"}"></ha-icon>${c}</span>`}_setOverviewTab(t){this._overviewTab=t;try{localStorage.setItem(F.overviewTab,t)}catch{}this._scrollContentToTop()}_renderToday(){let t=this._lang,e=this._taskRows,i=p=>`${p.entry_id}:${p.task_id}`,a=e.filter(p=>p.status==="overdue"||p.trigger_active),l=new Set(a.map(i)),h=e.filter(p=>!l.has(i(p))&&p.days_until_due===0);h.forEach(p=>l.add(i(p)));let c=e.filter(p=>!l.has(i(p))&&p.days_until_due!=null&&p.days_until_due>0&&p.days_until_due<=7);return a.length+h.length+c.length===0?r`
|
`}_statusBadge(t,e,i){let a=this._lang,l=t?"archived":e?"done":i,h=t?"archived":e?"completed":i,c=t?s("archived",a):e?s("completed",a):s(i,a);return r`<span class="status-badge ${l}"><ha-icon icon="${St[h]||"mdi:circle-medium"}"></ha-icon>${c}</span>`}_setOverviewTab(t){this._overviewTab=t;try{localStorage.setItem(F.overviewTab,t)}catch{}this._scrollContentToTop()}_renderToday(){let t=this._lang,e=this._taskRows,i=p=>`${p.entry_id}:${p.task_id}`,a=e.filter(p=>p.status==="overdue"||p.trigger_active),l=new Set(a.map(i)),h=e.filter(p=>!l.has(i(p))&&p.days_until_due===0);h.forEach(p=>l.add(i(p)));let c=e.filter(p=>!l.has(i(p))&&p.days_until_due!=null&&p.days_until_due>0&&p.days_until_due<=7);return a.length+h.length+c.length===0?r`
|
||||||
<div class="today-empty">
|
<div class="today-empty">
|
||||||
<ha-icon icon="mdi:check-circle-outline"></ha-icon>
|
<ha-icon icon="mdi:check-circle-outline"></ha-icon>
|
||||||
<p>${s("today_all_caught_up",t)}</p>
|
<p>${s("today_all_caught_up",t)}</p>
|
||||||
@@ -4748,7 +4783,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<span class="today-dot ${l.trigger_active?"triggered":l.status}"></span>
|
<span class="today-dot ${l.trigger_active?"triggered":l.status}"></span>
|
||||||
<div class="today-main">
|
<div class="today-main">
|
||||||
<div class="today-task">${l.task_name}</div>
|
<div class="today-task">${l.task_name}</div>
|
||||||
<div class="today-object">${l.object_name} · ${_t(l.days_until_due,a)}</div>
|
<div class="today-object">${l.object_name} · ${gt(l.days_until_due,a)}</div>
|
||||||
</div>
|
</div>
|
||||||
<mwc-icon-button class="btn-complete" title="${s("complete",a)}"
|
<mwc-icon-button class="btn-complete" title="${s("complete",a)}"
|
||||||
@click=${h=>{h.stopPropagation(),this._openCompleteDialogForRow(l)}}>
|
@click=${h=>{h.stopPropagation(),this._openCompleteDialogForRow(l)}}>
|
||||||
@@ -4758,7 +4793,6 @@ ${A(n.notes)}</div>`:""}
|
|||||||
`)}
|
`)}
|
||||||
</div>
|
</div>
|
||||||
`}_renderDashboard(){let t=this._stats,e=this._taskRows,i=this._lang,a=this._isOperator,l=this._objects.reduce((c,p)=>c+p.tasks.filter(u=>u.archived).length,0),h=(this._filterStatus?1:0)+(this._filterUser?1:0)+(this._filterLabel?1:0)+(this._activeViewId?1:0);return r`
|
`}_renderDashboard(){let t=this._stats,e=this._taskRows,i=this._lang,a=this._isOperator,l=this._objects.reduce((c,p)=>c+p.tasks.filter(u=>u.archived).length,0),h=(this._filterStatus?1:0)+(this._filterUser?1:0)+(this._filterLabel?1:0)+(this._activeViewId?1:0);return r`
|
||||||
${this._features.budget?this._renderBudgetBar():d}
|
|
||||||
|
|
||||||
${this.narrow?r`
|
${this.narrow?r`
|
||||||
<div class="mobile-controls">
|
<div class="mobile-controls">
|
||||||
@@ -4769,15 +4803,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<ha-icon icon="mdi:filter-variant"></ha-icon>
|
<ha-icon icon="mdi:filter-variant"></ha-icon>
|
||||||
${s("filter_label",i)}${h>0?` (${h})`:""}
|
${s("filter_label",i)}${h>0?` (${h})`:""}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
${a?d:r`
|
${a?d:this._renderNewMenu(i)}
|
||||||
<ha-button
|
|
||||||
class="mobile-toggle ${this._actionsMenuOpen?"active":""}"
|
|
||||||
@click=${()=>{this._actionsMenuOpen=!this._actionsMenuOpen}}
|
|
||||||
>
|
|
||||||
<ha-icon icon="mdi:plus"></ha-icon>
|
|
||||||
${s("add",i)}
|
|
||||||
</ha-button>
|
|
||||||
`}
|
|
||||||
</div>
|
</div>
|
||||||
`:d}
|
`:d}
|
||||||
|
|
||||||
@@ -4881,39 +4907,10 @@ ${A(n.notes)}</div>`:""}
|
|||||||
${this._bulkMode?s("cancel",i):s("bulk_select",i)}
|
${this._bulkMode?s("cancel",i):s("bulk_select",i)}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
`:d}
|
`:d}
|
||||||
|
${!a&&!this.narrow?this._renderNewMenu(i):d}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${a?d:r`
|
${a?d:this._renderGettingStartedChips(i)}
|
||||||
<div
|
|
||||||
class="actions-bar ${this.narrow&&!this._actionsMenuOpen?"collapsed":""}"
|
|
||||||
@click=${()=>{this.narrow&&(this._actionsMenuOpen=!1)}}
|
|
||||||
>
|
|
||||||
<ha-button
|
|
||||||
@click=${()=>this._ui("maintenance-task-dialog").then(c=>c?.openCreate("",this._objects))}
|
|
||||||
>
|
|
||||||
${s("new_task",i)}
|
|
||||||
</ha-button>
|
|
||||||
<ha-button
|
|
||||||
@click=${()=>this._ui("maintenance-object-dialog").then(c=>c?.openCreate())}
|
|
||||||
>
|
|
||||||
${s("new_object",i)}
|
|
||||||
</ha-button>
|
|
||||||
<ha-button @click=${()=>this._openTemplateGallery()}>
|
|
||||||
<ha-icon icon="mdi:view-grid-plus-outline"></ha-icon> ${s("templates_from",i)}
|
|
||||||
</ha-button>
|
|
||||||
<ha-button @click=${()=>this._openAdoptProblemSensors()}>
|
|
||||||
<ha-icon icon="mdi:alert-circle-check-outline"></ha-icon> ${s("adopt_problem_button",i)}
|
|
||||||
</ha-button>
|
|
||||||
<ha-button @click=${()=>this._openSuggestedSetups()}>
|
|
||||||
<ha-icon icon="mdi:auto-fix"></ha-icon> ${s("setups_button",i)}
|
|
||||||
</ha-button>
|
|
||||||
${this._batteryFleetSetupAvailable?r`
|
|
||||||
<ha-button @click=${()=>this._setupBatteryFleet()}>
|
|
||||||
<ha-icon icon="mdi:battery-sync"></ha-icon> ${s("battery_fleet_setup_button",i)}
|
|
||||||
</ha-button>
|
|
||||||
`:d}
|
|
||||||
</div>
|
|
||||||
`}
|
|
||||||
|
|
||||||
${e.length===0?r`
|
${e.length===0?r`
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
@@ -4996,9 +4993,9 @@ ${A(n.notes)}</div>`:""}
|
|||||||
</details>
|
</details>
|
||||||
`)}
|
`)}
|
||||||
`}_warrantyLabel(t,e,i){return t.kind==="expired"?s("warranty_expired",i):t.kind==="expiring"?s("warranty_expires_in",i).replace("{days}",String(t.days??0)):s("warranty_valid_until",i).replace("{date}",Y(e,i))}_renderWarrantyMeta(t,e){let i=Kt(t);return r`<p class="meta">${s("warranty",e)}:
|
`}_warrantyLabel(t,e,i){return t.kind==="expired"?s("warranty_expired",i):t.kind==="expiring"?s("warranty_expires_in",i).replace("{days}",String(t.days??0)):s("warranty_valid_until",i).replace("{date}",Y(e,i))}_renderWarrantyMeta(t,e){let i=Kt(t);return r`<p class="meta">${s("warranty",e)}:
|
||||||
<span class="warranty-chip warranty-${i.kind}">${this._warrantyLabel(i,t,e)}</span></p>`}_renderAllObjects(){let t=this._lang,e=this._isOperator,i=this._objectViewMode==="table"&&!this.narrow,a=this._objects.filter(u=>u.object.archived).length,l=u=>{let g=1/0;for(let v of u.tasks){let b=v.days_until_due;b!=null&&b<g&&(g=b)}return g},h=this._objects.filter(u=>this._showArchived||!u.object.archived);this._objectSortMode==="alphabetical"?h.sort((u,g)=>u.object.name.localeCompare(g.object.name)):this._objectSortMode==="task_count"?h.sort((u,g)=>g.tasks.length-u.tasks.length||u.object.name.localeCompare(g.object.name)):h.sort((u,g)=>l(u)-l(g)||u.object.name.localeCompare(g.object.name));let c=()=>{let u=new Map;for(let g of h){let v=g.object.area_id,b=v?this.hass?.areas?.[v]?.name||s("unassigned",t):s("no_area",t);u.has(b)||u.set(b,[]),u.get(b).push(g)}return new Map([...u.entries()].sort(([g],[v])=>g.localeCompare(v)))},p=u=>{let g=u.tasks.some(v=>v.status==="overdue"||v.status==="triggered");return r`
|
<span class="warranty-chip warranty-${i.kind}">${this._warrantyLabel(i,t,e)}</span></p>`}_renderAllObjects(){let t=this._lang,e=this._isOperator,i=this._objectViewMode==="table"&&!this.narrow,a=this._objects.filter(u=>u.object.archived).length,l=u=>{let _=1/0;for(let v of u.tasks){let b=v.days_until_due;b!=null&&b<_&&(_=b)}return _},h=this._objects.filter(u=>this._showArchived||!u.object.archived);this._objectSortMode==="alphabetical"?h.sort((u,_)=>u.object.name.localeCompare(_.object.name)):this._objectSortMode==="task_count"?h.sort((u,_)=>_.tasks.length-u.tasks.length||u.object.name.localeCompare(_.object.name)):h.sort((u,_)=>l(u)-l(_)||u.object.name.localeCompare(_.object.name));let c=()=>{let u=new Map;for(let _ of h){let v=_.object.area_id,b=v?this.hass?.areas?.[v]?.name||s("unassigned",t):s("no_area",t);u.has(b)||u.set(b,[]),u.get(b).push(_)}return new Map([...u.entries()].sort(([_],[v])=>_.localeCompare(v)))},p=u=>{let _=u.tasks.some(v=>v.status==="overdue"||v.status==="triggered");return r`
|
||||||
<div class="object-card${g?" object-card-overdue":""}" @click=${()=>this._showObject(u.entry_id)}>
|
<div class="object-card${_?" object-card-overdue":""}" @click=${()=>this._showObject(u.entry_id)}>
|
||||||
${g?r`<span class="overdue-dot" title="${s("has_overdue",t)}"></span>`:d}
|
${_?r`<span class="overdue-dot" title="${s("has_overdue",t)}"></span>`:d}
|
||||||
<div class="object-card-header">
|
<div class="object-card-header">
|
||||||
<span class="object-card-name">${u.object.name}</span>
|
<span class="object-card-name">${u.object.name}</span>
|
||||||
${u.object.paused?r`<span class="paused-badge" title="${s("object_paused_badge",t)}${u.object.paused_until?` \u2014 ${u.object.paused_until}`:""}">
|
${u.object.paused?r`<span class="paused-badge" title="${s("object_paused_badge",t)}${u.object.paused_until?` \u2014 ${u.object.paused_until}`:""}">
|
||||||
@@ -5078,14 +5075,14 @@ ${A(n.notes)}</div>`:""}
|
|||||||
`:d}
|
`:d}
|
||||||
</div>
|
</div>
|
||||||
${i?this._renderObjectsTable(h):this._groupByMode==="area"?r`
|
${i?this._renderObjectsTable(h):this._groupByMode==="area"?r`
|
||||||
${[...c().entries()].map(([u,g])=>r`
|
${[...c().entries()].map(([u,_])=>r`
|
||||||
<details class="group-section" open>
|
<details class="group-section" open>
|
||||||
<summary class="group-section-header">
|
<summary class="group-section-header">
|
||||||
<ha-icon icon="mdi:map-marker-outline"></ha-icon>
|
<ha-icon icon="mdi:map-marker-outline"></ha-icon>
|
||||||
<span>${u}</span>
|
<span>${u}</span>
|
||||||
<span class="group-section-count">(${g.length})</span>
|
<span class="group-section-count">(${_.length})</span>
|
||||||
</summary>
|
</summary>
|
||||||
<div class="objects-grid">${g.map(p)}</div>
|
<div class="objects-grid">${_.map(p)}</div>
|
||||||
</details>
|
</details>
|
||||||
`)}
|
`)}
|
||||||
`:r`<div class="objects-grid">${h.map(p)}</div>`}
|
`:r`<div class="objects-grid">${h.map(p)}</div>`}
|
||||||
@@ -5150,33 +5147,25 @@ ${A(n.notes)}</div>`:""}
|
|||||||
</div>
|
</div>
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
`}_openGroupCreate(){this.shadowRoot.querySelector("maintenance-group-dialog")?.openCreate()}_openGroupEdit(t){let e=this._groups[t];e&&this.shadowRoot.querySelector("maintenance-group-dialog")?.openEdit(t,e)}async _deleteGroup(t,e){let i=this.shadowRoot.querySelector("maintenance-confirm-dialog");if(i?await i.confirm({title:s("delete_group",this._lang),message:s("delete_group_confirm",this._lang).replace("{name}",e),confirmText:s("delete",this._lang)}):confirm(`${s("delete_group_confirm",this._lang).replace("{name}",e)}`))try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/delete",group_id:t}),await this._loadData()}catch{this._showToast(s("action_error",this._lang))}}_renderBudgetBar(){let t=this._budget;if(!t)return d;let e=this._lang,i=t.currency_symbol||ut,a=[];t.monthly_budget>0&&a.push({label:s("budget_monthly",e),spent:t.monthly_spent,budget:t.monthly_budget}),t.yearly_budget>0&&a.push({label:s("budget_yearly",e),spent:t.yearly_spent,budget:t.yearly_budget});let l=[];return t.monthly_budget>0||l.push({label:s("budget_monthly",e),spent:t.monthly_spent||0}),t.yearly_budget>0||l.push({label:s("budget_yearly",e),spent:t.yearly_spent||0}),r`
|
`}_openGroupCreate(){this.shadowRoot.querySelector("maintenance-group-dialog")?.openCreate()}_openGroupEdit(t){let e=this._groups[t];e&&this.shadowRoot.querySelector("maintenance-group-dialog")?.openEdit(t,e)}async _deleteGroup(t,e){let i=this.shadowRoot.querySelector("maintenance-confirm-dialog");if(i?await i.confirm({title:s("delete_group",this._lang),message:s("delete_group_confirm",this._lang).replace("{name}",e),confirmText:s("delete",this._lang)}):confirm(`${s("delete_group_confirm",this._lang).replace("{name}",e)}`))try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/group/delete",group_id:t}),await this._loadData()}catch{this._showToast(s("action_error",this._lang))}}_renderBudgetTiles(){let t=this._budget;if(!t)return d;let e=this._lang,i=t.currency_symbol||ut,a=(l,h,c)=>{if(c!==null){let p=Math.min(100,Math.max(0,h/c*100)),u=p>=100?"var(--error-color, #f44336)":p>=t.alert_threshold_pct?"var(--warning-color, #ff9800)":"var(--success-color, #4caf50)";return r`
|
||||||
<div class="budget-bars">
|
<div class="stat-item budget-tile" title="${l}: ${h.toFixed(2)} / ${c.toFixed(2)} ${i}">
|
||||||
${a.map(h=>{let c=Math.min(100,Math.max(0,h.spent/h.budget*100)),p=c>=100?"var(--error-color, #f44336)":c>=t.alert_threshold_pct?"var(--warning-color, #ff9800)":"var(--success-color, #4caf50)";return r`
|
<span class="stat-value budget-tile-value">${h.toFixed(2)} / ${c.toFixed(0)} ${i}</span>
|
||||||
<div class="budget-item">
|
<div class="budget-tile-bar"><div style="width:${p}%; background:${u}"></div></div>
|
||||||
<div class="budget-label">
|
<span class="stat-label">${l}</span>
|
||||||
<span>${h.label}</span>
|
|
||||||
<span>${h.spent.toFixed(2)} / ${h.budget.toFixed(2)} ${i}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="budget-bar">
|
`}return r`
|
||||||
<div class="budget-bar-fill" style="width:${c}%; background:${p}"></div>
|
<div class="stat-item budget-tile" title="${l}: ${h.toFixed(2)} ${i}">
|
||||||
|
<span class="stat-value budget-tile-value">${h.toFixed(2)} ${i}</span>
|
||||||
|
<span class="stat-label">${l}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
`};return r`
|
||||||
`})}
|
${a(s("budget_monthly",e),t.monthly_spent||0,t.monthly_budget>0?t.monthly_budget:null)}
|
||||||
${l.map(h=>r`
|
${a(s("budget_yearly",e),t.yearly_spent||0,t.yearly_budget>0?t.yearly_budget:null)}
|
||||||
<div class="budget-item budget-spent-only">
|
`}_renderOverviewRow(t){let e=this._lang,i=t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0,a=0,l=jt.ok,h=!1;if(i&&t.days_until_due!==null){let v=Ot(t.interval_days,t.days_until_due,t.interval_unit);a=v.pct,h=v.overflow,t.status==="overdue"?l=jt.overdue:t.status==="due_soon"&&(l=jt.due_soon)}let c=t.area_id?this.hass?.areas?.[t.area_id]?.name:null,p=t.responsible_user_id?this._userService?.getUserName(t.responsible_user_id):null,u=t.group_names.length>0||c||p,_=this._bulkMode&&this._bulkSelected.has(this._bulkKey(t));return r`
|
||||||
<div class="budget-label">
|
<div class="task-row${t.enabled?"":" task-disabled"}${_?" bulk-selected":""}">
|
||||||
<span>${h.label}</span>
|
|
||||||
<span>${h.spent.toFixed(2)} ${i}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`)}
|
|
||||||
</div>
|
|
||||||
`}_renderOverviewRow(t){let e=this._lang,i=t.schedule_type==="time_based"&&t.interval_days&&t.interval_days>0,a=0,l=jt.ok,h=!1;if(i&&t.days_until_due!==null){let v=Ot(t.interval_days,t.days_until_due,t.interval_unit);a=v.pct,h=v.overflow,t.status==="overdue"?l=jt.overdue:t.status==="due_soon"&&(l=jt.due_soon)}let c=t.area_id?this.hass?.areas?.[t.area_id]?.name:null,p=t.responsible_user_id?this._userService?.getUserName(t.responsible_user_id):null,u=t.group_names.length>0||c||p,g=this._bulkMode&&this._bulkSelected.has(this._bulkKey(t));return r`
|
|
||||||
<div class="task-row${t.enabled?"":" task-disabled"}${g?" bulk-selected":""}">
|
|
||||||
${this._bulkMode?r`
|
${this._bulkMode?r`
|
||||||
<label class="cell bulk-check" @click=${v=>v.stopPropagation()}>
|
<label class="cell bulk-check" @click=${v=>v.stopPropagation()}>
|
||||||
<input type="checkbox" .checked=${g} @change=${()=>this._toggleBulkRow(t)} />
|
<input type="checkbox" .checked=${_} @change=${()=>this._toggleBulkRow(t)} />
|
||||||
</label>
|
</label>
|
||||||
`:d}
|
`:d}
|
||||||
<span class="cell-badges">
|
<span class="cell-badges">
|
||||||
@@ -5208,7 +5197,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
</span>
|
</span>
|
||||||
<span class="cell type">${s(t.type,e)}</span>
|
<span class="cell type">${s(t.type,e)}</span>
|
||||||
<span class="due-cell" @click=${()=>this._showTask(t.entry_id,t.task_id)}>
|
<span class="due-cell" @click=${()=>this._showTask(t.entry_id,t.task_id)}>
|
||||||
<span class="due-text">${_t(t.days_until_due,e)}</span>
|
<span class="due-text">${gt(t.days_until_due,e)}</span>
|
||||||
${i?r`<div class="days-bar"><div class="days-bar-fill${h?" overflow":""}" style="width:${a}%;background:${l}"></div></div>`:d}
|
${i?r`<div class="days-bar"><div class="days-bar-fill${h?" overflow":""}" style="width:${a}%;background:${l}"></div></div>`:d}
|
||||||
${t.trigger_config?Zt(t):!i&&t.trigger_active?r`<span style="color:var(--maint-triggered-color);font-weight:600">⚡</span>`:d}
|
${t.trigger_config?Zt(t):!i&&t.trigger_active?r`<span style="color:var(--maint-triggered-color);font-weight:600">⚡</span>`:d}
|
||||||
${Qt(t,this._miniStatsData,this._lang)}
|
${Qt(t,this._miniStatsData,this._lang)}
|
||||||
@@ -5295,7 +5284,7 @@ ${A(n.notes)}</div>`:""}
|
|||||||
<span class="task-sub${c.responsible_user_id?"":" task-sub-empty"}">${te(c,p=>this._userService?.getUserName(p)??null)}</span>
|
<span class="task-sub${c.responsible_user_id?"":" task-sub-empty"}">${te(c,p=>this._userService?.getUserName(p)??null)}</span>
|
||||||
<span class="cell type">${s(c.type,i)}</span>
|
<span class="cell type">${s(c.type,i)}</span>
|
||||||
<span class="due-cell" @click=${()=>this._showTask(t.entry_id,c.id)}>
|
<span class="due-cell" @click=${()=>this._showTask(t.entry_id,c.id)}>
|
||||||
<span class="due-text">${_t(c.days_until_due,i)}</span>
|
<span class="due-text">${gt(c.days_until_due,i)}</span>
|
||||||
${c.trigger_config?Zt(c):d}
|
${c.trigger_config?Zt(c):d}
|
||||||
${Qt(c,this._miniStatsData,this._lang)}
|
${Qt(c,this._miniStatsData,this._lang)}
|
||||||
</span>
|
</span>
|
||||||
@@ -5325,7 +5314,56 @@ ${A(n.notes)}</div>`:""}
|
|||||||
@parts-changed=${()=>this._loadData()}
|
@parts-changed=${()=>this._loadData()}
|
||||||
></maintenance-parts-section>
|
></maintenance-parts-section>
|
||||||
</div>
|
</div>
|
||||||
|
`}_renderNewMenu(t){return r`
|
||||||
|
<div class="new-menu-wrapper">
|
||||||
|
<ha-button appearance="filled" class="new-menu-button"
|
||||||
|
@click=${e=>{e.stopPropagation(),this._toggleNewMenu()}}>
|
||||||
|
<ha-icon icon="mdi:plus"></ha-icon> ${s("new_menu",t)}
|
||||||
|
<ha-icon icon="mdi:menu-down"></ha-icon>
|
||||||
|
</ha-button>
|
||||||
|
${this._newMenuOpen?r`
|
||||||
|
<div class="popup-menu new-menu-popup" @click=${e=>e.stopPropagation()}>
|
||||||
|
<div class="popup-menu-item" @click=${()=>{this._closeNewMenu(),this._ui("maintenance-task-dialog").then(e=>e?.openCreate("",this._objects))}}>
|
||||||
|
<ha-icon icon="mdi:clipboard-plus-outline"></ha-icon> ${s("new_task",t)}
|
||||||
|
</div>
|
||||||
|
<div class="popup-menu-item" @click=${()=>{this._closeNewMenu(),this._ui("maintenance-object-dialog").then(e=>e?.openCreate())}}>
|
||||||
|
<ha-icon icon="mdi:package-variant-closed-plus"></ha-icon> ${s("new_object",t).replace(/^\+\s*/,"")}
|
||||||
|
</div>
|
||||||
|
<div class="popup-menu-item" @click=${()=>{this._closeNewMenu(),this._openTemplateGallery()}}>
|
||||||
|
<ha-icon icon="mdi:view-grid-plus-outline"></ha-icon> ${s("templates_from",t)}
|
||||||
|
</div>
|
||||||
|
<div class="popup-menu-divider"></div>
|
||||||
|
<div class="popup-menu-item" @click=${()=>{this._closeNewMenu(),this._openAdoptProblemSensors()}}>
|
||||||
|
<ha-icon icon="mdi:alert-circle-check-outline"></ha-icon> ${s("adopt_problem_button",t)}
|
||||||
|
</div>
|
||||||
|
<div class="popup-menu-item" @click=${()=>{this._closeNewMenu(),this._openSuggestedSetups()}}>
|
||||||
|
<ha-icon icon="mdi:auto-fix"></ha-icon> ${s("setups_button",t)}
|
||||||
|
</div>
|
||||||
|
${this._batteryFleetSetupAvailable?r`
|
||||||
|
<div class="popup-menu-item" @click=${()=>{this._closeNewMenu(),this._setupBatteryFleet()}}>
|
||||||
|
<ha-icon icon="mdi:battery-sync"></ha-icon> ${s("battery_fleet_setup_button",t)}
|
||||||
|
</div>
|
||||||
|
`:d}
|
||||||
|
</div>
|
||||||
|
`:d}
|
||||||
|
</div>
|
||||||
|
`}_toggleNewMenu(){this._newMenuOpen=!this._newMenuOpen,this._newMenuOpen&&setTimeout(()=>{let t=()=>{this._newMenuOpen=!1,document.removeEventListener("click",t)};document.addEventListener("click",t)},0)}_closeNewMenu(){this._newMenuOpen=!1}_isYoungInstall(){let t=this._objects.filter(i=>!i.object?.battery_fleet),e=t.reduce((i,a)=>i+a.tasks.length,0);return t.length<3&&e<8}_gsDismissed(){try{return new Set(JSON.parse(localStorage.getItem(F.gettingStartedDismissed)||"[]"))}catch{return new Set}}_dismissGettingStarted(t){let e=this._gsDismissed();e.add(t);try{localStorage.setItem(F.gettingStartedDismissed,JSON.stringify([...e]))}catch{}this.requestUpdate()}_maybeLoadGettingStarted(){this._gsLoaded||!this._isYoungInstall()||(this._gsLoaded=!0,this.hass.connection.sendMessagePromise({type:"maintenance_supporter/integration_setups/discover"}).then(t=>{this._gsSetupsCount=(t.setups||[]).length}).catch(()=>{this._gsSetupsCount=0}),this.hass.connection.sendMessagePromise({type:"maintenance_supporter/problem_sensors/discover"}).then(t=>{this._gsAdoptCount=(t.sensors||[]).length}).catch(()=>{this._gsAdoptCount=0}))}_renderGettingStartedChips(t){let e=this._gsDismissed(),i=this._isYoungInstall(),a=[];return i&&this._gsSetupsCount>0&&!e.has("setups")&&a.push({id:"setups",icon:"mdi:auto-fix",text:s("gs_setups_chip",t).replace("{n}",String(this._gsSetupsCount)),run:()=>this._openSuggestedSetups()}),i&&this._gsAdoptCount>0&&!e.has("adopt")&&a.push({id:"adopt",icon:"mdi:alert-circle-check-outline",text:s("gs_adopt_chip",t).replace("{n}",String(this._gsAdoptCount)),run:()=>this._openAdoptProblemSensors()}),this._batteryFleetSetupAvailable&&!e.has("fleet")&&a.push({id:"fleet",icon:"mdi:battery-sync",text:s("gs_fleet_chip",t),run:()=>this._setupBatteryFleet()}),a.length===0?d:r`
|
||||||
|
<div class="gs-chips-wrap">
|
||||||
|
<div class="gs-chips-label">${s("gs_label",t)}</div>
|
||||||
|
<div class="gs-chips">
|
||||||
|
${a.map(l=>r`
|
||||||
|
<div class="gs-chip" @click=${()=>l.run()}>
|
||||||
|
<ha-icon icon="${l.icon}"></ha-icon>
|
||||||
|
<span>${l.text}</span>
|
||||||
|
<span class="gs-chip-x" title="${s("dismiss",t)}"
|
||||||
|
@click=${h=>{h.stopPropagation(),this._dismissGettingStarted(l.id)}}>
|
||||||
|
<ha-icon icon="mdi:close"></ha-icon>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
`}_toggleObjMenu(){this._objMenuOpen=!this._objMenuOpen,this._objMenuOpen&&setTimeout(()=>{let t=()=>{this._objMenuOpen=!1,document.removeEventListener("click",t)};document.addEventListener("click",t)},0)}_closeObjMenu(){this._objMenuOpen=!1}_toggleMoreMenu(){if(this._moreMenuOpen=!this._moreMenuOpen,this._moreMenuOpen){let t=()=>{this._moreMenuOpen=!1,document.removeEventListener("click",t)};setTimeout(()=>document.addEventListener("click",t,{once:!0}),0)}}_closeMoreMenu(){this._moreMenuOpen=!1}get _sparklineCtx(){return{lang:this._lang,detailStatsData:this._detailStatsData,hasStatsService:!!this._statsService,isCounterEntity:t=>this._isCounterEntity(t),rangeDays:this._chartRangeDays,setRangeDays:t=>this._setChartRange(t),hideOutliers:this._hideOutliers,setHideOutliers:t=>this._setHideOutliers(t)}}_toggleSection(t){let e=new Set(this._collapsedSections);e.has(t)?e.delete(t):e.add(t),this._collapsedSections=e;try{localStorage.setItem(F.collapsedSections,JSON.stringify([...e]))}catch{}}_historyCtx(){let t=this._selectedEntryId&&this._selectedTaskId?this._getObject(this._selectedEntryId)?.tasks.find(l=>l.id===this._selectedTaskId):void 0,e=this._fullHistory,a=(e&&e.entryId===this._selectedEntryId&&e.taskId===this._selectedTaskId&&e.entries.length>(t?.history||[]).length?e.entries:t?.history||[]).filter(l=>l.reading_value!=null).sort((l,h)=>l.timestamp.localeCompare(h.timestamp));return{lang:this._lang,hass:this.hass,filter:this._historyFilter,search:this._historySearch,currencySymbol:this._budget?.currency_symbol||ut,setFilter:l=>{this._historyFilter=l},setSearch:l=>{this._historySearch=l},openEdit:l=>this._openHistoryEdit(l),readingUnit:t?.reading_unit??null,readingDelta:l=>{let h=a.findIndex(c=>c.timestamp===l.timestamp);return h<=0?null:l.reading_value-a[h-1].reading_value}}}_taskDetailCtx(){let t=this._selectedEntryId,e=this._selectedTaskId,i=this._getObject(t);return{lang:this._lang,hass:this.hass,entryId:t,taskId:e,objectName:i?.object.name||"",objectDocUrl:i?.object?.documentation_url??null,objectManualDocs:i?.object?.manual_docs??[],openManualDoc:a=>this._openManualDoc(a),setChecklistItem:(a,l)=>this._setChecklistItem(t,e,a,l),isOperator:this._isOperator,actionLoading:this._actionLoading,moreMenuOpen:this._moreMenuOpen,activeTab:this._activeTab,features:this._features,currencySymbol:this._budget?.currency_symbol||ut,collapsedSections:this._collapsedSections,costDurationToggle:this._costDurationToggle,suggestionDismissed:this._dismissedSuggestions.has(`${t}_${e}`),sparkline:this._sparklineCtx,history:this._historyCtx(),getUserName:a=>this._userService?.getUserName(a)??null,setActiveTab:a=>{this._activeTab=a},toggleSection:a=>this._toggleSection(a),setCostDurationToggle:a=>{this._costDurationToggle=a},showTaskView:()=>{this._view="task"},showObject:()=>this._showObject(t),toggleMoreMenu:()=>this._toggleMoreMenu(),closeMoreMenu:()=>this._closeMoreMenu(),openEdit:a=>{this._ui("maintenance-task-dialog").then(l=>l?.openEdit(t,a))},openComplete:a=>this._openCompleteDialog(t,e,a.name,this._features.checklists?a.checklist:void 0,this._features.adaptive&&!!a.adaptive_config?.enabled),promptSkip:()=>this._promptSkipTask(t,e),toggleArchive:a=>this._toggleArchiveTask(t,e,a),openQr:a=>this._openQrForTask(t,e,i?.object.name||"",a),duplicateTask:()=>this._duplicateTask(t,e),promptReset:()=>this._promptResetTask(t,e),promptPostpone:()=>this._promptPostponeTask(t,e),snoozeTask:()=>this._snoozeTask(t,e),printWorksheet:()=>this._printTaskWorksheet(t,e),deleteTask:()=>this._deleteTask(t,e),applySuggestion:a=>this._applySuggestion(t,e,a),reanalyze:()=>this._reanalyzeInterval(t,e),dismissSuggestion:()=>this._dismissSuggestion(t,e),openSeasonalOverrides:a=>this._openSeasonalOverrides(a)}}async _fetchFullHistory(t,e){try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:t,task_id:e});this._selectedEntryId===t&&this._selectedTaskId===e&&(this._fullHistory={entryId:t,taskId:e,entries:i.history||[]})}catch{this._fullHistory=null}}_renderTaskDetail(){if(!this._selectedEntryId||!this._selectedTaskId)return d;let t=this._getTask(this._selectedEntryId,this._selectedTaskId);if(!t)return r`<p>Task not found.</p>`;let e=this._fullHistory,i=e&&e.entryId===this._selectedEntryId&&e.taskId===this._selectedTaskId&&e.entries.length>(t.history||[]).length?{...t,history:e.entries}:t;return r`<maintenance-task-detail-view
|
`}_toggleObjMenu(){this._objMenuOpen=!this._objMenuOpen,this._objMenuOpen&&setTimeout(()=>{let t=()=>{this._objMenuOpen=!1,document.removeEventListener("click",t)};document.addEventListener("click",t)},0)}_closeObjMenu(){this._objMenuOpen=!1}_toggleMoreMenu(){if(this._moreMenuOpen=!this._moreMenuOpen,this._moreMenuOpen){let t=()=>{this._moreMenuOpen=!1,document.removeEventListener("click",t)};setTimeout(()=>document.addEventListener("click",t,{once:!0}),0)}}_closeMoreMenu(){this._moreMenuOpen=!1}get _sparklineCtx(){return{lang:this._lang,detailStatsData:this._detailStatsData,hasStatsService:!!this._statsService,isCounterEntity:t=>this._isCounterEntity(t),rangeDays:this._chartRangeDays,setRangeDays:t=>this._setChartRange(t),hideOutliers:this._hideOutliers,setHideOutliers:t=>this._setHideOutliers(t)}}_toggleSection(t){let e=new Set(this._collapsedSections);e.has(t)?e.delete(t):e.add(t),this._collapsedSections=e;try{localStorage.setItem(F.collapsedSections,JSON.stringify([...e]))}catch{}}_historyCtx(){let t=this._selectedEntryId&&this._selectedTaskId?this._getObject(this._selectedEntryId)?.tasks.find(l=>l.id===this._selectedTaskId):void 0,e=this._fullHistory,a=(e&&e.entryId===this._selectedEntryId&&e.taskId===this._selectedTaskId&&e.entries.length>(t?.history||[]).length?e.entries:t?.history||[]).filter(l=>l.reading_value!=null).sort((l,h)=>l.timestamp.localeCompare(h.timestamp));return{lang:this._lang,hass:this.hass,filter:this._historyFilter,search:this._historySearch,currencySymbol:this._budget?.currency_symbol||ut,setFilter:l=>{this._historyFilter=l},setSearch:l=>{this._historySearch=l},openEdit:l=>this._openHistoryEdit(l),readingUnit:t?.reading_unit??null,readingDelta:l=>{let h=a.findIndex(c=>c.timestamp===l.timestamp);return h<=0?null:l.reading_value-a[h-1].reading_value}}}_taskDetailCtx(){let t=this._selectedEntryId,e=this._selectedTaskId,i=this._getObject(t);return{lang:this._lang,hass:this.hass,entryId:t,taskId:e,objectName:i?.object.name||"",objectDocUrl:i?.object?.documentation_url??null,objectManualDocs:i?.object?.manual_docs??[],openManualDoc:a=>this._openManualDoc(a),setChecklistItem:(a,l)=>this._setChecklistItem(t,e,a,l),isOperator:this._isOperator,actionLoading:this._actionLoading,moreMenuOpen:this._moreMenuOpen,activeTab:this._activeTab,features:this._features,currencySymbol:this._budget?.currency_symbol||ut,collapsedSections:this._collapsedSections,costDurationToggle:this._costDurationToggle,suggestionDismissed:this._dismissedSuggestions.has(`${t}_${e}`),sparkline:this._sparklineCtx,history:this._historyCtx(),getUserName:a=>this._userService?.getUserName(a)??null,setActiveTab:a=>{this._activeTab=a},toggleSection:a=>this._toggleSection(a),setCostDurationToggle:a=>{this._costDurationToggle=a},showTaskView:()=>{this._view="task"},showObject:()=>this._showObject(t),toggleMoreMenu:()=>this._toggleMoreMenu(),closeMoreMenu:()=>this._closeMoreMenu(),openEdit:a=>{this._ui("maintenance-task-dialog").then(l=>l?.openEdit(t,a))},openComplete:a=>this._openCompleteDialog(t,e,a.name,this._features.checklists?a.checklist:void 0,this._features.adaptive&&!!a.adaptive_config?.enabled),promptSkip:()=>this._promptSkipTask(t,e),toggleArchive:a=>this._toggleArchiveTask(t,e,a),openQr:a=>this._openQrForTask(t,e,i?.object.name||"",a),duplicateTask:()=>this._duplicateTask(t,e),promptReset:()=>this._promptResetTask(t,e),promptPostpone:()=>this._promptPostponeTask(t,e),snoozeTask:()=>this._snoozeTask(t,e),printWorksheet:()=>this._printTaskWorksheet(t,e),deleteTask:()=>this._deleteTask(t,e),applySuggestion:a=>this._applySuggestion(t,e,a),reanalyze:()=>this._reanalyzeInterval(t,e),dismissSuggestion:()=>this._dismissSuggestion(t,e),openSeasonalOverrides:a=>this._openSeasonalOverrides(a)}}async _fetchFullHistory(t,e){try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:t,task_id:e});this._selectedEntryId===t&&this._selectedTaskId===e&&(this._fullHistory={entryId:t,taskId:e,entries:i.history||[]})}catch{this._fullHistory=null}}_renderTaskDetail(){if(!this._selectedEntryId||!this._selectedTaskId)return d;let t=this._getTask(this._selectedEntryId,this._selectedTaskId);if(!t)return r`<p>Task not found.</p>`;let e=this._fullHistory,i=e&&e.entryId===this._selectedEntryId&&e.taskId===this._selectedTaskId&&e.entries.length>(t.history||[]).length?{...t,history:e.entries}:t;return r`<maintenance-task-detail-view
|
||||||
.task=${i}
|
.task=${i}
|
||||||
.ctx=${this._taskDetailCtx()}
|
.ctx=${this._taskDetailCtx()}
|
||||||
></maintenance-task-detail-view>`}_openHistoryEdit(t){if(!this._selectedEntryId||!this._selectedTaskId)return;let e={entry_id:this._selectedEntryId,task_id:this._selectedTaskId,original_timestamp:t.timestamp,type:t.type,timestamp:t.timestamp,notes:t.notes??null,cost:t.cost??null,duration:t.duration??null,completed_by:t.completed_by??null};this.shadowRoot?.querySelector("maintenance-history-edit-dialog")?.openEdit(e)}};k.styles=[Lt,_e],_([T({attribute:!1})],k.prototype,"hass",2),_([T({type:Boolean,reflect:!0})],k.prototype,"narrow",2),_([T({attribute:!1})],k.prototype,"panel",2),_([m()],k.prototype,"_objects",2),_([m()],k.prototype,"_stats",2),_([m()],k.prototype,"_view",2),_([m()],k.prototype,"_selectedEntryId",2),_([m()],k.prototype,"_selectedTaskId",2),_([m()],k.prototype,"_filterStatus",2),_([m()],k.prototype,"_filterUser",2),_([m()],k.prototype,"_filterLabel",2),_([m()],k.prototype,"_savedViews",2),_([m()],k.prototype,"_activeViewId",2),_([m()],k.prototype,"_unsub",2),_([m()],k.prototype,"_chartRangeDays",2),_([m()],k.prototype,"_hideOutliers",2),_([m()],k.prototype,"_historyFilter",2),_([m()],k.prototype,"_budget",2),_([m()],k.prototype,"_groups",2),_([m()],k.prototype,"_detailStatsData",2),_([m()],k.prototype,"_miniStatsData",2),_([m()],k.prototype,"_features",2),_([m()],k.prototype,"_adminPanelUserIds",2),_([m()],k.prototype,"_operatorWriteEnabled",2),_([m()],k.prototype,"_defaultWarningDays",2),_([m()],k.prototype,"_actionLoading",2),_([m()],k.prototype,"_moreMenuOpen",2),_([m()],k.prototype,"_objMenuOpen",2),_([m()],k.prototype,"_toastMessage",2),_([m()],k.prototype,"_toastUndo",2),_([m()],k.prototype,"_toastActionLabel",2),_([m()],k.prototype,"_filtersOpen",2),_([m()],k.prototype,"_actionsMenuOpen",2),_([m()],k.prototype,"_batteryFleetSetupAvailable",2),_([m()],k.prototype,"_staleBundle",2),_([m()],k.prototype,"_overviewTab",2),_([m()],k.prototype,"_activeTab",2),_([m()],k.prototype,"_costDurationToggle",2),_([m()],k.prototype,"_historySearch",2),_([m()],k.prototype,"_sortMode",2),_([m()],k.prototype,"_objectSortMode",2),_([m()],k.prototype,"_groupByMode",2),_([m()],k.prototype,"_objectViewMode",2),_([m()],k.prototype,"_objectsTableColumns",2),_([m()],k.prototype,"_showArchived",2),_([m()],k.prototype,"_bulkMode",2),_([m()],k.prototype,"_bulkSelected",2),_([m()],k.prototype,"_virtStart",2),_([m()],k.prototype,"_virtEnd",2),_([m()],k.prototype,"_collapsedSections",2),_([m()],k.prototype,"_paletteOpen",2),_([m()],k.prototype,"_paletteQuery",2),_([m()],k.prototype,"_paletteActive",2),_([m()],k.prototype,"_templateGalleryOpen",2),_([m()],k.prototype,"_templates",2),_([m()],k.prototype,"_templateCategories",2),_([m()],k.prototype,"_templateBusy",2),_([m()],k.prototype,"_fullHistory",2),k=_([ee("maintenance-supporter-panel")],k);export{k as MaintenanceSupporterPanel};
|
></maintenance-task-detail-view>`}_openHistoryEdit(t){if(!this._selectedEntryId||!this._selectedTaskId)return;let e={entry_id:this._selectedEntryId,task_id:this._selectedTaskId,original_timestamp:t.timestamp,type:t.type,timestamp:t.timestamp,notes:t.notes??null,cost:t.cost??null,duration:t.duration??null,completed_by:t.completed_by??null};this.shadowRoot?.querySelector("maintenance-history-edit-dialog")?.openEdit(e)}};k.styles=[Lt,ge],g([T({attribute:!1})],k.prototype,"hass",2),g([T({type:Boolean,reflect:!0})],k.prototype,"narrow",2),g([T({attribute:!1})],k.prototype,"panel",2),g([m()],k.prototype,"_objects",2),g([m()],k.prototype,"_stats",2),g([m()],k.prototype,"_view",2),g([m()],k.prototype,"_selectedEntryId",2),g([m()],k.prototype,"_selectedTaskId",2),g([m()],k.prototype,"_filterStatus",2),g([m()],k.prototype,"_filterUser",2),g([m()],k.prototype,"_filterLabel",2),g([m()],k.prototype,"_savedViews",2),g([m()],k.prototype,"_activeViewId",2),g([m()],k.prototype,"_unsub",2),g([m()],k.prototype,"_chartRangeDays",2),g([m()],k.prototype,"_hideOutliers",2),g([m()],k.prototype,"_historyFilter",2),g([m()],k.prototype,"_budget",2),g([m()],k.prototype,"_groups",2),g([m()],k.prototype,"_detailStatsData",2),g([m()],k.prototype,"_miniStatsData",2),g([m()],k.prototype,"_features",2),g([m()],k.prototype,"_adminPanelUserIds",2),g([m()],k.prototype,"_operatorWriteEnabled",2),g([m()],k.prototype,"_defaultWarningDays",2),g([m()],k.prototype,"_actionLoading",2),g([m()],k.prototype,"_moreMenuOpen",2),g([m()],k.prototype,"_objMenuOpen",2),g([m()],k.prototype,"_toastMessage",2),g([m()],k.prototype,"_toastUndo",2),g([m()],k.prototype,"_toastActionLabel",2),g([m()],k.prototype,"_filtersOpen",2),g([m()],k.prototype,"_newMenuOpen",2),g([m()],k.prototype,"_gsSetupsCount",2),g([m()],k.prototype,"_gsAdoptCount",2),g([m()],k.prototype,"_batteryFleetSetupAvailable",2),g([m()],k.prototype,"_staleBundle",2),g([m()],k.prototype,"_overviewTab",2),g([m()],k.prototype,"_activeTab",2),g([m()],k.prototype,"_costDurationToggle",2),g([m()],k.prototype,"_historySearch",2),g([m()],k.prototype,"_sortMode",2),g([m()],k.prototype,"_objectSortMode",2),g([m()],k.prototype,"_groupByMode",2),g([m()],k.prototype,"_objectViewMode",2),g([m()],k.prototype,"_objectsTableColumns",2),g([m()],k.prototype,"_showArchived",2),g([m()],k.prototype,"_bulkMode",2),g([m()],k.prototype,"_bulkSelected",2),g([m()],k.prototype,"_virtStart",2),g([m()],k.prototype,"_virtEnd",2),g([m()],k.prototype,"_collapsedSections",2),g([m()],k.prototype,"_paletteOpen",2),g([m()],k.prototype,"_paletteQuery",2),g([m()],k.prototype,"_paletteActive",2),g([m()],k.prototype,"_templateGalleryOpen",2),g([m()],k.prototype,"_templates",2),g([m()],k.prototype,"_templateCategories",2),g([m()],k.prototype,"_templateBusy",2),g([m()],k.prototype,"_fullHistory",2),k=g([ee("maintenance-supporter-panel")],k);export{k as MaintenanceSupporterPanel};
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
/*! maintenance_supporter frontend 2.53.0 */
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
var S="2.53.0";var l="maintenance-supporter",T=`ll-strategy-dashboard-${l}`,D="hui-maintenance-supporter-strategy-editor",C=`/maintenance_supporter_strategy/maintenance-dashboard-strategy.js?v=${S}`,m=null;function v(){return m||(m=import(C)),m}async function I(){let r=await v();if(!r.MaintenanceDashboardStrategy)throw new Error("[maintenance-supporter] strategy bundle loaded but did not export MaintenanceDashboardStrategy");return r.MaintenanceDashboardStrategy}var p=class extends HTMLElement{static getCreateSuggestions(c){return{title:"Maintenance Supporter",icon:"mdi:wrench-clock"}}static async getConfigElement(){return await v(),document.createElement(D)}static async generate(c,f){return(await I()).generate(c,f)}};function M(){try{customElements.define(T,p)}catch{}}M();var w=window;w.customStrategies=w.customStrategies||[];w.customStrategies.some(r=>r.type===l&&r.strategyType==="dashboard")||w.customStrategies.push({type:l,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentationURL:"https://github.com/iluebbe/maintenance_supporter#dashboard-strategy"});(()=>{let r=window;if(r.__msStrategyHealActive)return;r.__msStrategyHealActive=!0;let c=/^\/(auth|config|developer-tools|profile|hassio|history|logbook|map|media-browser|energy|todo|calendar)\b/,f=/Timeout waiting for strategy element ll-strategy-(dashboard-)?maintenance-supporter/i,g=`custom:${l}`;function R(a){let t=[document.documentElement],n=0;for(;t.length&&n<9e3;){let o=t.pop();if(n++,!o)continue;let e=o;if(e.nodeType===1&&e.tagName&&e.tagName.toLowerCase()===a)return e;e.shadowRoot&&t.push(e.shadowRoot);let i=o.children;if(i)for(let d of Array.from(i))t.push(d)}return null}function k(a){let t=a?.views;if(!Array.isArray(t)||!t.length)return null;let n=window.location.pathname.split("/").filter(Boolean).pop()||"",o=t.find(i=>i?.path===n);if(o)return o;let e=Number(n);return Number.isInteger(e)&&t[e]?t[e]:t[0]}function b(){try{let t=R("ha-panel-lovelace")?.lovelace;if(!t)return!1;let n=o=>o?.type;for(let o of[t.config,t.rawConfig]){if(!o)continue;if(n(o.strategy)===g)return!0;let e=k(o);if(e&&n(e.strategy)===g)return!0}return!1}catch{return!1}}function A(){let a=!1,t=0,n=!1,o=!1,e=[document.documentElement],i=0;for(;e.length&&i<9e3;){let d=e.pop();if(i++,!d)continue;let u=d;if(u.nodeType===1&&u.tagName){let s=u.tagName.toLowerCase();(s==="hui-view"||s==="hui-sections-view")&&(a=!0),(s==="ha-card"||s==="hui-card")&&t++,s==="hui-empty-state-card"&&(o=!0),s==="hui-error-card"&&f.test(u.textContent||"")&&(n=!0)}u.shadowRoot&&e.push(u.shadowRoot);let E=d.children;if(E)for(let s of Array.from(E))e.push(s)}return n?!0:o?!1:a&&t<3&&b()}let N="/maintenance_supporter_strategy_shim.js",y=0,_=0;function L(){let a=Date.now();a-_<5e3||y>=3||(_=a,y+=1,import(`${N}?heal=${a}`).catch(()=>{}).finally(()=>{let t=window.location.pathname+window.location.search;history.pushState(null,"","/lovelace"),window.dispatchEvent(new CustomEvent("location-changed")),window.setTimeout(()=>{history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed"))},200)}))}function h(){if(c.test(window.location.pathname))return;let a=0,t=Date.now(),n=window.setInterval(()=>{a++;try{if(Date.now()-t<6e3)return;if(c.test(window.location.pathname)){window.clearInterval(n);return}A()?L():window.clearInterval(n),a>=30&&window.clearInterval(n)}catch{window.clearInterval(n)}},500)}try{document.readyState==="loading"?window.addEventListener("DOMContentLoaded",h):h(),window.addEventListener("location-changed",()=>{c.test(window.location.pathname)||h()})}catch{}})();
|
var S="2.54.0";var l="maintenance-supporter",T=`ll-strategy-dashboard-${l}`,D="hui-maintenance-supporter-strategy-editor",C=`/maintenance_supporter_strategy/maintenance-dashboard-strategy.js?v=${S}`,m=null;function v(){return m||(m=import(C)),m}async function I(){let r=await v();if(!r.MaintenanceDashboardStrategy)throw new Error("[maintenance-supporter] strategy bundle loaded but did not export MaintenanceDashboardStrategy");return r.MaintenanceDashboardStrategy}var p=class extends HTMLElement{static getCreateSuggestions(c){return{title:"Maintenance Supporter",icon:"mdi:wrench-clock"}}static async getConfigElement(){return await v(),document.createElement(D)}static async generate(c,f){return(await I()).generate(c,f)}};function M(){try{customElements.define(T,p)}catch{}}M();var w=window;w.customStrategies=w.customStrategies||[];w.customStrategies.some(r=>r.type===l&&r.strategyType==="dashboard")||w.customStrategies.push({type:l,strategyType:"dashboard",name:"Maintenance Supporter",description:"Auto-generated dashboard. Group views by area, status, floor, or due date \u2014 picked from the strategy editor or YAML.",documentationURL:"https://github.com/iluebbe/maintenance_supporter#dashboard-strategy"});(()=>{let r=window;if(r.__msStrategyHealActive)return;r.__msStrategyHealActive=!0;let c=/^\/(auth|config|developer-tools|profile|hassio|history|logbook|map|media-browser|energy|todo|calendar)\b/,f=/Timeout waiting for strategy element ll-strategy-(dashboard-)?maintenance-supporter/i,g=`custom:${l}`;function R(a){let t=[document.documentElement],n=0;for(;t.length&&n<9e3;){let o=t.pop();if(n++,!o)continue;let e=o;if(e.nodeType===1&&e.tagName&&e.tagName.toLowerCase()===a)return e;e.shadowRoot&&t.push(e.shadowRoot);let i=o.children;if(i)for(let d of Array.from(i))t.push(d)}return null}function k(a){let t=a?.views;if(!Array.isArray(t)||!t.length)return null;let n=window.location.pathname.split("/").filter(Boolean).pop()||"",o=t.find(i=>i?.path===n);if(o)return o;let e=Number(n);return Number.isInteger(e)&&t[e]?t[e]:t[0]}function b(){try{let t=R("ha-panel-lovelace")?.lovelace;if(!t)return!1;let n=o=>o?.type;for(let o of[t.config,t.rawConfig]){if(!o)continue;if(n(o.strategy)===g)return!0;let e=k(o);if(e&&n(e.strategy)===g)return!0}return!1}catch{return!1}}function A(){let a=!1,t=0,n=!1,o=!1,e=[document.documentElement],i=0;for(;e.length&&i<9e3;){let d=e.pop();if(i++,!d)continue;let u=d;if(u.nodeType===1&&u.tagName){let s=u.tagName.toLowerCase();(s==="hui-view"||s==="hui-sections-view")&&(a=!0),(s==="ha-card"||s==="hui-card")&&t++,s==="hui-empty-state-card"&&(o=!0),s==="hui-error-card"&&f.test(u.textContent||"")&&(n=!0)}u.shadowRoot&&e.push(u.shadowRoot);let E=d.children;if(E)for(let s of Array.from(E))e.push(s)}return n?!0:o?!1:a&&t<3&&b()}let N="/maintenance_supporter_strategy_shim.js",y=0,_=0;function L(){let a=Date.now();a-_<5e3||y>=3||(_=a,y+=1,import(`${N}?heal=${a}`).catch(()=>{}).finally(()=>{let t=window.location.pathname+window.location.search;history.pushState(null,"","/lovelace"),window.dispatchEvent(new CustomEvent("location-changed")),window.setTimeout(()=>{history.pushState(null,"",t),window.dispatchEvent(new CustomEvent("location-changed"))},200)}))}function h(){if(c.test(window.location.pathname))return;let a=0,t=Date.now(),n=window.setInterval(()=>{a++;try{if(Date.now()-t<6e3)return;if(c.test(window.location.pathname)){window.clearInterval(n);return}A()?L():window.clearInterval(n),a>=30&&window.clearInterval(n)}catch{window.clearInterval(n)}},500)}try{document.readyState==="loading"?window.addEventListener("DOMContentLoaded",h):h(),window.addEventListener("location-changed",()=>{c.test(window.location.pathname)||h()})}catch{}})();
|
||||||
+222
@@ -0,0 +1,222 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import{a as d}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WZ6RLKNK.js";import{a as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A7WM72WE.js";import{a,b as _,c as t,f as l,g as h,i as g,j as n,n as i,p as v}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C2ERU424.js";var r=class extends h{constructor(){super(...arguments);this._open=!1;this._loading=!1;this._adopting=!1;this._error="";this._sensors=[];this._selected=new Set;this._users=[];this._responsible="";this._localeReady=!1;this._userService=null;this._toggle=s=>{let o=new Set(this._selected);o.has(s)?o.delete(s):o.add(s),this._selected=o};this._toggleAll=()=>{this._selected.size===this._sensors.length?this._selected=new Set:this._selected=new Set(this._sensors.map(s=>s.entity_id))};this._adopt=async()=>{if(!(this._selected.size===0||this._adopting)){this._adopting=!0,this._error="";try{let s=this._sensors.filter(e=>this._selected.has(e.entity_id)).map(e=>({entity_id:e.entity_id,name:e.name,entry_id:e.suggested_entry_id??void 0,object_name:e.suggested_object_name,device_id:e.device_id??void 0,part_id:e.suggested_part_id??void 0,responsible_user_id:this._responsible||void 0})),o=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/problem_sensors/adopt",selections:s});this.dispatchEvent(new CustomEvent("problem-sensors-adopted",{bubbles:!0,composed:!0,detail:o})),this._open=!1}catch(s){this._error=d(s,this._lang)}finally{this._adopting=!1}}}}get _lang(){return this.hass?.language||"en"}updated(s){s.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,v(this._lang).then(()=>this.requestUpdate()))}async open(){this._open=!0,this._loading=!0,this._error="",this._sensors=[],this._selected=new Set,this._responsible="";try{this._userService?this._userService.updateHass(this.hass):this._userService=new u(this.hass);let[s,o]=await Promise.all([this.hass.connection.sendMessagePromise({type:"maintenance_supporter/problem_sensors/discover"}),this._userService.getUsers().catch(()=>[])]);this._sensors=s.sensors||[],this._selected=new Set(this._sensors.map(e=>e.entity_id)),this._users=o}catch(s){this._error=d(s,this._lang)}finally{this._loading=!1}}_close(){this._open=!1}render(){if(!this._open)return t``;let s=this._lang,o=this._sensors.length>0&&this._selected.size===this._sensors.length;return t`
|
||||||
|
<div class="overlay" @click=${this._close}>
|
||||||
|
<div class="card" @click=${e=>e.stopPropagation()}>
|
||||||
|
<div class="title">${i("adopt_problem_title",s)}</div>
|
||||||
|
<div class="hint">${i("adopt_problem_hint",s)}</div>
|
||||||
|
${this._error?t`<div class="error">${this._error}</div>`:l}
|
||||||
|
|
||||||
|
${this._loading?t`<div class="loading">…</div>`:this._sensors.length===0?t`<div class="empty">${i("adopt_problem_none",s)}</div>`:t`
|
||||||
|
<label class="select-all">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
.checked=${o}
|
||||||
|
@change=${this._toggleAll}
|
||||||
|
/>
|
||||||
|
<span>${i("selected",s)}: ${this._selected.size} / ${this._sensors.length}</span>
|
||||||
|
</label>
|
||||||
|
<div class="list">
|
||||||
|
${this._sensors.map(e=>{let m=this._selected.has(e.entity_id),p=e.state==="on",c=[e.device_name,e.area_name].filter(Boolean).join(" \xB7 ");return t`
|
||||||
|
<label class="row">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
.checked=${m}
|
||||||
|
@change=${()=>this._toggle(e.entity_id)}
|
||||||
|
/>
|
||||||
|
<div class="row-main">
|
||||||
|
<div class="row-top">
|
||||||
|
<span class="row-name">${e.name}</span>
|
||||||
|
<span class="chip ${p?"chip-active":"chip-ok"}">
|
||||||
|
${p?i("adopt_problem_active",s):i("adopt_problem_ok",s)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
${c?t`<div class="row-sub">${c}</div>`:l}
|
||||||
|
<div class="row-target">
|
||||||
|
→ ${e.suggested_object_name}${e.suggested_entry_id?l:t` <span class="new-tag">${i("adopt_problem_new_object",s)}</span>`}
|
||||||
|
</div>
|
||||||
|
${e.suggested_part_name?t`<div class="row-part">
|
||||||
|
<ha-icon icon="mdi:package-variant-closed"></ha-icon>
|
||||||
|
${i("adopt_problem_part",s).replace("{name}",e.suggested_part_name)}
|
||||||
|
</div>`:l}
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
`})}
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
|
||||||
|
${!this._loading&&this._sensors.length>0&&this._users.length>0?t`
|
||||||
|
<label class="responsible">
|
||||||
|
<span>${i("adopt_problem_responsible",s)}</span>
|
||||||
|
<select
|
||||||
|
.value=${this._responsible}
|
||||||
|
@change=${e=>{this._responsible=e.target.value}}
|
||||||
|
>
|
||||||
|
<option value="" ?selected=${!this._responsible}>${i("no_user_assigned",s)}</option>
|
||||||
|
${this._users.map(e=>t`<option value=${e.id} ?selected=${e.id===this._responsible}>${e.name}</option>`)}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
`:l}
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<ha-button appearance="plain" @click=${this._close}>
|
||||||
|
${i("cancel",s)}
|
||||||
|
</ha-button>
|
||||||
|
<ha-button
|
||||||
|
@click=${this._adopt}
|
||||||
|
.disabled=${this._selected.size===0||this._adopting}
|
||||||
|
>
|
||||||
|
${i("adopt_problem_adopt",s)}
|
||||||
|
</ha-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`}};r.styles=_`
|
||||||
|
.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-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;
|
||||||
|
}
|
||||||
|
.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([g({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,"_users",2),a([n()],r.prototype,"_responsible",2);customElements.get("maintenance-adopt-problem-sensors-dialog")||customElements.define("maintenance-adopt-problem-sensors-dialog",r);export{r as MaintenanceAdoptProblemSensorsDialog};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
var r=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 e=Date.now();if(!s&&this.usersCache&&e-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=e,this.usersCache}catch(t){return console.error("Failed to fetch users:",t),this.usersCache||[]}}async assignUser(s,e,t){await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/assign_user",entry_id:s,task_id:e,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}getUser(s){return!s||!this.usersCache?null:this.usersCache.find(e=>e.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{r as a};
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import{a as t,b as a,c as i,f as l,g as p,i as r}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C2ERU424.js";var e=class extends p{constructor(){super(...arguments);this.label="";this.value="";this.placeholder="";this.type="text";this.required=!1;this.disabled=!1}_onInput(n){let o=n.target.value;this.value=o,this.dispatchEvent(new CustomEvent("input",{bubbles:!0,composed:!0,detail:{value:o}}))}render(){return i`
|
||||||
|
<label class="field">
|
||||||
|
${this.label?i`<span class="label">${this.label}${this.required?i`<span class="req">*</span>`:l}</span>`:l}
|
||||||
|
<input
|
||||||
|
.value=${this.value??""}
|
||||||
|
.type=${this.type}
|
||||||
|
?required=${this.required}
|
||||||
|
?disabled=${this.disabled}
|
||||||
|
placeholder=${this.placeholder}
|
||||||
|
step=${this.step??l}
|
||||||
|
min=${this.min??l}
|
||||||
|
max=${this.max??l}
|
||||||
|
pattern=${this.pattern??l}
|
||||||
|
@input=${this._onInput}
|
||||||
|
@change=${this._onInput}
|
||||||
|
/>
|
||||||
|
${this.helper?i`<span class="helper">${this.helper}</span>`:l}
|
||||||
|
</label>
|
||||||
|
`}};e.styles=a`
|
||||||
|
: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; }
|
||||||
|
.helper {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
`,t([r()],e.prototype,"label",2),t([r()],e.prototype,"value",2),t([r()],e.prototype,"placeholder",2),t([r()],e.prototype,"type",2),t([r({type:Boolean})],e.prototype,"required",2),t([r({type:Boolean})],e.prototype,"disabled",2),t([r()],e.prototype,"step",2),t([r()],e.prototype,"min",2),t([r()],e.prototype,"max",2),t([r()],e.prototype,"pattern",2),t([r()],e.prototype,"helper",2);customElements.get("ms-textfield")||customElements.define("ms-textfield",e);
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,2 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import{n as u}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C2ERU424.js";function _(e){return`${e.entry_id??""}\0${e.part_id}`}function l(e,r,s,c){let t=!!e.entry_id&&e.entry_id!==r,a=t?e.entry_id:r,o=s.find(p=>p.entry_id===a),n=(o?.parts||[]).find(p=>p.id===e.part_id)||null,d=t&&o?.object?.name||"",i=n?.name||u("shared_part_unknown",c);return{part:n,foreign:t,ownerName:d,label:d?`${i} (${d})`:i}}function f(e,r,s,c){let{part:t,label:a}=l(e,r,s,c),o=t&&t.stock!==null&&t.stock!==void 0?` (${t.stock}${t.unit?" "+t.unit:""})`:"",n=t?.storage_location?` \u2014 ${t.storage_location}`:"";return`${e.quantity}\xD7 ${a}${o}${n}`}function g(e,r,s,c){let a=(s.find(n=>n.entry_id===r)?.parts||[]).map(n=>({...n})),o=new Set(a.map(n=>_({part_id:n.id})));for(let n of e?.consumes_parts||[]){if(!n.entry_id||n.entry_id===r)continue;let d=_(n);if(o.has(d))continue;o.add(d);let{part:i,ownerName:p}=l(n,r,s,c);a.push({id:n.part_id,name:i?.name||u("shared_part_unknown",c),unit:i?.unit,stock:i?.stock??null,storage_location:i?.storage_location,entry_id:n.entry_id,owner_name:p})}return a}export{_ as a,f as b,g as c};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
var i=[{key:"name",labelKey:"name",required:!0},{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"}],s=i.map(n=>n.key),l=["name","manufacturer","model","serial_number","installation_date","warranty_expiry","area_id","task_count","actions"];function c(n){if(!Array.isArray(n))return[...l];let o=new Set,e=[];for(let a of n)typeof a=="string"&&s.includes(a)&&!o.has(a)&&(o.add(a),e.push(a));return e.length?(e.includes("name")||e.unshift("name"),e):[...l]}function u(n,o,e){let a=new Blob([n],{type:e}),r=URL.createObjectURL(a),t=document.createElement("a");t.href=r,t.download=o,t.target="_blank",t.rel="noopener",t.style.display="none",document.body.appendChild(t),t.dispatchEvent(new MouseEvent("click")),document.body.removeChild(t),setTimeout(()=>URL.revokeObjectURL(r),6e4)}function y(n,o){let e=document.createElement("a");e.href=n,e.download=o,e.target="_blank",e.rel="noopener",e.style.display="none",document.body.appendChild(e),e.dispatchEvent(new MouseEvent("click")),document.body.removeChild(e)}export{i as a,l as b,c,u as d,y as e};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
var o=["notes","cost","duration","photo","user"],t={notes:"notes_label",cost:"cost",duration:"duration",photo:"photo_label",user:"user_label"};export{o as a,t as b};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import{n as a}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C2ERU424.js";var s={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",group_name:"name",group_description:"description_optional",environmental_entity:"environmental_entity_optional",environmental_attribute:"environmental_attribute_optional",trigger_above:"trigger_above",trigger_below:"trigger_below",trigger_for_minutes:"trigger_for_minutes"};function c(r,o){let e=s[r];if(!e)return r;let t=a(e,o);return t&&t!==e?t:r}function d(r){let e=r.match(/data\['([^']+)'\]/)?.[1],t;return(t=r.match(/length of value must be at most (\d+)/))?{field:e,rule:"too_long",param:t[1]}:(t=r.match(/length of value must be at least (\d+)/))?{field:e,rule:"too_short",param:t[1]}:(t=r.match(/value must be at most (\S+)/))?{field:e,rule:"value_too_high",param:t[1]}:(t=r.match(/value must be at least (\S+)/))?{field:e,rule:"value_too_low",param:t[1]}:/required key not provided/.test(r)?{field:e,rule:"required"}:(t=r.match(/expected (\w+)/))?{field:e,rule:"wrong_type",param:t[1]}:/value must be one of/.test(r)?{field:e,rule:"invalid_choice"}:/not a valid value/.test(r)?{field:e,rule:"invalid_value"}:{field:e,rule:"unknown"}}function g(r,o,e){if(e=e??a("action_error",o),typeof r=="string")return r;if(typeof r!="object"||r===null)return e;let t=r,_=t.message||t.error?.message||"";if(!_)return e;let i=d(_),l=i.field?c(i.field,o):"",n=u=>a(u,o).replace("{field}",l).replace("{n}",i.param??"");switch(i.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}",i.param??"");case"invalid_choice":return n("err_invalid_choice");case"invalid_value":return n("err_invalid_value");default:return _||e}}export{g as a};
|
||||||
+292
@@ -0,0 +1,292 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import{b as m}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-TLH3CQAL.js";import{a as _}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-KH7UXWPC.js";import{a as g}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WZ6RLKNK.js";import{a as s,b,c as a,f as d,g as v,i as n,j as l,n as r,x as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C2ERU424.js";var i=class extends v{constructor(){super(...arguments);this.entryId="";this.taskId="";this.taskName="";this.lang="en";this.checklist=[];this.adaptiveEnabled=!1;this.taskType="";this.readingUnit="";this.restockDefault=null;this.restockUnitCost=null;this.currencySymbol="";this.parts=[];this.consumesParts=[];this.consumesInfo=[];this.requiredFields=[];this._open=!1;this._notes="";this._cost="";this._duration="";this._loading=!1;this._error="";this._checklistState={};this._feedback="needed";this._photoDocId="";this._photoPreview="";this._photoUploading=!1;this._readingValue="";this._restockQty="";this._usedParts={};this.checklistPrefill={}}open(){this._open||(this._open=!0,this._notes="",this._cost="",this._duration="",this._error="",this._checklistState=Object.fromEntries(this.checklist.map((e,t)=>[String(t),!!this.checklistPrefill[e]]).filter(([,e])=>e)),this._feedback="needed",this._photoDocId="",this._photoPreview="",this._photoUploading=!1,this._readingValue="",this._restockQty=this.restockDefault!==null?String(this.restockDefault):"",this._usedParts=Object.fromEntries(this.consumesParts.map(e=>[_(e),{...e}])))}_toggleCheck(e){let t=String(e);this._checklistState={...this._checklistState,[t]:!this._checklistState[t]}}_setFeedback(e){this._feedback=e}async _onPhotoInput(e){let t=e.target,o=t.files?.[0];if(t.value="",!!o){this._photoUploading=!0,this._error="";try{let c=new FormData;c.append("entry_id",this.entryId),c.append("tags","photo"),c.append("file",o,o.name);let p=await fetch("/api/maintenance_supporter/document/upload",{method:"POST",headers:{Authorization:`Bearer ${this.hass.auth?.data?.access_token??""}`},body:c});if(!p.ok){this._error=p.status===413?r("doc_too_large",this.lang):r("doc_upload_failed",this.lang);return}let u=await p.json();u.id&&(this._photoDocId=u.id,this._photoPreview=URL.createObjectURL(o))}catch{this._error=r("doc_upload_failed",this.lang)}finally{this._photoUploading=!1}}}_removePhoto(){this._photoPreview&&URL.revokeObjectURL(this._photoPreview),this._photoDocId="",this._photoPreview=""}async _complete(){this._loading=!0,this._error="";try{let e={type:"maintenance_supporter/task/complete",entry_id:this.entryId,task_id:this.taskId};if(this._notes&&(e.notes=this._notes),this._cost){let t=parseFloat(this._cost);!isNaN(t)&&t>=0&&(e.cost=t)}if(this._duration){let t=parseInt(this._duration,10);!isNaN(t)&&t>=0&&(e.duration=t)}if(this.checklist.length>0&&(e.checklist_state=this._checklistState),this.adaptiveEnabled&&(e.feedback=this._feedback),this._photoDocId&&(e.photo_doc_id=this._photoDocId),this._readingValue!==""){let t=parseFloat(this._readingValue);isNaN(t)||(e.reading_value=t)}if(this.restockDefault!==null&&this._restockQty!==""){let t=parseFloat(this._restockQty);!isNaN(t)&&t>=1&&(e.restock_quantity=t)}this.parts.length>0&&(e.used_parts=Object.values(this._usedParts).filter(t=>Number.isFinite(t.quantity)&&t.quantity>0).map(t=>t.entry_id?{part_id:t.part_id,quantity:t.quantity,entry_id:t.entry_id}:{part_id:t.part_id,quantity:t.quantity})),await this.hass.connection.sendMessagePromise(e),this._open=!1,this.dispatchEvent(new CustomEvent("task-completed"))}catch(e){this._error=g(e,this.lang,r("save_error",this.lang))}finally{this._loading=!1}}get _missingRequired(){let e={notes:this._notes.trim()!=="",cost:this._cost.trim()!=="",duration:this._duration.trim()!=="",photo:this._photoDocId!=="",user:!!this.hass?.user};return this.requiredFields.filter(t=>!e[t])}_req(e){return this.requiredFields.includes(e)?a`<span class="req-mark" aria-hidden="true">*</span>`:d}_partsCostSuggestion(){if(this.restockDefault!==null){let o=parseFloat(this._restockQty);return this.restockUnitCost==null||!Number.isFinite(o)||o<=0?null:Math.round(this.restockUnitCost*o*100)/100}if(!this.parts.length)return null;let e=0,t=!1;for(let o of Object.values(this._usedParts)){let c=this.parts.find(p=>_({part_id:p.id,entry_id:p.entry_id})===_(o));c?.cost!=null&&(e+=c.cost*(o.quantity||1),t=!0)}return t?Math.round(e*100)/100:null}_renderCostSuggestion(e){if(this._cost.trim()!=="")return d;let t=this._partsCostSuggestion();if(t==null||t<=0)return d;let o=`${t.toFixed(2)}${this.currencySymbol?` ${this.currencySymbol}`:""}`;return a`<button
|
||||||
|
type="button"
|
||||||
|
class="cost-suggestion"
|
||||||
|
@click=${()=>this._cost=t.toFixed(2)}
|
||||||
|
>${r("cost_from_parts",e).replace("{amount}",o)}</button>`}_close(){this._open=!1}render(){if(!this._open)return a``;let e=this.lang||this.hass?.language||"en";return a`
|
||||||
|
<ha-dialog open @closed=${this._close}>
|
||||||
|
<div class="dialog-title">${r("complete_title",e)}${this.taskName}</div>
|
||||||
|
<div class="content">
|
||||||
|
${this._error?a`<div class="error">${this._error}</div>`:d}
|
||||||
|
${this.checklist.length>0?a`
|
||||||
|
<div class="checklist-section">
|
||||||
|
<label class="checklist-label">${r("checklist",e)}</label>
|
||||||
|
${this.checklist.map((t,o)=>a`
|
||||||
|
<label class="checklist-item" @click=${()=>this._toggleCheck(o)}>
|
||||||
|
<input type="checkbox" .checked=${!!this._checklistState[String(o)]} />
|
||||||
|
<span>${t}</span>
|
||||||
|
</label>
|
||||||
|
`)}
|
||||||
|
</div>
|
||||||
|
`:d}
|
||||||
|
${this.taskType==="reading"?a`
|
||||||
|
<label class="field">
|
||||||
|
<span class="field-label">${r("reading_value_label",e)}${this.readingUnit?` (${this.readingUnit})`:""}</span>
|
||||||
|
<input type="number" step="any" class="field-input"
|
||||||
|
.value=${this._readingValue}
|
||||||
|
@input=${t=>this._readingValue=t.target.value} />
|
||||||
|
</label>`:d}
|
||||||
|
${this.parts.length?a`<div class="used-parts">
|
||||||
|
<span class="field-label">${r("complete_parts_used",e)}</span>
|
||||||
|
${this.parts.map(t=>{let o=_({part_id:t.id,entry_id:t.entry_id}),c=this._usedParts[o],p=c!==void 0,u=t.entry_id?{part_id:t.id,quantity:1,entry_id:t.entry_id}:{part_id:t.id,quantity:1};return a`<div class="used-part-row">
|
||||||
|
<label class="used-part-check">
|
||||||
|
<input type="checkbox" .checked=${p}
|
||||||
|
@change=${f=>{let h={...this._usedParts};f.target.checked?h[o]=h[o]||u:delete h[o],this._usedParts=h}} />
|
||||||
|
<span
|
||||||
|
>${t.name}${t.owner_name?a`<span class="used-part-owner"> (${t.owner_name})</span>`:d}${t.stock!==null&&t.stock!==void 0?` (${t.stock}${t.unit?" "+t.unit:""})`:""}</span
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
${p?a`<input class="used-part-qty" type="number" min="0.01" max="999" step="0.01"
|
||||||
|
.value=${String(c.quantity)}
|
||||||
|
@input=${f=>{let h=parseFloat(f.target.value);this._usedParts={...this._usedParts,[o]:{...u,quantity:Number.isFinite(h)&&h>=.01?h:1}}}} />`:d}
|
||||||
|
</div>`})}
|
||||||
|
</div>`:this.consumesInfo.length?a`<div class="consumes-hint">
|
||||||
|
${this.consumesInfo.map(t=>a`<div>${t}</div>`)}
|
||||||
|
</div>`:d}
|
||||||
|
${this.restockDefault!==null?a`
|
||||||
|
<label class="field">
|
||||||
|
<span class="field-label">${r("restock_quantity_label",e)}</span>
|
||||||
|
<input type="number" step="0.01" min="0.01" class="field-input"
|
||||||
|
.value=${this._restockQty}
|
||||||
|
@input=${t=>this._restockQty=t.target.value} />
|
||||||
|
</label>`:d}
|
||||||
|
<!-- Native <input>s rather than <ha-textfield>: when this dialog
|
||||||
|
is opened from a Lovelace card via dialog-mount, ha-textfield
|
||||||
|
isn't yet registered (HA loads it lazily when its own panels
|
||||||
|
need it) so the elements render with zero height and the user
|
||||||
|
only sees the title + Cancel/Complete buttons — the original
|
||||||
|
bug report. Native inputs always render. -->
|
||||||
|
<label class="field">
|
||||||
|
<span class="field-label">${r("notes_optional",e)}${this._req("notes")}</span>
|
||||||
|
<input type="text" class="field-input"
|
||||||
|
.value=${this._notes}
|
||||||
|
@input=${t=>this._notes=t.target.value} />
|
||||||
|
</label>
|
||||||
|
<label class="field">
|
||||||
|
<span class="field-label">${r("cost_optional",e)}${this._req("cost")}</span>
|
||||||
|
<input type="number" step="0.01" min="0" class="field-input"
|
||||||
|
.value=${this._cost}
|
||||||
|
@input=${t=>this._cost=t.target.value} />
|
||||||
|
${this._renderCostSuggestion(e)}
|
||||||
|
</label>
|
||||||
|
<label class="field">
|
||||||
|
<span class="field-label">${r("duration_minutes",e)}${this._req("duration")}</span>
|
||||||
|
<input type="number" step="0.01" min="0" class="field-input"
|
||||||
|
.value=${this._duration}
|
||||||
|
@input=${t=>this._duration=t.target.value} />
|
||||||
|
</label>
|
||||||
|
<div class="field">
|
||||||
|
<span class="field-label">${r("completion_photo_optional",e)}${this._req("photo")}</span>
|
||||||
|
${this._photoPreview?a`
|
||||||
|
<div class="photo-preview">
|
||||||
|
<img src=${this._photoPreview} alt="" />
|
||||||
|
<button type="button" class="photo-remove" @click=${this._removePhoto}
|
||||||
|
title="${r("remove",e)}">✕</button>
|
||||||
|
</div>`:a`
|
||||||
|
<label class="photo-pick">
|
||||||
|
<ha-icon icon="mdi:camera"></ha-icon>
|
||||||
|
<span>${this._photoUploading?r("uploading",e):r("add_photo",e)}</span>
|
||||||
|
<input type="file" accept="image/*" capture="environment"
|
||||||
|
?disabled=${this._photoUploading}
|
||||||
|
@change=${this._onPhotoInput} />
|
||||||
|
</label>`}
|
||||||
|
</div>
|
||||||
|
${this.adaptiveEnabled?a`
|
||||||
|
<div class="feedback-section">
|
||||||
|
<label class="feedback-label">${r("was_maintenance_needed",e)}</label>
|
||||||
|
<div class="feedback-buttons">
|
||||||
|
<button
|
||||||
|
class="feedback-btn ${this._feedback==="needed"?"selected":""}"
|
||||||
|
@click=${()=>this._setFeedback("needed")}
|
||||||
|
>${r("feedback_needed",e)}</button>
|
||||||
|
<button
|
||||||
|
class="feedback-btn ${this._feedback==="not_needed"?"selected":""}"
|
||||||
|
@click=${()=>this._setFeedback("not_needed")}
|
||||||
|
>${r("feedback_not_needed",e)}</button>
|
||||||
|
<button
|
||||||
|
class="feedback-btn ${this._feedback==="not_sure"?"selected":""}"
|
||||||
|
@click=${()=>this._setFeedback("not_sure")}
|
||||||
|
>${r("feedback_not_sure",e)}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`:d}
|
||||||
|
</div>
|
||||||
|
<div class="dialog-actions">
|
||||||
|
<ha-button appearance="plain" @click=${this._close}>
|
||||||
|
${r("cancel",e)}
|
||||||
|
</ha-button>
|
||||||
|
<ha-button
|
||||||
|
@click=${this._complete}
|
||||||
|
.disabled=${this._loading||this._missingRequired.length>0}
|
||||||
|
title=${this._missingRequired.length?this._missingRequired.map(t=>r("err_required",e).replace("{field}",r(m[t]??t,e))).join(" \xB7 "):""}
|
||||||
|
>
|
||||||
|
${this._loading?r("completing",e):r("complete",e)}
|
||||||
|
</ha-button>
|
||||||
|
</div>
|
||||||
|
</ha-dialog>
|
||||||
|
`}};i.styles=[k,b`
|
||||||
|
.req-mark {
|
||||||
|
color: var(--error-color, #f44336);
|
||||||
|
margin-left: 2px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
/* #104: one-click cost suggestion from parts — quiet link-style chip. */
|
||||||
|
.cost-suggestion {
|
||||||
|
align-self: flex-start;
|
||||||
|
margin-top: 4px;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
color: var(--primary-color);
|
||||||
|
font-size: 12.5px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
}
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
.consumes-hint {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
border-left: 3px solid var(--primary-color);
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: 4px 0 8px;
|
||||||
|
}
|
||||||
|
/* #99: editable per-completion parts selection */
|
||||||
|
.used-parts { margin: 4px 0 8px; display: flex; flex-direction: column; gap: 4px; }
|
||||||
|
.used-part-row { display: flex; align-items: center; gap: 8px; }
|
||||||
|
.used-part-check {
|
||||||
|
display: flex; align-items: center; gap: 6px; flex: 1;
|
||||||
|
font-size: 13px; cursor: pointer;
|
||||||
|
}
|
||||||
|
.used-part-check input { cursor: pointer; }
|
||||||
|
/* #111: whose stock this row draws on. Muted but never omitted — an
|
||||||
|
unlabelled foreign pool is indistinguishable from an own part. */
|
||||||
|
.used-part-owner { color: var(--secondary-text-color); }
|
||||||
|
.used-part-qty {
|
||||||
|
width: 76px; padding: 4px 6px; border-radius: 4px; font: inherit; font-size: 13px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
background: var(--card-background-color);
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: var(--error-color, #f44336);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
/* .field/.field-label/.field-input come from nativeFieldStyles */
|
||||||
|
.photo-pick {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px dashed var(--divider-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
.photo-pick:hover { border-color: var(--primary-color); }
|
||||||
|
.photo-pick input[type="file"] { display: none; }
|
||||||
|
.photo-preview {
|
||||||
|
position: relative;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
.photo-preview img {
|
||||||
|
max-width: 160px;
|
||||||
|
max-height: 160px;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.photo-remove {
|
||||||
|
position: absolute;
|
||||||
|
top: -8px;
|
||||||
|
right: -8px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: none;
|
||||||
|
background: var(--error-color, #db4437);
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.checklist-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid var(--divider-color);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.checklist-label {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
.checklist-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.checklist-item input[type="checkbox"] {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.feedback-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 0;
|
||||||
|
border-top: 1px solid var(--divider-color);
|
||||||
|
}
|
||||||
|
.feedback-label {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
.feedback-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.feedback-btn {
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--card-background-color, #fff);
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.feedback-btn:hover {
|
||||||
|
background: var(--secondary-background-color, #f5f5f5);
|
||||||
|
}
|
||||||
|
.feedback-btn.selected {
|
||||||
|
background: var(--primary-color);
|
||||||
|
color: var(--text-primary-color, #fff);
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
`],s([n({attribute:!1})],i.prototype,"hass",2),s([n()],i.prototype,"entryId",2),s([n()],i.prototype,"taskId",2),s([n()],i.prototype,"taskName",2),s([n()],i.prototype,"lang",2),s([n({type:Array})],i.prototype,"checklist",2),s([n({type:Boolean})],i.prototype,"adaptiveEnabled",2),s([n()],i.prototype,"taskType",2),s([n()],i.prototype,"readingUnit",2),s([n({attribute:!1})],i.prototype,"restockDefault",2),s([n({attribute:!1})],i.prototype,"restockUnitCost",2),s([n()],i.prototype,"currencySymbol",2),s([n({attribute:!1})],i.prototype,"parts",2),s([n({attribute:!1})],i.prototype,"consumesParts",2),s([n({type:Array})],i.prototype,"consumesInfo",2),s([n({type:Array})],i.prototype,"requiredFields",2),s([l()],i.prototype,"_open",2),s([l()],i.prototype,"_notes",2),s([l()],i.prototype,"_cost",2),s([l()],i.prototype,"_duration",2),s([l()],i.prototype,"_loading",2),s([l()],i.prototype,"_error",2),s([l()],i.prototype,"_checklistState",2),s([l()],i.prototype,"_feedback",2),s([l()],i.prototype,"_photoDocId",2),s([l()],i.prototype,"_photoPreview",2),s([l()],i.prototype,"_photoUploading",2),s([l()],i.prototype,"_readingValue",2),s([l()],i.prototype,"_restockQty",2),s([l()],i.prototype,"_usedParts",2),s([n({attribute:!1})],i.prototype,"checklistPrefill",2);customElements.get("maintenance-complete-dialog")||customElements.define("maintenance-complete-dialog",i);export{i as MaintenanceCompleteDialog};
|
||||||
+143
@@ -0,0 +1,143 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import"/maintenance_supporter_panelfiles/panel-chunks/chunk-AEF5ZY4E.js";import{a as h}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WZ6RLKNK.js";import{a as r,b as _,c as l,f as o,g as p,i as d,j as s,n as i}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C2ERU424.js";var e=class extends p{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 this.hass?.language??navigator.language.split("-")[0]??"en"}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(a,n){this._entryId=a,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(a){this._error=h(a,this._lang,i("save_error",this._lang))}finally{this._loading=!1}}}_parentChoices(){return(this.objects||[]).filter(a=>a.entry_id!==this._entryId)}_close(){this._open=!1}render(){if(!this._open)return l``;let a=this._lang,n=this._entryId?i("edit_object",a):i("new_object",a);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",a)}"
|
||||||
|
required
|
||||||
|
.value=${this._name}
|
||||||
|
@input=${t=>this._name=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${i("manufacturer_optional",a)}"
|
||||||
|
.value=${this._manufacturer}
|
||||||
|
@input=${t=>this._manufacturer=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${i("model_optional",a)}"
|
||||||
|
.value=${this._model}
|
||||||
|
@input=${t=>this._model=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${i("serial_number_optional",a)}"
|
||||||
|
.value=${this._serialNumber}
|
||||||
|
@input=${t=>this._serialNumber=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${i("documentation_url_optional",a)}"
|
||||||
|
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",a)}"
|
||||||
|
.value=${this._areaId}
|
||||||
|
@value-changed=${t=>this._areaId=t.detail.value||""}
|
||||||
|
></ha-area-picker>
|
||||||
|
<ms-textfield
|
||||||
|
label="${i("installation_date_optional",a)}"
|
||||||
|
type="date"
|
||||||
|
.value=${this._installationDate}
|
||||||
|
@input=${t=>this._installationDate=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${i("warranty_expiry_optional",a)}"
|
||||||
|
type="date"
|
||||||
|
.value=${this._warrantyExpiry}
|
||||||
|
@input=${t=>this._warrantyExpiry=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ha-form
|
||||||
|
.hass=${this.hass}
|
||||||
|
.data=${{device:this._haDeviceId||void 0}}
|
||||||
|
.schema=${[{name:"device",selector:{device:{}}}]}
|
||||||
|
.computeLabel=${()=>i("link_device_optional",a)}
|
||||||
|
@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",a)}</span>
|
||||||
|
<select
|
||||||
|
class="parent-select"
|
||||||
|
.value=${this._parentEntryId}
|
||||||
|
@change=${t=>this._parentEntryId=t.target.value}
|
||||||
|
>
|
||||||
|
<option value="" ?selected=${!this._parentEntryId}>
|
||||||
|
${i("parent_none",a)}
|
||||||
|
</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",a)}</span>
|
||||||
|
<textarea
|
||||||
|
rows="3"
|
||||||
|
.value=${this._notes}
|
||||||
|
@input=${t=>this._notes=t.target.value}
|
||||||
|
></textarea>
|
||||||
|
</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>
|
||||||
|
`}};e.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);
|
||||||
|
}
|
||||||
|
.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})],e.prototype,"hass",2),r([d({attribute:!1})],e.prototype,"objects",2),r([s()],e.prototype,"_open",2),r([s()],e.prototype,"_loading",2),r([s()],e.prototype,"_error",2),r([s()],e.prototype,"_name",2),r([s()],e.prototype,"_manufacturer",2),r([s()],e.prototype,"_model",2),r([s()],e.prototype,"_serialNumber",2),r([s()],e.prototype,"_areaId",2),r([s()],e.prototype,"_installationDate",2),r([s()],e.prototype,"_warrantyExpiry",2),r([s()],e.prototype,"_documentationUrl",2),r([s()],e.prototype,"_notes",2),r([s()],e.prototype,"_haDeviceId",2),r([s()],e.prototype,"_parentEntryId",2),r([s()],e.prototype,"_entryId",2);customElements.get("maintenance-object-dialog")||customElements.define("maintenance-object-dialog",e);export{e as MaintenanceObjectDialog};
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import{a,b as v,c as n,f as g,g as b,i as m,j as c,n as t}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C2ERU424.js";function p(l){return l.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function x(l){return!l.startsWith("data:image/svg+xml,")&&!l.startsWith("data:image/png;base64,")?"":p(l)}function $(l){return l.replace(/[/\\:*?"<>|#%]+/g,"").replace(/\s+/g,"-").toLowerCase().substring(0,100)}var r=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,o,s){this._entryId=e,this._taskId=i,this._objectName=o,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 o=[this.hass.connection.sendMessagePromise({...i,action:"view"})];this._taskId&&o.push(this.hass.connection.sendMessagePromise({...i,action:"complete"}));let s=await Promise.all(o);if(e!==this._generateSeq)return;this._viewResult=s[0],s.length>1&&(this._completeResult=s[1])}catch(i){if(e!==this._generateSeq)return;let o=i?.code,s=i?.message;this._error=o==="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,o=[e.label.manufacturer,e.label.model].filter(Boolean).join(" "),s=window.open("","_blank","width=600,height=500");if(!s)return;let h=this.lang||"en",d=p(i),u=p(o),_=!!this._completeResult,f=p(t("qr_action_view",h)),w=p(t("qr_action_complete",h));s.document.write(`<!DOCTYPE html><html><head><meta charset="utf-8">
|
||||||
|
<meta name="color-scheme" content="light">
|
||||||
|
<title>${d}</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>${d}</h2>
|
||||||
|
${u?`<div class="sub">${u}</div>`:""}
|
||||||
|
<div class="qr-row">
|
||||||
|
<div class="qr-col">
|
||||||
|
<img src="${x(this._viewResult.svg_data_uri)}" alt="QR Info" />
|
||||||
|
<div class="qr-label">${f}</div>
|
||||||
|
</div>
|
||||||
|
${_?`<div class="qr-col">
|
||||||
|
<img src="${x(this._completeResult.svg_data_uri)}" alt="QR Complete" />
|
||||||
|
<div class="qr-label">${w}</div>
|
||||||
|
</div>`:""}
|
||||||
|
</div>
|
||||||
|
<div class="url">${p(this._viewResult.url)}</div>
|
||||||
|
<script>setTimeout(()=>window.print(),300)<\/script>
|
||||||
|
</body></html>`),s.document.close()}_downloadSvg(e,i){let o=decodeURIComponent(e.svg_data_uri.replace("data:image/svg+xml,","")),s=new Blob([o],{type:"image/svg+xml"}),h=URL.createObjectURL(s),d=document.createElement("a");d.href=h;let u=this._taskName?`${this._objectName}-${this._taskName}`:this._objectName;d.download=`qr-${$(u)}-${i}.svg`,d.click(),URL.revokeObjectURL(h)}_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}`,o=!!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>`:o?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>
|
||||||
|
`:g}
|
||||||
|
</div>
|
||||||
|
<div class="url-display">${this._viewResult.url}</div>
|
||||||
|
`:g}
|
||||||
|
<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=${!o}
|
||||||
|
>
|
||||||
|
${t("qr_print",e)}
|
||||||
|
</ha-button>
|
||||||
|
</div>
|
||||||
|
</ha-dialog>
|
||||||
|
`}};r.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([m({attribute:!1})],r.prototype,"hass",2),a([m()],r.prototype,"lang",2),a([c()],r.prototype,"_open",2),a([c()],r.prototype,"_loading",2),a([c()],r.prototype,"_error",2),a([c()],r.prototype,"_viewResult",2),a([c()],r.prototype,"_completeResult",2),a([c()],r.prototype,"_urlMode",2);customElements.get("maintenance-qr-dialog")||customElements.define("maintenance-qr-dialog",r);export{r as MaintenanceQrDialog};
|
||||||
+1141
File diff suppressed because it is too large.
Load diff
+146
@@ -0,0 +1,146 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import{a as g}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WZ6RLKNK.js";import{a as l,b as m,c as i,f as h,g as v,i as u,j as d,n as p,p as f}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C2ERU424.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 this.hass?.language||"en"}updated(t){t.has("hass")&&this.hass&&!this._localeReady&&(this._localeReady=!0,f(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};
|
||||||
+983
@@ -0,0 +1,983 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import"/maintenance_supporter_panelfiles/panel-chunks/chunk-AEF5ZY4E.js";import{a as A,b as L}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-TLH3CQAL.js";import{a as x}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-KH7UXWPC.js";import{a as C}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-WZ6RLKNK.js";import{a as k}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-A7WM72WE.js";import{a,b as T,c as l,f as u,g as I,i as b,j as o,n as s,r as S,u as $}from"/maintenance_supporter_panelfiles/panel-chunks/chunk-C2ERU424.js";var P=["cleaning","inspection","replacement","calibration","service","reading","custom"],N=["low","normal","high"],F=["time_based","weekdays","nth_weekday","day_of_month","sensor_based","one_time","manual"],E=["weekdays","nth_weekday","day_of_month"],H=["threshold","counter","state_change","runtime"],R=[...H,"compound"];function q(){return{entityIds:"",type:"threshold",above:"",below:"",forMinutes:"0",targetValue:"",deltaMode:!1,fromState:"",toState:"",targetChanges:"",runtimeHours:"",onStates:"",carry:{}}}var O=new Set(["entity_id","entity_ids","type","trigger_above","trigger_below","trigger_for_minutes","trigger_target_value","trigger_delta_mode","trigger_from_state","trigger_to_state","trigger_target_changes","trigger_runtime_hours","trigger_on_states"]);function U(p){return{entityIds:(p.entity_ids||(p.entity_id?[p.entity_id]:[])).join(", "),type:p.type||"threshold",above:p.trigger_above?.toString()??"",below:p.trigger_below?.toString()??"",forMinutes:p.trigger_for_minutes?.toString()??"0",targetValue:p.trigger_target_value?.toString()??"",deltaMode:p.trigger_delta_mode||!1,fromState:p.trigger_from_state||"",toState:p.trigger_to_state||"",targetChanges:p.trigger_target_changes?.toString()??"",runtimeHours:p.trigger_runtime_hours?.toString()??"",onStates:(p.trigger_on_states||[]).join(", "),carry:Object.fromEntries(Object.entries(p).filter(([e])=>!O.has(e)&&!e.startsWith("_")))}}function M(p){let y=p.entityIds.split(",").map(i=>i.trim()).filter(Boolean);if(y.length===0)return null;let e={...p.carry||{},entity_id:y[0],entity_ids:y,type:p.type};if(p.type==="threshold"){let i=parseFloat(p.above);isNaN(i)||(e.trigger_above=i);let t=parseFloat(p.below);isNaN(t)||(e.trigger_below=t);let r=parseInt(p.forMinutes,10);isNaN(r)||(e.trigger_for_minutes=r)}else if(p.type==="counter"){let i=parseFloat(p.targetValue);isNaN(i)||(e.trigger_target_value=i),e.trigger_delta_mode=p.deltaMode}else if(p.type==="state_change"){p.fromState&&(e.trigger_from_state=p.fromState),p.toState&&(e.trigger_to_state=p.toState);let i=parseInt(p.targetChanges,10);isNaN(i)||(e.trigger_target_changes=i)}else if(p.type==="runtime"){let i=parseFloat(p.runtimeHours);isNaN(i)||(e.trigger_runtime_hours=i);let t=(p.onStates||"").split(",").map(r=>r.trim()).filter(Boolean);t.length>0&&(e.trigger_on_states=t)}return e}function j(p){return Array.from({length:7},(y,e)=>$(e,p,"short"))}function B(p){let y=new Intl.DateTimeFormat(p||"en",{month:"short"});return Array.from({length:12},(e,i)=>y.format(new Date(2021,i,1)))}var n=class n extends I{constructor(){super(...arguments);this.checklistsEnabled=!1;this.scheduleTimeEnabled=!1;this.completionActionsEnabled=!1;this.defaultWarningDays=7;this.parts=[];this._foreignOwners=[];this._open=!1;this._loading=!1;this._error="";this._entryId="";this._taskId=null;this._objectChoices=[];this._name="";this._type="custom";this._scheduleType="time_based";this._intervalDays="30";this._intervalUnit="days";this._dueDate="";this._warningDays="7";this._earliestCompletionDays="";this._intervalAnchor="completion";this._weekdays=[];this._nth="1";this._nthWeekday="5";this._domDay="1";this._domLastDay=!1;this._domBusiness=!1;this._calOffset="0";this._seasonMonths=[];this._endsMode="never";this._endsCount="";this._endsUntil="";this._schedulePreview=[];this._schedulePreviewEnded=!1;this._previewSeq=0;this._notes="";this._documentationUrl="";this._customIcon="";this._priority="normal";this._labels="";this._enabled=!0;this._triggerEntityId="";this._triggerEntityIds=[];this._triggerEntityLogic="any";this._triggerAttribute="";this._triggerType="threshold";this._triggerAbove="";this._triggerBelow="";this._triggerForMinutes="0";this._triggerTargetValue="";this._triggerDeltaMode=!1;this._triggerBaselineValue="";this._liveBaselineValue=null;this._autoCompleteOnRecovery=!1;this._triggerFromState="";this._triggerToState="";this._triggerTargetChanges="";this._triggerRuntimeHours="";this._triggerOnStates="";this._compoundLogic="AND";this._compoundConditions=[];this._suggestedAttributes=[];this._availableAttributes=[];this._entityDomain="";this._lastPerformed="";this._nfcTagId="";this._readingUnit="";this._consumesParts={};this._partsLoadFailed=!1;this._availableTags=[];this._responsibleUserId=null;this._assigneePool=[];this._rotationStrategy="";this._availableUsers=[];this._checklistText="";this._requiredCompletion=[];this._scheduleTime="";this._actionService="";this._actionTargetEntity="";Line truncated
|
||||||
|
`),this._requiredCompletion=[...i.required_completion_fields||[]],this._scheduleTime=i.schedule_time||"";let _=i.on_complete_action;if(_&&_.service){this._actionService=_.service;let d=_.target?.entity_id;this._actionTargetEntity=Array.isArray(d)?d[0]||"":d||"",this._actionData=_.data&&typeof _.data=="object"?{..._.data}:{},this._actionDataJsonFallback=""}else this._actionService="",this._actionTargetEntity="",this._actionData={},this._actionDataJsonFallback="";let c=i.quick_complete_defaults;this._qcNotes=c?.notes||"",this._qcCost=c?.cost!=null?String(c.cost):"",this._qcDuration=c?.duration!=null?String(c.duration):"",this._qcFeedback=c?.feedback||"";let h=i.adaptive_config||{};if(this._environmentalEntity=h.environmental_entity||"",this._environmentalAttribute=h.environmental_attribute||"",this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute,i.trigger_config){let d=i.trigger_config;this._triggerEntityId=d.entity_id||d.entity_ids&&d.entity_ids[0]||"",this._triggerEntityIds=d.entity_ids||(d.entity_id?[d.entity_id]:[]),this._triggerEntityLogic=d.entity_logic||"any",this._triggerAttribute=d.attribute||"",this._triggerType=d.type||"threshold",this._triggerAbove=d.trigger_above?.toString()||"",this._triggerBelow=d.trigger_below?.toString()||"",this._triggerForMinutes=d.trigger_for_minutes?.toString()||"0",this._triggerTargetValue=d.trigger_target_value?.toString()||"",this._triggerDeltaMode=d.trigger_delta_mode||!1,this._triggerBaselineValue=d.trigger_baseline_value?.toString()||"",this._liveBaselineValue=i.trigger_baseline_value??null,this._autoCompleteOnRecovery=d.auto_complete_on_recovery||!1,this._triggerFromState=d.trigger_from_state||"",this._triggerToState=d.trigger_to_state||"",this._triggerTargetChanges=d.trigger_target_changes?.toString()||"",this._triggerRuntimeHours=d.trigger_runtime_hours?.toString()||"",this._triggerOnStates=(d.trigger_on_states||[]).join(", "),d.type==="compound"?(this._compoundLogic=d.compound_logic==="OR"?"OR":"AND",this._compoundConditions=(d.conditions||[]).map(U)):(this._compoundLogic="AND",this._compoundConditions=[])}else this._resetTriggerFields();this._triggerEntityId&&this._fetchEntityAttributes(this._triggerEntityId),await Promise.all([this._loadUsers(),this._loadTags(),this._loadParts(),this._loadForeignPools()]),this._open=!0}_resetFields(){this._name="",this._type="custom",this._scheduleType="time_based",this._intervalDays="30",this._intervalUnit="days",this._dueDate="",this._warningDays=String(this.defaultWarningDays),this._earliestCompletionDays="",this._intervalAnchor="completion",this._weekdays=[],this._nth="1",this._nthWeekday="5",this._domDay="1",this._domLastDay=!1,this._domBusiness=!1,this._calOffset="0",this._seasonMonths=[],this._endsMode="never",this._endsCount="",this._endsUntil="",this._notes="",this._documentationUrl="",this._customIcon="",this._priority="normal",this._labels="",this._enabled=!0,this._lastPerformed="",this._nfcTagId="",this._readingUnit="",this._consumesParts={},this._responsibleUserId=null,this._assigneePool=[],this._rotationStrategy="",this._checklistText="",this._requiredCompletion=[],this._scheduleTime="",this._environmentalEntity="",this._environmentalAttribute="",this._environmentalInitial="",this._environmentalAttributeInitial="",this._actionService="",this._actionTargetEntity="",this._actionData={},this._actionDataJsonFallback="",this._actionTesting=!1,this._actionTestResult="",this._qcNotes="",this._qcCost="",this._qcDuration="",this._qcFeedback="",this._resetTriggerFields()}_resetTriggerFields(){this._triggerEntityId="",this._triggerEntityIds=[],this._triggerEntityLogic="any",this._triggerAttribute="",this._suggestedAttributes=[],this._availableAttributes=[],this._entityDomain="",this._triggerType="threshold",this._triggerAbove="",this._triggerBelow="",this._triggerForMinutes="0",this._triggerTargetValue="",this._triggerDeltaMode=!1,this._triggerBaselineValue="",this._liveBaselineValue=null,this._autoCompleteOnRecovery=!1,this._triggerFromState="",this._triggerToState="",this._triggerTargetChanges="",this._triggerRuntimeHours="",this._triggerOnStates="",this._compoundLogic="AND",this._compoundConditions=[]}async _loadUsers(){this._userService||(this._userService=new k(this.hass));try{this._availableUsers=await this._userService.getUsers()}catch(e){console.error("Failed to load users:",e),this._availableUsers=[]}}_toggleAssignee(e){this._assigneePool=this._assigneePool.includes(e)?this._assigneePool.filter(i=>i!==e):[...this._assigneePool,e]}async _testAction(){let e=this._actionService.trim();if(!e||!/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(e)){this._actionTestResult="error",this._actionTestError="Invalid service format (expected 'domain.service')",setTimeout(()=>{this._actionTestResult="",this._actionTestError=""},5e3);return}let[i,t]=e.split(".");if(!this.hass?.services?.[i]?.[t]){this._actionTestResult="error",this._actionTestError=`Service "${e}" is not registeLine truncated
|
||||||
|
<details class="ca-section">
|
||||||
|
<summary>${s("on_complete_action_title",e)}</summary>
|
||||||
|
<p class="field-help">${s("on_complete_action_desc",e)}</p>
|
||||||
|
<ha-service-picker
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this._actionService}
|
||||||
|
@value-changed=${t=>{this._actionService=t.detail.value||"";let r=this._serviceSchema();if(r){let _=new Set(r.map(c=>c.name));this._actionData=Object.fromEntries(Object.entries(this._actionData).filter(([c])=>_.has(c)))}}}
|
||||||
|
></ha-service-picker>
|
||||||
|
<ha-form
|
||||||
|
.hass=${this.hass}
|
||||||
|
.schema=${[{name:"target_entity",selector:{entity:{}}}]}
|
||||||
|
.data=${{target_entity:this._actionTargetEntity}}
|
||||||
|
.computeLabel=${()=>s("on_complete_action_target",e)}
|
||||||
|
@value-changed=${t=>{let r=t.detail.value;this._actionTargetEntity=r.target_entity||""}}
|
||||||
|
></ha-form>
|
||||||
|
<p class="field-help ca-domain-hint">
|
||||||
|
${s("on_complete_action_target_hint",e)}
|
||||||
|
</p>
|
||||||
|
${i?l`
|
||||||
|
<ha-form
|
||||||
|
class="ca-data-form"
|
||||||
|
.hass=${this.hass}
|
||||||
|
.schema=${i}
|
||||||
|
.data=${this._actionData}
|
||||||
|
@value-changed=${t=>{this._actionData={...t.detail.value}}}
|
||||||
|
></ha-form>
|
||||||
|
`:l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("on_complete_action_data",e)}"
|
||||||
|
placeholder="{}"
|
||||||
|
.value=${this._actionDataJsonFallback}
|
||||||
|
@input=${t=>{this._actionDataJsonFallback=t.target.value}}
|
||||||
|
></ms-textfield>
|
||||||
|
`}
|
||||||
|
<div class="ca-test-row">
|
||||||
|
<button type="button" ?disabled=${this._actionTesting||!this._actionService}
|
||||||
|
@click=${this._testAction}>
|
||||||
|
${this._actionTesting?"\u2026":s("on_complete_action_test",e)}
|
||||||
|
</button>
|
||||||
|
${this._actionTestResult==="ok"?l`<span class="ca-test-ok">${s("on_complete_action_test_success",e)}</span>`:u}
|
||||||
|
${this._actionTestResult==="error"?l`<div class="ca-test-error-block">
|
||||||
|
<span class="ca-test-error">${s("on_complete_action_test_failed",e)}</span>
|
||||||
|
${this._actionTestError?l`<div class="ca-test-error-detail">${this._actionTestError}</div>`:u}
|
||||||
|
</div>`:u}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details class="ca-section">
|
||||||
|
<summary>${s("quick_complete_defaults_title",e)}</summary>
|
||||||
|
<p class="field-help">${s("quick_complete_defaults_desc",e)}</p>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("quick_complete_defaults_notes",e)}"
|
||||||
|
.value=${this._qcNotes}
|
||||||
|
@input=${t=>{this._qcNotes=t.target.value}}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("quick_complete_defaults_cost",e)}"
|
||||||
|
type="number" min="0" step="0.01"
|
||||||
|
.value=${this._qcCost}
|
||||||
|
@input=${t=>{this._qcCost=t.target.value}}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("quick_complete_defaults_duration",e)}"
|
||||||
|
type="number" min="0" step="1"
|
||||||
|
.value=${this._qcDuration}
|
||||||
|
@input=${t=>{this._qcDuration=t.target.value}}
|
||||||
|
></ms-textfield>
|
||||||
|
<select class="qc-feedback"
|
||||||
|
.value=${this._qcFeedback}
|
||||||
|
@change=${t=>{this._qcFeedback=t.target.value}}>
|
||||||
|
<option value="">${s("quick_complete_defaults_feedback_none",e)}</option>
|
||||||
|
<option value="needed">${s("quick_complete_defaults_feedback_needed",e)}</option>
|
||||||
|
<option value="not_needed">${s("quick_complete_defaults_feedback_not_needed",e)}</option>
|
||||||
|
</select>
|
||||||
|
</details>
|
||||||
|
`}async _loadParts(){if(this.parts=[],!!this._entryId)try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:this._entryId});this.parts=e.parts||[],this._partsLoadFailed=!1}catch{this.parts=[],this._partsLoadFailed=!0}}async _loadForeignPools(){if(this._foreignOwners=[],!!this._entryId)try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/objects"});this._foreignOwners=(e.objects||[]).filter(i=>i.entry_id!==this._entryId&&(i.parts||[]).length>0).map(i=>({entry_id:i.entry_id,name:i.object?.name||i.entry_id,parts:i.parts||[]})).sort((i,t)=>i.name.localeCompare(t.name))}catch{this._foreignOwners=[]}}async _loadTags(){try{let e=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/tags/list"});this._availableTags=e.tags||[]}catch{this._availableTags=[]}}async _fetchEntityAttributes(e){if(!e||!this.hass){this._suggestedAttributes=[],this._availableAttributes=[],this._entityDomain="";return}try{let i=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/entity/attributes",entity_id:e});this._entityDomain=i.domain||"",this._suggestedAttributes=i.suggested_attributes||[],this._availableAttributes=i.available_attributes||[]}catch{this._suggestedAttributes=[],this._availableAttributes=[],this._entityDomain=""}}get _hasForeignPick(){return Object.values(this._consumesParts).some(e=>!!e.entry_id)}_renderConsumesRow(e,i){let t=x({part_id:e.id,entry_id:i}),r=this._consumesParts[t],_=i?{part_id:e.id,quantity:1,entry_id:i}:{part_id:e.id,quantity:1};return l`
|
||||||
|
<div class="consumes-row">
|
||||||
|
<label class="consumes-check">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
.checked=${r!==void 0}
|
||||||
|
@change=${c=>{let h={...this._consumesParts};c.target.checked?h[t]=h[t]||_:delete h[t],this._consumesParts=h}}
|
||||||
|
/>
|
||||||
|
<span>${e.name}${e.unit?` (${e.unit})`:""}</span>
|
||||||
|
</label>
|
||||||
|
${r!==void 0?l`<input
|
||||||
|
class="consumes-qty"
|
||||||
|
type="number"
|
||||||
|
min="0.01"
|
||||||
|
max="999"
|
||||||
|
step="0.01"
|
||||||
|
.value=${String(r.quantity)}
|
||||||
|
@input=${c=>{let h=parseFloat(c.target.value);this._consumesParts={...this._consumesParts,[t]:{..._,quantity:Number.isFinite(h)&&h>=.01?h:1}}}}
|
||||||
|
/>`:u}
|
||||||
|
</div>
|
||||||
|
`}_toggleRequired(e,i){let t=new Set(this._requiredCompletion);i?t.add(e):t.delete(e),this._requiredCompletion=[...t]}async _save(){if(!this._loading&&this._name.trim()){this._loading=!0,this._error="";try{let e={type:this._taskId?"maintenance_supporter/task/update":"maintenance_supporter/task/create",entry_id:this._entryId,name:this._name,task_type:this._type,schedule_type:this._scheduleType,warning_days:Number.isNaN(parseInt(this._warningDays,10))?this.defaultWarningDays:Math.max(0,parseInt(this._warningDays,10))},i=this._earliestCompletionDays.trim();if(e.earliest_completion_days=i===""?null:Math.max(0,parseInt(i,10)||0),this._taskId&&(e.task_id=this._taskId),this._scheduleType==="one_time"?(e.due_date=this._dueDate||null,e.interval_days=null):E.includes(this._scheduleType)?(e.schedule={...this._buildSchedule(),...this._recurrenceExtras()},e.interval_days=null,this._taskId&&(e.due_date=null)):(this._taskId&&(e.due_date=null),this._scheduleType!=="manual"&&this._intervalDays?(e.interval_days=parseInt(this._intervalDays,10),e.interval_unit=this._intervalUnit,e.interval_anchor=this._intervalAnchor,this._scheduleType==="time_based"&&(e.schedule={kind:"interval",...this._recurrenceExtras()})):this._taskId&&(e.interval_days=null,e.interval_anchor="completion")),e.notes=this._notes||null,e.documentation_url=this._documentationUrl||null,e.custom_icon=this._customIcon||null,e.priority=this._priority,e.labels=this._labels.split(",").map(c=>c.trim()).filter(Boolean),e.enabled=this._enabled,e.last_performed=this._lastPerformed||null,e.nfc_tag_id=this._nfcTagId||null,e.reading_unit=this._readingUnit.trim()||null,(this.parts.length||this._foreignOwners.length)&&(e.consumes_parts=Object.values(this._consumesParts).map(c=>c.entry_id?{part_id:c.part_id,quantity:c.quantity,entry_id:c.entry_id}:{part_id:c.part_id,quantity:c.quantity})),e.responsible_user_id=this._responsibleUserId,e.assignee_pool=this._assigneePool,e.required_completion_fields=this._requiredCompletion,e.rotation_strategy=this._assigneePool.length>=2&&this._rotationStrategy?this._rotationStrategy:null,this._scheduleType==="sensor_based"&&this._triggerType==="compound"){let c=this._compoundConditions.map(M).filter(h=>h!==null);if(c.length>0){let h={type:"compound",compound_logic:this._compoundLogic,conditions:c};this._autoCompleteOnRecovery&&(h.auto_complete_on_recovery=!0),e.trigger_config=h}else this._taskId&&(e.trigger_config=null)}else if(this._scheduleType==="sensor_based"&&this._triggerEntityId){let c=this._triggerEntityIds.length>0?this._triggerEntityIds:[this._triggerEntityId],h={entity_id:c[0],entity_ids:c,type:this._triggerType};if(this._triggerAttribute&&(h.attribute=this._triggerAttribute),this._autoCompleteOnRecovery&&(h.auto_complete_on_recovery=!0),c.length>1&&(h.entity_logic=this._triggerEntityLogic),this._triggerType==="threshold"){if(this._triggerAbove){let d=parseFloat(this._triggerAbove);isNaN(d)||(h.trigger_above=d)}if(this._triggerBelow){let d=parseFloat(this._triggerBelow);isNaN(d)||(h.trigger_below=d)}if(this._triggerForMinutes){let d=parseInt(this._triggerForMinutes,10);isNaN(d)||(h.trigger_for_minutes=d)}}else if(this._triggerType==="counter"){if(this._triggerTargetValue){let d=parseFloat(this._triggerTargetValue);isNaN(d)||(h.trigger_target_value=d)}if(h.trigger_delta_mode=this._triggerDeltaMode,this._triggerDeltaMode&&this._triggerBaselineValue){let d=parseFloat(this._triggerBaselineValue);!isNaN(d)&&d>=0&&(h.trigger_baseline_value=d)}}else if(this._triggerType==="state_change"){if(this._triggerFromState&&(h.trigger_from_state=this._triggerFromState),this._triggerToState&&(h.trigger_to_state=this._triggerToState),this._triggerTargetChanges){let d=parseInt(this._triggerTargetChanges,10);isNaN(d)||(h.trigger_target_changes=d)}}else if(this._triggerType==="runtime"){if(this._triggerRuntimeHours){let m=parseFloat(this._triggerRuntimeHours);isNaN(m)||(h.trigger_runtime_hours=m)}let d=this._triggerOnStates.split(",").map(m=>m.trim()).filter(Boolean);d.length>0&&(h.trigger_on_states=d)}e.trigger_config=h}else this._taskId&&(e.trigger_config=null);if(this.scheduleTimeEnabled&&this._scheduleType==="time_based"){let c=this._scheduleTime.trim();e.schedule_time=/^([01]\d|2[0-3]):[0-5]\d$/.test(c)?c:null}if(this.checklistsEnabled){let c=this._checklistText.split(`
|
||||||
|
`).map(h=>h.trim()).filter(Boolean).slice(0,100);e.checklist=c.length?c:null}if(this.completionActionsEnabled){let c=this._actionService.trim();if(c&&/^[a-z][a-z0-9_]*\.[a-z0-9_]+$/.test(c)){let v={service:c},g=this._actionTargetEntity.trim();g&&(v.target={entity_id:g});let f=this._buildActionData();Object.keys(f).length>0&&(v.data=f),e.on_complete_action=v}else e.on_complete_action=null;let h={};this._qcNotes.trim()&&(h.notes=this._qcNotes.trim());let d=parseFloat(this._qcCost);!isNaN(d)&&d>=0&&(h.cost=d);let m=parseInt(this._qcDuration,10);!isNaN(m)&&m>=0&&(h.duration=m),this._qcFeedback&&(h.feedback=this._qcFeedback),e.quick_complete_defaults=Object.keys(h).length?h:null}let t=await this.hass.connection.sendMessagePromise(e),r=this._taskId||t?.task_id,_=this._environmentalEntity!==this._environmentalInitial||this._environmentalAttribute!==this._environmentalAttributeInitial;if(r&&this._scheduleType==="sensor_based"&&_)try{await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/task/set_environmental_entity",entry_id:this._entryId,task_id:r,environmental_entity:this._environmentalEntity||null,environmental_attribute:this._environmentalAttribute||null}),this._environmentalInitial=this._environmentalEntity,this._environmentalAttributeInitial=this._environmentalAttribute}catch{}this._open=!1,this.dispatchEvent(new CustomEvent("task-saved"))}catch(e){this._error=C(e,this._lang,s("save_error",this._lang))}finally{this._loading=!1}}}_close(){this._open=!1}_renderTriggerFields(){if(this._scheduleType!=="sensor_based")return u;let e=this._lang,i=this._triggerType==="compound";return l`
|
||||||
|
<h3>${s("trigger_configuration",e)}</h3>
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("trigger_type",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._triggerType}
|
||||||
|
@change=${t=>this._triggerType=t.target.value}
|
||||||
|
>
|
||||||
|
${R.map(t=>l`<option value=${t} ?selected=${t===this._triggerType}>${s(t,e)}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
${i?this._renderCompoundEditor():l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("entity_id",e)} (${s("comma_separated",e)})"
|
||||||
|
.value=${this._triggerEntityIds.length>0?this._triggerEntityIds.join(", "):this._triggerEntityId}
|
||||||
|
@input=${t=>{let _=t.target.value.split(",").map(c=>c.trim()).filter(Boolean);this._triggerEntityId=_[0]||"",this._triggerEntityIds=_,_[0]&&this._fetchEntityAttributes(_[0])}}
|
||||||
|
></ms-textfield>
|
||||||
|
${this._triggerEntityIds.length>1?l`
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("entity_logic",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._triggerEntityLogic}
|
||||||
|
@change=${t=>this._triggerEntityLogic=t.target.value}
|
||||||
|
>
|
||||||
|
<option value="any" ?selected=${this._triggerEntityLogic==="any"}>${s("entity_logic_any",e)}</option>
|
||||||
|
<option value="all" ?selected=${this._triggerEntityLogic==="all"}>${s("entity_logic_all",e)}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
`:u}
|
||||||
|
${this._availableAttributes.length>0?l`
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("attribute_optional",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._triggerAttribute}
|
||||||
|
@change=${t=>this._triggerAttribute=t.target.value}
|
||||||
|
>
|
||||||
|
<option value="" ?selected=${!this._triggerAttribute}>${s("use_entity_state",e)}</option>
|
||||||
|
${this._suggestedAttributes.map(t=>l`<option value=${t} ?selected=${t===this._triggerAttribute}>${t} ★</option>`)}
|
||||||
|
${this._availableAttributes.filter(t=>!this._suggestedAttributes.includes(t.name)).map(t=>l`<option value=${t.name} ?selected=${t.name===this._triggerAttribute}>${t.name}${t.numeric?"":" (non-numeric)"}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
`:l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("attribute_optional",e)}"
|
||||||
|
.value=${this._triggerAttribute}
|
||||||
|
@input=${t=>this._triggerAttribute=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
`}
|
||||||
|
${this._renderTriggerTypeFields()}
|
||||||
|
${this._renderTriggerLiveHint()}
|
||||||
|
`}
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
.checked=${this._autoCompleteOnRecovery}
|
||||||
|
@change=${t=>this._autoCompleteOnRecovery=t.target.checked}
|
||||||
|
/>
|
||||||
|
${s("auto_complete_on_recovery",e)}
|
||||||
|
</label>
|
||||||
|
<div class="field-help">${s("auto_complete_on_recovery_help",e)}</div>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("safety_interval",e)}"
|
||||||
|
type="number"
|
||||||
|
.value=${this._intervalDays}
|
||||||
|
@input=${t=>this._intervalDays=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
${this._intervalDays?this._renderUnitSelect():u}
|
||||||
|
`}_patchCondition(e,i){this._compoundConditions=this._compoundConditions.map((t,r)=>r===e?{...t,...i}:t)}_addCondition(){this._compoundConditions=[...this._compoundConditions,q()]}_removeCondition(e){this._compoundConditions=this._compoundConditions.filter((i,t)=>t!==e)}_renderCompoundEditor(){let e=this._lang;return l`
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("compound_logic",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._compoundLogic}
|
||||||
|
@change=${i=>this._compoundLogic=i.target.value}
|
||||||
|
>
|
||||||
|
<option value="AND" ?selected=${this._compoundLogic==="AND"}>${s("compound_logic_and",e)}</option>
|
||||||
|
<option value="OR" ?selected=${this._compoundLogic==="OR"}>${s("compound_logic_or",e)}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field-help">${s("compound_help",e)}</div>
|
||||||
|
${this._compoundConditions.length===0?l`<div class="field-help">${s("compound_no_conditions",e)}</div>`:this._compoundConditions.map((i,t)=>this._renderCondition(i,t))}
|
||||||
|
<button type="button" class="secondary-btn" @click=${()=>this._addCondition()}>
|
||||||
|
+ ${s("compound_add_condition",e)}
|
||||||
|
</button>
|
||||||
|
`}_renderCondition(e,i){let t=this._lang,r=i+1;return l`
|
||||||
|
<div class="compound-condition">
|
||||||
|
<div class="compound-condition-head">
|
||||||
|
<span class="compound-condition-title">${s("compound_condition",t)} ${r}</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="icon-btn"
|
||||||
|
title="${s("compound_remove_condition",t)}"
|
||||||
|
@click=${()=>this._removeCondition(i)}
|
||||||
|
>✕</button>
|
||||||
|
</div>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("entity_id",t)} (${s("comma_separated",t)})"
|
||||||
|
.value=${e.entityIds}
|
||||||
|
@input=${_=>this._patchCondition(i,{entityIds:_.target.value})}
|
||||||
|
></ms-textfield>
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("trigger_type",t)}</label>
|
||||||
|
<select
|
||||||
|
.value=${e.type}
|
||||||
|
@change=${_=>this._patchCondition(i,{type:_.target.value})}
|
||||||
|
>
|
||||||
|
${H.map(_=>l`<option value=${_} ?selected=${_===e.type}>${s(_,t)}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
${this._renderConditionTypeFields(e,i)}
|
||||||
|
</div>
|
||||||
|
`}_renderConditionTypeFields(e,i){let t=this._lang;return e.type==="threshold"?l`
|
||||||
|
<ms-textfield label="${s("trigger_above",t)}" type="number" .value=${e.above}
|
||||||
|
@input=${r=>this._patchCondition(i,{above:r.target.value})}></ms-textfield>
|
||||||
|
<ms-textfield label="${s("trigger_below",t)}" type="number" .value=${e.below}
|
||||||
|
@input=${r=>this._patchCondition(i,{below:r.target.value})}></ms-textfield>
|
||||||
|
<ms-textfield label="${s("for_minutes",t)}" type="number" .value=${e.forMinutes}
|
||||||
|
@input=${r=>this._patchCondition(i,{forMinutes:r.target.value})}></ms-textfield>
|
||||||
|
`:e.type==="counter"?l`
|
||||||
|
<ms-textfield label="${s("target_value",t)}" type="number" .value=${e.targetValue}
|
||||||
|
@input=${r=>this._patchCondition(i,{targetValue:r.target.value})}></ms-textfield>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" .checked=${e.deltaMode}
|
||||||
|
@change=${r=>this._patchCondition(i,{deltaMode:r.target.checked})} />
|
||||||
|
${s("delta_mode",t)}
|
||||||
|
</label>
|
||||||
|
`:e.type==="state_change"?l`
|
||||||
|
<ms-textfield label="${s("from_state_optional",t)}" .value=${e.fromState}
|
||||||
|
@input=${r=>this._patchCondition(i,{fromState:r.target.value})}></ms-textfield>
|
||||||
|
<ms-textfield label="${s("to_state_optional",t)}" .value=${e.toState}
|
||||||
|
@input=${r=>this._patchCondition(i,{toState:r.target.value})}></ms-textfield>
|
||||||
|
<ms-textfield label="${s("target_changes",t)}" type="number" .value=${e.targetChanges}
|
||||||
|
@input=${r=>this._patchCondition(i,{targetChanges:r.target.value})}></ms-textfield>
|
||||||
|
`:e.type==="runtime"?l`
|
||||||
|
<ms-textfield label="${s("runtime_hours",t)}" type="number" .value=${e.runtimeHours}
|
||||||
|
@input=${r=>this._patchCondition(i,{runtimeHours:r.target.value})}></ms-textfield>
|
||||||
|
<ms-textfield label="${s("runtime_on_states",t)}" placeholder="on" .value=${e.onStates}
|
||||||
|
@input=${r=>this._patchCondition(i,{onStates:r.target.value})}></ms-textfield>
|
||||||
|
`:u}_renderUnitSelect(){let e=this._lang;return l`
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("interval_unit",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._intervalUnit}
|
||||||
|
@change=${i=>this._intervalUnit=i.target.value}
|
||||||
|
>
|
||||||
|
${["days","weeks","months","years"].map(i=>l`<option value=${i} ?selected=${i===this._intervalUnit}>${s("unit_"+i,e)}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>`}_toggleWeekday(e){this._weekdays=this._weekdays.includes(e)?this._weekdays.filter(i=>i!==e):[...this._weekdays,e]}_previewScheduleDict(){if(this._scheduleType==="one_time")return this._dueDate?{kind:"one_time",due_date:this._dueDate}:null;if(E.includes(this._scheduleType))return{...this._buildSchedule(),...this._recurrenceExtras()};let e=parseInt(this._intervalDays,10);return this._scheduleType==="manual"||!e||e<=0?null:{kind:"interval",every:e,unit:this._intervalUnit,anchor:this._intervalAnchor,...this._recurrenceExtras()}}updated(e){super.updated?.(e);for(let i of e.keys())if(n._PREVIEW_RELEVANT.has(String(i))){this._schedulePreviewRefresh();return}}_schedulePreviewRefresh(){this._previewTimer&&clearTimeout(this._previewTimer),this._previewTimer=setTimeout(()=>{this._fetchSchedulePreview()},300)}async _fetchSchedulePreview(){let e=this._open?this._previewScheduleDict():null;if(!e){this._schedulePreview=[],this._schedulePreviewEnded=!1;return}let i=++this._previewSeq;try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/schedule/preview",schedule:e,...this._lastPerformed?{last_performed:this._lastPerformed}:{}});if(i!==this._previewSeq)return;this._schedulePreview=t.occurrences||[],this._schedulePreviewEnded=!!t.series_ended}catch{}}_renderSchedulePreview(){if(this._schedulePreview.length===0)return u;let e=this._lang,i=this.scheduleTimeEnabled&&this._scheduleTime?` ${this._scheduleTime}`:"",t=this._schedulePreview.map((_,c)=>{let h=new Date(`${_}T12:00:00`).getDay();return`${$(h===0?6:h-1,e,"short")} ${S(_,e)}${c===0?i:""}`}).join(" \xB7 "),r=this._scheduleType==="time_based"&&this._intervalAnchor==="completion"?l`<div class="field-help">${s("schedule_preview_ontime",e)}</div>`:u;return l`
|
||||||
|
<div class="trigger-live-hint schedule-preview">
|
||||||
|
${s("schedule_preview_title",e)}: ${t}${this._schedulePreviewEnded?l` <span class="field-help">${s("schedule_preview_ends",e)}</span>`:u}
|
||||||
|
${r}
|
||||||
|
</div>
|
||||||
|
`}_buildSchedule(){let e=t=>{let r=parseInt(this._calOffset,10)||0;return r&&(t.offset=Math.max(-15,Math.min(r,15))),t};if(this._scheduleType==="weekdays")return e({kind:"weekdays",weekdays:[...this._weekdays].sort((t,r)=>t-r)});if(this._scheduleType==="nth_weekday")return e({kind:"nth_weekday",nth:parseInt(this._nth,10),weekday:parseInt(this._nthWeekday,10)});let i={kind:"day_of_month",day:this._domLastDay?-1:parseInt(this._domDay,10)||1};return this._domBusiness&&(i.business=!0),e(i)}_recurrenceExtras(){let e={};if(this._seasonMonths.length&&(e.season_months=[...this._seasonMonths].sort((i,t)=>i-t)),this._endsMode==="count"){let i=parseInt(this._endsCount,10);i>=1&&(e.ends={count:i})}else this._endsMode==="until"&&this._endsUntil&&(e.ends={until:this._endsUntil});return e}_toggleSeasonMonth(e){this._seasonMonths=this._seasonMonths.includes(e)?this._seasonMonths.filter(i=>i!==e):[...this._seasonMonths,e]}_renderRecurrenceExtras(){let e=this._lang;if(!(this._scheduleType==="time_based"||E.includes(this._scheduleType)))return u;let t=B(e);return l`
|
||||||
|
<label class="field-label">${s("season_window_label",e)}</label>
|
||||||
|
<div class="field-help">${s("season_window_hint",e)}</div>
|
||||||
|
<div class="weekday-chips season-chips">
|
||||||
|
${t.map((r,_)=>l`
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="season-chip ${this._seasonMonths.includes(_+1)?"selected":""}"
|
||||||
|
@click=${()=>this._toggleSeasonMonth(_+1)}
|
||||||
|
>${r}</button>`)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label class="field-label">${s("series_end_label",e)}</label>
|
||||||
|
<div class="select-row">
|
||||||
|
<select .value=${this._endsMode}
|
||||||
|
@change=${r=>this._endsMode=r.target.value}>
|
||||||
|
<option value="never" ?selected=${this._endsMode==="never"}>${s("series_end_never",e)}</option>
|
||||||
|
<option value="count" ?selected=${this._endsMode==="count"}>${s("series_end_after_count",e)}</option>
|
||||||
|
<option value="until" ?selected=${this._endsMode==="until"}>${s("series_end_until",e)}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
${this._endsMode==="count"?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("series_end_count_label",e)}"
|
||||||
|
type="number" min="1"
|
||||||
|
.value=${this._endsCount}
|
||||||
|
@input=${r=>this._endsCount=r.target.value}
|
||||||
|
></ms-textfield>`:u}
|
||||||
|
${this._endsMode==="until"?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("series_end_until_label",e)}"
|
||||||
|
type="date"
|
||||||
|
.value=${this._endsUntil}
|
||||||
|
@input=${r=>this._endsUntil=r.target.value}
|
||||||
|
></ms-textfield>`:u}
|
||||||
|
`}_renderCalendarFields(){let e=this._lang,i=j(e);if(this._scheduleType==="weekdays")return l`
|
||||||
|
<label class="field-label">${s("recurrence_on_days",e)}</label>
|
||||||
|
<div class="weekday-chips">
|
||||||
|
${i.map((t,r)=>l`
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="weekday-chip ${this._weekdays.includes(r)?"selected":""}"
|
||||||
|
@click=${()=>this._toggleWeekday(r)}
|
||||||
|
>${t}</button>`)}
|
||||||
|
</div>
|
||||||
|
${this._renderCalOffsetField()}`;if(this._scheduleType==="nth_weekday"){let t=[["1",s("ord_1",e)],["2",s("ord_2",e)],["3",s("ord_3",e)],["4",s("ord_4",e)],["5",s("ord_5",e)],["-1",s("ord_last",e)]];return l`
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("recurrence_occurrence",e)}</label>
|
||||||
|
<select .value=${this._nth} @change=${r=>this._nth=r.target.value}>
|
||||||
|
${t.map(([r,_])=>l`<option value=${r} ?selected=${r===this._nth}>${_}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("recurrence_weekday",e)}</label>
|
||||||
|
<select .value=${this._nthWeekday} @change=${r=>this._nthWeekday=r.target.value}>
|
||||||
|
${i.map((r,_)=>l`<option value=${String(_)} ?selected=${String(_)===this._nthWeekday}>${r}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
${this._renderCalOffsetField()}`}return this._scheduleType==="day_of_month"?l`
|
||||||
|
${this._domLastDay?u:l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("recurrence_day",e)}"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="31"
|
||||||
|
.value=${this._domDay}
|
||||||
|
@input=${t=>this._domDay=t.target.value}
|
||||||
|
></ms-textfield>`}
|
||||||
|
<label class="checkbox-row">
|
||||||
|
<input type="checkbox" .checked=${this._domLastDay}
|
||||||
|
@change=${t=>this._domLastDay=t.target.checked} />
|
||||||
|
<span>${s("recurrence_last_day",e)}</span>
|
||||||
|
</label>
|
||||||
|
<label class="checkbox-row">
|
||||||
|
<input type="checkbox" .checked=${this._domBusiness}
|
||||||
|
@change=${t=>this._domBusiness=t.target.checked} />
|
||||||
|
<span>${s("recurrence_business_day",e)}</span>
|
||||||
|
</label>
|
||||||
|
${this._renderCalOffsetField()}`:u}_renderCalOffsetField(){let e=this._lang;return l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("recurrence_offset",e)}"
|
||||||
|
helper="${s("recurrence_offset_help",e)}"
|
||||||
|
type="number"
|
||||||
|
min="-15"
|
||||||
|
max="15"
|
||||||
|
.value=${this._calOffset}
|
||||||
|
@input=${i=>this._calOffset=i.target.value}
|
||||||
|
></ms-textfield>`}_renderTriggerLiveHint(){if(this._triggerType==="compound")return u;let e=this._triggerEntityId||this._triggerEntityIds[0];if(!e||!this.hass?.states)return u;let i=this.hass.states[e];if(!i)return u;let t=this._lang,r=i.attributes?.unit_of_measurement,_=typeof r=="string"&&r?` ${r}`:"",c=this._triggerAttribute?i.attributes?.[this._triggerAttribute]:i.state,h=typeof c=="number"?c:parseFloat(String(c)),d=c!=="unknown"&&c!=="unavailable"&&c!=null&&!isNaN(h),m=g=>Number.isInteger(g)?String(g):String(Math.round(g*10)/10),v=[];if(this._triggerType==="threshold"){let g=parseFloat(this._triggerAbove),f=parseFloat(this._triggerBelow);if(isNaN(g)&&isNaN(f))return u;d&&v.push(s("trigger_hint_now",t).replace("{value}",m(h)+_)),isNaN(g)||v.push(s("trigger_hint_above",t).replace("{target}",m(g)+_)),isNaN(f)||v.push(s("trigger_hint_below",t).replace("{target}",m(f)+_))}else if(this._triggerType==="counter"){let g=parseFloat(this._triggerTargetValue);if(isNaN(g))return u;this._triggerDeltaMode?this._taskId?v.push(s("trigger_hint_counter_delta_edit",t).replace("{target}",m(g)+_)):d?v.push(s("trigger_hint_counter_delta",t).replace("{value}",m(h)+_).replace("{due}",m(h+g)+_).replace("{target}",m(g)+_)):v.push(s("trigger_hint_counter_delta_edit",t).replace("{target}",m(g)+_)):(d&&v.push(s("trigger_hint_now",t).replace("{value}",m(h)+_)),v.push(s("trigger_hint_counter_abs",t).replace("{target}",m(g)+_)))}else if(this._triggerType==="runtime"){let g=parseFloat(this._triggerRuntimeHours);if(isNaN(g))return u;v.push(s("trigger_hint_runtime",t).replace("{hours}",m(g))),v.push(s("trigger_hint_state_now",t).replace("{value}",String(i.state)))}else if(this._triggerType==="state_change"){let g=parseInt(this._triggerTargetChanges,10)||1,f=this._triggerToState.trim();v.push((f?s("trigger_hint_state_change_to",t).replace("{state}",f):s("trigger_hint_state_change",t)).replace("{count}",String(g))),v.push(s("trigger_hint_state_now",t).replace("{value}",String(i.state)))}return v.length?l`<div class="trigger-live-hint">${v.join(" ")}</div>`:u}_renderTriggerTypeFields(){let e=this._lang;return this._triggerType==="threshold"?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("trigger_above",e)}"
|
||||||
|
type="number"
|
||||||
|
step="any"
|
||||||
|
.value=${this._triggerAbove}
|
||||||
|
@input=${i=>this._triggerAbove=i.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("trigger_below",e)}"
|
||||||
|
type="number"
|
||||||
|
step="any"
|
||||||
|
.value=${this._triggerBelow}
|
||||||
|
@input=${i=>this._triggerBelow=i.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("for_at_least_minutes",e)}"
|
||||||
|
type="number"
|
||||||
|
.value=${this._triggerForMinutes}
|
||||||
|
@input=${i=>this._triggerForMinutes=i.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
`:this._triggerType==="counter"?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("target_value",e)}"
|
||||||
|
type="number"
|
||||||
|
step="any"
|
||||||
|
.value=${this._triggerTargetValue}
|
||||||
|
@input=${i=>this._triggerTargetValue=i.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
.checked=${this._triggerDeltaMode}
|
||||||
|
@change=${i=>this._triggerDeltaMode=i.target.checked}
|
||||||
|
/>
|
||||||
|
${s("delta_mode",e)}
|
||||||
|
</label>
|
||||||
|
${this._triggerDeltaMode?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("baseline_start_value",e)}"
|
||||||
|
type="number"
|
||||||
|
step="any"
|
||||||
|
.value=${this._triggerBaselineValue}
|
||||||
|
@input=${i=>this._triggerBaselineValue=i.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<div class="field-help">
|
||||||
|
${this._taskId?s("baseline_start_help_edit",e):s("baseline_start_help",e)}
|
||||||
|
${this._taskId&&this._liveBaselineValue!=null?l`<div class="baseline-effective">
|
||||||
|
${s("baseline_current_effective",e).replace("{value}",String(this._liveBaselineValue))}
|
||||||
|
</div>`:u}
|
||||||
|
</div>
|
||||||
|
`:u}
|
||||||
|
`:this._triggerType==="state_change"?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("from_state_optional",e)}"
|
||||||
|
.value=${this._triggerFromState}
|
||||||
|
@input=${i=>this._triggerFromState=i.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<div class="field-help">${s("state_value_help",e)}</div>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("to_state_optional",e)}"
|
||||||
|
.value=${this._triggerToState}
|
||||||
|
@input=${i=>this._triggerToState=i.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("target_changes",e)}"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
.value=${this._triggerTargetChanges}
|
||||||
|
@input=${i=>this._triggerTargetChanges=i.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<div class="field-help">${s("target_changes_help",e)}</div>
|
||||||
|
`:this._triggerType==="runtime"?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("runtime_hours",e)}"
|
||||||
|
type="number"
|
||||||
|
step="1"
|
||||||
|
.value=${this._triggerRuntimeHours}
|
||||||
|
@input=${i=>this._triggerRuntimeHours=i.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("runtime_on_states",e)}"
|
||||||
|
placeholder="on"
|
||||||
|
.value=${this._triggerOnStates}
|
||||||
|
@input=${i=>this._triggerOnStates=i.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<div class="field-help">${s("runtime_on_states_help",e)}</div>
|
||||||
|
`:u}render(){if(!this._open)return l``;let e=this._lang,i=this._taskId?s("edit_task",e):s("new_task",e);return l`
|
||||||
|
<ha-dialog open @closed=${this._close}>
|
||||||
|
<div class="dialog-title">${i}</div>
|
||||||
|
<div class="content">
|
||||||
|
${this._error?l`<div class="error">${this._error}</div>`:u}
|
||||||
|
${this._objectChoices.length>0?l`
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("object",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._entryId}
|
||||||
|
@change=${t=>{this._entryId=t.target.value,this._consumesParts={},this._loadParts(),this._loadForeignPools()}}
|
||||||
|
>
|
||||||
|
${this._objectChoices.map(t=>l`<option value=${t.entry_id} ?selected=${t.entry_id===this._entryId}>${t.name}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
`:u}
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("task_name",e)}"
|
||||||
|
required
|
||||||
|
.value=${this._name}
|
||||||
|
@input=${t=>this._name=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("maintenance_type",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._type}
|
||||||
|
@change=${t=>this._type=t.target.value}
|
||||||
|
>
|
||||||
|
${P.map(t=>l`<option value=${t} ?selected=${t===this._type}>${s(t,e)}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
${this._type==="reading"?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("reading_unit_label",e)}"
|
||||||
|
.value=${this._readingUnit}
|
||||||
|
@input=${t=>this._readingUnit=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<div class="field-help">${s("reading_unit_help",e)}</div>
|
||||||
|
`:u}
|
||||||
|
${this._partsLoadFailed?l`<div class="field-help parts-load-failed">${s("parts_load_failed",e)}</div>`:u}
|
||||||
|
${this.parts.length||this._foreignOwners.length?l`
|
||||||
|
<div class="field">
|
||||||
|
<label>${s("consumes_parts_label",e)}</label>
|
||||||
|
${this.parts.map(t=>this._renderConsumesRow(t))}
|
||||||
|
${this._foreignOwners.length?l`
|
||||||
|
<details class="shared-pools" ?open=${this._hasForeignPick}>
|
||||||
|
<summary>${s("shared_parts_other_objects",e)}</summary>
|
||||||
|
<div class="field-help">${s("shared_parts_help",e)}</div>
|
||||||
|
${this._foreignOwners.map(t=>l`
|
||||||
|
<div class="shared-pool-owner">${t.name}</div>
|
||||||
|
${t.parts.map(r=>this._renderConsumesRow(r,t.entry_id))}
|
||||||
|
`)}
|
||||||
|
</details>
|
||||||
|
`:u}
|
||||||
|
</div>
|
||||||
|
`:u}
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("priority",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._priority}
|
||||||
|
@change=${t=>this._priority=t.target.value}
|
||||||
|
>
|
||||||
|
${N.map(t=>l`<option value=${t} ?selected=${t===this._priority}>${s("priority_"+t,e)}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>${s("labels",e)}</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
.value=${this._labels}
|
||||||
|
placeholder="${s("labels_placeholder",e)}"
|
||||||
|
@input=${t=>this._labels=t.target.value}
|
||||||
|
/>
|
||||||
|
<div class="field-help">${s("labels_help",e)}</div>
|
||||||
|
</div>
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("schedule_type",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._scheduleType}
|
||||||
|
@change=${t=>this._scheduleType=t.target.value}
|
||||||
|
>
|
||||||
|
${F.map(t=>l`<option value=${t} ?selected=${t===this._scheduleType}>${s(t,e)}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
${this._scheduleType==="time_based"?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("interval_value",e)}"
|
||||||
|
type="number"
|
||||||
|
.value=${this._intervalDays}
|
||||||
|
@input=${t=>this._intervalDays=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
${this._renderUnitSelect()}
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("interval_anchor",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._intervalAnchor}
|
||||||
|
@change=${t=>this._intervalAnchor=t.target.value}
|
||||||
|
>
|
||||||
|
<option value="completion" ?selected=${this._intervalAnchor==="completion"}>${s("anchor_completion",e)}</option>
|
||||||
|
<option value="planned" ?selected=${this._intervalAnchor==="planned"}>${s("anchor_planned",e)}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
${this.scheduleTimeEnabled?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("schedule_time_optional",e)}"
|
||||||
|
type="time"
|
||||||
|
.value=${this._scheduleTime}
|
||||||
|
helper="${s("schedule_time_help",e)}"
|
||||||
|
@input=${t=>this._scheduleTime=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
`:u}
|
||||||
|
`:u}
|
||||||
|
${this._renderCalendarFields()}
|
||||||
|
${this._scheduleType==="one_time"?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("due_date",e)}"
|
||||||
|
type="date"
|
||||||
|
.value=${this._dueDate}
|
||||||
|
@input=${t=>this._dueDate=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
`:u}
|
||||||
|
${this._renderRecurrenceExtras()}
|
||||||
|
${this._renderSchedulePreview()}
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("warning_days",e)}"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
max="365"
|
||||||
|
.value=${this._warningDays}
|
||||||
|
@input=${t=>this._warningDays=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("earliest_completion_days",e)}"
|
||||||
|
helper="${s("earliest_completion_days_help",e)}"
|
||||||
|
type="number"
|
||||||
|
.value=${this._earliestCompletionDays}
|
||||||
|
@input=${t=>this._earliestCompletionDays=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
${this.checklistsEnabled?l`
|
||||||
|
<h3>${s("checklist_steps_optional",e)}</h3>
|
||||||
|
<textarea
|
||||||
|
id="checklist-textarea"
|
||||||
|
class="checklist-textarea"
|
||||||
|
rows="5"
|
||||||
|
placeholder="${s("checklist_placeholder",e)}"
|
||||||
|
.value=${this._checklistText}
|
||||||
|
@input=${t=>this._checklistText=t.target.value}
|
||||||
|
></textarea>
|
||||||
|
<div class="field-help">${s("checklist_help",e)}</div>
|
||||||
|
`:u}
|
||||||
|
<h3>${s("require_on_completion",e)}</h3>
|
||||||
|
<div class="required-completion">
|
||||||
|
${A.map(t=>l`
|
||||||
|
<label class="req-option">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
.checked=${this._requiredCompletion.includes(t)}
|
||||||
|
@change=${r=>this._toggleRequired(t,r.target.checked)}
|
||||||
|
/>
|
||||||
|
<span>${s(L[t],e)}</span>
|
||||||
|
</label>
|
||||||
|
`)}
|
||||||
|
</div>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("last_performed_optional",e)}"
|
||||||
|
type="date"
|
||||||
|
.value=${this._lastPerformed}
|
||||||
|
@input=${t=>this._lastPerformed=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("responsible_user",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._responsibleUserId||""}
|
||||||
|
@change=${t=>{let r=t.target.value;this._responsibleUserId=r||null}}
|
||||||
|
>
|
||||||
|
<option value="" ?selected=${!this._responsibleUserId}>${s("no_user_assigned",e)}</option>
|
||||||
|
${this._availableUsers.map(t=>l`<option value=${t.id} ?selected=${t.id===this._responsibleUserId}>${t.name}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
${this._availableUsers.length>=2?l`
|
||||||
|
<div class="field">
|
||||||
|
<label>${s("shared_with",e)}</label>
|
||||||
|
<div class="field-help">${s("shared_with_help",e)}</div>
|
||||||
|
<div class="assignee-pool">
|
||||||
|
${this._availableUsers.map(t=>l`
|
||||||
|
<label class="pool-item">
|
||||||
|
<input type="checkbox"
|
||||||
|
.checked=${this._assigneePool.includes(t.id)}
|
||||||
|
@change=${()=>this._toggleAssignee(t.id)} />
|
||||||
|
<span>${t.name}</span>
|
||||||
|
</label>`)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
${this._assigneePool.length>=2?l`
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("rotation_strategy",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._rotationStrategy}
|
||||||
|
@change=${t=>this._rotationStrategy=t.target.value}
|
||||||
|
>
|
||||||
|
<option value="" ?selected=${!this._rotationStrategy}>${s("rotation_none",e)}</option>
|
||||||
|
${["round_robin","least_completed","random"].map(t=>l`<option value=${t} ?selected=${t===this._rotationStrategy}>${s("rotation_"+t,e)}</option>`)}
|
||||||
|
</select>
|
||||||
|
</div>`:u}
|
||||||
|
`:u}
|
||||||
|
${this._renderTriggerFields()}
|
||||||
|
${this._scheduleType==="sensor_based"?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("environmental_entity_optional",e)}"
|
||||||
|
helper="${s("environmental_entity_helper",e)}"
|
||||||
|
.value=${this._environmentalEntity}
|
||||||
|
@input=${t=>this._environmentalEntity=t.target.value.trim()}
|
||||||
|
></ms-textfield>
|
||||||
|
${this._environmentalEntity?l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("environmental_attribute_optional",e)}"
|
||||||
|
.value=${this._environmentalAttribute}
|
||||||
|
@input=${t=>this._environmentalAttribute=t.target.value.trim()}
|
||||||
|
></ms-textfield>
|
||||||
|
`:u}
|
||||||
|
`:u}
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("notes_optional",e)}"
|
||||||
|
.value=${this._notes}
|
||||||
|
@input=${t=>this._notes=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("documentation_url_optional",e)}"
|
||||||
|
.value=${this._documentationUrl}
|
||||||
|
@input=${t=>this._documentationUrl=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<ha-icon-picker
|
||||||
|
.hass=${this.hass}
|
||||||
|
label="${s("custom_icon_optional",e)}"
|
||||||
|
.value=${this._customIcon}
|
||||||
|
@value-changed=${t=>this._customIcon=t.detail.value||""}
|
||||||
|
></ha-icon-picker>
|
||||||
|
${this._availableTags.length>0?l`
|
||||||
|
<div class="select-row">
|
||||||
|
<label>${s("nfc_tag_id_optional",e)}</label>
|
||||||
|
<select
|
||||||
|
.value=${this._nfcTagId}
|
||||||
|
@change=${t=>this._nfcTagId=t.target.value}
|
||||||
|
>
|
||||||
|
<option value="" ?selected=${!this._nfcTagId}>${s("no_nfc_tag",e)}</option>
|
||||||
|
${this._availableTags.map(t=>l`<option value=${t.id} ?selected=${t.id===this._nfcTagId}>${t.name}</option>`)}
|
||||||
|
</select>
|
||||||
|
<button type="button" class="link-button" @click=${this._loadTags}
|
||||||
|
title="${s("nfc_tags_refresh",e)}">↻</button>
|
||||||
|
</div>
|
||||||
|
`:l`
|
||||||
|
<ms-textfield
|
||||||
|
label="${s("nfc_tag_id_optional",e)}"
|
||||||
|
.value=${this._nfcTagId}
|
||||||
|
@input=${t=>this._nfcTagId=t.target.value}
|
||||||
|
></ms-textfield>
|
||||||
|
<div class="field-help">
|
||||||
|
${s("nfc_tags_empty_help",e)}
|
||||||
|
<a href="/config/tags">${s("nfc_tags_open_settings",e)}</a>
|
||||||
|
·
|
||||||
|
<button type="button" class="link-button" @click=${this._loadTags}>
|
||||||
|
${s("nfc_tags_refresh",e)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
<label class="toggle-row">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
.checked=${this._enabled}
|
||||||
|
@change=${t=>this._enabled=t.target.checked}
|
||||||
|
/>
|
||||||
|
${s("task_enabled",e)}
|
||||||
|
</label>
|
||||||
|
${this._renderCompletionActionsSection(e)}
|
||||||
|
</div>
|
||||||
|
<div class="dialog-actions">
|
||||||
|
<ha-button appearance="plain" @click=${this._close}>${s("cancel",e)}</ha-button>
|
||||||
|
<ha-button
|
||||||
|
@click=${this._save}
|
||||||
|
.disabled=${this._loading||!this._name.trim()}
|
||||||
|
>
|
||||||
|
${this._loading?s("saving",e):s("save",e)}
|
||||||
|
</ha-button>
|
||||||
|
</div>
|
||||||
|
</ha-dialog>
|
||||||
|
`}};n._PREVIEW_RELEVANT=new Set(["_open","_scheduleType","_intervalDays","_intervalUnit","_intervalAnchor","_dueDate","_weekdays","_nth","_nthWeekday","_domDay","_domLastDay","_domBusiness","_calOffset","_seasonMonths","_endsMode","_endsCount","_endsUntil","_lastPerformed"]),n.styles=T`
|
||||||
|
.dialog-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
}
|
||||||
|
/* v1.3.0: completion-action sections */
|
||||||
|
.ca-section {
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.ca-section > summary {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.ca-section ms-textfield,
|
||||||
|
.ca-section ha-entity-picker,
|
||||||
|
.ca-section ha-service-picker,
|
||||||
|
.ca-section ha-form,
|
||||||
|
.ca-section .qc-feedback {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 8px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.ca-section .qc-feedback {
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
background: var(--card-background-color, #fff);
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
.ca-test-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.ca-test-ok { color: var(--success-color, #4caf50); font-size: 13px; }
|
||||||
|
.ca-test-error { color: var(--error-color, #f44336); font-size: 13px; font-weight: 500; }
|
||||||
|
.ca-test-error-block { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; }
|
||||||
|
.ca-test-error-detail {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
background: rgba(244, 67, 54, 0.08);
|
||||||
|
padding: 6px 8px; border-radius: 4px;
|
||||||
|
line-height: 1.4;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
min-width: 350px;
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.content {
|
||||||
|
min-width: 0;
|
||||||
|
max-height: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dialog-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
ms-textfield {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.field-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
.checklist-textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 88px;
|
||||||
|
padding: 8px;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 14px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
background: var(--card-background-color);
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
resize: vertical;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.consumes-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
.consumes-check {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.consumes-qty {
|
||||||
|
width: 64px;
|
||||||
|
padding: 4px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
background: var(--card-background-color);
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
/* #111: other objects' pools sit behind a disclosure so the object's OWN
|
||||||
|
parts stay the primary list; each group is headed by the owning object's
|
||||||
|
name, so which pool a checkbox means is never a guess. */
|
||||||
|
.shared-pools {
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
.shared-pools > summary {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 2px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
.shared-pool-owner {
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
.field-help {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
.baseline-effective {
|
||||||
|
margin-top: 2px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
/* Live computed trigger hint — reads the bound sensor and explains what
|
||||||
|
happens next. Info-accented so it reads as guidance, not an error. */
|
||||||
|
.trigger-live-hint {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
border-left: 3px solid var(--info-color, #2196f3);
|
||||||
|
background: rgba(33, 150, 243, 0.08);
|
||||||
|
border-radius: 0 6px 6px 0;
|
||||||
|
padding: 6px 10px;
|
||||||
|
margin: 4px 0;
|
||||||
|
}
|
||||||
|
.field-help a,
|
||||||
|
.link-button {
|
||||||
|
background: none;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
color: var(--primary-color);
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.field-help a:hover,
|
||||||
|
.link-button:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
/* Smaller refresh icon-button when shown next to the dropdown. */
|
||||||
|
.select-row .link-button {
|
||||||
|
margin-left: 8px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.select-row .link-button:hover {
|
||||||
|
color: var(--primary-color);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
margin: 8px 0 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
.select-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.assignee-pool {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px 14px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
.checkbox-row {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 2px 0;
|
||||||
|
}
|
||||||
|
.checkbox-row input[type="checkbox"] {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.pool-item {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.pool-item input[type="checkbox"] {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.select-row label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
.select-row select {
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
background: var(--card-background-color, #fff);
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.field-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
.weekday-chips {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.weekday-chip {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 16px;
|
||||||
|
background: var(--card-background-color, #fff);
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.weekday-chip.selected {
|
||||||
|
background: var(--primary-color, #03a9f4);
|
||||||
|
color: var(--text-primary-color, #fff);
|
||||||
|
border-color: var(--primary-color, #03a9f4);
|
||||||
|
}
|
||||||
|
.season-chip {
|
||||||
|
padding: 6px 10px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 16px;
|
||||||
|
background: var(--card-background-color, #fff);
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.season-chip.selected {
|
||||||
|
background: var(--primary-color, #03a9f4);
|
||||||
|
color: var(--text-primary-color, #fff);
|
||||||
|
border-color: var(--primary-color, #03a9f4);
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: var(--error-color, #f44336);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.toggle-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
`,a([b({attribute:!1})],n.prototype,"hass",2),a([b({type:Boolean,attribute:"checklists-enabled"})],n.prototype,"checklistsEnabled",2),a([b({type:Boolean,attribute:"schedule-time-enabled"})],n.prototype,"scheduleTimeEnabled",2),a([b({type:Boolean,attribute:"completion-actions-enabled"})],n.prototype,"completionActionsEnabled",2),a([b({type:Number,attribute:"default-warning-days"})],n.prototype,"defaultWarningDays",2),a([o()],n.prototype,"parts",2),a([o()],n.prototype,"_foreignOwners",2),a([o()],n.prototype,"_open",2),a([o()],n.prototype,"_loading",2),a([o()],n.prototype,"_error",2),a([o()],n.prototype,"_entryId",2),a([o()],n.prototype,"_taskId",2),a([o()],n.prototype,"_objectChoices",2),a([o()],n.prototype,"_name",2),a([o()],n.prototype,"_type",2),a([o()],n.prototype,"_scheduleType",2),a([o()],n.prototype,"_intervalDays",2),a([o()],n.prototype,"_intervalUnit",2),a([o()],n.prototype,"_dueDate",2),a([o()],n.prototype,"_warningDays",2),a([o()],n.prototype,"_earliestCompletionDays",2),a([o()],n.prototype,"_intervalAnchor",2),a([o()],n.prototype,"_weekdays",2),a([o()],n.prototype,"_nth",2),a([o()],n.prototype,"_nthWeekday",2),a([o()],n.prototype,"_domDay",2),a([o()],n.prototype,"_domLastDay",2),a([o()],n.prototype,"_domBusiness",2),a([o()],n.prototype,"_calOffset",2),a([o()],n.prototype,"_seasonMonths",2),a([o()],n.prototype,"_endsMode",2),a([o()],n.prototype,"_endsCount",2),a([o()],n.prototype,"_endsUntil",2),a([o()],n.prototype,"_schedulePreview",2),a([o()],n.prototype,"_schedulePreviewEnded",2),a([o()],n.prototype,"_notes",2),a([o()],n.prototype,"_documentationUrl",2),a([o()],n.prototype,"_customIcon",2),a([o()],n.prototype,"_priority",2),a([o()],n.prototype,"_labels",2),a([o()],n.prototype,"_enabled",2),a([o()],n.prototype,"_triggerEntityId",2),a([o()],n.prototype,"_triggerEntityIds",2),a([o()],n.prototype,"_triggerEntityLogic",2),a([o()],n.prototype,"_triggerAttribute",2),a([o()],n.prototype,"_triggerType",2),a([o()],n.prototype,"_triggerAbove",2),a([o()],n.prototype,"_triggerBelow",2),a([o()],n.prototype,"_triggerForMinutes",2),a([o()],n.prototype,"_triggerTargetValue",2),a([o()],n.prototype,"_triggerDeltaMode",2),a([o()],n.prototype,"_triggerBaselineValue",2),a([o()],n.prototype,"_liveBaselineValue",2),a([o()],n.prototype,"_autoCompleteOnRecovery",2),a([o()],n.prototype,"_triggerFromState",2),a([o()],n.prototype,"_triggerToState",2),a([o()],n.prototype,"_triggerTargetChanges",2),a([o()],n.prototype,"_triggerRuntimeHours",2),a([o()],n.prototype,"_triggerOnStates",2),a([o()],n.prototype,"_compoundLogic",2),a([o()],n.prototype,"_compoundConditions",2),a([o()],n.prototype,"_suggestedAttributes",2),a([o()],n.prototype,"_availableAttributes",2),a([o()],n.prototype,"_entityDomain",2),a([o()],n.prototype,"_lastPerformed",2),a([o()],n.prototype,"_nfcTagId",2),a([o()],n.prototype,"_readingUnit",2),a([o()],n.prototype,"_consumesParts",2),a([o()],n.prototype,"_partsLoadFailed",2),a([o()],n.prototype,"_availableTags",2),a([o()],n.prototype,"_responsibleUserId",2),a([o()],n.prototype,"_assigneePool",2),a([o()],n.prototype,"_rotationStrategy",2),a([o()],n.prototype,"_availableUsers",2),a([o()],n.prototype,"_checklistText",2),a([o()],n.prototype,"_requiredCompletion",2),a([o()],n.prototype,"_scheduleTime",2),a([o()],n.prototype,"_actionService",2),a([o()],n.prototype,"_actionTargetEntity",2),a([o()],n.prototype,"_actionData",2),a([o()],n.prototype,"_actionDataJsonFallback",2),a([o()],n.prototype,"_actionTesting",2),a([o()],n.prototype,"_actionTestResult",2),a([o()],n.prototype,"_actionTestError",2),a([o()],n.prototype,"_qcNotes",2),a([o()],n.prototype,"_qcCost",2),a([o()],n.prototype,"_qcDuration",2),a([o()],n.prototype,"_qcFeedback",2),a([o()],n.prototype,"_environmentalEntity",2),a([o()],n.prototype,"_environmentalAttribute",2);var w=n;customElements.get("maintenance-task-dialog")||customElements.define("maintenance-task-dialog",w);export{w as MaintenanceTaskDialog};
|
||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import{a as v}from"./chunk-HQRBSDQ5.js";import{a as u,b as o,d as h,e as b,f as y,g as l,h as g,i as r,k as m,t as p}from"./chunk-2TCUV3FU.js";import{a as n}from"./chunk-7GA7XVGX.js";var x=80,s=class extends b{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?.language||"en"}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load(),m(this._lang).then(()=>this.requestUpdate()))}async _load(){try{let t=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/budget_status"});this._status=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=parseFloat(this._localMonthly),a=parseFloat(this._localYearly),i={};!isNaN(t)&&t>=0&&(i.budget_monthly=t),!isNaN(a)&&a>=0&&(i.budget_yearly=a),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,a=this._status;if(!a)return o`<ha-card><div class="loading">${r("loading",t)||"Loading\u2026"}</div></ha-card>`;let i=a.currency_symbol||g,_=a.alert_threshold_pct??x,f=[{label:r("budget_monthly",t)||"Monthly",spent:a.monthly_spent||0,budget:a.monthly_budget||0},{label:r("budget_yearly",t)||"Yearly",spent:a.yearly_spent||0,budget:a.yearly_budget||0}];return o`
|
||||||
|
<ha-card>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">
|
||||||
|
<span class="emoji">💰</span>
|
||||||
|
<span>${this._config.title||r("settings_budget",t)||"Budget"}</span>
|
||||||
|
</div>
|
||||||
|
<span class="currency">${i}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${this._error?o`<div class="error">${this._error}</div>`:h}
|
||||||
|
|
||||||
|
${f.map(e=>{if(!(e.budget>0))return o`
|
||||||
|
<div class="track spent-only">
|
||||||
|
<div class="track-label-row">
|
||||||
|
<label>${e.label}</label>
|
||||||
|
<span class="track-numbers ok">${e.spent.toFixed(0)} ${i}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;let d=Math.min(100,Math.max(0,e.spent/e.budget*100)),c=d>=100?"danger":d>=_?"warning":"ok";return o`
|
||||||
|
<div class="track">
|
||||||
|
<div class="track-label-row">
|
||||||
|
<label>${e.label}</label>
|
||||||
|
<span class="track-numbers ${c}">
|
||||||
|
${e.spent.toFixed(0)} / ${e.budget.toFixed(0)} ${i}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="bar"><div class="bar-fill ${c}" style="width:${d}%"></div></div>
|
||||||
|
</div>
|
||||||
|
`})}
|
||||||
|
|
||||||
|
${this._isAdmin?o`
|
||||||
|
<div class="inputs-row">
|
||||||
|
<div class="input-field">
|
||||||
|
<label>${r("budget_monthly_set",t)||"Set monthly"}</label>
|
||||||
|
<div class="input-wrap">
|
||||||
|
<input type="number" min="0" step="1"
|
||||||
|
.value=${this._localMonthly}
|
||||||
|
?disabled=${this._busy}
|
||||||
|
@input=${e=>{this._localMonthly=e.target.value,this._dirty=!0}} />
|
||||||
|
<span class="input-suffix">${i}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input-field">
|
||||||
|
<label>${r("budget_yearly_set",t)||"Set yearly"}</label>
|
||||||
|
<div class="input-wrap">
|
||||||
|
<input type="number" min="0" step="1"
|
||||||
|
.value=${this._localYearly}
|
||||||
|
?disabled=${this._busy}
|
||||||
|
@input=${e=>{this._localYearly=e.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?r("save",t)||"Save":r("saved",t)||"Saved"}
|
||||||
|
</button>
|
||||||
|
<button class="btn link" @click=${this._onDeepLink}>
|
||||||
|
${r("budget_advanced",t)||"Currency, alerts\u2026"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`:o`
|
||||||
|
<button class="btn link" @click=${this._onDeepLink}>
|
||||||
|
${r("budget_open_panel",t)||"Open in panel"}
|
||||||
|
</button>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`}};s.styles=[v,u`
|
||||||
|
.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([y({attribute:!1})],s.prototype,"hass",2),n([l()],s.prototype,"_config",2),n([l()],s.prototype,"_status",2),n([l()],s.prototype,"_busy",2),n([l()],s.prototype,"_error",2),n([l()],s.prototype,"_localMonthly",2),n([l()],s.prototype,"_localYearly",2),n([l()],s.prototype,"_dirty",2);customElements.get("maintenance-budget-section-card")||customElements.define("maintenance-budget-section-card",s);window.customCards=window.customCards||[];window.customCards.push({type:"maintenance-budget-section-card",name:"Maintenance Supporter \u2014 Budget",description:"Inline monthly + yearly budget editor",preview:!1});export{s as MaintenanceBudgetSectionCard};
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,2 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.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.54.0 */
|
||||||
|
import{a as r}from"./chunk-2TCUV3FU.js";var a=r`
|
||||||
|
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{a};
|
||||||
+2453
File diff suppressed because it is too large.
Load diff
+137
@@ -0,0 +1,137 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import{a as m}from"./chunk-HQRBSDQ5.js";import{a as u,b as s,d as l,e as h,f as g,g as o,i,k as _,t as p}from"./chunk-2TCUV3FU.js";import{a}from"./chunk-7GA7XVGX.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?.language||"en"}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(),_(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)||'Delete group "{name}"?').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)||"Loading\u2026"}</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)||"Groups"}</span>
|
||||||
|
<span class="count">${r.length}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${this._error?s`<div class="error">${this._error}</div>`:l}
|
||||||
|
|
||||||
|
${r.length===0?s`<div class="empty">${i("groups_empty",t)||"No groups yet."}</div>`:s`
|
||||||
|
<div class="group-list">
|
||||||
|
${r.map(n=>{let d=this._groups[n],v=d.task_refs?.length??0,b=this._editingId===n;return s`
|
||||||
|
<div class="group-row">
|
||||||
|
${b?s`
|
||||||
|
<input class="edit-input" type="text"
|
||||||
|
.value=${this._editingName}
|
||||||
|
?disabled=${this._busy}
|
||||||
|
@input=${c=>{this._editingName=c.target.value}}
|
||||||
|
@keydown=${c=>this._onKeyDown(c,this._saveEdit.bind(this))} />
|
||||||
|
<button class="btn small primary"
|
||||||
|
@click=${this._saveEdit}
|
||||||
|
?disabled=${this._busy||!this._editingName.trim()}>
|
||||||
|
${i("save",t)||"Save"}
|
||||||
|
</button>
|
||||||
|
<button class="btn small"
|
||||||
|
@click=${()=>{this._editingId=null}}>
|
||||||
|
${i("cancel",t)||"Cancel"}
|
||||||
|
</button>
|
||||||
|
`:s`
|
||||||
|
<span class="group-name">${d.name||"Unnamed"}</span>
|
||||||
|
<span class="task-count">${v}</span>
|
||||||
|
${this._isAdmin?s`
|
||||||
|
<button class="icon-btn"
|
||||||
|
title="${i("edit",t)||"Edit"}"
|
||||||
|
@click=${()=>this._startEdit(n)}
|
||||||
|
?disabled=${this._busy}>
|
||||||
|
<ha-icon icon="mdi:pencil"></ha-icon>
|
||||||
|
</button>
|
||||||
|
<button class="icon-btn danger"
|
||||||
|
title="${i("delete",t)||"Delete"}"
|
||||||
|
@click=${()=>this._deleteGroup(n,d.name||"Unnamed")}
|
||||||
|
?disabled=${this._busy}>
|
||||||
|
<ha-icon icon="mdi:delete"></ha-icon>
|
||||||
|
</button>
|
||||||
|
`:l}
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
`})}
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
|
||||||
|
${this._isAdmin?s`
|
||||||
|
<div class="add-row">
|
||||||
|
<input type="text"
|
||||||
|
placeholder="${i("group_new_placeholder",t)||"Add group\u2026"}"
|
||||||
|
.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)||"Add"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button class="btn link" @click=${this._onDeepLink}>
|
||||||
|
${i("groups_manage_tasks",t)||"Manage task assignments\u2026"}
|
||||||
|
</button>
|
||||||
|
`:s`
|
||||||
|
<button class="btn link" @click=${this._onDeepLink}>
|
||||||
|
${i("groups_open_panel",t)||"Open in panel"}
|
||||||
|
</button>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`}};e.styles=[m,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);window.customCards=window.customCards||[];window.customCards.push({type:"maintenance-groups-section-card",name:"Maintenance Supporter \u2014 Groups",description:"Inline group CRUD",preview:!1});export{e as MaintenanceGroupsSectionCard};
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
|
import{a as m}from"./chunk-HQRBSDQ5.js";import{a as h,b as n,d as c,e as _,f as v,g as r,i as e,k as f,t as l}from"./chunk-2TCUV3FU.js";import{a as i}from"./chunk-7GA7XVGX.js";var a=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 this.hass?.language||"en"}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load(),f(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=l(t,this._lang)}}async _toggleEnabled(t){this._busy=!0,this._error="";try{let s=await this.hass.connection.sendMessagePromise({type:"maintenance_supporter/vacation/update",enabled:t});this._state=s}catch(s){this._error=l(s,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=l(t,this._lang)}finally{this._busy=!1}}}async _endNow(){if(this._isAdmin&&window.confirm(e("vacation_end_now_confirm",this._lang)||"End vacation immediately?")){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=l(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,s=this._state;if(!s)return n`<ha-card><div class="loading">${e("loading",t)||"Loading\u2026"}</div></ha-card>`;let p=s.is_active===!0,d=s.enabled===!0,u=s.exempt_task_ids?.length??0,b=p?e("vacation_status_active",t)||"Active now":d?e("vacation_status_scheduled",t)||"Scheduled":e("vacation_status_inactive",t)||"Inactive",g=p?"active":d?"scheduled":"inactive";return n`
|
||||||
|
<ha-card>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">
|
||||||
|
<span class="emoji">🏖️</span>
|
||||||
|
<span>${this._config.title||e("vacation_mode",t)||"Vacation mode"}</span>
|
||||||
|
</div>
|
||||||
|
<span class="status-pill ${g}">${b}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${this._error?n`<div class="error">${this._error}</div>`:c}
|
||||||
|
|
||||||
|
${this._isAdmin?n`
|
||||||
|
<div class="row toggle-row">
|
||||||
|
<label>${e("enable",t)||"Enable"}</label>
|
||||||
|
<ha-switch
|
||||||
|
.checked=${d}
|
||||||
|
.disabled=${this._busy}
|
||||||
|
@change=${o=>this._toggleEnabled(o.target.checked)}
|
||||||
|
></ha-switch>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dates-row">
|
||||||
|
<div class="date-field">
|
||||||
|
<label>${e("vacation_start",t)||"Start"}</label>
|
||||||
|
<input type="date" .value=${this._localStart}
|
||||||
|
?disabled=${this._busy}
|
||||||
|
@input=${o=>{this._localStart=o.target.value,this._dirty=!0}} />
|
||||||
|
</div>
|
||||||
|
<div class="date-field">
|
||||||
|
<label>${e("vacation_end",t)||"End"}</label>
|
||||||
|
<input type="date" .value=${this._localEnd}
|
||||||
|
?disabled=${this._busy}
|
||||||
|
@input=${o=>{this._localEnd=o.target.value,this._dirty=!0}} />
|
||||||
|
</div>
|
||||||
|
<div class="date-field buffer">
|
||||||
|
<label>${e("vacation_buffer",t)||"Buffer days"}</label>
|
||||||
|
<input type="number" min="0" max="14"
|
||||||
|
.value=${String(this._localBuffer)}
|
||||||
|
?disabled=${this._busy}
|
||||||
|
@input=${o=>{this._localBuffer=parseInt(o.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)||"Save":e("saved",t)||"Saved"}
|
||||||
|
</button>
|
||||||
|
${p?n`<button class="btn"
|
||||||
|
@click=${this._endNow}
|
||||||
|
?disabled=${this._busy}>
|
||||||
|
${e("vacation_end_now",t)||"End now"}
|
||||||
|
</button>`:c}
|
||||||
|
${u>0?n`<button class="btn link"
|
||||||
|
@click=${this._onDeepLink}>
|
||||||
|
${u} ${e("vacation_exempt_count",t)||"exempt"}…
|
||||||
|
</button>`:n`<button class="btn link"
|
||||||
|
@click=${this._onDeepLink}>
|
||||||
|
${e("vacation_advanced",t)||"Advanced\u2026"}
|
||||||
|
</button>`}
|
||||||
|
</div>
|
||||||
|
`:n`
|
||||||
|
<div class="readonly">
|
||||||
|
${d&&s.start&&s.end?n`<div>${s.start} → ${s.end}</div>`:c}
|
||||||
|
<button class="btn link" @click=${this._onDeepLink}>
|
||||||
|
${e("vacation_open_panel",t)||"Open in panel"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`}};a.styles=[m,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})],a.prototype,"hass",2),i([r()],a.prototype,"_config",2),i([r()],a.prototype,"_state",2),i([r()],a.prototype,"_busy",2),i([r()],a.prototype,"_error",2),i([r()],a.prototype,"_localStart",2),i([r()],a.prototype,"_localEnd",2),i([r()],a.prototype,"_localBuffer",2),i([r()],a.prototype,"_dirty",2);customElements.get("maintenance-vacation-section-card")||customElements.define("maintenance-vacation-section-card",a);window.customCards=window.customCards||[];window.customCards.push({type:"maintenance-vacation-section-card",name:"Maintenance Supporter \u2014 Vacation",description:"Inline vacation mode toggle + dates",preview:!1});export{a as MaintenanceVacationSectionCard};
|
||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
/*! maintenance_supporter frontend 2.53.0 */
|
/*! maintenance_supporter frontend 2.54.0 */
|
||||||
import{c as y}from"./chunks/chunk-5HT73ALV.js";var L="maintenance-supporter",G=`ll-strategy-dashboard-${L}`,x="hui-maintenance-supporter-strategy-editor",V="NOT_RUNNING",H=[{status:"overdue",title:"Overdue",icon:y.overdue,path:"overdue"},{status:"triggered",title:"Triggered",icon:y.triggered,path:"triggered"},{status:"due_soon",title:"Due Soon",icon:y.due_soon,path:"due-soon"},{status:"ok",title:"OK",icon:y.ok,path:"ok"}],E=[{title:"Overdue",icon:"mdi:alert-circle",path:"overdue",filter:{filter_due_max_days:-1},matches:n=>n<=-1},{title:"Today",icon:"mdi:calendar-today",path:"today",filter:{filter_due_min_days:0,filter_due_max_days:0},matches:n=>n===0},{title:"This Week",icon:"mdi:calendar-week",path:"this-week",filter:{filter_due_min_days:1,filter_due_max_days:7},matches:n=>n>=1&&n<=7},{title:"This Month",icon:"mdi:calendar-month",path:"this-month",filter:{filter_due_min_days:8,filter_due_max_days:30},matches:n=>n>=8&&n<=30},{title:"Later",icon:"mdi:calendar-clock",path:"later",filter:{filter_due_min_days:31},matches:n=>n>=31}];function l(n){return{type:"grid",cards:[n]}}var N={condition:"view_columns",min:2};function _(n,i,e){let s=i[n];if(s)return`{{ states('${s}') }}`;let t=e[n];return t==null?"\u2014":String(t)}function B(n={},i={}){return{type:"markdown",text_only:!0,content:[`\u{1F534} **${_("overdue",n,i)}** overdue`,`\u26A1 **${_("triggered",n,i)}** triggered`,`\u{1F7E1} **${_("due_soon",n,i)}** due soon`,`\u{1F7E2} **${_("ok",n,i)}** ok`].join(" \xB7 ")}}function $(){return{title:"Maintenance",type:"panel",cards:[{type:"empty-state",icon:"mdi:wrench-clock",icon_color:"primary",content_only:!0,title:"No maintenance objects yet",content:"Open the Maintenance panel to add your first object \u2014 pool pump, HVAC filter, vehicle, anything that needs scheduled care.",buttons:[{icon:"mdi:wrench",text:"Open Maintenance panel",appearance:"filled",variant:"brand",tap_action:{action:"navigate",navigation_path:"/maintenance-supporter"}},{icon:"mdi:plus",text:"Add object",appearance:"outlined",variant:"brand",tap_action:{action:"fire-dom-event",ll_custom:{type:"maintenance-supporter:add-object"}}}]}]}}function U(n={},i={}){let e=B(n,i);return{title:"Overview",icon:"mdi:wrench-clock",path:"overview",type:"sections",header:{layout:"responsive",card:e},sidebar:{sections:[{type:"grid",cards:[{type:"heading",heading:"Status",heading_style:"title"},e]}],visibility:[N],content_label:"Tasks",sidebar_label:"Status"},sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:["overdue","triggered","due_soon"]})]}}function W(n,i){let e=new Map;for(let a of n){let r=a.object.area_id||null;e.has(r)||e.set(r,[]),e.get(r).push(a)}let s=Array.from(e.keys()).filter(a=>a!==null);s.sort((a,r)=>{let d=i[a]?.name||a,c=i[r]?.name||r;return d.localeCompare(c)});let t=[];for(let a of s){let r=e.get(a);if(r.length===0)continue;let d=i[a];t.push({title:d?.name||a,icon:d?.icon||"mdi:floor-plan",path:`area-${a}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:r.map(c=>c.object.name)})]})}let o=e.get(null);return o&&o.length>0&&t.push({title:"Unassigned",icon:"mdi:help-circle-outline",path:"unassigned",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:o.map(a=>a.object.name)})]}),t}function Y(n){let i=new Set;for(let s of n)for(let t of s.tasks||[])t.status&&i.add(t.status);let e=[];for(let s of H)i.has(s.status)&&e.push({title:s.title,icon:s.icon,path:s.path,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:[s.status]})]});return e}function F(n,i,e){let s=new Map;for(let r of n){let d=r.object.area_id,c=d&&i[d]?.floor_id||null;s.has(c)||s.set(c,[]),s.get(c).push(r)}let t=Array.from(s.keys()).filter(r=>r!==null);t.sort((r,d)=>{let c=e[r],g=e[d],u=c?.level??0,p=g?.level??0;return u!==p?u-p:(c?.name||r).localeCompare(g?.name||d)});let o=[];for(let r of t){let d=s.get(r);if(d.length===0)continue;let c=e[r];o.push({title:c?.name||r,icon:c?.icon||"mdi:home-floor-1",path:`floor-${r}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:d.map(g=>g.object.name)})]})}let a=s.get(null);return a&&a.length>0&&o.push({title:"Other",icon:"mdi:help-circle-outline",path:"other",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:a.map(r=>r.object.name)})]}),o}function K(n){return[{title:"Week",icon:"mdi:calendar-week",path:"cal-7",window_days:7},{title:"Fortnight",icon:"mdi:calendar-week-begin",path:"cal-14",window_days:14},{title:"Month",icon:"mdi:calendar-month",path:"cal-30",window_days:30},{title:"Year",icon:"mdi:calendar-clock",path:"cal-365",window_days:365}].map(e=>({title:e.title,icon:e.icon,path:e.path,type:"panel",cards:[{type:"custom:maintenance-supporter-calendar-card",window_days:e.window_days,show_window_chips:!1,show_user_filter:!0}]}))}function q(n){let i=new Set;for(let sLine truncated
|
import{c as y}from"./chunks/chunk-7GA7XVGX.js";var L="maintenance-supporter",G=`ll-strategy-dashboard-${L}`,x="hui-maintenance-supporter-strategy-editor",V="NOT_RUNNING",H=[{status:"overdue",title:"Overdue",icon:y.overdue,path:"overdue"},{status:"triggered",title:"Triggered",icon:y.triggered,path:"triggered"},{status:"due_soon",title:"Due Soon",icon:y.due_soon,path:"due-soon"},{status:"ok",title:"OK",icon:y.ok,path:"ok"}],E=[{title:"Overdue",icon:"mdi:alert-circle",path:"overdue",filter:{filter_due_max_days:-1},matches:n=>n<=-1},{title:"Today",icon:"mdi:calendar-today",path:"today",filter:{filter_due_min_days:0,filter_due_max_days:0},matches:n=>n===0},{title:"This Week",icon:"mdi:calendar-week",path:"this-week",filter:{filter_due_min_days:1,filter_due_max_days:7},matches:n=>n>=1&&n<=7},{title:"This Month",icon:"mdi:calendar-month",path:"this-month",filter:{filter_due_min_days:8,filter_due_max_days:30},matches:n=>n>=8&&n<=30},{title:"Later",icon:"mdi:calendar-clock",path:"later",filter:{filter_due_min_days:31},matches:n=>n>=31}];function l(n){return{type:"grid",cards:[n]}}var N={condition:"view_columns",min:2};function _(n,i,e){let s=i[n];if(s)return`{{ states('${s}') }}`;let t=e[n];return t==null?"\u2014":String(t)}function B(n={},i={}){return{type:"markdown",text_only:!0,content:[`\u{1F534} **${_("overdue",n,i)}** overdue`,`\u26A1 **${_("triggered",n,i)}** triggered`,`\u{1F7E1} **${_("due_soon",n,i)}** due soon`,`\u{1F7E2} **${_("ok",n,i)}** ok`].join(" \xB7 ")}}function $(){return{title:"Maintenance",type:"panel",cards:[{type:"empty-state",icon:"mdi:wrench-clock",icon_color:"primary",content_only:!0,title:"No maintenance objects yet",content:"Open the Maintenance panel to add your first object \u2014 pool pump, HVAC filter, vehicle, anything that needs scheduled care.",buttons:[{icon:"mdi:wrench",text:"Open Maintenance panel",appearance:"filled",variant:"brand",tap_action:{action:"navigate",navigation_path:"/maintenance-supporter"}},{icon:"mdi:plus",text:"Add object",appearance:"outlined",variant:"brand",tap_action:{action:"fire-dom-event",ll_custom:{type:"maintenance-supporter:add-object"}}}]}]}}function U(n={},i={}){let e=B(n,i);return{title:"Overview",icon:"mdi:wrench-clock",path:"overview",type:"sections",header:{layout:"responsive",card:e},sidebar:{sections:[{type:"grid",cards:[{type:"heading",heading:"Status",heading_style:"title"},e]}],visibility:[N],content_label:"Tasks",sidebar_label:"Status"},sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:["overdue","triggered","due_soon"]})]}}function W(n,i){let e=new Map;for(let a of n){let r=a.object.area_id||null;e.has(r)||e.set(r,[]),e.get(r).push(a)}let s=Array.from(e.keys()).filter(a=>a!==null);s.sort((a,r)=>{let d=i[a]?.name||a,c=i[r]?.name||r;return d.localeCompare(c)});let t=[];for(let a of s){let r=e.get(a);if(r.length===0)continue;let d=i[a];t.push({title:d?.name||a,icon:d?.icon||"mdi:floor-plan",path:`area-${a}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:r.map(c=>c.object.name)})]})}let o=e.get(null);return o&&o.length>0&&t.push({title:"Unassigned",icon:"mdi:help-circle-outline",path:"unassigned",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:o.map(a=>a.object.name)})]}),t}function Y(n){let i=new Set;for(let s of n)for(let t of s.tasks||[])t.status&&i.add(t.status);let e=[];for(let s of H)i.has(s.status)&&e.push({title:s.title,icon:s.icon,path:s.path,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_status:[s.status]})]});return e}function F(n,i,e){let s=new Map;for(let r of n){let d=r.object.area_id,c=d&&i[d]?.floor_id||null;s.has(c)||s.set(c,[]),s.get(c).push(r)}let t=Array.from(s.keys()).filter(r=>r!==null);t.sort((r,d)=>{let c=e[r],g=e[d],u=c?.level??0,p=g?.level??0;return u!==p?u-p:(c?.name||r).localeCompare(g?.name||d)});let o=[];for(let r of t){let d=s.get(r);if(d.length===0)continue;let c=e[r];o.push({title:c?.name||r,icon:c?.icon||"mdi:home-floor-1",path:`floor-${r}`,type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:d.map(g=>g.object.name)})]})}let a=s.get(null);return a&&a.length>0&&o.push({title:"Other",icon:"mdi:help-circle-outline",path:"other",type:"sections",sections:[l({type:"custom:maintenance-supporter-card",show_header:!1,filter_objects:a.map(r=>r.object.name)})]}),o}function K(n){return[{title:"Week",icon:"mdi:calendar-week",path:"cal-7",window_days:7},{title:"Fortnight",icon:"mdi:calendar-week-begin",path:"cal-14",window_days:14},{title:"Month",icon:"mdi:calendar-month",path:"cal-30",window_days:30},{title:"Year",icon:"mdi:calendar-clock",path:"cal-365",window_days:365}].map(e=>({title:e.title,icon:e.icon,path:e.path,type:"panel",cards:[{type:"custom:maintenance-supporter-calendar-card",window_days:e.window_days,show_window_chips:!1,show_user_filter:!0}]}))}function q(n){let i=new Set;for(let sLine truncated
|
||||||
<style>
|
<style>
|
||||||
:host, .editor { display: block; padding: 16px 0; }
|
:host, .editor { display: block; padding: 16px 0; }
|
||||||
label { display: block; font-weight: 500; margin-bottom: 8px; }
|
label { display: block; font-weight: 500; margin-bottom: 8px; }
|
||||||
@@ -22,4 +22,4 @@ import{c as y}from"./chunks/chunk-5HT73ALV.js";var L="maintenance-supporter",G=`
|
|||||||
The "Overview" view is always first. Empty groups are skipped.
|
The "Overview" view is always first. Empty groups are skipped.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;let t=this.querySelector("#group-by");t?.addEventListener("change",()=>{let o={...this._config,group_by:t.value};this._config=o,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:o},bubbles:!0,composed:!0}))})}},I="maintenance-supporter-section",Q=`ll-strategy-section-${I}`,v=class extends HTMLElement{static async generate(i,e){let s={type:"custom:maintenance-supporter-card",show_header:!1};i?.filter_status?.length&&(s.filter_status=i.filter_status),i?.max_items&&(s.max_items=i.max_items),i?.filter_due_min_days!==void 0&&(s.filter_due_min_days=i.filter_due_min_days),i?.filter_due_max_days!==void 0&&(s.filter_due_max_days=i.filter_due_max_days);let t=i?.filter_objects;if(i?.area_id&&!t)try{t=((await e.connection.sendMessagePromise({type:"maintenance_supporter/objects"})).objects||[]).filter(r=>r.object.area_id===i.area_id).map(r=>r.object.name)}catch{}t&&t.length>0&&(s.filter_objects=t);let o=[];return i?.title&&o.push({type:"heading",heading:i.title,heading_style:"title"}),o.push(s),{type:"grid",cards:o}}},D="2.3.6",X="[maintenance-supporter]";function M(n,i){try{return customElements.get(n)?"skipped":(customElements.define(n,i),"ok")}catch(e){return`ERROR: ${String(e)}`}}var P={editor:M(x,w),section:M(Q,v)};console.log(`${X} strategy bundle v${D} loaded \u2014 registrations:`,P,"\u2014 run maintenanceSupporterDiagnose() in console for full state");window.maintenanceSupporterDiagnose=async()=>{let n=G,i=[];try{let e=document.querySelector("home-assistant");e?.hass&&(i=(await e.hass.connection.sendMessagePromise({type:"lovelace/resources"})).resources||[])}catch(e){i=[{url:`<error: ${String(e)}>`}]}return{version:D,el_registered:!!customElements.get(n),el_class_excerpt:customElements.get(n)?.toString().slice(0,100)||null,customStrategies_dashboard:window.customStrategies?.filter(e=>e.strategyType==="dashboard").map(e=>e.type)||[],scriptTagsInPage:Array.from(document.querySelectorAll("script[type=module]")).map(e=>e.src).filter(e=>/maint|strateg/i.test(e)),lovelaceResources_matching:i.filter(e=>/maint|strateg/i.test(e.url||"")).map(e=>e.url),registrations:P}};var k=class extends HTMLElement{static async generate(i,e){return await import("./chunks/vacation-section-card-CRAL2J5R.js"),{type:"grid",cards:[{type:"custom:maintenance-vacation-section-card",title:i?.title}]}}},C=class extends HTMLElement{static async generate(i,e){return await import("./chunks/budget-section-card-HV65MOOG.js"),{type:"grid",cards:[{type:"custom:maintenance-budget-section-card",title:i?.title}]}}},S=class extends HTMLElement{static async generate(i,e){return await import("./chunks/groups-section-card-XIGNRWQ6.js"),{type:"grid",cards:[{type:"custom:maintenance-groups-section-card",title:i?.title}]}}},j="ll-strategy-section-maintenance-supporter-vacation",R="ll-strategy-section-maintenance-supporter-budget",A="ll-strategy-section-maintenance-supporter-groups";customElements.get(j)||customElements.define(j,k);customElements.get(R)||customElements.define(R,C);customElements.get(A)||customElements.define(A,S);var h=null;function J(){return h||(h=import("./chunks/dialog-mount-ZDXPVJWH.js").catch(n=>{throw h=null,n})),h}var O="_msSupporterLlCustomBound";function m(n){history.pushState(null,"",n),window.dispatchEvent(new CustomEvent("location-changed"))}function Z(){let n=window;n[O]||(n[O]=!0,document.addEventListener("ll-custom",i=>{let e=i.detail;if(!e||typeof e!="object")return;let s=e.ll_custom,t=s&&typeof s=="object"?s:e;if(!t||typeof t.type!="string"||!t.type.startsWith("maintenance-supporter:"))return;let o=t.type.slice(22);if(o==="deep-link"&&typeof t.path=="string"){m(t.path);return}(async()=>{let a;try{a=await J()}catch{m("/maintenance-supporter");return}if(o==="add-object"){if(a.openCreateObjectDialog())return;m("/maintenance-supporter?ms_action=add_object");return}if(o==="open-task"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"){if(a.openTaskQuickActions(t.entry_id,t.task_id)||a.openEditTaskDialog(t.entry_id,t.task_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}&task_id=${encodeURIComponent(t.task_id)}`);return}if(o==="open-object"&&typeof t.entry_id=="string"){if(a.openObjectQuickActions(t.entry_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}`);return}if(o==="edit-history"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"&&typeof t.original_timestamp=="string"){let d=document.querySelector("home-assistant")?.hass;if(!d)return;try{let u=(await d.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:t.entry_id})).tasks?.find(p=>p.id===t.task_id)?.history?.find(p=>p.timestamp===t.original_timestamp);if(!u)return;a.openHistoryEditDialog({entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.original_timestamp,type:u.type||"completed",timestamp:u.timestamp||t.original_timestamp,notes:u.notes??null,cost:u.cost??null,duration:u.duration??null,completed_by:u.completed_by??null})}catch{m("/maintenance-suppor
Line truncated
|
`;let t=this.querySelector("#group-by");t?.addEventListener("change",()=>{let o={...this._config,group_by:t.value};this._config=o,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:o},bubbles:!0,composed:!0}))})}},I="maintenance-supporter-section",Q=`ll-strategy-section-${I}`,v=class extends HTMLElement{static async generate(i,e){let s={type:"custom:maintenance-supporter-card",show_header:!1};i?.filter_status?.length&&(s.filter_status=i.filter_status),i?.max_items&&(s.max_items=i.max_items),i?.filter_due_min_days!==void 0&&(s.filter_due_min_days=i.filter_due_min_days),i?.filter_due_max_days!==void 0&&(s.filter_due_max_days=i.filter_due_max_days);let t=i?.filter_objects;if(i?.area_id&&!t)try{t=((await e.connection.sendMessagePromise({type:"maintenance_supporter/objects"})).objects||[]).filter(r=>r.object.area_id===i.area_id).map(r=>r.object.name)}catch{}t&&t.length>0&&(s.filter_objects=t);let o=[];return i?.title&&o.push({type:"heading",heading:i.title,heading_style:"title"}),o.push(s),{type:"grid",cards:o}}},D="2.3.6",X="[maintenance-supporter]";function M(n,i){try{return customElements.get(n)?"skipped":(customElements.define(n,i),"ok")}catch(e){return`ERROR: ${String(e)}`}}var P={editor:M(x,w),section:M(Q,v)};console.log(`${X} strategy bundle v${D} loaded \u2014 registrations:`,P,"\u2014 run maintenanceSupporterDiagnose() in console for full state");window.maintenanceSupporterDiagnose=async()=>{let n=G,i=[];try{let e=document.querySelector("home-assistant");e?.hass&&(i=(await e.hass.connection.sendMessagePromise({type:"lovelace/resources"})).resources||[])}catch(e){i=[{url:`<error: ${String(e)}>`}]}return{version:D,el_registered:!!customElements.get(n),el_class_excerpt:customElements.get(n)?.toString().slice(0,100)||null,customStrategies_dashboard:window.customStrategies?.filter(e=>e.strategyType==="dashboard").map(e=>e.type)||[],scriptTagsInPage:Array.from(document.querySelectorAll("script[type=module]")).map(e=>e.src).filter(e=>/maint|strateg/i.test(e)),lovelaceResources_matching:i.filter(e=>/maint|strateg/i.test(e.url||"")).map(e=>e.url),registrations:P}};var k=class extends HTMLElement{static async generate(i,e){return await import("./chunks/vacation-section-card-RNXXYKC4.js"),{type:"grid",cards:[{type:"custom:maintenance-vacation-section-card",title:i?.title}]}}},C=class extends HTMLElement{static async generate(i,e){return await import("./chunks/budget-section-card-2AH3BUZO.js"),{type:"grid",cards:[{type:"custom:maintenance-budget-section-card",title:i?.title}]}}},S=class extends HTMLElement{static async generate(i,e){return await import("./chunks/groups-section-card-S5KXJ7RS.js"),{type:"grid",cards:[{type:"custom:maintenance-groups-section-card",title:i?.title}]}}},j="ll-strategy-section-maintenance-supporter-vacation",R="ll-strategy-section-maintenance-supporter-budget",A="ll-strategy-section-maintenance-supporter-groups";customElements.get(j)||customElements.define(j,k);customElements.get(R)||customElements.define(R,C);customElements.get(A)||customElements.define(A,S);var h=null;function J(){return h||(h=import("./chunks/dialog-mount-EBWEVGD6.js").catch(n=>{throw h=null,n})),h}var O="_msSupporterLlCustomBound";function m(n){history.pushState(null,"",n),window.dispatchEvent(new CustomEvent("location-changed"))}function Z(){let n=window;n[O]||(n[O]=!0,document.addEventListener("ll-custom",i=>{let e=i.detail;if(!e||typeof e!="object")return;let s=e.ll_custom,t=s&&typeof s=="object"?s:e;if(!t||typeof t.type!="string"||!t.type.startsWith("maintenance-supporter:"))return;let o=t.type.slice(22);if(o==="deep-link"&&typeof t.path=="string"){m(t.path);return}(async()=>{let a;try{a=await J()}catch{m("/maintenance-supporter");return}if(o==="add-object"){if(a.openCreateObjectDialog())return;m("/maintenance-supporter?ms_action=add_object");return}if(o==="open-task"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"){if(a.openTaskQuickActions(t.entry_id,t.task_id)||a.openEditTaskDialog(t.entry_id,t.task_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}&task_id=${encodeURIComponent(t.task_id)}`);return}if(o==="open-object"&&typeof t.entry_id=="string"){if(a.openObjectQuickActions(t.entry_id))return;m(`/maintenance-supporter?entry_id=${encodeURIComponent(t.entry_id)}`);return}if(o==="edit-history"&&typeof t.entry_id=="string"&&typeof t.task_id=="string"&&typeof t.original_timestamp=="string"){let d=document.querySelector("home-assistant")?.hass;if(!d)return;try{let u=(await d.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:t.entry_id})).tasks?.find(p=>p.id===t.task_id)?.history?.find(p=>p.timestamp===t.original_timestamp);if(!u)return;a.openHistoryEditDialog({entry_id:t.entry_id,task_id:t.task_id,original_timestamp:t.original_timestamp,type:u.type||"completed",timestamp:u.timestamp||t.original_timestamp,notes:u.notes??null,cost:u.cost??null,duration:u.duration??null,completed_by:u.completed_by??null})}catch{m("/maintenance-suppor
Line truncated
|
||||||
@@ -22,5 +22,5 @@
|
|||||||
"requirements": [
|
"requirements": [
|
||||||
"pypdf>=4.3.0"
|
"pypdf>=4.3.0"
|
||||||
],
|
],
|
||||||
"version": "2.53.0"
|
"version": "2.54.0"
|
||||||
}
|
}
|
||||||
@@ -306,11 +306,13 @@ async def _async_require_admin(hass: HomeAssistant, call: ServiceCall) -> None:
|
|||||||
async def _async_require_parent(hass: HomeAssistant, call: ServiceCall) -> None:
|
async def _async_require_parent(hass: HomeAssistant, call: ServiceCall) -> None:
|
||||||
"""Reject user-initiated calls that aren't from an admin or a TaskMate parent.
|
"""Reject user-initiated calls that aren't from an admin or a TaskMate parent.
|
||||||
|
|
||||||
Day-to-day parent actions (approve/reject, gift/adjust points, confirm
|
Day-to-day parent actions (approve/reject, gift/adjust points, apply a
|
||||||
rewards/allowance, award badges, complete-as-parent) accept non-admin HA
|
bonus or penalty, confirm rewards/allowance, award badges,
|
||||||
users listed in ``parent_user_ids`` (issue #661). Context-less calls
|
complete-as-parent) accept non-admin HA users listed in ``parent_user_ids``
|
||||||
(automations, scripts) pass. Structural config stays on
|
(issue #661). Context-less calls (automations, scripts) pass. Structural
|
||||||
``_async_require_admin``.
|
config — including *defining* bonuses and penalties — stays on
|
||||||
|
``_async_require_admin``; only applying an existing one is a parent action
|
||||||
|
(issue #749).
|
||||||
"""
|
"""
|
||||||
if not call.context.user_id:
|
if not call.context.user_id:
|
||||||
return
|
return
|
||||||
@@ -1324,7 +1326,7 @@ async def _async_register_services(hass: HomeAssistant) -> None:
|
|||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_REMOVE_POINTS,
|
SERVICE_REMOVE_POINTS,
|
||||||
_admin(handle_remove_points),
|
_parent(handle_remove_points),
|
||||||
schema=vol.Schema(
|
schema=vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Required(ATTR_CHILD_ID): cv.string,
|
vol.Required(ATTR_CHILD_ID): cv.string,
|
||||||
@@ -1399,7 +1401,7 @@ async def _async_register_services(hass: HomeAssistant) -> None:
|
|||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_APPLY_PENALTY,
|
SERVICE_APPLY_PENALTY,
|
||||||
_admin(handle_apply_penalty),
|
_parent(handle_apply_penalty),
|
||||||
schema=vol.Schema({
|
schema=vol.Schema({
|
||||||
vol.Required(ATTR_PENALTY_ID): cv.string,
|
vol.Required(ATTR_PENALTY_ID): cv.string,
|
||||||
vol.Required(ATTR_CHILD_ID): cv.string,
|
vol.Required(ATTR_CHILD_ID): cv.string,
|
||||||
@@ -1443,7 +1445,7 @@ async def _async_register_services(hass: HomeAssistant) -> None:
|
|||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_APPLY_BONUS,
|
SERVICE_APPLY_BONUS,
|
||||||
_admin(handle_apply_bonus),
|
_parent(handle_apply_bonus),
|
||||||
schema=vol.Schema({
|
schema=vol.Schema({
|
||||||
vol.Required(ATTR_BONUS_ID): cv.string,
|
vol.Required(ATTR_BONUS_ID): cv.string,
|
||||||
vol.Required(ATTR_CHILD_ID): cv.string,
|
vol.Required(ATTR_CHILD_ID): cv.string,
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loaded 100 of 119 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user