tomo queue added
This commit is contained in:
@@ -103,10 +103,8 @@ VERBOSITY_VERBOSE = 2
|
||||
VERBOSITY_DEBUG = 3
|
||||
|
||||
_PHONE_NUMBERS = [
|
||||
("Beamline", "+41 56 310 5845"),
|
||||
("Beamline mobile", "+41 56 310 5844"),
|
||||
("Local contact", "+41 79 343 9230"),
|
||||
("Control room", "+41 56 310 5503"),
|
||||
("Beamline", "+41 56 310 5845"),
|
||||
("Control room", "+41 56 310 5503"),
|
||||
]
|
||||
|
||||
|
||||
@@ -1030,6 +1028,12 @@ class WebpageGeneratorBase:
|
||||
else max(0.0, _epoch() - self._last_active_time)
|
||||
)
|
||||
|
||||
# ── Tomo queue ───────────────────────────────────────────────
|
||||
# Persisted list of parameter-snapshot jobs (global var "tomo_queue").
|
||||
# Each job: {"label": str, "params": {...},
|
||||
# "status": pending|running|incomplete|done, "added_at": ISO str}
|
||||
tomo_queue = self._bec.get_global_var("tomo_queue") or []
|
||||
|
||||
# ── Reconstruction queue ──────────────────────────────────────
|
||||
recon = self._collect_recon_data()
|
||||
|
||||
@@ -1061,6 +1065,7 @@ class WebpageGeneratorBase:
|
||||
"idle_for_human": _format_duration(idle_for_s),
|
||||
"queue_locks": queue_locks,
|
||||
"beamline_states": beamline_states_info,
|
||||
"tomo_queue": tomo_queue,
|
||||
"progress": {
|
||||
"tomo_type": progress.get("tomo_type", "N/A"),
|
||||
"projection": progress.get("projection", 0),
|
||||
@@ -1806,6 +1811,52 @@ def _render_html(phone_numbers: list) -> str:
|
||||
.bl-badge.bl-watched-no {{ background: var(--surface2); color: var(--text-dim); }}
|
||||
.blstates-none {{ font-family: var(--mono); font-size: 0.75rem; color: var(--text-dim); padding: 0.5rem 0; }}
|
||||
|
||||
/* ── Tomo queue card ── */
|
||||
.tq-empty {{
|
||||
font-family: var(--mono); font-size: 0.78rem; color: var(--text-dim);
|
||||
padding: 0.25rem 0;
|
||||
}}
|
||||
.tq-job {{ border-bottom: 1px solid var(--border); }}
|
||||
.tq-job:last-child {{ border-bottom: none; }}
|
||||
.tq-summary {{
|
||||
display: flex; align-items: center; gap: 0.75rem;
|
||||
padding: 0.55rem 0; cursor: pointer; list-style: none;
|
||||
font-size: 0.85rem;
|
||||
}}
|
||||
.tq-summary::-webkit-details-marker {{ display: none; }}
|
||||
.tq-summary::before {{
|
||||
content: '▶'; font-family: var(--mono); font-size: 0.55rem;
|
||||
color: var(--text-dim); transition: transform 0.2s; flex-shrink: 0;
|
||||
}}
|
||||
details.tq-job[open] > .tq-summary::before {{ transform: rotate(90deg); }}
|
||||
.tq-num {{
|
||||
font-family: var(--mono); font-size: 0.65rem; color: var(--text-dim);
|
||||
min-width: 1.8rem; flex-shrink: 0;
|
||||
}}
|
||||
.tq-label {{ flex: 1; font-weight: 600; color: var(--text); }}
|
||||
.tq-badge {{
|
||||
font-family: var(--mono); font-size: 0.58rem; font-weight: 700;
|
||||
letter-spacing: 0.06em; text-transform: uppercase;
|
||||
padding: 0.12rem 0.45rem; border-radius: 100px; white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}}
|
||||
.tq-badge.tq-pending {{ background: var(--surface2); color: var(--text-dim); }}
|
||||
.tq-badge.tq-running {{ background: color-mix(in srgb, var(--c-scanning) 20%, transparent); color: var(--c-scanning); }}
|
||||
.tq-badge.tq-incomplete {{ background: color-mix(in srgb, var(--c-blocked) 20%, transparent); color: var(--c-blocked); }}
|
||||
.tq-badge.tq-done {{ background: color-mix(in srgb, var(--c-running) 20%, transparent); color: var(--c-running); }}
|
||||
.tq-details {{ padding: 0.4rem 0 0.7rem 2.4rem; }}
|
||||
.tq-params {{ width: 100%; border-collapse: collapse; }}
|
||||
.tq-params td {{ padding: 0.18rem 0; font-size: 0.78rem; vertical-align: top; }}
|
||||
.tq-params td:first-child {{
|
||||
font-family: var(--mono); font-size: 0.65rem; color: var(--text-dim);
|
||||
padding-right: 1rem; white-space: nowrap; width: 40%;
|
||||
}}
|
||||
.tq-params td:last-child {{ color: var(--text); font-weight: 600; }}
|
||||
.tq-added {{
|
||||
font-family: var(--mono); font-size: 0.6rem; color: var(--text-dim);
|
||||
margin-top: 0.4rem;
|
||||
}}
|
||||
|
||||
/* ── Audio card ── */
|
||||
.audio-card {{
|
||||
display: flex; align-items: center;
|
||||
@@ -1964,6 +2015,7 @@ def _render_html(phone_numbers: list) -> str:
|
||||
<div class="info-item"><span class="label">Remaining</span><span class="value" id="pi-remaining">-</span></div>
|
||||
<div class="info-item"><span class="label">Finish time</span><span class="value" id="pi-finish">-</span></div>
|
||||
<div class="info-item"><span class="label">Started</span><span class="value" id="pi-start">-</span></div>
|
||||
<div class="info-item" id="pi-queue-item" style="display:none"><span class="label">Queue job</span><span class="value" id="pi-queue-label">-</span></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -2081,7 +2133,14 @@ def _render_html(phone_numbers: list) -> str:
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 5. Contacts -->
|
||||
<!-- 5. Tomo queue -->
|
||||
<div class="card draggable-card" data-card-id="tomo-queue">
|
||||
<div class="drag-handle" title="Drag to reorder">⋮⋮</div>
|
||||
<div class="card-title">Tomo queue</div>
|
||||
<div id="tomo-queue-content"></div>
|
||||
</div>
|
||||
|
||||
<!-- 6. Contacts -->
|
||||
<div class="card draggable-card" data-card-id="contacts">
|
||||
<div class="drag-handle" title="Drag to reorder">⋮⋮</div>
|
||||
<div class="card-title">Contacts</div>
|
||||
@@ -2119,7 +2178,7 @@ function setTheme(t) {{
|
||||
|
||||
// ── Drag-and-drop card ordering ──────────────────────────────────────────
|
||||
const CARD_ORDER_KEY = 'cardOrder';
|
||||
const DEFAULT_ORDER = ['audio','recon-queue','ptycho','instrument','blstates','contacts'];
|
||||
const DEFAULT_ORDER = ['audio','recon-queue','ptycho','instrument','blstates','tomo-queue','contacts'];
|
||||
let _dragSrc = null;
|
||||
|
||||
function savedOrder() {{
|
||||
@@ -2555,6 +2614,61 @@ function renderBeamlineStates(bl){{
|
||||
tbody.innerHTML=html;
|
||||
}}
|
||||
|
||||
// Key params to show in expanded job detail, in display order.
|
||||
const TQ_PARAM_DISPLAY = [
|
||||
['tomo_type', 'Type'],
|
||||
['tomo_countingtime', 'Exposure (s)'],
|
||||
['fovx', 'FOV x (\u00b5m)'],
|
||||
['fovy', 'FOV y (\u00b5m)'],
|
||||
['tomo_angle_stepsize', 'Angle step (\u00b0)'],
|
||||
['tomo_angle_range', 'Angle range (\u00b0)'],
|
||||
['tomo_shellstep', 'Shell step (\u00b5m)'],
|
||||
['stitch_x', 'Stitch x'],
|
||||
['stitch_y', 'Stitch y'],
|
||||
['ptycho_reconstruct_foldername','Recon folder'],
|
||||
];
|
||||
|
||||
function fmtTqParam(key, val){{
|
||||
if(val==null) return '-';
|
||||
if(typeof val==='number') return Number.isInteger(val)?String(val):val.toFixed(3).replace(/\\.?0+$/,'');
|
||||
return String(val);
|
||||
}}
|
||||
|
||||
function renderTomoQueue(jobs){{
|
||||
const el=document.getElementById('tomo-queue-content');
|
||||
if(!jobs||jobs.length===0){{
|
||||
el.innerHTML='<div class="tq-empty">No jobs queued</div>';
|
||||
return;
|
||||
}}
|
||||
let html='';
|
||||
jobs.forEach((job,i)=>{{
|
||||
const status=job.status||'pending';
|
||||
const label=job.label||('Job '+(i+1));
|
||||
const params=job.params||{{}};
|
||||
let paramRows='';
|
||||
TQ_PARAM_DISPLAY.forEach(([key,dispLabel])=>{{
|
||||
if(key in params){{
|
||||
paramRows+='<tr><td>'+dispLabel+'</td><td>'+esc(fmtTqParam(key,params[key]))+'</td></tr>';
|
||||
}}
|
||||
}});
|
||||
const addedAt=job.added_at
|
||||
?'Added '+new Date(job.added_at).toLocaleString([],{{month:'short',day:'numeric',hour:'2-digit',minute:'2-digit'}})
|
||||
:'';
|
||||
html+='<details class="tq-job"'+(status==='running'?' open':'')+'>'
|
||||
+'<summary class="tq-summary">'
|
||||
+'<span class="tq-num">#'+(i+1)+'</span>'
|
||||
+'<span class="tq-label">'+esc(label)+'</span>'
|
||||
+'<span class="tq-badge tq-'+esc(status)+'">'+esc(status)+'</span>'
|
||||
+'</summary>'
|
||||
+'<div class="tq-details">'
|
||||
+(paramRows?'<table class="tq-params">'+paramRows+'</table>':'')
|
||||
+(addedAt?'<div class="tq-added">'+esc(addedAt)+'</div>':'')
|
||||
+'</div>'
|
||||
+'</details>';
|
||||
}});
|
||||
el.innerHTML=html;
|
||||
}}
|
||||
|
||||
function render(d){{
|
||||
const s=d.experiment_status||'unknown',p=d.progress||{{}};
|
||||
document.body.className=s;
|
||||
@@ -2576,6 +2690,14 @@ function render(d){{
|
||||
document.getElementById('pi-remaining').textContent=p.estimated_remaining_human||'-';
|
||||
document.getElementById('pi-finish').textContent=fmtTime(p.estimated_finish_time);
|
||||
document.getElementById('pi-start').textContent=fmtTime(p.tomo_start_time);
|
||||
const runningJob=(d.tomo_queue||[]).find(j=>j.status==='running');
|
||||
const queueItem=document.getElementById('pi-queue-item');
|
||||
if(runningJob){{
|
||||
document.getElementById('pi-queue-label').textContent=runningJob.label||'-';
|
||||
queueItem.style.display='';
|
||||
}}else{{
|
||||
queueItem.style.display='none';
|
||||
}}
|
||||
|
||||
if(d.recon){{
|
||||
document.getElementById('recon-waiting').textContent=d.recon.waiting;
|
||||
@@ -2586,6 +2708,7 @@ function render(d){{
|
||||
}}
|
||||
renderInstrument(d.setup);
|
||||
renderBeamlineStates(d.beamline_states);
|
||||
renderTomoQueue(d.tomo_queue);
|
||||
renderPtycho(d.ptycho);
|
||||
document.getElementById('last-update').textContent='updated '+new Date(d.generated_at).toLocaleTimeString();
|
||||
const ageS=(Date.now()/1000)-d.generated_at_epoch;
|
||||
|
||||
Reference in New Issue
Block a user