Skip to content

Commit 6472ea1

Browse files
committed
fix(guest-agent): tighten the dashboard layout
Every value on this page sat inside three stacked surfaces: a white `.info-section` card, a grey rounded `.info-row` inside it, and a white bordered `.info-value` inside that. Three backgrounds to show one string, and the innermost one reads as a disabled text input, which is a claim the page cannot honour -- none of these values are editable. The card stays and the two inner boxes become a hairline between rows. With rows separating themselves the 12px grid gap is redundant, and the 1.6 line-height is a prose setting on a page that is entirely single-line data. Headings were spending about seventy pixels each on margins. A row goes from roughly 60px to 34px. Tables had the opposite problem in the same place: 15px cells made rows tall while the columns stayed too narrow to hold an identifier, so a single GPU row wrapped into three lines of text. Cells shrink, values stop wrapping, and the table scrolls sideways when it has to. That scrolling goes on a wrapper. Setting overflow on the table itself needs display:block, which drops the table formatting context and lets thead and tbody compute their widths independently -- the header bar and the body rows then disagree about where the right edge is. The wrapper also owns the rounded corners and the shadow now, which deletes the four per-corner rules that were placing them on individual cells.
1 parent 635510d commit 6472ea1

1 file changed

Lines changed: 134 additions & 125 deletions

File tree

dstack/guest-agent/templates/dashboard.html

Lines changed: 134 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121

2222
body {
2323
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
24-
line-height: 1.6;
25-
padding: 30px;
26-
max-width: 1000px;
24+
/* Data, not prose: 1.6 leading on single-line values reads as gaps. */
25+
line-height: 1.45;
26+
padding: 24px 20px;
27+
max-width: 1180px;
2728
margin: 0 auto;
2829
background-color: var(--background-color);
2930
color: var(--primary-color);
@@ -32,9 +33,18 @@
3233
h1,
3334
h2 {
3435
color: var(--primary-color);
35-
margin-bottom: 1rem;
3636
border-bottom: 2px solid var(--border-color);
37-
padding-bottom: 0.5rem;
37+
padding-bottom: 0.3rem;
38+
}
39+
40+
h1 {
41+
font-size: 1.6rem;
42+
margin: 0 0 0.6rem;
43+
}
44+
45+
h2 {
46+
font-size: 1.15rem;
47+
margin: 1.4rem 0 0.6rem;
3848
}
3949

4050
textarea {
@@ -49,45 +59,43 @@
4959
resize: vertical;
5060
}
5161

62+
/* Overflow belongs on a wrapper. Setting it on the table needs
63+
display:block, which drops the table formatting context and lets
64+
thead and tbody size themselves independently. */
65+
.table-scroll {
66+
overflow-x: auto;
67+
margin-top: 12px;
68+
border-radius: 8px;
69+
background-color: white;
70+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
71+
}
72+
5273
table {
5374
width: 100%;
5475
border-collapse: separate;
5576
border-spacing: 0;
56-
margin-top: 20px;
57-
background-color: white;
58-
border-radius: 8px;
59-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
77+
font-size: 0.92rem;
6078
}
6179

6280
th,
6381
td {
64-
padding: 15px;
82+
padding: 7px 10px;
6583
text-align: left;
6684
border-bottom: 1px solid var(--border-color);
6785
}
6886

87+
/* An identifier split across two lines is harder to read than a table
88+
the reader scrolls sideways. */
89+
td {
90+
white-space: nowrap;
91+
}
92+
6993
th {
7094
background-color: var(--primary-color);
7195
color: white;
7296
font-weight: 500;
7397
}
7498

75-
th:first-child {
76-
border-top-left-radius: 8px;
77-
}
78-
79-
th:last-child {
80-
border-top-right-radius: 8px;
81-
}
82-
83-
tr:last-child td:first-child {
84-
border-bottom-left-radius: 8px;
85-
}
86-
87-
tr:last-child td:last-child {
88-
border-bottom-right-radius: 8px;
89-
}
90-
9199
tbody tr:hover {
92100
background-color: #f5f6f7;
93101
}
@@ -106,25 +114,26 @@
106114

107115
.info-section {
108116
background-color: white;
109-
padding: 20px;
117+
padding: 6px 16px;
110118
border-radius: 8px;
111-
margin-bottom: 20px;
119+
margin-bottom: 14px;
112120
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
113121
}
114122

115123
.info-grid {
116124
display: grid;
117-
gap: 12px;
118-
margin-top: 16px;
119125
}
120126

121127
.info-row {
122128
display: grid;
123-
grid-template-columns: 200px 1fr;
129+
grid-template-columns: 190px 1fr;
124130
align-items: center;
125-
padding: 4px 12px;
126-
background-color: #f8f9fa;
127-
border-radius: 6px;
131+
padding: 5px 4px;
132+
border-bottom: 1px solid var(--border-color);
133+
}
134+
135+
.info-row:last-child {
136+
border-bottom: none;
128137
}
129138

130139
.info-label {
@@ -134,10 +143,6 @@
134143

135144
.info-value {
136145
font-family: monospace;
137-
background-color: white;
138-
padding: 6px 12px;
139-
border-radius: 4px;
140-
border: 1px solid var(--border-color);
141146
word-break: break-all;
142147
overflow-wrap: break-word;
143148
}
@@ -254,97 +259,101 @@ <h2>GPUs</h2>
254259
{%- endmatch %}
255260
</div>
256261
</div>
257-
<table>
258-
<thead>
259-
<tr>
260-
<th>Index</th>
261-
<th>PCI</th>
262-
<th>GPU %</th>
263-
<th>Mem %</th>
264-
<th>Memory</th>
265-
<th>Temp</th>
266-
<th>Power</th>
267-
<th>Error</th>
268-
</tr>
269-
</thead>
270-
<tbody>
271-
{% for gpu in gpu_info.gpus %}
272-
<tr>
273-
<td>{{ gpu.index }}</td>
274-
<td>{{ gpu.pci_bus_id|short_bdf }}</td>
275-
<td>
276-
{% match gpu.utilization_gpu %}
277-
{% when Some with (value) %}{{ value }}%
278-
{% when None %}-
279-
{% endmatch %}
280-
</td>
281-
<td>
282-
{% match gpu.utilization_memory %}
283-
{% when Some with (value) %}{{ value }}%
284-
{% when None %}-
285-
{% endmatch %}
286-
</td>
287-
<td>
288-
{% match gpu.memory_used_bytes %}
289-
{% when Some with (used) %}
290-
{% match gpu.memory_total_bytes %}
291-
{% when Some with (total) %}{{ used|hsize }} / {{ total|hsize }}
292-
{% when None %}{{ used|hsize }}
293-
{% endmatch %}
294-
{% when None %}
295-
{% match gpu.memory_total_bytes %}
296-
{% when Some with (total) %}- / {{ total|hsize }}
297-
{% when None %}-
298-
{% endmatch %}
299-
{% endmatch %}
300-
</td>
301-
<td>
302-
{% match gpu.temperature_c %}
303-
{% when Some with (value) %}{{ value }} C
304-
{% when None %}-
305-
{% endmatch %}
306-
</td>
307-
<td>
308-
{% match gpu.power_usage_mw %}
309-
{% when Some with (value) %}{{ "{:.1}"|format(value as f32 / 1000.0) }} W
310-
{% when None %}-
311-
{% endmatch %}
312-
</td>
313-
<td>{{ gpu.errors.join("; ") }}</td>
314-
</tr>
315-
{% endfor %}
316-
</tbody>
317-
</table>
262+
<div class="table-scroll">
263+
<table>
264+
<thead>
265+
<tr>
266+
<th>Index</th>
267+
<th>PCI</th>
268+
<th>GPU %</th>
269+
<th>Mem %</th>
270+
<th>Memory</th>
271+
<th>Temp</th>
272+
<th>Power</th>
273+
<th>Error</th>
274+
</tr>
275+
</thead>
276+
<tbody>
277+
{% for gpu in gpu_info.gpus %}
278+
<tr>
279+
<td>{{ gpu.index }}</td>
280+
<td>{{ gpu.pci_bus_id|short_bdf }}</td>
281+
<td>
282+
{% match gpu.utilization_gpu %}
283+
{% when Some with (value) %}{{ value }}%
284+
{% when None %}-
285+
{% endmatch %}
286+
</td>
287+
<td>
288+
{% match gpu.utilization_memory %}
289+
{% when Some with (value) %}{{ value }}%
290+
{% when None %}-
291+
{% endmatch %}
292+
</td>
293+
<td>
294+
{% match gpu.memory_used_bytes %}
295+
{% when Some with (used) %}
296+
{% match gpu.memory_total_bytes %}
297+
{% when Some with (total) %}{{ used|hsize }} / {{ total|hsize }}
298+
{% when None %}{{ used|hsize }}
299+
{% endmatch %}
300+
{% when None %}
301+
{% match gpu.memory_total_bytes %}
302+
{% when Some with (total) %}- / {{ total|hsize }}
303+
{% when None %}-
304+
{% endmatch %}
305+
{% endmatch %}
306+
</td>
307+
<td>
308+
{% match gpu.temperature_c %}
309+
{% when Some with (value) %}{{ value }} C
310+
{% when None %}-
311+
{% endmatch %}
312+
</td>
313+
<td>
314+
{% match gpu.power_usage_mw %}
315+
{% when Some with (value) %}{{ "{:.1}"|format(value as f32 / 1000.0) }} W
316+
{% when None %}-
317+
{% endmatch %}
318+
</td>
319+
<td>{{ gpu.errors.join("; ") }}</td>
320+
</tr>
321+
{% endfor %}
322+
</tbody>
323+
</table>
324+
</div>
318325
{% endif %}
319326
{% endif %}
320327

321328
<h2>Deployed Containers</h2>
322-
<table>
323-
<thead>
324-
<tr>
325-
<th>Name</th>
326-
<th>Status</th>
327-
{% if public_logs %}
328-
<th>Logs</th>
329-
{% endif %}
330-
</tr>
331-
</thead>
332-
<tbody>
333-
{% for container in containers %}
334-
{% set name = container.names.get(0) %}
335-
<tr>
336-
<td>{{name|cname}}</td>
337-
<td>{{container.status}}</td>
338-
{% if public_logs %}
339-
<td>
340-
<a href="/logs/{{name|cname}}?text&bare&timestamps&follow&tail=20" target="_blank">View
341-
Logs</a>
342-
</td>
343-
{% endif %}
344-
</tr>
345-
{% endfor %}
346-
</tbody>
347-
</table>
329+
<div class="table-scroll">
330+
<table>
331+
<thead>
332+
<tr>
333+
<th>Name</th>
334+
<th>Status</th>
335+
{% if public_logs %}
336+
<th>Logs</th>
337+
{% endif %}
338+
</tr>
339+
</thead>
340+
<tbody>
341+
{% for container in containers %}
342+
{% set name = container.names.get(0) %}
343+
<tr>
344+
<td>{{name|cname}}</td>
345+
<td>{{container.status}}</td>
346+
{% if public_logs %}
347+
<td>
348+
<a href="/logs/{{name|cname}}?text&bare&timestamps&follow&tail=20" target="_blank">View
349+
Logs</a>
350+
</td>
351+
{% endif %}
352+
</tr>
353+
{% endfor %}
354+
</tbody>
355+
</table>
356+
</div>
348357

349358
<h2>TCB Info</h2>
350359
{% if public_tcbinfo %}

0 commit comments

Comments
 (0)