mirror of https://github.com/aredn/aredn.git
Disable Done button when invalid dialog content (#1562)
* Disable Done button if entries are invalid. * Generalize Done validation
This commit is contained in:
parent
5b80ae8adc
commit
360b558b94
|
@ -92,6 +92,25 @@
|
|||
e.stopPropagation();
|
||||
}
|
||||
}, true);
|
||||
function dialogDone()
|
||||
{
|
||||
const d = htmx.find("#dialog-done");
|
||||
if (d) {
|
||||
setTimeout(function() {
|
||||
let invalid = false;
|
||||
const f = htmx.findAll(m, "form");
|
||||
for (let i = 0; i < f.length; i++) {
|
||||
if (!f[i].checkValidity()) {
|
||||
invalid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
d.disabled = invalid;
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
m.addEventListener("input", dialogDone);
|
||||
m.addEventListener("click", dialogDone);
|
||||
})();
|
||||
</script>
|
||||
{% } %}
|
||||
|
|
|
@ -239,35 +239,37 @@ const dhcpOptionTypes = {
|
|||
</div>
|
||||
{{_H("Creates a permenant mapping between a device MAC address and an IP address on the LAN network.
|
||||
The given hostname is available to everyone on the mesh unless the entry is marked as <b>do not propagate</b>")}}
|
||||
<div id="dhcp-reservations">
|
||||
<div class="cols reservation-label">
|
||||
<div style="white-space:nowrap">
|
||||
<div>hostname</div>
|
||||
<div>ip address</div>
|
||||
<div>mac a‌ddress</div>
|
||||
<div>do not propagate</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
{% if (reservations > 0) {
|
||||
for (let i = 0; i < length(options); i++) {
|
||||
const o = options[i];
|
||||
if (o.reserved) {
|
||||
%}
|
||||
<div class="cols reservation" data-ip="{{o.ip}}">
|
||||
<div style="white-space:nowrap">
|
||||
<input name="hostname" type="text" required placeholder="hostname" value="{{o.name}}">
|
||||
<select class="dhcp-addresses">
|
||||
</select>
|
||||
<input name="mac" type="text" required placeholder="mac a‌ddress" pattern="([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]" value="{{o.mac}}">
|
||||
<label><input type="checkbox" {{o.noprop ? "checked" : ""}}></label>
|
||||
</div>
|
||||
<button>-</button>
|
||||
<form>
|
||||
<div id="dhcp-reservations">
|
||||
<div class="cols reservation-label">
|
||||
<div style="white-space:nowrap">
|
||||
<div>hostname</div>
|
||||
<div>ip address</div>
|
||||
<div>mac a‌ddress</div>
|
||||
<div>do not propagate</div>
|
||||
</div>
|
||||
{% }
|
||||
}
|
||||
} %}
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
{% if (reservations > 0) {
|
||||
for (let i = 0; i < length(options); i++) {
|
||||
const o = options[i];
|
||||
if (o.reserved) {
|
||||
%}
|
||||
<div class="cols reservation" data-ip="{{o.ip}}">
|
||||
<div style="white-space:nowrap">
|
||||
<input name="hostname" type="text" required placeholder="hostname" value="{{o.name}}">
|
||||
<select class="dhcp-addresses">
|
||||
</select>
|
||||
<input name="mac" type="text" required placeholder="mac a‌ddress" pattern="([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]" value="{{o.mac}}">
|
||||
<label><input type="checkbox" {{o.noprop ? "checked" : ""}}></label>
|
||||
</div>
|
||||
<button>-</button>
|
||||
</div>
|
||||
{% }
|
||||
}
|
||||
} %}
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
<div class="o">Active Leases</div>
|
||||
<div class="m">Addresses currently in use</div>
|
||||
|
|
|
@ -204,62 +204,64 @@ if (f) {
|
|||
{{_H("Create a service by selecting from the templates above and hitting +. The two most generic templates are
|
||||
<b>Generic URL</b> and <b>Simple text</b> and can be used for any services. You can also use the other templates to
|
||||
help create services for specific cameras, mail servers, phones, etc. and these will pre-populate various service fields.")}}
|
||||
<div id="local-services">{%
|
||||
for (let i = 0; i < length(services); i++) {
|
||||
const s = services[i];
|
||||
%}
|
||||
<div class="service">
|
||||
<div class="cols">
|
||||
<form>
|
||||
<div id="local-services">{%
|
||||
for (let i = 0; i < length(services); i++) {
|
||||
const s = services[i];
|
||||
%}
|
||||
<div class="service">
|
||||
<div class="cols">
|
||||
<input name="name" type="text" placeholder="{{s.link === false ? 'service information' : 'service name'}}" required pattern='[^-:"|<>]+' value="{{s.name}}">
|
||||
<div style="flex:0">
|
||||
<select name="type">
|
||||
<option value="">-</option>
|
||||
{%
|
||||
for (t in types) {
|
||||
print(`<option value="${t}" ${t === s.type ? "selected" : ""}>${t}</option>`);
|
||||
}
|
||||
%}
|
||||
<div class="cols">
|
||||
<input name="name" type="text" placeholder="{{s.link === false ? 'service information' : 'service name'}}" required pattern='[^-:"|<>]+' value="{{s.name}}">
|
||||
<div style="flex:0">
|
||||
<select name="type">
|
||||
<option value="">-</option>
|
||||
{%
|
||||
for (t in types) {
|
||||
print(`<option value="${t}" ${t === s.type ? "selected" : ""}>${t}</option>`);
|
||||
}
|
||||
%}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<button>-</button>
|
||||
</div>
|
||||
<div class="cols">
|
||||
<div></div>
|
||||
{% if (s.link === false) { %}
|
||||
<div class="link">
|
||||
<select name="hostname">
|
||||
{%
|
||||
for (j = 0; j < length(hosts); j++) {
|
||||
print(`<option value="${hosts[j]}" ${hosts[j] === s.hostname ? "selected" : ""}>${hosts[j]}</option>`);
|
||||
}
|
||||
for (let j = 0; j < length(aliases.map); j++) {
|
||||
print(`<option value="${aliases.map[j].hostname}" ${aliases.map[j].hostname === s.hostname ? "selected" : ""}>${aliases.map[j].hostname}</option>`);
|
||||
}
|
||||
%}
|
||||
</select>
|
||||
</div>
|
||||
{% } else { %}
|
||||
<div>
|
||||
<input name="protocol" type="text" placeholder="proto" required pattern="[a-z]+" value="{{s.protocol}}">
|
||||
:// <select name="hostname">
|
||||
{%
|
||||
for (j = 0; j < length(hosts); j++) {
|
||||
print(`<option value="${hosts[j]}" ${hosts[j] === s.hostname ? "selected" : ""}>${hosts[j]}</option>`);
|
||||
}
|
||||
for (let j = 0; j < length(aliases.map); j++) {
|
||||
print(`<option value="${aliases.map[j].hostname}" ${aliases.map[j].hostname === s.hostname ? "selected" : ""}>${aliases.map[j].hostname}</option>`);
|
||||
}
|
||||
%}
|
||||
</select>
|
||||
: <input name="port" type="text" placeholder="port" required pattern="([1-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])" value="{{s.port}}">
|
||||
/ <input name="path" type="text" placeholder="path" pattern="[\-\/\?\&\._=#a-zA-Z0-9]*" value="{{s.path}}">
|
||||
</div>
|
||||
{% } %}
|
||||
</div>
|
||||
<button>-</button>
|
||||
</div>
|
||||
<div class="cols">
|
||||
<div></div>
|
||||
{% if (s.link === false) { %}
|
||||
<div class="link">
|
||||
<select name="hostname">
|
||||
{%
|
||||
for (j = 0; j < length(hosts); j++) {
|
||||
print(`<option value="${hosts[j]}" ${hosts[j] === s.hostname ? "selected" : ""}>${hosts[j]}</option>`);
|
||||
}
|
||||
for (let j = 0; j < length(aliases.map); j++) {
|
||||
print(`<option value="${aliases.map[j].hostname}" ${aliases.map[j].hostname === s.hostname ? "selected" : ""}>${aliases.map[j].hostname}</option>`);
|
||||
}
|
||||
%}
|
||||
</select>
|
||||
</div>
|
||||
{% } else { %}
|
||||
<div>
|
||||
<input name="protocol" type="text" placeholder="proto" required pattern="[a-z]+" value="{{s.protocol}}">
|
||||
:// <select name="hostname">
|
||||
{%
|
||||
for (j = 0; j < length(hosts); j++) {
|
||||
print(`<option value="${hosts[j]}" ${hosts[j] === s.hostname ? "selected" : ""}>${hosts[j]}</option>`);
|
||||
}
|
||||
for (let j = 0; j < length(aliases.map); j++) {
|
||||
print(`<option value="${aliases.map[j].hostname}" ${aliases.map[j].hostname === s.hostname ? "selected" : ""}>${aliases.map[j].hostname}</option>`);
|
||||
}
|
||||
%}
|
||||
</select>
|
||||
: <input name="port" type="text" placeholder="port" required pattern="([1-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])" value="{{s.port}}">
|
||||
/ <input name="path" type="text" placeholder="path" pattern="[\-\/\?\&\._=#a-zA-Z0-9]*" value="{{s.path}}">
|
||||
</div>
|
||||
{% } %}
|
||||
</div>
|
||||
</div>
|
||||
{% } %}</div>
|
||||
{% } %}</div>
|
||||
</form>
|
||||
<hr>
|
||||
<div id="host-aliases-add" class="cols">
|
||||
<div>
|
||||
|
@ -270,27 +272,29 @@ if (f) {
|
|||
</div>
|
||||
{{_H("Assign a hostname to an LAN IP address on this node. Multiple hostnames can be assigned to the same IP address. You are
|
||||
encouraged to prefix your hostnames with your callsign so it will be unique on the network.")}}
|
||||
<div id="host-aliases">{%
|
||||
for (let i = 0; i < length(aliases.map); i++) {
|
||||
%}
|
||||
<div class="cols alias">
|
||||
<input type="text" name="hostname" value="{{aliases.map[i].hostname}}" required pattern="(\*\.)?[a-zA-Z][a-zA-Z0-9_\-]*">
|
||||
<div>
|
||||
<select name="address">
|
||||
{%
|
||||
for (let j = as[3]; j <= ae[3]; j++) {
|
||||
const a = `${as[0]}.${as[1]}.${as[2]}.${j}`;
|
||||
const n = aliases.leases[a];
|
||||
print(`<option value="${a}" ${a === aliases.map[i].address ? "selected" : ""}>${n ? n : a}</option>`);
|
||||
}
|
||||
%}
|
||||
</select>
|
||||
<form>
|
||||
<div id="host-aliases">{%
|
||||
for (let i = 0; i < length(aliases.map); i++) {
|
||||
%}
|
||||
<div class="cols alias">
|
||||
<input type="text" name="hostname" value="{{aliases.map[i].hostname}}" required pattern="(\*\.)?[a-zA-Z][a-zA-Z0-9_\-]*">
|
||||
<div>
|
||||
<select name="address">
|
||||
{%
|
||||
for (let j = as[3]; j <= ae[3]; j++) {
|
||||
const a = `${as[0]}.${as[1]}.${as[2]}.${j}`;
|
||||
const n = aliases.leases[a];
|
||||
print(`<option value="${a}" ${a === aliases.map[i].address ? "selected" : ""}>${n ? n : a}</option>`);
|
||||
}
|
||||
%}
|
||||
</select>
|
||||
</div>
|
||||
<button>-</button>
|
||||
</div>
|
||||
<button>-</button>
|
||||
</div>
|
||||
{%
|
||||
}
|
||||
%}</div>
|
||||
{%
|
||||
}
|
||||
%}</div>
|
||||
</form>
|
||||
<hr>
|
||||
<div id="port-forward-add" class="cols">
|
||||
<div>
|
||||
|
@ -320,48 +324,50 @@ if (f) {
|
|||
<div>enabled</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="port-forwards">{%
|
||||
for (let i = 0; i < length(ports); i++) {
|
||||
const p = ports[i];
|
||||
%}<div class="cols noborder forward">
|
||||
<div class="row">
|
||||
<div>
|
||||
{% if (dhcp.mode === 0) { %}
|
||||
<select name="port_src">
|
||||
<option value="wifi" {{p.src == "wifi" ? "selected" : ""}}>Mesh</option>
|
||||
<option value="wan" {{p.src == "wan" ? "selected" : ""}}>WAN</option>
|
||||
<option value="both" {{p.src == "both" ? "selected" : ""}}>Mesh & WAN</option>
|
||||
</select>
|
||||
{% } else { %}
|
||||
<select name="port_src" disabled>
|
||||
<option value="wan">WAN</option>
|
||||
</select>
|
||||
{% } %}
|
||||
<input name="port_sports" type="text" required placeholder="Port or range" pattern="([1-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(?:-([1-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?" value="{{p.sports}}">
|
||||
<select name="port_type">
|
||||
<option value="tcp" {{p.type == "tcp" ? "selected" : ""}}>TCP</option>
|
||||
<option value="udp" {{p.type == "udp" ? "selected" : ""}}>UDP</option>
|
||||
<option value="both" {{p.type == "both" ? "selected" : ""}}>TCP & UDP</option>
|
||||
</select>
|
||||
<label class="switch"><input type="checkbox" name="port_enable" {{p.enabled ? "checked" : ""}}></label>
|
||||
<form>
|
||||
<div id="port-forwards">{%
|
||||
for (let i = 0; i < length(ports); i++) {
|
||||
const p = ports[i];
|
||||
%}<div class="cols noborder forward">
|
||||
<div class="row">
|
||||
<div>
|
||||
{% if (dhcp.mode === 0) { %}
|
||||
<select name="port_src">
|
||||
<option value="wifi" {{p.src == "wifi" ? "selected" : ""}}>Mesh</option>
|
||||
<option value="wan" {{p.src == "wan" ? "selected" : ""}}>WAN</option>
|
||||
<option value="both" {{p.src == "both" ? "selected" : ""}}>Mesh & WAN</option>
|
||||
</select>
|
||||
{% } else { %}
|
||||
<select name="port_src" disabled>
|
||||
<option value="wan">WAN</option>
|
||||
</select>
|
||||
{% } %}
|
||||
<input name="port_sports" type="text" required placeholder="Port or range" pattern="([1-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(?:-([1-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?" value="{{p.sports}}">
|
||||
<select name="port_type">
|
||||
<option value="tcp" {{p.type == "tcp" ? "selected" : ""}}>TCP</option>
|
||||
<option value="udp" {{p.type == "udp" ? "selected" : ""}}>UDP</option>
|
||||
<option value="both" {{p.type == "both" ? "selected" : ""}}>TCP & UDP</option>
|
||||
</select>
|
||||
<label class="switch"><input type="checkbox" name="port_enable" {{p.enabled ? "checked" : ""}}></label>
|
||||
</div>
|
||||
<div>
|
||||
<select name="port_dst">
|
||||
{%
|
||||
for (let j = as[3]; j <= ae[3]; j++) {
|
||||
const a = `${as[0]}.${as[1]}.${as[2]}.${j}`;
|
||||
const n = aliases.leases[a];
|
||||
print(`<option value="${a}" ${a === p.dst ? "selected" : ""}>${n ? n : a}</option>`);
|
||||
}
|
||||
%}
|
||||
</select>
|
||||
<input name="port_dport" type="text" required placeholder="LAN Port" pattern="{{constants.patPort}}" value="{{p.dport}}">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<select name="port_dst">
|
||||
{%
|
||||
for (let j = as[3]; j <= ae[3]; j++) {
|
||||
const a = `${as[0]}.${as[1]}.${as[2]}.${j}`;
|
||||
const n = aliases.leases[a];
|
||||
print(`<option value="${a}" ${a === p.dst ? "selected" : ""}>${n ? n : a}</option>`);
|
||||
}
|
||||
%}
|
||||
</select>
|
||||
<input name="port_dport" type="text" required placeholder="LAN Port" pattern="{{constants.patPort}}" value="{{p.dport}}">
|
||||
</div>
|
||||
</div>
|
||||
<button>-</button>
|
||||
</div>{%
|
||||
}
|
||||
%}</div>
|
||||
<button>-</button>
|
||||
</div>{%
|
||||
}
|
||||
%}</div>
|
||||
</form>
|
||||
</div>
|
||||
{{_R("dialog-footer")}}
|
||||
<script>
|
||||
|
@ -369,8 +375,10 @@ if (f) {
|
|||
{{_R("open")}}
|
||||
const templates = {{templates}};
|
||||
const hosts = {{hosts}};
|
||||
function updateServices() {
|
||||
function updateServices()
|
||||
{
|
||||
const services = [];
|
||||
let invalid = 0;
|
||||
const svc = htmx.findAll("#local-services .service");
|
||||
for (let i = 0; i < svc.length; i++) {
|
||||
const s = svc[i];
|
||||
|
@ -384,21 +392,31 @@ if (f) {
|
|||
if (name.validity.valid && protocol.validity.valid && port.validity.valid && path.validity.valid) {
|
||||
services.push(`${name.value}${type.value ? " [" + type.value + "]" : ""}|1|${protocol.value}|${host.value}|${port.value}|${path.value}`);
|
||||
}
|
||||
else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (name.validity.valid) {
|
||||
services.push(`${name.value}${type.value ? " [" + type.value + "]" : ""}|0||${host.value}||`);
|
||||
}
|
||||
else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
htmx.ajax("PUT", "{{request.env.REQUEST_URI}}", {
|
||||
swap: "none",
|
||||
values: { services: JSON.stringify(services) }
|
||||
});
|
||||
if (invalid === 0) {
|
||||
htmx.ajax("PUT", "{{request.env.REQUEST_URI}}", {
|
||||
swap: "none",
|
||||
values: { services: JSON.stringify(services) }
|
||||
});
|
||||
htmx.find("#dialog-done").disabled = false;
|
||||
}
|
||||
}
|
||||
function updateAliases()
|
||||
{
|
||||
const aliases = [];
|
||||
let invalid = 0;
|
||||
const al = htmx.findAll("#host-aliases .alias");
|
||||
for (let i = 0; i < al.length; i++) {
|
||||
const s = al[i];
|
||||
|
@ -407,15 +425,21 @@ if (f) {
|
|||
if (hostname.validity.valid) {
|
||||
aliases.push(`${address.value} ${hostname.value}`);
|
||||
}
|
||||
else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
if (invalid === 0) {
|
||||
htmx.ajax("PUT", "{{request.env.REQUEST_URI}}", {
|
||||
swap: "none",
|
||||
values: { aliases: JSON.stringify(aliases) }
|
||||
});
|
||||
}
|
||||
htmx.ajax("PUT", "{{request.env.REQUEST_URI}}", {
|
||||
swap: "none",
|
||||
values: { aliases: JSON.stringify(aliases) }
|
||||
});
|
||||
}
|
||||
function updatePortForwards()
|
||||
{
|
||||
const ports = [];
|
||||
let invalid = 0;
|
||||
const rows = htmx.findAll("#port-forwards .cols .row");
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const r = rows[i];
|
||||
|
@ -428,11 +452,16 @@ if (f) {
|
|||
if (sports.validity.valid && dport.validity.valid) {
|
||||
ports.push(`${src.value}:${type.value}:${sports.value}:${dst.value}:${dport.value}:${enabled.checked ? "1" : "0"}`);
|
||||
}
|
||||
else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
if (invalid === 0) {
|
||||
htmx.ajax("PUT", "{{request.env.REQUEST_URI}}", {
|
||||
swap: "none",
|
||||
values: { ports: JSON.stringify(ports) }
|
||||
});
|
||||
}
|
||||
htmx.ajax("PUT", "{{request.env.REQUEST_URI}}", {
|
||||
swap: "none",
|
||||
values: { ports: JSON.stringify(ports) }
|
||||
});
|
||||
}
|
||||
function refreshHostSelectors()
|
||||
{
|
||||
|
@ -644,10 +673,11 @@ if (f) {
|
|||
newForwardEntry();
|
||||
}
|
||||
});
|
||||
htmx.find("#dialog-done").disabled = true;
|
||||
}
|
||||
htmx.on("#port-forward-add button", "click", newForwardEntry);
|
||||
htmx.on("#port-forwards", "change", _ => updatePortForwards());
|
||||
htmx.on("#port-forwards", "select", _ => updatePortForwards());
|
||||
htmx.on("#port-forwards", "change", updatePortForwards);
|
||||
htmx.on("#port-forwards", "select", updatePortForwards);
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
|
|
|
@ -311,63 +311,65 @@ uciMesh.foreach("xlink", "interface", x => {
|
|||
<button class="add">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="xlink-list">
|
||||
<div class="cols xlink-label">
|
||||
<div style="white-space:nowrap">
|
||||
<div>vlan</div>
|
||||
<div>ip a‌ddress</div>
|
||||
<div>peer a‌ddress</div>
|
||||
<div>cidr</div>
|
||||
<div>weight</div>
|
||||
{% if (haveports) { %}
|
||||
<div>port</div>
|
||||
{% } %}
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
{% for (let i = 0; i < length(xlinks); i++) {
|
||||
const x = xlinks[i];
|
||||
%}
|
||||
<div class="cols xlink" data-name="{{x.name}}">
|
||||
<div>
|
||||
<input name="vlan" type="text" size="5" required pattern="([4-9]|[1-9][0-9]{1,2}|[1-3][0-9]{3}|40[0-8][0-9]|409[0-5])" placeholder="VLan" value="{{x.vlan}}">
|
||||
<input name="ipaddr" type="text" size="25" required pattern="{{constants.patIP}}" placeholder="IP A‌ddress" value="{{x.ipaddr}}">
|
||||
<input name="peer" type="text" size="25" pattern="{{constants.patIP}}" placeholder="IP A‌ddress" value="{{x.peer}}">
|
||||
<select name="cidr">
|
||||
<option value="32" {{x.cidr === 32 ? "selected" : ""}}>PtP</option>
|
||||
<option value="31" {{x.cidr === 31 ? "selected" : ""}}>/ 31</option>
|
||||
<option value="30" {{x.cidr === 30 ? "selected" : ""}}>/ 30</option>
|
||||
<option value="29" {{x.cidr === 29 ? "selected" : ""}}>/ 29</option>
|
||||
<option value="28" {{x.cidr === 28 ? "selected" : ""}}>/ 28</option>
|
||||
<option value="27" {{x.cidr === 27 ? "selected" : ""}}>/ 27</option>
|
||||
<option value="26" {{x.cidr === 26 ? "selected" : ""}}>/ 26</option>
|
||||
<option value="25" {{x.cidr === 25 ? "selected" : ""}}>/ 25</option>
|
||||
<option value="24" {{x.cidr === 24 ? "selected" : ""}}>/ 24</option>
|
||||
<option value="23" {{x.cidr === 23 ? "selected" : ""}}>/ 23</option>
|
||||
<option value="22" {{x.cidr === 22 ? "selected" : ""}}>/ 22</option>
|
||||
<option value="21" {{x.cidr === 21 ? "selected" : ""}}>/ 21</option>
|
||||
<option value="20" {{x.cidr === 20 ? "selected" : ""}}>/ 20</option>
|
||||
<option value="19" {{x.cidr === 19 ? "selected" : ""}}>/ 19</option>
|
||||
<option value="18" {{x.cidr === 18 ? "selected" : ""}}>/ 18</option>
|
||||
<option value="17" {{x.cidr === 17 ? "selected" : ""}}>/ 17</option>
|
||||
<option value="16" {{x.cidr === 16 ? "selected" : ""}}>/ 16</option>
|
||||
</select>
|
||||
<input name="weight" type="text" size="2" required pattern="([0-9]|[1-9][0-9]|100)" placeholder="Wt" value="{{x.weight}}">
|
||||
<form>
|
||||
<div id="xlink-list">
|
||||
<div class="cols xlink-label">
|
||||
<div style="white-space:nowrap">
|
||||
<div>vlan</div>
|
||||
<div>ip a‌ddress</div>
|
||||
<div>peer a‌ddress</div>
|
||||
<div>cidr</div>
|
||||
<div>weight</div>
|
||||
{% if (haveports) { %}
|
||||
<select name="port">
|
||||
{%
|
||||
for (let i = 0; i < length(ports); i++) {
|
||||
const p = ports[i];
|
||||
print(`<option value="${p.name}" ${x.port === p.name ? "selected" : ""}>${p.display}</option>`);
|
||||
}
|
||||
%}
|
||||
</select>
|
||||
<div>port</div>
|
||||
{% } %}
|
||||
</div>
|
||||
<button>-</button>
|
||||
<div></div>
|
||||
</div>
|
||||
{% } %}
|
||||
</div>
|
||||
{% for (let i = 0; i < length(xlinks); i++) {
|
||||
const x = xlinks[i];
|
||||
%}
|
||||
<div class="cols xlink" data-name="{{x.name}}">
|
||||
<div>
|
||||
<input name="vlan" type="text" size="5" required pattern="([4-9]|[1-9][0-9]{1,2}|[1-3][0-9]{3}|40[0-8][0-9]|409[0-5])" placeholder="VLan" value="{{x.vlan}}">
|
||||
<input name="ipaddr" type="text" size="25" required pattern="{{constants.patIP}}" placeholder="IP A‌ddress" value="{{x.ipaddr}}">
|
||||
<input name="peer" type="text" size="25" pattern="{{constants.patIP}}" placeholder="IP A‌ddress" value="{{x.peer}}">
|
||||
<select name="cidr">
|
||||
<option value="32" {{x.cidr === 32 ? "selected" : ""}}>PtP</option>
|
||||
<option value="31" {{x.cidr === 31 ? "selected" : ""}}>/ 31</option>
|
||||
<option value="30" {{x.cidr === 30 ? "selected" : ""}}>/ 30</option>
|
||||
<option value="29" {{x.cidr === 29 ? "selected" : ""}}>/ 29</option>
|
||||
<option value="28" {{x.cidr === 28 ? "selected" : ""}}>/ 28</option>
|
||||
<option value="27" {{x.cidr === 27 ? "selected" : ""}}>/ 27</option>
|
||||
<option value="26" {{x.cidr === 26 ? "selected" : ""}}>/ 26</option>
|
||||
<option value="25" {{x.cidr === 25 ? "selected" : ""}}>/ 25</option>
|
||||
<option value="24" {{x.cidr === 24 ? "selected" : ""}}>/ 24</option>
|
||||
<option value="23" {{x.cidr === 23 ? "selected" : ""}}>/ 23</option>
|
||||
<option value="22" {{x.cidr === 22 ? "selected" : ""}}>/ 22</option>
|
||||
<option value="21" {{x.cidr === 21 ? "selected" : ""}}>/ 21</option>
|
||||
<option value="20" {{x.cidr === 20 ? "selected" : ""}}>/ 20</option>
|
||||
<option value="19" {{x.cidr === 19 ? "selected" : ""}}>/ 19</option>
|
||||
<option value="18" {{x.cidr === 18 ? "selected" : ""}}>/ 18</option>
|
||||
<option value="17" {{x.cidr === 17 ? "selected" : ""}}>/ 17</option>
|
||||
<option value="16" {{x.cidr === 16 ? "selected" : ""}}>/ 16</option>
|
||||
</select>
|
||||
<input name="weight" type="text" size="2" required pattern="([0-9]|[1-9][0-9]|100)" placeholder="Wt" value="{{x.weight}}">
|
||||
{% if (haveports) { %}
|
||||
<select name="port">
|
||||
{%
|
||||
for (let i = 0; i < length(ports); i++) {
|
||||
const p = ports[i];
|
||||
print(`<option value="${p.name}" ${x.port === p.name ? "selected" : ""}>${p.display}</option>`);
|
||||
}
|
||||
%}
|
||||
</select>
|
||||
{% } %}
|
||||
</div>
|
||||
<button>-</button>
|
||||
</div>
|
||||
{% } %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{_H("<p>XLinks provide a way of routing AREDN traffic across external non-AREDN networks. Each is created with a specific VLAN,
|
||||
IP address for both ends, a weight of how likely to link is to be used, and an optional network size and port (on multi-port
|
||||
|
|
|
@ -299,37 +299,39 @@ function t2t(type)
|
|||
information as possible. For tunnel clients all the fields can be easily populated by copy-n-pasting the entire server configuration
|
||||
from another node into any field.")}}
|
||||
<br>
|
||||
<div id="tunnels">{%
|
||||
for (let i = 0; i < length(tunnels); i++) {
|
||||
const t = tunnels[i];
|
||||
const client = t.type === "lc" || t.type === "wc" ? true : false;
|
||||
const wireguard = t.type === "ws" || t.type === "wc" ? true : false;
|
||||
%}<div class="tunnel cols" data-index="{{t.index}}">
|
||||
<div class="cols">
|
||||
<div data-type="{{t.type}}">{{t2t(t.type)}}</div>
|
||||
<div>
|
||||
<div class="cols">
|
||||
<input type="text" name="name" required placeholder="{{client ? 'Server name' : 'Node name'}}" value="{{t.name}}">
|
||||
<label class="switch {{t.up ? 'up' : ''}}"><input type="checkbox" name="enable" {{t.enabled ? "checked" : ""}}></label>
|
||||
</div>
|
||||
<div class="cols pwnw">
|
||||
{% if (t.type === "ws") { %}
|
||||
<input type="hidden" name="key" value="{{t.key}}">
|
||||
{% } %}
|
||||
<input type="text" name="password" required pattern="{{wireguard ? '[A-Za-z0-9+\/=]+' : '[\\w@\-]+'}}" placeholder="{{wireguard ? 'Wireguard key' : 'Password'}}" value="{{t.passwd}}" {{t.type === "ws" ? "readonly" : ""}}>
|
||||
<input type="text" name="network" required pattern="{{constants.patIP}}{{wireguard ? ':' + constants.patPort : ''}}" placeholder="{{wireguard ? 'Network:Port' : 'Network'}}" value="{{t.network}}" {{client ? "" : "readonly"}}>
|
||||
<input type="text" name="weight" pattern="([0-9]|[1-9][0-9])" placeholder="Wgt" value="{{t.weight}}">
|
||||
</div>
|
||||
<div class="cols">
|
||||
<input type="text" name="notes" placeholder="Notes..." value="{{t.notes}}">
|
||||
{{client ? '' : '<button class="clipboard"><div class="icon clipboard"></div></button>'}}
|
||||
<form>
|
||||
<div id="tunnels">{%
|
||||
for (let i = 0; i < length(tunnels); i++) {
|
||||
const t = tunnels[i];
|
||||
const client = t.type === "lc" || t.type === "wc" ? true : false;
|
||||
const wireguard = t.type === "ws" || t.type === "wc" ? true : false;
|
||||
%}<div class="tunnel cols" data-index="{{t.index}}">
|
||||
<div class="cols">
|
||||
<div data-type="{{t.type}}">{{t2t(t.type)}}</div>
|
||||
<div>
|
||||
<div class="cols">
|
||||
<input type="text" name="name" required placeholder="{{client ? 'Server name' : 'Node name'}}" value="{{t.name}}">
|
||||
<label class="switch {{t.up ? 'up' : ''}}"><input type="checkbox" name="enable" {{t.enabled ? "checked" : ""}}></label>
|
||||
</div>
|
||||
<div class="cols pwnw">
|
||||
{% if (t.type === "ws") { %}
|
||||
<input type="hidden" name="key" value="{{t.key}}">
|
||||
{% } %}
|
||||
<input type="text" name="password" required pattern="{{wireguard ? '[A-Za-z0-9+\/=]+' : '[\\w@\-]+'}}" placeholder="{{wireguard ? 'Wireguard key' : 'Password'}}" value="{{t.passwd}}" {{t.type === "ws" ? "readonly" : ""}}>
|
||||
<input type="text" name="network" required pattern="{{constants.patIP}}{{wireguard ? ':' + constants.patPort : ''}}" placeholder="{{wireguard ? 'Network:Port' : 'Network'}}" value="{{t.network}}" {{client ? "" : "readonly"}}>
|
||||
<input type="text" name="weight" pattern="([0-9]|[1-9][0-9])" placeholder="Wgt" value="{{t.weight}}">
|
||||
</div>
|
||||
<div class="cols">
|
||||
<input type="text" name="notes" placeholder="Notes..." value="{{t.notes}}">
|
||||
{{client ? '' : '<button class="clipboard"><div class="icon clipboard"></div></button>'}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="remove">-</button>
|
||||
</div>{%
|
||||
}
|
||||
%}</div>
|
||||
<button class="remove">-</button>
|
||||
</div>{%
|
||||
}
|
||||
%}</div>
|
||||
</form>
|
||||
{{_R("dialog-advanced")}}
|
||||
<div>
|
||||
{% if (includeAdvanced) { %}
|
||||
|
@ -379,6 +381,7 @@ This value is used by default, but each tunnel may overide it.
|
|||
{
|
||||
const tunnels = [];
|
||||
let servercount = 0;
|
||||
let invalid = 0;
|
||||
const tuns = htmx.findAll("#tunnels .tunnel");
|
||||
for (let i = 0; i < tuns.length; i++) {
|
||||
const t = tuns[i];
|
||||
|
@ -404,14 +407,19 @@ This value is used by default, but each tunnel may overide it.
|
|||
weight: weight.value
|
||||
});
|
||||
}
|
||||
else {
|
||||
invalid++;
|
||||
}
|
||||
if (type === "ls" || type === "ws") {
|
||||
servercount++;
|
||||
}
|
||||
}
|
||||
htmx.ajax("PUT", "{{request.env.REQUEST_URI}}", {
|
||||
swap: "none",
|
||||
values: { tunnels: JSON.stringify(tunnels) }
|
||||
});
|
||||
if (invalid === 0) {
|
||||
htmx.ajax("PUT", "{{request.env.REQUEST_URI}}", {
|
||||
swap: "none",
|
||||
values: { tunnels: JSON.stringify(tunnels) }
|
||||
});
|
||||
}
|
||||
const start = htmx.find("input[name=tunnel_range_start]");
|
||||
if (start) {
|
||||
start.disabled = servercount > 0 ? true : false;
|
||||
|
@ -547,6 +555,7 @@ This value is used by default, but each tunnel may overide it.
|
|||
if (start && !client) {
|
||||
start.disabled = true;
|
||||
}
|
||||
htmx.find("#dialog-done").disabled = true;
|
||||
}
|
||||
htmx.on("#tunnel-templates button", "click", newTunnelEntry);
|
||||
htmx.on("#tunnels", "change", updateTunnels);
|
||||
|
|
Loading…
Reference in New Issue