feat: replace Dynamic DNS YAML editor with a web form
Adds structured form fields for nsupdate_bin, rndc_key, and dyndomains (comma-separated list). Wires list-type editable fields through the generic stageFormSection path and adds DNS support to apply_structured_section in configio. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -88,6 +88,12 @@ def apply_structured_section(data, section: str, values: dict) -> None:
|
|||||||
for key in _SERVER_KEYS:
|
for key in _SERVER_KEYS:
|
||||||
if key in values:
|
if key in values:
|
||||||
data[key] = values[key]
|
data[key] = values[key]
|
||||||
|
elif section == "dns":
|
||||||
|
for key in _DNS_KEYS:
|
||||||
|
if key in values:
|
||||||
|
data[key] = values[key]
|
||||||
|
else:
|
||||||
|
data.pop(key, None)
|
||||||
elif section == "users":
|
elif section == "users":
|
||||||
data["users"] = values
|
data["users"] = values
|
||||||
elif section == "hosts":
|
elif section == "hosts":
|
||||||
|
|||||||
+9
-3
@@ -1304,9 +1304,15 @@ async def start(
|
|||||||
attrs.pop("client_secret", None)
|
attrs.pop("client_secret", None)
|
||||||
data["oauth"] = new_oauth
|
data["oauth"] = new_oauth
|
||||||
|
|
||||||
for section in ("notification_channels", "dns"):
|
if "notification_channels" in payload:
|
||||||
if section in payload:
|
configio_mod.apply_yaml_section(data, "notification_channels", payload["notification_channels"])
|
||||||
configio_mod.apply_yaml_section(data, section, payload[section])
|
|
||||||
|
if "dns" in payload:
|
||||||
|
dns_payload = payload["dns"]
|
||||||
|
if isinstance(dns_payload, str):
|
||||||
|
configio_mod.apply_yaml_section(data, "dns", dns_payload)
|
||||||
|
else:
|
||||||
|
configio_mod.apply_structured_section(data, "dns", dns_payload)
|
||||||
|
|
||||||
if "thresholds" in payload:
|
if "thresholds" in payload:
|
||||||
tc = payload["thresholds"]
|
tc = payload["thresholds"]
|
||||||
|
|||||||
+11
-3
@@ -398,10 +398,18 @@ def get_settings_sections(config: dict, threshold_checker=None) -> list:
|
|||||||
{
|
{
|
||||||
"id": "dns",
|
"id": "dns",
|
||||||
"title": "Dynamic DNS",
|
"title": "Dynamic DNS",
|
||||||
"description": "nsupdate-based DNS registration — edit raw YAML.",
|
"description": "nsupdate-based DNS registration via nsupdate(8).",
|
||||||
"section_mode": "yaml",
|
"section_mode": "form",
|
||||||
"api_section": "dns",
|
"api_section": "dns",
|
||||||
"fields": [],
|
"fields": [
|
||||||
|
field("nsupdate_bin", "nsupdate binary", "path",
|
||||||
|
"Path to the nsupdate binary.", editable=True),
|
||||||
|
field("rndc_key", "RNDC key file", "path",
|
||||||
|
"Path to the rndc key file used to authenticate DNS updates.", editable=True),
|
||||||
|
field("dyndomains", "Dynamic domains", "list",
|
||||||
|
"Domains updated via nsupdate when a host with dyndns: true reports in.",
|
||||||
|
editable=True),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "users",
|
"id": "users",
|
||||||
|
|||||||
@@ -820,6 +820,11 @@
|
|||||||
<input type="number" class="field-input"
|
<input type="number" class="field-input"
|
||||||
data-key="{{ f.key }}" data-type="{{ f.type }}" data-section="{{ section.api_section }}"
|
data-key="{{ f.key }}" data-type="{{ f.type }}" data-section="{{ section.api_section }}"
|
||||||
value="{{ f.raw if f.raw is not none else '' }}">
|
value="{{ f.raw if f.raw is not none else '' }}">
|
||||||
|
{% elif f.type == 'list' %}
|
||||||
|
<input type="text" class="field-input"
|
||||||
|
data-key="{{ f.key }}" data-type="list" data-section="{{ section.api_section }}"
|
||||||
|
value="{{ f.value | join(', ') if f.value else '' }}"
|
||||||
|
placeholder="comma-separated">
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="text" class="field-input"
|
<input type="text" class="field-input"
|
||||||
data-key="{{ f.key }}" data-section="{{ section.api_section }}"
|
data-key="{{ f.key }}" data-section="{{ section.api_section }}"
|
||||||
@@ -1023,6 +1028,8 @@
|
|||||||
} else if (el.dataset.type === 'number' || el.dataset.type === 'port') {
|
} else if (el.dataset.type === 'number' || el.dataset.type === 'port') {
|
||||||
const v = parseInt(el.value, 10);
|
const v = parseInt(el.value, 10);
|
||||||
_staged[apiSection][key] = isNaN(v) ? null : v;
|
_staged[apiSection][key] = isNaN(v) ? null : v;
|
||||||
|
} else if (el.dataset.type === 'list') {
|
||||||
|
_staged[apiSection][key] = el.value.split(',').map(s => s.trim()).filter(Boolean);
|
||||||
} else {
|
} else {
|
||||||
_staged[apiSection][key] = el.value;
|
_staged[apiSection][key] = el.value;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user