File core-utils.js of Package PersistenceOS

/**
 * PersistenceOS Core Utilities Module
 * Shared utilities, common functions, and base configurations
 * 
 * This module provides the foundation for all other dashboard modules
 * and handles common functionality like notifications, API calls, and utilities.
 */

// =============================================================================
// CORE CONFIGURATION
// =============================================================================

const PERSISTENCE_CONFIG = {
    API_BASE_URL: '/api',
    NOTIFICATION_TIMEOUT: 3000,
    REFRESH_INTERVALS: {
        SYSTEM_STATS: 30000,
        VM_DATA: 15000,
        NETWORK_DATA: 20000,
        STORAGE_DATA: 25000,
        SNAPSHOT_DATA: 30000
    },
    UI_CONSTANTS: {
        SIDEBAR_COLLAPSED_KEY: 'persistence_sidebar_collapsed',
        ACTIVE_SECTION_KEY: 'persistence_active_section'
    }
};

// =============================================================================
// NOTIFICATION SYSTEM
// =============================================================================

/**
 * Show notification to user
 * @param {string} message - Message to display
 * @param {string} type - Notification type: 'success', 'error', 'info', 'warning'
 */
function showNotification(message, type = 'info') {
    const colors = {
        success: '#28a745',
        error: '#dc3545',
        info: '#17a2b8',
        warning: '#ffc107'
    };

    const notification = document.createElement('div');
    notification.style.cssText = `
        position: fixed;
        top: 20px;
        left: 50%;
        transform: translateX(-50%);
        background: ${colors[type]};
        color: white;
        padding: 12px 20px;
        border-radius: 6px;
        z-index: 10001;
        font-family: Arial, sans-serif;
        box-shadow: 0 4px 12px rgba(0,0,0,0.3);
        animation: slideInDown 0.3s ease-out;
    `;
    notification.textContent = message;

    // Add animation styles
    if (!document.getElementById('notification-styles')) {
        const style = document.createElement('style');
        style.id = 'notification-styles';
        style.textContent = `
            @keyframes slideInDown {
                from { opacity: 0; transform: translateX(-50%) translateY(-20px); }
                to { opacity: 1; transform: translateX(-50%) translateY(0); }
            }
        `;
        document.head.appendChild(style);
    }

    document.body.appendChild(notification);

    setTimeout(() => {
        notification.style.animation = 'slideInDown 0.3s ease-out reverse';
        setTimeout(() => notification.remove(), 300);
    }, PERSISTENCE_CONFIG.NOTIFICATION_TIMEOUT);
}

// =============================================================================
// API UTILITIES
// =============================================================================

/**
 * Make authenticated API request
 * @param {string} endpoint - API endpoint
 * @param {object} options - Fetch options
 * @returns {Promise<Response>}
 */
async function makeApiRequest(endpoint, options = {}) {
    const token = localStorage.getItem('access_token');
    const defaultHeaders = {
        'Content-Type': 'application/json',
        ...(token && { 'Authorization': `Bearer ${token}` })
    };

    const config = {
        ...options,
        headers: {
            ...defaultHeaders,
            ...options.headers
        }
    };

    const url = endpoint.startsWith('http') ? endpoint : `${PERSISTENCE_CONFIG.API_BASE_URL}${endpoint}`;
    
    try {
        const response = await fetch(url, config);
        
        // Handle authentication errors
        if (response.status === 401) {
            console.warn('Authentication failed, redirecting to login');
            localStorage.removeItem('access_token');
            window.location.href = '/login.html';
            throw new Error('Authentication required');
        }
        
        return response;
    } catch (error) {
        console.error(`API request failed for ${endpoint}:`, error);
        throw error;
    }
}

/**
 * Make GET request to API
 * @param {string} endpoint - API endpoint
 * @returns {Promise<any>}
 */
async function apiGet(endpoint) {
    const response = await makeApiRequest(endpoint);
    if (!response.ok) {
        throw new Error(`GET ${endpoint} failed: ${response.status} ${response.statusText}`);
    }
    return await response.json();
}

/**
 * Make POST request to API
 * @param {string} endpoint - API endpoint
 * @param {any} data - Request body data
 * @returns {Promise<any>}
 */
async function apiPost(endpoint, data) {
    const response = await makeApiRequest(endpoint, {
        method: 'POST',
        body: JSON.stringify(data)
    });
    if (!response.ok) {
        throw new Error(`POST ${endpoint} failed: ${response.status} ${response.statusText}`);
    }
    return await response.json();
}

/**
 * Make DELETE request to API
 * @param {string} endpoint - API endpoint
 * @returns {Promise<any>}
 */
async function apiDelete(endpoint) {
    const response = await makeApiRequest(endpoint, {
        method: 'DELETE'
    });
    if (!response.ok) {
        throw new Error(`DELETE ${endpoint} failed: ${response.status} ${response.statusText}`);
    }
    return await response.json();
}

// =============================================================================
// UTILITY FUNCTIONS
// =============================================================================

/**
 * Format bytes to human readable format
 * @param {number} bytes - Number of bytes
 * @param {number} decimals - Number of decimal places
 * @returns {string}
 */
function formatBytes(bytes, decimals = 2) {
    if (bytes === 0) return '0 Bytes';
    
    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
    
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    
    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}

/**
 * Get color based on usage percentage
 * @param {number} percentage - Usage percentage (0-100)
 * @returns {string} - CSS color value
 */
function getUsageColor(percentage) {
    if (percentage < 50) return '#28a745'; // Green
    if (percentage < 80) return '#ffc107'; // Yellow
    return '#dc3545'; // Red
}

/**
 * Debounce function calls
 * @param {Function} func - Function to debounce
 * @param {number} wait - Wait time in milliseconds
 * @returns {Function}
 */
function debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
        const later = () => {
            clearTimeout(timeout);
            func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

/**
 * Format timestamp to readable date
 * @param {string|Date} timestamp - Timestamp to format
 * @returns {string}
 */
function formatTimestamp(timestamp) {
    const date = new Date(timestamp);
    return date.toLocaleString();
}

/**
 * Validate required fields in an object
 * @param {object} obj - Object to validate
 * @param {string[]} requiredFields - Array of required field names
 * @returns {boolean}
 */
function validateRequiredFields(obj, requiredFields) {
    return requiredFields.every(field => 
        obj.hasOwnProperty(field) && 
        obj[field] !== null && 
        obj[field] !== undefined && 
        obj[field] !== ''
    );
}

// =============================================================================
// LOCAL STORAGE UTILITIES
// =============================================================================

/**
 * Get item from localStorage with JSON parsing
 * @param {string} key - Storage key
 * @param {any} defaultValue - Default value if key doesn't exist
 * @returns {any}
 */
function getStorageItem(key, defaultValue = null) {
    try {
        const item = localStorage.getItem(key);
        return item ? JSON.parse(item) : defaultValue;
    } catch (error) {
        console.warn(`Failed to parse localStorage item ${key}:`, error);
        return defaultValue;
    }
}

/**
 * Set item in localStorage with JSON stringification
 * @param {string} key - Storage key
 * @param {any} value - Value to store
 */
function setStorageItem(key, value) {
    try {
        localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
        console.error(`Failed to set localStorage item ${key}:`, error);
    }
}

// =============================================================================
// EXPORT FOR MODULE SYSTEM
// =============================================================================

// Export all utilities for use by other modules
window.PersistenceCore = {
    config: PERSISTENCE_CONFIG,
    showNotification,
    makeApiRequest,
    apiGet,
    apiPost,
    apiDelete,
    formatBytes,
    getUsageColor,
    debounce,
    formatTimestamp,
    validateRequiredFields,
    getStorageItem,
    setStorageItem
};

console.log('✅ PersistenceOS Core Utilities Module loaded');
openSUSE Build Service is sponsored by