iobroker.anomaly-detection 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +26 -1
  2. package/admin/custom/assets/Components-ClCLk8YC.js +3 -0
  3. package/admin/custom/assets/TextField-DNFcbJCE.js +110 -0
  4. package/admin/custom/assets/__virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__loadShare__react__loadShare__.js_commonjs-proxy-C6BYFHUa.js +1 -0
  5. package/admin/custom/assets/_commonjsHelpers-D6-XlEtG.js +1 -0
  6. package/admin/custom/assets/_virtual_mf-localSharedImportMap___mfe_internal__AnomalyDetectionAdmin__mf_owner__1-Bn45JlGM.js +1 -0
  7. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-CxByAkwq.js +2 -0
  8. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__loadShare___mf_0_mui_mf_1_icons_mf_2_material__loadShare__.js-C2PcnDBz.js +2 -0
  9. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__loadShare___mf_0_mui_mf_1_material__loadShare__.js-BWEm0L22.js +2 -0
  10. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__loadShare__react__loadShare__.js-B1BcPa9n.js +2 -0
  11. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-D-mkyUQs.js +2 -0
  12. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__loadShare__react_mf_2_dom__loadShare__.js-Ds3-Yu4l.js +2 -0
  13. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__prebuild___mf_0_iobroker_mf_1_json_mf_2_config__prebuild__-T67sp31H.js +2409 -0
  14. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__prebuild___mf_0_mui_mf_1_icons_mf_2_material__prebuild__-CSf7D3Rq.js +1 -0
  15. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__prebuild___mf_0_mui_mf_1_material__prebuild__-G3XIndY6.js +125 -0
  16. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__prebuild__react__prebuild__-Cta2Ac0K.js +1 -0
  17. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__prebuild__react_mf_1_jsx_mf_2_runtime__prebuild__-BKVK5lr0.js +9 -0
  18. package/admin/custom/assets/_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__prebuild__react_mf_2_dom__prebuild__-ab5OrS0v.js +24 -0
  19. package/admin/custom/assets/createSvgIcon-lbUx5w8b.js +22 -0
  20. package/admin/custom/assets/hostInit-BWN-RucD.js +1 -0
  21. package/admin/custom/assets/index-Bs96mP5z.js +1 -0
  22. package/admin/custom/assets/index-DQDnJGju.js +3 -0
  23. package/admin/custom/assets/index-X0XKF-KT.js +9 -0
  24. package/admin/custom/assets/index-wphymIgy.js +7 -0
  25. package/admin/custom/assets/mf-entry-bootstrap-0-d6d9d7a6.js +53 -0
  26. package/admin/custom/assets/pendingShares-CaFFrAdb.js +2 -0
  27. package/admin/custom/assets/virtualExposes-Dx4O0s8s.js +1 -0
  28. package/admin/custom/assets/vite-preload-helper-ckwbz45p.js +1 -0
  29. package/admin/custom/customComponents.js +13 -0
  30. package/admin/custom/index.html +14 -0
  31. package/admin/custom/mf-manifest.json +1 -0
  32. package/admin/custom/mf-stats.json +1 -0
  33. package/admin/i18n/de.json +13 -12
  34. package/admin/jsonConfig.json +225 -26
  35. package/admin/jsonTab.json +16 -0
  36. package/build/lib/advanced-detectors.js +4 -2
  37. package/build/lib/advanced-detectors.js.map +2 -2
  38. package/build/lib/detectors.js +9 -3
  39. package/build/lib/detectors.js.map +2 -2
  40. package/build/lib/history-provider.js +12 -5
  41. package/build/lib/history-provider.js.map +2 -2
  42. package/build/lib/scoring.js +31 -4
  43. package/build/lib/scoring.js.map +2 -2
  44. package/build/lib/source-monitor.js +91 -6
  45. package/build/lib/source-monitor.js.map +2 -2
  46. package/build/main.js +230 -4
  47. package/build/main.js.map +2 -2
  48. package/io-package.json +46 -2
  49. package/package.json +3 -3
package/README.md CHANGED
@@ -133,6 +133,21 @@ Configured changes take effect after the adapter restarts. Duplicate source IDs
133
133
 
134
134
  When a source row is removed from the configuration and the adapter restarts, its generated subtree under `anomaly-detection.0.sources` and its persisted model are removed. The cleanup uses the generated device's stored original source ID and deletes only the exact generated subtree; temporarily unavailable sources that remain configured are retained.
135
135
 
136
+ ### Analysis view: history and anomalies
137
+
138
+ The **Current anomaly assessments** tab provides a compact, responsive **History & anomalies** chart for every monitored source. The chart is collapsed initially and loads history only when opened. The period can be changed between **1 h**, **6 h**, **24 h** (default), and **7 days**; changing the period reloads the data for that source.
139
+
140
+ The chart uses the state unit from ioBroker (for example `W`, `%`, or `°C`) and scales its plot area to the actual card width. It shows:
141
+
142
+ - **Value** – the historical measurements from the configured History provider.
143
+ - **Expected range** – a translucent band made only from the historical `decisionLow`/`decisionHigh` values that were valid at each timestamp. Missing historical bounds remain empty; the current range is never projected backwards.
144
+ - **Assessment context** – a subtle background highlight only for time sections whose stored context matches the context used by the current assessment. Context names use the ioBroker `common.name` where available.
145
+ - **Anomaly** – a red triangle only when the adapter stored `detected: true` for that historical assessment. Historical markers do not change the current status badge.
146
+
147
+ Hovering or touching a point shows the information available for that exact historical timestamp: value and unit, historical expected range (or an explicit unavailable notice), status, translated reason, score, and context. For value/context deviations the tooltip also shows the concrete distance above or below the historical range. Rate, stuck, trend, and level-shift findings keep their detector-specific explanation and are not presented as fabricated range deviations.
148
+
149
+ The chart legend distinguishes **Value**, **Expected range**, **Assessment context**, and **Anomaly**. A small note reports the number of conspicuous historical measurements in the selected period. This is separate from the current **Normal** or **Anomaly** status; the adapter stores individual diagnostic snapshots, so the note counts displayed snapshots rather than inventing grouped anomaly events.
150
+
136
151
  ## Learning and persistence
137
152
 
138
153
  Normal observations update the global and configured temporal baselines gradually. Observations at or above the configured anomaly threshold are excluded from learning so an ongoing fault is not accepted as normal. The adapter stores only bounded samples (240 per baseline) and compact model metadata, not an unbounded raw time series.
@@ -284,7 +299,7 @@ For each source, the adapter creates a safe deterministic object ID under:
284
299
  | `score` | number / `value` | normalized 0–100 anomaly score |
285
300
  | `detected` | boolean / `indicator` | persistent anomaly indicator |
286
301
  | `status` | string / `info.status` | `insufficientData`, `learning`, or `monitoring` |
287
- | `reason` | string / `text` | deterministic explanation of the current score (`Normal` at score 0) |
302
+ | `reason` | string / `text` | deterministic explanation of the current score (`Normal` for scores below 50) |
288
303
  | `lastAnomaly` | string / `date` | time of the most recent high-score observation |
289
304
  | `sampleCount` | number / `value` | retained global value-model samples (bounded to 240) |
290
305
  | `baselineScope` | string / `info.status` | baseline used: `context`, `time`, `global`, or `insufficient` |
@@ -310,6 +325,16 @@ Processing and model storage are completely local to ioBroker. No monitored valu
310
325
 
311
326
  ## Changelog
312
327
 
328
+ ### 0.2.0 (unreleased)
329
+
330
+ - Report `Normal` as the current reason for scores below 50 instead of showing a technical detector message for a minor deviation.
331
+ - Improve analysis charts, historical explanations, and responsive layout.
332
+
333
+ ### 0.1.1 (2026-09-07)
334
+
335
+ - (Voodoo2man) improve configuration UI layout and translations
336
+ - (Voodoo2man) add detector guidance and contextual option visibility
337
+
313
338
  ### 0.1.0 (2026-09-06)
314
339
 
315
340
  - (Voodoo2man) add local statistical anomaly detection MVP
@@ -0,0 +1,3 @@
1
+ import"../customComponents.js";import{_ as c,a}from"./_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-D-mkyUQs.js";import{_ as C,a as ce,b as de,c as I,d as ee,e as he}from"./_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__loadShare__react__loadShare__.js-B1BcPa9n.js";import{a as W,b as T,c as u,d as S,e as z,f as E,g as ue,h as me,i as fe,j as xe,k as pe}from"./_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__loadShare___mf_0_mui_mf_1_material__loadShare__.js-BWEm0L22.js";import{_ as ve,a as ge,b as be}from"./_virtual_mf___mfe_internal__AnomalyDetectionAdmin__mf_owner__65673490305404__loadShare___mf_0_mui_mf_1_icons_mf_2_material__loadShare__.js-C2PcnDBz.js";import"./vite-preload-helper-ckwbz45p.js";import"./index-wphymIgy.js";function _e(e,r=[]){const l=[...e,...r].filter(i=>Number.isFinite(i));if(l.length===0)return{min:0,max:1};const o=Math.min(...l),d=Math.max(...l),m=d-o||Math.max(1,Math.abs(d)*.01);return{min:o>=0?0:o-m*.05,max:d+m*.05}}const te={en:{"reason.normal":"The value behaves as expected.","reason.insufficient_training_data":"I am still collecting data before rating this state reliably.","reason.unexpected_value":"The current value is outside the usual range.","reason.unexpected_low":"The current value is unusually low.","reason.unexpected_high":"The current value is unusually high.","reason.context_deviation":"The current value is unusual for this context.","reason.context_low":"The current value is unusually low for this context.","reason.context_high":"The current value is unusually high for this context.","reason.unexpected_rate_change":"The value is changing unusually quickly.","reason.stuck_value":"The value has not changed for longer than expected.","reason.persistent_level_shift":"A persistent change in the normal level was detected.","reason.unusual_trend":"An unusual long-term trend was detected.","reason.multiple_detectors":"Several detectors jointly indicate unusual behavior.","status.learning":"Learning","status.normal":"Normal","status.anomaly":"Anomaly","status.insufficient_data":"Insufficient data",title:"Current anomaly assessments",refresh:"Refresh",empty:"No assessment is available yet for the configured states.",current:"Current",decisionRange:"MAD decision range",chartValue:"Value",chartExpected:"Expected range",chartAnomaly:"Anomaly",chartStatus:"Status",chartReason:"Reason",chartAssessment:"Assessment",chartDeviation:"Deviation",chartExpectedUnavailable:"Historical expected range not available","deviation.below":"below the expected range","deviation.above":"above the expected range",chartContext:"Assessment context",historicalAnomaliesOne:"%s conspicuous measurement in the selected period",historicalAnomaliesMany:"%s conspicuous measurements in the selected period",chartNoContext:"Historical context information is not available for this period.",chartNow:"Now",chartNormalExplanation:"The value is within the expected range.",learned:"%s of at least %s required samples learned",comparisonSamples:"Comparison based on %s similar samples",context:"Compared with context: %s",since:"Anomalous since %s",details:"Technical details",overall:"Overall score",baseline:"Baseline",baseline_context:"Context-based",baseline_time:"Time-based",baseline_global:"Global fallback",baseline_insufficient:"Insufficient baseline",valueDeviation:"Value deviation",contextDeviation:"Context deviation",rateDeviation:"Rate of change",stuckDetection:"Stuck-state detection",levelShift:"Persistent level shift",trendDetection:"Trend detection",samples:"samples",contextSamples:"Context samples",lastEvaluation:"Last evaluation",activeDetectors:"Active detectors",loadError:"The anomaly assessments could not be loaded.",chart:"History & anomalies",chartUnavailable:"No history data is available for this state.",chartNoBounds:"Historical decision bounds are not available for this period.",hour:"1 h",sixHours:"6 h",day:"24 h",week:"7 days"},de:{"reason.normal":"Der Wert verhält sich wie erwartet.","reason.insufficient_training_data":"Ich sammle noch Daten, bevor ich diesen Datenpunkt zuverlässig bewerten kann.","reason.unexpected_value":"Der aktuelle Wert liegt außerhalb des üblichen Bereichs.","reason.unexpected_low":"Der aktuelle Wert ist ungewöhnlich niedrig.","reason.unexpected_high":"Der aktuelle Wert ist ungewöhnlich hoch.","reason.context_deviation":"Der aktuelle Wert ist für diesen Zustand ungewöhnlich.","reason.context_low":"Der aktuelle Wert ist für diesen Zustand ungewöhnlich niedrig.","reason.context_high":"Der aktuelle Wert ist für diesen Zustand ungewöhnlich hoch.","reason.unexpected_rate_change":"Der Wert verändert sich ungewöhnlich schnell.","reason.stuck_value":"Der Wert hat sich länger als erwartet nicht verändert.","reason.persistent_level_shift":"Eine dauerhafte Veränderung des normalen Niveaus wurde erkannt.","reason.unusual_trend":"Ein ungewöhnlicher längerfristiger Trend wurde erkannt.","reason.multiple_detectors":"Mehrere Detektoren weisen gemeinsam auf ein ungewöhnliches Verhalten hin.","status.learning":"Lernt noch","status.normal":"Normal","status.anomaly":"Auffällig","status.insufficient_data":"Zu wenig Daten",title:"Aktuelle Anomaliebewertungen",refresh:"Aktualisieren",empty:"Für die konfigurierten Datenpunkte liegt noch keine Bewertung vor.",current:"Aktuell",decisionRange:"Erwarteter Bereich",chartValue:"Messwert",chartExpected:"Erwarteter Bereich",chartAnomaly:"Anomalie",chartStatus:"Status",chartReason:"Grund",chartAssessment:"Bewertung",chartDeviation:"Abweichung",chartExpectedUnavailable:"Historischer erwarteter Bereich nicht verfügbar","deviation.below":"unter dem erwarteten Bereich","deviation.above":"über dem erwarteten Bereich",chartContext:"Bewertungskontext",historicalAnomaliesOne:"%s auffälliger Messpunkt im gewählten Zeitraum",historicalAnomaliesMany:"%s auffällige Messpunkte im gewählten Zeitraum",chartNoContext:"Für diesen Zeitraum sind keine historischen Kontextinformationen verfügbar.",chartNow:"Jetzt",chartNormalExplanation:"Der Wert liegt im erwarteten Bereich.",learned:"%s von mindestens %s benötigten Messwerten gelernt",comparisonSamples:"Vergleich basiert auf %s ähnlichen Messungen",context:"Verglichen mit Kontext: %s",since:"Auffällig seit %s",details:"Technische Details",overall:"Gesamtbewertung",baseline:"Baseline",baseline_context:"Kontextbezogen",baseline_time:"Zeitabhängig",baseline_global:"Globale Fallback-Baseline",baseline_insufficient:"Baseline noch nicht reif",valueDeviation:"Wertabweichung",contextDeviation:"Abweichung im aktuellen Kontext",rateDeviation:"Änderungsgeschwindigkeit",stuckDetection:"Festhängender Wert",levelShift:"Dauerhafte Pegelverschiebung",trendDetection:"Trenderkennung",samples:"Samples",contextSamples:"Kontext-Samples",lastEvaluation:"Letzte Bewertung",activeDetectors:"Aktive Detektoren",loadError:"Die Anomaliebewertungen konnten nicht geladen werden.",chart:"Verlauf & Anomalien",chartUnavailable:"Für diesen Datenpunkt sind keine Verlaufsdaten verfügbar.",chartNoBounds:"Für diesen Zeitraum sind keine historischen Bewertungsgrenzen verfügbar.",hour:"1 h",sixHours:"6 h",day:"24 h",week:"7 Tage"}};function K(){return(typeof navigator<"u"?navigator.language:"en").slice(0,2).toLowerCase()}function n(e,...r){var d;let o=((d=te[K()])==null?void 0:d[e])||te.en[e]||e;for(const m of r)o=o.replace("%s",String(m));return o}function ie(e,r){return e&&n(`reason.${e}`)||r||n("empty")}function ne(e){if(e.statusCode==="normal")return n("reason.normal");if((e.reasonCode==="context_deviation"||e.reasonCode==="unexpected_value")&&e.actual!==void 0&&e.expected!==void 0){const r=e.actual<e.expected?"low":"high",l=e.reasonCode==="context_deviation"?`reason.context_${r}`:`reason.unexpected_${r}`,o=n(l);if(o!==l)return o}return ie(e.reasonCode,e.reason)}function ye(e){return e?n(`baseline_${e}`):"–"}function we(e){return e.name==="context"||e.reasonCode==="context_deviation"?n("contextDeviation"):e.name==="value"||e.reasonCode==="unexpected_value"?n("valueDeviation"):e.name==="rate"||e.reasonCode==="unexpected_rate_change"?n("rateDeviation"):e.name==="stuck"||e.reasonCode==="stuck_value"?n("stuckDetection"):e.name==="changePoint"||e.reasonCode==="persistent_level_shift"?n("levelShift"):e.name==="trend"||e.reasonCode==="unusual_trend"?n("trendDetection"):e.name}function q(e,r){return e.split("|").map(l=>{const o=l.lastIndexOf("=");if(o<0)return l;const d=l.slice(0,o),m=l.slice(o+1),i=(r==null?void 0:r[d])||d;return m==="true"?`${i} – ${K()==="de"?"eingeschaltet":"on"}`:m==="false"?`${i} – ${K()==="de"?"ausgeschaltet":"off"}`:`${i}=${m}`}).join(", ")}function ae(e,r,l){const o=[G(e.timestamp),`${n("chartValue")}: ${y(e.value)}${l.unit?` ${l.unit}`:""}`];if(!r)return o.join(`
2
+ `);if(r.decisionLow!==void 0&&r.decisionHigh!==void 0?o.push(`${n("chartExpected")}: ${y(r.decisionLow)}–${y(r.decisionHigh)}${l.unit?` ${l.unit}`:""}`):o.push(n("chartExpectedUnavailable")),o.push(`${n("chartStatus")}: ${n(`status.${r.detected?"anomaly":"normal"}`)}`),r.detected){if(o.push(`${n("chartReason")}: ${ie(r.reasonCode)}`),(r.reasonCode==="unexpected_value"||r.reasonCode==="context_deviation")&&r.decisionLow!==void 0&&r.decisionHigh!==void 0){const m=e.value<r.decisionLow?r.decisionLow-e.value:e.value-r.decisionHigh,i=e.value<r.decisionLow?"below":"above";o.push(`${n("chartDeviation")}: ${y(m)}${l.unit?` ${l.unit}`:""} ${n(`deviation.${i}`)}`)}}else o.push(`${n("chartReason")}: ${n("chartNormalExplanation")}`);return r.score!==void 0&&o.push(`${n("chartAssessment")}: ${y(r.score)} %`),r.activeContext&&o.push(`${n("context")}: ${q(r.activeContext,l.contextLabels)}`),o.join(`
3
+ `)}function Ce({source:e,socket:r,target:l,refreshKey:o}){var Q;const[d,m]=C(!1),[i,b]=C(24),[f,p]=C(),[N,M]=C(600),A=ee(new Map),$=ee(null);I(()=>{if(!d||!$.current||typeof ResizeObserver>"u")return;const t=()=>{var L;const g=(L=$.current)==null?void 0:L.clientWidth;g&&g>0&&M(g)};t();const h=new ResizeObserver(t);return h.observe($.current),()=>h.disconnect()},[d]),I(()=>{A.current.clear(),d&&p(void 0)},[o]),I(()=>{if(!d||!(r!=null&&r.sendTo))return;const t=A.current.get(i);if(t){p(t);return}r.sendTo(l,"chartData",{sourceId:e.id,start:Date.now()-i*36e5,end:Date.now(),limit:500}).then(h=>{A.current.set(i,h.data),p(h.data)})},[i,d,o,r,e.id,l]);const s=(f==null?void 0:f.samples)||[],_=(f==null?void 0:f.diagnostics)||[],w=s.map(t=>t.value);if(!d)return a(S,{size:"small",onClick:()=>m(!0),sx:{mt:1},children:n("chart")});if(!(f!=null&&f.available))return c(W,{sx:{mt:1},children:[a(S,{size:"small",onClick:()=>m(!1),children:n("chart")}),a(z,{severity:"info",sx:{mt:1},children:n("chartUnavailable")})]});if(!s.length)return c(W,{sx:{mt:1},children:[a(S,{size:"small",onClick:()=>m(!1),children:n("chart")}),a(z,{severity:"info",sx:{mt:1},children:n("chartUnavailable")})]});const x=_.filter(t=>t.timestamp>=s[0].timestamp&&t.timestamp<=s[s.length-1].timestamp),B=e.evaluation.activeContext,H=[];for(let t=0;t<x.length;t++){const h=x[t];if(!B||h.activeContext!==B)continue;const g=((Q=x[t+1])==null?void 0:Q.timestamp)??s[s.length-1].timestamp;H.push({start:h.timestamp,end:g})}const V=x.filter(t=>t.decisionLow!==void 0&&t.decisionHigh!==void 0),R=[];let F=!1;for(const t of x){if(t.decisionLow===void 0||t.decisionHigh===void 0){F=!0;continue}const h=R[R.length-1];F||!h||h[h.length-1].timestamp<t.timestamp-7200*1e3?(R.push([t]),F=!1):h.push(t)}const P=_e(w,V.flatMap(t=>[t.decisionLow,t.decisionHigh])),j=P.min,Y=P.max,re=Y-j,D=44,O=Math.max(D+40,N-8),v=t=>D+(t-s[0].timestamp)/Math.max(1,s[s.length-1].timestamp-s[0].timestamp)*(O-D),k=t=>84-(t-j)/re*76,oe=t=>{let h,g=Number.POSITIVE_INFINITY;for(const L of x){const X=Math.abs(L.timestamp-t);X<g&&(h=L,g=X)}return h},se=s.map(t=>`${v(t.timestamp)},${k(t.value)}`).join(" "),J=t=>new Date(t).toLocaleString(void 0,{dateStyle:i>24?"short":void 0,timeStyle:"short"}),le=x.filter((t,h)=>h>0&&t.activeContext!==x[h-1].activeContext),Z=x.filter(t=>t.detected).length;return c(W,{ref:$,sx:{mt:1,width:"100%"},children:[c(T,{direction:"row",spacing:.5,alignItems:"center",children:[a(S,{size:"small",onClick:()=>m(!1),children:n("chart")}),[[1,"hour"],[6,"sixHours"],[24,"day"],[168,"week"]].map(([t,h])=>a(S,{size:"small",variant:i===t?"contained":"text",onClick:()=>b(t),children:n(h)},String(t)))]}),c("svg",{viewBox:`0 0 ${N} 100`,width:"100%",height:"220",role:"img","aria-label":n("chart"),style:{background:"rgba(127,127,127,0.08)",marginTop:8},children:[a("line",{x1:D,y1:"8",x2:D,y2:"84",stroke:"currentColor",opacity:"0.35"}),a("line",{x1:D,y1:"84",x2:O,y2:"84",stroke:"currentColor",opacity:"0.35"}),a("text",{x:D,y:"96",fontSize:"3",fill:"currentColor",children:J(s[0].timestamp)}),a("text",{x:O,y:"96",textAnchor:"end",fontSize:"3",fill:"currentColor",children:J(s[s.length-1].timestamp)}),c("text",{x:"1",y:"10",fontSize:"3",fill:"currentColor",children:[y(Y),e.unit?` ${e.unit}`:""]}),c("text",{x:"1",y:"84",fontSize:"3",fill:"currentColor",children:[y(j),e.unit?` ${e.unit}`:""]}),R.map((t,h)=>a(he.Fragment,{children:a("polygon",{fill:"#90caf9",opacity:"0.12",points:[...t.map(g=>`${v(g.timestamp)},${k(g.decisionLow)}`),...t.slice().reverse().map(g=>`${v(g.timestamp)},${k(g.decisionHigh)}`)].join(" ")})},`bounds-${h}`)),H.map(t=>a("rect",{x:v(t.start),width:Math.max(.2,v(t.end)-v(t.start)),y:"8",height:"76",fill:"#ab47bc",opacity:"0.08",children:a("title",{children:n("chartContext")})},`context-band-${t.start}`)),a("polyline",{fill:"none",stroke:"#2196f3",strokeWidth:"1.5",points:se,children:a("title",{children:n("chartValue")})}),le.map(t=>a("line",{x1:v(t.timestamp),x2:v(t.timestamp),y1:"8",y2:"84",stroke:"#ab47bc",strokeDasharray:"1 2",opacity:"0.7",children:a("title",{children:`${n("chartContext")}: ${q(t.activeContext,e.contextLabels)}`})},`context-${t.timestamp}`)),_.filter(t=>t.detected&&t.timestamp>=s[0].timestamp&&t.timestamp<=s[s.length-1].timestamp).map(t=>a("polygon",{points:`${v(t.timestamp)},${k(t.actual)-2.5} ${v(t.timestamp)-2.5},${k(t.actual)+2} ${v(t.timestamp)+2.5},${k(t.actual)+2}`,fill:"#f44336",role:"img",children:a("title",{children:ae({value:t.actual,timestamp:t.timestamp},t,e)})},t.timestamp)),s.map(t=>{const h=oe(t.timestamp);return a("circle",{cx:v(t.timestamp),cy:k(t.value),r:"1.2",fill:"#2196f3",children:a("title",{children:ae(t,h,e)})},t.timestamp)}),s.length>0&&a("line",{x1:v(s[s.length-1].timestamp),x2:v(s[s.length-1].timestamp),y1:"8",y2:"84",stroke:"#fff",opacity:"0.5",children:a("title",{children:n("chartNow")})})]}),c(T,{direction:"row",spacing:2,sx:{mt:.5},children:[c(u,{variant:"caption",children:["━ ",n("chartValue")]}),V.length>0&&c(u,{variant:"caption",color:"info.main",children:["┄ ",n("chartExpected")]}),H.length>0&&c(u,{variant:"caption",color:"secondary",children:["▧ ",n("chartContext")]}),x.some(t=>t.detected)&&c(u,{variant:"caption",color:"error",children:["▲ ",n("chartAnomaly")]})]}),Z>0&&a(u,{variant:"caption",color:"text.secondary",sx:{display:"block",mt:.5},children:n(Z===1?"historicalAnomaliesOne":"historicalAnomaliesMany",Z)}),e.evaluation.activeContext&&H.length===0&&a(u,{variant:"caption",color:"text.secondary",children:n("chartNoContext")}),!V.length&&a(u,{variant:"caption",color:"text.secondary",children:n("chartNoBounds")})]})}function U(e){return typeof e=="number"&&Number.isFinite(e)?new Intl.NumberFormat().format(e):""}function y(e){return typeof e=="number"&&Number.isFinite(e)?new Intl.NumberFormat(void 0,{maximumFractionDigits:1}).format(e):""}function G(e){return typeof e=="number"&&Number.isFinite(e)?new Date(e).toLocaleString():""}function $e(e){return n(`status.${e||"learning"}`)}function De(e){return e==="anomaly"?"error":e==="normal"?"success":e==="insufficient_data"?"warning":"default"}function ke({source:e,socket:r,target:l,refreshKey:o}){const[d,m]=C(!1),i=e.evaluation||{},b=i.decisionLow!==void 0&&i.decisionHigh!==void 0?`${y(i.decisionLow)}–${y(i.decisionHigh)}`:void 0,f=i.baselineScope==="context"&&i.contextSampleCount!==void 0?n("comparisonSamples",i.contextSampleCount):i.sampleCount!==void 0&&i.requiredSamples!==void 0?n("learned",i.sampleCount,i.requiredSamples):void 0;return a(ue,{variant:"outlined",sx:{height:"100%"},children:c(me,{children:[c(T,{direction:"row",sx:{justifyContent:"space-between",alignItems:"center",gap:1},children:[a(u,{variant:"h6",component:"h2",noWrap:!0,title:e.id,children:e.name}),a(fe,{label:$e(i.statusCode),color:De(i.statusCode)})]}),a(u,{variant:"subtitle1",sx:{mt:1},children:ne(i)}),c(E,{container:!0,spacing:2,sx:{mt:.5},children:[i.actual!==void 0&&c(E,{item:!0,xs:12,sm:6,children:[a(u,{variant:"body2",color:"text.secondary",children:n("current")}),c(u,{children:[U(i.actual),e.unit?` ${e.unit}`:""]})]}),b&&c(E,{item:!0,xs:12,sm:6,children:[a(u,{variant:"body2",color:"text.secondary",children:n("decisionRange")}),c(u,{children:[b,e.unit?` ${e.unit}`:""]})]})]}),f&&a(u,{variant:"body2",color:"text.secondary",sx:{mt:1},children:f}),i.reasonCode&&i.statusCode!=="normal"&&a(u,{variant:"body2",sx:{mt:1},children:ne(i)}),i.statusCode==="anomaly"&&i.anomalySince&&a(u,{variant:"body2",color:"text.secondary",sx:{mt:1},children:n("since",G(i.anomalySince))}),i.activeContext&&a(u,{variant:"body2",color:"text.secondary",sx:{mt:1},children:n("context",q(i.activeContext,e.contextLabels))}),a(Ce,{source:e,socket:r,target:l,refreshKey:o}),a(S,{size:"small",onClick:()=>m(p=>!p),endIcon:d?a(ge,{}):a(be,{}),sx:{mt:1},"aria-expanded":d,children:n("details")}),c(xe,{in:d,children:[a(pe,{sx:{my:1}}),c(T,{spacing:.5,children:[c(u,{variant:"body2",children:[n("overall"),":"," ",i.score!==void 0?`${U(i.score)} %`:"–"]}),c(u,{variant:"body2",children:[n("baseline"),": ",ye(i.baselineScope)," (",i.baselineSampleCount??0," ",n("samples"),")"]}),i.contextSampleCount!==void 0&&c(u,{variant:"body2",children:[n("contextSamples"),": ",i.contextSampleCount]}),i.lastEvaluated&&c(u,{variant:"body2",children:[n("lastEvaluation"),": ",G(i.lastEvaluated)]}),(i.detectors||[]).map(p=>c(u,{variant:"body2",children:[we(p),": ",U(p.score)," %"]},`${p.name}-${p.reasonCode}`))]})]})]})})}function Se(e){var N,M,A,$;const[r,l]=C(((N=e.data)==null?void 0:N.sources)||[]),[o,d]=C(),[m,i]=C(0),b=e.socket||((M=e.oContext)==null?void 0:M.socket),f=ce(()=>{var w,x;const s=e.adapterName||((w=e.oContext)==null?void 0:w.adapterName)||"anomaly-detection",_=e.instance??((x=e.oContext)==null?void 0:x.instance)??0;return String(_).includes(".")?String(_):`${s}.${_}`},[e.adapterName,e.instance,(A=e.oContext)==null?void 0:A.adapterName,($=e.oContext)==null?void 0:$.instance]),p=de(async()=>{var s,_;if(!(b!=null&&b.sendTo)){l(((s=e.data)==null?void 0:s.sources)||[]);return}try{i(B=>B+1);const w=await b.sendTo(f,"tab",{}),x=(_=w==null?void 0:w.data)==null?void 0:_.sources;Array.isArray(x)?(l(x),d(void 0)):d(n("loadError"))}catch{d(n("loadError"))}},[b,e.data,f]);return I(()=>{p()},[p]),c(W,{sx:{p:2},children:[c(T,{direction:"row",sx:{mb:2,justifyContent:"space-between",alignItems:"center"},children:[a(u,{variant:"h5",component:"h1",children:n("title")}),a(S,{onClick:p,startIcon:a(ve,{}),"aria-label":n("refresh"),children:n("refresh")})]}),o&&a(z,{severity:"error",sx:{mb:2},children:n("loadError")}),r.length===0?a(z,{severity:"info",children:n("empty")}):a(E,{container:!0,spacing:2,children:r.map(s=>a(E,{item:!0,xs:12,md:6,xl:4,children:a(ke,{source:s,socket:b,target:f,refreshKey:m})},s.id))})]})}const He={AnomalyDashboard:Se};export{Se as AnomalyDashboard,He as default};