myio-js-library 0.1.503 → 0.1.505

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
@@ -1131,6 +1131,7 @@ __export(index_exports, {
1131
1131
  renderStatusDonutChart: () => renderStatusDonutChart,
1132
1132
  renderTrendChart: () => renderTrendChart,
1133
1133
  reopenFreshdeskTicket: () => reopenTicket,
1134
+ resolvePercentDecimals: () => resolvePercentDecimals,
1134
1135
  schedCreateDateInput: () => createDateInput,
1135
1136
  schedCreateNumberInput: () => createNumberInput,
1136
1137
  schedCreateSelect: () => createSelect,
@@ -1163,7 +1164,7 @@ module.exports = __toCommonJS(index_exports);
1163
1164
  // package.json
1164
1165
  var package_default = {
1165
1166
  name: "myio-js-library",
1166
- version: "0.1.503",
1167
+ version: "0.1.505",
1167
1168
  description: "A clean, standalone JS SDK for MYIO projects",
1168
1169
  license: "MIT",
1169
1170
  repository: "github:gh-myio/myio-js-library",
@@ -14499,6 +14500,16 @@ var TempComparisonTooltip = {
14499
14500
  }
14500
14501
  };
14501
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
+
14502
14513
  // src/thingsboard/main-dashboard-shopping/v-5.2.0/card/template-card-v5.js
14503
14514
  var LABEL_CHAR_LIMIT2 = 18;
14504
14515
  var DEVICE_TYPE_CONFIG = {
@@ -14633,8 +14644,11 @@ function renderCardComponentV5({
14633
14644
  // Tooltip on percentage badge
14634
14645
  showTempComparisonTooltip = false,
14635
14646
  // Tooltip on temperature deviation badge
14636
- showTempRangeTooltip = false
14647
+ showTempRangeTooltip = false,
14637
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
14638
14652
  }) {
14639
14653
  const {
14640
14654
  entityId,
@@ -14660,8 +14674,10 @@ function renderCardComponentV5({
14660
14674
  temperature,
14661
14675
  temperatureMin,
14662
14676
  temperatureMax,
14663
- temperatureStatus
14677
+ temperatureStatus,
14664
14678
  // 'ok' | 'above' | 'below' | undefined
14679
+ // Per-device exclude_groups_totals attribute (SERVER_SCOPE) — drives the orange marker
14680
+ excludeGroupsTotals
14665
14681
  } = entityObject;
14666
14682
  const MyIOToast2 = (function() {
14667
14683
  let toastContainer = null;
@@ -14890,6 +14906,20 @@ function renderCardComponentV5({
14890
14906
  height: 100%;
14891
14907
  }
14892
14908
 
14909
+ /* Subtle orange marker \u2014 device flagged in exclude_groups_totals */
14910
+ .myio-enhanced-card-container-v5.myio-card-excluded::after {
14911
+ content: '';
14912
+ position: absolute;
14913
+ left: 12px;
14914
+ right: 12px;
14915
+ bottom: 3px;
14916
+ height: 3px;
14917
+ border-radius: 2px;
14918
+ background: linear-gradient(90deg, rgba(245, 158, 11, 0), #f59e0b 50%, rgba(245, 158, 11, 0));
14919
+ pointer-events: none;
14920
+ z-index: 5;
14921
+ }
14922
+
14893
14923
  .myio-enhanced-card-container-v5 .myio-draggable-card {
14894
14924
  width: 100%;
14895
14925
  border-radius: 10px;
@@ -15092,6 +15122,7 @@ function renderCardComponentV5({
15092
15122
  const isTermostatoDevice = deviceType?.toUpperCase() === "TERMOSTATO";
15093
15123
  const isEnergyDeviceFlag = isEnergyDevice2(deviceType);
15094
15124
  const percentageForDisplay = isTankDevice2 ? (waterPercentage || 0) * 100 : perc;
15125
+ const _pctDecimals = resolvePercentDecimals(percentDecimals);
15095
15126
  const calculateTempStatus2 = () => {
15096
15127
  if (temperatureStatus) return temperatureStatus;
15097
15128
  const currentTemp = Number(val) || 0;
@@ -15170,9 +15201,7 @@ function renderCardComponentV5({
15170
15201
  <span class="consumption-value">${formatCardValue(cardEntity.lastValue, deviceType)}</span>
15171
15202
  </div>
15172
15203
  </div>
15173
- ${!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(
15174
- 1
15175
- )}%</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>` : ""}
15204
+ ${!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>` : ""}
15176
15205
  </div>
15177
15206
  </div>
15178
15207
  </div>
@@ -15183,6 +15212,12 @@ function renderCardComponentV5({
15183
15212
  `;
15184
15213
  container.innerHTML = cardHTML;
15185
15214
  const enhancedCardElement = container.querySelector(".device-card-centered");
15215
+ try {
15216
+ const _excl = typeof excludeGroupsTotals === "string" ? JSON.parse(excludeGroupsTotals) : excludeGroupsTotals;
15217
+ const _isExcluded = !!(_excl && _excl.enabled === true && (_excl.groups && Object.values(_excl.groups).some((v) => v === true) || Array.isArray(_excl.excludedGroups) && _excl.excludedGroups.length > 0));
15218
+ if (_isExcluded) container.classList.add("myio-card-excluded");
15219
+ } catch (e) {
15220
+ }
15186
15221
  if (!document.getElementById("myio-enhanced-card-layout-styles-v5")) {
15187
15222
  const layoutStyle = document.createElement("style");
15188
15223
  layoutStyle.id = "myio-enhanced-card-layout-styles-v5";
@@ -16022,8 +16057,8 @@ var INFO_TOOLTIP_CSS = `
16022
16057
  border: 1px solid #e2e8f0;
16023
16058
  border-radius: 12px;
16024
16059
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.12), 0 2px 10px rgba(0, 0, 0, 0.08);
16025
- min-width: 320px;
16026
- max-width: 400px;
16060
+ width: 395px;
16061
+ max-width: 90vw;
16027
16062
  font-size: 12px;
16028
16063
  color: #1e293b;
16029
16064
  overflow: hidden;
@@ -69975,8 +70010,7 @@ var ENERGY_SUMMARY_TOOLTIP_CSS = `
69975
70010
  border: 1px solid #e2e8f0;
69976
70011
  border-radius: 12px;
69977
70012
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15), 0 2px 10px rgba(0, 0, 0, 0.08);
69978
- min-width: 380px;
69979
- width: max-content;
70013
+ width: 395px;
69980
70014
  max-width: 90vw;
69981
70015
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
69982
70016
  font-size: 12px;
@@ -71027,6 +71061,7 @@ var EnergySummaryTooltip = {
71027
71061
  const timestamp = formatTimestamp3(summary.lastUpdated);
71028
71062
  const excludedNotice = this.renderExcludedNotice(summary.excludedFromCAG, summary.unit);
71029
71063
  const titleSuffix = summary.customerName ? ` (${summary.customerName})` : "";
71064
+ const isMultiShopping = (summary.byShoppingTotal?.length || 0) >= 2;
71030
71065
  return `
71031
71066
  <div class="energy-summary-tooltip__content">
71032
71067
  <div class="energy-summary-tooltip__header" data-drag-handle>
@@ -71060,10 +71095,10 @@ var EnergySummaryTooltip = {
71060
71095
  </div>
71061
71096
  <div class="energy-summary-tooltip__section-header">
71062
71097
  <span class="energy-summary-tooltip__section-title">Distribui\xE7\xE3o</span>
71063
- <div class="energy-summary-tooltip__grouping-tabs">
71098
+ ${isMultiShopping ? `<div class="energy-summary-tooltip__grouping-tabs">
71064
71099
  <button class="energy-summary-tooltip__grouping-tab active" data-view="category">Por Categoria</button>
71065
71100
  <button class="energy-summary-tooltip__grouping-tab" data-view="shopping">Por ${summary.entityLabel || "Shopping"}</button>
71066
- </div>
71101
+ </div>` : ""}
71067
71102
  </div>
71068
71103
 
71069
71104
  <!-- Category View (default) -->
@@ -71078,8 +71113,8 @@ var EnergySummaryTooltip = {
71078
71113
  </div>
71079
71114
  </div>
71080
71115
 
71081
- <!-- Shopping View -->
71082
- <div class="energy-summary-tooltip__shopping-view" data-grouping="shopping">
71116
+ <!-- Shopping View (head-office only) -->
71117
+ ${isMultiShopping ? `<div class="energy-summary-tooltip__shopping-view" data-grouping="shopping">
71083
71118
  <div class="energy-summary-tooltip__category-tree">
71084
71119
  <div class="energy-summary-tooltip__category-header">
71085
71120
  <span>${summary.entityLabel || "Shopping"}</span>
@@ -71088,7 +71123,7 @@ var EnergySummaryTooltip = {
71088
71123
  </div>
71089
71124
  ${this.renderShoppingView(summary.byShoppingTotal, summary.unit)}
71090
71125
  </div>
71091
- </div>
71126
+ </div>` : ""}
71092
71127
 
71093
71128
  <div class="energy-summary-tooltip__section-title">Status dos Dispositivos</div>
71094
71129
  <div class="energy-summary-tooltip__status-matrix">
@@ -71805,7 +71840,7 @@ var EnergySummaryTooltip = {
71805
71840
  };
71806
71841
  summary.byCategory = [entrada, lojas, areaComum];
71807
71842
  summary.totalDevices = entrada.deviceCount + lojas.deviceCount + areaComumDeviceCount;
71808
- summary.totalConsumption = state6.grandTotal || entrada.consumption;
71843
+ summary.totalConsumption = entrada.consumption || state6.grandTotal || 0;
71809
71844
  const widgetAggregation = receivedData?.deviceStatusAggregation;
71810
71845
  if (widgetAggregation && widgetAggregation.hasData) {
71811
71846
  summary.byStatus = {
@@ -72028,8 +72063,7 @@ var WATER_SUMMARY_TOOLTIP_CSS = `
72028
72063
  border: 1px solid #e2e8f0;
72029
72064
  border-radius: 12px;
72030
72065
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15), 0 2px 10px rgba(0, 0, 0, 0.08);
72031
- min-width: 380px;
72032
- width: max-content;
72066
+ width: 395px;
72033
72067
  max-width: 90vw;
72034
72068
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
72035
72069
  font-size: 12px;
@@ -72941,6 +72975,7 @@ var WaterSummaryTooltip = {
72941
72975
  const statusMatrix = this.renderStatusMatrix(summary.byStatus);
72942
72976
  const timestamp = formatTimestamp4(summary.lastUpdated);
72943
72977
  const titleSuffix = summary.customerName ? ` (${summary.customerName})` : "";
72978
+ const isMultiShopping = (summary.byShoppingTotal?.length || 0) >= 2;
72944
72979
  return `
72945
72980
  <div class="water-summary-tooltip__content">
72946
72981
  <div class="water-summary-tooltip__header" data-drag-handle>
@@ -72975,10 +73010,10 @@ var WaterSummaryTooltip = {
72975
73010
 
72976
73011
  <div class="water-summary-tooltip__section-header">
72977
73012
  <span class="water-summary-tooltip__section-title">Distribui\xE7\xE3o</span>
72978
- <div class="water-summary-tooltip__grouping-tabs">
73013
+ ${isMultiShopping ? `<div class="water-summary-tooltip__grouping-tabs">
72979
73014
  <button class="water-summary-tooltip__grouping-tab active" data-view="category">Por Categoria</button>
72980
73015
  <button class="water-summary-tooltip__grouping-tab" data-view="shopping">Por ${summary.entityLabel || "Shopping"}</button>
72981
- </div>
73016
+ </div>` : ""}
72982
73017
  </div>
72983
73018
 
72984
73019
  <!-- Category View (default) -->
@@ -72993,8 +73028,8 @@ var WaterSummaryTooltip = {
72993
73028
  </div>
72994
73029
  </div>
72995
73030
 
72996
- <!-- Shopping View -->
72997
- <div class="water-summary-tooltip__shopping-view" data-grouping="shopping">
73031
+ <!-- Shopping View (head-office only) -->
73032
+ ${isMultiShopping ? `<div class="water-summary-tooltip__shopping-view" data-grouping="shopping">
72998
73033
  <div class="water-summary-tooltip__category-tree">
72999
73034
  <div class="water-summary-tooltip__category-header">
73000
73035
  <span>${summary.entityLabel || "Shopping"}</span>
@@ -73003,7 +73038,7 @@ var WaterSummaryTooltip = {
73003
73038
  </div>
73004
73039
  ${this.renderShoppingView(summary.byShoppingTotal, summary.unit)}
73005
73040
  </div>
73006
- </div>
73041
+ </div>` : ""}
73007
73042
 
73008
73043
  <div class="water-summary-tooltip__section-title">Status dos Medidores</div>
73009
73044
  <div class="water-summary-tooltip__status-matrix">
@@ -73844,9 +73879,25 @@ var WaterSummaryTooltip = {
73844
73879
  };
73845
73880
 
73846
73881
  // src/utils/ColumnSummaryTooltip.ts
73882
+ var PIE_COLORS = [
73883
+ "#3e1a7d",
73884
+ "#9333ea",
73885
+ "#0891b2",
73886
+ "#16a34a",
73887
+ "#f59e0b",
73888
+ "#db2777",
73889
+ "#0284c7",
73890
+ "#b45309",
73891
+ "#15803d",
73892
+ "#7c3aed",
73893
+ "#dc2626",
73894
+ "#0d9488",
73895
+ "#ca8a04",
73896
+ "#be185d"
73897
+ ];
73847
73898
  var COLUMN_SUMMARY_CSS = `
73848
73899
  .myio-col-summary {
73849
- max-width: 300px;
73900
+ max-width: 320px;
73850
73901
  font-family: 'Nunito', 'Segoe UI', system-ui, sans-serif;
73851
73902
  }
73852
73903
  .myio-col-summary__kpis {
@@ -73864,12 +73915,10 @@ var COLUMN_SUMMARY_CSS = `
73864
73915
  .myio-col-summary__kpi-value {
73865
73916
  font-size: 12px; font-weight: 700; color: #1e293b; text-align: right;
73866
73917
  }
73867
- .myio-col-summary__kpi-value--accent {
73868
- font-size: 14px; color: #3e1a7d;
73869
- }
73870
- .myio-col-summary__group {
73871
- display: flex; flex-direction: column; gap: 1px; margin-top: 8px;
73872
- }
73918
+ .myio-col-summary__kpi-value--accent { font-size: 14px; color: #3e1a7d; }
73919
+ .myio-col-summary__body { display: block; }
73920
+ .myio-col-summary__lists { display: flex; flex-direction: column; }
73921
+ .myio-col-summary__group { display: flex; flex-direction: column; gap: 1px; margin-top: 8px; }
73873
73922
  .myio-col-summary__group-label {
73874
73923
  font-size: 10px; font-weight: 800; letter-spacing: 0.3px;
73875
73924
  text-transform: uppercase; color: #64748b; margin-bottom: 3px;
@@ -73882,9 +73931,7 @@ var COLUMN_SUMMARY_CSS = `
73882
73931
  flex: 1 1 auto; min-width: 0;
73883
73932
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
73884
73933
  }
73885
- .myio-col-summary__val {
73886
- flex: 0 0 auto; font-weight: 700; color: #16a34a; text-align: right;
73887
- }
73934
+ .myio-col-summary__val { flex: 0 0 auto; font-weight: 700; color: #16a34a; text-align: right; }
73888
73935
  .myio-col-summary__pct {
73889
73936
  flex: 0 0 auto; min-width: 44px; text-align: right;
73890
73937
  font-size: 10px; font-weight: 600; color: #64748b;
@@ -73893,6 +73940,69 @@ var COLUMN_SUMMARY_CSS = `
73893
73940
  padding: 14px 0; text-align: center; font-style: italic;
73894
73941
  font-size: 11px; color: #94a3b8;
73895
73942
  }
73943
+
73944
+ /* Pie chart \u2014 hidden in the compact view, revealed when maximized. */
73945
+ .myio-col-summary__chart { display: none; }
73946
+ .myio-col-summary__chart-title {
73947
+ font-size: 11px; font-weight: 800; letter-spacing: 0.3px;
73948
+ text-transform: uppercase; color: #3e1a7d; margin-bottom: 8px;
73949
+ }
73950
+ .myio-col-summary__chart-hint {
73951
+ font-size: 10px; font-weight: 500; color: #94a3b8; margin: 0 0 8px;
73952
+ }
73953
+ .myio-col-summary__chart-body { display: flex; gap: 16px; align-items: flex-start; }
73954
+ .myio-col-summary__pie {
73955
+ width: 200px; height: 200px; flex-shrink: 0;
73956
+ filter: drop-shadow(0 2px 8px rgba(0,0,0,0.15));
73957
+ }
73958
+ .myio-col-summary__slice {
73959
+ stroke: #ffffff; stroke-width: 1.5;
73960
+ transition: opacity 0.12s ease;
73961
+ cursor: pointer;
73962
+ }
73963
+ .myio-col-summary__slice.is-hl {
73964
+ stroke: #1e293b; stroke-width: 3;
73965
+ }
73966
+ .myio-col-summary__slice:hover { opacity: 0.85; }
73967
+ .myio-col-summary__legend {
73968
+ flex: 1 1 auto; min-width: 0; max-height: 320px; overflow-y: auto;
73969
+ display: flex; flex-direction: column; gap: 1px;
73970
+ }
73971
+ .myio-col-summary__legend-row {
73972
+ display: flex; align-items: center; gap: 6px; padding: 3px 5px; font-size: 11px;
73973
+ border-radius: 4px; cursor: pointer;
73974
+ transition: background 0.12s ease;
73975
+ }
73976
+ .myio-col-summary__legend-row:hover,
73977
+ .myio-col-summary__legend-row.is-hl { background: #f1ecfa; }
73978
+ .myio-col-summary__legend-row.is-excluded { opacity: 0.45; }
73979
+ .myio-col-summary__legend-row.is-excluded .myio-col-summary__legend-name {
73980
+ text-decoration: line-through;
73981
+ }
73982
+ .myio-col-summary__legend-dot {
73983
+ width: 9px; height: 9px; border-radius: 2px; flex-shrink: 0;
73984
+ }
73985
+ .myio-col-summary__legend-name {
73986
+ flex: 1 1 auto; min-width: 0;
73987
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #1e293b;
73988
+ }
73989
+ .myio-col-summary__legend-val { flex: 0 0 auto; font-weight: 700; color: #16a34a; }
73990
+ .myio-col-summary__legend-pct {
73991
+ flex: 0 0 auto; min-width: 42px; text-align: right; font-size: 10px; color: #64748b;
73992
+ }
73993
+
73994
+ /* Maximized \u2014 use the extra space: widen, big pie, lists side-by-side. */
73995
+ .myio-info-tooltip.maximized .myio-col-summary { max-width: none; }
73996
+ .myio-info-tooltip.maximized .myio-col-summary__chart {
73997
+ display: block; margin-bottom: 16px;
73998
+ padding-bottom: 14px; border-bottom: 1px solid #e3d9f3;
73999
+ }
74000
+ .myio-info-tooltip.maximized .myio-col-summary__pie { width: 380px; height: 380px; }
74001
+ .myio-info-tooltip.maximized .myio-col-summary__legend { max-height: 380px; }
74002
+ .myio-info-tooltip.maximized .myio-col-summary__lists {
74003
+ display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
74004
+ }
74005
+ .myio-info-tooltip.maximized .myio-col-summary__group { margin-top: 0; }
73896
74006
  `;
73897
74007
  var _cssInjected2 = false;
73898
74008
  function injectCSS10() {
@@ -73918,50 +74028,94 @@ function defaultFormatter(unit) {
73918
74028
  const nf = new Intl.NumberFormat("pt-BR", { maximumFractionDigits: 2 });
73919
74029
  return (v) => nf.format(Number(v) || 0) + (unit ? " " + unit : "");
73920
74030
  }
73921
- function fmtPct(value, total) {
74031
+ function fmtPct(value, total, decimals) {
73922
74032
  const p = total > 0 ? (Number(value) || 0) / total * 100 : 0;
73923
- return p.toFixed(1).replace(".", ",") + "%";
73924
- }
73925
- function buildContent(data) {
73926
- const devices = Array.isArray(data.devices) ? data.devices.slice() : [];
73927
- const fmt2 = data.formatValue || defaultFormatter(data.unit || "");
73928
- const count = devices.length;
73929
- const total = devices.reduce((s, d) => s + (Number(d.value) || 0), 0);
74033
+ return p.toFixed(decimals).replace(".", ",") + "%";
74034
+ }
74035
+ function sliceColor(originalIndex) {
74036
+ return PIE_COLORS[originalIndex % PIE_COLORS.length];
74037
+ }
74038
+ function polar(cx, cy, r, deg) {
74039
+ const rad = (deg - 90) * Math.PI / 180;
74040
+ return [cx + r * Math.cos(rad), cy + r * Math.sin(rad)];
74041
+ }
74042
+ function arcPath(cx, cy, r, a0, a1) {
74043
+ const [x0, y0] = polar(cx, cy, r, a0);
74044
+ const [x1, y1] = polar(cx, cy, r, a1);
74045
+ const large = a1 - a0 > 180 ? 1 : 0;
74046
+ return `M${cx},${cy} L${x0.toFixed(2)},${y0.toFixed(2)} A${r},${r} 0 ${large} 1 ${x1.toFixed(
74047
+ 2
74048
+ )},${y1.toFixed(2)} Z`;
74049
+ }
74050
+ var _state = null;
74051
+ var _rootEl = null;
74052
+ function visibleDevices() {
74053
+ if (!_state) return [];
74054
+ return _state.data.devices.map((d, idx) => ({ d, idx })).filter((x) => !_state.excluded.has(x.idx));
74055
+ }
74056
+ function buildPieSvg(visible, total) {
74057
+ if (!_state) return "";
74058
+ const positives = visible.filter((v) => (Number(v.d.value) || 0) > 0);
74059
+ if (!positives.length || total <= 0) {
74060
+ return `<svg class="myio-col-summary__pie" viewBox="0 0 220 220" role="img" aria-label="Sem dados">
74061
+ <circle cx="110" cy="110" r="100" fill="#f1f5f9"></circle>
74062
+ <text x="110" y="115" text-anchor="middle" font-size="12" fill="#94a3b8">sem dados</text>
74063
+ </svg>`;
74064
+ }
74065
+ const { fmt: fmt2, pd } = _state;
74066
+ if (positives.length === 1) {
74067
+ const v = positives[0];
74068
+ const val = Number(v.d.value) || 0;
74069
+ return `<svg class="myio-col-summary__pie" viewBox="0 0 220 220">
74070
+ <circle class="myio-col-summary__slice" data-idx="${v.idx}" cx="110" cy="110" r="100"
74071
+ fill="${sliceColor(v.idx)}"><title>${esc3(v.d.name)} \u2014 ${esc3(fmt2(val))} (${fmtPct(
74072
+ val,
74073
+ total,
74074
+ pd
74075
+ )})</title></circle>
74076
+ </svg>`;
74077
+ }
74078
+ let acc = 0;
74079
+ const paths = positives.map((v) => {
74080
+ const val = Number(v.d.value) || 0;
74081
+ const a0 = acc / total * 360;
74082
+ acc += val;
74083
+ const a1 = acc / total * 360;
74084
+ return `<path class="myio-col-summary__slice" data-idx="${v.idx}"
74085
+ d="${arcPath(110, 110, 100, a0, a1)}" fill="${sliceColor(v.idx)}"
74086
+ ><title>${esc3(v.d.name)} \u2014 ${esc3(fmt2(val))} (${fmtPct(val, total, pd)})</title></path>`;
74087
+ }).join("");
74088
+ return `<svg class="myio-col-summary__pie" viewBox="0 0 220 220">${paths}</svg>`;
74089
+ }
74090
+ function buildLegend(total) {
74091
+ if (!_state) return "";
74092
+ const { data, excluded, fmt: fmt2, pd } = _state;
74093
+ const rows = data.devices.map((d, idx) => {
74094
+ const val = Number(d.value) || 0;
74095
+ const isExcl = excluded.has(idx);
74096
+ const pct = isExcl ? "\u2014" : fmtPct(val, total, pd);
74097
+ return `<div class="myio-col-summary__legend-row${isExcl ? " is-excluded" : ""}" data-idx="${idx}"
74098
+ title="Clique para ${isExcl ? "incluir" : "remover"} da pizza">
74099
+ <span class="myio-col-summary__legend-dot" style="background:${sliceColor(idx)};"></span>
74100
+ <span class="myio-col-summary__legend-name">${esc3(d.name)}</span>
74101
+ <span class="myio-col-summary__legend-val">${esc3(fmt2(val))}</span>
74102
+ <span class="myio-col-summary__legend-pct">${pct}</span>
74103
+ </div>`;
74104
+ }).join("");
74105
+ return `<div class="myio-col-summary__legend">${rows}</div>`;
74106
+ }
74107
+ function buildInner() {
74108
+ if (!_state) return "";
74109
+ const { data, fmt: fmt2, pd } = _state;
74110
+ const visible = visibleDevices();
74111
+ const count = visible.length;
74112
+ const total = visible.reduce((s, v) => s + (Number(v.d.value) || 0), 0);
73930
74113
  const avg = count ? total / count : 0;
73931
74114
  const periodRow = data.periodLabel ? `<div class="myio-col-summary__kpi">
73932
74115
  <span class="myio-col-summary__kpi-label">Per\xEDodo</span>
73933
74116
  <span class="myio-col-summary__kpi-value">${esc3(data.periodLabel)}</span>
73934
74117
  </div>` : "";
73935
- if (!count) {
73936
- return `<div class="myio-col-summary">
73937
- <div class="myio-col-summary__kpis">
73938
- ${periodRow}
73939
- <div class="myio-col-summary__kpi">
73940
- <span class="myio-col-summary__kpi-label">Dispositivos</span>
73941
- <span class="myio-col-summary__kpi-value">0</span>
73942
- </div>
73943
- </div>
73944
- <div class="myio-col-summary__empty">Nenhum dispositivo.</div>
73945
- </div>`;
73946
- }
73947
- const desc = devices.slice().sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0));
73948
- const top3 = desc.slice(0, 3);
73949
- const bottom3 = desc.slice(-3).reverse();
73950
- const near3 = devices.slice().sort(
73951
- (a, b) => Math.abs((Number(a.value) || 0) - avg) - Math.abs((Number(b.value) || 0) - avg)
73952
- ).slice(0, 3);
73953
- const row = (d) => `
73954
- <div class="myio-col-summary__row">
73955
- <span class="myio-col-summary__name" title="${esc3(d.name)}">${esc3(d.name)}</span>
73956
- <span class="myio-col-summary__val">${esc3(fmt2(Number(d.value) || 0))}</span>
73957
- <span class="myio-col-summary__pct">${fmtPct(Number(d.value) || 0, total)}</span>
73958
- </div>`;
73959
- const group = (label, list) => list.length ? `<div class="myio-col-summary__group">
73960
- <span class="myio-col-summary__group-label">${label}</span>
73961
- ${list.map(row).join("")}
73962
- </div>` : "";
73963
- return `<div class="myio-col-summary">
73964
- <div class="myio-col-summary__kpis">
74118
+ const kpis = `<div class="myio-col-summary__kpis">
73965
74119
  ${periodRow}
73966
74120
  <div class="myio-col-summary__kpi">
73967
74121
  <span class="myio-col-summary__kpi-label">Dispositivos</span>
@@ -73977,21 +74131,98 @@ function buildContent(data) {
73977
74131
  <span class="myio-col-summary__kpi-label">Consumo total</span>
73978
74132
  <span class="myio-col-summary__kpi-value">${esc3(fmt2(total))}</span>
73979
74133
  </div>
73980
- </div>
73981
- ${group("\u25B2 3 maiores", top3)}
73982
- ${group("\u25BC 3 menores", bottom3)}
73983
- ${group("\u25CF 3 na m\xE9dia", near3)}
73984
- </div>`;
74134
+ </div>`;
74135
+ if (!data.devices.length) {
74136
+ return `${kpis}<div class="myio-col-summary__empty">Nenhum dispositivo.</div>`;
74137
+ }
74138
+ const desc = visible.slice().sort((a, b) => (Number(b.d.value) || 0) - (Number(a.d.value) || 0));
74139
+ const top3 = desc.slice(0, 3);
74140
+ const bottom3 = desc.slice(-3).reverse();
74141
+ const near3 = visible.slice().sort(
74142
+ (a, b) => Math.abs((Number(a.d.value) || 0) - avg) - Math.abs((Number(b.d.value) || 0) - avg)
74143
+ ).slice(0, 3);
74144
+ const row = (v) => `
74145
+ <div class="myio-col-summary__row">
74146
+ <span class="myio-col-summary__name" title="${esc3(v.d.name)}">${esc3(v.d.name)}</span>
74147
+ <span class="myio-col-summary__val">${esc3(fmt2(Number(v.d.value) || 0))}</span>
74148
+ <span class="myio-col-summary__pct">${fmtPct(Number(v.d.value) || 0, total, pd)}</span>
74149
+ </div>`;
74150
+ const group = (label, list) => list.length ? `<div class="myio-col-summary__group">
74151
+ <span class="myio-col-summary__group-label">${label}</span>
74152
+ ${list.map(row).join("")}
74153
+ </div>` : "";
74154
+ return `${kpis}
74155
+ <div class="myio-col-summary__body">
74156
+ <div class="myio-col-summary__chart">
74157
+ <div class="myio-col-summary__chart-title">Distribui\xE7\xE3o \u2014 ${count} dispositivos</div>
74158
+ <p class="myio-col-summary__chart-hint">Passe o mouse para destacar \xB7 clique na lista para remover da pizza</p>
74159
+ <div class="myio-col-summary__chart-body">
74160
+ ${buildPieSvg(visible, total)}
74161
+ ${buildLegend(total)}
74162
+ </div>
74163
+ </div>
74164
+ <div class="myio-col-summary__lists">
74165
+ ${group("\u25B2 3 maiores", top3)}
74166
+ ${group("\u25BC 3 menores", bottom3)}
74167
+ ${group("\u25CF 3 na m\xE9dia", near3)}
74168
+ </div>
74169
+ </div>`;
74170
+ }
74171
+ function setHighlight(idx) {
74172
+ if (!_rootEl) return;
74173
+ _rootEl.querySelectorAll(".is-hl").forEach((el2) => el2.classList.remove("is-hl"));
74174
+ if (idx == null) return;
74175
+ _rootEl.querySelectorAll(`[data-idx="${idx}"]`).forEach((el2) => el2.classList.add("is-hl"));
74176
+ }
74177
+ function rerender() {
74178
+ if (!_rootEl) return;
74179
+ _rootEl.innerHTML = buildInner();
74180
+ }
74181
+ function wireRoot(root) {
74182
+ root.addEventListener("mouseover", (e) => {
74183
+ const el2 = e.target?.closest?.("[data-idx]");
74184
+ setHighlight(el2 ? el2.getAttribute("data-idx") : null);
74185
+ });
74186
+ root.addEventListener("mouseout", (e) => {
74187
+ const el2 = e.target?.closest?.("[data-idx]");
74188
+ if (el2) setHighlight(null);
74189
+ });
74190
+ root.addEventListener("click", (e) => {
74191
+ const legendRow = e.target?.closest?.(
74192
+ ".myio-col-summary__legend-row"
74193
+ );
74194
+ if (!legendRow || !_state) return;
74195
+ const idx = Number(legendRow.getAttribute("data-idx"));
74196
+ if (!Number.isInteger(idx)) return;
74197
+ if (_state.excluded.has(idx)) _state.excluded.delete(idx);
74198
+ else _state.excluded.add(idx);
74199
+ rerender();
74200
+ });
73985
74201
  }
73986
74202
  var ColumnSummaryTooltip = {
73987
74203
  /** Shows the column summary tooltip anchored to the trigger element. */
73988
74204
  show(triggerElement, data) {
73989
74205
  injectCSS10();
74206
+ _state = {
74207
+ data: data && Array.isArray(data.devices) ? data : { ...data, devices: [] },
74208
+ excluded: /* @__PURE__ */ new Set(),
74209
+ fmt: data.formatValue || defaultFormatter(data.unit || ""),
74210
+ pd: resolvePercentDecimals(data.percentDecimals)
74211
+ };
73990
74212
  InfoTooltip.show(triggerElement, {
73991
74213
  icon: "\u{1F4CA}",
73992
74214
  title: data.title ? `Resumo \u2014 ${data.title}` : "Resumo da Coluna",
73993
- content: buildContent(data)
74215
+ content: `<div class="myio-col-summary">${buildInner()}</div>`
73994
74216
  });
74217
+ if (typeof requestAnimationFrame === "function") {
74218
+ requestAnimationFrame(() => {
74219
+ const roots = document.querySelectorAll(
74220
+ ".myio-info-tooltip .myio-col-summary"
74221
+ );
74222
+ _rootEl = roots.length ? roots[roots.length - 1] : null;
74223
+ if (_rootEl) wireRoot(_rootEl);
74224
+ });
74225
+ }
73995
74226
  },
73996
74227
  /** Hides the tooltip immediately. */
73997
74228
  hide() {
@@ -102545,11 +102776,11 @@ var FilterModalComponent = class {
102545
102776
  }
102546
102777
  selectAllDevices() {
102547
102778
  const devices = this.options.devices || [];
102548
- const visibleDevices = devices.filter((d) => {
102779
+ const visibleDevices2 = devices.filter((d) => {
102549
102780
  const el2 = this.overlay.querySelector(`[data-device-id="${d.id}"]`);
102550
102781
  return el2 && !el2.classList.contains("myio-fm__device-item--hidden");
102551
102782
  });
102552
- visibleDevices.forEach((device) => {
102783
+ visibleDevices2.forEach((device) => {
102553
102784
  this.selectedDeviceIds.add(device.id);
102554
102785
  this.updateDeviceUI(device.id);
102555
102786
  });
@@ -102557,11 +102788,11 @@ var FilterModalComponent = class {
102557
102788
  }
102558
102789
  selectNoDevices() {
102559
102790
  const devices = this.options.devices || [];
102560
- const visibleDevices = devices.filter((d) => {
102791
+ const visibleDevices2 = devices.filter((d) => {
102561
102792
  const el2 = this.overlay.querySelector(`[data-device-id="${d.id}"]`);
102562
102793
  return el2 && !el2.classList.contains("myio-fm__device-item--hidden");
102563
102794
  });
102564
- visibleDevices.forEach((device) => {
102795
+ visibleDevices2.forEach((device) => {
102565
102796
  this.selectedDeviceIds.delete(device.id);
102566
102797
  this.updateDeviceUI(device.id);
102567
102798
  });
@@ -108777,12 +109008,13 @@ function buildRow(d, idx) {
108777
109008
  if (d.val === null || d.val === void 0) return "\u2014";
108778
109009
  return Number(d.val).toLocaleString("pt-BR", { maximumFractionDigits: 3, useGrouping: false });
108779
109010
  };
109011
+ const pd = resolvePercentDecimals();
108780
109012
  return {
108781
109013
  idx: String(idx + 1),
108782
109014
  nome: d.labelOrName || d.name || "\u2014",
108783
109015
  identificador: d.deviceIdentifier || "\u2014",
108784
109016
  consumo: fmtVal(),
108785
- perc: d.perc !== void 0 ? `${d.perc.toFixed(1)}%` : "\u2014"
109017
+ perc: d.perc !== void 0 ? `${d.perc.toFixed(pd).replace(".", ",")}%` : "\u2014"
108786
109018
  };
108787
109019
  }
108788
109020
  function fmtPeriod(period) {
@@ -142193,6 +142425,7 @@ var version = package_default.version || "0.0.0";
142193
142425
  renderStatusDonutChart,
142194
142426
  renderTrendChart,
142195
142427
  reopenFreshdeskTicket,
142428
+ resolvePercentDecimals,
142196
142429
  schedCreateDateInput,
142197
142430
  schedCreateNumberInput,
142198
142431
  schedCreateSelect,