opencroc 1.4.3 → 1.5.0

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.
@@ -57,7 +57,21 @@
57
57
  .tooltip.visible { display:block; }
58
58
 
59
59
  .log-panel { background:var(--bg-panel); border-left:var(--pixel-border); display:flex; flex-direction:column; overflow:hidden; }
60
- .log-panel h3 { font-size:10px; text-transform:uppercase; color:var(--text-dim); padding:10px 10px 6px; letter-spacing:1px; border-bottom:1px solid #222; }
60
+ .panel-tabs { display:flex; border-bottom:1px solid #222; }
61
+ .panel-tabs .tab { background:none; border:none; color:var(--text-dim); font-family:inherit; font-size:10px; padding:8px 12px; cursor:pointer; text-transform:uppercase; letter-spacing:1px; border-bottom:2px solid transparent; }
62
+ .panel-tabs .tab.active { color:var(--accent); border-bottom-color:var(--accent); }
63
+ .panel-tabs .tab:hover { color:var(--text); }
64
+ .file-list { flex:1; overflow-y:auto; padding:4px 8px; font-size:10px; }
65
+ .file-item { padding:6px 8px; border-bottom:1px solid #1a1a2e; cursor:pointer; border-radius:3px; }
66
+ .file-item:hover { background:var(--bg-card); }
67
+ .file-item .fname { color:var(--accent); font-weight:bold; }
68
+ .file-item .fmeta { color:var(--text-dim); font-size:9px; margin-top:2px; }
69
+ .file-preview { position:fixed; top:60px; left:50%; transform:translateX(-50%); width:700px; max-height:80vh; background:var(--bg-panel); border:2px solid var(--accent-dim); border-radius:8px; z-index:200; display:none; flex-direction:column; }
70
+ .file-preview.visible { display:flex; }
71
+ .file-preview .fp-header { display:flex; justify-content:space-between; align-items:center; padding:10px 14px; border-bottom:1px solid #333; }
72
+ .file-preview .fp-header h4 { font-size:12px; color:var(--accent); margin:0; }
73
+ .file-preview .fp-close { background:none; border:none; color:var(--text-dim); font-size:18px; cursor:pointer; }
74
+ .file-preview pre { flex:1; overflow:auto; padding:12px; margin:0; font-size:11px; line-height:1.5; color:var(--text); background:#0d0d20; }
61
75
  .log-list { flex:1; overflow-y:auto; padding:4px 8px; font-size:10px; line-height:1.6; }
62
76
  .log-list .log-entry { padding:2px 0; border-bottom:1px solid #1a1a2e; word-break:break-all; }
63
77
  .log-list .log-entry.warn { color:var(--orange); }
@@ -99,6 +113,7 @@
99
113
  <div>Modules: <span id="s-mod">-</span></div>
100
114
  <div>Models: <span id="s-mdl">-</span></div>
101
115
  <div>APIs: <span id="s-api">-</span></div>
116
+ <div>Tests: <span id="s-files">-</span></div>
102
117
  </div>
103
118
  <div class="conn-dot" id="conn-dot" title="WebSocket"></div>
104
119
  </header>
@@ -116,18 +131,28 @@
116
131
  </main>
117
132
 
118
133
  <div class="log-panel">
119
- <h3>📋 Activity Log</h3>
134
+ <div class="panel-tabs">
135
+ <button class="tab active" data-tab="log">📋 Log</button>
136
+ <button class="tab" data-tab="files">📄 Tests <span id="file-badge" style="display:none;background:var(--accent);color:#000;border-radius:8px;padding:0 5px;font-size:9px;margin-left:3px">0</span></button>
137
+ </div>
120
138
  <div class="log-list" id="log-list"></div>
139
+ <div class="file-list" id="file-list" style="display:none"></div>
121
140
  </div>
122
141
 
123
142
  <section class="office" id="croc-office"></section>
124
143
  </div>
125
144
 
145
+ <div class="file-preview" id="file-preview">
146
+ <div class="fp-header"><h4 id="fp-title">file.spec.ts</h4><button class="fp-close" id="fp-close">&times;</button></div>
147
+ <pre id="fp-code"></pre>
148
+ </div>
149
+
126
150
  <script>
127
151
  const S = {
128
152
  project:null, graph:{nodes:[],edges:[]}, agents:[], ws:null,
129
153
  pan:{x:0,y:0}, zoom:1, dragging:false, dragStart:{x:0,y:0},
130
- nodePos:new Map(), hoveredNode:null, running:false, _userPanned:false
154
+ nodePos:new Map(), hoveredNode:null, running:false, _userPanned:false,
155
+ generatedFiles:[]
131
156
  };
132
157
 
133
158
  async function fetchProject(){
@@ -171,6 +196,12 @@ function connectWS(){
171
196
  S.graph=m.payload; layoutGraph(); renderCanvas(); renderModList(); updateStats();
172
197
  }else if(m.type==='log'){
173
198
  addLog(m.payload.message, m.payload.level);
199
+ }else if(m.type==='files:generated'){
200
+ S.generatedFiles=m.payload||[];
201
+ renderFileList();
202
+ document.getElementById('s-files').textContent=S.generatedFiles.length;
203
+ const badge=document.getElementById('file-badge');
204
+ badge.textContent=S.generatedFiles.length;badge.style.display='inline';
174
205
  }else if(m.type==='pipeline:complete'){
175
206
  S.running=false; updateBtns();
176
207
  if(m.payload.status==='success') addLog('✅ Pipeline complete!');
@@ -438,6 +469,46 @@ document.getElementById('btn-scan').addEventListener('click',doScan);
438
469
  document.getElementById('btn-pipeline').addEventListener('click',doPipeline);
439
470
  document.getElementById('btn-reset').addEventListener('click',doReset);
440
471
 
472
+ // Tab switching
473
+ document.querySelectorAll('.panel-tabs .tab').forEach(tab=>{
474
+ tab.addEventListener('click',()=>{
475
+ document.querySelectorAll('.panel-tabs .tab').forEach(t=>t.classList.remove('active'));
476
+ tab.classList.add('active');
477
+ const t=tab.getAttribute('data-tab');
478
+ document.getElementById('log-list').style.display=t==='log'?'':'none';
479
+ document.getElementById('file-list').style.display=t==='files'?'':'none';
480
+ });
481
+ });
482
+
483
+ // File list rendering
484
+ function renderFileList(){
485
+ const el=document.getElementById('file-list');
486
+ if(!S.generatedFiles.length){el.innerHTML='<div style="padding:12px;color:#555;font-size:10px">No test files generated yet. Run Pipeline first.</div>';return;}
487
+ el.innerHTML=S.generatedFiles.map((f,i)=>
488
+ '<div class="file-item" data-idx="'+i+'"><div class="fname">'+esc(f.filePath.split('/').pop()||f.filePath)+'</div>'+
489
+ '<div class="fmeta">'+esc(f.module)+' / '+esc(f.chain)+' — '+f.lines+' lines</div></div>'
490
+ ).join('');
491
+ el.querySelectorAll('.file-item').forEach(item=>{
492
+ item.addEventListener('click',async()=>{
493
+ const idx=item.getAttribute('data-idx');
494
+ try{
495
+ const r=await fetch('/api/files/'+idx); const file=await r.json();
496
+ document.getElementById('fp-title').textContent=file.filePath;
497
+ document.getElementById('fp-code').textContent=file.content;
498
+ document.getElementById('file-preview').classList.add('visible');
499
+ }catch(e){addLog('Failed to load file: '+e.message,'error');}
500
+ });
501
+ });
502
+ }
503
+
504
+ // File preview close
505
+ document.getElementById('fp-close').addEventListener('click',()=>{
506
+ document.getElementById('file-preview').classList.remove('visible');
507
+ });
508
+ document.addEventListener('keydown',e=>{
509
+ if(e.key==='Escape') document.getElementById('file-preview').classList.remove('visible');
510
+ });
511
+
441
512
  (async()=>{setupCanvas();await fetchProject();connectWS();addLog('🐊 OpenCroc Studio ready');
442
513
  window.addEventListener('resize',()=>{layoutGraph();renderCanvas();});})();
443
514
  </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencroc",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "AI-native E2E testing framework — source-aware test generation, intelligent validation, and self-healing",
5
5
  "keywords": [
6
6
  "e2e",