myio-js-library 0.1.500 → 0.1.502
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 +724 -173
- package/dist/index.d.cts +1 -0
- package/dist/index.js +724 -173
- package/dist/myio-js-library.umd.js +728 -136
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1162,7 +1162,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
1162
1162
|
// package.json
|
|
1163
1163
|
var package_default = {
|
|
1164
1164
|
name: "myio-js-library",
|
|
1165
|
-
version: "0.1.
|
|
1165
|
+
version: "0.1.502",
|
|
1166
1166
|
description: "A clean, standalone JS SDK for MYIO projects",
|
|
1167
1167
|
license: "MIT",
|
|
1168
1168
|
repository: "github:gh-myio/myio-js-library",
|
|
@@ -15633,6 +15633,57 @@ function renderCardComponentV5({
|
|
|
15633
15633
|
`;
|
|
15634
15634
|
document.head.appendChild(layoutStyle);
|
|
15635
15635
|
}
|
|
15636
|
+
if (!document.getElementById("myio-card-alert-styles")) {
|
|
15637
|
+
const alertStyle = document.createElement("style");
|
|
15638
|
+
alertStyle.id = "myio-card-alert-styles";
|
|
15639
|
+
alertStyle.textContent = `
|
|
15640
|
+
.myio-alert-overlay {
|
|
15641
|
+
position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 100000;
|
|
15642
|
+
display: flex; align-items: center; justify-content: center;
|
|
15643
|
+
background: rgba(0,0,0,0.5); backdrop-filter: blur(4px);
|
|
15644
|
+
-webkit-backdrop-filter: blur(4px);
|
|
15645
|
+
animation: myio-fadeIn 0.2s ease-out;
|
|
15646
|
+
}
|
|
15647
|
+
@keyframes myio-fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
15648
|
+
.myio-alert-box {
|
|
15649
|
+
position: relative; max-width: 480px; width: 90%; padding: 32px;
|
|
15650
|
+
background: #ffffff; border: 1px solid rgba(0,0,0,0.1); border-radius: 20px;
|
|
15651
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
15652
|
+
animation: myio-slideUp 0.3s cubic-bezier(0.4,0,0.2,1);
|
|
15653
|
+
}
|
|
15654
|
+
@keyframes myio-slideUp {
|
|
15655
|
+
from { opacity: 0; transform: translateY(40px) scale(0.95); }
|
|
15656
|
+
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
15657
|
+
}
|
|
15658
|
+
.myio-alert-icon {
|
|
15659
|
+
width: 64px; height: 64px; margin: 0 auto 20px;
|
|
15660
|
+
display: flex; align-items: center; justify-content: center;
|
|
15661
|
+
background: linear-gradient(135deg, #3E1A7D 0%, #2D1359 100%);
|
|
15662
|
+
border: 2px solid #3E1A7D; border-radius: 50%; color: #ffffff; font-size: 32px;
|
|
15663
|
+
}
|
|
15664
|
+
.myio-alert-title {
|
|
15665
|
+
margin: 0 0 12px; font-size: 24px; font-weight: 700; color: #000000;
|
|
15666
|
+
text-align: center; letter-spacing: -0.02em;
|
|
15667
|
+
}
|
|
15668
|
+
.myio-alert-message {
|
|
15669
|
+
margin: 0 0 28px; font-size: 16px; font-weight: 500; color: #000000;
|
|
15670
|
+
text-align: center; line-height: 1.6;
|
|
15671
|
+
}
|
|
15672
|
+
.myio-alert-button {
|
|
15673
|
+
width: 100%; height: 48px; font-size: 15px; font-weight: 700;
|
|
15674
|
+
text-transform: uppercase;
|
|
15675
|
+
background: linear-gradient(135deg, #3E1A7D 0%, #2D1359 100%);
|
|
15676
|
+
border: none; border-radius: 12px; color: #ffffff; cursor: pointer;
|
|
15677
|
+
box-shadow: 0 4px 16px rgba(62,26,125,0.4);
|
|
15678
|
+
transition: all 0.2s cubic-bezier(0.4,0,0.2,1);
|
|
15679
|
+
}
|
|
15680
|
+
.myio-alert-button:hover {
|
|
15681
|
+
background: linear-gradient(135deg, #4E2A9D 0%, #3E1A7D 100%);
|
|
15682
|
+
box-shadow: 0 6px 24px rgba(62,26,125,0.5); transform: translateY(-2px);
|
|
15683
|
+
}
|
|
15684
|
+
`;
|
|
15685
|
+
document.head.appendChild(alertStyle);
|
|
15686
|
+
}
|
|
15636
15687
|
const actionsContainer = document.createElement("div");
|
|
15637
15688
|
actionsContainer.className = "card-actions";
|
|
15638
15689
|
if (typeof handleActionDashboard === "function") {
|
|
@@ -15681,6 +15732,44 @@ function renderCardComponentV5({
|
|
|
15681
15732
|
if (enhancedCardElement && actionsContainer.children.length > 0) {
|
|
15682
15733
|
enhancedCardElement.insertBefore(actionsContainer, enhancedCardElement.firstChild);
|
|
15683
15734
|
}
|
|
15735
|
+
let _cardAlertOverlay = null;
|
|
15736
|
+
function hideCardAlert() {
|
|
15737
|
+
if (_cardAlertOverlay && _cardAlertOverlay.parentNode) {
|
|
15738
|
+
_cardAlertOverlay.remove();
|
|
15739
|
+
_cardAlertOverlay = null;
|
|
15740
|
+
}
|
|
15741
|
+
}
|
|
15742
|
+
function showCardLimitAlert() {
|
|
15743
|
+
if (_cardAlertOverlay) hideCardAlert();
|
|
15744
|
+
const maxAllowed = MyIOSelectionStore?.MAX_SELECTION ?? 20;
|
|
15745
|
+
const overlay = document.createElement("div");
|
|
15746
|
+
overlay.className = "myio-alert-overlay";
|
|
15747
|
+
overlay.innerHTML = `
|
|
15748
|
+
<div class="myio-alert-box">
|
|
15749
|
+
<div class="myio-alert-icon">\u26A0</div>
|
|
15750
|
+
<h2 class="myio-alert-title">Limite Atingido</h2>
|
|
15751
|
+
<p class="myio-alert-message">
|
|
15752
|
+
Voc\xEA pode selecionar no m\xE1ximo <strong>${maxAllowed} dispositivos</strong> para compara\xE7\xE3o.
|
|
15753
|
+
Remova um dispositivo antes de adicionar outro.
|
|
15754
|
+
</p>
|
|
15755
|
+
<button class="myio-alert-button">FECHAR</button>
|
|
15756
|
+
</div>`;
|
|
15757
|
+
document.body.appendChild(overlay);
|
|
15758
|
+
_cardAlertOverlay = overlay;
|
|
15759
|
+
const closeBtn = overlay.querySelector(".myio-alert-button");
|
|
15760
|
+
const close = () => {
|
|
15761
|
+
document.removeEventListener("keydown", handleEscape);
|
|
15762
|
+
hideCardAlert();
|
|
15763
|
+
};
|
|
15764
|
+
const handleEscape = (e) => {
|
|
15765
|
+
if (e.key === "Escape") close();
|
|
15766
|
+
};
|
|
15767
|
+
closeBtn.addEventListener("click", close);
|
|
15768
|
+
overlay.addEventListener("click", (e) => {
|
|
15769
|
+
if (e.target === overlay) close();
|
|
15770
|
+
});
|
|
15771
|
+
document.addEventListener("keydown", handleEscape);
|
|
15772
|
+
}
|
|
15684
15773
|
if (enableSelection && MyIOSelectionStore) {
|
|
15685
15774
|
const checkbox = enhancedCardElement.querySelector(".card-checkbox");
|
|
15686
15775
|
if (checkbox) {
|
|
@@ -15691,10 +15780,10 @@ function renderCardComponentV5({
|
|
|
15691
15780
|
const selectedEntities = MyIOSelectionStore.getSelectedEntities();
|
|
15692
15781
|
console.log("selectedEntities", selectedEntities);
|
|
15693
15782
|
const isTryingToAdd = e.target.checked;
|
|
15694
|
-
if (isTryingToAdd && currentCount >=
|
|
15783
|
+
if (isTryingToAdd && currentCount >= (MyIOSelectionStore.MAX_SELECTION ?? 20)) {
|
|
15695
15784
|
e.preventDefault();
|
|
15696
15785
|
e.target.checked = false;
|
|
15697
|
-
|
|
15786
|
+
showCardLimitAlert();
|
|
15698
15787
|
return;
|
|
15699
15788
|
}
|
|
15700
15789
|
MyIOSelectionStore.add(entityId);
|
|
@@ -17936,6 +18025,95 @@ function renderCardComponentV6({
|
|
|
17936
18025
|
if (enhancedCardElement && actionsContainer.children.length > 0) {
|
|
17937
18026
|
enhancedCardElement.insertBefore(actionsContainer, enhancedCardElement.firstChild);
|
|
17938
18027
|
}
|
|
18028
|
+
let _cardAlertOverlay = null;
|
|
18029
|
+
function hideCardAlert() {
|
|
18030
|
+
if (_cardAlertOverlay && _cardAlertOverlay.parentNode) {
|
|
18031
|
+
_cardAlertOverlay.remove();
|
|
18032
|
+
_cardAlertOverlay = null;
|
|
18033
|
+
}
|
|
18034
|
+
}
|
|
18035
|
+
function showCardLimitAlert() {
|
|
18036
|
+
if (_cardAlertOverlay) hideCardAlert();
|
|
18037
|
+
if (!document.getElementById("myio-card-alert-styles")) {
|
|
18038
|
+
const alertStyle = document.createElement("style");
|
|
18039
|
+
alertStyle.id = "myio-card-alert-styles";
|
|
18040
|
+
alertStyle.textContent = `
|
|
18041
|
+
.myio-alert-overlay {
|
|
18042
|
+
position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 100000;
|
|
18043
|
+
display: flex; align-items: center; justify-content: center;
|
|
18044
|
+
background: rgba(0,0,0,0.5); backdrop-filter: blur(4px);
|
|
18045
|
+
-webkit-backdrop-filter: blur(4px);
|
|
18046
|
+
animation: myio-fadeIn 0.2s ease-out;
|
|
18047
|
+
}
|
|
18048
|
+
@keyframes myio-fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
18049
|
+
.myio-alert-box {
|
|
18050
|
+
position: relative; max-width: 480px; width: 90%; padding: 32px;
|
|
18051
|
+
background: #ffffff; border: 1px solid rgba(0,0,0,0.1); border-radius: 20px;
|
|
18052
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
18053
|
+
animation: myio-slideUp 0.3s cubic-bezier(0.4,0,0.2,1);
|
|
18054
|
+
}
|
|
18055
|
+
@keyframes myio-slideUp {
|
|
18056
|
+
from { opacity: 0; transform: translateY(40px) scale(0.95); }
|
|
18057
|
+
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
18058
|
+
}
|
|
18059
|
+
.myio-alert-icon {
|
|
18060
|
+
width: 64px; height: 64px; margin: 0 auto 20px;
|
|
18061
|
+
display: flex; align-items: center; justify-content: center;
|
|
18062
|
+
background: linear-gradient(135deg, #3E1A7D 0%, #2D1359 100%);
|
|
18063
|
+
border: 2px solid #3E1A7D; border-radius: 50%; color: #ffffff; font-size: 32px;
|
|
18064
|
+
}
|
|
18065
|
+
.myio-alert-title {
|
|
18066
|
+
margin: 0 0 12px; font-size: 24px; font-weight: 700; color: #000000;
|
|
18067
|
+
text-align: center; letter-spacing: -0.02em;
|
|
18068
|
+
}
|
|
18069
|
+
.myio-alert-message {
|
|
18070
|
+
margin: 0 0 28px; font-size: 16px; font-weight: 500; color: #000000;
|
|
18071
|
+
text-align: center; line-height: 1.6;
|
|
18072
|
+
}
|
|
18073
|
+
.myio-alert-button {
|
|
18074
|
+
width: 100%; height: 48px; font-size: 15px; font-weight: 700;
|
|
18075
|
+
text-transform: uppercase;
|
|
18076
|
+
background: linear-gradient(135deg, #3E1A7D 0%, #2D1359 100%);
|
|
18077
|
+
border: none; border-radius: 12px; color: #ffffff; cursor: pointer;
|
|
18078
|
+
box-shadow: 0 4px 16px rgba(62,26,125,0.4);
|
|
18079
|
+
transition: all 0.2s cubic-bezier(0.4,0,0.2,1);
|
|
18080
|
+
}
|
|
18081
|
+
.myio-alert-button:hover {
|
|
18082
|
+
background: linear-gradient(135deg, #4E2A9D 0%, #3E1A7D 100%);
|
|
18083
|
+
box-shadow: 0 6px 24px rgba(62,26,125,0.5); transform: translateY(-2px);
|
|
18084
|
+
}
|
|
18085
|
+
`;
|
|
18086
|
+
document.head.appendChild(alertStyle);
|
|
18087
|
+
}
|
|
18088
|
+
const maxAllowed = MyIOSelectionStore?.MAX_SELECTION ?? 20;
|
|
18089
|
+
const overlay = document.createElement("div");
|
|
18090
|
+
overlay.className = "myio-alert-overlay";
|
|
18091
|
+
overlay.innerHTML = `
|
|
18092
|
+
<div class="myio-alert-box">
|
|
18093
|
+
<div class="myio-alert-icon">\u26A0</div>
|
|
18094
|
+
<h2 class="myio-alert-title">Limite Atingido</h2>
|
|
18095
|
+
<p class="myio-alert-message">
|
|
18096
|
+
Voc\xEA pode selecionar no m\xE1ximo <strong>${maxAllowed} dispositivos</strong> para compara\xE7\xE3o.
|
|
18097
|
+
Remova um dispositivo antes de adicionar outro.
|
|
18098
|
+
</p>
|
|
18099
|
+
<button class="myio-alert-button">FECHAR</button>
|
|
18100
|
+
</div>`;
|
|
18101
|
+
document.body.appendChild(overlay);
|
|
18102
|
+
_cardAlertOverlay = overlay;
|
|
18103
|
+
const closeBtn = overlay.querySelector(".myio-alert-button");
|
|
18104
|
+
const close = () => {
|
|
18105
|
+
document.removeEventListener("keydown", handleEscape);
|
|
18106
|
+
hideCardAlert();
|
|
18107
|
+
};
|
|
18108
|
+
const handleEscape = (e) => {
|
|
18109
|
+
if (e.key === "Escape") close();
|
|
18110
|
+
};
|
|
18111
|
+
closeBtn.addEventListener("click", close);
|
|
18112
|
+
overlay.addEventListener("click", (e) => {
|
|
18113
|
+
if (e.target === overlay) close();
|
|
18114
|
+
});
|
|
18115
|
+
document.addEventListener("keydown", handleEscape);
|
|
18116
|
+
}
|
|
17939
18117
|
if (enableSelection && MyIOSelectionStore) {
|
|
17940
18118
|
const checkbox = enhancedCardElement.querySelector(".card-checkbox");
|
|
17941
18119
|
if (checkbox) {
|
|
@@ -17943,10 +18121,10 @@ function renderCardComponentV6({
|
|
|
17943
18121
|
e.stopPropagation();
|
|
17944
18122
|
if (e.target.checked) {
|
|
17945
18123
|
const currentCount = MyIOSelectionStore.getSelectedEntities().length;
|
|
17946
|
-
if (currentCount >=
|
|
18124
|
+
if (currentCount >= (MyIOSelectionStore.MAX_SELECTION ?? 20)) {
|
|
17947
18125
|
e.preventDefault();
|
|
17948
18126
|
e.target.checked = false;
|
|
17949
|
-
|
|
18127
|
+
showCardLimitAlert();
|
|
17950
18128
|
return;
|
|
17951
18129
|
}
|
|
17952
18130
|
MyIOSelectionStore.add(entityId);
|
|
@@ -32814,6 +32992,13 @@ var AllReportModal = class {
|
|
|
32814
32992
|
domainConfig;
|
|
32815
32993
|
// Granularity: '1d' (daily) | '1h' (hourly)
|
|
32816
32994
|
granularity = "1d";
|
|
32995
|
+
// When true, devices flagged via `exclude_groups_totals` for this group are dropped
|
|
32996
|
+
// from the report so its total reconciles with the dashboard KPIs. Toggleable in the UI.
|
|
32997
|
+
considerExclusion = true;
|
|
32998
|
+
// Raw API response kept so the exclusion toggle can re-map without a new fetch.
|
|
32999
|
+
lastApiResponse = null;
|
|
33000
|
+
// Cleanup for the InfoTooltip attached to the exclusion-flag info icon.
|
|
33001
|
+
exclusionTooltipCleanup = null;
|
|
32817
33002
|
// Debug logging helper
|
|
32818
33003
|
debugLog(message, data) {
|
|
32819
33004
|
if (this.debugEnabled) {
|
|
@@ -32822,7 +33007,7 @@ var AllReportModal = class {
|
|
|
32822
33007
|
}
|
|
32823
33008
|
// Helper: normalize identifiers (upper, strip spaces and non-alphanum)
|
|
32824
33009
|
normalizeId(v) {
|
|
32825
|
-
return (v || "").toString().normalize("NFKC").toUpperCase().replace(/\s+/g, "").replace(/[
|
|
33010
|
+
return (v || "").toString().normalize("NFKC").toUpperCase().replace(/\s+/g, "").replace(/[0300-036f]/g, "");
|
|
32826
33011
|
}
|
|
32827
33012
|
// Helper: extract store identifier from API item
|
|
32828
33013
|
// Priority: assetName -> parse from name (last token or token after space) -> null
|
|
@@ -32891,6 +33076,10 @@ var AllReportModal = class {
|
|
|
32891
33076
|
this.dateRangePicker.destroy();
|
|
32892
33077
|
this.dateRangePicker = null;
|
|
32893
33078
|
}
|
|
33079
|
+
if (this.exclusionTooltipCleanup) {
|
|
33080
|
+
this.exclusionTooltipCleanup();
|
|
33081
|
+
this.exclusionTooltipCleanup = null;
|
|
33082
|
+
}
|
|
32894
33083
|
if (this.filterModal) {
|
|
32895
33084
|
this.filterModal.destroy();
|
|
32896
33085
|
this.filterModal = null;
|
|
@@ -32929,6 +33118,20 @@ var AllReportModal = class {
|
|
|
32929
33118
|
<button id="filter-btn" class="myio-btn myio-btn-secondary" style="background: var(--myio-brand-700); color: white;">
|
|
32930
33119
|
\u{1F50D} Filtros & Ordena\xE7\xE3o
|
|
32931
33120
|
</button>
|
|
33121
|
+
<div class="myio-form-group" style="margin-bottom: 0; display: flex; align-items: center; gap: 6px; align-self: flex-end; padding-bottom: 8px;">
|
|
33122
|
+
<label for="consider-exclusion" style="display: flex; align-items: center; gap: 6px; cursor: pointer; font-size: 13px; color: var(--myio-text, #374151); white-space: nowrap;">
|
|
33123
|
+
<input type="checkbox" id="consider-exclusion" checked style="cursor: pointer; width: 15px; height: 15px; accent-color: var(--myio-brand-700, #5b2c9d);">
|
|
33124
|
+
Considerar exclus\xE3o de totais
|
|
33125
|
+
</label>
|
|
33126
|
+
<span id="exclusion-info" aria-label="Sobre a exclus\xE3o de totais" style="
|
|
33127
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
33128
|
+
width: 16px; height: 16px; border-radius: 50%;
|
|
33129
|
+
background: var(--myio-brand-700, #5b2c9d); color: #fff;
|
|
33130
|
+
font-size: 11px; font-weight: 700; font-style: italic;
|
|
33131
|
+
font-family: Georgia, 'Times New Roman', serif; cursor: help;
|
|
33132
|
+
user-select: none;
|
|
33133
|
+
">i</span>
|
|
33134
|
+
</div>
|
|
32932
33135
|
<div class="myio-form-group" style="margin-bottom: 0; margin-left: auto;">
|
|
32933
33136
|
<label class="myio-label" for="search-input">Busca r\xE1pida</label>
|
|
32934
33137
|
<input type="text" id="search-input" class="myio-input" placeholder="Digite para filtrar..." style="width: 200px;">
|
|
@@ -32987,6 +33190,20 @@ var AllReportModal = class {
|
|
|
32987
33190
|
this.renderTable();
|
|
32988
33191
|
});
|
|
32989
33192
|
}
|
|
33193
|
+
const exclusionCheckbox = document.getElementById("consider-exclusion");
|
|
33194
|
+
exclusionCheckbox?.addEventListener("change", () => {
|
|
33195
|
+
this.considerExclusion = exclusionCheckbox.checked;
|
|
33196
|
+
this.remapAndRender();
|
|
33197
|
+
});
|
|
33198
|
+
const exclusionInfo = document.getElementById("exclusion-info");
|
|
33199
|
+
if (exclusionInfo) {
|
|
33200
|
+
this.exclusionTooltipCleanup?.();
|
|
33201
|
+
this.exclusionTooltipCleanup = InfoTooltip.attach(exclusionInfo, () => ({
|
|
33202
|
+
icon: "\u2139\uFE0F",
|
|
33203
|
+
title: "Exclus\xE3o de totais",
|
|
33204
|
+
content: this.buildExclusionTooltipContent()
|
|
33205
|
+
}));
|
|
33206
|
+
}
|
|
32990
33207
|
try {
|
|
32991
33208
|
this.dateRangePicker = await attach(dateRangeInput, {
|
|
32992
33209
|
presetStart: this.getDefaultStartDate(),
|
|
@@ -33029,6 +33246,7 @@ var AllReportModal = class {
|
|
|
33029
33246
|
const customerTotalsData = await this.fetchCustomerTotals(startISO, endISO);
|
|
33030
33247
|
this.debugLog("\u2705 API response received", customerTotalsData);
|
|
33031
33248
|
this.debugLog("\u{1F504} Processing API response...");
|
|
33249
|
+
this.lastApiResponse = customerTotalsData;
|
|
33032
33250
|
this.data = this.mapCustomerTotalsResponse(customerTotalsData);
|
|
33033
33251
|
this.debugLog("\u2705 Data mapping completed", {
|
|
33034
33252
|
mappedDataLength: this.data.length,
|
|
@@ -33248,48 +33466,6 @@ var AllReportModal = class {
|
|
|
33248
33466
|
});
|
|
33249
33467
|
}
|
|
33250
33468
|
renderPagination() {
|
|
33251
|
-
return;
|
|
33252
|
-
const container = document.getElementById("pagination-container");
|
|
33253
|
-
if (!container) return;
|
|
33254
|
-
const filteredData = this.getFilteredData();
|
|
33255
|
-
const totalPages = Math.ceil(filteredData.length / this.itemsPerPage);
|
|
33256
|
-
if (totalPages <= 1) {
|
|
33257
|
-
container.style.display = "none";
|
|
33258
|
-
return;
|
|
33259
|
-
}
|
|
33260
|
-
const startItem = (this.currentPage - 1) * this.itemsPerPage + 1;
|
|
33261
|
-
const endItem = Math.min(this.currentPage * this.itemsPerPage, filteredData.length);
|
|
33262
|
-
container.innerHTML = `
|
|
33263
|
-
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px;">
|
|
33264
|
-
<div style="color: var(--myio-text-muted);">
|
|
33265
|
-
Mostrando ${startItem}-${endItem} de ${filteredData.length} lojas
|
|
33266
|
-
</div>
|
|
33267
|
-
<div style="display: flex; gap: 8px; align-items: center;">
|
|
33268
|
-
<button id="prev-page" class="myio-btn myio-btn-outline" ${this.currentPage === 1 ? "disabled" : ""}>
|
|
33269
|
-
Anterior
|
|
33270
|
-
</button>
|
|
33271
|
-
<span style="padding: 0 12px; font-weight: bold;">
|
|
33272
|
-
${this.currentPage} / ${totalPages}
|
|
33273
|
-
</span>
|
|
33274
|
-
<button id="next-page" class="myio-btn myio-btn-outline" ${this.currentPage === totalPages ? "disabled" : ""}>
|
|
33275
|
-
Pr\xF3ximo
|
|
33276
|
-
</button>
|
|
33277
|
-
</div>
|
|
33278
|
-
</div>
|
|
33279
|
-
`;
|
|
33280
|
-
document.getElementById("prev-page")?.addEventListener("click", () => {
|
|
33281
|
-
if (this.currentPage > 1) {
|
|
33282
|
-
this.currentPage--;
|
|
33283
|
-
this.renderTable();
|
|
33284
|
-
}
|
|
33285
|
-
});
|
|
33286
|
-
document.getElementById("next-page")?.addEventListener("click", () => {
|
|
33287
|
-
if (this.currentPage < totalPages) {
|
|
33288
|
-
this.currentPage++;
|
|
33289
|
-
this.renderTable();
|
|
33290
|
-
}
|
|
33291
|
-
});
|
|
33292
|
-
container.style.display = "block";
|
|
33293
33469
|
}
|
|
33294
33470
|
calculateTotalConsumption() {
|
|
33295
33471
|
return this.data.reduce((sum, row) => sum + row.consumption, 0);
|
|
@@ -33333,7 +33509,7 @@ var AllReportModal = class {
|
|
|
33333
33509
|
}
|
|
33334
33510
|
generateStoreId(storeName) {
|
|
33335
33511
|
const name = (storeName || "SEM-ID").toString();
|
|
33336
|
-
return name.toLowerCase().replace(/\s+/g, "-").replace(/[
|
|
33512
|
+
return name.toLowerCase().replace(/\s+/g, "-").replace(/[0300-036f]/g, "");
|
|
33337
33513
|
}
|
|
33338
33514
|
applyFiltersAndSort(selectedIds, sortMode) {
|
|
33339
33515
|
this.selectedStoreIds = new Set(selectedIds);
|
|
@@ -33382,8 +33558,10 @@ var AllReportModal = class {
|
|
|
33382
33558
|
async fetchCustomerTotals(startISO, endISO) {
|
|
33383
33559
|
if (this.params.fetcher) {
|
|
33384
33560
|
const token2 = this.params.api.ingestionToken || await this.authClient.getBearer();
|
|
33561
|
+
const baseUrl2 = this.params.api.dataApiBaseUrl;
|
|
33562
|
+
if (!baseUrl2) throw new Error("dataApiBaseUrl n\xE3o configurado.");
|
|
33385
33563
|
return await this.params.fetcher({
|
|
33386
|
-
baseUrl:
|
|
33564
|
+
baseUrl: baseUrl2,
|
|
33387
33565
|
token: token2,
|
|
33388
33566
|
customerId: this.params.customerId,
|
|
33389
33567
|
startISO,
|
|
@@ -33420,6 +33598,87 @@ var AllReportModal = class {
|
|
|
33420
33598
|
this.debugLog("[AllReportModal] Customer totals response:", data);
|
|
33421
33599
|
return data;
|
|
33422
33600
|
}
|
|
33601
|
+
// Re-map the cached API response under the current exclusion flag and refresh the UI.
|
|
33602
|
+
// No-op until data has been loaded at least once.
|
|
33603
|
+
remapAndRender() {
|
|
33604
|
+
if (!this.lastApiResponse) return;
|
|
33605
|
+
this.data = this.mapCustomerTotalsResponse(this.lastApiResponse);
|
|
33606
|
+
this.selectedStoreIds = new Set(this.data.map((s) => this.generateStoreId(s.identifier)));
|
|
33607
|
+
this.currentPage = 1;
|
|
33608
|
+
this.renderSummary();
|
|
33609
|
+
this.renderTable();
|
|
33610
|
+
}
|
|
33611
|
+
// Premium tooltip content for the exclusion-flag info icon. Uses the library
|
|
33612
|
+
// InfoTooltip CSS classes (myio-info-tooltip__*) — injected by InfoTooltip itself.
|
|
33613
|
+
buildExclusionTooltipContent() {
|
|
33614
|
+
return `
|
|
33615
|
+
<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>
|
|
33635
|
+
</div>
|
|
33636
|
+
<div class="myio-info-tooltip__notice">
|
|
33637
|
+
<span class="myio-info-tooltip__notice-icon">\u{1F4A1}</span>
|
|
33638
|
+
<span>N\xE3o altera nenhum dado \u2014 apenas o que o relat\xF3rio soma e lista.</span>
|
|
33639
|
+
</div>
|
|
33640
|
+
`;
|
|
33641
|
+
}
|
|
33642
|
+
// Resolve the canonical `exclude_groups_totals.groups` key for the report's current group.
|
|
33643
|
+
// Returns null for groupings that don't map to a single exclusion key (climatizavel, etc.).
|
|
33644
|
+
resolveExclusionGroupKey(item) {
|
|
33645
|
+
const g = String(this.params.group || "").toLowerCase();
|
|
33646
|
+
if (g === "entrada" || g === "lojas" || g === "area_comum") return g;
|
|
33647
|
+
if (g === "todos") {
|
|
33648
|
+
const gl = String(item.groupLabel || "").normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().trim();
|
|
33649
|
+
if (gl === "entrada") return "entrada";
|
|
33650
|
+
if (gl === "lojas") return "lojas";
|
|
33651
|
+
if (gl === "area comum" || gl === "areacomum") return "area_comum";
|
|
33652
|
+
if (gl === "climatizacao") return "climatizacao";
|
|
33653
|
+
if (gl === "elevadores") return "elevadores";
|
|
33654
|
+
if (gl === "escadas rolantes" || gl === "esc. rolantes") return "escadas_rolantes";
|
|
33655
|
+
if (gl === "outros" || gl === "outros equipamentos") return "outros";
|
|
33656
|
+
}
|
|
33657
|
+
return null;
|
|
33658
|
+
}
|
|
33659
|
+
// Mirrors getValorEfetivo (MAIN_VIEW): a device flagged in exclude_groups_totals for the
|
|
33660
|
+
// report's group is dropped, so the report total reconciles with the dashboard KPI card.
|
|
33661
|
+
isExcludedFromTotals(item) {
|
|
33662
|
+
const raw = item.excludeGroupsTotals;
|
|
33663
|
+
if (!raw) return false;
|
|
33664
|
+
let parsed;
|
|
33665
|
+
try {
|
|
33666
|
+
parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
33667
|
+
} catch {
|
|
33668
|
+
return false;
|
|
33669
|
+
}
|
|
33670
|
+
if (!parsed || parsed.enabled !== true) return false;
|
|
33671
|
+
const key = this.resolveExclusionGroupKey(item);
|
|
33672
|
+
if (!key) return false;
|
|
33673
|
+
if (parsed.groups && typeof parsed.groups === "object") {
|
|
33674
|
+
return parsed.groups[key] === true;
|
|
33675
|
+
}
|
|
33676
|
+
if (Array.isArray(parsed.excludedGroups)) {
|
|
33677
|
+
const ex = parsed.excludedGroups.map((x) => String(x).toLowerCase());
|
|
33678
|
+
return ex.includes(key) || ex.includes("all");
|
|
33679
|
+
}
|
|
33680
|
+
return false;
|
|
33681
|
+
}
|
|
33423
33682
|
mapCustomerTotalsResponse(apiResponse) {
|
|
33424
33683
|
this.debugLog("\u{1F50D} Starting mapCustomerTotalsResponse", { apiResponse });
|
|
33425
33684
|
const apiArray = Array.isArray(apiResponse?.data) ? apiResponse.data : Array.isArray(apiResponse) ? apiResponse : [];
|
|
@@ -33457,6 +33716,10 @@ var AllReportModal = class {
|
|
|
33457
33716
|
const apiId = String(apiItem?.id || "");
|
|
33458
33717
|
if (!apiId || !orchIdSet.has(apiId)) continue;
|
|
33459
33718
|
const meta = orchMeta.get(apiId);
|
|
33719
|
+
if (this.considerExclusion && meta && this.isExcludedFromTotals(meta)) {
|
|
33720
|
+
this.debugLog("[AllReportModal] device excluded via exclude_groups_totals:", meta.label);
|
|
33721
|
+
continue;
|
|
33722
|
+
}
|
|
33460
33723
|
const consumption = Math.round(this.pickConsumption(apiItem) * 100) / 100;
|
|
33461
33724
|
const result = {
|
|
33462
33725
|
identifier: meta?.identifier || apiItem.name || apiId,
|
|
@@ -84133,7 +84396,7 @@ async function fetchIngestionDevicesAllPaged(customerId) {
|
|
|
84133
84396
|
function findIngestionDeviceByCentralSlaveId(devices, centralId, slaveId) {
|
|
84134
84397
|
const slaveIdNum = typeof slaveId === "string" ? parseInt(slaveId, 10) : slaveId;
|
|
84135
84398
|
for (const device of devices) {
|
|
84136
|
-
const deviceGatewayId = device.gatewayId || device.gateway?.id;
|
|
84399
|
+
const deviceGatewayId = device.gateway?.hardwareUuid || device.gatewayId || device.gateway?.id;
|
|
84137
84400
|
if (deviceGatewayId === centralId && device.slaveId === slaveIdNum) {
|
|
84138
84401
|
console.log(
|
|
84139
84402
|
"[UpsellModal] Found matching device:",
|
|
@@ -84151,8 +84414,8 @@ function findIngestionDeviceByCentralSlaveId(devices, centralId, slaveId) {
|
|
|
84151
84414
|
console.log(
|
|
84152
84415
|
`[UpsellModal] Sample device ${i}:`,
|
|
84153
84416
|
d.name,
|
|
84154
|
-
"
|
|
84155
|
-
d.gatewayId || d.gateway?.id,
|
|
84417
|
+
"gateway(hwUuid|id):",
|
|
84418
|
+
d.gateway?.hardwareUuid || d.gatewayId || d.gateway?.id,
|
|
84156
84419
|
"slaveId:",
|
|
84157
84420
|
d.slaveId
|
|
84158
84421
|
);
|
|
@@ -84337,7 +84600,7 @@ function openUpsellModal(params) {
|
|
|
84337
84600
|
selectedDevices: [],
|
|
84338
84601
|
bulkAttributeModal: { open: false, attribute: "deviceType", value: "", saving: false },
|
|
84339
84602
|
bulkProfileModal: { open: false, selectedProfileId: "", saving: false },
|
|
84340
|
-
bulkOwnerModal: { open: false, saving: false },
|
|
84603
|
+
bulkOwnerModal: { open: false, saving: false, targetCustomerId: "" },
|
|
84341
84604
|
columnWidths: {
|
|
84342
84605
|
name: 180,
|
|
84343
84606
|
label: 120,
|
|
@@ -84374,6 +84637,7 @@ function openUpsellModal(params) {
|
|
|
84374
84637
|
lojasDeviceData: [],
|
|
84375
84638
|
lojasDataLoading: false,
|
|
84376
84639
|
lojasConfig: null,
|
|
84640
|
+
lojasApplyRelation: true,
|
|
84377
84641
|
customModeModal: { open: false },
|
|
84378
84642
|
bulkRelationModal: { open: false, target: "CUSTOMER", selectedAssetId: "", selectedAssetName: "", search: "", newAssetName: "", assetsLoaded: false, overrideCustomerId: "", overrideCustomerName: "", customerSearch: "", customerPickerOpen: false },
|
|
84379
84643
|
checkFixLoading: false,
|
|
@@ -84538,6 +84802,12 @@ function renderModal4(container, state6, modalId, t, error) {
|
|
|
84538
84802
|
font-size: 14px; font-weight: 500; font-family: 'Roboto', Arial, sans-serif;
|
|
84539
84803
|
display: flex; align-items: center; gap: 6px;
|
|
84540
84804
|
" ${!state6.selectedCustomer ? 'disabled title="Selecione um Customer primeiro"' : ""}>\u{1F504} Sync Ingestion ID (${state6.selectedDevices.length})</button>
|
|
84805
|
+
<button id="${modalId}-bulk-delete" style="
|
|
84806
|
+
background: #b91c1c; color: white; border: 1px solid #7f1d1d;
|
|
84807
|
+
padding: 8px 16px; border-radius: 6px; cursor: pointer;
|
|
84808
|
+
font-size: 14px; font-weight: 600; font-family: 'Roboto', Arial, sans-serif;
|
|
84809
|
+
display: flex; align-items: center; gap: 6px;
|
|
84810
|
+
" title="Deletar permanentemente os dispositivos selecionados (irrevers\xEDvel)">\u{1F5D1}\uFE0F Deletar (${state6.selectedDevices.length})</button>
|
|
84541
84811
|
` : ""}
|
|
84542
84812
|
${state6.currentStep === 3 && state6.lojasMode ? `
|
|
84543
84813
|
<button id="${modalId}-lojas-sync" style="
|
|
@@ -84776,7 +85046,18 @@ function renderModal4(container, state6, modalId, t, error) {
|
|
|
84776
85046
|
</div>
|
|
84777
85047
|
` : ""}
|
|
84778
85048
|
|
|
84779
|
-
${state6.bulkOwnerModal.open ?
|
|
85049
|
+
${state6.bulkOwnerModal.open ? (() => {
|
|
85050
|
+
const effId = state6.bulkOwnerModal.targetCustomerId || state6.selectedCustomer?.id?.id || "";
|
|
85051
|
+
const effCustomer = state6.customers.find((c) => c.id?.id === effId) || state6.selectedCustomer;
|
|
85052
|
+
const effName = effCustomer?.name || effCustomer?.title || "N\xE3o selecionado";
|
|
85053
|
+
const customerOptions = state6.customers.length === 0 ? `<option value="${effId}">${effName}</option>` : [...state6.customers].sort(
|
|
85054
|
+
(a, b) => (a.name || a.title || "").localeCompare(b.name || b.title || "", "pt-BR")
|
|
85055
|
+
).map((c) => {
|
|
85056
|
+
const cid = c.id?.id || "";
|
|
85057
|
+
const cname = c.name || c.title || cid;
|
|
85058
|
+
return `<option value="${cid}" ${cid === effId ? "selected" : ""}>${cname}</option>`;
|
|
85059
|
+
}).join("");
|
|
85060
|
+
return `
|
|
84780
85061
|
<!-- Bulk Owner Modal -->
|
|
84781
85062
|
<div class="myio-bulk-owner-overlay" style="
|
|
84782
85063
|
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
|
|
@@ -84802,17 +85083,25 @@ function renderModal4(container, state6, modalId, t, error) {
|
|
|
84802
85083
|
<div style="font-size: 14px; color: ${colors2.text}; font-weight: 500;">${state6.selectedDevices.length} dispositivos</div>
|
|
84803
85084
|
</div>
|
|
84804
85085
|
|
|
84805
|
-
<div style="margin-bottom: 16px;
|
|
84806
|
-
<div style="font-size: 12px; color: ${colors2.textMuted}; margin-bottom:
|
|
84807
|
-
|
|
85086
|
+
<div style="margin-bottom: 16px;">
|
|
85087
|
+
<div style="font-size: 12px; color: ${colors2.textMuted}; margin-bottom: 6px;">
|
|
85088
|
+
Novo Owner (Customer):
|
|
85089
|
+
</div>
|
|
85090
|
+
<select id="${modalId}-bulk-owner-customer" style="
|
|
85091
|
+
width: 100%; padding: 9px 10px; border-radius: 8px;
|
|
85092
|
+
border: 1px solid ${colors2.border}; background: ${colors2.inputBg};
|
|
85093
|
+
color: ${colors2.text}; font-size: 13px; cursor: pointer;
|
|
85094
|
+
">
|
|
85095
|
+
${customerOptions}
|
|
85096
|
+
</select>
|
|
84808
85097
|
<div style="font-size: 11px; color: ${colors2.textMuted}; margin-top: 4px;">
|
|
84809
|
-
ID: ${
|
|
85098
|
+
ID: ${effId || "N/A"}${state6.customers.length === 0 ? " \xB7 carregando lista de clientes\u2026" : ""}
|
|
84810
85099
|
</div>
|
|
84811
85100
|
</div>
|
|
84812
85101
|
|
|
84813
85102
|
<div style="margin-bottom: 16px; padding: 12px; background: ${colors2.warning}20; border-radius: 8px; border: 1px solid ${colors2.warning}40;">
|
|
84814
85103
|
<div style="font-size: 12px; color: ${colors2.warning}; font-weight: 500;">
|
|
84815
|
-
\u26A0\uFE0F Aten\xE7\xE3o: Esta a\xE7\xE3o ir\xE1 atribuir todos os ${state6.selectedDevices.length} devices selecionados ao customer "${
|
|
85104
|
+
\u26A0\uFE0F Aten\xE7\xE3o: Esta a\xE7\xE3o ir\xE1 atribuir todos os ${state6.selectedDevices.length} devices selecionados ao customer "${effName}".
|
|
84816
85105
|
</div>
|
|
84817
85106
|
</div>
|
|
84818
85107
|
|
|
@@ -84826,13 +85115,14 @@ function renderModal4(container, state6, modalId, t, error) {
|
|
|
84826
85115
|
background: #10b981; color: white; border: none;
|
|
84827
85116
|
padding: 10px 20px; border-radius: 6px; cursor: pointer;
|
|
84828
85117
|
font-size: 14px; font-weight: 500;
|
|
84829
|
-
" ${state6.bulkOwnerModal.saving || !
|
|
85118
|
+
" ${state6.bulkOwnerModal.saving || !effId ? "disabled" : ""}>
|
|
84830
85119
|
${state6.bulkOwnerModal.saving ? "Salvando..." : "Atribuir Owner para " + state6.selectedDevices.length + " devices"}
|
|
84831
85120
|
</button>
|
|
84832
85121
|
</div>
|
|
84833
85122
|
</div>
|
|
84834
85123
|
</div>
|
|
84835
|
-
|
|
85124
|
+
`;
|
|
85125
|
+
})() : ""}
|
|
84836
85126
|
|
|
84837
85127
|
${state6.customModeModal.open ? `
|
|
84838
85128
|
<!-- CUSTOM Mode Picker Modal -->
|
|
@@ -85052,6 +85342,7 @@ function renderModal4(container, state6, modalId, t, error) {
|
|
|
85052
85342
|
`;
|
|
85053
85343
|
})() : ""}
|
|
85054
85344
|
`;
|
|
85345
|
+
delete container.dataset.upsellListenersBound;
|
|
85055
85346
|
setupEventListeners3(container, state6, modalId, t);
|
|
85056
85347
|
}
|
|
85057
85348
|
function renderStepIndicator(step, label, currentStep, colors2) {
|
|
@@ -85255,6 +85546,8 @@ function renderCheckFixRow(r, state6, modalId, colors2, dupPairIds, dupIngestion
|
|
|
85255
85546
|
};
|
|
85256
85547
|
const valStr = Object.entries(r.telemetry.values).map(([k, v]) => v != null ? `${k}:<b>${v}${unit[k] ?? ""}</b>` : null).filter(Boolean).join(" \xB7 ") || "\u2014";
|
|
85257
85548
|
const connColor = r.connStatus ? CONN_COLOR[r.connStatus] || colors2.textMuted : colors2.textMuted;
|
|
85549
|
+
const valCopy = Object.entries(r.telemetry.values).filter(([, v]) => v != null).map(([k, v]) => `${k}: ${v}${unit[k] ?? ""}`).join(" \xB7 ");
|
|
85550
|
+
const copyAttr = (v) => `class="myio-copy-cell" data-copy="${encodeURIComponent(String(v ?? ""))}"`;
|
|
85258
85551
|
return `
|
|
85259
85552
|
<tr class="myio-list-item ${isSelected ? "selected" : ""}" data-device-id="${r.deviceId}"
|
|
85260
85553
|
style="border-bottom:1px solid ${colors2.border}; cursor:pointer;">
|
|
@@ -85263,21 +85556,21 @@ function renderCheckFixRow(r, state6, modalId, colors2, dupPairIds, dupIngestion
|
|
|
85263
85556
|
<input type="checkbox" class="myio-device-checkbox" data-device-id="${r.deviceId}"
|
|
85264
85557
|
${isSelectedMulti ? "checked" : ""} style="width:14px;height:14px;cursor:pointer;accent-color:${MYIO_PURPLE};"/>
|
|
85265
85558
|
</td>` : ""}
|
|
85266
|
-
<td style="${cell()} max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${r.deviceName}">${r.deviceName}</td>
|
|
85267
|
-
<td style="${cell()} max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:${colors2.textMuted};" title="${r.deviceLabel}">${r.deviceLabel || dash}</td>
|
|
85268
|
-
<td style="${cell(typeActWrong ? "ok" : "none", true)}">${r.inferred.deviceType}</td>
|
|
85269
|
-
<td style="${cell(typeActWrong ? r.typeEqualsProfile ? "warn" : "bad" : "none", true)}" title="${typeActWrong ? `esperado: ${r.inferred.deviceType}` : ""}">${r.actual.type || dash}</td>
|
|
85270
|
-
<td style="${cell(devTypeWrong ? "ok" : "none", true)}">${r.inferred.deviceType}</td>
|
|
85271
|
-
<td style="${cell(devTypeWrong ? "bad" : "none", true)}" title="${devTypeWrong ? `esperado: ${r.inferred.deviceType}` : ""}">${r.actual.deviceType || dash}</td>
|
|
85272
|
-
<td style="${cell(devProfWrong ? "ok" : "none", true)}">${r.inferred.deviceProfile}</td>
|
|
85273
|
-
<td style="${cell(devProfWrong ? "bad" : "none", true)}" title="${devProfWrong ? `esperado: ${r.inferred.deviceProfile}` : ""}">${r.actual.deviceProfile || dash}</td>
|
|
85274
|
-
<td style="${cell()} white-space:nowrap; color:${colors2.textMuted}; font-size:9px;">${tsStr}</td>
|
|
85275
|
-
<td style="${cell()} font-size:9px;">${valStr}</td>
|
|
85276
|
-
<td style="${cell()} color:${connColor}; font-weight:600; white-space:nowrap;">${r.connStatus || dash}</td>
|
|
85277
|
-
<td style="${cell()} font-size:9px; font-family:monospace; color:${colors2.textMuted}; max-width:110px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${r.gcdrDeviceId || ""}">${r.gcdrDeviceId || dash}</td>
|
|
85278
|
-
<td style="${cell(dupIngestionIds.has(r.deviceId) ? "bad" : "none")} font-size:9px; font-family:monospace; max-width:110px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${r.ingestionId || ""}">${r.ingestionId || dash}</td>
|
|
85279
|
-
<td style="${cell(dupPairIds.has(r.deviceId) ? "bad" : "none")} font-size:9px; font-family:monospace; max-width:80px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${r.centralId || ""}">${r.centralId || dash}</td>
|
|
85280
|
-
<td style="${cell(dupPairIds.has(r.deviceId) ? "bad" : "none")} font-size:9px; font-family:monospace; max-width:50px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">${r.slaveId || dash}</td>
|
|
85559
|
+
<td ${copyAttr(r.deviceName)} style="${cell()} max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${r.deviceName}">${r.deviceName}</td>
|
|
85560
|
+
<td ${copyAttr(r.deviceLabel)} style="${cell()} max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:${colors2.textMuted};" title="${r.deviceLabel}">${r.deviceLabel || dash}</td>
|
|
85561
|
+
<td ${copyAttr(r.inferred.deviceType)} style="${cell(typeActWrong ? "ok" : "none", true)}">${r.inferred.deviceType}</td>
|
|
85562
|
+
<td ${copyAttr(r.actual.type ?? "")} style="${cell(typeActWrong ? r.typeEqualsProfile ? "warn" : "bad" : "none", true)}" title="${typeActWrong ? `esperado: ${r.inferred.deviceType}` : ""}">${r.actual.type || dash}</td>
|
|
85563
|
+
<td ${copyAttr(r.inferred.deviceType)} style="${cell(devTypeWrong ? "ok" : "none", true)}">${r.inferred.deviceType}</td>
|
|
85564
|
+
<td ${copyAttr(r.actual.deviceType ?? "")} style="${cell(devTypeWrong ? "bad" : "none", true)}" title="${devTypeWrong ? `esperado: ${r.inferred.deviceType}` : ""}">${r.actual.deviceType || dash}</td>
|
|
85565
|
+
<td ${copyAttr(r.inferred.deviceProfile)} style="${cell(devProfWrong ? "ok" : "none", true)}">${r.inferred.deviceProfile}</td>
|
|
85566
|
+
<td ${copyAttr(r.actual.deviceProfile ?? "")} style="${cell(devProfWrong ? "bad" : "none", true)}" title="${devProfWrong ? `esperado: ${r.inferred.deviceProfile}` : ""}">${r.actual.deviceProfile || dash}</td>
|
|
85567
|
+
<td ${copyAttr(r.telemetry.ts ? tsStr : "")} style="${cell()} white-space:nowrap; color:${colors2.textMuted}; font-size:9px;">${tsStr}</td>
|
|
85568
|
+
<td ${copyAttr(valCopy)} style="${cell()} font-size:9px;">${valStr}</td>
|
|
85569
|
+
<td ${copyAttr(r.connStatus ?? "")} style="${cell()} color:${connColor}; font-weight:600; white-space:nowrap;">${r.connStatus || dash}</td>
|
|
85570
|
+
<td ${copyAttr(r.gcdrDeviceId ?? "")} style="${cell()} font-size:9px; font-family:monospace; color:${colors2.textMuted}; max-width:110px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${r.gcdrDeviceId || ""}">${r.gcdrDeviceId || dash}</td>
|
|
85571
|
+
<td ${copyAttr(r.ingestionId ?? "")} style="${cell(dupIngestionIds.has(r.deviceId) ? "bad" : "none")} font-size:9px; font-family:monospace; max-width:110px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${r.ingestionId || ""}">${r.ingestionId || dash}</td>
|
|
85572
|
+
<td ${copyAttr(r.centralId ?? "")} style="${cell(dupPairIds.has(r.deviceId) ? "bad" : "none")} font-size:9px; font-family:monospace; max-width:80px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${r.centralId || ""}">${r.centralId || dash}</td>
|
|
85573
|
+
<td ${copyAttr(r.slaveId ?? "")} style="${cell(dupPairIds.has(r.deviceId) ? "bad" : "none")} font-size:9px; font-family:monospace; max-width:50px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">${r.slaveId || dash}</td>
|
|
85281
85574
|
<td style="padding:4px 6px; font-size:10px; color:${STATUS_COLOR[r.status]}; font-weight:700; white-space:nowrap; cursor:${r.status !== "ok" ? "help" : "default"};"
|
|
85282
85575
|
${r.status !== "ok" ? `data-cf-status="${r.status}" data-cf-device="${encodeURIComponent(r.deviceName)}" data-cf-detail="${encodeURIComponent(_buildCfStatusDetail(r))}"` : ""}>
|
|
85283
85576
|
${STATUS_ICON[r.status]} ${r.status}
|
|
@@ -85323,16 +85616,7 @@ function renderStep2(state6, modalId, colors2, t) {
|
|
|
85323
85616
|
}
|
|
85324
85617
|
return true;
|
|
85325
85618
|
});
|
|
85326
|
-
const searchFilteredDevices = searchTerm ? filteredDevices.filter((d) =>
|
|
85327
|
-
const name = (d.name || "").toLowerCase();
|
|
85328
|
-
const label = (d.label || "").toLowerCase();
|
|
85329
|
-
const type = (d.type || "").toLowerCase();
|
|
85330
|
-
const deviceType = (d.serverAttrs?.deviceType || "").toLowerCase();
|
|
85331
|
-
const deviceProfile = (d.serverAttrs?.deviceProfile || "").toLowerCase();
|
|
85332
|
-
const slaveId = String(d.serverAttrs?.slaveId ?? "").toLowerCase();
|
|
85333
|
-
const status = (d.latestTelemetry?.connectionStatus?.value || "").toLowerCase();
|
|
85334
|
-
return name.includes(searchTerm) || label.includes(searchTerm) || type.includes(searchTerm) || deviceType.includes(searchTerm) || deviceProfile.includes(searchTerm) || slaveId.includes(searchTerm) || status.includes(searchTerm);
|
|
85335
|
-
}) : filteredDevices;
|
|
85619
|
+
const searchFilteredDevices = searchTerm ? filteredDevices.filter((d) => buildDeviceSearchHaystack(d, state6).includes(searchTerm)) : filteredDevices;
|
|
85336
85620
|
const sortedDevices = sortDevices2(searchFilteredDevices, sortField, sortOrder);
|
|
85337
85621
|
const gridHeight = state6.isMaximized ? "calc(100vh - 340px)" : "360px";
|
|
85338
85622
|
const hasActiveFilters = filterTypes.length > 0 || filterDeviceTypes.length > 0 || filterDeviceProfiles.length > 0 || filterStatuses.length > 0 || filterTelemetryKeys.length > 0;
|
|
@@ -85800,6 +86084,95 @@ function renderStep2(state6, modalId, colors2, t) {
|
|
|
85800
86084
|
})()}
|
|
85801
86085
|
`;
|
|
85802
86086
|
}
|
|
86087
|
+
function buildDeviceSearchHaystack(d, state6) {
|
|
86088
|
+
const id = getEntityId(d);
|
|
86089
|
+
const relTo = (state6.deviceRelToMap.get(id) || []).map((r) => r.name || "").join(" ");
|
|
86090
|
+
const relFrom = (state6.deviceRelFromMap.get(id) || []).map((r) => r.name || "").join(" ");
|
|
86091
|
+
const tel = d.latestTelemetry || {};
|
|
86092
|
+
const a = d.serverAttrs || {};
|
|
86093
|
+
return [
|
|
86094
|
+
d.name,
|
|
86095
|
+
d.label,
|
|
86096
|
+
d.type,
|
|
86097
|
+
d.createdTime ? formatDate6(d.createdTime, state6.locale) : "",
|
|
86098
|
+
relTo,
|
|
86099
|
+
relFrom,
|
|
86100
|
+
a.centralId,
|
|
86101
|
+
a.slaveId,
|
|
86102
|
+
a.deviceType,
|
|
86103
|
+
a.deviceProfile,
|
|
86104
|
+
tel.pulses?.value,
|
|
86105
|
+
tel.consumption?.value,
|
|
86106
|
+
tel.temperature?.value,
|
|
86107
|
+
tel.connectionStatus?.value
|
|
86108
|
+
].map((v) => String(v ?? "").toLowerCase()).join("");
|
|
86109
|
+
}
|
|
86110
|
+
function getGridVisibleDevices(state6) {
|
|
86111
|
+
const {
|
|
86112
|
+
types: filterTypes,
|
|
86113
|
+
deviceTypes: filterDeviceTypes,
|
|
86114
|
+
deviceProfiles: filterDeviceProfiles,
|
|
86115
|
+
statuses: filterStatuses,
|
|
86116
|
+
telemetryKeys: filterTelemetryKeys
|
|
86117
|
+
} = state6.deviceFilters;
|
|
86118
|
+
const searchTerm = state6.deviceSearchTerm.toLowerCase();
|
|
86119
|
+
let result = state6.devices.filter((d) => {
|
|
86120
|
+
if (filterTypes.length > 0 && !filterTypes.includes(d.type || "")) return false;
|
|
86121
|
+
if (filterDeviceTypes.length > 0 && !filterDeviceTypes.includes(d.serverAttrs?.deviceType || ""))
|
|
86122
|
+
return false;
|
|
86123
|
+
if (filterDeviceProfiles.length > 0 && !filterDeviceProfiles.includes(d.serverAttrs?.deviceProfile || ""))
|
|
86124
|
+
return false;
|
|
86125
|
+
if (filterStatuses.length > 0) {
|
|
86126
|
+
const status = d.latestTelemetry?.connectionStatus?.value || "offline";
|
|
86127
|
+
if (!filterStatuses.includes(status)) return false;
|
|
86128
|
+
}
|
|
86129
|
+
if (filterTelemetryKeys.length > 0) {
|
|
86130
|
+
const telem = d.latestTelemetry;
|
|
86131
|
+
const hasMatch = filterTelemetryKeys.some((k) => {
|
|
86132
|
+
if (k === "pulses") return telem?.pulses != null;
|
|
86133
|
+
if (k === "consumption") return telem?.consumption != null;
|
|
86134
|
+
return false;
|
|
86135
|
+
});
|
|
86136
|
+
if (!hasMatch) return false;
|
|
86137
|
+
}
|
|
86138
|
+
return true;
|
|
86139
|
+
});
|
|
86140
|
+
if (searchTerm) {
|
|
86141
|
+
result = result.filter((d) => buildDeviceSearchHaystack(d, state6).includes(searchTerm));
|
|
86142
|
+
}
|
|
86143
|
+
if (state6.checkFixReport) {
|
|
86144
|
+
const idToRecord = new Map(state6.checkFixReport.records.map((r) => [r.deviceId, r]));
|
|
86145
|
+
const af = state6.checkFixAdvancedFilter;
|
|
86146
|
+
result = result.filter((d) => {
|
|
86147
|
+
const r = idToRecord.get(getEntityId(d));
|
|
86148
|
+
if (!r) return false;
|
|
86149
|
+
if (!(state6.checkFixFilter === "all" || r.status === state6.checkFixFilter)) return false;
|
|
86150
|
+
if (af.statuses.length > 0 && !af.statuses.includes(r.status)) return false;
|
|
86151
|
+
if (af.connStatuses.length > 0 && !af.connStatuses.includes(r.connStatus || "null")) return false;
|
|
86152
|
+
if (af.domains.length > 0 && !af.domains.includes(r.domain || "null")) return false;
|
|
86153
|
+
if (af.missingIngestionId && r.ingestionId) return false;
|
|
86154
|
+
if (af.missingCentralSlave && r.centralId && r.slaveId != null) return false;
|
|
86155
|
+
return true;
|
|
86156
|
+
});
|
|
86157
|
+
}
|
|
86158
|
+
return result;
|
|
86159
|
+
}
|
|
86160
|
+
function copyCellValue(text, el2) {
|
|
86161
|
+
if (!text) return;
|
|
86162
|
+
const flash = (ok) => {
|
|
86163
|
+
const prev = el2.style.backgroundColor;
|
|
86164
|
+
el2.style.transition = "background-color 0.15s ease";
|
|
86165
|
+
el2.style.backgroundColor = ok ? "rgba(34,197,94,0.35)" : "rgba(239,68,68,0.35)";
|
|
86166
|
+
setTimeout(() => {
|
|
86167
|
+
el2.style.backgroundColor = prev;
|
|
86168
|
+
}, 350);
|
|
86169
|
+
};
|
|
86170
|
+
if (navigator.clipboard?.writeText) {
|
|
86171
|
+
navigator.clipboard.writeText(text).then(() => flash(true), () => flash(false));
|
|
86172
|
+
} else {
|
|
86173
|
+
flash(false);
|
|
86174
|
+
}
|
|
86175
|
+
}
|
|
85803
86176
|
function renderDeviceRow(device, state6, modalId, colors2) {
|
|
85804
86177
|
const deviceId = getEntityId(device);
|
|
85805
86178
|
const isSelectedSingle = state6.deviceSelectionMode === "single" && getEntityId(state6.selectedDevice) === deviceId;
|
|
@@ -85914,6 +86287,10 @@ function renderDeviceRow(device, state6, modalId, colors2) {
|
|
|
85914
86287
|
" title="${statusTs}">(+)</span>` : ""}
|
|
85915
86288
|
`;
|
|
85916
86289
|
};
|
|
86290
|
+
const relToNames = state6.relationsLoaded ? (state6.deviceRelToMap.get(deviceId) || []).map((r) => r.name || "").filter(Boolean).join(", ") : "";
|
|
86291
|
+
const relFromNames = state6.relationsLoaded ? (state6.deviceRelFromMap.get(deviceId) || []).map((r) => r.name || "").filter(Boolean).join(", ") : "";
|
|
86292
|
+
const telemetryCopy = telemetryItems.map((it) => `${it.label}: ${it.value}${it.unit}`).join("; ");
|
|
86293
|
+
const copyAttr = (v) => `class="myio-copy-cell" data-copy="${encodeURIComponent(String(v ?? ""))}" title="Clique para copiar valor"`;
|
|
85917
86294
|
return `
|
|
85918
86295
|
<div class="myio-list-item ${isSelected ? "selected" : ""}"
|
|
85919
86296
|
data-device-id="${deviceId}" style="
|
|
@@ -85929,8 +86306,8 @@ function renderDeviceRow(device, state6, modalId, colors2) {
|
|
|
85929
86306
|
" />
|
|
85930
86307
|
</div>
|
|
85931
86308
|
` : ""}
|
|
85932
|
-
<div style="width: 28px; font-size: 16px; flex-shrink: 0;">${getDeviceIcon3(device.type)}</div>
|
|
85933
|
-
<div style="width: ${state6.columnWidths.name}px; padding: 0 6px; overflow: hidden; display: flex; align-items: center; gap: 4px;">
|
|
86309
|
+
<div style="width: 28px; font-size: 16px; flex-shrink: 0; cursor: pointer;" title="Clique para selecionar o dispositivo">${getDeviceIcon3(device.type)}</div>
|
|
86310
|
+
<div ${copyAttr(device.name)} style="width: ${state6.columnWidths.name}px; padding: 0 6px; overflow: hidden; display: flex; align-items: center; gap: 4px; cursor: pointer;">
|
|
85934
86311
|
<div style="font-weight: 600; color: ${colors2.text}; font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1;" title="${device.name}">
|
|
85935
86312
|
${device.name}
|
|
85936
86313
|
</div>
|
|
@@ -85940,22 +86317,22 @@ function renderDeviceRow(device, state6, modalId, colors2) {
|
|
|
85940
86317
|
display: flex; align-items: center; justify-content: center; border: 1px solid ${colors2.border};
|
|
85941
86318
|
" title="Ver detalhes">\u24D8</span>
|
|
85942
86319
|
</div>
|
|
85943
|
-
<div style="width: ${state6.columnWidths.label}px; padding: 0 6px; overflow: hidden; flex-shrink: 0;">
|
|
86320
|
+
<div ${copyAttr(device.label ?? "")} style="width: ${state6.columnWidths.label}px; padding: 0 6px; overflow: hidden; flex-shrink: 0; cursor: pointer;">
|
|
85944
86321
|
<div style="font-size: 10px; color: ${colors2.textMuted}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" title="${device.label ?? ""}">
|
|
85945
86322
|
${device.label ?? ""}
|
|
85946
86323
|
</div>
|
|
85947
86324
|
</div>
|
|
85948
|
-
<div style="width: ${state6.columnWidths.type}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden;">
|
|
86325
|
+
<div ${copyAttr(device.type ?? "")} style="width: ${state6.columnWidths.type}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; cursor: pointer;">
|
|
85949
86326
|
<div style="font-size: 9px; padding: 2px 4px; border-radius: 3px; display: inline-block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
|
|
85950
86327
|
background: ${device.type?.includes("HIDRO") ? "#dbeafe" : "#fef3c7"};
|
|
85951
86328
|
color: ${device.type?.includes("HIDRO") ? "#1e40af" : "#92400e"};" title="${device.type || ""}">
|
|
85952
86329
|
${device.type || "\u2014"}
|
|
85953
86330
|
</div>
|
|
85954
86331
|
</div>
|
|
85955
|
-
<div style="width: ${state6.columnWidths.createdTime}px; padding: 0 6px; text-align: center; flex-shrink: 0;">
|
|
86332
|
+
<div ${copyAttr(device.createdTime ? createdTimeStr : "")} style="width: ${state6.columnWidths.createdTime}px; padding: 0 6px; text-align: center; flex-shrink: 0; cursor: pointer;">
|
|
85956
86333
|
<span style="font-size: 9px; color: ${colors2.textMuted};">${createdTimeStr}</span>
|
|
85957
86334
|
</div>
|
|
85958
|
-
<div style="width: ${state6.columnWidths.relationTo}px; padding: 0 6px; flex-shrink: 0; overflow: hidden; display:flex; align-items:center; justify-content:center; gap:3px;">
|
|
86335
|
+
<div ${copyAttr(relToNames)} style="width: ${state6.columnWidths.relationTo}px; padding: 0 6px; flex-shrink: 0; overflow: hidden; display:flex; align-items:center; justify-content:center; gap:3px; cursor: pointer;">
|
|
85959
86336
|
${(() => {
|
|
85960
86337
|
if (!state6.relationsLoaded) return `<span style="font-size: 8px; color: ${colors2.textMuted}; font-style: italic;">\u2014</span>`;
|
|
85961
86338
|
const rels = state6.deviceRelToMap.get(deviceId) || [];
|
|
@@ -85965,7 +86342,7 @@ function renderDeviceRow(device, state6, modalId, colors2) {
|
|
|
85965
86342
|
return `<span style="font-size:9px;color:${colors2.text};overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:${more > 0 ? 68 : 108}px" title="${first.name}">${first.name}</span>${more > 0 ? `<button data-show-relto="${deviceId}" data-device-name="${encodeURIComponent(device.name || "")}" style="flex-shrink:0;font-size:9px;background:#ede9ff;color:#4c1d95;border:none;border-radius:3px;padding:1px 4px;cursor:pointer;font-weight:700;line-height:1.4">+${more}</button>` : ""}`;
|
|
85966
86343
|
})()}
|
|
85967
86344
|
</div>
|
|
85968
|
-
<div style="width: ${state6.columnWidths.relationFrom}px; padding: 0 6px; flex-shrink: 0; overflow: hidden; display:flex; align-items:center; justify-content:center; gap:3px;">
|
|
86345
|
+
<div ${copyAttr(relFromNames)} style="width: ${state6.columnWidths.relationFrom}px; padding: 0 6px; flex-shrink: 0; overflow: hidden; display:flex; align-items:center; justify-content:center; gap:3px; cursor: pointer;">
|
|
85969
86346
|
${(() => {
|
|
85970
86347
|
if (!state6.relationsLoaded) return `<span style="font-size: 8px; color: ${colors2.textMuted}; font-style: italic;">\u2014</span>`;
|
|
85971
86348
|
const rels = state6.deviceRelFromMap.get(deviceId) || [];
|
|
@@ -85975,25 +86352,25 @@ function renderDeviceRow(device, state6, modalId, colors2) {
|
|
|
85975
86352
|
return `<span style="font-size:9px;color:${colors2.text};overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:${more > 0 ? 68 : 98}px" title="${first.name}">${first.name}</span>${more > 0 ? `<button data-show-relfrom="${deviceId}" data-device-name="${encodeURIComponent(device.name || "")}" style="flex-shrink:0;font-size:9px;background:#dbeafe;color:#1e40af;border:none;border-radius:3px;padding:1px 4px;cursor:pointer;font-weight:700;line-height:1.4">+${more}</button>` : ""}`;
|
|
85976
86353
|
})()}
|
|
85977
86354
|
</div>
|
|
85978
|
-
<div style="width: ${state6.columnWidths.centralId}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
|
|
86355
|
+
<div ${copyAttr(attrs.centralId ?? "")} style="width: ${state6.columnWidths.centralId}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; cursor: pointer;">
|
|
85979
86356
|
${!state6.deviceAttrsLoaded ? `<span style="font-size: 8px; color: ${colors2.textMuted}; font-style: italic;">\u2014</span>` : attrs.centralId ? `<span style="font-size: 9px; color: ${colors2.text};" title="${attrs.centralId}">${attrs.centralId}</span>` : `<span style="font-size: 9px; color: ${colors2.textMuted};">\u2014</span>`}
|
|
85980
86357
|
</div>
|
|
85981
|
-
<div style="width: ${state6.columnWidths.slaveId}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
|
|
86358
|
+
<div ${copyAttr(attrs.slaveId ?? "")} style="width: ${state6.columnWidths.slaveId}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; cursor: pointer;">
|
|
85982
86359
|
${!state6.deviceAttrsLoaded ? `<span style="font-size: 8px; color: ${colors2.textMuted}; font-style: italic;">\u2014</span>` : attrs.slaveId != null && attrs.slaveId !== "" ? `<span style="font-size: 9px; color: ${colors2.text};" title="${attrs.slaveId}">${attrs.slaveId}</span>` : `<span style="font-size: 9px; color: ${colors2.textMuted};">\u2014</span>`}
|
|
85983
86360
|
</div>
|
|
85984
|
-
<div style="width: ${state6.columnWidths.deviceType}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
|
|
86361
|
+
<div ${copyAttr(state6.deviceAttrsLoaded ? attrs.deviceType ?? "" : "")} style="width: ${state6.columnWidths.deviceType}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; cursor: pointer;">
|
|
85985
86362
|
${renderDeviceTypeValue()}
|
|
85986
86363
|
</div>
|
|
85987
|
-
<div style="width: ${state6.columnWidths.deviceProfile}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
|
|
86364
|
+
<div ${copyAttr(state6.deviceAttrsLoaded ? attrs.deviceProfile ?? "" : "")} style="width: ${state6.columnWidths.deviceProfile}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; cursor: pointer;">
|
|
85988
86365
|
${renderDeviceProfileValue()}
|
|
85989
86366
|
</div>
|
|
85990
|
-
<div style="width: ${state6.columnWidths.telemetry}px; padding: 0 6px; text-align: center; flex-shrink: 0; display: flex; align-items: center; justify-content: center; gap: 4px; flex-wrap: wrap;">
|
|
86367
|
+
<div ${copyAttr(telemetryCopy)} style="width: ${state6.columnWidths.telemetry}px; padding: 0 6px; text-align: center; flex-shrink: 0; display: flex; align-items: center; justify-content: center; gap: 4px; flex-wrap: wrap; cursor: pointer;">
|
|
85991
86368
|
${renderTelemetryValue()}
|
|
85992
86369
|
</div>
|
|
85993
|
-
<div style="width: ${state6.columnWidths.status}px; padding: 0 6px; text-align: center; flex-shrink: 0; display: flex; align-items: center; justify-content: center; gap: 2px;">
|
|
86370
|
+
<div ${copyAttr(connStatus ?? "")} style="width: ${state6.columnWidths.status}px; padding: 0 6px; text-align: center; flex-shrink: 0; display: flex; align-items: center; justify-content: center; gap: 2px; cursor: pointer;">
|
|
85994
86371
|
${renderStatusValue()}
|
|
85995
86372
|
</div>
|
|
85996
|
-
<div style="width: 24px; flex-shrink: 0; text-align: center;">
|
|
86373
|
+
<div style="width: 24px; flex-shrink: 0; text-align: center; cursor: pointer;" title="Clique para selecionar o dispositivo">
|
|
85997
86374
|
${isSelected ? `<span style="color: ${colors2.success}; font-size: 14px;">\u2713</span>` : ""}
|
|
85998
86375
|
</div>
|
|
85999
86376
|
</div>
|
|
@@ -86375,7 +86752,11 @@ function renderLojasStep3(state6, modalId, colors2, t) {
|
|
|
86375
86752
|
<span>Profile alvo: <strong style="color: ${colors2.text};">3F_MEDIDOR</strong></span>
|
|
86376
86753
|
<span>deviceType: <strong style="color: ${colors2.text};">3F_MEDIDOR</strong></span>
|
|
86377
86754
|
<span>deviceProfile: <strong style="color: ${colors2.text};">3F_MEDIDOR</strong></span>
|
|
86378
|
-
<
|
|
86755
|
+
<label style="display: flex; align-items: center; gap: 6px; cursor: pointer;"
|
|
86756
|
+
title="Marcado: for\xE7a a rela\xE7\xE3o Customer \u2192 Device. Desmarcado: n\xE3o altera rela\xE7\xF5es.">
|
|
86757
|
+
<input type="checkbox" id="${modalId}-lojas-apply-relation" ${state6.lojasApplyRelation ? "checked" : ""} style="accent-color: ${MYIO_PURPLE}; cursor: pointer;" />
|
|
86758
|
+
<span>Rela\xE7\xE3o: <strong style="color: ${colors2.text};">CUSTOMER \u2192 DEVICE (Contains)</strong></span>
|
|
86759
|
+
</label>
|
|
86379
86760
|
</div>
|
|
86380
86761
|
</div>
|
|
86381
86762
|
`;
|
|
@@ -86939,6 +87320,8 @@ async function openClearGcdrIdsModal(state6) {
|
|
|
86939
87320
|
}
|
|
86940
87321
|
}
|
|
86941
87322
|
function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
87323
|
+
if (container.dataset.upsellListenersBound === "true") return;
|
|
87324
|
+
container.dataset.upsellListenersBound = "true";
|
|
86942
87325
|
const closeHandler = () => closeModal(container, onClose);
|
|
86943
87326
|
const overlay = container.querySelector(".myio-upsell-modal-overlay");
|
|
86944
87327
|
if (overlay) {
|
|
@@ -87054,10 +87437,18 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87054
87437
|
});
|
|
87055
87438
|
});
|
|
87056
87439
|
});
|
|
87440
|
+
container.querySelectorAll(".myio-copy-cell").forEach((cell) => {
|
|
87441
|
+
cell.addEventListener("click", (e) => {
|
|
87442
|
+
e.stopPropagation();
|
|
87443
|
+
const target = e.target;
|
|
87444
|
+
if (target.closest("button, input, .myio-info-btn, .myio-ts-btn")) return;
|
|
87445
|
+
copyCellValue(decodeURIComponent(cell.dataset.copy || ""), cell);
|
|
87446
|
+
});
|
|
87447
|
+
});
|
|
87057
87448
|
document.getElementById(`${modalId}-device-search`)?.addEventListener("input", (e) => {
|
|
87058
87449
|
const search = e.target.value.toLowerCase();
|
|
87059
87450
|
state6.deviceSearchTerm = e.target.value;
|
|
87060
|
-
filterDeviceListVisual(container, state6.devices, search, state6.deviceFilters, state6.deviceSort);
|
|
87451
|
+
filterDeviceListVisual(container, state6.devices, search, state6.deviceFilters, state6.deviceSort, state6);
|
|
87061
87452
|
});
|
|
87062
87453
|
document.getElementById(`${modalId}-device-type-filter`)?.addEventListener("change", (e) => {
|
|
87063
87454
|
const select = e.target;
|
|
@@ -87279,15 +87670,17 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87279
87670
|
renderModal4(container, state6, modalId, t);
|
|
87280
87671
|
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
87281
87672
|
});
|
|
87282
|
-
document.getElementById(`${modalId}-check-fix`)?.addEventListener("click",
|
|
87673
|
+
document.getElementById(`${modalId}-check-fix`)?.addEventListener("click", () => {
|
|
87283
87674
|
if (state6.checkFixLoading) return;
|
|
87284
|
-
state6
|
|
87285
|
-
|
|
87286
|
-
|
|
87287
|
-
|
|
87288
|
-
|
|
87289
|
-
|
|
87290
|
-
|
|
87675
|
+
openCheckFixScopeDialog(state6, async (scopeDevices) => {
|
|
87676
|
+
state6.checkFixLoading = true;
|
|
87677
|
+
renderModal4(container, state6, modalId, t);
|
|
87678
|
+
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
87679
|
+
await runCheckFixRoutine(state6, container, modalId, t, onClose, scopeDevices);
|
|
87680
|
+
state6.checkFixLoading = false;
|
|
87681
|
+
renderModal4(container, state6, modalId, t);
|
|
87682
|
+
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
87683
|
+
});
|
|
87291
87684
|
});
|
|
87292
87685
|
document.getElementById(`${modalId}-checkfix-filter`)?.addEventListener("change", (e) => {
|
|
87293
87686
|
state6.checkFixFilter = e.target.value;
|
|
@@ -87385,35 +87778,7 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87385
87778
|
}
|
|
87386
87779
|
});
|
|
87387
87780
|
document.getElementById(`${modalId}-select-all`)?.addEventListener("click", () => {
|
|
87388
|
-
|
|
87389
|
-
types: filterTypes,
|
|
87390
|
-
deviceTypes: filterDeviceTypes,
|
|
87391
|
-
deviceProfiles: filterDeviceProfiles,
|
|
87392
|
-
statuses: filterStatuses,
|
|
87393
|
-
telemetryKeys: filterTelemetryKeys
|
|
87394
|
-
} = state6.deviceFilters;
|
|
87395
|
-
let filteredDevices = state6.devices.filter((d) => {
|
|
87396
|
-
if (filterTypes.length > 0 && !filterTypes.includes(d.type || "")) return false;
|
|
87397
|
-
if (filterDeviceTypes.length > 0 && !filterDeviceTypes.includes(d.serverAttrs?.deviceType || ""))
|
|
87398
|
-
return false;
|
|
87399
|
-
if (filterDeviceProfiles.length > 0 && !filterDeviceProfiles.includes(d.serverAttrs?.deviceProfile || ""))
|
|
87400
|
-
return false;
|
|
87401
|
-
if (filterStatuses.length > 0) {
|
|
87402
|
-
const status = d.latestTelemetry?.connectionStatus?.value || "offline";
|
|
87403
|
-
if (!filterStatuses.includes(status)) return false;
|
|
87404
|
-
}
|
|
87405
|
-
if (filterTelemetryKeys.length > 0) {
|
|
87406
|
-
const telem = d.latestTelemetry;
|
|
87407
|
-
const hasMatch = filterTelemetryKeys.some((k) => {
|
|
87408
|
-
if (k === "pulses") return telem?.pulses != null;
|
|
87409
|
-
if (k === "consumption") return telem?.consumption != null;
|
|
87410
|
-
return false;
|
|
87411
|
-
});
|
|
87412
|
-
if (!hasMatch) return false;
|
|
87413
|
-
}
|
|
87414
|
-
return true;
|
|
87415
|
-
});
|
|
87416
|
-
state6.selectedDevices = [...filteredDevices];
|
|
87781
|
+
state6.selectedDevices = [...getGridVisibleDevices(state6)];
|
|
87417
87782
|
const listEl = document.getElementById(`${modalId}-device-list`);
|
|
87418
87783
|
const savedScroll = listEl ? listEl.scrollTop : 0;
|
|
87419
87784
|
renderModal4(container, state6, modalId, t);
|
|
@@ -87529,12 +87894,27 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87529
87894
|
document.getElementById(`${modalId}-bulk-profile-save`)?.addEventListener("click", async () => {
|
|
87530
87895
|
await saveBulkProfile(state6, container, modalId, t, onClose);
|
|
87531
87896
|
});
|
|
87532
|
-
document.getElementById(`${modalId}-bulk-owner`)?.addEventListener("click", () => {
|
|
87897
|
+
document.getElementById(`${modalId}-bulk-owner`)?.addEventListener("click", async () => {
|
|
87533
87898
|
if (!state6.selectedCustomer) {
|
|
87534
87899
|
alert("Selecione um Customer primeiro no Step 1");
|
|
87535
87900
|
return;
|
|
87536
87901
|
}
|
|
87537
87902
|
state6.bulkOwnerModal.open = true;
|
|
87903
|
+
if (!state6.bulkOwnerModal.targetCustomerId) {
|
|
87904
|
+
state6.bulkOwnerModal.targetCustomerId = state6.selectedCustomer.id?.id || "";
|
|
87905
|
+
}
|
|
87906
|
+
renderModal4(container, state6, modalId, t);
|
|
87907
|
+
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
87908
|
+
if (state6.customers.length === 0) {
|
|
87909
|
+
await loadCustomers(state6, container, modalId, t, onClose);
|
|
87910
|
+
if (state6.bulkOwnerModal.open) {
|
|
87911
|
+
renderModal4(container, state6, modalId, t);
|
|
87912
|
+
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
87913
|
+
}
|
|
87914
|
+
}
|
|
87915
|
+
});
|
|
87916
|
+
document.getElementById(`${modalId}-bulk-owner-customer`)?.addEventListener("change", (e) => {
|
|
87917
|
+
state6.bulkOwnerModal.targetCustomerId = e.target.value;
|
|
87538
87918
|
renderModal4(container, state6, modalId, t);
|
|
87539
87919
|
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
87540
87920
|
});
|
|
@@ -87579,6 +87959,10 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87579
87959
|
if (!state6.selectedCustomer || state6.selectedDevices.length === 0) return;
|
|
87580
87960
|
await handleBulkSyncIngestionId(state6, container, modalId, t, onClose);
|
|
87581
87961
|
});
|
|
87962
|
+
document.getElementById(`${modalId}-bulk-delete`)?.addEventListener("click", async () => {
|
|
87963
|
+
if (state6.selectedDevices.length === 0) return;
|
|
87964
|
+
await handleBulkDeleteDevices(state6, container, modalId, t, onClose);
|
|
87965
|
+
});
|
|
87582
87966
|
document.getElementById(`${modalId}-clear-gcdr-ids`)?.addEventListener("click", () => {
|
|
87583
87967
|
if (!state6.selectedCustomer) {
|
|
87584
87968
|
alert("Selecione um Customer primeiro no Step 1");
|
|
@@ -87708,6 +88092,14 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87708
88092
|
});
|
|
87709
88093
|
}
|
|
87710
88094
|
});
|
|
88095
|
+
const applyRelCb = document.getElementById(
|
|
88096
|
+
`${modalId}-lojas-apply-relation`
|
|
88097
|
+
);
|
|
88098
|
+
if (applyRelCb) {
|
|
88099
|
+
applyRelCb.addEventListener("change", () => {
|
|
88100
|
+
state6.lojasApplyRelation = applyRelCb.checked;
|
|
88101
|
+
});
|
|
88102
|
+
}
|
|
87711
88103
|
}
|
|
87712
88104
|
document.getElementById(`${modalId}-change-owner`)?.addEventListener("click", () => {
|
|
87713
88105
|
const form = document.getElementById(`${modalId}-change-owner-form`);
|
|
@@ -87929,7 +88321,8 @@ Total de devices no customer: ${ingestionDevices.length}`
|
|
|
87929
88321
|
state6.devices,
|
|
87930
88322
|
state6.deviceSearchTerm.toLowerCase(),
|
|
87931
88323
|
state6.deviceFilters,
|
|
87932
|
-
state6.deviceSort
|
|
88324
|
+
state6.deviceSort,
|
|
88325
|
+
state6
|
|
87933
88326
|
);
|
|
87934
88327
|
}
|
|
87935
88328
|
}
|
|
@@ -88069,7 +88462,7 @@ function filterCustomerList(container, customers, search, selected, sort) {
|
|
|
88069
88462
|
item.style.display = matches ? "flex" : "none";
|
|
88070
88463
|
});
|
|
88071
88464
|
}
|
|
88072
|
-
function filterDeviceListVisual(container, devices, search, filters, sort) {
|
|
88465
|
+
function filterDeviceListVisual(container, devices, search, filters, sort, state6) {
|
|
88073
88466
|
const listContainer = container.querySelector('[id$="-device-list"]');
|
|
88074
88467
|
if (!listContainer) return;
|
|
88075
88468
|
let filtered = devices.filter((d) => {
|
|
@@ -88089,7 +88482,7 @@ function filterDeviceListVisual(container, devices, search, filters, sort) {
|
|
|
88089
88482
|
item.style.display = "none";
|
|
88090
88483
|
return;
|
|
88091
88484
|
}
|
|
88092
|
-
const matchesSearch = !search ||
|
|
88485
|
+
const matchesSearch = !search || buildDeviceSearchHaystack(device, state6).includes(search);
|
|
88093
88486
|
const el2 = item;
|
|
88094
88487
|
const isTableRow = el2.tagName === "TR";
|
|
88095
88488
|
el2.style.display = matchesSearch ? isTableRow ? "" : "flex" : "none";
|
|
@@ -88440,6 +88833,56 @@ async function loadLojasData(state6, container, modalId, t, onClose) {
|
|
|
88440
88833
|
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
88441
88834
|
}
|
|
88442
88835
|
}
|
|
88836
|
+
async function handleBulkDeleteDevices(state6, container, modalId, t, onClose) {
|
|
88837
|
+
const devices = [...state6.selectedDevices];
|
|
88838
|
+
if (devices.length === 0) return;
|
|
88839
|
+
const preview = devices.slice(0, 8).map((d) => `\u2022 ${d.name || d.label || getEntityId(d)}`).join("\n");
|
|
88840
|
+
const more = devices.length > 8 ? `
|
|
88841
|
+
\u2026 e mais ${devices.length - 8}` : "";
|
|
88842
|
+
const confirm1 = `\u26A0\uFE0F DELETAR ${devices.length} dispositivo(s) do ThingsBoard?
|
|
88843
|
+
|
|
88844
|
+
${preview}${more}
|
|
88845
|
+
|
|
88846
|
+
Esta a\xE7\xE3o \xE9 IRREVERS\xCDVEL \u2014 os dispositivos, suas rela\xE7\xF5es e telemetria ser\xE3o removidos permanentemente.`;
|
|
88847
|
+
if (!confirm(confirm1)) return;
|
|
88848
|
+
if (!confirm(
|
|
88849
|
+
`Confirma\xE7\xE3o final: deletar ${devices.length} dispositivo(s)?
|
|
88850
|
+
Esta a\xE7\xE3o N\xC3O pode ser desfeita.`
|
|
88851
|
+
))
|
|
88852
|
+
return;
|
|
88853
|
+
showBusyProgress(`Deletando ${devices.length} dispositivos...`, devices.length);
|
|
88854
|
+
let okCount = 0;
|
|
88855
|
+
let failCount = 0;
|
|
88856
|
+
const errors = [];
|
|
88857
|
+
const deletedIds = /* @__PURE__ */ new Set();
|
|
88858
|
+
for (let i = 0; i < devices.length; i++) {
|
|
88859
|
+
const d = devices[i];
|
|
88860
|
+
const id = getEntityId(d);
|
|
88861
|
+
try {
|
|
88862
|
+
await tbDelete(state6, `/api/device/${id}`);
|
|
88863
|
+
deletedIds.add(id);
|
|
88864
|
+
okCount++;
|
|
88865
|
+
} catch (err) {
|
|
88866
|
+
failCount++;
|
|
88867
|
+
errors.push(`${d.name || id}: ${err.message}`);
|
|
88868
|
+
}
|
|
88869
|
+
updateBusyProgress(i + 1);
|
|
88870
|
+
}
|
|
88871
|
+
hideBusyProgress();
|
|
88872
|
+
state6.devices = state6.devices.filter((d) => !deletedIds.has(getEntityId(d)));
|
|
88873
|
+
state6.selectedDevices = state6.selectedDevices.filter((d) => !deletedIds.has(getEntityId(d)));
|
|
88874
|
+
if (state6.selectedDevice && deletedIds.has(getEntityId(state6.selectedDevice))) {
|
|
88875
|
+
state6.selectedDevice = null;
|
|
88876
|
+
}
|
|
88877
|
+
renderModal4(container, state6, modalId, t);
|
|
88878
|
+
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
88879
|
+
alert(
|
|
88880
|
+
`Dispositivos deletados: ${okCount}` + (failCount > 0 ? `
|
|
88881
|
+
Falhas: ${failCount}
|
|
88882
|
+
${errors.slice(0, 5).join("\n")}` + (errors.length > 5 ? `
|
|
88883
|
+
\u2026 e mais ${errors.length - 5} erros` : "") : "")
|
|
88884
|
+
);
|
|
88885
|
+
}
|
|
88443
88886
|
async function handleBulkSyncIngestionId(state6, container, modalId, t, onClose) {
|
|
88444
88887
|
if (!state6.selectedCustomer || state6.selectedDevices.length === 0) return;
|
|
88445
88888
|
const customerId = getEntityId(state6.selectedCustomer);
|
|
@@ -88586,15 +89029,17 @@ async function handleLojasApply(state6, container, modalId, t, onClose) {
|
|
|
88586
89029
|
if (identifierInput) data[i].identifier = identifierInput.value;
|
|
88587
89030
|
}
|
|
88588
89031
|
const activeConfig = state6.lojasConfig ?? CUSTOM_MODES[0];
|
|
89032
|
+
const applyRelation = state6.lojasApplyRelation;
|
|
88589
89033
|
const confirmMsg = `Aplicar configura\xE7\xE3o "${activeConfig.label}" para ${data.length} dispositivos?
|
|
88590
89034
|
|
|
88591
89035
|
Cada device receber\xE1:
|
|
88592
89036
|
- Label atualizado (etiqueta)
|
|
88593
89037
|
- Profile: ${activeConfig.deviceProfile}
|
|
88594
89038
|
- deviceType/deviceProfile: ${activeConfig.deviceType} / ${activeConfig.deviceProfile}
|
|
88595
|
-
|
|
89039
|
+
` + (applyRelation ? `- Rela\xE7\xF5es existentes removidas
|
|
88596
89040
|
- Nova rela\xE7\xE3o: Customer \u2192 Device (Contains)
|
|
88597
|
-
|
|
89041
|
+
` : `- Rela\xE7\xF5es N\xC3O ser\xE3o alteradas (checkbox de rela\xE7\xE3o desmarcado)
|
|
89042
|
+
`) + `
|
|
88598
89043
|
Deseja continuar?`;
|
|
88599
89044
|
if (!confirm(confirmMsg)) return;
|
|
88600
89045
|
showBusyProgress(`Aplicando ${activeConfig.label}...`, data.length);
|
|
@@ -88622,31 +89067,33 @@ Deseja continuar?`;
|
|
|
88622
89067
|
attrs.ingestionId = d.ingestionId;
|
|
88623
89068
|
}
|
|
88624
89069
|
await tbPost(state6, `/api/plugins/telemetry/DEVICE/${d.deviceId}/attributes/SERVER_SCOPE`, attrs);
|
|
88625
|
-
if (
|
|
88626
|
-
|
|
88627
|
-
|
|
88628
|
-
|
|
88629
|
-
|
|
88630
|
-
|
|
88631
|
-
|
|
88632
|
-
|
|
88633
|
-
|
|
88634
|
-
|
|
88635
|
-
|
|
88636
|
-
|
|
88637
|
-
|
|
88638
|
-
|
|
88639
|
-
|
|
89070
|
+
if (applyRelation) {
|
|
89071
|
+
if (d.currentRelations.length > 0) {
|
|
89072
|
+
updateBusyProgress(i + 1, `[${i + 1}/${data.length}] ${d.name}: Removendo rela\xE7\xF5es...`);
|
|
89073
|
+
for (const rel of d.currentRelations) {
|
|
89074
|
+
try {
|
|
89075
|
+
const params = new URLSearchParams({
|
|
89076
|
+
fromId: rel.from.id,
|
|
89077
|
+
fromType: rel.from.entityType,
|
|
89078
|
+
toId: d.deviceId,
|
|
89079
|
+
toType: "DEVICE",
|
|
89080
|
+
relationType: rel.type || "Contains",
|
|
89081
|
+
relationTypeGroup: rel.typeGroup || "COMMON"
|
|
89082
|
+
});
|
|
89083
|
+
await tbDelete(state6, `/api/relation?${params.toString()}`);
|
|
89084
|
+
} catch (e) {
|
|
89085
|
+
console.warn("[UpsellModal] Error deleting relation for LOJAS:", e);
|
|
89086
|
+
}
|
|
88640
89087
|
}
|
|
88641
89088
|
}
|
|
89089
|
+
updateBusyProgress(i + 1, `[${i + 1}/${data.length}] ${d.name}: Criando rela\xE7\xE3o...`);
|
|
89090
|
+
await tbPost(state6, "/api/relation", {
|
|
89091
|
+
from: { entityType: "CUSTOMER", id: customerId },
|
|
89092
|
+
to: { entityType: "DEVICE", id: d.deviceId },
|
|
89093
|
+
type: "Contains",
|
|
89094
|
+
typeGroup: "COMMON"
|
|
89095
|
+
});
|
|
88642
89096
|
}
|
|
88643
|
-
updateBusyProgress(i + 1, `[${i + 1}/${data.length}] ${d.name}: Criando rela\xE7\xE3o...`);
|
|
88644
|
-
await tbPost(state6, "/api/relation", {
|
|
88645
|
-
from: { entityType: "CUSTOMER", id: customerId },
|
|
88646
|
-
to: { entityType: "DEVICE", id: d.deviceId },
|
|
88647
|
-
type: "Contains",
|
|
88648
|
-
typeGroup: "COMMON"
|
|
88649
|
-
});
|
|
88650
89097
|
successCount++;
|
|
88651
89098
|
} catch (error) {
|
|
88652
89099
|
errorCount++;
|
|
@@ -88934,8 +89381,111 @@ async function loadDeviceTelemetryInBatch(state6, container, modalId, t, onClose
|
|
|
88934
89381
|
hideBusyProgress();
|
|
88935
89382
|
}
|
|
88936
89383
|
}
|
|
88937
|
-
|
|
88938
|
-
const
|
|
89384
|
+
function openCheckFixScopeDialog(state6, onConfirm) {
|
|
89385
|
+
const DIALOG_ID = "myio-upsell-cf-scope-dialog";
|
|
89386
|
+
document.getElementById(DIALOG_ID)?.remove();
|
|
89387
|
+
const c = getThemeColors5(state6.theme);
|
|
89388
|
+
const allDevices = state6.devices;
|
|
89389
|
+
const allTypes = [...new Set(allDevices.map((d) => d.type).filter(Boolean))].sort();
|
|
89390
|
+
let namePattern = "";
|
|
89391
|
+
let caseSensitive = false;
|
|
89392
|
+
const selectedTypes = /* @__PURE__ */ new Set();
|
|
89393
|
+
function computeSubset() {
|
|
89394
|
+
let result = allDevices;
|
|
89395
|
+
if (namePattern) {
|
|
89396
|
+
const pat = caseSensitive ? namePattern : namePattern.toLowerCase();
|
|
89397
|
+
result = result.filter((d) => {
|
|
89398
|
+
const n = caseSensitive ? d.name || "" : (d.name || "").toLowerCase();
|
|
89399
|
+
return n.includes(pat);
|
|
89400
|
+
});
|
|
89401
|
+
}
|
|
89402
|
+
if (selectedTypes.size > 0) {
|
|
89403
|
+
result = result.filter((d) => selectedTypes.has(d.type || ""));
|
|
89404
|
+
}
|
|
89405
|
+
return result;
|
|
89406
|
+
}
|
|
89407
|
+
const overlay = document.createElement("div");
|
|
89408
|
+
overlay.id = DIALOG_ID;
|
|
89409
|
+
overlay.style.cssText = "position:fixed;inset:0;z-index:10000;background:rgba(0,0,0,0.55);display:flex;align-items:center;justify-content:center;font-family:Roboto,Inter,system-ui,sans-serif;";
|
|
89410
|
+
overlay.innerHTML = `
|
|
89411
|
+
<div style="background:${c.surface};border-radius:12px;width:480px;max-width:92vw;max-height:88vh;
|
|
89412
|
+
overflow:hidden;display:flex;flex-direction:column;box-shadow:0 12px 40px rgba(0,0,0,0.4);">
|
|
89413
|
+
<div style="background:${MYIO_PURPLE};color:#fff;padding:12px 16px;font-size:14px;font-weight:700;">
|
|
89414
|
+
\u{1F52C} Escopo do CHECK & FIX
|
|
89415
|
+
</div>
|
|
89416
|
+
<div style="padding:16px;overflow-y:auto;display:flex;flex-direction:column;gap:14px;">
|
|
89417
|
+
<div style="font-size:11px;color:${c.textMuted};">
|
|
89418
|
+
Os filtros abaixo se <strong>combinam (E)</strong>. Deixe ambos vazios para
|
|
89419
|
+
diagnosticar todos os ${allDevices.length} dispositivos.
|
|
89420
|
+
</div>
|
|
89421
|
+
|
|
89422
|
+
<div style="display:flex;flex-direction:column;gap:8px;">
|
|
89423
|
+
<span style="font-size:12px;font-weight:600;color:${c.text};">Filtro por nome</span>
|
|
89424
|
+
<input id="cf-scope-name-input" type="text" placeholder="nome cont\xE9m\u2026 (ex.: TEMP.)" style="
|
|
89425
|
+
font-size:12px;padding:7px 9px;border-radius:6px;border:1px solid ${c.border};
|
|
89426
|
+
background:${c.inputBg};color:${c.text};" />
|
|
89427
|
+
<label style="display:flex;gap:6px;align-items:center;font-size:11px;color:${c.textMuted};cursor:pointer;">
|
|
89428
|
+
<input id="cf-scope-case" type="checkbox" style="accent-color:${MYIO_PURPLE};" />
|
|
89429
|
+
Diferenciar mai\xFAsculas/min\xFAsculas (case-sensitive)
|
|
89430
|
+
</label>
|
|
89431
|
+
</div>
|
|
89432
|
+
|
|
89433
|
+
<div style="display:flex;flex-direction:column;gap:8px;">
|
|
89434
|
+
<span style="font-size:12px;font-weight:600;color:${c.text};">Filtro por tipo (device.type)</span>
|
|
89435
|
+
<div style="display:flex;flex-wrap:wrap;gap:6px;max-height:160px;overflow-y:auto;">
|
|
89436
|
+
${allTypes.length === 0 ? `<span style="font-size:11px;color:${c.textMuted};">Nenhum tipo dispon\xEDvel.</span>` : allTypes.map(
|
|
89437
|
+
(tp) => `
|
|
89438
|
+
<label style="display:flex;gap:5px;align-items:center;font-size:11px;color:${c.text};
|
|
89439
|
+
cursor:pointer;border:1px solid ${c.border};border-radius:6px;padding:3px 8px;background:${c.cardBg};">
|
|
89440
|
+
<input type="checkbox" class="cf-scope-type-cb" value="${tp}" style="accent-color:${MYIO_PURPLE};" />
|
|
89441
|
+
${tp}
|
|
89442
|
+
</label>`
|
|
89443
|
+
).join("")}
|
|
89444
|
+
</div>
|
|
89445
|
+
</div>
|
|
89446
|
+
</div>
|
|
89447
|
+
<div style="padding:12px 16px;border-top:1px solid ${c.border};display:flex;justify-content:flex-end;gap:8px;">
|
|
89448
|
+
<button id="cf-scope-cancel" style="font-size:12px;font-weight:600;padding:8px 14px;border-radius:6px;
|
|
89449
|
+
border:1px solid ${c.border};background:${c.cardBg};color:${c.text};cursor:pointer;">Cancelar</button>
|
|
89450
|
+
<button id="cf-scope-run" style="font-size:12px;font-weight:700;padding:8px 14px;border-radius:6px;
|
|
89451
|
+
border:none;background:${MYIO_PURPLE};color:#fff;cursor:pointer;">Executar diagn\xF3stico (${allDevices.length})</button>
|
|
89452
|
+
</div>
|
|
89453
|
+
</div>`;
|
|
89454
|
+
document.body.appendChild(overlay);
|
|
89455
|
+
const runBtn = overlay.querySelector("#cf-scope-run");
|
|
89456
|
+
function refresh() {
|
|
89457
|
+
const n = computeSubset().length;
|
|
89458
|
+
runBtn.textContent = `Executar diagn\xF3stico (${n})`;
|
|
89459
|
+
runBtn.disabled = n === 0;
|
|
89460
|
+
runBtn.style.opacity = n === 0 ? "0.5" : "1";
|
|
89461
|
+
runBtn.style.cursor = n === 0 ? "not-allowed" : "pointer";
|
|
89462
|
+
}
|
|
89463
|
+
overlay.querySelector("#cf-scope-name-input").addEventListener("input", (e) => {
|
|
89464
|
+
namePattern = e.target.value;
|
|
89465
|
+
refresh();
|
|
89466
|
+
});
|
|
89467
|
+
overlay.querySelector("#cf-scope-case").addEventListener("change", (e) => {
|
|
89468
|
+
caseSensitive = e.target.checked;
|
|
89469
|
+
refresh();
|
|
89470
|
+
});
|
|
89471
|
+
overlay.querySelectorAll(".cf-scope-type-cb").forEach((cb) => {
|
|
89472
|
+
cb.addEventListener("change", () => {
|
|
89473
|
+
if (cb.checked) selectedTypes.add(cb.value);
|
|
89474
|
+
else selectedTypes.delete(cb.value);
|
|
89475
|
+
refresh();
|
|
89476
|
+
});
|
|
89477
|
+
});
|
|
89478
|
+
overlay.querySelector("#cf-scope-cancel").addEventListener("click", () => overlay.remove());
|
|
89479
|
+
runBtn.addEventListener("click", () => {
|
|
89480
|
+
const subset = computeSubset();
|
|
89481
|
+
if (subset.length === 0) return;
|
|
89482
|
+
overlay.remove();
|
|
89483
|
+
onConfirm(subset);
|
|
89484
|
+
});
|
|
89485
|
+
refresh();
|
|
89486
|
+
}
|
|
89487
|
+
async function runCheckFixRoutine(state6, container, modalId, t, onClose, scopeDevices) {
|
|
89488
|
+
const devices = scopeDevices ?? state6.devices;
|
|
88939
89489
|
if (devices.length === 0) return;
|
|
88940
89490
|
const BATCH_SIZE = 5;
|
|
88941
89491
|
const BATCH_DELAY_MS = 1500;
|
|
@@ -89218,10 +89768,11 @@ ${errors.slice(0, 5).join("\n")}` + (errors.length > 5 ? `
|
|
|
89218
89768
|
}
|
|
89219
89769
|
async function saveBulkOwner(state6, container, modalId, t, onClose) {
|
|
89220
89770
|
const devices = state6.selectedDevices;
|
|
89221
|
-
const newCustomerId = state6.selectedCustomer?.id?.id;
|
|
89222
|
-
const
|
|
89771
|
+
const newCustomerId = state6.bulkOwnerModal.targetCustomerId || state6.selectedCustomer?.id?.id;
|
|
89772
|
+
const targetCustomer = state6.customers.find((c) => c.id?.id === newCustomerId) || state6.selectedCustomer;
|
|
89773
|
+
const customerName = targetCustomer?.name || targetCustomer?.title || "Unknown";
|
|
89223
89774
|
if (!newCustomerId) {
|
|
89224
|
-
alert("Por favor, selecione um Customer
|
|
89775
|
+
alert("Por favor, selecione um Customer de destino.");
|
|
89225
89776
|
return;
|
|
89226
89777
|
}
|
|
89227
89778
|
if (devices.length === 0) {
|