- 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>
681 lines
18 KiB
Markdown
681 lines
18 KiB
Markdown
# 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.js` file for API credentials
|
|
- ✅ Added `config.js` to `.gitignore`
|
|
- ✅ Created `config.example.js` template
|
|
- ✅ Updated `script.js` to 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
|
|
```javascript
|
|
// 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
|
|
```javascript
|
|
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 `requestAnimationFrame` for 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**:
|
|
```javascript
|
|
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
|
|
```javascript
|
|
// 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
|
|
```javascript
|
|
/**
|
|
* 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
|
|
```javascript
|
|
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
|
|
```css
|
|
/* 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
|
|
```html
|
|
<!-- 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
|
|
```html
|
|
<!-- 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
|
|
```javascript
|
|
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**:
|
|
```javascript
|
|
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
|
|
```javascript
|
|
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**:
|
|
```javascript
|
|
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)
|
|
|
|
```javascript
|
|
// 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**:
|
|
```javascript
|
|
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
|
|
```javascript
|
|
// 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**:
|
|
```javascript
|
|
// 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**:
|
|
```javascript
|
|
// 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)
|
|
1. ✅ Security improvements
|
|
2. Error handling and user feedback
|
|
3. Code quality improvements (reduce duplication)
|
|
4. Performance optimizations (Page Visibility API)
|
|
|
|
### Medium Priority (User Experience)
|
|
5. Docker container enhancements
|
|
6. Data visualization improvements
|
|
7. Responsive design enhancements
|
|
8. Accessibility improvements
|
|
|
|
### Low Priority (Nice to Have)
|
|
9. Additional features (themes, preferences)
|
|
10. Testing infrastructure
|
|
11. 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
|