From dac2f4011597be2b8a1c6abe5efcabfe8d9d583e Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20H=C3=A4rdeman?= Date: Wed, 15 Oct 2025 19:02:30 +0200 Subject: [PATCH] luci-mod-network: organize "leases" tab in dhcp/dns views MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Delete the tab from dns.js, sort the options that belong to it in dhcp.js. Signed-off-by: David Härdeman --- .../resources/view/network/dhcp.js | 368 +++++++++--------- .../luci-static/resources/view/network/dns.js | 257 +----------- 2 files changed, 186 insertions(+), 439 deletions(-) diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js index ff5b1609c3..3d7bf024af 100644 --- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js +++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js @@ -398,6 +398,15 @@ return view.extend({ s.tab('relay', _('Relay')); s.tab('pxe_tftp', _('PXE/TFTP')); + var ipaddrs = {}; + + Object.keys(hosts).forEach(function(mac) { + var addrs = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4); + + for (var i = 0; i < addrs.length; i++) + ipaddrs[addrs[i]] = hosts[mac].name || mac; + }); + // Begin general s.taboption('general', form.Flag, 'authoritative', _('Authoritative'), @@ -489,6 +498,182 @@ return view.extend({ _('File to store DHCP lease information.')); // End files + // Begin leases + o = s.taboption('leases', form.SectionValue, '__leases__', form.GridSection, 'host', null, + _('Static leases are used to assign fixed IP addresses and symbolic hostnames to DHCP clients. They are also required for non-dynamic interface configurations where only hosts with a corresponding lease are served.') + '

' + + _('Use the Add Button to add a new lease entry. The MAC address identifies the host, the IPv4 address specifies the fixed address to use, and the Hostname is assigned as a symbolic name to the requesting host. The optional Lease time can be used to set non-standard host-specific lease time, e.g. 12h, 3d or infinite.') + '

' + + _('The tag construct filters which host directives are used; more than one tag can be provided, in this case the request must match all of them. Tagged directives are used in preference to untagged ones. Note that one of mac, duid or hostname still needs to be specified (can be a wildcard).')); + + ss = o.subsection; + + ss.addremove = true; + ss.anonymous = true; + ss.sortable = true; + ss.nodescriptions = true; + ss.max_cols = 8; + ss.modaltitle = _('Edit static lease'); + + so = ss.option(form.Value, 'name', + _('Hostname'), + _('Optional hostname to assign')); + so.validate = validateHostname; + so.rmempty = true; + so.write = function(section, value) { + uci.set('dhcp', section, 'name', value); + uci.set('dhcp', section, 'dns', '1'); + }; + so.remove = function(section) { + uci.unset('dhcp', section, 'name'); + uci.unset('dhcp', section, 'dns'); + }; + + //this can be a .DynamicList or a .Value with a widget and dnsmasq handles multimac OK. + so = ss.option(form.DynamicList, 'mac', + _('MAC address(es)'), + _('The hardware address(es) of this entry/host.') + '

' + + _('In DHCPv4, it is possible to include more than one mac address. This allows an IP address to be associated with multiple macaddrs, and dnsmasq abandons a DHCP lease to one of the macaddrs when another asks for a lease. It only works reliably if only one of the macaddrs is active at any time.')); + //As a special case, in DHCPv4, it is possible to include more than one hardware address. eg: --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2 This allows an IP address to be associated with multiple hardware addresses, and gives dnsmasq permission to abandon a DHCP lease to one of the hardware addresses when another one asks for a lease + so.rmempty = true; + so.cfgvalue = function(section) { + var macs = uci.get('dhcp', section, 'mac'); + var formattedMacs; + var hint, entry; + + if(!Array.isArray(macs)){ + formattedMacs = expandAndFormatMAC(L.toArray(macs)); + } else { + formattedMacs = expandAndFormatMAC(macs); + } + + if (!macdata) { + return formattedMacs; + } + + + if (Array.isArray(formattedMacs)){ + for (let mac in formattedMacs) { + entry = formattedMacs[mac].toLowerCase(); + if (macdata[entry]) { + hint = macdata[entry].vendor ? macdata[entry].vendor : null; + formattedMacs[mac] += ` (${hint})`; + } + } + return formattedMacs; + } + + if (formattedMacs) { + entry = formattedMacs[0].toLowerCase(); + hint = macdata[entry].vendor ? macdata[entry].vendor : null; + formattedMacs[0] += ` (${hint})`; + } + return formattedMacs; + }; + //removed jows renderwidget function which hindered multi-mac entry + so.validate = validateMACAddr.bind(so, pools); + Object.keys(hosts).forEach(function(mac) { + var vendor; + var lower_mac = mac.toLowerCase(); + if (macdata) + vendor = macdata[lower_mac] ? macdata[lower_mac].vendor : null; + const hint = vendor || hosts[mac].name || L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0]; + so.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac); + }); + + so = ss.option(form.Value, 'ip', _('IPv4 address'), _('The IP address to be used for this host, or ignore to ignore any DHCP request from this host.')); + so.value('ignore', _('Ignore')); + so.datatype = 'or(ip4addr,"ignore")'; + so.validate = function(section, value) { + var m = this.section.formvalue(section, 'mac'), + n = this.section.formvalue(section, 'name'); + + if ((m && !m.length > 0) && !n) + return _('One of hostname or MAC address must be specified!'); + + if (!value || value == 'ignore') + return true; + + var leases = uci.sections('dhcp', 'host'); + + for (var i = 0; i < leases.length; i++) + if (leases[i]['.name'] != section && leases[i].ip == value) + return _('The IP address %h is already used by another static lease').format(value); + + for (var i = 0; i < pools.length; i++) { + var net_mask = calculateNetwork(value, pools[i].netmask); + + if (net_mask && net_mask[0] == pools[i].network) + return true; + } + + return _('The IP address is outside of any DHCP pool address range'); + }; + + L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) { + so.value(ipv4, ipaddrs[ipv4] ? '%s (%s)'.format(ipv4, ipaddrs[ipv4]) : ipv4); + }); + + so = ss.option(form.Value, 'leasetime', + _('Lease time'), + _('Host-specific lease time, e.g. 5m, 3h, 7d.')); + so.rmempty = true; + so.value('5m', _('5m (5 minutes)')); + so.value('3h', _('3h (3 hours)')); + so.value('12h', _('12h (12 hours - default)')); + so.value('7d', _('7d (7 days)')); + so.value('infinite', _('infinite (lease does not expire)')); + + so = ss.option(form.Value, 'duid', + _('DUID'), + _('The DHCPv6-DUID (DHCP unique identifier) of this host.')); + so.datatype = 'and(rangelength(20,36),hexstring)'; + Object.keys(duids).forEach(function(duid) { + so.value(duid, '%s (%s)'.format(duid, duids[duid].hostname || duids[duid].macaddr || duids[duid].ip6addr || '?')); + }); + + so = ss.option(form.Value, 'hostid', + _('IPv6-Suffix (hex)'), + _('The IPv6 interface identifier (address suffix) as hexadecimal number (max. 16 chars).')); + so.datatype = 'and(rangelength(0,16),hexstring)'; + + so = ss.option(form.DynamicList, 'tag', + _('Tag'), + _('Assign new, freeform tags to this entry.')); + + so = ss.option(form.DynamicList, 'match_tag', + _('Match Tag'), + _('When a host matches an entry then the special tag %s is set. Use %s to match all known hosts.').format('known', 'known') + '

' + + _('Ignore requests from unknown machines using %s.').format('!known') + '

' + + _('If a host matches an entry which cannot be used because it specifies an address on a different subnet, the tag %s is set.').format('known-othernet')); + so.value('known', _('known')); + so.value('!known', _('!known (not known)')); + so.value('known-othernet', _('known-othernet (on different subnet)')); + so.optional = true; + + so = ss.option(form.Value, 'instance', + _('Instance'), + _('Dnsmasq instance to which this DHCP host section is bound. If unspecified, the section is valid for all dnsmasq instances.')); + so.optional = true; + + Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) { + var [name, display_str] = generateDnsmasqInstanceEntry(val); + so.value(name, display_str); + }); + + + so = ss.option(form.Flag, 'broadcast', + _('Broadcast'), + _('Force broadcast DHCP response.')); + + so = ss.option(form.Flag, 'dns', + _('Forward/reverse DNS'), + _('Add static forward and reverse DNS entries for this host.')); + + o = s.taboption('leases', CBILeaseStatus, '__status__'); + + if (has_dhcpv6) + o = s.taboption('leases', CBILease6Status, '__status6__'); + // End leases + o = s.taboption('relay', form.SectionValue, '__relays__', form.TableSection, 'relay', null, _('Relay DHCP requests elsewhere. OK: v4↔v4, v6↔v6. Not OK: v4↔v6, v6↔v4.') + '
' + _('Note: you may also need a DHCP Proxy (currently unavailable) when specifying a non-standard Relay To port(addr#port).') @@ -686,15 +871,6 @@ return view.extend({ so.value('39', _('40: LoongArch 64-bit UEFI boot from HTTP')); so.value('41', _('41: ARM rpiboot')); - var ipaddrs = {}; - - Object.keys(hosts).forEach(function(mac) { - var addrs = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4); - - for (var i = 0; i < addrs.length; i++) - ipaddrs[addrs[i]] = hosts[mac].name || mac; - }); - o = s.taboption('ipsets', form.SectionValue, '__ipsets__', form.GridSection, 'ipset', null, _('List of IP sets to populate with the IPs of DNS lookup results of the FQDNs also specified here.') + '
' + _('The netfilter components below are only regarded when running fw4.')); @@ -735,180 +911,6 @@ return view.extend({ so.value('ip', _('IPv4')); so.value('ip6', _('IPv6')); - o = s.taboption('leases', form.SectionValue, '__leases__', form.GridSection, 'host', null, - _('Static leases are used to assign fixed IP addresses and symbolic hostnames to DHCP clients. They are also required for non-dynamic interface configurations where only hosts with a corresponding lease are served.') + '

' + - _('Use the Add Button to add a new lease entry. The MAC address identifies the host, the IPv4 address specifies the fixed address to use, and the Hostname is assigned as a symbolic name to the requesting host. The optional Lease time can be used to set non-standard host-specific lease time, e.g. 12h, 3d or infinite.') + '

' + - _('The tag construct filters which host directives are used; more than one tag can be provided, in this case the request must match all of them. Tagged directives are used in preference to untagged ones. Note that one of mac, duid or hostname still needs to be specified (can be a wildcard).')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.nodescriptions = true; - ss.max_cols = 8; - ss.modaltitle = _('Edit static lease'); - - so = ss.option(form.Value, 'name', - _('Hostname'), - _('Optional hostname to assign')); - so.validate = validateHostname; - so.rmempty = true; - so.write = function(section, value) { - uci.set('dhcp', section, 'name', value); - uci.set('dhcp', section, 'dns', '1'); - }; - so.remove = function(section) { - uci.unset('dhcp', section, 'name'); - uci.unset('dhcp', section, 'dns'); - }; - - //this can be a .DynamicList or a .Value with a widget and dnsmasq handles multimac OK. - so = ss.option(form.DynamicList, 'mac', - _('MAC address(es)'), - _('The hardware address(es) of this entry/host.') + '

' + - _('In DHCPv4, it is possible to include more than one mac address. This allows an IP address to be associated with multiple macaddrs, and dnsmasq abandons a DHCP lease to one of the macaddrs when another asks for a lease. It only works reliably if only one of the macaddrs is active at any time.')); - //As a special case, in DHCPv4, it is possible to include more than one hardware address. eg: --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2 This allows an IP address to be associated with multiple hardware addresses, and gives dnsmasq permission to abandon a DHCP lease to one of the hardware addresses when another one asks for a lease - so.rmempty = true; - so.cfgvalue = function(section) { - var macs = uci.get('dhcp', section, 'mac'); - var formattedMacs; - var hint, entry; - - if(!Array.isArray(macs)){ - formattedMacs = expandAndFormatMAC(L.toArray(macs)); - } else { - formattedMacs = expandAndFormatMAC(macs); - } - - if (!macdata) { - return formattedMacs; - } - - - if (Array.isArray(formattedMacs)){ - for (let mac in formattedMacs) { - entry = formattedMacs[mac].toLowerCase(); - if (macdata[entry]) { - hint = macdata[entry].vendor ? macdata[entry].vendor : null; - formattedMacs[mac] += ` (${hint})`; - } - } - return formattedMacs; - } - - if (formattedMacs) { - entry = formattedMacs[0].toLowerCase(); - hint = macdata[entry].vendor ? macdata[entry].vendor : null; - formattedMacs[0] += ` (${hint})`; - } - return formattedMacs; - }; - //removed jows renderwidget function which hindered multi-mac entry - so.validate = validateMACAddr.bind(so, pools); - Object.keys(hosts).forEach(function(mac) { - var vendor; - var lower_mac = mac.toLowerCase(); - if (macdata) - vendor = macdata[lower_mac] ? macdata[lower_mac].vendor : null; - const hint = vendor || hosts[mac].name || L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0]; - so.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac); - }); - - so = ss.option(form.Value, 'ip', _('IPv4 address'), _('The IP address to be used for this host, or ignore to ignore any DHCP request from this host.')); - so.value('ignore', _('Ignore')); - so.datatype = 'or(ip4addr,"ignore")'; - so.validate = function(section, value) { - var m = this.section.formvalue(section, 'mac'), - n = this.section.formvalue(section, 'name'); - - if ((m && !m.length > 0) && !n) - return _('One of hostname or MAC address must be specified!'); - - if (!value || value == 'ignore') - return true; - - var leases = uci.sections('dhcp', 'host'); - - for (var i = 0; i < leases.length; i++) - if (leases[i]['.name'] != section && leases[i].ip == value) - return _('The IP address %h is already used by another static lease').format(value); - - for (var i = 0; i < pools.length; i++) { - var net_mask = calculateNetwork(value, pools[i].netmask); - - if (net_mask && net_mask[0] == pools[i].network) - return true; - } - - return _('The IP address is outside of any DHCP pool address range'); - }; - - L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) { - so.value(ipv4, ipaddrs[ipv4] ? '%s (%s)'.format(ipv4, ipaddrs[ipv4]) : ipv4); - }); - - so = ss.option(form.Value, 'leasetime', - _('Lease time'), - _('Host-specific lease time, e.g. 5m, 3h, 7d.')); - so.rmempty = true; - so.value('5m', _('5m (5 minutes)')); - so.value('3h', _('3h (3 hours)')); - so.value('12h', _('12h (12 hours - default)')); - so.value('7d', _('7d (7 days)')); - so.value('infinite', _('infinite (lease does not expire)')); - - so = ss.option(form.Value, 'duid', - _('DUID'), - _('The DHCPv6-DUID (DHCP unique identifier) of this host.')); - so.datatype = 'and(rangelength(20,36),hexstring)'; - Object.keys(duids).forEach(function(duid) { - so.value(duid, '%s (%s)'.format(duid, duids[duid].hostname || duids[duid].macaddr || duids[duid].ip6addr || '?')); - }); - - so = ss.option(form.Value, 'hostid', - _('IPv6-Suffix (hex)'), - _('The IPv6 interface identifier (address suffix) as hexadecimal number (max. 16 chars).')); - so.datatype = 'and(rangelength(0,16),hexstring)'; - - so = ss.option(form.DynamicList, 'tag', - _('Tag'), - _('Assign new, freeform tags to this entry.')); - - so = ss.option(form.DynamicList, 'match_tag', - _('Match Tag'), - _('When a host matches an entry then the special tag %s is set. Use %s to match all known hosts.').format('known', 'known') + '

' + - _('Ignore requests from unknown machines using %s.').format('!known') + '

' + - _('If a host matches an entry which cannot be used because it specifies an address on a different subnet, the tag %s is set.').format('known-othernet')); - so.value('known', _('known')); - so.value('!known', _('!known (not known)')); - so.value('known-othernet', _('known-othernet (on different subnet)')); - so.optional = true; - - so = ss.option(form.Value, 'instance', - _('Instance'), - _('Dnsmasq instance to which this DHCP host section is bound. If unspecified, the section is valid for all dnsmasq instances.')); - so.optional = true; - - Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) { - var [name, display_str] = generateDnsmasqInstanceEntry(val); - so.value(name, display_str); - }); - - - so = ss.option(form.Flag, 'broadcast', - _('Broadcast'), - _('Force broadcast DHCP response.')); - - so = ss.option(form.Flag, 'dns', - _('Forward/reverse DNS'), - _('Add static forward and reverse DNS entries for this host.')); - - o = s.taboption('leases', CBILeaseStatus, '__status__'); - - if (has_dhcpv6) - o = s.taboption('leases', CBILease6Status, '__status6__'); - return m.render().then(function(mapEl) { poll.add(function() { return callDHCPLeases().then(function(leaseinfo) { diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dns.js b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dns.js index 626874df52..42e60c3c93 100644 --- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dns.js +++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dns.js @@ -400,7 +400,6 @@ return view.extend({ s.tab('limits', _('Limits')); s.tab('logging', _('Log')); s.tab('files', _('Resolv & Hosts Files')); - s.tab('leases', _('Static Leases')); s.tab('ipsets', _('IP Sets')); s.tab('relay', _('Relay')); s.tab('pxe_tftp', _('PXE/TFTP')); @@ -1256,260 +1255,6 @@ return view.extend({ so.value('ip', _('IPv4')); so.value('ip6', _('IPv6')); - o = s.taboption('leases', form.SectionValue, '__leases__', form.GridSection, 'host', null, - _('Static leases are used to assign fixed IP addresses and symbolic hostnames to DHCP clients. They are also required for non-dynamic interface configurations where only hosts with a corresponding lease are served.') + '

' + - _('Use the Add Button to add a new lease entry. The MAC address identifies the host, the IPv4 address specifies the fixed address to use, and the Hostname is assigned as a symbolic name to the requesting host. The optional Lease time can be used to set non-standard host-specific lease time, e.g. 12h, 3d or infinite.') + '

' + - _('The tag construct filters which host directives are used; more than one tag can be provided, in this case the request must match all of them. Tagged directives are used in preference to untagged ones. Note that one of mac, duid or hostname still needs to be specified (can be a wildcard).')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.nodescriptions = true; - ss.max_cols = 8; - ss.modaltitle = _('Edit static lease'); - - so = ss.option(form.Value, 'name', - _('Hostname'), - _('Optional hostname to assign')); - so.validate = validateHostname; - so.rmempty = true; - so.write = function(section, value) { - uci.set('dhcp', section, 'name', value); - uci.set('dhcp', section, 'dns', '1'); - }; - so.remove = function(section) { - uci.unset('dhcp', section, 'name'); - uci.unset('dhcp', section, 'dns'); - }; - - //this can be a .DynamicList or a .Value with a widget and dnsmasq handles multimac OK. - so = ss.option(form.DynamicList, 'mac', - _('MAC address(es)'), - _('The hardware address(es) of this entry/host.') + '

' + - _('In DHCPv4, it is possible to include more than one mac address. This allows an IP address to be associated with multiple macaddrs, and dnsmasq abandons a DHCP lease to one of the macaddrs when another asks for a lease. It only works reliably if only one of the macaddrs is active at any time.')); - //As a special case, in DHCPv4, it is possible to include more than one hardware address. eg: --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2 This allows an IP address to be associated with multiple hardware addresses, and gives dnsmasq permission to abandon a DHCP lease to one of the hardware addresses when another one asks for a lease - so.rmempty = true; - so.cfgvalue = function(section) { - var macs = uci.get('dhcp', section, 'mac'); - var formattedMacs; - var hint, entry; - - if(!Array.isArray(macs)){ - formattedMacs = expandAndFormatMAC(L.toArray(macs)); - } else { - formattedMacs = expandAndFormatMAC(macs); - } - - if (!macdata) { - return formattedMacs; - } - - - if (Array.isArray(formattedMacs)){ - for (let mac in formattedMacs) { - entry = formattedMacs[mac].toLowerCase(); - if (macdata[entry]) { - hint = macdata[entry].vendor ? macdata[entry].vendor : null; - formattedMacs[mac] += ` (${hint})`; - } - } - return formattedMacs; - } - - if (formattedMacs) { - entry = formattedMacs[0].toLowerCase(); - hint = macdata[entry].vendor ? macdata[entry].vendor : null; - formattedMacs[0] += ` (${hint})`; - } - return formattedMacs; - }; - //removed jows renderwidget function which hindered multi-mac entry - so.validate = validateMACAddr.bind(so, pools); - Object.keys(hosts).forEach(function(mac) { - var vendor; - var lower_mac = mac.toLowerCase(); - if (macdata) - vendor = macdata[lower_mac] ? macdata[lower_mac].vendor : null; - const hint = vendor || hosts[mac].name || L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0]; - so.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac); - }); - - so = ss.option(form.Value, 'ip', _('IPv4 address'), _('The IP address to be used for this host, or ignore to ignore any DHCP request from this host.')); - so.value('ignore', _('Ignore')); - so.datatype = 'or(ip4addr,"ignore")'; - so.validate = function(section, value) { - var m = this.section.formvalue(section, 'mac'), - n = this.section.formvalue(section, 'name'); - - if ((m && !m.length > 0) && !n) - return _('One of hostname or MAC address must be specified!'); - - if (!value || value == 'ignore') - return true; - - var leases = uci.sections('dhcp', 'host'); - - for (var i = 0; i < leases.length; i++) - if (leases[i]['.name'] != section && leases[i].ip == value) - return _('The IP address %h is already used by another static lease').format(value); - - for (var i = 0; i < pools.length; i++) { - var net_mask = calculateNetwork(value, pools[i].netmask); - - if (net_mask && net_mask[0] == pools[i].network) - return true; - } - - return _('The IP address is outside of any DHCP pool address range'); - }; - - L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) { - so.value(ipv4, ipaddrs[ipv4] ? '%s (%s)'.format(ipv4, ipaddrs[ipv4]) : ipv4); - }); - - so = ss.option(form.Value, 'leasetime', - _('Lease time'), - _('Host-specific lease time, e.g. 5m, 3h, 7d.')); - so.rmempty = true; - so.value('5m', _('5m (5 minutes)')); - so.value('3h', _('3h (3 hours)')); - so.value('12h', _('12h (12 hours - default)')); - so.value('7d', _('7d (7 days)')); - so.value('infinite', _('infinite (lease does not expire)')); - - so = ss.option(form.Value, 'duid', - _('DUID'), - _('The DHCPv6-DUID (DHCP unique identifier) of this host.')); - so.datatype = 'and(rangelength(20,36),hexstring)'; - Object.keys(duids).forEach(function(duid) { - so.value(duid, '%s (%s)'.format(duid, duids[duid].hostname || duids[duid].macaddr || duids[duid].ip6addr || '?')); - }); - - so = ss.option(form.Value, 'hostid', - _('IPv6-Suffix (hex)'), - _('The IPv6 interface identifier (address suffix) as hexadecimal number (max. 16 chars).')); - so.datatype = 'and(rangelength(0,16),hexstring)'; - - so = ss.option(form.DynamicList, 'tag', - _('Tag'), - _('Assign new, freeform tags to this entry.')); - - so = ss.option(form.DynamicList, 'match_tag', - _('Match Tag'), - _('When a host matches an entry then the special tag %s is set. Use %s to match all known hosts.').format('known', 'known') + '

' + - _('Ignore requests from unknown machines using %s.').format('!known') + '

' + - _('If a host matches an entry which cannot be used because it specifies an address on a different subnet, the tag %s is set.').format('known-othernet')); - so.value('known', _('known')); - so.value('!known', _('!known (not known)')); - so.value('known-othernet', _('known-othernet (on different subnet)')); - so.optional = true; - - so = ss.option(form.Value, 'instance', - _('Instance'), - _('Dnsmasq instance to which this DHCP host section is bound. If unspecified, the section is valid for all dnsmasq instances.')); - so.optional = true; - - Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) { - var [name, display_str] = generateDnsmasqInstanceEntry(val); - so.value(name, display_str); - }); - - - so = ss.option(form.Flag, 'broadcast', - _('Broadcast'), - _('Force broadcast DHCP response.')); - - so = ss.option(form.Flag, 'dns', - _('Forward/reverse DNS'), - _('Add static forward and reverse DNS entries for this host.')); - - o = s.taboption('leases', CBILeaseStatus, '__status__'); - - if (has_dhcpv6) - o = s.taboption('leases', CBILease6Status, '__status6__'); - - return m.render().then(function(mapEl) { - poll.add(function() { - return callDHCPLeases().then(function(leaseinfo) { - var leases = Array.isArray(leaseinfo.dhcp_leases) ? leaseinfo.dhcp_leases : [], - leases6 = Array.isArray(leaseinfo.dhcp6_leases) ? leaseinfo.dhcp6_leases : []; - - cbi_update_table(mapEl.querySelector('#lease_status_table'), - leases.map(function(lease) { - var exp; - var vendor; - - if (lease.expires === false) - exp = E('em', _('unlimited')); - else if (lease.expires <= 0) - exp = E('em', _('expired')); - else - exp = '%t'.format(lease.expires); - - for (let mac in macdata) { - if (mac.toUpperCase() === lease.macaddr) { - vendor = macdata[mac].vendor ? - ` (${macdata[mac].vendor})` : null; - } - } - - var hint = lease.macaddr ? hosts[lease.macaddr] : null, - name = hint ? hint.name : null, - host = null; - - if (name && lease.hostname && lease.hostname != name) - host = '%s (%s)'.format(lease.hostname, name); - else if (lease.hostname) - host = lease.hostname; - - return [ - host || '-', - lease.ipaddr, - vendor ? lease.macaddr + vendor : lease.macaddr, - exp - ]; - }), - E('em', _('There are no active leases'))); - - if (has_dhcpv6) { - cbi_update_table(mapEl.querySelector('#lease6_status_table'), - leases6.map(function(lease) { - var exp; - - if (lease.expires === false) - exp = E('em', _('unlimited')); - else if (lease.expires <= 0) - exp = E('em', _('expired')); - else - exp = '%t'.format(lease.expires); - - var hint = lease.macaddr ? hosts[lease.macaddr] : null, - name = hint ? (hint.name || L.toArray(hint.ipaddrs || hint.ipv4)[0] || L.toArray(hint.ip6addrs || hint.ipv6)[0]) : null, - host = null; - - if (name && lease.hostname && lease.hostname != name && lease.ip6addr != name) - host = '%s (%s)'.format(lease.hostname, name); - else if (lease.hostname) - host = lease.hostname; - else if (name) - host = name; - - return [ - host || '-', - lease.ip6addrs ? lease.ip6addrs.join('
') : lease.ip6addr, - lease.duid, - lease.iaid, - exp - ]; - }), - E('em', _('There are no active leases'))); - } - }); - }); - - return mapEl; - }); + return m.render(); } }); -- 2.30.2