Files
unraid-dashboard/IMPROVEMENTS.md
Michael Simard 8396fbcf6f Add Docker deployment for Unraid
- 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>
2026-01-22 09:43:02 -06:00

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.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

// 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 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:

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)

  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)

  1. Docker container enhancements
  2. Data visualization improvements
  3. Responsive design enhancements
  4. Accessibility improvements

Low Priority (Nice to Have)

  1. Additional features (themes, preferences)
  2. Testing infrastructure
  3. 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