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.cjs
CHANGED
|
@@ -588,6 +588,9 @@ __export(index_exports, {
|
|
|
588
588
|
MyIOSelectionStore: () => MyIOSelectionStore,
|
|
589
589
|
MyIOSelectionStoreClass: () => MyIOSelectionStoreClass,
|
|
590
590
|
MyIOToast: () => MyIOToast,
|
|
591
|
+
POWER_LIMITS_DEVICE_TYPES: () => DEVICE_TYPES,
|
|
592
|
+
POWER_LIMITS_STATUS_CONFIG: () => STATUS_CONFIG,
|
|
593
|
+
POWER_LIMITS_TELEMETRY_TYPES: () => TELEMETRY_TYPES2,
|
|
591
594
|
addDetectionContext: () => addDetectionContext,
|
|
592
595
|
addNamespace: () => addNamespace,
|
|
593
596
|
aggregateByDay: () => aggregateByDay,
|
|
@@ -642,7 +645,7 @@ __export(index_exports, {
|
|
|
642
645
|
formatNumberReadable: () => formatNumberReadable,
|
|
643
646
|
formatRelativeTime: () => formatRelativeTime,
|
|
644
647
|
formatTankHeadFromCm: () => formatTankHeadFromCm,
|
|
645
|
-
formatTemperature: () =>
|
|
648
|
+
formatTemperature: () => formatTemperature,
|
|
646
649
|
formatWater: () => formatWater,
|
|
647
650
|
formatWaterByGroup: () => formatWaterByGroup,
|
|
648
651
|
formatWaterVolumeM3: () => formatWaterVolumeM3,
|
|
@@ -685,6 +688,7 @@ __export(index_exports, {
|
|
|
685
688
|
openDashboardPopupWaterTank: () => openDashboardPopupWaterTank,
|
|
686
689
|
openDemandModal: () => openDemandModal,
|
|
687
690
|
openGoalsPanel: () => openGoalsPanel,
|
|
691
|
+
openPowerLimitsSetupModal: () => openPowerLimitsSetupModal,
|
|
688
692
|
openRealTimeTelemetryModal: () => openRealTimeTelemetryModal,
|
|
689
693
|
openTemperatureComparisonModal: () => openTemperatureComparisonModal,
|
|
690
694
|
openTemperatureModal: () => openTemperatureModal,
|
|
@@ -1459,7 +1463,8 @@ var DeviceStatusType = {
|
|
|
1459
1463
|
FAILURE: "failure",
|
|
1460
1464
|
MAINTENANCE: "maintenance",
|
|
1461
1465
|
NO_INFO: "no_info",
|
|
1462
|
-
NOT_INSTALLED: "not_installed"
|
|
1466
|
+
NOT_INSTALLED: "not_installed",
|
|
1467
|
+
OFFLINE: "offline"
|
|
1463
1468
|
};
|
|
1464
1469
|
var ConnectionStatusType = {
|
|
1465
1470
|
CONNECTED: "connected",
|
|
@@ -1468,39 +1473,42 @@ var ConnectionStatusType = {
|
|
|
1468
1473
|
var deviceStatusIcons = {
|
|
1469
1474
|
[DeviceStatusType.POWER_ON]: "\u26A1",
|
|
1470
1475
|
[DeviceStatusType.STANDBY]: "\u{1F50C}",
|
|
1471
|
-
[DeviceStatusType.POWER_OFF]: "\
|
|
1476
|
+
[DeviceStatusType.POWER_OFF]: "\u26AB",
|
|
1472
1477
|
[DeviceStatusType.WARNING]: "\u26A0\uFE0F",
|
|
1473
1478
|
[DeviceStatusType.FAILURE]: "\u{1F6A8}",
|
|
1474
1479
|
[DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
|
|
1475
1480
|
[DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
|
|
1476
|
-
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
|
|
1481
|
+
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
|
|
1482
|
+
[DeviceStatusType.OFFLINE]: "\u{1F534}"
|
|
1477
1483
|
};
|
|
1478
1484
|
var waterDeviceStatusIcons = {
|
|
1479
1485
|
[DeviceStatusType.POWER_ON]: "\u{1F4A7}",
|
|
1480
1486
|
[DeviceStatusType.STANDBY]: "\u{1F6B0}",
|
|
1481
|
-
[DeviceStatusType.POWER_OFF]: "\
|
|
1487
|
+
[DeviceStatusType.POWER_OFF]: "\u26AB",
|
|
1482
1488
|
[DeviceStatusType.WARNING]: "\u26A0\uFE0F",
|
|
1483
1489
|
[DeviceStatusType.FAILURE]: "\u{1F6A8}",
|
|
1484
1490
|
[DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
|
|
1485
1491
|
[DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
|
|
1486
|
-
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
|
|
1492
|
+
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
|
|
1493
|
+
[DeviceStatusType.OFFLINE]: "\u{1F534}"
|
|
1487
1494
|
};
|
|
1488
1495
|
var temperatureDeviceStatusIcons = {
|
|
1489
1496
|
[DeviceStatusType.POWER_ON]: "\u{1F321}\uFE0F",
|
|
1490
1497
|
[DeviceStatusType.STANDBY]: "\u{1F321}\uFE0F",
|
|
1491
|
-
[DeviceStatusType.POWER_OFF]: "\
|
|
1498
|
+
[DeviceStatusType.POWER_OFF]: "\u26AB",
|
|
1492
1499
|
[DeviceStatusType.WARNING]: "\u26A0\uFE0F",
|
|
1493
1500
|
[DeviceStatusType.FAILURE]: "\u{1F6A8}",
|
|
1494
1501
|
[DeviceStatusType.MAINTENANCE]: "\u{1F6E0}\uFE0F",
|
|
1495
1502
|
[DeviceStatusType.NO_INFO]: "\u2753\uFE0F",
|
|
1496
|
-
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}"
|
|
1503
|
+
[DeviceStatusType.NOT_INSTALLED]: "\u{1F4E6}",
|
|
1504
|
+
[DeviceStatusType.OFFLINE]: "\u{1F534}"
|
|
1497
1505
|
};
|
|
1498
1506
|
var connectionStatusIcons = {
|
|
1499
1507
|
[ConnectionStatusType.CONNECTED]: "\u{1F7E2}",
|
|
1500
1508
|
[ConnectionStatusType.OFFLINE]: "\u{1F6AB}"
|
|
1501
1509
|
};
|
|
1502
1510
|
function mapDeviceToConnectionStatus(deviceStatus) {
|
|
1503
|
-
if (deviceStatus === DeviceStatusType.NO_INFO) {
|
|
1511
|
+
if (deviceStatus === DeviceStatusType.NO_INFO || deviceStatus === DeviceStatusType.OFFLINE) {
|
|
1504
1512
|
return ConnectionStatusType.OFFLINE;
|
|
1505
1513
|
}
|
|
1506
1514
|
return ConnectionStatusType.CONNECTED;
|
|
@@ -1524,15 +1532,16 @@ function mapDeviceStatusToCardStatus(deviceStatus) {
|
|
|
1524
1532
|
[DeviceStatusType.FAILURE]: "fail",
|
|
1525
1533
|
[DeviceStatusType.MAINTENANCE]: "alert",
|
|
1526
1534
|
[DeviceStatusType.NO_INFO]: "unknown",
|
|
1527
|
-
[DeviceStatusType.NOT_INSTALLED]: "not_installed"
|
|
1535
|
+
[DeviceStatusType.NOT_INSTALLED]: "not_installed",
|
|
1536
|
+
[DeviceStatusType.OFFLINE]: "offline"
|
|
1528
1537
|
};
|
|
1529
1538
|
return statusMap[deviceStatus] || "unknown";
|
|
1530
1539
|
}
|
|
1531
1540
|
function shouldFlashIcon(deviceStatus) {
|
|
1532
|
-
return deviceStatus === DeviceStatusType.POWER_OFF || deviceStatus === DeviceStatusType.WARNING || deviceStatus === DeviceStatusType.FAILURE || deviceStatus === DeviceStatusType.MAINTENANCE;
|
|
1541
|
+
return deviceStatus === DeviceStatusType.POWER_OFF || deviceStatus === DeviceStatusType.WARNING || deviceStatus === DeviceStatusType.FAILURE || deviceStatus === DeviceStatusType.MAINTENANCE || deviceStatus === DeviceStatusType.OFFLINE;
|
|
1533
1542
|
}
|
|
1534
1543
|
function isDeviceOffline(deviceStatus) {
|
|
1535
|
-
return deviceStatus === DeviceStatusType.NO_INFO;
|
|
1544
|
+
return deviceStatus === DeviceStatusType.NO_INFO || deviceStatus === DeviceStatusType.OFFLINE;
|
|
1536
1545
|
}
|
|
1537
1546
|
function getDeviceStatusIcon(deviceStatus, deviceType = null) {
|
|
1538
1547
|
const normalizedType = deviceType?.toUpperCase() || "";
|
|
@@ -4088,15 +4097,30 @@ var CSS_STRING = `
|
|
|
4088
4097
|
--myio-chip-alert-fg: #b45309;
|
|
4089
4098
|
--myio-border-alert: rgba(245, 158, 11, 0.5);
|
|
4090
4099
|
|
|
4091
|
-
/* Status colors - Failure (red) */
|
|
4100
|
+
/* Status colors - Failure (dark red) */
|
|
4092
4101
|
--myio-chip-failure-bg: #fee2e2;
|
|
4093
4102
|
--myio-chip-failure-fg: #b91c1c;
|
|
4094
|
-
--myio-border-failure: rgba(
|
|
4103
|
+
--myio-border-failure: rgba(153, 27, 27, 0.6);
|
|
4104
|
+
|
|
4105
|
+
/* Status colors - Power Off (light red) */
|
|
4106
|
+
--myio-chip-power-off-bg: #fecaca;
|
|
4107
|
+
--myio-chip-power-off-fg: #dc2626;
|
|
4108
|
+
--myio-border-power-off: rgba(239, 68, 68, 0.5);
|
|
4109
|
+
|
|
4110
|
+
/* Status colors - Offline (dark gray) */
|
|
4111
|
+
--myio-chip-offline-bg: #e2e8f0;
|
|
4112
|
+
--myio-chip-offline-fg: #475569;
|
|
4113
|
+
--myio-border-offline: rgba(71, 85, 105, 0.6);
|
|
4114
|
+
|
|
4115
|
+
/* Status colors - No Info (dark orange) */
|
|
4116
|
+
--myio-chip-no-info-bg: #fed7aa;
|
|
4117
|
+
--myio-chip-no-info-fg: #c2410c;
|
|
4118
|
+
--myio-border-no-info: rgba(194, 65, 12, 0.5);
|
|
4095
4119
|
|
|
4096
|
-
/* Status colors -
|
|
4097
|
-
--myio-chip-
|
|
4098
|
-
--myio-chip-
|
|
4099
|
-
--myio-border-
|
|
4120
|
+
/* Status colors - Not Installed (purple) */
|
|
4121
|
+
--myio-chip-not-installed-bg: #e9d5ff;
|
|
4122
|
+
--myio-chip-not-installed-fg: #7c3aed;
|
|
4123
|
+
--myio-border-not-installed: rgba(124, 58, 237, 0.5);
|
|
4100
4124
|
|
|
4101
4125
|
--myio-text-1: #0f172a;
|
|
4102
4126
|
--myio-text-2: #4b5563;
|
|
@@ -4152,26 +4176,55 @@ var CSS_STRING = `
|
|
|
4152
4176
|
}
|
|
4153
4177
|
|
|
4154
4178
|
/* Card border states based on device status */
|
|
4155
|
-
|
|
4179
|
+
|
|
4180
|
+
/* POWER_ON - Blue */
|
|
4181
|
+
.myio-ho-card.is-power-on {
|
|
4156
4182
|
border-color: var(--myio-border-ok);
|
|
4157
4183
|
box-shadow: 0 0 0 2px var(--myio-border-ok), var(--myio-card-shadow);
|
|
4158
4184
|
}
|
|
4159
4185
|
|
|
4186
|
+
/* STANDBY - Green */
|
|
4160
4187
|
.myio-ho-card.is-standby {
|
|
4161
4188
|
border-color: var(--myio-border-standby);
|
|
4162
4189
|
box-shadow: 0 0 0 2px var(--myio-border-standby), var(--myio-card-shadow);
|
|
4163
4190
|
}
|
|
4164
4191
|
|
|
4165
|
-
|
|
4192
|
+
/* WARNING - Yellow */
|
|
4193
|
+
.myio-ho-card.is-warning {
|
|
4194
|
+
border-color: var(--myio-border-alert);
|
|
4195
|
+
box-shadow: 0 0 0 2px var(--myio-border-alert), var(--myio-card-shadow);
|
|
4196
|
+
}
|
|
4197
|
+
|
|
4198
|
+
/* MAINTENANCE - Yellow */
|
|
4199
|
+
.myio-ho-card.is-maintenance {
|
|
4166
4200
|
border-color: var(--myio-border-alert);
|
|
4167
4201
|
box-shadow: 0 0 0 2px var(--myio-border-alert), var(--myio-card-shadow);
|
|
4168
4202
|
}
|
|
4169
4203
|
|
|
4204
|
+
/* FAILURE - Dark Red */
|
|
4170
4205
|
.myio-ho-card.is-failure {
|
|
4171
4206
|
border-color: var(--myio-border-failure);
|
|
4172
4207
|
box-shadow: 0 0 0 2px var(--myio-border-failure), var(--myio-card-shadow);
|
|
4173
4208
|
}
|
|
4174
4209
|
|
|
4210
|
+
/* POWER_OFF - Light Red */
|
|
4211
|
+
.myio-ho-card.is-power-off {
|
|
4212
|
+
border-color: var(--myio-border-power-off);
|
|
4213
|
+
box-shadow: 0 0 0 2px var(--myio-border-power-off), var(--myio-card-shadow);
|
|
4214
|
+
}
|
|
4215
|
+
|
|
4216
|
+
/* NO_INFO - Dark Orange */
|
|
4217
|
+
.myio-ho-card.is-no-info {
|
|
4218
|
+
border-color: var(--myio-border-no-info);
|
|
4219
|
+
box-shadow: 0 0 0 2px var(--myio-border-no-info), var(--myio-card-shadow);
|
|
4220
|
+
}
|
|
4221
|
+
|
|
4222
|
+
/* NOT_INSTALLED - Purple */
|
|
4223
|
+
.myio-ho-card.is-not-installed {
|
|
4224
|
+
border-color: var(--myio-border-not-installed);
|
|
4225
|
+
box-shadow: 0 0 0 2px var(--myio-border-not-installed), var(--myio-card-shadow);
|
|
4226
|
+
}
|
|
4227
|
+
|
|
4175
4228
|
/* Header section */
|
|
4176
4229
|
.myio-ho-card__header {
|
|
4177
4230
|
display: flex;
|
|
@@ -4189,7 +4242,9 @@ var CSS_STRING = `
|
|
|
4189
4242
|
margin-top: 2px;
|
|
4190
4243
|
}
|
|
4191
4244
|
|
|
4192
|
-
|
|
4245
|
+
/* Icon colors based on status */
|
|
4246
|
+
.myio-ho-card.is-warning .myio-ho-card__icon,
|
|
4247
|
+
.myio-ho-card.is-maintenance .myio-ho-card__icon {
|
|
4193
4248
|
color: var(--myio-chip-alert-fg);
|
|
4194
4249
|
}
|
|
4195
4250
|
|
|
@@ -4197,14 +4252,28 @@ var CSS_STRING = `
|
|
|
4197
4252
|
color: var(--myio-chip-failure-fg);
|
|
4198
4253
|
}
|
|
4199
4254
|
|
|
4255
|
+
.myio-ho-card.is-power-off .myio-ho-card__icon {
|
|
4256
|
+
color: var(--myio-chip-power-off-fg);
|
|
4257
|
+
}
|
|
4258
|
+
|
|
4259
|
+
.myio-ho-card.is-offline .myio-ho-card__icon {
|
|
4260
|
+
color: var(--myio-chip-offline-fg);
|
|
4261
|
+
}
|
|
4262
|
+
|
|
4263
|
+
.myio-ho-card.is-no-info .myio-ho-card__icon {
|
|
4264
|
+
color: var(--myio-chip-no-info-fg);
|
|
4265
|
+
}
|
|
4266
|
+
|
|
4267
|
+
.myio-ho-card.is-not-installed .myio-ho-card__icon {
|
|
4268
|
+
color: var(--myio-chip-not-installed-fg);
|
|
4269
|
+
}
|
|
4270
|
+
|
|
4200
4271
|
.myio-ho-card__title {
|
|
4201
4272
|
flex: 1;
|
|
4202
4273
|
min-width: 0;
|
|
4203
4274
|
}
|
|
4204
4275
|
|
|
4205
|
-
/*
|
|
4206
|
-
|
|
4207
|
-
/* Estado Offline - borda cinza */
|
|
4276
|
+
/* OFFLINE - Dark Gray */
|
|
4208
4277
|
.myio-ho-card.is-offline {
|
|
4209
4278
|
border-color: var(--myio-border-offline);
|
|
4210
4279
|
box-shadow: 0 0 0 2px var(--myio-border-offline), var(--myio-card-shadow);
|
|
@@ -4599,6 +4668,37 @@ var CSS_STRING = `
|
|
|
4599
4668
|
color: var(--myio-chip-offline-fg);
|
|
4600
4669
|
}
|
|
4601
4670
|
|
|
4671
|
+
/* New chip classes aligned with getCardStateClass */
|
|
4672
|
+
.chip--power-on {
|
|
4673
|
+
background: var(--myio-chip-ok-bg);
|
|
4674
|
+
color: var(--myio-chip-ok-fg);
|
|
4675
|
+
}
|
|
4676
|
+
|
|
4677
|
+
.chip--warning {
|
|
4678
|
+
background: var(--myio-chip-alert-bg);
|
|
4679
|
+
color: var(--myio-chip-alert-fg);
|
|
4680
|
+
}
|
|
4681
|
+
|
|
4682
|
+
.chip--maintenance {
|
|
4683
|
+
background: var(--myio-chip-alert-bg);
|
|
4684
|
+
color: var(--myio-chip-alert-fg);
|
|
4685
|
+
}
|
|
4686
|
+
|
|
4687
|
+
.chip--power-off {
|
|
4688
|
+
background: var(--myio-chip-power-off-bg);
|
|
4689
|
+
color: var(--myio-chip-power-off-fg);
|
|
4690
|
+
}
|
|
4691
|
+
|
|
4692
|
+
.chip--no-info {
|
|
4693
|
+
background: var(--myio-chip-no-info-bg);
|
|
4694
|
+
color: var(--myio-chip-no-info-fg);
|
|
4695
|
+
}
|
|
4696
|
+
|
|
4697
|
+
.chip--not-installed {
|
|
4698
|
+
background: var(--myio-chip-not-installed-bg);
|
|
4699
|
+
color: var(--myio-chip-not-installed-fg);
|
|
4700
|
+
}
|
|
4701
|
+
|
|
4602
4702
|
/* Status indicator dot for power metric */
|
|
4603
4703
|
.status-dot {
|
|
4604
4704
|
width: 8px;
|
|
@@ -4632,6 +4732,31 @@ var CSS_STRING = `
|
|
|
4632
4732
|
background: var(--myio-muted);
|
|
4633
4733
|
}
|
|
4634
4734
|
|
|
4735
|
+
/* New dot classes aligned with getCardStateClass */
|
|
4736
|
+
.status-dot.dot--power-on {
|
|
4737
|
+
background: var(--myio-chip-ok-fg);
|
|
4738
|
+
}
|
|
4739
|
+
|
|
4740
|
+
.status-dot.dot--warning {
|
|
4741
|
+
background: var(--myio-chip-alert-fg);
|
|
4742
|
+
}
|
|
4743
|
+
|
|
4744
|
+
.status-dot.dot--maintenance {
|
|
4745
|
+
background: var(--myio-chip-alert-fg);
|
|
4746
|
+
}
|
|
4747
|
+
|
|
4748
|
+
.status-dot.dot--power-off {
|
|
4749
|
+
background: var(--myio-chip-power-off-fg);
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4752
|
+
.status-dot.dot--no-info {
|
|
4753
|
+
background: var(--myio-chip-no-info-fg);
|
|
4754
|
+
}
|
|
4755
|
+
|
|
4756
|
+
.status-dot.dot--not-installed {
|
|
4757
|
+
background: var(--myio-chip-not-installed-fg);
|
|
4758
|
+
}
|
|
4759
|
+
|
|
4635
4760
|
/* Primary metric */
|
|
4636
4761
|
.myio-ho-card__primary {
|
|
4637
4762
|
margin-bottom: 14px;
|
|
@@ -4814,6 +4939,215 @@ var CSS_STRING = `
|
|
|
4814
4939
|
transition: none;
|
|
4815
4940
|
}
|
|
4816
4941
|
}
|
|
4942
|
+
|
|
4943
|
+
/* ============================================
|
|
4944
|
+
DEBUG TOOLTIP STYLES (Premium)
|
|
4945
|
+
============================================ */
|
|
4946
|
+
|
|
4947
|
+
.has-debug-tooltip {
|
|
4948
|
+
cursor: help !important;
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4951
|
+
.has-debug-tooltip::after {
|
|
4952
|
+
content: '\u{1F41B}';
|
|
4953
|
+
position: absolute;
|
|
4954
|
+
top: -4px;
|
|
4955
|
+
right: -4px;
|
|
4956
|
+
font-size: 10px;
|
|
4957
|
+
z-index: 1;
|
|
4958
|
+
}
|
|
4959
|
+
|
|
4960
|
+
.debug-tooltip-container {
|
|
4961
|
+
position: absolute;
|
|
4962
|
+
bottom: calc(100% + 8px);
|
|
4963
|
+
left: 50%;
|
|
4964
|
+
transform: translateX(-50%);
|
|
4965
|
+
z-index: 10000;
|
|
4966
|
+
pointer-events: none;
|
|
4967
|
+
opacity: 0;
|
|
4968
|
+
transition: opacity 0.2s ease, transform 0.2s ease;
|
|
4969
|
+
}
|
|
4970
|
+
|
|
4971
|
+
.has-debug-tooltip:hover .debug-tooltip-container {
|
|
4972
|
+
opacity: 1;
|
|
4973
|
+
pointer-events: auto;
|
|
4974
|
+
}
|
|
4975
|
+
|
|
4976
|
+
.debug-tooltip {
|
|
4977
|
+
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
|
|
4978
|
+
border: 1px solid rgba(99, 102, 241, 0.3);
|
|
4979
|
+
border-radius: 12px;
|
|
4980
|
+
box-shadow:
|
|
4981
|
+
0 20px 40px rgba(0, 0, 0, 0.4),
|
|
4982
|
+
0 0 0 1px rgba(255, 255, 255, 0.05),
|
|
4983
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
|
4984
|
+
min-width: 340px;
|
|
4985
|
+
max-width: 420px;
|
|
4986
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
4987
|
+
font-size: 12px;
|
|
4988
|
+
color: #e2e8f0;
|
|
4989
|
+
overflow: hidden;
|
|
4990
|
+
}
|
|
4991
|
+
|
|
4992
|
+
.debug-tooltip__header {
|
|
4993
|
+
display: flex;
|
|
4994
|
+
align-items: center;
|
|
4995
|
+
gap: 8px;
|
|
4996
|
+
padding: 12px 16px;
|
|
4997
|
+
background: linear-gradient(90deg, rgba(99, 102, 241, 0.2) 0%, rgba(139, 92, 246, 0.1) 100%);
|
|
4998
|
+
border-bottom: 1px solid rgba(99, 102, 241, 0.2);
|
|
4999
|
+
}
|
|
5000
|
+
|
|
5001
|
+
.debug-tooltip__icon {
|
|
5002
|
+
font-size: 16px;
|
|
5003
|
+
}
|
|
5004
|
+
|
|
5005
|
+
.debug-tooltip__title {
|
|
5006
|
+
font-weight: 700;
|
|
5007
|
+
font-size: 13px;
|
|
5008
|
+
color: #f1f5f9;
|
|
5009
|
+
letter-spacing: 0.5px;
|
|
5010
|
+
text-transform: uppercase;
|
|
5011
|
+
}
|
|
5012
|
+
|
|
5013
|
+
.debug-tooltip__content {
|
|
5014
|
+
padding: 12px 16px;
|
|
5015
|
+
max-height: 400px;
|
|
5016
|
+
overflow-y: auto;
|
|
5017
|
+
}
|
|
5018
|
+
|
|
5019
|
+
.debug-tooltip__section {
|
|
5020
|
+
margin-bottom: 14px;
|
|
5021
|
+
padding-bottom: 12px;
|
|
5022
|
+
border-bottom: 1px solid rgba(148, 163, 184, 0.1);
|
|
5023
|
+
}
|
|
5024
|
+
|
|
5025
|
+
.debug-tooltip__section:last-child {
|
|
5026
|
+
margin-bottom: 0;
|
|
5027
|
+
padding-bottom: 0;
|
|
5028
|
+
border-bottom: none;
|
|
5029
|
+
}
|
|
5030
|
+
|
|
5031
|
+
.debug-tooltip__section-title {
|
|
5032
|
+
font-size: 11px;
|
|
5033
|
+
font-weight: 600;
|
|
5034
|
+
color: #94a3b8;
|
|
5035
|
+
text-transform: uppercase;
|
|
5036
|
+
letter-spacing: 0.8px;
|
|
5037
|
+
margin-bottom: 10px;
|
|
5038
|
+
display: flex;
|
|
5039
|
+
align-items: center;
|
|
5040
|
+
gap: 6px;
|
|
5041
|
+
}
|
|
5042
|
+
|
|
5043
|
+
.debug-tooltip__row {
|
|
5044
|
+
display: flex;
|
|
5045
|
+
justify-content: space-between;
|
|
5046
|
+
align-items: flex-start;
|
|
5047
|
+
padding: 4px 0;
|
|
5048
|
+
gap: 12px;
|
|
5049
|
+
}
|
|
5050
|
+
|
|
5051
|
+
.debug-tooltip__row--full {
|
|
5052
|
+
flex-direction: column;
|
|
5053
|
+
gap: 4px;
|
|
5054
|
+
}
|
|
5055
|
+
|
|
5056
|
+
.debug-tooltip__label {
|
|
5057
|
+
color: #94a3b8;
|
|
5058
|
+
font-size: 11px;
|
|
5059
|
+
flex-shrink: 0;
|
|
5060
|
+
}
|
|
5061
|
+
|
|
5062
|
+
.debug-tooltip__value {
|
|
5063
|
+
color: #f1f5f9;
|
|
5064
|
+
font-weight: 500;
|
|
5065
|
+
text-align: right;
|
|
5066
|
+
word-break: break-all;
|
|
5067
|
+
}
|
|
5068
|
+
|
|
5069
|
+
.debug-tooltip__row--full .debug-tooltip__value {
|
|
5070
|
+
text-align: left;
|
|
5071
|
+
background: rgba(0, 0, 0, 0.3);
|
|
5072
|
+
padding: 6px 10px;
|
|
5073
|
+
border-radius: 6px;
|
|
5074
|
+
font-size: 11px;
|
|
5075
|
+
width: 100%;
|
|
5076
|
+
box-sizing: border-box;
|
|
5077
|
+
}
|
|
5078
|
+
|
|
5079
|
+
.debug-tooltip__value--mono {
|
|
5080
|
+
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
|
|
5081
|
+
font-size: 11px;
|
|
5082
|
+
background: rgba(0, 0, 0, 0.3);
|
|
5083
|
+
padding: 2px 6px;
|
|
5084
|
+
border-radius: 4px;
|
|
5085
|
+
}
|
|
5086
|
+
|
|
5087
|
+
.debug-tooltip__value--highlight {
|
|
5088
|
+
color: #a5b4fc;
|
|
5089
|
+
font-style: italic;
|
|
5090
|
+
}
|
|
5091
|
+
|
|
5092
|
+
.debug-tooltip__badge {
|
|
5093
|
+
display: inline-block;
|
|
5094
|
+
padding: 2px 8px;
|
|
5095
|
+
border-radius: 4px;
|
|
5096
|
+
font-size: 10px;
|
|
5097
|
+
font-weight: 600;
|
|
5098
|
+
text-transform: uppercase;
|
|
5099
|
+
letter-spacing: 0.5px;
|
|
5100
|
+
background: rgba(99, 102, 241, 0.3);
|
|
5101
|
+
color: #a5b4fc;
|
|
5102
|
+
}
|
|
5103
|
+
|
|
5104
|
+
.debug-tooltip__badge--energy {
|
|
5105
|
+
background: rgba(59, 130, 246, 0.3);
|
|
5106
|
+
color: #93c5fd;
|
|
5107
|
+
}
|
|
5108
|
+
|
|
5109
|
+
.debug-tooltip__badge--water {
|
|
5110
|
+
background: rgba(6, 182, 212, 0.3);
|
|
5111
|
+
color: #67e8f9;
|
|
5112
|
+
}
|
|
5113
|
+
|
|
5114
|
+
.debug-tooltip__badge--temperature {
|
|
5115
|
+
background: rgba(249, 115, 22, 0.3);
|
|
5116
|
+
color: #fdba74;
|
|
5117
|
+
}
|
|
5118
|
+
|
|
5119
|
+
/* Tooltip arrow */
|
|
5120
|
+
.debug-tooltip::after {
|
|
5121
|
+
content: '';
|
|
5122
|
+
position: absolute;
|
|
5123
|
+
bottom: -6px;
|
|
5124
|
+
left: 50%;
|
|
5125
|
+
transform: translateX(-50%) rotate(45deg);
|
|
5126
|
+
width: 12px;
|
|
5127
|
+
height: 12px;
|
|
5128
|
+
background: #0f172a;
|
|
5129
|
+
border-right: 1px solid rgba(99, 102, 241, 0.3);
|
|
5130
|
+
border-bottom: 1px solid rgba(99, 102, 241, 0.3);
|
|
5131
|
+
}
|
|
5132
|
+
|
|
5133
|
+
/* Scrollbar styling for tooltip content */
|
|
5134
|
+
.debug-tooltip__content::-webkit-scrollbar {
|
|
5135
|
+
width: 6px;
|
|
5136
|
+
}
|
|
5137
|
+
|
|
5138
|
+
.debug-tooltip__content::-webkit-scrollbar-track {
|
|
5139
|
+
background: rgba(0, 0, 0, 0.2);
|
|
5140
|
+
border-radius: 3px;
|
|
5141
|
+
}
|
|
5142
|
+
|
|
5143
|
+
.debug-tooltip__content::-webkit-scrollbar-thumb {
|
|
5144
|
+
background: rgba(99, 102, 241, 0.4);
|
|
5145
|
+
border-radius: 3px;
|
|
5146
|
+
}
|
|
5147
|
+
|
|
5148
|
+
.debug-tooltip__content::-webkit-scrollbar-thumb:hover {
|
|
5149
|
+
background: rgba(99, 102, 241, 0.6);
|
|
5150
|
+
}
|
|
4817
5151
|
`;
|
|
4818
5152
|
|
|
4819
5153
|
// src/thingsboard/main-dashboard-shopping/v-4.0.0/head-office/card-head-office.icons.ts
|
|
@@ -4968,46 +5302,296 @@ var DEFAULT_I18N = {
|
|
|
4968
5302
|
menu_settings: "Configura\xE7\xF5es"
|
|
4969
5303
|
};
|
|
4970
5304
|
|
|
4971
|
-
// src/
|
|
4972
|
-
var
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
5305
|
+
// src/components/temperature/utils.ts
|
|
5306
|
+
var DAY_PERIODS = [
|
|
5307
|
+
{ id: "madrugada", label: "Madrugada (00h-06h)", startHour: 0, endHour: 6 },
|
|
5308
|
+
{ id: "manha", label: "Manh\xE3 (06h-12h)", startHour: 6, endHour: 12 },
|
|
5309
|
+
{ id: "tarde", label: "Tarde (12h-18h)", startHour: 12, endHour: 18 },
|
|
5310
|
+
{ id: "noite", label: "Noite (18h-24h)", startHour: 18, endHour: 24 }
|
|
5311
|
+
];
|
|
5312
|
+
var DEFAULT_CLAMP_RANGE = { min: 15, max: 40 };
|
|
5313
|
+
function getTodaySoFar() {
|
|
5314
|
+
const now = /* @__PURE__ */ new Date();
|
|
5315
|
+
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
|
|
5316
|
+
return {
|
|
5317
|
+
startTs: startOfDay.getTime(),
|
|
5318
|
+
endTs: now.getTime()
|
|
5319
|
+
};
|
|
4980
5320
|
}
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
5321
|
+
var CHART_COLORS = [
|
|
5322
|
+
"#1976d2",
|
|
5323
|
+
// Blue
|
|
5324
|
+
"#FF6B6B",
|
|
5325
|
+
// Red
|
|
5326
|
+
"#4CAF50",
|
|
5327
|
+
// Green
|
|
5328
|
+
"#FF9800",
|
|
5329
|
+
// Orange
|
|
5330
|
+
"#9C27B0",
|
|
5331
|
+
// Purple
|
|
5332
|
+
"#00BCD4",
|
|
5333
|
+
// Cyan
|
|
5334
|
+
"#E91E63",
|
|
5335
|
+
// Pink
|
|
5336
|
+
"#795548"
|
|
5337
|
+
// Brown
|
|
5338
|
+
];
|
|
5339
|
+
async function fetchTemperatureData(token, deviceId, startTs, endTs) {
|
|
5340
|
+
const url = `/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=temperature&startTs=${encodeURIComponent(startTs)}&endTs=${encodeURIComponent(endTs)}&limit=50000&agg=NONE`;
|
|
5341
|
+
const response = await fetch(url, {
|
|
5342
|
+
headers: {
|
|
5343
|
+
"X-Authorization": `Bearer ${token}`,
|
|
5344
|
+
"Content-Type": "application/json"
|
|
5345
|
+
}
|
|
5346
|
+
});
|
|
5347
|
+
if (!response.ok) {
|
|
5348
|
+
throw new Error(`Failed to fetch temperature data: ${response.status}`);
|
|
4984
5349
|
}
|
|
4985
|
-
const
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
5350
|
+
const data = await response.json();
|
|
5351
|
+
return data?.temperature || [];
|
|
5352
|
+
}
|
|
5353
|
+
function clampTemperature(value, range = DEFAULT_CLAMP_RANGE) {
|
|
5354
|
+
const num = Number(value || 0);
|
|
5355
|
+
if (num < range.min) return range.min;
|
|
5356
|
+
if (num > range.max) return range.max;
|
|
5357
|
+
return num;
|
|
5358
|
+
}
|
|
5359
|
+
function calculateStats(data, clampRange = DEFAULT_CLAMP_RANGE) {
|
|
5360
|
+
if (data.length === 0) {
|
|
5361
|
+
return { avg: 0, min: 0, max: 0, count: 0 };
|
|
4989
5362
|
}
|
|
5363
|
+
const values = data.map((item) => clampTemperature(item.value, clampRange));
|
|
5364
|
+
const sum = values.reduce((acc, v) => acc + v, 0);
|
|
4990
5365
|
return {
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
useNewComponents: Boolean(params.useNewComponents),
|
|
4996
|
-
// RFC-0091: Configurable delay time for connection status check (default 15 minutes)
|
|
4997
|
-
delayTimeConnectionInMins: params.delayTimeConnectionInMins ?? 15,
|
|
4998
|
-
callbacks: {
|
|
4999
|
-
handleActionDashboard: params.handleActionDashboard,
|
|
5000
|
-
handleActionReport: params.handleActionReport,
|
|
5001
|
-
handleActionSettings: params.handleActionSettings,
|
|
5002
|
-
handleSelect: params.handleSelect,
|
|
5003
|
-
handInfo: params.handInfo,
|
|
5004
|
-
handleClickCard: params.handleClickCard
|
|
5005
|
-
}
|
|
5366
|
+
avg: sum / values.length,
|
|
5367
|
+
min: Math.min(...values),
|
|
5368
|
+
max: Math.max(...values),
|
|
5369
|
+
count: values.length
|
|
5006
5370
|
};
|
|
5007
5371
|
}
|
|
5008
|
-
function
|
|
5009
|
-
|
|
5010
|
-
|
|
5372
|
+
function interpolateTemperature(data, options) {
|
|
5373
|
+
const { intervalMinutes, startTs, endTs, clampRange = DEFAULT_CLAMP_RANGE } = options;
|
|
5374
|
+
const intervalMs = intervalMinutes * 60 * 1e3;
|
|
5375
|
+
if (data.length === 0) {
|
|
5376
|
+
return [];
|
|
5377
|
+
}
|
|
5378
|
+
const sortedData = [...data].sort((a, b) => a.ts - b.ts);
|
|
5379
|
+
const result = [];
|
|
5380
|
+
let lastKnownValue = clampTemperature(sortedData[0].value, clampRange);
|
|
5381
|
+
let dataIndex = 0;
|
|
5382
|
+
for (let ts = startTs; ts <= endTs; ts += intervalMs) {
|
|
5383
|
+
while (dataIndex < sortedData.length - 1 && sortedData[dataIndex + 1].ts <= ts) {
|
|
5384
|
+
dataIndex++;
|
|
5385
|
+
}
|
|
5386
|
+
const currentData = sortedData[dataIndex];
|
|
5387
|
+
if (currentData && Math.abs(currentData.ts - ts) < intervalMs) {
|
|
5388
|
+
lastKnownValue = clampTemperature(currentData.value, clampRange);
|
|
5389
|
+
}
|
|
5390
|
+
result.push({
|
|
5391
|
+
ts,
|
|
5392
|
+
value: lastKnownValue
|
|
5393
|
+
});
|
|
5394
|
+
}
|
|
5395
|
+
return result;
|
|
5396
|
+
}
|
|
5397
|
+
function aggregateByDay(data, clampRange = DEFAULT_CLAMP_RANGE) {
|
|
5398
|
+
if (data.length === 0) {
|
|
5399
|
+
return [];
|
|
5400
|
+
}
|
|
5401
|
+
const dayMap = /* @__PURE__ */ new Map();
|
|
5402
|
+
data.forEach((item) => {
|
|
5403
|
+
const date = new Date(item.ts);
|
|
5404
|
+
const dateKey = date.toISOString().split("T")[0];
|
|
5405
|
+
if (!dayMap.has(dateKey)) {
|
|
5406
|
+
dayMap.set(dateKey, []);
|
|
5407
|
+
}
|
|
5408
|
+
dayMap.get(dateKey).push(item);
|
|
5409
|
+
});
|
|
5410
|
+
const result = [];
|
|
5411
|
+
dayMap.forEach((dayData, dateKey) => {
|
|
5412
|
+
const values = dayData.map((item) => clampTemperature(item.value, clampRange));
|
|
5413
|
+
const sum = values.reduce((acc, v) => acc + v, 0);
|
|
5414
|
+
result.push({
|
|
5415
|
+
date: dateKey,
|
|
5416
|
+
dateTs: new Date(dateKey).getTime(),
|
|
5417
|
+
avg: sum / values.length,
|
|
5418
|
+
min: Math.min(...values),
|
|
5419
|
+
max: Math.max(...values),
|
|
5420
|
+
count: values.length
|
|
5421
|
+
});
|
|
5422
|
+
});
|
|
5423
|
+
return result.sort((a, b) => a.dateTs - b.dateTs);
|
|
5424
|
+
}
|
|
5425
|
+
function filterByDayPeriods(data, selectedPeriods) {
|
|
5426
|
+
if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
|
|
5427
|
+
return data;
|
|
5428
|
+
}
|
|
5429
|
+
return data.filter((item) => {
|
|
5430
|
+
const date = new Date(item.ts);
|
|
5431
|
+
const hour = date.getHours();
|
|
5432
|
+
return selectedPeriods.some((periodId) => {
|
|
5433
|
+
const period = DAY_PERIODS.find((p) => p.id === periodId);
|
|
5434
|
+
if (!period) return false;
|
|
5435
|
+
return hour >= period.startHour && hour < period.endHour;
|
|
5436
|
+
});
|
|
5437
|
+
});
|
|
5438
|
+
}
|
|
5439
|
+
function getSelectedPeriodsLabel(selectedPeriods) {
|
|
5440
|
+
if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
|
|
5441
|
+
return "Todos os per\xEDodos";
|
|
5442
|
+
}
|
|
5443
|
+
if (selectedPeriods.length === 1) {
|
|
5444
|
+
const period = DAY_PERIODS.find((p) => p.id === selectedPeriods[0]);
|
|
5445
|
+
return period?.label || "";
|
|
5446
|
+
}
|
|
5447
|
+
return `${selectedPeriods.length} per\xEDodos selecionados`;
|
|
5448
|
+
}
|
|
5449
|
+
function formatTemperature(value, decimals = 1) {
|
|
5450
|
+
if (value === null || value === void 0 || isNaN(value)) {
|
|
5451
|
+
return "\u2014";
|
|
5452
|
+
}
|
|
5453
|
+
return `${value.toFixed(decimals)}\xB0C`;
|
|
5454
|
+
}
|
|
5455
|
+
function exportTemperatureCSV(data, deviceLabel, stats, startDate, endDate) {
|
|
5456
|
+
if (data.length === 0) {
|
|
5457
|
+
console.warn("No data to export");
|
|
5458
|
+
return;
|
|
5459
|
+
}
|
|
5460
|
+
const BOM = "\uFEFF";
|
|
5461
|
+
let csvContent = BOM;
|
|
5462
|
+
csvContent += `Relat\xF3rio de Temperatura - ${deviceLabel}
|
|
5463
|
+
`;
|
|
5464
|
+
csvContent += `Per\xEDodo: ${startDate} at\xE9 ${endDate}
|
|
5465
|
+
`;
|
|
5466
|
+
csvContent += `M\xE9dia: ${formatTemperature(stats.avg)}
|
|
5467
|
+
`;
|
|
5468
|
+
csvContent += `M\xEDnima: ${formatTemperature(stats.min)}
|
|
5469
|
+
`;
|
|
5470
|
+
csvContent += `M\xE1xima: ${formatTemperature(stats.max)}
|
|
5471
|
+
`;
|
|
5472
|
+
csvContent += `Total de leituras: ${stats.count}
|
|
5473
|
+
`;
|
|
5474
|
+
csvContent += "\n";
|
|
5475
|
+
csvContent += "Data/Hora,Temperatura (\xB0C)\n";
|
|
5476
|
+
data.forEach((item) => {
|
|
5477
|
+
const date = new Date(item.ts).toLocaleString("pt-BR");
|
|
5478
|
+
const temp = Number(item.value).toFixed(2);
|
|
5479
|
+
csvContent += `"${date}",${temp}
|
|
5480
|
+
`;
|
|
5481
|
+
});
|
|
5482
|
+
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
|
|
5483
|
+
const url = URL.createObjectURL(blob);
|
|
5484
|
+
const link = document.createElement("a");
|
|
5485
|
+
link.href = url;
|
|
5486
|
+
link.download = `temperatura_${deviceLabel.replace(/\s+/g, "_")}_${startDate}_${endDate}.csv`;
|
|
5487
|
+
document.body.appendChild(link);
|
|
5488
|
+
link.click();
|
|
5489
|
+
document.body.removeChild(link);
|
|
5490
|
+
URL.revokeObjectURL(url);
|
|
5491
|
+
}
|
|
5492
|
+
var DARK_THEME = {
|
|
5493
|
+
background: "rgba(0, 0, 0, 0.85)",
|
|
5494
|
+
surface: "#1a1f28",
|
|
5495
|
+
text: "#ffffff",
|
|
5496
|
+
textMuted: "rgba(255, 255, 255, 0.7)",
|
|
5497
|
+
border: "rgba(255, 255, 255, 0.1)",
|
|
5498
|
+
primary: "#1976d2",
|
|
5499
|
+
success: "#4CAF50",
|
|
5500
|
+
warning: "#FF9800",
|
|
5501
|
+
danger: "#f44336",
|
|
5502
|
+
chartLine: "#1976d2",
|
|
5503
|
+
chartGrid: "rgba(255, 255, 255, 0.1)"
|
|
5504
|
+
};
|
|
5505
|
+
var LIGHT_THEME = {
|
|
5506
|
+
background: "rgba(0, 0, 0, 0.6)",
|
|
5507
|
+
surface: "#ffffff",
|
|
5508
|
+
text: "#333333",
|
|
5509
|
+
textMuted: "#666666",
|
|
5510
|
+
border: "#e0e0e0",
|
|
5511
|
+
primary: "#1976d2",
|
|
5512
|
+
success: "#4CAF50",
|
|
5513
|
+
warning: "#FF9800",
|
|
5514
|
+
danger: "#f44336",
|
|
5515
|
+
chartLine: "#1976d2",
|
|
5516
|
+
chartGrid: "#e0e0e0"
|
|
5517
|
+
};
|
|
5518
|
+
function getThemeColors(theme) {
|
|
5519
|
+
return theme === "dark" ? DARK_THEME : LIGHT_THEME;
|
|
5520
|
+
}
|
|
5521
|
+
|
|
5522
|
+
// src/utils/logHelper.js
|
|
5523
|
+
function createLogHelper(debugActive = false) {
|
|
5524
|
+
return {
|
|
5525
|
+
log: function(...args) {
|
|
5526
|
+
if (debugActive) {
|
|
5527
|
+
console.log(...args);
|
|
5528
|
+
}
|
|
5529
|
+
},
|
|
5530
|
+
warn: function(...args) {
|
|
5531
|
+
if (debugActive) {
|
|
5532
|
+
console.warn(...args);
|
|
5533
|
+
}
|
|
5534
|
+
},
|
|
5535
|
+
error: function(...args) {
|
|
5536
|
+
console.error(...args);
|
|
5537
|
+
}
|
|
5538
|
+
};
|
|
5539
|
+
}
|
|
5540
|
+
var LogHelper = createLogHelper(false);
|
|
5541
|
+
|
|
5542
|
+
// src/thingsboard/main-dashboard-shopping/v-4.0.0/card/head-office/card-head-office.js
|
|
5543
|
+
var LABEL_CHAR_LIMIT = 18;
|
|
5544
|
+
var DEFAUL_DELAY_TIME_CONNECTION_IN_MINS = 1440;
|
|
5545
|
+
var CSS_TAG = "head-office-card-v1";
|
|
5546
|
+
function ensureCss() {
|
|
5547
|
+
if (!document.querySelector(`style[data-myio-css="${CSS_TAG}"]`)) {
|
|
5548
|
+
const style = document.createElement("style");
|
|
5549
|
+
style.setAttribute("data-myio-css", CSS_TAG);
|
|
5550
|
+
style.textContent = CSS_STRING;
|
|
5551
|
+
document.head.appendChild(style);
|
|
5552
|
+
}
|
|
5553
|
+
}
|
|
5554
|
+
function normalizeParams(params) {
|
|
5555
|
+
if (!params || !params.entityObject) {
|
|
5556
|
+
throw new Error("renderCardCompenteHeadOffice: entityObject is required");
|
|
5557
|
+
}
|
|
5558
|
+
const LogHelper2 = createLogHelper(params.debugActive ?? false);
|
|
5559
|
+
const entityObject = params.entityObject;
|
|
5560
|
+
if (!entityObject.entityId) {
|
|
5561
|
+
LogHelper2.warn("[CardHeadOffice] entityId is missing, generating temporary ID");
|
|
5562
|
+
entityObject.entityId = `temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
5563
|
+
}
|
|
5564
|
+
if (!params.delayTimeConnectionInMins) {
|
|
5565
|
+
LogHelper2.warn(
|
|
5566
|
+
`[CardHeadOffice] delayTimeConnectionInMins is missing, defaulting to ${DEFAUL_DELAY_TIME_CONNECTION_IN_MINS} mins`
|
|
5567
|
+
);
|
|
5568
|
+
}
|
|
5569
|
+
return {
|
|
5570
|
+
entityObject,
|
|
5571
|
+
i18n: { ...DEFAULT_I18N, ...params.i18n || {} },
|
|
5572
|
+
enableSelection: Boolean(params.enableSelection),
|
|
5573
|
+
enableDragDrop: Boolean(params.enableDragDrop),
|
|
5574
|
+
useNewComponents: Boolean(params.useNewComponents),
|
|
5575
|
+
// RFC-0091: Configurable delay time for connection status check (default 15 minutes)
|
|
5576
|
+
delayTimeConnectionInMins: params.delayTimeConnectionInMins ?? DEFAUL_DELAY_TIME_CONNECTION_IN_MINS,
|
|
5577
|
+
// Debug options
|
|
5578
|
+
debugActive: params.debugActive ?? false,
|
|
5579
|
+
activeTooltipDebug: params.activeTooltipDebug ?? false,
|
|
5580
|
+
// LogHelper instance for this card
|
|
5581
|
+
LogHelper: LogHelper2,
|
|
5582
|
+
callbacks: {
|
|
5583
|
+
handleActionDashboard: params.handleActionDashboard,
|
|
5584
|
+
handleActionReport: params.handleActionReport,
|
|
5585
|
+
handleActionSettings: params.handleActionSettings,
|
|
5586
|
+
handleSelect: params.handleSelect,
|
|
5587
|
+
handInfo: params.handInfo,
|
|
5588
|
+
handleClickCard: params.handleClickCard
|
|
5589
|
+
}
|
|
5590
|
+
};
|
|
5591
|
+
}
|
|
5592
|
+
function getIconSvg(deviceType, domain) {
|
|
5593
|
+
if (domain === "water") {
|
|
5594
|
+
return Icons.waterDrop;
|
|
5011
5595
|
}
|
|
5012
5596
|
if (domain === "temperature") {
|
|
5013
5597
|
return Icons.thermometer;
|
|
@@ -5032,16 +5616,10 @@ function formatValueByDomain(value, domain) {
|
|
|
5032
5616
|
return formatWaterVolumeM3(value);
|
|
5033
5617
|
}
|
|
5034
5618
|
if (domain === "temperature") {
|
|
5035
|
-
return formatTemperature(value);
|
|
5619
|
+
return formatTemperature(value, 0);
|
|
5036
5620
|
}
|
|
5037
5621
|
return formatEnergy(value);
|
|
5038
5622
|
}
|
|
5039
|
-
function formatTemperature(temp) {
|
|
5040
|
-
if (temp === null || temp === void 0 || isNaN(temp)) {
|
|
5041
|
-
return "\u2014";
|
|
5042
|
-
}
|
|
5043
|
-
return `${temp.toFixed(0)}\xB0C`;
|
|
5044
|
-
}
|
|
5045
5623
|
function calculateConsumptionPercentage(target, consumption) {
|
|
5046
5624
|
const numericTarget = Number(target);
|
|
5047
5625
|
const numericConsumption = Number(consumption);
|
|
@@ -5056,32 +5634,32 @@ function getStatusInfo(deviceStatus, i18n, domain) {
|
|
|
5056
5634
|
// --- Novos Status de Temperatura ---
|
|
5057
5635
|
case "normal":
|
|
5058
5636
|
return { chipClass: "chip--ok", label: "Normal" };
|
|
5059
|
-
// Verde/Azul
|
|
5060
5637
|
case "cold":
|
|
5061
5638
|
return { chipClass: "chip--standby", label: "Frio" };
|
|
5062
|
-
// Azul claro/Ciano
|
|
5063
5639
|
case "hot":
|
|
5064
5640
|
return { chipClass: "chip--alert", label: "Quente" };
|
|
5065
|
-
//
|
|
5066
|
-
// --- Status Existentes ---
|
|
5641
|
+
// --- Status Existentes (aligned with getCardStateClass) ---
|
|
5067
5642
|
case DeviceStatusType.POWER_ON:
|
|
5068
5643
|
if (domain === "water") {
|
|
5069
|
-
return { chipClass: "chip--
|
|
5644
|
+
return { chipClass: "chip--power-on", label: i18n.in_operation_water };
|
|
5070
5645
|
}
|
|
5071
|
-
return { chipClass: "chip--
|
|
5646
|
+
return { chipClass: "chip--power-on", label: i18n.in_operation };
|
|
5072
5647
|
case DeviceStatusType.STANDBY:
|
|
5073
5648
|
return { chipClass: "chip--standby", label: i18n.standby };
|
|
5074
5649
|
case DeviceStatusType.WARNING:
|
|
5075
|
-
return { chipClass: "chip--
|
|
5650
|
+
return { chipClass: "chip--warning", label: i18n.alert };
|
|
5651
|
+
case DeviceStatusType.MAINTENANCE:
|
|
5652
|
+
return { chipClass: "chip--maintenance", label: i18n.maintenance };
|
|
5076
5653
|
case DeviceStatusType.FAILURE:
|
|
5077
|
-
case DeviceStatusType.POWER_OFF:
|
|
5078
5654
|
return { chipClass: "chip--failure", label: i18n.failure };
|
|
5079
|
-
case DeviceStatusType.
|
|
5080
|
-
return { chipClass: "chip--
|
|
5081
|
-
case DeviceStatusType.
|
|
5082
|
-
return { chipClass: "chip--offline", label: i18n.
|
|
5083
|
-
// Default (Cai aqui se não achar 'normal', 'hot' etc)
|
|
5655
|
+
case DeviceStatusType.POWER_OFF:
|
|
5656
|
+
return { chipClass: "chip--power-off", label: i18n.power_off || i18n.failure };
|
|
5657
|
+
case DeviceStatusType.OFFLINE:
|
|
5658
|
+
return { chipClass: "chip--offline", label: i18n.offline };
|
|
5084
5659
|
case DeviceStatusType.NO_INFO:
|
|
5660
|
+
return { chipClass: "chip--no-info", label: i18n.no_info || i18n.offline };
|
|
5661
|
+
case DeviceStatusType.NOT_INSTALLED:
|
|
5662
|
+
return { chipClass: "chip--not-installed", label: i18n.not_installed };
|
|
5085
5663
|
default:
|
|
5086
5664
|
return { chipClass: "chip--offline", label: i18n.offline };
|
|
5087
5665
|
}
|
|
@@ -5089,23 +5667,32 @@ function getStatusInfo(deviceStatus, i18n, domain) {
|
|
|
5089
5667
|
function getCardStateClass(deviceStatus) {
|
|
5090
5668
|
switch (deviceStatus) {
|
|
5091
5669
|
case DeviceStatusType.POWER_ON:
|
|
5092
|
-
return "is-
|
|
5670
|
+
return "is-power-on";
|
|
5093
5671
|
// Blue border
|
|
5094
5672
|
case DeviceStatusType.STANDBY:
|
|
5095
5673
|
return "is-standby";
|
|
5096
5674
|
// Green border
|
|
5097
5675
|
case DeviceStatusType.WARNING:
|
|
5676
|
+
return "is-warning";
|
|
5677
|
+
// Yellow border
|
|
5098
5678
|
case DeviceStatusType.MAINTENANCE:
|
|
5099
|
-
return "is-
|
|
5679
|
+
return "is-maintenance";
|
|
5100
5680
|
// Yellow border
|
|
5101
5681
|
case DeviceStatusType.FAILURE:
|
|
5102
|
-
case DeviceStatusType.POWER_OFF:
|
|
5103
5682
|
return "is-failure";
|
|
5104
|
-
// Red border
|
|
5683
|
+
// Dark Red border
|
|
5684
|
+
case DeviceStatusType.POWER_OFF:
|
|
5685
|
+
return "is-power-off";
|
|
5686
|
+
// Light Red border
|
|
5687
|
+
case DeviceStatusType.OFFLINE:
|
|
5688
|
+
return "is-offline";
|
|
5689
|
+
// Dark Gray border
|
|
5105
5690
|
case DeviceStatusType.NO_INFO:
|
|
5691
|
+
return "is-no-info";
|
|
5692
|
+
// Dark Orange border
|
|
5106
5693
|
case DeviceStatusType.NOT_INSTALLED:
|
|
5107
|
-
return "is-
|
|
5108
|
-
//
|
|
5694
|
+
return "is-not-installed";
|
|
5695
|
+
// Purple border
|
|
5109
5696
|
default:
|
|
5110
5697
|
return "";
|
|
5111
5698
|
}
|
|
@@ -5119,17 +5706,25 @@ function getStatusDotClass(deviceStatus) {
|
|
|
5119
5706
|
return "dot--standby";
|
|
5120
5707
|
case "hot":
|
|
5121
5708
|
return "dot--alert";
|
|
5122
|
-
// --- Status Existentes ---
|
|
5709
|
+
// --- Status Existentes (aligned with getCardStateClass) ---
|
|
5123
5710
|
case DeviceStatusType.POWER_ON:
|
|
5124
|
-
return "dot--
|
|
5711
|
+
return "dot--power-on";
|
|
5125
5712
|
case DeviceStatusType.STANDBY:
|
|
5126
5713
|
return "dot--standby";
|
|
5127
5714
|
case DeviceStatusType.WARNING:
|
|
5715
|
+
return "dot--warning";
|
|
5128
5716
|
case DeviceStatusType.MAINTENANCE:
|
|
5129
|
-
return "dot--
|
|
5717
|
+
return "dot--maintenance";
|
|
5130
5718
|
case DeviceStatusType.FAILURE:
|
|
5131
|
-
case DeviceStatusType.POWER_OFF:
|
|
5132
5719
|
return "dot--failure";
|
|
5720
|
+
case DeviceStatusType.POWER_OFF:
|
|
5721
|
+
return "dot--power-off";
|
|
5722
|
+
case DeviceStatusType.OFFLINE:
|
|
5723
|
+
return "dot--offline";
|
|
5724
|
+
case DeviceStatusType.NO_INFO:
|
|
5725
|
+
return "dot--no-info";
|
|
5726
|
+
case DeviceStatusType.NOT_INSTALLED:
|
|
5727
|
+
return "dot--not-installed";
|
|
5133
5728
|
default:
|
|
5134
5729
|
return "dot--offline";
|
|
5135
5730
|
}
|
|
@@ -5153,7 +5748,13 @@ function buildDOM(state) {
|
|
|
5153
5748
|
titleSection.className = "myio-ho-card__title";
|
|
5154
5749
|
const nameEl = document.createElement("div");
|
|
5155
5750
|
nameEl.className = "myio-ho-card__name";
|
|
5156
|
-
|
|
5751
|
+
const fullName = entityObject.labelOrName || "Unknown Device";
|
|
5752
|
+
if (fullName.length > LABEL_CHAR_LIMIT) {
|
|
5753
|
+
nameEl.textContent = fullName.slice(0, LABEL_CHAR_LIMIT) + "\u2026";
|
|
5754
|
+
nameEl.title = fullName;
|
|
5755
|
+
} else {
|
|
5756
|
+
nameEl.textContent = fullName;
|
|
5757
|
+
}
|
|
5157
5758
|
titleSection.appendChild(nameEl);
|
|
5158
5759
|
if (entityObject.deviceIdentifier) {
|
|
5159
5760
|
const codeEl = document.createElement("div");
|
|
@@ -5282,29 +5883,207 @@ function buildDOM(state) {
|
|
|
5282
5883
|
root.appendChild(footer);
|
|
5283
5884
|
return root;
|
|
5284
5885
|
}
|
|
5285
|
-
function
|
|
5886
|
+
function buildDebugTooltipInfo(entityObject, statusInfo, stateClass, statusDecisionSource, delayTimeConnectionInMins) {
|
|
5887
|
+
const formatTimestamp = (ts) => {
|
|
5888
|
+
if (!ts) return "N/A";
|
|
5889
|
+
const d = new Date(ts);
|
|
5890
|
+
return d.toLocaleString("pt-BR", {
|
|
5891
|
+
day: "2-digit",
|
|
5892
|
+
month: "2-digit",
|
|
5893
|
+
year: "numeric",
|
|
5894
|
+
hour: "2-digit",
|
|
5895
|
+
minute: "2-digit",
|
|
5896
|
+
second: "2-digit"
|
|
5897
|
+
});
|
|
5898
|
+
};
|
|
5899
|
+
return {
|
|
5900
|
+
// Entity identification
|
|
5901
|
+
entityId: entityObject.entityId || "N/A",
|
|
5902
|
+
name: entityObject.name || entityObject.nameEl || "N/A",
|
|
5903
|
+
domain: entityObject.domain || "energy",
|
|
5904
|
+
// Status decision chain
|
|
5905
|
+
originalDeviceStatus: entityObject._originalDeviceStatus || entityObject.deviceStatus,
|
|
5906
|
+
finalDeviceStatus: entityObject.deviceStatus,
|
|
5907
|
+
connectionStatus: entityObject.connectionStatus || "N/A",
|
|
5908
|
+
statusDecisionSource,
|
|
5909
|
+
// Visual output
|
|
5910
|
+
stateClass,
|
|
5911
|
+
chipClass: statusInfo.chipClass,
|
|
5912
|
+
chipLabel: statusInfo.label,
|
|
5913
|
+
// Connection timestamps
|
|
5914
|
+
lastConnectTime: formatTimestamp(entityObject.lastConnectTime),
|
|
5915
|
+
lastDisconnectTime: formatTimestamp(entityObject.lastDisconnectTime),
|
|
5916
|
+
delayTimeConnectionInMins,
|
|
5917
|
+
// Raw values
|
|
5918
|
+
val: entityObject.val,
|
|
5919
|
+
consumptionTargetValue: entityObject.consumptionTargetValue,
|
|
5920
|
+
deviceType: entityObject.deviceType || "N/A"
|
|
5921
|
+
};
|
|
5922
|
+
}
|
|
5923
|
+
function attachDebugTooltip(element, debugInfo) {
|
|
5924
|
+
const existingTooltip = element.querySelector(".debug-tooltip-container");
|
|
5925
|
+
if (existingTooltip) {
|
|
5926
|
+
existingTooltip.remove();
|
|
5927
|
+
}
|
|
5928
|
+
const tooltipContainer = document.createElement("div");
|
|
5929
|
+
tooltipContainer.className = "debug-tooltip-container";
|
|
5930
|
+
const tooltip = document.createElement("div");
|
|
5931
|
+
tooltip.className = "debug-tooltip";
|
|
5932
|
+
tooltip.innerHTML = `
|
|
5933
|
+
<div class="debug-tooltip__header">
|
|
5934
|
+
<span class="debug-tooltip__icon">\u{1F50D}</span>
|
|
5935
|
+
<span class="debug-tooltip__title">Debug Info</span>
|
|
5936
|
+
</div>
|
|
5937
|
+
<div class="debug-tooltip__content">
|
|
5938
|
+
<div class="debug-tooltip__section">
|
|
5939
|
+
<div class="debug-tooltip__section-title">\u{1F4CB} Identifica\xE7\xE3o</div>
|
|
5940
|
+
<div class="debug-tooltip__row">
|
|
5941
|
+
<span class="debug-tooltip__label">Entity ID:</span>
|
|
5942
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.entityId}</span>
|
|
5943
|
+
</div>
|
|
5944
|
+
<div class="debug-tooltip__row">
|
|
5945
|
+
<span class="debug-tooltip__label">Nome:</span>
|
|
5946
|
+
<span class="debug-tooltip__value">${debugInfo.name}</span>
|
|
5947
|
+
</div>
|
|
5948
|
+
<div class="debug-tooltip__row">
|
|
5949
|
+
<span class="debug-tooltip__label">Dom\xEDnio:</span>
|
|
5950
|
+
<span class="debug-tooltip__value debug-tooltip__badge debug-tooltip__badge--${debugInfo.domain}">${debugInfo.domain}</span>
|
|
5951
|
+
</div>
|
|
5952
|
+
</div>
|
|
5953
|
+
|
|
5954
|
+
<div class="debug-tooltip__section">
|
|
5955
|
+
<div class="debug-tooltip__section-title">\u26A1 Decis\xE3o de Status</div>
|
|
5956
|
+
<div class="debug-tooltip__row">
|
|
5957
|
+
<span class="debug-tooltip__label">connectionStatus:</span>
|
|
5958
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.connectionStatus}</span>
|
|
5959
|
+
</div>
|
|
5960
|
+
<div class="debug-tooltip__row">
|
|
5961
|
+
<span class="debug-tooltip__label">deviceStatus (final):</span>
|
|
5962
|
+
<span class="debug-tooltip__value debug-tooltip__badge">${debugInfo.finalDeviceStatus}</span>
|
|
5963
|
+
</div>
|
|
5964
|
+
<div class="debug-tooltip__row debug-tooltip__row--full">
|
|
5965
|
+
<span class="debug-tooltip__label">Fonte da decis\xE3o:</span>
|
|
5966
|
+
<span class="debug-tooltip__value debug-tooltip__value--highlight">${debugInfo.statusDecisionSource}</span>
|
|
5967
|
+
</div>
|
|
5968
|
+
</div>
|
|
5969
|
+
|
|
5970
|
+
<div class="debug-tooltip__section">
|
|
5971
|
+
<div class="debug-tooltip__section-title">\u{1F3A8} Output Visual</div>
|
|
5972
|
+
<div class="debug-tooltip__row">
|
|
5973
|
+
<span class="debug-tooltip__label">stateClass:</span>
|
|
5974
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.stateClass}</span>
|
|
5975
|
+
</div>
|
|
5976
|
+
<div class="debug-tooltip__row">
|
|
5977
|
+
<span class="debug-tooltip__label">chipClass:</span>
|
|
5978
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.chipClass}</span>
|
|
5979
|
+
</div>
|
|
5980
|
+
<div class="debug-tooltip__row">
|
|
5981
|
+
<span class="debug-tooltip__label">chipLabel:</span>
|
|
5982
|
+
<span class="debug-tooltip__value">${debugInfo.chipLabel}</span>
|
|
5983
|
+
</div>
|
|
5984
|
+
</div>
|
|
5985
|
+
|
|
5986
|
+
<div class="debug-tooltip__section">
|
|
5987
|
+
<div class="debug-tooltip__section-title">\u{1F550} Timestamps de Conex\xE3o</div>
|
|
5988
|
+
<div class="debug-tooltip__row">
|
|
5989
|
+
<span class="debug-tooltip__label">lastConnectTime:</span>
|
|
5990
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.lastConnectTime}</span>
|
|
5991
|
+
</div>
|
|
5992
|
+
<div class="debug-tooltip__row">
|
|
5993
|
+
<span class="debug-tooltip__label">lastDisconnectTime:</span>
|
|
5994
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.lastDisconnectTime}</span>
|
|
5995
|
+
</div>
|
|
5996
|
+
<div class="debug-tooltip__row">
|
|
5997
|
+
<span class="debug-tooltip__label">delayTime:</span>
|
|
5998
|
+
<span class="debug-tooltip__value">${debugInfo.delayTimeConnectionInMins} mins</span>
|
|
5999
|
+
</div>
|
|
6000
|
+
</div>
|
|
6001
|
+
|
|
6002
|
+
<div class="debug-tooltip__section">
|
|
6003
|
+
<div class="debug-tooltip__section-title">\u{1F4CA} Valores</div>
|
|
6004
|
+
<div class="debug-tooltip__row">
|
|
6005
|
+
<span class="debug-tooltip__label">val (consumo):</span>
|
|
6006
|
+
<span class="debug-tooltip__value">${debugInfo.val ?? "N/A"}</span>
|
|
6007
|
+
</div>
|
|
6008
|
+
<div class="debug-tooltip__row">
|
|
6009
|
+
<span class="debug-tooltip__label">target (meta):</span>
|
|
6010
|
+
<span class="debug-tooltip__value">${debugInfo.consumptionTargetValue ?? "N/A"}</span>
|
|
6011
|
+
</div>
|
|
6012
|
+
<div class="debug-tooltip__row">
|
|
6013
|
+
<span class="debug-tooltip__label">deviceType:</span>
|
|
6014
|
+
<span class="debug-tooltip__value debug-tooltip__value--mono">${debugInfo.deviceType}</span>
|
|
6015
|
+
</div>
|
|
6016
|
+
</div>
|
|
6017
|
+
</div>
|
|
6018
|
+
`;
|
|
6019
|
+
tooltipContainer.appendChild(tooltip);
|
|
6020
|
+
element.style.position = "relative";
|
|
6021
|
+
element.style.cursor = "help";
|
|
6022
|
+
element.appendChild(tooltipContainer);
|
|
6023
|
+
element.classList.add("has-debug-tooltip");
|
|
6024
|
+
}
|
|
6025
|
+
function verifyOfflineStatus(entityObject, delayTimeInMins = 15, LogHelper2) {
|
|
5286
6026
|
const lastConnectionTime = new Date(entityObject.lastConnectTime || 0);
|
|
5287
6027
|
const lastDisconnectTime = new Date(entityObject.lastDisconnectTime || 0);
|
|
5288
6028
|
const now = /* @__PURE__ */ new Date();
|
|
5289
6029
|
const delayTimeInMs = delayTimeInMins * 60 * 1e3;
|
|
5290
6030
|
const timeSinceConnection = now.getTime() - lastConnectionTime.getTime();
|
|
6031
|
+
let isOffline = false;
|
|
5291
6032
|
if (lastDisconnectTime.getTime() > lastConnectionTime.getTime()) {
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
6033
|
+
isOffline = true;
|
|
6034
|
+
LogHelper2.log(
|
|
6035
|
+
"[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastDisconnectTime is more recent than lastConnectTime",
|
|
6036
|
+
entityObject.nameEl
|
|
6037
|
+
);
|
|
6038
|
+
} else if (timeSinceConnection > delayTimeInMs) {
|
|
6039
|
+
isOffline = true;
|
|
6040
|
+
LogHelper2.log(
|
|
6041
|
+
"[CardHeadOffice][ConnectionStatus Verify] Device is OFFLINE because lastConnectTime is older than configured delayTimeConnectionInMins:",
|
|
6042
|
+
delayTimeInMins,
|
|
6043
|
+
"for device",
|
|
6044
|
+
entityObject.nameEl
|
|
6045
|
+
);
|
|
6046
|
+
} else {
|
|
6047
|
+
isOffline = false;
|
|
6048
|
+
LogHelper2.log(
|
|
6049
|
+
"[CardHeadOffice][ConnectionStatus Verify] Device is ONLINE because lastConnectTime is within configured delayTimeConnectionInMins:",
|
|
6050
|
+
delayTimeInMins,
|
|
6051
|
+
"for device",
|
|
6052
|
+
entityObject.nameEl
|
|
6053
|
+
);
|
|
5296
6054
|
}
|
|
5297
|
-
return
|
|
6055
|
+
return isOffline;
|
|
5298
6056
|
}
|
|
5299
6057
|
function paint(root, state) {
|
|
5300
|
-
const { entityObject, i18n, delayTimeConnectionInMins, isSelected } = state;
|
|
6058
|
+
const { entityObject, i18n, delayTimeConnectionInMins, isSelected, LogHelper: LogHelper2, activeTooltipDebug } = state;
|
|
6059
|
+
let statusDecisionSource = "unknown";
|
|
5301
6060
|
if (entityObject.connectionStatus) {
|
|
5302
6061
|
if (entityObject.connectionStatus === "offline") {
|
|
5303
|
-
|
|
6062
|
+
LogHelper2.log(
|
|
6063
|
+
"[CardHeadOffice][ConnectionStatus Verify 01] Setting deviceStatus to OFFLINE based on connectionStatus"
|
|
6064
|
+
);
|
|
6065
|
+
entityObject.deviceStatus = DeviceStatusType.OFFLINE;
|
|
6066
|
+
statusDecisionSource = 'connectionStatus === "offline"';
|
|
6067
|
+
} else {
|
|
6068
|
+
LogHelper2.log(
|
|
6069
|
+
"[CardHeadOffice] Device is ONLINE or WAITING based on connectionStatus for device",
|
|
6070
|
+
entityObject.nameEl
|
|
6071
|
+
);
|
|
6072
|
+
statusDecisionSource = `connectionStatus === "${entityObject.connectionStatus}" (kept original deviceStatus)`;
|
|
5304
6073
|
}
|
|
5305
6074
|
} else {
|
|
5306
|
-
if (verifyOfflineStatus(entityObject, delayTimeConnectionInMins) === false) {
|
|
5307
|
-
|
|
6075
|
+
if (verifyOfflineStatus(entityObject, delayTimeConnectionInMins, LogHelper2) === false) {
|
|
6076
|
+
LogHelper2.log(
|
|
6077
|
+
"[CardHeadOffice][ConnectionStatus Verify 02] Setting deviceStatus to OFFLINE based on timestamp verification by verifyOfflineStatus METHOD with delayTimeConnectionInMins:",
|
|
6078
|
+
delayTimeConnectionInMins
|
|
6079
|
+
);
|
|
6080
|
+
entityObject.deviceStatus = DeviceStatusType.OFFLINE;
|
|
6081
|
+
statusDecisionSource = `verifyOfflineStatus() returned false (delay: ${delayTimeConnectionInMins} mins)`;
|
|
6082
|
+
} else {
|
|
6083
|
+
LogHelper2.log(
|
|
6084
|
+
`[CardHeadOffice][ConnectionStatus Verify 03] Device is ONLINE with deviceStatus = ${entityObject.deviceStatus} based on timestamp verification for device ${entityObject.nameEl}`
|
|
6085
|
+
);
|
|
6086
|
+
statusDecisionSource = `verifyOfflineStatus() returned true (delay: ${delayTimeConnectionInMins} mins)`;
|
|
5308
6087
|
}
|
|
5309
6088
|
}
|
|
5310
6089
|
const stateClass = getCardStateClass(entityObject.deviceStatus);
|
|
@@ -5313,6 +6092,10 @@ function paint(root, state) {
|
|
|
5313
6092
|
const chip = root.querySelector(".chip");
|
|
5314
6093
|
chip.className = `chip ${statusInfo.chipClass}`;
|
|
5315
6094
|
chip.innerHTML = statusInfo.label;
|
|
6095
|
+
if (activeTooltipDebug) {
|
|
6096
|
+
const debugInfo = buildDebugTooltipInfo(entityObject, statusInfo, stateClass, statusDecisionSource, delayTimeConnectionInMins);
|
|
6097
|
+
attachDebugTooltip(chip, debugInfo);
|
|
6098
|
+
}
|
|
5316
6099
|
const primaryValue = formatValueByDomain(entityObject.val, entityObject.domain);
|
|
5317
6100
|
const numSpan = root.querySelector(".myio-ho-card__value .num");
|
|
5318
6101
|
const unitSpan = root.querySelector(".myio-ho-card__value .unit");
|
|
@@ -5525,6 +6308,7 @@ function renderCardComponentHeadOffice(containerEl, params) {
|
|
|
5525
6308
|
}
|
|
5526
6309
|
|
|
5527
6310
|
// src/thingsboard/main-dashboard-shopping/v-5.2.0/card/template-card-v5.js
|
|
6311
|
+
var LABEL_CHAR_LIMIT2 = 18;
|
|
5528
6312
|
function renderCardComponentV5({
|
|
5529
6313
|
entityObject,
|
|
5530
6314
|
handleActionDashboard,
|
|
@@ -6041,7 +6825,7 @@ ${rangeText}`;
|
|
|
6041
6825
|
|
|
6042
6826
|
<div class="device-title-row" style="flex-direction: column; min-height: 38px; text-align: center; width: 100%;">
|
|
6043
6827
|
<span class="device-title" title="${cardEntity.name}">
|
|
6044
|
-
${cardEntity.name.length >
|
|
6828
|
+
${cardEntity.name.length > LABEL_CHAR_LIMIT2 ? cardEntity.name.slice(0, LABEL_CHAR_LIMIT2) + "\u2026" : cardEntity.name}
|
|
6045
6829
|
</span>
|
|
6046
6830
|
${deviceIdentifier ? `
|
|
6047
6831
|
<span class="device-subtitle" title="${deviceIdentifier}">
|
|
@@ -15981,23 +16765,1019 @@ function validateOptions2(options) {
|
|
|
15981
16765
|
if (isNaN(level) || level < 0 || level > 100) {
|
|
15982
16766
|
errors.push("currentLevel must be a number between 0 and 100");
|
|
15983
16767
|
}
|
|
15984
|
-
}
|
|
15985
|
-
if (options.limit !== void 0) {
|
|
15986
|
-
const limit = Number(options.limit);
|
|
15987
|
-
if (isNaN(limit) || limit < 1 || limit > 1e4) {
|
|
15988
|
-
errors.push("limit must be a number between 1 and 10000");
|
|
16768
|
+
}
|
|
16769
|
+
if (options.limit !== void 0) {
|
|
16770
|
+
const limit = Number(options.limit);
|
|
16771
|
+
if (isNaN(limit) || limit < 1 || limit > 1e4) {
|
|
16772
|
+
errors.push("limit must be a number between 1 and 10000");
|
|
16773
|
+
}
|
|
16774
|
+
}
|
|
16775
|
+
if (options.aggregation !== void 0) {
|
|
16776
|
+
const validAggregations = ["NONE", "MIN", "MAX", "AVG", "SUM", "COUNT"];
|
|
16777
|
+
if (!validAggregations.includes(options.aggregation)) {
|
|
16778
|
+
errors.push(`aggregation must be one of: ${validAggregations.join(", ")}`);
|
|
16779
|
+
}
|
|
16780
|
+
}
|
|
16781
|
+
if (errors.length > 0) {
|
|
16782
|
+
throw new Error(`Validation failed:
|
|
16783
|
+
- ${errors.join("\n- ")}`);
|
|
16784
|
+
}
|
|
16785
|
+
}
|
|
16786
|
+
|
|
16787
|
+
// src/components/premium-modals/power-limits/types.ts
|
|
16788
|
+
var DEVICE_TYPES = [
|
|
16789
|
+
{ value: "ELEVADOR", label: "Elevator" },
|
|
16790
|
+
{ value: "ESCADA_ROLANTE", label: "Escalator" },
|
|
16791
|
+
{ value: "MOTOR", label: "Motor" },
|
|
16792
|
+
{ value: "BOMBA", label: "Pump" },
|
|
16793
|
+
{ value: "CHILLER", label: "Chiller" },
|
|
16794
|
+
{ value: "AR_CONDICIONADO", label: "Air Conditioner" },
|
|
16795
|
+
{ value: "HVAC", label: "HVAC" },
|
|
16796
|
+
{ value: "FANCOIL", label: "Fancoil" },
|
|
16797
|
+
{ value: "3F_MEDIDOR", label: "Three-phase Meter" }
|
|
16798
|
+
];
|
|
16799
|
+
var TELEMETRY_TYPES2 = [
|
|
16800
|
+
{ value: "consumption", label: "Consumption (kW)", unit: "kW" },
|
|
16801
|
+
{ value: "voltage_a", label: "Voltage A (V)", unit: "V" },
|
|
16802
|
+
{ value: "voltage_b", label: "Voltage B (V)", unit: "V" },
|
|
16803
|
+
{ value: "voltage_c", label: "Voltage C (V)", unit: "V" },
|
|
16804
|
+
{ value: "current_a", label: "Current A (A)", unit: "A" },
|
|
16805
|
+
{ value: "current_b", label: "Current B (A)", unit: "A" },
|
|
16806
|
+
{ value: "current_c", label: "Current C (A)", unit: "A" },
|
|
16807
|
+
{ value: "total_current", label: "Total Current (A)", unit: "A" },
|
|
16808
|
+
{ value: "fp_a", label: "Power Factor A", unit: "" },
|
|
16809
|
+
{ value: "fp_b", label: "Power Factor B", unit: "" },
|
|
16810
|
+
{ value: "fp_c", label: "Power Factor C", unit: "" }
|
|
16811
|
+
];
|
|
16812
|
+
var STATUS_CONFIG = {
|
|
16813
|
+
standBy: { label: "StandBy", color: "#22c55e", bgColor: "rgba(34, 197, 94, 0.1)" },
|
|
16814
|
+
normal: { label: "Normal", color: "#3b82f6", bgColor: "rgba(59, 130, 246, 0.1)" },
|
|
16815
|
+
alert: { label: "Alert", color: "#f59e0b", bgColor: "rgba(245, 158, 11, 0.1)" },
|
|
16816
|
+
failure: { label: "Failure", color: "#ef4444", bgColor: "rgba(239, 68, 68, 0.1)" }
|
|
16817
|
+
};
|
|
16818
|
+
|
|
16819
|
+
// src/components/premium-modals/power-limits/PowerLimitsModalView.ts
|
|
16820
|
+
var PowerLimitsModalView = class {
|
|
16821
|
+
container = null;
|
|
16822
|
+
overlayEl = null;
|
|
16823
|
+
config;
|
|
16824
|
+
formData;
|
|
16825
|
+
isLoading = false;
|
|
16826
|
+
isSaving = false;
|
|
16827
|
+
constructor(config) {
|
|
16828
|
+
this.config = config;
|
|
16829
|
+
this.formData = {
|
|
16830
|
+
deviceType: config.deviceType,
|
|
16831
|
+
telemetryType: config.telemetryType,
|
|
16832
|
+
standby: { baseValue: null, topValue: null },
|
|
16833
|
+
normal: { baseValue: null, topValue: null },
|
|
16834
|
+
alert: { baseValue: null, topValue: null },
|
|
16835
|
+
failure: { baseValue: null, topValue: null }
|
|
16836
|
+
};
|
|
16837
|
+
}
|
|
16838
|
+
render(targetContainer) {
|
|
16839
|
+
this.overlayEl = document.createElement("div");
|
|
16840
|
+
this.overlayEl.className = "myio-power-limits-overlay";
|
|
16841
|
+
this.overlayEl.innerHTML = `
|
|
16842
|
+
<style>${this.getStyles()}</style>
|
|
16843
|
+
<div class="myio-power-limits-card">
|
|
16844
|
+
${this.renderHeader()}
|
|
16845
|
+
${this.renderSelectors()}
|
|
16846
|
+
${this.renderStatusCards()}
|
|
16847
|
+
${this.renderLoadingState()}
|
|
16848
|
+
${this.renderErrorState()}
|
|
16849
|
+
${this.renderSuccessState()}
|
|
16850
|
+
</div>
|
|
16851
|
+
`;
|
|
16852
|
+
const target = targetContainer || document.body;
|
|
16853
|
+
target.appendChild(this.overlayEl);
|
|
16854
|
+
this.container = this.overlayEl.querySelector(".myio-power-limits-card");
|
|
16855
|
+
this.setupEventListeners();
|
|
16856
|
+
requestAnimationFrame(() => {
|
|
16857
|
+
this.overlayEl?.classList.add("active");
|
|
16858
|
+
});
|
|
16859
|
+
return this.overlayEl;
|
|
16860
|
+
}
|
|
16861
|
+
renderHeader() {
|
|
16862
|
+
return `
|
|
16863
|
+
<div class="myio-power-limits-header">
|
|
16864
|
+
<div class="myio-power-limits-title-section">
|
|
16865
|
+
<span class="myio-power-limits-icon">⚙</span>
|
|
16866
|
+
<h2 class="myio-power-limits-title">Power Limits Setup</h2>
|
|
16867
|
+
</div>
|
|
16868
|
+
<div class="myio-power-limits-actions">
|
|
16869
|
+
<button class="myio-btn myio-btn-primary" id="plm-save-btn" type="button">
|
|
16870
|
+
<span class="myio-btn-text">Save</span>
|
|
16871
|
+
<span class="myio-btn-spinner" style="display: none;"></span>
|
|
16872
|
+
</button>
|
|
16873
|
+
<button class="myio-btn myio-btn-secondary" id="plm-reset-btn" type="button">Reset</button>
|
|
16874
|
+
<button class="myio-btn myio-btn-close" id="plm-close-btn" type="button" aria-label="Close">×</button>
|
|
16875
|
+
</div>
|
|
16876
|
+
</div>
|
|
16877
|
+
`;
|
|
16878
|
+
}
|
|
16879
|
+
renderSelectors() {
|
|
16880
|
+
const deviceOptions = DEVICE_TYPES.map(
|
|
16881
|
+
(dt) => `<option value="${dt.value}" ${dt.value === this.config.deviceType ? "selected" : ""}>${dt.label}</option>`
|
|
16882
|
+
).join("");
|
|
16883
|
+
const telemetryOptions = TELEMETRY_TYPES2.map(
|
|
16884
|
+
(tt) => `<option value="${tt.value}" ${tt.value === this.config.telemetryType ? "selected" : ""}>${tt.label}</option>`
|
|
16885
|
+
).join("");
|
|
16886
|
+
return `
|
|
16887
|
+
<div class="myio-power-limits-selectors">
|
|
16888
|
+
<div class="myio-form-group">
|
|
16889
|
+
<label for="plm-device-type">Device Type</label>
|
|
16890
|
+
<select id="plm-device-type" class="myio-select">
|
|
16891
|
+
${deviceOptions}
|
|
16892
|
+
</select>
|
|
16893
|
+
</div>
|
|
16894
|
+
<div class="myio-form-group">
|
|
16895
|
+
<label for="plm-telemetry-type">Telemetry Type</label>
|
|
16896
|
+
<select id="plm-telemetry-type" class="myio-select">
|
|
16897
|
+
${telemetryOptions}
|
|
16898
|
+
</select>
|
|
16899
|
+
</div>
|
|
16900
|
+
</div>
|
|
16901
|
+
`;
|
|
16902
|
+
}
|
|
16903
|
+
renderStatusCards() {
|
|
16904
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
16905
|
+
const cards = statuses.map((status) => {
|
|
16906
|
+
const config = STATUS_CONFIG[status === "standby" ? "standBy" : status];
|
|
16907
|
+
const formValues = this.formData[status];
|
|
16908
|
+
return `
|
|
16909
|
+
<div class="myio-power-limits-card-item myio-status-${status}" style="--status-color: ${config.color}; --status-bg: ${config.bgColor};">
|
|
16910
|
+
<div class="myio-card-header">
|
|
16911
|
+
<span class="myio-status-indicator"></span>
|
|
16912
|
+
<span class="myio-status-label">${config.label}</span>
|
|
16913
|
+
</div>
|
|
16914
|
+
<div class="myio-card-inputs">
|
|
16915
|
+
<div class="myio-input-group">
|
|
16916
|
+
<label for="plm-${status}-base">Base Value</label>
|
|
16917
|
+
<input
|
|
16918
|
+
type="number"
|
|
16919
|
+
id="plm-${status}-base"
|
|
16920
|
+
class="myio-input"
|
|
16921
|
+
min="0"
|
|
16922
|
+
step="0.01"
|
|
16923
|
+
value="${formValues.baseValue ?? ""}"
|
|
16924
|
+
placeholder="0"
|
|
16925
|
+
>
|
|
16926
|
+
</div>
|
|
16927
|
+
<div class="myio-input-group">
|
|
16928
|
+
<label for="plm-${status}-top">Top Value</label>
|
|
16929
|
+
<input
|
|
16930
|
+
type="number"
|
|
16931
|
+
id="plm-${status}-top"
|
|
16932
|
+
class="myio-input"
|
|
16933
|
+
min="0"
|
|
16934
|
+
step="0.01"
|
|
16935
|
+
value="${formValues.topValue ?? ""}"
|
|
16936
|
+
placeholder="0"
|
|
16937
|
+
>
|
|
16938
|
+
</div>
|
|
16939
|
+
</div>
|
|
16940
|
+
</div>
|
|
16941
|
+
`;
|
|
16942
|
+
}).join("");
|
|
16943
|
+
return `
|
|
16944
|
+
<div class="myio-power-limits-grid" id="plm-grid">
|
|
16945
|
+
${cards}
|
|
16946
|
+
</div>
|
|
16947
|
+
`;
|
|
16948
|
+
}
|
|
16949
|
+
renderLoadingState() {
|
|
16950
|
+
return `
|
|
16951
|
+
<div class="myio-power-limits-loading" id="plm-loading" style="display: none;">
|
|
16952
|
+
<div class="myio-spinner"></div>
|
|
16953
|
+
<span>Loading configuration...</span>
|
|
16954
|
+
</div>
|
|
16955
|
+
`;
|
|
16956
|
+
}
|
|
16957
|
+
renderErrorState() {
|
|
16958
|
+
return `
|
|
16959
|
+
<div class="myio-power-limits-error" id="plm-error" style="display: none;">
|
|
16960
|
+
<span class="myio-error-icon">⚠</span>
|
|
16961
|
+
<span class="myio-error-message" id="plm-error-msg"></span>
|
|
16962
|
+
</div>
|
|
16963
|
+
`;
|
|
16964
|
+
}
|
|
16965
|
+
renderSuccessState() {
|
|
16966
|
+
return `
|
|
16967
|
+
<div class="myio-power-limits-success" id="plm-success" style="display: none;">
|
|
16968
|
+
<span class="myio-success-icon">✓</span>
|
|
16969
|
+
<span class="myio-success-message">Configuration saved successfully!</span>
|
|
16970
|
+
</div>
|
|
16971
|
+
`;
|
|
16972
|
+
}
|
|
16973
|
+
setupEventListeners() {
|
|
16974
|
+
if (!this.overlayEl) return;
|
|
16975
|
+
const closeBtn = this.overlayEl.querySelector("#plm-close-btn");
|
|
16976
|
+
closeBtn?.addEventListener("click", () => this.close());
|
|
16977
|
+
this.overlayEl.addEventListener("click", (e) => {
|
|
16978
|
+
if (e.target === this.overlayEl) {
|
|
16979
|
+
this.close();
|
|
16980
|
+
}
|
|
16981
|
+
});
|
|
16982
|
+
document.addEventListener("keydown", this.handleKeyDown);
|
|
16983
|
+
const saveBtn = this.overlayEl.querySelector("#plm-save-btn");
|
|
16984
|
+
saveBtn?.addEventListener("click", () => this.handleSave());
|
|
16985
|
+
const resetBtn = this.overlayEl.querySelector("#plm-reset-btn");
|
|
16986
|
+
resetBtn?.addEventListener("click", () => this.handleReset());
|
|
16987
|
+
const deviceSelect = this.overlayEl.querySelector("#plm-device-type");
|
|
16988
|
+
deviceSelect?.addEventListener("change", (e) => {
|
|
16989
|
+
const value = e.target.value;
|
|
16990
|
+
this.formData.deviceType = value;
|
|
16991
|
+
this.config.onDeviceTypeChange(value);
|
|
16992
|
+
});
|
|
16993
|
+
const telemetrySelect = this.overlayEl.querySelector("#plm-telemetry-type");
|
|
16994
|
+
telemetrySelect?.addEventListener("change", (e) => {
|
|
16995
|
+
const value = e.target.value;
|
|
16996
|
+
this.formData.telemetryType = value;
|
|
16997
|
+
this.config.onTelemetryTypeChange(value);
|
|
16998
|
+
});
|
|
16999
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
17000
|
+
statuses.forEach((status) => {
|
|
17001
|
+
const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
|
|
17002
|
+
const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
|
|
17003
|
+
baseInput?.addEventListener("input", (e) => {
|
|
17004
|
+
const value = e.target.value;
|
|
17005
|
+
this.formData[status].baseValue = value ? parseFloat(value) : null;
|
|
17006
|
+
});
|
|
17007
|
+
topInput?.addEventListener("input", (e) => {
|
|
17008
|
+
const value = e.target.value;
|
|
17009
|
+
this.formData[status].topValue = value ? parseFloat(value) : null;
|
|
17010
|
+
});
|
|
17011
|
+
});
|
|
17012
|
+
}
|
|
17013
|
+
handleKeyDown = (e) => {
|
|
17014
|
+
if (e.key === "Escape") {
|
|
17015
|
+
this.close();
|
|
17016
|
+
}
|
|
17017
|
+
};
|
|
17018
|
+
async handleSave() {
|
|
17019
|
+
if (this.isSaving) return;
|
|
17020
|
+
const validationError = this.validateForm();
|
|
17021
|
+
if (validationError) {
|
|
17022
|
+
this.showError(validationError);
|
|
17023
|
+
return;
|
|
17024
|
+
}
|
|
17025
|
+
this.isSaving = true;
|
|
17026
|
+
this.showSaveLoading(true);
|
|
17027
|
+
this.hideError();
|
|
17028
|
+
this.hideSuccess();
|
|
17029
|
+
try {
|
|
17030
|
+
await this.config.onSave();
|
|
17031
|
+
this.showSuccess();
|
|
17032
|
+
setTimeout(() => this.hideSuccess(), 3e3);
|
|
17033
|
+
} catch (error) {
|
|
17034
|
+
this.showError(error.message || "Failed to save configuration");
|
|
17035
|
+
} finally {
|
|
17036
|
+
this.isSaving = false;
|
|
17037
|
+
this.showSaveLoading(false);
|
|
17038
|
+
}
|
|
17039
|
+
}
|
|
17040
|
+
handleReset() {
|
|
17041
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
17042
|
+
statuses.forEach((status) => {
|
|
17043
|
+
const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
|
|
17044
|
+
const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
|
|
17045
|
+
if (baseInput) baseInput.value = "";
|
|
17046
|
+
if (topInput) topInput.value = "";
|
|
17047
|
+
this.formData[status] = { baseValue: null, topValue: null };
|
|
17048
|
+
});
|
|
17049
|
+
this.hideError();
|
|
17050
|
+
this.hideSuccess();
|
|
17051
|
+
}
|
|
17052
|
+
validateForm() {
|
|
17053
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
17054
|
+
for (const status of statuses) {
|
|
17055
|
+
const base = this.formData[status].baseValue;
|
|
17056
|
+
const top = this.formData[status].topValue;
|
|
17057
|
+
if (base !== null && base < 0) {
|
|
17058
|
+
return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value cannot be negative`;
|
|
17059
|
+
}
|
|
17060
|
+
if (top !== null && top < 0) {
|
|
17061
|
+
return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Top value cannot be negative`;
|
|
17062
|
+
}
|
|
17063
|
+
if (base !== null && top !== null && base > top) {
|
|
17064
|
+
return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value should not exceed top value`;
|
|
17065
|
+
}
|
|
17066
|
+
}
|
|
17067
|
+
return null;
|
|
17068
|
+
}
|
|
17069
|
+
close() {
|
|
17070
|
+
document.removeEventListener("keydown", this.handleKeyDown);
|
|
17071
|
+
if (this.overlayEl) {
|
|
17072
|
+
this.overlayEl.classList.remove("active");
|
|
17073
|
+
setTimeout(() => {
|
|
17074
|
+
this.overlayEl?.remove();
|
|
17075
|
+
this.overlayEl = null;
|
|
17076
|
+
this.container = null;
|
|
17077
|
+
this.config.onClose();
|
|
17078
|
+
}, 300);
|
|
17079
|
+
}
|
|
17080
|
+
}
|
|
17081
|
+
destroy() {
|
|
17082
|
+
document.removeEventListener("keydown", this.handleKeyDown);
|
|
17083
|
+
this.overlayEl?.remove();
|
|
17084
|
+
this.overlayEl = null;
|
|
17085
|
+
this.container = null;
|
|
17086
|
+
}
|
|
17087
|
+
showLoading() {
|
|
17088
|
+
this.isLoading = true;
|
|
17089
|
+
const loadingEl = this.overlayEl?.querySelector("#plm-loading");
|
|
17090
|
+
const gridEl = this.overlayEl?.querySelector("#plm-grid");
|
|
17091
|
+
if (loadingEl) loadingEl.style.display = "flex";
|
|
17092
|
+
if (gridEl) gridEl.style.opacity = "0.5";
|
|
17093
|
+
}
|
|
17094
|
+
hideLoading() {
|
|
17095
|
+
this.isLoading = false;
|
|
17096
|
+
const loadingEl = this.overlayEl?.querySelector("#plm-loading");
|
|
17097
|
+
const gridEl = this.overlayEl?.querySelector("#plm-grid");
|
|
17098
|
+
if (loadingEl) loadingEl.style.display = "none";
|
|
17099
|
+
if (gridEl) gridEl.style.opacity = "1";
|
|
17100
|
+
}
|
|
17101
|
+
showSaveLoading(show) {
|
|
17102
|
+
const saveBtn = this.overlayEl?.querySelector("#plm-save-btn");
|
|
17103
|
+
const btnText = saveBtn?.querySelector(".myio-btn-text");
|
|
17104
|
+
const btnSpinner = saveBtn?.querySelector(".myio-btn-spinner");
|
|
17105
|
+
if (saveBtn) saveBtn.disabled = show;
|
|
17106
|
+
if (btnText) btnText.style.display = show ? "none" : "inline";
|
|
17107
|
+
if (btnSpinner) btnSpinner.style.display = show ? "inline-block" : "none";
|
|
17108
|
+
}
|
|
17109
|
+
showError(message) {
|
|
17110
|
+
const errorEl = this.overlayEl?.querySelector("#plm-error");
|
|
17111
|
+
const errorMsg = this.overlayEl?.querySelector("#plm-error-msg");
|
|
17112
|
+
if (errorEl) errorEl.style.display = "flex";
|
|
17113
|
+
if (errorMsg) errorMsg.textContent = message;
|
|
17114
|
+
}
|
|
17115
|
+
hideError() {
|
|
17116
|
+
const errorEl = this.overlayEl?.querySelector("#plm-error");
|
|
17117
|
+
if (errorEl) errorEl.style.display = "none";
|
|
17118
|
+
}
|
|
17119
|
+
showSuccess() {
|
|
17120
|
+
const successEl = this.overlayEl?.querySelector("#plm-success");
|
|
17121
|
+
if (successEl) successEl.style.display = "flex";
|
|
17122
|
+
}
|
|
17123
|
+
hideSuccess() {
|
|
17124
|
+
const successEl = this.overlayEl?.querySelector("#plm-success");
|
|
17125
|
+
if (successEl) successEl.style.display = "none";
|
|
17126
|
+
}
|
|
17127
|
+
getFormData() {
|
|
17128
|
+
return { ...this.formData };
|
|
17129
|
+
}
|
|
17130
|
+
setFormData(data) {
|
|
17131
|
+
if (data.deviceType) this.formData.deviceType = data.deviceType;
|
|
17132
|
+
if (data.telemetryType) this.formData.telemetryType = data.telemetryType;
|
|
17133
|
+
if (data.standby) this.formData.standby = { ...data.standby };
|
|
17134
|
+
if (data.normal) this.formData.normal = { ...data.normal };
|
|
17135
|
+
if (data.alert) this.formData.alert = { ...data.alert };
|
|
17136
|
+
if (data.failure) this.formData.failure = { ...data.failure };
|
|
17137
|
+
this.updateInputValues();
|
|
17138
|
+
}
|
|
17139
|
+
updateInputValues() {
|
|
17140
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
17141
|
+
statuses.forEach((status) => {
|
|
17142
|
+
const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
|
|
17143
|
+
const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
|
|
17144
|
+
if (baseInput) {
|
|
17145
|
+
baseInput.value = this.formData[status].baseValue?.toString() ?? "";
|
|
17146
|
+
}
|
|
17147
|
+
if (topInput) {
|
|
17148
|
+
topInput.value = this.formData[status].topValue?.toString() ?? "";
|
|
17149
|
+
}
|
|
17150
|
+
});
|
|
17151
|
+
const deviceSelect = this.overlayEl?.querySelector("#plm-device-type");
|
|
17152
|
+
const telemetrySelect = this.overlayEl?.querySelector("#plm-telemetry-type");
|
|
17153
|
+
if (deviceSelect) deviceSelect.value = this.formData.deviceType;
|
|
17154
|
+
if (telemetrySelect) telemetrySelect.value = this.formData.telemetryType;
|
|
17155
|
+
}
|
|
17156
|
+
getStyles() {
|
|
17157
|
+
const styles = this.config.styles || {};
|
|
17158
|
+
const primaryColor = styles.primaryColor || "#4A148C";
|
|
17159
|
+
const successColor = styles.successColor || "#22c55e";
|
|
17160
|
+
const warningColor = styles.warningColor || "#f59e0b";
|
|
17161
|
+
const dangerColor = styles.dangerColor || "#ef4444";
|
|
17162
|
+
const infoColor = styles.infoColor || "#3b82f6";
|
|
17163
|
+
return `
|
|
17164
|
+
.myio-power-limits-overlay {
|
|
17165
|
+
position: fixed;
|
|
17166
|
+
top: 0;
|
|
17167
|
+
left: 0;
|
|
17168
|
+
right: 0;
|
|
17169
|
+
bottom: 0;
|
|
17170
|
+
background: rgba(0, 0, 0, 0.6);
|
|
17171
|
+
display: flex;
|
|
17172
|
+
align-items: center;
|
|
17173
|
+
justify-content: center;
|
|
17174
|
+
z-index: ${styles.zIndex || 1e4};
|
|
17175
|
+
opacity: 0;
|
|
17176
|
+
visibility: hidden;
|
|
17177
|
+
transition: all 0.3s ease;
|
|
17178
|
+
font-family: ${styles.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'};
|
|
17179
|
+
}
|
|
17180
|
+
|
|
17181
|
+
.myio-power-limits-overlay.active {
|
|
17182
|
+
opacity: 1;
|
|
17183
|
+
visibility: visible;
|
|
17184
|
+
}
|
|
17185
|
+
|
|
17186
|
+
.myio-power-limits-card {
|
|
17187
|
+
background: ${styles.backgroundColor || "#ffffff"};
|
|
17188
|
+
border-radius: ${styles.borderRadius || "12px"};
|
|
17189
|
+
width: 90%;
|
|
17190
|
+
max-width: 700px;
|
|
17191
|
+
max-height: 90vh;
|
|
17192
|
+
overflow-y: auto;
|
|
17193
|
+
transform: scale(0.9);
|
|
17194
|
+
transition: transform 0.3s ease;
|
|
17195
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
17196
|
+
}
|
|
17197
|
+
|
|
17198
|
+
.myio-power-limits-overlay.active .myio-power-limits-card {
|
|
17199
|
+
transform: scale(1);
|
|
17200
|
+
}
|
|
17201
|
+
|
|
17202
|
+
.myio-power-limits-header {
|
|
17203
|
+
display: flex;
|
|
17204
|
+
align-items: center;
|
|
17205
|
+
justify-content: space-between;
|
|
17206
|
+
padding: 20px 24px;
|
|
17207
|
+
background: linear-gradient(135deg, ${primaryColor}, ${this.lightenColor(primaryColor, 20)});
|
|
17208
|
+
color: white;
|
|
17209
|
+
border-radius: 12px 12px 0 0;
|
|
17210
|
+
}
|
|
17211
|
+
|
|
17212
|
+
.myio-power-limits-title-section {
|
|
17213
|
+
display: flex;
|
|
17214
|
+
align-items: center;
|
|
17215
|
+
gap: 12px;
|
|
17216
|
+
}
|
|
17217
|
+
|
|
17218
|
+
.myio-power-limits-icon {
|
|
17219
|
+
font-size: 24px;
|
|
17220
|
+
}
|
|
17221
|
+
|
|
17222
|
+
.myio-power-limits-title {
|
|
17223
|
+
font-size: 1.25rem;
|
|
17224
|
+
font-weight: 600;
|
|
17225
|
+
margin: 0;
|
|
17226
|
+
}
|
|
17227
|
+
|
|
17228
|
+
.myio-power-limits-actions {
|
|
17229
|
+
display: flex;
|
|
17230
|
+
align-items: center;
|
|
17231
|
+
gap: 8px;
|
|
17232
|
+
}
|
|
17233
|
+
|
|
17234
|
+
.myio-btn {
|
|
17235
|
+
padding: 8px 16px;
|
|
17236
|
+
border-radius: ${styles.buttonRadius || "6px"};
|
|
17237
|
+
font-size: 14px;
|
|
17238
|
+
font-weight: 500;
|
|
17239
|
+
cursor: pointer;
|
|
17240
|
+
border: none;
|
|
17241
|
+
transition: all 0.2s;
|
|
17242
|
+
display: inline-flex;
|
|
17243
|
+
align-items: center;
|
|
17244
|
+
gap: 6px;
|
|
17245
|
+
}
|
|
17246
|
+
|
|
17247
|
+
.myio-btn:disabled {
|
|
17248
|
+
opacity: 0.6;
|
|
17249
|
+
cursor: not-allowed;
|
|
17250
|
+
}
|
|
17251
|
+
|
|
17252
|
+
.myio-btn-primary {
|
|
17253
|
+
background: white;
|
|
17254
|
+
color: ${primaryColor};
|
|
17255
|
+
}
|
|
17256
|
+
|
|
17257
|
+
.myio-btn-primary:hover:not(:disabled) {
|
|
17258
|
+
background: #f3f4f6;
|
|
17259
|
+
}
|
|
17260
|
+
|
|
17261
|
+
.myio-btn-secondary {
|
|
17262
|
+
background: rgba(255, 255, 255, 0.2);
|
|
17263
|
+
color: white;
|
|
17264
|
+
}
|
|
17265
|
+
|
|
17266
|
+
.myio-btn-secondary:hover:not(:disabled) {
|
|
17267
|
+
background: rgba(255, 255, 255, 0.3);
|
|
17268
|
+
}
|
|
17269
|
+
|
|
17270
|
+
.myio-btn-close {
|
|
17271
|
+
background: transparent;
|
|
17272
|
+
color: white;
|
|
17273
|
+
font-size: 24px;
|
|
17274
|
+
padding: 4px 8px;
|
|
17275
|
+
line-height: 1;
|
|
17276
|
+
}
|
|
17277
|
+
|
|
17278
|
+
.myio-btn-close:hover {
|
|
17279
|
+
background: rgba(255, 255, 255, 0.1);
|
|
17280
|
+
}
|
|
17281
|
+
|
|
17282
|
+
.myio-btn-spinner {
|
|
17283
|
+
width: 16px;
|
|
17284
|
+
height: 16px;
|
|
17285
|
+
border: 2px solid ${primaryColor};
|
|
17286
|
+
border-top-color: transparent;
|
|
17287
|
+
border-radius: 50%;
|
|
17288
|
+
animation: spin 0.8s linear infinite;
|
|
17289
|
+
}
|
|
17290
|
+
|
|
17291
|
+
@keyframes spin {
|
|
17292
|
+
to { transform: rotate(360deg); }
|
|
17293
|
+
}
|
|
17294
|
+
|
|
17295
|
+
.myio-power-limits-selectors {
|
|
17296
|
+
display: grid;
|
|
17297
|
+
grid-template-columns: 1fr 1fr;
|
|
17298
|
+
gap: 16px;
|
|
17299
|
+
padding: 20px 24px;
|
|
17300
|
+
background: #f9fafb;
|
|
17301
|
+
border-bottom: 1px solid #e5e7eb;
|
|
17302
|
+
}
|
|
17303
|
+
|
|
17304
|
+
.myio-form-group {
|
|
17305
|
+
display: flex;
|
|
17306
|
+
flex-direction: column;
|
|
17307
|
+
gap: 6px;
|
|
17308
|
+
}
|
|
17309
|
+
|
|
17310
|
+
.myio-form-group label {
|
|
17311
|
+
font-size: 13px;
|
|
17312
|
+
font-weight: 500;
|
|
17313
|
+
color: #374151;
|
|
17314
|
+
}
|
|
17315
|
+
|
|
17316
|
+
.myio-select, .myio-input {
|
|
17317
|
+
padding: 10px 12px;
|
|
17318
|
+
border: 1px solid #d1d5db;
|
|
17319
|
+
border-radius: 6px;
|
|
17320
|
+
font-size: 14px;
|
|
17321
|
+
background: white;
|
|
17322
|
+
color: #1f2937;
|
|
17323
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
17324
|
+
}
|
|
17325
|
+
|
|
17326
|
+
.myio-select:focus, .myio-input:focus {
|
|
17327
|
+
outline: none;
|
|
17328
|
+
border-color: ${primaryColor};
|
|
17329
|
+
box-shadow: 0 0 0 3px ${this.hexToRgba(primaryColor, 0.1)};
|
|
17330
|
+
}
|
|
17331
|
+
|
|
17332
|
+
.myio-power-limits-grid {
|
|
17333
|
+
display: grid;
|
|
17334
|
+
grid-template-columns: repeat(2, 1fr);
|
|
17335
|
+
gap: 16px;
|
|
17336
|
+
padding: 24px;
|
|
17337
|
+
transition: opacity 0.3s;
|
|
17338
|
+
}
|
|
17339
|
+
|
|
17340
|
+
.myio-power-limits-card-item {
|
|
17341
|
+
background: var(--status-bg);
|
|
17342
|
+
border: 1px solid var(--status-color);
|
|
17343
|
+
border-radius: 8px;
|
|
17344
|
+
padding: 16px;
|
|
17345
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
17346
|
+
}
|
|
17347
|
+
|
|
17348
|
+
.myio-power-limits-card-item:hover {
|
|
17349
|
+
transform: translateY(-2px);
|
|
17350
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
17351
|
+
}
|
|
17352
|
+
|
|
17353
|
+
.myio-card-header {
|
|
17354
|
+
display: flex;
|
|
17355
|
+
align-items: center;
|
|
17356
|
+
gap: 8px;
|
|
17357
|
+
margin-bottom: 12px;
|
|
17358
|
+
}
|
|
17359
|
+
|
|
17360
|
+
.myio-status-indicator {
|
|
17361
|
+
width: 12px;
|
|
17362
|
+
height: 12px;
|
|
17363
|
+
border-radius: 50%;
|
|
17364
|
+
background: var(--status-color);
|
|
17365
|
+
}
|
|
17366
|
+
|
|
17367
|
+
.myio-status-label {
|
|
17368
|
+
font-weight: 600;
|
|
17369
|
+
font-size: 14px;
|
|
17370
|
+
color: #1f2937;
|
|
17371
|
+
}
|
|
17372
|
+
|
|
17373
|
+
.myio-card-inputs {
|
|
17374
|
+
display: grid;
|
|
17375
|
+
grid-template-columns: 1fr 1fr;
|
|
17376
|
+
gap: 12px;
|
|
17377
|
+
}
|
|
17378
|
+
|
|
17379
|
+
.myio-input-group {
|
|
17380
|
+
display: flex;
|
|
17381
|
+
flex-direction: column;
|
|
17382
|
+
gap: 4px;
|
|
17383
|
+
}
|
|
17384
|
+
|
|
17385
|
+
.myio-input-group label {
|
|
17386
|
+
font-size: 11px;
|
|
17387
|
+
font-weight: 500;
|
|
17388
|
+
color: #6b7280;
|
|
17389
|
+
text-transform: uppercase;
|
|
17390
|
+
}
|
|
17391
|
+
|
|
17392
|
+
.myio-power-limits-loading,
|
|
17393
|
+
.myio-power-limits-error,
|
|
17394
|
+
.myio-power-limits-success {
|
|
17395
|
+
display: flex;
|
|
17396
|
+
align-items: center;
|
|
17397
|
+
justify-content: center;
|
|
17398
|
+
gap: 12px;
|
|
17399
|
+
padding: 16px 24px;
|
|
17400
|
+
margin: 0 24px 24px;
|
|
17401
|
+
border-radius: 8px;
|
|
17402
|
+
}
|
|
17403
|
+
|
|
17404
|
+
.myio-power-limits-loading {
|
|
17405
|
+
background: #f3f4f6;
|
|
17406
|
+
color: #6b7280;
|
|
17407
|
+
}
|
|
17408
|
+
|
|
17409
|
+
.myio-power-limits-error {
|
|
17410
|
+
background: #fef2f2;
|
|
17411
|
+
color: ${dangerColor};
|
|
17412
|
+
border: 1px solid ${dangerColor};
|
|
17413
|
+
}
|
|
17414
|
+
|
|
17415
|
+
.myio-power-limits-success {
|
|
17416
|
+
background: #f0fdf4;
|
|
17417
|
+
color: ${successColor};
|
|
17418
|
+
border: 1px solid ${successColor};
|
|
17419
|
+
}
|
|
17420
|
+
|
|
17421
|
+
.myio-spinner {
|
|
17422
|
+
width: 24px;
|
|
17423
|
+
height: 24px;
|
|
17424
|
+
border: 3px solid #e5e7eb;
|
|
17425
|
+
border-top-color: ${primaryColor};
|
|
17426
|
+
border-radius: 50%;
|
|
17427
|
+
animation: spin 0.8s linear infinite;
|
|
17428
|
+
}
|
|
17429
|
+
|
|
17430
|
+
.myio-error-icon, .myio-success-icon {
|
|
17431
|
+
font-size: 20px;
|
|
17432
|
+
}
|
|
17433
|
+
|
|
17434
|
+
@media (max-width: 600px) {
|
|
17435
|
+
.myio-power-limits-selectors,
|
|
17436
|
+
.myio-power-limits-grid {
|
|
17437
|
+
grid-template-columns: 1fr;
|
|
17438
|
+
}
|
|
17439
|
+
|
|
17440
|
+
.myio-power-limits-header {
|
|
17441
|
+
flex-direction: column;
|
|
17442
|
+
gap: 12px;
|
|
17443
|
+
text-align: center;
|
|
17444
|
+
}
|
|
17445
|
+
|
|
17446
|
+
.myio-power-limits-actions {
|
|
17447
|
+
width: 100%;
|
|
17448
|
+
justify-content: center;
|
|
17449
|
+
}
|
|
17450
|
+
}
|
|
17451
|
+
`;
|
|
17452
|
+
}
|
|
17453
|
+
lightenColor(hex, percent) {
|
|
17454
|
+
const num = parseInt(hex.replace("#", ""), 16);
|
|
17455
|
+
const amt = Math.round(2.55 * percent);
|
|
17456
|
+
const R = (num >> 16) + amt;
|
|
17457
|
+
const G = (num >> 8 & 255) + amt;
|
|
17458
|
+
const B = (num & 255) + amt;
|
|
17459
|
+
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);
|
|
17460
|
+
}
|
|
17461
|
+
hexToRgba(hex, alpha) {
|
|
17462
|
+
const num = parseInt(hex.replace("#", ""), 16);
|
|
17463
|
+
const R = num >> 16;
|
|
17464
|
+
const G = num >> 8 & 255;
|
|
17465
|
+
const B = num & 255;
|
|
17466
|
+
return `rgba(${R}, ${G}, ${B}, ${alpha})`;
|
|
17467
|
+
}
|
|
17468
|
+
};
|
|
17469
|
+
|
|
17470
|
+
// src/components/premium-modals/power-limits/PowerLimitsPersister.ts
|
|
17471
|
+
var PowerLimitsPersister = class {
|
|
17472
|
+
jwtToken;
|
|
17473
|
+
tbBaseUrl;
|
|
17474
|
+
constructor(jwtToken, tbBaseUrl) {
|
|
17475
|
+
this.jwtToken = jwtToken;
|
|
17476
|
+
this.tbBaseUrl = tbBaseUrl || window.location.origin;
|
|
17477
|
+
}
|
|
17478
|
+
/**
|
|
17479
|
+
* Load existing mapInstantaneousPower from customer server_scope attributes
|
|
17480
|
+
*/
|
|
17481
|
+
async loadCustomerPowerLimits(customerId) {
|
|
17482
|
+
try {
|
|
17483
|
+
const url = `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/values/attributes/SERVER_SCOPE?keys=mapInstantaneousPower`;
|
|
17484
|
+
const response = await fetch(url, {
|
|
17485
|
+
method: "GET",
|
|
17486
|
+
headers: {
|
|
17487
|
+
"X-Authorization": `Bearer ${this.jwtToken}`,
|
|
17488
|
+
"Content-Type": "application/json"
|
|
17489
|
+
}
|
|
17490
|
+
});
|
|
17491
|
+
if (!response.ok) {
|
|
17492
|
+
if (response.status === 404) {
|
|
17493
|
+
console.log("[PowerLimitsPersister] No existing mapInstantaneousPower found");
|
|
17494
|
+
return null;
|
|
17495
|
+
}
|
|
17496
|
+
throw this.createHttpError(response.status, await response.text().catch(() => ""));
|
|
17497
|
+
}
|
|
17498
|
+
const data = await response.json();
|
|
17499
|
+
if (!data || data.length === 0) {
|
|
17500
|
+
console.log("[PowerLimitsPersister] No mapInstantaneousPower attribute found");
|
|
17501
|
+
return null;
|
|
17502
|
+
}
|
|
17503
|
+
const attr = data.find((item) => item.key === "mapInstantaneousPower");
|
|
17504
|
+
if (!attr || !attr.value) {
|
|
17505
|
+
return null;
|
|
17506
|
+
}
|
|
17507
|
+
const parsedValue = typeof attr.value === "string" ? JSON.parse(attr.value) : attr.value;
|
|
17508
|
+
console.log("[PowerLimitsPersister] Loaded mapInstantaneousPower:", parsedValue);
|
|
17509
|
+
return parsedValue;
|
|
17510
|
+
} catch (error) {
|
|
17511
|
+
console.error("[PowerLimitsPersister] Error loading power limits:", error);
|
|
17512
|
+
throw this.mapError(error);
|
|
17513
|
+
}
|
|
17514
|
+
}
|
|
17515
|
+
/**
|
|
17516
|
+
* Save mapInstantaneousPower to customer server_scope attributes
|
|
17517
|
+
*/
|
|
17518
|
+
async saveCustomerPowerLimits(customerId, limits) {
|
|
17519
|
+
try {
|
|
17520
|
+
const url = `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/attributes/SERVER_SCOPE`;
|
|
17521
|
+
const payload = {
|
|
17522
|
+
mapInstantaneousPower: limits
|
|
17523
|
+
};
|
|
17524
|
+
console.log("[PowerLimitsPersister] Saving power limits:", payload);
|
|
17525
|
+
const response = await fetch(url, {
|
|
17526
|
+
method: "POST",
|
|
17527
|
+
headers: {
|
|
17528
|
+
"X-Authorization": `Bearer ${this.jwtToken}`,
|
|
17529
|
+
"Content-Type": "application/json"
|
|
17530
|
+
},
|
|
17531
|
+
body: JSON.stringify(payload)
|
|
17532
|
+
});
|
|
17533
|
+
if (!response.ok) {
|
|
17534
|
+
throw this.createHttpError(response.status, await response.text().catch(() => ""));
|
|
17535
|
+
}
|
|
17536
|
+
console.log("[PowerLimitsPersister] Successfully saved power limits");
|
|
17537
|
+
return { ok: true };
|
|
17538
|
+
} catch (error) {
|
|
17539
|
+
console.error("[PowerLimitsPersister] Error saving power limits:", error);
|
|
17540
|
+
return { ok: false, error: this.mapError(error) };
|
|
17541
|
+
}
|
|
17542
|
+
}
|
|
17543
|
+
/**
|
|
17544
|
+
* Extract form data for a specific device type and telemetry type
|
|
17545
|
+
*/
|
|
17546
|
+
extractFormData(limits, deviceType, telemetryType) {
|
|
17547
|
+
const defaultFormData = {
|
|
17548
|
+
deviceType,
|
|
17549
|
+
telemetryType,
|
|
17550
|
+
standby: { baseValue: null, topValue: null },
|
|
17551
|
+
normal: { baseValue: null, topValue: null },
|
|
17552
|
+
alert: { baseValue: null, topValue: null },
|
|
17553
|
+
failure: { baseValue: null, topValue: null }
|
|
17554
|
+
};
|
|
17555
|
+
if (!limits || !limits.limitsByInstantaneoustPowerType) {
|
|
17556
|
+
return defaultFormData;
|
|
17557
|
+
}
|
|
17558
|
+
const telemetryEntry = limits.limitsByInstantaneoustPowerType.find(
|
|
17559
|
+
(t) => t.telemetryType === telemetryType
|
|
17560
|
+
);
|
|
17561
|
+
if (!telemetryEntry || !telemetryEntry.itemsByDeviceType) {
|
|
17562
|
+
return defaultFormData;
|
|
17563
|
+
}
|
|
17564
|
+
const deviceEntry = telemetryEntry.itemsByDeviceType.find(
|
|
17565
|
+
(d) => d.deviceType === deviceType
|
|
17566
|
+
);
|
|
17567
|
+
if (!deviceEntry || !deviceEntry.limitsByDeviceStatus) {
|
|
17568
|
+
return defaultFormData;
|
|
17569
|
+
}
|
|
17570
|
+
const statusMap = {
|
|
17571
|
+
"standBy": "standby",
|
|
17572
|
+
"normal": "normal",
|
|
17573
|
+
"alert": "alert",
|
|
17574
|
+
"failure": "failure"
|
|
17575
|
+
};
|
|
17576
|
+
deviceEntry.limitsByDeviceStatus.forEach((status) => {
|
|
17577
|
+
const formKey = statusMap[status.deviceStatusName];
|
|
17578
|
+
if (formKey && defaultFormData[formKey]) {
|
|
17579
|
+
defaultFormData[formKey] = {
|
|
17580
|
+
baseValue: status.limitsValues.baseValue,
|
|
17581
|
+
topValue: status.limitsValues.topValue
|
|
17582
|
+
};
|
|
17583
|
+
}
|
|
17584
|
+
});
|
|
17585
|
+
return defaultFormData;
|
|
17586
|
+
}
|
|
17587
|
+
/**
|
|
17588
|
+
* Merge form data into existing limits JSON
|
|
17589
|
+
* Creates new entries if they don't exist
|
|
17590
|
+
*/
|
|
17591
|
+
mergeFormDataIntoLimits(existingLimits, formData) {
|
|
17592
|
+
const result = existingLimits ? JSON.parse(JSON.stringify(existingLimits)) : { version: "1.0.0", limitsByInstantaneoustPowerType: [] };
|
|
17593
|
+
const statusLimits = [
|
|
17594
|
+
{
|
|
17595
|
+
deviceStatusName: "standBy",
|
|
17596
|
+
limitsValues: {
|
|
17597
|
+
baseValue: formData.standby.baseValue ?? 0,
|
|
17598
|
+
topValue: formData.standby.topValue ?? 0
|
|
17599
|
+
}
|
|
17600
|
+
},
|
|
17601
|
+
{
|
|
17602
|
+
deviceStatusName: "normal",
|
|
17603
|
+
limitsValues: {
|
|
17604
|
+
baseValue: formData.normal.baseValue ?? 0,
|
|
17605
|
+
topValue: formData.normal.topValue ?? 0
|
|
17606
|
+
}
|
|
17607
|
+
},
|
|
17608
|
+
{
|
|
17609
|
+
deviceStatusName: "alert",
|
|
17610
|
+
limitsValues: {
|
|
17611
|
+
baseValue: formData.alert.baseValue ?? 0,
|
|
17612
|
+
topValue: formData.alert.topValue ?? 0
|
|
17613
|
+
}
|
|
17614
|
+
},
|
|
17615
|
+
{
|
|
17616
|
+
deviceStatusName: "failure",
|
|
17617
|
+
limitsValues: {
|
|
17618
|
+
baseValue: formData.failure.baseValue ?? 0,
|
|
17619
|
+
topValue: formData.failure.topValue ?? 0
|
|
17620
|
+
}
|
|
17621
|
+
}
|
|
17622
|
+
];
|
|
17623
|
+
let telemetryEntry = result.limitsByInstantaneoustPowerType.find(
|
|
17624
|
+
(t) => t.telemetryType === formData.telemetryType
|
|
17625
|
+
);
|
|
17626
|
+
if (!telemetryEntry) {
|
|
17627
|
+
telemetryEntry = {
|
|
17628
|
+
telemetryType: formData.telemetryType,
|
|
17629
|
+
itemsByDeviceType: []
|
|
17630
|
+
};
|
|
17631
|
+
result.limitsByInstantaneoustPowerType.push(telemetryEntry);
|
|
17632
|
+
}
|
|
17633
|
+
let deviceEntry = telemetryEntry.itemsByDeviceType.find(
|
|
17634
|
+
(d) => d.deviceType === formData.deviceType
|
|
17635
|
+
);
|
|
17636
|
+
if (!deviceEntry) {
|
|
17637
|
+
deviceEntry = {
|
|
17638
|
+
deviceType: formData.deviceType,
|
|
17639
|
+
name: `mapInstantaneousPower${this.formatDeviceTypeName(formData.deviceType)}`,
|
|
17640
|
+
description: `Power limits for ${formData.deviceType}`,
|
|
17641
|
+
limitsByDeviceStatus: []
|
|
17642
|
+
};
|
|
17643
|
+
telemetryEntry.itemsByDeviceType.push(deviceEntry);
|
|
17644
|
+
}
|
|
17645
|
+
deviceEntry.limitsByDeviceStatus = statusLimits;
|
|
17646
|
+
deviceEntry.name = `mapInstantaneousPower${this.formatDeviceTypeName(formData.deviceType)}`;
|
|
17647
|
+
deviceEntry.description = `Power limits for ${formData.deviceType} - ${formData.telemetryType}`;
|
|
17648
|
+
return result;
|
|
17649
|
+
}
|
|
17650
|
+
/**
|
|
17651
|
+
* Format device type name for the JSON name field
|
|
17652
|
+
*/
|
|
17653
|
+
formatDeviceTypeName(deviceType) {
|
|
17654
|
+
if (!deviceType) return "";
|
|
17655
|
+
return deviceType.toLowerCase().split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
17656
|
+
}
|
|
17657
|
+
createHttpError(status, body) {
|
|
17658
|
+
const error = new Error(`HTTP ${status}: ${body}`);
|
|
17659
|
+
error.status = status;
|
|
17660
|
+
error.body = body;
|
|
17661
|
+
return error;
|
|
17662
|
+
}
|
|
17663
|
+
mapError(error) {
|
|
17664
|
+
const status = error.status;
|
|
17665
|
+
if (status === 400) {
|
|
17666
|
+
return {
|
|
17667
|
+
code: "VALIDATION_ERROR",
|
|
17668
|
+
message: "Invalid input data",
|
|
17669
|
+
cause: error
|
|
17670
|
+
};
|
|
17671
|
+
}
|
|
17672
|
+
if (status === 401) {
|
|
17673
|
+
return {
|
|
17674
|
+
code: "TOKEN_EXPIRED",
|
|
17675
|
+
message: "Authentication token has expired",
|
|
17676
|
+
cause: error
|
|
17677
|
+
};
|
|
17678
|
+
}
|
|
17679
|
+
if (status === 403) {
|
|
17680
|
+
return {
|
|
17681
|
+
code: "AUTH_ERROR",
|
|
17682
|
+
message: "Insufficient permissions",
|
|
17683
|
+
cause: error
|
|
17684
|
+
};
|
|
17685
|
+
}
|
|
17686
|
+
if (status === 404) {
|
|
17687
|
+
return {
|
|
17688
|
+
code: "NETWORK_ERROR",
|
|
17689
|
+
message: "Customer not found",
|
|
17690
|
+
cause: error
|
|
17691
|
+
};
|
|
17692
|
+
}
|
|
17693
|
+
if (status >= 500) {
|
|
17694
|
+
return {
|
|
17695
|
+
code: "NETWORK_ERROR",
|
|
17696
|
+
message: "Server error occurred",
|
|
17697
|
+
cause: error
|
|
17698
|
+
};
|
|
15989
17699
|
}
|
|
17700
|
+
return {
|
|
17701
|
+
code: "UNKNOWN_ERROR",
|
|
17702
|
+
message: error.message || "Unknown error occurred",
|
|
17703
|
+
cause: error
|
|
17704
|
+
};
|
|
15990
17705
|
}
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
|
|
15994
|
-
|
|
17706
|
+
};
|
|
17707
|
+
|
|
17708
|
+
// src/components/premium-modals/power-limits/openPowerLimitsSetupModal.ts
|
|
17709
|
+
async function openPowerLimitsSetupModal(params) {
|
|
17710
|
+
if (!params.token) {
|
|
17711
|
+
throw new Error("[PowerLimitsSetupModal] token is required");
|
|
17712
|
+
}
|
|
17713
|
+
if (!params.customerId) {
|
|
17714
|
+
throw new Error("[PowerLimitsSetupModal] customerId is required");
|
|
17715
|
+
}
|
|
17716
|
+
const persister = new PowerLimitsPersister(params.token, params.tbBaseUrl);
|
|
17717
|
+
let currentDeviceType = params.deviceType || "ELEVADOR";
|
|
17718
|
+
let currentTelemetryType = params.telemetryType || "consumption";
|
|
17719
|
+
let existingLimits = params.existingMapPower || null;
|
|
17720
|
+
const view = new PowerLimitsModalView({
|
|
17721
|
+
deviceType: currentDeviceType,
|
|
17722
|
+
telemetryType: currentTelemetryType,
|
|
17723
|
+
styles: params.styles,
|
|
17724
|
+
locale: params.locale,
|
|
17725
|
+
onDeviceTypeChange: async (deviceType) => {
|
|
17726
|
+
currentDeviceType = deviceType;
|
|
17727
|
+
await loadFormData();
|
|
17728
|
+
},
|
|
17729
|
+
onTelemetryTypeChange: async (telemetryType) => {
|
|
17730
|
+
currentTelemetryType = telemetryType;
|
|
17731
|
+
await loadFormData();
|
|
17732
|
+
},
|
|
17733
|
+
onSave: async () => {
|
|
17734
|
+
const formData = view.getFormData();
|
|
17735
|
+
const updatedLimits = persister.mergeFormDataIntoLimits(existingLimits, formData);
|
|
17736
|
+
const result = await persister.saveCustomerPowerLimits(params.customerId, updatedLimits);
|
|
17737
|
+
if (!result.ok) {
|
|
17738
|
+
throw new Error(result.error?.message || "Failed to save configuration");
|
|
17739
|
+
}
|
|
17740
|
+
existingLimits = updatedLimits;
|
|
17741
|
+
if (params.onSave) {
|
|
17742
|
+
params.onSave(updatedLimits);
|
|
17743
|
+
}
|
|
17744
|
+
},
|
|
17745
|
+
onClose: () => {
|
|
17746
|
+
if (params.onClose) {
|
|
17747
|
+
params.onClose();
|
|
17748
|
+
}
|
|
17749
|
+
}
|
|
17750
|
+
});
|
|
17751
|
+
async function loadFormData() {
|
|
17752
|
+
view.showLoading();
|
|
17753
|
+
try {
|
|
17754
|
+
if (!existingLimits) {
|
|
17755
|
+
existingLimits = await persister.loadCustomerPowerLimits(params.customerId);
|
|
17756
|
+
}
|
|
17757
|
+
const formData = persister.extractFormData(existingLimits, currentDeviceType, currentTelemetryType);
|
|
17758
|
+
view.setFormData(formData);
|
|
17759
|
+
} catch (error) {
|
|
17760
|
+
console.error("[PowerLimitsSetupModal] Error loading form data:", error);
|
|
17761
|
+
view.showError(error.message || "Failed to load configuration");
|
|
17762
|
+
} finally {
|
|
17763
|
+
view.hideLoading();
|
|
15995
17764
|
}
|
|
15996
17765
|
}
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
17766
|
+
let container;
|
|
17767
|
+
if (params.container) {
|
|
17768
|
+
if (typeof params.container === "string") {
|
|
17769
|
+
container = document.querySelector(params.container);
|
|
17770
|
+
} else {
|
|
17771
|
+
container = params.container;
|
|
17772
|
+
}
|
|
16000
17773
|
}
|
|
17774
|
+
view.render(container);
|
|
17775
|
+
await loadFormData();
|
|
17776
|
+
return {
|
|
17777
|
+
destroy: () => view.destroy(),
|
|
17778
|
+
getFormData: () => view.getFormData(),
|
|
17779
|
+
setFormData: (data) => view.setFormData(data)
|
|
17780
|
+
};
|
|
16001
17781
|
}
|
|
16002
17782
|
|
|
16003
17783
|
// src/components/premium-modals/settings/SettingsModalView.ts
|
|
@@ -20368,220 +22148,6 @@ function openGoalsPanel(params) {
|
|
|
20368
22148
|
}
|
|
20369
22149
|
}
|
|
20370
22150
|
|
|
20371
|
-
// src/components/temperature/utils.ts
|
|
20372
|
-
var DAY_PERIODS = [
|
|
20373
|
-
{ id: "madrugada", label: "Madrugada (00h-06h)", startHour: 0, endHour: 6 },
|
|
20374
|
-
{ id: "manha", label: "Manh\xE3 (06h-12h)", startHour: 6, endHour: 12 },
|
|
20375
|
-
{ id: "tarde", label: "Tarde (12h-18h)", startHour: 12, endHour: 18 },
|
|
20376
|
-
{ id: "noite", label: "Noite (18h-24h)", startHour: 18, endHour: 24 }
|
|
20377
|
-
];
|
|
20378
|
-
var DEFAULT_CLAMP_RANGE = { min: 15, max: 40 };
|
|
20379
|
-
function getTodaySoFar() {
|
|
20380
|
-
const now = /* @__PURE__ */ new Date();
|
|
20381
|
-
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
|
|
20382
|
-
return {
|
|
20383
|
-
startTs: startOfDay.getTime(),
|
|
20384
|
-
endTs: now.getTime()
|
|
20385
|
-
};
|
|
20386
|
-
}
|
|
20387
|
-
var CHART_COLORS = [
|
|
20388
|
-
"#1976d2",
|
|
20389
|
-
// Blue
|
|
20390
|
-
"#FF6B6B",
|
|
20391
|
-
// Red
|
|
20392
|
-
"#4CAF50",
|
|
20393
|
-
// Green
|
|
20394
|
-
"#FF9800",
|
|
20395
|
-
// Orange
|
|
20396
|
-
"#9C27B0",
|
|
20397
|
-
// Purple
|
|
20398
|
-
"#00BCD4",
|
|
20399
|
-
// Cyan
|
|
20400
|
-
"#E91E63",
|
|
20401
|
-
// Pink
|
|
20402
|
-
"#795548"
|
|
20403
|
-
// Brown
|
|
20404
|
-
];
|
|
20405
|
-
async function fetchTemperatureData(token, deviceId, startTs, endTs) {
|
|
20406
|
-
const url = `/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=temperature&startTs=${encodeURIComponent(startTs)}&endTs=${encodeURIComponent(endTs)}&limit=50000&agg=NONE`;
|
|
20407
|
-
const response = await fetch(url, {
|
|
20408
|
-
headers: {
|
|
20409
|
-
"X-Authorization": `Bearer ${token}`,
|
|
20410
|
-
"Content-Type": "application/json"
|
|
20411
|
-
}
|
|
20412
|
-
});
|
|
20413
|
-
if (!response.ok) {
|
|
20414
|
-
throw new Error(`Failed to fetch temperature data: ${response.status}`);
|
|
20415
|
-
}
|
|
20416
|
-
const data = await response.json();
|
|
20417
|
-
return data?.temperature || [];
|
|
20418
|
-
}
|
|
20419
|
-
function clampTemperature(value, range = DEFAULT_CLAMP_RANGE) {
|
|
20420
|
-
const num = Number(value || 0);
|
|
20421
|
-
if (num < range.min) return range.min;
|
|
20422
|
-
if (num > range.max) return range.max;
|
|
20423
|
-
return num;
|
|
20424
|
-
}
|
|
20425
|
-
function calculateStats(data, clampRange = DEFAULT_CLAMP_RANGE) {
|
|
20426
|
-
if (data.length === 0) {
|
|
20427
|
-
return { avg: 0, min: 0, max: 0, count: 0 };
|
|
20428
|
-
}
|
|
20429
|
-
const values = data.map((item) => clampTemperature(item.value, clampRange));
|
|
20430
|
-
const sum = values.reduce((acc, v) => acc + v, 0);
|
|
20431
|
-
return {
|
|
20432
|
-
avg: sum / values.length,
|
|
20433
|
-
min: Math.min(...values),
|
|
20434
|
-
max: Math.max(...values),
|
|
20435
|
-
count: values.length
|
|
20436
|
-
};
|
|
20437
|
-
}
|
|
20438
|
-
function interpolateTemperature(data, options) {
|
|
20439
|
-
const { intervalMinutes, startTs, endTs, clampRange = DEFAULT_CLAMP_RANGE } = options;
|
|
20440
|
-
const intervalMs = intervalMinutes * 60 * 1e3;
|
|
20441
|
-
if (data.length === 0) {
|
|
20442
|
-
return [];
|
|
20443
|
-
}
|
|
20444
|
-
const sortedData = [...data].sort((a, b) => a.ts - b.ts);
|
|
20445
|
-
const result = [];
|
|
20446
|
-
let lastKnownValue = clampTemperature(sortedData[0].value, clampRange);
|
|
20447
|
-
let dataIndex = 0;
|
|
20448
|
-
for (let ts = startTs; ts <= endTs; ts += intervalMs) {
|
|
20449
|
-
while (dataIndex < sortedData.length - 1 && sortedData[dataIndex + 1].ts <= ts) {
|
|
20450
|
-
dataIndex++;
|
|
20451
|
-
}
|
|
20452
|
-
const currentData = sortedData[dataIndex];
|
|
20453
|
-
if (currentData && Math.abs(currentData.ts - ts) < intervalMs) {
|
|
20454
|
-
lastKnownValue = clampTemperature(currentData.value, clampRange);
|
|
20455
|
-
}
|
|
20456
|
-
result.push({
|
|
20457
|
-
ts,
|
|
20458
|
-
value: lastKnownValue
|
|
20459
|
-
});
|
|
20460
|
-
}
|
|
20461
|
-
return result;
|
|
20462
|
-
}
|
|
20463
|
-
function aggregateByDay(data, clampRange = DEFAULT_CLAMP_RANGE) {
|
|
20464
|
-
if (data.length === 0) {
|
|
20465
|
-
return [];
|
|
20466
|
-
}
|
|
20467
|
-
const dayMap = /* @__PURE__ */ new Map();
|
|
20468
|
-
data.forEach((item) => {
|
|
20469
|
-
const date = new Date(item.ts);
|
|
20470
|
-
const dateKey = date.toISOString().split("T")[0];
|
|
20471
|
-
if (!dayMap.has(dateKey)) {
|
|
20472
|
-
dayMap.set(dateKey, []);
|
|
20473
|
-
}
|
|
20474
|
-
dayMap.get(dateKey).push(item);
|
|
20475
|
-
});
|
|
20476
|
-
const result = [];
|
|
20477
|
-
dayMap.forEach((dayData, dateKey) => {
|
|
20478
|
-
const values = dayData.map((item) => clampTemperature(item.value, clampRange));
|
|
20479
|
-
const sum = values.reduce((acc, v) => acc + v, 0);
|
|
20480
|
-
result.push({
|
|
20481
|
-
date: dateKey,
|
|
20482
|
-
dateTs: new Date(dateKey).getTime(),
|
|
20483
|
-
avg: sum / values.length,
|
|
20484
|
-
min: Math.min(...values),
|
|
20485
|
-
max: Math.max(...values),
|
|
20486
|
-
count: values.length
|
|
20487
|
-
});
|
|
20488
|
-
});
|
|
20489
|
-
return result.sort((a, b) => a.dateTs - b.dateTs);
|
|
20490
|
-
}
|
|
20491
|
-
function filterByDayPeriods(data, selectedPeriods) {
|
|
20492
|
-
if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
|
|
20493
|
-
return data;
|
|
20494
|
-
}
|
|
20495
|
-
return data.filter((item) => {
|
|
20496
|
-
const date = new Date(item.ts);
|
|
20497
|
-
const hour = date.getHours();
|
|
20498
|
-
return selectedPeriods.some((periodId) => {
|
|
20499
|
-
const period = DAY_PERIODS.find((p) => p.id === periodId);
|
|
20500
|
-
if (!period) return false;
|
|
20501
|
-
return hour >= period.startHour && hour < period.endHour;
|
|
20502
|
-
});
|
|
20503
|
-
});
|
|
20504
|
-
}
|
|
20505
|
-
function getSelectedPeriodsLabel(selectedPeriods) {
|
|
20506
|
-
if (selectedPeriods.length === 0 || selectedPeriods.length === DAY_PERIODS.length) {
|
|
20507
|
-
return "Todos os per\xEDodos";
|
|
20508
|
-
}
|
|
20509
|
-
if (selectedPeriods.length === 1) {
|
|
20510
|
-
const period = DAY_PERIODS.find((p) => p.id === selectedPeriods[0]);
|
|
20511
|
-
return period?.label || "";
|
|
20512
|
-
}
|
|
20513
|
-
return `${selectedPeriods.length} per\xEDodos selecionados`;
|
|
20514
|
-
}
|
|
20515
|
-
function formatTemperature2(value, decimals = 1) {
|
|
20516
|
-
return `${value.toFixed(decimals)}\xB0C`;
|
|
20517
|
-
}
|
|
20518
|
-
function exportTemperatureCSV(data, deviceLabel, stats, startDate, endDate) {
|
|
20519
|
-
if (data.length === 0) {
|
|
20520
|
-
console.warn("No data to export");
|
|
20521
|
-
return;
|
|
20522
|
-
}
|
|
20523
|
-
const BOM = "\uFEFF";
|
|
20524
|
-
let csvContent = BOM;
|
|
20525
|
-
csvContent += `Relat\xF3rio de Temperatura - ${deviceLabel}
|
|
20526
|
-
`;
|
|
20527
|
-
csvContent += `Per\xEDodo: ${startDate} at\xE9 ${endDate}
|
|
20528
|
-
`;
|
|
20529
|
-
csvContent += `M\xE9dia: ${formatTemperature2(stats.avg)}
|
|
20530
|
-
`;
|
|
20531
|
-
csvContent += `M\xEDnima: ${formatTemperature2(stats.min)}
|
|
20532
|
-
`;
|
|
20533
|
-
csvContent += `M\xE1xima: ${formatTemperature2(stats.max)}
|
|
20534
|
-
`;
|
|
20535
|
-
csvContent += `Total de leituras: ${stats.count}
|
|
20536
|
-
`;
|
|
20537
|
-
csvContent += "\n";
|
|
20538
|
-
csvContent += "Data/Hora,Temperatura (\xB0C)\n";
|
|
20539
|
-
data.forEach((item) => {
|
|
20540
|
-
const date = new Date(item.ts).toLocaleString("pt-BR");
|
|
20541
|
-
const temp = Number(item.value).toFixed(2);
|
|
20542
|
-
csvContent += `"${date}",${temp}
|
|
20543
|
-
`;
|
|
20544
|
-
});
|
|
20545
|
-
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
|
|
20546
|
-
const url = URL.createObjectURL(blob);
|
|
20547
|
-
const link = document.createElement("a");
|
|
20548
|
-
link.href = url;
|
|
20549
|
-
link.download = `temperatura_${deviceLabel.replace(/\s+/g, "_")}_${startDate}_${endDate}.csv`;
|
|
20550
|
-
document.body.appendChild(link);
|
|
20551
|
-
link.click();
|
|
20552
|
-
document.body.removeChild(link);
|
|
20553
|
-
URL.revokeObjectURL(url);
|
|
20554
|
-
}
|
|
20555
|
-
var DARK_THEME = {
|
|
20556
|
-
background: "rgba(0, 0, 0, 0.85)",
|
|
20557
|
-
surface: "#1a1f28",
|
|
20558
|
-
text: "#ffffff",
|
|
20559
|
-
textMuted: "rgba(255, 255, 255, 0.7)",
|
|
20560
|
-
border: "rgba(255, 255, 255, 0.1)",
|
|
20561
|
-
primary: "#1976d2",
|
|
20562
|
-
success: "#4CAF50",
|
|
20563
|
-
warning: "#FF9800",
|
|
20564
|
-
danger: "#f44336",
|
|
20565
|
-
chartLine: "#1976d2",
|
|
20566
|
-
chartGrid: "rgba(255, 255, 255, 0.1)"
|
|
20567
|
-
};
|
|
20568
|
-
var LIGHT_THEME = {
|
|
20569
|
-
background: "rgba(0, 0, 0, 0.6)",
|
|
20570
|
-
surface: "#ffffff",
|
|
20571
|
-
text: "#333333",
|
|
20572
|
-
textMuted: "#666666",
|
|
20573
|
-
border: "#e0e0e0",
|
|
20574
|
-
primary: "#1976d2",
|
|
20575
|
-
success: "#4CAF50",
|
|
20576
|
-
warning: "#FF9800",
|
|
20577
|
-
danger: "#f44336",
|
|
20578
|
-
chartLine: "#1976d2",
|
|
20579
|
-
chartGrid: "#e0e0e0"
|
|
20580
|
-
};
|
|
20581
|
-
function getThemeColors(theme) {
|
|
20582
|
-
return theme === "dark" ? DARK_THEME : LIGHT_THEME;
|
|
20583
|
-
}
|
|
20584
|
-
|
|
20585
22151
|
// src/components/temperature/TemperatureModal.ts
|
|
20586
22152
|
async function openTemperatureModal(params) {
|
|
20587
22153
|
const modalId = `myio-temp-modal-${Date.now()}`;
|
|
@@ -20821,7 +22387,7 @@ function renderModal(container, state, modalId, error) {
|
|
|
20821
22387
|
">
|
|
20822
22388
|
<span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Temperatura Atual</span>
|
|
20823
22389
|
<div style="font-weight: 700; font-size: 24px; color: ${statusColor}; margin-top: 4px;">
|
|
20824
|
-
${state.currentTemperature !== null ?
|
|
22390
|
+
${state.currentTemperature !== null ? formatTemperature(state.currentTemperature) : "N/A"}
|
|
20825
22391
|
</div>
|
|
20826
22392
|
<div style="font-size: 11px; color: ${statusColor}; margin-top: 2px;">${statusText}</div>
|
|
20827
22393
|
</div>
|
|
@@ -20832,7 +22398,7 @@ function renderModal(container, state, modalId, error) {
|
|
|
20832
22398
|
">
|
|
20833
22399
|
<span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">M\xE9dia do Per\xEDodo</span>
|
|
20834
22400
|
<div id="${modalId}-avg" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
|
|
20835
|
-
${state.stats.count > 0 ?
|
|
22401
|
+
${state.stats.count > 0 ? formatTemperature(state.stats.avg) : "N/A"}
|
|
20836
22402
|
</div>
|
|
20837
22403
|
<div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${startDateStr} - ${endDateStr}</div>
|
|
20838
22404
|
</div>
|
|
@@ -20843,7 +22409,7 @@ function renderModal(container, state, modalId, error) {
|
|
|
20843
22409
|
">
|
|
20844
22410
|
<span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Min / Max</span>
|
|
20845
22411
|
<div id="${modalId}-minmax" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
|
|
20846
|
-
${state.stats.count > 0 ? `${
|
|
22412
|
+
${state.stats.count > 0 ? `${formatTemperature(state.stats.min)} / ${formatTemperature(state.stats.max)}` : "N/A"}
|
|
20847
22413
|
</div>
|
|
20848
22414
|
<div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${state.stats.count} leituras</div>
|
|
20849
22415
|
</div>
|
|
@@ -21159,7 +22725,7 @@ function setupChartTooltip(canvas, container, chartData, state, colors) {
|
|
|
21159
22725
|
}
|
|
21160
22726
|
tooltip.innerHTML = `
|
|
21161
22727
|
<div style="font-weight: 600; margin-bottom: 6px; color: ${colors.primary};">
|
|
21162
|
-
${
|
|
22728
|
+
${formatTemperature(point.y)}
|
|
21163
22729
|
</div>
|
|
21164
22730
|
<div style="font-size: 11px; color: ${colors.textMuted};">
|
|
21165
22731
|
\u{1F4C5} ${dateStr}
|
|
@@ -21422,7 +22988,7 @@ function renderModal2(container, state, modalId) {
|
|
|
21422
22988
|
<span style="width: 12px; height: 12px; border-radius: 50%; background: ${dd.color};"></span>
|
|
21423
22989
|
<span style="color: ${colors.text}; font-size: 13px;">${dd.device.label}</span>
|
|
21424
22990
|
<span style="color: ${colors.textMuted}; font-size: 11px; margin-left: auto;">
|
|
21425
|
-
${dd.stats.count > 0 ?
|
|
22991
|
+
${dd.stats.count > 0 ? formatTemperature(dd.stats.avg) : "N/A"}
|
|
21426
22992
|
</span>
|
|
21427
22993
|
</div>
|
|
21428
22994
|
`).join("");
|
|
@@ -21438,15 +23004,15 @@ function renderModal2(container, state, modalId) {
|
|
|
21438
23004
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 4px; font-size: 11px;">
|
|
21439
23005
|
<span style="color: ${colors.textMuted};">M\xE9dia:</span>
|
|
21440
23006
|
<span style="color: ${colors.text}; font-weight: 500;">
|
|
21441
|
-
${dd.stats.count > 0 ?
|
|
23007
|
+
${dd.stats.count > 0 ? formatTemperature(dd.stats.avg) : "N/A"}
|
|
21442
23008
|
</span>
|
|
21443
23009
|
<span style="color: ${colors.textMuted};">Min:</span>
|
|
21444
23010
|
<span style="color: ${colors.text};">
|
|
21445
|
-
${dd.stats.count > 0 ?
|
|
23011
|
+
${dd.stats.count > 0 ? formatTemperature(dd.stats.min) : "N/A"}
|
|
21446
23012
|
</span>
|
|
21447
23013
|
<span style="color: ${colors.textMuted};">Max:</span>
|
|
21448
23014
|
<span style="color: ${colors.text};">
|
|
21449
|
-
${dd.stats.count > 0 ?
|
|
23015
|
+
${dd.stats.count > 0 ? formatTemperature(dd.stats.max) : "N/A"}
|
|
21450
23016
|
</span>
|
|
21451
23017
|
<span style="color: ${colors.textMuted};">Leituras:</span>
|
|
21452
23018
|
<span style="color: ${colors.text};">${dd.stats.count}</span>
|
|
@@ -21982,7 +23548,7 @@ function setupComparisonChartTooltip(canvas, container, chartData, state, colors
|
|
|
21982
23548
|
<span style="font-weight: 600;">${point.deviceLabel}</span>
|
|
21983
23549
|
</div>
|
|
21984
23550
|
<div style="font-weight: 600; font-size: 16px; color: ${point.deviceColor}; margin-bottom: 4px;">
|
|
21985
|
-
${
|
|
23551
|
+
${formatTemperature(point.y)}
|
|
21986
23552
|
</div>
|
|
21987
23553
|
<div style="font-size: 11px; color: ${colors.textMuted};">
|
|
21988
23554
|
\u{1F4C5} ${dateStr}
|
|
@@ -26481,6 +28047,9 @@ function createDistributionChartWidget(config) {
|
|
|
26481
28047
|
MyIOSelectionStore,
|
|
26482
28048
|
MyIOSelectionStoreClass,
|
|
26483
28049
|
MyIOToast,
|
|
28050
|
+
POWER_LIMITS_DEVICE_TYPES,
|
|
28051
|
+
POWER_LIMITS_STATUS_CONFIG,
|
|
28052
|
+
POWER_LIMITS_TELEMETRY_TYPES,
|
|
26484
28053
|
addDetectionContext,
|
|
26485
28054
|
addNamespace,
|
|
26486
28055
|
aggregateByDay,
|
|
@@ -26578,6 +28147,7 @@ function createDistributionChartWidget(config) {
|
|
|
26578
28147
|
openDashboardPopupWaterTank,
|
|
26579
28148
|
openDemandModal,
|
|
26580
28149
|
openGoalsPanel,
|
|
28150
|
+
openPowerLimitsSetupModal,
|
|
26581
28151
|
openRealTimeTelemetryModal,
|
|
26582
28152
|
openTemperatureComparisonModal,
|
|
26583
28153
|
openTemperatureModal,
|