Fix/web UI display preview resolution (#69)

* fix(web-ui): Use config display dimensions instead of hardcoded 128x32 in Live Display Preview

- Updated /api/display/current endpoint to calculate display dimensions from config
- Modified HTML template to use config dimensions as fallbacks instead of hardcoded 128x32
- Display preview now shows correct resolution based on cols*chain_length x rows*parallel
- Maintains backward compatibility with existing API responses

* feat(web-ui): Add missing NCAAM Hockey sports manager to web interface

- Added NCAAM Hockey import and OnDemandRunner support
- Updated sports configuration UI to include NCAAM Hockey
- Fixed MLB and MiLB config keys to match template (_scoreboard suffix)
- All sports managers now properly represented in web interface:
  - NFL, MLB, MiLB, NHL, NBA, NCAA FB, NCAA Baseball, NCAAM Basketball, NCAAM Hockey, Soccer
- Maintains backward compatibility with existing configurations

* fix(web-ui): Improve on-demand button error handling and prevent crashes

- Enhanced error handling in OnDemandRunner with better logging and fallback modes
- Added robust display manager initialization with fallback support
- Improved error reporting via WebSocket to client for real-time feedback
- Added input validation for on-demand mode parameters
- Enhanced client-side error handling with better user notifications
- Added safety checks to prevent multiple on-demand instances
- Fixed display manager initialization issues that caused crashes
- Improved error recovery and graceful degradation
This commit is contained in:
Chuck
2025-09-25 19:08:21 -04:00
committed by GitHub
parent abceb8205c
commit 1bc4e531ae
2 changed files with 106 additions and 20 deletions

View File

@@ -2132,7 +2132,11 @@
body: JSON.stringify({ mode })
});
const data = await res.json();
showNotification(data.message || 'Requested on-demand start', data.status || 'success');
if(data.status === 'success'){
showNotification(data.message || 'On-demand started successfully', 'success');
} else {
showNotification(data.message || 'Failed to start on-demand', 'error');
}
refreshOnDemandStatus();
}catch(err){
showNotification('Error starting on-demand: ' + err, 'error');
@@ -2268,9 +2272,14 @@
startPreviewPolling();
});
socket.on('display_update', function(data) {
updateDisplayPreview(data);
});
socket.on('display_update', function(data) {
updateDisplayPreview(data);
});
socket.on('ondemand_error', function(data) {
showNotification(`On-demand error: ${data.error}`, 'error');
refreshOnDemandStatus();
});
}
async function updateApiMetrics(){
@@ -2381,19 +2390,25 @@
img.src = `data:image/png;base64,${data.image}`;
const meta = document.getElementById('previewMeta');
if (meta) {
meta.textContent = `${data.width || 128} x ${data.height || 32} @ ${scale}x`;
// Use config dimensions as fallback instead of hardcoded values
const configWidth = {{ main_config.get('display', {}).get('hardware', {}).get('cols', 64) * main_config.get('display', {}).get('hardware', {}).get('chain_length', 1) }};
const configHeight = {{ main_config.get('display', {}).get('hardware', {}).get('rows', 32) * main_config.get('display', {}).get('hardware', {}).get('parallel', 1) }};
meta.textContent = `${data.width || configWidth} x ${data.height || configHeight} @ ${scale}x`;
}
// Once image loads, size the canvas to match
const width = (data.width || 128) * scale;
const height = (data.height || 32) * scale;
// Use config dimensions as fallback instead of hardcoded values
const configWidth = {{ main_config.get('display', {}).get('hardware', {}).get('cols', 64) * main_config.get('display', {}).get('hardware', {}).get('chain_length', 1) }};
const configHeight = {{ main_config.get('display', {}).get('hardware', {}).get('rows', 32) * main_config.get('display', {}).get('hardware', {}).get('parallel', 1) }};
const width = (data.width || configWidth) * scale;
const height = (data.height || configHeight) * scale;
img.style.width = width + 'px';
img.style.height = height + 'px';
ledCanvas.width = width;
ledCanvas.height = height;
canvas.width = width;
canvas.height = height;
drawGrid(canvas, data.width || 128, data.height || 32, scale);
drawGrid(canvas, data.width || configWidth, data.height || configHeight, scale);
renderLedDots();
} else {
stage.style.display = 'none';
@@ -3528,24 +3543,26 @@
const cfg = currentConfig;
const leaguePrefixes = {
'nfl_scoreboard': 'nfl',
'mlb': 'mlb',
'milb': 'milb',
'mlb_scoreboard': 'mlb',
'milb_scoreboard': 'milb',
'nhl_scoreboard': 'nhl',
'nba_scoreboard': 'nba',
'ncaa_fb_scoreboard': 'ncaa_fb',
'ncaa_baseball_scoreboard': 'ncaa_baseball',
'ncaam_basketball_scoreboard': 'ncaam_basketball',
'ncaam_hockey_scoreboard': 'ncaam_hockey',
'soccer_scoreboard': 'soccer'
};
const leagues = [
{ key: 'nfl_scoreboard', label: 'NFL' },
{ key: 'mlb', label: 'MLB' },
{ key: 'milb', label: 'MiLB' },
{ key: 'mlb_scoreboard', label: 'MLB' },
{ key: 'milb_scoreboard', label: 'MiLB' },
{ key: 'nhl_scoreboard', label: 'NHL' },
{ key: 'nba_scoreboard', label: 'NBA' },
{ key: 'ncaa_fb_scoreboard', label: 'NCAA FB' },
{ key: 'ncaa_baseball_scoreboard', label: 'NCAA Baseball' },
{ key: 'ncaam_basketball_scoreboard', label: 'NCAAM Basketball' },
{ key: 'ncaam_hockey_scoreboard', label: 'NCAAM Hockey' },
{ key: 'soccer_scoreboard', label: 'Soccer' }
];
const container = document.getElementById('sports-config');