| Author | Andy Green <andy@warmcat.com> 2026-09-12 10:21 UTC | | Committer | Andy Green <andy@warmcat.com> 2026-09-12 10:21 UTC | | Tree | f1e7e857c8d78a609d77edbca8335ee33b4d42e4 Raw Patch | | | assets: task table: keep header above platform icons, duration is seconds | assets: task table: keep header above platform icons, duration is seconds
The first platform icon (img.zup) is positioned at z-index 11 so it can
overlap its siblings, which put it above the table's sticky header
(z-index 1) while scrolling. Lift the header to 20.
The server stores a task's duration in seconds (sais_process_rej():
lws_now_secs() - first_log_timestamp), not microseconds, so dividing by
1e6 showed 0s for every finished task in the table and "Dur: 0.0s" in
the taskinfo header. Treat it as seconds in both places. While a task
is still building, always show now - started, since the server also
refreshes duration at each step boundary and that would otherwise stick.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
diff --git a/assets/sai.css b/assets/sai.css
index 321814e..f54c72c 100644
--- a/assets/sai.css
+++ b/assets/sai.css
@@ -2467,7 +2467,8 @@ table.tt {
table.tt th.tt-th {
position: sticky;
top: 0;
- z-index: 1;
+ /* above the platform icons: img.zup is positioned at z-index 11 */
+ z-index: 20;
background: #f1f5f9;
color: #1e293b;
text-align: left;
diff --git a/assets/sai.js b/assets/sai.js
index ed246e1..27f63b0 100644
--- a/assets/sai.js
+++ b/assets/sai.js
@@ -1160,9 +1160,8 @@ function sai_taskinfo_render(t, now_ut)
/* started is a unix time, in seconds */
s += "<span class=\"ti5\"> " +
agify(now_ut, t.t.started) + " ago, Dur: " +
- (t.t.duration ? t.t.duration / 1000000 :
- now_ut - t.t.started).toFixed(1) +
- "s</span><div id=\"sai_arts\"></div><div id=\"metrics-summary-" + san(t.t.uuid) + "\"></div>";
+ sai_tt_fmt_dur(sai_tt_dur_secs(t.t, now_ut)) +
+ "</span><div id=\"sai_arts\"></div><div id=\"metrics-summary-" + san(t.t.uuid) + "\"></div>";
sai_arts = "";
}
@@ -2019,13 +2018,21 @@ function sai_tt_is_ongoing(state)
return state === 1 || state === 2 || state === 6 || state === 10;
}
-/* wallclock seconds the task took / has taken so far, or -1 if never started */
+/*
+ * Wallclock seconds the task has been building, or -1 if it never started.
+ *
+ * While it's still going, that's now minus the time the first step was
+ * accepted (t.started, unix secs). Once it reached a disposition, the
+ * server stored the elapsed seconds at that moment in t.duration (see
+ * sais_process_rej()); it also refreshes t.duration at each step boundary,
+ * so it must not be preferred over the live clock for an ongoing task.
+ */
function sai_tt_dur_secs(t, now_ut)
{
- if (t.duration)
- return t.duration / 1000000;
if (t.started && sai_tt_is_ongoing(t.state))
return Math.max(0, now_ut - t.started);
+ if (t.duration)
+ return t.duration;
return -1;
}
@@ -2185,10 +2192,10 @@ function sai_tt_row_key(tr, key, now_ut)
case "started":
return parseInt(d.started) > 0 ? parseInt(d.started) : null;
case "duration":
- if (parseInt(d.dur) > 0)
- return parseInt(d.dur) / 1000000;
if (parseInt(d.started) > 0 && sai_tt_is_ongoing(state))
return now_ut - parseInt(d.started);
+ if (parseInt(d.dur) > 0)
+ return parseInt(d.dur);
return null;
case "step":
return sai_tt_state_rank(state) * 10000 + (parseInt(d.step) + 1);
@@ -2300,7 +2307,7 @@ function sai_tt_tick()
rows.forEach(function(tr) {
var d = tr.dataset;
- if (parseInt(d.dur) > 0 || !(parseInt(d.started) > 0) ||
+ if (!(parseInt(d.started) > 0) ||
!sai_tt_is_ongoing(parseInt(d.state)))
return;
|