diff --git a/assets/index.html b/assets/index.html
index c9cf83e..a907111 100644
--- a/assets/index.html
+++ b/assets/index.html
@@ -23,14 +23,6 @@
</div>
<div id="lws-login-status-container" class="login-status-container"></div>
</div>
- <div id="sai_power_overview" class="power-overview hidden">
- <div class="power-text">Total Power: <span id="sai_total_power">0W</span></div>
- <canvas id="sai_power_graph" class="power-graph" height="20" width="150"></canvas>
- </div>
- <div id="sai_builders"></div>
- </div>
- <div class="resizer" id="resizer"></div>
- <div class="right-pane">
<div class="event-decals-section" id="sai_event_decals"></div>
<div class="tasks-section" id="sai_event_tasks"></div>
<div class="resizer-h" id="resizer_h"></div>
@@ -45,6 +37,14 @@
</div>
</div>
</div>
+ <div class="resizer" id="resizer"></div>
+ <div class="right-pane">
+ <div id="sai_power_overview" class="power-overview hidden">
+ <div class="power-text">Total Power: <span id="sai_total_power">0W</span></div>
+ <canvas id="sai_power_graph" class="power-graph" height="20" width="150"></canvas>
+ </div>
+ <div id="sai_builders"></div>
+ </div>
</div>
</body>
</html>
diff --git a/assets/sai.css b/assets/sai.css
index f63aa1a..d1be255 100644
--- a/assets/sai.css
+++ b/assets/sai.css
@@ -1044,13 +1044,17 @@ body.overlay-active {
height: 100vh;
}
.left-pane {
- flex: 0 0 30%;
- overflow: auto;
- flex-shrink: 0;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ overflow: hidden;
}
.right-pane {
- flex-grow: 1;
- overflow: auto;
+ flex: 0 0 0px;
+ overflow-x: hidden;
+ overflow-y: auto;
+ flex-shrink: 0;
}
.resizer {
width: 5px;
diff --git a/assets/sai.js b/assets/sai.js
index f399d40..69cf70b 100644
--- a/assets/sai.js
+++ b/assets/sai.js
@@ -1586,17 +1586,20 @@ function selectEvent(uuid) {
tfirst = 0;
lli = 1;
last_log_timestamp = 0;
+ }
- var par = new URLSearchParams(window.location.search);
+ var par = new URLSearchParams(window.location.search);
+ par.set("event", uuid);
+ if (!hasTask) {
par.delete("task");
par.delete("run");
- var qs = par.toString();
- var path = window.location.pathname;
- if (!path.endsWith('/') && !path.endsWith('index.html')) {
- path += '/';
- }
- window.history.pushState({}, "", path + (qs ? ("?" + qs) : ""));
}
+ var qs = par.toString();
+ var path = window.location.pathname;
+ if (!path.endsWith('/') && !path.endsWith('index.html')) {
+ path += '/';
+ }
+ window.history.pushState({}, "", path + (qs ? ("?" + qs) : ""));
// Highlight card
var container = document.getElementById("sai_event_decals");
@@ -2519,6 +2522,13 @@ function ws_open_sai()
}
document.body.classList.remove("overlay-active");
+ let savedRightPaneFlex = localStorage.getItem('sai-right-pane-flex');
+ let initialVisible = 0;
+ if (savedRightPaneFlex && parseInt(savedRightPaneFlex.replace(/[^0-9-]/g, '')) > 0) {
+ initialVisible = 1;
+ }
+ sai.send(JSON.stringify({ schema: "com.warmcat.sai.builder_visibility", visible: initialVisible }));
+
var par = new URLSearchParams(window.location.search),
tid, eid, run_idx;
tid = par.get('task');
@@ -3601,11 +3611,11 @@ window.addEventListener("load", function() {
}
});
- const savedFlex = localStorage.getItem('sai-left-pane-flex');
+ const savedFlex = localStorage.getItem('sai-right-pane-flex');
if (savedFlex) {
- const leftPane = document.querySelector('.left-pane');
- if (leftPane) {
- leftPane.style.flex = savedFlex;
+ const rightPane = document.querySelector('.right-pane');
+ if (rightPane) {
+ rightPane.style.flex = savedFlex;
}
}
@@ -3791,49 +3801,64 @@ window.addEventListener("load", function() {
});
const resizer = document.getElementById('resizer');
if (resizer) {
- const leftPane = resizer.previousElementSibling;
+ const rightPane = resizer.nextElementSibling;
let x = 0;
- let leftWidth = 0;
+ let rightWidth = 0;
+ let lastVisible = -1;
const onMouseMove = (e) => {
- const dx = e.clientX - x;
- const newLeftWidth = leftWidth + dx;
- leftPane.style.flex = `0 0 ${newLeftWidth}px`;
+ const dx = x - e.clientX;
+ let newRightWidth = rightWidth + dx;
+ if (newRightWidth < 20) newRightWidth = 0;
+ rightPane.style.flex = `0 0 ${newRightWidth}px`;
+ let visible = newRightWidth > 0 ? 1 : 0;
+ if (visible !== lastVisible) {
+ lastVisible = visible;
+ sai.send(JSON.stringify({ schema: "com.warmcat.sai.builder_visibility", visible: visible }));
+ }
};
const onMouseUp = () => {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
- localStorage.setItem('sai-left-pane-flex', leftPane.style.flex);
+ localStorage.setItem('sai-right-pane-flex', rightPane.style.flex);
};
const onMouseDown = (e) => {
x = e.clientX;
- leftWidth = leftPane.getBoundingClientRect().width;
+ rightWidth = rightPane.getBoundingClientRect().width;
+ lastVisible = rightWidth > 0 ? 1 : 0;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
};
const onTouchMove = (e) => {
if (e.touches.length === 1) {
- const dx = e.touches[0].clientX - x;
- const newLeftWidth = leftWidth + dx;
- leftPane.style.flex = `0 0 ${newLeftWidth}px`;
+ const dx = x - e.touches[0].clientX;
+ let newRightWidth = rightWidth + dx;
+ if (newRightWidth < 20) newRightWidth = 0;
+ rightPane.style.flex = `0 0 ${newRightWidth}px`;
e.preventDefault();
+ let visible = newRightWidth > 0 ? 1 : 0;
+ if (visible !== lastVisible) {
+ lastVisible = visible;
+ sai.send(JSON.stringify({ schema: "com.warmcat.sai.builder_visibility", visible: visible }));
+ }
}
};
const onTouchEnd = () => {
document.removeEventListener('touchmove', onTouchMove);
document.removeEventListener('touchend', onTouchEnd);
- localStorage.setItem('sai-left-pane-flex', leftPane.style.flex);
+ localStorage.setItem('sai-right-pane-flex', rightPane.style.flex);
};
const onTouchStart = (e) => {
if (e.touches.length === 1) {
x = e.touches[0].clientX;
- leftWidth = leftPane.getBoundingClientRect().width;
+ rightWidth = rightPane.getBoundingClientRect().width;
+ lastVisible = rightWidth > 0 ? 1 : 0;
document.addEventListener('touchmove', onTouchMove, { passive: false });
document.addEventListener('touchend', onTouchEnd);
}
diff --git a/src/web/w-private.h b/src/web/w-private.h
index 831d910..5d0b19a 100644
--- a/src/web/w-private.h
+++ b/src/web/w-private.h
@@ -134,6 +134,7 @@ struct pss {
unsigned int bulk_binary_data:1;
unsigned int toggle_favour_sch:1;
unsigned int resolved_task_offset:1;
+ uint8_t wants_builder_info;
sai_auth_state_t auth_state;
};
diff --git a/src/web/w-ws-browser.c b/src/web/w-ws-browser.c
index 8bb6526..79ee52e 100644
--- a/src/web/w-ws-browser.c
+++ b/src/web/w-ws-browser.c
@@ -59,6 +59,14 @@ static lws_struct_map_t lsm_browser_builderdelete[] = {
LSM_CARRAY (sai_browse_rx_builderdelete_t, builder_name, "builder_name"),
};
+typedef struct sai_browse_rx_builder_visibility {
+ uint8_t visible;
+} sai_browse_rx_builder_visibility_t;
+
+static lws_struct_map_t lsm_browser_builder_visibility[] = {
+ LSM_UNSIGNED (sai_browse_rx_builder_visibility_t, visible, "visible"),
+};
+
static lws_struct_map_t lsm_browser_taskinfo[] = {
LSM_CARRAY (sai_browse_rx_taskinfo_t, task_hash, "task_hash"),
LSM_UNSIGNED (sai_browse_rx_taskinfo_t, logs, "logs"),
@@ -110,6 +118,8 @@ static const lws_struct_map_t lsm_schema_json_map_bwsrx[] = {
"com.warmcat.sai.closeshell"),
LSM_SCHEMA (sai_ptydata_t, NULL, lsm_ptydata,
"com.warmcat.sai.ptydata"),
+ LSM_SCHEMA (sai_browse_rx_builder_visibility_t, NULL, lsm_browser_builder_visibility,
+ "com.warmcat.sai.builder_visibility"),
};
enum {
@@ -131,6 +141,7 @@ enum {
SAIM_WS_BROWSER_RX_OPENSHELL,
SAIM_WS_BROWSER_RX_CLOSESHELL,
SAIM_WS_BROWSER_RX_PTYDATA,
+ SAIM_WS_BROWSER_RX_BUILDER_VISIBILITY,
};
@@ -686,6 +697,18 @@ saiw_ws_json_rx_browser(struct vhd *vhd, struct pss *pss, uint8_t *buf,
switch (a.top_schema_index) {
+ case SAIM_WS_BROWSER_RX_BUILDER_VISIBILITY:
+ {
+ sai_browse_rx_builder_visibility_t *v = (sai_browse_rx_builder_visibility_t *)a.dest;
+ pss->wants_builder_info = v->visible;
+ if (v->visible) {
+ saiw_browser_broadcast_queue_builders(pss->vhd, pss);
+ saiw_browser_broadcast_queue_pcons(pss->vhd, pss);
+ saiw_browser_broadcast_queue_power_history(pss->vhd, pss);
+ }
+ }
+ goto ok;
+
case SAIM_WS_BROWSER_RX_TASKINFO:
ti = (sai_browse_rx_taskinfo_t *)a.dest;
@@ -1395,6 +1418,9 @@ saiw_browser_broadcast_queue_pcon_energy(struct vhd *vhd, struct pss *pss, sai_p
lws_struct_json_serialize_result_t r;
size_t w;
+ if (pss && !pss->wants_builder_info)
+ return 0;
+
if (!vhd || !energy)
return 0;
@@ -1445,7 +1471,10 @@ saiw_browser_broadcast_queue_pcons(struct vhd *vhd, struct pss *pss)
lws_struct_json_serialize_result_t r;
size_t w;
- if (!vhd || !vhd->pcons)
+ if (pss && !pss->wants_builder_info)
+ return 0;
+
+ if (!vhd || !vhd->pcons || !pss)
return 0;
memset(&d, 0, sizeof(d));
@@ -1491,7 +1520,6 @@ saiw_browser_broadcast_queue_pcons(struct vhd *vhd, struct pss *pss)
int
saiw_browser_broadcast_queue_builders(struct vhd *vhd, struct pss *pss)
{
- saiw_browser_broadcast_queue_pcons(vhd, pss);
struct sai_dyn_buf d;
char buf[1024]; /* temp buffer for serialization before append */
lws_struct_serialize_t *js;
@@ -1501,6 +1529,14 @@ saiw_browser_broadcast_queue_builders(struct vhd *vhd, struct pss *pss)
size_t w;
int n;
+ if (pss && !pss->wants_builder_info)
+ return 0;
+
+ if (!vhd || !vhd->builders || !pss)
+ return 0;
+
+ saiw_browser_broadcast_queue_pcons(vhd, pss);
+
memset(&d, 0, sizeof(d));
/* Reserve LWS_PRE header space */
@@ -1680,6 +1716,9 @@ saiw_browser_broadcast_queue_power_history(struct vhd *vhd, struct pss *pss)
char buf[2048];
int n, i;
+ if (pss && !pss->wants_builder_info)
+ return 0;
+
if (!vhd)
return 0;
diff --git a/src/web/w-ws-server.c b/src/web/w-ws-server.c
index ecd466b..fd55d6b 100644
--- a/src/web/w-ws-server.c
+++ b/src/web/w-ws-server.c
@@ -149,7 +149,7 @@ saiw_lp_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
memcpy(tmp + LWS_PRE, p, rem);
lws_start_foreach_dll(struct lws_dll2 *, pt, vhd->browsers.head) {
struct pss *pss = lws_container_of(pt, struct pss, same);
- if (!pss->is_gitohashi)
+ if (!pss->is_gitohashi && pss->wants_builder_info)
saiw_ws_browser_queue_REQUIRES_LWS_PRE(pss, tmp + LWS_PRE, rem,
lws_write_ws_flags(LWS_WRITE_TEXT, is_start, 0));
} lws_end_foreach_dll(pt);
@@ -194,7 +194,7 @@ saiw_lp_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
memcpy(tmp + LWS_PRE, p, consumed);
lws_start_foreach_dll(struct lws_dll2 *, pt, vhd->browsers.head) {
struct pss *pss = lws_container_of(pt, struct pss, same);
- if (!pss->is_gitohashi)
+ if (!pss->is_gitohashi && pss->wants_builder_info)
saiw_ws_browser_queue_REQUIRES_LWS_PRE(pss, tmp + LWS_PRE, consumed,
lws_write_ws_flags(LWS_WRITE_TEXT, is_start, 1));
} lws_end_foreach_dll(pt);