secubox-openwrt/luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/backup.js
CyberMind-FR aad081e841 chore: Release v0.4.2 - Menu reorganization and CSS enhancements
This release focuses on improved menu structure, enhanced CSS styling
across all modules, and documentation cleanup.

## Menu & Navigation (2 modules)
- Reorganized SecuBox menu with new "Network & Connectivity" category
- Moved Network Modes from top-level to Network submenu
- New menu path: admin/secubox/network/modes

## Network Modes Enhancements (14 files)
- Enhanced all mode views: Overview, Wizard, Router, Multi-WAN, Double NAT,
  Access Point, Relay, VPN Relay, Travel, Sniffer, Settings
- Improved dashboard.css styling
- Updated API and helpers for better functionality

## System Hub Improvements (11 files)
- Added dedicated CSS files for Backup and Health views
- Enhanced styling: common.css, components.css, logs.css, services.css
- Updated views: backup.js, components.js, health.js, logs.js, services.js
- Removed deprecated settings.js view

## SecuBox Dashboard Updates (4 files)
- Refined dashboard.css and modules.css styling
- Enhanced dashboard.js and modules.js functionality

## Theme Updates (1 file)
- Improved navigation.css component styling

## Documentation Cleanup (15 files deleted)
- Removed obsolete documentation from docs/ directory
- Migrated documentation to DOCS/ (uppercase) structure
- Cleaned up archive files and outdated guides

## Configuration (1 file)
- Updated Claude settings for new permissions

Summary:
- 50 files changed
- 3 modules enhanced (network-modes, system-hub, secubox)
- 15 documentation files cleaned up
- 2 new CSS files added
- Menu structure reorganized

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-28 19:07:44 +01:00

220 lines
6.7 KiB
JavaScript

'use strict';
'require view';
'require ui';
'require system-hub/api as API';
'require system-hub/theme as Theme';
Theme.init();
return view.extend({
load: function() {
return Promise.resolve();
},
render: function() {
var container = E('div', { 'class': 'system-hub-dashboard sh-backup-view' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('system-hub/dashboard.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('system-hub/backup.css') }),
this.renderHero(),
E('div', { 'class': 'sh-backup-grid' }, [
this.renderBackupCard(),
this.renderRestoreCard(),
this.renderMaintenanceCard()
])
]);
return container;
},
renderHero: function() {
return E('section', { 'class': 'sh-backup-hero' }, [
E('div', {}, [
E('div', { 'class': 'sh-hero-eyebrow' }, _('Configuration Safety')),
E('h1', {}, _('Backup & Restore Control Center')),
E('p', {}, _('Create encrypted snapshots of the complete configuration (network, firewall, packages) and restore them in one click.'))
]),
E('div', { 'class': 'sh-hero-badges' }, [
E('div', { 'class': 'sh-hero-badge' }, [
E('span', { 'class': 'label' }, _('Recommended cadence')),
E('strong', {}, _('Weekly'))
]),
E('div', { 'class': 'sh-hero-badge' }, [
E('span', { 'class': 'label' }, _('Includes')),
E('strong', {}, _('Configs + package list'))
])
])
]);
},
renderBackupCard: function() {
return E('section', { 'class': 'sh-card' }, [
E('div', { 'class': 'sh-card-header' }, [
E('div', { 'class': 'sh-card-title' }, [
E('span', { 'class': 'sh-card-title-icon' }, '💾'),
_('Create Instant Backup')
]),
E('span', { 'class': 'sh-card-badge' }, _('Manual'))
]),
E('div', { 'class': 'sh-card-body' }, [
E('p', { 'class': 'sh-text-muted' }, _('Exports full /etc configuration and package list. Store the archive in a safe place.')),
E('button', {
'class': 'sh-btn sh-btn-primary',
'type': 'button',
'click': ui.createHandlerFn(this, 'createBackup')
}, '⬇ ' + _('Download Backup'))
])
]);
},
renderRestoreCard: function() {
return E('section', { 'class': 'sh-card' }, [
E('div', { 'class': 'sh-card-header' }, [
E('div', { 'class': 'sh-card-title' }, [
E('span', { 'class': 'sh-card-title-icon' }, '📤'),
_('Restore From Archive')
]),
E('span', { 'class': 'sh-card-badge sh-badge-warning' }, _('Requires reboot'))
]),
E('div', { 'class': 'sh-card-body' }, [
E('p', { 'class': 'sh-text-muted' }, _('Upload a previously saved .tar.gz backup. Current settings will be overwritten.')),
E('label', { 'class': 'sh-upload' }, [
E('span', {}, '📁 ' + _('Select backup file')),
E('input', {
'type': 'file',
'accept': '.tar.gz,.tgz',
'id': 'backup-file'
})
]),
E('div', { 'class': 'sh-action-row' }, [
E('button', {
'class': 'sh-btn sh-btn-warning',
'type': 'button',
'click': ui.createHandlerFn(this, 'restoreBackup')
}, '↩ ' + _('Restore Backup'))
])
])
]);
},
renderMaintenanceCard: function() {
return E('section', { 'class': 'sh-card' }, [
E('div', { 'class': 'sh-card-header' }, [
E('div', { 'class': 'sh-card-title' }, [
E('span', { 'class': 'sh-card-title-icon' }, '⚙️'),
_('System Maintenance')
])
]),
E('div', { 'class': 'sh-card-body' }, [
E('p', { 'class': 'sh-text-muted' }, _('A reboot is recommended after restoring a backup to ensure all services reload with the new configuration.')),
E('button', {
'class': 'sh-btn sh-btn-danger',
'type': 'button',
'click': ui.createHandlerFn(this, 'rebootSystem')
}, '⏻ ' + _('Reboot System'))
])
]);
},
createBackup: function() {
ui.showModal(_('Creating backup…'), [
E('p', { 'class': 'spinning' }, _('Building archive and collecting package list...'))
]);
return API.backupConfig().then(function(result) {
ui.hideModal();
if (!result || result.success === false) {
ui.addNotification(null, E('p', {}, (result && result.message) || _('Backup failed')), 'error');
return;
}
var binary = atob(result.data || '');
var buffer = new Uint8Array(binary.length);
for (var i = 0; i < binary.length; i++) {
buffer[i] = binary.charCodeAt(i);
}
var blob = new Blob([buffer], { type: 'application/gzip' });
var url = window.URL.createObjectURL(blob);
var link = document.createElement('a');
link.href = url;
link.download = result.filename || 'backup.tar.gz';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
ui.addNotification(null, E('p', {}, _('Backup created: ') + (result.filename || 'backup')), 'info');
}).catch(function(err) {
ui.hideModal();
ui.addNotification(null, E('p', {}, err.message || err), 'error');
});
},
restoreBackup: function() {
var fileInput = document.getElementById('backup-file');
var file = fileInput && fileInput.files && fileInput.files[0];
if (!file) {
ui.addNotification(null, E('p', {}, _('Select a backup archive first')), 'warning');
return;
}
if (!confirm(_('Restore configuration from backup? This will overwrite all settings.'))) {
return;
}
ui.showModal(_('Restoring backup…'), [
E('p', { 'class': 'spinning' }, _('Uploading archive and applying configuration...'))
]);
var reader = new FileReader();
reader.onload = function(ev) {
var arrayBuffer = ev.target.result;
var bytes = new Uint8Array(arrayBuffer);
var binary = '';
for (var i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
var encoded = btoa(binary);
API.restoreConfig(encoded).then(function(result) {
ui.hideModal();
if (result && result.success) {
ui.addNotification(null, E('p', {}, _('Backup restored. Please reboot to apply changes.')), 'info');
} else {
ui.addNotification(null, E('p', {}, (result && result.message) || _('Restore failed')), 'error');
}
}).catch(function(err) {
ui.hideModal();
ui.addNotification(null, E('p', {}, err.message || err), 'error');
});
};
reader.onerror = function() {
ui.hideModal();
ui.addNotification(null, E('p', {}, _('Could not read backup file')), 'error');
};
reader.readAsArrayBuffer(file);
},
rebootSystem: function() {
if (!confirm(_('Reboot the device now? All connections will be interrupted.'))) {
return;
}
ui.showModal(_('System rebooting'), [
E('p', {}, _('Device is restarting. The interface will be unreachable for ~60 seconds.'))
]);
API.reboot().catch(function(err) {
ui.hideModal();
ui.addNotification(null, E('p', {}, err.message || err), 'error');
});
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});