Ship v0.1.1–v0.1.5: first-live-run fixes and dashboard viewer
- v0.1.1: config persistence — FileHelper paths made absolute (/media/startos/volumes/main/...); relative paths resolved into the JS runtime's ephemeral cwd so action saves never reached /data - v0.1.2: preJobStopContainers (Configure Grading) — docker-stop resident vLLM containers on the head Spark at job start, no auto-restart - v0.1.3: preflight auth (LiteLLM master_key gates /models), poll-until-loaded, crash fast-fail (restarting counts as dead) - v0.1.4: HF_HUB_OFFLINE/TRANSFORMERS_OFFLINE in airgapped serving (--internal network has no DNS); grader _post timeout 600→1800s for ~3.6 tok/s GB10 generation - v0.1.5: dashboard viewer survives the periodic background refresh; download buttons for deck reports, deck JSON, and SCORECARD.md - .gitignore: .startos/ build workspace, start-technologies/ Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
1d1074b625
commit
91212322c1
@@ -34,6 +34,9 @@
|
||||
padding:8px 12px;font-size:13px;cursor:pointer} button:hover{background:#2c3650}
|
||||
button.primary{background:#3a2f12;border-color:#6b551f;color:#ffdf9a}
|
||||
button.mini{padding:2px 8px;font-size:11px;border-radius:7px}
|
||||
a.mini{display:inline-block;background:#222a3a;border:1px solid var(--edge);border-radius:7px;
|
||||
padding:2px 8px;font-size:11px;color:var(--ink);text-decoration:none;cursor:pointer}
|
||||
a.mini:hover{background:#2c3650}
|
||||
select,input[type=text]{background:#0c0f16;color:var(--ink);border:1px solid var(--edge);
|
||||
border-radius:9px;padding:7px 10px;font-size:13px}
|
||||
.drop{border:1.5px dashed var(--edge);border-radius:12px;padding:18px;text-align:center;color:var(--dim);cursor:pointer;margin-top:10px}
|
||||
@@ -303,15 +306,21 @@ function renderPortfolio(){
|
||||
async function openCompany(slug,silent){
|
||||
try{
|
||||
const d=await getJSON('/api/companies/'+encodeURIComponent(slug));
|
||||
const changed = currentSlug!==slug;
|
||||
currentSlug=slug;
|
||||
renderDetail(d);
|
||||
renderDetail(d,changed);
|
||||
document.getElementById('companyCard').style.display='';
|
||||
if(!silent) document.getElementById('companyCard').scrollIntoView({behavior:'smooth'});
|
||||
}catch(e){ if(!silent) alert('load company failed: '+(e.message||e)); }
|
||||
}
|
||||
function closeCompany(){ currentSlug=null; document.getElementById('companyCard').style.display='none'; }
|
||||
function closeCompany(){
|
||||
currentSlug=null; scorecardOpen=false;
|
||||
document.getElementById('coViewer').innerHTML='';
|
||||
document.getElementById('scBtn').textContent='View SCORECARD.md';
|
||||
document.getElementById('companyCard').style.display='none';
|
||||
}
|
||||
|
||||
function renderDetail(d){
|
||||
function renderDetail(d,changed){
|
||||
const co=d.company||{}, recs=d.records||[];
|
||||
document.getElementById('coName').textContent=co.name||co.slug||'?';
|
||||
document.getElementById('coBadges').innerHTML=co.auto_created?'<span class="tag unreg">unregistered</span>':'';
|
||||
@@ -345,30 +354,41 @@ function renderDetail(d){
|
||||
`<tr><td>${esc(r.period||'?')}</td><td>${scoreBadge(r.composite)}</td>`+
|
||||
`<td class="muted">${esc(String(r.graded_at||'').slice(0,16).replace('T',' '))}</td>`+
|
||||
`<td><button class="mini" onclick="viewDeckReport('${esc(r.deck_id)}')">report</button> `+
|
||||
`<button class="mini" onclick="viewDeckJson('${esc(r.deck_id)}')">json</button></td></tr>`).join('')+
|
||||
`<button class="mini" onclick="viewDeckJson('${esc(r.deck_id)}')">json</button> `+
|
||||
`<a class="mini" href="${deckBase(r.deck_id)}/report" `+
|
||||
`download="${esc(co.slug||currentSlug)}-${esc(r.deck_id)}-report.md" title="Download report">⬇</a></td></tr>`).join('')+
|
||||
'</tbody></table>';
|
||||
|
||||
document.getElementById('coViewer').innerHTML='';
|
||||
document.getElementById('scBtn').textContent='View SCORECARD.md';
|
||||
// Only reset the viewer when switching companies — periodic re-renders must
|
||||
// not close whatever report the user has open.
|
||||
if(changed){
|
||||
scorecardOpen=false;
|
||||
document.getElementById('coViewer').innerHTML='';
|
||||
document.getElementById('scBtn').textContent='View SCORECARD.md';
|
||||
}
|
||||
}
|
||||
function deckBase(deckId){
|
||||
return '/api/companies/'+encodeURIComponent(currentSlug)+'/decks/'+encodeURIComponent(deckId);
|
||||
}
|
||||
|
||||
async function viewDeckReport(deckId){
|
||||
if(!currentSlug) return;
|
||||
const base='/api/companies/'+encodeURIComponent(currentSlug)+'/decks/'+encodeURIComponent(deckId);
|
||||
const base=deckBase(deckId);
|
||||
try{
|
||||
const r=await fetch(base+'/report');
|
||||
const t=await r.text();
|
||||
setViewer('Deck report — '+deckId, `<pre class="tall">${esc(r.ok?t:('error: '+t))}</pre>`);
|
||||
setViewer('Deck report — '+deckId, `<pre class="tall">${esc(r.ok?t:('error: '+t))}</pre>`,
|
||||
base+'/report', `${currentSlug}-${deckId}-report.md`);
|
||||
}catch(e){ alert(e); }
|
||||
}
|
||||
async function viewDeckJson(deckId){
|
||||
if(!currentSlug) return;
|
||||
try{
|
||||
const d=await getJSON('/api/companies/'+encodeURIComponent(currentSlug)+
|
||||
'/decks/'+encodeURIComponent(deckId));
|
||||
const d=await getJSON(deckBase(deckId));
|
||||
setViewer('Deck record — '+deckId,
|
||||
`<details class="jsonv" open><summary>collapse / expand raw JSON</summary>`+
|
||||
`<pre class="tall">${esc(JSON.stringify(d,null,2))}</pre></details>`);
|
||||
`<pre class="tall">${esc(JSON.stringify(d,null,2))}</pre></details>`,
|
||||
deckBase(deckId), `${currentSlug}-${deckId}.json`);
|
||||
}catch(e){ alert('load record failed: '+(e.message||e)); }
|
||||
}
|
||||
let scorecardOpen=false;
|
||||
@@ -377,18 +397,23 @@ async function toggleScorecard(){
|
||||
const v=document.getElementById('coViewer'), btn=document.getElementById('scBtn');
|
||||
if(scorecardOpen){ v.innerHTML=''; scorecardOpen=false; btn.textContent='View SCORECARD.md'; return; }
|
||||
try{
|
||||
const r=await fetch('/api/companies/'+encodeURIComponent(currentSlug)+'/scorecard');
|
||||
const url='/api/companies/'+encodeURIComponent(currentSlug)+'/scorecard';
|
||||
const r=await fetch(url);
|
||||
const t=await r.text();
|
||||
setViewer('SCORECARD.md', `<pre class="tall">${esc(r.ok?t:('error: '+t))}</pre>`);
|
||||
setViewer('SCORECARD.md', `<pre class="tall">${esc(r.ok?t:('error: '+t))}</pre>`,
|
||||
url, `${currentSlug}-SCORECARD.md`);
|
||||
scorecardOpen=true; btn.textContent='Hide SCORECARD.md';
|
||||
}catch(e){ alert(e); }
|
||||
}
|
||||
function setViewer(title,html){
|
||||
function setViewer(title,html,dlHref,dlName){
|
||||
scorecardOpen=false;
|
||||
document.getElementById('scBtn').textContent='View SCORECARD.md';
|
||||
const dl=dlHref?`<a class="mini" style="margin-left:auto" href="${dlHref}" `+
|
||||
`download="${esc(dlName||'report.txt')}" title="Download">⬇ download</a>`:'';
|
||||
document.getElementById('coViewer').innerHTML=
|
||||
`<h3 class="sub" style="display:flex;align-items:center">${esc(title)}`+
|
||||
`<button class="mini" style="margin-left:auto" onclick="document.getElementById('coViewer').innerHTML=''">close</button></h3>`+html;
|
||||
`<h3 class="sub" style="display:flex;align-items:center;gap:8px">${esc(title)}${dl}`+
|
||||
`<button class="mini" ${dlHref?'':'style="margin-left:auto"'} `+
|
||||
`onclick="document.getElementById('coViewer').innerHTML=''">close</button></h3>`+html;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ drop card
|
||||
|
||||
Reference in New Issue
Block a user