From cf39e2892167822070cab99ae6829624b0718d50 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:01:26 +0000 Subject: [PATCH 1/2] Initial plan From 43016296062b64fa5fc8e2a06a93348441290c9f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:07:23 +0000 Subject: [PATCH 2/2] feat: add dedicated domain reconfigure modal flow Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/34ab0742-1af8-46e9-9b12-a480c93366f1 Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com> --- .../static/js/features.js | 78 +++++++++++++++++++ .../static/js/service-detail.js | 13 +++- 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/app/sovran_systemsos_web/static/js/features.js b/app/sovran_systemsos_web/static/js/features.js index 2bdc568..5e239bf 100644 --- a/app/sovran_systemsos_web/static/js/features.js +++ b/app/sovran_systemsos_web/static/js/features.js @@ -132,6 +132,84 @@ function openDomainSetupModal(feat, onSaved) { $domainSetupModal.classList.add("open"); } +function openDomainReconfigureModal(feat, existingDomain, onSaved) { + if (!$domainSetupModal) return; + if ($domainSetupTitle) $domainSetupTitle.textContent = "🔄 Reconfigure Domain — " + feat.name; + + var npubField = ""; + if (feat.id === "haven") { + var currentNpub = ""; + if (feat.extra_fields && feat.extra_fields.length > 0) { + for (var i = 0; i < feat.extra_fields.length; i++) { + if (feat.extra_fields[i].id === "nostr_npub") { + currentNpub = feat.extra_fields[i].current_value || ""; + break; + } + } + } + npubField = '
'; + } + + var externalIp = _cachedExternalIp || "your external IP"; + var currentDomain = existingDomain || ""; + + $domainSetupBody.innerHTML = + '
' + + '

Your domain ' + escHtml(currentDomain || "this domain") + ' is configured but isn\'t resolving correctly.

' + + '

Troubleshooting steps:

' + + '
    ' + + '
  1. Log into your Njal.la dashboard at https://njal.la
  2. ' + + '
  3. Find the DNS record for ' + escHtml(currentDomain || "your domain") + '
  4. ' + + '
  5. Verify it has a Dynamic record pointing to your current external IP:
    ' + + '' + escHtml(externalIp) + '
  6. ' + + '
  7. If the IP is wrong or the record is missing, update it
  8. ' + + '
  9. If you changed the DDNS curl command, paste the updated one below
  10. ' + + '
' + + '
' + + '
' + + '

ℹ Paste the full curl command from your Njal.la dashboard\'s Dynamic record

' + + npubField + + '
'; + + document.getElementById("domain-setup-cancel-btn").addEventListener("click", closeDomainSetupModal); + + document.getElementById("domain-setup-save-btn").addEventListener("click", async function() { + var subdomain = (document.getElementById("domain-subdomain-input") || {}).value || ""; + var ddnsUrl = (document.getElementById("domain-ddns-input") || {}).value || ""; + var npub = document.getElementById("domain-npub-input") ? (document.getElementById("domain-npub-input").value || "") : ""; + subdomain = subdomain.trim(); + ddnsUrl = ddnsUrl.trim(); + npub = npub.trim(); + + if (!subdomain) { alert("Please enter a subdomain."); return; } + if (feat.id === "haven" && !npub) { alert("Please enter your Nostr public key."); return; } + + var saveBtn = document.getElementById("domain-setup-save-btn"); + saveBtn.disabled = true; + saveBtn.textContent = "Saving…"; + + try { + await apiFetch("/api/domains/set", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + domain_name: feat.domain_name, + domain: subdomain, + ddns_url: ddnsUrl, + }), + }); + closeDomainSetupModal(); + onSaved(npub); + } catch (err) { + saveBtn.disabled = false; + saveBtn.textContent = "Save & Update"; + alert("Failed to save domain. Please try again."); + } + }); + + $domainSetupModal.classList.add("open"); +} + function closeDomainSetupModal() { if ($domainSetupModal) $domainSetupModal.classList.remove("open"); } diff --git a/app/sovran_systemsos_web/static/js/service-detail.js b/app/sovran_systemsos_web/static/js/service-detail.js index e48f7f5..4d8effc 100644 --- a/app/sovran_systemsos_web/static/js/service-detail.js +++ b/app/sovran_systemsos_web/static/js/service-detail.js @@ -296,11 +296,10 @@ async function openServiceDetailModal(unit, name, icon) { } } - // Configure Domain button (for non-feature services that need a domain) + // Configure / Reconfigure Domain buttons (for non-feature services that need a domain) var configDomainBtn = document.getElementById("svc-detail-config-domain-btn"); var reconfigDomainBtn = document.getElementById("svc-detail-reconfig-domain-btn"); - var domainBtn = configDomainBtn || reconfigDomainBtn; - if (domainBtn && data.needs_domain && data.domain_name) { + if ((configDomainBtn || reconfigDomainBtn) && data.needs_domain && data.domain_name) { var pseudoFeat = { id: data.domain_name, name: name, @@ -308,12 +307,18 @@ async function openServiceDetailModal(unit, name, icon) { needs_ddns: true, extra_fields: [] }; - domainBtn.addEventListener("click", function() { + if (configDomainBtn) configDomainBtn.addEventListener("click", function() { closeCredsModal(); openDomainSetupModal(pseudoFeat, function() { openServiceDetailModal(unit, name, icon); }); }); + if (reconfigDomainBtn) reconfigDomainBtn.addEventListener("click", function() { + closeCredsModal(); + openDomainReconfigureModal(pseudoFeat, data.domain || "", function() { + openServiceDetailModal(unit, name, icon); + }); + }); } } catch (err) { if ($credsBody) $credsBody.innerHTML = '

Could not load service details.

';