Skip to content

Commit 3d540d5

Browse files
committed
revert: remove before/after chart preview (bump to 0.1.19)
1 parent d8351eb commit 3d540d5

2 files changed

Lines changed: 2 additions & 174 deletions

File tree

custom_components/statistics_outlier_cleaner/frontend/statistics-outlier-cleaner-panel.js

Lines changed: 1 addition & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -424,13 +424,6 @@ const STYLES = `
424424
}
425425
.apply-summary strong { color: var(--error-color, #db4437); }
426426
code { font-family: monospace; background: var(--secondary-background-color, #f5f5f5); padding: 1px 4px; border-radius: 3px; font-size: 0.85em; }
427-
#chart-container {
428-
margin: 0 0 14px;
429-
}
430-
#chart-container ha-chart-base {
431-
display: block;
432-
width: 100%;
433-
}
434427
`;
435428

436429
class StatisticsOutlierCleanerPanel extends HTMLElement {
@@ -447,10 +440,6 @@ class StatisticsOutlierCleanerPanel extends HTMLElement {
447440
this._allStats = []; // full list from WS
448441
this._activeIdx = -1; // keyboard nav index in dropdown
449442
this._recentStats = this._loadRecentStats();
450-
this._series = [];
451-
this._chartEl = null;
452-
this._scanStartTs = null;
453-
this._scanEndTs = null;
454443
this._onDocClick = (e) => {
455444
if (!this.shadowRoot.contains(e.target)) this._closeDropdown();
456445
};
@@ -588,7 +577,6 @@ class StatisticsOutlierCleanerPanel extends HTMLElement {
588577
<div id="results-card" class="card hidden">
589578
<h3>Detected Outliers</h3>
590579
<div id="scan-stats-row" class="scan-stats-row hidden"></div>
591-
<div id="chart-container" class="hidden"></div>
592580
<details id="scan-detail" class="hidden" style="margin-bottom:10px">
593581
<summary style="cursor:pointer;font-size:0.75rem;color:var(--secondary-text-color);user-select:none">Statistical detail</summary>
594582
<div id="scan-meta" class="meta" style="margin-top:4px"></div>
@@ -844,156 +832,6 @@ class StatisticsOutlierCleanerPanel extends HTMLElement {
844832
return this._hass.connection.sendMessagePromise({ id: this._msgId++, ...msg });
845833
}
846834

847-
async _fetchSeries(statId, startTs, endTs) {
848-
try {
849-
const result = await this._hass.connection.sendMessagePromise({
850-
id: this._msgId++,
851-
type: "recorder/statistics_during_period",
852-
start_time: new Date(startTs * 1000).toISOString(),
853-
end_time: new Date(endTs * 1000).toISOString(),
854-
statistic_ids: [statId],
855-
period: "hour",
856-
types: ["sum"],
857-
});
858-
const rows = result[statId] || [];
859-
this._series = rows
860-
.filter(r => r.sum != null)
861-
.map(r => ({ start: new Date(r.start).getTime(), sum: r.sum }));
862-
} catch (e) {
863-
console.warn("[outlier-cleaner] series fetch failed:", e);
864-
this._series = [];
865-
}
866-
}
867-
868-
_computeAfterSeries() {
869-
const replacement = parseFloat(this._q("replacement")?.value ?? "0") || 0;
870-
const sums = this._series.map(r => r.sum);
871-
const selected = [...this._selected]
872-
.map(i => this._candidates[i])
873-
.sort((a, b) => a.start - b.start);
874-
for (const c of selected) {
875-
const delta = replacement - c.change;
876-
const idx = this._series.findIndex(r => r.start >= c.start);
877-
if (idx === -1) continue;
878-
for (let j = idx; j < sums.length; j++) sums[j] += delta;
879-
}
880-
return sums;
881-
}
882-
883-
// ---------------------------------------------------------------------------
884-
// Chart
885-
// ---------------------------------------------------------------------------
886-
887-
async _renderChart() {
888-
const container = this._q("chart-container");
889-
if (!container || !this._series.length) return;
890-
891-
try {
892-
await Promise.race([
893-
customElements.whenDefined("ha-chart-base"),
894-
new Promise((_, reject) =>
895-
setTimeout(() => reject(new Error("timeout")), 3000)
896-
),
897-
]);
898-
} catch (_) {
899-
console.warn("[outlier-cleaner] ha-chart-base unavailable, skipping chart");
900-
return;
901-
}
902-
903-
const labels = this._series.map(r =>
904-
new Date(r.start).toLocaleString([], {
905-
month: "short", day: "numeric", hour: "2-digit", minute: "2-digit",
906-
})
907-
);
908-
const beforeSums = this._series.map(r => r.sum);
909-
const afterSums = this._computeAfterSeries();
910-
911-
const candidateMs = new Set(this._candidates.map(c => c.start));
912-
const selectedMs = new Set([...this._selected].map(i => this._candidates[i].start));
913-
const pointRadius = this._series.map(r =>
914-
candidateMs.has(r.start) ? 5 : 0
915-
);
916-
const pointBgColor = this._series.map(r => {
917-
const ms = r.start;
918-
if (!candidateMs.has(ms)) return "transparent";
919-
return selectedMs.has(ms) ? "#ef4444" : "transparent";
920-
});
921-
const pointBorderColor = this._series.map(r =>
922-
candidateMs.has(r.start) ? "#ef4444" : "transparent"
923-
);
924-
925-
const el = document.createElement("ha-chart-base");
926-
// Connect to DOM before setting data so Lit can initialise with hass context.
927-
container.innerHTML = "";
928-
container.appendChild(el);
929-
container.classList.remove("hidden");
930-
931-
el.hass = this._hass;
932-
el.chartType = "line";
933-
el.data = {
934-
labels,
935-
datasets: [
936-
{
937-
label: "Before",
938-
data: beforeSums,
939-
borderColor: "#ef4444",
940-
borderDash: [5, 4],
941-
borderWidth: 1.5,
942-
pointRadius,
943-
pointBackgroundColor: pointBgColor,
944-
pointBorderColor,
945-
pointBorderWidth: 2,
946-
tension: 0,
947-
fill: false,
948-
},
949-
{
950-
label: "After (simulated)",
951-
data: afterSums,
952-
borderColor: "#4ade80",
953-
borderWidth: 1.5,
954-
pointRadius: 0,
955-
tension: 0,
956-
fill: false,
957-
},
958-
],
959-
};
960-
el.options = {
961-
animation: false,
962-
responsive: true,
963-
maintainAspectRatio: true,
964-
aspectRatio: 3,
965-
plugins: {
966-
legend: { display: false },
967-
tooltip: { mode: "index", intersect: false },
968-
},
969-
scales: {
970-
x: { ticks: { maxTicksLimit: 8, maxRotation: 0 }, grid: { display: false } },
971-
y: { beginAtZero: false },
972-
},
973-
};
974-
975-
this._chartEl = el;
976-
}
977-
978-
_updateChart() {
979-
if (!this._chartEl || !this._series.length) return;
980-
const afterSums = this._computeAfterSeries();
981-
const selectedMs = new Set([...this._selected].map(i => this._candidates[i].start));
982-
const candidateMs = new Set(this._candidates.map(c => c.start));
983-
const pointBgColor = this._series.map(r => {
984-
const ms = r.start;
985-
if (!candidateMs.has(ms)) return "transparent";
986-
return selectedMs.has(ms) ? "#ef4444" : "transparent";
987-
});
988-
this._chartEl.data = {
989-
labels: this._chartEl.data.labels,
990-
datasets: [
991-
{ ...this._chartEl.data.datasets[0], pointBackgroundColor: pointBgColor },
992-
{ ...this._chartEl.data.datasets[1], data: afterSums },
993-
],
994-
};
995-
}
996-
997835
// ---------------------------------------------------------------------------
998836
// Scan
999837
// ---------------------------------------------------------------------------
@@ -1025,21 +863,14 @@ class StatisticsOutlierCleanerPanel extends HTMLElement {
1025863
if (method === "absolute") params.threshold = parseFloat(this._q("threshold").value) || 0;
1026864
if (method === "top_n") params.top_n = parseInt(this._q("top-n").value) || 10;
1027865

1028-
this._scanStartTs = params.start_ts || (Date.now() / 1000 - 86_400 * 30);
1029-
this._scanEndTs = params.end_ts || (Date.now() / 1000);
1030-
1031866
this._showStatus("info", "Scanning…");
1032867
this._q("btn-scan").disabled = true;
1033868

1034869
try {
1035-
const [result] = await Promise.all([
1036-
this._send(params),
1037-
this._fetchSeries(statId, this._scanStartTs, this._scanEndTs),
1038-
]);
870+
const result = await this._send(params);
1039871
this._candidates = result.candidates || [];
1040872
this._selected = new Set(this._candidates.map((_, i) => i));
1041873
this._renderResults(result);
1042-
this._renderChart();
1043874
this._clearStatus();
1044875
const statMeta = this._allStats.find((s) => s.statistic_id === statId);
1045876
this._saveRecentStat(statId, statMeta?.name || null);
@@ -1106,7 +937,6 @@ class StatisticsOutlierCleanerPanel extends HTMLElement {
1106937
? `Preview: would replace <strong>${n} reading${n !== 1 ? "s" : ""}</strong> with <strong>${replacement}</strong> — no DB changes`
1107938
: `Replace <strong>${n} reading${n !== 1 ? "s" : ""}</strong> with <strong>${replacement}</strong>`;
1108939
applyBtn.textContent = isDry ? `Preview ${n} rows` : `Apply to ${n} rows`;
1109-
this._updateChart();
1110940
}
1111941

1112942
_renderTable() {
@@ -1226,8 +1056,6 @@ class StatisticsOutlierCleanerPanel extends HTMLElement {
12261056
this._q("apply-area").classList.add("hidden");
12271057
}
12281058
this._loadHistory();
1229-
await this._fetchSeries(this._statId || statId, this._scanStartTs, this._scanEndTs);
1230-
this._renderChart();
12311059
}
12321060
} catch (e) {
12331061
this._showStatus("error", `Apply failed: ${e.message || JSON.stringify(e)}`);

custom_components/statistics_outlier_cleaner/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@
1313
"documentation": "https://github.com/poolski/homeassistant-outlier-cleaner",
1414
"iot_class": "local_polling",
1515
"issue_tracker": "https://github.com/poolski/homeassistant-outlier-cleaner/issues",
16-
"version": "0.1.18"
16+
"version": "0.1.19"
1717
}

0 commit comments

Comments
 (0)