myio-js-library 0.1.414 → 0.1.415

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
@@ -1122,7 +1122,7 @@ module.exports = __toCommonJS(index_exports);
1122
1122
  // package.json
1123
1123
  var package_default = {
1124
1124
  name: "myio-js-library",
1125
- version: "0.1.414",
1125
+ version: "0.1.415",
1126
1126
  description: "A clean, standalone JS SDK for MYIO projects",
1127
1127
  license: "MIT",
1128
1128
  repository: "github:gh-myio/myio-js-library",
@@ -49980,11 +49980,14 @@ function renderAlarmCard(alarm, _params) {
49980
49980
  ).join("")}</div>
49981
49981
  <button class="alarm-type-scroll-btn alarm-type-scroll-btn--right" tabindex="-1" aria-hidden="true">&#8250;</button>
49982
49982
  </div>` : "";
49983
- return `<article class="alarm-card${isSelected ? " alarm-card--selected" : ""}" data-alarm-id="${alarm.id}" data-severity="${alarm.severity}" data-state="${alarm.state}">
49983
+ const hideSelect = _params?.hideSelect ?? false;
49984
+ const hideDetails = _params?.hideDetails ?? false;
49985
+ const hideOccurrenceCount = _params?.hideOccurrenceCount ?? false;
49986
+ return `<article class="alarm-card${isSelected ? " alarm-card--selected" : ""}${hideDetails ? " alarm-card--clickable" : ""}" data-alarm-id="${alarm.id}" data-severity="${alarm.severity}" data-state="${alarm.state}">
49984
49987
  <header class="alarm-card-header">
49985
- <label class="alarm-card-checkbox-wrap" title="Selecionar para a\xE7\xE3o em lote" onclick="event.stopPropagation()">
49988
+ ${!hideSelect ? `<label class="alarm-card-checkbox-wrap" title="Selecionar para a\xE7\xE3o em lote" onclick="event.stopPropagation()">
49986
49989
  <input type="checkbox" class="alarm-card-select" data-alarm-id="${alarm.id}" data-alarm-title="${escapeHtml3(rawTitle)}"${isSelected ? " checked" : ""}>
49987
- </label>
49990
+ </label>` : ""}
49988
49991
  ${showDeviceBadge && safeSource ? `<span class="alarm-card-device-badge" title="${safeSource}"><svg viewBox="0 0 24 24" width="10" height="10" fill="currentColor" aria-hidden="true"><path d="M4 6h16v10H4zm8 12c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1zm-4 0h8v-1H8v1z"/></svg>${safeSource}</span>` : ""}
49989
49992
  <div class="alarm-card-badges">
49990
49993
  <span class="alarm-severity-badge" data-severity="${alarm.severity}" title="${severityConfig.label}">${severityConfig.icon}</span>
@@ -49996,10 +49999,10 @@ function renderAlarmCard(alarm, _params) {
49996
49999
  ${typeChipsHtml}
49997
50000
  ${showCustomer ? `<span class="alarm-shopping-chip">${BUILDING_ICON}<span class="chip-text">${safeCustomerName}</span></span>` : ""}
49998
50001
  <div class="alarm-card-stats">
49999
- <div class="alarm-stat">
50002
+ ${!hideOccurrenceCount ? `<div class="alarm-stat">
50000
50003
  <span class="alarm-stat-value alarm-stat-value--large">${safeOccurrences}</span>
50001
50004
  <span class="alarm-stat-label">Qte.</span>
50002
- </div>
50005
+ </div>` : ""}
50003
50006
  <div class="alarm-stat">
50004
50007
  <span class="alarm-stat-value">${firstSeenRelative}</span>
50005
50008
  <span class="alarm-stat-label">1a. Ocorr\xEAncia</span>
@@ -50011,10 +50014,10 @@ function renderAlarmCard(alarm, _params) {
50011
50014
  </div>
50012
50015
  </div>
50013
50016
  <footer class="alarm-card-footer">
50014
- ${isActive ? `<button class="btn btn-ack" data-action="acknowledge" data-alarm-id="${alarm.id}" title="Reconhecer"><svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" aria-hidden="true"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg></button>` : ""}
50015
- ${alarm.state !== "CLOSED" ? `<button class="btn btn-snooze" data-action="snooze" data-alarm-id="${alarm.id}" title="Adiar"><svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" aria-hidden="true"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67V7z"/></svg></button>` : ""}
50016
- ${alarm.state !== "CLOSED" ? `<button class="btn btn-escalate" data-action="escalate" data-alarm-id="${alarm.id}" title="Escalar"><svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" aria-hidden="true"><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg></button>` : ""}
50017
- <button class="btn btn-details" data-action="details" data-alarm-id="${alarm.id}" title="Detalhes"><svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" aria-hidden="true"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg></button>
50017
+ ${!_params?.hideActions && isActive ? `<button class="btn btn-ack" data-action="acknowledge" data-alarm-id="${alarm.id}" title="Reconhecer"><svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" aria-hidden="true"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg></button>` : ""}
50018
+ ${!_params?.hideActions && alarm.state !== "CLOSED" ? `<button class="btn btn-snooze" data-action="snooze" data-alarm-id="${alarm.id}" title="Adiar"><svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" aria-hidden="true"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67V7z"/></svg></button>` : ""}
50019
+ ${!_params?.hideActions && alarm.state !== "CLOSED" ? `<button class="btn btn-escalate" data-action="escalate" data-alarm-id="${alarm.id}" title="Escalar"><svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" aria-hidden="true"><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg></button>` : ""}
50020
+ ${!hideDetails ? `<button class="btn btn-details" data-action="details" data-alarm-id="${alarm.id}" title="Detalhes"><svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor" aria-hidden="true"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg></button>` : ""}
50018
50021
  </footer>
50019
50022
  </article>`;
50020
50023
  }
@@ -50445,7 +50448,7 @@ function createHodChart(canvas, vals) {
50445
50448
  function parseDevices(source) {
50446
50449
  return source.split(/[,;]+/).map((s) => s.trim()).filter(Boolean);
50447
50450
  }
50448
- function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50451
+ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode, onAction) {
50449
50452
  const sev = SEVERITY_CONFIG[alarm.severity];
50450
50453
  const st = STATE_CONFIG[alarm.state];
50451
50454
  const count = alarm.occurrenceCount || 1;
@@ -50517,9 +50520,9 @@ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50517
50520
  <svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><path d="M14 2v6h6M16 13H8M16 17H8M10 9H8"/></svg>
50518
50521
  Resumo
50519
50522
  </button>
50520
- <button class="adm-tab" data-panel="relatorio">
50521
- <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
50522
- Relat\xF3rio <span class="adm-tab-badge">${count}</span>
50523
+ <button class="adm-tab" data-panel="timeline">
50524
+ <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><line x1="12" y1="2" x2="12" y2="6"/><line x1="12" y1="18" x2="12" y2="22"/><line x1="4.22" y1="4.22" x2="7.05" y2="7.05"/><line x1="16.95" y1="16.95" x2="19.78" y2="19.78"/><line x1="2" y1="12" x2="6" y2="12"/><line x1="18" y1="12" x2="22" y2="12"/><line x1="4.22" y1="19.78" x2="7.05" y2="16.95"/><line x1="16.95" y1="7.05" x2="19.78" y2="4.22"/></svg>
50525
+ Timeline <span class="adm-tab-badge">${count}</span>
50523
50526
  </button>
50524
50527
  <button class="adm-tab" data-panel="dispositivos">
50525
50528
  <svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor"><path d="M20 3H4a1 1 0 00-1 1v12a1 1 0 001 1h8v2H8v2h8v-2h-4v-2h8a1 1 0 001-1V4a1 1 0 00-1-1zm-1 12H5V5h14v10z"/></svg>
@@ -50540,7 +50543,7 @@ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50540
50543
 
50541
50544
  <!-- RESUMO -->
50542
50545
  <div class="adm-panel is-active" data-panel="resumo">
50543
- <div class="adm-kpi-grid">
50546
+ ${groupMode !== "separado" ? `<div class="adm-kpi-grid">
50544
50547
  <div class="adm-kpi">
50545
50548
  <div class="adm-kpi-value" style="color:${sev.text}">${count}</div>
50546
50549
  <div class="adm-kpi-label">Ocorr\xEAncias</div>
@@ -50553,7 +50556,7 @@ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50553
50556
  <div class="adm-kpi-value">${durLabel}</div>
50554
50557
  <div class="adm-kpi-label">Dura\xE7\xE3o</div>
50555
50558
  </div>
50556
- </div>
50559
+ </div>` : ""}
50557
50560
 
50558
50561
  ${alarm.description ? `<div class="adm-description">${escHtml(alarm.description)}</div>` : ""}
50559
50562
 
@@ -50609,8 +50612,32 @@ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50609
50612
 
50610
50613
  </div>
50611
50614
 
50612
- <!-- RELAT\xD3RIO (unificado: timeline + estat\xEDsticas + sum\xE1rio + exporta\xE7\xE3o) -->
50613
- <div class="adm-panel" data-panel="relatorio">
50615
+ <!-- TIMELINE (ocorr\xEAncias + a\xE7\xF5es individuais e em lote) -->
50616
+ <div class="adm-panel" data-panel="timeline">
50617
+ <div class="adm-tl-header" id="admTlHeader">
50618
+ <div class="adm-tl-toolbar">
50619
+ <span class="adm-tl-summary" id="admTlSummary">${count} ocorr\xEAncia${count !== 1 ? "s" : ""}</span>
50620
+ <button class="adm-tl-batch-toggle" id="admTlBatchToggle" title="A\xE7\xF5es em lote">
50621
+ <svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="4" height="4" rx="1"/><path d="M10 7h11"/><rect x="3" y="12" width="4" height="4" rx="1"/><path d="M10 14h11"/><rect x="3" y="19" width="4" height="4" rx="1"/><path d="M10 21h11"/></svg>
50622
+ A\xE7\xE3o em lote
50623
+ </button>
50624
+ </div>
50625
+ <div class="adm-tl-batch-bar" id="admTlBatchBar">
50626
+ <label class="adm-tl-sel-all-label">
50627
+ <input type="checkbox" id="admTlSelAll" class="adm-tl-sel-all-cb">
50628
+ <span>Todos</span>
50629
+ </label>
50630
+ <span class="adm-tl-sel-count" id="admTlSelCount">0 selecionados</span>
50631
+ <select class="adm-tl-action-sel" id="admTlActionSel">
50632
+ <option value="">Selecione a\xE7\xE3o\u2026</option>
50633
+ <option value="acknowledge">Reconhecer</option>
50634
+ <option value="snooze">Adiar</option>
50635
+ <option value="escalate">Escalar</option>
50636
+ </select>
50637
+ <button class="adm-tl-exec-btn" id="admTlExecBtn" disabled>Executar</button>
50638
+ <button class="adm-tl-cancel-btn" id="admTlCancelBtn">Cancelar</button>
50639
+ </div>
50640
+ </div>
50614
50641
  <div class="adm-report-toolbar">
50615
50642
  <label class="adm-report-label">De</label>
50616
50643
  <input type="date" class="adm-report-date-input" id="admRptStart" value="${fmtDateInput(firstMs)}">
@@ -50756,7 +50783,7 @@ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50756
50783
  }, 30));
50757
50784
  });
50758
50785
  }
50759
- const rptPanel = overlay.querySelector('.adm-panel[data-panel="relatorio"]');
50786
+ const rptPanel = overlay.querySelector('.adm-panel[data-panel="timeline"]');
50760
50787
  if (rptPanel) {
50761
50788
  const emitBtn = rptPanel.querySelector("#admRptEmit");
50762
50789
  const csvBtn = rptPanel.querySelector("#admExportCsv");
@@ -50764,11 +50791,18 @@ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50764
50791
  const grid = rptPanel.querySelector("#admRptGrid");
50765
50792
  const isSeparado = groupMode === "separado";
50766
50793
  let lastCsvRows = [];
50794
+ let batchActive = false;
50795
+ const batchSelectedIds = /* @__PURE__ */ new Set();
50796
+ const _svgAck = `<svg viewBox="0 0 24 24" width="11" height="11" fill="currentColor" aria-hidden="true"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>`;
50797
+ const _svgSnooze = `<svg viewBox="0 0 24 24" width="11" height="11" fill="currentColor" aria-hidden="true"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67V7z"/></svg>`;
50798
+ const _svgEscalate = `<svg viewBox="0 0 24 24" width="11" height="11" fill="currentColor" aria-hidden="true"><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg>`;
50767
50799
  const buildOccurrenceSection = (occFirst, occLast) => {
50768
50800
  const intervalMs = count > 1 ? (occLast - occFirst) / (count - 1) : 0;
50769
50801
  const trigStr = alarm.triggerValue != null ? String(alarm.triggerValue) : null;
50770
50802
  const hasTrigger = trigStr != null;
50771
50803
  const showDevice = !isSeparado && devices.length > 0;
50804
+ const isActive = alarm.state === "OPEN" || alarm.state === "ESCALATED";
50805
+ const isClosed = alarm.state === "CLOSED";
50772
50806
  const idxStyle = (isSingle, isLatest, isFirst) => {
50773
50807
  if (isSingle) return "color:#7c3aed;font-weight:700";
50774
50808
  if (isLatest) return "color:#3b82f6;font-weight:700";
@@ -50816,7 +50850,16 @@ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50816
50850
  }
50817
50851
  const sepStyle = gi > 0 ? ' style="margin-top:12px;padding-top:12px;border-top:1px dashed #e5e7eb"' : "";
50818
50852
  return `<div${sepStyle}>
50819
- <div class="adm-timeline-group-header">${escHtml(grp.title)}<span class="adm-timeline-group-count">${gCount}</span></div>
50853
+ <div class="adm-timeline-group-header">
50854
+ <label class="adm-tl-cb-wrap" data-cb-wrap><input type="checkbox" class="adm-tl-row-cb" data-item-id="${alarm.id}__grp${gi}"></label>
50855
+ <span class="adm-tl-group-title">${escHtml(grp.title)}</span>
50856
+ <span class="adm-timeline-group-count">${gCount}</span>
50857
+ <div class="adm-tl-row-btns adm-tl-row-btns--group" data-row-btns>
50858
+ ${isActive ? `<button class="adm-tl-row-btn adm-tl-row-btn--ack" data-action="acknowledge" data-item-id="${alarm.id}" title="Reconhecer">${_svgAck}</button>` : ""}
50859
+ ${!isClosed ? `<button class="adm-tl-row-btn adm-tl-row-btn--snooze" data-action="snooze" data-item-id="${alarm.id}" title="Adiar">${_svgSnooze}</button>` : ""}
50860
+ ${!isClosed ? `<button class="adm-tl-row-btn adm-tl-row-btn--escalate" data-action="escalate" data-item-id="${alarm.id}" title="Escalar">${_svgEscalate}</button>` : ""}
50861
+ </div>
50862
+ </div>
50820
50863
  <div class="adm-rpt-table-wrap" style="margin-bottom:0">
50821
50864
  <table class="adm-rpt-table">${gThead}<tbody>${gRows.join("")}</tbody></table>
50822
50865
  </div>
@@ -50830,6 +50873,7 @@ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50830
50873
  <th class="adm-rpt-th">Data/Hora</th>
50831
50874
  ${showDevice ? `<th class="adm-rpt-th">Dispositivo</th>` : ""}
50832
50875
  ${hasTrigger ? `<th class="adm-rpt-th adm-rpt-th--num">Trigger</th>` : ""}
50876
+ <th class="adm-rpt-th adm-tl-actions-th">A\xE7\xF5es</th>
50833
50877
  </tr></thead>`;
50834
50878
  const MAX_SHOWN = 30;
50835
50879
  for (let i = count; i >= 1; i--) {
@@ -50846,6 +50890,14 @@ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50846
50890
  <td class="adm-rpt-cell">${timeStr}</td>
50847
50891
  ${showDevice ? `<td class="adm-rpt-cell adm-rpt-cell--dev">${escHtml(device)}</td>` : ""}
50848
50892
  ${hasTrigger ? `<td class="adm-rpt-cell adm-rpt-cell--num">${escHtml(trigStr)}</td>` : ""}
50893
+ <td class="adm-rpt-cell adm-tl-action-cell">
50894
+ <label class="adm-tl-cb-wrap" data-cb-wrap><input type="checkbox" class="adm-tl-row-cb" data-item-id="${alarm.id}__row${i}"></label>
50895
+ <div class="adm-tl-row-btns" data-row-btns>
50896
+ ${isActive ? `<button class="adm-tl-row-btn adm-tl-row-btn--ack" data-action="acknowledge" data-item-id="${alarm.id}" title="Reconhecer">${_svgAck}</button>` : ""}
50897
+ ${!isClosed ? `<button class="adm-tl-row-btn adm-tl-row-btn--snooze" data-action="snooze" data-item-id="${alarm.id}" title="Adiar">${_svgSnooze}</button>` : ""}
50898
+ ${!isClosed ? `<button class="adm-tl-row-btn adm-tl-row-btn--escalate" data-action="escalate" data-item-id="${alarm.id}" title="Escalar">${_svgEscalate}</button>` : ""}
50899
+ </div>
50900
+ </td>
50849
50901
  </tr>`);
50850
50902
  const csvRow = [`#${i}`, fmt(tsMs)];
50851
50903
  if (showDevice) csvRow.push(device);
@@ -50860,6 +50912,7 @@ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50860
50912
  <tfoot><tr>
50861
50913
  <td class="adm-rpt-cell adm-rpt-cell--total" colspan="${showDevice ? hasTrigger ? 3 : 2 : hasTrigger ? 2 : 1}">Total</td>
50862
50914
  <td class="adm-rpt-cell adm-rpt-cell--num adm-rpt-cell--total">${count} ocorr\xEAncia${count !== 1 ? "s" : ""}</td>
50915
+ <td class="adm-rpt-cell adm-rpt-cell--total"></td>
50863
50916
  </tr></tfoot>
50864
50917
  </table>
50865
50918
  </div>`;
@@ -50958,8 +51011,89 @@ function openAlarmDetailsModal(alarm, themeMode = "light", groupMode) {
50958
51011
  </body></html>`);
50959
51012
  win.document.close();
50960
51013
  });
50961
- emitBtn?.addEventListener("click", () => buildReportTable());
51014
+ emitBtn?.addEventListener("click", () => {
51015
+ buildReportTable();
51016
+ if (batchActive && grid) {
51017
+ grid.querySelectorAll("[data-cb-wrap]").forEach((el) => {
51018
+ el.style.display = "inline-flex";
51019
+ });
51020
+ grid.querySelectorAll("[data-row-btns]").forEach((el) => {
51021
+ el.style.display = "none";
51022
+ });
51023
+ }
51024
+ });
50962
51025
  buildReportTable();
51026
+ const batchToggleBtn = rptPanel.querySelector("#admTlBatchToggle");
51027
+ const batchBar = rptPanel.querySelector("#admTlBatchBar");
51028
+ const selAllCb = rptPanel.querySelector("#admTlSelAll");
51029
+ const selCountEl = rptPanel.querySelector("#admTlSelCount");
51030
+ const actionSel = rptPanel.querySelector("#admTlActionSel");
51031
+ const execBtn = rptPanel.querySelector("#admTlExecBtn");
51032
+ const cancelBatchBtn = rptPanel.querySelector("#admTlCancelBtn");
51033
+ const getAllRowCbs = () => Array.from((grid ?? rptPanel).querySelectorAll(".adm-tl-row-cb"));
51034
+ const updateBatchSelCount = () => {
51035
+ if (selCountEl) selCountEl.textContent = `${batchSelectedIds.size} selecionado${batchSelectedIds.size !== 1 ? "s" : ""}`;
51036
+ if (execBtn) execBtn.disabled = batchSelectedIds.size === 0 || !actionSel?.value;
51037
+ };
51038
+ const applyBatchVisuals = (active) => {
51039
+ (grid ?? rptPanel).querySelectorAll("[data-cb-wrap]").forEach((el) => {
51040
+ el.style.display = active ? "inline-flex" : "none";
51041
+ });
51042
+ (grid ?? rptPanel).querySelectorAll("[data-row-btns]").forEach((el) => {
51043
+ el.style.display = active ? "none" : "inline-flex";
51044
+ });
51045
+ };
51046
+ const setBatchMode = (active) => {
51047
+ batchActive = active;
51048
+ batchToggleBtn?.classList.toggle("is-active", active);
51049
+ if (batchBar) batchBar.style.display = active ? "flex" : "none";
51050
+ applyBatchVisuals(active);
51051
+ if (!active) {
51052
+ batchSelectedIds.clear();
51053
+ if (selAllCb) selAllCb.checked = false;
51054
+ if (actionSel) actionSel.value = "";
51055
+ updateBatchSelCount();
51056
+ }
51057
+ };
51058
+ batchToggleBtn?.addEventListener("click", () => setBatchMode(!batchActive));
51059
+ cancelBatchBtn?.addEventListener("click", () => setBatchMode(false));
51060
+ selAllCb?.addEventListener("change", () => {
51061
+ const checked = selAllCb.checked;
51062
+ getAllRowCbs().forEach((cb) => {
51063
+ cb.checked = checked;
51064
+ if (checked && cb.dataset.itemId) batchSelectedIds.add(cb.dataset.itemId);
51065
+ });
51066
+ if (!checked) batchSelectedIds.clear();
51067
+ updateBatchSelCount();
51068
+ });
51069
+ actionSel?.addEventListener("change", () => updateBatchSelCount());
51070
+ grid?.addEventListener("change", (e) => {
51071
+ const cb = e.target.closest(".adm-tl-row-cb");
51072
+ if (!cb) return;
51073
+ const id = cb.dataset.itemId;
51074
+ if (!id) return;
51075
+ if (cb.checked) batchSelectedIds.add(id);
51076
+ else {
51077
+ batchSelectedIds.delete(id);
51078
+ if (selAllCb) selAllCb.checked = false;
51079
+ }
51080
+ updateBatchSelCount();
51081
+ });
51082
+ grid?.addEventListener("click", (e) => {
51083
+ const btn = e.target.closest("[data-action][data-item-id]");
51084
+ if (!btn || !onAction) return;
51085
+ const action = btn.dataset.action;
51086
+ const itemId = btn.dataset.itemId;
51087
+ const baseId = itemId.split("__")[0];
51088
+ if (action && baseId) onAction(action, baseId);
51089
+ });
51090
+ execBtn?.addEventListener("click", () => {
51091
+ const action = actionSel?.value;
51092
+ if (!action || batchSelectedIds.size === 0 || !onAction) return;
51093
+ const uniqueBaseIds = [...new Set([...batchSelectedIds].map((id) => id.split("__")[0]))];
51094
+ uniqueBaseIds.forEach((id) => onAction(action, id));
51095
+ setBatchMode(false);
51096
+ });
50963
51097
  }
50964
51098
  const annotPanelEl = overlay.querySelector('.adm-panel[data-panel="anotacoes"]');
50965
51099
  if (annotPanelEl) {
@@ -51611,6 +51745,11 @@ var ALARMS_NOTIFICATIONS_PANEL_STYLES = `
51611
51745
  background: var(--alarms-card-hover);
51612
51746
  }
51613
51747
 
51748
+ /* Grouped modes (consolidado/porDispositivo): whole card is the click target */
51749
+ .alarm-card--clickable {
51750
+ cursor: pointer;
51751
+ }
51752
+
51614
51753
  /* Severity border colors */
51615
51754
  .alarm-card[data-severity="CRITICAL"] {
51616
51755
  border-left-color: var(--severity-critical);
@@ -52583,7 +52722,7 @@ var ALARMS_NOTIFICATIONS_PANEL_STYLES = `
52583
52722
  display: flex;
52584
52723
  align-items: center;
52585
52724
  justify-content: center;
52586
- z-index: 100002;
52725
+ z-index: 10000010;
52587
52726
  opacity: 0;
52588
52727
  transition: opacity 0.2s ease;
52589
52728
  }
@@ -52854,7 +52993,7 @@ var ALARMS_NOTIFICATIONS_PANEL_STYLES = `
52854
52993
  inset: 0;
52855
52994
  background: rgba(0, 0, 0, 0.52);
52856
52995
  backdrop-filter: blur(4px);
52857
- z-index: 100004;
52996
+ z-index: 10000010;
52858
52997
  display: flex;
52859
52998
  align-items: center;
52860
52999
  justify-content: center;
@@ -53361,6 +53500,141 @@ var ALARMS_NOTIFICATIONS_PANEL_STYLES = `
53361
53500
  border-radius: 8px;
53362
53501
  }
53363
53502
 
53503
+ /* ---- Timeline tab: batch toolbar + per-row actions ---- */
53504
+ .adm-tl-header {
53505
+ border-bottom: 1px solid #e5e7eb;
53506
+ padding-bottom: 6px;
53507
+ margin-bottom: 4px;
53508
+ }
53509
+ .adm-tl-toolbar {
53510
+ display: flex;
53511
+ align-items: center;
53512
+ justify-content: space-between;
53513
+ gap: 8px;
53514
+ padding: 4px 0 5px;
53515
+ }
53516
+ .adm-tl-summary {
53517
+ font-size: 11px;
53518
+ color: #6b7280;
53519
+ font-weight: 500;
53520
+ }
53521
+ .adm-tl-batch-toggle {
53522
+ display: inline-flex;
53523
+ align-items: center;
53524
+ gap: 5px;
53525
+ padding: 4px 10px;
53526
+ border: 1px solid #d1d5db;
53527
+ border-radius: 6px;
53528
+ background: #fff;
53529
+ color: #374151;
53530
+ font-size: 11px;
53531
+ font-weight: 600;
53532
+ cursor: pointer;
53533
+ transition: border-color 0.15s, color 0.15s, background 0.15s;
53534
+ }
53535
+ .adm-tl-batch-toggle:hover {
53536
+ border-color: #7c3aed;
53537
+ color: #7c3aed;
53538
+ background: rgba(124, 58, 237, 0.04);
53539
+ }
53540
+ .adm-tl-batch-toggle.is-active {
53541
+ border-color: #7c3aed;
53542
+ background: rgba(124, 58, 237, 0.08);
53543
+ color: #7c3aed;
53544
+ }
53545
+ .adm-tl-batch-bar {
53546
+ display: none;
53547
+ align-items: center;
53548
+ gap: 8px;
53549
+ flex-wrap: wrap;
53550
+ padding: 6px 0 2px;
53551
+ border-top: 1px dashed #e5e7eb;
53552
+ }
53553
+ .adm-tl-sel-all-label {
53554
+ display: inline-flex;
53555
+ align-items: center;
53556
+ gap: 5px;
53557
+ font-size: 11px;
53558
+ color: #374151;
53559
+ cursor: pointer;
53560
+ }
53561
+ .adm-tl-sel-count {
53562
+ font-size: 11px;
53563
+ color: #7c3aed;
53564
+ font-weight: 600;
53565
+ min-width: 86px;
53566
+ }
53567
+ .adm-tl-action-sel {
53568
+ padding: 4px 8px;
53569
+ border: 1px solid #d1d5db;
53570
+ border-radius: 6px;
53571
+ font-size: 11px;
53572
+ color: #374151;
53573
+ background: #fff;
53574
+ cursor: pointer;
53575
+ }
53576
+ .adm-tl-exec-btn {
53577
+ padding: 4px 12px;
53578
+ background: #7c3aed;
53579
+ color: #fff;
53580
+ border: none;
53581
+ border-radius: 6px;
53582
+ font-size: 11px;
53583
+ font-weight: 600;
53584
+ cursor: pointer;
53585
+ transition: background 0.15s;
53586
+ }
53587
+ .adm-tl-exec-btn:disabled { background: #d1d5db; cursor: not-allowed; }
53588
+ .adm-tl-exec-btn:not(:disabled):hover { background: #6d28d9; }
53589
+ .adm-tl-cancel-btn {
53590
+ padding: 4px 10px;
53591
+ background: transparent;
53592
+ color: #6b7280;
53593
+ border: 1px solid #e5e7eb;
53594
+ border-radius: 6px;
53595
+ font-size: 11px;
53596
+ cursor: pointer;
53597
+ }
53598
+ .adm-tl-cancel-btn:hover { border-color: #9ca3af; color: #374151; }
53599
+
53600
+ /* ---- Row action cell ---- */
53601
+ .adm-tl-action-cell { white-space: nowrap; padding: 3px 6px !important; vertical-align: middle; text-align: right; }
53602
+ .adm-tl-actions-th { text-align: right; min-width: 76px; }
53603
+ .adm-tl-cb-wrap {
53604
+ display: none;
53605
+ align-items: center;
53606
+ cursor: pointer;
53607
+ margin-right: 2px;
53608
+ }
53609
+ .adm-tl-row-btns {
53610
+ display: inline-flex;
53611
+ gap: 3px;
53612
+ align-items: center;
53613
+ }
53614
+ .adm-tl-row-btns--group { margin-left: auto; }
53615
+ .adm-tl-row-btn {
53616
+ display: inline-flex;
53617
+ align-items: center;
53618
+ justify-content: center;
53619
+ width: 22px;
53620
+ height: 22px;
53621
+ border: none;
53622
+ border-radius: 4px;
53623
+ cursor: pointer;
53624
+ transition: background 0.12s, color 0.12s;
53625
+ flex-shrink: 0;
53626
+ }
53627
+ .adm-tl-row-btn--ack { background: rgba(22, 163, 74, 0.1); color: #16a34a; }
53628
+ .adm-tl-row-btn--ack:hover { background: #16a34a; color: #fff; }
53629
+ .adm-tl-row-btn--snooze { background: rgba(217, 119, 6, 0.1); color: #d97706; }
53630
+ .adm-tl-row-btn--snooze:hover { background: #d97706; color: #fff; }
53631
+ .adm-tl-row-btn--escalate { background: rgba(220, 38, 38, 0.1); color: #dc2626; }
53632
+ .adm-tl-row-btn--escalate:hover { background: #dc2626; color: #fff; }
53633
+
53634
+ /* ---- group-header flex adjustments ---- */
53635
+ .adm-timeline-group-header { gap: 6px; }
53636
+ .adm-tl-group-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
53637
+
53364
53638
  /* ---- Device list ---- */
53365
53639
  .adm-devices-list {
53366
53640
  border: 1px solid #e5e7eb;
@@ -54369,6 +54643,19 @@ var ALARMS_NOTIFICATIONS_PANEL_STYLES = `
54369
54643
  color: #a78bfa;
54370
54644
  }
54371
54645
 
54646
+ .adm-overlay[data-theme="dark"] .adm-tl-header { border-color: #334155; }
54647
+ .adm-overlay[data-theme="dark"] .adm-tl-toolbar {}
54648
+ .adm-overlay[data-theme="dark"] .adm-tl-summary { color: #94a3b8; }
54649
+ .adm-overlay[data-theme="dark"] .adm-tl-batch-toggle { border-color: #475569; background: #1e293b; color: #e2e8f0; }
54650
+ .adm-overlay[data-theme="dark"] .adm-tl-batch-toggle:hover,
54651
+ .adm-overlay[data-theme="dark"] .adm-tl-batch-toggle.is-active { border-color: #a78bfa; color: #a78bfa; }
54652
+ .adm-overlay[data-theme="dark"] .adm-tl-batch-bar { border-color: #334155; }
54653
+ .adm-overlay[data-theme="dark"] .adm-tl-sel-all-label { color: #e2e8f0; }
54654
+ .adm-overlay[data-theme="dark"] .adm-tl-sel-count { color: #a78bfa; }
54655
+ .adm-overlay[data-theme="dark"] .adm-tl-action-sel { background: #1e293b; border-color: #475569; color: #e2e8f0; }
54656
+ .adm-overlay[data-theme="dark"] .adm-tl-cancel-btn { border-color: #475569; color: #94a3b8; }
54657
+ .adm-overlay[data-theme="dark"] .adm-tl-cancel-btn:hover { color: #e2e8f0; }
54658
+
54372
54659
  .adm-overlay[data-theme="dark"] .adm-devices-list {
54373
54660
  border-color: #2a2b3d;
54374
54661
  }
@@ -55145,32 +55432,10 @@ var OPERATOR_LABELS = {
55145
55432
  GTE: "\u2265",
55146
55433
  EQ: "="
55147
55434
  };
55148
- var STATE_PRIORITY = {
55149
- OPEN: 0,
55150
- ESCALATED: 1,
55151
- SNOOZED: 2,
55152
- ACK: 3,
55153
- CLOSED: 4
55154
- };
55155
- var SEVERITY_PRIORITY = {
55156
- CRITICAL: 0,
55157
- HIGH: 1,
55158
- MEDIUM: 2,
55159
- LOW: 3,
55160
- INFO: 4
55161
- };
55162
- var STATE_LABELS = {
55163
- OPEN: "Aberto",
55164
- ACK: "Reconhecido",
55165
- ESCALATED: "Escalado",
55166
- SNOOZED: "Silenciado",
55167
- CLOSED: "Fechado"
55168
- };
55169
55435
  var AlarmsTab = class {
55170
55436
  config;
55171
55437
  customerRules = [];
55172
55438
  activeAlarms = [];
55173
- alarmGroups = [];
55174
55439
  initialCheckedRuleIds = /* @__PURE__ */ new Set();
55175
55440
  constructor(config) {
55176
55441
  this.config = config;
@@ -55196,7 +55461,6 @@ var AlarmsTab = class {
55196
55461
  ]);
55197
55462
  this.activeAlarms = alarms;
55198
55463
  this.customerRules = rules;
55199
- this.alarmGroups = this.groupAlarms(alarms);
55200
55464
  for (const rule of this.customerRules) {
55201
55465
  if (rule.scope?.entityIds?.includes(this.config.gcdrDeviceId)) {
55202
55466
  this.initialCheckedRuleIds.add(rule.id);
@@ -55213,74 +55477,26 @@ var AlarmsTab = class {
55213
55477
  destroy() {
55214
55478
  }
55215
55479
  // ============================================================================
55216
- // Grouping
55480
+ // Card mapping — separado (Disp. + Tipo) view: one card per individual alarm
55217
55481
  // ============================================================================
55218
55482
  /**
55219
- * Group raw alarms by metadata.ruleId (fallback: title).
55220
- * One card per group; occurrenceCount = total alarms in group.
55483
+ * Map a raw GCDRAlarm Alarm for createAlarmCardElement.
55484
+ * Each alarm is its own card (no grouping by ruleId).
55221
55485
  */
55222
- groupAlarms(alarms) {
55223
- const map = /* @__PURE__ */ new Map();
55224
- for (const alarm of alarms) {
55225
- const key = alarm.metadata?.ruleId || alarm.title || alarm.id;
55226
- if (!map.has(key)) {
55227
- map.set(key, {
55228
- ruleId: key,
55229
- title: alarm.title || "",
55230
- alarmType: alarm.alarmType,
55231
- severity: alarm.severity || "LOW",
55232
- dominantState: alarm.state || "OPEN",
55233
- stateCounts: {},
55234
- totalCount: 0,
55235
- firstOccurrence: alarm.raisedAt || "",
55236
- lastOccurrence: alarm.lastUpdatedAt || alarm.raisedAt || "",
55237
- alarmIds: []
55238
- });
55239
- }
55240
- const g = map.get(key);
55241
- g.totalCount++;
55242
- g.alarmIds.push(alarm.id);
55243
- g.stateCounts[alarm.state] = (g.stateCounts[alarm.state] || 0) + 1;
55244
- if ((STATE_PRIORITY[alarm.state] ?? 99) < (STATE_PRIORITY[g.dominantState] ?? 99)) {
55245
- g.dominantState = alarm.state;
55246
- }
55247
- if ((SEVERITY_PRIORITY[alarm.severity] ?? 99) < (SEVERITY_PRIORITY[g.severity] ?? 99)) {
55248
- g.severity = alarm.severity;
55249
- }
55250
- if (alarm.raisedAt && (!g.firstOccurrence || alarm.raisedAt < g.firstOccurrence)) {
55251
- g.firstOccurrence = alarm.raisedAt;
55252
- }
55253
- const lastTs = alarm.lastUpdatedAt || alarm.raisedAt || "";
55254
- if (lastTs && lastTs > g.lastOccurrence) {
55255
- g.lastOccurrence = lastTs;
55256
- }
55257
- }
55258
- return [...map.values()].sort((a, b) => {
55259
- const sd = (STATE_PRIORITY[a.dominantState] ?? 99) - (STATE_PRIORITY[b.dominantState] ?? 99);
55260
- if (sd !== 0) return sd;
55261
- return (SEVERITY_PRIORITY[a.severity] ?? 99) - (SEVERITY_PRIORITY[b.severity] ?? 99);
55262
- });
55263
- }
55264
- /**
55265
- * Map an aggregated GCDRAlarmGroup → Alarm so createAlarmCardElement can be used.
55266
- * State-count chips go into _alarmTypes → rendered as type chips in the card body.
55267
- */
55268
- mapGroupToAlarm(group) {
55269
- const stateChips = Object.entries(group.stateCounts).sort((a, b) => (STATE_PRIORITY[a[0]] ?? 99) - (STATE_PRIORITY[b[0]] ?? 99)).map(([state6, count]) => `${STATE_LABELS[state6] || state6} \xD7 ${count}`);
55486
+ mapAlarmToCard(alarm) {
55270
55487
  return {
55271
- id: group.ruleId,
55488
+ id: alarm.id,
55272
55489
  customerId: this.config.gcdrCustomerId,
55273
55490
  customerName: "",
55274
- source: "",
55275
- severity: group.severity,
55276
- state: group.dominantState,
55277
- title: group.title,
55278
- description: "",
55491
+ source: alarm.deviceName || "",
55492
+ severity: alarm.severity || "LOW",
55493
+ state: alarm.state || "OPEN",
55494
+ title: alarm.title || "",
55495
+ description: alarm.description || "",
55279
55496
  tags: {},
55280
- firstOccurrence: group.firstOccurrence,
55281
- lastOccurrence: group.lastOccurrence,
55282
- occurrenceCount: group.totalCount,
55283
- _alarmTypes: stateChips
55497
+ firstOccurrence: alarm.raisedAt || "",
55498
+ lastOccurrence: alarm.lastUpdatedAt || alarm.raisedAt || "",
55499
+ occurrenceCount: 1
55284
55500
  };
55285
55501
  }
55286
55502
  // ============================================================================
@@ -55362,44 +55578,65 @@ var AlarmsTab = class {
55362
55578
  const alarmsBaseUrl = this.config.alarmsApiBaseUrl || ALARMS_DEFAULT_BASE_URL;
55363
55579
  const AlarmService2 = window.MyIOLibrary?.AlarmService;
55364
55580
  const userEmail = window.MyIOUtils?.currentUserEmail || "";
55365
- for (const group of this.alarmGroups) {
55366
- const alarm = this.mapGroupToAlarm(group);
55581
+ for (const rawAlarm of this.activeAlarms) {
55582
+ const alarm = this.mapAlarmToCard(rawAlarm);
55583
+ const onAction = (action, alarmId) => {
55584
+ const doAction = async () => {
55585
+ if (action === "acknowledge") {
55586
+ if (AlarmService2?.batchAcknowledge) {
55587
+ await AlarmService2.batchAcknowledge([alarmId], userEmail);
55588
+ } else {
55589
+ await this.postAlarmAction(alarmsBaseUrl, alarmId, "acknowledge");
55590
+ }
55591
+ } else if (action === "snooze") {
55592
+ if (AlarmService2?.batchSilence) {
55593
+ await AlarmService2.batchSilence([alarmId], userEmail, "4h");
55594
+ } else {
55595
+ await this.postAlarmAction(alarmsBaseUrl, alarmId, "snooze");
55596
+ }
55597
+ } else if (action === "escalate") {
55598
+ if (AlarmService2?.batchEscalate) {
55599
+ await AlarmService2.batchEscalate([alarmId], userEmail);
55600
+ } else {
55601
+ await this.postAlarmAction(alarmsBaseUrl, alarmId, "escalate");
55602
+ }
55603
+ }
55604
+ await this.refreshAlarmsGrid(alarmsBaseUrl);
55605
+ };
55606
+ doAction().catch(() => {
55607
+ });
55608
+ };
55367
55609
  const params = {
55368
55610
  showCustomerName: false,
55369
55611
  showDeviceBadge: false,
55370
- alarmTypes: alarm._alarmTypes,
55612
+ hideOccurrenceCount: true,
55613
+ // always 1 in separado — not meaningful
55371
55614
  onAcknowledge: async () => {
55372
55615
  if (AlarmService2?.batchAcknowledge) {
55373
- await AlarmService2.batchAcknowledge(group.alarmIds, userEmail);
55616
+ await AlarmService2.batchAcknowledge([rawAlarm.id], userEmail);
55374
55617
  } else {
55375
- await Promise.all(
55376
- group.alarmIds.map((id) => this.postAlarmAction(alarmsBaseUrl, id, "acknowledge"))
55377
- );
55618
+ await this.postAlarmAction(alarmsBaseUrl, rawAlarm.id, "acknowledge");
55378
55619
  }
55379
55620
  await this.refreshAlarmsGrid(alarmsBaseUrl);
55380
55621
  },
55381
55622
  onSnooze: async () => {
55382
55623
  if (AlarmService2?.batchSilence) {
55383
- await AlarmService2.batchSilence(group.alarmIds, userEmail, "4h");
55624
+ await AlarmService2.batchSilence([rawAlarm.id], userEmail, "4h");
55384
55625
  } else {
55385
- await Promise.all(
55386
- group.alarmIds.map((id) => this.postAlarmAction(alarmsBaseUrl, id, "snooze"))
55387
- );
55626
+ await this.postAlarmAction(alarmsBaseUrl, rawAlarm.id, "snooze");
55388
55627
  }
55389
55628
  await this.refreshAlarmsGrid(alarmsBaseUrl);
55390
55629
  },
55391
55630
  onEscalate: async () => {
55392
55631
  if (AlarmService2?.batchEscalate) {
55393
- await AlarmService2.batchEscalate(group.alarmIds, userEmail);
55632
+ await AlarmService2.batchEscalate([rawAlarm.id], userEmail);
55394
55633
  } else {
55395
- await Promise.all(
55396
- group.alarmIds.map((id) => this.postAlarmAction(alarmsBaseUrl, id, "escalate"))
55397
- );
55634
+ await this.postAlarmAction(alarmsBaseUrl, rawAlarm.id, "escalate");
55398
55635
  }
55399
55636
  await this.refreshAlarmsGrid(alarmsBaseUrl);
55400
55637
  },
55401
55638
  onDetails: () => {
55402
- openAlarmDetailsModal(alarm);
55639
+ openAlarmDetailsModal(alarm, "light", "separado", onAction);
55403
55640
  }
55404
55641
  };
55405
55642
  const el = createAlarmCardElement(alarm, params);
@@ -55408,16 +55645,16 @@ var AlarmsTab = class {
55408
55645
  }
55409
55646
  async refreshAlarmsGrid(alarmsBaseUrl) {
55410
55647
  this.activeAlarms = await this.fetchActiveAlarms(alarmsBaseUrl);
55411
- this.alarmGroups = this.groupAlarms(this.activeAlarms);
55412
55648
  const aso = window.AlarmServiceOrchestrator;
55413
55649
  if (aso) {
55414
55650
  await aso.refresh().catch(() => {
55415
55651
  });
55416
55652
  }
55653
+ const count = this.activeAlarms.length;
55417
55654
  const badge = this.config.container.querySelector("#at-alarms-count");
55418
55655
  if (badge) {
55419
- badge.textContent = String(this.alarmGroups.length);
55420
- badge.style.display = this.alarmGroups.length > 0 ? "" : "none";
55656
+ badge.textContent = String(count);
55657
+ badge.style.display = count > 0 ? "" : "none";
55421
55658
  }
55422
55659
  const sub = this.config.container.querySelector("#at-alarms-sub");
55423
55660
  if (sub) {
@@ -55425,7 +55662,7 @@ var AlarmsTab = class {
55425
55662
  }
55426
55663
  const grid = this.config.container.querySelector("#at-alarms-grid");
55427
55664
  const empty = this.config.container.querySelector("#at-alarms-empty");
55428
- if (this.alarmGroups.length === 0) {
55665
+ if (count === 0) {
55429
55666
  if (grid) grid.style.display = "none";
55430
55667
  if (empty) empty.style.display = "";
55431
55668
  } else {
@@ -55439,9 +55676,8 @@ var AlarmsTab = class {
55439
55676
  // ============================================================================
55440
55677
  buildSectionSubtitle() {
55441
55678
  const total = this.activeAlarms.length;
55442
- const groups = this.alarmGroups.length;
55443
55679
  if (total === 0) return "Nenhum alarme ativo para este dispositivo";
55444
- return `${total} ocorr\xEAncia${total !== 1 ? "s" : ""} em ${groups} tipo${groups !== 1 ? "s" : ""}`;
55680
+ return `${total} alarme${total !== 1 ? "s" : ""} ativo${total !== 1 ? "s" : ""} para este dispositivo`;
55445
55681
  }
55446
55682
  renderTab() {
55447
55683
  return `
@@ -55452,7 +55688,7 @@ var AlarmsTab = class {
55452
55688
  `;
55453
55689
  }
55454
55690
  renderSection1() {
55455
- const groups = this.alarmGroups.length;
55691
+ const count = this.activeAlarms.length;
55456
55692
  return `
55457
55693
  <div class="at-section">
55458
55694
  <div class="at-section-header">
@@ -55462,16 +55698,16 @@ var AlarmsTab = class {
55462
55698
  <div class="at-section-sub" id="at-alarms-sub">${this.buildSectionSubtitle()}</div>
55463
55699
  </div>
55464
55700
  <span class="at-count-badge" id="at-alarms-count"
55465
- style="${groups === 0 ? "display:none;" : ""}">${groups}</span>
55701
+ style="${count === 0 ? "display:none;" : ""}">${count}</span>
55466
55702
  </div>
55467
55703
  <!-- .myio-alarms-panel wrapper so panel CSS variables / alarm-card styles apply -->
55468
55704
  <div class="myio-alarms-panel at-alarms-panel-host">
55469
55705
  <div class="at-empty" id="at-alarms-empty"
55470
- style="${groups > 0 ? "display:none;" : ""}">
55706
+ style="${count > 0 ? "display:none;" : ""}">
55471
55707
  Nenhum alarme ativo para este dispositivo.
55472
55708
  </div>
55473
55709
  <div class="alarms-grid" id="at-alarms-grid"
55474
- style="${groups === 0 ? "display:none;" : ""}"></div>
55710
+ style="${count === 0 ? "display:none;" : ""}"></div>
55475
55711
  </div>
55476
55712
  </div>
55477
55713
  `;
@@ -105681,7 +105917,7 @@ var AlarmsNotificationsPanelView = class {
105681
105917
  // 'consolidado' – Por Tipo de Alarme (one row per alarm type, all devices merged)
105682
105918
  // 'separado' – Por Dispositivo - Tipo (one row per device × alarm type pair)
105683
105919
  // 'porDispositivo' – Por Dispositivo (one row per device, all alarm types merged)
105684
- groupMode = "consolidado";
105920
+ groupMode = "separado";
105685
105921
  // Table sort state
105686
105922
  sortCol = "";
105687
105923
  sortDir = "asc";
@@ -106039,7 +106275,8 @@ var AlarmsNotificationsPanelView = class {
106039
106275
  grid.className = "alarms-grid";
106040
106276
  cards.forEach((alarm) => {
106041
106277
  const card = createAlarmCardElement(alarm, {
106042
- onCardClick: (a) => this.handleAlarmClick(a),
106278
+ // Card click: in grouped modes opens modal directly; in separado fires generic click
106279
+ onCardClick: isSeparado ? (a) => this.handleAlarmClick(a) : (a) => this.handleDetails(a.id),
106043
106280
  onAcknowledge: (id) => this.openAlarmActionModal("acknowledge", id),
106044
106281
  onDetails: (id) => this.handleDetails(id),
106045
106282
  onMore: (id, e) => this.handleMore(id, e),
@@ -106048,7 +106285,15 @@ var AlarmsNotificationsPanelView = class {
106048
106285
  selected: this.selectedTitles.has(alarm.title),
106049
106286
  showDeviceBadge: isSeparado,
106050
106287
  // separado: show device badge in header
106051
- alarmTypes: isPorDispositivo ? alarm._alarmTypes ?? [] : void 0
106288
+ alarmTypes: isPorDispositivo ? alarm._alarmTypes ?? [] : void 0,
106289
+ hideActions: !isSeparado,
106290
+ // ACK/Snooze/Escalate only in separado (unit alarm)
106291
+ hideSelect: !isSeparado,
106292
+ // bulk-select only meaningful in separado
106293
+ hideDetails: !isSeparado,
106294
+ // card click opens modal in grouped modes
106295
+ hideOccurrenceCount: isSeparado
106296
+ // Qte. always 1 in separado — not useful
106052
106297
  });
106053
106298
  grid.appendChild(card);
106054
106299
  });
@@ -106839,7 +107084,12 @@ var AlarmsNotificationsPanelView = class {
106839
107084
  this.log("Details", alarmId);
106840
107085
  const alarm = this.groupedAlarms.find((a) => a.id === alarmId) ?? this.controller.getAlarms().find((a) => a.id === this.stripSeparadoId(alarmId));
106841
107086
  if (alarm) {
106842
- openAlarmDetailsModal(alarm, this.controller.getState().themeMode, this.groupMode);
107087
+ openAlarmDetailsModal(
107088
+ alarm,
107089
+ this.controller.getState().themeMode,
107090
+ this.groupMode,
107091
+ (action, id) => this.openAlarmActionModal(action, id)
107092
+ );
106843
107093
  this.emit("alarm-click", alarm);
106844
107094
  }
106845
107095
  }