diff --git a/assets/index.html b/assets/index.html
index b8c6709..583dc23 100644
--- a/assets/index.html
+++ b/assets/index.html
@@ -2,9 +2,9 @@
<html lang="en">
<head>
<meta charset=utf-8 http-equiv="Content-Language" content="en"/>
- <link rel="stylesheet" type="text/css" href="sai.css?v=4"/>
+ <link rel="stylesheet" type="text/css" href="sai.css?v=6"/>
<link rel="icon" href="sai-icon.svg" sizes="any" type="image/svg+xml"/>
- <script type='text/javascript' src='sai.js?v=4'></script>
+ <script type='text/javascript' src='sai.js?v=6'></script>
<script type='text/javascript' src='terminal-core.js'></script>
<script type='text/javascript' src='sai-terminal.js'></script>
<script type='text/javascript' src='lws-login.js'></script>
@@ -18,9 +18,11 @@
<div class="sidebar-pane" id="sai_sidebar">
<div class="sb-col sb-col-logo" id="sai_sb_logo">
<div class="logo">
- <img class="logo" src="sai.svg"><br>
- <span class="logo"><a href="https://warmcat.com/git/sai">Sai git</a></span>
- <span class="logo" id="apirev"></span>
+ <img class="logo" src="sai.svg">
+ <div class="logo-text">
+ <span class="logo"><a href="https://warmcat.com/git/sai">Sai git</a></span>
+ <span class="logo" id="apirev"></span>
+ </div>
</div>
<div id="lws-login-status-container" class="login-status-container"></div>
</div>
diff --git a/assets/sai.css b/assets/sai.css
index 9ab8afe..50df9c3 100644
--- a/assets/sai.css
+++ b/assets/sai.css
@@ -1817,25 +1817,37 @@ div.ibuil.vm-builder {
}
.sidebar-pane .sb-col-logo .logo {
- display: block;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 6px;
margin: 0;
padding: 0;
width: auto;
}
.sidebar-pane .sb-col-logo img.logo {
- width: 110px;
+ width: 70px;
height: auto;
display: block;
+ flex: 0 0 auto;
+}
+
+/* vertical stack of "Sai git" + "API rev N" to the right of the logo image */
+.sidebar-pane .sb-col-logo .logo-text {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 1px;
}
/* override the global span.logo (Sai git / apirev) for the narrow column */
.sidebar-pane .sb-col-logo span.logo {
width: auto;
max-width: 100%;
- margin: 1px 0 0 0;
+ margin: 0;
padding: 0;
- text-align: center;
+ text-align: left;
display: block;
}
@@ -1875,6 +1887,7 @@ div.ibuil.vm-builder {
.sb-row.selected {
background: #334155;
color: #ffffff;
+ font-weight: bold;
}
/* event rows in col 4 */
diff --git a/assets/sai.js b/assets/sai.js
index 6b78440..a5f26ac 100644
--- a/assets/sai.js
+++ b/assets/sai.js
@@ -1716,6 +1716,26 @@ function render_selected_event_tasks(o) {
var e = o.e;
/*
+ * The tasks pane only makes sense once we have a context for it: either
+ * a sidebar project + branch selection, or an explicit deep-link
+ * (?event= / ?task=) that named a specific event/task. Otherwise
+ * (initial page load, nothing chosen) leave it empty rather than
+ * showing tasks for an unrelated auto-selected event.
+ */
+ var deep_link = false;
+ try {
+ var _p = new URLSearchParams(window.location.search);
+ deep_link = !!(_p.get('event') || _p.get('task'));
+ } catch (e2) {}
+
+ if (!sb_selected_project && !sb_selected_ref && !deep_link) {
+ var c = document.getElementById("sai_event_tasks");
+ if (c)
+ c.innerHTML = "<div class=\"sb-empty\">Select a project and branch</div>";
+ return;
+ }
+
+ /*
* The header (title + admin restart-all / delete-event buttons) is
* always shown for the selected event, even when no task list is
* available yet (sidebar-scoped overview events arrive with t:[] and
diff --git a/src/web/w-comms.c b/src/web/w-comms.c
index fcb52e5..3fbfd86 100644
--- a/src/web/w-comms.c
+++ b/src/web/w-comms.c
@@ -537,6 +537,13 @@ http_resp:
pss->wsi = wsi;
pss->vhd = vhd;
+ /*
+ * Raise the tx buflist sanity limit well above lws's 2MiB
+ * default: a scoped sidebar overview can carry a large number
+ * of events before the connection drains. 32MiB is plenty for
+ * the biggest event lists while still bounding memory per pss.
+ */
+ pss->raw_tx.limit = 32 * 1024 * 1024;
pss->is_gitohashi = 1;
{
int r = 0;
@@ -667,7 +674,7 @@ http_resp:
case LWS_CALLBACK_CLOSED:
lwsl_wsi_info(wsi, "CLOSED browse conn");
- lws_buflist_destroy_all_segments(&pss->raw_tx);
+ lws_buflist2_destroy_all_segments(&pss->raw_tx);
saiw_browser_state_changed(pss, 0);
lws_dll2_remove(&pss->subs_list);
lws_sul_cancel(&pss->sul_logcache);
@@ -718,30 +725,30 @@ http_resp:
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
- if (!vhd || !pss->raw_tx)
+ if (!vhd || !pss->raw_tx.total_len)
break;
{
char som, eom, rb[1200 + LWS_PRE];
uint8_t *prb = (uint8_t *)rb + LWS_PRE;
int used, final = 1;
- size_t fsl = lws_buflist_next_segment_len(&pss->raw_tx, NULL);
+ size_t fsl = lws_buflist2_next_segment_len(&pss->raw_tx, NULL);
/*
* Each segment has a header containing the flags.
* We MUST only read it if we are at the start of the segment.
* If we are mid-segment, we use the cached flags.
*/
- if (lws_buflist_get_frag_start_or_NULL(&pss->raw_tx)) {
+ if (lws_buflist2_get_frag_start_or_NULL(&pss->raw_tx)) {
/* This is just a peek to see if we HAVE a segment */
- int *pi = (int *)lws_buflist_get_frag_start_or_NULL(&pss->raw_tx);
+ int *pi = (int *)lws_buflist2_get_frag_start_or_NULL(&pss->raw_tx);
int flags = *pi;
-
+
/*
* fragment_use sets 'som' to true if we are at
* the segment start.
*/
- used = lws_buflist_fragment_use(&pss->raw_tx, prb, 1200, &som, &eom);
+ used = lws_buflist2_fragment_use(&pss->raw_tx, prb, 1200, &som, &eom);
if (!used)
return 0;
@@ -764,7 +771,7 @@ http_resp:
}
}
- if (pss->raw_tx)
+ if (pss->raw_tx.total_len)
lws_callback_on_writable(pss->wsi);
break;
diff --git a/src/web/w-private.h b/src/web/w-private.h
index e74fab4..973e5aa 100644
--- a/src/web/w-private.h
+++ b/src/web/w-private.h
@@ -110,8 +110,14 @@ struct pss {
struct lws_spa *spa;
struct lejp_ctx ctx;
- struct lws_buflist *raw_tx;
- struct lws_dll2 same; /* owner: vhd.browsers */
+ /*
+ * Outgoing ws tx backlog for this browser connection. Uses the
+ * lws_buflist2 API so we can raise the per-owner sanity limit above
+ * the 2MiB lws_buflist default (a scoped sidebar overview can carry
+ * many events' worth of task data).
+ */
+ struct lws_buflist2_owner raw_tx;
+ struct lws_dll2 same; /* owner: vhd.browsers */
struct lws_dll2 subs_list;
diff --git a/src/web/w-ws-browser.c b/src/web/w-ws-browser.c
index f7553b2..e0eab0c 100644
--- a/src/web/w-ws-browser.c
+++ b/src/web/w-ws-browser.c
@@ -196,7 +196,7 @@ saiw_ws_browser_queue_REQUIRES_LWS_PRE(struct pss *pss, const void *buf,
*pi = (int)flags;
- if (lws_buflist_append_segment(&pss->raw_tx, buf - sizeof(int), len + sizeof(int)) < 0) {
+ if (lws_buflist2_append_segment(&pss->raw_tx, buf - sizeof(int), len + sizeof(int)) < 0) {
lwsl_wsi_err(pss->wsi, "unable to buflist_append"); /* still ask to drain */
r = 1;
}
@@ -1076,7 +1076,7 @@ saiw_broadcast_logs_batch(struct vhd *vhd, struct pss *pss)
if (!pss->subs_list.owner)
return 0;
- if (lws_buflist_total_len(&pss->raw_tx) > 100 * 1024) {
+ if (lws_buflist2_total_len(&pss->raw_tx) > 100 * 1024) {
lws_sul_schedule(vhd->context, 0, &pss->sul_logcache,
saiw_retry_logs, 250 * LWS_US_PER_MS);
return 0;