viberadar 0.3.78 → 0.3.79

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.
@@ -787,6 +787,50 @@
787
787
  .obs-hint-label.before { color: var(--red); }
788
788
  .obs-hint-label.after { color: var(--green); }
789
789
 
790
+ /* ── Floating selection action bar ── */
791
+ .obs-floating-bar {
792
+ position: fixed;
793
+ bottom: -80px;
794
+ left: 50%;
795
+ transform: translateX(-50%);
796
+ z-index: 300;
797
+ display: flex; align-items: center; gap: 12px;
798
+ background: #1c2128;
799
+ border: 1px solid var(--accent);
800
+ border-radius: 10px;
801
+ padding: 10px 10px 10px 16px;
802
+ box-shadow: 0 8px 32px rgba(0,0,0,0.5), 0 0 0 1px rgba(88,166,255,0.15);
803
+ min-width: 340px;
804
+ transition: bottom 0.25s cubic-bezier(0.34,1.56,0.64,1);
805
+ pointer-events: none;
806
+ opacity: 0;
807
+ }
808
+ .obs-floating-bar.visible {
809
+ bottom: 28px;
810
+ pointer-events: auto;
811
+ opacity: 1;
812
+ }
813
+ .obs-floating-count {
814
+ color: var(--text); font-size: 13px; font-weight: 600; white-space: nowrap;
815
+ }
816
+ .obs-floating-label {
817
+ color: var(--muted); font-size: 12px; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
818
+ }
819
+ .obs-floating-btn {
820
+ padding: 8px 18px; font-size: 13px; font-weight: 600;
821
+ background: var(--accent); color: var(--bg);
822
+ border: none; border-radius: 6px; cursor: pointer; min-height: 36px;
823
+ white-space: nowrap; flex-shrink: 0;
824
+ transition: opacity 0.1s;
825
+ }
826
+ .obs-floating-btn:hover { opacity: 0.85; }
827
+ .obs-floating-dismiss {
828
+ background: none; border: none; color: var(--dim); cursor: pointer;
829
+ font-size: 16px; padding: 4px 6px; line-height: 1; flex-shrink: 0;
830
+ border-radius: 4px; transition: color 0.1s;
831
+ }
832
+ .obs-floating-dismiss:hover { color: var(--text); }
833
+
790
834
  .file-row-err-badge {
791
835
  display: inline-flex; align-items: center;
792
836
  font-size: 11px; padding: 1px 6px; border-radius: 10px;
@@ -1219,6 +1263,13 @@
1219
1263
  <div id="panelContent"></div>
1220
1264
  </div>
1221
1265
 
1266
+ <div class="obs-floating-bar" id="obsFloatingBar">
1267
+ <span class="obs-floating-count" id="obsFloatingCount">0 выбрано</span>
1268
+ <span class="obs-floating-label" id="obsFloatingLabel"></span>
1269
+ <button class="obs-floating-btn" id="obsFloatingBtn" onclick="obsDispatchFloating()">запустить</button>
1270
+ <button class="obs-floating-dismiss" title="Снять выделение" onclick="obsFloatingDismiss()">✕</button>
1271
+ </div>
1272
+
1222
1273
  <div class="agent-panel" id="agentPanel">
1223
1274
  <div class="agent-panel-header">
1224
1275
  <span class="agent-panel-title" id="agentPanelTitle">🤖 Agent</span>
@@ -2237,9 +2288,62 @@ function obsUpdateSelectedCount(groupId) {
2237
2288
  const checked = container.querySelectorAll('input[type="checkbox"]:checked').length;
2238
2289
  const btn = container.querySelector('.obs-run-selected');
2239
2290
  if (btn) {
2240
- btn.textContent = checked > 0 ? `исправить выбранные (${checked})` : 'исправить выбранные';
2291
+ const baseLabel = btn.dataset.baseLabel || btn.textContent.replace(/\s*\(\d+\)$/, '');
2292
+ btn.dataset.baseLabel = baseLabel;
2293
+ btn.textContent = checked > 0 ? `${baseLabel} (${checked})` : baseLabel;
2241
2294
  btn.disabled = checked === 0;
2242
2295
  }
2296
+ // Update floating action bar
2297
+ const bar = document.getElementById('obsFloatingBar');
2298
+ if (!bar) return;
2299
+ if (checked > 0) {
2300
+ const action = container.dataset.obsAction || '';
2301
+ const actionLabels = { missing: 'добавить логи', field: 'обогатить поля', rec: 'исправить' };
2302
+ const groupLabel = container.dataset.obsLabel || '';
2303
+ bar.dataset.groupId = groupId;
2304
+ document.getElementById('obsFloatingCount').textContent = `${checked} выбрано`;
2305
+ document.getElementById('obsFloatingLabel').textContent = groupLabel;
2306
+ document.getElementById('obsFloatingBtn').textContent = actionLabels[action] || 'исправить';
2307
+ bar.classList.add('visible');
2308
+ } else {
2309
+ if (bar.dataset.groupId === groupId) {
2310
+ bar.classList.remove('visible');
2311
+ delete bar.dataset.groupId;
2312
+ }
2313
+ }
2314
+ }
2315
+
2316
+ function obsDispatchFloating() {
2317
+ const bar = document.getElementById('obsFloatingBar');
2318
+ if (!bar) return;
2319
+ const groupId = bar.dataset.groupId;
2320
+ if (!groupId) return;
2321
+ const container = document.getElementById('obs-detail-' + groupId);
2322
+ if (!container) return;
2323
+ const action = container.dataset.obsAction || '';
2324
+ if (action === 'missing') {
2325
+ obsMissingRunSelected(groupId);
2326
+ } else {
2327
+ const meta = container.dataset.obsMeta ? JSON.parse(container.dataset.obsMeta) : {};
2328
+ obsRunSelected(groupId, 'obs-fix-selected', meta);
2329
+ }
2330
+ bar.classList.remove('visible');
2331
+ }
2332
+
2333
+ function obsFloatingDismiss() {
2334
+ const bar = document.getElementById('obsFloatingBar');
2335
+ if (!bar) return;
2336
+ const groupId = bar.dataset.groupId;
2337
+ if (groupId) {
2338
+ const container = document.getElementById('obs-detail-' + groupId);
2339
+ if (container) {
2340
+ container.querySelectorAll('input[type="checkbox"]').forEach(cb => cb.checked = false);
2341
+ const btn = container.querySelector('.obs-run-selected');
2342
+ if (btn) { btn.textContent = btn.dataset.baseLabel || btn.textContent.replace(/\s*\(\d+\)$/, ''); btn.disabled = true; }
2343
+ }
2344
+ delete bar.dataset.groupId;
2345
+ }
2346
+ bar.classList.remove('visible');
2243
2347
  }
2244
2348
 
2245
2349
  function obsToggleAll(groupId) {
@@ -2645,7 +2749,7 @@ function renderObservability(c) {
2645
2749
  }).join('');
2646
2750
  const addBtn = hasAgent ? `<button class="obs-run-selected" disabled onclick="obsMissingRunSelected('${groupId}')">добавить логи выбранным</button>` : '';
2647
2751
  const detail = hasAgent ? `
2648
- <div id="obs-detail-${groupId}" class="obs-detail">
2752
+ <div id="obs-detail-${groupId}" class="obs-detail" data-obs-action="missing" data-obs-label="${tierLabels[tier]}">
2649
2753
  <div class="obs-detail-bar" style="border-top:none;padding-top:0;margin-bottom:4px">
2650
2754
  <button class="obs-select-all" onclick="obsToggleAll('${groupId}')">выбрать все / снять</button>
2651
2755
  </div>
@@ -2677,7 +2781,7 @@ function renderObservability(c) {
2677
2781
  return `<label class="obs-detail-item"><input type="checkbox" data-idx="${catIdx}" onchange="obsUpdateSelectedCount('${groupId}')"><span title="${escapeHtml(ci.modulePath)}">${escapeHtml(ci.modulePath.split('/').slice(-2).join('/'))}</span><span style="color:var(--dim);flex-shrink:0">${ci.format}</span></label>`;
2678
2782
  }).join('');
2679
2783
  const detail = hasAgent ? `
2680
- <div id="obs-detail-${groupId}" class="obs-detail">
2784
+ <div id="obs-detail-${groupId}" class="obs-detail" data-obs-action="field" data-obs-meta='{"fieldName":"${escapeHtml(name)}"}' data-obs-label="поле ${escapeHtml(name)}">
2681
2785
  <div class="obs-detail-bar" style="border-top:none;padding-top:0;margin-bottom:4px">
2682
2786
  <button class="obs-select-all" onclick="obsToggleAll('${groupId}')">выбрать все / снять</button>
2683
2787
  </div>
@@ -2814,7 +2918,7 @@ function renderObservability(c) {
2814
2918
  return `<label class="obs-detail-item"><input type="checkbox" data-idx="${catIdx}" onchange="obsUpdateSelectedCount('${groupId}')"><span title="${escapeHtml(ci.modulePath)}">${escapeHtml(ci.modulePath.split('/').slice(-2).join('/'))}</span><span style="color:var(--dim);flex-shrink:0">${ci.format}</span></label>`;
2815
2919
  }).join('');
2816
2920
  const detail = hasAgent ? `
2817
- <div id="obs-detail-${groupId}" class="obs-detail">
2921
+ <div id="obs-detail-${groupId}" class="obs-detail" data-obs-action="rec" data-obs-meta='{"recommendationType":"${rec}"}' data-obs-label="${recLabels[rec] || rec}">
2818
2922
  <div class="obs-detail-bar" style="border-top:none;padding-top:0;margin-bottom:4px">
2819
2923
  <button class="obs-select-all" onclick="obsToggleAll('${groupId}')">выбрать все / снять</button>
2820
2924
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viberadar",
3
- "version": "0.3.78",
3
+ "version": "0.3.79",
4
4
  "description": "Live module map with test coverage for vibecoding projects",
5
5
  "main": "./dist/cli.js",
6
6
  "bin": {