42720a70bc
Native, self-contained Cockpit page (plain HTML/JS, no build step) that polls nvidia-smi via cockpit.spawn to show live GPU utilization, memory, temperature, power, fan speed, ~5min history sparklines, and the list of processes using the GPU. No background systemd service; data collection only happens while the page is open.
165 lines
3.0 KiB
CSS
165 lines
3.0 KiB
CSS
/* gpu-monitor: estilos autocontenidos, sin dependencia de PatternFly ni de
|
|
* assets internos de Cockpit (para no acoplarse a rutas que cambian entre
|
|
* versiones). */
|
|
|
|
:root {
|
|
--gpu-bg: #ffffff;
|
|
--gpu-fg: #1a1a1a;
|
|
--gpu-muted: #6a6a6a;
|
|
--gpu-card-bg: #f5f5f5;
|
|
--gpu-border: #dcdcdc;
|
|
--gpu-accent: #0066cc;
|
|
--gpu-error-bg: #fdecea;
|
|
--gpu-error-fg: #7a1f1a;
|
|
--gpu-error-border: #f2b8b5;
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
:root {
|
|
--gpu-bg: #1e1e1e;
|
|
--gpu-fg: #e8e8e8;
|
|
--gpu-muted: #a0a0a0;
|
|
--gpu-card-bg: #2a2a2a;
|
|
--gpu-border: #3d3d3d;
|
|
--gpu-accent: #4da3ff;
|
|
--gpu-error-bg: #3a1f1e;
|
|
--gpu-error-fg: #f5b8b3;
|
|
--gpu-error-border: #5c2b28;
|
|
}
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
padding: 16px;
|
|
font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
background: var(--gpu-bg);
|
|
color: var(--gpu-fg);
|
|
}
|
|
|
|
h2 {
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
margin: 0 0 8px;
|
|
}
|
|
|
|
.error-banner {
|
|
background: var(--gpu-error-bg);
|
|
color: var(--gpu-error-fg);
|
|
border: 1px solid var(--gpu-error-border);
|
|
border-radius: 4px;
|
|
padding: 10px 14px;
|
|
margin-bottom: 16px;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.gpu-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.gpu-card {
|
|
background: var(--gpu-card-bg);
|
|
border: 1px solid var(--gpu-border);
|
|
border-radius: 6px;
|
|
padding: 16px;
|
|
}
|
|
|
|
.gpu-title {
|
|
color: var(--gpu-accent);
|
|
}
|
|
|
|
.tiles {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
|
gap: 12px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.tile {
|
|
background: var(--gpu-bg);
|
|
border: 1px solid var(--gpu-border);
|
|
border-radius: 4px;
|
|
padding: 8px 12px;
|
|
}
|
|
|
|
.tile-label {
|
|
font-size: 0.75rem;
|
|
color: var(--gpu-muted);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
}
|
|
|
|
.tile-value {
|
|
font-size: 1.3rem;
|
|
font-weight: 600;
|
|
margin-top: 2px;
|
|
}
|
|
|
|
.charts {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
gap: 16px;
|
|
}
|
|
|
|
.chart-box {
|
|
background: var(--gpu-bg);
|
|
border: 1px solid var(--gpu-border);
|
|
border-radius: 4px;
|
|
padding: 8px 12px;
|
|
}
|
|
|
|
.chart-title {
|
|
font-size: 0.75rem;
|
|
color: var(--gpu-muted);
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.sparkline {
|
|
width: 100%;
|
|
height: 60px;
|
|
display: block;
|
|
}
|
|
|
|
.sparkline polyline {
|
|
fill: none;
|
|
stroke: var(--gpu-accent);
|
|
stroke-width: 2;
|
|
vector-effect: non-scaling-stroke;
|
|
}
|
|
|
|
.process-section {
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.process-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.process-table th,
|
|
.process-table td {
|
|
text-align: left;
|
|
padding: 6px 10px;
|
|
border-bottom: 1px solid var(--gpu-border);
|
|
}
|
|
|
|
.process-table th {
|
|
color: var(--gpu-muted);
|
|
font-weight: 600;
|
|
font-size: 0.75rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
}
|
|
|
|
.empty-row td {
|
|
color: var(--gpu-muted);
|
|
font-style: italic;
|
|
}
|