viberadar 0.3.179 → 0.3.181
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/probe/runner.d.ts +7 -2
- package/dist/probe/runner.d.ts.map +1 -1
- package/dist/probe/runner.js +10 -4
- package/dist/probe/runner.js.map +1 -1
- package/dist/probe/types.d.ts +1 -0
- package/dist/probe/types.d.ts.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +42 -9
- package/dist/server/index.js.map +1 -1
- package/dist/ui/dashboard.html +212 -52
- package/package.json +1 -1
package/dist/ui/dashboard.html
CHANGED
|
@@ -1561,8 +1561,8 @@
|
|
|
1561
1561
|
.load-no-k6 code { background: var(--bg); border: 1px solid var(--border); padding: 3px 8px; border-radius: 4px; font-size: 13px; color: var(--blue); }
|
|
1562
1562
|
|
|
1563
1563
|
/* Probe panel */
|
|
1564
|
-
.probe-container { padding: 20px 24px; max-width:
|
|
1565
|
-
.probe-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom:
|
|
1564
|
+
.probe-container { padding: 20px 24px; max-width: 960px; }
|
|
1565
|
+
.probe-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 16px; gap: 12px; }
|
|
1566
1566
|
.probe-title { font-size: 16px; font-weight: 700; color: var(--text); margin-bottom: 4px; }
|
|
1567
1567
|
.probe-section { background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 16px; margin-bottom: 14px; }
|
|
1568
1568
|
.probe-section-title { font-size: 12px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 12px; }
|
|
@@ -1578,12 +1578,40 @@
|
|
|
1578
1578
|
.probe-btn-start:hover { background: rgba(88,166,255,0.1); }
|
|
1579
1579
|
.probe-btn-stop { border-color: var(--red); color: var(--red); }
|
|
1580
1580
|
.probe-btn-stop:hover { background: rgba(248,81,73,0.1); }
|
|
1581
|
-
|
|
1582
|
-
.probe-
|
|
1583
|
-
.probe-
|
|
1584
|
-
.probe-
|
|
1585
|
-
.probe-
|
|
1586
|
-
.probe-
|
|
1581
|
+
/* Probe cards */
|
|
1582
|
+
.probe-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; margin-top: 16px; }
|
|
1583
|
+
.probe-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 16px; cursor: pointer; transition: border-color 0.15s, background 0.15s; display: flex; flex-direction: column; gap: 0; }
|
|
1584
|
+
.probe-card:hover { border-color: var(--blue); background: var(--bg-hover); }
|
|
1585
|
+
.probe-card.running { border-color: var(--yellow, #e3b341); }
|
|
1586
|
+
.probe-card.passed { border-color: var(--green); }
|
|
1587
|
+
.probe-card.failed { border-color: var(--red); }
|
|
1588
|
+
.probe-card-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
|
|
1589
|
+
.probe-card-name { font-size: 13px; font-weight: 600; color: var(--text); flex: 1; line-height: 1.4; }
|
|
1590
|
+
.probe-card-icon { font-size: 20px; flex-shrink: 0; }
|
|
1591
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
1592
|
+
.probe-spin { display: inline-block; animation: spin 1s linear infinite; }
|
|
1593
|
+
.probe-card-meta { display: flex; gap: 6px; align-items: center; margin-top: 6px; flex-wrap: wrap; }
|
|
1594
|
+
.probe-badge { background: var(--bg); border: 1px solid var(--border); border-radius: 3px; padding: 1px 5px; font-size: 10px; color: var(--muted); }
|
|
1595
|
+
.probe-card-dur { font-size: 11px; color: var(--muted); }
|
|
1596
|
+
.probe-card-err { font-size: 11px; color: var(--red); margin-top: 6px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.4; }
|
|
1597
|
+
.probe-card-footer { display: flex; align-items: center; justify-content: flex-end; margin-top: 12px; }
|
|
1598
|
+
/* Probe detail */
|
|
1599
|
+
.probe-detail { padding: 20px 24px; max-width: 860px; }
|
|
1600
|
+
.probe-back { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--blue); cursor: pointer; margin-bottom: 16px; }
|
|
1601
|
+
.probe-back:hover { text-decoration: underline; }
|
|
1602
|
+
.probe-detail-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 20px; }
|
|
1603
|
+
.probe-detail-title { font-size: 18px; font-weight: 700; color: var(--text); }
|
|
1604
|
+
.probe-detail-meta { font-size: 12px; color: var(--muted); margin-top: 4px; display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
|
|
1605
|
+
.probe-status-badge { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; padding: 2px 8px; border-radius: 4px; }
|
|
1606
|
+
.probe-status-passed { background: rgba(63,185,80,0.12); color: var(--green); }
|
|
1607
|
+
.probe-status-failed { background: rgba(248,81,73,0.12); color: var(--red); }
|
|
1608
|
+
.probe-status-running { background: rgba(227,179,65,0.12); color: #e3b341; }
|
|
1609
|
+
.probe-status-idle { background: var(--bg); color: var(--muted); border: 1px solid var(--border); }
|
|
1610
|
+
.probe-steps-list { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
|
|
1611
|
+
.probe-step-row { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 7px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; }
|
|
1612
|
+
.probe-step-type { font-size: 10px; font-weight: 600; color: var(--blue); background: rgba(88,166,255,0.1); padding: 1px 5px; border-radius: 3px; min-width: 80px; text-align: center; }
|
|
1613
|
+
.probe-step-val { color: var(--text); font-family: monospace; }
|
|
1614
|
+
.probe-output-box { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 11px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 12px 14px; white-space: pre-wrap; overflow-x: auto; max-height: 360px; overflow-y: auto; color: var(--text); line-height: 1.5; margin-top: 8px; }
|
|
1587
1615
|
|
|
1588
1616
|
</style>
|
|
1589
1617
|
</head>
|
|
@@ -1697,8 +1725,9 @@
|
|
|
1697
1725
|
let D = null;
|
|
1698
1726
|
let contextMode = 'qa';
|
|
1699
1727
|
let view = 'features';
|
|
1700
|
-
let probeData = null; // { status, lastRun, intervalSec, nextRunAt, checks, configFound }
|
|
1728
|
+
let probeData = null; // { status, lastRun, intervalSec, nextRunAt, checks, configFound, checkResults, runningCheck }
|
|
1701
1729
|
let probeRunning = false;
|
|
1730
|
+
let probeDetailCheck = null; // null = cards view, string = check name being viewed
|
|
1702
1731
|
let searchQuery = '';
|
|
1703
1732
|
let activeTypes = new Set();
|
|
1704
1733
|
let activePanelKey = null;
|
|
@@ -3382,82 +3411,194 @@ async function loadProbeData() {
|
|
|
3382
3411
|
try {
|
|
3383
3412
|
const res = await fetch('/api/probe/status');
|
|
3384
3413
|
probeData = await res.json();
|
|
3414
|
+
if (contextMode === 'probe') renderContent();
|
|
3385
3415
|
} catch {}
|
|
3386
3416
|
}
|
|
3387
3417
|
|
|
3418
|
+
function probeCheckStatus(checkName) {
|
|
3419
|
+
if (!probeData) return 'idle';
|
|
3420
|
+
if (probeData.runningCheck === checkName) return 'running';
|
|
3421
|
+
const r = probeData.checkResults?.[checkName];
|
|
3422
|
+
return r ? r.status : 'idle';
|
|
3423
|
+
}
|
|
3424
|
+
|
|
3425
|
+
function probeCheckResult(checkName) {
|
|
3426
|
+
return probeData?.checkResults?.[checkName] || null;
|
|
3427
|
+
}
|
|
3428
|
+
|
|
3429
|
+
function probeStatusIcon(status) {
|
|
3430
|
+
if (status === 'running') return `<span class="probe-spin">⏳</span>`;
|
|
3431
|
+
if (status === 'passed') return '✅';
|
|
3432
|
+
if (status === 'failed') return '❌';
|
|
3433
|
+
return '⏸';
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3436
|
+
function probeStatusBadge(status) {
|
|
3437
|
+
if (status === 'running') return `<span class="probe-status-badge probe-status-running"><span class="probe-spin">⏳</span> Выполняется</span>`;
|
|
3438
|
+
if (status === 'passed') return `<span class="probe-status-badge probe-status-passed">✅ Passed</span>`;
|
|
3439
|
+
if (status === 'failed') return `<span class="probe-status-badge probe-status-failed">❌ Failed</span>`;
|
|
3440
|
+
return `<span class="probe-status-badge probe-status-idle">⏸ Не запускался</span>`;
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3388
3443
|
function renderProbePanel(c) {
|
|
3444
|
+
if (probeDetailCheck !== null) { renderProbeDetail(c); return; }
|
|
3445
|
+
|
|
3389
3446
|
const d = probeData;
|
|
3390
|
-
const
|
|
3391
|
-
const
|
|
3392
|
-
|
|
3393
|
-
const lastRunHtml = d && d.lastRun ? (() => {
|
|
3394
|
-
const r = d.lastRun;
|
|
3395
|
-
const allPassed = r.failed === 0;
|
|
3396
|
-
const rows = r.results.map(res => {
|
|
3397
|
-
const ok = res.status === 'passed';
|
|
3398
|
-
return `<div class="probe-check-row">
|
|
3399
|
-
<span class="probe-check-icon">${ok ? '✅' : '❌'}</span>
|
|
3400
|
-
<span class="probe-check-name">${escapeHtml(res.check)}</span>
|
|
3401
|
-
<span class="probe-check-dur" style="color:var(--muted)">${res.durationMs}ms</span>
|
|
3402
|
-
${!ok && res.error ? `<div class="probe-check-error">${escapeHtml(res.error)}</div>` : ''}
|
|
3403
|
-
${!ok && res.screenshotPath ? `<div class="probe-check-error" style="color:var(--muted)">📸 ${escapeHtml(res.screenshotPath)}</div>` : ''}
|
|
3404
|
-
</div>`;
|
|
3405
|
-
}).join('');
|
|
3406
|
-
return `
|
|
3407
|
-
<div class="probe-section">
|
|
3408
|
-
<div class="probe-section-title">Последний прогон <span style="color:var(--muted);font-weight:400;font-size:11px">${r.timestamp ? new Date(r.timestamp).toLocaleTimeString() : ''}</span>
|
|
3409
|
-
<span style="margin-left:8px;font-size:12px">${allPassed ? `<span style="color:var(--green)">✅ ${r.passed}/${r.results.length}</span>` : `<span style="color:var(--red)">❌ ${r.failed} failed</span>`}</span>
|
|
3410
|
-
</div>
|
|
3411
|
-
<div class="probe-checks">${rows}</div>
|
|
3412
|
-
</div>`;
|
|
3413
|
-
})() : `<div style="color:var(--muted);font-size:13px;padding:16px 0">Ещё не запускался</div>`;
|
|
3447
|
+
const isRunning = d?.status === 'running';
|
|
3448
|
+
const isScheduled = d?.status === 'scheduled';
|
|
3414
3449
|
|
|
3415
3450
|
const intervalOptions = [60, 300, 600, 1800, 3600].map(s => {
|
|
3416
3451
|
const label = s < 3600 ? `каждые ${s / 60} мин` : `каждый час`;
|
|
3417
|
-
const sel = d
|
|
3452
|
+
const sel = d?.intervalSec === s ? ' selected' : '';
|
|
3418
3453
|
return `<option value="${s}"${sel}>${label}</option>`;
|
|
3419
3454
|
}).join('');
|
|
3420
3455
|
|
|
3421
|
-
const
|
|
3422
|
-
|
|
3456
|
+
const checks = d?.checks || [];
|
|
3457
|
+
|
|
3458
|
+
const cards = checks.map(ch => {
|
|
3459
|
+
const status = probeCheckStatus(ch.name);
|
|
3460
|
+
const result = probeCheckResult(ch.name);
|
|
3461
|
+
const dur = result ? `${(result.durationMs / 1000).toFixed(1)}s` : '';
|
|
3462
|
+
const typeLabel = ch.type === 'file' ? 'playwright' : 'dsl';
|
|
3463
|
+
const stepsCount = ch.type === 'dsl' ? `${ch.steps.length} шагов` : ch.file?.split('/').pop() || '';
|
|
3464
|
+
return `
|
|
3465
|
+
<div class="probe-card ${status}" onclick="probeOpenDetail(${JSON.stringify(ch.name)})">
|
|
3466
|
+
<div class="probe-card-top">
|
|
3467
|
+
<div class="probe-card-name">${escapeHtml(ch.name)}</div>
|
|
3468
|
+
<div class="probe-card-icon">${probeStatusIcon(status)}</div>
|
|
3469
|
+
</div>
|
|
3470
|
+
<div class="probe-card-meta">
|
|
3471
|
+
<span class="probe-badge">${typeLabel}</span>
|
|
3472
|
+
<span class="probe-card-dur" style="color:var(--muted);font-size:11px">${escapeHtml(stepsCount)}</span>
|
|
3473
|
+
${dur ? `<span class="probe-card-dur">${dur}</span>` : ''}
|
|
3474
|
+
</div>
|
|
3475
|
+
${result?.error ? `<div class="probe-card-err">${escapeHtml(result.error)}</div>` : ''}
|
|
3476
|
+
<div class="probe-card-footer">
|
|
3477
|
+
<button class="probe-btn probe-btn-run" style="font-size:11px;padding:4px 10px"
|
|
3478
|
+
onclick="event.stopPropagation();probeRunOne(${JSON.stringify(ch.name)})"
|
|
3479
|
+
${status === 'running' ? 'disabled' : ''}>▶ Run</button>
|
|
3480
|
+
</div>
|
|
3481
|
+
</div>`;
|
|
3482
|
+
}).join('');
|
|
3483
|
+
|
|
3484
|
+
const lastTs = d?.lastRun?.timestamp ? `· последний запуск ${new Date(d.lastRun.timestamp).toLocaleTimeString()}` : '';
|
|
3485
|
+
const passedCount = checks.filter(ch => probeCheckStatus(ch.name) === 'passed').length;
|
|
3486
|
+
const failedCount = checks.filter(ch => probeCheckStatus(ch.name) === 'failed').length;
|
|
3487
|
+
const summary = checks.length
|
|
3488
|
+
? `${failedCount > 0 ? `<span style="color:var(--red)">❌ ${failedCount}</span> · ` : ''}${passedCount > 0 ? `<span style="color:var(--green)">✅ ${passedCount}</span> · ` : ''}${checks.length} checks ${lastTs}`
|
|
3489
|
+
: '';
|
|
3423
3490
|
|
|
3424
3491
|
c.innerHTML = `
|
|
3425
3492
|
<div class="probe-container">
|
|
3426
3493
|
<div class="probe-header">
|
|
3427
3494
|
<div>
|
|
3428
3495
|
<div class="probe-title">🔭 Probe monitoring</div>
|
|
3429
|
-
|
|
3430
|
-
:
|
|
3496
|
+
<div style="font-size:12px;color:var(--muted);margin-top:3px">
|
|
3497
|
+
${d?.effectiveTarget ? escapeHtml(d.effectiveTarget) + ' · ' : ''}${summary || '<span style="color:#e3b341">⚠️ Задайте домен в Настройках</span>'}
|
|
3498
|
+
</div>
|
|
3431
3499
|
</div>
|
|
3432
3500
|
<button class="probe-btn" onclick="openProbeSettingsModal()">⚙️ Настройки</button>
|
|
3433
3501
|
</div>
|
|
3434
3502
|
|
|
3435
|
-
<div class="probe-section">
|
|
3503
|
+
<div class="probe-section" style="margin-bottom:0">
|
|
3436
3504
|
<div class="probe-controls">
|
|
3437
3505
|
<button class="probe-btn probe-btn-run" onclick="probeRunNow()" ${isRunning ? 'disabled' : ''}>
|
|
3438
|
-
${isRunning ? '
|
|
3506
|
+
${isRunning ? '<span class="probe-spin">⏳</span> Выполняется…' : '▶ Run All'}
|
|
3439
3507
|
</button>
|
|
3440
3508
|
<div class="probe-schedule-row">
|
|
3441
|
-
<select id="probeIntervalSelect" class="probe-select">
|
|
3442
|
-
${intervalOptions}
|
|
3443
|
-
</select>
|
|
3509
|
+
<select id="probeIntervalSelect" class="probe-select">${intervalOptions}</select>
|
|
3444
3510
|
${isScheduled
|
|
3445
3511
|
? `<button class="probe-btn probe-btn-stop" onclick="probeScheduleStop()">⏹ Стоп</button>`
|
|
3446
|
-
: `<button class="probe-btn probe-btn-start" onclick="probeScheduleStart()">🕐 По расписанию</button>`
|
|
3447
|
-
|
|
3512
|
+
: `<button class="probe-btn probe-btn-start" onclick="probeScheduleStart()">🕐 По расписанию</button>`}
|
|
3513
|
+
</div>
|
|
3514
|
+
${isScheduled && d.nextRunAt ? `<span style="font-size:11px;color:var(--muted)">след. ${new Date(d.nextRunAt).toLocaleTimeString()}</span>` : ''}
|
|
3515
|
+
</div>
|
|
3516
|
+
</div>
|
|
3517
|
+
|
|
3518
|
+
${checks.length
|
|
3519
|
+
? `<div class="probe-cards">${cards}</div>`
|
|
3520
|
+
: `<div style="color:var(--muted);font-size:13px;padding:24px 0">Нет проверок в probe.config.yml</div>`}
|
|
3521
|
+
</div>`;
|
|
3522
|
+
}
|
|
3523
|
+
|
|
3524
|
+
function probeOpenDetail(checkName) {
|
|
3525
|
+
probeDetailCheck = checkName;
|
|
3526
|
+
renderContent();
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
function renderProbeDetail(c) {
|
|
3530
|
+
const d = probeData;
|
|
3531
|
+
const checks = d?.checks || [];
|
|
3532
|
+
const ch = checks.find(x => x.name === probeDetailCheck);
|
|
3533
|
+
if (!ch) { probeDetailCheck = null; renderProbePanel(c); return; }
|
|
3534
|
+
|
|
3535
|
+
const status = probeCheckStatus(ch.name);
|
|
3536
|
+
const result = probeCheckResult(ch.name);
|
|
3537
|
+
const isRunning = status === 'running';
|
|
3538
|
+
|
|
3539
|
+
const stepsHtml = ch.type === 'dsl' && ch.steps?.length
|
|
3540
|
+
? `<div style="font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px">Шаги</div>
|
|
3541
|
+
<div class="probe-steps-list">
|
|
3542
|
+
${ch.steps.map(s => `
|
|
3543
|
+
<div class="probe-step-row">
|
|
3544
|
+
<span class="probe-step-type">${escapeHtml(s.type)}</span>
|
|
3545
|
+
<span class="probe-step-val">${escapeHtml(s.value)}</span>
|
|
3546
|
+
</div>`).join('')}
|
|
3547
|
+
</div>` : '';
|
|
3548
|
+
|
|
3549
|
+
const fileHtml = ch.type === 'file'
|
|
3550
|
+
? `<div style="font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px">Файл теста</div>
|
|
3551
|
+
<code style="font-size:12px;color:var(--blue);background:var(--bg);padding:6px 10px;border-radius:4px;display:block">${escapeHtml(ch.file || '')}</code>` : '';
|
|
3552
|
+
|
|
3553
|
+
const outputHtml = result?.output
|
|
3554
|
+
? `<div style="font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-top:20px;margin-bottom:6px">Вывод</div>
|
|
3555
|
+
<div class="probe-output-box">${escapeHtml(result.output)}</div>` : '';
|
|
3556
|
+
|
|
3557
|
+
const errorHtml = result?.error && !result.output
|
|
3558
|
+
? `<div style="font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-top:20px;margin-bottom:6px">Ошибка</div>
|
|
3559
|
+
<div class="probe-output-box" style="color:var(--red)">${escapeHtml(result.error)}</div>` : '';
|
|
3560
|
+
|
|
3561
|
+
c.innerHTML = `
|
|
3562
|
+
<div class="probe-detail">
|
|
3563
|
+
<div class="probe-back" onclick="probeDetailCheck=null;renderContent()">← Назад к проверкам</div>
|
|
3564
|
+
|
|
3565
|
+
<div class="probe-detail-header">
|
|
3566
|
+
<div>
|
|
3567
|
+
<div class="probe-detail-title">${escapeHtml(ch.name)}</div>
|
|
3568
|
+
<div class="probe-detail-meta">
|
|
3569
|
+
<span class="probe-badge">${ch.type === 'file' ? 'playwright' : 'dsl'}</span>
|
|
3570
|
+
${probeStatusBadge(status)}
|
|
3571
|
+
${result ? `<span style="color:var(--muted)">${(result.durationMs / 1000).toFixed(1)}s</span>` : ''}
|
|
3572
|
+
${result ? `<span style="color:var(--muted)">${new Date().toLocaleTimeString()}</span>` : ''}
|
|
3448
3573
|
</div>
|
|
3449
3574
|
</div>
|
|
3450
|
-
|
|
3575
|
+
<button class="probe-btn probe-btn-run" style="flex-shrink:0" onclick="probeRunOne(${JSON.stringify(ch.name)})" ${isRunning ? 'disabled' : ''}>
|
|
3576
|
+
${isRunning ? '<span class="probe-spin">⏳</span> Выполняется…' : '▶ Run'}
|
|
3577
|
+
</button>
|
|
3451
3578
|
</div>
|
|
3452
3579
|
|
|
3453
|
-
${
|
|
3580
|
+
${stepsHtml}
|
|
3581
|
+
${fileHtml}
|
|
3582
|
+
${outputHtml}
|
|
3583
|
+
${errorHtml}
|
|
3454
3584
|
</div>`;
|
|
3455
3585
|
}
|
|
3456
3586
|
|
|
3457
3587
|
async function probeRunNow() {
|
|
3458
3588
|
probeRunning = true;
|
|
3459
3589
|
renderContent();
|
|
3460
|
-
try { await fetch('/api/probe/run', { method: 'POST' }); } catch {}
|
|
3590
|
+
try { await fetch('/api/probe/run', { method: 'POST', headers: {'Content-Type':'application/json'}, body: '{}' }); } catch {}
|
|
3591
|
+
}
|
|
3592
|
+
|
|
3593
|
+
async function probeRunOne(checkName) {
|
|
3594
|
+
try {
|
|
3595
|
+
await fetch('/api/probe/run', {
|
|
3596
|
+
method: 'POST',
|
|
3597
|
+
headers: { 'Content-Type': 'application/json' },
|
|
3598
|
+
body: JSON.stringify({ checkName }),
|
|
3599
|
+
});
|
|
3600
|
+
renderContent();
|
|
3601
|
+
} catch {}
|
|
3461
3602
|
}
|
|
3462
3603
|
|
|
3463
3604
|
async function probeScheduleStart() {
|
|
@@ -8007,11 +8148,29 @@ function connectSSE() {
|
|
|
8007
8148
|
if (contextMode === 'load') { renderSidebar(); renderContent(); }
|
|
8008
8149
|
});
|
|
8009
8150
|
|
|
8010
|
-
es.addEventListener('probe-run-started', () => {
|
|
8151
|
+
es.addEventListener('probe-run-started', (e) => {
|
|
8152
|
+
const payload = JSON.parse(e.data || '{}');
|
|
8011
8153
|
if (!probeData) probeData = {};
|
|
8012
8154
|
probeData.status = 'running';
|
|
8155
|
+
probeData.runningCheck = null;
|
|
8013
8156
|
probeRunning = true;
|
|
8014
|
-
if (
|
|
8157
|
+
if (contextMode === 'probe') renderContent();
|
|
8158
|
+
});
|
|
8159
|
+
|
|
8160
|
+
es.addEventListener('probe-check-started', (e) => {
|
|
8161
|
+
const payload = JSON.parse(e.data || '{}');
|
|
8162
|
+
if (!probeData) probeData = {};
|
|
8163
|
+
probeData.runningCheck = payload.checkName;
|
|
8164
|
+
if (contextMode === 'probe') renderContent();
|
|
8165
|
+
});
|
|
8166
|
+
|
|
8167
|
+
es.addEventListener('probe-check-done', (e) => {
|
|
8168
|
+
const result = JSON.parse(e.data || '{}');
|
|
8169
|
+
if (!probeData) probeData = {};
|
|
8170
|
+
if (!probeData.checkResults) probeData.checkResults = {};
|
|
8171
|
+
probeData.checkResults[result.check] = result;
|
|
8172
|
+
probeData.runningCheck = null;
|
|
8173
|
+
if (contextMode === 'probe') renderContent();
|
|
8015
8174
|
});
|
|
8016
8175
|
|
|
8017
8176
|
es.addEventListener('probe-run-done', (e) => {
|
|
@@ -8019,8 +8178,9 @@ function connectSSE() {
|
|
|
8019
8178
|
if (!probeData) probeData = {};
|
|
8020
8179
|
if (payload.results) probeData.lastRun = payload;
|
|
8021
8180
|
probeData.status = probeData.intervalSec ? 'scheduled' : 'idle';
|
|
8181
|
+
probeData.runningCheck = null;
|
|
8022
8182
|
probeRunning = false;
|
|
8023
|
-
if (
|
|
8183
|
+
if (contextMode === 'probe') renderContent();
|
|
8024
8184
|
});
|
|
8025
8185
|
|
|
8026
8186
|
es.addEventListener('probe-scheduled', (e) => {
|
|
@@ -8029,7 +8189,7 @@ function connectSSE() {
|
|
|
8029
8189
|
probeData.status = payload.status;
|
|
8030
8190
|
probeData.intervalSec = payload.intervalSec;
|
|
8031
8191
|
probeData.nextRunAt = payload.nextRunAt;
|
|
8032
|
-
if (
|
|
8192
|
+
if (contextMode === 'probe') renderContent();
|
|
8033
8193
|
});
|
|
8034
8194
|
|
|
8035
8195
|
es.onerror = () => {
|