myio-js-library 0.1.213 → 0.1.215
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 +479 -68
- package/dist/index.js +479 -68
- package/dist/myio-js-library.umd.js +479 -68
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
|
@@ -21113,26 +21113,26 @@
|
|
|
21113
21113
|
*/
|
|
21114
21114
|
getI18n() {
|
|
21115
21115
|
const defaults = {
|
|
21116
|
-
title: "
|
|
21117
|
-
loading: "
|
|
21118
|
-
error: "
|
|
21119
|
-
noData: "
|
|
21120
|
-
exportCsv: "
|
|
21121
|
-
close: "
|
|
21122
|
-
currentLevel: "
|
|
21123
|
-
averageLevel: "
|
|
21124
|
-
minLevel: "
|
|
21125
|
-
maxLevel: "
|
|
21126
|
-
dateRange: "
|
|
21127
|
-
deviceInfo: "
|
|
21128
|
-
levelChart: "
|
|
21116
|
+
title: "Caixa d'\xC1gua",
|
|
21117
|
+
loading: "Carregando...",
|
|
21118
|
+
error: "Erro ao carregar dados",
|
|
21119
|
+
noData: "Nenhum dado dispon\xEDvel",
|
|
21120
|
+
exportCsv: "Exportar CSV",
|
|
21121
|
+
close: "Fechar",
|
|
21122
|
+
currentLevel: "N\xEDvel Atual",
|
|
21123
|
+
averageLevel: "N\xEDvel M\xE9dio",
|
|
21124
|
+
minLevel: "N\xEDvel M\xEDnimo",
|
|
21125
|
+
maxLevel: "N\xEDvel M\xE1ximo",
|
|
21126
|
+
dateRange: "Per\xEDodo",
|
|
21127
|
+
deviceInfo: "Informa\xE7\xF5es do Dispositivo",
|
|
21128
|
+
levelChart: "Hist\xF3rico de N\xEDvel (m.c.a)",
|
|
21129
21129
|
percentUnit: "%",
|
|
21130
21130
|
status: {
|
|
21131
|
-
critical: "
|
|
21132
|
-
low: "
|
|
21133
|
-
medium: "
|
|
21134
|
-
good: "
|
|
21135
|
-
full: "
|
|
21131
|
+
critical: "Cr\xEDtico",
|
|
21132
|
+
low: "Baixo",
|
|
21133
|
+
medium: "M\xE9dio",
|
|
21134
|
+
good: "Bom",
|
|
21135
|
+
full: "Cheio"
|
|
21136
21136
|
}
|
|
21137
21137
|
};
|
|
21138
21138
|
return {
|
|
@@ -21233,62 +21233,327 @@
|
|
|
21233
21233
|
this.attachEventListeners();
|
|
21234
21234
|
}
|
|
21235
21235
|
/**
|
|
21236
|
-
* Render modal header
|
|
21236
|
+
* Render modal header - MyIO Premium Style
|
|
21237
21237
|
*/
|
|
21238
21238
|
renderHeader() {
|
|
21239
21239
|
const { context, params } = this.config;
|
|
21240
21240
|
const title = params.ui?.title || `${this.i18n.title} - ${context.device.label}`;
|
|
21241
21241
|
return `
|
|
21242
21242
|
<div class="myio-water-tank-modal-header" style="
|
|
21243
|
-
padding:
|
|
21244
|
-
border-bottom: 1px solid #e0e0e0;
|
|
21243
|
+
padding: 4px 8px;
|
|
21245
21244
|
display: flex;
|
|
21246
21245
|
align-items: center;
|
|
21247
21246
|
justify-content: space-between;
|
|
21247
|
+
background: #3e1a7d;
|
|
21248
|
+
color: white;
|
|
21249
|
+
border-radius: 12px 12px 0 0;
|
|
21250
|
+
min-height: 20px;
|
|
21248
21251
|
">
|
|
21249
21252
|
<h2 style="
|
|
21250
|
-
margin:
|
|
21251
|
-
font-size:
|
|
21253
|
+
margin: 6px;
|
|
21254
|
+
font-size: 18px;
|
|
21252
21255
|
font-weight: 600;
|
|
21253
|
-
color:
|
|
21254
|
-
|
|
21255
|
-
|
|
21256
|
-
|
|
21257
|
-
|
|
21258
|
-
|
|
21259
|
-
|
|
21260
|
-
|
|
21261
|
-
|
|
21262
|
-
|
|
21263
|
-
|
|
21264
|
-
|
|
21265
|
-
|
|
21266
|
-
|
|
21267
|
-
|
|
21268
|
-
transition: background 0.2s ease;
|
|
21269
|
-
" title="${this.i18n.close}">
|
|
21270
|
-
\xD7
|
|
21271
|
-
</button>
|
|
21256
|
+
color: white;
|
|
21257
|
+
line-height: 2;
|
|
21258
|
+
">\u{1F4A7} ${title}</h2>
|
|
21259
|
+
<div style="display: flex; gap: 4px; align-items: center;">
|
|
21260
|
+
<button class="myio-water-tank-modal-close" title="${this.i18n.close}" style="
|
|
21261
|
+
background: none;
|
|
21262
|
+
border: none;
|
|
21263
|
+
font-size: 20px;
|
|
21264
|
+
cursor: pointer;
|
|
21265
|
+
padding: 4px 8px;
|
|
21266
|
+
border-radius: 6px;
|
|
21267
|
+
color: rgba(255,255,255,0.8);
|
|
21268
|
+
transition: background-color 0.2s;
|
|
21269
|
+
">\xD7</button>
|
|
21270
|
+
</div>
|
|
21272
21271
|
</div>
|
|
21273
21272
|
`;
|
|
21274
21273
|
}
|
|
21275
21274
|
/**
|
|
21276
|
-
* Render modal body
|
|
21275
|
+
* RFC-0107: Render modal body with new layout
|
|
21276
|
+
* Left side: Tank visualization with percentage
|
|
21277
|
+
* Right side: Chart with controls (larger area)
|
|
21277
21278
|
*/
|
|
21278
21279
|
renderBody() {
|
|
21279
21280
|
return `
|
|
21280
21281
|
<div class="myio-water-tank-modal-body" style="
|
|
21281
|
-
padding:
|
|
21282
|
+
padding: 20px;
|
|
21282
21283
|
overflow-y: auto;
|
|
21283
21284
|
flex: 1;
|
|
21285
|
+
display: flex;
|
|
21286
|
+
flex-direction: column;
|
|
21287
|
+
gap: 16px;
|
|
21284
21288
|
">
|
|
21285
|
-
${this.
|
|
21286
|
-
|
|
21287
|
-
|
|
21289
|
+
${this.renderControlsBar()}
|
|
21290
|
+
<div style="
|
|
21291
|
+
display: flex;
|
|
21292
|
+
gap: 20px;
|
|
21293
|
+
flex: 1;
|
|
21294
|
+
min-height: 400px;
|
|
21295
|
+
">
|
|
21296
|
+
${this.renderTankPanel()}
|
|
21297
|
+
${this.renderChartPanel()}
|
|
21298
|
+
</div>
|
|
21288
21299
|
</div>
|
|
21289
21300
|
${this.renderFooter()}
|
|
21290
21301
|
`;
|
|
21291
21302
|
}
|
|
21303
|
+
/**
|
|
21304
|
+
* RFC-0107: Render controls bar with date range, aggregation, and limit
|
|
21305
|
+
*/
|
|
21306
|
+
renderControlsBar() {
|
|
21307
|
+
const { params } = this.config;
|
|
21308
|
+
const startDate = this.formatDateForInput(params.startTs);
|
|
21309
|
+
const endDate = this.formatDateForInput(params.endTs);
|
|
21310
|
+
const currentAggregation = params.aggregation || "NONE";
|
|
21311
|
+
const currentLimit = params.limit || 1e3;
|
|
21312
|
+
return `
|
|
21313
|
+
<div style="
|
|
21314
|
+
background: #f8f9fa;
|
|
21315
|
+
border: 1px solid #e0e0e0;
|
|
21316
|
+
border-radius: 8px;
|
|
21317
|
+
padding: 12px 16px;
|
|
21318
|
+
display: flex;
|
|
21319
|
+
align-items: center;
|
|
21320
|
+
gap: 16px;
|
|
21321
|
+
flex-wrap: wrap;
|
|
21322
|
+
">
|
|
21323
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21324
|
+
<label style="font-size: 13px; font-weight: 500; color: #2c3e50;">De:</label>
|
|
21325
|
+
<input type="date" id="myio-water-tank-start-date" value="${startDate}" style="
|
|
21326
|
+
padding: 6px 10px;
|
|
21327
|
+
border: 1px solid #ddd;
|
|
21328
|
+
border-radius: 6px;
|
|
21329
|
+
font-size: 13px;
|
|
21330
|
+
color: #2c3e50;
|
|
21331
|
+
cursor: pointer;
|
|
21332
|
+
"/>
|
|
21333
|
+
</div>
|
|
21334
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21335
|
+
<label style="font-size: 13px; font-weight: 500; color: #2c3e50;">At\xE9:</label>
|
|
21336
|
+
<input type="date" id="myio-water-tank-end-date" value="${endDate}" style="
|
|
21337
|
+
padding: 6px 10px;
|
|
21338
|
+
border: 1px solid #ddd;
|
|
21339
|
+
border-radius: 6px;
|
|
21340
|
+
font-size: 13px;
|
|
21341
|
+
color: #2c3e50;
|
|
21342
|
+
cursor: pointer;
|
|
21343
|
+
"/>
|
|
21344
|
+
</div>
|
|
21345
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21346
|
+
<label style="font-size: 13px; font-weight: 500; color: #2c3e50;">Agrega\xE7\xE3o:</label>
|
|
21347
|
+
<select id="myio-water-tank-aggregation" style="
|
|
21348
|
+
padding: 6px 10px;
|
|
21349
|
+
border: 1px solid #ddd;
|
|
21350
|
+
border-radius: 6px;
|
|
21351
|
+
font-size: 13px;
|
|
21352
|
+
color: #2c3e50;
|
|
21353
|
+
background: white;
|
|
21354
|
+
cursor: pointer;
|
|
21355
|
+
">
|
|
21356
|
+
<option value="NONE" ${currentAggregation === "NONE" ? "selected" : ""}>Nenhuma</option>
|
|
21357
|
+
<option value="AVG" ${currentAggregation === "AVG" ? "selected" : ""}>M\xE9dia</option>
|
|
21358
|
+
<option value="MIN" ${currentAggregation === "MIN" ? "selected" : ""}>M\xEDnimo</option>
|
|
21359
|
+
<option value="MAX" ${currentAggregation === "MAX" ? "selected" : ""}>M\xE1ximo</option>
|
|
21360
|
+
<option value="SUM" ${currentAggregation === "SUM" ? "selected" : ""}>Soma</option>
|
|
21361
|
+
<option value="COUNT" ${currentAggregation === "COUNT" ? "selected" : ""}>Contagem</option>
|
|
21362
|
+
</select>
|
|
21363
|
+
</div>
|
|
21364
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21365
|
+
<label style="font-size: 13px; font-weight: 500; color: #2c3e50;">Limite:</label>
|
|
21366
|
+
<select id="myio-water-tank-limit" style="
|
|
21367
|
+
padding: 6px 10px;
|
|
21368
|
+
border: 1px solid #ddd;
|
|
21369
|
+
border-radius: 6px;
|
|
21370
|
+
font-size: 13px;
|
|
21371
|
+
color: #2c3e50;
|
|
21372
|
+
background: white;
|
|
21373
|
+
cursor: pointer;
|
|
21374
|
+
">
|
|
21375
|
+
<option value="100" ${currentLimit === 100 ? "selected" : ""}>100</option>
|
|
21376
|
+
<option value="500" ${currentLimit === 500 ? "selected" : ""}>500</option>
|
|
21377
|
+
<option value="1000" ${currentLimit === 1e3 ? "selected" : ""}>1000</option>
|
|
21378
|
+
<option value="2000" ${currentLimit === 2e3 ? "selected" : ""}>2000</option>
|
|
21379
|
+
<option value="5000" ${currentLimit === 5e3 ? "selected" : ""}>5000</option>
|
|
21380
|
+
</select>
|
|
21381
|
+
</div>
|
|
21382
|
+
<button id="myio-water-tank-apply-dates" style="
|
|
21383
|
+
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
|
|
21384
|
+
color: white;
|
|
21385
|
+
border: none;
|
|
21386
|
+
padding: 6px 16px;
|
|
21387
|
+
border-radius: 6px;
|
|
21388
|
+
font-size: 13px;
|
|
21389
|
+
font-weight: 500;
|
|
21390
|
+
cursor: pointer;
|
|
21391
|
+
transition: all 0.2s ease;
|
|
21392
|
+
">
|
|
21393
|
+
Aplicar
|
|
21394
|
+
</button>
|
|
21395
|
+
</div>
|
|
21396
|
+
`;
|
|
21397
|
+
}
|
|
21398
|
+
/**
|
|
21399
|
+
* RFC-0107: Render tank panel (left side)
|
|
21400
|
+
*/
|
|
21401
|
+
renderTankPanel() {
|
|
21402
|
+
const { data, context } = this.config;
|
|
21403
|
+
let percentage = 0;
|
|
21404
|
+
const percentagePoints = data.telemetry.filter((p) => p.key === "water_percentage");
|
|
21405
|
+
if (percentagePoints.length > 0) {
|
|
21406
|
+
const latestPercentage = percentagePoints[percentagePoints.length - 1].value;
|
|
21407
|
+
percentage = latestPercentage <= 1.5 ? latestPercentage * 100 : latestPercentage;
|
|
21408
|
+
} else if (context.device.currentLevel !== void 0) {
|
|
21409
|
+
const level = context.device.currentLevel;
|
|
21410
|
+
percentage = level <= 1.5 ? level * 100 : level;
|
|
21411
|
+
}
|
|
21412
|
+
const levelStatus = this.getLevelStatus(Math.min(percentage, 100));
|
|
21413
|
+
const tankImageUrl = this.getTankImageUrl(Math.min(percentage, 100));
|
|
21414
|
+
const displayPercentage = percentage.toFixed(1);
|
|
21415
|
+
return `
|
|
21416
|
+
<div style="
|
|
21417
|
+
width: 200px;
|
|
21418
|
+
min-width: 200px;
|
|
21419
|
+
background: linear-gradient(135deg, ${levelStatus.color}10 0%, ${levelStatus.color}05 100%);
|
|
21420
|
+
border: 1px solid ${levelStatus.color}30;
|
|
21421
|
+
border-radius: 12px;
|
|
21422
|
+
padding: 24px 16px;
|
|
21423
|
+
display: flex;
|
|
21424
|
+
flex-direction: column;
|
|
21425
|
+
align-items: center;
|
|
21426
|
+
justify-content: center;
|
|
21427
|
+
gap: 16px;
|
|
21428
|
+
">
|
|
21429
|
+
<img src="${tankImageUrl}" alt="Water Tank" style="
|
|
21430
|
+
width: 100px;
|
|
21431
|
+
height: auto;
|
|
21432
|
+
filter: drop-shadow(0 4px 8px rgba(0,0,0,0.1));
|
|
21433
|
+
"/>
|
|
21434
|
+
<div style="
|
|
21435
|
+
font-size: 42px;
|
|
21436
|
+
font-weight: 700;
|
|
21437
|
+
color: ${levelStatus.color};
|
|
21438
|
+
line-height: 1;
|
|
21439
|
+
">${displayPercentage}%</div>
|
|
21440
|
+
<div style="
|
|
21441
|
+
background: ${levelStatus.color};
|
|
21442
|
+
color: white;
|
|
21443
|
+
padding: 4px 12px;
|
|
21444
|
+
border-radius: 20px;
|
|
21445
|
+
font-size: 11px;
|
|
21446
|
+
font-weight: 600;
|
|
21447
|
+
text-transform: uppercase;
|
|
21448
|
+
">${levelStatus.label}</div>
|
|
21449
|
+
<div style="
|
|
21450
|
+
font-size: 12px;
|
|
21451
|
+
color: #7f8c8d;
|
|
21452
|
+
text-align: center;
|
|
21453
|
+
">${this.i18n.currentLevel}</div>
|
|
21454
|
+
</div>
|
|
21455
|
+
`;
|
|
21456
|
+
}
|
|
21457
|
+
/**
|
|
21458
|
+
* RFC-0107: Render chart panel (right side) with maximize button
|
|
21459
|
+
*/
|
|
21460
|
+
renderChartPanel() {
|
|
21461
|
+
const chartPoints = this.getChartDataPoints();
|
|
21462
|
+
const chartTitle = this.chartDisplayMode === "water_percentage" ? "Hist\xF3rico de N\xEDvel (%)" : this.i18n.levelChart;
|
|
21463
|
+
if (chartPoints.length === 0) {
|
|
21464
|
+
const displayLabel = this.chartDisplayMode === "water_percentage" ? "%" : "m.c.a";
|
|
21465
|
+
return `
|
|
21466
|
+
<div style="
|
|
21467
|
+
flex: 1;
|
|
21468
|
+
background: #f8f9fa;
|
|
21469
|
+
border: 1px solid #e0e0e0;
|
|
21470
|
+
border-radius: 12px;
|
|
21471
|
+
display: flex;
|
|
21472
|
+
flex-direction: column;
|
|
21473
|
+
align-items: center;
|
|
21474
|
+
justify-content: center;
|
|
21475
|
+
padding: 24px;
|
|
21476
|
+
">
|
|
21477
|
+
<div style="font-size: 48px; margin-bottom: 16px; opacity: 0.3;">\u{1F4CA}</div>
|
|
21478
|
+
<div style="color: #7f8c8d; font-size: 16px;">${this.i18n.noData}</div>
|
|
21479
|
+
<div style="color: #bdc3c7; font-size: 13px; margin-top: 8px;">
|
|
21480
|
+
Sem dados de ${this.chartDisplayMode === "water_percentage" ? "percentual" : "n\xEDvel"} (${displayLabel}) dispon\xEDveis
|
|
21481
|
+
</div>
|
|
21482
|
+
</div>
|
|
21483
|
+
`;
|
|
21484
|
+
}
|
|
21485
|
+
const firstTs = chartPoints[0]?.ts;
|
|
21486
|
+
const lastTs = chartPoints[chartPoints.length - 1]?.ts;
|
|
21487
|
+
return `
|
|
21488
|
+
<div id="myio-water-tank-chart-panel" style="
|
|
21489
|
+
flex: 1;
|
|
21490
|
+
background: white;
|
|
21491
|
+
border: 1px solid #e0e0e0;
|
|
21492
|
+
border-radius: 12px;
|
|
21493
|
+
padding: 16px;
|
|
21494
|
+
display: flex;
|
|
21495
|
+
flex-direction: column;
|
|
21496
|
+
position: relative;
|
|
21497
|
+
">
|
|
21498
|
+
<div style="
|
|
21499
|
+
display: flex;
|
|
21500
|
+
align-items: center;
|
|
21501
|
+
justify-content: space-between;
|
|
21502
|
+
margin-bottom: 12px;
|
|
21503
|
+
">
|
|
21504
|
+
<h3 style="
|
|
21505
|
+
margin: 0;
|
|
21506
|
+
font-size: 15px;
|
|
21507
|
+
font-weight: 600;
|
|
21508
|
+
color: #2c3e50;
|
|
21509
|
+
">${chartTitle}</h3>
|
|
21510
|
+
<div style="
|
|
21511
|
+
display: flex;
|
|
21512
|
+
align-items: center;
|
|
21513
|
+
gap: 8px;
|
|
21514
|
+
">
|
|
21515
|
+
<select id="myio-water-tank-display-mode" style="
|
|
21516
|
+
padding: 4px 8px;
|
|
21517
|
+
border: 1px solid #ddd;
|
|
21518
|
+
border-radius: 4px;
|
|
21519
|
+
font-size: 12px;
|
|
21520
|
+
color: #2c3e50;
|
|
21521
|
+
background: white;
|
|
21522
|
+
cursor: pointer;
|
|
21523
|
+
">
|
|
21524
|
+
<option value="water_level" ${this.chartDisplayMode === "water_level" ? "selected" : ""}>N\xEDvel (m.c.a)</option>
|
|
21525
|
+
<option value="water_percentage" ${this.chartDisplayMode === "water_percentage" ? "selected" : ""}>Percentual (%)</option>
|
|
21526
|
+
</select>
|
|
21527
|
+
<button id="myio-water-tank-maximize" title="Maximizar gr\xE1fico" style="
|
|
21528
|
+
background: #f0f0f0;
|
|
21529
|
+
border: 1px solid #ddd;
|
|
21530
|
+
border-radius: 4px;
|
|
21531
|
+
padding: 4px 8px;
|
|
21532
|
+
cursor: pointer;
|
|
21533
|
+
font-size: 14px;
|
|
21534
|
+
display: flex;
|
|
21535
|
+
align-items: center;
|
|
21536
|
+
justify-content: center;
|
|
21537
|
+
">\u26F6</button>
|
|
21538
|
+
</div>
|
|
21539
|
+
</div>
|
|
21540
|
+
<div style="flex: 1; min-height: 300px;">
|
|
21541
|
+
<canvas id="myio-water-tank-chart" style="width: 100%; height: 100%;"></canvas>
|
|
21542
|
+
</div>
|
|
21543
|
+
${firstTs && lastTs ? `
|
|
21544
|
+
<div style="
|
|
21545
|
+
margin-top: 8px;
|
|
21546
|
+
font-size: 11px;
|
|
21547
|
+
color: #7f8c8d;
|
|
21548
|
+
text-align: center;
|
|
21549
|
+
">
|
|
21550
|
+
${this.formatDate(firstTs, false)} \u2014 ${this.formatDate(lastTs, false)}
|
|
21551
|
+
(${chartPoints.length} leituras)
|
|
21552
|
+
</div>
|
|
21553
|
+
` : ""}
|
|
21554
|
+
</div>
|
|
21555
|
+
`;
|
|
21556
|
+
}
|
|
21292
21557
|
/**
|
|
21293
21558
|
* Render date range picker
|
|
21294
21559
|
*/
|
|
@@ -21309,7 +21574,7 @@
|
|
|
21309
21574
|
flex-wrap: wrap;
|
|
21310
21575
|
">
|
|
21311
21576
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21312
|
-
<label style="font-size: 14px; font-weight: 500; color: #2c3e50;">
|
|
21577
|
+
<label style="font-size: 14px; font-weight: 500; color: #2c3e50;">De:</label>
|
|
21313
21578
|
<input type="date" id="myio-water-tank-start-date" value="${startDate}" style="
|
|
21314
21579
|
padding: 8px 12px;
|
|
21315
21580
|
border: 1px solid #ddd;
|
|
@@ -21320,7 +21585,7 @@
|
|
|
21320
21585
|
"/>
|
|
21321
21586
|
</div>
|
|
21322
21587
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
21323
|
-
<label style="font-size: 14px; font-weight: 500; color: #2c3e50;">
|
|
21588
|
+
<label style="font-size: 14px; font-weight: 500; color: #2c3e50;">At\xE9:</label>
|
|
21324
21589
|
<input type="date" id="myio-water-tank-end-date" value="${endDate}" style="
|
|
21325
21590
|
padding: 8px 12px;
|
|
21326
21591
|
border: 1px solid #ddd;
|
|
@@ -21341,7 +21606,7 @@
|
|
|
21341
21606
|
cursor: pointer;
|
|
21342
21607
|
transition: all 0.2s ease;
|
|
21343
21608
|
">
|
|
21344
|
-
|
|
21609
|
+
Aplicar
|
|
21345
21610
|
</button>
|
|
21346
21611
|
</div>
|
|
21347
21612
|
`;
|
|
@@ -21563,7 +21828,7 @@
|
|
|
21563
21828
|
}
|
|
21564
21829
|
const applyDatesBtn = this.modal.querySelector("#myio-water-tank-apply-dates");
|
|
21565
21830
|
if (applyDatesBtn) {
|
|
21566
|
-
applyDatesBtn.addEventListener("click", () => this.
|
|
21831
|
+
applyDatesBtn.addEventListener("click", () => this.handleApplyParams());
|
|
21567
21832
|
}
|
|
21568
21833
|
const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
|
|
21569
21834
|
if (displayModeSelect) {
|
|
@@ -21572,6 +21837,10 @@
|
|
|
21572
21837
|
this.refreshChart();
|
|
21573
21838
|
});
|
|
21574
21839
|
}
|
|
21840
|
+
const maximizeBtn = this.modal.querySelector("#myio-water-tank-maximize");
|
|
21841
|
+
if (maximizeBtn) {
|
|
21842
|
+
maximizeBtn.addEventListener("click", () => this.handleMaximize());
|
|
21843
|
+
}
|
|
21575
21844
|
this.overlay.addEventListener("click", (e) => {
|
|
21576
21845
|
if (e.target === this.overlay) {
|
|
21577
21846
|
this.config.onClose();
|
|
@@ -21586,12 +21855,20 @@
|
|
|
21586
21855
|
});
|
|
21587
21856
|
}
|
|
21588
21857
|
/**
|
|
21589
|
-
* Handle date range change
|
|
21858
|
+
* Handle date range change (legacy - kept for compatibility)
|
|
21590
21859
|
*/
|
|
21591
21860
|
handleDateRangeChange() {
|
|
21861
|
+
this.handleApplyParams();
|
|
21862
|
+
}
|
|
21863
|
+
/**
|
|
21864
|
+
* RFC-0107: Handle apply params (date range, aggregation, limit)
|
|
21865
|
+
*/
|
|
21866
|
+
handleApplyParams() {
|
|
21592
21867
|
if (!this.modal) return;
|
|
21593
21868
|
const startInput = this.modal.querySelector("#myio-water-tank-start-date");
|
|
21594
21869
|
const endInput = this.modal.querySelector("#myio-water-tank-end-date");
|
|
21870
|
+
const aggregationSelect = this.modal.querySelector("#myio-water-tank-aggregation");
|
|
21871
|
+
const limitSelect = this.modal.querySelector("#myio-water-tank-limit");
|
|
21595
21872
|
if (startInput && endInput) {
|
|
21596
21873
|
const startTs = new Date(startInput.value).setHours(0, 0, 0, 0);
|
|
21597
21874
|
const endTs = new Date(endInput.value).setHours(23, 59, 59, 999);
|
|
@@ -21599,17 +21876,77 @@
|
|
|
21599
21876
|
alert("Start date must be before end date");
|
|
21600
21877
|
return;
|
|
21601
21878
|
}
|
|
21602
|
-
|
|
21879
|
+
const aggregation = aggregationSelect?.value || "NONE";
|
|
21880
|
+
const limit = parseInt(limitSelect?.value || "1000", 10);
|
|
21881
|
+
console.log("[WaterTankModalView] Params changed:", {
|
|
21603
21882
|
startTs,
|
|
21604
21883
|
endTs,
|
|
21884
|
+
aggregation,
|
|
21885
|
+
limit,
|
|
21605
21886
|
startDate: new Date(startTs).toISOString(),
|
|
21606
21887
|
endDate: new Date(endTs).toISOString()
|
|
21607
21888
|
});
|
|
21608
|
-
|
|
21889
|
+
this.config.params.startTs = startTs;
|
|
21890
|
+
this.config.params.endTs = endTs;
|
|
21891
|
+
this.config.params.aggregation = aggregation;
|
|
21892
|
+
this.config.params.limit = limit;
|
|
21893
|
+
if (this.config.onParamsChange) {
|
|
21894
|
+
this.config.onParamsChange({ startTs, endTs, aggregation, limit });
|
|
21895
|
+
} else if (this.config.onDateRangeChange) {
|
|
21609
21896
|
this.config.onDateRangeChange(startTs, endTs);
|
|
21610
21897
|
}
|
|
21611
21898
|
}
|
|
21612
21899
|
}
|
|
21900
|
+
/**
|
|
21901
|
+
* RFC-0107: Handle maximize/restore chart
|
|
21902
|
+
*/
|
|
21903
|
+
isMaximized = false;
|
|
21904
|
+
originalModalStyle = "";
|
|
21905
|
+
handleMaximize() {
|
|
21906
|
+
if (!this.modal) return;
|
|
21907
|
+
const chartPanel = this.modal.querySelector("#myio-water-tank-chart-panel");
|
|
21908
|
+
const tankPanel = chartPanel?.previousElementSibling;
|
|
21909
|
+
const maximizeBtn = this.modal.querySelector("#myio-water-tank-maximize");
|
|
21910
|
+
if (!chartPanel) return;
|
|
21911
|
+
if (this.isMaximized) {
|
|
21912
|
+
this.modal.style.cssText = this.originalModalStyle;
|
|
21913
|
+
if (tankPanel) tankPanel.style.display = "";
|
|
21914
|
+
chartPanel.style.cssText = `
|
|
21915
|
+
flex: 1;
|
|
21916
|
+
background: white;
|
|
21917
|
+
border: 1px solid #e0e0e0;
|
|
21918
|
+
border-radius: 12px;
|
|
21919
|
+
padding: 16px;
|
|
21920
|
+
display: flex;
|
|
21921
|
+
flex-direction: column;
|
|
21922
|
+
position: relative;
|
|
21923
|
+
`;
|
|
21924
|
+
if (maximizeBtn) maximizeBtn.textContent = "\u26F6";
|
|
21925
|
+
this.isMaximized = false;
|
|
21926
|
+
} else {
|
|
21927
|
+
this.originalModalStyle = this.modal.style.cssText;
|
|
21928
|
+
this.modal.style.width = "95vw";
|
|
21929
|
+
this.modal.style.height = "90vh";
|
|
21930
|
+
this.modal.style.maxWidth = "95vw";
|
|
21931
|
+
if (tankPanel) tankPanel.style.display = "none";
|
|
21932
|
+
chartPanel.style.cssText = `
|
|
21933
|
+
flex: 1;
|
|
21934
|
+
background: white;
|
|
21935
|
+
border: 1px solid #e0e0e0;
|
|
21936
|
+
border-radius: 12px;
|
|
21937
|
+
padding: 16px;
|
|
21938
|
+
display: flex;
|
|
21939
|
+
flex-direction: column;
|
|
21940
|
+
position: relative;
|
|
21941
|
+
min-height: 100%;
|
|
21942
|
+
`;
|
|
21943
|
+
if (maximizeBtn) maximizeBtn.textContent = "\u26F6";
|
|
21944
|
+
this.isMaximized = true;
|
|
21945
|
+
}
|
|
21946
|
+
requestAnimationFrame(() => {
|
|
21947
|
+
this.renderCanvasChart();
|
|
21948
|
+
});
|
|
21949
|
+
}
|
|
21613
21950
|
handleEscapeKey(e) {
|
|
21614
21951
|
if (e.key === "Escape") {
|
|
21615
21952
|
this.config.onClose();
|
|
@@ -21748,7 +22085,7 @@
|
|
|
21748
22085
|
}
|
|
21749
22086
|
}
|
|
21750
22087
|
/**
|
|
21751
|
-
* Update data and re-render chart
|
|
22088
|
+
* Update data and re-render chart with new layout
|
|
21752
22089
|
*/
|
|
21753
22090
|
updateData(data) {
|
|
21754
22091
|
this.config.data = data;
|
|
@@ -21756,13 +22093,20 @@
|
|
|
21756
22093
|
const bodyEl = this.modal.querySelector(".myio-water-tank-modal-body");
|
|
21757
22094
|
if (bodyEl) {
|
|
21758
22095
|
bodyEl.innerHTML = `
|
|
21759
|
-
${this.
|
|
21760
|
-
|
|
21761
|
-
|
|
22096
|
+
${this.renderControlsBar()}
|
|
22097
|
+
<div style="
|
|
22098
|
+
display: flex;
|
|
22099
|
+
gap: 20px;
|
|
22100
|
+
flex: 1;
|
|
22101
|
+
min-height: 400px;
|
|
22102
|
+
">
|
|
22103
|
+
${this.renderTankPanel()}
|
|
22104
|
+
${this.renderChartPanel()}
|
|
22105
|
+
</div>
|
|
21762
22106
|
`;
|
|
21763
22107
|
const applyDatesBtn = this.modal.querySelector("#myio-water-tank-apply-dates");
|
|
21764
22108
|
if (applyDatesBtn) {
|
|
21765
|
-
applyDatesBtn.addEventListener("click", () => this.
|
|
22109
|
+
applyDatesBtn.addEventListener("click", () => this.handleApplyParams());
|
|
21766
22110
|
}
|
|
21767
22111
|
const displayModeSelect = this.modal.querySelector("#myio-water-tank-display-mode");
|
|
21768
22112
|
if (displayModeSelect) {
|
|
@@ -21771,6 +22115,10 @@
|
|
|
21771
22115
|
this.refreshChart();
|
|
21772
22116
|
});
|
|
21773
22117
|
}
|
|
22118
|
+
const maximizeBtn = this.modal.querySelector("#myio-water-tank-maximize");
|
|
22119
|
+
if (maximizeBtn) {
|
|
22120
|
+
maximizeBtn.addEventListener("click", () => this.handleMaximize());
|
|
22121
|
+
}
|
|
21774
22122
|
requestAnimationFrame(() => {
|
|
21775
22123
|
this.renderCanvasChart();
|
|
21776
22124
|
});
|
|
@@ -22050,7 +22398,8 @@
|
|
|
22050
22398
|
onError: (error) => this.handleError(error),
|
|
22051
22399
|
onClose: () => this.close(),
|
|
22052
22400
|
// Call close() to destroy view and trigger user callback
|
|
22053
|
-
onDateRangeChange: (startTs, endTs) => this.handleDateRangeChange(startTs, endTs)
|
|
22401
|
+
onDateRangeChange: (startTs, endTs) => this.handleDateRangeChange(startTs, endTs),
|
|
22402
|
+
onParamsChange: (params) => this.handleParamsChange(params)
|
|
22054
22403
|
});
|
|
22055
22404
|
this.view.render();
|
|
22056
22405
|
this.view.show();
|
|
@@ -22115,6 +22464,43 @@
|
|
|
22115
22464
|
this.handleError(error);
|
|
22116
22465
|
}
|
|
22117
22466
|
}
|
|
22467
|
+
/**
|
|
22468
|
+
* RFC-0107: Handle params change (date range, aggregation, limit)
|
|
22469
|
+
*/
|
|
22470
|
+
async handleParamsChange(params) {
|
|
22471
|
+
console.log("[WaterTankModal] Params changed:", {
|
|
22472
|
+
startTs: params.startTs,
|
|
22473
|
+
endTs: params.endTs,
|
|
22474
|
+
aggregation: params.aggregation,
|
|
22475
|
+
limit: params.limit,
|
|
22476
|
+
startDate: new Date(params.startTs).toISOString(),
|
|
22477
|
+
endDate: new Date(params.endTs).toISOString()
|
|
22478
|
+
});
|
|
22479
|
+
this.options.startTs = params.startTs;
|
|
22480
|
+
this.options.endTs = params.endTs;
|
|
22481
|
+
this.options.aggregation = params.aggregation;
|
|
22482
|
+
this.options.limit = params.limit;
|
|
22483
|
+
this.context.timeRange.startTs = params.startTs;
|
|
22484
|
+
this.context.timeRange.endTs = params.endTs;
|
|
22485
|
+
try {
|
|
22486
|
+
console.log("[WaterTankModal] Fetching data with new params...");
|
|
22487
|
+
this.data = await this.fetchTelemetryData();
|
|
22488
|
+
if (this.view) {
|
|
22489
|
+
this.view.updateData(this.data);
|
|
22490
|
+
}
|
|
22491
|
+
if (this.options.onDataLoaded) {
|
|
22492
|
+
try {
|
|
22493
|
+
this.options.onDataLoaded(this.data);
|
|
22494
|
+
} catch (callbackError) {
|
|
22495
|
+
console.warn("[WaterTankModal] onDataLoaded callback error:", callbackError);
|
|
22496
|
+
}
|
|
22497
|
+
}
|
|
22498
|
+
console.log("[WaterTankModal] Data refreshed with new params successfully");
|
|
22499
|
+
} catch (error) {
|
|
22500
|
+
console.error("[WaterTankModal] Failed to fetch data with new params:", error);
|
|
22501
|
+
this.handleError(error);
|
|
22502
|
+
}
|
|
22503
|
+
}
|
|
22118
22504
|
/**
|
|
22119
22505
|
* Handle export functionality
|
|
22120
22506
|
*/
|
|
@@ -22236,8 +22622,8 @@
|
|
|
22236
22622
|
}
|
|
22237
22623
|
if (options.currentLevel !== void 0) {
|
|
22238
22624
|
const level = Number(options.currentLevel);
|
|
22239
|
-
if (isNaN(level) || level < 0
|
|
22240
|
-
errors.push("currentLevel must be a number
|
|
22625
|
+
if (isNaN(level) || level < 0) {
|
|
22626
|
+
errors.push("currentLevel must be a non-negative number");
|
|
22241
22627
|
}
|
|
22242
22628
|
}
|
|
22243
22629
|
if (options.limit !== void 0) {
|
|
@@ -28462,13 +28848,31 @@
|
|
|
28462
28848
|
};
|
|
28463
28849
|
|
|
28464
28850
|
// src/components/premium-modals/settings/SettingsFetcher.ts
|
|
28465
|
-
var DefaultSettingsFetcher = class {
|
|
28851
|
+
var DefaultSettingsFetcher = class _DefaultSettingsFetcher {
|
|
28466
28852
|
jwtToken;
|
|
28467
28853
|
tbBaseUrl;
|
|
28854
|
+
static FETCH_TIMEOUT_MS = 8e3;
|
|
28855
|
+
// 8 second timeout
|
|
28468
28856
|
constructor(jwtToken, apiConfig) {
|
|
28469
28857
|
this.jwtToken = jwtToken;
|
|
28470
28858
|
this.tbBaseUrl = apiConfig?.tbBaseUrl || window.location.origin;
|
|
28471
28859
|
}
|
|
28860
|
+
/**
|
|
28861
|
+
* Fetch with timeout to prevent hanging requests from blocking modal render
|
|
28862
|
+
*/
|
|
28863
|
+
async fetchWithTimeout(url, options, timeoutMs = _DefaultSettingsFetcher.FETCH_TIMEOUT_MS) {
|
|
28864
|
+
const controller = new AbortController();
|
|
28865
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
28866
|
+
try {
|
|
28867
|
+
const response = await fetch(url, {
|
|
28868
|
+
...options,
|
|
28869
|
+
signal: controller.signal
|
|
28870
|
+
});
|
|
28871
|
+
return response;
|
|
28872
|
+
} finally {
|
|
28873
|
+
clearTimeout(timeoutId);
|
|
28874
|
+
}
|
|
28875
|
+
}
|
|
28472
28876
|
async fetchCurrentSettings(deviceId, jwtToken, scope = "SERVER_SCOPE") {
|
|
28473
28877
|
try {
|
|
28474
28878
|
const [entityResult, attributesResult] = await Promise.allSettled([
|
|
@@ -28502,9 +28906,12 @@
|
|
|
28502
28906
|
}
|
|
28503
28907
|
}
|
|
28504
28908
|
async fetchDeviceEntity(deviceId) {
|
|
28505
|
-
const response = await
|
|
28506
|
-
|
|
28507
|
-
|
|
28909
|
+
const response = await this.fetchWithTimeout(
|
|
28910
|
+
`${this.tbBaseUrl}/api/device/${deviceId}`,
|
|
28911
|
+
{
|
|
28912
|
+
headers: { "X-Authorization": `Bearer ${this.jwtToken}` }
|
|
28913
|
+
}
|
|
28914
|
+
);
|
|
28508
28915
|
if (!response.ok) {
|
|
28509
28916
|
throw new Error(
|
|
28510
28917
|
`Failed to fetch device entity: ${response.status} ${response.statusText}`
|
|
@@ -28516,7 +28923,7 @@
|
|
|
28516
28923
|
};
|
|
28517
28924
|
}
|
|
28518
28925
|
async fetchDeviceAttributes(deviceId, scope) {
|
|
28519
|
-
const response = await
|
|
28926
|
+
const response = await this.fetchWithTimeout(
|
|
28520
28927
|
`${this.tbBaseUrl}/api/plugins/telemetry/DEVICE/${deviceId}/values/attributes/${scope}`,
|
|
28521
28928
|
{
|
|
28522
28929
|
headers: { "X-Authorization": `Bearer ${this.jwtToken}` }
|
|
@@ -28725,12 +29132,16 @@
|
|
|
28725
29132
|
const tbBaseUrl = this.params.api?.tbBaseUrl || window.location.origin;
|
|
28726
29133
|
const url = `${tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/values/attributes/SERVER_SCOPE?keys=mapInstantaneousPower`;
|
|
28727
29134
|
console.log("[SettingsModal] RFC-0080: Fetching GLOBAL from:", url);
|
|
29135
|
+
const controller = new AbortController();
|
|
29136
|
+
const timeoutId = setTimeout(() => controller.abort(), 8e3);
|
|
28728
29137
|
const response = await fetch(url, {
|
|
28729
29138
|
headers: {
|
|
28730
29139
|
"X-Authorization": `Bearer ${jwtToken}`,
|
|
28731
29140
|
"Content-Type": "application/json"
|
|
28732
|
-
}
|
|
29141
|
+
},
|
|
29142
|
+
signal: controller.signal
|
|
28733
29143
|
});
|
|
29144
|
+
clearTimeout(timeoutId);
|
|
28734
29145
|
if (!response.ok) {
|
|
28735
29146
|
throw new Error(`HTTP ${response.status}`);
|
|
28736
29147
|
}
|