myio-js-library 0.1.563 → 0.1.564

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -352,7 +352,7 @@ __export(src_exports, {
352
352
  appendFreshdeskTicketToTB: () => appendFreshdeskTicketToTB,
353
353
  applyCustomerCodeToAssetName: () => applyCustomerCodeToAssetName,
354
354
  applyDashboardPalette: () => applyDashboardPalette,
355
- applyDeviceGridFilters: () => applyFilters,
355
+ applyDeviceGridFilters: () => applyFilters2,
356
356
  archiveAlarmAnnotation: () => archiveAlarmAnnotation,
357
357
  assetLocalToken: () => assetLocalToken,
358
358
  assignShoppingColors: () => assignShoppingColors,
@@ -711,6 +711,7 @@ __export(src_exports, {
711
711
  injectSolenoidControlStyles: () => injectSolenoidControlStyles,
712
712
  injectSwitchControlStyles: () => injectSwitchControlStyles,
713
713
  interpolateTemperature: () => interpolateTemperature,
714
+ inventory: () => inventory_exports,
714
715
  isAlarmActive: () => isAlarmActive,
715
716
  isAnnotationOverdue: () => isOverdue,
716
717
  isAssetCode: () => isAssetCode,
@@ -921,7 +922,7 @@ module.exports = __toCommonJS(src_exports);
921
922
  // package.json
922
923
  var package_default = {
923
924
  name: "myio-js-library",
924
- version: "0.1.563",
925
+ version: "0.1.564",
925
926
  description: "A clean, standalone JS SDK for MYIO projects",
926
927
  license: "MIT",
927
928
  repository: "github:gh-myio/myio-js-library",
@@ -2442,6 +2443,719 @@ function getTypesByCategory(category) {
2442
2443
  );
2443
2444
  }
2444
2445
 
2446
+ // src/utils/devices/inventory/index.ts
2447
+ var inventory_exports = {};
2448
+ __export(inventory_exports, {
2449
+ ATIVIDADE_LABELS: () => ATIVIDADE_LABELS,
2450
+ CADASTRO_LABELS: () => CADASTRO_LABELS,
2451
+ DOMAIN_LABELS: () => DOMAIN_LABELS,
2452
+ FILTER_DIMENSIONS: () => FILTER_DIMENSIONS,
2453
+ INVENTORY_ENTITY_FIELDS: () => INVENTORY_ENTITY_FIELDS,
2454
+ INVENTORY_EXPORT_COLUMNS: () => INVENTORY_EXPORT_COLUMNS,
2455
+ INVENTORY_PDF_COLUMN_KEYS: () => INVENTORY_PDF_COLUMN_KEYS,
2456
+ INVENTORY_RULES: () => INVENTORY_RULES,
2457
+ INVENTORY_SERVER_ATTRIBUTES: () => INVENTORY_SERVER_ATTRIBUTES,
2458
+ LIFECYCLE_LABELS: () => LIFECYCLE_LABELS,
2459
+ NO_CUSTOMER_KEY: () => NO_CUSTOMER_KEY,
2460
+ UNCLASSIFIED_PROFILE_LABEL: () => UNCLASSIFIED_PROFILE_LABEL,
2461
+ applyFilters: () => applyFilters,
2462
+ buildDashboardSummary: () => buildDashboardSummary,
2463
+ buildEntitiesQueryBody: () => buildEntitiesQueryBody,
2464
+ buildExportSummary: () => buildExportSummary,
2465
+ buildInventoryRows: () => buildInventoryRows,
2466
+ buildRuleContext: () => buildRuleContext,
2467
+ compareRows: () => compareRows,
2468
+ createEmptyFilters: () => createEmptyFilters,
2469
+ customerKeyLabel: () => customerKeyLabel,
2470
+ dimensionValues: () => dimensionValues,
2471
+ displayName: () => displayName,
2472
+ evaluateDevice: () => evaluateDevice,
2473
+ exportFileName: () => exportFileName,
2474
+ facetCounts: () => facetCounts,
2475
+ failedRulesText: () => failedRulesText,
2476
+ formatDateTime: () => formatDateTime,
2477
+ formatDeviceLabel: () => formatDeviceLabel,
2478
+ getInventoryRule: () => getInventoryRule,
2479
+ getVisibleGroups: () => getVisibleGroups,
2480
+ getVisibleRows: () => getVisibleRows,
2481
+ groupKey: () => groupKey,
2482
+ guardFormula: () => guardFormula,
2483
+ isBlank: () => isBlank,
2484
+ isRecognizedProfile: () => isRecognizedProfile,
2485
+ matchesFilters: () => matchesFilters,
2486
+ normalizeText: () => normalizeText,
2487
+ parseEntityRow: () => parseEntityRow,
2488
+ pickColumns: () => pickColumns,
2489
+ resolveLifecycle: () => resolveLifecycle,
2490
+ summarizeFilters: () => summarizeFilters,
2491
+ toBooleanStrict: () => toBooleanStrict,
2492
+ toCSV: () => toCSV2,
2493
+ toExportMatrix: () => toExportMatrix,
2494
+ toText: () => toText,
2495
+ toTimestamp: () => toTimestamp
2496
+ });
2497
+
2498
+ // src/utils/devices/inventory/loader.ts
2499
+ var INVENTORY_ENTITY_FIELDS = ["name", "label", "type", "createdTime", "ownerName", "ownerType"];
2500
+ var INVENTORY_SERVER_ATTRIBUTES = [
2501
+ "deviceProfile",
2502
+ "identifier",
2503
+ "ingestionId",
2504
+ "gcdrDeviceId",
2505
+ "centralId",
2506
+ "slaveId",
2507
+ "lifecycleStatus",
2508
+ "active",
2509
+ "lastActivityTime"
2510
+ ];
2511
+ function buildEntitiesQueryBody(page, pageSize) {
2512
+ return {
2513
+ entityFilter: { type: "entityType", entityType: "DEVICE" },
2514
+ entityFields: INVENTORY_ENTITY_FIELDS.map((key) => ({ type: "ENTITY_FIELD", key })),
2515
+ latestValues: INVENTORY_SERVER_ATTRIBUTES.map((key) => ({ type: "SERVER_ATTRIBUTE", key })),
2516
+ pageLink: {
2517
+ page,
2518
+ pageSize,
2519
+ sortOrder: { key: { type: "ENTITY_FIELD", key: "name" }, direction: "ASC" }
2520
+ }
2521
+ };
2522
+ }
2523
+ function isBlank(value) {
2524
+ if (value === null || value === void 0) return true;
2525
+ const s = String(value).trim();
2526
+ return s === "" || /^(null|undefined)$/i.test(s);
2527
+ }
2528
+ function toText(value) {
2529
+ return isBlank(value) ? null : String(value).trim();
2530
+ }
2531
+ function toBooleanStrict(value) {
2532
+ if (value === true || value === false) return value;
2533
+ const s = toText(value);
2534
+ if (s === null) return null;
2535
+ const lower = s.toLowerCase();
2536
+ if (lower === "true") return true;
2537
+ if (lower === "false") return false;
2538
+ return null;
2539
+ }
2540
+ function toTimestamp(value) {
2541
+ if (isBlank(value)) return null;
2542
+ const n = Number(value);
2543
+ return Number.isFinite(n) && n > 0 ? n : null;
2544
+ }
2545
+ function parseEntityRow(raw, options = {}) {
2546
+ const fields = raw.latest?.ENTITY_FIELD || {};
2547
+ const attrs = raw.latest?.SERVER_ATTRIBUTE || {};
2548
+ const field = (key) => fields[key]?.value;
2549
+ const attr = (key) => attrs[key]?.value;
2550
+ const ownerName = toText(field("ownerName"));
2551
+ const ownerType = toText(field("ownerType"));
2552
+ const customerId = ownerType === "CUSTOMER" && ownerName ? options.customerIdByName?.get(ownerName) ?? null : null;
2553
+ return {
2554
+ id: String(raw.entityId?.id || ""),
2555
+ name: toText(field("name")) ?? "",
2556
+ label: toText(field("label")),
2557
+ type: toText(field("type")),
2558
+ createdTime: toTimestamp(field("createdTime")),
2559
+ ownerName,
2560
+ ownerType: ownerType ? ownerType.toUpperCase() : null,
2561
+ customerId,
2562
+ deviceProfile: toText(attr("deviceProfile")),
2563
+ identifier: toText(attr("identifier")),
2564
+ ingestionId: toText(attr("ingestionId")),
2565
+ gcdrDeviceId: toText(attr("gcdrDeviceId")),
2566
+ centralId: toText(attr("centralId")),
2567
+ slaveId: toText(attr("slaveId")),
2568
+ lifecycleStatus: toText(attr("lifecycleStatus")),
2569
+ active: toBooleanStrict(attr("active")),
2570
+ lastActivityTime: toTimestamp(attr("lastActivityTime")),
2571
+ attributesLoaded: options.attributesLoaded !== false
2572
+ };
2573
+ }
2574
+
2575
+ // src/utils/devices/inventory/lifecycle.ts
2576
+ var VALID = /* @__PURE__ */ new Set(["active", "stock", "archived"]);
2577
+ function resolveLifecycle(device) {
2578
+ const raw = (device.lifecycleStatus || "").trim().toLowerCase();
2579
+ const fromAttribute = VALID.has(raw);
2580
+ const status = fromAttribute ? raw : "active";
2581
+ let legacyHint = null;
2582
+ if (status === "active") {
2583
+ if (/ARQUIVAD/i.test(device.deviceProfile || "")) legacyHint = "deviceProfile";
2584
+ else if (/DESATIVAR/i.test(device.ownerName || "")) legacyHint = "customerName";
2585
+ }
2586
+ return { status, source: fromAttribute ? "attribute" : "default", legacyHint };
2587
+ }
2588
+
2589
+ // src/utils/devices/inventory/rules.ts
2590
+ function isRecognizedProfile(deviceProfile) {
2591
+ return !!deviceProfile && Object.prototype.hasOwnProperty.call(DEVICE_TYPE_CONFIG, deviceProfile.toUpperCase());
2592
+ }
2593
+ function isIntegrated(device, ctx) {
2594
+ return !!device.ownerName && device.ownerType === "CUSTOMER" && ctx.integratedCustomers.has(device.ownerName);
2595
+ }
2596
+ function requiredOnIntegrated(pick) {
2597
+ return (device, ctx) => {
2598
+ if (!device.attributesLoaded) return "unknown";
2599
+ if (!isIntegrated(device, ctx)) return "notApplicable";
2600
+ return pick(device) === null ? "fail" : "pass";
2601
+ };
2602
+ }
2603
+ var INVENTORY_RULES = [
2604
+ {
2605
+ id: "C1",
2606
+ axis: "cadastro",
2607
+ severity: "pending",
2608
+ label: "Sem cliente",
2609
+ description: "O dispositivo pertence ao tenant e n\xE3o est\xE1 associado a nenhum cliente.",
2610
+ evaluate: (d) => {
2611
+ if (d.ownerType === null) return "unknown";
2612
+ return d.ownerType === "TENANT" ? "fail" : "pass";
2613
+ }
2614
+ },
2615
+ {
2616
+ id: "C2",
2617
+ axis: "cadastro",
2618
+ severity: "critical",
2619
+ label: "Sem deviceProfile",
2620
+ description: "O atributo deviceProfile n\xE3o est\xE1 preenchido; o dispositivo n\xE3o \xE9 classificado nos dashboards.",
2621
+ evaluate: requiredOnIntegrated((d) => d.deviceProfile)
2622
+ },
2623
+ {
2624
+ id: "C3",
2625
+ axis: "cadastro",
2626
+ severity: "critical",
2627
+ label: "Sem ingestionId",
2628
+ description: "Sem ingestionId, os dados do dispositivo n\xE3o chegam aos relat\xF3rios.",
2629
+ evaluate: requiredOnIntegrated((d) => d.ingestionId)
2630
+ },
2631
+ {
2632
+ id: "C4",
2633
+ axis: "cadastro",
2634
+ severity: "pending",
2635
+ label: "Sem gcdrDeviceId",
2636
+ description: "Sem gcdrDeviceId, alarmes e recursos do GCDR ficam indispon\xEDveis para o dispositivo.",
2637
+ evaluate: requiredOnIntegrated((d) => d.gcdrDeviceId)
2638
+ },
2639
+ {
2640
+ id: "C5",
2641
+ axis: "cadastro",
2642
+ severity: "pending",
2643
+ label: "Perfil n\xE3o reconhecido",
2644
+ description: 'O deviceProfile n\xE3o est\xE1 na lista de perfis conhecidos; o dispositivo aparece como "N\xE3o classificado".',
2645
+ evaluate: (d, ctx) => {
2646
+ if (!d.attributesLoaded) return "unknown";
2647
+ if (!isIntegrated(d, ctx) || d.deviceProfile === null) return "notApplicable";
2648
+ return isRecognizedProfile(d.deviceProfile) ? "pass" : "fail";
2649
+ }
2650
+ },
2651
+ {
2652
+ id: "C6",
2653
+ axis: "cadastro",
2654
+ severity: "info",
2655
+ label: "Perfil diverge do TB",
2656
+ description: "O deviceProfile difere do perfil do dispositivo no ThingsBoard.",
2657
+ evaluate: (d) => {
2658
+ if (!d.attributesLoaded) return "unknown";
2659
+ if (d.deviceProfile === null || d.type === null) return "notApplicable";
2660
+ return d.deviceProfile.toUpperCase() === d.type.toUpperCase() ? "pass" : "fail";
2661
+ }
2662
+ },
2663
+ {
2664
+ id: "C7",
2665
+ axis: "cadastro",
2666
+ severity: "pending",
2667
+ label: "Sem central/slave",
2668
+ description: "Dispositivo de dom\xEDnio ligado a central sem centralId ou slaveId.",
2669
+ evaluate: (d, ctx) => {
2670
+ if (!d.attributesLoaded) return "unknown";
2671
+ if (!isIntegrated(d, ctx) || !isRecognizedProfile(d.deviceProfile)) return "notApplicable";
2672
+ if (!ctx.centralDomains.has(getDeviceCategory(d.deviceProfile))) return "notApplicable";
2673
+ return d.centralId === null || d.slaveId === null ? "fail" : "pass";
2674
+ }
2675
+ },
2676
+ {
2677
+ id: "C8",
2678
+ axis: "cadastro",
2679
+ severity: "critical",
2680
+ label: "ID duplicado",
2681
+ description: "Outro dispositivo ativo usa o mesmo ingestionId ou gcdrDeviceId.",
2682
+ evaluate: (d, ctx) => {
2683
+ if (!d.attributesLoaded) return "unknown";
2684
+ if (d.ingestionId === null && d.gcdrDeviceId === null) return "notApplicable";
2685
+ const dupIngestion = d.ingestionId !== null && (ctx.ingestionIdCounts.get(d.ingestionId) || 0) > 1;
2686
+ const dupGcdr = d.gcdrDeviceId !== null && (ctx.gcdrDeviceIdCounts.get(d.gcdrDeviceId) || 0) > 1;
2687
+ return dupIngestion || dupGcdr ? "fail" : "pass";
2688
+ }
2689
+ },
2690
+ {
2691
+ id: "A1",
2692
+ axis: "atividade",
2693
+ severity: "inactive",
2694
+ label: "Inativo no TB",
2695
+ description: "O ThingsBoard marca o dispositivo como inativo (active = false).",
2696
+ evaluate: (d) => {
2697
+ if (d.active === null) return "unknown";
2698
+ return d.active ? "pass" : "fail";
2699
+ }
2700
+ },
2701
+ {
2702
+ id: "A2",
2703
+ axis: "atividade",
2704
+ severity: "inactive",
2705
+ label: "Sem atividade recente",
2706
+ description: "A \xFAltima atividade registrada \xE9 mais antiga que o limite configurado.",
2707
+ evaluate: (d, ctx) => {
2708
+ if (d.lastActivityTime === null) return "unknown";
2709
+ return ctx.now - d.lastActivityTime > ctx.staleHours * 3600 * 1e3 ? "fail" : "pass";
2710
+ }
2711
+ }
2712
+ ];
2713
+ var RULE_BY_ID = new Map(INVENTORY_RULES.map((r) => [r.id, r]));
2714
+ function getInventoryRule(id) {
2715
+ return RULE_BY_ID.get(id);
2716
+ }
2717
+ function buildRuleContext(devices, options) {
2718
+ const integrated = /* @__PURE__ */ new Set();
2719
+ const ingestionIdCounts = /* @__PURE__ */ new Map();
2720
+ const gcdrDeviceIdCounts = /* @__PURE__ */ new Map();
2721
+ for (const d of devices) {
2722
+ if (d.ownerType === "CUSTOMER" && d.ownerName && (d.ingestionId !== null || d.gcdrDeviceId !== null)) {
2723
+ integrated.add(d.ownerName);
2724
+ }
2725
+ if (resolveLifecycle(d).status === "archived") continue;
2726
+ if (d.ingestionId !== null) ingestionIdCounts.set(d.ingestionId, (ingestionIdCounts.get(d.ingestionId) || 0) + 1);
2727
+ if (d.gcdrDeviceId !== null) gcdrDeviceIdCounts.set(d.gcdrDeviceId, (gcdrDeviceIdCounts.get(d.gcdrDeviceId) || 0) + 1);
2728
+ }
2729
+ for (const [name, expected] of Object.entries(options.integrationOverrides || {})) {
2730
+ if (expected) integrated.add(name);
2731
+ else integrated.delete(name);
2732
+ }
2733
+ return {
2734
+ integratedCustomers: integrated,
2735
+ ingestionIdCounts,
2736
+ gcdrDeviceIdCounts,
2737
+ staleHours: options.staleHours ?? 24,
2738
+ disabledRules: new Set(options.disabledRules ?? ["C6"]),
2739
+ centralDomains: new Set(options.centralDomains ?? ["energy", "water"]),
2740
+ now: options.now
2741
+ };
2742
+ }
2743
+ var CADASTRO_RANK = { critical: 2, pending: 1 };
2744
+ function evaluateDevice(device, ctx) {
2745
+ const lifecycle = resolveLifecycle(device);
2746
+ if (lifecycle.status !== "active") {
2747
+ return {
2748
+ lifecycle,
2749
+ results: INVENTORY_RULES.map((r) => ({ id: r.id, outcome: "notApplicable" })),
2750
+ failed: [],
2751
+ cadastro: { level: "excluded", partial: false },
2752
+ atividade: { level: "excluded", partial: false }
2753
+ };
2754
+ }
2755
+ const results = INVENTORY_RULES.map((rule) => ({
2756
+ id: rule.id,
2757
+ outcome: ctx.disabledRules.has(rule.id) ? "notApplicable" : rule.evaluate(device, ctx)
2758
+ }));
2759
+ const failed = results.filter((r) => r.outcome === "fail").map((r) => r.id);
2760
+ let cadastroRank = 0;
2761
+ let cadastroUnknown = false;
2762
+ let atividadeFail = false;
2763
+ let atividadeUnknown = false;
2764
+ for (const result of results) {
2765
+ const rule = RULE_BY_ID.get(result.id);
2766
+ if (rule.axis === "cadastro") {
2767
+ if (rule.severity === "info") continue;
2768
+ if (result.outcome === "fail") cadastroRank = Math.max(cadastroRank, CADASTRO_RANK[rule.severity] || 0);
2769
+ if (result.outcome === "unknown") cadastroUnknown = true;
2770
+ } else {
2771
+ if (result.outcome === "fail") atividadeFail = true;
2772
+ if (result.outcome === "unknown") atividadeUnknown = true;
2773
+ }
2774
+ }
2775
+ const cadastroLevel = cadastroRank === 2 ? "critical" : cadastroRank === 1 ? "pending" : cadastroUnknown ? "partial" : "ok";
2776
+ const atividadeLevel = atividadeFail ? "inactive" : atividadeUnknown ? "nodata" : "ok";
2777
+ return {
2778
+ lifecycle,
2779
+ results,
2780
+ failed,
2781
+ cadastro: { level: cadastroLevel, partial: cadastroRank > 0 && cadastroUnknown },
2782
+ atividade: { level: atividadeLevel, partial: atividadeFail && atividadeUnknown }
2783
+ };
2784
+ }
2785
+
2786
+ // src/utils/devices/inventory/labels.ts
2787
+ var CADASTRO_LABELS = {
2788
+ ok: "\xCDntegro",
2789
+ pending: "Pendente",
2790
+ critical: "Cr\xEDtico",
2791
+ partial: "Parcial",
2792
+ excluded: "Fora dos indicadores"
2793
+ };
2794
+ var ATIVIDADE_LABELS = {
2795
+ ok: "Reportando",
2796
+ inactive: "Sem atividade",
2797
+ nodata: "Sem dado",
2798
+ excluded: "Fora dos indicadores"
2799
+ };
2800
+ var LIFECYCLE_LABELS = {
2801
+ active: "Ativo",
2802
+ stock: "Estoque",
2803
+ archived: "Arquivado"
2804
+ };
2805
+ var DOMAIN_LABELS = {
2806
+ energy: "Energia",
2807
+ water: "\xC1gua",
2808
+ temperature: "Temperatura",
2809
+ tank: "Reservat\xF3rio",
2810
+ solenoid: "Solenoide",
2811
+ unclassified: "N\xE3o classificado"
2812
+ };
2813
+
2814
+ // src/utils/devices/inventory/filters.ts
2815
+ var NO_CUSTOMER_KEY = "__no_customer__";
2816
+ var UNCLASSIFIED_PROFILE_LABEL = "N\xE3o classificado";
2817
+ function buildInventoryRows(devices, options) {
2818
+ const ctx = "context" in options ? options.context : buildRuleContext(devices, options);
2819
+ return devices.map((device) => {
2820
+ const recognized = isRecognizedProfile(device.deviceProfile);
2821
+ return {
2822
+ device,
2823
+ evaluation: evaluateDevice(device, ctx),
2824
+ domain: recognized ? getDeviceCategory(device.deviceProfile) : "unclassified",
2825
+ profileLabel: recognized ? device.deviceProfile.toUpperCase() : UNCLASSIFIED_PROFILE_LABEL,
2826
+ customerKey: device.ownerType === "TENANT" || !device.ownerName ? NO_CUSTOMER_KEY : device.ownerName
2827
+ };
2828
+ });
2829
+ }
2830
+ var FILTER_DIMENSIONS = [
2831
+ "customers",
2832
+ "domains",
2833
+ "profiles",
2834
+ "cadastro",
2835
+ "atividade",
2836
+ "rules",
2837
+ "lifecycle"
2838
+ ];
2839
+ function createEmptyFilters() {
2840
+ return {
2841
+ customers: /* @__PURE__ */ new Set(),
2842
+ domains: /* @__PURE__ */ new Set(),
2843
+ profiles: /* @__PURE__ */ new Set(),
2844
+ cadastro: /* @__PURE__ */ new Set(),
2845
+ atividade: /* @__PURE__ */ new Set(),
2846
+ rules: /* @__PURE__ */ new Set(),
2847
+ lifecycle: /* @__PURE__ */ new Set(["active"]),
2848
+ text: ""
2849
+ };
2850
+ }
2851
+ function normalizeText(value) {
2852
+ return String(value || "").normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().trim();
2853
+ }
2854
+ function dimensionValues(row, dimension) {
2855
+ switch (dimension) {
2856
+ case "customers":
2857
+ return [row.customerKey];
2858
+ case "domains":
2859
+ return [row.domain];
2860
+ case "profiles":
2861
+ return [row.profileLabel];
2862
+ case "cadastro":
2863
+ return row.evaluation.cadastro.level === "excluded" ? [] : [row.evaluation.cadastro.level];
2864
+ case "atividade":
2865
+ return row.evaluation.atividade.level === "excluded" ? [] : [row.evaluation.atividade.level];
2866
+ case "rules":
2867
+ return row.evaluation.failed;
2868
+ case "lifecycle":
2869
+ return [row.evaluation.lifecycle.status];
2870
+ }
2871
+ }
2872
+ function matchesText(row, needle) {
2873
+ if (!needle) return true;
2874
+ const d = row.device;
2875
+ return [d.label, d.name, d.identifier, row.profileLabel, d.deviceProfile, d.ownerName, d.ingestionId].some(
2876
+ (v) => normalizeText(v).includes(needle)
2877
+ );
2878
+ }
2879
+ function matchesFilters(row, filters, except) {
2880
+ for (const dimension of FILTER_DIMENSIONS) {
2881
+ if (dimension === except) continue;
2882
+ const selected = filters[dimension];
2883
+ if (selected.size === 0) continue;
2884
+ if (!dimensionValues(row, dimension).some((v) => selected.has(v))) return false;
2885
+ }
2886
+ return matchesText(row, normalizeText(filters.text));
2887
+ }
2888
+ function applyFilters(rows, filters) {
2889
+ return rows.filter((row) => matchesFilters(row, filters));
2890
+ }
2891
+ function facetCounts(rows, filters, dimension) {
2892
+ const counts = /* @__PURE__ */ new Map();
2893
+ for (const row of rows) {
2894
+ if (!matchesFilters(row, filters, dimension)) continue;
2895
+ for (const value of dimensionValues(row, dimension)) counts.set(value, (counts.get(value) || 0) + 1);
2896
+ }
2897
+ return counts;
2898
+ }
2899
+ var CADASTRO_ORDER = { critical: 0, pending: 1, partial: 2, ok: 3, excluded: 4 };
2900
+ var ATIVIDADE_ORDER = { inactive: 0, nodata: 1, ok: 2, excluded: 3 };
2901
+ function displayName(row) {
2902
+ return row.device.label || row.device.name;
2903
+ }
2904
+ function compareText(a, b) {
2905
+ return a.localeCompare(b, "pt-BR", { sensitivity: "base", numeric: true });
2906
+ }
2907
+ function compareRows(a, b, sort) {
2908
+ switch (sort) {
2909
+ case "gravity": {
2910
+ const c = CADASTRO_ORDER[a.evaluation.cadastro.level] - CADASTRO_ORDER[b.evaluation.cadastro.level];
2911
+ if (c) return c;
2912
+ const t = ATIVIDADE_ORDER[a.evaluation.atividade.level] - ATIVIDADE_ORDER[b.evaluation.atividade.level];
2913
+ if (t) return t;
2914
+ break;
2915
+ }
2916
+ case "customer": {
2917
+ const c = compareText(a.device.ownerName || "", b.device.ownerName || "");
2918
+ if (c) return c;
2919
+ break;
2920
+ }
2921
+ case "lastActivity": {
2922
+ const ta = a.device.lastActivityTime ?? -Infinity;
2923
+ const tb = b.device.lastActivityTime ?? -Infinity;
2924
+ if (ta !== tb) return ta < tb ? -1 : 1;
2925
+ break;
2926
+ }
2927
+ case "label":
2928
+ break;
2929
+ }
2930
+ return compareText(displayName(a), displayName(b)) || compareText(a.device.name, b.device.name);
2931
+ }
2932
+ function groupKey(row, groupBy) {
2933
+ switch (groupBy) {
2934
+ case "customer":
2935
+ return row.customerKey;
2936
+ case "domain":
2937
+ return row.domain;
2938
+ case "profile":
2939
+ return row.profileLabel;
2940
+ case "none":
2941
+ return "";
2942
+ }
2943
+ }
2944
+ function getVisibleGroups(rows, filters, sort, groupBy) {
2945
+ const groups = /* @__PURE__ */ new Map();
2946
+ for (const row of applyFilters(rows, filters)) {
2947
+ const key = groupKey(row, groupBy);
2948
+ if (!groups.has(key)) groups.set(key, []);
2949
+ groups.get(key).push(row);
2950
+ }
2951
+ const title = (key) => groupBy === "domain" ? DOMAIN_LABELS[key] || key : key;
2952
+ const keys = [...groups.keys()].sort((a, b) => {
2953
+ if (a === NO_CUSTOMER_KEY) return -1;
2954
+ if (b === NO_CUSTOMER_KEY) return 1;
2955
+ return compareText(title(a), title(b));
2956
+ });
2957
+ return keys.map((key) => ({ key, rows: groups.get(key).sort((x, y) => compareRows(x, y, sort)) }));
2958
+ }
2959
+ function getVisibleRows(rows, filters, sort, groupBy) {
2960
+ return getVisibleGroups(rows, filters, sort, groupBy).flatMap((g) => g.rows);
2961
+ }
2962
+
2963
+ // src/utils/devices/inventory/dashboard.ts
2964
+ function buildDashboardSummary(rows, options = {}) {
2965
+ const cadastro = { ok: 0, pending: 0, critical: 0, partial: 0 };
2966
+ const atividade = { ok: 0, inactive: 0, nodata: 0 };
2967
+ const excluded = { stock: 0, archived: 0 };
2968
+ const byCustomer = /* @__PURE__ */ new Map();
2969
+ const ruleCounts = /* @__PURE__ */ new Map();
2970
+ const failuresByCustomerRule = /* @__PURE__ */ new Map();
2971
+ for (const row of rows) {
2972
+ const { lifecycle, cadastro: cad, atividade: atv, failed } = row.evaluation;
2973
+ if (lifecycle.status !== "active") {
2974
+ excluded[lifecycle.status]++;
2975
+ continue;
2976
+ }
2977
+ if (cad.level !== "excluded") cadastro[cad.level]++;
2978
+ if (atv.level !== "excluded") atividade[atv.level]++;
2979
+ const customer = byCustomer.get(row.customerKey) || { key: row.customerKey, critical: 0, pending: 0, total: 0 };
2980
+ customer.total++;
2981
+ if (cad.level === "critical") customer.critical++;
2982
+ if (cad.level === "pending") customer.pending++;
2983
+ byCustomer.set(row.customerKey, customer);
2984
+ for (const id of failed) {
2985
+ ruleCounts.set(id, (ruleCounts.get(id) || 0) + 1);
2986
+ const perRule = failuresByCustomerRule.get(row.customerKey) || /* @__PURE__ */ new Map();
2987
+ perRule.set(id, (perRule.get(id) || 0) + 1);
2988
+ failuresByCustomerRule.set(row.customerKey, perRule);
2989
+ }
2990
+ }
2991
+ const ruleOrder = new Map(INVENTORY_RULES.map((r, i) => [r.id, i]));
2992
+ const topRules = [...ruleCounts.entries()].map(([id, count]) => ({ id, label: getInventoryRule(id)?.label || id, count })).sort((a, b) => b.count - a.count || (ruleOrder.get(a.id) ?? 99) - (ruleOrder.get(b.id) ?? 99));
2993
+ const worstFirst = (a, b) => b.critical - a.critical || b.pending - a.pending || a.key.localeCompare(b.key, "pt-BR");
2994
+ const topCustomers = [...byCustomer.values()].filter((c) => c.critical + c.pending > 0).sort(worstFirst).slice(0, options.topCustomers ?? 10);
2995
+ const failureTotal = (key) => [...failuresByCustomerRule.get(key)?.values() || []].reduce((s, n) => s + n, 0);
2996
+ const matrixCustomers = [...failuresByCustomerRule.keys()].sort((a, b) => failureTotal(b) - failureTotal(a) || a.localeCompare(b, "pt-BR")).slice(0, options.matrixCustomers ?? 15);
2997
+ const matrixRules = topRules.map((r) => r.id);
2998
+ return {
2999
+ total: rows.length,
3000
+ inIndicators: rows.length - excluded.stock - excluded.archived,
3001
+ excluded,
3002
+ cadastro,
3003
+ atividade,
3004
+ topCustomers,
3005
+ topRules,
3006
+ matrix: {
3007
+ customers: matrixCustomers,
3008
+ rules: matrixRules,
3009
+ cells: matrixCustomers.map((c) => matrixRules.map((r) => failuresByCustomerRule.get(c)?.get(r) || 0))
3010
+ }
3011
+ };
3012
+ }
3013
+ function customerKeyLabel(key) {
3014
+ return key === NO_CUSTOMER_KEY ? "Sem cliente" : key;
3015
+ }
3016
+
3017
+ // src/utils/devices/inventory/formatLabel.ts
3018
+ function formatDeviceLabel(device) {
3019
+ const name = String(device.name ?? "").trim();
3020
+ const label = String(device.label ?? "").trim();
3021
+ if (!label || label === name) return { primary: name, secondary: null };
3022
+ return { primary: label, secondary: name || null };
3023
+ }
3024
+
3025
+ // src/utils/devices/inventory/exportRows.ts
3026
+ function formatDateTime(ms) {
3027
+ if (ms === null) return "";
3028
+ const d = new Date(ms);
3029
+ if (Number.isNaN(d.getTime())) return "";
3030
+ return d.toLocaleString("pt-BR", {
3031
+ timeZone: "America/Sao_Paulo",
3032
+ day: "2-digit",
3033
+ month: "2-digit",
3034
+ year: "numeric",
3035
+ hour: "2-digit",
3036
+ minute: "2-digit"
3037
+ });
3038
+ }
3039
+ function cadastroText(row) {
3040
+ const { level, partial } = row.evaluation.cadastro;
3041
+ return CADASTRO_LABELS[level] + (partial ? " \xB7 avalia\xE7\xE3o parcial" : "");
3042
+ }
3043
+ function failedRulesText(row) {
3044
+ return row.evaluation.failed.map((id) => getInventoryRule(id)?.label || id).join("; ");
3045
+ }
3046
+ var col = (key, header, value) => ({
3047
+ key,
3048
+ header,
3049
+ value: (row) => {
3050
+ const v = value(row);
3051
+ return v === null || v === void 0 ? "" : String(v);
3052
+ }
3053
+ });
3054
+ var INVENTORY_EXPORT_COLUMNS = [
3055
+ col("cadastro", "Cadastro", cadastroText),
3056
+ col("atividade", "Atividade", (r) => ATIVIDADE_LABELS[r.evaluation.atividade.level]),
3057
+ col("reasons", "Regras com falha", failedRulesText),
3058
+ col("label", "Label", (r) => r.device.label),
3059
+ col("name", "Name", (r) => r.device.name),
3060
+ col("deviceId", "deviceId", (r) => r.device.id),
3061
+ col("identifier", "Identificador", (r) => r.device.identifier),
3062
+ col("profile", "Perfil", (r) => r.profileLabel),
3063
+ col("domain", "Dom\xEDnio", (r) => DOMAIN_LABELS[r.domain] || r.domain),
3064
+ col("customer", "Cliente", (r) => r.customerKey === NO_CUSTOMER_KEY ? "" : r.device.ownerName),
3065
+ col("customerId", "customerId", (r) => r.device.customerId),
3066
+ col("lifecycle", "Ciclo de vida", (r) => LIFECYCLE_LABELS[r.evaluation.lifecycle.status]),
3067
+ col("active", "Ativo (TB)", (r) => r.device.active === null ? "" : r.device.active ? "Sim" : "N\xE3o"),
3068
+ col("lastActivity", "\xDAltima atividade", (r) => formatDateTime(r.device.lastActivityTime)),
3069
+ col("ingestionId", "ingestionId", (r) => r.device.ingestionId),
3070
+ col("gcdrDeviceId", "gcdrDeviceId", (r) => r.device.gcdrDeviceId),
3071
+ col("centralId", "centralId", (r) => r.device.centralId),
3072
+ col("slaveId", "slaveId", (r) => r.device.slaveId),
3073
+ col("created", "Criado em", (r) => formatDateTime(r.device.createdTime))
3074
+ ];
3075
+ var INVENTORY_PDF_COLUMN_KEYS = [
3076
+ "cadastro",
3077
+ "atividade",
3078
+ "label",
3079
+ "name",
3080
+ "profile",
3081
+ "customer",
3082
+ "reasons",
3083
+ "lastActivity"
3084
+ ];
3085
+ function pickColumns(keys) {
3086
+ return keys.map((k) => {
3087
+ const c = INVENTORY_EXPORT_COLUMNS.find((x) => x.key === k);
3088
+ if (!c) throw new Error(`Unknown inventory export column: ${k}`);
3089
+ return c;
3090
+ });
3091
+ }
3092
+ function toExportMatrix(rows, columns = INVENTORY_EXPORT_COLUMNS) {
3093
+ return {
3094
+ header: columns.map((c) => c.header),
3095
+ rows: rows.map((row) => columns.map((c) => c.value(row)))
3096
+ };
3097
+ }
3098
+ function guardFormula(value) {
3099
+ return /^[=+\-@\t\r]/.test(value) ? `'${value}` : value;
3100
+ }
3101
+ function csvCell(value) {
3102
+ const safe = guardFormula(value);
3103
+ return /[";\r\n]/.test(safe) ? `"${safe.replace(/"/g, '""')}"` : safe;
3104
+ }
3105
+ function toCSV2(matrix) {
3106
+ const lines = [matrix.header, ...matrix.rows].map((cells) => cells.map(csvCell).join(";"));
3107
+ return "\uFEFF" + lines.join("\r\n") + "\r\n";
3108
+ }
3109
+ function summarizeFilters(filters) {
3110
+ const out = [];
3111
+ const list = (set, map) => [...set].map((v) => map ? map(v) : v).join(", ");
3112
+ if (filters.customers.size) {
3113
+ out.push(["Cliente", list(filters.customers, (v) => v === NO_CUSTOMER_KEY ? "Sem cliente" : v)]);
3114
+ }
3115
+ if (filters.domains.size) out.push(["Dom\xEDnio", list(filters.domains, (v) => DOMAIN_LABELS[v] || v)]);
3116
+ if (filters.profiles.size) out.push(["Perfil", list(filters.profiles)]);
3117
+ if (filters.cadastro.size) out.push(["Cadastro", list(filters.cadastro, (v) => CADASTRO_LABELS[v])]);
3118
+ if (filters.atividade.size) {
3119
+ out.push(["Atividade", list(filters.atividade, (v) => ATIVIDADE_LABELS[v])]);
3120
+ }
3121
+ if (filters.rules.size) out.push(["Regra", list(filters.rules, (v) => getInventoryRule(v)?.label || v)]);
3122
+ if (filters.lifecycle.size) {
3123
+ out.push(["Ciclo de vida", list(filters.lifecycle, (v) => LIFECYCLE_LABELS[v])]);
3124
+ }
3125
+ if (filters.text.trim()) out.push(["Busca", filters.text.trim()]);
3126
+ return out;
3127
+ }
3128
+ function buildExportSummary(filters, dashboard, meta) {
3129
+ const n = (v) => v.toLocaleString("pt-BR");
3130
+ const active = summarizeFilters(filters);
3131
+ return [
3132
+ ["Gerado em", formatDateTime(meta.generatedAt)],
3133
+ ["Gerado por", meta.generatedBy || ""],
3134
+ ["Dispositivos exportados", n(meta.exported)],
3135
+ ...active.length ? active : [["Filtros", "Nenhum (todos os dispositivos)"]],
3136
+ ["Nos indicadores", n(dashboard.inIndicators)],
3137
+ [`Cadastro \xB7 ${CADASTRO_LABELS.critical}`, n(dashboard.cadastro.critical)],
3138
+ [`Cadastro \xB7 ${CADASTRO_LABELS.pending}`, n(dashboard.cadastro.pending)],
3139
+ [`Cadastro \xB7 ${CADASTRO_LABELS.ok}`, n(dashboard.cadastro.ok)],
3140
+ [`Cadastro \xB7 ${CADASTRO_LABELS.partial}`, n(dashboard.cadastro.partial)],
3141
+ [`Atividade \xB7 ${ATIVIDADE_LABELS.ok}`, n(dashboard.atividade.ok)],
3142
+ [`Atividade \xB7 ${ATIVIDADE_LABELS.inactive}`, n(dashboard.atividade.inactive)],
3143
+ [`Atividade \xB7 ${ATIVIDADE_LABELS.nodata}`, n(dashboard.atividade.nodata)],
3144
+ ["Fora dos indicadores (estoque / arquivados)", `${n(dashboard.excluded.stock)} / ${n(dashboard.excluded.archived)}`]
3145
+ ];
3146
+ }
3147
+ function exportFileName(filters, ext, now) {
3148
+ const only = filters.customers.size === 1 ? [...filters.customers][0] : null;
3149
+ const scope = !only ? "todos" : only === NO_CUSTOMER_KEY ? "sem-cliente" : only;
3150
+ const slug = normalizeSlug(scope);
3151
+ const pad3 = (n) => String(n).padStart(2, "0");
3152
+ const stamp = `${now.getFullYear()}-${pad3(now.getMonth() + 1)}-${pad3(now.getDate())}_${pad3(now.getHours())}${pad3(now.getMinutes())}`;
3153
+ return `inventario_${slug}_${stamp}.${ext}`;
3154
+ }
3155
+ function normalizeSlug(value) {
3156
+ return value.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "todos";
3157
+ }
3158
+
2445
3159
  // src/utils/devices/device.ts
2446
3160
  var LETTERS = "ABCDEFGHJKLMNPQRSTUVWXYZ";
2447
3161
  var DIGITS = "23456789";
@@ -3553,9 +4267,9 @@ function selectBreakdownItems(groups, profile = getActiveProfile(), domain = "en
3553
4267
  out.push({ item, forcedCategory: null, sourceGroup: baseGroup, fromBaseGroup: true });
3554
4268
  }
3555
4269
  if (includes.size === 0) return out;
3556
- for (const groupKey of Object.keys(groups || {})) {
3557
- if (groupKey === baseGroup) continue;
3558
- for (const item of groups[groupKey] ?? []) {
4270
+ for (const groupKey2 of Object.keys(groups || {})) {
4271
+ if (groupKey2 === baseGroup) continue;
4272
+ for (const item of groups[groupKey2] ?? []) {
3559
4273
  const key = normalizeDeviceOverrideId(item?.id);
3560
4274
  if (!key || excludes.has(key) || seen.has(key)) continue;
3561
4275
  const forced = includes.get(key);
@@ -3564,7 +4278,7 @@ function selectBreakdownItems(groups, profile = getActiveProfile(), domain = "en
3564
4278
  out.push({
3565
4279
  item,
3566
4280
  forcedCategory: forced,
3567
- sourceGroup: groupKey,
4281
+ sourceGroup: groupKey2,
3568
4282
  fromBaseGroup: false,
3569
4283
  ...parentFlag(key)
3570
4284
  });
@@ -4015,13 +4729,13 @@ function resolveClassification(item, tree) {
4015
4729
  if (!current) return null;
4016
4730
  return { key: current.key, nodePath: path, matchedBy };
4017
4731
  }
4018
- function resolveSubcategory(item, groupKey, tree) {
4019
- const group = findNode(tree, groupKey);
4732
+ function resolveSubcategory(item, groupKey2, tree) {
4733
+ const group = findNode(tree, groupKey2);
4020
4734
  if (!group) return null;
4021
4735
  const kids = classifiable(group.children ?? []);
4022
4736
  if (kids.length === 0) return null;
4023
4737
  const r = resolveClassification(item, kids);
4024
- return r ? { ...r, nodePath: [groupKey, ...r.nodePath] } : null;
4738
+ return r ? { ...r, nodePath: [groupKey2, ...r.nodePath] } : null;
4025
4739
  }
4026
4740
  function findNode(tree, key) {
4027
4741
  for (const n of tree ?? []) {
@@ -9089,7 +9803,7 @@ function sortDevices(a, b, sortMode, config2) {
9089
9803
  return (a.label || "").localeCompare(b.label || "", "pt-BR", { sensitivity: "base" }) || a.value - b.value;
9090
9804
  }
9091
9805
  }
9092
- function applyFilters(config2, STATE, enriched) {
9806
+ function applyFilters2(config2, STATE, enriched) {
9093
9807
  let v = enriched.slice();
9094
9808
  if (STATE.selectedShoppingIds?.length > 0) {
9095
9809
  v = v.filter((x) => {
@@ -9588,7 +10302,7 @@ function createWidgetController(config2) {
9588
10302
  };
9589
10303
  let $root = null;
9590
10304
  async function reflow() {
9591
- const filtered = applyFilters(config2, STATE, STATE.itemsEnriched);
10305
+ const filtered = applyFilters2(config2, STATE, STATE.itemsEnriched);
9592
10306
  const { visible } = recomputePercentages(filtered);
9593
10307
  updateStats(config2, visible, context);
9594
10308
  await renderList(config2, STATE, visible, context);
@@ -9797,7 +10511,7 @@ function createWidgetController(config2) {
9797
10511
  var DeviceGridWidgetFactory = {
9798
10512
  createWidgetController,
9799
10513
  createState,
9800
- applyFilters,
10514
+ applyFilters: applyFilters2,
9801
10515
  recomputePercentages,
9802
10516
  buildEntityObject,
9803
10517
  renderList,
@@ -78602,7 +79316,7 @@ function formatDate4(date, locale) {
78602
79316
  year: "numeric"
78603
79317
  });
78604
79318
  }
78605
- function formatDateTime(date, locale) {
79319
+ function formatDateTime2(date, locale) {
78606
79320
  return date.toLocaleDateString(locale, {
78607
79321
  day: "2-digit",
78608
79322
  month: "2-digit",
@@ -78728,7 +79442,7 @@ function processMultiSeriesChartData(rawData, keys, correctionFactor, locale, ag
78728
79442
  value: maxPoint.y,
78729
79443
  timestamp: maxPoint.x,
78730
79444
  formattedValue: maxPoint.y.toFixed(2),
78731
- formattedTime: formatDateTime(new Date(maxPoint.x), locale),
79445
+ formattedTime: formatDateTime2(new Date(maxPoint.x), locale),
78732
79446
  key
78733
79447
  };
78734
79448
  if (!globalPeak || seriesPeak.value > globalPeak.value) {
@@ -82257,8 +82971,8 @@ function buildReportItemsList(groups, domain, group) {
82257
82971
  if (group === "todos") {
82258
82972
  return Object.entries(g).filter(([key]) => key !== "ocultos").flatMap(([key, items]) => (items || []).map((d) => toItem(d, domain, GROUP_LABELS[key] || key)));
82259
82973
  }
82260
- const groupKey = group === "area_comum" ? "areacomum" : group;
82261
- return (g[groupKey] || []).map((d) => toItem(d, domain, null));
82974
+ const groupKey2 = group === "area_comum" ? "areacomum" : group;
82975
+ return (g[groupKey2] || []).map((d) => toItem(d, domain, null));
82262
82976
  }
82263
82977
 
82264
82978
  // src/components/premium-modals/reports-hub/handlers.ts
@@ -100360,7 +101074,7 @@ var DOMAIN_ICONS = {
100360
101074
  water: DOMAIN_MAP.water.icon,
100361
101075
  temperature: DOMAIN_MAP.temperature.icon
100362
101076
  };
100363
- var DOMAIN_LABELS = {
101077
+ var DOMAIN_LABELS2 = {
100364
101078
  energy: DOMAIN_MAP.energy.name,
100365
101079
  water: DOMAIN_MAP.water.name,
100366
101080
  temperature: DOMAIN_MAP.temperature.name
@@ -100679,10 +101393,10 @@ function buildTemplateExport(params) {
100679
101393
  locale,
100680
101394
  includeChart,
100681
101395
  includeStats,
100682
- headerText: headerText || `${DOMAIN_LABELS[domain]} Report`,
101396
+ headerText: headerText || `${DOMAIN_LABELS2[domain]} Report`,
100683
101397
  footerText: footerText || "Generated by MyIO Platform",
100684
101398
  domainIcon: DOMAIN_ICONS[domain],
100685
- domainLabel: DOMAIN_LABELS[domain],
101399
+ domainLabel: DOMAIN_LABELS2[domain],
100686
101400
  domainUnit: DOMAIN_UNITS[domain]
100687
101401
  };
100688
101402
  }
@@ -100774,7 +101488,7 @@ function myioExportData(data, config2, options) {
100774
101488
  }
100775
101489
  var EXPORT_DEFAULT_COLORS = DEFAULT_COLORS4;
100776
101490
  var EXPORT_DOMAIN_ICONS = DOMAIN_ICONS;
100777
- var EXPORT_DOMAIN_LABELS = DOMAIN_LABELS;
101491
+ var EXPORT_DOMAIN_LABELS = DOMAIN_LABELS2;
100778
101492
  var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
100779
101493
 
100780
101494
  // src/components/DistributionChart/colorManager.ts
@@ -108641,11 +109355,11 @@ function renderStep2(state6, modalId, colors2, t) {
108641
109355
  const sortedDevices = sortDevices2(searchFilteredDevices, sortField, sortOrder);
108642
109356
  const gridHeight = state6.isMaximized ? "calc(100vh - 340px)" : "360px";
108643
109357
  const hasActiveFilters = filterTypes.length > 0 || filterDeviceTypes.length > 0 || filterDeviceProfiles.length > 0 || filterStatuses.length > 0 || filterTelemetryKeys.length > 0;
108644
- const renderSortableHeader = (col, label, field, width) => {
109358
+ const renderSortableHeader = (col2, label, field, width) => {
108645
109359
  const isActive = sortField === field;
108646
109360
  const arrow = isActive ? sortOrder === "asc" ? "\u25B2" : "\u25BC" : "\u25BD";
108647
109361
  return `
108648
- <div id="${modalId}-sort-col-${col}" data-sort-field="${field}" style="
109362
+ <div id="${modalId}-sort-col-${col2}" data-sort-field="${field}" style="
108649
109363
  width: ${width}px; padding: 0 6px; display: flex; align-items: center; justify-content: space-between;
108650
109364
  border-right: 1px solid ${colors2.border}; cursor: pointer; user-select: none;
108651
109365
  ${isActive ? `background: rgba(62,26,125,0.1);` : ""}
@@ -110519,8 +111233,8 @@ function setupEventListeners5(container, state6, modalId, t, onClose) {
110519
111233
  { col: "centralId", field: "centralId" },
110520
111234
  { col: "slaveId", field: "slaveId" }
110521
111235
  ];
110522
- sortableColumns.forEach(({ col, field }) => {
110523
- document.getElementById(`${modalId}-sort-col-${col}`)?.addEventListener("click", () => {
111236
+ sortableColumns.forEach(({ col: col2, field }) => {
111237
+ document.getElementById(`${modalId}-sort-col-${col2}`)?.addEventListener("click", () => {
110524
111238
  if (state6.deviceSort.field === field) {
110525
111239
  state6.deviceSort.order = state6.deviceSort.order === "asc" ? "desc" : "asc";
110526
111240
  } else {
@@ -116420,10 +117134,10 @@ var UserListTab = class {
116420
117134
  const popup = document.createElement("div");
116421
117135
  popup.className = "um-assign-popup";
116422
117136
  popup.setAttribute("data-theme", this.config.theme || "light");
116423
- const displayName = this.displayName(user);
117137
+ const displayName2 = this.displayName(user);
116424
117138
  popup.innerHTML = `
116425
117139
  <div class="um-assign-popup-header">
116426
- <span class="um-assign-popup-title">\u{1F511} Fun\xE7\xF5es \u2014 ${this.esc(displayName)}</span>
117140
+ <span class="um-assign-popup-title">\u{1F511} Fun\xE7\xF5es \u2014 ${this.esc(displayName2)}</span>
116427
117141
  <button class="um-assign-popup-close" type="button">\u2715</button>
116428
117142
  </div>
116429
117143
  <div class="um-assign-popup-body">
@@ -116545,7 +117259,7 @@ var UserListTab = class {
116545
117259
  tooltip.setAttribute("data-theme", this.config.theme || "light");
116546
117260
  this.syncTooltipEl = tooltip;
116547
117261
  const syncing = this.gcdrSyncing.has(uid2);
116548
- const displayName = this.displayName(user);
117262
+ const displayName2 = this.displayName(user);
116549
117263
  let bodyHtml;
116550
117264
  if (syncing) {
116551
117265
  bodyHtml = `<div class="um-sync-tooltip-row" style="justify-content:center;padding:8px 0;">
@@ -116595,7 +117309,7 @@ var UserListTab = class {
116595
117309
  <polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/>
116596
117310
  <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/>
116597
117311
  </svg>
116598
- <span>GCDR Sync \u2014 ${this.esc(displayName)}</span>
117312
+ <span>GCDR Sync \u2014 ${this.esc(displayName2)}</span>
116599
117313
  </div>
116600
117314
  <div class="um-sync-tooltip-body">${bodyHtml}</div>
116601
117315
  `;
@@ -123663,9 +124377,9 @@ var MenuView = class {
123663
124377
  const isActive = isActiveTab && contextId === currentContextId;
123664
124378
  el2.classList.toggle("is-active", isActive);
123665
124379
  });
123666
- this.root.querySelectorAll(".myio-unified-column").forEach((col) => {
123667
- const tabId = col.classList.contains("energy") ? "energy" : col.classList.contains("water") ? "water" : col.classList.contains("temperature") ? "temperature" : "";
123668
- col.classList.toggle("is-active-column", tabId === this.activeTabId);
124380
+ this.root.querySelectorAll(".myio-unified-column").forEach((col2) => {
124381
+ const tabId = col2.classList.contains("energy") ? "energy" : col2.classList.contains("water") ? "water" : col2.classList.contains("temperature") ? "temperature" : "";
124382
+ col2.classList.toggle("is-active-column", tabId === this.activeTabId);
123669
124383
  });
123670
124384
  }
123671
124385
  /**
@@ -137632,8 +138346,8 @@ var TelemetryGridShoppingView = class {
137632
138346
  this.controller.setSortMode(mode);
137633
138347
  });
137634
138348
  });
137635
- const applyFilters2 = this.filterModalEl.querySelector("#applyFilters");
137636
- applyFilters2?.addEventListener("click", () => {
138349
+ const applyFilters3 = this.filterModalEl.querySelector("#applyFilters");
138350
+ applyFilters3?.addEventListener("click", () => {
137637
138351
  this.applySelectedFilters();
137638
138352
  this.closeFilterModal();
137639
138353
  this.renderCards();
@@ -147064,11 +147778,11 @@ var AlarmsNotificationsPanelView = class {
147064
147778
  this.root.addEventListener("click", (e) => {
147065
147779
  const th = e.target.closest("[data-sort-col]");
147066
147780
  if (!th) return;
147067
- const col = th.getAttribute("data-sort-col");
147068
- if (this.sortCol === col) {
147781
+ const col2 = th.getAttribute("data-sort-col");
147782
+ if (this.sortCol === col2) {
147069
147783
  this.sortDir = this.sortDir === "asc" ? "desc" : "asc";
147070
147784
  } else {
147071
- this.sortCol = col;
147785
+ this.sortCol = col2;
147072
147786
  this.sortDir = "asc";
147073
147787
  }
147074
147788
  this.renderListContent(this.controller.getState());
@@ -147712,10 +148426,10 @@ var AlarmsNotificationsPanelView = class {
147712
148426
  }
147713
148427
  });
147714
148428
  }
147715
- const th = (label, col, extraClass = "") => {
147716
- const active = this.sortCol === col;
148429
+ const th = (label, col2, extraClass = "") => {
148430
+ const active = this.sortCol === col2;
147717
148431
  const icon2 = active ? `<span class="atbl-sort-icon is-active">${this.sortDir === "asc" ? "\u25B2" : "\u25BC"}</span>` : `<span class="atbl-sort-icon">\u21C5</span>`;
147718
- return `<th class="atbl-th atbl-th--sortable${extraClass ? " " + extraClass : ""}${active ? " is-sorted" : ""}" data-sort-col="${col}">${label}${icon2}</th>`;
148432
+ return `<th class="atbl-th atbl-th--sortable${extraClass ? " " + extraClass : ""}${active ? " is-sorted" : ""}" data-sort-col="${col2}">${label}${icon2}</th>`;
147719
148433
  };
147720
148434
  const rows = alarms.map((alarm) => {
147721
148435
  const sev = SEVERITY_CONFIG[alarm.severity];
@@ -148442,10 +149156,10 @@ var AlarmsNotificationsPanelView = class {
148442
149156
  const gOcc = totalOcc(groupAlarms);
148443
149157
  const gSCfg = severityCfg(gSev);
148444
149158
  const gStCfg = stateCfg(gSt);
148445
- const groupKey = `${ruleKey}||${central}`;
148446
- const isGroupOpen = this.ruleFirstOpenGroups.has(groupKey);
149159
+ const groupKey2 = `${ruleKey}||${central}`;
149160
+ const isGroupOpen = this.ruleFirstOpenGroups.has(groupKey2);
148447
149161
  const escCentral = this.esc(central);
148448
- const escGroupKey = this.esc(groupKey);
149162
+ const escGroupKey = this.esc(groupKey2);
148449
149163
  const deviceMap = /* @__PURE__ */ new Map();
148450
149164
  for (const atom of atoms) {
148451
149165
  if (!deviceMap.has(atom.device)) deviceMap.set(atom.device, []);
@@ -151649,7 +152363,7 @@ function formatDateShort(dateStr) {
151649
152363
  const month = String(date.getMonth() + 1).padStart(2, "0");
151650
152364
  return `${day}/${month}`;
151651
152365
  }
151652
- function formatDateTime2(dateStr) {
152366
+ function formatDateTime3(dateStr) {
151653
152367
  const date = new Date(dateStr);
151654
152368
  const day = String(date.getDate()).padStart(2, "0");
151655
152369
  const month = String(date.getMonth() + 1).padStart(2, "0");
@@ -151723,7 +152437,7 @@ function renderMTBFTimelineChart(data) {
151723
152437
  segmentPaths += `
151724
152438
  <rect x="${x1}" y="${onY}" width="${segWidth}" height="${barHeight}"
151725
152439
  fill="#22c55e" rx="3" class="mtbf-segment operating"
151726
- data-tooltip="Operacao|Inicio: ${formatDateTime2(seg.startTime)}|Fim: ${formatDateTime2(seg.endTime)}|Duracao: ${formatHoursDisplay(seg.durationHours)}${seg.activeEquipments ? `|Equipamentos ativos: ${seg.activeEquipments}/${data.totalEquipment}` : ""}" />
152440
+ data-tooltip="Operacao|Inicio: ${formatDateTime3(seg.startTime)}|Fim: ${formatDateTime3(seg.endTime)}|Duracao: ${formatHoursDisplay(seg.durationHours)}${seg.activeEquipments ? `|Equipamentos ativos: ${seg.activeEquipments}/${data.totalEquipment}` : ""}" />
151727
152441
  `;
151728
152442
  const centerX = x1 + segWidth / 2;
151729
152443
  if (segWidth > 50) {
@@ -151738,8 +152452,8 @@ function renderMTBFTimelineChart(data) {
151738
152452
  <rect x="${x1}" y="${onY}" width="${segWidth}" height="${barHeight}"
151739
152453
  fill="transparent" class="tooltip-trigger"
151740
152454
  data-type="operating"
151741
- data-start="${formatDateTime2(seg.startTime)}"
151742
- data-end="${formatDateTime2(seg.endTime)}"
152455
+ data-start="${formatDateTime3(seg.startTime)}"
152456
+ data-end="${formatDateTime3(seg.endTime)}"
151743
152457
  data-duration="${formatHoursDisplay(seg.durationHours)}"
151744
152458
  data-active="${seg.activeEquipments || data.totalEquipment}" />
151745
152459
  `;
@@ -151748,7 +152462,7 @@ function renderMTBFTimelineChart(data) {
151748
152462
  segmentPaths += `
151749
152463
  <rect x="${x1}" y="${offY - 15}" width="${segWidth}" height="20"
151750
152464
  fill="#ef4444" rx="2" class="mtbf-segment stopped"
151751
- data-tooltip="\u26A0\uFE0F Falha detectada|Data: ${formatDateTime2(seg.startTime)}|Tempo parado: ${formatHoursDisplay(seg.durationHours)}${seg.affectedEquipments ? `|Equipamentos afetados: ${seg.affectedEquipments}` : ""}${seg.failureType ? `|Tipo: ${seg.failureType}` : ""}" />
152465
+ data-tooltip="\u26A0\uFE0F Falha detectada|Data: ${formatDateTime3(seg.startTime)}|Tempo parado: ${formatHoursDisplay(seg.durationHours)}${seg.affectedEquipments ? `|Equipamentos afetados: ${seg.affectedEquipments}` : ""}${seg.failureType ? `|Tipo: ${seg.failureType}` : ""}" />
151752
152466
  `;
151753
152467
  failureMarkers += `
151754
152468
  <g class="failure-marker" transform="translate(${markerX}, ${offY + 10})">
@@ -151766,7 +152480,7 @@ function renderMTBFTimelineChart(data) {
151766
152480
  <rect x="${x1 - 10}" y="${offY - 20}" width="${segWidth + 20}" height="45"
151767
152481
  fill="transparent" class="tooltip-trigger"
151768
152482
  data-type="stopped"
151769
- data-date="${formatDateTime2(seg.startTime)}"
152483
+ data-date="${formatDateTime3(seg.startTime)}"
151770
152484
  data-duration="${formatHoursDisplay(seg.durationHours)}"
151771
152485
  data-affected="${seg.affectedEquipments || "?"}"
151772
152486
  data-failure-type="${seg.failureType || "Nao especificado"}" />
@@ -151789,7 +152503,7 @@ function renderMTBFTimelineChart(data) {
151789
152503
  <rect x="${x1 - 5}" y="${offY - 20}" width="${segWidth + 10}" height="45"
151790
152504
  fill="transparent" class="tooltip-trigger"
151791
152505
  data-type="maintenance"
151792
- data-start="${formatDateTime2(seg.startTime)}"
152506
+ data-start="${formatDateTime3(seg.startTime)}"
151793
152507
  data-duration="${formatHoursDisplay(seg.durationHours)}" />
151794
152508
  `;
151795
152509
  }
@@ -159698,7 +160412,7 @@ function formatDateShort2(dateStr) {
159698
160412
  const month = String(date.getMonth() + 1).padStart(2, "0");
159699
160413
  return `${day}/${month}`;
159700
160414
  }
159701
- function formatDateTime3(dateStr) {
160415
+ function formatDateTime4(dateStr) {
159702
160416
  const date = new Date(dateStr);
159703
160417
  const day = String(date.getDate()).padStart(2, "0");
159704
160418
  const month = String(date.getMonth() + 1).padStart(2, "0");
@@ -159777,8 +160491,8 @@ function renderTimelineSVG(data, config2) {
159777
160491
  fill="transparent"
159778
160492
  class="tooltip-trigger"
159779
160493
  data-state="${stateClass}"
159780
- data-start="${formatDateTime3(seg.startTime)}"
159781
- data-end="${formatDateTime3(seg.endTime)}"
160494
+ data-start="${formatDateTime4(seg.startTime)}"
160495
+ data-end="${formatDateTime4(seg.endTime)}"
159782
160496
  data-duration="${formatDuration2(seg.durationMinutes)}"
159783
160497
  data-source="${seg.source || "unknown"}"
159784
160498
  />
@@ -168544,8 +169258,8 @@ async function drawTag(doc, x, y, w, h3, device, gateway, allDevices) {
168544
169258
  const titleAreaH = h3 * 0.15;
168545
169259
  const qrAreaTop = y + titleAreaH;
168546
169260
  const qrAreaH = h3 - titleAreaH - 12;
168547
- const displayName = generateDeviceNameWithPrefix(device, void 0, allDevices);
168548
- const rawName = sanitizePdf(displayName);
169261
+ const displayName2 = generateDeviceNameWithPrefix(device, void 0, allDevices);
169262
+ const rawName = sanitizePdf(displayName2);
168549
169263
  const nameFont = Math.max(6, Math.min(11, titleAreaH * 0.45));
168550
169264
  doc.setFont("helvetica", "bold");
168551
169265
  doc.setFontSize(nameFont);
@@ -168622,8 +169336,8 @@ async function exportDeviceTagsPdf(devices, gateway, layout = "grid_4x7") {
168622
169336
  if (page > 0) doc.addPage();
168623
169337
  paintPage(page + 1, totalPages);
168624
169338
  for (let row = 0; row < rows && idx < devices.length; row++) {
168625
- for (let col = 0; col < cols && idx < devices.length; col++) {
168626
- const tx = usableX + col * (tagW + gutterX);
169339
+ for (let col2 = 0; col2 < cols && idx < devices.length; col2++) {
169340
+ const tx = usableX + col2 * (tagW + gutterX);
168627
169341
  const ty = usableY + row * (tagH + gutterY);
168628
169342
  await drawTag(doc, tx, ty, tagW, tagH, devices[idx], gateway, devices);
168629
169343
  idx++;
@@ -170764,7 +171478,7 @@ var DOMAIN_ICONS2 = {
170764
171478
  temperature: "\u{1F321}\uFE0F",
170765
171479
  unknown: "\xB7"
170766
171480
  };
170767
- var DOMAIN_LABELS2 = {
171481
+ var DOMAIN_LABELS3 = {
170768
171482
  energy: "Energia",
170769
171483
  water: "\xC1gua",
170770
171484
  temperature: "Temperatura",
@@ -170997,7 +171711,7 @@ function _applyFilterToDevice(device, filter) {
170997
171711
  function _labelForGroup(key, groupBy, sample) {
170998
171712
  if (groupBy === "identifier") return key;
170999
171713
  if (groupBy === "device") return sample?.label || sample?.name || key;
171000
- return DOMAIN_LABELS2[key] ?? key;
171714
+ return DOMAIN_LABELS3[key] ?? key;
171001
171715
  }
171002
171716
  function _iconForGroup(key, groupBy) {
171003
171717
  if (groupBy === "domain") return DOMAIN_ICONS2[key];
@@ -173032,8 +173746,8 @@ ${this._renderToolbar(filteredCount, totalAllUnfiltered)}
173032
173746
  </section>`;
173033
173747
  }
173034
173748
  /** Toggle a single group's collapsed state (scoped to current tab). */
173035
- _toggleGroupCollapsed(groupKey) {
173036
- const compoundKey = `${this.activeTab}::${groupKey}`;
173749
+ _toggleGroupCollapsed(groupKey2) {
173750
+ const compoundKey = `${this.activeTab}::${groupKey2}`;
173037
173751
  if (this.collapsedKeys.has(compoundKey)) {
173038
173752
  this.collapsedKeys.delete(compoundKey);
173039
173753
  } else {
@@ -174145,7 +174859,7 @@ function formatRoundedDuration(ms) {
174145
174859
  if (s < 86400) return `${Math.round(s / 3600)}h`;
174146
174860
  return `${Math.round(s / 86400)}d`;
174147
174861
  }
174148
- function formatDateTime4(iso, language) {
174862
+ function formatDateTime5(iso, language) {
174149
174863
  const t = Date.parse(iso);
174150
174864
  if (Number.isNaN(t)) return iso;
174151
174865
  return new Date(t).toLocaleString(language === "en" ? "en-US" : "pt-BR", {
@@ -174176,7 +174890,7 @@ function renderBarHtml(segments, language, legend) {
174176
174890
  return `<div class="myio-tlmodal__bar" role="img" aria-label="${escAttr5(
174177
174891
  segments.map((s) => `${legend[s.status]} ${formatRoundedDuration(s.durationMs)}`).join(", ")
174178
174892
  )}">` + segments.map((s, i) => {
174179
- const title = `${legend[s.status]} \xB7 ${formatDateTime4(s.start, language)} \u2192 ${formatDateTime4(
174893
+ const title = `${legend[s.status]} \xB7 ${formatDateTime5(s.start, language)} \u2192 ${formatDateTime5(
174180
174894
  s.end,
174181
174895
  language
174182
174896
  )} (${formatRoundedDuration(s.durationMs)})`;
@@ -174193,7 +174907,7 @@ function renderListHtml(transitions, language, emptyText) {
174193
174907
  return `<ul class="myio-tlmodal__list">` + sorted.map(
174194
174908
  (t) => `<li class="myio-tlmodal__list-item">
174195
174909
  <span class="myio-tlmodal__list-transition">${escAttr5(t.from_status)} \u2192 ${escAttr5(t.to_status)}</span>
174196
- <span class="myio-tlmodal__list-time">${escAttr5(formatDateTime4(t.created_at, language))}</span>
174910
+ <span class="myio-tlmodal__list-time">${escAttr5(formatDateTime5(t.created_at, language))}</span>
174197
174911
  ${t.probe_result ? `<span class="myio-tlmodal__list-probe">${escAttr5(t.probe_result)}</span>` : ""}
174198
174912
  <span class="myio-tlmodal__list-mode myio-tlmodal__list-mode--${t.mode}">${escAttr5(t.mode)}</span>
174199
174913
  </li>`
@@ -175836,6 +176550,7 @@ var version = package_default.version || "0.0.0";
175836
176550
  injectSolenoidControlStyles,
175837
176551
  injectSwitchControlStyles,
175838
176552
  interpolateTemperature,
176553
+ inventory,
175839
176554
  isAlarmActive,
175840
176555
  isAnnotationOverdue,
175841
176556
  isAssetCode,