secubox-openwrt/package/secubox/luci-app-traffic-shaper/htdocs/luci-static/resources/view/traffic-shaper/presets.js
CyberMind-FR 1bbd345cee refactor(luci): Mass KissTheme UI rework across all LuCI apps
Convert 90+ LuCI view files from legacy cbi-button-* classes to
KissTheme kiss-btn-* classes for consistent dark theme styling.

Pattern conversions applied:
- cbi-button-positive → kiss-btn-green
- cbi-button-negative/remove → kiss-btn-red
- cbi-button-apply → kiss-btn-cyan
- cbi-button-action → kiss-btn-blue
- cbi-button (plain) → kiss-btn

Also replaced hardcoded colors (#080, #c00, #888, etc.) with
CSS variables (--kiss-green, --kiss-red, --kiss-muted, etc.)
for proper dark theme compatibility.

Apps updated include: ai-gateway, auth-guardian, bandwidth-manager,
cloner, config-advisor, crowdsec-dashboard, dns-provider, exposure,
glances, haproxy, hexojs, iot-guard, jellyfin, ksm-manager,
mac-guardian, magicmirror2, master-link, meshname-dns, metablogizer,
metabolizer, mqtt-bridge, netdata-dashboard, picobrew, routes-status,
secubox-admin, secubox-mirror, secubox-p2p, secubox-security-threats,
service-registry, simplex, streamlit, system-hub, tor-shield,
traffic-shaper, vhost-manager, vortex-dns, vortex-firewall,
webradio, wireguard-dashboard, zigbee2mqtt, zkp, and more.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-12 11:09:34 +01:00

195 lines
6.4 KiB
JavaScript

'use strict';
'require view';
'require secubox-theme/theme as Theme';
'require secubox/kiss-theme as KissTheme';
'require ui';
'require dom';
'require traffic-shaper/api as API';
return view.extend({
load: function() {
return API.listPresets();
},
render: function(data) {
var presets = data.presets || [];
var container = E('div', { 'class': 'traffic-shaper-dashboard' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox-theme/secubox-theme.css') }),
E('h2', {}, _('Traffic Shaping Presets')),
E('div', { 'class': 'cbi-section' }, [
E('p', {}, _('Apply pre-configured traffic shaping profiles optimized for common use cases. Applying a preset will replace your current configuration.')),
E('p', { 'style': 'background: #fff3cd; padding: 0.75em; border-left: 4px solid #ffc107;' }, [
E('strong', {}, _('Warning:')),
' ',
_('Applying a preset will overwrite all existing traffic classes and rules.')
])
]),
E('div', { 'class': 'ts-preset-grid' },
presets.length > 0 ?
presets.map(L.bind(this.renderPresetCard, this)) :
this.renderDefaultPresets()
)
]);
return KissTheme.wrap([container], 'admin/network/traffic-shaper/presets');
},
renderPresetCard: function(preset) {
return E('div', { 'class': 'ts-preset-card' }, [
E('div', { 'class': 'ts-preset-title' }, preset.name || preset.id),
E('div', { 'class': 'ts-preset-description' }, preset.description || ''),
E('div', { 'style': 'margin: 1em 0; padding: 1em; background: #f8f9fa; border-radius: 4px;' }, [
E('strong', {}, _('Configuration:')),
E('ul', { 'style': 'margin: 0.5em 0 0 0; padding-left: 1.5em;' },
(preset.classes || []).map(function(cls) {
return E('li', {}, '%s: %s (priority %s)'.format(
cls.name,
cls.rate + ' → ' + cls.ceil,
cls.priority
));
})
)
]),
E('div', { 'class': 'ts-preset-apply' }, [
E('button', {
'class': 'ts-btn ts-btn-success',
'click': L.bind(function(ev) {
this.handleApplyPreset(ev, preset.id);
}, this)
}, _('Apply This Preset'))
])
]);
},
renderDefaultPresets: function() {
// Fallback presets if backend doesn't provide them
var defaultPresets = [
{
id: 'gaming',
name: _('Gaming & Low-Latency'),
description: _('Optimized for online gaming, VoIP, and real-time applications. Prioritizes UDP and low-latency traffic.'),
classes: [
{ name: _('Gaming/VoIP'), priority: '1', rate: '5mbit', ceil: '50mbit' },
{ name: _('Interactive'), priority: '3', rate: '10mbit', ceil: '80mbit' },
{ name: _('Streaming'), priority: '5', rate: '8mbit', ceil: '60mbit' },
{ name: _('Bulk Downloads'), priority: '8', rate: '2mbit', ceil: '30mbit' }
]
},
{
id: 'streaming',
name: _('Video Streaming'),
description: _('Optimized for video streaming services like Netflix, YouTube, and video conferencing. Ensures smooth playback.'),
classes: [
{ name: _('Video Conference'), priority: '2', rate: '10mbit', ceil: '60mbit' },
{ name: _('Video Streaming'), priority: '3', rate: '15mbit', ceil: '80mbit' },
{ name: _('Web Browsing'), priority: '5', rate: '5mbit', ceil: '50mbit' },
{ name: _('Background'), priority: '7', rate: '2mbit', ceil: '30mbit' }
]
},
{
id: 'work_from_home',
name: _('Work From Home'),
description: _('Balanced configuration for remote work. Prioritizes video calls, VPN, and web applications while allowing downloads.'),
classes: [
{ name: _('Video Calls'), priority: '1', rate: '8mbit', ceil: '50mbit' },
{ name: _('VPN Traffic'), priority: '2', rate: '10mbit', ceil: '60mbit' },
{ name: _('Web/Email'), priority: '4', rate: '8mbit', ceil: '70mbit' },
{ name: _('Downloads'), priority: '6', rate: '5mbit', ceil: '40mbit' }
]
},
{
id: 'balanced',
name: _('Balanced (Default)'),
description: _('General-purpose configuration that works well for most households. Equal priority for common applications.'),
classes: [
{ name: _('High Priority'), priority: '2', rate: '10mbit', ceil: '60mbit' },
{ name: _('Normal Traffic'), priority: '5', rate: '15mbit', ceil: '80mbit' },
{ name: _('Bulk Transfer'), priority: '7', rate: '5mbit', ceil: '50mbit' }
]
}
];
return defaultPresets.map(L.bind(this.renderPresetCard, this));
},
handleApplyPreset: function(ev, presetId) {
var btn = ev.target;
ui.showModal(_('Apply Preset'), [
E('p', {}, _('Are you sure you want to apply this preset? This will:')),
E('ul', {}, [
E('li', {}, _('Delete all existing traffic classes')),
E('li', {}, _('Delete all existing classification rules')),
E('li', {}, _('Create new classes from the preset')),
E('li', {}, _('Apply the new configuration immediately'))
]),
E('p', { 'style': 'font-weight: bold; color: #dc3545;' },
_('This action cannot be undone!')),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'kiss-btn',
'click': ui.hideModal
}, _('Cancel')),
' ',
E('button', {
'class': 'kiss-btn kiss-btn-blue',
'click': L.bind(function() {
ui.hideModal();
this.applyPreset(presetId, btn);
}, this)
}, _('Yes, Apply Preset'))
])
]);
},
applyPreset: function(presetId, btn) {
var originalText = btn.textContent;
btn.disabled = true;
btn.textContent = _('Applying...');
ui.showModal(_('Applying Preset'), [
E('p', { 'class': 'spinning' }, _('Applying preset configuration...'))
], null, null, { 'spinning': true });
API.applyPreset(presetId).then(L.bind(function(result) {
ui.hideModal();
if (result.success) {
ui.addNotification(null,
E('p', _('Preset applied successfully! Traffic shaping has been reconfigured.')),
'info'
);
// Redirect to overview after 2 seconds
setTimeout(function() {
window.location.href = L.url('admin/network/traffic-shaper/overview');
}, 2000);
} else {
ui.addNotification(null,
E('p', _('Failed to apply preset: %s').format(result.message || _('Unknown error'))),
'error'
);
btn.disabled = false;
btn.textContent = originalText;
}
}, this)).catch(L.bind(function(err) {
ui.hideModal();
ui.addNotification(null,
E('p', _('Error applying preset: %s').format(err.message || err)),
'error'
);
btn.disabled = false;
btn.textContent = originalText;
}, this));
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});