myio-js-library 0.1.501 → 0.1.503
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 +734 -184
- package/dist/index.d.cts +52 -1
- package/dist/index.js +733 -184
- package/dist/myio-js-library.umd.js +733 -143
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -583,6 +583,7 @@ __export(index_exports, {
|
|
|
583
583
|
CONSUMPTION_CHART_DEFAULTS: () => DEFAULT_CONFIG,
|
|
584
584
|
CONSUMPTION_THEME_COLORS: () => THEME_COLORS,
|
|
585
585
|
CardGridPanel: () => CardGridPanel,
|
|
586
|
+
ColumnSummaryTooltip: () => ColumnSummaryTooltip,
|
|
586
587
|
ConnectionStatusType: () => ConnectionStatusType,
|
|
587
588
|
ContractSummaryTooltip: () => ContractSummaryTooltip,
|
|
588
589
|
CustomerCardV1: () => CustomerCardV1,
|
|
@@ -1162,7 +1163,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
1162
1163
|
// package.json
|
|
1163
1164
|
var package_default = {
|
|
1164
1165
|
name: "myio-js-library",
|
|
1165
|
-
version: "0.1.
|
|
1166
|
+
version: "0.1.503",
|
|
1166
1167
|
description: "A clean, standalone JS SDK for MYIO projects",
|
|
1167
1168
|
license: "MIT",
|
|
1168
1169
|
repository: "github:gh-myio/myio-js-library",
|
|
@@ -27305,8 +27306,8 @@ var EnergyDataFetcher = class {
|
|
|
27305
27306
|
// src/components/premium-modals/internal/engines/CsvExporter.ts
|
|
27306
27307
|
var toCsv = (rows, locale = "pt-BR", sep = ";") => {
|
|
27307
27308
|
const fmt2 = new Intl.NumberFormat(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
27308
|
-
const
|
|
27309
|
-
return rows.map((r) => r.map((c) => `"${
|
|
27309
|
+
const esc4 = (v) => (typeof v === "number" ? fmt2.format(v) : String(v)).replace(/"/g, '""');
|
|
27310
|
+
return rows.map((r) => r.map((c) => `"${esc4(c)}"`).join(sep)).join("\r\n");
|
|
27310
27311
|
};
|
|
27311
27312
|
|
|
27312
27313
|
// src/utils/telemetryUtils.ts
|
|
@@ -32992,6 +32993,13 @@ var AllReportModal = class {
|
|
|
32992
32993
|
domainConfig;
|
|
32993
32994
|
// Granularity: '1d' (daily) | '1h' (hourly)
|
|
32994
32995
|
granularity = "1d";
|
|
32996
|
+
// When true, devices flagged via `exclude_groups_totals` for this group are dropped
|
|
32997
|
+
// from the report so its total reconciles with the dashboard KPIs. Toggleable in the UI.
|
|
32998
|
+
considerExclusion = true;
|
|
32999
|
+
// Raw API response kept so the exclusion toggle can re-map without a new fetch.
|
|
33000
|
+
lastApiResponse = null;
|
|
33001
|
+
// Cleanup for the InfoTooltip attached to the exclusion-flag info icon.
|
|
33002
|
+
exclusionTooltipCleanup = null;
|
|
32995
33003
|
// Debug logging helper
|
|
32996
33004
|
debugLog(message, data) {
|
|
32997
33005
|
if (this.debugEnabled) {
|
|
@@ -33000,7 +33008,7 @@ var AllReportModal = class {
|
|
|
33000
33008
|
}
|
|
33001
33009
|
// Helper: normalize identifiers (upper, strip spaces and non-alphanum)
|
|
33002
33010
|
normalizeId(v) {
|
|
33003
|
-
return (v || "").toString().normalize("NFKC").toUpperCase().replace(/\s+/g, "").replace(/[
|
|
33011
|
+
return (v || "").toString().normalize("NFKC").toUpperCase().replace(/\s+/g, "").replace(/[0300-036f]/g, "");
|
|
33004
33012
|
}
|
|
33005
33013
|
// Helper: extract store identifier from API item
|
|
33006
33014
|
// Priority: assetName -> parse from name (last token or token after space) -> null
|
|
@@ -33069,6 +33077,10 @@ var AllReportModal = class {
|
|
|
33069
33077
|
this.dateRangePicker.destroy();
|
|
33070
33078
|
this.dateRangePicker = null;
|
|
33071
33079
|
}
|
|
33080
|
+
if (this.exclusionTooltipCleanup) {
|
|
33081
|
+
this.exclusionTooltipCleanup();
|
|
33082
|
+
this.exclusionTooltipCleanup = null;
|
|
33083
|
+
}
|
|
33072
33084
|
if (this.filterModal) {
|
|
33073
33085
|
this.filterModal.destroy();
|
|
33074
33086
|
this.filterModal = null;
|
|
@@ -33107,6 +33119,20 @@ var AllReportModal = class {
|
|
|
33107
33119
|
<button id="filter-btn" class="myio-btn myio-btn-secondary" style="background: var(--myio-brand-700); color: white;">
|
|
33108
33120
|
\u{1F50D} Filtros & Ordena\xE7\xE3o
|
|
33109
33121
|
</button>
|
|
33122
|
+
<div class="myio-form-group" style="margin-bottom: 0; display: flex; align-items: center; gap: 6px; align-self: flex-end; padding-bottom: 8px;">
|
|
33123
|
+
<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;">
|
|
33124
|
+
<input type="checkbox" id="consider-exclusion" checked style="cursor: pointer; width: 15px; height: 15px; accent-color: var(--myio-brand-700, #5b2c9d);">
|
|
33125
|
+
Considerar exclus\xE3o de totais
|
|
33126
|
+
</label>
|
|
33127
|
+
<span id="exclusion-info" aria-label="Sobre a exclus\xE3o de totais" style="
|
|
33128
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
33129
|
+
width: 16px; height: 16px; border-radius: 50%;
|
|
33130
|
+
background: var(--myio-brand-700, #5b2c9d); color: #fff;
|
|
33131
|
+
font-size: 11px; font-weight: 700; font-style: italic;
|
|
33132
|
+
font-family: Georgia, 'Times New Roman', serif; cursor: help;
|
|
33133
|
+
user-select: none;
|
|
33134
|
+
">i</span>
|
|
33135
|
+
</div>
|
|
33110
33136
|
<div class="myio-form-group" style="margin-bottom: 0; margin-left: auto;">
|
|
33111
33137
|
<label class="myio-label" for="search-input">Busca r\xE1pida</label>
|
|
33112
33138
|
<input type="text" id="search-input" class="myio-input" placeholder="Digite para filtrar..." style="width: 200px;">
|
|
@@ -33165,6 +33191,20 @@ var AllReportModal = class {
|
|
|
33165
33191
|
this.renderTable();
|
|
33166
33192
|
});
|
|
33167
33193
|
}
|
|
33194
|
+
const exclusionCheckbox = document.getElementById("consider-exclusion");
|
|
33195
|
+
exclusionCheckbox?.addEventListener("change", () => {
|
|
33196
|
+
this.considerExclusion = exclusionCheckbox.checked;
|
|
33197
|
+
this.remapAndRender();
|
|
33198
|
+
});
|
|
33199
|
+
const exclusionInfo = document.getElementById("exclusion-info");
|
|
33200
|
+
if (exclusionInfo) {
|
|
33201
|
+
this.exclusionTooltipCleanup?.();
|
|
33202
|
+
this.exclusionTooltipCleanup = InfoTooltip.attach(exclusionInfo, () => ({
|
|
33203
|
+
icon: "\u2139\uFE0F",
|
|
33204
|
+
title: "Exclus\xE3o de totais",
|
|
33205
|
+
content: this.buildExclusionTooltipContent()
|
|
33206
|
+
}));
|
|
33207
|
+
}
|
|
33168
33208
|
try {
|
|
33169
33209
|
this.dateRangePicker = await attach(dateRangeInput, {
|
|
33170
33210
|
presetStart: this.getDefaultStartDate(),
|
|
@@ -33207,6 +33247,7 @@ var AllReportModal = class {
|
|
|
33207
33247
|
const customerTotalsData = await this.fetchCustomerTotals(startISO, endISO);
|
|
33208
33248
|
this.debugLog("\u2705 API response received", customerTotalsData);
|
|
33209
33249
|
this.debugLog("\u{1F504} Processing API response...");
|
|
33250
|
+
this.lastApiResponse = customerTotalsData;
|
|
33210
33251
|
this.data = this.mapCustomerTotalsResponse(customerTotalsData);
|
|
33211
33252
|
this.debugLog("\u2705 Data mapping completed", {
|
|
33212
33253
|
mappedDataLength: this.data.length,
|
|
@@ -33426,48 +33467,6 @@ var AllReportModal = class {
|
|
|
33426
33467
|
});
|
|
33427
33468
|
}
|
|
33428
33469
|
renderPagination() {
|
|
33429
|
-
return;
|
|
33430
|
-
const container = document.getElementById("pagination-container");
|
|
33431
|
-
if (!container) return;
|
|
33432
|
-
const filteredData = this.getFilteredData();
|
|
33433
|
-
const totalPages = Math.ceil(filteredData.length / this.itemsPerPage);
|
|
33434
|
-
if (totalPages <= 1) {
|
|
33435
|
-
container.style.display = "none";
|
|
33436
|
-
return;
|
|
33437
|
-
}
|
|
33438
|
-
const startItem = (this.currentPage - 1) * this.itemsPerPage + 1;
|
|
33439
|
-
const endItem = Math.min(this.currentPage * this.itemsPerPage, filteredData.length);
|
|
33440
|
-
container.innerHTML = `
|
|
33441
|
-
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px;">
|
|
33442
|
-
<div style="color: var(--myio-text-muted);">
|
|
33443
|
-
Mostrando ${startItem}-${endItem} de ${filteredData.length} lojas
|
|
33444
|
-
</div>
|
|
33445
|
-
<div style="display: flex; gap: 8px; align-items: center;">
|
|
33446
|
-
<button id="prev-page" class="myio-btn myio-btn-outline" ${this.currentPage === 1 ? "disabled" : ""}>
|
|
33447
|
-
Anterior
|
|
33448
|
-
</button>
|
|
33449
|
-
<span style="padding: 0 12px; font-weight: bold;">
|
|
33450
|
-
${this.currentPage} / ${totalPages}
|
|
33451
|
-
</span>
|
|
33452
|
-
<button id="next-page" class="myio-btn myio-btn-outline" ${this.currentPage === totalPages ? "disabled" : ""}>
|
|
33453
|
-
Pr\xF3ximo
|
|
33454
|
-
</button>
|
|
33455
|
-
</div>
|
|
33456
|
-
</div>
|
|
33457
|
-
`;
|
|
33458
|
-
document.getElementById("prev-page")?.addEventListener("click", () => {
|
|
33459
|
-
if (this.currentPage > 1) {
|
|
33460
|
-
this.currentPage--;
|
|
33461
|
-
this.renderTable();
|
|
33462
|
-
}
|
|
33463
|
-
});
|
|
33464
|
-
document.getElementById("next-page")?.addEventListener("click", () => {
|
|
33465
|
-
if (this.currentPage < totalPages) {
|
|
33466
|
-
this.currentPage++;
|
|
33467
|
-
this.renderTable();
|
|
33468
|
-
}
|
|
33469
|
-
});
|
|
33470
|
-
container.style.display = "block";
|
|
33471
33470
|
}
|
|
33472
33471
|
calculateTotalConsumption() {
|
|
33473
33472
|
return this.data.reduce((sum, row) => sum + row.consumption, 0);
|
|
@@ -33511,7 +33510,7 @@ var AllReportModal = class {
|
|
|
33511
33510
|
}
|
|
33512
33511
|
generateStoreId(storeName) {
|
|
33513
33512
|
const name = (storeName || "SEM-ID").toString();
|
|
33514
|
-
return name.toLowerCase().replace(/\s+/g, "-").replace(/[
|
|
33513
|
+
return name.toLowerCase().replace(/\s+/g, "-").replace(/[0300-036f]/g, "");
|
|
33515
33514
|
}
|
|
33516
33515
|
applyFiltersAndSort(selectedIds, sortMode) {
|
|
33517
33516
|
this.selectedStoreIds = new Set(selectedIds);
|
|
@@ -33560,8 +33559,10 @@ var AllReportModal = class {
|
|
|
33560
33559
|
async fetchCustomerTotals(startISO, endISO) {
|
|
33561
33560
|
if (this.params.fetcher) {
|
|
33562
33561
|
const token2 = this.params.api.ingestionToken || await this.authClient.getBearer();
|
|
33562
|
+
const baseUrl2 = this.params.api.dataApiBaseUrl;
|
|
33563
|
+
if (!baseUrl2) throw new Error("dataApiBaseUrl n\xE3o configurado.");
|
|
33563
33564
|
return await this.params.fetcher({
|
|
33564
|
-
baseUrl:
|
|
33565
|
+
baseUrl: baseUrl2,
|
|
33565
33566
|
token: token2,
|
|
33566
33567
|
customerId: this.params.customerId,
|
|
33567
33568
|
startISO,
|
|
@@ -33598,6 +33599,83 @@ var AllReportModal = class {
|
|
|
33598
33599
|
this.debugLog("[AllReportModal] Customer totals response:", data);
|
|
33599
33600
|
return data;
|
|
33600
33601
|
}
|
|
33602
|
+
// Re-map the cached API response under the current exclusion flag and refresh the UI.
|
|
33603
|
+
// No-op until data has been loaded at least once.
|
|
33604
|
+
remapAndRender() {
|
|
33605
|
+
if (!this.lastApiResponse) return;
|
|
33606
|
+
this.data = this.mapCustomerTotalsResponse(this.lastApiResponse);
|
|
33607
|
+
this.selectedStoreIds = new Set(this.data.map((s) => this.generateStoreId(s.identifier)));
|
|
33608
|
+
this.currentPage = 1;
|
|
33609
|
+
this.renderSummary();
|
|
33610
|
+
this.renderTable();
|
|
33611
|
+
}
|
|
33612
|
+
// Premium tooltip content for the exclusion-flag info icon. Uses the library
|
|
33613
|
+
// InfoTooltip CSS classes (myio-info-tooltip__*) — injected by InfoTooltip itself.
|
|
33614
|
+
buildExclusionTooltipContent() {
|
|
33615
|
+
const p = "margin:0 0 8px;font-size:11px;line-height:1.5;color:#475569;";
|
|
33616
|
+
const pLast = "margin:0;font-size:11px;line-height:1.5;color:#475569;";
|
|
33617
|
+
return `
|
|
33618
|
+
<div class="myio-info-tooltip__section" style="max-width:280px;">
|
|
33619
|
+
<p style="${p}">
|
|
33620
|
+
Alguns dispositivos t\xEAm o atributo <strong>exclude_groups_totals</strong> e s\xE3o
|
|
33621
|
+
propositalmente removidos dos totais do dashboard (ex.: medidor de locat\xE1rio que
|
|
33622
|
+
n\xE3o \xE9 consumo operacional do shopping).
|
|
33623
|
+
</p>
|
|
33624
|
+
<p style="${p}">
|
|
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
|
+
</p>
|
|
33628
|
+
<p style="${pLast}">
|
|
33629
|
+
<strong>Desligado</strong>: todos os dispositivos do grupo entram \u2014 mostra o
|
|
33630
|
+
consumo bruto, inclusive os exclu\xEDdos.
|
|
33631
|
+
</p>
|
|
33632
|
+
</div>
|
|
33633
|
+
<div class="myio-info-tooltip__notice">
|
|
33634
|
+
<span class="myio-info-tooltip__notice-icon">\u{1F4A1}</span>
|
|
33635
|
+
<span>N\xE3o altera nenhum dado \u2014 apenas o que o relat\xF3rio soma e lista.</span>
|
|
33636
|
+
</div>
|
|
33637
|
+
`;
|
|
33638
|
+
}
|
|
33639
|
+
// Resolve the canonical `exclude_groups_totals.groups` key for the report's current group.
|
|
33640
|
+
// Returns null for groupings that don't map to a single exclusion key (climatizavel, etc.).
|
|
33641
|
+
resolveExclusionGroupKey(item) {
|
|
33642
|
+
const g = String(this.params.group || "").toLowerCase();
|
|
33643
|
+
if (g === "entrada" || g === "lojas" || g === "area_comum") return g;
|
|
33644
|
+
if (g === "todos") {
|
|
33645
|
+
const gl = String(item.groupLabel || "").normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().trim();
|
|
33646
|
+
if (gl === "entrada") return "entrada";
|
|
33647
|
+
if (gl === "lojas") return "lojas";
|
|
33648
|
+
if (gl === "area comum" || gl === "areacomum") return "area_comum";
|
|
33649
|
+
if (gl === "climatizacao") return "climatizacao";
|
|
33650
|
+
if (gl === "elevadores") return "elevadores";
|
|
33651
|
+
if (gl === "escadas rolantes" || gl === "esc. rolantes") return "escadas_rolantes";
|
|
33652
|
+
if (gl === "outros" || gl === "outros equipamentos") return "outros";
|
|
33653
|
+
}
|
|
33654
|
+
return null;
|
|
33655
|
+
}
|
|
33656
|
+
// Mirrors getValorEfetivo (MAIN_VIEW): a device flagged in exclude_groups_totals for the
|
|
33657
|
+
// report's group is dropped, so the report total reconciles with the dashboard KPI card.
|
|
33658
|
+
isExcludedFromTotals(item) {
|
|
33659
|
+
const raw = item.excludeGroupsTotals;
|
|
33660
|
+
if (!raw) return false;
|
|
33661
|
+
let parsed;
|
|
33662
|
+
try {
|
|
33663
|
+
parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
33664
|
+
} catch {
|
|
33665
|
+
return false;
|
|
33666
|
+
}
|
|
33667
|
+
if (!parsed || parsed.enabled !== true) return false;
|
|
33668
|
+
const key = this.resolveExclusionGroupKey(item);
|
|
33669
|
+
if (!key) return false;
|
|
33670
|
+
if (parsed.groups && typeof parsed.groups === "object") {
|
|
33671
|
+
return parsed.groups[key] === true;
|
|
33672
|
+
}
|
|
33673
|
+
if (Array.isArray(parsed.excludedGroups)) {
|
|
33674
|
+
const ex = parsed.excludedGroups.map((x) => String(x).toLowerCase());
|
|
33675
|
+
return ex.includes(key) || ex.includes("all");
|
|
33676
|
+
}
|
|
33677
|
+
return false;
|
|
33678
|
+
}
|
|
33601
33679
|
mapCustomerTotalsResponse(apiResponse) {
|
|
33602
33680
|
this.debugLog("\u{1F50D} Starting mapCustomerTotalsResponse", { apiResponse });
|
|
33603
33681
|
const apiArray = Array.isArray(apiResponse?.data) ? apiResponse.data : Array.isArray(apiResponse) ? apiResponse : [];
|
|
@@ -33635,6 +33713,10 @@ var AllReportModal = class {
|
|
|
33635
33713
|
const apiId = String(apiItem?.id || "");
|
|
33636
33714
|
if (!apiId || !orchIdSet.has(apiId)) continue;
|
|
33637
33715
|
const meta = orchMeta.get(apiId);
|
|
33716
|
+
if (this.considerExclusion && meta && this.isExcludedFromTotals(meta)) {
|
|
33717
|
+
this.debugLog("[AllReportModal] device excluded via exclude_groups_totals:", meta.label);
|
|
33718
|
+
continue;
|
|
33719
|
+
}
|
|
33638
33720
|
const consumption = Math.round(this.pickConsumption(apiItem) * 100) / 100;
|
|
33639
33721
|
const result = {
|
|
33640
33722
|
identifier: meta?.identifier || apiItem.name || apiId,
|
|
@@ -73761,6 +73843,185 @@ var WaterSummaryTooltip = {
|
|
|
73761
73843
|
}
|
|
73762
73844
|
};
|
|
73763
73845
|
|
|
73846
|
+
// src/utils/ColumnSummaryTooltip.ts
|
|
73847
|
+
var COLUMN_SUMMARY_CSS = `
|
|
73848
|
+
.myio-col-summary {
|
|
73849
|
+
max-width: 300px;
|
|
73850
|
+
font-family: 'Nunito', 'Segoe UI', system-ui, sans-serif;
|
|
73851
|
+
}
|
|
73852
|
+
.myio-col-summary__kpis {
|
|
73853
|
+
display: flex; flex-direction: column; gap: 4px;
|
|
73854
|
+
padding: 8px 10px; margin-bottom: 10px;
|
|
73855
|
+
background: #faf8ff; border: 1px solid #e3d9f3; border-radius: 8px;
|
|
73856
|
+
}
|
|
73857
|
+
.myio-col-summary__kpi {
|
|
73858
|
+
display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
|
|
73859
|
+
}
|
|
73860
|
+
.myio-col-summary__kpi-label {
|
|
73861
|
+
font-size: 10px; font-weight: 700; letter-spacing: 0.3px;
|
|
73862
|
+
text-transform: uppercase; color: #64748b;
|
|
73863
|
+
}
|
|
73864
|
+
.myio-col-summary__kpi-value {
|
|
73865
|
+
font-size: 12px; font-weight: 700; color: #1e293b; text-align: right;
|
|
73866
|
+
}
|
|
73867
|
+
.myio-col-summary__kpi-value--accent {
|
|
73868
|
+
font-size: 14px; color: #3e1a7d;
|
|
73869
|
+
}
|
|
73870
|
+
.myio-col-summary__group {
|
|
73871
|
+
display: flex; flex-direction: column; gap: 1px; margin-top: 8px;
|
|
73872
|
+
}
|
|
73873
|
+
.myio-col-summary__group-label {
|
|
73874
|
+
font-size: 10px; font-weight: 800; letter-spacing: 0.3px;
|
|
73875
|
+
text-transform: uppercase; color: #64748b; margin-bottom: 3px;
|
|
73876
|
+
}
|
|
73877
|
+
.myio-col-summary__row {
|
|
73878
|
+
display: flex; align-items: center; gap: 8px; padding: 2px 0;
|
|
73879
|
+
font-size: 11px; color: #1e293b;
|
|
73880
|
+
}
|
|
73881
|
+
.myio-col-summary__name {
|
|
73882
|
+
flex: 1 1 auto; min-width: 0;
|
|
73883
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
73884
|
+
}
|
|
73885
|
+
.myio-col-summary__val {
|
|
73886
|
+
flex: 0 0 auto; font-weight: 700; color: #16a34a; text-align: right;
|
|
73887
|
+
}
|
|
73888
|
+
.myio-col-summary__pct {
|
|
73889
|
+
flex: 0 0 auto; min-width: 44px; text-align: right;
|
|
73890
|
+
font-size: 10px; font-weight: 600; color: #64748b;
|
|
73891
|
+
}
|
|
73892
|
+
.myio-col-summary__empty {
|
|
73893
|
+
padding: 14px 0; text-align: center; font-style: italic;
|
|
73894
|
+
font-size: 11px; color: #94a3b8;
|
|
73895
|
+
}
|
|
73896
|
+
`;
|
|
73897
|
+
var _cssInjected2 = false;
|
|
73898
|
+
function injectCSS10() {
|
|
73899
|
+
if (_cssInjected2 || typeof document === "undefined") return;
|
|
73900
|
+
const STYLE_ID4 = "myio-column-summary-tooltip-css";
|
|
73901
|
+
if (document.getElementById(STYLE_ID4)) {
|
|
73902
|
+
_cssInjected2 = true;
|
|
73903
|
+
return;
|
|
73904
|
+
}
|
|
73905
|
+
const style = document.createElement("style");
|
|
73906
|
+
style.id = STYLE_ID4;
|
|
73907
|
+
style.textContent = COLUMN_SUMMARY_CSS;
|
|
73908
|
+
document.head.appendChild(style);
|
|
73909
|
+
_cssInjected2 = true;
|
|
73910
|
+
}
|
|
73911
|
+
function esc3(value) {
|
|
73912
|
+
return String(value == null ? "" : value).replace(
|
|
73913
|
+
/[&<>"]/g,
|
|
73914
|
+
(c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]
|
|
73915
|
+
);
|
|
73916
|
+
}
|
|
73917
|
+
function defaultFormatter(unit) {
|
|
73918
|
+
const nf = new Intl.NumberFormat("pt-BR", { maximumFractionDigits: 2 });
|
|
73919
|
+
return (v) => nf.format(Number(v) || 0) + (unit ? " " + unit : "");
|
|
73920
|
+
}
|
|
73921
|
+
function fmtPct(value, total) {
|
|
73922
|
+
const p = total > 0 ? (Number(value) || 0) / total * 100 : 0;
|
|
73923
|
+
return p.toFixed(1).replace(".", ",") + "%";
|
|
73924
|
+
}
|
|
73925
|
+
function buildContent(data) {
|
|
73926
|
+
const devices = Array.isArray(data.devices) ? data.devices.slice() : [];
|
|
73927
|
+
const fmt2 = data.formatValue || defaultFormatter(data.unit || "");
|
|
73928
|
+
const count = devices.length;
|
|
73929
|
+
const total = devices.reduce((s, d) => s + (Number(d.value) || 0), 0);
|
|
73930
|
+
const avg = count ? total / count : 0;
|
|
73931
|
+
const periodRow = data.periodLabel ? `<div class="myio-col-summary__kpi">
|
|
73932
|
+
<span class="myio-col-summary__kpi-label">Per\xEDodo</span>
|
|
73933
|
+
<span class="myio-col-summary__kpi-value">${esc3(data.periodLabel)}</span>
|
|
73934
|
+
</div>` : "";
|
|
73935
|
+
if (!count) {
|
|
73936
|
+
return `<div class="myio-col-summary">
|
|
73937
|
+
<div class="myio-col-summary__kpis">
|
|
73938
|
+
${periodRow}
|
|
73939
|
+
<div class="myio-col-summary__kpi">
|
|
73940
|
+
<span class="myio-col-summary__kpi-label">Dispositivos</span>
|
|
73941
|
+
<span class="myio-col-summary__kpi-value">0</span>
|
|
73942
|
+
</div>
|
|
73943
|
+
</div>
|
|
73944
|
+
<div class="myio-col-summary__empty">Nenhum dispositivo.</div>
|
|
73945
|
+
</div>`;
|
|
73946
|
+
}
|
|
73947
|
+
const desc = devices.slice().sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0));
|
|
73948
|
+
const top3 = desc.slice(0, 3);
|
|
73949
|
+
const bottom3 = desc.slice(-3).reverse();
|
|
73950
|
+
const near3 = devices.slice().sort(
|
|
73951
|
+
(a, b) => Math.abs((Number(a.value) || 0) - avg) - Math.abs((Number(b.value) || 0) - avg)
|
|
73952
|
+
).slice(0, 3);
|
|
73953
|
+
const row = (d) => `
|
|
73954
|
+
<div class="myio-col-summary__row">
|
|
73955
|
+
<span class="myio-col-summary__name" title="${esc3(d.name)}">${esc3(d.name)}</span>
|
|
73956
|
+
<span class="myio-col-summary__val">${esc3(fmt2(Number(d.value) || 0))}</span>
|
|
73957
|
+
<span class="myio-col-summary__pct">${fmtPct(Number(d.value) || 0, total)}</span>
|
|
73958
|
+
</div>`;
|
|
73959
|
+
const group = (label, list) => list.length ? `<div class="myio-col-summary__group">
|
|
73960
|
+
<span class="myio-col-summary__group-label">${label}</span>
|
|
73961
|
+
${list.map(row).join("")}
|
|
73962
|
+
</div>` : "";
|
|
73963
|
+
return `<div class="myio-col-summary">
|
|
73964
|
+
<div class="myio-col-summary__kpis">
|
|
73965
|
+
${periodRow}
|
|
73966
|
+
<div class="myio-col-summary__kpi">
|
|
73967
|
+
<span class="myio-col-summary__kpi-label">Dispositivos</span>
|
|
73968
|
+
<span class="myio-col-summary__kpi-value">${count}</span>
|
|
73969
|
+
</div>
|
|
73970
|
+
<div class="myio-col-summary__kpi">
|
|
73971
|
+
<span class="myio-col-summary__kpi-label">Consumo m\xE9dio</span>
|
|
73972
|
+
<span class="myio-col-summary__kpi-value myio-col-summary__kpi-value--accent">${esc3(
|
|
73973
|
+
fmt2(avg)
|
|
73974
|
+
)}</span>
|
|
73975
|
+
</div>
|
|
73976
|
+
<div class="myio-col-summary__kpi">
|
|
73977
|
+
<span class="myio-col-summary__kpi-label">Consumo total</span>
|
|
73978
|
+
<span class="myio-col-summary__kpi-value">${esc3(fmt2(total))}</span>
|
|
73979
|
+
</div>
|
|
73980
|
+
</div>
|
|
73981
|
+
${group("\u25B2 3 maiores", top3)}
|
|
73982
|
+
${group("\u25BC 3 menores", bottom3)}
|
|
73983
|
+
${group("\u25CF 3 na m\xE9dia", near3)}
|
|
73984
|
+
</div>`;
|
|
73985
|
+
}
|
|
73986
|
+
var ColumnSummaryTooltip = {
|
|
73987
|
+
/** Shows the column summary tooltip anchored to the trigger element. */
|
|
73988
|
+
show(triggerElement, data) {
|
|
73989
|
+
injectCSS10();
|
|
73990
|
+
InfoTooltip.show(triggerElement, {
|
|
73991
|
+
icon: "\u{1F4CA}",
|
|
73992
|
+
title: data.title ? `Resumo \u2014 ${data.title}` : "Resumo da Coluna",
|
|
73993
|
+
content: buildContent(data)
|
|
73994
|
+
});
|
|
73995
|
+
},
|
|
73996
|
+
/** Hides the tooltip immediately. */
|
|
73997
|
+
hide() {
|
|
73998
|
+
InfoTooltip.hide();
|
|
73999
|
+
},
|
|
74000
|
+
/** Starts the delayed hide (use on mouseleave). */
|
|
74001
|
+
startDelayedHide() {
|
|
74002
|
+
InfoTooltip.startDelayedHide();
|
|
74003
|
+
},
|
|
74004
|
+
/**
|
|
74005
|
+
* Attaches hover behavior to a trigger element. `getData` is called on each
|
|
74006
|
+
* hover so the summary always reflects the latest data. Returns a cleanup fn.
|
|
74007
|
+
*/
|
|
74008
|
+
attach(triggerElement, getData) {
|
|
74009
|
+
injectCSS10();
|
|
74010
|
+
const handleEnter = () => {
|
|
74011
|
+
ColumnSummaryTooltip.show(triggerElement, getData());
|
|
74012
|
+
};
|
|
74013
|
+
const handleLeave = () => {
|
|
74014
|
+
InfoTooltip.startDelayedHide();
|
|
74015
|
+
};
|
|
74016
|
+
triggerElement.addEventListener("mouseenter", handleEnter);
|
|
74017
|
+
triggerElement.addEventListener("mouseleave", handleLeave);
|
|
74018
|
+
return () => {
|
|
74019
|
+
triggerElement.removeEventListener("mouseenter", handleEnter);
|
|
74020
|
+
triggerElement.removeEventListener("mouseleave", handleLeave);
|
|
74021
|
+
};
|
|
74022
|
+
}
|
|
74023
|
+
};
|
|
74024
|
+
|
|
73764
74025
|
// src/utils/TempSensorSummaryTooltip.ts
|
|
73765
74026
|
var TEMP_SENSOR_TOOLTIP_CSS = `
|
|
73766
74027
|
/* ============================================
|
|
@@ -74251,7 +74512,7 @@ var TEMP_SENSOR_TOOLTIP_CSS = `
|
|
|
74251
74512
|
}
|
|
74252
74513
|
`;
|
|
74253
74514
|
var cssInjected9 = false;
|
|
74254
|
-
function
|
|
74515
|
+
function injectCSS11() {
|
|
74255
74516
|
if (cssInjected9) return;
|
|
74256
74517
|
if (typeof document === "undefined") return;
|
|
74257
74518
|
const styleId = "myio-temp-sensor-tooltip-styles";
|
|
@@ -74638,7 +74899,7 @@ var TempSensorSummaryTooltip = {
|
|
|
74638
74899
|
* Get or create container
|
|
74639
74900
|
*/
|
|
74640
74901
|
getContainer() {
|
|
74641
|
-
|
|
74902
|
+
injectCSS11();
|
|
74642
74903
|
let container = document.getElementById(this.containerId);
|
|
74643
74904
|
if (!container) {
|
|
74644
74905
|
container = document.createElement("div");
|
|
@@ -75232,7 +75493,7 @@ var CONTRACT_SUMMARY_TOOLTIP_CSS = `
|
|
|
75232
75493
|
}
|
|
75233
75494
|
`;
|
|
75234
75495
|
var cssInjected10 = false;
|
|
75235
|
-
function
|
|
75496
|
+
function injectCSS12() {
|
|
75236
75497
|
if (cssInjected10) return;
|
|
75237
75498
|
if (typeof document === "undefined") return;
|
|
75238
75499
|
const styleId = "myio-contract-summary-tooltip-styles";
|
|
@@ -75675,7 +75936,7 @@ var ContractSummaryTooltip = {
|
|
|
75675
75936
|
* Get or create container
|
|
75676
75937
|
*/
|
|
75677
75938
|
getContainer() {
|
|
75678
|
-
|
|
75939
|
+
injectCSS12();
|
|
75679
75940
|
let container = document.getElementById(this.containerId);
|
|
75680
75941
|
if (!container) {
|
|
75681
75942
|
container = document.createElement("div");
|
|
@@ -76161,7 +76422,7 @@ var USERS_SUMMARY_TOOLTIP_CSS = `
|
|
|
76161
76422
|
}
|
|
76162
76423
|
`;
|
|
76163
76424
|
var cssInjected11 = false;
|
|
76164
|
-
function
|
|
76425
|
+
function injectCSS13() {
|
|
76165
76426
|
if (cssInjected11) return;
|
|
76166
76427
|
if (typeof document === "undefined") return;
|
|
76167
76428
|
const styleId = "myio-users-summary-tooltip-styles";
|
|
@@ -76192,7 +76453,7 @@ var UsersSummaryTooltip = {
|
|
|
76192
76453
|
* Create or get the tooltip container
|
|
76193
76454
|
*/
|
|
76194
76455
|
getContainer() {
|
|
76195
|
-
|
|
76456
|
+
injectCSS13();
|
|
76196
76457
|
let container = document.getElementById(this.containerId);
|
|
76197
76458
|
if (!container) {
|
|
76198
76459
|
container = document.createElement("div");
|
|
@@ -76869,7 +77130,7 @@ var ALARMS_SUMMARY_TOOLTIP_CSS = `
|
|
|
76869
77130
|
}
|
|
76870
77131
|
`;
|
|
76871
77132
|
var cssInjected12 = false;
|
|
76872
|
-
function
|
|
77133
|
+
function injectCSS14() {
|
|
76873
77134
|
if (cssInjected12) return;
|
|
76874
77135
|
if (typeof document === "undefined") return;
|
|
76875
77136
|
const styleId = "myio-alarms-summary-tooltip-styles";
|
|
@@ -76900,7 +77161,7 @@ var AlarmsSummaryTooltip = {
|
|
|
76900
77161
|
* Create or get the tooltip container
|
|
76901
77162
|
*/
|
|
76902
77163
|
getContainer() {
|
|
76903
|
-
|
|
77164
|
+
injectCSS14();
|
|
76904
77165
|
let container = document.getElementById(this.containerId);
|
|
76905
77166
|
if (!container) {
|
|
76906
77167
|
container = document.createElement("div");
|
|
@@ -77315,7 +77576,7 @@ var NOTIFICATIONS_SUMMARY_TOOLTIP_CSS = `
|
|
|
77315
77576
|
}
|
|
77316
77577
|
`;
|
|
77317
77578
|
var cssInjected13 = false;
|
|
77318
|
-
function
|
|
77579
|
+
function injectCSS15() {
|
|
77319
77580
|
if (cssInjected13) return;
|
|
77320
77581
|
if (typeof document === "undefined") return;
|
|
77321
77582
|
const styleId = "myio-notifications-summary-tooltip-styles";
|
|
@@ -77346,7 +77607,7 @@ var NotificationsSummaryTooltip = {
|
|
|
77346
77607
|
* Create or get the tooltip container
|
|
77347
77608
|
*/
|
|
77348
77609
|
getContainer() {
|
|
77349
|
-
|
|
77610
|
+
injectCSS15();
|
|
77350
77611
|
let container = document.getElementById(this.containerId);
|
|
77351
77612
|
if (!container) {
|
|
77352
77613
|
container = document.createElement("div");
|
|
@@ -84311,7 +84572,7 @@ async function fetchIngestionDevicesAllPaged(customerId) {
|
|
|
84311
84572
|
function findIngestionDeviceByCentralSlaveId(devices, centralId, slaveId) {
|
|
84312
84573
|
const slaveIdNum = typeof slaveId === "string" ? parseInt(slaveId, 10) : slaveId;
|
|
84313
84574
|
for (const device of devices) {
|
|
84314
|
-
const deviceGatewayId = device.gatewayId || device.gateway?.id;
|
|
84575
|
+
const deviceGatewayId = device.gateway?.hardwareUuid || device.gatewayId || device.gateway?.id;
|
|
84315
84576
|
if (deviceGatewayId === centralId && device.slaveId === slaveIdNum) {
|
|
84316
84577
|
console.log(
|
|
84317
84578
|
"[UpsellModal] Found matching device:",
|
|
@@ -84329,8 +84590,8 @@ function findIngestionDeviceByCentralSlaveId(devices, centralId, slaveId) {
|
|
|
84329
84590
|
console.log(
|
|
84330
84591
|
`[UpsellModal] Sample device ${i}:`,
|
|
84331
84592
|
d.name,
|
|
84332
|
-
"
|
|
84333
|
-
d.gatewayId || d.gateway?.id,
|
|
84593
|
+
"gateway(hwUuid|id):",
|
|
84594
|
+
d.gateway?.hardwareUuid || d.gatewayId || d.gateway?.id,
|
|
84334
84595
|
"slaveId:",
|
|
84335
84596
|
d.slaveId
|
|
84336
84597
|
);
|
|
@@ -84515,7 +84776,7 @@ function openUpsellModal(params) {
|
|
|
84515
84776
|
selectedDevices: [],
|
|
84516
84777
|
bulkAttributeModal: { open: false, attribute: "deviceType", value: "", saving: false },
|
|
84517
84778
|
bulkProfileModal: { open: false, selectedProfileId: "", saving: false },
|
|
84518
|
-
bulkOwnerModal: { open: false, saving: false },
|
|
84779
|
+
bulkOwnerModal: { open: false, saving: false, targetCustomerId: "" },
|
|
84519
84780
|
columnWidths: {
|
|
84520
84781
|
name: 180,
|
|
84521
84782
|
label: 120,
|
|
@@ -84552,6 +84813,7 @@ function openUpsellModal(params) {
|
|
|
84552
84813
|
lojasDeviceData: [],
|
|
84553
84814
|
lojasDataLoading: false,
|
|
84554
84815
|
lojasConfig: null,
|
|
84816
|
+
lojasApplyRelation: true,
|
|
84555
84817
|
customModeModal: { open: false },
|
|
84556
84818
|
bulkRelationModal: { open: false, target: "CUSTOMER", selectedAssetId: "", selectedAssetName: "", search: "", newAssetName: "", assetsLoaded: false, overrideCustomerId: "", overrideCustomerName: "", customerSearch: "", customerPickerOpen: false },
|
|
84557
84819
|
checkFixLoading: false,
|
|
@@ -84716,6 +84978,12 @@ function renderModal4(container, state6, modalId, t, error) {
|
|
|
84716
84978
|
font-size: 14px; font-weight: 500; font-family: 'Roboto', Arial, sans-serif;
|
|
84717
84979
|
display: flex; align-items: center; gap: 6px;
|
|
84718
84980
|
" ${!state6.selectedCustomer ? 'disabled title="Selecione um Customer primeiro"' : ""}>\u{1F504} Sync Ingestion ID (${state6.selectedDevices.length})</button>
|
|
84981
|
+
<button id="${modalId}-bulk-delete" style="
|
|
84982
|
+
background: #b91c1c; color: white; border: 1px solid #7f1d1d;
|
|
84983
|
+
padding: 8px 16px; border-radius: 6px; cursor: pointer;
|
|
84984
|
+
font-size: 14px; font-weight: 600; font-family: 'Roboto', Arial, sans-serif;
|
|
84985
|
+
display: flex; align-items: center; gap: 6px;
|
|
84986
|
+
" title="Deletar permanentemente os dispositivos selecionados (irrevers\xEDvel)">\u{1F5D1}\uFE0F Deletar (${state6.selectedDevices.length})</button>
|
|
84719
84987
|
` : ""}
|
|
84720
84988
|
${state6.currentStep === 3 && state6.lojasMode ? `
|
|
84721
84989
|
<button id="${modalId}-lojas-sync" style="
|
|
@@ -84954,7 +85222,18 @@ function renderModal4(container, state6, modalId, t, error) {
|
|
|
84954
85222
|
</div>
|
|
84955
85223
|
` : ""}
|
|
84956
85224
|
|
|
84957
|
-
${state6.bulkOwnerModal.open ?
|
|
85225
|
+
${state6.bulkOwnerModal.open ? (() => {
|
|
85226
|
+
const effId = state6.bulkOwnerModal.targetCustomerId || state6.selectedCustomer?.id?.id || "";
|
|
85227
|
+
const effCustomer = state6.customers.find((c) => c.id?.id === effId) || state6.selectedCustomer;
|
|
85228
|
+
const effName = effCustomer?.name || effCustomer?.title || "N\xE3o selecionado";
|
|
85229
|
+
const customerOptions = state6.customers.length === 0 ? `<option value="${effId}">${effName}</option>` : [...state6.customers].sort(
|
|
85230
|
+
(a, b) => (a.name || a.title || "").localeCompare(b.name || b.title || "", "pt-BR")
|
|
85231
|
+
).map((c) => {
|
|
85232
|
+
const cid = c.id?.id || "";
|
|
85233
|
+
const cname = c.name || c.title || cid;
|
|
85234
|
+
return `<option value="${cid}" ${cid === effId ? "selected" : ""}>${cname}</option>`;
|
|
85235
|
+
}).join("");
|
|
85236
|
+
return `
|
|
84958
85237
|
<!-- Bulk Owner Modal -->
|
|
84959
85238
|
<div class="myio-bulk-owner-overlay" style="
|
|
84960
85239
|
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
|
|
@@ -84980,17 +85259,25 @@ function renderModal4(container, state6, modalId, t, error) {
|
|
|
84980
85259
|
<div style="font-size: 14px; color: ${colors2.text}; font-weight: 500;">${state6.selectedDevices.length} dispositivos</div>
|
|
84981
85260
|
</div>
|
|
84982
85261
|
|
|
84983
|
-
<div style="margin-bottom: 16px;
|
|
84984
|
-
<div style="font-size: 12px; color: ${colors2.textMuted}; margin-bottom:
|
|
84985
|
-
|
|
85262
|
+
<div style="margin-bottom: 16px;">
|
|
85263
|
+
<div style="font-size: 12px; color: ${colors2.textMuted}; margin-bottom: 6px;">
|
|
85264
|
+
Novo Owner (Customer):
|
|
85265
|
+
</div>
|
|
85266
|
+
<select id="${modalId}-bulk-owner-customer" style="
|
|
85267
|
+
width: 100%; padding: 9px 10px; border-radius: 8px;
|
|
85268
|
+
border: 1px solid ${colors2.border}; background: ${colors2.inputBg};
|
|
85269
|
+
color: ${colors2.text}; font-size: 13px; cursor: pointer;
|
|
85270
|
+
">
|
|
85271
|
+
${customerOptions}
|
|
85272
|
+
</select>
|
|
84986
85273
|
<div style="font-size: 11px; color: ${colors2.textMuted}; margin-top: 4px;">
|
|
84987
|
-
ID: ${
|
|
85274
|
+
ID: ${effId || "N/A"}${state6.customers.length === 0 ? " \xB7 carregando lista de clientes\u2026" : ""}
|
|
84988
85275
|
</div>
|
|
84989
85276
|
</div>
|
|
84990
85277
|
|
|
84991
85278
|
<div style="margin-bottom: 16px; padding: 12px; background: ${colors2.warning}20; border-radius: 8px; border: 1px solid ${colors2.warning}40;">
|
|
84992
85279
|
<div style="font-size: 12px; color: ${colors2.warning}; font-weight: 500;">
|
|
84993
|
-
\u26A0\uFE0F Aten\xE7\xE3o: Esta a\xE7\xE3o ir\xE1 atribuir todos os ${state6.selectedDevices.length} devices selecionados ao customer "${
|
|
85280
|
+
\u26A0\uFE0F Aten\xE7\xE3o: Esta a\xE7\xE3o ir\xE1 atribuir todos os ${state6.selectedDevices.length} devices selecionados ao customer "${effName}".
|
|
84994
85281
|
</div>
|
|
84995
85282
|
</div>
|
|
84996
85283
|
|
|
@@ -85004,13 +85291,14 @@ function renderModal4(container, state6, modalId, t, error) {
|
|
|
85004
85291
|
background: #10b981; color: white; border: none;
|
|
85005
85292
|
padding: 10px 20px; border-radius: 6px; cursor: pointer;
|
|
85006
85293
|
font-size: 14px; font-weight: 500;
|
|
85007
|
-
" ${state6.bulkOwnerModal.saving || !
|
|
85294
|
+
" ${state6.bulkOwnerModal.saving || !effId ? "disabled" : ""}>
|
|
85008
85295
|
${state6.bulkOwnerModal.saving ? "Salvando..." : "Atribuir Owner para " + state6.selectedDevices.length + " devices"}
|
|
85009
85296
|
</button>
|
|
85010
85297
|
</div>
|
|
85011
85298
|
</div>
|
|
85012
85299
|
</div>
|
|
85013
|
-
|
|
85300
|
+
`;
|
|
85301
|
+
})() : ""}
|
|
85014
85302
|
|
|
85015
85303
|
${state6.customModeModal.open ? `
|
|
85016
85304
|
<!-- CUSTOM Mode Picker Modal -->
|
|
@@ -85230,6 +85518,7 @@ function renderModal4(container, state6, modalId, t, error) {
|
|
|
85230
85518
|
`;
|
|
85231
85519
|
})() : ""}
|
|
85232
85520
|
`;
|
|
85521
|
+
delete container.dataset.upsellListenersBound;
|
|
85233
85522
|
setupEventListeners3(container, state6, modalId, t);
|
|
85234
85523
|
}
|
|
85235
85524
|
function renderStepIndicator(step, label, currentStep, colors2) {
|
|
@@ -85433,6 +85722,8 @@ function renderCheckFixRow(r, state6, modalId, colors2, dupPairIds, dupIngestion
|
|
|
85433
85722
|
};
|
|
85434
85723
|
const valStr = Object.entries(r.telemetry.values).map(([k, v]) => v != null ? `${k}:<b>${v}${unit[k] ?? ""}</b>` : null).filter(Boolean).join(" \xB7 ") || "\u2014";
|
|
85435
85724
|
const connColor = r.connStatus ? CONN_COLOR[r.connStatus] || colors2.textMuted : colors2.textMuted;
|
|
85725
|
+
const valCopy = Object.entries(r.telemetry.values).filter(([, v]) => v != null).map(([k, v]) => `${k}: ${v}${unit[k] ?? ""}`).join(" \xB7 ");
|
|
85726
|
+
const copyAttr = (v) => `class="myio-copy-cell" data-copy="${encodeURIComponent(String(v ?? ""))}"`;
|
|
85436
85727
|
return `
|
|
85437
85728
|
<tr class="myio-list-item ${isSelected ? "selected" : ""}" data-device-id="${r.deviceId}"
|
|
85438
85729
|
style="border-bottom:1px solid ${colors2.border}; cursor:pointer;">
|
|
@@ -85441,21 +85732,21 @@ function renderCheckFixRow(r, state6, modalId, colors2, dupPairIds, dupIngestion
|
|
|
85441
85732
|
<input type="checkbox" class="myio-device-checkbox" data-device-id="${r.deviceId}"
|
|
85442
85733
|
${isSelectedMulti ? "checked" : ""} style="width:14px;height:14px;cursor:pointer;accent-color:${MYIO_PURPLE};"/>
|
|
85443
85734
|
</td>` : ""}
|
|
85444
|
-
<td style="${cell()} max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${r.deviceName}">${r.deviceName}</td>
|
|
85445
|
-
<td style="${cell()} max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:${colors2.textMuted};" title="${r.deviceLabel}">${r.deviceLabel || dash}</td>
|
|
85446
|
-
<td style="${cell(typeActWrong ? "ok" : "none", true)}">${r.inferred.deviceType}</td>
|
|
85447
|
-
<td style="${cell(typeActWrong ? r.typeEqualsProfile ? "warn" : "bad" : "none", true)}" title="${typeActWrong ? `esperado: ${r.inferred.deviceType}` : ""}">${r.actual.type || dash}</td>
|
|
85448
|
-
<td style="${cell(devTypeWrong ? "ok" : "none", true)}">${r.inferred.deviceType}</td>
|
|
85449
|
-
<td style="${cell(devTypeWrong ? "bad" : "none", true)}" title="${devTypeWrong ? `esperado: ${r.inferred.deviceType}` : ""}">${r.actual.deviceType || dash}</td>
|
|
85450
|
-
<td style="${cell(devProfWrong ? "ok" : "none", true)}">${r.inferred.deviceProfile}</td>
|
|
85451
|
-
<td style="${cell(devProfWrong ? "bad" : "none", true)}" title="${devProfWrong ? `esperado: ${r.inferred.deviceProfile}` : ""}">${r.actual.deviceProfile || dash}</td>
|
|
85452
|
-
<td style="${cell()} white-space:nowrap; color:${colors2.textMuted}; font-size:9px;">${tsStr}</td>
|
|
85453
|
-
<td style="${cell()} font-size:9px;">${valStr}</td>
|
|
85454
|
-
<td style="${cell()} color:${connColor}; font-weight:600; white-space:nowrap;">${r.connStatus || dash}</td>
|
|
85455
|
-
<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>
|
|
85456
|
-
<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>
|
|
85457
|
-
<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>
|
|
85458
|
-
<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>
|
|
85735
|
+
<td ${copyAttr(r.deviceName)} style="${cell()} max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${r.deviceName}">${r.deviceName}</td>
|
|
85736
|
+
<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>
|
|
85737
|
+
<td ${copyAttr(r.inferred.deviceType)} style="${cell(typeActWrong ? "ok" : "none", true)}">${r.inferred.deviceType}</td>
|
|
85738
|
+
<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>
|
|
85739
|
+
<td ${copyAttr(r.inferred.deviceType)} style="${cell(devTypeWrong ? "ok" : "none", true)}">${r.inferred.deviceType}</td>
|
|
85740
|
+
<td ${copyAttr(r.actual.deviceType ?? "")} style="${cell(devTypeWrong ? "bad" : "none", true)}" title="${devTypeWrong ? `esperado: ${r.inferred.deviceType}` : ""}">${r.actual.deviceType || dash}</td>
|
|
85741
|
+
<td ${copyAttr(r.inferred.deviceProfile)} style="${cell(devProfWrong ? "ok" : "none", true)}">${r.inferred.deviceProfile}</td>
|
|
85742
|
+
<td ${copyAttr(r.actual.deviceProfile ?? "")} style="${cell(devProfWrong ? "bad" : "none", true)}" title="${devProfWrong ? `esperado: ${r.inferred.deviceProfile}` : ""}">${r.actual.deviceProfile || dash}</td>
|
|
85743
|
+
<td ${copyAttr(r.telemetry.ts ? tsStr : "")} style="${cell()} white-space:nowrap; color:${colors2.textMuted}; font-size:9px;">${tsStr}</td>
|
|
85744
|
+
<td ${copyAttr(valCopy)} style="${cell()} font-size:9px;">${valStr}</td>
|
|
85745
|
+
<td ${copyAttr(r.connStatus ?? "")} style="${cell()} color:${connColor}; font-weight:600; white-space:nowrap;">${r.connStatus || dash}</td>
|
|
85746
|
+
<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>
|
|
85747
|
+
<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>
|
|
85748
|
+
<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>
|
|
85749
|
+
<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>
|
|
85459
85750
|
<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"};"
|
|
85460
85751
|
${r.status !== "ok" ? `data-cf-status="${r.status}" data-cf-device="${encodeURIComponent(r.deviceName)}" data-cf-detail="${encodeURIComponent(_buildCfStatusDetail(r))}"` : ""}>
|
|
85461
85752
|
${STATUS_ICON[r.status]} ${r.status}
|
|
@@ -85501,16 +85792,7 @@ function renderStep2(state6, modalId, colors2, t) {
|
|
|
85501
85792
|
}
|
|
85502
85793
|
return true;
|
|
85503
85794
|
});
|
|
85504
|
-
const searchFilteredDevices = searchTerm ? filteredDevices.filter((d) =>
|
|
85505
|
-
const name = (d.name || "").toLowerCase();
|
|
85506
|
-
const label = (d.label || "").toLowerCase();
|
|
85507
|
-
const type = (d.type || "").toLowerCase();
|
|
85508
|
-
const deviceType = (d.serverAttrs?.deviceType || "").toLowerCase();
|
|
85509
|
-
const deviceProfile = (d.serverAttrs?.deviceProfile || "").toLowerCase();
|
|
85510
|
-
const slaveId = String(d.serverAttrs?.slaveId ?? "").toLowerCase();
|
|
85511
|
-
const status = (d.latestTelemetry?.connectionStatus?.value || "").toLowerCase();
|
|
85512
|
-
return name.includes(searchTerm) || label.includes(searchTerm) || type.includes(searchTerm) || deviceType.includes(searchTerm) || deviceProfile.includes(searchTerm) || slaveId.includes(searchTerm) || status.includes(searchTerm);
|
|
85513
|
-
}) : filteredDevices;
|
|
85795
|
+
const searchFilteredDevices = searchTerm ? filteredDevices.filter((d) => buildDeviceSearchHaystack(d, state6).includes(searchTerm)) : filteredDevices;
|
|
85514
85796
|
const sortedDevices = sortDevices2(searchFilteredDevices, sortField, sortOrder);
|
|
85515
85797
|
const gridHeight = state6.isMaximized ? "calc(100vh - 340px)" : "360px";
|
|
85516
85798
|
const hasActiveFilters = filterTypes.length > 0 || filterDeviceTypes.length > 0 || filterDeviceProfiles.length > 0 || filterStatuses.length > 0 || filterTelemetryKeys.length > 0;
|
|
@@ -85978,6 +86260,95 @@ function renderStep2(state6, modalId, colors2, t) {
|
|
|
85978
86260
|
})()}
|
|
85979
86261
|
`;
|
|
85980
86262
|
}
|
|
86263
|
+
function buildDeviceSearchHaystack(d, state6) {
|
|
86264
|
+
const id = getEntityId(d);
|
|
86265
|
+
const relTo = (state6.deviceRelToMap.get(id) || []).map((r) => r.name || "").join(" ");
|
|
86266
|
+
const relFrom = (state6.deviceRelFromMap.get(id) || []).map((r) => r.name || "").join(" ");
|
|
86267
|
+
const tel = d.latestTelemetry || {};
|
|
86268
|
+
const a = d.serverAttrs || {};
|
|
86269
|
+
return [
|
|
86270
|
+
d.name,
|
|
86271
|
+
d.label,
|
|
86272
|
+
d.type,
|
|
86273
|
+
d.createdTime ? formatDate6(d.createdTime, state6.locale) : "",
|
|
86274
|
+
relTo,
|
|
86275
|
+
relFrom,
|
|
86276
|
+
a.centralId,
|
|
86277
|
+
a.slaveId,
|
|
86278
|
+
a.deviceType,
|
|
86279
|
+
a.deviceProfile,
|
|
86280
|
+
tel.pulses?.value,
|
|
86281
|
+
tel.consumption?.value,
|
|
86282
|
+
tel.temperature?.value,
|
|
86283
|
+
tel.connectionStatus?.value
|
|
86284
|
+
].map((v) => String(v ?? "").toLowerCase()).join("");
|
|
86285
|
+
}
|
|
86286
|
+
function getGridVisibleDevices(state6) {
|
|
86287
|
+
const {
|
|
86288
|
+
types: filterTypes,
|
|
86289
|
+
deviceTypes: filterDeviceTypes,
|
|
86290
|
+
deviceProfiles: filterDeviceProfiles,
|
|
86291
|
+
statuses: filterStatuses,
|
|
86292
|
+
telemetryKeys: filterTelemetryKeys
|
|
86293
|
+
} = state6.deviceFilters;
|
|
86294
|
+
const searchTerm = state6.deviceSearchTerm.toLowerCase();
|
|
86295
|
+
let result = state6.devices.filter((d) => {
|
|
86296
|
+
if (filterTypes.length > 0 && !filterTypes.includes(d.type || "")) return false;
|
|
86297
|
+
if (filterDeviceTypes.length > 0 && !filterDeviceTypes.includes(d.serverAttrs?.deviceType || ""))
|
|
86298
|
+
return false;
|
|
86299
|
+
if (filterDeviceProfiles.length > 0 && !filterDeviceProfiles.includes(d.serverAttrs?.deviceProfile || ""))
|
|
86300
|
+
return false;
|
|
86301
|
+
if (filterStatuses.length > 0) {
|
|
86302
|
+
const status = d.latestTelemetry?.connectionStatus?.value || "offline";
|
|
86303
|
+
if (!filterStatuses.includes(status)) return false;
|
|
86304
|
+
}
|
|
86305
|
+
if (filterTelemetryKeys.length > 0) {
|
|
86306
|
+
const telem = d.latestTelemetry;
|
|
86307
|
+
const hasMatch = filterTelemetryKeys.some((k) => {
|
|
86308
|
+
if (k === "pulses") return telem?.pulses != null;
|
|
86309
|
+
if (k === "consumption") return telem?.consumption != null;
|
|
86310
|
+
return false;
|
|
86311
|
+
});
|
|
86312
|
+
if (!hasMatch) return false;
|
|
86313
|
+
}
|
|
86314
|
+
return true;
|
|
86315
|
+
});
|
|
86316
|
+
if (searchTerm) {
|
|
86317
|
+
result = result.filter((d) => buildDeviceSearchHaystack(d, state6).includes(searchTerm));
|
|
86318
|
+
}
|
|
86319
|
+
if (state6.checkFixReport) {
|
|
86320
|
+
const idToRecord = new Map(state6.checkFixReport.records.map((r) => [r.deviceId, r]));
|
|
86321
|
+
const af = state6.checkFixAdvancedFilter;
|
|
86322
|
+
result = result.filter((d) => {
|
|
86323
|
+
const r = idToRecord.get(getEntityId(d));
|
|
86324
|
+
if (!r) return false;
|
|
86325
|
+
if (!(state6.checkFixFilter === "all" || r.status === state6.checkFixFilter)) return false;
|
|
86326
|
+
if (af.statuses.length > 0 && !af.statuses.includes(r.status)) return false;
|
|
86327
|
+
if (af.connStatuses.length > 0 && !af.connStatuses.includes(r.connStatus || "null")) return false;
|
|
86328
|
+
if (af.domains.length > 0 && !af.domains.includes(r.domain || "null")) return false;
|
|
86329
|
+
if (af.missingIngestionId && r.ingestionId) return false;
|
|
86330
|
+
if (af.missingCentralSlave && r.centralId && r.slaveId != null) return false;
|
|
86331
|
+
return true;
|
|
86332
|
+
});
|
|
86333
|
+
}
|
|
86334
|
+
return result;
|
|
86335
|
+
}
|
|
86336
|
+
function copyCellValue(text, el2) {
|
|
86337
|
+
if (!text) return;
|
|
86338
|
+
const flash = (ok) => {
|
|
86339
|
+
const prev = el2.style.backgroundColor;
|
|
86340
|
+
el2.style.transition = "background-color 0.15s ease";
|
|
86341
|
+
el2.style.backgroundColor = ok ? "rgba(34,197,94,0.35)" : "rgba(239,68,68,0.35)";
|
|
86342
|
+
setTimeout(() => {
|
|
86343
|
+
el2.style.backgroundColor = prev;
|
|
86344
|
+
}, 350);
|
|
86345
|
+
};
|
|
86346
|
+
if (navigator.clipboard?.writeText) {
|
|
86347
|
+
navigator.clipboard.writeText(text).then(() => flash(true), () => flash(false));
|
|
86348
|
+
} else {
|
|
86349
|
+
flash(false);
|
|
86350
|
+
}
|
|
86351
|
+
}
|
|
85981
86352
|
function renderDeviceRow(device, state6, modalId, colors2) {
|
|
85982
86353
|
const deviceId = getEntityId(device);
|
|
85983
86354
|
const isSelectedSingle = state6.deviceSelectionMode === "single" && getEntityId(state6.selectedDevice) === deviceId;
|
|
@@ -86092,6 +86463,10 @@ function renderDeviceRow(device, state6, modalId, colors2) {
|
|
|
86092
86463
|
" title="${statusTs}">(+)</span>` : ""}
|
|
86093
86464
|
`;
|
|
86094
86465
|
};
|
|
86466
|
+
const relToNames = state6.relationsLoaded ? (state6.deviceRelToMap.get(deviceId) || []).map((r) => r.name || "").filter(Boolean).join(", ") : "";
|
|
86467
|
+
const relFromNames = state6.relationsLoaded ? (state6.deviceRelFromMap.get(deviceId) || []).map((r) => r.name || "").filter(Boolean).join(", ") : "";
|
|
86468
|
+
const telemetryCopy = telemetryItems.map((it) => `${it.label}: ${it.value}${it.unit}`).join("; ");
|
|
86469
|
+
const copyAttr = (v) => `class="myio-copy-cell" data-copy="${encodeURIComponent(String(v ?? ""))}" title="Clique para copiar valor"`;
|
|
86095
86470
|
return `
|
|
86096
86471
|
<div class="myio-list-item ${isSelected ? "selected" : ""}"
|
|
86097
86472
|
data-device-id="${deviceId}" style="
|
|
@@ -86107,8 +86482,8 @@ function renderDeviceRow(device, state6, modalId, colors2) {
|
|
|
86107
86482
|
" />
|
|
86108
86483
|
</div>
|
|
86109
86484
|
` : ""}
|
|
86110
|
-
<div style="width: 28px; font-size: 16px; flex-shrink: 0;">${getDeviceIcon3(device.type)}</div>
|
|
86111
|
-
<div style="width: ${state6.columnWidths.name}px; padding: 0 6px; overflow: hidden; display: flex; align-items: center; gap: 4px;">
|
|
86485
|
+
<div style="width: 28px; font-size: 16px; flex-shrink: 0; cursor: pointer;" title="Clique para selecionar o dispositivo">${getDeviceIcon3(device.type)}</div>
|
|
86486
|
+
<div ${copyAttr(device.name)} style="width: ${state6.columnWidths.name}px; padding: 0 6px; overflow: hidden; display: flex; align-items: center; gap: 4px; cursor: pointer;">
|
|
86112
86487
|
<div style="font-weight: 600; color: ${colors2.text}; font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1;" title="${device.name}">
|
|
86113
86488
|
${device.name}
|
|
86114
86489
|
</div>
|
|
@@ -86118,22 +86493,22 @@ function renderDeviceRow(device, state6, modalId, colors2) {
|
|
|
86118
86493
|
display: flex; align-items: center; justify-content: center; border: 1px solid ${colors2.border};
|
|
86119
86494
|
" title="Ver detalhes">\u24D8</span>
|
|
86120
86495
|
</div>
|
|
86121
|
-
<div style="width: ${state6.columnWidths.label}px; padding: 0 6px; overflow: hidden; flex-shrink: 0;">
|
|
86496
|
+
<div ${copyAttr(device.label ?? "")} style="width: ${state6.columnWidths.label}px; padding: 0 6px; overflow: hidden; flex-shrink: 0; cursor: pointer;">
|
|
86122
86497
|
<div style="font-size: 10px; color: ${colors2.textMuted}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" title="${device.label ?? ""}">
|
|
86123
86498
|
${device.label ?? ""}
|
|
86124
86499
|
</div>
|
|
86125
86500
|
</div>
|
|
86126
|
-
<div style="width: ${state6.columnWidths.type}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden;">
|
|
86501
|
+
<div ${copyAttr(device.type ?? "")} style="width: ${state6.columnWidths.type}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; cursor: pointer;">
|
|
86127
86502
|
<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%;
|
|
86128
86503
|
background: ${device.type?.includes("HIDRO") ? "#dbeafe" : "#fef3c7"};
|
|
86129
86504
|
color: ${device.type?.includes("HIDRO") ? "#1e40af" : "#92400e"};" title="${device.type || ""}">
|
|
86130
86505
|
${device.type || "\u2014"}
|
|
86131
86506
|
</div>
|
|
86132
86507
|
</div>
|
|
86133
|
-
<div style="width: ${state6.columnWidths.createdTime}px; padding: 0 6px; text-align: center; flex-shrink: 0;">
|
|
86508
|
+
<div ${copyAttr(device.createdTime ? createdTimeStr : "")} style="width: ${state6.columnWidths.createdTime}px; padding: 0 6px; text-align: center; flex-shrink: 0; cursor: pointer;">
|
|
86134
86509
|
<span style="font-size: 9px; color: ${colors2.textMuted};">${createdTimeStr}</span>
|
|
86135
86510
|
</div>
|
|
86136
|
-
<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;">
|
|
86511
|
+
<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;">
|
|
86137
86512
|
${(() => {
|
|
86138
86513
|
if (!state6.relationsLoaded) return `<span style="font-size: 8px; color: ${colors2.textMuted}; font-style: italic;">\u2014</span>`;
|
|
86139
86514
|
const rels = state6.deviceRelToMap.get(deviceId) || [];
|
|
@@ -86143,7 +86518,7 @@ function renderDeviceRow(device, state6, modalId, colors2) {
|
|
|
86143
86518
|
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>` : ""}`;
|
|
86144
86519
|
})()}
|
|
86145
86520
|
</div>
|
|
86146
|
-
<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;">
|
|
86521
|
+
<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;">
|
|
86147
86522
|
${(() => {
|
|
86148
86523
|
if (!state6.relationsLoaded) return `<span style="font-size: 8px; color: ${colors2.textMuted}; font-style: italic;">\u2014</span>`;
|
|
86149
86524
|
const rels = state6.deviceRelFromMap.get(deviceId) || [];
|
|
@@ -86153,25 +86528,25 @@ function renderDeviceRow(device, state6, modalId, colors2) {
|
|
|
86153
86528
|
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>` : ""}`;
|
|
86154
86529
|
})()}
|
|
86155
86530
|
</div>
|
|
86156
|
-
<div style="width: ${state6.columnWidths.centralId}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
|
|
86531
|
+
<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;">
|
|
86157
86532
|
${!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>`}
|
|
86158
86533
|
</div>
|
|
86159
|
-
<div style="width: ${state6.columnWidths.slaveId}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
|
|
86534
|
+
<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;">
|
|
86160
86535
|
${!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>`}
|
|
86161
86536
|
</div>
|
|
86162
|
-
<div style="width: ${state6.columnWidths.deviceType}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
|
|
86537
|
+
<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;">
|
|
86163
86538
|
${renderDeviceTypeValue()}
|
|
86164
86539
|
</div>
|
|
86165
|
-
<div style="width: ${state6.columnWidths.deviceProfile}px; padding: 0 6px; text-align: center; flex-shrink: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
|
|
86540
|
+
<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;">
|
|
86166
86541
|
${renderDeviceProfileValue()}
|
|
86167
86542
|
</div>
|
|
86168
|
-
<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;">
|
|
86543
|
+
<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;">
|
|
86169
86544
|
${renderTelemetryValue()}
|
|
86170
86545
|
</div>
|
|
86171
|
-
<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;">
|
|
86546
|
+
<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;">
|
|
86172
86547
|
${renderStatusValue()}
|
|
86173
86548
|
</div>
|
|
86174
|
-
<div style="width: 24px; flex-shrink: 0; text-align: center;">
|
|
86549
|
+
<div style="width: 24px; flex-shrink: 0; text-align: center; cursor: pointer;" title="Clique para selecionar o dispositivo">
|
|
86175
86550
|
${isSelected ? `<span style="color: ${colors2.success}; font-size: 14px;">\u2713</span>` : ""}
|
|
86176
86551
|
</div>
|
|
86177
86552
|
</div>
|
|
@@ -86553,7 +86928,11 @@ function renderLojasStep3(state6, modalId, colors2, t) {
|
|
|
86553
86928
|
<span>Profile alvo: <strong style="color: ${colors2.text};">3F_MEDIDOR</strong></span>
|
|
86554
86929
|
<span>deviceType: <strong style="color: ${colors2.text};">3F_MEDIDOR</strong></span>
|
|
86555
86930
|
<span>deviceProfile: <strong style="color: ${colors2.text};">3F_MEDIDOR</strong></span>
|
|
86556
|
-
<
|
|
86931
|
+
<label style="display: flex; align-items: center; gap: 6px; cursor: pointer;"
|
|
86932
|
+
title="Marcado: for\xE7a a rela\xE7\xE3o Customer \u2192 Device. Desmarcado: n\xE3o altera rela\xE7\xF5es.">
|
|
86933
|
+
<input type="checkbox" id="${modalId}-lojas-apply-relation" ${state6.lojasApplyRelation ? "checked" : ""} style="accent-color: ${MYIO_PURPLE}; cursor: pointer;" />
|
|
86934
|
+
<span>Rela\xE7\xE3o: <strong style="color: ${colors2.text};">CUSTOMER \u2192 DEVICE (Contains)</strong></span>
|
|
86935
|
+
</label>
|
|
86557
86936
|
</div>
|
|
86558
86937
|
</div>
|
|
86559
86938
|
`;
|
|
@@ -87117,6 +87496,8 @@ async function openClearGcdrIdsModal(state6) {
|
|
|
87117
87496
|
}
|
|
87118
87497
|
}
|
|
87119
87498
|
function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
87499
|
+
if (container.dataset.upsellListenersBound === "true") return;
|
|
87500
|
+
container.dataset.upsellListenersBound = "true";
|
|
87120
87501
|
const closeHandler = () => closeModal(container, onClose);
|
|
87121
87502
|
const overlay = container.querySelector(".myio-upsell-modal-overlay");
|
|
87122
87503
|
if (overlay) {
|
|
@@ -87232,10 +87613,18 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87232
87613
|
});
|
|
87233
87614
|
});
|
|
87234
87615
|
});
|
|
87616
|
+
container.querySelectorAll(".myio-copy-cell").forEach((cell) => {
|
|
87617
|
+
cell.addEventListener("click", (e) => {
|
|
87618
|
+
e.stopPropagation();
|
|
87619
|
+
const target = e.target;
|
|
87620
|
+
if (target.closest("button, input, .myio-info-btn, .myio-ts-btn")) return;
|
|
87621
|
+
copyCellValue(decodeURIComponent(cell.dataset.copy || ""), cell);
|
|
87622
|
+
});
|
|
87623
|
+
});
|
|
87235
87624
|
document.getElementById(`${modalId}-device-search`)?.addEventListener("input", (e) => {
|
|
87236
87625
|
const search = e.target.value.toLowerCase();
|
|
87237
87626
|
state6.deviceSearchTerm = e.target.value;
|
|
87238
|
-
filterDeviceListVisual(container, state6.devices, search, state6.deviceFilters, state6.deviceSort);
|
|
87627
|
+
filterDeviceListVisual(container, state6.devices, search, state6.deviceFilters, state6.deviceSort, state6);
|
|
87239
87628
|
});
|
|
87240
87629
|
document.getElementById(`${modalId}-device-type-filter`)?.addEventListener("change", (e) => {
|
|
87241
87630
|
const select = e.target;
|
|
@@ -87457,15 +87846,17 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87457
87846
|
renderModal4(container, state6, modalId, t);
|
|
87458
87847
|
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
87459
87848
|
});
|
|
87460
|
-
document.getElementById(`${modalId}-check-fix`)?.addEventListener("click",
|
|
87849
|
+
document.getElementById(`${modalId}-check-fix`)?.addEventListener("click", () => {
|
|
87461
87850
|
if (state6.checkFixLoading) return;
|
|
87462
|
-
state6
|
|
87463
|
-
|
|
87464
|
-
|
|
87465
|
-
|
|
87466
|
-
|
|
87467
|
-
|
|
87468
|
-
|
|
87851
|
+
openCheckFixScopeDialog(state6, async (scopeDevices) => {
|
|
87852
|
+
state6.checkFixLoading = true;
|
|
87853
|
+
renderModal4(container, state6, modalId, t);
|
|
87854
|
+
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
87855
|
+
await runCheckFixRoutine(state6, container, modalId, t, onClose, scopeDevices);
|
|
87856
|
+
state6.checkFixLoading = false;
|
|
87857
|
+
renderModal4(container, state6, modalId, t);
|
|
87858
|
+
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
87859
|
+
});
|
|
87469
87860
|
});
|
|
87470
87861
|
document.getElementById(`${modalId}-checkfix-filter`)?.addEventListener("change", (e) => {
|
|
87471
87862
|
state6.checkFixFilter = e.target.value;
|
|
@@ -87563,35 +87954,7 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87563
87954
|
}
|
|
87564
87955
|
});
|
|
87565
87956
|
document.getElementById(`${modalId}-select-all`)?.addEventListener("click", () => {
|
|
87566
|
-
|
|
87567
|
-
types: filterTypes,
|
|
87568
|
-
deviceTypes: filterDeviceTypes,
|
|
87569
|
-
deviceProfiles: filterDeviceProfiles,
|
|
87570
|
-
statuses: filterStatuses,
|
|
87571
|
-
telemetryKeys: filterTelemetryKeys
|
|
87572
|
-
} = state6.deviceFilters;
|
|
87573
|
-
let filteredDevices = state6.devices.filter((d) => {
|
|
87574
|
-
if (filterTypes.length > 0 && !filterTypes.includes(d.type || "")) return false;
|
|
87575
|
-
if (filterDeviceTypes.length > 0 && !filterDeviceTypes.includes(d.serverAttrs?.deviceType || ""))
|
|
87576
|
-
return false;
|
|
87577
|
-
if (filterDeviceProfiles.length > 0 && !filterDeviceProfiles.includes(d.serverAttrs?.deviceProfile || ""))
|
|
87578
|
-
return false;
|
|
87579
|
-
if (filterStatuses.length > 0) {
|
|
87580
|
-
const status = d.latestTelemetry?.connectionStatus?.value || "offline";
|
|
87581
|
-
if (!filterStatuses.includes(status)) return false;
|
|
87582
|
-
}
|
|
87583
|
-
if (filterTelemetryKeys.length > 0) {
|
|
87584
|
-
const telem = d.latestTelemetry;
|
|
87585
|
-
const hasMatch = filterTelemetryKeys.some((k) => {
|
|
87586
|
-
if (k === "pulses") return telem?.pulses != null;
|
|
87587
|
-
if (k === "consumption") return telem?.consumption != null;
|
|
87588
|
-
return false;
|
|
87589
|
-
});
|
|
87590
|
-
if (!hasMatch) return false;
|
|
87591
|
-
}
|
|
87592
|
-
return true;
|
|
87593
|
-
});
|
|
87594
|
-
state6.selectedDevices = [...filteredDevices];
|
|
87957
|
+
state6.selectedDevices = [...getGridVisibleDevices(state6)];
|
|
87595
87958
|
const listEl = document.getElementById(`${modalId}-device-list`);
|
|
87596
87959
|
const savedScroll = listEl ? listEl.scrollTop : 0;
|
|
87597
87960
|
renderModal4(container, state6, modalId, t);
|
|
@@ -87707,12 +88070,27 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87707
88070
|
document.getElementById(`${modalId}-bulk-profile-save`)?.addEventListener("click", async () => {
|
|
87708
88071
|
await saveBulkProfile(state6, container, modalId, t, onClose);
|
|
87709
88072
|
});
|
|
87710
|
-
document.getElementById(`${modalId}-bulk-owner`)?.addEventListener("click", () => {
|
|
88073
|
+
document.getElementById(`${modalId}-bulk-owner`)?.addEventListener("click", async () => {
|
|
87711
88074
|
if (!state6.selectedCustomer) {
|
|
87712
88075
|
alert("Selecione um Customer primeiro no Step 1");
|
|
87713
88076
|
return;
|
|
87714
88077
|
}
|
|
87715
88078
|
state6.bulkOwnerModal.open = true;
|
|
88079
|
+
if (!state6.bulkOwnerModal.targetCustomerId) {
|
|
88080
|
+
state6.bulkOwnerModal.targetCustomerId = state6.selectedCustomer.id?.id || "";
|
|
88081
|
+
}
|
|
88082
|
+
renderModal4(container, state6, modalId, t);
|
|
88083
|
+
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
88084
|
+
if (state6.customers.length === 0) {
|
|
88085
|
+
await loadCustomers(state6, container, modalId, t, onClose);
|
|
88086
|
+
if (state6.bulkOwnerModal.open) {
|
|
88087
|
+
renderModal4(container, state6, modalId, t);
|
|
88088
|
+
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
88089
|
+
}
|
|
88090
|
+
}
|
|
88091
|
+
});
|
|
88092
|
+
document.getElementById(`${modalId}-bulk-owner-customer`)?.addEventListener("change", (e) => {
|
|
88093
|
+
state6.bulkOwnerModal.targetCustomerId = e.target.value;
|
|
87716
88094
|
renderModal4(container, state6, modalId, t);
|
|
87717
88095
|
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
87718
88096
|
});
|
|
@@ -87757,6 +88135,10 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87757
88135
|
if (!state6.selectedCustomer || state6.selectedDevices.length === 0) return;
|
|
87758
88136
|
await handleBulkSyncIngestionId(state6, container, modalId, t, onClose);
|
|
87759
88137
|
});
|
|
88138
|
+
document.getElementById(`${modalId}-bulk-delete`)?.addEventListener("click", async () => {
|
|
88139
|
+
if (state6.selectedDevices.length === 0) return;
|
|
88140
|
+
await handleBulkDeleteDevices(state6, container, modalId, t, onClose);
|
|
88141
|
+
});
|
|
87760
88142
|
document.getElementById(`${modalId}-clear-gcdr-ids`)?.addEventListener("click", () => {
|
|
87761
88143
|
if (!state6.selectedCustomer) {
|
|
87762
88144
|
alert("Selecione um Customer primeiro no Step 1");
|
|
@@ -87886,6 +88268,14 @@ function setupEventListeners3(container, state6, modalId, t, onClose) {
|
|
|
87886
88268
|
});
|
|
87887
88269
|
}
|
|
87888
88270
|
});
|
|
88271
|
+
const applyRelCb = document.getElementById(
|
|
88272
|
+
`${modalId}-lojas-apply-relation`
|
|
88273
|
+
);
|
|
88274
|
+
if (applyRelCb) {
|
|
88275
|
+
applyRelCb.addEventListener("change", () => {
|
|
88276
|
+
state6.lojasApplyRelation = applyRelCb.checked;
|
|
88277
|
+
});
|
|
88278
|
+
}
|
|
87889
88279
|
}
|
|
87890
88280
|
document.getElementById(`${modalId}-change-owner`)?.addEventListener("click", () => {
|
|
87891
88281
|
const form = document.getElementById(`${modalId}-change-owner-form`);
|
|
@@ -88107,7 +88497,8 @@ Total de devices no customer: ${ingestionDevices.length}`
|
|
|
88107
88497
|
state6.devices,
|
|
88108
88498
|
state6.deviceSearchTerm.toLowerCase(),
|
|
88109
88499
|
state6.deviceFilters,
|
|
88110
|
-
state6.deviceSort
|
|
88500
|
+
state6.deviceSort,
|
|
88501
|
+
state6
|
|
88111
88502
|
);
|
|
88112
88503
|
}
|
|
88113
88504
|
}
|
|
@@ -88247,7 +88638,7 @@ function filterCustomerList(container, customers, search, selected, sort) {
|
|
|
88247
88638
|
item.style.display = matches ? "flex" : "none";
|
|
88248
88639
|
});
|
|
88249
88640
|
}
|
|
88250
|
-
function filterDeviceListVisual(container, devices, search, filters, sort) {
|
|
88641
|
+
function filterDeviceListVisual(container, devices, search, filters, sort, state6) {
|
|
88251
88642
|
const listContainer = container.querySelector('[id$="-device-list"]');
|
|
88252
88643
|
if (!listContainer) return;
|
|
88253
88644
|
let filtered = devices.filter((d) => {
|
|
@@ -88267,7 +88658,7 @@ function filterDeviceListVisual(container, devices, search, filters, sort) {
|
|
|
88267
88658
|
item.style.display = "none";
|
|
88268
88659
|
return;
|
|
88269
88660
|
}
|
|
88270
|
-
const matchesSearch = !search ||
|
|
88661
|
+
const matchesSearch = !search || buildDeviceSearchHaystack(device, state6).includes(search);
|
|
88271
88662
|
const el2 = item;
|
|
88272
88663
|
const isTableRow = el2.tagName === "TR";
|
|
88273
88664
|
el2.style.display = matchesSearch ? isTableRow ? "" : "flex" : "none";
|
|
@@ -88618,6 +89009,56 @@ async function loadLojasData(state6, container, modalId, t, onClose) {
|
|
|
88618
89009
|
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
88619
89010
|
}
|
|
88620
89011
|
}
|
|
89012
|
+
async function handleBulkDeleteDevices(state6, container, modalId, t, onClose) {
|
|
89013
|
+
const devices = [...state6.selectedDevices];
|
|
89014
|
+
if (devices.length === 0) return;
|
|
89015
|
+
const preview = devices.slice(0, 8).map((d) => `\u2022 ${d.name || d.label || getEntityId(d)}`).join("\n");
|
|
89016
|
+
const more = devices.length > 8 ? `
|
|
89017
|
+
\u2026 e mais ${devices.length - 8}` : "";
|
|
89018
|
+
const confirm1 = `\u26A0\uFE0F DELETAR ${devices.length} dispositivo(s) do ThingsBoard?
|
|
89019
|
+
|
|
89020
|
+
${preview}${more}
|
|
89021
|
+
|
|
89022
|
+
Esta a\xE7\xE3o \xE9 IRREVERS\xCDVEL \u2014 os dispositivos, suas rela\xE7\xF5es e telemetria ser\xE3o removidos permanentemente.`;
|
|
89023
|
+
if (!confirm(confirm1)) return;
|
|
89024
|
+
if (!confirm(
|
|
89025
|
+
`Confirma\xE7\xE3o final: deletar ${devices.length} dispositivo(s)?
|
|
89026
|
+
Esta a\xE7\xE3o N\xC3O pode ser desfeita.`
|
|
89027
|
+
))
|
|
89028
|
+
return;
|
|
89029
|
+
showBusyProgress(`Deletando ${devices.length} dispositivos...`, devices.length);
|
|
89030
|
+
let okCount = 0;
|
|
89031
|
+
let failCount = 0;
|
|
89032
|
+
const errors = [];
|
|
89033
|
+
const deletedIds = /* @__PURE__ */ new Set();
|
|
89034
|
+
for (let i = 0; i < devices.length; i++) {
|
|
89035
|
+
const d = devices[i];
|
|
89036
|
+
const id = getEntityId(d);
|
|
89037
|
+
try {
|
|
89038
|
+
await tbDelete(state6, `/api/device/${id}`);
|
|
89039
|
+
deletedIds.add(id);
|
|
89040
|
+
okCount++;
|
|
89041
|
+
} catch (err) {
|
|
89042
|
+
failCount++;
|
|
89043
|
+
errors.push(`${d.name || id}: ${err.message}`);
|
|
89044
|
+
}
|
|
89045
|
+
updateBusyProgress(i + 1);
|
|
89046
|
+
}
|
|
89047
|
+
hideBusyProgress();
|
|
89048
|
+
state6.devices = state6.devices.filter((d) => !deletedIds.has(getEntityId(d)));
|
|
89049
|
+
state6.selectedDevices = state6.selectedDevices.filter((d) => !deletedIds.has(getEntityId(d)));
|
|
89050
|
+
if (state6.selectedDevice && deletedIds.has(getEntityId(state6.selectedDevice))) {
|
|
89051
|
+
state6.selectedDevice = null;
|
|
89052
|
+
}
|
|
89053
|
+
renderModal4(container, state6, modalId, t);
|
|
89054
|
+
setupEventListeners3(container, state6, modalId, t, onClose);
|
|
89055
|
+
alert(
|
|
89056
|
+
`Dispositivos deletados: ${okCount}` + (failCount > 0 ? `
|
|
89057
|
+
Falhas: ${failCount}
|
|
89058
|
+
${errors.slice(0, 5).join("\n")}` + (errors.length > 5 ? `
|
|
89059
|
+
\u2026 e mais ${errors.length - 5} erros` : "") : "")
|
|
89060
|
+
);
|
|
89061
|
+
}
|
|
88621
89062
|
async function handleBulkSyncIngestionId(state6, container, modalId, t, onClose) {
|
|
88622
89063
|
if (!state6.selectedCustomer || state6.selectedDevices.length === 0) return;
|
|
88623
89064
|
const customerId = getEntityId(state6.selectedCustomer);
|
|
@@ -88764,15 +89205,17 @@ async function handleLojasApply(state6, container, modalId, t, onClose) {
|
|
|
88764
89205
|
if (identifierInput) data[i].identifier = identifierInput.value;
|
|
88765
89206
|
}
|
|
88766
89207
|
const activeConfig = state6.lojasConfig ?? CUSTOM_MODES[0];
|
|
89208
|
+
const applyRelation = state6.lojasApplyRelation;
|
|
88767
89209
|
const confirmMsg = `Aplicar configura\xE7\xE3o "${activeConfig.label}" para ${data.length} dispositivos?
|
|
88768
89210
|
|
|
88769
89211
|
Cada device receber\xE1:
|
|
88770
89212
|
- Label atualizado (etiqueta)
|
|
88771
89213
|
- Profile: ${activeConfig.deviceProfile}
|
|
88772
89214
|
- deviceType/deviceProfile: ${activeConfig.deviceType} / ${activeConfig.deviceProfile}
|
|
88773
|
-
|
|
89215
|
+
` + (applyRelation ? `- Rela\xE7\xF5es existentes removidas
|
|
88774
89216
|
- Nova rela\xE7\xE3o: Customer \u2192 Device (Contains)
|
|
88775
|
-
|
|
89217
|
+
` : `- Rela\xE7\xF5es N\xC3O ser\xE3o alteradas (checkbox de rela\xE7\xE3o desmarcado)
|
|
89218
|
+
`) + `
|
|
88776
89219
|
Deseja continuar?`;
|
|
88777
89220
|
if (!confirm(confirmMsg)) return;
|
|
88778
89221
|
showBusyProgress(`Aplicando ${activeConfig.label}...`, data.length);
|
|
@@ -88800,31 +89243,33 @@ Deseja continuar?`;
|
|
|
88800
89243
|
attrs.ingestionId = d.ingestionId;
|
|
88801
89244
|
}
|
|
88802
89245
|
await tbPost(state6, `/api/plugins/telemetry/DEVICE/${d.deviceId}/attributes/SERVER_SCOPE`, attrs);
|
|
88803
|
-
if (
|
|
88804
|
-
|
|
88805
|
-
|
|
88806
|
-
|
|
88807
|
-
|
|
88808
|
-
|
|
88809
|
-
|
|
88810
|
-
|
|
88811
|
-
|
|
88812
|
-
|
|
88813
|
-
|
|
88814
|
-
|
|
88815
|
-
|
|
88816
|
-
|
|
88817
|
-
|
|
89246
|
+
if (applyRelation) {
|
|
89247
|
+
if (d.currentRelations.length > 0) {
|
|
89248
|
+
updateBusyProgress(i + 1, `[${i + 1}/${data.length}] ${d.name}: Removendo rela\xE7\xF5es...`);
|
|
89249
|
+
for (const rel of d.currentRelations) {
|
|
89250
|
+
try {
|
|
89251
|
+
const params = new URLSearchParams({
|
|
89252
|
+
fromId: rel.from.id,
|
|
89253
|
+
fromType: rel.from.entityType,
|
|
89254
|
+
toId: d.deviceId,
|
|
89255
|
+
toType: "DEVICE",
|
|
89256
|
+
relationType: rel.type || "Contains",
|
|
89257
|
+
relationTypeGroup: rel.typeGroup || "COMMON"
|
|
89258
|
+
});
|
|
89259
|
+
await tbDelete(state6, `/api/relation?${params.toString()}`);
|
|
89260
|
+
} catch (e) {
|
|
89261
|
+
console.warn("[UpsellModal] Error deleting relation for LOJAS:", e);
|
|
89262
|
+
}
|
|
88818
89263
|
}
|
|
88819
89264
|
}
|
|
89265
|
+
updateBusyProgress(i + 1, `[${i + 1}/${data.length}] ${d.name}: Criando rela\xE7\xE3o...`);
|
|
89266
|
+
await tbPost(state6, "/api/relation", {
|
|
89267
|
+
from: { entityType: "CUSTOMER", id: customerId },
|
|
89268
|
+
to: { entityType: "DEVICE", id: d.deviceId },
|
|
89269
|
+
type: "Contains",
|
|
89270
|
+
typeGroup: "COMMON"
|
|
89271
|
+
});
|
|
88820
89272
|
}
|
|
88821
|
-
updateBusyProgress(i + 1, `[${i + 1}/${data.length}] ${d.name}: Criando rela\xE7\xE3o...`);
|
|
88822
|
-
await tbPost(state6, "/api/relation", {
|
|
88823
|
-
from: { entityType: "CUSTOMER", id: customerId },
|
|
88824
|
-
to: { entityType: "DEVICE", id: d.deviceId },
|
|
88825
|
-
type: "Contains",
|
|
88826
|
-
typeGroup: "COMMON"
|
|
88827
|
-
});
|
|
88828
89273
|
successCount++;
|
|
88829
89274
|
} catch (error) {
|
|
88830
89275
|
errorCount++;
|
|
@@ -89112,8 +89557,111 @@ async function loadDeviceTelemetryInBatch(state6, container, modalId, t, onClose
|
|
|
89112
89557
|
hideBusyProgress();
|
|
89113
89558
|
}
|
|
89114
89559
|
}
|
|
89115
|
-
|
|
89116
|
-
const
|
|
89560
|
+
function openCheckFixScopeDialog(state6, onConfirm) {
|
|
89561
|
+
const DIALOG_ID = "myio-upsell-cf-scope-dialog";
|
|
89562
|
+
document.getElementById(DIALOG_ID)?.remove();
|
|
89563
|
+
const c = getThemeColors5(state6.theme);
|
|
89564
|
+
const allDevices = state6.devices;
|
|
89565
|
+
const allTypes = [...new Set(allDevices.map((d) => d.type).filter(Boolean))].sort();
|
|
89566
|
+
let namePattern = "";
|
|
89567
|
+
let caseSensitive = false;
|
|
89568
|
+
const selectedTypes = /* @__PURE__ */ new Set();
|
|
89569
|
+
function computeSubset() {
|
|
89570
|
+
let result = allDevices;
|
|
89571
|
+
if (namePattern) {
|
|
89572
|
+
const pat = caseSensitive ? namePattern : namePattern.toLowerCase();
|
|
89573
|
+
result = result.filter((d) => {
|
|
89574
|
+
const n = caseSensitive ? d.name || "" : (d.name || "").toLowerCase();
|
|
89575
|
+
return n.includes(pat);
|
|
89576
|
+
});
|
|
89577
|
+
}
|
|
89578
|
+
if (selectedTypes.size > 0) {
|
|
89579
|
+
result = result.filter((d) => selectedTypes.has(d.type || ""));
|
|
89580
|
+
}
|
|
89581
|
+
return result;
|
|
89582
|
+
}
|
|
89583
|
+
const overlay = document.createElement("div");
|
|
89584
|
+
overlay.id = DIALOG_ID;
|
|
89585
|
+
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;";
|
|
89586
|
+
overlay.innerHTML = `
|
|
89587
|
+
<div style="background:${c.surface};border-radius:12px;width:480px;max-width:92vw;max-height:88vh;
|
|
89588
|
+
overflow:hidden;display:flex;flex-direction:column;box-shadow:0 12px 40px rgba(0,0,0,0.4);">
|
|
89589
|
+
<div style="background:${MYIO_PURPLE};color:#fff;padding:12px 16px;font-size:14px;font-weight:700;">
|
|
89590
|
+
\u{1F52C} Escopo do CHECK & FIX
|
|
89591
|
+
</div>
|
|
89592
|
+
<div style="padding:16px;overflow-y:auto;display:flex;flex-direction:column;gap:14px;">
|
|
89593
|
+
<div style="font-size:11px;color:${c.textMuted};">
|
|
89594
|
+
Os filtros abaixo se <strong>combinam (E)</strong>. Deixe ambos vazios para
|
|
89595
|
+
diagnosticar todos os ${allDevices.length} dispositivos.
|
|
89596
|
+
</div>
|
|
89597
|
+
|
|
89598
|
+
<div style="display:flex;flex-direction:column;gap:8px;">
|
|
89599
|
+
<span style="font-size:12px;font-weight:600;color:${c.text};">Filtro por nome</span>
|
|
89600
|
+
<input id="cf-scope-name-input" type="text" placeholder="nome cont\xE9m\u2026 (ex.: TEMP.)" style="
|
|
89601
|
+
font-size:12px;padding:7px 9px;border-radius:6px;border:1px solid ${c.border};
|
|
89602
|
+
background:${c.inputBg};color:${c.text};" />
|
|
89603
|
+
<label style="display:flex;gap:6px;align-items:center;font-size:11px;color:${c.textMuted};cursor:pointer;">
|
|
89604
|
+
<input id="cf-scope-case" type="checkbox" style="accent-color:${MYIO_PURPLE};" />
|
|
89605
|
+
Diferenciar mai\xFAsculas/min\xFAsculas (case-sensitive)
|
|
89606
|
+
</label>
|
|
89607
|
+
</div>
|
|
89608
|
+
|
|
89609
|
+
<div style="display:flex;flex-direction:column;gap:8px;">
|
|
89610
|
+
<span style="font-size:12px;font-weight:600;color:${c.text};">Filtro por tipo (device.type)</span>
|
|
89611
|
+
<div style="display:flex;flex-wrap:wrap;gap:6px;max-height:160px;overflow-y:auto;">
|
|
89612
|
+
${allTypes.length === 0 ? `<span style="font-size:11px;color:${c.textMuted};">Nenhum tipo dispon\xEDvel.</span>` : allTypes.map(
|
|
89613
|
+
(tp) => `
|
|
89614
|
+
<label style="display:flex;gap:5px;align-items:center;font-size:11px;color:${c.text};
|
|
89615
|
+
cursor:pointer;border:1px solid ${c.border};border-radius:6px;padding:3px 8px;background:${c.cardBg};">
|
|
89616
|
+
<input type="checkbox" class="cf-scope-type-cb" value="${tp}" style="accent-color:${MYIO_PURPLE};" />
|
|
89617
|
+
${tp}
|
|
89618
|
+
</label>`
|
|
89619
|
+
).join("")}
|
|
89620
|
+
</div>
|
|
89621
|
+
</div>
|
|
89622
|
+
</div>
|
|
89623
|
+
<div style="padding:12px 16px;border-top:1px solid ${c.border};display:flex;justify-content:flex-end;gap:8px;">
|
|
89624
|
+
<button id="cf-scope-cancel" style="font-size:12px;font-weight:600;padding:8px 14px;border-radius:6px;
|
|
89625
|
+
border:1px solid ${c.border};background:${c.cardBg};color:${c.text};cursor:pointer;">Cancelar</button>
|
|
89626
|
+
<button id="cf-scope-run" style="font-size:12px;font-weight:700;padding:8px 14px;border-radius:6px;
|
|
89627
|
+
border:none;background:${MYIO_PURPLE};color:#fff;cursor:pointer;">Executar diagn\xF3stico (${allDevices.length})</button>
|
|
89628
|
+
</div>
|
|
89629
|
+
</div>`;
|
|
89630
|
+
document.body.appendChild(overlay);
|
|
89631
|
+
const runBtn = overlay.querySelector("#cf-scope-run");
|
|
89632
|
+
function refresh() {
|
|
89633
|
+
const n = computeSubset().length;
|
|
89634
|
+
runBtn.textContent = `Executar diagn\xF3stico (${n})`;
|
|
89635
|
+
runBtn.disabled = n === 0;
|
|
89636
|
+
runBtn.style.opacity = n === 0 ? "0.5" : "1";
|
|
89637
|
+
runBtn.style.cursor = n === 0 ? "not-allowed" : "pointer";
|
|
89638
|
+
}
|
|
89639
|
+
overlay.querySelector("#cf-scope-name-input").addEventListener("input", (e) => {
|
|
89640
|
+
namePattern = e.target.value;
|
|
89641
|
+
refresh();
|
|
89642
|
+
});
|
|
89643
|
+
overlay.querySelector("#cf-scope-case").addEventListener("change", (e) => {
|
|
89644
|
+
caseSensitive = e.target.checked;
|
|
89645
|
+
refresh();
|
|
89646
|
+
});
|
|
89647
|
+
overlay.querySelectorAll(".cf-scope-type-cb").forEach((cb) => {
|
|
89648
|
+
cb.addEventListener("change", () => {
|
|
89649
|
+
if (cb.checked) selectedTypes.add(cb.value);
|
|
89650
|
+
else selectedTypes.delete(cb.value);
|
|
89651
|
+
refresh();
|
|
89652
|
+
});
|
|
89653
|
+
});
|
|
89654
|
+
overlay.querySelector("#cf-scope-cancel").addEventListener("click", () => overlay.remove());
|
|
89655
|
+
runBtn.addEventListener("click", () => {
|
|
89656
|
+
const subset = computeSubset();
|
|
89657
|
+
if (subset.length === 0) return;
|
|
89658
|
+
overlay.remove();
|
|
89659
|
+
onConfirm(subset);
|
|
89660
|
+
});
|
|
89661
|
+
refresh();
|
|
89662
|
+
}
|
|
89663
|
+
async function runCheckFixRoutine(state6, container, modalId, t, onClose, scopeDevices) {
|
|
89664
|
+
const devices = scopeDevices ?? state6.devices;
|
|
89117
89665
|
if (devices.length === 0) return;
|
|
89118
89666
|
const BATCH_SIZE = 5;
|
|
89119
89667
|
const BATCH_DELAY_MS = 1500;
|
|
@@ -89396,10 +89944,11 @@ ${errors.slice(0, 5).join("\n")}` + (errors.length > 5 ? `
|
|
|
89396
89944
|
}
|
|
89397
89945
|
async function saveBulkOwner(state6, container, modalId, t, onClose) {
|
|
89398
89946
|
const devices = state6.selectedDevices;
|
|
89399
|
-
const newCustomerId = state6.selectedCustomer?.id?.id;
|
|
89400
|
-
const
|
|
89947
|
+
const newCustomerId = state6.bulkOwnerModal.targetCustomerId || state6.selectedCustomer?.id?.id;
|
|
89948
|
+
const targetCustomer = state6.customers.find((c) => c.id?.id === newCustomerId) || state6.selectedCustomer;
|
|
89949
|
+
const customerName = targetCustomer?.name || targetCustomer?.title || "Unknown";
|
|
89401
89950
|
if (!newCustomerId) {
|
|
89402
|
-
alert("Por favor, selecione um Customer
|
|
89951
|
+
alert("Por favor, selecione um Customer de destino.");
|
|
89403
89952
|
return;
|
|
89404
89953
|
}
|
|
89405
89954
|
if (devices.length === 0) {
|
|
@@ -118810,10 +119359,10 @@ var AlarmsNotificationsPanelView = class {
|
|
|
118810
119359
|
const renderListPanel = (group, items, sel) => {
|
|
118811
119360
|
if (items.length === 0) return '<div class="afm-empty">Nenhum item encontrado</div>';
|
|
118812
119361
|
return items.map((item) => {
|
|
118813
|
-
const
|
|
119362
|
+
const esc4 = this.esc(item);
|
|
118814
119363
|
return `<label class="afm-check-item">
|
|
118815
|
-
<input type="checkbox" class="afm-checkbox" data-group="${group}" data-value="${
|
|
118816
|
-
<span class="afm-check-label">${
|
|
119364
|
+
<input type="checkbox" class="afm-checkbox" data-group="${group}" data-value="${esc4}"${sel.has(item) ? " checked" : ""}>
|
|
119365
|
+
<span class="afm-check-label">${esc4}</span>
|
|
118817
119366
|
</label>`;
|
|
118818
119367
|
}).join("");
|
|
118819
119368
|
};
|
|
@@ -141096,6 +141645,7 @@ var version = package_default.version || "0.0.0";
|
|
|
141096
141645
|
CONSUMPTION_CHART_DEFAULTS,
|
|
141097
141646
|
CONSUMPTION_THEME_COLORS,
|
|
141098
141647
|
CardGridPanel,
|
|
141648
|
+
ColumnSummaryTooltip,
|
|
141099
141649
|
ConnectionStatusType,
|
|
141100
141650
|
ContractSummaryTooltip,
|
|
141101
141651
|
CustomerCardV1,
|