196 lines
6.3 KiB
JavaScript
196 lines
6.3 KiB
JavaScript
'use strict';
|
||
'require view';
|
||
'require dom';
|
||
'require ui';
|
||
'require network-modes.api as api';
|
||
|
||
return view.extend({
|
||
title: _('Network Modes'),
|
||
|
||
load: function() {
|
||
return api.getAllData();
|
||
},
|
||
|
||
handleModeSwitch: function(mode) {
|
||
var self = this;
|
||
ui.showModal(_('Switch Mode'), [
|
||
E('p', {}, _('Are you sure you want to switch to ') + mode + _(' mode?')),
|
||
E('p', { 'class': 'nm-alert nm-alert-warning' }, [
|
||
E('span', { 'class': 'nm-alert-icon' }, '⚠️'),
|
||
E('div', {}, [
|
||
E('div', { 'class': 'nm-alert-title' }, _('Warning')),
|
||
E('div', { 'class': 'nm-alert-text' }, _('This will change network configuration. A backup will be created.'))
|
||
])
|
||
]),
|
||
E('div', { 'class': 'right' }, [
|
||
E('button', {
|
||
'class': 'btn',
|
||
'click': ui.hideModal
|
||
}, _('Cancel')),
|
||
' ',
|
||
E('button', {
|
||
'class': 'btn cbi-button-positive',
|
||
'click': function() {
|
||
ui.hideModal();
|
||
return api.applyMode(mode).then(function(result) {
|
||
if (result.success) {
|
||
ui.addNotification(null, E('p', {}, result.message), 'success');
|
||
window.location.reload();
|
||
} else {
|
||
ui.addNotification(null, E('p', {}, 'Error: ' + result.error), 'error');
|
||
}
|
||
});
|
||
}
|
||
}, _('Switch Mode'))
|
||
])
|
||
]);
|
||
},
|
||
|
||
render: function(data) {
|
||
var self = this;
|
||
var status = data.status || {};
|
||
var modesData = (data.modes || {}).modes || [];
|
||
var currentMode = status.current_mode || 'router';
|
||
|
||
var modeInfos = {
|
||
sniffer: api.getModeInfo('sniffer'),
|
||
accesspoint: api.getModeInfo('accesspoint'),
|
||
relay: api.getModeInfo('relay'),
|
||
router: api.getModeInfo('router')
|
||
};
|
||
|
||
var currentModeInfo = modeInfos[currentMode];
|
||
|
||
var view = E('div', { 'class': 'network-modes-dashboard' }, [
|
||
// Header
|
||
E('div', { 'class': 'nm-header' }, [
|
||
E('div', { 'class': 'nm-logo' }, [
|
||
E('div', { 'class': 'nm-logo-icon' }, '⚙️'),
|
||
E('div', { 'class': 'nm-logo-text' }, ['Network ', E('span', {}, 'Modes')])
|
||
]),
|
||
E('div', { 'class': 'nm-mode-badge ' + currentMode }, [
|
||
E('span', { 'class': 'nm-mode-dot' }),
|
||
currentModeInfo ? currentModeInfo.name : currentMode
|
||
])
|
||
]),
|
||
|
||
// Status info
|
||
E('div', { 'class': 'nm-alert nm-alert-info' }, [
|
||
E('span', { 'class': 'nm-alert-icon' }, 'ℹ️'),
|
||
E('div', {}, [
|
||
E('div', { 'class': 'nm-alert-title' }, 'Current Mode: ' + (currentModeInfo ? currentModeInfo.name : currentMode)),
|
||
E('div', { 'class': 'nm-alert-text' },
|
||
'Last changed: ' + (status.last_change || 'Never') + ' • Uptime: ' + api.formatUptime(status.uptime))
|
||
])
|
||
]),
|
||
|
||
// Mode Selection Grid
|
||
E('div', { 'class': 'nm-modes-grid' },
|
||
Object.keys(modeInfos).map(function(modeId) {
|
||
var info = modeInfos[modeId];
|
||
var isActive = modeId === currentMode;
|
||
|
||
return E('div', {
|
||
'class': 'nm-mode-card ' + modeId + (isActive ? ' active' : ''),
|
||
'click': function() {
|
||
if (!isActive) {
|
||
self.handleModeSwitch(modeId);
|
||
}
|
||
}
|
||
}, [
|
||
isActive ? E('div', { 'class': 'nm-mode-active-indicator' }, 'Active') : '',
|
||
E('div', { 'class': 'nm-mode-header' }, [
|
||
E('div', { 'class': 'nm-mode-icon' }, info.icon),
|
||
E('div', { 'class': 'nm-mode-title' }, [
|
||
E('h3', {}, info.name),
|
||
E('p', {}, modeId.charAt(0).toUpperCase() + modeId.slice(1) + ' Mode')
|
||
])
|
||
]),
|
||
E('div', { 'class': 'nm-mode-description' }, info.description),
|
||
E('div', { 'class': 'nm-mode-features' },
|
||
info.features.map(function(f) {
|
||
return E('span', { 'class': 'nm-mode-feature' }, [
|
||
E('span', { 'class': 'nm-mode-feature-icon' }, '✓'),
|
||
f
|
||
]);
|
||
})
|
||
)
|
||
]);
|
||
})
|
||
),
|
||
|
||
// Interfaces Status
|
||
E('div', { 'class': 'nm-card' }, [
|
||
E('div', { 'class': 'nm-card-header' }, [
|
||
E('div', { 'class': 'nm-card-title' }, [
|
||
E('span', { 'class': 'nm-card-title-icon' }, '🔌'),
|
||
'Network Interfaces'
|
||
]),
|
||
E('div', { 'class': 'nm-card-badge' }, (status.interfaces || []).length + ' interfaces')
|
||
]),
|
||
E('div', { 'class': 'nm-card-body' }, [
|
||
E('div', { 'class': 'nm-interfaces-grid' },
|
||
(status.interfaces || []).map(function(iface) {
|
||
var icon = '🔌';
|
||
if (iface.name.startsWith('wlan') || iface.name.startsWith('wl')) icon = '📶';
|
||
else if (iface.name.startsWith('wg')) icon = '🔐';
|
||
else if (iface.name.startsWith('br')) icon = '🌉';
|
||
else if (iface.name.startsWith('eth')) icon = '🔗';
|
||
|
||
return E('div', { 'class': 'nm-interface-card' }, [
|
||
E('div', { 'class': 'nm-interface-icon' }, icon),
|
||
E('div', { 'class': 'nm-interface-info' }, [
|
||
E('div', { 'class': 'nm-interface-name' }, iface.name),
|
||
E('div', { 'class': 'nm-interface-ip' }, iface.ip || 'No IP')
|
||
]),
|
||
E('div', { 'class': 'nm-interface-status ' + iface.state })
|
||
]);
|
||
})
|
||
)
|
||
])
|
||
]),
|
||
|
||
// Services Status
|
||
E('div', { 'class': 'nm-card' }, [
|
||
E('div', { 'class': 'nm-card-header' }, [
|
||
E('div', { 'class': 'nm-card-title' }, [
|
||
E('span', { 'class': 'nm-card-title-icon' }, '🔧'),
|
||
'Services Status'
|
||
])
|
||
]),
|
||
E('div', { 'class': 'nm-card-body' }, [
|
||
E('div', { 'class': 'nm-interfaces-grid' },
|
||
[
|
||
{ name: 'Firewall', key: 'firewall', icon: '🛡️' },
|
||
{ name: 'DHCP/DNS', key: 'dnsmasq', icon: '📡' },
|
||
{ name: 'Netifyd', key: 'netifyd', icon: '🔍' },
|
||
{ name: 'Nginx', key: 'nginx', icon: '🌐' },
|
||
{ name: 'Squid', key: 'squid', icon: '🦑' }
|
||
].map(function(svc) {
|
||
var running = status.services && status.services[svc.key];
|
||
return E('div', { 'class': 'nm-interface-card' }, [
|
||
E('div', { 'class': 'nm-interface-icon' }, svc.icon),
|
||
E('div', { 'class': 'nm-interface-info' }, [
|
||
E('div', { 'class': 'nm-interface-name' }, svc.name),
|
||
E('div', { 'class': 'nm-interface-ip' }, running ? 'Running' : 'Stopped')
|
||
]),
|
||
E('div', { 'class': 'nm-interface-status ' + (running ? 'up' : 'down') })
|
||
]);
|
||
})
|
||
)
|
||
])
|
||
])
|
||
]);
|
||
|
||
// Include CSS
|
||
var cssLink = E('link', { 'rel': 'stylesheet', 'href': L.resource('network-modes/dashboard.css') });
|
||
document.head.appendChild(cssLink);
|
||
|
||
return view;
|
||
},
|
||
|
||
handleSaveApply: null,
|
||
handleSave: null,
|
||
handleReset: null
|
||
});
|