- Dockerfile with nginx:alpine for static file serving - docker-compose.yml with port 9113:80 mapping - deploy.sh for git-based deployment to Unraid - setup-unraid.sh for initial server configuration - manage.sh for container operations (logs, status, restart, etc.) - .gitignore to exclude config.js Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
18 KiB
Dashboard Improvement Ideas
This document contains recommended improvements for the Thanos Systems Monitor dashboard.
Status Legend
- ✅ Completed: Implementation finished
- 🔄 In Progress: Currently being worked on
- ⏳ Pending: Not yet started
- 💡 Proposed: Idea for consideration
1. Security Concerns ✅
Status: COMPLETED (2025-11-22)
Implementation:
- ✅ Created separate
config.jsfile for API credentials - ✅ Added
config.jsto.gitignore - ✅ Created
config.example.jstemplate - ✅ Updated
script.jsto remove hardcoded credentials - ✅ Added validation check for missing configuration
2. Error Handling and User Feedback ⏳
Current Limitation: The showError() function at script.js:479-485 only displays errors in the timestamp element, which does not exist in your HTML.
Proposed Improvements:
2.1 Add Timestamp and Error Display
- Add timestamp element to header showing last update time
- Create dedicated error notification system
- Style error notifications with cyberpunk theme
2.2 Enhanced Error Handling
- Implement retry logic with exponential backoff when API requests fail
- Display connection status indicator (online/offline/connecting)
- Show loading states during initial data fetch
- Add user-friendly error messages for common failures
2.3 Implementation Details
// Retry logic with exponential backoff
async function fetchWithRetry(fetchFunction, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fetchFunction();
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
}
}
}
// Connection status indicator
function updateConnectionStatus(status) {
// 'online', 'offline', 'connecting', 'error'
}
3. Data Visualization Enhancements ✅
3.1 Ring Chart Improvements
Status: COMPLETED (2025-11-22)
Implemented Features:
- ✅ Added smooth CSS transitions for ring chart value changes
- ✅ Display trend indicators (▲/▼/━ showing increasing/decreasing/stable usage)
- ✅ Added hover tooltips showing detailed information (Used, Free, Total, Usage %)
- ✅ Implemented historical data tracking (last 20 data points per metric)
- ✅ Enhanced hover effects with scale transformation
- ✅ Refactored code to use generic updateRingChartGeneric() function, reducing duplication
Implementation Details:
- Created HistoricalData object to track CPU, Memory, and individual disk usage over time
- Added createTrendIndicator() helper function for visual trend display
- Added createTooltip() helper function for consistent tooltip formatting
- Tooltips display on hover with fade-in animation
- Trend calculation based on last 3 data points with 1% threshold for stability
3.2 Disk Array Enhancements
Status: COMPLETED (2025-11-22)
Implemented Features:
- ✅ Added hover tooltips for each disk showing capacity, temperature, usage, and status
- ✅ Added trend indicators to disk progress bars (▲/▼/━)
- ✅ Enhanced hover effects (background color change, border color change)
- ✅ Historical data tracking for individual disks
Remaining Enhancements:
- ⏳ Visual indicators for disk health status (SMART data if available from API)
- ⏳ Show read/write speed metrics if available from API
- ⏳ Group disks by function (parity, cache, data) more clearly
- ⏳ Add disk age/hours powered on if available from API
3.3 Historical Data Graphs
New Feature:
- Line graphs for CPU usage over time (last hour/day)
- Memory usage trends
- Disk I/O graphs
- Network traffic visualization
- Implement using HTML5 Canvas or lightweight charting library
4. Performance Optimizations ⏳
Current Implementation: Updates occur every 5 seconds regardless of visibility
4.1 Page Visibility API
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// Pause updates
clearInterval(updateInterval);
} else {
// Resume updates
updateInterval = setInterval(updateDashboard, 5000);
updateDashboard(); // Immediate update on return
}
});
4.2 Animation Optimization
- Use
requestAnimationFramefor smoother animations - Batch DOM updates to minimize reflows
- Use CSS transforms instead of position changes
4.3 Differential Updates
- Only update DOM elements that have changed values
- Compare previous state with current state
- Reduce unnecessary re-renders
4.4 Web Workers
- Move data processing to Web Worker
- Keep UI thread responsive
- Process API responses in background
5. Code Quality Improvements ⏳
5.1 Eliminate Code Duplication
Current Issue: Ring chart update functions (script.js:113-240) contain significant duplication
Refactoring Recommendation:
function updateRingChart(elementId, percentage, usedKB, totalKB) {
const ring = document.getElementById(`${elementId}-ring`);
const text = document.getElementById(`${elementId}-percentage`);
const fraction = document.getElementById(`${elementId}-fraction`);
const circumference = 2 * Math.PI * 80;
const offset = circumference - (percentage / 100) * circumference;
ring.style.strokeDashoffset = offset;
text.textContent = percentage + '%';
const usedTB = (usedKB / 1024 / 1024 / 1024).toFixed(2);
const totalTB = (totalKB / 1024 / 1024 / 1024).toFixed(2);
fraction.textContent = `${usedTB} / ${totalTB} TB`;
// Apply color coding
applyThresholdColors(ring, text, fraction, percentage);
}
function applyThresholdColors(ring, text, fraction, percentage) {
const color = percentage >= 90 ? '#ffffff' :
percentage >= 70 ? '#ff00ff' : '#00ffff';
ring.style.stroke = color;
text.style.fill = color;
fraction.style.fill = color;
}
// Usage
updateRingChart('disk', totalUsagePercentage, totalUsed, totalCapacity);
updateRingChart('docker', dockerUsagePercentage, dockerUsed, dockerCapacity);
updateRingChart('photos', photosUsagePercentage, photosUsed, photosCapacity);
updateRingChart('media', mediaUsagePercentage, mediaUsed, mediaCapacity);
5.2 Extract Constants
// Configuration constants
const CONSTANTS = {
UPDATE_INTERVAL: 5000,
RING_RADIUS: 80,
WARNING_THRESHOLD: 70,
CRITICAL_THRESHOLD: 90,
COLORS: {
PRIMARY: '#00ffff',
WARNING: '#ff00ff',
CRITICAL: '#ffffff',
BACKGROUND: '#1a1a1a'
}
};
5.3 Add JSDoc Documentation
/**
* Updates a ring chart with usage data
* @param {string} elementId - The base ID for the ring chart elements
* @param {number} percentage - Usage percentage (0-100)
* @param {number} usedKB - Used space in kilobytes
* @param {number} totalKB - Total space in kilobytes
*/
function updateRingChart(elementId, percentage, usedKB, totalKB) {
// Implementation
}
5.4 Error Boundaries
- Add try-catch blocks around each update function
- Prevent one failing component from breaking entire dashboard
- Log errors for debugging
5.5 Data Validation
function validateMetricsData(data) {
if (!data || typeof data !== 'object') {
throw new Error('Invalid metrics data');
}
if (data.cpu && typeof data.cpu.percentTotal !== 'number') {
console.warn('Invalid CPU data:', data.cpu);
}
return data;
}
6. Responsive Design Enhancements ⏳
Current State: Basic responsive design at 768px breakpoint
6.1 Additional Breakpoints
/* Tablet landscape */
@media (max-width: 1024px) {
.grid-row-1 {
grid-template-columns: 1fr;
}
.disk-usage-layout {
grid-template-columns: 1fr;
}
}
/* Tablet portrait */
@media (max-width: 768px) {
.ring-chart-row-split {
grid-template-columns: 1fr;
}
}
/* Mobile */
@media (max-width: 480px) {
.mini-ring-chart {
width: 120px;
height: 120px;
}
.title {
font-size: 1.5rem;
}
}
6.2 Raspberry Pi Display Optimization
- Test on actual Raspberry Pi display resolution
- Optimize for common resolutions: 1920x1080, 1280x720
- Consider touch-friendly interface elements
- Test browser performance on Raspberry Pi 3
6.3 Orientation Support
- Handle landscape and portrait orientations
- Reflow layout appropriately for vertical displays
7. Accessibility Improvements ⏳
Current State: Limited accessibility features
7.1 ARIA Labels and Roles
<!-- Progress bars -->
<div class="progress-bar"
role="progressbar"
aria-valuenow="75"
aria-valuemin="0"
aria-valuemax="100"
aria-label="CPU Usage">
<div class="progress-fill" style="width: 75%"></div>
<span class="progress-text">75%</span>
</div>
<!-- Status indicators -->
<div class="status-item" role="status" aria-live="polite">
<span class="status-label">PARITY STATUS:</span>
<span class="status-value" id="parity-status">VALID</span>
</div>
7.2 Live Regions
<!-- Add to header for status updates -->
<div id="status-announcer"
role="status"
aria-live="polite"
aria-atomic="true"
class="sr-only">
<!-- Screen reader announcements go here -->
</div>
7.3 Keyboard Navigation
- Add tab index to interactive elements
- Implement keyboard shortcuts for common actions
- Ensure focus indicators are visible
7.4 Color Contrast
- Verify all text meets WCAG AA standards (4.5:1 ratio)
- Current cyan (#00ffff) on black (#000000) has 15.3:1 ratio ✓
- Test magenta (#ff00ff) and white (#ffffff) combinations
- Consider adding high contrast mode option
7.5 Screen Reader Support
function announceUpdate(message) {
const announcer = document.getElementById('status-announcer');
announcer.textContent = message;
}
// Usage
announceUpdate('CPU usage increased to 85%');
announceUpdate('Docker container "plex" started');
8. Additional Features 💡
8.1 User Preferences
Proposed Implementation:
const UserPreferences = {
updateInterval: 5000,
theme: 'dark', // Future: 'light' option
showAnimations: true,
temperatureUnit: 'celsius', // or 'fahrenheit'
notifications: {
enabled: true,
cpuThreshold: 90,
memoryThreshold: 90,
diskThreshold: 90
}
};
// Save to localStorage
function savePreferences(prefs) {
localStorage.setItem('dashboardPrefs', JSON.stringify(prefs));
}
// Load from localStorage
function loadPreferences() {
const saved = localStorage.getItem('dashboardPrefs');
return saved ? JSON.parse(saved) : UserPreferences;
}
8.2 Configurable Alerts
- Set custom thresholds for warnings
- Browser notifications for critical states
- Email/webhook notifications (requires backend)
- Sound alerts for critical conditions
8.3 Data Export
function exportData(format = 'json') {
const data = {
timestamp: new Date().toISOString(),
cpu: currentCPUUsage,
memory: currentMemoryUsage,
disks: currentDiskData,
docker: currentDockerData
};
if (format === 'json') {
const blob = new Blob([JSON.stringify(data, null, 2)],
{ type: 'application/json' });
downloadFile(blob, `unraid-metrics-${Date.now()}.json`);
} else if (format === 'csv') {
// Convert to CSV and download
}
}
8.4 Theme Options
- Light theme option
- Custom color schemes
- Adjustable glow intensity
- Disable animations option (for performance)
8.5 Network Monitoring
If Available from API:
- Network interface statistics
- Upload/download speeds
- Total bandwidth usage
- Per-container network usage
8.6 UPS Status
If Available from API:
- Battery charge level
- Runtime remaining
- Power status (on battery/on AC)
- UPS load percentage
8.7 System Temperature Monitoring
If Available from API:
- CPU temperature
- Motherboard temperature
- Additional thermal sensors
- Temperature history graphs
8.8 Cache Drive Monitoring
- Separate cache drive statistics
- Cache utilization
- Mover status and schedule
9. Docker Container Enhancements ⏳
Current Display: Basic name and status
9.1 Additional Container Information
Proposed Additions:
- CPU usage per container (if available)
- Memory usage per container (if available)
- Port mappings display
- Container uptime
- Container health check status
- Image version/tag
9.2 Container Controls
If API Supports:
async function controlContainer(containerId, action) {
// action: 'start', 'stop', 'restart'
const query = `mutation {
dockerContainerControl(id: "${containerId}", action: "${action}") {
success
message
}
}`;
return await executeGraphQLQuery(query);
}
UI Implementation:
- Add start/stop/restart buttons to each container card
- Confirmation dialog for destructive actions
- Loading state during action execution
- Success/error feedback
9.3 Container Details Modal
- Click container to view detailed information
- Show logs (last 100 lines)
- Environment variables
- Volume mounts
- Network configuration
10. Testing and Monitoring ⏳
10.1 Unit Tests
Proposed Framework: Jest or Vitest (lightweight)
// Example test file: script.test.js
describe('formatBytes', () => {
test('formats bytes correctly', () => {
expect(formatBytes(0)).toBe('0 B');
expect(formatBytes(1024)).toBe('1 KB');
expect(formatBytes(1048576)).toBe('1 MB');
expect(formatBytes(1073741824)).toBe('1 GB');
});
});
describe('updateCPU', () => {
test('applies critical class above 90%', () => {
document.body.innerHTML = `
<div class="progress-fill" id="cpu-progress"></div>
<span id="cpu-text"></span>
`;
updateCPU(95);
const progressBar = document.getElementById('cpu-progress');
expect(progressBar.classList.contains('critical')).toBe(true);
});
});
10.2 Integration Tests
Test API Integration:
describe('API Integration', () => {
test('fetches system metrics successfully', async () => {
const metrics = await fetchSystemMetrics();
expect(metrics).toHaveProperty('cpu');
expect(metrics).toHaveProperty('memory');
});
test('handles API errors gracefully', async () => {
// Mock failed request
global.fetch = jest.fn(() => Promise.reject('API Error'));
await expect(fetchSystemMetrics()).rejects.toThrow();
});
});
10.3 Performance Monitoring
// Add performance tracking
const performanceMetrics = {
apiCallDuration: [],
renderDuration: [],
totalUpdateDuration: []
};
async function updateDashboard() {
const startTime = performance.now();
try {
// Existing update logic
} finally {
const duration = performance.now() - startTime;
performanceMetrics.totalUpdateDuration.push(duration);
// Log if update takes too long
if (duration > 1000) {
console.warn(`Slow update: ${duration}ms`);
}
}
}
10.4 Error Logging
Client-Side Error Tracking:
// Simple error logger
const ErrorLogger = {
errors: [],
log(error, context = {}) {
const errorEntry = {
timestamp: new Date().toISOString(),
message: error.message,
stack: error.stack,
context: context
};
this.errors.push(errorEntry);
console.error('Error logged:', errorEntry);
// Optional: Send to remote logging service
// this.sendToRemote(errorEntry);
},
getErrors() {
return this.errors;
},
clearErrors() {
this.errors = [];
}
};
// Global error handler
window.addEventListener('error', (event) => {
ErrorLogger.log(event.error, {
type: 'uncaught',
filename: event.filename,
lineno: event.lineno
});
});
10.5 Health Check Endpoint
If you add a service worker:
// Monitor dashboard health
function dashboardHealthCheck() {
return {
status: 'healthy',
lastUpdate: lastUpdateTimestamp,
apiConnected: apiConnectionStatus,
errorCount: ErrorLogger.errors.length,
uptime: performance.now()
};
}
11. Advanced Features 💡
11.1 Mobile App
- Progressive Web App (PWA) support
- Add manifest.json
- Service worker for offline capability
- App install prompt
11.2 Multi-Server Support
- Monitor multiple Unraid servers
- Server selector dropdown
- Aggregate statistics
- Server comparison view
11.3 Custom Widgets
- Drag-and-drop dashboard customization
- User-configurable layout
- Widget library (add/remove sections)
- Save custom layouts
11.4 Scheduled Reports
- Daily/weekly summary emails
- PDF report generation
- Usage trends analysis
- Capacity planning recommendations
Implementation Priority
High Priority (Core Functionality)
- ✅ Security improvements
- Error handling and user feedback
- Code quality improvements (reduce duplication)
- Performance optimizations (Page Visibility API)
Medium Priority (User Experience)
- Docker container enhancements
- Data visualization improvements
- Responsive design enhancements
- Accessibility improvements
Low Priority (Nice to Have)
- Additional features (themes, preferences)
- Testing infrastructure
- Advanced features (PWA, multi-server)
Notes
- All improvements should maintain the cyberpunk aesthetic
- Keep implementation lightweight for Raspberry Pi 3 performance
- Test thoroughly on actual hardware before deployment
- Document all configuration options
- Maintain backward compatibility where possible
Last Updated: 2025-11-22 Status: Living document - update as improvements are implemented