viberadar 0.3.178 → 0.3.180

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.
@@ -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: 720px; }
1565
- .probe-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 20px; gap: 12px; }
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
- .probe-checks { display: flex; flex-direction: column; gap: 8px; }
1582
- .probe-check-row { display: grid; grid-template-columns: 20px 1fr auto; align-items: baseline; gap: 6px; font-size: 13px; }
1583
- .probe-check-icon { font-size: 14px; }
1584
- .probe-check-name { color: var(--text); }
1585
- .probe-check-dur { font-size: 11px; }
1586
- .probe-check-error { grid-column: 2 / -1; font-size: 11px; color: var(--red); margin-top: 2px; word-break: break-word; }
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;
@@ -1749,6 +1778,7 @@ const modeStore = {
1749
1778
  scenarios: { view: 'list', searchQuery: '', activeTypes: new Set(), drillFeatureKey: null, drillTestType: null, activePanelKey: null, showOnlyUntestedInFeature: false, testNavType: 'all', testNavFeature: null, testNavProblem: null },
1750
1779
  services: { view: 'graph', searchQuery: '', activeTypes: new Set(), drillFeatureKey: null, drillTestType: null, activePanelKey: null, showOnlyUntestedInFeature: false, testNavType: 'all', testNavFeature: null, testNavProblem: null, svcTab: 'graph' },
1751
1780
  load: { view: 'features', searchQuery: '', activeTypes: new Set(), drillFeatureKey: null, drillTestType: null, activePanelKey: null, showOnlyUntestedInFeature: false, testNavType: 'all', testNavFeature: null, testNavProblem: null },
1781
+ probe: { view: 'features', searchQuery: '', activeTypes: new Set(), drillFeatureKey: null, drillTestType: null, activePanelKey: null, showOnlyUntestedInFeature: false, testNavType: 'all', testNavFeature: null, testNavProblem: null },
1752
1782
  };
1753
1783
 
1754
1784
  function getModeFromPath(pathname = window.location.pathname) {
@@ -1756,6 +1786,7 @@ function getModeFromPath(pathname = window.location.pathname) {
1756
1786
  if (pathname.startsWith('/radar/docs')) return 'docs';
1757
1787
  if (pathname.startsWith('/radar/services')) return 'services';
1758
1788
  if (pathname.startsWith('/radar/load')) return 'load';
1789
+ if (pathname.startsWith('/radar/probe')) return 'probe';
1759
1790
  return 'qa';
1760
1791
  }
1761
1792
 
@@ -1764,6 +1795,7 @@ function routePathForMode(mode) {
1764
1795
  if (mode === 'docs') return '/radar/docs';
1765
1796
  if (mode === 'services') return '/radar/services';
1766
1797
  if (mode === 'load') return '/radar/load';
1798
+ if (mode === 'probe') return '/radar/probe';
1767
1799
  return '/radar/qa';
1768
1800
  }
1769
1801
 
@@ -3382,79 +3414,190 @@ async function loadProbeData() {
3382
3414
  } catch {}
3383
3415
  }
3384
3416
 
3417
+ function probeCheckStatus(checkName) {
3418
+ if (!probeData) return 'idle';
3419
+ if (probeData.runningCheck === checkName) return 'running';
3420
+ const r = probeData.checkResults?.[checkName];
3421
+ return r ? r.status : 'idle';
3422
+ }
3423
+
3424
+ function probeCheckResult(checkName) {
3425
+ return probeData?.checkResults?.[checkName] || null;
3426
+ }
3427
+
3428
+ function probeStatusIcon(status) {
3429
+ if (status === 'running') return `<span class="probe-spin">⏳</span>`;
3430
+ if (status === 'passed') return '✅';
3431
+ if (status === 'failed') return '❌';
3432
+ return '⏸';
3433
+ }
3434
+
3435
+ function probeStatusBadge(status) {
3436
+ if (status === 'running') return `<span class="probe-status-badge probe-status-running"><span class="probe-spin">⏳</span> Выполняется</span>`;
3437
+ if (status === 'passed') return `<span class="probe-status-badge probe-status-passed">✅ Passed</span>`;
3438
+ if (status === 'failed') return `<span class="probe-status-badge probe-status-failed">❌ Failed</span>`;
3439
+ return `<span class="probe-status-badge probe-status-idle">⏸ Не запускался</span>`;
3440
+ }
3441
+
3385
3442
  function renderProbePanel(c) {
3443
+ if (probeDetailCheck !== null) { renderProbeDetail(c); return; }
3444
+
3386
3445
  const d = probeData;
3387
- const statusColor = !d ? 'var(--muted)' : d.status === 'running' ? 'var(--yellow)' : d.status === 'scheduled' ? 'var(--green)' : 'var(--muted)';
3388
- const statusLabel = !d ? '—' : d.status === 'running' ? '● running' : d.status === 'scheduled' ? '● scheduled' : '○ idle';
3389
-
3390
- const lastRunHtml = d && d.lastRun ? (() => {
3391
- const r = d.lastRun;
3392
- const allPassed = r.failed === 0;
3393
- const rows = r.results.map(res => {
3394
- const ok = res.status === 'passed';
3395
- return `<div class="probe-check-row">
3396
- <span class="probe-check-icon">${ok ? '✅' : '❌'}</span>
3397
- <span class="probe-check-name">${escapeHtml(res.check)}</span>
3398
- <span class="probe-check-dur" style="color:var(--muted)">${res.durationMs}ms</span>
3399
- ${!ok && res.error ? `<div class="probe-check-error">${escapeHtml(res.error)}</div>` : ''}
3400
- ${!ok && res.screenshotPath ? `<div class="probe-check-error" style="color:var(--muted)">📸 ${escapeHtml(res.screenshotPath)}</div>` : ''}
3401
- </div>`;
3402
- }).join('');
3403
- return `
3404
- <div class="probe-section">
3405
- <div class="probe-section-title">Последний прогон <span style="color:var(--muted);font-weight:400;font-size:11px">${r.timestamp ? new Date(r.timestamp).toLocaleTimeString() : ''}</span>
3406
- <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>
3407
- </div>
3408
- <div class="probe-checks">${rows}</div>
3409
- </div>`;
3410
- })() : `<div style="color:var(--muted);font-size:13px;padding:16px 0">Ещё не запускался</div>`;
3446
+ const isRunning = d?.status === 'running';
3447
+ const isScheduled = d?.status === 'scheduled';
3411
3448
 
3412
3449
  const intervalOptions = [60, 300, 600, 1800, 3600].map(s => {
3413
3450
  const label = s < 3600 ? `каждые ${s / 60} мин` : `каждый час`;
3414
- const sel = d && d.intervalSec === s ? ' selected' : '';
3451
+ const sel = d?.intervalSec === s ? ' selected' : '';
3415
3452
  return `<option value="${s}"${sel}>${label}</option>`;
3416
3453
  }).join('');
3417
3454
 
3418
- const isScheduled = d && d.status === 'scheduled';
3419
- const isRunning = d && d.status === 'running';
3455
+ const checks = d?.checks || [];
3456
+
3457
+ const cards = checks.map(ch => {
3458
+ const status = probeCheckStatus(ch.name);
3459
+ const result = probeCheckResult(ch.name);
3460
+ const dur = result ? `${(result.durationMs / 1000).toFixed(1)}s` : '';
3461
+ const typeLabel = ch.type === 'file' ? 'playwright' : 'dsl';
3462
+ const stepsCount = ch.type === 'dsl' ? `${ch.steps.length} шагов` : ch.file?.split('/').pop() || '';
3463
+ return `
3464
+ <div class="probe-card ${status}" onclick="probeOpenDetail(${JSON.stringify(ch.name)})">
3465
+ <div class="probe-card-top">
3466
+ <div class="probe-card-name">${escapeHtml(ch.name)}</div>
3467
+ <div class="probe-card-icon">${probeStatusIcon(status)}</div>
3468
+ </div>
3469
+ <div class="probe-card-meta">
3470
+ <span class="probe-badge">${typeLabel}</span>
3471
+ <span class="probe-card-dur" style="color:var(--muted);font-size:11px">${escapeHtml(stepsCount)}</span>
3472
+ ${dur ? `<span class="probe-card-dur">${dur}</span>` : ''}
3473
+ </div>
3474
+ ${result?.error ? `<div class="probe-card-err">${escapeHtml(result.error)}</div>` : ''}
3475
+ <div class="probe-card-footer">
3476
+ <button class="probe-btn probe-btn-run" style="font-size:11px;padding:4px 10px"
3477
+ onclick="event.stopPropagation();probeRunOne(${JSON.stringify(ch.name)})"
3478
+ ${status === 'running' ? 'disabled' : ''}>▶ Run</button>
3479
+ </div>
3480
+ </div>`;
3481
+ }).join('');
3482
+
3483
+ const lastTs = d?.lastRun?.timestamp ? `· последний запуск ${new Date(d.lastRun.timestamp).toLocaleTimeString()}` : '';
3484
+ const passedCount = checks.filter(ch => probeCheckStatus(ch.name) === 'passed').length;
3485
+ const failedCount = checks.filter(ch => probeCheckStatus(ch.name) === 'failed').length;
3486
+ const summary = checks.length
3487
+ ? `${failedCount > 0 ? `<span style="color:var(--red)">❌ ${failedCount}</span> · ` : ''}${passedCount > 0 ? `<span style="color:var(--green)">✅ ${passedCount}</span> · ` : ''}${checks.length} checks ${lastTs}`
3488
+ : '';
3420
3489
 
3421
3490
  c.innerHTML = `
3422
3491
  <div class="probe-container">
3423
3492
  <div class="probe-header">
3424
3493
  <div>
3425
3494
  <div class="probe-title">🔭 Probe monitoring</div>
3426
- ${d && d.effectiveTarget ? `<div style="color:var(--muted);font-size:12px">${escapeHtml(d.effectiveTarget)} · ${escapeHtml((d.checks || []).length)} checks · <span style="color:${statusColor}">${statusLabel}</span></div>`
3427
- : `<div style="color:var(--yellow);font-size:12px">⚠️ Задайте домен стенда в Настройках</div>`}
3495
+ <div style="font-size:12px;color:var(--muted);margin-top:3px">
3496
+ ${d?.effectiveTarget ? escapeHtml(d.effectiveTarget) + ' · ' : ''}${summary || '<span style="color:#e3b341">⚠️ Задайте домен в Настройках</span>'}
3497
+ </div>
3428
3498
  </div>
3429
3499
  <button class="probe-btn" onclick="openProbeSettingsModal()">⚙️ Настройки</button>
3430
3500
  </div>
3431
3501
 
3432
- <div class="probe-section">
3502
+ <div class="probe-section" style="margin-bottom:0">
3433
3503
  <div class="probe-controls">
3434
3504
  <button class="probe-btn probe-btn-run" onclick="probeRunNow()" ${isRunning ? 'disabled' : ''}>
3435
- ${isRunning ? ' Выполняется…' : '▶ Run Now'}
3505
+ ${isRunning ? '<span class="probe-spin">⏳</span> Выполняется…' : '▶ Run All'}
3436
3506
  </button>
3437
3507
  <div class="probe-schedule-row">
3438
- <select id="probeIntervalSelect" class="probe-select">
3439
- ${intervalOptions}
3440
- </select>
3508
+ <select id="probeIntervalSelect" class="probe-select">${intervalOptions}</select>
3441
3509
  ${isScheduled
3442
3510
  ? `<button class="probe-btn probe-btn-stop" onclick="probeScheduleStop()">⏹ Стоп</button>`
3443
- : `<button class="probe-btn probe-btn-start" onclick="probeScheduleStart()">🕐 По расписанию</button>`
3444
- }
3511
+ : `<button class="probe-btn probe-btn-start" onclick="probeScheduleStart()">🕐 По расписанию</button>`}
3512
+ </div>
3513
+ ${isScheduled && d.nextRunAt ? `<span style="font-size:11px;color:var(--muted)">след. ${new Date(d.nextRunAt).toLocaleTimeString()}</span>` : ''}
3514
+ </div>
3515
+ </div>
3516
+
3517
+ ${checks.length
3518
+ ? `<div class="probe-cards">${cards}</div>`
3519
+ : `<div style="color:var(--muted);font-size:13px;padding:24px 0">Нет проверок в probe.config.yml</div>`}
3520
+ </div>`;
3521
+ }
3522
+
3523
+ function probeOpenDetail(checkName) {
3524
+ probeDetailCheck = checkName;
3525
+ renderContent();
3526
+ }
3527
+
3528
+ function renderProbeDetail(c) {
3529
+ const d = probeData;
3530
+ const checks = d?.checks || [];
3531
+ const ch = checks.find(x => x.name === probeDetailCheck);
3532
+ if (!ch) { probeDetailCheck = null; renderProbePanel(c); return; }
3533
+
3534
+ const status = probeCheckStatus(ch.name);
3535
+ const result = probeCheckResult(ch.name);
3536
+ const isRunning = status === 'running';
3537
+
3538
+ const stepsHtml = ch.type === 'dsl' && ch.steps?.length
3539
+ ? `<div style="font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px">Шаги</div>
3540
+ <div class="probe-steps-list">
3541
+ ${ch.steps.map(s => `
3542
+ <div class="probe-step-row">
3543
+ <span class="probe-step-type">${escapeHtml(s.type)}</span>
3544
+ <span class="probe-step-val">${escapeHtml(s.value)}</span>
3545
+ </div>`).join('')}
3546
+ </div>` : '';
3547
+
3548
+ const fileHtml = ch.type === 'file'
3549
+ ? `<div style="font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px">Файл теста</div>
3550
+ <code style="font-size:12px;color:var(--blue);background:var(--bg);padding:6px 10px;border-radius:4px;display:block">${escapeHtml(ch.file || '')}</code>` : '';
3551
+
3552
+ const outputHtml = result?.output
3553
+ ? `<div style="font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-top:20px;margin-bottom:6px">Вывод</div>
3554
+ <div class="probe-output-box">${escapeHtml(result.output)}</div>` : '';
3555
+
3556
+ const errorHtml = result?.error && !result.output
3557
+ ? `<div style="font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-top:20px;margin-bottom:6px">Ошибка</div>
3558
+ <div class="probe-output-box" style="color:var(--red)">${escapeHtml(result.error)}</div>` : '';
3559
+
3560
+ c.innerHTML = `
3561
+ <div class="probe-detail">
3562
+ <div class="probe-back" onclick="probeDetailCheck=null;renderContent()">← Назад к проверкам</div>
3563
+
3564
+ <div class="probe-detail-header">
3565
+ <div>
3566
+ <div class="probe-detail-title">${escapeHtml(ch.name)}</div>
3567
+ <div class="probe-detail-meta">
3568
+ <span class="probe-badge">${ch.type === 'file' ? 'playwright' : 'dsl'}</span>
3569
+ ${probeStatusBadge(status)}
3570
+ ${result ? `<span style="color:var(--muted)">${(result.durationMs / 1000).toFixed(1)}s</span>` : ''}
3571
+ ${result ? `<span style="color:var(--muted)">${new Date().toLocaleTimeString()}</span>` : ''}
3445
3572
  </div>
3446
3573
  </div>
3447
- ${isScheduled && d.nextRunAt ? `<div style="font-size:11px;color:var(--muted);margin-top:6px">Следующий запуск: ${new Date(d.nextRunAt).toLocaleTimeString()}</div>` : ''}
3574
+ <button class="probe-btn probe-btn-run" style="flex-shrink:0" onclick="probeRunOne(${JSON.stringify(ch.name)})" ${isRunning ? 'disabled' : ''}>
3575
+ ${isRunning ? '<span class="probe-spin">⏳</span> Выполняется…' : '▶ Run'}
3576
+ </button>
3448
3577
  </div>
3449
3578
 
3450
- ${lastRunHtml}
3579
+ ${stepsHtml}
3580
+ ${fileHtml}
3581
+ ${outputHtml}
3582
+ ${errorHtml}
3451
3583
  </div>`;
3452
3584
  }
3453
3585
 
3454
3586
  async function probeRunNow() {
3455
3587
  probeRunning = true;
3456
3588
  renderContent();
3457
- try { await fetch('/api/probe/run', { method: 'POST' }); } catch {}
3589
+ try { await fetch('/api/probe/run', { method: 'POST', headers: {'Content-Type':'application/json'}, body: '{}' }); } catch {}
3590
+ }
3591
+
3592
+ async function probeRunOne(checkName) {
3593
+ try {
3594
+ await fetch('/api/probe/run', {
3595
+ method: 'POST',
3596
+ headers: { 'Content-Type': 'application/json' },
3597
+ body: JSON.stringify({ checkName }),
3598
+ });
3599
+ renderContent();
3600
+ } catch {}
3458
3601
  }
3459
3602
 
3460
3603
  async function probeScheduleStart() {
@@ -8004,11 +8147,29 @@ function connectSSE() {
8004
8147
  if (contextMode === 'load') { renderSidebar(); renderContent(); }
8005
8148
  });
8006
8149
 
8007
- es.addEventListener('probe-run-started', () => {
8150
+ es.addEventListener('probe-run-started', (e) => {
8151
+ const payload = JSON.parse(e.data || '{}');
8008
8152
  if (!probeData) probeData = {};
8009
8153
  probeData.status = 'running';
8154
+ probeData.runningCheck = null;
8010
8155
  probeRunning = true;
8011
- if (view === 'probe') renderContent();
8156
+ if (contextMode === 'probe') renderContent();
8157
+ });
8158
+
8159
+ es.addEventListener('probe-check-started', (e) => {
8160
+ const payload = JSON.parse(e.data || '{}');
8161
+ if (!probeData) probeData = {};
8162
+ probeData.runningCheck = payload.checkName;
8163
+ if (contextMode === 'probe') renderContent();
8164
+ });
8165
+
8166
+ es.addEventListener('probe-check-done', (e) => {
8167
+ const result = JSON.parse(e.data || '{}');
8168
+ if (!probeData) probeData = {};
8169
+ if (!probeData.checkResults) probeData.checkResults = {};
8170
+ probeData.checkResults[result.check] = result;
8171
+ probeData.runningCheck = null;
8172
+ if (contextMode === 'probe') renderContent();
8012
8173
  });
8013
8174
 
8014
8175
  es.addEventListener('probe-run-done', (e) => {
@@ -8016,8 +8177,9 @@ function connectSSE() {
8016
8177
  if (!probeData) probeData = {};
8017
8178
  if (payload.results) probeData.lastRun = payload;
8018
8179
  probeData.status = probeData.intervalSec ? 'scheduled' : 'idle';
8180
+ probeData.runningCheck = null;
8019
8181
  probeRunning = false;
8020
- if (view === 'probe') renderContent();
8182
+ if (contextMode === 'probe') renderContent();
8021
8183
  });
8022
8184
 
8023
8185
  es.addEventListener('probe-scheduled', (e) => {
@@ -8026,7 +8188,7 @@ function connectSSE() {
8026
8188
  probeData.status = payload.status;
8027
8189
  probeData.intervalSec = payload.intervalSec;
8028
8190
  probeData.nextRunAt = payload.nextRunAt;
8029
- if (view === 'probe') renderContent();
8191
+ if (contextMode === 'probe') renderContent();
8030
8192
  });
8031
8193
 
8032
8194
  es.onerror = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viberadar",
3
- "version": "0.3.178",
3
+ "version": "0.3.180",
4
4
  "description": "Live module map with test coverage for vibecoding projects",
5
5
  "main": "./dist/cli.js",
6
6
  "bin": {