myio-js-library 0.1.563 → 0.1.565
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 +1077 -64
- package/dist/index.d.cts +531 -2
- package/dist/index.d.ts +531 -2
- package/dist/index.js +1075 -64
- package/dist/myio-js-library.umd.js +1073 -64
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -130,6 +130,7 @@ __export(src_exports, {
|
|
|
130
130
|
DEFAULT_SIDEBAR_CONFIG: () => DEFAULT_SIDEBAR_CONFIG,
|
|
131
131
|
DEFAULT_SOLENOID_SETTINGS: () => DEFAULT_SOLENOID_SETTINGS,
|
|
132
132
|
DEFAULT_SOLENOID_STATE: () => DEFAULT_SOLENOID_STATE,
|
|
133
|
+
DEFAULT_STORE_SEGMENTS: () => DEFAULT_STORE_SEGMENTS,
|
|
133
134
|
DEFAULT_SWITCH_SETTINGS: () => DEFAULT_SWITCH_SETTINGS,
|
|
134
135
|
DEFAULT_SWITCH_STATE: () => DEFAULT_SWITCH_STATE,
|
|
135
136
|
DEFAULT_TABS: () => DEFAULT_TABS,
|
|
@@ -352,7 +353,7 @@ __export(src_exports, {
|
|
|
352
353
|
appendFreshdeskTicketToTB: () => appendFreshdeskTicketToTB,
|
|
353
354
|
applyCustomerCodeToAssetName: () => applyCustomerCodeToAssetName,
|
|
354
355
|
applyDashboardPalette: () => applyDashboardPalette,
|
|
355
|
-
applyDeviceGridFilters: () =>
|
|
356
|
+
applyDeviceGridFilters: () => applyFilters2,
|
|
356
357
|
archiveAlarmAnnotation: () => archiveAlarmAnnotation,
|
|
357
358
|
assetLocalToken: () => assetLocalToken,
|
|
358
359
|
assignShoppingColors: () => assignShoppingColors,
|
|
@@ -711,6 +712,7 @@ __export(src_exports, {
|
|
|
711
712
|
injectSolenoidControlStyles: () => injectSolenoidControlStyles,
|
|
712
713
|
injectSwitchControlStyles: () => injectSwitchControlStyles,
|
|
713
714
|
interpolateTemperature: () => interpolateTemperature,
|
|
715
|
+
inventory: () => inventory_exports,
|
|
714
716
|
isAlarmActive: () => isAlarmActive,
|
|
715
717
|
isAnnotationOverdue: () => isOverdue,
|
|
716
718
|
isAssetCode: () => isAssetCode,
|
|
@@ -921,7 +923,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
921
923
|
// package.json
|
|
922
924
|
var package_default = {
|
|
923
925
|
name: "myio-js-library",
|
|
924
|
-
version: "0.1.
|
|
926
|
+
version: "0.1.565",
|
|
925
927
|
description: "A clean, standalone JS SDK for MYIO projects",
|
|
926
928
|
license: "MIT",
|
|
927
929
|
repository: "github:gh-myio/myio-js-library",
|
|
@@ -2442,6 +2444,719 @@ function getTypesByCategory(category) {
|
|
|
2442
2444
|
);
|
|
2443
2445
|
}
|
|
2444
2446
|
|
|
2447
|
+
// src/utils/devices/inventory/index.ts
|
|
2448
|
+
var inventory_exports = {};
|
|
2449
|
+
__export(inventory_exports, {
|
|
2450
|
+
ATIVIDADE_LABELS: () => ATIVIDADE_LABELS,
|
|
2451
|
+
CADASTRO_LABELS: () => CADASTRO_LABELS,
|
|
2452
|
+
DOMAIN_LABELS: () => DOMAIN_LABELS,
|
|
2453
|
+
FILTER_DIMENSIONS: () => FILTER_DIMENSIONS,
|
|
2454
|
+
INVENTORY_ENTITY_FIELDS: () => INVENTORY_ENTITY_FIELDS,
|
|
2455
|
+
INVENTORY_EXPORT_COLUMNS: () => INVENTORY_EXPORT_COLUMNS,
|
|
2456
|
+
INVENTORY_PDF_COLUMN_KEYS: () => INVENTORY_PDF_COLUMN_KEYS,
|
|
2457
|
+
INVENTORY_RULES: () => INVENTORY_RULES,
|
|
2458
|
+
INVENTORY_SERVER_ATTRIBUTES: () => INVENTORY_SERVER_ATTRIBUTES,
|
|
2459
|
+
LIFECYCLE_LABELS: () => LIFECYCLE_LABELS,
|
|
2460
|
+
NO_CUSTOMER_KEY: () => NO_CUSTOMER_KEY,
|
|
2461
|
+
UNCLASSIFIED_PROFILE_LABEL: () => UNCLASSIFIED_PROFILE_LABEL,
|
|
2462
|
+
applyFilters: () => applyFilters,
|
|
2463
|
+
buildDashboardSummary: () => buildDashboardSummary,
|
|
2464
|
+
buildEntitiesQueryBody: () => buildEntitiesQueryBody,
|
|
2465
|
+
buildExportSummary: () => buildExportSummary,
|
|
2466
|
+
buildInventoryRows: () => buildInventoryRows,
|
|
2467
|
+
buildRuleContext: () => buildRuleContext,
|
|
2468
|
+
compareRows: () => compareRows,
|
|
2469
|
+
createEmptyFilters: () => createEmptyFilters,
|
|
2470
|
+
customerKeyLabel: () => customerKeyLabel,
|
|
2471
|
+
dimensionValues: () => dimensionValues,
|
|
2472
|
+
displayName: () => displayName,
|
|
2473
|
+
evaluateDevice: () => evaluateDevice,
|
|
2474
|
+
exportFileName: () => exportFileName,
|
|
2475
|
+
facetCounts: () => facetCounts,
|
|
2476
|
+
failedRulesText: () => failedRulesText,
|
|
2477
|
+
formatDateTime: () => formatDateTime,
|
|
2478
|
+
formatDeviceLabel: () => formatDeviceLabel,
|
|
2479
|
+
getInventoryRule: () => getInventoryRule,
|
|
2480
|
+
getVisibleGroups: () => getVisibleGroups,
|
|
2481
|
+
getVisibleRows: () => getVisibleRows,
|
|
2482
|
+
groupKey: () => groupKey,
|
|
2483
|
+
guardFormula: () => guardFormula,
|
|
2484
|
+
isBlank: () => isBlank,
|
|
2485
|
+
isRecognizedProfile: () => isRecognizedProfile,
|
|
2486
|
+
matchesFilters: () => matchesFilters,
|
|
2487
|
+
normalizeText: () => normalizeText,
|
|
2488
|
+
parseEntityRow: () => parseEntityRow,
|
|
2489
|
+
pickColumns: () => pickColumns,
|
|
2490
|
+
resolveLifecycle: () => resolveLifecycle,
|
|
2491
|
+
summarizeFilters: () => summarizeFilters,
|
|
2492
|
+
toBooleanStrict: () => toBooleanStrict,
|
|
2493
|
+
toCSV: () => toCSV2,
|
|
2494
|
+
toExportMatrix: () => toExportMatrix,
|
|
2495
|
+
toText: () => toText,
|
|
2496
|
+
toTimestamp: () => toTimestamp
|
|
2497
|
+
});
|
|
2498
|
+
|
|
2499
|
+
// src/utils/devices/inventory/loader.ts
|
|
2500
|
+
var INVENTORY_ENTITY_FIELDS = ["name", "label", "type", "createdTime", "ownerName", "ownerType"];
|
|
2501
|
+
var INVENTORY_SERVER_ATTRIBUTES = [
|
|
2502
|
+
"deviceProfile",
|
|
2503
|
+
"identifier",
|
|
2504
|
+
"ingestionId",
|
|
2505
|
+
"gcdrDeviceId",
|
|
2506
|
+
"centralId",
|
|
2507
|
+
"slaveId",
|
|
2508
|
+
"lifecycleStatus",
|
|
2509
|
+
"active",
|
|
2510
|
+
"lastActivityTime"
|
|
2511
|
+
];
|
|
2512
|
+
function buildEntitiesQueryBody(page, pageSize) {
|
|
2513
|
+
return {
|
|
2514
|
+
entityFilter: { type: "entityType", entityType: "DEVICE" },
|
|
2515
|
+
entityFields: INVENTORY_ENTITY_FIELDS.map((key) => ({ type: "ENTITY_FIELD", key })),
|
|
2516
|
+
latestValues: INVENTORY_SERVER_ATTRIBUTES.map((key) => ({ type: "SERVER_ATTRIBUTE", key })),
|
|
2517
|
+
pageLink: {
|
|
2518
|
+
page,
|
|
2519
|
+
pageSize,
|
|
2520
|
+
sortOrder: { key: { type: "ENTITY_FIELD", key: "name" }, direction: "ASC" }
|
|
2521
|
+
}
|
|
2522
|
+
};
|
|
2523
|
+
}
|
|
2524
|
+
function isBlank(value) {
|
|
2525
|
+
if (value === null || value === void 0) return true;
|
|
2526
|
+
const s = String(value).trim();
|
|
2527
|
+
return s === "" || /^(null|undefined)$/i.test(s);
|
|
2528
|
+
}
|
|
2529
|
+
function toText(value) {
|
|
2530
|
+
return isBlank(value) ? null : String(value).trim();
|
|
2531
|
+
}
|
|
2532
|
+
function toBooleanStrict(value) {
|
|
2533
|
+
if (value === true || value === false) return value;
|
|
2534
|
+
const s = toText(value);
|
|
2535
|
+
if (s === null) return null;
|
|
2536
|
+
const lower = s.toLowerCase();
|
|
2537
|
+
if (lower === "true") return true;
|
|
2538
|
+
if (lower === "false") return false;
|
|
2539
|
+
return null;
|
|
2540
|
+
}
|
|
2541
|
+
function toTimestamp(value) {
|
|
2542
|
+
if (isBlank(value)) return null;
|
|
2543
|
+
const n = Number(value);
|
|
2544
|
+
return Number.isFinite(n) && n > 0 ? n : null;
|
|
2545
|
+
}
|
|
2546
|
+
function parseEntityRow(raw, options = {}) {
|
|
2547
|
+
const fields = raw.latest?.ENTITY_FIELD || {};
|
|
2548
|
+
const attrs = raw.latest?.SERVER_ATTRIBUTE || {};
|
|
2549
|
+
const field = (key) => fields[key]?.value;
|
|
2550
|
+
const attr = (key) => attrs[key]?.value;
|
|
2551
|
+
const ownerName = toText(field("ownerName"));
|
|
2552
|
+
const ownerType = toText(field("ownerType"));
|
|
2553
|
+
const customerId = ownerType === "CUSTOMER" && ownerName ? options.customerIdByName?.get(ownerName) ?? null : null;
|
|
2554
|
+
return {
|
|
2555
|
+
id: String(raw.entityId?.id || ""),
|
|
2556
|
+
name: toText(field("name")) ?? "",
|
|
2557
|
+
label: toText(field("label")),
|
|
2558
|
+
type: toText(field("type")),
|
|
2559
|
+
createdTime: toTimestamp(field("createdTime")),
|
|
2560
|
+
ownerName,
|
|
2561
|
+
ownerType: ownerType ? ownerType.toUpperCase() : null,
|
|
2562
|
+
customerId,
|
|
2563
|
+
deviceProfile: toText(attr("deviceProfile")),
|
|
2564
|
+
identifier: toText(attr("identifier")),
|
|
2565
|
+
ingestionId: toText(attr("ingestionId")),
|
|
2566
|
+
gcdrDeviceId: toText(attr("gcdrDeviceId")),
|
|
2567
|
+
centralId: toText(attr("centralId")),
|
|
2568
|
+
slaveId: toText(attr("slaveId")),
|
|
2569
|
+
lifecycleStatus: toText(attr("lifecycleStatus")),
|
|
2570
|
+
active: toBooleanStrict(attr("active")),
|
|
2571
|
+
lastActivityTime: toTimestamp(attr("lastActivityTime")),
|
|
2572
|
+
attributesLoaded: options.attributesLoaded !== false
|
|
2573
|
+
};
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
// src/utils/devices/inventory/lifecycle.ts
|
|
2577
|
+
var VALID = /* @__PURE__ */ new Set(["active", "stock", "archived"]);
|
|
2578
|
+
function resolveLifecycle(device) {
|
|
2579
|
+
const raw = (device.lifecycleStatus || "").trim().toLowerCase();
|
|
2580
|
+
const fromAttribute = VALID.has(raw);
|
|
2581
|
+
const status = fromAttribute ? raw : "active";
|
|
2582
|
+
let legacyHint = null;
|
|
2583
|
+
if (status === "active") {
|
|
2584
|
+
if (/ARQUIVAD/i.test(device.deviceProfile || "")) legacyHint = "deviceProfile";
|
|
2585
|
+
else if (/DESATIVAR/i.test(device.ownerName || "")) legacyHint = "customerName";
|
|
2586
|
+
}
|
|
2587
|
+
return { status, source: fromAttribute ? "attribute" : "default", legacyHint };
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
// src/utils/devices/inventory/rules.ts
|
|
2591
|
+
function isRecognizedProfile(deviceProfile) {
|
|
2592
|
+
return !!deviceProfile && Object.prototype.hasOwnProperty.call(DEVICE_TYPE_CONFIG, deviceProfile.toUpperCase());
|
|
2593
|
+
}
|
|
2594
|
+
function isIntegrated(device, ctx) {
|
|
2595
|
+
return !!device.ownerName && device.ownerType === "CUSTOMER" && ctx.integratedCustomers.has(device.ownerName);
|
|
2596
|
+
}
|
|
2597
|
+
function requiredOnIntegrated(pick) {
|
|
2598
|
+
return (device, ctx) => {
|
|
2599
|
+
if (!device.attributesLoaded) return "unknown";
|
|
2600
|
+
if (!isIntegrated(device, ctx)) return "notApplicable";
|
|
2601
|
+
return pick(device) === null ? "fail" : "pass";
|
|
2602
|
+
};
|
|
2603
|
+
}
|
|
2604
|
+
var INVENTORY_RULES = [
|
|
2605
|
+
{
|
|
2606
|
+
id: "C1",
|
|
2607
|
+
axis: "cadastro",
|
|
2608
|
+
severity: "pending",
|
|
2609
|
+
label: "Sem cliente",
|
|
2610
|
+
description: "O dispositivo pertence ao tenant e n\xE3o est\xE1 associado a nenhum cliente.",
|
|
2611
|
+
evaluate: (d) => {
|
|
2612
|
+
if (d.ownerType === null) return "unknown";
|
|
2613
|
+
return d.ownerType === "TENANT" ? "fail" : "pass";
|
|
2614
|
+
}
|
|
2615
|
+
},
|
|
2616
|
+
{
|
|
2617
|
+
id: "C2",
|
|
2618
|
+
axis: "cadastro",
|
|
2619
|
+
severity: "critical",
|
|
2620
|
+
label: "Sem deviceProfile",
|
|
2621
|
+
description: "O atributo deviceProfile n\xE3o est\xE1 preenchido; o dispositivo n\xE3o \xE9 classificado nos dashboards.",
|
|
2622
|
+
evaluate: requiredOnIntegrated((d) => d.deviceProfile)
|
|
2623
|
+
},
|
|
2624
|
+
{
|
|
2625
|
+
id: "C3",
|
|
2626
|
+
axis: "cadastro",
|
|
2627
|
+
severity: "critical",
|
|
2628
|
+
label: "Sem ingestionId",
|
|
2629
|
+
description: "Sem ingestionId, os dados do dispositivo n\xE3o chegam aos relat\xF3rios.",
|
|
2630
|
+
evaluate: requiredOnIntegrated((d) => d.ingestionId)
|
|
2631
|
+
},
|
|
2632
|
+
{
|
|
2633
|
+
id: "C4",
|
|
2634
|
+
axis: "cadastro",
|
|
2635
|
+
severity: "pending",
|
|
2636
|
+
label: "Sem gcdrDeviceId",
|
|
2637
|
+
description: "Sem gcdrDeviceId, alarmes e recursos do GCDR ficam indispon\xEDveis para o dispositivo.",
|
|
2638
|
+
evaluate: requiredOnIntegrated((d) => d.gcdrDeviceId)
|
|
2639
|
+
},
|
|
2640
|
+
{
|
|
2641
|
+
id: "C5",
|
|
2642
|
+
axis: "cadastro",
|
|
2643
|
+
severity: "pending",
|
|
2644
|
+
label: "Perfil n\xE3o reconhecido",
|
|
2645
|
+
description: 'O deviceProfile n\xE3o est\xE1 na lista de perfis conhecidos; o dispositivo aparece como "N\xE3o classificado".',
|
|
2646
|
+
evaluate: (d, ctx) => {
|
|
2647
|
+
if (!d.attributesLoaded) return "unknown";
|
|
2648
|
+
if (!isIntegrated(d, ctx) || d.deviceProfile === null) return "notApplicable";
|
|
2649
|
+
return isRecognizedProfile(d.deviceProfile) ? "pass" : "fail";
|
|
2650
|
+
}
|
|
2651
|
+
},
|
|
2652
|
+
{
|
|
2653
|
+
id: "C6",
|
|
2654
|
+
axis: "cadastro",
|
|
2655
|
+
severity: "info",
|
|
2656
|
+
label: "Perfil diverge do TB",
|
|
2657
|
+
description: "O deviceProfile difere do perfil do dispositivo no ThingsBoard.",
|
|
2658
|
+
evaluate: (d) => {
|
|
2659
|
+
if (!d.attributesLoaded) return "unknown";
|
|
2660
|
+
if (d.deviceProfile === null || d.type === null) return "notApplicable";
|
|
2661
|
+
return d.deviceProfile.toUpperCase() === d.type.toUpperCase() ? "pass" : "fail";
|
|
2662
|
+
}
|
|
2663
|
+
},
|
|
2664
|
+
{
|
|
2665
|
+
id: "C7",
|
|
2666
|
+
axis: "cadastro",
|
|
2667
|
+
severity: "pending",
|
|
2668
|
+
label: "Sem central/slave",
|
|
2669
|
+
description: "Dispositivo de dom\xEDnio ligado a central sem centralId ou slaveId.",
|
|
2670
|
+
evaluate: (d, ctx) => {
|
|
2671
|
+
if (!d.attributesLoaded) return "unknown";
|
|
2672
|
+
if (!isIntegrated(d, ctx) || !isRecognizedProfile(d.deviceProfile)) return "notApplicable";
|
|
2673
|
+
if (!ctx.centralDomains.has(getDeviceCategory(d.deviceProfile))) return "notApplicable";
|
|
2674
|
+
return d.centralId === null || d.slaveId === null ? "fail" : "pass";
|
|
2675
|
+
}
|
|
2676
|
+
},
|
|
2677
|
+
{
|
|
2678
|
+
id: "C8",
|
|
2679
|
+
axis: "cadastro",
|
|
2680
|
+
severity: "critical",
|
|
2681
|
+
label: "ID duplicado",
|
|
2682
|
+
description: "Outro dispositivo ativo usa o mesmo ingestionId ou gcdrDeviceId.",
|
|
2683
|
+
evaluate: (d, ctx) => {
|
|
2684
|
+
if (!d.attributesLoaded) return "unknown";
|
|
2685
|
+
if (d.ingestionId === null && d.gcdrDeviceId === null) return "notApplicable";
|
|
2686
|
+
const dupIngestion = d.ingestionId !== null && (ctx.ingestionIdCounts.get(d.ingestionId) || 0) > 1;
|
|
2687
|
+
const dupGcdr = d.gcdrDeviceId !== null && (ctx.gcdrDeviceIdCounts.get(d.gcdrDeviceId) || 0) > 1;
|
|
2688
|
+
return dupIngestion || dupGcdr ? "fail" : "pass";
|
|
2689
|
+
}
|
|
2690
|
+
},
|
|
2691
|
+
{
|
|
2692
|
+
id: "A1",
|
|
2693
|
+
axis: "atividade",
|
|
2694
|
+
severity: "inactive",
|
|
2695
|
+
label: "Inativo no TB",
|
|
2696
|
+
description: "O ThingsBoard marca o dispositivo como inativo (active = false).",
|
|
2697
|
+
evaluate: (d) => {
|
|
2698
|
+
if (d.active === null) return "unknown";
|
|
2699
|
+
return d.active ? "pass" : "fail";
|
|
2700
|
+
}
|
|
2701
|
+
},
|
|
2702
|
+
{
|
|
2703
|
+
id: "A2",
|
|
2704
|
+
axis: "atividade",
|
|
2705
|
+
severity: "inactive",
|
|
2706
|
+
label: "Sem atividade recente",
|
|
2707
|
+
description: "A \xFAltima atividade registrada \xE9 mais antiga que o limite configurado.",
|
|
2708
|
+
evaluate: (d, ctx) => {
|
|
2709
|
+
if (d.lastActivityTime === null) return "unknown";
|
|
2710
|
+
return ctx.now - d.lastActivityTime > ctx.staleHours * 3600 * 1e3 ? "fail" : "pass";
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
];
|
|
2714
|
+
var RULE_BY_ID = new Map(INVENTORY_RULES.map((r) => [r.id, r]));
|
|
2715
|
+
function getInventoryRule(id) {
|
|
2716
|
+
return RULE_BY_ID.get(id);
|
|
2717
|
+
}
|
|
2718
|
+
function buildRuleContext(devices, options) {
|
|
2719
|
+
const integrated = /* @__PURE__ */ new Set();
|
|
2720
|
+
const ingestionIdCounts = /* @__PURE__ */ new Map();
|
|
2721
|
+
const gcdrDeviceIdCounts = /* @__PURE__ */ new Map();
|
|
2722
|
+
for (const d of devices) {
|
|
2723
|
+
if (d.ownerType === "CUSTOMER" && d.ownerName && (d.ingestionId !== null || d.gcdrDeviceId !== null)) {
|
|
2724
|
+
integrated.add(d.ownerName);
|
|
2725
|
+
}
|
|
2726
|
+
if (resolveLifecycle(d).status === "archived") continue;
|
|
2727
|
+
if (d.ingestionId !== null) ingestionIdCounts.set(d.ingestionId, (ingestionIdCounts.get(d.ingestionId) || 0) + 1);
|
|
2728
|
+
if (d.gcdrDeviceId !== null) gcdrDeviceIdCounts.set(d.gcdrDeviceId, (gcdrDeviceIdCounts.get(d.gcdrDeviceId) || 0) + 1);
|
|
2729
|
+
}
|
|
2730
|
+
for (const [name, expected] of Object.entries(options.integrationOverrides || {})) {
|
|
2731
|
+
if (expected) integrated.add(name);
|
|
2732
|
+
else integrated.delete(name);
|
|
2733
|
+
}
|
|
2734
|
+
return {
|
|
2735
|
+
integratedCustomers: integrated,
|
|
2736
|
+
ingestionIdCounts,
|
|
2737
|
+
gcdrDeviceIdCounts,
|
|
2738
|
+
staleHours: options.staleHours ?? 24,
|
|
2739
|
+
disabledRules: new Set(options.disabledRules ?? ["C6"]),
|
|
2740
|
+
centralDomains: new Set(options.centralDomains ?? ["energy", "water"]),
|
|
2741
|
+
now: options.now
|
|
2742
|
+
};
|
|
2743
|
+
}
|
|
2744
|
+
var CADASTRO_RANK = { critical: 2, pending: 1 };
|
|
2745
|
+
function evaluateDevice(device, ctx) {
|
|
2746
|
+
const lifecycle = resolveLifecycle(device);
|
|
2747
|
+
if (lifecycle.status !== "active") {
|
|
2748
|
+
return {
|
|
2749
|
+
lifecycle,
|
|
2750
|
+
results: INVENTORY_RULES.map((r) => ({ id: r.id, outcome: "notApplicable" })),
|
|
2751
|
+
failed: [],
|
|
2752
|
+
cadastro: { level: "excluded", partial: false },
|
|
2753
|
+
atividade: { level: "excluded", partial: false }
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2756
|
+
const results = INVENTORY_RULES.map((rule) => ({
|
|
2757
|
+
id: rule.id,
|
|
2758
|
+
outcome: ctx.disabledRules.has(rule.id) ? "notApplicable" : rule.evaluate(device, ctx)
|
|
2759
|
+
}));
|
|
2760
|
+
const failed = results.filter((r) => r.outcome === "fail").map((r) => r.id);
|
|
2761
|
+
let cadastroRank = 0;
|
|
2762
|
+
let cadastroUnknown = false;
|
|
2763
|
+
let atividadeFail = false;
|
|
2764
|
+
let atividadeUnknown = false;
|
|
2765
|
+
for (const result of results) {
|
|
2766
|
+
const rule = RULE_BY_ID.get(result.id);
|
|
2767
|
+
if (rule.axis === "cadastro") {
|
|
2768
|
+
if (rule.severity === "info") continue;
|
|
2769
|
+
if (result.outcome === "fail") cadastroRank = Math.max(cadastroRank, CADASTRO_RANK[rule.severity] || 0);
|
|
2770
|
+
if (result.outcome === "unknown") cadastroUnknown = true;
|
|
2771
|
+
} else {
|
|
2772
|
+
if (result.outcome === "fail") atividadeFail = true;
|
|
2773
|
+
if (result.outcome === "unknown") atividadeUnknown = true;
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
const cadastroLevel = cadastroRank === 2 ? "critical" : cadastroRank === 1 ? "pending" : cadastroUnknown ? "partial" : "ok";
|
|
2777
|
+
const atividadeLevel = atividadeFail ? "inactive" : atividadeUnknown ? "nodata" : "ok";
|
|
2778
|
+
return {
|
|
2779
|
+
lifecycle,
|
|
2780
|
+
results,
|
|
2781
|
+
failed,
|
|
2782
|
+
cadastro: { level: cadastroLevel, partial: cadastroRank > 0 && cadastroUnknown },
|
|
2783
|
+
atividade: { level: atividadeLevel, partial: atividadeFail && atividadeUnknown }
|
|
2784
|
+
};
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
// src/utils/devices/inventory/labels.ts
|
|
2788
|
+
var CADASTRO_LABELS = {
|
|
2789
|
+
ok: "\xCDntegro",
|
|
2790
|
+
pending: "Pendente",
|
|
2791
|
+
critical: "Cr\xEDtico",
|
|
2792
|
+
partial: "Parcial",
|
|
2793
|
+
excluded: "Fora dos indicadores"
|
|
2794
|
+
};
|
|
2795
|
+
var ATIVIDADE_LABELS = {
|
|
2796
|
+
ok: "Reportando",
|
|
2797
|
+
inactive: "Sem atividade",
|
|
2798
|
+
nodata: "Sem dado",
|
|
2799
|
+
excluded: "Fora dos indicadores"
|
|
2800
|
+
};
|
|
2801
|
+
var LIFECYCLE_LABELS = {
|
|
2802
|
+
active: "Ativo",
|
|
2803
|
+
stock: "Estoque",
|
|
2804
|
+
archived: "Arquivado"
|
|
2805
|
+
};
|
|
2806
|
+
var DOMAIN_LABELS = {
|
|
2807
|
+
energy: "Energia",
|
|
2808
|
+
water: "\xC1gua",
|
|
2809
|
+
temperature: "Temperatura",
|
|
2810
|
+
tank: "Reservat\xF3rio",
|
|
2811
|
+
solenoid: "Solenoide",
|
|
2812
|
+
unclassified: "N\xE3o classificado"
|
|
2813
|
+
};
|
|
2814
|
+
|
|
2815
|
+
// src/utils/devices/inventory/filters.ts
|
|
2816
|
+
var NO_CUSTOMER_KEY = "__no_customer__";
|
|
2817
|
+
var UNCLASSIFIED_PROFILE_LABEL = "N\xE3o classificado";
|
|
2818
|
+
function buildInventoryRows(devices, options) {
|
|
2819
|
+
const ctx = "context" in options ? options.context : buildRuleContext(devices, options);
|
|
2820
|
+
return devices.map((device) => {
|
|
2821
|
+
const recognized = isRecognizedProfile(device.deviceProfile);
|
|
2822
|
+
return {
|
|
2823
|
+
device,
|
|
2824
|
+
evaluation: evaluateDevice(device, ctx),
|
|
2825
|
+
domain: recognized ? getDeviceCategory(device.deviceProfile) : "unclassified",
|
|
2826
|
+
profileLabel: recognized ? device.deviceProfile.toUpperCase() : UNCLASSIFIED_PROFILE_LABEL,
|
|
2827
|
+
customerKey: device.ownerType === "TENANT" || !device.ownerName ? NO_CUSTOMER_KEY : device.ownerName
|
|
2828
|
+
};
|
|
2829
|
+
});
|
|
2830
|
+
}
|
|
2831
|
+
var FILTER_DIMENSIONS = [
|
|
2832
|
+
"customers",
|
|
2833
|
+
"domains",
|
|
2834
|
+
"profiles",
|
|
2835
|
+
"cadastro",
|
|
2836
|
+
"atividade",
|
|
2837
|
+
"rules",
|
|
2838
|
+
"lifecycle"
|
|
2839
|
+
];
|
|
2840
|
+
function createEmptyFilters() {
|
|
2841
|
+
return {
|
|
2842
|
+
customers: /* @__PURE__ */ new Set(),
|
|
2843
|
+
domains: /* @__PURE__ */ new Set(),
|
|
2844
|
+
profiles: /* @__PURE__ */ new Set(),
|
|
2845
|
+
cadastro: /* @__PURE__ */ new Set(),
|
|
2846
|
+
atividade: /* @__PURE__ */ new Set(),
|
|
2847
|
+
rules: /* @__PURE__ */ new Set(),
|
|
2848
|
+
lifecycle: /* @__PURE__ */ new Set(["active"]),
|
|
2849
|
+
text: ""
|
|
2850
|
+
};
|
|
2851
|
+
}
|
|
2852
|
+
function normalizeText(value) {
|
|
2853
|
+
return String(value || "").normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().trim();
|
|
2854
|
+
}
|
|
2855
|
+
function dimensionValues(row, dimension) {
|
|
2856
|
+
switch (dimension) {
|
|
2857
|
+
case "customers":
|
|
2858
|
+
return [row.customerKey];
|
|
2859
|
+
case "domains":
|
|
2860
|
+
return [row.domain];
|
|
2861
|
+
case "profiles":
|
|
2862
|
+
return [row.profileLabel];
|
|
2863
|
+
case "cadastro":
|
|
2864
|
+
return row.evaluation.cadastro.level === "excluded" ? [] : [row.evaluation.cadastro.level];
|
|
2865
|
+
case "atividade":
|
|
2866
|
+
return row.evaluation.atividade.level === "excluded" ? [] : [row.evaluation.atividade.level];
|
|
2867
|
+
case "rules":
|
|
2868
|
+
return row.evaluation.failed;
|
|
2869
|
+
case "lifecycle":
|
|
2870
|
+
return [row.evaluation.lifecycle.status];
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
function matchesText(row, needle) {
|
|
2874
|
+
if (!needle) return true;
|
|
2875
|
+
const d = row.device;
|
|
2876
|
+
return [d.label, d.name, d.identifier, row.profileLabel, d.deviceProfile, d.ownerName, d.ingestionId].some(
|
|
2877
|
+
(v) => normalizeText(v).includes(needle)
|
|
2878
|
+
);
|
|
2879
|
+
}
|
|
2880
|
+
function matchesFilters(row, filters, except) {
|
|
2881
|
+
for (const dimension of FILTER_DIMENSIONS) {
|
|
2882
|
+
if (dimension === except) continue;
|
|
2883
|
+
const selected = filters[dimension];
|
|
2884
|
+
if (selected.size === 0) continue;
|
|
2885
|
+
if (!dimensionValues(row, dimension).some((v) => selected.has(v))) return false;
|
|
2886
|
+
}
|
|
2887
|
+
return matchesText(row, normalizeText(filters.text));
|
|
2888
|
+
}
|
|
2889
|
+
function applyFilters(rows, filters) {
|
|
2890
|
+
return rows.filter((row) => matchesFilters(row, filters));
|
|
2891
|
+
}
|
|
2892
|
+
function facetCounts(rows, filters, dimension) {
|
|
2893
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2894
|
+
for (const row of rows) {
|
|
2895
|
+
if (!matchesFilters(row, filters, dimension)) continue;
|
|
2896
|
+
for (const value of dimensionValues(row, dimension)) counts.set(value, (counts.get(value) || 0) + 1);
|
|
2897
|
+
}
|
|
2898
|
+
return counts;
|
|
2899
|
+
}
|
|
2900
|
+
var CADASTRO_ORDER = { critical: 0, pending: 1, partial: 2, ok: 3, excluded: 4 };
|
|
2901
|
+
var ATIVIDADE_ORDER = { inactive: 0, nodata: 1, ok: 2, excluded: 3 };
|
|
2902
|
+
function displayName(row) {
|
|
2903
|
+
return row.device.label || row.device.name;
|
|
2904
|
+
}
|
|
2905
|
+
function compareText(a, b) {
|
|
2906
|
+
return a.localeCompare(b, "pt-BR", { sensitivity: "base", numeric: true });
|
|
2907
|
+
}
|
|
2908
|
+
function compareRows(a, b, sort) {
|
|
2909
|
+
switch (sort) {
|
|
2910
|
+
case "gravity": {
|
|
2911
|
+
const c = CADASTRO_ORDER[a.evaluation.cadastro.level] - CADASTRO_ORDER[b.evaluation.cadastro.level];
|
|
2912
|
+
if (c) return c;
|
|
2913
|
+
const t = ATIVIDADE_ORDER[a.evaluation.atividade.level] - ATIVIDADE_ORDER[b.evaluation.atividade.level];
|
|
2914
|
+
if (t) return t;
|
|
2915
|
+
break;
|
|
2916
|
+
}
|
|
2917
|
+
case "customer": {
|
|
2918
|
+
const c = compareText(a.device.ownerName || "", b.device.ownerName || "");
|
|
2919
|
+
if (c) return c;
|
|
2920
|
+
break;
|
|
2921
|
+
}
|
|
2922
|
+
case "lastActivity": {
|
|
2923
|
+
const ta = a.device.lastActivityTime ?? -Infinity;
|
|
2924
|
+
const tb = b.device.lastActivityTime ?? -Infinity;
|
|
2925
|
+
if (ta !== tb) return ta < tb ? -1 : 1;
|
|
2926
|
+
break;
|
|
2927
|
+
}
|
|
2928
|
+
case "label":
|
|
2929
|
+
break;
|
|
2930
|
+
}
|
|
2931
|
+
return compareText(displayName(a), displayName(b)) || compareText(a.device.name, b.device.name);
|
|
2932
|
+
}
|
|
2933
|
+
function groupKey(row, groupBy) {
|
|
2934
|
+
switch (groupBy) {
|
|
2935
|
+
case "customer":
|
|
2936
|
+
return row.customerKey;
|
|
2937
|
+
case "domain":
|
|
2938
|
+
return row.domain;
|
|
2939
|
+
case "profile":
|
|
2940
|
+
return row.profileLabel;
|
|
2941
|
+
case "none":
|
|
2942
|
+
return "";
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
function getVisibleGroups(rows, filters, sort, groupBy) {
|
|
2946
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2947
|
+
for (const row of applyFilters(rows, filters)) {
|
|
2948
|
+
const key = groupKey(row, groupBy);
|
|
2949
|
+
if (!groups.has(key)) groups.set(key, []);
|
|
2950
|
+
groups.get(key).push(row);
|
|
2951
|
+
}
|
|
2952
|
+
const title = (key) => groupBy === "domain" ? DOMAIN_LABELS[key] || key : key;
|
|
2953
|
+
const keys = [...groups.keys()].sort((a, b) => {
|
|
2954
|
+
if (a === NO_CUSTOMER_KEY) return -1;
|
|
2955
|
+
if (b === NO_CUSTOMER_KEY) return 1;
|
|
2956
|
+
return compareText(title(a), title(b));
|
|
2957
|
+
});
|
|
2958
|
+
return keys.map((key) => ({ key, rows: groups.get(key).sort((x, y) => compareRows(x, y, sort)) }));
|
|
2959
|
+
}
|
|
2960
|
+
function getVisibleRows(rows, filters, sort, groupBy) {
|
|
2961
|
+
return getVisibleGroups(rows, filters, sort, groupBy).flatMap((g) => g.rows);
|
|
2962
|
+
}
|
|
2963
|
+
|
|
2964
|
+
// src/utils/devices/inventory/dashboard.ts
|
|
2965
|
+
function buildDashboardSummary(rows, options = {}) {
|
|
2966
|
+
const cadastro = { ok: 0, pending: 0, critical: 0, partial: 0 };
|
|
2967
|
+
const atividade = { ok: 0, inactive: 0, nodata: 0 };
|
|
2968
|
+
const excluded = { stock: 0, archived: 0 };
|
|
2969
|
+
const byCustomer = /* @__PURE__ */ new Map();
|
|
2970
|
+
const ruleCounts = /* @__PURE__ */ new Map();
|
|
2971
|
+
const failuresByCustomerRule = /* @__PURE__ */ new Map();
|
|
2972
|
+
for (const row of rows) {
|
|
2973
|
+
const { lifecycle, cadastro: cad, atividade: atv, failed } = row.evaluation;
|
|
2974
|
+
if (lifecycle.status !== "active") {
|
|
2975
|
+
excluded[lifecycle.status]++;
|
|
2976
|
+
continue;
|
|
2977
|
+
}
|
|
2978
|
+
if (cad.level !== "excluded") cadastro[cad.level]++;
|
|
2979
|
+
if (atv.level !== "excluded") atividade[atv.level]++;
|
|
2980
|
+
const customer = byCustomer.get(row.customerKey) || { key: row.customerKey, critical: 0, pending: 0, total: 0 };
|
|
2981
|
+
customer.total++;
|
|
2982
|
+
if (cad.level === "critical") customer.critical++;
|
|
2983
|
+
if (cad.level === "pending") customer.pending++;
|
|
2984
|
+
byCustomer.set(row.customerKey, customer);
|
|
2985
|
+
for (const id of failed) {
|
|
2986
|
+
ruleCounts.set(id, (ruleCounts.get(id) || 0) + 1);
|
|
2987
|
+
const perRule = failuresByCustomerRule.get(row.customerKey) || /* @__PURE__ */ new Map();
|
|
2988
|
+
perRule.set(id, (perRule.get(id) || 0) + 1);
|
|
2989
|
+
failuresByCustomerRule.set(row.customerKey, perRule);
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
const ruleOrder = new Map(INVENTORY_RULES.map((r, i) => [r.id, i]));
|
|
2993
|
+
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));
|
|
2994
|
+
const worstFirst = (a, b) => b.critical - a.critical || b.pending - a.pending || a.key.localeCompare(b.key, "pt-BR");
|
|
2995
|
+
const topCustomers = [...byCustomer.values()].filter((c) => c.critical + c.pending > 0).sort(worstFirst).slice(0, options.topCustomers ?? 10);
|
|
2996
|
+
const failureTotal = (key) => [...failuresByCustomerRule.get(key)?.values() || []].reduce((s, n) => s + n, 0);
|
|
2997
|
+
const matrixCustomers = [...failuresByCustomerRule.keys()].sort((a, b) => failureTotal(b) - failureTotal(a) || a.localeCompare(b, "pt-BR")).slice(0, options.matrixCustomers ?? 15);
|
|
2998
|
+
const matrixRules = topRules.map((r) => r.id);
|
|
2999
|
+
return {
|
|
3000
|
+
total: rows.length,
|
|
3001
|
+
inIndicators: rows.length - excluded.stock - excluded.archived,
|
|
3002
|
+
excluded,
|
|
3003
|
+
cadastro,
|
|
3004
|
+
atividade,
|
|
3005
|
+
topCustomers,
|
|
3006
|
+
topRules,
|
|
3007
|
+
matrix: {
|
|
3008
|
+
customers: matrixCustomers,
|
|
3009
|
+
rules: matrixRules,
|
|
3010
|
+
cells: matrixCustomers.map((c) => matrixRules.map((r) => failuresByCustomerRule.get(c)?.get(r) || 0))
|
|
3011
|
+
}
|
|
3012
|
+
};
|
|
3013
|
+
}
|
|
3014
|
+
function customerKeyLabel(key) {
|
|
3015
|
+
return key === NO_CUSTOMER_KEY ? "Sem cliente" : key;
|
|
3016
|
+
}
|
|
3017
|
+
|
|
3018
|
+
// src/utils/devices/inventory/formatLabel.ts
|
|
3019
|
+
function formatDeviceLabel(device) {
|
|
3020
|
+
const name = String(device.name ?? "").trim();
|
|
3021
|
+
const label = String(device.label ?? "").trim();
|
|
3022
|
+
if (!label || label === name) return { primary: name, secondary: null };
|
|
3023
|
+
return { primary: label, secondary: name || null };
|
|
3024
|
+
}
|
|
3025
|
+
|
|
3026
|
+
// src/utils/devices/inventory/exportRows.ts
|
|
3027
|
+
function formatDateTime(ms) {
|
|
3028
|
+
if (ms === null) return "";
|
|
3029
|
+
const d = new Date(ms);
|
|
3030
|
+
if (Number.isNaN(d.getTime())) return "";
|
|
3031
|
+
return d.toLocaleString("pt-BR", {
|
|
3032
|
+
timeZone: "America/Sao_Paulo",
|
|
3033
|
+
day: "2-digit",
|
|
3034
|
+
month: "2-digit",
|
|
3035
|
+
year: "numeric",
|
|
3036
|
+
hour: "2-digit",
|
|
3037
|
+
minute: "2-digit"
|
|
3038
|
+
});
|
|
3039
|
+
}
|
|
3040
|
+
function cadastroText(row) {
|
|
3041
|
+
const { level, partial } = row.evaluation.cadastro;
|
|
3042
|
+
return CADASTRO_LABELS[level] + (partial ? " \xB7 avalia\xE7\xE3o parcial" : "");
|
|
3043
|
+
}
|
|
3044
|
+
function failedRulesText(row) {
|
|
3045
|
+
return row.evaluation.failed.map((id) => getInventoryRule(id)?.label || id).join("; ");
|
|
3046
|
+
}
|
|
3047
|
+
var col = (key, header, value) => ({
|
|
3048
|
+
key,
|
|
3049
|
+
header,
|
|
3050
|
+
value: (row) => {
|
|
3051
|
+
const v = value(row);
|
|
3052
|
+
return v === null || v === void 0 ? "" : String(v);
|
|
3053
|
+
}
|
|
3054
|
+
});
|
|
3055
|
+
var INVENTORY_EXPORT_COLUMNS = [
|
|
3056
|
+
col("cadastro", "Cadastro", cadastroText),
|
|
3057
|
+
col("atividade", "Atividade", (r) => ATIVIDADE_LABELS[r.evaluation.atividade.level]),
|
|
3058
|
+
col("reasons", "Regras com falha", failedRulesText),
|
|
3059
|
+
col("label", "Label", (r) => r.device.label),
|
|
3060
|
+
col("name", "Name", (r) => r.device.name),
|
|
3061
|
+
col("deviceId", "deviceId", (r) => r.device.id),
|
|
3062
|
+
col("identifier", "Identificador", (r) => r.device.identifier),
|
|
3063
|
+
col("profile", "Perfil", (r) => r.profileLabel),
|
|
3064
|
+
col("domain", "Dom\xEDnio", (r) => DOMAIN_LABELS[r.domain] || r.domain),
|
|
3065
|
+
col("customer", "Cliente", (r) => r.customerKey === NO_CUSTOMER_KEY ? "" : r.device.ownerName),
|
|
3066
|
+
col("customerId", "customerId", (r) => r.device.customerId),
|
|
3067
|
+
col("lifecycle", "Ciclo de vida", (r) => LIFECYCLE_LABELS[r.evaluation.lifecycle.status]),
|
|
3068
|
+
col("active", "Ativo (TB)", (r) => r.device.active === null ? "" : r.device.active ? "Sim" : "N\xE3o"),
|
|
3069
|
+
col("lastActivity", "\xDAltima atividade", (r) => formatDateTime(r.device.lastActivityTime)),
|
|
3070
|
+
col("ingestionId", "ingestionId", (r) => r.device.ingestionId),
|
|
3071
|
+
col("gcdrDeviceId", "gcdrDeviceId", (r) => r.device.gcdrDeviceId),
|
|
3072
|
+
col("centralId", "centralId", (r) => r.device.centralId),
|
|
3073
|
+
col("slaveId", "slaveId", (r) => r.device.slaveId),
|
|
3074
|
+
col("created", "Criado em", (r) => formatDateTime(r.device.createdTime))
|
|
3075
|
+
];
|
|
3076
|
+
var INVENTORY_PDF_COLUMN_KEYS = [
|
|
3077
|
+
"cadastro",
|
|
3078
|
+
"atividade",
|
|
3079
|
+
"label",
|
|
3080
|
+
"name",
|
|
3081
|
+
"profile",
|
|
3082
|
+
"customer",
|
|
3083
|
+
"reasons",
|
|
3084
|
+
"lastActivity"
|
|
3085
|
+
];
|
|
3086
|
+
function pickColumns(keys) {
|
|
3087
|
+
return keys.map((k) => {
|
|
3088
|
+
const c = INVENTORY_EXPORT_COLUMNS.find((x) => x.key === k);
|
|
3089
|
+
if (!c) throw new Error(`Unknown inventory export column: ${k}`);
|
|
3090
|
+
return c;
|
|
3091
|
+
});
|
|
3092
|
+
}
|
|
3093
|
+
function toExportMatrix(rows, columns = INVENTORY_EXPORT_COLUMNS) {
|
|
3094
|
+
return {
|
|
3095
|
+
header: columns.map((c) => c.header),
|
|
3096
|
+
rows: rows.map((row) => columns.map((c) => c.value(row)))
|
|
3097
|
+
};
|
|
3098
|
+
}
|
|
3099
|
+
function guardFormula(value) {
|
|
3100
|
+
return /^[=+\-@\t\r]/.test(value) ? `'${value}` : value;
|
|
3101
|
+
}
|
|
3102
|
+
function csvCell(value) {
|
|
3103
|
+
const safe = guardFormula(value);
|
|
3104
|
+
return /[";\r\n]/.test(safe) ? `"${safe.replace(/"/g, '""')}"` : safe;
|
|
3105
|
+
}
|
|
3106
|
+
function toCSV2(matrix) {
|
|
3107
|
+
const lines = [matrix.header, ...matrix.rows].map((cells) => cells.map(csvCell).join(";"));
|
|
3108
|
+
return "\uFEFF" + lines.join("\r\n") + "\r\n";
|
|
3109
|
+
}
|
|
3110
|
+
function summarizeFilters(filters) {
|
|
3111
|
+
const out = [];
|
|
3112
|
+
const list = (set, map) => [...set].map((v) => map ? map(v) : v).join(", ");
|
|
3113
|
+
if (filters.customers.size) {
|
|
3114
|
+
out.push(["Cliente", list(filters.customers, (v) => v === NO_CUSTOMER_KEY ? "Sem cliente" : v)]);
|
|
3115
|
+
}
|
|
3116
|
+
if (filters.domains.size) out.push(["Dom\xEDnio", list(filters.domains, (v) => DOMAIN_LABELS[v] || v)]);
|
|
3117
|
+
if (filters.profiles.size) out.push(["Perfil", list(filters.profiles)]);
|
|
3118
|
+
if (filters.cadastro.size) out.push(["Cadastro", list(filters.cadastro, (v) => CADASTRO_LABELS[v])]);
|
|
3119
|
+
if (filters.atividade.size) {
|
|
3120
|
+
out.push(["Atividade", list(filters.atividade, (v) => ATIVIDADE_LABELS[v])]);
|
|
3121
|
+
}
|
|
3122
|
+
if (filters.rules.size) out.push(["Regra", list(filters.rules, (v) => getInventoryRule(v)?.label || v)]);
|
|
3123
|
+
if (filters.lifecycle.size) {
|
|
3124
|
+
out.push(["Ciclo de vida", list(filters.lifecycle, (v) => LIFECYCLE_LABELS[v])]);
|
|
3125
|
+
}
|
|
3126
|
+
if (filters.text.trim()) out.push(["Busca", filters.text.trim()]);
|
|
3127
|
+
return out;
|
|
3128
|
+
}
|
|
3129
|
+
function buildExportSummary(filters, dashboard, meta) {
|
|
3130
|
+
const n = (v) => v.toLocaleString("pt-BR");
|
|
3131
|
+
const active = summarizeFilters(filters);
|
|
3132
|
+
return [
|
|
3133
|
+
["Gerado em", formatDateTime(meta.generatedAt)],
|
|
3134
|
+
["Gerado por", meta.generatedBy || ""],
|
|
3135
|
+
["Dispositivos exportados", n(meta.exported)],
|
|
3136
|
+
...active.length ? active : [["Filtros", "Nenhum (todos os dispositivos)"]],
|
|
3137
|
+
["Nos indicadores", n(dashboard.inIndicators)],
|
|
3138
|
+
[`Cadastro \xB7 ${CADASTRO_LABELS.critical}`, n(dashboard.cadastro.critical)],
|
|
3139
|
+
[`Cadastro \xB7 ${CADASTRO_LABELS.pending}`, n(dashboard.cadastro.pending)],
|
|
3140
|
+
[`Cadastro \xB7 ${CADASTRO_LABELS.ok}`, n(dashboard.cadastro.ok)],
|
|
3141
|
+
[`Cadastro \xB7 ${CADASTRO_LABELS.partial}`, n(dashboard.cadastro.partial)],
|
|
3142
|
+
[`Atividade \xB7 ${ATIVIDADE_LABELS.ok}`, n(dashboard.atividade.ok)],
|
|
3143
|
+
[`Atividade \xB7 ${ATIVIDADE_LABELS.inactive}`, n(dashboard.atividade.inactive)],
|
|
3144
|
+
[`Atividade \xB7 ${ATIVIDADE_LABELS.nodata}`, n(dashboard.atividade.nodata)],
|
|
3145
|
+
["Fora dos indicadores (estoque / arquivados)", `${n(dashboard.excluded.stock)} / ${n(dashboard.excluded.archived)}`]
|
|
3146
|
+
];
|
|
3147
|
+
}
|
|
3148
|
+
function exportFileName(filters, ext, now) {
|
|
3149
|
+
const only = filters.customers.size === 1 ? [...filters.customers][0] : null;
|
|
3150
|
+
const scope = !only ? "todos" : only === NO_CUSTOMER_KEY ? "sem-cliente" : only;
|
|
3151
|
+
const slug = normalizeSlug(scope);
|
|
3152
|
+
const pad3 = (n) => String(n).padStart(2, "0");
|
|
3153
|
+
const stamp = `${now.getFullYear()}-${pad3(now.getMonth() + 1)}-${pad3(now.getDate())}_${pad3(now.getHours())}${pad3(now.getMinutes())}`;
|
|
3154
|
+
return `inventario_${slug}_${stamp}.${ext}`;
|
|
3155
|
+
}
|
|
3156
|
+
function normalizeSlug(value) {
|
|
3157
|
+
return value.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "todos";
|
|
3158
|
+
}
|
|
3159
|
+
|
|
2445
3160
|
// src/utils/devices/device.ts
|
|
2446
3161
|
var LETTERS = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
2447
3162
|
var DIGITS = "23456789";
|
|
@@ -3553,9 +4268,9 @@ function selectBreakdownItems(groups, profile = getActiveProfile(), domain = "en
|
|
|
3553
4268
|
out.push({ item, forcedCategory: null, sourceGroup: baseGroup, fromBaseGroup: true });
|
|
3554
4269
|
}
|
|
3555
4270
|
if (includes.size === 0) return out;
|
|
3556
|
-
for (const
|
|
3557
|
-
if (
|
|
3558
|
-
for (const item of groups[
|
|
4271
|
+
for (const groupKey2 of Object.keys(groups || {})) {
|
|
4272
|
+
if (groupKey2 === baseGroup) continue;
|
|
4273
|
+
for (const item of groups[groupKey2] ?? []) {
|
|
3559
4274
|
const key = normalizeDeviceOverrideId(item?.id);
|
|
3560
4275
|
if (!key || excludes.has(key) || seen.has(key)) continue;
|
|
3561
4276
|
const forced = includes.get(key);
|
|
@@ -3564,7 +4279,7 @@ function selectBreakdownItems(groups, profile = getActiveProfile(), domain = "en
|
|
|
3564
4279
|
out.push({
|
|
3565
4280
|
item,
|
|
3566
4281
|
forcedCategory: forced,
|
|
3567
|
-
sourceGroup:
|
|
4282
|
+
sourceGroup: groupKey2,
|
|
3568
4283
|
fromBaseGroup: false,
|
|
3569
4284
|
...parentFlag(key)
|
|
3570
4285
|
});
|
|
@@ -4015,13 +4730,13 @@ function resolveClassification(item, tree) {
|
|
|
4015
4730
|
if (!current) return null;
|
|
4016
4731
|
return { key: current.key, nodePath: path, matchedBy };
|
|
4017
4732
|
}
|
|
4018
|
-
function resolveSubcategory(item,
|
|
4019
|
-
const group = findNode(tree,
|
|
4733
|
+
function resolveSubcategory(item, groupKey2, tree) {
|
|
4734
|
+
const group = findNode(tree, groupKey2);
|
|
4020
4735
|
if (!group) return null;
|
|
4021
4736
|
const kids = classifiable(group.children ?? []);
|
|
4022
4737
|
if (kids.length === 0) return null;
|
|
4023
4738
|
const r = resolveClassification(item, kids);
|
|
4024
|
-
return r ? { ...r, nodePath: [
|
|
4739
|
+
return r ? { ...r, nodePath: [groupKey2, ...r.nodePath] } : null;
|
|
4025
4740
|
}
|
|
4026
4741
|
function findNode(tree, key) {
|
|
4027
4742
|
for (const n of tree ?? []) {
|
|
@@ -9089,7 +9804,7 @@ function sortDevices(a, b, sortMode, config2) {
|
|
|
9089
9804
|
return (a.label || "").localeCompare(b.label || "", "pt-BR", { sensitivity: "base" }) || a.value - b.value;
|
|
9090
9805
|
}
|
|
9091
9806
|
}
|
|
9092
|
-
function
|
|
9807
|
+
function applyFilters2(config2, STATE, enriched) {
|
|
9093
9808
|
let v = enriched.slice();
|
|
9094
9809
|
if (STATE.selectedShoppingIds?.length > 0) {
|
|
9095
9810
|
v = v.filter((x) => {
|
|
@@ -9588,7 +10303,7 @@ function createWidgetController(config2) {
|
|
|
9588
10303
|
};
|
|
9589
10304
|
let $root = null;
|
|
9590
10305
|
async function reflow() {
|
|
9591
|
-
const filtered =
|
|
10306
|
+
const filtered = applyFilters2(config2, STATE, STATE.itemsEnriched);
|
|
9592
10307
|
const { visible } = recomputePercentages(filtered);
|
|
9593
10308
|
updateStats(config2, visible, context);
|
|
9594
10309
|
await renderList(config2, STATE, visible, context);
|
|
@@ -9797,7 +10512,7 @@ function createWidgetController(config2) {
|
|
|
9797
10512
|
var DeviceGridWidgetFactory = {
|
|
9798
10513
|
createWidgetController,
|
|
9799
10514
|
createState,
|
|
9800
|
-
applyFilters,
|
|
10515
|
+
applyFilters: applyFilters2,
|
|
9801
10516
|
recomputePercentages,
|
|
9802
10517
|
buildEntityObject,
|
|
9803
10518
|
renderList,
|
|
@@ -63221,6 +63936,171 @@ function createTicketsTab(config2) {
|
|
|
63221
63936
|
return { destroy: () => tab.destroy() };
|
|
63222
63937
|
}
|
|
63223
63938
|
|
|
63939
|
+
// src/components/premium-modals/settings/commercialCatalog.ts
|
|
63940
|
+
var DEFAULT_STORE_SEGMENTS = [
|
|
63941
|
+
{
|
|
63942
|
+
segment: "Conveni\xEAncia / Servi\xE7os",
|
|
63943
|
+
activities: [
|
|
63944
|
+
"Ag\xEAncias De Viagens",
|
|
63945
|
+
"Alimentos Especias",
|
|
63946
|
+
"Consertos",
|
|
63947
|
+
"Correio",
|
|
63948
|
+
"Educa\xE7\xE3o/Ensino",
|
|
63949
|
+
"Emp\xF3rios",
|
|
63950
|
+
"Farm\xE1cias E Drogarias",
|
|
63951
|
+
"Foto Revela\xE7\xE3o",
|
|
63952
|
+
"Lavanderia",
|
|
63953
|
+
"Lot\xE9rica",
|
|
63954
|
+
"Outros Servi\xE7os",
|
|
63955
|
+
"Pet Shop",
|
|
63956
|
+
"Servi\xE7os Automotivos",
|
|
63957
|
+
"Servi\xE7os Est\xE9ticos",
|
|
63958
|
+
"Servi\xE7os Financeiros",
|
|
63959
|
+
"Servi\xE7os Gr\xE1ficos",
|
|
63960
|
+
"Servi\xE7os M\xE9dicos(Cl\xEDnicas/Laborat\xF3rios)",
|
|
63961
|
+
"Servi\xE7os P\xFAblicos",
|
|
63962
|
+
"Tatuagem/Piercing",
|
|
63963
|
+
"Venda E Loca\xE7\xE3o De Ve\xEDculos"
|
|
63964
|
+
]
|
|
63965
|
+
},
|
|
63966
|
+
{
|
|
63967
|
+
segment: "Entretenimento",
|
|
63968
|
+
activities: [
|
|
63969
|
+
"Arena Gamer",
|
|
63970
|
+
"Boliche",
|
|
63971
|
+
"Cinemas",
|
|
63972
|
+
"Outros(Museu,Espa\xE7o Cultural,Etc)",
|
|
63973
|
+
"Parques E Games"
|
|
63974
|
+
]
|
|
63975
|
+
},
|
|
63976
|
+
{
|
|
63977
|
+
segment: "Lojas \xC2ncoras",
|
|
63978
|
+
activities: [
|
|
63979
|
+
"Academias",
|
|
63980
|
+
"Artigos Esportivos",
|
|
63981
|
+
"Centros Educacionais / Escolas / Faculdades / Universidades",
|
|
63982
|
+
"Constru\xE7\xE3o E Decora\xE7\xE3o",
|
|
63983
|
+
"Eletrodom\xE9sticos, Eletr\xF4nicos",
|
|
63984
|
+
"Hipermercado / Supermercado / Atacarejo",
|
|
63985
|
+
"Magazines E/Ou Utens\xEDlios Para O Lar E Conveni\xEAncia",
|
|
63986
|
+
"Moda",
|
|
63987
|
+
"Outros"
|
|
63988
|
+
]
|
|
63989
|
+
},
|
|
63990
|
+
{
|
|
63991
|
+
segment: "Lojas Sat\xE9lites",
|
|
63992
|
+
activities: [
|
|
63993
|
+
"Acess\xF3rios",
|
|
63994
|
+
"Acess\xF3rios E Artigos Para Viagens",
|
|
63995
|
+
"Artigos Eletr\xF4nicos/Tecnologia Da Informa\xE7\xE3o(Ti)",
|
|
63996
|
+
"Brinquedos",
|
|
63997
|
+
"Caf\xE9s, Bares E Ch\xE1s",
|
|
63998
|
+
"Cal\xE7ados Esportivos",
|
|
63999
|
+
"Cal\xE7ados Feminimos",
|
|
64000
|
+
"Cal\xE7ados Geral",
|
|
64001
|
+
"Cal\xE7ados Infantis",
|
|
64002
|
+
"Cal\xE7ados Masculinos",
|
|
64003
|
+
"Cama/Mesa/Banho",
|
|
64004
|
+
"Colch\xF5es",
|
|
64005
|
+
"Docerias",
|
|
64006
|
+
"Fast-Food",
|
|
64007
|
+
"Livraria",
|
|
64008
|
+
"Moda Esportiva",
|
|
64009
|
+
"Moda Feminina",
|
|
64010
|
+
"Moda Geral",
|
|
64011
|
+
"Moda Infantil",
|
|
64012
|
+
"Moda \xCDntima E Roupas Para Dormir",
|
|
64013
|
+
"Moda Masculina",
|
|
64014
|
+
"Moda Praia",
|
|
64015
|
+
"Moda Unissex",
|
|
64016
|
+
"\xD3ticas",
|
|
64017
|
+
"Outros",
|
|
64018
|
+
"Perfumaria, Maquiagem E Cosm\xE9ticos",
|
|
64019
|
+
"Puericultura",
|
|
64020
|
+
"Relojoarias, Joalherias",
|
|
64021
|
+
"Restaurantes Com Servi\xE7os",
|
|
64022
|
+
"Restaurantes Sem Servi\xE7os",
|
|
64023
|
+
"Surfewear / Streetwear",
|
|
64024
|
+
"Telefonia Geral",
|
|
64025
|
+
"Utens\xEDlios P/ Lar, Acess\xF3rios P/ Decora\xE7\xE3o E Presentes"
|
|
64026
|
+
]
|
|
64027
|
+
},
|
|
64028
|
+
{
|
|
64029
|
+
segment: "Mall E Merchandising",
|
|
64030
|
+
activities: [
|
|
64031
|
+
"Acess\xF3rios",
|
|
64032
|
+
"Alimenta\xE7\xE3o E Bebidas",
|
|
64033
|
+
"Antenas De Operadoras",
|
|
64034
|
+
"Artigos Esportivos",
|
|
64035
|
+
"Artigos Para O Lar",
|
|
64036
|
+
"Brinquedos",
|
|
64037
|
+
"Cal\xE7ados",
|
|
64038
|
+
"Conveni\xEAncia / Servi\xE7os",
|
|
64039
|
+
"Eletr\xF4nicos",
|
|
64040
|
+
"Eventos",
|
|
64041
|
+
"Geek",
|
|
64042
|
+
"Livraria",
|
|
64043
|
+
"M\xEDdia",
|
|
64044
|
+
"\xD3ticas",
|
|
64045
|
+
"Outros",
|
|
64046
|
+
"Papelaria",
|
|
64047
|
+
"Perfumaria, Maquiagem E Cosm\xE9ticos",
|
|
64048
|
+
"Relojoarias E Joalherias",
|
|
64049
|
+
"Telefonia E Acess\xF3rios",
|
|
64050
|
+
"Vending Machines",
|
|
64051
|
+
"Vestu\xE1rio"
|
|
64052
|
+
]
|
|
64053
|
+
},
|
|
64054
|
+
{
|
|
64055
|
+
segment: "Megalojas",
|
|
64056
|
+
activities: [
|
|
64057
|
+
"Alimenta\xE7\xE3o E Bebidas",
|
|
64058
|
+
"Artigos Esportivos",
|
|
64059
|
+
"Brinquedos",
|
|
64060
|
+
"Centros Educacionais / Escolas / Faculdades / Universidades",
|
|
64061
|
+
"Constru\xE7\xE3o, Decora\xE7\xE3o",
|
|
64062
|
+
"Eletrodom\xE9sticos, Eletr\xF4nicos, Magazines E/Ou Utens. P/Lar",
|
|
64063
|
+
"Livrarias",
|
|
64064
|
+
"Magazines E/Ou Utens\xEDlios Para O Lar E Conveni\xEAncia",
|
|
64065
|
+
"Material De Escrit\xF3rio / Papelaria / Inform\xE1tica",
|
|
64066
|
+
"Moda",
|
|
64067
|
+
"Outros",
|
|
64068
|
+
"Puericultura"
|
|
64069
|
+
]
|
|
64070
|
+
},
|
|
64071
|
+
{
|
|
64072
|
+
segment: "Semi-\xC2ncoras",
|
|
64073
|
+
activities: [
|
|
64074
|
+
"Academias",
|
|
64075
|
+
"Alimenta\xE7\xE3o E Bebidas",
|
|
64076
|
+
"Artigos Esportivos",
|
|
64077
|
+
"Brinquedos",
|
|
64078
|
+
"Centros Educacionais / Escolas / Faculdades / Universidades",
|
|
64079
|
+
"Eletrodom\xE9sticos, Eletr\xF4nicos, Magazines E/Ou Utens. P/Lar",
|
|
64080
|
+
"Livrarias",
|
|
64081
|
+
"Magazines E/Ou Utens\xEDlios Para O Lar E Conveni\xEAncia",
|
|
64082
|
+
"Material De Escrit\xF3rio / Papelaria / Inform\xE1tica",
|
|
64083
|
+
"Moda",
|
|
64084
|
+
"Outros"
|
|
64085
|
+
]
|
|
64086
|
+
}
|
|
64087
|
+
];
|
|
64088
|
+
async function loadStoreSegmentCatalog(source) {
|
|
64089
|
+
if (!source) return DEFAULT_STORE_SEGMENTS;
|
|
64090
|
+
try {
|
|
64091
|
+
const list = typeof source === "function" ? await source() : source;
|
|
64092
|
+
return Array.isArray(list) && list.length > 0 ? list : DEFAULT_STORE_SEGMENTS;
|
|
64093
|
+
} catch (err) {
|
|
64094
|
+
console.warn("[SettingsModal] segmentCatalog loader falhou \u2014 usando cat\xE1logo padr\xE3o:", err);
|
|
64095
|
+
return DEFAULT_STORE_SEGMENTS;
|
|
64096
|
+
}
|
|
64097
|
+
}
|
|
64098
|
+
function activitiesForSegment(catalog, segment, currentActivity) {
|
|
64099
|
+
const list = catalog.find((s) => s.segment === segment)?.activities ?? [];
|
|
64100
|
+
if (currentActivity && !list.includes(currentActivity)) return [...list, currentActivity];
|
|
64101
|
+
return list;
|
|
64102
|
+
}
|
|
64103
|
+
|
|
63224
64104
|
// src/components/createInputDateRangePickerInsideDIV.ts
|
|
63225
64105
|
var PREMIUM_STYLES = `
|
|
63226
64106
|
.myio-daterange-wrapper {
|
|
@@ -63569,6 +64449,9 @@ var SettingsModalView = class _SettingsModalView {
|
|
|
63569
64449
|
if (lastUpdatedEl) {
|
|
63570
64450
|
lastUpdatedEl.textContent = formData.lastUpdatedTime ? this.formatTs(formData.lastUpdatedTime) : "\u2014";
|
|
63571
64451
|
}
|
|
64452
|
+
if (this.isSuperAdmin()) {
|
|
64453
|
+
this.initCommercialFields(formData);
|
|
64454
|
+
}
|
|
63572
64455
|
if (!this.config.gcdrDeviceId && formData.gcdrDeviceId) {
|
|
63573
64456
|
this.config.gcdrDeviceId = formData.gcdrDeviceId;
|
|
63574
64457
|
}
|
|
@@ -64202,6 +65085,7 @@ var SettingsModalView = class _SettingsModalView {
|
|
|
64202
65085
|
</div>
|
|
64203
65086
|
|
|
64204
65087
|
</div>
|
|
65088
|
+
${this.isSuperAdmin() ? this.getCommercialFieldsHTML() : ""}
|
|
64205
65089
|
</div>
|
|
64206
65090
|
|
|
64207
65091
|
<!-- Central/gateway identity+telemetry \u2014 only for CentralSettingsModal (isGateway);
|
|
@@ -64219,6 +65103,71 @@ var SettingsModalView = class _SettingsModalView {
|
|
|
64219
65103
|
</div>
|
|
64220
65104
|
`;
|
|
64221
65105
|
}
|
|
65106
|
+
/**
|
|
65107
|
+
* Campos comerciais — só @myio / superadmin (o bloco nem é renderizado para os demais,
|
|
65108
|
+
* então getFormData não envia essas chaves e o save não as sobrescreve).
|
|
65109
|
+
* Linha 1: ABL + Contrato (texto). Linha 2: Segmento → Atividade (selects em cascata,
|
|
65110
|
+
* opções preenchidas em initCommercialFields após carregar o catálogo).
|
|
65111
|
+
*/
|
|
65112
|
+
getCommercialFieldsHTML() {
|
|
65113
|
+
const customerName = String(
|
|
65114
|
+
this.config.customerName || window.MyIOUtils?.customerName || ""
|
|
65115
|
+
).trim();
|
|
65116
|
+
const escName = customerName.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
65117
|
+
return `
|
|
65118
|
+
<div class="commercial-block">
|
|
65119
|
+
<div class="commercial-title">Dados de Cadastro${escName ? ` <span class="commercial-sep">|</span> <span class="commercial-customer">${escName.toLocaleUpperCase("pt-BR")}</span>` : ""}</div>
|
|
65120
|
+
<div class="commercial-grid">
|
|
65121
|
+
<div class="commercial-field">
|
|
65122
|
+
<label class="identity-field-label" for="abl">ABL</label>
|
|
65123
|
+
<input type="text" id="abl" name="abl" class="identity-input" maxlength="50" placeholder="Ex.: 120,50 m\xB2">
|
|
65124
|
+
</div>
|
|
65125
|
+
<div class="commercial-field">
|
|
65126
|
+
<label class="identity-field-label" for="contract">Contrato</label>
|
|
65127
|
+
<input type="text" id="contract" name="contract" class="identity-input" maxlength="100" placeholder="N\xBA / identifica\xE7\xE3o do contrato">
|
|
65128
|
+
</div>
|
|
65129
|
+
<div class="commercial-field">
|
|
65130
|
+
<label class="identity-field-label" for="segment">Segmento</label>
|
|
65131
|
+
<select id="segment" name="segment" class="identity-input" disabled>
|
|
65132
|
+
<option value="">Carregando segmentos\u2026</option>
|
|
65133
|
+
</select>
|
|
65134
|
+
</div>
|
|
65135
|
+
<div class="commercial-field">
|
|
65136
|
+
<label class="identity-field-label" for="activity">Atividade</label>
|
|
65137
|
+
<select id="activity" name="activity" class="identity-input" disabled>
|
|
65138
|
+
<option value="">Selecione o segmento primeiro</option>
|
|
65139
|
+
</select>
|
|
65140
|
+
</div>
|
|
65141
|
+
</div>
|
|
65142
|
+
</div>
|
|
65143
|
+
`;
|
|
65144
|
+
}
|
|
65145
|
+
/** Carrega o catálogo de segmentos e liga a cascata Segmento → Atividade, restaurando os valores salvos. */
|
|
65146
|
+
async initCommercialFields(saved) {
|
|
65147
|
+
const segmentEl = this.modal.querySelector("#segment");
|
|
65148
|
+
const activityEl = this.modal.querySelector("#activity");
|
|
65149
|
+
if (!segmentEl || !activityEl) return;
|
|
65150
|
+
const esc9 = (s) => s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
65151
|
+
const options = (values, selected, placeholder) => `<option value="">${placeholder}</option>` + values.map((v) => `<option value="${esc9(v)}"${v === selected ? " selected" : ""}>${esc9(v)}</option>`).join("");
|
|
65152
|
+
const catalog = await loadStoreSegmentCatalog(this.config.segmentCatalog);
|
|
65153
|
+
const savedSegment = String(saved.segment || "");
|
|
65154
|
+
const savedActivity = String(saved.activity || "");
|
|
65155
|
+
const segments = catalog.map((s) => s.segment);
|
|
65156
|
+
if (savedSegment && !segments.includes(savedSegment)) segments.push(savedSegment);
|
|
65157
|
+
segmentEl.innerHTML = options(segments, savedSegment, "Selecione\u2026");
|
|
65158
|
+
segmentEl.disabled = false;
|
|
65159
|
+
const fillActivities = (segment, selected) => {
|
|
65160
|
+
if (!segment) {
|
|
65161
|
+
activityEl.innerHTML = options([], "", "Selecione o segmento primeiro");
|
|
65162
|
+
activityEl.disabled = true;
|
|
65163
|
+
return;
|
|
65164
|
+
}
|
|
65165
|
+
activityEl.innerHTML = options(activitiesForSegment(catalog, segment, selected), selected, "Selecione\u2026");
|
|
65166
|
+
activityEl.disabled = false;
|
|
65167
|
+
};
|
|
65168
|
+
fillActivities(savedSegment, savedActivity);
|
|
65169
|
+
segmentEl.addEventListener("change", () => fillActivities(segmentEl.value, ""));
|
|
65170
|
+
}
|
|
64222
65171
|
/** RFC-0171: Offset de Temperatura — sempre visível para domain=temperature; editável só para @myio.com.br */
|
|
64223
65172
|
getTemperatureOffsetHTML() {
|
|
64224
65173
|
const superAdmin = this.isSuperAdmin();
|
|
@@ -65902,6 +66851,49 @@ var SettingsModalView = class _SettingsModalView {
|
|
|
65902
66851
|
cursor: default;
|
|
65903
66852
|
}
|
|
65904
66853
|
|
|
66854
|
+
/* Campos comerciais (s\xF3 @myio / superadmin) */
|
|
66855
|
+
.commercial-block {
|
|
66856
|
+
margin-top: 14px;
|
|
66857
|
+
padding-top: 12px;
|
|
66858
|
+
border-top: 1px dashed #e5e7eb;
|
|
66859
|
+
}
|
|
66860
|
+
.commercial-title {
|
|
66861
|
+
display: flex;
|
|
66862
|
+
align-items: center;
|
|
66863
|
+
gap: 8px;
|
|
66864
|
+
font-size: 12px;
|
|
66865
|
+
font-weight: 700;
|
|
66866
|
+
color: #495057;
|
|
66867
|
+
margin-bottom: 8px;
|
|
66868
|
+
}
|
|
66869
|
+
.commercial-sep {
|
|
66870
|
+
color: #ced4da;
|
|
66871
|
+
font-weight: 400;
|
|
66872
|
+
}
|
|
66873
|
+
.commercial-customer {
|
|
66874
|
+
color: var(--myio-brand-700, #3e1a7d);
|
|
66875
|
+
letter-spacing: 0.3px;
|
|
66876
|
+
}
|
|
66877
|
+
.commercial-grid {
|
|
66878
|
+
display: grid;
|
|
66879
|
+
grid-template-columns: 1fr 1fr;
|
|
66880
|
+
gap: 10px 16px;
|
|
66881
|
+
}
|
|
66882
|
+
.commercial-field {
|
|
66883
|
+
display: flex;
|
|
66884
|
+
flex-direction: column;
|
|
66885
|
+
gap: 5px;
|
|
66886
|
+
}
|
|
66887
|
+
select.identity-input {
|
|
66888
|
+
height: 30px;
|
|
66889
|
+
cursor: pointer;
|
|
66890
|
+
}
|
|
66891
|
+
select.identity-input:disabled {
|
|
66892
|
+
background: #f8f9fa;
|
|
66893
|
+
color: #9ca3af;
|
|
66894
|
+
cursor: not-allowed;
|
|
66895
|
+
}
|
|
66896
|
+
|
|
65905
66897
|
/* Col 3: date info block */
|
|
65906
66898
|
.identity-dates-block {
|
|
65907
66899
|
grid-column: 3;
|
|
@@ -66900,6 +67892,11 @@ var SettingsModalView = class _SettingsModalView {
|
|
|
66900
67892
|
color: #6c757d;
|
|
66901
67893
|
border-color: #373a40;
|
|
66902
67894
|
}
|
|
67895
|
+
.theme-dark .commercial-block { border-top-color: #373a40; }
|
|
67896
|
+
.theme-dark .commercial-title { color: #ced4da; }
|
|
67897
|
+
.theme-dark .commercial-sep { color: #495057; }
|
|
67898
|
+
.theme-dark .commercial-customer { color: #c4b5fd; }
|
|
67899
|
+
.theme-dark select.identity-input:disabled { background: #1a1b1e; color: #6c757d; }
|
|
66903
67900
|
.theme-dark .device-name-subtitle {
|
|
66904
67901
|
color: #6c757d;
|
|
66905
67902
|
}
|
|
@@ -77387,6 +78384,8 @@ var DefaultSettingsFetcher = class _DefaultSettingsFetcher {
|
|
|
77387
78384
|
attributes.lastUpdatedTime = attr.value;
|
|
77388
78385
|
} else if (attr.key === "gcdrDeviceId") {
|
|
77389
78386
|
attributes.gcdrDeviceId = attr.value;
|
|
78387
|
+
} else if (["abl", "contract", "segment", "activity"].includes(attr.key)) {
|
|
78388
|
+
attributes[attr.key] = String(attr.value);
|
|
77390
78389
|
}
|
|
77391
78390
|
}
|
|
77392
78391
|
}
|
|
@@ -77416,7 +78415,12 @@ var DefaultSettingsFetcher = class _DefaultSettingsFetcher {
|
|
|
77416
78415
|
const stringFields = [
|
|
77417
78416
|
"label",
|
|
77418
78417
|
"floor",
|
|
77419
|
-
"identifier"
|
|
78418
|
+
"identifier",
|
|
78419
|
+
// Campos comerciais (só @myio / superadmin no modal)
|
|
78420
|
+
"abl",
|
|
78421
|
+
"contract",
|
|
78422
|
+
"segment",
|
|
78423
|
+
"activity"
|
|
77420
78424
|
];
|
|
77421
78425
|
for (const field of stringFields) {
|
|
77422
78426
|
if (data[field] && typeof data[field] === "string") {
|
|
@@ -77526,6 +78530,7 @@ var SettingsController = class {
|
|
|
77526
78530
|
superadmin: params.superadmin,
|
|
77527
78531
|
userEmail: params.userEmail || window.MyIOUtils?.currentUserEmail || null,
|
|
77528
78532
|
holdingAdmin: params.holdingAdmin ?? window.MyIOUtils?.HoldingAdmin ?? false,
|
|
78533
|
+
segmentCatalog: params.segmentCatalog,
|
|
77529
78534
|
// RFC-0144: Pass enableAnnotationsOnboarding flag for onboarding control
|
|
77530
78535
|
enableAnnotationsOnboarding: params.enableAnnotationsOnboarding ?? false,
|
|
77531
78536
|
// RFC-0180: Raw device name + GCDR identifiers for Alarms tab
|
|
@@ -77849,6 +78854,12 @@ var SettingsController = class {
|
|
|
77849
78854
|
if (formData.floor && formData.floor.length > 50) {
|
|
77850
78855
|
errors.push("Floor must be 50 characters or less");
|
|
77851
78856
|
}
|
|
78857
|
+
if (formData.abl && formData.abl.length > 50) {
|
|
78858
|
+
errors.push("ABL must be 50 characters or less");
|
|
78859
|
+
}
|
|
78860
|
+
if (formData.contract && formData.contract.length > 100) {
|
|
78861
|
+
errors.push("Contract must be 100 characters or less");
|
|
78862
|
+
}
|
|
77852
78863
|
if (formData.storeNumber && formData.storeNumber.length > 20) {
|
|
77853
78864
|
errors.push("Store number must be 20 characters or less");
|
|
77854
78865
|
}
|
|
@@ -78602,7 +79613,7 @@ function formatDate4(date, locale) {
|
|
|
78602
79613
|
year: "numeric"
|
|
78603
79614
|
});
|
|
78604
79615
|
}
|
|
78605
|
-
function
|
|
79616
|
+
function formatDateTime2(date, locale) {
|
|
78606
79617
|
return date.toLocaleDateString(locale, {
|
|
78607
79618
|
day: "2-digit",
|
|
78608
79619
|
month: "2-digit",
|
|
@@ -78728,7 +79739,7 @@ function processMultiSeriesChartData(rawData, keys, correctionFactor, locale, ag
|
|
|
78728
79739
|
value: maxPoint.y,
|
|
78729
79740
|
timestamp: maxPoint.x,
|
|
78730
79741
|
formattedValue: maxPoint.y.toFixed(2),
|
|
78731
|
-
formattedTime:
|
|
79742
|
+
formattedTime: formatDateTime2(new Date(maxPoint.x), locale),
|
|
78732
79743
|
key
|
|
78733
79744
|
};
|
|
78734
79745
|
if (!globalPeak || seriesPeak.value > globalPeak.value) {
|
|
@@ -82257,8 +83268,8 @@ function buildReportItemsList(groups, domain, group) {
|
|
|
82257
83268
|
if (group === "todos") {
|
|
82258
83269
|
return Object.entries(g).filter(([key]) => key !== "ocultos").flatMap(([key, items]) => (items || []).map((d) => toItem(d, domain, GROUP_LABELS[key] || key)));
|
|
82259
83270
|
}
|
|
82260
|
-
const
|
|
82261
|
-
return (g[
|
|
83271
|
+
const groupKey2 = group === "area_comum" ? "areacomum" : group;
|
|
83272
|
+
return (g[groupKey2] || []).map((d) => toItem(d, domain, null));
|
|
82262
83273
|
}
|
|
82263
83274
|
|
|
82264
83275
|
// src/components/premium-modals/reports-hub/handlers.ts
|
|
@@ -100360,7 +101371,7 @@ var DOMAIN_ICONS = {
|
|
|
100360
101371
|
water: DOMAIN_MAP.water.icon,
|
|
100361
101372
|
temperature: DOMAIN_MAP.temperature.icon
|
|
100362
101373
|
};
|
|
100363
|
-
var
|
|
101374
|
+
var DOMAIN_LABELS2 = {
|
|
100364
101375
|
energy: DOMAIN_MAP.energy.name,
|
|
100365
101376
|
water: DOMAIN_MAP.water.name,
|
|
100366
101377
|
temperature: DOMAIN_MAP.temperature.name
|
|
@@ -100679,10 +101690,10 @@ function buildTemplateExport(params) {
|
|
|
100679
101690
|
locale,
|
|
100680
101691
|
includeChart,
|
|
100681
101692
|
includeStats,
|
|
100682
|
-
headerText: headerText || `${
|
|
101693
|
+
headerText: headerText || `${DOMAIN_LABELS2[domain]} Report`,
|
|
100683
101694
|
footerText: footerText || "Generated by MyIO Platform",
|
|
100684
101695
|
domainIcon: DOMAIN_ICONS[domain],
|
|
100685
|
-
domainLabel:
|
|
101696
|
+
domainLabel: DOMAIN_LABELS2[domain],
|
|
100686
101697
|
domainUnit: DOMAIN_UNITS[domain]
|
|
100687
101698
|
};
|
|
100688
101699
|
}
|
|
@@ -100774,7 +101785,7 @@ function myioExportData(data, config2, options) {
|
|
|
100774
101785
|
}
|
|
100775
101786
|
var EXPORT_DEFAULT_COLORS = DEFAULT_COLORS4;
|
|
100776
101787
|
var EXPORT_DOMAIN_ICONS = DOMAIN_ICONS;
|
|
100777
|
-
var EXPORT_DOMAIN_LABELS =
|
|
101788
|
+
var EXPORT_DOMAIN_LABELS = DOMAIN_LABELS2;
|
|
100778
101789
|
var EXPORT_DOMAIN_UNITS = DOMAIN_UNITS;
|
|
100779
101790
|
|
|
100780
101791
|
// src/components/DistributionChart/colorManager.ts
|
|
@@ -108641,11 +109652,11 @@ function renderStep2(state6, modalId, colors2, t) {
|
|
|
108641
109652
|
const sortedDevices = sortDevices2(searchFilteredDevices, sortField, sortOrder);
|
|
108642
109653
|
const gridHeight = state6.isMaximized ? "calc(100vh - 340px)" : "360px";
|
|
108643
109654
|
const hasActiveFilters = filterTypes.length > 0 || filterDeviceTypes.length > 0 || filterDeviceProfiles.length > 0 || filterStatuses.length > 0 || filterTelemetryKeys.length > 0;
|
|
108644
|
-
const renderSortableHeader = (
|
|
109655
|
+
const renderSortableHeader = (col2, label, field, width) => {
|
|
108645
109656
|
const isActive = sortField === field;
|
|
108646
109657
|
const arrow = isActive ? sortOrder === "asc" ? "\u25B2" : "\u25BC" : "\u25BD";
|
|
108647
109658
|
return `
|
|
108648
|
-
<div id="${modalId}-sort-col-${
|
|
109659
|
+
<div id="${modalId}-sort-col-${col2}" data-sort-field="${field}" style="
|
|
108649
109660
|
width: ${width}px; padding: 0 6px; display: flex; align-items: center; justify-content: space-between;
|
|
108650
109661
|
border-right: 1px solid ${colors2.border}; cursor: pointer; user-select: none;
|
|
108651
109662
|
${isActive ? `background: rgba(62,26,125,0.1);` : ""}
|
|
@@ -110519,8 +111530,8 @@ function setupEventListeners5(container, state6, modalId, t, onClose) {
|
|
|
110519
111530
|
{ col: "centralId", field: "centralId" },
|
|
110520
111531
|
{ col: "slaveId", field: "slaveId" }
|
|
110521
111532
|
];
|
|
110522
|
-
sortableColumns.forEach(({ col, field }) => {
|
|
110523
|
-
document.getElementById(`${modalId}-sort-col-${
|
|
111533
|
+
sortableColumns.forEach(({ col: col2, field }) => {
|
|
111534
|
+
document.getElementById(`${modalId}-sort-col-${col2}`)?.addEventListener("click", () => {
|
|
110524
111535
|
if (state6.deviceSort.field === field) {
|
|
110525
111536
|
state6.deviceSort.order = state6.deviceSort.order === "asc" ? "desc" : "asc";
|
|
110526
111537
|
} else {
|
|
@@ -116420,10 +117431,10 @@ var UserListTab = class {
|
|
|
116420
117431
|
const popup = document.createElement("div");
|
|
116421
117432
|
popup.className = "um-assign-popup";
|
|
116422
117433
|
popup.setAttribute("data-theme", this.config.theme || "light");
|
|
116423
|
-
const
|
|
117434
|
+
const displayName2 = this.displayName(user);
|
|
116424
117435
|
popup.innerHTML = `
|
|
116425
117436
|
<div class="um-assign-popup-header">
|
|
116426
|
-
<span class="um-assign-popup-title">\u{1F511} Fun\xE7\xF5es \u2014 ${this.esc(
|
|
117437
|
+
<span class="um-assign-popup-title">\u{1F511} Fun\xE7\xF5es \u2014 ${this.esc(displayName2)}</span>
|
|
116427
117438
|
<button class="um-assign-popup-close" type="button">\u2715</button>
|
|
116428
117439
|
</div>
|
|
116429
117440
|
<div class="um-assign-popup-body">
|
|
@@ -116545,7 +117556,7 @@ var UserListTab = class {
|
|
|
116545
117556
|
tooltip.setAttribute("data-theme", this.config.theme || "light");
|
|
116546
117557
|
this.syncTooltipEl = tooltip;
|
|
116547
117558
|
const syncing = this.gcdrSyncing.has(uid2);
|
|
116548
|
-
const
|
|
117559
|
+
const displayName2 = this.displayName(user);
|
|
116549
117560
|
let bodyHtml;
|
|
116550
117561
|
if (syncing) {
|
|
116551
117562
|
bodyHtml = `<div class="um-sync-tooltip-row" style="justify-content:center;padding:8px 0;">
|
|
@@ -116595,7 +117606,7 @@ var UserListTab = class {
|
|
|
116595
117606
|
<polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/>
|
|
116596
117607
|
<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
117608
|
</svg>
|
|
116598
|
-
<span>GCDR Sync \u2014 ${this.esc(
|
|
117609
|
+
<span>GCDR Sync \u2014 ${this.esc(displayName2)}</span>
|
|
116599
117610
|
</div>
|
|
116600
117611
|
<div class="um-sync-tooltip-body">${bodyHtml}</div>
|
|
116601
117612
|
`;
|
|
@@ -123663,9 +124674,9 @@ var MenuView = class {
|
|
|
123663
124674
|
const isActive = isActiveTab && contextId === currentContextId;
|
|
123664
124675
|
el2.classList.toggle("is-active", isActive);
|
|
123665
124676
|
});
|
|
123666
|
-
this.root.querySelectorAll(".myio-unified-column").forEach((
|
|
123667
|
-
const tabId =
|
|
123668
|
-
|
|
124677
|
+
this.root.querySelectorAll(".myio-unified-column").forEach((col2) => {
|
|
124678
|
+
const tabId = col2.classList.contains("energy") ? "energy" : col2.classList.contains("water") ? "water" : col2.classList.contains("temperature") ? "temperature" : "";
|
|
124679
|
+
col2.classList.toggle("is-active-column", tabId === this.activeTabId);
|
|
123669
124680
|
});
|
|
123670
124681
|
}
|
|
123671
124682
|
/**
|
|
@@ -137632,8 +138643,8 @@ var TelemetryGridShoppingView = class {
|
|
|
137632
138643
|
this.controller.setSortMode(mode);
|
|
137633
138644
|
});
|
|
137634
138645
|
});
|
|
137635
|
-
const
|
|
137636
|
-
|
|
138646
|
+
const applyFilters3 = this.filterModalEl.querySelector("#applyFilters");
|
|
138647
|
+
applyFilters3?.addEventListener("click", () => {
|
|
137637
138648
|
this.applySelectedFilters();
|
|
137638
138649
|
this.closeFilterModal();
|
|
137639
138650
|
this.renderCards();
|
|
@@ -147064,11 +148075,11 @@ var AlarmsNotificationsPanelView = class {
|
|
|
147064
148075
|
this.root.addEventListener("click", (e) => {
|
|
147065
148076
|
const th = e.target.closest("[data-sort-col]");
|
|
147066
148077
|
if (!th) return;
|
|
147067
|
-
const
|
|
147068
|
-
if (this.sortCol ===
|
|
148078
|
+
const col2 = th.getAttribute("data-sort-col");
|
|
148079
|
+
if (this.sortCol === col2) {
|
|
147069
148080
|
this.sortDir = this.sortDir === "asc" ? "desc" : "asc";
|
|
147070
148081
|
} else {
|
|
147071
|
-
this.sortCol =
|
|
148082
|
+
this.sortCol = col2;
|
|
147072
148083
|
this.sortDir = "asc";
|
|
147073
148084
|
}
|
|
147074
148085
|
this.renderListContent(this.controller.getState());
|
|
@@ -147712,10 +148723,10 @@ var AlarmsNotificationsPanelView = class {
|
|
|
147712
148723
|
}
|
|
147713
148724
|
});
|
|
147714
148725
|
}
|
|
147715
|
-
const th = (label,
|
|
147716
|
-
const active = this.sortCol ===
|
|
148726
|
+
const th = (label, col2, extraClass = "") => {
|
|
148727
|
+
const active = this.sortCol === col2;
|
|
147717
148728
|
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="${
|
|
148729
|
+
return `<th class="atbl-th atbl-th--sortable${extraClass ? " " + extraClass : ""}${active ? " is-sorted" : ""}" data-sort-col="${col2}">${label}${icon2}</th>`;
|
|
147719
148730
|
};
|
|
147720
148731
|
const rows = alarms.map((alarm) => {
|
|
147721
148732
|
const sev = SEVERITY_CONFIG[alarm.severity];
|
|
@@ -148442,10 +149453,10 @@ var AlarmsNotificationsPanelView = class {
|
|
|
148442
149453
|
const gOcc = totalOcc(groupAlarms);
|
|
148443
149454
|
const gSCfg = severityCfg(gSev);
|
|
148444
149455
|
const gStCfg = stateCfg(gSt);
|
|
148445
|
-
const
|
|
148446
|
-
const isGroupOpen = this.ruleFirstOpenGroups.has(
|
|
149456
|
+
const groupKey2 = `${ruleKey}||${central}`;
|
|
149457
|
+
const isGroupOpen = this.ruleFirstOpenGroups.has(groupKey2);
|
|
148447
149458
|
const escCentral = this.esc(central);
|
|
148448
|
-
const escGroupKey = this.esc(
|
|
149459
|
+
const escGroupKey = this.esc(groupKey2);
|
|
148449
149460
|
const deviceMap = /* @__PURE__ */ new Map();
|
|
148450
149461
|
for (const atom of atoms) {
|
|
148451
149462
|
if (!deviceMap.has(atom.device)) deviceMap.set(atom.device, []);
|
|
@@ -151649,7 +152660,7 @@ function formatDateShort(dateStr) {
|
|
|
151649
152660
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
151650
152661
|
return `${day}/${month}`;
|
|
151651
152662
|
}
|
|
151652
|
-
function
|
|
152663
|
+
function formatDateTime3(dateStr) {
|
|
151653
152664
|
const date = new Date(dateStr);
|
|
151654
152665
|
const day = String(date.getDate()).padStart(2, "0");
|
|
151655
152666
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
@@ -151723,7 +152734,7 @@ function renderMTBFTimelineChart(data) {
|
|
|
151723
152734
|
segmentPaths += `
|
|
151724
152735
|
<rect x="${x1}" y="${onY}" width="${segWidth}" height="${barHeight}"
|
|
151725
152736
|
fill="#22c55e" rx="3" class="mtbf-segment operating"
|
|
151726
|
-
data-tooltip="Operacao|Inicio: ${
|
|
152737
|
+
data-tooltip="Operacao|Inicio: ${formatDateTime3(seg.startTime)}|Fim: ${formatDateTime3(seg.endTime)}|Duracao: ${formatHoursDisplay(seg.durationHours)}${seg.activeEquipments ? `|Equipamentos ativos: ${seg.activeEquipments}/${data.totalEquipment}` : ""}" />
|
|
151727
152738
|
`;
|
|
151728
152739
|
const centerX = x1 + segWidth / 2;
|
|
151729
152740
|
if (segWidth > 50) {
|
|
@@ -151738,8 +152749,8 @@ function renderMTBFTimelineChart(data) {
|
|
|
151738
152749
|
<rect x="${x1}" y="${onY}" width="${segWidth}" height="${barHeight}"
|
|
151739
152750
|
fill="transparent" class="tooltip-trigger"
|
|
151740
152751
|
data-type="operating"
|
|
151741
|
-
data-start="${
|
|
151742
|
-
data-end="${
|
|
152752
|
+
data-start="${formatDateTime3(seg.startTime)}"
|
|
152753
|
+
data-end="${formatDateTime3(seg.endTime)}"
|
|
151743
152754
|
data-duration="${formatHoursDisplay(seg.durationHours)}"
|
|
151744
152755
|
data-active="${seg.activeEquipments || data.totalEquipment}" />
|
|
151745
152756
|
`;
|
|
@@ -151748,7 +152759,7 @@ function renderMTBFTimelineChart(data) {
|
|
|
151748
152759
|
segmentPaths += `
|
|
151749
152760
|
<rect x="${x1}" y="${offY - 15}" width="${segWidth}" height="20"
|
|
151750
152761
|
fill="#ef4444" rx="2" class="mtbf-segment stopped"
|
|
151751
|
-
data-tooltip="\u26A0\uFE0F Falha detectada|Data: ${
|
|
152762
|
+
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
152763
|
`;
|
|
151753
152764
|
failureMarkers += `
|
|
151754
152765
|
<g class="failure-marker" transform="translate(${markerX}, ${offY + 10})">
|
|
@@ -151766,7 +152777,7 @@ function renderMTBFTimelineChart(data) {
|
|
|
151766
152777
|
<rect x="${x1 - 10}" y="${offY - 20}" width="${segWidth + 20}" height="45"
|
|
151767
152778
|
fill="transparent" class="tooltip-trigger"
|
|
151768
152779
|
data-type="stopped"
|
|
151769
|
-
data-date="${
|
|
152780
|
+
data-date="${formatDateTime3(seg.startTime)}"
|
|
151770
152781
|
data-duration="${formatHoursDisplay(seg.durationHours)}"
|
|
151771
152782
|
data-affected="${seg.affectedEquipments || "?"}"
|
|
151772
152783
|
data-failure-type="${seg.failureType || "Nao especificado"}" />
|
|
@@ -151789,7 +152800,7 @@ function renderMTBFTimelineChart(data) {
|
|
|
151789
152800
|
<rect x="${x1 - 5}" y="${offY - 20}" width="${segWidth + 10}" height="45"
|
|
151790
152801
|
fill="transparent" class="tooltip-trigger"
|
|
151791
152802
|
data-type="maintenance"
|
|
151792
|
-
data-start="${
|
|
152803
|
+
data-start="${formatDateTime3(seg.startTime)}"
|
|
151793
152804
|
data-duration="${formatHoursDisplay(seg.durationHours)}" />
|
|
151794
152805
|
`;
|
|
151795
152806
|
}
|
|
@@ -159698,7 +160709,7 @@ function formatDateShort2(dateStr) {
|
|
|
159698
160709
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
159699
160710
|
return `${day}/${month}`;
|
|
159700
160711
|
}
|
|
159701
|
-
function
|
|
160712
|
+
function formatDateTime4(dateStr) {
|
|
159702
160713
|
const date = new Date(dateStr);
|
|
159703
160714
|
const day = String(date.getDate()).padStart(2, "0");
|
|
159704
160715
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
@@ -159777,8 +160788,8 @@ function renderTimelineSVG(data, config2) {
|
|
|
159777
160788
|
fill="transparent"
|
|
159778
160789
|
class="tooltip-trigger"
|
|
159779
160790
|
data-state="${stateClass}"
|
|
159780
|
-
data-start="${
|
|
159781
|
-
data-end="${
|
|
160791
|
+
data-start="${formatDateTime4(seg.startTime)}"
|
|
160792
|
+
data-end="${formatDateTime4(seg.endTime)}"
|
|
159782
160793
|
data-duration="${formatDuration2(seg.durationMinutes)}"
|
|
159783
160794
|
data-source="${seg.source || "unknown"}"
|
|
159784
160795
|
/>
|
|
@@ -168544,8 +169555,8 @@ async function drawTag(doc, x, y, w, h3, device, gateway, allDevices) {
|
|
|
168544
169555
|
const titleAreaH = h3 * 0.15;
|
|
168545
169556
|
const qrAreaTop = y + titleAreaH;
|
|
168546
169557
|
const qrAreaH = h3 - titleAreaH - 12;
|
|
168547
|
-
const
|
|
168548
|
-
const rawName = sanitizePdf(
|
|
169558
|
+
const displayName2 = generateDeviceNameWithPrefix(device, void 0, allDevices);
|
|
169559
|
+
const rawName = sanitizePdf(displayName2);
|
|
168549
169560
|
const nameFont = Math.max(6, Math.min(11, titleAreaH * 0.45));
|
|
168550
169561
|
doc.setFont("helvetica", "bold");
|
|
168551
169562
|
doc.setFontSize(nameFont);
|
|
@@ -168622,8 +169633,8 @@ async function exportDeviceTagsPdf(devices, gateway, layout = "grid_4x7") {
|
|
|
168622
169633
|
if (page > 0) doc.addPage();
|
|
168623
169634
|
paintPage(page + 1, totalPages);
|
|
168624
169635
|
for (let row = 0; row < rows && idx < devices.length; row++) {
|
|
168625
|
-
for (let
|
|
168626
|
-
const tx = usableX +
|
|
169636
|
+
for (let col2 = 0; col2 < cols && idx < devices.length; col2++) {
|
|
169637
|
+
const tx = usableX + col2 * (tagW + gutterX);
|
|
168627
169638
|
const ty = usableY + row * (tagH + gutterY);
|
|
168628
169639
|
await drawTag(doc, tx, ty, tagW, tagH, devices[idx], gateway, devices);
|
|
168629
169640
|
idx++;
|
|
@@ -170764,7 +171775,7 @@ var DOMAIN_ICONS2 = {
|
|
|
170764
171775
|
temperature: "\u{1F321}\uFE0F",
|
|
170765
171776
|
unknown: "\xB7"
|
|
170766
171777
|
};
|
|
170767
|
-
var
|
|
171778
|
+
var DOMAIN_LABELS3 = {
|
|
170768
171779
|
energy: "Energia",
|
|
170769
171780
|
water: "\xC1gua",
|
|
170770
171781
|
temperature: "Temperatura",
|
|
@@ -170997,7 +172008,7 @@ function _applyFilterToDevice(device, filter) {
|
|
|
170997
172008
|
function _labelForGroup(key, groupBy, sample) {
|
|
170998
172009
|
if (groupBy === "identifier") return key;
|
|
170999
172010
|
if (groupBy === "device") return sample?.label || sample?.name || key;
|
|
171000
|
-
return
|
|
172011
|
+
return DOMAIN_LABELS3[key] ?? key;
|
|
171001
172012
|
}
|
|
171002
172013
|
function _iconForGroup(key, groupBy) {
|
|
171003
172014
|
if (groupBy === "domain") return DOMAIN_ICONS2[key];
|
|
@@ -173032,8 +174043,8 @@ ${this._renderToolbar(filteredCount, totalAllUnfiltered)}
|
|
|
173032
174043
|
</section>`;
|
|
173033
174044
|
}
|
|
173034
174045
|
/** Toggle a single group's collapsed state (scoped to current tab). */
|
|
173035
|
-
_toggleGroupCollapsed(
|
|
173036
|
-
const compoundKey = `${this.activeTab}::${
|
|
174046
|
+
_toggleGroupCollapsed(groupKey2) {
|
|
174047
|
+
const compoundKey = `${this.activeTab}::${groupKey2}`;
|
|
173037
174048
|
if (this.collapsedKeys.has(compoundKey)) {
|
|
173038
174049
|
this.collapsedKeys.delete(compoundKey);
|
|
173039
174050
|
} else {
|
|
@@ -174145,7 +175156,7 @@ function formatRoundedDuration(ms) {
|
|
|
174145
175156
|
if (s < 86400) return `${Math.round(s / 3600)}h`;
|
|
174146
175157
|
return `${Math.round(s / 86400)}d`;
|
|
174147
175158
|
}
|
|
174148
|
-
function
|
|
175159
|
+
function formatDateTime5(iso, language) {
|
|
174149
175160
|
const t = Date.parse(iso);
|
|
174150
175161
|
if (Number.isNaN(t)) return iso;
|
|
174151
175162
|
return new Date(t).toLocaleString(language === "en" ? "en-US" : "pt-BR", {
|
|
@@ -174176,7 +175187,7 @@ function renderBarHtml(segments, language, legend) {
|
|
|
174176
175187
|
return `<div class="myio-tlmodal__bar" role="img" aria-label="${escAttr5(
|
|
174177
175188
|
segments.map((s) => `${legend[s.status]} ${formatRoundedDuration(s.durationMs)}`).join(", ")
|
|
174178
175189
|
)}">` + segments.map((s, i) => {
|
|
174179
|
-
const title = `${legend[s.status]} \xB7 ${
|
|
175190
|
+
const title = `${legend[s.status]} \xB7 ${formatDateTime5(s.start, language)} \u2192 ${formatDateTime5(
|
|
174180
175191
|
s.end,
|
|
174181
175192
|
language
|
|
174182
175193
|
)} (${formatRoundedDuration(s.durationMs)})`;
|
|
@@ -174193,7 +175204,7 @@ function renderListHtml(transitions, language, emptyText) {
|
|
|
174193
175204
|
return `<ul class="myio-tlmodal__list">` + sorted.map(
|
|
174194
175205
|
(t) => `<li class="myio-tlmodal__list-item">
|
|
174195
175206
|
<span class="myio-tlmodal__list-transition">${escAttr5(t.from_status)} \u2192 ${escAttr5(t.to_status)}</span>
|
|
174196
|
-
<span class="myio-tlmodal__list-time">${escAttr5(
|
|
175207
|
+
<span class="myio-tlmodal__list-time">${escAttr5(formatDateTime5(t.created_at, language))}</span>
|
|
174197
175208
|
${t.probe_result ? `<span class="myio-tlmodal__list-probe">${escAttr5(t.probe_result)}</span>` : ""}
|
|
174198
175209
|
<span class="myio-tlmodal__list-mode myio-tlmodal__list-mode--${t.mode}">${escAttr5(t.mode)}</span>
|
|
174199
175210
|
</li>`
|
|
@@ -175255,6 +176266,7 @@ var version = package_default.version || "0.0.0";
|
|
|
175255
176266
|
DEFAULT_SIDEBAR_CONFIG,
|
|
175256
176267
|
DEFAULT_SOLENOID_SETTINGS,
|
|
175257
176268
|
DEFAULT_SOLENOID_STATE,
|
|
176269
|
+
DEFAULT_STORE_SEGMENTS,
|
|
175258
176270
|
DEFAULT_SWITCH_SETTINGS,
|
|
175259
176271
|
DEFAULT_SWITCH_STATE,
|
|
175260
176272
|
DEFAULT_TABS,
|
|
@@ -175836,6 +176848,7 @@ var version = package_default.version || "0.0.0";
|
|
|
175836
176848
|
injectSolenoidControlStyles,
|
|
175837
176849
|
injectSwitchControlStyles,
|
|
175838
176850
|
interpolateTemperature,
|
|
176851
|
+
inventory,
|
|
175839
176852
|
isAlarmActive,
|
|
175840
176853
|
isAnnotationOverdue,
|
|
175841
176854
|
isAssetCode,
|