# TASK.md — v0.5.4: Monitoring Page Frontend Fixes > Version bump: **v0.5.4** > Scope: Frontend-only — all changes in `monitoring.html` and `style.css` > No Go code changes needed. --- ## IMPORTANT: Build & Validation Build must happen in `~/build/felhom-controller/`, NOT in the git repo: ```bash cd ~/build/felhom-controller git -C ~/git/deploy-felhom-compose pull ./build.sh 0.5.2 --push ``` **Never run `go build` inside `~/git/deploy-felhom-compose/controller/`.** After deployment, validate all 4 fixes by: 1. Opening https://felhom.demo-felhom.eu/monitoring in browser 2. Opening the browser Developer Tools (F12) → Console tab 3. Checking each item below If you cannot access the browser, validate by reading the deployed HTML source: ```bash ssh kisfenyo@192.168.0.162 "docker exec felhom-controller cat /app/templates/monitoring.html" | head -50 ``` --- ## Bug 1: Tooltip shows "Invalid Date" ### Root cause The tooltip callback uses `items[0].parsed.x` which should return a numeric timestamp on a Chart.js linear axis. However, depending on the Chart.js version/build, `parsed.x` may return something unexpected (undefined, wrong type) causing `new Date()` to produce "Invalid Date". ### Diagnosis step Before fixing, add a temporary console.log to confirm what `parsed.x` actually returns. In `monitoring.html`, in the tooltip callback inside `chartOpts()`: ```javascript title: function(items) { if (!items.length) return ''; console.log('[tooltip debug]', 'parsed.x:', items[0].parsed.x, typeof items[0].parsed.x, 'raw:', items[0].raw); return formatTimestamp(items[0].parsed.x); } ``` Deploy, hover over a data point, check browser console. Possible findings: - `parsed.x` is `undefined` → Chart.js isn't finding the x value from `{x,y}` data - `parsed.x` is a very small number (like an index) → linear scale isn't applied - `parsed.x` is correct ms timestamp → bug is in `formatTimestamp` ### Fix Replace the tooltip callback with a more robust approach that accesses the raw data point directly: ```javascript callbacks: { title: function(items) { if (!items.length) return ''; // Access raw {x, y} data point directly — most reliable across Chart.js versions var raw = items[0].raw; if (raw && typeof raw === 'object' && raw.x) { return formatTimestamp(raw.x); } // Fallback: try parsed.x if (items[0].parsed && items[0].parsed.x) { return formatTimestamp(items[0].parsed.x); } return ''; } } ``` After deploying and verifying, remove the console.log line. ### Verification - Hover over any data point on any chart → tooltip title shows formatted date like "2026. 02. 16. 11:30" - Verify on CPU, Memory, Temperature, Load charts - Verify on container detail charts too (same `chartOpts` function is shared) --- ## Bug 2: Charts fill full width regardless of data density ### Root cause `setChartXBounds()` sets `chart.options.scales.x.min/max` after chart initialization. Chart.js may not pick up dynamically added `min`/`max` properties if they weren't present in the options during initialization. The scale was created without `min`/`max`, and adding them at runtime may be ignored. ### Diagnosis step Add console.log in `loadSystemMetrics()` after setting bounds and updating: ```javascript allCharts.forEach(function(c) { setChartXBounds(c, systemRange); }); updateLineChart(chartCPU, timestamps, d.cpu); console.log('[bounds debug] range:', systemRange, 'options.min:', chartCPU.options.scales.x.min, 'options.max:', chartCPU.options.scales.x.max, 'scale.min:', chartCPU.scales.x.min, 'scale.max:', chartCPU.scales.x.max); ``` Select "7 nap", check console. If `options.min/max` are set correctly but `scales.x.min/max` show the data extent, then Chart.js is ignoring the runtime-added properties. ### Fix Include `min` and `max` in the initial chart options so Chart.js registers them from creation. Then dynamic updates work. **Step 1**: Modify `chartOpts()` to include initial min/max: ```javascript function chartOpts(yLabel, beginAtZero) { var now = Date.now(); var defaultRangeMs = parseRangeMs('1h'); // match default systemRange return { responsive: true, maintainAspectRatio: false, animation: {duration: 300}, plugins: { legend: {display: false}, tooltip: { backgroundColor: '#1c2128', titleColor: '#e6edf3', bodyColor: '#8b949e', borderColor: '#30363d', borderWidth: 1, callbacks: { title: function(items) { if (!items.length) return ''; var raw = items[0].raw; if (raw && typeof raw === 'object' && raw.x) { return formatTimestamp(raw.x); } if (items[0].parsed && items[0].parsed.x) { return formatTimestamp(items[0].parsed.x); } return ''; } } } }, scales: { x: { type: 'linear', min: now - defaultRangeMs, max: now, grid: {color: 'rgba(48,54,61,0.5)'}, ticks: { color: '#8b949e', maxTicksLimit: 8, callback: function(v) { return formatTimeLabel(v); } } }, y: { grid: {color: 'rgba(48,54,61,0.5)'}, ticks: {color: '#8b949e'}, beginAtZero: beginAtZero !== false, title: {display: !!yLabel, text: yLabel || '', color: '#6e7681', font: {size: 11}} } } }; } ``` Key change: `min: now - defaultRangeMs, max: now` are present from creation. **Step 2**: `setChartXBounds()` stays the same — it updates existing properties. **Step 3**: Same fix for container detail charts — `initDetailCharts()` uses the same `chartOpts()` so it gets min/max automatically. ### Verification - Select "7 nap" → x-axis spans 7 full days (Feb 9 to Feb 16), data appears as a small cluster on the far right - Select "1 óra" → data fills most of the chart width - Select "24 óra" → data fills proportional to collection time - X-axis labels for 7d show dates (02.09 .. 02.16), not times - X-axis labels for 1h/6h/24h show times (10:00, 11:00, etc.) --- ## Bug 3: System overview values not consistently right-aligned ### Root cause `.sysinfo-row` uses `display: flex; justify-content: space-between` which does push values to the right of each cell. But `.sysinfo-grid` uses `repeat(auto-fill, minmax(280px, 1fr))` which creates varying cell widths — values don't align to a consistent edge across columns. The ` ``` The mobile rule `@media(max-width: 768px) { .sysinfo-grid { grid-template-columns: 1fr; } }` already exists and stays — collapses to single column on mobile. ### Verification - Values are consistently right-aligned within each cell - "Debian GNU/Linux 13 (trixie)" and "6.12.69+deb13-amd64" align to the right edge - Both grid columns have equal width - Long values wrap without breaking layout --- ## Bug 4: Charts overflow their container on mobile ### Root cause `.chart-wrap` has `position: relative; height: 180px` but no overflow or width constraint. CSS grid children default to `min-width: auto`, preventing them from shrinking below their content width. Chart.js canvas may render wider than the parent on narrow screens. ### Fix **In `style.css`**, update these rules: ```css .chart-box { background: var(--bg-secondary); border-radius: 8px; padding: .75rem; border: 1px solid rgba(48, 54, 61, 0.5); min-width: 0; /* Allow grid children to shrink — critical fix */ overflow: hidden; } .chart-wrap { position: relative; height: 180px; overflow: hidden; max-width: 100%; } .chart-wrap canvas { max-width: 100%; } .chart-wrap-bar { position: relative; height: 250px; overflow: hidden; max-width: 100%; } ``` Also add `.chart-box-half` update: ```css .chart-box-half { flex: 1; min-width: 0; /* Same fix for flex containers */ } ``` Key additions: - `min-width: 0` on `.chart-box` — **the critical CSS grid fix**: prevents grid children from forcing the grid wider than the viewport - `overflow: hidden` on `.chart-wrap` and `.chart-wrap-bar` — clips any canvas overflow - `max-width: 100%` on `.chart-wrap` and canvas - `min-width: 0` on `.chart-box-half` — same fix for the flex-based container charts ### Verification - Open monitoring page at 375px width (browser devtools responsive mode) - All four system metric charts fit within the screen - Container bar charts fit within the screen - No horizontal scrollbar appears - Charts remain interactive (hover/click works) --- ## Implementation order 1. Edit `style.css` — sysinfo alignment + chart overflow fixes 2. Edit `monitoring.html` — remove `