File snapshots-module.js of Package PersistenceOS
/**
* PersistenceOS Snapshots Management Module
* Handles snapshot creation, scheduling, and management functionality
*
* Depends on: core-utils.js, auth-module.js
*/
// =============================================================================
// SNAPSHOTS STATE MANAGEMENT
// =============================================================================
const snapshotsState = {
systemSnapshots: [
{ name: 'system-2023-06-15', type: 'System', date: '2023-06-15 10:30', size: '2.5 GB' },
{ name: 'vm-ubuntu-2023-06-14', type: 'VM', date: '2023-06-14 14:45', size: '4.2 GB' }
],
isRefreshing: false,
refreshInterval: null,
lastUpdate: null
};
// =============================================================================
// SNAPSHOT DATA FUNCTIONS
// =============================================================================
/**
* Refresh snapshots data from API
* @returns {Promise<void>}
*/
async function refreshSnapshots() {
snapshotsState.isRefreshing = true;
console.log('đ Refreshing snapshots data...');
try {
const [systemResponse, storageResponse] = await Promise.all([
PersistenceCore.apiGet('/snapshots/system'),
PersistenceCore.apiGet('/snapshots/storage')
]);
// Combine system and storage snapshots
snapshotsState.systemSnapshots = [
...systemResponse.snapshots.map(s => ({ ...s, category: 'system' })),
...storageResponse.snapshots.map(s => ({ ...s, category: 'storage' }))
];
console.log(`â
Loaded ${snapshotsState.systemSnapshots.length} snapshots`);
PersistenceCore.showNotification('â
Snapshots refreshed successfully', 'success');
snapshotsState.lastUpdate = new Date();
// Trigger custom event for Vue.js reactivity
window.dispatchEvent(new CustomEvent('snapshots-data-updated', {
detail: { snapshots: snapshotsState.systemSnapshots, stats: getSnapshotStats() }
}));
} catch (error) {
console.error('â Error refreshing snapshots:', error);
PersistenceCore.showNotification('â Failed to refresh snapshots', 'error');
} finally {
snapshotsState.isRefreshing = false;
}
}
/**
* Get snapshot statistics
* @returns {object}
*/
function getSnapshotStats() {
const snapshots = snapshotsState.systemSnapshots || [];
return {
total: snapshots.length,
recent: snapshots.filter(s => {
const created = new Date(s.created || s.date);
const now = new Date();
const daysDiff = (now - created) / (1000 * 60 * 60 * 24);
return daysDiff <= 7;
}).length,
scheduled: snapshots.filter(s => s.isScheduled).length,
failed: snapshots.filter(s => s.status === 'failed').length,
system: snapshots.filter(s => s.category === 'system').length,
storage: snapshots.filter(s => s.category === 'storage').length
};
}
// =============================================================================
// SNAPSHOT OPERATIONS
// =============================================================================
/**
* Create new snapshot
* @returns {Promise<void>}
*/
async function createSnapshot() {
console.log('đ¸ Creating new snapshot...');
// Show snapshot creation modal
const snapshotType = await showSnapshotCreationModal();
if (!snapshotType) return;
try {
const response = await PersistenceCore.apiPost('/snapshots/create', {
name: `snapshot-${Date.now()}`,
description: 'Manual snapshot created from UI',
type: snapshotType
});
PersistenceCore.showNotification('â
Snapshot created successfully', 'success');
await refreshSnapshots();
} catch (error) {
console.error('â Error creating snapshot:', error);
// Get detailed error information
const errorMessage = error.message || 'Unknown error';
PersistenceCore.showNotification(`â Snapshot failed: ${errorMessage}`, 'error');
}
}
/**
* Schedule snapshot creation
* @returns {Promise<void>}
*/
async function scheduleSnapshot() {
console.log('â° Opening snapshot scheduling...');
// Show snapshot scheduling modal
const scheduleConfig = await showSnapshotScheduleModal();
if (!scheduleConfig) return;
try {
await PersistenceCore.apiPost('/snapshots/schedule', scheduleConfig);
PersistenceCore.showNotification('â
Snapshot schedule created successfully', 'success');
} catch (error) {
console.error('â Error scheduling snapshot:', error);
PersistenceCore.showNotification('â Failed to schedule snapshot', 'error');
}
}
/**
* Restore from snapshot
* @param {string} snapshotId - Snapshot ID
* @param {string} snapshotName - Snapshot name
* @returns {Promise<void>}
*/
async function restoreSnapshot(snapshotId, snapshotName) {
console.log(`đ Restoring from snapshot: ${snapshotName} (${snapshotId})`);
const confirmed = confirm(`Are you sure you want to restore from snapshot "${snapshotName}"? This will revert the system to the snapshot state.`);
if (!confirmed) return;
try {
PersistenceCore.showNotification(`đ Restoring from snapshot "${snapshotName}"...`, 'info');
await PersistenceCore.apiPost(`/snapshots/${snapshotId}/restore`);
PersistenceCore.showNotification(`â
Restore from "${snapshotName}" completed successfully`, 'success');
// Refresh snapshots after restore
setTimeout(() => refreshSnapshots(), 2000);
} catch (error) {
console.error('â Error restoring snapshot:', error);
PersistenceCore.showNotification(`â Failed to restore from "${snapshotName}"`, 'error');
}
}
/**
* Delete snapshot
* @param {string} snapshotId - Snapshot ID
* @param {string} snapshotName - Snapshot name
* @returns {Promise<void>}
*/
async function deleteSnapshot(snapshotId, snapshotName) {
console.log(`đī¸ Deleting snapshot: ${snapshotName} (${snapshotId})`);
const confirmed = confirm(`Are you sure you want to delete snapshot "${snapshotName}"? This action cannot be undone.`);
if (!confirmed) return;
try {
await PersistenceCore.apiDelete(`/snapshots/${snapshotId}`);
PersistenceCore.showNotification(`â
Snapshot "${snapshotName}" deleted successfully`, 'success');
await refreshSnapshots();
} catch (error) {
console.error('â Error deleting snapshot:', error);
PersistenceCore.showNotification(`â Failed to delete "${snapshotName}"`, 'error');
}
}
/**
* Download snapshot
* @param {string} snapshotId - Snapshot ID
* @param {string} snapshotName - Snapshot name
* @returns {Promise<void>}
*/
async function downloadSnapshot(snapshotId, snapshotName) {
console.log(`đž Downloading snapshot: ${snapshotName} (${snapshotId})`);
try {
PersistenceCore.showNotification(`đž Preparing download for "${snapshotName}"...`, 'info');
// Create download link
const downloadUrl = `/api/snapshots/${snapshotId}/download`;
const link = document.createElement('a');
link.href = downloadUrl;
link.download = `${snapshotName}.tar.gz`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
PersistenceCore.showNotification(`â
Download started for "${snapshotName}"`, 'success');
} catch (error) {
console.error('â Error downloading snapshot:', error);
PersistenceCore.showNotification(`â Failed to download "${snapshotName}"`, 'error');
}
}
// =============================================================================
// SNAPSHOT MODAL FUNCTIONS
// =============================================================================
/**
* Show snapshot creation modal
* @returns {Promise<string|null>}
*/
async function showSnapshotCreationModal() {
return new Promise((resolve) => {
const modalHtml = `
<div id="snapshotCreationModal" class="modal" style="display: block;">
<div class="modal-content" style="max-width: 500px;">
<div class="modal-header">
<h3><i class="fas fa-camera"></i> Create Snapshot</h3>
<button class="close-btn" onclick="closeSnapshotCreationModal(null)">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body">
<form id="snapshotCreationForm">
<div class="form-group">
<label>Snapshot Type:</label>
<select id="snapshotType" required>
<option value="system">System Snapshot</option>
<option value="storage">Storage Snapshot</option>
<option value="full">Full System + Storage</option>
</select>
</div>
<div class="form-group">
<label>Description (Optional):</label>
<textarea id="snapshotDescription" placeholder="Enter snapshot description..."></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button onclick="closeSnapshotCreationModal(null)" class="btn btn-secondary">Cancel</button>
<button onclick="submitSnapshotCreation()" class="btn btn-primary">Create Snapshot</button>
</div>
</div>
</div>
`;
// Add modal to DOM
document.body.insertAdjacentHTML('beforeend', modalHtml);
document.body.classList.add('modal-open');
// Add modal functions
window.closeSnapshotCreationModal = (result) => {
const modal = document.getElementById('snapshotCreationModal');
if (modal) {
modal.remove();
document.body.classList.remove('modal-open');
}
delete window.closeSnapshotCreationModal;
delete window.submitSnapshotCreation;
resolve(result);
};
window.submitSnapshotCreation = () => {
const type = document.getElementById('snapshotType').value;
const description = document.getElementById('snapshotDescription').value;
window.closeSnapshotCreationModal({ type, description });
};
});
}
/**
* Show snapshot schedule modal
* @returns {Promise<object|null>}
*/
async function showSnapshotScheduleModal() {
return new Promise((resolve) => {
const modalHtml = `
<div id="snapshotScheduleModal" class="modal" style="display: block;">
<div class="modal-content" style="max-width: 600px;">
<div class="modal-header">
<h3><i class="fas fa-clock"></i> Schedule Snapshots</h3>
<button class="close-btn" onclick="closeSnapshotScheduleModal(null)">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body">
<form id="snapshotScheduleForm">
<div class="form-group">
<label>Schedule Name:</label>
<input type="text" id="scheduleName" required placeholder="Enter schedule name">
</div>
<div class="form-group">
<label>Frequency:</label>
<select id="scheduleFrequency" required>
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
</select>
</div>
<div class="form-group">
<label>Time:</label>
<input type="time" id="scheduleTime" required value="02:00">
</div>
<div class="form-group">
<label>Retention (days):</label>
<input type="number" id="retentionDays" required value="30" min="1" max="365">
</div>
</form>
</div>
<div class="modal-footer">
<button onclick="closeSnapshotScheduleModal(null)" class="btn btn-secondary">Cancel</button>
<button onclick="submitSnapshotSchedule()" class="btn btn-primary">Create Schedule</button>
</div>
</div>
</div>
`;
// Add modal to DOM
document.body.insertAdjacentHTML('beforeend', modalHtml);
document.body.classList.add('modal-open');
// Add modal functions
window.closeSnapshotScheduleModal = (result) => {
const modal = document.getElementById('snapshotScheduleModal');
if (modal) {
modal.remove();
document.body.classList.remove('modal-open');
}
delete window.closeSnapshotScheduleModal;
delete window.submitSnapshotSchedule;
resolve(result);
};
window.submitSnapshotSchedule = () => {
const name = document.getElementById('scheduleName').value;
const frequency = document.getElementById('scheduleFrequency').value;
const time = document.getElementById('scheduleTime').value;
const retention = parseInt(document.getElementById('retentionDays').value);
if (!name || !frequency || !time || !retention) {
PersistenceCore.showNotification('Please fill in all fields', 'error');
return;
}
window.closeSnapshotScheduleModal({ name, frequency, time, retention });
};
});
}
// =============================================================================
// SNAPSHOT MONITORING
// =============================================================================
/**
* Start snapshot monitoring with automatic refresh
*/
function startSnapshotMonitoring() {
console.log('đ¸ Starting snapshot monitoring...');
// Clear existing interval
if (snapshotsState.refreshInterval) {
clearInterval(snapshotsState.refreshInterval);
}
// Set up refresh interval
snapshotsState.refreshInterval = setInterval(async () => {
if (!snapshotsState.isRefreshing) {
await refreshSnapshots();
}
}, PersistenceCore.config.REFRESH_INTERVALS.SNAPSHOT_DATA);
// Initial refresh
refreshSnapshots();
}
/**
* Stop snapshot monitoring
*/
function stopSnapshotMonitoring() {
console.log('âšī¸ Stopping snapshot monitoring...');
if (snapshotsState.refreshInterval) {
clearInterval(snapshotsState.refreshInterval);
snapshotsState.refreshInterval = null;
}
}
// =============================================================================
// INITIALIZATION
// =============================================================================
/**
* Initialize snapshots module
*/
function initializeSnapshotsModule() {
console.log('đ¸ Initializing snapshots management module...');
// Start monitoring if authenticated
if (PersistenceAuth.state.isAuthenticated) {
startSnapshotMonitoring();
}
// Listen for authentication changes
window.addEventListener('auth-state-changed', (event) => {
if (event.detail.isAuthenticated) {
startSnapshotMonitoring();
} else {
stopSnapshotMonitoring();
}
});
}
// Initialize on DOM ready
document.addEventListener('DOMContentLoaded', initializeSnapshotsModule);
// =============================================================================
// EXPORT FOR MODULE SYSTEM
// =============================================================================
window.PersistenceSnapshots = {
state: snapshotsState,
refreshSnapshots,
getSnapshotStats,
createSnapshot,
scheduleSnapshot,
restoreSnapshot,
deleteSnapshot,
downloadSnapshot,
showSnapshotCreationModal,
showSnapshotScheduleModal,
startSnapshotMonitoring,
stopSnapshotMonitoring,
initializeSnapshotsModule
};
console.log('â
PersistenceOS Snapshots Management Module loaded');