myio-js-library 0.1.502 → 0.1.504

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.
package/dist/index.cjs CHANGED
@@ -583,6 +583,7 @@ __export(index_exports, {
583
583
  CONSUMPTION_CHART_DEFAULTS: () => DEFAULT_CONFIG,
584
584
  CONSUMPTION_THEME_COLORS: () => THEME_COLORS,
585
585
  CardGridPanel: () => CardGridPanel,
586
+ ColumnSummaryTooltip: () => ColumnSummaryTooltip,
586
587
  ConnectionStatusType: () => ConnectionStatusType,
587
588
  ContractSummaryTooltip: () => ContractSummaryTooltip,
588
589
  CustomerCardV1: () => CustomerCardV1,
@@ -1130,6 +1131,7 @@ __export(index_exports, {
1130
1131
  renderStatusDonutChart: () => renderStatusDonutChart,
1131
1132
  renderTrendChart: () => renderTrendChart,
1132
1133
  reopenFreshdeskTicket: () => reopenTicket,
1134
+ resolvePercentDecimals: () => resolvePercentDecimals,
1133
1135
  schedCreateDateInput: () => createDateInput,
1134
1136
  schedCreateNumberInput: () => createNumberInput,
1135
1137
  schedCreateSelect: () => createSelect,
@@ -1162,7 +1164,7 @@ module.exports = __toCommonJS(index_exports);
1162
1164
  // package.json
1163
1165
  var package_default = {
1164
1166
  name: "myio-js-library",
1165
- version: "0.1.502",
1167
+ version: "0.1.504",
1166
1168
  description: "A clean, standalone JS SDK for MYIO projects",
1167
1169
  license: "MIT",
1168
1170
  repository: "github:gh-myio/myio-js-library",
@@ -14498,6 +14500,16 @@ var TempComparisonTooltip = {
14498
14500
  }
14499
14501
  };
14500
14502
 
14503
+ // src/utils/percentDecimals.ts
14504
+ function resolvePercentDecimals(explicit) {
14505
+ const fromArg = Number(explicit);
14506
+ if (Number.isInteger(fromArg) && fromArg >= 0 && fromArg <= 6) return fromArg;
14507
+ const utils = typeof window !== "undefined" ? window.MyIOUtils : void 0;
14508
+ const fromGlobal = utils ? Number(utils.percentDecimals) : NaN;
14509
+ if (Number.isInteger(fromGlobal) && fromGlobal >= 0 && fromGlobal <= 6) return fromGlobal;
14510
+ return 2;
14511
+ }
14512
+
14501
14513
  // src/thingsboard/main-dashboard-shopping/v-5.2.0/card/template-card-v5.js
14502
14514
  var LABEL_CHAR_LIMIT2 = 18;
14503
14515
  var DEVICE_TYPE_CONFIG = {
@@ -14632,8 +14644,11 @@ function renderCardComponentV5({
14632
14644
  // Tooltip on percentage badge
14633
14645
  showTempComparisonTooltip = false,
14634
14646
  // Tooltip on temperature deviation badge
14635
- showTempRangeTooltip = false
14647
+ showTempRangeTooltip = false,
14636
14648
  // Tooltip on device image for temperature devices
14649
+ // Decimal places for the % badge. Resolved at render time so it can be changed
14650
+ // without rebuilding the lib: this prop > window.MyIOUtils.percentDecimals > 2.
14651
+ percentDecimals
14637
14652
  }) {
14638
14653
  const {
14639
14654
  entityId,
@@ -15091,6 +15106,7 @@ function renderCardComponentV5({
15091
15106
  const isTermostatoDevice = deviceType?.toUpperCase() === "TERMOSTATO";
15092
15107
  const isEnergyDeviceFlag = isEnergyDevice2(deviceType);
15093
15108
  const percentageForDisplay = isTankDevice2 ? (waterPercentage || 0) * 100 : perc;
15109
+ const _pctDecimals = resolvePercentDecimals(percentDecimals);
15094
15110
  const calculateTempStatus2 = () => {
15095
15111
  if (temperatureStatus) return temperatureStatus;
15096
15112
  const currentTemp = Number(val) || 0;
@@ -15169,9 +15185,7 @@ function renderCardComponentV5({
15169
15185
  <span class="consumption-value">${formatCardValue(cardEntity.lastValue, deviceType)}</span>
15170
15186
  </div>
15171
15187
  </div>
15172
- ${!isTermostatoDevice ? `<span class="device-percentage-badge percentage-tooltip-trigger" style="position: absolute; bottom: 12px; right: 12px; z-index: 20; background: none !important; cursor: help;">${percentageForDisplay.toFixed(
15173
- 1
15174
- )}%</span>` : tempDeviationPercent ? `<span class="device-percentage-badge temp-deviation-badge temp-comparison-tooltip-trigger" style="position: absolute; bottom: 12px; right: 12px; z-index: 20; background: none !important; color: ${tempDeviationPercent.isAbove ? "#ef4444" : tempDeviationPercent.isBelow ? "#3b82f6" : "#6b7280"}; font-weight: 600; cursor: help;">${tempDeviationPercent.sign}${tempDeviationPercent.value.toFixed(1)}%</span>` : ""}
15188
+ ${!isTermostatoDevice ? `<span class="device-percentage-badge percentage-tooltip-trigger" style="position: absolute; bottom: 12px; right: 12px; z-index: 20; background: none !important; cursor: help;">${percentageForDisplay.toFixed(_pctDecimals).replace(".", ",")}%</span>` : tempDeviationPercent ? `<span class="device-percentage-badge temp-deviation-badge temp-comparison-tooltip-trigger" style="position: absolute; bottom: 12px; right: 12px; z-index: 20; background: none !important; color: ${tempDeviationPercent.isAbove ? "#ef4444" : tempDeviationPercent.isBelow ? "#3b82f6" : "#6b7280"}; font-weight: 600; cursor: help;">${tempDeviationPercent.sign}${tempDeviationPercent.value.toFixed(1)}%</span>` : ""}
15175
15189
  </div>
15176
15190
  </div>
15177
15191
  </div>
@@ -27305,8 +27319,8 @@ var EnergyDataFetcher = class {
27305
27319
  // src/components/premium-modals/internal/engines/CsvExporter.ts
27306
27320
  var toCsv = (rows, locale = "pt-BR", sep = ";") => {
27307
27321
  const fmt2 = new Intl.NumberFormat(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
27308
- const esc3 = (v) => (typeof v === "number" ? fmt2.format(v) : String(v)).replace(/"/g, '""');
27309
- return rows.map((r) => r.map((c) => `"${esc3(c)}"`).join(sep)).join("\r\n");
27322
+ const esc4 = (v) => (typeof v === "number" ? fmt2.format(v) : String(v)).replace(/"/g, '""');
27323
+ return rows.map((r) => r.map((c) => `"${esc4(c)}"`).join(sep)).join("\r\n");
27310
27324
  };
27311
27325
 
27312
27326
  // src/utils/telemetryUtils.ts
@@ -33611,27 +33625,23 @@ var AllReportModal = class {
33611
33625
  // Premium tooltip content for the exclusion-flag info icon. Uses the library
33612
33626
  // InfoTooltip CSS classes (myio-info-tooltip__*) — injected by InfoTooltip itself.
33613
33627
  buildExclusionTooltipContent() {
33628
+ const p = "margin:0 0 8px;font-size:11px;line-height:1.5;color:#475569;";
33629
+ const pLast = "margin:0;font-size:11px;line-height:1.5;color:#475569;";
33614
33630
  return `
33615
33631
  <div class="myio-info-tooltip__section" style="max-width:280px;">
33616
- <div class="myio-info-tooltip__row" style="align-items:flex-start;padding:3px 0;">
33617
- <span class="myio-info-tooltip__label" style="font-size:11px;line-height:1.5;white-space:normal;">
33618
- Alguns dispositivos t\xEAm o atributo <strong>exclude_groups_totals</strong> e s\xE3o
33619
- propositalmente removidos dos totais do dashboard (ex.: medidor de locat\xE1rio que
33620
- n\xE3o \xE9 consumo operacional do shopping).
33621
- </span>
33622
- </div>
33623
- <div class="myio-info-tooltip__row" style="align-items:flex-start;padding:3px 0;">
33624
- <span class="myio-info-tooltip__label" style="font-size:11px;line-height:1.5;white-space:normal;">
33625
- <strong>Ligado</strong> (padr\xE3o): esses dispositivos s\xE3o omitidos do relat\xF3rio \u2014
33626
- o total bate com os cards do dashboard.
33627
- </span>
33628
- </div>
33629
- <div class="myio-info-tooltip__row" style="align-items:flex-start;padding:3px 0;">
33630
- <span class="myio-info-tooltip__label" style="font-size:11px;line-height:1.5;white-space:normal;">
33631
- <strong>Desligado</strong>: todos os dispositivos do grupo entram \u2014 mostra o
33632
- consumo bruto, inclusive os exclu\xEDdos.
33633
- </span>
33634
- </div>
33632
+ <p style="${p}">
33633
+ Alguns dispositivos t\xEAm o atributo <strong>exclude_groups_totals</strong> e s\xE3o
33634
+ propositalmente removidos dos totais do dashboard (ex.: medidor de locat\xE1rio que
33635
+ n\xE3o \xE9 consumo operacional do shopping).
33636
+ </p>
33637
+ <p style="${p}">
33638
+ <strong>Ligado</strong> (padr\xE3o): esses dispositivos s\xE3o omitidos do relat\xF3rio \u2014
33639
+ o total bate com os cards do dashboard.
33640
+ </p>
33641
+ <p style="${pLast}">
33642
+ <strong>Desligado</strong>: todos os dispositivos do grupo entram \u2014 mostra o
33643
+ consumo bruto, inclusive os exclu\xEDdos.
33644
+ </p>
33635
33645
  </div>
33636
33646
  <div class="myio-info-tooltip__notice">
33637
33647
  <span class="myio-info-tooltip__notice-icon">\u{1F4A1}</span>
@@ -71030,6 +71040,7 @@ var EnergySummaryTooltip = {
71030
71040
  const timestamp = formatTimestamp3(summary.lastUpdated);
71031
71041
  const excludedNotice = this.renderExcludedNotice(summary.excludedFromCAG, summary.unit);
71032
71042
  const titleSuffix = summary.customerName ? ` (${summary.customerName})` : "";
71043
+ const isMultiShopping = (summary.byShoppingTotal?.length || 0) >= 2;
71033
71044
  return `
71034
71045
  <div class="energy-summary-tooltip__content">
71035
71046
  <div class="energy-summary-tooltip__header" data-drag-handle>
@@ -71063,10 +71074,10 @@ var EnergySummaryTooltip = {
71063
71074
  </div>
71064
71075
  <div class="energy-summary-tooltip__section-header">
71065
71076
  <span class="energy-summary-tooltip__section-title">Distribui\xE7\xE3o</span>
71066
- <div class="energy-summary-tooltip__grouping-tabs">
71077
+ ${isMultiShopping ? `<div class="energy-summary-tooltip__grouping-tabs">
71067
71078
  <button class="energy-summary-tooltip__grouping-tab active" data-view="category">Por Categoria</button>
71068
71079
  <button class="energy-summary-tooltip__grouping-tab" data-view="shopping">Por ${summary.entityLabel || "Shopping"}</button>
71069
- </div>
71080
+ </div>` : ""}
71070
71081
  </div>
71071
71082
 
71072
71083
  <!-- Category View (default) -->
@@ -71081,8 +71092,8 @@ var EnergySummaryTooltip = {
71081
71092
  </div>
71082
71093
  </div>
71083
71094
 
71084
- <!-- Shopping View -->
71085
- <div class="energy-summary-tooltip__shopping-view" data-grouping="shopping">
71095
+ <!-- Shopping View (head-office only) -->
71096
+ ${isMultiShopping ? `<div class="energy-summary-tooltip__shopping-view" data-grouping="shopping">
71086
71097
  <div class="energy-summary-tooltip__category-tree">
71087
71098
  <div class="energy-summary-tooltip__category-header">
71088
71099
  <span>${summary.entityLabel || "Shopping"}</span>
@@ -71091,7 +71102,7 @@ var EnergySummaryTooltip = {
71091
71102
  </div>
71092
71103
  ${this.renderShoppingView(summary.byShoppingTotal, summary.unit)}
71093
71104
  </div>
71094
- </div>
71105
+ </div>` : ""}
71095
71106
 
71096
71107
  <div class="energy-summary-tooltip__section-title">Status dos Dispositivos</div>
71097
71108
  <div class="energy-summary-tooltip__status-matrix">
@@ -72944,6 +72955,7 @@ var WaterSummaryTooltip = {
72944
72955
  const statusMatrix = this.renderStatusMatrix(summary.byStatus);
72945
72956
  const timestamp = formatTimestamp4(summary.lastUpdated);
72946
72957
  const titleSuffix = summary.customerName ? ` (${summary.customerName})` : "";
72958
+ const isMultiShopping = (summary.byShoppingTotal?.length || 0) >= 2;
72947
72959
  return `
72948
72960
  <div class="water-summary-tooltip__content">
72949
72961
  <div class="water-summary-tooltip__header" data-drag-handle>
@@ -72978,10 +72990,10 @@ var WaterSummaryTooltip = {
72978
72990
 
72979
72991
  <div class="water-summary-tooltip__section-header">
72980
72992
  <span class="water-summary-tooltip__section-title">Distribui\xE7\xE3o</span>
72981
- <div class="water-summary-tooltip__grouping-tabs">
72993
+ ${isMultiShopping ? `<div class="water-summary-tooltip__grouping-tabs">
72982
72994
  <button class="water-summary-tooltip__grouping-tab active" data-view="category">Por Categoria</button>
72983
72995
  <button class="water-summary-tooltip__grouping-tab" data-view="shopping">Por ${summary.entityLabel || "Shopping"}</button>
72984
- </div>
72996
+ </div>` : ""}
72985
72997
  </div>
72986
72998
 
72987
72999
  <!-- Category View (default) -->
@@ -72996,8 +73008,8 @@ var WaterSummaryTooltip = {
72996
73008
  </div>
72997
73009
  </div>
72998
73010
 
72999
- <!-- Shopping View -->
73000
- <div class="water-summary-tooltip__shopping-view" data-grouping="shopping">
73011
+ <!-- Shopping View (head-office only) -->
73012
+ ${isMultiShopping ? `<div class="water-summary-tooltip__shopping-view" data-grouping="shopping">
73001
73013
  <div class="water-summary-tooltip__category-tree">
73002
73014
  <div class="water-summary-tooltip__category-header">
73003
73015
  <span>${summary.entityLabel || "Shopping"}</span>
@@ -73006,7 +73018,7 @@ var WaterSummaryTooltip = {
73006
73018
  </div>
73007
73019
  ${this.renderShoppingView(summary.byShoppingTotal, summary.unit)}
73008
73020
  </div>
73009
- </div>
73021
+ </div>` : ""}
73010
73022
 
73011
73023
  <div class="water-summary-tooltip__section-title">Status dos Medidores</div>
73012
73024
  <div class="water-summary-tooltip__status-matrix">
@@ -73846,6 +73858,284 @@ var WaterSummaryTooltip = {
73846
73858
  }
73847
73859
  };
73848
73860
 
73861
+ // src/utils/ColumnSummaryTooltip.ts
73862
+ var PIE_COLORS = [
73863
+ "#3e1a7d",
73864
+ "#9333ea",
73865
+ "#0891b2",
73866
+ "#16a34a",
73867
+ "#f59e0b",
73868
+ "#db2777",
73869
+ "#0284c7",
73870
+ "#b45309",
73871
+ "#15803d",
73872
+ "#7c3aed",
73873
+ "#dc2626",
73874
+ "#0d9488",
73875
+ "#ca8a04",
73876
+ "#be185d"
73877
+ ];
73878
+ var COLUMN_SUMMARY_CSS = `
73879
+ .myio-col-summary {
73880
+ max-width: 300px;
73881
+ font-family: 'Nunito', 'Segoe UI', system-ui, sans-serif;
73882
+ }
73883
+ .myio-col-summary__kpis {
73884
+ display: flex; flex-direction: column; gap: 4px;
73885
+ padding: 8px 10px; margin-bottom: 10px;
73886
+ background: #faf8ff; border: 1px solid #e3d9f3; border-radius: 8px;
73887
+ }
73888
+ .myio-col-summary__kpi {
73889
+ display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
73890
+ }
73891
+ .myio-col-summary__kpi-label {
73892
+ font-size: 10px; font-weight: 700; letter-spacing: 0.3px;
73893
+ text-transform: uppercase; color: #64748b;
73894
+ }
73895
+ .myio-col-summary__kpi-value {
73896
+ font-size: 12px; font-weight: 700; color: #1e293b; text-align: right;
73897
+ }
73898
+ .myio-col-summary__kpi-value--accent {
73899
+ font-size: 14px; color: #3e1a7d;
73900
+ }
73901
+ .myio-col-summary__body { display: block; }
73902
+ .myio-col-summary__lists { display: flex; flex-direction: column; }
73903
+ .myio-col-summary__group {
73904
+ display: flex; flex-direction: column; gap: 1px; margin-top: 8px;
73905
+ }
73906
+ .myio-col-summary__group-label {
73907
+ font-size: 10px; font-weight: 800; letter-spacing: 0.3px;
73908
+ text-transform: uppercase; color: #64748b; margin-bottom: 3px;
73909
+ }
73910
+ .myio-col-summary__row {
73911
+ display: flex; align-items: center; gap: 8px; padding: 2px 0;
73912
+ font-size: 11px; color: #1e293b;
73913
+ }
73914
+ .myio-col-summary__name {
73915
+ flex: 1 1 auto; min-width: 0;
73916
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
73917
+ }
73918
+ .myio-col-summary__val {
73919
+ flex: 0 0 auto; font-weight: 700; color: #16a34a; text-align: right;
73920
+ }
73921
+ .myio-col-summary__pct {
73922
+ flex: 0 0 auto; min-width: 44px; text-align: right;
73923
+ font-size: 10px; font-weight: 600; color: #64748b;
73924
+ }
73925
+ .myio-col-summary__empty {
73926
+ padding: 14px 0; text-align: center; font-style: italic;
73927
+ font-size: 11px; color: #94a3b8;
73928
+ }
73929
+
73930
+ /* Pie chart \u2014 hidden in the compact view, revealed when maximized. */
73931
+ .myio-col-summary__chart { display: none; }
73932
+ .myio-col-summary__chart-title {
73933
+ font-size: 11px; font-weight: 800; letter-spacing: 0.3px;
73934
+ text-transform: uppercase; color: #3e1a7d; margin-bottom: 8px;
73935
+ }
73936
+ .myio-col-summary__chart-body {
73937
+ display: flex; gap: 16px; align-items: flex-start;
73938
+ }
73939
+ .myio-col-summary__pie {
73940
+ width: 190px; height: 190px; border-radius: 50%; flex-shrink: 0;
73941
+ box-shadow: 0 2px 12px rgba(0,0,0,0.18);
73942
+ }
73943
+ .myio-col-summary__legend {
73944
+ flex: 1 1 auto; min-width: 0; max-height: 300px; overflow-y: auto;
73945
+ display: flex; flex-direction: column; gap: 1px;
73946
+ }
73947
+ .myio-col-summary__legend-row {
73948
+ display: flex; align-items: center; gap: 6px; padding: 2px 0; font-size: 11px;
73949
+ }
73950
+ .myio-col-summary__legend-dot {
73951
+ width: 9px; height: 9px; border-radius: 2px; flex-shrink: 0;
73952
+ }
73953
+ .myio-col-summary__legend-name {
73954
+ flex: 1 1 auto; min-width: 0;
73955
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #1e293b;
73956
+ }
73957
+ .myio-col-summary__legend-val { flex: 0 0 auto; font-weight: 700; color: #16a34a; }
73958
+ .myio-col-summary__legend-pct {
73959
+ flex: 0 0 auto; min-width: 42px; text-align: right; font-size: 10px; color: #64748b;
73960
+ }
73961
+
73962
+ /* Maximized \u2014 use the extra space: widen, show the pie chart, lists side-by-side. */
73963
+ .myio-info-tooltip.maximized .myio-col-summary { max-width: none; }
73964
+ .myio-info-tooltip.maximized .myio-col-summary__chart {
73965
+ display: block; margin-bottom: 16px;
73966
+ padding-bottom: 14px; border-bottom: 1px solid #e3d9f3;
73967
+ }
73968
+ .myio-info-tooltip.maximized .myio-col-summary__lists {
73969
+ display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
73970
+ }
73971
+ .myio-info-tooltip.maximized .myio-col-summary__group { margin-top: 0; }
73972
+ `;
73973
+ var _cssInjected2 = false;
73974
+ function injectCSS10() {
73975
+ if (_cssInjected2 || typeof document === "undefined") return;
73976
+ const STYLE_ID4 = "myio-column-summary-tooltip-css";
73977
+ if (document.getElementById(STYLE_ID4)) {
73978
+ _cssInjected2 = true;
73979
+ return;
73980
+ }
73981
+ const style = document.createElement("style");
73982
+ style.id = STYLE_ID4;
73983
+ style.textContent = COLUMN_SUMMARY_CSS;
73984
+ document.head.appendChild(style);
73985
+ _cssInjected2 = true;
73986
+ }
73987
+ function esc3(value) {
73988
+ return String(value == null ? "" : value).replace(
73989
+ /[&<>"]/g,
73990
+ (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c]
73991
+ );
73992
+ }
73993
+ function defaultFormatter(unit) {
73994
+ const nf = new Intl.NumberFormat("pt-BR", { maximumFractionDigits: 2 });
73995
+ return (v) => nf.format(Number(v) || 0) + (unit ? " " + unit : "");
73996
+ }
73997
+ function fmtPct(value, total, decimals) {
73998
+ const p = total > 0 ? (Number(value) || 0) / total * 100 : 0;
73999
+ return p.toFixed(decimals).replace(".", ",") + "%";
74000
+ }
74001
+ function buildPieChart(devices, total, fmt2, pctDecimals) {
74002
+ const sorted = devices.slice().sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0));
74003
+ if (total <= 0 || !sorted.length) {
74004
+ return `<div class="myio-col-summary__chart">
74005
+ <div class="myio-col-summary__empty">Sem dados para o gr\xE1fico.</div>
74006
+ </div>`;
74007
+ }
74008
+ let acc = 0;
74009
+ const stops = [];
74010
+ const legend = [];
74011
+ sorted.forEach((d, i) => {
74012
+ const v = Number(d.value) || 0;
74013
+ const color = PIE_COLORS[i % PIE_COLORS.length];
74014
+ const start = acc / total * 360;
74015
+ acc += v;
74016
+ const end = acc / total * 360;
74017
+ stops.push(`${color} ${start.toFixed(3)}deg ${end.toFixed(3)}deg`);
74018
+ legend.push(`<div class="myio-col-summary__legend-row">
74019
+ <span class="myio-col-summary__legend-dot" style="background:${color};"></span>
74020
+ <span class="myio-col-summary__legend-name" title="${esc3(d.name)}">${esc3(d.name)}</span>
74021
+ <span class="myio-col-summary__legend-val">${esc3(fmt2(v))}</span>
74022
+ <span class="myio-col-summary__legend-pct">${fmtPct(v, total, pctDecimals)}</span>
74023
+ </div>`);
74024
+ });
74025
+ return `<div class="myio-col-summary__chart">
74026
+ <div class="myio-col-summary__chart-title">Distribui\xE7\xE3o \u2014 ${sorted.length} dispositivos</div>
74027
+ <div class="myio-col-summary__chart-body">
74028
+ <div class="myio-col-summary__pie" style="background: conic-gradient(${stops.join(", ")});"></div>
74029
+ <div class="myio-col-summary__legend">${legend.join("")}</div>
74030
+ </div>
74031
+ </div>`;
74032
+ }
74033
+ function buildContent(data) {
74034
+ const devices = Array.isArray(data.devices) ? data.devices.slice() : [];
74035
+ const fmt2 = data.formatValue || defaultFormatter(data.unit || "");
74036
+ const pd = resolvePercentDecimals(data.percentDecimals);
74037
+ const count = devices.length;
74038
+ const total = devices.reduce((s, d) => s + (Number(d.value) || 0), 0);
74039
+ const avg = count ? total / count : 0;
74040
+ const periodRow = data.periodLabel ? `<div class="myio-col-summary__kpi">
74041
+ <span class="myio-col-summary__kpi-label">Per\xEDodo</span>
74042
+ <span class="myio-col-summary__kpi-value">${esc3(data.periodLabel)}</span>
74043
+ </div>` : "";
74044
+ if (!count) {
74045
+ return `<div class="myio-col-summary">
74046
+ <div class="myio-col-summary__kpis">
74047
+ ${periodRow}
74048
+ <div class="myio-col-summary__kpi">
74049
+ <span class="myio-col-summary__kpi-label">Dispositivos</span>
74050
+ <span class="myio-col-summary__kpi-value">0</span>
74051
+ </div>
74052
+ </div>
74053
+ <div class="myio-col-summary__empty">Nenhum dispositivo.</div>
74054
+ </div>`;
74055
+ }
74056
+ const desc = devices.slice().sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0));
74057
+ const top3 = desc.slice(0, 3);
74058
+ const bottom3 = desc.slice(-3).reverse();
74059
+ const near3 = devices.slice().sort(
74060
+ (a, b) => Math.abs((Number(a.value) || 0) - avg) - Math.abs((Number(b.value) || 0) - avg)
74061
+ ).slice(0, 3);
74062
+ const row = (d) => `
74063
+ <div class="myio-col-summary__row">
74064
+ <span class="myio-col-summary__name" title="${esc3(d.name)}">${esc3(d.name)}</span>
74065
+ <span class="myio-col-summary__val">${esc3(fmt2(Number(d.value) || 0))}</span>
74066
+ <span class="myio-col-summary__pct">${fmtPct(Number(d.value) || 0, total, pd)}</span>
74067
+ </div>`;
74068
+ const group = (label, list) => list.length ? `<div class="myio-col-summary__group">
74069
+ <span class="myio-col-summary__group-label">${label}</span>
74070
+ ${list.map(row).join("")}
74071
+ </div>` : "";
74072
+ return `<div class="myio-col-summary">
74073
+ <div class="myio-col-summary__kpis">
74074
+ ${periodRow}
74075
+ <div class="myio-col-summary__kpi">
74076
+ <span class="myio-col-summary__kpi-label">Dispositivos</span>
74077
+ <span class="myio-col-summary__kpi-value">${count}</span>
74078
+ </div>
74079
+ <div class="myio-col-summary__kpi">
74080
+ <span class="myio-col-summary__kpi-label">Consumo m\xE9dio</span>
74081
+ <span class="myio-col-summary__kpi-value myio-col-summary__kpi-value--accent">${esc3(
74082
+ fmt2(avg)
74083
+ )}</span>
74084
+ </div>
74085
+ <div class="myio-col-summary__kpi">
74086
+ <span class="myio-col-summary__kpi-label">Consumo total</span>
74087
+ <span class="myio-col-summary__kpi-value">${esc3(fmt2(total))}</span>
74088
+ </div>
74089
+ </div>
74090
+ <div class="myio-col-summary__body">
74091
+ ${buildPieChart(devices, total, fmt2, pd)}
74092
+ <div class="myio-col-summary__lists">
74093
+ ${group("\u25B2 3 maiores", top3)}
74094
+ ${group("\u25BC 3 menores", bottom3)}
74095
+ ${group("\u25CF 3 na m\xE9dia", near3)}
74096
+ </div>
74097
+ </div>
74098
+ </div>`;
74099
+ }
74100
+ var ColumnSummaryTooltip = {
74101
+ /** Shows the column summary tooltip anchored to the trigger element. */
74102
+ show(triggerElement, data) {
74103
+ injectCSS10();
74104
+ InfoTooltip.show(triggerElement, {
74105
+ icon: "\u{1F4CA}",
74106
+ title: data.title ? `Resumo \u2014 ${data.title}` : "Resumo da Coluna",
74107
+ content: buildContent(data)
74108
+ });
74109
+ },
74110
+ /** Hides the tooltip immediately. */
74111
+ hide() {
74112
+ InfoTooltip.hide();
74113
+ },
74114
+ /** Starts the delayed hide (use on mouseleave). */
74115
+ startDelayedHide() {
74116
+ InfoTooltip.startDelayedHide();
74117
+ },
74118
+ /**
74119
+ * Attaches hover behavior to a trigger element. `getData` is called on each
74120
+ * hover so the summary always reflects the latest data. Returns a cleanup fn.
74121
+ */
74122
+ attach(triggerElement, getData) {
74123
+ injectCSS10();
74124
+ const handleEnter = () => {
74125
+ ColumnSummaryTooltip.show(triggerElement, getData());
74126
+ };
74127
+ const handleLeave = () => {
74128
+ InfoTooltip.startDelayedHide();
74129
+ };
74130
+ triggerElement.addEventListener("mouseenter", handleEnter);
74131
+ triggerElement.addEventListener("mouseleave", handleLeave);
74132
+ return () => {
74133
+ triggerElement.removeEventListener("mouseenter", handleEnter);
74134
+ triggerElement.removeEventListener("mouseleave", handleLeave);
74135
+ };
74136
+ }
74137
+ };
74138
+
73849
74139
  // src/utils/TempSensorSummaryTooltip.ts
73850
74140
  var TEMP_SENSOR_TOOLTIP_CSS = `
73851
74141
  /* ============================================
@@ -74336,7 +74626,7 @@ var TEMP_SENSOR_TOOLTIP_CSS = `
74336
74626
  }
74337
74627
  `;
74338
74628
  var cssInjected9 = false;
74339
- function injectCSS10() {
74629
+ function injectCSS11() {
74340
74630
  if (cssInjected9) return;
74341
74631
  if (typeof document === "undefined") return;
74342
74632
  const styleId = "myio-temp-sensor-tooltip-styles";
@@ -74723,7 +75013,7 @@ var TempSensorSummaryTooltip = {
74723
75013
  * Get or create container
74724
75014
  */
74725
75015
  getContainer() {
74726
- injectCSS10();
75016
+ injectCSS11();
74727
75017
  let container = document.getElementById(this.containerId);
74728
75018
  if (!container) {
74729
75019
  container = document.createElement("div");
@@ -75317,7 +75607,7 @@ var CONTRACT_SUMMARY_TOOLTIP_CSS = `
75317
75607
  }
75318
75608
  `;
75319
75609
  var cssInjected10 = false;
75320
- function injectCSS11() {
75610
+ function injectCSS12() {
75321
75611
  if (cssInjected10) return;
75322
75612
  if (typeof document === "undefined") return;
75323
75613
  const styleId = "myio-contract-summary-tooltip-styles";
@@ -75760,7 +76050,7 @@ var ContractSummaryTooltip = {
75760
76050
  * Get or create container
75761
76051
  */
75762
76052
  getContainer() {
75763
- injectCSS11();
76053
+ injectCSS12();
75764
76054
  let container = document.getElementById(this.containerId);
75765
76055
  if (!container) {
75766
76056
  container = document.createElement("div");
@@ -76246,7 +76536,7 @@ var USERS_SUMMARY_TOOLTIP_CSS = `
76246
76536
  }
76247
76537
  `;
76248
76538
  var cssInjected11 = false;
76249
- function injectCSS12() {
76539
+ function injectCSS13() {
76250
76540
  if (cssInjected11) return;
76251
76541
  if (typeof document === "undefined") return;
76252
76542
  const styleId = "myio-users-summary-tooltip-styles";
@@ -76277,7 +76567,7 @@ var UsersSummaryTooltip = {
76277
76567
  * Create or get the tooltip container
76278
76568
  */
76279
76569
  getContainer() {
76280
- injectCSS12();
76570
+ injectCSS13();
76281
76571
  let container = document.getElementById(this.containerId);
76282
76572
  if (!container) {
76283
76573
  container = document.createElement("div");
@@ -76954,7 +77244,7 @@ var ALARMS_SUMMARY_TOOLTIP_CSS = `
76954
77244
  }
76955
77245
  `;
76956
77246
  var cssInjected12 = false;
76957
- function injectCSS13() {
77247
+ function injectCSS14() {
76958
77248
  if (cssInjected12) return;
76959
77249
  if (typeof document === "undefined") return;
76960
77250
  const styleId = "myio-alarms-summary-tooltip-styles";
@@ -76985,7 +77275,7 @@ var AlarmsSummaryTooltip = {
76985
77275
  * Create or get the tooltip container
76986
77276
  */
76987
77277
  getContainer() {
76988
- injectCSS13();
77278
+ injectCSS14();
76989
77279
  let container = document.getElementById(this.containerId);
76990
77280
  if (!container) {
76991
77281
  container = document.createElement("div");
@@ -77400,7 +77690,7 @@ var NOTIFICATIONS_SUMMARY_TOOLTIP_CSS = `
77400
77690
  }
77401
77691
  `;
77402
77692
  var cssInjected13 = false;
77403
- function injectCSS14() {
77693
+ function injectCSS15() {
77404
77694
  if (cssInjected13) return;
77405
77695
  if (typeof document === "undefined") return;
77406
77696
  const styleId = "myio-notifications-summary-tooltip-styles";
@@ -77431,7 +77721,7 @@ var NotificationsSummaryTooltip = {
77431
77721
  * Create or get the tooltip container
77432
77722
  */
77433
77723
  getContainer() {
77434
- injectCSS14();
77724
+ injectCSS15();
77435
77725
  let container = document.getElementById(this.containerId);
77436
77726
  if (!container) {
77437
77727
  container = document.createElement("div");
@@ -108601,12 +108891,13 @@ function buildRow(d, idx) {
108601
108891
  if (d.val === null || d.val === void 0) return "\u2014";
108602
108892
  return Number(d.val).toLocaleString("pt-BR", { maximumFractionDigits: 3, useGrouping: false });
108603
108893
  };
108894
+ const pd = resolvePercentDecimals();
108604
108895
  return {
108605
108896
  idx: String(idx + 1),
108606
108897
  nome: d.labelOrName || d.name || "\u2014",
108607
108898
  identificador: d.deviceIdentifier || "\u2014",
108608
108899
  consumo: fmtVal(),
108609
- perc: d.perc !== void 0 ? `${d.perc.toFixed(1)}%` : "\u2014"
108900
+ perc: d.perc !== void 0 ? `${d.perc.toFixed(pd).replace(".", ",")}%` : "\u2014"
108610
108901
  };
108611
108902
  }
108612
108903
  function fmtPeriod(period) {
@@ -119183,10 +119474,10 @@ var AlarmsNotificationsPanelView = class {
119183
119474
  const renderListPanel = (group, items, sel) => {
119184
119475
  if (items.length === 0) return '<div class="afm-empty">Nenhum item encontrado</div>';
119185
119476
  return items.map((item) => {
119186
- const esc3 = this.esc(item);
119477
+ const esc4 = this.esc(item);
119187
119478
  return `<label class="afm-check-item">
119188
- <input type="checkbox" class="afm-checkbox" data-group="${group}" data-value="${esc3}"${sel.has(item) ? " checked" : ""}>
119189
- <span class="afm-check-label">${esc3}</span>
119479
+ <input type="checkbox" class="afm-checkbox" data-group="${group}" data-value="${esc4}"${sel.has(item) ? " checked" : ""}>
119480
+ <span class="afm-check-label">${esc4}</span>
119190
119481
  </label>`;
119191
119482
  }).join("");
119192
119483
  };
@@ -141469,6 +141760,7 @@ var version = package_default.version || "0.0.0";
141469
141760
  CONSUMPTION_CHART_DEFAULTS,
141470
141761
  CONSUMPTION_THEME_COLORS,
141471
141762
  CardGridPanel,
141763
+ ColumnSummaryTooltip,
141472
141764
  ConnectionStatusType,
141473
141765
  ContractSummaryTooltip,
141474
141766
  CustomerCardV1,
@@ -142016,6 +142308,7 @@ var version = package_default.version || "0.0.0";
142016
142308
  renderStatusDonutChart,
142017
142309
  renderTrendChart,
142018
142310
  reopenFreshdeskTicket,
142311
+ resolvePercentDecimals,
142019
142312
  schedCreateDateInput,
142020
142313
  schedCreateNumberInput,
142021
142314
  schedCreateSelect,