viberadar 0.3.79 → 0.3.80
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/ui/dashboard.html +117 -1
- package/package.json +1 -1
package/dist/ui/dashboard.html
CHANGED
|
@@ -787,6 +787,34 @@
|
|
|
787
787
|
.obs-hint-label.before { color: var(--red); }
|
|
788
788
|
.obs-hint-label.after { color: var(--green); }
|
|
789
789
|
|
|
790
|
+
/* ── Progress & baseline delta badges ── */
|
|
791
|
+
.obs-kpi-delta {
|
|
792
|
+
display: block; font-size: 11px; font-weight: 700; margin-top: 2px; letter-spacing: 0.01em;
|
|
793
|
+
}
|
|
794
|
+
.obs-baseline-strip {
|
|
795
|
+
display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
|
|
796
|
+
padding: 4px 12px; background: rgba(255,255,255,0.02);
|
|
797
|
+
border: 1px solid rgba(255,255,255,0.07); border-radius: 6px;
|
|
798
|
+
font-size: 11px; color: var(--dim); margin-bottom: 6px;
|
|
799
|
+
}
|
|
800
|
+
.obs-baseline-strip button {
|
|
801
|
+
background: none; border: none; color: var(--accent); cursor: pointer;
|
|
802
|
+
font-size: 11px; padding: 0 2px; text-decoration: underline; text-underline-offset: 2px;
|
|
803
|
+
}
|
|
804
|
+
.obs-progress-banner {
|
|
805
|
+
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
|
|
806
|
+
padding: 8px 14px;
|
|
807
|
+
background: rgba(63,185,80,0.07); border: 1px solid rgba(63,185,80,0.2);
|
|
808
|
+
border-radius: 8px; margin-bottom: 8px; font-size: 12px;
|
|
809
|
+
}
|
|
810
|
+
.obs-progress-banner.has-regression {
|
|
811
|
+
background: rgba(248,81,73,0.07); border-color: rgba(248,81,73,0.2);
|
|
812
|
+
}
|
|
813
|
+
.obs-pb-title { color: #3fb950; font-weight: 700; font-size: 13px; flex-shrink: 0; }
|
|
814
|
+
.obs-pb-title.mixed { color: var(--yellow); }
|
|
815
|
+
.obs-pb-item { color: #3fb950; white-space: nowrap; }
|
|
816
|
+
.obs-pb-worse { color: #f85149; white-space: nowrap; }
|
|
817
|
+
|
|
790
818
|
/* ── Floating selection action bar ── */
|
|
791
819
|
.obs-floating-bar {
|
|
792
820
|
position: fixed;
|
|
@@ -2330,6 +2358,20 @@ function obsDispatchFloating() {
|
|
|
2330
2358
|
bar.classList.remove('visible');
|
|
2331
2359
|
}
|
|
2332
2360
|
|
|
2361
|
+
function obsTimeAgo(ts) {
|
|
2362
|
+
const s = Math.floor((Date.now() - ts) / 1000);
|
|
2363
|
+
if (s < 60) return `${s}с назад`;
|
|
2364
|
+
if (s < 3600) return `${Math.floor(s / 60)} мин назад`;
|
|
2365
|
+
if (s < 86400) return `${Math.floor(s / 3600)}ч назад`;
|
|
2366
|
+
return `${Math.floor(s / 86400)}д назад`;
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
function obsResetBaseline(key) {
|
|
2370
|
+
try { localStorage.removeItem('vr_obs_bl_' + key); } catch(e) {}
|
|
2371
|
+
const c = document.getElementById('content');
|
|
2372
|
+
if (c) renderObservability(c);
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2333
2375
|
function obsFloatingDismiss() {
|
|
2334
2376
|
const bar = document.getElementById('obsFloatingBar');
|
|
2335
2377
|
if (!bar) return;
|
|
@@ -2680,6 +2722,47 @@ function renderObservability(c) {
|
|
|
2680
2722
|
return val < warnThreshold ? 'var(--red)' : val < goodThreshold ? 'var(--yellow)' : 'var(--green)';
|
|
2681
2723
|
}
|
|
2682
2724
|
|
|
2725
|
+
// ── Baseline & delta tracking ──
|
|
2726
|
+
const _bsKey = String(D.currentFeatureKey || 'global').replace(/[^a-z0-9_-]/gi, '_');
|
|
2727
|
+
let _bl = null;
|
|
2728
|
+
try { _bl = JSON.parse(localStorage.getItem('vr_obs_bl_' + _bsKey) || 'null'); } catch(e) {}
|
|
2729
|
+
|
|
2730
|
+
// Pre-compute current snapshot values (before tierSections so _d is in scope)
|
|
2731
|
+
const _blCurrMissing = (o.missingCriticalLogsV2 || []).length;
|
|
2732
|
+
const _blCurrFPs = (o.missingCriticalLogsV2 || []).reduce((s, m) => s + (m.failurePoints || []).length, 0);
|
|
2733
|
+
const _blCurrNoise = (o.topNoisyPatterns || []).length;
|
|
2734
|
+
const _blCurrEnrich = Object.entries(o.fieldGaps || {}).filter(([, v]) => v > 0).length;
|
|
2735
|
+
const _blCurrTiers = {};
|
|
2736
|
+
['critical', 'important', 'normal'].forEach(tier => {
|
|
2737
|
+
const items = (o.missingCriticalLogsV2 || []).filter(m => m.riskTier === tier);
|
|
2738
|
+
_blCurrTiers[tier] = { modules: items.length, fps: items.reduce((s, m) => s + (m.failurePoints || []).length, 0) };
|
|
2739
|
+
});
|
|
2740
|
+
|
|
2741
|
+
if (!_bl) {
|
|
2742
|
+
_bl = { ts: Date.now(), noiseRatio, structPct, actionPct, coveragePct,
|
|
2743
|
+
missing: _blCurrMissing, fps: _blCurrFPs, noise: _blCurrNoise, enrich: _blCurrEnrich,
|
|
2744
|
+
tiers: _blCurrTiers };
|
|
2745
|
+
try { localStorage.setItem('vr_obs_bl_' + _bsKey, JSON.stringify(_bl)); } catch(e) {}
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
// Delta badge helpers
|
|
2749
|
+
const _d = (curr, base, invert = false) => {
|
|
2750
|
+
if (base == null || curr === base) return '';
|
|
2751
|
+
const diff = curr - base;
|
|
2752
|
+
const good = invert ? diff > 0 : diff < 0;
|
|
2753
|
+
const color = good ? '#3fb950' : '#f85149';
|
|
2754
|
+
const sign = diff > 0 ? '+' : '';
|
|
2755
|
+
return `<span style="color:${color};font-size:11px;font-weight:700;margin-left:5px">(${sign}${diff})</span>`;
|
|
2756
|
+
};
|
|
2757
|
+
const _dp = (curr, base, invert = false) => {
|
|
2758
|
+
if (base == null || curr === base) return '';
|
|
2759
|
+
const diff = curr - base;
|
|
2760
|
+
const good = invert ? diff > 0 : diff < 0;
|
|
2761
|
+
const color = good ? '#3fb950' : '#f85149';
|
|
2762
|
+
const arrow = good ? '↓' : '↑';
|
|
2763
|
+
return `<span class="obs-kpi-delta" style="color:${color}">${arrow}${Math.abs(diff)}%</span>`;
|
|
2764
|
+
};
|
|
2765
|
+
|
|
2683
2766
|
const formatLabels = { structured: 'structured', mixed: 'mixed', unstructured: 'unstructured' };
|
|
2684
2767
|
const sourceByFormat = [
|
|
2685
2768
|
{ label: 'Structured', count: o.catalog.filter(c => c.format === 'structured').length, color: 'var(--green)' },
|
|
@@ -2756,10 +2839,11 @@ function renderObservability(c) {
|
|
|
2756
2839
|
<div class="obs-detail-list">${detailItems}</div>
|
|
2757
2840
|
<div class="obs-detail-bar">${addBtn}</div>
|
|
2758
2841
|
</div>` : '';
|
|
2842
|
+
const _blTier = _bl?.tiers?.[tier];
|
|
2759
2843
|
return `<div class="obs-tier-group">
|
|
2760
2844
|
<div class="obs-tier-group-header">
|
|
2761
2845
|
<span class="obs-tier-badge obs-tier-${tier}">${tierLabels[tier]}</span>
|
|
2762
|
-
<span>${items.length} модулей, ${totalFPs} точек отказа</span>
|
|
2846
|
+
<span>${items.length}${_d(items.length, _blTier?.modules)} модулей, ${totalFPs}${_d(totalFPs, _blTier?.fps)} точек отказа</span>
|
|
2763
2847
|
${expandBtn}
|
|
2764
2848
|
</div>
|
|
2765
2849
|
${detail}
|
|
@@ -2822,27 +2906,59 @@ function renderObservability(c) {
|
|
|
2822
2906
|
const enrichCount = fieldGapEntries.length;
|
|
2823
2907
|
const catalogCount = o.catalog.length;
|
|
2824
2908
|
|
|
2909
|
+
// ── Build progress banner comparing to baseline ──
|
|
2910
|
+
const _blItems = [];
|
|
2911
|
+
if (_bl.missing != null && missingCount !== _bl.missing)
|
|
2912
|
+
_blItems.push({ label: `модулей без логов: ${_bl.missing} → ${missingCount}`, good: missingCount < _bl.missing });
|
|
2913
|
+
if (_bl.fps != null && _blCurrFPs !== _bl.fps)
|
|
2914
|
+
_blItems.push({ label: `точек отказа: ${_bl.fps} → ${_blCurrFPs}`, good: _blCurrFPs < _bl.fps });
|
|
2915
|
+
if (_bl.noise != null && noisyCount !== _bl.noise)
|
|
2916
|
+
_blItems.push({ label: `шумных паттернов: ${_bl.noise} → ${noisyCount}`, good: noisyCount < _bl.noise });
|
|
2917
|
+
if (_bl.enrich != null && enrichCount !== _bl.enrich)
|
|
2918
|
+
_blItems.push({ label: `нужно обогатить: ${_bl.enrich} → ${enrichCount}`, good: enrichCount < _bl.enrich });
|
|
2919
|
+
|
|
2920
|
+
const _hasReg = _blItems.some(x => !x.good);
|
|
2921
|
+
const _hasImp = _blItems.some(x => x.good);
|
|
2922
|
+
const _progressBanner = _blItems.length ? `
|
|
2923
|
+
<div class="obs-progress-banner${_hasReg ? ' has-regression' : ''}">
|
|
2924
|
+
<span class="obs-pb-title${_hasReg && _hasImp ? ' mixed' : _hasReg ? ' obs-pb-worse' : ''}">📊 прогресс</span>
|
|
2925
|
+
${_blItems.map(it => `<span class="${it.good ? 'obs-pb-item' : 'obs-pb-worse'}">${it.good ? '✅' : '⚠️'} ${it.label}</span>`).join('')}
|
|
2926
|
+
</div>` : '';
|
|
2927
|
+
|
|
2928
|
+
const _baselineStrip = `
|
|
2929
|
+
<div class="obs-baseline-strip">
|
|
2930
|
+
<span>📍 baseline: ${obsTimeAgo(_bl.ts)}</span>
|
|
2931
|
+
<button onclick="obsResetBaseline('${_bsKey}')">обновить</button>
|
|
2932
|
+
</div>`;
|
|
2933
|
+
|
|
2825
2934
|
c.innerHTML = `
|
|
2826
2935
|
<div class="onboarding-block">
|
|
2827
2936
|
<h3>Наблюдаемость: что это?</h3>
|
|
2828
2937
|
<p>Аудит покрытия логами: что добавить, что убрать, что обогатить — на основе статического анализа лог-вызовов.</p>
|
|
2829
2938
|
</div>
|
|
2830
2939
|
|
|
2940
|
+
${_progressBanner}
|
|
2941
|
+
${_baselineStrip}
|
|
2942
|
+
|
|
2831
2943
|
<div class="obs-kpi-strip">
|
|
2832
2944
|
<div class="obs-kpi">
|
|
2833
2945
|
<span class="obs-kpi-value" style="color:${metricColor(noiseRatio,10,30,true)}">${noiseRatio}%</span>
|
|
2946
|
+
${_dp(noiseRatio, _bl?.noiseRatio, true)}
|
|
2834
2947
|
<span class="obs-kpi-label">Шум</span>
|
|
2835
2948
|
</div>
|
|
2836
2949
|
<div class="obs-kpi">
|
|
2837
2950
|
<span class="obs-kpi-value" style="color:${metricColor(structPct,80,50,false)}">${structPct}%</span>
|
|
2951
|
+
${_dp(structPct, _bl?.structPct)}
|
|
2838
2952
|
<span class="obs-kpi-label">Структурированность</span>
|
|
2839
2953
|
</div>
|
|
2840
2954
|
<div class="obs-kpi">
|
|
2841
2955
|
<span class="obs-kpi-value" style="color:${metricColor(actionPct,80,50,false)}">${actionPct}%</span>
|
|
2956
|
+
${_dp(actionPct, _bl?.actionPct)}
|
|
2842
2957
|
<span class="obs-kpi-label">Actionable ошибки</span>
|
|
2843
2958
|
</div>
|
|
2844
2959
|
<div class="obs-kpi">
|
|
2845
2960
|
<span class="obs-kpi-value" style="color:${metricColor(coveragePct,80,50,false)}">${coveragePct}%</span>
|
|
2961
|
+
${_dp(coveragePct, _bl?.coveragePct)}
|
|
2846
2962
|
<span class="obs-kpi-label">Покрытие сценариев</span>
|
|
2847
2963
|
</div>
|
|
2848
2964
|
</div>
|