From 55eb4d0e4ad484dc41f22b9c74fba12a83222658 Mon Sep 17 00:00:00 2001 From: Miguel Fuertes Date: Tue, 7 Oct 2025 21:44:23 +0200 Subject: [PATCH] working! --- .../resources/view/usb-gadget/config.js | 44 +++++----- .../resources/view/usb-gadget/overview.js | 83 ++++++++++++++----- .../share/rpcd/acl.d/luci-app-usb-gadget.json | 5 +- 3 files changed, 84 insertions(+), 48 deletions(-) diff --git a/packages/luci-app-usb-gadget/htdocs/luci-static/resources/view/usb-gadget/config.js b/packages/luci-app-usb-gadget/htdocs/luci-static/resources/view/usb-gadget/config.js index 0d839f3..c5ad4b2 100644 --- a/packages/luci-app-usb-gadget/htdocs/luci-static/resources/view/usb-gadget/config.js +++ b/packages/luci-app-usb-gadget/htdocs/luci-static/resources/view/usb-gadget/config.js @@ -3,6 +3,7 @@ 'require form'; 'require uci'; 'require fs'; +'require ui'; return view.extend({ load: function() { @@ -27,8 +28,9 @@ return view.extend({ s.anonymous = true; s.addremove = false; - o = s.option(form.Flag, 'enabled', _('Enable USB Gadget'), - _('Disable to use USB port in host mode')); + o = s.option(form.Flag, 'enabled', _('Enable USB Gadget')); + o.description = _('Disable to use USB port in host mode.') + '
' + + 'May disconnect USB. Ensure alternative access.'; o.rmempty = false; o = s.option(form.Value, 'gadget_name', _('Gadget Name')); @@ -71,15 +73,10 @@ return view.extend({ _('RNDIS (Windows Ethernet)'), _('Windows-compatible USB ethernet. Works on all Windows versions.')); - o = s.option(form.Flag, 'enabled', _('Enable RNDIS')); + o = s.option(form.Flag, 'enabled', _('Enable RNDIS'), + _('Plug-and-play on Windows. Automatically adds to LAN bridge.')); o.rmempty = false; - o = s.option(form.DummyValue, '_desc', _('Description')); - o.rawhtml = true; - o.cfgvalue = function() { - return _('Plug-and-play on Windows. Automatically adds to LAN bridge.'); - }; - // ================================================================= // ECM // ================================================================= @@ -87,15 +84,10 @@ return view.extend({ _('ECM (macOS/Linux Ethernet)'), _('For macOS ≤10.14 and Linux. Do not enable with NCM.')); - o = s.option(form.Flag, 'enabled', _('Enable ECM')); + o = s.option(form.Flag, 'enabled', _('Enable ECM'), + _('CDC Ethernet for macOS and Linux. Disable RNDIS when using.')); o.rmempty = false; - o = s.option(form.DummyValue, '_desc', _('Description')); - o.rawhtml = true; - o.cfgvalue = function() { - return _('CDC Ethernet for macOS and Linux. Disable RNDIS when using.'); - }; - // ================================================================= // NCM // ================================================================= @@ -103,15 +95,10 @@ return view.extend({ _('NCM (Modern Ethernet)'), _('Best performance. For Windows 11+, macOS ≥10.15, Linux.')); - o = s.option(form.Flag, 'enabled', _('Enable NCM')); + o = s.option(form.Flag, 'enabled', _('Enable NCM'), + _('Modern high-speed USB ethernet. Best choice for new systems.')); o.rmempty = false; - o = s.option(form.DummyValue, '_desc', _('Description')); - o.rawhtml = true; - o.cfgvalue = function() { - return _('Modern high-speed USB ethernet. Best choice for new systems.'); - }; - // ================================================================= // ACM Serial // ================================================================= @@ -138,7 +125,7 @@ return view.extend({ // ================================================================= s = m.section(form.NamedSection, 'ums', 'function', _('Mass Storage'), - _('Expose storage image as USB drive.')); + _('Expose storage image as USB drive. Does not provide access to the device.')); o = s.option(form.Flag, 'enabled', _('Enable Mass Storage')); o.rmempty = false; @@ -161,7 +148,14 @@ return view.extend({ handleSaveApply: function(ev, mode) { return this.super('handleSaveApply', [ev, mode]).then(function() { - return fs.exec('/etc/init.d/usb-gadget', ['restart']); + ui.addNotification(null, + E('p', _('Configuration saved. Restarting USB Gadget service...')), + 'info'); + return fs.exec('/etc/init.d/usb-gadget', ['restart']).then(function() { + ui.addNotification(null, + E('p', _('USB Gadget service restarted successfully')), + 'info'); + }); }); } }); diff --git a/packages/luci-app-usb-gadget/htdocs/luci-static/resources/view/usb-gadget/overview.js b/packages/luci-app-usb-gadget/htdocs/luci-static/resources/view/usb-gadget/overview.js index 823171a..4e0ed22 100644 --- a/packages/luci-app-usb-gadget/htdocs/luci-static/resources/view/usb-gadget/overview.js +++ b/packages/luci-app-usb-gadget/htdocs/luci-static/resources/view/usb-gadget/overview.js @@ -4,19 +4,20 @@ 'require ui'; 'require uci'; 'require poll'; +'require network'; return view.extend({ load: function() { return Promise.all([ uci.load('usbgadget'), - L.resolveDefault(fs.exec('/etc/init.d/usb-gadget', ['status']), null), - L.resolveDefault(fs.list('/sys/class/udc'), []) + L.resolveDefault(fs.list('/sys/class/udc'), []), + network.getDevices() ]); }, render: function(data) { - var status_result = data[1]; - var udc_devices = data[2]; + var udc_devices = data[1]; + var net_devices = data[2]; var enabled = uci.get('usbgadget', 'usb', 'enabled'); var gadget_name = uci.get('usbgadget', 'usb', 'gadget_name') || 'g1'; @@ -31,6 +32,21 @@ return view.extend({ } }); + // Buscar interfaces USB y crear elementos con puntitos de colores + var usb_interface_elements = []; + net_devices.forEach(function(dev) { + var name = dev.getName(); + if (name && name.match(/^usb\d+$/)) { + var isUp = dev.isUp(); + usb_interface_elements.push( + E('span', { 'style': 'margin-right: 10px;' }, [ + E('span', { 'style': 'color:' + (isUp ? 'green' : 'red') }, '● '), + name + ]) + ); + } + }); + // Construir array de filas de la tabla var tableRows = [ E('tr', { 'class': 'tr' }, [ @@ -61,12 +77,20 @@ return view.extend({ // Añadir fila UDC solo si hay dispositivos if (udc_devices.length > 0) { - tableRows.splice(3, 0, E('tr', { 'class': 'tr' }, [ + tableRows.push(E('tr', { 'class': 'tr' }, [ E('td', { 'class': 'td left' }, E('strong', {}, _('USB Controller'))), E('td', { 'class': 'td left' }, udc_devices.map(function(d) { return d.name; }).join(', ')) ])); } + // Añadir interfaces de red USB con puntitos + if (usb_interface_elements.length > 0) { + tableRows.push(E('tr', { 'class': 'tr' }, [ + E('td', { 'class': 'td left' }, E('strong', {}, _('Network Interfaces'))), + E('td', { 'class': 'td left', 'id': 'usb_interfaces' }, usb_interface_elements) + ])); + } + var viewElements = [ E('h2', {}, _('USB Gadget Status')), E('div', { 'class': 'cbi-map-descr' }, @@ -77,11 +101,11 @@ return view.extend({ E('table', { 'class': 'table' }, tableRows) ]), + // Botón alineado a la derecha E('div', { 'class': 'cbi-section' }, [ E('div', { 'class': 'cbi-section-node' }, [ E('div', { 'class': 'cbi-value' }, [ - E('label', { 'class': 'cbi-value-title' }, _('Service Control')), - E('div', { 'class': 'cbi-value-field' }, [ + E('div', { 'class': 'cbi-value-field', 'style': 'text-align: right;' }, [ E('button', { 'class': 'cbi-button cbi-button-apply', 'click': function() { @@ -110,23 +134,14 @@ return view.extend({ ]) ]; - // Añadir output detallado solo si existe - if (status_result && status_result.stdout) { - viewElements.push( - E('div', { 'class': 'cbi-section' }, [ - E('h3', {}, _('Detailed Output')), - E('pre', { - 'style': 'background:#f9f9f9; padding:10px; overflow:auto; max-height:400px; border:1px solid #ddd' - }, status_result.stdout) - ]) - ); - } - var view = E('div', { 'class': 'cbi-map' }, viewElements); // Polling cada 5 segundos poll.add(function() { - return uci.load('usbgadget').then(function() { + return Promise.all([ + uci.load('usbgadget'), + network.getDevices() + ]).then(function(pollData) { var newEnabled = uci.get('usbgadget', 'usb', 'enabled'); var statusEl = document.getElementById('status_value'); if (statusEl) { @@ -137,6 +152,34 @@ return view.extend({ E('span', { 'style': 'color:red' }, '● ' + _('Disabled (Host Mode)')) ); } + + // Actualizar interfaces USB con puntitos + var ifacesEl = document.getElementById('usb_interfaces'); + if (ifacesEl) { + var newDevices = pollData[1]; + var newUsbElements = []; + newDevices.forEach(function(dev) { + var name = dev.getName(); + if (name && name.match(/^usb\d+$/)) { + var isUp = dev.isUp(); + newUsbElements.push( + E('span', { 'style': 'margin-right: 10px;' }, [ + E('span', { 'style': 'color:' + (isUp ? 'green' : 'red') }, '● '), + name + ]) + ); + } + }); + + ifacesEl.innerHTML = ''; + if (newUsbElements.length > 0) { + newUsbElements.forEach(function(el) { + ifacesEl.appendChild(el); + }); + } else { + ifacesEl.appendChild(E('em', {}, _('None'))); + } + } }); }, 5); diff --git a/packages/luci-app-usb-gadget/root/usr/share/rpcd/acl.d/luci-app-usb-gadget.json b/packages/luci-app-usb-gadget/root/usr/share/rpcd/acl.d/luci-app-usb-gadget.json index 56e3c1f..b6ea502 100644 --- a/packages/luci-app-usb-gadget/root/usr/share/rpcd/acl.d/luci-app-usb-gadget.json +++ b/packages/luci-app-usb-gadget/root/usr/share/rpcd/acl.d/luci-app-usb-gadget.json @@ -26,11 +26,10 @@ ] }, "file": { - "/etc/config/usbgadget": ["write"] + "/etc/config/usbgadget": ["write"], + "/etc/init.d/usb-gadget": ["exec"] }, "cgi-io": [ - "upload", - "download", "exec" ] }