myio-js-library 0.1.169 → 0.1.173
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 +1905 -335
- package/dist/index.d.cts +207 -4
- package/dist/index.js +1901 -335
- package/dist/myio-js-library.umd.js +1900 -335
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1318,7 +1318,8 @@ var DeviceStatusType = {
|
|
|
1318
1318
|
FAILURE: "failure",
|
|
1319
1319
|
MAINTENANCE: "maintenance",
|
|
1320
1320
|
NO_INFO: "no_info",
|
|
1321
|
-
NOT_INSTALLED: "not_installed"
|
|
1321
|
+
NOT_INSTALLED: "not_installed",
|
|
1322
|
+
OFFLINE: "offline"
|
|
1322
1323
|
};
|
|
1323
1324
|
var ConnectionStatusType = {
|
|
1324
1325
|
CONNECTED: "connected",
|
|
@@ -1327,39 +1328,42 @@ var ConnectionStatusType = {
|
|
|
1327
1328
|
var deviceStatusIcons = {
|
|
1328
1329
|
[DeviceStatusType.POWER_ON]: "\u26A1",
|
|
1329
1330
|
[DeviceStatusType.STANDBY]: "\u{1F50C}",
|
|
1330
|
-
[DeviceStatusType.POWER_OFF]: "\
|
|
1331
|
+
[DeviceStatusType.POWER_OFF]: "\u26AB",
|
|
1331
1332
|
[DeviceStatusType.WARNING]: "\u26A0\uFE0F",
|
|
1332
1333
|
[DeviceStatusType.FAILURE]: "\u{1F6A8}",
|
|
1333
1334
|
[DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
|
|
1334
1335
|
[DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
|
|
1335
|
-
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
|
|
1336
|
+
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
|
|
1337
|
+
[DeviceStatusType.OFFLINE]: "\u{1F534}"
|
|
1336
1338
|
};
|
|
1337
1339
|
var waterDeviceStatusIcons = {
|
|
1338
1340
|
[DeviceStatusType.POWER_ON]: "\u{1F4A7}",
|
|
1339
1341
|
[DeviceStatusType.STANDBY]: "\u{1F6B0}",
|
|
1340
|
-
[DeviceStatusType.POWER_OFF]: "\
|
|
1342
|
+
[DeviceStatusType.POWER_OFF]: "\u26AB",
|
|
1341
1343
|
[DeviceStatusType.WARNING]: "\u26A0\uFE0F",
|
|
1342
1344
|
[DeviceStatusType.FAILURE]: "\u{1F6A8}",
|
|
1343
1345
|
[DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
|
|
1344
1346
|
[DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
|
|
1345
|
-
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
|
|
1347
|
+
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
|
|
1348
|
+
[DeviceStatusType.OFFLINE]: "\u{1F534}"
|
|
1346
1349
|
};
|
|
1347
1350
|
var temperatureDeviceStatusIcons = {
|
|
1348
1351
|
[DeviceStatusType.POWER_ON]: "\u{1F321}\uFE0F",
|
|
1349
1352
|
[DeviceStatusType.STANDBY]: "\u{1F321}\uFE0F",
|
|
1350
|
-
[DeviceStatusType.POWER_OFF]: "\
|
|
1353
|
+
[DeviceStatusType.POWER_OFF]: "\u26AB",
|
|
1351
1354
|
[DeviceStatusType.WARNING]: "\u26A0\uFE0F",
|
|
1352
1355
|
[DeviceStatusType.FAILURE]: "\u{1F6A8}",
|
|
1353
1356
|
[DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
|
|
1354
1357
|
[DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
|
|
1355
|
-
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
|
|
1358
|
+
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
|
|
1359
|
+
[DeviceStatusType.OFFLINE]: "\u{1F534}"
|
|
1356
1360
|
};
|
|
1357
1361
|
var connectionStatusIcons = {
|
|
1358
1362
|
[ConnectionStatusType.CONNECTED]: "\u{1F7E2}",
|
|
1359
1363
|
[ConnectionStatusType.OFFLINE]: "\u{1F6AB}"
|
|
1360
1364
|
};
|
|
1361
1365
|
function mapDeviceToConnectionStatus(deviceStatus) {
|
|
1362
|
-
if (deviceStatus === DeviceStatusType.NO_INFO) {
|
|
1366
|
+
if (deviceStatus === DeviceStatusType.NO_INFO || deviceStatus === DeviceStatusType.OFFLINE) {
|
|
1363
1367
|
return ConnectionStatusType.OFFLINE;
|
|
1364
1368
|
}
|
|
1365
1369
|
return ConnectionStatusType.CONNECTED;
|
|
@@ -1383,15 +1387,16 @@ function mapDeviceStatusToCardStatus(deviceStatus) {
|
|
|
1383
1387
|
[DeviceStatusType.FAILURE]: "fail",
|
|
1384
1388
|
[DeviceStatusType.MAINTENANCE]: "alert",
|
|
1385
1389
|
[DeviceStatusType.NO_INFO]: "unknown",
|
|
1386
|
-
[DeviceStatusType.NOT_INSTALLED]: "not_installed"
|
|
1390
|
+
[DeviceStatusType.NOT_INSTALLED]: "not_installed",
|
|
1391
|
+
[DeviceStatusType.OFFLINE]: "offline"
|
|
1387
1392
|
};
|
|
1388
1393
|
return statusMap[deviceStatus] || "unknown";
|
|
1389
1394
|
}
|
|
1390
1395
|
function shouldFlashIcon(deviceStatus) {
|
|
1391
|
-
return deviceStatus === DeviceStatusType.POWER_OFF || deviceStatus === DeviceStatusType.WARNING || deviceStatus === DeviceStatusType.FAILURE || deviceStatus === DeviceStatusType.MAINTENANCE;
|
|
1396
|
+
return deviceStatus === DeviceStatusType.POWER_OFF || deviceStatus === DeviceStatusType.WARNING || deviceStatus === DeviceStatusType.FAILURE || deviceStatus === DeviceStatusType.MAINTENANCE || deviceStatus === DeviceStatusType.OFFLINE;
|
|
1392
1397
|
}
|
|
1393
1398
|
function isDeviceOffline(deviceStatus) {
|
|
1394
|
-
return deviceStatus === DeviceStatusType.NO_INFO;
|
|
1399
|
+
return deviceStatus === DeviceStatusType.NO_INFO || deviceStatus === DeviceStatusType.OFFLINE;
|
|
1395
1400
|
}
|
|
1396
1401
|
function getDeviceStatusIcon(deviceStatus, deviceType = null) {
|
|
1397
1402
|
const normalizedType = deviceType?.toUpperCase() || "";
|
|
@@ -3947,15 +3952,30 @@ var CSS_STRING = `
|
|
|
3947
3952
|
--myio-chip-alert-fg: #b45309;
|
|
3948
3953
|
--myio-border-alert: rgba(245, 158, 11, 0.5);
|
|
3949
3954
|
|
|
3950
|
-
/* Status colors - Failure (red) */
|
|
3955
|
+
/* Status colors - Failure (dark red) */
|
|
3951
3956
|
--myio-chip-failure-bg: #fee2e2;
|
|
3952
3957
|
--myio-chip-failure-fg: #b91c1c;
|
|
3953
|
-
--myio-border-failure: rgba(
|
|
3958
|
+
--myio-border-failure: rgba(153, 27, 27, 0.6);
|
|
3959
|
+
|
|
3960
|
+
/* Status colors - Power Off (light red) */
|
|
3961
|
+
--myio-chip-power-off-bg: #fecaca;
|
|
3962
|
+
--myio-chip-power-off-fg: #dc2626;
|
|
3963
|
+
--myio-border-power-off: rgba(239, 68, 68, 0.5);
|
|
3964
|
+
|
|
3965
|
+
/* Status colors - Offline (dark gray) */
|
|
3966
|
+
--myio-chip-offline-bg: #e2e8f0;
|
|
3967
|
+
--myio-chip-offline-fg: #475569;
|
|
3968
|
+
--myio-border-offline: rgba(71, 85, 105, 0.6);
|
|
3969
|
+
|
|
3970
|
+
/* Status colors - No Info (dark orange) */
|
|
3971
|
+
--myio-chip-no-info-bg: #fed7aa;
|
|
3972
|
+
--myio-chip-no-info-fg: #c2410c;
|
|
3973
|
+
--myio-border-no-info: rgba(194, 65, 12, 0.5);
|
|
3954
3974
|
|
|
3955
|
-
/* Status colors -
|
|
3956
|
-
--myio-chip-
|
|
3957
|
-
--myio-chip-
|
|
3958
|
-
--myio-border-
|
|
3975
|
+
/* Status colors - Not Installed (purple) */
|
|
3976
|
+
--myio-chip-not-installed-bg: #e9d5ff;
|
|
3977
|
+
--myio-chip-not-installed-fg: #7c3aed;
|
|
3978
|
+
--myio-border-not-installed: rgba(124, 58, 237, 0.5);
|
|
3959
3979
|
|
|
3960
3980
|
--myio-text-1: #0f172a;
|
|
3961
3981
|
--myio-text-2: #4b5563;
|
|
@@ -4011,26 +4031,55 @@ var CSS_STRING = `
|
|
|
4011
4031
|
}
|
|
4012
4032
|
|
|
4013
4033
|
/* Card border states based on device status */
|
|
4014
|
-
|
|
4034
|
+
|
|
4035
|
+
/* POWER_ON - Blue */
|
|
4036
|
+
.myio-ho-card.is-power-on {
|
|
4015
4037
|
border-color: var(--myio-border-ok);
|
|
4016
4038
|
box-shadow: 0 0 0 2px var(--myio-border-ok), var(--myio-card-shadow);
|
|
4017
4039
|
}
|
|
4018
4040
|
|
|
4041
|
+
/* STANDBY - Green */
|
|
4019
4042
|
.myio-ho-card.is-standby {
|
|
4020
4043
|
border-color: var(--myio-border-standby);
|
|
4021
4044
|
box-shadow: 0 0 0 2px var(--myio-border-standby), var(--myio-card-shadow);
|
|
4022
4045
|
}
|
|
4023
4046
|
|
|
4024
|
-
|
|
4047
|
+
/* WARNING - Yellow */
|
|
4048
|
+
.myio-ho-card.is-warning {
|
|
4049
|
+
border-color: var(--myio-border-alert);
|
|
4050
|
+
box-shadow: 0 0 0 2px var(--myio-border-alert), var(--myio-card-shadow);
|
|
4051
|
+
}
|
|
4052
|
+
|
|
4053
|
+
/* MAINTENANCE - Yellow */
|
|
4054
|
+
.myio-ho-card.is-maintenance {
|
|
4025
4055
|
border-color: var(--myio-border-alert);
|
|
4026
4056
|
box-shadow: 0 0 0 2px var(--myio-border-alert), var(--myio-card-shadow);
|
|
4027
4057
|
}
|
|
4028
4058
|
|
|
4059
|
+
/* FAILURE - Dark Red */
|
|
4029
4060
|
.myio-ho-card.is-failure {
|
|
4030
4061
|
border-color: var(--myio-border-failure);
|
|
4031
4062
|
box-shadow: 0 0 0 2px var(--myio-border-failure), var(--myio-card-shadow);
|
|
4032
4063
|
}
|
|
4033
4064
|
|
|
4065
|
+
/* POWER_OFF - Light Red */
|
|
4066
|
+
.myio-ho-card.is-power-off {
|
|
4067
|
+
border-color: var(--myio-border-power-off);
|
|
4068
|
+
box-shadow: 0 0 0 2px var(--myio-border-power-off), var(--myio-card-shadow);
|
|
4069
|
+
}
|
|
4070
|
+
|
|
4071
|
+
/* NO_INFO - Dark Orange */
|
|
4072
|
+
.myio-ho-card.is-no-info {
|
|
4073
|
+
border-color: var(--myio-border-no-info);
|
|
4074
|
+
box-shadow: 0 0 0 2px var(--myio-border-no-info), var(--myio-card-shadow);
|
|
4075
|
+
}
|
|
4076
|
+
|
|
4077
|
+
/* NOT_INSTALLED - Purple */
|
|
4078
|
+
.myio-ho-card.is-not-installed {
|
|
4079
|
+
border-color: var(--myio-border-not-installed);
|
|
4080
|
+
box-shadow: 0 0 0 2px var(--myio-border-not-installed), var(--myio-card-shadow);
|
|
4081
|
+
}
|
|
4082
|
+
|
|
4034
4083
|
/* Header section */
|
|
4035
4084
|
.myio-ho-card__header {
|
|
4036
4085
|
display: flex;
|
|
@@ -4048,7 +4097,9 @@ var CSS_STRING = `
|
|
|
4048
4097
|
margin-top: 2px;
|
|
4049
4098
|
}
|
|
4050
4099
|
|
|
4051
|
-
|
|
4100
|
+
/* Icon colors based on status */
|
|
4101
|
+
.myio-ho-card.is-warning .myio-ho-card__icon,
|
|
4102
|
+
.myio-ho-card.is-maintenance .myio-ho-card__icon {
|
|
4052
4103
|
color: var(--myio-chip-alert-fg);
|
|
4053
4104
|
}
|
|
4054
4105
|
|
|
@@ -4056,14 +4107,28 @@ var CSS_STRING = `
|
|
|
4056
4107
|
color: var(--myio-chip-failure-fg);
|
|
4057
4108
|
}
|
|
4058
4109
|
|
|
4110
|
+
.myio-ho-card.is-power-off .myio-ho-card__icon {
|
|
4111
|
+
color: var(--myio-chip-power-off-fg);
|
|
4112
|
+
}
|
|
4113
|
+
|
|
4114
|
+
.myio-ho-card.is-offline .myio-ho-card__icon {
|
|
4115
|
+
color: var(--myio-chip-offline-fg);
|
|
4116
|
+
}
|
|
4117
|
+
|
|
4118
|
+
.myio-ho-card.is-no-info .myio-ho-card__icon {
|
|
4119
|
+
color: var(--myio-chip-no-info-fg);
|
|
4120
|
+
}
|
|
4121
|
+
|
|
4122
|
+
.myio-ho-card.is-not-installed .myio-ho-card__icon {
|
|
4123
|
+
color: var(--myio-chip-not-installed-fg);
|
|
4124
|
+
}
|
|
4125
|
+
|
|
4059
4126
|
.myio-ho-card__title {
|
|
4060
4127
|
flex: 1;
|
|
4061
4128
|
min-width: 0;
|
|
4062
4129
|
}
|
|
4063
4130
|
|
|
4064
|
-
/*
|
|
4065
|
-
|
|
4066
|
-
/* Estado Offline - borda cinza */
|
|
4131
|
+
/* OFFLINE - Dark Gray */
|
|
4067
4132
|
.myio-ho-card.is-offline {
|
|
4068
4133
|
border-color: var(--myio-border-offline);
|
|
4069
4134
|
box-shadow: 0 0 0 2px var(--myio-border-offline), var(--myio-card-shadow);
|
|
@@ -4458,6 +4523,37 @@ var CSS_STRING = `
|
|
|
4458
4523
|
color: var(--myio-chip-offline-fg);
|
|
4459
4524
|
}
|
|
4460
4525
|
|
|
4526
|
+
/* New chip classes aligned with getCardStateClass */
|
|
4527
|
+
.chip--power-on {
|
|
4528
|
+
background: var(--myio-chip-ok-bg);
|
|
4529
|
+
color: var(--myio-chip-ok-fg);
|
|
4530
|
+
}
|
|
4531
|
+
|
|
4532
|
+
.chip--warning {
|
|
4533
|
+
background: var(--myio-chip-alert-bg);
|
|
4534
|
+
color: var(--myio-chip-alert-fg);
|
|
4535
|
+
}
|
|
4536
|
+
|
|
4537
|
+
.chip--maintenance {
|
|
4538
|
+
background: var(--myio-chip-alert-bg);
|
|
4539
|
+
color: var(--myio-chip-alert-fg);
|
|
4540
|
+
}
|
|
4541
|
+
|
|
4542
|
+
.chip--power-off {
|
|
4543
|
+
background: var(--myio-chip-power-off-bg);
|
|
4544
|
+
color: var(--myio-chip-power-off-fg);
|
|
4545
|
+
}
|
|
4546
|
+
|
|
4547
|
+
.chip--no-info {
|
|
4548
|
+
background: var(--myio-chip-no-info-bg);
|
|
4549
|
+
color: var(--myio-chip-no-info-fg);
|
|
4550
|
+
}
|
|
4551
|
+
|
|
4552
|
+
.chip--not-installed {
|
|
4553
|
+
background: var(--myio-chip-not-installed-bg);
|
|
4554
|
+
color: var(--myio-chip-not-installed-fg);
|
|
4555
|
+
}
|
|
4556
|
+
|
|
4461
4557
|
/* Status indicator dot for power metric */
|
|
4462
4558
|
.status-dot {
|
|
4463
4559
|
width: 8px;
|
|
@@ -4491,6 +4587,31 @@ var CSS_STRING = `
|
|
|
4491
4587
|
background: var(--myio-muted);
|
|
4492
4588
|
}
|
|
4493
4589
|
|
|
4590
|
+
/* New dot classes aligned with getCardStateClass */
|
|
4591
|
+
.status-dot.dot--power-on {
|
|
4592
|
+
background: var(--myio-chip-ok-fg);
|
|
4593
|
+
}
|
|
4594
|
+
|
|
4595
|
+
.status-dot.dot--warning {
|
|
4596
|
+
background: var(--myio-chip-alert-fg);
|
|
4597
|
+
}
|
|
4598
|
+
|
|
4599
|
+
.status-dot.dot--maintenance {
|
|
4600
|
+
background: var(--myio-chip-alert-fg);
|
|
4601
|
+
}
|
|
4602
|
+
|
|
4603
|
+
.status-dot.dot--power-off {
|
|
4604
|
+
background: var(--myio-chip-power-off-fg);
|
|
4605
|
+
}
|
|
4606
|
+
|
|
4607
|
+
.status-dot.dot--no-info {
|
|
4608
|
+
background: var(--myio-chip-no-info-fg);
|
|
4609
|
+
}
|
|
4610
|
+
|
|
4611
|
+
.status-dot.dot--not-installed {
|
|
4612
|
+
background: var(--myio-chip-not-installed-fg);
|
|
4613
|
+
}
|
|
4614
|
+
|
|
4494
4615
|
/* Primary metric */
|
|
4495
4616
|
.myio-ho-card__primary {
|
|
4496
4617
|
margin-bottom: 14px;
|
|
@@ -4673,6 +4794,215 @@ var CSS_STRING = `
|
|
|
4673
4794
|
transition: none;
|
|
4674
4795
|
}
|
|
4675
4796
|
}
|
|
4797
|
+
|
|
4798
|
+
/* ============================================
|
|
4799
|
+
DEBUG TOOLTIP STYLES (Premium)
|
|
4800
|
+
============================================ */
|
|
4801
|
+
|
|
4802
|
+
.has-debug-tooltip {
|
|
4803
|
+
cursor: help !important;
|
|
4804
|
+
}
|
|
4805
|
+
|
|
4806
|
+
.has-debug-tooltip::after {
|
|
4807
|
+
content: '\u{1F41B}';
|
|
4808
|
+
position: absolute;
|
|
4809
|
+
top: -4px;
|
|
4810
|
+
right: -4px;
|
|
4811
|
+
font-size: 10px;
|
|
4812
|
+
z-index: 1;
|
|
4813
|
+
}
|
|
4814
|
+
|
|
4815
|
+
.debug-tooltip-container {
|
|
4816
|
+
position: absolute;
|
|
4817
|
+
bottom: calc(100% + 8px);
|
|
4818
|
+
left: 50%;
|
|
4819
|
+
transform: translateX(-50%);
|
|
4820
|
+
z-index: 10000;
|
|
4821
|
+
pointer-events: none;
|
|
4822
|
+
opacity: 0;
|
|
4823
|
+
transition: opacity 0.2s ease, transform 0.2s ease;
|
|
4824
|
+
}
|
|
4825
|
+
|
|
4826
|
+
.has-debug-tooltip:hover .debug-tooltip-container {
|
|
4827
|
+
opacity: 1;
|
|
4828
|
+
pointer-events: auto;
|
|
4829
|
+
}
|
|
4830
|
+
|
|
4831
|
+
.debug-tooltip {
|
|
4832
|
+
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
|
|
4833
|
+
border: 1px solid rgba(99, 102, 241, 0.3);
|
|
4834
|
+
border-radius: 12px;
|
|
4835
|
+
box-shadow:
|
|
4836
|
+
0 20px 40px rgba(0, 0, 0, 0.4),
|
|
4837
|
+
0 0 0 1px rgba(255, 255, 255, 0.05),
|
|
4838
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
|
4839
|
+
min-width: 340px;
|
|
4840
|
+
max-width: 420px;
|
|
4841
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
4842
|
+
font-size: 12px;
|
|
4843
|
+
color: #e2e8f0;
|
|
4844
|
+
overflow: hidden;
|
|
4845
|
+
}
|
|
4846
|
+
|
|
4847
|
+
.debug-tooltip__header {
|
|
4848
|
+
display: flex;
|
|
4849
|
+
align-items: center;
|
|
4850
|
+
gap: 8px;
|
|
4851
|
+
padding: 12px 16px;
|
|
4852
|
+
background: linear-gradient(90deg, rgba(99, 102, 241, 0.2) 0%, rgba(139, 92, 246, 0.1) 100%);
|
|
4853
|
+
border-bottom: 1px solid rgba(99, 102, 241, 0.2);
|
|
4854
|
+
}
|
|
4855
|
+
|
|
4856
|
+
.debug-tooltip__icon {
|
|
4857
|
+
font-size: 16px;
|
|
4858
|
+
}
|
|
4859
|
+
|
|
4860
|
+
.debug-tooltip__title {
|
|
4861
|
+
font-weight: 700;
|
|
4862
|
+
font-size: 13px;
|
|
4863
|
+
color: #f1f5f9;
|
|
4864
|
+
letter-spacing: 0.5px;
|
|
4865
|
+
text-transform: uppercase;
|
|
4866
|
+
}
|
|
4867
|
+
|
|
4868
|
+
.debug-tooltip__content {
|
|
4869
|
+
padding: 12px 16px;
|
|
4870
|
+
max-height: 400px;
|
|
4871
|
+
overflow-y: auto;
|
|
4872
|
+
}
|
|
4873
|
+
|
|
4874
|
+
.debug-tooltip__section {
|
|
4875
|
+
margin-bottom: 14px;
|
|
4876
|
+
padding-bottom: 12px;
|
|
4877
|
+
border-bottom: 1px solid rgba(148, 163, 184, 0.1);
|
|
4878
|
+
}
|
|
4879
|
+
|
|
4880
|
+
.debug-tooltip__section:last-child {
|
|
4881
|
+
margin-bottom: 0;
|
|
4882
|
+
padding-bottom: 0;
|
|
4883
|
+
border-bottom: none;
|
|
4884
|
+
}
|
|
4885
|
+
|
|
4886
|
+
.debug-tooltip__section-title {
|
|
4887
|
+
font-size: 11px;
|
|
4888
|
+
font-weight: 600;
|
|
4889
|
+
color: #94a3b8;
|
|
4890
|
+
text-transform: uppercase;
|
|
4891
|
+
letter-spacing: 0.8px;
|
|
4892
|
+
margin-bottom: 10px;
|
|
4893
|
+
display: flex;
|
|
4894
|
+
align-items: center;
|
|
4895
|
+
gap: 6px;
|
|
4896
|
+
}
|
|
4897
|
+
|
|
4898
|
+
.debug-tooltip__row {
|
|
4899
|
+
display: flex;
|
|
4900
|
+
justify-content: space-between;
|
|
4901
|
+
align-items: flex-start;
|
|
4902
|
+
padding: 4px 0;
|
|
4903
|
+
gap: 12px;
|
|
4904
|
+
}
|
|
4905
|
+
|
|
4906
|
+
.debug-tooltip__row--full {
|
|
4907
|
+
flex-direction: column;
|
|
4908
|
+
gap: 4px;
|
|
4909
|
+
}
|
|
4910
|
+
|
|
4911
|
+
.debug-tooltip__label {
|
|
4912
|
+
color: #94a3b8;
|
|
4913
|
+
font-size: 11px;
|
|
4914
|
+
flex-shrink: 0;
|
|
4915
|
+
}
|
|
4916
|
+
|
|
4917
|
+
.debug-tooltip__value {
|
|
4918
|
+
color: #f1f5f9;
|
|
4919
|
+
font-weight: 500;
|
|
4920
|
+
text-align: right;
|
|
4921
|
+
word-break: break-all;
|
|
4922
|
+
}
|
|
4923
|
+
|
|
4924
|
+
.debug-tooltip__row--full .debug-tooltip__value {
|
|
4925
|
+
text-align: left;
|
|
4926
|
+
background: rgba(0, 0, 0, 0.3);
|
|
4927
|
+
padding: 6px 10px;
|
|
4928
|
+
border-radius: 6px;
|
|
4929
|
+
font-size: 11px;
|
|
4930
|
+
width: 100%;
|
|
4931
|
+
box-sizing: border-box;
|
|
4932
|
+
}
|
|
4933
|
+
|
|
4934
|
+
.debug-tooltip__value--mono {
|
|
4935
|
+
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
|
|
4936
|
+
font-size: 11px;
|
|
4937
|
+
background: rgba(0, 0, 0, 0.3);
|
|
4938
|
+
padding: 2px 6px;
|
|
4939
|
+
border-radius: 4px;
|
|
4940
|
+
}
|
|
4941
|
+
|
|
4942
|
+
.debug-tooltip__value--highlight {
|
|
4943
|
+
color: #a5b4fc;
|
|
4944
|
+
font-style: italic;
|
|
4945
|
+
}
|
|
4946
|
+
|
|
4947
|
+
.debug-tooltip__badge {
|
|
4948
|
+
display: inline-block;
|
|
4949
|
+
padding: 2px 8px;
|
|
4950
|
+
border-radius: 4px;
|
|
4951
|
+
font-size: 10px;
|
|
4952
|
+
font-weight: 600;
|
|
4953
|
+
text-transform: uppercase;
|
|
4954
|
+
letter-spacing: 0.5px;
|
|
4955
|
+
background: rgba(99, 102, 241, 0.3);
|
|
4956
|
+
color: #a5b4fc;
|
|
4957
|
+
}
|
|
4958
|
+
|
|
4959
|
+
.debug-tooltip__badge--energy {
|
|
4960
|
+
background: rgba(59, 130, 246, 0.3);
|
|
4961
|
+
color: #93c5fd;
|
|
4962
|
+
}
|
|
4963
|
+
|
|
4964
|
+
.debug-tooltip__badge--water {
|
|
4965
|
+
background: rgba(6, 182, 212, 0.3);
|
|
4966
|
+
color: #67e8f9;
|
|
4967
|
+
}
|
|
4968
|
+
|
|
4969
|
+
.debug-tooltip__badge--temperature {
|
|
4970
|
+
background: rgba(249, 115, 22, 0.3);
|
|
4971
|
+
color: #fdba74;
|
|
4972
|
+
}
|
|
4973
|
+
|
|
4974
|
+
/* Tooltip arrow */
|
|
4975
|
+
.debug-tooltip::after {
|
|
4976
|
+
content: '';
|
|
4977
|
+
position: absolute;
|
|
4978
|
+
bottom: -6px;
|
|
4979
|
+
left: 50%;
|
|
4980
|
+
transform: translateX(-50%) rotate(45deg);
|
|
4981
|
+
width: 12px;
|
|
4982
|
+
height: 12px;
|
|
4983
|
+
background: #0f172a;
|
|
4984
|
+
border-right: 1px solid rgba(99, 102, 241, 0.3);
|
|
4985
|
+
border-bottom: 1px solid rgba(99, 102, 241, 0.3);
|
|
4986
|
+
}
|
|
4987
|
+
|
|
4988
|
+
/* Scrollbar styling for tooltip content */
|
|
4989
|
+
.debug-tooltip__content::-webkit-scrollbar {
|
|
4990
|
+
width: 6px;
|
|
4991
|
+
}
|
|
4992
|
+
|
|
4993
|
+
.debug-tooltip__content::-webkit-scrollbar-track {
|
|
4994
|
+
background: rgba(0, 0, 0, 0.2);
|
|
4995
|
+
border-radius: 3px;
|
|
4996
|
+
}
|
|
4997
|
+
|
|
4998
|
+
.debug-tooltip__content::-webkit-scrollbar-thumb {
|
|
4999
|
+
background: rgba(99, 102, 241, 0.4);
|
|
5000
|
+
border-radius: 3px;
|
|
5001
|
+
}
|
|
5002
|
+
|
|
5003
|
+
.debug-tooltip__content::-webkit-scrollbar-thumb:hover {
|
|
5004
|
+
background: rgba(99, 102, 241, 0.6);
|
|
5005
|
+
}
|
|
4676
5006
|
`;
|
|
4677
5007
|
|
|
4678
5008
|
// src/thingsboard/main-dashboard-shopping/v-4.0.0/head-office/card-head-office.icons.ts
|
|
@@ -4827,46 +5157,296 @@ var DEFAULT_I18N = {
|
|
|
4827
5157
|
menu_settings: "Configura\xE7\xF5es"
|
|
4828
5158
|
};
|
|
4829
5159
|
|
|
4830
|
-
// src/
|
|
4831
|
-
var
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
5160
|
+
// src/components/temperature/utils.ts
|
|
5161
|
+
var DAY_PERIODS = [
|
|
5162
|
+
{ id: "madrugada", label: "Madrugada (00h-06h)", startHour: 0, endHour: 6 },
|
|
5163
|
+
{ id: "manha", label: "Manh\xE3 (06h-12h)", startHour: 6, endHour: 12 },
|
|
5164
|
+
{ id: "tarde", label: "Tarde (12h-18h)", startHour: 12, endHour: 18 },
|
|
5165
|
+
{ id: "noite", label: "Noite (18h-24h)", startHour: 18, endHour: 24 }
|
|
5166
|
+
];
|
|
5167
|
+
var DEFAULT_CLAMP_RANGE = { min: 15, max: 40 };
|
|
5168
|
+
function getTodaySoFar() {
|
|
5169
|
+
const now = /* @__PURE__ */ new Date();
|
|
5170
|
+
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
|
|
5171
|
+
return {
|
|
5172
|
+
startTs: startOfDay.getTime(),
|
|
5173
|
+
endTs: now.getTime()
|
|
5174
|
+
};
|
|
4839
5175
|
}
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
5176
|
+
var CHART_COLORS = [
|
|
5177
|
+
"#1976d2",
|
|
5178
|
+
// Blue
|
|
5179
|
+
"#FF6B6B",
|
|
5180
|
+
// Red
|
|
5181
|
+
"#4CAF50",
|
|
5182
|
+
// Green
|
|
5183
|
+
"#FF9800",
|
|
5184
|
+
// Orange
|
|
5185
|
+
"#9C27B0",
|
|
5186
|
+
// Purple
|
|
5187
|
+
"#00BCD4",
|
|
5188
|
+
// Cyan
|
|
5189
|
+
"#E91E63",
|
|
5190
|
+
// Pink
|
|
5191
|
+
"#795548"
|
|
5192
|
+
// Brown
|
|
5193
|
+
];
|
|
5194
|
+
async function fetchTemperatureData(token, deviceId, startTs, endTs) {
|
|
5195
|
+
const url = `/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=temperature&startTs=${encodeURIComponent(startTs)}&endTs=${encodeURIComponent(endTs)}&limit=50000&agg=NONE`;
|
|
5196
|
+
const response = await fetch(url, {
|
|
5197
|
+
headers: {
|
|
5198
|
+
"X-Authorization": `Bearer ${token}`,
|
|
5199
|
+
"Content-Type": "application/json"
|
|
5200
|
+
}
|
|
5201
|
+
});
|
|
5202
|
+
if (!response.ok) {
|
|
5203
|
+
throw new Error(`Failed to fetch temperature data: ${response.status}`);
|
|
4843
5204
|
}
|
|
4844
|
-
const
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
5205
|
+
const data = await response.json();
|
|
5206
|
+
return data?.temperature || [];
|
|
5207
|
+
}
|
|
5208
|
+
function clampTemperature(value, range = DEFAULT_CLAMP_RANGE) {
|
|
5209
|
+
const num = Number(value || 0);
|
|
5210
|
+
if (num < range.min) return range.min;
|
|
5211
|
+
if (num > range.max) return range.max;
|
|
5212
|
+
return num;
|
|
5213
|
+
}
|
|
5214
|
+
function calculateStats(data, clampRange = DEFAULT_CLAMP_RANGE) {
|
|
5215
|
+
if (data.length === 0) {
|
|
5216
|
+
return { avg: 0, min: 0, max: 0, count: 0 };
|
|
4848
5217
|
}
|
|
5218
|
+
const values = data.map((item) => clampTemperature(item.value, clampRange));
|
|
5219
|
+
const sum = values.reduce((acc, v) => acc + v, 0);
|
|
4849
5220
|
return {
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
useNewComponents: Boolean(params.useNewComponents),
|
|
4855
|
-
// RFC-0091: Configurable delay time for connection status check (default 15 minutes)
|
|
4856
|
-
delayTimeConnectionInMins: params.delayTimeConnectionInMins ?? 15,
|
|
4857
|
-
callbacks: {
|
|
4858
|
-
handleActionDashboard: params.handleActionDashboard,
|
|
4859
|
-
handleActionReport: params.handleActionReport,
|
|
4860
|
-
handleActionSettings: params.handleActionSettings,
|
|
4861
|
-
handleSelect: params.handleSelect,
|
|
4862
|
-
handInfo: params.handInfo,
|
|
4863
|
-
handleClickCard: params.handleClickCard
|
|
4864
|
-
}
|
|
5221
|
+
avg: sum / values.length,
|
|
5222
|
+
min: Math.min(...values),
|
|
5223
|
+
max: Math.max(...values),
|
|
5224
|
+
count: values.length
|
|
4865
5225
|
};
|
|
4866
5226
|
}
|
|
4867
|
-
function
|
|
4868
|
-
|
|
4869
|
-
|
|
5227
|
+
function interpolateTemperature(data, options) {
|
|
5228
|
+
const { intervalMinutes, startTs, endTs, clampRange = DEFAULT_CLAMP_RANGE } = options;
|
|
5229
|
+
const intervalMs = intervalMinutes * 60 * 1e3;
|
|
5230
|
+
if (data.length === 0) {
|
|
5231
|
+
return [];
|
|
5232
|
+
}
|
|
5233
|
+
const sortedData = [...data].sort((a, b) => a.ts - b.ts);
|
|
5234
|
+
const result = [];
|
|
5235
|
+
let lastKnownValue = clampTemperature(sortedData[0].value, clampRange);
|
|
5236
|
+
let dataIndex = 0;
|
|
5237
|
+
for (let ts = startTs; ts <= endTs; ts += intervalMs) {
|
|
5238
|
+
while (dataIndex < sortedData.length - 1 && sortedData[dataIndex + 1].ts <= ts) {
|
|
5239
|
+
dataIndex++;
|
|
5240
|
+
}
|
|
5241
|
+
const currentData = sortedData[dataIndex];
|
|
5242
|
+
if (currentData && Math.abs(currentData.ts - ts) < intervalMs) {
|
|
5243
|
+
lastKnownValue = clampTemperature(currentData.value, clampRange);
|
|
5244
|
+
}
|
|
5245
|
+
result.push({
|
|
5246
|
+
ts,
|
|
5247
|
+
value: lastKnownValue
|
|
5248
|
+
});
|
|
5249
|
+
}
|
|
5250
|
+
return result;
|
|
5251
|
+
}
|
|
5252
|
+
function aggregateByDay(data, clampRange = DEFAULT_CLAMP_RANGE) {
|
|
5253
|
+
if (data.length === 0) {
|
|
5254
|
+
return [];
|
|
5255
|
+
}
|
|
5256
|
+
const dayMap = /* @__PURE__ */ new Map();
|
|
5257
|
+
data.forEach((item) => {
|
|
5258
|
+
const date = new Date(item.ts);
|
|
5259
|
+
const dateKey = date.toISOString().split("T")[0];
|
|
5260
|
+
if (!dayMap.has(dateKey)) {
|
|
5261
|
+
dayMap.set(dateKey, []);
|
|
5262
|
+
}
|
|
5263
|
+
dayMap.get(dateKey).push(item);
|
|
5264
|
+
});
|
|
5265
|
+
const result = [];
|
|
5266
|
+
dayMap.forEach((dayData, dateKey) => {
|
|
5267
|
+
const values = dayData.map((item) => clampTemperature(item.value, clampRange));
|
|
5268
|
+
const sum = values.reduce((acc, v) => acc + v, 0);
|
|
5269
|
+
result.push({
|
|
5270
|
+
date: dateKey,
|
|
5271
|
+
dateTs: new Date(dateKey).getTime(),
|
|
5272
|
+
avg: sum / values.length,
|
|
5273
|
+
min: Math.min(...values),
|
|
5274
|
+
max: Math.max(...values),
|
|
5275
|
+
count: values.length
|
|
5276
|
+
});
|
|
5277
|
+
});
|
|
5278
|
+
return result.sort((a, b) => a.dateTs - b.dateTs);
|
|
5279
|
+
}
|
|
5280
|
+
function filterByDayPeriods(data, selectedPeriods) {
|
|
5281
|
+
if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
|
|
5282
|
+
return data;
|
|
5283
|
+
}
|
|
5284
|
+
return data.filter((item) => {
|
|
5285
|
+
const date = new Date(item.ts);
|
|
5286
|
+
const hour = date.getHours();
|
|
5287
|
+
return selectedPeriods.some((periodId) => {
|
|
5288
|
+
const period = DAY_PERIODS.find((p) => p.id === periodId);
|
|
5289
|
+
if (!period) return false;
|
|
5290
|
+
return hour >= period.startHour && hour < period.endHour;
|
|
5291
|
+
});
|
|
5292
|
+
});
|
|
5293
|
+
}
|
|
5294
|
+
function getSelectedPeriodsLabel(selectedPeriods) {
|
|
5295
|
+
if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
|
|
5296
|
+
return "Todos os per\xEDodos";
|
|
5297
|
+
}
|
|
5298
|
+
if (selectedPeriods.length === 1) {
|
|
5299
|
+
const period = DAY_PERIODS.find((p) => p.id === selectedPeriods[0]);
|
|
5300
|
+
return period?.label || "";
|
|
5301
|
+
}
|
|
5302
|
+
return `${selectedPeriods.length} per\xEDodos selecionados`;
|
|
5303
|
+
}
|
|
5304
|
+
function formatTemperature(value, decimals = 1) {
|
|
5305
|
+
if (value === null || value === void 0 || isNaN(value)) {
|
|
5306
|
+
return "\u2014";
|
|
5307
|
+
}
|
|
5308
|
+
return `${value.toFixed(decimals)}\xB0C`;
|
|
5309
|
+
}
|
|
5310
|
+
function exportTemperatureCSV(data, deviceLabel, stats, startDate, endDate) {
|
|
5311
|
+
if (data.length === 0) {
|
|
5312
|
+
console.warn("No data to export");
|
|
5313
|
+
return;
|
|
5314
|
+
}
|
|
5315
|
+
const BOM = "\uFEFF";
|
|
5316
|
+
let csvContent = BOM;
|
|
5317
|
+
csvContent += `Relat\xF3rio de Temperatura - ${deviceLabel}
|
|
5318
|
+
`;
|
|
5319
|
+
csvContent += `Per\xEDodo: ${startDate} at\xE9 ${endDate}
|
|
5320
|
+
`;
|
|
5321
|
+
csvContent += `M\xE9dia: ${formatTemperature(stats.avg)}
|
|
5322
|
+
`;
|
|
5323
|
+
csvContent += `M\xEDnima: ${formatTemperature(stats.min)}
|
|
5324
|
+
`;
|
|
5325
|
+
csvContent += `M\xE1xima: ${formatTemperature(stats.max)}
|
|
5326
|
+
`;
|
|
5327
|
+
csvContent += `Total de leituras: ${stats.count}
|
|
5328
|
+
`;
|
|
5329
|
+
csvContent += "\n";
|
|
5330
|
+
csvContent += "Data/Hora,Temperatura (\xB0C)\n";
|
|
5331
|
+
data.forEach((item) => {
|
|
5332
|
+
const date = new Date(item.ts).toLocaleString("pt-BR");
|
|
5333
|
+
const temp = Number(item.value).toFixed(2);
|
|
5334
|
+
csvContent += `"${date}",${temp}
|
|
5335
|
+
`;
|
|
5336
|
+
});
|
|
5337
|
+
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
|
|
5338
|
+
const url = URL.createObjectURL(blob);
|
|
5339
|
+
const link = document.createElement("a");
|
|
5340
|
+
link.href = url;
|
|
5341
|
+
link.download = `temperatura_${deviceLabel.replace(/\s+/g, "_")}_${startDate}_${endDate}.csv`;
|
|
5342
|
+
document.body.appendChild(link);
|
|
5343
|
+
link.click();
|
|
5344
|
+
document.body.removeChild(link);
|
|
5345
|
+
URL.revokeObjectURL(url);
|
|
5346
|
+
}
|
|
5347
|
+
var DARK_THEME = {
|
|
5348
|
+
background: "rgba(0, 0, 0, 0.85)",
|
|
5349
|
+
surface: "#1a1f28",
|
|
5350
|
+
text: "#ffffff",
|
|
5351
|
+
textMuted: "rgba(255, 255, 255, 0.7)",
|
|
5352
|
+
border: "rgba(255, 255, 255, 0.1)",
|
|
5353
|
+
primary: "#1976d2",
|
|
5354
|
+
success: "#4CAF50",
|
|
5355
|
+
warning: "#FF9800",
|
|
5356
|
+
danger: "#f44336",
|
|
5357
|
+
chartLine: "#1976d2",
|
|
5358
|
+
chartGrid: "rgba(255, 255, 255, 0.1)"
|
|
5359
|
+
};
|
|
5360
|
+
var LIGHT_THEME = {
|
|
5361
|
+
background: "rgba(0, 0, 0, 0.6)",
|
|
5362
|
+
surface: "#ffffff",
|
|
5363
|
+
text: "#333333",
|
|
5364
|
+
textMuted: "#666666",
|
|
5365
|
+
border: "#e0e0e0",
|
|
5366
|
+
primary: "#1976d2",
|
|
5367
|
+
success: "#4CAF50",
|
|
5368
|
+
warning: "#FF9800",
|
|
5369
|
+
danger: "#f44336",
|
|
5370
|
+
chartLine: "#1976d2",
|
|
5371
|
+
chartGrid: "#e0e0e0"
|
|
5372
|
+
};
|
|
5373
|
+
function getThemeColors(theme) {
|
|
5374
|
+
return theme === "dark" ? DARK_THEME : LIGHT_THEME;
|
|
5375
|
+
}
|
|
5376
|
+
|
|
5377
|
+
// src/utils/logHelper.js
|
|
5378
|
+
function createLogHelper(debugActive = false) {
|
|
5379
|
+
return {
|
|
5380
|
+
log: function(...args) {
|
|
5381
|
+
if (debugActive) {
|
|
5382
|
+
console.log(...args);
|
|
5383
|
+
}
|
|
5384
|
+
},
|
|
5385
|
+
warn: function(...args) {
|
|
5386
|
+
if (debugActive) {
|
|
5387
|
+
console.warn(...args);
|
|
5388
|
+
}
|
|
5389
|
+
},
|
|
5390
|
+
error: function(...args) {
|
|
5391
|
+
console.error(...args);
|
|
5392
|
+
}
|
|
5393
|
+
};
|
|
5394
|
+
}
|
|
5395
|
+
var LogHelper = createLogHelper(false);
|
|
5396
|
+
|
|
5397
|
+
// src/thingsboard/main-dashboard-shopping/v-4.0.0/card/head-office/card-head-office.js
|
|
5398
|
+
var LABEL_CHAR_LIMIT = 18;
|
|
5399
|
+
var DEFAUL_DELAY_TIME_CONNECTION_IN_MINS = 1440;
|
|
5400
|
+
var CSS_TAG = "head-office-card-v1";
|
|
5401
|
+
function ensureCss() {
|
|
5402
|
+
if (!document.querySelector(`style[data-myio-css="${CSS_TAG}"]`)) {
|
|
5403
|
+
const style = document.createElement("style");
|
|
5404
|
+
style.setAttribute("data-myio-css", CSS_TAG);
|
|
5405
|
+
style.textContent = CSS_STRING;
|
|
5406
|
+
document.head.appendChild(style);
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
function normalizeParams(params) {
|
|
5410
|
+
if (!params || !params.entityObject) {
|
|
5411
|
+
throw new Error("renderCardCompenteHeadOffice: entityObject is required");
|
|
5412
|
+
}
|
|
5413
|
+
const LogHelper2 = createLogHelper(params.debugActive ?? false);
|
|
5414
|
+
const entityObject = params.entityObject;
|
|
5415
|
+
if (!entityObject.entityId) {
|
|
5416
|
+
LogHelper2.warn("[CardHeadOffice] entityId is missing, generating temporary ID");
|
|
5417
|
+
entityObject.entityId = `temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
5418
|
+
}
|
|
5419
|
+
if (!params.delayTimeConnectionInMins) {
|
|
5420
|
+
LogHelper2.warn(
|
|
5421
|
+
`[CardHeadOffice] delayTimeConnectionInMins is missing, defaulting to ${DEFAUL_DELAY_TIME_CONNECTION_IN_MINS} mins`
|
|
5422
|
+
);
|
|
5423
|
+
}
|
|
5424
|
+
return {
|
|
5425
|
+
entityObject,
|
|
5426
|
+
i18n: { ...DEFAULT_I18N, ...params.i18n || {} },
|
|
5427
|
+
enableSelection: Boolean(params.enableSelection),
|
|
5428
|
+
enableDragDrop: Boolean(params.enableDragDrop),
|
|
5429
|
+
useNewComponents: Boolean(params.useNewComponents),
|
|
5430
|
+
// RFC-0091: Configurable delay time for connection status check (default 15 minutes)
|
|
5431
|
+
delayTimeConnectionInMins: params.delayTimeConnectionInMins ?? DEFAUL_DELAY_TIME_CONNECTION_IN_MINS,
|
|
5432
|
+
// Debug options
|
|
5433
|
+
debugActive: params.debugActive ?? false,
|
|
5434
|
+
activeTooltipDebug: params.activeTooltipDebug ?? false,
|
|
5435
|
+
// LogHelper instance for this card
|
|
5436
|
+
LogHelper: LogHelper2,
|
|
5437
|
+
callbacks: {
|
|
5438
|
+
handleActionDashboard: params.handleActionDashboard,
|
|
5439
|
+
handleActionReport: params.handleActionReport,
|
|
5440
|
+
handleActionSettings: params.handleActionSettings,
|
|
5441
|
+
handleSelect: params.handleSelect,
|
|
5442
|
+
handInfo: params.handInfo,
|
|
5443
|
+
handleClickCard: params.handleClickCard
|
|
5444
|
+
}
|
|
5445
|
+
};
|
|
5446
|
+
}
|
|
5447
|
+
function getIconSvg(deviceType, domain) {
|
|
5448
|
+
if (domain === "water") {
|
|
5449
|
+
return Icons.waterDrop;
|
|
4870
5450
|
}
|
|
4871
5451
|
if (domain === "temperature") {
|
|
4872
5452
|
return Icons.thermometer;
|
|
@@ -4891,16 +5471,10 @@ function formatValueByDomain(value, domain) {
|
|
|
4891
5471
|
return formatWaterVolumeM3(value);
|
|
4892
5472
|
}
|
|
4893
5473
|
if (domain === "temperature") {
|
|
4894
|
-
return formatTemperature(value);
|
|
5474
|
+
return formatTemperature(value, 0);
|
|
4895
5475
|
}
|
|
4896
5476
|
return formatEnergy(value);
|
|
4897
5477
|
}
|
|
4898
|
-
function formatTemperature(temp) {
|
|
4899
|
-
if (temp === null || temp === void 0 || isNaN(temp)) {
|
|
4900
|
-
return "\u2014";
|
|
4901
|
-
}
|
|
4902
|
-
return `${temp.toFixed(0)}\xB0C`;
|
|
4903
|
-
}
|
|
4904
5478
|
function calculateConsumptionPercentage(target, consumption) {
|
|
4905
5479
|
const numericTarget = Number(target);
|
|
4906
5480
|
const numericConsumption = Number(consumption);
|
|
@@ -4915,32 +5489,32 @@ function getStatusInfo(deviceStatus, i18n, domain) {
|
|
|
4915
5489
|
// --- Novos Status de Temperatura ---
|
|
4916
5490
|
case "normal":
|
|
4917
5491
|
return { chipClass: "chip--ok", label: "Normal" };
|
|
4918
|
-
// Verde/Azul
|
|
4919
5492
|
case "cold":
|
|
4920
5493
|
return { chipClass: "chip--standby", label: "Frio" };
|
|
4921
|
-
// Azul claro/Ciano
|
|
4922
5494
|
case "hot":
|
|
4923
5495
|
return { chipClass: "chip--alert", label: "Quente" };
|
|
4924
|
-
//
|
|
4925
|
-
// --- Status Existentes ---
|
|
5496
|
+
// --- Status Existentes (aligned with getCardStateClass) ---
|
|
4926
5497
|
case DeviceStatusType.POWER_ON:
|
|
4927
5498
|
if (domain === "water") {
|
|
4928
|
-
return { chipClass: "chip--
|
|
5499
|
+
return { chipClass: "chip--power-on", label: i18n.in_operation_water };
|
|
4929
5500
|
}
|
|
4930
|
-
return { chipClass: "chip--
|
|
5501
|
+
return { chipClass: "chip--power-on", label: i18n.in_operation };
|
|
4931
5502
|
case DeviceStatusType.STANDBY:
|
|
4932
5503
|
return { chipClass: "chip--standby", label: i18n.standby };
|
|
4933
5504
|
case DeviceStatusType.WARNING:
|
|
4934
|
-
return { chipClass: "chip--
|
|
5505
|
+
return { chipClass: "chip--warning", label: i18n.alert };
|
|
5506
|
+
case DeviceStatusType.MAINTENANCE:
|
|
5507
|
+
return { chipClass: "chip--maintenance", label: i18n.maintenance };
|
|
4935
5508
|
case DeviceStatusType.FAILURE:
|
|
4936
|
-
case DeviceStatusType.POWER_OFF:
|
|
4937
5509
|
return { chipClass: "chip--failure", label: i18n.failure };
|
|
4938
|
-
case DeviceStatusType.
|
|
4939
|
-
return { chipClass: "chip--
|
|
4940
|
-
case DeviceStatusType.
|
|
4941
|
-
return { chipClass: "chip--offline", label: i18n.
|
|
4942
|
-
// Default (Cai aqui se não achar 'normal', 'hot' etc)
|
|
5510
|
+
case DeviceStatusType.POWER_OFF:
|
|
5511
|
+
return { chipClass: "chip--power-off", label: i18n.power_off || i18n.failure };
|
|
5512
|
+
case DeviceStatusType.OFFLINE:
|
|
5513
|
+
return { chipClass: "chip--offline", label: i18n.offline };
|
|
4943
5514
|
case DeviceStatusType.NO_INFO:
|
|
5515
|
+
return { chipClass: "chip--no-info", label: i18n.no_info || i18n.offline };
|
|
5516
|
+
case DeviceStatusType.NOT_INSTALLED:
|
|
5517
|
+
return { chipClass: "chip--not-installed", label: i18n.not_installed };
|
|
4944
5518
|
default:
|
|
4945
5519
|
return { chipClass: "chip--offline", label: i18n.offline };
|
|
4946
5520
|
}
|
|
@@ -4948,23 +5522,32 @@ function getStatusInfo(deviceStatus, i18n, domain) {
|
|
|
4948
5522
|
function getCardStateClass(deviceStatus) {
|
|
4949
5523
|
switch (deviceStatus) {
|
|
4950
5524
|
case DeviceStatusType.POWER_ON:
|
|
4951
|
-
return "is-
|
|
5525
|
+
return "is-power-on";
|
|
4952
5526
|
// Blue border
|
|
4953
5527
|
case DeviceStatusType.STANDBY:
|
|
4954
5528
|
return "is-standby";
|
|
4955
5529
|
// Green border
|
|
4956
5530
|
case DeviceStatusType.WARNING:
|
|
5531
|
+
return "is-warning";
|
|
5532
|
+
// Yellow border
|
|
4957
5533
|
case DeviceStatusType.MAINTENANCE:
|
|
4958
|
-
return "is-
|
|
5534
|
+
return "is-maintenance";
|
|
4959
5535
|
// Yellow border
|
|
4960
5536
|
case DeviceStatusType.FAILURE:
|
|
4961
|
-
case DeviceStatusType.POWER_OFF:
|
|
4962
5537
|
return "is-failure";
|
|
4963
|
-
// Red border
|
|
5538
|
+
// Dark Red border
|
|
5539
|
+
case DeviceStatusType.POWER_OFF:
|
|
5540
|
+
return "is-power-off";
|
|
5541
|
+
// Light Red border
|
|
5542
|
+
case DeviceStatusType.OFFLINE:
|
|
5543
|
+
return "is-offline";
|
|
5544
|
+
// Dark Gray border
|
|
4964
5545
|
case DeviceStatusType.NO_INFO:
|
|
5546
|
+
return "is-no-info";
|
|
5547
|
+
// Dark Orange border
|
|
4965
5548
|
case DeviceStatusType.NOT_INSTALLED:
|
|
4966
|
-
return "is-
|
|
4967
|
-
//
|
|
5549
|
+
return "is-not-installed";
|
|
5550
|
+
// Purple border
|
|
4968
5551
|
default:
|
|
4969
5552
|
return "";
|
|
4970
5553
|
}
|
|
@@ -4978,17 +5561,25 @@ function getStatusDotClass(deviceStatus) {
|
|
|
4978
5561
|
return "dot--standby";
|
|
4979
5562
|
case "hot":
|
|
4980
5563
|
return "dot--alert";
|
|
4981
|
-
// --- Status Existentes ---
|
|
5564
|
+
// --- Status Existentes (aligned with getCardStateClass) ---
|
|
4982
5565
|
case DeviceStatusType.POWER_ON:
|
|
4983
|
-
return "dot--
|
|
5566
|
+
return "dot--power-on";
|
|
4984
5567
|
case DeviceStatusType.STANDBY:
|
|
4985
5568
|
return "dot--standby";
|
|
4986
5569
|
case DeviceStatusType.WARNING:
|
|
5570
|
+
return "dot--warning";
|
|
4987
5571
|
case DeviceStatusType.MAINTENANCE:
|
|
4988
|
-
return "dot--
|
|
5572
|
+
return "dot--maintenance";
|
|
4989
5573
|
case DeviceStatusType.FAILURE:
|
|
4990
|
-
case DeviceStatusType.POWER_OFF:
|
|
4991
5574
|
return "dot--failure";
|
|
5575
|
+
case DeviceStatusType.POWER_OFF:
|
|
5576
|
+
return "dot--power-off";
|
|
5577
|
+
case DeviceStatusType.OFFLINE:
|
|
5578
|
+
return "dot--offline";
|
|
5579
|
+
case DeviceStatusType.NO_INFO:
|
|
5580
|
+
return "dot--no-info";
|
|
5581
|
+
case DeviceStatusType.NOT_INSTALLED:
|
|
5582
|
+
return "dot--not-installed";
|
|
4992
5583
|
default:
|
|
4993
5584
|
return "dot--offline";
|
|
4994
5585
|
}
|
|
@@ -5012,7 +5603,13 @@ function buildDOM(state) {
|
|
|
5012
5603
|
titleSection.className = "myio-ho-card__title";
|
|
5013
5604
|
const nameEl = document.createElement("div");
|
|
5014
5605
|
nameEl.className = "myio-ho-card__name";
|
|
5015
|
-
|
|
5606
|
+
const fullName = entityObject.labelOrName || "Unknown Device";
|
|
5607
|
+
if (fullName.length > LABEL_CHAR_LIMIT) {
|
|
5608
|
+
nameEl.textContent = fullName.slice(0, LABEL_CHAR_LIMIT) + "\u2026";
|
|
5609
|
+
nameEl.title = fullName;
|
|
5610
|
+
} else {
|
|
5611
|
+
nameEl.textContent = fullName;
|
|
5612
|
+
}
|
|
5016
5613
|
titleSection.appendChild(nameEl);
|
|
5017
5614
|
if (entityObject.deviceIdentifier) {
|
|
5018
5615
|
const codeEl = document.createElement("div");
|
|
@@ -5141,29 +5738,207 @@ function buildDOM(state) {
|
|
|
5141
5738
|
root.appendChild(footer);
|
|
5142
5739
|
return root;
|
|
5143
5740
|
}
|
|
5144
|
-
function
|
|
5741
|
+
function buildDebugTooltipInfo(entityObject, statusInfo, stateClass, statusDecisionSource, delayTimeConnectionInMins) {
|
|
5742
|
+
const formatTimestamp = (ts) => {
|
|
5743
|
+
if (!ts) return "N/A";
|
|
5744
|
+
const d = new Date(ts);
|
|
5745
|
+
return d.toLocaleString("pt-BR", {
|
|
5746
|
+
day: "2-digit",
|
|
5747
|
+
month: "2-digit",
|
|
5748
|
+
year: "numeric",
|
|
5749
|
+
hour: "2-digit",
|
|
5750
|
+
minute: "2-digit",
|
|
5751
|
+
second: "2-digit"
|
|
5752
|
+
});
|
|
5753
|
+
};
|
|
5754
|
+
return {
|
|
5755
|
+
// Entity identification
|
|
5756
|
+
entityId: entityObject.entityId || "N/A",
|
|
5757
|
+
name: entityObject.name || entityObject.nameEl || "N/A",
|
|
5758
|
+
domain: entityObject.domain || "energy",
|
|
5759
|
+
// Status decision chain
|
|
5760
|
+
originalDeviceStatus: entityObject._originalDeviceStatus || entityObject.deviceStatus,
|
|
5761
|
+
finalDeviceStatus: entityObject.deviceStatus,
|
|
5762
|
+
connectionStatus: entityObject.connectionStatus || "N/A",
|
|
5763
|
+
statusDecisionSource,
|
|
5764
|
+
// Visual output
|
|
5765
|
+
stateClass,
|
|
5766
|
+
chipClass: statusInfo.chipClass,
|
|
5767
|
+
chipLabel: statusInfo.label,
|
|
5768
|
+
// Connection timestamps
|
|
5769
|
+
lastConnectTime: formatTimestamp(entityObject.lastConnectTime),
|
|
5770
|
+
lastDisconnectTime: formatTimestamp(entityObject.lastDisconnectTime),
|
|
5771
|
+
delayTimeConnectionInMins,
|
|
5772
|
+
// Raw values
|
|
5773
|
+
val: entityObject.val,
|
|
5774
|
+
consumptionTargetValue: entityObject.consumptionTargetValue,
|
|
5775
|
+
deviceType: entityObject.deviceType || "N/A"
|
|
5776
|
+
};
|
|
5777
|
+
}
|
|
5778
|
+
function attachDebugTooltip(element, debugInfo) {
|
|
5779
|
+
const existingTooltip = element.querySelector(".debug-tooltip-container");
|
|
5780
|
+
if (existingTooltip) {
|
|
5781
|
+
existingTooltip.remove();
|
|
5782
|
+
}
|
|
5783
|
+
const tooltipContainer = document.createElement("div");
|
|
5784
|
+
tooltipContainer.className = "debug-tooltip-container";
|
|
5785
|
+
const tooltip = document.createElement("div");
|
|
5786
|
+
tooltip.className = "debug-tooltip";
|
|
5787
|
+
tooltip.innerHTML = `
|
|
5788
|
+
<div class="debug-tooltip__header">
|
|
5789
|
+
<span class="debug-tooltip__icon">\u{1F50D}</span>
|
|
5790
|
+
<span class="debug-tooltip__title">Debug Info</span>
|
|
5791
|
+
</div>
|
|
5792
|
+
<div class="debug-tooltip__content">
|
|
5793
|
+
<div class="debug-tooltip__section">
|
|
5794
|
+
<div class="debug-tooltip__section-title">\u{1F4CB} Identifica\xE7\xE3o</div>
|
|
5795
|
+
<div class="debug-tooltip__row">
|
|
5796
|
+
<span class="debug-tooltip__label">Entity ID:</span>
|
|
5797
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.entityId}</span>
|
|
5798
|
+
</div>
|
|
5799
|
+
<div class="debug-tooltip__row">
|
|
5800
|
+
<span class="debug-tooltip__label">Nome:</span>
|
|
5801
|
+
<span class="debug-tooltip__value">${debugInfo.name}</span>
|
|
5802
|
+
</div>
|
|
5803
|
+
<div class="debug-tooltip__row">
|
|
5804
|
+
<span class="debug-tooltip__label">Dom\xEDnio:</span>
|
|
5805
|
+
<span class="debug-tooltip__value debug-tooltip__badge debug-tooltip__badge--${debugInfo.domain}">${debugInfo.domain}</span>
|
|
5806
|
+
</div>
|
|
5807
|
+
</div>
|
|
5808
|
+
|
|
5809
|
+
<div class="debug-tooltip__section">
|
|
5810
|
+
<div class="debug-tooltip__section-title">\u26A1 Decis\xE3o de Status</div>
|
|
5811
|
+
<div class="debug-tooltip__row">
|
|
5812
|
+
<span class="debug-tooltip__label">connectionStatus:</span>
|
|
5813
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.connectionStatus}</span>
|
|
5814
|
+
</div>
|
|
5815
|
+
<div class="debug-tooltip__row">
|
|
5816
|
+
<span class="debug-tooltip__label">deviceStatus (final):</span>
|
|
5817
|
+
<span class="debug-tooltip__value debug-tooltip__badge">${debugInfo.finalDeviceStatus}</span>
|
|
5818
|
+
</div>
|
|
5819
|
+
<div class="debug-tooltip__row debug-tooltip__row--full">
|
|
5820
|
+
<span class="debug-tooltip__label">Fonte da decis\xE3o:</span>
|
|
5821
|
+
<span class="debug-tooltip__value debug-tooltip__value--highlight">${debugInfo.statusDecisionSource}</span>
|
|
5822
|
+
</div>
|
|
5823
|
+
</div>
|
|
5824
|
+
|
|
5825
|
+
<div class="debug-tooltip__section">
|
|
5826
|
+
<div class="debug-tooltip__section-title">\u{1F3A8} Output Visual</div>
|
|
5827
|
+
<div class="debug-tooltip__row">
|
|
5828
|
+
<span class="debug-tooltip__label">stateClass:</span>
|
|
5829
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.stateClass}</span>
|
|
5830
|
+
</div>
|
|
5831
|
+
<div class="debug-tooltip__row">
|
|
5832
|
+
<span class="debug-tooltip__label">chipClass:</span>
|
|
5833
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.chipClass}</span>
|
|
5834
|
+
</div>
|
|
5835
|
+
<div class="debug-tooltip__row">
|
|
5836
|
+
<span class="debug-tooltip__label">chipLabel:</span>
|
|
5837
|
+
<span class="debug-tooltip__value">${debugInfo.chipLabel}</span>
|
|
5838
|
+
</div>
|
|
5839
|
+
</div>
|
|
5840
|
+
|
|
5841
|
+
<div class="debug-tooltip__section">
|
|
5842
|
+
<div class="debug-tooltip__section-title">\u{1F550} Timestamps de Conex\xE3o</div>
|
|
5843
|
+
<div class="debug-tooltip__row">
|
|
5844
|
+
<span class="debug-tooltip__label">lastConnectTime:</span>
|
|
5845
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.lastConnectTime}</span>
|
|
5846
|
+
</div>
|
|
5847
|
+
<div class="debug-tooltip__row">
|
|
5848
|
+
<span class="debug-tooltip__label">lastDisconnectTime:</span>
|
|
5849
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.lastDisconnectTime}</span>
|
|
5850
|
+
</div>
|
|
5851
|
+
<div class="debug-tooltip__row">
|
|
5852
|
+
<span class="debug-tooltip__label">delayTime:</span>
|
|
5853
|
+
<span class="debug-tooltip__value">${debugInfo.delayTimeConnectionInMins} mins</span>
|
|
5854
|
+
</div>
|
|
5855
|
+
</div>
|
|
5856
|
+
|
|
5857
|
+
<div class="debug-tooltip__section">
|
|
5858
|
+
<div class="debug-tooltip__section-title">\u{1F4CA} Valores</div>
|
|
5859
|
+
<div class="debug-tooltip__row">
|
|
5860
|
+
<span class="debug-tooltip__label">val (consumo):</span>
|
|
5861
|
+
<span class="debug-tooltip__value">${debugInfo.val ?? "N/A"}</span>
|
|
5862
|
+
</div>
|
|
5863
|
+
<div class="debug-tooltip__row">
|
|
5864
|
+
<span class="debug-tooltip__label">target (meta):</span>
|
|
5865
|
+
<span class="debug-tooltip__value">${debugInfo.consumptionTargetValue ?? "N/A"}</span>
|
|
5866
|
+
</div>
|
|
5867
|
+
<div class="debug-tooltip__row">
|
|
5868
|
+
<span class="debug-tooltip__label">deviceType:</span>
|
|
5869
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.deviceType}</span>
|
|
5870
|
+
</div>
|
|
5871
|
+
</div>
|
|
5872
|
+
</div>
|
|
5873
|
+
`;
|
|
5874
|
+
tooltipContainer.appendChild(tooltip);
|
|
5875
|
+
element.style.position = "relative";
|
|
5876
|
+
element.style.cursor = "help";
|
|
5877
|
+
element.appendChild(tooltipContainer);
|
|
5878
|
+
element.classList.add("has-debug-tooltip");
|
|
5879
|
+
}
|
|
5880
|
+
function verifyOfflineStatus(entityObject, delayTimeInMins = 15, LogHelper2) {
|
|
5145
5881
|
const lastConnectionTime = new Date(entityObject.lastConnectTime || 0);
|
|
5146
5882
|
const lastDisconnectTime = new Date(entityObject.lastDisconnectTime || 0);
|
|
5147
5883
|
const now = /* @__PURE__ */ new Date();
|
|
5148
5884
|
const delayTimeInMs = delayTimeInMins * 60 * 1e3;
|
|
5149
5885
|
const timeSinceConnection = now.getTime() - lastConnectionTime.getTime();
|
|
5886
|
+
let isOffline = false;
|
|
5150
5887
|
if (lastDisconnectTime.getTime() > lastConnectionTime.getTime()) {
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5888
|
+
isOffline = true;
|
|
5889
|
+
LogHelper2.log(
|
|
5890
|
+
"[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastDisconnectTime is more recent than lastConnectTime",
|
|
5891
|
+
entityObject.nameEl
|
|
5892
|
+
);
|
|
5893
|
+
} else if (timeSinceConnection > delayTimeInMs) {
|
|
5894
|
+
isOffline = true;
|
|
5895
|
+
LogHelper2.log(
|
|
5896
|
+
"[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastConnectTime is older than configured delayTimeConnectionInMins:",
|
|
5897
|
+
delayTimeInMins,
|
|
5898
|
+
"for device",
|
|
5899
|
+
entityObject.nameEl
|
|
5900
|
+
);
|
|
5901
|
+
} else {
|
|
5902
|
+
isOffline = false;
|
|
5903
|
+
LogHelper2.log(
|
|
5904
|
+
"[CardHeadOffice][ConnectionStatus Verify] Device is ONLINE because lastConnectTime is within configured delayTimeConnectionInMins:",
|
|
5905
|
+
delayTimeInMins,
|
|
5906
|
+
"for device",
|
|
5907
|
+
entityObject.nameEl
|
|
5908
|
+
);
|
|
5155
5909
|
}
|
|
5156
|
-
return
|
|
5910
|
+
return isOffline;
|
|
5157
5911
|
}
|
|
5158
5912
|
function paint(root, state) {
|
|
5159
|
-
const { entityObject, i18n, delayTimeConnectionInMins, isSelected } = state;
|
|
5913
|
+
const { entityObject, i18n, delayTimeConnectionInMins, isSelected, LogHelper: LogHelper2, activeTooltipDebug } = state;
|
|
5914
|
+
let statusDecisionSource = "unknown";
|
|
5160
5915
|
if (entityObject.connectionStatus) {
|
|
5161
5916
|
if (entityObject.connectionStatus === "offline") {
|
|
5162
|
-
|
|
5917
|
+
LogHelper2.log(
|
|
5918
|
+
"[CardHeadOffice][ConnectionStatus Verify 01] Setting deviceStatus to OFFLINE based on connectionStatus"
|
|
5919
|
+
);
|
|
5920
|
+
entityObject.deviceStatus = DeviceStatusType.OFFLINE;
|
|
5921
|
+
statusDecisionSource = 'connectionStatus === "offline"';
|
|
5922
|
+
} else {
|
|
5923
|
+
LogHelper2.log(
|
|
5924
|
+
"[CardHeadOffice] Device is ONLINE or WAITING based on connectionStatus for device",
|
|
5925
|
+
entityObject.nameEl
|
|
5926
|
+
);
|
|
5927
|
+
statusDecisionSource = `connectionStatus === "${entityObject.connectionStatus}" (kept original deviceStatus)`;
|
|
5163
5928
|
}
|
|
5164
5929
|
} else {
|
|
5165
|
-
if (verifyOfflineStatus(entityObject, delayTimeConnectionInMins) === false) {
|
|
5166
|
-
|
|
5930
|
+
if (verifyOfflineStatus(entityObject, delayTimeConnectionInMins, LogHelper2) === false) {
|
|
5931
|
+
LogHelper2.log(
|
|
5932
|
+
"[CardHeadOffice][ConnectionStatus Verify 02] Setting deviceStatus to OFFLINE based on timestamp verification by verifyOfflineStatus METHOD with delayTimeConnectionInMins:",
|
|
5933
|
+
delayTimeConnectionInMins
|
|
5934
|
+
);
|
|
5935
|
+
entityObject.deviceStatus = DeviceStatusType.OFFLINE;
|
|
5936
|
+
statusDecisionSource = `verifyOfflineStatus() returned false (delay: ${delayTimeConnectionInMins} mins)`;
|
|
5937
|
+
} else {
|
|
5938
|
+
LogHelper2.log(
|
|
5939
|
+
`[CardHeadOffice][ConnectionStatus Verify 03] Device is ONLINE with deviceStatus = ${entityObject.deviceStatus} based on timestamp verification for device ${entityObject.nameEl}`
|
|
5940
|
+
);
|
|
5941
|
+
statusDecisionSource = `verifyOfflineStatus() returned true (delay: ${delayTimeConnectionInMins} mins)`;
|
|
5167
5942
|
}
|
|
5168
5943
|
}
|
|
5169
5944
|
const stateClass = getCardStateClass(entityObject.deviceStatus);
|
|
@@ -5172,6 +5947,10 @@ function paint(root, state) {
|
|
|
5172
5947
|
const chip = root.querySelector(".chip");
|
|
5173
5948
|
chip.className = `chip ${statusInfo.chipClass}`;
|
|
5174
5949
|
chip.innerHTML = statusInfo.label;
|
|
5950
|
+
if (activeTooltipDebug) {
|
|
5951
|
+
const debugInfo = buildDebugTooltipInfo(entityObject, statusInfo, stateClass, statusDecisionSource, delayTimeConnectionInMins);
|
|
5952
|
+
attachDebugTooltip(chip, debugInfo);
|
|
5953
|
+
}
|
|
5175
5954
|
const primaryValue = formatValueByDomain(entityObject.val, entityObject.domain);
|
|
5176
5955
|
const numSpan = root.querySelector(".myio-ho-card__value .num");
|
|
5177
5956
|
const unitSpan = root.querySelector(".myio-ho-card__value .unit");
|
|
@@ -5384,6 +6163,7 @@ function renderCardComponentHeadOffice(containerEl, params) {
|
|
|
5384
6163
|
}
|
|
5385
6164
|
|
|
5386
6165
|
// src/thingsboard/main-dashboard-shopping/v-5.2.0/card/template-card-v5.js
|
|
6166
|
+
var LABEL_CHAR_LIMIT2 = 18;
|
|
5387
6167
|
function renderCardComponentV5({
|
|
5388
6168
|
entityObject,
|
|
5389
6169
|
handleActionDashboard,
|
|
@@ -5900,7 +6680,7 @@ ${rangeText}`;
|
|
|
5900
6680
|
|
|
5901
6681
|
<div class="device-title-row" style="flex-direction: column; min-height: 38px; text-align: center; width: 100%;">
|
|
5902
6682
|
<span class="device-title" title="${cardEntity.name}">
|
|
5903
|
-
${cardEntity.name.length >
|
|
6683
|
+
${cardEntity.name.length > LABEL_CHAR_LIMIT2 ? cardEntity.name.slice(0, LABEL_CHAR_LIMIT2) + "\u2026" : cardEntity.name}
|
|
5904
6684
|
</span>
|
|
5905
6685
|
${deviceIdentifier ? `
|
|
5906
6686
|
<span class="device-subtitle" title="${deviceIdentifier}">
|
|
@@ -15840,23 +16620,1019 @@ function validateOptions2(options) {
|
|
|
15840
16620
|
if (isNaN(level) || level < 0 || level > 100) {
|
|
15841
16621
|
errors.push("currentLevel must be a number between 0 and 100");
|
|
15842
16622
|
}
|
|
15843
|
-
}
|
|
15844
|
-
if (options.limit !== void 0) {
|
|
15845
|
-
const limit = Number(options.limit);
|
|
15846
|
-
if (isNaN(limit) || limit < 1 || limit > 1e4) {
|
|
15847
|
-
errors.push("limit must be a number between 1 and 10000");
|
|
16623
|
+
}
|
|
16624
|
+
if (options.limit !== void 0) {
|
|
16625
|
+
const limit = Number(options.limit);
|
|
16626
|
+
if (isNaN(limit) || limit < 1 || limit > 1e4) {
|
|
16627
|
+
errors.push("limit must be a number between 1 and 10000");
|
|
16628
|
+
}
|
|
16629
|
+
}
|
|
16630
|
+
if (options.aggregation !== void 0) {
|
|
16631
|
+
const validAggregations = ["NONE", "MIN", "MAX", "AVG", "SUM", "COUNT"];
|
|
16632
|
+
if (!validAggregations.includes(options.aggregation)) {
|
|
16633
|
+
errors.push(`aggregation must be one of: ${validAggregations.join(", ")}`);
|
|
16634
|
+
}
|
|
16635
|
+
}
|
|
16636
|
+
if (errors.length > 0) {
|
|
16637
|
+
throw new Error(`Validation failed:
|
|
16638
|
+
- ${errors.join("\n- ")}`);
|
|
16639
|
+
}
|
|
16640
|
+
}
|
|
16641
|
+
|
|
16642
|
+
// src/components/premium-modals/power-limits/types.ts
|
|
16643
|
+
var DEVICE_TYPES = [
|
|
16644
|
+
{ value: "ELEVADOR", label: "Elevator" },
|
|
16645
|
+
{ value: "ESCADA_ROLANTE", label: "Escalator" },
|
|
16646
|
+
{ value: "MOTOR", label: "Motor" },
|
|
16647
|
+
{ value: "BOMBA", label: "Pump" },
|
|
16648
|
+
{ value: "CHILLER", label: "Chiller" },
|
|
16649
|
+
{ value: "AR_CONDICIONADO", label: "Air Conditioner" },
|
|
16650
|
+
{ value: "HVAC", label: "HVAC" },
|
|
16651
|
+
{ value: "FANCOIL", label: "Fancoil" },
|
|
16652
|
+
{ value: "3F_MEDIDOR", label: "Three-phase Meter" }
|
|
16653
|
+
];
|
|
16654
|
+
var TELEMETRY_TYPES2 = [
|
|
16655
|
+
{ value: "consumption", label: "Consumption (kW)", unit: "kW" },
|
|
16656
|
+
{ value: "voltage_a", label: "Voltage A (V)", unit: "V" },
|
|
16657
|
+
{ value: "voltage_b", label: "Voltage B (V)", unit: "V" },
|
|
16658
|
+
{ value: "voltage_c", label: "Voltage C (V)", unit: "V" },
|
|
16659
|
+
{ value: "current_a", label: "Current A (A)", unit: "A" },
|
|
16660
|
+
{ value: "current_b", label: "Current B (A)", unit: "A" },
|
|
16661
|
+
{ value: "current_c", label: "Current C (A)", unit: "A" },
|
|
16662
|
+
{ value: "total_current", label: "Total Current (A)", unit: "A" },
|
|
16663
|
+
{ value: "fp_a", label: "Power Factor A", unit: "" },
|
|
16664
|
+
{ value: "fp_b", label: "Power Factor B", unit: "" },
|
|
16665
|
+
{ value: "fp_c", label: "Power Factor C", unit: "" }
|
|
16666
|
+
];
|
|
16667
|
+
var STATUS_CONFIG = {
|
|
16668
|
+
standBy: { label: "StandBy", color: "#22c55e", bgColor: "rgba(34, 197, 94, 0.1)" },
|
|
16669
|
+
normal: { label: "Normal", color: "#3b82f6", bgColor: "rgba(59, 130, 246, 0.1)" },
|
|
16670
|
+
alert: { label: "Alert", color: "#f59e0b", bgColor: "rgba(245, 158, 11, 0.1)" },
|
|
16671
|
+
failure: { label: "Failure", color: "#ef4444", bgColor: "rgba(239, 68, 68, 0.1)" }
|
|
16672
|
+
};
|
|
16673
|
+
|
|
16674
|
+
// src/components/premium-modals/power-limits/PowerLimitsModalView.ts
|
|
16675
|
+
var PowerLimitsModalView = class {
|
|
16676
|
+
container = null;
|
|
16677
|
+
overlayEl = null;
|
|
16678
|
+
config;
|
|
16679
|
+
formData;
|
|
16680
|
+
isLoading = false;
|
|
16681
|
+
isSaving = false;
|
|
16682
|
+
constructor(config) {
|
|
16683
|
+
this.config = config;
|
|
16684
|
+
this.formData = {
|
|
16685
|
+
deviceType: config.deviceType,
|
|
16686
|
+
telemetryType: config.telemetryType,
|
|
16687
|
+
standby: { baseValue: null, topValue: null },
|
|
16688
|
+
normal: { baseValue: null, topValue: null },
|
|
16689
|
+
alert: { baseValue: null, topValue: null },
|
|
16690
|
+
failure: { baseValue: null, topValue: null }
|
|
16691
|
+
};
|
|
16692
|
+
}
|
|
16693
|
+
render(targetContainer) {
|
|
16694
|
+
this.overlayEl = document.createElement("div");
|
|
16695
|
+
this.overlayEl.className = "myio-power-limits-overlay";
|
|
16696
|
+
this.overlayEl.innerHTML = `
|
|
16697
|
+
<style>${this.getStyles()}</style>
|
|
16698
|
+
<div class="myio-power-limits-card">
|
|
16699
|
+
${this.renderHeader()}
|
|
16700
|
+
${this.renderSelectors()}
|
|
16701
|
+
${this.renderStatusCards()}
|
|
16702
|
+
${this.renderLoadingState()}
|
|
16703
|
+
${this.renderErrorState()}
|
|
16704
|
+
${this.renderSuccessState()}
|
|
16705
|
+
</div>
|
|
16706
|
+
`;
|
|
16707
|
+
const target = targetContainer || document.body;
|
|
16708
|
+
target.appendChild(this.overlayEl);
|
|
16709
|
+
this.container = this.overlayEl.querySelector(".myio-power-limits-card");
|
|
16710
|
+
this.setupEventListeners();
|
|
16711
|
+
requestAnimationFrame(() => {
|
|
16712
|
+
this.overlayEl?.classList.add("active");
|
|
16713
|
+
});
|
|
16714
|
+
return this.overlayEl;
|
|
16715
|
+
}
|
|
16716
|
+
renderHeader() {
|
|
16717
|
+
return `
|
|
16718
|
+
<div class="myio-power-limits-header">
|
|
16719
|
+
<div class="myio-power-limits-title-section">
|
|
16720
|
+
<span class="myio-power-limits-icon">⚙</span>
|
|
16721
|
+
<h2 class="myio-power-limits-title">Power Limits Setup</h2>
|
|
16722
|
+
</div>
|
|
16723
|
+
<div class="myio-power-limits-actions">
|
|
16724
|
+
<button class="myio-btn myio-btn-primary" id="plm-save-btn" type="button">
|
|
16725
|
+
<span class="myio-btn-text">Save</span>
|
|
16726
|
+
<span class="myio-btn-spinner" style="display: none;"></span>
|
|
16727
|
+
</button>
|
|
16728
|
+
<button class="myio-btn myio-btn-secondary" id="plm-reset-btn" type="button">Reset</button>
|
|
16729
|
+
<button class="myio-btn myio-btn-close" id="plm-close-btn" type="button" aria-label="Close">×</button>
|
|
16730
|
+
</div>
|
|
16731
|
+
</div>
|
|
16732
|
+
`;
|
|
16733
|
+
}
|
|
16734
|
+
renderSelectors() {
|
|
16735
|
+
const deviceOptions = DEVICE_TYPES.map(
|
|
16736
|
+
(dt) => `<option value="${dt.value}" ${dt.value === this.config.deviceType ? "selected" : ""}>${dt.label}</option>`
|
|
16737
|
+
).join("");
|
|
16738
|
+
const telemetryOptions = TELEMETRY_TYPES2.map(
|
|
16739
|
+
(tt) => `<option value="${tt.value}" ${tt.value === this.config.telemetryType ? "selected" : ""}>${tt.label}</option>`
|
|
16740
|
+
).join("");
|
|
16741
|
+
return `
|
|
16742
|
+
<div class="myio-power-limits-selectors">
|
|
16743
|
+
<div class="myio-form-group">
|
|
16744
|
+
<label for="plm-device-type">Device Type</label>
|
|
16745
|
+
<select id="plm-device-type" class="myio-select">
|
|
16746
|
+
${deviceOptions}
|
|
16747
|
+
</select>
|
|
16748
|
+
</div>
|
|
16749
|
+
<div class="myio-form-group">
|
|
16750
|
+
<label for="plm-telemetry-type">Telemetry Type</label>
|
|
16751
|
+
<select id="plm-telemetry-type" class="myio-select">
|
|
16752
|
+
${telemetryOptions}
|
|
16753
|
+
</select>
|
|
16754
|
+
</div>
|
|
16755
|
+
</div>
|
|
16756
|
+
`;
|
|
16757
|
+
}
|
|
16758
|
+
renderStatusCards() {
|
|
16759
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
16760
|
+
const cards = statuses.map((status) => {
|
|
16761
|
+
const config = STATUS_CONFIG[status === "standby" ? "standBy" : status];
|
|
16762
|
+
const formValues = this.formData[status];
|
|
16763
|
+
return `
|
|
16764
|
+
<div class="myio-power-limits-card-item myio-status-${status}" style="--status-color: ${config.color}; --status-bg: ${config.bgColor};">
|
|
16765
|
+
<div class="myio-card-header">
|
|
16766
|
+
<span class="myio-status-indicator"></span>
|
|
16767
|
+
<span class="myio-status-label">${config.label}</span>
|
|
16768
|
+
</div>
|
|
16769
|
+
<div class="myio-card-inputs">
|
|
16770
|
+
<div class="myio-input-group">
|
|
16771
|
+
<label for="plm-${status}-base">Base Value</label>
|
|
16772
|
+
<input
|
|
16773
|
+
type="number"
|
|
16774
|
+
id="plm-${status}-base"
|
|
16775
|
+
class="myio-input"
|
|
16776
|
+
min="0"
|
|
16777
|
+
step="0.01"
|
|
16778
|
+
value="${formValues.baseValue ?? ""}"
|
|
16779
|
+
placeholder="0"
|
|
16780
|
+
>
|
|
16781
|
+
</div>
|
|
16782
|
+
<div class="myio-input-group">
|
|
16783
|
+
<label for="plm-${status}-top">Top Value</label>
|
|
16784
|
+
<input
|
|
16785
|
+
type="number"
|
|
16786
|
+
id="plm-${status}-top"
|
|
16787
|
+
class="myio-input"
|
|
16788
|
+
min="0"
|
|
16789
|
+
step="0.01"
|
|
16790
|
+
value="${formValues.topValue ?? ""}"
|
|
16791
|
+
placeholder="0"
|
|
16792
|
+
>
|
|
16793
|
+
</div>
|
|
16794
|
+
</div>
|
|
16795
|
+
</div>
|
|
16796
|
+
`;
|
|
16797
|
+
}).join("");
|
|
16798
|
+
return `
|
|
16799
|
+
<div class="myio-power-limits-grid" id="plm-grid">
|
|
16800
|
+
${cards}
|
|
16801
|
+
</div>
|
|
16802
|
+
`;
|
|
16803
|
+
}
|
|
16804
|
+
renderLoadingState() {
|
|
16805
|
+
return `
|
|
16806
|
+
<div class="myio-power-limits-loading" id="plm-loading" style="display: none;">
|
|
16807
|
+
<div class="myio-spinner"></div>
|
|
16808
|
+
<span>Loading configuration...</span>
|
|
16809
|
+
</div>
|
|
16810
|
+
`;
|
|
16811
|
+
}
|
|
16812
|
+
renderErrorState() {
|
|
16813
|
+
return `
|
|
16814
|
+
<div class="myio-power-limits-error" id="plm-error" style="display: none;">
|
|
16815
|
+
<span class="myio-error-icon">⚠</span>
|
|
16816
|
+
<span class="myio-error-message" id="plm-error-msg"></span>
|
|
16817
|
+
</div>
|
|
16818
|
+
`;
|
|
16819
|
+
}
|
|
16820
|
+
renderSuccessState() {
|
|
16821
|
+
return `
|
|
16822
|
+
<div class="myio-power-limits-success" id="plm-success" style="display: none;">
|
|
16823
|
+
<span class="myio-success-icon">✓</span>
|
|
16824
|
+
<span class="myio-success-message">Configuration saved successfully!</span>
|
|
16825
|
+
</div>
|
|
16826
|
+
`;
|
|
16827
|
+
}
|
|
16828
|
+
setupEventListeners() {
|
|
16829
|
+
if (!this.overlayEl) return;
|
|
16830
|
+
const closeBtn = this.overlayEl.querySelector("#plm-close-btn");
|
|
16831
|
+
closeBtn?.addEventListener("click", () => this.close());
|
|
16832
|
+
this.overlayEl.addEventListener("click", (e) => {
|
|
16833
|
+
if (e.target === this.overlayEl) {
|
|
16834
|
+
this.close();
|
|
16835
|
+
}
|
|
16836
|
+
});
|
|
16837
|
+
document.addEventListener("keydown", this.handleKeyDown);
|
|
16838
|
+
const saveBtn = this.overlayEl.querySelector("#plm-save-btn");
|
|
16839
|
+
saveBtn?.addEventListener("click", () => this.handleSave());
|
|
16840
|
+
const resetBtn = this.overlayEl.querySelector("#plm-reset-btn");
|
|
16841
|
+
resetBtn?.addEventListener("click", () => this.handleReset());
|
|
16842
|
+
const deviceSelect = this.overlayEl.querySelector("#plm-device-type");
|
|
16843
|
+
deviceSelect?.addEventListener("change", (e) => {
|
|
16844
|
+
const value = e.target.value;
|
|
16845
|
+
this.formData.deviceType = value;
|
|
16846
|
+
this.config.onDeviceTypeChange(value);
|
|
16847
|
+
});
|
|
16848
|
+
const telemetrySelect = this.overlayEl.querySelector("#plm-telemetry-type");
|
|
16849
|
+
telemetrySelect?.addEventListener("change", (e) => {
|
|
16850
|
+
const value = e.target.value;
|
|
16851
|
+
this.formData.telemetryType = value;
|
|
16852
|
+
this.config.onTelemetryTypeChange(value);
|
|
16853
|
+
});
|
|
16854
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
16855
|
+
statuses.forEach((status) => {
|
|
16856
|
+
const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
|
|
16857
|
+
const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
|
|
16858
|
+
baseInput?.addEventListener("input", (e) => {
|
|
16859
|
+
const value = e.target.value;
|
|
16860
|
+
this.formData[status].baseValue = value ? parseFloat(value) : null;
|
|
16861
|
+
});
|
|
16862
|
+
topInput?.addEventListener("input", (e) => {
|
|
16863
|
+
const value = e.target.value;
|
|
16864
|
+
this.formData[status].topValue = value ? parseFloat(value) : null;
|
|
16865
|
+
});
|
|
16866
|
+
});
|
|
16867
|
+
}
|
|
16868
|
+
handleKeyDown = (e) => {
|
|
16869
|
+
if (e.key === "Escape") {
|
|
16870
|
+
this.close();
|
|
16871
|
+
}
|
|
16872
|
+
};
|
|
16873
|
+
async handleSave() {
|
|
16874
|
+
if (this.isSaving) return;
|
|
16875
|
+
const validationError = this.validateForm();
|
|
16876
|
+
if (validationError) {
|
|
16877
|
+
this.showError(validationError);
|
|
16878
|
+
return;
|
|
16879
|
+
}
|
|
16880
|
+
this.isSaving = true;
|
|
16881
|
+
this.showSaveLoading(true);
|
|
16882
|
+
this.hideError();
|
|
16883
|
+
this.hideSuccess();
|
|
16884
|
+
try {
|
|
16885
|
+
await this.config.onSave();
|
|
16886
|
+
this.showSuccess();
|
|
16887
|
+
setTimeout(() => this.hideSuccess(), 3e3);
|
|
16888
|
+
} catch (error) {
|
|
16889
|
+
this.showError(error.message || "Failed to save configuration");
|
|
16890
|
+
} finally {
|
|
16891
|
+
this.isSaving = false;
|
|
16892
|
+
this.showSaveLoading(false);
|
|
16893
|
+
}
|
|
16894
|
+
}
|
|
16895
|
+
handleReset() {
|
|
16896
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
16897
|
+
statuses.forEach((status) => {
|
|
16898
|
+
const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
|
|
16899
|
+
const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
|
|
16900
|
+
if (baseInput) baseInput.value = "";
|
|
16901
|
+
if (topInput) topInput.value = "";
|
|
16902
|
+
this.formData[status] = { baseValue: null, topValue: null };
|
|
16903
|
+
});
|
|
16904
|
+
this.hideError();
|
|
16905
|
+
this.hideSuccess();
|
|
16906
|
+
}
|
|
16907
|
+
validateForm() {
|
|
16908
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
16909
|
+
for (const status of statuses) {
|
|
16910
|
+
const base = this.formData[status].baseValue;
|
|
16911
|
+
const top = this.formData[status].topValue;
|
|
16912
|
+
if (base !== null && base < 0) {
|
|
16913
|
+
return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value cannot be negative`;
|
|
16914
|
+
}
|
|
16915
|
+
if (top !== null && top < 0) {
|
|
16916
|
+
return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Top value cannot be negative`;
|
|
16917
|
+
}
|
|
16918
|
+
if (base !== null && top !== null && base > top) {
|
|
16919
|
+
return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value should not exceed top value`;
|
|
16920
|
+
}
|
|
16921
|
+
}
|
|
16922
|
+
return null;
|
|
16923
|
+
}
|
|
16924
|
+
close() {
|
|
16925
|
+
document.removeEventListener("keydown", this.handleKeyDown);
|
|
16926
|
+
if (this.overlayEl) {
|
|
16927
|
+
this.overlayEl.classList.remove("active");
|
|
16928
|
+
setTimeout(() => {
|
|
16929
|
+
this.overlayEl?.remove();
|
|
16930
|
+
this.overlayEl = null;
|
|
16931
|
+
this.container = null;
|
|
16932
|
+
this.config.onClose();
|
|
16933
|
+
}, 300);
|
|
16934
|
+
}
|
|
16935
|
+
}
|
|
16936
|
+
destroy() {
|
|
16937
|
+
document.removeEventListener("keydown", this.handleKeyDown);
|
|
16938
|
+
this.overlayEl?.remove();
|
|
16939
|
+
this.overlayEl = null;
|
|
16940
|
+
this.container = null;
|
|
16941
|
+
}
|
|
16942
|
+
showLoading() {
|
|
16943
|
+
this.isLoading = true;
|
|
16944
|
+
const loadingEl = this.overlayEl?.querySelector("#plm-loading");
|
|
16945
|
+
const gridEl = this.overlayEl?.querySelector("#plm-grid");
|
|
16946
|
+
if (loadingEl) loadingEl.style.display = "flex";
|
|
16947
|
+
if (gridEl) gridEl.style.opacity = "0.5";
|
|
16948
|
+
}
|
|
16949
|
+
hideLoading() {
|
|
16950
|
+
this.isLoading = false;
|
|
16951
|
+
const loadingEl = this.overlayEl?.querySelector("#plm-loading");
|
|
16952
|
+
const gridEl = this.overlayEl?.querySelector("#plm-grid");
|
|
16953
|
+
if (loadingEl) loadingEl.style.display = "none";
|
|
16954
|
+
if (gridEl) gridEl.style.opacity = "1";
|
|
16955
|
+
}
|
|
16956
|
+
showSaveLoading(show) {
|
|
16957
|
+
const saveBtn = this.overlayEl?.querySelector("#plm-save-btn");
|
|
16958
|
+
const btnText = saveBtn?.querySelector(".myio-btn-text");
|
|
16959
|
+
const btnSpinner = saveBtn?.querySelector(".myio-btn-spinner");
|
|
16960
|
+
if (saveBtn) saveBtn.disabled = show;
|
|
16961
|
+
if (btnText) btnText.style.display = show ? "none" : "inline";
|
|
16962
|
+
if (btnSpinner) btnSpinner.style.display = show ? "inline-block" : "none";
|
|
16963
|
+
}
|
|
16964
|
+
showError(message) {
|
|
16965
|
+
const errorEl = this.overlayEl?.querySelector("#plm-error");
|
|
16966
|
+
const errorMsg = this.overlayEl?.querySelector("#plm-error-msg");
|
|
16967
|
+
if (errorEl) errorEl.style.display = "flex";
|
|
16968
|
+
if (errorMsg) errorMsg.textContent = message;
|
|
16969
|
+
}
|
|
16970
|
+
hideError() {
|
|
16971
|
+
const errorEl = this.overlayEl?.querySelector("#plm-error");
|
|
16972
|
+
if (errorEl) errorEl.style.display = "none";
|
|
16973
|
+
}
|
|
16974
|
+
showSuccess() {
|
|
16975
|
+
const successEl = this.overlayEl?.querySelector("#plm-success");
|
|
16976
|
+
if (successEl) successEl.style.display = "flex";
|
|
16977
|
+
}
|
|
16978
|
+
hideSuccess() {
|
|
16979
|
+
const successEl = this.overlayEl?.querySelector("#plm-success");
|
|
16980
|
+
if (successEl) successEl.style.display = "none";
|
|
16981
|
+
}
|
|
16982
|
+
getFormData() {
|
|
16983
|
+
return { ...this.formData };
|
|
16984
|
+
}
|
|
16985
|
+
setFormData(data) {
|
|
16986
|
+
if (data.deviceType) this.formData.deviceType = data.deviceType;
|
|
16987
|
+
if (data.telemetryType) this.formData.telemetryType = data.telemetryType;
|
|
16988
|
+
if (data.standby) this.formData.standby = { ...data.standby };
|
|
16989
|
+
if (data.normal) this.formData.normal = { ...data.normal };
|
|
16990
|
+
if (data.alert) this.formData.alert = { ...data.alert };
|
|
16991
|
+
if (data.failure) this.formData.failure = { ...data.failure };
|
|
16992
|
+
this.updateInputValues();
|
|
16993
|
+
}
|
|
16994
|
+
updateInputValues() {
|
|
16995
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
16996
|
+
statuses.forEach((status) => {
|
|
16997
|
+
const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
|
|
16998
|
+
const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
|
|
16999
|
+
if (baseInput) {
|
|
17000
|
+
baseInput.value = this.formData[status].baseValue?.toString() ?? "";
|
|
17001
|
+
}
|
|
17002
|
+
if (topInput) {
|
|
17003
|
+
topInput.value = this.formData[status].topValue?.toString() ?? "";
|
|
17004
|
+
}
|
|
17005
|
+
});
|
|
17006
|
+
const deviceSelect = this.overlayEl?.querySelector("#plm-device-type");
|
|
17007
|
+
const telemetrySelect = this.overlayEl?.querySelector("#plm-telemetry-type");
|
|
17008
|
+
if (deviceSelect) deviceSelect.value = this.formData.deviceType;
|
|
17009
|
+
if (telemetrySelect) telemetrySelect.value = this.formData.telemetryType;
|
|
17010
|
+
}
|
|
17011
|
+
getStyles() {
|
|
17012
|
+
const styles = this.config.styles || {};
|
|
17013
|
+
const primaryColor = styles.primaryColor || "#4A148C";
|
|
17014
|
+
const successColor = styles.successColor || "#22c55e";
|
|
17015
|
+
const warningColor = styles.warningColor || "#f59e0b";
|
|
17016
|
+
const dangerColor = styles.dangerColor || "#ef4444";
|
|
17017
|
+
const infoColor = styles.infoColor || "#3b82f6";
|
|
17018
|
+
return `
|
|
17019
|
+
.myio-power-limits-overlay {
|
|
17020
|
+
position: fixed;
|
|
17021
|
+
top: 0;
|
|
17022
|
+
left: 0;
|
|
17023
|
+
right: 0;
|
|
17024
|
+
bottom: 0;
|
|
17025
|
+
background: rgba(0, 0, 0, 0.6);
|
|
17026
|
+
display: flex;
|
|
17027
|
+
align-items: center;
|
|
17028
|
+
justify-content: center;
|
|
17029
|
+
z-index: ${styles.zIndex || 1e4};
|
|
17030
|
+
opacity: 0;
|
|
17031
|
+
visibility: hidden;
|
|
17032
|
+
transition: all 0.3s ease;
|
|
17033
|
+
font-family: ${styles.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'};
|
|
17034
|
+
}
|
|
17035
|
+
|
|
17036
|
+
.myio-power-limits-overlay.active {
|
|
17037
|
+
opacity: 1;
|
|
17038
|
+
visibility: visible;
|
|
17039
|
+
}
|
|
17040
|
+
|
|
17041
|
+
.myio-power-limits-card {
|
|
17042
|
+
background: ${styles.backgroundColor || "#ffffff"};
|
|
17043
|
+
border-radius: ${styles.borderRadius || "12px"};
|
|
17044
|
+
width: 90%;
|
|
17045
|
+
max-width: 700px;
|
|
17046
|
+
max-height: 90vh;
|
|
17047
|
+
overflow-y: auto;
|
|
17048
|
+
transform: scale(0.9);
|
|
17049
|
+
transition: transform 0.3s ease;
|
|
17050
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
17051
|
+
}
|
|
17052
|
+
|
|
17053
|
+
.myio-power-limits-overlay.active .myio-power-limits-card {
|
|
17054
|
+
transform: scale(1);
|
|
17055
|
+
}
|
|
17056
|
+
|
|
17057
|
+
.myio-power-limits-header {
|
|
17058
|
+
display: flex;
|
|
17059
|
+
align-items: center;
|
|
17060
|
+
justify-content: space-between;
|
|
17061
|
+
padding: 20px 24px;
|
|
17062
|
+
background: linear-gradient(135deg, ${primaryColor}, ${this.lightenColor(primaryColor, 20)});
|
|
17063
|
+
color: white;
|
|
17064
|
+
border-radius: 12px 12px 0 0;
|
|
17065
|
+
}
|
|
17066
|
+
|
|
17067
|
+
.myio-power-limits-title-section {
|
|
17068
|
+
display: flex;
|
|
17069
|
+
align-items: center;
|
|
17070
|
+
gap: 12px;
|
|
17071
|
+
}
|
|
17072
|
+
|
|
17073
|
+
.myio-power-limits-icon {
|
|
17074
|
+
font-size: 24px;
|
|
17075
|
+
}
|
|
17076
|
+
|
|
17077
|
+
.myio-power-limits-title {
|
|
17078
|
+
font-size: 1.25rem;
|
|
17079
|
+
font-weight: 600;
|
|
17080
|
+
margin: 0;
|
|
17081
|
+
}
|
|
17082
|
+
|
|
17083
|
+
.myio-power-limits-actions {
|
|
17084
|
+
display: flex;
|
|
17085
|
+
align-items: center;
|
|
17086
|
+
gap: 8px;
|
|
17087
|
+
}
|
|
17088
|
+
|
|
17089
|
+
.myio-btn {
|
|
17090
|
+
padding: 8px 16px;
|
|
17091
|
+
border-radius: ${styles.buttonRadius || "6px"};
|
|
17092
|
+
font-size: 14px;
|
|
17093
|
+
font-weight: 500;
|
|
17094
|
+
cursor: pointer;
|
|
17095
|
+
border: none;
|
|
17096
|
+
transition: all 0.2s;
|
|
17097
|
+
display: inline-flex;
|
|
17098
|
+
align-items: center;
|
|
17099
|
+
gap: 6px;
|
|
17100
|
+
}
|
|
17101
|
+
|
|
17102
|
+
.myio-btn:disabled {
|
|
17103
|
+
opacity: 0.6;
|
|
17104
|
+
cursor: not-allowed;
|
|
17105
|
+
}
|
|
17106
|
+
|
|
17107
|
+
.myio-btn-primary {
|
|
17108
|
+
background: white;
|
|
17109
|
+
color: ${primaryColor};
|
|
17110
|
+
}
|
|
17111
|
+
|
|
17112
|
+
.myio-btn-primary:hover:not(:disabled) {
|
|
17113
|
+
background: #f3f4f6;
|
|
17114
|
+
}
|
|
17115
|
+
|
|
17116
|
+
.myio-btn-secondary {
|
|
17117
|
+
background: rgba(255, 255, 255, 0.2);
|
|
17118
|
+
color: white;
|
|
17119
|
+
}
|
|
17120
|
+
|
|
17121
|
+
.myio-btn-secondary:hover:not(:disabled) {
|
|
17122
|
+
background: rgba(255, 255, 255, 0.3);
|
|
17123
|
+
}
|
|
17124
|
+
|
|
17125
|
+
.myio-btn-close {
|
|
17126
|
+
background: transparent;
|
|
17127
|
+
color: white;
|
|
17128
|
+
font-size: 24px;
|
|
17129
|
+
padding: 4px 8px;
|
|
17130
|
+
line-height: 1;
|
|
17131
|
+
}
|
|
17132
|
+
|
|
17133
|
+
.myio-btn-close:hover {
|
|
17134
|
+
background: rgba(255, 255, 255, 0.1);
|
|
17135
|
+
}
|
|
17136
|
+
|
|
17137
|
+
.myio-btn-spinner {
|
|
17138
|
+
width: 16px;
|
|
17139
|
+
height: 16px;
|
|
17140
|
+
border: 2px solid ${primaryColor};
|
|
17141
|
+
border-top-color: transparent;
|
|
17142
|
+
border-radius: 50%;
|
|
17143
|
+
animation: spin 0.8s linear infinite;
|
|
17144
|
+
}
|
|
17145
|
+
|
|
17146
|
+
@keyframes spin {
|
|
17147
|
+
to { transform: rotate(360deg); }
|
|
17148
|
+
}
|
|
17149
|
+
|
|
17150
|
+
.myio-power-limits-selectors {
|
|
17151
|
+
display: grid;
|
|
17152
|
+
grid-template-columns: 1fr 1fr;
|
|
17153
|
+
gap: 16px;
|
|
17154
|
+
padding: 20px 24px;
|
|
17155
|
+
background: #f9fafb;
|
|
17156
|
+
border-bottom: 1px solid #e5e7eb;
|
|
17157
|
+
}
|
|
17158
|
+
|
|
17159
|
+
.myio-form-group {
|
|
17160
|
+
display: flex;
|
|
17161
|
+
flex-direction: column;
|
|
17162
|
+
gap: 6px;
|
|
17163
|
+
}
|
|
17164
|
+
|
|
17165
|
+
.myio-form-group label {
|
|
17166
|
+
font-size: 13px;
|
|
17167
|
+
font-weight: 500;
|
|
17168
|
+
color: #374151;
|
|
17169
|
+
}
|
|
17170
|
+
|
|
17171
|
+
.myio-select, .myio-input {
|
|
17172
|
+
padding: 10px 12px;
|
|
17173
|
+
border: 1px solid #d1d5db;
|
|
17174
|
+
border-radius: 6px;
|
|
17175
|
+
font-size: 14px;
|
|
17176
|
+
background: white;
|
|
17177
|
+
color: #1f2937;
|
|
17178
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
17179
|
+
}
|
|
17180
|
+
|
|
17181
|
+
.myio-select:focus, .myio-input:focus {
|
|
17182
|
+
outline: none;
|
|
17183
|
+
border-color: ${primaryColor};
|
|
17184
|
+
box-shadow: 0 0 0 3px ${this.hexToRgba(primaryColor, 0.1)};
|
|
17185
|
+
}
|
|
17186
|
+
|
|
17187
|
+
.myio-power-limits-grid {
|
|
17188
|
+
display: grid;
|
|
17189
|
+
grid-template-columns: repeat(2, 1fr);
|
|
17190
|
+
gap: 16px;
|
|
17191
|
+
padding: 24px;
|
|
17192
|
+
transition: opacity 0.3s;
|
|
17193
|
+
}
|
|
17194
|
+
|
|
17195
|
+
.myio-power-limits-card-item {
|
|
17196
|
+
background: var(--status-bg);
|
|
17197
|
+
border: 1px solid var(--status-color);
|
|
17198
|
+
border-radius: 8px;
|
|
17199
|
+
padding: 16px;
|
|
17200
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
17201
|
+
}
|
|
17202
|
+
|
|
17203
|
+
.myio-power-limits-card-item:hover {
|
|
17204
|
+
transform: translateY(-2px);
|
|
17205
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
17206
|
+
}
|
|
17207
|
+
|
|
17208
|
+
.myio-card-header {
|
|
17209
|
+
display: flex;
|
|
17210
|
+
align-items: center;
|
|
17211
|
+
gap: 8px;
|
|
17212
|
+
margin-bottom: 12px;
|
|
17213
|
+
}
|
|
17214
|
+
|
|
17215
|
+
.myio-status-indicator {
|
|
17216
|
+
width: 12px;
|
|
17217
|
+
height: 12px;
|
|
17218
|
+
border-radius: 50%;
|
|
17219
|
+
background: var(--status-color);
|
|
17220
|
+
}
|
|
17221
|
+
|
|
17222
|
+
.myio-status-label {
|
|
17223
|
+
font-weight: 600;
|
|
17224
|
+
font-size: 14px;
|
|
17225
|
+
color: #1f2937;
|
|
17226
|
+
}
|
|
17227
|
+
|
|
17228
|
+
.myio-card-inputs {
|
|
17229
|
+
display: grid;
|
|
17230
|
+
grid-template-columns: 1fr 1fr;
|
|
17231
|
+
gap: 12px;
|
|
17232
|
+
}
|
|
17233
|
+
|
|
17234
|
+
.myio-input-group {
|
|
17235
|
+
display: flex;
|
|
17236
|
+
flex-direction: column;
|
|
17237
|
+
gap: 4px;
|
|
17238
|
+
}
|
|
17239
|
+
|
|
17240
|
+
.myio-input-group label {
|
|
17241
|
+
font-size: 11px;
|
|
17242
|
+
font-weight: 500;
|
|
17243
|
+
color: #6b7280;
|
|
17244
|
+
text-transform: uppercase;
|
|
17245
|
+
}
|
|
17246
|
+
|
|
17247
|
+
.myio-power-limits-loading,
|
|
17248
|
+
.myio-power-limits-error,
|
|
17249
|
+
.myio-power-limits-success {
|
|
17250
|
+
display: flex;
|
|
17251
|
+
align-items: center;
|
|
17252
|
+
justify-content: center;
|
|
17253
|
+
gap: 12px;
|
|
17254
|
+
padding: 16px 24px;
|
|
17255
|
+
margin: 0 24px 24px;
|
|
17256
|
+
border-radius: 8px;
|
|
17257
|
+
}
|
|
17258
|
+
|
|
17259
|
+
.myio-power-limits-loading {
|
|
17260
|
+
background: #f3f4f6;
|
|
17261
|
+
color: #6b7280;
|
|
17262
|
+
}
|
|
17263
|
+
|
|
17264
|
+
.myio-power-limits-error {
|
|
17265
|
+
background: #fef2f2;
|
|
17266
|
+
color: ${dangerColor};
|
|
17267
|
+
border: 1px solid ${dangerColor};
|
|
17268
|
+
}
|
|
17269
|
+
|
|
17270
|
+
.myio-power-limits-success {
|
|
17271
|
+
background: #f0fdf4;
|
|
17272
|
+
color: ${successColor};
|
|
17273
|
+
border: 1px solid ${successColor};
|
|
17274
|
+
}
|
|
17275
|
+
|
|
17276
|
+
.myio-spinner {
|
|
17277
|
+
width: 24px;
|
|
17278
|
+
height: 24px;
|
|
17279
|
+
border: 3px solid #e5e7eb;
|
|
17280
|
+
border-top-color: ${primaryColor};
|
|
17281
|
+
border-radius: 50%;
|
|
17282
|
+
animation: spin 0.8s linear infinite;
|
|
17283
|
+
}
|
|
17284
|
+
|
|
17285
|
+
.myio-error-icon, .myio-success-icon {
|
|
17286
|
+
font-size: 20px;
|
|
17287
|
+
}
|
|
17288
|
+
|
|
17289
|
+
@media (max-width: 600px) {
|
|
17290
|
+
.myio-power-limits-selectors,
|
|
17291
|
+
.myio-power-limits-grid {
|
|
17292
|
+
grid-template-columns: 1fr;
|
|
17293
|
+
}
|
|
17294
|
+
|
|
17295
|
+
.myio-power-limits-header {
|
|
17296
|
+
flex-direction: column;
|
|
17297
|
+
gap: 12px;
|
|
17298
|
+
text-align: center;
|
|
17299
|
+
}
|
|
17300
|
+
|
|
17301
|
+
.myio-power-limits-actions {
|
|
17302
|
+
width: 100%;
|
|
17303
|
+
justify-content: center;
|
|
17304
|
+
}
|
|
17305
|
+
}
|
|
17306
|
+
`;
|
|
17307
|
+
}
|
|
17308
|
+
lightenColor(hex, percent) {
|
|
17309
|
+
const num = parseInt(hex.replace("#", ""), 16);
|
|
17310
|
+
const amt = Math.round(2.55 * percent);
|
|
17311
|
+
const R = (num >> 16) + amt;
|
|
17312
|
+
const G = (num >> 8 & 255) + amt;
|
|
17313
|
+
const B = (num & 255) + amt;
|
|
17314
|
+
return "#" + (16777216 + (R < 255 ? R < 1 ? 0 : R : 255) * 65536 + (G < 255 ? G < 1 ? 0 : G : 255) * 256 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
|
|
17315
|
+
}
|
|
17316
|
+
hexToRgba(hex, alpha) {
|
|
17317
|
+
const num = parseInt(hex.replace("#", ""), 16);
|
|
17318
|
+
const R = num >> 16;
|
|
17319
|
+
const G = num >> 8 & 255;
|
|
17320
|
+
const B = num & 255;
|
|
17321
|
+
return `rgba(${R}, ${G}, ${B}, ${alpha})`;
|
|
17322
|
+
}
|
|
17323
|
+
};
|
|
17324
|
+
|
|
17325
|
+
// src/components/premium-modals/power-limits/PowerLimitsPersister.ts
|
|
17326
|
+
var PowerLimitsPersister = class {
|
|
17327
|
+
jwtToken;
|
|
17328
|
+
tbBaseUrl;
|
|
17329
|
+
constructor(jwtToken, tbBaseUrl) {
|
|
17330
|
+
this.jwtToken = jwtToken;
|
|
17331
|
+
this.tbBaseUrl = tbBaseUrl || window.location.origin;
|
|
17332
|
+
}
|
|
17333
|
+
/**
|
|
17334
|
+
* Load existing mapInstantaneousPower from customer server_scope attributes
|
|
17335
|
+
*/
|
|
17336
|
+
async loadCustomerPowerLimits(customerId) {
|
|
17337
|
+
try {
|
|
17338
|
+
const url = `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/values/attributes/SERVER_SCOPE?keys=mapInstantaneousPower`;
|
|
17339
|
+
const response = await fetch(url, {
|
|
17340
|
+
method: "GET",
|
|
17341
|
+
headers: {
|
|
17342
|
+
"X-Authorization": `Bearer ${this.jwtToken}`,
|
|
17343
|
+
"Content-Type": "application/json"
|
|
17344
|
+
}
|
|
17345
|
+
});
|
|
17346
|
+
if (!response.ok) {
|
|
17347
|
+
if (response.status === 404) {
|
|
17348
|
+
console.log("[PowerLimitsPersister] No existing mapInstantaneousPower found");
|
|
17349
|
+
return null;
|
|
17350
|
+
}
|
|
17351
|
+
throw this.createHttpError(response.status, await response.text().catch(() => ""));
|
|
17352
|
+
}
|
|
17353
|
+
const data = await response.json();
|
|
17354
|
+
if (!data || data.length === 0) {
|
|
17355
|
+
console.log("[PowerLimitsPersister] No mapInstantaneousPower attribute found");
|
|
17356
|
+
return null;
|
|
17357
|
+
}
|
|
17358
|
+
const attr = data.find((item) => item.key === "mapInstantaneousPower");
|
|
17359
|
+
if (!attr || !attr.value) {
|
|
17360
|
+
return null;
|
|
17361
|
+
}
|
|
17362
|
+
const parsedValue = typeof attr.value === "string" ? JSON.parse(attr.value) : attr.value;
|
|
17363
|
+
console.log("[PowerLimitsPersister] Loaded mapInstantaneousPower:", parsedValue);
|
|
17364
|
+
return parsedValue;
|
|
17365
|
+
} catch (error) {
|
|
17366
|
+
console.error("[PowerLimitsPersister] Error loading power limits:", error);
|
|
17367
|
+
throw this.mapError(error);
|
|
17368
|
+
}
|
|
17369
|
+
}
|
|
17370
|
+
/**
|
|
17371
|
+
* Save mapInstantaneousPower to customer server_scope attributes
|
|
17372
|
+
*/
|
|
17373
|
+
async saveCustomerPowerLimits(customerId, limits) {
|
|
17374
|
+
try {
|
|
17375
|
+
const url = `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/attributes/SERVER_SCOPE`;
|
|
17376
|
+
const payload = {
|
|
17377
|
+
mapInstantaneousPower: limits
|
|
17378
|
+
};
|
|
17379
|
+
console.log("[PowerLimitsPersister] Saving power limits:", payload);
|
|
17380
|
+
const response = await fetch(url, {
|
|
17381
|
+
method: "POST",
|
|
17382
|
+
headers: {
|
|
17383
|
+
"X-Authorization": `Bearer ${this.jwtToken}`,
|
|
17384
|
+
"Content-Type": "application/json"
|
|
17385
|
+
},
|
|
17386
|
+
body: JSON.stringify(payload)
|
|
17387
|
+
});
|
|
17388
|
+
if (!response.ok) {
|
|
17389
|
+
throw this.createHttpError(response.status, await response.text().catch(() => ""));
|
|
17390
|
+
}
|
|
17391
|
+
console.log("[PowerLimitsPersister] Successfully saved power limits");
|
|
17392
|
+
return { ok: true };
|
|
17393
|
+
} catch (error) {
|
|
17394
|
+
console.error("[PowerLimitsPersister] Error saving power limits:", error);
|
|
17395
|
+
return { ok: false, error: this.mapError(error) };
|
|
17396
|
+
}
|
|
17397
|
+
}
|
|
17398
|
+
/**
|
|
17399
|
+
* Extract form data for a specific device type and telemetry type
|
|
17400
|
+
*/
|
|
17401
|
+
extractFormData(limits, deviceType, telemetryType) {
|
|
17402
|
+
const defaultFormData = {
|
|
17403
|
+
deviceType,
|
|
17404
|
+
telemetryType,
|
|
17405
|
+
standby: { baseValue: null, topValue: null },
|
|
17406
|
+
normal: { baseValue: null, topValue: null },
|
|
17407
|
+
alert: { baseValue: null, topValue: null },
|
|
17408
|
+
failure: { baseValue: null, topValue: null }
|
|
17409
|
+
};
|
|
17410
|
+
if (!limits || !limits.limitsByInstantaneoustPowerType) {
|
|
17411
|
+
return defaultFormData;
|
|
17412
|
+
}
|
|
17413
|
+
const telemetryEntry = limits.limitsByInstantaneoustPowerType.find(
|
|
17414
|
+
(t) => t.telemetryType === telemetryType
|
|
17415
|
+
);
|
|
17416
|
+
if (!telemetryEntry || !telemetryEntry.itemsByDeviceType) {
|
|
17417
|
+
return defaultFormData;
|
|
17418
|
+
}
|
|
17419
|
+
const deviceEntry = telemetryEntry.itemsByDeviceType.find(
|
|
17420
|
+
(d) => d.deviceType === deviceType
|
|
17421
|
+
);
|
|
17422
|
+
if (!deviceEntry || !deviceEntry.limitsByDeviceStatus) {
|
|
17423
|
+
return defaultFormData;
|
|
17424
|
+
}
|
|
17425
|
+
const statusMap = {
|
|
17426
|
+
"standBy": "standby",
|
|
17427
|
+
"normal": "normal",
|
|
17428
|
+
"alert": "alert",
|
|
17429
|
+
"failure": "failure"
|
|
17430
|
+
};
|
|
17431
|
+
deviceEntry.limitsByDeviceStatus.forEach((status) => {
|
|
17432
|
+
const formKey = statusMap[status.deviceStatusName];
|
|
17433
|
+
if (formKey && defaultFormData[formKey]) {
|
|
17434
|
+
defaultFormData[formKey] = {
|
|
17435
|
+
baseValue: status.limitsValues.baseValue,
|
|
17436
|
+
topValue: status.limitsValues.topValue
|
|
17437
|
+
};
|
|
17438
|
+
}
|
|
17439
|
+
});
|
|
17440
|
+
return defaultFormData;
|
|
17441
|
+
}
|
|
17442
|
+
/**
|
|
17443
|
+
* Merge form data into existing limits JSON
|
|
17444
|
+
* Creates new entries if they don't exist
|
|
17445
|
+
*/
|
|
17446
|
+
mergeFormDataIntoLimits(existingLimits, formData) {
|
|
17447
|
+
const result = existingLimits ? JSON.parse(JSON.stringify(existingLimits)) : { version: "1.0.0", limitsByInstantaneoustPowerType: [] };
|
|
17448
|
+
const statusLimits = [
|
|
17449
|
+
{
|
|
17450
|
+
deviceStatusName: "standBy",
|
|
17451
|
+
limitsValues: {
|
|
17452
|
+
baseValue: formData.standby.baseValue ?? 0,
|
|
17453
|
+
topValue: formData.standby.topValue ?? 0
|
|
17454
|
+
}
|
|
17455
|
+
},
|
|
17456
|
+
{
|
|
17457
|
+
deviceStatusName: "normal",
|
|
17458
|
+
limitsValues: {
|
|
17459
|
+
baseValue: formData.normal.baseValue ?? 0,
|
|
17460
|
+
topValue: formData.normal.topValue ?? 0
|
|
17461
|
+
}
|
|
17462
|
+
},
|
|
17463
|
+
{
|
|
17464
|
+
deviceStatusName: "alert",
|
|
17465
|
+
limitsValues: {
|
|
17466
|
+
baseValue: formData.alert.baseValue ?? 0,
|
|
17467
|
+
topValue: formData.alert.topValue ?? 0
|
|
17468
|
+
}
|
|
17469
|
+
},
|
|
17470
|
+
{
|
|
17471
|
+
deviceStatusName: "failure",
|
|
17472
|
+
limitsValues: {
|
|
17473
|
+
baseValue: formData.failure.baseValue ?? 0,
|
|
17474
|
+
topValue: formData.failure.topValue ?? 0
|
|
17475
|
+
}
|
|
17476
|
+
}
|
|
17477
|
+
];
|
|
17478
|
+
let telemetryEntry = result.limitsByInstantaneoustPowerType.find(
|
|
17479
|
+
(t) => t.telemetryType === formData.telemetryType
|
|
17480
|
+
);
|
|
17481
|
+
if (!telemetryEntry) {
|
|
17482
|
+
telemetryEntry = {
|
|
17483
|
+
telemetryType: formData.telemetryType,
|
|
17484
|
+
itemsByDeviceType: []
|
|
17485
|
+
};
|
|
17486
|
+
result.limitsByInstantaneoustPowerType.push(telemetryEntry);
|
|
17487
|
+
}
|
|
17488
|
+
let deviceEntry = telemetryEntry.itemsByDeviceType.find(
|
|
17489
|
+
(d) => d.deviceType === formData.deviceType
|
|
17490
|
+
);
|
|
17491
|
+
if (!deviceEntry) {
|
|
17492
|
+
deviceEntry = {
|
|
17493
|
+
deviceType: formData.deviceType,
|
|
17494
|
+
name: `mapInstantaneousPower${this.formatDeviceTypeName(formData.deviceType)}`,
|
|
17495
|
+
description: `Power limits for ${formData.deviceType}`,
|
|
17496
|
+
limitsByDeviceStatus: []
|
|
17497
|
+
};
|
|
17498
|
+
telemetryEntry.itemsByDeviceType.push(deviceEntry);
|
|
17499
|
+
}
|
|
17500
|
+
deviceEntry.limitsByDeviceStatus = statusLimits;
|
|
17501
|
+
deviceEntry.name = `mapInstantaneousPower${this.formatDeviceTypeName(formData.deviceType)}`;
|
|
17502
|
+
deviceEntry.description = `Power limits for ${formData.deviceType} - ${formData.telemetryType}`;
|
|
17503
|
+
return result;
|
|
17504
|
+
}
|
|
17505
|
+
/**
|
|
17506
|
+
* Format device type name for the JSON name field
|
|
17507
|
+
*/
|
|
17508
|
+
formatDeviceTypeName(deviceType) {
|
|
17509
|
+
if (!deviceType) return "";
|
|
17510
|
+
return deviceType.toLowerCase().split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
17511
|
+
}
|
|
17512
|
+
createHttpError(status, body) {
|
|
17513
|
+
const error = new Error(`HTTP ${status}: ${body}`);
|
|
17514
|
+
error.status = status;
|
|
17515
|
+
error.body = body;
|
|
17516
|
+
return error;
|
|
17517
|
+
}
|
|
17518
|
+
mapError(error) {
|
|
17519
|
+
const status = error.status;
|
|
17520
|
+
if (status === 400) {
|
|
17521
|
+
return {
|
|
17522
|
+
code: "VALIDATION_ERROR",
|
|
17523
|
+
message: "Invalid input data",
|
|
17524
|
+
cause: error
|
|
17525
|
+
};
|
|
17526
|
+
}
|
|
17527
|
+
if (status === 401) {
|
|
17528
|
+
return {
|
|
17529
|
+
code: "TOKEN_EXPIRED",
|
|
17530
|
+
message: "Authentication token has expired",
|
|
17531
|
+
cause: error
|
|
17532
|
+
};
|
|
17533
|
+
}
|
|
17534
|
+
if (status === 403) {
|
|
17535
|
+
return {
|
|
17536
|
+
code: "AUTH_ERROR",
|
|
17537
|
+
message: "Insufficient permissions",
|
|
17538
|
+
cause: error
|
|
17539
|
+
};
|
|
17540
|
+
}
|
|
17541
|
+
if (status === 404) {
|
|
17542
|
+
return {
|
|
17543
|
+
code: "NETWORK_ERROR",
|
|
17544
|
+
message: "Customer not found",
|
|
17545
|
+
cause: error
|
|
17546
|
+
};
|
|
17547
|
+
}
|
|
17548
|
+
if (status >= 500) {
|
|
17549
|
+
return {
|
|
17550
|
+
code: "NETWORK_ERROR",
|
|
17551
|
+
message: "Server error occurred",
|
|
17552
|
+
cause: error
|
|
17553
|
+
};
|
|
15848
17554
|
}
|
|
17555
|
+
return {
|
|
17556
|
+
code: "UNKNOWN_ERROR",
|
|
17557
|
+
message: error.message || "Unknown error occurred",
|
|
17558
|
+
cause: error
|
|
17559
|
+
};
|
|
15849
17560
|
}
|
|
15850
|
-
|
|
15851
|
-
|
|
15852
|
-
|
|
15853
|
-
|
|
17561
|
+
};
|
|
17562
|
+
|
|
17563
|
+
// src/components/premium-modals/power-limits/openPowerLimitsSetupModal.ts
|
|
17564
|
+
async function openPowerLimitsSetupModal(params) {
|
|
17565
|
+
if (!params.token) {
|
|
17566
|
+
throw new Error("[PowerLimitsSetupModal] token is required");
|
|
17567
|
+
}
|
|
17568
|
+
if (!params.customerId) {
|
|
17569
|
+
throw new Error("[PowerLimitsSetupModal] customerId is required");
|
|
17570
|
+
}
|
|
17571
|
+
const persister = new PowerLimitsPersister(params.token, params.tbBaseUrl);
|
|
17572
|
+
let currentDeviceType = params.deviceType || "ELEVADOR";
|
|
17573
|
+
let currentTelemetryType = params.telemetryType || "consumption";
|
|
17574
|
+
let existingLimits = params.existingMapPower || null;
|
|
17575
|
+
const view = new PowerLimitsModalView({
|
|
17576
|
+
deviceType: currentDeviceType,
|
|
17577
|
+
telemetryType: currentTelemetryType,
|
|
17578
|
+
styles: params.styles,
|
|
17579
|
+
locale: params.locale,
|
|
17580
|
+
onDeviceTypeChange: async (deviceType) => {
|
|
17581
|
+
currentDeviceType = deviceType;
|
|
17582
|
+
await loadFormData();
|
|
17583
|
+
},
|
|
17584
|
+
onTelemetryTypeChange: async (telemetryType) => {
|
|
17585
|
+
currentTelemetryType = telemetryType;
|
|
17586
|
+
await loadFormData();
|
|
17587
|
+
},
|
|
17588
|
+
onSave: async () => {
|
|
17589
|
+
const formData = view.getFormData();
|
|
17590
|
+
const updatedLimits = persister.mergeFormDataIntoLimits(existingLimits, formData);
|
|
17591
|
+
const result = await persister.saveCustomerPowerLimits(params.customerId, updatedLimits);
|
|
17592
|
+
if (!result.ok) {
|
|
17593
|
+
throw new Error(result.error?.message || "Failed to save configuration");
|
|
17594
|
+
}
|
|
17595
|
+
existingLimits = updatedLimits;
|
|
17596
|
+
if (params.onSave) {
|
|
17597
|
+
params.onSave(updatedLimits);
|
|
17598
|
+
}
|
|
17599
|
+
},
|
|
17600
|
+
onClose: () => {
|
|
17601
|
+
if (params.onClose) {
|
|
17602
|
+
params.onClose();
|
|
17603
|
+
}
|
|
17604
|
+
}
|
|
17605
|
+
});
|
|
17606
|
+
async function loadFormData() {
|
|
17607
|
+
view.showLoading();
|
|
17608
|
+
try {
|
|
17609
|
+
if (!existingLimits) {
|
|
17610
|
+
existingLimits = await persister.loadCustomerPowerLimits(params.customerId);
|
|
17611
|
+
}
|
|
17612
|
+
const formData = persister.extractFormData(existingLimits, currentDeviceType, currentTelemetryType);
|
|
17613
|
+
view.setFormData(formData);
|
|
17614
|
+
} catch (error) {
|
|
17615
|
+
console.error("[PowerLimitsSetupModal] Error loading form data:", error);
|
|
17616
|
+
view.showError(error.message || "Failed to load configuration");
|
|
17617
|
+
} finally {
|
|
17618
|
+
view.hideLoading();
|
|
15854
17619
|
}
|
|
15855
17620
|
}
|
|
15856
|
-
|
|
15857
|
-
|
|
15858
|
-
|
|
17621
|
+
let container;
|
|
17622
|
+
if (params.container) {
|
|
17623
|
+
if (typeof params.container === "string") {
|
|
17624
|
+
container = document.querySelector(params.container);
|
|
17625
|
+
} else {
|
|
17626
|
+
container = params.container;
|
|
17627
|
+
}
|
|
15859
17628
|
}
|
|
17629
|
+
view.render(container);
|
|
17630
|
+
await loadFormData();
|
|
17631
|
+
return {
|
|
17632
|
+
destroy: () => view.destroy(),
|
|
17633
|
+
getFormData: () => view.getFormData(),
|
|
17634
|
+
setFormData: (data) => view.setFormData(data)
|
|
17635
|
+
};
|
|
15860
17636
|
}
|
|
15861
17637
|
|
|
15862
17638
|
// src/components/premium-modals/settings/SettingsModalView.ts
|
|
@@ -20227,220 +22003,6 @@ function openGoalsPanel(params) {
|
|
|
20227
22003
|
}
|
|
20228
22004
|
}
|
|
20229
22005
|
|
|
20230
|
-
// src/components/temperature/utils.ts
|
|
20231
|
-
var DAY_PERIODS = [
|
|
20232
|
-
{ id: "madrugada", label: "Madrugada (00h-06h)", startHour: 0, endHour: 6 },
|
|
20233
|
-
{ id: "manha", label: "Manh\xE3 (06h-12h)", startHour: 6, endHour: 12 },
|
|
20234
|
-
{ id: "tarde", label: "Tarde (12h-18h)", startHour: 12, endHour: 18 },
|
|
20235
|
-
{ id: "noite", label: "Noite (18h-24h)", startHour: 18, endHour: 24 }
|
|
20236
|
-
];
|
|
20237
|
-
var DEFAULT_CLAMP_RANGE = { min: 15, max: 40 };
|
|
20238
|
-
function getTodaySoFar() {
|
|
20239
|
-
const now = /* @__PURE__ */ new Date();
|
|
20240
|
-
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
|
|
20241
|
-
return {
|
|
20242
|
-
startTs: startOfDay.getTime(),
|
|
20243
|
-
endTs: now.getTime()
|
|
20244
|
-
};
|
|
20245
|
-
}
|
|
20246
|
-
var CHART_COLORS = [
|
|
20247
|
-
"#1976d2",
|
|
20248
|
-
// Blue
|
|
20249
|
-
"#FF6B6B",
|
|
20250
|
-
// Red
|
|
20251
|
-
"#4CAF50",
|
|
20252
|
-
// Green
|
|
20253
|
-
"#FF9800",
|
|
20254
|
-
// Orange
|
|
20255
|
-
"#9C27B0",
|
|
20256
|
-
// Purple
|
|
20257
|
-
"#00BCD4",
|
|
20258
|
-
// Cyan
|
|
20259
|
-
"#E91E63",
|
|
20260
|
-
// Pink
|
|
20261
|
-
"#795548"
|
|
20262
|
-
// Brown
|
|
20263
|
-
];
|
|
20264
|
-
async function fetchTemperatureData(token, deviceId, startTs, endTs) {
|
|
20265
|
-
const url = `/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=temperature&startTs=${encodeURIComponent(startTs)}&endTs=${encodeURIComponent(endTs)}&limit=50000&agg=NONE`;
|
|
20266
|
-
const response = await fetch(url, {
|
|
20267
|
-
headers: {
|
|
20268
|
-
"X-Authorization": `Bearer ${token}`,
|
|
20269
|
-
"Content-Type": "application/json"
|
|
20270
|
-
}
|
|
20271
|
-
});
|
|
20272
|
-
if (!response.ok) {
|
|
20273
|
-
throw new Error(`Failed to fetch temperature data: ${response.status}`);
|
|
20274
|
-
}
|
|
20275
|
-
const data = await response.json();
|
|
20276
|
-
return data?.temperature || [];
|
|
20277
|
-
}
|
|
20278
|
-
function clampTemperature(value, range = DEFAULT_CLAMP_RANGE) {
|
|
20279
|
-
const num = Number(value || 0);
|
|
20280
|
-
if (num < range.min) return range.min;
|
|
20281
|
-
if (num > range.max) return range.max;
|
|
20282
|
-
return num;
|
|
20283
|
-
}
|
|
20284
|
-
function calculateStats(data, clampRange = DEFAULT_CLAMP_RANGE) {
|
|
20285
|
-
if (data.length === 0) {
|
|
20286
|
-
return { avg: 0, min: 0, max: 0, count: 0 };
|
|
20287
|
-
}
|
|
20288
|
-
const values = data.map((item) => clampTemperature(item.value, clampRange));
|
|
20289
|
-
const sum = values.reduce((acc, v) => acc + v, 0);
|
|
20290
|
-
return {
|
|
20291
|
-
avg: sum / values.length,
|
|
20292
|
-
min: Math.min(...values),
|
|
20293
|
-
max: Math.max(...values),
|
|
20294
|
-
count: values.length
|
|
20295
|
-
};
|
|
20296
|
-
}
|
|
20297
|
-
function interpolateTemperature(data, options) {
|
|
20298
|
-
const { intervalMinutes, startTs, endTs, clampRange = DEFAULT_CLAMP_RANGE } = options;
|
|
20299
|
-
const intervalMs = intervalMinutes * 60 * 1e3;
|
|
20300
|
-
if (data.length === 0) {
|
|
20301
|
-
return [];
|
|
20302
|
-
}
|
|
20303
|
-
const sortedData = [...data].sort((a, b) => a.ts - b.ts);
|
|
20304
|
-
const result = [];
|
|
20305
|
-
let lastKnownValue = clampTemperature(sortedData[0].value, clampRange);
|
|
20306
|
-
let dataIndex = 0;
|
|
20307
|
-
for (let ts = startTs; ts <= endTs; ts += intervalMs) {
|
|
20308
|
-
while (dataIndex < sortedData.length - 1 && sortedData[dataIndex + 1].ts <= ts) {
|
|
20309
|
-
dataIndex++;
|
|
20310
|
-
}
|
|
20311
|
-
const currentData = sortedData[dataIndex];
|
|
20312
|
-
if (currentData && Math.abs(currentData.ts - ts) < intervalMs) {
|
|
20313
|
-
lastKnownValue = clampTemperature(currentData.value, clampRange);
|
|
20314
|
-
}
|
|
20315
|
-
result.push({
|
|
20316
|
-
ts,
|
|
20317
|
-
value: lastKnownValue
|
|
20318
|
-
});
|
|
20319
|
-
}
|
|
20320
|
-
return result;
|
|
20321
|
-
}
|
|
20322
|
-
function aggregateByDay(data, clampRange = DEFAULT_CLAMP_RANGE) {
|
|
20323
|
-
if (data.length === 0) {
|
|
20324
|
-
return [];
|
|
20325
|
-
}
|
|
20326
|
-
const dayMap = /* @__PURE__ */ new Map();
|
|
20327
|
-
data.forEach((item) => {
|
|
20328
|
-
const date = new Date(item.ts);
|
|
20329
|
-
const dateKey = date.toISOString().split("T")[0];
|
|
20330
|
-
if (!dayMap.has(dateKey)) {
|
|
20331
|
-
dayMap.set(dateKey, []);
|
|
20332
|
-
}
|
|
20333
|
-
dayMap.get(dateKey).push(item);
|
|
20334
|
-
});
|
|
20335
|
-
const result = [];
|
|
20336
|
-
dayMap.forEach((dayData, dateKey) => {
|
|
20337
|
-
const values = dayData.map((item) => clampTemperature(item.value, clampRange));
|
|
20338
|
-
const sum = values.reduce((acc, v) => acc + v, 0);
|
|
20339
|
-
result.push({
|
|
20340
|
-
date: dateKey,
|
|
20341
|
-
dateTs: new Date(dateKey).getTime(),
|
|
20342
|
-
avg: sum / values.length,
|
|
20343
|
-
min: Math.min(...values),
|
|
20344
|
-
max: Math.max(...values),
|
|
20345
|
-
count: values.length
|
|
20346
|
-
});
|
|
20347
|
-
});
|
|
20348
|
-
return result.sort((a, b) => a.dateTs - b.dateTs);
|
|
20349
|
-
}
|
|
20350
|
-
function filterByDayPeriods(data, selectedPeriods) {
|
|
20351
|
-
if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
|
|
20352
|
-
return data;
|
|
20353
|
-
}
|
|
20354
|
-
return data.filter((item) => {
|
|
20355
|
-
const date = new Date(item.ts);
|
|
20356
|
-
const hour = date.getHours();
|
|
20357
|
-
return selectedPeriods.some((periodId) => {
|
|
20358
|
-
const period = DAY_PERIODS.find((p) => p.id === periodId);
|
|
20359
|
-
if (!period) return false;
|
|
20360
|
-
return hour >= period.startHour && hour < period.endHour;
|
|
20361
|
-
});
|
|
20362
|
-
});
|
|
20363
|
-
}
|
|
20364
|
-
function getSelectedPeriodsLabel(selectedPeriods) {
|
|
20365
|
-
if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
|
|
20366
|
-
return "Todos os per\xEDodos";
|
|
20367
|
-
}
|
|
20368
|
-
if (selectedPeriods.length === 1) {
|
|
20369
|
-
const period = DAY_PERIODS.find((p) => p.id === selectedPeriods[0]);
|
|
20370
|
-
return period?.label || "";
|
|
20371
|
-
}
|
|
20372
|
-
return `${selectedPeriods.length} per\xEDodos selecionados`;
|
|
20373
|
-
}
|
|
20374
|
-
function formatTemperature2(value, decimals = 1) {
|
|
20375
|
-
return `${value.toFixed(decimals)}\xB0C`;
|
|
20376
|
-
}
|
|
20377
|
-
function exportTemperatureCSV(data, deviceLabel, stats, startDate, endDate) {
|
|
20378
|
-
if (data.length === 0) {
|
|
20379
|
-
console.warn("No data to export");
|
|
20380
|
-
return;
|
|
20381
|
-
}
|
|
20382
|
-
const BOM = "\uFEFF";
|
|
20383
|
-
let csvContent = BOM;
|
|
20384
|
-
csvContent += `Relat\xF3rio de Temperatura - ${deviceLabel}
|
|
20385
|
-
`;
|
|
20386
|
-
csvContent += `Per\xEDodo: ${startDate} at\xE9 ${endDate}
|
|
20387
|
-
`;
|
|
20388
|
-
csvContent += `M\xE9dia: ${formatTemperature2(stats.avg)}
|
|
20389
|
-
`;
|
|
20390
|
-
csvContent += `M\xEDnima: ${formatTemperature2(stats.min)}
|
|
20391
|
-
`;
|
|
20392
|
-
csvContent += `M\xE1xima: ${formatTemperature2(stats.max)}
|
|
20393
|
-
`;
|
|
20394
|
-
csvContent += `Total de leituras: ${stats.count}
|
|
20395
|
-
`;
|
|
20396
|
-
csvContent += "\n";
|
|
20397
|
-
csvContent += "Data/Hora,Temperatura (\xB0C)\n";
|
|
20398
|
-
data.forEach((item) => {
|
|
20399
|
-
const date = new Date(item.ts).toLocaleString("pt-BR");
|
|
20400
|
-
const temp = Number(item.value).toFixed(2);
|
|
20401
|
-
csvContent += `"${date}",${temp}
|
|
20402
|
-
`;
|
|
20403
|
-
});
|
|
20404
|
-
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
|
|
20405
|
-
const url = URL.createObjectURL(blob);
|
|
20406
|
-
const link = document.createElement("a");
|
|
20407
|
-
link.href = url;
|
|
20408
|
-
link.download = `temperatura_${deviceLabel.replace(/\s+/g, "_")}_${startDate}_${endDate}.csv`;
|
|
20409
|
-
document.body.appendChild(link);
|
|
20410
|
-
link.click();
|
|
20411
|
-
document.body.removeChild(link);
|
|
20412
|
-
URL.revokeObjectURL(url);
|
|
20413
|
-
}
|
|
20414
|
-
var DARK_THEME = {
|
|
20415
|
-
background: "rgba(0, 0, 0, 0.85)",
|
|
20416
|
-
surface: "#1a1f28",
|
|
20417
|
-
text: "#ffffff",
|
|
20418
|
-
textMuted: "rgba(255, 255, 255, 0.7)",
|
|
20419
|
-
border: "rgba(255, 255, 255, 0.1)",
|
|
20420
|
-
primary: "#1976d2",
|
|
20421
|
-
success: "#4CAF50",
|
|
20422
|
-
warning: "#FF9800",
|
|
20423
|
-
danger: "#f44336",
|
|
20424
|
-
chartLine: "#1976d2",
|
|
20425
|
-
chartGrid: "rgba(255, 255, 255, 0.1)"
|
|
20426
|
-
};
|
|
20427
|
-
var LIGHT_THEME = {
|
|
20428
|
-
background: "rgba(0, 0, 0, 0.6)",
|
|
20429
|
-
surface: "#ffffff",
|
|
20430
|
-
text: "#333333",
|
|
20431
|
-
textMuted: "#666666",
|
|
20432
|
-
border: "#e0e0e0",
|
|
20433
|
-
primary: "#1976d2",
|
|
20434
|
-
success: "#4CAF50",
|
|
20435
|
-
warning: "#FF9800",
|
|
20436
|
-
danger: "#f44336",
|
|
20437
|
-
chartLine: "#1976d2",
|
|
20438
|
-
chartGrid: "#e0e0e0"
|
|
20439
|
-
};
|
|
20440
|
-
function getThemeColors(theme) {
|
|
20441
|
-
return theme === "dark" ? DARK_THEME : LIGHT_THEME;
|
|
20442
|
-
}
|
|
20443
|
-
|
|
20444
22006
|
// src/components/temperature/TemperatureModal.ts
|
|
20445
22007
|
async function openTemperatureModal(params) {
|
|
20446
22008
|
const modalId = `myio-temp-modal-${Date.now()}`;
|
|
@@ -20680,7 +22242,7 @@ function renderModal(container, state, modalId, error) {
|
|
|
20680
22242
|
">
|
|
20681
22243
|
<span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Temperatura Atual</span>
|
|
20682
22244
|
<div style="font-weight: 700; font-size: 24px; color: ${statusColor}; margin-top: 4px;">
|
|
20683
|
-
${state.currentTemperature !== null ?
|
|
22245
|
+
${state.currentTemperature !== null ? formatTemperature(state.currentTemperature) : "N/A"}
|
|
20684
22246
|
</div>
|
|
20685
22247
|
<div style="font-size: 11px; color: ${statusColor}; margin-top: 2px;">${statusText}</div>
|
|
20686
22248
|
</div>
|
|
@@ -20691,7 +22253,7 @@ function renderModal(container, state, modalId, error) {
|
|
|
20691
22253
|
">
|
|
20692
22254
|
<span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">M\xE9dia do Per\xEDodo</span>
|
|
20693
22255
|
<div id="${modalId}-avg" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
|
|
20694
|
-
${state.stats.count > 0 ?
|
|
22256
|
+
${state.stats.count > 0 ? formatTemperature(state.stats.avg) : "N/A"}
|
|
20695
22257
|
</div>
|
|
20696
22258
|
<div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${startDateStr} - ${endDateStr}</div>
|
|
20697
22259
|
</div>
|
|
@@ -20702,7 +22264,7 @@ function renderModal(container, state, modalId, error) {
|
|
|
20702
22264
|
">
|
|
20703
22265
|
<span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Min / Max</span>
|
|
20704
22266
|
<div id="${modalId}-minmax" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
|
|
20705
|
-
${state.stats.count > 0 ? `${
|
|
22267
|
+
${state.stats.count > 0 ? `${formatTemperature(state.stats.min)} / ${formatTemperature(state.stats.max)}` : "N/A"}
|
|
20706
22268
|
</div>
|
|
20707
22269
|
<div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${state.stats.count} leituras</div>
|
|
20708
22270
|
</div>
|
|
@@ -21018,7 +22580,7 @@ function setupChartTooltip(canvas, container, chartData, state, colors) {
|
|
|
21018
22580
|
}
|
|
21019
22581
|
tooltip.innerHTML = `
|
|
21020
22582
|
<div style="font-weight: 600; margin-bottom: 6px; color: ${colors.primary};">
|
|
21021
|
-
${
|
|
22583
|
+
${formatTemperature(point.y)}
|
|
21022
22584
|
</div>
|
|
21023
22585
|
<div style="font-size: 11px; color: ${colors.textMuted};">
|
|
21024
22586
|
\u{1F4C5} ${dateStr}
|
|
@@ -21281,7 +22843,7 @@ function renderModal2(container, state, modalId) {
|
|
|
21281
22843
|
<span style="width: 12px; height: 12px; border-radius: 50%; background: ${dd.color};"></span>
|
|
21282
22844
|
<span style="color: ${colors.text}; font-size: 13px;">${dd.device.label}</span>
|
|
21283
22845
|
<span style="color: ${colors.textMuted}; font-size: 11px; margin-left: auto;">
|
|
21284
|
-
${dd.stats.count > 0 ?
|
|
22846
|
+
${dd.stats.count > 0 ? formatTemperature(dd.stats.avg) : "N/A"}
|
|
21285
22847
|
</span>
|
|
21286
22848
|
</div>
|
|
21287
22849
|
`).join("");
|
|
@@ -21297,15 +22859,15 @@ function renderModal2(container, state, modalId) {
|
|
|
21297
22859
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 4px; font-size: 11px;">
|
|
21298
22860
|
<span style="color: ${colors.textMuted};">M\xE9dia:</span>
|
|
21299
22861
|
<span style="color: ${colors.text}; font-weight: 500;">
|
|
21300
|
-
${dd.stats.count > 0 ?
|
|
22862
|
+
${dd.stats.count > 0 ? formatTemperature(dd.stats.avg) : "N/A"}
|
|
21301
22863
|
</span>
|
|
21302
22864
|
<span style="color: ${colors.textMuted};">Min:</span>
|
|
21303
22865
|
<span style="color: ${colors.text};">
|
|
21304
|
-
${dd.stats.count > 0 ?
|
|
22866
|
+
${dd.stats.count > 0 ? formatTemperature(dd.stats.min) : "N/A"}
|
|
21305
22867
|
</span>
|
|
21306
22868
|
<span style="color: ${colors.textMuted};">Max:</span>
|
|
21307
22869
|
<span style="color: ${colors.text};">
|
|
21308
|
-
${dd.stats.count > 0 ?
|
|
22870
|
+
${dd.stats.count > 0 ? formatTemperature(dd.stats.max) : "N/A"}
|
|
21309
22871
|
</span>
|
|
21310
22872
|
<span style="color: ${colors.textMuted};">Leituras:</span>
|
|
21311
22873
|
<span style="color: ${colors.text};">${dd.stats.count}</span>
|
|
@@ -21841,7 +23403,7 @@ function setupComparisonChartTooltip(canvas, container, chartData, state, colors
|
|
|
21841
23403
|
<span style="font-weight: 600;">${point.deviceLabel}</span>
|
|
21842
23404
|
</div>
|
|
21843
23405
|
<div style="font-weight: 600; font-size: 16px; color: ${point.deviceColor}; margin-bottom: 4px;">
|
|
21844
|
-
${
|
|
23406
|
+
${formatTemperature(point.y)}
|
|
21845
23407
|
</div>
|
|
21846
23408
|
<div style="font-size: 11px; color: ${colors.textMuted};">
|
|
21847
23409
|
\u{1F4C5} ${dateStr}
|
|
@@ -26339,6 +27901,9 @@ export {
|
|
|
26339
27901
|
MyIOSelectionStore,
|
|
26340
27902
|
MyIOSelectionStoreClass,
|
|
26341
27903
|
MyIOToast,
|
|
27904
|
+
DEVICE_TYPES as POWER_LIMITS_DEVICE_TYPES,
|
|
27905
|
+
STATUS_CONFIG as POWER_LIMITS_STATUS_CONFIG,
|
|
27906
|
+
TELEMETRY_TYPES2 as POWER_LIMITS_TELEMETRY_TYPES,
|
|
26342
27907
|
addDetectionContext,
|
|
26343
27908
|
addNamespace,
|
|
26344
27909
|
aggregateByDay,
|
|
@@ -26393,7 +27958,7 @@ export {
|
|
|
26393
27958
|
formatNumberReadable,
|
|
26394
27959
|
formatRelativeTime,
|
|
26395
27960
|
formatTankHeadFromCm,
|
|
26396
|
-
|
|
27961
|
+
formatTemperature,
|
|
26397
27962
|
formatWater,
|
|
26398
27963
|
formatWaterByGroup,
|
|
26399
27964
|
formatWaterVolumeM3,
|
|
@@ -26436,6 +28001,7 @@ export {
|
|
|
26436
28001
|
openDashboardPopupWaterTank,
|
|
26437
28002
|
openDemandModal,
|
|
26438
28003
|
openGoalsPanel,
|
|
28004
|
+
openPowerLimitsSetupModal,
|
|
26439
28005
|
openRealTimeTelemetryModal,
|
|
26440
28006
|
openTemperatureComparisonModal,
|
|
26441
28007
|
openTemperatureModal,
|