Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
    npro  
 Modern all-safe Rust Network Protocol library supporting h1, h2, h3, ws, wt sans-IO and with socket IO + tls
git clone https://npro.rs/repo/npro
 
root / assets / sai-event.svg
Author[]Andy Green <andy@warmcat.com> 2026-08-03 02:36 UTC
Committer[]Andy Green <andy@warmcat.com> 2026-08-03 02:36 UTC
Tree9f40609a5c9d261b95c38b5bd0ee6f384c95b855   Raw Patch
 
ui8
ui8
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;
Page fetched 0s ago, creation time: 7ms (vhost etag hits: 0%, cache hits: 0%)