Fix script paths and move assets to public/ folder for Vite build compatibility
This commit is contained in:
669
public/js/core/backup-manager.js
Normal file
669
public/js/core/backup-manager.js
Normal file
@@ -0,0 +1,669 @@
|
||||
/**
|
||||
* BackupManager - Gerenciador de Backup e Restauração
|
||||
* Responsável por criar, gerenciar e restaurar backups do sistema
|
||||
*/
|
||||
class BackupManager {
|
||||
constructor() {
|
||||
this.backupKey = 'acoCalcPro_backups';
|
||||
this.maxBackups = 5;
|
||||
this.autoBackupKey = 'acoCalcPro_auto_backup';
|
||||
this.version = '1.0.0';
|
||||
|
||||
// Inicializar
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicializa o gerenciador de backup
|
||||
*/
|
||||
initialize() {
|
||||
try {
|
||||
// Limpar backups antigos se necessário
|
||||
this.cleanupOldBackups();
|
||||
console.log('🔄 BackupManager inicializado com sucesso');
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao inicializar BackupManager:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cria um backup completo do sistema
|
||||
* @param {string} description - Descrição opcional do backup
|
||||
* @returns {Object} Backup criado
|
||||
*/
|
||||
async createBackup(description = 'Backup manual') {
|
||||
try {
|
||||
console.log('📦 Criando backup do sistema...');
|
||||
|
||||
// Coletar todos os dados necessários
|
||||
const now = Date.now();
|
||||
const backupData = {
|
||||
id: `bkp-${now}`,
|
||||
timestamp: Number(now),
|
||||
createdAt: Number(now),
|
||||
type: description && description.toLowerCase().includes('auto') ? 'automatic' : 'manual',
|
||||
version: this.version,
|
||||
description: description,
|
||||
data: {
|
||||
// Configurações administrativas
|
||||
adminConfig: window.adminConfigManager ? window.adminConfigManager.getConfig() : null,
|
||||
|
||||
// Preferências do usuário
|
||||
userPreferences: this.getUserPreferences(),
|
||||
|
||||
// Cache stats do DataManager
|
||||
cacheStats: window.dataManager ? window.dataManager.getCacheStats() : null,
|
||||
|
||||
// Estado da aplicação
|
||||
appState: this.getAppState(),
|
||||
|
||||
// Dados do State Manager
|
||||
stateData: window.stateManager ? window.stateManager.getAllState() : null,
|
||||
|
||||
// Dados do Cache Manager
|
||||
cacheData: window.cacheManager ? await this.getCacheData() : null
|
||||
}
|
||||
};
|
||||
const sizeBytes = Number(JSON.stringify(backupData).length);
|
||||
backupData.sizeBytes = sizeBytes;
|
||||
backupData.size = this.formatBytes(sizeBytes);
|
||||
|
||||
// Obter backups existentes
|
||||
const backups = this.getBackups();
|
||||
|
||||
// Adicionar novo backup no início
|
||||
backups.unshift(backupData);
|
||||
|
||||
// Limitar número de backups
|
||||
if (backups.length > this.maxBackups) {
|
||||
const removed = backups.splice(this.maxBackups);
|
||||
console.log(`🗑️ ${removed.length} backup(s) antigo(s) removido(s)`);
|
||||
}
|
||||
|
||||
// Salvar no localStorage
|
||||
localStorage.setItem(this.backupKey, JSON.stringify(backups));
|
||||
|
||||
// Atualizar último backup nas configurações
|
||||
if (window.adminConfigManager) {
|
||||
window.adminConfigManager.updateConfig('lastBackup', backupData.timestamp);
|
||||
}
|
||||
|
||||
console.log('✅ Backup criado com sucesso:', new Date(backupData.timestamp).toLocaleString());
|
||||
|
||||
// Notificar sucesso
|
||||
if (window.toastManager) {
|
||||
window.toastManager.success('Backup criado com sucesso!');
|
||||
}
|
||||
|
||||
return backupData;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao criar backup:', error);
|
||||
|
||||
// Notificar erro
|
||||
if (window.toastManager) {
|
||||
window.toastManager.error('Erro ao criar backup: ' + error.message);
|
||||
}
|
||||
|
||||
throw new Error('Falha ao criar backup: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtém todos os backups salvos
|
||||
* @returns {Array} Lista de backups
|
||||
*/
|
||||
getBackups() {
|
||||
try {
|
||||
const saved = localStorage.getItem(this.backupKey);
|
||||
if (saved) {
|
||||
const raw = JSON.parse(saved);
|
||||
if (Array.isArray(raw)) {
|
||||
const normalized = raw.map(b => {
|
||||
const tsRaw = (b && b.timestamp != null) ? b.timestamp : Date.now();
|
||||
let ts;
|
||||
if (typeof tsRaw === 'number') {
|
||||
ts = tsRaw;
|
||||
} else if (typeof tsRaw === 'string') {
|
||||
const parsed = Date.parse(tsRaw);
|
||||
ts = isNaN(parsed) ? Number(tsRaw) : parsed;
|
||||
} else {
|
||||
ts = Date.now();
|
||||
}
|
||||
if (isNaN(ts)) ts = Date.now();
|
||||
const id = (b && b.id) ? b.id : `bkp-${ts}`;
|
||||
const createdAtRaw = (b && b.createdAt != null) ? b.createdAt : ts;
|
||||
let createdAt;
|
||||
if (typeof createdAtRaw === 'number') {
|
||||
createdAt = createdAtRaw;
|
||||
} else if (typeof createdAtRaw === 'string') {
|
||||
const parsedCA = Date.parse(createdAtRaw);
|
||||
createdAt = isNaN(parsedCA) ? Number(createdAtRaw) : parsedCA;
|
||||
} else {
|
||||
createdAt = ts;
|
||||
}
|
||||
if (isNaN(createdAt)) createdAt = ts;
|
||||
const type = b.type || 'manual';
|
||||
const version = b.version || this.version;
|
||||
const description = b.description || '';
|
||||
const data = b.data || {};
|
||||
let sizeBytes = Number(b.sizeBytes);
|
||||
if (isNaN(sizeBytes) || !sizeBytes) {
|
||||
sizeBytes = JSON.stringify(b).length;
|
||||
}
|
||||
const size = b.size || this.formatBytes(sizeBytes);
|
||||
return { id, timestamp: ts, createdAt, type, version, description, data, sizeBytes, size };
|
||||
});
|
||||
return normalized.filter(backup => this.isValidBackup(backup));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Erro ao carregar backups:', error);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Restaura um backup específico
|
||||
* @param {Object|string} backup - Backup a restaurar ou timestamp
|
||||
* @returns {boolean} Sucesso da restauração
|
||||
*/
|
||||
async restoreBackup(backup) {
|
||||
try {
|
||||
let backupToRestore;
|
||||
|
||||
// Se for timestamp, encontrar o backup correspondente
|
||||
if (typeof backup === 'string' || typeof backup === 'number') {
|
||||
const backups = this.getBackups();
|
||||
if (typeof backup === 'string' && isNaN(parseInt(backup))) {
|
||||
backupToRestore = backups.find(b => b.id === backup);
|
||||
} else {
|
||||
const timestamp = typeof backup === 'string' ? parseInt(backup) : backup;
|
||||
backupToRestore = backups.find(b => b.timestamp === timestamp);
|
||||
}
|
||||
|
||||
if (!backupToRestore) {
|
||||
throw new Error('Backup não encontrado');
|
||||
}
|
||||
} else {
|
||||
backupToRestore = backup;
|
||||
}
|
||||
|
||||
console.log('📤 Restaurando backup de:', new Date(backupToRestore.createdAt || backupToRestore.timestamp).toLocaleString());
|
||||
|
||||
// Confirmar com usuário se for restauração manual
|
||||
const isConfirmed = await this.confirmRestoration(backupToRestore);
|
||||
if (!isConfirmed) {
|
||||
console.log('❌ Restauração cancelada pelo usuário');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Criar backup antes de restaurar (precaução)
|
||||
await this.createBackup('Backup pré-restauração');
|
||||
|
||||
// Restaurar configurações administrativas
|
||||
if (backupToRestore.data.adminConfig && window.adminConfigManager) {
|
||||
window.adminConfigManager.saveConfig(backupToRestore.data.adminConfig);
|
||||
console.log('✅ Configurações administrativas restauradas');
|
||||
}
|
||||
|
||||
// Restaurar preferências do usuário
|
||||
if (backupToRestore.data.userPreferences) {
|
||||
this.setUserPreferences(backupToRestore.data.userPreferences);
|
||||
console.log('✅ Preferências do usuário restauradas');
|
||||
}
|
||||
|
||||
// Restaurar estado da aplicação
|
||||
if (backupToRestore.data.appState) {
|
||||
this.setAppState(backupToRestore.data.appState);
|
||||
console.log('✅ Estado da aplicação restaurado');
|
||||
}
|
||||
|
||||
// Restaurar dados do State Manager
|
||||
if (backupToRestore.data.stateData && window.stateManager) {
|
||||
window.stateManager.setAllState(backupToRestore.data.stateData);
|
||||
console.log('✅ Dados do State Manager restaurados');
|
||||
}
|
||||
|
||||
// Notificar sucesso
|
||||
if (window.toastManager) {
|
||||
window.toastManager.success('Backup restaurado com sucesso!');
|
||||
}
|
||||
|
||||
console.log('✅ Backup restaurado com sucesso');
|
||||
|
||||
// Disparar evento de restauração
|
||||
this.notifyRestorationComplete(backupToRestore);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao restaurar backup:', error);
|
||||
|
||||
// Notificar erro
|
||||
if (window.toastManager) {
|
||||
window.toastManager.error('Erro ao restaurar backup: ' + error.message);
|
||||
}
|
||||
|
||||
throw new Error('Falha ao restaurar backup: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove um backup específico
|
||||
* @param {string|number} timestamp - Timestamp do backup a remover
|
||||
* @returns {boolean} Sucesso da remoção
|
||||
*/
|
||||
removeBackup(idOrTimestamp) {
|
||||
try {
|
||||
const backups = this.getBackups();
|
||||
let filteredBackups;
|
||||
if (typeof idOrTimestamp === 'string' && isNaN(parseInt(idOrTimestamp))) {
|
||||
filteredBackups = backups.filter(backup => backup.id !== idOrTimestamp);
|
||||
} else {
|
||||
const timestampNum = typeof idOrTimestamp === 'string' ? parseInt(idOrTimestamp) : idOrTimestamp;
|
||||
filteredBackups = backups.filter(backup => backup.timestamp !== timestampNum);
|
||||
}
|
||||
|
||||
if (filteredBackups.length === backups.length) {
|
||||
throw new Error('Backup não encontrado');
|
||||
}
|
||||
|
||||
localStorage.setItem(this.backupKey, JSON.stringify(filteredBackups));
|
||||
|
||||
console.log('🗑️ Backup removido');
|
||||
|
||||
if (window.toastManager) {
|
||||
window.toastManager.info('Backup removido com sucesso');
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao remover backup:', error);
|
||||
throw new Error('Falha ao remover backup: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Limpa todos os backups
|
||||
* @returns {boolean} Sucesso da limpeza
|
||||
*/
|
||||
clearAllBackups() {
|
||||
try {
|
||||
localStorage.removeItem(this.backupKey);
|
||||
console.log('🗑️ Todos os backups foram removidos');
|
||||
|
||||
if (window.toastManager) {
|
||||
window.toastManager.info('Todos os backups foram removidos');
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao limpar backups:', error);
|
||||
throw new Error('Falha ao limpar backups: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exporta um backup como arquivo JSON
|
||||
* @param {Object|string} backup - Backup a exportar ou timestamp
|
||||
*/
|
||||
exportBackup(backup) {
|
||||
try {
|
||||
let backupToExport;
|
||||
|
||||
// Se for timestamp, encontrar o backup correspondente
|
||||
if (typeof backup === 'string' || typeof backup === 'number') {
|
||||
const timestamp = typeof backup === 'string' ? parseInt(backup) : backup;
|
||||
const backups = this.getBackups();
|
||||
backupToExport = backups.find(b => b.timestamp === timestamp);
|
||||
|
||||
if (!backupToExport) {
|
||||
throw new Error('Backup não encontrado');
|
||||
}
|
||||
} else {
|
||||
backupToExport = backup;
|
||||
}
|
||||
|
||||
const jsonString = JSON.stringify(backupToExport, null, 2);
|
||||
const blob = new Blob([jsonString], { type: 'application/json' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `steelbase-backup-${backupToExport.timestamp}.json`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
console.log('📤 Backup exportado com sucesso');
|
||||
|
||||
if (window.toastManager) {
|
||||
window.toastManager.success('Backup exportado com sucesso!');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao exportar backup:', error);
|
||||
|
||||
if (window.toastManager) {
|
||||
window.toastManager.error('Erro ao exportar backup: ' + error.message);
|
||||
}
|
||||
|
||||
throw new Error('Falha ao exportar backup: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Importa um backup de arquivo JSON
|
||||
* @param {File} file - Arquivo JSON a importar
|
||||
* @returns {Object} Backup importado
|
||||
*/
|
||||
async importBackup(file) {
|
||||
try {
|
||||
console.log('📥 Importando backup de arquivo...');
|
||||
|
||||
const text = await file.text();
|
||||
const backup = JSON.parse(text);
|
||||
|
||||
if (!this.isValidBackup(backup)) {
|
||||
throw new Error('Arquivo de backup inválido');
|
||||
}
|
||||
|
||||
// Adicionar aos backups existentes
|
||||
const backups = this.getBackups();
|
||||
backups.unshift(backup);
|
||||
|
||||
// Limitar número de backups
|
||||
if (backups.length > this.maxBackups) {
|
||||
backups.splice(this.maxBackups);
|
||||
}
|
||||
|
||||
localStorage.setItem(this.backupKey, JSON.stringify(backups));
|
||||
|
||||
console.log('✅ Backup importado com sucesso');
|
||||
|
||||
if (window.toastManager) {
|
||||
window.toastManager.success('Backup importado com sucesso!');
|
||||
}
|
||||
|
||||
return backup;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao importar backup:', error);
|
||||
|
||||
if (window.toastManager) {
|
||||
window.toastManager.error('Erro ao importar backup: ' + error.message);
|
||||
}
|
||||
|
||||
throw new Error('Falha ao importar backup: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configura backup automático
|
||||
* @param {boolean} enabled - Se deve estar ativado
|
||||
* @param {number} intervalHours - Intervalo em horas
|
||||
*/
|
||||
setupAutoBackup(enabled, intervalHours = 24) {
|
||||
try {
|
||||
const autoBackupConfig = {
|
||||
enabled: enabled,
|
||||
intervalHours: intervalHours,
|
||||
lastBackup: null
|
||||
};
|
||||
|
||||
localStorage.setItem(this.autoBackupKey, JSON.stringify(autoBackupConfig));
|
||||
|
||||
if (enabled) {
|
||||
console.log(`🔄 Backup automático configurado: a cada ${intervalHours} horas`);
|
||||
this.startAutoBackupTimer();
|
||||
} else {
|
||||
console.log('⏹️ Backup automático desativado');
|
||||
this.stopAutoBackupTimer();
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao configurar backup automático:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicia o timer de backup automático
|
||||
*/
|
||||
startAutoBackupTimer() {
|
||||
// Implementar timer de backup automático
|
||||
// Isso seria chamado na inicialização da aplicação
|
||||
console.log('⏰ Timer de backup automático iniciado');
|
||||
}
|
||||
|
||||
/**
|
||||
* Para o timer de backup automático
|
||||
*/
|
||||
stopAutoBackupTimer() {
|
||||
console.log('⏹️ Timer de backup automático parado');
|
||||
}
|
||||
|
||||
/**
|
||||
* Valida se um backup é válido
|
||||
* @param {Object} backup - Backup a validar
|
||||
* @returns {boolean} Se é válido
|
||||
*/
|
||||
isValidBackup(backup) {
|
||||
if (!backup || typeof backup !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verificar campos obrigatórios
|
||||
const requiredFields = ['timestamp', 'version', 'data'];
|
||||
for (const field of requiredFields) {
|
||||
if (!backup[field]) {
|
||||
console.warn(`⚠️ Campo obrigatório ausente no backup: ${field}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verificar estrutura de dados
|
||||
if (typeof backup.timestamp !== 'number' ||
|
||||
typeof backup.version !== 'string' ||
|
||||
typeof backup.data !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limpa backups antigos (mantém apenas os mais recentes)
|
||||
*/
|
||||
cleanupOldBackups() {
|
||||
try {
|
||||
const backups = this.getBackups();
|
||||
|
||||
if (backups.length > this.maxBackups) {
|
||||
const keptBackups = backups.slice(0, this.maxBackups);
|
||||
localStorage.setItem(this.backupKey, JSON.stringify(keptBackups));
|
||||
|
||||
console.log(`🗑️ ${backups.length - keptBackups.length} backup(s) antigo(s) removido(s)`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Erro ao limpar backups antigos:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtém preferências do usuário
|
||||
* @returns {Object} Preferências
|
||||
*/
|
||||
getUserPreferences() {
|
||||
try {
|
||||
const saved = localStorage.getItem('acoCalcPreferences');
|
||||
return saved ? JSON.parse(saved) : null;
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Erro ao obter preferências do usuário:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define preferências do usuário
|
||||
* @param {Object} preferences - Preferências a definir
|
||||
*/
|
||||
setUserPreferences(preferences) {
|
||||
try {
|
||||
localStorage.setItem('acoCalcPreferences', JSON.stringify(preferences));
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Erro ao definir preferências do usuário:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtém estado da aplicação
|
||||
* @returns {Object} Estado da aplicação
|
||||
*/
|
||||
getAppState() {
|
||||
try {
|
||||
// Coletar estado relevante da aplicação
|
||||
const state = {
|
||||
currentSection: window.currentSection || null,
|
||||
lastUpdate: window.lastUpdate || null,
|
||||
userSession: window.userSession || null
|
||||
};
|
||||
|
||||
return state;
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Erro ao obter estado da aplicação:', error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define estado da aplicação
|
||||
* @param {Object} state - Estado a definir
|
||||
*/
|
||||
setAppState(state) {
|
||||
try {
|
||||
if (state.currentSection) window.currentSection = state.currentSection;
|
||||
if (state.lastUpdate) window.lastUpdate = state.lastUpdate;
|
||||
if (state.userSession) window.userSession = state.userSession;
|
||||
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Erro ao definir estado da aplicação:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtém dados do cache
|
||||
* @returns {Promise<Object>} Dados do cache
|
||||
*/
|
||||
async getCacheData() {
|
||||
try {
|
||||
if (!window.cacheManager) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Obter dados relevantes do cache
|
||||
const cacheData = {
|
||||
metadata: window.cacheManager.getMetadata ? window.cacheManager.getMetadata() : null,
|
||||
stats: window.cacheManager.getStats ? window.cacheManager.getStats() : null
|
||||
};
|
||||
|
||||
return cacheData;
|
||||
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Erro ao obter dados do cache:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirma restauração com o usuário
|
||||
* @param {Object} backup - Backup a restaurar
|
||||
* @returns {Promise<boolean>} Confirmação
|
||||
*/
|
||||
async confirmRestoration(backup) {
|
||||
// Em ambiente real, isso seria um modal/dialog
|
||||
// Por enquanto, retorna true para testes
|
||||
return new Promise((resolve) => {
|
||||
console.log(`🔄 Confirmando restauração do backup: ${new Date(backup.timestamp).toLocaleString()}`);
|
||||
|
||||
// Simular confirmação após 1 segundo
|
||||
setTimeout(() => {
|
||||
resolve(true);
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifica conclusão da restauração
|
||||
* @param {Object} backup - Backup restaurado
|
||||
*/
|
||||
notifyRestorationComplete(backup) {
|
||||
const event = new CustomEvent('backupRestored', {
|
||||
detail: { backup: backup },
|
||||
bubbles: true
|
||||
});
|
||||
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtém estatísticas dos backups
|
||||
* @returns {Object} Estatísticas
|
||||
*/
|
||||
getStats() {
|
||||
const backups = this.getBackups();
|
||||
const totalSize = backups.reduce((total, backup) => {
|
||||
return total + JSON.stringify(backup).length;
|
||||
}, 0);
|
||||
|
||||
return {
|
||||
totalBackups: backups.length,
|
||||
oldestBackup: backups.length > 0 ? backups[backups.length - 1].timestamp : null,
|
||||
newestBackup: backups.length > 0 ? backups[0].timestamp : null,
|
||||
totalSize: totalSize,
|
||||
maxBackups: this.maxBackups
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorna um backup específico por id ou timestamp
|
||||
* @param {string|number} idOrTimestamp
|
||||
* @returns {Object|null}
|
||||
*/
|
||||
getBackup(idOrTimestamp) {
|
||||
const backups = this.getBackups();
|
||||
if (typeof idOrTimestamp === 'string' && isNaN(parseInt(idOrTimestamp))) {
|
||||
return backups.find(b => b.id === idOrTimestamp) || null;
|
||||
}
|
||||
const ts = typeof idOrTimestamp === 'string' ? Number(parseInt(idOrTimestamp)) : Number(idOrTimestamp);
|
||||
return backups.find(b => b.timestamp === ts) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formata bytes em string legível (KB, MB, GB)
|
||||
* @param {number} bytes
|
||||
* @returns {string}
|
||||
*/
|
||||
formatBytes(bytes) {
|
||||
if (!bytes || bytes < 1024) return `${bytes || 0} B`;
|
||||
const units = ['KB', 'MB', 'GB'];
|
||||
let value = bytes / 1024;
|
||||
let idx = 0;
|
||||
while (value >= 1024 && idx < units.length - 1) {
|
||||
value /= 1024;
|
||||
idx++;
|
||||
}
|
||||
return `${value.toFixed(1)} ${units[idx]}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Criar instância global
|
||||
window.backupManager = new BackupManager();
|
||||
|
||||
console.log('🔄 BackupManager inicializado com sucesso');
|
||||
Reference in New Issue
Block a user