myio-js-library 0.1.212 → 0.1.214
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 +456 -75
- package/dist/index.js +456 -75
- package/dist/myio-js-library.umd.js +456 -75
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21299,26 +21299,26 @@ var WaterTankModalView = class {
|
|
|
21299
21299
|
*/
|
|
21300
21300
|
getI18n() {
|
|
21301
21301
|
const defaults = {
|
|
21302
|
-
title: "
|
|
21303
|
-
loading: "
|
|
21304
|
-
error: "
|
|
21305
|
-
noData: "
|
|
21306
|
-
exportCsv: "
|
|
21307
|
-
close: "
|
|
21308
|
-
currentLevel: "
|
|
21309
|
-
averageLevel: "
|
|
21310
|
-
minLevel: "
|
|
21311
|
-
maxLevel: "
|
|
21312
|
-
dateRange: "
|
|
21313
|
-
deviceInfo: "
|
|
21314
|
-
levelChart: "
|
|
21302
|
+
title: "Caixa d'\xC1gua",
|
|
21303
|
+
loading: "Carregando...",
|
|
21304
|
+
error: "Erro ao carregar dados",
|
|
21305
|
+
noData: "Nenhum dado dispon\xEDvel",
|
|
21306
|
+
exportCsv: "Exportar CSV",
|
|
21307
|
+
close: "Fechar",
|
|
21308
|
+
currentLevel: "N\xEDvel Atual",
|
|
21309
|
+
averageLevel: "N\xEDvel M\xE9dio",
|
|
21310
|
+
minLevel: "N\xEDvel M\xEDnimo",
|
|
21311
|
+
maxLevel: "N\xEDvel M\xE1ximo",
|
|
21312
|
+
dateRange: "Per\xEDodo",
|
|
21313
|
+
deviceInfo: "Informa\xE7\xF5es do Dispositivo",
|
|
21314
|
+
levelChart: "Hist\xF3rico de N\xEDvel (m.c.a)",
|
|
21315
21315
|
percentUnit: "%",
|
|
21316
21316
|
status: {
|
|
21317
|
-
critical: "
|
|
21318
|
-
low: "
|
|
21319
|
-
medium: "
|
|
21320
|
-
good: "
|
|
21321
|
-
full: "
|
|
21317
|
+
critical: "Cr\xEDtico",
|
|
21318
|
+
low: "Baixo",
|
|
21319
|
+
medium: "M\xE9dio",
|
|
21320
|
+
good: "Bom",
|
|
21321
|
+
full: "Cheio"
|
|
21322
21322
|
}
|
|
21323
21323
|
};
|
|
21324
21324
|
return {
|
|
@@ -21419,62 +21419,327 @@ var WaterTankModalView = class {
|
|
|
21419
21419
|
this.attachEventListeners();
|
|
21420
21420
|
}
|
|
21421
21421
|
/**
|
|
21422
|
-
* Render modal header
|
|
21422
|
+
* Render modal header - MyIO Premium Style
|
|
21423
21423
|
*/
|
|
21424
21424
|
renderHeader() {
|
|
21425
21425
|
const { context, params } = this.config;
|
|
21426
21426
|
const title = params.ui?.title || `${this.i18n.title} - ${context.device.label}`;
|
|
21427
21427
|
return `
|
|
21428
21428
|
<div class="myio-water-tank-modal-header" style="
|
|
21429
|
-
padding:
|
|
21430
|
-
border-bottom: 1px solid #e0e0e0;
|
|
21429
|
+
padding: 4px 8px;
|
|
21431
21430
|
display: flex;
|
|
21432
21431
|
align-items: center;
|
|
21433
21432
|
justify-content: space-between;
|
|
21433
|
+
background: #3e1a7d;
|
|
21434
|
+
color: white;
|
|
21435
|
+
border-radius: 12px 12px 0 0;
|
|
21436
|
+
min-height: 20px;
|
|
21434
21437
|
">
|
|
21435
21438
|
<h2 style="
|
|
21436
|
-
margin:
|
|
21437
|
-
font-size:
|
|
21439
|
+
margin: 6px;
|
|
21440
|
+
font-size: 18px;
|
|
21438
21441
|
font-weight: 600;
|
|
21439
|
-
color:
|
|
21440
|
-
|
|
21441
|
-
|
|
21442
|
-
|
|
21443
|
-
|
|
21444
|
-
|
|
21445
|
-
|
|
21446
|
-
|
|
21447
|
-
|
|
21448
|
-
|
|
21449
|
-
|
|
21450
|
-
|
|
21451
|
-
|
|
21452
|
-
|
|
21453
|
-
|
|
21454
|
-
transition: background 0.2s ease;
|
|
21455
|
-
" title="${this.i18n.close}">
|
|
21456
|
-
\xD7
|
|
21457
|
-
</button>
|
|
21442
|
+
color: white;
|
|
21443
|
+
line-height: 2;
|
|
21444
|
+
">\u{1F4A7} ${title}</h2>
|
|
21445
|
+
<div style="display: flex; gap: 4px; align-items: center;">
|
|
21446
|
+
<button class="myio-water-tank-modal-close" title="${this.i18n.close}" style="
|
|
21447
|
+
background: none;
|
|
21448
|
+
border: none;
|
|
21449
|
+
font-size: 20px;
|
|
21450
|
+
cursor: pointer;
|
|
21451
|
+
padding: 4px 8px;
|
|
21452
|
+
border-radius: 6px;
|
|
21453
|
+
color: rgba(255,255,255,0.8);
|
|
21454
|
+
transition: background-color 0.2s;
|
|
21455
|
+
">\xD7</button>
|
|
21456
|
+
</div>
|
|
21458
21457
|
</div>
|
|
21459
21458
|
`;
|
|
21460
21459
|
}
|
|
21461
21460
|
/**
|
|
21462
|
-
* Render modal body
|
|
21461
|
+
* RFC-0107: Render modal body with new layout
|
|
21462
|
+
* Left side: Tank visualization with percentage
|
|
21463
|
+
* Right side: Chart with controls (larger area)
|
|
21463
21464
|
*/
|
|
21464
21465
|
renderBody() {
|
|
21465
21466
|
return `
|
|
21466
21467
|
<div class="myio-water-tank-modal-body" style="
|
|
21467
|
-
padding:
|
|
21468
|
+
padding: 20px;
|
|
21468
21469
|
overflow-y: auto;
|
|
21469
21470
|
flex: 1;
|
|
21471
|
+
display: flex;
|
|
21472
|
+
flex-direction: column;
|
|
21473
|
+
gap: 16px;
|
|
21470
21474
|
">
|
|
21471
|
-
${this.
|
|
21472
|
-
|
|
21473
|
-
|
|
21475
|
+
${this.renderControlsBar()}
|
|
21476
|
+
<div style="
|
|
21477
|
+
display: flex;
|
|
21478
|
+
gap: 20px;
|
|
21479
|
+
flex: 1;
|
|
21480
|
+
min-height: 400px;
|
|
21481
|
+
">
|
|
21482
|
+
${this.renderTankPanel()}
|
|
21483
|
+
${this.renderChartPanel()}
|
|
21484
|
+
</div>
|
|
21474
21485
|
</div>
|
|
21475
21486
|
${this.renderFooter()}
|
|
21476
21487
|
`;
|
|
21477
21488
|
}
|
|
21489
|
+
/**
|
|
21490
|
+
* RFC-0107: Render controls bar with date range, aggregation, and limit
|
|
21491
|
+
*/
|
|
21492
|
+
renderControlsBar() {
|
|
21493
|
+
const { params } = this.config;
|
|
21494
|
+
const startDate = this.formatDateForInput(params.startTs);
|
|
21495
|
+
const endDate = this.formatDateForInput(params.endTs);
|
|
21496
|
+
const currentAggregation = params.aggregation || "NONE";
|
|
21497
|
+
const currentLimit = params.limit || 1e3;
|
|
21498
|
+
return `
|
|
21499
|
+
<div style="
|
|
21500
|
+
background: #f8f9fa;
|
|
21501
|
+
border: 1px solid #e0e0e0;
|
|
21502
|
+
border-radius: 8px;
|
|
21503
|
+
padding: 12px 16px;
|
|
21504
|
+
display: flex;
|
|
21505
|
+
align-items: center;
|
|
21506
|
+
gap: 16px;
|
|
21507
|
+
flex-wrap: wrap;
|
|
21508
|
+
">
|
|
21509
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21510
|
+
<label style="font-size: 13px; font-weight: 500; color: #2c3e50;">De:</label>
|
|
21511
|
+
<input type="date" id="myio-water-tank-start-date" value="${startDate}" style="
|
|
21512
|
+
padding: 6px 10px;
|
|
21513
|
+
border: 1px solid #ddd;
|
|
21514
|
+
border-radius: 6px;
|
|
21515
|
+
font-size: 13px;
|
|
21516
|
+
color: #2c3e50;
|
|
21517
|
+
cursor: pointer;
|
|
21518
|
+
"/>
|
|
21519
|
+
</div>
|
|
21520
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21521
|
+
<label style="font-size: 13px; font-weight: 500; color: #2c3e50;">At\xE9:</label>
|
|
21522
|
+
<input type="date" id="myio-water-tank-end-date" value="${endDate}" style="
|
|
21523
|
+
padding: 6px 10px;
|
|
21524
|
+
border: 1px solid #ddd;
|
|
21525
|
+
border-radius: 6px;
|
|
21526
|
+
font-size: 13px;
|
|
21527
|
+
color: #2c3e50;
|
|
21528
|
+
cursor: pointer;
|
|
21529
|
+
"/>
|
|
21530
|
+
</div>
|
|
21531
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21532
|
+
<label style="font-size: 13px; font-weight: 500; color: #2c3e50;">Agrega\xE7\xE3o:</label>
|
|
21533
|
+
<select id="myio-water-tank-aggregation" style="
|
|
21534
|
+
padding: 6px 10px;
|
|
21535
|
+
border: 1px solid #ddd;
|
|
21536
|
+
border-radius: 6px;
|
|
21537
|
+
font-size: 13px;
|
|
21538
|
+
color: #2c3e50;
|
|
21539
|
+
background: white;
|
|
21540
|
+
cursor: pointer;
|
|
21541
|
+
">
|
|
21542
|
+
<option value="NONE" ${currentAggregation === "NONE" ? "selected" : ""}>Nenhuma</option>
|
|
21543
|
+
<option value="AVG" ${currentAggregation === "AVG" ? "selected" : ""}>M\xE9dia</option>
|
|
21544
|
+
<option value="MIN" ${currentAggregation === "MIN" ? "selected" : ""}>M\xEDnimo</option>
|
|
21545
|
+
<option value="MAX" ${currentAggregation === "MAX" ? "selected" : ""}>M\xE1ximo</option>
|
|
21546
|
+
<option value="SUM" ${currentAggregation === "SUM" ? "selected" : ""}>Soma</option>
|
|
21547
|
+
<option value="COUNT" ${currentAggregation === "COUNT" ? "selected" : ""}>Contagem</option>
|
|
21548
|
+
</select>
|
|
21549
|
+
</div>
|
|
21550
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21551
|
+
<label style="font-size: 13px; font-weight: 500; color: #2c3e50;">Limite:</label>
|
|
21552
|
+
<select id="myio-water-tank-limit" style="
|
|
21553
|
+
padding: 6px 10px;
|
|
21554
|
+
border: 1px solid #ddd;
|
|
21555
|
+
border-radius: 6px;
|
|
21556
|
+
font-size: 13px;
|
|
21557
|
+
color: #2c3e50;
|
|
21558
|
+
background: white;
|
|
21559
|
+
cursor: pointer;
|
|
21560
|
+
">
|
|
21561
|
+
<option value="100" ${currentLimit === 100 ? "selected" : ""}>100</option>
|
|
21562
|
+
<option value="500" ${currentLimit === 500 ? "selected" : ""}>500</option>
|
|
21563
|
+
<option value="1000" ${currentLimit === 1e3 ? "selected" : ""}>1000</option>
|
|
21564
|
+
<option value="2000" ${currentLimit === 2e3 ? "selected" : ""}>2000</option>
|
|
21565
|
+
<option value="5000" ${currentLimit === 5e3 ? "selected" : ""}>5000</option>
|
|
21566
|
+
</select>
|
|
21567
|
+
</div>
|
|
21568
|
+
<button id="myio-water-tank-apply-dates" style="
|
|
21569
|
+
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
|
|
21570
|
+
color: white;
|
|
21571
|
+
border: none;
|
|
21572
|
+
padding: 6px 16px;
|
|
21573
|
+
border-radius: 6px;
|
|
21574
|
+
font-size: 13px;
|
|
21575
|
+
font-weight: 500;
|
|
21576
|
+
cursor: pointer;
|
|
21577
|
+
transition: all 0.2s ease;
|
|
21578
|
+
">
|
|
21579
|
+
Aplicar
|
|
21580
|
+
</button>
|
|
21581
|
+
</div>
|
|
21582
|
+
`;
|
|
21583
|
+
}
|
|
21584
|
+
/**
|
|
21585
|
+
* RFC-0107: Render tank panel (left side)
|
|
21586
|
+
*/
|
|
21587
|
+
renderTankPanel() {
|
|
21588
|
+
const { data, context } = this.config;
|
|
21589
|
+
let percentage = 0;
|
|
21590
|
+
const percentagePoints = data.telemetry.filter((p) => p.key === "water_percentage");
|
|
21591
|
+
if (percentagePoints.length > 0) {
|
|
21592
|
+
const latestPercentage = percentagePoints[percentagePoints.length - 1].value;
|
|
21593
|
+
percentage = latestPercentage <= 1.5 ? latestPercentage * 100 : latestPercentage;
|
|
21594
|
+
} else if (context.device.currentLevel !== void 0) {
|
|
21595
|
+
const level = context.device.currentLevel;
|
|
21596
|
+
percentage = level <= 1.5 ? level * 100 : level;
|
|
21597
|
+
}
|
|
21598
|
+
const levelStatus = this.getLevelStatus(Math.min(percentage, 100));
|
|
21599
|
+
const tankImageUrl = this.getTankImageUrl(Math.min(percentage, 100));
|
|
21600
|
+
const displayPercentage = percentage.toFixed(1);
|
|
21601
|
+
return `
|
|
21602
|
+
<div style="
|
|
21603
|
+
width: 200px;
|
|
21604
|
+
min-width: 200px;
|
|
21605
|
+
background: linear-gradient(135deg, ${levelStatus.color}10 0%, ${levelStatus.color}05 100%);
|
|
21606
|
+
border: 1px solid ${levelStatus.color}30;
|
|
21607
|
+
border-radius: 12px;
|
|
21608
|
+
padding: 24px 16px;
|
|
21609
|
+
display: flex;
|
|
21610
|
+
flex-direction: column;
|
|
21611
|
+
align-items: center;
|
|
21612
|
+
justify-content: center;
|
|
21613
|
+
gap: 16px;
|
|
21614
|
+
">
|
|
21615
|
+
<img src="${tankImageUrl}" alt="Water Tank" style="
|
|
21616
|
+
width: 100px;
|
|
21617
|
+
height: auto;
|
|
21618
|
+
filter: drop-shadow(0 4px 8px rgba(0,0,0,0.1));
|
|
21619
|
+
"/>
|
|
21620
|
+
<div style="
|
|
21621
|
+
font-size: 42px;
|
|
21622
|
+
font-weight: 700;
|
|
21623
|
+
color: ${levelStatus.color};
|
|
21624
|
+
line-height: 1;
|
|
21625
|
+
">${displayPercentage}%</div>
|
|
21626
|
+
<div style="
|
|
21627
|
+
background: ${levelStatus.color};
|
|
21628
|
+
color: white;
|
|
21629
|
+
padding: 4px 12px;
|
|
21630
|
+
border-radius: 20px;
|
|
21631
|
+
font-size: 11px;
|
|
21632
|
+
font-weight: 600;
|
|
21633
|
+
text-transform: uppercase;
|
|
21634
|
+
">${levelStatus.label}</div>
|
|
21635
|
+
<div style="
|
|
21636
|
+
font-size: 12px;
|
|
21637
|
+
color: #7f8c8d;
|
|
21638
|
+
text-align: center;
|
|
21639
|
+
">${this.i18n.currentLevel}</div>
|
|
21640
|
+
</div>
|
|
21641
|
+
`;
|
|
21642
|
+
}
|
|
21643
|
+
/**
|
|
21644
|
+
* RFC-0107: Render chart panel (right side) with maximize button
|
|
21645
|
+
*/
|
|
21646
|
+
renderChartPanel() {
|
|
21647
|
+
const chartPoints = this.getChartDataPoints();
|
|
21648
|
+
const chartTitle = this.chartDisplayMode === "water_percentage" ? "Hist\xF3rico de N\xEDvel (%)" : this.i18n.levelChart;
|
|
21649
|
+
if (chartPoints.length === 0) {
|
|
21650
|
+
const displayLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
|
|
21651
|
+
return `
|
|
21652
|
+
<div style="
|
|
21653
|
+
flex: 1;
|
|
21654
|
+
background: #f8f9fa;
|
|
21655
|
+
border: 1px solid #e0e0e0;
|
|
21656
|
+
border-radius: 12px;
|
|
21657
|
+
display: flex;
|
|
21658
|
+
flex-direction: column;
|
|
21659
|
+
align-items: center;
|
|
21660
|
+
justify-content: center;
|
|
21661
|
+
padding: 24px;
|
|
21662
|
+
">
|
|
21663
|
+
<div style="font-size: 48px; margin-bottom: 16px; opacity: 0.3;">\u{1F4CA}</div>
|
|
21664
|
+
<div style="color: #7f8c8d; font-size: 16px;">${this.i18n.noData}</div>
|
|
21665
|
+
<div style="color: #bdc3c7; font-size: 13px; margin-top: 8px;">
|
|
21666
|
+
Sem dados de ${this.chartDisplayMode === "water_percentage" ? "percentual" : "n\xEDvel"} (${displayLabel}) dispon\xEDveis
|
|
21667
|
+
</div>
|
|
21668
|
+
</div>
|
|
21669
|
+
`;
|
|
21670
|
+
}
|
|
21671
|
+
const firstTs = chartPoints[0]?.ts;
|
|
21672
|
+
const lastTs = chartPoints[chartPoints.length - 1]?.ts;
|
|
21673
|
+
return `
|
|
21674
|
+
<div id="myio-water-tank-chart-panel" style="
|
|
21675
|
+
flex: 1;
|
|
21676
|
+
background: white;
|
|
21677
|
+
border: 1px solid #e0e0e0;
|
|
21678
|
+
border-radius: 12px;
|
|
21679
|
+
padding: 16px;
|
|
21680
|
+
display: flex;
|
|
21681
|
+
flex-direction: column;
|
|
21682
|
+
position: relative;
|
|
21683
|
+
">
|
|
21684
|
+
<div style="
|
|
21685
|
+
display: flex;
|
|
21686
|
+
align-items: center;
|
|
21687
|
+
justify-content: space-between;
|
|
21688
|
+
margin-bottom: 12px;
|
|
21689
|
+
">
|
|
21690
|
+
<h3 style="
|
|
21691
|
+
margin: 0;
|
|
21692
|
+
font-size: 15px;
|
|
21693
|
+
font-weight: 600;
|
|
21694
|
+
color: #2c3e50;
|
|
21695
|
+
">${chartTitle}</h3>
|
|
21696
|
+
<div style="
|
|
21697
|
+
display: flex;
|
|
21698
|
+
align-items: center;
|
|
21699
|
+
gap: 8px;
|
|
21700
|
+
">
|
|
21701
|
+
<select id="myio-water-tank-display-mode" style="
|
|
21702
|
+
padding: 4px 8px;
|
|
21703
|
+
border: 1px solid #ddd;
|
|
21704
|
+
border-radius: 4px;
|
|
21705
|
+
font-size: 12px;
|
|
21706
|
+
color: #2c3e50;
|
|
21707
|
+
background: white;
|
|
21708
|
+
cursor: pointer;
|
|
21709
|
+
">
|
|
21710
|
+
<option value="water_level" ${this.chartDisplayMode === "water_level" ? "selected" : ""}>N\xEDvel (m.c.a)</option>
|
|
21711
|
+
<option value="water_percentage" ${this.chartDisplayMode === "water_percentage" ? "selected" : ""}>Percentual (%)</option>
|
|
21712
|
+
</select>
|
|
21713
|
+
<button id="myio-water-tank-maximize" title="Maximizar gr\xE1fico" style="
|
|
21714
|
+
background: #f0f0f0;
|
|
21715
|
+
border: 1px solid #ddd;
|
|
21716
|
+
border-radius: 4px;
|
|
21717
|
+
padding: 4px 8px;
|
|
21718
|
+
cursor: pointer;
|
|
21719
|
+
font-size: 14px;
|
|
21720
|
+
display: flex;
|
|
21721
|
+
align-items: center;
|
|
21722
|
+
justify-content: center;
|
|
21723
|
+
">\u26F6</button>
|
|
21724
|
+
</div>
|
|
21725
|
+
</div>
|
|
21726
|
+
<div style="flex: 1; min-height: 300px;">
|
|
21727
|
+
<canvas id="myio-water-tank-chart" style="width: 100%; height: 100%;"></canvas>
|
|
21728
|
+
</div>
|
|
21729
|
+
${firstTs && lastTs ? `
|
|
21730
|
+
<div style="
|
|
21731
|
+
margin-top: 8px;
|
|
21732
|
+
font-size: 11px;
|
|
21733
|
+
color: #7f8c8d;
|
|
21734
|
+
text-align: center;
|
|
21735
|
+
">
|
|
21736
|
+
${this.formatDate(firstTs, false)} \u2014 ${this.formatDate(lastTs, false)}
|
|
21737
|
+
(${chartPoints.length} leituras)
|
|
21738
|
+
</div>
|
|
21739
|
+
` : ""}
|
|
21740
|
+
</div>
|
|
21741
|
+
`;
|
|
21742
|
+
}
|
|
21478
21743
|
/**
|
|
21479
21744
|
* Render date range picker
|
|
21480
21745
|
*/
|
|
@@ -21495,7 +21760,7 @@ var WaterTankModalView = class {
|
|
|
21495
21760
|
flex-wrap: wrap;
|
|
21496
21761
|
">
|
|
21497
21762
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21498
|
-
<label style="font-size: 14px; font-weight: 500; color: #2c3e50;">
|
|
21763
|
+
<label style="font-size: 14px; font-weight: 500; color: #2c3e50;">De:</label>
|
|
21499
21764
|
<input type="date" id="myio-water-tank-start-date" value="${startDate}" style="
|
|
21500
21765
|
padding: 8px 12px;
|
|
21501
21766
|
border: 1px solid #ddd;
|
|
@@ -21506,7 +21771,7 @@ var WaterTankModalView = class {
|
|
|
21506
21771
|
"/>
|
|
21507
21772
|
</div>
|
|
21508
21773
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21509
|
-
<label style="font-size: 14px; font-weight: 500; color: #2c3e50;">
|
|
21774
|
+
<label style="font-size: 14px; font-weight: 500; color: #2c3e50;">At\xE9:</label>
|
|
21510
21775
|
<input type="date" id="myio-water-tank-end-date" value="${endDate}" style="
|
|
21511
21776
|
padding: 8px 12px;
|
|
21512
21777
|
border: 1px solid #ddd;
|
|
@@ -21527,7 +21792,7 @@ var WaterTankModalView = class {
|
|
|
21527
21792
|
cursor: pointer;
|
|
21528
21793
|
transition: all 0.2s ease;
|
|
21529
21794
|
">
|
|
21530
|
-
|
|
21795
|
+
Aplicar
|
|
21531
21796
|
</button>
|
|
21532
21797
|
</div>
|
|
21533
21798
|
`;
|
|
@@ -21749,7 +22014,7 @@ var WaterTankModalView = class {
|
|
|
21749
22014
|
}
|
|
21750
22015
|
const applyDatesBtn = this.modal.querySelector("#myio-water-tank-apply-dates");
|
|
21751
22016
|
if (applyDatesBtn) {
|
|
21752
|
-
applyDatesBtn.addEventListener("click", () => this.
|
|
22017
|
+
applyDatesBtn.addEventListener("click", () => this.handleApplyParams());
|
|
21753
22018
|
}
|
|
21754
22019
|
const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
|
|
21755
22020
|
if (displayModeSelect) {
|
|
@@ -21758,6 +22023,10 @@ var WaterTankModalView = class {
|
|
|
21758
22023
|
this.refreshChart();
|
|
21759
22024
|
});
|
|
21760
22025
|
}
|
|
22026
|
+
const maximizeBtn = this.modal.querySelector("#myio-water-tank-maximize");
|
|
22027
|
+
if (maximizeBtn) {
|
|
22028
|
+
maximizeBtn.addEventListener("click", () => this.handleMaximize());
|
|
22029
|
+
}
|
|
21761
22030
|
this.overlay.addEventListener("click", (e) => {
|
|
21762
22031
|
if (e.target === this.overlay) {
|
|
21763
22032
|
this.config.onClose();
|
|
@@ -21772,12 +22041,20 @@ var WaterTankModalView = class {
|
|
|
21772
22041
|
});
|
|
21773
22042
|
}
|
|
21774
22043
|
/**
|
|
21775
|
-
* Handle date range change
|
|
22044
|
+
* Handle date range change (legacy - kept for compatibility)
|
|
21776
22045
|
*/
|
|
21777
22046
|
handleDateRangeChange() {
|
|
22047
|
+
this.handleApplyParams();
|
|
22048
|
+
}
|
|
22049
|
+
/**
|
|
22050
|
+
* RFC-0107: Handle apply params (date range, aggregation, limit)
|
|
22051
|
+
*/
|
|
22052
|
+
handleApplyParams() {
|
|
21778
22053
|
if (!this.modal) return;
|
|
21779
22054
|
const startInput = this.modal.querySelector("#myio-water-tank-start-date");
|
|
21780
22055
|
const endInput = this.modal.querySelector("#myio-water-tank-end-date");
|
|
22056
|
+
const aggregationSelect = this.modal.querySelector("#myio-water-tank-aggregation");
|
|
22057
|
+
const limitSelect = this.modal.querySelector("#myio-water-tank-limit");
|
|
21781
22058
|
if (startInput && endInput) {
|
|
21782
22059
|
const startTs = new Date(startInput.value).setHours(0, 0, 0, 0);
|
|
21783
22060
|
const endTs = new Date(endInput.value).setHours(23, 59, 59, 999);
|
|
@@ -21785,17 +22062,77 @@ var WaterTankModalView = class {
|
|
|
21785
22062
|
alert("Start date must be before end date");
|
|
21786
22063
|
return;
|
|
21787
22064
|
}
|
|
21788
|
-
|
|
22065
|
+
const aggregation = aggregationSelect?.value || "NONE";
|
|
22066
|
+
const limit = parseInt(limitSelect?.value || "1000", 10);
|
|
22067
|
+
console.log("[WaterTankModalView] Params changed:", {
|
|
21789
22068
|
startTs,
|
|
21790
22069
|
endTs,
|
|
22070
|
+
aggregation,
|
|
22071
|
+
limit,
|
|
21791
22072
|
startDate: new Date(startTs).toISOString(),
|
|
21792
22073
|
endDate: new Date(endTs).toISOString()
|
|
21793
22074
|
});
|
|
21794
|
-
|
|
22075
|
+
this.config.params.startTs = startTs;
|
|
22076
|
+
this.config.params.endTs = endTs;
|
|
22077
|
+
this.config.params.aggregation = aggregation;
|
|
22078
|
+
this.config.params.limit = limit;
|
|
22079
|
+
if (this.config.onParamsChange) {
|
|
22080
|
+
this.config.onParamsChange({ startTs, endTs, aggregation, limit });
|
|
22081
|
+
} else if (this.config.onDateRangeChange) {
|
|
21795
22082
|
this.config.onDateRangeChange(startTs, endTs);
|
|
21796
22083
|
}
|
|
21797
22084
|
}
|
|
21798
22085
|
}
|
|
22086
|
+
/**
|
|
22087
|
+
* RFC-0107: Handle maximize/restore chart
|
|
22088
|
+
*/
|
|
22089
|
+
isMaximized = false;
|
|
22090
|
+
originalModalStyle = "";
|
|
22091
|
+
handleMaximize() {
|
|
22092
|
+
if (!this.modal) return;
|
|
22093
|
+
const chartPanel = this.modal.querySelector("#myio-water-tank-chart-panel");
|
|
22094
|
+
const tankPanel = chartPanel?.previousElementSibling;
|
|
22095
|
+
const maximizeBtn = this.modal.querySelector("#myio-water-tank-maximize");
|
|
22096
|
+
if (!chartPanel) return;
|
|
22097
|
+
if (this.isMaximized) {
|
|
22098
|
+
this.modal.style.cssText = this.originalModalStyle;
|
|
22099
|
+
if (tankPanel) tankPanel.style.display = "";
|
|
22100
|
+
chartPanel.style.cssText = `
|
|
22101
|
+
flex: 1;
|
|
22102
|
+
background: white;
|
|
22103
|
+
border: 1px solid #e0e0e0;
|
|
22104
|
+
border-radius: 12px;
|
|
22105
|
+
padding: 16px;
|
|
22106
|
+
display: flex;
|
|
22107
|
+
flex-direction: column;
|
|
22108
|
+
position: relative;
|
|
22109
|
+
`;
|
|
22110
|
+
if (maximizeBtn) maximizeBtn.textContent = "\u26F6";
|
|
22111
|
+
this.isMaximized = false;
|
|
22112
|
+
} else {
|
|
22113
|
+
this.originalModalStyle = this.modal.style.cssText;
|
|
22114
|
+
this.modal.style.width = "95vw";
|
|
22115
|
+
this.modal.style.height = "90vh";
|
|
22116
|
+
this.modal.style.maxWidth = "95vw";
|
|
22117
|
+
if (tankPanel) tankPanel.style.display = "none";
|
|
22118
|
+
chartPanel.style.cssText = `
|
|
22119
|
+
flex: 1;
|
|
22120
|
+
background: white;
|
|
22121
|
+
border: 1px solid #e0e0e0;
|
|
22122
|
+
border-radius: 12px;
|
|
22123
|
+
padding: 16px;
|
|
22124
|
+
display: flex;
|
|
22125
|
+
flex-direction: column;
|
|
22126
|
+
position: relative;
|
|
22127
|
+
min-height: 100%;
|
|
22128
|
+
`;
|
|
22129
|
+
if (maximizeBtn) maximizeBtn.textContent = "\u26F6";
|
|
22130
|
+
this.isMaximized = true;
|
|
22131
|
+
}
|
|
22132
|
+
requestAnimationFrame(() => {
|
|
22133
|
+
this.renderCanvasChart();
|
|
22134
|
+
});
|
|
22135
|
+
}
|
|
21799
22136
|
handleEscapeKey(e) {
|
|
21800
22137
|
if (e.key === "Escape") {
|
|
21801
22138
|
this.config.onClose();
|
|
@@ -21934,7 +22271,7 @@ var WaterTankModalView = class {
|
|
|
21934
22271
|
}
|
|
21935
22272
|
}
|
|
21936
22273
|
/**
|
|
21937
|
-
* Update data and re-render chart
|
|
22274
|
+
* Update data and re-render chart with new layout
|
|
21938
22275
|
*/
|
|
21939
22276
|
updateData(data) {
|
|
21940
22277
|
this.config.data = data;
|
|
@@ -21942,13 +22279,20 @@ var WaterTankModalView = class {
|
|
|
21942
22279
|
const bodyEl = this.modal.querySelector(".myio-water-tank-modal-body");
|
|
21943
22280
|
if (bodyEl) {
|
|
21944
22281
|
bodyEl.innerHTML = `
|
|
21945
|
-
${this.
|
|
21946
|
-
|
|
21947
|
-
|
|
22282
|
+
${this.renderControlsBar()}
|
|
22283
|
+
<div style="
|
|
22284
|
+
display: flex;
|
|
22285
|
+
gap: 20px;
|
|
22286
|
+
flex: 1;
|
|
22287
|
+
min-height: 400px;
|
|
22288
|
+
">
|
|
22289
|
+
${this.renderTankPanel()}
|
|
22290
|
+
${this.renderChartPanel()}
|
|
22291
|
+
</div>
|
|
21948
22292
|
`;
|
|
21949
22293
|
const applyDatesBtn = this.modal.querySelector("#myio-water-tank-apply-dates");
|
|
21950
22294
|
if (applyDatesBtn) {
|
|
21951
|
-
applyDatesBtn.addEventListener("click", () => this.
|
|
22295
|
+
applyDatesBtn.addEventListener("click", () => this.handleApplyParams());
|
|
21952
22296
|
}
|
|
21953
22297
|
const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
|
|
21954
22298
|
if (displayModeSelect) {
|
|
@@ -21957,6 +22301,10 @@ var WaterTankModalView = class {
|
|
|
21957
22301
|
this.refreshChart();
|
|
21958
22302
|
});
|
|
21959
22303
|
}
|
|
22304
|
+
const maximizeBtn = this.modal.querySelector("#myio-water-tank-maximize");
|
|
22305
|
+
if (maximizeBtn) {
|
|
22306
|
+
maximizeBtn.addEventListener("click", () => this.handleMaximize());
|
|
22307
|
+
}
|
|
21960
22308
|
requestAnimationFrame(() => {
|
|
21961
22309
|
this.renderCanvasChart();
|
|
21962
22310
|
});
|
|
@@ -22129,13 +22477,12 @@ var WaterTankModal = class {
|
|
|
22129
22477
|
}
|
|
22130
22478
|
/**
|
|
22131
22479
|
* Transform raw ThingsBoard response to our data points
|
|
22132
|
-
* RFC-0107:
|
|
22480
|
+
* RFC-0107: Keep ALL data points with their original keys (no deduplication)
|
|
22481
|
+
* This allows the chart to switch between water_level and water_percentage dynamically
|
|
22133
22482
|
*/
|
|
22134
22483
|
transformTelemetryData(rawData, keys) {
|
|
22135
22484
|
const allPoints = [];
|
|
22136
|
-
const
|
|
22137
|
-
const prioritizedKeys = displayKey && rawData[displayKey] ? [displayKey, ...keys.filter((k) => k !== displayKey)] : keys;
|
|
22138
|
-
for (const key of prioritizedKeys) {
|
|
22485
|
+
for (const key of keys) {
|
|
22139
22486
|
if (rawData[key] && Array.isArray(rawData[key])) {
|
|
22140
22487
|
const keyPoints = rawData[key].map((point) => {
|
|
22141
22488
|
let value = typeof point.value === "string" ? parseFloat(point.value) : point.value;
|
|
@@ -22152,16 +22499,12 @@ var WaterTankModal = class {
|
|
|
22152
22499
|
}
|
|
22153
22500
|
}
|
|
22154
22501
|
allPoints.sort((a, b) => a.ts - b.ts);
|
|
22155
|
-
const
|
|
22156
|
-
const
|
|
22157
|
-
|
|
22158
|
-
if (!seenTimestamps.has(point.ts)) {
|
|
22159
|
-
seenTimestamps.add(point.ts);
|
|
22160
|
-
uniquePoints.push(point);
|
|
22161
|
-
}
|
|
22502
|
+
const keyCounts = {};
|
|
22503
|
+
for (const p of allPoints) {
|
|
22504
|
+
keyCounts[p.key || "unknown"] = (keyCounts[p.key || "unknown"] || 0) + 1;
|
|
22162
22505
|
}
|
|
22163
|
-
console.log(`[WaterTankModal] Transformed ${
|
|
22164
|
-
return
|
|
22506
|
+
console.log(`[WaterTankModal] Transformed ${allPoints.length} total points:`, keyCounts);
|
|
22507
|
+
return allPoints;
|
|
22165
22508
|
}
|
|
22166
22509
|
/**
|
|
22167
22510
|
* Calculate summary statistics from telemetry data
|
|
@@ -22241,7 +22584,8 @@ var WaterTankModal = class {
|
|
|
22241
22584
|
onError: (error) => this.handleError(error),
|
|
22242
22585
|
onClose: () => this.close(),
|
|
22243
22586
|
// Call close() to destroy view and trigger user callback
|
|
22244
|
-
onDateRangeChange: (startTs, endTs) => this.handleDateRangeChange(startTs, endTs)
|
|
22587
|
+
onDateRangeChange: (startTs, endTs) => this.handleDateRangeChange(startTs, endTs),
|
|
22588
|
+
onParamsChange: (params) => this.handleParamsChange(params)
|
|
22245
22589
|
});
|
|
22246
22590
|
this.view.render();
|
|
22247
22591
|
this.view.show();
|
|
@@ -22306,6 +22650,43 @@ var WaterTankModal = class {
|
|
|
22306
22650
|
this.handleError(error);
|
|
22307
22651
|
}
|
|
22308
22652
|
}
|
|
22653
|
+
/**
|
|
22654
|
+
* RFC-0107: Handle params change (date range, aggregation, limit)
|
|
22655
|
+
*/
|
|
22656
|
+
async handleParamsChange(params) {
|
|
22657
|
+
console.log("[WaterTankModal] Params changed:", {
|
|
22658
|
+
startTs: params.startTs,
|
|
22659
|
+
endTs: params.endTs,
|
|
22660
|
+
aggregation: params.aggregation,
|
|
22661
|
+
limit: params.limit,
|
|
22662
|
+
startDate: new Date(params.startTs).toISOString(),
|
|
22663
|
+
endDate: new Date(params.endTs).toISOString()
|
|
22664
|
+
});
|
|
22665
|
+
this.options.startTs = params.startTs;
|
|
22666
|
+
this.options.endTs = params.endTs;
|
|
22667
|
+
this.options.aggregation = params.aggregation;
|
|
22668
|
+
this.options.limit = params.limit;
|
|
22669
|
+
this.context.timeRange.startTs = params.startTs;
|
|
22670
|
+
this.context.timeRange.endTs = params.endTs;
|
|
22671
|
+
try {
|
|
22672
|
+
console.log("[WaterTankModal] Fetching data with new params...");
|
|
22673
|
+
this.data = await this.fetchTelemetryData();
|
|
22674
|
+
if (this.view) {
|
|
22675
|
+
this.view.updateData(this.data);
|
|
22676
|
+
}
|
|
22677
|
+
if (this.options.onDataLoaded) {
|
|
22678
|
+
try {
|
|
22679
|
+
this.options.onDataLoaded(this.data);
|
|
22680
|
+
} catch (callbackError) {
|
|
22681
|
+
console.warn("[WaterTankModal] onDataLoaded callback error:", callbackError);
|
|
22682
|
+
}
|
|
22683
|
+
}
|
|
22684
|
+
console.log("[WaterTankModal] Data refreshed with new params successfully");
|
|
22685
|
+
} catch (error) {
|
|
22686
|
+
console.error("[WaterTankModal] Failed to fetch data with new params:", error);
|
|
22687
|
+
this.handleError(error);
|
|
22688
|
+
}
|
|
22689
|
+
}
|
|
22309
22690
|
/**
|
|
22310
22691
|
* Handle export functionality
|
|
22311
22692
|
*/
|
|
@@ -22427,8 +22808,8 @@ function validateOptions2(options) {
|
|
|
22427
22808
|
}
|
|
22428
22809
|
if (options.currentLevel !== void 0) {
|
|
22429
22810
|
const level = Number(options.currentLevel);
|
|
22430
|
-
if (isNaN(level) || level < 0
|
|
22431
|
-
errors.push("currentLevel must be a number
|
|
22811
|
+
if (isNaN(level) || level < 0) {
|
|
22812
|
+
errors.push("currentLevel must be a non-negative number");
|
|
22432
22813
|
}
|
|
22433
22814
|
}
|
|
22434
22815
|
if (options.limit !== void 0) {
|