diff --git a/plugins/docker/templates/docker/widget_resources.html b/plugins/docker/templates/docker/widget_resources.html
index 33e0ba4..96f87e7 100644
--- a/plugins/docker/templates/docker/widget_resources.html
+++ b/plugins/docker/templates/docker/widget_resources.html
@@ -14,7 +14,7 @@
- | Container | Host | CPU | Memory |
+ | Container | Host | CPU | Memory |
{% for r in rows %}
{% set u = r.usage %}
@@ -22,7 +22,7 @@
{%- if session.user_id %}{{ r.label }}{% else %}{{ r.label }}{% endif -%}
|
- {{ r.host_name }} |
+ {{ r.host_name }} |
{% if u.cores is none %}— | {% else %}
@@ -37,5 +37,5 @@
{% endfor %}
|
-CPU over the last {{ minutes }} minutes. Shading: share of the host's cores, and of the memory limit (or the host's memory when no limit is set).
+CPU over the last {{ minutes }} min; shading is the share of the host.
{% endif %}
diff --git a/steward/static/dash-layout.js b/steward/static/dash-layout.js
index 36678e3..78b5787 100644
--- a/steward/static/dash-layout.js
+++ b/steward/static/dash-layout.js
@@ -7,9 +7,14 @@
side by side; none is stretched. Edit mode always shows the saved 12-column
layout, so what is saved never depends on the screen it was edited on.
+ Outside edit mode each saved row is split into ROW_SPLIT finer rows, so a
+ widget's height fits its content to within 10px rather than to a whole
+ 70px row (#5214). viewed() gives the saved place in those rows.
+
Used by the dashboard (Gridstack) and the share view (CSS grid). */
(function () {
- var COL_PX = 110, MIN_COLS = 12, MAX_COLS = 24, NARROW_PX = 700, MIN_ROWS = 2;
+ var COL_PX = 110, MIN_COLS = 12, MAX_COLS = 24, NARROW_PX = 700;
+ var ROW_SPLIT = 7, MIN_ROWS = ROW_SPLIT; // view rows: one saved row is the least
function columnsFor(width) {
if (width < NARROW_PX) return 1;
@@ -74,9 +79,9 @@
return h;
}
- /* Grid rows for that height: rowPx is one row plus the gap that follows it,
- gapPx the space a cell loses to its margins. Capped at the saved height,
- where the body scrolls instead. */
+ /* View rows for that height: rowPx is one view row (with its share of the
+ gap), gapPx the space a cell loses to its margins. Capped at maxRows, the
+ saved height in view rows, where the body scrolls instead. */
function fitRows(box, rowPx, gapPx, maxRows) {
var rows = Math.ceil((naturalHeight(box) + gapPx) / rowPx);
return Math.max(MIN_ROWS, Math.min(maxRows, rows));
@@ -86,7 +91,13 @@
return { x: +el.dataset.x, y: +el.dataset.y, w: +el.dataset.w, h: +el.dataset.h };
}
+ function viewed(el) {
+ var s = saved(el);
+ return { x: s.x, y: s.y * ROW_SPLIT, w: s.w, h: s.h * ROW_SPLIT };
+ }
+
window.StewardDashLayout = {
- MIN_COLS: MIN_COLS, columnsFor: columnsFor, pack: pack, fitRows: fitRows, saved: saved,
+ MIN_COLS: MIN_COLS, ROW_SPLIT: ROW_SPLIT, columnsFor: columnsFor, pack: pack,
+ fitRows: fitRows, saved: saved, viewed: viewed,
};
})();
diff --git a/steward/static/steward.css b/steward/static/steward.css
index e61cdb6..24bce80 100644
--- a/steward/static/steward.css
+++ b/steward/static/steward.css
@@ -390,6 +390,7 @@ body.dash-editing .widget-drawer { transform:translateY(0); }
.w-table th { text-align:right; font-weight:500; font-size:var(--fs-size-tiny); color:var(--text-dim); text-transform:uppercase; letter-spacing:var(--fs-tracking-tiny); padding:0 0 0.25rem 0.5rem; white-space:nowrap; }
.w-table td { text-align:right; padding:0.2rem 0 0.2rem 0.5rem; border-top:1px solid var(--border); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.w-table th:first-child, .w-table td:first-child { text-align:left; padding-left:0; }
+.w-table .w-text { text-align:left; } /* a text column after the name: reads from the left, like its header */
.w-table td.w-name { overflow:hidden; text-overflow:ellipsis; }
.w-table td.w-name a { color:inherit; text-decoration:none; }
.w-table td.w-name a:hover { text-decoration:underline; }
diff --git a/steward/templates/dashboard/index.html b/steward/templates/dashboard/index.html
index 7731738..762fd01 100644
--- a/steward/templates/dashboard/index.html
+++ b/steward/templates/dashboard/index.html
@@ -68,8 +68,9 @@
var L = window.StewardDashLayout;
var CELL_PX = 70, MARGIN_PX = 8;
+ var VIEW_PX = CELL_PX / L.ROW_SPLIT; // view mode: finer rows, so heights fit closely
var grid = GridStack.init({
- column: 12, cellHeight: CELL_PX, margin: MARGIN_PX, float: false,
+ column: 12, cellHeight: VIEW_PX, margin: MARGIN_PX, float: false,
staticGrid: true, // view mode: positioned but inert
handle: '.panel-drag',
resizable: { handles: 'e, se, s' },
@@ -84,7 +85,7 @@
var cols = L.columnsFor(gridEl.clientWidth);
var els = items();
var pos = L.pack(els.map(function (el) {
- var s = L.saved(el);
+ var s = L.viewed(el);
s.id = el.getAttribute('gs-id');
s.h = el._fitH || s.h;
return s;
@@ -100,7 +101,7 @@
function fit(el) {
var box = el.querySelector('.grid-stack-item-content');
if (!box) return;
- var rows = L.fitRows(box, CELL_PX, 2 * MARGIN_PX, L.saved(el).h);
+ var rows = L.fitRows(box, VIEW_PX, 2 * MARGIN_PX, L.viewed(el).h);
if (rows !== el._fitH) { el._fitH = rows; relayoutSoon(); }
}
document.body.addEventListener('htmx:afterSettle', function (e) {
@@ -135,6 +136,7 @@
// Edit mode shows the saved 12-column layout at saved heights, so a layout
// edited on a wide screen is the same one a narrow screen starts from.
function showSaved() {
+ grid.cellHeight(CELL_PX);
grid.batchUpdate();
if (grid.getColumn() !== L.MIN_COLS) grid.column(L.MIN_COLS, 'none');
items().forEach(function (el) { grid.update(el, L.saved(el)); });
@@ -148,7 +150,7 @@
document.body.classList.toggle('dash-editing', on);
var btn = document.getElementById('dash-edit-toggle');
if (btn) btn.textContent = on ? 'Done' : 'Edit';
- if (!on) { items().forEach(fit); relayout(); }
+ if (!on) { grid.cellHeight(VIEW_PX); items().forEach(fit); relayout(); }
}
var toggle = document.getElementById('dash-edit-toggle');
if (toggle) toggle.addEventListener('click', function () { setEditing(!editing); });
diff --git a/steward/templates/dashboard/share_view.html b/steward/templates/dashboard/share_view.html
index aeacb08..277caea 100644
--- a/steward/templates/dashboard/share_view.html
+++ b/steward/templates/dashboard/share_view.html
@@ -19,10 +19,12 @@
.share-header { background: var(--bg-card); padding: 0 1.5rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem; border-bottom: 1px solid var(--border-mid); min-height: 48px; }
.share-name { font-family: var(--fs-font-display); font-weight: 500; font-size: 1.15rem; color: var(--gold); overflow-wrap: anywhere; }
.share-main { max-width: 2400px; }
- /* The same layout as the signed-in dashboard: rows 70px, gaps 1rem, and
- static/dash-layout.js sets the columns and each cell's place and height. */
- .dash-grid { display: grid; grid-template-columns: repeat(12, 1fr); grid-auto-rows: 70px; gap: 1rem; }
- .dash-grid > .dash-cell { margin-bottom: 0; min-width: 0; overflow: hidden; display: flex; flex-direction: column; }
+ /* The same layout as the signed-in dashboard: a saved row is 70px plus a
+ 1rem gap, split into ROW_SPLIT view rows (the gap is each cell's bottom
+ margin), and static/dash-layout.js sets the columns and each cell's
+ place and height. */
+ .dash-grid { display: grid; grid-template-columns: repeat(12, 1fr); grid-auto-rows: calc((70px + 1rem) / 7); column-gap: 1rem; row-gap: 0; }
+ .dash-grid > .dash-cell { margin-bottom: 1rem; min-width: 0; overflow: hidden; display: flex; flex-direction: column; }
.dash-cell .dash-cell-body { flex: 1; min-height: 0; overflow: auto; }
@media (max-width: 820px) {
.share-main { padding: 1rem; }
@@ -69,12 +71,12 @@
document.addEventListener('DOMContentLoaded', function () {
var L = window.StewardDashLayout, grid = document.querySelector('.dash-grid');
if (!L || !grid) return;
- var ROW_PX = 70, GAP_PX = 16;
+ var GAP_PX = 16, VIEW_PX = (70 + GAP_PX) / L.ROW_SPLIT;
function cells() { return Array.prototype.slice.call(grid.querySelectorAll('.dash-cell')); }
function relayout() {
var cols = L.columnsFor(grid.clientWidth);
var pos = L.pack(cells().map(function (el) {
- var s = L.saved(el); s.id = el.dataset.id; s.h = el._fitH || s.h; return s;
+ var s = L.viewed(el); s.id = el.dataset.id; s.h = el._fitH || s.h; return s;
}), cols);
grid.style.gridTemplateColumns = 'repeat(' + cols + ', 1fr)';
cells().forEach(function (el) {
@@ -85,7 +87,7 @@ document.addEventListener('DOMContentLoaded', function () {
}
var pending = null;
function fit(el) {
- var rows = L.fitRows(el, ROW_PX + GAP_PX, GAP_PX, L.saved(el).h);
+ var rows = L.fitRows(el, VIEW_PX, GAP_PX, L.viewed(el).h);
if (rows !== el._fitH) { el._fitH = rows; clearTimeout(pending); pending = setTimeout(relayout, 60); }
}
document.body.addEventListener('htmx:afterSettle', function (e) {
diff --git a/steward/templates/hosts/overview_widget.html b/steward/templates/hosts/overview_widget.html
index 1c42369..5005f3e 100644
--- a/steward/templates/hosts/overview_widget.html
+++ b/steward/templates/hosts/overview_widget.html
@@ -17,7 +17,7 @@
- | Host | CPU | Mem | Disk / | Load |
+ | Host | CPU | Mem | Disk | Load |
{% for r in rows %}
{% set a = r.agent %}{% set fresh = a.get('fresh') %}