viberadar 0.3.2 → 0.3.3
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 +102 -1
- package/package.json +1 -1
package/dist/ui/dashboard.html
CHANGED
|
@@ -569,6 +569,37 @@ function renderFeatureCards(c) {
|
|
|
569
569
|
card.onclick = () => openFeaturePanel(f.key);
|
|
570
570
|
grid.appendChild(card);
|
|
571
571
|
});
|
|
572
|
+
|
|
573
|
+
// ── Unmapped card ──────────────────────────────────────────────────────────
|
|
574
|
+
if (!q) {
|
|
575
|
+
const unmappedSrc = D.modules.filter(m =>
|
|
576
|
+
m.type !== 'test' && (!m.featureKeys || m.featureKeys.length === 0)
|
|
577
|
+
);
|
|
578
|
+
if (unmappedSrc.length > 0) {
|
|
579
|
+
const isActive = activePanelKey === '__unmapped__';
|
|
580
|
+
const card = document.createElement('div');
|
|
581
|
+
card.className = 'feature-card' + (isActive ? ' active' : '');
|
|
582
|
+
card.style.borderStyle = 'dashed';
|
|
583
|
+
card.style.opacity = '0.75';
|
|
584
|
+
card.innerHTML = `
|
|
585
|
+
<div class="feature-accent" style="background:var(--yellow)"></div>
|
|
586
|
+
<div class="feature-body">
|
|
587
|
+
<div class="feature-title">
|
|
588
|
+
<span style="color:var(--yellow)">⚠ Unmapped</span>
|
|
589
|
+
<span class="feature-file-count">${unmappedSrc.length} ${pluralFiles(unmappedSrc.length)}</span>
|
|
590
|
+
</div>
|
|
591
|
+
<div class="feature-desc">Файлы вне карты фич — не входят ни в одну фичу</div>
|
|
592
|
+
<div class="feature-progress-wrap">
|
|
593
|
+
<div class="feature-progress-bar">
|
|
594
|
+
<div class="feature-progress-fill" style="width:100%;background:var(--border)"></div>
|
|
595
|
+
</div>
|
|
596
|
+
<span class="feature-progress-label" style="color:var(--dim)">нет привязки</span>
|
|
597
|
+
</div>
|
|
598
|
+
</div>`;
|
|
599
|
+
card.onclick = () => openUnmappedPanel(unmappedSrc);
|
|
600
|
+
grid.appendChild(card);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
572
603
|
}
|
|
573
604
|
|
|
574
605
|
function renderModuleGrid(c) {
|
|
@@ -726,6 +757,71 @@ function openModulePanel(m) {
|
|
|
726
757
|
document.getElementById('panel').classList.add('open');
|
|
727
758
|
}
|
|
728
759
|
|
|
760
|
+
function openUnmappedPanel(files) {
|
|
761
|
+
activePanelKey = '__unmapped__';
|
|
762
|
+
renderContent();
|
|
763
|
+
|
|
764
|
+
// Group by top-level directory
|
|
765
|
+
const byDir = {};
|
|
766
|
+
files.forEach(m => {
|
|
767
|
+
const parts = m.relativePath.replace(/\\/g, '/').split('/');
|
|
768
|
+
const dir = parts.length > 1 ? parts[0] : '(root)';
|
|
769
|
+
if (!byDir[dir]) byDir[dir] = [];
|
|
770
|
+
byDir[dir].push(m);
|
|
771
|
+
});
|
|
772
|
+
const dirs = Object.keys(byDir).sort();
|
|
773
|
+
|
|
774
|
+
// Build plain-text list for copying to AI agent
|
|
775
|
+
const plainList = files
|
|
776
|
+
.map(m => '- ' + m.relativePath.replace(/\\/g, '/'))
|
|
777
|
+
.join('\n');
|
|
778
|
+
|
|
779
|
+
const promptText =
|
|
780
|
+
`В проекте ${files.length} файлов без привязки к фичам (unmapped).\n` +
|
|
781
|
+
`Изучи список ниже и обнови viberadar.config.json:\n` +
|
|
782
|
+
`добавь эти файлы в существующие фичи или создай новые.\n\n` +
|
|
783
|
+
plainList;
|
|
784
|
+
|
|
785
|
+
document.getElementById('panelContent').innerHTML = `
|
|
786
|
+
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
|
|
787
|
+
<span style="font-size:16px">⚠</span>
|
|
788
|
+
<div class="panel-title" style="color:var(--yellow)">Unmapped файлы</div>
|
|
789
|
+
</div>
|
|
790
|
+
<div class="panel-subtitle">
|
|
791
|
+
Не входят ни в одну фичу.<br>
|
|
792
|
+
Запусти <code style="color:var(--blue)">npx viberadar init</code> — агент предложит куда добавить.
|
|
793
|
+
</div>
|
|
794
|
+
|
|
795
|
+
<button id="copyUnmapped" style="
|
|
796
|
+
width:100%; padding:8px 12px; margin-bottom:16px;
|
|
797
|
+
background:var(--bg); border:1px solid var(--border);
|
|
798
|
+
border-radius:6px; color:var(--blue); font-size:12px;
|
|
799
|
+
cursor:pointer; text-align:left;
|
|
800
|
+
">📋 Скопировать список для AI-агента</button>
|
|
801
|
+
|
|
802
|
+
${dirs.map(dir => `
|
|
803
|
+
<div class="panel-section">
|
|
804
|
+
<div class="panel-section-label">${dir}/ (${byDir[dir].length})</div>
|
|
805
|
+
<div class="file-list">
|
|
806
|
+
${byDir[dir].map(m => fileItem(m)).join('')}
|
|
807
|
+
</div>
|
|
808
|
+
</div>
|
|
809
|
+
`).join('')}`;
|
|
810
|
+
|
|
811
|
+
document.getElementById('copyUnmapped').onclick = function() {
|
|
812
|
+
navigator.clipboard.writeText(promptText).then(() => {
|
|
813
|
+
this.textContent = '✅ Скопировано! Вставь в AI-агента';
|
|
814
|
+
this.style.color = 'var(--green)';
|
|
815
|
+
setTimeout(() => {
|
|
816
|
+
this.textContent = '📋 Скопировать список для AI-агента';
|
|
817
|
+
this.style.color = 'var(--blue)';
|
|
818
|
+
}, 3000);
|
|
819
|
+
});
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
document.getElementById('panel').classList.add('open');
|
|
823
|
+
}
|
|
824
|
+
|
|
729
825
|
function closePanel() {
|
|
730
826
|
activePanelKey = null;
|
|
731
827
|
document.getElementById('panel').classList.remove('open');
|
|
@@ -778,7 +874,12 @@ async function refreshData() {
|
|
|
778
874
|
// Re-open panel if it was open
|
|
779
875
|
const panelOpen = document.getElementById('panel').classList.contains('open');
|
|
780
876
|
if (panelOpen && activePanelKey) {
|
|
781
|
-
if (
|
|
877
|
+
if (activePanelKey === '__unmapped__') {
|
|
878
|
+
const unmapped = D.modules.filter(m =>
|
|
879
|
+
m.type !== 'test' && (!m.featureKeys || m.featureKeys.length === 0)
|
|
880
|
+
);
|
|
881
|
+
openUnmappedPanel(unmapped);
|
|
882
|
+
} else if (view === 'features' && D.features) {
|
|
782
883
|
openFeaturePanel(activePanelKey);
|
|
783
884
|
} else {
|
|
784
885
|
const m = D.modules.find(m => m.id === activePanelKey);
|